Inital import.
Initial fork from f2d678e6e89b6508147086610e985d4e8416e867 (1.0.2 beta).
(This change contains substantial changes from the original and
effectively starts a new history.)
diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt
new file mode 100644
index 0000000..8fb78f1
--- /dev/null
+++ b/crypto/CMakeLists.txt
@@ -0,0 +1,159 @@
+include_directories(. ../include)
+
+if (UNIX)
+ set(PERLASM_STYLE elf)
+ set(ASM_EXT S)
+ enable_language(ASM)
+else()
+ if (CMAKE_CL_64)
+ message("Using masm")
+ set(PERLASM_STYLE masm)
+ else()
+ message("Using win32n")
+ set(PERLASM_STYLE win32n)
+ endif()
+ set(ASM_EXT asm)
+ enable_language(ASM_MASM)
+endif()
+
+function(perlasm dest src)
+ add_custom_command(
+ OUTPUT ${dest}
+ COMMAND perl ${CMAKE_CURRENT_SOURCE_DIR}/${src} ${PERLASM_STYLE} ${ARGN} > ${dest}
+ DEPENDS
+ ${src}
+ ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86_64-xlate.pl
+ ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86gas.pl
+ ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86asm.pl
+ ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86asm.pl
+ WORKING_DIRECTORY .
+ )
+endfunction()
+
+if (${ARCH} STREQUAL "x86_64")
+ set(
+ CRYPTO_ARCH_SOURCES
+
+ cpu-x86_64-asm.${ASM_EXT}
+ cpu-intel.c
+ )
+endif()
+
+if (${ARCH} STREQUAL "x86")
+ set(
+ CRYPTO_ARCH_SOURCES
+
+ cpu-x86-asm.${ASM_EXT}
+ cpu-intel.c
+ )
+endif()
+
+if (${ARCH} STREQUAL "arm")
+ set(
+ CRYPTO_ARCH_SOURCES
+
+ cpu-x86-asm.${ASM_EXT}
+ cpu-arm.c
+ )
+endif()
+
+# Level 0.1 - depends on nothing outside this set.
+add_subdirectory(stack)
+add_subdirectory(lhash)
+add_subdirectory(err)
+add_subdirectory(buf)
+add_subdirectory(comp)
+add_subdirectory(base64)
+add_subdirectory(bytestring)
+
+# Level 0.2 - depends on nothing but itself
+add_subdirectory(sha)
+add_subdirectory(md5)
+add_subdirectory(modes)
+add_subdirectory(aes)
+add_subdirectory(des)
+add_subdirectory(rc4)
+add_subdirectory(conf)
+
+# Level 1, depends only on 0.*
+add_subdirectory(digest)
+add_subdirectory(cipher)
+add_subdirectory(rand)
+add_subdirectory(bio)
+add_subdirectory(bn)
+add_subdirectory(obj)
+add_subdirectory(asn1)
+
+# Level 2
+add_subdirectory(engine)
+add_subdirectory(dh)
+add_subdirectory(dsa)
+add_subdirectory(rsa)
+add_subdirectory(ec)
+add_subdirectory(ecdh)
+add_subdirectory(ecdsa)
+add_subdirectory(hmac)
+
+# Level 3
+add_subdirectory(evp)
+add_subdirectory(pem)
+add_subdirectory(x509)
+add_subdirectory(x509v3)
+
+# Level 4
+add_subdirectory(pkcs8)
+
+add_library(
+ crypto
+ STATIC
+
+ crypto_error.c
+ mem.c
+ mem_clear.c
+ thread.c
+ ex_data.c
+ ex_data_impl.c
+ time_support.c
+ directory_posix.c
+ directory_win.c
+
+ ${CRYPTO_ARCH_SOURCES}
+
+ $<TARGET_OBJECTS:stack>
+ $<TARGET_OBJECTS:lhash>
+ $<TARGET_OBJECTS:err>
+ $<TARGET_OBJECTS:comp>
+ $<TARGET_OBJECTS:base64>
+ $<TARGET_OBJECTS:bytestring>
+ $<TARGET_OBJECTS:sha>
+ $<TARGET_OBJECTS:md5>
+ $<TARGET_OBJECTS:digest>
+ $<TARGET_OBJECTS:cipher>
+ $<TARGET_OBJECTS:modes>
+ $<TARGET_OBJECTS:aes>
+ $<TARGET_OBJECTS:des>
+ $<TARGET_OBJECTS:rc4>
+ $<TARGET_OBJECTS:conf>
+ $<TARGET_OBJECTS:buf>
+ $<TARGET_OBJECTS:bn>
+ $<TARGET_OBJECTS:bio>
+ $<TARGET_OBJECTS:rand>
+ $<TARGET_OBJECTS:obj>
+ $<TARGET_OBJECTS:asn1>
+ $<TARGET_OBJECTS:engine>
+ $<TARGET_OBJECTS:dh>
+ $<TARGET_OBJECTS:dsa>
+ $<TARGET_OBJECTS:rsa>
+ $<TARGET_OBJECTS:ec>
+ $<TARGET_OBJECTS:ecdh>
+ $<TARGET_OBJECTS:ecdsa>
+ $<TARGET_OBJECTS:hmac>
+ $<TARGET_OBJECTS:evp>
+ $<TARGET_OBJECTS:pem>
+ $<TARGET_OBJECTS:x509>
+ $<TARGET_OBJECTS:x509v3>
+ $<TARGET_OBJECTS:pkcs8>
+)
+
+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/crypto/aes/CMakeLists.txt b/crypto/aes/CMakeLists.txt
new file mode 100644
index 0000000..6545809
--- /dev/null
+++ b/crypto/aes/CMakeLists.txt
@@ -0,0 +1,52 @@
+include_directories(. .. ../../include)
+
+if (${ARCH} STREQUAL "x86_64")
+ set(
+ AES_ARCH_SOURCES
+
+ aes-x86_64.${ASM_EXT}
+ aesni-x86_64.${ASM_EXT}
+ bsaes-x86_64.${ASM_EXT}
+ vpaes-x86_64.${ASM_EXT}
+ )
+endif()
+
+if (${ARCH} STREQUAL "x86")
+ set(
+ AES_ARCH_SOURCES
+
+ aes-586.${ASM_EXT}
+ vpaes-x86.${ASM_EXT}
+ aesni-x86.${ASM_EXT}
+ )
+endif()
+
+if (${ARCH} STREQUAL "arm")
+ set(
+ AES_ARCH_SOURCES
+
+ aes-armv4.${ASM_EXT}
+ bsaes-armv7.${ASM_EXT}
+ )
+endif()
+
+add_library(
+ aes
+
+ OBJECT
+
+ aes.c
+ mode_wrappers.c
+
+ ${AES_ARCH_SOURCES}
+)
+
+perlasm(aes-x86_64.${ASM_EXT} asm/aes-x86_64.pl)
+perlasm(aesni-x86_64.${ASM_EXT} asm/aesni-x86_64.pl)
+perlasm(bsaes-x86_64.${ASM_EXT} asm/bsaes-x86_64.pl)
+perlasm(vpaes-x86_64.${ASM_EXT} asm/vpaes-x86_64.pl)
+perlasm(aes-586.${ASM_EXT} asm/aes-586.pl)
+perlasm(vpaes-x86.${ASM_EXT} asm/vpaes-x86.pl)
+perlasm(aesni-x86.${ASM_EXT} asm/aesni-x86.pl)
+perlasm(aes-armv4.${ASM_EXT} asm/aes-armv4.pl)
+perlasm(bsaes-armv7.${ASM_EXT} asm/bsaes-armv7.pl)
diff --git a/crypto/aes/aes.c b/crypto/aes/aes.c
new file mode 100644
index 0000000..b085787
--- /dev/null
+++ b/crypto/aes/aes.c
@@ -0,0 +1,1077 @@
+/* ====================================================================
+ * Copyright (c) 2002-2006 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.
+ * ==================================================================== */
+
+#include <openssl/aes.h>
+
+#include <assert.h>
+
+#include "internal.h"
+
+
+#if defined(OPENSSL_NO_ASM) || \
+ (!defined(OPENSSL_X86) && !defined(OPENSSL_X86_64) && !defined(OPENSSL_ARM))
+
+/* Te0[x] = S [x].[02, 01, 01, 03];
+ * Te1[x] = S [x].[03, 02, 01, 01];
+ * Te2[x] = S [x].[01, 03, 02, 01];
+ * Te3[x] = S [x].[01, 01, 03, 02];
+ *
+ * Td0[x] = Si[x].[0e, 09, 0d, 0b];
+ * Td1[x] = Si[x].[0b, 0e, 09, 0d];
+ * Td2[x] = Si[x].[0d, 0b, 0e, 09];
+ * Td3[x] = Si[x].[09, 0d, 0b, 0e];
+ * Td4[x] = Si[x].[01]; */
+
+static const uint32_t Te0[256] = {
+ 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, 0xfff2f20dU,
+ 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, 0x60303050U, 0x02010103U,
+ 0xce6767a9U, 0x562b2b7dU, 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U,
+ 0xec76769aU, 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
+ 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, 0x41adadecU,
+ 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, 0x239c9cbfU, 0x53a4a4f7U,
+ 0xe4727296U, 0x9bc0c05bU, 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU,
+ 0x4c26266aU, 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
+ 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, 0xe2717193U,
+ 0xabd8d873U, 0x62313153U, 0x2a15153fU, 0x0804040cU, 0x95c7c752U,
+ 0x46232365U, 0x9dc3c35eU, 0x30181828U, 0x379696a1U, 0x0a05050fU,
+ 0x2f9a9ab5U, 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
+ 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, 0x1209091bU,
+ 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, 0x361b1b2dU, 0xdc6e6eb2U,
+ 0xb45a5aeeU, 0x5ba0a0fbU, 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U,
+ 0x7db3b3ceU, 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
+ 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, 0x40202060U,
+ 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, 0xd46a6abeU, 0x8dcbcb46U,
+ 0x67bebed9U, 0x7239394bU, 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U,
+ 0x85cfcf4aU, 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
+ 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, 0x8a4545cfU,
+ 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, 0xa05050f0U, 0x783c3c44U,
+ 0x259f9fbaU, 0x4ba8a8e3U, 0xa25151f3U, 0x5da3a3feU, 0x804040c0U,
+ 0x058f8f8aU, 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
+ 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, 0x20101030U,
+ 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, 0x81cdcd4cU, 0x180c0c14U,
+ 0x26131335U, 0xc3ecec2fU, 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU,
+ 0x2e171739U, 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
+ 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, 0xc06060a0U,
+ 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, 0x44222266U, 0x542a2a7eU,
+ 0x3b9090abU, 0x0b888883U, 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U,
+ 0x2814143cU, 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
+ 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, 0x924949dbU,
+ 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, 0x9fc2c25dU, 0xbdd3d36eU,
+ 0x43acacefU, 0xc46262a6U, 0x399191a8U, 0x319595a4U, 0xd3e4e437U,
+ 0xf279798bU, 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
+ 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, 0xd86c6cb4U,
+ 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, 0xca6565afU, 0xf47a7a8eU,
+ 0x47aeaee9U, 0x10080818U, 0x6fbabad5U, 0xf0787888U, 0x4a25256fU,
+ 0x5c2e2e72U, 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
+ 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, 0x964b4bddU,
+ 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, 0xe0707090U, 0x7c3e3e42U,
+ 0x71b5b5c4U, 0xcc6666aaU, 0x904848d8U, 0x06030305U, 0xf7f6f601U,
+ 0x1c0e0e12U, 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
+ 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, 0xd9e1e138U,
+ 0xebf8f813U, 0x2b9898b3U, 0x22111133U, 0xd26969bbU, 0xa9d9d970U,
+ 0x078e8e89U, 0x339494a7U, 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U,
+ 0xc9e9e920U, 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
+ 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, 0x65bfbfdaU,
+ 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, 0x824141c3U, 0x299999b0U,
+ 0x5a2d2d77U, 0x1e0f0f11U, 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U,
+ 0x2c16163aU, };
+
+static const uint32_t Te1[256] = {
+ 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, 0x0dfff2f2U,
+ 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, 0x50603030U, 0x03020101U,
+ 0xa9ce6767U, 0x7d562b2bU, 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU,
+ 0x9aec7676U, 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
+ 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, 0xec41adadU,
+ 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, 0xbf239c9cU, 0xf753a4a4U,
+ 0x96e47272U, 0x5b9bc0c0U, 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U,
+ 0x6a4c2626U, 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
+ 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, 0x93e27171U,
+ 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, 0x0c080404U, 0x5295c7c7U,
+ 0x65462323U, 0x5e9dc3c3U, 0x28301818U, 0xa1379696U, 0x0f0a0505U,
+ 0xb52f9a9aU, 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
+ 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, 0x1b120909U,
+ 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, 0x2d361b1bU, 0xb2dc6e6eU,
+ 0xeeb45a5aU, 0xfb5ba0a0U, 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U,
+ 0xce7db3b3U, 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
+ 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, 0x60402020U,
+ 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, 0xbed46a6aU, 0x468dcbcbU,
+ 0xd967bebeU, 0x4b723939U, 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U,
+ 0x4a85cfcfU, 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
+ 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, 0xcf8a4545U,
+ 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, 0xf0a05050U, 0x44783c3cU,
+ 0xba259f9fU, 0xe34ba8a8U, 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U,
+ 0x8a058f8fU, 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
+ 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, 0x30201010U,
+ 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, 0x4c81cdcdU, 0x14180c0cU,
+ 0x35261313U, 0x2fc3ececU, 0xe1be5f5fU, 0xa2359797U, 0xcc884444U,
+ 0x392e1717U, 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
+ 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, 0xa0c06060U,
+ 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, 0x66442222U, 0x7e542a2aU,
+ 0xab3b9090U, 0x830b8888U, 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U,
+ 0x3c281414U, 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
+ 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, 0xdb924949U,
+ 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, 0x5d9fc2c2U, 0x6ebdd3d3U,
+ 0xef43acacU, 0xa6c46262U, 0xa8399191U, 0xa4319595U, 0x37d3e4e4U,
+ 0x8bf27979U, 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
+ 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, 0xb4d86c6cU,
+ 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, 0xafca6565U, 0x8ef47a7aU,
+ 0xe947aeaeU, 0x18100808U, 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U,
+ 0x725c2e2eU, 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
+ 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, 0xdd964b4bU,
+ 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, 0x90e07070U, 0x427c3e3eU,
+ 0xc471b5b5U, 0xaacc6666U, 0xd8904848U, 0x05060303U, 0x01f7f6f6U,
+ 0x121c0e0eU, 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
+ 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, 0x38d9e1e1U,
+ 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, 0xbbd26969U, 0x70a9d9d9U,
+ 0x89078e8eU, 0xa7339494U, 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U,
+ 0x20c9e9e9U, 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
+ 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, 0xda65bfbfU,
+ 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, 0xc3824141U, 0xb0299999U,
+ 0x775a2d2dU, 0x111e0f0fU, 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU,
+ 0x3a2c1616U, };
+
+static const uint32_t Te2[256] = {
+ 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, 0xf20dfff2U,
+ 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, 0x30506030U, 0x01030201U,
+ 0x67a9ce67U, 0x2b7d562bU, 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU,
+ 0x769aec76U, 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
+ 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, 0xadec41adU,
+ 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, 0x9cbf239cU, 0xa4f753a4U,
+ 0x7296e472U, 0xc05b9bc0U, 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U,
+ 0x266a4c26U, 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
+ 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, 0x7193e271U,
+ 0xd873abd8U, 0x31536231U, 0x153f2a15U, 0x040c0804U, 0xc75295c7U,
+ 0x23654623U, 0xc35e9dc3U, 0x18283018U, 0x96a13796U, 0x050f0a05U,
+ 0x9ab52f9aU, 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
+ 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, 0x091b1209U,
+ 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, 0x1b2d361bU, 0x6eb2dc6eU,
+ 0x5aeeb45aU, 0xa0fb5ba0U, 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U,
+ 0xb3ce7db3U, 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
+ 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, 0x20604020U,
+ 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, 0x6abed46aU, 0xcb468dcbU,
+ 0xbed967beU, 0x394b7239U, 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U,
+ 0xcf4a85cfU, 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
+ 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, 0x45cf8a45U,
+ 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, 0x50f0a050U, 0x3c44783cU,
+ 0x9fba259fU, 0xa8e34ba8U, 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U,
+ 0x8f8a058fU, 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
+ 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, 0x10302010U,
+ 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, 0xcd4c81cdU, 0x0c14180cU,
+ 0x13352613U, 0xec2fc3ecU, 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U,
+ 0x17392e17U, 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
+ 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, 0x60a0c060U,
+ 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, 0x22664422U, 0x2a7e542aU,
+ 0x90ab3b90U, 0x88830b88U, 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U,
+ 0x143c2814U, 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
+ 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, 0x49db9249U,
+ 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, 0xc25d9fc2U, 0xd36ebdd3U,
+ 0xacef43acU, 0x62a6c462U, 0x91a83991U, 0x95a43195U, 0xe437d3e4U,
+ 0x798bf279U, 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
+ 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, 0x6cb4d86cU,
+ 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, 0x65afca65U, 0x7a8ef47aU,
+ 0xaee947aeU, 0x08181008U, 0xbad56fbaU, 0x7888f078U, 0x256f4a25U,
+ 0x2e725c2eU, 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
+ 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, 0x4bdd964bU,
+ 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, 0x7090e070U, 0x3e427c3eU,
+ 0xb5c471b5U, 0x66aacc66U, 0x48d89048U, 0x03050603U, 0xf601f7f6U,
+ 0x0e121c0eU, 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
+ 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, 0xe138d9e1U,
+ 0xf813ebf8U, 0x98b32b98U, 0x11332211U, 0x69bbd269U, 0xd970a9d9U,
+ 0x8e89078eU, 0x94a73394U, 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U,
+ 0xe920c9e9U, 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
+ 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, 0xbfda65bfU,
+ 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, 0x41c38241U, 0x99b02999U,
+ 0x2d775a2dU, 0x0f111e0fU, 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU,
+ 0x163a2c16U, };
+
+static const uint32_t Te3[256] = {
+ 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, 0xf2f20dffU,
+ 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, 0x30305060U, 0x01010302U,
+ 0x6767a9ceU, 0x2b2b7d56U, 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU,
+ 0x76769aecU, 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
+ 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, 0xadadec41U,
+ 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, 0x9c9cbf23U, 0xa4a4f753U,
+ 0x727296e4U, 0xc0c05b9bU, 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU,
+ 0x26266a4cU, 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
+ 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, 0x717193e2U,
+ 0xd8d873abU, 0x31315362U, 0x15153f2aU, 0x04040c08U, 0xc7c75295U,
+ 0x23236546U, 0xc3c35e9dU, 0x18182830U, 0x9696a137U, 0x05050f0aU,
+ 0x9a9ab52fU, 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
+ 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, 0x09091b12U,
+ 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, 0x1b1b2d36U, 0x6e6eb2dcU,
+ 0x5a5aeeb4U, 0xa0a0fb5bU, 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U,
+ 0xb3b3ce7dU, 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
+ 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, 0x20206040U,
+ 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, 0x6a6abed4U, 0xcbcb468dU,
+ 0xbebed967U, 0x39394b72U, 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U,
+ 0xcfcf4a85U, 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
+ 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, 0x4545cf8aU,
+ 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, 0x5050f0a0U, 0x3c3c4478U,
+ 0x9f9fba25U, 0xa8a8e34bU, 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U,
+ 0x8f8f8a05U, 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
+ 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, 0x10103020U,
+ 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, 0xcdcd4c81U, 0x0c0c1418U,
+ 0x13133526U, 0xecec2fc3U, 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U,
+ 0x1717392eU, 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
+ 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, 0x6060a0c0U,
+ 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, 0x22226644U, 0x2a2a7e54U,
+ 0x9090ab3bU, 0x8888830bU, 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU,
+ 0x14143c28U, 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
+ 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, 0x4949db92U,
+ 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, 0xc2c25d9fU, 0xd3d36ebdU,
+ 0xacacef43U, 0x6262a6c4U, 0x9191a839U, 0x9595a431U, 0xe4e437d3U,
+ 0x79798bf2U, 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
+ 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, 0x6c6cb4d8U,
+ 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, 0x6565afcaU, 0x7a7a8ef4U,
+ 0xaeaee947U, 0x08081810U, 0xbabad56fU, 0x787888f0U, 0x25256f4aU,
+ 0x2e2e725cU, 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
+ 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, 0x4b4bdd96U,
+ 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, 0x707090e0U, 0x3e3e427cU,
+ 0xb5b5c471U, 0x6666aaccU, 0x4848d890U, 0x03030506U, 0xf6f601f7U,
+ 0x0e0e121cU, 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
+ 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, 0xe1e138d9U,
+ 0xf8f813ebU, 0x9898b32bU, 0x11113322U, 0x6969bbd2U, 0xd9d970a9U,
+ 0x8e8e8907U, 0x9494a733U, 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U,
+ 0xe9e920c9U, 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
+ 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, 0xbfbfda65U,
+ 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, 0x4141c382U, 0x9999b029U,
+ 0x2d2d775aU, 0x0f0f111eU, 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU,
+ 0x16163a2cU, };
+
+static const uint32_t Td0[256] = {
+ 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, 0x3bab6bcbU,
+ 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, 0x2030fa55U, 0xad766df6U,
+ 0x88cc7691U, 0xf5024c25U, 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U,
+ 0xb562a38fU, 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
+ 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, 0x038f5fe7U,
+ 0x15929c95U, 0xbf6d7aebU, 0x955259daU, 0xd4be832dU, 0x587421d3U,
+ 0x49e06929U, 0x8ec9c844U, 0x75c2896aU, 0xf48e7978U, 0x99583e6bU,
+ 0x27b971ddU, 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
+ 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, 0xb16477e0U,
+ 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, 0x70486858U, 0x8f45fd19U,
+ 0x94de6c87U, 0x527bf8b7U, 0xab73d323U, 0x724b02e2U, 0xe31f8f57U,
+ 0x6655ab2aU, 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
+ 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, 0x8acf1c2bU,
+ 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, 0x65daf4cdU, 0x0605bed5U,
+ 0xd134621fU, 0xc4a6fe8aU, 0x342e539dU, 0xa2f355a0U, 0x058ae132U,
+ 0xa4f6eb75U, 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
+ 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, 0x91548db5U,
+ 0x71c45d05U, 0x0406d46fU, 0x605015ffU, 0x1998fb24U, 0xd6bde997U,
+ 0x894043ccU, 0x67d99e77U, 0xb0e842bdU, 0x07898b88U, 0xe7195b38U,
+ 0x79c8eedbU, 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
+ 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, 0xfd0efffbU,
+ 0x0f853856U, 0x3daed51eU, 0x362d3927U, 0x0a0fd964U, 0x685ca621U,
+ 0x9b5b54d1U, 0x24362e3aU, 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U,
+ 0x1b9b919eU, 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
+ 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, 0x0e090d0bU,
+ 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, 0x57f11985U, 0xaf75074cU,
+ 0xee99ddbbU, 0xa37f60fdU, 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U,
+ 0x5bfb7e34U, 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
+ 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, 0x854a247dU,
+ 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, 0x1d9e2f4bU, 0xdcb230f3U,
+ 0x0d8652ecU, 0x77c1e3d0U, 0x2bb3166cU, 0xa970b999U, 0x119448faU,
+ 0x47e96422U, 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
+ 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, 0xa6f581cfU,
+ 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, 0x2c3a9de4U, 0x5078920dU,
+ 0x6a5fcc9bU, 0x547e4662U, 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU,
+ 0x82c3aff5U, 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
+ 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, 0xcd267809U,
+ 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, 0xe6956e65U, 0xaaffe67eU,
+ 0x21bccf08U, 0xef15e8e6U, 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U,
+ 0x29b07cd6U, 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
+ 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, 0xf104984aU,
+ 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, 0x764dd68dU, 0x43efb04dU,
+ 0xccaa4d54U, 0xe49604dfU, 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U,
+ 0x4665517fU, 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
+ 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, 0x9ad7618cU,
+ 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, 0xcea927eeU, 0xb761c935U,
+ 0xe11ce5edU, 0x7a47b13cU, 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U,
+ 0x73c737bfU, 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
+ 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, 0x161dc372U,
+ 0xbce2250cU, 0x283c498bU, 0xff0d9541U, 0x39a80171U, 0x080cb3deU,
+ 0xd8b4e49cU, 0x6456c190U, 0x7bcb8461U, 0xd532b670U, 0x486c5c74U,
+ 0xd0b85742U, };
+
+static const uint32_t Td1[256] = {
+ 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, 0xcb3bab6bU,
+ 0xf11f9d45U, 0xabacfa58U, 0x934be303U, 0x552030faU, 0xf6ad766dU,
+ 0x9188cc76U, 0x25f5024cU, 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U,
+ 0x8fb562a3U, 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U,
+ 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, 0xe7038f5fU,
+ 0x9515929cU, 0xebbf6d7aU, 0xda955259U, 0x2dd4be83U, 0xd3587421U,
+ 0x2949e069U, 0x448ec9c8U, 0x6a75c289U, 0x78f48e79U, 0x6b99583eU,
+ 0xdd27b971U, 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU,
+ 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, 0xe0b16477U,
+ 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, 0x58704868U, 0x198f45fdU,
+ 0x8794de6cU, 0xb7527bf8U, 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU,
+ 0x2a6655abU, 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U,
+ 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, 0x2b8acf1cU,
+ 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, 0xcd65daf4U, 0xd50605beU,
+ 0x1fd13462U, 0x8ac4a6feU, 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U,
+ 0x75a4f6ebU, 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
+ 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, 0xb591548dU,
+ 0x0571c45dU, 0x6f0406d4U, 0xff605015U, 0x241998fbU, 0x97d6bde9U,
+ 0xcc894043U, 0x7767d99eU, 0xbdb0e842U, 0x8807898bU, 0x38e7195bU,
+ 0xdb79c8eeU, 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U,
+ 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, 0xfbfd0effU,
+ 0x560f8538U, 0x1e3daed5U, 0x27362d39U, 0x640a0fd9U, 0x21685ca6U,
+ 0xd19b5b54U, 0x3a24362eU, 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U,
+ 0x9e1b9b91U, 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU,
+ 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, 0x0b0e090dU,
+ 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, 0x8557f119U, 0x4caf7507U,
+ 0xbbee99ddU, 0xfda37f60U, 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU,
+ 0x345bfb7eU, 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
+ 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, 0x7d854a24U,
+ 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, 0x4b1d9e2fU, 0xf3dcb230U,
+ 0xec0d8652U, 0xd077c1e3U, 0x6c2bb316U, 0x99a970b9U, 0xfa119448U,
+ 0x2247e964U, 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
+ 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, 0xcfa6f581U,
+ 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, 0xe42c3a9dU, 0x0d507892U,
+ 0x9b6a5fccU, 0x62547e46U, 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U,
+ 0xf582c3afU, 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U,
+ 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, 0x09cd2678U,
+ 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, 0x65e6956eU, 0x7eaaffe6U,
+ 0x0821bccfU, 0xe6ef15e8U, 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U,
+ 0xd629b07cU, 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U,
+ 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, 0x4af10498U,
+ 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, 0x8d764dd6U, 0x4d43efb0U,
+ 0x54ccaa4dU, 0xdfe49604U, 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU,
+ 0x7f466551U, 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U,
+ 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, 0x8c9ad761U,
+ 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, 0xeecea927U, 0x35b761c9U,
+ 0xede11ce5U, 0x3c7a47b1U, 0x599cd2dfU, 0x3f55f273U, 0x791814ceU,
+ 0xbf73c737U, 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
+ 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, 0x72161dc3U,
+ 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, 0x7139a801U, 0xde080cb3U,
+ 0x9cd8b4e4U, 0x906456c1U, 0x617bcb84U, 0x70d532b6U, 0x74486c5cU,
+ 0x42d0b857U, };
+
+static const uint32_t Td2[256] = {
+ 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, 0x6bcb3babU,
+ 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, 0xfa552030U, 0x6df6ad76U,
+ 0x769188ccU, 0x4c25f502U, 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U,
+ 0xa38fb562U, 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU,
+ 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, 0x5fe7038fU,
+ 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, 0x832dd4beU, 0x21d35874U,
+ 0x692949e0U, 0xc8448ec9U, 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U,
+ 0x71dd27b9U, 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU,
+ 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, 0x77e0b164U,
+ 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, 0x68587048U, 0xfd198f45U,
+ 0x6c8794deU, 0xf8b7527bU, 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU,
+ 0xab2a6655U, 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U,
+ 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, 0x1c2b8acfU,
+ 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, 0xf4cd65daU, 0xbed50605U,
+ 0x621fd134U, 0xfe8ac4a6U, 0x539d342eU, 0x55a0a2f3U, 0xe132058aU,
+ 0xeb75a4f6U, 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
+ 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, 0x8db59154U,
+ 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, 0xfb241998U, 0xe997d6bdU,
+ 0x43cc8940U, 0x9e7767d9U, 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U,
+ 0xeedb79c8U, 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U,
+ 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, 0xfffbfd0eU,
+ 0x38560f85U, 0xd51e3daeU, 0x3927362dU, 0xd9640a0fU, 0xa621685cU,
+ 0x54d19b5bU, 0x2e3a2436U, 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU,
+ 0x919e1b9bU, 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U,
+ 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, 0x0d0b0e09U,
+ 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, 0x198557f1U, 0x074caf75U,
+ 0xddbbee99U, 0x60fda37fU, 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U,
+ 0x7e345bfbU, 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
+ 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, 0x247d854aU,
+ 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, 0x2f4b1d9eU, 0x30f3dcb2U,
+ 0x52ec0d86U, 0xe3d077c1U, 0x166c2bb3U, 0xb999a970U, 0x48fa1194U,
+ 0x642247e9U, 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
+ 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, 0x81cfa6f5U,
+ 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, 0x9de42c3aU, 0x920d5078U,
+ 0xcc9b6a5fU, 0x4662547eU, 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U,
+ 0xaff582c3U, 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U,
+ 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, 0x7809cd26U,
+ 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, 0x6e65e695U, 0xe67eaaffU,
+ 0xcf0821bcU, 0xe8e6ef15U, 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU,
+ 0x7cd629b0U, 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U,
+ 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, 0x984af104U,
+ 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, 0xd68d764dU, 0xb04d43efU,
+ 0x4d54ccaaU, 0x04dfe496U, 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU,
+ 0x517f4665U, 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU,
+ 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, 0x618c9ad7U,
+ 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, 0x27eecea9U, 0xc935b761U,
+ 0xe5ede11cU, 0xb13c7a47U, 0xdf599cd2U, 0x733f55f2U, 0xce791814U,
+ 0x37bf73c7U, 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
+ 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, 0xc372161dU,
+ 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, 0x017139a8U, 0xb3de080cU,
+ 0xe49cd8b4U, 0xc1906456U, 0x84617bcbU, 0xb670d532U, 0x5c74486cU,
+ 0x5742d0b8U, };
+
+static const uint32_t Td3[256] = {
+ 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, 0xab6bcb3bU,
+ 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, 0x30fa5520U, 0x766df6adU,
+ 0xcc769188U, 0x024c25f5U, 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U,
+ 0x62a38fb5U, 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU,
+ 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, 0x8f5fe703U,
+ 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, 0xbe832dd4U, 0x7421d358U,
+ 0xe0692949U, 0xc9c8448eU, 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U,
+ 0xb971dd27U, 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU,
+ 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, 0x6477e0b1U,
+ 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, 0x48685870U, 0x45fd198fU,
+ 0xde6c8794U, 0x7bf8b752U, 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U,
+ 0x55ab2a66U, 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U,
+ 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, 0xcf1c2b8aU,
+ 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, 0xdaf4cd65U, 0x05bed506U,
+ 0x34621fd1U, 0xa6fe8ac4U, 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U,
+ 0xf6eb75a4U, 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
+ 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, 0x548db591U,
+ 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, 0x98fb2419U, 0xbde997d6U,
+ 0x4043cc89U, 0xd99e7767U, 0xe842bdb0U, 0x898b8807U, 0x195b38e7U,
+ 0xc8eedb79U, 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U,
+ 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, 0x0efffbfdU,
+ 0x8538560fU, 0xaed51e3dU, 0x2d392736U, 0x0fd9640aU, 0x5ca62168U,
+ 0x5b54d19bU, 0x362e3a24U, 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U,
+ 0x9b919e1bU, 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU,
+ 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, 0x090d0b0eU,
+ 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, 0xf1198557U, 0x75074cafU,
+ 0x99ddbbeeU, 0x7f60fda3U, 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U,
+ 0xfb7e345bU, 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
+ 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, 0x4a247d85U,
+ 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, 0x9e2f4b1dU, 0xb230f3dcU,
+ 0x8652ec0dU, 0xc1e3d077U, 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U,
+ 0xe9642247U, 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
+ 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, 0xf581cfa6U,
+ 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, 0x3a9de42cU, 0x78920d50U,
+ 0x5fcc9b6aU, 0x7e466254U, 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU,
+ 0xc3aff582U, 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU,
+ 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, 0x267809cdU,
+ 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, 0x956e65e6U, 0xffe67eaaU,
+ 0xbccf0821U, 0x15e8e6efU, 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU,
+ 0xb07cd629U, 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U,
+ 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, 0x04984af1U,
+ 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, 0x4dd68d76U, 0xefb04d43U,
+ 0xaa4d54ccU, 0x9604dfe4U, 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U,
+ 0x65517f46U, 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU,
+ 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, 0xd7618c9aU,
+ 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, 0xa927eeceU, 0x61c935b7U,
+ 0x1ce5ede1U, 0x47b13c7aU, 0xd2df599cU, 0xf2733f55U, 0x14ce7918U,
+ 0xc737bf73U, 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
+ 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, 0x1dc37216U,
+ 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, 0xa8017139U, 0x0cb3de08U,
+ 0xb4e49cd8U, 0x56c19064U, 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U,
+ 0xb85742d0U, };
+
+static const uint8_t Td4[256] = {
+ 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, 0xbfU, 0x40U, 0xa3U,
+ 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU, 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU,
+ 0xffU, 0x87U, 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU, 0x54U,
+ 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU, 0xeeU, 0x4cU, 0x95U, 0x0bU,
+ 0x42U, 0xfaU, 0xc3U, 0x4eU, 0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U,
+ 0xb2U, 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U, 0x72U, 0xf8U,
+ 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U, 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU,
+ 0x65U, 0xb6U, 0x92U, 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU,
+ 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U, 0x90U, 0xd8U, 0xabU,
+ 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU, 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U,
+ 0x45U, 0x06U, 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U, 0xc1U,
+ 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU, 0x3aU, 0x91U, 0x11U, 0x41U,
+ 0x4fU, 0x67U, 0xdcU, 0xeaU, 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U,
+ 0x73U, 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U, 0xe2U, 0xf9U,
+ 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU, 0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU,
+ 0x29U, 0xc5U, 0x89U, 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU,
+ 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U, 0x9aU, 0xdbU, 0xc0U,
+ 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U, 0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U,
+ 0xc7U, 0x31U, 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU, 0x60U,
+ 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU, 0x2dU, 0xe5U, 0x7aU, 0x9fU,
+ 0x93U, 0xc9U, 0x9cU, 0xefU, 0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U,
+ 0xb0U, 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U, 0x17U, 0x2bU,
+ 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U, 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U,
+ 0x21U, 0x0cU, 0x7dU, };
+
+static const uint8_t Te4[256] = {
+ 0x63U, 0x7cU, 0x77U, 0x7bU, 0xf2U, 0x6bU, 0x6fU, 0xc5U, 0x30U, 0x01U, 0x67U,
+ 0x2bU, 0xfeU, 0xd7U, 0xabU, 0x76U, 0xcaU, 0x82U, 0xc9U, 0x7dU, 0xfaU, 0x59U,
+ 0x47U, 0xf0U, 0xadU, 0xd4U, 0xa2U, 0xafU, 0x9cU, 0xa4U, 0x72U, 0xc0U, 0xb7U,
+ 0xfdU, 0x93U, 0x26U, 0x36U, 0x3fU, 0xf7U, 0xccU, 0x34U, 0xa5U, 0xe5U, 0xf1U,
+ 0x71U, 0xd8U, 0x31U, 0x15U, 0x04U, 0xc7U, 0x23U, 0xc3U, 0x18U, 0x96U, 0x05U,
+ 0x9aU, 0x07U, 0x12U, 0x80U, 0xe2U, 0xebU, 0x27U, 0xb2U, 0x75U, 0x09U, 0x83U,
+ 0x2cU, 0x1aU, 0x1bU, 0x6eU, 0x5aU, 0xa0U, 0x52U, 0x3bU, 0xd6U, 0xb3U, 0x29U,
+ 0xe3U, 0x2fU, 0x84U, 0x53U, 0xd1U, 0x00U, 0xedU, 0x20U, 0xfcU, 0xb1U, 0x5bU,
+ 0x6aU, 0xcbU, 0xbeU, 0x39U, 0x4aU, 0x4cU, 0x58U, 0xcfU, 0xd0U, 0xefU, 0xaaU,
+ 0xfbU, 0x43U, 0x4dU, 0x33U, 0x85U, 0x45U, 0xf9U, 0x02U, 0x7fU, 0x50U, 0x3cU,
+ 0x9fU, 0xa8U, 0x51U, 0xa3U, 0x40U, 0x8fU, 0x92U, 0x9dU, 0x38U, 0xf5U, 0xbcU,
+ 0xb6U, 0xdaU, 0x21U, 0x10U, 0xffU, 0xf3U, 0xd2U, 0xcdU, 0x0cU, 0x13U, 0xecU,
+ 0x5fU, 0x97U, 0x44U, 0x17U, 0xc4U, 0xa7U, 0x7eU, 0x3dU, 0x64U, 0x5dU, 0x19U,
+ 0x73U, 0x60U, 0x81U, 0x4fU, 0xdcU, 0x22U, 0x2aU, 0x90U, 0x88U, 0x46U, 0xeeU,
+ 0xb8U, 0x14U, 0xdeU, 0x5eU, 0x0bU, 0xdbU, 0xe0U, 0x32U, 0x3aU, 0x0aU, 0x49U,
+ 0x06U, 0x24U, 0x5cU, 0xc2U, 0xd3U, 0xacU, 0x62U, 0x91U, 0x95U, 0xe4U, 0x79U,
+ 0xe7U, 0xc8U, 0x37U, 0x6dU, 0x8dU, 0xd5U, 0x4eU, 0xa9U, 0x6cU, 0x56U, 0xf4U,
+ 0xeaU, 0x65U, 0x7aU, 0xaeU, 0x08U, 0xbaU, 0x78U, 0x25U, 0x2eU, 0x1cU, 0xa6U,
+ 0xb4U, 0xc6U, 0xe8U, 0xddU, 0x74U, 0x1fU, 0x4bU, 0xbdU, 0x8bU, 0x8aU, 0x70U,
+ 0x3eU, 0xb5U, 0x66U, 0x48U, 0x03U, 0xf6U, 0x0eU, 0x61U, 0x35U, 0x57U, 0xb9U,
+ 0x86U, 0xc1U, 0x1dU, 0x9eU, 0xe1U, 0xf8U, 0x98U, 0x11U, 0x69U, 0xd9U, 0x8eU,
+ 0x94U, 0x9bU, 0x1eU, 0x87U, 0xe9U, 0xceU, 0x55U, 0x28U, 0xdfU, 0x8cU, 0xa1U,
+ 0x89U, 0x0dU, 0xbfU, 0xe6U, 0x42U, 0x68U, 0x41U, 0x99U, 0x2dU, 0x0fU, 0xb0U,
+ 0x54U, 0xbbU, 0x16U};
+
+static const uint32_t rcon[] = {
+ 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
+ 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000,
+ /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+};
+
+int AES_set_encrypt_key(const uint8_t *key, const unsigned bits, AES_KEY *aeskey) {
+ uint32_t *rk;
+ int i = 0;
+ uint32_t temp;
+
+ if (!key || !aeskey) {
+ return -1;
+ }
+
+ switch (bits) {
+ case 128:
+ aeskey->rounds = 10;
+ break;
+ case 192:
+ aeskey->rounds = 12;
+ break;
+ case 256:
+ aeskey->rounds = 14;
+ break;
+ default:
+ return -2;
+ }
+
+ rk = aeskey->rd_key;
+
+ rk[0] = GETU32(key);
+ rk[1] = GETU32(key + 4);
+ rk[2] = GETU32(key + 8);
+ rk[3] = GETU32(key + 12);
+ if (bits == 128) {
+ while (1) {
+ temp = rk[3];
+ rk[4] = rk[0] ^ (Te2[(temp >> 16) & 0xff] & 0xff000000) ^
+ (Te3[(temp >> 8) & 0xff] & 0x00ff0000) ^
+ (Te0[(temp) & 0xff] & 0x0000ff00) ^
+ (Te1[(temp >> 24)] & 0x000000ff) ^ rcon[i];
+ rk[5] = rk[1] ^ rk[4];
+ rk[6] = rk[2] ^ rk[5];
+ rk[7] = rk[3] ^ rk[6];
+ if (++i == 10) {
+ return 0;
+ }
+ rk += 4;
+ }
+ }
+ rk[4] = GETU32(key + 16);
+ rk[5] = GETU32(key + 20);
+ if (bits == 192) {
+ while (1) {
+ temp = rk[5];
+ rk[6] = rk[0] ^ (Te2[(temp >> 16) & 0xff] & 0xff000000) ^
+ (Te3[(temp >> 8) & 0xff] & 0x00ff0000) ^
+ (Te0[(temp) & 0xff] & 0x0000ff00) ^
+ (Te1[(temp >> 24)] & 0x000000ff) ^ rcon[i];
+ rk[7] = rk[1] ^ rk[6];
+ rk[8] = rk[2] ^ rk[7];
+ rk[9] = rk[3] ^ rk[8];
+ if (++i == 8) {
+ return 0;
+ }
+ rk[10] = rk[4] ^ rk[9];
+ rk[11] = rk[5] ^ rk[10];
+ rk += 6;
+ }
+ }
+ rk[6] = GETU32(key + 24);
+ rk[7] = GETU32(key + 28);
+ if (bits == 256) {
+ while (1) {
+ temp = rk[7];
+ rk[8] = rk[0] ^ (Te2[(temp >> 16) & 0xff] & 0xff000000) ^
+ (Te3[(temp >> 8) & 0xff] & 0x00ff0000) ^
+ (Te0[(temp) & 0xff] & 0x0000ff00) ^
+ (Te1[(temp >> 24)] & 0x000000ff) ^ rcon[i];
+ rk[9] = rk[1] ^ rk[8];
+ rk[10] = rk[2] ^ rk[9];
+ rk[11] = rk[3] ^ rk[10];
+ if (++i == 7) {
+ return 0;
+ }
+ temp = rk[11];
+ rk[12] = rk[4] ^ (Te2[(temp >> 24)] & 0xff000000) ^
+ (Te3[(temp >> 16) & 0xff] & 0x00ff0000) ^
+ (Te0[(temp >> 8) & 0xff] & 0x0000ff00) ^
+ (Te1[(temp) & 0xff] & 0x000000ff);
+ rk[13] = rk[5] ^ rk[12];
+ rk[14] = rk[6] ^ rk[13];
+ rk[15] = rk[7] ^ rk[14];
+
+ rk += 8;
+ }
+ }
+ return 0;
+}
+
+int AES_set_decrypt_key(const unsigned char *key, const unsigned bits,
+ AES_KEY *aeskey) {
+ uint32_t *rk;
+ int i, j, status;
+ uint32_t temp;
+
+ /* first, start with an encryption schedule */
+ status = AES_set_encrypt_key(key, bits, aeskey);
+ if (status < 0) {
+ return status;
+ }
+
+ rk = aeskey->rd_key;
+
+ /* invert the order of the round keys: */
+ for (i = 0, j = 4 * aeskey->rounds; i < j; i += 4, j -= 4) {
+ temp = rk[i];
+ rk[i] = rk[j];
+ rk[j] = temp;
+ temp = rk[i + 1];
+ rk[i + 1] = rk[j + 1];
+ rk[j + 1] = temp;
+ temp = rk[i + 2];
+ rk[i + 2] = rk[j + 2];
+ rk[j + 2] = temp;
+ temp = rk[i + 3];
+ rk[i + 3] = rk[j + 3];
+ rk[j + 3] = temp;
+ }
+ /* apply the inverse MixColumn transform to all round keys but the first and
+ * the last: */
+ for (i = 1; i < aeskey->rounds; i++) {
+ rk += 4;
+ rk[0] =
+ Td0[Te1[(rk[0] >> 24)] & 0xff] ^ Td1[Te1[(rk[0] >> 16) & 0xff] & 0xff] ^
+ Td2[Te1[(rk[0] >> 8) & 0xff] & 0xff] ^ Td3[Te1[(rk[0]) & 0xff] & 0xff];
+ rk[1] =
+ Td0[Te1[(rk[1] >> 24)] & 0xff] ^ Td1[Te1[(rk[1] >> 16) & 0xff] & 0xff] ^
+ Td2[Te1[(rk[1] >> 8) & 0xff] & 0xff] ^ Td3[Te1[(rk[1]) & 0xff] & 0xff];
+ rk[2] =
+ Td0[Te1[(rk[2] >> 24)] & 0xff] ^ Td1[Te1[(rk[2] >> 16) & 0xff] & 0xff] ^
+ Td2[Te1[(rk[2] >> 8) & 0xff] & 0xff] ^ Td3[Te1[(rk[2]) & 0xff] & 0xff];
+ rk[3] =
+ Td0[Te1[(rk[3] >> 24)] & 0xff] ^ Td1[Te1[(rk[3] >> 16) & 0xff] & 0xff] ^
+ Td2[Te1[(rk[3] >> 8) & 0xff] & 0xff] ^ Td3[Te1[(rk[3]) & 0xff] & 0xff];
+ }
+ return 0;
+}
+
+void AES_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
+ const uint32_t *rk;
+ uint32_t s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+ int r;
+#endif /* ?FULL_UNROLL */
+
+ assert(in && out && key);
+ rk = key->rd_key;
+
+ /* map byte array block to cipher state
+ * and add initial round key: */
+ s0 = GETU32(in) ^ rk[0];
+ s1 = GETU32(in + 4) ^ rk[1];
+ s2 = GETU32(in + 8) ^ rk[2];
+ s3 = GETU32(in + 12) ^ rk[3];
+#ifdef FULL_UNROLL
+ /* round 1: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^
+ Te3[s3 & 0xff] ^ rk[4];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^
+ Te3[s0 & 0xff] ^ rk[5];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^
+ Te3[s1 & 0xff] ^ rk[6];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^
+ Te3[s2 & 0xff] ^ rk[7];
+ /* round 2: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^
+ Te3[t3 & 0xff] ^ rk[8];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^
+ Te3[t0 & 0xff] ^ rk[9];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^
+ Te3[t1 & 0xff] ^ rk[10];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^
+ Te3[t2 & 0xff] ^ rk[11];
+ /* round 3: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^
+ Te3[s3 & 0xff] ^ rk[12];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^
+ Te3[s0 & 0xff] ^ rk[13];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^
+ Te3[s1 & 0xff] ^ rk[14];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^
+ Te3[s2 & 0xff] ^ rk[15];
+ /* round 4: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^
+ Te3[t3 & 0xff] ^ rk[16];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^
+ Te3[t0 & 0xff] ^ rk[17];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^
+ Te3[t1 & 0xff] ^ rk[18];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^
+ Te3[t2 & 0xff] ^ rk[19];
+ /* round 5: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^
+ Te3[s3 & 0xff] ^ rk[20];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^
+ Te3[s0 & 0xff] ^ rk[21];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^
+ Te3[s1 & 0xff] ^ rk[22];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^
+ Te3[s2 & 0xff] ^ rk[23];
+ /* round 6: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^
+ Te3[t3 & 0xff] ^ rk[24];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^
+ Te3[t0 & 0xff] ^ rk[25];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^
+ Te3[t1 & 0xff] ^ rk[26];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^
+ Te3[t2 & 0xff] ^ rk[27];
+ /* round 7: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^
+ Te3[s3 & 0xff] ^ rk[28];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^
+ Te3[s0 & 0xff] ^ rk[29];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^
+ Te3[s1 & 0xff] ^ rk[30];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^
+ Te3[s2 & 0xff] ^ rk[31];
+ /* round 8: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^
+ Te3[t3 & 0xff] ^ rk[32];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^
+ Te3[t0 & 0xff] ^ rk[33];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^
+ Te3[t1 & 0xff] ^ rk[34];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^
+ Te3[t2 & 0xff] ^ rk[35];
+ /* round 9: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^
+ Te3[s3 & 0xff] ^ rk[36];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^
+ Te3[s0 & 0xff] ^ rk[37];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^
+ Te3[s1 & 0xff] ^ rk[38];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^
+ Te3[s2 & 0xff] ^ rk[39];
+ if (key->rounds > 10) {
+ /* round 10: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^
+ Te3[t3 & 0xff] ^ rk[40];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^
+ Te3[t0 & 0xff] ^ rk[41];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^
+ Te3[t1 & 0xff] ^ rk[42];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^
+ Te3[t2 & 0xff] ^ rk[43];
+ /* round 11: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^
+ Te3[s3 & 0xff] ^ rk[44];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^
+ Te3[s0 & 0xff] ^ rk[45];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^
+ Te3[s1 & 0xff] ^ rk[46];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^
+ Te3[s2 & 0xff] ^ rk[47];
+ if (key->rounds > 12) {
+ /* round 12: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^
+ Te3[t3 & 0xff] ^ rk[48];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^
+ Te3[t0 & 0xff] ^ rk[49];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^
+ Te3[t1 & 0xff] ^ rk[50];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^
+ Te3[t2 & 0xff] ^ rk[51];
+ /* round 13: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^
+ Te3[s3 & 0xff] ^ rk[52];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^
+ Te3[s0 & 0xff] ^ rk[53];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^
+ Te3[s1 & 0xff] ^ rk[54];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^
+ Te3[s2 & 0xff] ^ rk[55];
+ }
+ }
+ rk += key->rounds << 2;
+#else /* !FULL_UNROLL */
+ /*
+ * Nr - 1 full rounds:
+ */
+ r = key->rounds >> 1;
+ for (;;) {
+ t0 = Te0[(s0 >> 24)] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^
+ Te3[(s3) & 0xff] ^ rk[4];
+ t1 = Te0[(s1 >> 24)] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^
+ Te3[(s0) & 0xff] ^ rk[5];
+ t2 = Te0[(s2 >> 24)] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^
+ Te3[(s1) & 0xff] ^ rk[6];
+ t3 = Te0[(s3 >> 24)] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^
+ Te3[(s2) & 0xff] ^ rk[7];
+
+ rk += 8;
+ if (--r == 0) {
+ break;
+ }
+
+ s0 = Te0[(t0 >> 24)] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^
+ Te3[(t3) & 0xff] ^ rk[0];
+ s1 = Te0[(t1 >> 24)] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^
+ Te3[(t0) & 0xff] ^ rk[1];
+ s2 = Te0[(t2 >> 24)] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^
+ Te3[(t1) & 0xff] ^ rk[2];
+ s3 = Te0[(t3 >> 24)] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^
+ Te3[(t2) & 0xff] ^ rk[3];
+ }
+#endif /* ?FULL_UNROLL */
+ /* apply last round and map cipher state to byte array block: */
+ s0 = (Te2[(t0 >> 24)] & 0xff000000) ^ (Te3[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te0[(t2 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t3) & 0xff] & 0x000000ff) ^
+ rk[0];
+ PUTU32(out, s0);
+ s1 = (Te2[(t1 >> 24)] & 0xff000000) ^ (Te3[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te0[(t3 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t0) & 0xff] & 0x000000ff) ^
+ rk[1];
+ PUTU32(out + 4, s1);
+ s2 = (Te2[(t2 >> 24)] & 0xff000000) ^ (Te3[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te0[(t0 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t1) & 0xff] & 0x000000ff) ^
+ rk[2];
+ PUTU32(out + 8, s2);
+ s3 = (Te2[(t3 >> 24)] & 0xff000000) ^ (Te3[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te0[(t1 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t2) & 0xff] & 0x000000ff) ^
+ rk[3];
+ PUTU32(out + 12, s3);
+}
+
+void AES_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
+ const uint32_t *rk;
+ uint32_t s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+ int r;
+#endif /* ?FULL_UNROLL */
+
+ assert(in && out && key);
+ rk = key->rd_key;
+
+ /* map byte array block to cipher state
+ * and add initial round key: */
+ s0 = GETU32(in) ^ rk[0];
+ s1 = GETU32(in + 4) ^ rk[1];
+ s2 = GETU32(in + 8) ^ rk[2];
+ s3 = GETU32(in + 12) ^ rk[3];
+#ifdef FULL_UNROLL
+ /* round 1: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^
+ Td3[s1 & 0xff] ^ rk[4];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^
+ Td3[s2 & 0xff] ^ rk[5];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^
+ Td3[s3 & 0xff] ^ rk[6];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^
+ Td3[s0 & 0xff] ^ rk[7];
+ /* round 2: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^
+ Td3[t1 & 0xff] ^ rk[8];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^
+ Td3[t2 & 0xff] ^ rk[9];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^
+ Td3[t3 & 0xff] ^ rk[10];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^
+ Td3[t0 & 0xff] ^ rk[11];
+ /* round 3: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^
+ Td3[s1 & 0xff] ^ rk[12];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^
+ Td3[s2 & 0xff] ^ rk[13];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^
+ Td3[s3 & 0xff] ^ rk[14];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^
+ Td3[s0 & 0xff] ^ rk[15];
+ /* round 4: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^
+ Td3[t1 & 0xff] ^ rk[16];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^
+ Td3[t2 & 0xff] ^ rk[17];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^
+ Td3[t3 & 0xff] ^ rk[18];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^
+ Td3[t0 & 0xff] ^ rk[19];
+ /* round 5: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^
+ Td3[s1 & 0xff] ^ rk[20];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^
+ Td3[s2 & 0xff] ^ rk[21];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^
+ Td3[s3 & 0xff] ^ rk[22];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^
+ Td3[s0 & 0xff] ^ rk[23];
+ /* round 6: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^
+ Td3[t1 & 0xff] ^ rk[24];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^
+ Td3[t2 & 0xff] ^ rk[25];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^
+ Td3[t3 & 0xff] ^ rk[26];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^
+ Td3[t0 & 0xff] ^ rk[27];
+ /* round 7: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^
+ Td3[s1 & 0xff] ^ rk[28];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^
+ Td3[s2 & 0xff] ^ rk[29];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^
+ Td3[s3 & 0xff] ^ rk[30];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^
+ Td3[s0 & 0xff] ^ rk[31];
+ /* round 8: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^
+ Td3[t1 & 0xff] ^ rk[32];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^
+ Td3[t2 & 0xff] ^ rk[33];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^
+ Td3[t3 & 0xff] ^ rk[34];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^
+ Td3[t0 & 0xff] ^ rk[35];
+ /* round 9: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^
+ Td3[s1 & 0xff] ^ rk[36];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^
+ Td3[s2 & 0xff] ^ rk[37];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^
+ Td3[s3 & 0xff] ^ rk[38];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^
+ Td3[s0 & 0xff] ^ rk[39];
+ if (key->rounds > 10) {
+ /* round 10: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^
+ Td3[t1 & 0xff] ^ rk[40];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^
+ Td3[t2 & 0xff] ^ rk[41];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^
+ Td3[t3 & 0xff] ^ rk[42];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^
+ Td3[t0 & 0xff] ^ rk[43];
+ /* round 11: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^
+ Td3[s1 & 0xff] ^ rk[44];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^
+ Td3[s2 & 0xff] ^ rk[45];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^
+ Td3[s3 & 0xff] ^ rk[46];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^
+ Td3[s0 & 0xff] ^ rk[47];
+ if (key->rounds > 12) {
+ /* round 12: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^
+ Td3[t1 & 0xff] ^ rk[48];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^
+ Td3[t2 & 0xff] ^ rk[49];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^
+ Td3[t3 & 0xff] ^ rk[50];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^
+ Td3[t0 & 0xff] ^ rk[51];
+ /* round 13: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^
+ Td3[s1 & 0xff] ^ rk[52];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^
+ Td3[s2 & 0xff] ^ rk[53];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^
+ Td3[s3 & 0xff] ^ rk[54];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^
+ Td3[s0 & 0xff] ^ rk[55];
+ }
+ }
+ rk += key->rounds << 2;
+#else /* !FULL_UNROLL */
+ /*
+ * Nr - 1 full rounds:
+ */
+ r = key->rounds >> 1;
+ for (;;) {
+ t0 = Td0[(s0 >> 24)] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^
+ Td3[(s1) & 0xff] ^ rk[4];
+ t1 = Td0[(s1 >> 24)] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^
+ Td3[(s2) & 0xff] ^ rk[5];
+ t2 = Td0[(s2 >> 24)] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^
+ Td3[(s3) & 0xff] ^ rk[6];
+ t3 = Td0[(s3 >> 24)] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^
+ Td3[(s0) & 0xff] ^ rk[7];
+
+ rk += 8;
+ if (--r == 0) {
+ break;
+ }
+
+ s0 = Td0[(t0 >> 24)] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^
+ Td3[(t1) & 0xff] ^ rk[0];
+ s1 = Td0[(t1 >> 24)] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^
+ Td3[(t2) & 0xff] ^ rk[1];
+ s2 = Td0[(t2 >> 24)] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^
+ Td3[(t3) & 0xff] ^ rk[2];
+ s3 = Td0[(t3 >> 24)] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^
+ Td3[(t0) & 0xff] ^ rk[3];
+ }
+#endif /* ?FULL_UNROLL */
+ /* apply last round and
+ * map cipher state to byte array block: */
+ s0 = (Td4[(t0 >> 24)] << 24) ^ (Td4[(t3 >> 16) & 0xff] << 16) ^
+ (Td4[(t2 >> 8) & 0xff] << 8) ^ (Td4[(t1) & 0xff]) ^ rk[0];
+ PUTU32(out, s0);
+ s1 = (Td4[(t1 >> 24)] << 24) ^ (Td4[(t0 >> 16) & 0xff] << 16) ^
+ (Td4[(t3 >> 8) & 0xff] << 8) ^ (Td4[(t2) & 0xff]) ^ rk[1];
+ PUTU32(out + 4, s1);
+ s2 = (Td4[(t2 >> 24)] << 24) ^ (Td4[(t1 >> 16) & 0xff] << 16) ^
+ (Td4[(t0 >> 8) & 0xff] << 8) ^ (Td4[(t3) & 0xff]) ^ rk[2];
+ PUTU32(out + 8, s2);
+ s3 = (Td4[(t3 >> 24)] << 24) ^ (Td4[(t2 >> 16) & 0xff] << 16) ^
+ (Td4[(t1 >> 8) & 0xff] << 8) ^ (Td4[(t0) & 0xff]) ^ rk[3];
+ PUTU32(out + 12, s3);
+}
+
+#endif
diff --git a/crypto/aes/aes.h b/crypto/aes/aes.h
new file mode 100644
index 0000000..8156964
--- /dev/null
+++ b/crypto/aes/aes.h
@@ -0,0 +1,138 @@
+/* ====================================================================
+ * Copyright (c) 2002-2006 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.
+ * ==================================================================== */
+
+#ifndef OPENSSL_HEADER_AES_H
+#define OPENSSL_HEADER_AES_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* Raw AES functions. */
+
+
+#define AES_ENCRYPT 1
+#define AES_DECRYPT 0
+
+/* AES_MAXNR is the maximum number of AES rounds. */
+#define AES_MAXNR 14
+
+#define AES_BLOCK_SIZE 16
+
+/* aes_key_st should be an opaque type, but EVP requires that the size be
+ * known. */
+struct aes_key_st {
+ uint32_t rd_key[4 * (AES_MAXNR + 1)];
+ unsigned rounds;
+};
+typedef struct aes_key_st AES_KEY;
+
+/* AES_set_encrypt_key configures |aeskey| to encrypt with the |bits|-bit key,
+ * |key|.
+ *
+ * WARNING: unlike other OpenSSL functions, this returns zero on success and a
+ * negative number on error. */
+int AES_set_encrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey);
+
+/* AES_set_decrypt_key configures |aeskey| to decrypt with the |bits|-bit key,
+ * |key|.
+ *
+ * WARNING: unlike other OpenSSL functions, this returns zero on success and a
+ * negative number on error. */
+int AES_set_decrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey);
+
+/* AES_encrypt encrypts a single block from |in| to |out| with |key|. The |in|
+ * and |out| pointers may overlap. */
+void AES_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key);
+
+/* AES_decrypt decrypts a single block from |in| to |out| with |key|. The |in|
+ * and |out| pointers may overlap. */
+void AES_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key);
+
+
+/* Block cipher modes. */
+
+/* AES_ctr128_encrypt encrypts (or decrypts, it's the same in CTR mode) |len|
+ * bytes from |in| to |out|. The |num| parameter must be set to zero on the
+ * first call and |ivec| will be incremented. */
+void AES_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
+ const AES_KEY *key, uint8_t ivec[AES_BLOCK_SIZE],
+ uint8_t ecount_buf[AES_BLOCK_SIZE], unsigned int *num);
+
+/* AES_ecb_encrypt encrypts (or decrypts, if |enc| == |AES_DECRYPT|) a single,
+ * 16 byte block from |in| to |out|. */
+void AES_ecb_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key,
+ const int enc);
+
+/* AES_cbc_encrypt encrypts (or decrypts, if |enc| == |AES_DECRYPT|) |len|
+ * bytes from |in| to |out|. The length must be a multiple of the block size. */
+void AES_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len,
+ const AES_KEY *key, uint8_t *ivec, const int enc);
+
+/* AES_ofb128_encrypt encrypts (or decrypts, it's the same in CTR mode) |len|
+ * bytes from |in| to |out|. The |num| parameter must be set to zero on the
+ * first call. */
+void AES_ofb128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
+ const AES_KEY *key, uint8_t *ivec, int *num);
+
+/* AES_cfb128_encrypt encrypts (or decrypts, if |enc| == |AES_DECRYPT|) |len|
+ * bytes from |in| to |out|. The |num| parameter must be set to zero on the
+ * first call. */
+void AES_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
+ const AES_KEY *key, uint8_t *ivec, int *num,
+ int enc);
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_AES_H */
diff --git a/crypto/aes/asm/aes-586.pl b/crypto/aes/asm/aes-586.pl
new file mode 100755
index 0000000..1c1e23e
--- /dev/null
+++ b/crypto/aes/asm/aes-586.pl
@@ -0,0 +1,2987 @@
+#!/usr/bin/env perl
+#
+# ====================================================================
+# Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+#
+# Version 4.3.
+#
+# You might fail to appreciate this module performance from the first
+# try. If compared to "vanilla" linux-ia32-icc target, i.e. considered
+# to be *the* best Intel C compiler without -KPIC, performance appears
+# to be virtually identical... But try to re-configure with shared
+# library support... Aha! Intel compiler "suddenly" lags behind by 30%
+# [on P4, more on others]:-) And if compared to position-independent
+# code generated by GNU C, this code performs *more* than *twice* as
+# fast! Yes, all this buzz about PIC means that unlike other hand-
+# coded implementations, this one was explicitly designed to be safe
+# to use even in shared library context... This also means that this
+# code isn't necessarily absolutely fastest "ever," because in order
+# to achieve position independence an extra register has to be
+# off-loaded to stack, which affects the benchmark result.
+#
+# Special note about instruction choice. Do you recall RC4_INT code
+# performing poorly on P4? It might be the time to figure out why.
+# RC4_INT code implies effective address calculations in base+offset*4
+# form. Trouble is that it seems that offset scaling turned to be
+# critical path... At least eliminating scaling resulted in 2.8x RC4
+# performance improvement [as you might recall]. As AES code is hungry
+# for scaling too, I [try to] avoid the latter by favoring off-by-2
+# shifts and masking the result with 0xFF<<2 instead of "boring" 0xFF.
+#
+# As was shown by Dean Gaudet <dean@arctic.org>, the above note turned
+# void. Performance improvement with off-by-2 shifts was observed on
+# intermediate implementation, which was spilling yet another register
+# to stack... Final offset*4 code below runs just a tad faster on P4,
+# but exhibits up to 10% improvement on other cores.
+#
+# Second version is "monolithic" replacement for aes_core.c, which in
+# addition to AES_[de|en]crypt implements AES_set_[de|en]cryption_key.
+# This made it possible to implement little-endian variant of the
+# algorithm without modifying the base C code. Motivating factor for
+# 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...
+#
+# Third version adds AES_cbc_encrypt implementation, which resulted in
+# up to 40% performance imrovement of CBC benchmark results. 40% was
+# observed on P4 core, where "overall" imrovement coefficient, i.e. if
+# compared to PIC generated by GCC and in CBC mode, was observed to be
+# as large as 4x:-) CBC performance is virtually identical to ECB now
+# and on some platforms even better, e.g. 17.6 "small" cycles/byte on
+# Opteron, because certain function prologues and epilogues are
+# effectively taken out of the loop...
+#
+# Version 3.2 implements compressed tables and prefetch of these tables
+# in CBC[!] mode. Former means that 3/4 of table references are now
+# misaligned, which unfortunately has negative impact on elder IA-32
+# implementations, Pentium suffered 30% penalty, PIII - 10%.
+#
+# Version 3.3 avoids L1 cache aliasing between stack frame and
+# S-boxes, and 3.4 - L1 cache aliasing even between key schedule. The
+# latter is achieved by copying the key schedule to controlled place in
+# stack. This unfortunately has rather strong impact on small block CBC
+# performance, ~2x deterioration on 16-byte block if compared to 3.3.
+#
+# Version 3.5 checks if there is L1 cache aliasing between user-supplied
+# key schedule and S-boxes and abstains from copying the former if
+# there is no. This allows end-user to consciously retain small block
+# performance by aligning key schedule in specific manner.
+#
+# Version 3.6 compresses Td4 to 256 bytes and prefetches it in ECB.
+#
+# Current ECB performance numbers for 128-bit key in CPU cycles per
+# processed byte [measure commonly used by AES benchmarkers] are:
+#
+# small footprint fully unrolled
+# P4 24 22
+# AMD K8 20 19
+# PIII 25 23
+# Pentium 81 78
+#
+# Version 3.7 reimplements outer rounds as "compact." Meaning that
+# first and last rounds reference compact 256 bytes S-box. This means
+# that first round consumes a lot more CPU cycles and that encrypt
+# and decrypt performance becomes asymmetric. Encrypt performance
+# drops by 10-12%, while decrypt - by 20-25%:-( 256 bytes S-box is
+# aggressively pre-fetched.
+#
+# Version 4.0 effectively rolls back to 3.6 and instead implements
+# additional set of functions, _[x86|sse]_AES_[en|de]crypt_compact,
+# which use exclusively 256 byte S-box. These functions are to be
+# called in modes not concealing plain text, such as ECB, or when
+# we're asked to process smaller amount of data [or unconditionally
+# on hyper-threading CPU]. Currently it's called unconditionally from
+# AES_[en|de]crypt, which affects all modes, but CBC. CBC routine
+# still needs to be modified to switch between slower and faster
+# mode when appropriate... But in either case benchmark landscape
+# changes dramatically and below numbers are CPU cycles per processed
+# byte for 128-bit key.
+#
+# ECB encrypt ECB decrypt CBC large chunk
+# P4 52[54] 83[95] 23
+# AMD K8 46[41] 66[70] 18
+# PIII 41[50] 60[77] 24
+# Core 2 31[36] 45[64] 18.5
+# Atom 76[100] 96[138] 60
+# Pentium 115 150 77
+#
+# Version 4.1 switches to compact S-box even in key schedule setup.
+#
+# Version 4.2 prefetches compact S-box in every SSE round or in other
+# words every cache-line is *guaranteed* to be accessed within ~50
+# cycles window. Why just SSE? Because it's needed on hyper-threading
+# CPU! Which is also why it's prefetched with 64 byte stride. Best
+# part is that it has no negative effect on performance:-)
+#
+# Version 4.3 implements switch between compact and non-compact block
+# functions in AES_cbc_encrypt depending on how much data was asked
+# to be processed in one stroke.
+#
+######################################################################
+# Timing attacks are classified in two classes: synchronous when
+# attacker consciously initiates cryptographic operation and collects
+# timing data of various character afterwards, and asynchronous when
+# malicious code is executed on same CPU simultaneously with AES,
+# instruments itself and performs statistical analysis of this data.
+#
+# As far as synchronous attacks go the root to the AES timing
+# vulnerability is twofold. Firstly, of 256 S-box elements at most 160
+# are referred to in single 128-bit block operation. Well, in C
+# implementation with 4 distinct tables it's actually as little as 40
+# references per 256 elements table, but anyway... Secondly, even
+# though S-box elements are clustered into smaller amount of cache-
+# lines, smaller than 160 and even 40, it turned out that for certain
+# plain-text pattern[s] or simply put chosen plain-text and given key
+# few cache-lines remain unaccessed during block operation. Now, if
+# attacker can figure out this access pattern, he can deduct the key
+# [or at least part of it]. The natural way to mitigate this kind of
+# attacks is to minimize the amount of cache-lines in S-box and/or
+# prefetch them to ensure that every one is accessed for more uniform
+# timing. But note that *if* plain-text was concealed in such way that
+# input to block function is distributed *uniformly*, then attack
+# wouldn't apply. Now note that some encryption modes, most notably
+# CBC, do mask the plain-text in this exact way [secure cipher output
+# is distributed uniformly]. Yes, one still might find input that
+# would reveal the information about given key, but if amount of
+# candidate inputs to be tried is larger than amount of possible key
+# combinations then attack becomes infeasible. This is why revised
+# AES_cbc_encrypt "dares" to switch to larger S-box when larger chunk
+# of data is to be processed in one stroke. The current size limit of
+# 512 bytes is chosen to provide same [diminishigly low] probability
+# for cache-line to remain untouched in large chunk operation with
+# large S-box as for single block operation with compact S-box and
+# surely needs more careful consideration...
+#
+# As for asynchronous attacks. There are two flavours: attacker code
+# being interleaved with AES on hyper-threading CPU at *instruction*
+# level, and two processes time sharing single core. As for latter.
+# Two vectors. 1. Given that attacker process has higher priority,
+# yield execution to process performing AES just before timer fires
+# off the scheduler, immediately regain control of CPU and analyze the
+# cache state. For this attack to be efficient attacker would have to
+# effectively slow down the operation by several *orders* of magnitute,
+# by ratio of time slice to duration of handful of AES rounds, which
+# unlikely to remain unnoticed. Not to mention that this also means
+# that he would spend correspondigly more time to collect enough
+# statistical data to mount the attack. It's probably appropriate to
+# say that if adeversary reckons that this attack is beneficial and
+# risks to be noticed, you probably have larger problems having him
+# mere opportunity. In other words suggested code design expects you
+# to preclude/mitigate this attack by overall system security design.
+# 2. Attacker manages to make his code interrupt driven. In order for
+# this kind of attack to be feasible, interrupt rate has to be high
+# enough, again comparable to duration of handful of AES rounds. But
+# is there interrupt source of such rate? Hardly, not even 1Gbps NIC
+# generates interrupts at such raging rate...
+#
+# And now back to the former, hyper-threading CPU or more specifically
+# Intel P4. Recall that asynchronous attack implies that malicious
+# code instruments itself. And naturally instrumentation granularity
+# has be noticeably lower than duration of codepath accessing S-box.
+# Given that all cache-lines are accessed during that time that is.
+# Current implementation accesses *all* cache-lines within ~50 cycles
+# window, which is actually *less* than RDTSC latency on Intel P4!
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+push(@INC,"${dir}","${dir}../../perlasm");
+require "x86asm.pl";
+
+&asm_init($ARGV[0],"aes-586.pl",$x86only = $ARGV[$#ARGV] eq "386");
+&static_label("AES_Te");
+&static_label("AES_Td");
+
+$s0="eax";
+$s1="ebx";
+$s2="ecx";
+$s3="edx";
+$key="edi";
+$acc="esi";
+$tbl="ebp";
+
+# stack frame layout in _[x86|sse]_AES_* routines, frame is allocated
+# by caller
+$__ra=&DWP(0,"esp"); # return address
+$__s0=&DWP(4,"esp"); # s0 backing store
+$__s1=&DWP(8,"esp"); # s1 backing store
+$__s2=&DWP(12,"esp"); # s2 backing store
+$__s3=&DWP(16,"esp"); # s3 backing store
+$__key=&DWP(20,"esp"); # pointer to key schedule
+$__end=&DWP(24,"esp"); # pointer to end of key schedule
+$__tbl=&DWP(28,"esp"); # %ebp backing store
+
+# stack frame layout in AES_[en|crypt] routines, which differs from
+# above by 4 and overlaps by %ebp backing store
+$_tbl=&DWP(24,"esp");
+$_esp=&DWP(28,"esp");
+
+sub _data_word() { my $i; while(defined($i=shift)) { &data_word($i,$i); } }
+
+$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!
+ # I favor compact code to minimize cache
+ # contention and in hope to "collect" 5% back
+ # in real-life applications...
+
+$vertical_spin=0; # shift "verticaly" defaults to 0, because of
+ # its proof-of-concept status...
+# Note that there is no decvert(), as well as last encryption round is
+# performed with "horizontal" shifts. This is because this "vertical"
+# implementation [one which groups shifts on a given $s[i] to form a
+# "column," unlike "horizontal" one, which groups shifts on different
+# $s[i] to form a "row"] is work in progress. It was observed to run
+# few percents faster on Intel cores, but not AMD. On AMD K8 core it's
+# whole 12% slower:-( So we face a trade-off... Shall it be resolved
+# some day? Till then the code is considered experimental and by
+# default remains dormant...
+
+sub encvert()
+{ my ($te,@s) = @_;
+ my ($v0,$v1) = ($acc,$key);
+
+ &mov ($v0,$s[3]); # copy s3
+ &mov (&DWP(4,"esp"),$s[2]); # save s2
+ &mov ($v1,$s[0]); # copy s0
+ &mov (&DWP(8,"esp"),$s[1]); # save s1
+
+ &movz ($s[2],&HB($s[0]));
+ &and ($s[0],0xFF);
+ &mov ($s[0],&DWP(0,$te,$s[0],8)); # s0>>0
+ &shr ($v1,16);
+ &mov ($s[3],&DWP(3,$te,$s[2],8)); # s0>>8
+ &movz ($s[1],&HB($v1));
+ &and ($v1,0xFF);
+ &mov ($s[2],&DWP(2,$te,$v1,8)); # s0>>16
+ &mov ($v1,$v0);
+ &mov ($s[1],&DWP(1,$te,$s[1],8)); # s0>>24
+
+ &and ($v0,0xFF);
+ &xor ($s[3],&DWP(0,$te,$v0,8)); # s3>>0
+ &movz ($v0,&HB($v1));
+ &shr ($v1,16);
+ &xor ($s[2],&DWP(3,$te,$v0,8)); # s3>>8
+ &movz ($v0,&HB($v1));
+ &and ($v1,0xFF);
+ &xor ($s[1],&DWP(2,$te,$v1,8)); # s3>>16
+ &mov ($v1,&DWP(4,"esp")); # restore s2
+ &xor ($s[0],&DWP(1,$te,$v0,8)); # s3>>24
+
+ &mov ($v0,$v1);
+ &and ($v1,0xFF);
+ &xor ($s[2],&DWP(0,$te,$v1,8)); # s2>>0
+ &movz ($v1,&HB($v0));
+ &shr ($v0,16);
+ &xor ($s[1],&DWP(3,$te,$v1,8)); # s2>>8
+ &movz ($v1,&HB($v0));
+ &and ($v0,0xFF);
+ &xor ($s[0],&DWP(2,$te,$v0,8)); # s2>>16
+ &mov ($v0,&DWP(8,"esp")); # restore s1
+ &xor ($s[3],&DWP(1,$te,$v1,8)); # s2>>24
+
+ &mov ($v1,$v0);
+ &and ($v0,0xFF);
+ &xor ($s[1],&DWP(0,$te,$v0,8)); # s1>>0
+ &movz ($v0,&HB($v1));
+ &shr ($v1,16);
+ &xor ($s[0],&DWP(3,$te,$v0,8)); # s1>>8
+ &movz ($v0,&HB($v1));
+ &and ($v1,0xFF);
+ &xor ($s[3],&DWP(2,$te,$v1,8)); # s1>>16
+ &mov ($key,$__key); # reincarnate v1 as key
+ &xor ($s[2],&DWP(1,$te,$v0,8)); # s1>>24
+}
+
+# Another experimental routine, which features "horizontal spin," but
+# eliminates one reference to stack. Strangely enough runs slower...
+sub enchoriz()
+{ my ($v0,$v1) = ($key,$acc);
+
+ &movz ($v0,&LB($s0)); # 3, 2, 1, 0*
+ &rotr ($s2,8); # 8,11,10, 9
+ &mov ($v1,&DWP(0,$te,$v0,8)); # 0
+ &movz ($v0,&HB($s1)); # 7, 6, 5*, 4
+ &rotr ($s3,16); # 13,12,15,14
+ &xor ($v1,&DWP(3,$te,$v0,8)); # 5
+ &movz ($v0,&HB($s2)); # 8,11,10*, 9
+ &rotr ($s0,16); # 1, 0, 3, 2
+ &xor ($v1,&DWP(2,$te,$v0,8)); # 10
+ &movz ($v0,&HB($s3)); # 13,12,15*,14
+ &xor ($v1,&DWP(1,$te,$v0,8)); # 15, t[0] collected
+ &mov ($__s0,$v1); # t[0] saved
+
+ &movz ($v0,&LB($s1)); # 7, 6, 5, 4*
+ &shr ($s1,16); # -, -, 7, 6
+ &mov ($v1,&DWP(0,$te,$v0,8)); # 4
+ &movz ($v0,&LB($s3)); # 13,12,15,14*
+ &xor ($v1,&DWP(2,$te,$v0,8)); # 14
+ &movz ($v0,&HB($s0)); # 1, 0, 3*, 2
+ &and ($s3,0xffff0000); # 13,12, -, -
+ &xor ($v1,&DWP(1,$te,$v0,8)); # 3
+ &movz ($v0,&LB($s2)); # 8,11,10, 9*
+ &or ($s3,$s1); # 13,12, 7, 6
+ &xor ($v1,&DWP(3,$te,$v0,8)); # 9, t[1] collected
+ &mov ($s1,$v1); # s[1]=t[1]
+
+ &movz ($v0,&LB($s0)); # 1, 0, 3, 2*
+ &shr ($s2,16); # -, -, 8,11
+ &mov ($v1,&DWP(2,$te,$v0,8)); # 2
+ &movz ($v0,&HB($s3)); # 13,12, 7*, 6
+ &xor ($v1,&DWP(1,$te,$v0,8)); # 7
+ &movz ($v0,&HB($s2)); # -, -, 8*,11
+ &xor ($v1,&DWP(0,$te,$v0,8)); # 8
+ &mov ($v0,$s3);
+ &shr ($v0,24); # 13
+ &xor ($v1,&DWP(3,$te,$v0,8)); # 13, t[2] collected
+
+ &movz ($v0,&LB($s2)); # -, -, 8,11*
+ &shr ($s0,24); # 1*
+ &mov ($s2,&DWP(1,$te,$v0,8)); # 11
+ &xor ($s2,&DWP(3,$te,$s0,8)); # 1
+ &mov ($s0,$__s0); # s[0]=t[0]
+ &movz ($v0,&LB($s3)); # 13,12, 7, 6*
+ &shr ($s3,16); # , ,13,12
+ &xor ($s2,&DWP(2,$te,$v0,8)); # 6
+ &mov ($key,$__key); # reincarnate v0 as key
+ &and ($s3,0xff); # , ,13,12*
+ &mov ($s3,&DWP(0,$te,$s3,8)); # 12
+ &xor ($s3,$s2); # s[2]=t[3] collected
+ &mov ($s2,$v1); # s[2]=t[2]
+}
+
+# More experimental code... SSE one... Even though this one eliminates
+# *all* references to stack, it's not faster...
+sub sse_encbody()
+{
+ &movz ($acc,&LB("eax")); # 0
+ &mov ("ecx",&DWP(0,$tbl,$acc,8)); # 0
+ &pshufw ("mm2","mm0",0x0d); # 7, 6, 3, 2
+ &movz ("edx",&HB("eax")); # 1
+ &mov ("edx",&DWP(3,$tbl,"edx",8)); # 1
+ &shr ("eax",16); # 5, 4
+
+ &movz ($acc,&LB("ebx")); # 10
+ &xor ("ecx",&DWP(2,$tbl,$acc,8)); # 10
+ &pshufw ("mm6","mm4",0x08); # 13,12, 9, 8
+ &movz ($acc,&HB("ebx")); # 11
+ &xor ("edx",&DWP(1,$tbl,$acc,8)); # 11
+ &shr ("ebx",16); # 15,14
+
+ &movz ($acc,&HB("eax")); # 5
+ &xor ("ecx",&DWP(3,$tbl,$acc,8)); # 5
+ &movq ("mm3",QWP(16,$key));
+ &movz ($acc,&HB("ebx")); # 15
+ &xor ("ecx",&DWP(1,$tbl,$acc,8)); # 15
+ &movd ("mm0","ecx"); # t[0] collected
+
+ &movz ($acc,&LB("eax")); # 4
+ &mov ("ecx",&DWP(0,$tbl,$acc,8)); # 4
+ &movd ("eax","mm2"); # 7, 6, 3, 2
+ &movz ($acc,&LB("ebx")); # 14
+ &xor ("ecx",&DWP(2,$tbl,$acc,8)); # 14
+ &movd ("ebx","mm6"); # 13,12, 9, 8
+
+ &movz ($acc,&HB("eax")); # 3
+ &xor ("ecx",&DWP(1,$tbl,$acc,8)); # 3
+ &movz ($acc,&HB("ebx")); # 9
+ &xor ("ecx",&DWP(3,$tbl,$acc,8)); # 9
+ &movd ("mm1","ecx"); # t[1] collected
+
+ &movz ($acc,&LB("eax")); # 2
+ &mov ("ecx",&DWP(2,$tbl,$acc,8)); # 2
+ &shr ("eax",16); # 7, 6
+ &punpckldq ("mm0","mm1"); # t[0,1] collected
+ &movz ($acc,&LB("ebx")); # 8
+ &xor ("ecx",&DWP(0,$tbl,$acc,8)); # 8
+ &shr ("ebx",16); # 13,12
+
+ &movz ($acc,&HB("eax")); # 7
+ &xor ("ecx",&DWP(1,$tbl,$acc,8)); # 7
+ &pxor ("mm0","mm3");
+ &movz ("eax",&LB("eax")); # 6
+ &xor ("edx",&DWP(2,$tbl,"eax",8)); # 6
+ &pshufw ("mm1","mm0",0x08); # 5, 4, 1, 0
+ &movz ($acc,&HB("ebx")); # 13
+ &xor ("ecx",&DWP(3,$tbl,$acc,8)); # 13
+ &xor ("ecx",&DWP(24,$key)); # t[2]
+ &movd ("mm4","ecx"); # t[2] collected
+ &movz ("ebx",&LB("ebx")); # 12
+ &xor ("edx",&DWP(0,$tbl,"ebx",8)); # 12
+ &shr ("ecx",16);
+ &movd ("eax","mm1"); # 5, 4, 1, 0
+ &mov ("ebx",&DWP(28,$key)); # t[3]
+ &xor ("ebx","edx");
+ &movd ("mm5","ebx"); # t[3] collected
+ &and ("ebx",0xffff0000);
+ &or ("ebx","ecx");
+
+ &punpckldq ("mm4","mm5"); # t[2,3] collected
+}
+
+######################################################################
+# "Compact" block function
+######################################################################
+
+sub enccompact()
+{ my $Fn = \&mov;
+ while ($#_>5) { pop(@_); $Fn=sub{}; }
+ my ($i,$te,@s)=@_;
+ my $tmp = $key;
+ my $out = $i==3?$s[0]:$acc;
+
+ # $Fn is used in first compact round and its purpose is to
+ # void restoration of some values from stack, so that after
+ # 4xenccompact with extra argument $key value is left there...
+ if ($i==3) { &$Fn ($key,$__key); }##%edx
+ else { &mov ($out,$s[0]); }
+ &and ($out,0xFF);
+ if ($i==1) { &shr ($s[0],16); }#%ebx[1]
+ if ($i==2) { &shr ($s[0],24); }#%ecx[2]
+ &movz ($out,&BP(-128,$te,$out,1));
+
+ if ($i==3) { $tmp=$s[1]; }##%eax
+ &movz ($tmp,&HB($s[1]));
+ &movz ($tmp,&BP(-128,$te,$tmp,1));
+ &shl ($tmp,8);
+ &xor ($out,$tmp);
+
+ if ($i==3) { $tmp=$s[2]; &mov ($s[1],$__s0); }##%ebx
+ else { &mov ($tmp,$s[2]);
+ &shr ($tmp,16); }
+ if ($i==2) { &and ($s[1],0xFF); }#%edx[2]
+ &and ($tmp,0xFF);
+ &movz ($tmp,&BP(-128,$te,$tmp,1));
+ &shl ($tmp,16);
+ &xor ($out,$tmp);
+
+ if ($i==3) { $tmp=$s[3]; &mov ($s[2],$__s1); }##%ecx
+ elsif($i==2){ &movz ($tmp,&HB($s[3])); }#%ebx[2]
+ else { &mov ($tmp,$s[3]);
+ &shr ($tmp,24); }
+ &movz ($tmp,&BP(-128,$te,$tmp,1));
+ &shl ($tmp,24);
+ &xor ($out,$tmp);
+ if ($i<2) { &mov (&DWP(4+4*$i,"esp"),$out); }
+ if ($i==3) { &mov ($s[3],$acc); }
+ &comment();
+}
+
+sub enctransform()
+{ my @s = ($s0,$s1,$s2,$s3);
+ my $i = shift;
+ my $tmp = $tbl;
+ my $r2 = $key ;
+
+ &and ($tmp,$s[$i]);
+ &lea ($r2,&DWP(0,$s[$i],$s[$i]));
+ &mov ($acc,$tmp);
+ &shr ($tmp,7);
+ &and ($r2,0xfefefefe);
+ &sub ($acc,$tmp);
+ &mov ($tmp,$s[$i]);
+ &and ($acc,0x1b1b1b1b);
+ &rotr ($tmp,16);
+ &xor ($acc,$r2); # r2
+ &mov ($r2,$s[$i]);
+
+ &xor ($s[$i],$acc); # r0 ^ r2
+ &rotr ($r2,16+8);
+ &xor ($acc,$tmp);
+ &rotl ($s[$i],24);
+ &xor ($acc,$r2);
+ &mov ($tmp,0x80808080) if ($i!=1);
+ &xor ($s[$i],$acc); # ROTATE(r2^r0,24) ^ r2
+}
+
+&function_begin_B("_x86_AES_encrypt_compact");
+ # note that caller is expected to allocate stack frame for me!
+ &mov ($__key,$key); # save key
+
+ &xor ($s0,&DWP(0,$key)); # xor with key
+ &xor ($s1,&DWP(4,$key));
+ &xor ($s2,&DWP(8,$key));
+ &xor ($s3,&DWP(12,$key));
+
+ &mov ($acc,&DWP(240,$key)); # load key->rounds
+ &lea ($acc,&DWP(-2,$acc,$acc));
+ &lea ($acc,&DWP(0,$key,$acc,8));
+ &mov ($__end,$acc); # end of key schedule
+
+ # prefetch Te4
+ &mov ($key,&DWP(0-128,$tbl));
+ &mov ($acc,&DWP(32-128,$tbl));
+ &mov ($key,&DWP(64-128,$tbl));
+ &mov ($acc,&DWP(96-128,$tbl));
+ &mov ($key,&DWP(128-128,$tbl));
+ &mov ($acc,&DWP(160-128,$tbl));
+ &mov ($key,&DWP(192-128,$tbl));
+ &mov ($acc,&DWP(224-128,$tbl));
+
+ &set_label("loop",16);
+
+ &enccompact(0,$tbl,$s0,$s1,$s2,$s3,1);
+ &enccompact(1,$tbl,$s1,$s2,$s3,$s0,1);
+ &enccompact(2,$tbl,$s2,$s3,$s0,$s1,1);
+ &enccompact(3,$tbl,$s3,$s0,$s1,$s2,1);
+ &mov ($tbl,0x80808080);
+ &enctransform(2);
+ &enctransform(3);
+ &enctransform(0);
+ &enctransform(1);
+ &mov ($key,$__key);
+ &mov ($tbl,$__tbl);
+ &add ($key,16); # advance rd_key
+ &xor ($s0,&DWP(0,$key));
+ &xor ($s1,&DWP(4,$key));
+ &xor ($s2,&DWP(8,$key));
+ &xor ($s3,&DWP(12,$key));
+
+ &cmp ($key,$__end);
+ &mov ($__key,$key);
+ &jb (&label("loop"));
+
+ &enccompact(0,$tbl,$s0,$s1,$s2,$s3);
+ &enccompact(1,$tbl,$s1,$s2,$s3,$s0);
+ &enccompact(2,$tbl,$s2,$s3,$s0,$s1);
+ &enccompact(3,$tbl,$s3,$s0,$s1,$s2);
+
+ &xor ($s0,&DWP(16,$key));
+ &xor ($s1,&DWP(20,$key));
+ &xor ($s2,&DWP(24,$key));
+ &xor ($s3,&DWP(28,$key));
+
+ &ret ();
+&function_end_B("_x86_AES_encrypt_compact");
+
+######################################################################
+# "Compact" SSE block function.
+######################################################################
+#
+# 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%
+# 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.
+#
+# MMX register layout lsb
+# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+# | mm4 | mm0 |
+# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+# | s3 | s2 | s1 | s0 |
+# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+# |15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0|
+# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+#
+# Indexes translate as s[N/4]>>(8*(N%4)), e.g. 5 means s1>>8.
+# In this terms encryption and decryption "compact" permutation
+# matrices can be depicted as following:
+#
+# encryption lsb # decryption lsb
+# +----++----+----+----+----+ # +----++----+----+----+----+
+# | t0 || 15 | 10 | 5 | 0 | # | t0 || 7 | 10 | 13 | 0 |
+# +----++----+----+----+----+ # +----++----+----+----+----+
+# | t1 || 3 | 14 | 9 | 4 | # | t1 || 11 | 14 | 1 | 4 |
+# +----++----+----+----+----+ # +----++----+----+----+----+
+# | t2 || 7 | 2 | 13 | 8 | # | t2 || 15 | 2 | 5 | 8 |
+# +----++----+----+----+----+ # +----++----+----+----+----+
+# | t3 || 11 | 6 | 1 | 12 | # | t3 || 3 | 6 | 9 | 12 |
+# +----++----+----+----+----+ # +----++----+----+----+----+
+#
+######################################################################
+# Why not xmm registers? Short answer. It was actually tested and
+# was not any faster, but *contrary*, most notably on Intel CPUs.
+# Longer answer. Main advantage of using mm registers is that movd
+# latency is lower, especially on Intel P4. While arithmetic
+# instructions are twice as many, they can be scheduled every cycle
+# and not every second one when they are operating on xmm register,
+# so that "arithmetic throughput" remains virtually the same. And
+# finally the code can be executed even on elder SSE-only CPUs:-)
+
+sub sse_enccompact()
+{
+ &pshufw ("mm1","mm0",0x08); # 5, 4, 1, 0
+ &pshufw ("mm5","mm4",0x0d); # 15,14,11,10
+ &movd ("eax","mm1"); # 5, 4, 1, 0
+ &movd ("ebx","mm5"); # 15,14,11,10
+ &mov ($__key,$key);
+
+ &movz ($acc,&LB("eax")); # 0
+ &movz ("edx",&HB("eax")); # 1
+ &pshufw ("mm2","mm0",0x0d); # 7, 6, 3, 2
+ &movz ("ecx",&BP(-128,$tbl,$acc,1)); # 0
+ &movz ($key,&LB("ebx")); # 10
+ &movz ("edx",&BP(-128,$tbl,"edx",1)); # 1
+ &shr ("eax",16); # 5, 4
+ &shl ("edx",8); # 1
+
+ &movz ($acc,&BP(-128,$tbl,$key,1)); # 10
+ &movz ($key,&HB("ebx")); # 11
+ &shl ($acc,16); # 10
+ &pshufw ("mm6","mm4",0x08); # 13,12, 9, 8
+ &or ("ecx",$acc); # 10
+ &movz ($acc,&BP(-128,$tbl,$key,1)); # 11
+ &movz ($key,&HB("eax")); # 5
+ &shl ($acc,24); # 11
+ &shr ("ebx",16); # 15,14
+ &or ("edx",$acc); # 11
+
+ &movz ($acc,&BP(-128,$tbl,$key,1)); # 5
+ &movz ($key,&HB("ebx")); # 15
+ &shl ($acc,8); # 5
+ &or ("ecx",$acc); # 5
+ &movz ($acc,&BP(-128,$tbl,$key,1)); # 15
+ &movz ($key,&LB("eax")); # 4
+ &shl ($acc,24); # 15
+ &or ("ecx",$acc); # 15
+
+ &movz ($acc,&BP(-128,$tbl,$key,1)); # 4
+ &movz ($key,&LB("ebx")); # 14
+ &movd ("eax","mm2"); # 7, 6, 3, 2
+ &movd ("mm0","ecx"); # t[0] collected
+ &movz ("ecx",&BP(-128,$tbl,$key,1)); # 14
+ &movz ($key,&HB("eax")); # 3
+ &shl ("ecx",16); # 14
+ &movd ("ebx","mm6"); # 13,12, 9, 8
+ &or ("ecx",$acc); # 14
+
+ &movz ($acc,&BP(-128,$tbl,$key,1)); # 3
+ &movz ($key,&HB("ebx")); # 9
+ &shl ($acc,24); # 3
+ &or ("ecx",$acc); # 3
+ &movz ($acc,&BP(-128,$tbl,$key,1)); # 9
+ &movz ($key,&LB("ebx")); # 8
+ &shl ($acc,8); # 9
+ &shr ("ebx",16); # 13,12
+ &or ("ecx",$acc); # 9
+
+ &movz ($acc,&BP(-128,$tbl,$key,1)); # 8
+ &movz ($key,&LB("eax")); # 2
+ &shr ("eax",16); # 7, 6
+ &movd ("mm1","ecx"); # t[1] collected
+ &movz ("ecx",&BP(-128,$tbl,$key,1)); # 2
+ &movz ($key,&HB("eax")); # 7
+ &shl ("ecx",16); # 2
+ &and ("eax",0xff); # 6
+ &or ("ecx",$acc); # 2
+
+ &punpckldq ("mm0","mm1"); # t[0,1] collected
+
+ &movz ($acc,&BP(-128,$tbl,$key,1)); # 7
+ &movz ($key,&HB("ebx")); # 13
+ &shl ($acc,24); # 7
+ &and ("ebx",0xff); # 12
+ &movz ("eax",&BP(-128,$tbl,"eax",1)); # 6
+ &or ("ecx",$acc); # 7
+ &shl ("eax",16); # 6
+ &movz ($acc,&BP(-128,$tbl,$key,1)); # 13
+ &or ("edx","eax"); # 6
+ &shl ($acc,8); # 13
+ &movz ("ebx",&BP(-128,$tbl,"ebx",1)); # 12
+ &or ("ecx",$acc); # 13
+ &or ("edx","ebx"); # 12
+ &mov ($key,$__key);
+ &movd ("mm4","ecx"); # t[2] collected
+ &movd ("mm5","edx"); # t[3] collected
+
+ &punpckldq ("mm4","mm5"); # t[2,3] collected
+}
+
+ if (!$x86only) {
+&function_begin_B("_sse_AES_encrypt_compact");
+ &pxor ("mm0",&QWP(0,$key)); # 7, 6, 5, 4, 3, 2, 1, 0
+ &pxor ("mm4",&QWP(8,$key)); # 15,14,13,12,11,10, 9, 8
+
+ # note that caller is expected to allocate stack frame for me!
+ &mov ($acc,&DWP(240,$key)); # load key->rounds
+ &lea ($acc,&DWP(-2,$acc,$acc));
+ &lea ($acc,&DWP(0,$key,$acc,8));
+ &mov ($__end,$acc); # end of key schedule
+
+ &mov ($s0,0x1b1b1b1b); # magic constant
+ &mov (&DWP(8,"esp"),$s0);
+ &mov (&DWP(12,"esp"),$s0);
+
+ # prefetch Te4
+ &mov ($s0,&DWP(0-128,$tbl));
+ &mov ($s1,&DWP(32-128,$tbl));
+ &mov ($s2,&DWP(64-128,$tbl));
+ &mov ($s3,&DWP(96-128,$tbl));
+ &mov ($s0,&DWP(128-128,$tbl));
+ &mov ($s1,&DWP(160-128,$tbl));
+ &mov ($s2,&DWP(192-128,$tbl));
+ &mov ($s3,&DWP(224-128,$tbl));
+
+ &set_label("loop",16);
+ &sse_enccompact();
+ &add ($key,16);
+ &cmp ($key,$__end);
+ &ja (&label("out"));
+
+ &movq ("mm2",&QWP(8,"esp"));
+ &pxor ("mm3","mm3"); &pxor ("mm7","mm7");
+ &movq ("mm1","mm0"); &movq ("mm5","mm4"); # r0
+ &pcmpgtb("mm3","mm0"); &pcmpgtb("mm7","mm4");
+ &pand ("mm3","mm2"); &pand ("mm7","mm2");
+ &pshufw ("mm2","mm0",0xb1); &pshufw ("mm6","mm4",0xb1);# ROTATE(r0,16)
+ &paddb ("mm0","mm0"); &paddb ("mm4","mm4");
+ &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # = r2
+ &pshufw ("mm3","mm2",0xb1); &pshufw ("mm7","mm6",0xb1);# r0
+ &pxor ("mm1","mm0"); &pxor ("mm5","mm4"); # r0^r2
+ &pxor ("mm0","mm2"); &pxor ("mm4","mm6"); # ^= ROTATE(r0,16)
+
+ &movq ("mm2","mm3"); &movq ("mm6","mm7");
+ &pslld ("mm3",8); &pslld ("mm7",8);
+ &psrld ("mm2",24); &psrld ("mm6",24);
+ &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= r0<<8
+ &pxor ("mm0","mm2"); &pxor ("mm4","mm6"); # ^= r0>>24
+
+ &movq ("mm3","mm1"); &movq ("mm7","mm5");
+ &movq ("mm2",&QWP(0,$key)); &movq ("mm6",&QWP(8,$key));
+ &psrld ("mm1",8); &psrld ("mm5",8);
+ &mov ($s0,&DWP(0-128,$tbl));
+ &pslld ("mm3",24); &pslld ("mm7",24);
+ &mov ($s1,&DWP(64-128,$tbl));
+ &pxor ("mm0","mm1"); &pxor ("mm4","mm5"); # ^= (r2^r0)<<8
+ &mov ($s2,&DWP(128-128,$tbl));
+ &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= (r2^r0)>>24
+ &mov ($s3,&DWP(192-128,$tbl));
+
+ &pxor ("mm0","mm2"); &pxor ("mm4","mm6");
+ &jmp (&label("loop"));
+
+ &set_label("out",16);
+ &pxor ("mm0",&QWP(0,$key));
+ &pxor ("mm4",&QWP(8,$key));
+
+ &ret ();
+&function_end_B("_sse_AES_encrypt_compact");
+ }
+
+######################################################################
+# Vanilla block function.
+######################################################################
+
+sub encstep()
+{ my ($i,$te,@s) = @_;
+ my $tmp = $key;
+ my $out = $i==3?$s[0]:$acc;
+
+ # lines marked with #%e?x[i] denote "reordered" instructions...
+ if ($i==3) { &mov ($key,$__key); }##%edx
+ else { &mov ($out,$s[0]);
+ &and ($out,0xFF); }
+ if ($i==1) { &shr ($s[0],16); }#%ebx[1]
+ if ($i==2) { &shr ($s[0],24); }#%ecx[2]
+ &mov ($out,&DWP(0,$te,$out,8));
+
+ if ($i==3) { $tmp=$s[1]; }##%eax
+ &movz ($tmp,&HB($s[1]));
+ &xor ($out,&DWP(3,$te,$tmp,8));
+
+ if ($i==3) { $tmp=$s[2]; &mov ($s[1],$__s0); }##%ebx
+ else { &mov ($tmp,$s[2]);
+ &shr ($tmp,16); }
+ if ($i==2) { &and ($s[1],0xFF); }#%edx[2]
+ &and ($tmp,0xFF);
+ &xor ($out,&DWP(2,$te,$tmp,8));
+
+ if ($i==3) { $tmp=$s[3]; &mov ($s[2],$__s1); }##%ecx
+ elsif($i==2){ &movz ($tmp,&HB($s[3])); }#%ebx[2]
+ else { &mov ($tmp,$s[3]);
+ &shr ($tmp,24) }
+ &xor ($out,&DWP(1,$te,$tmp,8));
+ if ($i<2) { &mov (&DWP(4+4*$i,"esp"),$out); }
+ if ($i==3) { &mov ($s[3],$acc); }
+ &comment();
+}
+
+sub enclast()
+{ my ($i,$te,@s)=@_;
+ my $tmp = $key;
+ my $out = $i==3?$s[0]:$acc;
+
+ if ($i==3) { &mov ($key,$__key); }##%edx
+ else { &mov ($out,$s[0]); }
+ &and ($out,0xFF);
+ if ($i==1) { &shr ($s[0],16); }#%ebx[1]
+ if ($i==2) { &shr ($s[0],24); }#%ecx[2]
+ &mov ($out,&DWP(2,$te,$out,8));
+ &and ($out,0x000000ff);
+
+ if ($i==3) { $tmp=$s[1]; }##%eax
+ &movz ($tmp,&HB($s[1]));
+ &mov ($tmp,&DWP(0,$te,$tmp,8));
+ &and ($tmp,0x0000ff00);
+ &xor ($out,$tmp);
+
+ if ($i==3) { $tmp=$s[2]; &mov ($s[1],$__s0); }##%ebx
+ else { &mov ($tmp,$s[2]);
+ &shr ($tmp,16); }
+ if ($i==2) { &and ($s[1],0xFF); }#%edx[2]
+ &and ($tmp,0xFF);
+ &mov ($tmp,&DWP(0,$te,$tmp,8));
+ &and ($tmp,0x00ff0000);
+ &xor ($out,$tmp);
+
+ if ($i==3) { $tmp=$s[3]; &mov ($s[2],$__s1); }##%ecx
+ elsif($i==2){ &movz ($tmp,&HB($s[3])); }#%ebx[2]
+ else { &mov ($tmp,$s[3]);
+ &shr ($tmp,24); }
+ &mov ($tmp,&DWP(2,$te,$tmp,8));
+ &and ($tmp,0xff000000);
+ &xor ($out,$tmp);
+ if ($i<2) { &mov (&DWP(4+4*$i,"esp"),$out); }
+ if ($i==3) { &mov ($s[3],$acc); }
+}
+
+&function_begin_B("_x86_AES_encrypt");
+ if ($vertical_spin) {
+ # I need high parts of volatile registers to be accessible...
+ &exch ($s1="edi",$key="ebx");
+ &mov ($s2="esi",$acc="ecx");
+ }
+
+ # note that caller is expected to allocate stack frame for me!
+ &mov ($__key,$key); # save key
+
+ &xor ($s0,&DWP(0,$key)); # xor with key
+ &xor ($s1,&DWP(4,$key));
+ &xor ($s2,&DWP(8,$key));
+ &xor ($s3,&DWP(12,$key));
+
+ &mov ($acc,&DWP(240,$key)); # load key->rounds
+
+ if ($small_footprint) {
+ &lea ($acc,&DWP(-2,$acc,$acc));
+ &lea ($acc,&DWP(0,$key,$acc,8));
+ &mov ($__end,$acc); # end of key schedule
+
+ &set_label("loop",16);
+ if ($vertical_spin) {
+ &encvert($tbl,$s0,$s1,$s2,$s3);
+ } else {
+ &encstep(0,$tbl,$s0,$s1,$s2,$s3);
+ &encstep(1,$tbl,$s1,$s2,$s3,$s0);
+ &encstep(2,$tbl,$s2,$s3,$s0,$s1);
+ &encstep(3,$tbl,$s3,$s0,$s1,$s2);
+ }
+ &add ($key,16); # advance rd_key
+ &xor ($s0,&DWP(0,$key));
+ &xor ($s1,&DWP(4,$key));
+ &xor ($s2,&DWP(8,$key));
+ &xor ($s3,&DWP(12,$key));
+ &cmp ($key,$__end);
+ &mov ($__key,$key);
+ &jb (&label("loop"));
+ }
+ else {
+ &cmp ($acc,10);
+ &jle (&label("10rounds"));
+ &cmp ($acc,12);
+ &jle (&label("12rounds"));
+
+ &set_label("14rounds",4);
+ for ($i=1;$i<3;$i++) {
+ if ($vertical_spin) {
+ &encvert($tbl,$s0,$s1,$s2,$s3);
+ } else {
+ &encstep(0,$tbl,$s0,$s1,$s2,$s3);
+ &encstep(1,$tbl,$s1,$s2,$s3,$s0);
+ &encstep(2,$tbl,$s2,$s3,$s0,$s1);
+ &encstep(3,$tbl,$s3,$s0,$s1,$s2);
+ }
+ &xor ($s0,&DWP(16*$i+0,$key));
+ &xor ($s1,&DWP(16*$i+4,$key));
+ &xor ($s2,&DWP(16*$i+8,$key));
+ &xor ($s3,&DWP(16*$i+12,$key));
+ }
+ &add ($key,32);
+ &mov ($__key,$key); # advance rd_key
+ &set_label("12rounds",4);
+ for ($i=1;$i<3;$i++) {
+ if ($vertical_spin) {
+ &encvert($tbl,$s0,$s1,$s2,$s3);
+ } else {
+ &encstep(0,$tbl,$s0,$s1,$s2,$s3);
+ &encstep(1,$tbl,$s1,$s2,$s3,$s0);
+ &encstep(2,$tbl,$s2,$s3,$s0,$s1);
+ &encstep(3,$tbl,$s3,$s0,$s1,$s2);
+ }
+ &xor ($s0,&DWP(16*$i+0,$key));
+ &xor ($s1,&DWP(16*$i+4,$key));
+ &xor ($s2,&DWP(16*$i+8,$key));
+ &xor ($s3,&DWP(16*$i+12,$key));
+ }
+ &add ($key,32);
+ &mov ($__key,$key); # advance rd_key
+ &set_label("10rounds",4);
+ for ($i=1;$i<10;$i++) {
+ if ($vertical_spin) {
+ &encvert($tbl,$s0,$s1,$s2,$s3);
+ } else {
+ &encstep(0,$tbl,$s0,$s1,$s2,$s3);
+ &encstep(1,$tbl,$s1,$s2,$s3,$s0);
+ &encstep(2,$tbl,$s2,$s3,$s0,$s1);
+ &encstep(3,$tbl,$s3,$s0,$s1,$s2);
+ }
+ &xor ($s0,&DWP(16*$i+0,$key));
+ &xor ($s1,&DWP(16*$i+4,$key));
+ &xor ($s2,&DWP(16*$i+8,$key));
+ &xor ($s3,&DWP(16*$i+12,$key));
+ }
+ }
+
+ if ($vertical_spin) {
+ # "reincarnate" some registers for "horizontal" spin...
+ &mov ($s1="ebx",$key="edi");
+ &mov ($s2="ecx",$acc="esi");
+ }
+ &enclast(0,$tbl,$s0,$s1,$s2,$s3);
+ &enclast(1,$tbl,$s1,$s2,$s3,$s0);
+ &enclast(2,$tbl,$s2,$s3,$s0,$s1);
+ &enclast(3,$tbl,$s3,$s0,$s1,$s2);
+
+ &add ($key,$small_footprint?16:160);
+ &xor ($s0,&DWP(0,$key));
+ &xor ($s1,&DWP(4,$key));
+ &xor ($s2,&DWP(8,$key));
+ &xor ($s3,&DWP(12,$key));
+
+ &ret ();
+
+&set_label("AES_Te",64); # Yes! I keep it in the code segment!
+ &_data_word(0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6);
+ &_data_word(0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591);
+ &_data_word(0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56);
+ &_data_word(0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec);
+ &_data_word(0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa);
+ &_data_word(0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb);
+ &_data_word(0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45);
+ &_data_word(0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b);
+ &_data_word(0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c);
+ &_data_word(0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83);
+ &_data_word(0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9);
+ &_data_word(0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a);
+ &_data_word(0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d);
+ &_data_word(0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f);
+ &_data_word(0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df);
+ &_data_word(0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea);
+ &_data_word(0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34);
+ &_data_word(0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b);
+ &_data_word(0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d);
+ &_data_word(0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413);
+ &_data_word(0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1);
+ &_data_word(0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6);
+ &_data_word(0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972);
+ &_data_word(0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85);
+ &_data_word(0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed);
+ &_data_word(0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511);
+ &_data_word(0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe);
+ &_data_word(0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b);
+ &_data_word(0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05);
+ &_data_word(0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1);
+ &_data_word(0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142);
+ &_data_word(0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf);
+ &_data_word(0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3);
+ &_data_word(0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e);
+ &_data_word(0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a);
+ &_data_word(0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6);
+ &_data_word(0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3);
+ &_data_word(0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b);
+ &_data_word(0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428);
+ &_data_word(0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad);
+ &_data_word(0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14);
+ &_data_word(0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8);
+ &_data_word(0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4);
+ &_data_word(0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2);
+ &_data_word(0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda);
+ &_data_word(0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949);
+ &_data_word(0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf);
+ &_data_word(0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810);
+ &_data_word(0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c);
+ &_data_word(0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697);
+ &_data_word(0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e);
+ &_data_word(0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f);
+ &_data_word(0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc);
+ &_data_word(0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c);
+ &_data_word(0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969);
+ &_data_word(0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27);
+ &_data_word(0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122);
+ &_data_word(0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433);
+ &_data_word(0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9);
+ &_data_word(0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5);
+ &_data_word(0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a);
+ &_data_word(0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0);
+ &_data_word(0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e);
+ &_data_word(0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c);
+
+#Te4 # four copies of Te4 to choose from to avoid L1 aliasing
+ &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5);
+ &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76);
+ &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0);
+ &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0);
+ &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc);
+ &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15);
+ &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a);
+ &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75);
+ &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0);
+ &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84);
+ &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b);
+ &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf);
+ &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85);
+ &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8);
+ &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5);
+ &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2);
+ &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17);
+ &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73);
+ &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88);
+ &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb);
+ &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c);
+ &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79);
+ &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9);
+ &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08);
+ &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6);
+ &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a);
+ &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e);
+ &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e);
+ &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94);
+ &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf);
+ &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68);
+ &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16);
+
+ &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5);
+ &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76);
+ &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0);
+ &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0);
+ &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc);
+ &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15);
+ &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a);
+ &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75);
+ &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0);
+ &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84);
+ &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b);
+ &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf);
+ &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85);
+ &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8);
+ &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5);
+ &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2);
+ &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17);
+ &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73);
+ &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88);
+ &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb);
+ &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c);
+ &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79);
+ &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9);
+ &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08);
+ &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6);
+ &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a);
+ &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e);
+ &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e);
+ &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94);
+ &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf);
+ &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68);
+ &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16);
+
+ &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5);
+ &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76);
+ &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0);
+ &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0);
+ &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc);
+ &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15);
+ &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a);
+ &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75);
+ &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0);
+ &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84);
+ &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b);
+ &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf);
+ &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85);
+ &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8);
+ &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5);
+ &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2);
+ &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17);
+ &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73);
+ &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88);
+ &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb);
+ &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c);
+ &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79);
+ &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9);
+ &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08);
+ &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6);
+ &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a);
+ &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e);
+ &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e);
+ &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94);
+ &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf);
+ &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68);
+ &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16);
+
+ &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5);
+ &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76);
+ &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0);
+ &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0);
+ &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc);
+ &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15);
+ &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a);
+ &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75);
+ &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0);
+ &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84);
+ &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b);
+ &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf);
+ &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85);
+ &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8);
+ &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5);
+ &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2);
+ &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17);
+ &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73);
+ &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88);
+ &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb);
+ &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c);
+ &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79);
+ &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9);
+ &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08);
+ &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6);
+ &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a);
+ &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e);
+ &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e);
+ &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94);
+ &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf);
+ &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68);
+ &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16);
+#rcon:
+ &data_word(0x00000001, 0x00000002, 0x00000004, 0x00000008);
+ &data_word(0x00000010, 0x00000020, 0x00000040, 0x00000080);
+ &data_word(0x0000001b, 0x00000036, 0x00000000, 0x00000000);
+ &data_word(0x00000000, 0x00000000, 0x00000000, 0x00000000);
+&function_end_B("_x86_AES_encrypt");
+
+# void AES_encrypt (const void *inp,void *out,const AES_KEY *key);
+&function_begin("AES_encrypt");
+ &mov ($acc,&wparam(0)); # load inp
+ &mov ($key,&wparam(2)); # load key
+
+ &mov ($s0,"esp");
+ &sub ("esp",36);
+ &and ("esp",-64); # align to cache-line
+
+ # place stack frame just "above" the key schedule
+ &lea ($s1,&DWP(-64-63,$key));
+ &sub ($s1,"esp");
+ &neg ($s1);
+ &and ($s1,0x3C0); # modulo 1024, but aligned to cache-line
+ &sub ("esp",$s1);
+ &add ("esp",4); # 4 is reserved for caller's return address
+ &mov ($_esp,$s0); # save stack pointer
+
+ &call (&label("pic_point")); # make it PIC!
+ &set_label("pic_point");
+ &blindpop($tbl);
+ &picmeup($s0,"OPENSSL_ia32cap_P",$tbl,&label("pic_point")) if (!$x86only);
+ &lea ($tbl,&DWP(&label("AES_Te")."-".&label("pic_point"),$tbl));
+
+ # pick Te4 copy which can't "overlap" with stack frame or key schedule
+ &lea ($s1,&DWP(768-4,"esp"));
+ &sub ($s1,$tbl);
+ &and ($s1,0x300);
+ &lea ($tbl,&DWP(2048+128,$tbl,$s1));
+
+ if (!$x86only) {
+ &bt (&DWP(0,$s0),25); # check for SSE bit
+ &jnc (&label("x86"));
+
+ &movq ("mm0",&QWP(0,$acc));
+ &movq ("mm4",&QWP(8,$acc));
+ &call ("_sse_AES_encrypt_compact");
+ &mov ("esp",$_esp); # restore stack pointer
+ &mov ($acc,&wparam(1)); # load out
+ &movq (&QWP(0,$acc),"mm0"); # write output data
+ &movq (&QWP(8,$acc),"mm4");
+ &emms ();
+ &function_end_A();
+ }
+ &set_label("x86",16);
+ &mov ($_tbl,$tbl);
+ &mov ($s0,&DWP(0,$acc)); # load input data
+ &mov ($s1,&DWP(4,$acc));
+ &mov ($s2,&DWP(8,$acc));
+ &mov ($s3,&DWP(12,$acc));
+ &call ("_x86_AES_encrypt_compact");
+ &mov ("esp",$_esp); # restore stack pointer
+ &mov ($acc,&wparam(1)); # load out
+ &mov (&DWP(0,$acc),$s0); # write output data
+ &mov (&DWP(4,$acc),$s1);
+ &mov (&DWP(8,$acc),$s2);
+ &mov (&DWP(12,$acc),$s3);
+&function_end("AES_encrypt");
+
+#--------------------------------------------------------------------#
+
+######################################################################
+# "Compact" block function
+######################################################################
+
+sub deccompact()
+{ my $Fn = \&mov;
+ while ($#_>5) { pop(@_); $Fn=sub{}; }
+ my ($i,$td,@s)=@_;
+ my $tmp = $key;
+ my $out = $i==3?$s[0]:$acc;
+
+ # $Fn is used in first compact round and its purpose is to
+ # void restoration of some values from stack, so that after
+ # 4xdeccompact with extra argument $key, $s0 and $s1 values
+ # are left there...
+ if($i==3) { &$Fn ($key,$__key); }
+ else { &mov ($out,$s[0]); }
+ &and ($out,0xFF);
+ &movz ($out,&BP(-128,$td,$out,1));
+
+ if ($i==3) { $tmp=$s[1]; }
+ &movz ($tmp,&HB($s[1]));
+ &movz ($tmp,&BP(-128,$td,$tmp,1));
+ &shl ($tmp,8);
+ &xor ($out,$tmp);
+
+ if ($i==3) { $tmp=$s[2]; &mov ($s[1],$acc); }
+ else { mov ($tmp,$s[2]); }
+ &shr ($tmp,16);
+ &and ($tmp,0xFF);
+ &movz ($tmp,&BP(-128,$td,$tmp,1));
+ &shl ($tmp,16);
+ &xor ($out,$tmp);
+
+ if ($i==3) { $tmp=$s[3]; &$Fn ($s[2],$__s1); }
+ else { &mov ($tmp,$s[3]); }
+ &shr ($tmp,24);
+ &movz ($tmp,&BP(-128,$td,$tmp,1));
+ &shl ($tmp,24);
+ &xor ($out,$tmp);
+ if ($i<2) { &mov (&DWP(4+4*$i,"esp"),$out); }
+ if ($i==3) { &$Fn ($s[3],$__s0); }
+}
+
+# must be called with 2,3,0,1 as argument sequence!!!
+sub dectransform()
+{ my @s = ($s0,$s1,$s2,$s3);
+ my $i = shift;
+ my $tmp = $key;
+ my $tp2 = @s[($i+2)%4]; $tp2 = @s[2] if ($i==1);
+ my $tp4 = @s[($i+3)%4]; $tp4 = @s[3] if ($i==1);
+ my $tp8 = $tbl;
+
+ &mov ($tmp,0x80808080);
+ &and ($tmp,$s[$i]);
+ &mov ($acc,$tmp);
+ &shr ($tmp,7);
+ &lea ($tp2,&DWP(0,$s[$i],$s[$i]));
+ &sub ($acc,$tmp);
+ &and ($tp2,0xfefefefe);
+ &and ($acc,0x1b1b1b1b);
+ &xor ($tp2,$acc);
+ &mov ($tmp,0x80808080);
+
+ &and ($tmp,$tp2);
+ &mov ($acc,$tmp);
+ &shr ($tmp,7);
+ &lea ($tp4,&DWP(0,$tp2,$tp2));
+ &sub ($acc,$tmp);
+ &and ($tp4,0xfefefefe);
+ &and ($acc,0x1b1b1b1b);
+ &xor ($tp2,$s[$i]); # tp2^tp1
+ &xor ($tp4,$acc);
+ &mov ($tmp,0x80808080);
+
+ &and ($tmp,$tp4);
+ &mov ($acc,$tmp);
+ &shr ($tmp,7);
+ &lea ($tp8,&DWP(0,$tp4,$tp4));
+ &sub ($acc,$tmp);
+ &and ($tp8,0xfefefefe);
+ &and ($acc,0x1b1b1b1b);
+ &xor ($tp4,$s[$i]); # tp4^tp1
+ &rotl ($s[$i],8); # = ROTATE(tp1,8)
+ &xor ($tp8,$acc);
+
+ &xor ($s[$i],$tp2);
+ &xor ($tp2,$tp8);
+ &xor ($s[$i],$tp4);
+ &xor ($tp4,$tp8);
+ &rotl ($tp2,24);
+ &xor ($s[$i],$tp8); # ^= tp8^(tp4^tp1)^(tp2^tp1)
+ &rotl ($tp4,16);
+ &xor ($s[$i],$tp2); # ^= ROTATE(tp8^tp2^tp1,24)
+ &rotl ($tp8,8);
+ &xor ($s[$i],$tp4); # ^= ROTATE(tp8^tp4^tp1,16)
+ &mov ($s[0],$__s0) if($i==2); #prefetch $s0
+ &mov ($s[1],$__s1) if($i==3); #prefetch $s1
+ &mov ($s[2],$__s2) if($i==1);
+ &xor ($s[$i],$tp8); # ^= ROTATE(tp8,8)
+
+ &mov ($s[3],$__s3) if($i==1);
+ &mov (&DWP(4+4*$i,"esp"),$s[$i]) if($i>=2);
+}
+
+&function_begin_B("_x86_AES_decrypt_compact");
+ # note that caller is expected to allocate stack frame for me!
+ &mov ($__key,$key); # save key
+
+ &xor ($s0,&DWP(0,$key)); # xor with key
+ &xor ($s1,&DWP(4,$key));
+ &xor ($s2,&DWP(8,$key));
+ &xor ($s3,&DWP(12,$key));
+
+ &mov ($acc,&DWP(240,$key)); # load key->rounds
+
+ &lea ($acc,&DWP(-2,$acc,$acc));
+ &lea ($acc,&DWP(0,$key,$acc,8));
+ &mov ($__end,$acc); # end of key schedule
+
+ # prefetch Td4
+ &mov ($key,&DWP(0-128,$tbl));
+ &mov ($acc,&DWP(32-128,$tbl));
+ &mov ($key,&DWP(64-128,$tbl));
+ &mov ($acc,&DWP(96-128,$tbl));
+ &mov ($key,&DWP(128-128,$tbl));
+ &mov ($acc,&DWP(160-128,$tbl));
+ &mov ($key,&DWP(192-128,$tbl));
+ &mov ($acc,&DWP(224-128,$tbl));
+
+ &set_label("loop",16);
+
+ &deccompact(0,$tbl,$s0,$s3,$s2,$s1,1);
+ &deccompact(1,$tbl,$s1,$s0,$s3,$s2,1);
+ &deccompact(2,$tbl,$s2,$s1,$s0,$s3,1);
+ &deccompact(3,$tbl,$s3,$s2,$s1,$s0,1);
+ &dectransform(2);
+ &dectransform(3);
+ &dectransform(0);
+ &dectransform(1);
+ &mov ($key,$__key);
+ &mov ($tbl,$__tbl);
+ &add ($key,16); # advance rd_key
+ &xor ($s0,&DWP(0,$key));
+ &xor ($s1,&DWP(4,$key));
+ &xor ($s2,&DWP(8,$key));
+ &xor ($s3,&DWP(12,$key));
+
+ &cmp ($key,$__end);
+ &mov ($__key,$key);
+ &jb (&label("loop"));
+
+ &deccompact(0,$tbl,$s0,$s3,$s2,$s1);
+ &deccompact(1,$tbl,$s1,$s0,$s3,$s2);
+ &deccompact(2,$tbl,$s2,$s1,$s0,$s3);
+ &deccompact(3,$tbl,$s3,$s2,$s1,$s0);
+
+ &xor ($s0,&DWP(16,$key));
+ &xor ($s1,&DWP(20,$key));
+ &xor ($s2,&DWP(24,$key));
+ &xor ($s3,&DWP(28,$key));
+
+ &ret ();
+&function_end_B("_x86_AES_decrypt_compact");
+
+######################################################################
+# "Compact" SSE block function.
+######################################################################
+
+sub sse_deccompact()
+{
+ &pshufw ("mm1","mm0",0x0c); # 7, 6, 1, 0
+ &pshufw ("mm5","mm4",0x09); # 13,12,11,10
+ &movd ("eax","mm1"); # 7, 6, 1, 0
+ &movd ("ebx","mm5"); # 13,12,11,10
+ &mov ($__key,$key);
+
+ &movz ($acc,&LB("eax")); # 0
+ &movz ("edx",&HB("eax")); # 1
+ &pshufw ("mm2","mm0",0x06); # 3, 2, 5, 4
+ &movz ("ecx",&BP(-128,$tbl,$acc,1)); # 0
+ &movz ($key,&LB("ebx")); # 10
+ &movz ("edx",&BP(-128,$tbl,"edx",1)); # 1
+ &shr ("eax",16); # 7, 6
+ &shl ("edx",8); # 1
+
+ &movz ($acc,&BP(-128,$tbl,$key,1)); # 10
+ &movz ($key,&HB("ebx")); # 11
+ &shl ($acc,16); # 10
+ &pshufw ("mm6","mm4",0x03); # 9, 8,15,14
+ &or ("ecx",$acc); # 10
+ &movz ($acc,&BP(-128,$tbl,$key,1)); # 11
+ &movz ($key,&HB("eax")); # 7
+ &shl ($acc,24); # 11
+ &shr ("ebx",16); # 13,12
+ &or ("edx",$acc); # 11
+
+ &movz ($acc,&BP(-128,$tbl,$key,1)); # 7
+ &movz ($key,&HB("ebx")); # 13
+ &shl ($acc,24); # 7
+ &or ("ecx",$acc); # 7
+ &movz ($acc,&BP(-128,$tbl,$key,1)); # 13
+ &movz ($key,&LB("eax")); # 6
+ &shl ($acc,8); # 13
+ &movd ("eax","mm2"); # 3, 2, 5, 4
+ &or ("ecx",$acc); # 13
+
+ &movz ($acc,&BP(-128,$tbl,$key,1)); # 6
+ &movz ($key,&LB("ebx")); # 12
+ &shl ($acc,16); # 6
+ &movd ("ebx","mm6"); # 9, 8,15,14
+ &movd ("mm0","ecx"); # t[0] collected
+ &movz ("ecx",&BP(-128,$tbl,$key,1)); # 12
+ &movz ($key,&LB("eax")); # 4
+ &or ("ecx",$acc); # 12
+
+ &movz ($acc,&BP(-128,$tbl,$key,1)); # 4
+ &movz ($key,&LB("ebx")); # 14
+ &or ("edx",$acc); # 4
+ &movz ($acc,&BP(-128,$tbl,$key,1)); # 14
+ &movz ($key,&HB("eax")); # 5
+ &shl ($acc,16); # 14
+ &shr ("eax",16); # 3, 2
+ &or ("edx",$acc); # 14
+
+ &movz ($acc,&BP(-128,$tbl,$key,1)); # 5
+ &movz ($key,&HB("ebx")); # 15
+ &shr ("ebx",16); # 9, 8
+ &shl ($acc,8); # 5
+ &movd ("mm1","edx"); # t[1] collected
+ &movz ("edx",&BP(-128,$tbl,$key,1)); # 15
+ &movz ($key,&HB("ebx")); # 9
+ &shl ("edx",24); # 15
+ &and ("ebx",0xff); # 8
+ &or ("edx",$acc); # 15
+
+ &punpckldq ("mm0","mm1"); # t[0,1] collected
+
+ &movz ($acc,&BP(-128,$tbl,$key,1)); # 9
+ &movz ($key,&LB("eax")); # 2
+ &shl ($acc,8); # 9
+ &movz ("eax",&HB("eax")); # 3
+ &movz ("ebx",&BP(-128,$tbl,"ebx",1)); # 8
+ &or ("ecx",$acc); # 9
+ &movz ($acc,&BP(-128,$tbl,$key,1)); # 2
+ &or ("edx","ebx"); # 8
+ &shl ($acc,16); # 2
+ &movz ("eax",&BP(-128,$tbl,"eax",1)); # 3
+ &or ("edx",$acc); # 2
+ &shl ("eax",24); # 3
+ &or ("ecx","eax"); # 3
+ &mov ($key,$__key);
+ &movd ("mm4","edx"); # t[2] collected
+ &movd ("mm5","ecx"); # t[3] collected
+
+ &punpckldq ("mm4","mm5"); # t[2,3] collected
+}
+
+ if (!$x86only) {
+&function_begin_B("_sse_AES_decrypt_compact");
+ &pxor ("mm0",&QWP(0,$key)); # 7, 6, 5, 4, 3, 2, 1, 0
+ &pxor ("mm4",&QWP(8,$key)); # 15,14,13,12,11,10, 9, 8
+
+ # note that caller is expected to allocate stack frame for me!
+ &mov ($acc,&DWP(240,$key)); # load key->rounds
+ &lea ($acc,&DWP(-2,$acc,$acc));
+ &lea ($acc,&DWP(0,$key,$acc,8));
+ &mov ($__end,$acc); # end of key schedule
+
+ &mov ($s0,0x1b1b1b1b); # magic constant
+ &mov (&DWP(8,"esp"),$s0);
+ &mov (&DWP(12,"esp"),$s0);
+
+ # prefetch Td4
+ &mov ($s0,&DWP(0-128,$tbl));
+ &mov ($s1,&DWP(32-128,$tbl));
+ &mov ($s2,&DWP(64-128,$tbl));
+ &mov ($s3,&DWP(96-128,$tbl));
+ &mov ($s0,&DWP(128-128,$tbl));
+ &mov ($s1,&DWP(160-128,$tbl));
+ &mov ($s2,&DWP(192-128,$tbl));
+ &mov ($s3,&DWP(224-128,$tbl));
+
+ &set_label("loop",16);
+ &sse_deccompact();
+ &add ($key,16);
+ &cmp ($key,$__end);
+ &ja (&label("out"));
+
+ # ROTATE(x^y,N) == ROTATE(x,N)^ROTATE(y,N)
+ &movq ("mm3","mm0"); &movq ("mm7","mm4");
+ &movq ("mm2","mm0",1); &movq ("mm6","mm4",1);
+ &movq ("mm1","mm0"); &movq ("mm5","mm4");
+ &pshufw ("mm0","mm0",0xb1); &pshufw ("mm4","mm4",0xb1);# = ROTATE(tp0,16)
+ &pslld ("mm2",8); &pslld ("mm6",8);
+ &psrld ("mm3",8); &psrld ("mm7",8);
+ &pxor ("mm0","mm2"); &pxor ("mm4","mm6"); # ^= tp0<<8
+ &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= tp0>>8
+ &pslld ("mm2",16); &pslld ("mm6",16);
+ &psrld ("mm3",16); &psrld ("mm7",16);
+ &pxor ("mm0","mm2"); &pxor ("mm4","mm6"); # ^= tp0<<24
+ &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= tp0>>24
+
+ &movq ("mm3",&QWP(8,"esp"));
+ &pxor ("mm2","mm2"); &pxor ("mm6","mm6");
+ &pcmpgtb("mm2","mm1"); &pcmpgtb("mm6","mm5");
+ &pand ("mm2","mm3"); &pand ("mm6","mm3");
+ &paddb ("mm1","mm1"); &paddb ("mm5","mm5");
+ &pxor ("mm1","mm2"); &pxor ("mm5","mm6"); # tp2
+ &movq ("mm3","mm1"); &movq ("mm7","mm5");
+ &movq ("mm2","mm1"); &movq ("mm6","mm5");
+ &pxor ("mm0","mm1"); &pxor ("mm4","mm5"); # ^= tp2
+ &pslld ("mm3",24); &pslld ("mm7",24);
+ &psrld ("mm2",8); &psrld ("mm6",8);
+ &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= tp2<<24
+ &pxor ("mm0","mm2"); &pxor ("mm4","mm6"); # ^= tp2>>8
+
+ &movq ("mm2",&QWP(8,"esp"));
+ &pxor ("mm3","mm3"); &pxor ("mm7","mm7");
+ &pcmpgtb("mm3","mm1"); &pcmpgtb("mm7","mm5");
+ &pand ("mm3","mm2"); &pand ("mm7","mm2");
+ &paddb ("mm1","mm1"); &paddb ("mm5","mm5");
+ &pxor ("mm1","mm3"); &pxor ("mm5","mm7"); # tp4
+ &pshufw ("mm3","mm1",0xb1); &pshufw ("mm7","mm5",0xb1);
+ &pxor ("mm0","mm1"); &pxor ("mm4","mm5"); # ^= tp4
+ &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= ROTATE(tp4,16)
+
+ &pxor ("mm3","mm3"); &pxor ("mm7","mm7");
+ &pcmpgtb("mm3","mm1"); &pcmpgtb("mm7","mm5");
+ &pand ("mm3","mm2"); &pand ("mm7","mm2");
+ &paddb ("mm1","mm1"); &paddb ("mm5","mm5");
+ &pxor ("mm1","mm3"); &pxor ("mm5","mm7"); # tp8
+ &pxor ("mm0","mm1"); &pxor ("mm4","mm5"); # ^= tp8
+ &movq ("mm3","mm1"); &movq ("mm7","mm5");
+ &pshufw ("mm2","mm1",0xb1); &pshufw ("mm6","mm5",0xb1);
+ &pxor ("mm0","mm2"); &pxor ("mm4","mm6"); # ^= ROTATE(tp8,16)
+ &pslld ("mm1",8); &pslld ("mm5",8);
+ &psrld ("mm3",8); &psrld ("mm7",8);
+ &movq ("mm2",&QWP(0,$key)); &movq ("mm6",&QWP(8,$key));
+ &pxor ("mm0","mm1"); &pxor ("mm4","mm5"); # ^= tp8<<8
+ &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= tp8>>8
+ &mov ($s0,&DWP(0-128,$tbl));
+ &pslld ("mm1",16); &pslld ("mm5",16);
+ &mov ($s1,&DWP(64-128,$tbl));
+ &psrld ("mm3",16); &psrld ("mm7",16);
+ &mov ($s2,&DWP(128-128,$tbl));
+ &pxor ("mm0","mm1"); &pxor ("mm4","mm5"); # ^= tp8<<24
+ &mov ($s3,&DWP(192-128,$tbl));
+ &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= tp8>>24
+
+ &pxor ("mm0","mm2"); &pxor ("mm4","mm6");
+ &jmp (&label("loop"));
+
+ &set_label("out",16);
+ &pxor ("mm0",&QWP(0,$key));
+ &pxor ("mm4",&QWP(8,$key));
+
+ &ret ();
+&function_end_B("_sse_AES_decrypt_compact");
+ }
+
+######################################################################
+# Vanilla block function.
+######################################################################
+
+sub decstep()
+{ my ($i,$td,@s) = @_;
+ my $tmp = $key;
+ my $out = $i==3?$s[0]:$acc;
+
+ # no instructions are reordered, as performance appears
+ # optimal... or rather that all attempts to reorder didn't
+ # result in better performance [which by the way is not a
+ # bit lower than ecryption].
+ if($i==3) { &mov ($key,$__key); }
+ else { &mov ($out,$s[0]); }
+ &and ($out,0xFF);
+ &mov ($out,&DWP(0,$td,$out,8));
+
+ if ($i==3) { $tmp=$s[1]; }
+ &movz ($tmp,&HB($s[1]));
+ &xor ($out,&DWP(3,$td,$tmp,8));
+
+ if ($i==3) { $tmp=$s[2]; &mov ($s[1],$acc); }
+ else { &mov ($tmp,$s[2]); }
+ &shr ($tmp,16);
+ &and ($tmp,0xFF);
+ &xor ($out,&DWP(2,$td,$tmp,8));
+
+ if ($i==3) { $tmp=$s[3]; &mov ($s[2],$__s1); }
+ else { &mov ($tmp,$s[3]); }
+ &shr ($tmp,24);
+ &xor ($out,&DWP(1,$td,$tmp,8));
+ if ($i<2) { &mov (&DWP(4+4*$i,"esp"),$out); }
+ if ($i==3) { &mov ($s[3],$__s0); }
+ &comment();
+}
+
+sub declast()
+{ my ($i,$td,@s)=@_;
+ my $tmp = $key;
+ my $out = $i==3?$s[0]:$acc;
+
+ if($i==0) { &lea ($td,&DWP(2048+128,$td));
+ &mov ($tmp,&DWP(0-128,$td));
+ &mov ($acc,&DWP(32-128,$td));
+ &mov ($tmp,&DWP(64-128,$td));
+ &mov ($acc,&DWP(96-128,$td));
+ &mov ($tmp,&DWP(128-128,$td));
+ &mov ($acc,&DWP(160-128,$td));
+ &mov ($tmp,&DWP(192-128,$td));
+ &mov ($acc,&DWP(224-128,$td));
+ &lea ($td,&DWP(-128,$td)); }
+ if($i==3) { &mov ($key,$__key); }
+ else { &mov ($out,$s[0]); }
+ &and ($out,0xFF);
+ &movz ($out,&BP(0,$td,$out,1));
+
+ if ($i==3) { $tmp=$s[1]; }
+ &movz ($tmp,&HB($s[1]));
+ &movz ($tmp,&BP(0,$td,$tmp,1));
+ &shl ($tmp,8);
+ &xor ($out,$tmp);
+
+ if ($i==3) { $tmp=$s[2]; &mov ($s[1],$acc); }
+ else { mov ($tmp,$s[2]); }
+ &shr ($tmp,16);
+ &and ($tmp,0xFF);
+ &movz ($tmp,&BP(0,$td,$tmp,1));
+ &shl ($tmp,16);
+ &xor ($out,$tmp);
+
+ if ($i==3) { $tmp=$s[3]; &mov ($s[2],$__s1); }
+ else { &mov ($tmp,$s[3]); }
+ &shr ($tmp,24);
+ &movz ($tmp,&BP(0,$td,$tmp,1));
+ &shl ($tmp,24);
+ &xor ($out,$tmp);
+ if ($i<2) { &mov (&DWP(4+4*$i,"esp"),$out); }
+ if ($i==3) { &mov ($s[3],$__s0);
+ &lea ($td,&DWP(-2048,$td)); }
+}
+
+&function_begin_B("_x86_AES_decrypt");
+ # note that caller is expected to allocate stack frame for me!
+ &mov ($__key,$key); # save key
+
+ &xor ($s0,&DWP(0,$key)); # xor with key
+ &xor ($s1,&DWP(4,$key));
+ &xor ($s2,&DWP(8,$key));
+ &xor ($s3,&DWP(12,$key));
+
+ &mov ($acc,&DWP(240,$key)); # load key->rounds
+
+ if ($small_footprint) {
+ &lea ($acc,&DWP(-2,$acc,$acc));
+ &lea ($acc,&DWP(0,$key,$acc,8));
+ &mov ($__end,$acc); # end of key schedule
+ &set_label("loop",16);
+ &decstep(0,$tbl,$s0,$s3,$s2,$s1);
+ &decstep(1,$tbl,$s1,$s0,$s3,$s2);
+ &decstep(2,$tbl,$s2,$s1,$s0,$s3);
+ &decstep(3,$tbl,$s3,$s2,$s1,$s0);
+ &add ($key,16); # advance rd_key
+ &xor ($s0,&DWP(0,$key));
+ &xor ($s1,&DWP(4,$key));
+ &xor ($s2,&DWP(8,$key));
+ &xor ($s3,&DWP(12,$key));
+ &cmp ($key,$__end);
+ &mov ($__key,$key);
+ &jb (&label("loop"));
+ }
+ else {
+ &cmp ($acc,10);
+ &jle (&label("10rounds"));
+ &cmp ($acc,12);
+ &jle (&label("12rounds"));
+
+ &set_label("14rounds",4);
+ for ($i=1;$i<3;$i++) {
+ &decstep(0,$tbl,$s0,$s3,$s2,$s1);
+ &decstep(1,$tbl,$s1,$s0,$s3,$s2);
+ &decstep(2,$tbl,$s2,$s1,$s0,$s3);
+ &decstep(3,$tbl,$s3,$s2,$s1,$s0);
+ &xor ($s0,&DWP(16*$i+0,$key));
+ &xor ($s1,&DWP(16*$i+4,$key));
+ &xor ($s2,&DWP(16*$i+8,$key));
+ &xor ($s3,&DWP(16*$i+12,$key));
+ }
+ &add ($key,32);
+ &mov ($__key,$key); # advance rd_key
+ &set_label("12rounds",4);
+ for ($i=1;$i<3;$i++) {
+ &decstep(0,$tbl,$s0,$s3,$s2,$s1);
+ &decstep(1,$tbl,$s1,$s0,$s3,$s2);
+ &decstep(2,$tbl,$s2,$s1,$s0,$s3);
+ &decstep(3,$tbl,$s3,$s2,$s1,$s0);
+ &xor ($s0,&DWP(16*$i+0,$key));
+ &xor ($s1,&DWP(16*$i+4,$key));
+ &xor ($s2,&DWP(16*$i+8,$key));
+ &xor ($s3,&DWP(16*$i+12,$key));
+ }
+ &add ($key,32);
+ &mov ($__key,$key); # advance rd_key
+ &set_label("10rounds",4);
+ for ($i=1;$i<10;$i++) {
+ &decstep(0,$tbl,$s0,$s3,$s2,$s1);
+ &decstep(1,$tbl,$s1,$s0,$s3,$s2);
+ &decstep(2,$tbl,$s2,$s1,$s0,$s3);
+ &decstep(3,$tbl,$s3,$s2,$s1,$s0);
+ &xor ($s0,&DWP(16*$i+0,$key));
+ &xor ($s1,&DWP(16*$i+4,$key));
+ &xor ($s2,&DWP(16*$i+8,$key));
+ &xor ($s3,&DWP(16*$i+12,$key));
+ }
+ }
+
+ &declast(0,$tbl,$s0,$s3,$s2,$s1);
+ &declast(1,$tbl,$s1,$s0,$s3,$s2);
+ &declast(2,$tbl,$s2,$s1,$s0,$s3);
+ &declast(3,$tbl,$s3,$s2,$s1,$s0);
+
+ &add ($key,$small_footprint?16:160);
+ &xor ($s0,&DWP(0,$key));
+ &xor ($s1,&DWP(4,$key));
+ &xor ($s2,&DWP(8,$key));
+ &xor ($s3,&DWP(12,$key));
+
+ &ret ();
+
+&set_label("AES_Td",64); # Yes! I keep it in the code segment!
+ &_data_word(0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a);
+ &_data_word(0xcb6bab3b, 0xf1459d1f, 0xab58faac, 0x9303e34b);
+ &_data_word(0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5);
+ &_data_word(0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 0x8fa362b5);
+ &_data_word(0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d);
+ &_data_word(0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b);
+ &_data_word(0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295);
+ &_data_word(0x2d83bed4, 0xd3217458, 0x2969e049, 0x44c8c98e);
+ &_data_word(0x6a89c275, 0x78798ef4, 0x6b3e5899, 0xdd71b927);
+ &_data_word(0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d);
+ &_data_word(0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362);
+ &_data_word(0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9);
+ &_data_word(0x58684870, 0x19fd458f, 0x876cde94, 0xb7f87b52);
+ &_data_word(0x23d373ab, 0xe2024b72, 0x578f1fe3, 0x2aab5566);
+ &_data_word(0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3);
+ &_data_word(0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed);
+ &_data_word(0x2b1ccf8a, 0x92b479a7, 0xf0f207f3, 0xa1e2694e);
+ &_data_word(0xcdf4da65, 0xd5be0506, 0x1f6234d1, 0x8afea6c4);
+ &_data_word(0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4);
+ &_data_word(0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd);
+ &_data_word(0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d);
+ &_data_word(0xb58d5491, 0x055dc471, 0x6fd40604, 0xff155060);
+ &_data_word(0x24fb9819, 0x97e9bdd6, 0xcc434089, 0x779ed967);
+ &_data_word(0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879);
+ &_data_word(0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000);
+ &_data_word(0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c);
+ &_data_word(0xfbff0efd, 0x5638850f, 0x1ed5ae3d, 0x27392d36);
+ &_data_word(0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624);
+ &_data_word(0xb1670a0c, 0x0fe75793, 0xd296eeb4, 0x9e919b1b);
+ &_data_word(0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c);
+ &_data_word(0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12);
+ &_data_word(0x0b0d090e, 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14);
+ &_data_word(0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3);
+ &_data_word(0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b);
+ &_data_word(0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8);
+ &_data_word(0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684);
+ &_data_word(0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7);
+ &_data_word(0x4b2f9e1d, 0xf330b2dc, 0xec52860d, 0xd0e3c177);
+ &_data_word(0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947);
+ &_data_word(0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322);
+ &_data_word(0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498);
+ &_data_word(0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f);
+ &_data_word(0xe49d3a2c, 0x0d927850, 0x9bcc5f6a, 0x62467e54);
+ &_data_word(0xc2138df6, 0xe8b8d890, 0x5ef7392e, 0xf5afc382);
+ &_data_word(0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf);
+ &_data_word(0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb);
+ &_data_word(0x097826cd, 0xf418596e, 0x01b79aec, 0xa89a4f83);
+ &_data_word(0x656e95e6, 0x7ee6ffaa, 0x08cfbc21, 0xe6e815ef);
+ &_data_word(0xd99be7ba, 0xce366f4a, 0xd4099fea, 0xd67cb029);
+ &_data_word(0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235);
+ &_data_word(0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733);
+ &_data_word(0x4a9804f1, 0xf7daec41, 0x0e50cd7f, 0x2ff69117);
+ &_data_word(0x8dd64d76, 0x4db0ef43, 0x544daacc, 0xdf0496e4);
+ &_data_word(0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 0x7f516546);
+ &_data_word(0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb);
+ &_data_word(0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d);
+ &_data_word(0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb);
+ &_data_word(0xee27a9ce, 0x35c961b7, 0xede51ce1, 0x3cb1477a);
+ &_data_word(0x59dfd29c, 0x3f73f255, 0x79ce1418, 0xbf37c773);
+ &_data_word(0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478);
+ &_data_word(0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2);
+ &_data_word(0x72c31d16, 0x0c25e2bc, 0x8b493c28, 0x41950dff);
+ &_data_word(0x7101a839, 0xdeb30c08, 0x9ce4b4d8, 0x90c15664);
+ &_data_word(0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0);
+
+#Td4: # four copies of Td4 to choose from to avoid L1 aliasing
+ &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38);
+ &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb);
+ &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87);
+ &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb);
+ &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d);
+ &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e);
+ &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2);
+ &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25);
+ &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16);
+ &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92);
+ &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda);
+ &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84);
+ &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a);
+ &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06);
+ &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02);
+ &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b);
+ &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea);
+ &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73);
+ &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85);
+ &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e);
+ &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89);
+ &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b);
+ &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20);
+ &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4);
+ &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31);
+ &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f);
+ &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d);
+ &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef);
+ &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0);
+ &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61);
+ &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26);
+ &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d);
+
+ &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38);
+ &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb);
+ &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87);
+ &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb);
+ &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d);
+ &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e);
+ &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2);
+ &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25);
+ &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16);
+ &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92);
+ &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda);
+ &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84);
+ &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a);
+ &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06);
+ &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02);
+ &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b);
+ &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea);
+ &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73);
+ &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85);
+ &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e);
+ &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89);
+ &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b);
+ &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20);
+ &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4);
+ &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31);
+ &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f);
+ &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d);
+ &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef);
+ &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0);
+ &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61);
+ &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26);
+ &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d);
+
+ &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38);
+ &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb);
+ &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87);
+ &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb);
+ &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d);
+ &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e);
+ &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2);
+ &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25);
+ &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16);
+ &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92);
+ &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda);
+ &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84);
+ &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a);
+ &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06);
+ &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02);
+ &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b);
+ &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea);
+ &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73);
+ &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85);
+ &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e);
+ &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89);
+ &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b);
+ &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20);
+ &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4);
+ &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31);
+ &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f);
+ &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d);
+ &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef);
+ &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0);
+ &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61);
+ &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26);
+ &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d);
+
+ &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38);
+ &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb);
+ &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87);
+ &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb);
+ &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d);
+ &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e);
+ &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2);
+ &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25);
+ &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16);
+ &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92);
+ &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda);
+ &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84);
+ &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a);
+ &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06);
+ &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02);
+ &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b);
+ &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea);
+ &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73);
+ &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85);
+ &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e);
+ &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89);
+ &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b);
+ &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20);
+ &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4);
+ &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31);
+ &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f);
+ &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d);
+ &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef);
+ &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0);
+ &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61);
+ &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26);
+ &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d);
+&function_end_B("_x86_AES_decrypt");
+
+# void AES_decrypt (const void *inp,void *out,const AES_KEY *key);
+&function_begin("AES_decrypt");
+ &mov ($acc,&wparam(0)); # load inp
+ &mov ($key,&wparam(2)); # load key
+
+ &mov ($s0,"esp");
+ &sub ("esp",36);
+ &and ("esp",-64); # align to cache-line
+
+ # place stack frame just "above" the key schedule
+ &lea ($s1,&DWP(-64-63,$key));
+ &sub ($s1,"esp");
+ &neg ($s1);
+ &and ($s1,0x3C0); # modulo 1024, but aligned to cache-line
+ &sub ("esp",$s1);
+ &add ("esp",4); # 4 is reserved for caller's return address
+ &mov ($_esp,$s0); # save stack pointer
+
+ &call (&label("pic_point")); # make it PIC!
+ &set_label("pic_point");
+ &blindpop($tbl);
+ &picmeup($s0,"OPENSSL_ia32cap_P",$tbl,&label("pic_point")) if(!$x86only);
+ &lea ($tbl,&DWP(&label("AES_Td")."-".&label("pic_point"),$tbl));
+
+ # pick Td4 copy which can't "overlap" with stack frame or key schedule
+ &lea ($s1,&DWP(768-4,"esp"));
+ &sub ($s1,$tbl);
+ &and ($s1,0x300);
+ &lea ($tbl,&DWP(2048+128,$tbl,$s1));
+
+ if (!$x86only) {
+ &bt (&DWP(0,$s0),25); # check for SSE bit
+ &jnc (&label("x86"));
+
+ &movq ("mm0",&QWP(0,$acc));
+ &movq ("mm4",&QWP(8,$acc));
+ &call ("_sse_AES_decrypt_compact");
+ &mov ("esp",$_esp); # restore stack pointer
+ &mov ($acc,&wparam(1)); # load out
+ &movq (&QWP(0,$acc),"mm0"); # write output data
+ &movq (&QWP(8,$acc),"mm4");
+ &emms ();
+ &function_end_A();
+ }
+ &set_label("x86",16);
+ &mov ($_tbl,$tbl);
+ &mov ($s0,&DWP(0,$acc)); # load input data
+ &mov ($s1,&DWP(4,$acc));
+ &mov ($s2,&DWP(8,$acc));
+ &mov ($s3,&DWP(12,$acc));
+ &call ("_x86_AES_decrypt_compact");
+ &mov ("esp",$_esp); # restore stack pointer
+ &mov ($acc,&wparam(1)); # load out
+ &mov (&DWP(0,$acc),$s0); # write output data
+ &mov (&DWP(4,$acc),$s1);
+ &mov (&DWP(8,$acc),$s2);
+ &mov (&DWP(12,$acc),$s3);
+&function_end("AES_decrypt");
+
+# void AES_cbc_encrypt (const void char *inp, unsigned char *out,
+# size_t length, const AES_KEY *key,
+# unsigned char *ivp,const int enc);
+{
+# stack frame layout
+# -4(%esp) # return address 0(%esp)
+# 0(%esp) # s0 backing store 4(%esp)
+# 4(%esp) # s1 backing store 8(%esp)
+# 8(%esp) # s2 backing store 12(%esp)
+# 12(%esp) # s3 backing store 16(%esp)
+# 16(%esp) # key backup 20(%esp)
+# 20(%esp) # end of key schedule 24(%esp)
+# 24(%esp) # %ebp backup 28(%esp)
+# 28(%esp) # %esp backup
+my $_inp=&DWP(32,"esp"); # copy of wparam(0)
+my $_out=&DWP(36,"esp"); # copy of wparam(1)
+my $_len=&DWP(40,"esp"); # copy of wparam(2)
+my $_key=&DWP(44,"esp"); # copy of wparam(3)
+my $_ivp=&DWP(48,"esp"); # copy of wparam(4)
+my $_tmp=&DWP(52,"esp"); # volatile variable
+#
+my $ivec=&DWP(60,"esp"); # ivec[16]
+my $aes_key=&DWP(76,"esp"); # copy of aes_key
+my $mark=&DWP(76+240,"esp"); # copy of aes_key->rounds
+
+&function_begin("AES_cbc_encrypt");
+ &mov ($s2 eq "ecx"? $s2 : "",&wparam(2)); # load len
+ &cmp ($s2,0);
+ &je (&label("drop_out"));
+
+ &call (&label("pic_point")); # make it PIC!
+ &set_label("pic_point");
+ &blindpop($tbl);
+ &picmeup($s0,"OPENSSL_ia32cap_P",$tbl,&label("pic_point")) if(!$x86only);
+
+ &cmp (&wparam(5),0);
+ &lea ($tbl,&DWP(&label("AES_Te")."-".&label("pic_point"),$tbl));
+ &jne (&label("picked_te"));
+ &lea ($tbl,&DWP(&label("AES_Td")."-".&label("AES_Te"),$tbl));
+ &set_label("picked_te");
+
+ # one can argue if this is required
+ &pushf ();
+ &cld ();
+
+ &cmp ($s2,$speed_limit);
+ &jb (&label("slow_way"));
+ &test ($s2,15);
+ &jnz (&label("slow_way"));
+ if (!$x86only) {
+ &bt (&DWP(0,$s0),28); # check for hyper-threading bit
+ &jc (&label("slow_way"));
+ }
+ # pre-allocate aligned stack frame...
+ &lea ($acc,&DWP(-80-244,"esp"));
+ &and ($acc,-64);
+
+ # ... and make sure it doesn't alias with $tbl modulo 4096
+ &mov ($s0,$tbl);
+ &lea ($s1,&DWP(2048+256,$tbl));
+ &mov ($s3,$acc);
+ &and ($s0,0xfff); # s = %ebp&0xfff
+ &and ($s1,0xfff); # e = (%ebp+2048+256)&0xfff
+ &and ($s3,0xfff); # p = %esp&0xfff
+
+ &cmp ($s3,$s1); # if (p>=e) %esp =- (p-e);
+ &jb (&label("tbl_break_out"));
+ &sub ($s3,$s1);
+ &sub ($acc,$s3);
+ &jmp (&label("tbl_ok"));
+ &set_label("tbl_break_out",4); # else %esp -= (p-s)&0xfff + framesz;
+ &sub ($s3,$s0);
+ &and ($s3,0xfff);
+ &add ($s3,384);
+ &sub ($acc,$s3);
+ &set_label("tbl_ok",4);
+
+ &lea ($s3,&wparam(0)); # obtain pointer to parameter block
+ &exch ("esp",$acc); # allocate stack frame
+ &add ("esp",4); # reserve for return address!
+ &mov ($_tbl,$tbl); # save %ebp
+ &mov ($_esp,$acc); # save %esp
+
+ &mov ($s0,&DWP(0,$s3)); # load inp
+ &mov ($s1,&DWP(4,$s3)); # load out
+ #&mov ($s2,&DWP(8,$s3)); # load len
+ &mov ($key,&DWP(12,$s3)); # load key
+ &mov ($acc,&DWP(16,$s3)); # load ivp
+ &mov ($s3,&DWP(20,$s3)); # load enc flag
+
+ &mov ($_inp,$s0); # save copy of inp
+ &mov ($_out,$s1); # save copy of out
+ &mov ($_len,$s2); # save copy of len
+ &mov ($_key,$key); # save copy of key
+ &mov ($_ivp,$acc); # save copy of ivp
+
+ &mov ($mark,0); # copy of aes_key->rounds = 0;
+ # do we copy key schedule to stack?
+ &mov ($s1 eq "ebx" ? $s1 : "",$key);
+ &mov ($s2 eq "ecx" ? $s2 : "",244/4);
+ &sub ($s1,$tbl);
+ &mov ("esi",$key);
+ &and ($s1,0xfff);
+ &lea ("edi",$aes_key);
+ &cmp ($s1,2048+256);
+ &jb (&label("do_copy"));
+ &cmp ($s1,4096-244);
+ &jb (&label("skip_copy"));
+ &set_label("do_copy",4);
+ &mov ($_key,"edi");
+ &data_word(0xA5F3F689); # rep movsd
+ &set_label("skip_copy");
+
+ &mov ($key,16);
+ &set_label("prefetch_tbl",4);
+ &mov ($s0,&DWP(0,$tbl));
+ &mov ($s1,&DWP(32,$tbl));
+ &mov ($s2,&DWP(64,$tbl));
+ &mov ($acc,&DWP(96,$tbl));
+ &lea ($tbl,&DWP(128,$tbl));
+ &sub ($key,1);
+ &jnz (&label("prefetch_tbl"));
+ &sub ($tbl,2048);
+
+ &mov ($acc,$_inp);
+ &mov ($key,$_ivp);
+
+ &cmp ($s3,0);
+ &je (&label("fast_decrypt"));
+
+#----------------------------- ENCRYPT -----------------------------#
+ &mov ($s0,&DWP(0,$key)); # load iv
+ &mov ($s1,&DWP(4,$key));
+
+ &set_label("fast_enc_loop",16);
+ &mov ($s2,&DWP(8,$key));
+ &mov ($s3,&DWP(12,$key));
+
+ &xor ($s0,&DWP(0,$acc)); # xor input data
+ &xor ($s1,&DWP(4,$acc));
+ &xor ($s2,&DWP(8,$acc));
+ &xor ($s3,&DWP(12,$acc));
+
+ &mov ($key,$_key); # load key
+ &call ("_x86_AES_encrypt");
+
+ &mov ($acc,$_inp); # load inp
+ &mov ($key,$_out); # load out
+
+ &mov (&DWP(0,$key),$s0); # save output data
+ &mov (&DWP(4,$key),$s1);
+ &mov (&DWP(8,$key),$s2);
+ &mov (&DWP(12,$key),$s3);
+
+ &lea ($acc,&DWP(16,$acc)); # advance inp
+ &mov ($s2,$_len); # load len
+ &mov ($_inp,$acc); # save inp
+ &lea ($s3,&DWP(16,$key)); # advance out
+ &mov ($_out,$s3); # save out
+ &sub ($s2,16); # decrease len
+ &mov ($_len,$s2); # save len
+ &jnz (&label("fast_enc_loop"));
+ &mov ($acc,$_ivp); # load ivp
+ &mov ($s2,&DWP(8,$key)); # restore last 2 dwords
+ &mov ($s3,&DWP(12,$key));
+ &mov (&DWP(0,$acc),$s0); # save ivec
+ &mov (&DWP(4,$acc),$s1);
+ &mov (&DWP(8,$acc),$s2);
+ &mov (&DWP(12,$acc),$s3);
+
+ &cmp ($mark,0); # was the key schedule copied?
+ &mov ("edi",$_key);
+ &je (&label("skip_ezero"));
+ # zero copy of key schedule
+ &mov ("ecx",240/4);
+ &xor ("eax","eax");
+ &align (4);
+ &data_word(0xABF3F689); # rep stosd
+ &set_label("skip_ezero");
+ &mov ("esp",$_esp);
+ &popf ();
+ &set_label("drop_out");
+ &function_end_A();
+ &pushf (); # kludge, never executed
+
+#----------------------------- DECRYPT -----------------------------#
+&set_label("fast_decrypt",16);
+
+ &cmp ($acc,$_out);
+ &je (&label("fast_dec_in_place")); # in-place processing...
+
+ &mov ($_tmp,$key);
+
+ &align (4);
+ &set_label("fast_dec_loop",16);
+ &mov ($s0,&DWP(0,$acc)); # read input
+ &mov ($s1,&DWP(4,$acc));
+ &mov ($s2,&DWP(8,$acc));
+ &mov ($s3,&DWP(12,$acc));
+
+ &mov ($key,$_key); # load key
+ &call ("_x86_AES_decrypt");
+
+ &mov ($key,$_tmp); # load ivp
+ &mov ($acc,$_len); # load len
+ &xor ($s0,&DWP(0,$key)); # xor iv
+ &xor ($s1,&DWP(4,$key));
+ &xor ($s2,&DWP(8,$key));
+ &xor ($s3,&DWP(12,$key));
+
+ &mov ($key,$_out); # load out
+ &mov ($acc,$_inp); # load inp
+
+ &mov (&DWP(0,$key),$s0); # write output
+ &mov (&DWP(4,$key),$s1);
+ &mov (&DWP(8,$key),$s2);
+ &mov (&DWP(12,$key),$s3);
+
+ &mov ($s2,$_len); # load len
+ &mov ($_tmp,$acc); # save ivp
+ &lea ($acc,&DWP(16,$acc)); # advance inp
+ &mov ($_inp,$acc); # save inp
+ &lea ($key,&DWP(16,$key)); # advance out
+ &mov ($_out,$key); # save out
+ &sub ($s2,16); # decrease len
+ &mov ($_len,$s2); # save len
+ &jnz (&label("fast_dec_loop"));
+ &mov ($key,$_tmp); # load temp ivp
+ &mov ($acc,$_ivp); # load user ivp
+ &mov ($s0,&DWP(0,$key)); # load iv
+ &mov ($s1,&DWP(4,$key));
+ &mov ($s2,&DWP(8,$key));
+ &mov ($s3,&DWP(12,$key));
+ &mov (&DWP(0,$acc),$s0); # copy back to user
+ &mov (&DWP(4,$acc),$s1);
+ &mov (&DWP(8,$acc),$s2);
+ &mov (&DWP(12,$acc),$s3);
+ &jmp (&label("fast_dec_out"));
+
+ &set_label("fast_dec_in_place",16);
+ &set_label("fast_dec_in_place_loop");
+ &mov ($s0,&DWP(0,$acc)); # read input
+ &mov ($s1,&DWP(4,$acc));
+ &mov ($s2,&DWP(8,$acc));
+ &mov ($s3,&DWP(12,$acc));
+
+ &lea ($key,$ivec);
+ &mov (&DWP(0,$key),$s0); # copy to temp
+ &mov (&DWP(4,$key),$s1);
+ &mov (&DWP(8,$key),$s2);
+ &mov (&DWP(12,$key),$s3);
+
+ &mov ($key,$_key); # load key
+ &call ("_x86_AES_decrypt");
+
+ &mov ($key,$_ivp); # load ivp
+ &mov ($acc,$_out); # load out
+ &xor ($s0,&DWP(0,$key)); # xor iv
+ &xor ($s1,&DWP(4,$key));
+ &xor ($s2,&DWP(8,$key));
+ &xor ($s3,&DWP(12,$key));
+
+ &mov (&DWP(0,$acc),$s0); # write output
+ &mov (&DWP(4,$acc),$s1);
+ &mov (&DWP(8,$acc),$s2);
+ &mov (&DWP(12,$acc),$s3);
+
+ &lea ($acc,&DWP(16,$acc)); # advance out
+ &mov ($_out,$acc); # save out
+
+ &lea ($acc,$ivec);
+ &mov ($s0,&DWP(0,$acc)); # read temp
+ &mov ($s1,&DWP(4,$acc));
+ &mov ($s2,&DWP(8,$acc));
+ &mov ($s3,&DWP(12,$acc));
+
+ &mov (&DWP(0,$key),$s0); # copy iv
+ &mov (&DWP(4,$key),$s1);
+ &mov (&DWP(8,$key),$s2);
+ &mov (&DWP(12,$key),$s3);
+
+ &mov ($acc,$_inp); # load inp
+ &mov ($s2,$_len); # load len
+ &lea ($acc,&DWP(16,$acc)); # advance inp
+ &mov ($_inp,$acc); # save inp
+ &sub ($s2,16); # decrease len
+ &mov ($_len,$s2); # save len
+ &jnz (&label("fast_dec_in_place_loop"));
+
+ &set_label("fast_dec_out",4);
+ &cmp ($mark,0); # was the key schedule copied?
+ &mov ("edi",$_key);
+ &je (&label("skip_dzero"));
+ # zero copy of key schedule
+ &mov ("ecx",240/4);
+ &xor ("eax","eax");
+ &align (4);
+ &data_word(0xABF3F689); # rep stosd
+ &set_label("skip_dzero");
+ &mov ("esp",$_esp);
+ &popf ();
+ &function_end_A();
+ &pushf (); # kludge, never executed
+
+#--------------------------- SLOW ROUTINE ---------------------------#
+&set_label("slow_way",16);
+
+ &mov ($s0,&DWP(0,$s0)) if (!$x86only);# load OPENSSL_ia32cap
+ &mov ($key,&wparam(3)); # load key
+
+ # pre-allocate aligned stack frame...
+ &lea ($acc,&DWP(-80,"esp"));
+ &and ($acc,-64);
+
+ # ... and make sure it doesn't alias with $key modulo 1024
+ &lea ($s1,&DWP(-80-63,$key));
+ &sub ($s1,$acc);
+ &neg ($s1);
+ &and ($s1,0x3C0); # modulo 1024, but aligned to cache-line
+ &sub ($acc,$s1);
+
+ # pick S-box copy which can't overlap with stack frame or $key
+ &lea ($s1,&DWP(768,$acc));
+ &sub ($s1,$tbl);
+ &and ($s1,0x300);
+ &lea ($tbl,&DWP(2048+128,$tbl,$s1));
+
+ &lea ($s3,&wparam(0)); # pointer to parameter block
+
+ &exch ("esp",$acc);
+ &add ("esp",4); # reserve for return address!
+ &mov ($_tbl,$tbl); # save %ebp
+ &mov ($_esp,$acc); # save %esp
+ &mov ($_tmp,$s0); # save OPENSSL_ia32cap
+
+ &mov ($s0,&DWP(0,$s3)); # load inp
+ &mov ($s1,&DWP(4,$s3)); # load out
+ #&mov ($s2,&DWP(8,$s3)); # load len
+ #&mov ($key,&DWP(12,$s3)); # load key
+ &mov ($acc,&DWP(16,$s3)); # load ivp
+ &mov ($s3,&DWP(20,$s3)); # load enc flag
+
+ &mov ($_inp,$s0); # save copy of inp
+ &mov ($_out,$s1); # save copy of out
+ &mov ($_len,$s2); # save copy of len
+ &mov ($_key,$key); # save copy of key
+ &mov ($_ivp,$acc); # save copy of ivp
+
+ &mov ($key,$acc);
+ &mov ($acc,$s0);
+
+ &cmp ($s3,0);
+ &je (&label("slow_decrypt"));
+
+#--------------------------- SLOW ENCRYPT ---------------------------#
+ &cmp ($s2,16);
+ &mov ($s3,$s1);
+ &jb (&label("slow_enc_tail"));
+
+ if (!$x86only) {
+ &bt ($_tmp,25); # check for SSE bit
+ &jnc (&label("slow_enc_x86"));
+
+ &movq ("mm0",&QWP(0,$key)); # load iv
+ &movq ("mm4",&QWP(8,$key));
+
+ &set_label("slow_enc_loop_sse",16);
+ &pxor ("mm0",&QWP(0,$acc)); # xor input data
+ &pxor ("mm4",&QWP(8,$acc));
+
+ &mov ($key,$_key);
+ &call ("_sse_AES_encrypt_compact");
+
+ &mov ($acc,$_inp); # load inp
+ &mov ($key,$_out); # load out
+ &mov ($s2,$_len); # load len
+
+ &movq (&QWP(0,$key),"mm0"); # save output data
+ &movq (&QWP(8,$key),"mm4");
+
+ &lea ($acc,&DWP(16,$acc)); # advance inp
+ &mov ($_inp,$acc); # save inp
+ &lea ($s3,&DWP(16,$key)); # advance out
+ &mov ($_out,$s3); # save out
+ &sub ($s2,16); # decrease len
+ &cmp ($s2,16);
+ &mov ($_len,$s2); # save len
+ &jae (&label("slow_enc_loop_sse"));
+ &test ($s2,15);
+ &jnz (&label("slow_enc_tail"));
+ &mov ($acc,$_ivp); # load ivp
+ &movq (&QWP(0,$acc),"mm0"); # save ivec
+ &movq (&QWP(8,$acc),"mm4");
+ &emms ();
+ &mov ("esp",$_esp);
+ &popf ();
+ &function_end_A();
+ &pushf (); # kludge, never executed
+ }
+ &set_label("slow_enc_x86",16);
+ &mov ($s0,&DWP(0,$key)); # load iv
+ &mov ($s1,&DWP(4,$key));
+
+ &set_label("slow_enc_loop_x86",4);
+ &mov ($s2,&DWP(8,$key));
+ &mov ($s3,&DWP(12,$key));
+
+ &xor ($s0,&DWP(0,$acc)); # xor input data
+ &xor ($s1,&DWP(4,$acc));
+ &xor ($s2,&DWP(8,$acc));
+ &xor ($s3,&DWP(12,$acc));
+
+ &mov ($key,$_key); # load key
+ &call ("_x86_AES_encrypt_compact");
+
+ &mov ($acc,$_inp); # load inp
+ &mov ($key,$_out); # load out
+
+ &mov (&DWP(0,$key),$s0); # save output data
+ &mov (&DWP(4,$key),$s1);
+ &mov (&DWP(8,$key),$s2);
+ &mov (&DWP(12,$key),$s3);
+
+ &mov ($s2,$_len); # load len
+ &lea ($acc,&DWP(16,$acc)); # advance inp
+ &mov ($_inp,$acc); # save inp
+ &lea ($s3,&DWP(16,$key)); # advance out
+ &mov ($_out,$s3); # save out
+ &sub ($s2,16); # decrease len
+ &cmp ($s2,16);
+ &mov ($_len,$s2); # save len
+ &jae (&label("slow_enc_loop_x86"));
+ &test ($s2,15);
+ &jnz (&label("slow_enc_tail"));
+ &mov ($acc,$_ivp); # load ivp
+ &mov ($s2,&DWP(8,$key)); # restore last dwords
+ &mov ($s3,&DWP(12,$key));
+ &mov (&DWP(0,$acc),$s0); # save ivec
+ &mov (&DWP(4,$acc),$s1);
+ &mov (&DWP(8,$acc),$s2);
+ &mov (&DWP(12,$acc),$s3);
+
+ &mov ("esp",$_esp);
+ &popf ();
+ &function_end_A();
+ &pushf (); # kludge, never executed
+
+ &set_label("slow_enc_tail",16);
+ &emms () if (!$x86only);
+ &mov ($key eq "edi"? $key:"",$s3); # load out to edi
+ &mov ($s1,16);
+ &sub ($s1,$s2);
+ &cmp ($key,$acc eq "esi"? $acc:""); # compare with inp
+ &je (&label("enc_in_place"));
+ &align (4);
+ &data_word(0xA4F3F689); # rep movsb # copy input
+ &jmp (&label("enc_skip_in_place"));
+ &set_label("enc_in_place");
+ &lea ($key,&DWP(0,$key,$s2));
+ &set_label("enc_skip_in_place");
+ &mov ($s2,$s1);
+ &xor ($s0,$s0);
+ &align (4);
+ &data_word(0xAAF3F689); # rep stosb # zero tail
+
+ &mov ($key,$_ivp); # restore ivp
+ &mov ($acc,$s3); # output as input
+ &mov ($s0,&DWP(0,$key));
+ &mov ($s1,&DWP(4,$key));
+ &mov ($_len,16); # len=16
+ &jmp (&label("slow_enc_loop_x86")); # one more spin...
+
+#--------------------------- SLOW DECRYPT ---------------------------#
+&set_label("slow_decrypt",16);
+ if (!$x86only) {
+ &bt ($_tmp,25); # check for SSE bit
+ &jnc (&label("slow_dec_loop_x86"));
+
+ &set_label("slow_dec_loop_sse",4);
+ &movq ("mm0",&QWP(0,$acc)); # read input
+ &movq ("mm4",&QWP(8,$acc));
+
+ &mov ($key,$_key);
+ &call ("_sse_AES_decrypt_compact");
+
+ &mov ($acc,$_inp); # load inp
+ &lea ($s0,$ivec);
+ &mov ($s1,$_out); # load out
+ &mov ($s2,$_len); # load len
+ &mov ($key,$_ivp); # load ivp
+
+ &movq ("mm1",&QWP(0,$acc)); # re-read input
+ &movq ("mm5",&QWP(8,$acc));
+
+ &pxor ("mm0",&QWP(0,$key)); # xor iv
+ &pxor ("mm4",&QWP(8,$key));
+
+ &movq (&QWP(0,$key),"mm1"); # copy input to iv
+ &movq (&QWP(8,$key),"mm5");
+
+ &sub ($s2,16); # decrease len
+ &jc (&label("slow_dec_partial_sse"));
+
+ &movq (&QWP(0,$s1),"mm0"); # write output
+ &movq (&QWP(8,$s1),"mm4");
+
+ &lea ($s1,&DWP(16,$s1)); # advance out
+ &mov ($_out,$s1); # save out
+ &lea ($acc,&DWP(16,$acc)); # advance inp
+ &mov ($_inp,$acc); # save inp
+ &mov ($_len,$s2); # save len
+ &jnz (&label("slow_dec_loop_sse"));
+ &emms ();
+ &mov ("esp",$_esp);
+ &popf ();
+ &function_end_A();
+ &pushf (); # kludge, never executed
+
+ &set_label("slow_dec_partial_sse",16);
+ &movq (&QWP(0,$s0),"mm0"); # save output to temp
+ &movq (&QWP(8,$s0),"mm4");
+ &emms ();
+
+ &add ($s2 eq "ecx" ? "ecx":"",16);
+ &mov ("edi",$s1); # out
+ &mov ("esi",$s0); # temp
+ &align (4);
+ &data_word(0xA4F3F689); # rep movsb # copy partial output
+
+ &mov ("esp",$_esp);
+ &popf ();
+ &function_end_A();
+ &pushf (); # kludge, never executed
+ }
+ &set_label("slow_dec_loop_x86",16);
+ &mov ($s0,&DWP(0,$acc)); # read input
+ &mov ($s1,&DWP(4,$acc));
+ &mov ($s2,&DWP(8,$acc));
+ &mov ($s3,&DWP(12,$acc));
+
+ &lea ($key,$ivec);
+ &mov (&DWP(0,$key),$s0); # copy to temp
+ &mov (&DWP(4,$key),$s1);
+ &mov (&DWP(8,$key),$s2);
+ &mov (&DWP(12,$key),$s3);
+
+ &mov ($key,$_key); # load key
+ &call ("_x86_AES_decrypt_compact");
+
+ &mov ($key,$_ivp); # load ivp
+ &mov ($acc,$_len); # load len
+ &xor ($s0,&DWP(0,$key)); # xor iv
+ &xor ($s1,&DWP(4,$key));
+ &xor ($s2,&DWP(8,$key));
+ &xor ($s3,&DWP(12,$key));
+
+ &sub ($acc,16);
+ &jc (&label("slow_dec_partial_x86"));
+
+ &mov ($_len,$acc); # save len
+ &mov ($acc,$_out); # load out
+
+ &mov (&DWP(0,$acc),$s0); # write output
+ &mov (&DWP(4,$acc),$s1);
+ &mov (&DWP(8,$acc),$s2);
+ &mov (&DWP(12,$acc),$s3);
+
+ &lea ($acc,&DWP(16,$acc)); # advance out
+ &mov ($_out,$acc); # save out
+
+ &lea ($acc,$ivec);
+ &mov ($s0,&DWP(0,$acc)); # read temp
+ &mov ($s1,&DWP(4,$acc));
+ &mov ($s2,&DWP(8,$acc));
+ &mov ($s3,&DWP(12,$acc));
+
+ &mov (&DWP(0,$key),$s0); # copy it to iv
+ &mov (&DWP(4,$key),$s1);
+ &mov (&DWP(8,$key),$s2);
+ &mov (&DWP(12,$key),$s3);
+
+ &mov ($acc,$_inp); # load inp
+ &lea ($acc,&DWP(16,$acc)); # advance inp
+ &mov ($_inp,$acc); # save inp
+ &jnz (&label("slow_dec_loop_x86"));
+ &mov ("esp",$_esp);
+ &popf ();
+ &function_end_A();
+ &pushf (); # kludge, never executed
+
+ &set_label("slow_dec_partial_x86",16);
+ &lea ($acc,$ivec);
+ &mov (&DWP(0,$acc),$s0); # save output to temp
+ &mov (&DWP(4,$acc),$s1);
+ &mov (&DWP(8,$acc),$s2);
+ &mov (&DWP(12,$acc),$s3);
+
+ &mov ($acc,$_inp);
+ &mov ($s0,&DWP(0,$acc)); # re-read input
+ &mov ($s1,&DWP(4,$acc));
+ &mov ($s2,&DWP(8,$acc));
+ &mov ($s3,&DWP(12,$acc));
+
+ &mov (&DWP(0,$key),$s0); # copy it to iv
+ &mov (&DWP(4,$key),$s1);
+ &mov (&DWP(8,$key),$s2);
+ &mov (&DWP(12,$key),$s3);
+
+ &mov ("ecx",$_len);
+ &mov ("edi",$_out);
+ &lea ("esi",$ivec);
+ &align (4);
+ &data_word(0xA4F3F689); # rep movsb # copy partial output
+
+ &mov ("esp",$_esp);
+ &popf ();
+&function_end("AES_cbc_encrypt");
+}
+
+#------------------------------------------------------------------#
+
+sub enckey()
+{
+ &movz ("esi",&LB("edx")); # rk[i]>>0
+ &movz ("ebx",&BP(-128,$tbl,"esi",1));
+ &movz ("esi",&HB("edx")); # rk[i]>>8
+ &shl ("ebx",24);
+ &xor ("eax","ebx");
+
+ &movz ("ebx",&BP(-128,$tbl,"esi",1));
+ &shr ("edx",16);
+ &movz ("esi",&LB("edx")); # rk[i]>>16
+ &xor ("eax","ebx");
+
+ &movz ("ebx",&BP(-128,$tbl,"esi",1));
+ &movz ("esi",&HB("edx")); # rk[i]>>24
+ &shl ("ebx",8);
+ &xor ("eax","ebx");
+
+ &movz ("ebx",&BP(-128,$tbl,"esi",1));
+ &shl ("ebx",16);
+ &xor ("eax","ebx");
+
+ &xor ("eax",&DWP(1024-128,$tbl,"ecx",4)); # rcon
+}
+
+&function_begin("_x86_AES_set_encrypt_key");
+ &mov ("esi",&wparam(1)); # user supplied key
+ &mov ("edi",&wparam(3)); # private key schedule
+
+ &test ("esi",-1);
+ &jz (&label("badpointer"));
+ &test ("edi",-1);
+ &jz (&label("badpointer"));
+
+ &call (&label("pic_point"));
+ &set_label("pic_point");
+ &blindpop($tbl);
+ &lea ($tbl,&DWP(&label("AES_Te")."-".&label("pic_point"),$tbl));
+ &lea ($tbl,&DWP(2048+128,$tbl));
+
+ # prefetch Te4
+ &mov ("eax",&DWP(0-128,$tbl));
+ &mov ("ebx",&DWP(32-128,$tbl));
+ &mov ("ecx",&DWP(64-128,$tbl));
+ &mov ("edx",&DWP(96-128,$tbl));
+ &mov ("eax",&DWP(128-128,$tbl));
+ &mov ("ebx",&DWP(160-128,$tbl));
+ &mov ("ecx",&DWP(192-128,$tbl));
+ &mov ("edx",&DWP(224-128,$tbl));
+
+ &mov ("ecx",&wparam(2)); # number of bits in key
+ &cmp ("ecx",128);
+ &je (&label("10rounds"));
+ &cmp ("ecx",192);
+ &je (&label("12rounds"));
+ &cmp ("ecx",256);
+ &je (&label("14rounds"));
+ &mov ("eax",-2); # invalid number of bits
+ &jmp (&label("exit"));
+
+ &set_label("10rounds");
+ &mov ("eax",&DWP(0,"esi")); # copy first 4 dwords
+ &mov ("ebx",&DWP(4,"esi"));
+ &mov ("ecx",&DWP(8,"esi"));
+ &mov ("edx",&DWP(12,"esi"));
+ &mov (&DWP(0,"edi"),"eax");
+ &mov (&DWP(4,"edi"),"ebx");
+ &mov (&DWP(8,"edi"),"ecx");
+ &mov (&DWP(12,"edi"),"edx");
+
+ &xor ("ecx","ecx");
+ &jmp (&label("10shortcut"));
+
+ &align (4);
+ &set_label("10loop");
+ &mov ("eax",&DWP(0,"edi")); # rk[0]
+ &mov ("edx",&DWP(12,"edi")); # rk[3]
+ &set_label("10shortcut");
+ &enckey ();
+
+ &mov (&DWP(16,"edi"),"eax"); # rk[4]
+ &xor ("eax",&DWP(4,"edi"));
+ &mov (&DWP(20,"edi"),"eax"); # rk[5]
+ &xor ("eax",&DWP(8,"edi"));
+ &mov (&DWP(24,"edi"),"eax"); # rk[6]
+ &xor ("eax",&DWP(12,"edi"));
+ &mov (&DWP(28,"edi"),"eax"); # rk[7]
+ &inc ("ecx");
+ &add ("edi",16);
+ &cmp ("ecx",10);
+ &jl (&label("10loop"));
+
+ &mov (&DWP(80,"edi"),10); # setup number of rounds
+ &xor ("eax","eax");
+ &jmp (&label("exit"));
+
+ &set_label("12rounds");
+ &mov ("eax",&DWP(0,"esi")); # copy first 6 dwords
+ &mov ("ebx",&DWP(4,"esi"));
+ &mov ("ecx",&DWP(8,"esi"));
+ &mov ("edx",&DWP(12,"esi"));
+ &mov (&DWP(0,"edi"),"eax");
+ &mov (&DWP(4,"edi"),"ebx");
+ &mov (&DWP(8,"edi"),"ecx");
+ &mov (&DWP(12,"edi"),"edx");
+ &mov ("ecx",&DWP(16,"esi"));
+ &mov ("edx",&DWP(20,"esi"));
+ &mov (&DWP(16,"edi"),"ecx");
+ &mov (&DWP(20,"edi"),"edx");
+
+ &xor ("ecx","ecx");
+ &jmp (&label("12shortcut"));
+
+ &align (4);
+ &set_label("12loop");
+ &mov ("eax",&DWP(0,"edi")); # rk[0]
+ &mov ("edx",&DWP(20,"edi")); # rk[5]
+ &set_label("12shortcut");
+ &enckey ();
+
+ &mov (&DWP(24,"edi"),"eax"); # rk[6]
+ &xor ("eax",&DWP(4,"edi"));
+ &mov (&DWP(28,"edi"),"eax"); # rk[7]
+ &xor ("eax",&DWP(8,"edi"));
+ &mov (&DWP(32,"edi"),"eax"); # rk[8]
+ &xor ("eax",&DWP(12,"edi"));
+ &mov (&DWP(36,"edi"),"eax"); # rk[9]
+
+ &cmp ("ecx",7);
+ &je (&label("12break"));
+ &inc ("ecx");
+
+ &xor ("eax",&DWP(16,"edi"));
+ &mov (&DWP(40,"edi"),"eax"); # rk[10]
+ &xor ("eax",&DWP(20,"edi"));
+ &mov (&DWP(44,"edi"),"eax"); # rk[11]
+
+ &add ("edi",24);
+ &jmp (&label("12loop"));
+
+ &set_label("12break");
+ &mov (&DWP(72,"edi"),12); # setup number of rounds
+ &xor ("eax","eax");
+ &jmp (&label("exit"));
+
+ &set_label("14rounds");
+ &mov ("eax",&DWP(0,"esi")); # copy first 8 dwords
+ &mov ("ebx",&DWP(4,"esi"));
+ &mov ("ecx",&DWP(8,"esi"));
+ &mov ("edx",&DWP(12,"esi"));
+ &mov (&DWP(0,"edi"),"eax");
+ &mov (&DWP(4,"edi"),"ebx");
+ &mov (&DWP(8,"edi"),"ecx");
+ &mov (&DWP(12,"edi"),"edx");
+ &mov ("eax",&DWP(16,"esi"));
+ &mov ("ebx",&DWP(20,"esi"));
+ &mov ("ecx",&DWP(24,"esi"));
+ &mov ("edx",&DWP(28,"esi"));
+ &mov (&DWP(16,"edi"),"eax");
+ &mov (&DWP(20,"edi"),"ebx");
+ &mov (&DWP(24,"edi"),"ecx");
+ &mov (&DWP(28,"edi"),"edx");
+
+ &xor ("ecx","ecx");
+ &jmp (&label("14shortcut"));
+
+ &align (4);
+ &set_label("14loop");
+ &mov ("edx",&DWP(28,"edi")); # rk[7]
+ &set_label("14shortcut");
+ &mov ("eax",&DWP(0,"edi")); # rk[0]
+
+ &enckey ();
+
+ &mov (&DWP(32,"edi"),"eax"); # rk[8]
+ &xor ("eax",&DWP(4,"edi"));
+ &mov (&DWP(36,"edi"),"eax"); # rk[9]
+ &xor ("eax",&DWP(8,"edi"));
+ &mov (&DWP(40,"edi"),"eax"); # rk[10]
+ &xor ("eax",&DWP(12,"edi"));
+ &mov (&DWP(44,"edi"),"eax"); # rk[11]
+
+ &cmp ("ecx",6);
+ &je (&label("14break"));
+ &inc ("ecx");
+
+ &mov ("edx","eax");
+ &mov ("eax",&DWP(16,"edi")); # rk[4]
+ &movz ("esi",&LB("edx")); # rk[11]>>0
+ &movz ("ebx",&BP(-128,$tbl,"esi",1));
+ &movz ("esi",&HB("edx")); # rk[11]>>8
+ &xor ("eax","ebx");
+
+ &movz ("ebx",&BP(-128,$tbl,"esi",1));
+ &shr ("edx",16);
+ &shl ("ebx",8);
+ &movz ("esi",&LB("edx")); # rk[11]>>16
+ &xor ("eax","ebx");
+
+ &movz ("ebx",&BP(-128,$tbl,"esi",1));
+ &movz ("esi",&HB("edx")); # rk[11]>>24
+ &shl ("ebx",16);
+ &xor ("eax","ebx");
+
+ &movz ("ebx",&BP(-128,$tbl,"esi",1));
+ &shl ("ebx",24);
+ &xor ("eax","ebx");
+
+ &mov (&DWP(48,"edi"),"eax"); # rk[12]
+ &xor ("eax",&DWP(20,"edi"));
+ &mov (&DWP(52,"edi"),"eax"); # rk[13]
+ &xor ("eax",&DWP(24,"edi"));
+ &mov (&DWP(56,"edi"),"eax"); # rk[14]
+ &xor ("eax",&DWP(28,"edi"));
+ &mov (&DWP(60,"edi"),"eax"); # rk[15]
+
+ &add ("edi",32);
+ &jmp (&label("14loop"));
+
+ &set_label("14break");
+ &mov (&DWP(48,"edi"),14); # setup number of rounds
+ &xor ("eax","eax");
+ &jmp (&label("exit"));
+
+ &set_label("badpointer");
+ &mov ("eax",-1);
+ &set_label("exit");
+&function_end("_x86_AES_set_encrypt_key");
+
+# int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
+# AES_KEY *key)
+&function_begin_B("AES_set_encrypt_key");
+ &call ("_x86_AES_set_encrypt_key");
+ &ret ();
+&function_end_B("AES_set_encrypt_key");
+
+sub deckey()
+{ my ($i,$key,$tp1,$tp2,$tp4,$tp8) = @_;
+ my $tmp = $tbl;
+
+ &mov ($tmp,0x80808080);
+ &and ($tmp,$tp1);
+ &lea ($tp2,&DWP(0,$tp1,$tp1));
+ &mov ($acc,$tmp);
+ &shr ($tmp,7);
+ &sub ($acc,$tmp);
+ &and ($tp2,0xfefefefe);
+ &and ($acc,0x1b1b1b1b);
+ &xor ($tp2,$acc);
+ &mov ($tmp,0x80808080);
+
+ &and ($tmp,$tp2);
+ &lea ($tp4,&DWP(0,$tp2,$tp2));
+ &mov ($acc,$tmp);
+ &shr ($tmp,7);
+ &sub ($acc,$tmp);
+ &and ($tp4,0xfefefefe);
+ &and ($acc,0x1b1b1b1b);
+ &xor ($tp2,$tp1); # tp2^tp1
+ &xor ($tp4,$acc);
+ &mov ($tmp,0x80808080);
+
+ &and ($tmp,$tp4);
+ &lea ($tp8,&DWP(0,$tp4,$tp4));
+ &mov ($acc,$tmp);
+ &shr ($tmp,7);
+ &xor ($tp4,$tp1); # tp4^tp1
+ &sub ($acc,$tmp);
+ &and ($tp8,0xfefefefe);
+ &and ($acc,0x1b1b1b1b);
+ &rotl ($tp1,8); # = ROTATE(tp1,8)
+ &xor ($tp8,$acc);
+
+ &mov ($tmp,&DWP(4*($i+1),$key)); # modulo-scheduled load
+
+ &xor ($tp1,$tp2);
+ &xor ($tp2,$tp8);
+ &xor ($tp1,$tp4);
+ &rotl ($tp2,24);
+ &xor ($tp4,$tp8);
+ &xor ($tp1,$tp8); # ^= tp8^(tp4^tp1)^(tp2^tp1)
+ &rotl ($tp4,16);
+ &xor ($tp1,$tp2); # ^= ROTATE(tp8^tp2^tp1,24)
+ &rotl ($tp8,8);
+ &xor ($tp1,$tp4); # ^= ROTATE(tp8^tp4^tp1,16)
+ &mov ($tp2,$tmp);
+ &xor ($tp1,$tp8); # ^= ROTATE(tp8,8)
+
+ &mov (&DWP(4*$i,$key),$tp1);
+}
+
+# int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
+# AES_KEY *key)
+&function_begin_B("AES_set_decrypt_key");
+ &call ("_x86_AES_set_encrypt_key");
+ &cmp ("eax",0);
+ &je (&label("proceed"));
+ &ret ();
+
+ &set_label("proceed");
+ &push ("ebp");
+ &push ("ebx");
+ &push ("esi");
+ &push ("edi");
+
+ &mov ("esi",&wparam(2));
+ &mov ("ecx",&DWP(240,"esi")); # pull number of rounds
+ &lea ("ecx",&DWP(0,"","ecx",4));
+ &lea ("edi",&DWP(0,"esi","ecx",4)); # pointer to last chunk
+
+ &set_label("invert",4); # invert order of chunks
+ &mov ("eax",&DWP(0,"esi"));
+ &mov ("ebx",&DWP(4,"esi"));
+ &mov ("ecx",&DWP(0,"edi"));
+ &mov ("edx",&DWP(4,"edi"));
+ &mov (&DWP(0,"edi"),"eax");
+ &mov (&DWP(4,"edi"),"ebx");
+ &mov (&DWP(0,"esi"),"ecx");
+ &mov (&DWP(4,"esi"),"edx");
+ &mov ("eax",&DWP(8,"esi"));
+ &mov ("ebx",&DWP(12,"esi"));
+ &mov ("ecx",&DWP(8,"edi"));
+ &mov ("edx",&DWP(12,"edi"));
+ &mov (&DWP(8,"edi"),"eax");
+ &mov (&DWP(12,"edi"),"ebx");
+ &mov (&DWP(8,"esi"),"ecx");
+ &mov (&DWP(12,"esi"),"edx");
+ &add ("esi",16);
+ &sub ("edi",16);
+ &cmp ("esi","edi");
+ &jne (&label("invert"));
+
+ &mov ($key,&wparam(2));
+ &mov ($acc,&DWP(240,$key)); # pull number of rounds
+ &lea ($acc,&DWP(-2,$acc,$acc));
+ &lea ($acc,&DWP(0,$key,$acc,8));
+ &mov (&wparam(2),$acc);
+
+ &mov ($s0,&DWP(16,$key)); # modulo-scheduled load
+ &set_label("permute",4); # permute the key schedule
+ &add ($key,16);
+ &deckey (0,$key,$s0,$s1,$s2,$s3);
+ &deckey (1,$key,$s1,$s2,$s3,$s0);
+ &deckey (2,$key,$s2,$s3,$s0,$s1);
+ &deckey (3,$key,$s3,$s0,$s1,$s2);
+ &cmp ($key,&wparam(2));
+ &jb (&label("permute"));
+
+ &xor ("eax","eax"); # return success
+&function_end("AES_set_decrypt_key");
+&asciz("AES for x86, CRYPTOGAMS by <appro\@openssl.org>");
+
+&asm_finish();
diff --git a/crypto/aes/asm/aes-armv4.pl b/crypto/aes/asm/aes-armv4.pl
new file mode 100644
index 0000000..38a3f6a
--- /dev/null
+++ b/crypto/aes/asm/aes-armv4.pl
@@ -0,0 +1,1219 @@
+#!/usr/bin/env perl
+
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+
+# AES for ARMv4
+
+# January 2007.
+#
+# Code uses single 1K S-box and is >2 times faster than code generated
+# by gcc-3.4.1. This is thanks to unique feature of ARMv4 ISA, which
+# allows to merge logical or arithmetic operation with shift or rotate
+# in one instruction and emit combined result every cycle. The module
+# is endian-neutral. The performance is ~42 cycles/byte for 128-bit
+# key [on single-issue Xscale PXA250 core].
+
+# May 2007.
+#
+# AES_set_[en|de]crypt_key is added.
+
+# July 2010.
+#
+# Rescheduling for dual-issue pipeline resulted in 12% improvement on
+# Cortex A8 core and ~25 cycles per byte processed with 128-bit key.
+
+# February 2011.
+#
+# Profiler-assisted and platform-specific optimization resulted in 16%
+# improvement on Cortex A8 core and ~21.5 cycles per byte.
+
+while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {}
+open STDOUT,">$output";
+
+$s0="r0";
+$s1="r1";
+$s2="r2";
+$s3="r3";
+$t1="r4";
+$t2="r5";
+$t3="r6";
+$i1="r7";
+$i2="r8";
+$i3="r9";
+
+$tbl="r10";
+$key="r11";
+$rounds="r12";
+
+$code=<<___;
+#if defined(__arm__)
+#ifndef __KERNEL__
+# include "arm_arch.h"
+#else
+# define __ARM_ARCH__ __LINUX_ARM_ARCH__
+#endif
+
+.text
+#if __ARM_ARCH__<7
+.code 32
+#else
+.syntax unified
+# ifdef __thumb2__
+.thumb
+# else
+.code 32
+# endif
+#endif
+
+.type AES_Te,%object
+.align 5
+AES_Te:
+.word 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d
+.word 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554
+.word 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d
+.word 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a
+.word 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87
+.word 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b
+.word 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea
+.word 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b
+.word 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a
+.word 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f
+.word 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108
+.word 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f
+.word 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e
+.word 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5
+.word 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d
+.word 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f
+.word 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e
+.word 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb
+.word 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce
+.word 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497
+.word 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c
+.word 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed
+.word 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b
+.word 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a
+.word 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16
+.word 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594
+.word 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81
+.word 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3
+.word 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a
+.word 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504
+.word 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163
+.word 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d
+.word 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f
+.word 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739
+.word 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47
+.word 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395
+.word 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f
+.word 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883
+.word 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c
+.word 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76
+.word 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e
+.word 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4
+.word 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6
+.word 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b
+.word 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7
+.word 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0
+.word 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25
+.word 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818
+.word 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72
+.word 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651
+.word 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21
+.word 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85
+.word 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa
+.word 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12
+.word 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0
+.word 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9
+.word 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133
+.word 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7
+.word 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920
+.word 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a
+.word 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17
+.word 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8
+.word 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11
+.word 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a
+@ Te4[256]
+.byte 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5
+.byte 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76
+.byte 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0
+.byte 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0
+.byte 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc
+.byte 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15
+.byte 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a
+.byte 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75
+.byte 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0
+.byte 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84
+.byte 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b
+.byte 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf
+.byte 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85
+.byte 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8
+.byte 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5
+.byte 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2
+.byte 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17
+.byte 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73
+.byte 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88
+.byte 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb
+.byte 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c
+.byte 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79
+.byte 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9
+.byte 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08
+.byte 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6
+.byte 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a
+.byte 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e
+.byte 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e
+.byte 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94
+.byte 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf
+.byte 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68
+.byte 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
+@ rcon[]
+.word 0x01000000, 0x02000000, 0x04000000, 0x08000000
+.word 0x10000000, 0x20000000, 0x40000000, 0x80000000
+.word 0x1B000000, 0x36000000, 0, 0, 0, 0, 0, 0
+.size AES_Te,.-AES_Te
+
+@ void AES_encrypt(const unsigned char *in, unsigned char *out,
+@ const AES_KEY *key) {
+.global AES_encrypt
+.type AES_encrypt,%function
+.align 5
+AES_encrypt:
+#if __ARM_ARCH__<7
+ sub r3,pc,#8 @ AES_encrypt
+#else
+ adr r3,AES_encrypt
+#endif
+ stmdb sp!,{r1,r4-r12,lr}
+ mov $rounds,r0 @ inp
+ mov $key,r2
+ sub $tbl,r3,#AES_encrypt-AES_Te @ Te
+#if __ARM_ARCH__<7
+ ldrb $s0,[$rounds,#3] @ load input data in endian-neutral
+ ldrb $t1,[$rounds,#2] @ manner...
+ ldrb $t2,[$rounds,#1]
+ ldrb $t3,[$rounds,#0]
+ orr $s0,$s0,$t1,lsl#8
+ ldrb $s1,[$rounds,#7]
+ orr $s0,$s0,$t2,lsl#16
+ ldrb $t1,[$rounds,#6]
+ orr $s0,$s0,$t3,lsl#24
+ ldrb $t2,[$rounds,#5]
+ ldrb $t3,[$rounds,#4]
+ orr $s1,$s1,$t1,lsl#8
+ ldrb $s2,[$rounds,#11]
+ orr $s1,$s1,$t2,lsl#16
+ ldrb $t1,[$rounds,#10]
+ orr $s1,$s1,$t3,lsl#24
+ ldrb $t2,[$rounds,#9]
+ ldrb $t3,[$rounds,#8]
+ orr $s2,$s2,$t1,lsl#8
+ ldrb $s3,[$rounds,#15]
+ orr $s2,$s2,$t2,lsl#16
+ ldrb $t1,[$rounds,#14]
+ orr $s2,$s2,$t3,lsl#24
+ ldrb $t2,[$rounds,#13]
+ ldrb $t3,[$rounds,#12]
+ orr $s3,$s3,$t1,lsl#8
+ orr $s3,$s3,$t2,lsl#16
+ orr $s3,$s3,$t3,lsl#24
+#else
+ ldr $s0,[$rounds,#0]
+ ldr $s1,[$rounds,#4]
+ ldr $s2,[$rounds,#8]
+ ldr $s3,[$rounds,#12]
+#ifdef __ARMEL__
+ rev $s0,$s0
+ rev $s1,$s1
+ rev $s2,$s2
+ rev $s3,$s3
+#endif
+#endif
+ bl _armv4_AES_encrypt
+
+ ldr $rounds,[sp],#4 @ pop out
+#if __ARM_ARCH__>=7
+#ifdef __ARMEL__
+ rev $s0,$s0
+ rev $s1,$s1
+ rev $s2,$s2
+ rev $s3,$s3
+#endif
+ str $s0,[$rounds,#0]
+ str $s1,[$rounds,#4]
+ str $s2,[$rounds,#8]
+ str $s3,[$rounds,#12]
+#else
+ mov $t1,$s0,lsr#24 @ write output in endian-neutral
+ mov $t2,$s0,lsr#16 @ manner...
+ mov $t3,$s0,lsr#8
+ strb $t1,[$rounds,#0]
+ strb $t2,[$rounds,#1]
+ mov $t1,$s1,lsr#24
+ strb $t3,[$rounds,#2]
+ mov $t2,$s1,lsr#16
+ strb $s0,[$rounds,#3]
+ mov $t3,$s1,lsr#8
+ strb $t1,[$rounds,#4]
+ strb $t2,[$rounds,#5]
+ mov $t1,$s2,lsr#24
+ strb $t3,[$rounds,#6]
+ mov $t2,$s2,lsr#16
+ strb $s1,[$rounds,#7]
+ mov $t3,$s2,lsr#8
+ strb $t1,[$rounds,#8]
+ strb $t2,[$rounds,#9]
+ mov $t1,$s3,lsr#24
+ strb $t3,[$rounds,#10]
+ mov $t2,$s3,lsr#16
+ strb $s2,[$rounds,#11]
+ mov $t3,$s3,lsr#8
+ strb $t1,[$rounds,#12]
+ strb $t2,[$rounds,#13]
+ strb $t3,[$rounds,#14]
+ strb $s3,[$rounds,#15]
+#endif
+#if __ARM_ARCH__>=5
+ ldmia sp!,{r4-r12,pc}
+#else
+ ldmia sp!,{r4-r12,lr}
+ tst lr,#1
+ moveq pc,lr @ be binary compatible with V4, yet
+ bx lr @ interoperable with Thumb ISA:-)
+#endif
+.size AES_encrypt,.-AES_encrypt
+
+.type _armv4_AES_encrypt,%function
+.align 2
+_armv4_AES_encrypt:
+ str lr,[sp,#-4]! @ push lr
+ ldmia $key!,{$t1-$i1}
+ eor $s0,$s0,$t1
+ ldr $rounds,[$key,#240-16]
+ eor $s1,$s1,$t2
+ eor $s2,$s2,$t3
+ eor $s3,$s3,$i1
+ sub $rounds,$rounds,#1
+ mov lr,#255
+
+ and $i1,lr,$s0
+ and $i2,lr,$s0,lsr#8
+ and $i3,lr,$s0,lsr#16
+ mov $s0,$s0,lsr#24
+.Lenc_loop:
+ ldr $t1,[$tbl,$i1,lsl#2] @ Te3[s0>>0]
+ and $i1,lr,$s1,lsr#16 @ i0
+ ldr $t2,[$tbl,$i2,lsl#2] @ Te2[s0>>8]
+ and $i2,lr,$s1
+ ldr $t3,[$tbl,$i3,lsl#2] @ Te1[s0>>16]
+ and $i3,lr,$s1,lsr#8
+ ldr $s0,[$tbl,$s0,lsl#2] @ Te0[s0>>24]
+ mov $s1,$s1,lsr#24
+
+ ldr $i1,[$tbl,$i1,lsl#2] @ Te1[s1>>16]
+ ldr $i2,[$tbl,$i2,lsl#2] @ Te3[s1>>0]
+ ldr $i3,[$tbl,$i3,lsl#2] @ Te2[s1>>8]
+ eor $s0,$s0,$i1,ror#8
+ ldr $s1,[$tbl,$s1,lsl#2] @ Te0[s1>>24]
+ and $i1,lr,$s2,lsr#8 @ i0
+ eor $t2,$t2,$i2,ror#8
+ and $i2,lr,$s2,lsr#16 @ i1
+ eor $t3,$t3,$i3,ror#8
+ and $i3,lr,$s2
+ ldr $i1,[$tbl,$i1,lsl#2] @ Te2[s2>>8]
+ eor $s1,$s1,$t1,ror#24
+ ldr $i2,[$tbl,$i2,lsl#2] @ Te1[s2>>16]
+ mov $s2,$s2,lsr#24
+
+ ldr $i3,[$tbl,$i3,lsl#2] @ Te3[s2>>0]
+ eor $s0,$s0,$i1,ror#16
+ ldr $s2,[$tbl,$s2,lsl#2] @ Te0[s2>>24]
+ and $i1,lr,$s3 @ i0
+ eor $s1,$s1,$i2,ror#8
+ and $i2,lr,$s3,lsr#8 @ i1
+ eor $t3,$t3,$i3,ror#16
+ and $i3,lr,$s3,lsr#16 @ i2
+ ldr $i1,[$tbl,$i1,lsl#2] @ Te3[s3>>0]
+ eor $s2,$s2,$t2,ror#16
+ ldr $i2,[$tbl,$i2,lsl#2] @ Te2[s3>>8]
+ mov $s3,$s3,lsr#24
+
+ ldr $i3,[$tbl,$i3,lsl#2] @ Te1[s3>>16]
+ eor $s0,$s0,$i1,ror#24
+ ldr $i1,[$key],#16
+ eor $s1,$s1,$i2,ror#16
+ ldr $s3,[$tbl,$s3,lsl#2] @ Te0[s3>>24]
+ eor $s2,$s2,$i3,ror#8
+ ldr $t1,[$key,#-12]
+ eor $s3,$s3,$t3,ror#8
+
+ ldr $t2,[$key,#-8]
+ eor $s0,$s0,$i1
+ ldr $t3,[$key,#-4]
+ and $i1,lr,$s0
+ eor $s1,$s1,$t1
+ and $i2,lr,$s0,lsr#8
+ eor $s2,$s2,$t2
+ and $i3,lr,$s0,lsr#16
+ eor $s3,$s3,$t3
+ mov $s0,$s0,lsr#24
+
+ subs $rounds,$rounds,#1
+ bne .Lenc_loop
+
+ add $tbl,$tbl,#2
+
+ ldrb $t1,[$tbl,$i1,lsl#2] @ Te4[s0>>0]
+ and $i1,lr,$s1,lsr#16 @ i0
+ ldrb $t2,[$tbl,$i2,lsl#2] @ Te4[s0>>8]
+ and $i2,lr,$s1
+ ldrb $t3,[$tbl,$i3,lsl#2] @ Te4[s0>>16]
+ and $i3,lr,$s1,lsr#8
+ ldrb $s0,[$tbl,$s0,lsl#2] @ Te4[s0>>24]
+ mov $s1,$s1,lsr#24
+
+ ldrb $i1,[$tbl,$i1,lsl#2] @ Te4[s1>>16]
+ ldrb $i2,[$tbl,$i2,lsl#2] @ Te4[s1>>0]
+ ldrb $i3,[$tbl,$i3,lsl#2] @ Te4[s1>>8]
+ eor $s0,$i1,$s0,lsl#8
+ ldrb $s1,[$tbl,$s1,lsl#2] @ Te4[s1>>24]
+ and $i1,lr,$s2,lsr#8 @ i0
+ eor $t2,$i2,$t2,lsl#8
+ and $i2,lr,$s2,lsr#16 @ i1
+ eor $t3,$i3,$t3,lsl#8
+ and $i3,lr,$s2
+ ldrb $i1,[$tbl,$i1,lsl#2] @ Te4[s2>>8]
+ eor $s1,$t1,$s1,lsl#24
+ ldrb $i2,[$tbl,$i2,lsl#2] @ Te4[s2>>16]
+ mov $s2,$s2,lsr#24
+
+ ldrb $i3,[$tbl,$i3,lsl#2] @ Te4[s2>>0]
+ eor $s0,$i1,$s0,lsl#8
+ ldrb $s2,[$tbl,$s2,lsl#2] @ Te4[s2>>24]
+ and $i1,lr,$s3 @ i0
+ eor $s1,$s1,$i2,lsl#16
+ and $i2,lr,$s3,lsr#8 @ i1
+ eor $t3,$i3,$t3,lsl#8
+ and $i3,lr,$s3,lsr#16 @ i2
+ ldrb $i1,[$tbl,$i1,lsl#2] @ Te4[s3>>0]
+ eor $s2,$t2,$s2,lsl#24
+ ldrb $i2,[$tbl,$i2,lsl#2] @ Te4[s3>>8]
+ mov $s3,$s3,lsr#24
+
+ ldrb $i3,[$tbl,$i3,lsl#2] @ Te4[s3>>16]
+ eor $s0,$i1,$s0,lsl#8
+ ldr $i1,[$key,#0]
+ ldrb $s3,[$tbl,$s3,lsl#2] @ Te4[s3>>24]
+ eor $s1,$s1,$i2,lsl#8
+ ldr $t1,[$key,#4]
+ eor $s2,$s2,$i3,lsl#16
+ ldr $t2,[$key,#8]
+ eor $s3,$t3,$s3,lsl#24
+ ldr $t3,[$key,#12]
+
+ eor $s0,$s0,$i1
+ eor $s1,$s1,$t1
+ eor $s2,$s2,$t2
+ eor $s3,$s3,$t3
+
+ sub $tbl,$tbl,#2
+ ldr pc,[sp],#4 @ pop and return
+.size _armv4_AES_encrypt,.-_armv4_AES_encrypt
+
+.global AES_set_encrypt_key
+.type AES_set_encrypt_key,%function
+.align 5
+AES_set_encrypt_key:
+_armv4_AES_set_encrypt_key:
+#if __ARM_ARCH__<7
+ sub r3,pc,#8 @ AES_set_encrypt_key
+#else
+ adr r3,AES_set_encrypt_key
+#endif
+ teq r0,#0
+#if __ARM_ARCH__>=7
+ itt eq @ Thumb2 thing, sanity check in ARM
+#endif
+ moveq r0,#-1
+ beq .Labrt
+ teq r2,#0
+#if __ARM_ARCH__>=7
+ itt eq @ Thumb2 thing, sanity check in ARM
+#endif
+ moveq r0,#-1
+ beq .Labrt
+
+ teq r1,#128
+ beq .Lok
+ teq r1,#192
+ beq .Lok
+ teq r1,#256
+#if __ARM_ARCH__>=7
+ itt ne @ Thumb2 thing, sanity check in ARM
+#endif
+ movne r0,#-1
+ bne .Labrt
+
+.Lok: stmdb sp!,{r4-r12,lr}
+ sub $tbl,r3,#_armv4_AES_set_encrypt_key-AES_Te-1024 @ Te4
+
+ mov $rounds,r0 @ inp
+ mov lr,r1 @ bits
+ mov $key,r2 @ key
+
+#if __ARM_ARCH__<7
+ ldrb $s0,[$rounds,#3] @ load input data in endian-neutral
+ ldrb $t1,[$rounds,#2] @ manner...
+ ldrb $t2,[$rounds,#1]
+ ldrb $t3,[$rounds,#0]
+ orr $s0,$s0,$t1,lsl#8
+ ldrb $s1,[$rounds,#7]
+ orr $s0,$s0,$t2,lsl#16
+ ldrb $t1,[$rounds,#6]
+ orr $s0,$s0,$t3,lsl#24
+ ldrb $t2,[$rounds,#5]
+ ldrb $t3,[$rounds,#4]
+ orr $s1,$s1,$t1,lsl#8
+ ldrb $s2,[$rounds,#11]
+ orr $s1,$s1,$t2,lsl#16
+ ldrb $t1,[$rounds,#10]
+ orr $s1,$s1,$t3,lsl#24
+ ldrb $t2,[$rounds,#9]
+ ldrb $t3,[$rounds,#8]
+ orr $s2,$s2,$t1,lsl#8
+ ldrb $s3,[$rounds,#15]
+ orr $s2,$s2,$t2,lsl#16
+ ldrb $t1,[$rounds,#14]
+ orr $s2,$s2,$t3,lsl#24
+ ldrb $t2,[$rounds,#13]
+ ldrb $t3,[$rounds,#12]
+ orr $s3,$s3,$t1,lsl#8
+ str $s0,[$key],#16
+ orr $s3,$s3,$t2,lsl#16
+ str $s1,[$key,#-12]
+ orr $s3,$s3,$t3,lsl#24
+ str $s2,[$key,#-8]
+ str $s3,[$key,#-4]
+#else
+ ldr $s0,[$rounds,#0]
+ ldr $s1,[$rounds,#4]
+ ldr $s2,[$rounds,#8]
+ ldr $s3,[$rounds,#12]
+#ifdef __ARMEL__
+ rev $s0,$s0
+ rev $s1,$s1
+ rev $s2,$s2
+ rev $s3,$s3
+#endif
+ str $s0,[$key],#16
+ str $s1,[$key,#-12]
+ str $s2,[$key,#-8]
+ str $s3,[$key,#-4]
+#endif
+
+ teq lr,#128
+ bne .Lnot128
+ mov $rounds,#10
+ str $rounds,[$key,#240-16]
+ add $t3,$tbl,#256 @ rcon
+ mov lr,#255
+
+.L128_loop:
+ and $t2,lr,$s3,lsr#24
+ and $i1,lr,$s3,lsr#16
+ ldrb $t2,[$tbl,$t2]
+ and $i2,lr,$s3,lsr#8
+ ldrb $i1,[$tbl,$i1]
+ and $i3,lr,$s3
+ ldrb $i2,[$tbl,$i2]
+ orr $t2,$t2,$i1,lsl#24
+ ldrb $i3,[$tbl,$i3]
+ orr $t2,$t2,$i2,lsl#16
+ ldr $t1,[$t3],#4 @ rcon[i++]
+ orr $t2,$t2,$i3,lsl#8
+ eor $t2,$t2,$t1
+ eor $s0,$s0,$t2 @ rk[4]=rk[0]^...
+ eor $s1,$s1,$s0 @ rk[5]=rk[1]^rk[4]
+ str $s0,[$key],#16
+ eor $s2,$s2,$s1 @ rk[6]=rk[2]^rk[5]
+ str $s1,[$key,#-12]
+ eor $s3,$s3,$s2 @ rk[7]=rk[3]^rk[6]
+ str $s2,[$key,#-8]
+ subs $rounds,$rounds,#1
+ str $s3,[$key,#-4]
+ bne .L128_loop
+ sub r2,$key,#176
+ b .Ldone
+
+.Lnot128:
+#if __ARM_ARCH__<7
+ ldrb $i2,[$rounds,#19]
+ ldrb $t1,[$rounds,#18]
+ ldrb $t2,[$rounds,#17]
+ ldrb $t3,[$rounds,#16]
+ orr $i2,$i2,$t1,lsl#8
+ ldrb $i3,[$rounds,#23]
+ orr $i2,$i2,$t2,lsl#16
+ ldrb $t1,[$rounds,#22]
+ orr $i2,$i2,$t3,lsl#24
+ ldrb $t2,[$rounds,#21]
+ ldrb $t3,[$rounds,#20]
+ orr $i3,$i3,$t1,lsl#8
+ orr $i3,$i3,$t2,lsl#16
+ str $i2,[$key],#8
+ orr $i3,$i3,$t3,lsl#24
+ str $i3,[$key,#-4]
+#else
+ ldr $i2,[$rounds,#16]
+ ldr $i3,[$rounds,#20]
+#ifdef __ARMEL__
+ rev $i2,$i2
+ rev $i3,$i3
+#endif
+ str $i2,[$key],#8
+ str $i3,[$key,#-4]
+#endif
+
+ teq lr,#192
+ bne .Lnot192
+ mov $rounds,#12
+ str $rounds,[$key,#240-24]
+ add $t3,$tbl,#256 @ rcon
+ mov lr,#255
+ mov $rounds,#8
+
+.L192_loop:
+ and $t2,lr,$i3,lsr#24
+ and $i1,lr,$i3,lsr#16
+ ldrb $t2,[$tbl,$t2]
+ and $i2,lr,$i3,lsr#8
+ ldrb $i1,[$tbl,$i1]
+ and $i3,lr,$i3
+ ldrb $i2,[$tbl,$i2]
+ orr $t2,$t2,$i1,lsl#24
+ ldrb $i3,[$tbl,$i3]
+ orr $t2,$t2,$i2,lsl#16
+ ldr $t1,[$t3],#4 @ rcon[i++]
+ orr $t2,$t2,$i3,lsl#8
+ eor $i3,$t2,$t1
+ eor $s0,$s0,$i3 @ rk[6]=rk[0]^...
+ eor $s1,$s1,$s0 @ rk[7]=rk[1]^rk[6]
+ str $s0,[$key],#24
+ eor $s2,$s2,$s1 @ rk[8]=rk[2]^rk[7]
+ str $s1,[$key,#-20]
+ eor $s3,$s3,$s2 @ rk[9]=rk[3]^rk[8]
+ str $s2,[$key,#-16]
+ subs $rounds,$rounds,#1
+ str $s3,[$key,#-12]
+#if __ARM_ARCH__>=7
+ itt eq @ Thumb2 thing, sanity check in ARM
+#endif
+ subeq r2,$key,#216
+ beq .Ldone
+
+ ldr $i1,[$key,#-32]
+ ldr $i2,[$key,#-28]
+ eor $i1,$i1,$s3 @ rk[10]=rk[4]^rk[9]
+ eor $i3,$i2,$i1 @ rk[11]=rk[5]^rk[10]
+ str $i1,[$key,#-8]
+ str $i3,[$key,#-4]
+ b .L192_loop
+
+.Lnot192:
+#if __ARM_ARCH__<7
+ ldrb $i2,[$rounds,#27]
+ ldrb $t1,[$rounds,#26]
+ ldrb $t2,[$rounds,#25]
+ ldrb $t3,[$rounds,#24]
+ orr $i2,$i2,$t1,lsl#8
+ ldrb $i3,[$rounds,#31]
+ orr $i2,$i2,$t2,lsl#16
+ ldrb $t1,[$rounds,#30]
+ orr $i2,$i2,$t3,lsl#24
+ ldrb $t2,[$rounds,#29]
+ ldrb $t3,[$rounds,#28]
+ orr $i3,$i3,$t1,lsl#8
+ orr $i3,$i3,$t2,lsl#16
+ str $i2,[$key],#8
+ orr $i3,$i3,$t3,lsl#24
+ str $i3,[$key,#-4]
+#else
+ ldr $i2,[$rounds,#24]
+ ldr $i3,[$rounds,#28]
+#ifdef __ARMEL__
+ rev $i2,$i2
+ rev $i3,$i3
+#endif
+ str $i2,[$key],#8
+ str $i3,[$key,#-4]
+#endif
+
+ mov $rounds,#14
+ str $rounds,[$key,#240-32]
+ add $t3,$tbl,#256 @ rcon
+ mov lr,#255
+ mov $rounds,#7
+
+.L256_loop:
+ and $t2,lr,$i3,lsr#24
+ and $i1,lr,$i3,lsr#16
+ ldrb $t2,[$tbl,$t2]
+ and $i2,lr,$i3,lsr#8
+ ldrb $i1,[$tbl,$i1]
+ and $i3,lr,$i3
+ ldrb $i2,[$tbl,$i2]
+ orr $t2,$t2,$i1,lsl#24
+ ldrb $i3,[$tbl,$i3]
+ orr $t2,$t2,$i2,lsl#16
+ ldr $t1,[$t3],#4 @ rcon[i++]
+ orr $t2,$t2,$i3,lsl#8
+ eor $i3,$t2,$t1
+ eor $s0,$s0,$i3 @ rk[8]=rk[0]^...
+ eor $s1,$s1,$s0 @ rk[9]=rk[1]^rk[8]
+ str $s0,[$key],#32
+ eor $s2,$s2,$s1 @ rk[10]=rk[2]^rk[9]
+ str $s1,[$key,#-28]
+ eor $s3,$s3,$s2 @ rk[11]=rk[3]^rk[10]
+ str $s2,[$key,#-24]
+ subs $rounds,$rounds,#1
+ str $s3,[$key,#-20]
+#if __ARM_ARCH__>=7
+ itt eq @ Thumb2 thing, sanity check in ARM
+#endif
+ subeq r2,$key,#256
+ beq .Ldone
+
+ and $t2,lr,$s3
+ and $i1,lr,$s3,lsr#8
+ ldrb $t2,[$tbl,$t2]
+ and $i2,lr,$s3,lsr#16
+ ldrb $i1,[$tbl,$i1]
+ and $i3,lr,$s3,lsr#24
+ ldrb $i2,[$tbl,$i2]
+ orr $t2,$t2,$i1,lsl#8
+ ldrb $i3,[$tbl,$i3]
+ orr $t2,$t2,$i2,lsl#16
+ ldr $t1,[$key,#-48]
+ orr $t2,$t2,$i3,lsl#24
+
+ ldr $i1,[$key,#-44]
+ ldr $i2,[$key,#-40]
+ eor $t1,$t1,$t2 @ rk[12]=rk[4]^...
+ ldr $i3,[$key,#-36]
+ eor $i1,$i1,$t1 @ rk[13]=rk[5]^rk[12]
+ str $t1,[$key,#-16]
+ eor $i2,$i2,$i1 @ rk[14]=rk[6]^rk[13]
+ str $i1,[$key,#-12]
+ eor $i3,$i3,$i2 @ rk[15]=rk[7]^rk[14]
+ str $i2,[$key,#-8]
+ str $i3,[$key,#-4]
+ b .L256_loop
+
+.align 2
+.Ldone: mov r0,#0
+ ldmia sp!,{r4-r12,lr}
+.Labrt:
+#if defined(__thumb2__) && __ARM_ARCH__>=7
+ .short 0x4770 @ bx lr in Thumb2 encoding
+#else
+ tst lr,#1
+ moveq pc,lr @ be binary compatible with V4, yet
+ bx lr @ interoperable with Thumb ISA:-)
+#endif
+.size AES_set_encrypt_key,.-AES_set_encrypt_key
+
+.global AES_set_decrypt_key
+.type AES_set_decrypt_key,%function
+.align 5
+AES_set_decrypt_key:
+ str lr,[sp,#-4]! @ push lr
+ bl _armv4_AES_set_encrypt_key
+ teq r0,#0
+ ldr lr,[sp],#4 @ pop lr
+ bne .Labrt
+
+ mov r0,r2 @ AES_set_encrypt_key preserves r2,
+ mov r1,r2 @ which is AES_KEY *key
+ b _armv4_AES_set_enc2dec_key
+.size AES_set_decrypt_key,.-AES_set_decrypt_key
+
+@ void AES_set_enc2dec_key(const AES_KEY *inp,AES_KEY *out)
+.global AES_set_enc2dec_key
+.type AES_set_enc2dec_key,%function
+.align 5
+AES_set_enc2dec_key:
+_armv4_AES_set_enc2dec_key:
+ stmdb sp!,{r4-r12,lr}
+
+ ldr $rounds,[r0,#240]
+ mov $i1,r0 @ input
+ add $i2,r0,$rounds,lsl#4
+ mov $key,r1 @ ouput
+ add $tbl,r1,$rounds,lsl#4
+ str $rounds,[r1,#240]
+
+.Linv: ldr $s0,[$i1],#16
+ ldr $s1,[$i1,#-12]
+ ldr $s2,[$i1,#-8]
+ ldr $s3,[$i1,#-4]
+ ldr $t1,[$i2],#-16
+ ldr $t2,[$i2,#16+4]
+ ldr $t3,[$i2,#16+8]
+ ldr $i3,[$i2,#16+12]
+ str $s0,[$tbl],#-16
+ str $s1,[$tbl,#16+4]
+ str $s2,[$tbl,#16+8]
+ str $s3,[$tbl,#16+12]
+ str $t1,[$key],#16
+ str $t2,[$key,#-12]
+ str $t3,[$key,#-8]
+ str $i3,[$key,#-4]
+ teq $i1,$i2
+ bne .Linv
+
+ ldr $s0,[$i1]
+ ldr $s1,[$i1,#4]
+ ldr $s2,[$i1,#8]
+ ldr $s3,[$i1,#12]
+ str $s0,[$key]
+ str $s1,[$key,#4]
+ str $s2,[$key,#8]
+ str $s3,[$key,#12]
+ sub $key,$key,$rounds,lsl#3
+___
+$mask80=$i1;
+$mask1b=$i2;
+$mask7f=$i3;
+$code.=<<___;
+ ldr $s0,[$key,#16]! @ prefetch tp1
+ mov $mask80,#0x80
+ mov $mask1b,#0x1b
+ orr $mask80,$mask80,#0x8000
+ orr $mask1b,$mask1b,#0x1b00
+ orr $mask80,$mask80,$mask80,lsl#16
+ orr $mask1b,$mask1b,$mask1b,lsl#16
+ sub $rounds,$rounds,#1
+ mvn $mask7f,$mask80
+ mov $rounds,$rounds,lsl#2 @ (rounds-1)*4
+
+.Lmix: and $t1,$s0,$mask80
+ and $s1,$s0,$mask7f
+ sub $t1,$t1,$t1,lsr#7
+ and $t1,$t1,$mask1b
+ eor $s1,$t1,$s1,lsl#1 @ tp2
+
+ and $t1,$s1,$mask80
+ and $s2,$s1,$mask7f
+ sub $t1,$t1,$t1,lsr#7
+ and $t1,$t1,$mask1b
+ eor $s2,$t1,$s2,lsl#1 @ tp4
+
+ and $t1,$s2,$mask80
+ and $s3,$s2,$mask7f
+ sub $t1,$t1,$t1,lsr#7
+ and $t1,$t1,$mask1b
+ eor $s3,$t1,$s3,lsl#1 @ tp8
+
+ eor $t1,$s1,$s2
+ eor $t2,$s0,$s3 @ tp9
+ eor $t1,$t1,$s3 @ tpe
+ eor $t1,$t1,$s1,ror#24
+ eor $t1,$t1,$t2,ror#24 @ ^= ROTATE(tpb=tp9^tp2,8)
+ eor $t1,$t1,$s2,ror#16
+ eor $t1,$t1,$t2,ror#16 @ ^= ROTATE(tpd=tp9^tp4,16)
+ eor $t1,$t1,$t2,ror#8 @ ^= ROTATE(tp9,24)
+
+ ldr $s0,[$key,#4] @ prefetch tp1
+ str $t1,[$key],#4
+ subs $rounds,$rounds,#1
+ bne .Lmix
+
+ mov r0,#0
+#if __ARM_ARCH__>=5
+ ldmia sp!,{r4-r12,pc}
+#else
+ ldmia sp!,{r4-r12,lr}
+ tst lr,#1
+ moveq pc,lr @ be binary compatible with V4, yet
+ bx lr @ interoperable with Thumb ISA:-)
+#endif
+.size AES_set_enc2dec_key,.-AES_set_enc2dec_key
+
+.type AES_Td,%object
+.align 5
+AES_Td:
+.word 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96
+.word 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393
+.word 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25
+.word 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f
+.word 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1
+.word 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6
+.word 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da
+.word 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844
+.word 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd
+.word 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4
+.word 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45
+.word 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94
+.word 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7
+.word 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a
+.word 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5
+.word 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c
+.word 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1
+.word 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a
+.word 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75
+.word 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051
+.word 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46
+.word 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff
+.word 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77
+.word 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb
+.word 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000
+.word 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e
+.word 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927
+.word 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a
+.word 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e
+.word 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16
+.word 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d
+.word 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8
+.word 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd
+.word 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34
+.word 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163
+.word 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120
+.word 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d
+.word 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0
+.word 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422
+.word 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef
+.word 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36
+.word 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4
+.word 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662
+.word 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5
+.word 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3
+.word 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b
+.word 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8
+.word 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6
+.word 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6
+.word 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0
+.word 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815
+.word 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f
+.word 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df
+.word 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f
+.word 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e
+.word 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713
+.word 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89
+.word 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c
+.word 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf
+.word 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86
+.word 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f
+.word 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541
+.word 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190
+.word 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742
+@ Td4[256]
+.byte 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38
+.byte 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb
+.byte 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87
+.byte 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb
+.byte 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d
+.byte 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e
+.byte 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2
+.byte 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25
+.byte 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16
+.byte 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92
+.byte 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda
+.byte 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84
+.byte 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a
+.byte 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06
+.byte 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02
+.byte 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b
+.byte 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea
+.byte 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73
+.byte 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85
+.byte 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e
+.byte 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89
+.byte 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b
+.byte 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20
+.byte 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4
+.byte 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31
+.byte 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f
+.byte 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d
+.byte 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef
+.byte 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0
+.byte 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61
+.byte 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26
+.byte 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
+.size AES_Td,.-AES_Td
+
+@ void AES_decrypt(const unsigned char *in, unsigned char *out,
+@ const AES_KEY *key) {
+.global AES_decrypt
+.type AES_decrypt,%function
+.align 5
+AES_decrypt:
+#if __ARM_ARCH__<7
+ sub r3,pc,#8 @ AES_decrypt
+#else
+ adr r3,AES_decrypt
+#endif
+ stmdb sp!,{r1,r4-r12,lr}
+ mov $rounds,r0 @ inp
+ mov $key,r2
+ sub $tbl,r3,#AES_decrypt-AES_Td @ Td
+#if __ARM_ARCH__<7
+ ldrb $s0,[$rounds,#3] @ load input data in endian-neutral
+ ldrb $t1,[$rounds,#2] @ manner...
+ ldrb $t2,[$rounds,#1]
+ ldrb $t3,[$rounds,#0]
+ orr $s0,$s0,$t1,lsl#8
+ ldrb $s1,[$rounds,#7]
+ orr $s0,$s0,$t2,lsl#16
+ ldrb $t1,[$rounds,#6]
+ orr $s0,$s0,$t3,lsl#24
+ ldrb $t2,[$rounds,#5]
+ ldrb $t3,[$rounds,#4]
+ orr $s1,$s1,$t1,lsl#8
+ ldrb $s2,[$rounds,#11]
+ orr $s1,$s1,$t2,lsl#16
+ ldrb $t1,[$rounds,#10]
+ orr $s1,$s1,$t3,lsl#24
+ ldrb $t2,[$rounds,#9]
+ ldrb $t3,[$rounds,#8]
+ orr $s2,$s2,$t1,lsl#8
+ ldrb $s3,[$rounds,#15]
+ orr $s2,$s2,$t2,lsl#16
+ ldrb $t1,[$rounds,#14]
+ orr $s2,$s2,$t3,lsl#24
+ ldrb $t2,[$rounds,#13]
+ ldrb $t3,[$rounds,#12]
+ orr $s3,$s3,$t1,lsl#8
+ orr $s3,$s3,$t2,lsl#16
+ orr $s3,$s3,$t3,lsl#24
+#else
+ ldr $s0,[$rounds,#0]
+ ldr $s1,[$rounds,#4]
+ ldr $s2,[$rounds,#8]
+ ldr $s3,[$rounds,#12]
+#ifdef __ARMEL__
+ rev $s0,$s0
+ rev $s1,$s1
+ rev $s2,$s2
+ rev $s3,$s3
+#endif
+#endif
+ bl _armv4_AES_decrypt
+
+ ldr $rounds,[sp],#4 @ pop out
+#if __ARM_ARCH__>=7
+#ifdef __ARMEL__
+ rev $s0,$s0
+ rev $s1,$s1
+ rev $s2,$s2
+ rev $s3,$s3
+#endif
+ str $s0,[$rounds,#0]
+ str $s1,[$rounds,#4]
+ str $s2,[$rounds,#8]
+ str $s3,[$rounds,#12]
+#else
+ mov $t1,$s0,lsr#24 @ write output in endian-neutral
+ mov $t2,$s0,lsr#16 @ manner...
+ mov $t3,$s0,lsr#8
+ strb $t1,[$rounds,#0]
+ strb $t2,[$rounds,#1]
+ mov $t1,$s1,lsr#24
+ strb $t3,[$rounds,#2]
+ mov $t2,$s1,lsr#16
+ strb $s0,[$rounds,#3]
+ mov $t3,$s1,lsr#8
+ strb $t1,[$rounds,#4]
+ strb $t2,[$rounds,#5]
+ mov $t1,$s2,lsr#24
+ strb $t3,[$rounds,#6]
+ mov $t2,$s2,lsr#16
+ strb $s1,[$rounds,#7]
+ mov $t3,$s2,lsr#8
+ strb $t1,[$rounds,#8]
+ strb $t2,[$rounds,#9]
+ mov $t1,$s3,lsr#24
+ strb $t3,[$rounds,#10]
+ mov $t2,$s3,lsr#16
+ strb $s2,[$rounds,#11]
+ mov $t3,$s3,lsr#8
+ strb $t1,[$rounds,#12]
+ strb $t2,[$rounds,#13]
+ strb $t3,[$rounds,#14]
+ strb $s3,[$rounds,#15]
+#endif
+#if __ARM_ARCH__>=5
+ ldmia sp!,{r4-r12,pc}
+#else
+ ldmia sp!,{r4-r12,lr}
+ tst lr,#1
+ moveq pc,lr @ be binary compatible with V4, yet
+ bx lr @ interoperable with Thumb ISA:-)
+#endif
+.size AES_decrypt,.-AES_decrypt
+
+.type _armv4_AES_decrypt,%function
+.align 2
+_armv4_AES_decrypt:
+ str lr,[sp,#-4]! @ push lr
+ ldmia $key!,{$t1-$i1}
+ eor $s0,$s0,$t1
+ ldr $rounds,[$key,#240-16]
+ eor $s1,$s1,$t2
+ eor $s2,$s2,$t3
+ eor $s3,$s3,$i1
+ sub $rounds,$rounds,#1
+ mov lr,#255
+
+ and $i1,lr,$s0,lsr#16
+ and $i2,lr,$s0,lsr#8
+ and $i3,lr,$s0
+ mov $s0,$s0,lsr#24
+.Ldec_loop:
+ ldr $t1,[$tbl,$i1,lsl#2] @ Td1[s0>>16]
+ and $i1,lr,$s1 @ i0
+ ldr $t2,[$tbl,$i2,lsl#2] @ Td2[s0>>8]
+ and $i2,lr,$s1,lsr#16
+ ldr $t3,[$tbl,$i3,lsl#2] @ Td3[s0>>0]
+ and $i3,lr,$s1,lsr#8
+ ldr $s0,[$tbl,$s0,lsl#2] @ Td0[s0>>24]
+ mov $s1,$s1,lsr#24
+
+ ldr $i1,[$tbl,$i1,lsl#2] @ Td3[s1>>0]
+ ldr $i2,[$tbl,$i2,lsl#2] @ Td1[s1>>16]
+ ldr $i3,[$tbl,$i3,lsl#2] @ Td2[s1>>8]
+ eor $s0,$s0,$i1,ror#24
+ ldr $s1,[$tbl,$s1,lsl#2] @ Td0[s1>>24]
+ and $i1,lr,$s2,lsr#8 @ i0
+ eor $t2,$i2,$t2,ror#8
+ and $i2,lr,$s2 @ i1
+ eor $t3,$i3,$t3,ror#8
+ and $i3,lr,$s2,lsr#16
+ ldr $i1,[$tbl,$i1,lsl#2] @ Td2[s2>>8]
+ eor $s1,$s1,$t1,ror#8
+ ldr $i2,[$tbl,$i2,lsl#2] @ Td3[s2>>0]
+ mov $s2,$s2,lsr#24
+
+ ldr $i3,[$tbl,$i3,lsl#2] @ Td1[s2>>16]
+ eor $s0,$s0,$i1,ror#16
+ ldr $s2,[$tbl,$s2,lsl#2] @ Td0[s2>>24]
+ and $i1,lr,$s3,lsr#16 @ i0
+ eor $s1,$s1,$i2,ror#24
+ and $i2,lr,$s3,lsr#8 @ i1
+ eor $t3,$i3,$t3,ror#8
+ and $i3,lr,$s3 @ i2
+ ldr $i1,[$tbl,$i1,lsl#2] @ Td1[s3>>16]
+ eor $s2,$s2,$t2,ror#8
+ ldr $i2,[$tbl,$i2,lsl#2] @ Td2[s3>>8]
+ mov $s3,$s3,lsr#24
+
+ ldr $i3,[$tbl,$i3,lsl#2] @ Td3[s3>>0]
+ eor $s0,$s0,$i1,ror#8
+ ldr $i1,[$key],#16
+ eor $s1,$s1,$i2,ror#16
+ ldr $s3,[$tbl,$s3,lsl#2] @ Td0[s3>>24]
+ eor $s2,$s2,$i3,ror#24
+
+ ldr $t1,[$key,#-12]
+ eor $s0,$s0,$i1
+ ldr $t2,[$key,#-8]
+ eor $s3,$s3,$t3,ror#8
+ ldr $t3,[$key,#-4]
+ and $i1,lr,$s0,lsr#16
+ eor $s1,$s1,$t1
+ and $i2,lr,$s0,lsr#8
+ eor $s2,$s2,$t2
+ and $i3,lr,$s0
+ eor $s3,$s3,$t3
+ mov $s0,$s0,lsr#24
+
+ subs $rounds,$rounds,#1
+ bne .Ldec_loop
+
+ add $tbl,$tbl,#1024
+
+ ldr $t2,[$tbl,#0] @ prefetch Td4
+ ldr $t3,[$tbl,#32]
+ ldr $t1,[$tbl,#64]
+ ldr $t2,[$tbl,#96]
+ ldr $t3,[$tbl,#128]
+ ldr $t1,[$tbl,#160]
+ ldr $t2,[$tbl,#192]
+ ldr $t3,[$tbl,#224]
+
+ ldrb $s0,[$tbl,$s0] @ Td4[s0>>24]
+ ldrb $t1,[$tbl,$i1] @ Td4[s0>>16]
+ and $i1,lr,$s1 @ i0
+ ldrb $t2,[$tbl,$i2] @ Td4[s0>>8]
+ and $i2,lr,$s1,lsr#16
+ ldrb $t3,[$tbl,$i3] @ Td4[s0>>0]
+ and $i3,lr,$s1,lsr#8
+
+ add $s1,$tbl,$s1,lsr#24
+ ldrb $i1,[$tbl,$i1] @ Td4[s1>>0]
+ ldrb $s1,[$s1] @ Td4[s1>>24]
+ ldrb $i2,[$tbl,$i2] @ Td4[s1>>16]
+ eor $s0,$i1,$s0,lsl#24
+ ldrb $i3,[$tbl,$i3] @ Td4[s1>>8]
+ eor $s1,$t1,$s1,lsl#8
+ and $i1,lr,$s2,lsr#8 @ i0
+ eor $t2,$t2,$i2,lsl#8
+ and $i2,lr,$s2 @ i1
+ ldrb $i1,[$tbl,$i1] @ Td4[s2>>8]
+ eor $t3,$t3,$i3,lsl#8
+ ldrb $i2,[$tbl,$i2] @ Td4[s2>>0]
+ and $i3,lr,$s2,lsr#16
+
+ add $s2,$tbl,$s2,lsr#24
+ ldrb $s2,[$s2] @ Td4[s2>>24]
+ eor $s0,$s0,$i1,lsl#8
+ ldrb $i3,[$tbl,$i3] @ Td4[s2>>16]
+ eor $s1,$i2,$s1,lsl#16
+ and $i1,lr,$s3,lsr#16 @ i0
+ eor $s2,$t2,$s2,lsl#16
+ and $i2,lr,$s3,lsr#8 @ i1
+ ldrb $i1,[$tbl,$i1] @ Td4[s3>>16]
+ eor $t3,$t3,$i3,lsl#16
+ ldrb $i2,[$tbl,$i2] @ Td4[s3>>8]
+ and $i3,lr,$s3 @ i2
+
+ add $s3,$tbl,$s3,lsr#24
+ ldrb $i3,[$tbl,$i3] @ Td4[s3>>0]
+ ldrb $s3,[$s3] @ Td4[s3>>24]
+ eor $s0,$s0,$i1,lsl#16
+ ldr $i1,[$key,#0]
+ eor $s1,$s1,$i2,lsl#8
+ ldr $t1,[$key,#4]
+ eor $s2,$i3,$s2,lsl#8
+ ldr $t2,[$key,#8]
+ eor $s3,$t3,$s3,lsl#24
+ ldr $t3,[$key,#12]
+
+ eor $s0,$s0,$i1
+ eor $s1,$s1,$t1
+ eor $s2,$s2,$t2
+ eor $s3,$s3,$t3
+
+ sub $tbl,$tbl,#1024
+ ldr pc,[sp],#4 @ pop and return
+.size _armv4_AES_decrypt,.-_armv4_AES_decrypt
+.asciz "AES for ARMv4, CRYPTOGAMS by <appro\@openssl.org>"
+.align 2
+
+#endif
+___
+
+$code =~ s/\bbx\s+lr\b/.word\t0xe12fff1e/gm; # make it possible to compile with -march=armv4
+
+open SELF,$0;
+while(<SELF>) {
+ next if (/^#!/);
+ last if (!s/^#/@/ and !/^$/);
+ print;
+}
+close SELF;
+
+print $code;
+close STDOUT; # enforce flush
diff --git a/crypto/aes/asm/aes-x86_64.pl b/crypto/aes/asm/aes-x86_64.pl
new file mode 100644
index 0000000..e2a1246
--- /dev/null
+++ b/crypto/aes/asm/aes-x86_64.pl
@@ -0,0 +1,2811 @@
+#!/usr/bin/env perl
+#
+# ====================================================================
+# Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+#
+# Version 2.1.
+#
+# aes-*-cbc benchmarks are improved by >70% [compared to gcc 3.3.2 on
+# Opteron 240 CPU] plus all the bells-n-whistles from 32-bit version
+# [you'll notice a lot of resemblance], such as compressed S-boxes
+# in little-endian byte order, prefetch of these tables in CBC mode,
+# as well as avoiding L1 cache aliasing between stack frame and key
+# schedule and already mentioned tables, compressed Td4...
+#
+# Performance in number of cycles per processed byte for 128-bit key:
+#
+# ECB encrypt ECB decrypt CBC large chunk
+# AMD64 33 43 13.0
+# EM64T 38 56 18.6(*)
+# Core 2 30 42 14.5(*)
+# Atom 65 86 32.1(*)
+#
+# (*) with hyper-threading off
+
+$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;
+
+$verticalspin=1; # unlike 32-bit version $verticalspin performs
+ # ~15% better on both AMD and Intel cores
+$speed_limit=512; # see aes-586.pl for details
+
+$code=".text\n";
+
+$s0="%eax";
+$s1="%ebx";
+$s2="%ecx";
+$s3="%edx";
+$acc0="%esi"; $mask80="%rsi";
+$acc1="%edi"; $maskfe="%rdi";
+$acc2="%ebp"; $mask1b="%rbp";
+$inp="%r8";
+$out="%r9";
+$t0="%r10d";
+$t1="%r11d";
+$t2="%r12d";
+$rnds="%r13d";
+$sbox="%r14";
+$key="%r15";
+
+sub hi() { my $r=shift; $r =~ s/%[er]([a-d])x/%\1h/; $r; }
+sub lo() { my $r=shift; $r =~ s/%[er]([a-d])x/%\1l/;
+ $r =~ s/%[er]([sd]i)/%\1l/;
+ $r =~ s/%(r[0-9]+)[d]?/%\1b/; $r; }
+sub LO() { my $r=shift; $r =~ s/%r([a-z]+)/%e\1/;
+ $r =~ s/%r([0-9]+)/%r\1d/; $r; }
+sub _data_word()
+{ my $i;
+ while(defined($i=shift)) { $code.=sprintf".long\t0x%08x,0x%08x\n",$i,$i; }
+}
+sub data_word()
+{ my $i;
+ my $last=pop(@_);
+ $code.=".long\t";
+ while(defined($i=shift)) { $code.=sprintf"0x%08x,",$i; }
+ $code.=sprintf"0x%08x\n",$last;
+}
+
+sub data_byte()
+{ my $i;
+ my $last=pop(@_);
+ $code.=".byte\t";
+ while(defined($i=shift)) { $code.=sprintf"0x%02x,",$i&0xff; }
+ $code.=sprintf"0x%02x\n",$last&0xff;
+}
+
+sub encvert()
+{ my $t3="%r8d"; # zaps $inp!
+
+$code.=<<___;
+ # favor 3-way issue Opteron pipeline...
+ movzb `&lo("$s0")`,$acc0
+ movzb `&lo("$s1")`,$acc1
+ movzb `&lo("$s2")`,$acc2
+ mov 0($sbox,$acc0,8),$t0
+ mov 0($sbox,$acc1,8),$t1
+ mov 0($sbox,$acc2,8),$t2
+
+ movzb `&hi("$s1")`,$acc0
+ movzb `&hi("$s2")`,$acc1
+ movzb `&lo("$s3")`,$acc2
+ xor 3($sbox,$acc0,8),$t0
+ xor 3($sbox,$acc1,8),$t1
+ mov 0($sbox,$acc2,8),$t3
+
+ movzb `&hi("$s3")`,$acc0
+ shr \$16,$s2
+ movzb `&hi("$s0")`,$acc2
+ xor 3($sbox,$acc0,8),$t2
+ shr \$16,$s3
+ xor 3($sbox,$acc2,8),$t3
+
+ shr \$16,$s1
+ lea 16($key),$key
+ shr \$16,$s0
+
+ movzb `&lo("$s2")`,$acc0
+ movzb `&lo("$s3")`,$acc1
+ movzb `&lo("$s0")`,$acc2
+ xor 2($sbox,$acc0,8),$t0
+ xor 2($sbox,$acc1,8),$t1
+ xor 2($sbox,$acc2,8),$t2
+
+ movzb `&hi("$s3")`,$acc0
+ movzb `&hi("$s0")`,$acc1
+ movzb `&lo("$s1")`,$acc2
+ xor 1($sbox,$acc0,8),$t0
+ xor 1($sbox,$acc1,8),$t1
+ xor 2($sbox,$acc2,8),$t3
+
+ mov 12($key),$s3
+ movzb `&hi("$s1")`,$acc1
+ movzb `&hi("$s2")`,$acc2
+ mov 0($key),$s0
+ xor 1($sbox,$acc1,8),$t2
+ xor 1($sbox,$acc2,8),$t3
+
+ mov 4($key),$s1
+ mov 8($key),$s2
+ xor $t0,$s0
+ xor $t1,$s1
+ xor $t2,$s2
+ xor $t3,$s3
+___
+}
+
+sub enclastvert()
+{ my $t3="%r8d"; # zaps $inp!
+
+$code.=<<___;
+ movzb `&lo("$s0")`,$acc0
+ movzb `&lo("$s1")`,$acc1
+ movzb `&lo("$s2")`,$acc2
+ movzb 2($sbox,$acc0,8),$t0
+ movzb 2($sbox,$acc1,8),$t1
+ movzb 2($sbox,$acc2,8),$t2
+
+ movzb `&lo("$s3")`,$acc0
+ movzb `&hi("$s1")`,$acc1
+ movzb `&hi("$s2")`,$acc2
+ movzb 2($sbox,$acc0,8),$t3
+ mov 0($sbox,$acc1,8),$acc1 #$t0
+ mov 0($sbox,$acc2,8),$acc2 #$t1
+
+ and \$0x0000ff00,$acc1
+ and \$0x0000ff00,$acc2
+
+ xor $acc1,$t0
+ xor $acc2,$t1
+ shr \$16,$s2
+
+ movzb `&hi("$s3")`,$acc0
+ movzb `&hi("$s0")`,$acc1
+ shr \$16,$s3
+ mov 0($sbox,$acc0,8),$acc0 #$t2
+ mov 0($sbox,$acc1,8),$acc1 #$t3
+
+ and \$0x0000ff00,$acc0
+ and \$0x0000ff00,$acc1
+ shr \$16,$s1
+ xor $acc0,$t2
+ xor $acc1,$t3
+ shr \$16,$s0
+
+ movzb `&lo("$s2")`,$acc0
+ movzb `&lo("$s3")`,$acc1
+ movzb `&lo("$s0")`,$acc2
+ mov 0($sbox,$acc0,8),$acc0 #$t0
+ mov 0($sbox,$acc1,8),$acc1 #$t1
+ mov 0($sbox,$acc2,8),$acc2 #$t2
+
+ and \$0x00ff0000,$acc0
+ and \$0x00ff0000,$acc1
+ and \$0x00ff0000,$acc2
+
+ xor $acc0,$t0
+ xor $acc1,$t1
+ xor $acc2,$t2
+
+ movzb `&lo("$s1")`,$acc0
+ movzb `&hi("$s3")`,$acc1
+ movzb `&hi("$s0")`,$acc2
+ mov 0($sbox,$acc0,8),$acc0 #$t3
+ mov 2($sbox,$acc1,8),$acc1 #$t0
+ mov 2($sbox,$acc2,8),$acc2 #$t1
+
+ and \$0x00ff0000,$acc0
+ and \$0xff000000,$acc1
+ and \$0xff000000,$acc2
+
+ xor $acc0,$t3
+ xor $acc1,$t0
+ xor $acc2,$t1
+
+ movzb `&hi("$s1")`,$acc0
+ movzb `&hi("$s2")`,$acc1
+ mov 16+12($key),$s3
+ mov 2($sbox,$acc0,8),$acc0 #$t2
+ mov 2($sbox,$acc1,8),$acc1 #$t3
+ mov 16+0($key),$s0
+
+ and \$0xff000000,$acc0
+ and \$0xff000000,$acc1
+
+ xor $acc0,$t2
+ xor $acc1,$t3
+
+ mov 16+4($key),$s1
+ mov 16+8($key),$s2
+ xor $t0,$s0
+ xor $t1,$s1
+ xor $t2,$s2
+ xor $t3,$s3
+___
+}
+
+sub encstep()
+{ my ($i,@s) = @_;
+ my $tmp0=$acc0;
+ my $tmp1=$acc1;
+ my $tmp2=$acc2;
+ my $out=($t0,$t1,$t2,$s[0])[$i];
+
+ if ($i==3) {
+ $tmp0=$s[1];
+ $tmp1=$s[2];
+ $tmp2=$s[3];
+ }
+ $code.=" movzb ".&lo($s[0]).",$out\n";
+ $code.=" mov $s[2],$tmp1\n" if ($i!=3);
+ $code.=" lea 16($key),$key\n" if ($i==0);
+
+ $code.=" movzb ".&hi($s[1]).",$tmp0\n";
+ $code.=" mov 0($sbox,$out,8),$out\n";
+
+ $code.=" shr \$16,$tmp1\n";
+ $code.=" mov $s[3],$tmp2\n" if ($i!=3);
+ $code.=" xor 3($sbox,$tmp0,8),$out\n";
+
+ $code.=" movzb ".&lo($tmp1).",$tmp1\n";
+ $code.=" shr \$24,$tmp2\n";
+ $code.=" xor 4*$i($key),$out\n";
+
+ $code.=" xor 2($sbox,$tmp1,8),$out\n";
+ $code.=" xor 1($sbox,$tmp2,8),$out\n";
+
+ $code.=" mov $t0,$s[1]\n" if ($i==3);
+ $code.=" mov $t1,$s[2]\n" if ($i==3);
+ $code.=" mov $t2,$s[3]\n" if ($i==3);
+ $code.="\n";
+}
+
+sub enclast()
+{ my ($i,@s)=@_;
+ my $tmp0=$acc0;
+ my $tmp1=$acc1;
+ my $tmp2=$acc2;
+ my $out=($t0,$t1,$t2,$s[0])[$i];
+
+ if ($i==3) {
+ $tmp0=$s[1];
+ $tmp1=$s[2];
+ $tmp2=$s[3];
+ }
+ $code.=" movzb ".&lo($s[0]).",$out\n";
+ $code.=" mov $s[2],$tmp1\n" if ($i!=3);
+
+ $code.=" mov 2($sbox,$out,8),$out\n";
+ $code.=" shr \$16,$tmp1\n";
+ $code.=" mov $s[3],$tmp2\n" if ($i!=3);
+
+ $code.=" and \$0x000000ff,$out\n";
+ $code.=" movzb ".&hi($s[1]).",$tmp0\n";
+ $code.=" movzb ".&lo($tmp1).",$tmp1\n";
+ $code.=" shr \$24,$tmp2\n";
+
+ $code.=" mov 0($sbox,$tmp0,8),$tmp0\n";
+ $code.=" mov 0($sbox,$tmp1,8),$tmp1\n";
+ $code.=" mov 2($sbox,$tmp2,8),$tmp2\n";
+
+ $code.=" and \$0x0000ff00,$tmp0\n";
+ $code.=" and \$0x00ff0000,$tmp1\n";
+ $code.=" and \$0xff000000,$tmp2\n";
+
+ $code.=" xor $tmp0,$out\n";
+ $code.=" mov $t0,$s[1]\n" if ($i==3);
+ $code.=" xor $tmp1,$out\n";
+ $code.=" mov $t1,$s[2]\n" if ($i==3);
+ $code.=" xor $tmp2,$out\n";
+ $code.=" mov $t2,$s[3]\n" if ($i==3);
+ $code.="\n";
+}
+
+$code.=<<___;
+.type _x86_64_AES_encrypt,\@abi-omnipotent
+.align 16
+_x86_64_AES_encrypt:
+ xor 0($key),$s0 # xor with key
+ xor 4($key),$s1
+ xor 8($key),$s2
+ xor 12($key),$s3
+
+ mov 240($key),$rnds # load key->rounds
+ sub \$1,$rnds
+ jmp .Lenc_loop
+.align 16
+.Lenc_loop:
+___
+ if ($verticalspin) { &encvert(); }
+ else { &encstep(0,$s0,$s1,$s2,$s3);
+ &encstep(1,$s1,$s2,$s3,$s0);
+ &encstep(2,$s2,$s3,$s0,$s1);
+ &encstep(3,$s3,$s0,$s1,$s2);
+ }
+$code.=<<___;
+ sub \$1,$rnds
+ jnz .Lenc_loop
+___
+ if ($verticalspin) { &enclastvert(); }
+ else { &enclast(0,$s0,$s1,$s2,$s3);
+ &enclast(1,$s1,$s2,$s3,$s0);
+ &enclast(2,$s2,$s3,$s0,$s1);
+ &enclast(3,$s3,$s0,$s1,$s2);
+ $code.=<<___;
+ xor 16+0($key),$s0 # xor with key
+ xor 16+4($key),$s1
+ xor 16+8($key),$s2
+ xor 16+12($key),$s3
+___
+ }
+$code.=<<___;
+ .byte 0xf3,0xc3 # rep ret
+.size _x86_64_AES_encrypt,.-_x86_64_AES_encrypt
+___
+
+# it's possible to implement this by shifting tN by 8, filling least
+# significant byte with byte load and finally bswap-ing at the end,
+# but such partial register load kills Core 2...
+sub enccompactvert()
+{ my ($t3,$t4,$t5)=("%r8d","%r9d","%r13d");
+
+$code.=<<___;
+ movzb `&lo("$s0")`,$t0
+ movzb `&lo("$s1")`,$t1
+ movzb `&lo("$s2")`,$t2
+ movzb `&lo("$s3")`,$t3
+ movzb `&hi("$s1")`,$acc0
+ movzb `&hi("$s2")`,$acc1
+ shr \$16,$s2
+ movzb `&hi("$s3")`,$acc2
+ movzb ($sbox,$t0,1),$t0
+ movzb ($sbox,$t1,1),$t1
+ movzb ($sbox,$t2,1),$t2
+ movzb ($sbox,$t3,1),$t3
+
+ movzb ($sbox,$acc0,1),$t4 #$t0
+ movzb `&hi("$s0")`,$acc0
+ movzb ($sbox,$acc1,1),$t5 #$t1
+ movzb `&lo("$s2")`,$acc1
+ movzb ($sbox,$acc2,1),$acc2 #$t2
+ movzb ($sbox,$acc0,1),$acc0 #$t3
+
+ shl \$8,$t4
+ shr \$16,$s3
+ shl \$8,$t5
+ xor $t4,$t0
+ shr \$16,$s0
+ movzb `&lo("$s3")`,$t4
+ shr \$16,$s1
+ xor $t5,$t1
+ shl \$8,$acc2
+ movzb `&lo("$s0")`,$t5
+ movzb ($sbox,$acc1,1),$acc1 #$t0
+ xor $acc2,$t2
+
+ shl \$8,$acc0
+ movzb `&lo("$s1")`,$acc2
+ shl \$16,$acc1
+ xor $acc0,$t3
+ movzb ($sbox,$t4,1),$t4 #$t1
+ movzb `&hi("$s3")`,$acc0
+ movzb ($sbox,$t5,1),$t5 #$t2
+ xor $acc1,$t0
+
+ shr \$8,$s2
+ movzb `&hi("$s0")`,$acc1
+ shl \$16,$t4
+ shr \$8,$s1
+ shl \$16,$t5
+ xor $t4,$t1
+ movzb ($sbox,$acc2,1),$acc2 #$t3
+ movzb ($sbox,$acc0,1),$acc0 #$t0
+ movzb ($sbox,$acc1,1),$acc1 #$t1
+ movzb ($sbox,$s2,1),$s3 #$t3
+ movzb ($sbox,$s1,1),$s2 #$t2
+
+ shl \$16,$acc2
+ xor $t5,$t2
+ shl \$24,$acc0
+ xor $acc2,$t3
+ shl \$24,$acc1
+ xor $acc0,$t0
+ shl \$24,$s3
+ xor $acc1,$t1
+ shl \$24,$s2
+ mov $t0,$s0
+ mov $t1,$s1
+ xor $t2,$s2
+ xor $t3,$s3
+___
+}
+
+sub enctransform_ref()
+{ my $sn = shift;
+ my ($acc,$r2,$tmp)=("%r8d","%r9d","%r13d");
+
+$code.=<<___;
+ mov $sn,$acc
+ and \$0x80808080,$acc
+ mov $acc,$tmp
+ shr \$7,$tmp
+ lea ($sn,$sn),$r2
+ sub $tmp,$acc
+ and \$0xfefefefe,$r2
+ and \$0x1b1b1b1b,$acc
+ mov $sn,$tmp
+ xor $acc,$r2
+
+ xor $r2,$sn
+ rol \$24,$sn
+ xor $r2,$sn
+ ror \$16,$tmp
+ xor $tmp,$sn
+ ror \$8,$tmp
+ xor $tmp,$sn
+___
+}
+
+# unlike decrypt case it does not pay off to parallelize enctransform
+sub enctransform()
+{ my ($t3,$r20,$r21)=($acc2,"%r8d","%r9d");
+
+$code.=<<___;
+ mov \$0x80808080,$t0
+ mov \$0x80808080,$t1
+ and $s0,$t0
+ and $s1,$t1
+ mov $t0,$acc0
+ mov $t1,$acc1
+ shr \$7,$t0
+ lea ($s0,$s0),$r20
+ shr \$7,$t1
+ lea ($s1,$s1),$r21
+ sub $t0,$acc0
+ sub $t1,$acc1
+ and \$0xfefefefe,$r20
+ and \$0xfefefefe,$r21
+ and \$0x1b1b1b1b,$acc0
+ and \$0x1b1b1b1b,$acc1
+ mov $s0,$t0
+ mov $s1,$t1
+ xor $acc0,$r20
+ xor $acc1,$r21
+
+ xor $r20,$s0
+ xor $r21,$s1
+ mov \$0x80808080,$t2
+ rol \$24,$s0
+ mov \$0x80808080,$t3
+ rol \$24,$s1
+ and $s2,$t2
+ and $s3,$t3
+ xor $r20,$s0
+ xor $r21,$s1
+ mov $t2,$acc0
+ ror \$16,$t0
+ mov $t3,$acc1
+ ror \$16,$t1
+ lea ($s2,$s2),$r20
+ shr \$7,$t2
+ xor $t0,$s0
+ shr \$7,$t3
+ xor $t1,$s1
+ ror \$8,$t0
+ lea ($s3,$s3),$r21
+ ror \$8,$t1
+ sub $t2,$acc0
+ sub $t3,$acc1
+ xor $t0,$s0
+ xor $t1,$s1
+
+ and \$0xfefefefe,$r20
+ and \$0xfefefefe,$r21
+ and \$0x1b1b1b1b,$acc0
+ and \$0x1b1b1b1b,$acc1
+ mov $s2,$t2
+ mov $s3,$t3
+ xor $acc0,$r20
+ xor $acc1,$r21
+
+ ror \$16,$t2
+ xor $r20,$s2
+ ror \$16,$t3
+ xor $r21,$s3
+ rol \$24,$s2
+ mov 0($sbox),$acc0 # prefetch Te4
+ rol \$24,$s3
+ xor $r20,$s2
+ mov 64($sbox),$acc1
+ xor $r21,$s3
+ mov 128($sbox),$r20
+ xor $t2,$s2
+ ror \$8,$t2
+ xor $t3,$s3
+ ror \$8,$t3
+ xor $t2,$s2
+ mov 192($sbox),$r21
+ xor $t3,$s3
+___
+}
+
+$code.=<<___;
+.type _x86_64_AES_encrypt_compact,\@abi-omnipotent
+.align 16
+_x86_64_AES_encrypt_compact:
+ lea 128($sbox),$inp # size optimization
+ mov 0-128($inp),$acc1 # prefetch Te4
+ mov 32-128($inp),$acc2
+ mov 64-128($inp),$t0
+ mov 96-128($inp),$t1
+ mov 128-128($inp),$acc1
+ mov 160-128($inp),$acc2
+ mov 192-128($inp),$t0
+ mov 224-128($inp),$t1
+ jmp .Lenc_loop_compact
+.align 16
+.Lenc_loop_compact:
+ xor 0($key),$s0 # xor with key
+ xor 4($key),$s1
+ xor 8($key),$s2
+ xor 12($key),$s3
+ lea 16($key),$key
+___
+ &enccompactvert();
+$code.=<<___;
+ cmp 16(%rsp),$key
+ je .Lenc_compact_done
+___
+ &enctransform();
+$code.=<<___;
+ jmp .Lenc_loop_compact
+.align 16
+.Lenc_compact_done:
+ xor 0($key),$s0
+ xor 4($key),$s1
+ xor 8($key),$s2
+ xor 12($key),$s3
+ .byte 0xf3,0xc3 # rep ret
+.size _x86_64_AES_encrypt_compact,.-_x86_64_AES_encrypt_compact
+___
+
+# void AES_encrypt (const void *inp,void *out,const AES_KEY *key);
+$code.=<<___;
+.globl AES_encrypt
+.type AES_encrypt,\@function,3
+.align 16
+.globl asm_AES_encrypt
+.hidden asm_AES_encrypt
+asm_AES_encrypt:
+AES_encrypt:
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+
+ # allocate frame "above" key schedule
+ mov %rsp,%r10
+ lea -63(%rdx),%rcx # %rdx is key argument
+ and \$-64,%rsp
+ sub %rsp,%rcx
+ neg %rcx
+ and \$0x3c0,%rcx
+ sub %rcx,%rsp
+ sub \$32,%rsp
+
+ mov %rsi,16(%rsp) # save out
+ mov %r10,24(%rsp) # save real stack pointer
+.Lenc_prologue:
+
+ mov %rdx,$key
+ mov 240($key),$rnds # load rounds
+
+ mov 0(%rdi),$s0 # load input vector
+ mov 4(%rdi),$s1
+ mov 8(%rdi),$s2
+ mov 12(%rdi),$s3
+
+ shl \$4,$rnds
+ lea ($key,$rnds),%rbp
+ mov $key,(%rsp) # key schedule
+ mov %rbp,8(%rsp) # end of key schedule
+
+ # pick Te4 copy which can't "overlap" with stack frame or key schedule
+ lea .LAES_Te+2048(%rip),$sbox
+ lea 768(%rsp),%rbp
+ sub $sbox,%rbp
+ and \$0x300,%rbp
+ lea ($sbox,%rbp),$sbox
+
+ call _x86_64_AES_encrypt_compact
+
+ mov 16(%rsp),$out # restore out
+ mov 24(%rsp),%rsi # restore saved stack pointer
+ mov $s0,0($out) # write output vector
+ mov $s1,4($out)
+ mov $s2,8($out)
+ mov $s3,12($out)
+
+ mov (%rsi),%r15
+ mov 8(%rsi),%r14
+ mov 16(%rsi),%r13
+ mov 24(%rsi),%r12
+ mov 32(%rsi),%rbp
+ mov 40(%rsi),%rbx
+ lea 48(%rsi),%rsp
+.Lenc_epilogue:
+ ret
+.size AES_encrypt,.-AES_encrypt
+___
+
+#------------------------------------------------------------------#
+
+sub decvert()
+{ my $t3="%r8d"; # zaps $inp!
+
+$code.=<<___;
+ # favor 3-way issue Opteron pipeline...
+ movzb `&lo("$s0")`,$acc0
+ movzb `&lo("$s1")`,$acc1
+ movzb `&lo("$s2")`,$acc2
+ mov 0($sbox,$acc0,8),$t0
+ mov 0($sbox,$acc1,8),$t1
+ mov 0($sbox,$acc2,8),$t2
+
+ movzb `&hi("$s3")`,$acc0
+ movzb `&hi("$s0")`,$acc1
+ movzb `&lo("$s3")`,$acc2
+ xor 3($sbox,$acc0,8),$t0
+ xor 3($sbox,$acc1,8),$t1
+ mov 0($sbox,$acc2,8),$t3
+
+ movzb `&hi("$s1")`,$acc0
+ shr \$16,$s0
+ movzb `&hi("$s2")`,$acc2
+ xor 3($sbox,$acc0,8),$t2
+ shr \$16,$s3
+ xor 3($sbox,$acc2,8),$t3
+
+ shr \$16,$s1
+ lea 16($key),$key
+ shr \$16,$s2
+
+ movzb `&lo("$s2")`,$acc0
+ movzb `&lo("$s3")`,$acc1
+ movzb `&lo("$s0")`,$acc2
+ xor 2($sbox,$acc0,8),$t0
+ xor 2($sbox,$acc1,8),$t1
+ xor 2($sbox,$acc2,8),$t2
+
+ movzb `&hi("$s1")`,$acc0
+ movzb `&hi("$s2")`,$acc1
+ movzb `&lo("$s1")`,$acc2
+ xor 1($sbox,$acc0,8),$t0
+ xor 1($sbox,$acc1,8),$t1
+ xor 2($sbox,$acc2,8),$t3
+
+ movzb `&hi("$s3")`,$acc0
+ mov 12($key),$s3
+ movzb `&hi("$s0")`,$acc2
+ xor 1($sbox,$acc0,8),$t2
+ mov 0($key),$s0
+ xor 1($sbox,$acc2,8),$t3
+
+ xor $t0,$s0
+ mov 4($key),$s1
+ mov 8($key),$s2
+ xor $t2,$s2
+ xor $t1,$s1
+ xor $t3,$s3
+___
+}
+
+sub declastvert()
+{ my $t3="%r8d"; # zaps $inp!
+
+$code.=<<___;
+ lea 2048($sbox),$sbox # size optimization
+ movzb `&lo("$s0")`,$acc0
+ movzb `&lo("$s1")`,$acc1
+ movzb `&lo("$s2")`,$acc2
+ movzb ($sbox,$acc0,1),$t0
+ movzb ($sbox,$acc1,1),$t1
+ movzb ($sbox,$acc2,1),$t2
+
+ movzb `&lo("$s3")`,$acc0
+ movzb `&hi("$s3")`,$acc1
+ movzb `&hi("$s0")`,$acc2
+ movzb ($sbox,$acc0,1),$t3
+ movzb ($sbox,$acc1,1),$acc1 #$t0
+ movzb ($sbox,$acc2,1),$acc2 #$t1
+
+ shl \$8,$acc1
+ shl \$8,$acc2
+
+ xor $acc1,$t0
+ xor $acc2,$t1
+ shr \$16,$s3
+
+ movzb `&hi("$s1")`,$acc0
+ movzb `&hi("$s2")`,$acc1
+ shr \$16,$s0
+ movzb ($sbox,$acc0,1),$acc0 #$t2
+ movzb ($sbox,$acc1,1),$acc1 #$t3
+
+ shl \$8,$acc0
+ shl \$8,$acc1
+ shr \$16,$s1
+ xor $acc0,$t2
+ xor $acc1,$t3
+ shr \$16,$s2
+
+ movzb `&lo("$s2")`,$acc0
+ movzb `&lo("$s3")`,$acc1
+ movzb `&lo("$s0")`,$acc2
+ movzb ($sbox,$acc0,1),$acc0 #$t0
+ movzb ($sbox,$acc1,1),$acc1 #$t1
+ movzb ($sbox,$acc2,1),$acc2 #$t2
+
+ shl \$16,$acc0
+ shl \$16,$acc1
+ shl \$16,$acc2
+
+ xor $acc0,$t0
+ xor $acc1,$t1
+ xor $acc2,$t2
+
+ movzb `&lo("$s1")`,$acc0
+ movzb `&hi("$s1")`,$acc1
+ movzb `&hi("$s2")`,$acc2
+ movzb ($sbox,$acc0,1),$acc0 #$t3
+ movzb ($sbox,$acc1,1),$acc1 #$t0
+ movzb ($sbox,$acc2,1),$acc2 #$t1
+
+ shl \$16,$acc0
+ shl \$24,$acc1
+ shl \$24,$acc2
+
+ xor $acc0,$t3
+ xor $acc1,$t0
+ xor $acc2,$t1
+
+ movzb `&hi("$s3")`,$acc0
+ movzb `&hi("$s0")`,$acc1
+ mov 16+12($key),$s3
+ movzb ($sbox,$acc0,1),$acc0 #$t2
+ movzb ($sbox,$acc1,1),$acc1 #$t3
+ mov 16+0($key),$s0
+
+ shl \$24,$acc0
+ shl \$24,$acc1
+
+ xor $acc0,$t2
+ xor $acc1,$t3
+
+ mov 16+4($key),$s1
+ mov 16+8($key),$s2
+ lea -2048($sbox),$sbox
+ xor $t0,$s0
+ xor $t1,$s1
+ xor $t2,$s2
+ xor $t3,$s3
+___
+}
+
+sub decstep()
+{ my ($i,@s) = @_;
+ my $tmp0=$acc0;
+ my $tmp1=$acc1;
+ my $tmp2=$acc2;
+ my $out=($t0,$t1,$t2,$s[0])[$i];
+
+ $code.=" mov $s[0],$out\n" if ($i!=3);
+ $tmp1=$s[2] if ($i==3);
+ $code.=" mov $s[2],$tmp1\n" if ($i!=3);
+ $code.=" and \$0xFF,$out\n";
+
+ $code.=" mov 0($sbox,$out,8),$out\n";
+ $code.=" shr \$16,$tmp1\n";
+ $tmp2=$s[3] if ($i==3);
+ $code.=" mov $s[3],$tmp2\n" if ($i!=3);
+
+ $tmp0=$s[1] if ($i==3);
+ $code.=" movzb ".&hi($s[1]).",$tmp0\n";
+ $code.=" and \$0xFF,$tmp1\n";
+ $code.=" shr \$24,$tmp2\n";
+
+ $code.=" xor 3($sbox,$tmp0,8),$out\n";
+ $code.=" xor 2($sbox,$tmp1,8),$out\n";
+ $code.=" xor 1($sbox,$tmp2,8),$out\n";
+
+ $code.=" mov $t2,$s[1]\n" if ($i==3);
+ $code.=" mov $t1,$s[2]\n" if ($i==3);
+ $code.=" mov $t0,$s[3]\n" if ($i==3);
+ $code.="\n";
+}
+
+sub declast()
+{ my ($i,@s)=@_;
+ my $tmp0=$acc0;
+ my $tmp1=$acc1;
+ my $tmp2=$acc2;
+ my $out=($t0,$t1,$t2,$s[0])[$i];
+
+ $code.=" mov $s[0],$out\n" if ($i!=3);
+ $tmp1=$s[2] if ($i==3);
+ $code.=" mov $s[2],$tmp1\n" if ($i!=3);
+ $code.=" and \$0xFF,$out\n";
+
+ $code.=" movzb 2048($sbox,$out,1),$out\n";
+ $code.=" shr \$16,$tmp1\n";
+ $tmp2=$s[3] if ($i==3);
+ $code.=" mov $s[3],$tmp2\n" if ($i!=3);
+
+ $tmp0=$s[1] if ($i==3);
+ $code.=" movzb ".&hi($s[1]).",$tmp0\n";
+ $code.=" and \$0xFF,$tmp1\n";
+ $code.=" shr \$24,$tmp2\n";
+
+ $code.=" movzb 2048($sbox,$tmp0,1),$tmp0\n";
+ $code.=" movzb 2048($sbox,$tmp1,1),$tmp1\n";
+ $code.=" movzb 2048($sbox,$tmp2,1),$tmp2\n";
+
+ $code.=" shl \$8,$tmp0\n";
+ $code.=" shl \$16,$tmp1\n";
+ $code.=" shl \$24,$tmp2\n";
+
+ $code.=" xor $tmp0,$out\n";
+ $code.=" mov $t2,$s[1]\n" if ($i==3);
+ $code.=" xor $tmp1,$out\n";
+ $code.=" mov $t1,$s[2]\n" if ($i==3);
+ $code.=" xor $tmp2,$out\n";
+ $code.=" mov $t0,$s[3]\n" if ($i==3);
+ $code.="\n";
+}
+
+$code.=<<___;
+.type _x86_64_AES_decrypt,\@abi-omnipotent
+.align 16
+_x86_64_AES_decrypt:
+ xor 0($key),$s0 # xor with key
+ xor 4($key),$s1
+ xor 8($key),$s2
+ xor 12($key),$s3
+
+ mov 240($key),$rnds # load key->rounds
+ sub \$1,$rnds
+ jmp .Ldec_loop
+.align 16
+.Ldec_loop:
+___
+ if ($verticalspin) { &decvert(); }
+ else { &decstep(0,$s0,$s3,$s2,$s1);
+ &decstep(1,$s1,$s0,$s3,$s2);
+ &decstep(2,$s2,$s1,$s0,$s3);
+ &decstep(3,$s3,$s2,$s1,$s0);
+ $code.=<<___;
+ lea 16($key),$key
+ xor 0($key),$s0 # xor with key
+ xor 4($key),$s1
+ xor 8($key),$s2
+ xor 12($key),$s3
+___
+ }
+$code.=<<___;
+ sub \$1,$rnds
+ jnz .Ldec_loop
+___
+ if ($verticalspin) { &declastvert(); }
+ else { &declast(0,$s0,$s3,$s2,$s1);
+ &declast(1,$s1,$s0,$s3,$s2);
+ &declast(2,$s2,$s1,$s0,$s3);
+ &declast(3,$s3,$s2,$s1,$s0);
+ $code.=<<___;
+ xor 16+0($key),$s0 # xor with key
+ xor 16+4($key),$s1
+ xor 16+8($key),$s2
+ xor 16+12($key),$s3
+___
+ }
+$code.=<<___;
+ .byte 0xf3,0xc3 # rep ret
+.size _x86_64_AES_decrypt,.-_x86_64_AES_decrypt
+___
+
+sub deccompactvert()
+{ my ($t3,$t4,$t5)=("%r8d","%r9d","%r13d");
+
+$code.=<<___;
+ movzb `&lo("$s0")`,$t0
+ movzb `&lo("$s1")`,$t1
+ movzb `&lo("$s2")`,$t2
+ movzb `&lo("$s3")`,$t3
+ movzb `&hi("$s3")`,$acc0
+ movzb `&hi("$s0")`,$acc1
+ shr \$16,$s3
+ movzb `&hi("$s1")`,$acc2
+ movzb ($sbox,$t0,1),$t0
+ movzb ($sbox,$t1,1),$t1
+ movzb ($sbox,$t2,1),$t2
+ movzb ($sbox,$t3,1),$t3
+
+ movzb ($sbox,$acc0,1),$t4 #$t0
+ movzb `&hi("$s2")`,$acc0
+ movzb ($sbox,$acc1,1),$t5 #$t1
+ movzb ($sbox,$acc2,1),$acc2 #$t2
+ movzb ($sbox,$acc0,1),$acc0 #$t3
+
+ shr \$16,$s2
+ shl \$8,$t5
+ shl \$8,$t4
+ movzb `&lo("$s2")`,$acc1
+ shr \$16,$s0
+ xor $t4,$t0
+ shr \$16,$s1
+ movzb `&lo("$s3")`,$t4
+
+ shl \$8,$acc2
+ xor $t5,$t1
+ shl \$8,$acc0
+ movzb `&lo("$s0")`,$t5
+ movzb ($sbox,$acc1,1),$acc1 #$t0
+ xor $acc2,$t2
+ movzb `&lo("$s1")`,$acc2
+
+ shl \$16,$acc1
+ xor $acc0,$t3
+ movzb ($sbox,$t4,1),$t4 #$t1
+ movzb `&hi("$s1")`,$acc0
+ movzb ($sbox,$acc2,1),$acc2 #$t3
+ xor $acc1,$t0
+ movzb ($sbox,$t5,1),$t5 #$t2
+ movzb `&hi("$s2")`,$acc1
+
+ shl \$16,$acc2
+ shl \$16,$t4
+ shl \$16,$t5
+ xor $acc2,$t3
+ movzb `&hi("$s3")`,$acc2
+ xor $t4,$t1
+ shr \$8,$s0
+ xor $t5,$t2
+
+ movzb ($sbox,$acc0,1),$acc0 #$t0
+ movzb ($sbox,$acc1,1),$s1 #$t1
+ movzb ($sbox,$acc2,1),$s2 #$t2
+ movzb ($sbox,$s0,1),$s3 #$t3
+
+ mov $t0,$s0
+ shl \$24,$acc0
+ shl \$24,$s1
+ shl \$24,$s2
+ xor $acc0,$s0
+ shl \$24,$s3
+ xor $t1,$s1
+ xor $t2,$s2
+ xor $t3,$s3
+___
+}
+
+# parallelized version! input is pair of 64-bit values: %rax=s1.s0
+# and %rcx=s3.s2, output is four 32-bit values in %eax=s0, %ebx=s1,
+# %ecx=s2 and %edx=s3.
+sub dectransform()
+{ my ($tp10,$tp20,$tp40,$tp80,$acc0)=("%rax","%r8", "%r9", "%r10","%rbx");
+ my ($tp18,$tp28,$tp48,$tp88,$acc8)=("%rcx","%r11","%r12","%r13","%rdx");
+ my $prefetch = shift;
+
+$code.=<<___;
+ mov $mask80,$tp40
+ mov $mask80,$tp48
+ and $tp10,$tp40
+ and $tp18,$tp48
+ mov $tp40,$acc0
+ mov $tp48,$acc8
+ shr \$7,$tp40
+ lea ($tp10,$tp10),$tp20
+ shr \$7,$tp48
+ lea ($tp18,$tp18),$tp28
+ sub $tp40,$acc0
+ sub $tp48,$acc8
+ and $maskfe,$tp20
+ and $maskfe,$tp28
+ and $mask1b,$acc0
+ and $mask1b,$acc8
+ xor $acc0,$tp20
+ xor $acc8,$tp28
+ mov $mask80,$tp80
+ mov $mask80,$tp88
+
+ and $tp20,$tp80
+ and $tp28,$tp88
+ mov $tp80,$acc0
+ mov $tp88,$acc8
+ shr \$7,$tp80
+ lea ($tp20,$tp20),$tp40
+ shr \$7,$tp88
+ lea ($tp28,$tp28),$tp48
+ sub $tp80,$acc0
+ sub $tp88,$acc8
+ and $maskfe,$tp40
+ and $maskfe,$tp48
+ and $mask1b,$acc0
+ and $mask1b,$acc8
+ xor $acc0,$tp40
+ xor $acc8,$tp48
+ mov $mask80,$tp80
+ mov $mask80,$tp88
+
+ and $tp40,$tp80
+ and $tp48,$tp88
+ mov $tp80,$acc0
+ mov $tp88,$acc8
+ shr \$7,$tp80
+ xor $tp10,$tp20 # tp2^=tp1
+ shr \$7,$tp88
+ xor $tp18,$tp28 # tp2^=tp1
+ sub $tp80,$acc0
+ sub $tp88,$acc8
+ lea ($tp40,$tp40),$tp80
+ lea ($tp48,$tp48),$tp88
+ xor $tp10,$tp40 # tp4^=tp1
+ xor $tp18,$tp48 # tp4^=tp1
+ and $maskfe,$tp80
+ and $maskfe,$tp88
+ and $mask1b,$acc0
+ and $mask1b,$acc8
+ xor $acc0,$tp80
+ xor $acc8,$tp88
+
+ xor $tp80,$tp10 # tp1^=tp8
+ xor $tp88,$tp18 # tp1^=tp8
+ xor $tp80,$tp20 # tp2^tp1^=tp8
+ xor $tp88,$tp28 # tp2^tp1^=tp8
+ mov $tp10,$acc0
+ mov $tp18,$acc8
+ xor $tp80,$tp40 # tp4^tp1^=tp8
+ shr \$32,$acc0
+ xor $tp88,$tp48 # tp4^tp1^=tp8
+ shr \$32,$acc8
+ xor $tp20,$tp80 # tp8^=tp8^tp2^tp1=tp2^tp1
+ rol \$8,`&LO("$tp10")` # ROTATE(tp1^tp8,8)
+ xor $tp28,$tp88 # tp8^=tp8^tp2^tp1=tp2^tp1
+ rol \$8,`&LO("$tp18")` # ROTATE(tp1^tp8,8)
+ xor $tp40,$tp80 # tp2^tp1^=tp8^tp4^tp1=tp8^tp4^tp2
+ rol \$8,`&LO("$acc0")` # ROTATE(tp1^tp8,8)
+ xor $tp48,$tp88 # tp2^tp1^=tp8^tp4^tp1=tp8^tp4^tp2
+
+ rol \$8,`&LO("$acc8")` # ROTATE(tp1^tp8,8)
+ xor `&LO("$tp80")`,`&LO("$tp10")`
+ shr \$32,$tp80
+ xor `&LO("$tp88")`,`&LO("$tp18")`
+ shr \$32,$tp88
+ xor `&LO("$tp80")`,`&LO("$acc0")`
+ xor `&LO("$tp88")`,`&LO("$acc8")`
+
+ mov $tp20,$tp80
+ rol \$24,`&LO("$tp20")` # ROTATE(tp2^tp1^tp8,24)
+ mov $tp28,$tp88
+ rol \$24,`&LO("$tp28")` # ROTATE(tp2^tp1^tp8,24)
+ shr \$32,$tp80
+ xor `&LO("$tp20")`,`&LO("$tp10")`
+ shr \$32,$tp88
+ xor `&LO("$tp28")`,`&LO("$tp18")`
+ rol \$24,`&LO("$tp80")` # ROTATE(tp2^tp1^tp8,24)
+ mov $tp40,$tp20
+ rol \$24,`&LO("$tp88")` # ROTATE(tp2^tp1^tp8,24)
+ mov $tp48,$tp28
+ shr \$32,$tp20
+ xor `&LO("$tp80")`,`&LO("$acc0")`
+ shr \$32,$tp28
+ xor `&LO("$tp88")`,`&LO("$acc8")`
+
+ `"mov 0($sbox),$mask80" if ($prefetch)`
+ rol \$16,`&LO("$tp40")` # ROTATE(tp4^tp1^tp8,16)
+ `"mov 64($sbox),$maskfe" if ($prefetch)`
+ rol \$16,`&LO("$tp48")` # ROTATE(tp4^tp1^tp8,16)
+ `"mov 128($sbox),$mask1b" if ($prefetch)`
+ rol \$16,`&LO("$tp20")` # ROTATE(tp4^tp1^tp8,16)
+ `"mov 192($sbox),$tp80" if ($prefetch)`
+ xor `&LO("$tp40")`,`&LO("$tp10")`
+ rol \$16,`&LO("$tp28")` # ROTATE(tp4^tp1^tp8,16)
+ xor `&LO("$tp48")`,`&LO("$tp18")`
+ `"mov 256($sbox),$tp88" if ($prefetch)`
+ xor `&LO("$tp20")`,`&LO("$acc0")`
+ xor `&LO("$tp28")`,`&LO("$acc8")`
+___
+}
+
+$code.=<<___;
+.type _x86_64_AES_decrypt_compact,\@abi-omnipotent
+.align 16
+_x86_64_AES_decrypt_compact:
+ lea 128($sbox),$inp # size optimization
+ mov 0-128($inp),$acc1 # prefetch Td4
+ mov 32-128($inp),$acc2
+ mov 64-128($inp),$t0
+ mov 96-128($inp),$t1
+ mov 128-128($inp),$acc1
+ mov 160-128($inp),$acc2
+ mov 192-128($inp),$t0
+ mov 224-128($inp),$t1
+ jmp .Ldec_loop_compact
+
+.align 16
+.Ldec_loop_compact:
+ xor 0($key),$s0 # xor with key
+ xor 4($key),$s1
+ xor 8($key),$s2
+ xor 12($key),$s3
+ lea 16($key),$key
+___
+ &deccompactvert();
+$code.=<<___;
+ cmp 16(%rsp),$key
+ je .Ldec_compact_done
+
+ mov 256+0($sbox),$mask80
+ shl \$32,%rbx
+ shl \$32,%rdx
+ mov 256+8($sbox),$maskfe
+ or %rbx,%rax
+ or %rdx,%rcx
+ mov 256+16($sbox),$mask1b
+___
+ &dectransform(1);
+$code.=<<___;
+ jmp .Ldec_loop_compact
+.align 16
+.Ldec_compact_done:
+ xor 0($key),$s0
+ xor 4($key),$s1
+ xor 8($key),$s2
+ xor 12($key),$s3
+ .byte 0xf3,0xc3 # rep ret
+.size _x86_64_AES_decrypt_compact,.-_x86_64_AES_decrypt_compact
+___
+
+# void AES_decrypt (const void *inp,void *out,const AES_KEY *key);
+$code.=<<___;
+.globl AES_decrypt
+.type AES_decrypt,\@function,3
+.align 16
+.globl asm_AES_decrypt
+.hidden asm_AES_decrypt
+asm_AES_decrypt:
+AES_decrypt:
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+
+ # allocate frame "above" key schedule
+ mov %rsp,%r10
+ lea -63(%rdx),%rcx # %rdx is key argument
+ and \$-64,%rsp
+ sub %rsp,%rcx
+ neg %rcx
+ and \$0x3c0,%rcx
+ sub %rcx,%rsp
+ sub \$32,%rsp
+
+ mov %rsi,16(%rsp) # save out
+ mov %r10,24(%rsp) # save real stack pointer
+.Ldec_prologue:
+
+ mov %rdx,$key
+ mov 240($key),$rnds # load rounds
+
+ mov 0(%rdi),$s0 # load input vector
+ mov 4(%rdi),$s1
+ mov 8(%rdi),$s2
+ mov 12(%rdi),$s3
+
+ shl \$4,$rnds
+ lea ($key,$rnds),%rbp
+ mov $key,(%rsp) # key schedule
+ mov %rbp,8(%rsp) # end of key schedule
+
+ # pick Td4 copy which can't "overlap" with stack frame or key schedule
+ lea .LAES_Td+2048(%rip),$sbox
+ lea 768(%rsp),%rbp
+ sub $sbox,%rbp
+ and \$0x300,%rbp
+ lea ($sbox,%rbp),$sbox
+ shr \$3,%rbp # recall "magic" constants!
+ add %rbp,$sbox
+
+ call _x86_64_AES_decrypt_compact
+
+ mov 16(%rsp),$out # restore out
+ mov 24(%rsp),%rsi # restore saved stack pointer
+ mov $s0,0($out) # write output vector
+ mov $s1,4($out)
+ mov $s2,8($out)
+ mov $s3,12($out)
+
+ mov (%rsi),%r15
+ mov 8(%rsi),%r14
+ mov 16(%rsi),%r13
+ mov 24(%rsi),%r12
+ mov 32(%rsi),%rbp
+ mov 40(%rsi),%rbx
+ lea 48(%rsi),%rsp
+.Ldec_epilogue:
+ ret
+.size AES_decrypt,.-AES_decrypt
+___
+#------------------------------------------------------------------#
+
+sub enckey()
+{
+$code.=<<___;
+ movz %dl,%esi # rk[i]>>0
+ movzb -128(%rbp,%rsi),%ebx
+ movz %dh,%esi # rk[i]>>8
+ shl \$24,%ebx
+ xor %ebx,%eax
+
+ movzb -128(%rbp,%rsi),%ebx
+ shr \$16,%edx
+ movz %dl,%esi # rk[i]>>16
+ xor %ebx,%eax
+
+ movzb -128(%rbp,%rsi),%ebx
+ movz %dh,%esi # rk[i]>>24
+ shl \$8,%ebx
+ xor %ebx,%eax
+
+ movzb -128(%rbp,%rsi),%ebx
+ shl \$16,%ebx
+ xor %ebx,%eax
+
+ xor 1024-128(%rbp,%rcx,4),%eax # rcon
+___
+}
+
+# int AES_set_encrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key)
+$code.=<<___;
+.globl AES_set_encrypt_key
+.type AES_set_encrypt_key,\@function,3
+.align 16
+AES_set_encrypt_key:
+ push %rbx
+ push %rbp
+ push %r12 # redundant, but allows to share
+ push %r13 # exception handler...
+ push %r14
+ push %r15
+ sub \$8,%rsp
+.Lenc_key_prologue:
+
+ call _x86_64_AES_set_encrypt_key
+
+ mov 40(%rsp),%rbp
+ mov 48(%rsp),%rbx
+ add \$56,%rsp
+.Lenc_key_epilogue:
+ ret
+.size AES_set_encrypt_key,.-AES_set_encrypt_key
+
+.type _x86_64_AES_set_encrypt_key,\@abi-omnipotent
+.align 16
+_x86_64_AES_set_encrypt_key:
+ mov %esi,%ecx # %ecx=bits
+ mov %rdi,%rsi # %rsi=userKey
+ mov %rdx,%rdi # %rdi=key
+
+ test \$-1,%rsi
+ jz .Lbadpointer
+ test \$-1,%rdi
+ jz .Lbadpointer
+
+ lea .LAES_Te(%rip),%rbp
+ lea 2048+128(%rbp),%rbp
+
+ # prefetch Te4
+ mov 0-128(%rbp),%eax
+ mov 32-128(%rbp),%ebx
+ mov 64-128(%rbp),%r8d
+ mov 96-128(%rbp),%edx
+ mov 128-128(%rbp),%eax
+ mov 160-128(%rbp),%ebx
+ mov 192-128(%rbp),%r8d
+ mov 224-128(%rbp),%edx
+
+ cmp \$128,%ecx
+ je .L10rounds
+ cmp \$192,%ecx
+ je .L12rounds
+ cmp \$256,%ecx
+ je .L14rounds
+ mov \$-2,%rax # invalid number of bits
+ jmp .Lexit
+
+.L10rounds:
+ mov 0(%rsi),%rax # copy first 4 dwords
+ mov 8(%rsi),%rdx
+ mov %rax,0(%rdi)
+ mov %rdx,8(%rdi)
+
+ shr \$32,%rdx
+ xor %ecx,%ecx
+ jmp .L10shortcut
+.align 4
+.L10loop:
+ mov 0(%rdi),%eax # rk[0]
+ mov 12(%rdi),%edx # rk[3]
+.L10shortcut:
+___
+ &enckey ();
+$code.=<<___;
+ mov %eax,16(%rdi) # rk[4]
+ xor 4(%rdi),%eax
+ mov %eax,20(%rdi) # rk[5]
+ xor 8(%rdi),%eax
+ mov %eax,24(%rdi) # rk[6]
+ xor 12(%rdi),%eax
+ mov %eax,28(%rdi) # rk[7]
+ add \$1,%ecx
+ lea 16(%rdi),%rdi
+ cmp \$10,%ecx
+ jl .L10loop
+
+ movl \$10,80(%rdi) # setup number of rounds
+ xor %rax,%rax
+ jmp .Lexit
+
+.L12rounds:
+ mov 0(%rsi),%rax # copy first 6 dwords
+ mov 8(%rsi),%rbx
+ mov 16(%rsi),%rdx
+ mov %rax,0(%rdi)
+ mov %rbx,8(%rdi)
+ mov %rdx,16(%rdi)
+
+ shr \$32,%rdx
+ xor %ecx,%ecx
+ jmp .L12shortcut
+.align 4
+.L12loop:
+ mov 0(%rdi),%eax # rk[0]
+ mov 20(%rdi),%edx # rk[5]
+.L12shortcut:
+___
+ &enckey ();
+$code.=<<___;
+ mov %eax,24(%rdi) # rk[6]
+ xor 4(%rdi),%eax
+ mov %eax,28(%rdi) # rk[7]
+ xor 8(%rdi),%eax
+ mov %eax,32(%rdi) # rk[8]
+ xor 12(%rdi),%eax
+ mov %eax,36(%rdi) # rk[9]
+
+ cmp \$7,%ecx
+ je .L12break
+ add \$1,%ecx
+
+ xor 16(%rdi),%eax
+ mov %eax,40(%rdi) # rk[10]
+ xor 20(%rdi),%eax
+ mov %eax,44(%rdi) # rk[11]
+
+ lea 24(%rdi),%rdi
+ jmp .L12loop
+.L12break:
+ movl \$12,72(%rdi) # setup number of rounds
+ xor %rax,%rax
+ jmp .Lexit
+
+.L14rounds:
+ mov 0(%rsi),%rax # copy first 8 dwords
+ mov 8(%rsi),%rbx
+ mov 16(%rsi),%rcx
+ mov 24(%rsi),%rdx
+ mov %rax,0(%rdi)
+ mov %rbx,8(%rdi)
+ mov %rcx,16(%rdi)
+ mov %rdx,24(%rdi)
+
+ shr \$32,%rdx
+ xor %ecx,%ecx
+ jmp .L14shortcut
+.align 4
+.L14loop:
+ mov 0(%rdi),%eax # rk[0]
+ mov 28(%rdi),%edx # rk[4]
+.L14shortcut:
+___
+ &enckey ();
+$code.=<<___;
+ mov %eax,32(%rdi) # rk[8]
+ xor 4(%rdi),%eax
+ mov %eax,36(%rdi) # rk[9]
+ xor 8(%rdi),%eax
+ mov %eax,40(%rdi) # rk[10]
+ xor 12(%rdi),%eax
+ mov %eax,44(%rdi) # rk[11]
+
+ cmp \$6,%ecx
+ je .L14break
+ add \$1,%ecx
+
+ mov %eax,%edx
+ mov 16(%rdi),%eax # rk[4]
+ movz %dl,%esi # rk[11]>>0
+ movzb -128(%rbp,%rsi),%ebx
+ movz %dh,%esi # rk[11]>>8
+ xor %ebx,%eax
+
+ movzb -128(%rbp,%rsi),%ebx
+ shr \$16,%edx
+ shl \$8,%ebx
+ movz %dl,%esi # rk[11]>>16
+ xor %ebx,%eax
+
+ movzb -128(%rbp,%rsi),%ebx
+ movz %dh,%esi # rk[11]>>24
+ shl \$16,%ebx
+ xor %ebx,%eax
+
+ movzb -128(%rbp,%rsi),%ebx
+ shl \$24,%ebx
+ xor %ebx,%eax
+
+ mov %eax,48(%rdi) # rk[12]
+ xor 20(%rdi),%eax
+ mov %eax,52(%rdi) # rk[13]
+ xor 24(%rdi),%eax
+ mov %eax,56(%rdi) # rk[14]
+ xor 28(%rdi),%eax
+ mov %eax,60(%rdi) # rk[15]
+
+ lea 32(%rdi),%rdi
+ jmp .L14loop
+.L14break:
+ movl \$14,48(%rdi) # setup number of rounds
+ xor %rax,%rax
+ jmp .Lexit
+
+.Lbadpointer:
+ mov \$-1,%rax
+.Lexit:
+ .byte 0xf3,0xc3 # rep ret
+.size _x86_64_AES_set_encrypt_key,.-_x86_64_AES_set_encrypt_key
+___
+
+sub deckey_ref()
+{ my ($i,$ptr,$te,$td) = @_;
+ my ($tp1,$tp2,$tp4,$tp8,$acc)=("%eax","%ebx","%edi","%edx","%r8d");
+$code.=<<___;
+ mov $i($ptr),$tp1
+ mov $tp1,$acc
+ and \$0x80808080,$acc
+ mov $acc,$tp4
+ shr \$7,$tp4
+ lea 0($tp1,$tp1),$tp2
+ sub $tp4,$acc
+ and \$0xfefefefe,$tp2
+ and \$0x1b1b1b1b,$acc
+ xor $tp2,$acc
+ mov $acc,$tp2
+
+ and \$0x80808080,$acc
+ mov $acc,$tp8
+ shr \$7,$tp8
+ lea 0($tp2,$tp2),$tp4
+ sub $tp8,$acc
+ and \$0xfefefefe,$tp4
+ and \$0x1b1b1b1b,$acc
+ xor $tp1,$tp2 # tp2^tp1
+ xor $tp4,$acc
+ mov $acc,$tp4
+
+ and \$0x80808080,$acc
+ mov $acc,$tp8
+ shr \$7,$tp8
+ sub $tp8,$acc
+ lea 0($tp4,$tp4),$tp8
+ xor $tp1,$tp4 # tp4^tp1
+ and \$0xfefefefe,$tp8
+ and \$0x1b1b1b1b,$acc
+ xor $acc,$tp8
+
+ xor $tp8,$tp1 # tp1^tp8
+ rol \$8,$tp1 # ROTATE(tp1^tp8,8)
+ xor $tp8,$tp2 # tp2^tp1^tp8
+ xor $tp8,$tp4 # tp4^tp1^tp8
+ xor $tp2,$tp8
+ xor $tp4,$tp8 # tp8^(tp8^tp4^tp1)^(tp8^tp2^tp1)=tp8^tp4^tp2
+
+ xor $tp8,$tp1
+ rol \$24,$tp2 # ROTATE(tp2^tp1^tp8,24)
+ xor $tp2,$tp1
+ rol \$16,$tp4 # ROTATE(tp4^tp1^tp8,16)
+ xor $tp4,$tp1
+
+ mov $tp1,$i($ptr)
+___
+}
+
+# int AES_set_decrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key)
+$code.=<<___;
+.globl AES_set_decrypt_key
+.type AES_set_decrypt_key,\@function,3
+.align 16
+AES_set_decrypt_key:
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ push %rdx # save key schedule
+.Ldec_key_prologue:
+
+ call _x86_64_AES_set_encrypt_key
+ mov (%rsp),%r8 # restore key schedule
+ cmp \$0,%eax
+ jne .Labort
+
+ mov 240(%r8),%r14d # pull number of rounds
+ xor %rdi,%rdi
+ lea (%rdi,%r14d,4),%rcx
+ mov %r8,%rsi
+ lea (%r8,%rcx,4),%rdi # pointer to last chunk
+.align 4
+.Linvert:
+ mov 0(%rsi),%rax
+ mov 8(%rsi),%rbx
+ mov 0(%rdi),%rcx
+ mov 8(%rdi),%rdx
+ mov %rax,0(%rdi)
+ mov %rbx,8(%rdi)
+ mov %rcx,0(%rsi)
+ mov %rdx,8(%rsi)
+ lea 16(%rsi),%rsi
+ lea -16(%rdi),%rdi
+ cmp %rsi,%rdi
+ jne .Linvert
+
+ lea .LAES_Te+2048+1024(%rip),%rax # rcon
+
+ mov 40(%rax),$mask80
+ mov 48(%rax),$maskfe
+ mov 56(%rax),$mask1b
+
+ mov %r8,$key
+ sub \$1,%r14d
+.align 4
+.Lpermute:
+ lea 16($key),$key
+ mov 0($key),%rax
+ mov 8($key),%rcx
+___
+ &dectransform ();
+$code.=<<___;
+ mov %eax,0($key)
+ mov %ebx,4($key)
+ mov %ecx,8($key)
+ mov %edx,12($key)
+ sub \$1,%r14d
+ jnz .Lpermute
+
+ xor %rax,%rax
+.Labort:
+ mov 8(%rsp),%r15
+ mov 16(%rsp),%r14
+ mov 24(%rsp),%r13
+ mov 32(%rsp),%r12
+ mov 40(%rsp),%rbp
+ mov 48(%rsp),%rbx
+ add \$56,%rsp
+.Ldec_key_epilogue:
+ ret
+.size AES_set_decrypt_key,.-AES_set_decrypt_key
+___
+
+# void AES_cbc_encrypt (const void char *inp, unsigned char *out,
+# size_t length, const AES_KEY *key,
+# unsigned char *ivp,const int enc);
+{
+# stack frame layout
+# -8(%rsp) return address
+my $keyp="0(%rsp)"; # one to pass as $key
+my $keyend="8(%rsp)"; # &(keyp->rd_key[4*keyp->rounds])
+my $_rsp="16(%rsp)"; # saved %rsp
+my $_inp="24(%rsp)"; # copy of 1st parameter, inp
+my $_out="32(%rsp)"; # copy of 2nd parameter, out
+my $_len="40(%rsp)"; # copy of 3rd parameter, length
+my $_key="48(%rsp)"; # copy of 4th parameter, key
+my $_ivp="56(%rsp)"; # copy of 5th parameter, ivp
+my $ivec="64(%rsp)"; # ivec[16]
+my $aes_key="80(%rsp)"; # copy of aes_key
+my $mark="80+240(%rsp)"; # copy of aes_key->rounds
+
+$code.=<<___;
+.globl AES_cbc_encrypt
+.type AES_cbc_encrypt,\@function,6
+.align 16
+.extern OPENSSL_ia32cap_P
+.globl asm_AES_cbc_encrypt
+.hidden asm_AES_cbc_encrypt
+asm_AES_cbc_encrypt:
+AES_cbc_encrypt:
+ cmp \$0,%rdx # check length
+ je .Lcbc_epilogue
+ pushfq
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+.Lcbc_prologue:
+
+ cld
+ mov %r9d,%r9d # clear upper half of enc
+
+ lea .LAES_Te(%rip),$sbox
+ cmp \$0,%r9
+ jne .Lcbc_picked_te
+ lea .LAES_Td(%rip),$sbox
+.Lcbc_picked_te:
+
+ mov OPENSSL_ia32cap_P(%rip),%r10d
+ cmp \$$speed_limit,%rdx
+ jb .Lcbc_slow_prologue
+ test \$15,%rdx
+ jnz .Lcbc_slow_prologue
+ bt \$28,%r10d
+ jc .Lcbc_slow_prologue
+
+ # allocate aligned stack frame...
+ lea -88-248(%rsp),$key
+ and \$-64,$key
+
+ # ... and make sure it doesn't alias with AES_T[ed] modulo 4096
+ mov $sbox,%r10
+ lea 2304($sbox),%r11
+ mov $key,%r12
+ and \$0xFFF,%r10 # s = $sbox&0xfff
+ and \$0xFFF,%r11 # e = ($sbox+2048)&0xfff
+ and \$0xFFF,%r12 # p = %rsp&0xfff
+
+ cmp %r11,%r12 # if (p=>e) %rsp =- (p-e);
+ jb .Lcbc_te_break_out
+ sub %r11,%r12
+ sub %r12,$key
+ jmp .Lcbc_te_ok
+.Lcbc_te_break_out: # else %rsp -= (p-s)&0xfff + framesz
+ sub %r10,%r12
+ and \$0xFFF,%r12
+ add \$320,%r12
+ sub %r12,$key
+.align 4
+.Lcbc_te_ok:
+
+ xchg %rsp,$key
+ #add \$8,%rsp # reserve for return address!
+ mov $key,$_rsp # save %rsp
+.Lcbc_fast_body:
+ mov %rdi,$_inp # save copy of inp
+ mov %rsi,$_out # save copy of out
+ mov %rdx,$_len # save copy of len
+ mov %rcx,$_key # save copy of key
+ mov %r8,$_ivp # save copy of ivp
+ movl \$0,$mark # copy of aes_key->rounds = 0;
+ mov %r8,%rbp # rearrange input arguments
+ mov %r9,%rbx
+ mov %rsi,$out
+ mov %rdi,$inp
+ mov %rcx,$key
+
+ mov 240($key),%eax # key->rounds
+ # do we copy key schedule to stack?
+ mov $key,%r10
+ sub $sbox,%r10
+ and \$0xfff,%r10
+ cmp \$2304,%r10
+ jb .Lcbc_do_ecopy
+ cmp \$4096-248,%r10
+ jb .Lcbc_skip_ecopy
+.align 4
+.Lcbc_do_ecopy:
+ mov $key,%rsi
+ lea $aes_key,%rdi
+ lea $aes_key,$key
+ mov \$240/8,%ecx
+ .long 0x90A548F3 # rep movsq
+ mov %eax,(%rdi) # copy aes_key->rounds
+.Lcbc_skip_ecopy:
+ mov $key,$keyp # save key pointer
+
+ mov \$18,%ecx
+.align 4
+.Lcbc_prefetch_te:
+ mov 0($sbox),%r10
+ mov 32($sbox),%r11
+ mov 64($sbox),%r12
+ mov 96($sbox),%r13
+ lea 128($sbox),$sbox
+ sub \$1,%ecx
+ jnz .Lcbc_prefetch_te
+ lea -2304($sbox),$sbox
+
+ cmp \$0,%rbx
+ je .LFAST_DECRYPT
+
+#----------------------------- ENCRYPT -----------------------------#
+ mov 0(%rbp),$s0 # load iv
+ mov 4(%rbp),$s1
+ mov 8(%rbp),$s2
+ mov 12(%rbp),$s3
+
+.align 4
+.Lcbc_fast_enc_loop:
+ xor 0($inp),$s0
+ xor 4($inp),$s1
+ xor 8($inp),$s2
+ xor 12($inp),$s3
+ mov $keyp,$key # restore key
+ mov $inp,$_inp # if ($verticalspin) save inp
+
+ call _x86_64_AES_encrypt
+
+ mov $_inp,$inp # if ($verticalspin) restore inp
+ mov $_len,%r10
+ mov $s0,0($out)
+ mov $s1,4($out)
+ mov $s2,8($out)
+ mov $s3,12($out)
+
+ lea 16($inp),$inp
+ lea 16($out),$out
+ sub \$16,%r10
+ test \$-16,%r10
+ mov %r10,$_len
+ jnz .Lcbc_fast_enc_loop
+ mov $_ivp,%rbp # restore ivp
+ mov $s0,0(%rbp) # save ivec
+ mov $s1,4(%rbp)
+ mov $s2,8(%rbp)
+ mov $s3,12(%rbp)
+
+ jmp .Lcbc_fast_cleanup
+
+#----------------------------- DECRYPT -----------------------------#
+.align 16
+.LFAST_DECRYPT:
+ cmp $inp,$out
+ je .Lcbc_fast_dec_in_place
+
+ mov %rbp,$ivec
+.align 4
+.Lcbc_fast_dec_loop:
+ mov 0($inp),$s0 # read input
+ mov 4($inp),$s1
+ mov 8($inp),$s2
+ mov 12($inp),$s3
+ mov $keyp,$key # restore key
+ mov $inp,$_inp # if ($verticalspin) save inp
+
+ call _x86_64_AES_decrypt
+
+ mov $ivec,%rbp # load ivp
+ mov $_inp,$inp # if ($verticalspin) restore inp
+ mov $_len,%r10 # load len
+ xor 0(%rbp),$s0 # xor iv
+ xor 4(%rbp),$s1
+ xor 8(%rbp),$s2
+ xor 12(%rbp),$s3
+ mov $inp,%rbp # current input, next iv
+
+ sub \$16,%r10
+ mov %r10,$_len # update len
+ mov %rbp,$ivec # update ivp
+
+ mov $s0,0($out) # write output
+ mov $s1,4($out)
+ mov $s2,8($out)
+ mov $s3,12($out)
+
+ lea 16($inp),$inp
+ lea 16($out),$out
+ jnz .Lcbc_fast_dec_loop
+ mov $_ivp,%r12 # load user ivp
+ mov 0(%rbp),%r10 # load iv
+ mov 8(%rbp),%r11
+ mov %r10,0(%r12) # copy back to user
+ mov %r11,8(%r12)
+ jmp .Lcbc_fast_cleanup
+
+.align 16
+.Lcbc_fast_dec_in_place:
+ mov 0(%rbp),%r10 # copy iv to stack
+ mov 8(%rbp),%r11
+ mov %r10,0+$ivec
+ mov %r11,8+$ivec
+.align 4
+.Lcbc_fast_dec_in_place_loop:
+ mov 0($inp),$s0 # load input
+ mov 4($inp),$s1
+ mov 8($inp),$s2
+ mov 12($inp),$s3
+ mov $keyp,$key # restore key
+ mov $inp,$_inp # if ($verticalspin) save inp
+
+ call _x86_64_AES_decrypt
+
+ mov $_inp,$inp # if ($verticalspin) restore inp
+ mov $_len,%r10
+ xor 0+$ivec,$s0
+ xor 4+$ivec,$s1
+ xor 8+$ivec,$s2
+ xor 12+$ivec,$s3
+
+ mov 0($inp),%r11 # load input
+ mov 8($inp),%r12
+ sub \$16,%r10
+ jz .Lcbc_fast_dec_in_place_done
+
+ mov %r11,0+$ivec # copy input to iv
+ mov %r12,8+$ivec
+
+ mov $s0,0($out) # save output [zaps input]
+ mov $s1,4($out)
+ mov $s2,8($out)
+ mov $s3,12($out)
+
+ lea 16($inp),$inp
+ lea 16($out),$out
+ mov %r10,$_len
+ jmp .Lcbc_fast_dec_in_place_loop
+.Lcbc_fast_dec_in_place_done:
+ mov $_ivp,%rdi
+ mov %r11,0(%rdi) # copy iv back to user
+ mov %r12,8(%rdi)
+
+ mov $s0,0($out) # save output [zaps input]
+ mov $s1,4($out)
+ mov $s2,8($out)
+ mov $s3,12($out)
+
+.align 4
+.Lcbc_fast_cleanup:
+ cmpl \$0,$mark # was the key schedule copied?
+ lea $aes_key,%rdi
+ je .Lcbc_exit
+ mov \$240/8,%ecx
+ xor %rax,%rax
+ .long 0x90AB48F3 # rep stosq
+
+ jmp .Lcbc_exit
+
+#--------------------------- SLOW ROUTINE ---------------------------#
+.align 16
+.Lcbc_slow_prologue:
+ # allocate aligned stack frame...
+ lea -88(%rsp),%rbp
+ and \$-64,%rbp
+ # ... just "above" key schedule
+ lea -88-63(%rcx),%r10
+ sub %rbp,%r10
+ neg %r10
+ and \$0x3c0,%r10
+ sub %r10,%rbp
+
+ xchg %rsp,%rbp
+ #add \$8,%rsp # reserve for return address!
+ mov %rbp,$_rsp # save %rsp
+.Lcbc_slow_body:
+ #mov %rdi,$_inp # save copy of inp
+ #mov %rsi,$_out # save copy of out
+ #mov %rdx,$_len # save copy of len
+ #mov %rcx,$_key # save copy of key
+ mov %r8,$_ivp # save copy of ivp
+ mov %r8,%rbp # rearrange input arguments
+ mov %r9,%rbx
+ mov %rsi,$out
+ mov %rdi,$inp
+ mov %rcx,$key
+ mov %rdx,%r10
+
+ mov 240($key),%eax
+ mov $key,$keyp # save key pointer
+ shl \$4,%eax
+ lea ($key,%rax),%rax
+ mov %rax,$keyend
+
+ # pick Te4 copy which can't "overlap" with stack frame or key scdedule
+ lea 2048($sbox),$sbox
+ lea 768-8(%rsp),%rax
+ sub $sbox,%rax
+ and \$0x300,%rax
+ lea ($sbox,%rax),$sbox
+
+ cmp \$0,%rbx
+ je .LSLOW_DECRYPT
+
+#--------------------------- SLOW ENCRYPT ---------------------------#
+ test \$-16,%r10 # check upon length
+ mov 0(%rbp),$s0 # load iv
+ mov 4(%rbp),$s1
+ mov 8(%rbp),$s2
+ mov 12(%rbp),$s3
+ jz .Lcbc_slow_enc_tail # short input...
+
+.align 4
+.Lcbc_slow_enc_loop:
+ xor 0($inp),$s0
+ xor 4($inp),$s1
+ xor 8($inp),$s2
+ xor 12($inp),$s3
+ mov $keyp,$key # restore key
+ mov $inp,$_inp # save inp
+ mov $out,$_out # save out
+ mov %r10,$_len # save len
+
+ call _x86_64_AES_encrypt_compact
+
+ mov $_inp,$inp # restore inp
+ mov $_out,$out # restore out
+ mov $_len,%r10 # restore len
+ mov $s0,0($out)
+ mov $s1,4($out)
+ mov $s2,8($out)
+ mov $s3,12($out)
+
+ lea 16($inp),$inp
+ lea 16($out),$out
+ sub \$16,%r10
+ test \$-16,%r10
+ jnz .Lcbc_slow_enc_loop
+ test \$15,%r10
+ jnz .Lcbc_slow_enc_tail
+ mov $_ivp,%rbp # restore ivp
+ mov $s0,0(%rbp) # save ivec
+ mov $s1,4(%rbp)
+ mov $s2,8(%rbp)
+ mov $s3,12(%rbp)
+
+ jmp .Lcbc_exit
+
+.align 4
+.Lcbc_slow_enc_tail:
+ mov %rax,%r11
+ mov %rcx,%r12
+ mov %r10,%rcx
+ mov $inp,%rsi
+ mov $out,%rdi
+ .long 0x9066A4F3 # rep movsb
+ mov \$16,%rcx # zero tail
+ sub %r10,%rcx
+ xor %rax,%rax
+ .long 0x9066AAF3 # rep stosb
+ mov $out,$inp # this is not a mistake!
+ mov \$16,%r10 # len=16
+ mov %r11,%rax
+ mov %r12,%rcx
+ jmp .Lcbc_slow_enc_loop # one more spin...
+#--------------------------- SLOW DECRYPT ---------------------------#
+.align 16
+.LSLOW_DECRYPT:
+ shr \$3,%rax
+ add %rax,$sbox # recall "magic" constants!
+
+ mov 0(%rbp),%r11 # copy iv to stack
+ mov 8(%rbp),%r12
+ mov %r11,0+$ivec
+ mov %r12,8+$ivec
+
+.align 4
+.Lcbc_slow_dec_loop:
+ mov 0($inp),$s0 # load input
+ mov 4($inp),$s1
+ mov 8($inp),$s2
+ mov 12($inp),$s3
+ mov $keyp,$key # restore key
+ mov $inp,$_inp # save inp
+ mov $out,$_out # save out
+ mov %r10,$_len # save len
+
+ call _x86_64_AES_decrypt_compact
+
+ mov $_inp,$inp # restore inp
+ mov $_out,$out # restore out
+ mov $_len,%r10
+ xor 0+$ivec,$s0
+ xor 4+$ivec,$s1
+ xor 8+$ivec,$s2
+ xor 12+$ivec,$s3
+
+ mov 0($inp),%r11 # load input
+ mov 8($inp),%r12
+ sub \$16,%r10
+ jc .Lcbc_slow_dec_partial
+ jz .Lcbc_slow_dec_done
+
+ mov %r11,0+$ivec # copy input to iv
+ mov %r12,8+$ivec
+
+ mov $s0,0($out) # save output [can zap input]
+ mov $s1,4($out)
+ mov $s2,8($out)
+ mov $s3,12($out)
+
+ lea 16($inp),$inp
+ lea 16($out),$out
+ jmp .Lcbc_slow_dec_loop
+.Lcbc_slow_dec_done:
+ mov $_ivp,%rdi
+ mov %r11,0(%rdi) # copy iv back to user
+ mov %r12,8(%rdi)
+
+ mov $s0,0($out) # save output [can zap input]
+ mov $s1,4($out)
+ mov $s2,8($out)
+ mov $s3,12($out)
+
+ jmp .Lcbc_exit
+
+.align 4
+.Lcbc_slow_dec_partial:
+ mov $_ivp,%rdi
+ mov %r11,0(%rdi) # copy iv back to user
+ mov %r12,8(%rdi)
+
+ mov $s0,0+$ivec # save output to stack
+ mov $s1,4+$ivec
+ mov $s2,8+$ivec
+ mov $s3,12+$ivec
+
+ mov $out,%rdi
+ lea $ivec,%rsi
+ lea 16(%r10),%rcx
+ .long 0x9066A4F3 # rep movsb
+ jmp .Lcbc_exit
+
+.align 16
+.Lcbc_exit:
+ mov $_rsp,%rsi
+ mov (%rsi),%r15
+ mov 8(%rsi),%r14
+ mov 16(%rsi),%r13
+ mov 24(%rsi),%r12
+ mov 32(%rsi),%rbp
+ mov 40(%rsi),%rbx
+ lea 48(%rsi),%rsp
+.Lcbc_popfq:
+ popfq
+.Lcbc_epilogue:
+ ret
+.size AES_cbc_encrypt,.-AES_cbc_encrypt
+___
+}
+
+$code.=<<___;
+.align 64
+.LAES_Te:
+___
+ &_data_word(0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6);
+ &_data_word(0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591);
+ &_data_word(0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56);
+ &_data_word(0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec);
+ &_data_word(0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa);
+ &_data_word(0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb);
+ &_data_word(0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45);
+ &_data_word(0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b);
+ &_data_word(0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c);
+ &_data_word(0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83);
+ &_data_word(0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9);
+ &_data_word(0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a);
+ &_data_word(0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d);
+ &_data_word(0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f);
+ &_data_word(0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df);
+ &_data_word(0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea);
+ &_data_word(0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34);
+ &_data_word(0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b);
+ &_data_word(0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d);
+ &_data_word(0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413);
+ &_data_word(0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1);
+ &_data_word(0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6);
+ &_data_word(0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972);
+ &_data_word(0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85);
+ &_data_word(0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed);
+ &_data_word(0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511);
+ &_data_word(0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe);
+ &_data_word(0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b);
+ &_data_word(0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05);
+ &_data_word(0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1);
+ &_data_word(0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142);
+ &_data_word(0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf);
+ &_data_word(0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3);
+ &_data_word(0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e);
+ &_data_word(0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a);
+ &_data_word(0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6);
+ &_data_word(0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3);
+ &_data_word(0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b);
+ &_data_word(0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428);
+ &_data_word(0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad);
+ &_data_word(0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14);
+ &_data_word(0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8);
+ &_data_word(0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4);
+ &_data_word(0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2);
+ &_data_word(0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda);
+ &_data_word(0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949);
+ &_data_word(0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf);
+ &_data_word(0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810);
+ &_data_word(0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c);
+ &_data_word(0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697);
+ &_data_word(0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e);
+ &_data_word(0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f);
+ &_data_word(0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc);
+ &_data_word(0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c);
+ &_data_word(0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969);
+ &_data_word(0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27);
+ &_data_word(0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122);
+ &_data_word(0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433);
+ &_data_word(0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9);
+ &_data_word(0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5);
+ &_data_word(0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a);
+ &_data_word(0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0);
+ &_data_word(0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e);
+ &_data_word(0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c);
+
+#Te4 # four copies of Te4 to choose from to avoid L1 aliasing
+ &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5);
+ &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76);
+ &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0);
+ &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0);
+ &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc);
+ &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15);
+ &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a);
+ &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75);
+ &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0);
+ &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84);
+ &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b);
+ &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf);
+ &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85);
+ &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8);
+ &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5);
+ &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2);
+ &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17);
+ &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73);
+ &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88);
+ &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb);
+ &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c);
+ &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79);
+ &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9);
+ &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08);
+ &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6);
+ &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a);
+ &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e);
+ &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e);
+ &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94);
+ &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf);
+ &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68);
+ &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16);
+
+ &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5);
+ &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76);
+ &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0);
+ &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0);
+ &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc);
+ &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15);
+ &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a);
+ &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75);
+ &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0);
+ &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84);
+ &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b);
+ &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf);
+ &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85);
+ &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8);
+ &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5);
+ &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2);
+ &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17);
+ &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73);
+ &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88);
+ &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb);
+ &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c);
+ &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79);
+ &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9);
+ &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08);
+ &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6);
+ &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a);
+ &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e);
+ &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e);
+ &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94);
+ &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf);
+ &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68);
+ &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16);
+
+ &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5);
+ &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76);
+ &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0);
+ &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0);
+ &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc);
+ &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15);
+ &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a);
+ &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75);
+ &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0);
+ &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84);
+ &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b);
+ &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf);
+ &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85);
+ &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8);
+ &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5);
+ &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2);
+ &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17);
+ &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73);
+ &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88);
+ &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb);
+ &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c);
+ &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79);
+ &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9);
+ &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08);
+ &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6);
+ &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a);
+ &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e);
+ &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e);
+ &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94);
+ &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf);
+ &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68);
+ &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16);
+
+ &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5);
+ &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76);
+ &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0);
+ &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0);
+ &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc);
+ &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15);
+ &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a);
+ &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75);
+ &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0);
+ &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84);
+ &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b);
+ &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf);
+ &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85);
+ &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8);
+ &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5);
+ &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2);
+ &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17);
+ &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73);
+ &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88);
+ &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb);
+ &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c);
+ &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79);
+ &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9);
+ &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08);
+ &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6);
+ &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a);
+ &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e);
+ &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e);
+ &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94);
+ &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf);
+ &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68);
+ &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16);
+#rcon:
+$code.=<<___;
+ .long 0x00000001, 0x00000002, 0x00000004, 0x00000008
+ .long 0x00000010, 0x00000020, 0x00000040, 0x00000080
+ .long 0x0000001b, 0x00000036, 0x80808080, 0x80808080
+ .long 0xfefefefe, 0xfefefefe, 0x1b1b1b1b, 0x1b1b1b1b
+___
+$code.=<<___;
+.align 64
+.LAES_Td:
+___
+ &_data_word(0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a);
+ &_data_word(0xcb6bab3b, 0xf1459d1f, 0xab58faac, 0x9303e34b);
+ &_data_word(0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5);
+ &_data_word(0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 0x8fa362b5);
+ &_data_word(0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d);
+ &_data_word(0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b);
+ &_data_word(0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295);
+ &_data_word(0x2d83bed4, 0xd3217458, 0x2969e049, 0x44c8c98e);
+ &_data_word(0x6a89c275, 0x78798ef4, 0x6b3e5899, 0xdd71b927);
+ &_data_word(0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d);
+ &_data_word(0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362);
+ &_data_word(0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9);
+ &_data_word(0x58684870, 0x19fd458f, 0x876cde94, 0xb7f87b52);
+ &_data_word(0x23d373ab, 0xe2024b72, 0x578f1fe3, 0x2aab5566);
+ &_data_word(0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3);
+ &_data_word(0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed);
+ &_data_word(0x2b1ccf8a, 0x92b479a7, 0xf0f207f3, 0xa1e2694e);
+ &_data_word(0xcdf4da65, 0xd5be0506, 0x1f6234d1, 0x8afea6c4);
+ &_data_word(0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4);
+ &_data_word(0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd);
+ &_data_word(0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d);
+ &_data_word(0xb58d5491, 0x055dc471, 0x6fd40604, 0xff155060);
+ &_data_word(0x24fb9819, 0x97e9bdd6, 0xcc434089, 0x779ed967);
+ &_data_word(0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879);
+ &_data_word(0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000);
+ &_data_word(0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c);
+ &_data_word(0xfbff0efd, 0x5638850f, 0x1ed5ae3d, 0x27392d36);
+ &_data_word(0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624);
+ &_data_word(0xb1670a0c, 0x0fe75793, 0xd296eeb4, 0x9e919b1b);
+ &_data_word(0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c);
+ &_data_word(0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12);
+ &_data_word(0x0b0d090e, 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14);
+ &_data_word(0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3);
+ &_data_word(0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b);
+ &_data_word(0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8);
+ &_data_word(0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684);
+ &_data_word(0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7);
+ &_data_word(0x4b2f9e1d, 0xf330b2dc, 0xec52860d, 0xd0e3c177);
+ &_data_word(0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947);
+ &_data_word(0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322);
+ &_data_word(0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498);
+ &_data_word(0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f);
+ &_data_word(0xe49d3a2c, 0x0d927850, 0x9bcc5f6a, 0x62467e54);
+ &_data_word(0xc2138df6, 0xe8b8d890, 0x5ef7392e, 0xf5afc382);
+ &_data_word(0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf);
+ &_data_word(0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb);
+ &_data_word(0x097826cd, 0xf418596e, 0x01b79aec, 0xa89a4f83);
+ &_data_word(0x656e95e6, 0x7ee6ffaa, 0x08cfbc21, 0xe6e815ef);
+ &_data_word(0xd99be7ba, 0xce366f4a, 0xd4099fea, 0xd67cb029);
+ &_data_word(0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235);
+ &_data_word(0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733);
+ &_data_word(0x4a9804f1, 0xf7daec41, 0x0e50cd7f, 0x2ff69117);
+ &_data_word(0x8dd64d76, 0x4db0ef43, 0x544daacc, 0xdf0496e4);
+ &_data_word(0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 0x7f516546);
+ &_data_word(0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb);
+ &_data_word(0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d);
+ &_data_word(0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb);
+ &_data_word(0xee27a9ce, 0x35c961b7, 0xede51ce1, 0x3cb1477a);
+ &_data_word(0x59dfd29c, 0x3f73f255, 0x79ce1418, 0xbf37c773);
+ &_data_word(0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478);
+ &_data_word(0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2);
+ &_data_word(0x72c31d16, 0x0c25e2bc, 0x8b493c28, 0x41950dff);
+ &_data_word(0x7101a839, 0xdeb30c08, 0x9ce4b4d8, 0x90c15664);
+ &_data_word(0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0);
+
+#Td4: # four copies of Td4 to choose from to avoid L1 aliasing
+ &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38);
+ &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb);
+ &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87);
+ &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb);
+ &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d);
+ &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e);
+ &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2);
+ &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25);
+ &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16);
+ &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92);
+ &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda);
+ &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84);
+ &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a);
+ &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06);
+ &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02);
+ &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b);
+ &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea);
+ &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73);
+ &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85);
+ &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e);
+ &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89);
+ &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b);
+ &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20);
+ &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4);
+ &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31);
+ &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f);
+ &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d);
+ &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef);
+ &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0);
+ &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61);
+ &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26);
+ &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d);
+$code.=<<___;
+ .long 0x80808080, 0x80808080, 0xfefefefe, 0xfefefefe
+ .long 0x1b1b1b1b, 0x1b1b1b1b, 0, 0
+___
+ &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38);
+ &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb);
+ &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87);
+ &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb);
+ &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d);
+ &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e);
+ &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2);
+ &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25);
+ &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16);
+ &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92);
+ &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda);
+ &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84);
+ &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a);
+ &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06);
+ &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02);
+ &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b);
+ &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea);
+ &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73);
+ &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85);
+ &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e);
+ &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89);
+ &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b);
+ &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20);
+ &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4);
+ &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31);
+ &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f);
+ &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d);
+ &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef);
+ &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0);
+ &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61);
+ &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26);
+ &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d);
+$code.=<<___;
+ .long 0x80808080, 0x80808080, 0xfefefefe, 0xfefefefe
+ .long 0x1b1b1b1b, 0x1b1b1b1b, 0, 0
+___
+ &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38);
+ &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb);
+ &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87);
+ &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb);
+ &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d);
+ &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e);
+ &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2);
+ &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25);
+ &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16);
+ &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92);
+ &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda);
+ &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84);
+ &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a);
+ &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06);
+ &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02);
+ &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b);
+ &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea);
+ &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73);
+ &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85);
+ &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e);
+ &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89);
+ &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b);
+ &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20);
+ &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4);
+ &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31);
+ &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f);
+ &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d);
+ &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef);
+ &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0);
+ &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61);
+ &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26);
+ &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d);
+$code.=<<___;
+ .long 0x80808080, 0x80808080, 0xfefefefe, 0xfefefefe
+ .long 0x1b1b1b1b, 0x1b1b1b1b, 0, 0
+___
+ &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38);
+ &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb);
+ &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87);
+ &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb);
+ &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d);
+ &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e);
+ &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2);
+ &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25);
+ &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16);
+ &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92);
+ &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda);
+ &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84);
+ &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a);
+ &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06);
+ &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02);
+ &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b);
+ &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea);
+ &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73);
+ &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85);
+ &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e);
+ &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89);
+ &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b);
+ &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20);
+ &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4);
+ &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31);
+ &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f);
+ &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d);
+ &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef);
+ &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0);
+ &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61);
+ &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26);
+ &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d);
+$code.=<<___;
+ .long 0x80808080, 0x80808080, 0xfefefefe, 0xfefefefe
+ .long 0x1b1b1b1b, 0x1b1b1b1b, 0, 0
+.asciz "AES for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
+.align 64
+___
+
+# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
+# CONTEXT *context,DISPATCHER_CONTEXT *disp)
+if ($win64) {
+$rec="%rcx";
+$frame="%rdx";
+$context="%r8";
+$disp="%r9";
+
+$code.=<<___;
+.extern __imp_RtlVirtualUnwind
+.type block_se_handler,\@abi-omnipotent
+.align 16
+block_se_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 120($context),%rax # pull context->Rax
+ mov 248($context),%rbx # pull context->Rip
+
+ mov 8($disp),%rsi # disp->ImageBase
+ mov 56($disp),%r11 # disp->HandlerData
+
+ mov 0(%r11),%r10d # HandlerData[0]
+ lea (%rsi,%r10),%r10 # prologue label
+ cmp %r10,%rbx # context->Rip<prologue label
+ jb .Lin_block_prologue
+
+ mov 152($context),%rax # pull context->Rsp
+
+ mov 4(%r11),%r10d # HandlerData[1]
+ lea (%rsi,%r10),%r10 # epilogue label
+ cmp %r10,%rbx # context->Rip>=epilogue label
+ jae .Lin_block_prologue
+
+ mov 24(%rax),%rax # pull saved real stack pointer
+ lea 48(%rax),%rax # adjust...
+
+ mov -8(%rax),%rbx
+ mov -16(%rax),%rbp
+ mov -24(%rax),%r12
+ mov -32(%rax),%r13
+ mov -40(%rax),%r14
+ mov -48(%rax),%r15
+ mov %rbx,144($context) # restore context->Rbx
+ mov %rbp,160($context) # restore context->Rbp
+ mov %r12,216($context) # restore context->R12
+ mov %r13,224($context) # restore context->R13
+ mov %r14,232($context) # restore context->R14
+ mov %r15,240($context) # restore context->R15
+
+.Lin_block_prologue:
+ mov 8(%rax),%rdi
+ mov 16(%rax),%rsi
+ mov %rax,152($context) # restore context->Rsp
+ mov %rsi,168($context) # restore context->Rsi
+ mov %rdi,176($context) # restore context->Rdi
+
+ jmp .Lcommon_seh_exit
+.size block_se_handler,.-block_se_handler
+
+.type key_se_handler,\@abi-omnipotent
+.align 16
+key_se_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 120($context),%rax # pull context->Rax
+ mov 248($context),%rbx # pull context->Rip
+
+ mov 8($disp),%rsi # disp->ImageBase
+ mov 56($disp),%r11 # disp->HandlerData
+
+ mov 0(%r11),%r10d # HandlerData[0]
+ lea (%rsi,%r10),%r10 # prologue label
+ cmp %r10,%rbx # context->Rip<prologue label
+ jb .Lin_key_prologue
+
+ mov 152($context),%rax # pull context->Rsp
+
+ mov 4(%r11),%r10d # HandlerData[1]
+ lea (%rsi,%r10),%r10 # epilogue label
+ cmp %r10,%rbx # context->Rip>=epilogue label
+ jae .Lin_key_prologue
+
+ lea 56(%rax),%rax
+
+ mov -8(%rax),%rbx
+ mov -16(%rax),%rbp
+ mov -24(%rax),%r12
+ mov -32(%rax),%r13
+ mov -40(%rax),%r14
+ mov -48(%rax),%r15
+ mov %rbx,144($context) # restore context->Rbx
+ mov %rbp,160($context) # restore context->Rbp
+ mov %r12,216($context) # restore context->R12
+ mov %r13,224($context) # restore context->R13
+ mov %r14,232($context) # restore context->R14
+ mov %r15,240($context) # restore context->R15
+
+.Lin_key_prologue:
+ mov 8(%rax),%rdi
+ mov 16(%rax),%rsi
+ mov %rax,152($context) # restore context->Rsp
+ mov %rsi,168($context) # restore context->Rsi
+ mov %rdi,176($context) # restore context->Rdi
+
+ jmp .Lcommon_seh_exit
+.size key_se_handler,.-key_se_handler
+
+.type cbc_se_handler,\@abi-omnipotent
+.align 16
+cbc_se_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 120($context),%rax # pull context->Rax
+ mov 248($context),%rbx # pull context->Rip
+
+ lea .Lcbc_prologue(%rip),%r10
+ cmp %r10,%rbx # context->Rip<.Lcbc_prologue
+ jb .Lin_cbc_prologue
+
+ lea .Lcbc_fast_body(%rip),%r10
+ cmp %r10,%rbx # context->Rip<.Lcbc_fast_body
+ jb .Lin_cbc_frame_setup
+
+ lea .Lcbc_slow_prologue(%rip),%r10
+ cmp %r10,%rbx # context->Rip<.Lcbc_slow_prologue
+ jb .Lin_cbc_body
+
+ lea .Lcbc_slow_body(%rip),%r10
+ cmp %r10,%rbx # context->Rip<.Lcbc_slow_body
+ jb .Lin_cbc_frame_setup
+
+.Lin_cbc_body:
+ mov 152($context),%rax # pull context->Rsp
+
+ lea .Lcbc_epilogue(%rip),%r10
+ cmp %r10,%rbx # context->Rip>=.Lcbc_epilogue
+ jae .Lin_cbc_prologue
+
+ lea 8(%rax),%rax
+
+ lea .Lcbc_popfq(%rip),%r10
+ cmp %r10,%rbx # context->Rip>=.Lcbc_popfq
+ jae .Lin_cbc_prologue
+
+ mov `16-8`(%rax),%rax # biased $_rsp
+ lea 56(%rax),%rax
+
+.Lin_cbc_frame_setup:
+ mov -16(%rax),%rbx
+ mov -24(%rax),%rbp
+ mov -32(%rax),%r12
+ mov -40(%rax),%r13
+ mov -48(%rax),%r14
+ mov -56(%rax),%r15
+ mov %rbx,144($context) # restore context->Rbx
+ mov %rbp,160($context) # restore context->Rbp
+ mov %r12,216($context) # restore context->R12
+ mov %r13,224($context) # restore context->R13
+ mov %r14,232($context) # restore context->R14
+ mov %r15,240($context) # restore context->R15
+
+.Lin_cbc_prologue:
+ mov 8(%rax),%rdi
+ mov 16(%rax),%rsi
+ mov %rax,152($context) # restore context->Rsp
+ mov %rsi,168($context) # restore context->Rsi
+ mov %rdi,176($context) # restore context->Rdi
+
+.Lcommon_seh_exit:
+
+ mov 40($disp),%rdi # disp->ContextRecord
+ mov $context,%rsi # context
+ mov \$`1232/8`,%ecx # sizeof(CONTEXT)
+ .long 0xa548f3fc # cld; rep movsq
+
+ mov $disp,%rsi
+ xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER
+ mov 8(%rsi),%rdx # arg2, disp->ImageBase
+ mov 0(%rsi),%r8 # arg3, disp->ControlPc
+ mov 16(%rsi),%r9 # arg4, disp->FunctionEntry
+ mov 40(%rsi),%r10 # disp->ContextRecord
+ lea 56(%rsi),%r11 # &disp->HandlerData
+ lea 24(%rsi),%r12 # &disp->EstablisherFrame
+ mov %r10,32(%rsp) # arg5
+ mov %r11,40(%rsp) # arg6
+ mov %r12,48(%rsp) # arg7
+ mov %rcx,56(%rsp) # arg8, (NULL)
+ call *__imp_RtlVirtualUnwind(%rip)
+
+ mov \$1,%eax # ExceptionContinueSearch
+ add \$64,%rsp
+ popfq
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+ pop %rdi
+ pop %rsi
+ ret
+.size cbc_se_handler,.-cbc_se_handler
+
+.section .pdata
+.align 4
+ .rva .LSEH_begin_AES_encrypt
+ .rva .LSEH_end_AES_encrypt
+ .rva .LSEH_info_AES_encrypt
+
+ .rva .LSEH_begin_AES_decrypt
+ .rva .LSEH_end_AES_decrypt
+ .rva .LSEH_info_AES_decrypt
+
+ .rva .LSEH_begin_AES_set_encrypt_key
+ .rva .LSEH_end_AES_set_encrypt_key
+ .rva .LSEH_info_AES_set_encrypt_key
+
+ .rva .LSEH_begin_AES_set_decrypt_key
+ .rva .LSEH_end_AES_set_decrypt_key
+ .rva .LSEH_info_AES_set_decrypt_key
+
+ .rva .LSEH_begin_AES_cbc_encrypt
+ .rva .LSEH_end_AES_cbc_encrypt
+ .rva .LSEH_info_AES_cbc_encrypt
+
+.section .xdata
+.align 8
+.LSEH_info_AES_encrypt:
+ .byte 9,0,0,0
+ .rva block_se_handler
+ .rva .Lenc_prologue,.Lenc_epilogue # HandlerData[]
+.LSEH_info_AES_decrypt:
+ .byte 9,0,0,0
+ .rva block_se_handler
+ .rva .Ldec_prologue,.Ldec_epilogue # HandlerData[]
+.LSEH_info_AES_set_encrypt_key:
+ .byte 9,0,0,0
+ .rva key_se_handler
+ .rva .Lenc_key_prologue,.Lenc_key_epilogue # HandlerData[]
+.LSEH_info_AES_set_decrypt_key:
+ .byte 9,0,0,0
+ .rva key_se_handler
+ .rva .Ldec_key_prologue,.Ldec_key_epilogue # HandlerData[]
+.LSEH_info_AES_cbc_encrypt:
+ .byte 9,0,0,0
+ .rva cbc_se_handler
+___
+}
+
+$code =~ s/\`([^\`]*)\`/eval($1)/gem;
+
+print $code;
+
+close STDOUT;
diff --git a/crypto/aes/asm/aesni-x86.pl b/crypto/aes/asm/aesni-x86.pl
new file mode 100644
index 0000000..3dc345b
--- /dev/null
+++ b/crypto/aes/asm/aesni-x86.pl
@@ -0,0 +1,2189 @@
+#!/usr/bin/env perl
+
+# ====================================================================
+# Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+#
+# This module implements support for Intel AES-NI extension. In
+# OpenSSL context it's used with Intel engine, but can also be used as
+# drop-in replacement for crypto/aes/asm/aes-586.pl [see below for
+# details].
+#
+# Performance.
+#
+# To start with see corresponding paragraph in aesni-x86_64.pl...
+# Instead of filling table similar to one found there I've chosen to
+# summarize *comparison* results for raw ECB, CTR and CBC benchmarks.
+# The simplified table below represents 32-bit performance relative
+# to 64-bit one in every given point. Ratios vary for different
+# encryption modes, therefore interval values.
+#
+# 16-byte 64-byte 256-byte 1-KB 8-KB
+# 53-67% 67-84% 91-94% 95-98% 97-99.5%
+#
+# Lower ratios for smaller block sizes are perfectly understandable,
+# because function call overhead is higher in 32-bit mode. Largest
+# 8-KB block performance is virtually same: 32-bit code is less than
+# 1% slower for ECB, CBC and CCM, and ~3% slower otherwise.
+
+# January 2011
+#
+# See aesni-x86_64.pl for details. Unlike x86_64 version this module
+# interleaves at most 6 aes[enc|dec] instructions, because there are
+# not enough registers for 8x interleave [which should be optimal for
+# Sandy Bridge]. Actually, performance results for 6x interleave
+# factor presented in aesni-x86_64.pl (except for CTR) are for this
+# module.
+
+# April 2011
+#
+# Add aesni_xts_[en|de]crypt. Westmere spends 1.50 cycles processing
+# one byte out of 8KB with 128-bit key, Sandy Bridge - 1.09.
+
+$PREFIX="aesni"; # if $PREFIX is set to "AES", the script
+ # generates drop-in replacement for
+ # crypto/aes/asm/aes-586.pl:-)
+$inline=1; # inline _aesni_[en|de]crypt
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+push(@INC,"${dir}","${dir}../../perlasm");
+require "x86asm.pl";
+
+&asm_init($ARGV[0],$0);
+
+if ($PREFIX eq "aesni") { $movekey=*movups; }
+else { $movekey=*movups; }
+
+$len="eax";
+$rounds="ecx";
+$key="edx";
+$inp="esi";
+$out="edi";
+$rounds_="ebx"; # backup copy for $rounds
+$key_="ebp"; # backup copy for $key
+
+$rndkey0="xmm0";
+$rndkey1="xmm1";
+$inout0="xmm2";
+$inout1="xmm3";
+$inout2="xmm4";
+$inout3="xmm5"; $in1="xmm5";
+$inout4="xmm6"; $in0="xmm6";
+$inout5="xmm7"; $ivec="xmm7";
+
+# AESNI extenstion
+sub aeskeygenassist
+{ my($dst,$src,$imm)=@_;
+ if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/)
+ { &data_byte(0x66,0x0f,0x3a,0xdf,0xc0|($1<<3)|$2,$imm); }
+}
+sub aescommon
+{ my($opcodelet,$dst,$src)=@_;
+ if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/)
+ { &data_byte(0x66,0x0f,0x38,$opcodelet,0xc0|($1<<3)|$2);}
+}
+sub aesimc { aescommon(0xdb,@_); }
+sub aesenc { aescommon(0xdc,@_); }
+sub aesenclast { aescommon(0xdd,@_); }
+sub aesdec { aescommon(0xde,@_); }
+sub aesdeclast { aescommon(0xdf,@_); }
+
+# Inline version of internal aesni_[en|de]crypt1
+{ my $sn;
+sub aesni_inline_generate1
+{ my ($p,$inout,$ivec)=@_; $inout=$inout0 if (!defined($inout));
+ $sn++;
+
+ &$movekey ($rndkey0,&QWP(0,$key));
+ &$movekey ($rndkey1,&QWP(16,$key));
+ &xorps ($ivec,$rndkey0) if (defined($ivec));
+ &lea ($key,&DWP(32,$key));
+ &xorps ($inout,$ivec) if (defined($ivec));
+ &xorps ($inout,$rndkey0) if (!defined($ivec));
+ &set_label("${p}1_loop_$sn");
+ eval"&aes${p} ($inout,$rndkey1)";
+ &dec ($rounds);
+ &$movekey ($rndkey1,&QWP(0,$key));
+ &lea ($key,&DWP(16,$key));
+ &jnz (&label("${p}1_loop_$sn"));
+ eval"&aes${p}last ($inout,$rndkey1)";
+}}
+
+sub aesni_generate1 # fully unrolled loop
+{ my ($p,$inout)=@_; $inout=$inout0 if (!defined($inout));
+
+ &function_begin_B("_aesni_${p}rypt1");
+ &movups ($rndkey0,&QWP(0,$key));
+ &$movekey ($rndkey1,&QWP(0x10,$key));
+ &xorps ($inout,$rndkey0);
+ &$movekey ($rndkey0,&QWP(0x20,$key));
+ &lea ($key,&DWP(0x30,$key));
+ &cmp ($rounds,11);
+ &jb (&label("${p}128"));
+ &lea ($key,&DWP(0x20,$key));
+ &je (&label("${p}192"));
+ &lea ($key,&DWP(0x20,$key));
+ eval"&aes${p} ($inout,$rndkey1)";
+ &$movekey ($rndkey1,&QWP(-0x40,$key));
+ eval"&aes${p} ($inout,$rndkey0)";
+ &$movekey ($rndkey0,&QWP(-0x30,$key));
+ &set_label("${p}192");
+ eval"&aes${p} ($inout,$rndkey1)";
+ &$movekey ($rndkey1,&QWP(-0x20,$key));
+ eval"&aes${p} ($inout,$rndkey0)";
+ &$movekey ($rndkey0,&QWP(-0x10,$key));
+ &set_label("${p}128");
+ eval"&aes${p} ($inout,$rndkey1)";
+ &$movekey ($rndkey1,&QWP(0,$key));
+ eval"&aes${p} ($inout,$rndkey0)";
+ &$movekey ($rndkey0,&QWP(0x10,$key));
+ eval"&aes${p} ($inout,$rndkey1)";
+ &$movekey ($rndkey1,&QWP(0x20,$key));
+ eval"&aes${p} ($inout,$rndkey0)";
+ &$movekey ($rndkey0,&QWP(0x30,$key));
+ eval"&aes${p} ($inout,$rndkey1)";
+ &$movekey ($rndkey1,&QWP(0x40,$key));
+ eval"&aes${p} ($inout,$rndkey0)";
+ &$movekey ($rndkey0,&QWP(0x50,$key));
+ eval"&aes${p} ($inout,$rndkey1)";
+ &$movekey ($rndkey1,&QWP(0x60,$key));
+ eval"&aes${p} ($inout,$rndkey0)";
+ &$movekey ($rndkey0,&QWP(0x70,$key));
+ eval"&aes${p} ($inout,$rndkey1)";
+ eval"&aes${p}last ($inout,$rndkey0)";
+ &ret();
+ &function_end_B("_aesni_${p}rypt1");
+}
+
+# void $PREFIX_encrypt (const void *inp,void *out,const AES_KEY *key);
+&aesni_generate1("enc") if (!$inline);
+&function_begin_B("${PREFIX}_encrypt");
+ &mov ("eax",&wparam(0));
+ &mov ($key,&wparam(2));
+ &movups ($inout0,&QWP(0,"eax"));
+ &mov ($rounds,&DWP(240,$key));
+ &mov ("eax",&wparam(1));
+ if ($inline)
+ { &aesni_inline_generate1("enc"); }
+ else
+ { &call ("_aesni_encrypt1"); }
+ &movups (&QWP(0,"eax"),$inout0);
+ &ret ();
+&function_end_B("${PREFIX}_encrypt");
+
+# void $PREFIX_decrypt (const void *inp,void *out,const AES_KEY *key);
+&aesni_generate1("dec") if(!$inline);
+&function_begin_B("${PREFIX}_decrypt");
+ &mov ("eax",&wparam(0));
+ &mov ($key,&wparam(2));
+ &movups ($inout0,&QWP(0,"eax"));
+ &mov ($rounds,&DWP(240,$key));
+ &mov ("eax",&wparam(1));
+ if ($inline)
+ { &aesni_inline_generate1("dec"); }
+ else
+ { &call ("_aesni_decrypt1"); }
+ &movups (&QWP(0,"eax"),$inout0);
+ &ret ();
+&function_end_B("${PREFIX}_decrypt");
+
+# _aesni_[en|de]cryptN are private interfaces, N denotes interleave
+# factor. Why 3x subroutine were originally used in loops? Even though
+# aes[enc|dec] latency was originally 6, it could be scheduled only
+# every *2nd* cycle. Thus 3x interleave was the one providing optimal
+# utilization, i.e. when subroutine's throughput is virtually same as
+# of non-interleaved subroutine [for number of input blocks up to 3].
+# This is why it makes no sense to implement 2x subroutine.
+# aes[enc|dec] latency in next processor generation is 8, but the
+# instructions can be scheduled every cycle. Optimal interleave for
+# new processor is therefore 8x, but it's unfeasible to accommodate it
+# in XMM registers addreassable in 32-bit mode and therefore 6x is
+# used instead...
+
+sub aesni_generate3
+{ my $p=shift;
+
+ &function_begin_B("_aesni_${p}rypt3");
+ &$movekey ($rndkey0,&QWP(0,$key));
+ &shr ($rounds,1);
+ &$movekey ($rndkey1,&QWP(16,$key));
+ &lea ($key,&DWP(32,$key));
+ &xorps ($inout0,$rndkey0);
+ &pxor ($inout1,$rndkey0);
+ &pxor ($inout2,$rndkey0);
+ &$movekey ($rndkey0,&QWP(0,$key));
+
+ &set_label("${p}3_loop");
+ eval"&aes${p} ($inout0,$rndkey1)";
+ eval"&aes${p} ($inout1,$rndkey1)";
+ &dec ($rounds);
+ eval"&aes${p} ($inout2,$rndkey1)";
+ &$movekey ($rndkey1,&QWP(16,$key));
+ eval"&aes${p} ($inout0,$rndkey0)";
+ eval"&aes${p} ($inout1,$rndkey0)";
+ &lea ($key,&DWP(32,$key));
+ eval"&aes${p} ($inout2,$rndkey0)";
+ &$movekey ($rndkey0,&QWP(0,$key));
+ &jnz (&label("${p}3_loop"));
+ eval"&aes${p} ($inout0,$rndkey1)";
+ eval"&aes${p} ($inout1,$rndkey1)";
+ eval"&aes${p} ($inout2,$rndkey1)";
+ eval"&aes${p}last ($inout0,$rndkey0)";
+ eval"&aes${p}last ($inout1,$rndkey0)";
+ eval"&aes${p}last ($inout2,$rndkey0)";
+ &ret();
+ &function_end_B("_aesni_${p}rypt3");
+}
+
+# 4x interleave is implemented to improve small block performance,
+# most notably [and naturally] 4 block by ~30%. One can argue that one
+# should have implemented 5x as well, but improvement would be <20%,
+# so it's not worth it...
+sub aesni_generate4
+{ my $p=shift;
+
+ &function_begin_B("_aesni_${p}rypt4");
+ &$movekey ($rndkey0,&QWP(0,$key));
+ &$movekey ($rndkey1,&QWP(16,$key));
+ &shr ($rounds,1);
+ &lea ($key,&DWP(32,$key));
+ &xorps ($inout0,$rndkey0);
+ &pxor ($inout1,$rndkey0);
+ &pxor ($inout2,$rndkey0);
+ &pxor ($inout3,$rndkey0);
+ &$movekey ($rndkey0,&QWP(0,$key));
+
+ &set_label("${p}4_loop");
+ eval"&aes${p} ($inout0,$rndkey1)";
+ eval"&aes${p} ($inout1,$rndkey1)";
+ &dec ($rounds);
+ eval"&aes${p} ($inout2,$rndkey1)";
+ eval"&aes${p} ($inout3,$rndkey1)";
+ &$movekey ($rndkey1,&QWP(16,$key));
+ eval"&aes${p} ($inout0,$rndkey0)";
+ eval"&aes${p} ($inout1,$rndkey0)";
+ &lea ($key,&DWP(32,$key));
+ eval"&aes${p} ($inout2,$rndkey0)";
+ eval"&aes${p} ($inout3,$rndkey0)";
+ &$movekey ($rndkey0,&QWP(0,$key));
+ &jnz (&label("${p}4_loop"));
+
+ eval"&aes${p} ($inout0,$rndkey1)";
+ eval"&aes${p} ($inout1,$rndkey1)";
+ eval"&aes${p} ($inout2,$rndkey1)";
+ eval"&aes${p} ($inout3,$rndkey1)";
+ eval"&aes${p}last ($inout0,$rndkey0)";
+ eval"&aes${p}last ($inout1,$rndkey0)";
+ eval"&aes${p}last ($inout2,$rndkey0)";
+ eval"&aes${p}last ($inout3,$rndkey0)";
+ &ret();
+ &function_end_B("_aesni_${p}rypt4");
+}
+
+sub aesni_generate6
+{ my $p=shift;
+
+ &function_begin_B("_aesni_${p}rypt6");
+ &static_label("_aesni_${p}rypt6_enter");
+ &$movekey ($rndkey0,&QWP(0,$key));
+ &shr ($rounds,1);
+ &$movekey ($rndkey1,&QWP(16,$key));
+ &lea ($key,&DWP(32,$key));
+ &xorps ($inout0,$rndkey0);
+ &pxor ($inout1,$rndkey0); # pxor does better here
+ eval"&aes${p} ($inout0,$rndkey1)";
+ &pxor ($inout2,$rndkey0);
+ eval"&aes${p} ($inout1,$rndkey1)";
+ &pxor ($inout3,$rndkey0);
+ &dec ($rounds);
+ eval"&aes${p} ($inout2,$rndkey1)";
+ &pxor ($inout4,$rndkey0);
+ eval"&aes${p} ($inout3,$rndkey1)";
+ &pxor ($inout5,$rndkey0);
+ eval"&aes${p} ($inout4,$rndkey1)";
+ &$movekey ($rndkey0,&QWP(0,$key));
+ eval"&aes${p} ($inout5,$rndkey1)";
+ &jmp (&label("_aesni_${p}rypt6_enter"));
+
+ &set_label("${p}6_loop",16);
+ eval"&aes${p} ($inout0,$rndkey1)";
+ eval"&aes${p} ($inout1,$rndkey1)";
+ &dec ($rounds);
+ eval"&aes${p} ($inout2,$rndkey1)";
+ eval"&aes${p} ($inout3,$rndkey1)";
+ eval"&aes${p} ($inout4,$rndkey1)";
+ eval"&aes${p} ($inout5,$rndkey1)";
+ &set_label("_aesni_${p}rypt6_enter",16);
+ &$movekey ($rndkey1,&QWP(16,$key));
+ eval"&aes${p} ($inout0,$rndkey0)";
+ eval"&aes${p} ($inout1,$rndkey0)";
+ &lea ($key,&DWP(32,$key));
+ eval"&aes${p} ($inout2,$rndkey0)";
+ eval"&aes${p} ($inout3,$rndkey0)";
+ eval"&aes${p} ($inout4,$rndkey0)";
+ eval"&aes${p} ($inout5,$rndkey0)";
+ &$movekey ($rndkey0,&QWP(0,$key));
+ &jnz (&label("${p}6_loop"));
+
+ eval"&aes${p} ($inout0,$rndkey1)";
+ eval"&aes${p} ($inout1,$rndkey1)";
+ eval"&aes${p} ($inout2,$rndkey1)";
+ eval"&aes${p} ($inout3,$rndkey1)";
+ eval"&aes${p} ($inout4,$rndkey1)";
+ eval"&aes${p} ($inout5,$rndkey1)";
+ eval"&aes${p}last ($inout0,$rndkey0)";
+ eval"&aes${p}last ($inout1,$rndkey0)";
+ eval"&aes${p}last ($inout2,$rndkey0)";
+ eval"&aes${p}last ($inout3,$rndkey0)";
+ eval"&aes${p}last ($inout4,$rndkey0)";
+ eval"&aes${p}last ($inout5,$rndkey0)";
+ &ret();
+ &function_end_B("_aesni_${p}rypt6");
+}
+&aesni_generate3("enc") if ($PREFIX eq "aesni");
+&aesni_generate3("dec");
+&aesni_generate4("enc") if ($PREFIX eq "aesni");
+&aesni_generate4("dec");
+&aesni_generate6("enc") if ($PREFIX eq "aesni");
+&aesni_generate6("dec");
+
+if ($PREFIX eq "aesni") {
+######################################################################
+# void aesni_ecb_encrypt (const void *in, void *out,
+# size_t length, const AES_KEY *key,
+# int enc);
+&function_begin("aesni_ecb_encrypt");
+ &mov ($inp,&wparam(0));
+ &mov ($out,&wparam(1));
+ &mov ($len,&wparam(2));
+ &mov ($key,&wparam(3));
+ &mov ($rounds_,&wparam(4));
+ &and ($len,-16);
+ &jz (&label("ecb_ret"));
+ &mov ($rounds,&DWP(240,$key));
+ &test ($rounds_,$rounds_);
+ &jz (&label("ecb_decrypt"));
+
+ &mov ($key_,$key); # backup $key
+ &mov ($rounds_,$rounds); # backup $rounds
+ &cmp ($len,0x60);
+ &jb (&label("ecb_enc_tail"));
+
+ &movdqu ($inout0,&QWP(0,$inp));
+ &movdqu ($inout1,&QWP(0x10,$inp));
+ &movdqu ($inout2,&QWP(0x20,$inp));
+ &movdqu ($inout3,&QWP(0x30,$inp));
+ &movdqu ($inout4,&QWP(0x40,$inp));
+ &movdqu ($inout5,&QWP(0x50,$inp));
+ &lea ($inp,&DWP(0x60,$inp));
+ &sub ($len,0x60);
+ &jmp (&label("ecb_enc_loop6_enter"));
+
+&set_label("ecb_enc_loop6",16);
+ &movups (&QWP(0,$out),$inout0);
+ &movdqu ($inout0,&QWP(0,$inp));
+ &movups (&QWP(0x10,$out),$inout1);
+ &movdqu ($inout1,&QWP(0x10,$inp));
+ &movups (&QWP(0x20,$out),$inout2);
+ &movdqu ($inout2,&QWP(0x20,$inp));
+ &movups (&QWP(0x30,$out),$inout3);
+ &movdqu ($inout3,&QWP(0x30,$inp));
+ &movups (&QWP(0x40,$out),$inout4);
+ &movdqu ($inout4,&QWP(0x40,$inp));
+ &movups (&QWP(0x50,$out),$inout5);
+ &lea ($out,&DWP(0x60,$out));
+ &movdqu ($inout5,&QWP(0x50,$inp));
+ &lea ($inp,&DWP(0x60,$inp));
+&set_label("ecb_enc_loop6_enter");
+
+ &call ("_aesni_encrypt6");
+
+ &mov ($key,$key_); # restore $key
+ &mov ($rounds,$rounds_); # restore $rounds
+ &sub ($len,0x60);
+ &jnc (&label("ecb_enc_loop6"));
+
+ &movups (&QWP(0,$out),$inout0);
+ &movups (&QWP(0x10,$out),$inout1);
+ &movups (&QWP(0x20,$out),$inout2);
+ &movups (&QWP(0x30,$out),$inout3);
+ &movups (&QWP(0x40,$out),$inout4);
+ &movups (&QWP(0x50,$out),$inout5);
+ &lea ($out,&DWP(0x60,$out));
+ &add ($len,0x60);
+ &jz (&label("ecb_ret"));
+
+&set_label("ecb_enc_tail");
+ &movups ($inout0,&QWP(0,$inp));
+ &cmp ($len,0x20);
+ &jb (&label("ecb_enc_one"));
+ &movups ($inout1,&QWP(0x10,$inp));
+ &je (&label("ecb_enc_two"));
+ &movups ($inout2,&QWP(0x20,$inp));
+ &cmp ($len,0x40);
+ &jb (&label("ecb_enc_three"));
+ &movups ($inout3,&QWP(0x30,$inp));
+ &je (&label("ecb_enc_four"));
+ &movups ($inout4,&QWP(0x40,$inp));
+ &xorps ($inout5,$inout5);
+ &call ("_aesni_encrypt6");
+ &movups (&QWP(0,$out),$inout0);
+ &movups (&QWP(0x10,$out),$inout1);
+ &movups (&QWP(0x20,$out),$inout2);
+ &movups (&QWP(0x30,$out),$inout3);
+ &movups (&QWP(0x40,$out),$inout4);
+ jmp (&label("ecb_ret"));
+
+&set_label("ecb_enc_one",16);
+ if ($inline)
+ { &aesni_inline_generate1("enc"); }
+ else
+ { &call ("_aesni_encrypt1"); }
+ &movups (&QWP(0,$out),$inout0);
+ &jmp (&label("ecb_ret"));
+
+&set_label("ecb_enc_two",16);
+ &xorps ($inout2,$inout2);
+ &call ("_aesni_encrypt3");
+ &movups (&QWP(0,$out),$inout0);
+ &movups (&QWP(0x10,$out),$inout1);
+ &jmp (&label("ecb_ret"));
+
+&set_label("ecb_enc_three",16);
+ &call ("_aesni_encrypt3");
+ &movups (&QWP(0,$out),$inout0);
+ &movups (&QWP(0x10,$out),$inout1);
+ &movups (&QWP(0x20,$out),$inout2);
+ &jmp (&label("ecb_ret"));
+
+&set_label("ecb_enc_four",16);
+ &call ("_aesni_encrypt4");
+ &movups (&QWP(0,$out),$inout0);
+ &movups (&QWP(0x10,$out),$inout1);
+ &movups (&QWP(0x20,$out),$inout2);
+ &movups (&QWP(0x30,$out),$inout3);
+ &jmp (&label("ecb_ret"));
+######################################################################
+&set_label("ecb_decrypt",16);
+ &mov ($key_,$key); # backup $key
+ &mov ($rounds_,$rounds); # backup $rounds
+ &cmp ($len,0x60);
+ &jb (&label("ecb_dec_tail"));
+
+ &movdqu ($inout0,&QWP(0,$inp));
+ &movdqu ($inout1,&QWP(0x10,$inp));
+ &movdqu ($inout2,&QWP(0x20,$inp));
+ &movdqu ($inout3,&QWP(0x30,$inp));
+ &movdqu ($inout4,&QWP(0x40,$inp));
+ &movdqu ($inout5,&QWP(0x50,$inp));
+ &lea ($inp,&DWP(0x60,$inp));
+ &sub ($len,0x60);
+ &jmp (&label("ecb_dec_loop6_enter"));
+
+&set_label("ecb_dec_loop6",16);
+ &movups (&QWP(0,$out),$inout0);
+ &movdqu ($inout0,&QWP(0,$inp));
+ &movups (&QWP(0x10,$out),$inout1);
+ &movdqu ($inout1,&QWP(0x10,$inp));
+ &movups (&QWP(0x20,$out),$inout2);
+ &movdqu ($inout2,&QWP(0x20,$inp));
+ &movups (&QWP(0x30,$out),$inout3);
+ &movdqu ($inout3,&QWP(0x30,$inp));
+ &movups (&QWP(0x40,$out),$inout4);
+ &movdqu ($inout4,&QWP(0x40,$inp));
+ &movups (&QWP(0x50,$out),$inout5);
+ &lea ($out,&DWP(0x60,$out));
+ &movdqu ($inout5,&QWP(0x50,$inp));
+ &lea ($inp,&DWP(0x60,$inp));
+&set_label("ecb_dec_loop6_enter");
+
+ &call ("_aesni_decrypt6");
+
+ &mov ($key,$key_); # restore $key
+ &mov ($rounds,$rounds_); # restore $rounds
+ &sub ($len,0x60);
+ &jnc (&label("ecb_dec_loop6"));
+
+ &movups (&QWP(0,$out),$inout0);
+ &movups (&QWP(0x10,$out),$inout1);
+ &movups (&QWP(0x20,$out),$inout2);
+ &movups (&QWP(0x30,$out),$inout3);
+ &movups (&QWP(0x40,$out),$inout4);
+ &movups (&QWP(0x50,$out),$inout5);
+ &lea ($out,&DWP(0x60,$out));
+ &add ($len,0x60);
+ &jz (&label("ecb_ret"));
+
+&set_label("ecb_dec_tail");
+ &movups ($inout0,&QWP(0,$inp));
+ &cmp ($len,0x20);
+ &jb (&label("ecb_dec_one"));
+ &movups ($inout1,&QWP(0x10,$inp));
+ &je (&label("ecb_dec_two"));
+ &movups ($inout2,&QWP(0x20,$inp));
+ &cmp ($len,0x40);
+ &jb (&label("ecb_dec_three"));
+ &movups ($inout3,&QWP(0x30,$inp));
+ &je (&label("ecb_dec_four"));
+ &movups ($inout4,&QWP(0x40,$inp));
+ &xorps ($inout5,$inout5);
+ &call ("_aesni_decrypt6");
+ &movups (&QWP(0,$out),$inout0);
+ &movups (&QWP(0x10,$out),$inout1);
+ &movups (&QWP(0x20,$out),$inout2);
+ &movups (&QWP(0x30,$out),$inout3);
+ &movups (&QWP(0x40,$out),$inout4);
+ &jmp (&label("ecb_ret"));
+
+&set_label("ecb_dec_one",16);
+ if ($inline)
+ { &aesni_inline_generate1("dec"); }
+ else
+ { &call ("_aesni_decrypt1"); }
+ &movups (&QWP(0,$out),$inout0);
+ &jmp (&label("ecb_ret"));
+
+&set_label("ecb_dec_two",16);
+ &xorps ($inout2,$inout2);
+ &call ("_aesni_decrypt3");
+ &movups (&QWP(0,$out),$inout0);
+ &movups (&QWP(0x10,$out),$inout1);
+ &jmp (&label("ecb_ret"));
+
+&set_label("ecb_dec_three",16);
+ &call ("_aesni_decrypt3");
+ &movups (&QWP(0,$out),$inout0);
+ &movups (&QWP(0x10,$out),$inout1);
+ &movups (&QWP(0x20,$out),$inout2);
+ &jmp (&label("ecb_ret"));
+
+&set_label("ecb_dec_four",16);
+ &call ("_aesni_decrypt4");
+ &movups (&QWP(0,$out),$inout0);
+ &movups (&QWP(0x10,$out),$inout1);
+ &movups (&QWP(0x20,$out),$inout2);
+ &movups (&QWP(0x30,$out),$inout3);
+
+&set_label("ecb_ret");
+&function_end("aesni_ecb_encrypt");
+
+######################################################################
+# void aesni_ccm64_[en|de]crypt_blocks (const void *in, void *out,
+# size_t blocks, const AES_KEY *key,
+# const char *ivec,char *cmac);
+#
+# Handles only complete blocks, operates on 64-bit counter and
+# does not update *ivec! Nor does it finalize CMAC value
+# (see engine/eng_aesni.c for details)
+#
+{ my $cmac=$inout1;
+&function_begin("aesni_ccm64_encrypt_blocks");
+ &mov ($inp,&wparam(0));
+ &mov ($out,&wparam(1));
+ &mov ($len,&wparam(2));
+ &mov ($key,&wparam(3));
+ &mov ($rounds_,&wparam(4));
+ &mov ($rounds,&wparam(5));
+ &mov ($key_,"esp");
+ &sub ("esp",60);
+ &and ("esp",-16); # align stack
+ &mov (&DWP(48,"esp"),$key_);
+
+ &movdqu ($ivec,&QWP(0,$rounds_)); # load ivec
+ &movdqu ($cmac,&QWP(0,$rounds)); # load cmac
+ &mov ($rounds,&DWP(240,$key));
+
+ # compose byte-swap control mask for pshufb on stack
+ &mov (&DWP(0,"esp"),0x0c0d0e0f);
+ &mov (&DWP(4,"esp"),0x08090a0b);
+ &mov (&DWP(8,"esp"),0x04050607);
+ &mov (&DWP(12,"esp"),0x00010203);
+
+ # compose counter increment vector on stack
+ &mov ($rounds_,1);
+ &xor ($key_,$key_);
+ &mov (&DWP(16,"esp"),$rounds_);
+ &mov (&DWP(20,"esp"),$key_);
+ &mov (&DWP(24,"esp"),$key_);
+ &mov (&DWP(28,"esp"),$key_);
+
+ &shr ($rounds,1);
+ &lea ($key_,&DWP(0,$key));
+ &movdqa ($inout3,&QWP(0,"esp"));
+ &movdqa ($inout0,$ivec);
+ &mov ($rounds_,$rounds);
+ &pshufb ($ivec,$inout3);
+
+&set_label("ccm64_enc_outer");
+ &$movekey ($rndkey0,&QWP(0,$key_));
+ &mov ($rounds,$rounds_);
+ &movups ($in0,&QWP(0,$inp));
+
+ &xorps ($inout0,$rndkey0);
+ &$movekey ($rndkey1,&QWP(16,$key_));
+ &xorps ($rndkey0,$in0);
+ &lea ($key,&DWP(32,$key_));
+ &xorps ($cmac,$rndkey0); # cmac^=inp
+ &$movekey ($rndkey0,&QWP(0,$key));
+
+&set_label("ccm64_enc2_loop");
+ &aesenc ($inout0,$rndkey1);
+ &dec ($rounds);
+ &aesenc ($cmac,$rndkey1);
+ &$movekey ($rndkey1,&QWP(16,$key));
+ &aesenc ($inout0,$rndkey0);
+ &lea ($key,&DWP(32,$key));
+ &aesenc ($cmac,$rndkey0);
+ &$movekey ($rndkey0,&QWP(0,$key));
+ &jnz (&label("ccm64_enc2_loop"));
+ &aesenc ($inout0,$rndkey1);
+ &aesenc ($cmac,$rndkey1);
+ &paddq ($ivec,&QWP(16,"esp"));
+ &aesenclast ($inout0,$rndkey0);
+ &aesenclast ($cmac,$rndkey0);
+
+ &dec ($len);
+ &lea ($inp,&DWP(16,$inp));
+ &xorps ($in0,$inout0); # inp^=E(ivec)
+ &movdqa ($inout0,$ivec);
+ &movups (&QWP(0,$out),$in0); # save output
+ &lea ($out,&DWP(16,$out));
+ &pshufb ($inout0,$inout3);
+ &jnz (&label("ccm64_enc_outer"));
+
+ &mov ("esp",&DWP(48,"esp"));
+ &mov ($out,&wparam(5));
+ &movups (&QWP(0,$out),$cmac);
+&function_end("aesni_ccm64_encrypt_blocks");
+
+&function_begin("aesni_ccm64_decrypt_blocks");
+ &mov ($inp,&wparam(0));
+ &mov ($out,&wparam(1));
+ &mov ($len,&wparam(2));
+ &mov ($key,&wparam(3));
+ &mov ($rounds_,&wparam(4));
+ &mov ($rounds,&wparam(5));
+ &mov ($key_,"esp");
+ &sub ("esp",60);
+ &and ("esp",-16); # align stack
+ &mov (&DWP(48,"esp"),$key_);
+
+ &movdqu ($ivec,&QWP(0,$rounds_)); # load ivec
+ &movdqu ($cmac,&QWP(0,$rounds)); # load cmac
+ &mov ($rounds,&DWP(240,$key));
+
+ # compose byte-swap control mask for pshufb on stack
+ &mov (&DWP(0,"esp"),0x0c0d0e0f);
+ &mov (&DWP(4,"esp"),0x08090a0b);
+ &mov (&DWP(8,"esp"),0x04050607);
+ &mov (&DWP(12,"esp"),0x00010203);
+
+ # compose counter increment vector on stack
+ &mov ($rounds_,1);
+ &xor ($key_,$key_);
+ &mov (&DWP(16,"esp"),$rounds_);
+ &mov (&DWP(20,"esp"),$key_);
+ &mov (&DWP(24,"esp"),$key_);
+ &mov (&DWP(28,"esp"),$key_);
+
+ &movdqa ($inout3,&QWP(0,"esp")); # bswap mask
+ &movdqa ($inout0,$ivec);
+
+ &mov ($key_,$key);
+ &mov ($rounds_,$rounds);
+
+ &pshufb ($ivec,$inout3);
+ if ($inline)
+ { &aesni_inline_generate1("enc"); }
+ else
+ { &call ("_aesni_encrypt1"); }
+ &movups ($in0,&QWP(0,$inp)); # load inp
+ &paddq ($ivec,&QWP(16,"esp"));
+ &lea ($inp,&QWP(16,$inp));
+ &jmp (&label("ccm64_dec_outer"));
+
+&set_label("ccm64_dec_outer",16);
+ &xorps ($in0,$inout0); # inp ^= E(ivec)
+ &movdqa ($inout0,$ivec);
+ &mov ($rounds,$rounds_);
+ &movups (&QWP(0,$out),$in0); # save output
+ &lea ($out,&DWP(16,$out));
+ &pshufb ($inout0,$inout3);
+
+ &sub ($len,1);
+ &jz (&label("ccm64_dec_break"));
+
+ &$movekey ($rndkey0,&QWP(0,$key_));
+ &shr ($rounds,1);
+ &$movekey ($rndkey1,&QWP(16,$key_));
+ &xorps ($in0,$rndkey0);
+ &lea ($key,&DWP(32,$key_));
+ &xorps ($inout0,$rndkey0);
+ &xorps ($cmac,$in0); # cmac^=out
+ &$movekey ($rndkey0,&QWP(0,$key));
+
+&set_label("ccm64_dec2_loop");
+ &aesenc ($inout0,$rndkey1);
+ &dec ($rounds);
+ &aesenc ($cmac,$rndkey1);
+ &$movekey ($rndkey1,&QWP(16,$key));
+ &aesenc ($inout0,$rndkey0);
+ &lea ($key,&DWP(32,$key));
+ &aesenc ($cmac,$rndkey0);
+ &$movekey ($rndkey0,&QWP(0,$key));
+ &jnz (&label("ccm64_dec2_loop"));
+ &movups ($in0,&QWP(0,$inp)); # load inp
+ &paddq ($ivec,&QWP(16,"esp"));
+ &aesenc ($inout0,$rndkey1);
+ &aesenc ($cmac,$rndkey1);
+ &lea ($inp,&QWP(16,$inp));
+ &aesenclast ($inout0,$rndkey0);
+ &aesenclast ($cmac,$rndkey0);
+ &jmp (&label("ccm64_dec_outer"));
+
+&set_label("ccm64_dec_break",16);
+ &mov ($key,$key_);
+ if ($inline)
+ { &aesni_inline_generate1("enc",$cmac,$in0); }
+ else
+ { &call ("_aesni_encrypt1",$cmac); }
+
+ &mov ("esp",&DWP(48,"esp"));
+ &mov ($out,&wparam(5));
+ &movups (&QWP(0,$out),$cmac);
+&function_end("aesni_ccm64_decrypt_blocks");
+}
+
+######################################################################
+# void aesni_ctr32_encrypt_blocks (const void *in, void *out,
+# size_t blocks, const AES_KEY *key,
+# const char *ivec);
+#
+# Handles only complete blocks, operates on 32-bit counter and
+# does not update *ivec! (see engine/eng_aesni.c for details)
+#
+# stack layout:
+# 0 pshufb mask
+# 16 vector addend: 0,6,6,6
+# 32 counter-less ivec
+# 48 1st triplet of counter vector
+# 64 2nd triplet of counter vector
+# 80 saved %esp
+
+&function_begin("aesni_ctr32_encrypt_blocks");
+ &mov ($inp,&wparam(0));
+ &mov ($out,&wparam(1));
+ &mov ($len,&wparam(2));
+ &mov ($key,&wparam(3));
+ &mov ($rounds_,&wparam(4));
+ &mov ($key_,"esp");
+ &sub ("esp",88);
+ &and ("esp",-16); # align stack
+ &mov (&DWP(80,"esp"),$key_);
+
+ &cmp ($len,1);
+ &je (&label("ctr32_one_shortcut"));
+
+ &movdqu ($inout5,&QWP(0,$rounds_)); # load ivec
+
+ # compose byte-swap control mask for pshufb on stack
+ &mov (&DWP(0,"esp"),0x0c0d0e0f);
+ &mov (&DWP(4,"esp"),0x08090a0b);
+ &mov (&DWP(8,"esp"),0x04050607);
+ &mov (&DWP(12,"esp"),0x00010203);
+
+ # compose counter increment vector on stack
+ &mov ($rounds,6);
+ &xor ($key_,$key_);
+ &mov (&DWP(16,"esp"),$rounds);
+ &mov (&DWP(20,"esp"),$rounds);
+ &mov (&DWP(24,"esp"),$rounds);
+ &mov (&DWP(28,"esp"),$key_);
+
+ &pextrd ($rounds_,$inout5,3); # pull 32-bit counter
+ &pinsrd ($inout5,$key_,3); # wipe 32-bit counter
+
+ &mov ($rounds,&DWP(240,$key)); # key->rounds
+
+ # compose 2 vectors of 3x32-bit counters
+ &bswap ($rounds_);
+ &pxor ($rndkey1,$rndkey1);
+ &pxor ($rndkey0,$rndkey0);
+ &movdqa ($inout0,&QWP(0,"esp")); # load byte-swap mask
+ &pinsrd ($rndkey1,$rounds_,0);
+ &lea ($key_,&DWP(3,$rounds_));
+ &pinsrd ($rndkey0,$key_,0);
+ &inc ($rounds_);
+ &pinsrd ($rndkey1,$rounds_,1);
+ &inc ($key_);
+ &pinsrd ($rndkey0,$key_,1);
+ &inc ($rounds_);
+ &pinsrd ($rndkey1,$rounds_,2);
+ &inc ($key_);
+ &pinsrd ($rndkey0,$key_,2);
+ &movdqa (&QWP(48,"esp"),$rndkey1); # save 1st triplet
+ &pshufb ($rndkey1,$inout0); # byte swap
+ &movdqa (&QWP(64,"esp"),$rndkey0); # save 2nd triplet
+ &pshufb ($rndkey0,$inout0); # byte swap
+
+ &pshufd ($inout0,$rndkey1,3<<6); # place counter to upper dword
+ &pshufd ($inout1,$rndkey1,2<<6);
+ &cmp ($len,6);
+ &jb (&label("ctr32_tail"));
+ &movdqa (&QWP(32,"esp"),$inout5); # save counter-less ivec
+ &shr ($rounds,1);
+ &mov ($key_,$key); # backup $key
+ &mov ($rounds_,$rounds); # backup $rounds
+ &sub ($len,6);
+ &jmp (&label("ctr32_loop6"));
+
+&set_label("ctr32_loop6",16);
+ &pshufd ($inout2,$rndkey1,1<<6);
+ &movdqa ($rndkey1,&QWP(32,"esp")); # pull counter-less ivec
+ &pshufd ($inout3,$rndkey0,3<<6);
+ &por ($inout0,$rndkey1); # merge counter-less ivec
+ &pshufd ($inout4,$rndkey0,2<<6);
+ &por ($inout1,$rndkey1);
+ &pshufd ($inout5,$rndkey0,1<<6);
+ &por ($inout2,$rndkey1);
+ &por ($inout3,$rndkey1);
+ &por ($inout4,$rndkey1);
+ &por ($inout5,$rndkey1);
+
+ # inlining _aesni_encrypt6's prologue gives ~4% improvement...
+ &$movekey ($rndkey0,&QWP(0,$key_));
+ &$movekey ($rndkey1,&QWP(16,$key_));
+ &lea ($key,&DWP(32,$key_));
+ &dec ($rounds);
+ &pxor ($inout0,$rndkey0);
+ &pxor ($inout1,$rndkey0);
+ &aesenc ($inout0,$rndkey1);
+ &pxor ($inout2,$rndkey0);
+ &aesenc ($inout1,$rndkey1);
+ &pxor ($inout3,$rndkey0);
+ &aesenc ($inout2,$rndkey1);
+ &pxor ($inout4,$rndkey0);
+ &aesenc ($inout3,$rndkey1);
+ &pxor ($inout5,$rndkey0);
+ &aesenc ($inout4,$rndkey1);
+ &$movekey ($rndkey0,&QWP(0,$key));
+ &aesenc ($inout5,$rndkey1);
+
+ &call (&label("_aesni_encrypt6_enter"));
+
+ &movups ($rndkey1,&QWP(0,$inp));
+ &movups ($rndkey0,&QWP(0x10,$inp));
+ &xorps ($inout0,$rndkey1);
+ &movups ($rndkey1,&QWP(0x20,$inp));
+ &xorps ($inout1,$rndkey0);
+ &movups (&QWP(0,$out),$inout0);
+ &movdqa ($rndkey0,&QWP(16,"esp")); # load increment
+ &xorps ($inout2,$rndkey1);
+ &movdqa ($rndkey1,&QWP(48,"esp")); # load 1st triplet
+ &movups (&QWP(0x10,$out),$inout1);
+ &movups (&QWP(0x20,$out),$inout2);
+
+ &paddd ($rndkey1,$rndkey0); # 1st triplet increment
+ &paddd ($rndkey0,&QWP(64,"esp")); # 2nd triplet increment
+ &movdqa ($inout0,&QWP(0,"esp")); # load byte swap mask
+
+ &movups ($inout1,&QWP(0x30,$inp));
+ &movups ($inout2,&QWP(0x40,$inp));
+ &xorps ($inout3,$inout1);
+ &movups ($inout1,&QWP(0x50,$inp));
+ &lea ($inp,&DWP(0x60,$inp));
+ &movdqa (&QWP(48,"esp"),$rndkey1); # save 1st triplet
+ &pshufb ($rndkey1,$inout0); # byte swap
+ &xorps ($inout4,$inout2);
+ &movups (&QWP(0x30,$out),$inout3);
+ &xorps ($inout5,$inout1);
+ &movdqa (&QWP(64,"esp"),$rndkey0); # save 2nd triplet
+ &pshufb ($rndkey0,$inout0); # byte swap
+ &movups (&QWP(0x40,$out),$inout4);
+ &pshufd ($inout0,$rndkey1,3<<6);
+ &movups (&QWP(0x50,$out),$inout5);
+ &lea ($out,&DWP(0x60,$out));
+
+ &mov ($rounds,$rounds_);
+ &pshufd ($inout1,$rndkey1,2<<6);
+ &sub ($len,6);
+ &jnc (&label("ctr32_loop6"));
+
+ &add ($len,6);
+ &jz (&label("ctr32_ret"));
+ &mov ($key,$key_);
+ &lea ($rounds,&DWP(1,"",$rounds,2)); # restore $rounds
+ &movdqa ($inout5,&QWP(32,"esp")); # pull count-less ivec
+
+&set_label("ctr32_tail");
+ &por ($inout0,$inout5);
+ &cmp ($len,2);
+ &jb (&label("ctr32_one"));
+
+ &pshufd ($inout2,$rndkey1,1<<6);
+ &por ($inout1,$inout5);
+ &je (&label("ctr32_two"));
+
+ &pshufd ($inout3,$rndkey0,3<<6);
+ &por ($inout2,$inout5);
+ &cmp ($len,4);
+ &jb (&label("ctr32_three"));
+
+ &pshufd ($inout4,$rndkey0,2<<6);
+ &por ($inout3,$inout5);
+ &je (&label("ctr32_four"));
+
+ &por ($inout4,$inout5);
+ &call ("_aesni_encrypt6");
+ &movups ($rndkey1,&QWP(0,$inp));
+ &movups ($rndkey0,&QWP(0x10,$inp));
+ &xorps ($inout0,$rndkey1);
+ &movups ($rndkey1,&QWP(0x20,$inp));
+ &xorps ($inout1,$rndkey0);
+ &movups ($rndkey0,&QWP(0x30,$inp));
+ &xorps ($inout2,$rndkey1);
+ &movups ($rndkey1,&QWP(0x40,$inp));
+ &xorps ($inout3,$rndkey0);
+ &movups (&QWP(0,$out),$inout0);
+ &xorps ($inout4,$rndkey1);
+ &movups (&QWP(0x10,$out),$inout1);
+ &movups (&QWP(0x20,$out),$inout2);
+ &movups (&QWP(0x30,$out),$inout3);
+ &movups (&QWP(0x40,$out),$inout4);
+ &jmp (&label("ctr32_ret"));
+
+&set_label("ctr32_one_shortcut",16);
+ &movups ($inout0,&QWP(0,$rounds_)); # load ivec
+ &mov ($rounds,&DWP(240,$key));
+
+&set_label("ctr32_one");
+ if ($inline)
+ { &aesni_inline_generate1("enc"); }
+ else
+ { &call ("_aesni_encrypt1"); }
+ &movups ($in0,&QWP(0,$inp));
+ &xorps ($in0,$inout0);
+ &movups (&QWP(0,$out),$in0);
+ &jmp (&label("ctr32_ret"));
+
+&set_label("ctr32_two",16);
+ &call ("_aesni_encrypt3");
+ &movups ($inout3,&QWP(0,$inp));
+ &movups ($inout4,&QWP(0x10,$inp));
+ &xorps ($inout0,$inout3);
+ &xorps ($inout1,$inout4);
+ &movups (&QWP(0,$out),$inout0);
+ &movups (&QWP(0x10,$out),$inout1);
+ &jmp (&label("ctr32_ret"));
+
+&set_label("ctr32_three",16);
+ &call ("_aesni_encrypt3");
+ &movups ($inout3,&QWP(0,$inp));
+ &movups ($inout4,&QWP(0x10,$inp));
+ &xorps ($inout0,$inout3);
+ &movups ($inout5,&QWP(0x20,$inp));
+ &xorps ($inout1,$inout4);
+ &movups (&QWP(0,$out),$inout0);
+ &xorps ($inout2,$inout5);
+ &movups (&QWP(0x10,$out),$inout1);
+ &movups (&QWP(0x20,$out),$inout2);
+ &jmp (&label("ctr32_ret"));
+
+&set_label("ctr32_four",16);
+ &call ("_aesni_encrypt4");
+ &movups ($inout4,&QWP(0,$inp));
+ &movups ($inout5,&QWP(0x10,$inp));
+ &movups ($rndkey1,&QWP(0x20,$inp));
+ &xorps ($inout0,$inout4);
+ &movups ($rndkey0,&QWP(0x30,$inp));
+ &xorps ($inout1,$inout5);
+ &movups (&QWP(0,$out),$inout0);
+ &xorps ($inout2,$rndkey1);
+ &movups (&QWP(0x10,$out),$inout1);
+ &xorps ($inout3,$rndkey0);
+ &movups (&QWP(0x20,$out),$inout2);
+ &movups (&QWP(0x30,$out),$inout3);
+
+&set_label("ctr32_ret");
+ &mov ("esp",&DWP(80,"esp"));
+&function_end("aesni_ctr32_encrypt_blocks");
+
+######################################################################
+# void aesni_xts_[en|de]crypt(const char *inp,char *out,size_t len,
+# const AES_KEY *key1, const AES_KEY *key2
+# const unsigned char iv[16]);
+#
+{ my ($tweak,$twtmp,$twres,$twmask)=($rndkey1,$rndkey0,$inout0,$inout1);
+
+&function_begin("aesni_xts_encrypt");
+ &mov ($key,&wparam(4)); # key2
+ &mov ($inp,&wparam(5)); # clear-text tweak
+
+ &mov ($rounds,&DWP(240,$key)); # key2->rounds
+ &movups ($inout0,&QWP(0,$inp));
+ if ($inline)
+ { &aesni_inline_generate1("enc"); }
+ else
+ { &call ("_aesni_encrypt1"); }
+
+ &mov ($inp,&wparam(0));
+ &mov ($out,&wparam(1));
+ &mov ($len,&wparam(2));
+ &mov ($key,&wparam(3)); # key1
+
+ &mov ($key_,"esp");
+ &sub ("esp",16*7+8);
+ &mov ($rounds,&DWP(240,$key)); # key1->rounds
+ &and ("esp",-16); # align stack
+
+ &mov (&DWP(16*6+0,"esp"),0x87); # compose the magic constant
+ &mov (&DWP(16*6+4,"esp"),0);
+ &mov (&DWP(16*6+8,"esp"),1);
+ &mov (&DWP(16*6+12,"esp"),0);
+ &mov (&DWP(16*7+0,"esp"),$len); # save original $len
+ &mov (&DWP(16*7+4,"esp"),$key_); # save original %esp
+
+ &movdqa ($tweak,$inout0);
+ &pxor ($twtmp,$twtmp);
+ &movdqa ($twmask,&QWP(6*16,"esp")); # 0x0...010...87
+ &pcmpgtd($twtmp,$tweak); # broadcast upper bits
+
+ &and ($len,-16);
+ &mov ($key_,$key); # backup $key
+ &mov ($rounds_,$rounds); # backup $rounds
+ &sub ($len,16*6);
+ &jc (&label("xts_enc_short"));
+
+ &shr ($rounds,1);
+ &mov ($rounds_,$rounds);
+ &jmp (&label("xts_enc_loop6"));
+
+&set_label("xts_enc_loop6",16);
+ for ($i=0;$i<4;$i++) {
+ &pshufd ($twres,$twtmp,0x13);
+ &pxor ($twtmp,$twtmp);
+ &movdqa (&QWP(16*$i,"esp"),$tweak);
+ &paddq ($tweak,$tweak); # &psllq($tweak,1);
+ &pand ($twres,$twmask); # isolate carry and residue
+ &pcmpgtd ($twtmp,$tweak); # broadcast upper bits
+ &pxor ($tweak,$twres);
+ }
+ &pshufd ($inout5,$twtmp,0x13);
+ &movdqa (&QWP(16*$i++,"esp"),$tweak);
+ &paddq ($tweak,$tweak); # &psllq($tweak,1);
+ &$movekey ($rndkey0,&QWP(0,$key_));
+ &pand ($inout5,$twmask); # isolate carry and residue
+ &movups ($inout0,&QWP(0,$inp)); # load input
+ &pxor ($inout5,$tweak);
+
+ # inline _aesni_encrypt6 prologue and flip xor with tweak and key[0]
+ &movdqu ($inout1,&QWP(16*1,$inp));
+ &xorps ($inout0,$rndkey0); # input^=rndkey[0]
+ &movdqu ($inout2,&QWP(16*2,$inp));
+ &pxor ($inout1,$rndkey0);
+ &movdqu ($inout3,&QWP(16*3,$inp));
+ &pxor ($inout2,$rndkey0);
+ &movdqu ($inout4,&QWP(16*4,$inp));
+ &pxor ($inout3,$rndkey0);
+ &movdqu ($rndkey1,&QWP(16*5,$inp));
+ &pxor ($inout4,$rndkey0);
+ &lea ($inp,&DWP(16*6,$inp));
+ &pxor ($inout0,&QWP(16*0,"esp")); # input^=tweak
+ &movdqa (&QWP(16*$i,"esp"),$inout5); # save last tweak
+ &pxor ($inout5,$rndkey1);
+
+ &$movekey ($rndkey1,&QWP(16,$key_));
+ &lea ($key,&DWP(32,$key_));
+ &pxor ($inout1,&QWP(16*1,"esp"));
+ &aesenc ($inout0,$rndkey1);
+ &pxor ($inout2,&QWP(16*2,"esp"));
+ &aesenc ($inout1,$rndkey1);
+ &pxor ($inout3,&QWP(16*3,"esp"));
+ &dec ($rounds);
+ &aesenc ($inout2,$rndkey1);
+ &pxor ($inout4,&QWP(16*4,"esp"));
+ &aesenc ($inout3,$rndkey1);
+ &pxor ($inout5,$rndkey0);
+ &aesenc ($inout4,$rndkey1);
+ &$movekey ($rndkey0,&QWP(0,$key));
+ &aesenc ($inout5,$rndkey1);
+ &call (&label("_aesni_encrypt6_enter"));
+
+ &movdqa ($tweak,&QWP(16*5,"esp")); # last tweak
+ &pxor ($twtmp,$twtmp);
+ &xorps ($inout0,&QWP(16*0,"esp")); # output^=tweak
+ &pcmpgtd ($twtmp,$tweak); # broadcast upper bits
+ &xorps ($inout1,&QWP(16*1,"esp"));
+ &movups (&QWP(16*0,$out),$inout0); # write output
+ &xorps ($inout2,&QWP(16*2,"esp"));
+ &movups (&QWP(16*1,$out),$inout1);
+ &xorps ($inout3,&QWP(16*3,"esp"));
+ &movups (&QWP(16*2,$out),$inout2);
+ &xorps ($inout4,&QWP(16*4,"esp"));
+ &movups (&QWP(16*3,$out),$inout3);
+ &xorps ($inout5,$tweak);
+ &movups (&QWP(16*4,$out),$inout4);
+ &pshufd ($twres,$twtmp,0x13);
+ &movups (&QWP(16*5,$out),$inout5);
+ &lea ($out,&DWP(16*6,$out));
+ &movdqa ($twmask,&QWP(16*6,"esp")); # 0x0...010...87
+
+ &pxor ($twtmp,$twtmp);
+ &paddq ($tweak,$tweak); # &psllq($tweak,1);
+ &pand ($twres,$twmask); # isolate carry and residue
+ &pcmpgtd($twtmp,$tweak); # broadcast upper bits
+ &mov ($rounds,$rounds_); # restore $rounds
+ &pxor ($tweak,$twres);
+
+ &sub ($len,16*6);
+ &jnc (&label("xts_enc_loop6"));
+
+ &lea ($rounds,&DWP(1,"",$rounds,2)); # restore $rounds
+ &mov ($key,$key_); # restore $key
+ &mov ($rounds_,$rounds);
+
+&set_label("xts_enc_short");
+ &add ($len,16*6);
+ &jz (&label("xts_enc_done6x"));
+
+ &movdqa ($inout3,$tweak); # put aside previous tweak
+ &cmp ($len,0x20);
+ &jb (&label("xts_enc_one"));
+
+ &pshufd ($twres,$twtmp,0x13);
+ &pxor ($twtmp,$twtmp);
+ &paddq ($tweak,$tweak); # &psllq($tweak,1);
+ &pand ($twres,$twmask); # isolate carry and residue
+ &pcmpgtd($twtmp,$tweak); # broadcast upper bits
+ &pxor ($tweak,$twres);
+ &je (&label("xts_enc_two"));
+
+ &pshufd ($twres,$twtmp,0x13);
+ &pxor ($twtmp,$twtmp);
+ &movdqa ($inout4,$tweak); # put aside previous tweak
+ &paddq ($tweak,$tweak); # &psllq($tweak,1);
+ &pand ($twres,$twmask); # isolate carry and residue
+ &pcmpgtd($twtmp,$tweak); # broadcast upper bits
+ &pxor ($tweak,$twres);
+ &cmp ($len,0x40);
+ &jb (&label("xts_enc_three"));
+
+ &pshufd ($twres,$twtmp,0x13);
+ &pxor ($twtmp,$twtmp);
+ &movdqa ($inout5,$tweak); # put aside previous tweak
+ &paddq ($tweak,$tweak); # &psllq($tweak,1);
+ &pand ($twres,$twmask); # isolate carry and residue
+ &pcmpgtd($twtmp,$tweak); # broadcast upper bits
+ &pxor ($tweak,$twres);
+ &movdqa (&QWP(16*0,"esp"),$inout3);
+ &movdqa (&QWP(16*1,"esp"),$inout4);
+ &je (&label("xts_enc_four"));
+
+ &movdqa (&QWP(16*2,"esp"),$inout5);
+ &pshufd ($inout5,$twtmp,0x13);
+ &movdqa (&QWP(16*3,"esp"),$tweak);
+ &paddq ($tweak,$tweak); # &psllq($inout0,1);
+ &pand ($inout5,$twmask); # isolate carry and residue
+ &pxor ($inout5,$tweak);
+
+ &movdqu ($inout0,&QWP(16*0,$inp)); # load input
+ &movdqu ($inout1,&QWP(16*1,$inp));
+ &movdqu ($inout2,&QWP(16*2,$inp));
+ &pxor ($inout0,&QWP(16*0,"esp")); # input^=tweak
+ &movdqu ($inout3,&QWP(16*3,$inp));
+ &pxor ($inout1,&QWP(16*1,"esp"));
+ &movdqu ($inout4,&QWP(16*4,$inp));
+ &pxor ($inout2,&QWP(16*2,"esp"));
+ &lea ($inp,&DWP(16*5,$inp));
+ &pxor ($inout3,&QWP(16*3,"esp"));
+ &movdqa (&QWP(16*4,"esp"),$inout5); # save last tweak
+ &pxor ($inout4,$inout5);
+
+ &call ("_aesni_encrypt6");
+
+ &movaps ($tweak,&QWP(16*4,"esp")); # last tweak
+ &xorps ($inout0,&QWP(16*0,"esp")); # output^=tweak
+ &xorps ($inout1,&QWP(16*1,"esp"));
+ &xorps ($inout2,&QWP(16*2,"esp"));
+ &movups (&QWP(16*0,$out),$inout0); # write output
+ &xorps ($inout3,&QWP(16*3,"esp"));
+ &movups (&QWP(16*1,$out),$inout1);
+ &xorps ($inout4,$tweak);
+ &movups (&QWP(16*2,$out),$inout2);
+ &movups (&QWP(16*3,$out),$inout3);
+ &movups (&QWP(16*4,$out),$inout4);
+ &lea ($out,&DWP(16*5,$out));
+ &jmp (&label("xts_enc_done"));
+
+&set_label("xts_enc_one",16);
+ &movups ($inout0,&QWP(16*0,$inp)); # load input
+ &lea ($inp,&DWP(16*1,$inp));
+ &xorps ($inout0,$inout3); # input^=tweak
+ if ($inline)
+ { &aesni_inline_generate1("enc"); }
+ else
+ { &call ("_aesni_encrypt1"); }
+ &xorps ($inout0,$inout3); # output^=tweak
+ &movups (&QWP(16*0,$out),$inout0); # write output
+ &lea ($out,&DWP(16*1,$out));
+
+ &movdqa ($tweak,$inout3); # last tweak
+ &jmp (&label("xts_enc_done"));
+
+&set_label("xts_enc_two",16);
+ &movaps ($inout4,$tweak); # put aside last tweak
+
+ &movups ($inout0,&QWP(16*0,$inp)); # load input
+ &movups ($inout1,&QWP(16*1,$inp));
+ &lea ($inp,&DWP(16*2,$inp));
+ &xorps ($inout0,$inout3); # input^=tweak
+ &xorps ($inout1,$inout4);
+ &xorps ($inout2,$inout2);
+
+ &call ("_aesni_encrypt3");
+
+ &xorps ($inout0,$inout3); # output^=tweak
+ &xorps ($inout1,$inout4);
+ &movups (&QWP(16*0,$out),$inout0); # write output
+ &movups (&QWP(16*1,$out),$inout1);
+ &lea ($out,&DWP(16*2,$out));
+
+ &movdqa ($tweak,$inout4); # last tweak
+ &jmp (&label("xts_enc_done"));
+
+&set_label("xts_enc_three",16);
+ &movaps ($inout5,$tweak); # put aside last tweak
+ &movups ($inout0,&QWP(16*0,$inp)); # load input
+ &movups ($inout1,&QWP(16*1,$inp));
+ &movups ($inout2,&QWP(16*2,$inp));
+ &lea ($inp,&DWP(16*3,$inp));
+ &xorps ($inout0,$inout3); # input^=tweak
+ &xorps ($inout1,$inout4);
+ &xorps ($inout2,$inout5);
+
+ &call ("_aesni_encrypt3");
+
+ &xorps ($inout0,$inout3); # output^=tweak
+ &xorps ($inout1,$inout4);
+ &xorps ($inout2,$inout5);
+ &movups (&QWP(16*0,$out),$inout0); # write output
+ &movups (&QWP(16*1,$out),$inout1);
+ &movups (&QWP(16*2,$out),$inout2);
+ &lea ($out,&DWP(16*3,$out));
+
+ &movdqa ($tweak,$inout5); # last tweak
+ &jmp (&label("xts_enc_done"));
+
+&set_label("xts_enc_four",16);
+ &movaps ($inout4,$tweak); # put aside last tweak
+
+ &movups ($inout0,&QWP(16*0,$inp)); # load input
+ &movups ($inout1,&QWP(16*1,$inp));
+ &movups ($inout2,&QWP(16*2,$inp));
+ &xorps ($inout0,&QWP(16*0,"esp")); # input^=tweak
+ &movups ($inout3,&QWP(16*3,$inp));
+ &lea ($inp,&DWP(16*4,$inp));
+ &xorps ($inout1,&QWP(16*1,"esp"));
+ &xorps ($inout2,$inout5);
+ &xorps ($inout3,$inout4);
+
+ &call ("_aesni_encrypt4");
+
+ &xorps ($inout0,&QWP(16*0,"esp")); # output^=tweak
+ &xorps ($inout1,&QWP(16*1,"esp"));
+ &xorps ($inout2,$inout5);
+ &movups (&QWP(16*0,$out),$inout0); # write output
+ &xorps ($inout3,$inout4);
+ &movups (&QWP(16*1,$out),$inout1);
+ &movups (&QWP(16*2,$out),$inout2);
+ &movups (&QWP(16*3,$out),$inout3);
+ &lea ($out,&DWP(16*4,$out));
+
+ &movdqa ($tweak,$inout4); # last tweak
+ &jmp (&label("xts_enc_done"));
+
+&set_label("xts_enc_done6x",16); # $tweak is pre-calculated
+ &mov ($len,&DWP(16*7+0,"esp")); # restore original $len
+ &and ($len,15);
+ &jz (&label("xts_enc_ret"));
+ &movdqa ($inout3,$tweak);
+ &mov (&DWP(16*7+0,"esp"),$len); # save $len%16
+ &jmp (&label("xts_enc_steal"));
+
+&set_label("xts_enc_done",16);
+ &mov ($len,&DWP(16*7+0,"esp")); # restore original $len
+ &pxor ($twtmp,$twtmp);
+ &and ($len,15);
+ &jz (&label("xts_enc_ret"));
+
+ &pcmpgtd($twtmp,$tweak); # broadcast upper bits
+ &mov (&DWP(16*7+0,"esp"),$len); # save $len%16
+ &pshufd ($inout3,$twtmp,0x13);
+ &paddq ($tweak,$tweak); # &psllq($tweak,1);
+ &pand ($inout3,&QWP(16*6,"esp")); # isolate carry and residue
+ &pxor ($inout3,$tweak);
+
+&set_label("xts_enc_steal");
+ &movz ($rounds,&BP(0,$inp));
+ &movz ($key,&BP(-16,$out));
+ &lea ($inp,&DWP(1,$inp));
+ &mov (&BP(-16,$out),&LB($rounds));
+ &mov (&BP(0,$out),&LB($key));
+ &lea ($out,&DWP(1,$out));
+ &sub ($len,1);
+ &jnz (&label("xts_enc_steal"));
+
+ &sub ($out,&DWP(16*7+0,"esp")); # rewind $out
+ &mov ($key,$key_); # restore $key
+ &mov ($rounds,$rounds_); # restore $rounds
+
+ &movups ($inout0,&QWP(-16,$out)); # load input
+ &xorps ($inout0,$inout3); # input^=tweak
+ if ($inline)
+ { &aesni_inline_generate1("enc"); }
+ else
+ { &call ("_aesni_encrypt1"); }
+ &xorps ($inout0,$inout3); # output^=tweak
+ &movups (&QWP(-16,$out),$inout0); # write output
+
+&set_label("xts_enc_ret");
+ &mov ("esp",&DWP(16*7+4,"esp")); # restore %esp
+&function_end("aesni_xts_encrypt");
+
+&function_begin("aesni_xts_decrypt");
+ &mov ($key,&wparam(4)); # key2
+ &mov ($inp,&wparam(5)); # clear-text tweak
+
+ &mov ($rounds,&DWP(240,$key)); # key2->rounds
+ &movups ($inout0,&QWP(0,$inp));
+ if ($inline)
+ { &aesni_inline_generate1("enc"); }
+ else
+ { &call ("_aesni_encrypt1"); }
+
+ &mov ($inp,&wparam(0));
+ &mov ($out,&wparam(1));
+ &mov ($len,&wparam(2));
+ &mov ($key,&wparam(3)); # key1
+
+ &mov ($key_,"esp");
+ &sub ("esp",16*7+8);
+ &and ("esp",-16); # align stack
+
+ &xor ($rounds_,$rounds_); # if(len%16) len-=16;
+ &test ($len,15);
+ &setnz (&LB($rounds_));
+ &shl ($rounds_,4);
+ &sub ($len,$rounds_);
+
+ &mov (&DWP(16*6+0,"esp"),0x87); # compose the magic constant
+ &mov (&DWP(16*6+4,"esp"),0);
+ &mov (&DWP(16*6+8,"esp"),1);
+ &mov (&DWP(16*6+12,"esp"),0);
+ &mov (&DWP(16*7+0,"esp"),$len); # save original $len
+ &mov (&DWP(16*7+4,"esp"),$key_); # save original %esp
+
+ &mov ($rounds,&DWP(240,$key)); # key1->rounds
+ &mov ($key_,$key); # backup $key
+ &mov ($rounds_,$rounds); # backup $rounds
+
+ &movdqa ($tweak,$inout0);
+ &pxor ($twtmp,$twtmp);
+ &movdqa ($twmask,&QWP(6*16,"esp")); # 0x0...010...87
+ &pcmpgtd($twtmp,$tweak); # broadcast upper bits
+
+ &and ($len,-16);
+ &sub ($len,16*6);
+ &jc (&label("xts_dec_short"));
+
+ &shr ($rounds,1);
+ &mov ($rounds_,$rounds);
+ &jmp (&label("xts_dec_loop6"));
+
+&set_label("xts_dec_loop6",16);
+ for ($i=0;$i<4;$i++) {
+ &pshufd ($twres,$twtmp,0x13);
+ &pxor ($twtmp,$twtmp);
+ &movdqa (&QWP(16*$i,"esp"),$tweak);
+ &paddq ($tweak,$tweak); # &psllq($tweak,1);
+ &pand ($twres,$twmask); # isolate carry and residue
+ &pcmpgtd ($twtmp,$tweak); # broadcast upper bits
+ &pxor ($tweak,$twres);
+ }
+ &pshufd ($inout5,$twtmp,0x13);
+ &movdqa (&QWP(16*$i++,"esp"),$tweak);
+ &paddq ($tweak,$tweak); # &psllq($tweak,1);
+ &$movekey ($rndkey0,&QWP(0,$key_));
+ &pand ($inout5,$twmask); # isolate carry and residue
+ &movups ($inout0,&QWP(0,$inp)); # load input
+ &pxor ($inout5,$tweak);
+
+ # inline _aesni_encrypt6 prologue and flip xor with tweak and key[0]
+ &movdqu ($inout1,&QWP(16*1,$inp));
+ &xorps ($inout0,$rndkey0); # input^=rndkey[0]
+ &movdqu ($inout2,&QWP(16*2,$inp));
+ &pxor ($inout1,$rndkey0);
+ &movdqu ($inout3,&QWP(16*3,$inp));
+ &pxor ($inout2,$rndkey0);
+ &movdqu ($inout4,&QWP(16*4,$inp));
+ &pxor ($inout3,$rndkey0);
+ &movdqu ($rndkey1,&QWP(16*5,$inp));
+ &pxor ($inout4,$rndkey0);
+ &lea ($inp,&DWP(16*6,$inp));
+ &pxor ($inout0,&QWP(16*0,"esp")); # input^=tweak
+ &movdqa (&QWP(16*$i,"esp"),$inout5); # save last tweak
+ &pxor ($inout5,$rndkey1);
+
+ &$movekey ($rndkey1,&QWP(16,$key_));
+ &lea ($key,&DWP(32,$key_));
+ &pxor ($inout1,&QWP(16*1,"esp"));
+ &aesdec ($inout0,$rndkey1);
+ &pxor ($inout2,&QWP(16*2,"esp"));
+ &aesdec ($inout1,$rndkey1);
+ &pxor ($inout3,&QWP(16*3,"esp"));
+ &dec ($rounds);
+ &aesdec ($inout2,$rndkey1);
+ &pxor ($inout4,&QWP(16*4,"esp"));
+ &aesdec ($inout3,$rndkey1);
+ &pxor ($inout5,$rndkey0);
+ &aesdec ($inout4,$rndkey1);
+ &$movekey ($rndkey0,&QWP(0,$key));
+ &aesdec ($inout5,$rndkey1);
+ &call (&label("_aesni_decrypt6_enter"));
+
+ &movdqa ($tweak,&QWP(16*5,"esp")); # last tweak
+ &pxor ($twtmp,$twtmp);
+ &xorps ($inout0,&QWP(16*0,"esp")); # output^=tweak
+ &pcmpgtd ($twtmp,$tweak); # broadcast upper bits
+ &xorps ($inout1,&QWP(16*1,"esp"));
+ &movups (&QWP(16*0,$out),$inout0); # write output
+ &xorps ($inout2,&QWP(16*2,"esp"));
+ &movups (&QWP(16*1,$out),$inout1);
+ &xorps ($inout3,&QWP(16*3,"esp"));
+ &movups (&QWP(16*2,$out),$inout2);
+ &xorps ($inout4,&QWP(16*4,"esp"));
+ &movups (&QWP(16*3,$out),$inout3);
+ &xorps ($inout5,$tweak);
+ &movups (&QWP(16*4,$out),$inout4);
+ &pshufd ($twres,$twtmp,0x13);
+ &movups (&QWP(16*5,$out),$inout5);
+ &lea ($out,&DWP(16*6,$out));
+ &movdqa ($twmask,&QWP(16*6,"esp")); # 0x0...010...87
+
+ &pxor ($twtmp,$twtmp);
+ &paddq ($tweak,$tweak); # &psllq($tweak,1);
+ &pand ($twres,$twmask); # isolate carry and residue
+ &pcmpgtd($twtmp,$tweak); # broadcast upper bits
+ &mov ($rounds,$rounds_); # restore $rounds
+ &pxor ($tweak,$twres);
+
+ &sub ($len,16*6);
+ &jnc (&label("xts_dec_loop6"));
+
+ &lea ($rounds,&DWP(1,"",$rounds,2)); # restore $rounds
+ &mov ($key,$key_); # restore $key
+ &mov ($rounds_,$rounds);
+
+&set_label("xts_dec_short");
+ &add ($len,16*6);
+ &jz (&label("xts_dec_done6x"));
+
+ &movdqa ($inout3,$tweak); # put aside previous tweak
+ &cmp ($len,0x20);
+ &jb (&label("xts_dec_one"));
+
+ &pshufd ($twres,$twtmp,0x13);
+ &pxor ($twtmp,$twtmp);
+ &paddq ($tweak,$tweak); # &psllq($tweak,1);
+ &pand ($twres,$twmask); # isolate carry and residue
+ &pcmpgtd($twtmp,$tweak); # broadcast upper bits
+ &pxor ($tweak,$twres);
+ &je (&label("xts_dec_two"));
+
+ &pshufd ($twres,$twtmp,0x13);
+ &pxor ($twtmp,$twtmp);
+ &movdqa ($inout4,$tweak); # put aside previous tweak
+ &paddq ($tweak,$tweak); # &psllq($tweak,1);
+ &pand ($twres,$twmask); # isolate carry and residue
+ &pcmpgtd($twtmp,$tweak); # broadcast upper bits
+ &pxor ($tweak,$twres);
+ &cmp ($len,0x40);
+ &jb (&label("xts_dec_three"));
+
+ &pshufd ($twres,$twtmp,0x13);
+ &pxor ($twtmp,$twtmp);
+ &movdqa ($inout5,$tweak); # put aside previous tweak
+ &paddq ($tweak,$tweak); # &psllq($tweak,1);
+ &pand ($twres,$twmask); # isolate carry and residue
+ &pcmpgtd($twtmp,$tweak); # broadcast upper bits
+ &pxor ($tweak,$twres);
+ &movdqa (&QWP(16*0,"esp"),$inout3);
+ &movdqa (&QWP(16*1,"esp"),$inout4);
+ &je (&label("xts_dec_four"));
+
+ &movdqa (&QWP(16*2,"esp"),$inout5);
+ &pshufd ($inout5,$twtmp,0x13);
+ &movdqa (&QWP(16*3,"esp"),$tweak);
+ &paddq ($tweak,$tweak); # &psllq($inout0,1);
+ &pand ($inout5,$twmask); # isolate carry and residue
+ &pxor ($inout5,$tweak);
+
+ &movdqu ($inout0,&QWP(16*0,$inp)); # load input
+ &movdqu ($inout1,&QWP(16*1,$inp));
+ &movdqu ($inout2,&QWP(16*2,$inp));
+ &pxor ($inout0,&QWP(16*0,"esp")); # input^=tweak
+ &movdqu ($inout3,&QWP(16*3,$inp));
+ &pxor ($inout1,&QWP(16*1,"esp"));
+ &movdqu ($inout4,&QWP(16*4,$inp));
+ &pxor ($inout2,&QWP(16*2,"esp"));
+ &lea ($inp,&DWP(16*5,$inp));
+ &pxor ($inout3,&QWP(16*3,"esp"));
+ &movdqa (&QWP(16*4,"esp"),$inout5); # save last tweak
+ &pxor ($inout4,$inout5);
+
+ &call ("_aesni_decrypt6");
+
+ &movaps ($tweak,&QWP(16*4,"esp")); # last tweak
+ &xorps ($inout0,&QWP(16*0,"esp")); # output^=tweak
+ &xorps ($inout1,&QWP(16*1,"esp"));
+ &xorps ($inout2,&QWP(16*2,"esp"));
+ &movups (&QWP(16*0,$out),$inout0); # write output
+ &xorps ($inout3,&QWP(16*3,"esp"));
+ &movups (&QWP(16*1,$out),$inout1);
+ &xorps ($inout4,$tweak);
+ &movups (&QWP(16*2,$out),$inout2);
+ &movups (&QWP(16*3,$out),$inout3);
+ &movups (&QWP(16*4,$out),$inout4);
+ &lea ($out,&DWP(16*5,$out));
+ &jmp (&label("xts_dec_done"));
+
+&set_label("xts_dec_one",16);
+ &movups ($inout0,&QWP(16*0,$inp)); # load input
+ &lea ($inp,&DWP(16*1,$inp));
+ &xorps ($inout0,$inout3); # input^=tweak
+ if ($inline)
+ { &aesni_inline_generate1("dec"); }
+ else
+ { &call ("_aesni_decrypt1"); }
+ &xorps ($inout0,$inout3); # output^=tweak
+ &movups (&QWP(16*0,$out),$inout0); # write output
+ &lea ($out,&DWP(16*1,$out));
+
+ &movdqa ($tweak,$inout3); # last tweak
+ &jmp (&label("xts_dec_done"));
+
+&set_label("xts_dec_two",16);
+ &movaps ($inout4,$tweak); # put aside last tweak
+
+ &movups ($inout0,&QWP(16*0,$inp)); # load input
+ &movups ($inout1,&QWP(16*1,$inp));
+ &lea ($inp,&DWP(16*2,$inp));
+ &xorps ($inout0,$inout3); # input^=tweak
+ &xorps ($inout1,$inout4);
+
+ &call ("_aesni_decrypt3");
+
+ &xorps ($inout0,$inout3); # output^=tweak
+ &xorps ($inout1,$inout4);
+ &movups (&QWP(16*0,$out),$inout0); # write output
+ &movups (&QWP(16*1,$out),$inout1);
+ &lea ($out,&DWP(16*2,$out));
+
+ &movdqa ($tweak,$inout4); # last tweak
+ &jmp (&label("xts_dec_done"));
+
+&set_label("xts_dec_three",16);
+ &movaps ($inout5,$tweak); # put aside last tweak
+ &movups ($inout0,&QWP(16*0,$inp)); # load input
+ &movups ($inout1,&QWP(16*1,$inp));
+ &movups ($inout2,&QWP(16*2,$inp));
+ &lea ($inp,&DWP(16*3,$inp));
+ &xorps ($inout0,$inout3); # input^=tweak
+ &xorps ($inout1,$inout4);
+ &xorps ($inout2,$inout5);
+
+ &call ("_aesni_decrypt3");
+
+ &xorps ($inout0,$inout3); # output^=tweak
+ &xorps ($inout1,$inout4);
+ &xorps ($inout2,$inout5);
+ &movups (&QWP(16*0,$out),$inout0); # write output
+ &movups (&QWP(16*1,$out),$inout1);
+ &movups (&QWP(16*2,$out),$inout2);
+ &lea ($out,&DWP(16*3,$out));
+
+ &movdqa ($tweak,$inout5); # last tweak
+ &jmp (&label("xts_dec_done"));
+
+&set_label("xts_dec_four",16);
+ &movaps ($inout4,$tweak); # put aside last tweak
+
+ &movups ($inout0,&QWP(16*0,$inp)); # load input
+ &movups ($inout1,&QWP(16*1,$inp));
+ &movups ($inout2,&QWP(16*2,$inp));
+ &xorps ($inout0,&QWP(16*0,"esp")); # input^=tweak
+ &movups ($inout3,&QWP(16*3,$inp));
+ &lea ($inp,&DWP(16*4,$inp));
+ &xorps ($inout1,&QWP(16*1,"esp"));
+ &xorps ($inout2,$inout5);
+ &xorps ($inout3,$inout4);
+
+ &call ("_aesni_decrypt4");
+
+ &xorps ($inout0,&QWP(16*0,"esp")); # output^=tweak
+ &xorps ($inout1,&QWP(16*1,"esp"));
+ &xorps ($inout2,$inout5);
+ &movups (&QWP(16*0,$out),$inout0); # write output
+ &xorps ($inout3,$inout4);
+ &movups (&QWP(16*1,$out),$inout1);
+ &movups (&QWP(16*2,$out),$inout2);
+ &movups (&QWP(16*3,$out),$inout3);
+ &lea ($out,&DWP(16*4,$out));
+
+ &movdqa ($tweak,$inout4); # last tweak
+ &jmp (&label("xts_dec_done"));
+
+&set_label("xts_dec_done6x",16); # $tweak is pre-calculated
+ &mov ($len,&DWP(16*7+0,"esp")); # restore original $len
+ &and ($len,15);
+ &jz (&label("xts_dec_ret"));
+ &mov (&DWP(16*7+0,"esp"),$len); # save $len%16
+ &jmp (&label("xts_dec_only_one_more"));
+
+&set_label("xts_dec_done",16);
+ &mov ($len,&DWP(16*7+0,"esp")); # restore original $len
+ &pxor ($twtmp,$twtmp);
+ &and ($len,15);
+ &jz (&label("xts_dec_ret"));
+
+ &pcmpgtd($twtmp,$tweak); # broadcast upper bits
+ &mov (&DWP(16*7+0,"esp"),$len); # save $len%16
+ &pshufd ($twres,$twtmp,0x13);
+ &pxor ($twtmp,$twtmp);
+ &movdqa ($twmask,&QWP(16*6,"esp"));
+ &paddq ($tweak,$tweak); # &psllq($tweak,1);
+ &pand ($twres,$twmask); # isolate carry and residue
+ &pcmpgtd($twtmp,$tweak); # broadcast upper bits
+ &pxor ($tweak,$twres);
+
+&set_label("xts_dec_only_one_more");
+ &pshufd ($inout3,$twtmp,0x13);
+ &movdqa ($inout4,$tweak); # put aside previous tweak
+ &paddq ($tweak,$tweak); # &psllq($tweak,1);
+ &pand ($inout3,$twmask); # isolate carry and residue
+ &pxor ($inout3,$tweak);
+
+ &mov ($key,$key_); # restore $key
+ &mov ($rounds,$rounds_); # restore $rounds
+
+ &movups ($inout0,&QWP(0,$inp)); # load input
+ &xorps ($inout0,$inout3); # input^=tweak
+ if ($inline)
+ { &aesni_inline_generate1("dec"); }
+ else
+ { &call ("_aesni_decrypt1"); }
+ &xorps ($inout0,$inout3); # output^=tweak
+ &movups (&QWP(0,$out),$inout0); # write output
+
+&set_label("xts_dec_steal");
+ &movz ($rounds,&BP(16,$inp));
+ &movz ($key,&BP(0,$out));
+ &lea ($inp,&DWP(1,$inp));
+ &mov (&BP(0,$out),&LB($rounds));
+ &mov (&BP(16,$out),&LB($key));
+ &lea ($out,&DWP(1,$out));
+ &sub ($len,1);
+ &jnz (&label("xts_dec_steal"));
+
+ &sub ($out,&DWP(16*7+0,"esp")); # rewind $out
+ &mov ($key,$key_); # restore $key
+ &mov ($rounds,$rounds_); # restore $rounds
+
+ &movups ($inout0,&QWP(0,$out)); # load input
+ &xorps ($inout0,$inout4); # input^=tweak
+ if ($inline)
+ { &aesni_inline_generate1("dec"); }
+ else
+ { &call ("_aesni_decrypt1"); }
+ &xorps ($inout0,$inout4); # output^=tweak
+ &movups (&QWP(0,$out),$inout0); # write output
+
+&set_label("xts_dec_ret");
+ &mov ("esp",&DWP(16*7+4,"esp")); # restore %esp
+&function_end("aesni_xts_decrypt");
+}
+}
+
+######################################################################
+# void $PREFIX_cbc_encrypt (const void *inp, void *out,
+# size_t length, const AES_KEY *key,
+# unsigned char *ivp,const int enc);
+&function_begin("${PREFIX}_cbc_encrypt");
+ &mov ($inp,&wparam(0));
+ &mov ($rounds_,"esp");
+ &mov ($out,&wparam(1));
+ &sub ($rounds_,24);
+ &mov ($len,&wparam(2));
+ &and ($rounds_,-16);
+ &mov ($key,&wparam(3));
+ &mov ($key_,&wparam(4));
+ &test ($len,$len);
+ &jz (&label("cbc_abort"));
+
+ &cmp (&wparam(5),0);
+ &xchg ($rounds_,"esp"); # alloca
+ &movups ($ivec,&QWP(0,$key_)); # load IV
+ &mov ($rounds,&DWP(240,$key));
+ &mov ($key_,$key); # backup $key
+ &mov (&DWP(16,"esp"),$rounds_); # save original %esp
+ &mov ($rounds_,$rounds); # backup $rounds
+ &je (&label("cbc_decrypt"));
+
+ &movaps ($inout0,$ivec);
+ &cmp ($len,16);
+ &jb (&label("cbc_enc_tail"));
+ &sub ($len,16);
+ &jmp (&label("cbc_enc_loop"));
+
+&set_label("cbc_enc_loop",16);
+ &movups ($ivec,&QWP(0,$inp)); # input actually
+ &lea ($inp,&DWP(16,$inp));
+ if ($inline)
+ { &aesni_inline_generate1("enc",$inout0,$ivec); }
+ else
+ { &xorps($inout0,$ivec); &call("_aesni_encrypt1"); }
+ &mov ($rounds,$rounds_); # restore $rounds
+ &mov ($key,$key_); # restore $key
+ &movups (&QWP(0,$out),$inout0); # store output
+ &lea ($out,&DWP(16,$out));
+ &sub ($len,16);
+ &jnc (&label("cbc_enc_loop"));
+ &add ($len,16);
+ &jnz (&label("cbc_enc_tail"));
+ &movaps ($ivec,$inout0);
+ &jmp (&label("cbc_ret"));
+
+&set_label("cbc_enc_tail");
+ &mov ("ecx",$len); # zaps $rounds
+ &data_word(0xA4F3F689); # rep movsb
+ &mov ("ecx",16); # zero tail
+ &sub ("ecx",$len);
+ &xor ("eax","eax"); # zaps $len
+ &data_word(0xAAF3F689); # rep stosb
+ &lea ($out,&DWP(-16,$out)); # rewind $out by 1 block
+ &mov ($rounds,$rounds_); # restore $rounds
+ &mov ($inp,$out); # $inp and $out are the same
+ &mov ($key,$key_); # restore $key
+ &jmp (&label("cbc_enc_loop"));
+######################################################################
+&set_label("cbc_decrypt",16);
+ &cmp ($len,0x50);
+ &jbe (&label("cbc_dec_tail"));
+ &movaps (&QWP(0,"esp"),$ivec); # save IV
+ &sub ($len,0x50);
+ &jmp (&label("cbc_dec_loop6_enter"));
+
+&set_label("cbc_dec_loop6",16);
+ &movaps (&QWP(0,"esp"),$rndkey0); # save IV
+ &movups (&QWP(0,$out),$inout5);
+ &lea ($out,&DWP(0x10,$out));
+&set_label("cbc_dec_loop6_enter");
+ &movdqu ($inout0,&QWP(0,$inp));
+ &movdqu ($inout1,&QWP(0x10,$inp));
+ &movdqu ($inout2,&QWP(0x20,$inp));
+ &movdqu ($inout3,&QWP(0x30,$inp));
+ &movdqu ($inout4,&QWP(0x40,$inp));
+ &movdqu ($inout5,&QWP(0x50,$inp));
+
+ &call ("_aesni_decrypt6");
+
+ &movups ($rndkey1,&QWP(0,$inp));
+ &movups ($rndkey0,&QWP(0x10,$inp));
+ &xorps ($inout0,&QWP(0,"esp")); # ^=IV
+ &xorps ($inout1,$rndkey1);
+ &movups ($rndkey1,&QWP(0x20,$inp));
+ &xorps ($inout2,$rndkey0);
+ &movups ($rndkey0,&QWP(0x30,$inp));
+ &xorps ($inout3,$rndkey1);
+ &movups ($rndkey1,&QWP(0x40,$inp));
+ &xorps ($inout4,$rndkey0);
+ &movups ($rndkey0,&QWP(0x50,$inp)); # IV
+ &xorps ($inout5,$rndkey1);
+ &movups (&QWP(0,$out),$inout0);
+ &movups (&QWP(0x10,$out),$inout1);
+ &lea ($inp,&DWP(0x60,$inp));
+ &movups (&QWP(0x20,$out),$inout2);
+ &mov ($rounds,$rounds_) # restore $rounds
+ &movups (&QWP(0x30,$out),$inout3);
+ &mov ($key,$key_); # restore $key
+ &movups (&QWP(0x40,$out),$inout4);
+ &lea ($out,&DWP(0x50,$out));
+ &sub ($len,0x60);
+ &ja (&label("cbc_dec_loop6"));
+
+ &movaps ($inout0,$inout5);
+ &movaps ($ivec,$rndkey0);
+ &add ($len,0x50);
+ &jle (&label("cbc_dec_tail_collected"));
+ &movups (&QWP(0,$out),$inout0);
+ &lea ($out,&DWP(0x10,$out));
+&set_label("cbc_dec_tail");
+ &movups ($inout0,&QWP(0,$inp));
+ &movaps ($in0,$inout0);
+ &cmp ($len,0x10);
+ &jbe (&label("cbc_dec_one"));
+
+ &movups ($inout1,&QWP(0x10,$inp));
+ &movaps ($in1,$inout1);
+ &cmp ($len,0x20);
+ &jbe (&label("cbc_dec_two"));
+
+ &movups ($inout2,&QWP(0x20,$inp));
+ &cmp ($len,0x30);
+ &jbe (&label("cbc_dec_three"));
+
+ &movups ($inout3,&QWP(0x30,$inp));
+ &cmp ($len,0x40);
+ &jbe (&label("cbc_dec_four"));
+
+ &movups ($inout4,&QWP(0x40,$inp));
+ &movaps (&QWP(0,"esp"),$ivec); # save IV
+ &movups ($inout0,&QWP(0,$inp));
+ &xorps ($inout5,$inout5);
+ &call ("_aesni_decrypt6");
+ &movups ($rndkey1,&QWP(0,$inp));
+ &movups ($rndkey0,&QWP(0x10,$inp));
+ &xorps ($inout0,&QWP(0,"esp")); # ^= IV
+ &xorps ($inout1,$rndkey1);
+ &movups ($rndkey1,&QWP(0x20,$inp));
+ &xorps ($inout2,$rndkey0);
+ &movups ($rndkey0,&QWP(0x30,$inp));
+ &xorps ($inout3,$rndkey1);
+ &movups ($ivec,&QWP(0x40,$inp)); # IV
+ &xorps ($inout4,$rndkey0);
+ &movups (&QWP(0,$out),$inout0);
+ &movups (&QWP(0x10,$out),$inout1);
+ &movups (&QWP(0x20,$out),$inout2);
+ &movups (&QWP(0x30,$out),$inout3);
+ &lea ($out,&DWP(0x40,$out));
+ &movaps ($inout0,$inout4);
+ &sub ($len,0x50);
+ &jmp (&label("cbc_dec_tail_collected"));
+
+&set_label("cbc_dec_one",16);
+ if ($inline)
+ { &aesni_inline_generate1("dec"); }
+ else
+ { &call ("_aesni_decrypt1"); }
+ &xorps ($inout0,$ivec);
+ &movaps ($ivec,$in0);
+ &sub ($len,0x10);
+ &jmp (&label("cbc_dec_tail_collected"));
+
+&set_label("cbc_dec_two",16);
+ &xorps ($inout2,$inout2);
+ &call ("_aesni_decrypt3");
+ &xorps ($inout0,$ivec);
+ &xorps ($inout1,$in0);
+ &movups (&QWP(0,$out),$inout0);
+ &movaps ($inout0,$inout1);
+ &lea ($out,&DWP(0x10,$out));
+ &movaps ($ivec,$in1);
+ &sub ($len,0x20);
+ &jmp (&label("cbc_dec_tail_collected"));
+
+&set_label("cbc_dec_three",16);
+ &call ("_aesni_decrypt3");
+ &xorps ($inout0,$ivec);
+ &xorps ($inout1,$in0);
+ &xorps ($inout2,$in1);
+ &movups (&QWP(0,$out),$inout0);
+ &movaps ($inout0,$inout2);
+ &movups (&QWP(0x10,$out),$inout1);
+ &lea ($out,&DWP(0x20,$out));
+ &movups ($ivec,&QWP(0x20,$inp));
+ &sub ($len,0x30);
+ &jmp (&label("cbc_dec_tail_collected"));
+
+&set_label("cbc_dec_four",16);
+ &call ("_aesni_decrypt4");
+ &movups ($rndkey1,&QWP(0x10,$inp));
+ &movups ($rndkey0,&QWP(0x20,$inp));
+ &xorps ($inout0,$ivec);
+ &movups ($ivec,&QWP(0x30,$inp));
+ &xorps ($inout1,$in0);
+ &movups (&QWP(0,$out),$inout0);
+ &xorps ($inout2,$rndkey1);
+ &movups (&QWP(0x10,$out),$inout1);
+ &xorps ($inout3,$rndkey0);
+ &movups (&QWP(0x20,$out),$inout2);
+ &lea ($out,&DWP(0x30,$out));
+ &movaps ($inout0,$inout3);
+ &sub ($len,0x40);
+
+&set_label("cbc_dec_tail_collected");
+ &and ($len,15);
+ &jnz (&label("cbc_dec_tail_partial"));
+ &movups (&QWP(0,$out),$inout0);
+ &jmp (&label("cbc_ret"));
+
+&set_label("cbc_dec_tail_partial",16);
+ &movaps (&QWP(0,"esp"),$inout0);
+ &mov ("ecx",16);
+ &mov ($inp,"esp");
+ &sub ("ecx",$len);
+ &data_word(0xA4F3F689); # rep movsb
+
+&set_label("cbc_ret");
+ &mov ("esp",&DWP(16,"esp")); # pull original %esp
+ &mov ($key_,&wparam(4));
+ &movups (&QWP(0,$key_),$ivec); # output IV
+&set_label("cbc_abort");
+&function_end("${PREFIX}_cbc_encrypt");
+
+######################################################################
+# Mechanical port from aesni-x86_64.pl.
+#
+# _aesni_set_encrypt_key is private interface,
+# input:
+# "eax" const unsigned char *userKey
+# $rounds int bits
+# $key AES_KEY *key
+# output:
+# "eax" return code
+# $round rounds
+
+&function_begin_B("_aesni_set_encrypt_key");
+ &test ("eax","eax");
+ &jz (&label("bad_pointer"));
+ &test ($key,$key);
+ &jz (&label("bad_pointer"));
+
+ &movups ("xmm0",&QWP(0,"eax")); # pull first 128 bits of *userKey
+ &xorps ("xmm4","xmm4"); # low dword of xmm4 is assumed 0
+ &lea ($key,&DWP(16,$key));
+ &cmp ($rounds,256);
+ &je (&label("14rounds"));
+ &cmp ($rounds,192);
+ &je (&label("12rounds"));
+ &cmp ($rounds,128);
+ &jne (&label("bad_keybits"));
+
+&set_label("10rounds",16);
+ &mov ($rounds,9);
+ &$movekey (&QWP(-16,$key),"xmm0"); # round 0
+ &aeskeygenassist("xmm1","xmm0",0x01); # round 1
+ &call (&label("key_128_cold"));
+ &aeskeygenassist("xmm1","xmm0",0x2); # round 2
+ &call (&label("key_128"));
+ &aeskeygenassist("xmm1","xmm0",0x04); # round 3
+ &call (&label("key_128"));
+ &aeskeygenassist("xmm1","xmm0",0x08); # round 4
+ &call (&label("key_128"));
+ &aeskeygenassist("xmm1","xmm0",0x10); # round 5
+ &call (&label("key_128"));
+ &aeskeygenassist("xmm1","xmm0",0x20); # round 6
+ &call (&label("key_128"));
+ &aeskeygenassist("xmm1","xmm0",0x40); # round 7
+ &call (&label("key_128"));
+ &aeskeygenassist("xmm1","xmm0",0x80); # round 8
+ &call (&label("key_128"));
+ &aeskeygenassist("xmm1","xmm0",0x1b); # round 9
+ &call (&label("key_128"));
+ &aeskeygenassist("xmm1","xmm0",0x36); # round 10
+ &call (&label("key_128"));
+ &$movekey (&QWP(0,$key),"xmm0");
+ &mov (&DWP(80,$key),$rounds);
+ &xor ("eax","eax");
+ &ret();
+
+&set_label("key_128",16);
+ &$movekey (&QWP(0,$key),"xmm0");
+ &lea ($key,&DWP(16,$key));
+&set_label("key_128_cold");
+ &shufps ("xmm4","xmm0",0b00010000);
+ &xorps ("xmm0","xmm4");
+ &shufps ("xmm4","xmm0",0b10001100);
+ &xorps ("xmm0","xmm4");
+ &shufps ("xmm1","xmm1",0b11111111); # critical path
+ &xorps ("xmm0","xmm1");
+ &ret();
+
+&set_label("12rounds",16);
+ &movq ("xmm2",&QWP(16,"eax")); # remaining 1/3 of *userKey
+ &mov ($rounds,11);
+ &$movekey (&QWP(-16,$key),"xmm0") # round 0
+ &aeskeygenassist("xmm1","xmm2",0x01); # round 1,2
+ &call (&label("key_192a_cold"));
+ &aeskeygenassist("xmm1","xmm2",0x02); # round 2,3
+ &call (&label("key_192b"));
+ &aeskeygenassist("xmm1","xmm2",0x04); # round 4,5
+ &call (&label("key_192a"));
+ &aeskeygenassist("xmm1","xmm2",0x08); # round 5,6
+ &call (&label("key_192b"));
+ &aeskeygenassist("xmm1","xmm2",0x10); # round 7,8
+ &call (&label("key_192a"));
+ &aeskeygenassist("xmm1","xmm2",0x20); # round 8,9
+ &call (&label("key_192b"));
+ &aeskeygenassist("xmm1","xmm2",0x40); # round 10,11
+ &call (&label("key_192a"));
+ &aeskeygenassist("xmm1","xmm2",0x80); # round 11,12
+ &call (&label("key_192b"));
+ &$movekey (&QWP(0,$key),"xmm0");
+ &mov (&DWP(48,$key),$rounds);
+ &xor ("eax","eax");
+ &ret();
+
+&set_label("key_192a",16);
+ &$movekey (&QWP(0,$key),"xmm0");
+ &lea ($key,&DWP(16,$key));
+&set_label("key_192a_cold",16);
+ &movaps ("xmm5","xmm2");
+&set_label("key_192b_warm");
+ &shufps ("xmm4","xmm0",0b00010000);
+ &movdqa ("xmm3","xmm2");
+ &xorps ("xmm0","xmm4");
+ &shufps ("xmm4","xmm0",0b10001100);
+ &pslldq ("xmm3",4);
+ &xorps ("xmm0","xmm4");
+ &pshufd ("xmm1","xmm1",0b01010101); # critical path
+ &pxor ("xmm2","xmm3");
+ &pxor ("xmm0","xmm1");
+ &pshufd ("xmm3","xmm0",0b11111111);
+ &pxor ("xmm2","xmm3");
+ &ret();
+
+&set_label("key_192b",16);
+ &movaps ("xmm3","xmm0");
+ &shufps ("xmm5","xmm0",0b01000100);
+ &$movekey (&QWP(0,$key),"xmm5");
+ &shufps ("xmm3","xmm2",0b01001110);
+ &$movekey (&QWP(16,$key),"xmm3");
+ &lea ($key,&DWP(32,$key));
+ &jmp (&label("key_192b_warm"));
+
+&set_label("14rounds",16);
+ &movups ("xmm2",&QWP(16,"eax")); # remaining half of *userKey
+ &mov ($rounds,13);
+ &lea ($key,&DWP(16,$key));
+ &$movekey (&QWP(-32,$key),"xmm0"); # round 0
+ &$movekey (&QWP(-16,$key),"xmm2"); # round 1
+ &aeskeygenassist("xmm1","xmm2",0x01); # round 2
+ &call (&label("key_256a_cold"));
+ &aeskeygenassist("xmm1","xmm0",0x01); # round 3
+ &call (&label("key_256b"));
+ &aeskeygenassist("xmm1","xmm2",0x02); # round 4
+ &call (&label("key_256a"));
+ &aeskeygenassist("xmm1","xmm0",0x02); # round 5
+ &call (&label("key_256b"));
+ &aeskeygenassist("xmm1","xmm2",0x04); # round 6
+ &call (&label("key_256a"));
+ &aeskeygenassist("xmm1","xmm0",0x04); # round 7
+ &call (&label("key_256b"));
+ &aeskeygenassist("xmm1","xmm2",0x08); # round 8
+ &call (&label("key_256a"));
+ &aeskeygenassist("xmm1","xmm0",0x08); # round 9
+ &call (&label("key_256b"));
+ &aeskeygenassist("xmm1","xmm2",0x10); # round 10
+ &call (&label("key_256a"));
+ &aeskeygenassist("xmm1","xmm0",0x10); # round 11
+ &call (&label("key_256b"));
+ &aeskeygenassist("xmm1","xmm2",0x20); # round 12
+ &call (&label("key_256a"));
+ &aeskeygenassist("xmm1","xmm0",0x20); # round 13
+ &call (&label("key_256b"));
+ &aeskeygenassist("xmm1","xmm2",0x40); # round 14
+ &call (&label("key_256a"));
+ &$movekey (&QWP(0,$key),"xmm0");
+ &mov (&DWP(16,$key),$rounds);
+ &xor ("eax","eax");
+ &ret();
+
+&set_label("key_256a",16);
+ &$movekey (&QWP(0,$key),"xmm2");
+ &lea ($key,&DWP(16,$key));
+&set_label("key_256a_cold");
+ &shufps ("xmm4","xmm0",0b00010000);
+ &xorps ("xmm0","xmm4");
+ &shufps ("xmm4","xmm0",0b10001100);
+ &xorps ("xmm0","xmm4");
+ &shufps ("xmm1","xmm1",0b11111111); # critical path
+ &xorps ("xmm0","xmm1");
+ &ret();
+
+&set_label("key_256b",16);
+ &$movekey (&QWP(0,$key),"xmm0");
+ &lea ($key,&DWP(16,$key));
+
+ &shufps ("xmm4","xmm2",0b00010000);
+ &xorps ("xmm2","xmm4");
+ &shufps ("xmm4","xmm2",0b10001100);
+ &xorps ("xmm2","xmm4");
+ &shufps ("xmm1","xmm1",0b10101010); # critical path
+ &xorps ("xmm2","xmm1");
+ &ret();
+
+&set_label("bad_pointer",4);
+ &mov ("eax",-1);
+ &ret ();
+&set_label("bad_keybits",4);
+ &mov ("eax",-2);
+ &ret ();
+&function_end_B("_aesni_set_encrypt_key");
+
+# int $PREFIX_set_encrypt_key (const unsigned char *userKey, int bits,
+# AES_KEY *key)
+&function_begin_B("${PREFIX}_set_encrypt_key");
+ &mov ("eax",&wparam(0));
+ &mov ($rounds,&wparam(1));
+ &mov ($key,&wparam(2));
+ &call ("_aesni_set_encrypt_key");
+ &ret ();
+&function_end_B("${PREFIX}_set_encrypt_key");
+
+# int $PREFIX_set_decrypt_key (const unsigned char *userKey, int bits,
+# AES_KEY *key)
+&function_begin_B("${PREFIX}_set_decrypt_key");
+ &mov ("eax",&wparam(0));
+ &mov ($rounds,&wparam(1));
+ &mov ($key,&wparam(2));
+ &call ("_aesni_set_encrypt_key");
+ &mov ($key,&wparam(2));
+ &shl ($rounds,4) # rounds-1 after _aesni_set_encrypt_key
+ &test ("eax","eax");
+ &jnz (&label("dec_key_ret"));
+ &lea ("eax",&DWP(16,$key,$rounds)); # end of key schedule
+
+ &$movekey ("xmm0",&QWP(0,$key)); # just swap
+ &$movekey ("xmm1",&QWP(0,"eax"));
+ &$movekey (&QWP(0,"eax"),"xmm0");
+ &$movekey (&QWP(0,$key),"xmm1");
+ &lea ($key,&DWP(16,$key));
+ &lea ("eax",&DWP(-16,"eax"));
+
+&set_label("dec_key_inverse");
+ &$movekey ("xmm0",&QWP(0,$key)); # swap and inverse
+ &$movekey ("xmm1",&QWP(0,"eax"));
+ &aesimc ("xmm0","xmm0");
+ &aesimc ("xmm1","xmm1");
+ &lea ($key,&DWP(16,$key));
+ &lea ("eax",&DWP(-16,"eax"));
+ &$movekey (&QWP(16,"eax"),"xmm0");
+ &$movekey (&QWP(-16,$key),"xmm1");
+ &cmp ("eax",$key);
+ &ja (&label("dec_key_inverse"));
+
+ &$movekey ("xmm0",&QWP(0,$key)); # inverse middle
+ &aesimc ("xmm0","xmm0");
+ &$movekey (&QWP(0,$key),"xmm0");
+
+ &xor ("eax","eax"); # return success
+&set_label("dec_key_ret");
+ &ret ();
+&function_end_B("${PREFIX}_set_decrypt_key");
+&asciz("AES for Intel AES-NI, CRYPTOGAMS by <appro\@openssl.org>");
+
+&asm_finish();
diff --git a/crypto/aes/asm/aesni-x86_64.pl b/crypto/aes/asm/aesni-x86_64.pl
new file mode 100644
index 0000000..0dbb194
--- /dev/null
+++ b/crypto/aes/asm/aesni-x86_64.pl
@@ -0,0 +1,3069 @@
+#!/usr/bin/env perl
+#
+# ====================================================================
+# Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+#
+# This module implements support for Intel AES-NI extension. In
+# OpenSSL context it's used with Intel engine, but can also be used as
+# drop-in replacement for crypto/aes/asm/aes-x86_64.pl [see below for
+# details].
+#
+# Performance.
+#
+# Given aes(enc|dec) instructions' latency asymptotic performance for
+# non-parallelizable modes such as CBC encrypt is 3.75 cycles per byte
+# processed with 128-bit key. And given their throughput asymptotic
+# performance for parallelizable modes is 1.25 cycles per byte. Being
+# asymptotic limit it's not something you commonly achieve in reality,
+# but how close does one get? Below are results collected for
+# different modes and block sized. Pairs of numbers are for en-/
+# decryption.
+#
+# 16-byte 64-byte 256-byte 1-KB 8-KB
+# ECB 4.25/4.25 1.38/1.38 1.28/1.28 1.26/1.26 1.26/1.26
+# CTR 5.42/5.42 1.92/1.92 1.44/1.44 1.28/1.28 1.26/1.26
+# CBC 4.38/4.43 4.15/1.43 4.07/1.32 4.07/1.29 4.06/1.28
+# CCM 5.66/9.42 4.42/5.41 4.16/4.40 4.09/4.15 4.06/4.07
+# OFB 5.42/5.42 4.64/4.64 4.44/4.44 4.39/4.39 4.38/4.38
+# CFB 5.73/5.85 5.56/5.62 5.48/5.56 5.47/5.55 5.47/5.55
+#
+# ECB, CTR, CBC and CCM results are free from EVP overhead. This means
+# that otherwise used 'openssl speed -evp aes-128-??? -engine aesni
+# [-decrypt]' will exhibit 10-15% worse results for smaller blocks.
+# The results were collected with specially crafted speed.c benchmark
+# in order to compare them with results reported in "Intel Advanced
+# Encryption Standard (AES) New Instruction Set" White Paper Revision
+# 3.0 dated May 2010. All above results are consistently better. This
+# module also provides better performance for block sizes smaller than
+# 128 bytes in points *not* represented in the above table.
+#
+# Looking at the results for 8-KB buffer.
+#
+# CFB and OFB results are far from the limit, because implementation
+# uses "generic" CRYPTO_[c|o]fb128_encrypt interfaces relying on
+# single-block aesni_encrypt, which is not the most optimal way to go.
+# CBC encrypt result is unexpectedly high and there is no documented
+# explanation for it. Seemingly there is a small penalty for feeding
+# the result back to AES unit the way it's done in CBC mode. There is
+# nothing one can do and the result appears optimal. CCM result is
+# identical to CBC, because CBC-MAC is essentially CBC encrypt without
+# saving output. CCM CTR "stays invisible," because it's neatly
+# interleaved wih CBC-MAC. This provides ~30% improvement over
+# "straghtforward" CCM implementation with CTR and CBC-MAC performed
+# disjointly. Parallelizable modes practically achieve the theoretical
+# limit.
+#
+# Looking at how results vary with buffer size.
+#
+# Curves are practically saturated at 1-KB buffer size. In most cases
+# "256-byte" performance is >95%, and "64-byte" is ~90% of "8-KB" one.
+# CTR curve doesn't follow this pattern and is "slowest" changing one
+# with "256-byte" result being 87% of "8-KB." This is because overhead
+# in CTR mode is most computationally intensive. Small-block CCM
+# decrypt is slower than encrypt, because first CTR and last CBC-MAC
+# iterations can't be interleaved.
+#
+# Results for 192- and 256-bit keys.
+#
+# EVP-free results were observed to scale perfectly with number of
+# rounds for larger block sizes, i.e. 192-bit result being 10/12 times
+# lower and 256-bit one - 10/14. Well, in CBC encrypt case differences
+# are a tad smaller, because the above mentioned penalty biases all
+# results by same constant value. In similar way function call
+# overhead affects small-block performance, as well as OFB and CFB
+# results. Differences are not large, most common coefficients are
+# 10/11.7 and 10/13.4 (as opposite to 10/12.0 and 10/14.0), but one
+# observe even 10/11.2 and 10/12.4 (CTR, OFB, CFB)...
+
+# January 2011
+#
+# While Westmere processor features 6 cycles latency for aes[enc|dec]
+# instructions, which can be scheduled every second cycle, Sandy
+# Bridge spends 8 cycles per instruction, but it can schedule them
+# every cycle. This means that code targeting Westmere would perform
+# suboptimally on Sandy Bridge. Therefore this update.
+#
+# In addition, non-parallelizable CBC encrypt (as well as CCM) is
+# optimized. Relative improvement might appear modest, 8% on Westmere,
+# but in absolute terms it's 3.77 cycles per byte encrypted with
+# 128-bit key on Westmere, and 5.07 - on Sandy Bridge. These numbers
+# should be compared to asymptotic limits of 3.75 for Westmere and
+# 5.00 for Sandy Bridge. Actually, the fact that they get this close
+# to asymptotic limits is quite amazing. Indeed, the limit is
+# calculated as latency times number of rounds, 10 for 128-bit key,
+# and divided by 16, the number of bytes in block, or in other words
+# it accounts *solely* for aesenc instructions. But there are extra
+# instructions, and numbers so close to the asymptotic limits mean
+# that it's as if it takes as little as *one* additional cycle to
+# execute all of them. How is it possible? It is possible thanks to
+# out-of-order execution logic, which manages to overlap post-
+# processing of previous block, things like saving the output, with
+# actual encryption of current block, as well as pre-processing of
+# current block, things like fetching input and xor-ing it with
+# 0-round element of the key schedule, with actual encryption of
+# previous block. Keep this in mind...
+#
+# For parallelizable modes, such as ECB, CBC decrypt, CTR, higher
+# performance is achieved by interleaving instructions working on
+# independent blocks. In which case asymptotic limit for such modes
+# can be obtained by dividing above mentioned numbers by AES
+# instructions' interleave factor. Westmere can execute at most 3
+# instructions at a time, meaning that optimal interleave factor is 3,
+# and that's where the "magic" number of 1.25 come from. "Optimal
+# interleave factor" means that increase of interleave factor does
+# not improve performance. The formula has proven to reflect reality
+# pretty well on Westmere... Sandy Bridge on the other hand can
+# execute up to 8 AES instructions at a time, so how does varying
+# interleave factor affect the performance? Here is table for ECB
+# (numbers are cycles per byte processed with 128-bit key):
+#
+# instruction interleave factor 3x 6x 8x
+# theoretical asymptotic limit 1.67 0.83 0.625
+# measured performance for 8KB block 1.05 0.86 0.84
+#
+# "as if" interleave factor 4.7x 5.8x 6.0x
+#
+# Further data for other parallelizable modes:
+#
+# CBC decrypt 1.16 0.93 0.93
+# CTR 1.14 0.91 n/a
+#
+# Well, given 3x column it's probably inappropriate to call the limit
+# asymptotic, if it can be surpassed, isn't it? What happens there?
+# Rewind to CBC paragraph for the answer. Yes, out-of-order execution
+# magic is responsible for this. Processor overlaps not only the
+# additional instructions with AES ones, but even AES instuctions
+# processing adjacent triplets of independent blocks. In the 6x case
+# additional instructions still claim disproportionally small amount
+# of additional cycles, but in 8x case number of instructions must be
+# a tad too high for out-of-order logic to cope with, and AES unit
+# remains underutilized... As you can see 8x interleave is hardly
+# justifiable, so there no need to feel bad that 32-bit aesni-x86.pl
+# utilizies 6x interleave because of limited register bank capacity.
+#
+# Higher interleave factors do have negative impact on Westmere
+# performance. While for ECB mode it's negligible ~1.5%, other
+# parallelizables perform ~5% worse, which is outweighed by ~25%
+# improvement on Sandy Bridge. To balance regression on Westmere
+# CTR mode was implemented with 6x aesenc interleave factor.
+
+# April 2011
+#
+# Add aesni_xts_[en|de]crypt. Westmere spends 1.33 cycles processing
+# one byte out of 8KB with 128-bit key, Sandy Bridge - 0.97. Just like
+# in CTR mode AES instruction interleave factor was chosen to be 6x.
+
+$PREFIX="aesni"; # if $PREFIX is set to "AES", the script
+ # generates drop-in replacement for
+ # crypto/aes/asm/aes-x86_64.pl:-)
+
+$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;
+
+$movkey = $PREFIX eq "aesni" ? "movups" : "movups";
+@_4args=$win64? ("%rcx","%rdx","%r8", "%r9") : # Win64 order
+ ("%rdi","%rsi","%rdx","%rcx"); # Unix order
+
+$code=".text\n";
+
+$rounds="%eax"; # input to and changed by aesni_[en|de]cryptN !!!
+# this is natural Unix argument order for public $PREFIX_[ecb|cbc]_encrypt ...
+$inp="%rdi";
+$out="%rsi";
+$len="%rdx";
+$key="%rcx"; # input to and changed by aesni_[en|de]cryptN !!!
+$ivp="%r8"; # cbc, ctr, ...
+
+$rnds_="%r10d"; # backup copy for $rounds
+$key_="%r11"; # backup copy for $key
+
+# %xmm register layout
+$rndkey0="%xmm0"; $rndkey1="%xmm1";
+$inout0="%xmm2"; $inout1="%xmm3";
+$inout2="%xmm4"; $inout3="%xmm5";
+$inout4="%xmm6"; $inout5="%xmm7";
+$inout6="%xmm8"; $inout7="%xmm9";
+
+$in2="%xmm6"; $in1="%xmm7"; # used in CBC decrypt, CTR, ...
+$in0="%xmm8"; $iv="%xmm9";
+
+# Inline version of internal aesni_[en|de]crypt1.
+#
+# Why folded loop? Because aes[enc|dec] is slow enough to accommodate
+# cycles which take care of loop variables...
+{ my $sn;
+sub aesni_generate1 {
+my ($p,$key,$rounds,$inout,$ivec)=@_; $inout=$inout0 if (!defined($inout));
+++$sn;
+$code.=<<___;
+ $movkey ($key),$rndkey0
+ $movkey 16($key),$rndkey1
+___
+$code.=<<___ if (defined($ivec));
+ xorps $rndkey0,$ivec
+ lea 32($key),$key
+ xorps $ivec,$inout
+___
+$code.=<<___ if (!defined($ivec));
+ lea 32($key),$key
+ xorps $rndkey0,$inout
+___
+$code.=<<___;
+.Loop_${p}1_$sn:
+ aes${p} $rndkey1,$inout
+ dec $rounds
+ $movkey ($key),$rndkey1
+ lea 16($key),$key
+ jnz .Loop_${p}1_$sn # loop body is 16 bytes
+ aes${p}last $rndkey1,$inout
+___
+}}
+# void $PREFIX_[en|de]crypt (const void *inp,void *out,const AES_KEY *key);
+#
+{ my ($inp,$out,$key) = @_4args;
+
+$code.=<<___;
+.globl ${PREFIX}_encrypt
+.type ${PREFIX}_encrypt,\@abi-omnipotent
+.align 16
+${PREFIX}_encrypt:
+ movups ($inp),$inout0 # load input
+ mov 240($key),$rounds # key->rounds
+___
+ &aesni_generate1("enc",$key,$rounds);
+$code.=<<___;
+ movups $inout0,($out) # output
+ ret
+.size ${PREFIX}_encrypt,.-${PREFIX}_encrypt
+
+.globl ${PREFIX}_decrypt
+.type ${PREFIX}_decrypt,\@abi-omnipotent
+.align 16
+${PREFIX}_decrypt:
+ movups ($inp),$inout0 # load input
+ mov 240($key),$rounds # key->rounds
+___
+ &aesni_generate1("dec",$key,$rounds);
+$code.=<<___;
+ movups $inout0,($out) # output
+ ret
+.size ${PREFIX}_decrypt, .-${PREFIX}_decrypt
+___
+}
+
+# _aesni_[en|de]cryptN are private interfaces, N denotes interleave
+# factor. Why 3x subroutine were originally used in loops? Even though
+# aes[enc|dec] latency was originally 6, it could be scheduled only
+# every *2nd* cycle. Thus 3x interleave was the one providing optimal
+# utilization, i.e. when subroutine's throughput is virtually same as
+# of non-interleaved subroutine [for number of input blocks up to 3].
+# This is why it makes no sense to implement 2x subroutine.
+# aes[enc|dec] latency in next processor generation is 8, but the
+# instructions can be scheduled every cycle. Optimal interleave for
+# new processor is therefore 8x...
+sub aesni_generate3 {
+my $dir=shift;
+# As already mentioned it takes in $key and $rounds, which are *not*
+# preserved. $inout[0-2] is cipher/clear text...
+$code.=<<___;
+.type _aesni_${dir}rypt3,\@abi-omnipotent
+.align 16
+_aesni_${dir}rypt3:
+ $movkey ($key),$rndkey0
+ shr \$1,$rounds
+ $movkey 16($key),$rndkey1
+ lea 32($key),$key
+ xorps $rndkey0,$inout0
+ xorps $rndkey0,$inout1
+ xorps $rndkey0,$inout2
+ $movkey ($key),$rndkey0
+
+.L${dir}_loop3:
+ aes${dir} $rndkey1,$inout0
+ aes${dir} $rndkey1,$inout1
+ dec $rounds
+ aes${dir} $rndkey1,$inout2
+ $movkey 16($key),$rndkey1
+ aes${dir} $rndkey0,$inout0
+ aes${dir} $rndkey0,$inout1
+ lea 32($key),$key
+ aes${dir} $rndkey0,$inout2
+ $movkey ($key),$rndkey0
+ jnz .L${dir}_loop3
+
+ aes${dir} $rndkey1,$inout0
+ aes${dir} $rndkey1,$inout1
+ aes${dir} $rndkey1,$inout2
+ aes${dir}last $rndkey0,$inout0
+ aes${dir}last $rndkey0,$inout1
+ aes${dir}last $rndkey0,$inout2
+ ret
+.size _aesni_${dir}rypt3,.-_aesni_${dir}rypt3
+___
+}
+# 4x interleave is implemented to improve small block performance,
+# most notably [and naturally] 4 block by ~30%. One can argue that one
+# should have implemented 5x as well, but improvement would be <20%,
+# so it's not worth it...
+sub aesni_generate4 {
+my $dir=shift;
+# As already mentioned it takes in $key and $rounds, which are *not*
+# preserved. $inout[0-3] is cipher/clear text...
+$code.=<<___;
+.type _aesni_${dir}rypt4,\@abi-omnipotent
+.align 16
+_aesni_${dir}rypt4:
+ $movkey ($key),$rndkey0
+ shr \$1,$rounds
+ $movkey 16($key),$rndkey1
+ lea 32($key),$key
+ xorps $rndkey0,$inout0
+ xorps $rndkey0,$inout1
+ xorps $rndkey0,$inout2
+ xorps $rndkey0,$inout3
+ $movkey ($key),$rndkey0
+
+.L${dir}_loop4:
+ aes${dir} $rndkey1,$inout0
+ aes${dir} $rndkey1,$inout1
+ dec $rounds
+ aes${dir} $rndkey1,$inout2
+ aes${dir} $rndkey1,$inout3
+ $movkey 16($key),$rndkey1
+ aes${dir} $rndkey0,$inout0
+ aes${dir} $rndkey0,$inout1
+ lea 32($key),$key
+ aes${dir} $rndkey0,$inout2
+ aes${dir} $rndkey0,$inout3
+ $movkey ($key),$rndkey0
+ jnz .L${dir}_loop4
+
+ aes${dir} $rndkey1,$inout0
+ aes${dir} $rndkey1,$inout1
+ aes${dir} $rndkey1,$inout2
+ aes${dir} $rndkey1,$inout3
+ aes${dir}last $rndkey0,$inout0
+ aes${dir}last $rndkey0,$inout1
+ aes${dir}last $rndkey0,$inout2
+ aes${dir}last $rndkey0,$inout3
+ ret
+.size _aesni_${dir}rypt4,.-_aesni_${dir}rypt4
+___
+}
+sub aesni_generate6 {
+my $dir=shift;
+# As already mentioned it takes in $key and $rounds, which are *not*
+# preserved. $inout[0-5] is cipher/clear text...
+$code.=<<___;
+.type _aesni_${dir}rypt6,\@abi-omnipotent
+.align 16
+_aesni_${dir}rypt6:
+ $movkey ($key),$rndkey0
+ shr \$1,$rounds
+ $movkey 16($key),$rndkey1
+ lea 32($key),$key
+ xorps $rndkey0,$inout0
+ pxor $rndkey0,$inout1
+ aes${dir} $rndkey1,$inout0
+ pxor $rndkey0,$inout2
+ aes${dir} $rndkey1,$inout1
+ pxor $rndkey0,$inout3
+ aes${dir} $rndkey1,$inout2
+ pxor $rndkey0,$inout4
+ aes${dir} $rndkey1,$inout3
+ pxor $rndkey0,$inout5
+ dec $rounds
+ aes${dir} $rndkey1,$inout4
+ $movkey ($key),$rndkey0
+ aes${dir} $rndkey1,$inout5
+ jmp .L${dir}_loop6_enter
+.align 16
+.L${dir}_loop6:
+ aes${dir} $rndkey1,$inout0
+ aes${dir} $rndkey1,$inout1
+ dec $rounds
+ aes${dir} $rndkey1,$inout2
+ aes${dir} $rndkey1,$inout3
+ aes${dir} $rndkey1,$inout4
+ aes${dir} $rndkey1,$inout5
+.L${dir}_loop6_enter: # happens to be 16-byte aligned
+ $movkey 16($key),$rndkey1
+ aes${dir} $rndkey0,$inout0
+ aes${dir} $rndkey0,$inout1
+ lea 32($key),$key
+ aes${dir} $rndkey0,$inout2
+ aes${dir} $rndkey0,$inout3
+ aes${dir} $rndkey0,$inout4
+ aes${dir} $rndkey0,$inout5
+ $movkey ($key),$rndkey0
+ jnz .L${dir}_loop6
+
+ aes${dir} $rndkey1,$inout0
+ aes${dir} $rndkey1,$inout1
+ aes${dir} $rndkey1,$inout2
+ aes${dir} $rndkey1,$inout3
+ aes${dir} $rndkey1,$inout4
+ aes${dir} $rndkey1,$inout5
+ aes${dir}last $rndkey0,$inout0
+ aes${dir}last $rndkey0,$inout1
+ aes${dir}last $rndkey0,$inout2
+ aes${dir}last $rndkey0,$inout3
+ aes${dir}last $rndkey0,$inout4
+ aes${dir}last $rndkey0,$inout5
+ ret
+.size _aesni_${dir}rypt6,.-_aesni_${dir}rypt6
+___
+}
+sub aesni_generate8 {
+my $dir=shift;
+# As already mentioned it takes in $key and $rounds, which are *not*
+# preserved. $inout[0-7] is cipher/clear text...
+$code.=<<___;
+.type _aesni_${dir}rypt8,\@abi-omnipotent
+.align 16
+_aesni_${dir}rypt8:
+ $movkey ($key),$rndkey0
+ shr \$1,$rounds
+ $movkey 16($key),$rndkey1
+ lea 32($key),$key
+ xorps $rndkey0,$inout0
+ xorps $rndkey0,$inout1
+ aes${dir} $rndkey1,$inout0
+ pxor $rndkey0,$inout2
+ aes${dir} $rndkey1,$inout1
+ pxor $rndkey0,$inout3
+ aes${dir} $rndkey1,$inout2
+ pxor $rndkey0,$inout4
+ aes${dir} $rndkey1,$inout3
+ pxor $rndkey0,$inout5
+ dec $rounds
+ aes${dir} $rndkey1,$inout4
+ pxor $rndkey0,$inout6
+ aes${dir} $rndkey1,$inout5
+ pxor $rndkey0,$inout7
+ $movkey ($key),$rndkey0
+ aes${dir} $rndkey1,$inout6
+ aes${dir} $rndkey1,$inout7
+ $movkey 16($key),$rndkey1
+ jmp .L${dir}_loop8_enter
+.align 16
+.L${dir}_loop8:
+ aes${dir} $rndkey1,$inout0
+ aes${dir} $rndkey1,$inout1
+ dec $rounds
+ aes${dir} $rndkey1,$inout2
+ aes${dir} $rndkey1,$inout3
+ aes${dir} $rndkey1,$inout4
+ aes${dir} $rndkey1,$inout5
+ aes${dir} $rndkey1,$inout6
+ aes${dir} $rndkey1,$inout7
+ $movkey 16($key),$rndkey1
+.L${dir}_loop8_enter: # happens to be 16-byte aligned
+ aes${dir} $rndkey0,$inout0
+ aes${dir} $rndkey0,$inout1
+ lea 32($key),$key
+ aes${dir} $rndkey0,$inout2
+ aes${dir} $rndkey0,$inout3
+ aes${dir} $rndkey0,$inout4
+ aes${dir} $rndkey0,$inout5
+ aes${dir} $rndkey0,$inout6
+ aes${dir} $rndkey0,$inout7
+ $movkey ($key),$rndkey0
+ jnz .L${dir}_loop8
+
+ aes${dir} $rndkey1,$inout0
+ aes${dir} $rndkey1,$inout1
+ aes${dir} $rndkey1,$inout2
+ aes${dir} $rndkey1,$inout3
+ aes${dir} $rndkey1,$inout4
+ aes${dir} $rndkey1,$inout5
+ aes${dir} $rndkey1,$inout6
+ aes${dir} $rndkey1,$inout7
+ aes${dir}last $rndkey0,$inout0
+ aes${dir}last $rndkey0,$inout1
+ aes${dir}last $rndkey0,$inout2
+ aes${dir}last $rndkey0,$inout3
+ aes${dir}last $rndkey0,$inout4
+ aes${dir}last $rndkey0,$inout5
+ aes${dir}last $rndkey0,$inout6
+ aes${dir}last $rndkey0,$inout7
+ ret
+.size _aesni_${dir}rypt8,.-_aesni_${dir}rypt8
+___
+}
+&aesni_generate3("enc") if ($PREFIX eq "aesni");
+&aesni_generate3("dec");
+&aesni_generate4("enc") if ($PREFIX eq "aesni");
+&aesni_generate4("dec");
+&aesni_generate6("enc") if ($PREFIX eq "aesni");
+&aesni_generate6("dec");
+&aesni_generate8("enc") if ($PREFIX eq "aesni");
+&aesni_generate8("dec");
+
+if ($PREFIX eq "aesni") {
+########################################################################
+# void aesni_ecb_encrypt (const void *in, void *out,
+# size_t length, const AES_KEY *key,
+# int enc);
+$code.=<<___;
+.globl aesni_ecb_encrypt
+.type aesni_ecb_encrypt,\@function,5
+.align 16
+aesni_ecb_encrypt:
+ and \$-16,$len
+ jz .Lecb_ret
+
+ mov 240($key),$rounds # key->rounds
+ $movkey ($key),$rndkey0
+ mov $key,$key_ # backup $key
+ mov $rounds,$rnds_ # backup $rounds
+ test %r8d,%r8d # 5th argument
+ jz .Lecb_decrypt
+#--------------------------- ECB ENCRYPT ------------------------------#
+ cmp \$0x80,$len
+ jb .Lecb_enc_tail
+
+ movdqu ($inp),$inout0
+ movdqu 0x10($inp),$inout1
+ movdqu 0x20($inp),$inout2
+ movdqu 0x30($inp),$inout3
+ movdqu 0x40($inp),$inout4
+ movdqu 0x50($inp),$inout5
+ movdqu 0x60($inp),$inout6
+ movdqu 0x70($inp),$inout7
+ lea 0x80($inp),$inp
+ sub \$0x80,$len
+ jmp .Lecb_enc_loop8_enter
+.align 16
+.Lecb_enc_loop8:
+ movups $inout0,($out)
+ mov $key_,$key # restore $key
+ movdqu ($inp),$inout0
+ mov $rnds_,$rounds # restore $rounds
+ movups $inout1,0x10($out)
+ movdqu 0x10($inp),$inout1
+ movups $inout2,0x20($out)
+ movdqu 0x20($inp),$inout2
+ movups $inout3,0x30($out)
+ movdqu 0x30($inp),$inout3
+ movups $inout4,0x40($out)
+ movdqu 0x40($inp),$inout4
+ movups $inout5,0x50($out)
+ movdqu 0x50($inp),$inout5
+ movups $inout6,0x60($out)
+ movdqu 0x60($inp),$inout6
+ movups $inout7,0x70($out)
+ lea 0x80($out),$out
+ movdqu 0x70($inp),$inout7
+ lea 0x80($inp),$inp
+.Lecb_enc_loop8_enter:
+
+ call _aesni_encrypt8
+
+ sub \$0x80,$len
+ jnc .Lecb_enc_loop8
+
+ movups $inout0,($out)
+ mov $key_,$key # restore $key
+ movups $inout1,0x10($out)
+ mov $rnds_,$rounds # restore $rounds
+ movups $inout2,0x20($out)
+ movups $inout3,0x30($out)
+ movups $inout4,0x40($out)
+ movups $inout5,0x50($out)
+ movups $inout6,0x60($out)
+ movups $inout7,0x70($out)
+ lea 0x80($out),$out
+ add \$0x80,$len
+ jz .Lecb_ret
+
+.Lecb_enc_tail:
+ movups ($inp),$inout0
+ cmp \$0x20,$len
+ jb .Lecb_enc_one
+ movups 0x10($inp),$inout1
+ je .Lecb_enc_two
+ movups 0x20($inp),$inout2
+ cmp \$0x40,$len
+ jb .Lecb_enc_three
+ movups 0x30($inp),$inout3
+ je .Lecb_enc_four
+ movups 0x40($inp),$inout4
+ cmp \$0x60,$len
+ jb .Lecb_enc_five
+ movups 0x50($inp),$inout5
+ je .Lecb_enc_six
+ movdqu 0x60($inp),$inout6
+ call _aesni_encrypt8
+ movups $inout0,($out)
+ movups $inout1,0x10($out)
+ movups $inout2,0x20($out)
+ movups $inout3,0x30($out)
+ movups $inout4,0x40($out)
+ movups $inout5,0x50($out)
+ movups $inout6,0x60($out)
+ jmp .Lecb_ret
+.align 16
+.Lecb_enc_one:
+___
+ &aesni_generate1("enc",$key,$rounds);
+$code.=<<___;
+ movups $inout0,($out)
+ jmp .Lecb_ret
+.align 16
+.Lecb_enc_two:
+ xorps $inout2,$inout2
+ call _aesni_encrypt3
+ movups $inout0,($out)
+ movups $inout1,0x10($out)
+ jmp .Lecb_ret
+.align 16
+.Lecb_enc_three:
+ call _aesni_encrypt3
+ movups $inout0,($out)
+ movups $inout1,0x10($out)
+ movups $inout2,0x20($out)
+ jmp .Lecb_ret
+.align 16
+.Lecb_enc_four:
+ call _aesni_encrypt4
+ movups $inout0,($out)
+ movups $inout1,0x10($out)
+ movups $inout2,0x20($out)
+ movups $inout3,0x30($out)
+ jmp .Lecb_ret
+.align 16
+.Lecb_enc_five:
+ xorps $inout5,$inout5
+ call _aesni_encrypt6
+ movups $inout0,($out)
+ movups $inout1,0x10($out)
+ movups $inout2,0x20($out)
+ movups $inout3,0x30($out)
+ movups $inout4,0x40($out)
+ jmp .Lecb_ret
+.align 16
+.Lecb_enc_six:
+ call _aesni_encrypt6
+ movups $inout0,($out)
+ movups $inout1,0x10($out)
+ movups $inout2,0x20($out)
+ movups $inout3,0x30($out)
+ movups $inout4,0x40($out)
+ movups $inout5,0x50($out)
+ jmp .Lecb_ret
+#--------------------------- ECB DECRYPT ------------------------------#
+.align 16
+.Lecb_decrypt:
+ cmp \$0x80,$len
+ jb .Lecb_dec_tail
+
+ movdqu ($inp),$inout0
+ movdqu 0x10($inp),$inout1
+ movdqu 0x20($inp),$inout2
+ movdqu 0x30($inp),$inout3
+ movdqu 0x40($inp),$inout4
+ movdqu 0x50($inp),$inout5
+ movdqu 0x60($inp),$inout6
+ movdqu 0x70($inp),$inout7
+ lea 0x80($inp),$inp
+ sub \$0x80,$len
+ jmp .Lecb_dec_loop8_enter
+.align 16
+.Lecb_dec_loop8:
+ movups $inout0,($out)
+ mov $key_,$key # restore $key
+ movdqu ($inp),$inout0
+ mov $rnds_,$rounds # restore $rounds
+ movups $inout1,0x10($out)
+ movdqu 0x10($inp),$inout1
+ movups $inout2,0x20($out)
+ movdqu 0x20($inp),$inout2
+ movups $inout3,0x30($out)
+ movdqu 0x30($inp),$inout3
+ movups $inout4,0x40($out)
+ movdqu 0x40($inp),$inout4
+ movups $inout5,0x50($out)
+ movdqu 0x50($inp),$inout5
+ movups $inout6,0x60($out)
+ movdqu 0x60($inp),$inout6
+ movups $inout7,0x70($out)
+ lea 0x80($out),$out
+ movdqu 0x70($inp),$inout7
+ lea 0x80($inp),$inp
+.Lecb_dec_loop8_enter:
+
+ call _aesni_decrypt8
+
+ $movkey ($key_),$rndkey0
+ sub \$0x80,$len
+ jnc .Lecb_dec_loop8
+
+ movups $inout0,($out)
+ mov $key_,$key # restore $key
+ movups $inout1,0x10($out)
+ mov $rnds_,$rounds # restore $rounds
+ movups $inout2,0x20($out)
+ movups $inout3,0x30($out)
+ movups $inout4,0x40($out)
+ movups $inout5,0x50($out)
+ movups $inout6,0x60($out)
+ movups $inout7,0x70($out)
+ lea 0x80($out),$out
+ add \$0x80,$len
+ jz .Lecb_ret
+
+.Lecb_dec_tail:
+ movups ($inp),$inout0
+ cmp \$0x20,$len
+ jb .Lecb_dec_one
+ movups 0x10($inp),$inout1
+ je .Lecb_dec_two
+ movups 0x20($inp),$inout2
+ cmp \$0x40,$len
+ jb .Lecb_dec_three
+ movups 0x30($inp),$inout3
+ je .Lecb_dec_four
+ movups 0x40($inp),$inout4
+ cmp \$0x60,$len
+ jb .Lecb_dec_five
+ movups 0x50($inp),$inout5
+ je .Lecb_dec_six
+ movups 0x60($inp),$inout6
+ $movkey ($key),$rndkey0
+ call _aesni_decrypt8
+ movups $inout0,($out)
+ movups $inout1,0x10($out)
+ movups $inout2,0x20($out)
+ movups $inout3,0x30($out)
+ movups $inout4,0x40($out)
+ movups $inout5,0x50($out)
+ movups $inout6,0x60($out)
+ jmp .Lecb_ret
+.align 16
+.Lecb_dec_one:
+___
+ &aesni_generate1("dec",$key,$rounds);
+$code.=<<___;
+ movups $inout0,($out)
+ jmp .Lecb_ret
+.align 16
+.Lecb_dec_two:
+ xorps $inout2,$inout2
+ call _aesni_decrypt3
+ movups $inout0,($out)
+ movups $inout1,0x10($out)
+ jmp .Lecb_ret
+.align 16
+.Lecb_dec_three:
+ call _aesni_decrypt3
+ movups $inout0,($out)
+ movups $inout1,0x10($out)
+ movups $inout2,0x20($out)
+ jmp .Lecb_ret
+.align 16
+.Lecb_dec_four:
+ call _aesni_decrypt4
+ movups $inout0,($out)
+ movups $inout1,0x10($out)
+ movups $inout2,0x20($out)
+ movups $inout3,0x30($out)
+ jmp .Lecb_ret
+.align 16
+.Lecb_dec_five:
+ xorps $inout5,$inout5
+ call _aesni_decrypt6
+ movups $inout0,($out)
+ movups $inout1,0x10($out)
+ movups $inout2,0x20($out)
+ movups $inout3,0x30($out)
+ movups $inout4,0x40($out)
+ jmp .Lecb_ret
+.align 16
+.Lecb_dec_six:
+ call _aesni_decrypt6
+ movups $inout0,($out)
+ movups $inout1,0x10($out)
+ movups $inout2,0x20($out)
+ movups $inout3,0x30($out)
+ movups $inout4,0x40($out)
+ movups $inout5,0x50($out)
+
+.Lecb_ret:
+ ret
+.size aesni_ecb_encrypt,.-aesni_ecb_encrypt
+___
+
+{
+######################################################################
+# void aesni_ccm64_[en|de]crypt_blocks (const void *in, void *out,
+# size_t blocks, const AES_KEY *key,
+# const char *ivec,char *cmac);
+#
+# Handles only complete blocks, operates on 64-bit counter and
+# does not update *ivec! Nor does it finalize CMAC value
+# (see engine/eng_aesni.c for details)
+#
+{
+my $cmac="%r9"; # 6th argument
+
+my $increment="%xmm6";
+my $bswap_mask="%xmm7";
+
+$code.=<<___;
+.globl aesni_ccm64_encrypt_blocks
+.type aesni_ccm64_encrypt_blocks,\@function,6
+.align 16
+aesni_ccm64_encrypt_blocks:
+___
+$code.=<<___ if ($win64);
+ lea -0x58(%rsp),%rsp
+ movaps %xmm6,(%rsp)
+ movaps %xmm7,0x10(%rsp)
+ movaps %xmm8,0x20(%rsp)
+ movaps %xmm9,0x30(%rsp)
+.Lccm64_enc_body:
+___
+$code.=<<___;
+ mov 240($key),$rounds # key->rounds
+ movdqu ($ivp),$iv
+ movdqa .Lincrement64(%rip),$increment
+ movdqa .Lbswap_mask(%rip),$bswap_mask
+
+ shr \$1,$rounds
+ lea 0($key),$key_
+ movdqu ($cmac),$inout1
+ movdqa $iv,$inout0
+ mov $rounds,$rnds_
+ pshufb $bswap_mask,$iv
+ jmp .Lccm64_enc_outer
+.align 16
+.Lccm64_enc_outer:
+ $movkey ($key_),$rndkey0
+ mov $rnds_,$rounds
+ movups ($inp),$in0 # load inp
+
+ xorps $rndkey0,$inout0 # counter
+ $movkey 16($key_),$rndkey1
+ xorps $in0,$rndkey0
+ lea 32($key_),$key
+ xorps $rndkey0,$inout1 # cmac^=inp
+ $movkey ($key),$rndkey0
+
+.Lccm64_enc2_loop:
+ aesenc $rndkey1,$inout0
+ dec $rounds
+ aesenc $rndkey1,$inout1
+ $movkey 16($key),$rndkey1
+ aesenc $rndkey0,$inout0
+ lea 32($key),$key
+ aesenc $rndkey0,$inout1
+ $movkey 0($key),$rndkey0
+ jnz .Lccm64_enc2_loop
+ aesenc $rndkey1,$inout0
+ aesenc $rndkey1,$inout1
+ paddq $increment,$iv
+ aesenclast $rndkey0,$inout0
+ aesenclast $rndkey0,$inout1
+
+ dec $len
+ lea 16($inp),$inp
+ xorps $inout0,$in0 # inp ^= E(iv)
+ movdqa $iv,$inout0
+ movups $in0,($out) # save output
+ lea 16($out),$out
+ pshufb $bswap_mask,$inout0
+ jnz .Lccm64_enc_outer
+
+ movups $inout1,($cmac)
+___
+$code.=<<___ if ($win64);
+ movaps (%rsp),%xmm6
+ movaps 0x10(%rsp),%xmm7
+ movaps 0x20(%rsp),%xmm8
+ movaps 0x30(%rsp),%xmm9
+ lea 0x58(%rsp),%rsp
+.Lccm64_enc_ret:
+___
+$code.=<<___;
+ ret
+.size aesni_ccm64_encrypt_blocks,.-aesni_ccm64_encrypt_blocks
+___
+######################################################################
+$code.=<<___;
+.globl aesni_ccm64_decrypt_blocks
+.type aesni_ccm64_decrypt_blocks,\@function,6
+.align 16
+aesni_ccm64_decrypt_blocks:
+___
+$code.=<<___ if ($win64);
+ lea -0x58(%rsp),%rsp
+ movaps %xmm6,(%rsp)
+ movaps %xmm7,0x10(%rsp)
+ movaps %xmm8,0x20(%rsp)
+ movaps %xmm9,0x30(%rsp)
+.Lccm64_dec_body:
+___
+$code.=<<___;
+ mov 240($key),$rounds # key->rounds
+ movups ($ivp),$iv
+ movdqu ($cmac),$inout1
+ movdqa .Lincrement64(%rip),$increment
+ movdqa .Lbswap_mask(%rip),$bswap_mask
+
+ movaps $iv,$inout0
+ mov $rounds,$rnds_
+ mov $key,$key_
+ pshufb $bswap_mask,$iv
+___
+ &aesni_generate1("enc",$key,$rounds);
+$code.=<<___;
+ movups ($inp),$in0 # load inp
+ paddq $increment,$iv
+ lea 16($inp),$inp
+ jmp .Lccm64_dec_outer
+.align 16
+.Lccm64_dec_outer:
+ xorps $inout0,$in0 # inp ^= E(iv)
+ movdqa $iv,$inout0
+ mov $rnds_,$rounds
+ movups $in0,($out) # save output
+ lea 16($out),$out
+ pshufb $bswap_mask,$inout0
+
+ sub \$1,$len
+ jz .Lccm64_dec_break
+
+ $movkey ($key_),$rndkey0
+ shr \$1,$rounds
+ $movkey 16($key_),$rndkey1
+ xorps $rndkey0,$in0
+ lea 32($key_),$key
+ xorps $rndkey0,$inout0
+ xorps $in0,$inout1 # cmac^=out
+ $movkey ($key),$rndkey0
+
+.Lccm64_dec2_loop:
+ aesenc $rndkey1,$inout0
+ dec $rounds
+ aesenc $rndkey1,$inout1
+ $movkey 16($key),$rndkey1
+ aesenc $rndkey0,$inout0
+ lea 32($key),$key
+ aesenc $rndkey0,$inout1
+ $movkey 0($key),$rndkey0
+ jnz .Lccm64_dec2_loop
+ movups ($inp),$in0 # load inp
+ paddq $increment,$iv
+ aesenc $rndkey1,$inout0
+ aesenc $rndkey1,$inout1
+ lea 16($inp),$inp
+ aesenclast $rndkey0,$inout0
+ aesenclast $rndkey0,$inout1
+ jmp .Lccm64_dec_outer
+
+.align 16
+.Lccm64_dec_break:
+ #xorps $in0,$inout1 # cmac^=out
+___
+ &aesni_generate1("enc",$key_,$rounds,$inout1,$in0);
+$code.=<<___;
+ movups $inout1,($cmac)
+___
+$code.=<<___ if ($win64);
+ movaps (%rsp),%xmm6
+ movaps 0x10(%rsp),%xmm7
+ movaps 0x20(%rsp),%xmm8
+ movaps 0x30(%rsp),%xmm9
+ lea 0x58(%rsp),%rsp
+.Lccm64_dec_ret:
+___
+$code.=<<___;
+ ret
+.size aesni_ccm64_decrypt_blocks,.-aesni_ccm64_decrypt_blocks
+___
+}
+######################################################################
+# void aesni_ctr32_encrypt_blocks (const void *in, void *out,
+# size_t blocks, const AES_KEY *key,
+# const char *ivec);
+#
+# Handles only complete blocks, operates on 32-bit counter and
+# does not update *ivec! (see engine/eng_aesni.c for details)
+#
+{
+my $reserved = $win64?0:-0x28;
+my ($in0,$in1,$in2,$in3)=map("%xmm$_",(8..11));
+my ($iv0,$iv1,$ivec)=("%xmm12","%xmm13","%xmm14");
+my $bswap_mask="%xmm15";
+
+$code.=<<___;
+.globl aesni_ctr32_encrypt_blocks
+.type aesni_ctr32_encrypt_blocks,\@function,5
+.align 16
+aesni_ctr32_encrypt_blocks:
+___
+$code.=<<___ if ($win64);
+ lea -0xc8(%rsp),%rsp
+ movaps %xmm6,0x20(%rsp)
+ movaps %xmm7,0x30(%rsp)
+ movaps %xmm8,0x40(%rsp)
+ movaps %xmm9,0x50(%rsp)
+ movaps %xmm10,0x60(%rsp)
+ movaps %xmm11,0x70(%rsp)
+ movaps %xmm12,0x80(%rsp)
+ movaps %xmm13,0x90(%rsp)
+ movaps %xmm14,0xa0(%rsp)
+ movaps %xmm15,0xb0(%rsp)
+.Lctr32_body:
+___
+$code.=<<___;
+ cmp \$1,$len
+ je .Lctr32_one_shortcut
+
+ movdqu ($ivp),$ivec
+ movdqa .Lbswap_mask(%rip),$bswap_mask
+ xor $rounds,$rounds
+ pextrd \$3,$ivec,$rnds_ # pull 32-bit counter
+ pinsrd \$3,$rounds,$ivec # wipe 32-bit counter
+
+ mov 240($key),$rounds # key->rounds
+ bswap $rnds_
+ pxor $iv0,$iv0 # vector of 3 32-bit counters
+ pxor $iv1,$iv1 # vector of 3 32-bit counters
+ pinsrd \$0,$rnds_,$iv0
+ lea 3($rnds_),$key_
+ pinsrd \$0,$key_,$iv1
+ inc $rnds_
+ pinsrd \$1,$rnds_,$iv0
+ inc $key_
+ pinsrd \$1,$key_,$iv1
+ inc $rnds_
+ pinsrd \$2,$rnds_,$iv0
+ inc $key_
+ pinsrd \$2,$key_,$iv1
+ movdqa $iv0,$reserved(%rsp)
+ pshufb $bswap_mask,$iv0
+ movdqa $iv1,`$reserved+0x10`(%rsp)
+ pshufb $bswap_mask,$iv1
+
+ pshufd \$`3<<6`,$iv0,$inout0 # place counter to upper dword
+ pshufd \$`2<<6`,$iv0,$inout1
+ pshufd \$`1<<6`,$iv0,$inout2
+ cmp \$6,$len
+ jb .Lctr32_tail
+ shr \$1,$rounds
+ mov $key,$key_ # backup $key
+ mov $rounds,$rnds_ # backup $rounds
+ sub \$6,$len
+ jmp .Lctr32_loop6
+
+.align 16
+.Lctr32_loop6:
+ pshufd \$`3<<6`,$iv1,$inout3
+ por $ivec,$inout0 # merge counter-less ivec
+ $movkey ($key_),$rndkey0
+ pshufd \$`2<<6`,$iv1,$inout4
+ por $ivec,$inout1
+ $movkey 16($key_),$rndkey1
+ pshufd \$`1<<6`,$iv1,$inout5
+ por $ivec,$inout2
+ por $ivec,$inout3
+ xorps $rndkey0,$inout0
+ por $ivec,$inout4
+ por $ivec,$inout5
+
+ # inline _aesni_encrypt6 and interleave last rounds
+ # with own code...
+
+ pxor $rndkey0,$inout1
+ aesenc $rndkey1,$inout0
+ lea 32($key_),$key
+ pxor $rndkey0,$inout2
+ aesenc $rndkey1,$inout1
+ movdqa .Lincrement32(%rip),$iv1
+ pxor $rndkey0,$inout3
+ aesenc $rndkey1,$inout2
+ movdqa $reserved(%rsp),$iv0
+ pxor $rndkey0,$inout4
+ aesenc $rndkey1,$inout3
+ pxor $rndkey0,$inout5
+ $movkey ($key),$rndkey0
+ dec $rounds
+ aesenc $rndkey1,$inout4
+ aesenc $rndkey1,$inout5
+ jmp .Lctr32_enc_loop6_enter
+.align 16
+.Lctr32_enc_loop6:
+ aesenc $rndkey1,$inout0
+ aesenc $rndkey1,$inout1
+ dec $rounds
+ aesenc $rndkey1,$inout2
+ aesenc $rndkey1,$inout3
+ aesenc $rndkey1,$inout4
+ aesenc $rndkey1,$inout5
+.Lctr32_enc_loop6_enter:
+ $movkey 16($key),$rndkey1
+ aesenc $rndkey0,$inout0
+ aesenc $rndkey0,$inout1
+ lea 32($key),$key
+ aesenc $rndkey0,$inout2
+ aesenc $rndkey0,$inout3
+ aesenc $rndkey0,$inout4
+ aesenc $rndkey0,$inout5
+ $movkey ($key),$rndkey0
+ jnz .Lctr32_enc_loop6
+
+ aesenc $rndkey1,$inout0
+ paddd $iv1,$iv0 # increment counter vector
+ aesenc $rndkey1,$inout1
+ paddd `$reserved+0x10`(%rsp),$iv1
+ aesenc $rndkey1,$inout2
+ movdqa $iv0,$reserved(%rsp) # save counter vector
+ aesenc $rndkey1,$inout3
+ movdqa $iv1,`$reserved+0x10`(%rsp)
+ aesenc $rndkey1,$inout4
+ pshufb $bswap_mask,$iv0 # byte swap
+ aesenc $rndkey1,$inout5
+ pshufb $bswap_mask,$iv1
+
+ aesenclast $rndkey0,$inout0
+ movups ($inp),$in0 # load input
+ aesenclast $rndkey0,$inout1
+ movups 0x10($inp),$in1
+ aesenclast $rndkey0,$inout2
+ movups 0x20($inp),$in2
+ aesenclast $rndkey0,$inout3
+ movups 0x30($inp),$in3
+ aesenclast $rndkey0,$inout4
+ movups 0x40($inp),$rndkey1
+ aesenclast $rndkey0,$inout5
+ movups 0x50($inp),$rndkey0
+ lea 0x60($inp),$inp
+
+ xorps $inout0,$in0 # xor
+ pshufd \$`3<<6`,$iv0,$inout0
+ xorps $inout1,$in1
+ pshufd \$`2<<6`,$iv0,$inout1
+ movups $in0,($out) # store output
+ xorps $inout2,$in2
+ pshufd \$`1<<6`,$iv0,$inout2
+ movups $in1,0x10($out)
+ xorps $inout3,$in3
+ movups $in2,0x20($out)
+ xorps $inout4,$rndkey1
+ movups $in3,0x30($out)
+ xorps $inout5,$rndkey0
+ movups $rndkey1,0x40($out)
+ movups $rndkey0,0x50($out)
+ lea 0x60($out),$out
+ mov $rnds_,$rounds
+ sub \$6,$len
+ jnc .Lctr32_loop6
+
+ add \$6,$len
+ jz .Lctr32_done
+ mov $key_,$key # restore $key
+ lea 1($rounds,$rounds),$rounds # restore original value
+
+.Lctr32_tail:
+ por $ivec,$inout0
+ movups ($inp),$in0
+ cmp \$2,$len
+ jb .Lctr32_one
+
+ por $ivec,$inout1
+ movups 0x10($inp),$in1
+ je .Lctr32_two
+
+ pshufd \$`3<<6`,$iv1,$inout3
+ por $ivec,$inout2
+ movups 0x20($inp),$in2
+ cmp \$4,$len
+ jb .Lctr32_three
+
+ pshufd \$`2<<6`,$iv1,$inout4
+ por $ivec,$inout3
+ movups 0x30($inp),$in3
+ je .Lctr32_four
+
+ por $ivec,$inout4
+ xorps $inout5,$inout5
+
+ call _aesni_encrypt6
+
+ movups 0x40($inp),$rndkey1
+ xorps $inout0,$in0
+ xorps $inout1,$in1
+ movups $in0,($out)
+ xorps $inout2,$in2
+ movups $in1,0x10($out)
+ xorps $inout3,$in3
+ movups $in2,0x20($out)
+ xorps $inout4,$rndkey1
+ movups $in3,0x30($out)
+ movups $rndkey1,0x40($out)
+ jmp .Lctr32_done
+
+.align 16
+.Lctr32_one_shortcut:
+ movups ($ivp),$inout0
+ movups ($inp),$in0
+ mov 240($key),$rounds # key->rounds
+.Lctr32_one:
+___
+ &aesni_generate1("enc",$key,$rounds);
+$code.=<<___;
+ xorps $inout0,$in0
+ movups $in0,($out)
+ jmp .Lctr32_done
+
+.align 16
+.Lctr32_two:
+ xorps $inout2,$inout2
+ call _aesni_encrypt3
+ xorps $inout0,$in0
+ xorps $inout1,$in1
+ movups $in0,($out)
+ movups $in1,0x10($out)
+ jmp .Lctr32_done
+
+.align 16
+.Lctr32_three:
+ call _aesni_encrypt3
+ xorps $inout0,$in0
+ xorps $inout1,$in1
+ movups $in0,($out)
+ xorps $inout2,$in2
+ movups $in1,0x10($out)
+ movups $in2,0x20($out)
+ jmp .Lctr32_done
+
+.align 16
+.Lctr32_four:
+ call _aesni_encrypt4
+ xorps $inout0,$in0
+ xorps $inout1,$in1
+ movups $in0,($out)
+ xorps $inout2,$in2
+ movups $in1,0x10($out)
+ xorps $inout3,$in3
+ movups $in2,0x20($out)
+ movups $in3,0x30($out)
+
+.Lctr32_done:
+___
+$code.=<<___ if ($win64);
+ movaps 0x20(%rsp),%xmm6
+ movaps 0x30(%rsp),%xmm7
+ movaps 0x40(%rsp),%xmm8
+ movaps 0x50(%rsp),%xmm9
+ movaps 0x60(%rsp),%xmm10
+ movaps 0x70(%rsp),%xmm11
+ movaps 0x80(%rsp),%xmm12
+ movaps 0x90(%rsp),%xmm13
+ movaps 0xa0(%rsp),%xmm14
+ movaps 0xb0(%rsp),%xmm15
+ lea 0xc8(%rsp),%rsp
+.Lctr32_ret:
+___
+$code.=<<___;
+ ret
+.size aesni_ctr32_encrypt_blocks,.-aesni_ctr32_encrypt_blocks
+___
+}
+
+######################################################################
+# void aesni_xts_[en|de]crypt(const char *inp,char *out,size_t len,
+# const AES_KEY *key1, const AES_KEY *key2
+# const unsigned char iv[16]);
+#
+{
+my @tweak=map("%xmm$_",(10..15));
+my ($twmask,$twres,$twtmp)=("%xmm8","%xmm9",@tweak[4]);
+my ($key2,$ivp,$len_)=("%r8","%r9","%r9");
+my $frame_size = 0x68 + ($win64?160:0);
+
+$code.=<<___;
+.globl aesni_xts_encrypt
+.type aesni_xts_encrypt,\@function,6
+.align 16
+aesni_xts_encrypt:
+ lea -$frame_size(%rsp),%rsp
+___
+$code.=<<___ if ($win64);
+ movaps %xmm6,0x60(%rsp)
+ movaps %xmm7,0x70(%rsp)
+ movaps %xmm8,0x80(%rsp)
+ movaps %xmm9,0x90(%rsp)
+ movaps %xmm10,0xa0(%rsp)
+ movaps %xmm11,0xb0(%rsp)
+ movaps %xmm12,0xc0(%rsp)
+ movaps %xmm13,0xd0(%rsp)
+ movaps %xmm14,0xe0(%rsp)
+ movaps %xmm15,0xf0(%rsp)
+.Lxts_enc_body:
+___
+$code.=<<___;
+ movups ($ivp),@tweak[5] # load clear-text tweak
+ mov 240(%r8),$rounds # key2->rounds
+ mov 240($key),$rnds_ # key1->rounds
+___
+ # generate the tweak
+ &aesni_generate1("enc",$key2,$rounds,@tweak[5]);
+$code.=<<___;
+ mov $key,$key_ # backup $key
+ mov $rnds_,$rounds # backup $rounds
+ mov $len,$len_ # backup $len
+ and \$-16,$len
+
+ movdqa .Lxts_magic(%rip),$twmask
+ pxor $twtmp,$twtmp
+ pcmpgtd @tweak[5],$twtmp # broadcast upper bits
+___
+ for ($i=0;$i<4;$i++) {
+ $code.=<<___;
+ pshufd \$0x13,$twtmp,$twres
+ pxor $twtmp,$twtmp
+ movdqa @tweak[5],@tweak[$i]
+ paddq @tweak[5],@tweak[5] # psllq 1,$tweak
+ pand $twmask,$twres # isolate carry and residue
+ pcmpgtd @tweak[5],$twtmp # broadcat upper bits
+ pxor $twres,@tweak[5]
+___
+ }
+$code.=<<___;
+ sub \$16*6,$len
+ jc .Lxts_enc_short
+
+ shr \$1,$rounds
+ sub \$1,$rounds
+ mov $rounds,$rnds_
+ jmp .Lxts_enc_grandloop
+
+.align 16
+.Lxts_enc_grandloop:
+ pshufd \$0x13,$twtmp,$twres
+ movdqa @tweak[5],@tweak[4]
+ paddq @tweak[5],@tweak[5] # psllq 1,$tweak
+ movdqu `16*0`($inp),$inout0 # load input
+ pand $twmask,$twres # isolate carry and residue
+ movdqu `16*1`($inp),$inout1
+ pxor $twres,@tweak[5]
+
+ movdqu `16*2`($inp),$inout2
+ pxor @tweak[0],$inout0 # input^=tweak
+ movdqu `16*3`($inp),$inout3
+ pxor @tweak[1],$inout1
+ movdqu `16*4`($inp),$inout4
+ pxor @tweak[2],$inout2
+ movdqu `16*5`($inp),$inout5
+ lea `16*6`($inp),$inp
+ pxor @tweak[3],$inout3
+ $movkey ($key_),$rndkey0
+ pxor @tweak[4],$inout4
+ pxor @tweak[5],$inout5
+
+ # inline _aesni_encrypt6 and interleave first and last rounds
+ # with own code...
+ $movkey 16($key_),$rndkey1
+ pxor $rndkey0,$inout0
+ pxor $rndkey0,$inout1
+ movdqa @tweak[0],`16*0`(%rsp) # put aside tweaks
+ aesenc $rndkey1,$inout0
+ lea 32($key_),$key
+ pxor $rndkey0,$inout2
+ movdqa @tweak[1],`16*1`(%rsp)
+ aesenc $rndkey1,$inout1
+ pxor $rndkey0,$inout3
+ movdqa @tweak[2],`16*2`(%rsp)
+ aesenc $rndkey1,$inout2
+ pxor $rndkey0,$inout4
+ movdqa @tweak[3],`16*3`(%rsp)
+ aesenc $rndkey1,$inout3
+ pxor $rndkey0,$inout5
+ $movkey ($key),$rndkey0
+ dec $rounds
+ movdqa @tweak[4],`16*4`(%rsp)
+ aesenc $rndkey1,$inout4
+ movdqa @tweak[5],`16*5`(%rsp)
+ aesenc $rndkey1,$inout5
+ pxor $twtmp,$twtmp
+ pcmpgtd @tweak[5],$twtmp
+ jmp .Lxts_enc_loop6_enter
+
+.align 16
+.Lxts_enc_loop6:
+ aesenc $rndkey1,$inout0
+ aesenc $rndkey1,$inout1
+ dec $rounds
+ aesenc $rndkey1,$inout2
+ aesenc $rndkey1,$inout3
+ aesenc $rndkey1,$inout4
+ aesenc $rndkey1,$inout5
+.Lxts_enc_loop6_enter:
+ $movkey 16($key),$rndkey1
+ aesenc $rndkey0,$inout0
+ aesenc $rndkey0,$inout1
+ lea 32($key),$key
+ aesenc $rndkey0,$inout2
+ aesenc $rndkey0,$inout3
+ aesenc $rndkey0,$inout4
+ aesenc $rndkey0,$inout5
+ $movkey ($key),$rndkey0
+ jnz .Lxts_enc_loop6
+
+ pshufd \$0x13,$twtmp,$twres
+ pxor $twtmp,$twtmp
+ paddq @tweak[5],@tweak[5] # psllq 1,$tweak
+ aesenc $rndkey1,$inout0
+ pand $twmask,$twres # isolate carry and residue
+ aesenc $rndkey1,$inout1
+ pcmpgtd @tweak[5],$twtmp # broadcast upper bits
+ aesenc $rndkey1,$inout2
+ pxor $twres,@tweak[5]
+ aesenc $rndkey1,$inout3
+ aesenc $rndkey1,$inout4
+ aesenc $rndkey1,$inout5
+ $movkey 16($key),$rndkey1
+
+ pshufd \$0x13,$twtmp,$twres
+ pxor $twtmp,$twtmp
+ movdqa @tweak[5],@tweak[0]
+ paddq @tweak[5],@tweak[5] # psllq 1,$tweak
+ aesenc $rndkey0,$inout0
+ pand $twmask,$twres # isolate carry and residue
+ aesenc $rndkey0,$inout1
+ pcmpgtd @tweak[5],$twtmp # broadcat upper bits
+ aesenc $rndkey0,$inout2
+ pxor $twres,@tweak[5]
+ aesenc $rndkey0,$inout3
+ aesenc $rndkey0,$inout4
+ aesenc $rndkey0,$inout5
+ $movkey 32($key),$rndkey0
+
+ pshufd \$0x13,$twtmp,$twres
+ pxor $twtmp,$twtmp
+ movdqa @tweak[5],@tweak[1]
+ paddq @tweak[5],@tweak[5] # psllq 1,$tweak
+ aesenc $rndkey1,$inout0
+ pand $twmask,$twres # isolate carry and residue
+ aesenc $rndkey1,$inout1
+ pcmpgtd @tweak[5],$twtmp # broadcat upper bits
+ aesenc $rndkey1,$inout2
+ pxor $twres,@tweak[5]
+ aesenc $rndkey1,$inout3
+ aesenc $rndkey1,$inout4
+ aesenc $rndkey1,$inout5
+
+ pshufd \$0x13,$twtmp,$twres
+ pxor $twtmp,$twtmp
+ movdqa @tweak[5],@tweak[2]
+ paddq @tweak[5],@tweak[5] # psllq 1,$tweak
+ aesenclast $rndkey0,$inout0
+ pand $twmask,$twres # isolate carry and residue
+ aesenclast $rndkey0,$inout1
+ pcmpgtd @tweak[5],$twtmp # broadcat upper bits
+ aesenclast $rndkey0,$inout2
+ pxor $twres,@tweak[5]
+ aesenclast $rndkey0,$inout3
+ aesenclast $rndkey0,$inout4
+ aesenclast $rndkey0,$inout5
+
+ pshufd \$0x13,$twtmp,$twres
+ pxor $twtmp,$twtmp
+ movdqa @tweak[5],@tweak[3]
+ paddq @tweak[5],@tweak[5] # psllq 1,$tweak
+ xorps `16*0`(%rsp),$inout0 # output^=tweak
+ pand $twmask,$twres # isolate carry and residue
+ xorps `16*1`(%rsp),$inout1
+ pcmpgtd @tweak[5],$twtmp # broadcat upper bits
+ pxor $twres,@tweak[5]
+
+ xorps `16*2`(%rsp),$inout2
+ movups $inout0,`16*0`($out) # write output
+ xorps `16*3`(%rsp),$inout3
+ movups $inout1,`16*1`($out)
+ xorps `16*4`(%rsp),$inout4
+ movups $inout2,`16*2`($out)
+ xorps `16*5`(%rsp),$inout5
+ movups $inout3,`16*3`($out)
+ mov $rnds_,$rounds # restore $rounds
+ movups $inout4,`16*4`($out)
+ movups $inout5,`16*5`($out)
+ lea `16*6`($out),$out
+ sub \$16*6,$len
+ jnc .Lxts_enc_grandloop
+
+ lea 3($rounds,$rounds),$rounds # restore original value
+ mov $key_,$key # restore $key
+ mov $rounds,$rnds_ # backup $rounds
+
+.Lxts_enc_short:
+ add \$16*6,$len
+ jz .Lxts_enc_done
+
+ cmp \$0x20,$len
+ jb .Lxts_enc_one
+ je .Lxts_enc_two
+
+ cmp \$0x40,$len
+ jb .Lxts_enc_three
+ je .Lxts_enc_four
+
+ pshufd \$0x13,$twtmp,$twres
+ movdqa @tweak[5],@tweak[4]
+ paddq @tweak[5],@tweak[5] # psllq 1,$tweak
+ movdqu ($inp),$inout0
+ pand $twmask,$twres # isolate carry and residue
+ movdqu 16*1($inp),$inout1
+ pxor $twres,@tweak[5]
+
+ movdqu 16*2($inp),$inout2
+ pxor @tweak[0],$inout0
+ movdqu 16*3($inp),$inout3
+ pxor @tweak[1],$inout1
+ movdqu 16*4($inp),$inout4
+ lea 16*5($inp),$inp
+ pxor @tweak[2],$inout2
+ pxor @tweak[3],$inout3
+ pxor @tweak[4],$inout4
+
+ call _aesni_encrypt6
+
+ xorps @tweak[0],$inout0
+ movdqa @tweak[5],@tweak[0]
+ xorps @tweak[1],$inout1
+ xorps @tweak[2],$inout2
+ movdqu $inout0,($out)
+ xorps @tweak[3],$inout3
+ movdqu $inout1,16*1($out)
+ xorps @tweak[4],$inout4
+ movdqu $inout2,16*2($out)
+ movdqu $inout3,16*3($out)
+ movdqu $inout4,16*4($out)
+ lea 16*5($out),$out
+ jmp .Lxts_enc_done
+
+.align 16
+.Lxts_enc_one:
+ movups ($inp),$inout0
+ lea 16*1($inp),$inp
+ xorps @tweak[0],$inout0
+___
+ &aesni_generate1("enc",$key,$rounds);
+$code.=<<___;
+ xorps @tweak[0],$inout0
+ movdqa @tweak[1],@tweak[0]
+ movups $inout0,($out)
+ lea 16*1($out),$out
+ jmp .Lxts_enc_done
+
+.align 16
+.Lxts_enc_two:
+ movups ($inp),$inout0
+ movups 16($inp),$inout1
+ lea 32($inp),$inp
+ xorps @tweak[0],$inout0
+ xorps @tweak[1],$inout1
+
+ call _aesni_encrypt3
+
+ xorps @tweak[0],$inout0
+ movdqa @tweak[2],@tweak[0]
+ xorps @tweak[1],$inout1
+ movups $inout0,($out)
+ movups $inout1,16*1($out)
+ lea 16*2($out),$out
+ jmp .Lxts_enc_done
+
+.align 16
+.Lxts_enc_three:
+ movups ($inp),$inout0
+ movups 16*1($inp),$inout1
+ movups 16*2($inp),$inout2
+ lea 16*3($inp),$inp
+ xorps @tweak[0],$inout0
+ xorps @tweak[1],$inout1
+ xorps @tweak[2],$inout2
+
+ call _aesni_encrypt3
+
+ xorps @tweak[0],$inout0
+ movdqa @tweak[3],@tweak[0]
+ xorps @tweak[1],$inout1
+ xorps @tweak[2],$inout2
+ movups $inout0,($out)
+ movups $inout1,16*1($out)
+ movups $inout2,16*2($out)
+ lea 16*3($out),$out
+ jmp .Lxts_enc_done
+
+.align 16
+.Lxts_enc_four:
+ movups ($inp),$inout0
+ movups 16*1($inp),$inout1
+ movups 16*2($inp),$inout2
+ xorps @tweak[0],$inout0
+ movups 16*3($inp),$inout3
+ lea 16*4($inp),$inp
+ xorps @tweak[1],$inout1
+ xorps @tweak[2],$inout2
+ xorps @tweak[3],$inout3
+
+ call _aesni_encrypt4
+
+ xorps @tweak[0],$inout0
+ movdqa @tweak[5],@tweak[0]
+ xorps @tweak[1],$inout1
+ xorps @tweak[2],$inout2
+ movups $inout0,($out)
+ xorps @tweak[3],$inout3
+ movups $inout1,16*1($out)
+ movups $inout2,16*2($out)
+ movups $inout3,16*3($out)
+ lea 16*4($out),$out
+ jmp .Lxts_enc_done
+
+.align 16
+.Lxts_enc_done:
+ and \$15,$len_
+ jz .Lxts_enc_ret
+ mov $len_,$len
+
+.Lxts_enc_steal:
+ movzb ($inp),%eax # borrow $rounds ...
+ movzb -16($out),%ecx # ... and $key
+ lea 1($inp),$inp
+ mov %al,-16($out)
+ mov %cl,0($out)
+ lea 1($out),$out
+ sub \$1,$len
+ jnz .Lxts_enc_steal
+
+ sub $len_,$out # rewind $out
+ mov $key_,$key # restore $key
+ mov $rnds_,$rounds # restore $rounds
+
+ movups -16($out),$inout0
+ xorps @tweak[0],$inout0
+___
+ &aesni_generate1("enc",$key,$rounds);
+$code.=<<___;
+ xorps @tweak[0],$inout0
+ movups $inout0,-16($out)
+
+.Lxts_enc_ret:
+___
+$code.=<<___ if ($win64);
+ movaps 0x60(%rsp),%xmm6
+ movaps 0x70(%rsp),%xmm7
+ movaps 0x80(%rsp),%xmm8
+ movaps 0x90(%rsp),%xmm9
+ movaps 0xa0(%rsp),%xmm10
+ movaps 0xb0(%rsp),%xmm11
+ movaps 0xc0(%rsp),%xmm12
+ movaps 0xd0(%rsp),%xmm13
+ movaps 0xe0(%rsp),%xmm14
+ movaps 0xf0(%rsp),%xmm15
+___
+$code.=<<___;
+ lea $frame_size(%rsp),%rsp
+.Lxts_enc_epilogue:
+ ret
+.size aesni_xts_encrypt,.-aesni_xts_encrypt
+___
+
+$code.=<<___;
+.globl aesni_xts_decrypt
+.type aesni_xts_decrypt,\@function,6
+.align 16
+aesni_xts_decrypt:
+ lea -$frame_size(%rsp),%rsp
+___
+$code.=<<___ if ($win64);
+ movaps %xmm6,0x60(%rsp)
+ movaps %xmm7,0x70(%rsp)
+ movaps %xmm8,0x80(%rsp)
+ movaps %xmm9,0x90(%rsp)
+ movaps %xmm10,0xa0(%rsp)
+ movaps %xmm11,0xb0(%rsp)
+ movaps %xmm12,0xc0(%rsp)
+ movaps %xmm13,0xd0(%rsp)
+ movaps %xmm14,0xe0(%rsp)
+ movaps %xmm15,0xf0(%rsp)
+.Lxts_dec_body:
+___
+$code.=<<___;
+ movups ($ivp),@tweak[5] # load clear-text tweak
+ mov 240($key2),$rounds # key2->rounds
+ mov 240($key),$rnds_ # key1->rounds
+___
+ # generate the tweak
+ &aesni_generate1("enc",$key2,$rounds,@tweak[5]);
+$code.=<<___;
+ xor %eax,%eax # if ($len%16) len-=16;
+ test \$15,$len
+ setnz %al
+ shl \$4,%rax
+ sub %rax,$len
+
+ mov $key,$key_ # backup $key
+ mov $rnds_,$rounds # backup $rounds
+ mov $len,$len_ # backup $len
+ and \$-16,$len
+
+ movdqa .Lxts_magic(%rip),$twmask
+ pxor $twtmp,$twtmp
+ pcmpgtd @tweak[5],$twtmp # broadcast upper bits
+___
+ for ($i=0;$i<4;$i++) {
+ $code.=<<___;
+ pshufd \$0x13,$twtmp,$twres
+ pxor $twtmp,$twtmp
+ movdqa @tweak[5],@tweak[$i]
+ paddq @tweak[5],@tweak[5] # psllq 1,$tweak
+ pand $twmask,$twres # isolate carry and residue
+ pcmpgtd @tweak[5],$twtmp # broadcat upper bits
+ pxor $twres,@tweak[5]
+___
+ }
+$code.=<<___;
+ sub \$16*6,$len
+ jc .Lxts_dec_short
+
+ shr \$1,$rounds
+ sub \$1,$rounds
+ mov $rounds,$rnds_
+ jmp .Lxts_dec_grandloop
+
+.align 16
+.Lxts_dec_grandloop:
+ pshufd \$0x13,$twtmp,$twres
+ movdqa @tweak[5],@tweak[4]
+ paddq @tweak[5],@tweak[5] # psllq 1,$tweak
+ movdqu `16*0`($inp),$inout0 # load input
+ pand $twmask,$twres # isolate carry and residue
+ movdqu `16*1`($inp),$inout1
+ pxor $twres,@tweak[5]
+
+ movdqu `16*2`($inp),$inout2
+ pxor @tweak[0],$inout0 # input^=tweak
+ movdqu `16*3`($inp),$inout3
+ pxor @tweak[1],$inout1
+ movdqu `16*4`($inp),$inout4
+ pxor @tweak[2],$inout2
+ movdqu `16*5`($inp),$inout5
+ lea `16*6`($inp),$inp
+ pxor @tweak[3],$inout3
+ $movkey ($key_),$rndkey0
+ pxor @tweak[4],$inout4
+ pxor @tweak[5],$inout5
+
+ # inline _aesni_decrypt6 and interleave first and last rounds
+ # with own code...
+ $movkey 16($key_),$rndkey1
+ pxor $rndkey0,$inout0
+ pxor $rndkey0,$inout1
+ movdqa @tweak[0],`16*0`(%rsp) # put aside tweaks
+ aesdec $rndkey1,$inout0
+ lea 32($key_),$key
+ pxor $rndkey0,$inout2
+ movdqa @tweak[1],`16*1`(%rsp)
+ aesdec $rndkey1,$inout1
+ pxor $rndkey0,$inout3
+ movdqa @tweak[2],`16*2`(%rsp)
+ aesdec $rndkey1,$inout2
+ pxor $rndkey0,$inout4
+ movdqa @tweak[3],`16*3`(%rsp)
+ aesdec $rndkey1,$inout3
+ pxor $rndkey0,$inout5
+ $movkey ($key),$rndkey0
+ dec $rounds
+ movdqa @tweak[4],`16*4`(%rsp)
+ aesdec $rndkey1,$inout4
+ movdqa @tweak[5],`16*5`(%rsp)
+ aesdec $rndkey1,$inout5
+ pxor $twtmp,$twtmp
+ pcmpgtd @tweak[5],$twtmp
+ jmp .Lxts_dec_loop6_enter
+
+.align 16
+.Lxts_dec_loop6:
+ aesdec $rndkey1,$inout0
+ aesdec $rndkey1,$inout1
+ dec $rounds
+ aesdec $rndkey1,$inout2
+ aesdec $rndkey1,$inout3
+ aesdec $rndkey1,$inout4
+ aesdec $rndkey1,$inout5
+.Lxts_dec_loop6_enter:
+ $movkey 16($key),$rndkey1
+ aesdec $rndkey0,$inout0
+ aesdec $rndkey0,$inout1
+ lea 32($key),$key
+ aesdec $rndkey0,$inout2
+ aesdec $rndkey0,$inout3
+ aesdec $rndkey0,$inout4
+ aesdec $rndkey0,$inout5
+ $movkey ($key),$rndkey0
+ jnz .Lxts_dec_loop6
+
+ pshufd \$0x13,$twtmp,$twres
+ pxor $twtmp,$twtmp
+ paddq @tweak[5],@tweak[5] # psllq 1,$tweak
+ aesdec $rndkey1,$inout0
+ pand $twmask,$twres # isolate carry and residue
+ aesdec $rndkey1,$inout1
+ pcmpgtd @tweak[5],$twtmp # broadcast upper bits
+ aesdec $rndkey1,$inout2
+ pxor $twres,@tweak[5]
+ aesdec $rndkey1,$inout3
+ aesdec $rndkey1,$inout4
+ aesdec $rndkey1,$inout5
+ $movkey 16($key),$rndkey1
+
+ pshufd \$0x13,$twtmp,$twres
+ pxor $twtmp,$twtmp
+ movdqa @tweak[5],@tweak[0]
+ paddq @tweak[5],@tweak[5] # psllq 1,$tweak
+ aesdec $rndkey0,$inout0
+ pand $twmask,$twres # isolate carry and residue
+ aesdec $rndkey0,$inout1
+ pcmpgtd @tweak[5],$twtmp # broadcat upper bits
+ aesdec $rndkey0,$inout2
+ pxor $twres,@tweak[5]
+ aesdec $rndkey0,$inout3
+ aesdec $rndkey0,$inout4
+ aesdec $rndkey0,$inout5
+ $movkey 32($key),$rndkey0
+
+ pshufd \$0x13,$twtmp,$twres
+ pxor $twtmp,$twtmp
+ movdqa @tweak[5],@tweak[1]
+ paddq @tweak[5],@tweak[5] # psllq 1,$tweak
+ aesdec $rndkey1,$inout0
+ pand $twmask,$twres # isolate carry and residue
+ aesdec $rndkey1,$inout1
+ pcmpgtd @tweak[5],$twtmp # broadcat upper bits
+ aesdec $rndkey1,$inout2
+ pxor $twres,@tweak[5]
+ aesdec $rndkey1,$inout3
+ aesdec $rndkey1,$inout4
+ aesdec $rndkey1,$inout5
+
+ pshufd \$0x13,$twtmp,$twres
+ pxor $twtmp,$twtmp
+ movdqa @tweak[5],@tweak[2]
+ paddq @tweak[5],@tweak[5] # psllq 1,$tweak
+ aesdeclast $rndkey0,$inout0
+ pand $twmask,$twres # isolate carry and residue
+ aesdeclast $rndkey0,$inout1
+ pcmpgtd @tweak[5],$twtmp # broadcat upper bits
+ aesdeclast $rndkey0,$inout2
+ pxor $twres,@tweak[5]
+ aesdeclast $rndkey0,$inout3
+ aesdeclast $rndkey0,$inout4
+ aesdeclast $rndkey0,$inout5
+
+ pshufd \$0x13,$twtmp,$twres
+ pxor $twtmp,$twtmp
+ movdqa @tweak[5],@tweak[3]
+ paddq @tweak[5],@tweak[5] # psllq 1,$tweak
+ xorps `16*0`(%rsp),$inout0 # output^=tweak
+ pand $twmask,$twres # isolate carry and residue
+ xorps `16*1`(%rsp),$inout1
+ pcmpgtd @tweak[5],$twtmp # broadcat upper bits
+ pxor $twres,@tweak[5]
+
+ xorps `16*2`(%rsp),$inout2
+ movups $inout0,`16*0`($out) # write output
+ xorps `16*3`(%rsp),$inout3
+ movups $inout1,`16*1`($out)
+ xorps `16*4`(%rsp),$inout4
+ movups $inout2,`16*2`($out)
+ xorps `16*5`(%rsp),$inout5
+ movups $inout3,`16*3`($out)
+ mov $rnds_,$rounds # restore $rounds
+ movups $inout4,`16*4`($out)
+ movups $inout5,`16*5`($out)
+ lea `16*6`($out),$out
+ sub \$16*6,$len
+ jnc .Lxts_dec_grandloop
+
+ lea 3($rounds,$rounds),$rounds # restore original value
+ mov $key_,$key # restore $key
+ mov $rounds,$rnds_ # backup $rounds
+
+.Lxts_dec_short:
+ add \$16*6,$len
+ jz .Lxts_dec_done
+
+ cmp \$0x20,$len
+ jb .Lxts_dec_one
+ je .Lxts_dec_two
+
+ cmp \$0x40,$len
+ jb .Lxts_dec_three
+ je .Lxts_dec_four
+
+ pshufd \$0x13,$twtmp,$twres
+ movdqa @tweak[5],@tweak[4]
+ paddq @tweak[5],@tweak[5] # psllq 1,$tweak
+ movdqu ($inp),$inout0
+ pand $twmask,$twres # isolate carry and residue
+ movdqu 16*1($inp),$inout1
+ pxor $twres,@tweak[5]
+
+ movdqu 16*2($inp),$inout2
+ pxor @tweak[0],$inout0
+ movdqu 16*3($inp),$inout3
+ pxor @tweak[1],$inout1
+ movdqu 16*4($inp),$inout4
+ lea 16*5($inp),$inp
+ pxor @tweak[2],$inout2
+ pxor @tweak[3],$inout3
+ pxor @tweak[4],$inout4
+
+ call _aesni_decrypt6
+
+ xorps @tweak[0],$inout0
+ xorps @tweak[1],$inout1
+ xorps @tweak[2],$inout2
+ movdqu $inout0,($out)
+ xorps @tweak[3],$inout3
+ movdqu $inout1,16*1($out)
+ xorps @tweak[4],$inout4
+ movdqu $inout2,16*2($out)
+ pxor $twtmp,$twtmp
+ movdqu $inout3,16*3($out)
+ pcmpgtd @tweak[5],$twtmp
+ movdqu $inout4,16*4($out)
+ lea 16*5($out),$out
+ pshufd \$0x13,$twtmp,@tweak[1] # $twres
+ and \$15,$len_
+ jz .Lxts_dec_ret
+
+ movdqa @tweak[5],@tweak[0]
+ paddq @tweak[5],@tweak[5] # psllq 1,$tweak
+ pand $twmask,@tweak[1] # isolate carry and residue
+ pxor @tweak[5],@tweak[1]
+ jmp .Lxts_dec_done2
+
+.align 16
+.Lxts_dec_one:
+ movups ($inp),$inout0
+ lea 16*1($inp),$inp
+ xorps @tweak[0],$inout0
+___
+ &aesni_generate1("dec",$key,$rounds);
+$code.=<<___;
+ xorps @tweak[0],$inout0
+ movdqa @tweak[1],@tweak[0]
+ movups $inout0,($out)
+ movdqa @tweak[2],@tweak[1]
+ lea 16*1($out),$out
+ jmp .Lxts_dec_done
+
+.align 16
+.Lxts_dec_two:
+ movups ($inp),$inout0
+ movups 16($inp),$inout1
+ lea 32($inp),$inp
+ xorps @tweak[0],$inout0
+ xorps @tweak[1],$inout1
+
+ call _aesni_decrypt3
+
+ xorps @tweak[0],$inout0
+ movdqa @tweak[2],@tweak[0]
+ xorps @tweak[1],$inout1
+ movdqa @tweak[3],@tweak[1]
+ movups $inout0,($out)
+ movups $inout1,16*1($out)
+ lea 16*2($out),$out
+ jmp .Lxts_dec_done
+
+.align 16
+.Lxts_dec_three:
+ movups ($inp),$inout0
+ movups 16*1($inp),$inout1
+ movups 16*2($inp),$inout2
+ lea 16*3($inp),$inp
+ xorps @tweak[0],$inout0
+ xorps @tweak[1],$inout1
+ xorps @tweak[2],$inout2
+
+ call _aesni_decrypt3
+
+ xorps @tweak[0],$inout0
+ movdqa @tweak[3],@tweak[0]
+ xorps @tweak[1],$inout1
+ movdqa @tweak[5],@tweak[1]
+ xorps @tweak[2],$inout2
+ movups $inout0,($out)
+ movups $inout1,16*1($out)
+ movups $inout2,16*2($out)
+ lea 16*3($out),$out
+ jmp .Lxts_dec_done
+
+.align 16
+.Lxts_dec_four:
+ pshufd \$0x13,$twtmp,$twres
+ movdqa @tweak[5],@tweak[4]
+ paddq @tweak[5],@tweak[5] # psllq 1,$tweak
+ movups ($inp),$inout0
+ pand $twmask,$twres # isolate carry and residue
+ movups 16*1($inp),$inout1
+ pxor $twres,@tweak[5]
+
+ movups 16*2($inp),$inout2
+ xorps @tweak[0],$inout0
+ movups 16*3($inp),$inout3
+ lea 16*4($inp),$inp
+ xorps @tweak[1],$inout1
+ xorps @tweak[2],$inout2
+ xorps @tweak[3],$inout3
+
+ call _aesni_decrypt4
+
+ xorps @tweak[0],$inout0
+ movdqa @tweak[4],@tweak[0]
+ xorps @tweak[1],$inout1
+ movdqa @tweak[5],@tweak[1]
+ xorps @tweak[2],$inout2
+ movups $inout0,($out)
+ xorps @tweak[3],$inout3
+ movups $inout1,16*1($out)
+ movups $inout2,16*2($out)
+ movups $inout3,16*3($out)
+ lea 16*4($out),$out
+ jmp .Lxts_dec_done
+
+.align 16
+.Lxts_dec_done:
+ and \$15,$len_
+ jz .Lxts_dec_ret
+.Lxts_dec_done2:
+ mov $len_,$len
+ mov $key_,$key # restore $key
+ mov $rnds_,$rounds # restore $rounds
+
+ movups ($inp),$inout0
+ xorps @tweak[1],$inout0
+___
+ &aesni_generate1("dec",$key,$rounds);
+$code.=<<___;
+ xorps @tweak[1],$inout0
+ movups $inout0,($out)
+
+.Lxts_dec_steal:
+ movzb 16($inp),%eax # borrow $rounds ...
+ movzb ($out),%ecx # ... and $key
+ lea 1($inp),$inp
+ mov %al,($out)
+ mov %cl,16($out)
+ lea 1($out),$out
+ sub \$1,$len
+ jnz .Lxts_dec_steal
+
+ sub $len_,$out # rewind $out
+ mov $key_,$key # restore $key
+ mov $rnds_,$rounds # restore $rounds
+
+ movups ($out),$inout0
+ xorps @tweak[0],$inout0
+___
+ &aesni_generate1("dec",$key,$rounds);
+$code.=<<___;
+ xorps @tweak[0],$inout0
+ movups $inout0,($out)
+
+.Lxts_dec_ret:
+___
+$code.=<<___ if ($win64);
+ movaps 0x60(%rsp),%xmm6
+ movaps 0x70(%rsp),%xmm7
+ movaps 0x80(%rsp),%xmm8
+ movaps 0x90(%rsp),%xmm9
+ movaps 0xa0(%rsp),%xmm10
+ movaps 0xb0(%rsp),%xmm11
+ movaps 0xc0(%rsp),%xmm12
+ movaps 0xd0(%rsp),%xmm13
+ movaps 0xe0(%rsp),%xmm14
+ movaps 0xf0(%rsp),%xmm15
+___
+$code.=<<___;
+ lea $frame_size(%rsp),%rsp
+.Lxts_dec_epilogue:
+ ret
+.size aesni_xts_decrypt,.-aesni_xts_decrypt
+___
+} }}
+
+########################################################################
+# void $PREFIX_cbc_encrypt (const void *inp, void *out,
+# size_t length, const AES_KEY *key,
+# unsigned char *ivp,const int enc);
+{
+my $reserved = $win64?0x40:-0x18; # used in decrypt
+$code.=<<___;
+.globl ${PREFIX}_cbc_encrypt
+.type ${PREFIX}_cbc_encrypt,\@function,6
+.align 16
+${PREFIX}_cbc_encrypt:
+ test $len,$len # check length
+ jz .Lcbc_ret
+
+ mov 240($key),$rnds_ # key->rounds
+ mov $key,$key_ # backup $key
+ test %r9d,%r9d # 6th argument
+ jz .Lcbc_decrypt
+#--------------------------- CBC ENCRYPT ------------------------------#
+ movups ($ivp),$inout0 # load iv as initial state
+ mov $rnds_,$rounds
+ cmp \$16,$len
+ jb .Lcbc_enc_tail
+ sub \$16,$len
+ jmp .Lcbc_enc_loop
+.align 16
+.Lcbc_enc_loop:
+ movups ($inp),$inout1 # load input
+ lea 16($inp),$inp
+ #xorps $inout1,$inout0
+___
+ &aesni_generate1("enc",$key,$rounds,$inout0,$inout1);
+$code.=<<___;
+ mov $rnds_,$rounds # restore $rounds
+ mov $key_,$key # restore $key
+ movups $inout0,0($out) # store output
+ lea 16($out),$out
+ sub \$16,$len
+ jnc .Lcbc_enc_loop
+ add \$16,$len
+ jnz .Lcbc_enc_tail
+ movups $inout0,($ivp)
+ jmp .Lcbc_ret
+
+.Lcbc_enc_tail:
+ mov $len,%rcx # zaps $key
+ xchg $inp,$out # $inp is %rsi and $out is %rdi now
+ .long 0x9066A4F3 # rep movsb
+ mov \$16,%ecx # zero tail
+ sub $len,%rcx
+ xor %eax,%eax
+ .long 0x9066AAF3 # rep stosb
+ lea -16(%rdi),%rdi # rewind $out by 1 block
+ mov $rnds_,$rounds # restore $rounds
+ mov %rdi,%rsi # $inp and $out are the same
+ mov $key_,$key # restore $key
+ xor $len,$len # len=16
+ jmp .Lcbc_enc_loop # one more spin
+#--------------------------- CBC DECRYPT ------------------------------#
+.align 16
+.Lcbc_decrypt:
+___
+$code.=<<___ if ($win64);
+ lea -0x58(%rsp),%rsp
+ movaps %xmm6,(%rsp)
+ movaps %xmm7,0x10(%rsp)
+ movaps %xmm8,0x20(%rsp)
+ movaps %xmm9,0x30(%rsp)
+.Lcbc_decrypt_body:
+___
+$code.=<<___;
+ movups ($ivp),$iv
+ mov $rnds_,$rounds
+ cmp \$0x70,$len
+ jbe .Lcbc_dec_tail
+ shr \$1,$rnds_
+ sub \$0x70,$len
+ mov $rnds_,$rounds
+ movaps $iv,$reserved(%rsp)
+ jmp .Lcbc_dec_loop8_enter
+.align 16
+.Lcbc_dec_loop8:
+ movaps $rndkey0,$reserved(%rsp) # save IV
+ movups $inout7,($out)
+ lea 0x10($out),$out
+.Lcbc_dec_loop8_enter:
+ $movkey ($key),$rndkey0
+ movups ($inp),$inout0 # load input
+ movups 0x10($inp),$inout1
+ $movkey 16($key),$rndkey1
+
+ lea 32($key),$key
+ movdqu 0x20($inp),$inout2
+ xorps $rndkey0,$inout0
+ movdqu 0x30($inp),$inout3
+ xorps $rndkey0,$inout1
+ movdqu 0x40($inp),$inout4
+ aesdec $rndkey1,$inout0
+ pxor $rndkey0,$inout2
+ movdqu 0x50($inp),$inout5
+ aesdec $rndkey1,$inout1
+ pxor $rndkey0,$inout3
+ movdqu 0x60($inp),$inout6
+ aesdec $rndkey1,$inout2
+ pxor $rndkey0,$inout4
+ movdqu 0x70($inp),$inout7
+ aesdec $rndkey1,$inout3
+ pxor $rndkey0,$inout5
+ dec $rounds
+ aesdec $rndkey1,$inout4
+ pxor $rndkey0,$inout6
+ aesdec $rndkey1,$inout5
+ pxor $rndkey0,$inout7
+ $movkey ($key),$rndkey0
+ aesdec $rndkey1,$inout6
+ aesdec $rndkey1,$inout7
+ $movkey 16($key),$rndkey1
+
+ call .Ldec_loop8_enter
+
+ movups ($inp),$rndkey1 # re-load input
+ movups 0x10($inp),$rndkey0
+ xorps $reserved(%rsp),$inout0 # ^= IV
+ xorps $rndkey1,$inout1
+ movups 0x20($inp),$rndkey1
+ xorps $rndkey0,$inout2
+ movups 0x30($inp),$rndkey0
+ xorps $rndkey1,$inout3
+ movups 0x40($inp),$rndkey1
+ xorps $rndkey0,$inout4
+ movups 0x50($inp),$rndkey0
+ xorps $rndkey1,$inout5
+ movups 0x60($inp),$rndkey1
+ xorps $rndkey0,$inout6
+ movups 0x70($inp),$rndkey0 # IV
+ xorps $rndkey1,$inout7
+ movups $inout0,($out)
+ movups $inout1,0x10($out)
+ movups $inout2,0x20($out)
+ movups $inout3,0x30($out)
+ mov $rnds_,$rounds # restore $rounds
+ movups $inout4,0x40($out)
+ mov $key_,$key # restore $key
+ movups $inout5,0x50($out)
+ lea 0x80($inp),$inp
+ movups $inout6,0x60($out)
+ lea 0x70($out),$out
+ sub \$0x80,$len
+ ja .Lcbc_dec_loop8
+
+ movaps $inout7,$inout0
+ movaps $rndkey0,$iv
+ add \$0x70,$len
+ jle .Lcbc_dec_tail_collected
+ movups $inout0,($out)
+ lea 1($rnds_,$rnds_),$rounds
+ lea 0x10($out),$out
+.Lcbc_dec_tail:
+ movups ($inp),$inout0
+ movaps $inout0,$in0
+ cmp \$0x10,$len
+ jbe .Lcbc_dec_one
+
+ movups 0x10($inp),$inout1
+ movaps $inout1,$in1
+ cmp \$0x20,$len
+ jbe .Lcbc_dec_two
+
+ movups 0x20($inp),$inout2
+ movaps $inout2,$in2
+ cmp \$0x30,$len
+ jbe .Lcbc_dec_three
+
+ movups 0x30($inp),$inout3
+ cmp \$0x40,$len
+ jbe .Lcbc_dec_four
+
+ movups 0x40($inp),$inout4
+ cmp \$0x50,$len
+ jbe .Lcbc_dec_five
+
+ movups 0x50($inp),$inout5
+ cmp \$0x60,$len
+ jbe .Lcbc_dec_six
+
+ movups 0x60($inp),$inout6
+ movaps $iv,$reserved(%rsp) # save IV
+ call _aesni_decrypt8
+ movups ($inp),$rndkey1
+ movups 0x10($inp),$rndkey0
+ xorps $reserved(%rsp),$inout0 # ^= IV
+ xorps $rndkey1,$inout1
+ movups 0x20($inp),$rndkey1
+ xorps $rndkey0,$inout2
+ movups 0x30($inp),$rndkey0
+ xorps $rndkey1,$inout3
+ movups 0x40($inp),$rndkey1
+ xorps $rndkey0,$inout4
+ movups 0x50($inp),$rndkey0
+ xorps $rndkey1,$inout5
+ movups 0x60($inp),$iv # IV
+ xorps $rndkey0,$inout6
+ movups $inout0,($out)
+ movups $inout1,0x10($out)
+ movups $inout2,0x20($out)
+ movups $inout3,0x30($out)
+ movups $inout4,0x40($out)
+ movups $inout5,0x50($out)
+ lea 0x60($out),$out
+ movaps $inout6,$inout0
+ sub \$0x70,$len
+ jmp .Lcbc_dec_tail_collected
+.align 16
+.Lcbc_dec_one:
+___
+ &aesni_generate1("dec",$key,$rounds);
+$code.=<<___;
+ xorps $iv,$inout0
+ movaps $in0,$iv
+ sub \$0x10,$len
+ jmp .Lcbc_dec_tail_collected
+.align 16
+.Lcbc_dec_two:
+ xorps $inout2,$inout2
+ call _aesni_decrypt3
+ xorps $iv,$inout0
+ xorps $in0,$inout1
+ movups $inout0,($out)
+ movaps $in1,$iv
+ movaps $inout1,$inout0
+ lea 0x10($out),$out
+ sub \$0x20,$len
+ jmp .Lcbc_dec_tail_collected
+.align 16
+.Lcbc_dec_three:
+ call _aesni_decrypt3
+ xorps $iv,$inout0
+ xorps $in0,$inout1
+ movups $inout0,($out)
+ xorps $in1,$inout2
+ movups $inout1,0x10($out)
+ movaps $in2,$iv
+ movaps $inout2,$inout0
+ lea 0x20($out),$out
+ sub \$0x30,$len
+ jmp .Lcbc_dec_tail_collected
+.align 16
+.Lcbc_dec_four:
+ call _aesni_decrypt4
+ xorps $iv,$inout0
+ movups 0x30($inp),$iv
+ xorps $in0,$inout1
+ movups $inout0,($out)
+ xorps $in1,$inout2
+ movups $inout1,0x10($out)
+ xorps $in2,$inout3
+ movups $inout2,0x20($out)
+ movaps $inout3,$inout0
+ lea 0x30($out),$out
+ sub \$0x40,$len
+ jmp .Lcbc_dec_tail_collected
+.align 16
+.Lcbc_dec_five:
+ xorps $inout5,$inout5
+ call _aesni_decrypt6
+ movups 0x10($inp),$rndkey1
+ movups 0x20($inp),$rndkey0
+ xorps $iv,$inout0
+ xorps $in0,$inout1
+ xorps $rndkey1,$inout2
+ movups 0x30($inp),$rndkey1
+ xorps $rndkey0,$inout3
+ movups 0x40($inp),$iv
+ xorps $rndkey1,$inout4
+ movups $inout0,($out)
+ movups $inout1,0x10($out)
+ movups $inout2,0x20($out)
+ movups $inout3,0x30($out)
+ lea 0x40($out),$out
+ movaps $inout4,$inout0
+ sub \$0x50,$len
+ jmp .Lcbc_dec_tail_collected
+.align 16
+.Lcbc_dec_six:
+ call _aesni_decrypt6
+ movups 0x10($inp),$rndkey1
+ movups 0x20($inp),$rndkey0
+ xorps $iv,$inout0
+ xorps $in0,$inout1
+ xorps $rndkey1,$inout2
+ movups 0x30($inp),$rndkey1
+ xorps $rndkey0,$inout3
+ movups 0x40($inp),$rndkey0
+ xorps $rndkey1,$inout4
+ movups 0x50($inp),$iv
+ xorps $rndkey0,$inout5
+ movups $inout0,($out)
+ movups $inout1,0x10($out)
+ movups $inout2,0x20($out)
+ movups $inout3,0x30($out)
+ movups $inout4,0x40($out)
+ lea 0x50($out),$out
+ movaps $inout5,$inout0
+ sub \$0x60,$len
+ jmp .Lcbc_dec_tail_collected
+.align 16
+.Lcbc_dec_tail_collected:
+ and \$15,$len
+ movups $iv,($ivp)
+ jnz .Lcbc_dec_tail_partial
+ movups $inout0,($out)
+ jmp .Lcbc_dec_ret
+.align 16
+.Lcbc_dec_tail_partial:
+ movaps $inout0,$reserved(%rsp)
+ mov \$16,%rcx
+ mov $out,%rdi
+ sub $len,%rcx
+ lea $reserved(%rsp),%rsi
+ .long 0x9066A4F3 # rep movsb
+
+.Lcbc_dec_ret:
+___
+$code.=<<___ if ($win64);
+ movaps (%rsp),%xmm6
+ movaps 0x10(%rsp),%xmm7
+ movaps 0x20(%rsp),%xmm8
+ movaps 0x30(%rsp),%xmm9
+ lea 0x58(%rsp),%rsp
+___
+$code.=<<___;
+.Lcbc_ret:
+ ret
+.size ${PREFIX}_cbc_encrypt,.-${PREFIX}_cbc_encrypt
+___
+}
+# int $PREFIX_set_[en|de]crypt_key (const unsigned char *userKey,
+# int bits, AES_KEY *key)
+{ my ($inp,$bits,$key) = @_4args;
+ $bits =~ s/%r/%e/;
+
+$code.=<<___;
+.globl ${PREFIX}_set_decrypt_key
+.type ${PREFIX}_set_decrypt_key,\@abi-omnipotent
+.align 16
+${PREFIX}_set_decrypt_key:
+ .byte 0x48,0x83,0xEC,0x08 # sub rsp,8
+ call __aesni_set_encrypt_key
+ shl \$4,$bits # rounds-1 after _aesni_set_encrypt_key
+ test %eax,%eax
+ jnz .Ldec_key_ret
+ lea 16($key,$bits),$inp # points at the end of key schedule
+
+ $movkey ($key),%xmm0 # just swap
+ $movkey ($inp),%xmm1
+ $movkey %xmm0,($inp)
+ $movkey %xmm1,($key)
+ lea 16($key),$key
+ lea -16($inp),$inp
+
+.Ldec_key_inverse:
+ $movkey ($key),%xmm0 # swap and inverse
+ $movkey ($inp),%xmm1
+ aesimc %xmm0,%xmm0
+ aesimc %xmm1,%xmm1
+ lea 16($key),$key
+ lea -16($inp),$inp
+ $movkey %xmm0,16($inp)
+ $movkey %xmm1,-16($key)
+ cmp $key,$inp
+ ja .Ldec_key_inverse
+
+ $movkey ($key),%xmm0 # inverse middle
+ aesimc %xmm0,%xmm0
+ $movkey %xmm0,($inp)
+.Ldec_key_ret:
+ add \$8,%rsp
+ ret
+.LSEH_end_set_decrypt_key:
+.size ${PREFIX}_set_decrypt_key,.-${PREFIX}_set_decrypt_key
+___
+
+# This is based on submission by
+#
+# Huang Ying <ying.huang@intel.com>
+# Vinodh Gopal <vinodh.gopal@intel.com>
+# Kahraman Akdemir
+#
+# Agressively optimized in respect to aeskeygenassist's critical path
+# and is contained in %xmm0-5 to meet Win64 ABI requirement.
+#
+$code.=<<___;
+.globl ${PREFIX}_set_encrypt_key
+.type ${PREFIX}_set_encrypt_key,\@abi-omnipotent
+.align 16
+${PREFIX}_set_encrypt_key:
+__aesni_set_encrypt_key:
+ .byte 0x48,0x83,0xEC,0x08 # sub rsp,8
+ mov \$-1,%rax
+ test $inp,$inp
+ jz .Lenc_key_ret
+ test $key,$key
+ jz .Lenc_key_ret
+
+ movups ($inp),%xmm0 # pull first 128 bits of *userKey
+ xorps %xmm4,%xmm4 # low dword of xmm4 is assumed 0
+ lea 16($key),%rax
+ cmp \$256,$bits
+ je .L14rounds
+ cmp \$192,$bits
+ je .L12rounds
+ cmp \$128,$bits
+ jne .Lbad_keybits
+
+.L10rounds:
+ mov \$9,$bits # 10 rounds for 128-bit key
+ $movkey %xmm0,($key) # round 0
+ aeskeygenassist \$0x1,%xmm0,%xmm1 # round 1
+ call .Lkey_expansion_128_cold
+ aeskeygenassist \$0x2,%xmm0,%xmm1 # round 2
+ call .Lkey_expansion_128
+ aeskeygenassist \$0x4,%xmm0,%xmm1 # round 3
+ call .Lkey_expansion_128
+ aeskeygenassist \$0x8,%xmm0,%xmm1 # round 4
+ call .Lkey_expansion_128
+ aeskeygenassist \$0x10,%xmm0,%xmm1 # round 5
+ call .Lkey_expansion_128
+ aeskeygenassist \$0x20,%xmm0,%xmm1 # round 6
+ call .Lkey_expansion_128
+ aeskeygenassist \$0x40,%xmm0,%xmm1 # round 7
+ call .Lkey_expansion_128
+ aeskeygenassist \$0x80,%xmm0,%xmm1 # round 8
+ call .Lkey_expansion_128
+ aeskeygenassist \$0x1b,%xmm0,%xmm1 # round 9
+ call .Lkey_expansion_128
+ aeskeygenassist \$0x36,%xmm0,%xmm1 # round 10
+ call .Lkey_expansion_128
+ $movkey %xmm0,(%rax)
+ mov $bits,80(%rax) # 240(%rdx)
+ xor %eax,%eax
+ jmp .Lenc_key_ret
+
+.align 16
+.L12rounds:
+ movq 16($inp),%xmm2 # remaining 1/3 of *userKey
+ mov \$11,$bits # 12 rounds for 192
+ $movkey %xmm0,($key) # round 0
+ aeskeygenassist \$0x1,%xmm2,%xmm1 # round 1,2
+ call .Lkey_expansion_192a_cold
+ aeskeygenassist \$0x2,%xmm2,%xmm1 # round 2,3
+ call .Lkey_expansion_192b
+ aeskeygenassist \$0x4,%xmm2,%xmm1 # round 4,5
+ call .Lkey_expansion_192a
+ aeskeygenassist \$0x8,%xmm2,%xmm1 # round 5,6
+ call .Lkey_expansion_192b
+ aeskeygenassist \$0x10,%xmm2,%xmm1 # round 7,8
+ call .Lkey_expansion_192a
+ aeskeygenassist \$0x20,%xmm2,%xmm1 # round 8,9
+ call .Lkey_expansion_192b
+ aeskeygenassist \$0x40,%xmm2,%xmm1 # round 10,11
+ call .Lkey_expansion_192a
+ aeskeygenassist \$0x80,%xmm2,%xmm1 # round 11,12
+ call .Lkey_expansion_192b
+ $movkey %xmm0,(%rax)
+ mov $bits,48(%rax) # 240(%rdx)
+ xor %rax, %rax
+ jmp .Lenc_key_ret
+
+.align 16
+.L14rounds:
+ movups 16($inp),%xmm2 # remaning half of *userKey
+ mov \$13,$bits # 14 rounds for 256
+ lea 16(%rax),%rax
+ $movkey %xmm0,($key) # round 0
+ $movkey %xmm2,16($key) # round 1
+ aeskeygenassist \$0x1,%xmm2,%xmm1 # round 2
+ call .Lkey_expansion_256a_cold
+ aeskeygenassist \$0x1,%xmm0,%xmm1 # round 3
+ call .Lkey_expansion_256b
+ aeskeygenassist \$0x2,%xmm2,%xmm1 # round 4
+ call .Lkey_expansion_256a
+ aeskeygenassist \$0x2,%xmm0,%xmm1 # round 5
+ call .Lkey_expansion_256b
+ aeskeygenassist \$0x4,%xmm2,%xmm1 # round 6
+ call .Lkey_expansion_256a
+ aeskeygenassist \$0x4,%xmm0,%xmm1 # round 7
+ call .Lkey_expansion_256b
+ aeskeygenassist \$0x8,%xmm2,%xmm1 # round 8
+ call .Lkey_expansion_256a
+ aeskeygenassist \$0x8,%xmm0,%xmm1 # round 9
+ call .Lkey_expansion_256b
+ aeskeygenassist \$0x10,%xmm2,%xmm1 # round 10
+ call .Lkey_expansion_256a
+ aeskeygenassist \$0x10,%xmm0,%xmm1 # round 11
+ call .Lkey_expansion_256b
+ aeskeygenassist \$0x20,%xmm2,%xmm1 # round 12
+ call .Lkey_expansion_256a
+ aeskeygenassist \$0x20,%xmm0,%xmm1 # round 13
+ call .Lkey_expansion_256b
+ aeskeygenassist \$0x40,%xmm2,%xmm1 # round 14
+ call .Lkey_expansion_256a
+ $movkey %xmm0,(%rax)
+ mov $bits,16(%rax) # 240(%rdx)
+ xor %rax,%rax
+ jmp .Lenc_key_ret
+
+.align 16
+.Lbad_keybits:
+ mov \$-2,%rax
+.Lenc_key_ret:
+ add \$8,%rsp
+ ret
+.LSEH_end_set_encrypt_key:
+
+.align 16
+.Lkey_expansion_128:
+ $movkey %xmm0,(%rax)
+ lea 16(%rax),%rax
+.Lkey_expansion_128_cold:
+ shufps \$0b00010000,%xmm0,%xmm4
+ xorps %xmm4, %xmm0
+ shufps \$0b10001100,%xmm0,%xmm4
+ xorps %xmm4, %xmm0
+ shufps \$0b11111111,%xmm1,%xmm1 # critical path
+ xorps %xmm1,%xmm0
+ ret
+
+.align 16
+.Lkey_expansion_192a:
+ $movkey %xmm0,(%rax)
+ lea 16(%rax),%rax
+.Lkey_expansion_192a_cold:
+ movaps %xmm2, %xmm5
+.Lkey_expansion_192b_warm:
+ shufps \$0b00010000,%xmm0,%xmm4
+ movdqa %xmm2,%xmm3
+ xorps %xmm4,%xmm0
+ shufps \$0b10001100,%xmm0,%xmm4
+ pslldq \$4,%xmm3
+ xorps %xmm4,%xmm0
+ pshufd \$0b01010101,%xmm1,%xmm1 # critical path
+ pxor %xmm3,%xmm2
+ pxor %xmm1,%xmm0
+ pshufd \$0b11111111,%xmm0,%xmm3
+ pxor %xmm3,%xmm2
+ ret
+
+.align 16
+.Lkey_expansion_192b:
+ movaps %xmm0,%xmm3
+ shufps \$0b01000100,%xmm0,%xmm5
+ $movkey %xmm5,(%rax)
+ shufps \$0b01001110,%xmm2,%xmm3
+ $movkey %xmm3,16(%rax)
+ lea 32(%rax),%rax
+ jmp .Lkey_expansion_192b_warm
+
+.align 16
+.Lkey_expansion_256a:
+ $movkey %xmm2,(%rax)
+ lea 16(%rax),%rax
+.Lkey_expansion_256a_cold:
+ shufps \$0b00010000,%xmm0,%xmm4
+ xorps %xmm4,%xmm0
+ shufps \$0b10001100,%xmm0,%xmm4
+ xorps %xmm4,%xmm0
+ shufps \$0b11111111,%xmm1,%xmm1 # critical path
+ xorps %xmm1,%xmm0
+ ret
+
+.align 16
+.Lkey_expansion_256b:
+ $movkey %xmm0,(%rax)
+ lea 16(%rax),%rax
+
+ shufps \$0b00010000,%xmm2,%xmm4
+ xorps %xmm4,%xmm2
+ shufps \$0b10001100,%xmm2,%xmm4
+ xorps %xmm4,%xmm2
+ shufps \$0b10101010,%xmm1,%xmm1 # critical path
+ xorps %xmm1,%xmm2
+ ret
+.size ${PREFIX}_set_encrypt_key,.-${PREFIX}_set_encrypt_key
+.size __aesni_set_encrypt_key,.-__aesni_set_encrypt_key
+___
+}
+
+$code.=<<___;
+.align 64
+.Lbswap_mask:
+ .byte 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0
+.Lincrement32:
+ .long 6,6,6,0
+.Lincrement64:
+ .long 1,0,0,0
+.Lxts_magic:
+ .long 0x87,0,1,0
+
+.asciz "AES for Intel AES-NI, CRYPTOGAMS by <appro\@openssl.org>"
+.align 64
+___
+
+# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
+# CONTEXT *context,DISPATCHER_CONTEXT *disp)
+if ($win64) {
+$rec="%rcx";
+$frame="%rdx";
+$context="%r8";
+$disp="%r9";
+
+$code.=<<___;
+.extern __imp_RtlVirtualUnwind
+___
+$code.=<<___ if ($PREFIX eq "aesni");
+.type ecb_se_handler,\@abi-omnipotent
+.align 16
+ecb_se_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 152($context),%rax # pull context->Rsp
+
+ jmp .Lcommon_seh_tail
+.size ecb_se_handler,.-ecb_se_handler
+
+.type ccm64_se_handler,\@abi-omnipotent
+.align 16
+ccm64_se_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 120($context),%rax # pull context->Rax
+ mov 248($context),%rbx # pull context->Rip
+
+ mov 8($disp),%rsi # disp->ImageBase
+ mov 56($disp),%r11 # disp->HandlerData
+
+ mov 0(%r11),%r10d # HandlerData[0]
+ lea (%rsi,%r10),%r10 # prologue label
+ cmp %r10,%rbx # context->Rip<prologue label
+ jb .Lcommon_seh_tail
+
+ mov 152($context),%rax # pull context->Rsp
+
+ mov 4(%r11),%r10d # HandlerData[1]
+ lea (%rsi,%r10),%r10 # epilogue label
+ cmp %r10,%rbx # context->Rip>=epilogue label
+ jae .Lcommon_seh_tail
+
+ lea 0(%rax),%rsi # %xmm save area
+ lea 512($context),%rdi # &context.Xmm6
+ mov \$8,%ecx # 4*sizeof(%xmm0)/sizeof(%rax)
+ .long 0xa548f3fc # cld; rep movsq
+ lea 0x58(%rax),%rax # adjust stack pointer
+
+ jmp .Lcommon_seh_tail
+.size ccm64_se_handler,.-ccm64_se_handler
+
+.type ctr32_se_handler,\@abi-omnipotent
+.align 16
+ctr32_se_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 120($context),%rax # pull context->Rax
+ mov 248($context),%rbx # pull context->Rip
+
+ lea .Lctr32_body(%rip),%r10
+ cmp %r10,%rbx # context->Rip<"prologue" label
+ jb .Lcommon_seh_tail
+
+ mov 152($context),%rax # pull context->Rsp
+
+ lea .Lctr32_ret(%rip),%r10
+ cmp %r10,%rbx
+ jae .Lcommon_seh_tail
+
+ lea 0x20(%rax),%rsi # %xmm save area
+ lea 512($context),%rdi # &context.Xmm6
+ mov \$20,%ecx # 10*sizeof(%xmm0)/sizeof(%rax)
+ .long 0xa548f3fc # cld; rep movsq
+ lea 0xc8(%rax),%rax # adjust stack pointer
+
+ jmp .Lcommon_seh_tail
+.size ctr32_se_handler,.-ctr32_se_handler
+
+.type xts_se_handler,\@abi-omnipotent
+.align 16
+xts_se_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 120($context),%rax # pull context->Rax
+ mov 248($context),%rbx # pull context->Rip
+
+ mov 8($disp),%rsi # disp->ImageBase
+ mov 56($disp),%r11 # disp->HandlerData
+
+ mov 0(%r11),%r10d # HandlerData[0]
+ lea (%rsi,%r10),%r10 # prologue lable
+ cmp %r10,%rbx # context->Rip<prologue label
+ jb .Lcommon_seh_tail
+
+ mov 152($context),%rax # pull context->Rsp
+
+ mov 4(%r11),%r10d # HandlerData[1]
+ lea (%rsi,%r10),%r10 # epilogue label
+ cmp %r10,%rbx # context->Rip>=epilogue label
+ jae .Lcommon_seh_tail
+
+ lea 0x60(%rax),%rsi # %xmm save area
+ lea 512($context),%rdi # & context.Xmm6
+ mov \$20,%ecx # 10*sizeof(%xmm0)/sizeof(%rax)
+ .long 0xa548f3fc # cld; rep movsq
+ lea 0x68+160(%rax),%rax # adjust stack pointer
+
+ jmp .Lcommon_seh_tail
+.size xts_se_handler,.-xts_se_handler
+___
+$code.=<<___;
+.type cbc_se_handler,\@abi-omnipotent
+.align 16
+cbc_se_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 152($context),%rax # pull context->Rsp
+ mov 248($context),%rbx # pull context->Rip
+
+ lea .Lcbc_decrypt(%rip),%r10
+ cmp %r10,%rbx # context->Rip<"prologue" label
+ jb .Lcommon_seh_tail
+
+ lea .Lcbc_decrypt_body(%rip),%r10
+ cmp %r10,%rbx # context->Rip<cbc_decrypt_body
+ jb .Lrestore_cbc_rax
+
+ lea .Lcbc_ret(%rip),%r10
+ cmp %r10,%rbx # context->Rip>="epilogue" label
+ jae .Lcommon_seh_tail
+
+ lea 0(%rax),%rsi # top of stack
+ lea 512($context),%rdi # &context.Xmm6
+ mov \$8,%ecx # 4*sizeof(%xmm0)/sizeof(%rax)
+ .long 0xa548f3fc # cld; rep movsq
+ lea 0x58(%rax),%rax # adjust stack pointer
+ jmp .Lcommon_seh_tail
+
+.Lrestore_cbc_rax:
+ mov 120($context),%rax
+
+.Lcommon_seh_tail:
+ mov 8(%rax),%rdi
+ mov 16(%rax),%rsi
+ mov %rax,152($context) # restore context->Rsp
+ mov %rsi,168($context) # restore context->Rsi
+ mov %rdi,176($context) # restore context->Rdi
+
+ mov 40($disp),%rdi # disp->ContextRecord
+ mov $context,%rsi # context
+ mov \$154,%ecx # sizeof(CONTEXT)
+ .long 0xa548f3fc # cld; rep movsq
+
+ mov $disp,%rsi
+ xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER
+ mov 8(%rsi),%rdx # arg2, disp->ImageBase
+ mov 0(%rsi),%r8 # arg3, disp->ControlPc
+ mov 16(%rsi),%r9 # arg4, disp->FunctionEntry
+ mov 40(%rsi),%r10 # disp->ContextRecord
+ lea 56(%rsi),%r11 # &disp->HandlerData
+ lea 24(%rsi),%r12 # &disp->EstablisherFrame
+ mov %r10,32(%rsp) # arg5
+ mov %r11,40(%rsp) # arg6
+ mov %r12,48(%rsp) # arg7
+ mov %rcx,56(%rsp) # arg8, (NULL)
+ call *__imp_RtlVirtualUnwind(%rip)
+
+ mov \$1,%eax # ExceptionContinueSearch
+ add \$64,%rsp
+ popfq
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+ pop %rdi
+ pop %rsi
+ ret
+.size cbc_se_handler,.-cbc_se_handler
+
+.section .pdata
+.align 4
+___
+$code.=<<___ if ($PREFIX eq "aesni");
+ .rva .LSEH_begin_aesni_ecb_encrypt
+ .rva .LSEH_end_aesni_ecb_encrypt
+ .rva .LSEH_info_ecb
+
+ .rva .LSEH_begin_aesni_ccm64_encrypt_blocks
+ .rva .LSEH_end_aesni_ccm64_encrypt_blocks
+ .rva .LSEH_info_ccm64_enc
+
+ .rva .LSEH_begin_aesni_ccm64_decrypt_blocks
+ .rva .LSEH_end_aesni_ccm64_decrypt_blocks
+ .rva .LSEH_info_ccm64_dec
+
+ .rva .LSEH_begin_aesni_ctr32_encrypt_blocks
+ .rva .LSEH_end_aesni_ctr32_encrypt_blocks
+ .rva .LSEH_info_ctr32
+
+ .rva .LSEH_begin_aesni_xts_encrypt
+ .rva .LSEH_end_aesni_xts_encrypt
+ .rva .LSEH_info_xts_enc
+
+ .rva .LSEH_begin_aesni_xts_decrypt
+ .rva .LSEH_end_aesni_xts_decrypt
+ .rva .LSEH_info_xts_dec
+___
+$code.=<<___;
+ .rva .LSEH_begin_${PREFIX}_cbc_encrypt
+ .rva .LSEH_end_${PREFIX}_cbc_encrypt
+ .rva .LSEH_info_cbc
+
+ .rva ${PREFIX}_set_decrypt_key
+ .rva .LSEH_end_set_decrypt_key
+ .rva .LSEH_info_key
+
+ .rva ${PREFIX}_set_encrypt_key
+ .rva .LSEH_end_set_encrypt_key
+ .rva .LSEH_info_key
+.section .xdata
+.align 8
+___
+$code.=<<___ if ($PREFIX eq "aesni");
+.LSEH_info_ecb:
+ .byte 9,0,0,0
+ .rva ecb_se_handler
+.LSEH_info_ccm64_enc:
+ .byte 9,0,0,0
+ .rva ccm64_se_handler
+ .rva .Lccm64_enc_body,.Lccm64_enc_ret # HandlerData[]
+.LSEH_info_ccm64_dec:
+ .byte 9,0,0,0
+ .rva ccm64_se_handler
+ .rva .Lccm64_dec_body,.Lccm64_dec_ret # HandlerData[]
+.LSEH_info_ctr32:
+ .byte 9,0,0,0
+ .rva ctr32_se_handler
+.LSEH_info_xts_enc:
+ .byte 9,0,0,0
+ .rva xts_se_handler
+ .rva .Lxts_enc_body,.Lxts_enc_epilogue # HandlerData[]
+.LSEH_info_xts_dec:
+ .byte 9,0,0,0
+ .rva xts_se_handler
+ .rva .Lxts_dec_body,.Lxts_dec_epilogue # HandlerData[]
+___
+$code.=<<___;
+.LSEH_info_cbc:
+ .byte 9,0,0,0
+ .rva cbc_se_handler
+.LSEH_info_key:
+ .byte 0x01,0x04,0x01,0x00
+ .byte 0x04,0x02,0x00,0x00 # sub rsp,8
+___
+}
+
+sub rex {
+ local *opcode=shift;
+ my ($dst,$src)=@_;
+ my $rex=0;
+
+ $rex|=0x04 if($dst>=8);
+ $rex|=0x01 if($src>=8);
+ push @opcode,$rex|0x40 if($rex);
+}
+
+sub aesni {
+ my $line=shift;
+ my @opcode=(0x66);
+
+ if ($line=~/(aeskeygenassist)\s+\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) {
+ rex(\@opcode,$4,$3);
+ push @opcode,0x0f,0x3a,0xdf;
+ push @opcode,0xc0|($3&7)|(($4&7)<<3); # ModR/M
+ my $c=$2;
+ push @opcode,$c=~/^0/?oct($c):$c;
+ return ".byte\t".join(',',@opcode);
+ }
+ elsif ($line=~/(aes[a-z]+)\s+%xmm([0-9]+),\s*%xmm([0-9]+)/) {
+ my %opcodelet = (
+ "aesimc" => 0xdb,
+ "aesenc" => 0xdc, "aesenclast" => 0xdd,
+ "aesdec" => 0xde, "aesdeclast" => 0xdf
+ );
+ return undef if (!defined($opcodelet{$1}));
+ rex(\@opcode,$3,$2);
+ push @opcode,0x0f,0x38,$opcodelet{$1};
+ push @opcode,0xc0|($2&7)|(($3&7)<<3); # ModR/M
+ return ".byte\t".join(',',@opcode);
+ }
+ return $line;
+}
+
+$code =~ s/\`([^\`]*)\`/eval($1)/gem;
+$code =~ s/\b(aes.*%xmm[0-9]+).*$/aesni($1)/gem;
+
+print $code;
+
+close STDOUT;
diff --git a/crypto/aes/asm/bsaes-armv7.pl b/crypto/aes/asm/bsaes-armv7.pl
new file mode 100644
index 0000000..3da8542
--- /dev/null
+++ b/crypto/aes/asm/bsaes-armv7.pl
@@ -0,0 +1,2469 @@
+#!/usr/bin/env perl
+
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+#
+# Specific modes and adaptation for Linux kernel by Ard Biesheuvel
+# <ard.biesheuvel@linaro.org>. Permission to use under GPL terms is
+# granted.
+# ====================================================================
+
+# Bit-sliced AES for ARM NEON
+#
+# February 2012.
+#
+# This implementation is direct adaptation of bsaes-x86_64 module for
+# ARM NEON. Except that this module is endian-neutral [in sense that
+# it can be compiled for either endianness] by courtesy of vld1.8's
+# neutrality. Initial version doesn't implement interface to OpenSSL,
+# only low-level primitives and unsupported entry points, just enough
+# to collect performance results, which for Cortex-A8 core are:
+#
+# encrypt 19.5 cycles per byte processed with 128-bit key
+# decrypt 22.1 cycles per byte processed with 128-bit key
+# key conv. 440 cycles per 128-bit key/0.18 of 8x block
+#
+# Snapdragon S4 encrypts byte in 17.6 cycles and decrypts in 19.7,
+# which is [much] worse than anticipated (for further details see
+# http://www.openssl.org/~appro/Snapdragon-S4.html).
+#
+# Cortex-A15 manages in 14.2/16.1 cycles [when integer-only code
+# manages in 20.0 cycles].
+#
+# When comparing to x86_64 results keep in mind that NEON unit is
+# [mostly] single-issue and thus can't [fully] benefit from
+# instruction-level parallelism. And when comparing to aes-armv4
+# results keep in mind key schedule conversion overhead (see
+# bsaes-x86_64.pl for further details)...
+#
+# <appro@openssl.org>
+
+# April-August 2013
+#
+# Add CBC, CTR and XTS subroutines, adapt for kernel use.
+#
+# <ard.biesheuvel@linaro.org>
+
+while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {}
+open STDOUT,">$output";
+
+my ($inp,$out,$len,$key)=("r0","r1","r2","r3");
+my @XMM=map("q$_",(0..15));
+
+{
+my ($key,$rounds,$const)=("r4","r5","r6");
+
+sub Dlo() { shift=~m|q([1]?[0-9])|?"d".($1*2):""; }
+sub Dhi() { shift=~m|q([1]?[0-9])|?"d".($1*2+1):""; }
+
+sub Sbox {
+# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb
+# output in lsb > [b0, b1, b4, b6, b3, b7, b2, b5] < msb
+my @b=@_[0..7];
+my @t=@_[8..11];
+my @s=@_[12..15];
+ &InBasisChange (@b);
+ &Inv_GF256 (@b[6,5,0,3,7,1,4,2],@t,@s);
+ &OutBasisChange (@b[7,1,4,2,6,5,0,3]);
+}
+
+sub InBasisChange {
+# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb
+# output in lsb > [b6, b5, b0, b3, b7, b1, b4, b2] < msb
+my @b=@_[0..7];
+$code.=<<___;
+ veor @b[2], @b[2], @b[1]
+ veor @b[5], @b[5], @b[6]
+ veor @b[3], @b[3], @b[0]
+ veor @b[6], @b[6], @b[2]
+ veor @b[5], @b[5], @b[0]
+
+ veor @b[6], @b[6], @b[3]
+ veor @b[3], @b[3], @b[7]
+ veor @b[7], @b[7], @b[5]
+ veor @b[3], @b[3], @b[4]
+ veor @b[4], @b[4], @b[5]
+
+ veor @b[2], @b[2], @b[7]
+ veor @b[3], @b[3], @b[1]
+ veor @b[1], @b[1], @b[5]
+___
+}
+
+sub OutBasisChange {
+# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb
+# output in lsb > [b6, b1, b2, b4, b7, b0, b3, b5] < msb
+my @b=@_[0..7];
+$code.=<<___;
+ veor @b[0], @b[0], @b[6]
+ veor @b[1], @b[1], @b[4]
+ veor @b[4], @b[4], @b[6]
+ veor @b[2], @b[2], @b[0]
+ veor @b[6], @b[6], @b[1]
+
+ veor @b[1], @b[1], @b[5]
+ veor @b[5], @b[5], @b[3]
+ veor @b[3], @b[3], @b[7]
+ veor @b[7], @b[7], @b[5]
+ veor @b[2], @b[2], @b[5]
+
+ veor @b[4], @b[4], @b[7]
+___
+}
+
+sub InvSbox {
+# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb
+# output in lsb > [b0, b1, b6, b4, b2, b7, b3, b5] < msb
+my @b=@_[0..7];
+my @t=@_[8..11];
+my @s=@_[12..15];
+ &InvInBasisChange (@b);
+ &Inv_GF256 (@b[5,1,2,6,3,7,0,4],@t,@s);
+ &InvOutBasisChange (@b[3,7,0,4,5,1,2,6]);
+}
+
+sub InvInBasisChange { # OutBasisChange in reverse (with twist)
+my @b=@_[5,1,2,6,3,7,0,4];
+$code.=<<___
+ veor @b[1], @b[1], @b[7]
+ veor @b[4], @b[4], @b[7]
+
+ veor @b[7], @b[7], @b[5]
+ veor @b[1], @b[1], @b[3]
+ veor @b[2], @b[2], @b[5]
+ veor @b[3], @b[3], @b[7]
+
+ veor @b[6], @b[6], @b[1]
+ veor @b[2], @b[2], @b[0]
+ veor @b[5], @b[5], @b[3]
+ veor @b[4], @b[4], @b[6]
+ veor @b[0], @b[0], @b[6]
+ veor @b[1], @b[1], @b[4]
+___
+}
+
+sub InvOutBasisChange { # InBasisChange in reverse
+my @b=@_[2,5,7,3,6,1,0,4];
+$code.=<<___;
+ veor @b[1], @b[1], @b[5]
+ veor @b[2], @b[2], @b[7]
+
+ veor @b[3], @b[3], @b[1]
+ veor @b[4], @b[4], @b[5]
+ veor @b[7], @b[7], @b[5]
+ veor @b[3], @b[3], @b[4]
+ veor @b[5], @b[5], @b[0]
+ veor @b[3], @b[3], @b[7]
+ veor @b[6], @b[6], @b[2]
+ veor @b[2], @b[2], @b[1]
+ veor @b[6], @b[6], @b[3]
+
+ veor @b[3], @b[3], @b[0]
+ veor @b[5], @b[5], @b[6]
+___
+}
+
+sub Mul_GF4 {
+#;*************************************************************
+#;* Mul_GF4: Input x0-x1,y0-y1 Output x0-x1 Temp t0 (8) *
+#;*************************************************************
+my ($x0,$x1,$y0,$y1,$t0,$t1)=@_;
+$code.=<<___;
+ veor $t0, $y0, $y1
+ vand $t0, $t0, $x0
+ veor $x0, $x0, $x1
+ vand $t1, $x1, $y0
+ vand $x0, $x0, $y1
+ veor $x1, $t1, $t0
+ veor $x0, $x0, $t1
+___
+}
+
+sub Mul_GF4_N { # not used, see next subroutine
+# multiply and scale by N
+my ($x0,$x1,$y0,$y1,$t0)=@_;
+$code.=<<___;
+ veor $t0, $y0, $y1
+ vand $t0, $t0, $x0
+ veor $x0, $x0, $x1
+ vand $x1, $x1, $y0
+ vand $x0, $x0, $y1
+ veor $x1, $x1, $x0
+ veor $x0, $x0, $t0
+___
+}
+
+sub Mul_GF4_N_GF4 {
+# interleaved Mul_GF4_N and Mul_GF4
+my ($x0,$x1,$y0,$y1,$t0,
+ $x2,$x3,$y2,$y3,$t1)=@_;
+$code.=<<___;
+ veor $t0, $y0, $y1
+ veor $t1, $y2, $y3
+ vand $t0, $t0, $x0
+ vand $t1, $t1, $x2
+ veor $x0, $x0, $x1
+ veor $x2, $x2, $x3
+ vand $x1, $x1, $y0
+ vand $x3, $x3, $y2
+ vand $x0, $x0, $y1
+ vand $x2, $x2, $y3
+ veor $x1, $x1, $x0
+ veor $x2, $x2, $x3
+ veor $x0, $x0, $t0
+ veor $x3, $x3, $t1
+___
+}
+sub Mul_GF16_2 {
+my @x=@_[0..7];
+my @y=@_[8..11];
+my @t=@_[12..15];
+$code.=<<___;
+ veor @t[0], @x[0], @x[2]
+ veor @t[1], @x[1], @x[3]
+___
+ &Mul_GF4 (@x[0], @x[1], @y[0], @y[1], @t[2..3]);
+$code.=<<___;
+ veor @y[0], @y[0], @y[2]
+ veor @y[1], @y[1], @y[3]
+___
+ Mul_GF4_N_GF4 (@t[0], @t[1], @y[0], @y[1], @t[3],
+ @x[2], @x[3], @y[2], @y[3], @t[2]);
+$code.=<<___;
+ veor @x[0], @x[0], @t[0]
+ veor @x[2], @x[2], @t[0]
+ veor @x[1], @x[1], @t[1]
+ veor @x[3], @x[3], @t[1]
+
+ veor @t[0], @x[4], @x[6]
+ veor @t[1], @x[5], @x[7]
+___
+ &Mul_GF4_N_GF4 (@t[0], @t[1], @y[0], @y[1], @t[3],
+ @x[6], @x[7], @y[2], @y[3], @t[2]);
+$code.=<<___;
+ veor @y[0], @y[0], @y[2]
+ veor @y[1], @y[1], @y[3]
+___
+ &Mul_GF4 (@x[4], @x[5], @y[0], @y[1], @t[2..3]);
+$code.=<<___;
+ veor @x[4], @x[4], @t[0]
+ veor @x[6], @x[6], @t[0]
+ veor @x[5], @x[5], @t[1]
+ veor @x[7], @x[7], @t[1]
+___
+}
+sub Inv_GF256 {
+#;********************************************************************
+#;* Inv_GF256: Input x0-x7 Output x0-x7 Temp t0-t3,s0-s3 (144) *
+#;********************************************************************
+my @x=@_[0..7];
+my @t=@_[8..11];
+my @s=@_[12..15];
+# direct optimizations from hardware
+$code.=<<___;
+ veor @t[3], @x[4], @x[6]
+ veor @t[2], @x[5], @x[7]
+ veor @t[1], @x[1], @x[3]
+ veor @s[1], @x[7], @x[6]
+ vmov @t[0], @t[2]
+ veor @s[0], @x[0], @x[2]
+
+ vorr @t[2], @t[2], @t[1]
+ veor @s[3], @t[3], @t[0]
+ vand @s[2], @t[3], @s[0]
+ vorr @t[3], @t[3], @s[0]
+ veor @s[0], @s[0], @t[1]
+ vand @t[0], @t[0], @t[1]
+ veor @t[1], @x[3], @x[2]
+ vand @s[3], @s[3], @s[0]
+ vand @s[1], @s[1], @t[1]
+ veor @t[1], @x[4], @x[5]
+ veor @s[0], @x[1], @x[0]
+ veor @t[3], @t[3], @s[1]
+ veor @t[2], @t[2], @s[1]
+ vand @s[1], @t[1], @s[0]
+ vorr @t[1], @t[1], @s[0]
+ veor @t[3], @t[3], @s[3]
+ veor @t[0], @t[0], @s[1]
+ veor @t[2], @t[2], @s[2]
+ veor @t[1], @t[1], @s[3]
+ veor @t[0], @t[0], @s[2]
+ vand @s[0], @x[7], @x[3]
+ veor @t[1], @t[1], @s[2]
+ vand @s[1], @x[6], @x[2]
+ vand @s[2], @x[5], @x[1]
+ vorr @s[3], @x[4], @x[0]
+ veor @t[3], @t[3], @s[0]
+ veor @t[1], @t[1], @s[2]
+ veor @t[0], @t[0], @s[3]
+ veor @t[2], @t[2], @s[1]
+
+ @ Inv_GF16 \t0, \t1, \t2, \t3, \s0, \s1, \s2, \s3
+
+ @ new smaller inversion
+
+ vand @s[2], @t[3], @t[1]
+ vmov @s[0], @t[0]
+
+ veor @s[1], @t[2], @s[2]
+ veor @s[3], @t[0], @s[2]
+ veor @s[2], @t[0], @s[2] @ @s[2]=@s[3]
+
+ vbsl @s[1], @t[1], @t[0]
+ vbsl @s[3], @t[3], @t[2]
+ veor @t[3], @t[3], @t[2]
+
+ vbsl @s[0], @s[1], @s[2]
+ vbsl @t[0], @s[2], @s[1]
+
+ vand @s[2], @s[0], @s[3]
+ veor @t[1], @t[1], @t[0]
+
+ veor @s[2], @s[2], @t[3]
+___
+# output in s3, s2, s1, t1
+
+# Mul_GF16_2 \x0, \x1, \x2, \x3, \x4, \x5, \x6, \x7, \t2, \t3, \t0, \t1, \s0, \s1, \s2, \s3
+
+# Mul_GF16_2 \x0, \x1, \x2, \x3, \x4, \x5, \x6, \x7, \s3, \s2, \s1, \t1, \s0, \t0, \t2, \t3
+ &Mul_GF16_2(@x,@s[3,2,1],@t[1],@s[0],@t[0,2,3]);
+
+### output msb > [x3,x2,x1,x0,x7,x6,x5,x4] < lsb
+}
+
+# AES linear components
+
+sub ShiftRows {
+my @x=@_[0..7];
+my @t=@_[8..11];
+my $mask=pop;
+$code.=<<___;
+ vldmia $key!, {@t[0]-@t[3]}
+ veor @t[0], @t[0], @x[0]
+ veor @t[1], @t[1], @x[1]
+ vtbl.8 `&Dlo(@x[0])`, {@t[0]}, `&Dlo($mask)`
+ vtbl.8 `&Dhi(@x[0])`, {@t[0]}, `&Dhi($mask)`
+ vldmia $key!, {@t[0]}
+ veor @t[2], @t[2], @x[2]
+ vtbl.8 `&Dlo(@x[1])`, {@t[1]}, `&Dlo($mask)`
+ vtbl.8 `&Dhi(@x[1])`, {@t[1]}, `&Dhi($mask)`
+ vldmia $key!, {@t[1]}
+ veor @t[3], @t[3], @x[3]
+ vtbl.8 `&Dlo(@x[2])`, {@t[2]}, `&Dlo($mask)`
+ vtbl.8 `&Dhi(@x[2])`, {@t[2]}, `&Dhi($mask)`
+ vldmia $key!, {@t[2]}
+ vtbl.8 `&Dlo(@x[3])`, {@t[3]}, `&Dlo($mask)`
+ vtbl.8 `&Dhi(@x[3])`, {@t[3]}, `&Dhi($mask)`
+ vldmia $key!, {@t[3]}
+ veor @t[0], @t[0], @x[4]
+ veor @t[1], @t[1], @x[5]
+ vtbl.8 `&Dlo(@x[4])`, {@t[0]}, `&Dlo($mask)`
+ vtbl.8 `&Dhi(@x[4])`, {@t[0]}, `&Dhi($mask)`
+ veor @t[2], @t[2], @x[6]
+ vtbl.8 `&Dlo(@x[5])`, {@t[1]}, `&Dlo($mask)`
+ vtbl.8 `&Dhi(@x[5])`, {@t[1]}, `&Dhi($mask)`
+ veor @t[3], @t[3], @x[7]
+ vtbl.8 `&Dlo(@x[6])`, {@t[2]}, `&Dlo($mask)`
+ vtbl.8 `&Dhi(@x[6])`, {@t[2]}, `&Dhi($mask)`
+ vtbl.8 `&Dlo(@x[7])`, {@t[3]}, `&Dlo($mask)`
+ vtbl.8 `&Dhi(@x[7])`, {@t[3]}, `&Dhi($mask)`
+___
+}
+
+sub MixColumns {
+# modified to emit output in order suitable for feeding back to aesenc[last]
+my @x=@_[0..7];
+my @t=@_[8..15];
+my $inv=@_[16]; # optional
+$code.=<<___;
+ vext.8 @t[0], @x[0], @x[0], #12 @ x0 <<< 32
+ vext.8 @t[1], @x[1], @x[1], #12
+ veor @x[0], @x[0], @t[0] @ x0 ^ (x0 <<< 32)
+ vext.8 @t[2], @x[2], @x[2], #12
+ veor @x[1], @x[1], @t[1]
+ vext.8 @t[3], @x[3], @x[3], #12
+ veor @x[2], @x[2], @t[2]
+ vext.8 @t[4], @x[4], @x[4], #12
+ veor @x[3], @x[3], @t[3]
+ vext.8 @t[5], @x[5], @x[5], #12
+ veor @x[4], @x[4], @t[4]
+ vext.8 @t[6], @x[6], @x[6], #12
+ veor @x[5], @x[5], @t[5]
+ vext.8 @t[7], @x[7], @x[7], #12
+ veor @x[6], @x[6], @t[6]
+
+ veor @t[1], @t[1], @x[0]
+ veor @x[7], @x[7], @t[7]
+ vext.8 @x[0], @x[0], @x[0], #8 @ (x0 ^ (x0 <<< 32)) <<< 64)
+ veor @t[2], @t[2], @x[1]
+ veor @t[0], @t[0], @x[7]
+ veor @t[1], @t[1], @x[7]
+ vext.8 @x[1], @x[1], @x[1], #8
+ veor @t[5], @t[5], @x[4]
+ veor @x[0], @x[0], @t[0]
+ veor @t[6], @t[6], @x[5]
+ veor @x[1], @x[1], @t[1]
+ vext.8 @t[0], @x[4], @x[4], #8
+ veor @t[4], @t[4], @x[3]
+ vext.8 @t[1], @x[5], @x[5], #8
+ veor @t[7], @t[7], @x[6]
+ vext.8 @x[4], @x[3], @x[3], #8
+ veor @t[3], @t[3], @x[2]
+ vext.8 @x[5], @x[7], @x[7], #8
+ veor @t[4], @t[4], @x[7]
+ vext.8 @x[3], @x[6], @x[6], #8
+ veor @t[3], @t[3], @x[7]
+ vext.8 @x[6], @x[2], @x[2], #8
+ veor @x[7], @t[1], @t[5]
+___
+$code.=<<___ if (!$inv);
+ veor @x[2], @t[0], @t[4]
+ veor @x[4], @x[4], @t[3]
+ veor @x[5], @x[5], @t[7]
+ veor @x[3], @x[3], @t[6]
+ @ vmov @x[2], @t[0]
+ veor @x[6], @x[6], @t[2]
+ @ vmov @x[7], @t[1]
+___
+$code.=<<___ if ($inv);
+ veor @t[3], @t[3], @x[4]
+ veor @x[5], @x[5], @t[7]
+ veor @x[2], @x[3], @t[6]
+ veor @x[3], @t[0], @t[4]
+ veor @x[4], @x[6], @t[2]
+ vmov @x[6], @t[3]
+ @ vmov @x[7], @t[1]
+___
+}
+
+sub InvMixColumns_orig {
+my @x=@_[0..7];
+my @t=@_[8..15];
+
+$code.=<<___;
+ @ multiplication by 0x0e
+ vext.8 @t[7], @x[7], @x[7], #12
+ vmov @t[2], @x[2]
+ veor @x[2], @x[2], @x[5] @ 2 5
+ veor @x[7], @x[7], @x[5] @ 7 5
+ vext.8 @t[0], @x[0], @x[0], #12
+ vmov @t[5], @x[5]
+ veor @x[5], @x[5], @x[0] @ 5 0 [1]
+ veor @x[0], @x[0], @x[1] @ 0 1
+ vext.8 @t[1], @x[1], @x[1], #12
+ veor @x[1], @x[1], @x[2] @ 1 25
+ veor @x[0], @x[0], @x[6] @ 01 6 [2]
+ vext.8 @t[3], @x[3], @x[3], #12
+ veor @x[1], @x[1], @x[3] @ 125 3 [4]
+ veor @x[2], @x[2], @x[0] @ 25 016 [3]
+ veor @x[3], @x[3], @x[7] @ 3 75
+ veor @x[7], @x[7], @x[6] @ 75 6 [0]
+ vext.8 @t[6], @x[6], @x[6], #12
+ vmov @t[4], @x[4]
+ veor @x[6], @x[6], @x[4] @ 6 4
+ veor @x[4], @x[4], @x[3] @ 4 375 [6]
+ veor @x[3], @x[3], @x[7] @ 375 756=36
+ veor @x[6], @x[6], @t[5] @ 64 5 [7]
+ veor @x[3], @x[3], @t[2] @ 36 2
+ vext.8 @t[5], @t[5], @t[5], #12
+ veor @x[3], @x[3], @t[4] @ 362 4 [5]
+___
+ my @y = @x[7,5,0,2,1,3,4,6];
+$code.=<<___;
+ @ multiplication by 0x0b
+ veor @y[1], @y[1], @y[0]
+ veor @y[0], @y[0], @t[0]
+ vext.8 @t[2], @t[2], @t[2], #12
+ veor @y[1], @y[1], @t[1]
+ veor @y[0], @y[0], @t[5]
+ vext.8 @t[4], @t[4], @t[4], #12
+ veor @y[1], @y[1], @t[6]
+ veor @y[0], @y[0], @t[7]
+ veor @t[7], @t[7], @t[6] @ clobber t[7]
+
+ veor @y[3], @y[3], @t[0]
+ veor @y[1], @y[1], @y[0]
+ vext.8 @t[0], @t[0], @t[0], #12
+ veor @y[2], @y[2], @t[1]
+ veor @y[4], @y[4], @t[1]
+ vext.8 @t[1], @t[1], @t[1], #12
+ veor @y[2], @y[2], @t[2]
+ veor @y[3], @y[3], @t[2]
+ veor @y[5], @y[5], @t[2]
+ veor @y[2], @y[2], @t[7]
+ vext.8 @t[2], @t[2], @t[2], #12
+ veor @y[3], @y[3], @t[3]
+ veor @y[6], @y[6], @t[3]
+ veor @y[4], @y[4], @t[3]
+ veor @y[7], @y[7], @t[4]
+ vext.8 @t[3], @t[3], @t[3], #12
+ veor @y[5], @y[5], @t[4]
+ veor @y[7], @y[7], @t[7]
+ veor @t[7], @t[7], @t[5] @ clobber t[7] even more
+ veor @y[3], @y[3], @t[5]
+ veor @y[4], @y[4], @t[4]
+
+ veor @y[5], @y[5], @t[7]
+ vext.8 @t[4], @t[4], @t[4], #12
+ veor @y[6], @y[6], @t[7]
+ veor @y[4], @y[4], @t[7]
+
+ veor @t[7], @t[7], @t[5]
+ vext.8 @t[5], @t[5], @t[5], #12
+
+ @ multiplication by 0x0d
+ veor @y[4], @y[4], @y[7]
+ veor @t[7], @t[7], @t[6] @ restore t[7]
+ veor @y[7], @y[7], @t[4]
+ vext.8 @t[6], @t[6], @t[6], #12
+ veor @y[2], @y[2], @t[0]
+ veor @y[7], @y[7], @t[5]
+ vext.8 @t[7], @t[7], @t[7], #12
+ veor @y[2], @y[2], @t[2]
+
+ veor @y[3], @y[3], @y[1]
+ veor @y[1], @y[1], @t[1]
+ veor @y[0], @y[0], @t[0]
+ veor @y[3], @y[3], @t[0]
+ veor @y[1], @y[1], @t[5]
+ veor @y[0], @y[0], @t[5]
+ vext.8 @t[0], @t[0], @t[0], #12
+ veor @y[1], @y[1], @t[7]
+ veor @y[0], @y[0], @t[6]
+ veor @y[3], @y[3], @y[1]
+ veor @y[4], @y[4], @t[1]
+ vext.8 @t[1], @t[1], @t[1], #12
+
+ veor @y[7], @y[7], @t[7]
+ veor @y[4], @y[4], @t[2]
+ veor @y[5], @y[5], @t[2]
+ veor @y[2], @y[2], @t[6]
+ veor @t[6], @t[6], @t[3] @ clobber t[6]
+ vext.8 @t[2], @t[2], @t[2], #12
+ veor @y[4], @y[4], @y[7]
+ veor @y[3], @y[3], @t[6]
+
+ veor @y[6], @y[6], @t[6]
+ veor @y[5], @y[5], @t[5]
+ vext.8 @t[5], @t[5], @t[5], #12
+ veor @y[6], @y[6], @t[4]
+ vext.8 @t[4], @t[4], @t[4], #12
+ veor @y[5], @y[5], @t[6]
+ veor @y[6], @y[6], @t[7]
+ vext.8 @t[7], @t[7], @t[7], #12
+ veor @t[6], @t[6], @t[3] @ restore t[6]
+ vext.8 @t[3], @t[3], @t[3], #12
+
+ @ multiplication by 0x09
+ veor @y[4], @y[4], @y[1]
+ veor @t[1], @t[1], @y[1] @ t[1]=y[1]
+ veor @t[0], @t[0], @t[5] @ clobber t[0]
+ vext.8 @t[6], @t[6], @t[6], #12
+ veor @t[1], @t[1], @t[5]
+ veor @y[3], @y[3], @t[0]
+ veor @t[0], @t[0], @y[0] @ t[0]=y[0]
+ veor @t[1], @t[1], @t[6]
+ veor @t[6], @t[6], @t[7] @ clobber t[6]
+ veor @y[4], @y[4], @t[1]
+ veor @y[7], @y[7], @t[4]
+ veor @y[6], @y[6], @t[3]
+ veor @y[5], @y[5], @t[2]
+ veor @t[4], @t[4], @y[4] @ t[4]=y[4]
+ veor @t[3], @t[3], @y[3] @ t[3]=y[3]
+ veor @t[5], @t[5], @y[5] @ t[5]=y[5]
+ veor @t[2], @t[2], @y[2] @ t[2]=y[2]
+ veor @t[3], @t[3], @t[7]
+ veor @XMM[5], @t[5], @t[6]
+ veor @XMM[6], @t[6], @y[6] @ t[6]=y[6]
+ veor @XMM[2], @t[2], @t[6]
+ veor @XMM[7], @t[7], @y[7] @ t[7]=y[7]
+
+ vmov @XMM[0], @t[0]
+ vmov @XMM[1], @t[1]
+ @ vmov @XMM[2], @t[2]
+ vmov @XMM[3], @t[3]
+ vmov @XMM[4], @t[4]
+ @ vmov @XMM[5], @t[5]
+ @ vmov @XMM[6], @t[6]
+ @ vmov @XMM[7], @t[7]
+___
+}
+
+sub InvMixColumns {
+my @x=@_[0..7];
+my @t=@_[8..15];
+
+# Thanks to Jussi Kivilinna for providing pointer to
+#
+# | 0e 0b 0d 09 | | 02 03 01 01 | | 05 00 04 00 |
+# | 09 0e 0b 0d | = | 01 02 03 01 | x | 00 05 00 04 |
+# | 0d 09 0e 0b | | 01 01 02 03 | | 04 00 05 00 |
+# | 0b 0d 09 0e | | 03 01 01 02 | | 00 04 00 05 |
+
+$code.=<<___;
+ @ multiplication by 0x05-0x00-0x04-0x00
+ vext.8 @t[0], @x[0], @x[0], #8
+ vext.8 @t[6], @x[6], @x[6], #8
+ vext.8 @t[7], @x[7], @x[7], #8
+ veor @t[0], @t[0], @x[0]
+ vext.8 @t[1], @x[1], @x[1], #8
+ veor @t[6], @t[6], @x[6]
+ vext.8 @t[2], @x[2], @x[2], #8
+ veor @t[7], @t[7], @x[7]
+ vext.8 @t[3], @x[3], @x[3], #8
+ veor @t[1], @t[1], @x[1]
+ vext.8 @t[4], @x[4], @x[4], #8
+ veor @t[2], @t[2], @x[2]
+ vext.8 @t[5], @x[5], @x[5], #8
+ veor @t[3], @t[3], @x[3]
+ veor @t[4], @t[4], @x[4]
+ veor @t[5], @t[5], @x[5]
+
+ veor @x[0], @x[0], @t[6]
+ veor @x[1], @x[1], @t[6]
+ veor @x[2], @x[2], @t[0]
+ veor @x[4], @x[4], @t[2]
+ veor @x[3], @x[3], @t[1]
+ veor @x[1], @x[1], @t[7]
+ veor @x[2], @x[2], @t[7]
+ veor @x[4], @x[4], @t[6]
+ veor @x[5], @x[5], @t[3]
+ veor @x[3], @x[3], @t[6]
+ veor @x[6], @x[6], @t[4]
+ veor @x[4], @x[4], @t[7]
+ veor @x[5], @x[5], @t[7]
+ veor @x[7], @x[7], @t[5]
+___
+ &MixColumns (@x,@t,1); # flipped 2<->3 and 4<->6
+}
+
+sub swapmove {
+my ($a,$b,$n,$mask,$t)=@_;
+$code.=<<___;
+ vshr.u64 $t, $b, #$n
+ veor $t, $t, $a
+ vand $t, $t, $mask
+ veor $a, $a, $t
+ vshl.u64 $t, $t, #$n
+ veor $b, $b, $t
+___
+}
+sub swapmove2x {
+my ($a0,$b0,$a1,$b1,$n,$mask,$t0,$t1)=@_;
+$code.=<<___;
+ vshr.u64 $t0, $b0, #$n
+ vshr.u64 $t1, $b1, #$n
+ veor $t0, $t0, $a0
+ veor $t1, $t1, $a1
+ vand $t0, $t0, $mask
+ vand $t1, $t1, $mask
+ veor $a0, $a0, $t0
+ vshl.u64 $t0, $t0, #$n
+ veor $a1, $a1, $t1
+ vshl.u64 $t1, $t1, #$n
+ veor $b0, $b0, $t0
+ veor $b1, $b1, $t1
+___
+}
+
+sub bitslice {
+my @x=reverse(@_[0..7]);
+my ($t0,$t1,$t2,$t3)=@_[8..11];
+$code.=<<___;
+ vmov.i8 $t0,#0x55 @ compose .LBS0
+ vmov.i8 $t1,#0x33 @ compose .LBS1
+___
+ &swapmove2x(@x[0,1,2,3],1,$t0,$t2,$t3);
+ &swapmove2x(@x[4,5,6,7],1,$t0,$t2,$t3);
+$code.=<<___;
+ vmov.i8 $t0,#0x0f @ compose .LBS2
+___
+ &swapmove2x(@x[0,2,1,3],2,$t1,$t2,$t3);
+ &swapmove2x(@x[4,6,5,7],2,$t1,$t2,$t3);
+
+ &swapmove2x(@x[0,4,1,5],4,$t0,$t2,$t3);
+ &swapmove2x(@x[2,6,3,7],4,$t0,$t2,$t3);
+}
+
+$code.=<<___;
+#if defined(__arm__)
+#ifndef __KERNEL__
+# include "arm_arch.h"
+
+# define VFP_ABI_PUSH vstmdb sp!,{d8-d15}
+# define VFP_ABI_POP vldmia sp!,{d8-d15}
+# define VFP_ABI_FRAME 0x40
+#else
+# define VFP_ABI_PUSH
+# define VFP_ABI_POP
+# define VFP_ABI_FRAME 0
+# define BSAES_ASM_EXTENDED_KEY
+# define XTS_CHAIN_TWEAK
+# define __ARM_ARCH__ __LINUX_ARM_ARCH__
+#endif
+
+#ifdef __thumb__
+# define adrl adr
+#endif
+
+#if __ARM_ARCH__>=7
+.text
+.syntax unified @ ARMv7-capable assembler is expected to handle this
+#ifdef __thumb2__
+.thumb
+#else
+.code 32
+#endif
+
+.fpu neon
+
+.type _bsaes_decrypt8,%function
+.align 4
+_bsaes_decrypt8:
+ adr $const,_bsaes_decrypt8
+ vldmia $key!, {@XMM[9]} @ round 0 key
+ add $const,$const,#.LM0ISR-_bsaes_decrypt8
+
+ vldmia $const!, {@XMM[8]} @ .LM0ISR
+ veor @XMM[10], @XMM[0], @XMM[9] @ xor with round0 key
+ veor @XMM[11], @XMM[1], @XMM[9]
+ vtbl.8 `&Dlo(@XMM[0])`, {@XMM[10]}, `&Dlo(@XMM[8])`
+ vtbl.8 `&Dhi(@XMM[0])`, {@XMM[10]}, `&Dhi(@XMM[8])`
+ veor @XMM[12], @XMM[2], @XMM[9]
+ vtbl.8 `&Dlo(@XMM[1])`, {@XMM[11]}, `&Dlo(@XMM[8])`
+ vtbl.8 `&Dhi(@XMM[1])`, {@XMM[11]}, `&Dhi(@XMM[8])`
+ veor @XMM[13], @XMM[3], @XMM[9]
+ vtbl.8 `&Dlo(@XMM[2])`, {@XMM[12]}, `&Dlo(@XMM[8])`
+ vtbl.8 `&Dhi(@XMM[2])`, {@XMM[12]}, `&Dhi(@XMM[8])`
+ veor @XMM[14], @XMM[4], @XMM[9]
+ vtbl.8 `&Dlo(@XMM[3])`, {@XMM[13]}, `&Dlo(@XMM[8])`
+ vtbl.8 `&Dhi(@XMM[3])`, {@XMM[13]}, `&Dhi(@XMM[8])`
+ veor @XMM[15], @XMM[5], @XMM[9]
+ vtbl.8 `&Dlo(@XMM[4])`, {@XMM[14]}, `&Dlo(@XMM[8])`
+ vtbl.8 `&Dhi(@XMM[4])`, {@XMM[14]}, `&Dhi(@XMM[8])`
+ veor @XMM[10], @XMM[6], @XMM[9]
+ vtbl.8 `&Dlo(@XMM[5])`, {@XMM[15]}, `&Dlo(@XMM[8])`
+ vtbl.8 `&Dhi(@XMM[5])`, {@XMM[15]}, `&Dhi(@XMM[8])`
+ veor @XMM[11], @XMM[7], @XMM[9]
+ vtbl.8 `&Dlo(@XMM[6])`, {@XMM[10]}, `&Dlo(@XMM[8])`
+ vtbl.8 `&Dhi(@XMM[6])`, {@XMM[10]}, `&Dhi(@XMM[8])`
+ vtbl.8 `&Dlo(@XMM[7])`, {@XMM[11]}, `&Dlo(@XMM[8])`
+ vtbl.8 `&Dhi(@XMM[7])`, {@XMM[11]}, `&Dhi(@XMM[8])`
+___
+ &bitslice (@XMM[0..7, 8..11]);
+$code.=<<___;
+ sub $rounds,$rounds,#1
+ b .Ldec_sbox
+.align 4
+.Ldec_loop:
+___
+ &ShiftRows (@XMM[0..7, 8..12]);
+$code.=".Ldec_sbox:\n";
+ &InvSbox (@XMM[0..7, 8..15]);
+$code.=<<___;
+ subs $rounds,$rounds,#1
+ bcc .Ldec_done
+___
+ &InvMixColumns (@XMM[0,1,6,4,2,7,3,5, 8..15]);
+$code.=<<___;
+ vldmia $const, {@XMM[12]} @ .LISR
+ ite eq @ Thumb2 thing, sanity check in ARM
+ addeq $const,$const,#0x10
+ bne .Ldec_loop
+ vldmia $const, {@XMM[12]} @ .LISRM0
+ b .Ldec_loop
+.align 4
+.Ldec_done:
+___
+ &bitslice (@XMM[0,1,6,4,2,7,3,5, 8..11]);
+$code.=<<___;
+ vldmia $key, {@XMM[8]} @ last round key
+ veor @XMM[6], @XMM[6], @XMM[8]
+ veor @XMM[4], @XMM[4], @XMM[8]
+ veor @XMM[2], @XMM[2], @XMM[8]
+ veor @XMM[7], @XMM[7], @XMM[8]
+ veor @XMM[3], @XMM[3], @XMM[8]
+ veor @XMM[5], @XMM[5], @XMM[8]
+ veor @XMM[0], @XMM[0], @XMM[8]
+ veor @XMM[1], @XMM[1], @XMM[8]
+ bx lr
+.size _bsaes_decrypt8,.-_bsaes_decrypt8
+
+.type _bsaes_const,%object
+.align 6
+_bsaes_const:
+.LM0ISR: @ InvShiftRows constants
+ .quad 0x0a0e0206070b0f03, 0x0004080c0d010509
+.LISR:
+ .quad 0x0504070602010003, 0x0f0e0d0c080b0a09
+.LISRM0:
+ .quad 0x01040b0e0205080f, 0x0306090c00070a0d
+.LM0SR: @ ShiftRows constants
+ .quad 0x0a0e02060f03070b, 0x0004080c05090d01
+.LSR:
+ .quad 0x0504070600030201, 0x0f0e0d0c0a09080b
+.LSRM0:
+ .quad 0x0304090e00050a0f, 0x01060b0c0207080d
+.LM0:
+ .quad 0x02060a0e03070b0f, 0x0004080c0105090d
+.LREVM0SR:
+ .quad 0x090d01050c000408, 0x03070b0f060a0e02
+.asciz "Bit-sliced AES for NEON, CRYPTOGAMS by <appro\@openssl.org>"
+.align 6
+.size _bsaes_const,.-_bsaes_const
+
+.type _bsaes_encrypt8,%function
+.align 4
+_bsaes_encrypt8:
+ adr $const,_bsaes_encrypt8
+ vldmia $key!, {@XMM[9]} @ round 0 key
+ sub $const,$const,#_bsaes_encrypt8-.LM0SR
+
+ vldmia $const!, {@XMM[8]} @ .LM0SR
+_bsaes_encrypt8_alt:
+ veor @XMM[10], @XMM[0], @XMM[9] @ xor with round0 key
+ veor @XMM[11], @XMM[1], @XMM[9]
+ vtbl.8 `&Dlo(@XMM[0])`, {@XMM[10]}, `&Dlo(@XMM[8])`
+ vtbl.8 `&Dhi(@XMM[0])`, {@XMM[10]}, `&Dhi(@XMM[8])`
+ veor @XMM[12], @XMM[2], @XMM[9]
+ vtbl.8 `&Dlo(@XMM[1])`, {@XMM[11]}, `&Dlo(@XMM[8])`
+ vtbl.8 `&Dhi(@XMM[1])`, {@XMM[11]}, `&Dhi(@XMM[8])`
+ veor @XMM[13], @XMM[3], @XMM[9]
+ vtbl.8 `&Dlo(@XMM[2])`, {@XMM[12]}, `&Dlo(@XMM[8])`
+ vtbl.8 `&Dhi(@XMM[2])`, {@XMM[12]}, `&Dhi(@XMM[8])`
+ veor @XMM[14], @XMM[4], @XMM[9]
+ vtbl.8 `&Dlo(@XMM[3])`, {@XMM[13]}, `&Dlo(@XMM[8])`
+ vtbl.8 `&Dhi(@XMM[3])`, {@XMM[13]}, `&Dhi(@XMM[8])`
+ veor @XMM[15], @XMM[5], @XMM[9]
+ vtbl.8 `&Dlo(@XMM[4])`, {@XMM[14]}, `&Dlo(@XMM[8])`
+ vtbl.8 `&Dhi(@XMM[4])`, {@XMM[14]}, `&Dhi(@XMM[8])`
+ veor @XMM[10], @XMM[6], @XMM[9]
+ vtbl.8 `&Dlo(@XMM[5])`, {@XMM[15]}, `&Dlo(@XMM[8])`
+ vtbl.8 `&Dhi(@XMM[5])`, {@XMM[15]}, `&Dhi(@XMM[8])`
+ veor @XMM[11], @XMM[7], @XMM[9]
+ vtbl.8 `&Dlo(@XMM[6])`, {@XMM[10]}, `&Dlo(@XMM[8])`
+ vtbl.8 `&Dhi(@XMM[6])`, {@XMM[10]}, `&Dhi(@XMM[8])`
+ vtbl.8 `&Dlo(@XMM[7])`, {@XMM[11]}, `&Dlo(@XMM[8])`
+ vtbl.8 `&Dhi(@XMM[7])`, {@XMM[11]}, `&Dhi(@XMM[8])`
+_bsaes_encrypt8_bitslice:
+___
+ &bitslice (@XMM[0..7, 8..11]);
+$code.=<<___;
+ sub $rounds,$rounds,#1
+ b .Lenc_sbox
+.align 4
+.Lenc_loop:
+___
+ &ShiftRows (@XMM[0..7, 8..12]);
+$code.=".Lenc_sbox:\n";
+ &Sbox (@XMM[0..7, 8..15]);
+$code.=<<___;
+ subs $rounds,$rounds,#1
+ bcc .Lenc_done
+___
+ &MixColumns (@XMM[0,1,4,6,3,7,2,5, 8..15]);
+$code.=<<___;
+ vldmia $const, {@XMM[12]} @ .LSR
+ ite eq @ Thumb2 thing, samity check in ARM
+ addeq $const,$const,#0x10
+ bne .Lenc_loop
+ vldmia $const, {@XMM[12]} @ .LSRM0
+ b .Lenc_loop
+.align 4
+.Lenc_done:
+___
+ # output in lsb > [t0, t1, t4, t6, t3, t7, t2, t5] < msb
+ &bitslice (@XMM[0,1,4,6,3,7,2,5, 8..11]);
+$code.=<<___;
+ vldmia $key, {@XMM[8]} @ last round key
+ veor @XMM[4], @XMM[4], @XMM[8]
+ veor @XMM[6], @XMM[6], @XMM[8]
+ veor @XMM[3], @XMM[3], @XMM[8]
+ veor @XMM[7], @XMM[7], @XMM[8]
+ veor @XMM[2], @XMM[2], @XMM[8]
+ veor @XMM[5], @XMM[5], @XMM[8]
+ veor @XMM[0], @XMM[0], @XMM[8]
+ veor @XMM[1], @XMM[1], @XMM[8]
+ bx lr
+.size _bsaes_encrypt8,.-_bsaes_encrypt8
+___
+}
+{
+my ($out,$inp,$rounds,$const)=("r12","r4","r5","r6");
+
+sub bitslice_key {
+my @x=reverse(@_[0..7]);
+my ($bs0,$bs1,$bs2,$t2,$t3)=@_[8..12];
+
+ &swapmove (@x[0,1],1,$bs0,$t2,$t3);
+$code.=<<___;
+ @ &swapmove(@x[2,3],1,$t0,$t2,$t3);
+ vmov @x[2], @x[0]
+ vmov @x[3], @x[1]
+___
+ #&swapmove2x(@x[4,5,6,7],1,$t0,$t2,$t3);
+
+ &swapmove2x (@x[0,2,1,3],2,$bs1,$t2,$t3);
+$code.=<<___;
+ @ &swapmove2x(@x[4,6,5,7],2,$t1,$t2,$t3);
+ vmov @x[4], @x[0]
+ vmov @x[6], @x[2]
+ vmov @x[5], @x[1]
+ vmov @x[7], @x[3]
+___
+ &swapmove2x (@x[0,4,1,5],4,$bs2,$t2,$t3);
+ &swapmove2x (@x[2,6,3,7],4,$bs2,$t2,$t3);
+}
+
+$code.=<<___;
+.type _bsaes_key_convert,%function
+.align 4
+_bsaes_key_convert:
+ adr $const,_bsaes_key_convert
+ vld1.8 {@XMM[7]}, [$inp]! @ load round 0 key
+ sub $const,$const,#_bsaes_key_convert-.LM0
+ vld1.8 {@XMM[15]}, [$inp]! @ load round 1 key
+
+ vmov.i8 @XMM[8], #0x01 @ bit masks
+ vmov.i8 @XMM[9], #0x02
+ vmov.i8 @XMM[10], #0x04
+ vmov.i8 @XMM[11], #0x08
+ vmov.i8 @XMM[12], #0x10
+ vmov.i8 @XMM[13], #0x20
+ vldmia $const, {@XMM[14]} @ .LM0
+
+#ifdef __ARMEL__
+ vrev32.8 @XMM[7], @XMM[7]
+ vrev32.8 @XMM[15], @XMM[15]
+#endif
+ sub $rounds,$rounds,#1
+ vstmia $out!, {@XMM[7]} @ save round 0 key
+ b .Lkey_loop
+
+.align 4
+.Lkey_loop:
+ vtbl.8 `&Dlo(@XMM[7])`,{@XMM[15]},`&Dlo(@XMM[14])`
+ vtbl.8 `&Dhi(@XMM[7])`,{@XMM[15]},`&Dhi(@XMM[14])`
+ vmov.i8 @XMM[6], #0x40
+ vmov.i8 @XMM[15], #0x80
+
+ vtst.8 @XMM[0], @XMM[7], @XMM[8]
+ vtst.8 @XMM[1], @XMM[7], @XMM[9]
+ vtst.8 @XMM[2], @XMM[7], @XMM[10]
+ vtst.8 @XMM[3], @XMM[7], @XMM[11]
+ vtst.8 @XMM[4], @XMM[7], @XMM[12]
+ vtst.8 @XMM[5], @XMM[7], @XMM[13]
+ vtst.8 @XMM[6], @XMM[7], @XMM[6]
+ vtst.8 @XMM[7], @XMM[7], @XMM[15]
+ vld1.8 {@XMM[15]}, [$inp]! @ load next round key
+ vmvn @XMM[0], @XMM[0] @ "pnot"
+ vmvn @XMM[1], @XMM[1]
+ vmvn @XMM[5], @XMM[5]
+ vmvn @XMM[6], @XMM[6]
+#ifdef __ARMEL__
+ vrev32.8 @XMM[15], @XMM[15]
+#endif
+ subs $rounds,$rounds,#1
+ vstmia $out!,{@XMM[0]-@XMM[7]} @ write bit-sliced round key
+ bne .Lkey_loop
+
+ vmov.i8 @XMM[7],#0x63 @ compose .L63
+ @ don't save last round key
+ bx lr
+.size _bsaes_key_convert,.-_bsaes_key_convert
+___
+}
+
+if (0) { # following four functions are unsupported interface
+ # used for benchmarking...
+$code.=<<___;
+.globl bsaes_enc_key_convert
+.type bsaes_enc_key_convert,%function
+.align 4
+bsaes_enc_key_convert:
+ stmdb sp!,{r4-r6,lr}
+ vstmdb sp!,{d8-d15} @ ABI specification says so
+
+ ldr r5,[$inp,#240] @ pass rounds
+ mov r4,$inp @ pass key
+ mov r12,$out @ pass key schedule
+ bl _bsaes_key_convert
+ veor @XMM[7],@XMM[7],@XMM[15] @ fix up last round key
+ vstmia r12, {@XMM[7]} @ save last round key
+
+ vldmia sp!,{d8-d15}
+ ldmia sp!,{r4-r6,pc}
+.size bsaes_enc_key_convert,.-bsaes_enc_key_convert
+
+.globl bsaes_encrypt_128
+.type bsaes_encrypt_128,%function
+.align 4
+bsaes_encrypt_128:
+ stmdb sp!,{r4-r6,lr}
+ vstmdb sp!,{d8-d15} @ ABI specification says so
+.Lenc128_loop:
+ vld1.8 {@XMM[0]-@XMM[1]}, [$inp]! @ load input
+ vld1.8 {@XMM[2]-@XMM[3]}, [$inp]!
+ mov r4,$key @ pass the key
+ vld1.8 {@XMM[4]-@XMM[5]}, [$inp]!
+ mov r5,#10 @ pass rounds
+ vld1.8 {@XMM[6]-@XMM[7]}, [$inp]!
+
+ bl _bsaes_encrypt8
+
+ vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output
+ vst1.8 {@XMM[4]}, [$out]!
+ vst1.8 {@XMM[6]}, [$out]!
+ vst1.8 {@XMM[3]}, [$out]!
+ vst1.8 {@XMM[7]}, [$out]!
+ vst1.8 {@XMM[2]}, [$out]!
+ subs $len,$len,#0x80
+ vst1.8 {@XMM[5]}, [$out]!
+ bhi .Lenc128_loop
+
+ vldmia sp!,{d8-d15}
+ ldmia sp!,{r4-r6,pc}
+.size bsaes_encrypt_128,.-bsaes_encrypt_128
+
+.globl bsaes_dec_key_convert
+.type bsaes_dec_key_convert,%function
+.align 4
+bsaes_dec_key_convert:
+ stmdb sp!,{r4-r6,lr}
+ vstmdb sp!,{d8-d15} @ ABI specification says so
+
+ ldr r5,[$inp,#240] @ pass rounds
+ mov r4,$inp @ pass key
+ mov r12,$out @ pass key schedule
+ bl _bsaes_key_convert
+ vldmia $out, {@XMM[6]}
+ vstmia r12, {@XMM[15]} @ save last round key
+ veor @XMM[7], @XMM[7], @XMM[6] @ fix up round 0 key
+ vstmia $out, {@XMM[7]}
+
+ vldmia sp!,{d8-d15}
+ ldmia sp!,{r4-r6,pc}
+.size bsaes_dec_key_convert,.-bsaes_dec_key_convert
+
+.globl bsaes_decrypt_128
+.type bsaes_decrypt_128,%function
+.align 4
+bsaes_decrypt_128:
+ stmdb sp!,{r4-r6,lr}
+ vstmdb sp!,{d8-d15} @ ABI specification says so
+.Ldec128_loop:
+ vld1.8 {@XMM[0]-@XMM[1]}, [$inp]! @ load input
+ vld1.8 {@XMM[2]-@XMM[3]}, [$inp]!
+ mov r4,$key @ pass the key
+ vld1.8 {@XMM[4]-@XMM[5]}, [$inp]!
+ mov r5,#10 @ pass rounds
+ vld1.8 {@XMM[6]-@XMM[7]}, [$inp]!
+
+ bl _bsaes_decrypt8
+
+ vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output
+ vst1.8 {@XMM[6]}, [$out]!
+ vst1.8 {@XMM[4]}, [$out]!
+ vst1.8 {@XMM[2]}, [$out]!
+ vst1.8 {@XMM[7]}, [$out]!
+ vst1.8 {@XMM[3]}, [$out]!
+ subs $len,$len,#0x80
+ vst1.8 {@XMM[5]}, [$out]!
+ bhi .Ldec128_loop
+
+ vldmia sp!,{d8-d15}
+ ldmia sp!,{r4-r6,pc}
+.size bsaes_decrypt_128,.-bsaes_decrypt_128
+___
+}
+{
+my ($inp,$out,$len,$key, $ivp,$fp,$rounds)=map("r$_",(0..3,8..10));
+my ($keysched)=("sp");
+
+$code.=<<___;
+.extern AES_cbc_encrypt
+.extern AES_decrypt
+
+.global bsaes_cbc_encrypt
+.type bsaes_cbc_encrypt,%function
+.align 5
+bsaes_cbc_encrypt:
+#ifndef __KERNEL__
+ cmp $len, #128
+#ifndef __thumb__
+ blo AES_cbc_encrypt
+#else
+ bhs 1f
+ b AES_cbc_encrypt
+1:
+#endif
+#endif
+
+ @ it is up to the caller to make sure we are called with enc == 0
+
+ mov ip, sp
+ stmdb sp!, {r4-r10, lr}
+ VFP_ABI_PUSH
+ ldr $ivp, [ip] @ IV is 1st arg on the stack
+ mov $len, $len, lsr#4 @ len in 16 byte blocks
+ sub sp, #0x10 @ scratch space to carry over the IV
+ mov $fp, sp @ save sp
+
+ ldr $rounds, [$key, #240] @ get # of rounds
+#ifndef BSAES_ASM_EXTENDED_KEY
+ @ allocate the key schedule on the stack
+ sub r12, sp, $rounds, lsl#7 @ 128 bytes per inner round key
+ add r12, #`128-32` @ sifze of bit-slices key schedule
+
+ @ populate the key schedule
+ mov r4, $key @ pass key
+ mov r5, $rounds @ pass # of rounds
+ mov sp, r12 @ sp is $keysched
+ bl _bsaes_key_convert
+ vldmia $keysched, {@XMM[6]}
+ vstmia r12, {@XMM[15]} @ save last round key
+ veor @XMM[7], @XMM[7], @XMM[6] @ fix up round 0 key
+ vstmia $keysched, {@XMM[7]}
+#else
+ ldr r12, [$key, #244]
+ eors r12, #1
+ beq 0f
+
+ @ populate the key schedule
+ str r12, [$key, #244]
+ mov r4, $key @ pass key
+ mov r5, $rounds @ pass # of rounds
+ add r12, $key, #248 @ pass key schedule
+ bl _bsaes_key_convert
+ add r4, $key, #248
+ vldmia r4, {@XMM[6]}
+ vstmia r12, {@XMM[15]} @ save last round key
+ veor @XMM[7], @XMM[7], @XMM[6] @ fix up round 0 key
+ vstmia r4, {@XMM[7]}
+
+.align 2
+0:
+#endif
+
+ vld1.8 {@XMM[15]}, [$ivp] @ load IV
+ b .Lcbc_dec_loop
+
+.align 4
+.Lcbc_dec_loop:
+ subs $len, $len, #0x8
+ bmi .Lcbc_dec_loop_finish
+
+ vld1.8 {@XMM[0]-@XMM[1]}, [$inp]! @ load input
+ vld1.8 {@XMM[2]-@XMM[3]}, [$inp]!
+#ifndef BSAES_ASM_EXTENDED_KEY
+ mov r4, $keysched @ pass the key
+#else
+ add r4, $key, #248
+#endif
+ vld1.8 {@XMM[4]-@XMM[5]}, [$inp]!
+ mov r5, $rounds
+ vld1.8 {@XMM[6]-@XMM[7]}, [$inp]
+ sub $inp, $inp, #0x60
+ vstmia $fp, {@XMM[15]} @ put aside IV
+
+ bl _bsaes_decrypt8
+
+ vldmia $fp, {@XMM[14]} @ reload IV
+ vld1.8 {@XMM[8]-@XMM[9]}, [$inp]! @ reload input
+ veor @XMM[0], @XMM[0], @XMM[14] @ ^= IV
+ vld1.8 {@XMM[10]-@XMM[11]}, [$inp]!
+ veor @XMM[1], @XMM[1], @XMM[8]
+ veor @XMM[6], @XMM[6], @XMM[9]
+ vld1.8 {@XMM[12]-@XMM[13]}, [$inp]!
+ veor @XMM[4], @XMM[4], @XMM[10]
+ veor @XMM[2], @XMM[2], @XMM[11]
+ vld1.8 {@XMM[14]-@XMM[15]}, [$inp]!
+ veor @XMM[7], @XMM[7], @XMM[12]
+ vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output
+ veor @XMM[3], @XMM[3], @XMM[13]
+ vst1.8 {@XMM[6]}, [$out]!
+ veor @XMM[5], @XMM[5], @XMM[14]
+ vst1.8 {@XMM[4]}, [$out]!
+ vst1.8 {@XMM[2]}, [$out]!
+ vst1.8 {@XMM[7]}, [$out]!
+ vst1.8 {@XMM[3]}, [$out]!
+ vst1.8 {@XMM[5]}, [$out]!
+
+ b .Lcbc_dec_loop
+
+.Lcbc_dec_loop_finish:
+ adds $len, $len, #8
+ beq .Lcbc_dec_done
+
+ vld1.8 {@XMM[0]}, [$inp]! @ load input
+ cmp $len, #2
+ blo .Lcbc_dec_one
+ vld1.8 {@XMM[1]}, [$inp]!
+#ifndef BSAES_ASM_EXTENDED_KEY
+ mov r4, $keysched @ pass the key
+#else
+ add r4, $key, #248
+#endif
+ mov r5, $rounds
+ vstmia $fp, {@XMM[15]} @ put aside IV
+ beq .Lcbc_dec_two
+ vld1.8 {@XMM[2]}, [$inp]!
+ cmp $len, #4
+ blo .Lcbc_dec_three
+ vld1.8 {@XMM[3]}, [$inp]!
+ beq .Lcbc_dec_four
+ vld1.8 {@XMM[4]}, [$inp]!
+ cmp $len, #6
+ blo .Lcbc_dec_five
+ vld1.8 {@XMM[5]}, [$inp]!
+ beq .Lcbc_dec_six
+ vld1.8 {@XMM[6]}, [$inp]!
+ sub $inp, $inp, #0x70
+
+ bl _bsaes_decrypt8
+
+ vldmia $fp, {@XMM[14]} @ reload IV
+ vld1.8 {@XMM[8]-@XMM[9]}, [$inp]! @ reload input
+ veor @XMM[0], @XMM[0], @XMM[14] @ ^= IV
+ vld1.8 {@XMM[10]-@XMM[11]}, [$inp]!
+ veor @XMM[1], @XMM[1], @XMM[8]
+ veor @XMM[6], @XMM[6], @XMM[9]
+ vld1.8 {@XMM[12]-@XMM[13]}, [$inp]!
+ veor @XMM[4], @XMM[4], @XMM[10]
+ veor @XMM[2], @XMM[2], @XMM[11]
+ vld1.8 {@XMM[15]}, [$inp]!
+ veor @XMM[7], @XMM[7], @XMM[12]
+ vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output
+ veor @XMM[3], @XMM[3], @XMM[13]
+ vst1.8 {@XMM[6]}, [$out]!
+ vst1.8 {@XMM[4]}, [$out]!
+ vst1.8 {@XMM[2]}, [$out]!
+ vst1.8 {@XMM[7]}, [$out]!
+ vst1.8 {@XMM[3]}, [$out]!
+ b .Lcbc_dec_done
+.align 4
+.Lcbc_dec_six:
+ sub $inp, $inp, #0x60
+ bl _bsaes_decrypt8
+ vldmia $fp,{@XMM[14]} @ reload IV
+ vld1.8 {@XMM[8]-@XMM[9]}, [$inp]! @ reload input
+ veor @XMM[0], @XMM[0], @XMM[14] @ ^= IV
+ vld1.8 {@XMM[10]-@XMM[11]}, [$inp]!
+ veor @XMM[1], @XMM[1], @XMM[8]
+ veor @XMM[6], @XMM[6], @XMM[9]
+ vld1.8 {@XMM[12]}, [$inp]!
+ veor @XMM[4], @XMM[4], @XMM[10]
+ veor @XMM[2], @XMM[2], @XMM[11]
+ vld1.8 {@XMM[15]}, [$inp]!
+ veor @XMM[7], @XMM[7], @XMM[12]
+ vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output
+ vst1.8 {@XMM[6]}, [$out]!
+ vst1.8 {@XMM[4]}, [$out]!
+ vst1.8 {@XMM[2]}, [$out]!
+ vst1.8 {@XMM[7]}, [$out]!
+ b .Lcbc_dec_done
+.align 4
+.Lcbc_dec_five:
+ sub $inp, $inp, #0x50
+ bl _bsaes_decrypt8
+ vldmia $fp, {@XMM[14]} @ reload IV
+ vld1.8 {@XMM[8]-@XMM[9]}, [$inp]! @ reload input
+ veor @XMM[0], @XMM[0], @XMM[14] @ ^= IV
+ vld1.8 {@XMM[10]-@XMM[11]}, [$inp]!
+ veor @XMM[1], @XMM[1], @XMM[8]
+ veor @XMM[6], @XMM[6], @XMM[9]
+ vld1.8 {@XMM[15]}, [$inp]!
+ veor @XMM[4], @XMM[4], @XMM[10]
+ vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output
+ veor @XMM[2], @XMM[2], @XMM[11]
+ vst1.8 {@XMM[6]}, [$out]!
+ vst1.8 {@XMM[4]}, [$out]!
+ vst1.8 {@XMM[2]}, [$out]!
+ b .Lcbc_dec_done
+.align 4
+.Lcbc_dec_four:
+ sub $inp, $inp, #0x40
+ bl _bsaes_decrypt8
+ vldmia $fp, {@XMM[14]} @ reload IV
+ vld1.8 {@XMM[8]-@XMM[9]}, [$inp]! @ reload input
+ veor @XMM[0], @XMM[0], @XMM[14] @ ^= IV
+ vld1.8 {@XMM[10]}, [$inp]!
+ veor @XMM[1], @XMM[1], @XMM[8]
+ veor @XMM[6], @XMM[6], @XMM[9]
+ vld1.8 {@XMM[15]}, [$inp]!
+ veor @XMM[4], @XMM[4], @XMM[10]
+ vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output
+ vst1.8 {@XMM[6]}, [$out]!
+ vst1.8 {@XMM[4]}, [$out]!
+ b .Lcbc_dec_done
+.align 4
+.Lcbc_dec_three:
+ sub $inp, $inp, #0x30
+ bl _bsaes_decrypt8
+ vldmia $fp, {@XMM[14]} @ reload IV
+ vld1.8 {@XMM[8]-@XMM[9]}, [$inp]! @ reload input
+ veor @XMM[0], @XMM[0], @XMM[14] @ ^= IV
+ vld1.8 {@XMM[15]}, [$inp]!
+ veor @XMM[1], @XMM[1], @XMM[8]
+ veor @XMM[6], @XMM[6], @XMM[9]
+ vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output
+ vst1.8 {@XMM[6]}, [$out]!
+ b .Lcbc_dec_done
+.align 4
+.Lcbc_dec_two:
+ sub $inp, $inp, #0x20
+ bl _bsaes_decrypt8
+ vldmia $fp, {@XMM[14]} @ reload IV
+ vld1.8 {@XMM[8]}, [$inp]! @ reload input
+ veor @XMM[0], @XMM[0], @XMM[14] @ ^= IV
+ vld1.8 {@XMM[15]}, [$inp]! @ reload input
+ veor @XMM[1], @XMM[1], @XMM[8]
+ vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output
+ b .Lcbc_dec_done
+.align 4
+.Lcbc_dec_one:
+ sub $inp, $inp, #0x10
+ mov $rounds, $out @ save original out pointer
+ mov $out, $fp @ use the iv scratch space as out buffer
+ mov r2, $key
+ vmov @XMM[4],@XMM[15] @ just in case ensure that IV
+ vmov @XMM[5],@XMM[0] @ and input are preserved
+ bl AES_decrypt
+ vld1.8 {@XMM[0]}, [$fp,:64] @ load result
+ veor @XMM[0], @XMM[0], @XMM[4] @ ^= IV
+ vmov @XMM[15], @XMM[5] @ @XMM[5] holds input
+ vst1.8 {@XMM[0]}, [$rounds] @ write output
+
+.Lcbc_dec_done:
+#ifndef BSAES_ASM_EXTENDED_KEY
+ vmov.i32 q0, #0
+ vmov.i32 q1, #0
+.Lcbc_dec_bzero: @ wipe key schedule [if any]
+ vstmia $keysched!, {q0-q1}
+ cmp $keysched, $fp
+ bne .Lcbc_dec_bzero
+#endif
+
+ mov sp, $fp
+ add sp, #0x10 @ add sp,$fp,#0x10 is no good for thumb
+ vst1.8 {@XMM[15]}, [$ivp] @ return IV
+ VFP_ABI_POP
+ ldmia sp!, {r4-r10, pc}
+.size bsaes_cbc_encrypt,.-bsaes_cbc_encrypt
+___
+}
+{
+my ($inp,$out,$len,$key, $ctr,$fp,$rounds)=(map("r$_",(0..3,8..10)));
+my $const = "r6"; # shared with _bsaes_encrypt8_alt
+my $keysched = "sp";
+
+$code.=<<___;
+.extern AES_encrypt
+.global bsaes_ctr32_encrypt_blocks
+.type bsaes_ctr32_encrypt_blocks,%function
+.align 5
+bsaes_ctr32_encrypt_blocks:
+ cmp $len, #8 @ use plain AES for
+ blo .Lctr_enc_short @ small sizes
+
+ mov ip, sp
+ stmdb sp!, {r4-r10, lr}
+ VFP_ABI_PUSH
+ ldr $ctr, [ip] @ ctr is 1st arg on the stack
+ sub sp, sp, #0x10 @ scratch space to carry over the ctr
+ mov $fp, sp @ save sp
+
+ ldr $rounds, [$key, #240] @ get # of rounds
+#ifndef BSAES_ASM_EXTENDED_KEY
+ @ allocate the key schedule on the stack
+ sub r12, sp, $rounds, lsl#7 @ 128 bytes per inner round key
+ add r12, #`128-32` @ size of bit-sliced key schedule
+
+ @ populate the key schedule
+ mov r4, $key @ pass key
+ mov r5, $rounds @ pass # of rounds
+ mov sp, r12 @ sp is $keysched
+ bl _bsaes_key_convert
+ veor @XMM[7],@XMM[7],@XMM[15] @ fix up last round key
+ vstmia r12, {@XMM[7]} @ save last round key
+
+ vld1.8 {@XMM[0]}, [$ctr] @ load counter
+ add $ctr, $const, #.LREVM0SR-.LM0 @ borrow $ctr
+ vldmia $keysched, {@XMM[4]} @ load round0 key
+#else
+ ldr r12, [$key, #244]
+ eors r12, #1
+ beq 0f
+
+ @ populate the key schedule
+ str r12, [$key, #244]
+ mov r4, $key @ pass key
+ mov r5, $rounds @ pass # of rounds
+ add r12, $key, #248 @ pass key schedule
+ bl _bsaes_key_convert
+ veor @XMM[7],@XMM[7],@XMM[15] @ fix up last round key
+ vstmia r12, {@XMM[7]} @ save last round key
+
+.align 2
+0: add r12, $key, #248
+ vld1.8 {@XMM[0]}, [$ctr] @ load counter
+ adrl $ctr, .LREVM0SR @ borrow $ctr
+ vldmia r12, {@XMM[4]} @ load round0 key
+ sub sp, #0x10 @ place for adjusted round0 key
+#endif
+
+ vmov.i32 @XMM[8],#1 @ compose 1<<96
+ veor @XMM[9],@XMM[9],@XMM[9]
+ vrev32.8 @XMM[0],@XMM[0]
+ vext.8 @XMM[8],@XMM[9],@XMM[8],#4
+ vrev32.8 @XMM[4],@XMM[4]
+ vadd.u32 @XMM[9],@XMM[8],@XMM[8] @ compose 2<<96
+ vstmia $keysched, {@XMM[4]} @ save adjusted round0 key
+ b .Lctr_enc_loop
+
+.align 4
+.Lctr_enc_loop:
+ vadd.u32 @XMM[10], @XMM[8], @XMM[9] @ compose 3<<96
+ vadd.u32 @XMM[1], @XMM[0], @XMM[8] @ +1
+ vadd.u32 @XMM[2], @XMM[0], @XMM[9] @ +2
+ vadd.u32 @XMM[3], @XMM[0], @XMM[10] @ +3
+ vadd.u32 @XMM[4], @XMM[1], @XMM[10]
+ vadd.u32 @XMM[5], @XMM[2], @XMM[10]
+ vadd.u32 @XMM[6], @XMM[3], @XMM[10]
+ vadd.u32 @XMM[7], @XMM[4], @XMM[10]
+ vadd.u32 @XMM[10], @XMM[5], @XMM[10] @ next counter
+
+ @ Borrow prologue from _bsaes_encrypt8 to use the opportunity
+ @ to flip byte order in 32-bit counter
+
+ vldmia $keysched, {@XMM[9]} @ load round0 key
+#ifndef BSAES_ASM_EXTENDED_KEY
+ add r4, $keysched, #0x10 @ pass next round key
+#else
+ add r4, $key, #`248+16`
+#endif
+ vldmia $ctr, {@XMM[8]} @ .LREVM0SR
+ mov r5, $rounds @ pass rounds
+ vstmia $fp, {@XMM[10]} @ save next counter
+ sub $const, $ctr, #.LREVM0SR-.LSR @ pass constants
+
+ bl _bsaes_encrypt8_alt
+
+ subs $len, $len, #8
+ blo .Lctr_enc_loop_done
+
+ vld1.8 {@XMM[8]-@XMM[9]}, [$inp]! @ load input
+ vld1.8 {@XMM[10]-@XMM[11]}, [$inp]!
+ veor @XMM[0], @XMM[8]
+ veor @XMM[1], @XMM[9]
+ vld1.8 {@XMM[12]-@XMM[13]}, [$inp]!
+ veor @XMM[4], @XMM[10]
+ veor @XMM[6], @XMM[11]
+ vld1.8 {@XMM[14]-@XMM[15]}, [$inp]!
+ veor @XMM[3], @XMM[12]
+ vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output
+ veor @XMM[7], @XMM[13]
+ veor @XMM[2], @XMM[14]
+ vst1.8 {@XMM[4]}, [$out]!
+ veor @XMM[5], @XMM[15]
+ vst1.8 {@XMM[6]}, [$out]!
+ vmov.i32 @XMM[8], #1 @ compose 1<<96
+ vst1.8 {@XMM[3]}, [$out]!
+ veor @XMM[9], @XMM[9], @XMM[9]
+ vst1.8 {@XMM[7]}, [$out]!
+ vext.8 @XMM[8], @XMM[9], @XMM[8], #4
+ vst1.8 {@XMM[2]}, [$out]!
+ vadd.u32 @XMM[9],@XMM[8],@XMM[8] @ compose 2<<96
+ vst1.8 {@XMM[5]}, [$out]!
+ vldmia $fp, {@XMM[0]} @ load counter
+
+ bne .Lctr_enc_loop
+ b .Lctr_enc_done
+
+.align 4
+.Lctr_enc_loop_done:
+ add $len, $len, #8
+ vld1.8 {@XMM[8]}, [$inp]! @ load input
+ veor @XMM[0], @XMM[8]
+ vst1.8 {@XMM[0]}, [$out]! @ write output
+ cmp $len, #2
+ blo .Lctr_enc_done
+ vld1.8 {@XMM[9]}, [$inp]!
+ veor @XMM[1], @XMM[9]
+ vst1.8 {@XMM[1]}, [$out]!
+ beq .Lctr_enc_done
+ vld1.8 {@XMM[10]}, [$inp]!
+ veor @XMM[4], @XMM[10]
+ vst1.8 {@XMM[4]}, [$out]!
+ cmp $len, #4
+ blo .Lctr_enc_done
+ vld1.8 {@XMM[11]}, [$inp]!
+ veor @XMM[6], @XMM[11]
+ vst1.8 {@XMM[6]}, [$out]!
+ beq .Lctr_enc_done
+ vld1.8 {@XMM[12]}, [$inp]!
+ veor @XMM[3], @XMM[12]
+ vst1.8 {@XMM[3]}, [$out]!
+ cmp $len, #6
+ blo .Lctr_enc_done
+ vld1.8 {@XMM[13]}, [$inp]!
+ veor @XMM[7], @XMM[13]
+ vst1.8 {@XMM[7]}, [$out]!
+ beq .Lctr_enc_done
+ vld1.8 {@XMM[14]}, [$inp]
+ veor @XMM[2], @XMM[14]
+ vst1.8 {@XMM[2]}, [$out]!
+
+.Lctr_enc_done:
+ vmov.i32 q0, #0
+ vmov.i32 q1, #0
+#ifndef BSAES_ASM_EXTENDED_KEY
+.Lctr_enc_bzero: @ wipe key schedule [if any]
+ vstmia $keysched!, {q0-q1}
+ cmp $keysched, $fp
+ bne .Lctr_enc_bzero
+#else
+ vstmia $keysched, {q0-q1}
+#endif
+
+ mov sp, $fp
+ add sp, #0x10 @ add sp,$fp,#0x10 is no good for thumb
+ VFP_ABI_POP
+ ldmia sp!, {r4-r10, pc} @ return
+
+.align 4
+.Lctr_enc_short:
+ ldr ip, [sp] @ ctr pointer is passed on stack
+ stmdb sp!, {r4-r8, lr}
+
+ mov r4, $inp @ copy arguments
+ mov r5, $out
+ mov r6, $len
+ mov r7, $key
+ ldr r8, [ip, #12] @ load counter LSW
+ vld1.8 {@XMM[1]}, [ip] @ load whole counter value
+#ifdef __ARMEL__
+ rev r8, r8
+#endif
+ sub sp, sp, #0x10
+ vst1.8 {@XMM[1]}, [sp,:64] @ copy counter value
+ sub sp, sp, #0x10
+
+.Lctr_enc_short_loop:
+ add r0, sp, #0x10 @ input counter value
+ mov r1, sp @ output on the stack
+ mov r2, r7 @ key
+
+ bl AES_encrypt
+
+ vld1.8 {@XMM[0]}, [r4]! @ load input
+ vld1.8 {@XMM[1]}, [sp,:64] @ load encrypted counter
+ add r8, r8, #1
+#ifdef __ARMEL__
+ rev r0, r8
+ str r0, [sp, #0x1c] @ next counter value
+#else
+ str r8, [sp, #0x1c] @ next counter value
+#endif
+ veor @XMM[0],@XMM[0],@XMM[1]
+ vst1.8 {@XMM[0]}, [r5]! @ store output
+ subs r6, r6, #1
+ bne .Lctr_enc_short_loop
+
+ vmov.i32 q0, #0
+ vmov.i32 q1, #0
+ vstmia sp!, {q0-q1}
+
+ ldmia sp!, {r4-r8, pc}
+.size bsaes_ctr32_encrypt_blocks,.-bsaes_ctr32_encrypt_blocks
+___
+}
+{
+######################################################################
+# void bsaes_xts_[en|de]crypt(const char *inp,char *out,size_t len,
+# const AES_KEY *key1, const AES_KEY *key2,
+# const unsigned char iv[16]);
+#
+my ($inp,$out,$len,$key,$rounds,$magic,$fp)=(map("r$_",(7..10,1..3)));
+my $const="r6"; # returned by _bsaes_key_convert
+my $twmask=@XMM[5];
+my @T=@XMM[6..7];
+
+$code.=<<___;
+.globl bsaes_xts_encrypt
+.type bsaes_xts_encrypt,%function
+.align 4
+bsaes_xts_encrypt:
+ mov ip, sp
+ stmdb sp!, {r4-r10, lr} @ 0x20
+ VFP_ABI_PUSH
+ mov r6, sp @ future $fp
+
+ mov $inp, r0
+ mov $out, r1
+ mov $len, r2
+ mov $key, r3
+
+ sub r0, sp, #0x10 @ 0x10
+ bic r0, #0xf @ align at 16 bytes
+ mov sp, r0
+
+#ifdef XTS_CHAIN_TWEAK
+ ldr r0, [ip] @ pointer to input tweak
+#else
+ @ generate initial tweak
+ ldr r0, [ip, #4] @ iv[]
+ mov r1, sp
+ ldr r2, [ip, #0] @ key2
+ bl AES_encrypt
+ mov r0,sp @ pointer to initial tweak
+#endif
+
+ ldr $rounds, [$key, #240] @ get # of rounds
+ mov $fp, r6
+#ifndef BSAES_ASM_EXTENDED_KEY
+ @ allocate the key schedule on the stack
+ sub r12, sp, $rounds, lsl#7 @ 128 bytes per inner round key
+ @ add r12, #`128-32` @ size of bit-sliced key schedule
+ sub r12, #`32+16` @ place for tweak[9]
+
+ @ populate the key schedule
+ mov r4, $key @ pass key
+ mov r5, $rounds @ pass # of rounds
+ mov sp, r12
+ add r12, #0x90 @ pass key schedule
+ bl _bsaes_key_convert
+ veor @XMM[7], @XMM[7], @XMM[15] @ fix up last round key
+ vstmia r12, {@XMM[7]} @ save last round key
+#else
+ ldr r12, [$key, #244]
+ eors r12, #1
+ beq 0f
+
+ str r12, [$key, #244]
+ mov r4, $key @ pass key
+ mov r5, $rounds @ pass # of rounds
+ add r12, $key, #248 @ pass key schedule
+ bl _bsaes_key_convert
+ veor @XMM[7], @XMM[7], @XMM[15] @ fix up last round key
+ vstmia r12, {@XMM[7]}
+
+.align 2
+0: sub sp, #0x90 @ place for tweak[9]
+#endif
+
+ vld1.8 {@XMM[8]}, [r0] @ initial tweak
+ adr $magic, .Lxts_magic
+
+ subs $len, #0x80
+ blo .Lxts_enc_short
+ b .Lxts_enc_loop
+
+.align 4
+.Lxts_enc_loop:
+ vldmia $magic, {$twmask} @ load XTS magic
+ vshr.s64 @T[0], @XMM[8], #63
+ mov r0, sp
+ vand @T[0], @T[0], $twmask
+___
+for($i=9;$i<16;$i++) {
+$code.=<<___;
+ vadd.u64 @XMM[$i], @XMM[$i-1], @XMM[$i-1]
+ vst1.64 {@XMM[$i-1]}, [r0,:128]!
+ vswp `&Dhi("@T[0]")`,`&Dlo("@T[0]")`
+ vshr.s64 @T[1], @XMM[$i], #63
+ veor @XMM[$i], @XMM[$i], @T[0]
+ vand @T[1], @T[1], $twmask
+___
+ @T=reverse(@T);
+
+$code.=<<___ if ($i>=10);
+ vld1.8 {@XMM[$i-10]}, [$inp]!
+___
+$code.=<<___ if ($i>=11);
+ veor @XMM[$i-11], @XMM[$i-11], @XMM[$i-3]
+___
+}
+$code.=<<___;
+ vadd.u64 @XMM[8], @XMM[15], @XMM[15]
+ vst1.64 {@XMM[15]}, [r0,:128]!
+ vswp `&Dhi("@T[0]")`,`&Dlo("@T[0]")`
+ veor @XMM[8], @XMM[8], @T[0]
+ vst1.64 {@XMM[8]}, [r0,:128] @ next round tweak
+
+ vld1.8 {@XMM[6]-@XMM[7]}, [$inp]!
+ veor @XMM[5], @XMM[5], @XMM[13]
+#ifndef BSAES_ASM_EXTENDED_KEY
+ add r4, sp, #0x90 @ pass key schedule
+#else
+ add r4, $key, #248 @ pass key schedule
+#endif
+ veor @XMM[6], @XMM[6], @XMM[14]
+ mov r5, $rounds @ pass rounds
+ veor @XMM[7], @XMM[7], @XMM[15]
+ mov r0, sp
+
+ bl _bsaes_encrypt8
+
+ vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]!
+ vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]!
+ veor @XMM[0], @XMM[0], @XMM[ 8]
+ vld1.64 {@XMM[12]-@XMM[13]}, [r0,:128]!
+ veor @XMM[1], @XMM[1], @XMM[ 9]
+ veor @XMM[8], @XMM[4], @XMM[10]
+ vst1.8 {@XMM[0]-@XMM[1]}, [$out]!
+ veor @XMM[9], @XMM[6], @XMM[11]
+ vld1.64 {@XMM[14]-@XMM[15]}, [r0,:128]!
+ veor @XMM[10], @XMM[3], @XMM[12]
+ vst1.8 {@XMM[8]-@XMM[9]}, [$out]!
+ veor @XMM[11], @XMM[7], @XMM[13]
+ veor @XMM[12], @XMM[2], @XMM[14]
+ vst1.8 {@XMM[10]-@XMM[11]}, [$out]!
+ veor @XMM[13], @XMM[5], @XMM[15]
+ vst1.8 {@XMM[12]-@XMM[13]}, [$out]!
+
+ vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak
+
+ subs $len, #0x80
+ bpl .Lxts_enc_loop
+
+.Lxts_enc_short:
+ adds $len, #0x70
+ bmi .Lxts_enc_done
+
+ vldmia $magic, {$twmask} @ load XTS magic
+ vshr.s64 @T[0], @XMM[8], #63
+ mov r0, sp
+ vand @T[0], @T[0], $twmask
+___
+for($i=9;$i<16;$i++) {
+$code.=<<___;
+ vadd.u64 @XMM[$i], @XMM[$i-1], @XMM[$i-1]
+ vst1.64 {@XMM[$i-1]}, [r0,:128]!
+ vswp `&Dhi("@T[0]")`,`&Dlo("@T[0]")`
+ vshr.s64 @T[1], @XMM[$i], #63
+ veor @XMM[$i], @XMM[$i], @T[0]
+ vand @T[1], @T[1], $twmask
+___
+ @T=reverse(@T);
+
+$code.=<<___ if ($i>=10);
+ vld1.8 {@XMM[$i-10]}, [$inp]!
+ subs $len, #0x10
+ bmi .Lxts_enc_`$i-9`
+___
+$code.=<<___ if ($i>=11);
+ veor @XMM[$i-11], @XMM[$i-11], @XMM[$i-3]
+___
+}
+$code.=<<___;
+ sub $len, #0x10
+ vst1.64 {@XMM[15]}, [r0,:128] @ next round tweak
+
+ vld1.8 {@XMM[6]}, [$inp]!
+ veor @XMM[5], @XMM[5], @XMM[13]
+#ifndef BSAES_ASM_EXTENDED_KEY
+ add r4, sp, #0x90 @ pass key schedule
+#else
+ add r4, $key, #248 @ pass key schedule
+#endif
+ veor @XMM[6], @XMM[6], @XMM[14]
+ mov r5, $rounds @ pass rounds
+ mov r0, sp
+
+ bl _bsaes_encrypt8
+
+ vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]!
+ vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]!
+ veor @XMM[0], @XMM[0], @XMM[ 8]
+ vld1.64 {@XMM[12]-@XMM[13]}, [r0,:128]!
+ veor @XMM[1], @XMM[1], @XMM[ 9]
+ veor @XMM[8], @XMM[4], @XMM[10]
+ vst1.8 {@XMM[0]-@XMM[1]}, [$out]!
+ veor @XMM[9], @XMM[6], @XMM[11]
+ vld1.64 {@XMM[14]}, [r0,:128]!
+ veor @XMM[10], @XMM[3], @XMM[12]
+ vst1.8 {@XMM[8]-@XMM[9]}, [$out]!
+ veor @XMM[11], @XMM[7], @XMM[13]
+ veor @XMM[12], @XMM[2], @XMM[14]
+ vst1.8 {@XMM[10]-@XMM[11]}, [$out]!
+ vst1.8 {@XMM[12]}, [$out]!
+
+ vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak
+ b .Lxts_enc_done
+.align 4
+.Lxts_enc_6:
+ vst1.64 {@XMM[14]}, [r0,:128] @ next round tweak
+
+ veor @XMM[4], @XMM[4], @XMM[12]
+#ifndef BSAES_ASM_EXTENDED_KEY
+ add r4, sp, #0x90 @ pass key schedule
+#else
+ add r4, $key, #248 @ pass key schedule
+#endif
+ veor @XMM[5], @XMM[5], @XMM[13]
+ mov r5, $rounds @ pass rounds
+ mov r0, sp
+
+ bl _bsaes_encrypt8
+
+ vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]!
+ vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]!
+ veor @XMM[0], @XMM[0], @XMM[ 8]
+ vld1.64 {@XMM[12]-@XMM[13]}, [r0,:128]!
+ veor @XMM[1], @XMM[1], @XMM[ 9]
+ veor @XMM[8], @XMM[4], @XMM[10]
+ vst1.8 {@XMM[0]-@XMM[1]}, [$out]!
+ veor @XMM[9], @XMM[6], @XMM[11]
+ veor @XMM[10], @XMM[3], @XMM[12]
+ vst1.8 {@XMM[8]-@XMM[9]}, [$out]!
+ veor @XMM[11], @XMM[7], @XMM[13]
+ vst1.8 {@XMM[10]-@XMM[11]}, [$out]!
+
+ vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak
+ b .Lxts_enc_done
+
+@ put this in range for both ARM and Thumb mode adr instructions
+.align 5
+.Lxts_magic:
+ .quad 1, 0x87
+
+.align 5
+.Lxts_enc_5:
+ vst1.64 {@XMM[13]}, [r0,:128] @ next round tweak
+
+ veor @XMM[3], @XMM[3], @XMM[11]
+#ifndef BSAES_ASM_EXTENDED_KEY
+ add r4, sp, #0x90 @ pass key schedule
+#else
+ add r4, $key, #248 @ pass key schedule
+#endif
+ veor @XMM[4], @XMM[4], @XMM[12]
+ mov r5, $rounds @ pass rounds
+ mov r0, sp
+
+ bl _bsaes_encrypt8
+
+ vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]!
+ vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]!
+ veor @XMM[0], @XMM[0], @XMM[ 8]
+ vld1.64 {@XMM[12]}, [r0,:128]!
+ veor @XMM[1], @XMM[1], @XMM[ 9]
+ veor @XMM[8], @XMM[4], @XMM[10]
+ vst1.8 {@XMM[0]-@XMM[1]}, [$out]!
+ veor @XMM[9], @XMM[6], @XMM[11]
+ veor @XMM[10], @XMM[3], @XMM[12]
+ vst1.8 {@XMM[8]-@XMM[9]}, [$out]!
+ vst1.8 {@XMM[10]}, [$out]!
+
+ vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak
+ b .Lxts_enc_done
+.align 4
+.Lxts_enc_4:
+ vst1.64 {@XMM[12]}, [r0,:128] @ next round tweak
+
+ veor @XMM[2], @XMM[2], @XMM[10]
+#ifndef BSAES_ASM_EXTENDED_KEY
+ add r4, sp, #0x90 @ pass key schedule
+#else
+ add r4, $key, #248 @ pass key schedule
+#endif
+ veor @XMM[3], @XMM[3], @XMM[11]
+ mov r5, $rounds @ pass rounds
+ mov r0, sp
+
+ bl _bsaes_encrypt8
+
+ vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]!
+ vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]!
+ veor @XMM[0], @XMM[0], @XMM[ 8]
+ veor @XMM[1], @XMM[1], @XMM[ 9]
+ veor @XMM[8], @XMM[4], @XMM[10]
+ vst1.8 {@XMM[0]-@XMM[1]}, [$out]!
+ veor @XMM[9], @XMM[6], @XMM[11]
+ vst1.8 {@XMM[8]-@XMM[9]}, [$out]!
+
+ vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak
+ b .Lxts_enc_done
+.align 4
+.Lxts_enc_3:
+ vst1.64 {@XMM[11]}, [r0,:128] @ next round tweak
+
+ veor @XMM[1], @XMM[1], @XMM[9]
+#ifndef BSAES_ASM_EXTENDED_KEY
+ add r4, sp, #0x90 @ pass key schedule
+#else
+ add r4, $key, #248 @ pass key schedule
+#endif
+ veor @XMM[2], @XMM[2], @XMM[10]
+ mov r5, $rounds @ pass rounds
+ mov r0, sp
+
+ bl _bsaes_encrypt8
+
+ vld1.64 {@XMM[8]-@XMM[9]}, [r0,:128]!
+ vld1.64 {@XMM[10]}, [r0,:128]!
+ veor @XMM[0], @XMM[0], @XMM[ 8]
+ veor @XMM[1], @XMM[1], @XMM[ 9]
+ veor @XMM[8], @XMM[4], @XMM[10]
+ vst1.8 {@XMM[0]-@XMM[1]}, [$out]!
+ vst1.8 {@XMM[8]}, [$out]!
+
+ vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak
+ b .Lxts_enc_done
+.align 4
+.Lxts_enc_2:
+ vst1.64 {@XMM[10]}, [r0,:128] @ next round tweak
+
+ veor @XMM[0], @XMM[0], @XMM[8]
+#ifndef BSAES_ASM_EXTENDED_KEY
+ add r4, sp, #0x90 @ pass key schedule
+#else
+ add r4, $key, #248 @ pass key schedule
+#endif
+ veor @XMM[1], @XMM[1], @XMM[9]
+ mov r5, $rounds @ pass rounds
+ mov r0, sp
+
+ bl _bsaes_encrypt8
+
+ vld1.64 {@XMM[8]-@XMM[9]}, [r0,:128]!
+ veor @XMM[0], @XMM[0], @XMM[ 8]
+ veor @XMM[1], @XMM[1], @XMM[ 9]
+ vst1.8 {@XMM[0]-@XMM[1]}, [$out]!
+
+ vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak
+ b .Lxts_enc_done
+.align 4
+.Lxts_enc_1:
+ mov r0, sp
+ veor @XMM[0], @XMM[8]
+ mov r1, sp
+ vst1.8 {@XMM[0]}, [sp,:128]
+ mov r2, $key
+ mov r4, $fp @ preserve fp
+
+ bl AES_encrypt
+
+ vld1.8 {@XMM[0]}, [sp,:128]
+ veor @XMM[0], @XMM[0], @XMM[8]
+ vst1.8 {@XMM[0]}, [$out]!
+ mov $fp, r4
+
+ vmov @XMM[8], @XMM[9] @ next round tweak
+
+.Lxts_enc_done:
+#ifndef XTS_CHAIN_TWEAK
+ adds $len, #0x10
+ beq .Lxts_enc_ret
+ sub r6, $out, #0x10
+
+.Lxts_enc_steal:
+ ldrb r0, [$inp], #1
+ ldrb r1, [$out, #-0x10]
+ strb r0, [$out, #-0x10]
+ strb r1, [$out], #1
+
+ subs $len, #1
+ bhi .Lxts_enc_steal
+
+ vld1.8 {@XMM[0]}, [r6]
+ mov r0, sp
+ veor @XMM[0], @XMM[0], @XMM[8]
+ mov r1, sp
+ vst1.8 {@XMM[0]}, [sp,:128]
+ mov r2, $key
+ mov r4, $fp @ preserve fp
+
+ bl AES_encrypt
+
+ vld1.8 {@XMM[0]}, [sp,:128]
+ veor @XMM[0], @XMM[0], @XMM[8]
+ vst1.8 {@XMM[0]}, [r6]
+ mov $fp, r4
+#endif
+
+.Lxts_enc_ret:
+ bic r0, $fp, #0xf
+ vmov.i32 q0, #0
+ vmov.i32 q1, #0
+#ifdef XTS_CHAIN_TWEAK
+ ldr r1, [$fp, #0x20+VFP_ABI_FRAME] @ chain tweak
+#endif
+.Lxts_enc_bzero: @ wipe key schedule [if any]
+ vstmia sp!, {q0-q1}
+ cmp sp, r0
+ bne .Lxts_enc_bzero
+
+ mov sp, $fp
+#ifdef XTS_CHAIN_TWEAK
+ vst1.8 {@XMM[8]}, [r1]
+#endif
+ VFP_ABI_POP
+ ldmia sp!, {r4-r10, pc} @ return
+
+.size bsaes_xts_encrypt,.-bsaes_xts_encrypt
+
+.globl bsaes_xts_decrypt
+.type bsaes_xts_decrypt,%function
+.align 4
+bsaes_xts_decrypt:
+ mov ip, sp
+ stmdb sp!, {r4-r10, lr} @ 0x20
+ VFP_ABI_PUSH
+ mov r6, sp @ future $fp
+
+ mov $inp, r0
+ mov $out, r1
+ mov $len, r2
+ mov $key, r3
+
+ sub r0, sp, #0x10 @ 0x10
+ bic r0, #0xf @ align at 16 bytes
+ mov sp, r0
+
+#ifdef XTS_CHAIN_TWEAK
+ ldr r0, [ip] @ pointer to input tweak
+#else
+ @ generate initial tweak
+ ldr r0, [ip, #4] @ iv[]
+ mov r1, sp
+ ldr r2, [ip, #0] @ key2
+ bl AES_encrypt
+ mov r0, sp @ pointer to initial tweak
+#endif
+
+ ldr $rounds, [$key, #240] @ get # of rounds
+ mov $fp, r6
+#ifndef BSAES_ASM_EXTENDED_KEY
+ @ allocate the key schedule on the stack
+ sub r12, sp, $rounds, lsl#7 @ 128 bytes per inner round key
+ @ add r12, #`128-32` @ size of bit-sliced key schedule
+ sub r12, #`32+16` @ place for tweak[9]
+
+ @ populate the key schedule
+ mov r4, $key @ pass key
+ mov r5, $rounds @ pass # of rounds
+ mov sp, r12
+ add r12, #0x90 @ pass key schedule
+ bl _bsaes_key_convert
+ add r4, sp, #0x90
+ vldmia r4, {@XMM[6]}
+ vstmia r12, {@XMM[15]} @ save last round key
+ veor @XMM[7], @XMM[7], @XMM[6] @ fix up round 0 key
+ vstmia r4, {@XMM[7]}
+#else
+ ldr r12, [$key, #244]
+ eors r12, #1
+ beq 0f
+
+ str r12, [$key, #244]
+ mov r4, $key @ pass key
+ mov r5, $rounds @ pass # of rounds
+ add r12, $key, #248 @ pass key schedule
+ bl _bsaes_key_convert
+ add r4, $key, #248
+ vldmia r4, {@XMM[6]}
+ vstmia r12, {@XMM[15]} @ save last round key
+ veor @XMM[7], @XMM[7], @XMM[6] @ fix up round 0 key
+ vstmia r4, {@XMM[7]}
+
+.align 2
+0: sub sp, #0x90 @ place for tweak[9]
+#endif
+ vld1.8 {@XMM[8]}, [r0] @ initial tweak
+ adr $magic, .Lxts_magic
+
+ tst $len, #0xf @ if not multiple of 16
+ it ne @ Thumb2 thing, sanity check in ARM
+ subne $len, #0x10 @ subtract another 16 bytes
+ subs $len, #0x80
+
+ blo .Lxts_dec_short
+ b .Lxts_dec_loop
+
+.align 4
+.Lxts_dec_loop:
+ vldmia $magic, {$twmask} @ load XTS magic
+ vshr.s64 @T[0], @XMM[8], #63
+ mov r0, sp
+ vand @T[0], @T[0], $twmask
+___
+for($i=9;$i<16;$i++) {
+$code.=<<___;
+ vadd.u64 @XMM[$i], @XMM[$i-1], @XMM[$i-1]
+ vst1.64 {@XMM[$i-1]}, [r0,:128]!
+ vswp `&Dhi("@T[0]")`,`&Dlo("@T[0]")`
+ vshr.s64 @T[1], @XMM[$i], #63
+ veor @XMM[$i], @XMM[$i], @T[0]
+ vand @T[1], @T[1], $twmask
+___
+ @T=reverse(@T);
+
+$code.=<<___ if ($i>=10);
+ vld1.8 {@XMM[$i-10]}, [$inp]!
+___
+$code.=<<___ if ($i>=11);
+ veor @XMM[$i-11], @XMM[$i-11], @XMM[$i-3]
+___
+}
+$code.=<<___;
+ vadd.u64 @XMM[8], @XMM[15], @XMM[15]
+ vst1.64 {@XMM[15]}, [r0,:128]!
+ vswp `&Dhi("@T[0]")`,`&Dlo("@T[0]")`
+ veor @XMM[8], @XMM[8], @T[0]
+ vst1.64 {@XMM[8]}, [r0,:128] @ next round tweak
+
+ vld1.8 {@XMM[6]-@XMM[7]}, [$inp]!
+ veor @XMM[5], @XMM[5], @XMM[13]
+#ifndef BSAES_ASM_EXTENDED_KEY
+ add r4, sp, #0x90 @ pass key schedule
+#else
+ add r4, $key, #248 @ pass key schedule
+#endif
+ veor @XMM[6], @XMM[6], @XMM[14]
+ mov r5, $rounds @ pass rounds
+ veor @XMM[7], @XMM[7], @XMM[15]
+ mov r0, sp
+
+ bl _bsaes_decrypt8
+
+ vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]!
+ vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]!
+ veor @XMM[0], @XMM[0], @XMM[ 8]
+ vld1.64 {@XMM[12]-@XMM[13]}, [r0,:128]!
+ veor @XMM[1], @XMM[1], @XMM[ 9]
+ veor @XMM[8], @XMM[6], @XMM[10]
+ vst1.8 {@XMM[0]-@XMM[1]}, [$out]!
+ veor @XMM[9], @XMM[4], @XMM[11]
+ vld1.64 {@XMM[14]-@XMM[15]}, [r0,:128]!
+ veor @XMM[10], @XMM[2], @XMM[12]
+ vst1.8 {@XMM[8]-@XMM[9]}, [$out]!
+ veor @XMM[11], @XMM[7], @XMM[13]
+ veor @XMM[12], @XMM[3], @XMM[14]
+ vst1.8 {@XMM[10]-@XMM[11]}, [$out]!
+ veor @XMM[13], @XMM[5], @XMM[15]
+ vst1.8 {@XMM[12]-@XMM[13]}, [$out]!
+
+ vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak
+
+ subs $len, #0x80
+ bpl .Lxts_dec_loop
+
+.Lxts_dec_short:
+ adds $len, #0x70
+ bmi .Lxts_dec_done
+
+ vldmia $magic, {$twmask} @ load XTS magic
+ vshr.s64 @T[0], @XMM[8], #63
+ mov r0, sp
+ vand @T[0], @T[0], $twmask
+___
+for($i=9;$i<16;$i++) {
+$code.=<<___;
+ vadd.u64 @XMM[$i], @XMM[$i-1], @XMM[$i-1]
+ vst1.64 {@XMM[$i-1]}, [r0,:128]!
+ vswp `&Dhi("@T[0]")`,`&Dlo("@T[0]")`
+ vshr.s64 @T[1], @XMM[$i], #63
+ veor @XMM[$i], @XMM[$i], @T[0]
+ vand @T[1], @T[1], $twmask
+___
+ @T=reverse(@T);
+
+$code.=<<___ if ($i>=10);
+ vld1.8 {@XMM[$i-10]}, [$inp]!
+ subs $len, #0x10
+ bmi .Lxts_dec_`$i-9`
+___
+$code.=<<___ if ($i>=11);
+ veor @XMM[$i-11], @XMM[$i-11], @XMM[$i-3]
+___
+}
+$code.=<<___;
+ sub $len, #0x10
+ vst1.64 {@XMM[15]}, [r0,:128] @ next round tweak
+
+ vld1.8 {@XMM[6]}, [$inp]!
+ veor @XMM[5], @XMM[5], @XMM[13]
+#ifndef BSAES_ASM_EXTENDED_KEY
+ add r4, sp, #0x90 @ pass key schedule
+#else
+ add r4, $key, #248 @ pass key schedule
+#endif
+ veor @XMM[6], @XMM[6], @XMM[14]
+ mov r5, $rounds @ pass rounds
+ mov r0, sp
+
+ bl _bsaes_decrypt8
+
+ vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]!
+ vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]!
+ veor @XMM[0], @XMM[0], @XMM[ 8]
+ vld1.64 {@XMM[12]-@XMM[13]}, [r0,:128]!
+ veor @XMM[1], @XMM[1], @XMM[ 9]
+ veor @XMM[8], @XMM[6], @XMM[10]
+ vst1.8 {@XMM[0]-@XMM[1]}, [$out]!
+ veor @XMM[9], @XMM[4], @XMM[11]
+ vld1.64 {@XMM[14]}, [r0,:128]!
+ veor @XMM[10], @XMM[2], @XMM[12]
+ vst1.8 {@XMM[8]-@XMM[9]}, [$out]!
+ veor @XMM[11], @XMM[7], @XMM[13]
+ veor @XMM[12], @XMM[3], @XMM[14]
+ vst1.8 {@XMM[10]-@XMM[11]}, [$out]!
+ vst1.8 {@XMM[12]}, [$out]!
+
+ vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak
+ b .Lxts_dec_done
+.align 4
+.Lxts_dec_6:
+ vst1.64 {@XMM[14]}, [r0,:128] @ next round tweak
+
+ veor @XMM[4], @XMM[4], @XMM[12]
+#ifndef BSAES_ASM_EXTENDED_KEY
+ add r4, sp, #0x90 @ pass key schedule
+#else
+ add r4, $key, #248 @ pass key schedule
+#endif
+ veor @XMM[5], @XMM[5], @XMM[13]
+ mov r5, $rounds @ pass rounds
+ mov r0, sp
+
+ bl _bsaes_decrypt8
+
+ vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]!
+ vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]!
+ veor @XMM[0], @XMM[0], @XMM[ 8]
+ vld1.64 {@XMM[12]-@XMM[13]}, [r0,:128]!
+ veor @XMM[1], @XMM[1], @XMM[ 9]
+ veor @XMM[8], @XMM[6], @XMM[10]
+ vst1.8 {@XMM[0]-@XMM[1]}, [$out]!
+ veor @XMM[9], @XMM[4], @XMM[11]
+ veor @XMM[10], @XMM[2], @XMM[12]
+ vst1.8 {@XMM[8]-@XMM[9]}, [$out]!
+ veor @XMM[11], @XMM[7], @XMM[13]
+ vst1.8 {@XMM[10]-@XMM[11]}, [$out]!
+
+ vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak
+ b .Lxts_dec_done
+.align 4
+.Lxts_dec_5:
+ vst1.64 {@XMM[13]}, [r0,:128] @ next round tweak
+
+ veor @XMM[3], @XMM[3], @XMM[11]
+#ifndef BSAES_ASM_EXTENDED_KEY
+ add r4, sp, #0x90 @ pass key schedule
+#else
+ add r4, $key, #248 @ pass key schedule
+#endif
+ veor @XMM[4], @XMM[4], @XMM[12]
+ mov r5, $rounds @ pass rounds
+ mov r0, sp
+
+ bl _bsaes_decrypt8
+
+ vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]!
+ vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]!
+ veor @XMM[0], @XMM[0], @XMM[ 8]
+ vld1.64 {@XMM[12]}, [r0,:128]!
+ veor @XMM[1], @XMM[1], @XMM[ 9]
+ veor @XMM[8], @XMM[6], @XMM[10]
+ vst1.8 {@XMM[0]-@XMM[1]}, [$out]!
+ veor @XMM[9], @XMM[4], @XMM[11]
+ veor @XMM[10], @XMM[2], @XMM[12]
+ vst1.8 {@XMM[8]-@XMM[9]}, [$out]!
+ vst1.8 {@XMM[10]}, [$out]!
+
+ vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak
+ b .Lxts_dec_done
+.align 4
+.Lxts_dec_4:
+ vst1.64 {@XMM[12]}, [r0,:128] @ next round tweak
+
+ veor @XMM[2], @XMM[2], @XMM[10]
+#ifndef BSAES_ASM_EXTENDED_KEY
+ add r4, sp, #0x90 @ pass key schedule
+#else
+ add r4, $key, #248 @ pass key schedule
+#endif
+ veor @XMM[3], @XMM[3], @XMM[11]
+ mov r5, $rounds @ pass rounds
+ mov r0, sp
+
+ bl _bsaes_decrypt8
+
+ vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]!
+ vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]!
+ veor @XMM[0], @XMM[0], @XMM[ 8]
+ veor @XMM[1], @XMM[1], @XMM[ 9]
+ veor @XMM[8], @XMM[6], @XMM[10]
+ vst1.8 {@XMM[0]-@XMM[1]}, [$out]!
+ veor @XMM[9], @XMM[4], @XMM[11]
+ vst1.8 {@XMM[8]-@XMM[9]}, [$out]!
+
+ vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak
+ b .Lxts_dec_done
+.align 4
+.Lxts_dec_3:
+ vst1.64 {@XMM[11]}, [r0,:128] @ next round tweak
+
+ veor @XMM[1], @XMM[1], @XMM[9]
+#ifndef BSAES_ASM_EXTENDED_KEY
+ add r4, sp, #0x90 @ pass key schedule
+#else
+ add r4, $key, #248 @ pass key schedule
+#endif
+ veor @XMM[2], @XMM[2], @XMM[10]
+ mov r5, $rounds @ pass rounds
+ mov r0, sp
+
+ bl _bsaes_decrypt8
+
+ vld1.64 {@XMM[8]-@XMM[9]}, [r0,:128]!
+ vld1.64 {@XMM[10]}, [r0,:128]!
+ veor @XMM[0], @XMM[0], @XMM[ 8]
+ veor @XMM[1], @XMM[1], @XMM[ 9]
+ veor @XMM[8], @XMM[6], @XMM[10]
+ vst1.8 {@XMM[0]-@XMM[1]}, [$out]!
+ vst1.8 {@XMM[8]}, [$out]!
+
+ vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak
+ b .Lxts_dec_done
+.align 4
+.Lxts_dec_2:
+ vst1.64 {@XMM[10]}, [r0,:128] @ next round tweak
+
+ veor @XMM[0], @XMM[0], @XMM[8]
+#ifndef BSAES_ASM_EXTENDED_KEY
+ add r4, sp, #0x90 @ pass key schedule
+#else
+ add r4, $key, #248 @ pass key schedule
+#endif
+ veor @XMM[1], @XMM[1], @XMM[9]
+ mov r5, $rounds @ pass rounds
+ mov r0, sp
+
+ bl _bsaes_decrypt8
+
+ vld1.64 {@XMM[8]-@XMM[9]}, [r0,:128]!
+ veor @XMM[0], @XMM[0], @XMM[ 8]
+ veor @XMM[1], @XMM[1], @XMM[ 9]
+ vst1.8 {@XMM[0]-@XMM[1]}, [$out]!
+
+ vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak
+ b .Lxts_dec_done
+.align 4
+.Lxts_dec_1:
+ mov r0, sp
+ veor @XMM[0], @XMM[8]
+ mov r1, sp
+ vst1.8 {@XMM[0]}, [sp,:128]
+ mov r2, $key
+ mov r4, $fp @ preserve fp
+ mov r5, $magic @ preserve magic
+
+ bl AES_decrypt
+
+ vld1.8 {@XMM[0]}, [sp,:128]
+ veor @XMM[0], @XMM[0], @XMM[8]
+ vst1.8 {@XMM[0]}, [$out]!
+ mov $fp, r4
+ mov $magic, r5
+
+ vmov @XMM[8], @XMM[9] @ next round tweak
+
+.Lxts_dec_done:
+#ifndef XTS_CHAIN_TWEAK
+ adds $len, #0x10
+ beq .Lxts_dec_ret
+
+ @ calculate one round of extra tweak for the stolen ciphertext
+ vldmia $magic, {$twmask}
+ vshr.s64 @XMM[6], @XMM[8], #63
+ vand @XMM[6], @XMM[6], $twmask
+ vadd.u64 @XMM[9], @XMM[8], @XMM[8]
+ vswp `&Dhi("@XMM[6]")`,`&Dlo("@XMM[6]")`
+ veor @XMM[9], @XMM[9], @XMM[6]
+
+ @ perform the final decryption with the last tweak value
+ vld1.8 {@XMM[0]}, [$inp]!
+ mov r0, sp
+ veor @XMM[0], @XMM[0], @XMM[9]
+ mov r1, sp
+ vst1.8 {@XMM[0]}, [sp,:128]
+ mov r2, $key
+ mov r4, $fp @ preserve fp
+
+ bl AES_decrypt
+
+ vld1.8 {@XMM[0]}, [sp,:128]
+ veor @XMM[0], @XMM[0], @XMM[9]
+ vst1.8 {@XMM[0]}, [$out]
+
+ mov r6, $out
+.Lxts_dec_steal:
+ ldrb r1, [$out]
+ ldrb r0, [$inp], #1
+ strb r1, [$out, #0x10]
+ strb r0, [$out], #1
+
+ subs $len, #1
+ bhi .Lxts_dec_steal
+
+ vld1.8 {@XMM[0]}, [r6]
+ mov r0, sp
+ veor @XMM[0], @XMM[8]
+ mov r1, sp
+ vst1.8 {@XMM[0]}, [sp,:128]
+ mov r2, $key
+
+ bl AES_decrypt
+
+ vld1.8 {@XMM[0]}, [sp,:128]
+ veor @XMM[0], @XMM[0], @XMM[8]
+ vst1.8 {@XMM[0]}, [r6]
+ mov $fp, r4
+#endif
+
+.Lxts_dec_ret:
+ bic r0, $fp, #0xf
+ vmov.i32 q0, #0
+ vmov.i32 q1, #0
+#ifdef XTS_CHAIN_TWEAK
+ ldr r1, [$fp, #0x20+VFP_ABI_FRAME] @ chain tweak
+#endif
+.Lxts_dec_bzero: @ wipe key schedule [if any]
+ vstmia sp!, {q0-q1}
+ cmp sp, r0
+ bne .Lxts_dec_bzero
+
+ mov sp, $fp
+#ifdef XTS_CHAIN_TWEAK
+ vst1.8 {@XMM[8]}, [r1]
+#endif
+ VFP_ABI_POP
+ ldmia sp!, {r4-r10, pc} @ return
+
+.size bsaes_xts_decrypt,.-bsaes_xts_decrypt
+___
+}
+$code.=<<___;
+#endif
+#endif
+___
+
+$code =~ s/\`([^\`]*)\`/eval($1)/gem;
+
+open SELF,$0;
+while(<SELF>) {
+ next if (/^#!/);
+ last if (!s/^#/@/ and !/^$/);
+ print;
+}
+close SELF;
+
+print $code;
+
+close STDOUT;
diff --git a/crypto/aes/asm/bsaes-x86_64.pl b/crypto/aes/asm/bsaes-x86_64.pl
new file mode 100644
index 0000000..41b90f0
--- /dev/null
+++ b/crypto/aes/asm/bsaes-x86_64.pl
@@ -0,0 +1,3108 @@
+#!/usr/bin/env perl
+
+###################################################################
+### AES-128 [originally in CTR mode] ###
+### bitsliced implementation for Intel Core 2 processors ###
+### requires support of SSE extensions up to SSSE3 ###
+### Author: Emilia Käsper and Peter Schwabe ###
+### Date: 2009-03-19 ###
+### Public domain ###
+### ###
+### See http://homes.esat.kuleuven.be/~ekasper/#software for ###
+### further information. ###
+###################################################################
+#
+# September 2011.
+#
+# Started as transliteration to "perlasm" the original code has
+# undergone following changes:
+#
+# - code was made position-independent;
+# - rounds were folded into a loop resulting in >5x size reduction
+# from 12.5KB to 2.2KB;
+# - above was possibile thanks to mixcolumns() modification that
+# allowed to feed its output back to aesenc[last], this was
+# achieved at cost of two additional inter-registers moves;
+# - some instruction reordering and interleaving;
+# - this module doesn't implement key setup subroutine, instead it
+# relies on conversion of "conventional" key schedule as returned
+# by AES_set_encrypt_key (see discussion below);
+# - first and last round keys are treated differently, which allowed
+# to skip one shiftrows(), reduce bit-sliced key schedule and
+# speed-up conversion by 22%;
+# - support for 192- and 256-bit keys was added;
+#
+# Resulting performance in CPU cycles spent to encrypt one byte out
+# of 4096-byte buffer with 128-bit key is:
+#
+# Emilia's this(*) difference
+#
+# Core 2 9.30 8.69 +7%
+# Nehalem(**) 7.63 6.98 +9%
+# Atom 17.1 17.4 -2%(***)
+#
+# (*) Comparison is not completely fair, because "this" is ECB,
+# i.e. no extra processing such as counter values calculation
+# and xor-ing input as in Emilia's CTR implementation is
+# performed. However, the CTR calculations stand for not more
+# than 1% of total time, so comparison is *rather* fair.
+#
+# (**) Results were collected on Westmere, which is considered to
+# be equivalent to Nehalem for this code.
+#
+# (***) Slowdown on Atom is rather strange per se, because original
+# implementation has a number of 9+-bytes instructions, which
+# are bad for Atom front-end, and which I eliminated completely.
+# In attempt to address deterioration sbox() was tested in FP
+# SIMD "domain" (movaps instead of movdqa, xorps instead of
+# pxor, etc.). While it resulted in nominal 4% improvement on
+# Atom, it hurted Westmere by more than 2x factor.
+#
+# As for key schedule conversion subroutine. Interface to OpenSSL
+# relies on per-invocation on-the-fly conversion. This naturally
+# has impact on performance, especially for short inputs. Conversion
+# time in CPU cycles and its ratio to CPU cycles spent in 8x block
+# function is:
+#
+# conversion conversion/8x block
+# Core 2 240 0.22
+# Nehalem 180 0.20
+# Atom 430 0.19
+#
+# The ratio values mean that 128-byte blocks will be processed
+# 16-18% slower, 256-byte blocks - 9-10%, 384-byte blocks - 6-7%,
+# etc. Then keep in mind that input sizes not divisible by 128 are
+# *effectively* slower, especially shortest ones, e.g. consecutive
+# 144-byte blocks are processed 44% slower than one would expect,
+# 272 - 29%, 400 - 22%, etc. Yet, despite all these "shortcomings"
+# it's still faster than ["hyper-threading-safe" code path in]
+# aes-x86_64.pl on all lengths above 64 bytes...
+#
+# October 2011.
+#
+# Add decryption procedure. Performance in CPU cycles spent to decrypt
+# one byte out of 4096-byte buffer with 128-bit key is:
+#
+# Core 2 9.83
+# Nehalem 7.74
+# Atom 19.0
+#
+# November 2011.
+#
+# Add bsaes_xts_[en|de]crypt. Less-than-80-bytes-block performance is
+# suboptimal, but XTS is meant to be used with larger blocks...
+#
+# <appro@openssl.org>
+
+$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;
+
+my ($inp,$out,$len,$key,$ivp)=("%rdi","%rsi","%rdx","%rcx");
+my @XMM=map("%xmm$_",(15,0..14)); # best on Atom, +10% over (0..15)
+my $ecb=0; # suppress unreferenced ECB subroutines, spare some space...
+
+{
+my ($key,$rounds,$const)=("%rax","%r10d","%r11");
+
+sub Sbox {
+# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb
+# output in lsb > [b0, b1, b4, b6, b3, b7, b2, b5] < msb
+my @b=@_[0..7];
+my @t=@_[8..11];
+my @s=@_[12..15];
+ &InBasisChange (@b);
+ &Inv_GF256 (@b[6,5,0,3,7,1,4,2],@t,@s);
+ &OutBasisChange (@b[7,1,4,2,6,5,0,3]);
+}
+
+sub InBasisChange {
+# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb
+# output in lsb > [b6, b5, b0, b3, b7, b1, b4, b2] < msb
+my @b=@_[0..7];
+$code.=<<___;
+ pxor @b[6], @b[5]
+ pxor @b[1], @b[2]
+ pxor @b[0], @b[3]
+ pxor @b[2], @b[6]
+ pxor @b[0], @b[5]
+
+ pxor @b[3], @b[6]
+ pxor @b[7], @b[3]
+ pxor @b[5], @b[7]
+ pxor @b[4], @b[3]
+ pxor @b[5], @b[4]
+ pxor @b[1], @b[3]
+
+ pxor @b[7], @b[2]
+ pxor @b[5], @b[1]
+___
+}
+
+sub OutBasisChange {
+# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb
+# output in lsb > [b6, b1, b2, b4, b7, b0, b3, b5] < msb
+my @b=@_[0..7];
+$code.=<<___;
+ pxor @b[6], @b[0]
+ pxor @b[4], @b[1]
+ pxor @b[0], @b[2]
+ pxor @b[6], @b[4]
+ pxor @b[1], @b[6]
+
+ pxor @b[5], @b[1]
+ pxor @b[3], @b[5]
+ pxor @b[7], @b[3]
+ pxor @b[5], @b[7]
+ pxor @b[5], @b[2]
+
+ pxor @b[7], @b[4]
+___
+}
+
+sub InvSbox {
+# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb
+# output in lsb > [b0, b1, b6, b4, b2, b7, b3, b5] < msb
+my @b=@_[0..7];
+my @t=@_[8..11];
+my @s=@_[12..15];
+ &InvInBasisChange (@b);
+ &Inv_GF256 (@b[5,1,2,6,3,7,0,4],@t,@s);
+ &InvOutBasisChange (@b[3,7,0,4,5,1,2,6]);
+}
+
+sub InvInBasisChange { # OutBasisChange in reverse
+my @b=@_[5,1,2,6,3,7,0,4];
+$code.=<<___
+ pxor @b[7], @b[4]
+
+ pxor @b[5], @b[7]
+ pxor @b[5], @b[2]
+ pxor @b[7], @b[3]
+ pxor @b[3], @b[5]
+ pxor @b[5], @b[1]
+
+ pxor @b[1], @b[6]
+ pxor @b[0], @b[2]
+ pxor @b[6], @b[4]
+ pxor @b[6], @b[0]
+ pxor @b[4], @b[1]
+___
+}
+
+sub InvOutBasisChange { # InBasisChange in reverse
+my @b=@_[2,5,7,3,6,1,0,4];
+$code.=<<___;
+ pxor @b[5], @b[1]
+ pxor @b[7], @b[2]
+
+ pxor @b[1], @b[3]
+ pxor @b[5], @b[4]
+ pxor @b[5], @b[7]
+ pxor @b[4], @b[3]
+ pxor @b[0], @b[5]
+ pxor @b[7], @b[3]
+ pxor @b[2], @b[6]
+ pxor @b[1], @b[2]
+ pxor @b[3], @b[6]
+
+ pxor @b[0], @b[3]
+ pxor @b[6], @b[5]
+___
+}
+
+sub Mul_GF4 {
+#;*************************************************************
+#;* Mul_GF4: Input x0-x1,y0-y1 Output x0-x1 Temp t0 (8) *
+#;*************************************************************
+my ($x0,$x1,$y0,$y1,$t0)=@_;
+$code.=<<___;
+ movdqa $y0, $t0
+ pxor $y1, $t0
+ pand $x0, $t0
+ pxor $x1, $x0
+ pand $y0, $x1
+ pand $y1, $x0
+ pxor $x1, $x0
+ pxor $t0, $x1
+___
+}
+
+sub Mul_GF4_N { # not used, see next subroutine
+# multiply and scale by N
+my ($x0,$x1,$y0,$y1,$t0)=@_;
+$code.=<<___;
+ movdqa $y0, $t0
+ pxor $y1, $t0
+ pand $x0, $t0
+ pxor $x1, $x0
+ pand $y0, $x1
+ pand $y1, $x0
+ pxor $x0, $x1
+ pxor $t0, $x0
+___
+}
+
+sub Mul_GF4_N_GF4 {
+# interleaved Mul_GF4_N and Mul_GF4
+my ($x0,$x1,$y0,$y1,$t0,
+ $x2,$x3,$y2,$y3,$t1)=@_;
+$code.=<<___;
+ movdqa $y0, $t0
+ movdqa $y2, $t1
+ pxor $y1, $t0
+ pxor $y3, $t1
+ pand $x0, $t0
+ pand $x2, $t1
+ pxor $x1, $x0
+ pxor $x3, $x2
+ pand $y0, $x1
+ pand $y2, $x3
+ pand $y1, $x0
+ pand $y3, $x2
+ pxor $x0, $x1
+ pxor $x3, $x2
+ pxor $t0, $x0
+ pxor $t1, $x3
+___
+}
+sub Mul_GF16_2 {
+my @x=@_[0..7];
+my @y=@_[8..11];
+my @t=@_[12..15];
+$code.=<<___;
+ movdqa @x[0], @t[0]
+ movdqa @x[1], @t[1]
+___
+ &Mul_GF4 (@x[0], @x[1], @y[0], @y[1], @t[2]);
+$code.=<<___;
+ pxor @x[2], @t[0]
+ pxor @x[3], @t[1]
+ pxor @y[2], @y[0]
+ pxor @y[3], @y[1]
+___
+ Mul_GF4_N_GF4 (@t[0], @t[1], @y[0], @y[1], @t[3],
+ @x[2], @x[3], @y[2], @y[3], @t[2]);
+$code.=<<___;
+ pxor @t[0], @x[0]
+ pxor @t[0], @x[2]
+ pxor @t[1], @x[1]
+ pxor @t[1], @x[3]
+
+ movdqa @x[4], @t[0]
+ movdqa @x[5], @t[1]
+ pxor @x[6], @t[0]
+ pxor @x[7], @t[1]
+___
+ &Mul_GF4_N_GF4 (@t[0], @t[1], @y[0], @y[1], @t[3],
+ @x[6], @x[7], @y[2], @y[3], @t[2]);
+$code.=<<___;
+ pxor @y[2], @y[0]
+ pxor @y[3], @y[1]
+___
+ &Mul_GF4 (@x[4], @x[5], @y[0], @y[1], @t[3]);
+$code.=<<___;
+ pxor @t[0], @x[4]
+ pxor @t[0], @x[6]
+ pxor @t[1], @x[5]
+ pxor @t[1], @x[7]
+___
+}
+sub Inv_GF256 {
+#;********************************************************************
+#;* Inv_GF256: Input x0-x7 Output x0-x7 Temp t0-t3,s0-s3 (144) *
+#;********************************************************************
+my @x=@_[0..7];
+my @t=@_[8..11];
+my @s=@_[12..15];
+# direct optimizations from hardware
+$code.=<<___;
+ movdqa @x[4], @t[3]
+ movdqa @x[5], @t[2]
+ movdqa @x[1], @t[1]
+ movdqa @x[7], @s[1]
+ movdqa @x[0], @s[0]
+
+ pxor @x[6], @t[3]
+ pxor @x[7], @t[2]
+ pxor @x[3], @t[1]
+ movdqa @t[3], @s[2]
+ pxor @x[6], @s[1]
+ movdqa @t[2], @t[0]
+ pxor @x[2], @s[0]
+ movdqa @t[3], @s[3]
+
+ por @t[1], @t[2]
+ por @s[0], @t[3]
+ pxor @t[0], @s[3]
+ pand @s[0], @s[2]
+ pxor @t[1], @s[0]
+ pand @t[1], @t[0]
+ pand @s[0], @s[3]
+ movdqa @x[3], @s[0]
+ pxor @x[2], @s[0]
+ pand @s[0], @s[1]
+ pxor @s[1], @t[3]
+ pxor @s[1], @t[2]
+ movdqa @x[4], @s[1]
+ movdqa @x[1], @s[0]
+ pxor @x[5], @s[1]
+ pxor @x[0], @s[0]
+ movdqa @s[1], @t[1]
+ pand @s[0], @s[1]
+ por @s[0], @t[1]
+ pxor @s[1], @t[0]
+ pxor @s[3], @t[3]
+ pxor @s[2], @t[2]
+ pxor @s[3], @t[1]
+ movdqa @x[7], @s[0]
+ pxor @s[2], @t[0]
+ movdqa @x[6], @s[1]
+ pxor @s[2], @t[1]
+ movdqa @x[5], @s[2]
+ pand @x[3], @s[0]
+ movdqa @x[4], @s[3]
+ pand @x[2], @s[1]
+ pand @x[1], @s[2]
+ por @x[0], @s[3]
+ pxor @s[0], @t[3]
+ pxor @s[1], @t[2]
+ pxor @s[2], @t[1]
+ pxor @s[3], @t[0]
+
+ #Inv_GF16 \t0, \t1, \t2, \t3, \s0, \s1, \s2, \s3
+
+ # new smaller inversion
+
+ movdqa @t[3], @s[0]
+ pand @t[1], @t[3]
+ pxor @t[2], @s[0]
+
+ movdqa @t[0], @s[2]
+ movdqa @s[0], @s[3]
+ pxor @t[3], @s[2]
+ pand @s[2], @s[3]
+
+ movdqa @t[1], @s[1]
+ pxor @t[2], @s[3]
+ pxor @t[0], @s[1]
+
+ pxor @t[2], @t[3]
+
+ pand @t[3], @s[1]
+
+ movdqa @s[2], @t[2]
+ pxor @t[0], @s[1]
+
+ pxor @s[1], @t[2]
+ pxor @s[1], @t[1]
+
+ pand @t[0], @t[2]
+
+ pxor @t[2], @s[2]
+ pxor @t[2], @t[1]
+
+ pand @s[3], @s[2]
+
+ pxor @s[0], @s[2]
+___
+# output in s3, s2, s1, t1
+
+# Mul_GF16_2 \x0, \x1, \x2, \x3, \x4, \x5, \x6, \x7, \t2, \t3, \t0, \t1, \s0, \s1, \s2, \s3
+
+# Mul_GF16_2 \x0, \x1, \x2, \x3, \x4, \x5, \x6, \x7, \s3, \s2, \s1, \t1, \s0, \t0, \t2, \t3
+ &Mul_GF16_2(@x,@s[3,2,1],@t[1],@s[0],@t[0,2,3]);
+
+### output msb > [x3,x2,x1,x0,x7,x6,x5,x4] < lsb
+}
+
+# AES linear components
+
+sub ShiftRows {
+my @x=@_[0..7];
+my $mask=pop;
+$code.=<<___;
+ pxor 0x00($key),@x[0]
+ pxor 0x10($key),@x[1]
+ pshufb $mask,@x[0]
+ pxor 0x20($key),@x[2]
+ pshufb $mask,@x[1]
+ pxor 0x30($key),@x[3]
+ pshufb $mask,@x[2]
+ pxor 0x40($key),@x[4]
+ pshufb $mask,@x[3]
+ pxor 0x50($key),@x[5]
+ pshufb $mask,@x[4]
+ pxor 0x60($key),@x[6]
+ pshufb $mask,@x[5]
+ pxor 0x70($key),@x[7]
+ pshufb $mask,@x[6]
+ lea 0x80($key),$key
+ pshufb $mask,@x[7]
+___
+}
+
+sub MixColumns {
+# modified to emit output in order suitable for feeding back to aesenc[last]
+my @x=@_[0..7];
+my @t=@_[8..15];
+my $inv=@_[16]; # optional
+$code.=<<___;
+ pshufd \$0x93, @x[0], @t[0] # x0 <<< 32
+ pshufd \$0x93, @x[1], @t[1]
+ pxor @t[0], @x[0] # x0 ^ (x0 <<< 32)
+ pshufd \$0x93, @x[2], @t[2]
+ pxor @t[1], @x[1]
+ pshufd \$0x93, @x[3], @t[3]
+ pxor @t[2], @x[2]
+ pshufd \$0x93, @x[4], @t[4]
+ pxor @t[3], @x[3]
+ pshufd \$0x93, @x[5], @t[5]
+ pxor @t[4], @x[4]
+ pshufd \$0x93, @x[6], @t[6]
+ pxor @t[5], @x[5]
+ pshufd \$0x93, @x[7], @t[7]
+ pxor @t[6], @x[6]
+ pxor @t[7], @x[7]
+
+ pxor @x[0], @t[1]
+ pxor @x[7], @t[0]
+ pxor @x[7], @t[1]
+ pshufd \$0x4E, @x[0], @x[0] # (x0 ^ (x0 <<< 32)) <<< 64)
+ pxor @x[1], @t[2]
+ pshufd \$0x4E, @x[1], @x[1]
+ pxor @x[4], @t[5]
+ pxor @t[0], @x[0]
+ pxor @x[5], @t[6]
+ pxor @t[1], @x[1]
+ pxor @x[3], @t[4]
+ pshufd \$0x4E, @x[4], @t[0]
+ pxor @x[6], @t[7]
+ pshufd \$0x4E, @x[5], @t[1]
+ pxor @x[2], @t[3]
+ pshufd \$0x4E, @x[3], @x[4]
+ pxor @x[7], @t[3]
+ pshufd \$0x4E, @x[7], @x[5]
+ pxor @x[7], @t[4]
+ pshufd \$0x4E, @x[6], @x[3]
+ pxor @t[4], @t[0]
+ pshufd \$0x4E, @x[2], @x[6]
+ pxor @t[5], @t[1]
+___
+$code.=<<___ if (!$inv);
+ pxor @t[3], @x[4]
+ pxor @t[7], @x[5]
+ pxor @t[6], @x[3]
+ movdqa @t[0], @x[2]
+ pxor @t[2], @x[6]
+ movdqa @t[1], @x[7]
+___
+$code.=<<___ if ($inv);
+ pxor @x[4], @t[3]
+ pxor @t[7], @x[5]
+ pxor @x[3], @t[6]
+ movdqa @t[0], @x[3]
+ pxor @t[2], @x[6]
+ movdqa @t[6], @x[2]
+ movdqa @t[1], @x[7]
+ movdqa @x[6], @x[4]
+ movdqa @t[3], @x[6]
+___
+}
+
+sub InvMixColumns_orig {
+my @x=@_[0..7];
+my @t=@_[8..15];
+
+$code.=<<___;
+ # multiplication by 0x0e
+ pshufd \$0x93, @x[7], @t[7]
+ movdqa @x[2], @t[2]
+ pxor @x[5], @x[7] # 7 5
+ pxor @x[5], @x[2] # 2 5
+ pshufd \$0x93, @x[0], @t[0]
+ movdqa @x[5], @t[5]
+ pxor @x[0], @x[5] # 5 0 [1]
+ pxor @x[1], @x[0] # 0 1
+ pshufd \$0x93, @x[1], @t[1]
+ pxor @x[2], @x[1] # 1 25
+ pxor @x[6], @x[0] # 01 6 [2]
+ pxor @x[3], @x[1] # 125 3 [4]
+ pshufd \$0x93, @x[3], @t[3]
+ pxor @x[0], @x[2] # 25 016 [3]
+ pxor @x[7], @x[3] # 3 75
+ pxor @x[6], @x[7] # 75 6 [0]
+ pshufd \$0x93, @x[6], @t[6]
+ movdqa @x[4], @t[4]
+ pxor @x[4], @x[6] # 6 4
+ pxor @x[3], @x[4] # 4 375 [6]
+ pxor @x[7], @x[3] # 375 756=36
+ pxor @t[5], @x[6] # 64 5 [7]
+ pxor @t[2], @x[3] # 36 2
+ pxor @t[4], @x[3] # 362 4 [5]
+ pshufd \$0x93, @t[5], @t[5]
+___
+ my @y = @x[7,5,0,2,1,3,4,6];
+$code.=<<___;
+ # multiplication by 0x0b
+ pxor @y[0], @y[1]
+ pxor @t[0], @y[0]
+ pxor @t[1], @y[1]
+ pshufd \$0x93, @t[2], @t[2]
+ pxor @t[5], @y[0]
+ pxor @t[6], @y[1]
+ pxor @t[7], @y[0]
+ pshufd \$0x93, @t[4], @t[4]
+ pxor @t[6], @t[7] # clobber t[7]
+ pxor @y[0], @y[1]
+
+ pxor @t[0], @y[3]
+ pshufd \$0x93, @t[0], @t[0]
+ pxor @t[1], @y[2]
+ pxor @t[1], @y[4]
+ pxor @t[2], @y[2]
+ pshufd \$0x93, @t[1], @t[1]
+ pxor @t[2], @y[3]
+ pxor @t[2], @y[5]
+ pxor @t[7], @y[2]
+ pshufd \$0x93, @t[2], @t[2]
+ pxor @t[3], @y[3]
+ pxor @t[3], @y[6]
+ pxor @t[3], @y[4]
+ pshufd \$0x93, @t[3], @t[3]
+ pxor @t[4], @y[7]
+ pxor @t[4], @y[5]
+ pxor @t[7], @y[7]
+ pxor @t[5], @y[3]
+ pxor @t[4], @y[4]
+ pxor @t[5], @t[7] # clobber t[7] even more
+
+ pxor @t[7], @y[5]
+ pshufd \$0x93, @t[4], @t[4]
+ pxor @t[7], @y[6]
+ pxor @t[7], @y[4]
+
+ pxor @t[5], @t[7]
+ pshufd \$0x93, @t[5], @t[5]
+ pxor @t[6], @t[7] # restore t[7]
+
+ # multiplication by 0x0d
+ pxor @y[7], @y[4]
+ pxor @t[4], @y[7]
+ pshufd \$0x93, @t[6], @t[6]
+ pxor @t[0], @y[2]
+ pxor @t[5], @y[7]
+ pxor @t[2], @y[2]
+ pshufd \$0x93, @t[7], @t[7]
+
+ pxor @y[1], @y[3]
+ pxor @t[1], @y[1]
+ pxor @t[0], @y[0]
+ pxor @t[0], @y[3]
+ pxor @t[5], @y[1]
+ pxor @t[5], @y[0]
+ pxor @t[7], @y[1]
+ pshufd \$0x93, @t[0], @t[0]
+ pxor @t[6], @y[0]
+ pxor @y[1], @y[3]
+ pxor @t[1], @y[4]
+ pshufd \$0x93, @t[1], @t[1]
+
+ pxor @t[7], @y[7]
+ pxor @t[2], @y[4]
+ pxor @t[2], @y[5]
+ pshufd \$0x93, @t[2], @t[2]
+ pxor @t[6], @y[2]
+ pxor @t[3], @t[6] # clobber t[6]
+ pxor @y[7], @y[4]
+ pxor @t[6], @y[3]
+
+ pxor @t[6], @y[6]
+ pxor @t[5], @y[5]
+ pxor @t[4], @y[6]
+ pshufd \$0x93, @t[4], @t[4]
+ pxor @t[6], @y[5]
+ pxor @t[7], @y[6]
+ pxor @t[3], @t[6] # restore t[6]
+
+ pshufd \$0x93, @t[5], @t[5]
+ pshufd \$0x93, @t[6], @t[6]
+ pshufd \$0x93, @t[7], @t[7]
+ pshufd \$0x93, @t[3], @t[3]
+
+ # multiplication by 0x09
+ pxor @y[1], @y[4]
+ pxor @y[1], @t[1] # t[1]=y[1]
+ pxor @t[5], @t[0] # clobber t[0]
+ pxor @t[5], @t[1]
+ pxor @t[0], @y[3]
+ pxor @y[0], @t[0] # t[0]=y[0]
+ pxor @t[6], @t[1]
+ pxor @t[7], @t[6] # clobber t[6]
+ pxor @t[1], @y[4]
+ pxor @t[4], @y[7]
+ pxor @y[4], @t[4] # t[4]=y[4]
+ pxor @t[3], @y[6]
+ pxor @y[3], @t[3] # t[3]=y[3]
+ pxor @t[2], @y[5]
+ pxor @y[2], @t[2] # t[2]=y[2]
+ pxor @t[7], @t[3]
+ pxor @y[5], @t[5] # t[5]=y[5]
+ pxor @t[6], @t[2]
+ pxor @t[6], @t[5]
+ pxor @y[6], @t[6] # t[6]=y[6]
+ pxor @y[7], @t[7] # t[7]=y[7]
+
+ movdqa @t[0],@XMM[0]
+ movdqa @t[1],@XMM[1]
+ movdqa @t[2],@XMM[2]
+ movdqa @t[3],@XMM[3]
+ movdqa @t[4],@XMM[4]
+ movdqa @t[5],@XMM[5]
+ movdqa @t[6],@XMM[6]
+ movdqa @t[7],@XMM[7]
+___
+}
+
+sub InvMixColumns {
+my @x=@_[0..7];
+my @t=@_[8..15];
+
+# Thanks to Jussi Kivilinna for providing pointer to
+#
+# | 0e 0b 0d 09 | | 02 03 01 01 | | 05 00 04 00 |
+# | 09 0e 0b 0d | = | 01 02 03 01 | x | 00 05 00 04 |
+# | 0d 09 0e 0b | | 01 01 02 03 | | 04 00 05 00 |
+# | 0b 0d 09 0e | | 03 01 01 02 | | 00 04 00 05 |
+
+$code.=<<___;
+ # multiplication by 0x05-0x00-0x04-0x00
+ pshufd \$0x4E, @x[0], @t[0]
+ pshufd \$0x4E, @x[6], @t[6]
+ pxor @x[0], @t[0]
+ pshufd \$0x4E, @x[7], @t[7]
+ pxor @x[6], @t[6]
+ pshufd \$0x4E, @x[1], @t[1]
+ pxor @x[7], @t[7]
+ pshufd \$0x4E, @x[2], @t[2]
+ pxor @x[1], @t[1]
+ pshufd \$0x4E, @x[3], @t[3]
+ pxor @x[2], @t[2]
+ pxor @t[6], @x[0]
+ pxor @t[6], @x[1]
+ pshufd \$0x4E, @x[4], @t[4]
+ pxor @x[3], @t[3]
+ pxor @t[0], @x[2]
+ pxor @t[1], @x[3]
+ pshufd \$0x4E, @x[5], @t[5]
+ pxor @x[4], @t[4]
+ pxor @t[7], @x[1]
+ pxor @t[2], @x[4]
+ pxor @x[5], @t[5]
+
+ pxor @t[7], @x[2]
+ pxor @t[6], @x[3]
+ pxor @t[6], @x[4]
+ pxor @t[3], @x[5]
+ pxor @t[4], @x[6]
+ pxor @t[7], @x[4]
+ pxor @t[7], @x[5]
+ pxor @t[5], @x[7]
+___
+ &MixColumns (@x,@t,1); # flipped 2<->3 and 4<->6
+}
+
+sub aesenc { # not used
+my @b=@_[0..7];
+my @t=@_[8..15];
+$code.=<<___;
+ movdqa 0x30($const),@t[0] # .LSR
+___
+ &ShiftRows (@b,@t[0]);
+ &Sbox (@b,@t);
+ &MixColumns (@b[0,1,4,6,3,7,2,5],@t);
+}
+
+sub aesenclast { # not used
+my @b=@_[0..7];
+my @t=@_[8..15];
+$code.=<<___;
+ movdqa 0x40($const),@t[0] # .LSRM0
+___
+ &ShiftRows (@b,@t[0]);
+ &Sbox (@b,@t);
+$code.=<<___
+ pxor 0x00($key),@b[0]
+ pxor 0x10($key),@b[1]
+ pxor 0x20($key),@b[4]
+ pxor 0x30($key),@b[6]
+ pxor 0x40($key),@b[3]
+ pxor 0x50($key),@b[7]
+ pxor 0x60($key),@b[2]
+ pxor 0x70($key),@b[5]
+___
+}
+
+sub swapmove {
+my ($a,$b,$n,$mask,$t)=@_;
+$code.=<<___;
+ movdqa $b,$t
+ psrlq \$$n,$b
+ pxor $a,$b
+ pand $mask,$b
+ pxor $b,$a
+ psllq \$$n,$b
+ pxor $t,$b
+___
+}
+sub swapmove2x {
+my ($a0,$b0,$a1,$b1,$n,$mask,$t0,$t1)=@_;
+$code.=<<___;
+ movdqa $b0,$t0
+ psrlq \$$n,$b0
+ movdqa $b1,$t1
+ psrlq \$$n,$b1
+ pxor $a0,$b0
+ pxor $a1,$b1
+ pand $mask,$b0
+ pand $mask,$b1
+ pxor $b0,$a0
+ psllq \$$n,$b0
+ pxor $b1,$a1
+ psllq \$$n,$b1
+ pxor $t0,$b0
+ pxor $t1,$b1
+___
+}
+
+sub bitslice {
+my @x=reverse(@_[0..7]);
+my ($t0,$t1,$t2,$t3)=@_[8..11];
+$code.=<<___;
+ movdqa 0x00($const),$t0 # .LBS0
+ movdqa 0x10($const),$t1 # .LBS1
+___
+ &swapmove2x(@x[0,1,2,3],1,$t0,$t2,$t3);
+ &swapmove2x(@x[4,5,6,7],1,$t0,$t2,$t3);
+$code.=<<___;
+ movdqa 0x20($const),$t0 # .LBS2
+___
+ &swapmove2x(@x[0,2,1,3],2,$t1,$t2,$t3);
+ &swapmove2x(@x[4,6,5,7],2,$t1,$t2,$t3);
+
+ &swapmove2x(@x[0,4,1,5],4,$t0,$t2,$t3);
+ &swapmove2x(@x[2,6,3,7],4,$t0,$t2,$t3);
+}
+
+$code.=<<___;
+.text
+
+.extern asm_AES_encrypt
+.extern asm_AES_decrypt
+
+.type _bsaes_encrypt8,\@abi-omnipotent
+.align 64
+_bsaes_encrypt8:
+ lea .LBS0(%rip), $const # constants table
+
+ movdqa ($key), @XMM[9] # round 0 key
+ lea 0x10($key), $key
+ movdqa 0x50($const), @XMM[8] # .LM0SR
+ pxor @XMM[9], @XMM[0] # xor with round0 key
+ pxor @XMM[9], @XMM[1]
+ pshufb @XMM[8], @XMM[0]
+ pxor @XMM[9], @XMM[2]
+ pshufb @XMM[8], @XMM[1]
+ pxor @XMM[9], @XMM[3]
+ pshufb @XMM[8], @XMM[2]
+ pxor @XMM[9], @XMM[4]
+ pshufb @XMM[8], @XMM[3]
+ pxor @XMM[9], @XMM[5]
+ pshufb @XMM[8], @XMM[4]
+ pxor @XMM[9], @XMM[6]
+ pshufb @XMM[8], @XMM[5]
+ pxor @XMM[9], @XMM[7]
+ pshufb @XMM[8], @XMM[6]
+ pshufb @XMM[8], @XMM[7]
+_bsaes_encrypt8_bitslice:
+___
+ &bitslice (@XMM[0..7, 8..11]);
+$code.=<<___;
+ dec $rounds
+ jmp .Lenc_sbox
+.align 16
+.Lenc_loop:
+___
+ &ShiftRows (@XMM[0..7, 8]);
+$code.=".Lenc_sbox:\n";
+ &Sbox (@XMM[0..7, 8..15]);
+$code.=<<___;
+ dec $rounds
+ jl .Lenc_done
+___
+ &MixColumns (@XMM[0,1,4,6,3,7,2,5, 8..15]);
+$code.=<<___;
+ movdqa 0x30($const), @XMM[8] # .LSR
+ jnz .Lenc_loop
+ movdqa 0x40($const), @XMM[8] # .LSRM0
+ jmp .Lenc_loop
+.align 16
+.Lenc_done:
+___
+ # output in lsb > [t0, t1, t4, t6, t3, t7, t2, t5] < msb
+ &bitslice (@XMM[0,1,4,6,3,7,2,5, 8..11]);
+$code.=<<___;
+ movdqa ($key), @XMM[8] # last round key
+ pxor @XMM[8], @XMM[4]
+ pxor @XMM[8], @XMM[6]
+ pxor @XMM[8], @XMM[3]
+ pxor @XMM[8], @XMM[7]
+ pxor @XMM[8], @XMM[2]
+ pxor @XMM[8], @XMM[5]
+ pxor @XMM[8], @XMM[0]
+ pxor @XMM[8], @XMM[1]
+ ret
+.size _bsaes_encrypt8,.-_bsaes_encrypt8
+
+.type _bsaes_decrypt8,\@abi-omnipotent
+.align 64
+_bsaes_decrypt8:
+ lea .LBS0(%rip), $const # constants table
+
+ movdqa ($key), @XMM[9] # round 0 key
+ lea 0x10($key), $key
+ movdqa -0x30($const), @XMM[8] # .LM0ISR
+ pxor @XMM[9], @XMM[0] # xor with round0 key
+ pxor @XMM[9], @XMM[1]
+ pshufb @XMM[8], @XMM[0]
+ pxor @XMM[9], @XMM[2]
+ pshufb @XMM[8], @XMM[1]
+ pxor @XMM[9], @XMM[3]
+ pshufb @XMM[8], @XMM[2]
+ pxor @XMM[9], @XMM[4]
+ pshufb @XMM[8], @XMM[3]
+ pxor @XMM[9], @XMM[5]
+ pshufb @XMM[8], @XMM[4]
+ pxor @XMM[9], @XMM[6]
+ pshufb @XMM[8], @XMM[5]
+ pxor @XMM[9], @XMM[7]
+ pshufb @XMM[8], @XMM[6]
+ pshufb @XMM[8], @XMM[7]
+___
+ &bitslice (@XMM[0..7, 8..11]);
+$code.=<<___;
+ dec $rounds
+ jmp .Ldec_sbox
+.align 16
+.Ldec_loop:
+___
+ &ShiftRows (@XMM[0..7, 8]);
+$code.=".Ldec_sbox:\n";
+ &InvSbox (@XMM[0..7, 8..15]);
+$code.=<<___;
+ dec $rounds
+ jl .Ldec_done
+___
+ &InvMixColumns (@XMM[0,1,6,4,2,7,3,5, 8..15]);
+$code.=<<___;
+ movdqa -0x10($const), @XMM[8] # .LISR
+ jnz .Ldec_loop
+ movdqa -0x20($const), @XMM[8] # .LISRM0
+ jmp .Ldec_loop
+.align 16
+.Ldec_done:
+___
+ &bitslice (@XMM[0,1,6,4,2,7,3,5, 8..11]);
+$code.=<<___;
+ movdqa ($key), @XMM[8] # last round key
+ pxor @XMM[8], @XMM[6]
+ pxor @XMM[8], @XMM[4]
+ pxor @XMM[8], @XMM[2]
+ pxor @XMM[8], @XMM[7]
+ pxor @XMM[8], @XMM[3]
+ pxor @XMM[8], @XMM[5]
+ pxor @XMM[8], @XMM[0]
+ pxor @XMM[8], @XMM[1]
+ ret
+.size _bsaes_decrypt8,.-_bsaes_decrypt8
+___
+}
+{
+my ($out,$inp,$rounds,$const)=("%rax","%rcx","%r10d","%r11");
+
+sub bitslice_key {
+my @x=reverse(@_[0..7]);
+my ($bs0,$bs1,$bs2,$t2,$t3)=@_[8..12];
+
+ &swapmove (@x[0,1],1,$bs0,$t2,$t3);
+$code.=<<___;
+ #&swapmove(@x[2,3],1,$t0,$t2,$t3);
+ movdqa @x[0], @x[2]
+ movdqa @x[1], @x[3]
+___
+ #&swapmove2x(@x[4,5,6,7],1,$t0,$t2,$t3);
+
+ &swapmove2x (@x[0,2,1,3],2,$bs1,$t2,$t3);
+$code.=<<___;
+ #&swapmove2x(@x[4,6,5,7],2,$t1,$t2,$t3);
+ movdqa @x[0], @x[4]
+ movdqa @x[2], @x[6]
+ movdqa @x[1], @x[5]
+ movdqa @x[3], @x[7]
+___
+ &swapmove2x (@x[0,4,1,5],4,$bs2,$t2,$t3);
+ &swapmove2x (@x[2,6,3,7],4,$bs2,$t2,$t3);
+}
+
+$code.=<<___;
+.type _bsaes_key_convert,\@abi-omnipotent
+.align 16
+_bsaes_key_convert:
+ lea .Lmasks(%rip), $const
+ movdqu ($inp), %xmm7 # load round 0 key
+ lea 0x10($inp), $inp
+ movdqa 0x00($const), %xmm0 # 0x01...
+ movdqa 0x10($const), %xmm1 # 0x02...
+ movdqa 0x20($const), %xmm2 # 0x04...
+ movdqa 0x30($const), %xmm3 # 0x08...
+ movdqa 0x40($const), %xmm4 # .LM0
+ pcmpeqd %xmm5, %xmm5 # .LNOT
+
+ movdqu ($inp), %xmm6 # load round 1 key
+ movdqa %xmm7, ($out) # save round 0 key
+ lea 0x10($out), $out
+ dec $rounds
+ jmp .Lkey_loop
+.align 16
+.Lkey_loop:
+ pshufb %xmm4, %xmm6 # .LM0
+
+ movdqa %xmm0, %xmm8
+ movdqa %xmm1, %xmm9
+
+ pand %xmm6, %xmm8
+ pand %xmm6, %xmm9
+ movdqa %xmm2, %xmm10
+ pcmpeqb %xmm0, %xmm8
+ psllq \$4, %xmm0 # 0x10...
+ movdqa %xmm3, %xmm11
+ pcmpeqb %xmm1, %xmm9
+ psllq \$4, %xmm1 # 0x20...
+
+ pand %xmm6, %xmm10
+ pand %xmm6, %xmm11
+ movdqa %xmm0, %xmm12
+ pcmpeqb %xmm2, %xmm10
+ psllq \$4, %xmm2 # 0x40...
+ movdqa %xmm1, %xmm13
+ pcmpeqb %xmm3, %xmm11
+ psllq \$4, %xmm3 # 0x80...
+
+ movdqa %xmm2, %xmm14
+ movdqa %xmm3, %xmm15
+ pxor %xmm5, %xmm8 # "pnot"
+ pxor %xmm5, %xmm9
+
+ pand %xmm6, %xmm12
+ pand %xmm6, %xmm13
+ movdqa %xmm8, 0x00($out) # write bit-sliced round key
+ pcmpeqb %xmm0, %xmm12
+ psrlq \$4, %xmm0 # 0x01...
+ movdqa %xmm9, 0x10($out)
+ pcmpeqb %xmm1, %xmm13
+ psrlq \$4, %xmm1 # 0x02...
+ lea 0x10($inp), $inp
+
+ pand %xmm6, %xmm14
+ pand %xmm6, %xmm15
+ movdqa %xmm10, 0x20($out)
+ pcmpeqb %xmm2, %xmm14
+ psrlq \$4, %xmm2 # 0x04...
+ movdqa %xmm11, 0x30($out)
+ pcmpeqb %xmm3, %xmm15
+ psrlq \$4, %xmm3 # 0x08...
+ movdqu ($inp), %xmm6 # load next round key
+
+ pxor %xmm5, %xmm13 # "pnot"
+ pxor %xmm5, %xmm14
+ movdqa %xmm12, 0x40($out)
+ movdqa %xmm13, 0x50($out)
+ movdqa %xmm14, 0x60($out)
+ movdqa %xmm15, 0x70($out)
+ lea 0x80($out),$out
+ dec $rounds
+ jnz .Lkey_loop
+
+ movdqa 0x50($const), %xmm7 # .L63
+ #movdqa %xmm6, ($out) # don't save last round key
+ ret
+.size _bsaes_key_convert,.-_bsaes_key_convert
+___
+}
+
+if (0 && !$win64) { # following four functions are unsupported interface
+ # used for benchmarking...
+$code.=<<___;
+.globl bsaes_enc_key_convert
+.type bsaes_enc_key_convert,\@function,2
+.align 16
+bsaes_enc_key_convert:
+ mov 240($inp),%r10d # pass rounds
+ mov $inp,%rcx # pass key
+ mov $out,%rax # pass key schedule
+ call _bsaes_key_convert
+ pxor %xmm6,%xmm7 # fix up last round key
+ movdqa %xmm7,(%rax) # save last round key
+ ret
+.size bsaes_enc_key_convert,.-bsaes_enc_key_convert
+
+.globl bsaes_encrypt_128
+.type bsaes_encrypt_128,\@function,4
+.align 16
+bsaes_encrypt_128:
+.Lenc128_loop:
+ movdqu 0x00($inp), @XMM[0] # load input
+ movdqu 0x10($inp), @XMM[1]
+ movdqu 0x20($inp), @XMM[2]
+ movdqu 0x30($inp), @XMM[3]
+ movdqu 0x40($inp), @XMM[4]
+ movdqu 0x50($inp), @XMM[5]
+ movdqu 0x60($inp), @XMM[6]
+ movdqu 0x70($inp), @XMM[7]
+ mov $key, %rax # pass the $key
+ lea 0x80($inp), $inp
+ mov \$10,%r10d
+
+ call _bsaes_encrypt8
+
+ movdqu @XMM[0], 0x00($out) # write output
+ movdqu @XMM[1], 0x10($out)
+ movdqu @XMM[4], 0x20($out)
+ movdqu @XMM[6], 0x30($out)
+ movdqu @XMM[3], 0x40($out)
+ movdqu @XMM[7], 0x50($out)
+ movdqu @XMM[2], 0x60($out)
+ movdqu @XMM[5], 0x70($out)
+ lea 0x80($out), $out
+ sub \$0x80,$len
+ ja .Lenc128_loop
+ ret
+.size bsaes_encrypt_128,.-bsaes_encrypt_128
+
+.globl bsaes_dec_key_convert
+.type bsaes_dec_key_convert,\@function,2
+.align 16
+bsaes_dec_key_convert:
+ mov 240($inp),%r10d # pass rounds
+ mov $inp,%rcx # pass key
+ mov $out,%rax # pass key schedule
+ call _bsaes_key_convert
+ pxor ($out),%xmm7 # fix up round 0 key
+ movdqa %xmm6,(%rax) # save last round key
+ movdqa %xmm7,($out)
+ ret
+.size bsaes_dec_key_convert,.-bsaes_dec_key_convert
+
+.globl bsaes_decrypt_128
+.type bsaes_decrypt_128,\@function,4
+.align 16
+bsaes_decrypt_128:
+.Ldec128_loop:
+ movdqu 0x00($inp), @XMM[0] # load input
+ movdqu 0x10($inp), @XMM[1]
+ movdqu 0x20($inp), @XMM[2]
+ movdqu 0x30($inp), @XMM[3]
+ movdqu 0x40($inp), @XMM[4]
+ movdqu 0x50($inp), @XMM[5]
+ movdqu 0x60($inp), @XMM[6]
+ movdqu 0x70($inp), @XMM[7]
+ mov $key, %rax # pass the $key
+ lea 0x80($inp), $inp
+ mov \$10,%r10d
+
+ call _bsaes_decrypt8
+
+ movdqu @XMM[0], 0x00($out) # write output
+ movdqu @XMM[1], 0x10($out)
+ movdqu @XMM[6], 0x20($out)
+ movdqu @XMM[4], 0x30($out)
+ movdqu @XMM[2], 0x40($out)
+ movdqu @XMM[7], 0x50($out)
+ movdqu @XMM[3], 0x60($out)
+ movdqu @XMM[5], 0x70($out)
+ lea 0x80($out), $out
+ sub \$0x80,$len
+ ja .Ldec128_loop
+ ret
+.size bsaes_decrypt_128,.-bsaes_decrypt_128
+___
+}
+{
+######################################################################
+#
+# OpenSSL interface
+#
+my ($arg1,$arg2,$arg3,$arg4,$arg5,$arg6)=$win64 ? ("%rcx","%rdx","%r8","%r9","%r10","%r11d")
+ : ("%rdi","%rsi","%rdx","%rcx","%r8","%r9d");
+my ($inp,$out,$len,$key)=("%r12","%r13","%r14","%r15");
+
+if ($ecb) {
+$code.=<<___;
+.globl bsaes_ecb_encrypt_blocks
+.type bsaes_ecb_encrypt_blocks,\@abi-omnipotent
+.align 16
+bsaes_ecb_encrypt_blocks:
+ mov %rsp, %rax
+.Lecb_enc_prologue:
+ push %rbp
+ push %rbx
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ lea -0x48(%rsp),%rsp
+___
+$code.=<<___ if ($win64);
+ lea -0xa0(%rsp), %rsp
+ movaps %xmm6, 0x40(%rsp)
+ movaps %xmm7, 0x50(%rsp)
+ movaps %xmm8, 0x60(%rsp)
+ movaps %xmm9, 0x70(%rsp)
+ movaps %xmm10, 0x80(%rsp)
+ movaps %xmm11, 0x90(%rsp)
+ movaps %xmm12, 0xa0(%rsp)
+ movaps %xmm13, 0xb0(%rsp)
+ movaps %xmm14, 0xc0(%rsp)
+ movaps %xmm15, 0xd0(%rsp)
+.Lecb_enc_body:
+___
+$code.=<<___;
+ mov %rsp,%rbp # backup %rsp
+ mov 240($arg4),%eax # rounds
+ mov $arg1,$inp # backup arguments
+ mov $arg2,$out
+ mov $arg3,$len
+ mov $arg4,$key
+ cmp \$8,$arg3
+ jb .Lecb_enc_short
+
+ mov %eax,%ebx # backup rounds
+ shl \$7,%rax # 128 bytes per inner round key
+ sub \$`128-32`,%rax # size of bit-sliced key schedule
+ sub %rax,%rsp
+ mov %rsp,%rax # pass key schedule
+ mov $key,%rcx # pass key
+ mov %ebx,%r10d # pass rounds
+ call _bsaes_key_convert
+ pxor %xmm6,%xmm7 # fix up last round key
+ movdqa %xmm7,(%rax) # save last round key
+
+ sub \$8,$len
+.Lecb_enc_loop:
+ movdqu 0x00($inp), @XMM[0] # load input
+ movdqu 0x10($inp), @XMM[1]
+ movdqu 0x20($inp), @XMM[2]
+ movdqu 0x30($inp), @XMM[3]
+ movdqu 0x40($inp), @XMM[4]
+ movdqu 0x50($inp), @XMM[5]
+ mov %rsp, %rax # pass key schedule
+ movdqu 0x60($inp), @XMM[6]
+ mov %ebx,%r10d # pass rounds
+ movdqu 0x70($inp), @XMM[7]
+ lea 0x80($inp), $inp
+
+ call _bsaes_encrypt8
+
+ movdqu @XMM[0], 0x00($out) # write output
+ movdqu @XMM[1], 0x10($out)
+ movdqu @XMM[4], 0x20($out)
+ movdqu @XMM[6], 0x30($out)
+ movdqu @XMM[3], 0x40($out)
+ movdqu @XMM[7], 0x50($out)
+ movdqu @XMM[2], 0x60($out)
+ movdqu @XMM[5], 0x70($out)
+ lea 0x80($out), $out
+ sub \$8,$len
+ jnc .Lecb_enc_loop
+
+ add \$8,$len
+ jz .Lecb_enc_done
+
+ movdqu 0x00($inp), @XMM[0] # load input
+ mov %rsp, %rax # pass key schedule
+ mov %ebx,%r10d # pass rounds
+ cmp \$2,$len
+ jb .Lecb_enc_one
+ movdqu 0x10($inp), @XMM[1]
+ je .Lecb_enc_two
+ movdqu 0x20($inp), @XMM[2]
+ cmp \$4,$len
+ jb .Lecb_enc_three
+ movdqu 0x30($inp), @XMM[3]
+ je .Lecb_enc_four
+ movdqu 0x40($inp), @XMM[4]
+ cmp \$6,$len
+ jb .Lecb_enc_five
+ movdqu 0x50($inp), @XMM[5]
+ je .Lecb_enc_six
+ movdqu 0x60($inp), @XMM[6]
+ call _bsaes_encrypt8
+ movdqu @XMM[0], 0x00($out) # write output
+ movdqu @XMM[1], 0x10($out)
+ movdqu @XMM[4], 0x20($out)
+ movdqu @XMM[6], 0x30($out)
+ movdqu @XMM[3], 0x40($out)
+ movdqu @XMM[7], 0x50($out)
+ movdqu @XMM[2], 0x60($out)
+ jmp .Lecb_enc_done
+.align 16
+.Lecb_enc_six:
+ call _bsaes_encrypt8
+ movdqu @XMM[0], 0x00($out) # write output
+ movdqu @XMM[1], 0x10($out)
+ movdqu @XMM[4], 0x20($out)
+ movdqu @XMM[6], 0x30($out)
+ movdqu @XMM[3], 0x40($out)
+ movdqu @XMM[7], 0x50($out)
+ jmp .Lecb_enc_done
+.align 16
+.Lecb_enc_five:
+ call _bsaes_encrypt8
+ movdqu @XMM[0], 0x00($out) # write output
+ movdqu @XMM[1], 0x10($out)
+ movdqu @XMM[4], 0x20($out)
+ movdqu @XMM[6], 0x30($out)
+ movdqu @XMM[3], 0x40($out)
+ jmp .Lecb_enc_done
+.align 16
+.Lecb_enc_four:
+ call _bsaes_encrypt8
+ movdqu @XMM[0], 0x00($out) # write output
+ movdqu @XMM[1], 0x10($out)
+ movdqu @XMM[4], 0x20($out)
+ movdqu @XMM[6], 0x30($out)
+ jmp .Lecb_enc_done
+.align 16
+.Lecb_enc_three:
+ call _bsaes_encrypt8
+ movdqu @XMM[0], 0x00($out) # write output
+ movdqu @XMM[1], 0x10($out)
+ movdqu @XMM[4], 0x20($out)
+ jmp .Lecb_enc_done
+.align 16
+.Lecb_enc_two:
+ call _bsaes_encrypt8
+ movdqu @XMM[0], 0x00($out) # write output
+ movdqu @XMM[1], 0x10($out)
+ jmp .Lecb_enc_done
+.align 16
+.Lecb_enc_one:
+ call _bsaes_encrypt8
+ movdqu @XMM[0], 0x00($out) # write output
+ jmp .Lecb_enc_done
+.align 16
+.Lecb_enc_short:
+ lea ($inp), $arg1
+ lea ($out), $arg2
+ lea ($key), $arg3
+ call asm_AES_encrypt
+ lea 16($inp), $inp
+ lea 16($out), $out
+ dec $len
+ jnz .Lecb_enc_short
+
+.Lecb_enc_done:
+ lea (%rsp),%rax
+ pxor %xmm0, %xmm0
+.Lecb_enc_bzero: # wipe key schedule [if any]
+ movdqa %xmm0, 0x00(%rax)
+ movdqa %xmm0, 0x10(%rax)
+ lea 0x20(%rax), %rax
+ cmp %rax, %rbp
+ jb .Lecb_enc_bzero
+
+ lea (%rbp),%rsp # restore %rsp
+___
+$code.=<<___ if ($win64);
+ movaps 0x40(%rbp), %xmm6
+ movaps 0x50(%rbp), %xmm7
+ movaps 0x60(%rbp), %xmm8
+ movaps 0x70(%rbp), %xmm9
+ movaps 0x80(%rbp), %xmm10
+ movaps 0x90(%rbp), %xmm11
+ movaps 0xa0(%rbp), %xmm12
+ movaps 0xb0(%rbp), %xmm13
+ movaps 0xc0(%rbp), %xmm14
+ movaps 0xd0(%rbp), %xmm15
+ lea 0xa0(%rbp), %rsp
+___
+$code.=<<___;
+ mov 0x48(%rsp), %r15
+ mov 0x50(%rsp), %r14
+ mov 0x58(%rsp), %r13
+ mov 0x60(%rsp), %r12
+ mov 0x68(%rsp), %rbx
+ mov 0x70(%rsp), %rax
+ lea 0x78(%rsp), %rsp
+ mov %rax, %rbp
+.Lecb_enc_epilogue:
+ ret
+.size bsaes_ecb_encrypt_blocks,.-bsaes_ecb_encrypt_blocks
+
+.globl bsaes_ecb_decrypt_blocks
+.type bsaes_ecb_decrypt_blocks,\@abi-omnipotent
+.align 16
+bsaes_ecb_decrypt_blocks:
+ mov %rsp, %rax
+.Lecb_dec_prologue:
+ push %rbp
+ push %rbx
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ lea -0x48(%rsp),%rsp
+___
+$code.=<<___ if ($win64);
+ lea -0xa0(%rsp), %rsp
+ movaps %xmm6, 0x40(%rsp)
+ movaps %xmm7, 0x50(%rsp)
+ movaps %xmm8, 0x60(%rsp)
+ movaps %xmm9, 0x70(%rsp)
+ movaps %xmm10, 0x80(%rsp)
+ movaps %xmm11, 0x90(%rsp)
+ movaps %xmm12, 0xa0(%rsp)
+ movaps %xmm13, 0xb0(%rsp)
+ movaps %xmm14, 0xc0(%rsp)
+ movaps %xmm15, 0xd0(%rsp)
+.Lecb_dec_body:
+___
+$code.=<<___;
+ mov %rsp,%rbp # backup %rsp
+ mov 240($arg4),%eax # rounds
+ mov $arg1,$inp # backup arguments
+ mov $arg2,$out
+ mov $arg3,$len
+ mov $arg4,$key
+ cmp \$8,$arg3
+ jb .Lecb_dec_short
+
+ mov %eax,%ebx # backup rounds
+ shl \$7,%rax # 128 bytes per inner round key
+ sub \$`128-32`,%rax # size of bit-sliced key schedule
+ sub %rax,%rsp
+ mov %rsp,%rax # pass key schedule
+ mov $key,%rcx # pass key
+ mov %ebx,%r10d # pass rounds
+ call _bsaes_key_convert
+ pxor (%rsp),%xmm7 # fix up 0 round key
+ movdqa %xmm6,(%rax) # save last round key
+ movdqa %xmm7,(%rsp)
+
+ sub \$8,$len
+.Lecb_dec_loop:
+ movdqu 0x00($inp), @XMM[0] # load input
+ movdqu 0x10($inp), @XMM[1]
+ movdqu 0x20($inp), @XMM[2]
+ movdqu 0x30($inp), @XMM[3]
+ movdqu 0x40($inp), @XMM[4]
+ movdqu 0x50($inp), @XMM[5]
+ mov %rsp, %rax # pass key schedule
+ movdqu 0x60($inp), @XMM[6]
+ mov %ebx,%r10d # pass rounds
+ movdqu 0x70($inp), @XMM[7]
+ lea 0x80($inp), $inp
+
+ call _bsaes_decrypt8
+
+ movdqu @XMM[0], 0x00($out) # write output
+ movdqu @XMM[1], 0x10($out)
+ movdqu @XMM[6], 0x20($out)
+ movdqu @XMM[4], 0x30($out)
+ movdqu @XMM[2], 0x40($out)
+ movdqu @XMM[7], 0x50($out)
+ movdqu @XMM[3], 0x60($out)
+ movdqu @XMM[5], 0x70($out)
+ lea 0x80($out), $out
+ sub \$8,$len
+ jnc .Lecb_dec_loop
+
+ add \$8,$len
+ jz .Lecb_dec_done
+
+ movdqu 0x00($inp), @XMM[0] # load input
+ mov %rsp, %rax # pass key schedule
+ mov %ebx,%r10d # pass rounds
+ cmp \$2,$len
+ jb .Lecb_dec_one
+ movdqu 0x10($inp), @XMM[1]
+ je .Lecb_dec_two
+ movdqu 0x20($inp), @XMM[2]
+ cmp \$4,$len
+ jb .Lecb_dec_three
+ movdqu 0x30($inp), @XMM[3]
+ je .Lecb_dec_four
+ movdqu 0x40($inp), @XMM[4]
+ cmp \$6,$len
+ jb .Lecb_dec_five
+ movdqu 0x50($inp), @XMM[5]
+ je .Lecb_dec_six
+ movdqu 0x60($inp), @XMM[6]
+ call _bsaes_decrypt8
+ movdqu @XMM[0], 0x00($out) # write output
+ movdqu @XMM[1], 0x10($out)
+ movdqu @XMM[6], 0x20($out)
+ movdqu @XMM[4], 0x30($out)
+ movdqu @XMM[2], 0x40($out)
+ movdqu @XMM[7], 0x50($out)
+ movdqu @XMM[3], 0x60($out)
+ jmp .Lecb_dec_done
+.align 16
+.Lecb_dec_six:
+ call _bsaes_decrypt8
+ movdqu @XMM[0], 0x00($out) # write output
+ movdqu @XMM[1], 0x10($out)
+ movdqu @XMM[6], 0x20($out)
+ movdqu @XMM[4], 0x30($out)
+ movdqu @XMM[2], 0x40($out)
+ movdqu @XMM[7], 0x50($out)
+ jmp .Lecb_dec_done
+.align 16
+.Lecb_dec_five:
+ call _bsaes_decrypt8
+ movdqu @XMM[0], 0x00($out) # write output
+ movdqu @XMM[1], 0x10($out)
+ movdqu @XMM[6], 0x20($out)
+ movdqu @XMM[4], 0x30($out)
+ movdqu @XMM[2], 0x40($out)
+ jmp .Lecb_dec_done
+.align 16
+.Lecb_dec_four:
+ call _bsaes_decrypt8
+ movdqu @XMM[0], 0x00($out) # write output
+ movdqu @XMM[1], 0x10($out)
+ movdqu @XMM[6], 0x20($out)
+ movdqu @XMM[4], 0x30($out)
+ jmp .Lecb_dec_done
+.align 16
+.Lecb_dec_three:
+ call _bsaes_decrypt8
+ movdqu @XMM[0], 0x00($out) # write output
+ movdqu @XMM[1], 0x10($out)
+ movdqu @XMM[6], 0x20($out)
+ jmp .Lecb_dec_done
+.align 16
+.Lecb_dec_two:
+ call _bsaes_decrypt8
+ movdqu @XMM[0], 0x00($out) # write output
+ movdqu @XMM[1], 0x10($out)
+ jmp .Lecb_dec_done
+.align 16
+.Lecb_dec_one:
+ call _bsaes_decrypt8
+ movdqu @XMM[0], 0x00($out) # write output
+ jmp .Lecb_dec_done
+.align 16
+.Lecb_dec_short:
+ lea ($inp), $arg1
+ lea ($out), $arg2
+ lea ($key), $arg3
+ call asm_AES_decrypt
+ lea 16($inp), $inp
+ lea 16($out), $out
+ dec $len
+ jnz .Lecb_dec_short
+
+.Lecb_dec_done:
+ lea (%rsp),%rax
+ pxor %xmm0, %xmm0
+.Lecb_dec_bzero: # wipe key schedule [if any]
+ movdqa %xmm0, 0x00(%rax)
+ movdqa %xmm0, 0x10(%rax)
+ lea 0x20(%rax), %rax
+ cmp %rax, %rbp
+ jb .Lecb_dec_bzero
+
+ lea (%rbp),%rsp # restore %rsp
+___
+$code.=<<___ if ($win64);
+ movaps 0x40(%rbp), %xmm6
+ movaps 0x50(%rbp), %xmm7
+ movaps 0x60(%rbp), %xmm8
+ movaps 0x70(%rbp), %xmm9
+ movaps 0x80(%rbp), %xmm10
+ movaps 0x90(%rbp), %xmm11
+ movaps 0xa0(%rbp), %xmm12
+ movaps 0xb0(%rbp), %xmm13
+ movaps 0xc0(%rbp), %xmm14
+ movaps 0xd0(%rbp), %xmm15
+ lea 0xa0(%rbp), %rsp
+___
+$code.=<<___;
+ mov 0x48(%rsp), %r15
+ mov 0x50(%rsp), %r14
+ mov 0x58(%rsp), %r13
+ mov 0x60(%rsp), %r12
+ mov 0x68(%rsp), %rbx
+ mov 0x70(%rsp), %rax
+ lea 0x78(%rsp), %rsp
+ mov %rax, %rbp
+.Lecb_dec_epilogue:
+ ret
+.size bsaes_ecb_decrypt_blocks,.-bsaes_ecb_decrypt_blocks
+___
+}
+$code.=<<___;
+.extern asm_AES_cbc_encrypt
+.globl bsaes_cbc_encrypt
+.type bsaes_cbc_encrypt,\@abi-omnipotent
+.align 16
+bsaes_cbc_encrypt:
+___
+$code.=<<___ if ($win64);
+ mov 48(%rsp),$arg6 # pull direction flag
+___
+$code.=<<___;
+ cmp \$0,$arg6
+ jne asm_AES_cbc_encrypt
+ cmp \$128,$arg3
+ jb asm_AES_cbc_encrypt
+
+ mov %rsp, %rax
+.Lcbc_dec_prologue:
+ push %rbp
+ push %rbx
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ lea -0x48(%rsp), %rsp
+___
+$code.=<<___ if ($win64);
+ mov 0xa0(%rsp),$arg5 # pull ivp
+ lea -0xa0(%rsp), %rsp
+ movaps %xmm6, 0x40(%rsp)
+ movaps %xmm7, 0x50(%rsp)
+ movaps %xmm8, 0x60(%rsp)
+ movaps %xmm9, 0x70(%rsp)
+ movaps %xmm10, 0x80(%rsp)
+ movaps %xmm11, 0x90(%rsp)
+ movaps %xmm12, 0xa0(%rsp)
+ movaps %xmm13, 0xb0(%rsp)
+ movaps %xmm14, 0xc0(%rsp)
+ movaps %xmm15, 0xd0(%rsp)
+.Lcbc_dec_body:
+___
+$code.=<<___;
+ mov %rsp, %rbp # backup %rsp
+ mov 240($arg4), %eax # rounds
+ mov $arg1, $inp # backup arguments
+ mov $arg2, $out
+ mov $arg3, $len
+ mov $arg4, $key
+ mov $arg5, %rbx
+ shr \$4, $len # bytes to blocks
+
+ mov %eax, %edx # rounds
+ shl \$7, %rax # 128 bytes per inner round key
+ sub \$`128-32`, %rax # size of bit-sliced key schedule
+ sub %rax, %rsp
+
+ mov %rsp, %rax # pass key schedule
+ mov $key, %rcx # pass key
+ mov %edx, %r10d # pass rounds
+ call _bsaes_key_convert
+ pxor (%rsp),%xmm7 # fix up 0 round key
+ movdqa %xmm6,(%rax) # save last round key
+ movdqa %xmm7,(%rsp)
+
+ movdqu (%rbx), @XMM[15] # load IV
+ sub \$8,$len
+.Lcbc_dec_loop:
+ movdqu 0x00($inp), @XMM[0] # load input
+ movdqu 0x10($inp), @XMM[1]
+ movdqu 0x20($inp), @XMM[2]
+ movdqu 0x30($inp), @XMM[3]
+ movdqu 0x40($inp), @XMM[4]
+ movdqu 0x50($inp), @XMM[5]
+ mov %rsp, %rax # pass key schedule
+ movdqu 0x60($inp), @XMM[6]
+ mov %edx,%r10d # pass rounds
+ movdqu 0x70($inp), @XMM[7]
+ movdqa @XMM[15], 0x20(%rbp) # put aside IV
+
+ call _bsaes_decrypt8
+
+ pxor 0x20(%rbp), @XMM[0] # ^= IV
+ movdqu 0x00($inp), @XMM[8] # re-load input
+ movdqu 0x10($inp), @XMM[9]
+ pxor @XMM[8], @XMM[1]
+ movdqu 0x20($inp), @XMM[10]
+ pxor @XMM[9], @XMM[6]
+ movdqu 0x30($inp), @XMM[11]
+ pxor @XMM[10], @XMM[4]
+ movdqu 0x40($inp), @XMM[12]
+ pxor @XMM[11], @XMM[2]
+ movdqu 0x50($inp), @XMM[13]
+ pxor @XMM[12], @XMM[7]
+ movdqu 0x60($inp), @XMM[14]
+ pxor @XMM[13], @XMM[3]
+ movdqu 0x70($inp), @XMM[15] # IV
+ pxor @XMM[14], @XMM[5]
+ movdqu @XMM[0], 0x00($out) # write output
+ lea 0x80($inp), $inp
+ movdqu @XMM[1], 0x10($out)
+ movdqu @XMM[6], 0x20($out)
+ movdqu @XMM[4], 0x30($out)
+ movdqu @XMM[2], 0x40($out)
+ movdqu @XMM[7], 0x50($out)
+ movdqu @XMM[3], 0x60($out)
+ movdqu @XMM[5], 0x70($out)
+ lea 0x80($out), $out
+ sub \$8,$len
+ jnc .Lcbc_dec_loop
+
+ add \$8,$len
+ jz .Lcbc_dec_done
+
+ movdqu 0x00($inp), @XMM[0] # load input
+ mov %rsp, %rax # pass key schedule
+ mov %edx, %r10d # pass rounds
+ cmp \$2,$len
+ jb .Lcbc_dec_one
+ movdqu 0x10($inp), @XMM[1]
+ je .Lcbc_dec_two
+ movdqu 0x20($inp), @XMM[2]
+ cmp \$4,$len
+ jb .Lcbc_dec_three
+ movdqu 0x30($inp), @XMM[3]
+ je .Lcbc_dec_four
+ movdqu 0x40($inp), @XMM[4]
+ cmp \$6,$len
+ jb .Lcbc_dec_five
+ movdqu 0x50($inp), @XMM[5]
+ je .Lcbc_dec_six
+ movdqu 0x60($inp), @XMM[6]
+ movdqa @XMM[15], 0x20(%rbp) # put aside IV
+ call _bsaes_decrypt8
+ pxor 0x20(%rbp), @XMM[0] # ^= IV
+ movdqu 0x00($inp), @XMM[8] # re-load input
+ movdqu 0x10($inp), @XMM[9]
+ pxor @XMM[8], @XMM[1]
+ movdqu 0x20($inp), @XMM[10]
+ pxor @XMM[9], @XMM[6]
+ movdqu 0x30($inp), @XMM[11]
+ pxor @XMM[10], @XMM[4]
+ movdqu 0x40($inp), @XMM[12]
+ pxor @XMM[11], @XMM[2]
+ movdqu 0x50($inp), @XMM[13]
+ pxor @XMM[12], @XMM[7]
+ movdqu 0x60($inp), @XMM[15] # IV
+ pxor @XMM[13], @XMM[3]
+ movdqu @XMM[0], 0x00($out) # write output
+ movdqu @XMM[1], 0x10($out)
+ movdqu @XMM[6], 0x20($out)
+ movdqu @XMM[4], 0x30($out)
+ movdqu @XMM[2], 0x40($out)
+ movdqu @XMM[7], 0x50($out)
+ movdqu @XMM[3], 0x60($out)
+ jmp .Lcbc_dec_done
+.align 16
+.Lcbc_dec_six:
+ movdqa @XMM[15], 0x20(%rbp) # put aside IV
+ call _bsaes_decrypt8
+ pxor 0x20(%rbp), @XMM[0] # ^= IV
+ movdqu 0x00($inp), @XMM[8] # re-load input
+ movdqu 0x10($inp), @XMM[9]
+ pxor @XMM[8], @XMM[1]
+ movdqu 0x20($inp), @XMM[10]
+ pxor @XMM[9], @XMM[6]
+ movdqu 0x30($inp), @XMM[11]
+ pxor @XMM[10], @XMM[4]
+ movdqu 0x40($inp), @XMM[12]
+ pxor @XMM[11], @XMM[2]
+ movdqu 0x50($inp), @XMM[15] # IV
+ pxor @XMM[12], @XMM[7]
+ movdqu @XMM[0], 0x00($out) # write output
+ movdqu @XMM[1], 0x10($out)
+ movdqu @XMM[6], 0x20($out)
+ movdqu @XMM[4], 0x30($out)
+ movdqu @XMM[2], 0x40($out)
+ movdqu @XMM[7], 0x50($out)
+ jmp .Lcbc_dec_done
+.align 16
+.Lcbc_dec_five:
+ movdqa @XMM[15], 0x20(%rbp) # put aside IV
+ call _bsaes_decrypt8
+ pxor 0x20(%rbp), @XMM[0] # ^= IV
+ movdqu 0x00($inp), @XMM[8] # re-load input
+ movdqu 0x10($inp), @XMM[9]
+ pxor @XMM[8], @XMM[1]
+ movdqu 0x20($inp), @XMM[10]
+ pxor @XMM[9], @XMM[6]
+ movdqu 0x30($inp), @XMM[11]
+ pxor @XMM[10], @XMM[4]
+ movdqu 0x40($inp), @XMM[15] # IV
+ pxor @XMM[11], @XMM[2]
+ movdqu @XMM[0], 0x00($out) # write output
+ movdqu @XMM[1], 0x10($out)
+ movdqu @XMM[6], 0x20($out)
+ movdqu @XMM[4], 0x30($out)
+ movdqu @XMM[2], 0x40($out)
+ jmp .Lcbc_dec_done
+.align 16
+.Lcbc_dec_four:
+ movdqa @XMM[15], 0x20(%rbp) # put aside IV
+ call _bsaes_decrypt8
+ pxor 0x20(%rbp), @XMM[0] # ^= IV
+ movdqu 0x00($inp), @XMM[8] # re-load input
+ movdqu 0x10($inp), @XMM[9]
+ pxor @XMM[8], @XMM[1]
+ movdqu 0x20($inp), @XMM[10]
+ pxor @XMM[9], @XMM[6]
+ movdqu 0x30($inp), @XMM[15] # IV
+ pxor @XMM[10], @XMM[4]
+ movdqu @XMM[0], 0x00($out) # write output
+ movdqu @XMM[1], 0x10($out)
+ movdqu @XMM[6], 0x20($out)
+ movdqu @XMM[4], 0x30($out)
+ jmp .Lcbc_dec_done
+.align 16
+.Lcbc_dec_three:
+ movdqa @XMM[15], 0x20(%rbp) # put aside IV
+ call _bsaes_decrypt8
+ pxor 0x20(%rbp), @XMM[0] # ^= IV
+ movdqu 0x00($inp), @XMM[8] # re-load input
+ movdqu 0x10($inp), @XMM[9]
+ pxor @XMM[8], @XMM[1]
+ movdqu 0x20($inp), @XMM[15] # IV
+ pxor @XMM[9], @XMM[6]
+ movdqu @XMM[0], 0x00($out) # write output
+ movdqu @XMM[1], 0x10($out)
+ movdqu @XMM[6], 0x20($out)
+ jmp .Lcbc_dec_done
+.align 16
+.Lcbc_dec_two:
+ movdqa @XMM[15], 0x20(%rbp) # put aside IV
+ call _bsaes_decrypt8
+ pxor 0x20(%rbp), @XMM[0] # ^= IV
+ movdqu 0x00($inp), @XMM[8] # re-load input
+ movdqu 0x10($inp), @XMM[15] # IV
+ pxor @XMM[8], @XMM[1]
+ movdqu @XMM[0], 0x00($out) # write output
+ movdqu @XMM[1], 0x10($out)
+ jmp .Lcbc_dec_done
+.align 16
+.Lcbc_dec_one:
+ lea ($inp), $arg1
+ lea 0x20(%rbp), $arg2 # buffer output
+ lea ($key), $arg3
+ call asm_AES_decrypt # doesn't touch %xmm
+ pxor 0x20(%rbp), @XMM[15] # ^= IV
+ movdqu @XMM[15], ($out) # write output
+ movdqa @XMM[0], @XMM[15] # IV
+
+.Lcbc_dec_done:
+ movdqu @XMM[15], (%rbx) # return IV
+ lea (%rsp), %rax
+ pxor %xmm0, %xmm0
+.Lcbc_dec_bzero: # wipe key schedule [if any]
+ movdqa %xmm0, 0x00(%rax)
+ movdqa %xmm0, 0x10(%rax)
+ lea 0x20(%rax), %rax
+ cmp %rax, %rbp
+ ja .Lcbc_dec_bzero
+
+ lea (%rbp),%rsp # restore %rsp
+___
+$code.=<<___ if ($win64);
+ movaps 0x40(%rbp), %xmm6
+ movaps 0x50(%rbp), %xmm7
+ movaps 0x60(%rbp), %xmm8
+ movaps 0x70(%rbp), %xmm9
+ movaps 0x80(%rbp), %xmm10
+ movaps 0x90(%rbp), %xmm11
+ movaps 0xa0(%rbp), %xmm12
+ movaps 0xb0(%rbp), %xmm13
+ movaps 0xc0(%rbp), %xmm14
+ movaps 0xd0(%rbp), %xmm15
+ lea 0xa0(%rbp), %rsp
+___
+$code.=<<___;
+ mov 0x48(%rsp), %r15
+ mov 0x50(%rsp), %r14
+ mov 0x58(%rsp), %r13
+ mov 0x60(%rsp), %r12
+ mov 0x68(%rsp), %rbx
+ mov 0x70(%rsp), %rax
+ lea 0x78(%rsp), %rsp
+ mov %rax, %rbp
+.Lcbc_dec_epilogue:
+ ret
+.size bsaes_cbc_encrypt,.-bsaes_cbc_encrypt
+
+.globl bsaes_ctr32_encrypt_blocks
+.type bsaes_ctr32_encrypt_blocks,\@abi-omnipotent
+.align 16
+bsaes_ctr32_encrypt_blocks:
+ mov %rsp, %rax
+.Lctr_enc_prologue:
+ push %rbp
+ push %rbx
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ lea -0x48(%rsp), %rsp
+___
+$code.=<<___ if ($win64);
+ mov 0xa0(%rsp),$arg5 # pull ivp
+ lea -0xa0(%rsp), %rsp
+ movaps %xmm6, 0x40(%rsp)
+ movaps %xmm7, 0x50(%rsp)
+ movaps %xmm8, 0x60(%rsp)
+ movaps %xmm9, 0x70(%rsp)
+ movaps %xmm10, 0x80(%rsp)
+ movaps %xmm11, 0x90(%rsp)
+ movaps %xmm12, 0xa0(%rsp)
+ movaps %xmm13, 0xb0(%rsp)
+ movaps %xmm14, 0xc0(%rsp)
+ movaps %xmm15, 0xd0(%rsp)
+.Lctr_enc_body:
+___
+$code.=<<___;
+ mov %rsp, %rbp # backup %rsp
+ movdqu ($arg5), %xmm0 # load counter
+ mov 240($arg4), %eax # rounds
+ mov $arg1, $inp # backup arguments
+ mov $arg2, $out
+ mov $arg3, $len
+ mov $arg4, $key
+ movdqa %xmm0, 0x20(%rbp) # copy counter
+ cmp \$8, $arg3
+ jb .Lctr_enc_short
+
+ mov %eax, %ebx # rounds
+ shl \$7, %rax # 128 bytes per inner round key
+ sub \$`128-32`, %rax # size of bit-sliced key schedule
+ sub %rax, %rsp
+
+ mov %rsp, %rax # pass key schedule
+ mov $key, %rcx # pass key
+ mov %ebx, %r10d # pass rounds
+ call _bsaes_key_convert
+ pxor %xmm6,%xmm7 # fix up last round key
+ movdqa %xmm7,(%rax) # save last round key
+
+ movdqa (%rsp), @XMM[9] # load round0 key
+ lea .LADD1(%rip), %r11
+ movdqa 0x20(%rbp), @XMM[0] # counter copy
+ movdqa -0x20(%r11), @XMM[8] # .LSWPUP
+ pshufb @XMM[8], @XMM[9] # byte swap upper part
+ pshufb @XMM[8], @XMM[0]
+ movdqa @XMM[9], (%rsp) # save adjusted round0 key
+ jmp .Lctr_enc_loop
+.align 16
+.Lctr_enc_loop:
+ movdqa @XMM[0], 0x20(%rbp) # save counter
+ movdqa @XMM[0], @XMM[1] # prepare 8 counter values
+ movdqa @XMM[0], @XMM[2]
+ paddd 0x00(%r11), @XMM[1] # .LADD1
+ movdqa @XMM[0], @XMM[3]
+ paddd 0x10(%r11), @XMM[2] # .LADD2
+ movdqa @XMM[0], @XMM[4]
+ paddd 0x20(%r11), @XMM[3] # .LADD3
+ movdqa @XMM[0], @XMM[5]
+ paddd 0x30(%r11), @XMM[4] # .LADD4
+ movdqa @XMM[0], @XMM[6]
+ paddd 0x40(%r11), @XMM[5] # .LADD5
+ movdqa @XMM[0], @XMM[7]
+ paddd 0x50(%r11), @XMM[6] # .LADD6
+ paddd 0x60(%r11), @XMM[7] # .LADD7
+
+ # Borrow prologue from _bsaes_encrypt8 to use the opportunity
+ # to flip byte order in 32-bit counter
+ movdqa (%rsp), @XMM[9] # round 0 key
+ lea 0x10(%rsp), %rax # pass key schedule
+ movdqa -0x10(%r11), @XMM[8] # .LSWPUPM0SR
+ pxor @XMM[9], @XMM[0] # xor with round0 key
+ pxor @XMM[9], @XMM[1]
+ pshufb @XMM[8], @XMM[0]
+ pxor @XMM[9], @XMM[2]
+ pshufb @XMM[8], @XMM[1]
+ pxor @XMM[9], @XMM[3]
+ pshufb @XMM[8], @XMM[2]
+ pxor @XMM[9], @XMM[4]
+ pshufb @XMM[8], @XMM[3]
+ pxor @XMM[9], @XMM[5]
+ pshufb @XMM[8], @XMM[4]
+ pxor @XMM[9], @XMM[6]
+ pshufb @XMM[8], @XMM[5]
+ pxor @XMM[9], @XMM[7]
+ pshufb @XMM[8], @XMM[6]
+ lea .LBS0(%rip), %r11 # constants table
+ pshufb @XMM[8], @XMM[7]
+ mov %ebx,%r10d # pass rounds
+
+ call _bsaes_encrypt8_bitslice
+
+ sub \$8,$len
+ jc .Lctr_enc_loop_done
+
+ movdqu 0x00($inp), @XMM[8] # load input
+ movdqu 0x10($inp), @XMM[9]
+ movdqu 0x20($inp), @XMM[10]
+ movdqu 0x30($inp), @XMM[11]
+ movdqu 0x40($inp), @XMM[12]
+ movdqu 0x50($inp), @XMM[13]
+ movdqu 0x60($inp), @XMM[14]
+ movdqu 0x70($inp), @XMM[15]
+ lea 0x80($inp),$inp
+ pxor @XMM[0], @XMM[8]
+ movdqa 0x20(%rbp), @XMM[0] # load counter
+ pxor @XMM[9], @XMM[1]
+ movdqu @XMM[8], 0x00($out) # write output
+ pxor @XMM[10], @XMM[4]
+ movdqu @XMM[1], 0x10($out)
+ pxor @XMM[11], @XMM[6]
+ movdqu @XMM[4], 0x20($out)
+ pxor @XMM[12], @XMM[3]
+ movdqu @XMM[6], 0x30($out)
+ pxor @XMM[13], @XMM[7]
+ movdqu @XMM[3], 0x40($out)
+ pxor @XMM[14], @XMM[2]
+ movdqu @XMM[7], 0x50($out)
+ pxor @XMM[15], @XMM[5]
+ movdqu @XMM[2], 0x60($out)
+ lea .LADD1(%rip), %r11
+ movdqu @XMM[5], 0x70($out)
+ lea 0x80($out), $out
+ paddd 0x70(%r11), @XMM[0] # .LADD8
+ jnz .Lctr_enc_loop
+
+ jmp .Lctr_enc_done
+.align 16
+.Lctr_enc_loop_done:
+ add \$8, $len
+ movdqu 0x00($inp), @XMM[8] # load input
+ pxor @XMM[8], @XMM[0]
+ movdqu @XMM[0], 0x00($out) # write output
+ cmp \$2,$len
+ jb .Lctr_enc_done
+ movdqu 0x10($inp), @XMM[9]
+ pxor @XMM[9], @XMM[1]
+ movdqu @XMM[1], 0x10($out)
+ je .Lctr_enc_done
+ movdqu 0x20($inp), @XMM[10]
+ pxor @XMM[10], @XMM[4]
+ movdqu @XMM[4], 0x20($out)
+ cmp \$4,$len
+ jb .Lctr_enc_done
+ movdqu 0x30($inp), @XMM[11]
+ pxor @XMM[11], @XMM[6]
+ movdqu @XMM[6], 0x30($out)
+ je .Lctr_enc_done
+ movdqu 0x40($inp), @XMM[12]
+ pxor @XMM[12], @XMM[3]
+ movdqu @XMM[3], 0x40($out)
+ cmp \$6,$len
+ jb .Lctr_enc_done
+ movdqu 0x50($inp), @XMM[13]
+ pxor @XMM[13], @XMM[7]
+ movdqu @XMM[7], 0x50($out)
+ je .Lctr_enc_done
+ movdqu 0x60($inp), @XMM[14]
+ pxor @XMM[14], @XMM[2]
+ movdqu @XMM[2], 0x60($out)
+ jmp .Lctr_enc_done
+
+.align 16
+.Lctr_enc_short:
+ lea 0x20(%rbp), $arg1
+ lea 0x30(%rbp), $arg2
+ lea ($key), $arg3
+ call asm_AES_encrypt
+ movdqu ($inp), @XMM[1]
+ lea 16($inp), $inp
+ mov 0x2c(%rbp), %eax # load 32-bit counter
+ bswap %eax
+ pxor 0x30(%rbp), @XMM[1]
+ inc %eax # increment
+ movdqu @XMM[1], ($out)
+ bswap %eax
+ lea 16($out), $out
+ mov %eax, 0x2c(%rsp) # save 32-bit counter
+ dec $len
+ jnz .Lctr_enc_short
+
+.Lctr_enc_done:
+ lea (%rsp), %rax
+ pxor %xmm0, %xmm0
+.Lctr_enc_bzero: # wipe key schedule [if any]
+ movdqa %xmm0, 0x00(%rax)
+ movdqa %xmm0, 0x10(%rax)
+ lea 0x20(%rax), %rax
+ cmp %rax, %rbp
+ ja .Lctr_enc_bzero
+
+ lea (%rbp),%rsp # restore %rsp
+___
+$code.=<<___ if ($win64);
+ movaps 0x40(%rbp), %xmm6
+ movaps 0x50(%rbp), %xmm7
+ movaps 0x60(%rbp), %xmm8
+ movaps 0x70(%rbp), %xmm9
+ movaps 0x80(%rbp), %xmm10
+ movaps 0x90(%rbp), %xmm11
+ movaps 0xa0(%rbp), %xmm12
+ movaps 0xb0(%rbp), %xmm13
+ movaps 0xc0(%rbp), %xmm14
+ movaps 0xd0(%rbp), %xmm15
+ lea 0xa0(%rbp), %rsp
+___
+$code.=<<___;
+ mov 0x48(%rsp), %r15
+ mov 0x50(%rsp), %r14
+ mov 0x58(%rsp), %r13
+ mov 0x60(%rsp), %r12
+ mov 0x68(%rsp), %rbx
+ mov 0x70(%rsp), %rax
+ lea 0x78(%rsp), %rsp
+ mov %rax, %rbp
+.Lctr_enc_epilogue:
+ ret
+.size bsaes_ctr32_encrypt_blocks,.-bsaes_ctr32_encrypt_blocks
+___
+######################################################################
+# void bsaes_xts_[en|de]crypt(const char *inp,char *out,size_t len,
+# const AES_KEY *key1, const AES_KEY *key2,
+# const unsigned char iv[16]);
+#
+my ($twmask,$twres,$twtmp)=@XMM[13..15];
+$arg6=~s/d$//;
+
+$code.=<<___;
+.globl bsaes_xts_encrypt
+.type bsaes_xts_encrypt,\@abi-omnipotent
+.align 16
+bsaes_xts_encrypt:
+ mov %rsp, %rax
+.Lxts_enc_prologue:
+ push %rbp
+ push %rbx
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ lea -0x48(%rsp), %rsp
+___
+$code.=<<___ if ($win64);
+ mov 0xa0(%rsp),$arg5 # pull key2
+ mov 0xa8(%rsp),$arg6 # pull ivp
+ lea -0xa0(%rsp), %rsp
+ movaps %xmm6, 0x40(%rsp)
+ movaps %xmm7, 0x50(%rsp)
+ movaps %xmm8, 0x60(%rsp)
+ movaps %xmm9, 0x70(%rsp)
+ movaps %xmm10, 0x80(%rsp)
+ movaps %xmm11, 0x90(%rsp)
+ movaps %xmm12, 0xa0(%rsp)
+ movaps %xmm13, 0xb0(%rsp)
+ movaps %xmm14, 0xc0(%rsp)
+ movaps %xmm15, 0xd0(%rsp)
+.Lxts_enc_body:
+___
+$code.=<<___;
+ mov %rsp, %rbp # backup %rsp
+ mov $arg1, $inp # backup arguments
+ mov $arg2, $out
+ mov $arg3, $len
+ mov $arg4, $key
+
+ lea ($arg6), $arg1
+ lea 0x20(%rbp), $arg2
+ lea ($arg5), $arg3
+ call asm_AES_encrypt # generate initial tweak
+
+ mov 240($key), %eax # rounds
+ mov $len, %rbx # backup $len
+
+ mov %eax, %edx # rounds
+ shl \$7, %rax # 128 bytes per inner round key
+ sub \$`128-32`, %rax # size of bit-sliced key schedule
+ sub %rax, %rsp
+
+ mov %rsp, %rax # pass key schedule
+ mov $key, %rcx # pass key
+ mov %edx, %r10d # pass rounds
+ call _bsaes_key_convert
+ pxor %xmm6, %xmm7 # fix up last round key
+ movdqa %xmm7, (%rax) # save last round key
+
+ and \$-16, $len
+ sub \$0x80, %rsp # place for tweak[8]
+ movdqa 0x20(%rbp), @XMM[7] # initial tweak
+
+ pxor $twtmp, $twtmp
+ movdqa .Lxts_magic(%rip), $twmask
+ pcmpgtd @XMM[7], $twtmp # broadcast upper bits
+
+ sub \$0x80, $len
+ jc .Lxts_enc_short
+ jmp .Lxts_enc_loop
+
+.align 16
+.Lxts_enc_loop:
+___
+ for ($i=0;$i<7;$i++) {
+ $code.=<<___;
+ pshufd \$0x13, $twtmp, $twres
+ pxor $twtmp, $twtmp
+ movdqa @XMM[7], @XMM[$i]
+ movdqa @XMM[7], `0x10*$i`(%rsp)# save tweak[$i]
+ paddq @XMM[7], @XMM[7] # psllq 1,$tweak
+ pand $twmask, $twres # isolate carry and residue
+ pcmpgtd @XMM[7], $twtmp # broadcast upper bits
+ pxor $twres, @XMM[7]
+___
+ $code.=<<___ if ($i>=1);
+ movdqu `0x10*($i-1)`($inp), @XMM[8+$i-1]
+___
+ $code.=<<___ if ($i>=2);
+ pxor @XMM[8+$i-2], @XMM[$i-2]# input[] ^ tweak[]
+___
+ }
+$code.=<<___;
+ movdqu 0x60($inp), @XMM[8+6]
+ pxor @XMM[8+5], @XMM[5]
+ movdqu 0x70($inp), @XMM[8+7]
+ lea 0x80($inp), $inp
+ movdqa @XMM[7], 0x70(%rsp)
+ pxor @XMM[8+6], @XMM[6]
+ lea 0x80(%rsp), %rax # pass key schedule
+ pxor @XMM[8+7], @XMM[7]
+ mov %edx, %r10d # pass rounds
+
+ call _bsaes_encrypt8
+
+ pxor 0x00(%rsp), @XMM[0] # ^= tweak[]
+ pxor 0x10(%rsp), @XMM[1]
+ movdqu @XMM[0], 0x00($out) # write output
+ pxor 0x20(%rsp), @XMM[4]
+ movdqu @XMM[1], 0x10($out)
+ pxor 0x30(%rsp), @XMM[6]
+ movdqu @XMM[4], 0x20($out)
+ pxor 0x40(%rsp), @XMM[3]
+ movdqu @XMM[6], 0x30($out)
+ pxor 0x50(%rsp), @XMM[7]
+ movdqu @XMM[3], 0x40($out)
+ pxor 0x60(%rsp), @XMM[2]
+ movdqu @XMM[7], 0x50($out)
+ pxor 0x70(%rsp), @XMM[5]
+ movdqu @XMM[2], 0x60($out)
+ movdqu @XMM[5], 0x70($out)
+ lea 0x80($out), $out
+
+ movdqa 0x70(%rsp), @XMM[7] # prepare next iteration tweak
+ pxor $twtmp, $twtmp
+ movdqa .Lxts_magic(%rip), $twmask
+ pcmpgtd @XMM[7], $twtmp
+ pshufd \$0x13, $twtmp, $twres
+ pxor $twtmp, $twtmp
+ paddq @XMM[7], @XMM[7] # psllq 1,$tweak
+ pand $twmask, $twres # isolate carry and residue
+ pcmpgtd @XMM[7], $twtmp # broadcast upper bits
+ pxor $twres, @XMM[7]
+
+ sub \$0x80,$len
+ jnc .Lxts_enc_loop
+
+.Lxts_enc_short:
+ add \$0x80, $len
+ jz .Lxts_enc_done
+___
+ for ($i=0;$i<7;$i++) {
+ $code.=<<___;
+ pshufd \$0x13, $twtmp, $twres
+ pxor $twtmp, $twtmp
+ movdqa @XMM[7], @XMM[$i]
+ movdqa @XMM[7], `0x10*$i`(%rsp)# save tweak[$i]
+ paddq @XMM[7], @XMM[7] # psllq 1,$tweak
+ pand $twmask, $twres # isolate carry and residue
+ pcmpgtd @XMM[7], $twtmp # broadcast upper bits
+ pxor $twres, @XMM[7]
+___
+ $code.=<<___ if ($i>=1);
+ movdqu `0x10*($i-1)`($inp), @XMM[8+$i-1]
+ cmp \$`0x10*$i`,$len
+ je .Lxts_enc_$i
+___
+ $code.=<<___ if ($i>=2);
+ pxor @XMM[8+$i-2], @XMM[$i-2]# input[] ^ tweak[]
+___
+ }
+$code.=<<___;
+ movdqu 0x60($inp), @XMM[8+6]
+ pxor @XMM[8+5], @XMM[5]
+ movdqa @XMM[7], 0x70(%rsp)
+ lea 0x70($inp), $inp
+ pxor @XMM[8+6], @XMM[6]
+ lea 0x80(%rsp), %rax # pass key schedule
+ mov %edx, %r10d # pass rounds
+
+ call _bsaes_encrypt8
+
+ pxor 0x00(%rsp), @XMM[0] # ^= tweak[]
+ pxor 0x10(%rsp), @XMM[1]
+ movdqu @XMM[0], 0x00($out) # write output
+ pxor 0x20(%rsp), @XMM[4]
+ movdqu @XMM[1], 0x10($out)
+ pxor 0x30(%rsp), @XMM[6]
+ movdqu @XMM[4], 0x20($out)
+ pxor 0x40(%rsp), @XMM[3]
+ movdqu @XMM[6], 0x30($out)
+ pxor 0x50(%rsp), @XMM[7]
+ movdqu @XMM[3], 0x40($out)
+ pxor 0x60(%rsp), @XMM[2]
+ movdqu @XMM[7], 0x50($out)
+ movdqu @XMM[2], 0x60($out)
+ lea 0x70($out), $out
+
+ movdqa 0x70(%rsp), @XMM[7] # next iteration tweak
+ jmp .Lxts_enc_done
+.align 16
+.Lxts_enc_6:
+ pxor @XMM[8+4], @XMM[4]
+ lea 0x60($inp), $inp
+ pxor @XMM[8+5], @XMM[5]
+ lea 0x80(%rsp), %rax # pass key schedule
+ mov %edx, %r10d # pass rounds
+
+ call _bsaes_encrypt8
+
+ pxor 0x00(%rsp), @XMM[0] # ^= tweak[]
+ pxor 0x10(%rsp), @XMM[1]
+ movdqu @XMM[0], 0x00($out) # write output
+ pxor 0x20(%rsp), @XMM[4]
+ movdqu @XMM[1], 0x10($out)
+ pxor 0x30(%rsp), @XMM[6]
+ movdqu @XMM[4], 0x20($out)
+ pxor 0x40(%rsp), @XMM[3]
+ movdqu @XMM[6], 0x30($out)
+ pxor 0x50(%rsp), @XMM[7]
+ movdqu @XMM[3], 0x40($out)
+ movdqu @XMM[7], 0x50($out)
+ lea 0x60($out), $out
+
+ movdqa 0x60(%rsp), @XMM[7] # next iteration tweak
+ jmp .Lxts_enc_done
+.align 16
+.Lxts_enc_5:
+ pxor @XMM[8+3], @XMM[3]
+ lea 0x50($inp), $inp
+ pxor @XMM[8+4], @XMM[4]
+ lea 0x80(%rsp), %rax # pass key schedule
+ mov %edx, %r10d # pass rounds
+
+ call _bsaes_encrypt8
+
+ pxor 0x00(%rsp), @XMM[0] # ^= tweak[]
+ pxor 0x10(%rsp), @XMM[1]
+ movdqu @XMM[0], 0x00($out) # write output
+ pxor 0x20(%rsp), @XMM[4]
+ movdqu @XMM[1], 0x10($out)
+ pxor 0x30(%rsp), @XMM[6]
+ movdqu @XMM[4], 0x20($out)
+ pxor 0x40(%rsp), @XMM[3]
+ movdqu @XMM[6], 0x30($out)
+ movdqu @XMM[3], 0x40($out)
+ lea 0x50($out), $out
+
+ movdqa 0x50(%rsp), @XMM[7] # next iteration tweak
+ jmp .Lxts_enc_done
+.align 16
+.Lxts_enc_4:
+ pxor @XMM[8+2], @XMM[2]
+ lea 0x40($inp), $inp
+ pxor @XMM[8+3], @XMM[3]
+ lea 0x80(%rsp), %rax # pass key schedule
+ mov %edx, %r10d # pass rounds
+
+ call _bsaes_encrypt8
+
+ pxor 0x00(%rsp), @XMM[0] # ^= tweak[]
+ pxor 0x10(%rsp), @XMM[1]
+ movdqu @XMM[0], 0x00($out) # write output
+ pxor 0x20(%rsp), @XMM[4]
+ movdqu @XMM[1], 0x10($out)
+ pxor 0x30(%rsp), @XMM[6]
+ movdqu @XMM[4], 0x20($out)
+ movdqu @XMM[6], 0x30($out)
+ lea 0x40($out), $out
+
+ movdqa 0x40(%rsp), @XMM[7] # next iteration tweak
+ jmp .Lxts_enc_done
+.align 16
+.Lxts_enc_3:
+ pxor @XMM[8+1], @XMM[1]
+ lea 0x30($inp), $inp
+ pxor @XMM[8+2], @XMM[2]
+ lea 0x80(%rsp), %rax # pass key schedule
+ mov %edx, %r10d # pass rounds
+
+ call _bsaes_encrypt8
+
+ pxor 0x00(%rsp), @XMM[0] # ^= tweak[]
+ pxor 0x10(%rsp), @XMM[1]
+ movdqu @XMM[0], 0x00($out) # write output
+ pxor 0x20(%rsp), @XMM[4]
+ movdqu @XMM[1], 0x10($out)
+ movdqu @XMM[4], 0x20($out)
+ lea 0x30($out), $out
+
+ movdqa 0x30(%rsp), @XMM[7] # next iteration tweak
+ jmp .Lxts_enc_done
+.align 16
+.Lxts_enc_2:
+ pxor @XMM[8+0], @XMM[0]
+ lea 0x20($inp), $inp
+ pxor @XMM[8+1], @XMM[1]
+ lea 0x80(%rsp), %rax # pass key schedule
+ mov %edx, %r10d # pass rounds
+
+ call _bsaes_encrypt8
+
+ pxor 0x00(%rsp), @XMM[0] # ^= tweak[]
+ pxor 0x10(%rsp), @XMM[1]
+ movdqu @XMM[0], 0x00($out) # write output
+ movdqu @XMM[1], 0x10($out)
+ lea 0x20($out), $out
+
+ movdqa 0x20(%rsp), @XMM[7] # next iteration tweak
+ jmp .Lxts_enc_done
+.align 16
+.Lxts_enc_1:
+ pxor @XMM[0], @XMM[8]
+ lea 0x10($inp), $inp
+ movdqa @XMM[8], 0x20(%rbp)
+ lea 0x20(%rbp), $arg1
+ lea 0x20(%rbp), $arg2
+ lea ($key), $arg3
+ call asm_AES_encrypt # doesn't touch %xmm
+ pxor 0x20(%rbp), @XMM[0] # ^= tweak[]
+ #pxor @XMM[8], @XMM[0]
+ #lea 0x80(%rsp), %rax # pass key schedule
+ #mov %edx, %r10d # pass rounds
+ #call _bsaes_encrypt8
+ #pxor 0x00(%rsp), @XMM[0] # ^= tweak[]
+ movdqu @XMM[0], 0x00($out) # write output
+ lea 0x10($out), $out
+
+ movdqa 0x10(%rsp), @XMM[7] # next iteration tweak
+
+.Lxts_enc_done:
+ and \$15, %ebx
+ jz .Lxts_enc_ret
+ mov $out, %rdx
+
+.Lxts_enc_steal:
+ movzb ($inp), %eax
+ movzb -16(%rdx), %ecx
+ lea 1($inp), $inp
+ mov %al, -16(%rdx)
+ mov %cl, 0(%rdx)
+ lea 1(%rdx), %rdx
+ sub \$1,%ebx
+ jnz .Lxts_enc_steal
+
+ movdqu -16($out), @XMM[0]
+ lea 0x20(%rbp), $arg1
+ pxor @XMM[7], @XMM[0]
+ lea 0x20(%rbp), $arg2
+ movdqa @XMM[0], 0x20(%rbp)
+ lea ($key), $arg3
+ call asm_AES_encrypt # doesn't touch %xmm
+ pxor 0x20(%rbp), @XMM[7]
+ movdqu @XMM[7], -16($out)
+
+.Lxts_enc_ret:
+ lea (%rsp), %rax
+ pxor %xmm0, %xmm0
+.Lxts_enc_bzero: # wipe key schedule [if any]
+ movdqa %xmm0, 0x00(%rax)
+ movdqa %xmm0, 0x10(%rax)
+ lea 0x20(%rax), %rax
+ cmp %rax, %rbp
+ ja .Lxts_enc_bzero
+
+ lea (%rbp),%rsp # restore %rsp
+___
+$code.=<<___ if ($win64);
+ movaps 0x40(%rbp), %xmm6
+ movaps 0x50(%rbp), %xmm7
+ movaps 0x60(%rbp), %xmm8
+ movaps 0x70(%rbp), %xmm9
+ movaps 0x80(%rbp), %xmm10
+ movaps 0x90(%rbp), %xmm11
+ movaps 0xa0(%rbp), %xmm12
+ movaps 0xb0(%rbp), %xmm13
+ movaps 0xc0(%rbp), %xmm14
+ movaps 0xd0(%rbp), %xmm15
+ lea 0xa0(%rbp), %rsp
+___
+$code.=<<___;
+ mov 0x48(%rsp), %r15
+ mov 0x50(%rsp), %r14
+ mov 0x58(%rsp), %r13
+ mov 0x60(%rsp), %r12
+ mov 0x68(%rsp), %rbx
+ mov 0x70(%rsp), %rax
+ lea 0x78(%rsp), %rsp
+ mov %rax, %rbp
+.Lxts_enc_epilogue:
+ ret
+.size bsaes_xts_encrypt,.-bsaes_xts_encrypt
+
+.globl bsaes_xts_decrypt
+.type bsaes_xts_decrypt,\@abi-omnipotent
+.align 16
+bsaes_xts_decrypt:
+ mov %rsp, %rax
+.Lxts_dec_prologue:
+ push %rbp
+ push %rbx
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ lea -0x48(%rsp), %rsp
+___
+$code.=<<___ if ($win64);
+ mov 0xa0(%rsp),$arg5 # pull key2
+ mov 0xa8(%rsp),$arg6 # pull ivp
+ lea -0xa0(%rsp), %rsp
+ movaps %xmm6, 0x40(%rsp)
+ movaps %xmm7, 0x50(%rsp)
+ movaps %xmm8, 0x60(%rsp)
+ movaps %xmm9, 0x70(%rsp)
+ movaps %xmm10, 0x80(%rsp)
+ movaps %xmm11, 0x90(%rsp)
+ movaps %xmm12, 0xa0(%rsp)
+ movaps %xmm13, 0xb0(%rsp)
+ movaps %xmm14, 0xc0(%rsp)
+ movaps %xmm15, 0xd0(%rsp)
+.Lxts_dec_body:
+___
+$code.=<<___;
+ mov %rsp, %rbp # backup %rsp
+ mov $arg1, $inp # backup arguments
+ mov $arg2, $out
+ mov $arg3, $len
+ mov $arg4, $key
+
+ lea ($arg6), $arg1
+ lea 0x20(%rbp), $arg2
+ lea ($arg5), $arg3
+ call asm_AES_encrypt # generate initial tweak
+
+ mov 240($key), %eax # rounds
+ mov $len, %rbx # backup $len
+
+ mov %eax, %edx # rounds
+ shl \$7, %rax # 128 bytes per inner round key
+ sub \$`128-32`, %rax # size of bit-sliced key schedule
+ sub %rax, %rsp
+
+ mov %rsp, %rax # pass key schedule
+ mov $key, %rcx # pass key
+ mov %edx, %r10d # pass rounds
+ call _bsaes_key_convert
+ pxor (%rsp), %xmm7 # fix up round 0 key
+ movdqa %xmm6, (%rax) # save last round key
+ movdqa %xmm7, (%rsp)
+
+ xor %eax, %eax # if ($len%16) len-=16;
+ and \$-16, $len
+ test \$15, %ebx
+ setnz %al
+ shl \$4, %rax
+ sub %rax, $len
+
+ sub \$0x80, %rsp # place for tweak[8]
+ movdqa 0x20(%rbp), @XMM[7] # initial tweak
+
+ pxor $twtmp, $twtmp
+ movdqa .Lxts_magic(%rip), $twmask
+ pcmpgtd @XMM[7], $twtmp # broadcast upper bits
+
+ sub \$0x80, $len
+ jc .Lxts_dec_short
+ jmp .Lxts_dec_loop
+
+.align 16
+.Lxts_dec_loop:
+___
+ for ($i=0;$i<7;$i++) {
+ $code.=<<___;
+ pshufd \$0x13, $twtmp, $twres
+ pxor $twtmp, $twtmp
+ movdqa @XMM[7], @XMM[$i]
+ movdqa @XMM[7], `0x10*$i`(%rsp)# save tweak[$i]
+ paddq @XMM[7], @XMM[7] # psllq 1,$tweak
+ pand $twmask, $twres # isolate carry and residue
+ pcmpgtd @XMM[7], $twtmp # broadcast upper bits
+ pxor $twres, @XMM[7]
+___
+ $code.=<<___ if ($i>=1);
+ movdqu `0x10*($i-1)`($inp), @XMM[8+$i-1]
+___
+ $code.=<<___ if ($i>=2);
+ pxor @XMM[8+$i-2], @XMM[$i-2]# input[] ^ tweak[]
+___
+ }
+$code.=<<___;
+ movdqu 0x60($inp), @XMM[8+6]
+ pxor @XMM[8+5], @XMM[5]
+ movdqu 0x70($inp), @XMM[8+7]
+ lea 0x80($inp), $inp
+ movdqa @XMM[7], 0x70(%rsp)
+ pxor @XMM[8+6], @XMM[6]
+ lea 0x80(%rsp), %rax # pass key schedule
+ pxor @XMM[8+7], @XMM[7]
+ mov %edx, %r10d # pass rounds
+
+ call _bsaes_decrypt8
+
+ pxor 0x00(%rsp), @XMM[0] # ^= tweak[]
+ pxor 0x10(%rsp), @XMM[1]
+ movdqu @XMM[0], 0x00($out) # write output
+ pxor 0x20(%rsp), @XMM[6]
+ movdqu @XMM[1], 0x10($out)
+ pxor 0x30(%rsp), @XMM[4]
+ movdqu @XMM[6], 0x20($out)
+ pxor 0x40(%rsp), @XMM[2]
+ movdqu @XMM[4], 0x30($out)
+ pxor 0x50(%rsp), @XMM[7]
+ movdqu @XMM[2], 0x40($out)
+ pxor 0x60(%rsp), @XMM[3]
+ movdqu @XMM[7], 0x50($out)
+ pxor 0x70(%rsp), @XMM[5]
+ movdqu @XMM[3], 0x60($out)
+ movdqu @XMM[5], 0x70($out)
+ lea 0x80($out), $out
+
+ movdqa 0x70(%rsp), @XMM[7] # prepare next iteration tweak
+ pxor $twtmp, $twtmp
+ movdqa .Lxts_magic(%rip), $twmask
+ pcmpgtd @XMM[7], $twtmp
+ pshufd \$0x13, $twtmp, $twres
+ pxor $twtmp, $twtmp
+ paddq @XMM[7], @XMM[7] # psllq 1,$tweak
+ pand $twmask, $twres # isolate carry and residue
+ pcmpgtd @XMM[7], $twtmp # broadcast upper bits
+ pxor $twres, @XMM[7]
+
+ sub \$0x80,$len
+ jnc .Lxts_dec_loop
+
+.Lxts_dec_short:
+ add \$0x80, $len
+ jz .Lxts_dec_done
+___
+ for ($i=0;$i<7;$i++) {
+ $code.=<<___;
+ pshufd \$0x13, $twtmp, $twres
+ pxor $twtmp, $twtmp
+ movdqa @XMM[7], @XMM[$i]
+ movdqa @XMM[7], `0x10*$i`(%rsp)# save tweak[$i]
+ paddq @XMM[7], @XMM[7] # psllq 1,$tweak
+ pand $twmask, $twres # isolate carry and residue
+ pcmpgtd @XMM[7], $twtmp # broadcast upper bits
+ pxor $twres, @XMM[7]
+___
+ $code.=<<___ if ($i>=1);
+ movdqu `0x10*($i-1)`($inp), @XMM[8+$i-1]
+ cmp \$`0x10*$i`,$len
+ je .Lxts_dec_$i
+___
+ $code.=<<___ if ($i>=2);
+ pxor @XMM[8+$i-2], @XMM[$i-2]# input[] ^ tweak[]
+___
+ }
+$code.=<<___;
+ movdqu 0x60($inp), @XMM[8+6]
+ pxor @XMM[8+5], @XMM[5]
+ movdqa @XMM[7], 0x70(%rsp)
+ lea 0x70($inp), $inp
+ pxor @XMM[8+6], @XMM[6]
+ lea 0x80(%rsp), %rax # pass key schedule
+ mov %edx, %r10d # pass rounds
+
+ call _bsaes_decrypt8
+
+ pxor 0x00(%rsp), @XMM[0] # ^= tweak[]
+ pxor 0x10(%rsp), @XMM[1]
+ movdqu @XMM[0], 0x00($out) # write output
+ pxor 0x20(%rsp), @XMM[6]
+ movdqu @XMM[1], 0x10($out)
+ pxor 0x30(%rsp), @XMM[4]
+ movdqu @XMM[6], 0x20($out)
+ pxor 0x40(%rsp), @XMM[2]
+ movdqu @XMM[4], 0x30($out)
+ pxor 0x50(%rsp), @XMM[7]
+ movdqu @XMM[2], 0x40($out)
+ pxor 0x60(%rsp), @XMM[3]
+ movdqu @XMM[7], 0x50($out)
+ movdqu @XMM[3], 0x60($out)
+ lea 0x70($out), $out
+
+ movdqa 0x70(%rsp), @XMM[7] # next iteration tweak
+ jmp .Lxts_dec_done
+.align 16
+.Lxts_dec_6:
+ pxor @XMM[8+4], @XMM[4]
+ lea 0x60($inp), $inp
+ pxor @XMM[8+5], @XMM[5]
+ lea 0x80(%rsp), %rax # pass key schedule
+ mov %edx, %r10d # pass rounds
+
+ call _bsaes_decrypt8
+
+ pxor 0x00(%rsp), @XMM[0] # ^= tweak[]
+ pxor 0x10(%rsp), @XMM[1]
+ movdqu @XMM[0], 0x00($out) # write output
+ pxor 0x20(%rsp), @XMM[6]
+ movdqu @XMM[1], 0x10($out)
+ pxor 0x30(%rsp), @XMM[4]
+ movdqu @XMM[6], 0x20($out)
+ pxor 0x40(%rsp), @XMM[2]
+ movdqu @XMM[4], 0x30($out)
+ pxor 0x50(%rsp), @XMM[7]
+ movdqu @XMM[2], 0x40($out)
+ movdqu @XMM[7], 0x50($out)
+ lea 0x60($out), $out
+
+ movdqa 0x60(%rsp), @XMM[7] # next iteration tweak
+ jmp .Lxts_dec_done
+.align 16
+.Lxts_dec_5:
+ pxor @XMM[8+3], @XMM[3]
+ lea 0x50($inp), $inp
+ pxor @XMM[8+4], @XMM[4]
+ lea 0x80(%rsp), %rax # pass key schedule
+ mov %edx, %r10d # pass rounds
+
+ call _bsaes_decrypt8
+
+ pxor 0x00(%rsp), @XMM[0] # ^= tweak[]
+ pxor 0x10(%rsp), @XMM[1]
+ movdqu @XMM[0], 0x00($out) # write output
+ pxor 0x20(%rsp), @XMM[6]
+ movdqu @XMM[1], 0x10($out)
+ pxor 0x30(%rsp), @XMM[4]
+ movdqu @XMM[6], 0x20($out)
+ pxor 0x40(%rsp), @XMM[2]
+ movdqu @XMM[4], 0x30($out)
+ movdqu @XMM[2], 0x40($out)
+ lea 0x50($out), $out
+
+ movdqa 0x50(%rsp), @XMM[7] # next iteration tweak
+ jmp .Lxts_dec_done
+.align 16
+.Lxts_dec_4:
+ pxor @XMM[8+2], @XMM[2]
+ lea 0x40($inp), $inp
+ pxor @XMM[8+3], @XMM[3]
+ lea 0x80(%rsp), %rax # pass key schedule
+ mov %edx, %r10d # pass rounds
+
+ call _bsaes_decrypt8
+
+ pxor 0x00(%rsp), @XMM[0] # ^= tweak[]
+ pxor 0x10(%rsp), @XMM[1]
+ movdqu @XMM[0], 0x00($out) # write output
+ pxor 0x20(%rsp), @XMM[6]
+ movdqu @XMM[1], 0x10($out)
+ pxor 0x30(%rsp), @XMM[4]
+ movdqu @XMM[6], 0x20($out)
+ movdqu @XMM[4], 0x30($out)
+ lea 0x40($out), $out
+
+ movdqa 0x40(%rsp), @XMM[7] # next iteration tweak
+ jmp .Lxts_dec_done
+.align 16
+.Lxts_dec_3:
+ pxor @XMM[8+1], @XMM[1]
+ lea 0x30($inp), $inp
+ pxor @XMM[8+2], @XMM[2]
+ lea 0x80(%rsp), %rax # pass key schedule
+ mov %edx, %r10d # pass rounds
+
+ call _bsaes_decrypt8
+
+ pxor 0x00(%rsp), @XMM[0] # ^= tweak[]
+ pxor 0x10(%rsp), @XMM[1]
+ movdqu @XMM[0], 0x00($out) # write output
+ pxor 0x20(%rsp), @XMM[6]
+ movdqu @XMM[1], 0x10($out)
+ movdqu @XMM[6], 0x20($out)
+ lea 0x30($out), $out
+
+ movdqa 0x30(%rsp), @XMM[7] # next iteration tweak
+ jmp .Lxts_dec_done
+.align 16
+.Lxts_dec_2:
+ pxor @XMM[8+0], @XMM[0]
+ lea 0x20($inp), $inp
+ pxor @XMM[8+1], @XMM[1]
+ lea 0x80(%rsp), %rax # pass key schedule
+ mov %edx, %r10d # pass rounds
+
+ call _bsaes_decrypt8
+
+ pxor 0x00(%rsp), @XMM[0] # ^= tweak[]
+ pxor 0x10(%rsp), @XMM[1]
+ movdqu @XMM[0], 0x00($out) # write output
+ movdqu @XMM[1], 0x10($out)
+ lea 0x20($out), $out
+
+ movdqa 0x20(%rsp), @XMM[7] # next iteration tweak
+ jmp .Lxts_dec_done
+.align 16
+.Lxts_dec_1:
+ pxor @XMM[0], @XMM[8]
+ lea 0x10($inp), $inp
+ movdqa @XMM[8], 0x20(%rbp)
+ lea 0x20(%rbp), $arg1
+ lea 0x20(%rbp), $arg2
+ lea ($key), $arg3
+ call asm_AES_decrypt # doesn't touch %xmm
+ pxor 0x20(%rbp), @XMM[0] # ^= tweak[]
+ #pxor @XMM[8], @XMM[0]
+ #lea 0x80(%rsp), %rax # pass key schedule
+ #mov %edx, %r10d # pass rounds
+ #call _bsaes_decrypt8
+ #pxor 0x00(%rsp), @XMM[0] # ^= tweak[]
+ movdqu @XMM[0], 0x00($out) # write output
+ lea 0x10($out), $out
+
+ movdqa 0x10(%rsp), @XMM[7] # next iteration tweak
+
+.Lxts_dec_done:
+ and \$15, %ebx
+ jz .Lxts_dec_ret
+
+ pxor $twtmp, $twtmp
+ movdqa .Lxts_magic(%rip), $twmask
+ pcmpgtd @XMM[7], $twtmp
+ pshufd \$0x13, $twtmp, $twres
+ movdqa @XMM[7], @XMM[6]
+ paddq @XMM[7], @XMM[7] # psllq 1,$tweak
+ pand $twmask, $twres # isolate carry and residue
+ movdqu ($inp), @XMM[0]
+ pxor $twres, @XMM[7]
+
+ lea 0x20(%rbp), $arg1
+ pxor @XMM[7], @XMM[0]
+ lea 0x20(%rbp), $arg2
+ movdqa @XMM[0], 0x20(%rbp)
+ lea ($key), $arg3
+ call asm_AES_decrypt # doesn't touch %xmm
+ pxor 0x20(%rbp), @XMM[7]
+ mov $out, %rdx
+ movdqu @XMM[7], ($out)
+
+.Lxts_dec_steal:
+ movzb 16($inp), %eax
+ movzb (%rdx), %ecx
+ lea 1($inp), $inp
+ mov %al, (%rdx)
+ mov %cl, 16(%rdx)
+ lea 1(%rdx), %rdx
+ sub \$1,%ebx
+ jnz .Lxts_dec_steal
+
+ movdqu ($out), @XMM[0]
+ lea 0x20(%rbp), $arg1
+ pxor @XMM[6], @XMM[0]
+ lea 0x20(%rbp), $arg2
+ movdqa @XMM[0], 0x20(%rbp)
+ lea ($key), $arg3
+ call asm_AES_decrypt # doesn't touch %xmm
+ pxor 0x20(%rbp), @XMM[6]
+ movdqu @XMM[6], ($out)
+
+.Lxts_dec_ret:
+ lea (%rsp), %rax
+ pxor %xmm0, %xmm0
+.Lxts_dec_bzero: # wipe key schedule [if any]
+ movdqa %xmm0, 0x00(%rax)
+ movdqa %xmm0, 0x10(%rax)
+ lea 0x20(%rax), %rax
+ cmp %rax, %rbp
+ ja .Lxts_dec_bzero
+
+ lea (%rbp),%rsp # restore %rsp
+___
+$code.=<<___ if ($win64);
+ movaps 0x40(%rbp), %xmm6
+ movaps 0x50(%rbp), %xmm7
+ movaps 0x60(%rbp), %xmm8
+ movaps 0x70(%rbp), %xmm9
+ movaps 0x80(%rbp), %xmm10
+ movaps 0x90(%rbp), %xmm11
+ movaps 0xa0(%rbp), %xmm12
+ movaps 0xb0(%rbp), %xmm13
+ movaps 0xc0(%rbp), %xmm14
+ movaps 0xd0(%rbp), %xmm15
+ lea 0xa0(%rbp), %rsp
+___
+$code.=<<___;
+ mov 0x48(%rsp), %r15
+ mov 0x50(%rsp), %r14
+ mov 0x58(%rsp), %r13
+ mov 0x60(%rsp), %r12
+ mov 0x68(%rsp), %rbx
+ mov 0x70(%rsp), %rax
+ lea 0x78(%rsp), %rsp
+ mov %rax, %rbp
+.Lxts_dec_epilogue:
+ ret
+.size bsaes_xts_decrypt,.-bsaes_xts_decrypt
+___
+}
+$code.=<<___;
+.type _bsaes_const,\@object
+.align 64
+_bsaes_const:
+.LM0ISR: # InvShiftRows constants
+ .quad 0x0a0e0206070b0f03, 0x0004080c0d010509
+.LISRM0:
+ .quad 0x01040b0e0205080f, 0x0306090c00070a0d
+.LISR:
+ .quad 0x0504070602010003, 0x0f0e0d0c080b0a09
+.LBS0: # bit-slice constants
+ .quad 0x5555555555555555, 0x5555555555555555
+.LBS1:
+ .quad 0x3333333333333333, 0x3333333333333333
+.LBS2:
+ .quad 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
+.LSR: # shiftrows constants
+ .quad 0x0504070600030201, 0x0f0e0d0c0a09080b
+.LSRM0:
+ .quad 0x0304090e00050a0f, 0x01060b0c0207080d
+.LM0SR:
+ .quad 0x0a0e02060f03070b, 0x0004080c05090d01
+.LSWPUP: # byte-swap upper dword
+ .quad 0x0706050403020100, 0x0c0d0e0f0b0a0908
+.LSWPUPM0SR:
+ .quad 0x0a0d02060c03070b, 0x0004080f05090e01
+.LADD1: # counter increment constants
+ .quad 0x0000000000000000, 0x0000000100000000
+.LADD2:
+ .quad 0x0000000000000000, 0x0000000200000000
+.LADD3:
+ .quad 0x0000000000000000, 0x0000000300000000
+.LADD4:
+ .quad 0x0000000000000000, 0x0000000400000000
+.LADD5:
+ .quad 0x0000000000000000, 0x0000000500000000
+.LADD6:
+ .quad 0x0000000000000000, 0x0000000600000000
+.LADD7:
+ .quad 0x0000000000000000, 0x0000000700000000
+.LADD8:
+ .quad 0x0000000000000000, 0x0000000800000000
+.Lxts_magic:
+ .long 0x87,0,1,0
+.Lmasks:
+ .quad 0x0101010101010101, 0x0101010101010101
+ .quad 0x0202020202020202, 0x0202020202020202
+ .quad 0x0404040404040404, 0x0404040404040404
+ .quad 0x0808080808080808, 0x0808080808080808
+.LM0:
+ .quad 0x02060a0e03070b0f, 0x0004080c0105090d
+.L63:
+ .quad 0x6363636363636363, 0x6363636363636363
+.asciz "Bit-sliced AES for x86_64/SSSE3, Emilia Käsper, Peter Schwabe, Andy Polyakov"
+.align 64
+.size _bsaes_const,.-_bsaes_const
+___
+
+# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
+# CONTEXT *context,DISPATCHER_CONTEXT *disp)
+if ($win64) {
+$rec="%rcx";
+$frame="%rdx";
+$context="%r8";
+$disp="%r9";
+
+$code.=<<___;
+.extern __imp_RtlVirtualUnwind
+.type se_handler,\@abi-omnipotent
+.align 16
+se_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 120($context),%rax # pull context->Rax
+ mov 248($context),%rbx # pull context->Rip
+
+ mov 8($disp),%rsi # disp->ImageBase
+ mov 56($disp),%r11 # disp->HandlerData
+
+ mov 0(%r11),%r10d # HandlerData[0]
+ lea (%rsi,%r10),%r10 # prologue label
+ cmp %r10,%rbx # context->Rip<prologue label
+ jb .Lin_prologue
+
+ mov 152($context),%rax # pull context->Rsp
+
+ mov 4(%r11),%r10d # HandlerData[1]
+ lea (%rsi,%r10),%r10 # epilogue label
+ cmp %r10,%rbx # context->Rip>=epilogue label
+ jae .Lin_prologue
+
+ mov 160($context),%rax # pull context->Rbp
+
+ lea 0x40(%rax),%rsi # %xmm save area
+ lea 512($context),%rdi # &context.Xmm6
+ mov \$20,%ecx # 10*sizeof(%xmm0)/sizeof(%rax)
+ .long 0xa548f3fc # cld; rep movsq
+ lea 0xa0(%rax),%rax # adjust stack pointer
+
+ mov 0x70(%rax),%rbp
+ mov 0x68(%rax),%rbx
+ mov 0x60(%rax),%r12
+ mov 0x58(%rax),%r13
+ mov 0x50(%rax),%r14
+ mov 0x48(%rax),%r15
+ lea 0x78(%rax),%rax # adjust stack pointer
+ mov %rbx,144($context) # restore context->Rbx
+ mov %rbp,160($context) # restore context->Rbp
+ mov %r12,216($context) # restore context->R12
+ mov %r13,224($context) # restore context->R13
+ mov %r14,232($context) # restore context->R14
+ mov %r15,240($context) # restore context->R15
+
+.Lin_prologue:
+ mov %rax,152($context) # restore context->Rsp
+
+ mov 40($disp),%rdi # disp->ContextRecord
+ mov $context,%rsi # context
+ mov \$`1232/8`,%ecx # sizeof(CONTEXT)
+ .long 0xa548f3fc # cld; rep movsq
+
+ mov $disp,%rsi
+ xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER
+ mov 8(%rsi),%rdx # arg2, disp->ImageBase
+ mov 0(%rsi),%r8 # arg3, disp->ControlPc
+ mov 16(%rsi),%r9 # arg4, disp->FunctionEntry
+ mov 40(%rsi),%r10 # disp->ContextRecord
+ lea 56(%rsi),%r11 # &disp->HandlerData
+ lea 24(%rsi),%r12 # &disp->EstablisherFrame
+ mov %r10,32(%rsp) # arg5
+ mov %r11,40(%rsp) # arg6
+ mov %r12,48(%rsp) # arg7
+ mov %rcx,56(%rsp) # arg8, (NULL)
+ call *__imp_RtlVirtualUnwind(%rip)
+
+ mov \$1,%eax # ExceptionContinueSearch
+ add \$64,%rsp
+ popfq
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+ pop %rdi
+ pop %rsi
+ ret
+.size se_handler,.-se_handler
+
+.section .pdata
+.align 4
+___
+$code.=<<___ if ($ecb);
+ .rva .Lecb_enc_prologue
+ .rva .Lecb_enc_epilogue
+ .rva .Lecb_enc_info
+
+ .rva .Lecb_dec_prologue
+ .rva .Lecb_dec_epilogue
+ .rva .Lecb_dec_info
+___
+$code.=<<___;
+ .rva .Lcbc_dec_prologue
+ .rva .Lcbc_dec_epilogue
+ .rva .Lcbc_dec_info
+
+ .rva .Lctr_enc_prologue
+ .rva .Lctr_enc_epilogue
+ .rva .Lctr_enc_info
+
+ .rva .Lxts_enc_prologue
+ .rva .Lxts_enc_epilogue
+ .rva .Lxts_enc_info
+
+ .rva .Lxts_dec_prologue
+ .rva .Lxts_dec_epilogue
+ .rva .Lxts_dec_info
+
+.section .xdata
+.align 8
+___
+$code.=<<___ if ($ecb);
+.Lecb_enc_info:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lecb_enc_body,.Lecb_enc_epilogue # HandlerData[]
+.Lecb_dec_info:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lecb_dec_body,.Lecb_dec_epilogue # HandlerData[]
+___
+$code.=<<___;
+.Lcbc_dec_info:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lcbc_dec_body,.Lcbc_dec_epilogue # HandlerData[]
+.Lctr_enc_info:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lctr_enc_body,.Lctr_enc_epilogue # HandlerData[]
+.Lxts_enc_info:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lxts_enc_body,.Lxts_enc_epilogue # HandlerData[]
+.Lxts_dec_info:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lxts_dec_body,.Lxts_dec_epilogue # HandlerData[]
+___
+}
+
+$code =~ s/\`([^\`]*)\`/eval($1)/gem;
+
+print $code;
+
+close STDOUT;
diff --git a/crypto/aes/asm/vpaes-x86.pl b/crypto/aes/asm/vpaes-x86.pl
new file mode 100644
index 0000000..bacf42c
--- /dev/null
+++ b/crypto/aes/asm/vpaes-x86.pl
@@ -0,0 +1,902 @@
+#!/usr/bin/env perl
+
+######################################################################
+## Constant-time SSSE3 AES core implementation.
+## version 0.1
+##
+## By Mike Hamburg (Stanford University), 2009
+## Public domain.
+##
+## For details see http://shiftleft.org/papers/vector_aes/ and
+## http://crypto.stanford.edu/vpaes/.
+
+######################################################################
+# September 2011.
+#
+# Port vpaes-x86_64.pl as 32-bit "almost" drop-in replacement for
+# aes-586.pl. "Almost" refers to the fact that AES_cbc_encrypt
+# doesn't handle partial vectors (doesn't have to if called from
+# EVP only). "Drop-in" implies that this module doesn't share key
+# schedule structure with the original nor does it make assumption
+# about its alignment...
+#
+# Performance summary. aes-586.pl column lists large-block CBC
+# encrypt/decrypt/with-hyper-threading-off(*) results in cycles per
+# byte processed with 128-bit key, and vpaes-x86.pl column - [also
+# large-block CBC] encrypt/decrypt.
+#
+# aes-586.pl vpaes-x86.pl
+#
+# Core 2(**) 28.1/41.4/18.3 21.9/25.2(***)
+# Nehalem 27.9/40.4/18.1 10.2/11.9
+# Atom 70.7/92.1/60.1 61.1/75.4(***)
+#
+# (*) "Hyper-threading" in the context refers rather to cache shared
+# among multiple cores, than to specifically Intel HTT. As vast
+# majority of contemporary cores share cache, slower code path
+# is common place. In other words "with-hyper-threading-off"
+# results are presented mostly for reference purposes.
+#
+# (**) "Core 2" refers to initial 65nm design, a.k.a. Conroe.
+#
+# (***) Less impressive improvement on Core 2 and Atom is due to slow
+# pshufb, yet it's respectable +28%/64% improvement on Core 2
+# and +15% on Atom (as implied, over "hyper-threading-safe"
+# code path).
+#
+# <appro@openssl.org>
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+push(@INC,"${dir}","${dir}../../perlasm");
+require "x86asm.pl";
+
+&asm_init($ARGV[0],"vpaes-x86.pl",$x86only = $ARGV[$#ARGV] eq "386");
+
+$PREFIX="vpaes";
+
+my ($round, $base, $magic, $key, $const, $inp, $out)=
+ ("eax", "ebx", "ecx", "edx","ebp", "esi","edi");
+
+&static_label("_vpaes_consts");
+&static_label("_vpaes_schedule_low_round");
+
+&set_label("_vpaes_consts",64);
+$k_inv=-0x30; # inv, inva
+ &data_word(0x0D080180,0x0E05060F,0x0A0B0C02,0x04070309);
+ &data_word(0x0F0B0780,0x01040A06,0x02050809,0x030D0E0C);
+
+$k_s0F=-0x10; # s0F
+ &data_word(0x0F0F0F0F,0x0F0F0F0F,0x0F0F0F0F,0x0F0F0F0F);
+
+$k_ipt=0x00; # input transform (lo, hi)
+ &data_word(0x5A2A7000,0xC2B2E898,0x52227808,0xCABAE090);
+ &data_word(0x317C4D00,0x4C01307D,0xB0FDCC81,0xCD80B1FC);
+
+$k_sb1=0x20; # sb1u, sb1t
+ &data_word(0xCB503E00,0xB19BE18F,0x142AF544,0xA5DF7A6E);
+ &data_word(0xFAE22300,0x3618D415,0x0D2ED9EF,0x3BF7CCC1);
+$k_sb2=0x40; # sb2u, sb2t
+ &data_word(0x0B712400,0xE27A93C6,0xBC982FCD,0x5EB7E955);
+ &data_word(0x0AE12900,0x69EB8840,0xAB82234A,0xC2A163C8);
+$k_sbo=0x60; # sbou, sbot
+ &data_word(0x6FBDC700,0xD0D26D17,0xC502A878,0x15AABF7A);
+ &data_word(0x5FBB6A00,0xCFE474A5,0x412B35FA,0x8E1E90D1);
+
+$k_mc_forward=0x80; # mc_forward
+ &data_word(0x00030201,0x04070605,0x080B0A09,0x0C0F0E0D);
+ &data_word(0x04070605,0x080B0A09,0x0C0F0E0D,0x00030201);
+ &data_word(0x080B0A09,0x0C0F0E0D,0x00030201,0x04070605);
+ &data_word(0x0C0F0E0D,0x00030201,0x04070605,0x080B0A09);
+
+$k_mc_backward=0xc0; # mc_backward
+ &data_word(0x02010003,0x06050407,0x0A09080B,0x0E0D0C0F);
+ &data_word(0x0E0D0C0F,0x02010003,0x06050407,0x0A09080B);
+ &data_word(0x0A09080B,0x0E0D0C0F,0x02010003,0x06050407);
+ &data_word(0x06050407,0x0A09080B,0x0E0D0C0F,0x02010003);
+
+$k_sr=0x100; # sr
+ &data_word(0x03020100,0x07060504,0x0B0A0908,0x0F0E0D0C);
+ &data_word(0x0F0A0500,0x030E0904,0x07020D08,0x0B06010C);
+ &data_word(0x0B020900,0x0F060D04,0x030A0108,0x070E050C);
+ &data_word(0x070A0D00,0x0B0E0104,0x0F020508,0x0306090C);
+
+$k_rcon=0x140; # rcon
+ &data_word(0xAF9DEEB6,0x1F8391B9,0x4D7C7D81,0x702A9808);
+
+$k_s63=0x150; # s63: all equal to 0x63 transformed
+ &data_word(0x5B5B5B5B,0x5B5B5B5B,0x5B5B5B5B,0x5B5B5B5B);
+
+$k_opt=0x160; # output transform
+ &data_word(0xD6B66000,0xFF9F4929,0xDEBE6808,0xF7974121);
+ &data_word(0x50BCEC00,0x01EDBD51,0xB05C0CE0,0xE10D5DB1);
+
+$k_deskew=0x180; # deskew tables: inverts the sbox's "skew"
+ &data_word(0x47A4E300,0x07E4A340,0x5DBEF91A,0x1DFEB95A);
+ &data_word(0x83EA6900,0x5F36B5DC,0xF49D1E77,0x2841C2AB);
+##
+## Decryption stuff
+## Key schedule constants
+##
+$k_dksd=0x1a0; # decryption key schedule: invskew x*D
+ &data_word(0xA3E44700,0xFEB91A5D,0x5A1DBEF9,0x0740E3A4);
+ &data_word(0xB5368300,0x41C277F4,0xAB289D1E,0x5FDC69EA);
+$k_dksb=0x1c0; # decryption key schedule: invskew x*B
+ &data_word(0x8550D500,0x9A4FCA1F,0x1CC94C99,0x03D65386);
+ &data_word(0xB6FC4A00,0x115BEDA7,0x7E3482C8,0xD993256F);
+$k_dkse=0x1e0; # decryption key schedule: invskew x*E + 0x63
+ &data_word(0x1FC9D600,0xD5031CCA,0x994F5086,0x53859A4C);
+ &data_word(0x4FDC7BE8,0xA2319605,0x20B31487,0xCD5EF96A);
+$k_dks9=0x200; # decryption key schedule: invskew x*9
+ &data_word(0x7ED9A700,0xB6116FC8,0x82255BFC,0x4AED9334);
+ &data_word(0x27143300,0x45765162,0xE9DAFDCE,0x8BB89FAC);
+
+##
+## Decryption stuff
+## Round function constants
+##
+$k_dipt=0x220; # decryption input transform
+ &data_word(0x0B545F00,0x0F505B04,0x114E451A,0x154A411E);
+ &data_word(0x60056500,0x86E383E6,0xF491F194,0x12771772);
+
+$k_dsb9=0x240; # decryption sbox output *9*u, *9*t
+ &data_word(0x9A86D600,0x851C0353,0x4F994CC9,0xCAD51F50);
+ &data_word(0xECD74900,0xC03B1789,0xB2FBA565,0x725E2C9E);
+$k_dsbd=0x260; # decryption sbox output *D*u, *D*t
+ &data_word(0xE6B1A200,0x7D57CCDF,0x882A4439,0xF56E9B13);
+ &data_word(0x24C6CB00,0x3CE2FAF7,0x15DEEFD3,0x2931180D);
+$k_dsbb=0x280; # decryption sbox output *B*u, *B*t
+ &data_word(0x96B44200,0xD0226492,0xB0F2D404,0x602646F6);
+ &data_word(0xCD596700,0xC19498A6,0x3255AA6B,0xF3FF0C3E);
+$k_dsbe=0x2a0; # decryption sbox output *E*u, *E*t
+ &data_word(0x26D4D000,0x46F29296,0x64B4F6B0,0x22426004);
+ &data_word(0xFFAAC100,0x0C55A6CD,0x98593E32,0x9467F36B);
+$k_dsbo=0x2c0; # decryption sbox final output
+ &data_word(0x7EF94000,0x1387EA53,0xD4943E2D,0xC7AA6DB9);
+ &data_word(0x93441D00,0x12D7560F,0xD8C58E9C,0xCA4B8159);
+&asciz ("Vector Permutation AES for x86/SSSE3, Mike Hamburg (Stanford University)");
+&align (64);
+
+&function_begin_B("_vpaes_preheat");
+ &add ($const,&DWP(0,"esp"));
+ &movdqa ("xmm7",&QWP($k_inv,$const));
+ &movdqa ("xmm6",&QWP($k_s0F,$const));
+ &ret ();
+&function_end_B("_vpaes_preheat");
+
+##
+## _aes_encrypt_core
+##
+## AES-encrypt %xmm0.
+##
+## Inputs:
+## %xmm0 = input
+## %xmm6-%xmm7 as in _vpaes_preheat
+## (%edx) = scheduled keys
+##
+## Output in %xmm0
+## Clobbers %xmm1-%xmm5, %eax, %ebx, %ecx, %edx
+##
+##
+&function_begin_B("_vpaes_encrypt_core");
+ &mov ($magic,16);
+ &mov ($round,&DWP(240,$key));
+ &movdqa ("xmm1","xmm6")
+ &movdqa ("xmm2",&QWP($k_ipt,$const));
+ &pandn ("xmm1","xmm0");
+ &pand ("xmm0","xmm6");
+ &movdqu ("xmm5",&QWP(0,$key));
+ &pshufb ("xmm2","xmm0");
+ &movdqa ("xmm0",&QWP($k_ipt+16,$const));
+ &pxor ("xmm2","xmm5");
+ &psrld ("xmm1",4);
+ &add ($key,16);
+ &pshufb ("xmm0","xmm1");
+ &lea ($base,&DWP($k_mc_backward,$const));
+ &pxor ("xmm0","xmm2");
+ &jmp (&label("enc_entry"));
+
+
+&set_label("enc_loop",16);
+ # middle of middle round
+ &movdqa ("xmm4",&QWP($k_sb1,$const)); # 4 : sb1u
+ &movdqa ("xmm0",&QWP($k_sb1+16,$const));# 0 : sb1t
+ &pshufb ("xmm4","xmm2"); # 4 = sb1u
+ &pshufb ("xmm0","xmm3"); # 0 = sb1t
+ &pxor ("xmm4","xmm5"); # 4 = sb1u + k
+ &movdqa ("xmm5",&QWP($k_sb2,$const)); # 4 : sb2u
+ &pxor ("xmm0","xmm4"); # 0 = A
+ &movdqa ("xmm1",&QWP(-0x40,$base,$magic));# .Lk_mc_forward[]
+ &pshufb ("xmm5","xmm2"); # 4 = sb2u
+ &movdqa ("xmm2",&QWP($k_sb2+16,$const));# 2 : sb2t
+ &movdqa ("xmm4",&QWP(0,$base,$magic)); # .Lk_mc_backward[]
+ &pshufb ("xmm2","xmm3"); # 2 = sb2t
+ &movdqa ("xmm3","xmm0"); # 3 = A
+ &pxor ("xmm2","xmm5"); # 2 = 2A
+ &pshufb ("xmm0","xmm1"); # 0 = B
+ &add ($key,16); # next key
+ &pxor ("xmm0","xmm2"); # 0 = 2A+B
+ &pshufb ("xmm3","xmm4"); # 3 = D
+ &add ($magic,16); # next mc
+ &pxor ("xmm3","xmm0"); # 3 = 2A+B+D
+ &pshufb ("xmm0","xmm1"); # 0 = 2B+C
+ &and ($magic,0x30); # ... mod 4
+ &sub ($round,1); # nr--
+ &pxor ("xmm0","xmm3"); # 0 = 2A+3B+C+D
+
+&set_label("enc_entry");
+ # top of round
+ &movdqa ("xmm1","xmm6"); # 1 : i
+ &movdqa ("xmm5",&QWP($k_inv+16,$const));# 2 : a/k
+ &pandn ("xmm1","xmm0"); # 1 = i<<4
+ &psrld ("xmm1",4); # 1 = i
+ &pand ("xmm0","xmm6"); # 0 = k
+ &pshufb ("xmm5","xmm0"); # 2 = a/k
+ &movdqa ("xmm3","xmm7"); # 3 : 1/i
+ &pxor ("xmm0","xmm1"); # 0 = j
+ &pshufb ("xmm3","xmm1"); # 3 = 1/i
+ &movdqa ("xmm4","xmm7"); # 4 : 1/j
+ &pxor ("xmm3","xmm5"); # 3 = iak = 1/i + a/k
+ &pshufb ("xmm4","xmm0"); # 4 = 1/j
+ &movdqa ("xmm2","xmm7"); # 2 : 1/iak
+ &pxor ("xmm4","xmm5"); # 4 = jak = 1/j + a/k
+ &pshufb ("xmm2","xmm3"); # 2 = 1/iak
+ &movdqa ("xmm3","xmm7"); # 3 : 1/jak
+ &pxor ("xmm2","xmm0"); # 2 = io
+ &pshufb ("xmm3","xmm4"); # 3 = 1/jak
+ &movdqu ("xmm5",&QWP(0,$key));
+ &pxor ("xmm3","xmm1"); # 3 = jo
+ &jnz (&label("enc_loop"));
+
+ # middle of last round
+ &movdqa ("xmm4",&QWP($k_sbo,$const)); # 3 : sbou .Lk_sbo
+ &movdqa ("xmm0",&QWP($k_sbo+16,$const));# 3 : sbot .Lk_sbo+16
+ &pshufb ("xmm4","xmm2"); # 4 = sbou
+ &pxor ("xmm4","xmm5"); # 4 = sb1u + k
+ &pshufb ("xmm0","xmm3"); # 0 = sb1t
+ &movdqa ("xmm1",&QWP(0x40,$base,$magic));# .Lk_sr[]
+ &pxor ("xmm0","xmm4"); # 0 = A
+ &pshufb ("xmm0","xmm1");
+ &ret ();
+&function_end_B("_vpaes_encrypt_core");
+
+##
+## Decryption core
+##
+## Same API as encryption core.
+##
+&function_begin_B("_vpaes_decrypt_core");
+ &lea ($base,&DWP($k_dsbd,$const));
+ &mov ($round,&DWP(240,$key));
+ &movdqa ("xmm1","xmm6");
+ &movdqa ("xmm2",&QWP($k_dipt-$k_dsbd,$base));
+ &pandn ("xmm1","xmm0");
+ &mov ($magic,$round);
+ &psrld ("xmm1",4)
+ &movdqu ("xmm5",&QWP(0,$key));
+ &shl ($magic,4);
+ &pand ("xmm0","xmm6");
+ &pshufb ("xmm2","xmm0");
+ &movdqa ("xmm0",&QWP($k_dipt-$k_dsbd+16,$base));
+ &xor ($magic,0x30);
+ &pshufb ("xmm0","xmm1");
+ &and ($magic,0x30);
+ &pxor ("xmm2","xmm5");
+ &movdqa ("xmm5",&QWP($k_mc_forward+48,$const));
+ &pxor ("xmm0","xmm2");
+ &add ($key,16);
+ &lea ($magic,&DWP($k_sr-$k_dsbd,$base,$magic));
+ &jmp (&label("dec_entry"));
+
+&set_label("dec_loop",16);
+##
+## Inverse mix columns
+##
+ &movdqa ("xmm4",&QWP(-0x20,$base)); # 4 : sb9u
+ &movdqa ("xmm1",&QWP(-0x10,$base)); # 0 : sb9t
+ &pshufb ("xmm4","xmm2"); # 4 = sb9u
+ &pshufb ("xmm1","xmm3"); # 0 = sb9t
+ &pxor ("xmm0","xmm4");
+ &movdqa ("xmm4",&QWP(0,$base)); # 4 : sbdu
+ &pxor ("xmm0","xmm1"); # 0 = ch
+ &movdqa ("xmm1",&QWP(0x10,$base)); # 0 : sbdt
+
+ &pshufb ("xmm4","xmm2"); # 4 = sbdu
+ &pshufb ("xmm0","xmm5"); # MC ch
+ &pshufb ("xmm1","xmm3"); # 0 = sbdt
+ &pxor ("xmm0","xmm4"); # 4 = ch
+ &movdqa ("xmm4",&QWP(0x20,$base)); # 4 : sbbu
+ &pxor ("xmm0","xmm1"); # 0 = ch
+ &movdqa ("xmm1",&QWP(0x30,$base)); # 0 : sbbt
+
+ &pshufb ("xmm4","xmm2"); # 4 = sbbu
+ &pshufb ("xmm0","xmm5"); # MC ch
+ &pshufb ("xmm1","xmm3"); # 0 = sbbt
+ &pxor ("xmm0","xmm4"); # 4 = ch
+ &movdqa ("xmm4",&QWP(0x40,$base)); # 4 : sbeu
+ &pxor ("xmm0","xmm1"); # 0 = ch
+ &movdqa ("xmm1",&QWP(0x50,$base)); # 0 : sbet
+
+ &pshufb ("xmm4","xmm2"); # 4 = sbeu
+ &pshufb ("xmm0","xmm5"); # MC ch
+ &pshufb ("xmm1","xmm3"); # 0 = sbet
+ &pxor ("xmm0","xmm4"); # 4 = ch
+ &add ($key,16); # next round key
+ &palignr("xmm5","xmm5",12);
+ &pxor ("xmm0","xmm1"); # 0 = ch
+ &sub ($round,1); # nr--
+
+&set_label("dec_entry");
+ # top of round
+ &movdqa ("xmm1","xmm6"); # 1 : i
+ &movdqa ("xmm2",&QWP($k_inv+16,$const));# 2 : a/k
+ &pandn ("xmm1","xmm0"); # 1 = i<<4
+ &pand ("xmm0","xmm6"); # 0 = k
+ &psrld ("xmm1",4); # 1 = i
+ &pshufb ("xmm2","xmm0"); # 2 = a/k
+ &movdqa ("xmm3","xmm7"); # 3 : 1/i
+ &pxor ("xmm0","xmm1"); # 0 = j
+ &pshufb ("xmm3","xmm1"); # 3 = 1/i
+ &movdqa ("xmm4","xmm7"); # 4 : 1/j
+ &pxor ("xmm3","xmm2"); # 3 = iak = 1/i + a/k
+ &pshufb ("xmm4","xmm0"); # 4 = 1/j
+ &pxor ("xmm4","xmm2"); # 4 = jak = 1/j + a/k
+ &movdqa ("xmm2","xmm7"); # 2 : 1/iak
+ &pshufb ("xmm2","xmm3"); # 2 = 1/iak
+ &movdqa ("xmm3","xmm7"); # 3 : 1/jak
+ &pxor ("xmm2","xmm0"); # 2 = io
+ &pshufb ("xmm3","xmm4"); # 3 = 1/jak
+ &movdqu ("xmm0",&QWP(0,$key));
+ &pxor ("xmm3","xmm1"); # 3 = jo
+ &jnz (&label("dec_loop"));
+
+ # middle of last round
+ &movdqa ("xmm4",&QWP(0x60,$base)); # 3 : sbou
+ &pshufb ("xmm4","xmm2"); # 4 = sbou
+ &pxor ("xmm4","xmm0"); # 4 = sb1u + k
+ &movdqa ("xmm0",&QWP(0x70,$base)); # 0 : sbot
+ &movdqa ("xmm2",&QWP(0,$magic));
+ &pshufb ("xmm0","xmm3"); # 0 = sb1t
+ &pxor ("xmm0","xmm4"); # 0 = A
+ &pshufb ("xmm0","xmm2");
+ &ret ();
+&function_end_B("_vpaes_decrypt_core");
+
+########################################################
+## ##
+## AES key schedule ##
+## ##
+########################################################
+&function_begin_B("_vpaes_schedule_core");
+ &add ($const,&DWP(0,"esp"));
+ &movdqu ("xmm0",&QWP(0,$inp)); # load key (unaligned)
+ &movdqa ("xmm2",&QWP($k_rcon,$const)); # load rcon
+
+ # input transform
+ &movdqa ("xmm3","xmm0");
+ &lea ($base,&DWP($k_ipt,$const));
+ &movdqa (&QWP(4,"esp"),"xmm2"); # xmm8
+ &call ("_vpaes_schedule_transform");
+ &movdqa ("xmm7","xmm0");
+
+ &test ($out,$out);
+ &jnz (&label("schedule_am_decrypting"));
+
+ # encrypting, output zeroth round key after transform
+ &movdqu (&QWP(0,$key),"xmm0");
+ &jmp (&label("schedule_go"));
+
+&set_label("schedule_am_decrypting");
+ # decrypting, output zeroth round key after shiftrows
+ &movdqa ("xmm1",&QWP($k_sr,$const,$magic));
+ &pshufb ("xmm3","xmm1");
+ &movdqu (&QWP(0,$key),"xmm3");
+ &xor ($magic,0x30);
+
+&set_label("schedule_go");
+ &cmp ($round,192);
+ &ja (&label("schedule_256"));
+ &je (&label("schedule_192"));
+ # 128: fall though
+
+##
+## .schedule_128
+##
+## 128-bit specific part of key schedule.
+##
+## This schedule is really simple, because all its parts
+## are accomplished by the subroutines.
+##
+&set_label("schedule_128");
+ &mov ($round,10);
+
+&set_label("loop_schedule_128");
+ &call ("_vpaes_schedule_round");
+ &dec ($round);
+ &jz (&label("schedule_mangle_last"));
+ &call ("_vpaes_schedule_mangle"); # write output
+ &jmp (&label("loop_schedule_128"));
+
+##
+## .aes_schedule_192
+##
+## 192-bit specific part of key schedule.
+##
+## The main body of this schedule is the same as the 128-bit
+## schedule, but with more smearing. The long, high side is
+## stored in %xmm7 as before, and the short, low side is in
+## the high bits of %xmm6.
+##
+## This schedule is somewhat nastier, however, because each
+## round produces 192 bits of key material, or 1.5 round keys.
+## Therefore, on each cycle we do 2 rounds and produce 3 round
+## keys.
+##
+&set_label("schedule_192",16);
+ &movdqu ("xmm0",&QWP(8,$inp)); # load key part 2 (very unaligned)
+ &call ("_vpaes_schedule_transform"); # input transform
+ &movdqa ("xmm6","xmm0"); # save short part
+ &pxor ("xmm4","xmm4"); # clear 4
+ &movhlps("xmm6","xmm4"); # clobber low side with zeros
+ &mov ($round,4);
+
+&set_label("loop_schedule_192");
+ &call ("_vpaes_schedule_round");
+ &palignr("xmm0","xmm6",8);
+ &call ("_vpaes_schedule_mangle"); # save key n
+ &call ("_vpaes_schedule_192_smear");
+ &call ("_vpaes_schedule_mangle"); # save key n+1
+ &call ("_vpaes_schedule_round");
+ &dec ($round);
+ &jz (&label("schedule_mangle_last"));
+ &call ("_vpaes_schedule_mangle"); # save key n+2
+ &call ("_vpaes_schedule_192_smear");
+ &jmp (&label("loop_schedule_192"));
+
+##
+## .aes_schedule_256
+##
+## 256-bit specific part of key schedule.
+##
+## The structure here is very similar to the 128-bit
+## schedule, but with an additional "low side" in
+## %xmm6. The low side's rounds are the same as the
+## high side's, except no rcon and no rotation.
+##
+&set_label("schedule_256",16);
+ &movdqu ("xmm0",&QWP(16,$inp)); # load key part 2 (unaligned)
+ &call ("_vpaes_schedule_transform"); # input transform
+ &mov ($round,7);
+
+&set_label("loop_schedule_256");
+ &call ("_vpaes_schedule_mangle"); # output low result
+ &movdqa ("xmm6","xmm0"); # save cur_lo in xmm6
+
+ # high round
+ &call ("_vpaes_schedule_round");
+ &dec ($round);
+ &jz (&label("schedule_mangle_last"));
+ &call ("_vpaes_schedule_mangle");
+
+ # low round. swap xmm7 and xmm6
+ &pshufd ("xmm0","xmm0",0xFF);
+ &movdqa (&QWP(20,"esp"),"xmm7");
+ &movdqa ("xmm7","xmm6");
+ &call ("_vpaes_schedule_low_round");
+ &movdqa ("xmm7",&QWP(20,"esp"));
+
+ &jmp (&label("loop_schedule_256"));
+
+##
+## .aes_schedule_mangle_last
+##
+## Mangler for last round of key schedule
+## Mangles %xmm0
+## when encrypting, outputs out(%xmm0) ^ 63
+## when decrypting, outputs unskew(%xmm0)
+##
+## Always called right before return... jumps to cleanup and exits
+##
+&set_label("schedule_mangle_last",16);
+ # schedule last round key from xmm0
+ &lea ($base,&DWP($k_deskew,$const));
+ &test ($out,$out);
+ &jnz (&label("schedule_mangle_last_dec"));
+
+ # encrypting
+ &movdqa ("xmm1",&QWP($k_sr,$const,$magic));
+ &pshufb ("xmm0","xmm1"); # output permute
+ &lea ($base,&DWP($k_opt,$const)); # prepare to output transform
+ &add ($key,32);
+
+&set_label("schedule_mangle_last_dec");
+ &add ($key,-16);
+ &pxor ("xmm0",&QWP($k_s63,$const));
+ &call ("_vpaes_schedule_transform"); # output transform
+ &movdqu (&QWP(0,$key),"xmm0"); # save last key
+
+ # cleanup
+ &pxor ("xmm0","xmm0");
+ &pxor ("xmm1","xmm1");
+ &pxor ("xmm2","xmm2");
+ &pxor ("xmm3","xmm3");
+ &pxor ("xmm4","xmm4");
+ &pxor ("xmm5","xmm5");
+ &pxor ("xmm6","xmm6");
+ &pxor ("xmm7","xmm7");
+ &ret ();
+&function_end_B("_vpaes_schedule_core");
+
+##
+## .aes_schedule_192_smear
+##
+## Smear the short, low side in the 192-bit key schedule.
+##
+## Inputs:
+## %xmm7: high side, b a x y
+## %xmm6: low side, d c 0 0
+## %xmm13: 0
+##
+## Outputs:
+## %xmm6: b+c+d b+c 0 0
+## %xmm0: b+c+d b+c b a
+##
+&function_begin_B("_vpaes_schedule_192_smear");
+ &pshufd ("xmm1","xmm6",0x80); # d c 0 0 -> c 0 0 0
+ &pshufd ("xmm0","xmm7",0xFE); # b a _ _ -> b b b a
+ &pxor ("xmm6","xmm1"); # -> c+d c 0 0
+ &pxor ("xmm1","xmm1");
+ &pxor ("xmm6","xmm0"); # -> b+c+d b+c b a
+ &movdqa ("xmm0","xmm6");
+ &movhlps("xmm6","xmm1"); # clobber low side with zeros
+ &ret ();
+&function_end_B("_vpaes_schedule_192_smear");
+
+##
+## .aes_schedule_round
+##
+## Runs one main round of the key schedule on %xmm0, %xmm7
+##
+## Specifically, runs subbytes on the high dword of %xmm0
+## then rotates it by one byte and xors into the low dword of
+## %xmm7.
+##
+## Adds rcon from low byte of %xmm8, then rotates %xmm8 for
+## next rcon.
+##
+## Smears the dwords of %xmm7 by xoring the low into the
+## second low, result into third, result into highest.
+##
+## Returns results in %xmm7 = %xmm0.
+## Clobbers %xmm1-%xmm5.
+##
+&function_begin_B("_vpaes_schedule_round");
+ # extract rcon from xmm8
+ &movdqa ("xmm2",&QWP(8,"esp")); # xmm8
+ &pxor ("xmm1","xmm1");
+ &palignr("xmm1","xmm2",15);
+ &palignr("xmm2","xmm2",15);
+ &pxor ("xmm7","xmm1");
+
+ # rotate
+ &pshufd ("xmm0","xmm0",0xFF);
+ &palignr("xmm0","xmm0",1);
+
+ # fall through...
+ &movdqa (&QWP(8,"esp"),"xmm2"); # xmm8
+
+ # low round: same as high round, but no rotation and no rcon.
+&set_label("_vpaes_schedule_low_round");
+ # smear xmm7
+ &movdqa ("xmm1","xmm7");
+ &pslldq ("xmm7",4);
+ &pxor ("xmm7","xmm1");
+ &movdqa ("xmm1","xmm7");
+ &pslldq ("xmm7",8);
+ &pxor ("xmm7","xmm1");
+ &pxor ("xmm7",&QWP($k_s63,$const));
+
+ # subbyte
+ &movdqa ("xmm4",&QWP($k_s0F,$const));
+ &movdqa ("xmm5",&QWP($k_inv,$const)); # 4 : 1/j
+ &movdqa ("xmm1","xmm4");
+ &pandn ("xmm1","xmm0");
+ &psrld ("xmm1",4); # 1 = i
+ &pand ("xmm0","xmm4"); # 0 = k
+ &movdqa ("xmm2",&QWP($k_inv+16,$const));# 2 : a/k
+ &pshufb ("xmm2","xmm0"); # 2 = a/k
+ &pxor ("xmm0","xmm1"); # 0 = j
+ &movdqa ("xmm3","xmm5"); # 3 : 1/i
+ &pshufb ("xmm3","xmm1"); # 3 = 1/i
+ &pxor ("xmm3","xmm2"); # 3 = iak = 1/i + a/k
+ &movdqa ("xmm4","xmm5"); # 4 : 1/j
+ &pshufb ("xmm4","xmm0"); # 4 = 1/j
+ &pxor ("xmm4","xmm2"); # 4 = jak = 1/j + a/k
+ &movdqa ("xmm2","xmm5"); # 2 : 1/iak
+ &pshufb ("xmm2","xmm3"); # 2 = 1/iak
+ &pxor ("xmm2","xmm0"); # 2 = io
+ &movdqa ("xmm3","xmm5"); # 3 : 1/jak
+ &pshufb ("xmm3","xmm4"); # 3 = 1/jak
+ &pxor ("xmm3","xmm1"); # 3 = jo
+ &movdqa ("xmm4",&QWP($k_sb1,$const)); # 4 : sbou
+ &pshufb ("xmm4","xmm2"); # 4 = sbou
+ &movdqa ("xmm0",&QWP($k_sb1+16,$const));# 0 : sbot
+ &pshufb ("xmm0","xmm3"); # 0 = sb1t
+ &pxor ("xmm0","xmm4"); # 0 = sbox output
+
+ # add in smeared stuff
+ &pxor ("xmm0","xmm7");
+ &movdqa ("xmm7","xmm0");
+ &ret ();
+&function_end_B("_vpaes_schedule_round");
+
+##
+## .aes_schedule_transform
+##
+## Linear-transform %xmm0 according to tables at (%ebx)
+##
+## Output in %xmm0
+## Clobbers %xmm1, %xmm2
+##
+&function_begin_B("_vpaes_schedule_transform");
+ &movdqa ("xmm2",&QWP($k_s0F,$const));
+ &movdqa ("xmm1","xmm2");
+ &pandn ("xmm1","xmm0");
+ &psrld ("xmm1",4);
+ &pand ("xmm0","xmm2");
+ &movdqa ("xmm2",&QWP(0,$base));
+ &pshufb ("xmm2","xmm0");
+ &movdqa ("xmm0",&QWP(16,$base));
+ &pshufb ("xmm0","xmm1");
+ &pxor ("xmm0","xmm2");
+ &ret ();
+&function_end_B("_vpaes_schedule_transform");
+
+##
+## .aes_schedule_mangle
+##
+## Mangle xmm0 from (basis-transformed) standard version
+## to our version.
+##
+## On encrypt,
+## xor with 0x63
+## multiply by circulant 0,1,1,1
+## apply shiftrows transform
+##
+## On decrypt,
+## xor with 0x63
+## multiply by "inverse mixcolumns" circulant E,B,D,9
+## deskew
+## apply shiftrows transform
+##
+##
+## Writes out to (%edx), and increments or decrements it
+## Keeps track of round number mod 4 in %ecx
+## Preserves xmm0
+## Clobbers xmm1-xmm5
+##
+&function_begin_B("_vpaes_schedule_mangle");
+ &movdqa ("xmm4","xmm0"); # save xmm0 for later
+ &movdqa ("xmm5",&QWP($k_mc_forward,$const));
+ &test ($out,$out);
+ &jnz (&label("schedule_mangle_dec"));
+
+ # encrypting
+ &add ($key,16);
+ &pxor ("xmm4",&QWP($k_s63,$const));
+ &pshufb ("xmm4","xmm5");
+ &movdqa ("xmm3","xmm4");
+ &pshufb ("xmm4","xmm5");
+ &pxor ("xmm3","xmm4");
+ &pshufb ("xmm4","xmm5");
+ &pxor ("xmm3","xmm4");
+
+ &jmp (&label("schedule_mangle_both"));
+
+&set_label("schedule_mangle_dec",16);
+ # inverse mix columns
+ &movdqa ("xmm2",&QWP($k_s0F,$const));
+ &lea ($inp,&DWP($k_dksd,$const));
+ &movdqa ("xmm1","xmm2");
+ &pandn ("xmm1","xmm4");
+ &psrld ("xmm1",4); # 1 = hi
+ &pand ("xmm4","xmm2"); # 4 = lo
+
+ &movdqa ("xmm2",&QWP(0,$inp));
+ &pshufb ("xmm2","xmm4");
+ &movdqa ("xmm3",&QWP(0x10,$inp));
+ &pshufb ("xmm3","xmm1");
+ &pxor ("xmm3","xmm2");
+ &pshufb ("xmm3","xmm5");
+
+ &movdqa ("xmm2",&QWP(0x20,$inp));
+ &pshufb ("xmm2","xmm4");
+ &pxor ("xmm2","xmm3");
+ &movdqa ("xmm3",&QWP(0x30,$inp));
+ &pshufb ("xmm3","xmm1");
+ &pxor ("xmm3","xmm2");
+ &pshufb ("xmm3","xmm5");
+
+ &movdqa ("xmm2",&QWP(0x40,$inp));
+ &pshufb ("xmm2","xmm4");
+ &pxor ("xmm2","xmm3");
+ &movdqa ("xmm3",&QWP(0x50,$inp));
+ &pshufb ("xmm3","xmm1");
+ &pxor ("xmm3","xmm2");
+ &pshufb ("xmm3","xmm5");
+
+ &movdqa ("xmm2",&QWP(0x60,$inp));
+ &pshufb ("xmm2","xmm4");
+ &pxor ("xmm2","xmm3");
+ &movdqa ("xmm3",&QWP(0x70,$inp));
+ &pshufb ("xmm3","xmm1");
+ &pxor ("xmm3","xmm2");
+
+ &add ($key,-16);
+
+&set_label("schedule_mangle_both");
+ &movdqa ("xmm1",&QWP($k_sr,$const,$magic));
+ &pshufb ("xmm3","xmm1");
+ &add ($magic,-16);
+ &and ($magic,0x30);
+ &movdqu (&QWP(0,$key),"xmm3");
+ &ret ();
+&function_end_B("_vpaes_schedule_mangle");
+
+#
+# Interface to OpenSSL
+#
+&function_begin("${PREFIX}_set_encrypt_key");
+ &mov ($inp,&wparam(0)); # inp
+ &lea ($base,&DWP(-56,"esp"));
+ &mov ($round,&wparam(1)); # bits
+ &and ($base,-16);
+ &mov ($key,&wparam(2)); # key
+ &xchg ($base,"esp"); # alloca
+ &mov (&DWP(48,"esp"),$base);
+
+ &mov ($base,$round);
+ &shr ($base,5);
+ &add ($base,5);
+ &mov (&DWP(240,$key),$base); # AES_KEY->rounds = nbits/32+5;
+ &mov ($magic,0x30);
+ &mov ($out,0);
+
+ &lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point")));
+ &call ("_vpaes_schedule_core");
+&set_label("pic_point");
+
+ &mov ("esp",&DWP(48,"esp"));
+ &xor ("eax","eax");
+&function_end("${PREFIX}_set_encrypt_key");
+
+&function_begin("${PREFIX}_set_decrypt_key");
+ &mov ($inp,&wparam(0)); # inp
+ &lea ($base,&DWP(-56,"esp"));
+ &mov ($round,&wparam(1)); # bits
+ &and ($base,-16);
+ &mov ($key,&wparam(2)); # key
+ &xchg ($base,"esp"); # alloca
+ &mov (&DWP(48,"esp"),$base);
+
+ &mov ($base,$round);
+ &shr ($base,5);
+ &add ($base,5);
+ &mov (&DWP(240,$key),$base); # AES_KEY->rounds = nbits/32+5;
+ &shl ($base,4);
+ &lea ($key,&DWP(16,$key,$base));
+
+ &mov ($out,1);
+ &mov ($magic,$round);
+ &shr ($magic,1);
+ &and ($magic,32);
+ &xor ($magic,32); # nbist==192?0:32;
+
+ &lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point")));
+ &call ("_vpaes_schedule_core");
+&set_label("pic_point");
+
+ &mov ("esp",&DWP(48,"esp"));
+ &xor ("eax","eax");
+&function_end("${PREFIX}_set_decrypt_key");
+
+&function_begin("${PREFIX}_encrypt");
+ &lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point")));
+ &call ("_vpaes_preheat");
+&set_label("pic_point");
+ &mov ($inp,&wparam(0)); # inp
+ &lea ($base,&DWP(-56,"esp"));
+ &mov ($out,&wparam(1)); # out
+ &and ($base,-16);
+ &mov ($key,&wparam(2)); # key
+ &xchg ($base,"esp"); # alloca
+ &mov (&DWP(48,"esp"),$base);
+
+ &movdqu ("xmm0",&QWP(0,$inp));
+ &call ("_vpaes_encrypt_core");
+ &movdqu (&QWP(0,$out),"xmm0");
+
+ &mov ("esp",&DWP(48,"esp"));
+&function_end("${PREFIX}_encrypt");
+
+&function_begin("${PREFIX}_decrypt");
+ &lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point")));
+ &call ("_vpaes_preheat");
+&set_label("pic_point");
+ &mov ($inp,&wparam(0)); # inp
+ &lea ($base,&DWP(-56,"esp"));
+ &mov ($out,&wparam(1)); # out
+ &and ($base,-16);
+ &mov ($key,&wparam(2)); # key
+ &xchg ($base,"esp"); # alloca
+ &mov (&DWP(48,"esp"),$base);
+
+ &movdqu ("xmm0",&QWP(0,$inp));
+ &call ("_vpaes_decrypt_core");
+ &movdqu (&QWP(0,$out),"xmm0");
+
+ &mov ("esp",&DWP(48,"esp"));
+&function_end("${PREFIX}_decrypt");
+
+&function_begin("${PREFIX}_cbc_encrypt");
+ &mov ($inp,&wparam(0)); # inp
+ &mov ($out,&wparam(1)); # out
+ &mov ($round,&wparam(2)); # len
+ &mov ($key,&wparam(3)); # key
+ &sub ($round,16);
+ &jc (&label("cbc_abort"));
+ &lea ($base,&DWP(-56,"esp"));
+ &mov ($const,&wparam(4)); # ivp
+ &and ($base,-16);
+ &mov ($magic,&wparam(5)); # enc
+ &xchg ($base,"esp"); # alloca
+ &movdqu ("xmm1",&QWP(0,$const)); # load IV
+ &sub ($out,$inp);
+ &mov (&DWP(48,"esp"),$base);
+
+ &mov (&DWP(0,"esp"),$out); # save out
+ &mov (&DWP(4,"esp"),$key) # save key
+ &mov (&DWP(8,"esp"),$const); # save ivp
+ &mov ($out,$round); # $out works as $len
+
+ &lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point")));
+ &call ("_vpaes_preheat");
+&set_label("pic_point");
+ &cmp ($magic,0);
+ &je (&label("cbc_dec_loop"));
+ &jmp (&label("cbc_enc_loop"));
+
+&set_label("cbc_enc_loop",16);
+ &movdqu ("xmm0",&QWP(0,$inp)); # load input
+ &pxor ("xmm0","xmm1"); # inp^=iv
+ &call ("_vpaes_encrypt_core");
+ &mov ($base,&DWP(0,"esp")); # restore out
+ &mov ($key,&DWP(4,"esp")); # restore key
+ &movdqa ("xmm1","xmm0");
+ &movdqu (&QWP(0,$base,$inp),"xmm0"); # write output
+ &lea ($inp,&DWP(16,$inp));
+ &sub ($out,16);
+ &jnc (&label("cbc_enc_loop"));
+ &jmp (&label("cbc_done"));
+
+&set_label("cbc_dec_loop",16);
+ &movdqu ("xmm0",&QWP(0,$inp)); # load input
+ &movdqa (&QWP(16,"esp"),"xmm1"); # save IV
+ &movdqa (&QWP(32,"esp"),"xmm0"); # save future IV
+ &call ("_vpaes_decrypt_core");
+ &mov ($base,&DWP(0,"esp")); # restore out
+ &mov ($key,&DWP(4,"esp")); # restore key
+ &pxor ("xmm0",&QWP(16,"esp")); # out^=iv
+ &movdqa ("xmm1",&QWP(32,"esp")); # load next IV
+ &movdqu (&QWP(0,$base,$inp),"xmm0"); # write output
+ &lea ($inp,&DWP(16,$inp));
+ &sub ($out,16);
+ &jnc (&label("cbc_dec_loop"));
+
+&set_label("cbc_done");
+ &mov ($base,&DWP(8,"esp")); # restore ivp
+ &mov ("esp",&DWP(48,"esp"));
+ &movdqu (&QWP(0,$base),"xmm1"); # write IV
+&set_label("cbc_abort");
+&function_end("${PREFIX}_cbc_encrypt");
+
+&asm_finish();
diff --git a/crypto/aes/asm/vpaes-x86_64.pl b/crypto/aes/asm/vpaes-x86_64.pl
new file mode 100644
index 0000000..212394b
--- /dev/null
+++ b/crypto/aes/asm/vpaes-x86_64.pl
@@ -0,0 +1,1206 @@
+#!/usr/bin/env perl
+
+######################################################################
+## Constant-time SSSE3 AES core implementation.
+## version 0.1
+##
+## By Mike Hamburg (Stanford University), 2009
+## Public domain.
+##
+## For details see http://shiftleft.org/papers/vector_aes/ and
+## http://crypto.stanford.edu/vpaes/.
+
+######################################################################
+# September 2011.
+#
+# Interface to OpenSSL as "almost" drop-in replacement for
+# aes-x86_64.pl. "Almost" refers to the fact that AES_cbc_encrypt
+# doesn't handle partial vectors (doesn't have to if called from
+# EVP only). "Drop-in" implies that this module doesn't share key
+# schedule structure with the original nor does it make assumption
+# about its alignment...
+#
+# Performance summary. aes-x86_64.pl column lists large-block CBC
+# encrypt/decrypt/with-hyper-threading-off(*) results in cycles per
+# byte processed with 128-bit key, and vpaes-x86_64.pl column -
+# [also large-block CBC] encrypt/decrypt.
+#
+# aes-x86_64.pl vpaes-x86_64.pl
+#
+# Core 2(**) 29.6/41.1/14.3 21.9/25.2(***)
+# Nehalem 29.6/40.3/14.6 10.0/11.8
+# Atom 57.3/74.2/32.1 60.9/77.2(***)
+#
+# (*) "Hyper-threading" in the context refers rather to cache shared
+# among multiple cores, than to specifically Intel HTT. As vast
+# majority of contemporary cores share cache, slower code path
+# is common place. In other words "with-hyper-threading-off"
+# results are presented mostly for reference purposes.
+#
+# (**) "Core 2" refers to initial 65nm design, a.k.a. Conroe.
+#
+# (***) Less impressive improvement on Core 2 and Atom is due to slow
+# pshufb, yet it's respectable +36%/62% improvement on Core 2
+# (as implied, over "hyper-threading-safe" code path).
+#
+# <appro@openssl.org>
+
+$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;
+
+$PREFIX="vpaes";
+
+$code.=<<___;
+.text
+
+##
+## _aes_encrypt_core
+##
+## AES-encrypt %xmm0.
+##
+## Inputs:
+## %xmm0 = input
+## %xmm9-%xmm15 as in _vpaes_preheat
+## (%rdx) = scheduled keys
+##
+## Output in %xmm0
+## Clobbers %xmm1-%xmm5, %r9, %r10, %r11, %rax
+## Preserves %xmm6 - %xmm8 so you get some local vectors
+##
+##
+.type _vpaes_encrypt_core,\@abi-omnipotent
+.align 16
+_vpaes_encrypt_core:
+ mov %rdx, %r9
+ mov \$16, %r11
+ mov 240(%rdx),%eax
+ movdqa %xmm9, %xmm1
+ movdqa .Lk_ipt(%rip), %xmm2 # iptlo
+ pandn %xmm0, %xmm1
+ movdqu (%r9), %xmm5 # round0 key
+ psrld \$4, %xmm1
+ pand %xmm9, %xmm0
+ pshufb %xmm0, %xmm2
+ movdqa .Lk_ipt+16(%rip), %xmm0 # ipthi
+ pshufb %xmm1, %xmm0
+ pxor %xmm5, %xmm2
+ add \$16, %r9
+ pxor %xmm2, %xmm0
+ lea .Lk_mc_backward(%rip),%r10
+ jmp .Lenc_entry
+
+.align 16
+.Lenc_loop:
+ # middle of middle round
+ movdqa %xmm13, %xmm4 # 4 : sb1u
+ movdqa %xmm12, %xmm0 # 0 : sb1t
+ pshufb %xmm2, %xmm4 # 4 = sb1u
+ pshufb %xmm3, %xmm0 # 0 = sb1t
+ pxor %xmm5, %xmm4 # 4 = sb1u + k
+ movdqa %xmm15, %xmm5 # 4 : sb2u
+ pxor %xmm4, %xmm0 # 0 = A
+ movdqa -0x40(%r11,%r10), %xmm1 # .Lk_mc_forward[]
+ pshufb %xmm2, %xmm5 # 4 = sb2u
+ movdqa (%r11,%r10), %xmm4 # .Lk_mc_backward[]
+ movdqa %xmm14, %xmm2 # 2 : sb2t
+ pshufb %xmm3, %xmm2 # 2 = sb2t
+ movdqa %xmm0, %xmm3 # 3 = A
+ pxor %xmm5, %xmm2 # 2 = 2A
+ pshufb %xmm1, %xmm0 # 0 = B
+ add \$16, %r9 # next key
+ pxor %xmm2, %xmm0 # 0 = 2A+B
+ pshufb %xmm4, %xmm3 # 3 = D
+ add \$16, %r11 # next mc
+ pxor %xmm0, %xmm3 # 3 = 2A+B+D
+ pshufb %xmm1, %xmm0 # 0 = 2B+C
+ and \$0x30, %r11 # ... mod 4
+ sub \$1,%rax # nr--
+ pxor %xmm3, %xmm0 # 0 = 2A+3B+C+D
+
+.Lenc_entry:
+ # top of round
+ movdqa %xmm9, %xmm1 # 1 : i
+ movdqa %xmm11, %xmm5 # 2 : a/k
+ pandn %xmm0, %xmm1 # 1 = i<<4
+ psrld \$4, %xmm1 # 1 = i
+ pand %xmm9, %xmm0 # 0 = k
+ pshufb %xmm0, %xmm5 # 2 = a/k
+ movdqa %xmm10, %xmm3 # 3 : 1/i
+ pxor %xmm1, %xmm0 # 0 = j
+ pshufb %xmm1, %xmm3 # 3 = 1/i
+ movdqa %xmm10, %xmm4 # 4 : 1/j
+ pxor %xmm5, %xmm3 # 3 = iak = 1/i + a/k
+ pshufb %xmm0, %xmm4 # 4 = 1/j
+ movdqa %xmm10, %xmm2 # 2 : 1/iak
+ pxor %xmm5, %xmm4 # 4 = jak = 1/j + a/k
+ pshufb %xmm3, %xmm2 # 2 = 1/iak
+ movdqa %xmm10, %xmm3 # 3 : 1/jak
+ pxor %xmm0, %xmm2 # 2 = io
+ pshufb %xmm4, %xmm3 # 3 = 1/jak
+ movdqu (%r9), %xmm5
+ pxor %xmm1, %xmm3 # 3 = jo
+ jnz .Lenc_loop
+
+ # middle of last round
+ movdqa -0x60(%r10), %xmm4 # 3 : sbou .Lk_sbo
+ movdqa -0x50(%r10), %xmm0 # 0 : sbot .Lk_sbo+16
+ pshufb %xmm2, %xmm4 # 4 = sbou
+ pxor %xmm5, %xmm4 # 4 = sb1u + k
+ pshufb %xmm3, %xmm0 # 0 = sb1t
+ movdqa 0x40(%r11,%r10), %xmm1 # .Lk_sr[]
+ pxor %xmm4, %xmm0 # 0 = A
+ pshufb %xmm1, %xmm0
+ ret
+.size _vpaes_encrypt_core,.-_vpaes_encrypt_core
+
+##
+## Decryption core
+##
+## Same API as encryption core.
+##
+.type _vpaes_decrypt_core,\@abi-omnipotent
+.align 16
+_vpaes_decrypt_core:
+ mov %rdx, %r9 # load key
+ mov 240(%rdx),%eax
+ movdqa %xmm9, %xmm1
+ movdqa .Lk_dipt(%rip), %xmm2 # iptlo
+ pandn %xmm0, %xmm1
+ mov %rax, %r11
+ psrld \$4, %xmm1
+ movdqu (%r9), %xmm5 # round0 key
+ shl \$4, %r11
+ pand %xmm9, %xmm0
+ pshufb %xmm0, %xmm2
+ movdqa .Lk_dipt+16(%rip), %xmm0 # ipthi
+ xor \$0x30, %r11
+ lea .Lk_dsbd(%rip),%r10
+ pshufb %xmm1, %xmm0
+ and \$0x30, %r11
+ pxor %xmm5, %xmm2
+ movdqa .Lk_mc_forward+48(%rip), %xmm5
+ pxor %xmm2, %xmm0
+ add \$16, %r9
+ add %r10, %r11
+ jmp .Ldec_entry
+
+.align 16
+.Ldec_loop:
+##
+## Inverse mix columns
+##
+ movdqa -0x20(%r10),%xmm4 # 4 : sb9u
+ movdqa -0x10(%r10),%xmm1 # 0 : sb9t
+ pshufb %xmm2, %xmm4 # 4 = sb9u
+ pshufb %xmm3, %xmm1 # 0 = sb9t
+ pxor %xmm4, %xmm0
+ movdqa 0x00(%r10),%xmm4 # 4 : sbdu
+ pxor %xmm1, %xmm0 # 0 = ch
+ movdqa 0x10(%r10),%xmm1 # 0 : sbdt
+
+ pshufb %xmm2, %xmm4 # 4 = sbdu
+ pshufb %xmm5, %xmm0 # MC ch
+ pshufb %xmm3, %xmm1 # 0 = sbdt
+ pxor %xmm4, %xmm0 # 4 = ch
+ movdqa 0x20(%r10),%xmm4 # 4 : sbbu
+ pxor %xmm1, %xmm0 # 0 = ch
+ movdqa 0x30(%r10),%xmm1 # 0 : sbbt
+
+ pshufb %xmm2, %xmm4 # 4 = sbbu
+ pshufb %xmm5, %xmm0 # MC ch
+ pshufb %xmm3, %xmm1 # 0 = sbbt
+ pxor %xmm4, %xmm0 # 4 = ch
+ movdqa 0x40(%r10),%xmm4 # 4 : sbeu
+ pxor %xmm1, %xmm0 # 0 = ch
+ movdqa 0x50(%r10),%xmm1 # 0 : sbet
+
+ pshufb %xmm2, %xmm4 # 4 = sbeu
+ pshufb %xmm5, %xmm0 # MC ch
+ pshufb %xmm3, %xmm1 # 0 = sbet
+ pxor %xmm4, %xmm0 # 4 = ch
+ add \$16, %r9 # next round key
+ palignr \$12, %xmm5, %xmm5
+ pxor %xmm1, %xmm0 # 0 = ch
+ sub \$1,%rax # nr--
+
+.Ldec_entry:
+ # top of round
+ movdqa %xmm9, %xmm1 # 1 : i
+ pandn %xmm0, %xmm1 # 1 = i<<4
+ movdqa %xmm11, %xmm2 # 2 : a/k
+ psrld \$4, %xmm1 # 1 = i
+ pand %xmm9, %xmm0 # 0 = k
+ pshufb %xmm0, %xmm2 # 2 = a/k
+ movdqa %xmm10, %xmm3 # 3 : 1/i
+ pxor %xmm1, %xmm0 # 0 = j
+ pshufb %xmm1, %xmm3 # 3 = 1/i
+ movdqa %xmm10, %xmm4 # 4 : 1/j
+ pxor %xmm2, %xmm3 # 3 = iak = 1/i + a/k
+ pshufb %xmm0, %xmm4 # 4 = 1/j
+ pxor %xmm2, %xmm4 # 4 = jak = 1/j + a/k
+ movdqa %xmm10, %xmm2 # 2 : 1/iak
+ pshufb %xmm3, %xmm2 # 2 = 1/iak
+ movdqa %xmm10, %xmm3 # 3 : 1/jak
+ pxor %xmm0, %xmm2 # 2 = io
+ pshufb %xmm4, %xmm3 # 3 = 1/jak
+ movdqu (%r9), %xmm0
+ pxor %xmm1, %xmm3 # 3 = jo
+ jnz .Ldec_loop
+
+ # middle of last round
+ movdqa 0x60(%r10), %xmm4 # 3 : sbou
+ pshufb %xmm2, %xmm4 # 4 = sbou
+ pxor %xmm0, %xmm4 # 4 = sb1u + k
+ movdqa 0x70(%r10), %xmm0 # 0 : sbot
+ movdqa -0x160(%r11), %xmm2 # .Lk_sr-.Lk_dsbd=-0x160
+ pshufb %xmm3, %xmm0 # 0 = sb1t
+ pxor %xmm4, %xmm0 # 0 = A
+ pshufb %xmm2, %xmm0
+ ret
+.size _vpaes_decrypt_core,.-_vpaes_decrypt_core
+
+########################################################
+## ##
+## AES key schedule ##
+## ##
+########################################################
+.type _vpaes_schedule_core,\@abi-omnipotent
+.align 16
+_vpaes_schedule_core:
+ # rdi = key
+ # rsi = size in bits
+ # rdx = buffer
+ # rcx = direction. 0=encrypt, 1=decrypt
+
+ call _vpaes_preheat # load the tables
+ movdqa .Lk_rcon(%rip), %xmm8 # load rcon
+ movdqu (%rdi), %xmm0 # load key (unaligned)
+
+ # input transform
+ movdqa %xmm0, %xmm3
+ lea .Lk_ipt(%rip), %r11
+ call _vpaes_schedule_transform
+ movdqa %xmm0, %xmm7
+
+ lea .Lk_sr(%rip),%r10
+ test %rcx, %rcx
+ jnz .Lschedule_am_decrypting
+
+ # encrypting, output zeroth round key after transform
+ movdqu %xmm0, (%rdx)
+ jmp .Lschedule_go
+
+.Lschedule_am_decrypting:
+ # decrypting, output zeroth round key after shiftrows
+ movdqa (%r8,%r10),%xmm1
+ pshufb %xmm1, %xmm3
+ movdqu %xmm3, (%rdx)
+ xor \$0x30, %r8
+
+.Lschedule_go:
+ cmp \$192, %esi
+ ja .Lschedule_256
+ je .Lschedule_192
+ # 128: fall though
+
+##
+## .schedule_128
+##
+## 128-bit specific part of key schedule.
+##
+## This schedule is really simple, because all its parts
+## are accomplished by the subroutines.
+##
+.Lschedule_128:
+ mov \$10, %esi
+
+.Loop_schedule_128:
+ call _vpaes_schedule_round
+ dec %rsi
+ jz .Lschedule_mangle_last
+ call _vpaes_schedule_mangle # write output
+ jmp .Loop_schedule_128
+
+##
+## .aes_schedule_192
+##
+## 192-bit specific part of key schedule.
+##
+## The main body of this schedule is the same as the 128-bit
+## schedule, but with more smearing. The long, high side is
+## stored in %xmm7 as before, and the short, low side is in
+## the high bits of %xmm6.
+##
+## This schedule is somewhat nastier, however, because each
+## round produces 192 bits of key material, or 1.5 round keys.
+## Therefore, on each cycle we do 2 rounds and produce 3 round
+## keys.
+##
+.align 16
+.Lschedule_192:
+ movdqu 8(%rdi),%xmm0 # load key part 2 (very unaligned)
+ call _vpaes_schedule_transform # input transform
+ movdqa %xmm0, %xmm6 # save short part
+ pxor %xmm4, %xmm4 # clear 4
+ movhlps %xmm4, %xmm6 # clobber low side with zeros
+ mov \$4, %esi
+
+.Loop_schedule_192:
+ call _vpaes_schedule_round
+ palignr \$8,%xmm6,%xmm0
+ call _vpaes_schedule_mangle # save key n
+ call _vpaes_schedule_192_smear
+ call _vpaes_schedule_mangle # save key n+1
+ call _vpaes_schedule_round
+ dec %rsi
+ jz .Lschedule_mangle_last
+ call _vpaes_schedule_mangle # save key n+2
+ call _vpaes_schedule_192_smear
+ jmp .Loop_schedule_192
+
+##
+## .aes_schedule_256
+##
+## 256-bit specific part of key schedule.
+##
+## The structure here is very similar to the 128-bit
+## schedule, but with an additional "low side" in
+## %xmm6. The low side's rounds are the same as the
+## high side's, except no rcon and no rotation.
+##
+.align 16
+.Lschedule_256:
+ movdqu 16(%rdi),%xmm0 # load key part 2 (unaligned)
+ call _vpaes_schedule_transform # input transform
+ mov \$7, %esi
+
+.Loop_schedule_256:
+ call _vpaes_schedule_mangle # output low result
+ movdqa %xmm0, %xmm6 # save cur_lo in xmm6
+
+ # high round
+ call _vpaes_schedule_round
+ dec %rsi
+ jz .Lschedule_mangle_last
+ call _vpaes_schedule_mangle
+
+ # low round. swap xmm7 and xmm6
+ pshufd \$0xFF, %xmm0, %xmm0
+ movdqa %xmm7, %xmm5
+ movdqa %xmm6, %xmm7
+ call _vpaes_schedule_low_round
+ movdqa %xmm5, %xmm7
+
+ jmp .Loop_schedule_256
+
+
+##
+## .aes_schedule_mangle_last
+##
+## Mangler for last round of key schedule
+## Mangles %xmm0
+## when encrypting, outputs out(%xmm0) ^ 63
+## when decrypting, outputs unskew(%xmm0)
+##
+## Always called right before return... jumps to cleanup and exits
+##
+.align 16
+.Lschedule_mangle_last:
+ # schedule last round key from xmm0
+ lea .Lk_deskew(%rip),%r11 # prepare to deskew
+ test %rcx, %rcx
+ jnz .Lschedule_mangle_last_dec
+
+ # encrypting
+ movdqa (%r8,%r10),%xmm1
+ pshufb %xmm1, %xmm0 # output permute
+ lea .Lk_opt(%rip), %r11 # prepare to output transform
+ add \$32, %rdx
+
+.Lschedule_mangle_last_dec:
+ add \$-16, %rdx
+ pxor .Lk_s63(%rip), %xmm0
+ call _vpaes_schedule_transform # output transform
+ movdqu %xmm0, (%rdx) # save last key
+
+ # cleanup
+ pxor %xmm0, %xmm0
+ pxor %xmm1, %xmm1
+ pxor %xmm2, %xmm2
+ pxor %xmm3, %xmm3
+ pxor %xmm4, %xmm4
+ pxor %xmm5, %xmm5
+ pxor %xmm6, %xmm6
+ pxor %xmm7, %xmm7
+ ret
+.size _vpaes_schedule_core,.-_vpaes_schedule_core
+
+##
+## .aes_schedule_192_smear
+##
+## Smear the short, low side in the 192-bit key schedule.
+##
+## Inputs:
+## %xmm7: high side, b a x y
+## %xmm6: low side, d c 0 0
+## %xmm13: 0
+##
+## Outputs:
+## %xmm6: b+c+d b+c 0 0
+## %xmm0: b+c+d b+c b a
+##
+.type _vpaes_schedule_192_smear,\@abi-omnipotent
+.align 16
+_vpaes_schedule_192_smear:
+ pshufd \$0x80, %xmm6, %xmm1 # d c 0 0 -> c 0 0 0
+ pshufd \$0xFE, %xmm7, %xmm0 # b a _ _ -> b b b a
+ pxor %xmm1, %xmm6 # -> c+d c 0 0
+ pxor %xmm1, %xmm1
+ pxor %xmm0, %xmm6 # -> b+c+d b+c b a
+ movdqa %xmm6, %xmm0
+ movhlps %xmm1, %xmm6 # clobber low side with zeros
+ ret
+.size _vpaes_schedule_192_smear,.-_vpaes_schedule_192_smear
+
+##
+## .aes_schedule_round
+##
+## Runs one main round of the key schedule on %xmm0, %xmm7
+##
+## Specifically, runs subbytes on the high dword of %xmm0
+## then rotates it by one byte and xors into the low dword of
+## %xmm7.
+##
+## Adds rcon from low byte of %xmm8, then rotates %xmm8 for
+## next rcon.
+##
+## Smears the dwords of %xmm7 by xoring the low into the
+## second low, result into third, result into highest.
+##
+## Returns results in %xmm7 = %xmm0.
+## Clobbers %xmm1-%xmm4, %r11.
+##
+.type _vpaes_schedule_round,\@abi-omnipotent
+.align 16
+_vpaes_schedule_round:
+ # extract rcon from xmm8
+ pxor %xmm1, %xmm1
+ palignr \$15, %xmm8, %xmm1
+ palignr \$15, %xmm8, %xmm8
+ pxor %xmm1, %xmm7
+
+ # rotate
+ pshufd \$0xFF, %xmm0, %xmm0
+ palignr \$1, %xmm0, %xmm0
+
+ # fall through...
+
+ # low round: same as high round, but no rotation and no rcon.
+_vpaes_schedule_low_round:
+ # smear xmm7
+ movdqa %xmm7, %xmm1
+ pslldq \$4, %xmm7
+ pxor %xmm1, %xmm7
+ movdqa %xmm7, %xmm1
+ pslldq \$8, %xmm7
+ pxor %xmm1, %xmm7
+ pxor .Lk_s63(%rip), %xmm7
+
+ # subbytes
+ movdqa %xmm9, %xmm1
+ pandn %xmm0, %xmm1
+ psrld \$4, %xmm1 # 1 = i
+ pand %xmm9, %xmm0 # 0 = k
+ movdqa %xmm11, %xmm2 # 2 : a/k
+ pshufb %xmm0, %xmm2 # 2 = a/k
+ pxor %xmm1, %xmm0 # 0 = j
+ movdqa %xmm10, %xmm3 # 3 : 1/i
+ pshufb %xmm1, %xmm3 # 3 = 1/i
+ pxor %xmm2, %xmm3 # 3 = iak = 1/i + a/k
+ movdqa %xmm10, %xmm4 # 4 : 1/j
+ pshufb %xmm0, %xmm4 # 4 = 1/j
+ pxor %xmm2, %xmm4 # 4 = jak = 1/j + a/k
+ movdqa %xmm10, %xmm2 # 2 : 1/iak
+ pshufb %xmm3, %xmm2 # 2 = 1/iak
+ pxor %xmm0, %xmm2 # 2 = io
+ movdqa %xmm10, %xmm3 # 3 : 1/jak
+ pshufb %xmm4, %xmm3 # 3 = 1/jak
+ pxor %xmm1, %xmm3 # 3 = jo
+ movdqa %xmm13, %xmm4 # 4 : sbou
+ pshufb %xmm2, %xmm4 # 4 = sbou
+ movdqa %xmm12, %xmm0 # 0 : sbot
+ pshufb %xmm3, %xmm0 # 0 = sb1t
+ pxor %xmm4, %xmm0 # 0 = sbox output
+
+ # add in smeared stuff
+ pxor %xmm7, %xmm0
+ movdqa %xmm0, %xmm7
+ ret
+.size _vpaes_schedule_round,.-_vpaes_schedule_round
+
+##
+## .aes_schedule_transform
+##
+## Linear-transform %xmm0 according to tables at (%r11)
+##
+## Requires that %xmm9 = 0x0F0F... as in preheat
+## Output in %xmm0
+## Clobbers %xmm1, %xmm2
+##
+.type _vpaes_schedule_transform,\@abi-omnipotent
+.align 16
+_vpaes_schedule_transform:
+ movdqa %xmm9, %xmm1
+ pandn %xmm0, %xmm1
+ psrld \$4, %xmm1
+ pand %xmm9, %xmm0
+ movdqa (%r11), %xmm2 # lo
+ pshufb %xmm0, %xmm2
+ movdqa 16(%r11), %xmm0 # hi
+ pshufb %xmm1, %xmm0
+ pxor %xmm2, %xmm0
+ ret
+.size _vpaes_schedule_transform,.-_vpaes_schedule_transform
+
+##
+## .aes_schedule_mangle
+##
+## Mangle xmm0 from (basis-transformed) standard version
+## to our version.
+##
+## On encrypt,
+## xor with 0x63
+## multiply by circulant 0,1,1,1
+## apply shiftrows transform
+##
+## On decrypt,
+## xor with 0x63
+## multiply by "inverse mixcolumns" circulant E,B,D,9
+## deskew
+## apply shiftrows transform
+##
+##
+## Writes out to (%rdx), and increments or decrements it
+## Keeps track of round number mod 4 in %r8
+## Preserves xmm0
+## Clobbers xmm1-xmm5
+##
+.type _vpaes_schedule_mangle,\@abi-omnipotent
+.align 16
+_vpaes_schedule_mangle:
+ movdqa %xmm0, %xmm4 # save xmm0 for later
+ movdqa .Lk_mc_forward(%rip),%xmm5
+ test %rcx, %rcx
+ jnz .Lschedule_mangle_dec
+
+ # encrypting
+ add \$16, %rdx
+ pxor .Lk_s63(%rip),%xmm4
+ pshufb %xmm5, %xmm4
+ movdqa %xmm4, %xmm3
+ pshufb %xmm5, %xmm4
+ pxor %xmm4, %xmm3
+ pshufb %xmm5, %xmm4
+ pxor %xmm4, %xmm3
+
+ jmp .Lschedule_mangle_both
+.align 16
+.Lschedule_mangle_dec:
+ # inverse mix columns
+ lea .Lk_dksd(%rip),%r11
+ movdqa %xmm9, %xmm1
+ pandn %xmm4, %xmm1
+ psrld \$4, %xmm1 # 1 = hi
+ pand %xmm9, %xmm4 # 4 = lo
+
+ movdqa 0x00(%r11), %xmm2
+ pshufb %xmm4, %xmm2
+ movdqa 0x10(%r11), %xmm3
+ pshufb %xmm1, %xmm3
+ pxor %xmm2, %xmm3
+ pshufb %xmm5, %xmm3
+
+ movdqa 0x20(%r11), %xmm2
+ pshufb %xmm4, %xmm2
+ pxor %xmm3, %xmm2
+ movdqa 0x30(%r11), %xmm3
+ pshufb %xmm1, %xmm3
+ pxor %xmm2, %xmm3
+ pshufb %xmm5, %xmm3
+
+ movdqa 0x40(%r11), %xmm2
+ pshufb %xmm4, %xmm2
+ pxor %xmm3, %xmm2
+ movdqa 0x50(%r11), %xmm3
+ pshufb %xmm1, %xmm3
+ pxor %xmm2, %xmm3
+ pshufb %xmm5, %xmm3
+
+ movdqa 0x60(%r11), %xmm2
+ pshufb %xmm4, %xmm2
+ pxor %xmm3, %xmm2
+ movdqa 0x70(%r11), %xmm3
+ pshufb %xmm1, %xmm3
+ pxor %xmm2, %xmm3
+
+ add \$-16, %rdx
+
+.Lschedule_mangle_both:
+ movdqa (%r8,%r10),%xmm1
+ pshufb %xmm1,%xmm3
+ add \$-16, %r8
+ and \$0x30, %r8
+ movdqu %xmm3, (%rdx)
+ ret
+.size _vpaes_schedule_mangle,.-_vpaes_schedule_mangle
+
+#
+# Interface to OpenSSL
+#
+.globl ${PREFIX}_set_encrypt_key
+.type ${PREFIX}_set_encrypt_key,\@function,3
+.align 16
+${PREFIX}_set_encrypt_key:
+___
+$code.=<<___ if ($win64);
+ lea -0xb8(%rsp),%rsp
+ movaps %xmm6,0x10(%rsp)
+ movaps %xmm7,0x20(%rsp)
+ movaps %xmm8,0x30(%rsp)
+ movaps %xmm9,0x40(%rsp)
+ movaps %xmm10,0x50(%rsp)
+ movaps %xmm11,0x60(%rsp)
+ movaps %xmm12,0x70(%rsp)
+ movaps %xmm13,0x80(%rsp)
+ movaps %xmm14,0x90(%rsp)
+ movaps %xmm15,0xa0(%rsp)
+.Lenc_key_body:
+___
+$code.=<<___;
+ mov %esi,%eax
+ shr \$5,%eax
+ add \$5,%eax
+ mov %eax,240(%rdx) # AES_KEY->rounds = nbits/32+5;
+
+ mov \$0,%ecx
+ mov \$0x30,%r8d
+ call _vpaes_schedule_core
+___
+$code.=<<___ if ($win64);
+ movaps 0x10(%rsp),%xmm6
+ movaps 0x20(%rsp),%xmm7
+ movaps 0x30(%rsp),%xmm8
+ movaps 0x40(%rsp),%xmm9
+ movaps 0x50(%rsp),%xmm10
+ movaps 0x60(%rsp),%xmm11
+ movaps 0x70(%rsp),%xmm12
+ movaps 0x80(%rsp),%xmm13
+ movaps 0x90(%rsp),%xmm14
+ movaps 0xa0(%rsp),%xmm15
+ lea 0xb8(%rsp),%rsp
+.Lenc_key_epilogue:
+___
+$code.=<<___;
+ xor %eax,%eax
+ ret
+.size ${PREFIX}_set_encrypt_key,.-${PREFIX}_set_encrypt_key
+
+.globl ${PREFIX}_set_decrypt_key
+.type ${PREFIX}_set_decrypt_key,\@function,3
+.align 16
+${PREFIX}_set_decrypt_key:
+___
+$code.=<<___ if ($win64);
+ lea -0xb8(%rsp),%rsp
+ movaps %xmm6,0x10(%rsp)
+ movaps %xmm7,0x20(%rsp)
+ movaps %xmm8,0x30(%rsp)
+ movaps %xmm9,0x40(%rsp)
+ movaps %xmm10,0x50(%rsp)
+ movaps %xmm11,0x60(%rsp)
+ movaps %xmm12,0x70(%rsp)
+ movaps %xmm13,0x80(%rsp)
+ movaps %xmm14,0x90(%rsp)
+ movaps %xmm15,0xa0(%rsp)
+.Ldec_key_body:
+___
+$code.=<<___;
+ mov %esi,%eax
+ shr \$5,%eax
+ add \$5,%eax
+ mov %eax,240(%rdx) # AES_KEY->rounds = nbits/32+5;
+ shl \$4,%eax
+ lea 16(%rdx,%rax),%rdx
+
+ mov \$1,%ecx
+ mov %esi,%r8d
+ shr \$1,%r8d
+ and \$32,%r8d
+ xor \$32,%r8d # nbits==192?0:32
+ call _vpaes_schedule_core
+___
+$code.=<<___ if ($win64);
+ movaps 0x10(%rsp),%xmm6
+ movaps 0x20(%rsp),%xmm7
+ movaps 0x30(%rsp),%xmm8
+ movaps 0x40(%rsp),%xmm9
+ movaps 0x50(%rsp),%xmm10
+ movaps 0x60(%rsp),%xmm11
+ movaps 0x70(%rsp),%xmm12
+ movaps 0x80(%rsp),%xmm13
+ movaps 0x90(%rsp),%xmm14
+ movaps 0xa0(%rsp),%xmm15
+ lea 0xb8(%rsp),%rsp
+.Ldec_key_epilogue:
+___
+$code.=<<___;
+ xor %eax,%eax
+ ret
+.size ${PREFIX}_set_decrypt_key,.-${PREFIX}_set_decrypt_key
+
+.globl ${PREFIX}_encrypt
+.type ${PREFIX}_encrypt,\@function,3
+.align 16
+${PREFIX}_encrypt:
+___
+$code.=<<___ if ($win64);
+ lea -0xb8(%rsp),%rsp
+ movaps %xmm6,0x10(%rsp)
+ movaps %xmm7,0x20(%rsp)
+ movaps %xmm8,0x30(%rsp)
+ movaps %xmm9,0x40(%rsp)
+ movaps %xmm10,0x50(%rsp)
+ movaps %xmm11,0x60(%rsp)
+ movaps %xmm12,0x70(%rsp)
+ movaps %xmm13,0x80(%rsp)
+ movaps %xmm14,0x90(%rsp)
+ movaps %xmm15,0xa0(%rsp)
+.Lenc_body:
+___
+$code.=<<___;
+ movdqu (%rdi),%xmm0
+ call _vpaes_preheat
+ call _vpaes_encrypt_core
+ movdqu %xmm0,(%rsi)
+___
+$code.=<<___ if ($win64);
+ movaps 0x10(%rsp),%xmm6
+ movaps 0x20(%rsp),%xmm7
+ movaps 0x30(%rsp),%xmm8
+ movaps 0x40(%rsp),%xmm9
+ movaps 0x50(%rsp),%xmm10
+ movaps 0x60(%rsp),%xmm11
+ movaps 0x70(%rsp),%xmm12
+ movaps 0x80(%rsp),%xmm13
+ movaps 0x90(%rsp),%xmm14
+ movaps 0xa0(%rsp),%xmm15
+ lea 0xb8(%rsp),%rsp
+.Lenc_epilogue:
+___
+$code.=<<___;
+ ret
+.size ${PREFIX}_encrypt,.-${PREFIX}_encrypt
+
+.globl ${PREFIX}_decrypt
+.type ${PREFIX}_decrypt,\@function,3
+.align 16
+${PREFIX}_decrypt:
+___
+$code.=<<___ if ($win64);
+ lea -0xb8(%rsp),%rsp
+ movaps %xmm6,0x10(%rsp)
+ movaps %xmm7,0x20(%rsp)
+ movaps %xmm8,0x30(%rsp)
+ movaps %xmm9,0x40(%rsp)
+ movaps %xmm10,0x50(%rsp)
+ movaps %xmm11,0x60(%rsp)
+ movaps %xmm12,0x70(%rsp)
+ movaps %xmm13,0x80(%rsp)
+ movaps %xmm14,0x90(%rsp)
+ movaps %xmm15,0xa0(%rsp)
+.Ldec_body:
+___
+$code.=<<___;
+ movdqu (%rdi),%xmm0
+ call _vpaes_preheat
+ call _vpaes_decrypt_core
+ movdqu %xmm0,(%rsi)
+___
+$code.=<<___ if ($win64);
+ movaps 0x10(%rsp),%xmm6
+ movaps 0x20(%rsp),%xmm7
+ movaps 0x30(%rsp),%xmm8
+ movaps 0x40(%rsp),%xmm9
+ movaps 0x50(%rsp),%xmm10
+ movaps 0x60(%rsp),%xmm11
+ movaps 0x70(%rsp),%xmm12
+ movaps 0x80(%rsp),%xmm13
+ movaps 0x90(%rsp),%xmm14
+ movaps 0xa0(%rsp),%xmm15
+ lea 0xb8(%rsp),%rsp
+.Ldec_epilogue:
+___
+$code.=<<___;
+ ret
+.size ${PREFIX}_decrypt,.-${PREFIX}_decrypt
+___
+{
+my ($inp,$out,$len,$key,$ivp,$enc)=("%rdi","%rsi","%rdx","%rcx","%r8","%r9");
+# void AES_cbc_encrypt (const void char *inp, unsigned char *out,
+# size_t length, const AES_KEY *key,
+# unsigned char *ivp,const int enc);
+$code.=<<___;
+.globl ${PREFIX}_cbc_encrypt
+.type ${PREFIX}_cbc_encrypt,\@function,6
+.align 16
+${PREFIX}_cbc_encrypt:
+ xchg $key,$len
+___
+($len,$key)=($key,$len);
+$code.=<<___;
+ sub \$16,$len
+ jc .Lcbc_abort
+___
+$code.=<<___ if ($win64);
+ lea -0xb8(%rsp),%rsp
+ movaps %xmm6,0x10(%rsp)
+ movaps %xmm7,0x20(%rsp)
+ movaps %xmm8,0x30(%rsp)
+ movaps %xmm9,0x40(%rsp)
+ movaps %xmm10,0x50(%rsp)
+ movaps %xmm11,0x60(%rsp)
+ movaps %xmm12,0x70(%rsp)
+ movaps %xmm13,0x80(%rsp)
+ movaps %xmm14,0x90(%rsp)
+ movaps %xmm15,0xa0(%rsp)
+.Lcbc_body:
+___
+$code.=<<___;
+ movdqu ($ivp),%xmm6 # load IV
+ sub $inp,$out
+ call _vpaes_preheat
+ cmp \$0,${enc}d
+ je .Lcbc_dec_loop
+ jmp .Lcbc_enc_loop
+.align 16
+.Lcbc_enc_loop:
+ movdqu ($inp),%xmm0
+ pxor %xmm6,%xmm0
+ call _vpaes_encrypt_core
+ movdqa %xmm0,%xmm6
+ movdqu %xmm0,($out,$inp)
+ lea 16($inp),$inp
+ sub \$16,$len
+ jnc .Lcbc_enc_loop
+ jmp .Lcbc_done
+.align 16
+.Lcbc_dec_loop:
+ movdqu ($inp),%xmm0
+ movdqa %xmm0,%xmm7
+ call _vpaes_decrypt_core
+ pxor %xmm6,%xmm0
+ movdqa %xmm7,%xmm6
+ movdqu %xmm0,($out,$inp)
+ lea 16($inp),$inp
+ sub \$16,$len
+ jnc .Lcbc_dec_loop
+.Lcbc_done:
+ movdqu %xmm6,($ivp) # save IV
+___
+$code.=<<___ if ($win64);
+ movaps 0x10(%rsp),%xmm6
+ movaps 0x20(%rsp),%xmm7
+ movaps 0x30(%rsp),%xmm8
+ movaps 0x40(%rsp),%xmm9
+ movaps 0x50(%rsp),%xmm10
+ movaps 0x60(%rsp),%xmm11
+ movaps 0x70(%rsp),%xmm12
+ movaps 0x80(%rsp),%xmm13
+ movaps 0x90(%rsp),%xmm14
+ movaps 0xa0(%rsp),%xmm15
+ lea 0xb8(%rsp),%rsp
+.Lcbc_epilogue:
+___
+$code.=<<___;
+.Lcbc_abort:
+ ret
+.size ${PREFIX}_cbc_encrypt,.-${PREFIX}_cbc_encrypt
+___
+}
+$code.=<<___;
+##
+## _aes_preheat
+##
+## Fills register %r10 -> .aes_consts (so you can -fPIC)
+## and %xmm9-%xmm15 as specified below.
+##
+.type _vpaes_preheat,\@abi-omnipotent
+.align 16
+_vpaes_preheat:
+ lea .Lk_s0F(%rip), %r10
+ movdqa -0x20(%r10), %xmm10 # .Lk_inv
+ movdqa -0x10(%r10), %xmm11 # .Lk_inv+16
+ movdqa 0x00(%r10), %xmm9 # .Lk_s0F
+ movdqa 0x30(%r10), %xmm13 # .Lk_sb1
+ movdqa 0x40(%r10), %xmm12 # .Lk_sb1+16
+ movdqa 0x50(%r10), %xmm15 # .Lk_sb2
+ movdqa 0x60(%r10), %xmm14 # .Lk_sb2+16
+ ret
+.size _vpaes_preheat,.-_vpaes_preheat
+########################################################
+## ##
+## Constants ##
+## ##
+########################################################
+.type _vpaes_consts,\@object
+.align 64
+_vpaes_consts:
+.Lk_inv: # inv, inva
+ .quad 0x0E05060F0D080180, 0x040703090A0B0C02
+ .quad 0x01040A060F0B0780, 0x030D0E0C02050809
+
+.Lk_s0F: # s0F
+ .quad 0x0F0F0F0F0F0F0F0F, 0x0F0F0F0F0F0F0F0F
+
+.Lk_ipt: # input transform (lo, hi)
+ .quad 0xC2B2E8985A2A7000, 0xCABAE09052227808
+ .quad 0x4C01307D317C4D00, 0xCD80B1FCB0FDCC81
+
+.Lk_sb1: # sb1u, sb1t
+ .quad 0xB19BE18FCB503E00, 0xA5DF7A6E142AF544
+ .quad 0x3618D415FAE22300, 0x3BF7CCC10D2ED9EF
+.Lk_sb2: # sb2u, sb2t
+ .quad 0xE27A93C60B712400, 0x5EB7E955BC982FCD
+ .quad 0x69EB88400AE12900, 0xC2A163C8AB82234A
+.Lk_sbo: # sbou, sbot
+ .quad 0xD0D26D176FBDC700, 0x15AABF7AC502A878
+ .quad 0xCFE474A55FBB6A00, 0x8E1E90D1412B35FA
+
+.Lk_mc_forward: # mc_forward
+ .quad 0x0407060500030201, 0x0C0F0E0D080B0A09
+ .quad 0x080B0A0904070605, 0x000302010C0F0E0D
+ .quad 0x0C0F0E0D080B0A09, 0x0407060500030201
+ .quad 0x000302010C0F0E0D, 0x080B0A0904070605
+
+.Lk_mc_backward:# mc_backward
+ .quad 0x0605040702010003, 0x0E0D0C0F0A09080B
+ .quad 0x020100030E0D0C0F, 0x0A09080B06050407
+ .quad 0x0E0D0C0F0A09080B, 0x0605040702010003
+ .quad 0x0A09080B06050407, 0x020100030E0D0C0F
+
+.Lk_sr: # sr
+ .quad 0x0706050403020100, 0x0F0E0D0C0B0A0908
+ .quad 0x030E09040F0A0500, 0x0B06010C07020D08
+ .quad 0x0F060D040B020900, 0x070E050C030A0108
+ .quad 0x0B0E0104070A0D00, 0x0306090C0F020508
+
+.Lk_rcon: # rcon
+ .quad 0x1F8391B9AF9DEEB6, 0x702A98084D7C7D81
+
+.Lk_s63: # s63: all equal to 0x63 transformed
+ .quad 0x5B5B5B5B5B5B5B5B, 0x5B5B5B5B5B5B5B5B
+
+.Lk_opt: # output transform
+ .quad 0xFF9F4929D6B66000, 0xF7974121DEBE6808
+ .quad 0x01EDBD5150BCEC00, 0xE10D5DB1B05C0CE0
+
+.Lk_deskew: # deskew tables: inverts the sbox's "skew"
+ .quad 0x07E4A34047A4E300, 0x1DFEB95A5DBEF91A
+ .quad 0x5F36B5DC83EA6900, 0x2841C2ABF49D1E77
+
+##
+## Decryption stuff
+## Key schedule constants
+##
+.Lk_dksd: # decryption key schedule: invskew x*D
+ .quad 0xFEB91A5DA3E44700, 0x0740E3A45A1DBEF9
+ .quad 0x41C277F4B5368300, 0x5FDC69EAAB289D1E
+.Lk_dksb: # decryption key schedule: invskew x*B
+ .quad 0x9A4FCA1F8550D500, 0x03D653861CC94C99
+ .quad 0x115BEDA7B6FC4A00, 0xD993256F7E3482C8
+.Lk_dkse: # decryption key schedule: invskew x*E + 0x63
+ .quad 0xD5031CCA1FC9D600, 0x53859A4C994F5086
+ .quad 0xA23196054FDC7BE8, 0xCD5EF96A20B31487
+.Lk_dks9: # decryption key schedule: invskew x*9
+ .quad 0xB6116FC87ED9A700, 0x4AED933482255BFC
+ .quad 0x4576516227143300, 0x8BB89FACE9DAFDCE
+
+##
+## Decryption stuff
+## Round function constants
+##
+.Lk_dipt: # decryption input transform
+ .quad 0x0F505B040B545F00, 0x154A411E114E451A
+ .quad 0x86E383E660056500, 0x12771772F491F194
+
+.Lk_dsb9: # decryption sbox output *9*u, *9*t
+ .quad 0x851C03539A86D600, 0xCAD51F504F994CC9
+ .quad 0xC03B1789ECD74900, 0x725E2C9EB2FBA565
+.Lk_dsbd: # decryption sbox output *D*u, *D*t
+ .quad 0x7D57CCDFE6B1A200, 0xF56E9B13882A4439
+ .quad 0x3CE2FAF724C6CB00, 0x2931180D15DEEFD3
+.Lk_dsbb: # decryption sbox output *B*u, *B*t
+ .quad 0xD022649296B44200, 0x602646F6B0F2D404
+ .quad 0xC19498A6CD596700, 0xF3FF0C3E3255AA6B
+.Lk_dsbe: # decryption sbox output *E*u, *E*t
+ .quad 0x46F2929626D4D000, 0x2242600464B4F6B0
+ .quad 0x0C55A6CDFFAAC100, 0x9467F36B98593E32
+.Lk_dsbo: # decryption sbox final output
+ .quad 0x1387EA537EF94000, 0xC7AA6DB9D4943E2D
+ .quad 0x12D7560F93441D00, 0xCA4B8159D8C58E9C
+.asciz "Vector Permutaion AES for x86_64/SSSE3, Mike Hamburg (Stanford University)"
+.align 64
+.size _vpaes_consts,.-_vpaes_consts
+___
+
+if ($win64) {
+# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
+# CONTEXT *context,DISPATCHER_CONTEXT *disp)
+$rec="%rcx";
+$frame="%rdx";
+$context="%r8";
+$disp="%r9";
+
+$code.=<<___;
+.extern __imp_RtlVirtualUnwind
+.type se_handler,\@abi-omnipotent
+.align 16
+se_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 120($context),%rax # pull context->Rax
+ mov 248($context),%rbx # pull context->Rip
+
+ mov 8($disp),%rsi # disp->ImageBase
+ mov 56($disp),%r11 # disp->HandlerData
+
+ mov 0(%r11),%r10d # HandlerData[0]
+ lea (%rsi,%r10),%r10 # prologue label
+ cmp %r10,%rbx # context->Rip<prologue label
+ jb .Lin_prologue
+
+ mov 152($context),%rax # pull context->Rsp
+
+ mov 4(%r11),%r10d # HandlerData[1]
+ lea (%rsi,%r10),%r10 # epilogue label
+ cmp %r10,%rbx # context->Rip>=epilogue label
+ jae .Lin_prologue
+
+ lea 16(%rax),%rsi # %xmm save area
+ lea 512($context),%rdi # &context.Xmm6
+ mov \$20,%ecx # 10*sizeof(%xmm0)/sizeof(%rax)
+ .long 0xa548f3fc # cld; rep movsq
+ lea 0xb8(%rax),%rax # adjust stack pointer
+
+.Lin_prologue:
+ mov 8(%rax),%rdi
+ mov 16(%rax),%rsi
+ mov %rax,152($context) # restore context->Rsp
+ mov %rsi,168($context) # restore context->Rsi
+ mov %rdi,176($context) # restore context->Rdi
+
+ mov 40($disp),%rdi # disp->ContextRecord
+ mov $context,%rsi # context
+ mov \$`1232/8`,%ecx # sizeof(CONTEXT)
+ .long 0xa548f3fc # cld; rep movsq
+
+ mov $disp,%rsi
+ xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER
+ mov 8(%rsi),%rdx # arg2, disp->ImageBase
+ mov 0(%rsi),%r8 # arg3, disp->ControlPc
+ mov 16(%rsi),%r9 # arg4, disp->FunctionEntry
+ mov 40(%rsi),%r10 # disp->ContextRecord
+ lea 56(%rsi),%r11 # &disp->HandlerData
+ lea 24(%rsi),%r12 # &disp->EstablisherFrame
+ mov %r10,32(%rsp) # arg5
+ mov %r11,40(%rsp) # arg6
+ mov %r12,48(%rsp) # arg7
+ mov %rcx,56(%rsp) # arg8, (NULL)
+ call *__imp_RtlVirtualUnwind(%rip)
+
+ mov \$1,%eax # ExceptionContinueSearch
+ add \$64,%rsp
+ popfq
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+ pop %rdi
+ pop %rsi
+ ret
+.size se_handler,.-se_handler
+
+.section .pdata
+.align 4
+ .rva .LSEH_begin_${PREFIX}_set_encrypt_key
+ .rva .LSEH_end_${PREFIX}_set_encrypt_key
+ .rva .LSEH_info_${PREFIX}_set_encrypt_key
+
+ .rva .LSEH_begin_${PREFIX}_set_decrypt_key
+ .rva .LSEH_end_${PREFIX}_set_decrypt_key
+ .rva .LSEH_info_${PREFIX}_set_decrypt_key
+
+ .rva .LSEH_begin_${PREFIX}_encrypt
+ .rva .LSEH_end_${PREFIX}_encrypt
+ .rva .LSEH_info_${PREFIX}_encrypt
+
+ .rva .LSEH_begin_${PREFIX}_decrypt
+ .rva .LSEH_end_${PREFIX}_decrypt
+ .rva .LSEH_info_${PREFIX}_decrypt
+
+ .rva .LSEH_begin_${PREFIX}_cbc_encrypt
+ .rva .LSEH_end_${PREFIX}_cbc_encrypt
+ .rva .LSEH_info_${PREFIX}_cbc_encrypt
+
+.section .xdata
+.align 8
+.LSEH_info_${PREFIX}_set_encrypt_key:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lenc_key_body,.Lenc_key_epilogue # HandlerData[]
+.LSEH_info_${PREFIX}_set_decrypt_key:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Ldec_key_body,.Ldec_key_epilogue # HandlerData[]
+.LSEH_info_${PREFIX}_encrypt:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lenc_body,.Lenc_epilogue # HandlerData[]
+.LSEH_info_${PREFIX}_decrypt:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Ldec_body,.Ldec_epilogue # HandlerData[]
+.LSEH_info_${PREFIX}_cbc_encrypt:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lcbc_body,.Lcbc_epilogue # HandlerData[]
+___
+}
+
+$code =~ s/\`([^\`]*)\`/eval($1)/gem;
+
+print $code;
+
+close STDOUT;
diff --git a/crypto/aes/internal.h b/crypto/aes/internal.h
new file mode 100644
index 0000000..3dc5c63
--- /dev/null
+++ b/crypto/aes/internal.h
@@ -0,0 +1,87 @@
+/* ====================================================================
+ * Copyright (c) 2002-2006 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.
+ * ==================================================================== */
+
+#ifndef OPENSSL_HEADER_AES_INTERNAL_H
+#define OPENSSL_HEADER_AES_INTERNAL_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+#if defined(_MSC_VER) && \
+ (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64))
+#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
+#define GETU32(p) SWAP(*((uint32_t *)(p)))
+#define PUTU32(ct, st) \
+ { *((uint32_t *)(ct)) = SWAP((st)); }
+#else
+#define GETU32(pt) \
+ (((uint32_t)(pt)[0] << 24) ^ ((uint32_t)(pt)[1] << 16) ^ \
+ ((uint32_t)(pt)[2] << 8) ^ ((uint32_t)(pt)[3]))
+#define PUTU32(ct, st) \
+ { \
+ (ct)[0] = (uint8_t)((st) >> 24); \
+ (ct)[1] = (uint8_t)((st) >> 16); \
+ (ct)[2] = (uint8_t)((st) >> 8); \
+ (ct)[3] = (uint8_t)(st); \
+ }
+#endif
+
+#define MAXKC (256 / 32)
+#define MAXKB (256 / 8)
+#define MAXNR 14
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_AES_INTERNAL_H */
diff --git a/crypto/aes/mode_wrappers.c b/crypto/aes/mode_wrappers.c
new file mode 100644
index 0000000..0ee2326
--- /dev/null
+++ b/crypto/aes/mode_wrappers.c
@@ -0,0 +1,99 @@
+/* ====================================================================
+ * Copyright (c) 2002-2006 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.
+ * ==================================================================== */
+
+#include <openssl/aes.h>
+
+#include "assert.h"
+
+#include <openssl/modes.h>
+
+
+void AES_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
+ const AES_KEY *key, uint8_t ivec[AES_BLOCK_SIZE],
+ uint8_t ecount_buf[AES_BLOCK_SIZE], unsigned int *num) {
+ CRYPTO_ctr128_encrypt(in, out, len, key, ivec, ecount_buf, num,
+ (block128_f)AES_encrypt);
+}
+
+void AES_ecb_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key,
+ const int enc) {
+ assert(in && out && key);
+ assert((AES_ENCRYPT == enc) || (AES_DECRYPT == enc));
+
+ if (AES_ENCRYPT == enc) {
+ AES_encrypt(in, out, key);
+ } else {
+ AES_decrypt(in, out, key);
+ }
+}
+
+#if defined(OPENSSL_NO_ASM) || \
+ (!defined(OPENSSL_X86_64) && !defined(OPENSSL_X86))
+void AES_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len,
+ const AES_KEY *key, uint8_t *ivec, const int enc) {
+
+ if (enc) {
+ CRYPTO_cbc128_encrypt(in, out, len, key, ivec, (block128_f)AES_encrypt);
+ } else {
+ CRYPTO_cbc128_decrypt(in, out, len, key, ivec, (block128_f)AES_decrypt);
+ }
+}
+#endif
+
+void AES_ofb128_encrypt(const uint8_t *in, uint8_t *out, size_t length,
+ const AES_KEY *key, uint8_t *ivec, int *num) {
+ CRYPTO_ofb128_encrypt(in, out, length, key, ivec, num,
+ (block128_f)AES_encrypt);
+}
+
+void AES_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t length,
+ const AES_KEY *key, uint8_t *ivec, int *num,
+ int enc) {
+ CRYPTO_cfb128_encrypt(in, out, length, key, ivec, num, enc,
+ (block128_f)AES_encrypt);
+}
diff --git a/crypto/arm_arch.h b/crypto/arm_arch.h
new file mode 100644
index 0000000..d528eee
--- /dev/null
+++ b/crypto/arm_arch.h
@@ -0,0 +1,100 @@
+/* ====================================================================
+ * 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__)
+ /* 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. */
+# if 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
+
+#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 unsigned int OPENSSL_armcap_P;
+
+#define ARMV7_NEON (1<<0)
+#endif
+
+
+#endif /* OPENSSL_HEADER_THREAD_H */
diff --git a/crypto/asn1/CMakeLists.txt b/crypto/asn1/CMakeLists.txt
new file mode 100644
index 0000000..884ecd2
--- /dev/null
+++ b/crypto/asn1/CMakeLists.txt
@@ -0,0 +1,46 @@
+include_directories(. .. ../../include)
+
+add_library(
+ asn1
+
+ OBJECT
+
+ a_bitstr.c
+ a_bool.c
+ a_bytes.c
+ a_d2i_fp.c
+ a_dup.c
+ a_enum.c
+ a_gentm.c
+ a_i2d_fp.c
+ a_int.c
+ a_mbstr.c
+ a_object.c
+ a_octet.c
+ a_print.c
+ a_strnid.c
+ a_time.c
+ a_type.c
+ a_utctm.c
+ a_utf8.c
+ asn1_error.c
+ asn1_lib.c
+ asn1_par.c
+ asn_pack.c
+ bio_asn1.c
+ bio_ndef.c
+ f_enum.c
+ f_int.c
+ f_string.c
+ t_bitst.c
+ t_pkey.c
+ tasn_dec.c
+ tasn_enc.c
+ tasn_fre.c
+ tasn_new.c
+ tasn_prn.c
+ tasn_typ.c
+ tasn_utl.c
+ x_bignum.c
+ x_long.c
+)
diff --git a/crypto/asn1/a_bitstr.c b/crypto/asn1/a_bitstr.c
new file mode 100644
index 0000000..4917bda
--- /dev/null
+++ b/crypto/asn1/a_bitstr.c
@@ -0,0 +1,247 @@
+/* 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/asn1.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+int ASN1_BIT_STRING_set(ASN1_BIT_STRING *x, unsigned char *d, int len)
+{ return M_ASN1_BIT_STRING_set(x, d, len); }
+
+int i2c_ASN1_BIT_STRING(ASN1_BIT_STRING *a, unsigned char **pp)
+ {
+ int ret,j,bits,len;
+ unsigned char *p,*d;
+
+ if (a == NULL) return(0);
+
+ len=a->length;
+
+ if (len > 0)
+ {
+ if (a->flags & ASN1_STRING_FLAG_BITS_LEFT)
+ {
+ bits=(int)a->flags&0x07;
+ }
+ else
+ {
+ for ( ; len > 0; len--)
+ {
+ if (a->data[len-1]) break;
+ }
+ j=a->data[len-1];
+ if (j & 0x01) bits=0;
+ else if (j & 0x02) bits=1;
+ else if (j & 0x04) bits=2;
+ else if (j & 0x08) bits=3;
+ else if (j & 0x10) bits=4;
+ else if (j & 0x20) bits=5;
+ else if (j & 0x40) bits=6;
+ else if (j & 0x80) bits=7;
+ else bits=0; /* should not happen */
+ }
+ }
+ else
+ bits=0;
+
+ ret=1+len;
+ if (pp == NULL) return(ret);
+
+ p= *pp;
+
+ *(p++)=(unsigned char)bits;
+ d=a->data;
+ memcpy(p,d,len);
+ p+=len;
+ if (len > 0) p[-1]&=(0xff<<bits);
+ *pp=p;
+ return(ret);
+ }
+
+ASN1_BIT_STRING *c2i_ASN1_BIT_STRING(ASN1_BIT_STRING **a,
+ const unsigned char **pp, long len)
+ {
+ ASN1_BIT_STRING *ret=NULL;
+ const unsigned char *p;
+ unsigned char *s;
+ int i;
+
+ if (len < 1)
+ {
+ i=ASN1_R_STRING_TOO_SHORT;
+ goto err;
+ }
+
+ if ((a == NULL) || ((*a) == NULL))
+ {
+ if ((ret=M_ASN1_BIT_STRING_new()) == NULL) return(NULL);
+ }
+ else
+ ret=(*a);
+
+ p= *pp;
+ i= *(p++);
+ /* We do this to preserve the settings. If we modify
+ * the settings, via the _set_bit function, we will recalculate
+ * on output */
+ ret->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); /* clear */
+ ret->flags|=(ASN1_STRING_FLAG_BITS_LEFT|(i&0x07)); /* set */
+
+ if (len-- > 1) /* using one because of the bits left byte */
+ {
+ s=(unsigned char *)OPENSSL_malloc((int)len);
+ if (s == NULL)
+ {
+ i=ERR_R_MALLOC_FAILURE;
+ goto err;
+ }
+ memcpy(s,p,(int)len);
+ s[len-1]&=(0xff<<i);
+ p+=len;
+ }
+ else
+ s=NULL;
+
+ ret->length=(int)len;
+ if (ret->data != NULL) OPENSSL_free(ret->data);
+ ret->data=s;
+ ret->type=V_ASN1_BIT_STRING;
+ if (a != NULL) (*a)=ret;
+ *pp=p;
+ return(ret);
+err:
+ OPENSSL_PUT_ERROR(ASN1, c2i_ASN1_BIT_STRING, i);
+ if ((ret != NULL) && ((a == NULL) || (*a != ret)))
+ M_ASN1_BIT_STRING_free(ret);
+ return(NULL);
+ }
+
+/* These next 2 functions from Goetz Babin-Ebell <babinebell@trustcenter.de>
+ */
+int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value)
+ {
+ int w,v,iv;
+ unsigned char *c;
+
+ w=n/8;
+ v=1<<(7-(n&0x07));
+ iv= ~v;
+ if (!value) v=0;
+
+ if (a == NULL)
+ return 0;
+
+ a->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); /* clear, set on write */
+
+ if ((a->length < (w+1)) || (a->data == NULL))
+ {
+ if (!value) return(1); /* Don't need to set */
+ if (a->data == NULL)
+ c=(unsigned char *)OPENSSL_malloc(w+1);
+ else
+ c=(unsigned char *)OPENSSL_realloc_clean(a->data,
+ a->length,
+ w+1);
+ if (c == NULL)
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_BIT_STRING_set_bit, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ if (w+1-a->length > 0) memset(c+a->length, 0, w+1-a->length);
+ a->data=c;
+ a->length=w+1;
+ }
+ a->data[w]=((a->data[w])&iv)|v;
+ while ((a->length > 0) && (a->data[a->length-1] == 0))
+ a->length--;
+ return(1);
+ }
+
+int ASN1_BIT_STRING_get_bit(ASN1_BIT_STRING *a, int n)
+ {
+ int w,v;
+
+ w=n/8;
+ v=1<<(7-(n&0x07));
+ if ((a == NULL) || (a->length < (w+1)) || (a->data == NULL))
+ return(0);
+ return((a->data[w]&v) != 0);
+ }
+
+/*
+ * Checks if the given bit string contains only bits specified by
+ * the flags vector. Returns 0 if there is at least one bit set in 'a'
+ * which is not specified in 'flags', 1 otherwise.
+ * 'len' is the length of 'flags'.
+ */
+int ASN1_BIT_STRING_check(ASN1_BIT_STRING *a,
+ unsigned char *flags, int flags_len)
+ {
+ int i, ok;
+ /* Check if there is one bit set at all. */
+ if (!a || !a->data) return 1;
+
+ /* Check each byte of the internal representation of the bit string. */
+ ok = 1;
+ for (i = 0; i < a->length && ok; ++i)
+ {
+ unsigned char mask = i < flags_len ? ~flags[i] : 0xff;
+ /* We are done if there is an unneeded bit set. */
+ ok = (a->data[i] & mask) == 0;
+ }
+ return ok;
+ }
diff --git a/crypto/asn1/a_bool.c b/crypto/asn1/a_bool.c
new file mode 100644
index 0000000..c30ee48
--- /dev/null
+++ b/crypto/asn1/a_bool.c
@@ -0,0 +1,112 @@
+/* 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/asn1.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+int i2d_ASN1_BOOLEAN(int a, unsigned char **pp)
+ {
+ int r;
+ unsigned char *p;
+
+ r=ASN1_object_size(0,1,V_ASN1_BOOLEAN);
+ if (pp == NULL) return(r);
+ p= *pp;
+
+ ASN1_put_object(&p,0,1,V_ASN1_BOOLEAN,V_ASN1_UNIVERSAL);
+ *(p++)= (unsigned char)a;
+ *pp=p;
+ return(r);
+ }
+
+int d2i_ASN1_BOOLEAN(int *a, const unsigned char **pp, long length)
+ {
+ int ret= -1;
+ const unsigned char *p;
+ long len;
+ int inf,tag,xclass;
+ int i=0;
+
+ p= *pp;
+ inf=ASN1_get_object(&p,&len,&tag,&xclass,length);
+ if (inf & 0x80)
+ {
+ i=ASN1_R_BAD_OBJECT_HEADER;
+ goto err;
+ }
+
+ if (tag != V_ASN1_BOOLEAN)
+ {
+ i=ASN1_R_EXPECTING_A_BOOLEAN;
+ goto err;
+ }
+
+ if (len != 1)
+ {
+ i=ASN1_R_BOOLEAN_IS_WRONG_LENGTH;
+ goto err;
+ }
+ ret= (int)*(p++);
+ if (a != NULL) (*a)=ret;
+ *pp=p;
+ return(ret);
+err:
+ OPENSSL_PUT_ERROR(ASN1, d2i_ASN1_BOOLEAN, i);
+ return(ret);
+ }
diff --git a/crypto/asn1/a_bytes.c b/crypto/asn1/a_bytes.c
new file mode 100644
index 0000000..b9dd816
--- /dev/null
+++ b/crypto/asn1/a_bytes.c
@@ -0,0 +1,315 @@
+/* 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/asn1.h>
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+static int asn1_collate_primitive(ASN1_STRING *a, ASN1_const_CTX *c);
+/* type is a 'bitmap' of acceptable string types.
+ */
+ASN1_STRING *d2i_ASN1_type_bytes(ASN1_STRING **a, const unsigned char **pp,
+ long length, int type)
+ {
+ ASN1_STRING *ret=NULL;
+ const unsigned char *p;
+ unsigned char *s;
+ long len;
+ int inf,tag,xclass;
+ int i=0;
+
+ p= *pp;
+ inf=ASN1_get_object(&p,&len,&tag,&xclass,length);
+ if (inf & 0x80) goto err;
+
+ if (tag >= 32)
+ {
+ i=ASN1_R_TAG_VALUE_TOO_HIGH;
+ goto err;
+ }
+ if (!(ASN1_tag2bit(tag) & type))
+ {
+ i=ASN1_R_WRONG_TYPE;
+ goto err;
+ }
+
+ /* If a bit-string, exit early */
+ if (tag == V_ASN1_BIT_STRING)
+ return(d2i_ASN1_BIT_STRING(a,pp,length));
+
+ if ((a == NULL) || ((*a) == NULL))
+ {
+ if ((ret=ASN1_STRING_new()) == NULL) return(NULL);
+ }
+ else
+ ret=(*a);
+
+ if (len != 0)
+ {
+ s=(unsigned char *)OPENSSL_malloc((int)len+1);
+ if (s == NULL)
+ {
+ i=ERR_R_MALLOC_FAILURE;
+ goto err;
+ }
+ memcpy(s,p,(int)len);
+ s[len]='\0';
+ p+=len;
+ }
+ else
+ s=NULL;
+
+ if (ret->data != NULL) OPENSSL_free(ret->data);
+ ret->length=(int)len;
+ ret->data=s;
+ ret->type=tag;
+ if (a != NULL) (*a)=ret;
+ *pp=p;
+ return(ret);
+err:
+ OPENSSL_PUT_ERROR(ASN1, d2i_ASN1_type_bytes, i);
+ if ((ret != NULL) && ((a == NULL) || (*a != ret)))
+ ASN1_STRING_free(ret);
+ return(NULL);
+ }
+
+int i2d_ASN1_bytes(ASN1_STRING *a, unsigned char **pp, int tag, int xclass)
+ {
+ int ret,r,constructed;
+ unsigned char *p;
+
+ if (a == NULL) return(0);
+
+ if (tag == V_ASN1_BIT_STRING)
+ return(i2d_ASN1_BIT_STRING(a,pp));
+
+ ret=a->length;
+ r=ASN1_object_size(0,ret,tag);
+ if (pp == NULL) return(r);
+ p= *pp;
+
+ if ((tag == V_ASN1_SEQUENCE) || (tag == V_ASN1_SET))
+ constructed=1;
+ else
+ constructed=0;
+ ASN1_put_object(&p,constructed,ret,tag,xclass);
+ memcpy(p,a->data,a->length);
+ p+=a->length;
+ *pp= p;
+ return(r);
+ }
+
+ASN1_STRING *d2i_ASN1_bytes(ASN1_STRING **a, const unsigned char **pp,
+ long length, int Ptag, int Pclass)
+ {
+ ASN1_STRING *ret=NULL;
+ const unsigned char *p;
+ unsigned char *s;
+ long len;
+ int inf,tag,xclass;
+ int i=0;
+
+ if ((a == NULL) || ((*a) == NULL))
+ {
+ if ((ret=ASN1_STRING_new()) == NULL) return(NULL);
+ }
+ else
+ ret=(*a);
+
+ p= *pp;
+ inf=ASN1_get_object(&p,&len,&tag,&xclass,length);
+ if (inf & 0x80)
+ {
+ i=ASN1_R_BAD_OBJECT_HEADER;
+ goto err;
+ }
+
+ if (tag != Ptag)
+ {
+ i=ASN1_R_WRONG_TAG;
+ goto err;
+ }
+
+ if (inf & V_ASN1_CONSTRUCTED)
+ {
+ ASN1_const_CTX c;
+
+ c.pp=pp;
+ c.p=p;
+ c.inf=inf;
+ c.slen=len;
+ c.tag=Ptag;
+ c.xclass=Pclass;
+ c.max=(length == 0)?0:(p+length);
+ if (!asn1_collate_primitive(ret,&c))
+ goto err;
+ else
+ {
+ p=c.p;
+ }
+ }
+ else
+ {
+ if (len != 0)
+ {
+ if ((ret->length < len) || (ret->data == NULL))
+ {
+ if (ret->data != NULL) OPENSSL_free(ret->data);
+ s=(unsigned char *)OPENSSL_malloc((int)len + 1);
+ if (s == NULL)
+ {
+ i=ERR_R_MALLOC_FAILURE;
+ goto err;
+ }
+ }
+ else
+ s=ret->data;
+ memcpy(s,p,(int)len);
+ s[len] = '\0';
+ p+=len;
+ }
+ else
+ {
+ s=NULL;
+ if (ret->data != NULL) OPENSSL_free(ret->data);
+ }
+
+ ret->length=(int)len;
+ ret->data=s;
+ ret->type=Ptag;
+ }
+
+ if (a != NULL) (*a)=ret;
+ *pp=p;
+ return(ret);
+err:
+ if ((ret != NULL) && ((a == NULL) || (*a != ret)))
+ ASN1_STRING_free(ret);
+ OPENSSL_PUT_ERROR(ASN1, d2i_ASN1_bytes, i);
+ return(NULL);
+ }
+
+
+/* We are about to parse 0..n d2i_ASN1_bytes objects, we are to collapse
+ * them into the one structure that is then returned */
+/* There have been a few bug fixes for this function from
+ * Paul Keogh <paul.keogh@sse.ie>, many thanks to him */
+static int asn1_collate_primitive(ASN1_STRING *a, ASN1_const_CTX *c)
+ {
+ ASN1_STRING *os=NULL;
+ BUF_MEM b;
+ int num;
+
+ b.length=0;
+ b.max=0;
+ b.data=NULL;
+
+ if (a == NULL)
+ {
+ c->error=ERR_R_PASSED_NULL_PARAMETER;
+ goto err;
+ }
+
+ num=0;
+ for (;;)
+ {
+ if (c->inf & 1)
+ {
+ c->eos=ASN1_const_check_infinite_end(&c->p,
+ (long)(c->max-c->p));
+ if (c->eos) break;
+ }
+ else
+ {
+ if (c->slen <= 0) break;
+ }
+
+ c->q=c->p;
+ if (d2i_ASN1_bytes(&os,&c->p,c->max-c->p,c->tag,c->xclass)
+ == NULL)
+ {
+ c->error=ERR_R_ASN1_LIB;
+ goto err;
+ }
+
+ if (!BUF_MEM_grow_clean(&b,num+os->length))
+ {
+ c->error=ERR_R_BUF_LIB;
+ goto err;
+ }
+ memcpy(&(b.data[num]),os->data,os->length);
+ if (!(c->inf & 1))
+ c->slen-=(c->p-c->q);
+ num+=os->length;
+ }
+
+ if (!asn1_const_Finish(c)) goto err;
+
+ a->length=num;
+ if (a->data != NULL) OPENSSL_free(a->data);
+ a->data=(unsigned char *)b.data;
+ if (os != NULL) ASN1_STRING_free(os);
+ return(1);
+err:
+ OPENSSL_PUT_ERROR(ASN1, asn1_collate_primitive, c->error);
+ if (os != NULL) ASN1_STRING_free(os);
+ if (b.data != NULL) OPENSSL_free(b.data);
+ return(0);
+ }
+
diff --git a/crypto/asn1/a_d2i_fp.c b/crypto/asn1/a_d2i_fp.c
new file mode 100644
index 0000000..c28532b
--- /dev/null
+++ b/crypto/asn1/a_d2i_fp.c
@@ -0,0 +1,286 @@
+/* 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/asn1.h>
+
+#include <limits.h>
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb);
+
+#ifndef NO_OLD_ASN1
+#ifndef OPENSSL_NO_FP_API
+
+void *ASN1_d2i_fp(void *(*xnew)(void), d2i_of_void *d2i, FILE *in, void **x)
+ {
+ BIO *b;
+ void *ret;
+
+ if ((b=BIO_new(BIO_s_file())) == NULL)
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_d2i_fp, ERR_R_BUF_LIB);
+ return(NULL);
+ }
+ BIO_set_fp(b,in,BIO_NOCLOSE);
+ ret=ASN1_d2i_bio(xnew,d2i,b,x);
+ BIO_free(b);
+ return(ret);
+ }
+#endif
+
+void *ASN1_d2i_bio(void *(*xnew)(void), d2i_of_void *d2i, BIO *in, void **x)
+ {
+ BUF_MEM *b = NULL;
+ const unsigned char *p;
+ void *ret=NULL;
+ int len;
+
+ len = asn1_d2i_read_bio(in, &b);
+ if(len < 0) goto err;
+
+ p=(unsigned char *)b->data;
+ ret=d2i(x,&p,len);
+err:
+ if (b != NULL) BUF_MEM_free(b);
+ return(ret);
+ }
+
+#endif
+
+void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x)
+ {
+ BUF_MEM *b = NULL;
+ const unsigned char *p;
+ void *ret=NULL;
+ int len;
+
+ len = asn1_d2i_read_bio(in, &b);
+ if(len < 0) goto err;
+
+ p=(const unsigned char *)b->data;
+ ret=ASN1_item_d2i(x,&p,len, it);
+err:
+ if (b != NULL) BUF_MEM_free(b);
+ return(ret);
+ }
+
+#ifndef OPENSSL_NO_FP_API
+void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x)
+ {
+ BIO *b;
+ char *ret;
+
+ if ((b=BIO_new(BIO_s_file())) == NULL)
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_item_d2i_fp, ERR_R_BUF_LIB);
+ return(NULL);
+ }
+ BIO_set_fp(b,in,BIO_NOCLOSE);
+ ret=ASN1_item_d2i_bio(it,b,x);
+ BIO_free(b);
+ return(ret);
+ }
+#endif
+
+#define HEADER_SIZE 8
+static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
+ {
+ BUF_MEM *b;
+ unsigned char *p;
+ int i;
+ ASN1_const_CTX c;
+ size_t want=HEADER_SIZE;
+ int eos=0;
+ size_t off=0;
+ size_t len=0;
+
+ b=BUF_MEM_new();
+ if (b == NULL)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_d2i_read_bio, ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+
+ ERR_clear_error();
+ for (;;)
+ {
+ if (want >= (len-off))
+ {
+ want-=(len-off);
+
+ if (len + want < len || !BUF_MEM_grow_clean(b,len+want))
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_d2i_read_bio, 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);
+ goto err;
+ }
+ if (i > 0)
+ {
+ if (len+i < len)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_d2i_read_bio, ASN1_R_TOO_LONG);
+ goto err;
+ }
+ len+=i;
+ }
+ }
+ /* else data already loaded */
+
+ p=(unsigned char *)&(b->data[off]);
+ c.p=p;
+ c.inf=ASN1_get_object(&(c.p),&(c.slen),&(c.tag),&(c.xclass),
+ len-off);
+ if (c.inf & 0x80)
+ {
+ unsigned long e;
+
+ e=ERR_GET_REASON(ERR_peek_error());
+ if (e != ASN1_R_TOO_LONG)
+ goto err;
+ else
+ ERR_clear_error(); /* clear error */
+ }
+ i=c.p-p;/* header length */
+ off+=i; /* end of data */
+
+ if (c.inf & 1)
+ {
+ /* no data body so go round again */
+ eos++;
+ if (eos < 0)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_d2i_read_bio, ASN1_R_HEADER_TOO_LONG);
+ goto err;
+ }
+ want=HEADER_SIZE;
+ }
+ else if (eos && (c.slen == 0) && (c.tag == V_ASN1_EOC))
+ {
+ /* eos value, so go back and read another header */
+ eos--;
+ if (eos <= 0)
+ break;
+ else
+ want=HEADER_SIZE;
+ }
+ else
+ {
+ /* suck in c.slen bytes of data */
+ want=c.slen;
+ if (want > (len-off))
+ {
+ want-=(len-off);
+ 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);
+ goto err;
+ }
+ if (!BUF_MEM_grow_clean(b,len+want))
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_d2i_read_bio, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ while (want > 0)
+ {
+ i=BIO_read(in,&(b->data[len]),want);
+ if (i <= 0)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_d2i_read_bio, ASN1_R_NOT_ENOUGH_DATA);
+ goto err;
+ }
+ /* This can't overflow because
+ * |len+want| didn't overflow. */
+ len+=i;
+ want-=i;
+ }
+ }
+ if (off + c.slen < off)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_d2i_read_bio, ASN1_R_TOO_LONG);
+ goto err;
+ }
+ off+=c.slen;
+ if (eos <= 0)
+ {
+ break;
+ }
+ else
+ want=HEADER_SIZE;
+ }
+ }
+
+ if (off > INT_MAX)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_d2i_read_bio, ASN1_R_TOO_LONG);
+ goto err;
+ }
+
+ *pb = b;
+ return off;
+err:
+ if (b != NULL) BUF_MEM_free(b);
+ return -1;
+ }
diff --git a/crypto/asn1/a_dup.c b/crypto/asn1/a_dup.c
new file mode 100644
index 0000000..8ec1c5f
--- /dev/null
+++ b/crypto/asn1/a_dup.c
@@ -0,0 +1,103 @@
+/* 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/asn1.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+void *ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, void *x)
+ {
+ unsigned char *b,*p;
+ const unsigned char *p2;
+ int i;
+ char *ret;
+
+ if (x == NULL) return(NULL);
+
+ i=i2d(x,NULL);
+ b=OPENSSL_malloc(i+10);
+ if (b == NULL)
+ { OPENSSL_PUT_ERROR(ASN1, ASN1_dup, ERR_R_MALLOC_FAILURE); return(NULL); }
+ p= b;
+ i=i2d(x,&p);
+ p2= b;
+ ret=d2i(NULL,&p2,i);
+ OPENSSL_free(b);
+ return(ret);
+ }
+
+/* ASN1_ITEM version of dup: this follows the model above except we don't need
+ * to allocate the buffer. At some point this could be rewritten to directly dup
+ * the underlying structure instead of doing and encode and decode. */
+void *ASN1_item_dup(const ASN1_ITEM *it, void *x)
+ {
+ unsigned char *b = NULL;
+ const unsigned char *p;
+ long i;
+ void *ret;
+
+ if (x == NULL) return(NULL);
+
+ i=ASN1_item_i2d(x,&b,it);
+ if (b == NULL)
+ { OPENSSL_PUT_ERROR(ASN1, ASN1_item_dup, ERR_R_MALLOC_FAILURE); return(NULL); }
+ p= b;
+ ret=ASN1_item_d2i(NULL,&p,i, it);
+ OPENSSL_free(b);
+ return(ret);
+ }
diff --git a/crypto/asn1/a_enum.c b/crypto/asn1/a_enum.c
new file mode 100644
index 0000000..d6d237a
--- /dev/null
+++ b/crypto/asn1/a_enum.c
@@ -0,0 +1,181 @@
+/* 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/asn1.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+/*
+ * Code for ENUMERATED type: identical to INTEGER apart from a different tag.
+ * for comments on encoding see a_int.c
+ */
+
+int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v)
+ {
+ int j,k;
+ unsigned int i;
+ unsigned char buf[sizeof(long)+1];
+ long d;
+
+ a->type=V_ASN1_ENUMERATED;
+ if (a->length < (int)(sizeof(long)+1))
+ {
+ if (a->data != NULL)
+ OPENSSL_free(a->data);
+ if ((a->data=(unsigned char *)OPENSSL_malloc(sizeof(long)+1)) != NULL)
+ memset((char *)a->data,0,sizeof(long)+1);
+ }
+ if (a->data == NULL)
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_ENUMERATED_set, ERR_R_MALLOC_FAILURE);
+ return(0);
+ }
+ d=v;
+ if (d < 0)
+ {
+ d= -d;
+ a->type=V_ASN1_NEG_ENUMERATED;
+ }
+
+ for (i=0; i<sizeof(long); i++)
+ {
+ if (d == 0) break;
+ buf[i]=(int)d&0xff;
+ d>>=8;
+ }
+ j=0;
+ for (k=i-1; k >=0; k--)
+ a->data[j++]=buf[k];
+ a->length=j;
+ return(1);
+ }
+
+long ASN1_ENUMERATED_get(ASN1_ENUMERATED *a)
+ {
+ int neg=0,i;
+ long r=0;
+
+ if (a == NULL) return(0L);
+ i=a->type;
+ if (i == V_ASN1_NEG_ENUMERATED)
+ neg=1;
+ else if (i != V_ASN1_ENUMERATED)
+ return -1;
+
+ if (a->length > (int)sizeof(long))
+ {
+ /* hmm... a bit ugly */
+ return(0xffffffffL);
+ }
+ if (a->data == NULL)
+ return 0;
+
+ for (i=0; i<a->length; i++)
+ {
+ r<<=8;
+ r|=(unsigned char)a->data[i];
+ }
+ if (neg) r= -r;
+ return(r);
+ }
+
+ASN1_ENUMERATED *BN_to_ASN1_ENUMERATED(BIGNUM *bn, ASN1_ENUMERATED *ai)
+ {
+ ASN1_ENUMERATED *ret;
+ int len,j;
+
+ if (ai == NULL)
+ ret=M_ASN1_ENUMERATED_new();
+ else
+ ret=ai;
+ if (ret == NULL)
+ {
+ OPENSSL_PUT_ERROR(ASN1, BN_to_ASN1_ENUMERATED, ASN1_R_NESTED_ASN1_ERROR);
+ goto err;
+ }
+ if(BN_is_negative(bn)) ret->type = V_ASN1_NEG_ENUMERATED;
+ else ret->type=V_ASN1_ENUMERATED;
+ j=BN_num_bits(bn);
+ len=((j == 0)?0:((j/8)+1));
+ if (ret->length < len+4)
+ {
+ 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);
+ goto err;
+ }
+ ret->data=new_data;
+ }
+
+ ret->length=BN_bn2bin(bn,ret->data);
+ return(ret);
+err:
+ if (ret != ai) M_ASN1_ENUMERATED_free(ret);
+ return(NULL);
+ }
+
+BIGNUM *ASN1_ENUMERATED_to_BN(ASN1_ENUMERATED *ai, BIGNUM *bn)
+ {
+ BIGNUM *ret;
+
+ if ((ret=BN_bin2bn(ai->data,ai->length,bn)) == NULL)
+ OPENSSL_PUT_ERROR(ASN1, ASN1_ENUMERATED_to_BN, ASN1_R_BN_LIB);
+ else if(ai->type == V_ASN1_NEG_ENUMERATED) BN_set_negative(ret,1);
+ return(ret);
+ }
diff --git a/crypto/asn1/a_gentm.c b/crypto/asn1/a_gentm.c
new file mode 100644
index 0000000..1b8d78e
--- /dev/null
+++ b/crypto/asn1/a_gentm.c
@@ -0,0 +1,255 @@
+/* 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/asn1.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/time_support.h>
+
+
+int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d)
+ {
+ static const int min[9]={ 0, 0, 1, 1, 0, 0, 0, 0, 0};
+ static const int max[9]={99, 99,12,31,23,59,59,12,59};
+ char *a;
+ int n,i,l,o;
+
+ if (d->type != V_ASN1_GENERALIZEDTIME) return(0);
+ l=d->length;
+ a=(char *)d->data;
+ o=0;
+ /* GENERALIZEDTIME is similar to UTCTIME except the year is
+ * represented as YYYY. This stuff treats everything as a two digit
+ * field so make first two fields 00 to 99
+ */
+ if (l < 13) goto err;
+ for (i=0; i<7; i++)
+ {
+ if ((i == 6) && ((a[o] == 'Z') ||
+ (a[o] == '+') || (a[o] == '-')))
+ {
+ i++;
+ if (tm)
+ tm->tm_sec = 0;
+ break;
+ }
+ if ((a[o] < '0') || (a[o] > '9')) goto err;
+ n= a[o]-'0';
+ if (++o > l) goto err;
+
+ if ((a[o] < '0') || (a[o] > '9')) goto err;
+ n=(n*10)+ a[o]-'0';
+ if (++o > l) goto err;
+
+ if ((n < min[i]) || (n > max[i])) goto err;
+ if (tm)
+ {
+ switch(i)
+ {
+ case 0:
+ tm->tm_year = n * 100 - 1900;
+ break;
+ case 1:
+ tm->tm_year += n;
+ break;
+ case 2:
+ tm->tm_mon = n - 1;
+ break;
+ case 3:
+ tm->tm_mday = n;
+ break;
+ case 4:
+ tm->tm_hour = n;
+ break;
+ case 5:
+ tm->tm_min = n;
+ break;
+ case 6:
+ tm->tm_sec = n;
+ break;
+ }
+ }
+ }
+ /* Optional fractional seconds: decimal point followed by one
+ * or more digits.
+ */
+ if (a[o] == '.')
+ {
+ if (++o > l) goto err;
+ i = o;
+ while ((a[o] >= '0') && (a[o] <= '9') && (o <= l))
+ o++;
+ /* Must have at least one digit after decimal point */
+ if (i == o) goto err;
+ }
+
+ if (a[o] == 'Z')
+ o++;
+ else if ((a[o] == '+') || (a[o] == '-'))
+ {
+ int offsign = a[o] == '-' ? -1 : 1, offset = 0;
+ o++;
+ if (o+4 > l) goto err;
+ for (i=7; i<9; i++)
+ {
+ if ((a[o] < '0') || (a[o] > '9')) goto err;
+ n= a[o]-'0';
+ o++;
+ if ((a[o] < '0') || (a[o] > '9')) goto err;
+ n=(n*10)+ a[o]-'0';
+ if ((n < min[i]) || (n > max[i])) goto err;
+ if (tm)
+ {
+ if (i == 7)
+ offset = n * 3600;
+ else if (i == 8)
+ offset += n * 60;
+ }
+ o++;
+ }
+ if (offset && !OPENSSL_gmtime_adj(tm, 0, offset * offsign))
+ return 0;
+ }
+ else if (a[o])
+ {
+ /* Missing time zone information. */
+ goto err;
+ }
+ return(o == l);
+err:
+ return(0);
+ }
+
+int ASN1_GENERALIZEDTIME_check(const ASN1_GENERALIZEDTIME *d)
+ {
+ return asn1_generalizedtime_to_tm(NULL, d);
+ }
+
+int ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *s, const char *str)
+ {
+ ASN1_GENERALIZEDTIME t;
+
+ t.type=V_ASN1_GENERALIZEDTIME;
+ t.length=strlen(str);
+ t.data=(unsigned char *)str;
+ if (ASN1_GENERALIZEDTIME_check(&t))
+ {
+ if (s != NULL)
+ {
+ if (!ASN1_STRING_set((ASN1_STRING *)s,
+ (unsigned char *)str,t.length))
+ return 0;
+ s->type=V_ASN1_GENERALIZEDTIME;
+ }
+ return(1);
+ }
+ else
+ return(0);
+ }
+
+ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *s,
+ time_t t)
+ {
+ return ASN1_GENERALIZEDTIME_adj(s, t, 0, 0);
+ }
+
+ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s,
+ time_t t, int offset_day, long offset_sec)
+ {
+ char *p;
+ struct tm *ts;
+ struct tm data;
+ size_t len = 20;
+
+ if (s == NULL)
+ s=M_ASN1_GENERALIZEDTIME_new();
+ if (s == NULL)
+ return(NULL);
+
+ ts=OPENSSL_gmtime(&t, &data);
+ if (ts == NULL)
+ return(NULL);
+
+ if (offset_day || offset_sec)
+ {
+ if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec))
+ return NULL;
+ }
+
+ p=(char *)s->data;
+ if ((p == NULL) || ((size_t)s->length < len))
+ {
+ p=OPENSSL_malloc(len);
+ if (p == NULL)
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_GENERALIZEDTIME_adj, ERR_R_MALLOC_FAILURE);
+ return(NULL);
+ }
+ if (s->data != NULL)
+ OPENSSL_free(s->data);
+ s->data=(unsigned char *)p;
+ }
+
+ BIO_snprintf(p,len,"%04d%02d%02d%02d%02d%02dZ",ts->tm_year + 1900,
+ ts->tm_mon+1,ts->tm_mday,ts->tm_hour,ts->tm_min,ts->tm_sec);
+ s->length=strlen(p);
+ s->type=V_ASN1_GENERALIZEDTIME;
+#ifdef CHARSET_EBCDIC_not
+ ebcdic2ascii(s->data, s->data, s->length);
+#endif
+ return(s);
+ }
diff --git a/crypto/asn1/a_i2d_fp.c b/crypto/asn1/a_i2d_fp.c
new file mode 100644
index 0000000..11e40d3
--- /dev/null
+++ b/crypto/asn1/a_i2d_fp.c
@@ -0,0 +1,154 @@
+/* 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/asn1.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+int ASN1_i2d_fp(i2d_of_void *i2d, FILE *out, void *x)
+ {
+ BIO *b;
+ int ret;
+
+ if ((b=BIO_new(BIO_s_file())) == NULL)
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_i2d_fp, ERR_R_BUF_LIB);
+ return(0);
+ }
+ BIO_set_fp(b,out,BIO_NOCLOSE);
+ ret=ASN1_i2d_bio(i2d,b,x);
+ BIO_free(b);
+ return(ret);
+ }
+
+int ASN1_i2d_bio(i2d_of_void *i2d, BIO *out, unsigned char *x)
+ {
+ char *b;
+ unsigned char *p;
+ int i,j=0,n,ret=1;
+
+ n=i2d(x,NULL);
+ b=(char *)OPENSSL_malloc(n);
+ if (b == NULL)
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_i2d_bio, ERR_R_MALLOC_FAILURE);
+ return(0);
+ }
+
+ p=(unsigned char *)b;
+ i2d(x,&p);
+
+ for (;;)
+ {
+ i=BIO_write(out,&(b[j]),n);
+ if (i == n) break;
+ if (i <= 0)
+ {
+ ret=0;
+ break;
+ }
+ j+=i;
+ n-=i;
+ }
+ OPENSSL_free(b);
+ return(ret);
+ }
+
+int ASN1_item_i2d_fp(const ASN1_ITEM *it, FILE *out, void *x)
+ {
+ BIO *b;
+ int ret;
+
+ if ((b=BIO_new(BIO_s_file())) == NULL)
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_item_i2d_fp, ERR_R_BUF_LIB);
+ return(0);
+ }
+ BIO_set_fp(b,out,BIO_NOCLOSE);
+ ret=ASN1_item_i2d_bio(it,b,x);
+ BIO_free(b);
+ return(ret);
+ }
+
+int ASN1_item_i2d_bio(const ASN1_ITEM *it, BIO *out, void *x)
+ {
+ unsigned char *b = NULL;
+ int i,j=0,n,ret=1;
+
+ n = ASN1_item_i2d(x, &b, it);
+ if (b == NULL)
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_item_i2d_bio, ERR_R_MALLOC_FAILURE);
+ return(0);
+ }
+
+ for (;;)
+ {
+ i=BIO_write(out,&(b[j]),n);
+ if (i == n) break;
+ if (i <= 0)
+ {
+ ret=0;
+ break;
+ }
+ j+=i;
+ n-=i;
+ }
+ OPENSSL_free(b);
+ return(ret);
+ }
diff --git a/crypto/asn1/a_int.c b/crypto/asn1/a_int.c
new file mode 100644
index 0000000..6d7e225
--- /dev/null
+++ b/crypto/asn1/a_int.c
@@ -0,0 +1,454 @@
+/* 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/asn1.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+ASN1_INTEGER *ASN1_INTEGER_dup(const ASN1_INTEGER *x)
+{ return M_ASN1_INTEGER_dup(x);}
+
+int ASN1_INTEGER_cmp(const ASN1_INTEGER *x, const ASN1_INTEGER *y)
+ {
+ int neg, ret;
+ /* Compare signs */
+ neg = x->type & V_ASN1_NEG;
+ if (neg != (y->type & V_ASN1_NEG))
+ {
+ if (neg)
+ return -1;
+ else
+ return 1;
+ }
+
+ ret = ASN1_STRING_cmp(x, y);
+
+ if (neg)
+ return -ret;
+ else
+ return ret;
+ }
+
+
+/*
+ * This converts an ASN1 INTEGER into its content encoding.
+ * The internal representation is an ASN1_STRING whose data is a big endian
+ * representation of the value, ignoring the sign. The sign is determined by
+ * the type: V_ASN1_INTEGER for positive and V_ASN1_NEG_INTEGER for negative.
+ *
+ * Positive integers are no problem: they are almost the same as the DER
+ * encoding, except if the first byte is >= 0x80 we need to add a zero pad.
+ *
+ * Negative integers are a bit trickier...
+ * The DER representation of negative integers is in 2s complement form.
+ * The internal form is converted by complementing each octet and finally
+ * adding one to the result. This can be done less messily with a little trick.
+ * If the internal form has trailing zeroes then they will become FF by the
+ * complement and 0 by the add one (due to carry) so just copy as many trailing
+ * zeros to the destination as there are in the source. The carry will add one
+ * to the last none zero octet: so complement this octet and add one and finally
+ * complement any left over until you get to the start of the string.
+ *
+ * Padding is a little trickier too. If the first bytes is > 0x80 then we pad
+ * with 0xff. However if the first byte is 0x80 and one of the following bytes
+ * is non-zero we pad with 0xff. The reason for this distinction is that 0x80
+ * followed by optional zeros isn't padded.
+ */
+
+int i2c_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **pp)
+ {
+ int pad=0,ret,i,neg;
+ unsigned char *p,*n,pb=0;
+
+ if (a == NULL) return(0);
+ neg=a->type & V_ASN1_NEG;
+ if (a->length == 0)
+ ret=1;
+ else
+ {
+ ret=a->length;
+ i=a->data[0];
+ if (!neg && (i > 127)) {
+ pad=1;
+ pb=0;
+ } else if(neg) {
+ if(i>128) {
+ pad=1;
+ pb=0xFF;
+ } else if(i == 128) {
+ /*
+ * Special case: if any other bytes non zero we pad:
+ * otherwise we don't.
+ */
+ for(i = 1; i < a->length; i++) if(a->data[i]) {
+ pad=1;
+ pb=0xFF;
+ break;
+ }
+ }
+ }
+ ret+=pad;
+ }
+ if (pp == NULL) return(ret);
+ p= *pp;
+
+ if (pad) *(p++)=pb;
+ if (a->length == 0) *(p++)=0;
+ else if (!neg) memcpy(p,a->data,(unsigned int)a->length);
+ else {
+ /* Begin at the end of the encoding */
+ n=a->data + a->length - 1;
+ p += a->length - 1;
+ i = a->length;
+ /* Copy zeros to destination as long as source is zero */
+ while(!*n) {
+ *(p--) = 0;
+ n--;
+ i--;
+ }
+ /* Complement and increment next octet */
+ *(p--) = ((*(n--)) ^ 0xff) + 1;
+ i--;
+ /* Complement any octets left */
+ for(;i > 0; i--) *(p--) = *(n--) ^ 0xff;
+ }
+
+ *pp+=ret;
+ return(ret);
+ }
+
+/* Convert just ASN1 INTEGER content octets to ASN1_INTEGER structure */
+
+ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a, const unsigned char **pp,
+ long len)
+ {
+ ASN1_INTEGER *ret=NULL;
+ const unsigned char *p, *pend;
+ unsigned char *to,*s;
+ int i;
+
+ if ((a == NULL) || ((*a) == NULL))
+ {
+ if ((ret=M_ASN1_INTEGER_new()) == NULL) return(NULL);
+ ret->type=V_ASN1_INTEGER;
+ }
+ else
+ ret=(*a);
+
+ p= *pp;
+ pend = p + len;
+
+ /* We must OPENSSL_malloc stuff, even for 0 bytes otherwise it
+ * signifies a missing NULL parameter. */
+ s=(unsigned char *)OPENSSL_malloc((int)len+1);
+ if (s == NULL)
+ {
+ i=ERR_R_MALLOC_FAILURE;
+ goto err;
+ }
+ to=s;
+ if(!len) {
+ /* Strictly speaking this is an illegal INTEGER but we
+ * tolerate it.
+ */
+ ret->type=V_ASN1_INTEGER;
+ } else if (*p & 0x80) /* a negative number */
+ {
+ ret->type=V_ASN1_NEG_INTEGER;
+ if ((*p == 0xff) && (len != 1)) {
+ p++;
+ len--;
+ }
+ i = len;
+ p += i - 1;
+ to += i - 1;
+ while((!*p) && i) {
+ *(to--) = 0;
+ i--;
+ p--;
+ }
+ /* Special case: if all zeros then the number will be of
+ * the form FF followed by n zero bytes: this corresponds to
+ * 1 followed by n zero bytes. We've already written n zeros
+ * so we just append an extra one and set the first byte to
+ * a 1. This is treated separately because it is the only case
+ * where the number of bytes is larger than len.
+ */
+ if(!i) {
+ *s = 1;
+ s[len] = 0;
+ len++;
+ } else {
+ *(to--) = (*(p--) ^ 0xff) + 1;
+ i--;
+ for(;i > 0; i--) *(to--) = *(p--) ^ 0xff;
+ }
+ } else {
+ ret->type=V_ASN1_INTEGER;
+ if ((*p == 0) && (len != 1))
+ {
+ p++;
+ len--;
+ }
+ memcpy(s,p,(int)len);
+ }
+
+ if (ret->data != NULL) OPENSSL_free(ret->data);
+ ret->data=s;
+ ret->length=(int)len;
+ if (a != NULL) (*a)=ret;
+ *pp=pend;
+ return(ret);
+err:
+ OPENSSL_PUT_ERROR(ASN1, c2i_ASN1_INTEGER, i);
+ if ((ret != NULL) && ((a == NULL) || (*a != ret)))
+ M_ASN1_INTEGER_free(ret);
+ return(NULL);
+ }
+
+
+/* This is a version of d2i_ASN1_INTEGER that ignores the sign bit of
+ * ASN1 integers: some broken software can encode a positive INTEGER
+ * with its MSB set as negative (it doesn't add a padding zero).
+ */
+
+ASN1_INTEGER *d2i_ASN1_UINTEGER(ASN1_INTEGER **a, const unsigned char **pp,
+ long length)
+ {
+ ASN1_INTEGER *ret=NULL;
+ const unsigned char *p;
+ unsigned char *s;
+ long len;
+ int inf,tag,xclass;
+ int i;
+
+ if ((a == NULL) || ((*a) == NULL))
+ {
+ if ((ret=M_ASN1_INTEGER_new()) == NULL) return(NULL);
+ ret->type=V_ASN1_INTEGER;
+ }
+ else
+ ret=(*a);
+
+ p= *pp;
+ inf=ASN1_get_object(&p,&len,&tag,&xclass,length);
+ if (inf & 0x80)
+ {
+ i=ASN1_R_BAD_OBJECT_HEADER;
+ goto err;
+ }
+
+ if (tag != V_ASN1_INTEGER)
+ {
+ i=ASN1_R_EXPECTING_AN_INTEGER;
+ goto err;
+ }
+
+ /* We must OPENSSL_malloc stuff, even for 0 bytes otherwise it
+ * signifies a missing NULL parameter. */
+ s=(unsigned char *)OPENSSL_malloc((int)len+1);
+ if (s == NULL)
+ {
+ i=ERR_R_MALLOC_FAILURE;
+ goto err;
+ }
+ ret->type=V_ASN1_INTEGER;
+ if(len) {
+ if ((*p == 0) && (len != 1))
+ {
+ p++;
+ len--;
+ }
+ memcpy(s,p,(int)len);
+ p+=len;
+ }
+
+ if (ret->data != NULL) OPENSSL_free(ret->data);
+ ret->data=s;
+ ret->length=(int)len;
+ if (a != NULL) (*a)=ret;
+ *pp=p;
+ return(ret);
+err:
+ OPENSSL_PUT_ERROR(ASN1, d2i_ASN1_UINTEGER, i);
+ if ((ret != NULL) && ((a == NULL) || (*a != ret)))
+ M_ASN1_INTEGER_free(ret);
+ return(NULL);
+ }
+
+int ASN1_INTEGER_set(ASN1_INTEGER *a, long v)
+ {
+ int j,k;
+ unsigned int i;
+ unsigned char buf[sizeof(long)+1];
+ long d;
+
+ a->type=V_ASN1_INTEGER;
+ if (a->length < (int)(sizeof(long)+1))
+ {
+ if (a->data != NULL)
+ OPENSSL_free(a->data);
+ if ((a->data=(unsigned char *)OPENSSL_malloc(sizeof(long)+1)) != NULL)
+ memset((char *)a->data,0,sizeof(long)+1);
+ }
+ if (a->data == NULL)
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_INTEGER_set, ERR_R_MALLOC_FAILURE);
+ return(0);
+ }
+ d=v;
+ if (d < 0)
+ {
+ d= -d;
+ a->type=V_ASN1_NEG_INTEGER;
+ }
+
+ for (i=0; i<sizeof(long); i++)
+ {
+ if (d == 0) break;
+ buf[i]=(int)d&0xff;
+ d>>=8;
+ }
+ j=0;
+ for (k=i-1; k >=0; k--)
+ a->data[j++]=buf[k];
+ a->length=j;
+ return(1);
+ }
+
+long ASN1_INTEGER_get(const ASN1_INTEGER *a)
+ {
+ int neg=0,i;
+ long r=0;
+
+ if (a == NULL) return(0L);
+ i=a->type;
+ if (i == V_ASN1_NEG_INTEGER)
+ neg=1;
+ else if (i != V_ASN1_INTEGER)
+ return -1;
+
+ if (a->length > (int)sizeof(long))
+ {
+ /* hmm... a bit ugly, return all ones */
+ return -1;
+ }
+ if (a->data == NULL)
+ return 0;
+
+ for (i=0; i<a->length; i++)
+ {
+ r<<=8;
+ r|=(unsigned char)a->data[i];
+ }
+ if (neg) r= -r;
+ return(r);
+ }
+
+ASN1_INTEGER *BN_to_ASN1_INTEGER(const BIGNUM *bn, ASN1_INTEGER *ai)
+ {
+ ASN1_INTEGER *ret;
+ int len,j;
+
+ if (ai == NULL)
+ ret=M_ASN1_INTEGER_new();
+ else
+ ret=ai;
+ if (ret == NULL)
+ {
+ OPENSSL_PUT_ERROR(ASN1, BN_to_ASN1_INTEGER, ASN1_R_NESTED_ASN1_ERROR);
+ goto err;
+ }
+ if (BN_is_negative(bn))
+ ret->type = V_ASN1_NEG_INTEGER;
+ else ret->type=V_ASN1_INTEGER;
+ j=BN_num_bits(bn);
+ len=((j == 0)?0:((j/8)+1));
+ if (ret->length < len+4)
+ {
+ 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);
+ goto err;
+ }
+ ret->data=new_data;
+ }
+ ret->length=BN_bn2bin(bn,ret->data);
+ /* Correct zero case */
+ if(!ret->length)
+ {
+ ret->data[0] = 0;
+ ret->length = 1;
+ }
+ return(ret);
+err:
+ if (ret != ai) M_ASN1_INTEGER_free(ret);
+ return(NULL);
+ }
+
+BIGNUM *ASN1_INTEGER_to_BN(const ASN1_INTEGER *ai, BIGNUM *bn)
+ {
+ BIGNUM *ret;
+
+ if ((ret=BN_bin2bn(ai->data,ai->length,bn)) == NULL)
+ OPENSSL_PUT_ERROR(ASN1, ASN1_INTEGER_to_BN, ASN1_R_BN_LIB);
+ else if(ai->type == V_ASN1_NEG_INTEGER)
+ BN_set_negative(ret, 1);
+ return(ret);
+ }
diff --git a/crypto/asn1/a_mbstr.c b/crypto/asn1/a_mbstr.c
new file mode 100644
index 0000000..6543f52
--- /dev/null
+++ b/crypto/asn1/a_mbstr.c
@@ -0,0 +1,395 @@
+/* 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/asn1.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+static int traverse_string(const unsigned char *p, int len, int inform,
+ int (*rfunc)(unsigned long value, void *in), void *arg);
+static int in_utf8(unsigned long value, void *arg);
+static int out_utf8(unsigned long value, void *arg);
+static int type_str(unsigned long value, void *arg);
+static int cpy_asc(unsigned long value, void *arg);
+static int cpy_bmp(unsigned long value, void *arg);
+static int cpy_univ(unsigned long value, void *arg);
+static int cpy_utf8(unsigned long value, void *arg);
+static int is_printable(unsigned long value);
+
+/* These functions take a string in UTF8, ASCII or multibyte form and
+ * a mask of permissible ASN1 string types. It then works out the minimal
+ * type (using the order Printable < IA5 < T61 < BMP < Universal < UTF8)
+ * and creates a string of the correct type with the supplied data.
+ * Yes this is horrible: it has to be :-(
+ * The 'ncopy' form checks minimum and maximum size limits too.
+ */
+
+int ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len,
+ int inform, unsigned long mask)
+{
+ return ASN1_mbstring_ncopy(out, in, len, inform, mask, 0, 0);
+}
+
+int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
+ int inform, unsigned long mask,
+ long minsize, long maxsize)
+{
+ int str_type;
+ int ret;
+ char free_out;
+ int outform, outlen = 0;
+ ASN1_STRING *dest;
+ unsigned char *p;
+ int nchar;
+ char strbuf[32];
+ int (*cpyfunc)(unsigned long,void *) = NULL;
+ if(len == -1) len = strlen((const char *)in);
+ if(!mask) mask = DIRSTRING_TYPE;
+
+ /* First do a string check and work out the number of characters */
+ switch(inform) {
+
+ case MBSTRING_BMP:
+ if(len & 1) {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_mbstring_ncopy, ASN1_R_INVALID_BMPSTRING_LENGTH);
+ return -1;
+ }
+ nchar = len >> 1;
+ break;
+
+ case MBSTRING_UNIV:
+ if(len & 3) {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_mbstring_ncopy, ASN1_R_INVALID_UNIVERSALSTRING_LENGTH);
+ return -1;
+ }
+ nchar = len >> 2;
+ break;
+
+ case MBSTRING_UTF8:
+ nchar = 0;
+ /* 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);
+ return -1;
+ }
+ break;
+
+ case MBSTRING_ASC:
+ nchar = len;
+ break;
+
+ default:
+ OPENSSL_PUT_ERROR(ASN1, ASN1_mbstring_ncopy, ASN1_R_UNKNOWN_FORMAT);
+ return -1;
+ }
+
+ if((minsize > 0) && (nchar < minsize)) {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_mbstring_ncopy, 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);
+ BIO_snprintf(strbuf, sizeof strbuf, "%ld", maxsize);
+ ERR_add_error_data(2, "maxsize=", strbuf);
+ return -1;
+ }
+
+ /* 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);
+ return -1;
+ }
+
+
+ /* Now work out output format and string type */
+ outform = MBSTRING_ASC;
+ if(mask & B_ASN1_PRINTABLESTRING) str_type = V_ASN1_PRINTABLESTRING;
+ else if(mask & B_ASN1_IA5STRING) str_type = V_ASN1_IA5STRING;
+ else if(mask & B_ASN1_T61STRING) str_type = V_ASN1_T61STRING;
+ else if(mask & B_ASN1_BMPSTRING) {
+ str_type = V_ASN1_BMPSTRING;
+ outform = MBSTRING_BMP;
+ } else if(mask & B_ASN1_UNIVERSALSTRING) {
+ str_type = V_ASN1_UNIVERSALSTRING;
+ outform = MBSTRING_UNIV;
+ } else {
+ str_type = V_ASN1_UTF8STRING;
+ outform = MBSTRING_UTF8;
+ }
+ if(!out) return str_type;
+ if(*out) {
+ free_out = 0;
+ dest = *out;
+ if(dest->data) {
+ dest->length = 0;
+ OPENSSL_free(dest->data);
+ dest->data = NULL;
+ }
+ dest->type = str_type;
+ } else {
+ free_out = 1;
+ dest = ASN1_STRING_type_new(str_type);
+ if(!dest) {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_mbstring_ncopy, ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+ *out = dest;
+ }
+ /* 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);
+ return -1;
+ }
+ return str_type;
+ }
+
+ /* Work out how much space the destination will need */
+ switch(outform) {
+ case MBSTRING_ASC:
+ outlen = nchar;
+ cpyfunc = cpy_asc;
+ break;
+
+ case MBSTRING_BMP:
+ outlen = nchar << 1;
+ cpyfunc = cpy_bmp;
+ break;
+
+ case MBSTRING_UNIV:
+ outlen = nchar << 2;
+ cpyfunc = cpy_univ;
+ break;
+
+ case MBSTRING_UTF8:
+ outlen = 0;
+ traverse_string(in, len, inform, out_utf8, &outlen);
+ cpyfunc = cpy_utf8;
+ break;
+ }
+ if(!(p = OPENSSL_malloc(outlen + 1))) {
+ if(free_out) ASN1_STRING_free(dest);
+ OPENSSL_PUT_ERROR(ASN1, ASN1_mbstring_ncopy, ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+ dest->length = outlen;
+ dest->data = p;
+ p[outlen] = 0;
+ traverse_string(in, len, inform, cpyfunc, &p);
+ return str_type;
+}
+
+/* This function traverses a string and passes the value of each character
+ * to an optional function along with a void * argument.
+ */
+
+static int traverse_string(const unsigned char *p, int len, int inform,
+ int (*rfunc)(unsigned long value, void *in), void *arg)
+{
+ unsigned long value;
+ int ret;
+ while(len) {
+ if(inform == MBSTRING_ASC) {
+ value = *p++;
+ len--;
+ } else if(inform == MBSTRING_BMP) {
+ value = *p++ << 8;
+ value |= *p++;
+ len -= 2;
+ } else if(inform == MBSTRING_UNIV) {
+ value = ((unsigned long)*p++) << 24;
+ value |= ((unsigned long)*p++) << 16;
+ value |= *p++ << 8;
+ value |= *p++;
+ len -= 4;
+ } else {
+ ret = UTF8_getc(p, len, &value);
+ if(ret < 0) return -1;
+ len -= ret;
+ p += ret;
+ }
+ if(rfunc) {
+ ret = rfunc(value, arg);
+ if(ret <= 0) return ret;
+ }
+ }
+ return 1;
+}
+
+/* Various utility functions for traverse_string */
+
+/* Just count number of characters */
+
+static int in_utf8(unsigned long value, void *arg)
+{
+ int *nchar;
+ nchar = arg;
+ (*nchar)++;
+ return 1;
+}
+
+/* Determine size of output as a UTF8 String */
+
+static int out_utf8(unsigned long value, void *arg)
+{
+ int *outlen;
+ outlen = arg;
+ *outlen += UTF8_putc(NULL, -1, value);
+ return 1;
+}
+
+/* Determine the "type" of a string: check each character against a
+ * supplied "mask".
+ */
+
+static int type_str(unsigned long value, void *arg)
+{
+ unsigned long types;
+ types = *((unsigned long *)arg);
+ if((types & B_ASN1_PRINTABLESTRING) && !is_printable(value))
+ types &= ~B_ASN1_PRINTABLESTRING;
+ if((types & B_ASN1_IA5STRING) && (value > 127))
+ types &= ~B_ASN1_IA5STRING;
+ if((types & B_ASN1_T61STRING) && (value > 0xff))
+ types &= ~B_ASN1_T61STRING;
+ if((types & B_ASN1_BMPSTRING) && (value > 0xffff))
+ types &= ~B_ASN1_BMPSTRING;
+ if(!types) return -1;
+ *((unsigned long *)arg) = types;
+ return 1;
+}
+
+/* Copy one byte per character ASCII like strings */
+
+static int cpy_asc(unsigned long value, void *arg)
+{
+ unsigned char **p, *q;
+ p = arg;
+ q = *p;
+ *q = (unsigned char) value;
+ (*p)++;
+ return 1;
+}
+
+/* Copy two byte per character BMPStrings */
+
+static int cpy_bmp(unsigned long value, void *arg)
+{
+ unsigned char **p, *q;
+ p = arg;
+ q = *p;
+ *q++ = (unsigned char) ((value >> 8) & 0xff);
+ *q = (unsigned char) (value & 0xff);
+ *p += 2;
+ return 1;
+}
+
+/* Copy four byte per character UniversalStrings */
+
+static int cpy_univ(unsigned long value, void *arg)
+{
+ unsigned char **p, *q;
+ p = arg;
+ q = *p;
+ *q++ = (unsigned char) ((value >> 24) & 0xff);
+ *q++ = (unsigned char) ((value >> 16) & 0xff);
+ *q++ = (unsigned char) ((value >> 8) & 0xff);
+ *q = (unsigned char) (value & 0xff);
+ *p += 4;
+ return 1;
+}
+
+/* Copy to a UTF8String */
+
+static int cpy_utf8(unsigned long value, void *arg)
+{
+ unsigned char **p;
+ int ret;
+ p = arg;
+ /* We already know there is enough room so pass 0xff as the length */
+ ret = UTF8_putc(*p, 0xff, value);
+ *p += ret;
+ return 1;
+}
+
+/* Return 1 if the character is permitted in a PrintableString */
+static int is_printable(unsigned long value)
+{
+ int ch;
+ if(value > 0x7f) return 0;
+ ch = (int) value;
+ /* Note: we can't use 'isalnum' because certain accented
+ * characters may count as alphanumeric in some environments.
+ */
+#ifndef CHARSET_EBCDIC
+ if((ch >= 'a') && (ch <= 'z')) return 1;
+ if((ch >= 'A') && (ch <= 'Z')) return 1;
+ if((ch >= '0') && (ch <= '9')) return 1;
+ if ((ch == ' ') || strchr("'()+,-./:=?", ch)) return 1;
+#else /*CHARSET_EBCDIC*/
+ if((ch >= os_toascii['a']) && (ch <= os_toascii['z'])) return 1;
+ if((ch >= os_toascii['A']) && (ch <= os_toascii['Z'])) return 1;
+ if((ch >= os_toascii['0']) && (ch <= os_toascii['9'])) return 1;
+ if ((ch == os_toascii[' ']) || strchr("'()+,-./:=?", os_toebcdic[ch])) return 1;
+#endif /*CHARSET_EBCDIC*/
+ return 0;
+}
diff --git a/crypto/asn1/a_object.c b/crypto/asn1/a_object.c
new file mode 100644
index 0000000..f2a9e2d
--- /dev/null
+++ b/crypto/asn1/a_object.c
@@ -0,0 +1,399 @@
+/* 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/asn1.h>
+
+#include <limits.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+
+
+int i2d_ASN1_OBJECT(ASN1_OBJECT *a, unsigned char **pp)
+ {
+ unsigned char *p;
+ int objsize;
+
+ if ((a == NULL) || (a->data == NULL)) return(0);
+
+ objsize = ASN1_object_size(0,a->length,V_ASN1_OBJECT);
+ if (pp == NULL) return objsize;
+
+ p= *pp;
+ ASN1_put_object(&p,0,a->length,V_ASN1_OBJECT,V_ASN1_UNIVERSAL);
+ memcpy(p,a->data,a->length);
+ p+=a->length;
+
+ *pp=p;
+ return(objsize);
+ }
+
+int a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num)
+ {
+ int i,first,len=0,c, use_bn;
+ char ftmp[24], *tmp = ftmp;
+ int tmpsize = sizeof ftmp;
+ const char *p;
+ unsigned long l;
+ BIGNUM *bl = NULL;
+
+ if (num == 0)
+ return(0);
+ else if (num == -1)
+ num=strlen(buf);
+
+ p=buf;
+ c= *(p++);
+ num--;
+ if ((c >= '0') && (c <= '2'))
+ {
+ first= c-'0';
+ }
+ else
+ {
+ OPENSSL_PUT_ERROR(ASN1, a2d_ASN1_OBJECT, ASN1_R_FIRST_NUM_TOO_LARGE);
+ goto err;
+ }
+
+ if (num <= 0)
+ {
+ OPENSSL_PUT_ERROR(ASN1, a2d_ASN1_OBJECT, ASN1_R_MISSING_SECOND_NUMBER);
+ goto err;
+ }
+ c= *(p++);
+ num--;
+ for (;;)
+ {
+ if (num <= 0) break;
+ if ((c != '.') && (c != ' '))
+ {
+ OPENSSL_PUT_ERROR(ASN1, a2d_ASN1_OBJECT, ASN1_R_INVALID_SEPARATOR);
+ goto err;
+ }
+ l=0;
+ use_bn = 0;
+ for (;;)
+ {
+ if (num <= 0) break;
+ num--;
+ c= *(p++);
+ if ((c == ' ') || (c == '.'))
+ break;
+ if ((c < '0') || (c > '9'))
+ {
+ OPENSSL_PUT_ERROR(ASN1, a2d_ASN1_OBJECT, ASN1_R_INVALID_DIGIT);
+ goto err;
+ }
+ if (!use_bn && l >= ((ULONG_MAX - 80) / 10L))
+ {
+ use_bn = 1;
+ if (!bl)
+ bl = BN_new();
+ if (!bl || !BN_set_word(bl, l))
+ goto err;
+ }
+ if (use_bn)
+ {
+ if (!BN_mul_word(bl, 10L)
+ || !BN_add_word(bl, c-'0'))
+ goto err;
+ }
+ else
+ l=l*10L+(long)(c-'0');
+ }
+ if (len == 0)
+ {
+ if ((first < 2) && (l >= 40))
+ {
+ OPENSSL_PUT_ERROR(ASN1, a2d_ASN1_OBJECT, ASN1_R_SECOND_NUMBER_TOO_LARGE);
+ goto err;
+ }
+ if (use_bn)
+ {
+ if (!BN_add_word(bl, first * 40))
+ goto err;
+ }
+ else
+ l+=(long)first*40;
+ }
+ i=0;
+ if (use_bn)
+ {
+ int blsize;
+ blsize = BN_num_bits(bl);
+ blsize = (blsize + 6)/7;
+ if (blsize > tmpsize)
+ {
+ if (tmp != ftmp)
+ OPENSSL_free(tmp);
+ tmpsize = blsize + 32;
+ tmp = OPENSSL_malloc(tmpsize);
+ if (!tmp)
+ goto err;
+ }
+ while(blsize--)
+ tmp[i++] = (unsigned char)BN_div_word(bl, 0x80L);
+ }
+ else
+ {
+
+ for (;;)
+ {
+ tmp[i++]=(unsigned char)l&0x7f;
+ l>>=7L;
+ if (l == 0L) break;
+ }
+
+ }
+ if (out != NULL)
+ {
+ if (len+i > olen)
+ {
+ OPENSSL_PUT_ERROR(ASN1, a2d_ASN1_OBJECT, ASN1_R_BUFFER_TOO_SMALL);
+ goto err;
+ }
+ while (--i > 0)
+ out[len++]=tmp[i]|0x80;
+ out[len++]=tmp[0];
+ }
+ else
+ len+=i;
+ }
+ if (tmp != ftmp)
+ OPENSSL_free(tmp);
+ if (bl)
+ BN_free(bl);
+ return(len);
+err:
+ if (tmp != ftmp)
+ OPENSSL_free(tmp);
+ if (bl)
+ BN_free(bl);
+ return(0);
+ }
+
+int i2t_ASN1_OBJECT(char *buf, int buf_len, ASN1_OBJECT *a)
+{
+ return OBJ_obj2txt(buf, buf_len, a, 0);
+}
+
+int i2a_ASN1_OBJECT(BIO *bp, ASN1_OBJECT *a)
+ {
+ char buf[80], *p = buf;
+ int i;
+
+ if ((a == NULL) || (a->data == NULL))
+ return(BIO_write(bp,"NULL",4));
+ i=i2t_ASN1_OBJECT(buf,sizeof buf,a);
+ if (i > (int)(sizeof(buf) - 1))
+ {
+ p = OPENSSL_malloc(i + 1);
+ if (!p)
+ return -1;
+ i2t_ASN1_OBJECT(p,i + 1,a);
+ }
+ if (i <= 0)
+ return BIO_write(bp, "<INVALID>", 9);
+ BIO_write(bp,p,i);
+ if (p != buf)
+ OPENSSL_free(p);
+ return(i);
+ }
+
+ASN1_OBJECT *d2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp,
+ long length)
+{
+ const unsigned char *p;
+ long len;
+ int tag,xclass;
+ int inf,i;
+ ASN1_OBJECT *ret = NULL;
+ p= *pp;
+ inf=ASN1_get_object(&p,&len,&tag,&xclass,length);
+ if (inf & 0x80)
+ {
+ i=ASN1_R_BAD_OBJECT_HEADER;
+ goto err;
+ }
+
+ if (tag != V_ASN1_OBJECT)
+ {
+ i=ASN1_R_EXPECTING_AN_OBJECT;
+ goto err;
+ }
+ ret = c2i_ASN1_OBJECT(a, &p, len);
+ if(ret) *pp = p;
+ return ret;
+err:
+ OPENSSL_PUT_ERROR(ASN1, d2i_ASN1_OBJECT, i);
+ return(NULL);
+}
+ASN1_OBJECT *c2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp,
+ long len)
+ {
+ ASN1_OBJECT *ret=NULL;
+ const unsigned char *p;
+ unsigned char *data;
+ int i;
+ /* Sanity check OID encoding: can't have leading 0x80 in
+ * subidentifiers, see: X.690 8.19.2
+ */
+ for (i = 0, p = *pp; i < len; i++, p++)
+ {
+ if (*p == 0x80 && (!i || !(p[-1] & 0x80)))
+ {
+ OPENSSL_PUT_ERROR(ASN1, c2i_ASN1_OBJECT, ASN1_R_INVALID_OBJECT_ENCODING);
+ return NULL;
+ }
+ }
+
+ /* only the ASN1_OBJECTs from the 'table' will have values
+ * for ->sn or ->ln */
+ if ((a == NULL) || ((*a) == NULL) ||
+ !((*a)->flags & ASN1_OBJECT_FLAG_DYNAMIC))
+ {
+ if ((ret=ASN1_OBJECT_new()) == NULL) return(NULL);
+ }
+ else ret=(*a);
+
+ p= *pp;
+ /* detach data from object */
+ data = (unsigned char *)ret->data;
+ ret->data = NULL;
+ /* once detached we can change it */
+ if ((data == NULL) || (ret->length < len))
+ {
+ ret->length=0;
+ if (data != NULL) OPENSSL_free(data);
+ data=(unsigned char *)OPENSSL_malloc(len ? (int)len : 1);
+ if (data == NULL)
+ { i=ERR_R_MALLOC_FAILURE; goto err; }
+ ret->flags|=ASN1_OBJECT_FLAG_DYNAMIC_DATA;
+ }
+ memcpy(data,p,(int)len);
+ /* reattach data to object, after which it remains const */
+ ret->data =data;
+ ret->length=(int)len;
+ ret->sn=NULL;
+ ret->ln=NULL;
+ /* ret->flags=ASN1_OBJECT_FLAG_DYNAMIC; we know it is dynamic */
+ p+=len;
+
+ if (a != NULL) (*a)=ret;
+ *pp=p;
+ return(ret);
+err:
+ OPENSSL_PUT_ERROR(ASN1, c2i_ASN1_OBJECT, i);
+ if ((ret != NULL) && ((a == NULL) || (*a != ret)))
+ ASN1_OBJECT_free(ret);
+ return(NULL);
+ }
+
+ASN1_OBJECT *ASN1_OBJECT_new(void)
+ {
+ ASN1_OBJECT *ret;
+
+ ret=(ASN1_OBJECT *)OPENSSL_malloc(sizeof(ASN1_OBJECT));
+ if (ret == NULL)
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_OBJECT_new, ERR_R_MALLOC_FAILURE);
+ return(NULL);
+ }
+ ret->length=0;
+ ret->data=NULL;
+ ret->nid=0;
+ ret->sn=NULL;
+ ret->ln=NULL;
+ ret->flags=ASN1_OBJECT_FLAG_DYNAMIC;
+ return(ret);
+ }
+
+void ASN1_OBJECT_free(ASN1_OBJECT *a)
+ {
+ if (a == NULL) return;
+ if (a->flags & ASN1_OBJECT_FLAG_DYNAMIC_STRINGS)
+ {
+#ifndef CONST_STRICT /* disable purely for compile-time strict const checking. Doing this on a "real" compile will cause memory leaks */
+ if (a->sn != NULL) OPENSSL_free((void *)a->sn);
+ if (a->ln != NULL) OPENSSL_free((void *)a->ln);
+#endif
+ a->sn=a->ln=NULL;
+ }
+ if (a->flags & ASN1_OBJECT_FLAG_DYNAMIC_DATA)
+ {
+ if (a->data != NULL) OPENSSL_free((void *)a->data);
+ a->data=NULL;
+ a->length=0;
+ }
+ if (a->flags & ASN1_OBJECT_FLAG_DYNAMIC)
+ OPENSSL_free(a);
+ }
+
+ASN1_OBJECT *ASN1_OBJECT_create(int nid, unsigned char *data, int len,
+ const char *sn, const char *ln)
+ {
+ ASN1_OBJECT o;
+
+ o.sn=sn;
+ o.ln=ln;
+ o.data=data;
+ o.nid=nid;
+ o.length=len;
+ o.flags=ASN1_OBJECT_FLAG_DYNAMIC|ASN1_OBJECT_FLAG_DYNAMIC_STRINGS|
+ ASN1_OBJECT_FLAG_DYNAMIC_DATA;
+ return(OBJ_dup(&o));
+ }
diff --git a/crypto/asn1/a_octet.c b/crypto/asn1/a_octet.c
new file mode 100644
index 0000000..583c9e9
--- /dev/null
+++ b/crypto/asn1/a_octet.c
@@ -0,0 +1,70 @@
+/* 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/asn1.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+ASN1_OCTET_STRING *ASN1_OCTET_STRING_dup(const ASN1_OCTET_STRING *x)
+{ return M_ASN1_OCTET_STRING_dup(x); }
+
+int ASN1_OCTET_STRING_cmp(const ASN1_OCTET_STRING *a, const ASN1_OCTET_STRING *b)
+{ return M_ASN1_OCTET_STRING_cmp(a, b); }
+
+int ASN1_OCTET_STRING_set(ASN1_OCTET_STRING *x, const unsigned char *d, int len)
+{ return M_ASN1_OCTET_STRING_set(x, d, len); }
diff --git a/crypto/asn1/a_print.c b/crypto/asn1/a_print.c
new file mode 100644
index 0000000..e2cde68
--- /dev/null
+++ b/crypto/asn1/a_print.c
@@ -0,0 +1,127 @@
+/* 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/asn1.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+int ASN1_PRINTABLE_type(const unsigned char *s, int len)
+ {
+ int c;
+ int ia5=0;
+ int t61=0;
+
+ if (len <= 0) len= -1;
+ if (s == NULL) return(V_ASN1_PRINTABLESTRING);
+
+ while ((*s) && (len-- != 0))
+ {
+ c= *(s++);
+#ifndef CHARSET_EBCDIC
+ if (!( ((c >= 'a') && (c <= 'z')) ||
+ ((c >= 'A') && (c <= 'Z')) ||
+ (c == ' ') ||
+ ((c >= '0') && (c <= '9')) ||
+ (c == ' ') || (c == '\'') ||
+ (c == '(') || (c == ')') ||
+ (c == '+') || (c == ',') ||
+ (c == '-') || (c == '.') ||
+ (c == '/') || (c == ':') ||
+ (c == '=') || (c == '?')))
+ ia5=1;
+ if (c&0x80)
+ t61=1;
+#else
+ if (!isalnum(c) && (c != ' ') &&
+ strchr("'()+,-./:=?", c) == NULL)
+ ia5=1;
+ if (os_toascii[c] & 0x80)
+ t61=1;
+#endif
+ }
+ if (t61) return(V_ASN1_T61STRING);
+ if (ia5) return(V_ASN1_IA5STRING);
+ return(V_ASN1_PRINTABLESTRING);
+ }
+
+int ASN1_UNIVERSALSTRING_to_string(ASN1_UNIVERSALSTRING *s)
+ {
+ int i;
+ unsigned char *p;
+
+ if (s->type != V_ASN1_UNIVERSALSTRING) return(0);
+ if ((s->length%4) != 0) return(0);
+ p=s->data;
+ for (i=0; i<s->length; i+=4)
+ {
+ if ((p[0] != '\0') || (p[1] != '\0') || (p[2] != '\0'))
+ break;
+ else
+ p+=4;
+ }
+ if (i < s->length) return(0);
+ p=s->data;
+ for (i=3; i<s->length; i+=4)
+ {
+ *(p++)=s->data[i];
+ }
+ *(p)='\0';
+ s->length/=4;
+ s->type=ASN1_PRINTABLE_type(s->data,s->length);
+ return(1);
+ }
diff --git a/crypto/asn1/a_strnid.c b/crypto/asn1/a_strnid.c
new file mode 100644
index 0000000..836c6d9
--- /dev/null
+++ b/crypto/asn1/a_strnid.c
@@ -0,0 +1,283 @@
+/* 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/asn1.h>
+
+#include <stdlib.h> /* For bsearch */
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+
+
+static STACK_OF(ASN1_STRING_TABLE) *stable = NULL;
+static void st_free(ASN1_STRING_TABLE *tbl);
+
+/* This is the global mask for the mbstring functions: this is use to
+ * mask out certain types (such as BMPString and UTF8String) because
+ * certain software (e.g. Netscape) has problems with them.
+ */
+
+static unsigned long global_mask = 0xFFFFFFFFL;
+
+void ASN1_STRING_set_default_mask(unsigned long mask)
+{
+ global_mask = mask;
+}
+
+unsigned long ASN1_STRING_get_default_mask(void)
+{
+ return global_mask;
+}
+
+/* This function sets the default to various "flavours" of configuration.
+ * based on an ASCII string. Currently this is:
+ * MASK:XXXX : a numerical mask value.
+ * nobmp : Don't use BMPStrings (just Printable, T61).
+ * pkix : PKIX recommendation in RFC2459.
+ * utf8only : only use UTF8Strings (RFC2459 recommendation for 2004).
+ * default: the default value, Printable, T61, BMP.
+ */
+
+int ASN1_STRING_set_default_mask_asc(const char *p)
+{
+ unsigned long mask;
+ char *end;
+ if(!strncmp(p, "MASK:", 5)) {
+ if(!p[5]) return 0;
+ mask = strtoul(p + 5, &end, 0);
+ if(*end) return 0;
+ } else if(!strcmp(p, "nombstr"))
+ mask = ~((unsigned long)(B_ASN1_BMPSTRING|B_ASN1_UTF8STRING));
+ else if(!strcmp(p, "pkix"))
+ mask = ~((unsigned long)B_ASN1_T61STRING);
+ else if(!strcmp(p, "utf8only")) mask = B_ASN1_UTF8STRING;
+ else if(!strcmp(p, "default"))
+ mask = 0xFFFFFFFFL;
+ else return 0;
+ ASN1_STRING_set_default_mask(mask);
+ return 1;
+}
+
+/* The following function generates an ASN1_STRING based on limits in a table.
+ * Frequently the types and length of an ASN1_STRING are restricted by a
+ * corresponding OID. For example certificates and certificate requests.
+ */
+
+ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out, const unsigned char *in,
+ int inlen, int inform, int nid)
+{
+ ASN1_STRING_TABLE *tbl;
+ ASN1_STRING *str = NULL;
+ unsigned long mask;
+ int ret;
+ if(!out) out = &str;
+ tbl = ASN1_STRING_TABLE_get(nid);
+ if(tbl) {
+ mask = tbl->mask;
+ if(!(tbl->flags & STABLE_NO_MASK)) mask &= global_mask;
+ ret = ASN1_mbstring_ncopy(out, in, inlen, inform, mask,
+ tbl->minsize, tbl->maxsize);
+ } else ret = ASN1_mbstring_copy(out, in, inlen, inform, DIRSTRING_TYPE & global_mask);
+ if(ret <= 0) return NULL;
+ return *out;
+}
+
+/* Now the tables and helper functions for the string table:
+ */
+
+/* size limits: this stuff is taken straight from RFC3280 */
+
+#define ub_name 32768
+#define ub_common_name 64
+#define ub_locality_name 128
+#define ub_state_name 128
+#define ub_organization_name 64
+#define ub_organization_unit_name 64
+#define ub_title 64
+#define ub_email_address 128
+#define ub_serial_number 64
+
+
+/* This table must be kept in NID order */
+
+static const ASN1_STRING_TABLE tbl_standard[] = {
+{NID_commonName, 1, ub_common_name, DIRSTRING_TYPE, 0},
+{NID_countryName, 2, 2, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
+{NID_localityName, 1, ub_locality_name, DIRSTRING_TYPE, 0},
+{NID_stateOrProvinceName, 1, ub_state_name, DIRSTRING_TYPE, 0},
+{NID_organizationName, 1, ub_organization_name, DIRSTRING_TYPE, 0},
+{NID_organizationalUnitName, 1, ub_organization_unit_name, DIRSTRING_TYPE, 0},
+{NID_pkcs9_emailAddress, 1, ub_email_address, B_ASN1_IA5STRING, STABLE_NO_MASK},
+{NID_pkcs9_unstructuredName, 1, -1, PKCS9STRING_TYPE, 0},
+{NID_pkcs9_challengePassword, 1, -1, PKCS9STRING_TYPE, 0},
+{NID_pkcs9_unstructuredAddress, 1, -1, DIRSTRING_TYPE, 0},
+{NID_givenName, 1, ub_name, DIRSTRING_TYPE, 0},
+{NID_surname, 1, ub_name, DIRSTRING_TYPE, 0},
+{NID_initials, 1, ub_name, DIRSTRING_TYPE, 0},
+{NID_serialNumber, 1, ub_serial_number, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
+{NID_friendlyName, -1, -1, B_ASN1_BMPSTRING, STABLE_NO_MASK},
+{NID_name, 1, ub_name, DIRSTRING_TYPE, 0},
+{NID_dnQualifier, -1, -1, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
+{NID_domainComponent, 1, -1, B_ASN1_IA5STRING, STABLE_NO_MASK},
+{NID_ms_csp_name, -1, -1, B_ASN1_BMPSTRING, STABLE_NO_MASK}
+};
+
+static int sk_table_cmp(const ASN1_STRING_TABLE **a,
+ const ASN1_STRING_TABLE **b)
+{
+ return (*a)->nid - (*b)->nid;
+}
+
+static int table_cmp(const void *in_a, const void *in_b)
+{
+ const ASN1_STRING_TABLE *a = in_a;
+ const ASN1_STRING_TABLE *b = in_b;
+ return a->nid - b->nid;
+}
+
+ASN1_STRING_TABLE *ASN1_STRING_TABLE_get(int nid)
+{
+ int found;
+ size_t idx;
+ ASN1_STRING_TABLE *ttmp;
+ ASN1_STRING_TABLE fnd;
+ fnd.nid = nid;
+
+ ttmp = bsearch(&fnd, tbl_standard, sizeof(tbl_standard)/sizeof(ASN1_STRING_TABLE), sizeof(ASN1_STRING_TABLE), table_cmp);
+ if(ttmp) return ttmp;
+ if(!stable) return NULL;
+ found = sk_ASN1_STRING_TABLE_find(stable, &idx, &fnd);
+ if (!found) return NULL;
+ return sk_ASN1_STRING_TABLE_value(stable, idx);
+}
+
+int ASN1_STRING_TABLE_add(int nid,
+ long minsize, long maxsize, unsigned long mask,
+ unsigned long flags)
+{
+ ASN1_STRING_TABLE *tmp;
+ char new_nid = 0;
+ 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);
+ 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);
+ return 0;
+ }
+ tmp->flags = flags | STABLE_FLAGS_MALLOC;
+ tmp->nid = nid;
+ new_nid = 1;
+ } else tmp->flags = (tmp->flags & STABLE_FLAGS_MALLOC) | flags;
+ if(minsize != -1) tmp->minsize = minsize;
+ if(maxsize != -1) tmp->maxsize = maxsize;
+ tmp->mask = mask;
+ if(new_nid) sk_ASN1_STRING_TABLE_push(stable, tmp);
+ return 1;
+}
+
+void ASN1_STRING_TABLE_cleanup(void)
+{
+ STACK_OF(ASN1_STRING_TABLE) *tmp;
+ tmp = stable;
+ if(!tmp) return;
+ stable = NULL;
+ sk_ASN1_STRING_TABLE_pop_free(tmp, st_free);
+}
+
+static void st_free(ASN1_STRING_TABLE *tbl)
+{
+ if(tbl->flags & STABLE_FLAGS_MALLOC) OPENSSL_free(tbl);
+}
+
+
+#ifdef STRING_TABLE_TEST
+
+main()
+{
+ ASN1_STRING_TABLE *tmp;
+ int i, last_nid = -1;
+
+ for (tmp = tbl_standard, i = 0;
+ i < sizeof(tbl_standard)/sizeof(ASN1_STRING_TABLE); i++, tmp++)
+ {
+ if (tmp->nid < last_nid)
+ {
+ last_nid = 0;
+ break;
+ }
+ last_nid = tmp->nid;
+ }
+
+ if (last_nid != 0)
+ {
+ printf("Table order OK\n");
+ exit(0);
+ }
+
+ for (tmp = tbl_standard, i = 0;
+ i < sizeof(tbl_standard)/sizeof(ASN1_STRING_TABLE); i++, tmp++)
+ printf("Index %d, NID %d, Name=%s\n", i, tmp->nid,
+ OBJ_nid2ln(tmp->nid));
+
+}
+
+#endif
diff --git a/crypto/asn1/a_time.c b/crypto/asn1/a_time.c
new file mode 100644
index 0000000..3b80ba4
--- /dev/null
+++ b/crypto/asn1/a_time.c
@@ -0,0 +1,233 @@
+/* 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/asn1.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/time_support.h>
+
+#include "asn1_locl.h"
+
+
+/* This is an implementation of the ASN1 Time structure which is:
+ * Time ::= CHOICE {
+ * utcTime UTCTime,
+ * generalTime GeneralizedTime }
+ * written by Steve Henson.
+ */
+
+IMPLEMENT_ASN1_MSTRING(ASN1_TIME, B_ASN1_TIME)
+
+IMPLEMENT_ASN1_FUNCTIONS(ASN1_TIME)
+
+#if 0
+int i2d_ASN1_TIME(ASN1_TIME *a, unsigned char **pp)
+ {
+#ifdef CHARSET_EBCDIC
+ /* KLUDGE! We convert to ascii before writing DER */
+ char tmp[24];
+ ASN1_STRING tmpstr;
+
+ if(a->type == V_ASN1_UTCTIME || a->type == V_ASN1_GENERALIZEDTIME) {
+ int len;
+
+ tmpstr = *(ASN1_STRING *)a;
+ len = tmpstr.length;
+ ebcdic2ascii(tmp, tmpstr.data, (len >= sizeof tmp) ? sizeof tmp : len);
+ tmpstr.data = tmp;
+ a = (ASN1_GENERALIZEDTIME *) &tmpstr;
+ }
+#endif
+ 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);
+ return -1;
+ }
+#endif
+
+
+ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s, time_t t)
+ {
+ return ASN1_TIME_adj(s, t, 0, 0);
+ }
+
+ASN1_TIME *ASN1_TIME_adj(ASN1_TIME *s, time_t t,
+ int offset_day, long offset_sec)
+ {
+ struct tm *ts;
+ struct tm data;
+
+ ts=OPENSSL_gmtime(&t,&data);
+ if (ts == NULL)
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_TIME_adj, ASN1_R_ERROR_GETTING_TIME);
+ return NULL;
+ }
+ if (offset_day || offset_sec)
+ {
+ if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec))
+ return NULL;
+ }
+ if((ts->tm_year >= 50) && (ts->tm_year < 150))
+ return ASN1_UTCTIME_adj(s, t, offset_day, offset_sec);
+ return ASN1_GENERALIZEDTIME_adj(s, t, offset_day, offset_sec);
+ }
+
+int ASN1_TIME_check(ASN1_TIME *t)
+ {
+ if (t->type == V_ASN1_GENERALIZEDTIME)
+ return ASN1_GENERALIZEDTIME_check(t);
+ else if (t->type == V_ASN1_UTCTIME)
+ return ASN1_UTCTIME_check(t);
+ return 0;
+ }
+
+/* Convert an ASN1_TIME structure to GeneralizedTime */
+ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *t, ASN1_GENERALIZEDTIME **out)
+ {
+ ASN1_GENERALIZEDTIME *ret;
+ char *str;
+ int newlen;
+
+ if (!ASN1_TIME_check(t)) return NULL;
+
+ if (!out || !*out)
+ {
+ if (!(ret = ASN1_GENERALIZEDTIME_new ()))
+ return NULL;
+ if (out) *out = ret;
+ }
+ else ret = *out;
+
+ /* If already GeneralizedTime just copy across */
+ if (t->type == V_ASN1_GENERALIZEDTIME)
+ {
+ if(!ASN1_STRING_set(ret, t->data, t->length))
+ return NULL;
+ return ret;
+ }
+
+ /* grow the string */
+ if (!ASN1_STRING_set(ret, NULL, t->length + 2))
+ return NULL;
+ /* ASN1_STRING_set() allocated 'len + 1' bytes. */
+ newlen = t->length + 2 + 1;
+ str = (char *)ret->data;
+ /* Work out the century and prepend */
+ if (t->data[0] >= '5') BUF_strlcpy(str, "19", newlen);
+ else BUF_strlcpy(str, "20", newlen);
+
+ BUF_strlcat(str, (char *)t->data, newlen);
+
+ return ret;
+ }
+
+int ASN1_TIME_set_string(ASN1_TIME *s, const char *str)
+ {
+ ASN1_TIME t;
+
+ t.length = strlen(str);
+ t.data = (unsigned char *)str;
+ t.flags = 0;
+
+ t.type = V_ASN1_UTCTIME;
+
+ if (!ASN1_TIME_check(&t))
+ {
+ t.type = V_ASN1_GENERALIZEDTIME;
+ if (!ASN1_TIME_check(&t))
+ return 0;
+ }
+
+ if (s && !ASN1_STRING_copy((ASN1_STRING *)s, (ASN1_STRING *)&t))
+ return 0;
+
+ return 1;
+ }
+
+static int asn1_time_to_tm(struct tm *tm, const ASN1_TIME *t)
+ {
+ if (t == NULL)
+ {
+ time_t now_t;
+ time(&now_t);
+ if (OPENSSL_gmtime(&now_t, tm))
+ return 1;
+ return 0;
+ }
+
+ if (t->type == V_ASN1_UTCTIME)
+ return asn1_utctime_to_tm(tm, t);
+ else if (t->type == V_ASN1_GENERALIZEDTIME)
+ return asn1_generalizedtime_to_tm(tm, t);
+
+ return 0;
+ }
+
+int ASN1_TIME_diff(int *pday, int *psec,
+ const ASN1_TIME *from, const ASN1_TIME *to)
+ {
+ struct tm tm_from, tm_to;
+ if (!asn1_time_to_tm(&tm_from, from))
+ return 0;
+ if (!asn1_time_to_tm(&tm_to, to))
+ return 0;
+ return OPENSSL_gmtime_diff(pday, psec, &tm_from, &tm_to);
+ }
diff --git a/crypto/asn1/a_type.c b/crypto/asn1/a_type.c
new file mode 100644
index 0000000..62bffde
--- /dev/null
+++ b/crypto/asn1/a_type.c
@@ -0,0 +1,157 @@
+/* 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/asn1.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+
+
+int ASN1_TYPE_get(ASN1_TYPE *a)
+ {
+ if ((a->value.ptr != NULL) || (a->type == V_ASN1_NULL))
+ return(a->type);
+ else
+ return(0);
+ }
+
+void ASN1_TYPE_set(ASN1_TYPE *a, int type, void *value)
+ {
+ if (a->value.ptr != NULL)
+ {
+ ASN1_TYPE **tmp_a = &a;
+ ASN1_primitive_free((ASN1_VALUE **)tmp_a, NULL);
+ }
+ a->type=type;
+ if (type == V_ASN1_BOOLEAN)
+ a->value.boolean = value ? 0xff : 0;
+ else
+ a->value.ptr=value;
+ }
+
+int ASN1_TYPE_set1(ASN1_TYPE *a, int type, const void *value)
+ {
+ if (!value || (type == V_ASN1_BOOLEAN))
+ {
+ void *p = (void *)value;
+ ASN1_TYPE_set(a, type, p);
+ }
+ else if (type == V_ASN1_OBJECT)
+ {
+ ASN1_OBJECT *odup;
+ odup = OBJ_dup(value);
+ if (!odup)
+ return 0;
+ ASN1_TYPE_set(a, type, odup);
+ }
+ else
+ {
+ ASN1_STRING *sdup;
+ sdup = ASN1_STRING_dup(value);
+ if (!sdup)
+ return 0;
+ ASN1_TYPE_set(a, type, sdup);
+ }
+ return 1;
+ }
+
+/* Returns 0 if they are equal, != 0 otherwise. */
+int ASN1_TYPE_cmp(ASN1_TYPE *a, ASN1_TYPE *b)
+ {
+ int result = -1;
+
+ if (!a || !b || a->type != b->type) return -1;
+
+ switch (a->type)
+ {
+ case V_ASN1_OBJECT:
+ result = OBJ_cmp(a->value.object, b->value.object);
+ break;
+ case V_ASN1_NULL:
+ result = 0; /* They do not have content. */
+ break;
+ case V_ASN1_INTEGER:
+ case V_ASN1_NEG_INTEGER:
+ case V_ASN1_ENUMERATED:
+ case V_ASN1_NEG_ENUMERATED:
+ case V_ASN1_BIT_STRING:
+ case V_ASN1_OCTET_STRING:
+ case V_ASN1_SEQUENCE:
+ case V_ASN1_SET:
+ case V_ASN1_NUMERICSTRING:
+ case V_ASN1_PRINTABLESTRING:
+ case V_ASN1_T61STRING:
+ case V_ASN1_VIDEOTEXSTRING:
+ case V_ASN1_IA5STRING:
+ case V_ASN1_UTCTIME:
+ case V_ASN1_GENERALIZEDTIME:
+ case V_ASN1_GRAPHICSTRING:
+ case V_ASN1_VISIBLESTRING:
+ case V_ASN1_GENERALSTRING:
+ case V_ASN1_UNIVERSALSTRING:
+ case V_ASN1_BMPSTRING:
+ case V_ASN1_UTF8STRING:
+ case V_ASN1_OTHER:
+ default:
+ result = ASN1_STRING_cmp((ASN1_STRING *) a->value.ptr,
+ (ASN1_STRING *) b->value.ptr);
+ break;
+ }
+
+ return result;
+ }
diff --git a/crypto/asn1/a_utctm.c b/crypto/asn1/a_utctm.c
new file mode 100644
index 0000000..72a09be
--- /dev/null
+++ b/crypto/asn1/a_utctm.c
@@ -0,0 +1,348 @@
+/* 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/asn1.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/time_support.h>
+
+
+#if 0
+int i2d_ASN1_UTCTIME(ASN1_UTCTIME *a, unsigned char **pp)
+ {
+#ifndef CHARSET_EBCDIC
+ return(i2d_ASN1_bytes((ASN1_STRING *)a,pp,
+ V_ASN1_UTCTIME,V_ASN1_UNIVERSAL));
+#else
+ /* KLUDGE! We convert to ascii before writing DER */
+ int len;
+ char tmp[24];
+ ASN1_STRING x = *(ASN1_STRING *)a;
+
+ len = x.length;
+ ebcdic2ascii(tmp, x.data, (len >= sizeof tmp) ? sizeof tmp : len);
+ x.data = tmp;
+ return i2d_ASN1_bytes(&x, pp, V_ASN1_UTCTIME,V_ASN1_UNIVERSAL);
+#endif
+ }
+
+
+ASN1_UTCTIME *d2i_ASN1_UTCTIME(ASN1_UTCTIME **a, unsigned char **pp,
+ long length)
+ {
+ ASN1_UTCTIME *ret=NULL;
+
+ ret=(ASN1_UTCTIME *)d2i_ASN1_bytes((ASN1_STRING **)a,pp,length,
+ V_ASN1_UTCTIME,V_ASN1_UNIVERSAL);
+ if (ret == NULL)
+ {
+ OPENSSL_PUT_ERROR(ASN1, XXX, ERR_R_NESTED_ASN1_ERROR);
+ return(NULL);
+ }
+#ifdef CHARSET_EBCDIC
+ ascii2ebcdic(ret->data, ret->data, ret->length);
+#endif
+ if (!ASN1_UTCTIME_check(ret))
+ {
+ OPENSSL_PUT_ERROR(ASN1, XXX, ASN1_R_INVALID_TIME_FORMAT);
+ goto err;
+ }
+
+ return(ret);
+err:
+ if ((ret != NULL) && ((a == NULL) || (*a != ret)))
+ M_ASN1_UTCTIME_free(ret);
+ return(NULL);
+ }
+
+#endif
+
+int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d)
+ {
+ static const int min[8]={ 0, 1, 1, 0, 0, 0, 0, 0};
+ static const int max[8]={99,12,31,23,59,59,12,59};
+ char *a;
+ int n,i,l,o;
+
+ if (d->type != V_ASN1_UTCTIME) return(0);
+ l=d->length;
+ a=(char *)d->data;
+ o=0;
+
+ if (l < 11) goto err;
+ for (i=0; i<6; i++)
+ {
+ if ((i == 5) && ((a[o] == 'Z') ||
+ (a[o] == '+') || (a[o] == '-')))
+ {
+ i++;
+ if (tm)
+ tm->tm_sec = 0;
+ break;
+ }
+ if ((a[o] < '0') || (a[o] > '9')) goto err;
+ n= a[o]-'0';
+ if (++o > l) goto err;
+
+ if ((a[o] < '0') || (a[o] > '9')) goto err;
+ n=(n*10)+ a[o]-'0';
+ if (++o > l) goto err;
+
+ if ((n < min[i]) || (n > max[i])) goto err;
+ if (tm)
+ {
+ switch(i)
+ {
+ case 0:
+ tm->tm_year = n < 50 ? n + 100 : n;
+ break;
+ case 1:
+ tm->tm_mon = n - 1;
+ break;
+ case 2:
+ tm->tm_mday = n;
+ break;
+ case 3:
+ tm->tm_hour = n;
+ break;
+ case 4:
+ tm->tm_min = n;
+ break;
+ case 5:
+ tm->tm_sec = n;
+ break;
+ }
+ }
+ }
+ if (a[o] == 'Z')
+ o++;
+ else if ((a[o] == '+') || (a[o] == '-'))
+ {
+ int offsign = a[o] == '-' ? -1 : 1, offset = 0;
+ o++;
+ if (o+4 > l) goto err;
+ for (i=6; i<8; i++)
+ {
+ if ((a[o] < '0') || (a[o] > '9')) goto err;
+ n= a[o]-'0';
+ o++;
+ if ((a[o] < '0') || (a[o] > '9')) goto err;
+ n=(n*10)+ a[o]-'0';
+ if ((n < min[i]) || (n > max[i])) goto err;
+ if (tm)
+ {
+ if (i == 6)
+ offset = n * 3600;
+ else if (i == 7)
+ offset += n * 60;
+ }
+ o++;
+ }
+ if (offset && !OPENSSL_gmtime_adj(tm, 0, offset * offsign))
+ return 0;
+ }
+ return o == l;
+err:
+ return 0;
+ }
+
+int ASN1_UTCTIME_check(const ASN1_UTCTIME *d)
+ {
+ return asn1_utctime_to_tm(NULL, d);
+ }
+
+int ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str)
+ {
+ ASN1_UTCTIME t;
+
+ t.type=V_ASN1_UTCTIME;
+ t.length=strlen(str);
+ t.data=(unsigned char *)str;
+ if (ASN1_UTCTIME_check(&t))
+ {
+ if (s != NULL)
+ {
+ if (!ASN1_STRING_set((ASN1_STRING *)s,
+ (unsigned char *)str,t.length))
+ return 0;
+ s->type = V_ASN1_UTCTIME;
+ }
+ return(1);
+ }
+ else
+ return(0);
+ }
+
+ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s, time_t t)
+ {
+ return ASN1_UTCTIME_adj(s, t, 0, 0);
+ }
+
+ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t,
+ int offset_day, long offset_sec)
+ {
+ char *p;
+ struct tm *ts;
+ struct tm data;
+ size_t len = 20;
+
+ if (s == NULL)
+ s=M_ASN1_UTCTIME_new();
+ if (s == NULL)
+ return(NULL);
+
+ ts=OPENSSL_gmtime(&t, &data);
+ if (ts == NULL)
+ return(NULL);
+
+ if (offset_day || offset_sec)
+ {
+ if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec))
+ return NULL;
+ }
+
+ if((ts->tm_year < 50) || (ts->tm_year >= 150))
+ return NULL;
+
+ p=(char *)s->data;
+ if ((p == NULL) || ((size_t)s->length < len))
+ {
+ p=OPENSSL_malloc(len);
+ if (p == NULL)
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_UTCTIME_adj, ERR_R_MALLOC_FAILURE);
+ return(NULL);
+ }
+ if (s->data != NULL)
+ OPENSSL_free(s->data);
+ s->data=(unsigned char *)p;
+ }
+
+ BIO_snprintf(p,len,"%02d%02d%02d%02d%02d%02dZ",ts->tm_year%100,
+ ts->tm_mon+1,ts->tm_mday,ts->tm_hour,ts->tm_min,ts->tm_sec);
+ s->length=strlen(p);
+ s->type=V_ASN1_UTCTIME;
+#ifdef CHARSET_EBCDIC_not
+ ebcdic2ascii(s->data, s->data, s->length);
+#endif
+ return(s);
+ }
+
+
+int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t)
+ {
+ struct tm stm, ttm;
+ int day, sec;
+
+ if (!asn1_utctime_to_tm(&stm, s))
+ return -2;
+
+ if (!OPENSSL_gmtime(&t, &ttm))
+ return -2;
+
+ if (!OPENSSL_gmtime_diff(&day, &sec, &stm, &ttm))
+ return -2;
+
+ if (day > 0)
+ return 1;
+ if (day < 0)
+ return -1;
+ if (sec > 0)
+ return 1;
+ if (sec < 0)
+ return -1;
+ return 0;
+ }
+
+
+#if 0
+time_t ASN1_UTCTIME_get(const ASN1_UTCTIME *s)
+ {
+ struct tm tm;
+ int offset;
+
+ memset(&tm,'\0',sizeof tm);
+
+#define g2(p) (((p)[0]-'0')*10+(p)[1]-'0')
+ tm.tm_year=g2(s->data);
+ if(tm.tm_year < 50)
+ tm.tm_year+=100;
+ tm.tm_mon=g2(s->data+2)-1;
+ tm.tm_mday=g2(s->data+4);
+ tm.tm_hour=g2(s->data+6);
+ tm.tm_min=g2(s->data+8);
+ tm.tm_sec=g2(s->data+10);
+ if(s->data[12] == 'Z')
+ offset=0;
+ else
+ {
+ offset=g2(s->data+13)*60+g2(s->data+15);
+ if(s->data[12] == '-')
+ offset= -offset;
+ }
+#undef g2
+
+ return mktime(&tm)-offset*60; /* FIXME: mktime assumes the current timezone
+ * instead of UTC, and unless we rewrite OpenSSL
+ * in Lisp we cannot locally change the timezone
+ * without possibly interfering with other parts
+ * of the program. timegm, which uses UTC, is
+ * non-standard.
+ * Also time_t is inappropriate for general
+ * UTC times because it may a 32 bit type. */
+ }
+#endif
diff --git a/crypto/asn1/a_utf8.c b/crypto/asn1/a_utf8.c
new file mode 100644
index 0000000..ed6e98d
--- /dev/null
+++ b/crypto/asn1/a_utf8.c
@@ -0,0 +1,210 @@
+/* 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/asn1.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+/* UTF8 utilities */
+
+/* This parses a UTF8 string one character at a time. It is passed a pointer
+ * to the string and the length of the string. It sets 'value' to the value of
+ * the current character. It returns the number of characters read or a
+ * negative error code:
+ * -1 = string too short
+ * -2 = illegal character
+ * -3 = subsequent characters not of the form 10xxxxxx
+ * -4 = character encoded incorrectly (not minimal length).
+ */
+
+int UTF8_getc(const unsigned char *str, int len, unsigned long *val)
+{
+ const unsigned char *p;
+ unsigned long value;
+ int ret;
+ if(len <= 0) return 0;
+ p = str;
+
+ /* Check syntax and work out the encoded value (if correct) */
+ if((*p & 0x80) == 0) {
+ value = *p++ & 0x7f;
+ ret = 1;
+ } else if((*p & 0xe0) == 0xc0) {
+ if(len < 2) return -1;
+ if((p[1] & 0xc0) != 0x80) return -3;
+ value = (*p++ & 0x1f) << 6;
+ value |= *p++ & 0x3f;
+ if(value < 0x80) return -4;
+ ret = 2;
+ } else if((*p & 0xf0) == 0xe0) {
+ if(len < 3) return -1;
+ if( ((p[1] & 0xc0) != 0x80)
+ || ((p[2] & 0xc0) != 0x80) ) return -3;
+ value = (*p++ & 0xf) << 12;
+ value |= (*p++ & 0x3f) << 6;
+ value |= *p++ & 0x3f;
+ if(value < 0x800) return -4;
+ ret = 3;
+ } else if((*p & 0xf8) == 0xf0) {
+ if(len < 4) return -1;
+ if( ((p[1] & 0xc0) != 0x80)
+ || ((p[2] & 0xc0) != 0x80)
+ || ((p[3] & 0xc0) != 0x80) ) return -3;
+ value = ((unsigned long)(*p++ & 0x7)) << 18;
+ value |= (*p++ & 0x3f) << 12;
+ value |= (*p++ & 0x3f) << 6;
+ value |= *p++ & 0x3f;
+ if(value < 0x10000) return -4;
+ ret = 4;
+ } else if((*p & 0xfc) == 0xf8) {
+ if(len < 5) return -1;
+ if( ((p[1] & 0xc0) != 0x80)
+ || ((p[2] & 0xc0) != 0x80)
+ || ((p[3] & 0xc0) != 0x80)
+ || ((p[4] & 0xc0) != 0x80) ) return -3;
+ value = ((unsigned long)(*p++ & 0x3)) << 24;
+ value |= ((unsigned long)(*p++ & 0x3f)) << 18;
+ value |= ((unsigned long)(*p++ & 0x3f)) << 12;
+ value |= (*p++ & 0x3f) << 6;
+ value |= *p++ & 0x3f;
+ if(value < 0x200000) return -4;
+ ret = 5;
+ } else if((*p & 0xfe) == 0xfc) {
+ if(len < 6) return -1;
+ if( ((p[1] & 0xc0) != 0x80)
+ || ((p[2] & 0xc0) != 0x80)
+ || ((p[3] & 0xc0) != 0x80)
+ || ((p[4] & 0xc0) != 0x80)
+ || ((p[5] & 0xc0) != 0x80) ) return -3;
+ value = ((unsigned long)(*p++ & 0x1)) << 30;
+ value |= ((unsigned long)(*p++ & 0x3f)) << 24;
+ value |= ((unsigned long)(*p++ & 0x3f)) << 18;
+ value |= ((unsigned long)(*p++ & 0x3f)) << 12;
+ value |= (*p++ & 0x3f) << 6;
+ value |= *p++ & 0x3f;
+ if(value < 0x4000000) return -4;
+ ret = 6;
+ } else return -2;
+ *val = value;
+ return ret;
+}
+
+/* This takes a character 'value' and writes the UTF8 encoded value in
+ * 'str' where 'str' is a buffer containing 'len' characters. Returns
+ * the number of characters written or -1 if 'len' is too small. 'str' can
+ * be set to NULL in which case it just returns the number of characters.
+ * It will need at most 6 characters.
+ */
+
+int UTF8_putc(unsigned char *str, int len, unsigned long value)
+{
+ if(!str) len = 6; /* Maximum we will need */
+ else if(len <= 0) return -1;
+ if(value < 0x80) {
+ if(str) *str = (unsigned char)value;
+ return 1;
+ }
+ if(value < 0x800) {
+ if(len < 2) return -1;
+ if(str) {
+ *str++ = (unsigned char)(((value >> 6) & 0x1f) | 0xc0);
+ *str = (unsigned char)((value & 0x3f) | 0x80);
+ }
+ return 2;
+ }
+ if(value < 0x10000) {
+ if(len < 3) return -1;
+ if(str) {
+ *str++ = (unsigned char)(((value >> 12) & 0xf) | 0xe0);
+ *str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80);
+ *str = (unsigned char)((value & 0x3f) | 0x80);
+ }
+ return 3;
+ }
+ if(value < 0x200000) {
+ if(len < 4) return -1;
+ if(str) {
+ *str++ = (unsigned char)(((value >> 18) & 0x7) | 0xf0);
+ *str++ = (unsigned char)(((value >> 12) & 0x3f) | 0x80);
+ *str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80);
+ *str = (unsigned char)((value & 0x3f) | 0x80);
+ }
+ return 4;
+ }
+ if(value < 0x4000000) {
+ if(len < 5) return -1;
+ if(str) {
+ *str++ = (unsigned char)(((value >> 24) & 0x3) | 0xf8);
+ *str++ = (unsigned char)(((value >> 18) & 0x3f) | 0x80);
+ *str++ = (unsigned char)(((value >> 12) & 0x3f) | 0x80);
+ *str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80);
+ *str = (unsigned char)((value & 0x3f) | 0x80);
+ }
+ return 5;
+ }
+ if(len < 6) return -1;
+ if(str) {
+ *str++ = (unsigned char)(((value >> 30) & 0x1) | 0xfc);
+ *str++ = (unsigned char)(((value >> 24) & 0x3f) | 0x80);
+ *str++ = (unsigned char)(((value >> 18) & 0x3f) | 0x80);
+ *str++ = (unsigned char)(((value >> 12) & 0x3f) | 0x80);
+ *str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80);
+ *str = (unsigned char)((value & 0x3f) | 0x80);
+ }
+ return 6;
+}
diff --git a/crypto/asn1/asn1.h b/crypto/asn1/asn1.h
new file mode 100644
index 0000000..79635bb
--- /dev/null
+++ b/crypto/asn1/asn1.h
@@ -0,0 +1,1333 @@
+/* crypto/asn1/asn1.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_ASN1_H
+#define HEADER_ASN1_H
+
+#include <openssl/base.h>
+
+#include <time.h>
+
+#ifndef OPENSSL_NO_BIO
+#include <openssl/bio.h>
+#endif
+#include <openssl/stack.h>
+
+#include <openssl/bn.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define V_ASN1_UNIVERSAL 0x00
+#define V_ASN1_APPLICATION 0x40
+#define V_ASN1_CONTEXT_SPECIFIC 0x80
+#define V_ASN1_PRIVATE 0xc0
+
+#define V_ASN1_CONSTRUCTED 0x20
+#define V_ASN1_PRIMITIVE_TAG 0x1f
+#define V_ASN1_PRIMATIVE_TAG 0x1f
+
+#define V_ASN1_APP_CHOOSE -2 /* let the recipient choose */
+#define V_ASN1_OTHER -3 /* used in ASN1_TYPE */
+#define V_ASN1_ANY -4 /* used in ASN1 template code */
+
+#define V_ASN1_NEG 0x100 /* negative flag */
+
+#define V_ASN1_UNDEF -1
+#define V_ASN1_EOC 0
+#define V_ASN1_BOOLEAN 1 /**/
+#define V_ASN1_INTEGER 2
+#define V_ASN1_NEG_INTEGER (2 | V_ASN1_NEG)
+#define V_ASN1_BIT_STRING 3
+#define V_ASN1_OCTET_STRING 4
+#define V_ASN1_NULL 5
+#define V_ASN1_OBJECT 6
+#define V_ASN1_OBJECT_DESCRIPTOR 7
+#define V_ASN1_EXTERNAL 8
+#define V_ASN1_REAL 9
+#define V_ASN1_ENUMERATED 10
+#define V_ASN1_NEG_ENUMERATED (10 | V_ASN1_NEG)
+#define V_ASN1_UTF8STRING 12
+#define V_ASN1_SEQUENCE 16
+#define V_ASN1_SET 17
+#define V_ASN1_NUMERICSTRING 18 /**/
+#define V_ASN1_PRINTABLESTRING 19
+#define V_ASN1_T61STRING 20
+#define V_ASN1_TELETEXSTRING 20 /* alias */
+#define V_ASN1_VIDEOTEXSTRING 21 /**/
+#define V_ASN1_IA5STRING 22
+#define V_ASN1_UTCTIME 23
+#define V_ASN1_GENERALIZEDTIME 24 /**/
+#define V_ASN1_GRAPHICSTRING 25 /**/
+#define V_ASN1_ISO64STRING 26 /**/
+#define V_ASN1_VISIBLESTRING 26 /* alias */
+#define V_ASN1_GENERALSTRING 27 /**/
+#define V_ASN1_UNIVERSALSTRING 28 /**/
+#define V_ASN1_BMPSTRING 30
+
+/* For use with d2i_ASN1_type_bytes() */
+#define B_ASN1_NUMERICSTRING 0x0001
+#define B_ASN1_PRINTABLESTRING 0x0002
+#define B_ASN1_T61STRING 0x0004
+#define B_ASN1_TELETEXSTRING 0x0004
+#define B_ASN1_VIDEOTEXSTRING 0x0008
+#define B_ASN1_IA5STRING 0x0010
+#define B_ASN1_GRAPHICSTRING 0x0020
+#define B_ASN1_ISO64STRING 0x0040
+#define B_ASN1_VISIBLESTRING 0x0040
+#define B_ASN1_GENERALSTRING 0x0080
+#define B_ASN1_UNIVERSALSTRING 0x0100
+#define B_ASN1_OCTET_STRING 0x0200
+#define B_ASN1_BIT_STRING 0x0400
+#define B_ASN1_BMPSTRING 0x0800
+#define B_ASN1_UNKNOWN 0x1000
+#define B_ASN1_UTF8STRING 0x2000
+#define B_ASN1_UTCTIME 0x4000
+#define B_ASN1_GENERALIZEDTIME 0x8000
+#define B_ASN1_SEQUENCE 0x10000
+
+/* For use with ASN1_mbstring_copy() */
+#define MBSTRING_FLAG 0x1000
+#define MBSTRING_UTF8 (MBSTRING_FLAG)
+#define MBSTRING_ASC (MBSTRING_FLAG|1)
+#define MBSTRING_BMP (MBSTRING_FLAG|2)
+#define MBSTRING_UNIV (MBSTRING_FLAG|4)
+
+#define SMIME_OLDMIME 0x400
+#define SMIME_CRLFEOL 0x800
+#define SMIME_STREAM 0x1000
+
+#define DECLARE_ASN1_SET_OF(type) /* filled in by mkstack.pl */
+#define IMPLEMENT_ASN1_SET_OF(type) /* nothing, no longer needed */
+
+/* We MUST make sure that, except for constness, asn1_ctx_st and
+ asn1_const_ctx are exactly the same. Fortunately, as soon as
+ the old ASN1 parsing macros are gone, we can throw this away
+ as well... */
+typedef struct asn1_ctx_st
+ {
+ unsigned char *p;/* work char pointer */
+ int eos; /* end of sequence read for indefinite encoding */
+ int error; /* error code to use when returning an error */
+ int inf; /* constructed if 0x20, indefinite is 0x21 */
+ int tag; /* tag from last 'get object' */
+ int xclass; /* class from last 'get object' */
+ long slen; /* length of last 'get object' */
+ unsigned char *max; /* largest value of p allowed */
+ unsigned char *q;/* temporary variable */
+ unsigned char **pp;/* variable */
+ int line; /* used in error processing */
+ } ASN1_CTX;
+
+typedef struct asn1_const_ctx_st
+ {
+ const unsigned char *p;/* work char pointer */
+ int eos; /* end of sequence read for indefinite encoding */
+ int error; /* error code to use when returning an error */
+ int inf; /* constructed if 0x20, indefinite is 0x21 */
+ int tag; /* tag from last 'get object' */
+ int xclass; /* class from last 'get object' */
+ long slen; /* length of last 'get object' */
+ const unsigned char *max; /* largest value of p allowed */
+ const unsigned char *q;/* temporary variable */
+ const unsigned char **pp;/* variable */
+ int line; /* used in error processing */
+ } ASN1_const_CTX;
+
+/* These are used internally in the ASN1_OBJECT to keep track of
+ * whether the names and data need to be free()ed */
+#define ASN1_OBJECT_FLAG_DYNAMIC 0x01 /* internal use */
+#define ASN1_OBJECT_FLAG_CRITICAL 0x02 /* critical x509v3 object id */
+#define ASN1_OBJECT_FLAG_DYNAMIC_STRINGS 0x04 /* internal use */
+#define ASN1_OBJECT_FLAG_DYNAMIC_DATA 0x08 /* internal use */
+struct asn1_object_st
+ {
+ const char *sn,*ln;
+ int nid;
+ int length;
+ const unsigned char *data; /* data remains const after init */
+ int flags; /* Should we free this one */
+ };
+
+#define ASN1_STRING_FLAG_BITS_LEFT 0x08 /* Set if 0x07 has bits left value */
+/* This indicates that the ASN1_STRING is not a real value but just a place
+ * holder for the location where indefinite length constructed data should
+ * be inserted in the memory buffer
+ */
+#define ASN1_STRING_FLAG_NDEF 0x010
+
+/* This flag is used by the CMS code to indicate that a string is not
+ * complete and is a place holder for content when it had all been
+ * accessed. The flag will be reset when content has been written to it.
+ */
+
+#define ASN1_STRING_FLAG_CONT 0x020
+/* This flag is used by ASN1 code to indicate an ASN1_STRING is an MSTRING
+ * type.
+ */
+#define ASN1_STRING_FLAG_MSTRING 0x040
+/* This is the base type that holds just about everything :-) */
+struct asn1_string_st
+ {
+ int length;
+ int type;
+ unsigned char *data;
+ /* The value of the following field depends on the type being
+ * held. It is mostly being used for BIT_STRING so if the
+ * input data has a non-zero 'unused bits' value, it will be
+ * handled correctly */
+ long flags;
+ };
+
+/* ASN1_ENCODING structure: this is used to save the received
+ * encoding of an ASN1 type. This is useful to get round
+ * problems with invalid encodings which can break signatures.
+ */
+
+typedef struct ASN1_ENCODING_st
+ {
+ unsigned char *enc; /* DER encoding */
+ long len; /* Length of encoding */
+ int modified; /* set to 1 if 'enc' is invalid */
+ } ASN1_ENCODING;
+
+/* Used with ASN1 LONG type: if a long is set to this it is omitted */
+#define ASN1_LONG_UNDEF 0x7fffffffL
+
+#define STABLE_FLAGS_MALLOC 0x01
+#define STABLE_NO_MASK 0x02
+#define DIRSTRING_TYPE \
+ (B_ASN1_PRINTABLESTRING|B_ASN1_T61STRING|B_ASN1_BMPSTRING|B_ASN1_UTF8STRING)
+#define PKCS9STRING_TYPE (DIRSTRING_TYPE|B_ASN1_IA5STRING)
+
+typedef struct asn1_string_table_st {
+ int nid;
+ long minsize;
+ long maxsize;
+ unsigned long mask;
+ unsigned long flags;
+} ASN1_STRING_TABLE;
+
+/* size limits: this stuff is taken straight from RFC2459 */
+
+#define ub_name 32768
+#define ub_common_name 64
+#define ub_locality_name 128
+#define ub_state_name 128
+#define ub_organization_name 64
+#define ub_organization_unit_name 64
+#define ub_title 64
+#define ub_email_address 128
+
+/* Declarations for template structures: for full definitions
+ * see asn1t.h
+ */
+typedef struct ASN1_TEMPLATE_st ASN1_TEMPLATE;
+typedef struct ASN1_TLC_st ASN1_TLC;
+/* This is just an opaque pointer */
+typedef struct ASN1_VALUE_st ASN1_VALUE;
+
+/* Declare ASN1 functions: the implement macro in in asn1t.h */
+
+#define DECLARE_ASN1_FUNCTIONS(type) DECLARE_ASN1_FUNCTIONS_name(type, type)
+
+#define DECLARE_ASN1_ALLOC_FUNCTIONS(type) \
+ DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, type)
+
+#define DECLARE_ASN1_FUNCTIONS_name(type, name) \
+ DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \
+ DECLARE_ASN1_ENCODE_FUNCTIONS(type, name, name)
+
+#define DECLARE_ASN1_FUNCTIONS_fname(type, itname, name) \
+ DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \
+ DECLARE_ASN1_ENCODE_FUNCTIONS(type, itname, name)
+
+#define DECLARE_ASN1_ENCODE_FUNCTIONS(type, itname, name) \
+ type *d2i_##name(type **a, const unsigned char **in, long len); \
+ int i2d_##name(type *a, unsigned char **out); \
+ DECLARE_ASN1_ITEM(itname)
+
+#define DECLARE_ASN1_ENCODE_FUNCTIONS_const(type, name) \
+ type *d2i_##name(type **a, const unsigned char **in, long len); \
+ int i2d_##name(const type *a, unsigned char **out); \
+ DECLARE_ASN1_ITEM(name)
+
+#define DECLARE_ASN1_NDEF_FUNCTION(name) \
+ int i2d_##name##_NDEF(name *a, unsigned char **out);
+
+#define DECLARE_ASN1_FUNCTIONS_const(name) \
+ DECLARE_ASN1_ALLOC_FUNCTIONS(name) \
+ DECLARE_ASN1_ENCODE_FUNCTIONS_const(name, name)
+
+#define DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \
+ type *name##_new(void); \
+ void name##_free(type *a);
+
+#define DECLARE_ASN1_PRINT_FUNCTION(stname) \
+ DECLARE_ASN1_PRINT_FUNCTION_fname(stname, stname)
+
+#define DECLARE_ASN1_PRINT_FUNCTION_fname(stname, fname) \
+ int fname##_print_ctx(BIO *out, stname *x, int indent, \
+ const ASN1_PCTX *pctx);
+
+#define D2I_OF(type) type *(*)(type **,const unsigned char **,long)
+#define I2D_OF(type) int (*)(type *,unsigned char **)
+#define I2D_OF_const(type) int (*)(const type *,unsigned char **)
+
+#define CHECKED_D2I_OF(type, d2i) \
+ ((d2i_of_void*) (1 ? d2i : ((D2I_OF(type))0)))
+#define CHECKED_I2D_OF(type, i2d) \
+ ((i2d_of_void*) (1 ? i2d : ((I2D_OF(type))0)))
+#define CHECKED_NEW_OF(type, xnew) \
+ ((void *(*)(void)) (1 ? xnew : ((type *(*)(void))0)))
+#define CHECKED_PPTR_OF(type, p) \
+ ((void**) (1 ? p : (type**)0))
+
+#define TYPEDEF_D2I_OF(type) typedef type *d2i_of_##type(type **,const unsigned char **,long)
+#define TYPEDEF_I2D_OF(type) typedef int i2d_of_##type(const type *,unsigned char **)
+#define TYPEDEF_D2I2D_OF(type) TYPEDEF_D2I_OF(type); TYPEDEF_I2D_OF(type)
+
+TYPEDEF_D2I2D_OF(void);
+
+/* The following macros and typedefs allow an ASN1_ITEM
+ * to be embedded in a structure and referenced. Since
+ * the ASN1_ITEM pointers need to be globally accessible
+ * (possibly from shared libraries) they may exist in
+ * different forms. On platforms that support it the
+ * ASN1_ITEM structure itself will be globally exported.
+ * Other platforms will export a function that returns
+ * an ASN1_ITEM pointer.
+ *
+ * To handle both cases transparently the macros below
+ * should be used instead of hard coding an ASN1_ITEM
+ * pointer in a structure.
+ *
+ * The structure will look like this:
+ *
+ * typedef struct SOMETHING_st {
+ * ...
+ * ASN1_ITEM_EXP *iptr;
+ * ...
+ * } SOMETHING;
+ *
+ * It would be initialised as e.g.:
+ *
+ * SOMETHING somevar = {...,ASN1_ITEM_ref(X509),...};
+ *
+ * and the actual pointer extracted with:
+ *
+ * const ASN1_ITEM *it = ASN1_ITEM_ptr(somevar.iptr);
+ *
+ * Finally an ASN1_ITEM pointer can be extracted from an
+ * appropriate reference with: ASN1_ITEM_rptr(X509). This
+ * would be used when a function takes an ASN1_ITEM * argument.
+ *
+ */
+
+#ifndef OPENSSL_EXPORT_VAR_AS_FUNCTION
+
+/* ASN1_ITEM pointer exported type */
+typedef const ASN1_ITEM ASN1_ITEM_EXP;
+
+/* Macro to obtain ASN1_ITEM pointer from exported type */
+#define ASN1_ITEM_ptr(iptr) (iptr)
+
+/* Macro to include ASN1_ITEM pointer from base type */
+#define ASN1_ITEM_ref(iptr) (&(iptr##_it))
+
+#define ASN1_ITEM_rptr(ref) (&(ref##_it))
+
+#define DECLARE_ASN1_ITEM(name) \
+ extern const ASN1_ITEM name##_it;
+
+#else
+
+/* Platforms that can't easily handle shared global variables are declared
+ * as functions returning ASN1_ITEM pointers.
+ */
+
+/* ASN1_ITEM pointer exported type */
+typedef const ASN1_ITEM * ASN1_ITEM_EXP(void);
+
+/* Macro to obtain ASN1_ITEM pointer from exported type */
+#define ASN1_ITEM_ptr(iptr) (iptr())
+
+/* Macro to include ASN1_ITEM pointer from base type */
+#define ASN1_ITEM_ref(iptr) (iptr##_it)
+
+#define ASN1_ITEM_rptr(ref) (ref##_it())
+
+#define DECLARE_ASN1_ITEM(name) \
+ const ASN1_ITEM * name##_it(void);
+
+#endif
+
+/* Parameters used by ASN1_STRING_print_ex() */
+
+/* These determine which characters to escape:
+ * RFC2253 special characters, control characters and
+ * MSB set characters
+ */
+
+#define ASN1_STRFLGS_ESC_2253 1
+#define ASN1_STRFLGS_ESC_CTRL 2
+#define ASN1_STRFLGS_ESC_MSB 4
+
+
+/* This flag determines how we do escaping: normally
+ * RC2253 backslash only, set this to use backslash and
+ * quote.
+ */
+
+#define ASN1_STRFLGS_ESC_QUOTE 8
+
+
+/* These three flags are internal use only. */
+
+/* Character is a valid PrintableString character */
+#define CHARTYPE_PRINTABLESTRING 0x10
+/* Character needs escaping if it is the first character */
+#define CHARTYPE_FIRST_ESC_2253 0x20
+/* Character needs escaping if it is the last character */
+#define CHARTYPE_LAST_ESC_2253 0x40
+
+/* NB the internal flags are safely reused below by flags
+ * handled at the top level.
+ */
+
+/* If this is set we convert all character strings
+ * to UTF8 first
+ */
+
+#define ASN1_STRFLGS_UTF8_CONVERT 0x10
+
+/* If this is set we don't attempt to interpret content:
+ * just assume all strings are 1 byte per character. This
+ * will produce some pretty odd looking output!
+ */
+
+#define ASN1_STRFLGS_IGNORE_TYPE 0x20
+
+/* If this is set we include the string type in the output */
+#define ASN1_STRFLGS_SHOW_TYPE 0x40
+
+/* This determines which strings to display and which to
+ * 'dump' (hex dump of content octets or DER encoding). We can
+ * only dump non character strings or everything. If we
+ * don't dump 'unknown' they are interpreted as character
+ * strings with 1 octet per character and are subject to
+ * the usual escaping options.
+ */
+
+#define ASN1_STRFLGS_DUMP_ALL 0x80
+#define ASN1_STRFLGS_DUMP_UNKNOWN 0x100
+
+/* These determine what 'dumping' does, we can dump the
+ * content octets or the DER encoding: both use the
+ * RFC2253 #XXXXX notation.
+ */
+
+#define ASN1_STRFLGS_DUMP_DER 0x200
+
+/* All the string flags consistent with RFC2253,
+ * escaping control characters isn't essential in
+ * RFC2253 but it is advisable anyway.
+ */
+
+#define ASN1_STRFLGS_RFC2253 (ASN1_STRFLGS_ESC_2253 | \
+ ASN1_STRFLGS_ESC_CTRL | \
+ ASN1_STRFLGS_ESC_MSB | \
+ ASN1_STRFLGS_UTF8_CONVERT | \
+ ASN1_STRFLGS_DUMP_UNKNOWN | \
+ ASN1_STRFLGS_DUMP_DER)
+
+DECLARE_ASN1_SET_OF(ASN1_INTEGER)
+
+typedef struct asn1_type_st
+ {
+ int type;
+ union {
+ char *ptr;
+ ASN1_BOOLEAN boolean;
+ ASN1_STRING * asn1_string;
+ ASN1_OBJECT * object;
+ ASN1_INTEGER * integer;
+ ASN1_ENUMERATED * enumerated;
+ ASN1_BIT_STRING * bit_string;
+ ASN1_OCTET_STRING * octet_string;
+ ASN1_PRINTABLESTRING * printablestring;
+ ASN1_T61STRING * t61string;
+ ASN1_IA5STRING * ia5string;
+ ASN1_GENERALSTRING * generalstring;
+ ASN1_BMPSTRING * bmpstring;
+ ASN1_UNIVERSALSTRING * universalstring;
+ ASN1_UTCTIME * utctime;
+ ASN1_GENERALIZEDTIME * generalizedtime;
+ ASN1_VISIBLESTRING * visiblestring;
+ ASN1_UTF8STRING * utf8string;
+ /* set and sequence are left complete and still
+ * contain the set or sequence bytes */
+ ASN1_STRING * set;
+ ASN1_STRING * sequence;
+ ASN1_VALUE * asn1_value;
+ } value;
+ } ASN1_TYPE;
+
+DECLARE_ASN1_SET_OF(ASN1_TYPE)
+
+typedef STACK_OF(ASN1_TYPE) ASN1_SEQUENCE_ANY;
+
+DECLARE_ASN1_ENCODE_FUNCTIONS_const(ASN1_SEQUENCE_ANY, ASN1_SEQUENCE_ANY)
+DECLARE_ASN1_ENCODE_FUNCTIONS_const(ASN1_SEQUENCE_ANY, ASN1_SET_ANY)
+
+struct X509_algor_st
+ {
+ ASN1_OBJECT *algorithm;
+ ASN1_TYPE *parameter;
+ } /* X509_ALGOR */;
+DEFINE_STACK_OF(X509_ALGOR);
+
+DECLARE_ASN1_FUNCTIONS(X509_ALGOR);
+
+typedef struct NETSCAPE_X509_st
+ {
+ ASN1_OCTET_STRING *header;
+ X509 *cert;
+ } NETSCAPE_X509;
+
+/* This is used to contain a list of bit names */
+typedef struct BIT_STRING_BITNAME_st {
+ int bitnum;
+ const char *lname;
+ const char *sname;
+} BIT_STRING_BITNAME;
+
+
+#define M_ASN1_STRING_length(x) ((x)->length)
+#define M_ASN1_STRING_length_set(x, n) ((x)->length = (n))
+#define M_ASN1_STRING_type(x) ((x)->type)
+#define M_ASN1_STRING_data(x) ((x)->data)
+
+/* Macros for string operations */
+#define M_ASN1_BIT_STRING_new() (ASN1_BIT_STRING *)\
+ ASN1_STRING_type_new(V_ASN1_BIT_STRING)
+#define M_ASN1_BIT_STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a)
+#define M_ASN1_BIT_STRING_dup(a) (ASN1_BIT_STRING *)\
+ ASN1_STRING_dup((const ASN1_STRING *)a)
+#define M_ASN1_BIT_STRING_cmp(a,b) ASN1_STRING_cmp(\
+ (const ASN1_STRING *)a,(const ASN1_STRING *)b)
+#define M_ASN1_BIT_STRING_set(a,b,c) ASN1_STRING_set((ASN1_STRING *)a,b,c)
+
+#define M_ASN1_INTEGER_new() (ASN1_INTEGER *)\
+ ASN1_STRING_type_new(V_ASN1_INTEGER)
+#define M_ASN1_INTEGER_free(a) ASN1_STRING_free((ASN1_STRING *)a)
+#define M_ASN1_INTEGER_dup(a) (ASN1_INTEGER *)\
+ ASN1_STRING_dup((const ASN1_STRING *)a)
+#define M_ASN1_INTEGER_cmp(a,b) ASN1_STRING_cmp(\
+ (const ASN1_STRING *)a,(const ASN1_STRING *)b)
+
+#define M_ASN1_ENUMERATED_new() (ASN1_ENUMERATED *)\
+ ASN1_STRING_type_new(V_ASN1_ENUMERATED)
+#define M_ASN1_ENUMERATED_free(a) ASN1_STRING_free((ASN1_STRING *)a)
+#define M_ASN1_ENUMERATED_dup(a) (ASN1_ENUMERATED *)\
+ ASN1_STRING_dup((const ASN1_STRING *)a)
+#define M_ASN1_ENUMERATED_cmp(a,b) ASN1_STRING_cmp(\
+ (const ASN1_STRING *)a,(const ASN1_STRING *)b)
+
+#define M_ASN1_OCTET_STRING_new() (ASN1_OCTET_STRING *)\
+ ASN1_STRING_type_new(V_ASN1_OCTET_STRING)
+#define M_ASN1_OCTET_STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a)
+#define M_ASN1_OCTET_STRING_dup(a) (ASN1_OCTET_STRING *)\
+ ASN1_STRING_dup((const ASN1_STRING *)a)
+#define M_ASN1_OCTET_STRING_cmp(a,b) ASN1_STRING_cmp(\
+ (const ASN1_STRING *)a,(const ASN1_STRING *)b)
+#define M_ASN1_OCTET_STRING_set(a,b,c) ASN1_STRING_set((ASN1_STRING *)a,b,c)
+#define M_ASN1_OCTET_STRING_print(a,b) ASN1_STRING_print(a,(ASN1_STRING *)b)
+#define M_i2d_ASN1_OCTET_STRING(a,pp) \
+ i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_OCTET_STRING,\
+ V_ASN1_UNIVERSAL)
+
+#define B_ASN1_TIME \
+ B_ASN1_UTCTIME | \
+ B_ASN1_GENERALIZEDTIME
+
+#define B_ASN1_PRINTABLE \
+ B_ASN1_NUMERICSTRING| \
+ B_ASN1_PRINTABLESTRING| \
+ B_ASN1_T61STRING| \
+ B_ASN1_IA5STRING| \
+ B_ASN1_BIT_STRING| \
+ B_ASN1_UNIVERSALSTRING|\
+ B_ASN1_BMPSTRING|\
+ B_ASN1_UTF8STRING|\
+ B_ASN1_SEQUENCE|\
+ B_ASN1_UNKNOWN
+
+#define B_ASN1_DIRECTORYSTRING \
+ B_ASN1_PRINTABLESTRING| \
+ B_ASN1_TELETEXSTRING|\
+ B_ASN1_BMPSTRING|\
+ B_ASN1_UNIVERSALSTRING|\
+ B_ASN1_UTF8STRING
+
+#define B_ASN1_DISPLAYTEXT \
+ B_ASN1_IA5STRING| \
+ B_ASN1_VISIBLESTRING| \
+ B_ASN1_BMPSTRING|\
+ B_ASN1_UTF8STRING
+
+#define M_ASN1_PRINTABLE_new() ASN1_STRING_type_new(V_ASN1_T61STRING)
+#define M_ASN1_PRINTABLE_free(a) ASN1_STRING_free((ASN1_STRING *)a)
+#define M_i2d_ASN1_PRINTABLE(a,pp) i2d_ASN1_bytes((ASN1_STRING *)a,\
+ pp,a->type,V_ASN1_UNIVERSAL)
+#define M_d2i_ASN1_PRINTABLE(a,pp,l) \
+ d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l, \
+ B_ASN1_PRINTABLE)
+
+#define M_DIRECTORYSTRING_new() ASN1_STRING_type_new(V_ASN1_PRINTABLESTRING)
+#define M_DIRECTORYSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a)
+#define M_i2d_DIRECTORYSTRING(a,pp) i2d_ASN1_bytes((ASN1_STRING *)a,\
+ pp,a->type,V_ASN1_UNIVERSAL)
+#define M_d2i_DIRECTORYSTRING(a,pp,l) \
+ d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l, \
+ B_ASN1_DIRECTORYSTRING)
+
+#define M_DISPLAYTEXT_new() ASN1_STRING_type_new(V_ASN1_VISIBLESTRING)
+#define M_DISPLAYTEXT_free(a) ASN1_STRING_free((ASN1_STRING *)a)
+#define M_i2d_DISPLAYTEXT(a,pp) i2d_ASN1_bytes((ASN1_STRING *)a,\
+ pp,a->type,V_ASN1_UNIVERSAL)
+#define M_d2i_DISPLAYTEXT(a,pp,l) \
+ d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l, \
+ B_ASN1_DISPLAYTEXT)
+
+#define M_ASN1_PRINTABLESTRING_new() (ASN1_PRINTABLESTRING *)\
+ ASN1_STRING_type_new(V_ASN1_PRINTABLESTRING)
+#define M_ASN1_PRINTABLESTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a)
+#define M_i2d_ASN1_PRINTABLESTRING(a,pp) \
+ i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_PRINTABLESTRING,\
+ V_ASN1_UNIVERSAL)
+#define M_d2i_ASN1_PRINTABLESTRING(a,pp,l) \
+ (ASN1_PRINTABLESTRING *)d2i_ASN1_type_bytes\
+ ((ASN1_STRING **)a,pp,l,B_ASN1_PRINTABLESTRING)
+
+#define M_ASN1_T61STRING_new() (ASN1_T61STRING *)\
+ ASN1_STRING_type_new(V_ASN1_T61STRING)
+#define M_ASN1_T61STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a)
+#define M_i2d_ASN1_T61STRING(a,pp) \
+ i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_T61STRING,\
+ V_ASN1_UNIVERSAL)
+#define M_d2i_ASN1_T61STRING(a,pp,l) \
+ (ASN1_T61STRING *)d2i_ASN1_type_bytes\
+ ((ASN1_STRING **)a,pp,l,B_ASN1_T61STRING)
+
+#define M_ASN1_IA5STRING_new() (ASN1_IA5STRING *)\
+ ASN1_STRING_type_new(V_ASN1_IA5STRING)
+#define M_ASN1_IA5STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a)
+#define M_ASN1_IA5STRING_dup(a) \
+ (ASN1_IA5STRING *)ASN1_STRING_dup((const ASN1_STRING *)a)
+#define M_i2d_ASN1_IA5STRING(a,pp) \
+ i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_IA5STRING,\
+ V_ASN1_UNIVERSAL)
+#define M_d2i_ASN1_IA5STRING(a,pp,l) \
+ (ASN1_IA5STRING *)d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l,\
+ B_ASN1_IA5STRING)
+
+#define M_ASN1_UTCTIME_new() (ASN1_UTCTIME *)\
+ ASN1_STRING_type_new(V_ASN1_UTCTIME)
+#define M_ASN1_UTCTIME_free(a) ASN1_STRING_free((ASN1_STRING *)a)
+#define M_ASN1_UTCTIME_dup(a) (ASN1_UTCTIME *)\
+ ASN1_STRING_dup((const ASN1_STRING *)a)
+
+#define M_ASN1_GENERALIZEDTIME_new() (ASN1_GENERALIZEDTIME *)\
+ ASN1_STRING_type_new(V_ASN1_GENERALIZEDTIME)
+#define M_ASN1_GENERALIZEDTIME_free(a) ASN1_STRING_free((ASN1_STRING *)a)
+#define M_ASN1_GENERALIZEDTIME_dup(a) (ASN1_GENERALIZEDTIME *)ASN1_STRING_dup(\
+ (const ASN1_STRING *)a)
+
+#define M_ASN1_TIME_new() (ASN1_TIME *)\
+ ASN1_STRING_type_new(V_ASN1_UTCTIME)
+#define M_ASN1_TIME_free(a) ASN1_STRING_free((ASN1_STRING *)a)
+#define M_ASN1_TIME_dup(a) (ASN1_TIME *)\
+ ASN1_STRING_dup((const ASN1_STRING *)a)
+
+#define M_ASN1_GENERALSTRING_new() (ASN1_GENERALSTRING *)\
+ ASN1_STRING_type_new(V_ASN1_GENERALSTRING)
+#define M_ASN1_GENERALSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a)
+#define M_i2d_ASN1_GENERALSTRING(a,pp) \
+ i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_GENERALSTRING,\
+ V_ASN1_UNIVERSAL)
+#define M_d2i_ASN1_GENERALSTRING(a,pp,l) \
+ (ASN1_GENERALSTRING *)d2i_ASN1_type_bytes\
+ ((ASN1_STRING **)a,pp,l,B_ASN1_GENERALSTRING)
+
+#define M_ASN1_UNIVERSALSTRING_new() (ASN1_UNIVERSALSTRING *)\
+ ASN1_STRING_type_new(V_ASN1_UNIVERSALSTRING)
+#define M_ASN1_UNIVERSALSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a)
+#define M_i2d_ASN1_UNIVERSALSTRING(a,pp) \
+ i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_UNIVERSALSTRING,\
+ V_ASN1_UNIVERSAL)
+#define M_d2i_ASN1_UNIVERSALSTRING(a,pp,l) \
+ (ASN1_UNIVERSALSTRING *)d2i_ASN1_type_bytes\
+ ((ASN1_STRING **)a,pp,l,B_ASN1_UNIVERSALSTRING)
+
+#define M_ASN1_BMPSTRING_new() (ASN1_BMPSTRING *)\
+ ASN1_STRING_type_new(V_ASN1_BMPSTRING)
+#define M_ASN1_BMPSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a)
+#define M_i2d_ASN1_BMPSTRING(a,pp) \
+ i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_BMPSTRING,\
+ V_ASN1_UNIVERSAL)
+#define M_d2i_ASN1_BMPSTRING(a,pp,l) \
+ (ASN1_BMPSTRING *)d2i_ASN1_type_bytes\
+ ((ASN1_STRING **)a,pp,l,B_ASN1_BMPSTRING)
+
+#define M_ASN1_VISIBLESTRING_new() (ASN1_VISIBLESTRING *)\
+ ASN1_STRING_type_new(V_ASN1_VISIBLESTRING)
+#define M_ASN1_VISIBLESTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a)
+#define M_i2d_ASN1_VISIBLESTRING(a,pp) \
+ i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_VISIBLESTRING,\
+ V_ASN1_UNIVERSAL)
+#define M_d2i_ASN1_VISIBLESTRING(a,pp,l) \
+ (ASN1_VISIBLESTRING *)d2i_ASN1_type_bytes\
+ ((ASN1_STRING **)a,pp,l,B_ASN1_VISIBLESTRING)
+
+#define M_ASN1_UTF8STRING_new() (ASN1_UTF8STRING *)\
+ ASN1_STRING_type_new(V_ASN1_UTF8STRING)
+#define M_ASN1_UTF8STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a)
+#define M_i2d_ASN1_UTF8STRING(a,pp) \
+ i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_UTF8STRING,\
+ V_ASN1_UNIVERSAL)
+#define M_d2i_ASN1_UTF8STRING(a,pp,l) \
+ (ASN1_UTF8STRING *)d2i_ASN1_type_bytes\
+ ((ASN1_STRING **)a,pp,l,B_ASN1_UTF8STRING)
+
+ /* for the is_set parameter to i2d_ASN1_SET */
+#define IS_SEQUENCE 0
+#define IS_SET 1
+
+DECLARE_ASN1_FUNCTIONS_fname(ASN1_TYPE, ASN1_ANY, ASN1_TYPE)
+
+int ASN1_TYPE_get(ASN1_TYPE *a);
+void ASN1_TYPE_set(ASN1_TYPE *a, int type, void *value);
+int ASN1_TYPE_set1(ASN1_TYPE *a, int type, const void *value);
+int ASN1_TYPE_cmp(ASN1_TYPE *a, ASN1_TYPE *b);
+
+ASN1_OBJECT * ASN1_OBJECT_new(void );
+void ASN1_OBJECT_free(ASN1_OBJECT *a);
+int i2d_ASN1_OBJECT(ASN1_OBJECT *a,unsigned char **pp);
+ASN1_OBJECT * c2i_ASN1_OBJECT(ASN1_OBJECT **a,const unsigned char **pp,
+ long length);
+ASN1_OBJECT * d2i_ASN1_OBJECT(ASN1_OBJECT **a,const unsigned char **pp,
+ long length);
+
+DECLARE_ASN1_ITEM(ASN1_OBJECT)
+
+DECLARE_ASN1_SET_OF(ASN1_OBJECT)
+
+ASN1_STRING * ASN1_STRING_new(void);
+void ASN1_STRING_free(ASN1_STRING *a);
+int ASN1_STRING_copy(ASN1_STRING *dst, const ASN1_STRING *str);
+ASN1_STRING * ASN1_STRING_dup(const ASN1_STRING *a);
+ASN1_STRING * ASN1_STRING_type_new(int type );
+int ASN1_STRING_cmp(const ASN1_STRING *a, const ASN1_STRING *b);
+ /* Since this is used to store all sorts of things, via macros, for now, make
+ its data void * */
+int ASN1_STRING_set(ASN1_STRING *str, const void *data, int len);
+void ASN1_STRING_set0(ASN1_STRING *str, void *data, int len);
+int ASN1_STRING_length(const ASN1_STRING *x);
+void ASN1_STRING_length_set(ASN1_STRING *x, int n);
+int ASN1_STRING_type(ASN1_STRING *x);
+unsigned char * ASN1_STRING_data(ASN1_STRING *x);
+
+DECLARE_ASN1_FUNCTIONS(ASN1_BIT_STRING)
+int i2c_ASN1_BIT_STRING(ASN1_BIT_STRING *a,unsigned char **pp);
+ASN1_BIT_STRING *c2i_ASN1_BIT_STRING(ASN1_BIT_STRING **a,const unsigned char **pp,
+ long length);
+int ASN1_BIT_STRING_set(ASN1_BIT_STRING *a, unsigned char *d,
+ int length );
+int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value);
+int ASN1_BIT_STRING_get_bit(ASN1_BIT_STRING *a, int n);
+int ASN1_BIT_STRING_check(ASN1_BIT_STRING *a,
+ unsigned char *flags, int flags_len);
+
+#ifndef OPENSSL_NO_BIO
+int ASN1_BIT_STRING_name_print(BIO *out, ASN1_BIT_STRING *bs,
+ BIT_STRING_BITNAME *tbl, int indent);
+#endif
+int ASN1_BIT_STRING_num_asc(char *name, BIT_STRING_BITNAME *tbl);
+int ASN1_BIT_STRING_set_asc(ASN1_BIT_STRING *bs, char *name, int value,
+ BIT_STRING_BITNAME *tbl);
+
+int i2d_ASN1_BOOLEAN(int a,unsigned char **pp);
+int d2i_ASN1_BOOLEAN(int *a,const unsigned char **pp,long length);
+
+DECLARE_ASN1_FUNCTIONS(ASN1_INTEGER)
+int i2c_ASN1_INTEGER(ASN1_INTEGER *a,unsigned char **pp);
+ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a,const unsigned char **pp,
+ long length);
+ASN1_INTEGER *d2i_ASN1_UINTEGER(ASN1_INTEGER **a,const unsigned char **pp,
+ long length);
+ASN1_INTEGER * ASN1_INTEGER_dup(const ASN1_INTEGER *x);
+int ASN1_INTEGER_cmp(const ASN1_INTEGER *x, const ASN1_INTEGER *y);
+
+DECLARE_ASN1_FUNCTIONS(ASN1_ENUMERATED)
+
+int ASN1_UTCTIME_check(const ASN1_UTCTIME *a);
+ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s,time_t t);
+ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t,
+ int offset_day, long offset_sec);
+int ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str);
+int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t);
+#if 0
+time_t ASN1_UTCTIME_get(const ASN1_UTCTIME *s);
+#endif
+
+int ASN1_GENERALIZEDTIME_check(const ASN1_GENERALIZEDTIME *a);
+ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *s,time_t t);
+ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s,
+ time_t t, int offset_day, long offset_sec);
+int ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *s, const char *str);
+int ASN1_TIME_diff(int *pday, int *psec,
+ const ASN1_TIME *from, const ASN1_TIME *to);
+
+DECLARE_ASN1_FUNCTIONS(ASN1_OCTET_STRING)
+ASN1_OCTET_STRING * ASN1_OCTET_STRING_dup(const ASN1_OCTET_STRING *a);
+int ASN1_OCTET_STRING_cmp(const ASN1_OCTET_STRING *a, const ASN1_OCTET_STRING *b);
+int ASN1_OCTET_STRING_set(ASN1_OCTET_STRING *str, const unsigned char *data, int len);
+
+DECLARE_ASN1_FUNCTIONS(ASN1_VISIBLESTRING)
+DECLARE_ASN1_FUNCTIONS(ASN1_UNIVERSALSTRING)
+DECLARE_ASN1_FUNCTIONS(ASN1_UTF8STRING)
+DECLARE_ASN1_FUNCTIONS(ASN1_NULL)
+DECLARE_ASN1_FUNCTIONS(ASN1_BMPSTRING)
+
+int UTF8_getc(const unsigned char *str, int len, unsigned long *val);
+int UTF8_putc(unsigned char *str, int len, unsigned long value);
+
+DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, ASN1_PRINTABLE)
+
+DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, DIRECTORYSTRING)
+DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, DISPLAYTEXT)
+DECLARE_ASN1_FUNCTIONS(ASN1_PRINTABLESTRING)
+DECLARE_ASN1_FUNCTIONS(ASN1_T61STRING)
+DECLARE_ASN1_FUNCTIONS(ASN1_IA5STRING)
+DECLARE_ASN1_FUNCTIONS(ASN1_GENERALSTRING)
+DECLARE_ASN1_FUNCTIONS(ASN1_UTCTIME)
+DECLARE_ASN1_FUNCTIONS(ASN1_GENERALIZEDTIME)
+DECLARE_ASN1_FUNCTIONS(ASN1_TIME)
+
+DECLARE_ASN1_ITEM(ASN1_OCTET_STRING_NDEF)
+
+ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s,time_t t);
+ASN1_TIME *ASN1_TIME_adj(ASN1_TIME *s,time_t t,
+ int offset_day, long offset_sec);
+int ASN1_TIME_check(ASN1_TIME *t);
+ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *t, ASN1_GENERALIZEDTIME **out);
+int ASN1_TIME_set_string(ASN1_TIME *s, const char *str);
+
+int i2d_ASN1_SET(STACK_OF(OPENSSL_BLOCK) *a, unsigned char **pp,
+ i2d_of_void *i2d, int ex_tag, int ex_class,
+ int is_set);
+STACK_OF(OPENSSL_BLOCK) *d2i_ASN1_SET(STACK_OF(OPENSSL_BLOCK) **a,
+ const unsigned char **pp,
+ long length, d2i_of_void *d2i,
+ void (*free_func)(OPENSSL_BLOCK), int ex_tag,
+ int ex_class);
+
+#ifndef OPENSSL_NO_BIO
+int i2a_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *a);
+int a2i_ASN1_INTEGER(BIO *bp,ASN1_INTEGER *bs,char *buf,int size);
+int i2a_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *a);
+int a2i_ASN1_ENUMERATED(BIO *bp,ASN1_ENUMERATED *bs,char *buf,int size);
+int i2a_ASN1_OBJECT(BIO *bp,ASN1_OBJECT *a);
+int a2i_ASN1_STRING(BIO *bp,ASN1_STRING *bs,char *buf,int size);
+int i2a_ASN1_STRING(BIO *bp, ASN1_STRING *a, int type);
+#endif
+int i2t_ASN1_OBJECT(char *buf,int buf_len,ASN1_OBJECT *a);
+
+int a2d_ASN1_OBJECT(unsigned char *out,int olen, const char *buf, int num);
+ASN1_OBJECT *ASN1_OBJECT_create(int nid, unsigned char *data,int len,
+ const char *sn, const char *ln);
+
+int ASN1_INTEGER_set(ASN1_INTEGER *a, long v);
+long ASN1_INTEGER_get(const ASN1_INTEGER *a);
+ASN1_INTEGER *BN_to_ASN1_INTEGER(const BIGNUM *bn, ASN1_INTEGER *ai);
+BIGNUM *ASN1_INTEGER_to_BN(const ASN1_INTEGER *ai,BIGNUM *bn);
+
+int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v);
+long ASN1_ENUMERATED_get(ASN1_ENUMERATED *a);
+ASN1_ENUMERATED *BN_to_ASN1_ENUMERATED(BIGNUM *bn, ASN1_ENUMERATED *ai);
+BIGNUM *ASN1_ENUMERATED_to_BN(ASN1_ENUMERATED *ai,BIGNUM *bn);
+
+/* General */
+/* given a string, return the correct type, max is the maximum length */
+int ASN1_PRINTABLE_type(const unsigned char *s, int max);
+
+int i2d_ASN1_bytes(ASN1_STRING *a, unsigned char **pp, int tag, int xclass);
+ASN1_STRING *d2i_ASN1_bytes(ASN1_STRING **a, const unsigned char **pp,
+ long length, int Ptag, int Pclass);
+unsigned long ASN1_tag2bit(int tag);
+/* type is one or more of the B_ASN1_ values. */
+ASN1_STRING *d2i_ASN1_type_bytes(ASN1_STRING **a,const unsigned char **pp,
+ long length,int type);
+
+/* PARSING */
+int asn1_Finish(ASN1_CTX *c);
+int asn1_const_Finish(ASN1_const_CTX *c);
+
+/* SPECIALS */
+int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag,
+ int *pclass, long omax);
+int ASN1_check_infinite_end(unsigned char **p,long len);
+int ASN1_const_check_infinite_end(const unsigned char **p,long len);
+void ASN1_put_object(unsigned char **pp, int constructed, int length,
+ int tag, int xclass);
+int ASN1_put_eoc(unsigned char **pp);
+int ASN1_object_size(int constructed, int length, int tag);
+
+/* Used to implement other functions */
+void *ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, void *x);
+
+#define ASN1_dup_of(type,i2d,d2i,x) \
+ ((type*)ASN1_dup(CHECKED_I2D_OF(type, i2d), \
+ CHECKED_D2I_OF(type, d2i), \
+ CHECKED_PTR_OF(type, x)))
+
+#define ASN1_dup_of_const(type,i2d,d2i,x) \
+ ((type*)ASN1_dup(CHECKED_I2D_OF(const type, i2d), \
+ CHECKED_D2I_OF(type, d2i), \
+ CHECKED_PTR_OF(const type, x)))
+
+void *ASN1_item_dup(const ASN1_ITEM *it, void *x);
+
+/* ASN1 alloc/free macros for when a type is only used internally */
+
+#define M_ASN1_new_of(type) (type *)ASN1_item_new(ASN1_ITEM_rptr(type))
+#define M_ASN1_free_of(x, type) \
+ ASN1_item_free(CHECKED_PTR_OF(type, x), ASN1_ITEM_rptr(type))
+
+#ifndef OPENSSL_NO_FP_API
+void *ASN1_d2i_fp(void *(*xnew)(void), d2i_of_void *d2i, FILE *in, void **x);
+
+#define ASN1_d2i_fp_of(type,xnew,d2i,in,x) \
+ ((type*)ASN1_d2i_fp(CHECKED_NEW_OF(type, xnew), \
+ CHECKED_D2I_OF(type, d2i), \
+ in, \
+ CHECKED_PPTR_OF(type, x)))
+
+void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x);
+int ASN1_i2d_fp(i2d_of_void *i2d,FILE *out,void *x);
+
+#define ASN1_i2d_fp_of(type,i2d,out,x) \
+ (ASN1_i2d_fp(CHECKED_I2D_OF(type, i2d), \
+ out, \
+ CHECKED_PTR_OF(type, x)))
+
+#define ASN1_i2d_fp_of_const(type,i2d,out,x) \
+ (ASN1_i2d_fp(CHECKED_I2D_OF(const type, i2d), \
+ out, \
+ CHECKED_PTR_OF(const type, x)))
+
+int ASN1_item_i2d_fp(const ASN1_ITEM *it, FILE *out, void *x);
+int ASN1_STRING_print_ex_fp(FILE *fp, ASN1_STRING *str, unsigned long flags);
+#endif
+
+int ASN1_STRING_to_UTF8(unsigned char **out, ASN1_STRING *in);
+
+#ifndef OPENSSL_NO_BIO
+void *ASN1_d2i_bio(void *(*xnew)(void), d2i_of_void *d2i, BIO *in, void **x);
+
+#define ASN1_d2i_bio_of(type,xnew,d2i,in,x) \
+ ((type*)ASN1_d2i_bio( CHECKED_NEW_OF(type, xnew), \
+ CHECKED_D2I_OF(type, d2i), \
+ in, \
+ CHECKED_PPTR_OF(type, x)))
+
+void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x);
+int ASN1_i2d_bio(i2d_of_void *i2d,BIO *out, unsigned char *x);
+
+#define ASN1_i2d_bio_of(type,i2d,out,x) \
+ (ASN1_i2d_bio(CHECKED_I2D_OF(type, i2d), \
+ out, \
+ CHECKED_PTR_OF(type, x)))
+
+#define ASN1_i2d_bio_of_const(type,i2d,out,x) \
+ (ASN1_i2d_bio(CHECKED_I2D_OF(const type, i2d), \
+ out, \
+ CHECKED_PTR_OF(const type, x)))
+
+int ASN1_item_i2d_bio(const ASN1_ITEM *it, BIO *out, void *x);
+int ASN1_UTCTIME_print(BIO *fp, const ASN1_UTCTIME *a);
+int ASN1_GENERALIZEDTIME_print(BIO *fp, const ASN1_GENERALIZEDTIME *a);
+int ASN1_TIME_print(BIO *fp, const ASN1_TIME *a);
+int ASN1_STRING_print(BIO *bp, const ASN1_STRING *v);
+int ASN1_STRING_print_ex(BIO *out, ASN1_STRING *str, unsigned long flags);
+int ASN1_bn_print(BIO *bp, const char *number, const BIGNUM *num,
+ unsigned char *buf, int off);
+int ASN1_parse(BIO *bp,const unsigned char *pp,long len,int indent);
+int ASN1_parse_dump(BIO *bp,const unsigned char *pp,long len,int indent,int dump);
+#endif
+const char *ASN1_tag2str(int tag);
+
+/* Used to load and write netscape format cert */
+
+DECLARE_ASN1_FUNCTIONS(NETSCAPE_X509)
+
+int ASN1_UNIVERSALSTRING_to_string(ASN1_UNIVERSALSTRING *s);
+
+STACK_OF(OPENSSL_BLOCK) *ASN1_seq_unpack(const unsigned char *buf, int len,
+ d2i_of_void *d2i, void (*free_func)(OPENSSL_BLOCK));
+unsigned char *ASN1_seq_pack(STACK_OF(OPENSSL_BLOCK) *safes, i2d_of_void *i2d,
+ unsigned char **buf, int *len );
+void *ASN1_unpack_string(ASN1_STRING *oct, d2i_of_void *d2i);
+void *ASN1_item_unpack(ASN1_STRING *oct, const ASN1_ITEM *it);
+ASN1_STRING *ASN1_pack_string(void *obj, i2d_of_void *i2d,
+ ASN1_OCTET_STRING **oct);
+
+#define ASN1_pack_string_of(type,obj,i2d,oct) \
+ (ASN1_pack_string(CHECKED_PTR_OF(type, obj), \
+ CHECKED_I2D_OF(type, i2d), \
+ oct))
+
+ASN1_STRING *ASN1_item_pack(void *obj, const ASN1_ITEM *it, ASN1_OCTET_STRING **oct);
+
+void ASN1_STRING_set_default_mask(unsigned long mask);
+int ASN1_STRING_set_default_mask_asc(const char *p);
+unsigned long ASN1_STRING_get_default_mask(void);
+int ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len,
+ int inform, unsigned long mask);
+int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
+ int inform, unsigned long mask,
+ long minsize, long maxsize);
+
+ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out,
+ const unsigned char *in, int inlen, int inform, int nid);
+ASN1_STRING_TABLE *ASN1_STRING_TABLE_get(int nid);
+int ASN1_STRING_TABLE_add(int, long, long, unsigned long, unsigned long);
+void ASN1_STRING_TABLE_cleanup(void);
+
+/* ASN1 template functions */
+
+/* Old API compatible functions */
+ASN1_VALUE *ASN1_item_new(const ASN1_ITEM *it);
+void ASN1_item_free(ASN1_VALUE *val, const ASN1_ITEM *it);
+ASN1_VALUE * ASN1_item_d2i(ASN1_VALUE **val, const unsigned char **in, long len, const ASN1_ITEM *it);
+int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it);
+int ASN1_item_ndef_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it);
+
+void ASN1_add_oid_module(void);
+
+ASN1_TYPE *ASN1_generate_nconf(char *str, CONF *nconf);
+ASN1_TYPE *ASN1_generate_v3(char *str, X509V3_CTX *cnf);
+
+/* ASN1 Print flags */
+
+/* Indicate missing OPTIONAL fields */
+#define ASN1_PCTX_FLAGS_SHOW_ABSENT 0x001
+/* Mark start and end of SEQUENCE */
+#define ASN1_PCTX_FLAGS_SHOW_SEQUENCE 0x002
+/* Mark start and end of SEQUENCE/SET OF */
+#define ASN1_PCTX_FLAGS_SHOW_SSOF 0x004
+/* Show the ASN1 type of primitives */
+#define ASN1_PCTX_FLAGS_SHOW_TYPE 0x008
+/* Don't show ASN1 type of ANY */
+#define ASN1_PCTX_FLAGS_NO_ANY_TYPE 0x010
+/* Don't show ASN1 type of MSTRINGs */
+#define ASN1_PCTX_FLAGS_NO_MSTRING_TYPE 0x020
+/* Don't show field names in SEQUENCE */
+#define ASN1_PCTX_FLAGS_NO_FIELD_NAME 0x040
+/* Show structure names of each SEQUENCE field */
+#define ASN1_PCTX_FLAGS_SHOW_FIELD_STRUCT_NAME 0x080
+/* Don't show structure name even at top level */
+#define ASN1_PCTX_FLAGS_NO_STRUCT_NAME 0x100
+
+int ASN1_item_print(BIO *out, ASN1_VALUE *ifld, int indent,
+ const ASN1_ITEM *it, const ASN1_PCTX *pctx);
+ASN1_PCTX *ASN1_PCTX_new(void);
+void ASN1_PCTX_free(ASN1_PCTX *p);
+unsigned long ASN1_PCTX_get_flags(ASN1_PCTX *p);
+void ASN1_PCTX_set_flags(ASN1_PCTX *p, unsigned long flags);
+unsigned long ASN1_PCTX_get_nm_flags(ASN1_PCTX *p);
+void ASN1_PCTX_set_nm_flags(ASN1_PCTX *p, unsigned long flags);
+unsigned long ASN1_PCTX_get_cert_flags(ASN1_PCTX *p);
+void ASN1_PCTX_set_cert_flags(ASN1_PCTX *p, unsigned long flags);
+unsigned long ASN1_PCTX_get_oid_flags(ASN1_PCTX *p);
+void ASN1_PCTX_set_oid_flags(ASN1_PCTX *p, unsigned long flags);
+unsigned long ASN1_PCTX_get_str_flags(ASN1_PCTX *p);
+void ASN1_PCTX_set_str_flags(ASN1_PCTX *p, unsigned long flags);
+
+BIO_METHOD *BIO_f_asn1(void);
+
+BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it);
+
+int i2d_ASN1_bio_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags,
+ const ASN1_ITEM *it);
+int PEM_write_bio_ASN1_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags,
+ const char *hdr,
+ const ASN1_ITEM *it);
+ASN1_VALUE *SMIME_read_ASN1(BIO *bio, BIO **bcont, const ASN1_ITEM *it);
+int SMIME_crlf_copy(BIO *in, BIO *out, int flags);
+int SMIME_text(BIO *in, BIO *out);
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_ASN1_strings(void);
+
+typedef int asn1_ps_func(BIO *b, unsigned char **pbuf, int *plen, void *parg);
+int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix,
+ asn1_ps_func *prefix_free);
+int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix,
+ asn1_ps_func **pprefix_free);
+int BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix,
+ asn1_ps_func *suffix_free);
+int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix,
+ asn1_ps_func **psuffix_free);
+
+#ifdef __cplusplus
+}
+#endif
+
+#define ASN1_F_asn1_template_ex_d2i 100
+#define ASN1_F_ASN1_dup 101
+#define ASN1_F_a2i_ASN1_STRING 102
+#define ASN1_F_ASN1_d2i_fp 103
+#define ASN1_F_d2i_ASN1_OBJECT 104
+#define ASN1_F_asn1_item_ex_combine_new 105
+#define ASN1_F_ASN1_template_new 106
+#define ASN1_F_asn1_do_adb 107
+#define ASN1_F_asn1_d2i_read_bio 108
+#define ASN1_F_asn1_ex_c2i 109
+#define ASN1_F_c2i_ASN1_INTEGER 110
+#define ASN1_F_ASN1_PCTX_new 111
+#define ASN1_F_ASN1_item_unpack 112
+#define ASN1_F_d2i_ASN1_type_bytes 113
+#define ASN1_F_a2i_ASN1_INTEGER 114
+#define ASN1_F_asn1_collect 115
+#define ASN1_F_ASN1_item_dup 116
+#define ASN1_F_ASN1_ENUMERATED_set 117
+#define ASN1_F_c2i_ASN1_OBJECT 118
+#define ASN1_F_ASN1_unpack_string 119
+#define ASN1_F_d2i_ASN1_UINTEGER 120
+#define ASN1_F_long_c2i 121
+#define ASN1_F_ASN1_seq_pack 122
+#define ASN1_F_a2d_ASN1_OBJECT 123
+#define ASN1_F_ASN1_STRING_type_new 124
+#define ASN1_F_ASN1_INTEGER_set 125
+#define ASN1_F_BN_to_ASN1_INTEGER 126
+#define ASN1_F_BIO_new_NDEF 127
+#define ASN1_F_ASN1_ENUMERATED_to_BN 128
+#define ASN1_F_ASN1_item_ex_d2i 129
+#define ASN1_F_ASN1_INTEGER_to_BN 130
+#define ASN1_F_i2d_ASN1_TIME 131
+#define ASN1_F_ASN1_TIME_adj 132
+#define ASN1_F_ASN1_BIT_STRING_set_bit 133
+#define ASN1_F_ASN1_seq_unpack 134
+#define ASN1_F_ASN1_item_pack 135
+#define ASN1_F_ASN1_STRING_set 136
+#define ASN1_F_ASN1_UTCTIME_adj 137
+#define ASN1_F_ASN1_mbstring_ncopy 138
+#define ASN1_F_d2i_ASN1_BOOLEAN 139
+#define ASN1_F_ASN1_OBJECT_new 140
+#define ASN1_F_asn1_template_noexp_d2i 141
+#define ASN1_F_c2i_ASN1_BIT_STRING 142
+#define ASN1_F_BN_to_ASN1_ENUMERATED 143
+#define ASN1_F_asn1_d2i_ex_primitive 144
+#define ASN1_F_ASN1_i2d_bio 145
+#define ASN1_F_ASN1_item_i2d_bio 146
+#define ASN1_F_d2i_ASN1_UTCTIME 147
+#define ASN1_F_ASN1_STRING_TABLE_add 148
+#define ASN1_F_asn1_find_end 149
+#define ASN1_F_ASN1_item_d2i_fp 150
+#define ASN1_F_collect_data 151
+#define ASN1_F_asn1_check_tlen 152
+#define ASN1_F_ASN1_i2d_fp 153
+#define ASN1_F_ASN1_item_i2d_fp 154
+#define ASN1_F_ASN1_GENERALIZEDTIME_adj 155
+#define ASN1_F_asn1_collate_primitive 156
+#define ASN1_F_ASN1_pack_string 157
+#define ASN1_F_ASN1_get_object 158
+#define ASN1_F_d2i_ASN1_bytes 159
+#define ASN1_F_a2i_ASN1_ENUMERATED 160
+#define ASN1_R_ASN1_SIG_PARSE_ERROR 100
+#define ASN1_R_ADDING_OBJECT 101
+#define ASN1_R_MIME_NO_CONTENT_TYPE 102
+#define ASN1_R_UNKNOWN_OBJECT_TYPE 103
+#define ASN1_R_ILLEGAL_FORMAT 104
+#define ASN1_R_HEADER_TOO_LONG 105
+#define ASN1_R_INVALID_UTF8STRING 106
+#define ASN1_R_EXPLICIT_LENGTH_MISMATCH 107
+#define ASN1_R_ILLEGAL_TAGGED_ANY 108
+#define ASN1_R_DATA_IS_WRONG 109
+#define ASN1_R_NOT_ASCII_FORMAT 110
+#define ASN1_R_NOT_ENOUGH_DATA 111
+#define ASN1_R_MSTRING_NOT_UNIVERSAL 112
+#define ASN1_R_UNKOWN_FORMAT 113
+#define ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM 114
+#define ASN1_R_BAD_PASSWORD_READ 115
+#define ASN1_R_BAD_OBJECT_HEADER 116
+#define ASN1_R_ILLEGAL_CHARACTERS 117
+#define ASN1_R_CONTEXT_NOT_INITIALISED 118
+#define ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG 119
+#define ASN1_R_BN_LIB 120
+#define ASN1_R_NO_MATCHING_CHOICE_TYPE 121
+#define ASN1_R_SEQUENCE_NOT_CONSTRUCTED 122
+#define ASN1_R_ASN1_PARSE_ERROR 123
+#define ASN1_R_NO_MULTIPART_BOUNDARY 124
+#define ASN1_R_INVALID_SEPARATOR 125
+#define ASN1_R_MALLOC_FAILURE 126
+#define ASN1_R_ILLEGAL_NULL 127
+#define ASN1_R_INVALID_MIME_TYPE 128
+#define ASN1_R_INVALID_NUMBER 129
+#define ASN1_R_STRING_TOO_LONG 130
+#define ASN1_R_BAD_GET_ASN1_OBJECT_CALL 131
+#define ASN1_R_UNABLE_TO_DECODE_RSA_KEY 132
+#define ASN1_R_EXPECTING_A_TIME 133
+#define ASN1_R_TAG_VALUE_TOO_HIGH 134
+#define ASN1_R_NESTED_ASN1_STRING 135
+#define ASN1_R_ILLEGAL_BITSTRING_FORMAT 136
+#define ASN1_R_MISSING_SECOND_NUMBER 137
+#define ASN1_R_TIME_NOT_ASCII_FORMAT 138
+#define ASN1_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD 139
+#define ASN1_R_WRONG_TYPE 140
+#define ASN1_R_EXPECTING_AN_INTEGER 141
+#define ASN1_R_DEPTH_EXCEEDED 142
+#define ASN1_R_ILLEGAL_OBJECT 143
+#define ASN1_R_UNKNOWN_TAG 144
+#define ASN1_R_ILLEGAL_IMPLICIT_TAG 145
+#define ASN1_R_AUX_ERROR 146
+#define ASN1_R_SEQUENCE_LENGTH_MISMATCH 147
+#define ASN1_R_FIELD_MISSING 148
+#define ASN1_R_TYPE_NOT_CONSTRUCTED 149
+#define ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH 150
+#define ASN1_R_FIRST_NUM_TOO_LARGE 151
+#define ASN1_R_INVALID_DIGIT 152
+#define ASN1_R_MSTRING_WRONG_TAG 153
+#define ASN1_R_OBJECT_NOT_ASCII_FORMAT 154
+#define ASN1_R_UNSUPPORTED_TYPE 155
+#define ASN1_R_ERROR_LOADING_SECTION 156
+#define ASN1_R_ODD_NUMBER_OF_CHARS 157
+#define ASN1_R_ASN1_LENGTH_MISMATCH 158
+#define ASN1_R_MISSING_EOC 159
+#define ASN1_R_ILLEGAL_INTEGER 160
+#define ASN1_R_ILLEGAL_HEX 161
+#define ASN1_R_NESTED_ASN1_ERROR 162
+#define ASN1_R_TOO_LONG 163
+#define ASN1_R_LENGTH_ERROR 164
+#define ASN1_R_DECODING_ERROR 165
+#define ASN1_R_MIME_SIG_PARSE_ERROR 166
+#define ASN1_R_ILLEGAL_NULL_VALUE 167
+#define ASN1_R_EXPECTING_A_BOOLEAN 168
+#define ASN1_R_STREAMING_NOT_SUPPORTED 169
+#define ASN1_R_INVALID_BMPSTRING_LENGTH 170
+#define ASN1_R_INTEGER_NOT_ASCII_FORMAT 171
+#define ASN1_R_INVALID_MODIFIER 172
+#define ASN1_R_UNEXPECTED_EOC 173
+#define ASN1_R_ILLEGAL_NESTED_TAGGING 174
+#define ASN1_R_IV_TOO_LARGE 175
+#define ASN1_R_INTEGER_TOO_LARGE_FOR_LONG 176
+#define ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE 177
+#define ASN1_R_BUFFER_TOO_SMALL 178
+#define ASN1_R_INVALID_UNIVERSALSTRING_LENGTH 179
+#define ASN1_R_WRONG_PUBLIC_KEY_TYPE 180
+#define ASN1_R_UNSUPPORTED_ENCRYPTION_ALGORITHM 181
+#define ASN1_R_MIME_PARSE_ERROR 182
+#define ASN1_R_INVALID_OBJECT_ENCODING 183
+#define ASN1_R_PRIVATE_KEY_HEADER_MISSING 184
+#define ASN1_R_UNSUPPORTED_CIPHER 185
+#define ASN1_R_NO_MULTIPART_BODY_FAILURE 186
+#define ASN1_R_NO_CONTENT_TYPE 187
+#define ASN1_R_SECOND_NUMBER_TOO_LARGE 188
+#define ASN1_R_INVALID_TIME_FORMAT 189
+#define ASN1_R_NO_DEFAULT_DIGEST 190
+#define ASN1_R_ERROR_SETTING_CIPHER_PARAMS 191
+#define ASN1_R_EXPECTING_AN_OBJECT 192
+#define ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE 193
+#define ASN1_R_ERROR_GETTING_TIME 194
+#define ASN1_R_MISSING_VALUE 195
+#define ASN1_R_LIST_ERROR 196
+#define ASN1_R_DECODE_ERROR 197
+#define ASN1_R_NON_HEX_CHARACTERS 198
+#define ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE 199
+#define ASN1_R_UNKNOWN_FORMAT 200
+#define ASN1_R_EXPECTING_AN_ASN1_SEQUENCE 201
+#define ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM 202
+#define ASN1_R_STRING_TOO_SHORT 203
+#define ASN1_R_ILLEGAL_OPTIONAL_ANY 204
+#define ASN1_R_BMPSTRING_IS_WRONG_LENGTH 205
+#define ASN1_R_NO_SIG_CONTENT_TYPE 206
+#define ASN1_R_ENCODE_ERROR 207
+#define ASN1_R_SHORT_LINE 208
+#define ASN1_R_ILLEGAL_TIME_VALUE 209
+#define ASN1_R_UNABLE_TO_DECODE_RSA_PRIVATE_KEY 210
+#define ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER 211
+#define ASN1_R_BAD_CLASS 212
+#define ASN1_R_BAD_TAG 213
+#define ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE 214
+#define ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED 215
+#define ASN1_R_ILLEGAL_BOOLEAN 216
+#define ASN1_R_SIG_INVALID_MIME_TYPE 217
+#define ASN1_R_NULL_IS_WRONG_LENGTH 218
+#define ASN1_R_MISSING_ASN1_EOS 219
+#define ASN1_R_ERROR_PARSING_SET_ELEMENT 220
+#define ASN1_R_WRONG_TAG 221
+#define ASN1_R_BOOLEAN_IS_WRONG_LENGTH 222
+#define ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED 223
+
+#endif
diff --git a/crypto/asn1/asn1_error.c b/crypto/asn1/asn1_error.c
new file mode 100644
index 0000000..3354ffe
--- /dev/null
+++ b/crypto/asn1/asn1_error.c
@@ -0,0 +1,206 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/err.h>
+
+#include "asn1.h"
+
+const ERR_STRING_DATA ASN1_error_string_data[] = {
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_BIT_STRING_set_bit, 0), "ASN1_BIT_STRING_set_bit"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_ENUMERATED_set, 0), "ASN1_ENUMERATED_set"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_ENUMERATED_to_BN, 0), "ASN1_ENUMERATED_to_BN"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_GENERALIZEDTIME_adj, 0), "ASN1_GENERALIZEDTIME_adj"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_INTEGER_set, 0), "ASN1_INTEGER_set"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_INTEGER_to_BN, 0), "ASN1_INTEGER_to_BN"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_OBJECT_new, 0), "ASN1_OBJECT_new"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_PCTX_new, 0), "ASN1_PCTX_new"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_STRING_TABLE_add, 0), "ASN1_STRING_TABLE_add"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_STRING_set, 0), "ASN1_STRING_set"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_STRING_type_new, 0), "ASN1_STRING_type_new"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_TIME_adj, 0), "ASN1_TIME_adj"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_UTCTIME_adj, 0), "ASN1_UTCTIME_adj"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_d2i_fp, 0), "ASN1_d2i_fp"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_dup, 0), "ASN1_dup"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_get_object, 0), "ASN1_get_object"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_i2d_bio, 0), "ASN1_i2d_bio"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_i2d_fp, 0), "ASN1_i2d_fp"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_item_d2i_fp, 0), "ASN1_item_d2i_fp"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_item_dup, 0), "ASN1_item_dup"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_item_ex_d2i, 0), "ASN1_item_ex_d2i"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_item_i2d_bio, 0), "ASN1_item_i2d_bio"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_item_i2d_fp, 0), "ASN1_item_i2d_fp"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_item_pack, 0), "ASN1_item_pack"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_item_unpack, 0), "ASN1_item_unpack"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_mbstring_ncopy, 0), "ASN1_mbstring_ncopy"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_pack_string, 0), "ASN1_pack_string"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_seq_pack, 0), "ASN1_seq_pack"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_seq_unpack, 0), "ASN1_seq_unpack"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_template_new, 0), "ASN1_template_new"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_unpack_string, 0), "ASN1_unpack_string"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_BIO_new_NDEF, 0), "BIO_new_NDEF"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_BN_to_ASN1_ENUMERATED, 0), "BN_to_ASN1_ENUMERATED"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_BN_to_ASN1_INTEGER, 0), "BN_to_ASN1_INTEGER"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_a2d_ASN1_OBJECT, 0), "a2d_ASN1_OBJECT"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_a2i_ASN1_ENUMERATED, 0), "a2i_ASN1_ENUMERATED"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_a2i_ASN1_INTEGER, 0), "a2i_ASN1_INTEGER"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_a2i_ASN1_STRING, 0), "a2i_ASN1_STRING"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_asn1_check_tlen, 0), "asn1_check_tlen"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_asn1_collate_primitive, 0), "asn1_collate_primitive"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_asn1_collect, 0), "asn1_collect"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_asn1_d2i_ex_primitive, 0), "asn1_d2i_ex_primitive"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_asn1_d2i_read_bio, 0), "asn1_d2i_read_bio"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_asn1_do_adb, 0), "asn1_do_adb"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_asn1_ex_c2i, 0), "asn1_ex_c2i"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_asn1_find_end, 0), "asn1_find_end"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_asn1_item_ex_combine_new, 0), "asn1_item_ex_combine_new"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_asn1_template_ex_d2i, 0), "asn1_template_ex_d2i"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_asn1_template_noexp_d2i, 0), "asn1_template_noexp_d2i"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_c2i_ASN1_BIT_STRING, 0), "c2i_ASN1_BIT_STRING"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_c2i_ASN1_INTEGER, 0), "c2i_ASN1_INTEGER"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_c2i_ASN1_OBJECT, 0), "c2i_ASN1_OBJECT"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_collect_data, 0), "collect_data"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_d2i_ASN1_BOOLEAN, 0), "d2i_ASN1_BOOLEAN"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_d2i_ASN1_OBJECT, 0), "d2i_ASN1_OBJECT"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_d2i_ASN1_UINTEGER, 0), "d2i_ASN1_UINTEGER"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_d2i_ASN1_UTCTIME, 0), "d2i_ASN1_UTCTIME"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_d2i_ASN1_bytes, 0), "d2i_ASN1_bytes"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_d2i_ASN1_type_bytes, 0), "d2i_ASN1_type_bytes"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_i2d_ASN1_TIME, 0), "i2d_ASN1_TIME"},
+ {ERR_PACK(ERR_LIB_ASN1, ASN1_F_long_c2i, 0), "long_c2i"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ADDING_OBJECT), "ADDING_OBJECT"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ASN1_LENGTH_MISMATCH), "ASN1_LENGTH_MISMATCH"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ASN1_PARSE_ERROR), "ASN1_PARSE_ERROR"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ASN1_SIG_PARSE_ERROR), "ASN1_SIG_PARSE_ERROR"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_AUX_ERROR), "AUX_ERROR"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_BAD_CLASS), "BAD_CLASS"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_BAD_GET_ASN1_OBJECT_CALL), "BAD_GET_ASN1_OBJECT_CALL"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_BAD_OBJECT_HEADER), "BAD_OBJECT_HEADER"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_BAD_PASSWORD_READ), "BAD_PASSWORD_READ"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_BAD_TAG), "BAD_TAG"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_BMPSTRING_IS_WRONG_LENGTH), "BMPSTRING_IS_WRONG_LENGTH"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_BN_LIB), "BN_LIB"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_BOOLEAN_IS_WRONG_LENGTH), "BOOLEAN_IS_WRONG_LENGTH"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_BUFFER_TOO_SMALL), "BUFFER_TOO_SMALL"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER), "CIPHER_HAS_NO_OBJECT_IDENTIFIER"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_CONTEXT_NOT_INITIALISED), "CONTEXT_NOT_INITIALISED"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_DATA_IS_WRONG), "DATA_IS_WRONG"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_DECODE_ERROR), "DECODE_ERROR"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_DECODING_ERROR), "DECODING_ERROR"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_DEPTH_EXCEEDED), "DEPTH_EXCEEDED"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED), "DIGEST_AND_KEY_TYPE_NOT_SUPPORTED"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ENCODE_ERROR), "ENCODE_ERROR"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ERROR_GETTING_TIME), "ERROR_GETTING_TIME"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ERROR_LOADING_SECTION), "ERROR_LOADING_SECTION"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ERROR_PARSING_SET_ELEMENT), "ERROR_PARSING_SET_ELEMENT"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ERROR_SETTING_CIPHER_PARAMS), "ERROR_SETTING_CIPHER_PARAMS"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_EXPECTING_AN_ASN1_SEQUENCE), "EXPECTING_AN_ASN1_SEQUENCE"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_EXPECTING_AN_INTEGER), "EXPECTING_AN_INTEGER"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_EXPECTING_AN_OBJECT), "EXPECTING_AN_OBJECT"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_EXPECTING_A_BOOLEAN), "EXPECTING_A_BOOLEAN"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_EXPECTING_A_TIME), "EXPECTING_A_TIME"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_EXPLICIT_LENGTH_MISMATCH), "EXPLICIT_LENGTH_MISMATCH"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED), "EXPLICIT_TAG_NOT_CONSTRUCTED"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_FIELD_MISSING), "FIELD_MISSING"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_FIRST_NUM_TOO_LARGE), "FIRST_NUM_TOO_LARGE"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_HEADER_TOO_LONG), "HEADER_TOO_LONG"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_BITSTRING_FORMAT), "ILLEGAL_BITSTRING_FORMAT"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_BOOLEAN), "ILLEGAL_BOOLEAN"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_CHARACTERS), "ILLEGAL_CHARACTERS"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_FORMAT), "ILLEGAL_FORMAT"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_HEX), "ILLEGAL_HEX"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_IMPLICIT_TAG), "ILLEGAL_IMPLICIT_TAG"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_INTEGER), "ILLEGAL_INTEGER"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_NESTED_TAGGING), "ILLEGAL_NESTED_TAGGING"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_NULL), "ILLEGAL_NULL"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_NULL_VALUE), "ILLEGAL_NULL_VALUE"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_OBJECT), "ILLEGAL_OBJECT"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_OPTIONAL_ANY), "ILLEGAL_OPTIONAL_ANY"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE), "ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_TAGGED_ANY), "ILLEGAL_TAGGED_ANY"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_TIME_VALUE), "ILLEGAL_TIME_VALUE"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INTEGER_NOT_ASCII_FORMAT), "INTEGER_NOT_ASCII_FORMAT"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG), "INTEGER_TOO_LARGE_FOR_LONG"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_BMPSTRING_LENGTH), "INVALID_BMPSTRING_LENGTH"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_DIGIT), "INVALID_DIGIT"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_MIME_TYPE), "INVALID_MIME_TYPE"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_MODIFIER), "INVALID_MODIFIER"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_NUMBER), "INVALID_NUMBER"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_OBJECT_ENCODING), "INVALID_OBJECT_ENCODING"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_SEPARATOR), "INVALID_SEPARATOR"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_TIME_FORMAT), "INVALID_TIME_FORMAT"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_UNIVERSALSTRING_LENGTH), "INVALID_UNIVERSALSTRING_LENGTH"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_UTF8STRING), "INVALID_UTF8STRING"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_IV_TOO_LARGE), "IV_TOO_LARGE"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_LENGTH_ERROR), "LENGTH_ERROR"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_LIST_ERROR), "LIST_ERROR"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_MALLOC_FAILURE), "MALLOC_FAILURE"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_MIME_NO_CONTENT_TYPE), "MIME_NO_CONTENT_TYPE"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_MIME_PARSE_ERROR), "MIME_PARSE_ERROR"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_MIME_SIG_PARSE_ERROR), "MIME_SIG_PARSE_ERROR"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_MISSING_ASN1_EOS), "MISSING_ASN1_EOS"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_MISSING_EOC), "MISSING_EOC"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_MISSING_SECOND_NUMBER), "MISSING_SECOND_NUMBER"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_MISSING_VALUE), "MISSING_VALUE"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_MSTRING_NOT_UNIVERSAL), "MSTRING_NOT_UNIVERSAL"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_MSTRING_WRONG_TAG), "MSTRING_WRONG_TAG"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_NESTED_ASN1_ERROR), "NESTED_ASN1_ERROR"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_NESTED_ASN1_STRING), "NESTED_ASN1_STRING"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_NON_HEX_CHARACTERS), "NON_HEX_CHARACTERS"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_NOT_ASCII_FORMAT), "NOT_ASCII_FORMAT"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_NOT_ENOUGH_DATA), "NOT_ENOUGH_DATA"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_NO_CONTENT_TYPE), "NO_CONTENT_TYPE"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_NO_DEFAULT_DIGEST), "NO_DEFAULT_DIGEST"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_NO_MATCHING_CHOICE_TYPE), "NO_MATCHING_CHOICE_TYPE"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_NO_MULTIPART_BODY_FAILURE), "NO_MULTIPART_BODY_FAILURE"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_NO_MULTIPART_BOUNDARY), "NO_MULTIPART_BOUNDARY"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_NO_SIG_CONTENT_TYPE), "NO_SIG_CONTENT_TYPE"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_NULL_IS_WRONG_LENGTH), "NULL_IS_WRONG_LENGTH"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_OBJECT_NOT_ASCII_FORMAT), "OBJECT_NOT_ASCII_FORMAT"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ODD_NUMBER_OF_CHARS), "ODD_NUMBER_OF_CHARS"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_PRIVATE_KEY_HEADER_MISSING), "PRIVATE_KEY_HEADER_MISSING"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_SECOND_NUMBER_TOO_LARGE), "SECOND_NUMBER_TOO_LARGE"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_SEQUENCE_LENGTH_MISMATCH), "SEQUENCE_LENGTH_MISMATCH"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_SEQUENCE_NOT_CONSTRUCTED), "SEQUENCE_NOT_CONSTRUCTED"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG), "SEQUENCE_OR_SET_NEEDS_CONFIG"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_SHORT_LINE), "SHORT_LINE"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_SIG_INVALID_MIME_TYPE), "SIG_INVALID_MIME_TYPE"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_STREAMING_NOT_SUPPORTED), "STREAMING_NOT_SUPPORTED"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_STRING_TOO_LONG), "STRING_TOO_LONG"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_STRING_TOO_SHORT), "STRING_TOO_SHORT"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_TAG_VALUE_TOO_HIGH), "TAG_VALUE_TOO_HIGH"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD), "THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_TIME_NOT_ASCII_FORMAT), "TIME_NOT_ASCII_FORMAT"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_TOO_LONG), "TOO_LONG"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_TYPE_NOT_CONSTRUCTED), "TYPE_NOT_CONSTRUCTED"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNABLE_TO_DECODE_RSA_KEY), "UNABLE_TO_DECODE_RSA_KEY"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNABLE_TO_DECODE_RSA_PRIVATE_KEY), "UNABLE_TO_DECODE_RSA_PRIVATE_KEY"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNEXPECTED_EOC), "UNEXPECTED_EOC"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH), "UNIVERSALSTRING_IS_WRONG_LENGTH"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNKNOWN_FORMAT), "UNKNOWN_FORMAT"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM), "UNKNOWN_MESSAGE_DIGEST_ALGORITHM"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNKNOWN_OBJECT_TYPE), "UNKNOWN_OBJECT_TYPE"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE), "UNKNOWN_PUBLIC_KEY_TYPE"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM), "UNKNOWN_SIGNATURE_ALGORITHM"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNKNOWN_TAG), "UNKNOWN_TAG"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNKOWN_FORMAT), "UNKOWN_FORMAT"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE), "UNSUPPORTED_ANY_DEFINED_BY_TYPE"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNSUPPORTED_CIPHER), "UNSUPPORTED_CIPHER"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNSUPPORTED_ENCRYPTION_ALGORITHM), "UNSUPPORTED_ENCRYPTION_ALGORITHM"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE), "UNSUPPORTED_PUBLIC_KEY_TYPE"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNSUPPORTED_TYPE), "UNSUPPORTED_TYPE"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_WRONG_PUBLIC_KEY_TYPE), "WRONG_PUBLIC_KEY_TYPE"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_WRONG_TAG), "WRONG_TAG"},
+ {ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_WRONG_TYPE), "WRONG_TYPE"},
+ {0, NULL},
+};
diff --git a/crypto/asn1/asn1_lib.c b/crypto/asn1/asn1_lib.c
new file mode 100644
index 0000000..ca7209e
--- /dev/null
+++ b/crypto/asn1/asn1_lib.c
@@ -0,0 +1,483 @@
+/* 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/asn1.h>
+
+#include <limits.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+OPENSSL_DECLARE_ERROR_REASON(ASN1, MALLOC_FAILURE);
+
+
+static int asn1_get_length(const unsigned char **pp,int *inf,long *rl,int max);
+static void asn1_put_length(unsigned char **pp, int length);
+
+static int _asn1_check_infinite_end(const unsigned char **p, long len)
+ {
+ /* If there is 0 or 1 byte left, the length check should pick
+ * things up */
+ if (len <= 0)
+ return(1);
+ else if ((len >= 2) && ((*p)[0] == 0) && ((*p)[1] == 0))
+ {
+ (*p)+=2;
+ return(1);
+ }
+ return(0);
+ }
+
+int ASN1_check_infinite_end(unsigned char **p, long len)
+ {
+ return _asn1_check_infinite_end((const unsigned char **)p, len);
+ }
+
+int ASN1_const_check_infinite_end(const unsigned char **p, long len)
+ {
+ return _asn1_check_infinite_end(p, len);
+ }
+
+
+int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag,
+ int *pclass, long omax)
+ {
+ int i,ret;
+ long l;
+ const unsigned char *p= *pp;
+ int tag,xclass,inf;
+ long max=omax;
+
+ if (!max) goto err;
+ ret=(*p&V_ASN1_CONSTRUCTED);
+ xclass=(*p&V_ASN1_PRIVATE);
+ i= *p&V_ASN1_PRIMITIVE_TAG;
+ if (i == V_ASN1_PRIMITIVE_TAG)
+ { /* high-tag */
+ p++;
+ if (--max == 0) goto err;
+ l=0;
+ while (*p&0x80)
+ {
+ l<<=7L;
+ l|= *(p++)&0x7f;
+ if (--max == 0) goto err;
+ if (l > (INT_MAX >> 7L)) goto err;
+ }
+ l<<=7L;
+ l|= *(p++)&0x7f;
+ tag=(int)l;
+ if (--max == 0) goto err;
+ }
+ else
+ {
+ tag=i;
+ p++;
+ if (--max == 0) goto err;
+ }
+ *ptag=tag;
+ *pclass=xclass;
+ if (!asn1_get_length(&p,&inf,plength,(int)max)) goto err;
+
+#if 0
+ fprintf(stderr,"p=%d + *plength=%ld > omax=%ld + *pp=%d (%d > %d)\n",
+ (int)p,*plength,omax,(int)*pp,(int)(p+ *plength),
+ (int)(omax+ *pp));
+
+#endif
+ if (*plength > (omax - (p - *pp)))
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_get_object, ASN1_R_TOO_LONG);
+ /* Set this so that even if things are not long enough
+ * the values are set correctly */
+ ret|=0x80;
+ }
+ *pp=p;
+ return(ret|inf);
+err:
+ OPENSSL_PUT_ERROR(ASN1, ASN1_get_object, ASN1_R_HEADER_TOO_LONG);
+ return(0x80);
+ }
+
+static int asn1_get_length(const unsigned char **pp, int *inf, long *rl, int max)
+ {
+ const unsigned char *p= *pp;
+ unsigned long ret=0;
+ unsigned int i;
+
+ if (max-- < 1) return(0);
+ if (*p == 0x80)
+ {
+ *inf=1;
+ ret=0;
+ p++;
+ }
+ else
+ {
+ *inf=0;
+ i= *p&0x7f;
+ if (*(p++) & 0x80)
+ {
+ if (i > sizeof(long))
+ return 0;
+ if (max-- == 0) return(0);
+ while (i-- > 0)
+ {
+ ret<<=8L;
+ ret|= *(p++);
+ if (max-- == 0) return(0);
+ }
+ }
+ else
+ ret=i;
+ }
+ if (ret > LONG_MAX)
+ return 0;
+ *pp=p;
+ *rl=(long)ret;
+ return(1);
+ }
+
+/* class 0 is constructed
+ * constructed == 2 for indefinite length constructed */
+void ASN1_put_object(unsigned char **pp, int constructed, int length, int tag,
+ int xclass)
+ {
+ unsigned char *p= *pp;
+ int i, ttag;
+
+ i=(constructed)?V_ASN1_CONSTRUCTED:0;
+ i|=(xclass&V_ASN1_PRIVATE);
+ if (tag < 31)
+ *(p++)=i|(tag&V_ASN1_PRIMITIVE_TAG);
+ else
+ {
+ *(p++)=i|V_ASN1_PRIMITIVE_TAG;
+ for(i = 0, ttag = tag; ttag > 0; i++) ttag >>=7;
+ ttag = i;
+ while(i-- > 0)
+ {
+ p[i] = tag & 0x7f;
+ if(i != (ttag - 1)) p[i] |= 0x80;
+ tag >>= 7;
+ }
+ p += ttag;
+ }
+ if (constructed == 2)
+ *(p++)=0x80;
+ else
+ asn1_put_length(&p,length);
+ *pp=p;
+ }
+
+int ASN1_put_eoc(unsigned char **pp)
+ {
+ unsigned char *p = *pp;
+ *p++ = 0;
+ *p++ = 0;
+ *pp = p;
+ return 2;
+ }
+
+static void asn1_put_length(unsigned char **pp, int length)
+ {
+ unsigned char *p= *pp;
+ int i,l;
+ if (length <= 127)
+ *(p++)=(unsigned char)length;
+ else
+ {
+ l=length;
+ for (i=0; l > 0; i++)
+ l>>=8;
+ *(p++)=i|0x80;
+ l=i;
+ while (i-- > 0)
+ {
+ p[i]=length&0xff;
+ length>>=8;
+ }
+ p+=l;
+ }
+ *pp=p;
+ }
+
+int ASN1_object_size(int constructed, int length, int tag)
+ {
+ int ret;
+
+ ret=length;
+ ret++;
+ if (tag >= 31)
+ {
+ while (tag > 0)
+ {
+ tag>>=7;
+ ret++;
+ }
+ }
+ if (constructed == 2)
+ return ret + 3;
+ ret++;
+ if (length > 127)
+ {
+ while (length > 0)
+ {
+ length>>=8;
+ ret++;
+ }
+ }
+ return(ret);
+ }
+
+static int _asn1_Finish(ASN1_const_CTX *c)
+ {
+ if ((c->inf == (1|V_ASN1_CONSTRUCTED)) && (!c->eos))
+ {
+ if (!ASN1_const_check_infinite_end(&c->p,c->slen))
+ {
+ c->error=ASN1_R_MISSING_ASN1_EOS;
+ return(0);
+ }
+ }
+ if ( ((c->slen != 0) && !(c->inf & 1)) ||
+ ((c->slen < 0) && (c->inf & 1)))
+ {
+ c->error=ASN1_R_ASN1_LENGTH_MISMATCH;
+ return(0);
+ }
+ return(1);
+ }
+
+int asn1_Finish(ASN1_CTX *c)
+ {
+ return _asn1_Finish((ASN1_const_CTX *)c);
+ }
+
+int asn1_const_Finish(ASN1_const_CTX *c)
+ {
+ return _asn1_Finish(c);
+ }
+
+int asn1_GetSequence(ASN1_const_CTX *c, long *length)
+ {
+ const unsigned char *q;
+
+ q=c->p;
+ c->inf=ASN1_get_object(&(c->p),&(c->slen),&(c->tag),&(c->xclass),
+ *length);
+ if (c->inf & 0x80)
+ {
+ c->error=ASN1_R_BAD_GET_ASN1_OBJECT_CALL;
+ return(0);
+ }
+ if (c->tag != V_ASN1_SEQUENCE)
+ {
+ c->error=ASN1_R_EXPECTING_AN_ASN1_SEQUENCE;
+ return(0);
+ }
+ (*length)-=(c->p-q);
+ if (c->max && (*length < 0))
+ {
+ c->error=ASN1_R_ASN1_LENGTH_MISMATCH;
+ return(0);
+ }
+ if (c->inf == (1|V_ASN1_CONSTRUCTED))
+ c->slen= *length+ *(c->pp)-c->p;
+ c->eos=0;
+ return(1);
+ }
+
+int ASN1_STRING_copy(ASN1_STRING *dst, const ASN1_STRING *str)
+ {
+ if (str == NULL)
+ return 0;
+ dst->type = str->type;
+ if (!ASN1_STRING_set(dst,str->data,str->length))
+ return 0;
+ dst->flags = str->flags;
+ return 1;
+ }
+
+ASN1_STRING *ASN1_STRING_dup(const ASN1_STRING *str)
+ {
+ ASN1_STRING *ret;
+ if (!str)
+ return NULL;
+ ret=ASN1_STRING_new();
+ if (!ret)
+ return NULL;
+ if (!ASN1_STRING_copy(ret,str))
+ {
+ ASN1_STRING_free(ret);
+ return NULL;
+ }
+ return ret;
+ }
+
+int ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len)
+ {
+ unsigned char *c;
+ const char *data=_data;
+
+ if (len < 0)
+ {
+ if (data == NULL)
+ return(0);
+ else
+ len=strlen(data);
+ }
+ if ((str->length < len) || (str->data == NULL))
+ {
+ c=str->data;
+ if (c == NULL)
+ str->data=OPENSSL_malloc(len+1);
+ else
+ str->data=OPENSSL_realloc(c,len+1);
+
+ if (str->data == NULL)
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_STRING_set, ERR_R_MALLOC_FAILURE);
+ str->data=c;
+ return(0);
+ }
+ }
+ str->length=len;
+ if (data != NULL)
+ {
+ memcpy(str->data,data,len);
+ /* an allowance for strings :-) */
+ str->data[len]='\0';
+ }
+ return(1);
+ }
+
+void ASN1_STRING_set0(ASN1_STRING *str, void *data, int len)
+ {
+ if (str->data)
+ OPENSSL_free(str->data);
+ str->data = data;
+ str->length = len;
+ }
+
+ASN1_STRING *ASN1_STRING_new(void)
+ {
+ return(ASN1_STRING_type_new(V_ASN1_OCTET_STRING));
+ }
+
+
+ASN1_STRING *ASN1_STRING_type_new(int type)
+ {
+ ASN1_STRING *ret;
+
+ ret=(ASN1_STRING *)OPENSSL_malloc(sizeof(ASN1_STRING));
+ if (ret == NULL)
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_STRING_type_new, ERR_R_MALLOC_FAILURE);
+ return(NULL);
+ }
+ ret->length=0;
+ ret->type=type;
+ ret->data=NULL;
+ ret->flags=0;
+ return(ret);
+ }
+
+void ASN1_STRING_free(ASN1_STRING *a)
+ {
+ if (a == NULL) return;
+ if (a->data && !(a->flags & ASN1_STRING_FLAG_NDEF))
+ OPENSSL_free(a->data);
+ OPENSSL_free(a);
+ }
+
+int ASN1_STRING_cmp(const ASN1_STRING *a, const ASN1_STRING *b)
+ {
+ int i;
+
+ i=(a->length-b->length);
+ if (i == 0)
+ {
+ i=memcmp(a->data,b->data,a->length);
+ if (i == 0)
+ return(a->type-b->type);
+ else
+ return(i);
+ }
+ else
+ return(i);
+ }
+
+void asn1_add_error(const unsigned char *address, int offset)
+ {
+ char buf1[DECIMAL_SIZE(address)+1],buf2[DECIMAL_SIZE(offset)+1];
+
+ BIO_snprintf(buf1,sizeof buf1,"%lu",(unsigned long)address);
+ BIO_snprintf(buf2,sizeof buf2,"%d",offset);
+ ERR_add_error_data(4,"address=",buf1," offset=",buf2);
+ }
+
+int ASN1_STRING_length(const ASN1_STRING *x)
+{ return M_ASN1_STRING_length(x); }
+
+void ASN1_STRING_length_set(ASN1_STRING *x, int len)
+{ M_ASN1_STRING_length_set(x, len); return; }
+
+int ASN1_STRING_type(ASN1_STRING *x)
+{ return M_ASN1_STRING_type(x); }
+
+unsigned char * ASN1_STRING_data(ASN1_STRING *x)
+{ return M_ASN1_STRING_data(x); }
diff --git a/crypto/asn1/asn1_locl.h b/crypto/asn1/asn1_locl.h
new file mode 100644
index 0000000..1444390
--- /dev/null
+++ b/crypto/asn1/asn1_locl.h
@@ -0,0 +1,95 @@
+/* asn1t.h */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2006.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 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).
+ *
+ */
+
+/* Internal ASN1 structures and functions: not for application use */
+
+int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d);
+int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d);
+
+/* ASN1 print context structure */
+
+struct asn1_pctx_st
+ {
+ unsigned long flags;
+ unsigned long nm_flags;
+ unsigned long cert_flags;
+ unsigned long oid_flags;
+ unsigned long str_flags;
+ } /* ASN1_PCTX */;
+
+/* ASN1 public key method structure */
+
+
+/* Method to handle CRL access.
+ * In general a CRL could be very large (several Mb) and can consume large
+ * amounts of resources if stored in memory by multiple processes.
+ * This method allows general CRL operations to be redirected to more
+ * efficient callbacks: for example a CRL entry database.
+ */
+
+#define X509_CRL_METHOD_DYNAMIC 1
+
+struct x509_crl_method_st
+ {
+ int flags;
+ int (*crl_init)(X509_CRL *crl);
+ int (*crl_free)(X509_CRL *crl);
+ int (*crl_lookup)(X509_CRL *crl, X509_REVOKED **ret,
+ ASN1_INTEGER *ser, X509_NAME *issuer);
+ int (*crl_verify)(X509_CRL *crl, EVP_PKEY *pk);
+ };
diff --git a/crypto/asn1/asn1_mac.h b/crypto/asn1/asn1_mac.h
new file mode 100644
index 0000000..a69bea4
--- /dev/null
+++ b/crypto/asn1/asn1_mac.h
@@ -0,0 +1,578 @@
+/* crypto/asn1/asn1_mac.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_ASN1_MAC_H
+#define HEADER_ASN1_MAC_H
+
+#include <openssl/asn1.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef ASN1_MAC_ERR_LIB
+#define ASN1_MAC_ERR_LIB ERR_LIB_ASN1
+#endif
+
+#define ASN1_MAC_H_err(f,r,line) \
+ ERR_put_error(ASN1_MAC_ERR_LIB,(f),(r),__FILE__,(line))
+
+#define M_ASN1_D2I_vars(a,type,func) \
+ ASN1_const_CTX c; \
+ type ret=NULL; \
+ \
+ c.pp=(const unsigned char **)pp; \
+ c.q= *(const unsigned char **)pp; \
+ c.error=ASN1_R_NESTED_ASN1_ERROR; \
+ if ((a == NULL) || ((*a) == NULL)) \
+ { if ((ret=(type)func()) == NULL) \
+ { c.line=__LINE__; goto err; } } \
+ else ret=(*a);
+
+#define M_ASN1_D2I_Init() \
+ c.p= *(const unsigned char **)pp; \
+ c.max=(length == 0)?0:(c.p+length);
+
+#define M_ASN1_D2I_Finish_2(a) \
+ if (!asn1_const_Finish(&c)) \
+ { c.line=__LINE__; goto err; } \
+ *(const unsigned char **)pp=c.p; \
+ if (a != NULL) (*a)=ret; \
+ return(ret);
+
+#define M_ASN1_D2I_Finish(a,func,e) \
+ M_ASN1_D2I_Finish_2(a); \
+err:\
+ ASN1_MAC_H_err((e),c.error,c.line); \
+ asn1_add_error(*(const unsigned char **)pp,(int)(c.q- *pp)); \
+ if ((ret != NULL) && ((a == NULL) || (*a != ret))) func(ret); \
+ return(NULL)
+
+#define M_ASN1_D2I_start_sequence() \
+ if (!asn1_GetSequence(&c,&length)) \
+ { c.line=__LINE__; goto err; }
+/* Begin reading ASN1 without a surrounding sequence */
+#define M_ASN1_D2I_begin() \
+ c.slen = length;
+
+/* End reading ASN1 with no check on length */
+#define M_ASN1_D2I_Finish_nolen(a, func, e) \
+ *pp=c.p; \
+ if (a != NULL) (*a)=ret; \
+ return(ret); \
+err:\
+ ASN1_MAC_H_err((e),c.error,c.line); \
+ asn1_add_error(*pp,(int)(c.q- *pp)); \
+ if ((ret != NULL) && ((a == NULL) || (*a != ret))) func(ret); \
+ return(NULL)
+
+#define M_ASN1_D2I_end_sequence() \
+ (((c.inf&1) == 0)?(c.slen <= 0): \
+ (c.eos=ASN1_const_check_infinite_end(&c.p,c.slen)))
+
+/* Don't use this with d2i_ASN1_BOOLEAN() */
+#define M_ASN1_D2I_get(b, func) \
+ c.q=c.p; \
+ if (func(&(b),&c.p,c.slen) == NULL) \
+ {c.line=__LINE__; goto err; } \
+ c.slen-=(c.p-c.q);
+
+/* Don't use this with d2i_ASN1_BOOLEAN() */
+#define M_ASN1_D2I_get_x(type,b,func) \
+ c.q=c.p; \
+ if (((D2I_OF(type))func)(&(b),&c.p,c.slen) == NULL) \
+ {c.line=__LINE__; goto err; } \
+ c.slen-=(c.p-c.q);
+
+/* use this instead () */
+#define M_ASN1_D2I_get_int(b,func) \
+ c.q=c.p; \
+ if (func(&(b),&c.p,c.slen) < 0) \
+ {c.line=__LINE__; goto err; } \
+ c.slen-=(c.p-c.q);
+
+#define M_ASN1_D2I_get_opt(b,func,type) \
+ if ((c.slen != 0) && ((M_ASN1_next & (~V_ASN1_CONSTRUCTED)) \
+ == (V_ASN1_UNIVERSAL|(type)))) \
+ { \
+ M_ASN1_D2I_get(b,func); \
+ }
+
+#define M_ASN1_D2I_get_int_opt(b,func,type) \
+ if ((c.slen != 0) && ((M_ASN1_next & (~V_ASN1_CONSTRUCTED)) \
+ == (V_ASN1_UNIVERSAL|(type)))) \
+ { \
+ M_ASN1_D2I_get_int(b,func); \
+ }
+
+#define M_ASN1_D2I_get_imp(b,func, type) \
+ M_ASN1_next=(_tmp& V_ASN1_CONSTRUCTED)|type; \
+ c.q=c.p; \
+ if (func(&(b),&c.p,c.slen) == NULL) \
+ {c.line=__LINE__; M_ASN1_next_prev = _tmp; goto err; } \
+ c.slen-=(c.p-c.q);\
+ M_ASN1_next_prev=_tmp;
+
+#define M_ASN1_D2I_get_IMP_opt(b,func,tag,type) \
+ if ((c.slen != 0) && ((M_ASN1_next & (~V_ASN1_CONSTRUCTED)) == \
+ (V_ASN1_CONTEXT_SPECIFIC|(tag)))) \
+ { \
+ unsigned char _tmp = M_ASN1_next; \
+ M_ASN1_D2I_get_imp(b,func, type);\
+ }
+
+#define M_ASN1_D2I_get_set(r,func,free_func) \
+ M_ASN1_D2I_get_imp_set(r,func,free_func, \
+ V_ASN1_SET,V_ASN1_UNIVERSAL);
+
+#define M_ASN1_D2I_get_set_type(type,r,func,free_func) \
+ M_ASN1_D2I_get_imp_set_type(type,r,func,free_func, \
+ V_ASN1_SET,V_ASN1_UNIVERSAL);
+
+#define M_ASN1_D2I_get_set_opt(r,func,free_func) \
+ if ((c.slen != 0) && (M_ASN1_next == (V_ASN1_UNIVERSAL| \
+ V_ASN1_CONSTRUCTED|V_ASN1_SET)))\
+ { M_ASN1_D2I_get_set(r,func,free_func); }
+
+#define M_ASN1_D2I_get_set_opt_type(type,r,func,free_func) \
+ if ((c.slen != 0) && (M_ASN1_next == (V_ASN1_UNIVERSAL| \
+ V_ASN1_CONSTRUCTED|V_ASN1_SET)))\
+ { M_ASN1_D2I_get_set_type(type,r,func,free_func); }
+
+#define M_ASN1_I2D_len_SET_opt(a,f) \
+ if ((a != NULL) && (sk_num(a) != 0)) \
+ M_ASN1_I2D_len_SET(a,f);
+
+#define M_ASN1_I2D_put_SET_opt(a,f) \
+ if ((a != NULL) && (sk_num(a) != 0)) \
+ M_ASN1_I2D_put_SET(a,f);
+
+#define M_ASN1_I2D_put_SEQUENCE_opt(a,f) \
+ if ((a != NULL) && (sk_num(a) != 0)) \
+ M_ASN1_I2D_put_SEQUENCE(a,f);
+
+#define M_ASN1_I2D_put_SEQUENCE_opt_type(type,a,f) \
+ if ((a != NULL) && (sk_##type##_num(a) != 0)) \
+ M_ASN1_I2D_put_SEQUENCE_type(type,a,f);
+
+#define M_ASN1_D2I_get_IMP_set_opt(b,func,free_func,tag) \
+ if ((c.slen != 0) && \
+ (M_ASN1_next == \
+ (V_ASN1_CONTEXT_SPECIFIC|V_ASN1_CONSTRUCTED|(tag))))\
+ { \
+ M_ASN1_D2I_get_imp_set(b,func,free_func,\
+ tag,V_ASN1_CONTEXT_SPECIFIC); \
+ }
+
+#define M_ASN1_D2I_get_IMP_set_opt_type(type,b,func,free_func,tag) \
+ if ((c.slen != 0) && \
+ (M_ASN1_next == \
+ (V_ASN1_CONTEXT_SPECIFIC|V_ASN1_CONSTRUCTED|(tag))))\
+ { \
+ M_ASN1_D2I_get_imp_set_type(type,b,func,free_func,\
+ tag,V_ASN1_CONTEXT_SPECIFIC); \
+ }
+
+#define M_ASN1_D2I_get_seq(r,func,free_func) \
+ M_ASN1_D2I_get_imp_set(r,func,free_func,\
+ V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL);
+
+#define M_ASN1_D2I_get_seq_type(type,r,func,free_func) \
+ M_ASN1_D2I_get_imp_set_type(type,r,func,free_func,\
+ V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL)
+
+#define M_ASN1_D2I_get_seq_opt(r,func,free_func) \
+ if ((c.slen != 0) && (M_ASN1_next == (V_ASN1_UNIVERSAL| \
+ V_ASN1_CONSTRUCTED|V_ASN1_SEQUENCE)))\
+ { M_ASN1_D2I_get_seq(r,func,free_func); }
+
+#define M_ASN1_D2I_get_seq_opt_type(type,r,func,free_func) \
+ if ((c.slen != 0) && (M_ASN1_next == (V_ASN1_UNIVERSAL| \
+ V_ASN1_CONSTRUCTED|V_ASN1_SEQUENCE)))\
+ { M_ASN1_D2I_get_seq_type(type,r,func,free_func); }
+
+#define M_ASN1_D2I_get_IMP_set(r,func,free_func,x) \
+ M_ASN1_D2I_get_imp_set(r,func,free_func,\
+ x,V_ASN1_CONTEXT_SPECIFIC);
+
+#define M_ASN1_D2I_get_IMP_set_type(type,r,func,free_func,x) \
+ M_ASN1_D2I_get_imp_set_type(type,r,func,free_func,\
+ x,V_ASN1_CONTEXT_SPECIFIC);
+
+#define M_ASN1_D2I_get_imp_set(r,func,free_func,a,b) \
+ c.q=c.p; \
+ if (d2i_ASN1_SET(&(r),&c.p,c.slen,(char *(*)())func,\
+ (void (*)())free_func,a,b) == NULL) \
+ { c.line=__LINE__; goto err; } \
+ c.slen-=(c.p-c.q);
+
+#define M_ASN1_D2I_get_imp_set_type(type,r,func,free_func,a,b) \
+ c.q=c.p; \
+ if (d2i_ASN1_SET_OF_##type(&(r),&c.p,c.slen,func,\
+ free_func,a,b) == NULL) \
+ { c.line=__LINE__; goto err; } \
+ c.slen-=(c.p-c.q);
+
+#define M_ASN1_D2I_get_set_strings(r,func,a,b) \
+ c.q=c.p; \
+ if (d2i_ASN1_STRING_SET(&(r),&c.p,c.slen,a,b) == NULL) \
+ { c.line=__LINE__; goto err; } \
+ c.slen-=(c.p-c.q);
+
+#define M_ASN1_D2I_get_EXP_opt(r,func,tag) \
+ if ((c.slen != 0L) && (M_ASN1_next == \
+ (V_ASN1_CONSTRUCTED|V_ASN1_CONTEXT_SPECIFIC|tag))) \
+ { \
+ int Tinf,Ttag,Tclass; \
+ long Tlen; \
+ \
+ c.q=c.p; \
+ Tinf=ASN1_get_object(&c.p,&Tlen,&Ttag,&Tclass,c.slen); \
+ if (Tinf & 0x80) \
+ { c.error=ASN1_R_BAD_OBJECT_HEADER; \
+ c.line=__LINE__; goto err; } \
+ if (Tinf == (V_ASN1_CONSTRUCTED+1)) \
+ Tlen = c.slen - (c.p - c.q) - 2; \
+ if (func(&(r),&c.p,Tlen) == NULL) \
+ { c.line=__LINE__; goto err; } \
+ if (Tinf == (V_ASN1_CONSTRUCTED+1)) { \
+ Tlen = c.slen - (c.p - c.q); \
+ if(!ASN1_const_check_infinite_end(&c.p, Tlen)) \
+ { c.error=ASN1_R_MISSING_ASN1_EOS; \
+ c.line=__LINE__; goto err; } \
+ }\
+ c.slen-=(c.p-c.q); \
+ }
+
+#define M_ASN1_D2I_get_EXP_set_opt(r,func,free_func,tag,b) \
+ if ((c.slen != 0) && (M_ASN1_next == \
+ (V_ASN1_CONSTRUCTED|V_ASN1_CONTEXT_SPECIFIC|tag))) \
+ { \
+ int Tinf,Ttag,Tclass; \
+ long Tlen; \
+ \
+ c.q=c.p; \
+ Tinf=ASN1_get_object(&c.p,&Tlen,&Ttag,&Tclass,c.slen); \
+ if (Tinf & 0x80) \
+ { c.error=ASN1_R_BAD_OBJECT_HEADER; \
+ c.line=__LINE__; goto err; } \
+ if (Tinf == (V_ASN1_CONSTRUCTED+1)) \
+ Tlen = c.slen - (c.p - c.q) - 2; \
+ if (d2i_ASN1_SET(&(r),&c.p,Tlen,(char *(*)())func, \
+ (void (*)())free_func, \
+ b,V_ASN1_UNIVERSAL) == NULL) \
+ { c.line=__LINE__; goto err; } \
+ if (Tinf == (V_ASN1_CONSTRUCTED+1)) { \
+ Tlen = c.slen - (c.p - c.q); \
+ if(!ASN1_check_infinite_end(&c.p, Tlen)) \
+ { c.error=ASN1_R_MISSING_ASN1_EOS; \
+ c.line=__LINE__; goto err; } \
+ }\
+ c.slen-=(c.p-c.q); \
+ }
+
+#define M_ASN1_D2I_get_EXP_set_opt_type(type,r,func,free_func,tag,b) \
+ if ((c.slen != 0) && (M_ASN1_next == \
+ (V_ASN1_CONSTRUCTED|V_ASN1_CONTEXT_SPECIFIC|tag))) \
+ { \
+ int Tinf,Ttag,Tclass; \
+ long Tlen; \
+ \
+ c.q=c.p; \
+ Tinf=ASN1_get_object(&c.p,&Tlen,&Ttag,&Tclass,c.slen); \
+ if (Tinf & 0x80) \
+ { c.error=ASN1_R_BAD_OBJECT_HEADER; \
+ c.line=__LINE__; goto err; } \
+ if (Tinf == (V_ASN1_CONSTRUCTED+1)) \
+ Tlen = c.slen - (c.p - c.q) - 2; \
+ if (d2i_ASN1_SET_OF_##type(&(r),&c.p,Tlen,func, \
+ free_func,b,V_ASN1_UNIVERSAL) == NULL) \
+ { c.line=__LINE__; goto err; } \
+ if (Tinf == (V_ASN1_CONSTRUCTED+1)) { \
+ Tlen = c.slen - (c.p - c.q); \
+ if(!ASN1_check_infinite_end(&c.p, Tlen)) \
+ { c.error=ASN1_R_MISSING_ASN1_EOS; \
+ c.line=__LINE__; goto err; } \
+ }\
+ c.slen-=(c.p-c.q); \
+ }
+
+/* New macros */
+#define M_ASN1_New_Malloc(ret,type) \
+ if ((ret=(type *)OPENSSL_malloc(sizeof(type))) == NULL) \
+ { c.line=__LINE__; goto err2; }
+
+#define M_ASN1_New(arg,func) \
+ if (((arg)=func()) == NULL) return(NULL)
+
+#define M_ASN1_New_Error(a) \
+/* err: ASN1_MAC_H_err((a),ASN1_R_NESTED_ASN1_ERROR,c.line); \
+ return(NULL);*/ \
+ err2: ASN1_MAC_H_err((a),ASN1_R_MALLOC_FAILURE,c.line); \
+ return(NULL)
+
+
+/* BIG UGLY WARNING! This is so damn ugly I wanna puke. Unfortunately,
+ some macros that use ASN1_const_CTX still insist on writing in the input
+ stream. ARGH! ARGH! ARGH! Let's get rid of this macro package.
+ Please? -- Richard Levitte */
+#define M_ASN1_next (*((unsigned char *)(c.p)))
+#define M_ASN1_next_prev (*((unsigned char *)(c.q)))
+
+/*************************************************/
+
+#define M_ASN1_I2D_vars(a) int r=0,ret=0; \
+ unsigned char *p; \
+ if (a == NULL) return(0)
+
+/* Length Macros */
+#define M_ASN1_I2D_len(a,f) ret+=f(a,NULL)
+#define M_ASN1_I2D_len_IMP_opt(a,f) if (a != NULL) M_ASN1_I2D_len(a,f)
+
+#define M_ASN1_I2D_len_SET(a,f) \
+ ret+=i2d_ASN1_SET(a,NULL,f,V_ASN1_SET,V_ASN1_UNIVERSAL,IS_SET);
+
+#define M_ASN1_I2D_len_SET_type(type,a,f) \
+ ret+=i2d_ASN1_SET_OF_##type(a,NULL,f,V_ASN1_SET, \
+ V_ASN1_UNIVERSAL,IS_SET);
+
+#define M_ASN1_I2D_len_SEQUENCE(a,f) \
+ ret+=i2d_ASN1_SET(a,NULL,f,V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL, \
+ IS_SEQUENCE);
+
+#define M_ASN1_I2D_len_SEQUENCE_type(type,a,f) \
+ ret+=i2d_ASN1_SET_OF_##type(a,NULL,f,V_ASN1_SEQUENCE, \
+ V_ASN1_UNIVERSAL,IS_SEQUENCE)
+
+#define M_ASN1_I2D_len_SEQUENCE_opt(a,f) \
+ if ((a != NULL) && (sk_num(a) != 0)) \
+ M_ASN1_I2D_len_SEQUENCE(a,f);
+
+#define M_ASN1_I2D_len_SEQUENCE_opt_type(type,a,f) \
+ if ((a != NULL) && (sk_##type##_num(a) != 0)) \
+ M_ASN1_I2D_len_SEQUENCE_type(type,a,f);
+
+#define M_ASN1_I2D_len_IMP_SET(a,f,x) \
+ ret+=i2d_ASN1_SET(a,NULL,f,x,V_ASN1_CONTEXT_SPECIFIC,IS_SET);
+
+#define M_ASN1_I2D_len_IMP_SET_type(type,a,f,x) \
+ ret+=i2d_ASN1_SET_OF_##type(a,NULL,f,x, \
+ V_ASN1_CONTEXT_SPECIFIC,IS_SET);
+
+#define M_ASN1_I2D_len_IMP_SET_opt(a,f,x) \
+ if ((a != NULL) && (sk_num(a) != 0)) \
+ ret+=i2d_ASN1_SET(a,NULL,f,x,V_ASN1_CONTEXT_SPECIFIC, \
+ IS_SET);
+
+#define M_ASN1_I2D_len_IMP_SET_opt_type(type,a,f,x) \
+ if ((a != NULL) && (sk_##type##_num(a) != 0)) \
+ ret+=i2d_ASN1_SET_OF_##type(a,NULL,f,x, \
+ V_ASN1_CONTEXT_SPECIFIC,IS_SET);
+
+#define M_ASN1_I2D_len_IMP_SEQUENCE(a,f,x) \
+ ret+=i2d_ASN1_SET(a,NULL,f,x,V_ASN1_CONTEXT_SPECIFIC, \
+ IS_SEQUENCE);
+
+#define M_ASN1_I2D_len_IMP_SEQUENCE_opt(a,f,x) \
+ if ((a != NULL) && (sk_num(a) != 0)) \
+ ret+=i2d_ASN1_SET(a,NULL,f,x,V_ASN1_CONTEXT_SPECIFIC, \
+ IS_SEQUENCE);
+
+#define M_ASN1_I2D_len_IMP_SEQUENCE_opt_type(type,a,f,x) \
+ if ((a != NULL) && (sk_##type##_num(a) != 0)) \
+ ret+=i2d_ASN1_SET_OF_##type(a,NULL,f,x, \
+ V_ASN1_CONTEXT_SPECIFIC, \
+ IS_SEQUENCE);
+
+#define M_ASN1_I2D_len_EXP_opt(a,f,mtag,v) \
+ if (a != NULL)\
+ { \
+ v=f(a,NULL); \
+ ret+=ASN1_object_size(1,v,mtag); \
+ }
+
+#define M_ASN1_I2D_len_EXP_SET_opt(a,f,mtag,tag,v) \
+ if ((a != NULL) && (sk_num(a) != 0))\
+ { \
+ v=i2d_ASN1_SET(a,NULL,f,tag,V_ASN1_UNIVERSAL,IS_SET); \
+ ret+=ASN1_object_size(1,v,mtag); \
+ }
+
+#define M_ASN1_I2D_len_EXP_SEQUENCE_opt(a,f,mtag,tag,v) \
+ if ((a != NULL) && (sk_num(a) != 0))\
+ { \
+ v=i2d_ASN1_SET(a,NULL,f,tag,V_ASN1_UNIVERSAL, \
+ IS_SEQUENCE); \
+ ret+=ASN1_object_size(1,v,mtag); \
+ }
+
+#define M_ASN1_I2D_len_EXP_SEQUENCE_opt_type(type,a,f,mtag,tag,v) \
+ if ((a != NULL) && (sk_##type##_num(a) != 0))\
+ { \
+ v=i2d_ASN1_SET_OF_##type(a,NULL,f,tag, \
+ V_ASN1_UNIVERSAL, \
+ IS_SEQUENCE); \
+ ret+=ASN1_object_size(1,v,mtag); \
+ }
+
+/* Put Macros */
+#define M_ASN1_I2D_put(a,f) f(a,&p)
+
+#define M_ASN1_I2D_put_IMP_opt(a,f,t) \
+ if (a != NULL) \
+ { \
+ unsigned char *q=p; \
+ f(a,&p); \
+ *q=(V_ASN1_CONTEXT_SPECIFIC|t|(*q&V_ASN1_CONSTRUCTED));\
+ }
+
+#define M_ASN1_I2D_put_SET(a,f) i2d_ASN1_SET(a,&p,f,V_ASN1_SET,\
+ V_ASN1_UNIVERSAL,IS_SET)
+#define M_ASN1_I2D_put_SET_type(type,a,f) \
+ i2d_ASN1_SET_OF_##type(a,&p,f,V_ASN1_SET,V_ASN1_UNIVERSAL,IS_SET)
+#define M_ASN1_I2D_put_IMP_SET(a,f,x) i2d_ASN1_SET(a,&p,f,x,\
+ V_ASN1_CONTEXT_SPECIFIC,IS_SET)
+#define M_ASN1_I2D_put_IMP_SET_type(type,a,f,x) \
+ i2d_ASN1_SET_OF_##type(a,&p,f,x,V_ASN1_CONTEXT_SPECIFIC,IS_SET)
+#define M_ASN1_I2D_put_IMP_SEQUENCE(a,f,x) i2d_ASN1_SET(a,&p,f,x,\
+ V_ASN1_CONTEXT_SPECIFIC,IS_SEQUENCE)
+
+#define M_ASN1_I2D_put_SEQUENCE(a,f) i2d_ASN1_SET(a,&p,f,V_ASN1_SEQUENCE,\
+ V_ASN1_UNIVERSAL,IS_SEQUENCE)
+
+#define M_ASN1_I2D_put_SEQUENCE_type(type,a,f) \
+ i2d_ASN1_SET_OF_##type(a,&p,f,V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL, \
+ IS_SEQUENCE)
+
+#define M_ASN1_I2D_put_SEQUENCE_opt(a,f) \
+ if ((a != NULL) && (sk_num(a) != 0)) \
+ M_ASN1_I2D_put_SEQUENCE(a,f);
+
+#define M_ASN1_I2D_put_IMP_SET_opt(a,f,x) \
+ if ((a != NULL) && (sk_num(a) != 0)) \
+ { i2d_ASN1_SET(a,&p,f,x,V_ASN1_CONTEXT_SPECIFIC, \
+ IS_SET); }
+
+#define M_ASN1_I2D_put_IMP_SET_opt_type(type,a,f,x) \
+ if ((a != NULL) && (sk_##type##_num(a) != 0)) \
+ { i2d_ASN1_SET_OF_##type(a,&p,f,x, \
+ V_ASN1_CONTEXT_SPECIFIC, \
+ IS_SET); }
+
+#define M_ASN1_I2D_put_IMP_SEQUENCE_opt(a,f,x) \
+ if ((a != NULL) && (sk_num(a) != 0)) \
+ { i2d_ASN1_SET(a,&p,f,x,V_ASN1_CONTEXT_SPECIFIC, \
+ IS_SEQUENCE); }
+
+#define M_ASN1_I2D_put_IMP_SEQUENCE_opt_type(type,a,f,x) \
+ if ((a != NULL) && (sk_##type##_num(a) != 0)) \
+ { i2d_ASN1_SET_OF_##type(a,&p,f,x, \
+ V_ASN1_CONTEXT_SPECIFIC, \
+ IS_SEQUENCE); }
+
+#define M_ASN1_I2D_put_EXP_opt(a,f,tag,v) \
+ if (a != NULL) \
+ { \
+ ASN1_put_object(&p,1,v,tag,V_ASN1_CONTEXT_SPECIFIC); \
+ f(a,&p); \
+ }
+
+#define M_ASN1_I2D_put_EXP_SET_opt(a,f,mtag,tag,v) \
+ if ((a != NULL) && (sk_num(a) != 0)) \
+ { \
+ ASN1_put_object(&p,1,v,mtag,V_ASN1_CONTEXT_SPECIFIC); \
+ i2d_ASN1_SET(a,&p,f,tag,V_ASN1_UNIVERSAL,IS_SET); \
+ }
+
+#define M_ASN1_I2D_put_EXP_SEQUENCE_opt(a,f,mtag,tag,v) \
+ if ((a != NULL) && (sk_num(a) != 0)) \
+ { \
+ ASN1_put_object(&p,1,v,mtag,V_ASN1_CONTEXT_SPECIFIC); \
+ i2d_ASN1_SET(a,&p,f,tag,V_ASN1_UNIVERSAL,IS_SEQUENCE); \
+ }
+
+#define M_ASN1_I2D_put_EXP_SEQUENCE_opt_type(type,a,f,mtag,tag,v) \
+ if ((a != NULL) && (sk_##type##_num(a) != 0)) \
+ { \
+ ASN1_put_object(&p,1,v,mtag,V_ASN1_CONTEXT_SPECIFIC); \
+ i2d_ASN1_SET_OF_##type(a,&p,f,tag,V_ASN1_UNIVERSAL, \
+ IS_SEQUENCE); \
+ }
+
+#define M_ASN1_I2D_seq_total() \
+ r=ASN1_object_size(1,ret,V_ASN1_SEQUENCE); \
+ if (pp == NULL) return(r); \
+ p= *pp; \
+ ASN1_put_object(&p,1,ret,V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL)
+
+#define M_ASN1_I2D_INF_seq_start(tag,ctx) \
+ *(p++)=(V_ASN1_CONSTRUCTED|(tag)|(ctx)); \
+ *(p++)=0x80
+
+#define M_ASN1_I2D_INF_seq_end() *(p++)=0x00; *(p++)=0x00
+
+#define M_ASN1_I2D_finish() *pp=p; \
+ return(r);
+
+int asn1_GetSequence(ASN1_const_CTX *c, long *length);
+void asn1_add_error(const unsigned char *address,int offset);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/crypto/asn1/asn1_par.c b/crypto/asn1/asn1_par.c
new file mode 100644
index 0000000..53b11fe
--- /dev/null
+++ b/crypto/asn1/asn1_par.c
@@ -0,0 +1,435 @@
+/* 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/asn1.h>
+
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+static int asn1_print_info(BIO *bp, int tag, int xclass,int constructed,
+ int indent);
+static int asn1_parse2(BIO *bp, const unsigned char **pp, long length,
+ int offset, int depth, int indent, int dump);
+static int asn1_print_info(BIO *bp, int tag, int xclass, int constructed,
+ int indent)
+ {
+ static const char fmt[]="%-18s";
+ char str[128];
+ const char *p;
+
+ if (constructed & V_ASN1_CONSTRUCTED)
+ p="cons: ";
+ else
+ p="prim: ";
+ if (BIO_write(bp,p,6) < 6) goto err;
+ BIO_indent(bp,indent,128);
+
+ p=str;
+ if ((xclass & V_ASN1_PRIVATE) == V_ASN1_PRIVATE)
+ BIO_snprintf(str,sizeof str,"priv [ %d ] ",tag);
+ else if ((xclass & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC)
+ BIO_snprintf(str,sizeof str,"cont [ %d ]",tag);
+ else if ((xclass & V_ASN1_APPLICATION) == V_ASN1_APPLICATION)
+ BIO_snprintf(str,sizeof str,"appl [ %d ]",tag);
+ else if (tag > 30)
+ BIO_snprintf(str,sizeof str,"<ASN1 %d>",tag);
+ else
+ p = ASN1_tag2str(tag);
+
+ if (BIO_printf(bp,fmt,p) <= 0)
+ goto err;
+ return(1);
+err:
+ return(0);
+ }
+
+int ASN1_parse(BIO *bp, const unsigned char *pp, long len, int indent)
+ {
+ return(asn1_parse2(bp,&pp,len,0,0,indent,0));
+ }
+
+int ASN1_parse_dump(BIO *bp, const unsigned char *pp, long len, int indent, int dump)
+ {
+ return(asn1_parse2(bp,&pp,len,0,0,indent,dump));
+ }
+
+static int asn1_parse2(BIO *bp, const unsigned char **pp, long length, int offset,
+ int depth, int indent, int dump)
+ {
+ const unsigned char *p,*ep,*tot,*op,*opp;
+ long len;
+ int tag,xclass,ret=0;
+ int nl,hl,j,r;
+ ASN1_OBJECT *o=NULL;
+ ASN1_OCTET_STRING *os=NULL;
+ /* ASN1_BMPSTRING *bmp=NULL;*/
+ int dump_indent;
+
+#if 0
+ dump_indent = indent;
+#else
+ dump_indent = 6; /* Because we know BIO_dump_indent() */
+#endif
+ p= *pp;
+ tot=p+length;
+ op=p-1;
+ while ((p < tot) && (op < p))
+ {
+ op=p;
+ j=ASN1_get_object(&p,&len,&tag,&xclass,length);
+#ifdef LINT
+ j=j;
+#endif
+ if (j & 0x80)
+ {
+ if (BIO_write(bp,"Error in encoding\n",18) <= 0)
+ goto end;
+ ret=0;
+ goto end;
+ }
+ hl=(p-op);
+ length-=hl;
+ /* if j == 0x21 it is a constructed indefinite length object */
+ if (BIO_printf(bp,"%5ld:",(long)offset+(long)(op- *pp))
+ <= 0) goto end;
+
+ if (j != (V_ASN1_CONSTRUCTED | 1))
+ {
+ if (BIO_printf(bp,"d=%-2d hl=%ld l=%4ld ",
+ depth,(long)hl,len) <= 0)
+ goto end;
+ }
+ else
+ {
+ if (BIO_printf(bp,"d=%-2d hl=%ld l=inf ",
+ depth,(long)hl) <= 0)
+ goto end;
+ }
+ if (!asn1_print_info(bp,tag,xclass,j,(indent)?depth:0))
+ goto end;
+ if (j & V_ASN1_CONSTRUCTED)
+ {
+ ep=p+len;
+ if (BIO_write(bp,"\n",1) <= 0) goto end;
+ if (len > length)
+ {
+ BIO_printf(bp,
+ "length is greater than %ld\n",length);
+ ret=0;
+ goto end;
+ }
+ if ((j == 0x21) && (len == 0))
+ {
+ for (;;)
+ {
+ r=asn1_parse2(bp,&p,(long)(tot-p),
+ offset+(p - *pp),depth+1,
+ indent,dump);
+ if (r == 0) { ret=0; goto end; }
+ if ((r == 2) || (p >= tot)) break;
+ }
+ }
+ else
+ while (p < ep)
+ {
+ r=asn1_parse2(bp,&p,(long)len,
+ offset+(p - *pp),depth+1,
+ indent,dump);
+ if (r == 0) { ret=0; goto end; }
+ }
+ }
+ else if (xclass != 0)
+ {
+ p+=len;
+ if (BIO_write(bp,"\n",1) <= 0) goto end;
+ }
+ else
+ {
+ nl=0;
+ if ( (tag == V_ASN1_PRINTABLESTRING) ||
+ (tag == V_ASN1_T61STRING) ||
+ (tag == V_ASN1_IA5STRING) ||
+ (tag == V_ASN1_VISIBLESTRING) ||
+ (tag == V_ASN1_NUMERICSTRING) ||
+ (tag == V_ASN1_UTF8STRING) ||
+ (tag == V_ASN1_UTCTIME) ||
+ (tag == V_ASN1_GENERALIZEDTIME))
+ {
+ if (BIO_write(bp,":",1) <= 0) goto end;
+ if ((len > 0) &&
+ BIO_write(bp,(const char *)p,(int)len)
+ != (int)len)
+ goto end;
+ }
+ else if (tag == V_ASN1_OBJECT)
+ {
+ opp=op;
+ if (d2i_ASN1_OBJECT(&o,&opp,len+hl) != NULL)
+ {
+ if (BIO_write(bp,":",1) <= 0) goto end;
+ i2a_ASN1_OBJECT(bp,o);
+ }
+ else
+ {
+ if (BIO_write(bp,":BAD OBJECT",11) <= 0)
+ goto end;
+ }
+ }
+ else if (tag == V_ASN1_BOOLEAN)
+ {
+ int ii;
+
+ opp=op;
+ ii=d2i_ASN1_BOOLEAN(NULL,&opp,len+hl);
+ if (ii < 0)
+ {
+ if (BIO_write(bp,"Bad boolean\n",12) <= 0)
+ goto end;
+ }
+ BIO_printf(bp,":%d",ii);
+ }
+ else if (tag == V_ASN1_BMPSTRING)
+ {
+ /* do the BMP thang */
+ }
+ else if (tag == V_ASN1_OCTET_STRING)
+ {
+ int i,printable=1;
+
+ opp=op;
+ os=d2i_ASN1_OCTET_STRING(NULL,&opp,len+hl);
+ if (os != NULL && os->length > 0)
+ {
+ opp = os->data;
+ /* testing whether the octet string is
+ * printable */
+ for (i=0; i<os->length; i++)
+ {
+ if (( (opp[i] < ' ') &&
+ (opp[i] != '\n') &&
+ (opp[i] != '\r') &&
+ (opp[i] != '\t')) ||
+ (opp[i] > '~'))
+ {
+ printable=0;
+ break;
+ }
+ }
+ if (printable)
+ /* printable string */
+ {
+ if (BIO_write(bp,":",1) <= 0)
+ goto end;
+ if (BIO_write(bp,(const char *)opp,
+ os->length) <= 0)
+ goto end;
+ }
+ else if (!dump)
+ /* not printable => print octet string
+ * as hex dump */
+ {
+ if (BIO_write(bp,"[HEX DUMP]:",11) <= 0)
+ goto end;
+ for (i=0; i<os->length; i++)
+ {
+ if (BIO_printf(bp,"%02X"
+ , opp[i]) <= 0)
+ goto end;
+ }
+ }
+ else
+ /* print the normal dump */
+ {
+ if (!nl)
+ {
+ if (BIO_write(bp,"\n",1) <= 0)
+ goto end;
+ }
+ if (!BIO_hexdump(bp, opp,
+ ((dump == -1 || dump >
+ os->length)?os->length:dump),
+ dump_indent))
+ goto end;
+ nl=1;
+ }
+ }
+ if (os != NULL)
+ {
+ M_ASN1_OCTET_STRING_free(os);
+ os=NULL;
+ }
+ }
+ else if (tag == V_ASN1_INTEGER)
+ {
+ ASN1_INTEGER *bs;
+ int i;
+
+ opp=op;
+ bs=d2i_ASN1_INTEGER(NULL,&opp,len+hl);
+ if (bs != NULL)
+ {
+ if (BIO_write(bp,":",1) <= 0) goto end;
+ if (bs->type == V_ASN1_NEG_INTEGER)
+ if (BIO_write(bp,"-",1) <= 0)
+ goto end;
+ for (i=0; i<bs->length; i++)
+ {
+ if (BIO_printf(bp,"%02X",
+ bs->data[i]) <= 0)
+ goto end;
+ }
+ if (bs->length == 0)
+ {
+ if (BIO_write(bp,"00",2) <= 0)
+ goto end;
+ }
+ }
+ else
+ {
+ if (BIO_write(bp,"BAD INTEGER",11) <= 0)
+ goto end;
+ }
+ M_ASN1_INTEGER_free(bs);
+ }
+ else if (tag == V_ASN1_ENUMERATED)
+ {
+ ASN1_ENUMERATED *bs;
+ int i;
+
+ opp=op;
+ bs=d2i_ASN1_ENUMERATED(NULL,&opp,len+hl);
+ if (bs != NULL)
+ {
+ if (BIO_write(bp,":",1) <= 0) goto end;
+ if (bs->type == V_ASN1_NEG_ENUMERATED)
+ if (BIO_write(bp,"-",1) <= 0)
+ goto end;
+ for (i=0; i<bs->length; i++)
+ {
+ if (BIO_printf(bp,"%02X",
+ bs->data[i]) <= 0)
+ goto end;
+ }
+ if (bs->length == 0)
+ {
+ if (BIO_write(bp,"00",2) <= 0)
+ goto end;
+ }
+ }
+ else
+ {
+ if (BIO_write(bp,"BAD ENUMERATED",11) <= 0)
+ goto end;
+ }
+ M_ASN1_ENUMERATED_free(bs);
+ }
+ else if (len > 0 && dump)
+ {
+ if (!nl)
+ {
+ if (BIO_write(bp,"\n",1) <= 0)
+ goto end;
+ }
+ if (!BIO_hexdump(bp,p,
+ ((dump == -1 || dump > len)?len:dump),
+ dump_indent))
+ goto end;
+ nl=1;
+ }
+
+ if (!nl)
+ {
+ if (BIO_write(bp,"\n",1) <= 0) goto end;
+ }
+ p+=len;
+ if ((tag == V_ASN1_EOC) && (xclass == 0))
+ {
+ ret=2; /* End of sequence */
+ goto end;
+ }
+ }
+ length-=len;
+ }
+ ret=1;
+end:
+ if (o != NULL) ASN1_OBJECT_free(o);
+ if (os != NULL) M_ASN1_OCTET_STRING_free(os);
+ *pp=p;
+ return(ret);
+ }
+
+const char *ASN1_tag2str(int tag)
+{
+ static const char * const tag2str[] = {
+ "EOC", "BOOLEAN", "INTEGER", "BIT STRING", "OCTET STRING", /* 0-4 */
+ "NULL", "OBJECT", "OBJECT DESCRIPTOR", "EXTERNAL", "REAL", /* 5-9 */
+ "ENUMERATED", "<ASN1 11>", "UTF8STRING", "<ASN1 13>", /* 10-13 */
+ "<ASN1 14>", "<ASN1 15>", "SEQUENCE", "SET", /* 15-17 */
+ "NUMERICSTRING", "PRINTABLESTRING", "T61STRING", /* 18-20 */
+ "VIDEOTEXSTRING", "IA5STRING", "UTCTIME","GENERALIZEDTIME", /* 21-24 */
+ "GRAPHICSTRING", "VISIBLESTRING", "GENERALSTRING", /* 25-27 */
+ "UNIVERSALSTRING", "<ASN1 29>", "BMPSTRING" /* 28-30 */
+ };
+
+ if((tag == V_ASN1_NEG_INTEGER) || (tag == V_ASN1_NEG_ENUMERATED))
+ tag &= ~0x100;
+
+ if(tag < 0 || tag > 30) return "(unknown)";
+ return tag2str[tag];
+}
+
diff --git a/crypto/asn1/asn1t.h b/crypto/asn1/asn1t.h
new file mode 100644
index 0000000..ea59aaa
--- /dev/null
+++ b/crypto/asn1/asn1t.h
@@ -0,0 +1,959 @@
+/* asn1t.h */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2000.
+ */
+/* ====================================================================
+ * Copyright (c) 2000-2005 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).
+ *
+ */
+#ifndef HEADER_ASN1T_H
+#define HEADER_ASN1T_H
+
+#include <stddef.h>
+#include <openssl/asn1.h>
+
+#ifdef OPENSSL_BUILD_SHLIBCRYPTO
+# undef OPENSSL_EXTERN
+# define OPENSSL_EXTERN OPENSSL_EXPORT
+#endif
+
+/* ASN1 template defines, structures and functions */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifndef OPENSSL_EXPORT_VAR_AS_FUNCTION
+
+/* Macro to obtain ASN1_ADB pointer from a type (only used internally) */
+#define ASN1_ADB_ptr(iptr) ((const ASN1_ADB *)(iptr))
+
+
+/* Macros for start and end of ASN1_ITEM definition */
+
+#define ASN1_ITEM_start(itname) \
+ const ASN1_ITEM itname##_it = {
+
+#define ASN1_ITEM_end(itname) \
+ };
+
+#else
+
+/* Macro to obtain ASN1_ADB pointer from a type (only used internally) */
+#define ASN1_ADB_ptr(iptr) ((const ASN1_ADB *)(iptr()))
+
+
+/* Macros for start and end of ASN1_ITEM definition */
+
+#define ASN1_ITEM_start(itname) \
+ const ASN1_ITEM * itname##_it(void) \
+ { \
+ static const ASN1_ITEM local_it = {
+
+#define ASN1_ITEM_end(itname) \
+ }; \
+ return &local_it; \
+ }
+
+#endif
+
+
+/* Macros to aid ASN1 template writing */
+
+#define ASN1_ITEM_TEMPLATE(tname) \
+ static const ASN1_TEMPLATE tname##_item_tt
+
+#define ASN1_ITEM_TEMPLATE_END(tname) \
+ ;\
+ ASN1_ITEM_start(tname) \
+ ASN1_ITYPE_PRIMITIVE,\
+ -1,\
+ &tname##_item_tt,\
+ 0,\
+ NULL,\
+ 0,\
+ #tname \
+ ASN1_ITEM_end(tname)
+
+
+/* This is a ASN1 type which just embeds a template */
+
+/* This pair helps declare a SEQUENCE. We can do:
+ *
+ * ASN1_SEQUENCE(stname) = {
+ * ... SEQUENCE components ...
+ * } ASN1_SEQUENCE_END(stname)
+ *
+ * This will produce an ASN1_ITEM called stname_it
+ * for a structure called stname.
+ *
+ * If you want the same structure but a different
+ * name then use:
+ *
+ * ASN1_SEQUENCE(itname) = {
+ * ... SEQUENCE components ...
+ * } ASN1_SEQUENCE_END_name(stname, itname)
+ *
+ * This will create an item called itname_it using
+ * a structure called stname.
+ */
+
+#define ASN1_SEQUENCE(tname) \
+ static const ASN1_TEMPLATE tname##_seq_tt[]
+
+#define ASN1_SEQUENCE_END(stname) ASN1_SEQUENCE_END_name(stname, stname)
+
+#define ASN1_SEQUENCE_END_name(stname, tname) \
+ ;\
+ ASN1_ITEM_start(tname) \
+ ASN1_ITYPE_SEQUENCE,\
+ V_ASN1_SEQUENCE,\
+ tname##_seq_tt,\
+ sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\
+ NULL,\
+ sizeof(stname),\
+ #stname \
+ ASN1_ITEM_end(tname)
+
+#define ASN1_NDEF_SEQUENCE(tname) \
+ ASN1_SEQUENCE(tname)
+
+#define ASN1_NDEF_SEQUENCE_cb(tname, cb) \
+ ASN1_SEQUENCE_cb(tname, cb)
+
+#define ASN1_SEQUENCE_cb(tname, cb) \
+ static const ASN1_AUX tname##_aux = {NULL, 0, 0, 0, cb, 0}; \
+ ASN1_SEQUENCE(tname)
+
+#define ASN1_BROKEN_SEQUENCE(tname) \
+ static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_BROKEN, 0, 0, 0, 0}; \
+ ASN1_SEQUENCE(tname)
+
+#define ASN1_SEQUENCE_ref(tname, cb, lck) \
+ static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_REFCOUNT, offsetof(tname, references), lck, cb, 0}; \
+ ASN1_SEQUENCE(tname)
+
+#define ASN1_SEQUENCE_enc(tname, enc, cb) \
+ static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_ENCODING, 0, 0, cb, offsetof(tname, enc)}; \
+ ASN1_SEQUENCE(tname)
+
+#define ASN1_NDEF_SEQUENCE_END(tname) \
+ ;\
+ ASN1_ITEM_start(tname) \
+ ASN1_ITYPE_NDEF_SEQUENCE,\
+ V_ASN1_SEQUENCE,\
+ tname##_seq_tt,\
+ sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\
+ NULL,\
+ sizeof(tname),\
+ #tname \
+ ASN1_ITEM_end(tname)
+
+#define ASN1_BROKEN_SEQUENCE_END(stname) ASN1_SEQUENCE_END_ref(stname, stname)
+
+#define ASN1_SEQUENCE_END_enc(stname, tname) ASN1_SEQUENCE_END_ref(stname, tname)
+
+#define ASN1_SEQUENCE_END_cb(stname, tname) ASN1_SEQUENCE_END_ref(stname, tname)
+
+#define ASN1_SEQUENCE_END_ref(stname, tname) \
+ ;\
+ ASN1_ITEM_start(tname) \
+ ASN1_ITYPE_SEQUENCE,\
+ V_ASN1_SEQUENCE,\
+ tname##_seq_tt,\
+ sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\
+ &tname##_aux,\
+ sizeof(stname),\
+ #stname \
+ ASN1_ITEM_end(tname)
+
+#define ASN1_NDEF_SEQUENCE_END_cb(stname, tname) \
+ ;\
+ ASN1_ITEM_start(tname) \
+ ASN1_ITYPE_NDEF_SEQUENCE,\
+ V_ASN1_SEQUENCE,\
+ tname##_seq_tt,\
+ sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\
+ &tname##_aux,\
+ sizeof(stname),\
+ #stname \
+ ASN1_ITEM_end(tname)
+
+
+/* This pair helps declare a CHOICE type. We can do:
+ *
+ * ASN1_CHOICE(chname) = {
+ * ... CHOICE options ...
+ * ASN1_CHOICE_END(chname)
+ *
+ * This will produce an ASN1_ITEM called chname_it
+ * for a structure called chname. The structure
+ * definition must look like this:
+ * typedef struct {
+ * int type;
+ * union {
+ * ASN1_SOMETHING *opt1;
+ * ASN1_SOMEOTHER *opt2;
+ * } value;
+ * } chname;
+ *
+ * the name of the selector must be 'type'.
+ * to use an alternative selector name use the
+ * ASN1_CHOICE_END_selector() version.
+ */
+
+#define ASN1_CHOICE(tname) \
+ static const ASN1_TEMPLATE tname##_ch_tt[]
+
+#define ASN1_CHOICE_cb(tname, cb) \
+ static const ASN1_AUX tname##_aux = {NULL, 0, 0, 0, cb, 0}; \
+ ASN1_CHOICE(tname)
+
+#define ASN1_CHOICE_END(stname) ASN1_CHOICE_END_name(stname, stname)
+
+#define ASN1_CHOICE_END_name(stname, tname) ASN1_CHOICE_END_selector(stname, tname, type)
+
+#define ASN1_CHOICE_END_selector(stname, tname, selname) \
+ ;\
+ ASN1_ITEM_start(tname) \
+ ASN1_ITYPE_CHOICE,\
+ offsetof(stname,selname) ,\
+ tname##_ch_tt,\
+ sizeof(tname##_ch_tt) / sizeof(ASN1_TEMPLATE),\
+ NULL,\
+ sizeof(stname),\
+ #stname \
+ ASN1_ITEM_end(tname)
+
+#define ASN1_CHOICE_END_cb(stname, tname, selname) \
+ ;\
+ ASN1_ITEM_start(tname) \
+ ASN1_ITYPE_CHOICE,\
+ offsetof(stname,selname) ,\
+ tname##_ch_tt,\
+ sizeof(tname##_ch_tt) / sizeof(ASN1_TEMPLATE),\
+ &tname##_aux,\
+ sizeof(stname),\
+ #stname \
+ ASN1_ITEM_end(tname)
+
+/* This helps with the template wrapper form of ASN1_ITEM */
+
+#define ASN1_EX_TEMPLATE_TYPE(flags, tag, name, type) { \
+ (flags), (tag), 0,\
+ #name, ASN1_ITEM_ref(type) }
+
+/* These help with SEQUENCE or CHOICE components */
+
+/* used to declare other types */
+
+#define ASN1_EX_TYPE(flags, tag, stname, field, type) { \
+ (flags), (tag), offsetof(stname, field),\
+ #field, ASN1_ITEM_ref(type) }
+
+/* used when the structure is combined with the parent */
+
+#define ASN1_EX_COMBINE(flags, tag, type) { \
+ (flags)|ASN1_TFLG_COMBINE, (tag), 0, NULL, ASN1_ITEM_ref(type) }
+
+/* implicit and explicit helper macros */
+
+#define ASN1_IMP_EX(stname, field, type, tag, ex) \
+ ASN1_EX_TYPE(ASN1_TFLG_IMPLICIT | ex, tag, stname, field, type)
+
+#define ASN1_EXP_EX(stname, field, type, tag, ex) \
+ ASN1_EX_TYPE(ASN1_TFLG_EXPLICIT | ex, tag, stname, field, type)
+
+/* Any defined by macros: the field used is in the table itself */
+
+#ifndef OPENSSL_EXPORT_VAR_AS_FUNCTION
+#define ASN1_ADB_OBJECT(tblname) { ASN1_TFLG_ADB_OID, -1, 0, #tblname, (const ASN1_ITEM *)&(tblname##_adb) }
+#define ASN1_ADB_INTEGER(tblname) { ASN1_TFLG_ADB_INT, -1, 0, #tblname, (const ASN1_ITEM *)&(tblname##_adb) }
+#else
+#define ASN1_ADB_OBJECT(tblname) { ASN1_TFLG_ADB_OID, -1, 0, #tblname, tblname##_adb }
+#define ASN1_ADB_INTEGER(tblname) { ASN1_TFLG_ADB_INT, -1, 0, #tblname, tblname##_adb }
+#endif
+/* Plain simple type */
+#define ASN1_SIMPLE(stname, field, type) ASN1_EX_TYPE(0,0, stname, field, type)
+
+/* OPTIONAL simple type */
+#define ASN1_OPT(stname, field, type) ASN1_EX_TYPE(ASN1_TFLG_OPTIONAL, 0, stname, field, type)
+
+/* IMPLICIT tagged simple type */
+#define ASN1_IMP(stname, field, type, tag) ASN1_IMP_EX(stname, field, type, tag, 0)
+
+/* IMPLICIT tagged OPTIONAL simple type */
+#define ASN1_IMP_OPT(stname, field, type, tag) ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL)
+
+/* Same as above but EXPLICIT */
+
+#define ASN1_EXP(stname, field, type, tag) ASN1_EXP_EX(stname, field, type, tag, 0)
+#define ASN1_EXP_OPT(stname, field, type, tag) ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL)
+
+/* SEQUENCE OF type */
+#define ASN1_SEQUENCE_OF(stname, field, type) \
+ ASN1_EX_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, stname, field, type)
+
+/* OPTIONAL SEQUENCE OF */
+#define ASN1_SEQUENCE_OF_OPT(stname, field, type) \
+ ASN1_EX_TYPE(ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL, 0, stname, field, type)
+
+/* Same as above but for SET OF */
+
+#define ASN1_SET_OF(stname, field, type) \
+ ASN1_EX_TYPE(ASN1_TFLG_SET_OF, 0, stname, field, type)
+
+#define ASN1_SET_OF_OPT(stname, field, type) \
+ ASN1_EX_TYPE(ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL, 0, stname, field, type)
+
+/* Finally compound types of SEQUENCE, SET, IMPLICIT, EXPLICIT and OPTIONAL */
+
+#define ASN1_IMP_SET_OF(stname, field, type, tag) \
+ ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF)
+
+#define ASN1_EXP_SET_OF(stname, field, type, tag) \
+ ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF)
+
+#define ASN1_IMP_SET_OF_OPT(stname, field, type, tag) \
+ ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL)
+
+#define ASN1_EXP_SET_OF_OPT(stname, field, type, tag) \
+ ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL)
+
+#define ASN1_IMP_SEQUENCE_OF(stname, field, type, tag) \
+ ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF)
+
+#define ASN1_IMP_SEQUENCE_OF_OPT(stname, field, type, tag) \
+ ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL)
+
+#define ASN1_EXP_SEQUENCE_OF(stname, field, type, tag) \
+ ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF)
+
+#define ASN1_EXP_SEQUENCE_OF_OPT(stname, field, type, tag) \
+ ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL)
+
+/* EXPLICIT using indefinite length constructed form */
+#define ASN1_NDEF_EXP(stname, field, type, tag) \
+ ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_NDEF)
+
+/* EXPLICIT OPTIONAL using indefinite length constructed form */
+#define ASN1_NDEF_EXP_OPT(stname, field, type, tag) \
+ ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL|ASN1_TFLG_NDEF)
+
+/* Macros for the ASN1_ADB structure */
+
+#define ASN1_ADB(name) \
+ static const ASN1_ADB_TABLE name##_adbtbl[]
+
+#ifndef OPENSSL_EXPORT_VAR_AS_FUNCTION
+
+#define ASN1_ADB_END(name, flags, field, app_table, def, none) \
+ ;\
+ static const ASN1_ADB name##_adb = {\
+ flags,\
+ offsetof(name, field),\
+ app_table,\
+ name##_adbtbl,\
+ sizeof(name##_adbtbl) / sizeof(ASN1_ADB_TABLE),\
+ def,\
+ none\
+ }
+
+#else
+
+#define ASN1_ADB_END(name, flags, field, app_table, def, none) \
+ ;\
+ static const ASN1_ITEM *name##_adb(void) \
+ { \
+ static const ASN1_ADB internal_adb = \
+ {\
+ flags,\
+ offsetof(name, field),\
+ app_table,\
+ name##_adbtbl,\
+ sizeof(name##_adbtbl) / sizeof(ASN1_ADB_TABLE),\
+ def,\
+ none\
+ }; \
+ return (const ASN1_ITEM *) &internal_adb; \
+ } \
+ void dummy_function(void)
+
+#endif
+
+#define ADB_ENTRY(val, template) {val, template}
+
+#define ASN1_ADB_TEMPLATE(name) \
+ static const ASN1_TEMPLATE name##_tt
+
+/* This is the ASN1 template structure that defines
+ * a wrapper round the actual type. It determines the
+ * actual position of the field in the value structure,
+ * various flags such as OPTIONAL and the field name.
+ */
+
+struct ASN1_TEMPLATE_st {
+unsigned long flags; /* Various flags */
+long tag; /* tag, not used if no tagging */
+unsigned long offset; /* Offset of this field in structure */
+#ifndef NO_ASN1_FIELD_NAMES
+const char *field_name; /* Field name */
+#endif
+ASN1_ITEM_EXP *item; /* Relevant ASN1_ITEM or ASN1_ADB */
+};
+
+/* Macro to extract ASN1_ITEM and ASN1_ADB pointer from ASN1_TEMPLATE */
+
+#define ASN1_TEMPLATE_item(t) (t->item_ptr)
+#define ASN1_TEMPLATE_adb(t) (t->item_ptr)
+
+typedef struct ASN1_ADB_TABLE_st ASN1_ADB_TABLE;
+typedef struct ASN1_ADB_st ASN1_ADB;
+
+struct ASN1_ADB_st {
+ unsigned long flags; /* Various flags */
+ unsigned long offset; /* Offset of selector field */
+ STACK_OF(ASN1_ADB_TABLE) **app_items; /* Application defined items */
+ const ASN1_ADB_TABLE *tbl; /* Table of possible types */
+ long tblcount; /* Number of entries in tbl */
+ const ASN1_TEMPLATE *default_tt; /* Type to use if no match */
+ const ASN1_TEMPLATE *null_tt; /* Type to use if selector is NULL */
+};
+
+struct ASN1_ADB_TABLE_st {
+ long value; /* NID for an object or value for an int */
+ const ASN1_TEMPLATE tt; /* item for this value */
+};
+
+/* template flags */
+
+/* Field is optional */
+#define ASN1_TFLG_OPTIONAL (0x1)
+
+/* Field is a SET OF */
+#define ASN1_TFLG_SET_OF (0x1 << 1)
+
+/* Field is a SEQUENCE OF */
+#define ASN1_TFLG_SEQUENCE_OF (0x2 << 1)
+
+/* Special case: this refers to a SET OF that
+ * will be sorted into DER order when encoded *and*
+ * the corresponding STACK will be modified to match
+ * the new order.
+ */
+#define ASN1_TFLG_SET_ORDER (0x3 << 1)
+
+/* Mask for SET OF or SEQUENCE OF */
+#define ASN1_TFLG_SK_MASK (0x3 << 1)
+
+/* These flags mean the tag should be taken from the
+ * tag field. If EXPLICIT then the underlying type
+ * is used for the inner tag.
+ */
+
+/* IMPLICIT tagging */
+#define ASN1_TFLG_IMPTAG (0x1 << 3)
+
+
+/* EXPLICIT tagging, inner tag from underlying type */
+#define ASN1_TFLG_EXPTAG (0x2 << 3)
+
+#define ASN1_TFLG_TAG_MASK (0x3 << 3)
+
+/* context specific IMPLICIT */
+#define ASN1_TFLG_IMPLICIT ASN1_TFLG_IMPTAG|ASN1_TFLG_CONTEXT
+
+/* context specific EXPLICIT */
+#define ASN1_TFLG_EXPLICIT ASN1_TFLG_EXPTAG|ASN1_TFLG_CONTEXT
+
+/* If tagging is in force these determine the
+ * type of tag to use. Otherwise the tag is
+ * determined by the underlying type. These
+ * values reflect the actual octet format.
+ */
+
+/* Universal tag */
+#define ASN1_TFLG_UNIVERSAL (0x0<<6)
+/* Application tag */
+#define ASN1_TFLG_APPLICATION (0x1<<6)
+/* Context specific tag */
+#define ASN1_TFLG_CONTEXT (0x2<<6)
+/* Private tag */
+#define ASN1_TFLG_PRIVATE (0x3<<6)
+
+#define ASN1_TFLG_TAG_CLASS (0x3<<6)
+
+/* These are for ANY DEFINED BY type. In this case
+ * the 'item' field points to an ASN1_ADB structure
+ * which contains a table of values to decode the
+ * relevant type
+ */
+
+#define ASN1_TFLG_ADB_MASK (0x3<<8)
+
+#define ASN1_TFLG_ADB_OID (0x1<<8)
+
+#define ASN1_TFLG_ADB_INT (0x1<<9)
+
+/* This flag means a parent structure is passed
+ * instead of the field: this is useful is a
+ * SEQUENCE is being combined with a CHOICE for
+ * example. Since this means the structure and
+ * item name will differ we need to use the
+ * ASN1_CHOICE_END_name() macro for example.
+ */
+
+#define ASN1_TFLG_COMBINE (0x1<<10)
+
+/* This flag when present in a SEQUENCE OF, SET OF
+ * or EXPLICIT causes indefinite length constructed
+ * encoding to be used if required.
+ */
+
+#define ASN1_TFLG_NDEF (0x1<<11)
+
+/* This is the actual ASN1 item itself */
+
+struct ASN1_ITEM_st {
+char itype; /* The item type, primitive, SEQUENCE, CHOICE or extern */
+long utype; /* underlying type */
+const ASN1_TEMPLATE *templates; /* If SEQUENCE or CHOICE this contains the contents */
+long tcount; /* Number of templates if SEQUENCE or CHOICE */
+const void *funcs; /* functions that handle this type */
+long size; /* Structure size (usually)*/
+#ifndef NO_ASN1_FIELD_NAMES
+const char *sname; /* Structure name */
+#endif
+};
+
+/* These are values for the itype field and
+ * determine how the type is interpreted.
+ *
+ * For PRIMITIVE types the underlying type
+ * determines the behaviour if items is NULL.
+ *
+ * Otherwise templates must contain a single
+ * template and the type is treated in the
+ * same way as the type specified in the template.
+ *
+ * For SEQUENCE types the templates field points
+ * to the members, the size field is the
+ * structure size.
+ *
+ * For CHOICE types the templates field points
+ * to each possible member (typically a union)
+ * and the 'size' field is the offset of the
+ * selector.
+ *
+ * The 'funcs' field is used for application
+ * specific functions.
+ *
+ * For COMPAT types the funcs field gives a
+ * set of functions that handle this type, this
+ * supports the old d2i, i2d convention.
+ *
+ * The EXTERN type uses a new style d2i/i2d.
+ * The new style should be used where possible
+ * because it avoids things like the d2i IMPLICIT
+ * hack.
+ *
+ * MSTRING is a multiple string type, it is used
+ * for a CHOICE of character strings where the
+ * actual strings all occupy an ASN1_STRING
+ * structure. In this case the 'utype' field
+ * has a special meaning, it is used as a mask
+ * of acceptable types using the B_ASN1 constants.
+ *
+ * NDEF_SEQUENCE is the same as SEQUENCE except
+ * that it will use indefinite length constructed
+ * encoding if requested.
+ *
+ */
+
+#define ASN1_ITYPE_PRIMITIVE 0x0
+
+#define ASN1_ITYPE_SEQUENCE 0x1
+
+#define ASN1_ITYPE_CHOICE 0x2
+
+#define ASN1_ITYPE_COMPAT 0x3
+
+#define ASN1_ITYPE_EXTERN 0x4
+
+#define ASN1_ITYPE_MSTRING 0x5
+
+#define ASN1_ITYPE_NDEF_SEQUENCE 0x6
+
+/* Cache for ASN1 tag and length, so we
+ * don't keep re-reading it for things
+ * like CHOICE
+ */
+
+struct ASN1_TLC_st{
+ char valid; /* Values below are valid */
+ int ret; /* return value */
+ long plen; /* length */
+ int ptag; /* class value */
+ int pclass; /* class value */
+ int hdrlen; /* header length */
+};
+
+/* Typedefs for ASN1 function pointers */
+
+typedef ASN1_VALUE * ASN1_new_func(void);
+typedef void ASN1_free_func(ASN1_VALUE *a);
+typedef ASN1_VALUE * ASN1_d2i_func(ASN1_VALUE **a, const unsigned char ** in, long length);
+typedef int ASN1_i2d_func(ASN1_VALUE * a, unsigned char **in);
+
+typedef int ASN1_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it,
+ int tag, int aclass, char opt, ASN1_TLC *ctx);
+
+typedef int ASN1_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass);
+typedef int ASN1_ex_new_func(ASN1_VALUE **pval, const ASN1_ITEM *it);
+typedef void ASN1_ex_free_func(ASN1_VALUE **pval, const ASN1_ITEM *it);
+
+typedef int ASN1_ex_print_func(BIO *out, ASN1_VALUE **pval,
+ int indent, const char *fname,
+ const ASN1_PCTX *pctx);
+
+typedef int ASN1_primitive_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it);
+typedef int ASN1_primitive_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it);
+typedef int ASN1_primitive_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it, int indent, const ASN1_PCTX *pctx);
+
+typedef struct ASN1_COMPAT_FUNCS_st {
+ ASN1_new_func *asn1_new;
+ ASN1_free_func *asn1_free;
+ ASN1_d2i_func *asn1_d2i;
+ ASN1_i2d_func *asn1_i2d;
+} ASN1_COMPAT_FUNCS;
+
+typedef struct ASN1_EXTERN_FUNCS_st {
+ void *app_data;
+ ASN1_ex_new_func *asn1_ex_new;
+ ASN1_ex_free_func *asn1_ex_free;
+ ASN1_ex_free_func *asn1_ex_clear;
+ ASN1_ex_d2i *asn1_ex_d2i;
+ ASN1_ex_i2d *asn1_ex_i2d;
+ ASN1_ex_print_func *asn1_ex_print;
+} ASN1_EXTERN_FUNCS;
+
+typedef struct ASN1_PRIMITIVE_FUNCS_st {
+ void *app_data;
+ unsigned long flags;
+ ASN1_ex_new_func *prim_new;
+ ASN1_ex_free_func *prim_free;
+ ASN1_ex_free_func *prim_clear;
+ ASN1_primitive_c2i *prim_c2i;
+ ASN1_primitive_i2c *prim_i2c;
+ ASN1_primitive_print *prim_print;
+} ASN1_PRIMITIVE_FUNCS;
+
+/* This is the ASN1_AUX structure: it handles various
+ * miscellaneous requirements. For example the use of
+ * reference counts and an informational callback.
+ *
+ * The "informational callback" is called at various
+ * points during the ASN1 encoding and decoding. It can
+ * be used to provide minor customisation of the structures
+ * used. This is most useful where the supplied routines
+ * *almost* do the right thing but need some extra help
+ * at a few points. If the callback returns zero then
+ * it is assumed a fatal error has occurred and the
+ * main operation should be abandoned.
+ *
+ * If major changes in the default behaviour are required
+ * then an external type is more appropriate.
+ */
+
+typedef int ASN1_aux_cb(int operation, ASN1_VALUE **in, const ASN1_ITEM *it,
+ void *exarg);
+
+typedef struct ASN1_AUX_st {
+ void *app_data;
+ int flags;
+ int ref_offset; /* Offset of reference value */
+ int ref_lock; /* Lock type to use */
+ ASN1_aux_cb *asn1_cb;
+ int enc_offset; /* Offset of ASN1_ENCODING structure */
+} ASN1_AUX;
+
+/* For print related callbacks exarg points to this structure */
+typedef struct ASN1_PRINT_ARG_st {
+ BIO *out;
+ int indent;
+ const ASN1_PCTX *pctx;
+} ASN1_PRINT_ARG;
+
+/* For streaming related callbacks exarg points to this structure */
+typedef struct ASN1_STREAM_ARG_st {
+ /* BIO to stream through */
+ BIO *out;
+ /* BIO with filters appended */
+ BIO *ndef_bio;
+ /* Streaming I/O boundary */
+ unsigned char **boundary;
+} ASN1_STREAM_ARG;
+
+/* Flags in ASN1_AUX */
+
+/* Use a reference count */
+#define ASN1_AFLG_REFCOUNT 1
+/* Save the encoding of structure (useful for signatures) */
+#define ASN1_AFLG_ENCODING 2
+/* The Sequence length is invalid */
+#define ASN1_AFLG_BROKEN 4
+
+/* operation values for asn1_cb */
+
+#define ASN1_OP_NEW_PRE 0
+#define ASN1_OP_NEW_POST 1
+#define ASN1_OP_FREE_PRE 2
+#define ASN1_OP_FREE_POST 3
+#define ASN1_OP_D2I_PRE 4
+#define ASN1_OP_D2I_POST 5
+#define ASN1_OP_I2D_PRE 6
+#define ASN1_OP_I2D_POST 7
+#define ASN1_OP_PRINT_PRE 8
+#define ASN1_OP_PRINT_POST 9
+#define ASN1_OP_STREAM_PRE 10
+#define ASN1_OP_STREAM_POST 11
+#define ASN1_OP_DETACHED_PRE 12
+#define ASN1_OP_DETACHED_POST 13
+
+/* Macro to implement a primitive type */
+#define IMPLEMENT_ASN1_TYPE(stname) IMPLEMENT_ASN1_TYPE_ex(stname, stname, 0)
+#define IMPLEMENT_ASN1_TYPE_ex(itname, vname, ex) \
+ ASN1_ITEM_start(itname) \
+ ASN1_ITYPE_PRIMITIVE, V_##vname, NULL, 0, NULL, ex, #itname \
+ ASN1_ITEM_end(itname)
+
+/* Macro to implement a multi string type */
+#define IMPLEMENT_ASN1_MSTRING(itname, mask) \
+ ASN1_ITEM_start(itname) \
+ ASN1_ITYPE_MSTRING, mask, NULL, 0, NULL, sizeof(ASN1_STRING), #itname \
+ ASN1_ITEM_end(itname)
+
+/* Macro to implement an ASN1_ITEM in terms of old style funcs */
+
+#define IMPLEMENT_COMPAT_ASN1(sname) IMPLEMENT_COMPAT_ASN1_type(sname, V_ASN1_SEQUENCE)
+
+#define IMPLEMENT_COMPAT_ASN1_type(sname, tag) \
+ static const ASN1_COMPAT_FUNCS sname##_ff = { \
+ (ASN1_new_func *)sname##_new, \
+ (ASN1_free_func *)sname##_free, \
+ (ASN1_d2i_func *)d2i_##sname, \
+ (ASN1_i2d_func *)i2d_##sname, \
+ }; \
+ ASN1_ITEM_start(sname) \
+ ASN1_ITYPE_COMPAT, \
+ tag, \
+ NULL, \
+ 0, \
+ &sname##_ff, \
+ 0, \
+ #sname \
+ ASN1_ITEM_end(sname)
+
+#define IMPLEMENT_EXTERN_ASN1(sname, tag, fptrs) \
+ ASN1_ITEM_start(sname) \
+ ASN1_ITYPE_EXTERN, \
+ tag, \
+ NULL, \
+ 0, \
+ &fptrs, \
+ 0, \
+ #sname \
+ ASN1_ITEM_end(sname)
+
+/* Macro to implement standard functions in terms of ASN1_ITEM structures */
+
+#define IMPLEMENT_ASN1_FUNCTIONS(stname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, stname, stname)
+
+#define IMPLEMENT_ASN1_FUNCTIONS_name(stname, itname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, itname)
+
+#define IMPLEMENT_ASN1_FUNCTIONS_ENCODE_name(stname, itname) \
+ IMPLEMENT_ASN1_FUNCTIONS_ENCODE_fname(stname, itname, itname)
+
+#define IMPLEMENT_STATIC_ASN1_ALLOC_FUNCTIONS(stname) \
+ IMPLEMENT_ASN1_ALLOC_FUNCTIONS_pfname(static, stname, stname, stname)
+
+#define IMPLEMENT_ASN1_ALLOC_FUNCTIONS(stname) \
+ IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, stname, stname)
+
+#define IMPLEMENT_ASN1_ALLOC_FUNCTIONS_pfname(pre, stname, itname, fname) \
+ pre stname *fname##_new(void) \
+ { \
+ return (stname *)ASN1_item_new(ASN1_ITEM_rptr(itname)); \
+ } \
+ pre void fname##_free(stname *a) \
+ { \
+ ASN1_item_free((ASN1_VALUE *)a, ASN1_ITEM_rptr(itname)); \
+ }
+
+#define IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname) \
+ stname *fname##_new(void) \
+ { \
+ return (stname *)ASN1_item_new(ASN1_ITEM_rptr(itname)); \
+ } \
+ void fname##_free(stname *a) \
+ { \
+ ASN1_item_free((ASN1_VALUE *)a, ASN1_ITEM_rptr(itname)); \
+ }
+
+#define IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, fname) \
+ IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname) \
+ IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname)
+
+#define IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname) \
+ stname *d2i_##fname(stname **a, const unsigned char **in, long len) \
+ { \
+ return (stname *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, ASN1_ITEM_rptr(itname));\
+ } \
+ int i2d_##fname(stname *a, unsigned char **out) \
+ { \
+ return ASN1_item_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(itname));\
+ }
+
+#define IMPLEMENT_ASN1_NDEF_FUNCTION(stname) \
+ int i2d_##stname##_NDEF(stname *a, unsigned char **out) \
+ { \
+ return ASN1_item_ndef_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(stname));\
+ }
+
+/* This includes evil casts to remove const: they will go away when full
+ * ASN1 constification is done.
+ */
+#define IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(stname, itname, fname) \
+ stname *d2i_##fname(stname **a, const unsigned char **in, long len) \
+ { \
+ return (stname *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, ASN1_ITEM_rptr(itname));\
+ } \
+ int i2d_##fname(const stname *a, unsigned char **out) \
+ { \
+ return ASN1_item_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(itname));\
+ }
+
+#define IMPLEMENT_ASN1_DUP_FUNCTION(stname) \
+ stname * stname##_dup(stname *x) \
+ { \
+ return ASN1_item_dup(ASN1_ITEM_rptr(stname), x); \
+ }
+
+#define IMPLEMENT_ASN1_PRINT_FUNCTION(stname) \
+ IMPLEMENT_ASN1_PRINT_FUNCTION_fname(stname, stname, stname)
+
+#define IMPLEMENT_ASN1_PRINT_FUNCTION_fname(stname, itname, fname) \
+ int fname##_print_ctx(BIO *out, stname *x, int indent, \
+ const ASN1_PCTX *pctx) \
+ { \
+ return ASN1_item_print(out, (ASN1_VALUE *)x, indent, \
+ ASN1_ITEM_rptr(itname), pctx); \
+ }
+
+#define IMPLEMENT_ASN1_FUNCTIONS_const(name) \
+ IMPLEMENT_ASN1_FUNCTIONS_const_fname(name, name, name)
+
+#define IMPLEMENT_ASN1_FUNCTIONS_const_fname(stname, itname, fname) \
+ IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(stname, itname, fname) \
+ IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname)
+
+/* external definitions for primitive types */
+
+DECLARE_ASN1_ITEM(ASN1_BOOLEAN)
+DECLARE_ASN1_ITEM(ASN1_TBOOLEAN)
+DECLARE_ASN1_ITEM(ASN1_FBOOLEAN)
+DECLARE_ASN1_ITEM(ASN1_SEQUENCE)
+DECLARE_ASN1_ITEM(CBIGNUM)
+DECLARE_ASN1_ITEM(BIGNUM)
+DECLARE_ASN1_ITEM(LONG)
+DECLARE_ASN1_ITEM(ZLONG)
+
+DECLARE_STACK_OF(ASN1_VALUE)
+
+/* Functions used internally by the ASN1 code */
+
+int ASN1_item_ex_new(ASN1_VALUE **pval, const ASN1_ITEM *it);
+void ASN1_item_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
+int ASN1_template_new(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt);
+int ASN1_primitive_new(ASN1_VALUE **pval, const ASN1_ITEM *it);
+
+void ASN1_template_free(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt);
+int ASN1_template_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_TEMPLATE *tt);
+int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it,
+ int tag, int aclass, char opt, ASN1_TLC *ctx);
+
+int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass);
+int ASN1_template_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_TEMPLATE *tt);
+void ASN1_primitive_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
+
+int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it);
+int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it);
+
+int asn1_get_choice_selector(ASN1_VALUE **pval, const ASN1_ITEM *it);
+int asn1_set_choice_selector(ASN1_VALUE **pval, int value, const ASN1_ITEM *it);
+
+ASN1_VALUE ** asn1_get_field_ptr(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt);
+
+const ASN1_TEMPLATE *asn1_do_adb(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt, int nullerr);
+
+int asn1_do_lock(ASN1_VALUE **pval, int op, const ASN1_ITEM *it);
+
+void asn1_enc_init(ASN1_VALUE **pval, const ASN1_ITEM *it);
+void asn1_enc_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
+int asn1_enc_restore(int *len, unsigned char **out, ASN1_VALUE **pval, const ASN1_ITEM *it);
+int asn1_enc_save(ASN1_VALUE **pval, const unsigned char *in, int inlen, const ASN1_ITEM *it);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/crypto/asn1/asn_pack.c b/crypto/asn1/asn_pack.c
new file mode 100644
index 0000000..3845906
--- /dev/null
+++ b/crypto/asn1/asn_pack.c
@@ -0,0 +1,193 @@
+/* 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/asn1.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+#if 0
+#ifndef NO_ASN1_OLD
+
+/* ASN1 packing and unpacking functions */
+
+/* Turn an ASN1 encoded SEQUENCE OF into a STACK of structures */
+
+STACK_OF(OPENSSL_BLOCK) *ASN1_seq_unpack(const unsigned char *buf, int len,
+ d2i_of_void *d2i, void (*free_func)(OPENSSL_BLOCK))
+{
+ STACK_OF(OPENSSL_BLOCK) *sk;
+ const unsigned char *pbuf;
+ pbuf = buf;
+ if (!(sk = d2i_ASN1_SET(NULL, &pbuf, len, d2i, free_func,
+ V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL)))
+ OPENSSL_PUT_ERROR(ASN1, XXX, ASN1_R_DECODE_ERROR);
+ return sk;
+}
+
+/* Turn a STACK structures into an ASN1 encoded SEQUENCE OF structure in a
+ * OPENSSL_malloc'ed buffer
+ */
+
+unsigned char *ASN1_seq_pack(STACK_OF(OPENSSL_BLOCK) *safes, i2d_of_void *i2d,
+ unsigned char **buf, int *len)
+{
+ int safelen;
+ unsigned char *safe, *p;
+ if (!(safelen = i2d_ASN1_SET(safes, NULL, i2d, V_ASN1_SEQUENCE,
+ V_ASN1_UNIVERSAL, IS_SEQUENCE))) {
+ OPENSSL_PUT_ERROR(ASN1, XXX, ASN1_R_ENCODE_ERROR);
+ return NULL;
+ }
+ if (!(safe = OPENSSL_malloc (safelen))) {
+ OPENSSL_PUT_ERROR(ASN1, XXX, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ p = safe;
+ i2d_ASN1_SET(safes, &p, i2d, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL,
+ IS_SEQUENCE);
+ if (len) *len = safelen;
+ if (buf) *buf = safe;
+ return safe;
+}
+
+/* Extract an ASN1 object from an ASN1_STRING */
+
+void *ASN1_unpack_string(ASN1_STRING *oct, d2i_of_void *d2i)
+{
+ const unsigned char *p;
+ char *ret;
+
+ p = oct->data;
+ if(!(ret = d2i(NULL, &p, oct->length)))
+ OPENSSL_PUT_ERROR(ASN1, XXX, ASN1_R_DECODE_ERROR);
+ return ret;
+}
+
+/* Pack an ASN1 object into an ASN1_STRING */
+
+ASN1_STRING *ASN1_pack_string(void *obj, i2d_of_void *i2d, ASN1_STRING **oct)
+{
+ unsigned char *p;
+ ASN1_STRING *octmp;
+
+ if (!oct || !*oct) {
+ if (!(octmp = ASN1_STRING_new ())) {
+ OPENSSL_PUT_ERROR(ASN1, XXX, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ if (oct) *oct = octmp;
+ } else octmp = *oct;
+
+ if (!(octmp->length = i2d(obj, NULL))) {
+ OPENSSL_PUT_ERROR(ASN1, XXX, ASN1_R_ENCODE_ERROR);
+ return NULL;
+ }
+ if (!(p = OPENSSL_malloc (octmp->length))) {
+ OPENSSL_PUT_ERROR(ASN1, XXX, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ octmp->data = p;
+ i2d (obj, &p);
+ return octmp;
+}
+
+#endif
+#endif
+
+/* ASN1_ITEM versions of the above */
+
+ASN1_STRING *ASN1_item_pack(void *obj, const ASN1_ITEM *it, ASN1_STRING **oct)
+{
+ ASN1_STRING *octmp;
+
+ if (!oct || !*oct) {
+ if (!(octmp = ASN1_STRING_new ())) {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_item_pack, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ if (oct) *oct = octmp;
+ } else octmp = *oct;
+
+ if(octmp->data) {
+ OPENSSL_free(octmp->data);
+ octmp->data = NULL;
+ }
+
+ if (!(octmp->length = ASN1_item_i2d(obj, &octmp->data, it))) {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_item_pack, ASN1_R_ENCODE_ERROR);
+ return NULL;
+ }
+ if (!octmp->data) {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_item_pack, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ return octmp;
+}
+
+/* Extract an ASN1 object from an ASN1_STRING */
+
+void *ASN1_item_unpack(ASN1_STRING *oct, const ASN1_ITEM *it)
+{
+ const unsigned char *p;
+ void *ret;
+
+ p = oct->data;
+ if(!(ret = ASN1_item_d2i(NULL, &p, oct->length, it)))
+ OPENSSL_PUT_ERROR(ASN1, ASN1_item_unpack, ASN1_R_DECODE_ERROR);
+ return ret;
+}
diff --git a/crypto/asn1/bio_asn1.c b/crypto/asn1/bio_asn1.c
new file mode 100644
index 0000000..5658839
--- /dev/null
+++ b/crypto/asn1/bio_asn1.c
@@ -0,0 +1,492 @@
+/* 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/asn1.h>
+
+#include <assert.h>
+
+#include <openssl/bio.h>
+#include <openssl/mem.h>
+
+
+/* Must be large enough for biggest tag+length */
+#define DEFAULT_ASN1_BUF_SIZE 20
+
+typedef enum
+ {
+ ASN1_STATE_START,
+ ASN1_STATE_PRE_COPY,
+ ASN1_STATE_HEADER,
+ ASN1_STATE_HEADER_COPY,
+ ASN1_STATE_DATA_COPY,
+ ASN1_STATE_POST_COPY,
+ ASN1_STATE_DONE
+ } asn1_bio_state_t;
+
+typedef struct BIO_ASN1_EX_FUNCS_st
+ {
+ asn1_ps_func *ex_func;
+ asn1_ps_func *ex_free_func;
+ } BIO_ASN1_EX_FUNCS;
+
+typedef struct BIO_ASN1_BUF_CTX_t
+ {
+ /* Internal state */
+ asn1_bio_state_t state;
+ /* Internal buffer */
+ unsigned char *buf;
+ /* Size of buffer */
+ int bufsize;
+ /* Current position in buffer */
+ int bufpos;
+ /* Current buffer length */
+ int buflen;
+ /* Amount of data to copy */
+ int copylen;
+ /* Class and tag to use */
+ int asn1_class, asn1_tag;
+ asn1_ps_func *prefix, *prefix_free, *suffix, *suffix_free;
+ /* Extra buffer for prefix and suffix data */
+ unsigned char *ex_buf;
+ int ex_len;
+ int ex_pos;
+ void *ex_arg;
+ } BIO_ASN1_BUF_CTX;
+
+
+static int asn1_bio_write(BIO *h, const char *buf,int num);
+static int asn1_bio_read(BIO *h, char *buf, int size);
+static int asn1_bio_puts(BIO *h, const char *str);
+static int asn1_bio_gets(BIO *h, char *str, int size);
+static long asn1_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2);
+static int asn1_bio_new(BIO *h);
+static int asn1_bio_free(BIO *data);
+static long asn1_bio_callback_ctrl(BIO *h, int cmd, bio_info_cb fp);
+
+static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size);
+static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
+ asn1_ps_func *cleanup, asn1_bio_state_t next);
+static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
+ asn1_ps_func *setup,
+ asn1_bio_state_t ex_state,
+ asn1_bio_state_t other_state);
+
+static BIO_METHOD methods_asn1=
+ {
+ BIO_TYPE_ASN1,
+ "asn1",
+ asn1_bio_write,
+ asn1_bio_read,
+ asn1_bio_puts,
+ asn1_bio_gets,
+ asn1_bio_ctrl,
+ asn1_bio_new,
+ asn1_bio_free,
+ asn1_bio_callback_ctrl,
+ };
+
+BIO_METHOD *BIO_f_asn1(void)
+ {
+ return(&methods_asn1);
+ }
+
+
+static int asn1_bio_new(BIO *b)
+ {
+ BIO_ASN1_BUF_CTX *ctx;
+ ctx = OPENSSL_malloc(sizeof(BIO_ASN1_BUF_CTX));
+ if (!ctx)
+ return 0;
+ if (!asn1_bio_init(ctx, DEFAULT_ASN1_BUF_SIZE))
+ return 0;
+ b->init = 1;
+ b->ptr = (char *)ctx;
+ b->flags = 0;
+ return 1;
+ }
+
+static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size)
+ {
+ ctx->buf = OPENSSL_malloc(size);
+ if (!ctx->buf)
+ return 0;
+ ctx->bufsize = size;
+ ctx->bufpos = 0;
+ ctx->buflen = 0;
+ ctx->copylen = 0;
+ ctx->asn1_class = V_ASN1_UNIVERSAL;
+ ctx->asn1_tag = V_ASN1_OCTET_STRING;
+ ctx->ex_buf = 0;
+ ctx->ex_pos = 0;
+ ctx->ex_len = 0;
+ ctx->state = ASN1_STATE_START;
+ return 1;
+ }
+
+static int asn1_bio_free(BIO *b)
+ {
+ BIO_ASN1_BUF_CTX *ctx;
+ ctx = (BIO_ASN1_BUF_CTX *) b->ptr;
+ if (ctx == NULL)
+ return 0;
+ if (ctx->buf)
+ OPENSSL_free(ctx->buf);
+ OPENSSL_free(ctx);
+ b->init = 0;
+ b->ptr = NULL;
+ b->flags = 0;
+ return 1;
+ }
+
+static int asn1_bio_write(BIO *b, const char *in , int inl)
+ {
+ BIO_ASN1_BUF_CTX *ctx;
+ int wrmax, wrlen, ret;
+ unsigned char *p;
+ if (!in || (inl < 0) || (b->next_bio == NULL))
+ return 0;
+ ctx = (BIO_ASN1_BUF_CTX *) b->ptr;
+ if (ctx == NULL)
+ return 0;
+
+ wrlen = 0;
+ ret = -1;
+
+ for(;;)
+ {
+ switch (ctx->state)
+ {
+
+ /* Setup prefix data, call it */
+ case ASN1_STATE_START:
+ if (!asn1_bio_setup_ex(b, ctx, ctx->prefix,
+ ASN1_STATE_PRE_COPY, ASN1_STATE_HEADER))
+ return 0;
+ break;
+
+ /* Copy any pre data first */
+ case ASN1_STATE_PRE_COPY:
+
+ ret = asn1_bio_flush_ex(b, ctx, ctx->prefix_free,
+ ASN1_STATE_HEADER);
+
+ if (ret <= 0)
+ goto done;
+
+ break;
+
+ case ASN1_STATE_HEADER:
+ ctx->buflen =
+ ASN1_object_size(0, inl, ctx->asn1_tag) - inl;
+ assert(ctx->buflen <= ctx->bufsize);
+ p = ctx->buf;
+ ASN1_put_object(&p, 0, inl,
+ ctx->asn1_tag, ctx->asn1_class);
+ ctx->copylen = inl;
+ ctx->state = ASN1_STATE_HEADER_COPY;
+
+ break;
+
+ case ASN1_STATE_HEADER_COPY:
+ ret = BIO_write(b->next_bio,
+ ctx->buf + ctx->bufpos, ctx->buflen);
+ if (ret <= 0)
+ goto done;
+
+ ctx->buflen -= ret;
+ if (ctx->buflen)
+ ctx->bufpos += ret;
+ else
+ {
+ ctx->bufpos = 0;
+ ctx->state = ASN1_STATE_DATA_COPY;
+ }
+
+ break;
+
+ case ASN1_STATE_DATA_COPY:
+
+ if (inl > ctx->copylen)
+ wrmax = ctx->copylen;
+ else
+ wrmax = inl;
+ ret = BIO_write(b->next_bio, in, wrmax);
+ if (ret <= 0)
+ break;
+ wrlen += ret;
+ ctx->copylen -= ret;
+ in += ret;
+ inl -= ret;
+
+ if (ctx->copylen == 0)
+ ctx->state = ASN1_STATE_HEADER;
+
+ if (inl == 0)
+ goto done;
+
+ break;
+
+ default:
+ BIO_clear_retry_flags(b);
+ return 0;
+
+ }
+
+ }
+
+ done:
+ BIO_clear_retry_flags(b);
+ BIO_copy_next_retry(b);
+
+ return (wrlen > 0) ? wrlen : ret;
+
+ }
+
+static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
+ asn1_ps_func *cleanup, asn1_bio_state_t next)
+ {
+ int ret;
+ if (ctx->ex_len <= 0)
+ return 1;
+ for(;;)
+ {
+ ret = BIO_write(b->next_bio, ctx->ex_buf + ctx->ex_pos,
+ ctx->ex_len);
+ if (ret <= 0)
+ break;
+ ctx->ex_len -= ret;
+ if (ctx->ex_len > 0)
+ ctx->ex_pos += ret;
+ else
+ {
+ if(cleanup)
+ cleanup(b, &ctx->ex_buf, &ctx->ex_len,
+ &ctx->ex_arg);
+ ctx->state = next;
+ ctx->ex_pos = 0;
+ break;
+ }
+ }
+ return ret;
+ }
+
+static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
+ asn1_ps_func *setup,
+ asn1_bio_state_t ex_state,
+ asn1_bio_state_t other_state)
+ {
+ if (setup && !setup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg))
+ {
+ BIO_clear_retry_flags(b);
+ return 0;
+ }
+ if (ctx->ex_len > 0)
+ ctx->state = ex_state;
+ else
+ ctx->state = other_state;
+ return 1;
+ }
+
+static int asn1_bio_read(BIO *b, char *in , int inl)
+ {
+ if (!b->next_bio)
+ return 0;
+ return BIO_read(b->next_bio, in , inl);
+ }
+
+static int asn1_bio_puts(BIO *b, const char *str)
+ {
+ return asn1_bio_write(b, str, strlen(str));
+ }
+
+static int asn1_bio_gets(BIO *b, char *str, int size)
+ {
+ if (!b->next_bio)
+ return 0;
+ return BIO_gets(b->next_bio, str , size);
+ }
+
+static long asn1_bio_callback_ctrl(BIO *b, int cmd, bio_info_cb fp)
+ {
+ if (b->next_bio == NULL) return(0);
+ return BIO_callback_ctrl(b->next_bio,cmd,fp);
+ }
+
+static long asn1_bio_ctrl(BIO *b, int cmd, long arg1, void *arg2)
+ {
+ BIO_ASN1_BUF_CTX *ctx;
+ BIO_ASN1_EX_FUNCS *ex_func;
+ long ret = 1;
+ ctx = (BIO_ASN1_BUF_CTX *) b->ptr;
+ if (ctx == NULL)
+ return 0;
+ switch(cmd)
+ {
+
+ case BIO_C_SET_PREFIX:
+ ex_func = arg2;
+ ctx->prefix = ex_func->ex_func;
+ ctx->prefix_free = ex_func->ex_free_func;
+ break;
+
+ case BIO_C_GET_PREFIX:
+ ex_func = arg2;
+ ex_func->ex_func = ctx->prefix;
+ ex_func->ex_free_func = ctx->prefix_free;
+ break;
+
+ case BIO_C_SET_SUFFIX:
+ ex_func = arg2;
+ ctx->suffix = ex_func->ex_func;
+ ctx->suffix_free = ex_func->ex_free_func;
+ break;
+
+ case BIO_C_GET_SUFFIX:
+ ex_func = arg2;
+ ex_func->ex_func = ctx->suffix;
+ ex_func->ex_free_func = ctx->suffix_free;
+ break;
+
+ case BIO_C_SET_EX_ARG:
+ ctx->ex_arg = arg2;
+ break;
+
+ case BIO_C_GET_EX_ARG:
+ *(void **)arg2 = ctx->ex_arg;
+ break;
+
+ case BIO_CTRL_FLUSH:
+ if (!b->next_bio)
+ return 0;
+
+ /* Call post function if possible */
+ if (ctx->state == ASN1_STATE_HEADER)
+ {
+ if (!asn1_bio_setup_ex(b, ctx, ctx->suffix,
+ ASN1_STATE_POST_COPY, ASN1_STATE_DONE))
+ return 0;
+ }
+
+ if (ctx->state == ASN1_STATE_POST_COPY)
+ {
+ ret = asn1_bio_flush_ex(b, ctx, ctx->suffix_free,
+ ASN1_STATE_DONE);
+ if (ret <= 0)
+ return ret;
+ }
+
+ if (ctx->state == ASN1_STATE_DONE)
+ return BIO_ctrl(b->next_bio, cmd, arg1, arg2);
+ else
+ {
+ BIO_clear_retry_flags(b);
+ return 0;
+ }
+ break;
+
+
+ default:
+ if (!b->next_bio)
+ return 0;
+ return BIO_ctrl(b->next_bio, cmd, arg1, arg2);
+
+ }
+
+ return ret;
+ }
+
+static int asn1_bio_set_ex(BIO *b, int cmd,
+ asn1_ps_func *ex_func, asn1_ps_func *ex_free_func)
+ {
+ BIO_ASN1_EX_FUNCS extmp;
+ extmp.ex_func = ex_func;
+ extmp.ex_free_func = ex_free_func;
+ return BIO_ctrl(b, cmd, 0, &extmp);
+ }
+
+static int asn1_bio_get_ex(BIO *b, int cmd,
+ asn1_ps_func **ex_func, asn1_ps_func **ex_free_func)
+ {
+ BIO_ASN1_EX_FUNCS extmp;
+ int ret;
+ ret = BIO_ctrl(b, cmd, 0, &extmp);
+ if (ret > 0)
+ {
+ *ex_func = extmp.ex_func;
+ *ex_free_func = extmp.ex_free_func;
+ }
+ return ret;
+ }
+
+int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix, asn1_ps_func *prefix_free)
+ {
+ return asn1_bio_set_ex(b, BIO_C_SET_PREFIX, prefix, prefix_free);
+ }
+
+int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix, asn1_ps_func **pprefix_free)
+ {
+ return asn1_bio_get_ex(b, BIO_C_GET_PREFIX, pprefix, pprefix_free);
+ }
+
+int BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix, asn1_ps_func *suffix_free)
+ {
+ return asn1_bio_set_ex(b, BIO_C_SET_SUFFIX, suffix, suffix_free);
+ }
+
+int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix, asn1_ps_func **psuffix_free)
+ {
+ return asn1_bio_get_ex(b, BIO_C_GET_SUFFIX, psuffix, psuffix_free);
+ }
diff --git a/crypto/asn1/bio_ndef.c b/crypto/asn1/bio_ndef.c
new file mode 100644
index 0000000..c814814
--- /dev/null
+++ b/crypto/asn1/bio_ndef.c
@@ -0,0 +1,248 @@
+/* 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/asn1.h>
+
+#include <assert.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+/* Experimental NDEF ASN1 BIO support routines */
+
+/* The usage is quite simple, initialize an ASN1 structure,
+ * get a BIO from it then any data written through the BIO
+ * will end up translated to approptiate format on the fly.
+ * The data is streamed out and does *not* need to be
+ * all held in memory at once.
+ *
+ * When the BIO is flushed the output is finalized and any
+ * signatures etc written out.
+ *
+ * The BIO is a 'proper' BIO and can handle non blocking I/O
+ * correctly.
+ *
+ * The usage is simple. The implementation is *not*...
+ */
+
+/* BIO support data stored in the ASN1 BIO ex_arg */
+
+typedef struct ndef_aux_st
+ {
+ /* ASN1 structure this BIO refers to */
+ ASN1_VALUE *val;
+ const ASN1_ITEM *it;
+ /* Top of the BIO chain */
+ BIO *ndef_bio;
+ /* Output BIO */
+ BIO *out;
+ /* Boundary where content is inserted */
+ unsigned char **boundary;
+ /* DER buffer start */
+ unsigned char *derbuf;
+ } NDEF_SUPPORT;
+
+static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg);
+static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen, void *parg);
+static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg);
+static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen, void *parg);
+
+BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it)
+ {
+ NDEF_SUPPORT *ndef_aux = NULL;
+ BIO *asn_bio = NULL;
+ const ASN1_AUX *aux = it->funcs;
+ ASN1_STREAM_ARG sarg;
+
+ if (!aux || !aux->asn1_cb)
+ {
+ OPENSSL_PUT_ERROR(ASN1, BIO_new_NDEF, ASN1_R_STREAMING_NOT_SUPPORTED);
+ return NULL;
+ }
+ ndef_aux = OPENSSL_malloc(sizeof(NDEF_SUPPORT));
+ asn_bio = BIO_new(BIO_f_asn1());
+
+ /* ASN1 bio needs to be next to output BIO */
+
+ out = BIO_push(asn_bio, out);
+
+ if (!ndef_aux || !asn_bio || !out)
+ goto err;
+
+ BIO_asn1_set_prefix(asn_bio, ndef_prefix, ndef_prefix_free);
+ BIO_asn1_set_suffix(asn_bio, ndef_suffix, ndef_suffix_free);
+
+ /* Now let callback prepend any digest, cipher etc BIOs
+ * ASN1 structure needs.
+ */
+
+ sarg.out = out;
+ sarg.ndef_bio = NULL;
+ sarg.boundary = NULL;
+
+ if (aux->asn1_cb(ASN1_OP_STREAM_PRE, &val, it, &sarg) <= 0)
+ goto err;
+
+ ndef_aux->val = val;
+ ndef_aux->it = it;
+ ndef_aux->ndef_bio = sarg.ndef_bio;
+ ndef_aux->boundary = sarg.boundary;
+ ndef_aux->out = out;
+
+ BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux);
+
+ return sarg.ndef_bio;
+
+ err:
+ if (asn_bio)
+ BIO_free(asn_bio);
+ if (ndef_aux)
+ OPENSSL_free(ndef_aux);
+ return NULL;
+ }
+
+static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg)
+ {
+ NDEF_SUPPORT *ndef_aux;
+ unsigned char *p;
+ int derlen;
+
+ if (!parg)
+ return 0;
+
+ ndef_aux = *(NDEF_SUPPORT **)parg;
+
+ derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it);
+ p = OPENSSL_malloc(derlen);
+ ndef_aux->derbuf = p;
+ *pbuf = p;
+ derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
+
+ if (!*ndef_aux->boundary)
+ return 0;
+
+ *plen = *ndef_aux->boundary - *pbuf;
+
+ return 1;
+ }
+
+static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen, void *parg)
+ {
+ NDEF_SUPPORT *ndef_aux;
+
+ if (!parg)
+ return 0;
+
+ ndef_aux = *(NDEF_SUPPORT **)parg;
+
+ if (ndef_aux->derbuf)
+ OPENSSL_free(ndef_aux->derbuf);
+
+ ndef_aux->derbuf = NULL;
+ *pbuf = NULL;
+ *plen = 0;
+ return 1;
+ }
+
+static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen, void *parg)
+ {
+ NDEF_SUPPORT **pndef_aux = (NDEF_SUPPORT **)parg;
+ if (!ndef_prefix_free(b, pbuf, plen, parg))
+ return 0;
+ OPENSSL_free(*pndef_aux);
+ *pndef_aux = NULL;
+ return 1;
+ }
+
+static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg)
+ {
+ NDEF_SUPPORT *ndef_aux;
+ unsigned char *p;
+ int derlen;
+ const ASN1_AUX *aux;
+ ASN1_STREAM_ARG sarg;
+
+ if (!parg)
+ return 0;
+
+ ndef_aux = *(NDEF_SUPPORT **)parg;
+
+ aux = ndef_aux->it->funcs;
+
+ /* Finalize structures */
+ sarg.ndef_bio = ndef_aux->ndef_bio;
+ sarg.out = ndef_aux->out;
+ sarg.boundary = ndef_aux->boundary;
+ if (aux->asn1_cb(ASN1_OP_STREAM_POST,
+ &ndef_aux->val, ndef_aux->it, &sarg) <= 0)
+ return 0;
+
+ derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it);
+ p = OPENSSL_malloc(derlen);
+ ndef_aux->derbuf = p;
+ *pbuf = p;
+ derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
+
+ if (!*ndef_aux->boundary)
+ return 0;
+ *pbuf = *ndef_aux->boundary;
+ *plen = derlen - (*ndef_aux->boundary - ndef_aux->derbuf);
+
+ return 1;
+ }
diff --git a/crypto/asn1/charmap.pl b/crypto/asn1/charmap.pl
new file mode 100644
index 0000000..2875c59
--- /dev/null
+++ b/crypto/asn1/charmap.pl
@@ -0,0 +1,80 @@
+#!/usr/local/bin/perl -w
+
+use strict;
+
+my ($i, @arr);
+
+# Set up an array with the type of ASCII characters
+# Each set bit represents a character property.
+
+# RFC2253 character properties
+my $RFC2253_ESC = 1; # Character escaped with \
+my $ESC_CTRL = 2; # Escaped control character
+# These are used with RFC1779 quoting using "
+my $NOESC_QUOTE = 8; # Not escaped if quoted
+my $PSTRING_CHAR = 0x10; # Valid PrintableString character
+my $RFC2253_FIRST_ESC = 0x20; # Escaped with \ if first character
+my $RFC2253_LAST_ESC = 0x40; # Escaped with \ if last character
+
+for($i = 0; $i < 128; $i++) {
+ # Set the RFC2253 escape characters (control)
+ $arr[$i] = 0;
+ if(($i < 32) || ($i > 126)) {
+ $arr[$i] |= $ESC_CTRL;
+ }
+
+ # Some PrintableString characters
+ if( ( ( $i >= ord("a")) && ( $i <= ord("z")) )
+ || ( ( $i >= ord("A")) && ( $i <= ord("Z")) )
+ || ( ( $i >= ord("0")) && ( $i <= ord("9")) ) ) {
+ $arr[$i] |= $PSTRING_CHAR;
+ }
+}
+
+# Now setup the rest
+
+# Remaining RFC2253 escaped characters
+
+$arr[ord(" ")] |= $NOESC_QUOTE | $RFC2253_FIRST_ESC | $RFC2253_LAST_ESC;
+$arr[ord("#")] |= $NOESC_QUOTE | $RFC2253_FIRST_ESC;
+
+$arr[ord(",")] |= $NOESC_QUOTE | $RFC2253_ESC;
+$arr[ord("+")] |= $NOESC_QUOTE | $RFC2253_ESC;
+$arr[ord("\"")] |= $RFC2253_ESC;
+$arr[ord("\\")] |= $RFC2253_ESC;
+$arr[ord("<")] |= $NOESC_QUOTE | $RFC2253_ESC;
+$arr[ord(">")] |= $NOESC_QUOTE | $RFC2253_ESC;
+$arr[ord(";")] |= $NOESC_QUOTE | $RFC2253_ESC;
+
+# Remaining PrintableString characters
+
+$arr[ord(" ")] |= $PSTRING_CHAR;
+$arr[ord("'")] |= $PSTRING_CHAR;
+$arr[ord("(")] |= $PSTRING_CHAR;
+$arr[ord(")")] |= $PSTRING_CHAR;
+$arr[ord("+")] |= $PSTRING_CHAR;
+$arr[ord(",")] |= $PSTRING_CHAR;
+$arr[ord("-")] |= $PSTRING_CHAR;
+$arr[ord(".")] |= $PSTRING_CHAR;
+$arr[ord("/")] |= $PSTRING_CHAR;
+$arr[ord(":")] |= $PSTRING_CHAR;
+$arr[ord("=")] |= $PSTRING_CHAR;
+$arr[ord("?")] |= $PSTRING_CHAR;
+
+# Now generate the C code
+
+print <<EOF;
+/* Auto generated with chartype.pl script.
+ * Mask of various character properties
+ */
+
+static unsigned char char_type[] = {
+EOF
+
+for($i = 0; $i < 128; $i++) {
+ print("\n") if($i && (($i % 16) == 0));
+ printf("%2d", $arr[$i]);
+ print(",") if ($i != 127);
+}
+print("\n};\n\n");
+
diff --git a/crypto/asn1/f_enum.c b/crypto/asn1/f_enum.c
new file mode 100644
index 0000000..5725824
--- /dev/null
+++ b/crypto/asn1/f_enum.c
@@ -0,0 +1,205 @@
+/* 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/asn1.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+/* Based on a_int.c: equivalent ENUMERATED functions */
+
+int i2a_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *a)
+ {
+ int i,n=0;
+ static const char *h="0123456789ABCDEF";
+ char buf[2];
+
+ if (a == NULL) return(0);
+
+ if (a->length == 0)
+ {
+ if (BIO_write(bp,"00",2) != 2) goto err;
+ n=2;
+ }
+ else
+ {
+ for (i=0; i<a->length; i++)
+ {
+ if ((i != 0) && (i%35 == 0))
+ {
+ if (BIO_write(bp,"\\\n",2) != 2) goto err;
+ n+=2;
+ }
+ buf[0]=h[((unsigned char)a->data[i]>>4)&0x0f];
+ buf[1]=h[((unsigned char)a->data[i] )&0x0f];
+ if (BIO_write(bp,buf,2) != 2) goto err;
+ n+=2;
+ }
+ }
+ return(n);
+err:
+ return(-1);
+ }
+
+int a2i_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *bs, char *buf, int size)
+ {
+ int ret=0;
+ int i,j,k,m,n,again,bufsize;
+ unsigned char *s=NULL,*sp;
+ unsigned char *bufp;
+ int num=0,slen=0,first=1;
+
+ bs->type=V_ASN1_ENUMERATED;
+
+ bufsize=BIO_gets(bp,buf,size);
+ for (;;)
+ {
+ if (bufsize < 1) goto err_sl;
+ i=bufsize;
+ if (buf[i-1] == '\n') buf[--i]='\0';
+ if (i == 0) goto err_sl;
+ if (buf[i-1] == '\r') buf[--i]='\0';
+ if (i == 0) goto err_sl;
+ again=(buf[i-1] == '\\');
+
+ for (j=0; j<i; j++)
+ {
+ if (!( ((buf[j] >= '0') && (buf[j] <= '9')) ||
+ ((buf[j] >= 'a') && (buf[j] <= 'f')) ||
+ ((buf[j] >= 'A') && (buf[j] <= 'F'))))
+ {
+ i=j;
+ break;
+ }
+ }
+ buf[i]='\0';
+ /* We have now cleared all the crap off the end of the
+ * line */
+ if (i < 2) goto err_sl;
+
+ bufp=(unsigned char *)buf;
+ if (first)
+ {
+ first=0;
+ if ((bufp[0] == '0') && (buf[1] == '0'))
+ {
+ bufp+=2;
+ i-=2;
+ }
+ }
+ k=0;
+ i-=again;
+ if (i%2 != 0)
+ {
+ OPENSSL_PUT_ERROR(ASN1, a2i_ASN1_ENUMERATED, ASN1_R_ODD_NUMBER_OF_CHARS);
+ goto err;
+ }
+ i/=2;
+ if (num+i > slen)
+ {
+ if (s == NULL)
+ sp=(unsigned char *)OPENSSL_malloc(
+ (unsigned int)num+i*2);
+ else
+ sp=(unsigned char *)OPENSSL_realloc(s,
+ (unsigned int)num+i*2);
+ if (sp == NULL)
+ {
+ OPENSSL_PUT_ERROR(ASN1, a2i_ASN1_ENUMERATED, ERR_R_MALLOC_FAILURE);
+ if (s != NULL) OPENSSL_free(s);
+ goto err;
+ }
+ s=sp;
+ slen=num+i*2;
+ }
+ for (j=0; j<i; j++,k+=2)
+ {
+ for (n=0; n<2; n++)
+ {
+ m=bufp[k+n];
+ if ((m >= '0') && (m <= '9'))
+ m-='0';
+ else if ((m >= 'a') && (m <= 'f'))
+ m=m-'a'+10;
+ else if ((m >= 'A') && (m <= 'F'))
+ m=m-'A'+10;
+ else
+ {
+ OPENSSL_PUT_ERROR(ASN1, a2i_ASN1_ENUMERATED, ASN1_R_NON_HEX_CHARACTERS);
+ goto err;
+ }
+ s[num+j]<<=4;
+ s[num+j]|=m;
+ }
+ }
+ num+=i;
+ if (again)
+ bufsize=BIO_gets(bp,buf,size);
+ else
+ break;
+ }
+ bs->length=num;
+ bs->data=s;
+ ret=1;
+err:
+ if (0)
+ {
+err_sl:
+ OPENSSL_PUT_ERROR(ASN1, a2i_ASN1_ENUMERATED, ASN1_R_SHORT_LINE);
+ }
+ return(ret);
+ }
+
diff --git a/crypto/asn1/f_int.c b/crypto/asn1/f_int.c
new file mode 100644
index 0000000..d9ddcf8
--- /dev/null
+++ b/crypto/asn1/f_int.c
@@ -0,0 +1,218 @@
+/* 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/asn1.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+int i2a_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *a)
+ {
+ int i,n=0;
+ static const char *h="0123456789ABCDEF";
+ char buf[2];
+
+ if (a == NULL) return(0);
+
+ if (a->type & V_ASN1_NEG)
+ {
+ if (BIO_write(bp, "-", 1) != 1) goto err;
+ n = 1;
+ }
+
+ if (a->length == 0)
+ {
+ if (BIO_write(bp,"00",2) != 2) goto err;
+ n += 2;
+ }
+ else
+ {
+ for (i=0; i<a->length; i++)
+ {
+ if ((i != 0) && (i%35 == 0))
+ {
+ if (BIO_write(bp,"\\\n",2) != 2) goto err;
+ n+=2;
+ }
+ buf[0]=h[((unsigned char)a->data[i]>>4)&0x0f];
+ buf[1]=h[((unsigned char)a->data[i] )&0x0f];
+ if (BIO_write(bp,buf,2) != 2) goto err;
+ n+=2;
+ }
+ }
+ return(n);
+err:
+ return(-1);
+ }
+
+int a2i_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *bs, char *buf, int size)
+ {
+ int ret=0;
+ int i,j,k,m,n,again,bufsize;
+ unsigned char *s=NULL,*sp;
+ unsigned char *bufp;
+ int num=0,slen=0,first=1;
+
+ bs->type=V_ASN1_INTEGER;
+
+ bufsize=BIO_gets(bp,buf,size);
+ for (;;)
+ {
+ if (bufsize < 1) goto err_sl;
+ i=bufsize;
+ if (buf[i-1] == '\n') buf[--i]='\0';
+ if (i == 0) goto err_sl;
+ if (buf[i-1] == '\r') buf[--i]='\0';
+ if (i == 0) goto err_sl;
+ again=(buf[i-1] == '\\');
+
+ for (j=0; j<i; j++)
+ {
+#ifndef CHARSET_EBCDIC
+ if (!( ((buf[j] >= '0') && (buf[j] <= '9')) ||
+ ((buf[j] >= 'a') && (buf[j] <= 'f')) ||
+ ((buf[j] >= 'A') && (buf[j] <= 'F'))))
+#else
+ /* This #ifdef is not strictly necessary, since
+ * the characters A...F a...f 0...9 are contiguous
+ * (yes, even in EBCDIC - but not the whole alphabet).
+ * Nevertheless, isxdigit() is faster.
+ */
+ if (!isxdigit(buf[j]))
+#endif
+ {
+ i=j;
+ break;
+ }
+ }
+ buf[i]='\0';
+ /* We have now cleared all the crap off the end of the
+ * line */
+ if (i < 2) goto err_sl;
+
+ bufp=(unsigned char *)buf;
+ if (first)
+ {
+ first=0;
+ if ((bufp[0] == '0') && (buf[1] == '0'))
+ {
+ bufp+=2;
+ i-=2;
+ }
+ }
+ k=0;
+ i-=again;
+ if (i%2 != 0)
+ {
+ OPENSSL_PUT_ERROR(ASN1, a2i_ASN1_INTEGER, ASN1_R_ODD_NUMBER_OF_CHARS);
+ goto err;
+ }
+ i/=2;
+ if (num+i > slen)
+ {
+ if (s == NULL)
+ sp=(unsigned char *)OPENSSL_malloc(
+ (unsigned int)num+i*2);
+ else
+ sp=OPENSSL_realloc_clean(s,slen,num+i*2);
+ if (sp == NULL)
+ {
+ OPENSSL_PUT_ERROR(ASN1, a2i_ASN1_INTEGER, ERR_R_MALLOC_FAILURE);
+ if (s != NULL) OPENSSL_free(s);
+ goto err;
+ }
+ s=sp;
+ slen=num+i*2;
+ }
+ for (j=0; j<i; j++,k+=2)
+ {
+ for (n=0; n<2; n++)
+ {
+ m=bufp[k+n];
+ if ((m >= '0') && (m <= '9'))
+ m-='0';
+ else if ((m >= 'a') && (m <= 'f'))
+ m=m-'a'+10;
+ else if ((m >= 'A') && (m <= 'F'))
+ m=m-'A'+10;
+ else
+ {
+ OPENSSL_PUT_ERROR(ASN1, a2i_ASN1_INTEGER, ASN1_R_NON_HEX_CHARACTERS);
+ goto err;
+ }
+ s[num+j]<<=4;
+ s[num+j]|=m;
+ }
+ }
+ num+=i;
+ if (again)
+ bufsize=BIO_gets(bp,buf,size);
+ else
+ break;
+ }
+ bs->length=num;
+ bs->data=s;
+ ret=1;
+err:
+ if (0)
+ {
+err_sl:
+ OPENSSL_PUT_ERROR(ASN1, a2i_ASN1_INTEGER, ASN1_R_SHORT_LINE);
+ }
+ return(ret);
+ }
+
diff --git a/crypto/asn1/f_string.c b/crypto/asn1/f_string.c
new file mode 100644
index 0000000..95e59ff
--- /dev/null
+++ b/crypto/asn1/f_string.c
@@ -0,0 +1,212 @@
+/* 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/asn1.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+
+int i2a_ASN1_STRING(BIO *bp, ASN1_STRING *a, int type)
+ {
+ int i,n=0;
+ static const char *h="0123456789ABCDEF";
+ char buf[2];
+
+ if (a == NULL) return(0);
+
+ if (a->length == 0)
+ {
+ if (BIO_write(bp,"0",1) != 1) goto err;
+ n=1;
+ }
+ else
+ {
+ for (i=0; i<a->length; i++)
+ {
+ if ((i != 0) && (i%35 == 0))
+ {
+ if (BIO_write(bp,"\\\n",2) != 2) goto err;
+ n+=2;
+ }
+ buf[0]=h[((unsigned char)a->data[i]>>4)&0x0f];
+ buf[1]=h[((unsigned char)a->data[i] )&0x0f];
+ if (BIO_write(bp,buf,2) != 2) goto err;
+ n+=2;
+ }
+ }
+ return(n);
+err:
+ return(-1);
+ }
+
+int a2i_ASN1_STRING(BIO *bp, ASN1_STRING *bs, char *buf, int size)
+ {
+ int ret=0;
+ int i,j,k,m,n,again,bufsize;
+ unsigned char *s=NULL,*sp;
+ unsigned char *bufp;
+ int num=0,slen=0,first=1;
+
+ bufsize=BIO_gets(bp,buf,size);
+ for (;;)
+ {
+ if (bufsize < 1)
+ {
+ if (first)
+ break;
+ else
+ goto err_sl;
+ }
+ first=0;
+
+ i=bufsize;
+ if (buf[i-1] == '\n') buf[--i]='\0';
+ if (i == 0) goto err_sl;
+ if (buf[i-1] == '\r') buf[--i]='\0';
+ if (i == 0) goto err_sl;
+ again=(buf[i-1] == '\\');
+
+ for (j=i-1; j>0; j--)
+ {
+#ifndef CHARSET_EBCDIC
+ if (!( ((buf[j] >= '0') && (buf[j] <= '9')) ||
+ ((buf[j] >= 'a') && (buf[j] <= 'f')) ||
+ ((buf[j] >= 'A') && (buf[j] <= 'F'))))
+#else
+ /* This #ifdef is not strictly necessary, since
+ * the characters A...F a...f 0...9 are contiguous
+ * (yes, even in EBCDIC - but not the whole alphabet).
+ * Nevertheless, isxdigit() is faster.
+ */
+ if (!isxdigit(buf[j]))
+#endif
+ {
+ i=j;
+ break;
+ }
+ }
+ buf[i]='\0';
+ /* We have now cleared all the crap off the end of the
+ * line */
+ if (i < 2) goto err_sl;
+
+ bufp=(unsigned char *)buf;
+
+ k=0;
+ i-=again;
+ if (i%2 != 0)
+ {
+ OPENSSL_PUT_ERROR(ASN1, a2i_ASN1_STRING, ASN1_R_ODD_NUMBER_OF_CHARS);
+ goto err;
+ }
+ i/=2;
+ if (num+i > slen)
+ {
+ if (s == NULL)
+ sp=(unsigned char *)OPENSSL_malloc(
+ (unsigned int)num+i*2);
+ else
+ sp=(unsigned char *)OPENSSL_realloc(s,
+ (unsigned int)num+i*2);
+ if (sp == NULL)
+ {
+ OPENSSL_PUT_ERROR(ASN1, a2i_ASN1_STRING, ERR_R_MALLOC_FAILURE);
+ if (s != NULL) OPENSSL_free(s);
+ goto err;
+ }
+ s=sp;
+ slen=num+i*2;
+ }
+ for (j=0; j<i; j++,k+=2)
+ {
+ for (n=0; n<2; n++)
+ {
+ m=bufp[k+n];
+ if ((m >= '0') && (m <= '9'))
+ m-='0';
+ else if ((m >= 'a') && (m <= 'f'))
+ m=m-'a'+10;
+ else if ((m >= 'A') && (m <= 'F'))
+ m=m-'A'+10;
+ else
+ {
+ OPENSSL_PUT_ERROR(ASN1, a2i_ASN1_STRING, ASN1_R_NON_HEX_CHARACTERS);
+ goto err;
+ }
+ s[num+j]<<=4;
+ s[num+j]|=m;
+ }
+ }
+ num+=i;
+ if (again)
+ bufsize=BIO_gets(bp,buf,size);
+ else
+ break;
+ }
+ bs->length=num;
+ bs->data=s;
+ ret=1;
+err:
+ if (0)
+ {
+err_sl:
+ OPENSSL_PUT_ERROR(ASN1, a2i_ASN1_STRING, ASN1_R_SHORT_LINE);
+ }
+ return(ret);
+ }
+
diff --git a/crypto/asn1/t_bitst.c b/crypto/asn1/t_bitst.c
new file mode 100644
index 0000000..cc2c50b
--- /dev/null
+++ b/crypto/asn1/t_bitst.c
@@ -0,0 +1,100 @@
+/* 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/asn1.h>
+
+#include <openssl/mem.h>
+
+
+int ASN1_BIT_STRING_name_print(BIO *out, ASN1_BIT_STRING *bs,
+ BIT_STRING_BITNAME *tbl, int indent)
+{
+ BIT_STRING_BITNAME *bnam;
+ char first = 1;
+ BIO_printf(out, "%*s", indent, "");
+ for(bnam = tbl; bnam->lname; bnam++) {
+ if(ASN1_BIT_STRING_get_bit(bs, bnam->bitnum)) {
+ if(!first) BIO_puts(out, ", ");
+ BIO_puts(out, bnam->lname);
+ first = 0;
+ }
+ }
+ BIO_puts(out, "\n");
+ return 1;
+}
+
+int ASN1_BIT_STRING_set_asc(ASN1_BIT_STRING *bs, char *name, int value,
+ BIT_STRING_BITNAME *tbl)
+{
+ int bitnum;
+ bitnum = ASN1_BIT_STRING_num_asc(name, tbl);
+ if(bitnum < 0) return 0;
+ if(bs) {
+ if(!ASN1_BIT_STRING_set_bit(bs, bitnum, value))
+ return 0;
+ }
+ return 1;
+}
+
+int ASN1_BIT_STRING_num_asc(char *name, BIT_STRING_BITNAME *tbl)
+{
+ BIT_STRING_BITNAME *bnam;
+ for(bnam = tbl; bnam->lname; bnam++) {
+ if(!strcmp(bnam->sname, name) ||
+ !strcmp(bnam->lname, name) ) return bnam->bitnum;
+ }
+ return -1;
+}
diff --git a/crypto/asn1/t_pkey.c b/crypto/asn1/t_pkey.c
new file mode 100644
index 0000000..6ac9b3d
--- /dev/null
+++ b/crypto/asn1/t_pkey.c
@@ -0,0 +1,112 @@
+/* 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/asn1.h>
+
+#include <openssl/bio.h>
+#include <openssl/mem.h>
+
+
+int ASN1_bn_print(BIO *bp, const char *number, const BIGNUM *num,
+ unsigned char *buf, int off)
+ {
+ int n,i;
+ const char *neg;
+
+ if (num == NULL) return(1);
+ neg = (BN_is_negative(num))?"-":"";
+ if(!BIO_indent(bp,off,128))
+ return 0;
+ if (BN_is_zero(num))
+ {
+ if (BIO_printf(bp, "%s 0\n", number) <= 0)
+ return 0;
+ return 1;
+ }
+
+ if (BN_num_bytes(num) <= sizeof(long))
+ {
+ if (BIO_printf(bp,"%s %s%lu (%s0x%lx)\n",number,neg,
+ (unsigned long)num->d[0],neg,(unsigned long)num->d[0])
+ <= 0) return(0);
+ }
+ else
+ {
+ buf[0]=0;
+ if (BIO_printf(bp,"%s%s",number,
+ (neg[0] == '-')?" (Negative)":"") <= 0)
+ return(0);
+ n=BN_bn2bin(num,&buf[1]);
+
+ if (buf[1] & 0x80)
+ n++;
+ else buf++;
+
+ for (i=0; i<n; i++)
+ {
+ if ((i%15) == 0)
+ {
+ if(BIO_puts(bp,"\n") <= 0
+ || !BIO_indent(bp,off+4,128))
+ return 0;
+ }
+ if (BIO_printf(bp,"%02x%s",buf[i],((i+1) == n)?"":":")
+ <= 0) return(0);
+ }
+ if (BIO_write(bp,"\n",1) <= 0) return(0);
+ }
+ return(1);
+ }
diff --git a/crypto/asn1/tasn_dec.c b/crypto/asn1/tasn_dec.c
new file mode 100644
index 0000000..80c8b7d
--- /dev/null
+++ b/crypto/asn1/tasn_dec.c
@@ -0,0 +1,1303 @@
+/* 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/asn1.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+static int asn1_check_eoc(const unsigned char **in, long len);
+static int asn1_find_end(const unsigned char **in, long len, char inf);
+
+static int asn1_collect(BUF_MEM *buf, const unsigned char **in, long len,
+ char inf, int tag, int aclass, int depth);
+
+static int collect_data(BUF_MEM *buf, const unsigned char **p, long plen);
+
+static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass,
+ char *inf, char *cst,
+ const unsigned char **in, long len,
+ int exptag, int expclass, char opt,
+ ASN1_TLC *ctx);
+
+static int asn1_template_ex_d2i(ASN1_VALUE **pval,
+ const unsigned char **in, long len,
+ const ASN1_TEMPLATE *tt, char opt,
+ ASN1_TLC *ctx);
+static int asn1_template_noexp_d2i(ASN1_VALUE **val,
+ const unsigned char **in, long len,
+ const ASN1_TEMPLATE *tt, char opt,
+ ASN1_TLC *ctx);
+static int asn1_d2i_ex_primitive(ASN1_VALUE **pval,
+ const unsigned char **in, long len,
+ const ASN1_ITEM *it,
+ int tag, int aclass, char opt, ASN1_TLC *ctx);
+
+/* Table to convert tags to bit values, used for MSTRING type */
+static const unsigned long tag2bit[32] = {
+0, 0, 0, B_ASN1_BIT_STRING, /* tags 0 - 3 */
+B_ASN1_OCTET_STRING, 0, 0, B_ASN1_UNKNOWN,/* tags 4- 7 */
+B_ASN1_UNKNOWN, B_ASN1_UNKNOWN, B_ASN1_UNKNOWN, B_ASN1_UNKNOWN,/* tags 8-11 */
+B_ASN1_UTF8STRING,B_ASN1_UNKNOWN,B_ASN1_UNKNOWN,B_ASN1_UNKNOWN,/* tags 12-15 */
+B_ASN1_SEQUENCE,0,B_ASN1_NUMERICSTRING,B_ASN1_PRINTABLESTRING, /* tags 16-19 */
+B_ASN1_T61STRING,B_ASN1_VIDEOTEXSTRING,B_ASN1_IA5STRING, /* tags 20-22 */
+B_ASN1_UTCTIME, B_ASN1_GENERALIZEDTIME, /* tags 23-24 */
+B_ASN1_GRAPHICSTRING,B_ASN1_ISO64STRING,B_ASN1_GENERALSTRING, /* tags 25-27 */
+B_ASN1_UNIVERSALSTRING,B_ASN1_UNKNOWN,B_ASN1_BMPSTRING,B_ASN1_UNKNOWN, /* tags 28-31 */
+ };
+
+unsigned long ASN1_tag2bit(int tag)
+ {
+ if ((tag < 0) || (tag > 30)) return 0;
+ return tag2bit[tag];
+ }
+
+/* Macro to initialize and invalidate the cache */
+
+#define asn1_tlc_clear(c) if (c) (c)->valid = 0
+/* Version to avoid compiler warning about 'c' always non-NULL */
+#define asn1_tlc_clear_nc(c) (c)->valid = 0
+
+/* Decode an ASN1 item, this currently behaves just
+ * like a standard 'd2i' function. 'in' points to
+ * a buffer to read the data from, in future we will
+ * have more advanced versions that can input data
+ * a piece at a time and this will simply be a special
+ * case.
+ */
+
+ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **pval,
+ const unsigned char **in, long len, const ASN1_ITEM *it)
+ {
+ ASN1_TLC c;
+ ASN1_VALUE *ptmpval = NULL;
+ if (!pval)
+ pval = &ptmpval;
+ asn1_tlc_clear_nc(&c);
+ if (ASN1_item_ex_d2i(pval, in, len, it, -1, 0, 0, &c) > 0)
+ return *pval;
+ return NULL;
+ }
+
+int ASN1_template_d2i(ASN1_VALUE **pval,
+ const unsigned char **in, long len, const ASN1_TEMPLATE *tt)
+ {
+ ASN1_TLC c;
+ asn1_tlc_clear_nc(&c);
+ return asn1_template_ex_d2i(pval, in, len, tt, 0, &c);
+ }
+
+
+/* Decode an item, taking care of IMPLICIT tagging, if any.
+ * If 'opt' set and tag mismatch return -1 to handle OPTIONAL
+ */
+
+int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
+ const ASN1_ITEM *it,
+ int tag, int aclass, char opt, ASN1_TLC *ctx)
+ {
+ const ASN1_TEMPLATE *tt, *errtt = NULL;
+ const ASN1_COMPAT_FUNCS *cf;
+ const ASN1_EXTERN_FUNCS *ef;
+ const ASN1_AUX *aux = it->funcs;
+ ASN1_aux_cb *asn1_cb;
+ const unsigned char *p = NULL, *q;
+ unsigned char *wp=NULL; /* BIG FAT WARNING! BREAKS CONST WHERE USED */
+ unsigned char imphack = 0, oclass;
+ char seq_eoc, seq_nolen, cst, isopt;
+ long tmplen;
+ int i;
+ int otag;
+ int ret = 0;
+ ASN1_VALUE **pchptr, *ptmpval;
+ if (!pval)
+ return 0;
+ if (aux && aux->asn1_cb)
+ asn1_cb = aux->asn1_cb;
+ else asn1_cb = 0;
+
+ switch(it->itype)
+ {
+ case ASN1_ITYPE_PRIMITIVE:
+ if (it->templates)
+ {
+ /* tagging or OPTIONAL is currently illegal on an item
+ * template because the flags can't get passed down.
+ * In practice this isn't a problem: we include the
+ * relevant flags from the item template in the
+ * template itself.
+ */
+ if ((tag != -1) || opt)
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i, ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE);
+ goto err;
+ }
+ return asn1_template_ex_d2i(pval, in, len,
+ it->templates, opt, ctx);
+ }
+ return asn1_d2i_ex_primitive(pval, in, len, it,
+ tag, aclass, opt, ctx);
+ break;
+
+ case ASN1_ITYPE_MSTRING:
+ p = *in;
+ /* Just read in tag and class */
+ ret = asn1_check_tlen(NULL, &otag, &oclass, NULL, NULL,
+ &p, len, -1, 0, 1, ctx);
+ if (!ret)
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i, ASN1_R_NESTED_ASN1_ERROR);
+ goto err;
+ }
+
+ /* Must be UNIVERSAL class */
+ if (oclass != V_ASN1_UNIVERSAL)
+ {
+ /* If OPTIONAL, assume this is OK */
+ if (opt) return -1;
+ OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i, ASN1_R_MSTRING_NOT_UNIVERSAL);
+ goto err;
+ }
+ /* Check tag matches bit map */
+ if (!(ASN1_tag2bit(otag) & it->utype))
+ {
+ /* If OPTIONAL, assume this is OK */
+ if (opt)
+ return -1;
+ OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i, ASN1_R_MSTRING_WRONG_TAG);
+ goto err;
+ }
+ return asn1_d2i_ex_primitive(pval, in, len,
+ it, otag, 0, 0, ctx);
+
+ case ASN1_ITYPE_EXTERN:
+ /* Use new style d2i */
+ ef = it->funcs;
+ return ef->asn1_ex_d2i(pval, in, len,
+ it, tag, aclass, opt, ctx);
+
+ case ASN1_ITYPE_COMPAT:
+ /* we must resort to old style evil hackery */
+ cf = it->funcs;
+
+ /* If OPTIONAL see if it is there */
+ if (opt)
+ {
+ int exptag;
+ p = *in;
+ if (tag == -1)
+ exptag = it->utype;
+ else exptag = tag;
+ /* Don't care about anything other than presence
+ * of expected tag */
+
+ ret = asn1_check_tlen(NULL, NULL, NULL, NULL, NULL,
+ &p, len, exptag, aclass, 1, ctx);
+ if (!ret)
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i, ASN1_R_NESTED_ASN1_ERROR);
+ goto err;
+ }
+ if (ret == -1)
+ return -1;
+ }
+
+ /* This is the old style evil hack IMPLICIT handling:
+ * since the underlying code is expecting a tag and
+ * class other than the one present we change the
+ * buffer temporarily then change it back afterwards.
+ * This doesn't and never did work for tags > 30.
+ *
+ * Yes this is *horrible* but it is only needed for
+ * old style d2i which will hopefully not be around
+ * for much longer.
+ * FIXME: should copy the buffer then modify it so
+ * the input buffer can be const: we should *always*
+ * copy because the old style d2i might modify the
+ * buffer.
+ */
+
+ if (tag != -1)
+ {
+ wp = *(unsigned char **)in;
+ imphack = *wp;
+ if (p == NULL)
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i, ASN1_R_NESTED_ASN1_ERROR);
+ goto err;
+ }
+ *wp = (unsigned char)((*p & V_ASN1_CONSTRUCTED)
+ | it->utype);
+ }
+
+ ptmpval = cf->asn1_d2i(pval, in, len);
+
+ if (tag != -1)
+ *wp = imphack;
+
+ if (ptmpval)
+ return 1;
+
+ OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i, ASN1_R_NESTED_ASN1_ERROR);
+ goto err;
+
+
+ case ASN1_ITYPE_CHOICE:
+ if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it, NULL))
+ goto auxerr;
+
+ /* Allocate structure */
+ if (!*pval && !ASN1_item_ex_new(pval, it))
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i, ASN1_R_NESTED_ASN1_ERROR);
+ goto err;
+ }
+ /* CHOICE type, try each possibility in turn */
+ p = *in;
+ for (i = 0, tt=it->templates; i < it->tcount; i++, tt++)
+ {
+ pchptr = asn1_get_field_ptr(pval, tt);
+ /* We mark field as OPTIONAL so its absence
+ * can be recognised.
+ */
+ ret = asn1_template_ex_d2i(pchptr, &p, len, tt, 1, ctx);
+ /* If field not present, try the next one */
+ if (ret == -1)
+ continue;
+ /* If positive return, read OK, break loop */
+ if (ret > 0)
+ break;
+ /* Otherwise must be an ASN1 parsing error */
+ errtt = tt;
+ OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i, ASN1_R_NESTED_ASN1_ERROR);
+ goto err;
+ }
+
+ /* Did we fall off the end without reading anything? */
+ if (i == it->tcount)
+ {
+ /* If OPTIONAL, this is OK */
+ if (opt)
+ {
+ /* Free and zero it */
+ ASN1_item_ex_free(pval, it);
+ return -1;
+ }
+ OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i, ASN1_R_NO_MATCHING_CHOICE_TYPE);
+ goto err;
+ }
+
+ asn1_set_choice_selector(pval, i, it);
+ *in = p;
+ if (asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it, NULL))
+ goto auxerr;
+ return 1;
+
+ case ASN1_ITYPE_NDEF_SEQUENCE:
+ case ASN1_ITYPE_SEQUENCE:
+ p = *in;
+ tmplen = len;
+
+ /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */
+ if (tag == -1)
+ {
+ tag = V_ASN1_SEQUENCE;
+ aclass = V_ASN1_UNIVERSAL;
+ }
+ /* Get SEQUENCE length and update len, p */
+ ret = asn1_check_tlen(&len, NULL, NULL, &seq_eoc, &cst,
+ &p, len, tag, aclass, opt, ctx);
+ if (!ret)
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i, ASN1_R_NESTED_ASN1_ERROR);
+ goto err;
+ }
+ else if (ret == -1)
+ return -1;
+ if (aux && (aux->flags & ASN1_AFLG_BROKEN))
+ {
+ len = tmplen - (p - *in);
+ seq_nolen = 1;
+ }
+ /* If indefinite we don't do a length check */
+ else seq_nolen = seq_eoc;
+ if (!cst)
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i, 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);
+ goto err;
+ }
+
+ if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it, NULL))
+ goto auxerr;
+
+ /* Get each field entry */
+ for (i = 0, tt = it->templates; i < it->tcount; i++, tt++)
+ {
+ const ASN1_TEMPLATE *seqtt;
+ ASN1_VALUE **pseqval;
+ seqtt = asn1_do_adb(pval, tt, 1);
+ if (!seqtt)
+ goto err;
+ pseqval = asn1_get_field_ptr(pval, seqtt);
+ /* Have we ran out of data? */
+ if (!len)
+ break;
+ q = p;
+ if (asn1_check_eoc(&p, len))
+ {
+ if (!seq_eoc)
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i, ASN1_R_UNEXPECTED_EOC);
+ goto err;
+ }
+ len -= p - q;
+ seq_eoc = 0;
+ q = p;
+ break;
+ }
+ /* This determines the OPTIONAL flag value. The field
+ * cannot be omitted if it is the last of a SEQUENCE
+ * and there is still data to be read. This isn't
+ * strictly necessary but it increases efficiency in
+ * some cases.
+ */
+ if (i == (it->tcount - 1))
+ isopt = 0;
+ else isopt = (char)(seqtt->flags & ASN1_TFLG_OPTIONAL);
+ /* attempt to read in field, allowing each to be
+ * OPTIONAL */
+
+ ret = asn1_template_ex_d2i(pseqval, &p, len,
+ seqtt, isopt, ctx);
+ if (!ret)
+ {
+ errtt = seqtt;
+ goto err;
+ }
+ else if (ret == -1)
+ {
+ /* OPTIONAL component absent.
+ * Free and zero the field.
+ */
+ ASN1_template_free(pseqval, seqtt);
+ continue;
+ }
+ /* Update length */
+ len -= p - q;
+ }
+
+ /* 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);
+ goto err;
+ }
+ /* Check all data read */
+ if (!seq_nolen && len)
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i, ASN1_R_SEQUENCE_LENGTH_MISMATCH);
+ goto err;
+ }
+
+ /* If we get here we've got no more data in the SEQUENCE,
+ * however we may not have read all fields so check all
+ * remaining are OPTIONAL and clear any that are.
+ */
+ for (; i < it->tcount; tt++, i++)
+ {
+ const ASN1_TEMPLATE *seqtt;
+ seqtt = asn1_do_adb(pval, tt, 1);
+ if (!seqtt)
+ goto err;
+ if (seqtt->flags & ASN1_TFLG_OPTIONAL)
+ {
+ ASN1_VALUE **pseqval;
+ pseqval = asn1_get_field_ptr(pval, seqtt);
+ ASN1_template_free(pseqval, seqtt);
+ }
+ else
+ {
+ errtt = seqtt;
+ OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i, ASN1_R_FIELD_MISSING);
+ goto err;
+ }
+ }
+ /* Save encoding */
+ if (!asn1_enc_save(pval, *in, p - *in, it))
+ goto auxerr;
+ *in = p;
+ if (asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it, NULL))
+ goto auxerr;
+ return 1;
+
+ default:
+ return 0;
+ }
+ auxerr:
+ OPENSSL_PUT_ERROR(ASN1, ASN1_item_ex_d2i, ASN1_R_AUX_ERROR);
+ err:
+ ASN1_item_ex_free(pval, it);
+ if (errtt)
+ ERR_add_error_data(4, "Field=", errtt->field_name,
+ ", Type=", it->sname);
+ else
+ ERR_add_error_data(2, "Type=", it->sname);
+ return 0;
+ }
+
+/* Templates are handled with two separate functions.
+ * One handles any EXPLICIT tag and the other handles the rest.
+ */
+
+static int asn1_template_ex_d2i(ASN1_VALUE **val,
+ const unsigned char **in, long inlen,
+ const ASN1_TEMPLATE *tt, char opt,
+ ASN1_TLC *ctx)
+ {
+ int flags, aclass;
+ int ret;
+ long len;
+ const unsigned char *p, *q;
+ char exp_eoc;
+ if (!val)
+ return 0;
+ flags = tt->flags;
+ aclass = flags & ASN1_TFLG_TAG_CLASS;
+
+ p = *in;
+
+ /* Check if EXPLICIT tag expected */
+ if (flags & ASN1_TFLG_EXPTAG)
+ {
+ char cst;
+ /* Need to work out amount of data available to the inner
+ * content and where it starts: so read in EXPLICIT header to
+ * get the info.
+ */
+ ret = asn1_check_tlen(&len, NULL, NULL, &exp_eoc, &cst,
+ &p, inlen, tt->tag, aclass, opt, ctx);
+ q = p;
+ if (!ret)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_template_ex_d2i, 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);
+ 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);
+ return 0;
+ }
+ /* We read the field in OK so update length */
+ len -= p - q;
+ if (exp_eoc)
+ {
+ /* 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);
+ goto err;
+ }
+ }
+ else
+ {
+ /* Otherwise we must hit the EXPLICIT tag end or its
+ * an error */
+ if (len)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_template_ex_d2i, ASN1_R_EXPLICIT_LENGTH_MISMATCH);
+ goto err;
+ }
+ }
+ }
+ else
+ return asn1_template_noexp_d2i(val, in, inlen,
+ tt, opt, ctx);
+
+ *in = p;
+ return 1;
+
+ err:
+ ASN1_template_free(val, tt);
+ return 0;
+ }
+
+static int asn1_template_noexp_d2i(ASN1_VALUE **val,
+ const unsigned char **in, long len,
+ const ASN1_TEMPLATE *tt, char opt,
+ ASN1_TLC *ctx)
+ {
+ int flags, aclass;
+ int ret;
+ const unsigned char *p, *q;
+ if (!val)
+ return 0;
+ flags = tt->flags;
+ aclass = flags & ASN1_TFLG_TAG_CLASS;
+
+ p = *in;
+ q = p;
+
+ if (flags & ASN1_TFLG_SK_MASK)
+ {
+ /* SET OF, SEQUENCE OF */
+ int sktag, skaclass;
+ char sk_eoc;
+ /* First work out expected inner tag value */
+ if (flags & ASN1_TFLG_IMPTAG)
+ {
+ sktag = tt->tag;
+ skaclass = aclass;
+ }
+ else
+ {
+ skaclass = V_ASN1_UNIVERSAL;
+ if (flags & ASN1_TFLG_SET_OF)
+ sktag = V_ASN1_SET;
+ else
+ sktag = V_ASN1_SEQUENCE;
+ }
+ /* Get the tag */
+ ret = asn1_check_tlen(&len, NULL, NULL, &sk_eoc, NULL,
+ &p, len, sktag, skaclass, opt, ctx);
+ if (!ret)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_template_noexp_d2i, ASN1_R_NESTED_ASN1_ERROR);
+ return 0;
+ }
+ else if (ret == -1)
+ return -1;
+ if (!*val)
+ *val = (ASN1_VALUE *)sk_new_null();
+ else
+ {
+ /* We've got a valid STACK: free up any items present */
+ STACK_OF(ASN1_VALUE) *sktmp
+ = (STACK_OF(ASN1_VALUE) *)*val;
+ ASN1_VALUE *vtmp;
+ while(sk_ASN1_VALUE_num(sktmp) > 0)
+ {
+ vtmp = sk_ASN1_VALUE_pop(sktmp);
+ ASN1_item_ex_free(&vtmp,
+ ASN1_ITEM_ptr(tt->item));
+ }
+ }
+
+ if (!*val)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_template_noexp_d2i, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* Read as many items as we can */
+ while(len > 0)
+ {
+ ASN1_VALUE *skfield;
+ q = p;
+ /* See if EOC found */
+ if (asn1_check_eoc(&p, len))
+ {
+ if (!sk_eoc)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_template_noexp_d2i, ASN1_R_UNEXPECTED_EOC);
+ goto err;
+ }
+ len -= p - q;
+ sk_eoc = 0;
+ break;
+ }
+ skfield = NULL;
+ if (!ASN1_item_ex_d2i(&skfield, &p, len,
+ ASN1_ITEM_ptr(tt->item),
+ -1, 0, 0, ctx))
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_template_noexp_d2i, 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);
+ goto err;
+ }
+ }
+ if (sk_eoc)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_template_noexp_d2i, ASN1_R_MISSING_EOC);
+ goto err;
+ }
+ }
+ else if (flags & ASN1_TFLG_IMPTAG)
+ {
+ /* IMPLICIT tagging */
+ ret = ASN1_item_ex_d2i(val, &p, len,
+ 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);
+ goto err;
+ }
+ else if (ret == -1)
+ return -1;
+ }
+ else
+ {
+ /* Nothing special */
+ ret = ASN1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item),
+ -1, 0, opt, ctx);
+ if (!ret)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_template_noexp_d2i, ASN1_R_NESTED_ASN1_ERROR);
+ goto err;
+ }
+ else if (ret == -1)
+ return -1;
+ }
+
+ *in = p;
+ return 1;
+
+ err:
+ ASN1_template_free(val, tt);
+ return 0;
+ }
+
+static int asn1_d2i_ex_primitive(ASN1_VALUE **pval,
+ const unsigned char **in, long inlen,
+ const ASN1_ITEM *it,
+ int tag, int aclass, char opt, ASN1_TLC *ctx)
+ {
+ int ret = 0, utype;
+ long plen;
+ char cst, inf, free_cont = 0;
+ const unsigned char *p;
+ BUF_MEM buf;
+ const unsigned char *cont = NULL;
+ long len;
+ if (!pval)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_d2i_ex_primitive, ASN1_R_ILLEGAL_NULL);
+ return 0; /* Should never happen */
+ }
+
+ if (it->itype == ASN1_ITYPE_MSTRING)
+ {
+ utype = tag;
+ tag = -1;
+ }
+ else
+ utype = it->utype;
+
+ if (utype == V_ASN1_ANY)
+ {
+ /* If type is ANY need to figure out type from tag */
+ unsigned char oclass;
+ if (tag >= 0)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_d2i_ex_primitive, ASN1_R_ILLEGAL_TAGGED_ANY);
+ return 0;
+ }
+ if (opt)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_d2i_ex_primitive, ASN1_R_ILLEGAL_OPTIONAL_ANY);
+ return 0;
+ }
+ p = *in;
+ ret = asn1_check_tlen(NULL, &utype, &oclass, NULL, NULL,
+ &p, inlen, -1, 0, 0, ctx);
+ if (!ret)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_d2i_ex_primitive, ASN1_R_NESTED_ASN1_ERROR);
+ return 0;
+ }
+ if (oclass != V_ASN1_UNIVERSAL)
+ utype = V_ASN1_OTHER;
+ }
+ if (tag == -1)
+ {
+ tag = utype;
+ aclass = V_ASN1_UNIVERSAL;
+ }
+ p = *in;
+ /* Check header */
+ ret = asn1_check_tlen(&plen, NULL, NULL, &inf, &cst,
+ &p, inlen, tag, aclass, opt, ctx);
+ if (!ret)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_d2i_ex_primitive, ASN1_R_NESTED_ASN1_ERROR);
+ return 0;
+ }
+ else if (ret == -1)
+ return -1;
+ ret = 0;
+ /* SEQUENCE, SET and "OTHER" are left in encoded form */
+ if ((utype == V_ASN1_SEQUENCE)
+ || (utype == V_ASN1_SET) || (utype == V_ASN1_OTHER))
+ {
+ /* Clear context cache for type OTHER because the auto clear
+ * when we have a exact match wont work
+ */
+ if (utype == V_ASN1_OTHER)
+ {
+ asn1_tlc_clear(ctx);
+ }
+ /* SEQUENCE and SET must be constructed */
+ else if (!cst)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_d2i_ex_primitive, ASN1_R_TYPE_NOT_CONSTRUCTED);
+ return 0;
+ }
+
+ cont = *in;
+ /* If indefinite length constructed find the real end */
+ if (inf)
+ {
+ if (!asn1_find_end(&p, plen, inf))
+ goto err;
+ len = p - cont;
+ }
+ else
+ {
+ len = p - cont + plen;
+ p += plen;
+ buf.data = NULL;
+ }
+ }
+ else if (cst)
+ {
+ buf.length = 0;
+ buf.max = 0;
+ buf.data = NULL;
+ /* Should really check the internal tags are correct but
+ * some things may get this wrong. The relevant specs
+ * say that constructed string types should be OCTET STRINGs
+ * internally irrespective of the type. So instead just check
+ * for UNIVERSAL class and ignore the tag.
+ */
+ if (!asn1_collect(&buf, &p, plen, inf, -1, V_ASN1_UNIVERSAL, 0))
+ {
+ free_cont = 1;
+ goto err;
+ }
+ len = buf.length;
+ /* 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);
+ return 0;
+ }
+ buf.data[len] = 0;
+ cont = (const unsigned char *)buf.data;
+ free_cont = 1;
+ }
+ else
+ {
+ cont = p;
+ len = plen;
+ p += plen;
+ }
+
+ /* We now have content length and type: translate into a structure */
+ if (!asn1_ex_c2i(pval, cont, len, utype, &free_cont, it))
+ goto err;
+
+ *in = p;
+ ret = 1;
+ err:
+ if (free_cont && buf.data) OPENSSL_free(buf.data);
+ return ret;
+ }
+
+/* Translate ASN1 content octets into a structure */
+
+int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
+ int utype, char *free_cont, const ASN1_ITEM *it)
+ {
+ ASN1_VALUE **opval = NULL;
+ ASN1_STRING *stmp;
+ ASN1_TYPE *typ = NULL;
+ int ret = 0;
+ const ASN1_PRIMITIVE_FUNCS *pf;
+ ASN1_INTEGER **tint;
+ pf = it->funcs;
+
+ if (pf && pf->prim_c2i)
+ return pf->prim_c2i(pval, cont, len, utype, free_cont, it);
+ /* If ANY type clear type and set pointer to internal value */
+ if (it->utype == V_ASN1_ANY)
+ {
+ if (!*pval)
+ {
+ typ = ASN1_TYPE_new();
+ if (typ == NULL)
+ goto err;
+ *pval = (ASN1_VALUE *)typ;
+ }
+ else
+ typ = (ASN1_TYPE *)*pval;
+
+ if (utype != typ->type)
+ ASN1_TYPE_set(typ, utype, NULL);
+ opval = pval;
+ pval = &typ->value.asn1_value;
+ }
+ switch(utype)
+ {
+ case V_ASN1_OBJECT:
+ if (!c2i_ASN1_OBJECT((ASN1_OBJECT **)pval, &cont, len))
+ goto err;
+ break;
+
+ case V_ASN1_NULL:
+ if (len)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_ex_c2i, ASN1_R_NULL_IS_WRONG_LENGTH);
+ goto err;
+ }
+ *pval = (ASN1_VALUE *)1;
+ break;
+
+ case V_ASN1_BOOLEAN:
+ if (len != 1)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_ex_c2i, ASN1_R_BOOLEAN_IS_WRONG_LENGTH);
+ goto err;
+ }
+ else
+ {
+ ASN1_BOOLEAN *tbool;
+ tbool = (ASN1_BOOLEAN *)pval;
+ *tbool = *cont;
+ }
+ break;
+
+ case V_ASN1_BIT_STRING:
+ if (!c2i_ASN1_BIT_STRING((ASN1_BIT_STRING **)pval, &cont, len))
+ goto err;
+ break;
+
+ case V_ASN1_INTEGER:
+ case V_ASN1_NEG_INTEGER:
+ case V_ASN1_ENUMERATED:
+ case V_ASN1_NEG_ENUMERATED:
+ tint = (ASN1_INTEGER **)pval;
+ if (!c2i_ASN1_INTEGER(tint, &cont, len))
+ goto err;
+ /* Fixup type to match the expected form */
+ (*tint)->type = utype | ((*tint)->type & V_ASN1_NEG);
+ break;
+
+ case V_ASN1_OCTET_STRING:
+ case V_ASN1_NUMERICSTRING:
+ case V_ASN1_PRINTABLESTRING:
+ case V_ASN1_T61STRING:
+ case V_ASN1_VIDEOTEXSTRING:
+ case V_ASN1_IA5STRING:
+ case V_ASN1_UTCTIME:
+ case V_ASN1_GENERALIZEDTIME:
+ case V_ASN1_GRAPHICSTRING:
+ case V_ASN1_VISIBLESTRING:
+ case V_ASN1_GENERALSTRING:
+ case V_ASN1_UNIVERSALSTRING:
+ case V_ASN1_BMPSTRING:
+ case V_ASN1_UTF8STRING:
+ case V_ASN1_OTHER:
+ case V_ASN1_SET:
+ case V_ASN1_SEQUENCE:
+ default:
+ if (utype == V_ASN1_BMPSTRING && (len & 1))
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_ex_c2i, 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);
+ goto err;
+ }
+ /* All based on ASN1_STRING and handled the same */
+ if (!*pval)
+ {
+ stmp = ASN1_STRING_type_new(utype);
+ if (!stmp)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_ex_c2i, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ *pval = (ASN1_VALUE *)stmp;
+ }
+ else
+ {
+ stmp = (ASN1_STRING *)*pval;
+ stmp->type = utype;
+ }
+ /* If we've already allocated a buffer use it */
+ if (*free_cont)
+ {
+ if (stmp->data)
+ OPENSSL_free(stmp->data);
+ stmp->data = (unsigned char *)cont; /* UGLY CAST! RL */
+ stmp->length = len;
+ *free_cont = 0;
+ }
+ else
+ {
+ if (!ASN1_STRING_set(stmp, cont, len))
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_ex_c2i, ERR_R_MALLOC_FAILURE);
+ ASN1_STRING_free(stmp);
+ *pval = NULL;
+ goto err;
+ }
+ }
+ break;
+ }
+ /* If ASN1_ANY and NULL type fix up value */
+ if (typ && (utype == V_ASN1_NULL))
+ typ->value.ptr = NULL;
+
+ ret = 1;
+ err:
+ if (!ret)
+ {
+ ASN1_TYPE_free(typ);
+ if (opval)
+ *opval = NULL;
+ }
+ return ret;
+ }
+
+
+/* This function finds the end of an ASN1 structure when passed its maximum
+ * length, whether it is indefinite length and a pointer to the content.
+ * This is more efficient than calling asn1_collect because it does not
+ * recurse on each indefinite length header.
+ */
+
+static int asn1_find_end(const unsigned char **in, long len, char inf)
+ {
+ int expected_eoc;
+ long plen;
+ const unsigned char *p = *in, *q;
+ /* If not indefinite length constructed just add length */
+ if (inf == 0)
+ {
+ *in += len;
+ return 1;
+ }
+ expected_eoc = 1;
+ /* Indefinite length constructed form. Find the end when enough EOCs
+ * are found. If more indefinite length constructed headers
+ * are encountered increment the expected eoc count otherwise just
+ * skip to the end of the data.
+ */
+ while (len > 0)
+ {
+ if(asn1_check_eoc(&p, len))
+ {
+ expected_eoc--;
+ if (expected_eoc == 0)
+ break;
+ len -= 2;
+ continue;
+ }
+ q = p;
+ /* Just read in a header: only care about the length */
+ 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);
+ return 0;
+ }
+ if (inf)
+ expected_eoc++;
+ else
+ p += plen;
+ len -= p - q;
+ }
+ if (expected_eoc)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_find_end, ASN1_R_MISSING_EOC);
+ return 0;
+ }
+ *in = p;
+ return 1;
+ }
+/* This function collects the asn1 data from a constructred string
+ * type into a buffer. The values of 'in' and 'len' should refer
+ * to the contents of the constructed type and 'inf' should be set
+ * if it is indefinite length.
+ */
+
+#ifndef ASN1_MAX_STRING_NEST
+/* This determines how many levels of recursion are permitted in ASN1
+ * string types. If it is not limited stack overflows can occur. If set
+ * to zero no recursion is allowed at all. Although zero should be adequate
+ * examples exist that require a value of 1. So 5 should be more than enough.
+ */
+#define ASN1_MAX_STRING_NEST 5
+#endif
+
+
+static int asn1_collect(BUF_MEM *buf, const unsigned char **in, long len,
+ char inf, int tag, int aclass, int depth)
+ {
+ const unsigned char *p, *q;
+ long plen;
+ char cst, ininf;
+ p = *in;
+ inf &= 1;
+ /* If no buffer and not indefinite length constructed just pass over
+ * the encoded data */
+ if (!buf && !inf)
+ {
+ *in += len;
+ return 1;
+ }
+ while(len > 0)
+ {
+ q = p;
+ /* Check for EOC */
+ if (asn1_check_eoc(&p, len))
+ {
+ /* EOC is illegal outside indefinite length
+ * constructed form */
+ if (!inf)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_collect, ASN1_R_UNEXPECTED_EOC);
+ return 0;
+ }
+ inf = 0;
+ break;
+ }
+
+ 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);
+ return 0;
+ }
+
+ /* If indefinite length constructed update max length */
+ if (cst)
+ {
+ if (depth >= ASN1_MAX_STRING_NEST)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_collect, ASN1_R_NESTED_ASN1_STRING);
+ return 0;
+ }
+ if (!asn1_collect(buf, &p, plen, ininf, tag, aclass,
+ depth + 1))
+ return 0;
+ }
+ else if (plen && !collect_data(buf, &p, plen))
+ return 0;
+ len -= p - q;
+ }
+ if (inf)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_collect, ASN1_R_MISSING_EOC);
+ return 0;
+ }
+ *in = p;
+ return 1;
+ }
+
+static int collect_data(BUF_MEM *buf, const unsigned char **p, long plen)
+ {
+ int len;
+ if (buf)
+ {
+ len = buf->length;
+ if (!BUF_MEM_grow_clean(buf, len + plen))
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_collect, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ memcpy(buf->data + len, *p, plen);
+ }
+ *p += plen;
+ return 1;
+ }
+
+/* Check for ASN1 EOC and swallow it if found */
+
+static int asn1_check_eoc(const unsigned char **in, long len)
+ {
+ const unsigned char *p;
+ if (len < 2) return 0;
+ p = *in;
+ if (!p[0] && !p[1])
+ {
+ *in += 2;
+ return 1;
+ }
+ return 0;
+ }
+
+/* Check an ASN1 tag and length: a bit like ASN1_get_object
+ * but it sets the length for indefinite length constructed
+ * form, we don't know the exact length but we can set an
+ * upper bound to the amount of data available minus the
+ * header length just read.
+ */
+
+static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass,
+ char *inf, char *cst,
+ const unsigned char **in, long len,
+ int exptag, int expclass, char opt,
+ ASN1_TLC *ctx)
+ {
+ int i;
+ int ptag, pclass;
+ long plen;
+ const unsigned char *p, *q;
+ p = *in;
+ q = p;
+
+ if (ctx && ctx->valid)
+ {
+ i = ctx->ret;
+ plen = ctx->plen;
+ pclass = ctx->pclass;
+ ptag = ctx->ptag;
+ p += ctx->hdrlen;
+ }
+ else
+ {
+ i = ASN1_get_object(&p, &plen, &ptag, &pclass, len);
+ if (ctx)
+ {
+ ctx->ret = i;
+ ctx->plen = plen;
+ ctx->pclass = pclass;
+ ctx->ptag = ptag;
+ ctx->hdrlen = p - q;
+ ctx->valid = 1;
+ /* If definite length, and no error, length +
+ * header can't exceed total amount of data available.
+ */
+ if (!(i & 0x81) && ((plen + ctx->hdrlen) > len))
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_check_tlen, ASN1_R_TOO_LONG);
+ asn1_tlc_clear(ctx);
+ return 0;
+ }
+ }
+ }
+
+ if (i & 0x80)
+ {
+ OPENSSL_PUT_ERROR(ASN1, asn1_check_tlen, ASN1_R_BAD_OBJECT_HEADER);
+ asn1_tlc_clear(ctx);
+ return 0;
+ }
+ if (exptag >= 0)
+ {
+ if ((exptag != ptag) || (expclass != pclass))
+ {
+ /* If type is OPTIONAL, not an error:
+ * indicate missing type.
+ */
+ if (opt) return -1;
+ asn1_tlc_clear(ctx);
+ OPENSSL_PUT_ERROR(ASN1, asn1_check_tlen, ASN1_R_WRONG_TAG);
+ return 0;
+ }
+ /* We have a tag and class match:
+ * assume we are going to do something with it */
+ asn1_tlc_clear(ctx);
+ }
+
+ if (i & 1)
+ plen = len - (p - q);
+
+ if (inf)
+ *inf = i & 1;
+
+ if (cst)
+ *cst = i & V_ASN1_CONSTRUCTED;
+
+ if (olen)
+ *olen = plen;
+
+ if (oclass)
+ *oclass = pclass;
+
+ if (otag)
+ *otag = ptag;
+
+ *in = p;
+ return 1;
+ }
diff --git a/crypto/asn1/tasn_enc.c b/crypto/asn1/tasn_enc.c
new file mode 100644
index 0000000..5912e01
--- /dev/null
+++ b/crypto/asn1/tasn_enc.c
@@ -0,0 +1,688 @@
+/* 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/asn1.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/mem.h>
+
+
+static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out,
+ const ASN1_ITEM *it,
+ int tag, int aclass);
+static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out,
+ int skcontlen, const ASN1_ITEM *item,
+ int do_sort, int iclass);
+static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
+ const ASN1_TEMPLATE *tt,
+ int tag, int aclass);
+static int asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out,
+ const ASN1_ITEM *it, int flags);
+
+/* Top level i2d equivalents: the 'ndef' variant instructs the encoder
+ * to use indefinite length constructed encoding, where appropriate
+ */
+
+int ASN1_item_ndef_i2d(ASN1_VALUE *val, unsigned char **out,
+ const ASN1_ITEM *it)
+ {
+ return asn1_item_flags_i2d(val, out, it, ASN1_TFLG_NDEF);
+ }
+
+int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it)
+ {
+ return asn1_item_flags_i2d(val, out, it, 0);
+ }
+
+/* Encode an ASN1 item, this is use by the
+ * standard 'i2d' function. 'out' points to
+ * a buffer to output the data to.
+ *
+ * The new i2d has one additional feature. If the output
+ * buffer is NULL (i.e. *out == NULL) then a buffer is
+ * allocated and populated with the encoding.
+ */
+
+static int asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out,
+ const ASN1_ITEM *it, int flags)
+ {
+ if (out && !*out)
+ {
+ unsigned char *p, *buf;
+ int len;
+ len = ASN1_item_ex_i2d(&val, NULL, it, -1, flags);
+ if (len <= 0)
+ return len;
+ buf = OPENSSL_malloc(len);
+ if (!buf)
+ return -1;
+ p = buf;
+ ASN1_item_ex_i2d(&val, &p, it, -1, flags);
+ *out = buf;
+ return len;
+ }
+
+ return ASN1_item_ex_i2d(&val, out, it, -1, flags);
+ }
+
+/* Encode an item, taking care of IMPLICIT tagging (if any).
+ * This function performs the normal item handling: it can be
+ * used in external types.
+ */
+
+int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
+ const ASN1_ITEM *it, int tag, int aclass)
+ {
+ const ASN1_TEMPLATE *tt = NULL;
+ unsigned char *p = NULL;
+ int i, seqcontlen, seqlen, ndef = 1;
+ const ASN1_COMPAT_FUNCS *cf;
+ const ASN1_EXTERN_FUNCS *ef;
+ const ASN1_AUX *aux = it->funcs;
+ ASN1_aux_cb *asn1_cb = 0;
+
+ if ((it->itype != ASN1_ITYPE_PRIMITIVE) && !*pval)
+ return 0;
+
+ if (aux && aux->asn1_cb)
+ asn1_cb = aux->asn1_cb;
+
+ switch(it->itype)
+ {
+
+ case ASN1_ITYPE_PRIMITIVE:
+ if (it->templates)
+ return asn1_template_ex_i2d(pval, out, it->templates,
+ tag, aclass);
+ return asn1_i2d_ex_primitive(pval, out, it, tag, aclass);
+ break;
+
+ case ASN1_ITYPE_MSTRING:
+ return asn1_i2d_ex_primitive(pval, out, it, -1, aclass);
+
+ case ASN1_ITYPE_CHOICE:
+ if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL))
+ return 0;
+ i = asn1_get_choice_selector(pval, it);
+ if ((i >= 0) && (i < it->tcount))
+ {
+ ASN1_VALUE **pchval;
+ const ASN1_TEMPLATE *chtt;
+ chtt = it->templates + i;
+ pchval = asn1_get_field_ptr(pval, chtt);
+ return asn1_template_ex_i2d(pchval, out, chtt,
+ -1, aclass);
+ }
+ /* Fixme: error condition if selector out of range */
+ if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it, NULL))
+ return 0;
+ break;
+
+ case ASN1_ITYPE_EXTERN:
+ /* If new style i2d it does all the work */
+ ef = it->funcs;
+ return ef->asn1_ex_i2d(pval, out, it, tag, aclass);
+
+ case ASN1_ITYPE_COMPAT:
+ /* old style hackery... */
+ cf = it->funcs;
+ if (out)
+ p = *out;
+ i = cf->asn1_i2d(*pval, out);
+ /* Fixup for IMPLICIT tag: note this messes up for tags > 30,
+ * but so did the old code. Tags > 30 are very rare anyway.
+ */
+ if (out && (tag != -1))
+ *p = aclass | tag | (*p & V_ASN1_CONSTRUCTED);
+ return i;
+
+ case ASN1_ITYPE_NDEF_SEQUENCE:
+ /* Use indefinite length constructed if requested */
+ if (aclass & ASN1_TFLG_NDEF) ndef = 2;
+ /* fall through */
+
+ case ASN1_ITYPE_SEQUENCE:
+ i = asn1_enc_restore(&seqcontlen, out, pval, it);
+ /* An error occurred */
+ if (i < 0)
+ return 0;
+ /* We have a valid cached encoding... */
+ if (i > 0)
+ return seqcontlen;
+ /* Otherwise carry on */
+ seqcontlen = 0;
+ /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */
+ if (tag == -1)
+ {
+ tag = V_ASN1_SEQUENCE;
+ /* Retain any other flags in aclass */
+ aclass = (aclass & ~ASN1_TFLG_TAG_CLASS)
+ | V_ASN1_UNIVERSAL;
+ }
+ if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL))
+ return 0;
+ /* First work out sequence content length */
+ for (i = 0, tt = it->templates; i < it->tcount; tt++, i++)
+ {
+ const ASN1_TEMPLATE *seqtt;
+ ASN1_VALUE **pseqval;
+ seqtt = asn1_do_adb(pval, tt, 1);
+ if (!seqtt)
+ return 0;
+ pseqval = asn1_get_field_ptr(pval, seqtt);
+ /* FIXME: check for errors in enhanced version */
+ seqcontlen += asn1_template_ex_i2d(pseqval, NULL, seqtt,
+ -1, aclass);
+ }
+
+ seqlen = ASN1_object_size(ndef, seqcontlen, tag);
+ if (!out)
+ return seqlen;
+ /* Output SEQUENCE header */
+ ASN1_put_object(out, ndef, seqcontlen, tag, aclass);
+ for (i = 0, tt = it->templates; i < it->tcount; tt++, i++)
+ {
+ const ASN1_TEMPLATE *seqtt;
+ ASN1_VALUE **pseqval;
+ seqtt = asn1_do_adb(pval, tt, 1);
+ if (!seqtt)
+ return 0;
+ pseqval = asn1_get_field_ptr(pval, seqtt);
+ /* FIXME: check for errors in enhanced version */
+ asn1_template_ex_i2d(pseqval, out, seqtt, -1, aclass);
+ }
+ if (ndef == 2)
+ ASN1_put_eoc(out);
+ if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it, NULL))
+ return 0;
+ return seqlen;
+
+ default:
+ return 0;
+
+ }
+ return 0;
+ }
+
+int ASN1_template_i2d(ASN1_VALUE **pval, unsigned char **out,
+ const ASN1_TEMPLATE *tt)
+ {
+ return asn1_template_ex_i2d(pval, out, tt, -1, 0);
+ }
+
+static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
+ const ASN1_TEMPLATE *tt, int tag, int iclass)
+ {
+ int i, ret, flags, ttag, tclass, ndef;
+ size_t j;
+ flags = tt->flags;
+ /* Work out tag and class to use: tagging may come
+ * either from the template or the arguments, not both
+ * because this would create ambiguity. Additionally
+ * the iclass argument may contain some additional flags
+ * which should be noted and passed down to other levels.
+ */
+ if (flags & ASN1_TFLG_TAG_MASK)
+ {
+ /* Error if argument and template tagging */
+ if (tag != -1)
+ /* FIXME: error code here */
+ return -1;
+ /* Get tagging from template */
+ ttag = tt->tag;
+ tclass = flags & ASN1_TFLG_TAG_CLASS;
+ }
+ else if (tag != -1)
+ {
+ /* No template tagging, get from arguments */
+ ttag = tag;
+ tclass = iclass & ASN1_TFLG_TAG_CLASS;
+ }
+ else
+ {
+ ttag = -1;
+ tclass = 0;
+ }
+ /*
+ * Remove any class mask from iflag.
+ */
+ iclass &= ~ASN1_TFLG_TAG_CLASS;
+
+ /* At this point 'ttag' contains the outer tag to use,
+ * 'tclass' is the class and iclass is any flags passed
+ * to this function.
+ */
+
+ /* if template and arguments require ndef, use it */
+ if ((flags & ASN1_TFLG_NDEF) && (iclass & ASN1_TFLG_NDEF))
+ ndef = 2;
+ else ndef = 1;
+
+ if (flags & ASN1_TFLG_SK_MASK)
+ {
+ /* SET OF, SEQUENCE OF */
+ STACK_OF(ASN1_VALUE) *sk = (STACK_OF(ASN1_VALUE) *)*pval;
+ int isset, sktag, skaclass;
+ int skcontlen, sklen;
+ ASN1_VALUE *skitem;
+
+ if (!*pval)
+ return 0;
+
+ if (flags & ASN1_TFLG_SET_OF)
+ {
+ isset = 1;
+ /* 2 means we reorder */
+ if (flags & ASN1_TFLG_SEQUENCE_OF)
+ isset = 2;
+ }
+ else isset = 0;
+
+ /* Work out inner tag value: if EXPLICIT
+ * or no tagging use underlying type.
+ */
+ if ((ttag != -1) && !(flags & ASN1_TFLG_EXPTAG))
+ {
+ sktag = ttag;
+ skaclass = tclass;
+ }
+ else
+ {
+ skaclass = V_ASN1_UNIVERSAL;
+ if (isset)
+ sktag = V_ASN1_SET;
+ else sktag = V_ASN1_SEQUENCE;
+ }
+
+ /* Determine total length of items */
+ skcontlen = 0;
+ for (j = 0; j < sk_ASN1_VALUE_num(sk); j++)
+ {
+ skitem = sk_ASN1_VALUE_value(sk, j);
+ skcontlen += ASN1_item_ex_i2d(&skitem, NULL,
+ ASN1_ITEM_ptr(tt->item),
+ -1, iclass);
+ }
+ sklen = ASN1_object_size(ndef, skcontlen, sktag);
+ /* If EXPLICIT need length of surrounding tag */
+ if (flags & ASN1_TFLG_EXPTAG)
+ ret = ASN1_object_size(ndef, sklen, ttag);
+ else ret = sklen;
+
+ if (!out)
+ return ret;
+
+ /* Now encode this lot... */
+ /* EXPLICIT tag */
+ if (flags & ASN1_TFLG_EXPTAG)
+ ASN1_put_object(out, ndef, sklen, ttag, tclass);
+ /* SET or SEQUENCE and IMPLICIT tag */
+ ASN1_put_object(out, ndef, skcontlen, sktag, skaclass);
+ /* And the stuff itself */
+ asn1_set_seq_out(sk, out, skcontlen, ASN1_ITEM_ptr(tt->item),
+ isset, iclass);
+ if (ndef == 2)
+ {
+ ASN1_put_eoc(out);
+ if (flags & ASN1_TFLG_EXPTAG)
+ ASN1_put_eoc(out);
+ }
+
+ return ret;
+ }
+
+ if (flags & ASN1_TFLG_EXPTAG)
+ {
+ /* EXPLICIT tagging */
+ /* Find length of tagged item */
+ i = ASN1_item_ex_i2d(pval, NULL, ASN1_ITEM_ptr(tt->item),
+ -1, iclass);
+ if (!i)
+ return 0;
+ /* Find length of EXPLICIT tag */
+ ret = ASN1_object_size(ndef, i, ttag);
+ if (out)
+ {
+ /* Output tag and item */
+ ASN1_put_object(out, ndef, i, ttag, tclass);
+ ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item),
+ -1, iclass);
+ if (ndef == 2)
+ ASN1_put_eoc(out);
+ }
+ return ret;
+ }
+
+ /* Either normal or IMPLICIT tagging: combine class and flags */
+ return ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item),
+ ttag, tclass | iclass);
+
+}
+
+/* Temporary structure used to hold DER encoding of items for SET OF */
+
+typedef struct {
+ unsigned char *data;
+ int length;
+ ASN1_VALUE *field;
+} DER_ENC;
+
+static int der_cmp(const void *a, const void *b)
+ {
+ const DER_ENC *d1 = a, *d2 = b;
+ int cmplen, i;
+ cmplen = (d1->length < d2->length) ? d1->length : d2->length;
+ i = memcmp(d1->data, d2->data, cmplen);
+ if (i)
+ return i;
+ return d1->length - d2->length;
+ }
+
+/* Output the content octets of SET OF or SEQUENCE OF */
+
+static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out,
+ int skcontlen, const ASN1_ITEM *item,
+ int do_sort, int iclass)
+ {
+ size_t i;
+ ASN1_VALUE *skitem;
+ unsigned char *tmpdat = NULL, *p = NULL;
+ DER_ENC *derlst = NULL, *tder;
+ if (do_sort)
+ {
+ /* Don't need to sort less than 2 items */
+ if (sk_ASN1_VALUE_num(sk) < 2)
+ do_sort = 0;
+ else
+ {
+ derlst = OPENSSL_malloc(sk_ASN1_VALUE_num(sk)
+ * sizeof(*derlst));
+ tmpdat = OPENSSL_malloc(skcontlen);
+ if (!derlst || !tmpdat)
+ return 0;
+ }
+ }
+ /* If not sorting just output each item */
+ if (!do_sort)
+ {
+ for (i = 0; i < sk_ASN1_VALUE_num(sk); i++)
+ {
+ skitem = sk_ASN1_VALUE_value(sk, i);
+ ASN1_item_ex_i2d(&skitem, out, item, -1, iclass);
+ }
+ return 1;
+ }
+ p = tmpdat;
+
+ /* Doing sort: build up a list of each member's DER encoding */
+ for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++)
+ {
+ skitem = sk_ASN1_VALUE_value(sk, i);
+ tder->data = p;
+ tder->length = ASN1_item_ex_i2d(&skitem, &p, item, -1, iclass);
+ tder->field = skitem;
+ }
+
+ /* Now sort them */
+ qsort(derlst, sk_ASN1_VALUE_num(sk), sizeof(*derlst), der_cmp);
+ /* Output sorted DER encoding */
+ p = *out;
+ for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++)
+ {
+ memcpy(p, tder->data, tder->length);
+ p += tder->length;
+ }
+ *out = p;
+ /* If do_sort is 2 then reorder the STACK */
+ if (do_sort == 2)
+ {
+ for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk);
+ i++, tder++)
+ (void)sk_ASN1_VALUE_set(sk, i, tder->field);
+ }
+ OPENSSL_free(derlst);
+ OPENSSL_free(tmpdat);
+ return 1;
+ }
+
+static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out,
+ const ASN1_ITEM *it, int tag, int aclass)
+ {
+ int len;
+ int utype;
+ int usetag;
+ int ndef = 0;
+
+ utype = it->utype;
+
+ /* Get length of content octets and maybe find
+ * out the underlying type.
+ */
+
+ len = asn1_ex_i2c(pval, NULL, &utype, it);
+
+ /* If SEQUENCE, SET or OTHER then header is
+ * included in pseudo content octets so don't
+ * include tag+length. We need to check here
+ * because the call to asn1_ex_i2c() could change
+ * utype.
+ */
+ if ((utype == V_ASN1_SEQUENCE) || (utype == V_ASN1_SET) ||
+ (utype == V_ASN1_OTHER))
+ usetag = 0;
+ else usetag = 1;
+
+ /* -1 means omit type */
+
+ if (len == -1)
+ return 0;
+
+ /* -2 return is special meaning use ndef */
+ if (len == -2)
+ {
+ ndef = 2;
+ len = 0;
+ }
+
+ /* If not implicitly tagged get tag from underlying type */
+ if (tag == -1) tag = utype;
+
+ /* Output tag+length followed by content octets */
+ if (out)
+ {
+ if (usetag)
+ ASN1_put_object(out, ndef, len, tag, aclass);
+ asn1_ex_i2c(pval, *out, &utype, it);
+ if (ndef)
+ ASN1_put_eoc(out);
+ else
+ *out += len;
+ }
+
+ if (usetag)
+ return ASN1_object_size(ndef, len, tag);
+ return len;
+ }
+
+/* Produce content octets from a structure */
+
+int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype,
+ const ASN1_ITEM *it)
+ {
+ ASN1_BOOLEAN *tbool = NULL;
+ ASN1_STRING *strtmp;
+ ASN1_OBJECT *otmp;
+ int utype;
+ const unsigned char *cont;
+ unsigned char c;
+ int len;
+ const ASN1_PRIMITIVE_FUNCS *pf;
+ pf = it->funcs;
+ if (pf && pf->prim_i2c)
+ return pf->prim_i2c(pval, cout, putype, it);
+
+ /* Should type be omitted? */
+ if ((it->itype != ASN1_ITYPE_PRIMITIVE)
+ || (it->utype != V_ASN1_BOOLEAN))
+ {
+ if (!*pval) return -1;
+ }
+
+ if (it->itype == ASN1_ITYPE_MSTRING)
+ {
+ /* If MSTRING type set the underlying type */
+ strtmp = (ASN1_STRING *)*pval;
+ utype = strtmp->type;
+ *putype = utype;
+ }
+ else if (it->utype == V_ASN1_ANY)
+ {
+ /* If ANY set type and pointer to value */
+ ASN1_TYPE *typ;
+ typ = (ASN1_TYPE *)*pval;
+ utype = typ->type;
+ *putype = utype;
+ pval = &typ->value.asn1_value;
+ }
+ else utype = *putype;
+
+ switch(utype)
+ {
+ case V_ASN1_OBJECT:
+ otmp = (ASN1_OBJECT *)*pval;
+ cont = otmp->data;
+ len = otmp->length;
+ break;
+
+ case V_ASN1_NULL:
+ cont = NULL;
+ len = 0;
+ break;
+
+ case V_ASN1_BOOLEAN:
+ tbool = (ASN1_BOOLEAN *)pval;
+ if (*tbool == -1)
+ return -1;
+ if (it->utype != V_ASN1_ANY)
+ {
+ /* Default handling if value == size field then omit */
+ if (*tbool && (it->size > 0))
+ return -1;
+ if (!*tbool && !it->size)
+ return -1;
+ }
+ c = (unsigned char)*tbool;
+ cont = &c;
+ len = 1;
+ break;
+
+ case V_ASN1_BIT_STRING:
+ return i2c_ASN1_BIT_STRING((ASN1_BIT_STRING *)*pval,
+ cout ? &cout : NULL);
+ break;
+
+ case V_ASN1_INTEGER:
+ case V_ASN1_NEG_INTEGER:
+ case V_ASN1_ENUMERATED:
+ case V_ASN1_NEG_ENUMERATED:
+ /* These are all have the same content format
+ * as ASN1_INTEGER
+ */
+ return i2c_ASN1_INTEGER((ASN1_INTEGER *)*pval,
+ cout ? &cout : NULL);
+ break;
+
+ case V_ASN1_OCTET_STRING:
+ case V_ASN1_NUMERICSTRING:
+ case V_ASN1_PRINTABLESTRING:
+ case V_ASN1_T61STRING:
+ case V_ASN1_VIDEOTEXSTRING:
+ case V_ASN1_IA5STRING:
+ case V_ASN1_UTCTIME:
+ case V_ASN1_GENERALIZEDTIME:
+ case V_ASN1_GRAPHICSTRING:
+ case V_ASN1_VISIBLESTRING:
+ case V_ASN1_GENERALSTRING:
+ case V_ASN1_UNIVERSALSTRING:
+ case V_ASN1_BMPSTRING:
+ case V_ASN1_UTF8STRING:
+ case V_ASN1_SEQUENCE:
+ case V_ASN1_SET:
+ default:
+ /* All based on ASN1_STRING and handled the same */
+ strtmp = (ASN1_STRING *)*pval;
+ /* Special handling for NDEF */
+ if ((it->size == ASN1_TFLG_NDEF)
+ && (strtmp->flags & ASN1_STRING_FLAG_NDEF))
+ {
+ if (cout)
+ {
+ strtmp->data = cout;
+ strtmp->length = 0;
+ }
+ /* Special return code */
+ return -2;
+ }
+ cont = strtmp->data;
+ len = strtmp->length;
+
+ break;
+
+ }
+ if (cout && len)
+ memcpy(cout, cont, len);
+ return len;
+ }
diff --git a/crypto/asn1/tasn_fre.c b/crypto/asn1/tasn_fre.c
new file mode 100644
index 0000000..c344ed7
--- /dev/null
+++ b/crypto/asn1/tasn_fre.c
@@ -0,0 +1,264 @@
+/* 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/asn1.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/mem.h>
+
+
+static void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it, int combine);
+
+/* Free up an ASN1 structure */
+
+void ASN1_item_free(ASN1_VALUE *val, const ASN1_ITEM *it)
+ {
+ asn1_item_combine_free(&val, it, 0);
+ }
+
+void ASN1_item_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
+ {
+ asn1_item_combine_free(pval, it, 0);
+ }
+
+static void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it, int combine)
+ {
+ const ASN1_TEMPLATE *tt = NULL, *seqtt;
+ const ASN1_EXTERN_FUNCS *ef;
+ const ASN1_COMPAT_FUNCS *cf;
+ const ASN1_AUX *aux = it->funcs;
+ ASN1_aux_cb *asn1_cb;
+ int i;
+ if (!pval)
+ return;
+ if ((it->itype != ASN1_ITYPE_PRIMITIVE) && !*pval)
+ return;
+ if (aux && aux->asn1_cb)
+ asn1_cb = aux->asn1_cb;
+ else
+ asn1_cb = 0;
+
+ switch(it->itype)
+ {
+
+ case ASN1_ITYPE_PRIMITIVE:
+ if (it->templates)
+ ASN1_template_free(pval, it->templates);
+ else
+ ASN1_primitive_free(pval, it);
+ break;
+
+ case ASN1_ITYPE_MSTRING:
+ ASN1_primitive_free(pval, it);
+ break;
+
+ case ASN1_ITYPE_CHOICE:
+ if (asn1_cb)
+ {
+ i = asn1_cb(ASN1_OP_FREE_PRE, pval, it, NULL);
+ if (i == 2)
+ return;
+ }
+ i = asn1_get_choice_selector(pval, it);
+ if ((i >= 0) && (i < it->tcount))
+ {
+ ASN1_VALUE **pchval;
+ tt = it->templates + i;
+ pchval = asn1_get_field_ptr(pval, tt);
+ ASN1_template_free(pchval, tt);
+ }
+ if (asn1_cb)
+ asn1_cb(ASN1_OP_FREE_POST, pval, it, NULL);
+ if (!combine)
+ {
+ OPENSSL_free(*pval);
+ *pval = NULL;
+ }
+ break;
+
+ case ASN1_ITYPE_COMPAT:
+ cf = it->funcs;
+ if (cf && cf->asn1_free)
+ cf->asn1_free(*pval);
+ break;
+
+ case ASN1_ITYPE_EXTERN:
+ ef = it->funcs;
+ if (ef && ef->asn1_ex_free)
+ ef->asn1_ex_free(pval, it);
+ break;
+
+ case ASN1_ITYPE_NDEF_SEQUENCE:
+ case ASN1_ITYPE_SEQUENCE:
+ if (asn1_do_lock(pval, -1, it) > 0)
+ return;
+ if (asn1_cb)
+ {
+ i = asn1_cb(ASN1_OP_FREE_PRE, pval, it, NULL);
+ if (i == 2)
+ return;
+ }
+ asn1_enc_free(pval, it);
+ /* If we free up as normal we will invalidate any
+ * ANY DEFINED BY field and we wont be able to
+ * determine the type of the field it defines. So
+ * free up in reverse order.
+ */
+ tt = it->templates + it->tcount - 1;
+ for (i = 0; i < it->tcount; tt--, i++)
+ {
+ ASN1_VALUE **pseqval;
+ seqtt = asn1_do_adb(pval, tt, 0);
+ if (!seqtt)
+ continue;
+ pseqval = asn1_get_field_ptr(pval, seqtt);
+ ASN1_template_free(pseqval, seqtt);
+ }
+ if (asn1_cb)
+ asn1_cb(ASN1_OP_FREE_POST, pval, it, NULL);
+ if (!combine)
+ {
+ OPENSSL_free(*pval);
+ *pval = NULL;
+ }
+ break;
+ }
+ }
+
+void ASN1_template_free(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt)
+ {
+ size_t i;
+ if (tt->flags & ASN1_TFLG_SK_MASK)
+ {
+ STACK_OF(ASN1_VALUE) *sk = (STACK_OF(ASN1_VALUE) *)*pval;
+ for (i = 0; i < sk_ASN1_VALUE_num(sk); i++)
+ {
+ ASN1_VALUE *vtmp;
+ vtmp = sk_ASN1_VALUE_value(sk, i);
+ asn1_item_combine_free(&vtmp, ASN1_ITEM_ptr(tt->item),
+ 0);
+ }
+ sk_ASN1_VALUE_free(sk);
+ *pval = NULL;
+ }
+ else
+ asn1_item_combine_free(pval, ASN1_ITEM_ptr(tt->item),
+ tt->flags & ASN1_TFLG_COMBINE);
+ }
+
+void ASN1_primitive_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
+ {
+ int utype;
+ if (it)
+ {
+ const ASN1_PRIMITIVE_FUNCS *pf;
+ pf = it->funcs;
+ if (pf && pf->prim_free)
+ {
+ pf->prim_free(pval, it);
+ return;
+ }
+ }
+ /* Special case: if 'it' is NULL free contents of ASN1_TYPE */
+ if (!it)
+ {
+ ASN1_TYPE *typ = (ASN1_TYPE *)*pval;
+ utype = typ->type;
+ pval = &typ->value.asn1_value;
+ if (!*pval)
+ return;
+ }
+ else if (it->itype == ASN1_ITYPE_MSTRING)
+ {
+ utype = -1;
+ if (!*pval)
+ return;
+ }
+ else
+ {
+ utype = it->utype;
+ if ((utype != V_ASN1_BOOLEAN) && !*pval)
+ return;
+ }
+
+ switch(utype)
+ {
+ case V_ASN1_OBJECT:
+ ASN1_OBJECT_free((ASN1_OBJECT *)*pval);
+ break;
+
+ case V_ASN1_BOOLEAN:
+ if (it)
+ *(ASN1_BOOLEAN *)pval = it->size;
+ else
+ *(ASN1_BOOLEAN *)pval = -1;
+ return;
+
+ case V_ASN1_NULL:
+ break;
+
+ case V_ASN1_ANY:
+ ASN1_primitive_free(pval, NULL);
+ OPENSSL_free(*pval);
+ break;
+
+ default:
+ ASN1_STRING_free((ASN1_STRING *)*pval);
+ *pval = NULL;
+ break;
+ }
+ *pval = NULL;
+ }
diff --git a/crypto/asn1/tasn_new.c b/crypto/asn1/tasn_new.c
new file mode 100644
index 0000000..8a2b27d
--- /dev/null
+++ b/crypto/asn1/tasn_new.c
@@ -0,0 +1,394 @@
+/* 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/asn1.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+
+
+static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it,
+ int combine);
+static void asn1_item_clear(ASN1_VALUE **pval, const ASN1_ITEM *it);
+static void asn1_template_clear(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt);
+static void asn1_primitive_clear(ASN1_VALUE **pval, const ASN1_ITEM *it);
+
+ASN1_VALUE *ASN1_item_new(const ASN1_ITEM *it)
+ {
+ ASN1_VALUE *ret = NULL;
+ if (ASN1_item_ex_new(&ret, it) > 0)
+ return ret;
+ return NULL;
+ }
+
+/* Allocate an ASN1 structure */
+
+int ASN1_item_ex_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
+ {
+ return asn1_item_ex_combine_new(pval, it, 0);
+ }
+
+static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it,
+ int combine)
+ {
+ const ASN1_TEMPLATE *tt = NULL;
+ const ASN1_COMPAT_FUNCS *cf;
+ const ASN1_EXTERN_FUNCS *ef;
+ const ASN1_AUX *aux = it->funcs;
+ ASN1_aux_cb *asn1_cb;
+ ASN1_VALUE **pseqval;
+ int i;
+ if (aux && aux->asn1_cb)
+ asn1_cb = aux->asn1_cb;
+ else
+ asn1_cb = 0;
+
+ if (!combine) *pval = NULL;
+
+#ifdef CRYPTO_MDEBUG
+ if (it->sname)
+ CRYPTO_push_info(it->sname);
+#endif
+
+ switch(it->itype)
+ {
+
+ case ASN1_ITYPE_EXTERN:
+ ef = it->funcs;
+ if (ef && ef->asn1_ex_new)
+ {
+ if (!ef->asn1_ex_new(pval, it))
+ goto memerr;
+ }
+ break;
+
+ case ASN1_ITYPE_COMPAT:
+ cf = it->funcs;
+ if (cf && cf->asn1_new) {
+ *pval = cf->asn1_new();
+ if (!*pval)
+ goto memerr;
+ }
+ break;
+
+ case ASN1_ITYPE_PRIMITIVE:
+ if (it->templates)
+ {
+ if (!ASN1_template_new(pval, it->templates))
+ goto memerr;
+ }
+ else if (!ASN1_primitive_new(pval, it))
+ goto memerr;
+ break;
+
+ case ASN1_ITYPE_MSTRING:
+ if (!ASN1_primitive_new(pval, it))
+ goto memerr;
+ break;
+
+ case ASN1_ITYPE_CHOICE:
+ if (asn1_cb)
+ {
+ i = asn1_cb(ASN1_OP_NEW_PRE, pval, it, NULL);
+ if (!i)
+ goto auxerr;
+ if (i==2)
+ {
+#ifdef CRYPTO_MDEBUG
+ if (it->sname)
+ CRYPTO_pop_info();
+#endif
+ return 1;
+ }
+ }
+ if (!combine)
+ {
+ *pval = OPENSSL_malloc(it->size);
+ if (!*pval)
+ goto memerr;
+ memset(*pval, 0, it->size);
+ }
+ asn1_set_choice_selector(pval, -1, it);
+ if (asn1_cb && !asn1_cb(ASN1_OP_NEW_POST, pval, it, NULL))
+ goto auxerr;
+ break;
+
+ case ASN1_ITYPE_NDEF_SEQUENCE:
+ case ASN1_ITYPE_SEQUENCE:
+ if (asn1_cb)
+ {
+ i = asn1_cb(ASN1_OP_NEW_PRE, pval, it, NULL);
+ if (!i)
+ goto auxerr;
+ if (i==2)
+ {
+#ifdef CRYPTO_MDEBUG
+ if (it->sname)
+ CRYPTO_pop_info();
+#endif
+ return 1;
+ }
+ }
+ if (!combine)
+ {
+ *pval = OPENSSL_malloc(it->size);
+ if (!*pval)
+ goto memerr;
+ memset(*pval, 0, it->size);
+ asn1_do_lock(pval, 0, it);
+ asn1_enc_init(pval, it);
+ }
+ for (i = 0, tt = it->templates; i < it->tcount; tt++, i++)
+ {
+ pseqval = asn1_get_field_ptr(pval, tt);
+ if (!ASN1_template_new(pseqval, tt))
+ goto memerr;
+ }
+ if (asn1_cb && !asn1_cb(ASN1_OP_NEW_POST, pval, it, NULL))
+ goto auxerr;
+ break;
+ }
+#ifdef CRYPTO_MDEBUG
+ if (it->sname) CRYPTO_pop_info();
+#endif
+ return 1;
+
+ memerr:
+ OPENSSL_PUT_ERROR(ASN1, asn1_item_ex_combine_new, ERR_R_MALLOC_FAILURE);
+#ifdef CRYPTO_MDEBUG
+ if (it->sname) CRYPTO_pop_info();
+#endif
+ return 0;
+
+ auxerr:
+ OPENSSL_PUT_ERROR(ASN1, asn1_item_ex_combine_new, ASN1_R_AUX_ERROR);
+ ASN1_item_ex_free(pval, it);
+#ifdef CRYPTO_MDEBUG
+ if (it->sname) CRYPTO_pop_info();
+#endif
+ return 0;
+
+ }
+
+static void asn1_item_clear(ASN1_VALUE **pval, const ASN1_ITEM *it)
+ {
+ const ASN1_EXTERN_FUNCS *ef;
+
+ switch(it->itype)
+ {
+
+ case ASN1_ITYPE_EXTERN:
+ ef = it->funcs;
+ if (ef && ef->asn1_ex_clear)
+ ef->asn1_ex_clear(pval, it);
+ else *pval = NULL;
+ break;
+
+
+ case ASN1_ITYPE_PRIMITIVE:
+ if (it->templates)
+ asn1_template_clear(pval, it->templates);
+ else
+ asn1_primitive_clear(pval, it);
+ break;
+
+ case ASN1_ITYPE_MSTRING:
+ asn1_primitive_clear(pval, it);
+ break;
+
+ case ASN1_ITYPE_COMPAT:
+ case ASN1_ITYPE_CHOICE:
+ case ASN1_ITYPE_SEQUENCE:
+ case ASN1_ITYPE_NDEF_SEQUENCE:
+ *pval = NULL;
+ break;
+ }
+ }
+
+
+int ASN1_template_new(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt)
+ {
+ const ASN1_ITEM *it = ASN1_ITEM_ptr(tt->item);
+ int ret;
+ if (tt->flags & ASN1_TFLG_OPTIONAL)
+ {
+ asn1_template_clear(pval, tt);
+ return 1;
+ }
+ /* If ANY DEFINED BY nothing to do */
+
+ if (tt->flags & ASN1_TFLG_ADB_MASK)
+ {
+ *pval = NULL;
+ return 1;
+ }
+#ifdef CRYPTO_MDEBUG
+ if (tt->field_name)
+ CRYPTO_push_info(tt->field_name);
+#endif
+ /* If SET OF or SEQUENCE OF, its a STACK */
+ if (tt->flags & ASN1_TFLG_SK_MASK)
+ {
+ STACK_OF(ASN1_VALUE) *skval;
+ skval = sk_ASN1_VALUE_new_null();
+ if (!skval)
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_template_new, ERR_R_MALLOC_FAILURE);
+ ret = 0;
+ goto done;
+ }
+ *pval = (ASN1_VALUE *)skval;
+ ret = 1;
+ goto done;
+ }
+ /* Otherwise pass it back to the item routine */
+ ret = asn1_item_ex_combine_new(pval, it, tt->flags & ASN1_TFLG_COMBINE);
+ done:
+#ifdef CRYPTO_MDEBUG
+ if (it->sname)
+ CRYPTO_pop_info();
+#endif
+ return ret;
+ }
+
+static void asn1_template_clear(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt)
+ {
+ /* If ADB or STACK just NULL the field */
+ if (tt->flags & (ASN1_TFLG_ADB_MASK|ASN1_TFLG_SK_MASK))
+ *pval = NULL;
+ else
+ asn1_item_clear(pval, ASN1_ITEM_ptr(tt->item));
+ }
+
+
+/* NB: could probably combine most of the real XXX_new() behaviour and junk
+ * all the old functions.
+ */
+
+int ASN1_primitive_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
+ {
+ ASN1_TYPE *typ;
+ ASN1_STRING *str;
+ int utype;
+
+ if (it && it->funcs)
+ {
+ const ASN1_PRIMITIVE_FUNCS *pf = it->funcs;
+ if (pf->prim_new)
+ return pf->prim_new(pval, it);
+ }
+
+ if (!it || (it->itype == ASN1_ITYPE_MSTRING))
+ utype = -1;
+ else
+ utype = it->utype;
+ switch(utype)
+ {
+ case V_ASN1_OBJECT:
+ *pval = (ASN1_VALUE *)OBJ_nid2obj(NID_undef);
+ return 1;
+
+ case V_ASN1_BOOLEAN:
+ *(ASN1_BOOLEAN *)pval = it->size;
+ return 1;
+
+ case V_ASN1_NULL:
+ *pval = (ASN1_VALUE *)1;
+ return 1;
+
+ case V_ASN1_ANY:
+ typ = OPENSSL_malloc(sizeof(ASN1_TYPE));
+ if (!typ)
+ return 0;
+ typ->value.ptr = NULL;
+ typ->type = -1;
+ *pval = (ASN1_VALUE *)typ;
+ break;
+
+ default:
+ str = ASN1_STRING_type_new(utype);
+ if (it->itype == ASN1_ITYPE_MSTRING && str)
+ str->flags |= ASN1_STRING_FLAG_MSTRING;
+ *pval = (ASN1_VALUE *)str;
+ break;
+ }
+ if (*pval)
+ return 1;
+ return 0;
+ }
+
+static void asn1_primitive_clear(ASN1_VALUE **pval, const ASN1_ITEM *it)
+ {
+ int utype;
+ if (it && it->funcs)
+ {
+ const ASN1_PRIMITIVE_FUNCS *pf = it->funcs;
+ if (pf->prim_clear)
+ pf->prim_clear(pval, it);
+ else
+ *pval = NULL;
+ return;
+ }
+ if (!it || (it->itype == ASN1_ITYPE_MSTRING))
+ utype = -1;
+ else
+ utype = it->utype;
+ if (utype == V_ASN1_BOOLEAN)
+ *(ASN1_BOOLEAN *)pval = it->size;
+ else *pval = NULL;
+ }
diff --git a/crypto/asn1/tasn_prn.c b/crypto/asn1/tasn_prn.c
new file mode 100644
index 0000000..7b10cfe
--- /dev/null
+++ b/crypto/asn1/tasn_prn.c
@@ -0,0 +1,639 @@
+/* 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/asn1.h>
+
+#include <time.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/err.h>
+#include <openssl/obj.h>
+#include <openssl/mem.h>
+
+#include "asn1_locl.h"
+
+
+
+/* Print routines.
+ */
+
+/* ASN1_PCTX routines */
+
+ASN1_PCTX default_pctx =
+ {
+ ASN1_PCTX_FLAGS_SHOW_ABSENT, /* flags */
+ 0, /* nm_flags */
+ 0, /* cert_flags */
+ 0, /* oid_flags */
+ 0 /* str_flags */
+ };
+
+
+ASN1_PCTX *ASN1_PCTX_new(void)
+ {
+ ASN1_PCTX *ret;
+ ret = OPENSSL_malloc(sizeof(ASN1_PCTX));
+ if (ret == NULL)
+ {
+ OPENSSL_PUT_ERROR(ASN1, ASN1_PCTX_new, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ ret->flags = 0;
+ ret->nm_flags = 0;
+ ret->cert_flags = 0;
+ ret->oid_flags = 0;
+ ret->str_flags = 0;
+ return ret;
+ }
+
+void ASN1_PCTX_free(ASN1_PCTX *p)
+ {
+ OPENSSL_free(p);
+ }
+
+unsigned long ASN1_PCTX_get_flags(ASN1_PCTX *p)
+ {
+ return p->flags;
+ }
+
+void ASN1_PCTX_set_flags(ASN1_PCTX *p, unsigned long flags)
+ {
+ p->flags = flags;
+ }
+
+unsigned long ASN1_PCTX_get_nm_flags(ASN1_PCTX *p)
+ {
+ return p->nm_flags;
+ }
+
+void ASN1_PCTX_set_nm_flags(ASN1_PCTX *p, unsigned long flags)
+ {
+ p->nm_flags = flags;
+ }
+
+unsigned long ASN1_PCTX_get_cert_flags(ASN1_PCTX *p)
+ {
+ return p->cert_flags;
+ }
+
+void ASN1_PCTX_set_cert_flags(ASN1_PCTX *p, unsigned long flags)
+ {
+ p->cert_flags = flags;
+ }
+
+unsigned long ASN1_PCTX_get_oid_flags(ASN1_PCTX *p)
+ {
+ return p->oid_flags;
+ }
+
+void ASN1_PCTX_set_oid_flags(ASN1_PCTX *p, unsigned long flags)
+ {
+ p->oid_flags = flags;
+ }
+
+unsigned long ASN1_PCTX_get_str_flags(ASN1_PCTX *p)
+ {
+ return p->str_flags;
+ }
+
+void ASN1_PCTX_set_str_flags(ASN1_PCTX *p, unsigned long flags)
+ {
+ p->str_flags = flags;
+ }
+
+/* Main print routines */
+
+static int asn1_item_print_ctx(BIO *out, ASN1_VALUE **fld, int indent,
+ const ASN1_ITEM *it,
+ const char *fname, const char *sname,
+ int nohdr, const ASN1_PCTX *pctx);
+
+int asn1_template_print_ctx(BIO *out, ASN1_VALUE **fld, int indent,
+ const ASN1_TEMPLATE *tt, const ASN1_PCTX *pctx);
+
+static int asn1_primitive_print(BIO *out, ASN1_VALUE **fld,
+ const ASN1_ITEM *it, int indent,
+ const char *fname, const char *sname,
+ const ASN1_PCTX *pctx);
+
+static int asn1_print_fsname(BIO *out, int indent,
+ const char *fname, const char *sname,
+ const ASN1_PCTX *pctx);
+
+int ASN1_item_print(BIO *out, ASN1_VALUE *ifld, int indent,
+ const ASN1_ITEM *it, const ASN1_PCTX *pctx)
+ {
+ const char *sname;
+ if (pctx == NULL)
+ pctx = &default_pctx;
+ if (pctx->flags & ASN1_PCTX_FLAGS_NO_STRUCT_NAME)
+ sname = NULL;
+ else
+ sname = it->sname;
+ return asn1_item_print_ctx(out, &ifld, indent, it,
+ NULL, sname, 0, pctx);
+ }
+
+static int asn1_item_print_ctx(BIO *out, ASN1_VALUE **fld, int indent,
+ const ASN1_ITEM *it,
+ const char *fname, const char *sname,
+ int nohdr, const ASN1_PCTX *pctx)
+ {
+ const ASN1_TEMPLATE *tt;
+ const ASN1_EXTERN_FUNCS *ef;
+ ASN1_VALUE **tmpfld;
+ const ASN1_AUX *aux = it->funcs;
+ ASN1_aux_cb *asn1_cb;
+ ASN1_PRINT_ARG parg;
+ int i;
+ if (aux && aux->asn1_cb)
+ {
+ parg.out = out;
+ parg.indent = indent;
+ parg.pctx = pctx;
+ asn1_cb = aux->asn1_cb;
+ }
+ else asn1_cb = 0;
+
+ if(*fld == NULL)
+ {
+ if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_ABSENT)
+ {
+ if (!nohdr && !asn1_print_fsname(out, indent,
+ fname, sname, pctx))
+ return 0;
+ if (BIO_puts(out, "<ABSENT>\n") <= 0)
+ return 0;
+ }
+ return 1;
+ }
+
+ switch(it->itype)
+ {
+ case ASN1_ITYPE_PRIMITIVE:
+ if(it->templates)
+ {
+ if (!asn1_template_print_ctx(out, fld, indent,
+ it->templates, pctx))
+ return 0;
+ }
+ /* fall thru */
+ case ASN1_ITYPE_MSTRING:
+ if (!asn1_primitive_print(out, fld, it,
+ indent, fname, sname,pctx))
+ return 0;
+ break;
+
+ case ASN1_ITYPE_EXTERN:
+ if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx))
+ return 0;
+ /* Use new style print routine if possible */
+ ef = it->funcs;
+ if (ef && ef->asn1_ex_print)
+ {
+ i = ef->asn1_ex_print(out, fld, indent, "", pctx);
+ if (!i)
+ return 0;
+ if ((i == 2) && (BIO_puts(out, "\n") <= 0))
+ return 0;
+ return 1;
+ }
+ else if (sname &&
+ BIO_printf(out, ":EXTERNAL TYPE %s\n", sname) <= 0)
+ return 0;
+ break;
+
+ case ASN1_ITYPE_CHOICE:
+#if 0
+ if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx))
+ return 0;
+#endif
+ /* CHOICE type, get selector */
+ i = asn1_get_choice_selector(fld, it);
+ /* This should never happen... */
+ if((i < 0) || (i >= it->tcount))
+ {
+ if (BIO_printf(out,
+ "ERROR: selector [%d] invalid\n", i) <= 0)
+ return 0;
+ return 1;
+ }
+ tt = it->templates + i;
+ tmpfld = asn1_get_field_ptr(fld, tt);
+ if (!asn1_template_print_ctx(out, tmpfld, indent, tt, pctx))
+ return 0;
+ break;
+
+ case ASN1_ITYPE_SEQUENCE:
+ case ASN1_ITYPE_NDEF_SEQUENCE:
+ if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx))
+ return 0;
+ if (fname || sname)
+ {
+ if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE)
+ {
+ if (BIO_puts(out, " {\n") <= 0)
+ return 0;
+ }
+ else
+ {
+ if (BIO_puts(out, "\n") <= 0)
+ return 0;
+ }
+ }
+
+ if (asn1_cb)
+ {
+ i = asn1_cb(ASN1_OP_PRINT_PRE, fld, it, &parg);
+ if (i == 0)
+ return 0;
+ if (i == 2)
+ return 1;
+ }
+
+ /* Print each field entry */
+ for(i = 0, tt = it->templates; i < it->tcount; i++, tt++)
+ {
+ const ASN1_TEMPLATE *seqtt;
+ seqtt = asn1_do_adb(fld, tt, 1);
+ tmpfld = asn1_get_field_ptr(fld, seqtt);
+ if (!asn1_template_print_ctx(out, tmpfld,
+ indent + 2, seqtt, pctx))
+ return 0;
+ }
+ if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE)
+ {
+ if (BIO_printf(out, "%*s}\n", indent, "") < 0)
+ return 0;
+ }
+
+ if (asn1_cb)
+ {
+ i = asn1_cb(ASN1_OP_PRINT_POST, fld, it, &parg);
+ if (i == 0)
+ return 0;
+ }
+ break;
+
+ default:
+ BIO_printf(out, "Unprocessed type %d\n", it->itype);
+ return 0;
+ }
+
+ return 1;
+ }
+
+int asn1_template_print_ctx(BIO *out, ASN1_VALUE **fld, int indent,
+ const ASN1_TEMPLATE *tt, const ASN1_PCTX *pctx)
+ {
+ int flags;
+ size_t i;
+ const char *sname, *fname;
+ flags = tt->flags;
+ if(pctx->flags & ASN1_PCTX_FLAGS_SHOW_FIELD_STRUCT_NAME)
+ sname = ASN1_ITEM_ptr(tt->item)->sname;
+ else
+ sname = NULL;
+ if(pctx->flags & ASN1_PCTX_FLAGS_NO_FIELD_NAME)
+ fname = NULL;
+ else
+ fname = tt->field_name;
+ if(flags & ASN1_TFLG_SK_MASK)
+ {
+ char *tname;
+ ASN1_VALUE *skitem;
+ STACK_OF(ASN1_VALUE) *stack;
+
+ /* SET OF, SEQUENCE OF */
+ if (fname)
+ {
+ if(pctx->flags & ASN1_PCTX_FLAGS_SHOW_SSOF)
+ {
+ if(flags & ASN1_TFLG_SET_OF)
+ tname = "SET";
+ else
+ tname = "SEQUENCE";
+ if (BIO_printf(out, "%*s%s OF %s {\n",
+ indent, "", tname, tt->field_name) <= 0)
+ return 0;
+ }
+ else if (BIO_printf(out, "%*s%s:\n", indent, "",
+ fname) <= 0)
+ return 0;
+ }
+ stack = (STACK_OF(ASN1_VALUE) *)*fld;
+ for(i = 0; i < sk_ASN1_VALUE_num(stack); i++)
+ {
+ if ((i > 0) && (BIO_puts(out, "\n") <= 0))
+ return 0;
+
+ skitem = sk_ASN1_VALUE_value(stack, i);
+ if (!asn1_item_print_ctx(out, &skitem, indent + 2,
+ ASN1_ITEM_ptr(tt->item), NULL, NULL, 1, pctx))
+ return 0;
+ }
+ if (!i && BIO_printf(out, "%*s<EMPTY>\n", indent + 2, "") <= 0)
+ return 0;
+ if(pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE)
+ {
+ if (BIO_printf(out, "%*s}\n", indent, "") <= 0)
+ return 0;
+ }
+ return 1;
+ }
+ return asn1_item_print_ctx(out, fld, indent, ASN1_ITEM_ptr(tt->item),
+ fname, sname, 0, pctx);
+ }
+
+static int asn1_print_fsname(BIO *out, int indent,
+ const char *fname, const char *sname,
+ const ASN1_PCTX *pctx)
+ {
+ static char spaces[] = " ";
+ const int nspaces = sizeof(spaces) - 1;
+
+#if 0
+ if (!sname && !fname)
+ return 1;
+#endif
+
+ while (indent > nspaces)
+ {
+ if (BIO_write(out, spaces, nspaces) != nspaces)
+ return 0;
+ indent -= nspaces;
+ }
+ if (BIO_write(out, spaces, indent) != indent)
+ return 0;
+ if (pctx->flags & ASN1_PCTX_FLAGS_NO_STRUCT_NAME)
+ sname = NULL;
+ if (pctx->flags & ASN1_PCTX_FLAGS_NO_FIELD_NAME)
+ fname = NULL;
+ if (!sname && !fname)
+ return 1;
+ if (fname)
+ {
+ if (BIO_puts(out, fname) <= 0)
+ return 0;
+ }
+ if (sname)
+ {
+ if (fname)
+ {
+ if (BIO_printf(out, " (%s)", sname) <= 0)
+ return 0;
+ }
+ else
+ {
+ if (BIO_puts(out, sname) <= 0)
+ return 0;
+ }
+ }
+ if (BIO_write(out, ": ", 2) != 2)
+ return 0;
+ return 1;
+ }
+
+static int asn1_print_boolean_ctx(BIO *out, int boolval,
+ const ASN1_PCTX *pctx)
+ {
+ const char *str;
+ switch (boolval)
+ {
+ case -1:
+ str = "BOOL ABSENT";
+ break;
+
+ case 0:
+ str = "FALSE";
+ break;
+
+ default:
+ str = "TRUE";
+ break;
+
+ }
+
+ if (BIO_puts(out, str) <= 0)
+ return 0;
+ return 1;
+
+ }
+
+static int asn1_print_integer_ctx(BIO *out, ASN1_INTEGER *str,
+ const ASN1_PCTX *pctx)
+ {
+ BIGNUM *bn = NULL;
+ char *s = NULL;
+ int ret = 1;
+
+ bn = ASN1_INTEGER_to_BN(str, NULL);
+ if (bn == NULL) {
+ return 0;
+ }
+ s = BN_bn2dec(bn);
+ BN_free(bn);
+ if (s == NULL) {
+ return 0;
+ }
+
+ if (BIO_puts(out, s) <= 0) {
+ ret = 0;
+ }
+ OPENSSL_free(s);
+ return ret;
+ }
+
+static int asn1_print_oid_ctx(BIO *out, const ASN1_OBJECT *oid,
+ const ASN1_PCTX *pctx)
+ {
+ char objbuf[80];
+ const char *ln;
+ ln = OBJ_nid2ln(OBJ_obj2nid(oid));
+ if(!ln)
+ ln = "";
+ OBJ_obj2txt(objbuf, sizeof objbuf, oid, 1);
+ if (BIO_printf(out, "%s (%s)", ln, objbuf) <= 0)
+ return 0;
+ return 1;
+ }
+
+static int asn1_print_obstring_ctx(BIO *out, ASN1_STRING *str, int indent,
+ const ASN1_PCTX *pctx)
+ {
+ if (str->type == V_ASN1_BIT_STRING)
+ {
+ if (BIO_printf(out, " (%ld unused bits)\n",
+ str->flags & 0x7) <= 0)
+ return 0;
+ }
+ else if (BIO_puts(out, "\n") <= 0)
+ return 0;
+ if (str->length > 0 && !BIO_hexdump(out, str->data, str->length, indent + 2)) {
+ return 0;
+ }
+ return 1;
+ }
+
+static int asn1_primitive_print(BIO *out, ASN1_VALUE **fld,
+ const ASN1_ITEM *it, int indent,
+ const char *fname, const char *sname,
+ const ASN1_PCTX *pctx)
+ {
+ long utype;
+ ASN1_STRING *str;
+ int ret = 1, needlf = 1;
+ const char *pname;
+ const ASN1_PRIMITIVE_FUNCS *pf;
+ pf = it->funcs;
+ if (!asn1_print_fsname(out, indent, fname, sname, pctx))
+ return 0;
+ if (pf && pf->prim_print)
+ return pf->prim_print(out, fld, it, indent, pctx);
+ str = (ASN1_STRING *)*fld;
+ if (it->itype == ASN1_ITYPE_MSTRING)
+ utype = str->type & ~V_ASN1_NEG;
+ else
+ utype = it->utype;
+ if (utype == V_ASN1_ANY)
+ {
+ ASN1_TYPE *atype = (ASN1_TYPE *)*fld;
+ utype = atype->type;
+ fld = &atype->value.asn1_value;
+ str = (ASN1_STRING *)*fld;
+ if (pctx->flags & ASN1_PCTX_FLAGS_NO_ANY_TYPE)
+ pname = NULL;
+ else
+ pname = ASN1_tag2str(utype);
+ }
+ else
+ {
+ if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_TYPE)
+ pname = ASN1_tag2str(utype);
+ else
+ pname = NULL;
+ }
+
+ if (utype == V_ASN1_NULL)
+ {
+ if (BIO_puts(out, "NULL\n") <= 0)
+ return 0;
+ return 1;
+ }
+
+ if (pname)
+ {
+ if (BIO_puts(out, pname) <= 0)
+ return 0;
+ if (BIO_puts(out, ":") <= 0)
+ return 0;
+ }
+
+ switch (utype)
+ {
+ case V_ASN1_BOOLEAN:
+ {
+ int boolval = *(int *)fld;
+ if (boolval == -1)
+ boolval = it->size;
+ ret = asn1_print_boolean_ctx(out, boolval, pctx);
+ }
+ break;
+
+ case V_ASN1_INTEGER:
+ case V_ASN1_ENUMERATED:
+ ret = asn1_print_integer_ctx(out, str, pctx);
+ break;
+
+ case V_ASN1_UTCTIME:
+ ret = ASN1_UTCTIME_print(out, str);
+ break;
+
+ case V_ASN1_GENERALIZEDTIME:
+ ret = ASN1_GENERALIZEDTIME_print(out, str);
+ break;
+
+ case V_ASN1_OBJECT:
+ ret = asn1_print_oid_ctx(out, (const ASN1_OBJECT *)*fld, pctx);
+ break;
+
+ case V_ASN1_OCTET_STRING:
+ case V_ASN1_BIT_STRING:
+ ret = asn1_print_obstring_ctx(out, str, indent, pctx);
+ needlf = 0;
+ break;
+
+ case V_ASN1_SEQUENCE:
+ case V_ASN1_SET:
+ case V_ASN1_OTHER:
+ if (BIO_puts(out, "\n") <= 0)
+ return 0;
+ if (ASN1_parse_dump(out, str->data, str->length,
+ indent, 0) <= 0)
+ ret = 0;
+ needlf = 0;
+ break;
+
+ default:
+ ret = ASN1_STRING_print_ex(out, str, pctx->str_flags);
+
+ }
+ if (!ret)
+ return 0;
+ if (needlf && BIO_puts(out, "\n") <= 0)
+ return 0;
+ return 1;
+ }
diff --git a/crypto/asn1/tasn_typ.c b/crypto/asn1/tasn_typ.c
new file mode 100644
index 0000000..f2bbbc8
--- /dev/null
+++ b/crypto/asn1/tasn_typ.c
@@ -0,0 +1,152 @@
+/* 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/asn1.h>
+
+#include <openssl/asn1t.h>
+
+
+/* Declarations for string types */
+
+IMPLEMENT_ASN1_TYPE(ASN1_INTEGER);
+IMPLEMENT_ASN1_FUNCTIONS(ASN1_INTEGER);
+
+IMPLEMENT_ASN1_TYPE(ASN1_ENUMERATED);
+IMPLEMENT_ASN1_FUNCTIONS(ASN1_ENUMERATED);
+
+IMPLEMENT_ASN1_TYPE(ASN1_BIT_STRING);
+IMPLEMENT_ASN1_FUNCTIONS(ASN1_BIT_STRING);
+
+IMPLEMENT_ASN1_TYPE(ASN1_OCTET_STRING);
+IMPLEMENT_ASN1_FUNCTIONS(ASN1_OCTET_STRING);
+
+IMPLEMENT_ASN1_TYPE(ASN1_NULL);
+IMPLEMENT_ASN1_FUNCTIONS(ASN1_NULL);
+
+IMPLEMENT_ASN1_TYPE(ASN1_OBJECT);
+
+IMPLEMENT_ASN1_TYPE(ASN1_UTF8STRING);
+IMPLEMENT_ASN1_FUNCTIONS(ASN1_UTF8STRING);
+
+IMPLEMENT_ASN1_TYPE(ASN1_PRINTABLESTRING);
+IMPLEMENT_ASN1_FUNCTIONS(ASN1_PRINTABLESTRING);
+
+IMPLEMENT_ASN1_TYPE(ASN1_T61STRING);
+IMPLEMENT_ASN1_FUNCTIONS(ASN1_T61STRING);
+
+IMPLEMENT_ASN1_TYPE(ASN1_IA5STRING);
+IMPLEMENT_ASN1_FUNCTIONS(ASN1_IA5STRING);
+
+IMPLEMENT_ASN1_TYPE(ASN1_GENERALSTRING);
+IMPLEMENT_ASN1_FUNCTIONS(ASN1_GENERALSTRING);
+
+IMPLEMENT_ASN1_TYPE(ASN1_UTCTIME);
+IMPLEMENT_ASN1_FUNCTIONS(ASN1_UTCTIME);
+
+IMPLEMENT_ASN1_TYPE(ASN1_GENERALIZEDTIME);
+IMPLEMENT_ASN1_FUNCTIONS(ASN1_GENERALIZEDTIME);
+
+IMPLEMENT_ASN1_TYPE(ASN1_VISIBLESTRING);
+IMPLEMENT_ASN1_FUNCTIONS(ASN1_VISIBLESTRING);
+
+IMPLEMENT_ASN1_TYPE(ASN1_UNIVERSALSTRING);
+IMPLEMENT_ASN1_FUNCTIONS(ASN1_UNIVERSALSTRING);
+
+IMPLEMENT_ASN1_TYPE(ASN1_BMPSTRING);
+IMPLEMENT_ASN1_FUNCTIONS(ASN1_BMPSTRING);
+
+IMPLEMENT_ASN1_TYPE(ASN1_ANY);
+
+/* Just swallow an ASN1_SEQUENCE in an ASN1_STRING */;
+IMPLEMENT_ASN1_TYPE(ASN1_SEQUENCE);
+
+IMPLEMENT_ASN1_FUNCTIONS_fname(ASN1_TYPE, ASN1_ANY, ASN1_TYPE);
+
+/* Multistring types */;
+
+IMPLEMENT_ASN1_MSTRING(ASN1_PRINTABLE, B_ASN1_PRINTABLE);
+IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, ASN1_PRINTABLE);
+
+IMPLEMENT_ASN1_MSTRING(DISPLAYTEXT, B_ASN1_DISPLAYTEXT);
+IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, DISPLAYTEXT);
+
+IMPLEMENT_ASN1_MSTRING(DIRECTORYSTRING, B_ASN1_DIRECTORYSTRING);
+IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, DIRECTORYSTRING);
+
+/* Three separate BOOLEAN type: normal, DEFAULT TRUE and DEFAULT FALSE */;
+IMPLEMENT_ASN1_TYPE_ex(ASN1_BOOLEAN, ASN1_BOOLEAN, -1);
+IMPLEMENT_ASN1_TYPE_ex(ASN1_TBOOLEAN, ASN1_BOOLEAN, 1);
+IMPLEMENT_ASN1_TYPE_ex(ASN1_FBOOLEAN, ASN1_BOOLEAN, 0);
+
+/* Special, OCTET STRING with indefinite length constructed support */;
+
+IMPLEMENT_ASN1_TYPE_ex(ASN1_OCTET_STRING_NDEF, ASN1_OCTET_STRING,
+ ASN1_TFLG_NDEF);
+
+ASN1_ITEM_TEMPLATE(ASN1_SEQUENCE_ANY) = ASN1_EX_TEMPLATE_TYPE(
+ ASN1_TFLG_SEQUENCE_OF, 0, ASN1_SEQUENCE_ANY, ASN1_ANY);
+ASN1_ITEM_TEMPLATE_END(ASN1_SEQUENCE_ANY);
+
+ASN1_ITEM_TEMPLATE(ASN1_SET_ANY) = ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_OF, 0,
+ ASN1_SET_ANY,
+ ASN1_ANY);
+ASN1_ITEM_TEMPLATE_END(ASN1_SET_ANY);
+
+IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(ASN1_SEQUENCE_ANY,
+ ASN1_SEQUENCE_ANY,
+ ASN1_SEQUENCE_ANY);
+IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(ASN1_SEQUENCE_ANY, ASN1_SET_ANY,
+ ASN1_SET_ANY);
diff --git a/crypto/asn1/tasn_utl.c b/crypto/asn1/tasn_utl.c
new file mode 100644
index 0000000..250975a
--- /dev/null
+++ b/crypto/asn1/tasn_utl.c
@@ -0,0 +1,258 @@
+/* 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/asn1.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/err.h>
+
+
+/* Utility functions for manipulating fields and offsets */
+
+/* Add 'offset' to 'addr' */
+#define offset2ptr(addr, offset) (void *)(((char *) addr) + offset)
+
+/* Given an ASN1_ITEM CHOICE type return the selector value */
+int asn1_get_choice_selector(ASN1_VALUE **pval, const ASN1_ITEM *it) {
+ int *sel = offset2ptr(*pval, it->utype);
+ return *sel;
+}
+
+/* Given an ASN1_ITEM CHOICE type set the selector value, return old value. */
+int asn1_set_choice_selector(ASN1_VALUE **pval, int value,
+ const ASN1_ITEM *it) {
+ int *sel, ret;
+ sel = offset2ptr(*pval, it->utype);
+ ret = *sel;
+ *sel = value;
+ return ret;
+}
+
+/* Do reference counting. The value 'op' decides what to do. if it is +1 then
+ * the count is incremented. If op is 0 count is set to 1. If op is -1 count is
+ * decremented and the return value is the current refrence count or 0 if no
+ * reference count exists. */
+int asn1_do_lock(ASN1_VALUE **pval, int op, const ASN1_ITEM *it) {
+ const ASN1_AUX *aux;
+ int *lck, ret;
+ if (it->itype != ASN1_ITYPE_SEQUENCE &&
+ it->itype != ASN1_ITYPE_NDEF_SEQUENCE) {
+ return 0;
+ }
+ aux = it->funcs;
+ if (!aux || !(aux->flags & ASN1_AFLG_REFCOUNT)) {
+ return 0;
+ }
+ lck = offset2ptr(*pval, aux->ref_offset);
+ if (op == 0) {
+ *lck = 1;
+ return 1;
+ }
+ ret = CRYPTO_add(lck, op, aux->ref_lock);
+ return ret;
+}
+
+static ASN1_ENCODING *asn1_get_enc_ptr(ASN1_VALUE **pval, const ASN1_ITEM *it) {
+ const ASN1_AUX *aux;
+ if (!pval || !*pval) {
+ return NULL;
+ }
+ aux = it->funcs;
+ if (!aux || !(aux->flags & ASN1_AFLG_ENCODING)) {
+ return NULL;
+ }
+ return offset2ptr(*pval, aux->enc_offset);
+}
+
+void asn1_enc_init(ASN1_VALUE **pval, const ASN1_ITEM *it) {
+ ASN1_ENCODING *enc;
+ enc = asn1_get_enc_ptr(pval, it);
+ if (enc) {
+ enc->enc = NULL;
+ enc->len = 0;
+ enc->modified = 1;
+ }
+}
+
+void asn1_enc_free(ASN1_VALUE **pval, const ASN1_ITEM *it) {
+ ASN1_ENCODING *enc;
+ enc = asn1_get_enc_ptr(pval, it);
+ if (enc) {
+ if (enc->enc) {
+ OPENSSL_free(enc->enc);
+ }
+ enc->enc = NULL;
+ enc->len = 0;
+ enc->modified = 1;
+ }
+}
+
+int asn1_enc_save(ASN1_VALUE **pval, const unsigned char *in, int inlen,
+ const ASN1_ITEM *it) {
+ ASN1_ENCODING *enc;
+ enc = asn1_get_enc_ptr(pval, it);
+ if (!enc) {
+ return 1;
+ }
+
+ if (enc->enc) {
+ OPENSSL_free(enc->enc);
+ }
+ enc->enc = OPENSSL_malloc(inlen);
+ if (!enc->enc) {
+ return 0;
+ }
+ memcpy(enc->enc, in, inlen);
+ enc->len = inlen;
+ enc->modified = 0;
+
+ return 1;
+}
+
+int asn1_enc_restore(int *len, unsigned char **out, ASN1_VALUE **pval,
+ const ASN1_ITEM *it) {
+ ASN1_ENCODING *enc;
+ enc = asn1_get_enc_ptr(pval, it);
+ if (!enc || enc->modified) {
+ return 0;
+ }
+ if (out) {
+ memcpy(*out, enc->enc, enc->len);
+ *out += enc->len;
+ }
+ if (len) {
+ *len = enc->len;
+ }
+ return 1;
+}
+
+/* Given an ASN1_TEMPLATE get a pointer to a field */
+ASN1_VALUE **asn1_get_field_ptr(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt) {
+ ASN1_VALUE **pvaltmp;
+ if (tt->flags & ASN1_TFLG_COMBINE) {
+ return pval;
+ }
+ pvaltmp = offset2ptr(*pval, tt->offset);
+ /* NOTE for BOOLEAN types the field is just a plain int so we can't return
+ * int **, so settle for (int *). */
+ return pvaltmp;
+}
+
+/* Handle ANY DEFINED BY template, find the selector, look up the relevant
+ * ASN1_TEMPLATE in the table and return it. */
+const ASN1_TEMPLATE *asn1_do_adb(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt,
+ int nullerr) {
+ const ASN1_ADB *adb;
+ const ASN1_ADB_TABLE *atbl;
+ long selector;
+ ASN1_VALUE **sfld;
+ int i;
+ if (!(tt->flags & ASN1_TFLG_ADB_MASK)) {
+ return tt;
+ }
+
+ /* Else ANY DEFINED BY ... get the table */
+ adb = ASN1_ADB_ptr(tt->item);
+
+ /* Get the selector field */
+ sfld = offset2ptr(*pval, adb->offset);
+
+ /* Check if NULL */
+ if (!sfld) {
+ if (!adb->null_tt) {
+ goto err;
+ }
+ return adb->null_tt;
+ }
+
+ /* Convert type to a long:
+ * NB: don't check for NID_undef here because it
+ * might be a legitimate value in the table */
+ if (tt->flags & ASN1_TFLG_ADB_OID) {
+ selector = OBJ_obj2nid((ASN1_OBJECT *)*sfld);
+ } else {
+ selector = ASN1_INTEGER_get((ASN1_INTEGER *)*sfld);
+ }
+
+ /* Try to find matching entry in table Maybe should check application types
+ * first to allow application override? Might also be useful to have a flag
+ * which indicates table is sorted and we can do a binary search. For now
+ * stick to a linear search. */
+
+ for (atbl = adb->tbl, i = 0; i < adb->tblcount; i++, atbl++) {
+ if (atbl->value == selector) {
+ return &atbl->tt;
+ }
+ }
+
+ /* FIXME: need to search application table too */
+
+ /* No match, return default type */
+ if (!adb->default_tt) {
+ goto err;
+ }
+ return adb->default_tt;
+
+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);
+ }
+ return NULL;
+}
diff --git a/crypto/asn1/x_bignum.c b/crypto/asn1/x_bignum.c
new file mode 100644
index 0000000..2ffa093
--- /dev/null
+++ b/crypto/asn1/x_bignum.c
@@ -0,0 +1,136 @@
+/* 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/asn1.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/bn.h>
+
+
+/* Custom primitive type for BIGNUM handling. This reads in an ASN1_INTEGER as a
+ * BIGNUM directly. Currently it ignores the sign which isn't a problem since all
+ * BIGNUMs used are non negative and anything that looks negative is normally due
+ * to an encoding error.
+ */
+
+#define BN_SENSITIVE 1
+
+static int bn_new(ASN1_VALUE **pval, const ASN1_ITEM *it);
+static void bn_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
+
+static int bn_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it);
+static int bn_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it);
+
+static ASN1_PRIMITIVE_FUNCS bignum_pf = {
+ NULL, 0,
+ bn_new,
+ bn_free,
+ 0,
+ bn_c2i,
+ bn_i2c
+};
+
+ASN1_ITEM_start(BIGNUM)
+ ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &bignum_pf, 0, "BIGNUM"
+ASN1_ITEM_end(BIGNUM)
+
+ASN1_ITEM_start(CBIGNUM)
+ ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &bignum_pf, BN_SENSITIVE, "BIGNUM"
+ASN1_ITEM_end(CBIGNUM)
+
+static int bn_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
+{
+ *pval = (ASN1_VALUE *)BN_new();
+ if(*pval) return 1;
+ else return 0;
+}
+
+static void bn_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
+{
+ if(!*pval) return;
+ if(it->size & BN_SENSITIVE) BN_clear_free((BIGNUM *)*pval);
+ else BN_free((BIGNUM *)*pval);
+ *pval = NULL;
+}
+
+static int bn_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it)
+{
+ BIGNUM *bn;
+ int pad;
+ if(!*pval) return -1;
+ bn = (BIGNUM *)*pval;
+ /* If MSB set in an octet we need a padding byte */
+ if(BN_num_bits(bn) & 0x7) pad = 0;
+ else pad = 1;
+ if(cont) {
+ if(pad) *cont++ = 0;
+ BN_bn2bin(bn, cont);
+ }
+ return pad + BN_num_bytes(bn);
+}
+
+static int bn_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
+ int utype, char *free_cont, const ASN1_ITEM *it)
+{
+ BIGNUM *bn;
+ if(!*pval) bn_new(pval, it);
+ bn = (BIGNUM *)*pval;
+ if(!BN_bin2bn(cont, len, bn)) {
+ bn_free(pval, it);
+ return 0;
+ }
+ return 1;
+}
diff --git a/crypto/asn1/x_long.c b/crypto/asn1/x_long.c
new file mode 100644
index 0000000..cb0dad1
--- /dev/null
+++ b/crypto/asn1/x_long.c
@@ -0,0 +1,180 @@
+/* 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/asn1.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/bn.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+/* Custom primitive type for long handling. This converts between an ASN1_INTEGER
+ * and a long directly.
+ */
+
+
+static int long_new(ASN1_VALUE **pval, const ASN1_ITEM *it);
+static void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
+
+static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it);
+static int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it);
+static int long_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it, int indent, const ASN1_PCTX *pctx);
+
+static ASN1_PRIMITIVE_FUNCS long_pf = {
+ NULL, 0,
+ long_new,
+ long_free,
+ long_free, /* Clear should set to initial value */
+ long_c2i,
+ long_i2c,
+ long_print
+};
+
+ASN1_ITEM_start(LONG)
+ ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &long_pf, ASN1_LONG_UNDEF, "LONG"
+ASN1_ITEM_end(LONG)
+
+ASN1_ITEM_start(ZLONG)
+ ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &long_pf, 0, "ZLONG"
+ASN1_ITEM_end(ZLONG)
+
+static int long_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
+{
+ *(long *)pval = it->size;
+ return 1;
+}
+
+static void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
+{
+ *(long *)pval = it->size;
+}
+
+static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it)
+{
+ long ltmp;
+ unsigned long utmp;
+ int clen, pad, i;
+ /* this exists to bypass broken gcc optimization */
+ char *cp = (char *)pval;
+
+ /* use memcpy, because we may not be long aligned */
+ memcpy(<mp, cp, sizeof(long));
+
+ if(ltmp == it->size) return -1;
+ /* Convert the long to positive: we subtract one if negative so
+ * we can cleanly handle the padding if only the MSB of the leading
+ * octet is set.
+ */
+ if(ltmp < 0) utmp = -ltmp - 1;
+ else utmp = ltmp;
+ clen = BN_num_bits_word(utmp);
+ /* If MSB of leading octet set we need to pad */
+ if(!(clen & 0x7)) pad = 1;
+ else pad = 0;
+
+ /* Convert number of bits to number of octets */
+ clen = (clen + 7) >> 3;
+
+ if(cont) {
+ if(pad) *cont++ = (ltmp < 0) ? 0xff : 0;
+ for(i = clen - 1; i >= 0; i--) {
+ cont[i] = (unsigned char)(utmp & 0xff);
+ if(ltmp < 0) cont[i] ^= 0xff;
+ utmp >>= 8;
+ }
+ }
+ return clen + pad;
+}
+
+static int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
+ int utype, char *free_cont, const ASN1_ITEM *it)
+{
+ int neg, i;
+ long ltmp;
+ 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);
+ return 0;
+ }
+ /* Is it negative? */
+ if(len && (cont[0] & 0x80)) neg = 1;
+ else neg = 0;
+ utmp = 0;
+ for(i = 0; i < len; i++) {
+ utmp <<= 8;
+ if(neg) utmp |= cont[i] ^ 0xff;
+ else utmp |= cont[i];
+ }
+ ltmp = (long)utmp;
+ if(neg) {
+ ltmp++;
+ ltmp = -ltmp;
+ }
+ if(ltmp == it->size) {
+ OPENSSL_PUT_ERROR(ASN1, long_c2i, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG);
+ return 0;
+ }
+ memcpy(cp, <mp, sizeof(long));
+ return 1;
+}
+
+static int long_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it,
+ int indent, const ASN1_PCTX *pctx)
+ {
+ return BIO_printf(out, "%ld\n", *(long *)pval);
+ }
diff --git a/crypto/base.h b/crypto/base.h
new file mode 100644
index 0000000..d4b4028
--- /dev/null
+++ b/crypto/base.h
@@ -0,0 +1,167 @@
+/* ====================================================================
+ * Copyright (c) 1998-2001 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_BASE_H
+#define OPENSSL_HEADER_BASE_H
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+
+#if defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64)
+#define OPENSSL_64_BIT
+#define OPENSSL_X86_64
+#elif defined(__x86) || defined(__i386) || defined(__i386__) || defined(_M_IX86)
+#define OPENSSL_32_BIT
+#define OPENSSL_X86
+#elif defined(__aarch64__)
+#define OPENSSL_64_BIT
+#define OPENSSL_AARCH64
+#elif defined(__arm) || defined(__arm__) || defined(_M_ARM)
+#define OPENSSL_32_BIT
+#define OPENSSL_ARM
+#else
+#error "Unknown target CPU"
+#endif
+
+#define OPENSSL_IS_BORINGSSL
+#define OPENSSL_VERSION_NUMBER 0x10002000
+
+
+/* This file should be the first included by all BoringSSL headers. */
+
+typedef int ASN1_BOOLEAN;
+typedef int ASN1_NULL;
+typedef struct ASN1_ITEM_st ASN1_ITEM;
+typedef struct asn1_object_st ASN1_OBJECT;
+typedef struct asn1_pctx_st ASN1_PCTX;
+typedef struct asn1_string_st ASN1_BIT_STRING;
+typedef struct asn1_string_st ASN1_BMPSTRING;
+typedef struct asn1_string_st ASN1_ENUMERATED;
+typedef struct asn1_string_st ASN1_GENERALIZEDTIME;
+typedef struct asn1_string_st ASN1_GENERALSTRING;
+typedef struct asn1_string_st ASN1_IA5STRING;
+typedef struct asn1_string_st ASN1_INTEGER;
+typedef struct asn1_string_st ASN1_OCTET_STRING;
+typedef struct asn1_string_st ASN1_PRINTABLESTRING;
+typedef struct asn1_string_st ASN1_STRING;
+typedef struct asn1_string_st ASN1_T61STRING;
+typedef struct asn1_string_st ASN1_TIME;
+typedef struct asn1_string_st ASN1_UNIVERSALSTRING;
+typedef struct asn1_string_st ASN1_UTCTIME;
+typedef struct asn1_string_st ASN1_UTF8STRING;
+typedef struct asn1_string_st ASN1_VISIBLESTRING;
+
+typedef struct AUTHORITY_KEYID_st AUTHORITY_KEYID;
+typedef struct DIST_POINT_st DIST_POINT;
+typedef struct ISSUING_DIST_POINT_st ISSUING_DIST_POINT;
+typedef struct NAME_CONSTRAINTS_st NAME_CONSTRAINTS;
+typedef struct X509_POLICY_CACHE_st X509_POLICY_CACHE;
+typedef struct X509_POLICY_LEVEL_st X509_POLICY_LEVEL;
+typedef struct X509_POLICY_NODE_st X509_POLICY_NODE;
+typedef struct X509_POLICY_TREE_st X509_POLICY_TREE;
+typedef struct X509_algor_st X509_ALGOR;
+typedef struct X509_crl_st X509_CRL;
+typedef struct X509_name_st X509_NAME;
+typedef struct X509_pubkey_st X509_PUBKEY;
+typedef struct bignum_ctx BN_CTX;
+typedef struct bignum_st BIGNUM;
+typedef struct bio_method_st BIO_METHOD;
+typedef struct bio_st BIO;
+typedef struct bn_gencb_st BN_GENCB;
+typedef struct bn_mont_ctx_st BN_MONT_CTX;
+typedef struct buf_mem_st BUF_MEM;
+typedef struct cbb_st CBB;
+typedef struct cbs_st CBS;
+typedef struct comp_ctx_st COMP_CTX;
+typedef struct comp_method_st COMP_METHOD;
+typedef struct conf_st CONF;
+typedef struct dh_method DH_METHOD;
+typedef struct dh_st DH;
+typedef struct dsa_method DSA_METHOD;
+typedef struct dsa_st DSA;
+typedef struct ec_key_st EC_KEY;
+typedef struct ecdsa_method_st ECDSA_METHOD;
+typedef struct ecdsa_sig_st ECDSA_SIG;
+typedef struct engine_st ENGINE;
+typedef struct env_md_ctx_st EVP_MD_CTX;
+typedef struct env_md_st EVP_MD;
+typedef struct evp_cipher_ctx_st EVP_CIPHER_CTX;
+typedef struct evp_cipher_st EVP_CIPHER;
+typedef struct evp_pkey_asn1_method_st EVP_PKEY_ASN1_METHOD;
+typedef struct evp_pkey_ctx_st EVP_PKEY_CTX;
+typedef struct evp_pkey_method_st EVP_PKEY_METHOD;
+typedef struct evp_pkey_st EVP_PKEY;
+typedef struct hmac_ctx_st HMAC_CTX;
+typedef struct md5_state_st MD5_CTX;
+typedef struct pkcs8_priv_key_info_st PKCS8_PRIV_KEY_INFO;
+typedef struct rand_meth_st RAND_METHOD;
+typedef struct rsa_meth_st RSA_METHOD;
+typedef struct rsa_st RSA;
+typedef struct sha256_state_st SHA256_CTX;
+typedef struct sha512_state_st SHA512_CTX;
+typedef struct sha_state_st SHA_CTX;
+typedef struct ssl_ctx_st SSL_CTX;
+typedef struct ssl_st SSL;
+typedef struct st_ERR_FNS ERR_FNS;
+typedef struct v3_ext_ctx X509V3_CTX;
+typedef struct x509_crl_method_st X509_CRL_METHOD;
+typedef struct x509_revoked_st X509_REVOKED;
+typedef struct x509_st X509;
+typedef struct x509_store_ctx_st X509_STORE_CTX;
+typedef struct x509_store_st X509_STORE;
+typedef void *OPENSSL_BLOCK;
+
+
+#endif /* OPENSSL_HEADER_BASE_H */
diff --git a/crypto/base64/CMakeLists.txt b/crypto/base64/CMakeLists.txt
new file mode 100644
index 0000000..2601abd
--- /dev/null
+++ b/crypto/base64/CMakeLists.txt
@@ -0,0 +1,9 @@
+include_directories(. .. ../../include)
+
+add_library(
+ base64
+
+ OBJECT
+
+ base64.c
+)
diff --git a/crypto/base64/base64.c b/crypto/base64/base64.c
new file mode 100644
index 0000000..fb9aa36
--- /dev/null
+++ b/crypto/base64/base64.c
@@ -0,0 +1,391 @@
+/* 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/base64.h>
+
+#include <assert.h>
+
+
+static const unsigned char data_bin2ascii[65] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+#define conv_bin2ascii(a) (data_bin2ascii[(a) & 0x3f])
+#define conv_ascii2bin(a) (data_ascii2bin[(a) & 0x7f])
+
+/* 64 char lines
+ * pad input with 0
+ * left over chars are set to =
+ * 1 byte => xx==
+ * 2 bytes => xxx=
+ * 3 bytes => xxxx
+ */
+#define BIN_PER_LINE (64/4*3)
+#define CHUNKS_PER_LINE (64/4)
+#define CHAR_PER_LINE (64+1)
+
+/* 0xF0 is a EOLN
+ * 0xF1 is ignore but next needs to be 0xF0 (for \r\n processing).
+ * 0xF2 is EOF
+ * 0xE0 is ignore at start of line.
+ * 0xFF is error */
+
+#define B64_EOLN 0xF0
+#define B64_CR 0xF1
+#define B64_EOF 0xF2
+#define B64_WS 0xE0
+#define B64_ERROR 0xFF
+#define B64_NOT_BASE64(a) (((a) | 0x13) == 0xF3)
+
+static const unsigned char data_ascii2bin[128] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xF0, 0xFF,
+ 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xF2, 0xFF, 0x3F,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF,
+ 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12,
+ 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
+ 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
+ 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+};
+
+void EVP_EncodeInit(EVP_ENCODE_CTX *ctx) {
+ ctx->length = 48;
+ ctx->num = 0;
+ ctx->line_num = 0;
+}
+
+void EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len,
+ const uint8_t *in, size_t in_len) {
+ unsigned i, j;
+ unsigned total = 0;
+
+ *out_len = 0;
+ if (in_len == 0) {
+ return;
+ }
+
+ assert(ctx->length <= sizeof(ctx->enc_data));
+
+ if ((ctx->num + in_len) < ctx->length) {
+ memcpy(&ctx->enc_data[ctx->num], in, in_len);
+ ctx->num += in_len;
+ return;
+ }
+ if (ctx->num != 0) {
+ i = ctx->length - ctx->num;
+ memcpy(&ctx->enc_data[ctx->num], in, i);
+ in += i;
+ in_len -= i;
+ j = EVP_EncodeBlock(out, ctx->enc_data, ctx->length);
+ ctx->num = 0;
+ out += j;
+ *(out++) = '\n';
+ *out = '\0';
+ total = j + 1;
+ }
+ while (in_len >= ctx->length) {
+ j = EVP_EncodeBlock(out, in, ctx->length);
+ in += ctx->length;
+ in_len -= ctx->length;
+ out += j;
+ *(out++) = '\n';
+ *out = '\0';
+ total += j + 1;
+ }
+ if (in_len != 0) {
+ memcpy(&ctx->enc_data[0], in, in_len);
+ }
+ ctx->num = in_len;
+ *out_len = total;
+}
+
+void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len) {
+ unsigned ret = 0;
+
+ if (ctx->num != 0) {
+ ret = EVP_EncodeBlock(out, ctx->enc_data, ctx->num);
+ out[ret++] = '\n';
+ out[ret] = '\0';
+ ctx->num = 0;
+ }
+ *out_len = ret;
+}
+
+size_t EVP_EncodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) {
+ unsigned long l;
+ size_t i, ret = 0;
+
+ for (i = src_len; i > 0; i -= 3) {
+ if (i >= 3) {
+ l = (((unsigned long)src[0]) << 16L) | (((unsigned long)src[1]) << 8L) | src[2];
+ *(dst++) = conv_bin2ascii(l >> 18L);
+ *(dst++) = conv_bin2ascii(l >> 12L);
+ *(dst++) = conv_bin2ascii(l >> 6L);
+ *(dst++) = conv_bin2ascii(l);
+ } else {
+ l = ((unsigned long)src[0]) << 16L;
+ if (i == 2) {
+ l |= ((unsigned long)src[1] << 8L);
+ }
+
+ *(dst++) = conv_bin2ascii(l >> 18L);
+ *(dst++) = conv_bin2ascii(l >> 12L);
+ *(dst++) = (i == 1) ? '=' : conv_bin2ascii(l >> 6L);
+ *(dst++) = '=';
+ }
+ ret += 4;
+ src += 3;
+ }
+
+ *dst = '\0';
+ return ret;
+}
+
+void EVP_DecodeInit(EVP_ENCODE_CTX *ctx) {
+ ctx->length = 30;
+ ctx->num = 0;
+ ctx->line_num = 0;
+ ctx->expect_nl = 0;
+}
+
+int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len,
+ const uint8_t *in, size_t in_len) {
+ int seof = -1, eof = 0, rv = -1, v, tmp, exp_nl;
+ uint8_t *d;
+ unsigned i, n, ln, ret = 0;
+
+ n = ctx->num;
+ d = ctx->enc_data;
+ ln = ctx->line_num;
+ exp_nl = ctx->expect_nl;
+
+ /* last line of input. */
+ if (in_len == 0 || (n == 0 && conv_ascii2bin(in[0]) == B64_EOF)) {
+ rv = 0;
+ goto end;
+ }
+
+ /* We parse the input data */
+ for (i = 0; i < in_len; i++) {
+ /* If the current line is > 80 characters, scream alot */
+ if (ln >= 80) {
+ rv = -1;
+ goto end;
+ }
+
+ /* Get char and put it into the buffer */
+ tmp = *(in++);
+ v = conv_ascii2bin(tmp);
+ /* only save the good data :-) */
+ if (!B64_NOT_BASE64(v)) {
+ assert(n < sizeof(ctx->enc_data));
+ d[n++] = tmp;
+ ln++;
+ } else if (v == B64_ERROR) {
+ rv = -1;
+ goto end;
+ }
+
+ /* have we seen a '=' which is 'definitly' the last
+ * input line. seof will point to the character that
+ * holds it. and eof will hold how many characters to
+ * chop off. */
+ if (tmp == '=') {
+ if (seof == -1) {
+ seof = n;
+ }
+ eof++;
+ }
+
+ if (v == B64_CR) {
+ ln = 0;
+ if (exp_nl) {
+ continue;
+ }
+ }
+
+ /* eoln */
+ if (v == B64_EOLN) {
+ ln = 0;
+ if (exp_nl) {
+ exp_nl = 0;
+ continue;
+ }
+ }
+ exp_nl = 0;
+
+ /* If we are at the end of input and it looks like a
+ * line, process it. */
+ if ((i + 1) == in_len && (((n & 3) == 0) || eof)) {
+ v = B64_EOF;
+ /* In case things were given us in really small
+ records (so two '=' were given in separate
+ updates), eof may contain the incorrect number
+ of ending bytes to skip, so let's redo the count */
+ eof = 0;
+ if (d[n - 1] == '=') {
+ eof++;
+ }
+ if (d[n - 2] == '=') {
+ eof++;
+ }
+ /* There will never be more than two '=' */
+ }
+
+ if ((v == B64_EOF && (n & 3) == 0) || n >= 64) {
+ /* This is needed to work correctly on 64 byte input
+ * lines. We process the line and then need to
+ * accept the '\n' */
+ if (v != B64_EOF && n >= 64) {
+ exp_nl = 1;
+ }
+ if (n > 0) {
+ v = EVP_DecodeBlock(out, d, n);
+ n = 0;
+ if (v < 0) {
+ rv = 0;
+ goto end;
+ }
+ ret += (v - eof);
+ } else {
+ eof = 1;
+ v = 0;
+ }
+
+ /* This is the case where we have had a short
+ * but valid input line */
+ if (v < (int)ctx->length && eof) {
+ rv = 0;
+ goto end;
+ } else {
+ ctx->length = v;
+ }
+
+ if (seof >= 0) {
+ rv = 0;
+ goto end;
+ }
+ out += v;
+ }
+ }
+ rv = 1;
+
+end:
+ *out_len = ret;
+ ctx->num = n;
+ ctx->line_num = ln;
+ ctx->expect_nl = exp_nl;
+ return rv;
+}
+
+int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, int *outl) {
+ int i;
+
+ *outl = 0;
+ if (ctx->num != 0) {
+ i = EVP_DecodeBlock(out, ctx->enc_data, ctx->num);
+ if (i < 0) {
+ return -1;
+ }
+ ctx->num = 0;
+ *outl = i;
+ return 1;
+ } else {
+ return 1;
+ }
+}
+
+size_t EVP_DecodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) {
+ int a, b, c, d;
+ unsigned long l;
+ size_t i, ret = 0;
+
+ /* trim white space from the start of the line. */
+ while (conv_ascii2bin(*src) == B64_WS && src_len > 0) {
+ src++;
+ src_len--;
+ }
+
+ /* strip off stuff at the end of the line
+ * ascii2bin values B64_WS, B64_EOLN, B64_EOLN and B64_EOF */
+ while (src_len > 3 && B64_NOT_BASE64(conv_ascii2bin(src[src_len - 1]))) {
+ src_len--;
+ }
+
+ if (src_len % 4 != 0) {
+ return -1;
+ }
+
+ for (i = 0; i < src_len; i += 4) {
+ a = conv_ascii2bin(*(src++));
+ b = conv_ascii2bin(*(src++));
+ c = conv_ascii2bin(*(src++));
+ d = conv_ascii2bin(*(src++));
+ if ((a & 0x80) || (b & 0x80) || (c & 0x80) || (d & 0x80)) {
+ return -1;
+ }
+ l = ((((unsigned long)a) << 18L) | (((unsigned long)b) << 12L) |
+ (((unsigned long)c) << 6L) | (((unsigned long)d)));
+ *(dst++) = (uint8_t)(l >> 16L) & 0xff;
+ *(dst++) = (uint8_t)(l >> 8L) & 0xff;
+ *(dst++) = (uint8_t)(l) & 0xff;
+ ret += 3;
+ }
+
+ return ret;
+}
diff --git a/crypto/base64/base64.h b/crypto/base64/base64.h
new file mode 100644
index 0000000..afafaef
--- /dev/null
+++ b/crypto/base64/base64.h
@@ -0,0 +1,141 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_BASE64_H
+#define OPENSSL_HEADER_BASE64_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* base64 functions.
+ *
+ * For historical reasons, these functions have the EVP_ prefix but just do
+ * base64 encoding and decoding. */
+
+
+typedef struct evp_encode_ctx_st EVP_ENCODE_CTX;
+
+
+/* Encoding */
+
+/* EVP_EncodeInit initialises |*ctx|, which is typically stack allocated, for
+ * an encoding operation. */
+void EVP_EncodeInit(EVP_ENCODE_CTX *ctx);
+
+/* EVP_EncodeUpdate encodes |in_len| bytes from |in| and writes an encoded
+ * version of them to |out| and sets |*out_len| to the number of bytes written.
+ * Some state may be contained in |ctx| so |EVP_EncodeFinal| must be used to
+ * flush it before using the encoded data. */
+void EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len,
+ const uint8_t *in, size_t in_len);
+
+/* EVP_EncodeFinal flushes any remaining output bytes from |ctx| to |out| and
+ * sets |*out_len| to the number of bytes written. */
+void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len);
+
+/* EVP_EncodeBlock encodes |src_len| bytes from |src| and writes the result to
+ * |dst|. It returns the number of bytes written. */
+size_t EVP_EncodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len);
+
+
+/* Decoding */
+
+/* EVP_DecodeInit initialises |*ctx|, which is typically stack allocated, for
+ * a decoding operation. */
+void EVP_DecodeInit(EVP_ENCODE_CTX *ctx);
+
+/* EVP_DecodeUpdate decodes |in_len| bytes from |in| and writes the decoded
+ * data to |out| and sets |*out_len| to the number of bytes written. Some state
+ * may be contained in |ctx| so |EVP_DecodeFinal| must be used to flush it
+ * before using the encoded data.
+ *
+ * It returns -1 on error, one if a full line of input was processed and zero
+ * if the line was short (i.e. it was the last line). */
+int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len,
+ const uint8_t *in, size_t in_len);
+
+/* EVP_DecodeFinal flushes any remaining output bytes from |ctx| to |out| and
+ * sets |*out_len| to the number of bytes written. It returns one on success
+ * and minus one on error. */
+int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len);
+
+/* EVP_DecodeBlock encodes |src_len| bytes from |src| and writes the result to
+ * |dst|. It returns the number of bytes written. */
+size_t EVP_DecodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len);
+
+
+struct evp_encode_ctx_st {
+ unsigned num; /* number saved in a partial encode/decode */
+ unsigned length; /* The length is either the output line length
+ * (in input bytes) or the shortest input line
+ * length that is ok. Once decoding begins,
+ * the length is adjusted up each time a longer
+ * line is decoded */
+ uint8_t enc_data[80]; /* data to encode */
+ unsigned line_num; /* number read on current line */
+ int expect_nl;
+};
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_BASE64_H */
diff --git a/crypto/bio/CMakeLists.txt b/crypto/bio/CMakeLists.txt
new file mode 100644
index 0000000..86092f0
--- /dev/null
+++ b/crypto/bio/CMakeLists.txt
@@ -0,0 +1,28 @@
+include_directories(. .. ../../include)
+
+add_library(
+ bio
+
+ OBJECT
+
+ bio.c
+ bio_error.c
+ bio_mem.c
+ buffer.c
+ connect.c
+ fd.c
+ file.c
+ hexdump.c
+ pair.c
+ printf.c
+ socket.c
+ socket_helper.c
+)
+
+add_executable(
+ bio_test
+
+ bio_test.c
+)
+
+target_link_libraries(bio_test crypto)
diff --git a/crypto/bio/bio.c b/crypto/bio/bio.c
new file mode 100644
index 0000000..d9f7f40
--- /dev/null
+++ b/crypto/bio/bio.c
@@ -0,0 +1,452 @@
+/* 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/bio.h>
+
+#include <errno.h>
+#include <stddef.h>
+#include <limits.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/thread.h>
+
+
+/* BIO_set initialises a BIO structure to have the given type and sets the
+ * reference count to one. It returns one on success or zero on error. */
+static int bio_set(BIO *bio, const BIO_METHOD *method) {
+ /* This function can be called with a stack allocated |BIO| so we have to
+ * assume that the contents of |BIO| are arbitary. This also means that it'll
+ * leak memory if you call |BIO_set| twice on the same BIO. */
+ memset(bio, 0, sizeof(BIO));
+
+ bio->method = method;
+ bio->shutdown = 1;
+ bio->references = 1;
+
+ if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data)) {
+ return 0;
+ }
+
+ if (method->create != NULL) {
+ if (!method->create(bio)) {
+ CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+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);
+ return NULL;
+ }
+
+ if (!bio_set(ret, method)) {
+ OPENSSL_free(ret);
+ ret = NULL;
+ }
+
+ return ret;
+}
+
+int BIO_free(BIO *bio) {
+ BIO *next_bio;
+
+ for (; bio != NULL; bio = next_bio) {
+ int refs = CRYPTO_add(&bio->references, -1, CRYPTO_LOCK_BIO);
+ if (refs > 0) {
+ return 0;
+ }
+
+ if (bio->callback != NULL) {
+ int i = (int)bio->callback(bio, BIO_CB_FREE, NULL, 0, 0, 1);
+ if (i <= 0) {
+ return i;
+ }
+ }
+
+ next_bio = BIO_pop(bio);
+
+ CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data);
+
+ if (bio->method != NULL && bio->method->destroy != NULL) {
+ bio->method->destroy(bio);
+ }
+
+ OPENSSL_free(bio);
+ }
+ return 1;
+}
+
+void BIO_vfree(BIO *bio) {
+ BIO_free(bio);
+}
+
+void BIO_free_all(BIO *bio) {
+ BIO_free(bio);
+}
+
+static int bio_io(BIO *bio, void *buf, int len, size_t method_offset,
+ int callback_flags, unsigned long *num) {
+ int i;
+ typedef int (*io_func_t)(BIO *, char *, int);
+ io_func_t io_func = NULL;
+
+ if (bio != NULL && bio->method != NULL) {
+ io_func =
+ *((const io_func_t *)(((const uint8_t *)bio->method) + method_offset));
+ }
+
+ if (io_func == NULL) {
+ OPENSSL_PUT_ERROR(BIO, bio_io, BIO_R_UNSUPPORTED_METHOD);
+ return -2;
+ }
+
+ if (bio->callback != NULL) {
+ i = (int) bio->callback(bio, callback_flags, buf, len, 0L, 1L);
+ if (i <= 0) {
+ return i;
+ }
+ }
+
+ if (!bio->init) {
+ OPENSSL_PUT_ERROR(BIO, bio_io, BIO_R_UNINITIALIZED);
+ return -2;
+ }
+
+ i = 0;
+ if (buf != NULL && len > 0) {
+ i = io_func(bio, buf, len);
+ }
+
+ if (i > 0) {
+ *num += i;
+ }
+
+ if (bio->callback != NULL) {
+ i = (int)(bio->callback(bio, callback_flags | BIO_CB_RETURN, buf, len, 0L,
+ (long)i));
+ }
+
+ return i;
+}
+
+int BIO_read(BIO *bio, void *buf, int len) {
+ return bio_io(bio, buf, len, offsetof(BIO_METHOD, bread), BIO_CB_READ,
+ &bio->num_read);
+}
+
+int BIO_gets(BIO *bio, char *buf, int len) {
+ return bio_io(bio, buf, len, offsetof(BIO_METHOD, bgets), BIO_CB_GETS,
+ &bio->num_read);
+}
+
+int BIO_write(BIO *bio, const void *in, int inl) {
+ return bio_io(bio, (char *)in, inl, offsetof(BIO_METHOD, bwrite),
+ BIO_CB_WRITE, &bio->num_write);
+}
+
+int BIO_puts(BIO *bio, const char *in) {
+ return BIO_write(bio, in, strlen(in));
+}
+
+int BIO_flush(BIO *bio) {
+ return BIO_ctrl(bio, BIO_CTRL_FLUSH, 0, NULL);
+}
+
+long BIO_ctrl(BIO *bio, int cmd, long larg, void *parg) {
+ long ret;
+
+ if (bio == NULL) {
+ return 0;
+ }
+
+ if (bio->method == NULL || bio->method->ctrl == NULL) {
+ OPENSSL_PUT_ERROR(BIO, BIO_ctrl, BIO_R_UNSUPPORTED_METHOD);
+ return -2;
+ }
+
+ if (bio->callback != NULL) {
+ ret = bio->callback(bio, BIO_CB_CTRL, parg, cmd, larg, 1);
+ if (ret <= 0) {
+ return ret;
+ }
+ }
+
+ ret = bio->method->ctrl(bio, cmd, larg, parg);
+
+ if (bio->callback != NULL) {
+ ret = bio->callback(bio, BIO_CB_CTRL | BIO_CB_RETURN, parg, cmd, larg, ret);
+ }
+
+ return ret;
+}
+
+char *BIO_ptr_ctrl(BIO *b, int cmd, long larg) {
+ char *p = NULL;
+
+ if (BIO_ctrl(b, cmd, larg, (void *)&p) <= 0) {
+ return NULL;
+ }
+
+ return p;
+}
+
+long BIO_int_ctrl(BIO *b, int cmd, long larg, int iarg) {
+ int i = iarg;
+
+ return BIO_ctrl(b, cmd, larg, (void *)&i);
+}
+
+int BIO_reset(BIO *bio) {
+ return BIO_ctrl(bio, BIO_CTRL_RESET, 0, NULL);
+}
+
+void BIO_set_flags(BIO *bio, int flags) {
+ bio->flags |= flags;
+}
+
+int BIO_test_flags(const BIO *bio, int flags) {
+ return bio->flags & flags;
+}
+
+int BIO_should_read(const BIO *bio) {
+ return BIO_test_flags(bio, BIO_FLAGS_READ);
+}
+
+int BIO_should_write(const BIO *bio) {
+ return BIO_test_flags(bio, BIO_FLAGS_WRITE);
+}
+
+int BIO_should_retry(const BIO *bio) {
+ return BIO_test_flags(bio, BIO_FLAGS_SHOULD_RETRY);
+}
+
+int BIO_should_io_special(const BIO *bio) {
+ return BIO_test_flags(bio, BIO_FLAGS_IO_SPECIAL);
+}
+
+int BIO_get_retry_reason(const BIO *bio) { return bio->retry_reason; }
+
+void BIO_clear_flags(BIO *bio, int flags) {
+ bio->flags &= ~flags;
+}
+
+void BIO_set_retry_read(BIO *bio) {
+ bio->flags |= BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY;
+}
+
+void BIO_set_retry_write(BIO *bio) {
+ bio->flags |= BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY;
+}
+
+static const int kRetryFlags = BIO_FLAGS_RWS | BIO_FLAGS_SHOULD_RETRY;
+
+int BIO_get_retry_flags(BIO *bio) {
+ return bio->flags & kRetryFlags;
+}
+
+void BIO_clear_retry_flags(BIO *bio) {
+ bio->flags &= ~kRetryFlags;
+ bio->retry_reason = 0;
+}
+
+int BIO_method_type(const BIO *bio) { return bio->method->type; }
+
+void BIO_copy_next_retry(BIO *bio) {
+ BIO_clear_retry_flags(bio);
+ BIO_set_flags(bio, BIO_get_retry_flags(bio->next_bio));
+ bio->retry_reason = bio->next_bio->retry_reason;
+}
+
+long BIO_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) {
+ long ret;
+ bio_info_cb cb;
+
+ if (bio == NULL) {
+ return 0;
+ }
+
+ if (bio->method == NULL || bio->method->callback_ctrl == NULL) {
+ OPENSSL_PUT_ERROR(BIO, BIO_callback_ctrl, BIO_R_UNSUPPORTED_METHOD);
+ return 0;
+ }
+
+ cb = bio->callback;
+
+ if (cb != NULL) {
+ ret = cb(bio, BIO_CB_CTRL, (void *)&fp, cmd, 0, 1L);
+ if (ret <= 0) {
+ return ret;
+ }
+ }
+
+ ret = bio->method->callback_ctrl(bio, cmd, fp);
+
+ if (cb != NULL) {
+ ret = cb(bio, BIO_CB_CTRL | BIO_CB_RETURN, (void *)&fp, cmd, 0, ret);
+ }
+
+ return ret;
+}
+
+size_t BIO_pending(const BIO *bio) {
+ return BIO_ctrl((BIO *) bio, BIO_CTRL_PENDING, 0, NULL);
+}
+
+size_t BIO_wpending(const BIO *bio) {
+ return BIO_ctrl((BIO *) bio, BIO_CTRL_WPENDING, 0, NULL);
+}
+
+int BIO_set_close(BIO *bio, int close_flag) {
+ return BIO_ctrl(bio, BIO_CTRL_SET_CLOSE, close_flag, NULL);
+}
+
+BIO *BIO_push(BIO *bio, BIO *appended_bio) {
+ BIO *last_bio;
+
+ if (bio == NULL) {
+ return bio;
+ }
+
+ last_bio = bio;
+ while (last_bio->next_bio != NULL) {
+ last_bio = last_bio->next_bio;
+ }
+
+ last_bio->next_bio = appended_bio;
+ /* TODO(fork): this seems very suspect. If we got rid of BIO SSL, we could
+ * get rid of this. */
+ BIO_ctrl(bio, BIO_CTRL_PUSH, 0, bio);
+
+ return bio;
+}
+
+BIO *BIO_pop(BIO *bio) {
+ BIO *ret;
+
+ if (bio == NULL) {
+ return NULL;
+ }
+ ret = bio->next_bio;
+ BIO_ctrl(bio, BIO_CTRL_POP, 0, bio);
+ bio->next_bio = NULL;
+ return ret;
+}
+
+BIO *BIO_next(BIO *bio) {
+ if (!bio) {
+ return NULL;
+ }
+ return bio->next_bio;
+}
+
+BIO *BIO_find_type(BIO *bio, int type) {
+ int method_type, mask;
+
+ if (!bio) {
+ return NULL;
+ }
+ mask = type & 0xff;
+
+ do {
+ if (bio->method != NULL) {
+ method_type = bio->method->type;
+
+ if (!mask) {
+ if (method_type & type) {
+ return bio;
+ }
+ } else if (method_type == type) {
+ return bio;
+ }
+ }
+ bio = bio->next_bio;
+ } while (bio != NULL);
+
+ return NULL;
+}
+
+int BIO_indent(BIO *bio, unsigned indent, unsigned max_indent) {
+ if (indent > max_indent) {
+ indent = max_indent;
+ }
+
+ while (indent--) {
+ if (BIO_puts(bio, " ") != 1) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+void BIO_print_errors_fp(FILE *out) {
+ BIO *bio = BIO_new_fp(out, BIO_NOCLOSE);
+ BIO_print_errors(bio);
+ BIO_free(bio);
+}
+
+static int print_bio(const char *str, size_t len, void *bio) {
+ return BIO_write((BIO *)bio, str, len);
+}
+
+void BIO_print_errors(BIO *bio) {
+ ERR_print_errors_cb(print_bio, bio);
+}
diff --git a/crypto/bio/bio.h b/crypto/bio/bio.h
new file mode 100644
index 0000000..76054c3
--- /dev/null
+++ b/crypto/bio/bio.h
@@ -0,0 +1,790 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_BIO_H
+#define OPENSSL_HEADER_BIO_H
+
+#include <openssl/base.h>
+
+#include <stdarg.h>
+#include <stdio.h> /* For FILE */
+
+#include <openssl/ex_data.h>
+#include <openssl/stack.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* BIO abstracts over a file-descriptor like interface. */
+
+
+/* Allocation and freeing. */
+
+DEFINE_STACK_OF(BIO);
+
+/* BIO_new creates a new BIO with the given type and a reference count of one.
+ * It returns the fresh |BIO|, or NULL on error. */
+BIO *BIO_new(const BIO_METHOD *type);
+
+/* BIO_free decrements the reference count of |bio|. If the reference count
+ * drops to zero, it (optionally) calls the BIO's callback with |BIO_CB_FREE|,
+ * frees the ex_data and then, if the BIO has a destroy callback for the
+ * method, calls it. Finally it frees |bio| itself. It then repeats that for
+ * the next BIO in the chain, if any.
+ *
+ * It returns one on success or zero otherwise. */
+int BIO_free(BIO *bio);
+
+/* BIO_vfree performs the same actions as |BIO_free|, but has a void return
+ * value. This is provided for API-compat.
+ *
+ * TODO(fork): remove. */
+void BIO_vfree(BIO *bio);
+
+
+/* Basic I/O. */
+
+/* BIO_read attempts to read |len| bytes into |data|. It returns the number of
+ * bytes read, zero on EOF, or a negative number on error. */
+int BIO_read(BIO *bio, void *data, int len);
+
+/* BIO_gets "reads a line" from |bio| and puts at most |size| bytes into |buf|.
+ * It returns the number of bytes read or a negative number on error. The
+ * phrase "reads a line" is in quotes in the previous sentence because the
+ * exact operation depends on the BIO's method. For example, a digest BIO will
+ * return the digest in response to a |BIO_gets| call.
+ *
+ * TODO(fork): audit the set of BIOs that we end up needing. If all actually
+ * return a line for this call, remove the warning above. */
+int BIO_gets(BIO *bio, char *buf, int size);
+
+/* BIO_write writes |len| bytes from |data| to BIO. It returns the number of
+ * bytes written or a negative number on error. */
+int BIO_write(BIO *bio, const void *data, int len);
+
+/* BIO_puts writes a NUL terminated string from |buf| to |bio|. It returns the
+ * number of bytes written or a negative number on error. */
+int BIO_puts(BIO *bio, const char *buf);
+
+/* BIO_flush flushes any buffered output. It returns one on success and zero
+ * otherwise. */
+int BIO_flush(BIO *bio);
+
+
+/* Low-level control functions.
+ *
+ * These are generic functions for sending control requests to a BIO. In
+ * general one should use the wrapper functions like |BIO_get_close|. */
+
+/* BIO_ctrl sends the control request |cmd| to |bio|. The |cmd| argument should
+ * be one of the |BIO_C_*| values. */
+long BIO_ctrl(BIO *bio, int cmd, long larg, void *parg);
+
+/* BIO_ptr_ctrl acts like |BIO_ctrl| but passes the address of a |void*|
+ * pointer as |parg| and returns the value that is written to it, or NULL if
+ * the control request returns <= 0. */
+char *BIO_ptr_ctrl(BIO *bp, int cmd, long larg);
+
+/* BIO_int_ctrl acts like |BIO_ctrl| but passes the address of a copy of |iarg|
+ * as |parg|. */
+long BIO_int_ctrl(BIO *bp, int cmd, long larg, int iarg);
+
+/* BIO_reset resets |bio| to its initial state, the precise meaning of which
+ * depends on the concrete type of |bio|. It returns one on success and zero
+ * otherwise. */
+int BIO_reset(BIO *bio);
+
+/* BIO_set_flags ORs |flags| with |bio->flags|. */
+void BIO_set_flags(BIO *bio, int flags);
+
+/* BIO_test_flags returns |bio->flags| AND |flags|. */
+int BIO_test_flags(const BIO *bio, int flags);
+
+/* BIO_should_read returns non-zero if |bio| encountered a temporary error
+ * while reading (i.e. EAGAIN), indicating that the caller should retry the
+ * read. */
+int BIO_should_read(const BIO *bio);
+
+/* BIO_should_write returns non-zero if |bio| encountered a temporary error
+ * while writing (i.e. EAGAIN), indicating that the caller should retry the
+ * write. */
+int BIO_should_write(const BIO *bio);
+
+/* BIO_should_retry returns non-zero if the reason that caused a failed I/O
+ * operation is temporary and thus the operation should be retried. Otherwise,
+ * it was a permanent error and it returns zero. */
+int BIO_should_retry(const BIO *bio);
+
+/* BIO_should_io_special returns non-zero if |bio| encountered a temporary
+ * error while performing a special I/O operation, indicating that the caller
+ * should retry. The operation that caused the error is returned by
+ * |BIO_get_retry_reason|. */
+int BIO_should_io_special(const BIO *bio);
+
+/* BIO_RR_SSL_X509_LOOKUP indicates that an SSL BIO blocked because the SSL
+ * library returned with SSL_ERROR_WANT_X509_LOOKUP.
+ *
+ * TODO(fork): remove. */
+#define BIO_RR_SSL_X509_LOOKUP 0x01
+
+/* BIO_RR_CONNECT indicates that a connect would have blocked */
+#define BIO_RR_CONNECT 0x02
+
+/* BIO_RR_ACCEPT indicates that an accept would have blocked */
+#define BIO_RR_ACCEPT 0x03
+
+/* BIO_get_retry_reason returns the special I/O operation that needs to be
+ * retried. The return value is one of the |BIO_RR_*| values. */
+int BIO_get_retry_reason(const BIO *bio);
+
+/* BIO_clear_flags ANDs |bio->flags| with the bitwise-complement of |flags|. */
+void BIO_clear_flags(BIO *bio, int flags);
+
+/* BIO_set_retry_read sets the |BIO_FLAGS_READ| and |BIO_FLAGS_SHOULD_RETRY|
+ * flags on |bio|. */
+void BIO_set_retry_read(BIO *bio);
+
+/* BIO_set_retry_read sets the |BIO_FLAGS_WRITE| and |BIO_FLAGS_SHOULD_RETRY|
+ * flags on |bio|. */
+void BIO_set_retry_write(BIO *bio);
+
+/* BIO_get_retry_flags gets the |BIO_FLAGS_READ|, |BIO_FLAGS_WRITE|,
+ * |BIO_FLAGS_IO_SPECIAL| and |BIO_FLAGS_SHOULD_RETRY| flags from |bio|. */
+int BIO_get_retry_flags(BIO *bio);
+
+/* BIO_clear_retry_flags clears the |BIO_FLAGS_READ|, |BIO_FLAGS_WRITE|,
+ * |BIO_FLAGS_IO_SPECIAL| and |BIO_FLAGS_SHOULD_RETRY| flags from |bio|. */
+void BIO_clear_retry_flags(BIO *bio);
+
+/* BIO_method_type returns the type of |bio|, which is one of the |BIO_TYPE_*|
+ * values. */
+int BIO_method_type(const BIO *bio);
+
+/* bio_info_cb is the type of a callback function that can be called for most
+ * BIO operations. The |event| argument is one of |BIO_CB_*| and can be ORed
+ * with |BIO_CB_RETURN| if the callback is being made after the operation in
+ * question. In that case, |return_value| will contain the return value from
+ * the operation. */
+typedef long (*bio_info_cb)(BIO *bio, int event, const char *parg, int cmd,
+ long larg, long return_value);
+
+/* BIO_callback_ctrl allows the callback function to be manipulated. The |cmd|
+ * arg will generally be |BIO_CTRL_SET_CALLBACK| but arbitary command values
+ * can be interpreted by the |BIO|. */
+long BIO_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp);
+
+/* BIO_pending returns the number of bytes pending to be read. */
+size_t BIO_pending(const BIO *bio);
+
+/* BIO_wpending returns the number of bytes pending to be written. */
+size_t BIO_wpending(const BIO *bio);
+
+/* BIO_set_close sets the close flag for |bio|. The meaning of which depends on
+ * the type of |bio| but, for example, a memory BIO interprets the close flag
+ * as meaning that it owns its buffer. It returns one on success and zero
+ * otherwise. */
+int BIO_set_close(BIO *bio, int close_flag);
+
+
+/* Managing chains of BIOs.
+ *
+ * BIOs can be put into chains where the output of one is used as the input of
+ * the next etc. The most common case is a buffering BIO, which accepts and
+ * buffers writes until flushed into the next BIO in the chain. */
+
+/* BIO_push adds |appended_bio| to the end of the chain with |bio| at the head.
+ * It returns |bio|. Note that |appended_bio| may be the head of a chain itself
+ * and thus this function can be used to join two chains.
+ *
+ * BIO_push takes ownership of the caller's reference to |appended_bio|. */
+BIO *BIO_push(BIO *bio, BIO *appended_bio);
+
+/* BIO_pop removes |bio| from the head of a chain and returns the next BIO in
+ * the chain, or NULL if there is no next BIO.
+ *
+ * The caller takes ownership of the chain's reference to |bio|. */
+BIO *BIO_pop(BIO *bio);
+
+/* BIO_next returns the next BIO in the chain after |bio|, or NULL if there is
+ * no such BIO. */
+BIO *BIO_next(BIO *bio);
+
+/* BIO_free_all calls |BIO_free|.
+ *
+ * TODO(fork): update callers and remove. */
+void BIO_free_all(BIO *bio);
+
+/* BIO_find_type walks a chain of BIOs and returns the first that matches
+ * |type|, which is one of the |BIO_TYPE_*| values. */
+BIO *BIO_find_type(BIO *bio, int type);
+
+/* BIO_copy_next_retry sets the retry flags and |retry_reason| of |bio| from
+ * the next BIO in the chain. */
+void BIO_copy_next_retry(BIO *bio);
+
+
+/* Printf functions.
+ *
+ * These functions are versions of printf functions that output to a BIO rather
+ * than a FILE. */
+#ifdef __GNUC__
+#define __bio_h__attr__ __attribute__
+#else
+#define __bio_h__attr__(x)
+#endif
+int BIO_printf(BIO *bio, const char *format, ...)
+ __bio_h__attr__((__format__(__printf__, 2, 3)));
+
+int BIO_vprintf(BIO *bio, const char *format, va_list args)
+ __bio_h__attr__((__format__(__printf__, 2, 0)));
+#undef __bio_h__attr__
+
+
+/* Utility functions. */
+
+/* BIO_indent prints min(|indent|, |max_indent|) spaces. It returns one on
+ * success and zero otherwise. */
+int BIO_indent(BIO *bio, unsigned indent, unsigned max_indent);
+
+/* BIO_hexdump writes a hex dump of |data| to |bio|. Each line will be indented
+ * by |indent| spaces. */
+int BIO_hexdump(BIO *bio, const uint8_t *data, size_t len, unsigned indent);
+
+/* BIO_print_errors_fp prints the current contents of the error stack to |out|
+ * using human readable strings where possible. */
+void BIO_print_errors_fp(FILE *out);
+
+/* BIO_print_errors prints the current contents of the error stack to |bio|
+ * using human readable strings where possible. */
+void BIO_print_errors(BIO *bio);
+
+
+/* Memory BIOs.
+ *
+ * Memory BIOs can be used as a read-only source (with |BIO_new_mem_buf|) or a
+ * writable sink (with |BIO_new|, |BIO_s_mem| and |BIO_get_mem_buf|). Data
+ * written to a writable, memory BIO can be recalled by reading from it.
+ *
+ * Calling |BIO_reset| on a read-only BIO resets it to the original contents.
+ * On a writable BIO, it clears any data.
+ *
+ * If the close flag is set to |BIO_NOCLOSE| (not the default) then the
+ * underlying |BUF_MEM| will not be freed when the |BIO| is freed.
+ *
+ * Memory BIOs support |BIO_gets| and |BIO_puts|.
+ *
+ * |BIO_eof| is true if no data is in the BIO.
+ *
+ * |BIO_ctrl_pending| returns the number of bytes currently stored. */
+
+/* BIO_s_mem returns a |BIO_METHOD| that uses a in-memory buffer. */
+const BIO_METHOD *BIO_s_mem(void);
+
+/* BIO_new_mem_buf creates BIO that reads and writes from |len| bytes at |buf|.
+ * It does not take ownership of |buf|. It returns the BIO or NULL on error.
+ *
+ * If |len| is negative, then |buf| is treated as a NUL-terminated string, but
+ * don't depend on this in new code. */
+BIO *BIO_new_mem_buf(void *buf, int len);
+
+/* BIO_get_mem_data sets |*contents| to point to the current contents of |bio|
+ * and returns the length of the data. */
+long BIO_get_mem_data(BIO *bio, char **contents);
+
+/* BIO_get_mem_ptr sets |*out| to a BUF_MEM containing the current contents of
+ * |bio|. It returns one on success or zero on error. */
+int BIO_get_mem_ptr(BIO *bio, BUF_MEM **out);
+
+/* BIO_set_mem_buf sets |b| as the contents of |bio|. If |take_ownership| is
+ * non-zero, then |b| will be freed when |bio| is closed. Returns one on
+ * success or zero otherwise. */
+int BIO_set_mem_buf(BIO *bio, BUF_MEM *b, int take_ownership);
+
+/* BIO_set_mem_eof_return sets the value that will be returned from reading
+ * |bio| when empty. If |eof_value| is zero then an empty memory BIO will
+ * return EOF (that is it will return zero and |BIO_should_retry| will be
+ * false). If |eof_value| is non zero then it will return |eof_value| when it
+ * is empty and it will set the read retry flag (that is |BIO_read_retry| is
+ * true). To avoid ambiguity with a normal positive return value, |eof_value|
+ * should be set to a negative value, typically -1.
+ *
+ * For a read-only BIO, the default is zero (EOF). For a writable BIO, the
+ * default is -1 so that additional data can be written once exhausted. */
+int BIO_set_mem_eof_return(BIO *bio, int eof_value);
+
+
+/* File descriptor BIOs.
+ *
+ * File descriptor BIOs are wrappers around the system's |read| and |write|
+ * functions. If the close flag is set then then |close| is called on the
+ * underlying file descriptor when the BIO is freed.
+ *
+ * |BIO_reset| attempts to seek the file pointer to the start of file using
+ * |lseek|.
+ *
+ * |BIO_seek| sets the file pointer to position |off| from start of file using
+ * |lseek|.
+ *
+ * |BIO_tell| returns the current file position. */
+
+/* BIO_s_fd returns a |BIO_METHOD| for file descriptor fds. */
+const BIO_METHOD *BIO_s_fd(void);
+
+/* BIO_new_fd creates a new file descriptor BIO wrapping |fd|. If |close_flag|
+ * is non-zero, then |fd| will be closed when the BIO is. */
+BIO *BIO_new_fd(int fd, int close_flag);
+
+/* BIO_set_fd sets the file descriptor of |bio| to |fd|. If |close_flag| is
+ * non-zero then |fd| will be closed when |bio| is. It returns one on success
+ * or zero on error. */
+int BIO_set_fd(BIO *bio, int fd, int close_flag);
+
+/* BIO_get_fd sets |*out_fd| to the file descriptor currently in use by |bio|.
+ * It returns one on success and zero on error. */
+int BIO_get_fd(BIO *bio, int *out_fd);
+
+
+/* File BIOs.
+ *
+ * File BIOs are wrappers around a C |FILE| object.
+ *
+ * |BIO_flush| on a file BIO calls |fflush| on the wrapped stream.
+ *
+ * |BIO_reset| attempts to seek the file pointer to the start of file using
+ * |fseek|.
+ *
+ * |BIO_seek| sets the file pointer to the given position from the start of
+ * file using |fseek|.
+ *
+ * |BIO_eof| calls |feof|.
+ *
+ * Setting the close flag causes |fclose| to be called on the stream when the
+ * BIO is freed. */
+
+/* BIO_s_file returns a BIO_METHOD that wraps a |FILE|. */
+const BIO_METHOD *BIO_s_file(void);
+
+/* BIO_new_file creates a file BIO by opening |filename| with the given mode.
+ * See the |fopen| manual page for details of the mode argument. */
+BIO *BIO_new_file(const char *filename, const char *mode);
+
+/* BIO_new_fp creates a new file BIO that wraps the given |FILE|. If
+ * |close_flag| is |BIO_CLOSE|, then |fclose| will be called on |stream| when
+ * the BIO is closed. */
+BIO *BIO_new_fp(FILE *stream, int close_flag);
+
+/* BIO_get_fp sets |*out_file| to the current |FILE| for |bio|. It returns one
+ * on success and zero otherwise. */
+int BIO_get_fp(BIO *bio, FILE **out_file);
+
+/* BIO_set_fp sets the |FILE| for |bio|. If |close_flag| is |BIO_CLOSE| then
+ * |fclose| will be called on |file| when |bio| is closed. It returns one on
+ * sucess and zero otherwise. */
+int BIO_set_fp(BIO *bio, FILE *file, int close_flag);
+
+/* BIO_read_filename opens |filename| for reading and sets the result as the
+ * |FILE| for |bio|. It returns one on success and zero otherwise. The |FILE|
+ * will be closed when |bio| is freed. */
+int BIO_read_filename(BIO *bio, const char *filename);
+
+/* BIO_write_filename opens |filename| for writing and sets the result as the
+ * |FILE| for |bio|. It returns one on success and zero otherwise. The |FILE|
+ * will be closed when |bio| is freed. */
+int BIO_write_filename(BIO *bio, const char *filename);
+
+/* BIO_append_filename opens |filename| for appending and sets the result as
+ * the |FILE| for |bio|. It returns one on success and zero otherwise. The
+ * |FILE| will be closed when |bio| is freed. */
+int BIO_append_filename(BIO *bio, const char *filename);
+
+/* BIO_rw_filename opens |filename| for reading and writing and sets the result
+ * as the |FILE| for |bio|. It returns one on success and zero otherwise. The
+ * |FILE| will be closed when |bio| is freed. */
+int BIO_rw_filename(BIO *bio, const char *filename);
+
+
+/* Buffer BIOs.
+ *
+ * Buffer BIOs are a filter-type BIO, i.e. they are designed to be used in a
+ * chain of BIOs. They provide buffering to reduce the number of operations on
+ * the underlying BIOs. */
+
+const BIO_METHOD *BIO_f_buffer(void);
+
+/* BIO_set_read_buffer_size sets the size, in bytes, of the read buffer and
+ * clears it. It returns one on success and zero on failure. */
+int BIO_set_read_buffer_size(BIO *bio, int buffer_size);
+
+/* BIO_set_write_buffer_size sets the size, in bytes, of the write buffer and
+ * clears it. It returns one on success and zero on failure. */
+int BIO_set_write_buffer_size(BIO *bio, int buffer_size);
+
+
+/* Socket BIOs. */
+
+const BIO_METHOD *BIO_s_socket(void);
+
+/* BIO_new_socket allocates and initialises a fresh BIO which will read and
+ * write to the socket |fd|. If |close_flag| is |BIO_CLOSE| then closing the
+ * BIO will close |fd|. It returns the fresh |BIO| or NULL on error. */
+BIO *BIO_new_socket(int fd, int close_flag);
+
+
+/* Connect BIOs.
+ *
+ * A connection BIO creates a network connection and transfers data over the
+ * resulting socket. */
+
+const BIO_METHOD *BIO_s_connect(void);
+
+/* BIO_new_connect returns a BIO that connects to the given hostname and port.
+ * The |host_and_optional_port| argument should be of the form
+ * "www.example.com" or "www.example.com:443". If the port is omitted, it must
+ * be provided with |BIO_set_conn_port|.
+ *
+ * It returns the new BIO on success, or NULL on error. */
+BIO *BIO_new_connect(const char *host_and_optional_port);
+
+/* BIO_set_conn_hostname sets |host_and_optional_port| as the hostname and
+ * optional port that |bio| will connect to. If the port is omitted, it must be
+ * provided with |BIO_set_conn_port|.
+ *
+ * It returns one on success and zero otherwise. */
+int BIO_set_conn_hostname(BIO *bio, const char *host_and_optional_port);
+
+/* BIO_set_conn_port sets |port_str| as the port or service name that |bio|
+ * will connect to. It returns one on success and zero otherwise. */
+int BIO_set_conn_port(BIO *bio, const char *port_str);
+
+/* BIO_set_nbio sets whether |bio| will use non-blocking I/O operations. It
+ * returns one on success and zero otherwise. */
+int BIO_set_nbio(BIO *bio, int on);
+
+
+/* Datagram BIOs.
+ *
+ * TODO(fork): not implemented. */
+
+#define BIO_CTRL_DGRAM_QUERY_MTU 40 /* as kernel for current MTU */
+
+#define BIO_CTRL_DGRAM_SET_MTU 42 /* set cached value for MTU. want to use
+ this if asking the kernel fails */
+
+#define BIO_CTRL_DGRAM_MTU_EXCEEDED 43 /* check whether the MTU was exceed in
+ the previous write operation. */
+
+#define BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT \
+ 45 /* Next DTLS handshake timeout to adjust socket timeouts */
+
+#define BIO_CTRL_DGRAM_GET_PEER 46
+
+#define BIO_CTRL_DGRAM_GET_FALLBACK_MTU 47
+
+
+/* BIO Pairs.
+ *
+ * BIO pairs provide a "loopback" like system: a pair of BIOs where data
+ * written to one can be read from the other and vice versa. */
+
+/* BIO_new_bio_pair sets |*out1| and |*out2| to two freshly created BIOs where
+ * data written to one can be read from the other and vice versa. The
+ * |writebuf1| argument gives the size of the buffer used in |*out1| and
+ * |writebuf2| for |*out2|. It returns one on success and zero on error. */
+int BIO_new_bio_pair(BIO **out1, size_t writebuf1, BIO **out2,
+ size_t writebuf2);
+
+/* BIO_s_bio returns the method for a BIO pair. */
+const BIO_METHOD *BIO_s_bio(void);
+
+/* BIO_ctrl_get_read_request returns the number of bytes that the other side of
+ * |bio| tried (unsuccessfully) to read. */
+size_t BIO_ctrl_get_read_request(BIO *bio);
+
+/* BIO_ctrl_get_write_guarantee returns the number of bytes that |bio| (which
+ * must have been returned by |BIO_new_bio_pair|) will accept on the next
+ * |BIO_write| call. */
+size_t BIO_ctrl_get_write_guarantee(BIO *bio);
+
+/* BIO_shutdown_wr marks |bio| as closed, from the point of view of the other
+ * side of the pair. Future |BIO_write| calls on |bio| will fail. It returns
+ * one on success and zero otherwise. */
+int BIO_shutdown_wr(BIO *bio);
+
+
+/* BIO_NOCLOSE and |BIO_CLOSE| can be used as symbolic arguments when a "close
+ * flag" is passed to a BIO function. */
+#define BIO_NOCLOSE 0
+#define BIO_CLOSE 1
+
+/* These are passed to the BIO callback */
+#define BIO_CB_FREE 0x01
+#define BIO_CB_READ 0x02
+#define BIO_CB_WRITE 0x03
+#define BIO_CB_PUTS 0x04
+#define BIO_CB_GETS 0x05
+#define BIO_CB_CTRL 0x06
+
+/* The callback is called before and after the underling operation,
+ * The BIO_CB_RETURN flag indicates if it is after the call */
+#define BIO_CB_RETURN 0x80
+
+/* These are values of the |cmd| argument to |BIO_ctrl|. */
+#define BIO_CTRL_RESET 1 /* opt - rewind/zero etc */
+#define BIO_CTRL_EOF 2 /* opt - are we at the eof */
+#define BIO_CTRL_INFO 3 /* opt - extra tit-bits */
+#define BIO_CTRL_SET 4 /* man - set the 'IO' type */
+#define BIO_CTRL_GET 5 /* man - get the 'IO' type */
+#define BIO_CTRL_PUSH 6 /* opt - internal, used to signify change */
+#define BIO_CTRL_POP 7 /* opt - internal, used to signify change */
+#define BIO_CTRL_GET_CLOSE 8 /* man - set the 'close' on free */
+#define BIO_CTRL_SET_CLOSE 9 /* man - set the 'close' on free */
+#define BIO_CTRL_PENDING 10 /* opt - is their more data buffered */
+#define BIO_CTRL_FLUSH 11 /* opt - 'flush' buffered output */
+#define BIO_CTRL_WPENDING 13 /* opt - number of bytes still to write */
+/* callback is int cb(BIO *bio,state,ret); */
+#define BIO_CTRL_SET_CALLBACK 14 /* opt - set callback function */
+#define BIO_CTRL_GET_CALLBACK 15 /* opt - set callback function */
+#define BIO_CTRL_SET_FILENAME 30 /* BIO_s_file special */
+
+
+/* Private functions */
+
+#define BIO_FLAGS_READ 0x01
+#define BIO_FLAGS_WRITE 0x02
+#define BIO_FLAGS_IO_SPECIAL 0x04
+#define BIO_FLAGS_RWS (BIO_FLAGS_READ | BIO_FLAGS_WRITE | BIO_FLAGS_IO_SPECIAL)
+#define BIO_FLAGS_SHOULD_RETRY 0x08
+#define BIO_FLAGS_BASE64_NO_NL 0x100
+/* This is used with memory BIOs: it means we shouldn't free up or change the
+ * data in any way. */
+#define BIO_FLAGS_MEM_RDONLY 0x200
+
+/* These are the 'types' of BIOs */
+#define BIO_TYPE_NONE 0
+#define BIO_TYPE_MEM (1 | 0x0400)
+#define BIO_TYPE_FILE (2 | 0x0400)
+#define BIO_TYPE_FD (4 | 0x0400 | 0x0100)
+#define BIO_TYPE_SOCKET (5 | 0x0400 | 0x0100)
+#define BIO_TYPE_NULL (6 | 0x0400)
+#define BIO_TYPE_SSL (7 | 0x0200)
+#define BIO_TYPE_MD (8 | 0x0200) /* passive filter */
+#define BIO_TYPE_BUFFER (9 | 0x0200) /* filter */
+#define BIO_TYPE_CIPHER (10 | 0x0200) /* filter */
+#define BIO_TYPE_BASE64 (11 | 0x0200) /* filter */
+#define BIO_TYPE_CONNECT (12 | 0x0400 | 0x0100) /* socket - connect */
+#define BIO_TYPE_ACCEPT (13 | 0x0400 | 0x0100) /* socket for accept */
+#define BIO_TYPE_PROXY_CLIENT (14 | 0x0200) /* client proxy BIO */
+#define BIO_TYPE_PROXY_SERVER (15 | 0x0200) /* server proxy BIO */
+#define BIO_TYPE_NBIO_TEST (16 | 0x0200) /* server proxy BIO */
+#define BIO_TYPE_NULL_FILTER (17 | 0x0200)
+#define BIO_TYPE_BER (18 | 0x0200) /* BER -> bin filter */
+#define BIO_TYPE_BIO (19 | 0x0400) /* (half a) BIO pair */
+#define BIO_TYPE_LINEBUFFER (20 | 0x0200) /* filter */
+#define BIO_TYPE_DGRAM (21 | 0x0400 | 0x0100)
+#define BIO_TYPE_ASN1 (22 | 0x0200) /* filter */
+#define BIO_TYPE_COMP (23 | 0x0200) /* filter */
+
+#define BIO_TYPE_DESCRIPTOR 0x0100 /* socket, fd, connect or accept */
+#define BIO_TYPE_FILTER 0x0200
+#define BIO_TYPE_SOURCE_SINK 0x0400
+
+struct bio_method_st {
+ int type;
+ const char *name;
+ int (*bwrite)(BIO *, const char *, int);
+ int (*bread)(BIO *, char *, int);
+ /* TODO(fork): remove bputs. */
+ int (*bputs)(BIO *, const char *);
+ int (*bgets)(BIO *, char *, int);
+ long (*ctrl)(BIO *, int, long, void *);
+ int (*create)(BIO *);
+ int (*destroy)(BIO *);
+ long (*callback_ctrl)(BIO *, int, bio_info_cb);
+};
+
+struct bio_st {
+ const BIO_METHOD *method;
+ /* bio, mode, argp, argi, argl, ret */
+ long (*callback)(struct bio_st *, int, const char *, int, long, long);
+ char *cb_arg; /* first argument for the callback */
+
+ /* init is non-zero if this |BIO| has been initialised. */
+ int init;
+ /* shutdown is often used by specific |BIO_METHOD|s to determine whether
+ * they own some underlying resource. This flag can often by controlled by
+ * |BIO_set_close|. For example, whether an fd BIO closes the underlying fd
+ * when it, itself, is closed. */
+ int shutdown;
+ int flags;
+ int retry_reason;
+ /* num is a BIO-specific value. For example, in fd BIOs it's used to store a
+ * file descriptor. */
+ int num;
+ /* TODO(fork): reference counting is only used by the SSL BIO code. If we can
+ * dump that then we can remove this. We could also drop
+ * BIO_CTRL_PUSH/BIO_CTRL_POP. */
+ int references;
+ void *ptr;
+ /* next_bio points to the next |BIO| in a chain. This |BIO| owns a reference
+ * to |next_bio|. */
+ struct bio_st *next_bio; /* used by filter BIOs */
+ /* TODO(fork): either bring back BIO_number_read and write or remove these. */
+ unsigned long num_read;
+ unsigned long num_write;
+
+ CRYPTO_EX_DATA ex_data;
+};
+
+#define BIO_C_SET_CONNECT 100
+#define BIO_C_DO_STATE_MACHINE 101
+#define BIO_C_SET_NBIO 102
+#define BIO_C_SET_PROXY_PARAM 103
+#define BIO_C_SET_FD 104
+#define BIO_C_GET_FD 105
+#define BIO_C_SET_FILE_PTR 106
+#define BIO_C_GET_FILE_PTR 107
+#define BIO_C_SET_FILENAME 108
+#define BIO_C_SET_SSL 109
+#define BIO_C_GET_SSL 110
+#define BIO_C_SET_MD 111
+#define BIO_C_GET_MD 112
+#define BIO_C_GET_CIPHER_STATUS 113
+#define BIO_C_SET_BUF_MEM 114
+#define BIO_C_GET_BUF_MEM_PTR 115
+#define BIO_C_GET_BUFF_NUM_LINES 116
+#define BIO_C_SET_BUFF_SIZE 117
+#define BIO_C_SET_ACCEPT 118
+#define BIO_C_SSL_MODE 119
+#define BIO_C_GET_MD_CTX 120
+#define BIO_C_GET_PROXY_PARAM 121
+#define BIO_C_SET_BUFF_READ_DATA 122 /* data to read first */
+#define BIO_C_GET_CONNECT 123
+#define BIO_C_GET_ACCEPT 124
+#define BIO_C_SET_SSL_RENEGOTIATE_BYTES 125
+#define BIO_C_GET_SSL_NUM_RENEGOTIATES 126
+#define BIO_C_SET_SSL_RENEGOTIATE_TIMEOUT 127
+#define BIO_C_FILE_SEEK 128
+#define BIO_C_GET_CIPHER_CTX 129
+#define BIO_C_SET_BUF_MEM_EOF_RETURN 130/*return end of input value*/
+#define BIO_C_SET_BIND_MODE 131
+#define BIO_C_GET_BIND_MODE 132
+#define BIO_C_FILE_TELL 133
+#define BIO_C_GET_SOCKS 134
+#define BIO_C_SET_SOCKS 135
+
+#define BIO_C_SET_WRITE_BUF_SIZE 136/* for BIO_s_bio */
+#define BIO_C_GET_WRITE_BUF_SIZE 137
+#define BIO_C_GET_WRITE_GUARANTEE 140
+#define BIO_C_GET_READ_REQUEST 141
+#define BIO_C_SHUTDOWN_WR 142
+#define BIO_C_NREAD0 143
+#define BIO_C_NREAD 144
+#define BIO_C_NWRITE0 145
+#define BIO_C_NWRITE 146
+#define BIO_C_RESET_READ_REQUEST 147
+#define BIO_C_SET_MD_CTX 148
+
+#define BIO_C_SET_PREFIX 149
+#define BIO_C_GET_PREFIX 150
+#define BIO_C_SET_SUFFIX 151
+#define BIO_C_GET_SUFFIX 152
+
+#define BIO_C_SET_EX_ARG 153
+#define BIO_C_GET_EX_ARG 154
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#define BIO_F_bio_make_pair 100
+#define BIO_F_bio_ctrl 101
+#define BIO_F_buffer_ctrl 102
+#define BIO_F_BIO_new_file 103
+#define BIO_F_file_read 104
+#define BIO_F_BIO_new 105
+#define BIO_F_bio_io 106
+#define BIO_F_BIO_new_mem_buf 107
+#define BIO_F_mem_write 108
+#define BIO_F_conn_state 109
+#define BIO_F_conn_ctrl 110
+#define BIO_F_file_ctrl 111
+#define BIO_F_BIO_callback_ctrl 112
+#define BIO_F_bio_ip_and_port_to_socket_and_addr 113
+#define BIO_F_bio_write 114
+#define BIO_F_BIO_ctrl 115
+#define BIO_R_UNSUPPORTED_METHOD 100
+#define BIO_R_NO_PORT_SPECIFIED 101
+#define BIO_R_NO_HOSTNAME_SPECIFIED 102
+#define BIO_R_IN_USE 103
+#define BIO_R_UNINITIALIZED 104
+#define BIO_R_CONNECT_ERROR 105
+#define BIO_R_KEEPALIVE 106
+#define BIO_R_BROKEN_PIPE 107
+#define BIO_R_NBIO_CONNECT_ERROR 108
+#define BIO_R_BAD_FOPEN_MODE 109
+#define BIO_R_ASN1_OBJECT_TOO_LONG 110
+#define BIO_R_INVALID_ARGUMENT 111
+#define BIO_R_WRITE_TO_READ_ONLY_BIO 112
+#define BIO_R_ERROR_SETTING_NBIO 113
+#define BIO_R_SYS_LIB 114
+#define BIO_R_NO_SUCH_FILE 115
+#define BIO_R_NULL_PARAMETER 116
+#define BIO_R_UNABLE_TO_CREATE_SOCKET 117
+
+#endif /* OPENSSL_HEADER_BIO_H */
diff --git a/crypto/bio/bio_error.c b/crypto/bio/bio_error.c
new file mode 100644
index 0000000..f4ce8f8
--- /dev/null
+++ b/crypto/bio/bio_error.c
@@ -0,0 +1,55 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/err.h>
+
+#include "bio.h"
+
+const ERR_STRING_DATA BIO_error_string_data[] = {
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_callback_ctrl, 0), "BIO_callback_ctrl"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_ctrl, 0), "BIO_ctrl"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_new, 0), "BIO_new"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_new_file, 0), "BIO_new_file"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_new_mem_buf, 0), "BIO_new_mem_buf"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_bio_ctrl, 0), "bio_ctrl"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_bio_io, 0), "bio_io"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_bio_ip_and_port_to_socket_and_addr, 0), "bio_ip_and_port_to_socket_and_addr"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_bio_make_pair, 0), "bio_make_pair"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_bio_write, 0), "bio_write"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_buffer_ctrl, 0), "buffer_ctrl"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_conn_ctrl, 0), "conn_ctrl"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_conn_state, 0), "conn_state"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_file_ctrl, 0), "file_ctrl"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_file_read, 0), "file_read"},
+ {ERR_PACK(ERR_LIB_BIO, BIO_F_mem_write, 0), "mem_write"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_ASN1_OBJECT_TOO_LONG), "ASN1_OBJECT_TOO_LONG"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_BAD_FOPEN_MODE), "BAD_FOPEN_MODE"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_BROKEN_PIPE), "BROKEN_PIPE"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_CONNECT_ERROR), "CONNECT_ERROR"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_ERROR_SETTING_NBIO), "ERROR_SETTING_NBIO"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_INVALID_ARGUMENT), "INVALID_ARGUMENT"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_IN_USE), "IN_USE"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_KEEPALIVE), "KEEPALIVE"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NBIO_CONNECT_ERROR), "NBIO_CONNECT_ERROR"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NO_HOSTNAME_SPECIFIED), "NO_HOSTNAME_SPECIFIED"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NO_PORT_SPECIFIED), "NO_PORT_SPECIFIED"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NO_SUCH_FILE), "NO_SUCH_FILE"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NULL_PARAMETER), "NULL_PARAMETER"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_SYS_LIB), "SYS_LIB"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_CREATE_SOCKET), "UNABLE_TO_CREATE_SOCKET"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNINITIALIZED), "UNINITIALIZED"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNSUPPORTED_METHOD), "UNSUPPORTED_METHOD"},
+ {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_WRITE_TO_READ_ONLY_BIO), "WRITE_TO_READ_ONLY_BIO"},
+ {0, NULL},
+};
diff --git a/crypto/bio/bio_mem.c b/crypto/bio/bio_mem.c
new file mode 100644
index 0000000..4d047cf
--- /dev/null
+++ b/crypto/bio/bio_mem.c
@@ -0,0 +1,314 @@
+/* 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/bio.h>
+
+#include <limits.h>
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+BIO *BIO_new_mem_buf(void *buf, int len) {
+ BIO *ret;
+ BUF_MEM *b;
+ 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);
+ return NULL;
+ }
+
+ ret = BIO_new(BIO_s_mem());
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ b = (BUF_MEM *)ret->ptr;
+ b->data = buf;
+ b->length = size;
+ b->max = size;
+
+ ret->flags |= BIO_FLAGS_MEM_RDONLY;
+
+ /* |num| is used to store the value that this BIO will return when it runs
+ * out of data. If it's negative then the retry flags will also be set. Since
+ * this is static data, retrying wont help */
+ ret->num = 0;
+
+ return ret;
+}
+
+static int mem_new(BIO *bio) {
+ BUF_MEM *b;
+
+ b = BUF_MEM_new();
+ if (b == NULL) {
+ return 0;
+ }
+
+ /* |shutdown| is used to store the close flag: whether the BIO has ownership
+ * of the BUF_MEM. */
+ bio->shutdown = 1;
+ bio->init = 1;
+ bio->num = -1;
+ bio->ptr = (char *)b;
+
+ return 1;
+}
+
+static int mem_free(BIO *bio) {
+ BUF_MEM *b;
+
+ if (bio == NULL) {
+ return 0;
+ }
+
+ if (!bio->shutdown || !bio->init || bio->ptr == NULL) {
+ return 1;
+ }
+
+ b = (BUF_MEM *)bio->ptr;
+ if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
+ b->data = NULL;
+ }
+ BUF_MEM_free(b);
+ bio->ptr = NULL;
+ return 1;
+}
+
+static int mem_read(BIO *bio, char *out, int outl) {
+ int ret = -1;
+ BUF_MEM *b;
+
+ b = (BUF_MEM *)bio->ptr;
+ BIO_clear_retry_flags(bio);
+ ret = outl;
+ if (ret > (int)b->length) {
+ ret = b->length;
+ }
+
+ if (ret > 0) {
+ memcpy(out, b->data, ret);
+ b->length -= ret;
+ if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
+ b->data += ret;
+ } else {
+ memmove(b->data, &b->data[ret], b->length);
+ }
+ } else if (b->length == 0) {
+ ret = bio->num;
+ if (ret != 0) {
+ BIO_set_retry_read(bio);
+ }
+ }
+ return ret;
+}
+
+static int mem_write(BIO *bio, const char *in, int inl) {
+ int ret = -1;
+ int blen;
+ BUF_MEM *b;
+
+ 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);
+ goto err;
+ }
+
+ BIO_clear_retry_flags(bio);
+ blen = b->length;
+ if (INT_MAX - blen < inl) {
+ goto err;
+ }
+ if (BUF_MEM_grow_clean(b, blen + inl) != (blen + inl)) {
+ goto err;
+ }
+ memcpy(&b->data[blen], in, inl);
+ ret = inl;
+
+err:
+ return ret;
+}
+
+static int mem_puts(BIO *bp, const char *str) {
+ return mem_write(bp, str, strlen(str));
+}
+
+static int mem_gets(BIO *bio, char *buf, int size) {
+ int i, j;
+ char *p;
+ BUF_MEM *b = (BUF_MEM *)bio->ptr;
+
+ BIO_clear_retry_flags(bio);
+ j = b->length;
+ if (size - 1 < j) {
+ j = size - 1;
+ }
+ if (j <= 0) {
+ if (size > 0) {
+ *buf = 0;
+ }
+ return 0;
+ }
+
+ p = b->data;
+ for (i = 0; i < j; i++) {
+ if (p[i] == '\n') {
+ i++;
+ break;
+ }
+ }
+
+ /* i is now the max num of bytes to copy, either j or up to and including the
+ * first newline */
+
+ i = mem_read(bio, buf, i);
+ if (i > 0) {
+ buf[i] = '\0';
+ }
+ return i;
+}
+
+static long mem_ctrl(BIO *bio, int cmd, long num, void *ptr) {
+ long ret = 1;
+ char **pptr;
+
+ BUF_MEM *b = (BUF_MEM *)bio->ptr;
+
+ switch (cmd) {
+ case BIO_CTRL_RESET:
+ if (b->data != NULL) {
+ /* For read only case reset to the start again */
+ if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
+ b->data -= b->max - b->length;
+ b->length = b->max;
+ } else {
+ memset(b->data, 0, b->max);
+ b->length = 0;
+ }
+ }
+ break;
+ case BIO_CTRL_EOF:
+ ret = (long)(b->length == 0);
+ break;
+ case BIO_C_SET_BUF_MEM_EOF_RETURN:
+ bio->num = (int)num;
+ break;
+ case BIO_CTRL_INFO:
+ ret = (long)b->length;
+ if (ptr != NULL) {
+ pptr = (char **)ptr;
+ *pptr = (char *)&(b->data[0]);
+ }
+ break;
+ case BIO_C_SET_BUF_MEM:
+ mem_free(bio);
+ bio->shutdown = (int)num;
+ bio->ptr = ptr;
+ break;
+ case BIO_C_GET_BUF_MEM_PTR:
+ if (ptr != NULL) {
+ pptr = (char **)ptr;
+ *pptr = (char *)b;
+ }
+ break;
+ case BIO_CTRL_GET_CLOSE:
+ ret = (long)bio->shutdown;
+ break;
+ case BIO_CTRL_SET_CLOSE:
+ bio->shutdown = (int)num;
+ break;
+
+ case BIO_CTRL_WPENDING:
+ ret = 0L;
+ break;
+ case BIO_CTRL_PENDING:
+ ret = (long)b->length;
+ break;
+ case BIO_CTRL_FLUSH:
+ ret = 1;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+static const BIO_METHOD mem_method = {
+ BIO_TYPE_MEM, "memory buffer", mem_write, mem_read, mem_puts,
+ mem_gets, mem_ctrl, mem_new, mem_free, NULL, };
+
+const BIO_METHOD *BIO_s_mem(void) { return &mem_method; }
+
+long BIO_get_mem_data(BIO *bio, char **contents) {
+ return BIO_ctrl(bio, BIO_CTRL_INFO, 0, (char *) contents);
+}
+
+int BIO_get_mem_ptr(BIO *bio, BUF_MEM **out) {
+ return BIO_ctrl(bio, BIO_C_GET_BUF_MEM_PTR, 0, (char *) out);
+}
+
+int BIO_set_mem_buf(BIO *bio, BUF_MEM *b, int take_ownership) {
+ return BIO_ctrl(bio, BIO_C_SET_BUF_MEM, take_ownership, (char *) b);
+}
+
+int BIO_set_mem_eof_return(BIO *bio, int eof_value) {
+ return BIO_ctrl(bio, BIO_C_SET_BUF_MEM_EOF_RETURN, eof_value, NULL);
+}
diff --git a/crypto/bio/bio_test.c b/crypto/bio/bio_test.c
new file mode 100644
index 0000000..a38674f
--- /dev/null
+++ b/crypto/bio/bio_test.c
@@ -0,0 +1,93 @@
+/* TODO(fork): license */
+
+#define _BSD_SOURCE
+
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <openssl/bio.h>
+#include <openssl/err.h>
+
+
+static int test_socket_connect() {
+ int listening_sock = socket(AF_INET, SOCK_STREAM, 0);
+ int sock;
+ struct sockaddr_in sin;
+ socklen_t sockaddr_len = sizeof(sin);
+ static const char kTestMessage[] = "test";
+ char hostname[80], buf[5];
+ BIO *bio;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ if (!inet_aton("127.0.0.1", &sin.sin_addr)) {
+ perror("inet_aton");
+ return 0;
+ }
+
+ if (bind(listening_sock, (struct sockaddr *)&sin, sizeof(sin)) != 0) {
+ perror("bind");
+ return 0;
+ }
+
+ if (listen(listening_sock, 1)) {
+ perror("listen");
+ return 0;
+ }
+
+ if (getsockname(listening_sock, (struct sockaddr *)&sin, &sockaddr_len) ||
+ sockaddr_len != sizeof(sin)) {
+ perror("getsockname");
+ return 0;
+ }
+
+ snprintf(hostname, sizeof(hostname), "%s:%d", "127.0.0.1",
+ ntohs(sin.sin_port));
+ bio = BIO_new_connect(hostname);
+ if (!bio) {
+ fprintf(stderr, "BIO_new_connect failed.\n");
+ return 0;
+ }
+
+ if (BIO_write(bio, kTestMessage, sizeof(kTestMessage)) !=
+ sizeof(kTestMessage)) {
+ fprintf(stderr, "BIO_write failed.\n");
+ BIO_print_errors_fp(stderr);
+ return 0;
+ }
+
+ sock = accept(listening_sock, (struct sockaddr *) &sin, &sockaddr_len);
+ if (sock < 0) {
+ perror("accept");
+ return 0;
+ }
+
+ if (read(sock, buf, sizeof(buf)) != sizeof(kTestMessage)) {
+ perror("read");
+ return 0;
+ }
+
+ if (memcmp(buf, kTestMessage, sizeof(kTestMessage))) {
+ return 0;
+ }
+
+ close(sock);
+ close(listening_sock);
+ BIO_free(bio);
+
+ return 1;
+}
+
+int main() {
+ ERR_load_crypto_strings();
+
+ if (!test_socket_connect()) {
+ return 1;
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/crypto/bio/buffer.c b/crypto/bio/buffer.c
new file mode 100644
index 0000000..144afd2
--- /dev/null
+++ b/crypto/bio/buffer.c
@@ -0,0 +1,497 @@
+/* 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/bio.h>
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+#define DEFAULT_BUFFER_SIZE 4096
+
+typedef struct bio_f_buffer_ctx_struct {
+ /* Buffers are setup like this:
+ *
+ * <---------------------- size ----------------------->
+ * +---------------------------------------------------+
+ * | consumed | remaining | free space |
+ * +---------------------------------------------------+
+ * <-- off --><------- len ------->
+ */
+
+ int ibuf_size; /* how big is the input buffer */
+ int obuf_size; /* how big is the output buffer */
+
+ char *ibuf; /* the char array */
+ int ibuf_len; /* how many bytes are in it */
+ int ibuf_off; /* write/read offset */
+
+ char *obuf; /* the char array */
+ int obuf_len; /* how many bytes are in it */
+ int obuf_off; /* write/read offset */
+} BIO_F_BUFFER_CTX;
+
+static int buffer_new(BIO *bio) {
+ BIO_F_BUFFER_CTX *ctx;
+
+ ctx = OPENSSL_malloc(sizeof(BIO_F_BUFFER_CTX));
+ if (ctx == NULL) {
+ return 0;
+ }
+ memset(ctx, 0, sizeof(BIO_F_BUFFER_CTX));
+
+ ctx->ibuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE);
+ if (ctx->ibuf == NULL) {
+ goto err1;
+ }
+ ctx->obuf = (char *)OPENSSL_malloc(DEFAULT_BUFFER_SIZE);
+ if (ctx->obuf == NULL) {
+ goto err2;
+ }
+ ctx->ibuf_size = DEFAULT_BUFFER_SIZE;
+ ctx->obuf_size = DEFAULT_BUFFER_SIZE;
+
+ bio->init = 1;
+ bio->ptr = (char *)ctx;
+ return 1;
+
+err2:
+ OPENSSL_free(ctx->ibuf);
+
+err1:
+ OPENSSL_free(ctx);
+ return 0;
+}
+
+static int buffer_free(BIO *bio) {
+ BIO_F_BUFFER_CTX *ctx;
+
+ if (bio == NULL) {
+ return 0;
+ }
+
+ ctx = (BIO_F_BUFFER_CTX *)bio->ptr;
+ if (ctx->ibuf != NULL) {
+ OPENSSL_free(ctx->ibuf);
+ }
+ if (ctx->obuf != NULL) {
+ OPENSSL_free(ctx->obuf);
+ }
+ OPENSSL_free(bio->ptr);
+
+ bio->ptr = NULL;
+ bio->init = 0;
+ bio->flags = 0;
+
+ return 1;
+}
+
+static int buffer_read(BIO *bio, char *out, int outl) {
+ int i, num = 0;
+ BIO_F_BUFFER_CTX *ctx;
+
+ ctx = (BIO_F_BUFFER_CTX *)bio->ptr;
+
+ if (ctx == NULL || bio->next_bio == NULL) {
+ return 0;
+ }
+
+ num = 0;
+ BIO_clear_retry_flags(bio);
+
+ for (;;) {
+ i = ctx->ibuf_len;
+ /* If there is stuff left over, grab it */
+ if (i != 0) {
+ if (i > outl) {
+ i = outl;
+ }
+ memcpy(out, &ctx->ibuf[ctx->ibuf_off], i);
+ ctx->ibuf_off += i;
+ ctx->ibuf_len -= i;
+ num += i;
+ if (outl == i) {
+ return num;
+ }
+ outl -= i;
+ out += i;
+ }
+
+ /* We may have done a partial read. Try to do more. We have nothing in the
+ * buffer. If we get an error and have read some data, just return it and
+ * let them retry to get the error again. Copy direct to parent address
+ * space */
+ if (outl > ctx->ibuf_size) {
+ for (;;) {
+ i = BIO_read(bio->next_bio, out, outl);
+ if (i <= 0) {
+ BIO_copy_next_retry(bio);
+ if (i < 0) {
+ return (num > 0) ? num : i;
+ }
+ return num;
+ }
+ num += i;
+ if (outl == i) {
+ return num;
+ }
+ out += i;
+ outl -= i;
+ }
+ }
+ /* else */
+
+ /* we are going to be doing some buffering */
+ i = BIO_read(bio->next_bio, ctx->ibuf, ctx->ibuf_size);
+ if (i <= 0) {
+ BIO_copy_next_retry(bio);
+ if (i < 0) {
+ return (num > 0) ? num : i;
+ }
+ return num;
+ }
+ ctx->ibuf_off = 0;
+ ctx->ibuf_len = i;
+ }
+}
+
+static int buffer_write(BIO *b, const char *in, int inl) {
+ int i, num = 0;
+ BIO_F_BUFFER_CTX *ctx;
+
+ ctx = (BIO_F_BUFFER_CTX *)b->ptr;
+ if (ctx == NULL || b->next_bio == NULL) {
+ return 0;
+ }
+
+ BIO_clear_retry_flags(b);
+
+ for (;;) {
+ i = ctx->obuf_size - (ctx->obuf_off + ctx->obuf_len);
+ /* add to buffer and return */
+ if (i >= inl) {
+ memcpy(&ctx->obuf[ctx->obuf_off + ctx->obuf_len], in, inl);
+ ctx->obuf_len += inl;
+ return num + inl;
+ }
+ /* else */
+ /* stuff already in buffer, so add to it first, then flush */
+ if (ctx->obuf_len != 0) {
+ if (i > 0) {
+ memcpy(&ctx->obuf[ctx->obuf_off + ctx->obuf_len], in, i);
+ in += i;
+ inl -= i;
+ num += i;
+ ctx->obuf_len += i;
+ }
+
+ /* we now have a full buffer needing flushing */
+ for (;;) {
+ i = BIO_write(b->next_bio, &ctx->obuf[ctx->obuf_off], ctx->obuf_len);
+ if (i <= 0) {
+ BIO_copy_next_retry(b);
+
+ if (i < 0) {
+ return (num > 0) ? num : i;
+ }
+ return num;
+ }
+ ctx->obuf_off += i;
+ ctx->obuf_len -= i;
+ if (ctx->obuf_len == 0) {
+ break;
+ }
+ }
+ }
+
+ /* we only get here if the buffer has been flushed and we
+ * still have stuff to write */
+ ctx->obuf_off = 0;
+
+ /* we now have inl bytes to write */
+ while (inl >= ctx->obuf_size) {
+ i = BIO_write(b->next_bio, in, inl);
+ if (i <= 0) {
+ BIO_copy_next_retry(b);
+ if (i < 0) {
+ return (num > 0) ? num : i;
+ }
+ return num;
+ }
+ num += i;
+ in += i;
+ inl -= i;
+ if (inl == 0) {
+ return num;
+ }
+ }
+
+ /* copy the rest into the buffer since we have only a small
+ * amount left */
+ }
+}
+
+static long buffer_ctrl(BIO *b, int cmd, long num, void *ptr) {
+ BIO_F_BUFFER_CTX *ctx;
+ long ret = 1;
+ char *p1, *p2;
+ int r, *ip;
+ int ibs, obs;
+
+ ctx = (BIO_F_BUFFER_CTX *)b->ptr;
+
+ switch (cmd) {
+ case BIO_CTRL_RESET:
+ ctx->ibuf_off = 0;
+ ctx->ibuf_len = 0;
+ ctx->obuf_off = 0;
+ ctx->obuf_len = 0;
+ if (b->next_bio == NULL) {
+ return 0;
+ }
+ ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
+ break;
+
+ case BIO_CTRL_INFO:
+ ret = ctx->obuf_len;
+ break;
+
+ case BIO_CTRL_WPENDING:
+ ret = (long)ctx->obuf_len;
+ if (ret == 0) {
+ if (b->next_bio == NULL)
+ return 0;
+ ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
+ }
+ break;
+
+ case BIO_CTRL_PENDING:
+ ret = (long)ctx->ibuf_len;
+ if (ret == 0) {
+ if (b->next_bio == NULL) {
+ return 0;
+ }
+ ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
+ }
+ break;
+
+ case BIO_C_SET_BUFF_SIZE:
+ ip = (int *)ptr;
+ if (*ip == 0) {
+ ibs = (int)num;
+ obs = ctx->obuf_size;
+ } else /* if (*ip == 1) */ {
+ ibs = ctx->ibuf_size;
+ obs = (int)num;
+ }
+ p1 = ctx->ibuf;
+ p2 = ctx->obuf;
+ if (ibs > DEFAULT_BUFFER_SIZE && ibs != ctx->ibuf_size) {
+ p1 = (char *)OPENSSL_malloc(ibs);
+ if (p1 == NULL) {
+ goto malloc_error;
+ }
+ }
+ if (obs > DEFAULT_BUFFER_SIZE && obs != ctx->obuf_size) {
+ p2 = (char *)OPENSSL_malloc(obs);
+ if (p2 == NULL) {
+ if (p1 != ctx->ibuf) {
+ OPENSSL_free(p1);
+ }
+ goto malloc_error;
+ }
+ }
+
+ if (ctx->ibuf != p1) {
+ OPENSSL_free(ctx->ibuf);
+ ctx->ibuf = p1;
+ ctx->ibuf_size = ibs;
+ }
+ ctx->ibuf_off = 0;
+ ctx->ibuf_len = 0;
+
+ if (ctx->obuf != p2) {
+ OPENSSL_free(ctx->obuf);
+ ctx->obuf = p2;
+ ctx->obuf_size = obs;
+ }
+ ctx->obuf_off = 0;
+ ctx->obuf_len = 0;
+ break;
+
+ case BIO_CTRL_FLUSH:
+ if (b->next_bio == NULL) {
+ return 0;
+ }
+
+ while (ctx->obuf_len > 0) {
+ BIO_clear_retry_flags(b);
+ r = BIO_write(b->next_bio, &(ctx->obuf[ctx->obuf_off]),
+ ctx->obuf_len);
+ BIO_copy_next_retry(b);
+ if (r <= 0) {
+ return r;
+ }
+ ctx->obuf_off += r;
+ ctx->obuf_len -= r;
+ }
+
+ ctx->obuf_len = 0;
+ ctx->obuf_off = 0;
+ ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
+ break;
+
+ default:
+ if (b->next_bio == NULL) {
+ return 0;
+ }
+ BIO_clear_retry_flags(b);
+ ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
+ BIO_copy_next_retry(b);
+ break;
+ }
+ return ret;
+
+malloc_error:
+ OPENSSL_PUT_ERROR(BIO, buffer_ctrl, ERR_R_MALLOC_FAILURE);
+ return 0;
+}
+
+static long buffer_callback_ctrl(BIO *b, int cmd, bio_info_cb fp) {
+ long ret = 1;
+
+ if (b->next_bio == NULL) {
+ return 0;
+ }
+
+ switch (cmd) {
+ default:
+ ret = BIO_callback_ctrl(b->next_bio, cmd, fp);
+ break;
+ }
+ return ret;
+}
+
+static int buffer_gets(BIO *b, char *buf, int size) {
+ BIO_F_BUFFER_CTX *ctx;
+ int num = 0, i, flag;
+ char *p;
+
+ ctx = (BIO_F_BUFFER_CTX *)b->ptr;
+ if (buf == NULL || size <= 0) {
+ return 0;
+ }
+
+ size--; /* reserve space for a '\0' */
+ BIO_clear_retry_flags(b);
+
+ for (;;) {
+ if (ctx->ibuf_len > 0) {
+ p = &ctx->ibuf[ctx->ibuf_off];
+ flag = 0;
+ for (i = 0; (i < ctx->ibuf_len) && (i < size); i++) {
+ *(buf++) = p[i];
+ if (p[i] == '\n') {
+ flag = 1;
+ i++;
+ break;
+ }
+ }
+ num += i;
+ size -= i;
+ ctx->ibuf_len -= i;
+ ctx->ibuf_off += i;
+ if (flag || size == 0) {
+ *buf = '\0';
+ return num;
+ }
+ } else /* read another chunk */
+ {
+ i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size);
+ if (i <= 0) {
+ BIO_copy_next_retry(b);
+ *buf = '\0';
+ if (i < 0) {
+ return (num > 0) ? num : i;
+ }
+ return num;
+ }
+ ctx->ibuf_len = i;
+ ctx->ibuf_off = 0;
+ }
+ }
+}
+
+static int buffer_puts(BIO *b, const char *str) {
+ return buffer_write(b, str, strlen(str));
+}
+
+static BIO_METHOD methods_buffer = {
+ BIO_TYPE_BUFFER, "buffer", buffer_write, buffer_read,
+ buffer_puts, buffer_gets, buffer_ctrl, buffer_new,
+ buffer_free, buffer_callback_ctrl,
+};
+
+const BIO_METHOD *BIO_f_buffer(void) { return &methods_buffer; }
+
+int BIO_set_read_buffer_size(BIO *bio, int buffer_size) {
+ return BIO_int_ctrl(bio, BIO_C_SET_BUFF_SIZE, buffer_size, 0);
+}
+
+int BIO_set_write_buffer_size(BIO *bio, int buffer_size) {
+ return BIO_int_ctrl(bio, BIO_C_SET_BUFF_SIZE, buffer_size, 1);
+}
diff --git a/crypto/bio/connect.c b/crypto/bio/connect.c
new file mode 100644
index 0000000..3798a1c
--- /dev/null
+++ b/crypto/bio/connect.c
@@ -0,0 +1,527 @@
+/* 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/bio.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+
+#if !defined(OPENSSL_WINDOWS)
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#endif
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+#include "internal.h"
+
+
+enum {
+ BIO_CONN_S_BEFORE,
+ BIO_CONN_S_BLOCKED_CONNECT,
+ BIO_CONN_S_OK,
+};
+
+typedef struct bio_connect_st {
+ int state;
+
+ char *param_hostname;
+ char *param_port;
+ int nbio;
+
+ uint8_t ip[4];
+ unsigned short port;
+
+ struct sockaddr_storage them;
+
+ /* the file descriptor is kept in bio->num in order to match the socket
+ * BIO. */
+
+ /* info_callback is called when the connection is initially made
+ * callback(BIO,state,ret); The callback should return 'ret', state is for
+ * compatibility with the SSL info_callback. */
+ int (*info_callback)(const BIO *bio, int state, int ret);
+} BIO_CONNECT;
+
+/* maybe_copy_ipv4_address sets |*ipv4| to the IPv4 address from |ss| (in
+ * big-endian order), if |ss| contains an IPv4 socket address. */
+static void maybe_copy_ipv4_address(uint8_t *ipv4,
+ const struct sockaddr_storage *ss) {
+ const struct sockaddr_in *sin;
+
+ if (ss->ss_family != AF_INET) {
+ return;
+ }
+
+ sin = (const struct sockaddr_in*) ss;
+ memcpy(ipv4, &sin->sin_addr, 4);
+}
+
+static int conn_state(BIO *bio, BIO_CONNECT *c) {
+ int ret = -1, i;
+ char *p, *q;
+ int (*cb)(const BIO *, int, int) = NULL;
+
+ if (c->info_callback != NULL) {
+ cb = c->info_callback;
+ }
+
+ for (;;) {
+ switch (c->state) {
+ case BIO_CONN_S_BEFORE:
+ p = c->param_hostname;
+ if (p == NULL) {
+ OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_NO_HOSTNAME_SPECIFIED);
+ goto exit_loop;
+ }
+ for (; *p != 0; p++) {
+ if (*p == ':' || *p == '/') {
+ break;
+ }
+ }
+
+ i = *p;
+ if (i == ':' || i == '/') {
+ *(p++) = 0;
+ if (i == ':') {
+ for (q = p; *q; q++) {
+ if (*q == '/') {
+ *q = 0;
+ break;
+ }
+ }
+ if (c->param_port != NULL) {
+ OPENSSL_free(c->param_port);
+ }
+ c->param_port = BUF_strdup(p);
+ }
+ }
+
+ if (c->param_port == NULL) {
+ OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_NO_PORT_SPECIFIED);
+ ERR_add_error_data(2, "host=", c->param_hostname);
+ goto exit_loop;
+ }
+
+ if (!bio_ip_and_port_to_socket_and_addr(
+ &bio->num, &c->them, c->param_hostname, c->param_port)) {
+ OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_UNABLE_TO_CREATE_SOCKET);
+ ERR_add_error_data(4, "host=", c->param_hostname, ":", c->param_port);
+ goto exit_loop;
+ }
+
+ memset(c->ip, 0, 4);
+ maybe_copy_ipv4_address(c->ip, &c->them);
+
+ if (c->nbio) {
+ if (!bio_socket_nbio(bio->num, 1)) {
+ OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_ERROR_SETTING_NBIO);
+ ERR_add_error_data(4, "host=", c->param_hostname, ":",
+ c->param_port);
+ goto exit_loop;
+ }
+ }
+
+ i = 1;
+ ret = setsockopt(bio->num, SOL_SOCKET, SO_KEEPALIVE, (char *)&i,
+ sizeof(i));
+ if (ret < 0) {
+ OPENSSL_PUT_SYSTEM_ERROR(setsockopt);
+ OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_KEEPALIVE);
+ ERR_add_error_data(4, "host=", c->param_hostname, ":", c->param_port);
+ goto exit_loop;
+ }
+
+ BIO_clear_retry_flags(bio);
+ ret = connect(bio->num, (struct sockaddr*) &c->them, sizeof(c->them));
+ if (ret < 0) {
+ if (bio_fd_should_retry(ret)) {
+ BIO_set_flags(bio, (BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY));
+ c->state = BIO_CONN_S_BLOCKED_CONNECT;
+ bio->retry_reason = BIO_RR_CONNECT;
+ } else {
+ OPENSSL_PUT_SYSTEM_ERROR(connect);
+ OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_CONNECT_ERROR);
+ ERR_add_error_data(4, "host=", c->param_hostname, ":",
+ c->param_port);
+ }
+ goto exit_loop;
+ } else {
+ c->state = BIO_CONN_S_OK;
+ }
+ break;
+
+ case BIO_CONN_S_BLOCKED_CONNECT:
+ i = bio_sock_error(bio->num);
+ if (i) {
+ if (bio_fd_should_retry(ret)) {
+ BIO_set_flags(bio, (BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY));
+ c->state = BIO_CONN_S_BLOCKED_CONNECT;
+ bio->retry_reason = BIO_RR_CONNECT;
+ ret = -1;
+ } else {
+ BIO_clear_retry_flags(bio);
+ OPENSSL_PUT_SYSTEM_ERROR(connect);
+ OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_NBIO_CONNECT_ERROR);
+ ERR_add_error_data(4, "host=", c->param_hostname, ":", c->param_port);
+ ret = 0;
+ }
+ goto exit_loop;
+ } else {
+ c->state = BIO_CONN_S_OK;
+ }
+ break;
+
+ case BIO_CONN_S_OK:
+ ret = 1;
+ goto exit_loop;
+ default:
+ assert(0);
+ goto exit_loop;
+ }
+
+ if (cb != NULL) {
+ ret = cb((BIO *)bio, c->state, ret);
+ if (ret == 0) {
+ goto end;
+ }
+ }
+ }
+
+exit_loop:
+ if (cb != NULL) {
+ ret = cb((BIO *)bio, c->state, ret);
+ }
+
+end:
+ return ret;
+}
+
+static BIO_CONNECT *BIO_CONNECT_new(void) {
+ BIO_CONNECT *ret = OPENSSL_malloc(sizeof(BIO_CONNECT));
+
+ if (ret == NULL) {
+ return NULL;
+ }
+ memset(ret, 0, sizeof(BIO_CONNECT));
+
+ ret->state = BIO_CONN_S_BEFORE;
+ return ret;
+}
+
+static void BIO_CONNECT_free(BIO_CONNECT *c) {
+ if (c == NULL) {
+ return;
+ }
+
+ if (c->param_hostname != NULL) {
+ OPENSSL_free(c->param_hostname);
+ }
+ if (c->param_port != NULL) {
+ OPENSSL_free(c->param_port);
+ }
+ OPENSSL_free(c);
+}
+
+static int conn_new(BIO *bio) {
+ bio->init = 0;
+ bio->num = -1;
+ bio->flags = 0;
+ bio->ptr = (char *)BIO_CONNECT_new();
+ return bio->ptr != NULL;
+}
+
+static void conn_close_socket(BIO *bio) {
+ BIO_CONNECT *c = (BIO_CONNECT *) bio->ptr;
+
+ if (bio->num == -1) {
+ return;
+ }
+
+ /* Only do a shutdown if things were established */
+ if (c->state == BIO_CONN_S_OK) {
+ shutdown(bio->num, 2);
+ }
+ close(bio->num);
+ bio->num = -1;
+}
+
+static int conn_free(BIO *bio) {
+ if (bio == NULL) {
+ return 0;
+ }
+
+ if (bio->shutdown) {
+ conn_close_socket(bio);
+ }
+
+ BIO_CONNECT_free((BIO_CONNECT*) bio->ptr);
+
+ return 1;
+}
+
+static int conn_read(BIO *bio, char *out, int out_len) {
+ int ret = 0;
+ BIO_CONNECT *data;
+
+ data = (BIO_CONNECT *)bio->ptr;
+ if (data->state != BIO_CONN_S_OK) {
+ ret = conn_state(bio, data);
+ if (ret <= 0) {
+ return ret;
+ }
+ }
+
+ bio_clear_socket_error();
+ ret = recv(bio->num, out, out_len, 0);
+ BIO_clear_retry_flags(bio);
+ if (ret <= 0) {
+ if (bio_fd_should_retry(ret)) {
+ BIO_set_retry_read(bio);
+ }
+ }
+
+ return ret;
+}
+
+static int conn_write(BIO *bio, const char *in, int in_len) {
+ int ret;
+ BIO_CONNECT *data;
+
+ data = (BIO_CONNECT *)bio->ptr;
+ if (data->state != BIO_CONN_S_OK) {
+ ret = conn_state(bio, data);
+ if (ret <= 0) {
+ return ret;
+ }
+ }
+
+ bio_clear_socket_error();
+ ret = send(bio->num, in, in_len, 0);
+ BIO_clear_retry_flags(bio);
+ if (ret <= 0) {
+ if (bio_fd_should_retry(ret)) {
+ BIO_set_retry_write(bio);
+ }
+ }
+
+ return ret;
+}
+
+static long conn_ctrl(BIO *bio, int cmd, long num, void *ptr) {
+ int *ip;
+ const char **pptr;
+ long ret = 1;
+ BIO_CONNECT *data;
+
+ data = (BIO_CONNECT *)bio->ptr;
+
+ switch (cmd) {
+ case BIO_CTRL_RESET:
+ ret = 0;
+ data->state = BIO_CONN_S_BEFORE;
+ conn_close_socket(bio);
+ bio->flags = 0;
+ break;
+ case BIO_C_DO_STATE_MACHINE:
+ /* use this one to start the connection */
+ if (data->state != BIO_CONN_S_OK)
+ ret = (long)conn_state(bio, data);
+ else
+ ret = 1;
+ break;
+ case BIO_C_GET_CONNECT:
+ /* TODO(fork): can this be removed? (Or maybe this whole file). */
+ if (ptr != NULL) {
+ pptr = (const char **)ptr;
+ if (num == 0) {
+ *pptr = data->param_hostname;
+ } else if (num == 1) {
+ *pptr = data->param_port;
+ } else if (num == 2) {
+ *pptr = (char *) &data->ip[0];
+ } else if (num == 3) {
+ *((int *)ptr) = data->port;
+ }
+ if (!bio->init) {
+ *pptr = "not initialized";
+ }
+ ret = 1;
+ }
+ break;
+ case BIO_C_SET_CONNECT:
+ if (ptr != NULL) {
+ bio->init = 1;
+ if (num == 0) {
+ if (data->param_hostname != NULL) {
+ OPENSSL_free(data->param_hostname);
+ }
+ data->param_hostname = BUF_strdup(ptr);
+ } else if (num == 1) {
+ if (data->param_port != NULL) {
+ OPENSSL_free(data->param_port);
+ }
+ data->param_port = BUF_strdup(ptr);
+ } else {
+ ret = 0;
+ }
+ }
+ break;
+ case BIO_C_SET_NBIO:
+ data->nbio = (int)num;
+ break;
+ case BIO_C_GET_FD:
+ if (bio->init) {
+ ip = (int *)ptr;
+ if (ip != NULL) {
+ *ip = bio->num;
+ }
+ ret = 1;
+ } else {
+ ret = 0;
+ }
+ break;
+ case BIO_CTRL_GET_CLOSE:
+ ret = bio->shutdown;
+ break;
+ case BIO_CTRL_SET_CLOSE:
+ bio->shutdown = (int)num;
+ break;
+ case BIO_CTRL_PENDING:
+ case BIO_CTRL_WPENDING:
+ ret = 0;
+ break;
+ case BIO_CTRL_FLUSH:
+ 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);
+ ret = -1;
+#else
+ ret = 0;
+#endif
+ } break;
+ case BIO_CTRL_GET_CALLBACK: {
+ int (**fptr)(const BIO *bio, int state, int xret);
+ fptr = (int (**)(const BIO *bio, int state, int xret))ptr;
+ *fptr = data->info_callback;
+ } break;
+ default:
+ ret = 0;
+ break;
+ }
+ return (ret);
+}
+
+static long conn_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) {
+ long ret = 1;
+ BIO_CONNECT *data;
+
+ data = (BIO_CONNECT *)bio->ptr;
+
+ switch (cmd) {
+ case BIO_CTRL_SET_CALLBACK: {
+ data->info_callback = (int (*)(const struct bio_st *, int, int))fp;
+ } break;
+ default:
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+static int conn_puts(BIO *bp, const char *str) {
+ return conn_write(bp, str, strlen(str));
+}
+
+BIO *BIO_new_connect(const char *hostname) {
+ BIO *ret;
+
+ ret = BIO_new(BIO_s_connect());
+ if (ret == NULL) {
+ return NULL;
+ }
+ if (!BIO_set_conn_hostname(ret, hostname)) {
+ BIO_free(ret);
+ return NULL;
+ }
+ return ret;
+}
+
+static const BIO_METHOD methods_connectp = {
+ BIO_TYPE_CONNECT, "socket connect", conn_write, conn_read,
+ conn_puts, NULL /* connect_gets, */, conn_ctrl, conn_new,
+ conn_free, conn_callback_ctrl,
+};
+
+const BIO_METHOD *BIO_s_connect(void) { return &methods_connectp; }
+
+int BIO_set_conn_hostname(BIO *bio, const char *name) {
+ return BIO_ctrl(bio, BIO_C_SET_CONNECT, 0, (void*) name);
+}
+
+int BIO_set_conn_port(BIO *bio, const char *port_str) {
+ return BIO_ctrl(bio, BIO_C_SET_CONNECT, 1, (void*) port_str);
+}
+
+int BIO_set_nbio(BIO *bio, int on) {
+ return BIO_ctrl(bio, BIO_C_SET_NBIO, on, NULL);
+}
diff --git a/crypto/bio/fd.c b/crypto/bio/fd.c
new file mode 100644
index 0000000..c40056d
--- /dev/null
+++ b/crypto/bio/fd.c
@@ -0,0 +1,264 @@
+/* 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/bio.h>
+
+#include <errno.h>
+
+#if !defined(OPENSSL_WINDOWS)
+#include <unistd.h>
+#endif
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+static int bio_fd_non_fatal_error(int err) {
+ if (
+#ifdef EWOULDBLOCK
+ err == EWOULDBLOCK ||
+#endif
+#ifdef WSAEWOULDBLOCK
+ err == WSAEWOULDBLOCK ||
+#endif
+#ifdef ENOTCONN
+ err == ENOTCONN ||
+#endif
+#ifdef EINTR
+ err == EINTR ||
+#endif
+#ifdef EAGAIN
+ err == EAGAIN ||
+#endif
+#ifdef EPROTO
+ err == EPROTO ||
+#endif
+#ifdef EINPROGRESS
+ err == EINPROGRESS ||
+#endif
+#ifdef EALREADY
+ err == EALREADY ||
+#endif
+ 0) {
+ return 1;
+ }
+ return 0;
+}
+
+#if defined(WIN32)
+static int bio_fd_should_retry(int i) {
+ if (i == -1) {
+ return bio_fd_non_fatal_error((int)GetLastError());
+ }
+ return 0;
+}
+#else
+int bio_fd_should_retry(int i) {
+ if (i == -1) {
+ return bio_fd_non_fatal_error(errno);
+ }
+ return 0;
+}
+#endif
+
+BIO *BIO_new_fd(int fd, int close_flag) {
+ BIO *ret = BIO_new(BIO_s_fd());
+ if (ret == NULL) {
+ return NULL;
+ }
+ BIO_set_fd(ret, fd, close_flag);
+ return ret;
+}
+
+static int fd_new(BIO *bio) {
+ /* num is used to store the file descriptor. */
+ bio->num = -1;
+ return 1;
+}
+
+static int fd_free(BIO *bio) {
+ if (bio == NULL) {
+ return 0;
+ }
+
+ if (bio->shutdown) {
+ if (bio->init) {
+ close(bio->num);
+ }
+ bio->init = 0;
+ }
+ return 1;
+}
+
+static int fd_read(BIO *b, char *out, int outl) {
+ int ret = 0;
+
+ ret = read(b->num, out, outl);
+ BIO_clear_retry_flags(b);
+ if (ret <= 0) {
+ if (bio_fd_should_retry(ret)) {
+ BIO_set_retry_read(b);
+ }
+ }
+
+ return ret;
+}
+
+static int fd_write(BIO *b, const char *in, int inl) {
+ int ret = write(b->num, in, inl);
+ BIO_clear_retry_flags(b);
+ if (ret <= 0) {
+ if (bio_fd_should_retry(ret)) {
+ BIO_set_retry_write(b);
+ }
+ }
+
+ return ret;
+}
+
+static long fd_ctrl(BIO *b, int cmd, long num, void *ptr) {
+ long ret = 1;
+ int *ip;
+
+ switch (cmd) {
+ case BIO_CTRL_RESET:
+ num = 0;
+ case BIO_C_FILE_SEEK:
+ ret = 0;
+ if (b->init) {
+ ret = (long)lseek(b->num, num, SEEK_SET);
+ }
+ break;
+ case BIO_C_FILE_TELL:
+ case BIO_CTRL_INFO:
+ ret = 0;
+ if (b->init) {
+ ret = (long)lseek(b->num, 0, SEEK_CUR);
+ }
+ break;
+ case BIO_C_SET_FD:
+ fd_free(b);
+ b->num = *((int *)ptr);
+ b->shutdown = (int)num;
+ b->init = 1;
+ break;
+ case BIO_C_GET_FD:
+ if (b->init) {
+ ip = (int *)ptr;
+ if (ip != NULL) {
+ *ip = b->num;
+ }
+ return 1;
+ } else {
+ ret = 0;
+ }
+ break;
+ case BIO_CTRL_GET_CLOSE:
+ ret = b->shutdown;
+ break;
+ case BIO_CTRL_SET_CLOSE:
+ b->shutdown = (int)num;
+ break;
+ case BIO_CTRL_PENDING:
+ case BIO_CTRL_WPENDING:
+ ret = 0;
+ break;
+ case BIO_CTRL_FLUSH:
+ ret = 1;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static int fd_puts(BIO *bp, const char *str) {
+ return fd_write(bp, str, strlen(str));
+}
+
+static int fd_gets(BIO *bp, char *buf, int size) {
+ char *ptr = buf;
+ char *end = buf + size - 1;
+
+ if (size <= 0) {
+ return 0;
+ }
+
+ while (ptr < end && fd_read(bp, ptr, 1) > 0 && ptr[0] != '\n') {
+ ptr++;
+ }
+
+ ptr[0] = '\0';
+
+ return ptr - buf;
+}
+
+static const BIO_METHOD methods_fdp = {
+ BIO_TYPE_FD, "file descriptor", fd_write, fd_read, fd_puts,
+ fd_gets, fd_ctrl, fd_new, fd_free, NULL, };
+
+const BIO_METHOD *BIO_s_fd(void) { return &methods_fdp; }
+
+int BIO_set_fd(BIO *bio, int fd, int close_flag) {
+ return BIO_int_ctrl(bio, BIO_C_SET_FD, close_flag, fd);
+}
+
+int BIO_get_fd(BIO *bio, int *out_fd) {
+ return BIO_ctrl(bio, BIO_C_GET_FD, 0, (char *) out_fd);
+}
diff --git a/crypto/bio/file.c b/crypto/bio/file.c
new file mode 100644
index 0000000..e1a67ca
--- /dev/null
+++ b/crypto/bio/file.c
@@ -0,0 +1,349 @@
+/* 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.] */
+
+#if defined(__linux) || defined(__sun) || defined(__hpux)
+/* Following definition aliases fopen to fopen64 on above mentioned
+ * platforms. This makes it possible to open and sequentially access
+ * files larger than 2GB from 32-bit application. It does not allow to
+ * traverse them beyond 2GB with fseek/ftell, but on the other hand *no*
+ * 32-bit platform permits that, not with fseek/ftell. Not to mention
+ * that breaking 2GB limit for seeking would require surgery to *our*
+ * API. But sequential access suffices for practical cases when you
+ * can run into large files, such as fingerprinting, so we can let API
+ * alone. For reference, the list of 32-bit platforms which allow for
+ * sequential access of large files without extra "magic" comprise *BSD,
+ * Darwin, IRIX...
+ */
+#ifndef _FILE_OFFSET_BITS
+#define _FILE_OFFSET_BITS 64
+#endif
+#endif
+
+#include <openssl/bio.h>
+
+#include <errno.h>
+#include <stdio.h>
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+#define BIO_FP_READ 0x02
+#define BIO_FP_WRITE 0x04
+#define BIO_FP_APPEND 0x08
+
+static FILE *open_file(const char *filename, const char *mode) {
+#if defined(_WIN32) && defined(CP_UTF8)
+ int sz, len_0 = (int)strlen(filename) + 1;
+ DWORD flags;
+
+ /* Basically there are three cases to cover: a) filename is pure ASCII
+ * string; b) actual UTF-8 encoded string and c) locale-ized string, i.e. one
+ * containing 8-bit characters that are meaningful in current system locale.
+ * If filename is pure ASCII or real UTF-8 encoded string,
+ * MultiByteToWideChar succeeds and _wfopen works. If filename is locale-ized
+ * string, chances are that MultiByteToWideChar fails reporting
+ * ERROR_NO_UNICODE_TRANSLATION, in which case we fall back to fopen... */
+ if ((sz = MultiByteToWideChar(CP_UTF8, (flags = MB_ERR_INVALID_CHARS),
+ filename, len_0, NULL, 0)) > 0 ||
+ (GetLastError() == ERROR_INVALID_FLAGS &&
+ (sz = MultiByteToWideChar(CP_UTF8, (flags = 0), filename, len_0, NULL,
+ 0)) > 0)) {
+ WCHAR wmode[8];
+ WCHAR *wfilename = _alloca(sz * sizeof(WCHAR));
+
+ if (MultiByteToWideChar(CP_UTF8, flags, filename, len_0, wfilename, sz) &&
+ MultiByteToWideChar(CP_UTF8, 0, mode, strlen(mode) + 1, wmode,
+ sizeof(wmode) / sizeof(wmode[0])) &&
+ (file = _wfopen(wfilename, wmode)) == NULL &&
+ (errno == ENOENT ||
+ errno == EBADF)) /* UTF-8 decode succeeded, but no file, filename
+ * could still have been locale-ized... */
+ return fopen(filename, mode);
+ } else if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
+ return fopen(filename, mode);
+ }
+#else
+ return fopen(filename, mode);
+#endif
+}
+
+BIO *BIO_new_file(const char *filename, const char *mode) {
+ BIO *ret;
+ FILE *file;
+
+ file = open_file(filename, mode);
+ if (file == NULL) {
+ OPENSSL_PUT_SYSTEM_ERROR(fopen);
+
+ ERR_add_error_data(5, "fopen('", filename, "','", mode, "')");
+ if (errno == ENOENT) {
+ OPENSSL_PUT_ERROR(BIO, BIO_new_file, BIO_R_NO_SUCH_FILE);
+ } else {
+ OPENSSL_PUT_ERROR(BIO, BIO_new_file, BIO_R_SYS_LIB);
+ }
+ return NULL;
+ }
+
+ ret = BIO_new(BIO_s_file());
+ if (ret == NULL) {
+ fclose(file);
+ return NULL;
+ }
+
+ BIO_set_fp(ret, file, BIO_CLOSE);
+ return ret;
+}
+
+BIO *BIO_new_fp(FILE *stream, int close_flag) {
+ BIO *ret = BIO_new(BIO_s_file());
+
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ BIO_set_fp(ret, stream, close_flag);
+ return ret;
+}
+
+static int file_new(BIO *bio) { return 1; }
+
+static int file_free(BIO *bio) {
+ if (bio == NULL) {
+ return 0;
+ }
+
+ if (!bio->shutdown) {
+ return 1;
+ }
+
+ if (bio->init && bio->ptr != NULL) {
+ fclose(bio->ptr);
+ bio->ptr = NULL;
+ }
+ bio->init = 0;
+
+ return 1;
+}
+
+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);
+ if (ret == 0 && ferror((FILE *)b->ptr)) {
+ OPENSSL_PUT_SYSTEM_ERROR(fread);
+ OPENSSL_PUT_ERROR(BIO, file_read, ERR_R_SYS_LIB);
+ ret = -1;
+ }
+
+ return ret;
+}
+
+static int file_write(BIO *b, const char *in, int inl) {
+ int ret = 0;
+
+ if (!b->init) {
+ return 0;
+ }
+
+ ret = fwrite(in, inl, 1, (FILE *)b->ptr);
+ if (ret > 0) {
+ ret = inl;
+ }
+ return ret;
+}
+
+static long file_ctrl(BIO *b, int cmd, long num, void *ptr) {
+ long ret = 1;
+ FILE *fp = (FILE *)b->ptr;
+ FILE **fpp;
+ char p[4];
+
+ switch (cmd) {
+ case BIO_CTRL_RESET:
+ num = 0;
+ case BIO_C_FILE_SEEK:
+ ret = (long)fseek(fp, num, 0);
+ break;
+ case BIO_CTRL_EOF:
+ ret = (long)feof(fp);
+ break;
+ case BIO_C_FILE_TELL:
+ case BIO_CTRL_INFO:
+ ret = ftell(fp);
+ break;
+ case BIO_C_SET_FILE_PTR:
+ file_free(b);
+ b->shutdown = (int)num & BIO_CLOSE;
+ b->ptr = ptr;
+ b->init = 1;
+ break;
+ case BIO_C_SET_FILENAME:
+ file_free(b);
+ b->shutdown = (int)num & BIO_CLOSE;
+ if (num & BIO_FP_APPEND) {
+ if (num & BIO_FP_READ) {
+ BUF_strlcpy(p, "a+", sizeof(p));
+ } else {
+ BUF_strlcpy(p, "a", sizeof(p));
+ }
+ } else if ((num & BIO_FP_READ) && (num & BIO_FP_WRITE)) {
+ BUF_strlcpy(p, "r+", sizeof(p));
+ } else if (num & BIO_FP_WRITE) {
+ BUF_strlcpy(p, "w", sizeof(p));
+ } else if (num & BIO_FP_READ) {
+ BUF_strlcpy(p, "r", sizeof(p));
+ } else {
+ OPENSSL_PUT_ERROR(BIO, file_ctrl, BIO_R_BAD_FOPEN_MODE);
+ ret = 0;
+ break;
+ }
+ fp = open_file(ptr, p);
+ 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);
+ ret = 0;
+ break;
+ }
+ b->ptr = fp;
+ b->init = 1;
+ break;
+ case BIO_C_GET_FILE_PTR:
+ /* the ptr parameter is actually a FILE ** in this case. */
+ if (ptr != NULL) {
+ fpp = (FILE **)ptr;
+ *fpp = (FILE *)b->ptr;
+ }
+ break;
+ case BIO_CTRL_GET_CLOSE:
+ ret = (long)b->shutdown;
+ break;
+ case BIO_CTRL_SET_CLOSE:
+ b->shutdown = (int)num;
+ break;
+ case BIO_CTRL_FLUSH:
+ ret = 0 == fflush((FILE *)b->ptr);
+ break;
+ case BIO_CTRL_WPENDING:
+ case BIO_CTRL_PENDING:
+ default:
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+static int file_gets(BIO *bp, char *buf, int size) {
+ int ret = 0;
+
+ if (size == 0) {
+ return 0;
+ }
+
+ if (!fgets(buf, size, (FILE *)bp->ptr)) {
+ buf[0] = 0;
+ goto err;
+ }
+ ret = strlen(buf);
+
+err:
+ return ret;
+}
+
+static int file_puts(BIO *bp, const char *str) {
+ return file_write(bp, str, strlen(str));
+}
+
+static const BIO_METHOD methods_filep = {
+ BIO_TYPE_FILE, "FILE pointer", file_write, file_read, file_puts,
+ file_gets, file_ctrl, file_new, file_free, NULL, };
+
+const BIO_METHOD *BIO_s_file(void) { return &methods_filep; }
+
+
+int BIO_get_fp(BIO *bio, FILE **out_file) {
+ return BIO_ctrl(bio, BIO_C_GET_FILE_PTR, 0, (char*) out_file);
+}
+
+int BIO_set_fp(BIO *bio, FILE *file, int close_flag) {
+ return BIO_ctrl(bio, BIO_C_SET_FILE_PTR, close_flag, (char *) file);
+}
+
+int BIO_read_filename(BIO *bio, const char *filename) {
+ return BIO_ctrl(bio, BIO_C_SET_FILENAME, BIO_CLOSE | BIO_FP_READ,
+ (char *)filename);
+}
+
+int BIO_write_filename(BIO *bio, const char *filename) {
+ return BIO_ctrl(bio, BIO_C_SET_FILENAME, BIO_CLOSE | BIO_FP_WRITE,
+ (char *)filename);
+}
+
+int BIO_append_filename(BIO *bio, const char *filename) {
+ return BIO_ctrl(bio, BIO_C_SET_FILENAME, BIO_CLOSE | BIO_FP_APPEND,
+ (char *)filename);
+}
+
+int BIO_rw_filename(BIO *bio, const char *filename) {
+ return BIO_ctrl(bio, BIO_C_SET_FILENAME,
+ BIO_CLOSE | BIO_FP_READ | BIO_FP_WRITE, (char *)filename);
+}
diff --git a/crypto/bio/hexdump.c b/crypto/bio/hexdump.c
new file mode 100644
index 0000000..d31d3a4
--- /dev/null
+++ b/crypto/bio/hexdump.c
@@ -0,0 +1,190 @@
+/* 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/bio.h>
+
+#include <limits.h>
+
+
+/* hexdump_ctx contains the state of a hexdump. */
+struct hexdump_ctx {
+ BIO *bio;
+ char right_chars[18]; /* the contents of the right-hand side, ASCII dump. */
+ unsigned used; /* number of bytes in the current line. */
+ size_t n; /* number of bytes total. */
+ unsigned indent;
+};
+
+static void hexbyte(char *out, uint8_t b) {
+ static const char hextable[] = "0123456789abcdef";
+ out[0] = hextable[b>>4];
+ out[1] = hextable[b&0x0f];
+}
+
+static char to_char(uint8_t b) {
+ if (b < 32 || b > 126) {
+ return '.';
+ }
+ return b;
+}
+
+/* hexdump adds |len| bytes of |data| to the current hex dump described by
+ * |ctx|. */
+static int hexdump(struct hexdump_ctx *ctx, const uint8_t *data, size_t len) {
+ size_t i;
+ char buf[10];
+ unsigned l;
+
+ /* Output lines look like:
+ * 00000010 2e 2f 30 31 32 33 34 35 36 37 38 ... 3c 3d // |./0123456789:;<=|
+ * ^ offset ^ extra space ^ ASCII of line
+ */
+
+ for (i = 0; i < len; i++) {
+ if (ctx->used == 0) {
+ /* The beginning of a line. */
+ BIO_indent(ctx->bio, ctx->indent, UINT_MAX);
+
+ hexbyte(&buf[0], ctx->n >> 24);
+ hexbyte(&buf[2], ctx->n >> 16);
+ hexbyte(&buf[4], ctx->n >> 8);
+ hexbyte(&buf[6], ctx->n);
+ buf[8] = buf[9] = ' ';
+ if (BIO_write(ctx->bio, buf, 10) < 0) {
+ return 0;
+ }
+ }
+
+ hexbyte(buf, data[i]);
+ buf[2] = ' ';
+ l = 3;
+ if (ctx->used == 7) {
+ /* There's an additional space after the 8th byte. */
+ buf[3] = ' ';
+ l = 4;
+ } else if (ctx->used == 15) {
+ /* At the end of the line there's an extra space and the bar for the
+ * right column. */
+ buf[3] = ' ';
+ buf[4] = '|';
+ l = 5;
+ }
+
+ if (BIO_write(ctx->bio, buf, l) < 0) {
+ return 0;
+ }
+ ctx->right_chars[ctx->used] = to_char(data[i]);
+ ctx->used++;
+ ctx->n++;
+ if (ctx->used == 16) {
+ ctx->right_chars[16] = '|';
+ ctx->right_chars[17] = '\n';
+ if (BIO_write(ctx->bio, ctx->right_chars, sizeof(ctx->right_chars)) < 0) {
+ return 0;
+ }
+ ctx->used = 0;
+ }
+ }
+
+ return 1;
+}
+
+/* finish flushes any buffered data in |ctx|. */
+static int finish(struct hexdump_ctx *ctx) {
+ /* See the comments in |hexdump| for the details of this format. */
+ const unsigned n_bytes = ctx->used;
+ unsigned l;
+ char buf[5];
+
+ if (n_bytes == 0) {
+ return 1;
+ }
+
+ memset(buf, ' ', 4);
+ buf[4] = '|';
+
+ for (; ctx->used < 16; ctx->used++) {
+ l = 3;
+ if (ctx->used == 7) {
+ l = 4;
+ } else if (ctx->used == 15) {
+ l = 5;
+ }
+ if (BIO_write(ctx->bio, buf, l) < 0) {
+ return 0;
+ }
+ }
+
+ ctx->right_chars[n_bytes] = '|';
+ ctx->right_chars[n_bytes + 1] = '\n';
+ if (BIO_write(ctx->bio, ctx->right_chars, n_bytes + 2) < 0) {
+ return 0;
+ }
+ return 1;
+}
+
+int BIO_hexdump(BIO *bio, const uint8_t *data, size_t len, unsigned indent) {
+ struct hexdump_ctx ctx;
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.bio = bio;
+ ctx.indent = indent;
+
+ if (!hexdump(&ctx, data, len) || !finish(&ctx)) {
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/crypto/bio/internal.h b/crypto/bio/internal.h
new file mode 100644
index 0000000..d498708
--- /dev/null
+++ b/crypto/bio/internal.h
@@ -0,0 +1,102 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_BIO_INTERNAL_H
+#define OPENSSL_HEADER_BIO_INTERNAL_H
+
+#include <openssl/base.h>
+
+#if !defined(OPENSSL_WINDOWS)
+#include <sys/socket.h>
+#else
+#include <WinSock2.h>
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* BIO_ip_and_port_to_socket_and_addr creates a socket and fills in |*out_addr|
+ * with the correct values for connecting to |hostname| on |port_str|. It
+ * returns one on success or zero on error. */
+int bio_ip_and_port_to_socket_and_addr(int *out_sock,
+ struct sockaddr_storage *out_addr,
+ const char *hostname,
+ const char *port_str);
+
+/* BIO_socket_nbio sets whether |sock| is non-blocking. It returns one on
+ * success and zero otherwise. */
+int bio_socket_nbio(int sock, int on);
+
+/* BIO_clear_socket_error clears the last system socket error.
+ *
+ * TODO(fork): remove all callers of this. */
+void bio_clear_socket_error();
+
+/* BIO_sock_error returns the last socket error on |sock|. */
+int bio_sock_error(int sock);
+
+/* BIO_fd_should_retry returns non-zero if |return_value| indicates an error
+ * and |errno| indicates that it's non-fatal. */
+int bio_fd_should_retry(int return_value);
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_BIO_INTERNAL_H */
diff --git a/crypto/bio/pair.c b/crypto/bio/pair.c
new file mode 100644
index 0000000..a2cc6d6
--- /dev/null
+++ b/crypto/bio/pair.c
@@ -0,0 +1,549 @@
+/* ====================================================================
+ * Copyright (c) 1998-2003 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). */
+
+#include <openssl/bio.h>
+
+#include <assert.h>
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+struct bio_bio_st {
+ BIO *peer; /* NULL if buf == NULL.
+ * If peer != NULL, then peer->ptr is also a bio_bio_st,
+ * and its "peer" member points back to us.
+ * peer != NULL iff init != 0 in the BIO. */
+
+ /* This is for what we write (i.e. reading uses peer's struct): */
+ int closed; /* valid iff peer != NULL */
+ size_t len; /* valid iff buf != NULL; 0 if peer == NULL */
+ size_t offset; /* valid iff buf != NULL; 0 if len == 0 */
+ size_t size;
+ char *buf; /* "size" elements (if != NULL) */
+
+ size_t request; /* valid iff peer != NULL; 0 if len != 0,
+ * otherwise set by peer to number of bytes
+ * it (unsuccessfully) tried to read,
+ * never more than buffer space (size-len) warrants. */
+};
+
+static int bio_new(BIO *bio) {
+ struct bio_bio_st *b;
+
+ b = OPENSSL_malloc(sizeof *b);
+ if (b == NULL) {
+ return 0;
+ }
+
+ b->peer = NULL;
+ b->size = 17 * 1024; /* enough for one TLS record (just a default) */
+ b->buf = NULL;
+
+ bio->ptr = b;
+ return 1;
+}
+
+static void bio_destroy_pair(BIO *bio) {
+ struct bio_bio_st *b = bio->ptr;
+ BIO *peer_bio;
+ struct bio_bio_st *peer_b;
+
+ if (b == NULL) {
+ return;
+ }
+
+ peer_bio = b->peer;
+ if (peer_bio == NULL) {
+ return;
+ }
+
+ peer_b = peer_bio->ptr;
+
+ assert(peer_b != NULL);
+ assert(peer_b->peer == bio);
+
+ peer_b->peer = NULL;
+ peer_bio->init = 0;
+ assert(peer_b->buf != NULL);
+ peer_b->len = 0;
+ peer_b->offset = 0;
+
+ b->peer = NULL;
+ bio->init = 0;
+ assert(b->buf != NULL);
+ b->len = 0;
+ b->offset = 0;
+}
+
+static int bio_free(BIO *bio) {
+ struct bio_bio_st *b;
+
+ if (bio == NULL) {
+ return 0;
+ }
+ b = bio->ptr;
+
+ assert(b != NULL);
+
+ if (b->peer) {
+ bio_destroy_pair(bio);
+ }
+
+ if (b->buf != NULL) {
+ OPENSSL_free(b->buf);
+ }
+
+ OPENSSL_free(b);
+
+ return 1;
+}
+
+static int bio_read(BIO *bio, char *buf, int size_) {
+ size_t size = size_;
+ size_t rest;
+ struct bio_bio_st *b, *peer_b;
+
+ BIO_clear_retry_flags(bio);
+
+ if (!bio->init) {
+ return 0;
+ }
+
+ b = bio->ptr;
+ assert(b != NULL);
+ assert(b->peer != NULL);
+ peer_b = b->peer->ptr;
+ assert(peer_b != NULL);
+ assert(peer_b->buf != NULL);
+
+ peer_b->request = 0; /* will be set in "retry_read" situation */
+
+ if (buf == NULL || size == 0) {
+ return 0;
+ }
+
+ if (peer_b->len == 0) {
+ if (peer_b->closed) {
+ return 0; /* writer has closed, and no data is left */
+ } else {
+ BIO_set_retry_read(bio); /* buffer is empty */
+ if (size <= peer_b->size) {
+ peer_b->request = size;
+ } else {
+ /* don't ask for more than the peer can
+ * deliver in one write */
+ peer_b->request = peer_b->size;
+ }
+ return -1;
+ }
+ }
+
+ /* we can read */
+ if (peer_b->len < size) {
+ size = peer_b->len;
+ }
+
+ /* now read "size" bytes */
+ rest = size;
+
+ assert(rest > 0);
+ /* one or two iterations */
+ do {
+ size_t chunk;
+
+ assert(rest <= peer_b->len);
+ if (peer_b->offset + rest <= peer_b->size) {
+ chunk = rest;
+ } else {
+ /* wrap around ring buffer */
+ chunk = peer_b->size - peer_b->offset;
+ }
+ assert(peer_b->offset + chunk <= peer_b->size);
+
+ memcpy(buf, peer_b->buf + peer_b->offset, chunk);
+
+ peer_b->len -= chunk;
+ if (peer_b->len) {
+ peer_b->offset += chunk;
+ assert(peer_b->offset <= peer_b->size);
+ if (peer_b->offset == peer_b->size) {
+ peer_b->offset = 0;
+ }
+ buf += chunk;
+ } else {
+ /* buffer now empty, no need to advance "buf" */
+ assert(chunk == rest);
+ peer_b->offset = 0;
+ }
+ rest -= chunk;
+ } while (rest);
+
+ return size;
+}
+
+static int bio_write(BIO *bio, const char *buf, int num_) {
+ size_t num = num_;
+ size_t rest;
+ struct bio_bio_st *b;
+
+ BIO_clear_retry_flags(bio);
+
+ if (!bio->init || buf == NULL || num == 0) {
+ return 0;
+ }
+
+ b = bio->ptr;
+ assert(b != NULL);
+ assert(b->peer != NULL);
+ assert(b->buf != NULL);
+
+ b->request = 0;
+ if (b->closed) {
+ /* we already closed */
+ OPENSSL_PUT_ERROR(BIO, bio_write, BIO_R_BROKEN_PIPE);
+ return -1;
+ }
+
+ assert(b->len <= b->size);
+
+ if (b->len == b->size) {
+ BIO_set_retry_write(bio); /* buffer is full */
+ return -1;
+ }
+
+ /* we can write */
+ if (num > b->size - b->len) {
+ num = b->size - b->len;
+ }
+
+ /* now write "num" bytes */
+ rest = num;
+
+ assert(rest > 0);
+ /* one or two iterations */
+ do {
+ size_t write_offset;
+ size_t chunk;
+
+ assert(b->len + rest <= b->size);
+
+ write_offset = b->offset + b->len;
+ if (write_offset >= b->size) {
+ write_offset -= b->size;
+ }
+ /* b->buf[write_offset] is the first byte we can write to. */
+
+ if (write_offset + rest <= b->size) {
+ chunk = rest;
+ } else {
+ /* wrap around ring buffer */
+ chunk = b->size - write_offset;
+ }
+
+ memcpy(b->buf + write_offset, buf, chunk);
+
+ b->len += chunk;
+
+ assert(b->len <= b->size);
+
+ rest -= chunk;
+ buf += chunk;
+ } while (rest);
+
+ return num;
+}
+
+static int bio_make_pair(BIO *bio1, BIO *bio2) {
+ struct bio_bio_st *b1, *b2;
+
+ assert(bio1 != NULL);
+ assert(bio2 != NULL);
+
+ b1 = bio1->ptr;
+ b2 = bio2->ptr;
+
+ if (b1->peer != NULL || b2->peer != NULL) {
+ OPENSSL_PUT_ERROR(BIO, bio_make_pair, BIO_R_IN_USE);
+ return 0;
+ }
+
+ if (b1->buf == NULL) {
+ b1->buf = OPENSSL_malloc(b1->size);
+ if (b1->buf == NULL) {
+ OPENSSL_PUT_ERROR(BIO, bio_make_pair, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ b1->len = 0;
+ b1->offset = 0;
+ }
+
+ if (b2->buf == NULL) {
+ b2->buf = OPENSSL_malloc(b2->size);
+ if (b2->buf == NULL) {
+ OPENSSL_PUT_ERROR(BIO, bio_make_pair, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ b2->len = 0;
+ b2->offset = 0;
+ }
+
+ b1->peer = bio2;
+ b1->closed = 0;
+ b1->request = 0;
+ b2->peer = bio1;
+ b2->closed = 0;
+ b2->request = 0;
+
+ bio1->init = 1;
+ bio2->init = 1;
+
+ return 1;
+}
+
+static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr) {
+ long ret;
+ struct bio_bio_st *b = bio->ptr;
+
+ assert(b != NULL);
+
+ switch (cmd) {
+ /* specific CTRL codes */
+
+ case BIO_C_SET_BUFF_SIZE:
+ if (b->peer) {
+ OPENSSL_PUT_ERROR(BIO, bio_ctrl, BIO_R_IN_USE);
+ ret = 0;
+ } else if (num == 0) {
+ OPENSSL_PUT_ERROR(BIO, bio_ctrl, BIO_R_INVALID_ARGUMENT);
+ ret = 0;
+ } else {
+ size_t new_size = num;
+
+ if (b->size != new_size) {
+ if (b->buf) {
+ OPENSSL_free(b->buf);
+ b->buf = NULL;
+ }
+ b->size = new_size;
+ }
+ ret = 1;
+ }
+ break;
+
+ case BIO_C_GET_WRITE_BUF_SIZE:
+ ret = (long)b->size;
+ break;
+
+ case BIO_C_GET_WRITE_GUARANTEE:
+ /* How many bytes can the caller feed to the next write
+ * without having to keep any? */
+ if (b->peer == NULL || b->closed) {
+ ret = 0;
+ } else {
+ ret = (long)b->size - b->len;
+ }
+ break;
+
+ case BIO_C_GET_READ_REQUEST:
+ /* If the peer unsuccessfully tried to read, how many bytes
+ * were requested? (As with BIO_CTRL_PENDING, that number
+ * can usually be treated as boolean.) */
+ ret = (long)b->request;
+ break;
+
+ case BIO_C_RESET_READ_REQUEST:
+ /* Reset request. (Can be useful after read attempts
+ * at the other side that are meant to be non-blocking,
+ * e.g. when probing SSL_read to see if any data is
+ * available.) */
+ b->request = 0;
+ ret = 1;
+ break;
+
+ case BIO_C_SHUTDOWN_WR:
+ /* similar to shutdown(..., SHUT_WR) */
+ b->closed = 1;
+ ret = 1;
+ break;
+
+ /* standard CTRL codes follow */
+
+ case BIO_CTRL_RESET:
+ if (b->buf != NULL) {
+ b->len = 0;
+ b->offset = 0;
+ }
+ ret = 0;
+ break;
+
+ case BIO_CTRL_GET_CLOSE:
+ ret = bio->shutdown;
+ break;
+
+ case BIO_CTRL_SET_CLOSE:
+ bio->shutdown = (int)num;
+ ret = 1;
+ break;
+
+ case BIO_CTRL_PENDING:
+ if (b->peer != NULL) {
+ struct bio_bio_st *peer_b = b->peer->ptr;
+ ret = (long)peer_b->len;
+ } else {
+ ret = 0;
+ }
+ break;
+
+ case BIO_CTRL_WPENDING:
+ ret = 0;
+ if (b->buf != NULL) {
+ ret = (long)b->len;
+ }
+ break;
+
+ case BIO_CTRL_FLUSH:
+ ret = 1;
+ break;
+
+ case BIO_CTRL_EOF: {
+ BIO *other_bio = ptr;
+
+ if (other_bio) {
+ struct bio_bio_st *other_b = other_bio->ptr;
+ assert(other_b != NULL);
+ ret = other_b->len == 0 && other_b->closed;
+ } else {
+ ret = 1;
+ }
+ } break;
+
+ default:
+ ret = 0;
+ }
+ return ret;
+}
+
+static int bio_puts(BIO *bio, const char *str) {
+ return bio_write(bio, str, strlen(str));
+}
+
+int BIO_new_bio_pair(BIO **bio1_p, size_t writebuf1, BIO **bio2_p,
+ size_t writebuf2) {
+ BIO *bio1 = NULL, *bio2 = NULL;
+ long r;
+ int ret = 0;
+
+ bio1 = BIO_new(BIO_s_bio());
+ if (bio1 == NULL) {
+ goto err;
+ }
+ bio2 = BIO_new(BIO_s_bio());
+ if (bio2 == NULL) {
+ goto err;
+ }
+
+ if (writebuf1) {
+ r = BIO_set_write_buffer_size(bio1, writebuf1);
+ if (!r) {
+ goto err;
+ }
+ }
+ if (writebuf2) {
+ r = BIO_set_write_buffer_size(bio2, writebuf2);
+ if (!r) {
+ goto err;
+ }
+ }
+
+ if (!bio_make_pair(bio1, bio2)) {
+ goto err;
+ }
+ ret = 1;
+
+err:
+ if (ret == 0) {
+ if (bio1) {
+ BIO_free(bio1);
+ bio1 = NULL;
+ }
+ if (bio2) {
+ BIO_free(bio2);
+ bio2 = NULL;
+ }
+ }
+
+ *bio1_p = bio1;
+ *bio2_p = bio2;
+ return ret;
+}
+
+static const BIO_METHOD methods_biop = {
+ BIO_TYPE_BIO, "BIO pair", bio_write, bio_read,
+ bio_puts, NULL /* no bio_gets */, bio_ctrl, bio_new,
+ bio_free, NULL /* no bio_callback_ctrl */
+};
+
+const BIO_METHOD *BIO_s_bio(void) { return &methods_biop; }
+
+size_t BIO_ctrl_get_read_request(BIO *bio) {
+ return BIO_ctrl(bio, BIO_C_GET_READ_REQUEST, 0, NULL);
+}
+
+size_t BIO_ctrl_get_write_guarantee(BIO *bio) {
+ return BIO_ctrl(bio, BIO_C_GET_WRITE_GUARANTEE, 0, NULL);
+}
+
+int BIO_shutdown_wr(BIO *bio) {
+ return BIO_ctrl(bio, BIO_C_SHUTDOWN_WR, 0, NULL);
+}
diff --git a/crypto/bio/printf.c b/crypto/bio/printf.c
new file mode 100644
index 0000000..e513ff3
--- /dev/null
+++ b/crypto/bio/printf.c
@@ -0,0 +1,110 @@
+/* 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.] */
+
+#define _BSD_SOURCE /* for snprintf, vprintf etc */
+
+#include <openssl/bio.h>
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include <openssl/mem.h>
+
+
+int BIO_printf(BIO *bio, const char *format, ...) {
+ va_list args;
+ int ret;
+
+ va_start(args, format);
+
+ ret = BIO_vprintf(bio, format, args);
+
+ va_end(args);
+ return ret;
+}
+
+int BIO_vprintf(BIO *bio, const char *format, va_list args) {
+ char buf[256], *out, out_malloced = 0;
+ int out_len, ret;
+
+ /* Note: this is assuming that va_list is ok to copy as POD. If the system
+ * defines it with a pointer to mutable state then passing it twice to
+ * vsnprintf will not work. */
+ out_len = vsnprintf(buf, sizeof(buf), format, args);
+ if (out_len >= sizeof(buf)) {
+ const int requested_len = out_len;
+ /* The output was truncated. */
+ out = OPENSSL_malloc(requested_len);
+ out_malloced = 1;
+ if (out == NULL) {
+ /* Unclear what can be done in this situation. OpenSSL has historically
+ * crashed and that seems better than producing the wrong output. */
+ abort();
+ }
+ out_len = vsnprintf(out, requested_len, format, args);
+ assert(out_len == requested_len);
+ } else {
+ out = buf;
+ }
+
+ ret = BIO_write(bio, out, out_len);
+ if (out_malloced) {
+ OPENSSL_free(out);
+ }
+
+ return ret;
+}
diff --git a/crypto/bio/socket.c b/crypto/bio/socket.c
new file mode 100644
index 0000000..93dd512
--- /dev/null
+++ b/crypto/bio/socket.c
@@ -0,0 +1,180 @@
+/* crypto/bio/bss_sock.c */
+/* 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/bio.h>
+
+#include <fcntl.h>
+
+#if !defined(OPENSSL_WINDOWS)
+#include <unistd.h>
+#endif
+
+#include "internal.h"
+
+
+static int sock_new(BIO *bio) {
+ bio->init = 0;
+ bio->num = 0;
+ bio->ptr = NULL;
+ bio->flags = 0;
+ return 1;
+}
+
+static int sock_free(BIO *bio) {
+ if (bio == NULL) {
+ return 0;
+ }
+
+ if (bio->shutdown) {
+ if (bio->init) {
+ close(bio->num);
+ }
+ bio->init = 0;
+ bio->flags = 0;
+ }
+ return 1;
+}
+
+static int sock_read(BIO *b, char *out, int outl) {
+ int ret = 0;
+
+ if (out == NULL) {
+ return 0;
+ }
+
+ bio_clear_socket_error();
+ ret = recv(b->num, out, outl, 0);
+ BIO_clear_retry_flags(b);
+ if (ret <= 0) {
+ if (bio_fd_should_retry(ret)) {
+ BIO_set_retry_read(b);
+ }
+ }
+ return ret;
+}
+
+static int sock_write(BIO *b, const char *in, int inl) {
+ int ret;
+
+ bio_clear_socket_error();
+ ret = send(b->num, in, inl, 0);
+ BIO_clear_retry_flags(b);
+ if (ret <= 0) {
+ if (bio_fd_should_retry(ret)) {
+ BIO_set_retry_write(b);
+ }
+ }
+ return ret;
+}
+
+static int sock_puts(BIO *bp, const char *str) {
+ return sock_write(bp, str, strlen(str));
+}
+
+static long sock_ctrl(BIO *b, int cmd, long num, void *ptr) {
+ long ret = 1;
+ int *ip;
+
+ switch (cmd) {
+ case BIO_C_SET_FD:
+ sock_free(b);
+ b->num = *((int *)ptr);
+ b->shutdown = (int)num;
+ b->init = 1;
+ break;
+ case BIO_C_GET_FD:
+ if (b->init) {
+ ip = (int *)ptr;
+ if (ip != NULL)
+ *ip = b->num;
+ ret = b->num;
+ } else
+ ret = -1;
+ break;
+ case BIO_CTRL_GET_CLOSE:
+ ret = b->shutdown;
+ break;
+ case BIO_CTRL_SET_CLOSE:
+ b->shutdown = (int)num;
+ break;
+ case BIO_CTRL_FLUSH:
+ ret = 1;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+static const BIO_METHOD methods_sockp = {
+ BIO_TYPE_SOCKET, "socket", sock_write, sock_read, sock_puts,
+ NULL /* gets, */, sock_ctrl, sock_new, sock_free, NULL,
+};
+
+const BIO_METHOD *BIO_s_socket(void) { return &methods_sockp; }
+
+BIO *BIO_new_socket(int fd, int close_flag) {
+ BIO *ret;
+
+ ret = BIO_new(BIO_s_socket());
+ if (ret == NULL) {
+ return NULL;
+ }
+ BIO_set_fd(ret, fd, close_flag);
+ return ret;
+}
diff --git a/crypto/bio/socket_helper.c b/crypto/bio/socket_helper.c
new file mode 100644
index 0000000..d304e12
--- /dev/null
+++ b/crypto/bio/socket_helper.c
@@ -0,0 +1,108 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#define _POSIX_SOURCE
+
+#include <openssl/bio.h>
+#include <openssl/err.h>
+
+#include <fcntl.h>
+#include <sys/types.h>
+
+#if !defined(OPENSSL_WINDOWS)
+#include <netdb.h>
+#include <unistd.h>
+#else
+#include <WinSock2.h>
+#include <WS2tcpip.h>
+typedef int socklen_t;
+#endif
+
+#include "internal.h"
+
+
+int bio_ip_and_port_to_socket_and_addr(int *out_sock,
+ struct sockaddr_storage *out_addr,
+ const char *hostname,
+ const char *port_str) {
+ struct addrinfo hint, *result, *cur;
+ int ret;
+
+ *out_sock = -1;
+
+ memset(&hint, 0, sizeof(hint));
+ hint.ai_family = AF_UNSPEC;
+ hint.ai_socktype = SOCK_STREAM;
+
+ ret = getaddrinfo(hostname, port_str, &hint, &result);
+ if (ret != 0) {
+ OPENSSL_PUT_ERROR(SYS, getaddrinfo, 0);
+ ERR_add_error_data(2, gai_strerror(ret));
+ return 0;
+ }
+
+ ret = 0;
+
+ for (cur = result; cur; cur = cur->ai_next) {
+ if (cur->ai_addrlen > sizeof(struct sockaddr_storage)) {
+ continue;
+ }
+ memset(out_addr, 0, sizeof(struct sockaddr_storage));
+ memcpy(out_addr, cur->ai_addr, cur->ai_addrlen);
+
+ *out_sock = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol);
+ if (*out_sock < 0) {
+ OPENSSL_PUT_SYSTEM_ERROR(socket);
+ goto out;
+ }
+
+ ret = 1;
+ break;
+ }
+
+out:
+ freeaddrinfo(result);
+ return ret;
+}
+
+int bio_socket_nbio(int sock, int on) {
+#if defined(OPENSSL_WINDOWS)
+ u_long arg = on;
+
+ return 0 == ioctlsocket(sock, FIONBIO, &arg);
+#else
+ int flags = fcntl(sock, F_GETFL, 0);
+ if (flags < 0) {
+ return 0;
+ }
+ if (!on) {
+ flags &= ~O_NONBLOCK;
+ } else {
+ flags |= O_NONBLOCK;
+ }
+ return fcntl(sock, F_SETFL, flags) == 0;
+#endif
+}
+
+void bio_clear_socket_error() {}
+
+int bio_sock_error(int sock) {
+ int error;
+ socklen_t error_size = sizeof(error);
+
+ if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&error, &error_size) < 0) {
+ return 1;
+ }
+ return error;
+}
diff --git a/crypto/bn/CMakeLists.txt b/crypto/bn/CMakeLists.txt
new file mode 100644
index 0000000..5d2dfcc
--- /dev/null
+++ b/crypto/bn/CMakeLists.txt
@@ -0,0 +1,81 @@
+include_directories(. .. ../../include)
+
+if (${ARCH} STREQUAL "x86_64")
+ set(
+ BN_ARCH_SOURCES
+
+ asm/x86_64-gcc.c
+ x86_64-mont.${ASM_EXT}
+ x86_64-mont5.${ASM_EXT}
+ modexp512-x86_64.${ASM_EXT}
+ rsaz-x86_64.${ASM_EXT}
+ rsaz-avx2.${ASM_EXT}
+
+ rsaz_exp.c
+ )
+endif()
+
+if (${ARCH} STREQUAL "x86")
+ set(
+ BN_ARCH_SOURCES
+
+ bn-586.${ASM_EXT}
+ co-586.${ASM_EXT}
+ x86-mont.${ASM_EXT}
+ x86.${ASM_EXT}
+ )
+endif()
+
+if (${ARCH} STREQUAL "arm")
+ set(
+ BN_ARCH_SOURCES
+
+ armv4-mont.${ASM_EXT}
+ )
+endif()
+
+add_library(
+ bn
+
+ OBJECT
+
+ bn_error.c
+ add.c
+ bn.c
+ cmp.c
+ convert.c
+ ctx.c
+ div.c
+ exponentiation.c
+ generic.c
+ gcd.c
+ kronecker.c
+ montgomery.c
+ mul.c
+ prime.c
+ random.c
+ shift.c
+ sqrt.c
+
+ ${BN_ARCH_SOURCES}
+)
+
+perlasm(x86_64-mont.${ASM_EXT} asm/x86_64-mont.pl)
+perlasm(x86_64-mont5.${ASM_EXT} asm/x86_64-mont5.pl)
+perlasm(x86_64-gf2m.${ASM_EXT} asm/x86_64-gf2m.pl)
+perlasm(modexp512-x86_64.${ASM_EXT} asm/modexp512-x86_64.pl)
+perlasm(rsaz-x86_64.${ASM_EXT} asm/rsaz-x86_64.pl)
+perlasm(rsaz-avx2.${ASM_EXT} asm/rsaz-avx2.pl)
+perlasm(bn-586.${ASM_EXT} asm/bn-586.pl)
+perlasm(co-586.${ASM_EXT} asm/co-586.pl)
+perlasm(x86-mont.${ASM_EXT} asm/x86-mont.pl)
+perlasm(x86.${ASM_EXT} asm/x86.pl)
+perlasm(armv4-mont.${ASM_EXT} asm/armv4-mont.pl)
+
+add_executable(
+ bn_test
+
+ bn_test.c
+)
+
+target_link_libraries(bn_test crypto)
diff --git a/crypto/bn/add.c b/crypto/bn/add.c
new file mode 100644
index 0000000..1c6b2d7
--- /dev/null
+++ b/crypto/bn/add.c
@@ -0,0 +1,394 @@
+/* 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/bn.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+#include "internal.h"
+
+
+int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
+ const BIGNUM *tmp;
+ int a_neg = a->neg, ret;
+
+ /* a + b a+b
+ * a + -b a-b
+ * -a + b b-a
+ * -a + -b -(a+b)
+ */
+ if (a_neg ^ b->neg) {
+ /* only one is negative */
+ if (a_neg) {
+ tmp = a;
+ a = b;
+ b = tmp;
+ }
+
+ /* we are now a - b */
+ if (BN_ucmp(a, b) < 0) {
+ if (!BN_usub(r, b, a)) {
+ return 0;
+ }
+ r->neg = 1;
+ } else {
+ if (!BN_usub(r, a, b)) {
+ return 0;
+ }
+ r->neg = 0;
+ }
+ return 1;
+ }
+
+ ret = BN_uadd(r, a, b);
+ r->neg = a_neg;
+ return ret;
+}
+
+int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
+ int max, min, dif;
+ BN_ULONG *ap, *bp, *rp, carry, t1, t2;
+ const BIGNUM *tmp;
+
+ if (a->top < b->top) {
+ tmp = a;
+ a = b;
+ b = tmp;
+ }
+ max = a->top;
+ min = b->top;
+ dif = max - min;
+
+ if (bn_wexpand(r, max + 1) == NULL) {
+ return 0;
+ }
+
+ r->top = max;
+
+ ap = a->d;
+ bp = b->d;
+ rp = r->d;
+
+ carry = bn_add_words(rp, ap, bp, min);
+ rp += min;
+ ap += min;
+ bp += min;
+
+ if (carry) {
+ while (dif) {
+ dif--;
+ t1 = *(ap++);
+ t2 = (t1 + 1) & BN_MASK2;
+ *(rp++) = t2;
+ if (t2) {
+ carry = 0;
+ break;
+ }
+ }
+ if (carry) {
+ /* carry != 0 => dif == 0 */
+ *rp = 1;
+ r->top++;
+ }
+ }
+
+ if (dif && rp != ap) {
+ while (dif--) {
+ /* copy remaining words if ap != rp */
+ *(rp++) = *(ap++);
+ }
+ }
+
+ r->neg = 0;
+ return 1;
+}
+
+int BN_add_word(BIGNUM *a, BN_ULONG w) {
+ BN_ULONG l;
+ int i;
+
+ w &= BN_MASK2;
+
+ /* degenerate case: w is zero */
+ if (!w) {
+ return 1;
+ }
+
+ /* degenerate case: a is zero */
+ if (BN_is_zero(a)) {
+ return BN_set_word(a, w);
+ }
+
+ /* handle 'a' when negative */
+ if (a->neg) {
+ a->neg = 0;
+ i = BN_sub_word(a, w);
+ if (!BN_is_zero(a)) {
+ a->neg = !(a->neg);
+ }
+ return i;
+ }
+
+ for (i = 0; w != 0 && i < a->top; i++) {
+ a->d[i] = l = (a->d[i] + w) & BN_MASK2;
+ w = (w > l) ? 1 : 0;
+ }
+
+ if (w && i == a->top) {
+ if (bn_wexpand(a, a->top + 1) == NULL) {
+ return 0;
+ }
+ a->top++;
+ a->d[i] = w;
+ }
+
+ return 1;
+}
+
+int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
+ int max;
+ int add = 0, neg = 0;
+ const BIGNUM *tmp;
+
+ /* a - b a-b
+ * a - -b a+b
+ * -a - b -(a+b)
+ * -a - -b b-a
+ */
+ if (a->neg) {
+ if (b->neg) {
+ tmp = a;
+ a = b;
+ b = tmp;
+ } else {
+ add = 1;
+ neg = 1;
+ }
+ } else {
+ if (b->neg) {
+ add = 1;
+ neg = 0;
+ }
+ }
+
+ if (add) {
+ if (!BN_uadd(r, a, b)) {
+ return 0;
+ }
+
+ r->neg = neg;
+ return 1;
+ }
+
+ /* We are actually doing a - b :-) */
+
+ max = (a->top > b->top) ? a->top : b->top;
+ if (bn_wexpand(r, max) == NULL) {
+ return 0;
+ }
+
+ if (BN_ucmp(a, b) < 0) {
+ if (!BN_usub(r, b, a)) {
+ return 0;
+ }
+ r->neg = 1;
+ } else {
+ if (!BN_usub(r, a, b)) {
+ return 0;
+ }
+ r->neg = 0;
+ }
+
+ return 1;
+}
+
+int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
+ int max, min, dif;
+ register BN_ULONG t1, t2, *ap, *bp, *rp;
+ int i, carry;
+
+ max = a->top;
+ min = b->top;
+ dif = max - min;
+
+ if (dif < 0) /* hmm... should not be happening */
+ {
+ OPENSSL_PUT_ERROR(BN, BN_usub, BN_R_ARG2_LT_ARG3);
+ return 0;
+ }
+
+ if (bn_wexpand(r, max) == NULL) {
+ return 0;
+ }
+
+ ap = a->d;
+ bp = b->d;
+ rp = r->d;
+
+ carry = 0;
+ for (i = min; i != 0; i--) {
+ t1 = *(ap++);
+ t2 = *(bp++);
+ if (carry) {
+ carry = (t1 <= t2);
+ t1 = (t1 - t2 - 1) & BN_MASK2;
+ } else {
+ carry = (t1 < t2);
+ t1 = (t1 - t2) & BN_MASK2;
+ }
+ *(rp++) = t1 & BN_MASK2;
+ }
+
+ if (carry) /* subtracted */
+ {
+ if (!dif) {
+ /* error: a < b */
+ return 0;
+ }
+
+ while (dif) {
+ dif--;
+ t1 = *(ap++);
+ t2 = (t1 - 1) & BN_MASK2;
+ *(rp++) = t2;
+ if (t1) {
+ break;
+ }
+ }
+ }
+
+ if (rp != ap) {
+ for (;;) {
+ if (!dif--) {
+ break;
+ }
+ rp[0] = ap[0];
+ if (!dif--) {
+ break;
+ }
+ rp[1] = ap[1];
+ if (!dif--) {
+ break;
+ }
+ rp[2] = ap[2];
+ if (!dif--) {
+ break;
+ }
+ rp[3] = ap[3];
+ rp += 4;
+ ap += 4;
+ }
+ }
+
+ r->top = max;
+ r->neg = 0;
+ bn_correct_top(r);
+
+ return 1;
+}
+
+int BN_sub_word(BIGNUM *a, BN_ULONG w) {
+ int i;
+
+ w &= BN_MASK2;
+
+ /* degenerate case: w is zero */
+ if (!w) {
+ return 1;
+ }
+
+ /* degenerate case: a is zero */
+ if (BN_is_zero(a)) {
+ i = BN_set_word(a, w);
+ if (i != 0) {
+ BN_set_negative(a, 1);
+ }
+ return i;
+ }
+
+ /* handle 'a' when negative */
+ if (a->neg) {
+ a->neg = 0;
+ i = BN_add_word(a, w);
+ a->neg = 1;
+ return i;
+ }
+
+ if ((a->top == 1) && (a->d[0] < w)) {
+ a->d[0] = w - a->d[0];
+ a->neg = 1;
+ return 1;
+ }
+
+ i = 0;
+ for (;;) {
+ if (a->d[i] >= w) {
+ a->d[i] -= w;
+ break;
+ } else {
+ a->d[i] = (a->d[i] - w) & BN_MASK2;
+ i++;
+ w = 1;
+ }
+ }
+
+ if ((a->d[i] == 0) && (i == (a->top - 1))) {
+ a->top--;
+ }
+
+ return 1;
+}
diff --git a/crypto/bn/asm/armv4-mont.pl b/crypto/bn/asm/armv4-mont.pl
new file mode 100644
index 0000000..fe81f9b
--- /dev/null
+++ b/crypto/bn/asm/armv4-mont.pl
@@ -0,0 +1,669 @@
+#!/usr/bin/env perl
+
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+
+# January 2007.
+
+# Montgomery multiplication for ARMv4.
+#
+# Performance improvement naturally varies among CPU implementations
+# and compilers. The code was observed to provide +65-35% improvement
+# [depending on key length, less for longer keys] on ARM920T, and
+# +115-80% on Intel IXP425. This is compared to pre-bn_mul_mont code
+# base and compiler generated code with in-lined umull and even umlal
+# instructions. The latter means that this code didn't really have an
+# "advantage" of utilizing some "secret" instruction.
+#
+# The code is interoperable with Thumb ISA and is rather compact, less
+# than 1/2KB. Windows CE port would be trivial, as it's exclusively
+# about decorations, ABI and instruction syntax are identical.
+
+# November 2013
+#
+# Add NEON code path, which handles lengths divisible by 8. RSA/DSA
+# performance improvement on Cortex-A8 is ~45-100% depending on key
+# length, more for longer keys. On Cortex-A15 the span is ~10-105%.
+# On Snapdragon S4 improvement was measured to vary from ~70% to
+# incredible ~380%, yes, 4.8x faster, for RSA4096 sign. But this is
+# rather because original integer-only code seems to perform
+# suboptimally on S4. Situation on Cortex-A9 is unfortunately
+# different. It's being looked into, but the trouble is that
+# performance for vectors longer than 256 bits is actually couple
+# of percent worse than for integer-only code. The code is chosen
+# for execution on all NEON-capable processors, because gain on
+# others outweighs the marginal loss on Cortex-A9.
+
+while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {}
+open STDOUT,">$output";
+
+$num="r0"; # starts as num argument, but holds &tp[num-1]
+$ap="r1";
+$bp="r2"; $bi="r2"; $rp="r2";
+$np="r3";
+$tp="r4";
+$aj="r5";
+$nj="r6";
+$tj="r7";
+$n0="r8";
+########### # r9 is reserved by ELF as platform specific, e.g. TLS pointer
+$alo="r10"; # sl, gcc uses it to keep @GOT
+$ahi="r11"; # fp
+$nlo="r12"; # ip
+########### # r13 is stack pointer
+$nhi="r14"; # lr
+########### # r15 is program counter
+
+#### argument block layout relative to &tp[num-1], a.k.a. $num
+$_rp="$num,#12*4";
+# ap permanently resides in r1
+$_bp="$num,#13*4";
+# np permanently resides in r3
+$_n0="$num,#14*4";
+$_num="$num,#15*4"; $_bpend=$_num;
+
+$code=<<___;
+#include "arm_arch.h"
+
+.text
+.code 32
+
+#if __ARM_ARCH__>=7
+.align 5
+.LOPENSSL_armcap:
+.word OPENSSL_armcap_P-bn_mul_mont
+#endif
+
+.global bn_mul_mont
+.type bn_mul_mont,%function
+
+.align 5
+bn_mul_mont:
+ ldr ip,[sp,#4] @ load num
+ stmdb sp!,{r0,r2} @ sp points at argument block
+#if __ARM_ARCH__>=7
+ tst ip,#7
+ bne .Lialu
+ adr r0,bn_mul_mont
+ ldr r2,.LOPENSSL_armcap
+ ldr r0,[r0,r2]
+ tst r0,#1 @ NEON available?
+ ldmia sp, {r0,r2}
+ beq .Lialu
+ add sp,sp,#8
+ b bn_mul8x_mont_neon
+.align 4
+.Lialu:
+#endif
+ cmp ip,#2
+ mov $num,ip @ load num
+ movlt r0,#0
+ addlt sp,sp,#2*4
+ blt .Labrt
+
+ stmdb sp!,{r4-r12,lr} @ save 10 registers
+
+ mov $num,$num,lsl#2 @ rescale $num for byte count
+ sub sp,sp,$num @ alloca(4*num)
+ sub sp,sp,#4 @ +extra dword
+ sub $num,$num,#4 @ "num=num-1"
+ add $tp,$bp,$num @ &bp[num-1]
+
+ add $num,sp,$num @ $num to point at &tp[num-1]
+ ldr $n0,[$_n0] @ &n0
+ ldr $bi,[$bp] @ bp[0]
+ ldr $aj,[$ap],#4 @ ap[0],ap++
+ ldr $nj,[$np],#4 @ np[0],np++
+ ldr $n0,[$n0] @ *n0
+ str $tp,[$_bpend] @ save &bp[num]
+
+ umull $alo,$ahi,$aj,$bi @ ap[0]*bp[0]
+ str $n0,[$_n0] @ save n0 value
+ mul $n0,$alo,$n0 @ "tp[0]"*n0
+ mov $nlo,#0
+ umlal $alo,$nlo,$nj,$n0 @ np[0]*n0+"t[0]"
+ mov $tp,sp
+
+.L1st:
+ ldr $aj,[$ap],#4 @ ap[j],ap++
+ mov $alo,$ahi
+ ldr $nj,[$np],#4 @ np[j],np++
+ mov $ahi,#0
+ umlal $alo,$ahi,$aj,$bi @ ap[j]*bp[0]
+ mov $nhi,#0
+ umlal $nlo,$nhi,$nj,$n0 @ np[j]*n0
+ adds $nlo,$nlo,$alo
+ str $nlo,[$tp],#4 @ tp[j-1]=,tp++
+ adc $nlo,$nhi,#0
+ cmp $tp,$num
+ bne .L1st
+
+ adds $nlo,$nlo,$ahi
+ ldr $tp,[$_bp] @ restore bp
+ mov $nhi,#0
+ ldr $n0,[$_n0] @ restore n0
+ adc $nhi,$nhi,#0
+ str $nlo,[$num] @ tp[num-1]=
+ str $nhi,[$num,#4] @ tp[num]=
+
+.Louter:
+ sub $tj,$num,sp @ "original" $num-1 value
+ sub $ap,$ap,$tj @ "rewind" ap to &ap[1]
+ ldr $bi,[$tp,#4]! @ *(++bp)
+ sub $np,$np,$tj @ "rewind" np to &np[1]
+ ldr $aj,[$ap,#-4] @ ap[0]
+ ldr $alo,[sp] @ tp[0]
+ ldr $nj,[$np,#-4] @ np[0]
+ ldr $tj,[sp,#4] @ tp[1]
+
+ mov $ahi,#0
+ umlal $alo,$ahi,$aj,$bi @ ap[0]*bp[i]+tp[0]
+ str $tp,[$_bp] @ save bp
+ mul $n0,$alo,$n0
+ mov $nlo,#0
+ umlal $alo,$nlo,$nj,$n0 @ np[0]*n0+"tp[0]"
+ mov $tp,sp
+
+.Linner:
+ ldr $aj,[$ap],#4 @ ap[j],ap++
+ adds $alo,$ahi,$tj @ +=tp[j]
+ ldr $nj,[$np],#4 @ np[j],np++
+ mov $ahi,#0
+ umlal $alo,$ahi,$aj,$bi @ ap[j]*bp[i]
+ mov $nhi,#0
+ umlal $nlo,$nhi,$nj,$n0 @ np[j]*n0
+ adc $ahi,$ahi,#0
+ ldr $tj,[$tp,#8] @ tp[j+1]
+ adds $nlo,$nlo,$alo
+ str $nlo,[$tp],#4 @ tp[j-1]=,tp++
+ adc $nlo,$nhi,#0
+ cmp $tp,$num
+ bne .Linner
+
+ adds $nlo,$nlo,$ahi
+ mov $nhi,#0
+ ldr $tp,[$_bp] @ restore bp
+ adc $nhi,$nhi,#0
+ ldr $n0,[$_n0] @ restore n0
+ adds $nlo,$nlo,$tj
+ ldr $tj,[$_bpend] @ restore &bp[num]
+ adc $nhi,$nhi,#0
+ str $nlo,[$num] @ tp[num-1]=
+ str $nhi,[$num,#4] @ tp[num]=
+
+ cmp $tp,$tj
+ bne .Louter
+
+ ldr $rp,[$_rp] @ pull rp
+ add $num,$num,#4 @ $num to point at &tp[num]
+ sub $aj,$num,sp @ "original" num value
+ mov $tp,sp @ "rewind" $tp
+ mov $ap,$tp @ "borrow" $ap
+ sub $np,$np,$aj @ "rewind" $np to &np[0]
+
+ subs $tj,$tj,$tj @ "clear" carry flag
+.Lsub: ldr $tj,[$tp],#4
+ ldr $nj,[$np],#4
+ sbcs $tj,$tj,$nj @ tp[j]-np[j]
+ str $tj,[$rp],#4 @ rp[j]=
+ teq $tp,$num @ preserve carry
+ bne .Lsub
+ sbcs $nhi,$nhi,#0 @ upmost carry
+ mov $tp,sp @ "rewind" $tp
+ sub $rp,$rp,$aj @ "rewind" $rp
+
+ and $ap,$tp,$nhi
+ bic $np,$rp,$nhi
+ orr $ap,$ap,$np @ ap=borrow?tp:rp
+
+.Lcopy: ldr $tj,[$ap],#4 @ copy or in-place refresh
+ str sp,[$tp],#4 @ zap tp
+ str $tj,[$rp],#4
+ cmp $tp,$num
+ bne .Lcopy
+
+ add sp,$num,#4 @ skip over tp[num+1]
+ ldmia sp!,{r4-r12,lr} @ restore registers
+ add sp,sp,#2*4 @ skip over {r0,r2}
+ mov r0,#1
+.Labrt: tst lr,#1
+ moveq pc,lr @ be binary compatible with V4, yet
+ bx lr @ interoperable with Thumb ISA:-)
+.size bn_mul_mont,.-bn_mul_mont
+___
+{
+sub Dlo() { shift=~m|q([1]?[0-9])|?"d".($1*2):""; }
+sub Dhi() { shift=~m|q([1]?[0-9])|?"d".($1*2+1):""; }
+
+my ($A0,$A1,$A2,$A3)=map("d$_",(0..3));
+my ($N0,$N1,$N2,$N3)=map("d$_",(4..7));
+my ($Z,$Temp)=("q4","q5");
+my ($A0xB,$A1xB,$A2xB,$A3xB,$A4xB,$A5xB,$A6xB,$A7xB)=map("q$_",(6..13));
+my ($Bi,$Ni,$M0)=map("d$_",(28..31));
+my $zero=&Dlo($Z);
+my $temp=&Dlo($Temp);
+
+my ($rptr,$aptr,$bptr,$nptr,$n0,$num)=map("r$_",(0..5));
+my ($tinptr,$toutptr,$inner,$outer)=map("r$_",(6..9));
+
+$code.=<<___;
+#if __ARM_ARCH__>=7
+.fpu neon
+
+.type bn_mul8x_mont_neon,%function
+.align 5
+bn_mul8x_mont_neon:
+ mov ip,sp
+ stmdb sp!,{r4-r11}
+ vstmdb sp!,{d8-d15} @ ABI specification says so
+ ldmia ip,{r4-r5} @ load rest of parameter block
+
+ sub $toutptr,sp,#16
+ vld1.32 {${Bi}[0]}, [$bptr,:32]!
+ sub $toutptr,$toutptr,$num,lsl#4
+ vld1.32 {$A0-$A3}, [$aptr]! @ can't specify :32 :-(
+ and $toutptr,$toutptr,#-64
+ vld1.32 {${M0}[0]}, [$n0,:32]
+ mov sp,$toutptr @ alloca
+ veor $zero,$zero,$zero
+ subs $inner,$num,#8
+ vzip.16 $Bi,$zero
+
+ vmull.u32 $A0xB,$Bi,${A0}[0]
+ vmull.u32 $A1xB,$Bi,${A0}[1]
+ vmull.u32 $A2xB,$Bi,${A1}[0]
+ vshl.i64 $temp,`&Dhi("$A0xB")`,#16
+ vmull.u32 $A3xB,$Bi,${A1}[1]
+
+ vadd.u64 $temp,$temp,`&Dlo("$A0xB")`
+ veor $zero,$zero,$zero
+ vmul.u32 $Ni,$temp,$M0
+
+ vmull.u32 $A4xB,$Bi,${A2}[0]
+ vld1.32 {$N0-$N3}, [$nptr]!
+ vmull.u32 $A5xB,$Bi,${A2}[1]
+ vmull.u32 $A6xB,$Bi,${A3}[0]
+ vzip.16 $Ni,$zero
+ vmull.u32 $A7xB,$Bi,${A3}[1]
+
+ bne .LNEON_1st
+
+ @ special case for num=8, everything is in register bank...
+
+ vmlal.u32 $A0xB,$Ni,${N0}[0]
+ sub $outer,$num,#1
+ vmlal.u32 $A1xB,$Ni,${N0}[1]
+ vmlal.u32 $A2xB,$Ni,${N1}[0]
+ vmlal.u32 $A3xB,$Ni,${N1}[1]
+
+ vmlal.u32 $A4xB,$Ni,${N2}[0]
+ vmov $Temp,$A0xB
+ vmlal.u32 $A5xB,$Ni,${N2}[1]
+ vmov $A0xB,$A1xB
+ vmlal.u32 $A6xB,$Ni,${N3}[0]
+ vmov $A1xB,$A2xB
+ vmlal.u32 $A7xB,$Ni,${N3}[1]
+ vmov $A2xB,$A3xB
+ vmov $A3xB,$A4xB
+ vshr.u64 $temp,$temp,#16
+ vmov $A4xB,$A5xB
+ vmov $A5xB,$A6xB
+ vadd.u64 $temp,$temp,`&Dhi("$Temp")`
+ vmov $A6xB,$A7xB
+ veor $A7xB,$A7xB
+ vshr.u64 $temp,$temp,#16
+
+ b .LNEON_outer8
+
+.align 4
+.LNEON_outer8:
+ vld1.32 {${Bi}[0]}, [$bptr,:32]!
+ veor $zero,$zero,$zero
+ vzip.16 $Bi,$zero
+ vadd.u64 `&Dlo("$A0xB")`,`&Dlo("$A0xB")`,$temp
+
+ vmlal.u32 $A0xB,$Bi,${A0}[0]
+ vmlal.u32 $A1xB,$Bi,${A0}[1]
+ vmlal.u32 $A2xB,$Bi,${A1}[0]
+ vshl.i64 $temp,`&Dhi("$A0xB")`,#16
+ vmlal.u32 $A3xB,$Bi,${A1}[1]
+
+ vadd.u64 $temp,$temp,`&Dlo("$A0xB")`
+ veor $zero,$zero,$zero
+ subs $outer,$outer,#1
+ vmul.u32 $Ni,$temp,$M0
+
+ vmlal.u32 $A4xB,$Bi,${A2}[0]
+ vmlal.u32 $A5xB,$Bi,${A2}[1]
+ vmlal.u32 $A6xB,$Bi,${A3}[0]
+ vzip.16 $Ni,$zero
+ vmlal.u32 $A7xB,$Bi,${A3}[1]
+
+ vmlal.u32 $A0xB,$Ni,${N0}[0]
+ vmlal.u32 $A1xB,$Ni,${N0}[1]
+ vmlal.u32 $A2xB,$Ni,${N1}[0]
+ vmlal.u32 $A3xB,$Ni,${N1}[1]
+
+ vmlal.u32 $A4xB,$Ni,${N2}[0]
+ vmov $Temp,$A0xB
+ vmlal.u32 $A5xB,$Ni,${N2}[1]
+ vmov $A0xB,$A1xB
+ vmlal.u32 $A6xB,$Ni,${N3}[0]
+ vmov $A1xB,$A2xB
+ vmlal.u32 $A7xB,$Ni,${N3}[1]
+ vmov $A2xB,$A3xB
+ vmov $A3xB,$A4xB
+ vshr.u64 $temp,$temp,#16
+ vmov $A4xB,$A5xB
+ vmov $A5xB,$A6xB
+ vadd.u64 $temp,$temp,`&Dhi("$Temp")`
+ vmov $A6xB,$A7xB
+ veor $A7xB,$A7xB
+ vshr.u64 $temp,$temp,#16
+
+ bne .LNEON_outer8
+
+ vadd.u64 `&Dlo("$A0xB")`,`&Dlo("$A0xB")`,$temp
+ mov $toutptr,sp
+ vshr.u64 $temp,`&Dlo("$A0xB")`,#16
+ mov $inner,$num
+ vadd.u64 `&Dhi("$A0xB")`,`&Dhi("$A0xB")`,$temp
+ add $tinptr,sp,#16
+ vshr.u64 $temp,`&Dhi("$A0xB")`,#16
+ vzip.16 `&Dlo("$A0xB")`,`&Dhi("$A0xB")`
+
+ b .LNEON_tail2
+
+.align 4
+.LNEON_1st:
+ vmlal.u32 $A0xB,$Ni,${N0}[0]
+ vld1.32 {$A0-$A3}, [$aptr]!
+ vmlal.u32 $A1xB,$Ni,${N0}[1]
+ subs $inner,$inner,#8
+ vmlal.u32 $A2xB,$Ni,${N1}[0]
+ vmlal.u32 $A3xB,$Ni,${N1}[1]
+
+ vmlal.u32 $A4xB,$Ni,${N2}[0]
+ vld1.32 {$N0-$N1}, [$nptr]!
+ vmlal.u32 $A5xB,$Ni,${N2}[1]
+ vst1.64 {$A0xB-$A1xB}, [$toutptr,:256]!
+ vmlal.u32 $A6xB,$Ni,${N3}[0]
+ vmlal.u32 $A7xB,$Ni,${N3}[1]
+ vst1.64 {$A2xB-$A3xB}, [$toutptr,:256]!
+
+ vmull.u32 $A0xB,$Bi,${A0}[0]
+ vld1.32 {$N2-$N3}, [$nptr]!
+ vmull.u32 $A1xB,$Bi,${A0}[1]
+ vst1.64 {$A4xB-$A5xB}, [$toutptr,:256]!
+ vmull.u32 $A2xB,$Bi,${A1}[0]
+ vmull.u32 $A3xB,$Bi,${A1}[1]
+ vst1.64 {$A6xB-$A7xB}, [$toutptr,:256]!
+
+ vmull.u32 $A4xB,$Bi,${A2}[0]
+ vmull.u32 $A5xB,$Bi,${A2}[1]
+ vmull.u32 $A6xB,$Bi,${A3}[0]
+ vmull.u32 $A7xB,$Bi,${A3}[1]
+
+ bne .LNEON_1st
+
+ vmlal.u32 $A0xB,$Ni,${N0}[0]
+ add $tinptr,sp,#16
+ vmlal.u32 $A1xB,$Ni,${N0}[1]
+ sub $aptr,$aptr,$num,lsl#2 @ rewind $aptr
+ vmlal.u32 $A2xB,$Ni,${N1}[0]
+ vld1.64 {$Temp}, [sp,:128]
+ vmlal.u32 $A3xB,$Ni,${N1}[1]
+ sub $outer,$num,#1
+
+ vmlal.u32 $A4xB,$Ni,${N2}[0]
+ vst1.64 {$A0xB-$A1xB}, [$toutptr,:256]!
+ vmlal.u32 $A5xB,$Ni,${N2}[1]
+ vshr.u64 $temp,$temp,#16
+ vld1.64 {$A0xB}, [$tinptr, :128]!
+ vmlal.u32 $A6xB,$Ni,${N3}[0]
+ vst1.64 {$A2xB-$A3xB}, [$toutptr,:256]!
+ vmlal.u32 $A7xB,$Ni,${N3}[1]
+
+ vst1.64 {$A4xB-$A5xB}, [$toutptr,:256]!
+ vadd.u64 $temp,$temp,`&Dhi("$Temp")`
+ veor $Z,$Z,$Z
+ vst1.64 {$A6xB-$A7xB}, [$toutptr,:256]!
+ vld1.64 {$A1xB-$A2xB}, [$tinptr, :256]!
+ vst1.64 {$Z}, [$toutptr,:128]
+ vshr.u64 $temp,$temp,#16
+
+ b .LNEON_outer
+
+.align 4
+.LNEON_outer:
+ vld1.32 {${Bi}[0]}, [$bptr,:32]!
+ sub $nptr,$nptr,$num,lsl#2 @ rewind $nptr
+ vld1.32 {$A0-$A3}, [$aptr]!
+ veor $zero,$zero,$zero
+ mov $toutptr,sp
+ vzip.16 $Bi,$zero
+ sub $inner,$num,#8
+ vadd.u64 `&Dlo("$A0xB")`,`&Dlo("$A0xB")`,$temp
+
+ vmlal.u32 $A0xB,$Bi,${A0}[0]
+ vld1.64 {$A3xB-$A4xB},[$tinptr,:256]!
+ vmlal.u32 $A1xB,$Bi,${A0}[1]
+ vmlal.u32 $A2xB,$Bi,${A1}[0]
+ vld1.64 {$A5xB-$A6xB},[$tinptr,:256]!
+ vmlal.u32 $A3xB,$Bi,${A1}[1]
+
+ vshl.i64 $temp,`&Dhi("$A0xB")`,#16
+ veor $zero,$zero,$zero
+ vadd.u64 $temp,$temp,`&Dlo("$A0xB")`
+ vld1.64 {$A7xB},[$tinptr,:128]!
+ vmul.u32 $Ni,$temp,$M0
+
+ vmlal.u32 $A4xB,$Bi,${A2}[0]
+ vld1.32 {$N0-$N3}, [$nptr]!
+ vmlal.u32 $A5xB,$Bi,${A2}[1]
+ vmlal.u32 $A6xB,$Bi,${A3}[0]
+ vzip.16 $Ni,$zero
+ vmlal.u32 $A7xB,$Bi,${A3}[1]
+
+.LNEON_inner:
+ vmlal.u32 $A0xB,$Ni,${N0}[0]
+ vld1.32 {$A0-$A3}, [$aptr]!
+ vmlal.u32 $A1xB,$Ni,${N0}[1]
+ subs $inner,$inner,#8
+ vmlal.u32 $A2xB,$Ni,${N1}[0]
+ vmlal.u32 $A3xB,$Ni,${N1}[1]
+ vst1.64 {$A0xB-$A1xB}, [$toutptr,:256]!
+
+ vmlal.u32 $A4xB,$Ni,${N2}[0]
+ vld1.64 {$A0xB}, [$tinptr, :128]!
+ vmlal.u32 $A5xB,$Ni,${N2}[1]
+ vst1.64 {$A2xB-$A3xB}, [$toutptr,:256]!
+ vmlal.u32 $A6xB,$Ni,${N3}[0]
+ vld1.64 {$A1xB-$A2xB}, [$tinptr, :256]!
+ vmlal.u32 $A7xB,$Ni,${N3}[1]
+ vst1.64 {$A4xB-$A5xB}, [$toutptr,:256]!
+
+ vmlal.u32 $A0xB,$Bi,${A0}[0]
+ vld1.64 {$A3xB-$A4xB}, [$tinptr, :256]!
+ vmlal.u32 $A1xB,$Bi,${A0}[1]
+ vst1.64 {$A6xB-$A7xB}, [$toutptr,:256]!
+ vmlal.u32 $A2xB,$Bi,${A1}[0]
+ vld1.64 {$A5xB-$A6xB}, [$tinptr, :256]!
+ vmlal.u32 $A3xB,$Bi,${A1}[1]
+ vld1.32 {$N0-$N3}, [$nptr]!
+
+ vmlal.u32 $A4xB,$Bi,${A2}[0]
+ vld1.64 {$A7xB}, [$tinptr, :128]!
+ vmlal.u32 $A5xB,$Bi,${A2}[1]
+ vmlal.u32 $A6xB,$Bi,${A3}[0]
+ vmlal.u32 $A7xB,$Bi,${A3}[1]
+
+ bne .LNEON_inner
+
+ vmlal.u32 $A0xB,$Ni,${N0}[0]
+ add $tinptr,sp,#16
+ vmlal.u32 $A1xB,$Ni,${N0}[1]
+ sub $aptr,$aptr,$num,lsl#2 @ rewind $aptr
+ vmlal.u32 $A2xB,$Ni,${N1}[0]
+ vld1.64 {$Temp}, [sp,:128]
+ vmlal.u32 $A3xB,$Ni,${N1}[1]
+ subs $outer,$outer,#1
+
+ vmlal.u32 $A4xB,$Ni,${N2}[0]
+ vst1.64 {$A0xB-$A1xB}, [$toutptr,:256]!
+ vmlal.u32 $A5xB,$Ni,${N2}[1]
+ vld1.64 {$A0xB}, [$tinptr, :128]!
+ vshr.u64 $temp,$temp,#16
+ vst1.64 {$A2xB-$A3xB}, [$toutptr,:256]!
+ vmlal.u32 $A6xB,$Ni,${N3}[0]
+ vld1.64 {$A1xB-$A2xB}, [$tinptr, :256]!
+ vmlal.u32 $A7xB,$Ni,${N3}[1]
+
+ vst1.64 {$A4xB-$A5xB}, [$toutptr,:256]!
+ vadd.u64 $temp,$temp,`&Dhi("$Temp")`
+ vst1.64 {$A6xB-$A7xB}, [$toutptr,:256]!
+ vshr.u64 $temp,$temp,#16
+
+ bne .LNEON_outer
+
+ mov $toutptr,sp
+ mov $inner,$num
+
+.LNEON_tail:
+ vadd.u64 `&Dlo("$A0xB")`,`&Dlo("$A0xB")`,$temp
+ vld1.64 {$A3xB-$A4xB}, [$tinptr, :256]!
+ vshr.u64 $temp,`&Dlo("$A0xB")`,#16
+ vadd.u64 `&Dhi("$A0xB")`,`&Dhi("$A0xB")`,$temp
+ vld1.64 {$A5xB-$A6xB}, [$tinptr, :256]!
+ vshr.u64 $temp,`&Dhi("$A0xB")`,#16
+ vld1.64 {$A7xB}, [$tinptr, :128]!
+ vzip.16 `&Dlo("$A0xB")`,`&Dhi("$A0xB")`
+
+.LNEON_tail2:
+ vadd.u64 `&Dlo("$A1xB")`,`&Dlo("$A1xB")`,$temp
+ vst1.32 {`&Dlo("$A0xB")`[0]}, [$toutptr, :32]!
+ vshr.u64 $temp,`&Dlo("$A1xB")`,#16
+ vadd.u64 `&Dhi("$A1xB")`,`&Dhi("$A1xB")`,$temp
+ vshr.u64 $temp,`&Dhi("$A1xB")`,#16
+ vzip.16 `&Dlo("$A1xB")`,`&Dhi("$A1xB")`
+
+ vadd.u64 `&Dlo("$A2xB")`,`&Dlo("$A2xB")`,$temp
+ vst1.32 {`&Dlo("$A1xB")`[0]}, [$toutptr, :32]!
+ vshr.u64 $temp,`&Dlo("$A2xB")`,#16
+ vadd.u64 `&Dhi("$A2xB")`,`&Dhi("$A2xB")`,$temp
+ vshr.u64 $temp,`&Dhi("$A2xB")`,#16
+ vzip.16 `&Dlo("$A2xB")`,`&Dhi("$A2xB")`
+
+ vadd.u64 `&Dlo("$A3xB")`,`&Dlo("$A3xB")`,$temp
+ vst1.32 {`&Dlo("$A2xB")`[0]}, [$toutptr, :32]!
+ vshr.u64 $temp,`&Dlo("$A3xB")`,#16
+ vadd.u64 `&Dhi("$A3xB")`,`&Dhi("$A3xB")`,$temp
+ vshr.u64 $temp,`&Dhi("$A3xB")`,#16
+ vzip.16 `&Dlo("$A3xB")`,`&Dhi("$A3xB")`
+
+ vadd.u64 `&Dlo("$A4xB")`,`&Dlo("$A4xB")`,$temp
+ vst1.32 {`&Dlo("$A3xB")`[0]}, [$toutptr, :32]!
+ vshr.u64 $temp,`&Dlo("$A4xB")`,#16
+ vadd.u64 `&Dhi("$A4xB")`,`&Dhi("$A4xB")`,$temp
+ vshr.u64 $temp,`&Dhi("$A4xB")`,#16
+ vzip.16 `&Dlo("$A4xB")`,`&Dhi("$A4xB")`
+
+ vadd.u64 `&Dlo("$A5xB")`,`&Dlo("$A5xB")`,$temp
+ vst1.32 {`&Dlo("$A4xB")`[0]}, [$toutptr, :32]!
+ vshr.u64 $temp,`&Dlo("$A5xB")`,#16
+ vadd.u64 `&Dhi("$A5xB")`,`&Dhi("$A5xB")`,$temp
+ vshr.u64 $temp,`&Dhi("$A5xB")`,#16
+ vzip.16 `&Dlo("$A5xB")`,`&Dhi("$A5xB")`
+
+ vadd.u64 `&Dlo("$A6xB")`,`&Dlo("$A6xB")`,$temp
+ vst1.32 {`&Dlo("$A5xB")`[0]}, [$toutptr, :32]!
+ vshr.u64 $temp,`&Dlo("$A6xB")`,#16
+ vadd.u64 `&Dhi("$A6xB")`,`&Dhi("$A6xB")`,$temp
+ vld1.64 {$A0xB}, [$tinptr, :128]!
+ vshr.u64 $temp,`&Dhi("$A6xB")`,#16
+ vzip.16 `&Dlo("$A6xB")`,`&Dhi("$A6xB")`
+
+ vadd.u64 `&Dlo("$A7xB")`,`&Dlo("$A7xB")`,$temp
+ vst1.32 {`&Dlo("$A6xB")`[0]}, [$toutptr, :32]!
+ vshr.u64 $temp,`&Dlo("$A7xB")`,#16
+ vadd.u64 `&Dhi("$A7xB")`,`&Dhi("$A7xB")`,$temp
+ vld1.64 {$A1xB-$A2xB}, [$tinptr, :256]!
+ vshr.u64 $temp,`&Dhi("$A7xB")`,#16
+ vzip.16 `&Dlo("$A7xB")`,`&Dhi("$A7xB")`
+ subs $inner,$inner,#8
+ vst1.32 {`&Dlo("$A7xB")`[0]}, [$toutptr, :32]!
+
+ bne .LNEON_tail
+
+ vst1.32 {${temp}[0]}, [$toutptr, :32] @ top-most bit
+ sub $nptr,$nptr,$num,lsl#2 @ rewind $nptr
+ subs $aptr,sp,#0 @ clear carry flag
+ add $bptr,sp,$num,lsl#2
+
+.LNEON_sub:
+ ldmia $aptr!, {r4-r7}
+ ldmia $nptr!, {r8-r11}
+ sbcs r8, r4,r8
+ sbcs r9, r5,r9
+ sbcs r10,r6,r10
+ sbcs r11,r7,r11
+ teq $aptr,$bptr @ preserves carry
+ stmia $rptr!, {r8-r11}
+ bne .LNEON_sub
+
+ ldr r10, [$aptr] @ load top-most bit
+ veor q0,q0,q0
+ sub r11,$bptr,sp @ this is num*4
+ veor q1,q1,q1
+ mov $aptr,sp
+ sub $rptr,$rptr,r11 @ rewind $rptr
+ mov $nptr,$bptr @ second 3/4th of frame
+ sbcs r10,r10,#0 @ result is carry flag
+
+.LNEON_copy_n_zap:
+ ldmia $aptr!, {r4-r7}
+ ldmia $rptr, {r8-r11}
+ movcc r8, r4
+ vst1.64 {q0-q1}, [$nptr,:256]! @ wipe
+ movcc r9, r5
+ movcc r10,r6
+ vst1.64 {q0-q1}, [$nptr,:256]! @ wipe
+ movcc r11,r7
+ ldmia $aptr, {r4-r7}
+ stmia $rptr!, {r8-r11}
+ sub $aptr,$aptr,#16
+ ldmia $rptr, {r8-r11}
+ movcc r8, r4
+ vst1.64 {q0-q1}, [$aptr,:256]! @ wipe
+ movcc r9, r5
+ movcc r10,r6
+ vst1.64 {q0-q1}, [$nptr,:256]! @ wipe
+ movcc r11,r7
+ teq $aptr,$bptr @ preserves carry
+ stmia $rptr!, {r8-r11}
+ bne .LNEON_copy_n_zap
+
+ sub sp,ip,#96
+ vldmia sp!,{d8-d15}
+ ldmia sp!,{r4-r11}
+ bx lr
+.size bn_mul8x_mont_neon,.-bn_mul8x_mont_neon
+#endif
+___
+}
+$code.=<<___;
+.asciz "Montgomery multiplication for ARMv4/NEON, CRYPTOGAMS by <appro\@openssl.org>"
+.align 2
+#if __ARM_ARCH__>=7
+.comm OPENSSL_armcap_P,4,4
+#endif
+___
+
+$code =~ s/\`([^\`]*)\`/eval $1/gem;
+$code =~ s/\bbx\s+lr\b/.word\t0xe12fff1e/gm; # make it possible to compile with -march=armv4
+print $code;
+close STDOUT;
diff --git a/crypto/bn/asm/bn-586.pl b/crypto/bn/asm/bn-586.pl
new file mode 100644
index 0000000..26d9bcb
--- /dev/null
+++ b/crypto/bn/asm/bn-586.pl
@@ -0,0 +1,774 @@
+#!/usr/bin/env perl
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+push(@INC,"${dir}","${dir}../../perlasm");
+require "x86asm.pl";
+
+&asm_init($ARGV[0],$0);
+
+$sse2=0;
+for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); }
+
+&external_label("OPENSSL_ia32cap_P") if ($sse2);
+
+&bn_mul_add_words("bn_mul_add_words");
+&bn_mul_words("bn_mul_words");
+&bn_sqr_words("bn_sqr_words");
+&bn_div_words("bn_div_words");
+&bn_add_words("bn_add_words");
+&bn_sub_words("bn_sub_words");
+&bn_sub_part_words("bn_sub_part_words");
+
+&asm_finish();
+
+sub bn_mul_add_words
+ {
+ local($name)=@_;
+
+ &function_begin_B($name,$sse2?"EXTRN\t_OPENSSL_ia32cap_P:DWORD":"");
+
+ $r="eax";
+ $a="edx";
+ $c="ecx";
+
+ if ($sse2) {
+ &picmeup("eax","OPENSSL_ia32cap_P");
+ &bt(&DWP(0,"eax"),26);
+ &jnc(&label("maw_non_sse2"));
+
+ &mov($r,&wparam(0));
+ &mov($a,&wparam(1));
+ &mov($c,&wparam(2));
+ &movd("mm0",&wparam(3)); # mm0 = w
+ &pxor("mm1","mm1"); # mm1 = carry_in
+ &jmp(&label("maw_sse2_entry"));
+
+ &set_label("maw_sse2_unrolled",16);
+ &movd("mm3",&DWP(0,$r,"",0)); # mm3 = r[0]
+ &paddq("mm1","mm3"); # mm1 = carry_in + r[0]
+ &movd("mm2",&DWP(0,$a,"",0)); # mm2 = a[0]
+ &pmuludq("mm2","mm0"); # mm2 = w*a[0]
+ &movd("mm4",&DWP(4,$a,"",0)); # mm4 = a[1]
+ &pmuludq("mm4","mm0"); # mm4 = w*a[1]
+ &movd("mm6",&DWP(8,$a,"",0)); # mm6 = a[2]
+ &pmuludq("mm6","mm0"); # mm6 = w*a[2]
+ &movd("mm7",&DWP(12,$a,"",0)); # mm7 = a[3]
+ &pmuludq("mm7","mm0"); # mm7 = w*a[3]
+ &paddq("mm1","mm2"); # mm1 = carry_in + r[0] + w*a[0]
+ &movd("mm3",&DWP(4,$r,"",0)); # mm3 = r[1]
+ &paddq("mm3","mm4"); # mm3 = r[1] + w*a[1]
+ &movd("mm5",&DWP(8,$r,"",0)); # mm5 = r[2]
+ &paddq("mm5","mm6"); # mm5 = r[2] + w*a[2]
+ &movd("mm4",&DWP(12,$r,"",0)); # mm4 = r[3]
+ &paddq("mm7","mm4"); # mm7 = r[3] + w*a[3]
+ &movd(&DWP(0,$r,"",0),"mm1");
+ &movd("mm2",&DWP(16,$a,"",0)); # mm2 = a[4]
+ &pmuludq("mm2","mm0"); # mm2 = w*a[4]
+ &psrlq("mm1",32); # mm1 = carry0
+ &movd("mm4",&DWP(20,$a,"",0)); # mm4 = a[5]
+ &pmuludq("mm4","mm0"); # mm4 = w*a[5]
+ &paddq("mm1","mm3"); # mm1 = carry0 + r[1] + w*a[1]
+ &movd("mm6",&DWP(24,$a,"",0)); # mm6 = a[6]
+ &pmuludq("mm6","mm0"); # mm6 = w*a[6]
+ &movd(&DWP(4,$r,"",0),"mm1");
+ &psrlq("mm1",32); # mm1 = carry1
+ &movd("mm3",&DWP(28,$a,"",0)); # mm3 = a[7]
+ &add($a,32);
+ &pmuludq("mm3","mm0"); # mm3 = w*a[7]
+ &paddq("mm1","mm5"); # mm1 = carry1 + r[2] + w*a[2]
+ &movd("mm5",&DWP(16,$r,"",0)); # mm5 = r[4]
+ &paddq("mm2","mm5"); # mm2 = r[4] + w*a[4]
+ &movd(&DWP(8,$r,"",0),"mm1");
+ &psrlq("mm1",32); # mm1 = carry2
+ &paddq("mm1","mm7"); # mm1 = carry2 + r[3] + w*a[3]
+ &movd("mm5",&DWP(20,$r,"",0)); # mm5 = r[5]
+ &paddq("mm4","mm5"); # mm4 = r[5] + w*a[5]
+ &movd(&DWP(12,$r,"",0),"mm1");
+ &psrlq("mm1",32); # mm1 = carry3
+ &paddq("mm1","mm2"); # mm1 = carry3 + r[4] + w*a[4]
+ &movd("mm5",&DWP(24,$r,"",0)); # mm5 = r[6]
+ &paddq("mm6","mm5"); # mm6 = r[6] + w*a[6]
+ &movd(&DWP(16,$r,"",0),"mm1");
+ &psrlq("mm1",32); # mm1 = carry4
+ &paddq("mm1","mm4"); # mm1 = carry4 + r[5] + w*a[5]
+ &movd("mm5",&DWP(28,$r,"",0)); # mm5 = r[7]
+ &paddq("mm3","mm5"); # mm3 = r[7] + w*a[7]
+ &movd(&DWP(20,$r,"",0),"mm1");
+ &psrlq("mm1",32); # mm1 = carry5
+ &paddq("mm1","mm6"); # mm1 = carry5 + r[6] + w*a[6]
+ &movd(&DWP(24,$r,"",0),"mm1");
+ &psrlq("mm1",32); # mm1 = carry6
+ &paddq("mm1","mm3"); # mm1 = carry6 + r[7] + w*a[7]
+ &movd(&DWP(28,$r,"",0),"mm1");
+ &lea($r,&DWP(32,$r));
+ &psrlq("mm1",32); # mm1 = carry_out
+
+ &sub($c,8);
+ &jz(&label("maw_sse2_exit"));
+ &set_label("maw_sse2_entry");
+ &test($c,0xfffffff8);
+ &jnz(&label("maw_sse2_unrolled"));
+
+ &set_label("maw_sse2_loop",4);
+ &movd("mm2",&DWP(0,$a)); # mm2 = a[i]
+ &movd("mm3",&DWP(0,$r)); # mm3 = r[i]
+ &pmuludq("mm2","mm0"); # a[i] *= w
+ &lea($a,&DWP(4,$a));
+ &paddq("mm1","mm3"); # carry += r[i]
+ &paddq("mm1","mm2"); # carry += a[i]*w
+ &movd(&DWP(0,$r),"mm1"); # r[i] = carry_low
+ &sub($c,1);
+ &psrlq("mm1",32); # carry = carry_high
+ &lea($r,&DWP(4,$r));
+ &jnz(&label("maw_sse2_loop"));
+ &set_label("maw_sse2_exit");
+ &movd("eax","mm1"); # c = carry_out
+ &emms();
+ &ret();
+
+ &set_label("maw_non_sse2",16);
+ }
+
+ # function_begin prologue
+ &push("ebp");
+ &push("ebx");
+ &push("esi");
+ &push("edi");
+
+ &comment("");
+ $Low="eax";
+ $High="edx";
+ $a="ebx";
+ $w="ebp";
+ $r="edi";
+ $c="esi";
+
+ &xor($c,$c); # clear carry
+ &mov($r,&wparam(0)); #
+
+ &mov("ecx",&wparam(2)); #
+ &mov($a,&wparam(1)); #
+
+ &and("ecx",0xfffffff8); # num / 8
+ &mov($w,&wparam(3)); #
+
+ &push("ecx"); # Up the stack for a tmp variable
+
+ &jz(&label("maw_finish"));
+
+ &set_label("maw_loop",16);
+
+ for ($i=0; $i<32; $i+=4)
+ {
+ &comment("Round $i");
+
+ &mov("eax",&DWP($i,$a)); # *a
+ &mul($w); # *a * w
+ &add("eax",$c); # L(t)+= c
+ &adc("edx",0); # H(t)+=carry
+ &add("eax",&DWP($i,$r)); # L(t)+= *r
+ &adc("edx",0); # H(t)+=carry
+ &mov(&DWP($i,$r),"eax"); # *r= L(t);
+ &mov($c,"edx"); # c= H(t);
+ }
+
+ &comment("");
+ &sub("ecx",8);
+ &lea($a,&DWP(32,$a));
+ &lea($r,&DWP(32,$r));
+ &jnz(&label("maw_loop"));
+
+ &set_label("maw_finish",0);
+ &mov("ecx",&wparam(2)); # get num
+ &and("ecx",7);
+ &jnz(&label("maw_finish2")); # helps branch prediction
+ &jmp(&label("maw_end"));
+
+ &set_label("maw_finish2",1);
+ for ($i=0; $i<7; $i++)
+ {
+ &comment("Tail Round $i");
+ &mov("eax",&DWP($i*4,$a)); # *a
+ &mul($w); # *a * w
+ &add("eax",$c); # L(t)+=c
+ &adc("edx",0); # H(t)+=carry
+ &add("eax",&DWP($i*4,$r)); # L(t)+= *r
+ &adc("edx",0); # H(t)+=carry
+ &dec("ecx") if ($i != 7-1);
+ &mov(&DWP($i*4,$r),"eax"); # *r= L(t);
+ &mov($c,"edx"); # c= H(t);
+ &jz(&label("maw_end")) if ($i != 7-1);
+ }
+ &set_label("maw_end",0);
+ &mov("eax",$c);
+
+ &pop("ecx"); # clear variable from
+
+ &function_end($name);
+ }
+
+sub bn_mul_words
+ {
+ local($name)=@_;
+
+ &function_begin_B($name,$sse2?"EXTRN\t_OPENSSL_ia32cap_P:DWORD":"");
+
+ $r="eax";
+ $a="edx";
+ $c="ecx";
+
+ if ($sse2) {
+ &picmeup("eax","OPENSSL_ia32cap_P");
+ &bt(&DWP(0,"eax"),26);
+ &jnc(&label("mw_non_sse2"));
+
+ &mov($r,&wparam(0));
+ &mov($a,&wparam(1));
+ &mov($c,&wparam(2));
+ &movd("mm0",&wparam(3)); # mm0 = w
+ &pxor("mm1","mm1"); # mm1 = carry = 0
+
+ &set_label("mw_sse2_loop",16);
+ &movd("mm2",&DWP(0,$a)); # mm2 = a[i]
+ &pmuludq("mm2","mm0"); # a[i] *= w
+ &lea($a,&DWP(4,$a));
+ &paddq("mm1","mm2"); # carry += a[i]*w
+ &movd(&DWP(0,$r),"mm1"); # r[i] = carry_low
+ &sub($c,1);
+ &psrlq("mm1",32); # carry = carry_high
+ &lea($r,&DWP(4,$r));
+ &jnz(&label("mw_sse2_loop"));
+
+ &movd("eax","mm1"); # return carry
+ &emms();
+ &ret();
+ &set_label("mw_non_sse2",16);
+ }
+
+ # function_begin prologue
+ &push("ebp");
+ &push("ebx");
+ &push("esi");
+ &push("edi");
+
+ &comment("");
+ $Low="eax";
+ $High="edx";
+ $a="ebx";
+ $w="ecx";
+ $r="edi";
+ $c="esi";
+ $num="ebp";
+
+ &xor($c,$c); # clear carry
+ &mov($r,&wparam(0)); #
+ &mov($a,&wparam(1)); #
+ &mov($num,&wparam(2)); #
+ &mov($w,&wparam(3)); #
+
+ &and($num,0xfffffff8); # num / 8
+ &jz(&label("mw_finish"));
+
+ &set_label("mw_loop",0);
+ for ($i=0; $i<32; $i+=4)
+ {
+ &comment("Round $i");
+
+ &mov("eax",&DWP($i,$a,"",0)); # *a
+ &mul($w); # *a * w
+ &add("eax",$c); # L(t)+=c
+ # XXX
+
+ &adc("edx",0); # H(t)+=carry
+ &mov(&DWP($i,$r,"",0),"eax"); # *r= L(t);
+
+ &mov($c,"edx"); # c= H(t);
+ }
+
+ &comment("");
+ &add($a,32);
+ &add($r,32);
+ &sub($num,8);
+ &jz(&label("mw_finish"));
+ &jmp(&label("mw_loop"));
+
+ &set_label("mw_finish",0);
+ &mov($num,&wparam(2)); # get num
+ &and($num,7);
+ &jnz(&label("mw_finish2"));
+ &jmp(&label("mw_end"));
+
+ &set_label("mw_finish2",1);
+ for ($i=0; $i<7; $i++)
+ {
+ &comment("Tail Round $i");
+ &mov("eax",&DWP($i*4,$a,"",0));# *a
+ &mul($w); # *a * w
+ &add("eax",$c); # L(t)+=c
+ # XXX
+ &adc("edx",0); # H(t)+=carry
+ &mov(&DWP($i*4,$r,"",0),"eax");# *r= L(t);
+ &mov($c,"edx"); # c= H(t);
+ &dec($num) if ($i != 7-1);
+ &jz(&label("mw_end")) if ($i != 7-1);
+ }
+ &set_label("mw_end",0);
+ &mov("eax",$c);
+
+ &function_end($name);
+ }
+
+sub bn_sqr_words
+ {
+ local($name)=@_;
+
+ &function_begin_B($name,$sse2?"EXTRN\t_OPENSSL_ia32cap_P:DWORD":"");
+
+ $r="eax";
+ $a="edx";
+ $c="ecx";
+
+ if ($sse2) {
+ &picmeup("eax","OPENSSL_ia32cap_P");
+ &bt(&DWP(0,"eax"),26);
+ &jnc(&label("sqr_non_sse2"));
+
+ &mov($r,&wparam(0));
+ &mov($a,&wparam(1));
+ &mov($c,&wparam(2));
+
+ &set_label("sqr_sse2_loop",16);
+ &movd("mm0",&DWP(0,$a)); # mm0 = a[i]
+ &pmuludq("mm0","mm0"); # a[i] *= a[i]
+ &lea($a,&DWP(4,$a)); # a++
+ &movq(&QWP(0,$r),"mm0"); # r[i] = a[i]*a[i]
+ &sub($c,1);
+ &lea($r,&DWP(8,$r)); # r += 2
+ &jnz(&label("sqr_sse2_loop"));
+
+ &emms();
+ &ret();
+ &set_label("sqr_non_sse2",16);
+ }
+
+ # function_begin prologue
+ &push("ebp");
+ &push("ebx");
+ &push("esi");
+ &push("edi");
+
+ &comment("");
+ $r="esi";
+ $a="edi";
+ $num="ebx";
+
+ &mov($r,&wparam(0)); #
+ &mov($a,&wparam(1)); #
+ &mov($num,&wparam(2)); #
+
+ &and($num,0xfffffff8); # num / 8
+ &jz(&label("sw_finish"));
+
+ &set_label("sw_loop",0);
+ for ($i=0; $i<32; $i+=4)
+ {
+ &comment("Round $i");
+ &mov("eax",&DWP($i,$a,"",0)); # *a
+ # XXX
+ &mul("eax"); # *a * *a
+ &mov(&DWP($i*2,$r,"",0),"eax"); #
+ &mov(&DWP($i*2+4,$r,"",0),"edx");#
+ }
+
+ &comment("");
+ &add($a,32);
+ &add($r,64);
+ &sub($num,8);
+ &jnz(&label("sw_loop"));
+
+ &set_label("sw_finish",0);
+ &mov($num,&wparam(2)); # get num
+ &and($num,7);
+ &jz(&label("sw_end"));
+
+ for ($i=0; $i<7; $i++)
+ {
+ &comment("Tail Round $i");
+ &mov("eax",&DWP($i*4,$a,"",0)); # *a
+ # XXX
+ &mul("eax"); # *a * *a
+ &mov(&DWP($i*8,$r,"",0),"eax"); #
+ &dec($num) if ($i != 7-1);
+ &mov(&DWP($i*8+4,$r,"",0),"edx");
+ &jz(&label("sw_end")) if ($i != 7-1);
+ }
+ &set_label("sw_end",0);
+
+ &function_end($name);
+ }
+
+sub bn_div_words
+ {
+ local($name)=@_;
+
+ &function_begin_B($name,"");
+ &mov("edx",&wparam(0)); #
+ &mov("eax",&wparam(1)); #
+ &mov("ecx",&wparam(2)); #
+ &div("ecx");
+ &ret();
+ &function_end_B($name);
+ }
+
+sub bn_add_words
+ {
+ local($name)=@_;
+
+ &function_begin($name,"");
+
+ &comment("");
+ $a="esi";
+ $b="edi";
+ $c="eax";
+ $r="ebx";
+ $tmp1="ecx";
+ $tmp2="edx";
+ $num="ebp";
+
+ &mov($r,&wparam(0)); # get r
+ &mov($a,&wparam(1)); # get a
+ &mov($b,&wparam(2)); # get b
+ &mov($num,&wparam(3)); # get num
+ &xor($c,$c); # clear carry
+ &and($num,0xfffffff8); # num / 8
+
+ &jz(&label("aw_finish"));
+
+ &set_label("aw_loop",0);
+ for ($i=0; $i<8; $i++)
+ {
+ &comment("Round $i");
+
+ &mov($tmp1,&DWP($i*4,$a,"",0)); # *a
+ &mov($tmp2,&DWP($i*4,$b,"",0)); # *b
+ &add($tmp1,$c);
+ &mov($c,0);
+ &adc($c,$c);
+ &add($tmp1,$tmp2);
+ &adc($c,0);
+ &mov(&DWP($i*4,$r,"",0),$tmp1); # *r
+ }
+
+ &comment("");
+ &add($a,32);
+ &add($b,32);
+ &add($r,32);
+ &sub($num,8);
+ &jnz(&label("aw_loop"));
+
+ &set_label("aw_finish",0);
+ &mov($num,&wparam(3)); # get num
+ &and($num,7);
+ &jz(&label("aw_end"));
+
+ for ($i=0; $i<7; $i++)
+ {
+ &comment("Tail Round $i");
+ &mov($tmp1,&DWP($i*4,$a,"",0)); # *a
+ &mov($tmp2,&DWP($i*4,$b,"",0));# *b
+ &add($tmp1,$c);
+ &mov($c,0);
+ &adc($c,$c);
+ &add($tmp1,$tmp2);
+ &adc($c,0);
+ &dec($num) if ($i != 6);
+ &mov(&DWP($i*4,$r,"",0),$tmp1); # *r
+ &jz(&label("aw_end")) if ($i != 6);
+ }
+ &set_label("aw_end",0);
+
+# &mov("eax",$c); # $c is "eax"
+
+ &function_end($name);
+ }
+
+sub bn_sub_words
+ {
+ local($name)=@_;
+
+ &function_begin($name,"");
+
+ &comment("");
+ $a="esi";
+ $b="edi";
+ $c="eax";
+ $r="ebx";
+ $tmp1="ecx";
+ $tmp2="edx";
+ $num="ebp";
+
+ &mov($r,&wparam(0)); # get r
+ &mov($a,&wparam(1)); # get a
+ &mov($b,&wparam(2)); # get b
+ &mov($num,&wparam(3)); # get num
+ &xor($c,$c); # clear carry
+ &and($num,0xfffffff8); # num / 8
+
+ &jz(&label("aw_finish"));
+
+ &set_label("aw_loop",0);
+ for ($i=0; $i<8; $i++)
+ {
+ &comment("Round $i");
+
+ &mov($tmp1,&DWP($i*4,$a,"",0)); # *a
+ &mov($tmp2,&DWP($i*4,$b,"",0)); # *b
+ &sub($tmp1,$c);
+ &mov($c,0);
+ &adc($c,$c);
+ &sub($tmp1,$tmp2);
+ &adc($c,0);
+ &mov(&DWP($i*4,$r,"",0),$tmp1); # *r
+ }
+
+ &comment("");
+ &add($a,32);
+ &add($b,32);
+ &add($r,32);
+ &sub($num,8);
+ &jnz(&label("aw_loop"));
+
+ &set_label("aw_finish",0);
+ &mov($num,&wparam(3)); # get num
+ &and($num,7);
+ &jz(&label("aw_end"));
+
+ for ($i=0; $i<7; $i++)
+ {
+ &comment("Tail Round $i");
+ &mov($tmp1,&DWP($i*4,$a,"",0)); # *a
+ &mov($tmp2,&DWP($i*4,$b,"",0));# *b
+ &sub($tmp1,$c);
+ &mov($c,0);
+ &adc($c,$c);
+ &sub($tmp1,$tmp2);
+ &adc($c,0);
+ &dec($num) if ($i != 6);
+ &mov(&DWP($i*4,$r,"",0),$tmp1); # *r
+ &jz(&label("aw_end")) if ($i != 6);
+ }
+ &set_label("aw_end",0);
+
+# &mov("eax",$c); # $c is "eax"
+
+ &function_end($name);
+ }
+
+sub bn_sub_part_words
+ {
+ local($name)=@_;
+
+ &function_begin($name,"");
+
+ &comment("");
+ $a="esi";
+ $b="edi";
+ $c="eax";
+ $r="ebx";
+ $tmp1="ecx";
+ $tmp2="edx";
+ $num="ebp";
+
+ &mov($r,&wparam(0)); # get r
+ &mov($a,&wparam(1)); # get a
+ &mov($b,&wparam(2)); # get b
+ &mov($num,&wparam(3)); # get num
+ &xor($c,$c); # clear carry
+ &and($num,0xfffffff8); # num / 8
+
+ &jz(&label("aw_finish"));
+
+ &set_label("aw_loop",0);
+ for ($i=0; $i<8; $i++)
+ {
+ &comment("Round $i");
+
+ &mov($tmp1,&DWP($i*4,$a,"",0)); # *a
+ &mov($tmp2,&DWP($i*4,$b,"",0)); # *b
+ &sub($tmp1,$c);
+ &mov($c,0);
+ &adc($c,$c);
+ &sub($tmp1,$tmp2);
+ &adc($c,0);
+ &mov(&DWP($i*4,$r,"",0),$tmp1); # *r
+ }
+
+ &comment("");
+ &add($a,32);
+ &add($b,32);
+ &add($r,32);
+ &sub($num,8);
+ &jnz(&label("aw_loop"));
+
+ &set_label("aw_finish",0);
+ &mov($num,&wparam(3)); # get num
+ &and($num,7);
+ &jz(&label("aw_end"));
+
+ for ($i=0; $i<7; $i++)
+ {
+ &comment("Tail Round $i");
+ &mov($tmp1,&DWP(0,$a,"",0)); # *a
+ &mov($tmp2,&DWP(0,$b,"",0));# *b
+ &sub($tmp1,$c);
+ &mov($c,0);
+ &adc($c,$c);
+ &sub($tmp1,$tmp2);
+ &adc($c,0);
+ &mov(&DWP(0,$r,"",0),$tmp1); # *r
+ &add($a, 4);
+ &add($b, 4);
+ &add($r, 4);
+ &dec($num) if ($i != 6);
+ &jz(&label("aw_end")) if ($i != 6);
+ }
+ &set_label("aw_end",0);
+
+ &cmp(&wparam(4),0);
+ &je(&label("pw_end"));
+
+ &mov($num,&wparam(4)); # get dl
+ &cmp($num,0);
+ &je(&label("pw_end"));
+ &jge(&label("pw_pos"));
+
+ &comment("pw_neg");
+ &mov($tmp2,0);
+ &sub($tmp2,$num);
+ &mov($num,$tmp2);
+ &and($num,0xfffffff8); # num / 8
+ &jz(&label("pw_neg_finish"));
+
+ &set_label("pw_neg_loop",0);
+ for ($i=0; $i<8; $i++)
+ {
+ &comment("dl<0 Round $i");
+
+ &mov($tmp1,0);
+ &mov($tmp2,&DWP($i*4,$b,"",0)); # *b
+ &sub($tmp1,$c);
+ &mov($c,0);
+ &adc($c,$c);
+ &sub($tmp1,$tmp2);
+ &adc($c,0);
+ &mov(&DWP($i*4,$r,"",0),$tmp1); # *r
+ }
+
+ &comment("");
+ &add($b,32);
+ &add($r,32);
+ &sub($num,8);
+ &jnz(&label("pw_neg_loop"));
+
+ &set_label("pw_neg_finish",0);
+ &mov($tmp2,&wparam(4)); # get dl
+ &mov($num,0);
+ &sub($num,$tmp2);
+ &and($num,7);
+ &jz(&label("pw_end"));
+
+ for ($i=0; $i<7; $i++)
+ {
+ &comment("dl<0 Tail Round $i");
+ &mov($tmp1,0);
+ &mov($tmp2,&DWP($i*4,$b,"",0));# *b
+ &sub($tmp1,$c);
+ &mov($c,0);
+ &adc($c,$c);
+ &sub($tmp1,$tmp2);
+ &adc($c,0);
+ &dec($num) if ($i != 6);
+ &mov(&DWP($i*4,$r,"",0),$tmp1); # *r
+ &jz(&label("pw_end")) if ($i != 6);
+ }
+
+ &jmp(&label("pw_end"));
+
+ &set_label("pw_pos",0);
+
+ &and($num,0xfffffff8); # num / 8
+ &jz(&label("pw_pos_finish"));
+
+ &set_label("pw_pos_loop",0);
+
+ for ($i=0; $i<8; $i++)
+ {
+ &comment("dl>0 Round $i");
+
+ &mov($tmp1,&DWP($i*4,$a,"",0)); # *a
+ &sub($tmp1,$c);
+ &mov(&DWP($i*4,$r,"",0),$tmp1); # *r
+ &jnc(&label("pw_nc".$i));
+ }
+
+ &comment("");
+ &add($a,32);
+ &add($r,32);
+ &sub($num,8);
+ &jnz(&label("pw_pos_loop"));
+
+ &set_label("pw_pos_finish",0);
+ &mov($num,&wparam(4)); # get dl
+ &and($num,7);
+ &jz(&label("pw_end"));
+
+ for ($i=0; $i<7; $i++)
+ {
+ &comment("dl>0 Tail Round $i");
+ &mov($tmp1,&DWP($i*4,$a,"",0)); # *a
+ &sub($tmp1,$c);
+ &mov(&DWP($i*4,$r,"",0),$tmp1); # *r
+ &jnc(&label("pw_tail_nc".$i));
+ &dec($num) if ($i != 6);
+ &jz(&label("pw_end")) if ($i != 6);
+ }
+ &mov($c,1);
+ &jmp(&label("pw_end"));
+
+ &set_label("pw_nc_loop",0);
+ for ($i=0; $i<8; $i++)
+ {
+ &mov($tmp1,&DWP($i*4,$a,"",0)); # *a
+ &mov(&DWP($i*4,$r,"",0),$tmp1); # *r
+ &set_label("pw_nc".$i,0);
+ }
+
+ &comment("");
+ &add($a,32);
+ &add($r,32);
+ &sub($num,8);
+ &jnz(&label("pw_nc_loop"));
+
+ &mov($num,&wparam(4)); # get dl
+ &and($num,7);
+ &jz(&label("pw_nc_end"));
+
+ for ($i=0; $i<7; $i++)
+ {
+ &mov($tmp1,&DWP($i*4,$a,"",0)); # *a
+ &mov(&DWP($i*4,$r,"",0),$tmp1); # *r
+ &set_label("pw_tail_nc".$i,0);
+ &dec($num) if ($i != 6);
+ &jz(&label("pw_nc_end")) if ($i != 6);
+ }
+
+ &set_label("pw_nc_end",0);
+ &mov($c,0);
+
+ &set_label("pw_end",0);
+
+# &mov("eax",$c); # $c is "eax"
+
+ &function_end($name);
+ }
+
diff --git a/crypto/bn/asm/co-586.pl b/crypto/bn/asm/co-586.pl
new file mode 100644
index 0000000..57101a6
--- /dev/null
+++ b/crypto/bn/asm/co-586.pl
@@ -0,0 +1,287 @@
+#!/usr/local/bin/perl
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+push(@INC,"${dir}","${dir}../../perlasm");
+require "x86asm.pl";
+
+&asm_init($ARGV[0],$0);
+
+&bn_mul_comba("bn_mul_comba8",8);
+&bn_mul_comba("bn_mul_comba4",4);
+&bn_sqr_comba("bn_sqr_comba8",8);
+&bn_sqr_comba("bn_sqr_comba4",4);
+
+&asm_finish();
+
+sub mul_add_c
+ {
+ local($a,$ai,$b,$bi,$c0,$c1,$c2,$pos,$i,$na,$nb)=@_;
+
+ # pos == -1 if eax and edx are pre-loaded, 0 to load from next
+ # words, and 1 if load return value
+
+ &comment("mul a[$ai]*b[$bi]");
+
+ # "eax" and "edx" will always be pre-loaded.
+ # &mov("eax",&DWP($ai*4,$a,"",0)) ;
+ # &mov("edx",&DWP($bi*4,$b,"",0));
+
+ &mul("edx");
+ &add($c0,"eax");
+ &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 0; # laod next a
+ &mov("eax",&wparam(0)) if $pos > 0; # load r[]
+ ###
+ &adc($c1,"edx");
+ &mov("edx",&DWP(($nb)*4,$b,"",0)) if $pos == 0; # laod next b
+ &mov("edx",&DWP(($nb)*4,$b,"",0)) if $pos == 1; # laod next b
+ ###
+ &adc($c2,0);
+ # is pos > 1, it means it is the last loop
+ &mov(&DWP($i*4,"eax","",0),$c0) if $pos > 0; # save r[];
+ &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 1; # laod next a
+ }
+
+sub sqr_add_c
+ {
+ local($r,$a,$ai,$bi,$c0,$c1,$c2,$pos,$i,$na,$nb)=@_;
+
+ # pos == -1 if eax and edx are pre-loaded, 0 to load from next
+ # words, and 1 if load return value
+
+ &comment("sqr a[$ai]*a[$bi]");
+
+ # "eax" and "edx" will always be pre-loaded.
+ # &mov("eax",&DWP($ai*4,$a,"",0)) ;
+ # &mov("edx",&DWP($bi*4,$b,"",0));
+
+ if ($ai == $bi)
+ { &mul("eax");}
+ else
+ { &mul("edx");}
+ &add($c0,"eax");
+ &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 0; # load next a
+ ###
+ &adc($c1,"edx");
+ &mov("edx",&DWP(($nb)*4,$a,"",0)) if ($pos == 1) && ($na != $nb);
+ ###
+ &adc($c2,0);
+ # is pos > 1, it means it is the last loop
+ &mov(&DWP($i*4,$r,"",0),$c0) if $pos > 0; # save r[];
+ &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 1; # load next b
+ }
+
+sub sqr_add_c2
+ {
+ local($r,$a,$ai,$bi,$c0,$c1,$c2,$pos,$i,$na,$nb)=@_;
+
+ # pos == -1 if eax and edx are pre-loaded, 0 to load from next
+ # words, and 1 if load return value
+
+ &comment("sqr a[$ai]*a[$bi]");
+
+ # "eax" and "edx" will always be pre-loaded.
+ # &mov("eax",&DWP($ai*4,$a,"",0)) ;
+ # &mov("edx",&DWP($bi*4,$a,"",0));
+
+ if ($ai == $bi)
+ { &mul("eax");}
+ else
+ { &mul("edx");}
+ &add("eax","eax");
+ ###
+ &adc("edx","edx");
+ ###
+ &adc($c2,0);
+ &add($c0,"eax");
+ &adc($c1,"edx");
+ &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 0; # load next a
+ &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 1; # load next b
+ &adc($c2,0);
+ &mov(&DWP($i*4,$r,"",0),$c0) if $pos > 0; # save r[];
+ &mov("edx",&DWP(($nb)*4,$a,"",0)) if ($pos <= 1) && ($na != $nb);
+ ###
+ }
+
+sub bn_mul_comba
+ {
+ local($name,$num)=@_;
+ local($a,$b,$c0,$c1,$c2);
+ local($i,$as,$ae,$bs,$be,$ai,$bi);
+ local($tot,$end);
+
+ &function_begin_B($name,"");
+
+ $c0="ebx";
+ $c1="ecx";
+ $c2="ebp";
+ $a="esi";
+ $b="edi";
+
+ $as=0;
+ $ae=0;
+ $bs=0;
+ $be=0;
+ $tot=$num+$num-1;
+
+ &push("esi");
+ &mov($a,&wparam(1));
+ &push("edi");
+ &mov($b,&wparam(2));
+ &push("ebp");
+ &push("ebx");
+
+ &xor($c0,$c0);
+ &mov("eax",&DWP(0,$a,"",0)); # load the first word
+ &xor($c1,$c1);
+ &mov("edx",&DWP(0,$b,"",0)); # load the first second
+
+ for ($i=0; $i<$tot; $i++)
+ {
+ $ai=$as;
+ $bi=$bs;
+ $end=$be+1;
+
+ &comment("################## Calculate word $i");
+
+ for ($j=$bs; $j<$end; $j++)
+ {
+ &xor($c2,$c2) if ($j == $bs);
+ if (($j+1) == $end)
+ {
+ $v=1;
+ $v=2 if (($i+1) == $tot);
+ }
+ else
+ { $v=0; }
+ if (($j+1) != $end)
+ {
+ $na=($ai-1);
+ $nb=($bi+1);
+ }
+ else
+ {
+ $na=$as+($i < ($num-1));
+ $nb=$bs+($i >= ($num-1));
+ }
+#printf STDERR "[$ai,$bi] -> [$na,$nb]\n";
+ &mul_add_c($a,$ai,$b,$bi,$c0,$c1,$c2,$v,$i,$na,$nb);
+ if ($v)
+ {
+ &comment("saved r[$i]");
+ # &mov("eax",&wparam(0));
+ # &mov(&DWP($i*4,"eax","",0),$c0);
+ ($c0,$c1,$c2)=($c1,$c2,$c0);
+ }
+ $ai--;
+ $bi++;
+ }
+ $as++ if ($i < ($num-1));
+ $ae++ if ($i >= ($num-1));
+
+ $bs++ if ($i >= ($num-1));
+ $be++ if ($i < ($num-1));
+ }
+ &comment("save r[$i]");
+ # &mov("eax",&wparam(0));
+ &mov(&DWP($i*4,"eax","",0),$c0);
+
+ &pop("ebx");
+ &pop("ebp");
+ &pop("edi");
+ &pop("esi");
+ &ret();
+ &function_end_B($name);
+ }
+
+sub bn_sqr_comba
+ {
+ local($name,$num)=@_;
+ local($r,$a,$c0,$c1,$c2)=@_;
+ local($i,$as,$ae,$bs,$be,$ai,$bi);
+ local($b,$tot,$end,$half);
+
+ &function_begin_B($name,"");
+
+ $c0="ebx";
+ $c1="ecx";
+ $c2="ebp";
+ $a="esi";
+ $r="edi";
+
+ &push("esi");
+ &push("edi");
+ &push("ebp");
+ &push("ebx");
+ &mov($r,&wparam(0));
+ &mov($a,&wparam(1));
+ &xor($c0,$c0);
+ &xor($c1,$c1);
+ &mov("eax",&DWP(0,$a,"",0)); # load the first word
+
+ $as=0;
+ $ae=0;
+ $bs=0;
+ $be=0;
+ $tot=$num+$num-1;
+
+ for ($i=0; $i<$tot; $i++)
+ {
+ $ai=$as;
+ $bi=$bs;
+ $end=$be+1;
+
+ &comment("############### Calculate word $i");
+ for ($j=$bs; $j<$end; $j++)
+ {
+ &xor($c2,$c2) if ($j == $bs);
+ if (($ai-1) < ($bi+1))
+ {
+ $v=1;
+ $v=2 if ($i+1) == $tot;
+ }
+ else
+ { $v=0; }
+ if (!$v)
+ {
+ $na=$ai-1;
+ $nb=$bi+1;
+ }
+ else
+ {
+ $na=$as+($i < ($num-1));
+ $nb=$bs+($i >= ($num-1));
+ }
+ if ($ai == $bi)
+ {
+ &sqr_add_c($r,$a,$ai,$bi,
+ $c0,$c1,$c2,$v,$i,$na,$nb);
+ }
+ else
+ {
+ &sqr_add_c2($r,$a,$ai,$bi,
+ $c0,$c1,$c2,$v,$i,$na,$nb);
+ }
+ if ($v)
+ {
+ &comment("saved r[$i]");
+ #&mov(&DWP($i*4,$r,"",0),$c0);
+ ($c0,$c1,$c2)=($c1,$c2,$c0);
+ last;
+ }
+ $ai--;
+ $bi++;
+ }
+ $as++ if ($i < ($num-1));
+ $ae++ if ($i >= ($num-1));
+
+ $bs++ if ($i >= ($num-1));
+ $be++ if ($i < ($num-1));
+ }
+ &mov(&DWP($i*4,$r,"",0),$c0);
+ &pop("ebx");
+ &pop("ebp");
+ &pop("edi");
+ &pop("esi");
+ &ret();
+ &function_end_B($name);
+ }
diff --git a/crypto/bn/asm/modexp512-x86_64.pl b/crypto/bn/asm/modexp512-x86_64.pl
new file mode 100644
index 0000000..bfd6e97
--- /dev/null
+++ b/crypto/bn/asm/modexp512-x86_64.pl
@@ -0,0 +1,1497 @@
+#!/usr/bin/env perl
+#
+# Copyright (c) 2010-2011 Intel Corp.
+# Author: Vinodh.Gopal@intel.com
+# Jim Guilford
+# Erdinc.Ozturk@intel.com
+# Maxim.Perminov@intel.com
+#
+# More information about algorithm used can be found at:
+# http://www.cse.buffalo.edu/srds2009/escs2009_submission_Gopal.pdf
+#
+# ====================================================================
+# Copyright (c) 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
+# 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.
+# ====================================================================
+
+$flavour = shift;
+$output = shift;
+if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
+
+my $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;
+
+use strict;
+my $code=".text\n\n";
+my $m=0;
+
+#
+# Define x512 macros
+#
+
+#MULSTEP_512_ADD MACRO x7, x6, x5, x4, x3, x2, x1, x0, dst, src1, src2, add_src, tmp1, tmp2
+#
+# uses rax, rdx, and args
+sub MULSTEP_512_ADD
+{
+ my ($x, $DST, $SRC2, $ASRC, $OP, $TMP)=@_;
+ my @X=@$x; # make a copy
+$code.=<<___;
+ mov (+8*0)($SRC2), %rax
+ mul $OP # rdx:rax = %OP * [0]
+ mov ($ASRC), $X[0]
+ add %rax, $X[0]
+ adc \$0, %rdx
+ mov $X[0], $DST
+___
+for(my $i=1;$i<8;$i++) {
+$code.=<<___;
+ mov %rdx, $TMP
+
+ mov (+8*$i)($SRC2), %rax
+ mul $OP # rdx:rax = %OP * [$i]
+ mov (+8*$i)($ASRC), $X[$i]
+ add %rax, $X[$i]
+ adc \$0, %rdx
+ add $TMP, $X[$i]
+ adc \$0, %rdx
+___
+}
+$code.=<<___;
+ mov %rdx, $X[0]
+___
+}
+
+#MULSTEP_512 MACRO x7, x6, x5, x4, x3, x2, x1, x0, dst, src2, src1_val, tmp
+#
+# uses rax, rdx, and args
+sub MULSTEP_512
+{
+ my ($x, $DST, $SRC2, $OP, $TMP)=@_;
+ my @X=@$x; # make a copy
+$code.=<<___;
+ mov (+8*0)($SRC2), %rax
+ mul $OP # rdx:rax = %OP * [0]
+ add %rax, $X[0]
+ adc \$0, %rdx
+ mov $X[0], $DST
+___
+for(my $i=1;$i<8;$i++) {
+$code.=<<___;
+ mov %rdx, $TMP
+
+ mov (+8*$i)($SRC2), %rax
+ mul $OP # rdx:rax = %OP * [$i]
+ add %rax, $X[$i]
+ adc \$0, %rdx
+ add $TMP, $X[$i]
+ adc \$0, %rdx
+___
+}
+$code.=<<___;
+ mov %rdx, $X[0]
+___
+}
+
+#
+# Swizzle Macros
+#
+
+# macro to copy data from flat space to swizzled table
+#MACRO swizzle pDst, pSrc, tmp1, tmp2
+# pDst and pSrc are modified
+sub swizzle
+{
+ my ($pDst, $pSrc, $cnt, $d0)=@_;
+$code.=<<___;
+ mov \$8, $cnt
+loop_$m:
+ mov ($pSrc), $d0
+ mov $d0#w, ($pDst)
+ shr \$16, $d0
+ mov $d0#w, (+64*1)($pDst)
+ shr \$16, $d0
+ mov $d0#w, (+64*2)($pDst)
+ shr \$16, $d0
+ mov $d0#w, (+64*3)($pDst)
+ lea 8($pSrc), $pSrc
+ lea 64*4($pDst), $pDst
+ dec $cnt
+ jnz loop_$m
+___
+
+ $m++;
+}
+
+# macro to copy data from swizzled table to flat space
+#MACRO unswizzle pDst, pSrc, tmp*3
+sub unswizzle
+{
+ my ($pDst, $pSrc, $cnt, $d0, $d1)=@_;
+$code.=<<___;
+ mov \$4, $cnt
+loop_$m:
+ movzxw (+64*3+256*0)($pSrc), $d0
+ movzxw (+64*3+256*1)($pSrc), $d1
+ shl \$16, $d0
+ shl \$16, $d1
+ mov (+64*2+256*0)($pSrc), $d0#w
+ mov (+64*2+256*1)($pSrc), $d1#w
+ shl \$16, $d0
+ shl \$16, $d1
+ mov (+64*1+256*0)($pSrc), $d0#w
+ mov (+64*1+256*1)($pSrc), $d1#w
+ shl \$16, $d0
+ shl \$16, $d1
+ mov (+64*0+256*0)($pSrc), $d0#w
+ mov (+64*0+256*1)($pSrc), $d1#w
+ mov $d0, (+8*0)($pDst)
+ mov $d1, (+8*1)($pDst)
+ lea 256*2($pSrc), $pSrc
+ lea 8*2($pDst), $pDst
+ sub \$1, $cnt
+ jnz loop_$m
+___
+
+ $m++;
+}
+
+#
+# Data Structures
+#
+
+# Reduce Data
+#
+#
+# Offset Value
+# 0C0 Carries
+# 0B8 X2[10]
+# 0B0 X2[9]
+# 0A8 X2[8]
+# 0A0 X2[7]
+# 098 X2[6]
+# 090 X2[5]
+# 088 X2[4]
+# 080 X2[3]
+# 078 X2[2]
+# 070 X2[1]
+# 068 X2[0]
+# 060 X1[12] P[10]
+# 058 X1[11] P[9] Z[8]
+# 050 X1[10] P[8] Z[7]
+# 048 X1[9] P[7] Z[6]
+# 040 X1[8] P[6] Z[5]
+# 038 X1[7] P[5] Z[4]
+# 030 X1[6] P[4] Z[3]
+# 028 X1[5] P[3] Z[2]
+# 020 X1[4] P[2] Z[1]
+# 018 X1[3] P[1] Z[0]
+# 010 X1[2] P[0] Y[2]
+# 008 X1[1] Q[1] Y[1]
+# 000 X1[0] Q[0] Y[0]
+
+my $X1_offset = 0; # 13 qwords
+my $X2_offset = $X1_offset + 13*8; # 11 qwords
+my $Carries_offset = $X2_offset + 11*8; # 1 qword
+my $Q_offset = 0; # 2 qwords
+my $P_offset = $Q_offset + 2*8; # 11 qwords
+my $Y_offset = 0; # 3 qwords
+my $Z_offset = $Y_offset + 3*8; # 9 qwords
+
+my $Red_Data_Size = $Carries_offset + 1*8; # (25 qwords)
+
+#
+# Stack Frame
+#
+#
+# offset value
+# ... <old stack contents>
+# ...
+# 280 Garray
+
+# 278 tmp16[15]
+# ... ...
+# 200 tmp16[0]
+
+# 1F8 tmp[7]
+# ... ...
+# 1C0 tmp[0]
+
+# 1B8 GT[7]
+# ... ...
+# 180 GT[0]
+
+# 178 Reduce Data
+# ... ...
+# 0B8 Reduce Data
+# 0B0 reserved
+# 0A8 reserved
+# 0A0 reserved
+# 098 reserved
+# 090 reserved
+# 088 reduce result addr
+# 080 exp[8]
+
+# ...
+# 048 exp[1]
+# 040 exp[0]
+
+# 038 reserved
+# 030 loop_idx
+# 028 pg
+# 020 i
+# 018 pData ; arg 4
+# 010 pG ; arg 2
+# 008 pResult ; arg 1
+# 000 rsp ; stack pointer before subtract
+
+my $rsp_offset = 0;
+my $pResult_offset = 8*1 + $rsp_offset;
+my $pG_offset = 8*1 + $pResult_offset;
+my $pData_offset = 8*1 + $pG_offset;
+my $i_offset = 8*1 + $pData_offset;
+my $pg_offset = 8*1 + $i_offset;
+my $loop_idx_offset = 8*1 + $pg_offset;
+my $reserved1_offset = 8*1 + $loop_idx_offset;
+my $exp_offset = 8*1 + $reserved1_offset;
+my $red_result_addr_offset= 8*9 + $exp_offset;
+my $reserved2_offset = 8*1 + $red_result_addr_offset;
+my $Reduce_Data_offset = 8*5 + $reserved2_offset;
+my $GT_offset = $Red_Data_Size + $Reduce_Data_offset;
+my $tmp_offset = 8*8 + $GT_offset;
+my $tmp16_offset = 8*8 + $tmp_offset;
+my $garray_offset = 8*16 + $tmp16_offset;
+my $mem_size = 8*8*32 + $garray_offset;
+
+#
+# Offsets within Reduce Data
+#
+#
+# struct MODF_2FOLD_MONT_512_C1_DATA {
+# UINT64 t[8][8];
+# UINT64 m[8];
+# UINT64 m1[8]; /* 2^768 % m */
+# UINT64 m2[8]; /* 2^640 % m */
+# UINT64 k1[2]; /* (- 1/m) % 2^128 */
+# };
+
+my $T = 0;
+my $M = 512; # = 8 * 8 * 8
+my $M1 = 576; # = 8 * 8 * 9 /* += 8 * 8 */
+my $M2 = 640; # = 8 * 8 * 10 /* += 8 * 8 */
+my $K1 = 704; # = 8 * 8 * 11 /* += 8 * 8 */
+
+#
+# FUNCTIONS
+#
+
+{{{
+#
+# MULADD_128x512 : Function to multiply 128-bits (2 qwords) by 512-bits (8 qwords)
+# and add 512-bits (8 qwords)
+# to get 640 bits (10 qwords)
+# Input: 128-bit mul source: [rdi+8*1], rbp
+# 512-bit mul source: [rsi+8*n]
+# 512-bit add source: r15, r14, ..., r9, r8
+# Output: r9, r8, r15, r14, r13, r12, r11, r10, [rcx+8*1], [rcx+8*0]
+# Clobbers all regs except: rcx, rsi, rdi
+$code.=<<___;
+.type MULADD_128x512,\@abi-omnipotent
+.align 16
+MULADD_128x512:
+___
+ &MULSTEP_512([map("%r$_",(8..15))], "(+8*0)(%rcx)", "%rsi", "%rbp", "%rbx");
+$code.=<<___;
+ mov (+8*1)(%rdi), %rbp
+___
+ &MULSTEP_512([map("%r$_",(9..15,8))], "(+8*1)(%rcx)", "%rsi", "%rbp", "%rbx");
+$code.=<<___;
+ ret
+.size MULADD_128x512,.-MULADD_128x512
+___
+}}}
+
+{{{
+#MULADD_256x512 MACRO pDst, pA, pB, OP, TMP, X7, X6, X5, X4, X3, X2, X1, X0
+#
+# Inputs: pDst: Destination (768 bits, 12 qwords)
+# pA: Multiplicand (1024 bits, 16 qwords)
+# pB: Multiplicand (512 bits, 8 qwords)
+# Dst = Ah * B + Al
+# where Ah is (in qwords) A[15:12] (256 bits) and Al is A[7:0] (512 bits)
+# Results in X3 X2 X1 X0 X7 X6 X5 X4 Dst[3:0]
+# Uses registers: arguments, RAX, RDX
+sub MULADD_256x512
+{
+ my ($pDst, $pA, $pB, $OP, $TMP, $X)=@_;
+$code.=<<___;
+ mov (+8*12)($pA), $OP
+___
+ &MULSTEP_512_ADD($X, "(+8*0)($pDst)", $pB, $pA, $OP, $TMP);
+ push(@$X,shift(@$X));
+
+$code.=<<___;
+ mov (+8*13)($pA), $OP
+___
+ &MULSTEP_512($X, "(+8*1)($pDst)", $pB, $OP, $TMP);
+ push(@$X,shift(@$X));
+
+$code.=<<___;
+ mov (+8*14)($pA), $OP
+___
+ &MULSTEP_512($X, "(+8*2)($pDst)", $pB, $OP, $TMP);
+ push(@$X,shift(@$X));
+
+$code.=<<___;
+ mov (+8*15)($pA), $OP
+___
+ &MULSTEP_512($X, "(+8*3)($pDst)", $pB, $OP, $TMP);
+ push(@$X,shift(@$X));
+}
+
+#
+# mont_reduce(UINT64 *x, /* 1024 bits, 16 qwords */
+# UINT64 *m, /* 512 bits, 8 qwords */
+# MODF_2FOLD_MONT_512_C1_DATA *data,
+# UINT64 *r) /* 512 bits, 8 qwords */
+# Input: x (number to be reduced): tmp16 (Implicit)
+# m (modulus): [pM] (Implicit)
+# data (reduce data): [pData] (Implicit)
+# Output: r (result): Address in [red_res_addr]
+# result also in: r9, r8, r15, r14, r13, r12, r11, r10
+
+my @X=map("%r$_",(8..15));
+
+$code.=<<___;
+.type mont_reduce,\@abi-omnipotent
+.align 16
+mont_reduce:
+___
+
+my $STACK_DEPTH = 8;
+ #
+ # X1 = Xh * M1 + Xl
+$code.=<<___;
+ lea (+$Reduce_Data_offset+$X1_offset+$STACK_DEPTH)(%rsp), %rdi # pX1 (Dst) 769 bits, 13 qwords
+ mov (+$pData_offset+$STACK_DEPTH)(%rsp), %rsi # pM1 (Bsrc) 512 bits, 8 qwords
+ add \$$M1, %rsi
+ lea (+$tmp16_offset+$STACK_DEPTH)(%rsp), %rcx # X (Asrc) 1024 bits, 16 qwords
+
+___
+
+ &MULADD_256x512("%rdi", "%rcx", "%rsi", "%rbp", "%rbx", \@X); # rotates @X 4 times
+ # results in r11, r10, r9, r8, r15, r14, r13, r12, X1[3:0]
+
+$code.=<<___;
+ xor %rax, %rax
+ # X1 += xl
+ add (+8*8)(%rcx), $X[4]
+ adc (+8*9)(%rcx), $X[5]
+ adc (+8*10)(%rcx), $X[6]
+ adc (+8*11)(%rcx), $X[7]
+ adc \$0, %rax
+ # X1 is now rax, r11-r8, r15-r12, tmp16[3:0]
+
+ #
+ # check for carry ;; carry stored in rax
+ mov $X[4], (+8*8)(%rdi) # rdi points to X1
+ mov $X[5], (+8*9)(%rdi)
+ mov $X[6], %rbp
+ mov $X[7], (+8*11)(%rdi)
+
+ mov %rax, (+$Reduce_Data_offset+$Carries_offset+$STACK_DEPTH)(%rsp)
+
+ mov (+8*0)(%rdi), $X[4]
+ mov (+8*1)(%rdi), $X[5]
+ mov (+8*2)(%rdi), $X[6]
+ mov (+8*3)(%rdi), $X[7]
+
+ # X1 is now stored in: X1[11], rbp, X1[9:8], r15-r8
+ # rdi -> X1
+ # rsi -> M1
+
+ #
+ # X2 = Xh * M2 + Xl
+ # do first part (X2 = Xh * M2)
+ add \$8*10, %rdi # rdi -> pXh ; 128 bits, 2 qwords
+ # Xh is actually { [rdi+8*1], rbp }
+ add \$`$M2-$M1`, %rsi # rsi -> M2
+ lea (+$Reduce_Data_offset+$X2_offset+$STACK_DEPTH)(%rsp), %rcx # rcx -> pX2 ; 641 bits, 11 qwords
+___
+ unshift(@X,pop(@X)); unshift(@X,pop(@X));
+$code.=<<___;
+
+ call MULADD_128x512 # args in rcx, rdi / rbp, rsi, r15-r8
+ # result in r9, r8, r15, r14, r13, r12, r11, r10, X2[1:0]
+ mov (+$Reduce_Data_offset+$Carries_offset+$STACK_DEPTH)(%rsp), %rax
+
+ # X2 += Xl
+ add (+8*8-8*10)(%rdi), $X[6] # (-8*10) is to adjust rdi -> Xh to Xl
+ adc (+8*9-8*10)(%rdi), $X[7]
+ mov $X[6], (+8*8)(%rcx)
+ mov $X[7], (+8*9)(%rcx)
+
+ adc %rax, %rax
+ mov %rax, (+$Reduce_Data_offset+$Carries_offset+$STACK_DEPTH)(%rsp)
+
+ lea (+$Reduce_Data_offset+$Q_offset+$STACK_DEPTH)(%rsp), %rdi # rdi -> pQ ; 128 bits, 2 qwords
+ add \$`$K1-$M2`, %rsi # rsi -> pK1 ; 128 bits, 2 qwords
+
+ # MUL_128x128t128 rdi, rcx, rsi ; Q = X2 * K1 (bottom half)
+ # B1:B0 = rsi[1:0] = K1[1:0]
+ # A1:A0 = rcx[1:0] = X2[1:0]
+ # Result = rdi[1],rbp = Q[1],rbp
+ mov (%rsi), %r8 # B0
+ mov (+8*1)(%rsi), %rbx # B1
+
+ mov (%rcx), %rax # A0
+ mul %r8 # B0
+ mov %rax, %rbp
+ mov %rdx, %r9
+
+ mov (+8*1)(%rcx), %rax # A1
+ mul %r8 # B0
+ add %rax, %r9
+
+ mov (%rcx), %rax # A0
+ mul %rbx # B1
+ add %rax, %r9
+
+ mov %r9, (+8*1)(%rdi)
+ # end MUL_128x128t128
+
+ sub \$`$K1-$M`, %rsi
+
+ mov (%rcx), $X[6]
+ mov (+8*1)(%rcx), $X[7] # r9:r8 = X2[1:0]
+
+ call MULADD_128x512 # args in rcx, rdi / rbp, rsi, r15-r8
+ # result in r9, r8, r15, r14, r13, r12, r11, r10, X2[1:0]
+
+ # load first half of m to rdx, rdi, rbx, rax
+ # moved this here for efficiency
+ mov (+8*0)(%rsi), %rax
+ mov (+8*1)(%rsi), %rbx
+ mov (+8*2)(%rsi), %rdi
+ mov (+8*3)(%rsi), %rdx
+
+ # continue with reduction
+ mov (+$Reduce_Data_offset+$Carries_offset+$STACK_DEPTH)(%rsp), %rbp
+
+ add (+8*8)(%rcx), $X[6]
+ adc (+8*9)(%rcx), $X[7]
+
+ #accumulate the final carry to rbp
+ adc %rbp, %rbp
+
+ # Add in overflow corrections: R = (X2>>128) += T[overflow]
+ # R = {r9, r8, r15, r14, ..., r10}
+ shl \$3, %rbp
+ mov (+$pData_offset+$STACK_DEPTH)(%rsp), %rcx # rsi -> Data (and points to T)
+ add %rcx, %rbp # pT ; 512 bits, 8 qwords, spread out
+
+ # rsi will be used to generate a mask after the addition
+ xor %rsi, %rsi
+
+ add (+8*8*0)(%rbp), $X[0]
+ adc (+8*8*1)(%rbp), $X[1]
+ adc (+8*8*2)(%rbp), $X[2]
+ adc (+8*8*3)(%rbp), $X[3]
+ adc (+8*8*4)(%rbp), $X[4]
+ adc (+8*8*5)(%rbp), $X[5]
+ adc (+8*8*6)(%rbp), $X[6]
+ adc (+8*8*7)(%rbp), $X[7]
+
+ # if there is a carry: rsi = 0xFFFFFFFFFFFFFFFF
+ # if carry is clear: rsi = 0x0000000000000000
+ sbb \$0, %rsi
+
+ # if carry is clear, subtract 0. Otherwise, subtract 256 bits of m
+ and %rsi, %rax
+ and %rsi, %rbx
+ and %rsi, %rdi
+ and %rsi, %rdx
+
+ mov \$1, %rbp
+ sub %rax, $X[0]
+ sbb %rbx, $X[1]
+ sbb %rdi, $X[2]
+ sbb %rdx, $X[3]
+
+ # if there is a borrow: rbp = 0
+ # if there is no borrow: rbp = 1
+ # this is used to save the borrows in between the first half and the 2nd half of the subtraction of m
+ sbb \$0, %rbp
+
+ #load second half of m to rdx, rdi, rbx, rax
+
+ add \$$M, %rcx
+ mov (+8*4)(%rcx), %rax
+ mov (+8*5)(%rcx), %rbx
+ mov (+8*6)(%rcx), %rdi
+ mov (+8*7)(%rcx), %rdx
+
+ # use the rsi mask as before
+ # if carry is clear, subtract 0. Otherwise, subtract 256 bits of m
+ and %rsi, %rax
+ and %rsi, %rbx
+ and %rsi, %rdi
+ and %rsi, %rdx
+
+ # if rbp = 0, there was a borrow before, it is moved to the carry flag
+ # if rbp = 1, there was not a borrow before, carry flag is cleared
+ sub \$1, %rbp
+
+ sbb %rax, $X[4]
+ sbb %rbx, $X[5]
+ sbb %rdi, $X[6]
+ sbb %rdx, $X[7]
+
+ # write R back to memory
+
+ mov (+$red_result_addr_offset+$STACK_DEPTH)(%rsp), %rsi
+ mov $X[0], (+8*0)(%rsi)
+ mov $X[1], (+8*1)(%rsi)
+ mov $X[2], (+8*2)(%rsi)
+ mov $X[3], (+8*3)(%rsi)
+ mov $X[4], (+8*4)(%rsi)
+ mov $X[5], (+8*5)(%rsi)
+ mov $X[6], (+8*6)(%rsi)
+ mov $X[7], (+8*7)(%rsi)
+
+ ret
+.size mont_reduce,.-mont_reduce
+___
+}}}
+
+{{{
+#MUL_512x512 MACRO pDst, pA, pB, x7, x6, x5, x4, x3, x2, x1, x0, tmp*2
+#
+# Inputs: pDst: Destination (1024 bits, 16 qwords)
+# pA: Multiplicand (512 bits, 8 qwords)
+# pB: Multiplicand (512 bits, 8 qwords)
+# Uses registers rax, rdx, args
+# B operand in [pB] and also in x7...x0
+sub MUL_512x512
+{
+ my ($pDst, $pA, $pB, $x, $OP, $TMP, $pDst_o)=@_;
+ my ($pDst, $pDst_o) = ($pDst =~ m/([^+]*)\+?(.*)?/);
+ my @X=@$x; # make a copy
+
+$code.=<<___;
+ mov (+8*0)($pA), $OP
+
+ mov $X[0], %rax
+ mul $OP # rdx:rax = %OP * [0]
+ mov %rax, (+$pDst_o+8*0)($pDst)
+ mov %rdx, $X[0]
+___
+for(my $i=1;$i<8;$i++) {
+$code.=<<___;
+ mov $X[$i], %rax
+ mul $OP # rdx:rax = %OP * [$i]
+ add %rax, $X[$i-1]
+ adc \$0, %rdx
+ mov %rdx, $X[$i]
+___
+}
+
+for(my $i=1;$i<8;$i++) {
+$code.=<<___;
+ mov (+8*$i)($pA), $OP
+___
+
+ &MULSTEP_512(\@X, "(+$pDst_o+8*$i)($pDst)", $pB, $OP, $TMP);
+ push(@X,shift(@X));
+}
+
+$code.=<<___;
+ mov $X[0], (+$pDst_o+8*8)($pDst)
+ mov $X[1], (+$pDst_o+8*9)($pDst)
+ mov $X[2], (+$pDst_o+8*10)($pDst)
+ mov $X[3], (+$pDst_o+8*11)($pDst)
+ mov $X[4], (+$pDst_o+8*12)($pDst)
+ mov $X[5], (+$pDst_o+8*13)($pDst)
+ mov $X[6], (+$pDst_o+8*14)($pDst)
+ mov $X[7], (+$pDst_o+8*15)($pDst)
+___
+}
+
+#
+# mont_mul_a3b : subroutine to compute (Src1 * Src2) % M (all 512-bits)
+# Input: src1: Address of source 1: rdi
+# src2: Address of source 2: rsi
+# Output: dst: Address of destination: [red_res_addr]
+# src2 and result also in: r9, r8, r15, r14, r13, r12, r11, r10
+# Temp: Clobbers [tmp16], all registers
+$code.=<<___;
+.type mont_mul_a3b,\@abi-omnipotent
+.align 16
+mont_mul_a3b:
+ #
+ # multiply tmp = src1 * src2
+ # For multiply: dst = rcx, src1 = rdi, src2 = rsi
+ # stack depth is extra 8 from call
+___
+ &MUL_512x512("%rsp+$tmp16_offset+8", "%rdi", "%rsi", [map("%r$_",(10..15,8..9))], "%rbp", "%rbx");
+$code.=<<___;
+ #
+ # Dst = tmp % m
+ # Call reduce(tmp, m, data, dst)
+
+ # tail recursion optimization: jmp to mont_reduce and return from there
+ jmp mont_reduce
+ # call mont_reduce
+ # ret
+.size mont_mul_a3b,.-mont_mul_a3b
+___
+}}}
+
+{{{
+#SQR_512 MACRO pDest, pA, x7, x6, x5, x4, x3, x2, x1, x0, tmp*4
+#
+# Input in memory [pA] and also in x7...x0
+# Uses all argument registers plus rax and rdx
+#
+# This version computes all of the off-diagonal terms into memory,
+# and then it adds in the diagonal terms
+
+sub SQR_512
+{
+ my ($pDst, $pA, $x, $A, $tmp, $x7, $x6, $pDst_o)=@_;
+ my ($pDst, $pDst_o) = ($pDst =~ m/([^+]*)\+?(.*)?/);
+ my @X=@$x; # make a copy
+$code.=<<___;
+ # ------------------
+ # first pass 01...07
+ # ------------------
+ mov $X[0], $A
+
+ mov $X[1],%rax
+ mul $A
+ mov %rax, (+$pDst_o+8*1)($pDst)
+___
+for(my $i=2;$i<8;$i++) {
+$code.=<<___;
+ mov %rdx, $X[$i-2]
+ mov $X[$i],%rax
+ mul $A
+ add %rax, $X[$i-2]
+ adc \$0, %rdx
+___
+}
+$code.=<<___;
+ mov %rdx, $x7
+
+ mov $X[0], (+$pDst_o+8*2)($pDst)
+
+ # ------------------
+ # second pass 12...17
+ # ------------------
+
+ mov (+8*1)($pA), $A
+
+ mov (+8*2)($pA),%rax
+ mul $A
+ add %rax, $X[1]
+ adc \$0, %rdx
+ mov $X[1], (+$pDst_o+8*3)($pDst)
+
+ mov %rdx, $X[0]
+ mov (+8*3)($pA),%rax
+ mul $A
+ add %rax, $X[2]
+ adc \$0, %rdx
+ add $X[0], $X[2]
+ adc \$0, %rdx
+ mov $X[2], (+$pDst_o+8*4)($pDst)
+
+ mov %rdx, $X[0]
+ mov (+8*4)($pA),%rax
+ mul $A
+ add %rax, $X[3]
+ adc \$0, %rdx
+ add $X[0], $X[3]
+ adc \$0, %rdx
+
+ mov %rdx, $X[0]
+ mov (+8*5)($pA),%rax
+ mul $A
+ add %rax, $X[4]
+ adc \$0, %rdx
+ add $X[0], $X[4]
+ adc \$0, %rdx
+
+ mov %rdx, $X[0]
+ mov $X[6],%rax
+ mul $A
+ add %rax, $X[5]
+ adc \$0, %rdx
+ add $X[0], $X[5]
+ adc \$0, %rdx
+
+ mov %rdx, $X[0]
+ mov $X[7],%rax
+ mul $A
+ add %rax, $x7
+ adc \$0, %rdx
+ add $X[0], $x7
+ adc \$0, %rdx
+
+ mov %rdx, $X[1]
+
+ # ------------------
+ # third pass 23...27
+ # ------------------
+ mov (+8*2)($pA), $A
+
+ mov (+8*3)($pA),%rax
+ mul $A
+ add %rax, $X[3]
+ adc \$0, %rdx
+ mov $X[3], (+$pDst_o+8*5)($pDst)
+
+ mov %rdx, $X[0]
+ mov (+8*4)($pA),%rax
+ mul $A
+ add %rax, $X[4]
+ adc \$0, %rdx
+ add $X[0], $X[4]
+ adc \$0, %rdx
+ mov $X[4], (+$pDst_o+8*6)($pDst)
+
+ mov %rdx, $X[0]
+ mov (+8*5)($pA),%rax
+ mul $A
+ add %rax, $X[5]
+ adc \$0, %rdx
+ add $X[0], $X[5]
+ adc \$0, %rdx
+
+ mov %rdx, $X[0]
+ mov $X[6],%rax
+ mul $A
+ add %rax, $x7
+ adc \$0, %rdx
+ add $X[0], $x7
+ adc \$0, %rdx
+
+ mov %rdx, $X[0]
+ mov $X[7],%rax
+ mul $A
+ add %rax, $X[1]
+ adc \$0, %rdx
+ add $X[0], $X[1]
+ adc \$0, %rdx
+
+ mov %rdx, $X[2]
+
+ # ------------------
+ # fourth pass 34...37
+ # ------------------
+
+ mov (+8*3)($pA), $A
+
+ mov (+8*4)($pA),%rax
+ mul $A
+ add %rax, $X[5]
+ adc \$0, %rdx
+ mov $X[5], (+$pDst_o+8*7)($pDst)
+
+ mov %rdx, $X[0]
+ mov (+8*5)($pA),%rax
+ mul $A
+ add %rax, $x7
+ adc \$0, %rdx
+ add $X[0], $x7
+ adc \$0, %rdx
+ mov $x7, (+$pDst_o+8*8)($pDst)
+
+ mov %rdx, $X[0]
+ mov $X[6],%rax
+ mul $A
+ add %rax, $X[1]
+ adc \$0, %rdx
+ add $X[0], $X[1]
+ adc \$0, %rdx
+
+ mov %rdx, $X[0]
+ mov $X[7],%rax
+ mul $A
+ add %rax, $X[2]
+ adc \$0, %rdx
+ add $X[0], $X[2]
+ adc \$0, %rdx
+
+ mov %rdx, $X[5]
+
+ # ------------------
+ # fifth pass 45...47
+ # ------------------
+ mov (+8*4)($pA), $A
+
+ mov (+8*5)($pA),%rax
+ mul $A
+ add %rax, $X[1]
+ adc \$0, %rdx
+ mov $X[1], (+$pDst_o+8*9)($pDst)
+
+ mov %rdx, $X[0]
+ mov $X[6],%rax
+ mul $A
+ add %rax, $X[2]
+ adc \$0, %rdx
+ add $X[0], $X[2]
+ adc \$0, %rdx
+ mov $X[2], (+$pDst_o+8*10)($pDst)
+
+ mov %rdx, $X[0]
+ mov $X[7],%rax
+ mul $A
+ add %rax, $X[5]
+ adc \$0, %rdx
+ add $X[0], $X[5]
+ adc \$0, %rdx
+
+ mov %rdx, $X[1]
+
+ # ------------------
+ # sixth pass 56...57
+ # ------------------
+ mov (+8*5)($pA), $A
+
+ mov $X[6],%rax
+ mul $A
+ add %rax, $X[5]
+ adc \$0, %rdx
+ mov $X[5], (+$pDst_o+8*11)($pDst)
+
+ mov %rdx, $X[0]
+ mov $X[7],%rax
+ mul $A
+ add %rax, $X[1]
+ adc \$0, %rdx
+ add $X[0], $X[1]
+ adc \$0, %rdx
+ mov $X[1], (+$pDst_o+8*12)($pDst)
+
+ mov %rdx, $X[2]
+
+ # ------------------
+ # seventh pass 67
+ # ------------------
+ mov $X[6], $A
+
+ mov $X[7],%rax
+ mul $A
+ add %rax, $X[2]
+ adc \$0, %rdx
+ mov $X[2], (+$pDst_o+8*13)($pDst)
+
+ mov %rdx, (+$pDst_o+8*14)($pDst)
+
+ # start finalize (add in squares, and double off-terms)
+ mov (+$pDst_o+8*1)($pDst), $X[0]
+ mov (+$pDst_o+8*2)($pDst), $X[1]
+ mov (+$pDst_o+8*3)($pDst), $X[2]
+ mov (+$pDst_o+8*4)($pDst), $X[3]
+ mov (+$pDst_o+8*5)($pDst), $X[4]
+ mov (+$pDst_o+8*6)($pDst), $X[5]
+
+ mov (+8*3)($pA), %rax
+ mul %rax
+ mov %rax, $x6
+ mov %rdx, $X[6]
+
+ add $X[0], $X[0]
+ adc $X[1], $X[1]
+ adc $X[2], $X[2]
+ adc $X[3], $X[3]
+ adc $X[4], $X[4]
+ adc $X[5], $X[5]
+ adc \$0, $X[6]
+
+ mov (+8*0)($pA), %rax
+ mul %rax
+ mov %rax, (+$pDst_o+8*0)($pDst)
+ mov %rdx, $A
+
+ mov (+8*1)($pA), %rax
+ mul %rax
+
+ add $A, $X[0]
+ adc %rax, $X[1]
+ adc \$0, %rdx
+
+ mov %rdx, $A
+ mov $X[0], (+$pDst_o+8*1)($pDst)
+ mov $X[1], (+$pDst_o+8*2)($pDst)
+
+ mov (+8*2)($pA), %rax
+ mul %rax
+
+ add $A, $X[2]
+ adc %rax, $X[3]
+ adc \$0, %rdx
+
+ mov %rdx, $A
+
+ mov $X[2], (+$pDst_o+8*3)($pDst)
+ mov $X[3], (+$pDst_o+8*4)($pDst)
+
+ xor $tmp, $tmp
+ add $A, $X[4]
+ adc $x6, $X[5]
+ adc \$0, $tmp
+
+ mov $X[4], (+$pDst_o+8*5)($pDst)
+ mov $X[5], (+$pDst_o+8*6)($pDst)
+
+ # %%tmp has 0/1 in column 7
+ # %%A6 has a full value in column 7
+
+ mov (+$pDst_o+8*7)($pDst), $X[0]
+ mov (+$pDst_o+8*8)($pDst), $X[1]
+ mov (+$pDst_o+8*9)($pDst), $X[2]
+ mov (+$pDst_o+8*10)($pDst), $X[3]
+ mov (+$pDst_o+8*11)($pDst), $X[4]
+ mov (+$pDst_o+8*12)($pDst), $X[5]
+ mov (+$pDst_o+8*13)($pDst), $x6
+ mov (+$pDst_o+8*14)($pDst), $x7
+
+ mov $X[7], %rax
+ mul %rax
+ mov %rax, $X[7]
+ mov %rdx, $A
+
+ add $X[0], $X[0]
+ adc $X[1], $X[1]
+ adc $X[2], $X[2]
+ adc $X[3], $X[3]
+ adc $X[4], $X[4]
+ adc $X[5], $X[5]
+ adc $x6, $x6
+ adc $x7, $x7
+ adc \$0, $A
+
+ add $tmp, $X[0]
+
+ mov (+8*4)($pA), %rax
+ mul %rax
+
+ add $X[6], $X[0]
+ adc %rax, $X[1]
+ adc \$0, %rdx
+
+ mov %rdx, $tmp
+
+ mov $X[0], (+$pDst_o+8*7)($pDst)
+ mov $X[1], (+$pDst_o+8*8)($pDst)
+
+ mov (+8*5)($pA), %rax
+ mul %rax
+
+ add $tmp, $X[2]
+ adc %rax, $X[3]
+ adc \$0, %rdx
+
+ mov %rdx, $tmp
+
+ mov $X[2], (+$pDst_o+8*9)($pDst)
+ mov $X[3], (+$pDst_o+8*10)($pDst)
+
+ mov (+8*6)($pA), %rax
+ mul %rax
+
+ add $tmp, $X[4]
+ adc %rax, $X[5]
+ adc \$0, %rdx
+
+ mov $X[4], (+$pDst_o+8*11)($pDst)
+ mov $X[5], (+$pDst_o+8*12)($pDst)
+
+ add %rdx, $x6
+ adc $X[7], $x7
+ adc \$0, $A
+
+ mov $x6, (+$pDst_o+8*13)($pDst)
+ mov $x7, (+$pDst_o+8*14)($pDst)
+ mov $A, (+$pDst_o+8*15)($pDst)
+___
+}
+
+#
+# sqr_reduce: subroutine to compute Result = reduce(Result * Result)
+#
+# input and result also in: r9, r8, r15, r14, r13, r12, r11, r10
+#
+$code.=<<___;
+.type sqr_reduce,\@abi-omnipotent
+.align 16
+sqr_reduce:
+ mov (+$pResult_offset+8)(%rsp), %rcx
+___
+ &SQR_512("%rsp+$tmp16_offset+8", "%rcx", [map("%r$_",(10..15,8..9))], "%rbx", "%rbp", "%rsi", "%rdi");
+$code.=<<___;
+ # tail recursion optimization: jmp to mont_reduce and return from there
+ jmp mont_reduce
+ # call mont_reduce
+ # ret
+.size sqr_reduce,.-sqr_reduce
+___
+}}}
+
+#
+# MAIN FUNCTION
+#
+
+#mod_exp_512(UINT64 *result, /* 512 bits, 8 qwords */
+# UINT64 *g, /* 512 bits, 8 qwords */
+# UINT64 *exp, /* 512 bits, 8 qwords */
+# struct mod_ctx_512 *data)
+
+# window size = 5
+# table size = 2^5 = 32
+#table_entries equ 32
+#table_size equ table_entries * 8
+$code.=<<___;
+.globl mod_exp_512
+.type mod_exp_512,\@function,4
+mod_exp_512:
+ push %rbp
+ push %rbx
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+
+ # adjust stack down and then align it with cache boundary
+ mov %rsp, %r8
+ sub \$$mem_size, %rsp
+ and \$-64, %rsp
+
+ # store previous stack pointer and arguments
+ mov %r8, (+$rsp_offset)(%rsp)
+ mov %rdi, (+$pResult_offset)(%rsp)
+ mov %rsi, (+$pG_offset)(%rsp)
+ mov %rcx, (+$pData_offset)(%rsp)
+.Lbody:
+ # transform g into montgomery space
+ # GT = reduce(g * C2) = reduce(g * (2^256))
+ # reduce expects to have the input in [tmp16]
+ pxor %xmm4, %xmm4
+ movdqu (+16*0)(%rsi), %xmm0
+ movdqu (+16*1)(%rsi), %xmm1
+ movdqu (+16*2)(%rsi), %xmm2
+ movdqu (+16*3)(%rsi), %xmm3
+ movdqa %xmm4, (+$tmp16_offset+16*0)(%rsp)
+ movdqa %xmm4, (+$tmp16_offset+16*1)(%rsp)
+ movdqa %xmm4, (+$tmp16_offset+16*6)(%rsp)
+ movdqa %xmm4, (+$tmp16_offset+16*7)(%rsp)
+ movdqa %xmm0, (+$tmp16_offset+16*2)(%rsp)
+ movdqa %xmm1, (+$tmp16_offset+16*3)(%rsp)
+ movdqa %xmm2, (+$tmp16_offset+16*4)(%rsp)
+ movdqa %xmm3, (+$tmp16_offset+16*5)(%rsp)
+
+ # load pExp before rdx gets blown away
+ movdqu (+16*0)(%rdx), %xmm0
+ movdqu (+16*1)(%rdx), %xmm1
+ movdqu (+16*2)(%rdx), %xmm2
+ movdqu (+16*3)(%rdx), %xmm3
+
+ lea (+$GT_offset)(%rsp), %rbx
+ mov %rbx, (+$red_result_addr_offset)(%rsp)
+ call mont_reduce
+
+ # Initialize tmp = C
+ lea (+$tmp_offset)(%rsp), %rcx
+ xor %rax, %rax
+ mov %rax, (+8*0)(%rcx)
+ mov %rax, (+8*1)(%rcx)
+ mov %rax, (+8*3)(%rcx)
+ mov %rax, (+8*4)(%rcx)
+ mov %rax, (+8*5)(%rcx)
+ mov %rax, (+8*6)(%rcx)
+ mov %rax, (+8*7)(%rcx)
+ mov %rax, (+$exp_offset+8*8)(%rsp)
+ movq \$1, (+8*2)(%rcx)
+
+ lea (+$garray_offset)(%rsp), %rbp
+ mov %rcx, %rsi # pTmp
+ mov %rbp, %rdi # Garray[][0]
+___
+
+ &swizzle("%rdi", "%rcx", "%rax", "%rbx");
+
+ # for (rax = 31; rax != 0; rax--) {
+ # tmp = reduce(tmp * G)
+ # swizzle(pg, tmp);
+ # pg += 2; }
+$code.=<<___;
+ mov \$31, %rax
+ mov %rax, (+$i_offset)(%rsp)
+ mov %rbp, (+$pg_offset)(%rsp)
+ # rsi -> pTmp
+ mov %rsi, (+$red_result_addr_offset)(%rsp)
+ mov (+8*0)(%rsi), %r10
+ mov (+8*1)(%rsi), %r11
+ mov (+8*2)(%rsi), %r12
+ mov (+8*3)(%rsi), %r13
+ mov (+8*4)(%rsi), %r14
+ mov (+8*5)(%rsi), %r15
+ mov (+8*6)(%rsi), %r8
+ mov (+8*7)(%rsi), %r9
+init_loop:
+ lea (+$GT_offset)(%rsp), %rdi
+ call mont_mul_a3b
+ lea (+$tmp_offset)(%rsp), %rsi
+ mov (+$pg_offset)(%rsp), %rbp
+ add \$2, %rbp
+ mov %rbp, (+$pg_offset)(%rsp)
+ mov %rsi, %rcx # rcx = rsi = addr of tmp
+___
+
+ &swizzle("%rbp", "%rcx", "%rax", "%rbx");
+$code.=<<___;
+ mov (+$i_offset)(%rsp), %rax
+ sub \$1, %rax
+ mov %rax, (+$i_offset)(%rsp)
+ jne init_loop
+
+ #
+ # Copy exponent onto stack
+ movdqa %xmm0, (+$exp_offset+16*0)(%rsp)
+ movdqa %xmm1, (+$exp_offset+16*1)(%rsp)
+ movdqa %xmm2, (+$exp_offset+16*2)(%rsp)
+ movdqa %xmm3, (+$exp_offset+16*3)(%rsp)
+
+
+ #
+ # Do exponentiation
+ # Initialize result to G[exp{511:507}]
+ mov (+$exp_offset+62)(%rsp), %eax
+ mov %rax, %rdx
+ shr \$11, %rax
+ and \$0x07FF, %edx
+ mov %edx, (+$exp_offset+62)(%rsp)
+ lea (+$garray_offset)(%rsp,%rax,2), %rsi
+ mov (+$pResult_offset)(%rsp), %rdx
+___
+
+ &unswizzle("%rdx", "%rsi", "%rbp", "%rbx", "%rax");
+
+ #
+ # Loop variables
+ # rcx = [loop_idx] = index: 510-5 to 0 by 5
+$code.=<<___;
+ movq \$505, (+$loop_idx_offset)(%rsp)
+
+ mov (+$pResult_offset)(%rsp), %rcx
+ mov %rcx, (+$red_result_addr_offset)(%rsp)
+ mov (+8*0)(%rcx), %r10
+ mov (+8*1)(%rcx), %r11
+ mov (+8*2)(%rcx), %r12
+ mov (+8*3)(%rcx), %r13
+ mov (+8*4)(%rcx), %r14
+ mov (+8*5)(%rcx), %r15
+ mov (+8*6)(%rcx), %r8
+ mov (+8*7)(%rcx), %r9
+ jmp sqr_2
+
+main_loop_a3b:
+ call sqr_reduce
+ call sqr_reduce
+ call sqr_reduce
+sqr_2:
+ call sqr_reduce
+ call sqr_reduce
+
+ #
+ # Do multiply, first look up proper value in Garray
+ mov (+$loop_idx_offset)(%rsp), %rcx # bit index
+ mov %rcx, %rax
+ shr \$4, %rax # rax is word pointer
+ mov (+$exp_offset)(%rsp,%rax,2), %edx
+ and \$15, %rcx
+ shrq %cl, %rdx
+ and \$0x1F, %rdx
+
+ lea (+$garray_offset)(%rsp,%rdx,2), %rsi
+ lea (+$tmp_offset)(%rsp), %rdx
+ mov %rdx, %rdi
+___
+
+ &unswizzle("%rdx", "%rsi", "%rbp", "%rbx", "%rax");
+ # rdi = tmp = pG
+
+ #
+ # Call mod_mul_a1(pDst, pSrc1, pSrc2, pM, pData)
+ # result result pG M Data
+$code.=<<___;
+ mov (+$pResult_offset)(%rsp), %rsi
+ call mont_mul_a3b
+
+ #
+ # finish loop
+ mov (+$loop_idx_offset)(%rsp), %rcx
+ sub \$5, %rcx
+ mov %rcx, (+$loop_idx_offset)(%rsp)
+ jge main_loop_a3b
+
+ #
+
+end_main_loop_a3b:
+ # transform result out of Montgomery space
+ # result = reduce(result)
+ mov (+$pResult_offset)(%rsp), %rdx
+ pxor %xmm4, %xmm4
+ movdqu (+16*0)(%rdx), %xmm0
+ movdqu (+16*1)(%rdx), %xmm1
+ movdqu (+16*2)(%rdx), %xmm2
+ movdqu (+16*3)(%rdx), %xmm3
+ movdqa %xmm4, (+$tmp16_offset+16*4)(%rsp)
+ movdqa %xmm4, (+$tmp16_offset+16*5)(%rsp)
+ movdqa %xmm4, (+$tmp16_offset+16*6)(%rsp)
+ movdqa %xmm4, (+$tmp16_offset+16*7)(%rsp)
+ movdqa %xmm0, (+$tmp16_offset+16*0)(%rsp)
+ movdqa %xmm1, (+$tmp16_offset+16*1)(%rsp)
+ movdqa %xmm2, (+$tmp16_offset+16*2)(%rsp)
+ movdqa %xmm3, (+$tmp16_offset+16*3)(%rsp)
+ call mont_reduce
+
+ # If result > m, subract m
+ # load result into r15:r8
+ mov (+$pResult_offset)(%rsp), %rax
+ mov (+8*0)(%rax), %r8
+ mov (+8*1)(%rax), %r9
+ mov (+8*2)(%rax), %r10
+ mov (+8*3)(%rax), %r11
+ mov (+8*4)(%rax), %r12
+ mov (+8*5)(%rax), %r13
+ mov (+8*6)(%rax), %r14
+ mov (+8*7)(%rax), %r15
+
+ # subtract m
+ mov (+$pData_offset)(%rsp), %rbx
+ add \$$M, %rbx
+
+ sub (+8*0)(%rbx), %r8
+ sbb (+8*1)(%rbx), %r9
+ sbb (+8*2)(%rbx), %r10
+ sbb (+8*3)(%rbx), %r11
+ sbb (+8*4)(%rbx), %r12
+ sbb (+8*5)(%rbx), %r13
+ sbb (+8*6)(%rbx), %r14
+ sbb (+8*7)(%rbx), %r15
+
+ # if Carry is clear, replace result with difference
+ mov (+8*0)(%rax), %rsi
+ mov (+8*1)(%rax), %rdi
+ mov (+8*2)(%rax), %rcx
+ mov (+8*3)(%rax), %rdx
+ cmovnc %r8, %rsi
+ cmovnc %r9, %rdi
+ cmovnc %r10, %rcx
+ cmovnc %r11, %rdx
+ mov %rsi, (+8*0)(%rax)
+ mov %rdi, (+8*1)(%rax)
+ mov %rcx, (+8*2)(%rax)
+ mov %rdx, (+8*3)(%rax)
+
+ mov (+8*4)(%rax), %rsi
+ mov (+8*5)(%rax), %rdi
+ mov (+8*6)(%rax), %rcx
+ mov (+8*7)(%rax), %rdx
+ cmovnc %r12, %rsi
+ cmovnc %r13, %rdi
+ cmovnc %r14, %rcx
+ cmovnc %r15, %rdx
+ mov %rsi, (+8*4)(%rax)
+ mov %rdi, (+8*5)(%rax)
+ mov %rcx, (+8*6)(%rax)
+ mov %rdx, (+8*7)(%rax)
+
+ mov (+$rsp_offset)(%rsp), %rsi
+ mov 0(%rsi),%r15
+ mov 8(%rsi),%r14
+ mov 16(%rsi),%r13
+ mov 24(%rsi),%r12
+ mov 32(%rsi),%rbx
+ mov 40(%rsi),%rbp
+ lea 48(%rsi),%rsp
+.Lepilogue:
+ ret
+.size mod_exp_512, . - mod_exp_512
+___
+
+if ($win64) {
+# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
+# CONTEXT *context,DISPATCHER_CONTEXT *disp)
+my $rec="%rcx";
+my $frame="%rdx";
+my $context="%r8";
+my $disp="%r9";
+
+$code.=<<___;
+.extern __imp_RtlVirtualUnwind
+.type mod_exp_512_se_handler,\@abi-omnipotent
+.align 16
+mod_exp_512_se_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 120($context),%rax # pull context->Rax
+ mov 248($context),%rbx # pull context->Rip
+
+ lea .Lbody(%rip),%r10
+ cmp %r10,%rbx # context->Rip<prologue label
+ jb .Lin_prologue
+
+ mov 152($context),%rax # pull context->Rsp
+
+ lea .Lepilogue(%rip),%r10
+ cmp %r10,%rbx # context->Rip>=epilogue label
+ jae .Lin_prologue
+
+ mov $rsp_offset(%rax),%rax # pull saved Rsp
+
+ mov 32(%rax),%rbx
+ mov 40(%rax),%rbp
+ mov 24(%rax),%r12
+ mov 16(%rax),%r13
+ mov 8(%rax),%r14
+ mov 0(%rax),%r15
+ lea 48(%rax),%rax
+ mov %rbx,144($context) # restore context->Rbx
+ mov %rbp,160($context) # restore context->Rbp
+ mov %r12,216($context) # restore context->R12
+ mov %r13,224($context) # restore context->R13
+ mov %r14,232($context) # restore context->R14
+ mov %r15,240($context) # restore context->R15
+
+.Lin_prologue:
+ mov 8(%rax),%rdi
+ mov 16(%rax),%rsi
+ mov %rax,152($context) # restore context->Rsp
+ mov %rsi,168($context) # restore context->Rsi
+ mov %rdi,176($context) # restore context->Rdi
+
+ mov 40($disp),%rdi # disp->ContextRecord
+ mov $context,%rsi # context
+ mov \$154,%ecx # sizeof(CONTEXT)
+ .long 0xa548f3fc # cld; rep movsq
+
+ mov $disp,%rsi
+ xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER
+ mov 8(%rsi),%rdx # arg2, disp->ImageBase
+ mov 0(%rsi),%r8 # arg3, disp->ControlPc
+ mov 16(%rsi),%r9 # arg4, disp->FunctionEntry
+ mov 40(%rsi),%r10 # disp->ContextRecord
+ lea 56(%rsi),%r11 # &disp->HandlerData
+ lea 24(%rsi),%r12 # &disp->EstablisherFrame
+ mov %r10,32(%rsp) # arg5
+ mov %r11,40(%rsp) # arg6
+ mov %r12,48(%rsp) # arg7
+ mov %rcx,56(%rsp) # arg8, (NULL)
+ call *__imp_RtlVirtualUnwind(%rip)
+
+ mov \$1,%eax # ExceptionContinueSearch
+ add \$64,%rsp
+ popfq
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+ pop %rdi
+ pop %rsi
+ ret
+.size mod_exp_512_se_handler,.-mod_exp_512_se_handler
+
+.section .pdata
+.align 4
+ .rva .LSEH_begin_mod_exp_512
+ .rva .LSEH_end_mod_exp_512
+ .rva .LSEH_info_mod_exp_512
+
+.section .xdata
+.align 8
+.LSEH_info_mod_exp_512:
+ .byte 9,0,0,0
+ .rva mod_exp_512_se_handler
+___
+}
+
+sub reg_part {
+my ($reg,$conv)=@_;
+ if ($reg =~ /%r[0-9]+/) { $reg .= $conv; }
+ elsif ($conv eq "b") { $reg =~ s/%[er]([^x]+)x?/%$1l/; }
+ elsif ($conv eq "w") { $reg =~ s/%[er](.+)/%$1/; }
+ elsif ($conv eq "d") { $reg =~ s/%[er](.+)/%e$1/; }
+ return $reg;
+}
+
+$code =~ s/(%[a-z0-9]+)#([bwd])/reg_part($1,$2)/gem;
+$code =~ s/\`([^\`]*)\`/eval $1/gem;
+$code =~ s/(\(\+[^)]+\))/eval $1/gem;
+print $code;
+close STDOUT;
diff --git a/crypto/bn/asm/rsaz-avx2.pl b/crypto/bn/asm/rsaz-avx2.pl
new file mode 100644
index 0000000..3eb9556
--- /dev/null
+++ b/crypto/bn/asm/rsaz-avx2.pl
@@ -0,0 +1,1875 @@
+#!/usr/bin/env perl
+
+##############################################################################
+# #
+# 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. #
+# #
+##############################################################################
+# Developers and authors: #
+# Shay Gueron (1, 2), and Vlad Krasnov (1) #
+# (1) Intel Corporation, Israel Development Center, Haifa, Israel #
+# (2) University of Haifa, Israel #
+##############################################################################
+# Reference: #
+# [1] S. Gueron, V. Krasnov: "Software Implementation of Modular #
+# Exponentiation, Using Advanced Vector Instructions Architectures", #
+# F. Ozbudak and F. Rodriguez-Henriquez (Eds.): WAIFI 2012, LNCS 7369, #
+# pp. 119?135, 2012. Springer-Verlag Berlin Heidelberg 2012 #
+# [2] S. Gueron: "Efficient Software Implementations of Modular #
+# Exponentiation", Journal of Cryptographic Engineering 2:31-43 (2012). #
+# [3] S. Gueron, V. Krasnov: "Speeding up Big-numbers Squaring",IEEE #
+# Proceedings of 9th International Conference on Information Technology: #
+# New Generations (ITNG 2012), pp.821-823 (2012) #
+# [4] S. Gueron, V. Krasnov: "[PATCH] Efficient and side channel analysis #
+# resistant 1024-bit modular exponentiation, for optimizing RSA2048 #
+# on AVX2 capable x86_64 platforms", #
+# http://rt.openssl.org/Ticket/Display.html?id=2850&user=guest&pass=guest#
+##############################################################################
+#
+# +13% improvement over original submission by <appro@openssl.org>
+#
+# rsa2048 sign/sec OpenSSL 1.0.1 scalar(*) this
+# 2.3GHz Haswell 621 765/+23% 1113/+79%
+#
+# (*) if system doesn't support AVX2, for reference purposes;
+
+$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";
+
+if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
+ =~ /GNU assembler version ([2-9]\.[0-9]+)/) {
+ $avx = ($1>=2.19) + ($1>=2.22);
+}
+
+if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
+ `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
+ $avx = ($1>=2.09) + ($1>=2.10);
+}
+
+if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
+ `ml64 2>&1` =~ /Version ([0-9]+)\./) {
+ $avx = ($1>=10) + ($1>=11);
+}
+
+open OUT,"| $^X $xlate $flavour $output";
+*STDOUT = *OUT;
+
+if ($avx>1) {{{
+{ # void AMS_WW(
+my $rp="%rdi"; # BN_ULONG *rp,
+my $ap="%rsi"; # const BN_ULONG *ap,
+my $np="%rdx"; # const BN_ULONG *np,
+my $n0="%ecx"; # const BN_ULONG n0,
+my $rep="%r8d"; # int repeat);
+
+# The registers that hold the accumulated redundant result
+# The AMM works on 1024 bit operands, and redundant word size is 29
+# Therefore: ceil(1024/29)/4 = 9
+my $ACC0="%ymm0";
+my $ACC1="%ymm1";
+my $ACC2="%ymm2";
+my $ACC3="%ymm3";
+my $ACC4="%ymm4";
+my $ACC5="%ymm5";
+my $ACC6="%ymm6";
+my $ACC7="%ymm7";
+my $ACC8="%ymm8";
+my $ACC9="%ymm9";
+# Registers that hold the broadcasted words of bp, currently used
+my $B1="%ymm10";
+my $B2="%ymm11";
+# Registers that hold the broadcasted words of Y, currently used
+my $Y1="%ymm12";
+my $Y2="%ymm13";
+# Helper registers
+my $TEMP1="%ymm14";
+my $AND_MASK="%ymm15";
+# alu registers that hold the first words of the ACC
+my $r0="%r9";
+my $r1="%r10";
+my $r2="%r11";
+my $r3="%r12";
+
+my $i="%r14d"; # loop counter
+my $tmp = "%r15";
+
+my $FrameSize=32*18+32*8; # place for A^2 and 2*A
+
+my $aap=$r0;
+my $tp0="%rbx";
+my $tp1=$r3;
+my $tpa=$tmp;
+
+$np="%r13"; # reassigned argument
+
+$code.=<<___;
+.text
+
+.globl rsaz_1024_sqr_avx2
+.type rsaz_1024_sqr_avx2,\@function,5
+.align 64
+rsaz_1024_sqr_avx2: # 702 cycles, 14% faster than rsaz_1024_mul_avx2
+ lea (%rsp), %rax
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ vzeroupper
+___
+$code.=<<___ if ($win64);
+ lea -0xa8(%rsp),%rsp
+ vmovaps %xmm6,-0xd8(%rax)
+ vmovaps %xmm7,-0xc8(%rax)
+ vmovaps %xmm8,-0xb8(%rax)
+ vmovaps %xmm9,-0xa8(%rax)
+ vmovaps %xmm10,-0x98(%rax)
+ vmovaps %xmm11,-0x88(%rax)
+ vmovaps %xmm12,-0x78(%rax)
+ vmovaps %xmm13,-0x68(%rax)
+ vmovaps %xmm14,-0x58(%rax)
+ vmovaps %xmm15,-0x48(%rax)
+.Lsqr_1024_body:
+___
+$code.=<<___;
+ mov %rax,%rbp
+ mov %rdx, $np # reassigned argument
+ sub \$$FrameSize, %rsp
+ mov $np, $tmp
+ sub \$-128, $rp # size optimization
+ sub \$-128, $ap
+ sub \$-128, $np
+
+ and \$4095, $tmp # see if $np crosses page
+ add \$32*10, $tmp
+ shr \$12, $tmp
+ vpxor $ACC9,$ACC9,$ACC9
+ jz .Lsqr_1024_no_n_copy
+
+ # unaligned 256-bit load that crosses page boundary can
+ # cause >2x performance degradation here, so if $np does
+ # cross page boundary, copy it to stack and make sure stack
+ # frame doesn't...
+ sub \$32*10,%rsp
+ vmovdqu 32*0-128($np), $ACC0
+ and \$-2048, %rsp
+ vmovdqu 32*1-128($np), $ACC1
+ vmovdqu 32*2-128($np), $ACC2
+ vmovdqu 32*3-128($np), $ACC3
+ vmovdqu 32*4-128($np), $ACC4
+ vmovdqu 32*5-128($np), $ACC5
+ vmovdqu 32*6-128($np), $ACC6
+ vmovdqu 32*7-128($np), $ACC7
+ vmovdqu 32*8-128($np), $ACC8
+ lea $FrameSize+128(%rsp),$np
+ vmovdqu $ACC0, 32*0-128($np)
+ vmovdqu $ACC1, 32*1-128($np)
+ vmovdqu $ACC2, 32*2-128($np)
+ vmovdqu $ACC3, 32*3-128($np)
+ vmovdqu $ACC4, 32*4-128($np)
+ vmovdqu $ACC5, 32*5-128($np)
+ vmovdqu $ACC6, 32*6-128($np)
+ vmovdqu $ACC7, 32*7-128($np)
+ vmovdqu $ACC8, 32*8-128($np)
+ vmovdqu $ACC9, 32*9-128($np) # $ACC9 is zero
+
+.Lsqr_1024_no_n_copy:
+ and \$-1024, %rsp
+
+ vmovdqu 32*1-128($ap), $ACC1
+ vmovdqu 32*2-128($ap), $ACC2
+ vmovdqu 32*3-128($ap), $ACC3
+ vmovdqu 32*4-128($ap), $ACC4
+ vmovdqu 32*5-128($ap), $ACC5
+ vmovdqu 32*6-128($ap), $ACC6
+ vmovdqu 32*7-128($ap), $ACC7
+ vmovdqu 32*8-128($ap), $ACC8
+
+ lea 192(%rsp), $tp0 # 64+128=192
+ vpbroadcastq .Land_mask(%rip), $AND_MASK
+ jmp .LOOP_GRANDE_SQR_1024
+
+.align 32
+.LOOP_GRANDE_SQR_1024:
+ lea 32*18+128(%rsp), $aap # size optimization
+ lea 448(%rsp), $tp1 # 64+128+256=448
+
+ # the squaring is performed as described in Variant B of
+ # "Speeding up Big-Number Squaring", so start by calculating
+ # the A*2=A+A vector
+ vpaddq $ACC1, $ACC1, $ACC1
+ vpbroadcastq 32*0-128($ap), $B1
+ vpaddq $ACC2, $ACC2, $ACC2
+ vmovdqa $ACC1, 32*0-128($aap)
+ vpaddq $ACC3, $ACC3, $ACC3
+ vmovdqa $ACC2, 32*1-128($aap)
+ vpaddq $ACC4, $ACC4, $ACC4
+ vmovdqa $ACC3, 32*2-128($aap)
+ vpaddq $ACC5, $ACC5, $ACC5
+ vmovdqa $ACC4, 32*3-128($aap)
+ vpaddq $ACC6, $ACC6, $ACC6
+ vmovdqa $ACC5, 32*4-128($aap)
+ vpaddq $ACC7, $ACC7, $ACC7
+ vmovdqa $ACC6, 32*5-128($aap)
+ vpaddq $ACC8, $ACC8, $ACC8
+ vmovdqa $ACC7, 32*6-128($aap)
+ vpxor $ACC9, $ACC9, $ACC9
+ vmovdqa $ACC8, 32*7-128($aap)
+
+ vpmuludq 32*0-128($ap), $B1, $ACC0
+ vpbroadcastq 32*1-128($ap), $B2
+ vmovdqu $ACC9, 32*9-192($tp0) # zero upper half
+ vpmuludq $B1, $ACC1, $ACC1
+ vmovdqu $ACC9, 32*10-448($tp1)
+ vpmuludq $B1, $ACC2, $ACC2
+ vmovdqu $ACC9, 32*11-448($tp1)
+ vpmuludq $B1, $ACC3, $ACC3
+ vmovdqu $ACC9, 32*12-448($tp1)
+ vpmuludq $B1, $ACC4, $ACC4
+ vmovdqu $ACC9, 32*13-448($tp1)
+ vpmuludq $B1, $ACC5, $ACC5
+ vmovdqu $ACC9, 32*14-448($tp1)
+ vpmuludq $B1, $ACC6, $ACC6
+ vmovdqu $ACC9, 32*15-448($tp1)
+ vpmuludq $B1, $ACC7, $ACC7
+ vmovdqu $ACC9, 32*16-448($tp1)
+ vpmuludq $B1, $ACC8, $ACC8
+ vpbroadcastq 32*2-128($ap), $B1
+ vmovdqu $ACC9, 32*17-448($tp1)
+
+ mov $ap, $tpa
+ mov \$4, $i
+ jmp .Lsqr_entry_1024
+___
+$TEMP0=$Y1;
+$TEMP2=$Y2;
+$code.=<<___;
+.align 32
+.LOOP_SQR_1024:
+ vpbroadcastq 32*1-128($tpa), $B2
+ vpmuludq 32*0-128($ap), $B1, $ACC0
+ vpaddq 32*0-192($tp0), $ACC0, $ACC0
+ vpmuludq 32*0-128($aap), $B1, $ACC1
+ vpaddq 32*1-192($tp0), $ACC1, $ACC1
+ vpmuludq 32*1-128($aap), $B1, $ACC2
+ vpaddq 32*2-192($tp0), $ACC2, $ACC2
+ vpmuludq 32*2-128($aap), $B1, $ACC3
+ vpaddq 32*3-192($tp0), $ACC3, $ACC3
+ vpmuludq 32*3-128($aap), $B1, $ACC4
+ vpaddq 32*4-192($tp0), $ACC4, $ACC4
+ vpmuludq 32*4-128($aap), $B1, $ACC5
+ vpaddq 32*5-192($tp0), $ACC5, $ACC5
+ vpmuludq 32*5-128($aap), $B1, $ACC6
+ vpaddq 32*6-192($tp0), $ACC6, $ACC6
+ vpmuludq 32*6-128($aap), $B1, $ACC7
+ vpaddq 32*7-192($tp0), $ACC7, $ACC7
+ vpmuludq 32*7-128($aap), $B1, $ACC8
+ vpbroadcastq 32*2-128($tpa), $B1
+ vpaddq 32*8-192($tp0), $ACC8, $ACC8
+.Lsqr_entry_1024:
+ vmovdqu $ACC0, 32*0-192($tp0)
+ vmovdqu $ACC1, 32*1-192($tp0)
+
+ vpmuludq 32*1-128($ap), $B2, $TEMP0
+ vpaddq $TEMP0, $ACC2, $ACC2
+ vpmuludq 32*1-128($aap), $B2, $TEMP1
+ vpaddq $TEMP1, $ACC3, $ACC3
+ vpmuludq 32*2-128($aap), $B2, $TEMP2
+ vpaddq $TEMP2, $ACC4, $ACC4
+ vpmuludq 32*3-128($aap), $B2, $TEMP0
+ vpaddq $TEMP0, $ACC5, $ACC5
+ vpmuludq 32*4-128($aap), $B2, $TEMP1
+ vpaddq $TEMP1, $ACC6, $ACC6
+ vpmuludq 32*5-128($aap), $B2, $TEMP2
+ vpaddq $TEMP2, $ACC7, $ACC7
+ vpmuludq 32*6-128($aap), $B2, $TEMP0
+ vpaddq $TEMP0, $ACC8, $ACC8
+ vpmuludq 32*7-128($aap), $B2, $ACC0
+ vpbroadcastq 32*3-128($tpa), $B2
+ vpaddq 32*9-192($tp0), $ACC0, $ACC0
+
+ vmovdqu $ACC2, 32*2-192($tp0)
+ vmovdqu $ACC3, 32*3-192($tp0)
+
+ vpmuludq 32*2-128($ap), $B1, $TEMP2
+ vpaddq $TEMP2, $ACC4, $ACC4
+ vpmuludq 32*2-128($aap), $B1, $TEMP0
+ vpaddq $TEMP0, $ACC5, $ACC5
+ vpmuludq 32*3-128($aap), $B1, $TEMP1
+ vpaddq $TEMP1, $ACC6, $ACC6
+ vpmuludq 32*4-128($aap), $B1, $TEMP2
+ vpaddq $TEMP2, $ACC7, $ACC7
+ vpmuludq 32*5-128($aap), $B1, $TEMP0
+ vpaddq $TEMP0, $ACC8, $ACC8
+ vpmuludq 32*6-128($aap), $B1, $TEMP1
+ vpaddq $TEMP1, $ACC0, $ACC0
+ vpmuludq 32*7-128($aap), $B1, $ACC1
+ vpbroadcastq 32*4-128($tpa), $B1
+ vpaddq 32*10-448($tp1), $ACC1, $ACC1
+
+ vmovdqu $ACC4, 32*4-192($tp0)
+ vmovdqu $ACC5, 32*5-192($tp0)
+
+ vpmuludq 32*3-128($ap), $B2, $TEMP0
+ vpaddq $TEMP0, $ACC6, $ACC6
+ vpmuludq 32*3-128($aap), $B2, $TEMP1
+ vpaddq $TEMP1, $ACC7, $ACC7
+ vpmuludq 32*4-128($aap), $B2, $TEMP2
+ vpaddq $TEMP2, $ACC8, $ACC8
+ vpmuludq 32*5-128($aap), $B2, $TEMP0
+ vpaddq $TEMP0, $ACC0, $ACC0
+ vpmuludq 32*6-128($aap), $B2, $TEMP1
+ vpaddq $TEMP1, $ACC1, $ACC1
+ vpmuludq 32*7-128($aap), $B2, $ACC2
+ vpbroadcastq 32*5-128($tpa), $B2
+ vpaddq 32*11-448($tp1), $ACC2, $ACC2
+
+ vmovdqu $ACC6, 32*6-192($tp0)
+ vmovdqu $ACC7, 32*7-192($tp0)
+
+ vpmuludq 32*4-128($ap), $B1, $TEMP0
+ vpaddq $TEMP0, $ACC8, $ACC8
+ vpmuludq 32*4-128($aap), $B1, $TEMP1
+ vpaddq $TEMP1, $ACC0, $ACC0
+ vpmuludq 32*5-128($aap), $B1, $TEMP2
+ vpaddq $TEMP2, $ACC1, $ACC1
+ vpmuludq 32*6-128($aap), $B1, $TEMP0
+ vpaddq $TEMP0, $ACC2, $ACC2
+ vpmuludq 32*7-128($aap), $B1, $ACC3
+ vpbroadcastq 32*6-128($tpa), $B1
+ vpaddq 32*12-448($tp1), $ACC3, $ACC3
+
+ vmovdqu $ACC8, 32*8-192($tp0)
+ vmovdqu $ACC0, 32*9-192($tp0)
+ lea 8($tp0), $tp0
+
+ vpmuludq 32*5-128($ap), $B2, $TEMP2
+ vpaddq $TEMP2, $ACC1, $ACC1
+ vpmuludq 32*5-128($aap), $B2, $TEMP0
+ vpaddq $TEMP0, $ACC2, $ACC2
+ vpmuludq 32*6-128($aap), $B2, $TEMP1
+ vpaddq $TEMP1, $ACC3, $ACC3
+ vpmuludq 32*7-128($aap), $B2, $ACC4
+ vpbroadcastq 32*7-128($tpa), $B2
+ vpaddq 32*13-448($tp1), $ACC4, $ACC4
+
+ vmovdqu $ACC1, 32*10-448($tp1)
+ vmovdqu $ACC2, 32*11-448($tp1)
+
+ vpmuludq 32*6-128($ap), $B1, $TEMP0
+ vpaddq $TEMP0, $ACC3, $ACC3
+ vpmuludq 32*6-128($aap), $B1, $TEMP1
+ vpbroadcastq 32*8-128($tpa), $ACC0 # borrow $ACC0 for $B1
+ vpaddq $TEMP1, $ACC4, $ACC4
+ vpmuludq 32*7-128($aap), $B1, $ACC5
+ vpbroadcastq 32*0+8-128($tpa), $B1 # for next iteration
+ vpaddq 32*14-448($tp1), $ACC5, $ACC5
+
+ vmovdqu $ACC3, 32*12-448($tp1)
+ vmovdqu $ACC4, 32*13-448($tp1)
+ lea 8($tpa), $tpa
+
+ vpmuludq 32*7-128($ap), $B2, $TEMP0
+ vpaddq $TEMP0, $ACC5, $ACC5
+ vpmuludq 32*7-128($aap), $B2, $ACC6
+ vpaddq 32*15-448($tp1), $ACC6, $ACC6
+
+ vpmuludq 32*8-128($ap), $ACC0, $ACC7
+ vmovdqu $ACC5, 32*14-448($tp1)
+ vpaddq 32*16-448($tp1), $ACC7, $ACC7
+ vmovdqu $ACC6, 32*15-448($tp1)
+ vmovdqu $ACC7, 32*16-448($tp1)
+ lea 8($tp1), $tp1
+
+ dec $i
+ jnz .LOOP_SQR_1024
+___
+$ZERO = $ACC9;
+$TEMP0 = $B1;
+$TEMP2 = $B2;
+$TEMP3 = $Y1;
+$TEMP4 = $Y2;
+$code.=<<___;
+ #we need to fix indexes 32-39 to avoid overflow
+ vmovdqu 32*8(%rsp), $ACC8 # 32*8-192($tp0),
+ vmovdqu 32*9(%rsp), $ACC1 # 32*9-192($tp0)
+ vmovdqu 32*10(%rsp), $ACC2 # 32*10-192($tp0)
+ lea 192(%rsp), $tp0 # 64+128=192
+
+ vpsrlq \$29, $ACC8, $TEMP1
+ vpand $AND_MASK, $ACC8, $ACC8
+ vpsrlq \$29, $ACC1, $TEMP2
+ vpand $AND_MASK, $ACC1, $ACC1
+
+ vpermq \$0x93, $TEMP1, $TEMP1
+ vpxor $ZERO, $ZERO, $ZERO
+ vpermq \$0x93, $TEMP2, $TEMP2
+
+ vpblendd \$3, $ZERO, $TEMP1, $TEMP0
+ vpblendd \$3, $TEMP1, $TEMP2, $TEMP1
+ vpaddq $TEMP0, $ACC8, $ACC8
+ vpblendd \$3, $TEMP2, $ZERO, $TEMP2
+ vpaddq $TEMP1, $ACC1, $ACC1
+ vpaddq $TEMP2, $ACC2, $ACC2
+ vmovdqu $ACC1, 32*9-192($tp0)
+ vmovdqu $ACC2, 32*10-192($tp0)
+
+ mov (%rsp), %rax
+ mov 8(%rsp), $r1
+ mov 16(%rsp), $r2
+ mov 24(%rsp), $r3
+ vmovdqu 32*1(%rsp), $ACC1
+ vmovdqu 32*2-192($tp0), $ACC2
+ vmovdqu 32*3-192($tp0), $ACC3
+ vmovdqu 32*4-192($tp0), $ACC4
+ vmovdqu 32*5-192($tp0), $ACC5
+ vmovdqu 32*6-192($tp0), $ACC6
+ vmovdqu 32*7-192($tp0), $ACC7
+
+ mov %rax, $r0
+ imull $n0, %eax
+ and \$0x1fffffff, %eax
+ vmovd %eax, $Y1
+
+ mov %rax, %rdx
+ imulq -128($np), %rax
+ vpbroadcastq $Y1, $Y1
+ add %rax, $r0
+ mov %rdx, %rax
+ imulq 8-128($np), %rax
+ shr \$29, $r0
+ add %rax, $r1
+ mov %rdx, %rax
+ imulq 16-128($np), %rax
+ add $r0, $r1
+ add %rax, $r2
+ imulq 24-128($np), %rdx
+ add %rdx, $r3
+
+ mov $r1, %rax
+ imull $n0, %eax
+ and \$0x1fffffff, %eax
+
+ mov \$9, $i
+ jmp .LOOP_REDUCE_1024
+
+.align 32
+.LOOP_REDUCE_1024:
+ vmovd %eax, $Y2
+ vpbroadcastq $Y2, $Y2
+
+ vpmuludq 32*1-128($np), $Y1, $TEMP0
+ mov %rax, %rdx
+ imulq -128($np), %rax
+ vpaddq $TEMP0, $ACC1, $ACC1
+ add %rax, $r1
+ vpmuludq 32*2-128($np), $Y1, $TEMP1
+ mov %rdx, %rax
+ imulq 8-128($np), %rax
+ vpaddq $TEMP1, $ACC2, $ACC2
+ vpmuludq 32*3-128($np), $Y1, $TEMP2
+ .byte 0x67
+ add %rax, $r2
+ .byte 0x67
+ mov %rdx, %rax
+ imulq 16-128($np), %rax
+ shr \$29, $r1
+ vpaddq $TEMP2, $ACC3, $ACC3
+ vpmuludq 32*4-128($np), $Y1, $TEMP0
+ add %rax, $r3
+ add $r1, $r2
+ vpaddq $TEMP0, $ACC4, $ACC4
+ vpmuludq 32*5-128($np), $Y1, $TEMP1
+ mov $r2, %rax
+ imull $n0, %eax
+ vpaddq $TEMP1, $ACC5, $ACC5
+ vpmuludq 32*6-128($np), $Y1, $TEMP2
+ and \$0x1fffffff, %eax
+ vpaddq $TEMP2, $ACC6, $ACC6
+ vpmuludq 32*7-128($np), $Y1, $TEMP0
+ vpaddq $TEMP0, $ACC7, $ACC7
+ vpmuludq 32*8-128($np), $Y1, $TEMP1
+ vmovd %eax, $Y1
+ #vmovdqu 32*1-8-128($np), $TEMP2 # moved below
+ vpaddq $TEMP1, $ACC8, $ACC8
+ #vmovdqu 32*2-8-128($np), $TEMP0 # moved below
+ vpbroadcastq $Y1, $Y1
+
+ vpmuludq 32*1-8-128($np), $Y2, $TEMP2 # see above
+ vmovdqu 32*3-8-128($np), $TEMP1
+ mov %rax, %rdx
+ imulq -128($np), %rax
+ vpaddq $TEMP2, $ACC1, $ACC1
+ vpmuludq 32*2-8-128($np), $Y2, $TEMP0 # see above
+ vmovdqu 32*4-8-128($np), $TEMP2
+ add %rax, $r2
+ mov %rdx, %rax
+ imulq 8-128($np), %rax
+ vpaddq $TEMP0, $ACC2, $ACC2
+ add $r3, %rax
+ shr \$29, $r2
+ vpmuludq $Y2, $TEMP1, $TEMP1
+ vmovdqu 32*5-8-128($np), $TEMP0
+ add $r2, %rax
+ vpaddq $TEMP1, $ACC3, $ACC3
+ vpmuludq $Y2, $TEMP2, $TEMP2
+ vmovdqu 32*6-8-128($np), $TEMP1
+ .byte 0x67
+ mov %rax, $r3
+ imull $n0, %eax
+ vpaddq $TEMP2, $ACC4, $ACC4
+ vpmuludq $Y2, $TEMP0, $TEMP0
+ .byte 0xc4,0x41,0x7e,0x6f,0x9d,0x58,0x00,0x00,0x00 # vmovdqu 32*7-8-128($np), $TEMP2
+ and \$0x1fffffff, %eax
+ vpaddq $TEMP0, $ACC5, $ACC5
+ vpmuludq $Y2, $TEMP1, $TEMP1
+ vmovdqu 32*8-8-128($np), $TEMP0
+ vpaddq $TEMP1, $ACC6, $ACC6
+ vpmuludq $Y2, $TEMP2, $TEMP2
+ vmovdqu 32*9-8-128($np), $ACC9
+ vmovd %eax, $ACC0 # borrow ACC0 for Y2
+ imulq -128($np), %rax
+ vpaddq $TEMP2, $ACC7, $ACC7
+ vpmuludq $Y2, $TEMP0, $TEMP0
+ vmovdqu 32*1-16-128($np), $TEMP1
+ vpbroadcastq $ACC0, $ACC0
+ vpaddq $TEMP0, $ACC8, $ACC8
+ vpmuludq $Y2, $ACC9, $ACC9
+ vmovdqu 32*2-16-128($np), $TEMP2
+ add %rax, $r3
+
+___
+($ACC0,$Y2)=($Y2,$ACC0);
+$code.=<<___;
+ vmovdqu 32*1-24-128($np), $ACC0
+ vpmuludq $Y1, $TEMP1, $TEMP1
+ vmovdqu 32*3-16-128($np), $TEMP0
+ vpaddq $TEMP1, $ACC1, $ACC1
+ vpmuludq $Y2, $ACC0, $ACC0
+ vpmuludq $Y1, $TEMP2, $TEMP2
+ .byte 0xc4,0x41,0x7e,0x6f,0xb5,0xf0,0xff,0xff,0xff # vmovdqu 32*4-16-128($np), $TEMP1
+ vpaddq $ACC1, $ACC0, $ACC0
+ vpaddq $TEMP2, $ACC2, $ACC2
+ vpmuludq $Y1, $TEMP0, $TEMP0
+ vmovdqu 32*5-16-128($np), $TEMP2
+ .byte 0x67
+ vmovq $ACC0, %rax
+ vmovdqu $ACC0, (%rsp) # transfer $r0-$r3
+ vpaddq $TEMP0, $ACC3, $ACC3
+ vpmuludq $Y1, $TEMP1, $TEMP1
+ vmovdqu 32*6-16-128($np), $TEMP0
+ vpaddq $TEMP1, $ACC4, $ACC4
+ vpmuludq $Y1, $TEMP2, $TEMP2
+ vmovdqu 32*7-16-128($np), $TEMP1
+ vpaddq $TEMP2, $ACC5, $ACC5
+ vpmuludq $Y1, $TEMP0, $TEMP0
+ vmovdqu 32*8-16-128($np), $TEMP2
+ vpaddq $TEMP0, $ACC6, $ACC6
+ vpmuludq $Y1, $TEMP1, $TEMP1
+ shr \$29, $r3
+ vmovdqu 32*9-16-128($np), $TEMP0
+ add $r3, %rax
+ vpaddq $TEMP1, $ACC7, $ACC7
+ vpmuludq $Y1, $TEMP2, $TEMP2
+ #vmovdqu 32*2-24-128($np), $TEMP1 # moved below
+ mov %rax, $r0
+ imull $n0, %eax
+ vpaddq $TEMP2, $ACC8, $ACC8
+ vpmuludq $Y1, $TEMP0, $TEMP0
+ and \$0x1fffffff, %eax
+ vmovd %eax, $Y1
+ vmovdqu 32*3-24-128($np), $TEMP2
+ .byte 0x67
+ vpaddq $TEMP0, $ACC9, $ACC9
+ vpbroadcastq $Y1, $Y1
+
+ vpmuludq 32*2-24-128($np), $Y2, $TEMP1 # see above
+ vmovdqu 32*4-24-128($np), $TEMP0
+ mov %rax, %rdx
+ imulq -128($np), %rax
+ mov 8(%rsp), $r1
+ vpaddq $TEMP1, $ACC2, $ACC1
+ vpmuludq $Y2, $TEMP2, $TEMP2
+ vmovdqu 32*5-24-128($np), $TEMP1
+ add %rax, $r0
+ mov %rdx, %rax
+ imulq 8-128($np), %rax
+ .byte 0x67
+ shr \$29, $r0
+ mov 16(%rsp), $r2
+ vpaddq $TEMP2, $ACC3, $ACC2
+ vpmuludq $Y2, $TEMP0, $TEMP0
+ vmovdqu 32*6-24-128($np), $TEMP2
+ add %rax, $r1
+ mov %rdx, %rax
+ imulq 16-128($np), %rax
+ vpaddq $TEMP0, $ACC4, $ACC3
+ vpmuludq $Y2, $TEMP1, $TEMP1
+ vmovdqu 32*7-24-128($np), $TEMP0
+ imulq 24-128($np), %rdx # future $r3
+ add %rax, $r2
+ lea ($r0,$r1), %rax
+ vpaddq $TEMP1, $ACC5, $ACC4
+ vpmuludq $Y2, $TEMP2, $TEMP2
+ vmovdqu 32*8-24-128($np), $TEMP1
+ mov %rax, $r1
+ imull $n0, %eax
+ vpmuludq $Y2, $TEMP0, $TEMP0
+ vpaddq $TEMP2, $ACC6, $ACC5
+ vmovdqu 32*9-24-128($np), $TEMP2
+ and \$0x1fffffff, %eax
+ vpaddq $TEMP0, $ACC7, $ACC6
+ vpmuludq $Y2, $TEMP1, $TEMP1
+ add 24(%rsp), %rdx
+ vpaddq $TEMP1, $ACC8, $ACC7
+ vpmuludq $Y2, $TEMP2, $TEMP2
+ vpaddq $TEMP2, $ACC9, $ACC8
+ vmovq $r3, $ACC9
+ mov %rdx, $r3
+
+ dec $i
+ jnz .LOOP_REDUCE_1024
+___
+($ACC0,$Y2)=($Y2,$ACC0);
+$code.=<<___;
+ lea 448(%rsp), $tp1 # size optimization
+ vpaddq $ACC9, $Y2, $ACC0
+ vpxor $ZERO, $ZERO, $ZERO
+
+ vpaddq 32*9-192($tp0), $ACC0, $ACC0
+ vpaddq 32*10-448($tp1), $ACC1, $ACC1
+ vpaddq 32*11-448($tp1), $ACC2, $ACC2
+ vpaddq 32*12-448($tp1), $ACC3, $ACC3
+ vpaddq 32*13-448($tp1), $ACC4, $ACC4
+ vpaddq 32*14-448($tp1), $ACC5, $ACC5
+ vpaddq 32*15-448($tp1), $ACC6, $ACC6
+ vpaddq 32*16-448($tp1), $ACC7, $ACC7
+ vpaddq 32*17-448($tp1), $ACC8, $ACC8
+
+ vpsrlq \$29, $ACC0, $TEMP1
+ vpand $AND_MASK, $ACC0, $ACC0
+ vpsrlq \$29, $ACC1, $TEMP2
+ vpand $AND_MASK, $ACC1, $ACC1
+ vpsrlq \$29, $ACC2, $TEMP3
+ vpermq \$0x93, $TEMP1, $TEMP1
+ vpand $AND_MASK, $ACC2, $ACC2
+ vpsrlq \$29, $ACC3, $TEMP4
+ vpermq \$0x93, $TEMP2, $TEMP2
+ vpand $AND_MASK, $ACC3, $ACC3
+ vpermq \$0x93, $TEMP3, $TEMP3
+
+ vpblendd \$3, $ZERO, $TEMP1, $TEMP0
+ vpermq \$0x93, $TEMP4, $TEMP4
+ vpblendd \$3, $TEMP1, $TEMP2, $TEMP1
+ vpaddq $TEMP0, $ACC0, $ACC0
+ vpblendd \$3, $TEMP2, $TEMP3, $TEMP2
+ vpaddq $TEMP1, $ACC1, $ACC1
+ vpblendd \$3, $TEMP3, $TEMP4, $TEMP3
+ vpaddq $TEMP2, $ACC2, $ACC2
+ vpblendd \$3, $TEMP4, $ZERO, $TEMP4
+ vpaddq $TEMP3, $ACC3, $ACC3
+ vpaddq $TEMP4, $ACC4, $ACC4
+
+ vpsrlq \$29, $ACC0, $TEMP1
+ vpand $AND_MASK, $ACC0, $ACC0
+ vpsrlq \$29, $ACC1, $TEMP2
+ vpand $AND_MASK, $ACC1, $ACC1
+ vpsrlq \$29, $ACC2, $TEMP3
+ vpermq \$0x93, $TEMP1, $TEMP1
+ vpand $AND_MASK, $ACC2, $ACC2
+ vpsrlq \$29, $ACC3, $TEMP4
+ vpermq \$0x93, $TEMP2, $TEMP2
+ vpand $AND_MASK, $ACC3, $ACC3
+ vpermq \$0x93, $TEMP3, $TEMP3
+
+ vpblendd \$3, $ZERO, $TEMP1, $TEMP0
+ vpermq \$0x93, $TEMP4, $TEMP4
+ vpblendd \$3, $TEMP1, $TEMP2, $TEMP1
+ vpaddq $TEMP0, $ACC0, $ACC0
+ vpblendd \$3, $TEMP2, $TEMP3, $TEMP2
+ vpaddq $TEMP1, $ACC1, $ACC1
+ vmovdqu $ACC0, 32*0-128($rp)
+ vpblendd \$3, $TEMP3, $TEMP4, $TEMP3
+ vpaddq $TEMP2, $ACC2, $ACC2
+ vmovdqu $ACC1, 32*1-128($rp)
+ vpblendd \$3, $TEMP4, $ZERO, $TEMP4
+ vpaddq $TEMP3, $ACC3, $ACC3
+ vmovdqu $ACC2, 32*2-128($rp)
+ vpaddq $TEMP4, $ACC4, $ACC4
+ vmovdqu $ACC3, 32*3-128($rp)
+___
+$TEMP5=$ACC0;
+$code.=<<___;
+ vpsrlq \$29, $ACC4, $TEMP1
+ vpand $AND_MASK, $ACC4, $ACC4
+ vpsrlq \$29, $ACC5, $TEMP2
+ vpand $AND_MASK, $ACC5, $ACC5
+ vpsrlq \$29, $ACC6, $TEMP3
+ vpermq \$0x93, $TEMP1, $TEMP1
+ vpand $AND_MASK, $ACC6, $ACC6
+ vpsrlq \$29, $ACC7, $TEMP4
+ vpermq \$0x93, $TEMP2, $TEMP2
+ vpand $AND_MASK, $ACC7, $ACC7
+ vpsrlq \$29, $ACC8, $TEMP5
+ vpermq \$0x93, $TEMP3, $TEMP3
+ vpand $AND_MASK, $ACC8, $ACC8
+ vpermq \$0x93, $TEMP4, $TEMP4
+
+ vpblendd \$3, $ZERO, $TEMP1, $TEMP0
+ vpermq \$0x93, $TEMP5, $TEMP5
+ vpblendd \$3, $TEMP1, $TEMP2, $TEMP1
+ vpaddq $TEMP0, $ACC4, $ACC4
+ vpblendd \$3, $TEMP2, $TEMP3, $TEMP2
+ vpaddq $TEMP1, $ACC5, $ACC5
+ vpblendd \$3, $TEMP3, $TEMP4, $TEMP3
+ vpaddq $TEMP2, $ACC6, $ACC6
+ vpblendd \$3, $TEMP4, $TEMP5, $TEMP4
+ vpaddq $TEMP3, $ACC7, $ACC7
+ vpaddq $TEMP4, $ACC8, $ACC8
+
+ vpsrlq \$29, $ACC4, $TEMP1
+ vpand $AND_MASK, $ACC4, $ACC4
+ vpsrlq \$29, $ACC5, $TEMP2
+ vpand $AND_MASK, $ACC5, $ACC5
+ vpsrlq \$29, $ACC6, $TEMP3
+ vpermq \$0x93, $TEMP1, $TEMP1
+ vpand $AND_MASK, $ACC6, $ACC6
+ vpsrlq \$29, $ACC7, $TEMP4
+ vpermq \$0x93, $TEMP2, $TEMP2
+ vpand $AND_MASK, $ACC7, $ACC7
+ vpsrlq \$29, $ACC8, $TEMP5
+ vpermq \$0x93, $TEMP3, $TEMP3
+ vpand $AND_MASK, $ACC8, $ACC8
+ vpermq \$0x93, $TEMP4, $TEMP4
+
+ vpblendd \$3, $ZERO, $TEMP1, $TEMP0
+ vpermq \$0x93, $TEMP5, $TEMP5
+ vpblendd \$3, $TEMP1, $TEMP2, $TEMP1
+ vpaddq $TEMP0, $ACC4, $ACC4
+ vpblendd \$3, $TEMP2, $TEMP3, $TEMP2
+ vpaddq $TEMP1, $ACC5, $ACC5
+ vmovdqu $ACC4, 32*4-128($rp)
+ vpblendd \$3, $TEMP3, $TEMP4, $TEMP3
+ vpaddq $TEMP2, $ACC6, $ACC6
+ vmovdqu $ACC5, 32*5-128($rp)
+ vpblendd \$3, $TEMP4, $TEMP5, $TEMP4
+ vpaddq $TEMP3, $ACC7, $ACC7
+ vmovdqu $ACC6, 32*6-128($rp)
+ vpaddq $TEMP4, $ACC8, $ACC8
+ vmovdqu $ACC7, 32*7-128($rp)
+ vmovdqu $ACC8, 32*8-128($rp)
+
+ mov $rp, $ap
+ dec $rep
+ jne .LOOP_GRANDE_SQR_1024
+
+ vzeroall
+ mov %rbp, %rax
+___
+$code.=<<___ if ($win64);
+ movaps -0xd8(%rax),%xmm6
+ movaps -0xc8(%rax),%xmm7
+ movaps -0xb8(%rax),%xmm8
+ movaps -0xa8(%rax),%xmm9
+ movaps -0x98(%rax),%xmm10
+ movaps -0x88(%rax),%xmm11
+ movaps -0x78(%rax),%xmm12
+ movaps -0x68(%rax),%xmm13
+ movaps -0x58(%rax),%xmm14
+ movaps -0x48(%rax),%xmm15
+___
+$code.=<<___;
+ mov -48(%rax),%r15
+ mov -40(%rax),%r14
+ mov -32(%rax),%r13
+ mov -24(%rax),%r12
+ mov -16(%rax),%rbp
+ mov -8(%rax),%rbx
+ lea (%rax),%rsp # restore %rsp
+.Lsqr_1024_epilogue:
+ ret
+.size rsaz_1024_sqr_avx2,.-rsaz_1024_sqr_avx2
+___
+}
+
+{ # void AMM_WW(
+my $rp="%rdi"; # BN_ULONG *rp,
+my $ap="%rsi"; # const BN_ULONG *ap,
+my $bp="%rdx"; # const BN_ULONG *bp,
+my $np="%rcx"; # const BN_ULONG *np,
+my $n0="%r8d"; # unsigned int n0);
+
+# The registers that hold the accumulated redundant result
+# The AMM works on 1024 bit operands, and redundant word size is 29
+# Therefore: ceil(1024/29)/4 = 9
+my $ACC0="%ymm0";
+my $ACC1="%ymm1";
+my $ACC2="%ymm2";
+my $ACC3="%ymm3";
+my $ACC4="%ymm4";
+my $ACC5="%ymm5";
+my $ACC6="%ymm6";
+my $ACC7="%ymm7";
+my $ACC8="%ymm8";
+my $ACC9="%ymm9";
+
+# Registers that hold the broadcasted words of multiplier, currently used
+my $Bi="%ymm10";
+my $Yi="%ymm11";
+
+# Helper registers
+my $TEMP0=$ACC0;
+my $TEMP1="%ymm12";
+my $TEMP2="%ymm13";
+my $ZERO="%ymm14";
+my $AND_MASK="%ymm15";
+
+# alu registers that hold the first words of the ACC
+my $r0="%r9";
+my $r1="%r10";
+my $r2="%r11";
+my $r3="%r12";
+
+my $i="%r14d";
+my $tmp="%r15";
+
+$bp="%r13"; # reassigned argument
+
+$code.=<<___;
+.globl rsaz_1024_mul_avx2
+.type rsaz_1024_mul_avx2,\@function,5
+.align 64
+rsaz_1024_mul_avx2:
+ lea (%rsp), %rax
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+___
+$code.=<<___ if ($win64);
+ vzeroupper
+ lea -0xa8(%rsp),%rsp
+ vmovaps %xmm6,-0xd8(%rax)
+ vmovaps %xmm7,-0xc8(%rax)
+ vmovaps %xmm8,-0xb8(%rax)
+ vmovaps %xmm9,-0xa8(%rax)
+ vmovaps %xmm10,-0x98(%rax)
+ vmovaps %xmm11,-0x88(%rax)
+ vmovaps %xmm12,-0x78(%rax)
+ vmovaps %xmm13,-0x68(%rax)
+ vmovaps %xmm14,-0x58(%rax)
+ vmovaps %xmm15,-0x48(%rax)
+.Lmul_1024_body:
+___
+$code.=<<___;
+ mov %rax,%rbp
+ vzeroall
+ mov %rdx, $bp # reassigned argument
+ sub \$64,%rsp
+
+ # unaligned 256-bit load that crosses page boundary can
+ # cause severe performance degradation here, so if $ap does
+ # cross page boundary, swap it with $bp [meaning that caller
+ # is advised to lay down $ap and $bp next to each other, so
+ # that only one can cross page boundary].
+ .byte 0x67,0x67
+ mov $ap, $tmp
+ and \$4095, $tmp
+ add \$32*10, $tmp
+ shr \$12, $tmp
+ mov $ap, $tmp
+ cmovnz $bp, $ap
+ cmovnz $tmp, $bp
+
+ mov $np, $tmp
+ sub \$-128,$ap # size optimization
+ sub \$-128,$np
+ sub \$-128,$rp
+
+ and \$4095, $tmp # see if $np crosses page
+ add \$32*10, $tmp
+ .byte 0x67,0x67
+ shr \$12, $tmp
+ jz .Lmul_1024_no_n_copy
+
+ # unaligned 256-bit load that crosses page boundary can
+ # cause severe performance degradation here, so if $np does
+ # cross page boundary, copy it to stack and make sure stack
+ # frame doesn't...
+ sub \$32*10,%rsp
+ vmovdqu 32*0-128($np), $ACC0
+ and \$-512, %rsp
+ vmovdqu 32*1-128($np), $ACC1
+ vmovdqu 32*2-128($np), $ACC2
+ vmovdqu 32*3-128($np), $ACC3
+ vmovdqu 32*4-128($np), $ACC4
+ vmovdqu 32*5-128($np), $ACC5
+ vmovdqu 32*6-128($np), $ACC6
+ vmovdqu 32*7-128($np), $ACC7
+ vmovdqu 32*8-128($np), $ACC8
+ lea 64+128(%rsp),$np
+ vmovdqu $ACC0, 32*0-128($np)
+ vpxor $ACC0, $ACC0, $ACC0
+ vmovdqu $ACC1, 32*1-128($np)
+ vpxor $ACC1, $ACC1, $ACC1
+ vmovdqu $ACC2, 32*2-128($np)
+ vpxor $ACC2, $ACC2, $ACC2
+ vmovdqu $ACC3, 32*3-128($np)
+ vpxor $ACC3, $ACC3, $ACC3
+ vmovdqu $ACC4, 32*4-128($np)
+ vpxor $ACC4, $ACC4, $ACC4
+ vmovdqu $ACC5, 32*5-128($np)
+ vpxor $ACC5, $ACC5, $ACC5
+ vmovdqu $ACC6, 32*6-128($np)
+ vpxor $ACC6, $ACC6, $ACC6
+ vmovdqu $ACC7, 32*7-128($np)
+ vpxor $ACC7, $ACC7, $ACC7
+ vmovdqu $ACC8, 32*8-128($np)
+ vmovdqa $ACC0, $ACC8
+ vmovdqu $ACC9, 32*9-128($np) # $ACC9 is zero after vzeroall
+.Lmul_1024_no_n_copy:
+ and \$-64,%rsp
+
+ mov ($bp), %rbx
+ vpbroadcastq ($bp), $Bi
+ vmovdqu $ACC0, (%rsp) # clear top of stack
+ xor $r0, $r0
+ .byte 0x67
+ xor $r1, $r1
+ xor $r2, $r2
+ xor $r3, $r3
+
+ vmovdqu .Land_mask(%rip), $AND_MASK
+ mov \$9, $i
+ jmp .Loop_mul_1024
+
+.align 32
+.Loop_mul_1024:
+ vpsrlq \$29, $ACC3, $ACC9 # correct $ACC3(*)
+ mov %rbx, %rax
+ imulq -128($ap), %rax
+ add $r0, %rax
+ mov %rbx, $r1
+ imulq 8-128($ap), $r1
+ add 8(%rsp), $r1
+
+ mov %rax, $r0
+ imull $n0, %eax
+ and \$0x1fffffff, %eax
+
+ mov %rbx, $r2
+ imulq 16-128($ap), $r2
+ add 16(%rsp), $r2
+
+ mov %rbx, $r3
+ imulq 24-128($ap), $r3
+ add 24(%rsp), $r3
+ vpmuludq 32*1-128($ap),$Bi,$TEMP0
+ vmovd %eax, $Yi
+ vpaddq $TEMP0,$ACC1,$ACC1
+ vpmuludq 32*2-128($ap),$Bi,$TEMP1
+ vpbroadcastq $Yi, $Yi
+ vpaddq $TEMP1,$ACC2,$ACC2
+ vpmuludq 32*3-128($ap),$Bi,$TEMP2
+ vpand $AND_MASK, $ACC3, $ACC3 # correct $ACC3
+ vpaddq $TEMP2,$ACC3,$ACC3
+ vpmuludq 32*4-128($ap),$Bi,$TEMP0
+ vpaddq $TEMP0,$ACC4,$ACC4
+ vpmuludq 32*5-128($ap),$Bi,$TEMP1
+ vpaddq $TEMP1,$ACC5,$ACC5
+ vpmuludq 32*6-128($ap),$Bi,$TEMP2
+ vpaddq $TEMP2,$ACC6,$ACC6
+ vpmuludq 32*7-128($ap),$Bi,$TEMP0
+ vpermq \$0x93, $ACC9, $ACC9 # correct $ACC3
+ vpaddq $TEMP0,$ACC7,$ACC7
+ vpmuludq 32*8-128($ap),$Bi,$TEMP1
+ vpbroadcastq 8($bp), $Bi
+ vpaddq $TEMP1,$ACC8,$ACC8
+
+ mov %rax,%rdx
+ imulq -128($np),%rax
+ add %rax,$r0
+ mov %rdx,%rax
+ imulq 8-128($np),%rax
+ add %rax,$r1
+ mov %rdx,%rax
+ imulq 16-128($np),%rax
+ add %rax,$r2
+ shr \$29, $r0
+ imulq 24-128($np),%rdx
+ add %rdx,$r3
+ add $r0, $r1
+
+ vpmuludq 32*1-128($np),$Yi,$TEMP2
+ vmovq $Bi, %rbx
+ vpaddq $TEMP2,$ACC1,$ACC1
+ vpmuludq 32*2-128($np),$Yi,$TEMP0
+ vpaddq $TEMP0,$ACC2,$ACC2
+ vpmuludq 32*3-128($np),$Yi,$TEMP1
+ vpaddq $TEMP1,$ACC3,$ACC3
+ vpmuludq 32*4-128($np),$Yi,$TEMP2
+ vpaddq $TEMP2,$ACC4,$ACC4
+ vpmuludq 32*5-128($np),$Yi,$TEMP0
+ vpaddq $TEMP0,$ACC5,$ACC5
+ vpmuludq 32*6-128($np),$Yi,$TEMP1
+ vpaddq $TEMP1,$ACC6,$ACC6
+ vpmuludq 32*7-128($np),$Yi,$TEMP2
+ vpblendd \$3, $ZERO, $ACC9, $ACC9 # correct $ACC3
+ vpaddq $TEMP2,$ACC7,$ACC7
+ vpmuludq 32*8-128($np),$Yi,$TEMP0
+ vpaddq $ACC9, $ACC3, $ACC3 # correct $ACC3
+ vpaddq $TEMP0,$ACC8,$ACC8
+
+ mov %rbx, %rax
+ imulq -128($ap),%rax
+ add %rax,$r1
+ vmovdqu -8+32*1-128($ap),$TEMP1
+ mov %rbx, %rax
+ imulq 8-128($ap),%rax
+ add %rax,$r2
+ vmovdqu -8+32*2-128($ap),$TEMP2
+
+ mov $r1, %rax
+ imull $n0, %eax
+ and \$0x1fffffff, %eax
+
+ imulq 16-128($ap),%rbx
+ add %rbx,$r3
+ vpmuludq $Bi,$TEMP1,$TEMP1
+ vmovd %eax, $Yi
+ vmovdqu -8+32*3-128($ap),$TEMP0
+ vpaddq $TEMP1,$ACC1,$ACC1
+ vpmuludq $Bi,$TEMP2,$TEMP2
+ vpbroadcastq $Yi, $Yi
+ vmovdqu -8+32*4-128($ap),$TEMP1
+ vpaddq $TEMP2,$ACC2,$ACC2
+ vpmuludq $Bi,$TEMP0,$TEMP0
+ vmovdqu -8+32*5-128($ap),$TEMP2
+ vpaddq $TEMP0,$ACC3,$ACC3
+ vpmuludq $Bi,$TEMP1,$TEMP1
+ vmovdqu -8+32*6-128($ap),$TEMP0
+ vpaddq $TEMP1,$ACC4,$ACC4
+ vpmuludq $Bi,$TEMP2,$TEMP2
+ vmovdqu -8+32*7-128($ap),$TEMP1
+ vpaddq $TEMP2,$ACC5,$ACC5
+ vpmuludq $Bi,$TEMP0,$TEMP0
+ vmovdqu -8+32*8-128($ap),$TEMP2
+ vpaddq $TEMP0,$ACC6,$ACC6
+ vpmuludq $Bi,$TEMP1,$TEMP1
+ vmovdqu -8+32*9-128($ap),$ACC9
+ vpaddq $TEMP1,$ACC7,$ACC7
+ vpmuludq $Bi,$TEMP2,$TEMP2
+ vpaddq $TEMP2,$ACC8,$ACC8
+ vpmuludq $Bi,$ACC9,$ACC9
+ vpbroadcastq 16($bp), $Bi
+
+ mov %rax,%rdx
+ imulq -128($np),%rax
+ add %rax,$r1
+ vmovdqu -8+32*1-128($np),$TEMP0
+ mov %rdx,%rax
+ imulq 8-128($np),%rax
+ add %rax,$r2
+ vmovdqu -8+32*2-128($np),$TEMP1
+ shr \$29, $r1
+ imulq 16-128($np),%rdx
+ add %rdx,$r3
+ add $r1, $r2
+
+ vpmuludq $Yi,$TEMP0,$TEMP0
+ vmovq $Bi, %rbx
+ vmovdqu -8+32*3-128($np),$TEMP2
+ vpaddq $TEMP0,$ACC1,$ACC1
+ vpmuludq $Yi,$TEMP1,$TEMP1
+ vmovdqu -8+32*4-128($np),$TEMP0
+ vpaddq $TEMP1,$ACC2,$ACC2
+ vpmuludq $Yi,$TEMP2,$TEMP2
+ vmovdqu -8+32*5-128($np),$TEMP1
+ vpaddq $TEMP2,$ACC3,$ACC3
+ vpmuludq $Yi,$TEMP0,$TEMP0
+ vmovdqu -8+32*6-128($np),$TEMP2
+ vpaddq $TEMP0,$ACC4,$ACC4
+ vpmuludq $Yi,$TEMP1,$TEMP1
+ vmovdqu -8+32*7-128($np),$TEMP0
+ vpaddq $TEMP1,$ACC5,$ACC5
+ vpmuludq $Yi,$TEMP2,$TEMP2
+ vmovdqu -8+32*8-128($np),$TEMP1
+ vpaddq $TEMP2,$ACC6,$ACC6
+ vpmuludq $Yi,$TEMP0,$TEMP0
+ vmovdqu -8+32*9-128($np),$TEMP2
+ vpaddq $TEMP0,$ACC7,$ACC7
+ vpmuludq $Yi,$TEMP1,$TEMP1
+ vpaddq $TEMP1,$ACC8,$ACC8
+ vpmuludq $Yi,$TEMP2,$TEMP2
+ vpaddq $TEMP2,$ACC9,$ACC9
+
+ vmovdqu -16+32*1-128($ap),$TEMP0
+ mov %rbx,%rax
+ imulq -128($ap),%rax
+ add $r2,%rax
+
+ vmovdqu -16+32*2-128($ap),$TEMP1
+ mov %rax,$r2
+ imull $n0, %eax
+ and \$0x1fffffff, %eax
+
+ imulq 8-128($ap),%rbx
+ add %rbx,$r3
+ vpmuludq $Bi,$TEMP0,$TEMP0
+ vmovd %eax, $Yi
+ vmovdqu -16+32*3-128($ap),$TEMP2
+ vpaddq $TEMP0,$ACC1,$ACC1
+ vpmuludq $Bi,$TEMP1,$TEMP1
+ vpbroadcastq $Yi, $Yi
+ vmovdqu -16+32*4-128($ap),$TEMP0
+ vpaddq $TEMP1,$ACC2,$ACC2
+ vpmuludq $Bi,$TEMP2,$TEMP2
+ vmovdqu -16+32*5-128($ap),$TEMP1
+ vpaddq $TEMP2,$ACC3,$ACC3
+ vpmuludq $Bi,$TEMP0,$TEMP0
+ vmovdqu -16+32*6-128($ap),$TEMP2
+ vpaddq $TEMP0,$ACC4,$ACC4
+ vpmuludq $Bi,$TEMP1,$TEMP1
+ vmovdqu -16+32*7-128($ap),$TEMP0
+ vpaddq $TEMP1,$ACC5,$ACC5
+ vpmuludq $Bi,$TEMP2,$TEMP2
+ vmovdqu -16+32*8-128($ap),$TEMP1
+ vpaddq $TEMP2,$ACC6,$ACC6
+ vpmuludq $Bi,$TEMP0,$TEMP0
+ vmovdqu -16+32*9-128($ap),$TEMP2
+ vpaddq $TEMP0,$ACC7,$ACC7
+ vpmuludq $Bi,$TEMP1,$TEMP1
+ vpaddq $TEMP1,$ACC8,$ACC8
+ vpmuludq $Bi,$TEMP2,$TEMP2
+ vpbroadcastq 24($bp), $Bi
+ vpaddq $TEMP2,$ACC9,$ACC9
+
+ vmovdqu -16+32*1-128($np),$TEMP0
+ mov %rax,%rdx
+ imulq -128($np),%rax
+ add %rax,$r2
+ vmovdqu -16+32*2-128($np),$TEMP1
+ imulq 8-128($np),%rdx
+ add %rdx,$r3
+ shr \$29, $r2
+
+ vpmuludq $Yi,$TEMP0,$TEMP0
+ vmovq $Bi, %rbx
+ vmovdqu -16+32*3-128($np),$TEMP2
+ vpaddq $TEMP0,$ACC1,$ACC1
+ vpmuludq $Yi,$TEMP1,$TEMP1
+ vmovdqu -16+32*4-128($np),$TEMP0
+ vpaddq $TEMP1,$ACC2,$ACC2
+ vpmuludq $Yi,$TEMP2,$TEMP2
+ vmovdqu -16+32*5-128($np),$TEMP1
+ vpaddq $TEMP2,$ACC3,$ACC3
+ vpmuludq $Yi,$TEMP0,$TEMP0
+ vmovdqu -16+32*6-128($np),$TEMP2
+ vpaddq $TEMP0,$ACC4,$ACC4
+ vpmuludq $Yi,$TEMP1,$TEMP1
+ vmovdqu -16+32*7-128($np),$TEMP0
+ vpaddq $TEMP1,$ACC5,$ACC5
+ vpmuludq $Yi,$TEMP2,$TEMP2
+ vmovdqu -16+32*8-128($np),$TEMP1
+ vpaddq $TEMP2,$ACC6,$ACC6
+ vpmuludq $Yi,$TEMP0,$TEMP0
+ vmovdqu -16+32*9-128($np),$TEMP2
+ vpaddq $TEMP0,$ACC7,$ACC7
+ vpmuludq $Yi,$TEMP1,$TEMP1
+ vmovdqu -24+32*1-128($ap),$TEMP0
+ vpaddq $TEMP1,$ACC8,$ACC8
+ vpmuludq $Yi,$TEMP2,$TEMP2
+ vmovdqu -24+32*2-128($ap),$TEMP1
+ vpaddq $TEMP2,$ACC9,$ACC9
+
+ add $r2, $r3
+ imulq -128($ap),%rbx
+ add %rbx,$r3
+
+ mov $r3, %rax
+ imull $n0, %eax
+ and \$0x1fffffff, %eax
+
+ vpmuludq $Bi,$TEMP0,$TEMP0
+ vmovd %eax, $Yi
+ vmovdqu -24+32*3-128($ap),$TEMP2
+ vpaddq $TEMP0,$ACC1,$ACC1
+ vpmuludq $Bi,$TEMP1,$TEMP1
+ vpbroadcastq $Yi, $Yi
+ vmovdqu -24+32*4-128($ap),$TEMP0
+ vpaddq $TEMP1,$ACC2,$ACC2
+ vpmuludq $Bi,$TEMP2,$TEMP2
+ vmovdqu -24+32*5-128($ap),$TEMP1
+ vpaddq $TEMP2,$ACC3,$ACC3
+ vpmuludq $Bi,$TEMP0,$TEMP0
+ vmovdqu -24+32*6-128($ap),$TEMP2
+ vpaddq $TEMP0,$ACC4,$ACC4
+ vpmuludq $Bi,$TEMP1,$TEMP1
+ vmovdqu -24+32*7-128($ap),$TEMP0
+ vpaddq $TEMP1,$ACC5,$ACC5
+ vpmuludq $Bi,$TEMP2,$TEMP2
+ vmovdqu -24+32*8-128($ap),$TEMP1
+ vpaddq $TEMP2,$ACC6,$ACC6
+ vpmuludq $Bi,$TEMP0,$TEMP0
+ vmovdqu -24+32*9-128($ap),$TEMP2
+ vpaddq $TEMP0,$ACC7,$ACC7
+ vpmuludq $Bi,$TEMP1,$TEMP1
+ vpaddq $TEMP1,$ACC8,$ACC8
+ vpmuludq $Bi,$TEMP2,$TEMP2
+ vpbroadcastq 32($bp), $Bi
+ vpaddq $TEMP2,$ACC9,$ACC9
+ add \$32, $bp # $bp++
+
+ vmovdqu -24+32*1-128($np),$TEMP0
+ imulq -128($np),%rax
+ add %rax,$r3
+ shr \$29, $r3
+
+ vmovdqu -24+32*2-128($np),$TEMP1
+ vpmuludq $Yi,$TEMP0,$TEMP0
+ vmovq $Bi, %rbx
+ vmovdqu -24+32*3-128($np),$TEMP2
+ vpaddq $TEMP0,$ACC1,$ACC0 # $ACC0==$TEMP0
+ vpmuludq $Yi,$TEMP1,$TEMP1
+ vmovdqu $ACC0, (%rsp) # transfer $r0-$r3
+ vpaddq $TEMP1,$ACC2,$ACC1
+ vmovdqu -24+32*4-128($np),$TEMP0
+ vpmuludq $Yi,$TEMP2,$TEMP2
+ vmovdqu -24+32*5-128($np),$TEMP1
+ vpaddq $TEMP2,$ACC3,$ACC2
+ vpmuludq $Yi,$TEMP0,$TEMP0
+ vmovdqu -24+32*6-128($np),$TEMP2
+ vpaddq $TEMP0,$ACC4,$ACC3
+ vpmuludq $Yi,$TEMP1,$TEMP1
+ vmovdqu -24+32*7-128($np),$TEMP0
+ vpaddq $TEMP1,$ACC5,$ACC4
+ vpmuludq $Yi,$TEMP2,$TEMP2
+ vmovdqu -24+32*8-128($np),$TEMP1
+ vpaddq $TEMP2,$ACC6,$ACC5
+ vpmuludq $Yi,$TEMP0,$TEMP0
+ vmovdqu -24+32*9-128($np),$TEMP2
+ mov $r3, $r0
+ vpaddq $TEMP0,$ACC7,$ACC6
+ vpmuludq $Yi,$TEMP1,$TEMP1
+ add (%rsp), $r0
+ vpaddq $TEMP1,$ACC8,$ACC7
+ vpmuludq $Yi,$TEMP2,$TEMP2
+ vmovq $r3, $TEMP1
+ vpaddq $TEMP2,$ACC9,$ACC8
+
+ dec $i
+ jnz .Loop_mul_1024
+___
+
+# (*) Original implementation was correcting ACC1-ACC3 for overflow
+# after 7 loop runs, or after 28 iterations, or 56 additions.
+# But as we underutilize resources, it's possible to correct in
+# each iteration with marginal performance loss. But then, as
+# we do it in each iteration, we can correct less digits, and
+# avoid performance penalties completely. Also note that we
+# correct only three digits out of four. This works because
+# most significant digit is subjected to less additions.
+
+$TEMP0 = $ACC9;
+$TEMP3 = $Bi;
+$TEMP4 = $Yi;
+$code.=<<___;
+ vpermq \$0, $AND_MASK, $AND_MASK
+ vpaddq (%rsp), $TEMP1, $ACC0
+
+ vpsrlq \$29, $ACC0, $TEMP1
+ vpand $AND_MASK, $ACC0, $ACC0
+ vpsrlq \$29, $ACC1, $TEMP2
+ vpand $AND_MASK, $ACC1, $ACC1
+ vpsrlq \$29, $ACC2, $TEMP3
+ vpermq \$0x93, $TEMP1, $TEMP1
+ vpand $AND_MASK, $ACC2, $ACC2
+ vpsrlq \$29, $ACC3, $TEMP4
+ vpermq \$0x93, $TEMP2, $TEMP2
+ vpand $AND_MASK, $ACC3, $ACC3
+
+ vpblendd \$3, $ZERO, $TEMP1, $TEMP0
+ vpermq \$0x93, $TEMP3, $TEMP3
+ vpblendd \$3, $TEMP1, $TEMP2, $TEMP1
+ vpermq \$0x93, $TEMP4, $TEMP4
+ vpaddq $TEMP0, $ACC0, $ACC0
+ vpblendd \$3, $TEMP2, $TEMP3, $TEMP2
+ vpaddq $TEMP1, $ACC1, $ACC1
+ vpblendd \$3, $TEMP3, $TEMP4, $TEMP3
+ vpaddq $TEMP2, $ACC2, $ACC2
+ vpblendd \$3, $TEMP4, $ZERO, $TEMP4
+ vpaddq $TEMP3, $ACC3, $ACC3
+ vpaddq $TEMP4, $ACC4, $ACC4
+
+ vpsrlq \$29, $ACC0, $TEMP1
+ vpand $AND_MASK, $ACC0, $ACC0
+ vpsrlq \$29, $ACC1, $TEMP2
+ vpand $AND_MASK, $ACC1, $ACC1
+ vpsrlq \$29, $ACC2, $TEMP3
+ vpermq \$0x93, $TEMP1, $TEMP1
+ vpand $AND_MASK, $ACC2, $ACC2
+ vpsrlq \$29, $ACC3, $TEMP4
+ vpermq \$0x93, $TEMP2, $TEMP2
+ vpand $AND_MASK, $ACC3, $ACC3
+ vpermq \$0x93, $TEMP3, $TEMP3
+
+ vpblendd \$3, $ZERO, $TEMP1, $TEMP0
+ vpermq \$0x93, $TEMP4, $TEMP4
+ vpblendd \$3, $TEMP1, $TEMP2, $TEMP1
+ vpaddq $TEMP0, $ACC0, $ACC0
+ vpblendd \$3, $TEMP2, $TEMP3, $TEMP2
+ vpaddq $TEMP1, $ACC1, $ACC1
+ vpblendd \$3, $TEMP3, $TEMP4, $TEMP3
+ vpaddq $TEMP2, $ACC2, $ACC2
+ vpblendd \$3, $TEMP4, $ZERO, $TEMP4
+ vpaddq $TEMP3, $ACC3, $ACC3
+ vpaddq $TEMP4, $ACC4, $ACC4
+
+ vmovdqu $ACC0, 0-128($rp)
+ vmovdqu $ACC1, 32-128($rp)
+ vmovdqu $ACC2, 64-128($rp)
+ vmovdqu $ACC3, 96-128($rp)
+___
+
+$TEMP5=$ACC0;
+$code.=<<___;
+ vpsrlq \$29, $ACC4, $TEMP1
+ vpand $AND_MASK, $ACC4, $ACC4
+ vpsrlq \$29, $ACC5, $TEMP2
+ vpand $AND_MASK, $ACC5, $ACC5
+ vpsrlq \$29, $ACC6, $TEMP3
+ vpermq \$0x93, $TEMP1, $TEMP1
+ vpand $AND_MASK, $ACC6, $ACC6
+ vpsrlq \$29, $ACC7, $TEMP4
+ vpermq \$0x93, $TEMP2, $TEMP2
+ vpand $AND_MASK, $ACC7, $ACC7
+ vpsrlq \$29, $ACC8, $TEMP5
+ vpermq \$0x93, $TEMP3, $TEMP3
+ vpand $AND_MASK, $ACC8, $ACC8
+ vpermq \$0x93, $TEMP4, $TEMP4
+
+ vpblendd \$3, $ZERO, $TEMP1, $TEMP0
+ vpermq \$0x93, $TEMP5, $TEMP5
+ vpblendd \$3, $TEMP1, $TEMP2, $TEMP1
+ vpaddq $TEMP0, $ACC4, $ACC4
+ vpblendd \$3, $TEMP2, $TEMP3, $TEMP2
+ vpaddq $TEMP1, $ACC5, $ACC5
+ vpblendd \$3, $TEMP3, $TEMP4, $TEMP3
+ vpaddq $TEMP2, $ACC6, $ACC6
+ vpblendd \$3, $TEMP4, $TEMP5, $TEMP4
+ vpaddq $TEMP3, $ACC7, $ACC7
+ vpaddq $TEMP4, $ACC8, $ACC8
+
+ vpsrlq \$29, $ACC4, $TEMP1
+ vpand $AND_MASK, $ACC4, $ACC4
+ vpsrlq \$29, $ACC5, $TEMP2
+ vpand $AND_MASK, $ACC5, $ACC5
+ vpsrlq \$29, $ACC6, $TEMP3
+ vpermq \$0x93, $TEMP1, $TEMP1
+ vpand $AND_MASK, $ACC6, $ACC6
+ vpsrlq \$29, $ACC7, $TEMP4
+ vpermq \$0x93, $TEMP2, $TEMP2
+ vpand $AND_MASK, $ACC7, $ACC7
+ vpsrlq \$29, $ACC8, $TEMP5
+ vpermq \$0x93, $TEMP3, $TEMP3
+ vpand $AND_MASK, $ACC8, $ACC8
+ vpermq \$0x93, $TEMP4, $TEMP4
+
+ vpblendd \$3, $ZERO, $TEMP1, $TEMP0
+ vpermq \$0x93, $TEMP5, $TEMP5
+ vpblendd \$3, $TEMP1, $TEMP2, $TEMP1
+ vpaddq $TEMP0, $ACC4, $ACC4
+ vpblendd \$3, $TEMP2, $TEMP3, $TEMP2
+ vpaddq $TEMP1, $ACC5, $ACC5
+ vpblendd \$3, $TEMP3, $TEMP4, $TEMP3
+ vpaddq $TEMP2, $ACC6, $ACC6
+ vpblendd \$3, $TEMP4, $TEMP5, $TEMP4
+ vpaddq $TEMP3, $ACC7, $ACC7
+ vpaddq $TEMP4, $ACC8, $ACC8
+
+ vmovdqu $ACC4, 128-128($rp)
+ vmovdqu $ACC5, 160-128($rp)
+ vmovdqu $ACC6, 192-128($rp)
+ vmovdqu $ACC7, 224-128($rp)
+ vmovdqu $ACC8, 256-128($rp)
+ vzeroupper
+
+ mov %rbp, %rax
+___
+$code.=<<___ if ($win64);
+ movaps -0xd8(%rax),%xmm6
+ movaps -0xc8(%rax),%xmm7
+ movaps -0xb8(%rax),%xmm8
+ movaps -0xa8(%rax),%xmm9
+ movaps -0x98(%rax),%xmm10
+ movaps -0x88(%rax),%xmm11
+ movaps -0x78(%rax),%xmm12
+ movaps -0x68(%rax),%xmm13
+ movaps -0x58(%rax),%xmm14
+ movaps -0x48(%rax),%xmm15
+___
+$code.=<<___;
+ mov -48(%rax),%r15
+ mov -40(%rax),%r14
+ mov -32(%rax),%r13
+ mov -24(%rax),%r12
+ mov -16(%rax),%rbp
+ mov -8(%rax),%rbx
+ lea (%rax),%rsp # restore %rsp
+.Lmul_1024_epilogue:
+ ret
+.size rsaz_1024_mul_avx2,.-rsaz_1024_mul_avx2
+___
+}
+{
+my ($out,$inp) = $win64 ? ("%rcx","%rdx") : ("%rdi","%rsi");
+my @T = map("%r$_",(8..11));
+
+$code.=<<___;
+.globl rsaz_1024_red2norm_avx2
+.type rsaz_1024_red2norm_avx2,\@abi-omnipotent
+.align 32
+rsaz_1024_red2norm_avx2:
+ sub \$-128,$inp # size optimization
+ xor %rax,%rax
+___
+
+for ($j=0,$i=0; $i<16; $i++) {
+ my $k=0;
+ while (29*$j<64*($i+1)) { # load data till boundary
+ $code.=" mov `8*$j-128`($inp), @T[0]\n";
+ $j++; $k++; push(@T,shift(@T));
+ }
+ $l=$k;
+ while ($k>1) { # shift loaded data but last value
+ $code.=" shl \$`29*($j-$k)`,@T[-$k]\n";
+ $k--;
+ }
+ $code.=<<___; # shift last value
+ mov @T[-1], @T[0]
+ shl \$`29*($j-1)`, @T[-1]
+ shr \$`-29*($j-1)`, @T[0]
+___
+ while ($l) { # accumulate all values
+ $code.=" add @T[-$l], %rax\n";
+ $l--;
+ }
+ $code.=<<___;
+ adc \$0, @T[0] # consume eventual carry
+ mov %rax, 8*$i($out)
+ mov @T[0], %rax
+___
+ push(@T,shift(@T));
+}
+$code.=<<___;
+ ret
+.size rsaz_1024_red2norm_avx2,.-rsaz_1024_red2norm_avx2
+
+.globl rsaz_1024_norm2red_avx2
+.type rsaz_1024_norm2red_avx2,\@abi-omnipotent
+.align 32
+rsaz_1024_norm2red_avx2:
+ sub \$-128,$out # size optimization
+ mov ($inp),@T[0]
+ mov \$0x1fffffff,%eax
+___
+for ($j=0,$i=0; $i<16; $i++) {
+ $code.=" mov `8*($i+1)`($inp),@T[1]\n" if ($i<15);
+ $code.=" xor @T[1],@T[1]\n" if ($i==15);
+ my $k=1;
+ while (29*($j+1)<64*($i+1)) {
+ $code.=<<___;
+ mov @T[0],@T[-$k]
+ shr \$`29*$j`,@T[-$k]
+ and %rax,@T[-$k] # &0x1fffffff
+ mov @T[-$k],`8*$j-128`($out)
+___
+ $j++; $k++;
+ }
+ $code.=<<___;
+ shrd \$`29*$j`,@T[1],@T[0]
+ and %rax,@T[0]
+ mov @T[0],`8*$j-128`($out)
+___
+ $j++;
+ push(@T,shift(@T));
+}
+$code.=<<___;
+ mov @T[0],`8*$j-128`($out) # zero
+ mov @T[0],`8*($j+1)-128`($out)
+ mov @T[0],`8*($j+2)-128`($out)
+ mov @T[0],`8*($j+3)-128`($out)
+ ret
+.size rsaz_1024_norm2red_avx2,.-rsaz_1024_norm2red_avx2
+___
+}
+{
+my ($out,$inp,$power) = $win64 ? ("%rcx","%rdx","%r8d") : ("%rdi","%rsi","%edx");
+
+$code.=<<___;
+.globl rsaz_1024_scatter5_avx2
+.type rsaz_1024_scatter5_avx2,\@abi-omnipotent
+.align 32
+rsaz_1024_scatter5_avx2:
+ vzeroupper
+ vmovdqu .Lscatter_permd(%rip),%ymm5
+ shl \$4,$power
+ lea ($out,$power),$out
+ mov \$9,%eax
+ jmp .Loop_scatter_1024
+
+.align 32
+.Loop_scatter_1024:
+ vmovdqu ($inp),%ymm0
+ lea 32($inp),$inp
+ vpermd %ymm0,%ymm5,%ymm0
+ vmovdqu %xmm0,($out)
+ lea 16*32($out),$out
+ dec %eax
+ jnz .Loop_scatter_1024
+
+ vzeroupper
+ ret
+.size rsaz_1024_scatter5_avx2,.-rsaz_1024_scatter5_avx2
+
+.globl rsaz_1024_gather5_avx2
+.type rsaz_1024_gather5_avx2,\@abi-omnipotent
+.align 32
+rsaz_1024_gather5_avx2:
+___
+$code.=<<___ if ($win64);
+ lea -0x88(%rsp),%rax
+ vzeroupper
+.LSEH_begin_rsaz_1024_gather5:
+ # I can't trust assembler to use specific encoding:-(
+ .byte 0x48,0x8d,0x60,0xe0 #lea -0x20(%rax),%rsp
+ .byte 0xc5,0xf8,0x29,0x70,0xe0 #vmovaps %xmm6,-0x20(%rax)
+ .byte 0xc5,0xf8,0x29,0x78,0xf0 #vmovaps %xmm7,-0x10(%rax)
+ .byte 0xc5,0x78,0x29,0x40,0x00 #vmovaps %xmm8,0(%rax)
+ .byte 0xc5,0x78,0x29,0x48,0x10 #vmovaps %xmm9,0x10(%rax)
+ .byte 0xc5,0x78,0x29,0x50,0x20 #vmovaps %xmm10,0x20(%rax)
+ .byte 0xc5,0x78,0x29,0x58,0x30 #vmovaps %xmm11,0x30(%rax)
+ .byte 0xc5,0x78,0x29,0x60,0x40 #vmovaps %xmm12,0x40(%rax)
+ .byte 0xc5,0x78,0x29,0x68,0x50 #vmovaps %xmm13,0x50(%rax)
+ .byte 0xc5,0x78,0x29,0x70,0x60 #vmovaps %xmm14,0x60(%rax)
+ .byte 0xc5,0x78,0x29,0x78,0x70 #vmovaps %xmm15,0x70(%rax)
+___
+$code.=<<___;
+ lea .Lgather_table(%rip),%r11
+ mov $power,%eax
+ and \$3,$power
+ shr \$2,%eax # cache line number
+ shl \$4,$power # offset within cache line
+
+ vmovdqu -32(%r11),%ymm7 # .Lgather_permd
+ vpbroadcastb 8(%r11,%rax), %xmm8
+ vpbroadcastb 7(%r11,%rax), %xmm9
+ vpbroadcastb 6(%r11,%rax), %xmm10
+ vpbroadcastb 5(%r11,%rax), %xmm11
+ vpbroadcastb 4(%r11,%rax), %xmm12
+ vpbroadcastb 3(%r11,%rax), %xmm13
+ vpbroadcastb 2(%r11,%rax), %xmm14
+ vpbroadcastb 1(%r11,%rax), %xmm15
+
+ lea 64($inp,$power),$inp
+ mov \$64,%r11 # size optimization
+ mov \$9,%eax
+ jmp .Loop_gather_1024
+
+.align 32
+.Loop_gather_1024:
+ vpand -64($inp), %xmm8,%xmm0
+ vpand ($inp), %xmm9,%xmm1
+ vpand 64($inp), %xmm10,%xmm2
+ vpand ($inp,%r11,2), %xmm11,%xmm3
+ vpor %xmm0,%xmm1,%xmm1
+ vpand 64($inp,%r11,2), %xmm12,%xmm4
+ vpor %xmm2,%xmm3,%xmm3
+ vpand ($inp,%r11,4), %xmm13,%xmm5
+ vpor %xmm1,%xmm3,%xmm3
+ vpand 64($inp,%r11,4), %xmm14,%xmm6
+ vpor %xmm4,%xmm5,%xmm5
+ vpand -128($inp,%r11,8), %xmm15,%xmm2
+ lea ($inp,%r11,8),$inp
+ vpor %xmm3,%xmm5,%xmm5
+ vpor %xmm2,%xmm6,%xmm6
+ vpor %xmm5,%xmm6,%xmm6
+ vpermd %ymm6,%ymm7,%ymm6
+ vmovdqu %ymm6,($out)
+ lea 32($out),$out
+ dec %eax
+ jnz .Loop_gather_1024
+
+ vpxor %ymm0,%ymm0,%ymm0
+ vmovdqu %ymm0,($out)
+ vzeroupper
+___
+$code.=<<___ if ($win64);
+ movaps (%rsp),%xmm6
+ movaps 0x10(%rsp),%xmm7
+ movaps 0x20(%rsp),%xmm8
+ movaps 0x30(%rsp),%xmm9
+ movaps 0x40(%rsp),%xmm10
+ movaps 0x50(%rsp),%xmm11
+ movaps 0x60(%rsp),%xmm12
+ movaps 0x70(%rsp),%xmm13
+ movaps 0x80(%rsp),%xmm14
+ movaps 0x90(%rsp),%xmm15
+ lea 0xa8(%rsp),%rsp
+.LSEH_end_rsaz_1024_gather5:
+___
+$code.=<<___;
+ ret
+.size rsaz_1024_gather5_avx2,.-rsaz_1024_gather5_avx2
+___
+}
+
+$code.=<<___;
+.extern OPENSSL_ia32cap_P
+.globl rsaz_avx2_eligible
+.type rsaz_avx2_eligible,\@abi-omnipotent
+.align 32
+rsaz_avx2_eligible:
+ mov OPENSSL_ia32cap_P+8(%rip),%eax
+ and \$`1<<5`,%eax
+ shr \$5,%eax
+ ret
+.size rsaz_avx2_eligible,.-rsaz_avx2_eligible
+
+.align 64
+.Land_mask:
+ .quad 0x1fffffff,0x1fffffff,0x1fffffff,-1
+.Lscatter_permd:
+ .long 0,2,4,6,7,7,7,7
+.Lgather_permd:
+ .long 0,7,1,7,2,7,3,7
+.Lgather_table:
+ .byte 0,0,0,0,0,0,0,0, 0xff,0,0,0,0,0,0,0
+.align 64
+___
+
+if ($win64) {
+$rec="%rcx";
+$frame="%rdx";
+$context="%r8";
+$disp="%r9";
+
+$code.=<<___
+.extern __imp_RtlVirtualUnwind
+.type rsaz_se_handler,\@abi-omnipotent
+.align 16
+rsaz_se_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 120($context),%rax # pull context->Rax
+ mov 248($context),%rbx # pull context->Rip
+
+ mov 8($disp),%rsi # disp->ImageBase
+ mov 56($disp),%r11 # disp->HandlerData
+
+ mov 0(%r11),%r10d # HandlerData[0]
+ lea (%rsi,%r10),%r10 # prologue label
+ cmp %r10,%rbx # context->Rip<prologue label
+ jb .Lcommon_seh_tail
+
+ mov 152($context),%rax # pull context->Rsp
+
+ mov 4(%r11),%r10d # HandlerData[1]
+ lea (%rsi,%r10),%r10 # epilogue label
+ cmp %r10,%rbx # context->Rip>=epilogue label
+ jae .Lcommon_seh_tail
+
+ mov 160($context),%rax # pull context->Rbp
+
+ mov -48(%rax),%r15
+ mov -40(%rax),%r14
+ mov -32(%rax),%r13
+ mov -24(%rax),%r12
+ mov -16(%rax),%rbp
+ mov -8(%rax),%rbx
+ mov %r15,240($context)
+ mov %r14,232($context)
+ mov %r13,224($context)
+ mov %r12,216($context)
+ mov %rbp,160($context)
+ mov %rbx,144($context)
+
+ lea -0xd8(%rax),%rsi # %xmm save area
+ lea 512($context),%rdi # & context.Xmm6
+ mov \$20,%ecx # 10*sizeof(%xmm0)/sizeof(%rax)
+ .long 0xa548f3fc # cld; rep movsq
+
+.Lcommon_seh_tail:
+ mov 8(%rax),%rdi
+ mov 16(%rax),%rsi
+ mov %rax,152($context) # restore context->Rsp
+ mov %rsi,168($context) # restore context->Rsi
+ mov %rdi,176($context) # restore context->Rdi
+
+ mov 40($disp),%rdi # disp->ContextRecord
+ mov $context,%rsi # context
+ mov \$154,%ecx # sizeof(CONTEXT)
+ .long 0xa548f3fc # cld; rep movsq
+
+ mov $disp,%rsi
+ xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER
+ mov 8(%rsi),%rdx # arg2, disp->ImageBase
+ mov 0(%rsi),%r8 # arg3, disp->ControlPc
+ mov 16(%rsi),%r9 # arg4, disp->FunctionEntry
+ mov 40(%rsi),%r10 # disp->ContextRecord
+ lea 56(%rsi),%r11 # &disp->HandlerData
+ lea 24(%rsi),%r12 # &disp->EstablisherFrame
+ mov %r10,32(%rsp) # arg5
+ mov %r11,40(%rsp) # arg6
+ mov %r12,48(%rsp) # arg7
+ mov %rcx,56(%rsp) # arg8, (NULL)
+ call *__imp_RtlVirtualUnwind(%rip)
+
+ mov \$1,%eax # ExceptionContinueSearch
+ add \$64,%rsp
+ popfq
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+ pop %rdi
+ pop %rsi
+ ret
+.size rsaz_se_handler,.-rsaz_se_handler
+
+.section .pdata
+.align 4
+ .rva .LSEH_begin_rsaz_1024_sqr_avx2
+ .rva .LSEH_end_rsaz_1024_sqr_avx2
+ .rva .LSEH_info_rsaz_1024_sqr_avx2
+
+ .rva .LSEH_begin_rsaz_1024_mul_avx2
+ .rva .LSEH_end_rsaz_1024_mul_avx2
+ .rva .LSEH_info_rsaz_1024_mul_avx2
+
+ .rva .LSEH_begin_rsaz_1024_gather5
+ .rva .LSEH_end_rsaz_1024_gather5
+ .rva .LSEH_info_rsaz_1024_gather5
+.section .xdata
+.align 8
+.LSEH_info_rsaz_1024_sqr_avx2:
+ .byte 9,0,0,0
+ .rva rsaz_se_handler
+ .rva .Lsqr_1024_body,.Lsqr_1024_epilogue
+.LSEH_info_rsaz_1024_mul_avx2:
+ .byte 9,0,0,0
+ .rva rsaz_se_handler
+ .rva .Lmul_1024_body,.Lmul_1024_epilogue
+.LSEH_info_rsaz_1024_gather5:
+ .byte 0x01,0x33,0x16,0x00
+ .byte 0x36,0xf8,0x09,0x00 #vmovaps 0x90(rsp),xmm15
+ .byte 0x31,0xe8,0x08,0x00 #vmovaps 0x80(rsp),xmm14
+ .byte 0x2c,0xd8,0x07,0x00 #vmovaps 0x70(rsp),xmm13
+ .byte 0x27,0xc8,0x06,0x00 #vmovaps 0x60(rsp),xmm12
+ .byte 0x22,0xb8,0x05,0x00 #vmovaps 0x50(rsp),xmm11
+ .byte 0x1d,0xa8,0x04,0x00 #vmovaps 0x40(rsp),xmm10
+ .byte 0x18,0x98,0x03,0x00 #vmovaps 0x30(rsp),xmm9
+ .byte 0x13,0x88,0x02,0x00 #vmovaps 0x20(rsp),xmm8
+ .byte 0x0e,0x78,0x01,0x00 #vmovaps 0x10(rsp),xmm7
+ .byte 0x09,0x68,0x00,0x00 #vmovaps 0x00(rsp),xmm6
+ .byte 0x04,0x01,0x15,0x00 #sub rsp,0xa8
+___
+}
+
+foreach (split("\n",$code)) {
+ s/\`([^\`]*)\`/eval($1)/ge;
+
+ s/\b(sh[rl]d?\s+\$)(-?[0-9]+)/$1.$2%64/ge or
+
+ s/\b(vmov[dq])\b(.+)%ymm([0-9]+)/$1$2%xmm$3/go or
+ s/\b(vmovdqu)\b(.+)%x%ymm([0-9]+)/$1$2%xmm$3/go or
+ s/\b(vpinsr[qd])\b(.+)%ymm([0-9]+)/$1$2%xmm$3/go or
+ s/\b(vpextr[qd])\b(.+)%ymm([0-9]+)/$1$2%xmm$3/go or
+ s/\b(vpbroadcast[qd]\s+)%ymm([0-9]+)/$1%xmm$2/go;
+ print $_,"\n";
+}
+
+}}} else {{{
+print <<___; # assembler is too old
+.text
+
+.globl rsaz_avx2_eligible
+.type rsaz_avx2_eligible,\@abi-omnipotent
+rsaz_avx2_eligible:
+ xor %eax,%eax
+ ret
+.size rsaz_avx2_eligible,.-rsaz_avx2_eligible
+
+.globl rsaz_1024_sqr_avx2
+.globl rsaz_1024_mul_avx2
+.globl rsaz_1024_norm2red_avx2
+.globl rsaz_1024_red2norm_avx2
+.globl rsaz_1024_scatter5_avx2
+.globl rsaz_1024_gather5_avx2
+.type rsaz_1024_sqr_avx2,\@abi-omnipotent
+rsaz_1024_sqr_avx2:
+rsaz_1024_mul_avx2:
+rsaz_1024_norm2red_avx2:
+rsaz_1024_red2norm_avx2:
+rsaz_1024_scatter5_avx2:
+rsaz_1024_gather5_avx2:
+ .byte 0x0f,0x0b # ud2
+ ret
+.size rsaz_1024_sqr_avx2,.-rsaz_1024_sqr_avx2
+___
+}}}
+
+close STDOUT;
diff --git a/crypto/bn/asm/rsaz-x86_64.pl b/crypto/bn/asm/rsaz-x86_64.pl
new file mode 100644
index 0000000..120b473
--- /dev/null
+++ b/crypto/bn/asm/rsaz-x86_64.pl
@@ -0,0 +1,2139 @@
+#!/usr/bin/env perl
+
+##############################################################################
+# #
+# 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. #
+# #
+##############################################################################
+# Developers and authors: #
+# Shay Gueron (1, 2), and Vlad Krasnov (1) #
+# (1) Intel Architecture Group, Microprocessor and Chipset Development, #
+# Israel Development Center, Haifa, Israel #
+# (2) University of Haifa #
+##############################################################################
+# Reference: #
+# [1] S. Gueron, "Efficient Software Implementations of Modular #
+# Exponentiation", http://eprint.iacr.org/2011/239 #
+# [2] S. Gueron, V. Krasnov. "Speeding up Big-Numbers Squaring". #
+# IEEE Proceedings of 9th International Conference on Information #
+# Technology: New Generations (ITNG 2012), 821-823 (2012). #
+# [3] S. Gueron, Efficient Software Implementations of Modular Exponentiation#
+# Journal of Cryptographic Engineering 2:31-43 (2012). #
+# [4] S. Gueron, V. Krasnov: "[PATCH] Efficient and side channel analysis #
+# resistant 512-bit and 1024-bit modular exponentiation for optimizing #
+# RSA1024 and RSA2048 on x86_64 platforms", #
+# http://rt.openssl.org/Ticket/Display.html?id=2582&user=guest&pass=guest#
+##############################################################################
+
+# While original submission covers 512- and 1024-bit exponentiation,
+# this module is limited to 512-bit version only (and as such
+# accelerates RSA1024 sign). This is because improvement for longer
+# keys is not high enough to justify the effort, highest measured
+# was ~5% on Westmere. [This is relative to OpenSSL 1.0.2, upcoming
+# for the moment of this writing!] Nor does this module implement
+# "monolithic" complete exponentiation jumbo-subroutine, but adheres
+# to more modular mixture of C and assembly. And it's optimized even
+# for processors other than Intel Core family (see table below for
+# improvement coefficients).
+# <appro@openssl.org>
+#
+# RSA1024 sign/sec this/original |this/rsax(*) this/fips(*)
+# ----------------+---------------------------
+# Opteron +13% |+5% +20%
+# Bulldozer -0% |-1% +10%
+# P4 +11% |+7% +8%
+# Westmere +5% |+14% +17%
+# Sandy Bridge +2% |+12% +29%
+# Ivy Bridge +1% |+11% +35%
+# Haswell(**) -0% |+12% +39%
+# Atom +13% |+11% +4%
+# VIA Nano +70% |+9% +25%
+#
+# (*) rsax engine and fips numbers are presented for reference
+# purposes;
+# (**) MULX was attempted, but found to give only marginal improvement;
+
+$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;
+
+if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
+ =~ /GNU assembler version ([2-9]\.[0-9]+)/) {
+ $addx = ($1>=2.23);
+}
+
+if (!$addx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
+ `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
+ $addx = ($1>=2.10);
+}
+
+if (!$addx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
+ `ml64 2>&1` =~ /Version ([0-9]+)\./) {
+ $addx = ($1>=11);
+}
+
+($out, $inp, $mod) = ("%rdi", "%rsi", "%rbp"); # common internal API
+{
+my ($out,$inp,$mod,$n0,$times) = ("%rdi","%rsi","%rdx","%rcx","%r8d");
+
+$code.=<<___;
+.text
+
+.extern OPENSSL_ia32cap_P
+
+.globl rsaz_512_sqr
+.type rsaz_512_sqr,\@function,5
+.align 32
+rsaz_512_sqr: # 25-29% faster than rsaz_512_mul
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+
+ subq \$128+24, %rsp
+.Lsqr_body:
+ movq $mod, %rbp # common argument
+ movq ($inp), %rdx
+ movq 8($inp), %rax
+ movq $n0, 128(%rsp)
+___
+$code.=<<___ if ($addx);
+ movl \$0x80100,%r11d
+ andl OPENSSL_ia32cap_P+8(%rip),%r11d
+ cmpl \$0x80100,%r11d # check for MULX and ADO/CX
+ je .Loop_sqrx
+___
+$code.=<<___;
+ jmp .Loop_sqr
+
+.align 32
+.Loop_sqr:
+ movl $times,128+8(%rsp)
+#first iteration
+ movq %rdx, %rbx
+ mulq %rdx
+ movq %rax, %r8
+ movq 16($inp), %rax
+ movq %rdx, %r9
+
+ mulq %rbx
+ addq %rax, %r9
+ movq 24($inp), %rax
+ movq %rdx, %r10
+ adcq \$0, %r10
+
+ mulq %rbx
+ addq %rax, %r10
+ movq 32($inp), %rax
+ movq %rdx, %r11
+ adcq \$0, %r11
+
+ mulq %rbx
+ addq %rax, %r11
+ movq 40($inp), %rax
+ movq %rdx, %r12
+ adcq \$0, %r12
+
+ mulq %rbx
+ addq %rax, %r12
+ movq 48($inp), %rax
+ movq %rdx, %r13
+ adcq \$0, %r13
+
+ mulq %rbx
+ addq %rax, %r13
+ movq 56($inp), %rax
+ movq %rdx, %r14
+ adcq \$0, %r14
+
+ mulq %rbx
+ addq %rax, %r14
+ movq %rbx, %rax
+ movq %rdx, %r15
+ adcq \$0, %r15
+
+ addq %r8, %r8 #shlq \$1, %r8
+ movq %r9, %rcx
+ adcq %r9, %r9 #shld \$1, %r8, %r9
+
+ mulq %rax
+ movq %rax, (%rsp)
+ addq %rdx, %r8
+ adcq \$0, %r9
+
+ movq %r8, 8(%rsp)
+ shrq \$63, %rcx
+
+#second iteration
+ movq 8($inp), %r8
+ movq 16($inp), %rax
+ mulq %r8
+ addq %rax, %r10
+ movq 24($inp), %rax
+ movq %rdx, %rbx
+ adcq \$0, %rbx
+
+ mulq %r8
+ addq %rax, %r11
+ movq 32($inp), %rax
+ adcq \$0, %rdx
+ addq %rbx, %r11
+ movq %rdx, %rbx
+ adcq \$0, %rbx
+
+ mulq %r8
+ addq %rax, %r12
+ movq 40($inp), %rax
+ adcq \$0, %rdx
+ addq %rbx, %r12
+ movq %rdx, %rbx
+ adcq \$0, %rbx
+
+ mulq %r8
+ addq %rax, %r13
+ movq 48($inp), %rax
+ adcq \$0, %rdx
+ addq %rbx, %r13
+ movq %rdx, %rbx
+ adcq \$0, %rbx
+
+ mulq %r8
+ addq %rax, %r14
+ movq 56($inp), %rax
+ adcq \$0, %rdx
+ addq %rbx, %r14
+ movq %rdx, %rbx
+ adcq \$0, %rbx
+
+ mulq %r8
+ addq %rax, %r15
+ movq %r8, %rax
+ adcq \$0, %rdx
+ addq %rbx, %r15
+ movq %rdx, %r8
+ movq %r10, %rdx
+ adcq \$0, %r8
+
+ add %rdx, %rdx
+ lea (%rcx,%r10,2), %r10 #shld \$1, %rcx, %r10
+ movq %r11, %rbx
+ adcq %r11, %r11 #shld \$1, %r10, %r11
+
+ mulq %rax
+ addq %rax, %r9
+ adcq %rdx, %r10
+ adcq \$0, %r11
+
+ movq %r9, 16(%rsp)
+ movq %r10, 24(%rsp)
+ shrq \$63, %rbx
+
+#third iteration
+ movq 16($inp), %r9
+ movq 24($inp), %rax
+ mulq %r9
+ addq %rax, %r12
+ movq 32($inp), %rax
+ movq %rdx, %rcx
+ adcq \$0, %rcx
+
+ mulq %r9
+ addq %rax, %r13
+ movq 40($inp), %rax
+ adcq \$0, %rdx
+ addq %rcx, %r13
+ movq %rdx, %rcx
+ adcq \$0, %rcx
+
+ mulq %r9
+ addq %rax, %r14
+ movq 48($inp), %rax
+ adcq \$0, %rdx
+ addq %rcx, %r14
+ movq %rdx, %rcx
+ adcq \$0, %rcx
+
+ mulq %r9
+ movq %r12, %r10
+ lea (%rbx,%r12,2), %r12 #shld \$1, %rbx, %r12
+ addq %rax, %r15
+ movq 56($inp), %rax
+ adcq \$0, %rdx
+ addq %rcx, %r15
+ movq %rdx, %rcx
+ adcq \$0, %rcx
+
+ mulq %r9
+ shrq \$63, %r10
+ addq %rax, %r8
+ movq %r9, %rax
+ adcq \$0, %rdx
+ addq %rcx, %r8
+ movq %rdx, %r9
+ adcq \$0, %r9
+
+ movq %r13, %rcx
+ leaq (%r10,%r13,2), %r13 #shld \$1, %r12, %r13
+
+ mulq %rax
+ addq %rax, %r11
+ adcq %rdx, %r12
+ adcq \$0, %r13
+
+ movq %r11, 32(%rsp)
+ movq %r12, 40(%rsp)
+ shrq \$63, %rcx
+
+#fourth iteration
+ movq 24($inp), %r10
+ movq 32($inp), %rax
+ mulq %r10
+ addq %rax, %r14
+ movq 40($inp), %rax
+ movq %rdx, %rbx
+ adcq \$0, %rbx
+
+ mulq %r10
+ addq %rax, %r15
+ movq 48($inp), %rax
+ adcq \$0, %rdx
+ addq %rbx, %r15
+ movq %rdx, %rbx
+ adcq \$0, %rbx
+
+ mulq %r10
+ movq %r14, %r12
+ leaq (%rcx,%r14,2), %r14 #shld \$1, %rcx, %r14
+ addq %rax, %r8
+ movq 56($inp), %rax
+ adcq \$0, %rdx
+ addq %rbx, %r8
+ movq %rdx, %rbx
+ adcq \$0, %rbx
+
+ mulq %r10
+ shrq \$63, %r12
+ addq %rax, %r9
+ movq %r10, %rax
+ adcq \$0, %rdx
+ addq %rbx, %r9
+ movq %rdx, %r10
+ adcq \$0, %r10
+
+ movq %r15, %rbx
+ leaq (%r12,%r15,2),%r15 #shld \$1, %r14, %r15
+
+ mulq %rax
+ addq %rax, %r13
+ adcq %rdx, %r14
+ adcq \$0, %r15
+
+ movq %r13, 48(%rsp)
+ movq %r14, 56(%rsp)
+ shrq \$63, %rbx
+
+#fifth iteration
+ movq 32($inp), %r11
+ movq 40($inp), %rax
+ mulq %r11
+ addq %rax, %r8
+ movq 48($inp), %rax
+ movq %rdx, %rcx
+ adcq \$0, %rcx
+
+ mulq %r11
+ addq %rax, %r9
+ movq 56($inp), %rax
+ adcq \$0, %rdx
+ movq %r8, %r12
+ leaq (%rbx,%r8,2), %r8 #shld \$1, %rbx, %r8
+ addq %rcx, %r9
+ movq %rdx, %rcx
+ adcq \$0, %rcx
+
+ mulq %r11
+ shrq \$63, %r12
+ addq %rax, %r10
+ movq %r11, %rax
+ adcq \$0, %rdx
+ addq %rcx, %r10
+ movq %rdx, %r11
+ adcq \$0, %r11
+
+ movq %r9, %rcx
+ leaq (%r12,%r9,2), %r9 #shld \$1, %r8, %r9
+
+ mulq %rax
+ addq %rax, %r15
+ adcq %rdx, %r8
+ adcq \$0, %r9
+
+ movq %r15, 64(%rsp)
+ movq %r8, 72(%rsp)
+ shrq \$63, %rcx
+
+#sixth iteration
+ movq 40($inp), %r12
+ movq 48($inp), %rax
+ mulq %r12
+ addq %rax, %r10
+ movq 56($inp), %rax
+ movq %rdx, %rbx
+ adcq \$0, %rbx
+
+ mulq %r12
+ addq %rax, %r11
+ movq %r12, %rax
+ movq %r10, %r15
+ leaq (%rcx,%r10,2), %r10 #shld \$1, %rcx, %r10
+ adcq \$0, %rdx
+ shrq \$63, %r15
+ addq %rbx, %r11
+ movq %rdx, %r12
+ adcq \$0, %r12
+
+ movq %r11, %rbx
+ leaq (%r15,%r11,2), %r11 #shld \$1, %r10, %r11
+
+ mulq %rax
+ addq %rax, %r9
+ adcq %rdx, %r10
+ adcq \$0, %r11
+
+ movq %r9, 80(%rsp)
+ movq %r10, 88(%rsp)
+
+#seventh iteration
+ movq 48($inp), %r13
+ movq 56($inp), %rax
+ mulq %r13
+ addq %rax, %r12
+ movq %r13, %rax
+ movq %rdx, %r13
+ adcq \$0, %r13
+
+ xorq %r14, %r14
+ shlq \$1, %rbx
+ adcq %r12, %r12 #shld \$1, %rbx, %r12
+ adcq %r13, %r13 #shld \$1, %r12, %r13
+ adcq %r14, %r14 #shld \$1, %r13, %r14
+
+ mulq %rax
+ addq %rax, %r11
+ adcq %rdx, %r12
+ adcq \$0, %r13
+
+ movq %r11, 96(%rsp)
+ movq %r12, 104(%rsp)
+
+#eighth iteration
+ movq 56($inp), %rax
+ mulq %rax
+ addq %rax, %r13
+ adcq \$0, %rdx
+
+ addq %rdx, %r14
+
+ movq %r13, 112(%rsp)
+ movq %r14, 120(%rsp)
+
+ movq (%rsp), %r8
+ movq 8(%rsp), %r9
+ movq 16(%rsp), %r10
+ movq 24(%rsp), %r11
+ movq 32(%rsp), %r12
+ movq 40(%rsp), %r13
+ movq 48(%rsp), %r14
+ movq 56(%rsp), %r15
+
+ call __rsaz_512_reduce
+
+ addq 64(%rsp), %r8
+ adcq 72(%rsp), %r9
+ adcq 80(%rsp), %r10
+ adcq 88(%rsp), %r11
+ adcq 96(%rsp), %r12
+ adcq 104(%rsp), %r13
+ adcq 112(%rsp), %r14
+ adcq 120(%rsp), %r15
+ sbbq %rcx, %rcx
+
+ call __rsaz_512_subtract
+
+ movq %r8, %rdx
+ movq %r9, %rax
+ movl 128+8(%rsp), $times
+ movq $out, $inp
+
+ decl $times
+ jnz .Loop_sqr
+___
+if ($addx) {
+$code.=<<___;
+ jmp .Lsqr_tail
+
+.align 32
+.Loop_sqrx:
+ movl $times,128+8(%rsp)
+ movq $out, %xmm0 # off-load
+ movq %rbp, %xmm1 # off-load
+#first iteration
+ mulx %rax, %r8, %r9
+
+ mulx 16($inp), %rcx, %r10
+ xor %rbp, %rbp # cf=0, of=0
+
+ mulx 24($inp), %rax, %r11
+ adcx %rcx, %r9
+
+ mulx 32($inp), %rcx, %r12
+ adcx %rax, %r10
+
+ mulx 40($inp), %rax, %r13
+ adcx %rcx, %r11
+
+ .byte 0xc4,0x62,0xf3,0xf6,0xb6,0x30,0x00,0x00,0x00 # mulx 48($inp), %rcx, %r14
+ adcx %rax, %r12
+ adcx %rcx, %r13
+
+ .byte 0xc4,0x62,0xfb,0xf6,0xbe,0x38,0x00,0x00,0x00 # mulx 56($inp), %rax, %r15
+ adcx %rax, %r14
+ adcx %rbp, %r15 # %rbp is 0
+
+ mov %r9, %rcx
+ shld \$1, %r8, %r9
+ shl \$1, %r8
+
+ xor %ebp, %ebp
+ mulx %rdx, %rax, %rdx
+ adcx %rdx, %r8
+ mov 8($inp), %rdx
+ adcx %rbp, %r9
+
+ mov %rax, (%rsp)
+ mov %r8, 8(%rsp)
+
+#second iteration
+ mulx 16($inp), %rax, %rbx
+ adox %rax, %r10
+ adcx %rbx, %r11
+
+ .byte 0xc4,0x62,0xc3,0xf6,0x86,0x18,0x00,0x00,0x00 # mulx 24($inp), $out, %r8
+ adox $out, %r11
+ adcx %r8, %r12
+
+ mulx 32($inp), %rax, %rbx
+ adox %rax, %r12
+ adcx %rbx, %r13
+
+ mulx 40($inp), $out, %r8
+ adox $out, %r13
+ adcx %r8, %r14
+
+ .byte 0xc4,0xe2,0xfb,0xf6,0x9e,0x30,0x00,0x00,0x00 # mulx 48($inp), %rax, %rbx
+ adox %rax, %r14
+ adcx %rbx, %r15
+
+ .byte 0xc4,0x62,0xc3,0xf6,0x86,0x38,0x00,0x00,0x00 # mulx 56($inp), $out, %r8
+ adox $out, %r15
+ adcx %rbp, %r8
+ adox %rbp, %r8
+
+ mov %r11, %rbx
+ shld \$1, %r10, %r11
+ shld \$1, %rcx, %r10
+
+ xor %ebp,%ebp
+ mulx %rdx, %rax, %rcx
+ mov 16($inp), %rdx
+ adcx %rax, %r9
+ adcx %rcx, %r10
+ adcx %rbp, %r11
+
+ mov %r9, 16(%rsp)
+ .byte 0x4c,0x89,0x94,0x24,0x18,0x00,0x00,0x00 # mov %r10, 24(%rsp)
+
+#third iteration
+ .byte 0xc4,0x62,0xc3,0xf6,0x8e,0x18,0x00,0x00,0x00 # mulx 24($inp), $out, %r9
+ adox $out, %r12
+ adcx %r9, %r13
+
+ mulx 32($inp), %rax, %rcx
+ adox %rax, %r13
+ adcx %rcx, %r14
+
+ mulx 40($inp), $out, %r9
+ adox $out, %r14
+ adcx %r9, %r15
+
+ .byte 0xc4,0xe2,0xfb,0xf6,0x8e,0x30,0x00,0x00,0x00 # mulx 48($inp), %rax, %rcx
+ adox %rax, %r15
+ adcx %rcx, %r8
+
+ .byte 0xc4,0x62,0xc3,0xf6,0x8e,0x38,0x00,0x00,0x00 # mulx 56($inp), $out, %r9
+ adox $out, %r8
+ adcx %rbp, %r9
+ adox %rbp, %r9
+
+ mov %r13, %rcx
+ shld \$1, %r12, %r13
+ shld \$1, %rbx, %r12
+
+ xor %ebp, %ebp
+ mulx %rdx, %rax, %rdx
+ adcx %rax, %r11
+ adcx %rdx, %r12
+ mov 24($inp), %rdx
+ adcx %rbp, %r13
+
+ mov %r11, 32(%rsp)
+ .byte 0x4c,0x89,0xa4,0x24,0x28,0x00,0x00,0x00 # mov %r12, 40(%rsp)
+
+#fourth iteration
+ .byte 0xc4,0xe2,0xfb,0xf6,0x9e,0x20,0x00,0x00,0x00 # mulx 32($inp), %rax, %rbx
+ adox %rax, %r14
+ adcx %rbx, %r15
+
+ mulx 40($inp), $out, %r10
+ adox $out, %r15
+ adcx %r10, %r8
+
+ mulx 48($inp), %rax, %rbx
+ adox %rax, %r8
+ adcx %rbx, %r9
+
+ mulx 56($inp), $out, %r10
+ adox $out, %r9
+ adcx %rbp, %r10
+ adox %rbp, %r10
+
+ .byte 0x66
+ mov %r15, %rbx
+ shld \$1, %r14, %r15
+ shld \$1, %rcx, %r14
+
+ xor %ebp, %ebp
+ mulx %rdx, %rax, %rdx
+ adcx %rax, %r13
+ adcx %rdx, %r14
+ mov 32($inp), %rdx
+ adcx %rbp, %r15
+
+ mov %r13, 48(%rsp)
+ mov %r14, 56(%rsp)
+
+#fifth iteration
+ .byte 0xc4,0x62,0xc3,0xf6,0x9e,0x28,0x00,0x00,0x00 # mulx 40($inp), $out, %r11
+ adox $out, %r8
+ adcx %r11, %r9
+
+ mulx 48($inp), %rax, %rcx
+ adox %rax, %r9
+ adcx %rcx, %r10
+
+ mulx 56($inp), $out, %r11
+ adox $out, %r10
+ adcx %rbp, %r11
+ adox %rbp, %r11
+
+ mov %r9, %rcx
+ shld \$1, %r8, %r9
+ shld \$1, %rbx, %r8
+
+ xor %ebp, %ebp
+ mulx %rdx, %rax, %rdx
+ adcx %rax, %r15
+ adcx %rdx, %r8
+ mov 40($inp), %rdx
+ adcx %rbp, %r9
+
+ mov %r15, 64(%rsp)
+ mov %r8, 72(%rsp)
+
+#sixth iteration
+ .byte 0xc4,0xe2,0xfb,0xf6,0x9e,0x30,0x00,0x00,0x00 # mulx 48($inp), %rax, %rbx
+ adox %rax, %r10
+ adcx %rbx, %r11
+
+ .byte 0xc4,0x62,0xc3,0xf6,0xa6,0x38,0x00,0x00,0x00 # mulx 56($inp), $out, %r12
+ adox $out, %r11
+ adcx %rbp, %r12
+ adox %rbp, %r12
+
+ mov %r11, %rbx
+ shld \$1, %r10, %r11
+ shld \$1, %rcx, %r10
+
+ xor %ebp, %ebp
+ mulx %rdx, %rax, %rdx
+ adcx %rax, %r9
+ adcx %rdx, %r10
+ mov 48($inp), %rdx
+ adcx %rbp, %r11
+
+ mov %r9, 80(%rsp)
+ mov %r10, 88(%rsp)
+
+#seventh iteration
+ .byte 0xc4,0x62,0xfb,0xf6,0xae,0x38,0x00,0x00,0x00 # mulx 56($inp), %rax, %r13
+ adox %rax, %r12
+ adox %rbp, %r13
+
+ xor %r14, %r14
+ shld \$1, %r13, %r14
+ shld \$1, %r12, %r13
+ shld \$1, %rbx, %r12
+
+ xor %ebp, %ebp
+ mulx %rdx, %rax, %rdx
+ adcx %rax, %r11
+ adcx %rdx, %r12
+ mov 56($inp), %rdx
+ adcx %rbp, %r13
+
+ .byte 0x4c,0x89,0x9c,0x24,0x60,0x00,0x00,0x00 # mov %r11, 96(%rsp)
+ .byte 0x4c,0x89,0xa4,0x24,0x68,0x00,0x00,0x00 # mov %r12, 104(%rsp)
+
+#eighth iteration
+ mulx %rdx, %rax, %rdx
+ adox %rax, %r13
+ adox %rbp, %rdx
+
+ .byte 0x66
+ add %rdx, %r14
+
+ movq %r13, 112(%rsp)
+ movq %r14, 120(%rsp)
+ movq %xmm0, $out
+ movq %xmm1, %rbp
+
+ movq 128(%rsp), %rdx # pull $n0
+ movq (%rsp), %r8
+ movq 8(%rsp), %r9
+ movq 16(%rsp), %r10
+ movq 24(%rsp), %r11
+ movq 32(%rsp), %r12
+ movq 40(%rsp), %r13
+ movq 48(%rsp), %r14
+ movq 56(%rsp), %r15
+
+ call __rsaz_512_reducex
+
+ addq 64(%rsp), %r8
+ adcq 72(%rsp), %r9
+ adcq 80(%rsp), %r10
+ adcq 88(%rsp), %r11
+ adcq 96(%rsp), %r12
+ adcq 104(%rsp), %r13
+ adcq 112(%rsp), %r14
+ adcq 120(%rsp), %r15
+ sbbq %rcx, %rcx
+
+ call __rsaz_512_subtract
+
+ movq %r8, %rdx
+ movq %r9, %rax
+ movl 128+8(%rsp), $times
+ movq $out, $inp
+
+ decl $times
+ jnz .Loop_sqrx
+
+.Lsqr_tail:
+___
+}
+$code.=<<___;
+
+ leaq 128+24+48(%rsp), %rax
+ movq -48(%rax), %r15
+ movq -40(%rax), %r14
+ movq -32(%rax), %r13
+ movq -24(%rax), %r12
+ movq -16(%rax), %rbp
+ movq -8(%rax), %rbx
+ leaq (%rax), %rsp
+.Lsqr_epilogue:
+ ret
+.size rsaz_512_sqr,.-rsaz_512_sqr
+___
+}
+{
+my ($out,$ap,$bp,$mod,$n0) = ("%rdi","%rsi","%rdx","%rcx","%r8");
+$code.=<<___;
+.globl rsaz_512_mul
+.type rsaz_512_mul,\@function,5
+.align 32
+rsaz_512_mul:
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+
+ subq \$128+24, %rsp
+.Lmul_body:
+ movq $out, %xmm0 # off-load arguments
+ movq $mod, %xmm1
+ movq $n0, 128(%rsp)
+___
+$code.=<<___ if ($addx);
+ movl \$0x80100,%r11d
+ andl OPENSSL_ia32cap_P+8(%rip),%r11d
+ cmpl \$0x80100,%r11d # check for MULX and ADO/CX
+ je .Lmulx
+___
+$code.=<<___;
+ movq ($bp), %rbx # pass b[0]
+ movq $bp, %rbp # pass argument
+ call __rsaz_512_mul
+
+ movq %xmm0, $out
+ movq %xmm1, %rbp
+
+ movq (%rsp), %r8
+ movq 8(%rsp), %r9
+ movq 16(%rsp), %r10
+ movq 24(%rsp), %r11
+ movq 32(%rsp), %r12
+ movq 40(%rsp), %r13
+ movq 48(%rsp), %r14
+ movq 56(%rsp), %r15
+
+ call __rsaz_512_reduce
+___
+$code.=<<___ if ($addx);
+ jmp .Lmul_tail
+
+.align 32
+.Lmulx:
+ movq $bp, %rbp # pass argument
+ movq ($bp), %rdx # pass b[0]
+ call __rsaz_512_mulx
+
+ movq %xmm0, $out
+ movq %xmm1, %rbp
+
+ movq 128(%rsp), %rdx # pull $n0
+ movq (%rsp), %r8
+ movq 8(%rsp), %r9
+ movq 16(%rsp), %r10
+ movq 24(%rsp), %r11
+ movq 32(%rsp), %r12
+ movq 40(%rsp), %r13
+ movq 48(%rsp), %r14
+ movq 56(%rsp), %r15
+
+ call __rsaz_512_reducex
+.Lmul_tail:
+___
+$code.=<<___;
+ addq 64(%rsp), %r8
+ adcq 72(%rsp), %r9
+ adcq 80(%rsp), %r10
+ adcq 88(%rsp), %r11
+ adcq 96(%rsp), %r12
+ adcq 104(%rsp), %r13
+ adcq 112(%rsp), %r14
+ adcq 120(%rsp), %r15
+ sbbq %rcx, %rcx
+
+ call __rsaz_512_subtract
+
+ leaq 128+24+48(%rsp), %rax
+ movq -48(%rax), %r15
+ movq -40(%rax), %r14
+ movq -32(%rax), %r13
+ movq -24(%rax), %r12
+ movq -16(%rax), %rbp
+ movq -8(%rax), %rbx
+ leaq (%rax), %rsp
+.Lmul_epilogue:
+ ret
+.size rsaz_512_mul,.-rsaz_512_mul
+___
+}
+{
+my ($out,$ap,$bp,$mod,$n0,$pwr) = ("%rdi","%rsi","%rdx","%rcx","%r8","%r9d");
+$code.=<<___;
+.globl rsaz_512_mul_gather4
+.type rsaz_512_mul_gather4,\@function,6
+.align 32
+rsaz_512_mul_gather4:
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+
+ mov $pwr, $pwr
+ subq \$128+24, %rsp
+.Lmul_gather4_body:
+___
+$code.=<<___ if ($addx);
+ movl \$0x80100,%r11d
+ andl OPENSSL_ia32cap_P+8(%rip),%r11d
+ cmpl \$0x80100,%r11d # check for MULX and ADO/CX
+ je .Lmulx_gather
+___
+$code.=<<___;
+ movl 64($bp,$pwr,4), %eax
+ movq $out, %xmm0 # off-load arguments
+ movl ($bp,$pwr,4), %ebx
+ movq $mod, %xmm1
+ movq $n0, 128(%rsp)
+
+ shlq \$32, %rax
+ or %rax, %rbx
+ movq ($ap), %rax
+ movq 8($ap), %rcx
+ leaq 128($bp,$pwr,4), %rbp
+ mulq %rbx # 0 iteration
+ movq %rax, (%rsp)
+ movq %rcx, %rax
+ movq %rdx, %r8
+
+ mulq %rbx
+ movd (%rbp), %xmm4
+ addq %rax, %r8
+ movq 16($ap), %rax
+ movq %rdx, %r9
+ adcq \$0, %r9
+
+ mulq %rbx
+ movd 64(%rbp), %xmm5
+ addq %rax, %r9
+ movq 24($ap), %rax
+ movq %rdx, %r10
+ adcq \$0, %r10
+
+ mulq %rbx
+ pslldq \$4, %xmm5
+ addq %rax, %r10
+ movq 32($ap), %rax
+ movq %rdx, %r11
+ adcq \$0, %r11
+
+ mulq %rbx
+ por %xmm5, %xmm4
+ addq %rax, %r11
+ movq 40($ap), %rax
+ movq %rdx, %r12
+ adcq \$0, %r12
+
+ mulq %rbx
+ addq %rax, %r12
+ movq 48($ap), %rax
+ movq %rdx, %r13
+ adcq \$0, %r13
+
+ mulq %rbx
+ leaq 128(%rbp), %rbp
+ addq %rax, %r13
+ movq 56($ap), %rax
+ movq %rdx, %r14
+ adcq \$0, %r14
+
+ mulq %rbx
+ movq %xmm4, %rbx
+ addq %rax, %r14
+ movq ($ap), %rax
+ movq %rdx, %r15
+ adcq \$0, %r15
+
+ leaq 8(%rsp), %rdi
+ movl \$7, %ecx
+ jmp .Loop_mul_gather
+
+.align 32
+.Loop_mul_gather:
+ mulq %rbx
+ addq %rax, %r8
+ movq 8($ap), %rax
+ movq %r8, (%rdi)
+ movq %rdx, %r8
+ adcq \$0, %r8
+
+ mulq %rbx
+ movd (%rbp), %xmm4
+ addq %rax, %r9
+ movq 16($ap), %rax
+ adcq \$0, %rdx
+ addq %r9, %r8
+ movq %rdx, %r9
+ adcq \$0, %r9
+
+ mulq %rbx
+ movd 64(%rbp), %xmm5
+ addq %rax, %r10
+ movq 24($ap), %rax
+ adcq \$0, %rdx
+ addq %r10, %r9
+ movq %rdx, %r10
+ adcq \$0, %r10
+
+ mulq %rbx
+ pslldq \$4, %xmm5
+ addq %rax, %r11
+ movq 32($ap), %rax
+ adcq \$0, %rdx
+ addq %r11, %r10
+ movq %rdx, %r11
+ adcq \$0, %r11
+
+ mulq %rbx
+ por %xmm5, %xmm4
+ addq %rax, %r12
+ movq 40($ap), %rax
+ adcq \$0, %rdx
+ addq %r12, %r11
+ movq %rdx, %r12
+ adcq \$0, %r12
+
+ mulq %rbx
+ addq %rax, %r13
+ movq 48($ap), %rax
+ adcq \$0, %rdx
+ addq %r13, %r12
+ movq %rdx, %r13
+ adcq \$0, %r13
+
+ mulq %rbx
+ addq %rax, %r14
+ movq 56($ap), %rax
+ adcq \$0, %rdx
+ addq %r14, %r13
+ movq %rdx, %r14
+ adcq \$0, %r14
+
+ mulq %rbx
+ movq %xmm4, %rbx
+ addq %rax, %r15
+ movq ($ap), %rax
+ adcq \$0, %rdx
+ addq %r15, %r14
+ movq %rdx, %r15
+ adcq \$0, %r15
+
+ leaq 128(%rbp), %rbp
+ leaq 8(%rdi), %rdi
+
+ decl %ecx
+ jnz .Loop_mul_gather
+
+ movq %r8, (%rdi)
+ movq %r9, 8(%rdi)
+ movq %r10, 16(%rdi)
+ movq %r11, 24(%rdi)
+ movq %r12, 32(%rdi)
+ movq %r13, 40(%rdi)
+ movq %r14, 48(%rdi)
+ movq %r15, 56(%rdi)
+
+ movq %xmm0, $out
+ movq %xmm1, %rbp
+
+ movq (%rsp), %r8
+ movq 8(%rsp), %r9
+ movq 16(%rsp), %r10
+ movq 24(%rsp), %r11
+ movq 32(%rsp), %r12
+ movq 40(%rsp), %r13
+ movq 48(%rsp), %r14
+ movq 56(%rsp), %r15
+
+ call __rsaz_512_reduce
+___
+$code.=<<___ if ($addx);
+ jmp .Lmul_gather_tail
+
+.align 32
+.Lmulx_gather:
+ mov 64($bp,$pwr,4), %eax
+ movq $out, %xmm0 # off-load arguments
+ lea 128($bp,$pwr,4), %rbp
+ mov ($bp,$pwr,4), %edx
+ movq $mod, %xmm1
+ mov $n0, 128(%rsp)
+
+ shl \$32, %rax
+ or %rax, %rdx
+ mulx ($ap), %rbx, %r8 # 0 iteration
+ mov %rbx, (%rsp)
+ xor %edi, %edi # cf=0, of=0
+
+ mulx 8($ap), %rax, %r9
+ movd (%rbp), %xmm4
+
+ mulx 16($ap), %rbx, %r10
+ movd 64(%rbp), %xmm5
+ adcx %rax, %r8
+
+ mulx 24($ap), %rax, %r11
+ pslldq \$4, %xmm5
+ adcx %rbx, %r9
+
+ mulx 32($ap), %rbx, %r12
+ por %xmm5, %xmm4
+ adcx %rax, %r10
+
+ mulx 40($ap), %rax, %r13
+ adcx %rbx, %r11
+
+ mulx 48($ap), %rbx, %r14
+ lea 128(%rbp), %rbp
+ adcx %rax, %r12
+
+ mulx 56($ap), %rax, %r15
+ movq %xmm4, %rdx
+ adcx %rbx, %r13
+ adcx %rax, %r14
+ mov %r8, %rbx
+ adcx %rdi, %r15 # %rdi is 0
+
+ mov \$-7, %rcx
+ jmp .Loop_mulx_gather
+
+.align 32
+.Loop_mulx_gather:
+ mulx ($ap), %rax, %r8
+ adcx %rax, %rbx
+ adox %r9, %r8
+
+ mulx 8($ap), %rax, %r9
+ .byte 0x66,0x0f,0x6e,0xa5,0x00,0x00,0x00,0x00 # movd (%rbp), %xmm4
+ adcx %rax, %r8
+ adox %r10, %r9
+
+ mulx 16($ap), %rax, %r10
+ movd 64(%rbp), %xmm5
+ lea 128(%rbp), %rbp
+ adcx %rax, %r9
+ adox %r11, %r10
+
+ .byte 0xc4,0x62,0xfb,0xf6,0x9e,0x18,0x00,0x00,0x00 # mulx 24($ap), %rax, %r11
+ pslldq \$4, %xmm5
+ por %xmm5, %xmm4
+ adcx %rax, %r10
+ adox %r12, %r11
+
+ mulx 32($ap), %rax, %r12
+ adcx %rax, %r11
+ adox %r13, %r12
+
+ mulx 40($ap), %rax, %r13
+ adcx %rax, %r12
+ adox %r14, %r13
+
+ .byte 0xc4,0x62,0xfb,0xf6,0xb6,0x30,0x00,0x00,0x00 # mulx 48($ap), %rax, %r14
+ adcx %rax, %r13
+ adox %r15, %r14
+
+ mulx 56($ap), %rax, %r15
+ movq %xmm4, %rdx
+ mov %rbx, 64(%rsp,%rcx,8)
+ adcx %rax, %r14
+ adox %rdi, %r15
+ mov %r8, %rbx
+ adcx %rdi, %r15 # cf=0
+
+ inc %rcx # of=0
+ jnz .Loop_mulx_gather
+
+ mov %r8, 64(%rsp)
+ mov %r9, 64+8(%rsp)
+ mov %r10, 64+16(%rsp)
+ mov %r11, 64+24(%rsp)
+ mov %r12, 64+32(%rsp)
+ mov %r13, 64+40(%rsp)
+ mov %r14, 64+48(%rsp)
+ mov %r15, 64+56(%rsp)
+
+ movq %xmm0, $out
+ movq %xmm1, %rbp
+
+ mov 128(%rsp), %rdx # pull $n0
+ mov (%rsp), %r8
+ mov 8(%rsp), %r9
+ mov 16(%rsp), %r10
+ mov 24(%rsp), %r11
+ mov 32(%rsp), %r12
+ mov 40(%rsp), %r13
+ mov 48(%rsp), %r14
+ mov 56(%rsp), %r15
+
+ call __rsaz_512_reducex
+
+.Lmul_gather_tail:
+___
+$code.=<<___;
+ addq 64(%rsp), %r8
+ adcq 72(%rsp), %r9
+ adcq 80(%rsp), %r10
+ adcq 88(%rsp), %r11
+ adcq 96(%rsp), %r12
+ adcq 104(%rsp), %r13
+ adcq 112(%rsp), %r14
+ adcq 120(%rsp), %r15
+ sbbq %rcx, %rcx
+
+ call __rsaz_512_subtract
+
+ leaq 128+24+48(%rsp), %rax
+ movq -48(%rax), %r15
+ movq -40(%rax), %r14
+ movq -32(%rax), %r13
+ movq -24(%rax), %r12
+ movq -16(%rax), %rbp
+ movq -8(%rax), %rbx
+ leaq (%rax), %rsp
+.Lmul_gather4_epilogue:
+ ret
+.size rsaz_512_mul_gather4,.-rsaz_512_mul_gather4
+___
+}
+{
+my ($out,$ap,$mod,$n0,$tbl,$pwr) = ("%rdi","%rsi","%rdx","%rcx","%r8","%r9d");
+$code.=<<___;
+.globl rsaz_512_mul_scatter4
+.type rsaz_512_mul_scatter4,\@function,6
+.align 32
+rsaz_512_mul_scatter4:
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+
+ mov $pwr, $pwr
+ subq \$128+24, %rsp
+.Lmul_scatter4_body:
+ leaq ($tbl,$pwr,4), $tbl
+ movq $out, %xmm0 # off-load arguments
+ movq $mod, %xmm1
+ movq $tbl, %xmm2
+ movq $n0, 128(%rsp)
+
+ movq $out, %rbp
+___
+$code.=<<___ if ($addx);
+ movl \$0x80100,%r11d
+ andl OPENSSL_ia32cap_P+8(%rip),%r11d
+ cmpl \$0x80100,%r11d # check for MULX and ADO/CX
+ je .Lmulx_scatter
+___
+$code.=<<___;
+ movq ($out),%rbx # pass b[0]
+ call __rsaz_512_mul
+
+ movq %xmm0, $out
+ movq %xmm1, %rbp
+
+ movq (%rsp), %r8
+ movq 8(%rsp), %r9
+ movq 16(%rsp), %r10
+ movq 24(%rsp), %r11
+ movq 32(%rsp), %r12
+ movq 40(%rsp), %r13
+ movq 48(%rsp), %r14
+ movq 56(%rsp), %r15
+
+ call __rsaz_512_reduce
+___
+$code.=<<___ if ($addx);
+ jmp .Lmul_scatter_tail
+
+.align 32
+.Lmulx_scatter:
+ movq ($out), %rdx # pass b[0]
+ call __rsaz_512_mulx
+
+ movq %xmm0, $out
+ movq %xmm1, %rbp
+
+ movq 128(%rsp), %rdx # pull $n0
+ movq (%rsp), %r8
+ movq 8(%rsp), %r9
+ movq 16(%rsp), %r10
+ movq 24(%rsp), %r11
+ movq 32(%rsp), %r12
+ movq 40(%rsp), %r13
+ movq 48(%rsp), %r14
+ movq 56(%rsp), %r15
+
+ call __rsaz_512_reducex
+
+.Lmul_scatter_tail:
+___
+$code.=<<___;
+ addq 64(%rsp), %r8
+ adcq 72(%rsp), %r9
+ adcq 80(%rsp), %r10
+ adcq 88(%rsp), %r11
+ adcq 96(%rsp), %r12
+ adcq 104(%rsp), %r13
+ adcq 112(%rsp), %r14
+ adcq 120(%rsp), %r15
+ movq %xmm2, $inp
+ sbbq %rcx, %rcx
+
+ call __rsaz_512_subtract
+
+ movl %r8d, 64*0($inp) # scatter
+ shrq \$32, %r8
+ movl %r9d, 64*2($inp)
+ shrq \$32, %r9
+ movl %r10d, 64*4($inp)
+ shrq \$32, %r10
+ movl %r11d, 64*6($inp)
+ shrq \$32, %r11
+ movl %r12d, 64*8($inp)
+ shrq \$32, %r12
+ movl %r13d, 64*10($inp)
+ shrq \$32, %r13
+ movl %r14d, 64*12($inp)
+ shrq \$32, %r14
+ movl %r15d, 64*14($inp)
+ shrq \$32, %r15
+ movl %r8d, 64*1($inp)
+ movl %r9d, 64*3($inp)
+ movl %r10d, 64*5($inp)
+ movl %r11d, 64*7($inp)
+ movl %r12d, 64*9($inp)
+ movl %r13d, 64*11($inp)
+ movl %r14d, 64*13($inp)
+ movl %r15d, 64*15($inp)
+
+ leaq 128+24+48(%rsp), %rax
+ movq -48(%rax), %r15
+ movq -40(%rax), %r14
+ movq -32(%rax), %r13
+ movq -24(%rax), %r12
+ movq -16(%rax), %rbp
+ movq -8(%rax), %rbx
+ leaq (%rax), %rsp
+.Lmul_scatter4_epilogue:
+ ret
+.size rsaz_512_mul_scatter4,.-rsaz_512_mul_scatter4
+___
+}
+{
+my ($out,$inp,$mod,$n0) = ("%rdi","%rsi","%rdx","%rcx");
+$code.=<<___;
+.globl rsaz_512_mul_by_one
+.type rsaz_512_mul_by_one,\@function,4
+.align 32
+rsaz_512_mul_by_one:
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+
+ subq \$128+24, %rsp
+.Lmul_by_one_body:
+___
+$code.=<<___ if ($addx);
+ movl OPENSSL_ia32cap_P+8(%rip),%eax
+___
+$code.=<<___;
+ movq $mod, %rbp # reassign argument
+ movq $n0, 128(%rsp)
+
+ movq ($inp), %r8
+ pxor %xmm0, %xmm0
+ movq 8($inp), %r9
+ movq 16($inp), %r10
+ movq 24($inp), %r11
+ movq 32($inp), %r12
+ movq 40($inp), %r13
+ movq 48($inp), %r14
+ movq 56($inp), %r15
+
+ movdqa %xmm0, (%rsp)
+ movdqa %xmm0, 16(%rsp)
+ movdqa %xmm0, 32(%rsp)
+ movdqa %xmm0, 48(%rsp)
+ movdqa %xmm0, 64(%rsp)
+ movdqa %xmm0, 80(%rsp)
+ movdqa %xmm0, 96(%rsp)
+___
+$code.=<<___ if ($addx);
+ andl \$0x80100,%eax
+ cmpl \$0x80100,%eax # check for MULX and ADO/CX
+ je .Lby_one_callx
+___
+$code.=<<___;
+ call __rsaz_512_reduce
+___
+$code.=<<___ if ($addx);
+ jmp .Lby_one_tail
+.align 32
+.Lby_one_callx:
+ movq 128(%rsp), %rdx # pull $n0
+ call __rsaz_512_reducex
+.Lby_one_tail:
+___
+$code.=<<___;
+ movq %r8, ($out)
+ movq %r9, 8($out)
+ movq %r10, 16($out)
+ movq %r11, 24($out)
+ movq %r12, 32($out)
+ movq %r13, 40($out)
+ movq %r14, 48($out)
+ movq %r15, 56($out)
+
+ leaq 128+24+48(%rsp), %rax
+ movq -48(%rax), %r15
+ movq -40(%rax), %r14
+ movq -32(%rax), %r13
+ movq -24(%rax), %r12
+ movq -16(%rax), %rbp
+ movq -8(%rax), %rbx
+ leaq (%rax), %rsp
+.Lmul_by_one_epilogue:
+ ret
+.size rsaz_512_mul_by_one,.-rsaz_512_mul_by_one
+___
+}
+{ # __rsaz_512_reduce
+ #
+ # input: %r8-%r15, %rbp - mod, 128(%rsp) - n0
+ # output: %r8-%r15
+ # clobbers: everything except %rbp and %rdi
+$code.=<<___;
+.type __rsaz_512_reduce,\@abi-omnipotent
+.align 32
+__rsaz_512_reduce:
+ movq %r8, %rbx
+ imulq 128+8(%rsp), %rbx
+ movq 0(%rbp), %rax
+ movl \$8, %ecx
+ jmp .Lreduction_loop
+
+.align 32
+.Lreduction_loop:
+ mulq %rbx
+ movq 8(%rbp), %rax
+ negq %r8
+ movq %rdx, %r8
+ adcq \$0, %r8
+
+ mulq %rbx
+ addq %rax, %r9
+ movq 16(%rbp), %rax
+ adcq \$0, %rdx
+ addq %r9, %r8
+ movq %rdx, %r9
+ adcq \$0, %r9
+
+ mulq %rbx
+ addq %rax, %r10
+ movq 24(%rbp), %rax
+ adcq \$0, %rdx
+ addq %r10, %r9
+ movq %rdx, %r10
+ adcq \$0, %r10
+
+ mulq %rbx
+ addq %rax, %r11
+ movq 32(%rbp), %rax
+ adcq \$0, %rdx
+ addq %r11, %r10
+ movq 128+8(%rsp), %rsi
+ #movq %rdx, %r11
+ #adcq \$0, %r11
+ adcq \$0, %rdx
+ movq %rdx, %r11
+
+ mulq %rbx
+ addq %rax, %r12
+ movq 40(%rbp), %rax
+ adcq \$0, %rdx
+ imulq %r8, %rsi
+ addq %r12, %r11
+ movq %rdx, %r12
+ adcq \$0, %r12
+
+ mulq %rbx
+ addq %rax, %r13
+ movq 48(%rbp), %rax
+ adcq \$0, %rdx
+ addq %r13, %r12
+ movq %rdx, %r13
+ adcq \$0, %r13
+
+ mulq %rbx
+ addq %rax, %r14
+ movq 56(%rbp), %rax
+ adcq \$0, %rdx
+ addq %r14, %r13
+ movq %rdx, %r14
+ adcq \$0, %r14
+
+ mulq %rbx
+ movq %rsi, %rbx
+ addq %rax, %r15
+ movq 0(%rbp), %rax
+ adcq \$0, %rdx
+ addq %r15, %r14
+ movq %rdx, %r15
+ adcq \$0, %r15
+
+ decl %ecx
+ jne .Lreduction_loop
+
+ ret
+.size __rsaz_512_reduce,.-__rsaz_512_reduce
+___
+}
+if ($addx) {
+ # __rsaz_512_reducex
+ #
+ # input: %r8-%r15, %rbp - mod, 128(%rsp) - n0
+ # output: %r8-%r15
+ # clobbers: everything except %rbp and %rdi
+$code.=<<___;
+.type __rsaz_512_reducex,\@abi-omnipotent
+.align 32
+__rsaz_512_reducex:
+ #movq 128+8(%rsp), %rdx # pull $n0
+ imulq %r8, %rdx
+ xorq %rsi, %rsi # cf=0,of=0
+ movl \$8, %ecx
+ jmp .Lreduction_loopx
+
+.align 32
+.Lreduction_loopx:
+ mov %r8, %rbx
+ mulx 0(%rbp), %rax, %r8
+ adcx %rbx, %rax
+ adox %r9, %r8
+
+ mulx 8(%rbp), %rax, %r9
+ adcx %rax, %r8
+ adox %r10, %r9
+
+ mulx 16(%rbp), %rbx, %r10
+ adcx %rbx, %r9
+ adox %r11, %r10
+
+ mulx 24(%rbp), %rbx, %r11
+ adcx %rbx, %r10
+ adox %r12, %r11
+
+ .byte 0xc4,0x62,0xe3,0xf6,0xa5,0x20,0x00,0x00,0x00 # mulx 32(%rbp), %rbx, %r12
+ mov %rdx, %rax
+ mov %r8, %rdx
+ adcx %rbx, %r11
+ adox %r13, %r12
+
+ mulx 128+8(%rsp), %rbx, %rdx
+ mov %rax, %rdx
+
+ mulx 40(%rbp), %rax, %r13
+ adcx %rax, %r12
+ adox %r14, %r13
+
+ .byte 0xc4,0x62,0xfb,0xf6,0xb5,0x30,0x00,0x00,0x00 # mulx 48(%rbp), %rax, %r14
+ adcx %rax, %r13
+ adox %r15, %r14
+
+ mulx 56(%rbp), %rax, %r15
+ mov %rbx, %rdx
+ adcx %rax, %r14
+ adox %rsi, %r15 # %rsi is 0
+ adcx %rsi, %r15 # cf=0
+
+ decl %ecx # of=0
+ jne .Lreduction_loopx
+
+ ret
+.size __rsaz_512_reducex,.-__rsaz_512_reducex
+___
+}
+{ # __rsaz_512_subtract
+ # input: %r8-%r15, %rdi - $out, %rbp - $mod, %rcx - mask
+ # output:
+ # clobbers: everything but %rdi, %rsi and %rbp
+$code.=<<___;
+.type __rsaz_512_subtract,\@abi-omnipotent
+.align 32
+__rsaz_512_subtract:
+ movq %r8, ($out)
+ movq %r9, 8($out)
+ movq %r10, 16($out)
+ movq %r11, 24($out)
+ movq %r12, 32($out)
+ movq %r13, 40($out)
+ movq %r14, 48($out)
+ movq %r15, 56($out)
+
+ movq 0($mod), %r8
+ movq 8($mod), %r9
+ negq %r8
+ notq %r9
+ andq %rcx, %r8
+ movq 16($mod), %r10
+ andq %rcx, %r9
+ notq %r10
+ movq 24($mod), %r11
+ andq %rcx, %r10
+ notq %r11
+ movq 32($mod), %r12
+ andq %rcx, %r11
+ notq %r12
+ movq 40($mod), %r13
+ andq %rcx, %r12
+ notq %r13
+ movq 48($mod), %r14
+ andq %rcx, %r13
+ notq %r14
+ movq 56($mod), %r15
+ andq %rcx, %r14
+ notq %r15
+ andq %rcx, %r15
+
+ addq ($out), %r8
+ adcq 8($out), %r9
+ adcq 16($out), %r10
+ adcq 24($out), %r11
+ adcq 32($out), %r12
+ adcq 40($out), %r13
+ adcq 48($out), %r14
+ adcq 56($out), %r15
+
+ movq %r8, ($out)
+ movq %r9, 8($out)
+ movq %r10, 16($out)
+ movq %r11, 24($out)
+ movq %r12, 32($out)
+ movq %r13, 40($out)
+ movq %r14, 48($out)
+ movq %r15, 56($out)
+
+ ret
+.size __rsaz_512_subtract,.-__rsaz_512_subtract
+___
+}
+{ # __rsaz_512_mul
+ #
+ # input: %rsi - ap, %rbp - bp
+ # ouput:
+ # clobbers: everything
+my ($ap,$bp) = ("%rsi","%rbp");
+$code.=<<___;
+.type __rsaz_512_mul,\@abi-omnipotent
+.align 32
+__rsaz_512_mul:
+ leaq 8(%rsp), %rdi
+
+ movq ($ap), %rax
+ mulq %rbx
+ movq %rax, (%rdi)
+ movq 8($ap), %rax
+ movq %rdx, %r8
+
+ mulq %rbx
+ addq %rax, %r8
+ movq 16($ap), %rax
+ movq %rdx, %r9
+ adcq \$0, %r9
+
+ mulq %rbx
+ addq %rax, %r9
+ movq 24($ap), %rax
+ movq %rdx, %r10
+ adcq \$0, %r10
+
+ mulq %rbx
+ addq %rax, %r10
+ movq 32($ap), %rax
+ movq %rdx, %r11
+ adcq \$0, %r11
+
+ mulq %rbx
+ addq %rax, %r11
+ movq 40($ap), %rax
+ movq %rdx, %r12
+ adcq \$0, %r12
+
+ mulq %rbx
+ addq %rax, %r12
+ movq 48($ap), %rax
+ movq %rdx, %r13
+ adcq \$0, %r13
+
+ mulq %rbx
+ addq %rax, %r13
+ movq 56($ap), %rax
+ movq %rdx, %r14
+ adcq \$0, %r14
+
+ mulq %rbx
+ addq %rax, %r14
+ movq ($ap), %rax
+ movq %rdx, %r15
+ adcq \$0, %r15
+
+ leaq 8($bp), $bp
+ leaq 8(%rdi), %rdi
+
+ movl \$7, %ecx
+ jmp .Loop_mul
+
+.align 32
+.Loop_mul:
+ movq ($bp), %rbx
+ mulq %rbx
+ addq %rax, %r8
+ movq 8($ap), %rax
+ movq %r8, (%rdi)
+ movq %rdx, %r8
+ adcq \$0, %r8
+
+ mulq %rbx
+ addq %rax, %r9
+ movq 16($ap), %rax
+ adcq \$0, %rdx
+ addq %r9, %r8
+ movq %rdx, %r9
+ adcq \$0, %r9
+
+ mulq %rbx
+ addq %rax, %r10
+ movq 24($ap), %rax
+ adcq \$0, %rdx
+ addq %r10, %r9
+ movq %rdx, %r10
+ adcq \$0, %r10
+
+ mulq %rbx
+ addq %rax, %r11
+ movq 32($ap), %rax
+ adcq \$0, %rdx
+ addq %r11, %r10
+ movq %rdx, %r11
+ adcq \$0, %r11
+
+ mulq %rbx
+ addq %rax, %r12
+ movq 40($ap), %rax
+ adcq \$0, %rdx
+ addq %r12, %r11
+ movq %rdx, %r12
+ adcq \$0, %r12
+
+ mulq %rbx
+ addq %rax, %r13
+ movq 48($ap), %rax
+ adcq \$0, %rdx
+ addq %r13, %r12
+ movq %rdx, %r13
+ adcq \$0, %r13
+
+ mulq %rbx
+ addq %rax, %r14
+ movq 56($ap), %rax
+ adcq \$0, %rdx
+ addq %r14, %r13
+ movq %rdx, %r14
+ leaq 8($bp), $bp
+ adcq \$0, %r14
+
+ mulq %rbx
+ addq %rax, %r15
+ movq ($ap), %rax
+ adcq \$0, %rdx
+ addq %r15, %r14
+ movq %rdx, %r15
+ adcq \$0, %r15
+
+ leaq 8(%rdi), %rdi
+
+ decl %ecx
+ jnz .Loop_mul
+
+ movq %r8, (%rdi)
+ movq %r9, 8(%rdi)
+ movq %r10, 16(%rdi)
+ movq %r11, 24(%rdi)
+ movq %r12, 32(%rdi)
+ movq %r13, 40(%rdi)
+ movq %r14, 48(%rdi)
+ movq %r15, 56(%rdi)
+
+ ret
+.size __rsaz_512_mul,.-__rsaz_512_mul
+___
+}
+if ($addx) {
+ # __rsaz_512_mulx
+ #
+ # input: %rsi - ap, %rbp - bp
+ # ouput:
+ # clobbers: everything
+my ($ap,$bp,$zero) = ("%rsi","%rbp","%rdi");
+$code.=<<___;
+.type __rsaz_512_mulx,\@abi-omnipotent
+.align 32
+__rsaz_512_mulx:
+ mulx ($ap), %rbx, %r8 # initial %rdx preloaded by caller
+ mov \$-6, %rcx
+
+ mulx 8($ap), %rax, %r9
+ movq %rbx, 8(%rsp)
+
+ mulx 16($ap), %rbx, %r10
+ adc %rax, %r8
+
+ mulx 24($ap), %rax, %r11
+ adc %rbx, %r9
+
+ mulx 32($ap), %rbx, %r12
+ adc %rax, %r10
+
+ mulx 40($ap), %rax, %r13
+ adc %rbx, %r11
+
+ mulx 48($ap), %rbx, %r14
+ adc %rax, %r12
+
+ mulx 56($ap), %rax, %r15
+ mov 8($bp), %rdx
+ adc %rbx, %r13
+ adc %rax, %r14
+ adc \$0, %r15
+
+ xor $zero, $zero # cf=0,of=0
+ jmp .Loop_mulx
+
+.align 32
+.Loop_mulx:
+ movq %r8, %rbx
+ mulx ($ap), %rax, %r8
+ adcx %rax, %rbx
+ adox %r9, %r8
+
+ mulx 8($ap), %rax, %r9
+ adcx %rax, %r8
+ adox %r10, %r9
+
+ mulx 16($ap), %rax, %r10
+ adcx %rax, %r9
+ adox %r11, %r10
+
+ mulx 24($ap), %rax, %r11
+ adcx %rax, %r10
+ adox %r12, %r11
+
+ .byte 0x3e,0xc4,0x62,0xfb,0xf6,0xa6,0x20,0x00,0x00,0x00 # mulx 32($ap), %rax, %r12
+ adcx %rax, %r11
+ adox %r13, %r12
+
+ mulx 40($ap), %rax, %r13
+ adcx %rax, %r12
+ adox %r14, %r13
+
+ mulx 48($ap), %rax, %r14
+ adcx %rax, %r13
+ adox %r15, %r14
+
+ mulx 56($ap), %rax, %r15
+ movq 64($bp,%rcx,8), %rdx
+ movq %rbx, 8+64-8(%rsp,%rcx,8)
+ adcx %rax, %r14
+ adox $zero, %r15
+ adcx $zero, %r15 # cf=0
+
+ inc %rcx # of=0
+ jnz .Loop_mulx
+
+ movq %r8, %rbx
+ mulx ($ap), %rax, %r8
+ adcx %rax, %rbx
+ adox %r9, %r8
+
+ .byte 0xc4,0x62,0xfb,0xf6,0x8e,0x08,0x00,0x00,0x00 # mulx 8($ap), %rax, %r9
+ adcx %rax, %r8
+ adox %r10, %r9
+
+ .byte 0xc4,0x62,0xfb,0xf6,0x96,0x10,0x00,0x00,0x00 # mulx 16($ap), %rax, %r10
+ adcx %rax, %r9
+ adox %r11, %r10
+
+ mulx 24($ap), %rax, %r11
+ adcx %rax, %r10
+ adox %r12, %r11
+
+ mulx 32($ap), %rax, %r12
+ adcx %rax, %r11
+ adox %r13, %r12
+
+ mulx 40($ap), %rax, %r13
+ adcx %rax, %r12
+ adox %r14, %r13
+
+ .byte 0xc4,0x62,0xfb,0xf6,0xb6,0x30,0x00,0x00,0x00 # mulx 48($ap), %rax, %r14
+ adcx %rax, %r13
+ adox %r15, %r14
+
+ .byte 0xc4,0x62,0xfb,0xf6,0xbe,0x38,0x00,0x00,0x00 # mulx 56($ap), %rax, %r15
+ adcx %rax, %r14
+ adox $zero, %r15
+ adcx $zero, %r15
+
+ mov %rbx, 8+64-8(%rsp)
+ mov %r8, 8+64(%rsp)
+ mov %r9, 8+64+8(%rsp)
+ mov %r10, 8+64+16(%rsp)
+ mov %r11, 8+64+24(%rsp)
+ mov %r12, 8+64+32(%rsp)
+ mov %r13, 8+64+40(%rsp)
+ mov %r14, 8+64+48(%rsp)
+ mov %r15, 8+64+56(%rsp)
+
+ ret
+.size __rsaz_512_mulx,.-__rsaz_512_mulx
+___
+}
+{
+my ($out,$inp,$power)= $win64 ? ("%rcx","%rdx","%r8d") : ("%rdi","%rsi","%edx");
+$code.=<<___;
+.globl rsaz_512_scatter4
+.type rsaz_512_scatter4,\@abi-omnipotent
+.align 16
+rsaz_512_scatter4:
+ leaq ($out,$power,4), $out
+ movl \$8, %r9d
+ jmp .Loop_scatter
+.align 16
+.Loop_scatter:
+ movq ($inp), %rax
+ leaq 8($inp), $inp
+ movl %eax, ($out)
+ shrq \$32, %rax
+ movl %eax, 64($out)
+ leaq 128($out), $out
+ decl %r9d
+ jnz .Loop_scatter
+ ret
+.size rsaz_512_scatter4,.-rsaz_512_scatter4
+
+.globl rsaz_512_gather4
+.type rsaz_512_gather4,\@abi-omnipotent
+.align 16
+rsaz_512_gather4:
+ leaq ($inp,$power,4), $inp
+ movl \$8, %r9d
+ jmp .Loop_gather
+.align 16
+.Loop_gather:
+ movl ($inp), %eax
+ movl 64($inp), %r8d
+ leaq 128($inp), $inp
+ shlq \$32, %r8
+ or %r8, %rax
+ movq %rax, ($out)
+ leaq 8($out), $out
+ decl %r9d
+ jnz .Loop_gather
+ ret
+.size rsaz_512_gather4,.-rsaz_512_gather4
+___
+}
+
+# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
+# CONTEXT *context,DISPATCHER_CONTEXT *disp)
+if ($win64) {
+$rec="%rcx";
+$frame="%rdx";
+$context="%r8";
+$disp="%r9";
+
+$code.=<<___;
+.extern __imp_RtlVirtualUnwind
+.type se_handler,\@abi-omnipotent
+.align 16
+se_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 120($context),%rax # pull context->Rax
+ mov 248($context),%rbx # pull context->Rip
+
+ mov 8($disp),%rsi # disp->ImageBase
+ mov 56($disp),%r11 # disp->HandlerData
+
+ mov 0(%r11),%r10d # HandlerData[0]
+ lea (%rsi,%r10),%r10 # end of prologue label
+ cmp %r10,%rbx # context->Rip<end of prologue label
+ jb .Lcommon_seh_tail
+
+ mov 152($context),%rax # pull context->Rsp
+
+ mov 4(%r11),%r10d # HandlerData[1]
+ lea (%rsi,%r10),%r10 # epilogue label
+ cmp %r10,%rbx # context->Rip>=epilogue label
+ jae .Lcommon_seh_tail
+
+ lea 128+24+48(%rax),%rax
+
+ mov -8(%rax),%rbx
+ mov -16(%rax),%rbp
+ mov -24(%rax),%r12
+ mov -32(%rax),%r13
+ mov -40(%rax),%r14
+ mov -48(%rax),%r15
+ mov %rbx,144($context) # restore context->Rbx
+ mov %rbp,160($context) # restore context->Rbp
+ mov %r12,216($context) # restore context->R12
+ mov %r13,224($context) # restore context->R13
+ mov %r14,232($context) # restore context->R14
+ mov %r15,240($context) # restore context->R15
+
+.Lcommon_seh_tail:
+ mov 8(%rax),%rdi
+ mov 16(%rax),%rsi
+ mov %rax,152($context) # restore context->Rsp
+ mov %rsi,168($context) # restore context->Rsi
+ mov %rdi,176($context) # restore context->Rdi
+
+ mov 40($disp),%rdi # disp->ContextRecord
+ mov $context,%rsi # context
+ mov \$154,%ecx # sizeof(CONTEXT)
+ .long 0xa548f3fc # cld; rep movsq
+
+ mov $disp,%rsi
+ xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER
+ mov 8(%rsi),%rdx # arg2, disp->ImageBase
+ mov 0(%rsi),%r8 # arg3, disp->ControlPc
+ mov 16(%rsi),%r9 # arg4, disp->FunctionEntry
+ mov 40(%rsi),%r10 # disp->ContextRecord
+ lea 56(%rsi),%r11 # &disp->HandlerData
+ lea 24(%rsi),%r12 # &disp->EstablisherFrame
+ mov %r10,32(%rsp) # arg5
+ mov %r11,40(%rsp) # arg6
+ mov %r12,48(%rsp) # arg7
+ mov %rcx,56(%rsp) # arg8, (NULL)
+ call *__imp_RtlVirtualUnwind(%rip)
+
+ mov \$1,%eax # ExceptionContinueSearch
+ add \$64,%rsp
+ popfq
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+ pop %rdi
+ pop %rsi
+ ret
+.size sqr_handler,.-sqr_handler
+
+.section .pdata
+.align 4
+ .rva .LSEH_begin_rsaz_512_sqr
+ .rva .LSEH_end_rsaz_512_sqr
+ .rva .LSEH_info_rsaz_512_sqr
+
+ .rva .LSEH_begin_rsaz_512_mul
+ .rva .LSEH_end_rsaz_512_mul
+ .rva .LSEH_info_rsaz_512_mul
+
+ .rva .LSEH_begin_rsaz_512_mul_gather4
+ .rva .LSEH_end_rsaz_512_mul_gather4
+ .rva .LSEH_info_rsaz_512_mul_gather4
+
+ .rva .LSEH_begin_rsaz_512_mul_scatter4
+ .rva .LSEH_end_rsaz_512_mul_scatter4
+ .rva .LSEH_info_rsaz_512_mul_scatter4
+
+ .rva .LSEH_begin_rsaz_512_mul_by_one
+ .rva .LSEH_end_rsaz_512_mul_by_one
+ .rva .LSEH_info_rsaz_512_mul_by_one
+
+.section .xdata
+.align 8
+.LSEH_info_rsaz_512_sqr:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lsqr_body,.Lsqr_epilogue # HandlerData[]
+.LSEH_info_rsaz_512_mul:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lmul_body,.Lmul_epilogue # HandlerData[]
+.LSEH_info_rsaz_512_mul_gather4:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lmul_gather4_body,.Lmul_gather4_epilogue # HandlerData[]
+.LSEH_info_rsaz_512_mul_scatter4:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lmul_scatter4_body,.Lmul_scatter4_epilogue # HandlerData[]
+.LSEH_info_rsaz_512_mul_by_one:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lmul_by_one_body,.Lmul_by_one_epilogue # HandlerData[]
+___
+}
+
+$code =~ s/\`([^\`]*)\`/eval $1/gem;
+print $code;
+close STDOUT;
diff --git a/crypto/bn/asm/x86-mont.pl b/crypto/bn/asm/x86-mont.pl
new file mode 100644
index 0000000..e8f6b05
--- /dev/null
+++ b/crypto/bn/asm/x86-mont.pl
@@ -0,0 +1,593 @@
+#!/usr/bin/env perl
+
+# ====================================================================
+# Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+
+# October 2005
+#
+# This is a "teaser" code, as it can be improved in several ways...
+# First of all non-SSE2 path should be implemented (yes, for now it
+# performs Montgomery multiplication/convolution only on SSE2-capable
+# CPUs such as P4, others fall down to original code). Then inner loop
+# can be unrolled and modulo-scheduled to improve ILP and possibly
+# moved to 128-bit XMM register bank (though it would require input
+# rearrangement and/or increase bus bandwidth utilization). Dedicated
+# squaring procedure should give further performance improvement...
+# Yet, for being draft, the code improves rsa512 *sign* benchmark by
+# 110%(!), rsa1024 one - by 70% and rsa4096 - by 20%:-)
+
+# December 2006
+#
+# Modulo-scheduling SSE2 loops results in further 15-20% improvement.
+# Integer-only code [being equipped with dedicated squaring procedure]
+# gives ~40% on rsa512 sign benchmark...
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+push(@INC,"${dir}","${dir}../../perlasm");
+require "x86asm.pl";
+
+&asm_init($ARGV[0],$0);
+
+$sse2=0;
+for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); }
+
+&external_label("OPENSSL_ia32cap_P") if ($sse2);
+
+&function_begin("bn_mul_mont");
+
+$i="edx";
+$j="ecx";
+$ap="esi"; $tp="esi"; # overlapping variables!!!
+$rp="edi"; $bp="edi"; # overlapping variables!!!
+$np="ebp";
+$num="ebx";
+
+$_num=&DWP(4*0,"esp"); # stack top layout
+$_rp=&DWP(4*1,"esp");
+$_ap=&DWP(4*2,"esp");
+$_bp=&DWP(4*3,"esp");
+$_np=&DWP(4*4,"esp");
+$_n0=&DWP(4*5,"esp"); $_n0q=&QWP(4*5,"esp");
+$_sp=&DWP(4*6,"esp");
+$_bpend=&DWP(4*7,"esp");
+$frame=32; # size of above frame rounded up to 16n
+
+ &xor ("eax","eax");
+ &mov ("edi",&wparam(5)); # int num
+ &cmp ("edi",4);
+ &jl (&label("just_leave"));
+
+ &lea ("esi",&wparam(0)); # put aside pointer to argument block
+ &lea ("edx",&wparam(1)); # load ap
+ &mov ("ebp","esp"); # saved stack pointer!
+ &add ("edi",2); # extra two words on top of tp
+ &neg ("edi");
+ &lea ("esp",&DWP(-$frame,"esp","edi",4)); # alloca($frame+4*(num+2))
+ &neg ("edi");
+
+ # minimize cache contention by arraning 2K window between stack
+ # pointer and ap argument [np is also position sensitive vector,
+ # but it's assumed to be near ap, as it's allocated at ~same
+ # time].
+ &mov ("eax","esp");
+ &sub ("eax","edx");
+ &and ("eax",2047);
+ &sub ("esp","eax"); # this aligns sp and ap modulo 2048
+
+ &xor ("edx","esp");
+ &and ("edx",2048);
+ &xor ("edx",2048);
+ &sub ("esp","edx"); # this splits them apart modulo 4096
+
+ &and ("esp",-64); # align to cache line
+
+ ################################# load argument block...
+ &mov ("eax",&DWP(0*4,"esi"));# BN_ULONG *rp
+ &mov ("ebx",&DWP(1*4,"esi"));# const BN_ULONG *ap
+ &mov ("ecx",&DWP(2*4,"esi"));# const BN_ULONG *bp
+ &mov ("edx",&DWP(3*4,"esi"));# const BN_ULONG *np
+ &mov ("esi",&DWP(4*4,"esi"));# const BN_ULONG *n0
+ #&mov ("edi",&DWP(5*4,"esi"));# int num
+
+ &mov ("esi",&DWP(0,"esi")); # pull n0[0]
+ &mov ($_rp,"eax"); # ... save a copy of argument block
+ &mov ($_ap,"ebx");
+ &mov ($_bp,"ecx");
+ &mov ($_np,"edx");
+ &mov ($_n0,"esi");
+ &lea ($num,&DWP(-3,"edi")); # num=num-1 to assist modulo-scheduling
+ #&mov ($_num,$num); # redundant as $num is not reused
+ &mov ($_sp,"ebp"); # saved stack pointer!
+
+if($sse2) {
+$acc0="mm0"; # mmx register bank layout
+$acc1="mm1";
+$car0="mm2";
+$car1="mm3";
+$mul0="mm4";
+$mul1="mm5";
+$temp="mm6";
+$mask="mm7";
+
+ &picmeup("eax","OPENSSL_ia32cap_P");
+ &bt (&DWP(0,"eax"),26);
+ &jnc (&label("non_sse2"));
+
+ &mov ("eax",-1);
+ &movd ($mask,"eax"); # mask 32 lower bits
+
+ &mov ($ap,$_ap); # load input pointers
+ &mov ($bp,$_bp);
+ &mov ($np,$_np);
+
+ &xor ($i,$i); # i=0
+ &xor ($j,$j); # j=0
+
+ &movd ($mul0,&DWP(0,$bp)); # bp[0]
+ &movd ($mul1,&DWP(0,$ap)); # ap[0]
+ &movd ($car1,&DWP(0,$np)); # np[0]
+
+ &pmuludq($mul1,$mul0); # ap[0]*bp[0]
+ &movq ($car0,$mul1);
+ &movq ($acc0,$mul1); # I wish movd worked for
+ &pand ($acc0,$mask); # inter-register transfers
+
+ &pmuludq($mul1,$_n0q); # *=n0
+
+ &pmuludq($car1,$mul1); # "t[0]"*np[0]*n0
+ &paddq ($car1,$acc0);
+
+ &movd ($acc1,&DWP(4,$np)); # np[1]
+ &movd ($acc0,&DWP(4,$ap)); # ap[1]
+
+ &psrlq ($car0,32);
+ &psrlq ($car1,32);
+
+ &inc ($j); # j++
+&set_label("1st",16);
+ &pmuludq($acc0,$mul0); # ap[j]*bp[0]
+ &pmuludq($acc1,$mul1); # np[j]*m1
+ &paddq ($car0,$acc0); # +=c0
+ &paddq ($car1,$acc1); # +=c1
+
+ &movq ($acc0,$car0);
+ &pand ($acc0,$mask);
+ &movd ($acc1,&DWP(4,$np,$j,4)); # np[j+1]
+ &paddq ($car1,$acc0); # +=ap[j]*bp[0];
+ &movd ($acc0,&DWP(4,$ap,$j,4)); # ap[j+1]
+ &psrlq ($car0,32);
+ &movd (&DWP($frame-4,"esp",$j,4),$car1); # tp[j-1]=
+ &psrlq ($car1,32);
+
+ &lea ($j,&DWP(1,$j));
+ &cmp ($j,$num);
+ &jl (&label("1st"));
+
+ &pmuludq($acc0,$mul0); # ap[num-1]*bp[0]
+ &pmuludq($acc1,$mul1); # np[num-1]*m1
+ &paddq ($car0,$acc0); # +=c0
+ &paddq ($car1,$acc1); # +=c1
+
+ &movq ($acc0,$car0);
+ &pand ($acc0,$mask);
+ &paddq ($car1,$acc0); # +=ap[num-1]*bp[0];
+ &movd (&DWP($frame-4,"esp",$j,4),$car1); # tp[num-2]=
+
+ &psrlq ($car0,32);
+ &psrlq ($car1,32);
+
+ &paddq ($car1,$car0);
+ &movq (&QWP($frame,"esp",$num,4),$car1); # tp[num].tp[num-1]
+
+ &inc ($i); # i++
+&set_label("outer");
+ &xor ($j,$j); # j=0
+
+ &movd ($mul0,&DWP(0,$bp,$i,4)); # bp[i]
+ &movd ($mul1,&DWP(0,$ap)); # ap[0]
+ &movd ($temp,&DWP($frame,"esp")); # tp[0]
+ &movd ($car1,&DWP(0,$np)); # np[0]
+ &pmuludq($mul1,$mul0); # ap[0]*bp[i]
+
+ &paddq ($mul1,$temp); # +=tp[0]
+ &movq ($acc0,$mul1);
+ &movq ($car0,$mul1);
+ &pand ($acc0,$mask);
+
+ &pmuludq($mul1,$_n0q); # *=n0
+
+ &pmuludq($car1,$mul1);
+ &paddq ($car1,$acc0);
+
+ &movd ($temp,&DWP($frame+4,"esp")); # tp[1]
+ &movd ($acc1,&DWP(4,$np)); # np[1]
+ &movd ($acc0,&DWP(4,$ap)); # ap[1]
+
+ &psrlq ($car0,32);
+ &psrlq ($car1,32);
+ &paddq ($car0,$temp); # +=tp[1]
+
+ &inc ($j); # j++
+ &dec ($num);
+&set_label("inner");
+ &pmuludq($acc0,$mul0); # ap[j]*bp[i]
+ &pmuludq($acc1,$mul1); # np[j]*m1
+ &paddq ($car0,$acc0); # +=c0
+ &paddq ($car1,$acc1); # +=c1
+
+ &movq ($acc0,$car0);
+ &movd ($temp,&DWP($frame+4,"esp",$j,4));# tp[j+1]
+ &pand ($acc0,$mask);
+ &movd ($acc1,&DWP(4,$np,$j,4)); # np[j+1]
+ &paddq ($car1,$acc0); # +=ap[j]*bp[i]+tp[j]
+ &movd ($acc0,&DWP(4,$ap,$j,4)); # ap[j+1]
+ &psrlq ($car0,32);
+ &movd (&DWP($frame-4,"esp",$j,4),$car1);# tp[j-1]=
+ &psrlq ($car1,32);
+ &paddq ($car0,$temp); # +=tp[j+1]
+
+ &dec ($num);
+ &lea ($j,&DWP(1,$j)); # j++
+ &jnz (&label("inner"));
+
+ &mov ($num,$j);
+ &pmuludq($acc0,$mul0); # ap[num-1]*bp[i]
+ &pmuludq($acc1,$mul1); # np[num-1]*m1
+ &paddq ($car0,$acc0); # +=c0
+ &paddq ($car1,$acc1); # +=c1
+
+ &movq ($acc0,$car0);
+ &pand ($acc0,$mask);
+ &paddq ($car1,$acc0); # +=ap[num-1]*bp[i]+tp[num-1]
+ &movd (&DWP($frame-4,"esp",$j,4),$car1); # tp[num-2]=
+ &psrlq ($car0,32);
+ &psrlq ($car1,32);
+
+ &movd ($temp,&DWP($frame+4,"esp",$num,4)); # += tp[num]
+ &paddq ($car1,$car0);
+ &paddq ($car1,$temp);
+ &movq (&QWP($frame,"esp",$num,4),$car1); # tp[num].tp[num-1]
+
+ &lea ($i,&DWP(1,$i)); # i++
+ &cmp ($i,$num);
+ &jle (&label("outer"));
+
+ &emms (); # done with mmx bank
+ &jmp (&label("common_tail"));
+
+&set_label("non_sse2",16);
+}
+
+if (0) {
+ &mov ("esp",$_sp);
+ &xor ("eax","eax"); # signal "not fast enough [yet]"
+ &jmp (&label("just_leave"));
+ # While the below code provides competitive performance for
+ # all key lengthes on modern Intel cores, it's still more
+ # than 10% slower for 4096-bit key elsewhere:-( "Competitive"
+ # means compared to the original integer-only assembler.
+ # 512-bit RSA sign is better by ~40%, but that's about all
+ # one can say about all CPUs...
+} else {
+$inp="esi"; # integer path uses these registers differently
+$word="edi";
+$carry="ebp";
+
+ &mov ($inp,$_ap);
+ &lea ($carry,&DWP(1,$num));
+ &mov ($word,$_bp);
+ &xor ($j,$j); # j=0
+ &mov ("edx",$inp);
+ &and ($carry,1); # see if num is even
+ &sub ("edx",$word); # see if ap==bp
+ &lea ("eax",&DWP(4,$word,$num,4)); # &bp[num]
+ &or ($carry,"edx");
+ &mov ($word,&DWP(0,$word)); # bp[0]
+ &jz (&label("bn_sqr_mont"));
+ &mov ($_bpend,"eax");
+ &mov ("eax",&DWP(0,$inp));
+ &xor ("edx","edx");
+
+&set_label("mull",16);
+ &mov ($carry,"edx");
+ &mul ($word); # ap[j]*bp[0]
+ &add ($carry,"eax");
+ &lea ($j,&DWP(1,$j));
+ &adc ("edx",0);
+ &mov ("eax",&DWP(0,$inp,$j,4)); # ap[j+1]
+ &cmp ($j,$num);
+ &mov (&DWP($frame-4,"esp",$j,4),$carry); # tp[j]=
+ &jl (&label("mull"));
+
+ &mov ($carry,"edx");
+ &mul ($word); # ap[num-1]*bp[0]
+ &mov ($word,$_n0);
+ &add ("eax",$carry);
+ &mov ($inp,$_np);
+ &adc ("edx",0);
+ &imul ($word,&DWP($frame,"esp")); # n0*tp[0]
+
+ &mov (&DWP($frame,"esp",$num,4),"eax"); # tp[num-1]=
+ &xor ($j,$j);
+ &mov (&DWP($frame+4,"esp",$num,4),"edx"); # tp[num]=
+ &mov (&DWP($frame+8,"esp",$num,4),$j); # tp[num+1]=
+
+ &mov ("eax",&DWP(0,$inp)); # np[0]
+ &mul ($word); # np[0]*m
+ &add ("eax",&DWP($frame,"esp")); # +=tp[0]
+ &mov ("eax",&DWP(4,$inp)); # np[1]
+ &adc ("edx",0);
+ &inc ($j);
+
+ &jmp (&label("2ndmadd"));
+
+&set_label("1stmadd",16);
+ &mov ($carry,"edx");
+ &mul ($word); # ap[j]*bp[i]
+ &add ($carry,&DWP($frame,"esp",$j,4)); # +=tp[j]
+ &lea ($j,&DWP(1,$j));
+ &adc ("edx",0);
+ &add ($carry,"eax");
+ &mov ("eax",&DWP(0,$inp,$j,4)); # ap[j+1]
+ &adc ("edx",0);
+ &cmp ($j,$num);
+ &mov (&DWP($frame-4,"esp",$j,4),$carry); # tp[j]=
+ &jl (&label("1stmadd"));
+
+ &mov ($carry,"edx");
+ &mul ($word); # ap[num-1]*bp[i]
+ &add ("eax",&DWP($frame,"esp",$num,4)); # +=tp[num-1]
+ &mov ($word,$_n0);
+ &adc ("edx",0);
+ &mov ($inp,$_np);
+ &add ($carry,"eax");
+ &adc ("edx",0);
+ &imul ($word,&DWP($frame,"esp")); # n0*tp[0]
+
+ &xor ($j,$j);
+ &add ("edx",&DWP($frame+4,"esp",$num,4)); # carry+=tp[num]
+ &mov (&DWP($frame,"esp",$num,4),$carry); # tp[num-1]=
+ &adc ($j,0);
+ &mov ("eax",&DWP(0,$inp)); # np[0]
+ &mov (&DWP($frame+4,"esp",$num,4),"edx"); # tp[num]=
+ &mov (&DWP($frame+8,"esp",$num,4),$j); # tp[num+1]=
+
+ &mul ($word); # np[0]*m
+ &add ("eax",&DWP($frame,"esp")); # +=tp[0]
+ &mov ("eax",&DWP(4,$inp)); # np[1]
+ &adc ("edx",0);
+ &mov ($j,1);
+
+&set_label("2ndmadd",16);
+ &mov ($carry,"edx");
+ &mul ($word); # np[j]*m
+ &add ($carry,&DWP($frame,"esp",$j,4)); # +=tp[j]
+ &lea ($j,&DWP(1,$j));
+ &adc ("edx",0);
+ &add ($carry,"eax");
+ &mov ("eax",&DWP(0,$inp,$j,4)); # np[j+1]
+ &adc ("edx",0);
+ &cmp ($j,$num);
+ &mov (&DWP($frame-8,"esp",$j,4),$carry); # tp[j-1]=
+ &jl (&label("2ndmadd"));
+
+ &mov ($carry,"edx");
+ &mul ($word); # np[j]*m
+ &add ($carry,&DWP($frame,"esp",$num,4)); # +=tp[num-1]
+ &adc ("edx",0);
+ &add ($carry,"eax");
+ &adc ("edx",0);
+ &mov (&DWP($frame-4,"esp",$num,4),$carry); # tp[num-2]=
+
+ &xor ("eax","eax");
+ &mov ($j,$_bp); # &bp[i]
+ &add ("edx",&DWP($frame+4,"esp",$num,4)); # carry+=tp[num]
+ &adc ("eax",&DWP($frame+8,"esp",$num,4)); # +=tp[num+1]
+ &lea ($j,&DWP(4,$j));
+ &mov (&DWP($frame,"esp",$num,4),"edx"); # tp[num-1]=
+ &cmp ($j,$_bpend);
+ &mov (&DWP($frame+4,"esp",$num,4),"eax"); # tp[num]=
+ &je (&label("common_tail"));
+
+ &mov ($word,&DWP(0,$j)); # bp[i+1]
+ &mov ($inp,$_ap);
+ &mov ($_bp,$j); # &bp[++i]
+ &xor ($j,$j);
+ &xor ("edx","edx");
+ &mov ("eax",&DWP(0,$inp));
+ &jmp (&label("1stmadd"));
+
+&set_label("bn_sqr_mont",16);
+$sbit=$num;
+ &mov ($_num,$num);
+ &mov ($_bp,$j); # i=0
+
+ &mov ("eax",$word); # ap[0]
+ &mul ($word); # ap[0]*ap[0]
+ &mov (&DWP($frame,"esp"),"eax"); # tp[0]=
+ &mov ($sbit,"edx");
+ &shr ("edx",1);
+ &and ($sbit,1);
+ &inc ($j);
+&set_label("sqr",16);
+ &mov ("eax",&DWP(0,$inp,$j,4)); # ap[j]
+ &mov ($carry,"edx");
+ &mul ($word); # ap[j]*ap[0]
+ &add ("eax",$carry);
+ &lea ($j,&DWP(1,$j));
+ &adc ("edx",0);
+ &lea ($carry,&DWP(0,$sbit,"eax",2));
+ &shr ("eax",31);
+ &cmp ($j,$_num);
+ &mov ($sbit,"eax");
+ &mov (&DWP($frame-4,"esp",$j,4),$carry); # tp[j]=
+ &jl (&label("sqr"));
+
+ &mov ("eax",&DWP(0,$inp,$j,4)); # ap[num-1]
+ &mov ($carry,"edx");
+ &mul ($word); # ap[num-1]*ap[0]
+ &add ("eax",$carry);
+ &mov ($word,$_n0);
+ &adc ("edx",0);
+ &mov ($inp,$_np);
+ &lea ($carry,&DWP(0,$sbit,"eax",2));
+ &imul ($word,&DWP($frame,"esp")); # n0*tp[0]
+ &shr ("eax",31);
+ &mov (&DWP($frame,"esp",$j,4),$carry); # tp[num-1]=
+
+ &lea ($carry,&DWP(0,"eax","edx",2));
+ &mov ("eax",&DWP(0,$inp)); # np[0]
+ &shr ("edx",31);
+ &mov (&DWP($frame+4,"esp",$j,4),$carry); # tp[num]=
+ &mov (&DWP($frame+8,"esp",$j,4),"edx"); # tp[num+1]=
+
+ &mul ($word); # np[0]*m
+ &add ("eax",&DWP($frame,"esp")); # +=tp[0]
+ &mov ($num,$j);
+ &adc ("edx",0);
+ &mov ("eax",&DWP(4,$inp)); # np[1]
+ &mov ($j,1);
+
+&set_label("3rdmadd",16);
+ &mov ($carry,"edx");
+ &mul ($word); # np[j]*m
+ &add ($carry,&DWP($frame,"esp",$j,4)); # +=tp[j]
+ &adc ("edx",0);
+ &add ($carry,"eax");
+ &mov ("eax",&DWP(4,$inp,$j,4)); # np[j+1]
+ &adc ("edx",0);
+ &mov (&DWP($frame-4,"esp",$j,4),$carry); # tp[j-1]=
+
+ &mov ($carry,"edx");
+ &mul ($word); # np[j+1]*m
+ &add ($carry,&DWP($frame+4,"esp",$j,4)); # +=tp[j+1]
+ &lea ($j,&DWP(2,$j));
+ &adc ("edx",0);
+ &add ($carry,"eax");
+ &mov ("eax",&DWP(0,$inp,$j,4)); # np[j+2]
+ &adc ("edx",0);
+ &cmp ($j,$num);
+ &mov (&DWP($frame-8,"esp",$j,4),$carry); # tp[j]=
+ &jl (&label("3rdmadd"));
+
+ &mov ($carry,"edx");
+ &mul ($word); # np[j]*m
+ &add ($carry,&DWP($frame,"esp",$num,4)); # +=tp[num-1]
+ &adc ("edx",0);
+ &add ($carry,"eax");
+ &adc ("edx",0);
+ &mov (&DWP($frame-4,"esp",$num,4),$carry); # tp[num-2]=
+
+ &mov ($j,$_bp); # i
+ &xor ("eax","eax");
+ &mov ($inp,$_ap);
+ &add ("edx",&DWP($frame+4,"esp",$num,4)); # carry+=tp[num]
+ &adc ("eax",&DWP($frame+8,"esp",$num,4)); # +=tp[num+1]
+ &mov (&DWP($frame,"esp",$num,4),"edx"); # tp[num-1]=
+ &cmp ($j,$num);
+ &mov (&DWP($frame+4,"esp",$num,4),"eax"); # tp[num]=
+ &je (&label("common_tail"));
+
+ &mov ($word,&DWP(4,$inp,$j,4)); # ap[i]
+ &lea ($j,&DWP(1,$j));
+ &mov ("eax",$word);
+ &mov ($_bp,$j); # ++i
+ &mul ($word); # ap[i]*ap[i]
+ &add ("eax",&DWP($frame,"esp",$j,4)); # +=tp[i]
+ &adc ("edx",0);
+ &mov (&DWP($frame,"esp",$j,4),"eax"); # tp[i]=
+ &xor ($carry,$carry);
+ &cmp ($j,$num);
+ &lea ($j,&DWP(1,$j));
+ &je (&label("sqrlast"));
+
+ &mov ($sbit,"edx"); # zaps $num
+ &shr ("edx",1);
+ &and ($sbit,1);
+&set_label("sqradd",16);
+ &mov ("eax",&DWP(0,$inp,$j,4)); # ap[j]
+ &mov ($carry,"edx");
+ &mul ($word); # ap[j]*ap[i]
+ &add ("eax",$carry);
+ &lea ($carry,&DWP(0,"eax","eax"));
+ &adc ("edx",0);
+ &shr ("eax",31);
+ &add ($carry,&DWP($frame,"esp",$j,4)); # +=tp[j]
+ &lea ($j,&DWP(1,$j));
+ &adc ("eax",0);
+ &add ($carry,$sbit);
+ &adc ("eax",0);
+ &cmp ($j,$_num);
+ &mov (&DWP($frame-4,"esp",$j,4),$carry); # tp[j]=
+ &mov ($sbit,"eax");
+ &jle (&label("sqradd"));
+
+ &mov ($carry,"edx");
+ &add ("edx","edx");
+ &shr ($carry,31);
+ &add ("edx",$sbit);
+ &adc ($carry,0);
+&set_label("sqrlast");
+ &mov ($word,$_n0);
+ &mov ($inp,$_np);
+ &imul ($word,&DWP($frame,"esp")); # n0*tp[0]
+
+ &add ("edx",&DWP($frame,"esp",$j,4)); # +=tp[num]
+ &mov ("eax",&DWP(0,$inp)); # np[0]
+ &adc ($carry,0);
+ &mov (&DWP($frame,"esp",$j,4),"edx"); # tp[num]=
+ &mov (&DWP($frame+4,"esp",$j,4),$carry); # tp[num+1]=
+
+ &mul ($word); # np[0]*m
+ &add ("eax",&DWP($frame,"esp")); # +=tp[0]
+ &lea ($num,&DWP(-1,$j));
+ &adc ("edx",0);
+ &mov ($j,1);
+ &mov ("eax",&DWP(4,$inp)); # np[1]
+
+ &jmp (&label("3rdmadd"));
+}
+
+&set_label("common_tail",16);
+ &mov ($np,$_np); # load modulus pointer
+ &mov ($rp,$_rp); # load result pointer
+ &lea ($tp,&DWP($frame,"esp")); # [$ap and $bp are zapped]
+
+ &mov ("eax",&DWP(0,$tp)); # tp[0]
+ &mov ($j,$num); # j=num-1
+ &xor ($i,$i); # i=0 and clear CF!
+
+&set_label("sub",16);
+ &sbb ("eax",&DWP(0,$np,$i,4));
+ &mov (&DWP(0,$rp,$i,4),"eax"); # rp[i]=tp[i]-np[i]
+ &dec ($j); # doesn't affect CF!
+ &mov ("eax",&DWP(4,$tp,$i,4)); # tp[i+1]
+ &lea ($i,&DWP(1,$i)); # i++
+ &jge (&label("sub"));
+
+ &sbb ("eax",0); # handle upmost overflow bit
+ &and ($tp,"eax");
+ ¬ ("eax");
+ &mov ($np,$rp);
+ &and ($np,"eax");
+ &or ($tp,$np); # tp=carry?tp:rp
+
+&set_label("copy",16); # copy or in-place refresh
+ &mov ("eax",&DWP(0,$tp,$num,4));
+ &mov (&DWP(0,$rp,$num,4),"eax"); # rp[i]=tp[i]
+ &mov (&DWP($frame,"esp",$num,4),$j); # zap temporary vector
+ &dec ($num);
+ &jge (&label("copy"));
+
+ &mov ("esp",$_sp); # pull saved stack pointer
+ &mov ("eax",1);
+&set_label("just_leave");
+&function_end("bn_mul_mont");
+
+&asciz("Montgomery Multiplication for x86, CRYPTOGAMS by <appro\@openssl.org>");
+
+&asm_finish();
diff --git a/crypto/bn/asm/x86.pl b/crypto/bn/asm/x86.pl
new file mode 100644
index 0000000..783f8dd
--- /dev/null
+++ b/crypto/bn/asm/x86.pl
@@ -0,0 +1,28 @@
+#!/usr/bin/env perl
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+push(@INC,"${dir}","${dir}../../perlasm");
+require "x86asm.pl";
+
+require("x86/mul_add.pl");
+require("x86/mul.pl");
+require("x86/sqr.pl");
+require("x86/div.pl");
+require("x86/add.pl");
+require("x86/sub.pl");
+require("x86/comba.pl");
+
+&asm_init($ARGV[0],$0);
+
+&bn_mul_add_words("bn_mul_add_words");
+&bn_mul_words("bn_mul_words");
+&bn_sqr_words("bn_sqr_words");
+&bn_div_words("bn_div_words");
+&bn_add_words("bn_add_words");
+&bn_sub_words("bn_sub_words");
+&bn_mul_comba("bn_mul_comba8",8);
+&bn_mul_comba("bn_mul_comba4",4);
+&bn_sqr_comba("bn_sqr_comba8",8);
+&bn_sqr_comba("bn_sqr_comba4",4);
+
+&asm_finish();
diff --git a/crypto/bn/asm/x86/add.pl b/crypto/bn/asm/x86/add.pl
new file mode 100644
index 0000000..0b5cf58
--- /dev/null
+++ b/crypto/bn/asm/x86/add.pl
@@ -0,0 +1,76 @@
+#!/usr/local/bin/perl
+# x86 assember
+
+sub bn_add_words
+ {
+ local($name)=@_;
+
+ &function_begin($name,"");
+
+ &comment("");
+ $a="esi";
+ $b="edi";
+ $c="eax";
+ $r="ebx";
+ $tmp1="ecx";
+ $tmp2="edx";
+ $num="ebp";
+
+ &mov($r,&wparam(0)); # get r
+ &mov($a,&wparam(1)); # get a
+ &mov($b,&wparam(2)); # get b
+ &mov($num,&wparam(3)); # get num
+ &xor($c,$c); # clear carry
+ &and($num,0xfffffff8); # num / 8
+
+ &jz(&label("aw_finish"));
+
+ &set_label("aw_loop",0);
+ for ($i=0; $i<8; $i++)
+ {
+ &comment("Round $i");
+
+ &mov($tmp1,&DWP($i*4,$a,"",0)); # *a
+ &mov($tmp2,&DWP($i*4,$b,"",0)); # *b
+ &add($tmp1,$c);
+ &mov($c,0);
+ &adc($c,$c);
+ &add($tmp1,$tmp2);
+ &adc($c,0);
+ &mov(&DWP($i*4,$r,"",0),$tmp1); # *r
+ }
+
+ &comment("");
+ &add($a,32);
+ &add($b,32);
+ &add($r,32);
+ &sub($num,8);
+ &jnz(&label("aw_loop"));
+
+ &set_label("aw_finish",0);
+ &mov($num,&wparam(3)); # get num
+ &and($num,7);
+ &jz(&label("aw_end"));
+
+ for ($i=0; $i<7; $i++)
+ {
+ &comment("Tail Round $i");
+ &mov($tmp1,&DWP($i*4,$a,"",0)); # *a
+ &mov($tmp2,&DWP($i*4,$b,"",0));# *b
+ &add($tmp1,$c);
+ &mov($c,0);
+ &adc($c,$c);
+ &add($tmp1,$tmp2);
+ &adc($c,0);
+ &dec($num) if ($i != 6);
+ &mov(&DWP($i*4,$r,"",0),$tmp1); # *a
+ &jz(&label("aw_end")) if ($i != 6);
+ }
+ &set_label("aw_end",0);
+
+# &mov("eax",$c); # $c is "eax"
+
+ &function_end($name);
+ }
+
+1;
diff --git a/crypto/bn/asm/x86/comba.pl b/crypto/bn/asm/x86/comba.pl
new file mode 100644
index 0000000..2291253
--- /dev/null
+++ b/crypto/bn/asm/x86/comba.pl
@@ -0,0 +1,277 @@
+#!/usr/local/bin/perl
+# x86 assember
+
+sub mul_add_c
+ {
+ local($a,$ai,$b,$bi,$c0,$c1,$c2,$pos,$i,$na,$nb)=@_;
+
+ # pos == -1 if eax and edx are pre-loaded, 0 to load from next
+ # words, and 1 if load return value
+
+ &comment("mul a[$ai]*b[$bi]");
+
+ # "eax" and "edx" will always be pre-loaded.
+ # &mov("eax",&DWP($ai*4,$a,"",0)) ;
+ # &mov("edx",&DWP($bi*4,$b,"",0));
+
+ &mul("edx");
+ &add($c0,"eax");
+ &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 0; # laod next a
+ &mov("eax",&wparam(0)) if $pos > 0; # load r[]
+ ###
+ &adc($c1,"edx");
+ &mov("edx",&DWP(($nb)*4,$b,"",0)) if $pos == 0; # laod next b
+ &mov("edx",&DWP(($nb)*4,$b,"",0)) if $pos == 1; # laod next b
+ ###
+ &adc($c2,0);
+ # is pos > 1, it means it is the last loop
+ &mov(&DWP($i*4,"eax","",0),$c0) if $pos > 0; # save r[];
+ &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 1; # laod next a
+ }
+
+sub sqr_add_c
+ {
+ local($r,$a,$ai,$bi,$c0,$c1,$c2,$pos,$i,$na,$nb)=@_;
+
+ # pos == -1 if eax and edx are pre-loaded, 0 to load from next
+ # words, and 1 if load return value
+
+ &comment("sqr a[$ai]*a[$bi]");
+
+ # "eax" and "edx" will always be pre-loaded.
+ # &mov("eax",&DWP($ai*4,$a,"",0)) ;
+ # &mov("edx",&DWP($bi*4,$b,"",0));
+
+ if ($ai == $bi)
+ { &mul("eax");}
+ else
+ { &mul("edx");}
+ &add($c0,"eax");
+ &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 0; # load next a
+ ###
+ &adc($c1,"edx");
+ &mov("edx",&DWP(($nb)*4,$a,"",0)) if ($pos == 1) && ($na != $nb);
+ ###
+ &adc($c2,0);
+ # is pos > 1, it means it is the last loop
+ &mov(&DWP($i*4,$r,"",0),$c0) if $pos > 0; # save r[];
+ &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 1; # load next b
+ }
+
+sub sqr_add_c2
+ {
+ local($r,$a,$ai,$bi,$c0,$c1,$c2,$pos,$i,$na,$nb)=@_;
+
+ # pos == -1 if eax and edx are pre-loaded, 0 to load from next
+ # words, and 1 if load return value
+
+ &comment("sqr a[$ai]*a[$bi]");
+
+ # "eax" and "edx" will always be pre-loaded.
+ # &mov("eax",&DWP($ai*4,$a,"",0)) ;
+ # &mov("edx",&DWP($bi*4,$a,"",0));
+
+ if ($ai == $bi)
+ { &mul("eax");}
+ else
+ { &mul("edx");}
+ &add("eax","eax");
+ ###
+ &adc("edx","edx");
+ ###
+ &adc($c2,0);
+ &add($c0,"eax");
+ &adc($c1,"edx");
+ &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 0; # load next a
+ &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 1; # load next b
+ &adc($c2,0);
+ &mov(&DWP($i*4,$r,"",0),$c0) if $pos > 0; # save r[];
+ &mov("edx",&DWP(($nb)*4,$a,"",0)) if ($pos <= 1) && ($na != $nb);
+ ###
+ }
+
+sub bn_mul_comba
+ {
+ local($name,$num)=@_;
+ local($a,$b,$c0,$c1,$c2);
+ local($i,$as,$ae,$bs,$be,$ai,$bi);
+ local($tot,$end);
+
+ &function_begin_B($name,"");
+
+ $c0="ebx";
+ $c1="ecx";
+ $c2="ebp";
+ $a="esi";
+ $b="edi";
+
+ $as=0;
+ $ae=0;
+ $bs=0;
+ $be=0;
+ $tot=$num+$num-1;
+
+ &push("esi");
+ &mov($a,&wparam(1));
+ &push("edi");
+ &mov($b,&wparam(2));
+ &push("ebp");
+ &push("ebx");
+
+ &xor($c0,$c0);
+ &mov("eax",&DWP(0,$a,"",0)); # load the first word
+ &xor($c1,$c1);
+ &mov("edx",&DWP(0,$b,"",0)); # load the first second
+
+ for ($i=0; $i<$tot; $i++)
+ {
+ $ai=$as;
+ $bi=$bs;
+ $end=$be+1;
+
+ &comment("################## Calculate word $i");
+
+ for ($j=$bs; $j<$end; $j++)
+ {
+ &xor($c2,$c2) if ($j == $bs);
+ if (($j+1) == $end)
+ {
+ $v=1;
+ $v=2 if (($i+1) == $tot);
+ }
+ else
+ { $v=0; }
+ if (($j+1) != $end)
+ {
+ $na=($ai-1);
+ $nb=($bi+1);
+ }
+ else
+ {
+ $na=$as+($i < ($num-1));
+ $nb=$bs+($i >= ($num-1));
+ }
+#printf STDERR "[$ai,$bi] -> [$na,$nb]\n";
+ &mul_add_c($a,$ai,$b,$bi,$c0,$c1,$c2,$v,$i,$na,$nb);
+ if ($v)
+ {
+ &comment("saved r[$i]");
+ # &mov("eax",&wparam(0));
+ # &mov(&DWP($i*4,"eax","",0),$c0);
+ ($c0,$c1,$c2)=($c1,$c2,$c0);
+ }
+ $ai--;
+ $bi++;
+ }
+ $as++ if ($i < ($num-1));
+ $ae++ if ($i >= ($num-1));
+
+ $bs++ if ($i >= ($num-1));
+ $be++ if ($i < ($num-1));
+ }
+ &comment("save r[$i]");
+ # &mov("eax",&wparam(0));
+ &mov(&DWP($i*4,"eax","",0),$c0);
+
+ &pop("ebx");
+ &pop("ebp");
+ &pop("edi");
+ &pop("esi");
+ &ret();
+ &function_end_B($name);
+ }
+
+sub bn_sqr_comba
+ {
+ local($name,$num)=@_;
+ local($r,$a,$c0,$c1,$c2)=@_;
+ local($i,$as,$ae,$bs,$be,$ai,$bi);
+ local($b,$tot,$end,$half);
+
+ &function_begin_B($name,"");
+
+ $c0="ebx";
+ $c1="ecx";
+ $c2="ebp";
+ $a="esi";
+ $r="edi";
+
+ &push("esi");
+ &push("edi");
+ &push("ebp");
+ &push("ebx");
+ &mov($r,&wparam(0));
+ &mov($a,&wparam(1));
+ &xor($c0,$c0);
+ &xor($c1,$c1);
+ &mov("eax",&DWP(0,$a,"",0)); # load the first word
+
+ $as=0;
+ $ae=0;
+ $bs=0;
+ $be=0;
+ $tot=$num+$num-1;
+
+ for ($i=0; $i<$tot; $i++)
+ {
+ $ai=$as;
+ $bi=$bs;
+ $end=$be+1;
+
+ &comment("############### Calculate word $i");
+ for ($j=$bs; $j<$end; $j++)
+ {
+ &xor($c2,$c2) if ($j == $bs);
+ if (($ai-1) < ($bi+1))
+ {
+ $v=1;
+ $v=2 if ($i+1) == $tot;
+ }
+ else
+ { $v=0; }
+ if (!$v)
+ {
+ $na=$ai-1;
+ $nb=$bi+1;
+ }
+ else
+ {
+ $na=$as+($i < ($num-1));
+ $nb=$bs+($i >= ($num-1));
+ }
+ if ($ai == $bi)
+ {
+ &sqr_add_c($r,$a,$ai,$bi,
+ $c0,$c1,$c2,$v,$i,$na,$nb);
+ }
+ else
+ {
+ &sqr_add_c2($r,$a,$ai,$bi,
+ $c0,$c1,$c2,$v,$i,$na,$nb);
+ }
+ if ($v)
+ {
+ &comment("saved r[$i]");
+ #&mov(&DWP($i*4,$r,"",0),$c0);
+ ($c0,$c1,$c2)=($c1,$c2,$c0);
+ last;
+ }
+ $ai--;
+ $bi++;
+ }
+ $as++ if ($i < ($num-1));
+ $ae++ if ($i >= ($num-1));
+
+ $bs++ if ($i >= ($num-1));
+ $be++ if ($i < ($num-1));
+ }
+ &mov(&DWP($i*4,$r,"",0),$c0);
+ &pop("ebx");
+ &pop("ebp");
+ &pop("edi");
+ &pop("esi");
+ &ret();
+ &function_end_B($name);
+ }
+
+1;
diff --git a/crypto/bn/asm/x86/div.pl b/crypto/bn/asm/x86/div.pl
new file mode 100644
index 0000000..0e90152
--- /dev/null
+++ b/crypto/bn/asm/x86/div.pl
@@ -0,0 +1,15 @@
+#!/usr/local/bin/perl
+# x86 assember
+
+sub bn_div_words
+ {
+ local($name)=@_;
+
+ &function_begin($name,"");
+ &mov("edx",&wparam(0)); #
+ &mov("eax",&wparam(1)); #
+ &mov("ebx",&wparam(2)); #
+ &div("ebx");
+ &function_end($name);
+ }
+1;
diff --git a/crypto/bn/asm/x86/mul.pl b/crypto/bn/asm/x86/mul.pl
new file mode 100644
index 0000000..674cb9b
--- /dev/null
+++ b/crypto/bn/asm/x86/mul.pl
@@ -0,0 +1,77 @@
+#!/usr/local/bin/perl
+# x86 assember
+
+sub bn_mul_words
+ {
+ local($name)=@_;
+
+ &function_begin($name,"");
+
+ &comment("");
+ $Low="eax";
+ $High="edx";
+ $a="ebx";
+ $w="ecx";
+ $r="edi";
+ $c="esi";
+ $num="ebp";
+
+ &xor($c,$c); # clear carry
+ &mov($r,&wparam(0)); #
+ &mov($a,&wparam(1)); #
+ &mov($num,&wparam(2)); #
+ &mov($w,&wparam(3)); #
+
+ &and($num,0xfffffff8); # num / 8
+ &jz(&label("mw_finish"));
+
+ &set_label("mw_loop",0);
+ for ($i=0; $i<32; $i+=4)
+ {
+ &comment("Round $i");
+
+ &mov("eax",&DWP($i,$a,"",0)); # *a
+ &mul($w); # *a * w
+ &add("eax",$c); # L(t)+=c
+ # XXX
+
+ &adc("edx",0); # H(t)+=carry
+ &mov(&DWP($i,$r,"",0),"eax"); # *r= L(t);
+
+ &mov($c,"edx"); # c= H(t);
+ }
+
+ &comment("");
+ &add($a,32);
+ &add($r,32);
+ &sub($num,8);
+ &jz(&label("mw_finish"));
+ &jmp(&label("mw_loop"));
+
+ &set_label("mw_finish",0);
+ &mov($num,&wparam(2)); # get num
+ &and($num,7);
+ &jnz(&label("mw_finish2"));
+ &jmp(&label("mw_end"));
+
+ &set_label("mw_finish2",1);
+ for ($i=0; $i<7; $i++)
+ {
+ &comment("Tail Round $i");
+ &mov("eax",&DWP($i*4,$a,"",0));# *a
+ &mul($w); # *a * w
+ &add("eax",$c); # L(t)+=c
+ # XXX
+ &adc("edx",0); # H(t)+=carry
+ &mov(&DWP($i*4,$r,"",0),"eax");# *r= L(t);
+ &mov($c,"edx"); # c= H(t);
+ &dec($num) if ($i != 7-1);
+ &jz(&label("mw_end")) if ($i != 7-1);
+ }
+ &set_label("mw_end",0);
+ &mov("eax",$c);
+
+ &function_end($name);
+ }
+
+1;
diff --git a/crypto/bn/asm/x86/mul_add.pl b/crypto/bn/asm/x86/mul_add.pl
new file mode 100644
index 0000000..61830d3
--- /dev/null
+++ b/crypto/bn/asm/x86/mul_add.pl
@@ -0,0 +1,87 @@
+#!/usr/local/bin/perl
+# x86 assember
+
+sub bn_mul_add_words
+ {
+ local($name)=@_;
+
+ &function_begin($name,"");
+
+ &comment("");
+ $Low="eax";
+ $High="edx";
+ $a="ebx";
+ $w="ebp";
+ $r="edi";
+ $c="esi";
+
+ &xor($c,$c); # clear carry
+ &mov($r,&wparam(0)); #
+
+ &mov("ecx",&wparam(2)); #
+ &mov($a,&wparam(1)); #
+
+ &and("ecx",0xfffffff8); # num / 8
+ &mov($w,&wparam(3)); #
+
+ &push("ecx"); # Up the stack for a tmp variable
+
+ &jz(&label("maw_finish"));
+
+ &set_label("maw_loop",0);
+
+ &mov(&swtmp(0),"ecx"); #
+
+ for ($i=0; $i<32; $i+=4)
+ {
+ &comment("Round $i");
+
+ &mov("eax",&DWP($i,$a,"",0)); # *a
+ &mul($w); # *a * w
+ &add("eax",$c); # L(t)+= *r
+ &mov($c,&DWP($i,$r,"",0)); # L(t)+= *r
+ &adc("edx",0); # H(t)+=carry
+ &add("eax",$c); # L(t)+=c
+ &adc("edx",0); # H(t)+=carry
+ &mov(&DWP($i,$r,"",0),"eax"); # *r= L(t);
+ &mov($c,"edx"); # c= H(t);
+ }
+
+ &comment("");
+ &mov("ecx",&swtmp(0)); #
+ &add($a,32);
+ &add($r,32);
+ &sub("ecx",8);
+ &jnz(&label("maw_loop"));
+
+ &set_label("maw_finish",0);
+ &mov("ecx",&wparam(2)); # get num
+ &and("ecx",7);
+ &jnz(&label("maw_finish2")); # helps branch prediction
+ &jmp(&label("maw_end"));
+
+ &set_label("maw_finish2",1);
+ for ($i=0; $i<7; $i++)
+ {
+ &comment("Tail Round $i");
+ &mov("eax",&DWP($i*4,$a,"",0));# *a
+ &mul($w); # *a * w
+ &add("eax",$c); # L(t)+=c
+ &mov($c,&DWP($i*4,$r,"",0)); # L(t)+= *r
+ &adc("edx",0); # H(t)+=carry
+ &add("eax",$c);
+ &adc("edx",0); # H(t)+=carry
+ &dec("ecx") if ($i != 7-1);
+ &mov(&DWP($i*4,$r,"",0),"eax"); # *r= L(t);
+ &mov($c,"edx"); # c= H(t);
+ &jz(&label("maw_end")) if ($i != 7-1);
+ }
+ &set_label("maw_end",0);
+ &mov("eax",$c);
+
+ &pop("ecx"); # clear variable from
+
+ &function_end($name);
+ }
+
+1;
diff --git a/crypto/bn/asm/x86/sqr.pl b/crypto/bn/asm/x86/sqr.pl
new file mode 100644
index 0000000..1f90993
--- /dev/null
+++ b/crypto/bn/asm/x86/sqr.pl
@@ -0,0 +1,60 @@
+#!/usr/local/bin/perl
+# x86 assember
+
+sub bn_sqr_words
+ {
+ local($name)=@_;
+
+ &function_begin($name,"");
+
+ &comment("");
+ $r="esi";
+ $a="edi";
+ $num="ebx";
+
+ &mov($r,&wparam(0)); #
+ &mov($a,&wparam(1)); #
+ &mov($num,&wparam(2)); #
+
+ &and($num,0xfffffff8); # num / 8
+ &jz(&label("sw_finish"));
+
+ &set_label("sw_loop",0);
+ for ($i=0; $i<32; $i+=4)
+ {
+ &comment("Round $i");
+ &mov("eax",&DWP($i,$a,"",0)); # *a
+ # XXX
+ &mul("eax"); # *a * *a
+ &mov(&DWP($i*2,$r,"",0),"eax"); #
+ &mov(&DWP($i*2+4,$r,"",0),"edx");#
+ }
+
+ &comment("");
+ &add($a,32);
+ &add($r,64);
+ &sub($num,8);
+ &jnz(&label("sw_loop"));
+
+ &set_label("sw_finish",0);
+ &mov($num,&wparam(2)); # get num
+ &and($num,7);
+ &jz(&label("sw_end"));
+
+ for ($i=0; $i<7; $i++)
+ {
+ &comment("Tail Round $i");
+ &mov("eax",&DWP($i*4,$a,"",0)); # *a
+ # XXX
+ &mul("eax"); # *a * *a
+ &mov(&DWP($i*8,$r,"",0),"eax"); #
+ &dec($num) if ($i != 7-1);
+ &mov(&DWP($i*8+4,$r,"",0),"edx");
+ &jz(&label("sw_end")) if ($i != 7-1);
+ }
+ &set_label("sw_end",0);
+
+ &function_end($name);
+ }
+
+1;
diff --git a/crypto/bn/asm/x86/sub.pl b/crypto/bn/asm/x86/sub.pl
new file mode 100644
index 0000000..837b0e1
--- /dev/null
+++ b/crypto/bn/asm/x86/sub.pl
@@ -0,0 +1,76 @@
+#!/usr/local/bin/perl
+# x86 assember
+
+sub bn_sub_words
+ {
+ local($name)=@_;
+
+ &function_begin($name,"");
+
+ &comment("");
+ $a="esi";
+ $b="edi";
+ $c="eax";
+ $r="ebx";
+ $tmp1="ecx";
+ $tmp2="edx";
+ $num="ebp";
+
+ &mov($r,&wparam(0)); # get r
+ &mov($a,&wparam(1)); # get a
+ &mov($b,&wparam(2)); # get b
+ &mov($num,&wparam(3)); # get num
+ &xor($c,$c); # clear carry
+ &and($num,0xfffffff8); # num / 8
+
+ &jz(&label("aw_finish"));
+
+ &set_label("aw_loop",0);
+ for ($i=0; $i<8; $i++)
+ {
+ &comment("Round $i");
+
+ &mov($tmp1,&DWP($i*4,$a,"",0)); # *a
+ &mov($tmp2,&DWP($i*4,$b,"",0)); # *b
+ &sub($tmp1,$c);
+ &mov($c,0);
+ &adc($c,$c);
+ &sub($tmp1,$tmp2);
+ &adc($c,0);
+ &mov(&DWP($i*4,$r,"",0),$tmp1); # *r
+ }
+
+ &comment("");
+ &add($a,32);
+ &add($b,32);
+ &add($r,32);
+ &sub($num,8);
+ &jnz(&label("aw_loop"));
+
+ &set_label("aw_finish",0);
+ &mov($num,&wparam(3)); # get num
+ &and($num,7);
+ &jz(&label("aw_end"));
+
+ for ($i=0; $i<7; $i++)
+ {
+ &comment("Tail Round $i");
+ &mov($tmp1,&DWP($i*4,$a,"",0)); # *a
+ &mov($tmp2,&DWP($i*4,$b,"",0));# *b
+ &sub($tmp1,$c);
+ &mov($c,0);
+ &adc($c,$c);
+ &sub($tmp1,$tmp2);
+ &adc($c,0);
+ &dec($num) if ($i != 6);
+ &mov(&DWP($i*4,$r,"",0),$tmp1); # *a
+ &jz(&label("aw_end")) if ($i != 6);
+ }
+ &set_label("aw_end",0);
+
+# &mov("eax",$c); # $c is "eax"
+
+ &function_end($name);
+ }
+
+1;
diff --git a/crypto/bn/asm/x86_64-gcc.c b/crypto/bn/asm/x86_64-gcc.c
new file mode 100644
index 0000000..836f001
--- /dev/null
+++ b/crypto/bn/asm/x86_64-gcc.c
@@ -0,0 +1,613 @@
+#include <openssl/bn.h>
+
+#if defined(OPENSSL_X86_64) && !defined(OPENSSL_WINDOWS)
+
+#include "../internal.h"
+
+/* x86_64 BIGNUM accelerator version 0.1, December 2002.
+ *
+ * Implemented by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
+ * project.
+ *
+ * Rights for redistribution and usage in source and binary forms are
+ * granted according to the OpenSSL license. Warranty of any kind is
+ * disclaimed.
+ *
+ * Q. Version 0.1? It doesn't sound like Andy, he used to assign real
+ * versions, like 1.0...
+ * A. Well, that's because this code is basically a quick-n-dirty
+ * proof-of-concept hack. As you can see it's implemented with
+ * inline assembler, which means that you're bound to GCC and that
+ * there might be enough room for further improvement.
+ *
+ * Q. Why inline assembler?
+ * A. x86_64 features own ABI which I'm not familiar with. This is
+ * why I decided to let the compiler take care of subroutine
+ * prologue/epilogue as well as register allocation. For reference.
+ * Win64 implements different ABI for AMD64, different from Linux.
+ *
+ * Q. How much faster does it get?
+ * A. 'apps/openssl speed rsa dsa' output with no-asm:
+ *
+ * sign verify sign/s verify/s
+ * rsa 512 bits 0.0006s 0.0001s 1683.8 18456.2
+ * rsa 1024 bits 0.0028s 0.0002s 356.0 6407.0
+ * rsa 2048 bits 0.0172s 0.0005s 58.0 1957.8
+ * rsa 4096 bits 0.1155s 0.0018s 8.7 555.6
+ * sign verify sign/s verify/s
+ * dsa 512 bits 0.0005s 0.0006s 2100.8 1768.3
+ * dsa 1024 bits 0.0014s 0.0018s 692.3 559.2
+ * dsa 2048 bits 0.0049s 0.0061s 204.7 165.0
+ *
+ * 'apps/openssl speed rsa dsa' output with this module:
+ *
+ * sign verify sign/s verify/s
+ * rsa 512 bits 0.0004s 0.0000s 2767.1 33297.9
+ * rsa 1024 bits 0.0012s 0.0001s 867.4 14674.7
+ * rsa 2048 bits 0.0061s 0.0002s 164.0 5270.0
+ * rsa 4096 bits 0.0384s 0.0006s 26.1 1650.8
+ * sign verify sign/s verify/s
+ * dsa 512 bits 0.0002s 0.0003s 4442.2 3786.3
+ * dsa 1024 bits 0.0005s 0.0007s 1835.1 1497.4
+ * dsa 2048 bits 0.0016s 0.0020s 620.4 504.6
+ *
+ * For the reference. IA-32 assembler implementation performs
+ * very much like 64-bit code compiled with no-asm on the same
+ * machine.
+ */
+
+#undef mul
+#undef mul_add
+
+#define asm __asm__
+
+/*
+ * "m"(a), "+m"(r) is the way to favor DirectPath µ-code;
+ * "g"(0) let the compiler to decide where does it
+ * want to keep the value of zero;
+ */
+#define mul_add(r, a, word, carry) \
+ do { \
+ register BN_ULONG high, low; \
+ asm("mulq %3" : "=a"(low), "=d"(high) : "a"(word), "m"(a) : "cc"); \
+ asm("addq %2,%0; adcq %3,%1" \
+ : "+r"(carry), "+d"(high) \
+ : "a"(low), "g"(0) \
+ : "cc"); \
+ asm("addq %2,%0; adcq %3,%1" \
+ : "+m"(r), "+d"(high) \
+ : "r"(carry), "g"(0) \
+ : "cc"); \
+ carry = high; \
+ } while (0)
+
+#define mul(r, a, word, carry) \
+ do { \
+ register BN_ULONG high, low; \
+ asm("mulq %3" : "=a"(low), "=d"(high) : "a"(word), "g"(a) : "cc"); \
+ asm("addq %2,%0; adcq %3,%1" \
+ : "+r"(carry), "+d"(high) \
+ : "a"(low), "g"(0) \
+ : "cc"); \
+ (r) = carry, carry = high; \
+ } while (0)
+#undef sqr
+#define sqr(r0, r1, a) asm("mulq %2" : "=a"(r0), "=d"(r1) : "a"(a) : "cc");
+
+BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num,
+ BN_ULONG w) {
+ BN_ULONG c1 = 0;
+
+ if (num <= 0)
+ return (c1);
+
+ while (num & ~3) {
+ mul_add(rp[0], ap[0], w, c1);
+ mul_add(rp[1], ap[1], w, c1);
+ mul_add(rp[2], ap[2], w, c1);
+ mul_add(rp[3], ap[3], w, c1);
+ ap += 4;
+ rp += 4;
+ num -= 4;
+ }
+ if (num) {
+ mul_add(rp[0], ap[0], w, c1);
+ if (--num == 0)
+ return c1;
+ mul_add(rp[1], ap[1], w, c1);
+ if (--num == 0)
+ return c1;
+ mul_add(rp[2], ap[2], w, c1);
+ return c1;
+ }
+
+ return (c1);
+}
+
+BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w) {
+ BN_ULONG c1 = 0;
+
+ if (num <= 0)
+ return (c1);
+
+ while (num & ~3) {
+ mul(rp[0], ap[0], w, c1);
+ mul(rp[1], ap[1], w, c1);
+ mul(rp[2], ap[2], w, c1);
+ mul(rp[3], ap[3], w, c1);
+ ap += 4;
+ rp += 4;
+ num -= 4;
+ }
+ if (num) {
+ mul(rp[0], ap[0], w, c1);
+ if (--num == 0)
+ return c1;
+ mul(rp[1], ap[1], w, c1);
+ if (--num == 0)
+ return c1;
+ mul(rp[2], ap[2], w, c1);
+ }
+ return (c1);
+}
+
+void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, int n) {
+ if (n <= 0)
+ return;
+
+ while (n & ~3) {
+ sqr(r[0], r[1], a[0]);
+ sqr(r[2], r[3], a[1]);
+ sqr(r[4], r[5], a[2]);
+ sqr(r[6], r[7], a[3]);
+ a += 4;
+ r += 8;
+ n -= 4;
+ }
+ if (n) {
+ sqr(r[0], r[1], a[0]);
+ if (--n == 0)
+ return;
+ sqr(r[2], r[3], a[1]);
+ if (--n == 0)
+ return;
+ sqr(r[4], r[5], a[2]);
+ }
+}
+
+BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d) {
+ BN_ULONG ret, waste;
+
+ asm("divq %4" : "=a"(ret), "=d"(waste) : "a"(l), "d"(h), "g"(d) : "cc");
+
+ return ret;
+}
+
+BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
+ int n) {
+ BN_ULONG ret;
+ size_t i = 0;
+
+ if (n <= 0)
+ return 0;
+
+ asm(" subq %0,%0 \n" /* clear carry */
+ " jmp 1f \n"
+ ".p2align 4 \n"
+ "1: movq (%4,%2,8),%0 \n"
+ " adcq (%5,%2,8),%0 \n"
+ " movq %0,(%3,%2,8) \n"
+ " lea 1(%2),%2 \n"
+ " loop 1b \n"
+ " sbbq %0,%0 \n"
+ : "=&r"(ret), "+c"(n), "+r"(i)
+ : "r"(rp), "r"(ap), "r"(bp)
+ : "cc");
+
+ return ret & 1;
+}
+
+#ifndef SIMICS
+BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
+ int n) {
+ BN_ULONG ret;
+ size_t i = 0;
+
+ if (n <= 0)
+ return 0;
+
+ asm(" subq %0,%0 \n" /* clear borrow */
+ " jmp 1f \n"
+ ".p2align 4 \n"
+ "1: movq (%4,%2,8),%0 \n"
+ " sbbq (%5,%2,8),%0 \n"
+ " movq %0,(%3,%2,8) \n"
+ " lea 1(%2),%2 \n"
+ " loop 1b \n"
+ " sbbq %0,%0 \n"
+ : "=&r"(ret), "+c"(n), "+r"(i)
+ : "r"(rp), "r"(ap), "r"(bp)
+ : "cc");
+
+ return ret & 1;
+}
+#else
+/* Simics 1.4<7 has buggy sbbq:-( */
+#define BN_MASK2 0xffffffffffffffffL
+BN_ULONG bn_sub_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n) {
+ BN_ULONG t1, t2;
+ int c = 0;
+
+ if (n <= 0)
+ return ((BN_ULONG)0);
+
+ for (;;) {
+ t1 = a[0];
+ t2 = b[0];
+ r[0] = (t1 - t2 - c) & BN_MASK2;
+ if (t1 != t2)
+ c = (t1 < t2);
+ if (--n <= 0)
+ break;
+
+ t1 = a[1];
+ t2 = b[1];
+ r[1] = (t1 - t2 - c) & BN_MASK2;
+ if (t1 != t2)
+ c = (t1 < t2);
+ if (--n <= 0)
+ break;
+
+ t1 = a[2];
+ t2 = b[2];
+ r[2] = (t1 - t2 - c) & BN_MASK2;
+ if (t1 != t2)
+ c = (t1 < t2);
+ if (--n <= 0)
+ break;
+
+ t1 = a[3];
+ t2 = b[3];
+ r[3] = (t1 - t2 - c) & BN_MASK2;
+ if (t1 != t2)
+ c = (t1 < t2);
+ if (--n <= 0)
+ break;
+
+ a += 4;
+ b += 4;
+ r += 4;
+ }
+ return (c);
+}
+#endif
+
+/* mul_add_c(a,b,c0,c1,c2) -- c+=a*b for three word number c=(c2,c1,c0) */
+/* mul_add_c2(a,b,c0,c1,c2) -- c+=2*a*b for three word number c=(c2,c1,c0) */
+/* sqr_add_c(a,i,c0,c1,c2) -- c+=a[i]^2 for three word number c=(c2,c1,c0) */
+/* sqr_add_c2(a,i,c0,c1,c2) -- c+=2*a[i]*a[j] for three word number c=(c2,c1,c0)
+ */
+
+#if 0
+/* original macros are kept for reference purposes */
+#define mul_add_c(a, b, c0, c1, c2) \
+ { \
+ BN_ULONG ta = (a), tb = (b); \
+ t1 = ta * tb; \
+ t2 = BN_UMULT_HIGH(ta, tb); \
+ c0 += t1; \
+ t2 += (c0 < t1) ? 1 : 0; \
+ c1 += t2; \
+ c2 += (c1 < t2) ? 1 : 0; \
+ }
+
+#define mul_add_c2(a, b, c0, c1, c2) \
+ { \
+ BN_ULONG ta = (a), tb = (b), t0; \
+ t1 = BN_UMULT_HIGH(ta, tb); \
+ t0 = ta * tb; \
+ t2 = t1 + t1; \
+ c2 += (t2 < t1) ? 1 : 0; \
+ t1 = t0 + t0; \
+ t2 += (t1 < t0) ? 1 : 0; \
+ c0 += t1; \
+ t2 += (c0 < t1) ? 1 : 0; \
+ c1 += t2; \
+ c2 += (c1 < t2) ? 1 : 0; \
+ }
+#else
+#define mul_add_c(a, b, c0, c1, c2) \
+ do { \
+ asm("mulq %3" : "=a"(t1), "=d"(t2) : "a"(a), "m"(b) : "cc"); \
+ asm("addq %2,%0; adcq %3,%1" \
+ : "+r"(c0), "+d"(t2) \
+ : "a"(t1), "g"(0) \
+ : "cc"); \
+ asm("addq %2,%0; adcq %3,%1" \
+ : "+r"(c1), "+r"(c2) \
+ : "d"(t2), "g"(0) \
+ : "cc"); \
+ } while (0)
+
+#define sqr_add_c(a, i, c0, c1, c2) \
+ do { \
+ asm("mulq %2" : "=a"(t1), "=d"(t2) : "a"(a[i]) : "cc"); \
+ asm("addq %2,%0; adcq %3,%1" \
+ : "+r"(c0), "+d"(t2) \
+ : "a"(t1), "g"(0) \
+ : "cc"); \
+ asm("addq %2,%0; adcq %3,%1" \
+ : "+r"(c1), "+r"(c2) \
+ : "d"(t2), "g"(0) \
+ : "cc"); \
+ } while (0)
+
+#define mul_add_c2(a, b, c0, c1, c2) \
+ do { \
+ asm("mulq %3" : "=a"(t1), "=d"(t2) : "a"(a), "m"(b) : "cc"); \
+ asm("addq %0,%0; adcq %2,%1" : "+d"(t2), "+r"(c2) : "g"(0) : "cc"); \
+ asm("addq %0,%0; adcq %2,%1" : "+a"(t1), "+d"(t2) : "g"(0) : "cc"); \
+ asm("addq %2,%0; adcq %3,%1" \
+ : "+r"(c0), "+d"(t2) \
+ : "a"(t1), "g"(0) \
+ : "cc"); \
+ asm("addq %2,%0; adcq %3,%1" \
+ : "+r"(c1), "+r"(c2) \
+ : "d"(t2), "g"(0) \
+ : "cc"); \
+ } while (0)
+#endif
+
+#define sqr_add_c2(a, i, j, c0, c1, c2) mul_add_c2((a)[i], (a)[j], c0, c1, c2)
+
+void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) {
+ BN_ULONG t1, t2;
+ BN_ULONG c1, c2, c3;
+
+ c1 = 0;
+ c2 = 0;
+ c3 = 0;
+ mul_add_c(a[0], b[0], c1, c2, c3);
+ r[0] = c1;
+ c1 = 0;
+ mul_add_c(a[0], b[1], c2, c3, c1);
+ mul_add_c(a[1], b[0], c2, c3, c1);
+ r[1] = c2;
+ c2 = 0;
+ mul_add_c(a[2], b[0], c3, c1, c2);
+ mul_add_c(a[1], b[1], c3, c1, c2);
+ mul_add_c(a[0], b[2], c3, c1, c2);
+ r[2] = c3;
+ c3 = 0;
+ mul_add_c(a[0], b[3], c1, c2, c3);
+ mul_add_c(a[1], b[2], c1, c2, c3);
+ mul_add_c(a[2], b[1], c1, c2, c3);
+ mul_add_c(a[3], b[0], c1, c2, c3);
+ r[3] = c1;
+ c1 = 0;
+ mul_add_c(a[4], b[0], c2, c3, c1);
+ mul_add_c(a[3], b[1], c2, c3, c1);
+ mul_add_c(a[2], b[2], c2, c3, c1);
+ mul_add_c(a[1], b[3], c2, c3, c1);
+ mul_add_c(a[0], b[4], c2, c3, c1);
+ r[4] = c2;
+ c2 = 0;
+ mul_add_c(a[0], b[5], c3, c1, c2);
+ mul_add_c(a[1], b[4], c3, c1, c2);
+ mul_add_c(a[2], b[3], c3, c1, c2);
+ mul_add_c(a[3], b[2], c3, c1, c2);
+ mul_add_c(a[4], b[1], c3, c1, c2);
+ mul_add_c(a[5], b[0], c3, c1, c2);
+ r[5] = c3;
+ c3 = 0;
+ mul_add_c(a[6], b[0], c1, c2, c3);
+ mul_add_c(a[5], b[1], c1, c2, c3);
+ mul_add_c(a[4], b[2], c1, c2, c3);
+ mul_add_c(a[3], b[3], c1, c2, c3);
+ mul_add_c(a[2], b[4], c1, c2, c3);
+ mul_add_c(a[1], b[5], c1, c2, c3);
+ mul_add_c(a[0], b[6], c1, c2, c3);
+ r[6] = c1;
+ c1 = 0;
+ mul_add_c(a[0], b[7], c2, c3, c1);
+ mul_add_c(a[1], b[6], c2, c3, c1);
+ mul_add_c(a[2], b[5], c2, c3, c1);
+ mul_add_c(a[3], b[4], c2, c3, c1);
+ mul_add_c(a[4], b[3], c2, c3, c1);
+ mul_add_c(a[5], b[2], c2, c3, c1);
+ mul_add_c(a[6], b[1], c2, c3, c1);
+ mul_add_c(a[7], b[0], c2, c3, c1);
+ r[7] = c2;
+ c2 = 0;
+ mul_add_c(a[7], b[1], c3, c1, c2);
+ mul_add_c(a[6], b[2], c3, c1, c2);
+ mul_add_c(a[5], b[3], c3, c1, c2);
+ mul_add_c(a[4], b[4], c3, c1, c2);
+ mul_add_c(a[3], b[5], c3, c1, c2);
+ mul_add_c(a[2], b[6], c3, c1, c2);
+ mul_add_c(a[1], b[7], c3, c1, c2);
+ r[8] = c3;
+ c3 = 0;
+ mul_add_c(a[2], b[7], c1, c2, c3);
+ mul_add_c(a[3], b[6], c1, c2, c3);
+ mul_add_c(a[4], b[5], c1, c2, c3);
+ mul_add_c(a[5], b[4], c1, c2, c3);
+ mul_add_c(a[6], b[3], c1, c2, c3);
+ mul_add_c(a[7], b[2], c1, c2, c3);
+ r[9] = c1;
+ c1 = 0;
+ mul_add_c(a[7], b[3], c2, c3, c1);
+ mul_add_c(a[6], b[4], c2, c3, c1);
+ mul_add_c(a[5], b[5], c2, c3, c1);
+ mul_add_c(a[4], b[6], c2, c3, c1);
+ mul_add_c(a[3], b[7], c2, c3, c1);
+ r[10] = c2;
+ c2 = 0;
+ mul_add_c(a[4], b[7], c3, c1, c2);
+ mul_add_c(a[5], b[6], c3, c1, c2);
+ mul_add_c(a[6], b[5], c3, c1, c2);
+ mul_add_c(a[7], b[4], c3, c1, c2);
+ r[11] = c3;
+ c3 = 0;
+ mul_add_c(a[7], b[5], c1, c2, c3);
+ mul_add_c(a[6], b[6], c1, c2, c3);
+ mul_add_c(a[5], b[7], c1, c2, c3);
+ r[12] = c1;
+ c1 = 0;
+ mul_add_c(a[6], b[7], c2, c3, c1);
+ mul_add_c(a[7], b[6], c2, c3, c1);
+ r[13] = c2;
+ c2 = 0;
+ mul_add_c(a[7], b[7], c3, c1, c2);
+ r[14] = c3;
+ r[15] = c1;
+}
+
+void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) {
+ BN_ULONG t1, t2;
+ BN_ULONG c1, c2, c3;
+
+ c1 = 0;
+ c2 = 0;
+ c3 = 0;
+ mul_add_c(a[0], b[0], c1, c2, c3);
+ r[0] = c1;
+ c1 = 0;
+ mul_add_c(a[0], b[1], c2, c3, c1);
+ mul_add_c(a[1], b[0], c2, c3, c1);
+ r[1] = c2;
+ c2 = 0;
+ mul_add_c(a[2], b[0], c3, c1, c2);
+ mul_add_c(a[1], b[1], c3, c1, c2);
+ mul_add_c(a[0], b[2], c3, c1, c2);
+ r[2] = c3;
+ c3 = 0;
+ mul_add_c(a[0], b[3], c1, c2, c3);
+ mul_add_c(a[1], b[2], c1, c2, c3);
+ mul_add_c(a[2], b[1], c1, c2, c3);
+ mul_add_c(a[3], b[0], c1, c2, c3);
+ r[3] = c1;
+ c1 = 0;
+ mul_add_c(a[3], b[1], c2, c3, c1);
+ mul_add_c(a[2], b[2], c2, c3, c1);
+ mul_add_c(a[1], b[3], c2, c3, c1);
+ r[4] = c2;
+ c2 = 0;
+ mul_add_c(a[2], b[3], c3, c1, c2);
+ mul_add_c(a[3], b[2], c3, c1, c2);
+ r[5] = c3;
+ c3 = 0;
+ mul_add_c(a[3], b[3], c1, c2, c3);
+ r[6] = c1;
+ r[7] = c2;
+}
+
+void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a) {
+ BN_ULONG t1, t2;
+ BN_ULONG c1, c2, c3;
+
+ c1 = 0;
+ c2 = 0;
+ c3 = 0;
+ sqr_add_c(a, 0, c1, c2, c3);
+ r[0] = c1;
+ c1 = 0;
+ sqr_add_c2(a, 1, 0, c2, c3, c1);
+ r[1] = c2;
+ c2 = 0;
+ sqr_add_c(a, 1, c3, c1, c2);
+ sqr_add_c2(a, 2, 0, c3, c1, c2);
+ r[2] = c3;
+ c3 = 0;
+ sqr_add_c2(a, 3, 0, c1, c2, c3);
+ sqr_add_c2(a, 2, 1, c1, c2, c3);
+ r[3] = c1;
+ c1 = 0;
+ sqr_add_c(a, 2, c2, c3, c1);
+ sqr_add_c2(a, 3, 1, c2, c3, c1);
+ sqr_add_c2(a, 4, 0, c2, c3, c1);
+ r[4] = c2;
+ c2 = 0;
+ sqr_add_c2(a, 5, 0, c3, c1, c2);
+ sqr_add_c2(a, 4, 1, c3, c1, c2);
+ sqr_add_c2(a, 3, 2, c3, c1, c2);
+ r[5] = c3;
+ c3 = 0;
+ sqr_add_c(a, 3, c1, c2, c3);
+ sqr_add_c2(a, 4, 2, c1, c2, c3);
+ sqr_add_c2(a, 5, 1, c1, c2, c3);
+ sqr_add_c2(a, 6, 0, c1, c2, c3);
+ r[6] = c1;
+ c1 = 0;
+ sqr_add_c2(a, 7, 0, c2, c3, c1);
+ sqr_add_c2(a, 6, 1, c2, c3, c1);
+ sqr_add_c2(a, 5, 2, c2, c3, c1);
+ sqr_add_c2(a, 4, 3, c2, c3, c1);
+ r[7] = c2;
+ c2 = 0;
+ sqr_add_c(a, 4, c3, c1, c2);
+ sqr_add_c2(a, 5, 3, c3, c1, c2);
+ sqr_add_c2(a, 6, 2, c3, c1, c2);
+ sqr_add_c2(a, 7, 1, c3, c1, c2);
+ r[8] = c3;
+ c3 = 0;
+ sqr_add_c2(a, 7, 2, c1, c2, c3);
+ sqr_add_c2(a, 6, 3, c1, c2, c3);
+ sqr_add_c2(a, 5, 4, c1, c2, c3);
+ r[9] = c1;
+ c1 = 0;
+ sqr_add_c(a, 5, c2, c3, c1);
+ sqr_add_c2(a, 6, 4, c2, c3, c1);
+ sqr_add_c2(a, 7, 3, c2, c3, c1);
+ r[10] = c2;
+ c2 = 0;
+ sqr_add_c2(a, 7, 4, c3, c1, c2);
+ sqr_add_c2(a, 6, 5, c3, c1, c2);
+ r[11] = c3;
+ c3 = 0;
+ sqr_add_c(a, 6, c1, c2, c3);
+ sqr_add_c2(a, 7, 5, c1, c2, c3);
+ r[12] = c1;
+ c1 = 0;
+ sqr_add_c2(a, 7, 6, c2, c3, c1);
+ r[13] = c2;
+ c2 = 0;
+ sqr_add_c(a, 7, c3, c1, c2);
+ r[14] = c3;
+ r[15] = c1;
+}
+
+void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a) {
+ BN_ULONG t1, t2;
+ BN_ULONG c1, c2, c3;
+
+ c1 = 0;
+ c2 = 0;
+ c3 = 0;
+ sqr_add_c(a, 0, c1, c2, c3);
+ r[0] = c1;
+ c1 = 0;
+ sqr_add_c2(a, 1, 0, c2, c3, c1);
+ r[1] = c2;
+ c2 = 0;
+ sqr_add_c(a, 1, c3, c1, c2);
+ sqr_add_c2(a, 2, 0, c3, c1, c2);
+ r[2] = c3;
+ c3 = 0;
+ sqr_add_c2(a, 3, 0, c1, c2, c3);
+ sqr_add_c2(a, 2, 1, c1, c2, c3);
+ r[3] = c1;
+ c1 = 0;
+ sqr_add_c(a, 2, c2, c3, c1);
+ sqr_add_c2(a, 3, 1, c2, c3, c1);
+ r[4] = c2;
+ c2 = 0;
+ sqr_add_c2(a, 3, 2, c3, c1, c2);
+ r[5] = c3;
+ c3 = 0;
+ sqr_add_c(a, 3, c1, c2, c3);
+ r[6] = c1;
+ r[7] = c2;
+}
+
+#endif /* defined(OPENSSL_X86_64) && !defined(OPENSSL_WINDOWS) */
diff --git a/crypto/bn/asm/x86_64-mont.pl b/crypto/bn/asm/x86_64-mont.pl
new file mode 100644
index 0000000..3803928
--- /dev/null
+++ b/crypto/bn/asm/x86_64-mont.pl
@@ -0,0 +1,1400 @@
+#!/usr/bin/env perl
+
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+
+# October 2005.
+#
+# Montgomery multiplication routine for x86_64. While it gives modest
+# 9% improvement of rsa4096 sign on Opteron, rsa512 sign runs more
+# than twice, >2x, as fast. Most common rsa1024 sign is improved by
+# respectful 50%. It remains to be seen if loop unrolling and
+# dedicated squaring routine can provide further improvement...
+
+# July 2011.
+#
+# Add dedicated squaring procedure. Performance improvement varies
+# from platform to platform, but in average it's ~5%/15%/25%/33%
+# for 512-/1024-/2048-/4096-bit RSA *sign* benchmarks respectively.
+
+# August 2011.
+#
+# Unroll and modulo-schedule inner loops in such manner that they
+# are "fallen through" for input lengths of 8, which is critical for
+# 1024-bit RSA *sign*. Average performance improvement in comparison
+# to *initial* version of this module from 2005 is ~0%/30%/40%/45%
+# for 512-/1024-/2048-/4096-bit RSA *sign* benchmarks respectively.
+
+# June 2013.
+#
+# Optimize reduction in squaring procedure and improve 1024+-bit RSA
+# sign performance by 10-16% on Intel Sandy Bridge and later
+# (virtually same on non-Intel processors).
+
+# August 2013.
+#
+# Add MULX/ADOX/ADCX code path.
+
+$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;
+
+if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
+ =~ /GNU assembler version ([2-9]\.[0-9]+)/) {
+ $addx = ($1>=2.23);
+}
+
+if (!$addx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
+ `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
+ $addx = ($1>=2.10);
+}
+
+if (!$addx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
+ `ml64 2>&1` =~ /Version ([0-9]+)\./) {
+ $addx = ($1>=11);
+}
+
+# int bn_mul_mont(
+$rp="%rdi"; # BN_ULONG *rp,
+$ap="%rsi"; # const BN_ULONG *ap,
+$bp="%rdx"; # const BN_ULONG *bp,
+$np="%rcx"; # const BN_ULONG *np,
+$n0="%r8"; # const BN_ULONG *n0,
+$num="%r9"; # int num);
+$lo0="%r10";
+$hi0="%r11";
+$hi1="%r13";
+$i="%r14";
+$j="%r15";
+$m0="%rbx";
+$m1="%rbp";
+
+$code=<<___;
+.text
+
+.extern OPENSSL_ia32cap_P
+
+.globl bn_mul_mont
+.type bn_mul_mont,\@function,6
+.align 16
+bn_mul_mont:
+ test \$3,${num}d
+ jnz .Lmul_enter
+ cmp \$8,${num}d
+ jb .Lmul_enter
+___
+$code.=<<___ if ($addx);
+ mov OPENSSL_ia32cap_P+8(%rip),%r11d
+___
+$code.=<<___;
+ cmp $ap,$bp
+ jne .Lmul4x_enter
+ test \$7,${num}d
+ jz .Lsqr8x_enter
+ jmp .Lmul4x_enter
+
+.align 16
+.Lmul_enter:
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+
+ mov ${num}d,${num}d
+ lea 2($num),%r10
+ mov %rsp,%r11
+ neg %r10
+ lea (%rsp,%r10,8),%rsp # tp=alloca(8*(num+2))
+ and \$-1024,%rsp # minimize TLB usage
+
+ mov %r11,8(%rsp,$num,8) # tp[num+1]=%rsp
+.Lmul_body:
+ mov $bp,%r12 # reassign $bp
+___
+ $bp="%r12";
+$code.=<<___;
+ mov ($n0),$n0 # pull n0[0] value
+ mov ($bp),$m0 # m0=bp[0]
+ mov ($ap),%rax
+
+ xor $i,$i # i=0
+ xor $j,$j # j=0
+
+ mov $n0,$m1
+ mulq $m0 # ap[0]*bp[0]
+ mov %rax,$lo0
+ mov ($np),%rax
+
+ imulq $lo0,$m1 # "tp[0]"*n0
+ mov %rdx,$hi0
+
+ mulq $m1 # np[0]*m1
+ add %rax,$lo0 # discarded
+ mov 8($ap),%rax
+ adc \$0,%rdx
+ mov %rdx,$hi1
+
+ lea 1($j),$j # j++
+ jmp .L1st_enter
+
+.align 16
+.L1st:
+ add %rax,$hi1
+ mov ($ap,$j,8),%rax
+ adc \$0,%rdx
+ add $hi0,$hi1 # np[j]*m1+ap[j]*bp[0]
+ mov $lo0,$hi0
+ adc \$0,%rdx
+ mov $hi1,-16(%rsp,$j,8) # tp[j-1]
+ mov %rdx,$hi1
+
+.L1st_enter:
+ mulq $m0 # ap[j]*bp[0]
+ add %rax,$hi0
+ mov ($np,$j,8),%rax
+ adc \$0,%rdx
+ lea 1($j),$j # j++
+ mov %rdx,$lo0
+
+ mulq $m1 # np[j]*m1
+ cmp $num,$j
+ jne .L1st
+
+ add %rax,$hi1
+ mov ($ap),%rax # ap[0]
+ adc \$0,%rdx
+ add $hi0,$hi1 # np[j]*m1+ap[j]*bp[0]
+ adc \$0,%rdx
+ mov $hi1,-16(%rsp,$j,8) # tp[j-1]
+ mov %rdx,$hi1
+ mov $lo0,$hi0
+
+ xor %rdx,%rdx
+ add $hi0,$hi1
+ adc \$0,%rdx
+ mov $hi1,-8(%rsp,$num,8)
+ mov %rdx,(%rsp,$num,8) # store upmost overflow bit
+
+ lea 1($i),$i # i++
+ jmp .Louter
+.align 16
+.Louter:
+ mov ($bp,$i,8),$m0 # m0=bp[i]
+ xor $j,$j # j=0
+ mov $n0,$m1
+ mov (%rsp),$lo0
+ mulq $m0 # ap[0]*bp[i]
+ add %rax,$lo0 # ap[0]*bp[i]+tp[0]
+ mov ($np),%rax
+ adc \$0,%rdx
+
+ imulq $lo0,$m1 # tp[0]*n0
+ mov %rdx,$hi0
+
+ mulq $m1 # np[0]*m1
+ add %rax,$lo0 # discarded
+ mov 8($ap),%rax
+ adc \$0,%rdx
+ mov 8(%rsp),$lo0 # tp[1]
+ mov %rdx,$hi1
+
+ lea 1($j),$j # j++
+ jmp .Linner_enter
+
+.align 16
+.Linner:
+ add %rax,$hi1
+ mov ($ap,$j,8),%rax
+ adc \$0,%rdx
+ add $lo0,$hi1 # np[j]*m1+ap[j]*bp[i]+tp[j]
+ mov (%rsp,$j,8),$lo0
+ adc \$0,%rdx
+ mov $hi1,-16(%rsp,$j,8) # tp[j-1]
+ mov %rdx,$hi1
+
+.Linner_enter:
+ mulq $m0 # ap[j]*bp[i]
+ add %rax,$hi0
+ mov ($np,$j,8),%rax
+ adc \$0,%rdx
+ add $hi0,$lo0 # ap[j]*bp[i]+tp[j]
+ mov %rdx,$hi0
+ adc \$0,$hi0
+ lea 1($j),$j # j++
+
+ mulq $m1 # np[j]*m1
+ cmp $num,$j
+ jne .Linner
+
+ add %rax,$hi1
+ mov ($ap),%rax # ap[0]
+ adc \$0,%rdx
+ add $lo0,$hi1 # np[j]*m1+ap[j]*bp[i]+tp[j]
+ mov (%rsp,$j,8),$lo0
+ adc \$0,%rdx
+ mov $hi1,-16(%rsp,$j,8) # tp[j-1]
+ mov %rdx,$hi1
+
+ xor %rdx,%rdx
+ add $hi0,$hi1
+ adc \$0,%rdx
+ add $lo0,$hi1 # pull upmost overflow bit
+ adc \$0,%rdx
+ mov $hi1,-8(%rsp,$num,8)
+ mov %rdx,(%rsp,$num,8) # store upmost overflow bit
+
+ lea 1($i),$i # i++
+ cmp $num,$i
+ jb .Louter
+
+ xor $i,$i # i=0 and clear CF!
+ mov (%rsp),%rax # tp[0]
+ lea (%rsp),$ap # borrow ap for tp
+ mov $num,$j # j=num
+ jmp .Lsub
+.align 16
+.Lsub: sbb ($np,$i,8),%rax
+ mov %rax,($rp,$i,8) # rp[i]=tp[i]-np[i]
+ mov 8($ap,$i,8),%rax # tp[i+1]
+ lea 1($i),$i # i++
+ dec $j # doesnn't affect CF!
+ jnz .Lsub
+
+ sbb \$0,%rax # handle upmost overflow bit
+ xor $i,$i
+ and %rax,$ap
+ not %rax
+ mov $rp,$np
+ and %rax,$np
+ mov $num,$j # j=num
+ or $np,$ap # ap=borrow?tp:rp
+.align 16
+.Lcopy: # copy or in-place refresh
+ mov ($ap,$i,8),%rax
+ mov $i,(%rsp,$i,8) # zap temporary vector
+ mov %rax,($rp,$i,8) # rp[i]=tp[i]
+ lea 1($i),$i
+ sub \$1,$j
+ jnz .Lcopy
+
+ mov 8(%rsp,$num,8),%rsi # restore %rsp
+ mov \$1,%rax
+ mov (%rsi),%r15
+ mov 8(%rsi),%r14
+ mov 16(%rsi),%r13
+ mov 24(%rsi),%r12
+ mov 32(%rsi),%rbp
+ mov 40(%rsi),%rbx
+ lea 48(%rsi),%rsp
+.Lmul_epilogue:
+ ret
+.size bn_mul_mont,.-bn_mul_mont
+___
+{{{
+my @A=("%r10","%r11");
+my @N=("%r13","%rdi");
+$code.=<<___;
+.type bn_mul4x_mont,\@function,6
+.align 16
+bn_mul4x_mont:
+.Lmul4x_enter:
+___
+$code.=<<___ if ($addx);
+ and \$0x80100,%r11d
+ cmp \$0x80100,%r11d
+ je .Lmulx4x_enter
+___
+$code.=<<___;
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+
+ mov ${num}d,${num}d
+ lea 4($num),%r10
+ mov %rsp,%r11
+ neg %r10
+ lea (%rsp,%r10,8),%rsp # tp=alloca(8*(num+4))
+ and \$-1024,%rsp # minimize TLB usage
+
+ mov %r11,8(%rsp,$num,8) # tp[num+1]=%rsp
+.Lmul4x_body:
+ mov $rp,16(%rsp,$num,8) # tp[num+2]=$rp
+ mov %rdx,%r12 # reassign $bp
+___
+ $bp="%r12";
+$code.=<<___;
+ mov ($n0),$n0 # pull n0[0] value
+ mov ($bp),$m0 # m0=bp[0]
+ mov ($ap),%rax
+
+ xor $i,$i # i=0
+ xor $j,$j # j=0
+
+ mov $n0,$m1
+ mulq $m0 # ap[0]*bp[0]
+ mov %rax,$A[0]
+ mov ($np),%rax
+
+ imulq $A[0],$m1 # "tp[0]"*n0
+ mov %rdx,$A[1]
+
+ mulq $m1 # np[0]*m1
+ add %rax,$A[0] # discarded
+ mov 8($ap),%rax
+ adc \$0,%rdx
+ mov %rdx,$N[1]
+
+ mulq $m0
+ add %rax,$A[1]
+ mov 8($np),%rax
+ adc \$0,%rdx
+ mov %rdx,$A[0]
+
+ mulq $m1
+ add %rax,$N[1]
+ mov 16($ap),%rax
+ adc \$0,%rdx
+ add $A[1],$N[1]
+ lea 4($j),$j # j++
+ adc \$0,%rdx
+ mov $N[1],(%rsp)
+ mov %rdx,$N[0]
+ jmp .L1st4x
+.align 16
+.L1st4x:
+ mulq $m0 # ap[j]*bp[0]
+ add %rax,$A[0]
+ mov -16($np,$j,8),%rax
+ adc \$0,%rdx
+ mov %rdx,$A[1]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[0]
+ mov -8($ap,$j,8),%rax
+ adc \$0,%rdx
+ add $A[0],$N[0] # np[j]*m1+ap[j]*bp[0]
+ adc \$0,%rdx
+ mov $N[0],-24(%rsp,$j,8) # tp[j-1]
+ mov %rdx,$N[1]
+
+ mulq $m0 # ap[j]*bp[0]
+ add %rax,$A[1]
+ mov -8($np,$j,8),%rax
+ adc \$0,%rdx
+ mov %rdx,$A[0]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[1]
+ mov ($ap,$j,8),%rax
+ adc \$0,%rdx
+ add $A[1],$N[1] # np[j]*m1+ap[j]*bp[0]
+ adc \$0,%rdx
+ mov $N[1],-16(%rsp,$j,8) # tp[j-1]
+ mov %rdx,$N[0]
+
+ mulq $m0 # ap[j]*bp[0]
+ add %rax,$A[0]
+ mov ($np,$j,8),%rax
+ adc \$0,%rdx
+ mov %rdx,$A[1]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[0]
+ mov 8($ap,$j,8),%rax
+ adc \$0,%rdx
+ add $A[0],$N[0] # np[j]*m1+ap[j]*bp[0]
+ adc \$0,%rdx
+ mov $N[0],-8(%rsp,$j,8) # tp[j-1]
+ mov %rdx,$N[1]
+
+ mulq $m0 # ap[j]*bp[0]
+ add %rax,$A[1]
+ mov 8($np,$j,8),%rax
+ adc \$0,%rdx
+ lea 4($j),$j # j++
+ mov %rdx,$A[0]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[1]
+ mov -16($ap,$j,8),%rax
+ adc \$0,%rdx
+ add $A[1],$N[1] # np[j]*m1+ap[j]*bp[0]
+ adc \$0,%rdx
+ mov $N[1],-32(%rsp,$j,8) # tp[j-1]
+ mov %rdx,$N[0]
+ cmp $num,$j
+ jb .L1st4x
+
+ mulq $m0 # ap[j]*bp[0]
+ add %rax,$A[0]
+ mov -16($np,$j,8),%rax
+ adc \$0,%rdx
+ mov %rdx,$A[1]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[0]
+ mov -8($ap,$j,8),%rax
+ adc \$0,%rdx
+ add $A[0],$N[0] # np[j]*m1+ap[j]*bp[0]
+ adc \$0,%rdx
+ mov $N[0],-24(%rsp,$j,8) # tp[j-1]
+ mov %rdx,$N[1]
+
+ mulq $m0 # ap[j]*bp[0]
+ add %rax,$A[1]
+ mov -8($np,$j,8),%rax
+ adc \$0,%rdx
+ mov %rdx,$A[0]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[1]
+ mov ($ap),%rax # ap[0]
+ adc \$0,%rdx
+ add $A[1],$N[1] # np[j]*m1+ap[j]*bp[0]
+ adc \$0,%rdx
+ mov $N[1],-16(%rsp,$j,8) # tp[j-1]
+ mov %rdx,$N[0]
+
+ xor $N[1],$N[1]
+ add $A[0],$N[0]
+ adc \$0,$N[1]
+ mov $N[0],-8(%rsp,$j,8)
+ mov $N[1],(%rsp,$j,8) # store upmost overflow bit
+
+ lea 1($i),$i # i++
+.align 4
+.Louter4x:
+ mov ($bp,$i,8),$m0 # m0=bp[i]
+ xor $j,$j # j=0
+ mov (%rsp),$A[0]
+ mov $n0,$m1
+ mulq $m0 # ap[0]*bp[i]
+ add %rax,$A[0] # ap[0]*bp[i]+tp[0]
+ mov ($np),%rax
+ adc \$0,%rdx
+
+ imulq $A[0],$m1 # tp[0]*n0
+ mov %rdx,$A[1]
+
+ mulq $m1 # np[0]*m1
+ add %rax,$A[0] # "$N[0]", discarded
+ mov 8($ap),%rax
+ adc \$0,%rdx
+ mov %rdx,$N[1]
+
+ mulq $m0 # ap[j]*bp[i]
+ add %rax,$A[1]
+ mov 8($np),%rax
+ adc \$0,%rdx
+ add 8(%rsp),$A[1] # +tp[1]
+ adc \$0,%rdx
+ mov %rdx,$A[0]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[1]
+ mov 16($ap),%rax
+ adc \$0,%rdx
+ add $A[1],$N[1] # np[j]*m1+ap[j]*bp[i]+tp[j]
+ lea 4($j),$j # j+=2
+ adc \$0,%rdx
+ mov $N[1],(%rsp) # tp[j-1]
+ mov %rdx,$N[0]
+ jmp .Linner4x
+.align 16
+.Linner4x:
+ mulq $m0 # ap[j]*bp[i]
+ add %rax,$A[0]
+ mov -16($np,$j,8),%rax
+ adc \$0,%rdx
+ add -16(%rsp,$j,8),$A[0] # ap[j]*bp[i]+tp[j]
+ adc \$0,%rdx
+ mov %rdx,$A[1]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[0]
+ mov -8($ap,$j,8),%rax
+ adc \$0,%rdx
+ add $A[0],$N[0]
+ adc \$0,%rdx
+ mov $N[0],-24(%rsp,$j,8) # tp[j-1]
+ mov %rdx,$N[1]
+
+ mulq $m0 # ap[j]*bp[i]
+ add %rax,$A[1]
+ mov -8($np,$j,8),%rax
+ adc \$0,%rdx
+ add -8(%rsp,$j,8),$A[1]
+ adc \$0,%rdx
+ mov %rdx,$A[0]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[1]
+ mov ($ap,$j,8),%rax
+ adc \$0,%rdx
+ add $A[1],$N[1]
+ adc \$0,%rdx
+ mov $N[1],-16(%rsp,$j,8) # tp[j-1]
+ mov %rdx,$N[0]
+
+ mulq $m0 # ap[j]*bp[i]
+ add %rax,$A[0]
+ mov ($np,$j,8),%rax
+ adc \$0,%rdx
+ add (%rsp,$j,8),$A[0] # ap[j]*bp[i]+tp[j]
+ adc \$0,%rdx
+ mov %rdx,$A[1]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[0]
+ mov 8($ap,$j,8),%rax
+ adc \$0,%rdx
+ add $A[0],$N[0]
+ adc \$0,%rdx
+ mov $N[0],-8(%rsp,$j,8) # tp[j-1]
+ mov %rdx,$N[1]
+
+ mulq $m0 # ap[j]*bp[i]
+ add %rax,$A[1]
+ mov 8($np,$j,8),%rax
+ adc \$0,%rdx
+ add 8(%rsp,$j,8),$A[1]
+ adc \$0,%rdx
+ lea 4($j),$j # j++
+ mov %rdx,$A[0]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[1]
+ mov -16($ap,$j,8),%rax
+ adc \$0,%rdx
+ add $A[1],$N[1]
+ adc \$0,%rdx
+ mov $N[1],-32(%rsp,$j,8) # tp[j-1]
+ mov %rdx,$N[0]
+ cmp $num,$j
+ jb .Linner4x
+
+ mulq $m0 # ap[j]*bp[i]
+ add %rax,$A[0]
+ mov -16($np,$j,8),%rax
+ adc \$0,%rdx
+ add -16(%rsp,$j,8),$A[0] # ap[j]*bp[i]+tp[j]
+ adc \$0,%rdx
+ mov %rdx,$A[1]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[0]
+ mov -8($ap,$j,8),%rax
+ adc \$0,%rdx
+ add $A[0],$N[0]
+ adc \$0,%rdx
+ mov $N[0],-24(%rsp,$j,8) # tp[j-1]
+ mov %rdx,$N[1]
+
+ mulq $m0 # ap[j]*bp[i]
+ add %rax,$A[1]
+ mov -8($np,$j,8),%rax
+ adc \$0,%rdx
+ add -8(%rsp,$j,8),$A[1]
+ adc \$0,%rdx
+ lea 1($i),$i # i++
+ mov %rdx,$A[0]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[1]
+ mov ($ap),%rax # ap[0]
+ adc \$0,%rdx
+ add $A[1],$N[1]
+ adc \$0,%rdx
+ mov $N[1],-16(%rsp,$j,8) # tp[j-1]
+ mov %rdx,$N[0]
+
+ xor $N[1],$N[1]
+ add $A[0],$N[0]
+ adc \$0,$N[1]
+ add (%rsp,$num,8),$N[0] # pull upmost overflow bit
+ adc \$0,$N[1]
+ mov $N[0],-8(%rsp,$j,8)
+ mov $N[1],(%rsp,$j,8) # store upmost overflow bit
+
+ cmp $num,$i
+ jb .Louter4x
+___
+{
+my @ri=("%rax","%rdx",$m0,$m1);
+$code.=<<___;
+ mov 16(%rsp,$num,8),$rp # restore $rp
+ mov 0(%rsp),@ri[0] # tp[0]
+ pxor %xmm0,%xmm0
+ mov 8(%rsp),@ri[1] # tp[1]
+ shr \$2,$num # num/=4
+ lea (%rsp),$ap # borrow ap for tp
+ xor $i,$i # i=0 and clear CF!
+
+ sub 0($np),@ri[0]
+ mov 16($ap),@ri[2] # tp[2]
+ mov 24($ap),@ri[3] # tp[3]
+ sbb 8($np),@ri[1]
+ lea -1($num),$j # j=num/4-1
+ jmp .Lsub4x
+.align 16
+.Lsub4x:
+ mov @ri[0],0($rp,$i,8) # rp[i]=tp[i]-np[i]
+ mov @ri[1],8($rp,$i,8) # rp[i]=tp[i]-np[i]
+ sbb 16($np,$i,8),@ri[2]
+ mov 32($ap,$i,8),@ri[0] # tp[i+1]
+ mov 40($ap,$i,8),@ri[1]
+ sbb 24($np,$i,8),@ri[3]
+ mov @ri[2],16($rp,$i,8) # rp[i]=tp[i]-np[i]
+ mov @ri[3],24($rp,$i,8) # rp[i]=tp[i]-np[i]
+ sbb 32($np,$i,8),@ri[0]
+ mov 48($ap,$i,8),@ri[2]
+ mov 56($ap,$i,8),@ri[3]
+ sbb 40($np,$i,8),@ri[1]
+ lea 4($i),$i # i++
+ dec $j # doesnn't affect CF!
+ jnz .Lsub4x
+
+ mov @ri[0],0($rp,$i,8) # rp[i]=tp[i]-np[i]
+ mov 32($ap,$i,8),@ri[0] # load overflow bit
+ sbb 16($np,$i,8),@ri[2]
+ mov @ri[1],8($rp,$i,8) # rp[i]=tp[i]-np[i]
+ sbb 24($np,$i,8),@ri[3]
+ mov @ri[2],16($rp,$i,8) # rp[i]=tp[i]-np[i]
+
+ sbb \$0,@ri[0] # handle upmost overflow bit
+ mov @ri[3],24($rp,$i,8) # rp[i]=tp[i]-np[i]
+ xor $i,$i # i=0
+ and @ri[0],$ap
+ not @ri[0]
+ mov $rp,$np
+ and @ri[0],$np
+ lea -1($num),$j
+ or $np,$ap # ap=borrow?tp:rp
+
+ movdqu ($ap),%xmm1
+ movdqa %xmm0,(%rsp)
+ movdqu %xmm1,($rp)
+ jmp .Lcopy4x
+.align 16
+.Lcopy4x: # copy or in-place refresh
+ movdqu 16($ap,$i),%xmm2
+ movdqu 32($ap,$i),%xmm1
+ movdqa %xmm0,16(%rsp,$i)
+ movdqu %xmm2,16($rp,$i)
+ movdqa %xmm0,32(%rsp,$i)
+ movdqu %xmm1,32($rp,$i)
+ lea 32($i),$i
+ dec $j
+ jnz .Lcopy4x
+
+ shl \$2,$num
+ movdqu 16($ap,$i),%xmm2
+ movdqa %xmm0,16(%rsp,$i)
+ movdqu %xmm2,16($rp,$i)
+___
+}
+$code.=<<___;
+ mov 8(%rsp,$num,8),%rsi # restore %rsp
+ mov \$1,%rax
+ mov (%rsi),%r15
+ mov 8(%rsi),%r14
+ mov 16(%rsi),%r13
+ mov 24(%rsi),%r12
+ mov 32(%rsi),%rbp
+ mov 40(%rsi),%rbx
+ lea 48(%rsi),%rsp
+.Lmul4x_epilogue:
+ ret
+.size bn_mul4x_mont,.-bn_mul4x_mont
+___
+}}}
+{{{
+######################################################################
+# void bn_sqr8x_mont(
+my $rptr="%rdi"; # const BN_ULONG *rptr,
+my $aptr="%rsi"; # const BN_ULONG *aptr,
+my $bptr="%rdx"; # not used
+my $nptr="%rcx"; # const BN_ULONG *nptr,
+my $n0 ="%r8"; # const BN_ULONG *n0);
+my $num ="%r9"; # int num, has to be divisible by 8
+
+my ($i,$j,$tptr)=("%rbp","%rcx",$rptr);
+my @A0=("%r10","%r11");
+my @A1=("%r12","%r13");
+my ($a0,$a1,$ai)=("%r14","%r15","%rbx");
+
+$code.=<<___;
+.extern bn_sqr8x_internal # see x86_64-mont5 module
+.extern bn_sqrx8x_internal # see x86_64-mont5 module
+
+.type bn_sqr8x_mont,\@function,6
+.align 32
+bn_sqr8x_mont:
+.Lsqr8x_enter:
+ mov %rsp,%rax
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+
+ mov ${num}d,%r10d
+ shl \$3,${num}d # convert $num to bytes
+ shl \$3+2,%r10 # 4*$num
+ neg $num
+
+ ##############################################################
+ # ensure that stack frame doesn't alias with $aptr modulo
+ # 4096. this is done to allow memory disambiguation logic
+ # do its job.
+ #
+ lea -64(%rsp,$num,4),%r11
+ mov ($n0),$n0 # *n0
+ sub $aptr,%r11
+ and \$4095,%r11
+ cmp %r11,%r10
+ jb .Lsqr8x_sp_alt
+ sub %r11,%rsp # align with $aptr
+ lea -64(%rsp,$num,4),%rsp # alloca(frame+4*$num)
+ jmp .Lsqr8x_sp_done
+
+.align 32
+.Lsqr8x_sp_alt:
+ lea 4096-64(,$num,4),%r10 # 4096-frame-4*$num
+ lea -64(%rsp,$num,4),%rsp # alloca(frame+4*$num)
+ sub %r10,%r11
+ mov \$0,%r10
+ cmovc %r10,%r11
+ sub %r11,%rsp
+.Lsqr8x_sp_done:
+ and \$-64,%rsp
+ mov $num,%r10
+ neg $num
+
+ lea 64(%rsp,$num,2),%r11 # copy of modulus
+ mov $n0, 32(%rsp)
+ mov %rax, 40(%rsp) # save original %rsp
+.Lsqr8x_body:
+
+ mov $num,$i
+ movq %r11, %xmm2 # save pointer to modulus copy
+ shr \$3+2,$i
+ mov OPENSSL_ia32cap_P+8(%rip),%eax
+ jmp .Lsqr8x_copy_n
+
+.align 32
+.Lsqr8x_copy_n:
+ movq 8*0($nptr),%xmm0
+ movq 8*1($nptr),%xmm1
+ movq 8*2($nptr),%xmm3
+ movq 8*3($nptr),%xmm4
+ lea 8*4($nptr),$nptr
+ movdqa %xmm0,16*0(%r11)
+ movdqa %xmm1,16*1(%r11)
+ movdqa %xmm3,16*2(%r11)
+ movdqa %xmm4,16*3(%r11)
+ lea 16*4(%r11),%r11
+ dec $i
+ jnz .Lsqr8x_copy_n
+
+ pxor %xmm0,%xmm0
+ movq $rptr,%xmm1 # save $rptr
+ movq %r10, %xmm3 # -$num
+___
+$code.=<<___ if ($addx);
+ and \$0x80100,%eax
+ cmp \$0x80100,%eax
+ jne .Lsqr8x_nox
+
+ call bn_sqrx8x_internal # see x86_64-mont5 module
+
+ pxor %xmm0,%xmm0
+ lea 48(%rsp),%rax
+ lea 64(%rsp,$num,2),%rdx
+ shr \$3+2,$num
+ mov 40(%rsp),%rsi # restore %rsp
+ jmp .Lsqr8x_zero
+
+.align 32
+.Lsqr8x_nox:
+___
+$code.=<<___;
+ call bn_sqr8x_internal # see x86_64-mont5 module
+
+ pxor %xmm0,%xmm0
+ lea 48(%rsp),%rax
+ lea 64(%rsp,$num,2),%rdx
+ shr \$3+2,$num
+ mov 40(%rsp),%rsi # restore %rsp
+ jmp .Lsqr8x_zero
+
+.align 32
+.Lsqr8x_zero:
+ movdqa %xmm0,16*0(%rax) # wipe t
+ movdqa %xmm0,16*1(%rax)
+ movdqa %xmm0,16*2(%rax)
+ movdqa %xmm0,16*3(%rax)
+ lea 16*4(%rax),%rax
+ movdqa %xmm0,16*0(%rdx) # wipe n
+ movdqa %xmm0,16*1(%rdx)
+ movdqa %xmm0,16*2(%rdx)
+ movdqa %xmm0,16*3(%rdx)
+ lea 16*4(%rdx),%rdx
+ dec $num
+ jnz .Lsqr8x_zero
+
+ mov \$1,%rax
+ mov -48(%rsi),%r15
+ mov -40(%rsi),%r14
+ mov -32(%rsi),%r13
+ mov -24(%rsi),%r12
+ mov -16(%rsi),%rbp
+ mov -8(%rsi),%rbx
+ lea (%rsi),%rsp
+.Lsqr8x_epilogue:
+ ret
+.size bn_sqr8x_mont,.-bn_sqr8x_mont
+___
+}}}
+
+if ($addx) {{{
+my $bp="%rdx"; # original value
+
+$code.=<<___;
+.type bn_mulx4x_mont,\@function,6
+.align 32
+bn_mulx4x_mont:
+.Lmulx4x_enter:
+ mov %rsp,%rax
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+
+ shl \$3,${num}d # convert $num to bytes
+ .byte 0x67
+ xor %r10,%r10
+ sub $num,%r10 # -$num
+ mov ($n0),$n0 # *n0
+ lea -72(%rsp,%r10),%rsp # alloca(frame+$num+8)
+ lea ($bp,$num),%r10
+ and \$-128,%rsp
+ ##############################################################
+ # Stack layout
+ # +0 num
+ # +8 off-loaded &b[i]
+ # +16 end of b[num]
+ # +24 saved n0
+ # +32 saved rp
+ # +40 saved %rsp
+ # +48 inner counter
+ # +56
+ # +64 tmp[num+1]
+ #
+ mov $num,0(%rsp) # save $num
+ shr \$5,$num
+ mov %r10,16(%rsp) # end of b[num]
+ sub \$1,$num
+ mov $n0, 24(%rsp) # save *n0
+ mov $rp, 32(%rsp) # save $rp
+ mov %rax,40(%rsp) # save original %rsp
+ mov $num,48(%rsp) # inner counter
+ jmp .Lmulx4x_body
+
+.align 32
+.Lmulx4x_body:
+___
+my ($aptr, $bptr, $nptr, $tptr, $mi, $bi, $zero, $num)=
+ ("%rsi","%rdi","%rcx","%rbx","%r8","%r9","%rbp","%rax");
+my $rptr=$bptr;
+$code.=<<___;
+ lea 8($bp),$bptr
+ mov ($bp),%rdx # b[0], $bp==%rdx actually
+ lea 64+32(%rsp),$tptr
+ mov %rdx,$bi
+
+ mulx 0*8($aptr),$mi,%rax # a[0]*b[0]
+ mulx 1*8($aptr),%r11,%r14 # a[1]*b[0]
+ add %rax,%r11
+ mov $bptr,8(%rsp) # off-load &b[i]
+ mulx 2*8($aptr),%r12,%r13 # ...
+ adc %r14,%r12
+ adc \$0,%r13
+
+ mov $mi,$bptr # borrow $bptr
+ imulq 24(%rsp),$mi # "t[0]"*n0
+ xor $zero,$zero # cf=0, of=0
+
+ mulx 3*8($aptr),%rax,%r14
+ mov $mi,%rdx
+ lea 4*8($aptr),$aptr
+ adcx %rax,%r13
+ adcx $zero,%r14 # cf=0
+
+ mulx 0*8($nptr),%rax,%r10
+ adcx %rax,$bptr # discarded
+ adox %r11,%r10
+ mulx 1*8($nptr),%rax,%r11
+ adcx %rax,%r10
+ adox %r12,%r11
+ .byte 0xc4,0x62,0xfb,0xf6,0xa1,0x10,0x00,0x00,0x00 # mulx 2*8($nptr),%rax,%r12
+ mov 48(%rsp),$bptr # counter value
+ mov %r10,-4*8($tptr)
+ adcx %rax,%r11
+ adox %r13,%r12
+ mulx 3*8($nptr),%rax,%r15
+ mov $bi,%rdx
+ mov %r11,-3*8($tptr)
+ adcx %rax,%r12
+ adox $zero,%r15 # of=0
+ lea 4*8($nptr),$nptr
+ mov %r12,-2*8($tptr)
+
+ jmp .Lmulx4x_1st
+
+.align 32
+.Lmulx4x_1st:
+ adcx $zero,%r15 # cf=0, modulo-scheduled
+ mulx 0*8($aptr),%r10,%rax # a[4]*b[0]
+ adcx %r14,%r10
+ mulx 1*8($aptr),%r11,%r14 # a[5]*b[0]
+ adcx %rax,%r11
+ mulx 2*8($aptr),%r12,%rax # ...
+ adcx %r14,%r12
+ mulx 3*8($aptr),%r13,%r14
+ .byte 0x67,0x67
+ mov $mi,%rdx
+ adcx %rax,%r13
+ adcx $zero,%r14 # cf=0
+ lea 4*8($aptr),$aptr
+ lea 4*8($tptr),$tptr
+
+ adox %r15,%r10
+ mulx 0*8($nptr),%rax,%r15
+ adcx %rax,%r10
+ adox %r15,%r11
+ mulx 1*8($nptr),%rax,%r15
+ adcx %rax,%r11
+ adox %r15,%r12
+ mulx 2*8($nptr),%rax,%r15
+ mov %r10,-5*8($tptr)
+ adcx %rax,%r12
+ mov %r11,-4*8($tptr)
+ adox %r15,%r13
+ mulx 3*8($nptr),%rax,%r15
+ mov $bi,%rdx
+ mov %r12,-3*8($tptr)
+ adcx %rax,%r13
+ adox $zero,%r15
+ lea 4*8($nptr),$nptr
+ mov %r13,-2*8($tptr)
+
+ dec $bptr # of=0, pass cf
+ jnz .Lmulx4x_1st
+
+ mov 0(%rsp),$num # load num
+ mov 8(%rsp),$bptr # re-load &b[i]
+ adc $zero,%r15 # modulo-scheduled
+ add %r15,%r14
+ sbb %r15,%r15 # top-most carry
+ mov %r14,-1*8($tptr)
+ jmp .Lmulx4x_outer
+
+.align 32
+.Lmulx4x_outer:
+ mov ($bptr),%rdx # b[i]
+ lea 8($bptr),$bptr # b++
+ sub $num,$aptr # rewind $aptr
+ mov %r15,($tptr) # save top-most carry
+ lea 64+4*8(%rsp),$tptr
+ sub $num,$nptr # rewind $nptr
+
+ mulx 0*8($aptr),$mi,%r11 # a[0]*b[i]
+ xor %ebp,%ebp # xor $zero,$zero # cf=0, of=0
+ mov %rdx,$bi
+ mulx 1*8($aptr),%r14,%r12 # a[1]*b[i]
+ adox -4*8($tptr),$mi
+ adcx %r14,%r11
+ mulx 2*8($aptr),%r15,%r13 # ...
+ adox -3*8($tptr),%r11
+ adcx %r15,%r12
+ adox $zero,%r12
+ adcx $zero,%r13
+
+ mov $bptr,8(%rsp) # off-load &b[i]
+ .byte 0x67
+ mov $mi,%r15
+ imulq 24(%rsp),$mi # "t[0]"*n0
+ xor %ebp,%ebp # xor $zero,$zero # cf=0, of=0
+
+ mulx 3*8($aptr),%rax,%r14
+ mov $mi,%rdx
+ adox -2*8($tptr),%r12
+ adcx %rax,%r13
+ adox -1*8($tptr),%r13
+ adcx $zero,%r14
+ lea 4*8($aptr),$aptr
+ adox $zero,%r14
+
+ mulx 0*8($nptr),%rax,%r10
+ adcx %rax,%r15 # discarded
+ adox %r11,%r10
+ mulx 1*8($nptr),%rax,%r11
+ adcx %rax,%r10
+ adox %r12,%r11
+ mulx 2*8($nptr),%rax,%r12
+ mov %r10,-4*8($tptr)
+ adcx %rax,%r11
+ adox %r13,%r12
+ mulx 3*8($nptr),%rax,%r15
+ mov $bi,%rdx
+ mov %r11,-3*8($tptr)
+ lea 4*8($nptr),$nptr
+ adcx %rax,%r12
+ adox $zero,%r15 # of=0
+ mov 48(%rsp),$bptr # counter value
+ mov %r12,-2*8($tptr)
+
+ jmp .Lmulx4x_inner
+
+.align 32
+.Lmulx4x_inner:
+ mulx 0*8($aptr),%r10,%rax # a[4]*b[i]
+ adcx $zero,%r15 # cf=0, modulo-scheduled
+ adox %r14,%r10
+ mulx 1*8($aptr),%r11,%r14 # a[5]*b[i]
+ adcx 0*8($tptr),%r10
+ adox %rax,%r11
+ mulx 2*8($aptr),%r12,%rax # ...
+ adcx 1*8($tptr),%r11
+ adox %r14,%r12
+ mulx 3*8($aptr),%r13,%r14
+ mov $mi,%rdx
+ adcx 2*8($tptr),%r12
+ adox %rax,%r13
+ adcx 3*8($tptr),%r13
+ adox $zero,%r14 # of=0
+ lea 4*8($aptr),$aptr
+ lea 4*8($tptr),$tptr
+ adcx $zero,%r14 # cf=0
+
+ adox %r15,%r10
+ mulx 0*8($nptr),%rax,%r15
+ adcx %rax,%r10
+ adox %r15,%r11
+ mulx 1*8($nptr),%rax,%r15
+ adcx %rax,%r11
+ adox %r15,%r12
+ mulx 2*8($nptr),%rax,%r15
+ mov %r10,-5*8($tptr)
+ adcx %rax,%r12
+ adox %r15,%r13
+ mulx 3*8($nptr),%rax,%r15
+ mov $bi,%rdx
+ mov %r11,-4*8($tptr)
+ mov %r12,-3*8($tptr)
+ adcx %rax,%r13
+ adox $zero,%r15
+ lea 4*8($nptr),$nptr
+ mov %r13,-2*8($tptr)
+
+ dec $bptr # of=0, pass cf
+ jnz .Lmulx4x_inner
+
+ mov 0(%rsp),$num # load num
+ mov 8(%rsp),$bptr # re-load &b[i]
+ adc $zero,%r15 # modulo-scheduled
+ sub 0*8($tptr),$zero # pull top-most carry
+ adc %r15,%r14
+ mov -8($nptr),$mi
+ sbb %r15,%r15 # top-most carry
+ mov %r14,-1*8($tptr)
+
+ cmp 16(%rsp),$bptr
+ jne .Lmulx4x_outer
+
+ sub %r14,$mi # compare top-most words
+ sbb $mi,$mi
+ or $mi,%r15
+
+ neg $num
+ xor %rdx,%rdx
+ mov 32(%rsp),$rptr # restore rp
+ lea 64(%rsp),$tptr
+
+ pxor %xmm0,%xmm0
+ mov 0*8($nptr,$num),%r8
+ mov 1*8($nptr,$num),%r9
+ neg %r8
+ jmp .Lmulx4x_sub_entry
+
+.align 32
+.Lmulx4x_sub:
+ mov 0*8($nptr,$num),%r8
+ mov 1*8($nptr,$num),%r9
+ not %r8
+.Lmulx4x_sub_entry:
+ mov 2*8($nptr,$num),%r10
+ not %r9
+ and %r15,%r8
+ mov 3*8($nptr,$num),%r11
+ not %r10
+ and %r15,%r9
+ not %r11
+ and %r15,%r10
+ and %r15,%r11
+
+ neg %rdx # mov %rdx,%cf
+ adc 0*8($tptr),%r8
+ adc 1*8($tptr),%r9
+ movdqa %xmm0,($tptr)
+ adc 2*8($tptr),%r10
+ adc 3*8($tptr),%r11
+ movdqa %xmm0,16($tptr)
+ lea 4*8($tptr),$tptr
+ sbb %rdx,%rdx # mov %cf,%rdx
+
+ mov %r8,0*8($rptr)
+ mov %r9,1*8($rptr)
+ mov %r10,2*8($rptr)
+ mov %r11,3*8($rptr)
+ lea 4*8($rptr),$rptr
+
+ add \$32,$num
+ jnz .Lmulx4x_sub
+
+ mov 40(%rsp),%rsi # restore %rsp
+ mov \$1,%rax
+ mov -48(%rsi),%r15
+ mov -40(%rsi),%r14
+ mov -32(%rsi),%r13
+ mov -24(%rsi),%r12
+ mov -16(%rsi),%rbp
+ mov -8(%rsi),%rbx
+ lea (%rsi),%rsp
+.Lmulx4x_epilogue:
+ ret
+.size bn_mulx4x_mont,.-bn_mulx4x_mont
+___
+}}}
+$code.=<<___;
+.asciz "Montgomery Multiplication for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
+.align 16
+___
+
+# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
+# CONTEXT *context,DISPATCHER_CONTEXT *disp)
+if ($win64) {
+$rec="%rcx";
+$frame="%rdx";
+$context="%r8";
+$disp="%r9";
+
+$code.=<<___;
+.extern __imp_RtlVirtualUnwind
+.type mul_handler,\@abi-omnipotent
+.align 16
+mul_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 120($context),%rax # pull context->Rax
+ mov 248($context),%rbx # pull context->Rip
+
+ mov 8($disp),%rsi # disp->ImageBase
+ mov 56($disp),%r11 # disp->HandlerData
+
+ mov 0(%r11),%r10d # HandlerData[0]
+ lea (%rsi,%r10),%r10 # end of prologue label
+ cmp %r10,%rbx # context->Rip<end of prologue label
+ jb .Lcommon_seh_tail
+
+ mov 152($context),%rax # pull context->Rsp
+
+ mov 4(%r11),%r10d # HandlerData[1]
+ lea (%rsi,%r10),%r10 # epilogue label
+ cmp %r10,%rbx # context->Rip>=epilogue label
+ jae .Lcommon_seh_tail
+
+ mov 192($context),%r10 # pull $num
+ mov 8(%rax,%r10,8),%rax # pull saved stack pointer
+ lea 48(%rax),%rax
+
+ mov -8(%rax),%rbx
+ mov -16(%rax),%rbp
+ mov -24(%rax),%r12
+ mov -32(%rax),%r13
+ mov -40(%rax),%r14
+ mov -48(%rax),%r15
+ mov %rbx,144($context) # restore context->Rbx
+ mov %rbp,160($context) # restore context->Rbp
+ mov %r12,216($context) # restore context->R12
+ mov %r13,224($context) # restore context->R13
+ mov %r14,232($context) # restore context->R14
+ mov %r15,240($context) # restore context->R15
+
+ jmp .Lcommon_seh_tail
+.size mul_handler,.-mul_handler
+
+.type sqr_handler,\@abi-omnipotent
+.align 16
+sqr_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 120($context),%rax # pull context->Rax
+ mov 248($context),%rbx # pull context->Rip
+
+ mov 8($disp),%rsi # disp->ImageBase
+ mov 56($disp),%r11 # disp->HandlerData
+
+ mov 0(%r11),%r10d # HandlerData[0]
+ lea (%rsi,%r10),%r10 # end of prologue label
+ cmp %r10,%rbx # context->Rip<.Lsqr_body
+ jb .Lcommon_seh_tail
+
+ mov 152($context),%rax # pull context->Rsp
+
+ mov 4(%r11),%r10d # HandlerData[1]
+ lea (%rsi,%r10),%r10 # epilogue label
+ cmp %r10,%rbx # context->Rip>=.Lsqr_epilogue
+ jae .Lcommon_seh_tail
+
+ mov 40(%rax),%rax # pull saved stack pointer
+
+ mov -8(%rax),%rbx
+ mov -16(%rax),%rbp
+ mov -24(%rax),%r12
+ mov -32(%rax),%r13
+ mov -40(%rax),%r14
+ mov -48(%rax),%r15
+ mov %rbx,144($context) # restore context->Rbx
+ mov %rbp,160($context) # restore context->Rbp
+ mov %r12,216($context) # restore context->R12
+ mov %r13,224($context) # restore context->R13
+ mov %r14,232($context) # restore context->R14
+ mov %r15,240($context) # restore context->R15
+
+.Lcommon_seh_tail:
+ mov 8(%rax),%rdi
+ mov 16(%rax),%rsi
+ mov %rax,152($context) # restore context->Rsp
+ mov %rsi,168($context) # restore context->Rsi
+ mov %rdi,176($context) # restore context->Rdi
+
+ mov 40($disp),%rdi # disp->ContextRecord
+ mov $context,%rsi # context
+ mov \$154,%ecx # sizeof(CONTEXT)
+ .long 0xa548f3fc # cld; rep movsq
+
+ mov $disp,%rsi
+ xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER
+ mov 8(%rsi),%rdx # arg2, disp->ImageBase
+ mov 0(%rsi),%r8 # arg3, disp->ControlPc
+ mov 16(%rsi),%r9 # arg4, disp->FunctionEntry
+ mov 40(%rsi),%r10 # disp->ContextRecord
+ lea 56(%rsi),%r11 # &disp->HandlerData
+ lea 24(%rsi),%r12 # &disp->EstablisherFrame
+ mov %r10,32(%rsp) # arg5
+ mov %r11,40(%rsp) # arg6
+ mov %r12,48(%rsp) # arg7
+ mov %rcx,56(%rsp) # arg8, (NULL)
+ call *__imp_RtlVirtualUnwind(%rip)
+
+ mov \$1,%eax # ExceptionContinueSearch
+ add \$64,%rsp
+ popfq
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+ pop %rdi
+ pop %rsi
+ ret
+.size sqr_handler,.-sqr_handler
+
+.section .pdata
+.align 4
+ .rva .LSEH_begin_bn_mul_mont
+ .rva .LSEH_end_bn_mul_mont
+ .rva .LSEH_info_bn_mul_mont
+
+ .rva .LSEH_begin_bn_mul4x_mont
+ .rva .LSEH_end_bn_mul4x_mont
+ .rva .LSEH_info_bn_mul4x_mont
+
+ .rva .LSEH_begin_bn_sqr8x_mont
+ .rva .LSEH_end_bn_sqr8x_mont
+ .rva .LSEH_info_bn_sqr8x_mont
+___
+$code.=<<___ if ($addx);
+ .rva .LSEH_begin_bn_mulx4x_mont
+ .rva .LSEH_end_bn_mulx4x_mont
+ .rva .LSEH_info_bn_mulx4x_mont
+___
+$code.=<<___;
+.section .xdata
+.align 8
+.LSEH_info_bn_mul_mont:
+ .byte 9,0,0,0
+ .rva mul_handler
+ .rva .Lmul_body,.Lmul_epilogue # HandlerData[]
+.LSEH_info_bn_mul4x_mont:
+ .byte 9,0,0,0
+ .rva mul_handler
+ .rva .Lmul4x_body,.Lmul4x_epilogue # HandlerData[]
+.LSEH_info_bn_sqr8x_mont:
+ .byte 9,0,0,0
+ .rva sqr_handler
+ .rva .Lsqr8x_body,.Lsqr8x_epilogue # HandlerData[]
+___
+$code.=<<___ if ($addx);
+.LSEH_info_bn_mulx4x_mont:
+ .byte 9,0,0,0
+ .rva sqr_handler
+ .rva .Lmulx4x_body,.Lmulx4x_epilogue # HandlerData[]
+___
+}
+
+print $code;
+close STDOUT;
diff --git a/crypto/bn/asm/x86_64-mont5.pl b/crypto/bn/asm/x86_64-mont5.pl
new file mode 100644
index 0000000..c107df9
--- /dev/null
+++ b/crypto/bn/asm/x86_64-mont5.pl
@@ -0,0 +1,3514 @@
+#!/usr/bin/env perl
+
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+
+# August 2011.
+#
+# Companion to x86_64-mont.pl that optimizes cache-timing attack
+# countermeasures. The subroutines are produced by replacing bp[i]
+# references in their x86_64-mont.pl counterparts with cache-neutral
+# references to powers table computed in BN_mod_exp_mont_consttime.
+# In addition subroutine that scatters elements of the powers table
+# is implemented, so that scatter-/gathering can be tuned without
+# bn_exp.c modifications.
+
+# August 2013.
+#
+# Add MULX/AD*X code paths and additional interfaces to optimize for
+# branch prediction unit. For input lengths that are multiples of 8
+# the np argument is not just modulus value, but one interleaved
+# with 0. This is to optimize post-condition...
+
+$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;
+
+if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
+ =~ /GNU assembler version ([2-9]\.[0-9]+)/) {
+ $addx = ($1>=2.23);
+}
+
+if (!$addx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
+ `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
+ $addx = ($1>=2.10);
+}
+
+if (!$addx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
+ `ml64 2>&1` =~ /Version ([0-9]+)\./) {
+ $addx = ($1>=11);
+}
+
+# int bn_mul_mont_gather5(
+$rp="%rdi"; # BN_ULONG *rp,
+$ap="%rsi"; # const BN_ULONG *ap,
+$bp="%rdx"; # const BN_ULONG *bp,
+$np="%rcx"; # const BN_ULONG *np,
+$n0="%r8"; # const BN_ULONG *n0,
+$num="%r9"; # int num,
+ # int idx); # 0 to 2^5-1, "index" in $bp holding
+ # pre-computed powers of a', interlaced
+ # in such manner that b[0] is $bp[idx],
+ # b[1] is [2^5+idx], etc.
+$lo0="%r10";
+$hi0="%r11";
+$hi1="%r13";
+$i="%r14";
+$j="%r15";
+$m0="%rbx";
+$m1="%rbp";
+
+$code=<<___;
+.text
+
+.extern OPENSSL_ia32cap_P
+
+.globl bn_mul_mont_gather5
+.type bn_mul_mont_gather5,\@function,6
+.align 64
+bn_mul_mont_gather5:
+ test \$7,${num}d
+ jnz .Lmul_enter
+___
+$code.=<<___ if ($addx);
+ mov OPENSSL_ia32cap_P+8(%rip),%r11d
+___
+$code.=<<___;
+ jmp .Lmul4x_enter
+
+.align 16
+.Lmul_enter:
+ mov ${num}d,${num}d
+ mov %rsp,%rax
+ mov `($win64?56:8)`(%rsp),%r10d # load 7th argument
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+___
+$code.=<<___ if ($win64);
+ lea -0x28(%rsp),%rsp
+ movaps %xmm6,(%rsp)
+ movaps %xmm7,0x10(%rsp)
+___
+$code.=<<___;
+ lea 2($num),%r11
+ neg %r11
+ lea (%rsp,%r11,8),%rsp # tp=alloca(8*(num+2))
+ and \$-1024,%rsp # minimize TLB usage
+
+ mov %rax,8(%rsp,$num,8) # tp[num+1]=%rsp
+.Lmul_body:
+ mov $bp,%r12 # reassign $bp
+___
+ $bp="%r12";
+ $STRIDE=2**5*8; # 5 is "window size"
+ $N=$STRIDE/4; # should match cache line size
+$code.=<<___;
+ mov %r10,%r11
+ shr \$`log($N/8)/log(2)`,%r10
+ and \$`$N/8-1`,%r11
+ not %r10
+ lea .Lmagic_masks(%rip),%rax
+ and \$`2**5/($N/8)-1`,%r10 # 5 is "window size"
+ lea 96($bp,%r11,8),$bp # pointer within 1st cache line
+ movq 0(%rax,%r10,8),%xmm4 # set of masks denoting which
+ movq 8(%rax,%r10,8),%xmm5 # cache line contains element
+ movq 16(%rax,%r10,8),%xmm6 # denoted by 7th argument
+ movq 24(%rax,%r10,8),%xmm7
+
+ movq `0*$STRIDE/4-96`($bp),%xmm0
+ movq `1*$STRIDE/4-96`($bp),%xmm1
+ pand %xmm4,%xmm0
+ movq `2*$STRIDE/4-96`($bp),%xmm2
+ pand %xmm5,%xmm1
+ movq `3*$STRIDE/4-96`($bp),%xmm3
+ pand %xmm6,%xmm2
+ por %xmm1,%xmm0
+ pand %xmm7,%xmm3
+ por %xmm2,%xmm0
+ lea $STRIDE($bp),$bp
+ por %xmm3,%xmm0
+
+ movq %xmm0,$m0 # m0=bp[0]
+
+ mov ($n0),$n0 # pull n0[0] value
+ mov ($ap),%rax
+
+ xor $i,$i # i=0
+ xor $j,$j # j=0
+
+ movq `0*$STRIDE/4-96`($bp),%xmm0
+ movq `1*$STRIDE/4-96`($bp),%xmm1
+ pand %xmm4,%xmm0
+ movq `2*$STRIDE/4-96`($bp),%xmm2
+ pand %xmm5,%xmm1
+
+ mov $n0,$m1
+ mulq $m0 # ap[0]*bp[0]
+ mov %rax,$lo0
+ mov ($np),%rax
+
+ movq `3*$STRIDE/4-96`($bp),%xmm3
+ pand %xmm6,%xmm2
+ por %xmm1,%xmm0
+ pand %xmm7,%xmm3
+
+ imulq $lo0,$m1 # "tp[0]"*n0
+ mov %rdx,$hi0
+
+ por %xmm2,%xmm0
+ lea $STRIDE($bp),$bp
+ por %xmm3,%xmm0
+
+ mulq $m1 # np[0]*m1
+ add %rax,$lo0 # discarded
+ mov 8($ap),%rax
+ adc \$0,%rdx
+ mov %rdx,$hi1
+
+ lea 1($j),$j # j++
+ jmp .L1st_enter
+
+.align 16
+.L1st:
+ add %rax,$hi1
+ mov ($ap,$j,8),%rax
+ adc \$0,%rdx
+ add $hi0,$hi1 # np[j]*m1+ap[j]*bp[0]
+ mov $lo0,$hi0
+ adc \$0,%rdx
+ mov $hi1,-16(%rsp,$j,8) # tp[j-1]
+ mov %rdx,$hi1
+
+.L1st_enter:
+ mulq $m0 # ap[j]*bp[0]
+ add %rax,$hi0
+ mov ($np,$j,8),%rax
+ adc \$0,%rdx
+ lea 1($j),$j # j++
+ mov %rdx,$lo0
+
+ mulq $m1 # np[j]*m1
+ cmp $num,$j
+ jne .L1st
+
+ movq %xmm0,$m0 # bp[1]
+
+ add %rax,$hi1
+ mov ($ap),%rax # ap[0]
+ adc \$0,%rdx
+ add $hi0,$hi1 # np[j]*m1+ap[j]*bp[0]
+ adc \$0,%rdx
+ mov $hi1,-16(%rsp,$j,8) # tp[j-1]
+ mov %rdx,$hi1
+ mov $lo0,$hi0
+
+ xor %rdx,%rdx
+ add $hi0,$hi1
+ adc \$0,%rdx
+ mov $hi1,-8(%rsp,$num,8)
+ mov %rdx,(%rsp,$num,8) # store upmost overflow bit
+
+ lea 1($i),$i # i++
+ jmp .Louter
+.align 16
+.Louter:
+ xor $j,$j # j=0
+ mov $n0,$m1
+ mov (%rsp),$lo0
+
+ movq `0*$STRIDE/4-96`($bp),%xmm0
+ movq `1*$STRIDE/4-96`($bp),%xmm1
+ pand %xmm4,%xmm0
+ movq `2*$STRIDE/4-96`($bp),%xmm2
+ pand %xmm5,%xmm1
+
+ mulq $m0 # ap[0]*bp[i]
+ add %rax,$lo0 # ap[0]*bp[i]+tp[0]
+ mov ($np),%rax
+ adc \$0,%rdx
+
+ movq `3*$STRIDE/4-96`($bp),%xmm3
+ pand %xmm6,%xmm2
+ por %xmm1,%xmm0
+ pand %xmm7,%xmm3
+
+ imulq $lo0,$m1 # tp[0]*n0
+ mov %rdx,$hi0
+
+ por %xmm2,%xmm0
+ lea $STRIDE($bp),$bp
+ por %xmm3,%xmm0
+
+ mulq $m1 # np[0]*m1
+ add %rax,$lo0 # discarded
+ mov 8($ap),%rax
+ adc \$0,%rdx
+ mov 8(%rsp),$lo0 # tp[1]
+ mov %rdx,$hi1
+
+ lea 1($j),$j # j++
+ jmp .Linner_enter
+
+.align 16
+.Linner:
+ add %rax,$hi1
+ mov ($ap,$j,8),%rax
+ adc \$0,%rdx
+ add $lo0,$hi1 # np[j]*m1+ap[j]*bp[i]+tp[j]
+ mov (%rsp,$j,8),$lo0
+ adc \$0,%rdx
+ mov $hi1,-16(%rsp,$j,8) # tp[j-1]
+ mov %rdx,$hi1
+
+.Linner_enter:
+ mulq $m0 # ap[j]*bp[i]
+ add %rax,$hi0
+ mov ($np,$j,8),%rax
+ adc \$0,%rdx
+ add $hi0,$lo0 # ap[j]*bp[i]+tp[j]
+ mov %rdx,$hi0
+ adc \$0,$hi0
+ lea 1($j),$j # j++
+
+ mulq $m1 # np[j]*m1
+ cmp $num,$j
+ jne .Linner
+
+ movq %xmm0,$m0 # bp[i+1]
+
+ add %rax,$hi1
+ mov ($ap),%rax # ap[0]
+ adc \$0,%rdx
+ add $lo0,$hi1 # np[j]*m1+ap[j]*bp[i]+tp[j]
+ mov (%rsp,$j,8),$lo0
+ adc \$0,%rdx
+ mov $hi1,-16(%rsp,$j,8) # tp[j-1]
+ mov %rdx,$hi1
+
+ xor %rdx,%rdx
+ add $hi0,$hi1
+ adc \$0,%rdx
+ add $lo0,$hi1 # pull upmost overflow bit
+ adc \$0,%rdx
+ mov $hi1,-8(%rsp,$num,8)
+ mov %rdx,(%rsp,$num,8) # store upmost overflow bit
+
+ lea 1($i),$i # i++
+ cmp $num,$i
+ jb .Louter
+
+ xor $i,$i # i=0 and clear CF!
+ mov (%rsp),%rax # tp[0]
+ lea (%rsp),$ap # borrow ap for tp
+ mov $num,$j # j=num
+ jmp .Lsub
+.align 16
+.Lsub: sbb ($np,$i,8),%rax
+ mov %rax,($rp,$i,8) # rp[i]=tp[i]-np[i]
+ mov 8($ap,$i,8),%rax # tp[i+1]
+ lea 1($i),$i # i++
+ dec $j # doesnn't affect CF!
+ jnz .Lsub
+
+ sbb \$0,%rax # handle upmost overflow bit
+ xor $i,$i
+ and %rax,$ap
+ not %rax
+ mov $rp,$np
+ and %rax,$np
+ mov $num,$j # j=num
+ or $np,$ap # ap=borrow?tp:rp
+.align 16
+.Lcopy: # copy or in-place refresh
+ mov ($ap,$i,8),%rax
+ mov $i,(%rsp,$i,8) # zap temporary vector
+ mov %rax,($rp,$i,8) # rp[i]=tp[i]
+ lea 1($i),$i
+ sub \$1,$j
+ jnz .Lcopy
+
+ mov 8(%rsp,$num,8),%rsi # restore %rsp
+ mov \$1,%rax
+___
+$code.=<<___ if ($win64);
+ movaps -88(%rsi),%xmm6
+ movaps -72(%rsi),%xmm7
+___
+$code.=<<___;
+ mov -48(%rsi),%r15
+ mov -40(%rsi),%r14
+ mov -32(%rsi),%r13
+ mov -24(%rsi),%r12
+ mov -16(%rsi),%rbp
+ mov -8(%rsi),%rbx
+ lea (%rsi),%rsp
+.Lmul_epilogue:
+ ret
+.size bn_mul_mont_gather5,.-bn_mul_mont_gather5
+___
+{{{
+my @A=("%r10","%r11");
+my @N=("%r13","%rdi");
+$code.=<<___;
+.type bn_mul4x_mont_gather5,\@function,6
+.align 32
+bn_mul4x_mont_gather5:
+.Lmul4x_enter:
+___
+$code.=<<___ if ($addx);
+ and \$0x80100,%r11d
+ cmp \$0x80100,%r11d
+ je .Lmulx4x_enter
+___
+$code.=<<___;
+ .byte 0x67
+ mov %rsp,%rax
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+___
+$code.=<<___ if ($win64);
+ lea -0x28(%rsp),%rsp
+ movaps %xmm6,(%rsp)
+ movaps %xmm7,0x10(%rsp)
+___
+$code.=<<___;
+ .byte 0x67
+ mov ${num}d,%r10d
+ shl \$3,${num}d
+ shl \$3+2,%r10d # 4*$num
+ neg $num # -$num
+
+ ##############################################################
+ # ensure that stack frame doesn't alias with $aptr+4*$num
+ # modulo 4096, which covers ret[num], am[num] and n[2*num]
+ # (see bn_exp.c). this is done to allow memory disambiguation
+ # logic do its magic. [excessive frame is allocated in order
+ # to allow bn_from_mont8x to clear it.]
+ #
+ lea -64(%rsp,$num,2),%r11
+ sub $ap,%r11
+ and \$4095,%r11
+ cmp %r11,%r10
+ jb .Lmul4xsp_alt
+ sub %r11,%rsp # align with $ap
+ lea -64(%rsp,$num,2),%rsp # alloca(128+num*8)
+ jmp .Lmul4xsp_done
+
+.align 32
+.Lmul4xsp_alt:
+ lea 4096-64(,$num,2),%r10
+ lea -64(%rsp,$num,2),%rsp # alloca(128+num*8)
+ sub %r10,%r11
+ mov \$0,%r10
+ cmovc %r10,%r11
+ sub %r11,%rsp
+.Lmul4xsp_done:
+ and \$-64,%rsp
+ neg $num
+
+ mov %rax,40(%rsp)
+.Lmul4x_body:
+
+ call mul4x_internal
+
+ mov 40(%rsp),%rsi # restore %rsp
+ mov \$1,%rax
+___
+$code.=<<___ if ($win64);
+ movaps -88(%rsi),%xmm6
+ movaps -72(%rsi),%xmm7
+___
+$code.=<<___;
+ mov -48(%rsi),%r15
+ mov -40(%rsi),%r14
+ mov -32(%rsi),%r13
+ mov -24(%rsi),%r12
+ mov -16(%rsi),%rbp
+ mov -8(%rsi),%rbx
+ lea (%rsi),%rsp
+.Lmul4x_epilogue:
+ ret
+.size bn_mul4x_mont_gather5,.-bn_mul4x_mont_gather5
+
+.type mul4x_internal,\@abi-omnipotent
+.align 32
+mul4x_internal:
+ shl \$5,$num
+ mov `($win64?56:8)`(%rax),%r10d # load 7th argument
+ lea 256(%rdx,$num),%r13
+ shr \$5,$num # restore $num
+___
+ $bp="%r12";
+ $STRIDE=2**5*8; # 5 is "window size"
+ $N=$STRIDE/4; # should match cache line size
+ $tp=$i;
+$code.=<<___;
+ mov %r10,%r11
+ shr \$`log($N/8)/log(2)`,%r10
+ and \$`$N/8-1`,%r11
+ not %r10
+ lea .Lmagic_masks(%rip),%rax
+ and \$`2**5/($N/8)-1`,%r10 # 5 is "window size"
+ lea 96(%rdx,%r11,8),$bp # pointer within 1st cache line
+ movq 0(%rax,%r10,8),%xmm4 # set of masks denoting which
+ movq 8(%rax,%r10,8),%xmm5 # cache line contains element
+ add \$7,%r11
+ movq 16(%rax,%r10,8),%xmm6 # denoted by 7th argument
+ movq 24(%rax,%r10,8),%xmm7
+ and \$7,%r11
+
+ movq `0*$STRIDE/4-96`($bp),%xmm0
+ lea $STRIDE($bp),$tp # borrow $tp
+ movq `1*$STRIDE/4-96`($bp),%xmm1
+ pand %xmm4,%xmm0
+ movq `2*$STRIDE/4-96`($bp),%xmm2
+ pand %xmm5,%xmm1
+ movq `3*$STRIDE/4-96`($bp),%xmm3
+ pand %xmm6,%xmm2
+ .byte 0x67
+ por %xmm1,%xmm0
+ movq `0*$STRIDE/4-96`($tp),%xmm1
+ .byte 0x67
+ pand %xmm7,%xmm3
+ .byte 0x67
+ por %xmm2,%xmm0
+ movq `1*$STRIDE/4-96`($tp),%xmm2
+ .byte 0x67
+ pand %xmm4,%xmm1
+ .byte 0x67
+ por %xmm3,%xmm0
+ movq `2*$STRIDE/4-96`($tp),%xmm3
+
+ movq %xmm0,$m0 # m0=bp[0]
+ movq `3*$STRIDE/4-96`($tp),%xmm0
+ mov %r13,16+8(%rsp) # save end of b[num]
+ mov $rp, 56+8(%rsp) # save $rp
+
+ mov ($n0),$n0 # pull n0[0] value
+ mov ($ap),%rax
+ lea ($ap,$num),$ap # end of a[num]
+ neg $num
+
+ mov $n0,$m1
+ mulq $m0 # ap[0]*bp[0]
+ mov %rax,$A[0]
+ mov ($np),%rax
+
+ pand %xmm5,%xmm2
+ pand %xmm6,%xmm3
+ por %xmm2,%xmm1
+
+ imulq $A[0],$m1 # "tp[0]"*n0
+ ##############################################################
+ # $tp is chosen so that writing to top-most element of the
+ # vector occurs just "above" references to powers table,
+ # "above" modulo cache-line size, which effectively precludes
+ # possibility of memory disambiguation logic failure when
+ # accessing the table.
+ #
+ lea 64+8(%rsp,%r11,8),$tp
+ mov %rdx,$A[1]
+
+ pand %xmm7,%xmm0
+ por %xmm3,%xmm1
+ lea 2*$STRIDE($bp),$bp
+ por %xmm1,%xmm0
+
+ mulq $m1 # np[0]*m1
+ add %rax,$A[0] # discarded
+ mov 8($ap,$num),%rax
+ adc \$0,%rdx
+ mov %rdx,$N[1]
+
+ mulq $m0
+ add %rax,$A[1]
+ mov 16*1($np),%rax # interleaved with 0, therefore 16*n
+ adc \$0,%rdx
+ mov %rdx,$A[0]
+
+ mulq $m1
+ add %rax,$N[1]
+ mov 16($ap,$num),%rax
+ adc \$0,%rdx
+ add $A[1],$N[1]
+ lea 4*8($num),$j # j=4
+ lea 16*4($np),$np
+ adc \$0,%rdx
+ mov $N[1],($tp)
+ mov %rdx,$N[0]
+ jmp .L1st4x
+
+.align 32
+.L1st4x:
+ mulq $m0 # ap[j]*bp[0]
+ add %rax,$A[0]
+ mov -16*2($np),%rax
+ lea 32($tp),$tp
+ adc \$0,%rdx
+ mov %rdx,$A[1]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[0]
+ mov -8($ap,$j),%rax
+ adc \$0,%rdx
+ add $A[0],$N[0] # np[j]*m1+ap[j]*bp[0]
+ adc \$0,%rdx
+ mov $N[0],-24($tp) # tp[j-1]
+ mov %rdx,$N[1]
+
+ mulq $m0 # ap[j]*bp[0]
+ add %rax,$A[1]
+ mov -16*1($np),%rax
+ adc \$0,%rdx
+ mov %rdx,$A[0]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[1]
+ mov ($ap,$j),%rax
+ adc \$0,%rdx
+ add $A[1],$N[1] # np[j]*m1+ap[j]*bp[0]
+ adc \$0,%rdx
+ mov $N[1],-16($tp) # tp[j-1]
+ mov %rdx,$N[0]
+
+ mulq $m0 # ap[j]*bp[0]
+ add %rax,$A[0]
+ mov 16*0($np),%rax
+ adc \$0,%rdx
+ mov %rdx,$A[1]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[0]
+ mov 8($ap,$j),%rax
+ adc \$0,%rdx
+ add $A[0],$N[0] # np[j]*m1+ap[j]*bp[0]
+ adc \$0,%rdx
+ mov $N[0],-8($tp) # tp[j-1]
+ mov %rdx,$N[1]
+
+ mulq $m0 # ap[j]*bp[0]
+ add %rax,$A[1]
+ mov 16*1($np),%rax
+ adc \$0,%rdx
+ mov %rdx,$A[0]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[1]
+ mov 16($ap,$j),%rax
+ adc \$0,%rdx
+ add $A[1],$N[1] # np[j]*m1+ap[j]*bp[0]
+ lea 16*4($np),$np
+ adc \$0,%rdx
+ mov $N[1],($tp) # tp[j-1]
+ mov %rdx,$N[0]
+
+ add \$32,$j # j+=4
+ jnz .L1st4x
+
+ mulq $m0 # ap[j]*bp[0]
+ add %rax,$A[0]
+ mov -16*2($np),%rax
+ lea 32($tp),$tp
+ adc \$0,%rdx
+ mov %rdx,$A[1]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[0]
+ mov -8($ap),%rax
+ adc \$0,%rdx
+ add $A[0],$N[0] # np[j]*m1+ap[j]*bp[0]
+ adc \$0,%rdx
+ mov $N[0],-24($tp) # tp[j-1]
+ mov %rdx,$N[1]
+
+ mulq $m0 # ap[j]*bp[0]
+ add %rax,$A[1]
+ mov -16*1($np),%rax
+ adc \$0,%rdx
+ mov %rdx,$A[0]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[1]
+ mov ($ap,$num),%rax # ap[0]
+ adc \$0,%rdx
+ add $A[1],$N[1] # np[j]*m1+ap[j]*bp[0]
+ adc \$0,%rdx
+ mov $N[1],-16($tp) # tp[j-1]
+ mov %rdx,$N[0]
+
+ movq %xmm0,$m0 # bp[1]
+ lea ($np,$num,2),$np # rewind $np
+
+ xor $N[1],$N[1]
+ add $A[0],$N[0]
+ adc \$0,$N[1]
+ mov $N[0],-8($tp)
+
+ jmp .Louter4x
+
+.align 32
+.Louter4x:
+ mov ($tp,$num),$A[0]
+ mov $n0,$m1
+ mulq $m0 # ap[0]*bp[i]
+ add %rax,$A[0] # ap[0]*bp[i]+tp[0]
+ mov ($np),%rax
+ adc \$0,%rdx
+
+ movq `0*$STRIDE/4-96`($bp),%xmm0
+ movq `1*$STRIDE/4-96`($bp),%xmm1
+ pand %xmm4,%xmm0
+ movq `2*$STRIDE/4-96`($bp),%xmm2
+ pand %xmm5,%xmm1
+ movq `3*$STRIDE/4-96`($bp),%xmm3
+
+ imulq $A[0],$m1 # tp[0]*n0
+ .byte 0x67
+ mov %rdx,$A[1]
+ mov $N[1],($tp) # store upmost overflow bit
+
+ pand %xmm6,%xmm2
+ por %xmm1,%xmm0
+ pand %xmm7,%xmm3
+ por %xmm2,%xmm0
+ lea ($tp,$num),$tp # rewind $tp
+ lea $STRIDE($bp),$bp
+ por %xmm3,%xmm0
+
+ mulq $m1 # np[0]*m1
+ add %rax,$A[0] # "$N[0]", discarded
+ mov 8($ap,$num),%rax
+ adc \$0,%rdx
+ mov %rdx,$N[1]
+
+ mulq $m0 # ap[j]*bp[i]
+ add %rax,$A[1]
+ mov 16*1($np),%rax # interleaved with 0, therefore 16*n
+ adc \$0,%rdx
+ add 8($tp),$A[1] # +tp[1]
+ adc \$0,%rdx
+ mov %rdx,$A[0]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[1]
+ mov 16($ap,$num),%rax
+ adc \$0,%rdx
+ add $A[1],$N[1] # np[j]*m1+ap[j]*bp[i]+tp[j]
+ lea 4*8($num),$j # j=4
+ lea 16*4($np),$np
+ adc \$0,%rdx
+ mov %rdx,$N[0]
+ jmp .Linner4x
+
+.align 32
+.Linner4x:
+ mulq $m0 # ap[j]*bp[i]
+ add %rax,$A[0]
+ mov -16*2($np),%rax
+ adc \$0,%rdx
+ add 16($tp),$A[0] # ap[j]*bp[i]+tp[j]
+ lea 32($tp),$tp
+ adc \$0,%rdx
+ mov %rdx,$A[1]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[0]
+ mov -8($ap,$j),%rax
+ adc \$0,%rdx
+ add $A[0],$N[0]
+ adc \$0,%rdx
+ mov $N[1],-32($tp) # tp[j-1]
+ mov %rdx,$N[1]
+
+ mulq $m0 # ap[j]*bp[i]
+ add %rax,$A[1]
+ mov -16*1($np),%rax
+ adc \$0,%rdx
+ add -8($tp),$A[1]
+ adc \$0,%rdx
+ mov %rdx,$A[0]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[1]
+ mov ($ap,$j),%rax
+ adc \$0,%rdx
+ add $A[1],$N[1]
+ adc \$0,%rdx
+ mov $N[0],-24($tp) # tp[j-1]
+ mov %rdx,$N[0]
+
+ mulq $m0 # ap[j]*bp[i]
+ add %rax,$A[0]
+ mov 16*0($np),%rax
+ adc \$0,%rdx
+ add ($tp),$A[0] # ap[j]*bp[i]+tp[j]
+ adc \$0,%rdx
+ mov %rdx,$A[1]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[0]
+ mov 8($ap,$j),%rax
+ adc \$0,%rdx
+ add $A[0],$N[0]
+ adc \$0,%rdx
+ mov $N[1],-16($tp) # tp[j-1]
+ mov %rdx,$N[1]
+
+ mulq $m0 # ap[j]*bp[i]
+ add %rax,$A[1]
+ mov 16*1($np),%rax
+ adc \$0,%rdx
+ add 8($tp),$A[1]
+ adc \$0,%rdx
+ mov %rdx,$A[0]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[1]
+ mov 16($ap,$j),%rax
+ adc \$0,%rdx
+ add $A[1],$N[1]
+ lea 16*4($np),$np
+ adc \$0,%rdx
+ mov $N[0],-8($tp) # tp[j-1]
+ mov %rdx,$N[0]
+
+ add \$32,$j # j+=4
+ jnz .Linner4x
+
+ mulq $m0 # ap[j]*bp[i]
+ add %rax,$A[0]
+ mov -16*2($np),%rax
+ adc \$0,%rdx
+ add 16($tp),$A[0] # ap[j]*bp[i]+tp[j]
+ lea 32($tp),$tp
+ adc \$0,%rdx
+ mov %rdx,$A[1]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[0]
+ mov -8($ap),%rax
+ adc \$0,%rdx
+ add $A[0],$N[0]
+ adc \$0,%rdx
+ mov $N[1],-32($tp) # tp[j-1]
+ mov %rdx,$N[1]
+
+ mulq $m0 # ap[j]*bp[i]
+ add %rax,$A[1]
+ mov $m1,%rax
+ mov -16*1($np),$m1
+ adc \$0,%rdx
+ add -8($tp),$A[1]
+ adc \$0,%rdx
+ mov %rdx,$A[0]
+
+ mulq $m1 # np[j]*m1
+ add %rax,$N[1]
+ mov ($ap,$num),%rax # ap[0]
+ adc \$0,%rdx
+ add $A[1],$N[1]
+ adc \$0,%rdx
+ mov $N[0],-24($tp) # tp[j-1]
+ mov %rdx,$N[0]
+
+ movq %xmm0,$m0 # bp[i+1]
+ mov $N[1],-16($tp) # tp[j-1]
+ lea ($np,$num,2),$np # rewind $np
+
+ xor $N[1],$N[1]
+ add $A[0],$N[0]
+ adc \$0,$N[1]
+ add ($tp),$N[0] # pull upmost overflow bit
+ adc \$0,$N[1] # upmost overflow bit
+ mov $N[0],-8($tp)
+
+ cmp 16+8(%rsp),$bp
+ jb .Louter4x
+___
+if (1) {
+$code.=<<___;
+ sub $N[0],$m1 # compare top-most words
+ adc $j,$j # $j is zero
+ or $j,$N[1]
+ xor \$1,$N[1]
+ lea ($tp,$num),%rbx # tptr in .sqr4x_sub
+ lea ($np,$N[1],8),%rbp # nptr in .sqr4x_sub
+ mov %r9,%rcx
+ sar \$3+2,%rcx # cf=0
+ mov 56+8(%rsp),%rdi # rptr in .sqr4x_sub
+ jmp .Lsqr4x_sub
+___
+} else {
+my @ri=("%rax",$bp,$m0,$m1);
+my $rp="%rdx";
+$code.=<<___
+ xor \$1,$N[1]
+ lea ($tp,$num),$tp # rewind $tp
+ sar \$5,$num # cf=0
+ lea ($np,$N[1],8),$np
+ mov 56+8(%rsp),$rp # restore $rp
+ jmp .Lsub4x
+
+.align 32
+.Lsub4x:
+ .byte 0x66
+ mov 8*0($tp),@ri[0]
+ mov 8*1($tp),@ri[1]
+ .byte 0x66
+ sbb 16*0($np),@ri[0]
+ mov 8*2($tp),@ri[2]
+ sbb 16*1($np),@ri[1]
+ mov 3*8($tp),@ri[3]
+ lea 4*8($tp),$tp
+ sbb 16*2($np),@ri[2]
+ mov @ri[0],8*0($rp)
+ sbb 16*3($np),@ri[3]
+ lea 16*4($np),$np
+ mov @ri[1],8*1($rp)
+ mov @ri[2],8*2($rp)
+ mov @ri[3],8*3($rp)
+ lea 8*4($rp),$rp
+
+ inc $num
+ jnz .Lsub4x
+
+ ret
+___
+}
+$code.=<<___;
+.size mul4x_internal,.-mul4x_internal
+___
+}}}
+{{{
+######################################################################
+# void bn_power5(
+my $rptr="%rdi"; # BN_ULONG *rptr,
+my $aptr="%rsi"; # const BN_ULONG *aptr,
+my $bptr="%rdx"; # const void *table,
+my $nptr="%rcx"; # const BN_ULONG *nptr,
+my $n0 ="%r8"; # const BN_ULONG *n0);
+my $num ="%r9"; # int num, has to be divisible by 8
+ # int pwr
+
+my ($i,$j,$tptr)=("%rbp","%rcx",$rptr);
+my @A0=("%r10","%r11");
+my @A1=("%r12","%r13");
+my ($a0,$a1,$ai)=("%r14","%r15","%rbx");
+
+$code.=<<___;
+.globl bn_power5
+.type bn_power5,\@function,6
+.align 32
+bn_power5:
+___
+$code.=<<___ if ($addx);
+ mov OPENSSL_ia32cap_P+8(%rip),%r11d
+ and \$0x80100,%r11d
+ cmp \$0x80100,%r11d
+ je .Lpowerx5_enter
+___
+$code.=<<___;
+ mov %rsp,%rax
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+___
+$code.=<<___ if ($win64);
+ lea -0x28(%rsp),%rsp
+ movaps %xmm6,(%rsp)
+ movaps %xmm7,0x10(%rsp)
+___
+$code.=<<___;
+ mov ${num}d,%r10d
+ shl \$3,${num}d # convert $num to bytes
+ shl \$3+2,%r10d # 4*$num
+ neg $num
+ mov ($n0),$n0 # *n0
+
+ ##############################################################
+ # ensure that stack frame doesn't alias with $aptr+4*$num
+ # modulo 4096, which covers ret[num], am[num] and n[2*num]
+ # (see bn_exp.c). this is done to allow memory disambiguation
+ # logic do its magic.
+ #
+ lea -64(%rsp,$num,2),%r11
+ sub $aptr,%r11
+ and \$4095,%r11
+ cmp %r11,%r10
+ jb .Lpwr_sp_alt
+ sub %r11,%rsp # align with $aptr
+ lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num)
+ jmp .Lpwr_sp_done
+
+.align 32
+.Lpwr_sp_alt:
+ lea 4096-64(,$num,2),%r10 # 4096-frame-2*$num
+ lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num)
+ sub %r10,%r11
+ mov \$0,%r10
+ cmovc %r10,%r11
+ sub %r11,%rsp
+.Lpwr_sp_done:
+ and \$-64,%rsp
+ mov $num,%r10
+ neg $num
+
+ ##############################################################
+ # Stack layout
+ #
+ # +0 saved $num, used in reduction section
+ # +8 &t[2*$num], used in reduction section
+ # +32 saved *n0
+ # +40 saved %rsp
+ # +48 t[2*$num]
+ #
+ mov $n0, 32(%rsp)
+ mov %rax, 40(%rsp) # save original %rsp
+.Lpower5_body:
+ movq $rptr,%xmm1 # save $rptr
+ movq $nptr,%xmm2 # save $nptr
+ movq %r10, %xmm3 # -$num
+ movq $bptr,%xmm4
+
+ call __bn_sqr8x_internal
+ call __bn_sqr8x_internal
+ call __bn_sqr8x_internal
+ call __bn_sqr8x_internal
+ call __bn_sqr8x_internal
+
+ movq %xmm2,$nptr
+ movq %xmm4,$bptr
+ mov $aptr,$rptr
+ mov 40(%rsp),%rax
+ lea 32(%rsp),$n0
+
+ call mul4x_internal
+
+ mov 40(%rsp),%rsi # restore %rsp
+ mov \$1,%rax
+ mov -48(%rsi),%r15
+ mov -40(%rsi),%r14
+ mov -32(%rsi),%r13
+ mov -24(%rsi),%r12
+ mov -16(%rsi),%rbp
+ mov -8(%rsi),%rbx
+ lea (%rsi),%rsp
+.Lpower5_epilogue:
+ ret
+.size bn_power5,.-bn_power5
+
+.globl bn_sqr8x_internal
+.hidden bn_sqr8x_internal
+.type bn_sqr8x_internal,\@abi-omnipotent
+.align 32
+bn_sqr8x_internal:
+__bn_sqr8x_internal:
+ ##############################################################
+ # Squaring part:
+ #
+ # a) multiply-n-add everything but a[i]*a[i];
+ # b) shift result of a) by 1 to the left and accumulate
+ # a[i]*a[i] products;
+ #
+ ##############################################################
+ # a[1]a[0]
+ # a[2]a[0]
+ # a[3]a[0]
+ # a[2]a[1]
+ # a[4]a[0]
+ # a[3]a[1]
+ # a[5]a[0]
+ # a[4]a[1]
+ # a[3]a[2]
+ # a[6]a[0]
+ # a[5]a[1]
+ # a[4]a[2]
+ # a[7]a[0]
+ # a[6]a[1]
+ # a[5]a[2]
+ # a[4]a[3]
+ # a[7]a[1]
+ # a[6]a[2]
+ # a[5]a[3]
+ # a[7]a[2]
+ # a[6]a[3]
+ # a[5]a[4]
+ # a[7]a[3]
+ # a[6]a[4]
+ # a[7]a[4]
+ # a[6]a[5]
+ # a[7]a[5]
+ # a[7]a[6]
+ # a[1]a[0]
+ # a[2]a[0]
+ # a[3]a[0]
+ # a[4]a[0]
+ # a[5]a[0]
+ # a[6]a[0]
+ # a[7]a[0]
+ # a[2]a[1]
+ # a[3]a[1]
+ # a[4]a[1]
+ # a[5]a[1]
+ # a[6]a[1]
+ # a[7]a[1]
+ # a[3]a[2]
+ # a[4]a[2]
+ # a[5]a[2]
+ # a[6]a[2]
+ # a[7]a[2]
+ # a[4]a[3]
+ # a[5]a[3]
+ # a[6]a[3]
+ # a[7]a[3]
+ # a[5]a[4]
+ # a[6]a[4]
+ # a[7]a[4]
+ # a[6]a[5]
+ # a[7]a[5]
+ # a[7]a[6]
+ # a[0]a[0]
+ # a[1]a[1]
+ # a[2]a[2]
+ # a[3]a[3]
+ # a[4]a[4]
+ # a[5]a[5]
+ # a[6]a[6]
+ # a[7]a[7]
+
+ lea 32(%r10),$i # $i=-($num-32)
+ lea ($aptr,$num),$aptr # end of a[] buffer, ($aptr,$i)=&ap[2]
+
+ mov $num,$j # $j=$num
+
+ # comments apply to $num==8 case
+ mov -32($aptr,$i),$a0 # a[0]
+ lea 48+8(%rsp,$num,2),$tptr # end of tp[] buffer, &tp[2*$num]
+ mov -24($aptr,$i),%rax # a[1]
+ lea -32($tptr,$i),$tptr # end of tp[] window, &tp[2*$num-"$i"]
+ mov -16($aptr,$i),$ai # a[2]
+ mov %rax,$a1
+
+ mul $a0 # a[1]*a[0]
+ mov %rax,$A0[0] # a[1]*a[0]
+ mov $ai,%rax # a[2]
+ mov %rdx,$A0[1]
+ mov $A0[0],-24($tptr,$i) # t[1]
+
+ mul $a0 # a[2]*a[0]
+ add %rax,$A0[1]
+ mov $ai,%rax
+ adc \$0,%rdx
+ mov $A0[1],-16($tptr,$i) # t[2]
+ mov %rdx,$A0[0]
+
+
+ mov -8($aptr,$i),$ai # a[3]
+ mul $a1 # a[2]*a[1]
+ mov %rax,$A1[0] # a[2]*a[1]+t[3]
+ mov $ai,%rax
+ mov %rdx,$A1[1]
+
+ lea ($i),$j
+ mul $a0 # a[3]*a[0]
+ add %rax,$A0[0] # a[3]*a[0]+a[2]*a[1]+t[3]
+ mov $ai,%rax
+ mov %rdx,$A0[1]
+ adc \$0,$A0[1]
+ add $A1[0],$A0[0]
+ adc \$0,$A0[1]
+ mov $A0[0],-8($tptr,$j) # t[3]
+ jmp .Lsqr4x_1st
+
+.align 32
+.Lsqr4x_1st:
+ mov ($aptr,$j),$ai # a[4]
+ mul $a1 # a[3]*a[1]
+ add %rax,$A1[1] # a[3]*a[1]+t[4]
+ mov $ai,%rax
+ mov %rdx,$A1[0]
+ adc \$0,$A1[0]
+
+ mul $a0 # a[4]*a[0]
+ add %rax,$A0[1] # a[4]*a[0]+a[3]*a[1]+t[4]
+ mov $ai,%rax # a[3]
+ mov 8($aptr,$j),$ai # a[5]
+ mov %rdx,$A0[0]
+ adc \$0,$A0[0]
+ add $A1[1],$A0[1]
+ adc \$0,$A0[0]
+
+
+ mul $a1 # a[4]*a[3]
+ add %rax,$A1[0] # a[4]*a[3]+t[5]
+ mov $ai,%rax
+ mov $A0[1],($tptr,$j) # t[4]
+ mov %rdx,$A1[1]
+ adc \$0,$A1[1]
+
+ mul $a0 # a[5]*a[2]
+ add %rax,$A0[0] # a[5]*a[2]+a[4]*a[3]+t[5]
+ mov $ai,%rax
+ mov 16($aptr,$j),$ai # a[6]
+ mov %rdx,$A0[1]
+ adc \$0,$A0[1]
+ add $A1[0],$A0[0]
+ adc \$0,$A0[1]
+
+ mul $a1 # a[5]*a[3]
+ add %rax,$A1[1] # a[5]*a[3]+t[6]
+ mov $ai,%rax
+ mov $A0[0],8($tptr,$j) # t[5]
+ mov %rdx,$A1[0]
+ adc \$0,$A1[0]
+
+ mul $a0 # a[6]*a[2]
+ add %rax,$A0[1] # a[6]*a[2]+a[5]*a[3]+t[6]
+ mov $ai,%rax # a[3]
+ mov 24($aptr,$j),$ai # a[7]
+ mov %rdx,$A0[0]
+ adc \$0,$A0[0]
+ add $A1[1],$A0[1]
+ adc \$0,$A0[0]
+
+
+ mul $a1 # a[6]*a[5]
+ add %rax,$A1[0] # a[6]*a[5]+t[7]
+ mov $ai,%rax
+ mov $A0[1],16($tptr,$j) # t[6]
+ mov %rdx,$A1[1]
+ adc \$0,$A1[1]
+ lea 32($j),$j
+
+ mul $a0 # a[7]*a[4]
+ add %rax,$A0[0] # a[7]*a[4]+a[6]*a[5]+t[6]
+ mov $ai,%rax
+ mov %rdx,$A0[1]
+ adc \$0,$A0[1]
+ add $A1[0],$A0[0]
+ adc \$0,$A0[1]
+ mov $A0[0],-8($tptr,$j) # t[7]
+
+ cmp \$0,$j
+ jne .Lsqr4x_1st
+
+ mul $a1 # a[7]*a[5]
+ add %rax,$A1[1]
+ lea 16($i),$i
+ adc \$0,%rdx
+ add $A0[1],$A1[1]
+ adc \$0,%rdx
+
+ mov $A1[1],($tptr) # t[8]
+ mov %rdx,$A1[0]
+ mov %rdx,8($tptr) # t[9]
+ jmp .Lsqr4x_outer
+
+.align 32
+.Lsqr4x_outer: # comments apply to $num==6 case
+ mov -32($aptr,$i),$a0 # a[0]
+ lea 48+8(%rsp,$num,2),$tptr # end of tp[] buffer, &tp[2*$num]
+ mov -24($aptr,$i),%rax # a[1]
+ lea -32($tptr,$i),$tptr # end of tp[] window, &tp[2*$num-"$i"]
+ mov -16($aptr,$i),$ai # a[2]
+ mov %rax,$a1
+
+ mul $a0 # a[1]*a[0]
+ mov -24($tptr,$i),$A0[0] # t[1]
+ add %rax,$A0[0] # a[1]*a[0]+t[1]
+ mov $ai,%rax # a[2]
+ adc \$0,%rdx
+ mov $A0[0],-24($tptr,$i) # t[1]
+ mov %rdx,$A0[1]
+
+ mul $a0 # a[2]*a[0]
+ add %rax,$A0[1]
+ mov $ai,%rax
+ adc \$0,%rdx
+ add -16($tptr,$i),$A0[1] # a[2]*a[0]+t[2]
+ mov %rdx,$A0[0]
+ adc \$0,$A0[0]
+ mov $A0[1],-16($tptr,$i) # t[2]
+
+ xor $A1[0],$A1[0]
+
+ mov -8($aptr,$i),$ai # a[3]
+ mul $a1 # a[2]*a[1]
+ add %rax,$A1[0] # a[2]*a[1]+t[3]
+ mov $ai,%rax
+ adc \$0,%rdx
+ add -8($tptr,$i),$A1[0]
+ mov %rdx,$A1[1]
+ adc \$0,$A1[1]
+
+ mul $a0 # a[3]*a[0]
+ add %rax,$A0[0] # a[3]*a[0]+a[2]*a[1]+t[3]
+ mov $ai,%rax
+ adc \$0,%rdx
+ add $A1[0],$A0[0]
+ mov %rdx,$A0[1]
+ adc \$0,$A0[1]
+ mov $A0[0],-8($tptr,$i) # t[3]
+
+ lea ($i),$j
+ jmp .Lsqr4x_inner
+
+.align 32
+.Lsqr4x_inner:
+ mov ($aptr,$j),$ai # a[4]
+ mul $a1 # a[3]*a[1]
+ add %rax,$A1[1] # a[3]*a[1]+t[4]
+ mov $ai,%rax
+ mov %rdx,$A1[0]
+ adc \$0,$A1[0]
+ add ($tptr,$j),$A1[1]
+ adc \$0,$A1[0]
+
+ .byte 0x67
+ mul $a0 # a[4]*a[0]
+ add %rax,$A0[1] # a[4]*a[0]+a[3]*a[1]+t[4]
+ mov $ai,%rax # a[3]
+ mov 8($aptr,$j),$ai # a[5]
+ mov %rdx,$A0[0]
+ adc \$0,$A0[0]
+ add $A1[1],$A0[1]
+ adc \$0,$A0[0]
+
+ mul $a1 # a[4]*a[3]
+ add %rax,$A1[0] # a[4]*a[3]+t[5]
+ mov $A0[1],($tptr,$j) # t[4]
+ mov $ai,%rax
+ mov %rdx,$A1[1]
+ adc \$0,$A1[1]
+ add 8($tptr,$j),$A1[0]
+ lea 16($j),$j # j++
+ adc \$0,$A1[1]
+
+ mul $a0 # a[5]*a[2]
+ add %rax,$A0[0] # a[5]*a[2]+a[4]*a[3]+t[5]
+ mov $ai,%rax
+ adc \$0,%rdx
+ add $A1[0],$A0[0]
+ mov %rdx,$A0[1]
+ adc \$0,$A0[1]
+ mov $A0[0],-8($tptr,$j) # t[5], "preloaded t[1]" below
+
+ cmp \$0,$j
+ jne .Lsqr4x_inner
+
+ .byte 0x67
+ mul $a1 # a[5]*a[3]
+ add %rax,$A1[1]
+ adc \$0,%rdx
+ add $A0[1],$A1[1]
+ adc \$0,%rdx
+
+ mov $A1[1],($tptr) # t[6], "preloaded t[2]" below
+ mov %rdx,$A1[0]
+ mov %rdx,8($tptr) # t[7], "preloaded t[3]" below
+
+ add \$16,$i
+ jnz .Lsqr4x_outer
+
+ # comments apply to $num==4 case
+ mov -32($aptr),$a0 # a[0]
+ lea 48+8(%rsp,$num,2),$tptr # end of tp[] buffer, &tp[2*$num]
+ mov -24($aptr),%rax # a[1]
+ lea -32($tptr,$i),$tptr # end of tp[] window, &tp[2*$num-"$i"]
+ mov -16($aptr),$ai # a[2]
+ mov %rax,$a1
+
+ mul $a0 # a[1]*a[0]
+ add %rax,$A0[0] # a[1]*a[0]+t[1], preloaded t[1]
+ mov $ai,%rax # a[2]
+ mov %rdx,$A0[1]
+ adc \$0,$A0[1]
+
+ mul $a0 # a[2]*a[0]
+ add %rax,$A0[1]
+ mov $ai,%rax
+ mov $A0[0],-24($tptr) # t[1]
+ mov %rdx,$A0[0]
+ adc \$0,$A0[0]
+ add $A1[1],$A0[1] # a[2]*a[0]+t[2], preloaded t[2]
+ mov -8($aptr),$ai # a[3]
+ adc \$0,$A0[0]
+
+ mul $a1 # a[2]*a[1]
+ add %rax,$A1[0] # a[2]*a[1]+t[3], preloaded t[3]
+ mov $ai,%rax
+ mov $A0[1],-16($tptr) # t[2]
+ mov %rdx,$A1[1]
+ adc \$0,$A1[1]
+
+ mul $a0 # a[3]*a[0]
+ add %rax,$A0[0] # a[3]*a[0]+a[2]*a[1]+t[3]
+ mov $ai,%rax
+ mov %rdx,$A0[1]
+ adc \$0,$A0[1]
+ add $A1[0],$A0[0]
+ adc \$0,$A0[1]
+ mov $A0[0],-8($tptr) # t[3]
+
+ mul $a1 # a[3]*a[1]
+ add %rax,$A1[1]
+ mov -16($aptr),%rax # a[2]
+ adc \$0,%rdx
+ add $A0[1],$A1[1]
+ adc \$0,%rdx
+
+ mov $A1[1],($tptr) # t[4]
+ mov %rdx,$A1[0]
+ mov %rdx,8($tptr) # t[5]
+
+ mul $ai # a[2]*a[3]
+___
+{
+my ($shift,$carry)=($a0,$a1);
+my @S=(@A1,$ai,$n0);
+$code.=<<___;
+ add \$16,$i
+ xor $shift,$shift
+ sub $num,$i # $i=16-$num
+ xor $carry,$carry
+
+ add $A1[0],%rax # t[5]
+ adc \$0,%rdx
+ mov %rax,8($tptr) # t[5]
+ mov %rdx,16($tptr) # t[6]
+ mov $carry,24($tptr) # t[7]
+
+ mov -16($aptr,$i),%rax # a[0]
+ lea 48+8(%rsp),$tptr
+ xor $A0[0],$A0[0] # t[0]
+ mov 8($tptr),$A0[1] # t[1]
+
+ lea ($shift,$A0[0],2),$S[0] # t[2*i]<<1 | shift
+ shr \$63,$A0[0]
+ lea ($j,$A0[1],2),$S[1] # t[2*i+1]<<1 |
+ shr \$63,$A0[1]
+ or $A0[0],$S[1] # | t[2*i]>>63
+ mov 16($tptr),$A0[0] # t[2*i+2] # prefetch
+ mov $A0[1],$shift # shift=t[2*i+1]>>63
+ mul %rax # a[i]*a[i]
+ neg $carry # mov $carry,cf
+ mov 24($tptr),$A0[1] # t[2*i+2+1] # prefetch
+ adc %rax,$S[0]
+ mov -8($aptr,$i),%rax # a[i+1] # prefetch
+ mov $S[0],($tptr)
+ adc %rdx,$S[1]
+
+ lea ($shift,$A0[0],2),$S[2] # t[2*i]<<1 | shift
+ mov $S[1],8($tptr)
+ sbb $carry,$carry # mov cf,$carry
+ shr \$63,$A0[0]
+ lea ($j,$A0[1],2),$S[3] # t[2*i+1]<<1 |
+ shr \$63,$A0[1]
+ or $A0[0],$S[3] # | t[2*i]>>63
+ mov 32($tptr),$A0[0] # t[2*i+2] # prefetch
+ mov $A0[1],$shift # shift=t[2*i+1]>>63
+ mul %rax # a[i]*a[i]
+ neg $carry # mov $carry,cf
+ mov 40($tptr),$A0[1] # t[2*i+2+1] # prefetch
+ adc %rax,$S[2]
+ mov 0($aptr,$i),%rax # a[i+1] # prefetch
+ mov $S[2],16($tptr)
+ adc %rdx,$S[3]
+ lea 16($i),$i
+ mov $S[3],24($tptr)
+ sbb $carry,$carry # mov cf,$carry
+ lea 64($tptr),$tptr
+ jmp .Lsqr4x_shift_n_add
+
+.align 32
+.Lsqr4x_shift_n_add:
+ lea ($shift,$A0[0],2),$S[0] # t[2*i]<<1 | shift
+ shr \$63,$A0[0]
+ lea ($j,$A0[1],2),$S[1] # t[2*i+1]<<1 |
+ shr \$63,$A0[1]
+ or $A0[0],$S[1] # | t[2*i]>>63
+ mov -16($tptr),$A0[0] # t[2*i+2] # prefetch
+ mov $A0[1],$shift # shift=t[2*i+1]>>63
+ mul %rax # a[i]*a[i]
+ neg $carry # mov $carry,cf
+ mov -8($tptr),$A0[1] # t[2*i+2+1] # prefetch
+ adc %rax,$S[0]
+ mov -8($aptr,$i),%rax # a[i+1] # prefetch
+ mov $S[0],-32($tptr)
+ adc %rdx,$S[1]
+
+ lea ($shift,$A0[0],2),$S[2] # t[2*i]<<1 | shift
+ mov $S[1],-24($tptr)
+ sbb $carry,$carry # mov cf,$carry
+ shr \$63,$A0[0]
+ lea ($j,$A0[1],2),$S[3] # t[2*i+1]<<1 |
+ shr \$63,$A0[1]
+ or $A0[0],$S[3] # | t[2*i]>>63
+ mov 0($tptr),$A0[0] # t[2*i+2] # prefetch
+ mov $A0[1],$shift # shift=t[2*i+1]>>63
+ mul %rax # a[i]*a[i]
+ neg $carry # mov $carry,cf
+ mov 8($tptr),$A0[1] # t[2*i+2+1] # prefetch
+ adc %rax,$S[2]
+ mov 0($aptr,$i),%rax # a[i+1] # prefetch
+ mov $S[2],-16($tptr)
+ adc %rdx,$S[3]
+
+ lea ($shift,$A0[0],2),$S[0] # t[2*i]<<1 | shift
+ mov $S[3],-8($tptr)
+ sbb $carry,$carry # mov cf,$carry
+ shr \$63,$A0[0]
+ lea ($j,$A0[1],2),$S[1] # t[2*i+1]<<1 |
+ shr \$63,$A0[1]
+ or $A0[0],$S[1] # | t[2*i]>>63
+ mov 16($tptr),$A0[0] # t[2*i+2] # prefetch
+ mov $A0[1],$shift # shift=t[2*i+1]>>63
+ mul %rax # a[i]*a[i]
+ neg $carry # mov $carry,cf
+ mov 24($tptr),$A0[1] # t[2*i+2+1] # prefetch
+ adc %rax,$S[0]
+ mov 8($aptr,$i),%rax # a[i+1] # prefetch
+ mov $S[0],0($tptr)
+ adc %rdx,$S[1]
+
+ lea ($shift,$A0[0],2),$S[2] # t[2*i]<<1 | shift
+ mov $S[1],8($tptr)
+ sbb $carry,$carry # mov cf,$carry
+ shr \$63,$A0[0]
+ lea ($j,$A0[1],2),$S[3] # t[2*i+1]<<1 |
+ shr \$63,$A0[1]
+ or $A0[0],$S[3] # | t[2*i]>>63
+ mov 32($tptr),$A0[0] # t[2*i+2] # prefetch
+ mov $A0[1],$shift # shift=t[2*i+1]>>63
+ mul %rax # a[i]*a[i]
+ neg $carry # mov $carry,cf
+ mov 40($tptr),$A0[1] # t[2*i+2+1] # prefetch
+ adc %rax,$S[2]
+ mov 16($aptr,$i),%rax # a[i+1] # prefetch
+ mov $S[2],16($tptr)
+ adc %rdx,$S[3]
+ mov $S[3],24($tptr)
+ sbb $carry,$carry # mov cf,$carry
+ lea 64($tptr),$tptr
+ add \$32,$i
+ jnz .Lsqr4x_shift_n_add
+
+ lea ($shift,$A0[0],2),$S[0] # t[2*i]<<1 | shift
+ .byte 0x67
+ shr \$63,$A0[0]
+ lea ($j,$A0[1],2),$S[1] # t[2*i+1]<<1 |
+ shr \$63,$A0[1]
+ or $A0[0],$S[1] # | t[2*i]>>63
+ mov -16($tptr),$A0[0] # t[2*i+2] # prefetch
+ mov $A0[1],$shift # shift=t[2*i+1]>>63
+ mul %rax # a[i]*a[i]
+ neg $carry # mov $carry,cf
+ mov -8($tptr),$A0[1] # t[2*i+2+1] # prefetch
+ adc %rax,$S[0]
+ mov -8($aptr),%rax # a[i+1] # prefetch
+ mov $S[0],-32($tptr)
+ adc %rdx,$S[1]
+
+ lea ($shift,$A0[0],2),$S[2] # t[2*i]<<1|shift
+ mov $S[1],-24($tptr)
+ sbb $carry,$carry # mov cf,$carry
+ shr \$63,$A0[0]
+ lea ($j,$A0[1],2),$S[3] # t[2*i+1]<<1 |
+ shr \$63,$A0[1]
+ or $A0[0],$S[3] # | t[2*i]>>63
+ mul %rax # a[i]*a[i]
+ neg $carry # mov $carry,cf
+ adc %rax,$S[2]
+ adc %rdx,$S[3]
+ mov $S[2],-16($tptr)
+ mov $S[3],-8($tptr)
+___
+}
+######################################################################
+# Montgomery reduction part, "word-by-word" algorithm.
+#
+# This new path is inspired by multiple submissions from Intel, by
+# Shay Gueron, Vlad Krasnov, Erdinc Ozturk, James Guilford,
+# Vinodh Gopal...
+{
+my ($nptr,$tptr,$carry,$m0)=("%rbp","%rdi","%rsi","%rbx");
+
+$code.=<<___;
+ movq %xmm2,$nptr
+sqr8x_reduction:
+ xor %rax,%rax
+ lea ($nptr,$num,2),%rcx # end of n[]
+ lea 48+8(%rsp,$num,2),%rdx # end of t[] buffer
+ mov %rcx,0+8(%rsp)
+ lea 48+8(%rsp,$num),$tptr # end of initial t[] window
+ mov %rdx,8+8(%rsp)
+ neg $num
+ jmp .L8x_reduction_loop
+
+.align 32
+.L8x_reduction_loop:
+ lea ($tptr,$num),$tptr # start of current t[] window
+ .byte 0x66
+ mov 8*0($tptr),$m0
+ mov 8*1($tptr),%r9
+ mov 8*2($tptr),%r10
+ mov 8*3($tptr),%r11
+ mov 8*4($tptr),%r12
+ mov 8*5($tptr),%r13
+ mov 8*6($tptr),%r14
+ mov 8*7($tptr),%r15
+ mov %rax,(%rdx) # store top-most carry bit
+ lea 8*8($tptr),$tptr
+
+ .byte 0x67
+ mov $m0,%r8
+ imulq 32+8(%rsp),$m0 # n0*a[0]
+ mov 16*0($nptr),%rax # n[0]
+ mov \$8,%ecx
+ jmp .L8x_reduce
+
+.align 32
+.L8x_reduce:
+ mulq $m0
+ mov 16*1($nptr),%rax # n[1]
+ neg %r8
+ mov %rdx,%r8
+ adc \$0,%r8
+
+ mulq $m0
+ add %rax,%r9
+ mov 16*2($nptr),%rax
+ adc \$0,%rdx
+ add %r9,%r8
+ mov $m0,48-8+8(%rsp,%rcx,8) # put aside n0*a[i]
+ mov %rdx,%r9
+ adc \$0,%r9
+
+ mulq $m0
+ add %rax,%r10
+ mov 16*3($nptr),%rax
+ adc \$0,%rdx
+ add %r10,%r9
+ mov 32+8(%rsp),$carry # pull n0, borrow $carry
+ mov %rdx,%r10
+ adc \$0,%r10
+
+ mulq $m0
+ add %rax,%r11
+ mov 16*4($nptr),%rax
+ adc \$0,%rdx
+ imulq %r8,$carry # modulo-scheduled
+ add %r11,%r10
+ mov %rdx,%r11
+ adc \$0,%r11
+
+ mulq $m0
+ add %rax,%r12
+ mov 16*5($nptr),%rax
+ adc \$0,%rdx
+ add %r12,%r11
+ mov %rdx,%r12
+ adc \$0,%r12
+
+ mulq $m0
+ add %rax,%r13
+ mov 16*6($nptr),%rax
+ adc \$0,%rdx
+ add %r13,%r12
+ mov %rdx,%r13
+ adc \$0,%r13
+
+ mulq $m0
+ add %rax,%r14
+ mov 16*7($nptr),%rax
+ adc \$0,%rdx
+ add %r14,%r13
+ mov %rdx,%r14
+ adc \$0,%r14
+
+ mulq $m0
+ mov $carry,$m0 # n0*a[i]
+ add %rax,%r15
+ mov 16*0($nptr),%rax # n[0]
+ adc \$0,%rdx
+ add %r15,%r14
+ mov %rdx,%r15
+ adc \$0,%r15
+
+ dec %ecx
+ jnz .L8x_reduce
+
+ lea 16*8($nptr),$nptr
+ xor %rax,%rax
+ mov 8+8(%rsp),%rdx # pull end of t[]
+ cmp 0+8(%rsp),$nptr # end of n[]?
+ jae .L8x_no_tail
+
+ .byte 0x66
+ add 8*0($tptr),%r8
+ adc 8*1($tptr),%r9
+ adc 8*2($tptr),%r10
+ adc 8*3($tptr),%r11
+ adc 8*4($tptr),%r12
+ adc 8*5($tptr),%r13
+ adc 8*6($tptr),%r14
+ adc 8*7($tptr),%r15
+ sbb $carry,$carry # top carry
+
+ mov 48+56+8(%rsp),$m0 # pull n0*a[0]
+ mov \$8,%ecx
+ mov 16*0($nptr),%rax
+ jmp .L8x_tail
+
+.align 32
+.L8x_tail:
+ mulq $m0
+ add %rax,%r8
+ mov 16*1($nptr),%rax
+ mov %r8,($tptr) # save result
+ mov %rdx,%r8
+ adc \$0,%r8
+
+ mulq $m0
+ add %rax,%r9
+ mov 16*2($nptr),%rax
+ adc \$0,%rdx
+ add %r9,%r8
+ lea 8($tptr),$tptr # $tptr++
+ mov %rdx,%r9
+ adc \$0,%r9
+
+ mulq $m0
+ add %rax,%r10
+ mov 16*3($nptr),%rax
+ adc \$0,%rdx
+ add %r10,%r9
+ mov %rdx,%r10
+ adc \$0,%r10
+
+ mulq $m0
+ add %rax,%r11
+ mov 16*4($nptr),%rax
+ adc \$0,%rdx
+ add %r11,%r10
+ mov %rdx,%r11
+ adc \$0,%r11
+
+ mulq $m0
+ add %rax,%r12
+ mov 16*5($nptr),%rax
+ adc \$0,%rdx
+ add %r12,%r11
+ mov %rdx,%r12
+ adc \$0,%r12
+
+ mulq $m0
+ add %rax,%r13
+ mov 16*6($nptr),%rax
+ adc \$0,%rdx
+ add %r13,%r12
+ mov %rdx,%r13
+ adc \$0,%r13
+
+ mulq $m0
+ add %rax,%r14
+ mov 16*7($nptr),%rax
+ adc \$0,%rdx
+ add %r14,%r13
+ mov %rdx,%r14
+ adc \$0,%r14
+
+ mulq $m0
+ mov 48-16+8(%rsp,%rcx,8),$m0# pull n0*a[i]
+ add %rax,%r15
+ adc \$0,%rdx
+ add %r15,%r14
+ mov 16*0($nptr),%rax # pull n[0]
+ mov %rdx,%r15
+ adc \$0,%r15
+
+ dec %ecx
+ jnz .L8x_tail
+
+ lea 16*8($nptr),$nptr
+ mov 8+8(%rsp),%rdx # pull end of t[]
+ cmp 0+8(%rsp),$nptr # end of n[]?
+ jae .L8x_tail_done # break out of loop
+
+ mov 48+56+8(%rsp),$m0 # pull n0*a[0]
+ neg $carry
+ mov 8*0($nptr),%rax # pull n[0]
+ adc 8*0($tptr),%r8
+ adc 8*1($tptr),%r9
+ adc 8*2($tptr),%r10
+ adc 8*3($tptr),%r11
+ adc 8*4($tptr),%r12
+ adc 8*5($tptr),%r13
+ adc 8*6($tptr),%r14
+ adc 8*7($tptr),%r15
+ sbb $carry,$carry # top carry
+
+ mov \$8,%ecx
+ jmp .L8x_tail
+
+.align 32
+.L8x_tail_done:
+ add (%rdx),%r8 # can this overflow?
+ xor %rax,%rax
+
+ neg $carry
+.L8x_no_tail:
+ adc 8*0($tptr),%r8
+ adc 8*1($tptr),%r9
+ adc 8*2($tptr),%r10
+ adc 8*3($tptr),%r11
+ adc 8*4($tptr),%r12
+ adc 8*5($tptr),%r13
+ adc 8*6($tptr),%r14
+ adc 8*7($tptr),%r15
+ adc \$0,%rax # top-most carry
+ mov -16($nptr),%rcx # np[num-1]
+ xor $carry,$carry
+
+ movq %xmm2,$nptr # restore $nptr
+
+ mov %r8,8*0($tptr) # store top 512 bits
+ mov %r9,8*1($tptr)
+ movq %xmm3,$num # $num is %r9, can't be moved upwards
+ mov %r10,8*2($tptr)
+ mov %r11,8*3($tptr)
+ mov %r12,8*4($tptr)
+ mov %r13,8*5($tptr)
+ mov %r14,8*6($tptr)
+ mov %r15,8*7($tptr)
+ lea 8*8($tptr),$tptr
+
+ cmp %rdx,$tptr # end of t[]?
+ jb .L8x_reduction_loop
+___
+}
+##############################################################
+# Post-condition, 4x unrolled
+#
+{
+my ($tptr,$nptr)=("%rbx","%rbp");
+$code.=<<___;
+ #xor %rsi,%rsi # %rsi was $carry above
+ sub %r15,%rcx # compare top-most words
+ lea (%rdi,$num),$tptr # %rdi was $tptr above
+ adc %rsi,%rsi
+ mov $num,%rcx
+ or %rsi,%rax
+ movq %xmm1,$rptr # restore $rptr
+ xor \$1,%rax
+ movq %xmm1,$aptr # prepare for back-to-back call
+ lea ($nptr,%rax,8),$nptr
+ sar \$3+2,%rcx # cf=0
+ jmp .Lsqr4x_sub
+
+.align 32
+.Lsqr4x_sub:
+ .byte 0x66
+ mov 8*0($tptr),%r12
+ mov 8*1($tptr),%r13
+ sbb 16*0($nptr),%r12
+ mov 8*2($tptr),%r14
+ sbb 16*1($nptr),%r13
+ mov 8*3($tptr),%r15
+ lea 8*4($tptr),$tptr
+ sbb 16*2($nptr),%r14
+ mov %r12,8*0($rptr)
+ sbb 16*3($nptr),%r15
+ lea 16*4($nptr),$nptr
+ mov %r13,8*1($rptr)
+ mov %r14,8*2($rptr)
+ mov %r15,8*3($rptr)
+ lea 8*4($rptr),$rptr
+
+ inc %rcx # pass %cf
+ jnz .Lsqr4x_sub
+___
+}
+$code.=<<___;
+ mov $num,%r10 # prepare for back-to-back call
+ neg $num # restore $num
+ ret
+.size bn_sqr8x_internal,.-bn_sqr8x_internal
+___
+{
+$code.=<<___;
+.globl bn_from_montgomery
+.type bn_from_montgomery,\@abi-omnipotent
+.align 32
+bn_from_montgomery:
+ testl \$7,`($win64?"48(%rsp)":"%r9d")`
+ jz bn_from_mont8x
+ xor %eax,%eax
+ ret
+.size bn_from_montgomery,.-bn_from_montgomery
+
+.type bn_from_mont8x,\@function,6
+.align 32
+bn_from_mont8x:
+ .byte 0x67
+ mov %rsp,%rax
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+___
+$code.=<<___ if ($win64);
+ lea -0x28(%rsp),%rsp
+ movaps %xmm6,(%rsp)
+ movaps %xmm7,0x10(%rsp)
+___
+$code.=<<___;
+ .byte 0x67
+ mov ${num}d,%r10d
+ shl \$3,${num}d # convert $num to bytes
+ shl \$3+2,%r10d # 4*$num
+ neg $num
+ mov ($n0),$n0 # *n0
+
+ ##############################################################
+ # ensure that stack frame doesn't alias with $aptr+4*$num
+ # modulo 4096, which covers ret[num], am[num] and n[2*num]
+ # (see bn_exp.c). this is done to allow memory disambiguation
+ # logic do its magic.
+ #
+ lea -64(%rsp,$num,2),%r11
+ sub $aptr,%r11
+ and \$4095,%r11
+ cmp %r11,%r10
+ jb .Lfrom_sp_alt
+ sub %r11,%rsp # align with $aptr
+ lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num)
+ jmp .Lfrom_sp_done
+
+.align 32
+.Lfrom_sp_alt:
+ lea 4096-64(,$num,2),%r10 # 4096-frame-2*$num
+ lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num)
+ sub %r10,%r11
+ mov \$0,%r10
+ cmovc %r10,%r11
+ sub %r11,%rsp
+.Lfrom_sp_done:
+ and \$-64,%rsp
+ mov $num,%r10
+ neg $num
+
+ ##############################################################
+ # Stack layout
+ #
+ # +0 saved $num, used in reduction section
+ # +8 &t[2*$num], used in reduction section
+ # +32 saved *n0
+ # +40 saved %rsp
+ # +48 t[2*$num]
+ #
+ mov $n0, 32(%rsp)
+ mov %rax, 40(%rsp) # save original %rsp
+.Lfrom_body:
+ mov $num,%r11
+ lea 48(%rsp),%rax
+ pxor %xmm0,%xmm0
+ jmp .Lmul_by_1
+
+.align 32
+.Lmul_by_1:
+ movdqu ($aptr),%xmm1
+ movdqu 16($aptr),%xmm2
+ movdqu 32($aptr),%xmm3
+ movdqa %xmm0,(%rax,$num)
+ movdqu 48($aptr),%xmm4
+ movdqa %xmm0,16(%rax,$num)
+ .byte 0x48,0x8d,0xb6,0x40,0x00,0x00,0x00 # lea 64($aptr),$aptr
+ movdqa %xmm1,(%rax)
+ movdqa %xmm0,32(%rax,$num)
+ movdqa %xmm2,16(%rax)
+ movdqa %xmm0,48(%rax,$num)
+ movdqa %xmm3,32(%rax)
+ movdqa %xmm4,48(%rax)
+ lea 64(%rax),%rax
+ sub \$64,%r11
+ jnz .Lmul_by_1
+
+ movq $rptr,%xmm1
+ movq $nptr,%xmm2
+ .byte 0x67
+ mov $nptr,%rbp
+ movq %r10, %xmm3 # -num
+___
+$code.=<<___ if ($addx);
+ mov OPENSSL_ia32cap_P+8(%rip),%r11d
+ and \$0x80100,%r11d
+ cmp \$0x80100,%r11d
+ jne .Lfrom_mont_nox
+
+ lea (%rax,$num),$rptr
+ call sqrx8x_reduction
+
+ pxor %xmm0,%xmm0
+ lea 48(%rsp),%rax
+ mov 40(%rsp),%rsi # restore %rsp
+ jmp .Lfrom_mont_zero
+
+.align 32
+.Lfrom_mont_nox:
+___
+$code.=<<___;
+ call sqr8x_reduction
+
+ pxor %xmm0,%xmm0
+ lea 48(%rsp),%rax
+ mov 40(%rsp),%rsi # restore %rsp
+ jmp .Lfrom_mont_zero
+
+.align 32
+.Lfrom_mont_zero:
+ movdqa %xmm0,16*0(%rax)
+ movdqa %xmm0,16*1(%rax)
+ movdqa %xmm0,16*2(%rax)
+ movdqa %xmm0,16*3(%rax)
+ lea 16*4(%rax),%rax
+ sub \$32,$num
+ jnz .Lfrom_mont_zero
+
+ mov \$1,%rax
+ mov -48(%rsi),%r15
+ mov -40(%rsi),%r14
+ mov -32(%rsi),%r13
+ mov -24(%rsi),%r12
+ mov -16(%rsi),%rbp
+ mov -8(%rsi),%rbx
+ lea (%rsi),%rsp
+.Lfrom_epilogue:
+ ret
+.size bn_from_mont8x,.-bn_from_mont8x
+___
+}
+}}}
+
+if ($addx) {{{
+my $bp="%rdx"; # restore original value
+
+$code.=<<___;
+.type bn_mulx4x_mont_gather5,\@function,6
+.align 32
+bn_mulx4x_mont_gather5:
+.Lmulx4x_enter:
+ .byte 0x67
+ mov %rsp,%rax
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+___
+$code.=<<___ if ($win64);
+ lea -0x28(%rsp),%rsp
+ movaps %xmm6,(%rsp)
+ movaps %xmm7,0x10(%rsp)
+___
+$code.=<<___;
+ .byte 0x67
+ mov ${num}d,%r10d
+ shl \$3,${num}d # convert $num to bytes
+ shl \$3+2,%r10d # 4*$num
+ neg $num # -$num
+ mov ($n0),$n0 # *n0
+
+ ##############################################################
+ # ensure that stack frame doesn't alias with $aptr+4*$num
+ # modulo 4096, which covers a[num], ret[num] and n[2*num]
+ # (see bn_exp.c). this is done to allow memory disambiguation
+ # logic do its magic. [excessive frame is allocated in order
+ # to allow bn_from_mont8x to clear it.]
+ #
+ lea -64(%rsp,$num,2),%r11
+ sub $ap,%r11
+ and \$4095,%r11
+ cmp %r11,%r10
+ jb .Lmulx4xsp_alt
+ sub %r11,%rsp # align with $aptr
+ lea -64(%rsp,$num,2),%rsp # alloca(frame+$num)
+ jmp .Lmulx4xsp_done
+
+.align 32
+.Lmulx4xsp_alt:
+ lea 4096-64(,$num,2),%r10 # 4096-frame-$num
+ lea -64(%rsp,$num,2),%rsp # alloca(frame+$num)
+ sub %r10,%r11
+ mov \$0,%r10
+ cmovc %r10,%r11
+ sub %r11,%rsp
+.Lmulx4xsp_done:
+ and \$-64,%rsp # ensure alignment
+ ##############################################################
+ # Stack layout
+ # +0 -num
+ # +8 off-loaded &b[i]
+ # +16 end of b[num]
+ # +24 inner counter
+ # +32 saved n0
+ # +40 saved %rsp
+ # +48
+ # +56 saved rp
+ # +64 tmp[num+1]
+ #
+ mov $n0, 32(%rsp) # save *n0
+ mov %rax,40(%rsp) # save original %rsp
+.Lmulx4x_body:
+ call mulx4x_internal
+
+ mov 40(%rsp),%rsi # restore %rsp
+ mov \$1,%rax
+___
+$code.=<<___ if ($win64);
+ movaps -88(%rsi),%xmm6
+ movaps -72(%rsi),%xmm7
+___
+$code.=<<___;
+ mov -48(%rsi),%r15
+ mov -40(%rsi),%r14
+ mov -32(%rsi),%r13
+ mov -24(%rsi),%r12
+ mov -16(%rsi),%rbp
+ mov -8(%rsi),%rbx
+ lea (%rsi),%rsp
+.Lmulx4x_epilogue:
+ ret
+.size bn_mulx4x_mont_gather5,.-bn_mulx4x_mont_gather5
+
+.type mulx4x_internal,\@abi-omnipotent
+.align 32
+mulx4x_internal:
+ .byte 0x4c,0x89,0x8c,0x24,0x08,0x00,0x00,0x00 # mov $num,8(%rsp) # save -$num
+ .byte 0x67
+ neg $num # restore $num
+ shl \$5,$num
+ lea 256($bp,$num),%r13
+ shr \$5+5,$num
+ mov `($win64?56:8)`(%rax),%r10d # load 7th argument
+ sub \$1,$num
+ mov %r13,16+8(%rsp) # end of b[num]
+ mov $num,24+8(%rsp) # inner counter
+ mov $rp, 56+8(%rsp) # save $rp
+___
+my ($aptr, $bptr, $nptr, $tptr, $mi, $bi, $zero, $num)=
+ ("%rsi","%rdi","%rcx","%rbx","%r8","%r9","%rbp","%rax");
+my $rptr=$bptr;
+my $STRIDE=2**5*8; # 5 is "window size"
+my $N=$STRIDE/4; # should match cache line size
+$code.=<<___;
+ mov %r10,%r11
+ shr \$`log($N/8)/log(2)`,%r10
+ and \$`$N/8-1`,%r11
+ not %r10
+ lea .Lmagic_masks(%rip),%rax
+ and \$`2**5/($N/8)-1`,%r10 # 5 is "window size"
+ lea 96($bp,%r11,8),$bptr # pointer within 1st cache line
+ movq 0(%rax,%r10,8),%xmm4 # set of masks denoting which
+ movq 8(%rax,%r10,8),%xmm5 # cache line contains element
+ add \$7,%r11
+ movq 16(%rax,%r10,8),%xmm6 # denoted by 7th argument
+ movq 24(%rax,%r10,8),%xmm7
+ and \$7,%r11
+
+ movq `0*$STRIDE/4-96`($bptr),%xmm0
+ lea $STRIDE($bptr),$tptr # borrow $tptr
+ movq `1*$STRIDE/4-96`($bptr),%xmm1
+ pand %xmm4,%xmm0
+ movq `2*$STRIDE/4-96`($bptr),%xmm2
+ pand %xmm5,%xmm1
+ movq `3*$STRIDE/4-96`($bptr),%xmm3
+ pand %xmm6,%xmm2
+ por %xmm1,%xmm0
+ movq `0*$STRIDE/4-96`($tptr),%xmm1
+ pand %xmm7,%xmm3
+ por %xmm2,%xmm0
+ movq `1*$STRIDE/4-96`($tptr),%xmm2
+ por %xmm3,%xmm0
+ .byte 0x67,0x67
+ pand %xmm4,%xmm1
+ movq `2*$STRIDE/4-96`($tptr),%xmm3
+
+ movq %xmm0,%rdx # bp[0]
+ movq `3*$STRIDE/4-96`($tptr),%xmm0
+ lea 2*$STRIDE($bptr),$bptr # next &b[i]
+ pand %xmm5,%xmm2
+ .byte 0x67,0x67
+ pand %xmm6,%xmm3
+ ##############################################################
+ # $tptr is chosen so that writing to top-most element of the
+ # vector occurs just "above" references to powers table,
+ # "above" modulo cache-line size, which effectively precludes
+ # possibility of memory disambiguation logic failure when
+ # accessing the table.
+ #
+ lea 64+8*4+8(%rsp,%r11,8),$tptr
+
+ mov %rdx,$bi
+ mulx 0*8($aptr),$mi,%rax # a[0]*b[0]
+ mulx 1*8($aptr),%r11,%r12 # a[1]*b[0]
+ add %rax,%r11
+ mulx 2*8($aptr),%rax,%r13 # ...
+ adc %rax,%r12
+ adc \$0,%r13
+ mulx 3*8($aptr),%rax,%r14
+
+ mov $mi,%r15
+ imulq 32+8(%rsp),$mi # "t[0]"*n0
+ xor $zero,$zero # cf=0, of=0
+ mov $mi,%rdx
+
+ por %xmm2,%xmm1
+ pand %xmm7,%xmm0
+ por %xmm3,%xmm1
+ mov $bptr,8+8(%rsp) # off-load &b[i]
+ por %xmm1,%xmm0
+
+ .byte 0x48,0x8d,0xb6,0x20,0x00,0x00,0x00 # lea 4*8($aptr),$aptr
+ adcx %rax,%r13
+ adcx $zero,%r14 # cf=0
+
+ mulx 0*16($nptr),%rax,%r10
+ adcx %rax,%r15 # discarded
+ adox %r11,%r10
+ mulx 1*16($nptr),%rax,%r11
+ adcx %rax,%r10
+ adox %r12,%r11
+ mulx 2*16($nptr),%rax,%r12
+ mov 24+8(%rsp),$bptr # counter value
+ .byte 0x66
+ mov %r10,-8*4($tptr)
+ adcx %rax,%r11
+ adox %r13,%r12
+ mulx 3*16($nptr),%rax,%r15
+ .byte 0x67,0x67
+ mov $bi,%rdx
+ mov %r11,-8*3($tptr)
+ adcx %rax,%r12
+ adox $zero,%r15 # of=0
+ .byte 0x48,0x8d,0x89,0x40,0x00,0x00,0x00 # lea 4*16($nptr),$nptr
+ mov %r12,-8*2($tptr)
+ #jmp .Lmulx4x_1st
+
+.align 32
+.Lmulx4x_1st:
+ adcx $zero,%r15 # cf=0, modulo-scheduled
+ mulx 0*8($aptr),%r10,%rax # a[4]*b[0]
+ adcx %r14,%r10
+ mulx 1*8($aptr),%r11,%r14 # a[5]*b[0]
+ adcx %rax,%r11
+ mulx 2*8($aptr),%r12,%rax # ...
+ adcx %r14,%r12
+ mulx 3*8($aptr),%r13,%r14
+ .byte 0x67,0x67
+ mov $mi,%rdx
+ adcx %rax,%r13
+ adcx $zero,%r14 # cf=0
+ lea 4*8($aptr),$aptr
+ lea 4*8($tptr),$tptr
+
+ adox %r15,%r10
+ mulx 0*16($nptr),%rax,%r15
+ adcx %rax,%r10
+ adox %r15,%r11
+ mulx 1*16($nptr),%rax,%r15
+ adcx %rax,%r11
+ adox %r15,%r12
+ mulx 2*16($nptr),%rax,%r15
+ mov %r10,-5*8($tptr)
+ adcx %rax,%r12
+ mov %r11,-4*8($tptr)
+ adox %r15,%r13
+ mulx 3*16($nptr),%rax,%r15
+ mov $bi,%rdx
+ mov %r12,-3*8($tptr)
+ adcx %rax,%r13
+ adox $zero,%r15
+ lea 4*16($nptr),$nptr
+ mov %r13,-2*8($tptr)
+
+ dec $bptr # of=0, pass cf
+ jnz .Lmulx4x_1st
+
+ mov 8(%rsp),$num # load -num
+ movq %xmm0,%rdx # bp[1]
+ adc $zero,%r15 # modulo-scheduled
+ lea ($aptr,$num),$aptr # rewind $aptr
+ add %r15,%r14
+ mov 8+8(%rsp),$bptr # re-load &b[i]
+ adc $zero,$zero # top-most carry
+ mov %r14,-1*8($tptr)
+ jmp .Lmulx4x_outer
+
+.align 32
+.Lmulx4x_outer:
+ mov $zero,($tptr) # save top-most carry
+ lea 4*8($tptr,$num),$tptr # rewind $tptr
+ mulx 0*8($aptr),$mi,%r11 # a[0]*b[i]
+ xor $zero,$zero # cf=0, of=0
+ mov %rdx,$bi
+ mulx 1*8($aptr),%r14,%r12 # a[1]*b[i]
+ adox -4*8($tptr),$mi # +t[0]
+ adcx %r14,%r11
+ mulx 2*8($aptr),%r15,%r13 # ...
+ adox -3*8($tptr),%r11
+ adcx %r15,%r12
+ mulx 3*8($aptr),%rdx,%r14
+ adox -2*8($tptr),%r12
+ adcx %rdx,%r13
+ lea ($nptr,$num,2),$nptr # rewind $nptr
+ lea 4*8($aptr),$aptr
+ adox -1*8($tptr),%r13
+ adcx $zero,%r14
+ adox $zero,%r14
+
+ .byte 0x67
+ mov $mi,%r15
+ imulq 32+8(%rsp),$mi # "t[0]"*n0
+
+ movq `0*$STRIDE/4-96`($bptr),%xmm0
+ .byte 0x67,0x67
+ mov $mi,%rdx
+ movq `1*$STRIDE/4-96`($bptr),%xmm1
+ .byte 0x67
+ pand %xmm4,%xmm0
+ movq `2*$STRIDE/4-96`($bptr),%xmm2
+ .byte 0x67
+ pand %xmm5,%xmm1
+ movq `3*$STRIDE/4-96`($bptr),%xmm3
+ add \$$STRIDE,$bptr # next &b[i]
+ .byte 0x67
+ pand %xmm6,%xmm2
+ por %xmm1,%xmm0
+ pand %xmm7,%xmm3
+ xor $zero,$zero # cf=0, of=0
+ mov $bptr,8+8(%rsp) # off-load &b[i]
+
+ mulx 0*16($nptr),%rax,%r10
+ adcx %rax,%r15 # discarded
+ adox %r11,%r10
+ mulx 1*16($nptr),%rax,%r11
+ adcx %rax,%r10
+ adox %r12,%r11
+ mulx 2*16($nptr),%rax,%r12
+ adcx %rax,%r11
+ adox %r13,%r12
+ mulx 3*16($nptr),%rax,%r15
+ mov $bi,%rdx
+ por %xmm2,%xmm0
+ mov 24+8(%rsp),$bptr # counter value
+ mov %r10,-8*4($tptr)
+ por %xmm3,%xmm0
+ adcx %rax,%r12
+ mov %r11,-8*3($tptr)
+ adox $zero,%r15 # of=0
+ mov %r12,-8*2($tptr)
+ lea 4*16($nptr),$nptr
+ jmp .Lmulx4x_inner
+
+.align 32
+.Lmulx4x_inner:
+ mulx 0*8($aptr),%r10,%rax # a[4]*b[i]
+ adcx $zero,%r15 # cf=0, modulo-scheduled
+ adox %r14,%r10
+ mulx 1*8($aptr),%r11,%r14 # a[5]*b[i]
+ adcx 0*8($tptr),%r10
+ adox %rax,%r11
+ mulx 2*8($aptr),%r12,%rax # ...
+ adcx 1*8($tptr),%r11
+ adox %r14,%r12
+ mulx 3*8($aptr),%r13,%r14
+ mov $mi,%rdx
+ adcx 2*8($tptr),%r12
+ adox %rax,%r13
+ adcx 3*8($tptr),%r13
+ adox $zero,%r14 # of=0
+ lea 4*8($aptr),$aptr
+ lea 4*8($tptr),$tptr
+ adcx $zero,%r14 # cf=0
+
+ adox %r15,%r10
+ mulx 0*16($nptr),%rax,%r15
+ adcx %rax,%r10
+ adox %r15,%r11
+ mulx 1*16($nptr),%rax,%r15
+ adcx %rax,%r11
+ adox %r15,%r12
+ mulx 2*16($nptr),%rax,%r15
+ mov %r10,-5*8($tptr)
+ adcx %rax,%r12
+ adox %r15,%r13
+ mov %r11,-4*8($tptr)
+ mulx 3*16($nptr),%rax,%r15
+ mov $bi,%rdx
+ lea 4*16($nptr),$nptr
+ mov %r12,-3*8($tptr)
+ adcx %rax,%r13
+ adox $zero,%r15
+ mov %r13,-2*8($tptr)
+
+ dec $bptr # of=0, pass cf
+ jnz .Lmulx4x_inner
+
+ mov 0+8(%rsp),$num # load -num
+ movq %xmm0,%rdx # bp[i+1]
+ adc $zero,%r15 # modulo-scheduled
+ sub 0*8($tptr),$bptr # pull top-most carry to %cf
+ mov 8+8(%rsp),$bptr # re-load &b[i]
+ mov 16+8(%rsp),%r10
+ adc %r15,%r14
+ lea ($aptr,$num),$aptr # rewind $aptr
+ adc $zero,$zero # top-most carry
+ mov %r14,-1*8($tptr)
+
+ cmp %r10,$bptr
+ jb .Lmulx4x_outer
+
+ mov -16($nptr),%r10
+ xor %r15,%r15
+ sub %r14,%r10 # compare top-most words
+ adc %r15,%r15
+ or %r15,$zero
+ xor \$1,$zero
+ lea ($tptr,$num),%rdi # rewind $tptr
+ lea ($nptr,$num,2),$nptr # rewind $nptr
+ .byte 0x67,0x67
+ sar \$3+2,$num # cf=0
+ lea ($nptr,$zero,8),%rbp
+ mov 56+8(%rsp),%rdx # restore rp
+ mov $num,%rcx
+ jmp .Lsqrx4x_sub # common post-condition
+.size mulx4x_internal,.-mulx4x_internal
+___
+}{
+######################################################################
+# void bn_power5(
+my $rptr="%rdi"; # BN_ULONG *rptr,
+my $aptr="%rsi"; # const BN_ULONG *aptr,
+my $bptr="%rdx"; # const void *table,
+my $nptr="%rcx"; # const BN_ULONG *nptr,
+my $n0 ="%r8"; # const BN_ULONG *n0);
+my $num ="%r9"; # int num, has to be divisible by 8
+ # int pwr);
+
+my ($i,$j,$tptr)=("%rbp","%rcx",$rptr);
+my @A0=("%r10","%r11");
+my @A1=("%r12","%r13");
+my ($a0,$a1,$ai)=("%r14","%r15","%rbx");
+
+$code.=<<___;
+.type bn_powerx5,\@function,6
+.align 32
+bn_powerx5:
+.Lpowerx5_enter:
+ .byte 0x67
+ mov %rsp,%rax
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+___
+$code.=<<___ if ($win64);
+ lea -0x28(%rsp),%rsp
+ movaps %xmm6,(%rsp)
+ movaps %xmm7,0x10(%rsp)
+___
+$code.=<<___;
+ .byte 0x67
+ mov ${num}d,%r10d
+ shl \$3,${num}d # convert $num to bytes
+ shl \$3+2,%r10d # 4*$num
+ neg $num
+ mov ($n0),$n0 # *n0
+
+ ##############################################################
+ # ensure that stack frame doesn't alias with $aptr+4*$num
+ # modulo 4096, which covers ret[num], am[num] and n[2*num]
+ # (see bn_exp.c). this is done to allow memory disambiguation
+ # logic do its magic.
+ #
+ lea -64(%rsp,$num,2),%r11
+ sub $aptr,%r11
+ and \$4095,%r11
+ cmp %r11,%r10
+ jb .Lpwrx_sp_alt
+ sub %r11,%rsp # align with $aptr
+ lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num)
+ jmp .Lpwrx_sp_done
+
+.align 32
+.Lpwrx_sp_alt:
+ lea 4096-64(,$num,2),%r10 # 4096-frame-2*$num
+ lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num)
+ sub %r10,%r11
+ mov \$0,%r10
+ cmovc %r10,%r11
+ sub %r11,%rsp
+.Lpwrx_sp_done:
+ and \$-64,%rsp
+ mov $num,%r10
+ neg $num
+
+ ##############################################################
+ # Stack layout
+ #
+ # +0 saved $num, used in reduction section
+ # +8 &t[2*$num], used in reduction section
+ # +16 intermediate carry bit
+ # +24 top-most carry bit, used in reduction section
+ # +32 saved *n0
+ # +40 saved %rsp
+ # +48 t[2*$num]
+ #
+ pxor %xmm0,%xmm0
+ movq $rptr,%xmm1 # save $rptr
+ movq $nptr,%xmm2 # save $nptr
+ movq %r10, %xmm3 # -$num
+ movq $bptr,%xmm4
+ mov $n0, 32(%rsp)
+ mov %rax, 40(%rsp) # save original %rsp
+.Lpowerx5_body:
+
+ call __bn_sqrx8x_internal
+ call __bn_sqrx8x_internal
+ call __bn_sqrx8x_internal
+ call __bn_sqrx8x_internal
+ call __bn_sqrx8x_internal
+
+ mov %r10,$num # -num
+ mov $aptr,$rptr
+ movq %xmm2,$nptr
+ movq %xmm4,$bptr
+ mov 40(%rsp),%rax
+
+ call mulx4x_internal
+
+ mov 40(%rsp),%rsi # restore %rsp
+ mov \$1,%rax
+___
+$code.=<<___ if ($win64);
+ movaps -88(%rsi),%xmm6
+ movaps -72(%rsi),%xmm7
+___
+$code.=<<___;
+ mov -48(%rsi),%r15
+ mov -40(%rsi),%r14
+ mov -32(%rsi),%r13
+ mov -24(%rsi),%r12
+ mov -16(%rsi),%rbp
+ mov -8(%rsi),%rbx
+ lea (%rsi),%rsp
+.Lpowerx5_epilogue:
+ ret
+.size bn_powerx5,.-bn_powerx5
+
+.globl bn_sqrx8x_internal
+.hidden bn_sqrx8x_internal
+.type bn_sqrx8x_internal,\@abi-omnipotent
+.align 32
+bn_sqrx8x_internal:
+__bn_sqrx8x_internal:
+ ##################################################################
+ # Squaring part:
+ #
+ # a) multiply-n-add everything but a[i]*a[i];
+ # b) shift result of a) by 1 to the left and accumulate
+ # a[i]*a[i] products;
+ #
+ ##################################################################
+ # a[7]a[7]a[6]a[6]a[5]a[5]a[4]a[4]a[3]a[3]a[2]a[2]a[1]a[1]a[0]a[0]
+ # a[1]a[0]
+ # a[2]a[0]
+ # a[3]a[0]
+ # a[2]a[1]
+ # a[3]a[1]
+ # a[3]a[2]
+ #
+ # a[4]a[0]
+ # a[5]a[0]
+ # a[6]a[0]
+ # a[7]a[0]
+ # a[4]a[1]
+ # a[5]a[1]
+ # a[6]a[1]
+ # a[7]a[1]
+ # a[4]a[2]
+ # a[5]a[2]
+ # a[6]a[2]
+ # a[7]a[2]
+ # a[4]a[3]
+ # a[5]a[3]
+ # a[6]a[3]
+ # a[7]a[3]
+ #
+ # a[5]a[4]
+ # a[6]a[4]
+ # a[7]a[4]
+ # a[6]a[5]
+ # a[7]a[5]
+ # a[7]a[6]
+ # a[7]a[7]a[6]a[6]a[5]a[5]a[4]a[4]a[3]a[3]a[2]a[2]a[1]a[1]a[0]a[0]
+___
+{
+my ($zero,$carry)=("%rbp","%rcx");
+my $aaptr=$zero;
+$code.=<<___;
+ lea 48+8(%rsp),$tptr
+ lea ($aptr,$num),$aaptr
+ mov $num,0+8(%rsp) # save $num
+ mov $aaptr,8+8(%rsp) # save end of $aptr
+ jmp .Lsqr8x_zero_start
+
+.align 32
+.byte 0x66,0x66,0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00
+.Lsqrx8x_zero:
+ .byte 0x3e
+ movdqa %xmm0,0*8($tptr)
+ movdqa %xmm0,2*8($tptr)
+ movdqa %xmm0,4*8($tptr)
+ movdqa %xmm0,6*8($tptr)
+.Lsqr8x_zero_start: # aligned at 32
+ movdqa %xmm0,8*8($tptr)
+ movdqa %xmm0,10*8($tptr)
+ movdqa %xmm0,12*8($tptr)
+ movdqa %xmm0,14*8($tptr)
+ lea 16*8($tptr),$tptr
+ sub \$64,$num
+ jnz .Lsqrx8x_zero
+
+ mov 0*8($aptr),%rdx # a[0], modulo-scheduled
+ #xor %r9,%r9 # t[1], ex-$num, zero already
+ xor %r10,%r10
+ xor %r11,%r11
+ xor %r12,%r12
+ xor %r13,%r13
+ xor %r14,%r14
+ xor %r15,%r15
+ lea 48+8(%rsp),$tptr
+ xor $zero,$zero # cf=0, cf=0
+ jmp .Lsqrx8x_outer_loop
+
+.align 32
+.Lsqrx8x_outer_loop:
+ mulx 1*8($aptr),%r8,%rax # a[1]*a[0]
+ adcx %r9,%r8 # a[1]*a[0]+=t[1]
+ adox %rax,%r10
+ mulx 2*8($aptr),%r9,%rax # a[2]*a[0]
+ adcx %r10,%r9
+ adox %rax,%r11
+ .byte 0xc4,0xe2,0xab,0xf6,0x86,0x18,0x00,0x00,0x00 # mulx 3*8($aptr),%r10,%rax # ...
+ adcx %r11,%r10
+ adox %rax,%r12
+ .byte 0xc4,0xe2,0xa3,0xf6,0x86,0x20,0x00,0x00,0x00 # mulx 4*8($aptr),%r11,%rax
+ adcx %r12,%r11
+ adox %rax,%r13
+ mulx 5*8($aptr),%r12,%rax
+ adcx %r13,%r12
+ adox %rax,%r14
+ mulx 6*8($aptr),%r13,%rax
+ adcx %r14,%r13
+ adox %r15,%rax
+ mulx 7*8($aptr),%r14,%r15
+ mov 1*8($aptr),%rdx # a[1]
+ adcx %rax,%r14
+ adox $zero,%r15
+ adc 8*8($tptr),%r15
+ mov %r8,1*8($tptr) # t[1]
+ mov %r9,2*8($tptr) # t[2]
+ sbb $carry,$carry # mov %cf,$carry
+ xor $zero,$zero # cf=0, of=0
+
+
+ mulx 2*8($aptr),%r8,%rbx # a[2]*a[1]
+ mulx 3*8($aptr),%r9,%rax # a[3]*a[1]
+ adcx %r10,%r8
+ adox %rbx,%r9
+ mulx 4*8($aptr),%r10,%rbx # ...
+ adcx %r11,%r9
+ adox %rax,%r10
+ .byte 0xc4,0xe2,0xa3,0xf6,0x86,0x28,0x00,0x00,0x00 # mulx 5*8($aptr),%r11,%rax
+ adcx %r12,%r10
+ adox %rbx,%r11
+ .byte 0xc4,0xe2,0x9b,0xf6,0x9e,0x30,0x00,0x00,0x00 # mulx 6*8($aptr),%r12,%rbx
+ adcx %r13,%r11
+ adox %r14,%r12
+ .byte 0xc4,0x62,0x93,0xf6,0xb6,0x38,0x00,0x00,0x00 # mulx 7*8($aptr),%r13,%r14
+ mov 2*8($aptr),%rdx # a[2]
+ adcx %rax,%r12
+ adox %rbx,%r13
+ adcx %r15,%r13
+ adox $zero,%r14 # of=0
+ adcx $zero,%r14 # cf=0
+
+ mov %r8,3*8($tptr) # t[3]
+ mov %r9,4*8($tptr) # t[4]
+
+ mulx 3*8($aptr),%r8,%rbx # a[3]*a[2]
+ mulx 4*8($aptr),%r9,%rax # a[4]*a[2]
+ adcx %r10,%r8
+ adox %rbx,%r9
+ mulx 5*8($aptr),%r10,%rbx # ...
+ adcx %r11,%r9
+ adox %rax,%r10
+ .byte 0xc4,0xe2,0xa3,0xf6,0x86,0x30,0x00,0x00,0x00 # mulx 6*8($aptr),%r11,%rax
+ adcx %r12,%r10
+ adox %r13,%r11
+ .byte 0xc4,0x62,0x9b,0xf6,0xae,0x38,0x00,0x00,0x00 # mulx 7*8($aptr),%r12,%r13
+ .byte 0x3e
+ mov 3*8($aptr),%rdx # a[3]
+ adcx %rbx,%r11
+ adox %rax,%r12
+ adcx %r14,%r12
+ mov %r8,5*8($tptr) # t[5]
+ mov %r9,6*8($tptr) # t[6]
+ mulx 4*8($aptr),%r8,%rax # a[4]*a[3]
+ adox $zero,%r13 # of=0
+ adcx $zero,%r13 # cf=0
+
+ mulx 5*8($aptr),%r9,%rbx # a[5]*a[3]
+ adcx %r10,%r8
+ adox %rax,%r9
+ mulx 6*8($aptr),%r10,%rax # ...
+ adcx %r11,%r9
+ adox %r12,%r10
+ mulx 7*8($aptr),%r11,%r12
+ mov 4*8($aptr),%rdx # a[4]
+ mov 5*8($aptr),%r14 # a[5]
+ adcx %rbx,%r10
+ adox %rax,%r11
+ mov 6*8($aptr),%r15 # a[6]
+ adcx %r13,%r11
+ adox $zero,%r12 # of=0
+ adcx $zero,%r12 # cf=0
+
+ mov %r8,7*8($tptr) # t[7]
+ mov %r9,8*8($tptr) # t[8]
+
+ mulx %r14,%r9,%rax # a[5]*a[4]
+ mov 7*8($aptr),%r8 # a[7]
+ adcx %r10,%r9
+ mulx %r15,%r10,%rbx # a[6]*a[4]
+ adox %rax,%r10
+ adcx %r11,%r10
+ mulx %r8,%r11,%rax # a[7]*a[4]
+ mov %r14,%rdx # a[5]
+ adox %rbx,%r11
+ adcx %r12,%r11
+ #adox $zero,%rax # of=0
+ adcx $zero,%rax # cf=0
+
+ mulx %r15,%r14,%rbx # a[6]*a[5]
+ mulx %r8,%r12,%r13 # a[7]*a[5]
+ mov %r15,%rdx # a[6]
+ lea 8*8($aptr),$aptr
+ adcx %r14,%r11
+ adox %rbx,%r12
+ adcx %rax,%r12
+ adox $zero,%r13
+
+ .byte 0x67,0x67
+ mulx %r8,%r8,%r14 # a[7]*a[6]
+ adcx %r8,%r13
+ adcx $zero,%r14
+
+ cmp 8+8(%rsp),$aptr
+ je .Lsqrx8x_outer_break
+
+ neg $carry # mov $carry,%cf
+ mov \$-8,%rcx
+ mov $zero,%r15
+ mov 8*8($tptr),%r8
+ adcx 9*8($tptr),%r9 # +=t[9]
+ adcx 10*8($tptr),%r10 # ...
+ adcx 11*8($tptr),%r11
+ adc 12*8($tptr),%r12
+ adc 13*8($tptr),%r13
+ adc 14*8($tptr),%r14
+ adc 15*8($tptr),%r15
+ lea ($aptr),$aaptr
+ lea 2*64($tptr),$tptr
+ sbb %rax,%rax # mov %cf,$carry
+
+ mov -64($aptr),%rdx # a[0]
+ mov %rax,16+8(%rsp) # offload $carry
+ mov $tptr,24+8(%rsp)
+
+ #lea 8*8($tptr),$tptr # see 2*8*8($tptr) above
+ xor %eax,%eax # cf=0, of=0
+ jmp .Lsqrx8x_loop
+
+.align 32
+.Lsqrx8x_loop:
+ mov %r8,%rbx
+ mulx 0*8($aaptr),%rax,%r8 # a[8]*a[i]
+ adcx %rax,%rbx # +=t[8]
+ adox %r9,%r8
+
+ mulx 1*8($aaptr),%rax,%r9 # ...
+ adcx %rax,%r8
+ adox %r10,%r9
+
+ mulx 2*8($aaptr),%rax,%r10
+ adcx %rax,%r9
+ adox %r11,%r10
+
+ mulx 3*8($aaptr),%rax,%r11
+ adcx %rax,%r10
+ adox %r12,%r11
+
+ .byte 0xc4,0x62,0xfb,0xf6,0xa5,0x20,0x00,0x00,0x00 # mulx 4*8($aaptr),%rax,%r12
+ adcx %rax,%r11
+ adox %r13,%r12
+
+ mulx 5*8($aaptr),%rax,%r13
+ adcx %rax,%r12
+ adox %r14,%r13
+
+ mulx 6*8($aaptr),%rax,%r14
+ mov %rbx,($tptr,%rcx,8) # store t[8+i]
+ mov \$0,%ebx
+ adcx %rax,%r13
+ adox %r15,%r14
+
+ .byte 0xc4,0x62,0xfb,0xf6,0xbd,0x38,0x00,0x00,0x00 # mulx 7*8($aaptr),%rax,%r15
+ mov 8($aptr,%rcx,8),%rdx # a[i]
+ adcx %rax,%r14
+ adox %rbx,%r15 # %rbx is 0, of=0
+ adcx %rbx,%r15 # cf=0
+
+ .byte 0x67
+ inc %rcx # of=0
+ jnz .Lsqrx8x_loop
+
+ lea 8*8($aaptr),$aaptr
+ mov \$-8,%rcx
+ cmp 8+8(%rsp),$aaptr # done?
+ je .Lsqrx8x_break
+
+ sub 16+8(%rsp),%rbx # mov 16(%rsp),%cf
+ .byte 0x66
+ mov -64($aptr),%rdx
+ adcx 0*8($tptr),%r8
+ adcx 1*8($tptr),%r9
+ adc 2*8($tptr),%r10
+ adc 3*8($tptr),%r11
+ adc 4*8($tptr),%r12
+ adc 5*8($tptr),%r13
+ adc 6*8($tptr),%r14
+ adc 7*8($tptr),%r15
+ lea 8*8($tptr),$tptr
+ .byte 0x67
+ sbb %rax,%rax # mov %cf,%rax
+ xor %ebx,%ebx # cf=0, of=0
+ mov %rax,16+8(%rsp) # offload carry
+ jmp .Lsqrx8x_loop
+
+.align 32
+.Lsqrx8x_break:
+ sub 16+8(%rsp),%r8 # consume last carry
+ mov 24+8(%rsp),$carry # initial $tptr, borrow $carry
+ mov 0*8($aptr),%rdx # a[8], modulo-scheduled
+ xor %ebp,%ebp # xor $zero,$zero
+ mov %r8,0*8($tptr)
+ cmp $carry,$tptr # cf=0, of=0
+ je .Lsqrx8x_outer_loop
+
+ mov %r9,1*8($tptr)
+ mov 1*8($carry),%r9
+ mov %r10,2*8($tptr)
+ mov 2*8($carry),%r10
+ mov %r11,3*8($tptr)
+ mov 3*8($carry),%r11
+ mov %r12,4*8($tptr)
+ mov 4*8($carry),%r12
+ mov %r13,5*8($tptr)
+ mov 5*8($carry),%r13
+ mov %r14,6*8($tptr)
+ mov 6*8($carry),%r14
+ mov %r15,7*8($tptr)
+ mov 7*8($carry),%r15
+ mov $carry,$tptr
+ jmp .Lsqrx8x_outer_loop
+
+.align 32
+.Lsqrx8x_outer_break:
+ mov %r9,9*8($tptr) # t[9]
+ movq %xmm3,%rcx # -$num
+ mov %r10,10*8($tptr) # ...
+ mov %r11,11*8($tptr)
+ mov %r12,12*8($tptr)
+ mov %r13,13*8($tptr)
+ mov %r14,14*8($tptr)
+___
+}{
+my $i="%rcx";
+$code.=<<___;
+ lea 48+8(%rsp),$tptr
+ mov ($aptr,$i),%rdx # a[0]
+
+ mov 8($tptr),$A0[1] # t[1]
+ xor $A0[0],$A0[0] # t[0], of=0, cf=0
+ mov 0+8(%rsp),$num # restore $num
+ adox $A0[1],$A0[1]
+ mov 16($tptr),$A1[0] # t[2] # prefetch
+ mov 24($tptr),$A1[1] # t[3] # prefetch
+ #jmp .Lsqrx4x_shift_n_add # happens to be aligned
+
+.align 32
+.Lsqrx4x_shift_n_add:
+ mulx %rdx,%rax,%rbx
+ adox $A1[0],$A1[0]
+ adcx $A0[0],%rax
+ .byte 0x48,0x8b,0x94,0x0e,0x08,0x00,0x00,0x00 # mov 8($aptr,$i),%rdx # a[i+1] # prefetch
+ .byte 0x4c,0x8b,0x97,0x20,0x00,0x00,0x00 # mov 32($tptr),$A0[0] # t[2*i+4] # prefetch
+ adox $A1[1],$A1[1]
+ adcx $A0[1],%rbx
+ mov 40($tptr),$A0[1] # t[2*i+4+1] # prefetch
+ mov %rax,0($tptr)
+ mov %rbx,8($tptr)
+
+ mulx %rdx,%rax,%rbx
+ adox $A0[0],$A0[0]
+ adcx $A1[0],%rax
+ mov 16($aptr,$i),%rdx # a[i+2] # prefetch
+ mov 48($tptr),$A1[0] # t[2*i+6] # prefetch
+ adox $A0[1],$A0[1]
+ adcx $A1[1],%rbx
+ mov 56($tptr),$A1[1] # t[2*i+6+1] # prefetch
+ mov %rax,16($tptr)
+ mov %rbx,24($tptr)
+
+ mulx %rdx,%rax,%rbx
+ adox $A1[0],$A1[0]
+ adcx $A0[0],%rax
+ mov 24($aptr,$i),%rdx # a[i+3] # prefetch
+ lea 32($i),$i
+ mov 64($tptr),$A0[0] # t[2*i+8] # prefetch
+ adox $A1[1],$A1[1]
+ adcx $A0[1],%rbx
+ mov 72($tptr),$A0[1] # t[2*i+8+1] # prefetch
+ mov %rax,32($tptr)
+ mov %rbx,40($tptr)
+
+ mulx %rdx,%rax,%rbx
+ adox $A0[0],$A0[0]
+ adcx $A1[0],%rax
+ jrcxz .Lsqrx4x_shift_n_add_break
+ .byte 0x48,0x8b,0x94,0x0e,0x00,0x00,0x00,0x00 # mov 0($aptr,$i),%rdx # a[i+4] # prefetch
+ adox $A0[1],$A0[1]
+ adcx $A1[1],%rbx
+ mov 80($tptr),$A1[0] # t[2*i+10] # prefetch
+ mov 88($tptr),$A1[1] # t[2*i+10+1] # prefetch
+ mov %rax,48($tptr)
+ mov %rbx,56($tptr)
+ lea 64($tptr),$tptr
+ nop
+ jmp .Lsqrx4x_shift_n_add
+
+.align 32
+.Lsqrx4x_shift_n_add_break:
+ adcx $A1[1],%rbx
+ mov %rax,48($tptr)
+ mov %rbx,56($tptr)
+ lea 64($tptr),$tptr # end of t[] buffer
+___
+}
+######################################################################
+# Montgomery reduction part, "word-by-word" algorithm.
+#
+# This new path is inspired by multiple submissions from Intel, by
+# Shay Gueron, Vlad Krasnov, Erdinc Ozturk, James Guilford,
+# Vinodh Gopal...
+{
+my ($nptr,$carry,$m0)=("%rbp","%rsi","%rdx");
+
+$code.=<<___;
+ movq %xmm2,$nptr
+sqrx8x_reduction:
+ xor %eax,%eax # initial top-most carry bit
+ mov 32+8(%rsp),%rbx # n0
+ mov 48+8(%rsp),%rdx # "%r8", 8*0($tptr)
+ lea -128($nptr,$num,2),%rcx # end of n[]
+ #lea 48+8(%rsp,$num,2),$tptr # end of t[] buffer
+ mov %rcx, 0+8(%rsp) # save end of n[]
+ mov $tptr,8+8(%rsp) # save end of t[]
+
+ lea 48+8(%rsp),$tptr # initial t[] window
+ jmp .Lsqrx8x_reduction_loop
+
+.align 32
+.Lsqrx8x_reduction_loop:
+ mov 8*1($tptr),%r9
+ mov 8*2($tptr),%r10
+ mov 8*3($tptr),%r11
+ mov 8*4($tptr),%r12
+ mov %rdx,%r8
+ imulq %rbx,%rdx # n0*a[i]
+ mov 8*5($tptr),%r13
+ mov 8*6($tptr),%r14
+ mov 8*7($tptr),%r15
+ mov %rax,24+8(%rsp) # store top-most carry bit
+
+ lea 8*8($tptr),$tptr
+ xor $carry,$carry # cf=0,of=0
+ mov \$-8,%rcx
+ jmp .Lsqrx8x_reduce
+
+.align 32
+.Lsqrx8x_reduce:
+ mov %r8, %rbx
+ mulx 16*0($nptr),%rax,%r8 # n[0]
+ adcx %rbx,%rax # discarded
+ adox %r9,%r8
+
+ mulx 16*1($nptr),%rbx,%r9 # n[1]
+ adcx %rbx,%r8
+ adox %r10,%r9
+
+ mulx 16*2($nptr),%rbx,%r10
+ adcx %rbx,%r9
+ adox %r11,%r10
+
+ mulx 16*3($nptr),%rbx,%r11
+ adcx %rbx,%r10
+ adox %r12,%r11
+
+ .byte 0xc4,0x62,0xe3,0xf6,0xa5,0x40,0x00,0x00,0x00 # mulx 16*4($nptr),%rbx,%r12
+ mov %rdx,%rax
+ mov %r8,%rdx
+ adcx %rbx,%r11
+ adox %r13,%r12
+
+ mulx 32+8(%rsp),%rbx,%rdx # %rdx discarded
+ mov %rax,%rdx
+ mov %rax,64+48+8(%rsp,%rcx,8) # put aside n0*a[i]
+
+ mulx 16*5($nptr),%rax,%r13
+ adcx %rax,%r12
+ adox %r14,%r13
+
+ mulx 16*6($nptr),%rax,%r14
+ adcx %rax,%r13
+ adox %r15,%r14
+
+ mulx 16*7($nptr),%rax,%r15
+ mov %rbx,%rdx
+ adcx %rax,%r14
+ adox $carry,%r15 # $carry is 0
+ adcx $carry,%r15 # cf=0
+
+ .byte 0x67,0x67,0x67
+ inc %rcx # of=0
+ jnz .Lsqrx8x_reduce
+
+ mov $carry,%rax # xor %rax,%rax
+ cmp 0+8(%rsp),$nptr # end of n[]?
+ jae .Lsqrx8x_no_tail
+
+ mov 48+8(%rsp),%rdx # pull n0*a[0]
+ add 8*0($tptr),%r8
+ lea 16*8($nptr),$nptr
+ mov \$-8,%rcx
+ adcx 8*1($tptr),%r9
+ adcx 8*2($tptr),%r10
+ adc 8*3($tptr),%r11
+ adc 8*4($tptr),%r12
+ adc 8*5($tptr),%r13
+ adc 8*6($tptr),%r14
+ adc 8*7($tptr),%r15
+ lea 8*8($tptr),$tptr
+ sbb %rax,%rax # top carry
+
+ xor $carry,$carry # of=0, cf=0
+ mov %rax,16+8(%rsp)
+ jmp .Lsqrx8x_tail
+
+.align 32
+.Lsqrx8x_tail:
+ mov %r8,%rbx
+ mulx 16*0($nptr),%rax,%r8
+ adcx %rax,%rbx
+ adox %r9,%r8
+
+ mulx 16*1($nptr),%rax,%r9
+ adcx %rax,%r8
+ adox %r10,%r9
+
+ mulx 16*2($nptr),%rax,%r10
+ adcx %rax,%r9
+ adox %r11,%r10
+
+ mulx 16*3($nptr),%rax,%r11
+ adcx %rax,%r10
+ adox %r12,%r11
+
+ .byte 0xc4,0x62,0xfb,0xf6,0xa5,0x40,0x00,0x00,0x00 # mulx 16*4($nptr),%rax,%r12
+ adcx %rax,%r11
+ adox %r13,%r12
+
+ mulx 16*5($nptr),%rax,%r13
+ adcx %rax,%r12
+ adox %r14,%r13
+
+ mulx 16*6($nptr),%rax,%r14
+ adcx %rax,%r13
+ adox %r15,%r14
+
+ mulx 16*7($nptr),%rax,%r15
+ mov 72+48+8(%rsp,%rcx,8),%rdx # pull n0*a[i]
+ adcx %rax,%r14
+ adox $carry,%r15
+ mov %rbx,($tptr,%rcx,8) # save result
+ mov %r8,%rbx
+ adcx $carry,%r15 # cf=0
+
+ inc %rcx # of=0
+ jnz .Lsqrx8x_tail
+
+ cmp 0+8(%rsp),$nptr # end of n[]?
+ jae .Lsqrx8x_tail_done # break out of loop
+
+ sub 16+8(%rsp),$carry # mov 16(%rsp),%cf
+ mov 48+8(%rsp),%rdx # pull n0*a[0]
+ lea 16*8($nptr),$nptr
+ adc 8*0($tptr),%r8
+ adc 8*1($tptr),%r9
+ adc 8*2($tptr),%r10
+ adc 8*3($tptr),%r11
+ adc 8*4($tptr),%r12
+ adc 8*5($tptr),%r13
+ adc 8*6($tptr),%r14
+ adc 8*7($tptr),%r15
+ lea 8*8($tptr),$tptr
+ sbb %rax,%rax
+ sub \$8,%rcx # mov \$-8,%rcx
+
+ xor $carry,$carry # of=0, cf=0
+ mov %rax,16+8(%rsp)
+ jmp .Lsqrx8x_tail
+
+.align 32
+.Lsqrx8x_tail_done:
+ add 24+8(%rsp),%r8 # can this overflow?
+ mov $carry,%rax # xor %rax,%rax
+
+ sub 16+8(%rsp),$carry # mov 16(%rsp),%cf
+.Lsqrx8x_no_tail: # %cf is 0 if jumped here
+ adc 8*0($tptr),%r8
+ movq %xmm3,%rcx
+ adc 8*1($tptr),%r9
+ mov 16*7($nptr),$carry
+ movq %xmm2,$nptr # restore $nptr
+ adc 8*2($tptr),%r10
+ adc 8*3($tptr),%r11
+ adc 8*4($tptr),%r12
+ adc 8*5($tptr),%r13
+ adc 8*6($tptr),%r14
+ adc 8*7($tptr),%r15
+ adc %rax,%rax # top-most carry
+
+ mov 32+8(%rsp),%rbx # n0
+ mov 8*8($tptr,%rcx),%rdx # modulo-scheduled "%r8"
+
+ mov %r8,8*0($tptr) # store top 512 bits
+ lea 8*8($tptr),%r8 # borrow %r8
+ mov %r9,8*1($tptr)
+ mov %r10,8*2($tptr)
+ mov %r11,8*3($tptr)
+ mov %r12,8*4($tptr)
+ mov %r13,8*5($tptr)
+ mov %r14,8*6($tptr)
+ mov %r15,8*7($tptr)
+
+ lea 8*8($tptr,%rcx),$tptr # start of current t[] window
+ cmp 8+8(%rsp),%r8 # end of t[]?
+ jb .Lsqrx8x_reduction_loop
+___
+}
+##############################################################
+# Post-condition, 4x unrolled
+#
+{
+my ($rptr,$nptr)=("%rdx","%rbp");
+my @ri=map("%r$_",(10..13));
+my @ni=map("%r$_",(14..15));
+$code.=<<___;
+ xor %rbx,%rbx
+ sub %r15,%rsi # compare top-most words
+ adc %rbx,%rbx
+ mov %rcx,%r10 # -$num
+ .byte 0x67
+ or %rbx,%rax
+ .byte 0x67
+ mov %rcx,%r9 # -$num
+ xor \$1,%rax
+ sar \$3+2,%rcx # cf=0
+ #lea 48+8(%rsp,%r9),$tptr
+ lea ($nptr,%rax,8),$nptr
+ movq %xmm1,$rptr # restore $rptr
+ movq %xmm1,$aptr # prepare for back-to-back call
+ jmp .Lsqrx4x_sub
+
+.align 32
+.Lsqrx4x_sub:
+ .byte 0x66
+ mov 8*0($tptr),%r12
+ mov 8*1($tptr),%r13
+ sbb 16*0($nptr),%r12
+ mov 8*2($tptr),%r14
+ sbb 16*1($nptr),%r13
+ mov 8*3($tptr),%r15
+ lea 8*4($tptr),$tptr
+ sbb 16*2($nptr),%r14
+ mov %r12,8*0($rptr)
+ sbb 16*3($nptr),%r15
+ lea 16*4($nptr),$nptr
+ mov %r13,8*1($rptr)
+ mov %r14,8*2($rptr)
+ mov %r15,8*3($rptr)
+ lea 8*4($rptr),$rptr
+
+ inc %rcx
+ jnz .Lsqrx4x_sub
+___
+}
+$code.=<<___;
+ neg %r9 # restore $num
+
+ ret
+.size bn_sqrx8x_internal,.-bn_sqrx8x_internal
+___
+}}}
+{
+my ($inp,$num,$tbl,$idx)=$win64?("%rcx","%edx","%r8", "%r9d") : # Win64 order
+ ("%rdi","%esi","%rdx","%ecx"); # Unix order
+my $out=$inp;
+my $STRIDE=2**5*8;
+my $N=$STRIDE/4;
+
+$code.=<<___;
+.globl bn_get_bits5
+.type bn_get_bits5,\@abi-omnipotent
+.align 16
+bn_get_bits5:
+ mov $inp,%r10
+ mov $num,%ecx
+ shr \$3,$num
+ movzw (%r10,$num),%eax
+ and \$7,%ecx
+ shrl %cl,%eax
+ and \$31,%eax
+ ret
+.size bn_get_bits5,.-bn_get_bits5
+
+.globl bn_scatter5
+.type bn_scatter5,\@abi-omnipotent
+.align 16
+bn_scatter5:
+ cmp \$0, $num
+ jz .Lscatter_epilogue
+ lea ($tbl,$idx,8),$tbl
+.Lscatter:
+ mov ($inp),%rax
+ lea 8($inp),$inp
+ mov %rax,($tbl)
+ lea 32*8($tbl),$tbl
+ sub \$1,$num
+ jnz .Lscatter
+.Lscatter_epilogue:
+ ret
+.size bn_scatter5,.-bn_scatter5
+
+.globl bn_gather5
+.type bn_gather5,\@abi-omnipotent
+.align 16
+bn_gather5:
+___
+$code.=<<___ if ($win64);
+.LSEH_begin_bn_gather5:
+ # I can't trust assembler to use specific encoding:-(
+ .byte 0x48,0x83,0xec,0x28 #sub \$0x28,%rsp
+ .byte 0x0f,0x29,0x34,0x24 #movaps %xmm6,(%rsp)
+ .byte 0x0f,0x29,0x7c,0x24,0x10 #movdqa %xmm7,0x10(%rsp)
+___
+$code.=<<___;
+ mov $idx,%r11d
+ shr \$`log($N/8)/log(2)`,$idx
+ and \$`$N/8-1`,%r11
+ not $idx
+ lea .Lmagic_masks(%rip),%rax
+ and \$`2**5/($N/8)-1`,$idx # 5 is "window size"
+ lea 128($tbl,%r11,8),$tbl # pointer within 1st cache line
+ movq 0(%rax,$idx,8),%xmm4 # set of masks denoting which
+ movq 8(%rax,$idx,8),%xmm5 # cache line contains element
+ movq 16(%rax,$idx,8),%xmm6 # denoted by 7th argument
+ movq 24(%rax,$idx,8),%xmm7
+ jmp .Lgather
+.align 16
+.Lgather:
+ movq `0*$STRIDE/4-128`($tbl),%xmm0
+ movq `1*$STRIDE/4-128`($tbl),%xmm1
+ pand %xmm4,%xmm0
+ movq `2*$STRIDE/4-128`($tbl),%xmm2
+ pand %xmm5,%xmm1
+ movq `3*$STRIDE/4-128`($tbl),%xmm3
+ pand %xmm6,%xmm2
+ por %xmm1,%xmm0
+ pand %xmm7,%xmm3
+ .byte 0x67,0x67
+ por %xmm2,%xmm0
+ lea $STRIDE($tbl),$tbl
+ por %xmm3,%xmm0
+
+ movq %xmm0,($out) # m0=bp[0]
+ lea 8($out),$out
+ sub \$1,$num
+ jnz .Lgather
+___
+$code.=<<___ if ($win64);
+ movaps (%rsp),%xmm6
+ movaps 0x10(%rsp),%xmm7
+ lea 0x28(%rsp),%rsp
+___
+$code.=<<___;
+ ret
+.LSEH_end_bn_gather5:
+.size bn_gather5,.-bn_gather5
+___
+}
+$code.=<<___;
+.align 64
+.Lmagic_masks:
+ .long 0,0, 0,0, 0,0, -1,-1
+ .long 0,0, 0,0, 0,0, 0,0
+.asciz "Montgomery Multiplication with scatter/gather for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
+___
+
+# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
+# CONTEXT *context,DISPATCHER_CONTEXT *disp)
+if ($win64) {
+$rec="%rcx";
+$frame="%rdx";
+$context="%r8";
+$disp="%r9";
+
+$code.=<<___;
+.extern __imp_RtlVirtualUnwind
+.type mul_handler,\@abi-omnipotent
+.align 16
+mul_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 120($context),%rax # pull context->Rax
+ mov 248($context),%rbx # pull context->Rip
+
+ mov 8($disp),%rsi # disp->ImageBase
+ mov 56($disp),%r11 # disp->HandlerData
+
+ mov 0(%r11),%r10d # HandlerData[0]
+ lea (%rsi,%r10),%r10 # end of prologue label
+ cmp %r10,%rbx # context->Rip<end of prologue label
+ jb .Lcommon_seh_tail
+
+ mov 152($context),%rax # pull context->Rsp
+
+ mov 4(%r11),%r10d # HandlerData[1]
+ lea (%rsi,%r10),%r10 # epilogue label
+ cmp %r10,%rbx # context->Rip>=epilogue label
+ jae .Lcommon_seh_tail
+
+ lea .Lmul_epilogue(%rip),%r10
+ cmp %r10,%rbx
+ jb .Lbody_40
+
+ mov 192($context),%r10 # pull $num
+ mov 8(%rax,%r10,8),%rax # pull saved stack pointer
+ jmp .Lbody_proceed
+
+.Lbody_40:
+ mov 40(%rax),%rax # pull saved stack pointer
+.Lbody_proceed:
+
+ movaps -88(%rax),%xmm0
+ movaps -72(%rax),%xmm1
+
+ mov -8(%rax),%rbx
+ mov -16(%rax),%rbp
+ mov -24(%rax),%r12
+ mov -32(%rax),%r13
+ mov -40(%rax),%r14
+ mov -48(%rax),%r15
+ mov %rbx,144($context) # restore context->Rbx
+ mov %rbp,160($context) # restore context->Rbp
+ mov %r12,216($context) # restore context->R12
+ mov %r13,224($context) # restore context->R13
+ mov %r14,232($context) # restore context->R14
+ mov %r15,240($context) # restore context->R15
+ movups %xmm0,512($context) # restore context->Xmm6
+ movups %xmm1,528($context) # restore context->Xmm7
+
+.Lcommon_seh_tail:
+ mov 8(%rax),%rdi
+ mov 16(%rax),%rsi
+ mov %rax,152($context) # restore context->Rsp
+ mov %rsi,168($context) # restore context->Rsi
+ mov %rdi,176($context) # restore context->Rdi
+
+ mov 40($disp),%rdi # disp->ContextRecord
+ mov $context,%rsi # context
+ mov \$154,%ecx # sizeof(CONTEXT)
+ .long 0xa548f3fc # cld; rep movsq
+
+ mov $disp,%rsi
+ xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER
+ mov 8(%rsi),%rdx # arg2, disp->ImageBase
+ mov 0(%rsi),%r8 # arg3, disp->ControlPc
+ mov 16(%rsi),%r9 # arg4, disp->FunctionEntry
+ mov 40(%rsi),%r10 # disp->ContextRecord
+ lea 56(%rsi),%r11 # &disp->HandlerData
+ lea 24(%rsi),%r12 # &disp->EstablisherFrame
+ mov %r10,32(%rsp) # arg5
+ mov %r11,40(%rsp) # arg6
+ mov %r12,48(%rsp) # arg7
+ mov %rcx,56(%rsp) # arg8, (NULL)
+ call *__imp_RtlVirtualUnwind(%rip)
+
+ mov \$1,%eax # ExceptionContinueSearch
+ add \$64,%rsp
+ popfq
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+ pop %rdi
+ pop %rsi
+ ret
+.size mul_handler,.-mul_handler
+
+.section .pdata
+.align 4
+ .rva .LSEH_begin_bn_mul_mont_gather5
+ .rva .LSEH_end_bn_mul_mont_gather5
+ .rva .LSEH_info_bn_mul_mont_gather5
+
+ .rva .LSEH_begin_bn_mul4x_mont_gather5
+ .rva .LSEH_end_bn_mul4x_mont_gather5
+ .rva .LSEH_info_bn_mul4x_mont_gather5
+
+ .rva .LSEH_begin_bn_power5
+ .rva .LSEH_end_bn_power5
+ .rva .LSEH_info_bn_power5
+
+ .rva .LSEH_begin_bn_from_mont8x
+ .rva .LSEH_end_bn_from_mont8x
+ .rva .LSEH_info_bn_from_mont8x
+___
+$code.=<<___ if ($addx);
+ .rva .LSEH_begin_bn_mulx4x_mont_gather5
+ .rva .LSEH_end_bn_mulx4x_mont_gather5
+ .rva .LSEH_info_bn_mulx4x_mont_gather5
+
+ .rva .LSEH_begin_bn_powerx5
+ .rva .LSEH_end_bn_powerx5
+ .rva .LSEH_info_bn_powerx5
+___
+$code.=<<___;
+ .rva .LSEH_begin_bn_gather5
+ .rva .LSEH_end_bn_gather5
+ .rva .LSEH_info_bn_gather5
+
+.section .xdata
+.align 8
+.LSEH_info_bn_mul_mont_gather5:
+ .byte 9,0,0,0
+ .rva mul_handler
+ .rva .Lmul_body,.Lmul_epilogue # HandlerData[]
+.align 8
+.LSEH_info_bn_mul4x_mont_gather5:
+ .byte 9,0,0,0
+ .rva mul_handler
+ .rva .Lmul4x_body,.Lmul4x_epilogue # HandlerData[]
+.align 8
+.LSEH_info_bn_power5:
+ .byte 9,0,0,0
+ .rva mul_handler
+ .rva .Lpower5_body,.Lpower5_epilogue # HandlerData[]
+.align 8
+.LSEH_info_bn_from_mont8x:
+ .byte 9,0,0,0
+ .rva mul_handler
+ .rva .Lfrom_body,.Lfrom_epilogue # HandlerData[]
+___
+$code.=<<___ if ($addx);
+.align 8
+.LSEH_info_bn_mulx4x_mont_gather5:
+ .byte 9,0,0,0
+ .rva mul_handler
+ .rva .Lmulx4x_body,.Lmulx4x_epilogue # HandlerData[]
+.align 8
+.LSEH_info_bn_powerx5:
+ .byte 9,0,0,0
+ .rva mul_handler
+ .rva .Lpowerx5_body,.Lpowerx5_epilogue # HandlerData[]
+___
+$code.=<<___;
+.align 8
+.LSEH_info_bn_gather5:
+ .byte 0x01,0x0d,0x05,0x00
+ .byte 0x0d,0x78,0x01,0x00 #movaps 0x10(rsp),xmm7
+ .byte 0x08,0x68,0x00,0x00 #movaps (rsp),xmm6
+ .byte 0x04,0x42,0x00,0x00 #sub rsp,0x28
+.align 8
+___
+}
+
+$code =~ s/\`([^\`]*)\`/eval($1)/gem;
+
+print $code;
+close STDOUT;
diff --git a/crypto/bn/bn.c b/crypto/bn/bn.c
new file mode 100644
index 0000000..a996a47
--- /dev/null
+++ b/crypto/bn/bn.c
@@ -0,0 +1,336 @@
+/* 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/bn.h>
+
+#include <limits.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+#include "internal.h"
+
+
+BIGNUM *BN_new(void) {
+ BIGNUM *bn = OPENSSL_malloc(sizeof(BIGNUM));
+
+ if (bn == NULL) {
+ OPENSSL_PUT_ERROR(BN, BN_new, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ memset(bn, 0, sizeof(BIGNUM));
+ bn->flags = BN_FLG_MALLOCED;
+
+ return bn;
+}
+
+void BN_init(BIGNUM *bn) {
+ memset(bn, 0, sizeof(BIGNUM));
+}
+
+void BN_free(BIGNUM *bn) {
+ if (bn == NULL) {
+ return;
+ }
+
+ if (bn->d != NULL && (bn->flags & BN_FLG_STATIC_DATA) == 0) {
+ OPENSSL_free(bn->d);
+ }
+
+ if (bn->flags & BN_FLG_MALLOCED) {
+ OPENSSL_free(bn);
+ } else {
+ bn->d = NULL;
+ }
+}
+
+void BN_clear_free(BIGNUM *bn) {
+ char should_free;
+
+ if (bn == NULL) {
+ return;
+ }
+
+ if (bn->d != NULL) {
+ OPENSSL_cleanse(bn->d, bn->dmax * sizeof(bn->d[0]));
+ if ((bn->flags & BN_FLG_STATIC_DATA) == 0) {
+ OPENSSL_free(bn->d);
+ }
+ }
+
+ should_free = (bn->flags & BN_FLG_MALLOCED) != 0;
+ OPENSSL_cleanse(bn, sizeof(BIGNUM));
+ if (should_free) {
+ OPENSSL_free(bn);
+ }
+}
+
+BIGNUM *BN_dup(const BIGNUM *src) {
+ BIGNUM *copy;
+
+ if (src == NULL) {
+ return NULL;
+ }
+
+ copy = BN_new();
+ if (copy == NULL) {
+ return NULL;
+ }
+
+ if (!BN_copy(copy, src)) {
+ BN_free(copy);
+ return NULL;
+ }
+
+ return copy;
+}
+
+BIGNUM *BN_copy(BIGNUM *dest, const BIGNUM *src) {
+ if (src == dest) {
+ return dest;
+ }
+
+ if (bn_wexpand(dest, src->top) == NULL) {
+ return NULL;
+ }
+
+ memcpy(dest->d, src->d, sizeof(src->d[0]) * src->top);
+
+ dest->top = src->top;
+ dest->neg = src->neg;
+ return dest;
+}
+
+void BN_clear(BIGNUM *bn) {
+ if (bn->d != NULL) {
+ memset(bn->d, 0, bn->dmax * sizeof(bn->d[0]));
+ }
+
+ bn->top = 0;
+ bn->neg = 0;
+}
+
+const BIGNUM *BN_value_one(void) {
+ static const BN_ULONG data_one = 1;
+ static const BIGNUM const_one = {(BN_ULONG *)&data_one, 1, 1, 0,
+ BN_FLG_STATIC_DATA};
+
+ return &const_one;
+}
+
+void BN_with_flags(BIGNUM *out, const BIGNUM *in, int flags) {
+ memcpy(out, in, sizeof(BIGNUM));
+ out->flags &= ~BN_FLG_MALLOCED;
+ out->flags |= BN_FLG_STATIC_DATA | flags;
+}
+
+/* BN_num_bits_word returns the minimum number of bits needed to represent the
+ * value in |l|. */
+unsigned BN_num_bits_word(BN_ULONG l) {
+ static const unsigned char bits[256] = {
+ 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8};
+
+#if defined(OPENSSL_64_BIT)
+ if (l & 0xffffffff00000000L) {
+ if (l & 0xffff000000000000L) {
+ if (l & 0xff00000000000000L) {
+ return (bits[(int)(l >> 56)] + 56);
+ } else
+ return (bits[(int)(l >> 48)] + 48);
+ } else {
+ if (l & 0x0000ff0000000000L) {
+ return (bits[(int)(l >> 40)] + 40);
+ } else
+ return (bits[(int)(l >> 32)] + 32);
+ }
+ } else
+#endif
+ {
+ if (l & 0xffff0000L) {
+ if (l & 0xff000000L) {
+ return (bits[(int)(l >> 24L)] + 24);
+ } else {
+ return (bits[(int)(l >> 16L)] + 16);
+ }
+ } else {
+ if (l & 0xff00L) {
+ return (bits[(int)(l >> 8)] + 8);
+ } else {
+ return (bits[(int)(l)]);
+ }
+ }
+ }
+}
+
+unsigned BN_num_bits(const BIGNUM *bn) {
+ const int max = bn->top - 1;
+
+ if (BN_is_zero(bn)) {
+ return 0;
+ }
+
+ return max*BN_BITS2 + BN_num_bits_word(bn->d[max]);
+}
+
+unsigned BN_num_bytes(const BIGNUM *bn) {
+ return (BN_num_bits(bn) + 7) / 8;
+}
+
+void BN_zero(BIGNUM *bn) {
+ bn->top = bn->neg = 0;
+}
+
+int BN_one(BIGNUM *bn) {
+ return BN_set_word(bn, 1);
+}
+
+int BN_set_word(BIGNUM *bn, BN_ULONG value) {
+ if (value == 0) {
+ BN_zero(bn);
+ return 1;
+ }
+
+ if (bn_wexpand(bn, 1) == NULL) {
+ return 0;
+ }
+
+ bn->neg = 0;
+ bn->d[0] = value;
+ bn->top = 1;
+ return 1;
+}
+
+int BN_is_negative(const BIGNUM *bn) {
+ return bn->neg != 0;
+}
+
+void BN_set_negative(BIGNUM *bn, int sign) {
+ if (sign && !BN_is_zero(bn)) {
+ bn->neg = 1;
+ } else {
+ bn->neg = 0;
+ }
+}
+
+BIGNUM *bn_wexpand(BIGNUM *bn, unsigned words) {
+ BN_ULONG *a;
+
+ if (words <= (unsigned) bn->dmax) {
+ return bn;
+ }
+
+ if (words > (INT_MAX / (4 * BN_BITS2))) {
+ OPENSSL_PUT_ERROR(BN, bn_wexpand, 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);
+ return NULL;
+ }
+
+ a = (BN_ULONG *)OPENSSL_malloc(sizeof(BN_ULONG) * words);
+ if (a == NULL) {
+ OPENSSL_PUT_ERROR(BN, bn_wexpand, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ memcpy(a, bn->d, sizeof(BN_ULONG) * bn->top);
+
+ if (bn->d) {
+ OPENSSL_free(bn->d);
+ }
+ bn->d = a;
+ bn->dmax = words;
+
+ return bn;
+}
+
+BIGNUM *bn_expand(BIGNUM *bn, unsigned bits) {
+ return bn_wexpand(bn, (bits+BN_BITS2-1)/BN_BITS2);
+}
+
+void bn_correct_top(BIGNUM *bn) {
+ BN_ULONG *ftl;
+ int tmp_top = bn->top;
+
+ if (tmp_top > 0) {
+ for (ftl = &(bn->d[tmp_top - 1]); tmp_top > 0; tmp_top--) {
+ if (*(ftl--)) {
+ break;
+ }
+ }
+ bn->top = tmp_top;
+ }
+}
+
+int BN_get_flags(const BIGNUM *bn, int flags) {
+ return bn->flags & flags;
+}
+
+void BN_set_flags(BIGNUM *bn, int flags) {
+ bn->flags |= flags;
+}
diff --git a/crypto/bn/bn.h b/crypto/bn/bn.h
new file mode 100644
index 0000000..16ce65f
--- /dev/null
+++ b/crypto/bn/bn.h
@@ -0,0 +1,790 @@
+/* Copyright (C) 1995-1997 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.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2006 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).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the Eric Young open source
+ * license provided above.
+ *
+ * The binary polynomial arithmetic software is originally written by
+ * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems
+ * Laboratories. */
+
+#ifndef OPENSSL_HEADER_BN_H
+#define OPENSSL_HEADER_BN_H
+
+#include <openssl/base.h>
+
+#include <stdio.h> /* for FILE* */
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* BN provides support for working with arbitary sized integers. For example,
+ * although the largest integer supported by the compiler might be 64 bits, BN
+ * will allow you to work with numbers until you run out of memory. */
+
+
+/* BN_ULONG is the native word size when working with big integers. */
+#if defined(OPENSSL_64_BIT)
+#define BN_ULONG uint64_t
+#define BN_BITS2 64
+#elif defined(OPENSSL_32_BIT)
+#define BN_ULONG uint32_t
+#define BN_BITS2 32
+#else
+#error "Must define either OPENSSL_32_BIT or OPENSSL_64_BIT"
+#endif
+
+
+/* Allocation and freeing. */
+
+/* BN_new creates a new, allocated BIGNUM and initialises it. */
+BIGNUM *BN_new(void);
+
+/* BN_init initialises a stack allocated |BIGNUM|. */
+void BN_init(BIGNUM *bn);
+
+/* BN_free frees the data referenced by |bn| and, if |bn| was originally
+ * allocated on the heap, frees |bn| also. */
+void BN_free(BIGNUM *bn);
+
+/* BN_clear_free erases and frees the data referenced by |bn| and, if |bn| was
+ * originally allocated on the heap, frees |bn| also. */
+void BN_clear_free(BIGNUM *bn);
+
+/* BN_dup allocates a new BIGNUM and sets it equal to |src|. It returns the
+ * allocated BIGNUM on success or NULL otherwise. */
+BIGNUM *BN_dup(const BIGNUM *src);
+
+/* BN_copy sets |dest| equal to |src| and returns |dest|. */
+BIGNUM *BN_copy(BIGNUM *dest, const BIGNUM *src);
+
+/* BN_clear sets |bn| to zero and erases the old data. */
+void BN_clear(BIGNUM *bn);
+
+/* BN_value_one returns a static BIGNUM with value 1. */
+const BIGNUM *BN_value_one(void);
+
+/* BN_with_flags initialises a stack allocated |BIGNUM| with pointers to the
+ * contents of |in| but with |flags| ORed into the flags field.
+ *
+ * Note: the two BIGNUMs share state and so |out| should /not/ be passed to
+ * |BN_free|. */
+void BN_with_flags(BIGNUM *out, const BIGNUM *in, int flags);
+
+
+/* Basic functions. */
+
+/* BN_num_bits returns the minimum number of bits needed to represent the
+ * absolute value of |bn|. */
+unsigned BN_num_bits(const BIGNUM *bn);
+
+/* BN_num_bytes returns the minimum number of bytes needed to represent the
+ * absolute value of |bn|. */
+unsigned BN_num_bytes(const BIGNUM *bn);
+
+/* BN_zero sets |bn| to zero. */
+void BN_zero(BIGNUM *bn);
+
+/* BN_one sets |bn| to one. It returns one on success or zero on allocation
+ * failure. */
+int BN_one(BIGNUM *bn);
+
+/* BN_set_word sets |bn| to |value|. It returns one on success or zero on
+ * allocation failure. */
+int BN_set_word(BIGNUM *bn, BN_ULONG value);
+
+/* BN_set_negative sets the sign of |bn|. */
+void BN_set_negative(BIGNUM *bn, int sign);
+
+/* BN_is_negative returns one if |bn| is negative and zero otherwise. */
+int BN_is_negative(const BIGNUM *bn);
+
+/* BN_get_flags returns |bn->flags| & |flags|. */
+int BN_get_flags(const BIGNUM *bn, int flags);
+
+/* BN_set_flags sets |flags| on |bn|. */
+void BN_set_flags(BIGNUM *bn, int flags);
+
+
+/* Conversion functions. */
+
+/* BN_bin2bn sets |*ret| to the value of |len| bytes from |in|, interpreted as
+ * a big-endian number, and returns |ret|. If |ret| is NULL then a fresh
+ * |BIGNUM| is allocated and returned. It returns NULL on allocation
+ * failure. */
+BIGNUM *BN_bin2bn(const uint8_t *in, size_t len, BIGNUM *ret);
+
+/* BN_bn2bin serialises the absolute value of |in| to |out| as a big-endian
+ * integer, which must have |BN_num_bytes| of space available. It returns the
+ * number of bytes written. */
+size_t BN_bn2bin(const BIGNUM *in, uint8_t *out);
+
+/* BN_bn2hex returns an allocated string that contains a NUL-terminated, hex
+ * representation of |bn|. If |bn| is negative, the first char in the resulting
+ * string will be '-'. Returns NULL on allocation failure. */
+char *BN_bn2hex(const BIGNUM *bn);
+
+/* BN_hex2bn parses the leading hex number from |in|, which may be proceeded by
+ * a '-' to indicate a negative number and may contain trailing, non-hex data.
+ * If |outp| is not NULL, it constructs a BIGNUM equal to the hex number and
+ * stores it in |*outp|. If |*outp| is NULL then it allocates a new BIGNUM and
+ * updates |*outp|. It returns the number of bytes of |in| processed or zero on
+ * error. */
+int BN_hex2bn(BIGNUM **outp, const char *in);
+
+/* BN_bn2dec returns an allocated string that contains a NUL-terminated,
+ * decimal representation of |bn|. If |bn| is negative, the first char in the
+ * resulting string will be '-'. Returns NULL on allocation failure. */
+char *BN_bn2dec(const BIGNUM *a);
+
+/* BN_dec2bn parses the leading decimal number from |in|, which may be
+ * proceeded by a '-' to indicate a negative number and may contain trailing,
+ * non-decimal data. If |outp| is not NULL, it constructs a BIGNUM equal to the
+ * decimal number and stores it in |*outp|. If |*outp| is NULL then it
+ * allocates a new BIGNUM and updates |*outp|. It returns the number of bytes
+ * of |in| processed or zero on error. */
+int BN_dec2bn(BIGNUM **outp, const char *in);
+
+/* BN_asc2bn acts like |BN_dec2bn| or |BN_hex2bn| depending on whether |in|
+ * begins with "0X" or "0x" (indicating hex) or not (indicating decimal). A
+ * leading '-' is still permitted and comes before the optional 0X/0x. It
+ * returns one on success or zero on error. */
+int BN_asc2bn(BIGNUM **outp, const char *in);
+
+/* BN_print writes a hex encoding of |a| to |bio|. It returns one on success
+ * and zero on error. */
+int BN_print(BIO *bio, const BIGNUM *a);
+
+/* BN_print_fp acts like |BIO_print|, but wraps |fp| in a |BIO| first. */
+int BN_print_fp(FILE *fp, const BIGNUM *a);
+
+/* BN_get_word returns the absolute value of |bn| as a single word. If |bn| is
+ * too large to be represented as a single word, the maximum possible value
+ * will be returned. */
+BN_ULONG BN_get_word(const BIGNUM *bn);
+
+
+/* BIGNUM pools.
+ *
+ * Certain BIGNUM operations need to use many temporary variables and
+ * allocating and freeing them can be quite slow. Thus such opertions typically
+ * take a |BN_CTX| parameter, which contains a pool of |BIGNUMs|. The |ctx|
+ * argument to a public function may be NULL, in which case a local |BN_CTX|
+ * will be created just for the lifetime of that call.
+ *
+ * A function must call |BN_CTX_start| first. Then, |BN_CTX_get| may be called
+ * repeatedly to obtain temporary |BIGNUM|s. All |BN_CTX_get| calls must be made
+ * before calling any other functions that use the |ctx| as an argument.
+ *
+ * Finally, |BN_CTX_end| must be called before returning from the function.
+ * When |BN_CTX_end| is called, the |BIGNUM| pointers obtained from
+ * |BN_CTX_get| become invalid. */
+
+/* BN_CTX_new returns a new, empty BN_CTX or NULL on allocation failure. */
+BN_CTX *BN_CTX_new(void);
+
+/* BN_CTX_free frees all BIGNUMs contained in |ctx| and then frees |ctx|
+ * itself. */
+void BN_CTX_free(BN_CTX *ctx);
+
+/* BN_CTX_start "pushes" a new entry onto the |ctx| stack and allows future
+ * calls to |BN_CTX_get|. */
+void BN_CTX_start(BN_CTX *ctx);
+
+/* BN_CTX_get returns a new |BIGNUM|, or NULL on allocation failure. Once
+ * |BN_CTX_get| has returned NULL, all future calls will also return NULL until
+ * |BN_CTX_end| is called. */
+BIGNUM *BN_CTX_get(BN_CTX *ctx);
+
+/* BN_CTX_end invalidates all |BIGNUM|s returned from |BN_CTX_get| since the
+ * matching |BN_CTX_start| call. */
+void BN_CTX_end(BN_CTX *ctx);
+
+
+/* Simple arithmetic */
+
+/* BN_add sets |r| = |a| + |b|, where |r| may be the same pointer as either |a|
+ * or |b|. It returns one on success and zero on allocation failure. */
+int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
+
+/* BN_uadd sets |r| = |a| + |b|, where |a| and |b| are non-negative and |r| may
+ * be the same pointer as either |a| or |b|. It returns one on success and zero
+ * on allocation failure. */
+int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
+
+/* BN_add_word adds |w| to |a|. It returns one on success and zero otherwise. */
+int BN_add_word(BIGNUM *a, BN_ULONG w);
+
+/* BN_sub sets |r| = |a| + |b|, where |r| must be a distinct pointer from |a|
+ * and |b|. It returns one on success and zero on allocation failure. */
+int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
+
+/* BN_usub sets |r| = |a| + |b|, where |a| and |b| are non-negative integers,
+ * |b| < |a| and |r| must be a distinct pointer from |a| and |b|. It returns
+ * one on success and zero on allocation failure. */
+int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
+
+/* BN_sub_word subtracts |w| from |a|. It returns one on success and zero on
+ * allocation failure. */
+int BN_sub_word(BIGNUM *a, BN_ULONG w);
+
+/* BN_mul sets |r| = |a| * |b|, where |r| may be the same pointer as |a| or
+ * |b|. Returns one on success and zero otherwise. */
+int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
+
+/* BN_mul_word sets |bn| = |bn| * |w|. It returns one on success or zero on
+ * allocation failure. */
+int BN_mul_word(BIGNUM *bn, BN_ULONG w);
+
+/* BN_sqr sets |r| = |a|^2 (i.e. squares), where |r| may be the same pointer as
+ * |a|. Returns one on success and zero otherwise. This is more efficient than
+ * BN_mul(r, a, a, ctx). */
+int BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx);
+
+/* BN_div divides |numerator| by |divisor| and places the result in |quotient|
+ * and the remainder in |rem|. Either of |quotient| or |rem| may be NULL, in
+ * which case the respective value is not returned. The result is rounded
+ * towards zero; thus if |numerator| is negative, the remainder will be zero or
+ * negative. It returns one on success or zero on error. */
+int BN_div(BIGNUM *quotient, BIGNUM *rem, const BIGNUM *numerator,
+ const BIGNUM *divisor, BN_CTX *ctx);
+
+/* BN_div_word sets |numerator| = |numerator|/|divisor| and returns the
+ * remainder or (BN_ULONG)-1 on error. */
+BN_ULONG BN_div_word(BIGNUM *numerator, BN_ULONG divisor);
+
+
+/* Comparison functions */
+
+/* BN_cmp returns a value less than, equal to or greater than zero if |a| is
+ * less than, equal to or greater than |b|, respectively. */
+int BN_cmp(const BIGNUM *a, const BIGNUM *b);
+
+/* BN_ucmp returns a value less than, equal to or greater than zero if the
+ * absolute value of |a| is less than, equal to or greater than the absolute
+ * value of |b|, respectively. */
+int BN_ucmp(const BIGNUM *a, const BIGNUM *b);
+
+/* BN_abs_is_word returns one if the absolute value of |bn| equals |w| and zero
+ * otherwise. */
+int BN_abs_is_word(const BIGNUM *bn, BN_ULONG w);
+
+/* BN_is_zero returns one if |bn| is zero and zero otherwise. */
+int BN_is_zero(const BIGNUM *bn);
+
+/* BN_is_one returns one if |bn| equals one and zero otherwise. */
+int BN_is_one(const BIGNUM *bn);
+
+/* BN_is_word returns one if |bn| is exactly |w| and zero otherwise. */
+int BN_is_word(const BIGNUM *bn, BN_ULONG w);
+
+/* BN_is_odd returns one if |bn| is odd and zero otherwise. */
+int BN_is_odd(const BIGNUM *bn);
+
+
+/* Bitwise operations. */
+
+/* BN_lshift sets |r| equal to |a| << n. The |a| and |r| arguments may be the
+ * same |BIGNUM|. It returns one on success and zero on allocation failure. */
+int BN_lshift(BIGNUM *r, const BIGNUM *a, int n);
+
+/* BN_lshift1 sets |r| equal to |a| << 1, where |r| and |a| may be the same
+ * pointer. It returns one on success and zero on allocation failure. */
+int BN_lshift1(BIGNUM *r, const BIGNUM *a);
+
+/* BN_rshift sets |r| equal to |a| >> n, where |r| and |a| may be the same
+ * pointer. It returns one on success and zero on allocation failure. */
+int BN_rshift(BIGNUM *r, const BIGNUM *a, int n);
+
+/* BN_rshift1 sets |r| equal to |a| >> 1, where |r| and |a| may be the same
+ * pointer. It returns one on success and zero on allocation failure. */
+int BN_rshift1(BIGNUM *r, const BIGNUM *a);
+
+/* BN_set_bit sets the |n|th, least-significant bit in |a|. For example, if |a|
+ * is 2 then setting bit zero will make it 3. It returns one on success or zero
+ * on allocation failure. */
+int BN_set_bit(BIGNUM *a, int n);
+
+/* BN_clear_bit clears the |n|th, least-significant bit in |a|. For example, if
+ * |a| is 3, clearing bit zero will make it two. It returns one on success or
+ * zero on allocation failure. */
+int BN_clear_bit(BIGNUM *a, int n);
+
+/* BN_is_bit_set returns the value of the |n|th, least-significant bit in |a|,
+ * or zero if the bit doesn't exist. */
+int BN_is_bit_set(const BIGNUM *a, int n);
+
+/* BN_mask_bits truncates |a| so that it is only |n| bits long. It returns one
+ * on success or zero if |n| is greater than the length of |a| already. */
+int BN_mask_bits(BIGNUM *a, int n);
+
+
+/* Modulo arithmetic. */
+
+/* BN_mod_word returns |a| mod |w|. */
+BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w);
+
+/* BN_mod is a helper macro that calls |BN_div| and discards the quotient. */
+#define BN_mod(rem, numerator, divisor, ctx) \
+ BN_div(NULL, (rem), (numerator), (divisor), (ctx))
+
+/* BN_nnmod is a non-negative modulo function. It acts like |BN_mod|, but 0 <=
+ * |rem| < |divisor| is always true. */
+int BN_nnmod(BIGNUM *rem, const BIGNUM *numerator, const BIGNUM *divisor,
+ BN_CTX *ctx);
+
+/* BN_mod_add sets |r| = |a| + |b| mod |m|. It returns one on success and zero
+ * on error. */
+int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
+ BN_CTX *ctx);
+
+/* BN_mod_add_quick acts like |BN_mod_add| but requires that |a| and |b| be
+ * non-negative and less than |m|. */
+int BN_mod_add_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+ const BIGNUM *m);
+
+/* BN_mod_sub sets |r| = |a| - |b| mod |m|. It returns one on success and zero
+ * on error. */
+int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
+ BN_CTX *ctx);
+
+/* BN_mod_sub_quick acts like |BN_mod_sub| but requires that |a| and |b| be
+ * non-negative and less than |m|. */
+int BN_mod_sub_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+ const BIGNUM *m);
+
+/* BN_mod_mul sets |r| = |a|*|b| mod |m|. It returns one on success and zero
+ * on error. */
+int BN_mod_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
+ BN_CTX *ctx);
+
+/* BN_mod_mul sets |r| = |a|^2 mod |m|. It returns one on success and zero
+ * on error. */
+int BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx);
+
+/* BN_mod_lshift sets |r| = (|a| << n) mod |m|, where |r| and |a| may be the
+ * same pointer. It returns one on success and zero on error. */
+int BN_mod_lshift(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m,
+ BN_CTX *ctx);
+
+/* BN_mod_lshift_quick acts like |BN_mod_lshift| but requires that |a| be
+ * non-negative and less than |m|. */
+int BN_mod_lshift_quick(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m);
+
+/* BN_mod_lshift1 sets |r| = (|a| << 1) mod |m|, where |r| and |a| may be the
+ * same pointer. It returns one on success and zero on error. */
+int BN_mod_lshift1(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx);
+
+/* BN_mod_lshift1_quick acts like |BN_mod_lshift1| but requires that |a| be
+ * non-negative and less than |m|. */
+int BN_mod_lshift1_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *m);
+
+/* BN_mod_sqrt returns a |BIGNUM|, r, such that r^2 == a (mod p). */
+BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx);
+
+
+/* Random and prime number generation. */
+
+/* BN_rand sets |rnd| to a random number of length |bits|. If |top| is zero,
+ * the most-significant bit will be set. If |top| is one, the two most
+ * significant bits will be set.
+ *
+ * If |top| is -1 then no extra action will be taken and |BN_num_bits(rnd)| may
+ * not equal |bits| if the most significant bits randomly ended up as zeros.
+ *
+ * If |bottom| is non-zero, the least-significant bit will be set. The function
+ * returns one on success or zero otherwise. */
+int BN_rand(BIGNUM *rnd, int bits, int top, int bottom);
+
+/* BN_pseudo_rand is an alias for |BN_rand|. */
+int BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom);
+
+/* BN_rand_range sets |rnd| to a random value [0..range). It returns one on
+ * success and zero otherwise. */
+int BN_rand_range(BIGNUM *rnd, const BIGNUM *range);
+
+/* BN_pseudo_rand_range is an alias for BN_rand_range. */
+int BN_pseudo_rand_range(BIGNUM *rnd, const BIGNUM *range);
+
+/* BN_GENCB holds a callback function that is used by generation functions that
+ * can take a very long time to complete. Use |BN_GENCB_set| to initialise a
+ * |BN_GENCB| structure.
+ *
+ * The callback receives the address of that |BN_GENCB| structure as its last
+ * argument and the user is free to put an arbitary pointer in |arg|. The other
+ * arguments are set as follows:
+ * event=BN_GENCB_GENERATED, n=i: after generating the i'th possible prime
+ * number.
+ * event=BN_GENCB_PRIME_TEST, n=-1: when finished trial division primality
+ * checks.
+ * event=BN_GENCB_PRIME_TEST, n=i: when the i'th primality test has finished.
+ *
+ * The callback can return zero to abort the generation progress or one to
+ * allow it to continue.
+ *
+ * When other code needs to call a BN generation function it will often take a
+ * BN_GENCB argument and may call the function with other argument values. */
+#define BN_GENCB_GENERATED 0
+#define BN_GENCB_PRIME_TEST 1
+
+struct bn_gencb_st {
+ void *arg; /* callback-specific data */
+ int (*callback)(int event, int n, struct bn_gencb_st *);
+};
+
+/* BN_GENCB_set configures |callback| to call |f| and sets |callout->arg| to
+ * |arg|. */
+void BN_GENCB_set(BN_GENCB *callback,
+ int (*f)(int event, int n, struct bn_gencb_st *),
+ void *arg);
+
+/* BN_GENCB_call calls |callback|, if not NULL, and returns the return value of
+ * the callback, or 1 if |callback| is NULL. */
+int BN_GENCB_call(BN_GENCB *callback, int event, int n);
+
+/* BN_generate_prime_ex sets |ret| to a prime number of |bits| length. If safe
+ * is non-zero then the prime will be such that (ret-1)/2 is also a prime.
+ * (This is needed for Diffie-Hellman groups to ensure that the only subgroups
+ * are of size 2 and (p-1)/2.).
+ *
+ * If |add| is not NULL, the prime will fulfill the condition |ret| % |add| ==
+ * |rem| in order to suit a given generator. (If |rem| is NULL then |ret| %
+ * |add| == 1.)
+ *
+ * If |cb| is not NULL, it will be called during processing to give an
+ * indication of progress. See the comments for |BN_GENCB|. It returns one on
+ * success and zero otherwise. */
+int BN_generate_prime_ex(BIGNUM *ret, int bits, int safe, const BIGNUM *add,
+ const BIGNUM *rem, BN_GENCB *cb);
+
+/* BN_prime_checks is magic value that can be used as the |checks| argument to
+ * the primality testing functions in order to automatically select a number of
+ * Miller-Rabin checks that gives a false positive rate of ~2^{-80}. */
+#define BN_prime_checks 0
+
+/* BN_primality_test sets |*is_probably_prime| to one if |candidate| is
+ * probably a prime number by the Miller-Rabin test or zero if it's certainly
+ * not.
+ *
+ * If |do_trial_division| is non-zero then |candidate| will be tested against a
+ * list of small primes before Miller-Rabin tests. The probability of this
+ * function returning a false positive is 2^{2*checks}. If |checks| is
+ * |BN_prime_checks| then a value that results in approximately 2^{-80} false
+ * positive probability is used. If |cb| is not NULL then it is called during
+ * the checking process. See the comment above |BN_GENCB|.
+ *
+ * The function returns one on success and zero on error.
+ *
+ * (If you are unsure whether you want |do_trial_division|, don't set it.) */
+int BN_primality_test(int *is_probably_prime, const BIGNUM *candidate,
+ int checks, BN_CTX *ctx, int do_trial_division,
+ BN_GENCB *cb);
+
+/* BN_is_prime_fasttest_ex returns one if |candidate| is probably a prime
+ * number by the Miller-Rabin test, zero if it's certainly not and -1 on error.
+ *
+ * If |do_trial_division| is non-zero then |candidate| will be tested against a
+ * list of small primes before Miller-Rabin tests. The probability of this
+ * function returning one when |candidate| is composite is 2^{2*checks}. If
+ * |checks| is |BN_prime_checks| then a value that results in approximately
+ * 2^{-80} false positive probability is used. If |cb| is not NULL then it is
+ * called during the checking process. See the comment above |BN_GENCB|.
+ *
+ * WARNING: deprecated. Use |BN_primality_test|. */
+int BN_is_prime_fasttest_ex(const BIGNUM *candidate, int checks, BN_CTX *ctx,
+ int do_trial_division, BN_GENCB *cb);
+
+/* BN_is_prime_ex acts the same as |BN_is_prime_fasttest_ex| with
+ * |do_trial_division| set to zero.
+ *
+ * WARNING: deprecated: Use |BN_primality_test|. */
+int BN_is_prime_ex(const BIGNUM *candidate, int checks, BN_CTX *ctx,
+ BN_GENCB *cb);
+
+
+/* Number theory functions */
+
+/* BN_gcd sets |r| = gcd(|a|, |b|). It returns one on success and zero
+ * otherwise. */
+int BN_gcd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
+
+/* BN_mod_inverse sets |out| equal to |a|^-1, mod |n|. If either of |a| or |n|
+ * have |BN_FLG_CONSTTIME| set then the operation is performed in constant
+ * time. If |out| is NULL, a fresh BIGNUM is allocated. It returns the result
+ * or NULL on error. */
+BIGNUM *BN_mod_inverse(BIGNUM *out, const BIGNUM *a, const BIGNUM *n,
+ BN_CTX *ctx);
+
+/* BN_kronecker returns the Kronecker symbol of |a| and |b| (which is -1, 0 or
+ * 1), or -2 on error. */
+int BN_kronecker(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
+
+
+/* Montgomery arithmetic. */
+
+/* BN_MONT_CTX contains the precomputed values needed to work in a specific
+ * Montgomery domain. */
+
+/* BN_MONT_CTX_new returns a fresh BN_MONT_CTX or NULL on allocation failure. */
+BN_MONT_CTX *BN_MONT_CTX_new(void);
+
+/* BN_MONT_CTX_init initialises a stack allocated |BN_MONT_CTX|. */
+void BN_MONT_CTX_init(BN_MONT_CTX *mont);
+
+/* BN_MONT_CTX_free frees the contexts of |mont| and, if it was originally
+ * allocated with |BN_MONT_CTX_new|, |mont| itself. */
+void BN_MONT_CTX_free(BN_MONT_CTX *mont);
+
+/* BN_MONT_CTX_copy sets |to| equal to |from|. It returns |to| on success or
+ * NULL on error. */
+BN_MONT_CTX *BN_MONT_CTX_copy(BN_MONT_CTX *to, BN_MONT_CTX *from);
+
+/* BN_MONT_CTX_set sets up a Montgomery context given the modulus, |mod|. It
+ * returns one on success and zero on error. */
+int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx);
+
+/* BN_MONT_CTX_set_locked takes the lock indicated by |lock| and checks whether
+ * |*pmont| is NULL. If so, it creates a new |BN_MONT_CTX| and sets the modulus
+ * for it to |mod|. It then stores it as |*pmont| and returns it, or NULL on
+ * error.
+ *
+ * If |*pmont| is already non-NULL then the existing value is returned. */
+BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, int lock,
+ const BIGNUM *mod, BN_CTX *ctx);
+
+/* BN_to_montgomery sets |ret| equal to |a| in the Montgomery domain. It
+ * returns one on success and zero on error. */
+int BN_to_montgomery(BIGNUM *ret, const BIGNUM *a, const BN_MONT_CTX *mont,
+ BN_CTX *ctx);
+
+/* BN_from_montgomery sets |ret| equal to |a| * R^-1, i.e. translates values
+ * out of the Montgomery domain. It returns one on success or zero on error. */
+int BN_from_montgomery(BIGNUM *ret, const BIGNUM *a, const BN_MONT_CTX *mont,
+ BN_CTX *ctx);
+
+/* BN_mod_mul_montgomery set |r| equal to |a| * |b|, in the Montgomery domain.
+ * Both |a| and |b| must already be in the Montgomery domain (by
+ * |BN_to_montgomery|). It returns one on success or zero on error. */
+int BN_mod_mul_montgomery(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+ const BN_MONT_CTX *mont, BN_CTX *ctx);
+
+
+/* Exponentiation. */
+
+/* BN_exp sets |r| equal to |a|^{|p|}. It does so with a square-and-multiply
+ * algorithm that leaks side-channel information. It returns one on success or
+ * zero otherwise. */
+int BN_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx);
+
+/* BN_exp sets |r| equal to |a|^{|p|} mod |m|. It does so with the best
+ * algorithm for the values provided and can run in constant time if
+ * |BN_FLG_CONSTTIME| is set for |p|. It returns one on success or zero
+ * otherwise. */
+int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m,
+ BN_CTX *ctx);
+
+int BN_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+ const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
+
+int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
+ const BIGNUM *m, BN_CTX *ctx,
+ BN_MONT_CTX *in_mont);
+
+int BN_mod_exp_mont_word(BIGNUM *r, BN_ULONG a, const BIGNUM *p,
+ const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
+int BN_mod_exp2_mont(BIGNUM *r, const BIGNUM *a1, const BIGNUM *p1,
+ const BIGNUM *a2, const BIGNUM *p2, const BIGNUM *m,
+ BN_CTX *ctx, BN_MONT_CTX *m_ctx);
+int BN_mod_exp_simple(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+ const BIGNUM *m, BN_CTX *ctx);
+
+
+
+/* Private functions */
+
+struct bignum_st {
+ BN_ULONG *d; /* Pointer to an array of 'BN_BITS2' bit chunks in little-endian
+ order. */
+ int top; /* Index of last used element in |d|, plus one. */
+ int dmax; /* Size of |d|, in words. */
+ int neg; /* one if the number is negative */
+ int flags; /* bitmask of BN_FLG_* values */
+};
+
+struct bn_mont_ctx_st {
+ BIGNUM RR; /* used to convert to montgomery form */
+ BIGNUM N; /* The modulus */
+ BIGNUM Ni; /* R*(1/R mod N) - N*Ni = 1
+ * (Ni is only stored for bignum algorithm) */
+ BN_ULONG n0[2]; /* least significant word(s) of Ni;
+ (type changed with 0.9.9, was "BN_ULONG n0;" before) */
+ int flags;
+ int ri; /* number of bits in R */
+};
+
+unsigned BN_num_bits_word(BN_ULONG l);
+
+#define BN_FLG_MALLOCED 0x01
+#define BN_FLG_STATIC_DATA 0x02
+/* avoid leaking exponent information through timing, BN_mod_exp_mont() will
+ * call BN_mod_exp_mont_consttime, BN_div() will call BN_div_no_branch,
+ * BN_mod_inverse() will call BN_mod_inverse_no_branch. */
+#define BN_FLG_CONSTTIME 0x04
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#define BN_F_BN_bn2hex 100
+#define BN_F_BN_new 101
+#define BN_F_BN_exp 102
+#define BN_F_mod_exp_recp 103
+#define BN_F_BN_mod_sqrt 104
+#define BN_F_BN_rand 105
+#define BN_F_BN_rand_range 106
+#define BN_F_bn_wexpand 107
+#define BN_F_BN_mod_exp_mont 108
+#define BN_F_BN_mod_exp2_mont 109
+#define BN_F_BN_CTX_get 110
+#define BN_F_BN_mod_inverse 111
+#define BN_F_BN_bn2dec 112
+#define BN_F_BN_div 113
+#define BN_F_BN_div_recp 114
+#define BN_F_BN_mod_exp_mont_consttime 115
+#define BN_F_BN_mod_exp_mont_word 116
+#define BN_F_BN_CTX_start 117
+#define BN_F_BN_usub 118
+#define BN_F_BN_mod_lshift_quick 119
+#define BN_F_BN_CTX_new 120
+#define BN_F_BN_mod_inverse_no_branch 121
+#define BN_R_NOT_A_SQUARE 100
+#define BN_R_TOO_MANY_ITERATIONS 101
+#define BN_R_INPUT_NOT_REDUCED 102
+#define BN_R_TOO_MANY_TEMPORARY_VARIABLES 103
+#define BN_R_NO_INVERSE 104
+#define BN_R_NOT_INITIALIZED 105
+#define BN_R_DIV_BY_ZERO 106
+#define BN_R_CALLED_WITH_EVEN_MODULUS 107
+#define BN_R_EXPAND_ON_STATIC_BIGNUM_DATA 108
+#define BN_R_BAD_RECIPROCAL 109
+#define BN_R_P_IS_NOT_PRIME 110
+#define BN_R_INVALID_RANGE 111
+#define BN_R_ARG2_LT_ARG3 112
+#define BN_R_BIGNUM_TOO_LONG 113
+
+#endif /* OPENSSL_HEADER_BN_H */
diff --git a/crypto/bn/bn_error.c b/crypto/bn/bn_error.c
new file mode 100644
index 0000000..a73571c
--- /dev/null
+++ b/crypto/bn/bn_error.c
@@ -0,0 +1,57 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/err.h>
+
+#include "bn.h"
+
+const ERR_STRING_DATA BN_error_string_data[] = {
+ {ERR_PACK(ERR_LIB_BN, BN_F_BN_CTX_get, 0), "BN_CTX_get"},
+ {ERR_PACK(ERR_LIB_BN, BN_F_BN_CTX_new, 0), "BN_CTX_new"},
+ {ERR_PACK(ERR_LIB_BN, BN_F_BN_CTX_start, 0), "BN_CTX_start"},
+ {ERR_PACK(ERR_LIB_BN, BN_F_BN_bn2dec, 0), "BN_bn2dec"},
+ {ERR_PACK(ERR_LIB_BN, BN_F_BN_bn2hex, 0), "BN_bn2hex"},
+ {ERR_PACK(ERR_LIB_BN, BN_F_BN_div, 0), "BN_div"},
+ {ERR_PACK(ERR_LIB_BN, BN_F_BN_div_recp, 0), "BN_div_recp"},
+ {ERR_PACK(ERR_LIB_BN, BN_F_BN_exp, 0), "BN_exp"},
+ {ERR_PACK(ERR_LIB_BN, BN_F_BN_mod_exp2_mont, 0), "BN_mod_exp2_mont"},
+ {ERR_PACK(ERR_LIB_BN, BN_F_BN_mod_exp_mont, 0), "BN_mod_exp_mont"},
+ {ERR_PACK(ERR_LIB_BN, BN_F_BN_mod_exp_mont_consttime, 0), "BN_mod_exp_mont_consttime"},
+ {ERR_PACK(ERR_LIB_BN, BN_F_BN_mod_exp_mont_word, 0), "BN_mod_exp_mont_word"},
+ {ERR_PACK(ERR_LIB_BN, BN_F_BN_mod_inverse, 0), "BN_mod_inverse"},
+ {ERR_PACK(ERR_LIB_BN, BN_F_BN_mod_inverse_no_branch, 0), "BN_mod_inverse_no_branch"},
+ {ERR_PACK(ERR_LIB_BN, BN_F_BN_mod_lshift_quick, 0), "BN_mod_lshift_quick"},
+ {ERR_PACK(ERR_LIB_BN, BN_F_BN_mod_sqrt, 0), "BN_mod_sqrt"},
+ {ERR_PACK(ERR_LIB_BN, BN_F_BN_new, 0), "BN_new"},
+ {ERR_PACK(ERR_LIB_BN, BN_F_BN_rand, 0), "BN_rand"},
+ {ERR_PACK(ERR_LIB_BN, BN_F_BN_rand_range, 0), "BN_rand_range"},
+ {ERR_PACK(ERR_LIB_BN, BN_F_BN_usub, 0), "BN_usub"},
+ {ERR_PACK(ERR_LIB_BN, BN_F_bn_wexpand, 0), "bn_wexpand"},
+ {ERR_PACK(ERR_LIB_BN, BN_F_mod_exp_recp, 0), "mod_exp_recp"},
+ {ERR_PACK(ERR_LIB_BN, 0, BN_R_ARG2_LT_ARG3), "ARG2_LT_ARG3"},
+ {ERR_PACK(ERR_LIB_BN, 0, BN_R_BAD_RECIPROCAL), "BAD_RECIPROCAL"},
+ {ERR_PACK(ERR_LIB_BN, 0, BN_R_BIGNUM_TOO_LONG), "BIGNUM_TOO_LONG"},
+ {ERR_PACK(ERR_LIB_BN, 0, BN_R_CALLED_WITH_EVEN_MODULUS), "CALLED_WITH_EVEN_MODULUS"},
+ {ERR_PACK(ERR_LIB_BN, 0, BN_R_DIV_BY_ZERO), "DIV_BY_ZERO"},
+ {ERR_PACK(ERR_LIB_BN, 0, BN_R_EXPAND_ON_STATIC_BIGNUM_DATA), "EXPAND_ON_STATIC_BIGNUM_DATA"},
+ {ERR_PACK(ERR_LIB_BN, 0, BN_R_INPUT_NOT_REDUCED), "INPUT_NOT_REDUCED"},
+ {ERR_PACK(ERR_LIB_BN, 0, BN_R_INVALID_RANGE), "INVALID_RANGE"},
+ {ERR_PACK(ERR_LIB_BN, 0, BN_R_NOT_A_SQUARE), "NOT_A_SQUARE"},
+ {ERR_PACK(ERR_LIB_BN, 0, BN_R_NOT_INITIALIZED), "NOT_INITIALIZED"},
+ {ERR_PACK(ERR_LIB_BN, 0, BN_R_NO_INVERSE), "NO_INVERSE"},
+ {ERR_PACK(ERR_LIB_BN, 0, BN_R_P_IS_NOT_PRIME), "P_IS_NOT_PRIME"},
+ {ERR_PACK(ERR_LIB_BN, 0, BN_R_TOO_MANY_ITERATIONS), "TOO_MANY_ITERATIONS"},
+ {ERR_PACK(ERR_LIB_BN, 0, BN_R_TOO_MANY_TEMPORARY_VARIABLES), "TOO_MANY_TEMPORARY_VARIABLES"},
+ {0, NULL},
+};
diff --git a/crypto/bn/bn_test.c b/crypto/bn/bn_test.c
new file mode 100644
index 0000000..1a89802
--- /dev/null
+++ b/crypto/bn/bn_test.c
@@ -0,0 +1,1152 @@
+/* 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.]
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the Eric Young open source
+ * license provided above.
+ *
+ * The binary polynomial arithmetic software is originally written by
+ * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems
+ * Laboratories. */
+
+#include <stdio.h>
+
+#include <openssl/bn.h>
+#include <openssl/err.h>
+#include <openssl/bio.h>
+
+#include "internal.h"
+
+static const int num0 = 100; /* number of tests */
+static const int num1 = 50; /* additional tests for some functions */
+static const int num2 = 5; /* number of tests for slow functions */
+
+int test_add(BIO *bp);
+int test_sub(BIO *bp);
+int test_lshift1(BIO *bp);
+int test_lshift(BIO *bp, BN_CTX *ctx, BIGNUM *a_);
+int test_rshift1(BIO *bp);
+int test_rshift(BIO *bp, BN_CTX *ctx);
+int test_sqr(BIO *bp, BN_CTX *ctx);
+int test_mul(BIO *bp);
+int test_div(BIO *bp, BN_CTX *ctx);
+int rand_neg(void);
+
+int test_div_word(BIO *bp);
+int test_mont(BIO *bp, BN_CTX *ctx);
+int test_mod(BIO *bp, BN_CTX *ctx);
+int test_mod_mul(BIO *bp, BN_CTX *ctx);
+int test_mod_exp(BIO *bp, BN_CTX *ctx);
+int test_mod_exp_mont_consttime(BIO *bp, BN_CTX *ctx);
+int test_exp(BIO *bp, BN_CTX *ctx);
+int test_mod_sqrt(BIO *bp, BN_CTX *ctx);
+#if 0
+int test_gf2m_add(BIO *bp);
+int test_gf2m_mod(BIO *bp);
+int test_gf2m_mod_mul(BIO *bp, BN_CTX *ctx);
+int test_gf2m_mod_sqr(BIO *bp, BN_CTX *ctx);
+int test_gf2m_mod_inv(BIO *bp, BN_CTX *ctx);
+int test_gf2m_mod_div(BIO *bp, BN_CTX *ctx);
+int test_gf2m_mod_exp(BIO *bp, BN_CTX *ctx);
+int test_gf2m_mod_sqrt(BIO *bp, BN_CTX *ctx);
+int test_gf2m_mod_solve_quad(BIO *bp, BN_CTX *ctx);
+#endif
+static int results = 0;
+
+static unsigned char lst[] =
+ "\xC6\x4F\x43\x04\x2A\xEA\xCA\x6E\x58\x36\x80\x5B\xE8\xC9"
+ "\x9B\x04\x5D\x48\x36\xC2\xFD\x16\xC9\x64\xF0";
+
+static void ERR_print_errors_fp(FILE *out) {
+}
+
+static void message(BIO *out, char *m) {
+ BIO_puts(out, "print \"test ");
+ BIO_puts(out, m);
+ BIO_puts(out, "\\n\"\n");
+}
+
+int main(int argc, char *argv[]) {
+ BN_CTX *ctx;
+ BIO *out = NULL;
+ char *outfile = NULL;
+
+ results = 0;
+
+ argc--;
+ argv++;
+ while (argc >= 1) {
+ if (strcmp(*argv, "-results") == 0)
+ results = 1;
+ else if (strcmp(*argv, "-out") == 0) {
+ if (--argc < 1)
+ break;
+ outfile = *(++argv);
+ }
+ argc--;
+ argv++;
+ }
+
+
+ ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return 1;
+
+ out = BIO_new(BIO_s_file());
+ if (out == NULL) {
+ return 1;
+ }
+
+ if (outfile == NULL) {
+ BIO_set_fp(out, stdout, BIO_NOCLOSE);
+ } else {
+ if (!BIO_write_filename(out, outfile)) {
+ perror(outfile);
+ return 1;
+ }
+ }
+
+ if (!results)
+ BIO_puts(out, "obase=16\nibase=16\n");
+
+ message(out, "BN_add");
+ if (!test_add(out))
+ goto err;
+ (void)BIO_flush(out);
+
+ message(out, "BN_sub");
+ if (!test_sub(out))
+ goto err;
+ (void)BIO_flush(out);
+
+ message(out, "BN_lshift1");
+ if (!test_lshift1(out))
+ goto err;
+ (void)BIO_flush(out);
+
+ message(out, "BN_lshift (fixed)");
+ if (!test_lshift(out, ctx, BN_bin2bn(lst, sizeof(lst) - 1, NULL)))
+ goto err;
+ (void)BIO_flush(out);
+
+ message(out, "BN_lshift");
+ if (!test_lshift(out, ctx, NULL))
+ goto err;
+ (void)BIO_flush(out);
+
+ message(out, "BN_rshift1");
+ if (!test_rshift1(out))
+ goto err;
+ (void)BIO_flush(out);
+
+ message(out, "BN_rshift");
+ if (!test_rshift(out, ctx))
+ goto err;
+ (void)BIO_flush(out);
+
+ message(out, "BN_sqr");
+ if (!test_sqr(out, ctx))
+ goto err;
+ (void)BIO_flush(out);
+
+ message(out, "BN_mul");
+ if (!test_mul(out))
+ goto err;
+ (void)BIO_flush(out);
+
+ message(out, "BN_div");
+ if (!test_div(out, ctx))
+ goto err;
+ (void)BIO_flush(out);
+
+ message(out, "BN_div_word");
+ if (!test_div_word(out))
+ goto err;
+ (void)BIO_flush(out);
+
+ message(out, "BN_mod");
+ if (!test_mod(out, ctx))
+ goto err;
+ (void)BIO_flush(out);
+
+ message(out, "BN_mod_mul");
+ if (!test_mod_mul(out, ctx))
+ goto err;
+ (void)BIO_flush(out);
+
+ message(out, "BN_mont");
+ if (!test_mont(out, ctx))
+ goto err;
+ (void)BIO_flush(out);
+
+ message(out, "BN_mod_exp");
+ if (!test_mod_exp(out, ctx))
+ goto err;
+ (void)BIO_flush(out);
+
+ message(out, "BN_mod_exp_mont_consttime");
+ if (!test_mod_exp_mont_consttime(out, ctx))
+ goto err;
+ (void)BIO_flush(out);
+
+ message(out, "BN_exp");
+ if (!test_exp(out, ctx))
+ goto err;
+ (void)BIO_flush(out);
+
+ message(out, "BN_mod_sqrt");
+ if (!test_mod_sqrt(out, ctx))
+ goto err;
+ (void)BIO_flush(out);
+
+ BN_CTX_free(ctx);
+ BIO_free(out);
+
+ printf("PASS\n");
+ return 0;
+
+err:
+ BIO_puts(out, "1\n"); /* make sure the Perl script fed by bc notices
+ * the failure, see test_bn in test/Makefile.ssl*/
+ (void)BIO_flush(out);
+
+ return 1;
+}
+
+int test_add(BIO *bp) {
+ BIGNUM a, b, c;
+ int i;
+
+ BN_init(&a);
+ BN_init(&b);
+ BN_init(&c);
+
+ BN_rand(&a, 512, 0, 0);
+ for (i = 0; i < num0; i++) {
+ BN_rand(&b, 450 + i, 0, 0);
+ a.neg = rand_neg();
+ b.neg = rand_neg();
+ BN_add(&c, &a, &b);
+ if (bp != NULL) {
+ if (!results) {
+ BN_print(bp, &a);
+ BIO_puts(bp, " + ");
+ BN_print(bp, &b);
+ BIO_puts(bp, " - ");
+ }
+ BN_print(bp, &c);
+ BIO_puts(bp, "\n");
+ }
+ a.neg = !a.neg;
+ b.neg = !b.neg;
+ BN_add(&c, &c, &b);
+ BN_add(&c, &c, &a);
+ if (!BN_is_zero(&c)) {
+ fprintf(stderr, "Add test failed!\n");
+ return 0;
+ }
+ }
+ BN_free(&a);
+ BN_free(&b);
+ BN_free(&c);
+ return (1);
+}
+
+int test_sub(BIO *bp) {
+ BIGNUM a, b, c;
+ int i;
+
+ BN_init(&a);
+ BN_init(&b);
+ BN_init(&c);
+
+ for (i = 0; i < num0 + num1; i++) {
+ if (i < num1) {
+ BN_rand(&a, 512, 0, 0);
+ BN_copy(&b, &a);
+ if (BN_set_bit(&a, i) == 0)
+ return (0);
+ BN_add_word(&b, i);
+ } else {
+ BN_rand(&b, 400 + i - num1, 0, 0);
+ a.neg = rand_neg();
+ b.neg = rand_neg();
+ }
+ BN_sub(&c, &a, &b);
+ if (bp != NULL) {
+ if (!results) {
+ BN_print(bp, &a);
+ BIO_puts(bp, " - ");
+ BN_print(bp, &b);
+ BIO_puts(bp, " - ");
+ }
+ BN_print(bp, &c);
+ BIO_puts(bp, "\n");
+ }
+ BN_add(&c, &c, &b);
+ BN_sub(&c, &c, &a);
+ if (!BN_is_zero(&c)) {
+ fprintf(stderr, "Subtract test failed!\n");
+ return 0;
+ }
+ }
+ BN_free(&a);
+ BN_free(&b);
+ BN_free(&c);
+ return (1);
+}
+
+int test_div(BIO *bp, BN_CTX *ctx) {
+ BIGNUM a, b, c, d, e;
+ int i;
+
+ BN_init(&a);
+ BN_init(&b);
+ BN_init(&c);
+ BN_init(&d);
+ BN_init(&e);
+
+ for (i = 0; i < num0 + num1; i++) {
+ if (i < num1) {
+ BN_rand(&a, 400, 0, 0);
+ BN_copy(&b, &a);
+ BN_lshift(&a, &a, i);
+ BN_add_word(&a, i);
+ } else
+ BN_rand(&b, 50 + 3 * (i - num1), 0, 0);
+ a.neg = rand_neg();
+ b.neg = rand_neg();
+ BN_div(&d, &c, &a, &b, ctx);
+ if (bp != NULL) {
+ if (!results) {
+ BN_print(bp, &a);
+ BIO_puts(bp, " / ");
+ BN_print(bp, &b);
+ BIO_puts(bp, " - ");
+ }
+ BN_print(bp, &d);
+ BIO_puts(bp, "\n");
+
+ if (!results) {
+ BN_print(bp, &a);
+ BIO_puts(bp, " % ");
+ BN_print(bp, &b);
+ BIO_puts(bp, " - ");
+ }
+ BN_print(bp, &c);
+ BIO_puts(bp, "\n");
+ }
+ BN_mul(&e, &d, &b, ctx);
+ BN_add(&d, &e, &c);
+ BN_sub(&d, &d, &a);
+ if (!BN_is_zero(&d)) {
+ fprintf(stderr, "Division test failed!\n");
+ return 0;
+ }
+ }
+ BN_free(&a);
+ BN_free(&b);
+ BN_free(&c);
+ BN_free(&d);
+ BN_free(&e);
+ return (1);
+}
+
+int test_lshift1(BIO *bp) {
+ BIGNUM *a, *b, *c;
+ int i;
+
+ a = BN_new();
+ b = BN_new();
+ c = BN_new();
+
+ BN_rand(a, 200, 0, 0); /**/
+ a->neg = rand_neg();
+ for (i = 0; i < num0; i++) {
+ BN_lshift1(b, a);
+ if (bp != NULL) {
+ if (!results) {
+ BN_print(bp, a);
+ BIO_puts(bp, " * 2");
+ BIO_puts(bp, " - ");
+ }
+ BN_print(bp, b);
+ BIO_puts(bp, "\n");
+ }
+ BN_add(c, a, a);
+ BN_sub(a, b, c);
+ if (!BN_is_zero(a)) {
+ fprintf(stderr, "Left shift one test failed!\n");
+ return 0;
+ }
+
+ BN_copy(a, b);
+ }
+ BN_free(a);
+ BN_free(b);
+ BN_free(c);
+ return (1);
+}
+
+int test_rshift(BIO *bp, BN_CTX *ctx) {
+ BIGNUM *a, *b, *c, *d, *e;
+ int i;
+
+ a = BN_new();
+ b = BN_new();
+ c = BN_new();
+ d = BN_new();
+ e = BN_new();
+ BN_one(c);
+
+ BN_rand(a, 200, 0, 0); /**/
+ a->neg = rand_neg();
+ for (i = 0; i < num0; i++) {
+ BN_rshift(b, a, i + 1);
+ BN_add(c, c, c);
+ if (bp != NULL) {
+ if (!results) {
+ BN_print(bp, a);
+ BIO_puts(bp, " / ");
+ BN_print(bp, c);
+ BIO_puts(bp, " - ");
+ }
+ BN_print(bp, b);
+ BIO_puts(bp, "\n");
+ }
+ BN_div(d, e, a, c, ctx);
+ BN_sub(d, d, b);
+ if (!BN_is_zero(d)) {
+ fprintf(stderr, "Right shift test failed!\n");
+ return 0;
+ }
+ }
+ BN_free(a);
+ BN_free(b);
+ BN_free(c);
+ BN_free(d);
+ BN_free(e);
+ return (1);
+}
+
+int test_rshift1(BIO *bp) {
+ BIGNUM *a, *b, *c;
+ int i;
+
+ a = BN_new();
+ b = BN_new();
+ c = BN_new();
+
+ BN_rand(a, 200, 0, 0); /**/
+ a->neg = rand_neg();
+ for (i = 0; i < num0; i++) {
+ BN_rshift1(b, a);
+ if (bp != NULL) {
+ if (!results) {
+ BN_print(bp, a);
+ BIO_puts(bp, " / 2");
+ BIO_puts(bp, " - ");
+ }
+ BN_print(bp, b);
+ BIO_puts(bp, "\n");
+ }
+ BN_sub(c, a, b);
+ BN_sub(c, c, b);
+ if (!BN_is_zero(c) && !BN_abs_is_word(c, 1)) {
+ fprintf(stderr, "Right shift one test failed!\n");
+ return 0;
+ }
+ BN_copy(a, b);
+ }
+ BN_free(a);
+ BN_free(b);
+ BN_free(c);
+ return (1);
+}
+
+int test_lshift(BIO *bp, BN_CTX *ctx, BIGNUM *a_) {
+ BIGNUM *a, *b, *c, *d;
+ int i;
+
+ b = BN_new();
+ c = BN_new();
+ d = BN_new();
+ BN_one(c);
+
+ if (a_)
+ a = a_;
+ else {
+ a = BN_new();
+ BN_rand(a, 200, 0, 0); /**/
+ a->neg = rand_neg();
+ }
+ for (i = 0; i < num0; i++) {
+ BN_lshift(b, a, i + 1);
+ BN_add(c, c, c);
+ if (bp != NULL) {
+ if (!results) {
+ BN_print(bp, a);
+ BIO_puts(bp, " * ");
+ BN_print(bp, c);
+ BIO_puts(bp, " - ");
+ }
+ BN_print(bp, b);
+ BIO_puts(bp, "\n");
+ }
+ BN_mul(d, a, c, ctx);
+ BN_sub(d, d, b);
+ if (!BN_is_zero(d)) {
+ fprintf(stderr, "Left shift test failed!\n");
+ fprintf(stderr, "a=");
+ BN_print_fp(stderr, a);
+ fprintf(stderr, "\nb=");
+ BN_print_fp(stderr, b);
+ fprintf(stderr, "\nc=");
+ BN_print_fp(stderr, c);
+ fprintf(stderr, "\nd=");
+ BN_print_fp(stderr, d);
+ fprintf(stderr, "\n");
+ return 0;
+ }
+ }
+ BN_free(a);
+ BN_free(b);
+ BN_free(c);
+ BN_free(d);
+ return (1);
+}
+
+int test_mul(BIO *bp) {
+ BIGNUM a, b, c, d, e;
+ int i;
+ BN_CTX *ctx;
+
+ ctx = BN_CTX_new();
+ if (ctx == NULL)
+ abort();
+
+ BN_init(&a);
+ BN_init(&b);
+ BN_init(&c);
+ BN_init(&d);
+ BN_init(&e);
+
+ for (i = 0; i < num0 + num1; i++) {
+ if (i <= num1) {
+ BN_rand(&a, 100, 0, 0);
+ BN_rand(&b, 100, 0, 0);
+ } else
+ BN_rand(&b, i - num1, 0, 0);
+ a.neg = rand_neg();
+ b.neg = rand_neg();
+ BN_mul(&c, &a, &b, ctx);
+ if (bp != NULL) {
+ if (!results) {
+ BN_print(bp, &a);
+ BIO_puts(bp, " * ");
+ BN_print(bp, &b);
+ BIO_puts(bp, " - ");
+ }
+ BN_print(bp, &c);
+ BIO_puts(bp, "\n");
+ }
+ BN_div(&d, &e, &c, &a, ctx);
+ BN_sub(&d, &d, &b);
+ if (!BN_is_zero(&d) || !BN_is_zero(&e)) {
+ fprintf(stderr, "Multiplication test failed!\n");
+ return 0;
+ }
+ }
+ BN_free(&a);
+ BN_free(&b);
+ BN_free(&c);
+ BN_free(&d);
+ BN_free(&e);
+ BN_CTX_free(ctx);
+ return (1);
+}
+
+int test_sqr(BIO *bp, BN_CTX *ctx) {
+ BIGNUM a, c, d, e;
+ int i;
+
+ BN_init(&a);
+ BN_init(&c);
+ BN_init(&d);
+ BN_init(&e);
+
+ for (i = 0; i < num0; i++) {
+ BN_rand(&a, 40 + i * 10, 0, 0);
+ a.neg = rand_neg();
+ BN_sqr(&c, &a, ctx);
+ if (bp != NULL) {
+ if (!results) {
+ BN_print(bp, &a);
+ BIO_puts(bp, " * ");
+ BN_print(bp, &a);
+ BIO_puts(bp, " - ");
+ }
+ BN_print(bp, &c);
+ BIO_puts(bp, "\n");
+ }
+ BN_div(&d, &e, &c, &a, ctx);
+ BN_sub(&d, &d, &a);
+ if (!BN_is_zero(&d) || !BN_is_zero(&e)) {
+ fprintf(stderr, "Square test failed!\n");
+ return 0;
+ }
+ }
+ BN_free(&a);
+ BN_free(&c);
+ BN_free(&d);
+ BN_free(&e);
+ return (1);
+}
+
+
+int rand_neg(void) {
+ static unsigned int neg = 0;
+ static int sign[8] = {0, 0, 0, 1, 1, 0, 1, 1};
+
+ return (sign[(neg++) % 8]);
+}
+
+static void print_word(BIO *bp, BN_ULONG w) {
+#ifdef OPENSSL_64_BIT
+ if (sizeof(w) > sizeof(unsigned long)) {
+ unsigned long h = (unsigned long)(w >> 32), l = (unsigned long)(w);
+
+ if (h)
+ BIO_printf(bp, "%lX%08lX", h, l);
+ else
+ BIO_printf(bp, "%lX", l);
+ return;
+ }
+#endif
+ BIO_printf(bp, BN_HEX_FMT1, w);
+}
+
+int test_div_word(BIO *bp) {
+ BIGNUM a, b;
+ BN_ULONG r, s;
+ int i;
+
+ BN_init(&a);
+ BN_init(&b);
+
+ for (i = 0; i < num0; i++) {
+ do {
+ BN_rand(&a, 512, -1, 0);
+ BN_rand(&b, BN_BITS2, -1, 0);
+ s = b.d[0];
+ } while (!s);
+
+ BN_copy(&b, &a);
+ r = BN_div_word(&b, s);
+
+ if (bp != NULL) {
+ if (!results) {
+ BN_print(bp, &a);
+ BIO_puts(bp, " / ");
+ print_word(bp, s);
+ BIO_puts(bp, " - ");
+ }
+ BN_print(bp, &b);
+ BIO_puts(bp, "\n");
+
+ if (!results) {
+ BN_print(bp, &a);
+ BIO_puts(bp, " % ");
+ print_word(bp, s);
+ BIO_puts(bp, " - ");
+ }
+ print_word(bp, r);
+ BIO_puts(bp, "\n");
+ }
+ BN_mul_word(&b, s);
+ BN_add_word(&b, r);
+ BN_sub(&b, &a, &b);
+ if (!BN_is_zero(&b)) {
+ fprintf(stderr, "Division (word) test failed!\n");
+ return 0;
+ }
+ }
+ BN_free(&a);
+ BN_free(&b);
+ return (1);
+}
+
+int test_mont(BIO *bp, BN_CTX *ctx) {
+ BIGNUM a, b, c, d, A, B;
+ BIGNUM n;
+ int i;
+ BN_MONT_CTX *mont;
+
+ BN_init(&a);
+ BN_init(&b);
+ BN_init(&c);
+ BN_init(&d);
+ BN_init(&A);
+ BN_init(&B);
+ BN_init(&n);
+
+ mont = BN_MONT_CTX_new();
+ if (mont == NULL)
+ return 0;
+
+ BN_rand(&a, 100, 0, 0); /**/
+ BN_rand(&b, 100, 0, 0); /**/
+ for (i = 0; i < num2; i++) {
+ int bits = (200 * (i + 1)) / num2;
+
+ if (bits == 0)
+ continue;
+ BN_rand(&n, bits, 0, 1);
+ BN_MONT_CTX_set(mont, &n, ctx);
+
+ BN_nnmod(&a, &a, &n, ctx);
+ BN_nnmod(&b, &b, &n, ctx);
+
+ BN_to_montgomery(&A, &a, mont, ctx);
+ BN_to_montgomery(&B, &b, mont, ctx);
+
+ BN_mod_mul_montgomery(&c, &A, &B, mont, ctx); /**/
+ BN_from_montgomery(&A, &c, mont, ctx); /**/
+ if (bp != NULL) {
+ if (!results) {
+#ifdef undef
+ fprintf(stderr, "%d * %d %% %d\n", BN_num_bits(&a), BN_num_bits(&b),
+ BN_num_bits(mont->N));
+#endif
+ BN_print(bp, &a);
+ BIO_puts(bp, " * ");
+ BN_print(bp, &b);
+ BIO_puts(bp, " % ");
+ BN_print(bp, &(mont->N));
+ BIO_puts(bp, " - ");
+ }
+ BN_print(bp, &A);
+ BIO_puts(bp, "\n");
+ }
+ BN_mod_mul(&d, &a, &b, &n, ctx);
+ BN_sub(&d, &d, &A);
+ if (!BN_is_zero(&d)) {
+ fprintf(stderr, "Montgomery multiplication test failed!\n");
+ return 0;
+ }
+ }
+ BN_MONT_CTX_free(mont);
+ BN_free(&a);
+ BN_free(&b);
+ BN_free(&c);
+ BN_free(&d);
+ BN_free(&A);
+ BN_free(&B);
+ BN_free(&n);
+ return (1);
+}
+
+int test_mod(BIO *bp, BN_CTX *ctx) {
+ BIGNUM *a, *b, *c, *d, *e;
+ int i;
+
+ a = BN_new();
+ b = BN_new();
+ c = BN_new();
+ d = BN_new();
+ e = BN_new();
+
+ BN_rand(a, 1024, 0, 0); /**/
+ for (i = 0; i < num0; i++) {
+ BN_rand(b, 450 + i * 10, 0, 0); /**/
+ a->neg = rand_neg();
+ b->neg = rand_neg();
+ BN_mod(c, a, b, ctx); /**/
+ if (bp != NULL) {
+ if (!results) {
+ BN_print(bp, a);
+ BIO_puts(bp, " % ");
+ BN_print(bp, b);
+ BIO_puts(bp, " - ");
+ }
+ BN_print(bp, c);
+ BIO_puts(bp, "\n");
+ }
+ BN_div(d, e, a, b, ctx);
+ BN_sub(e, e, c);
+ if (!BN_is_zero(e)) {
+ fprintf(stderr, "Modulo test failed!\n");
+ return 0;
+ }
+ }
+ BN_free(a);
+ BN_free(b);
+ BN_free(c);
+ BN_free(d);
+ BN_free(e);
+ return (1);
+}
+
+int test_mod_mul(BIO *bp, BN_CTX *ctx) {
+ BIGNUM *a, *b, *c, *d, *e;
+ int i, j;
+
+ a = BN_new();
+ b = BN_new();
+ c = BN_new();
+ d = BN_new();
+ e = BN_new();
+
+ for (j = 0; j < 3; j++) {
+ BN_rand(c, 1024, 0, 0); /**/
+ for (i = 0; i < num0; i++) {
+ BN_rand(a, 475 + i * 10, 0, 0); /**/
+ BN_rand(b, 425 + i * 11, 0, 0); /**/
+ a->neg = rand_neg();
+ b->neg = rand_neg();
+ if (!BN_mod_mul(e, a, b, c, ctx)) {
+ unsigned long l;
+
+ while ((l = ERR_get_error()))
+ fprintf(stderr, "ERROR:%s\n", ERR_error_string(l, NULL));
+ abort();
+ }
+ if (bp != NULL) {
+ if (!results) {
+ BN_print(bp, a);
+ BIO_puts(bp, " * ");
+ BN_print(bp, b);
+ BIO_puts(bp, " % ");
+ BN_print(bp, c);
+ if ((a->neg ^ b->neg) && !BN_is_zero(e)) {
+ /* If (a*b) % c is negative, c must be added
+ * in order to obtain the normalized remainder
+ * (new with OpenSSL 0.9.7, previous versions of
+ * BN_mod_mul could generate negative results)
+ */
+ BIO_puts(bp, " + ");
+ BN_print(bp, c);
+ }
+ BIO_puts(bp, " - ");
+ }
+ BN_print(bp, e);
+ BIO_puts(bp, "\n");
+ }
+ BN_mul(d, a, b, ctx);
+ BN_sub(d, d, e);
+ BN_div(a, b, d, c, ctx);
+ if (!BN_is_zero(b)) {
+ fprintf(stderr, "Modulo multiply test failed!\n");
+ ERR_print_errors_fp(stderr);
+ return 0;
+ }
+ }
+ }
+ BN_free(a);
+ BN_free(b);
+ BN_free(c);
+ BN_free(d);
+ BN_free(e);
+ return (1);
+}
+
+int test_mod_exp(BIO *bp, BN_CTX *ctx) {
+ BIGNUM *a, *b, *c, *d, *e;
+ int i;
+
+ a = BN_new();
+ b = BN_new();
+ c = BN_new();
+ d = BN_new();
+ e = BN_new();
+
+ BN_rand(c, 30, 0, 1); /* must be odd for montgomery */
+ for (i = 0; i < num2; i++) {
+ BN_rand(a, 20 + i * 5, 0, 0); /**/
+ BN_rand(b, 2 + i, 0, 0); /**/
+
+ if (!BN_mod_exp(d, a, b, c, ctx))
+ return (0);
+
+ if (bp != NULL) {
+ if (!results) {
+ BN_print(bp, a);
+ BIO_puts(bp, " ^ ");
+ BN_print(bp, b);
+ BIO_puts(bp, " % ");
+ BN_print(bp, c);
+ BIO_puts(bp, " - ");
+ }
+ BN_print(bp, d);
+ BIO_puts(bp, "\n");
+ }
+ BN_exp(e, a, b, ctx);
+ BN_sub(e, e, d);
+ BN_div(a, b, e, c, ctx);
+ if (!BN_is_zero(b)) {
+ fprintf(stderr, "Modulo exponentiation test failed!\n");
+ return 0;
+ }
+ }
+ BN_free(a);
+ BN_free(b);
+ BN_free(c);
+ BN_free(d);
+ BN_free(e);
+ return (1);
+}
+
+int test_mod_exp_mont_consttime(BIO *bp, BN_CTX *ctx) {
+ BIGNUM *a, *b, *c, *d, *e;
+ int i;
+
+ a = BN_new();
+ b = BN_new();
+ c = BN_new();
+ d = BN_new();
+ e = BN_new();
+
+ BN_rand(c, 30, 0, 1); /* must be odd for montgomery */
+ for (i = 0; i < num2; i++) {
+ BN_rand(a, 20 + i * 5, 0, 0); /**/
+ BN_rand(b, 2 + i, 0, 0); /**/
+
+ if (!BN_mod_exp_mont_consttime(d, a, b, c, ctx, NULL))
+ return (00);
+
+ if (bp != NULL) {
+ if (!results) {
+ BN_print(bp, a);
+ BIO_puts(bp, " ^ ");
+ BN_print(bp, b);
+ BIO_puts(bp, " % ");
+ BN_print(bp, c);
+ BIO_puts(bp, " - ");
+ }
+ BN_print(bp, d);
+ BIO_puts(bp, "\n");
+ }
+ BN_exp(e, a, b, ctx);
+ BN_sub(e, e, d);
+ BN_div(a, b, e, c, ctx);
+ if (!BN_is_zero(b)) {
+ fprintf(stderr, "Modulo exponentiation test failed!\n");
+ return 0;
+ }
+ }
+ BN_free(a);
+ BN_free(b);
+ BN_free(c);
+ BN_free(d);
+ BN_free(e);
+ return (1);
+}
+
+int test_exp(BIO *bp, BN_CTX *ctx) {
+ BIGNUM *a, *b, *d, *e, *one;
+ int i;
+
+ a = BN_new();
+ b = BN_new();
+ d = BN_new();
+ e = BN_new();
+ one = BN_new();
+ BN_one(one);
+
+ for (i = 0; i < num2; i++) {
+ BN_rand(a, 20 + i * 5, 0, 0); /**/
+ BN_rand(b, 2 + i, 0, 0); /**/
+
+ if (BN_exp(d, a, b, ctx) <= 0)
+ return (0);
+
+ if (bp != NULL) {
+ if (!results) {
+ BN_print(bp, a);
+ BIO_puts(bp, " ^ ");
+ BN_print(bp, b);
+ BIO_puts(bp, " - ");
+ }
+ BN_print(bp, d);
+ BIO_puts(bp, "\n");
+ }
+ BN_one(e);
+ for (; !BN_is_zero(b); BN_sub(b, b, one))
+ BN_mul(e, e, a, ctx);
+ BN_sub(e, e, d);
+ if (!BN_is_zero(e)) {
+ fprintf(stderr, "Exponentiation test failed!\n");
+ return 0;
+ }
+ }
+ BN_free(a);
+ BN_free(b);
+ BN_free(d);
+ BN_free(e);
+ BN_free(one);
+ return (1);
+}
+
+static int genprime_cb(int p, int n, BN_GENCB *arg) {
+ char c = '*';
+
+ if (p == 0)
+ c = '.';
+ if (p == 1)
+ c = '+';
+ if (p == 2)
+ c = '*';
+ if (p == 3)
+ c = '\n';
+ putc(c, stdout);
+ fflush(stdout);
+ return 1;
+}
+
+int test_mod_sqrt(BIO *bp, BN_CTX *ctx) {
+ BN_GENCB cb;
+ BIGNUM *a, *p, *r;
+ int i, j;
+ int ret = 0;
+
+ a = BN_new();
+ p = BN_new();
+ r = BN_new();
+ if (a == NULL || p == NULL || r == NULL)
+ goto err;
+
+ BN_GENCB_set(&cb, genprime_cb, NULL);
+
+ for (i = 0; i < 16; i++) {
+ if (i < 8) {
+ unsigned primes[8] = {2, 3, 5, 7, 11, 13, 17, 19};
+
+ if (!BN_set_word(p, primes[i]))
+ goto err;
+ } else {
+ if (!BN_set_word(a, 32))
+ goto err;
+ if (!BN_set_word(r, 2 * i + 1))
+ goto err;
+
+ if (!BN_generate_prime_ex(p, 256, 0, a, r, &cb))
+ goto err;
+ putc('\n', stdout);
+ }
+ p->neg = rand_neg();
+
+ for (j = 0; j < num2; j++) {
+ /* construct 'a' such that it is a square modulo p,
+ * but in general not a proper square and not reduced modulo p */
+ if (!BN_rand(r, 256, 0, 3))
+ goto err;
+ if (!BN_nnmod(r, r, p, ctx))
+ goto err;
+ if (!BN_mod_sqr(r, r, p, ctx))
+ goto err;
+ if (!BN_rand(a, 256, 0, 3))
+ goto err;
+ if (!BN_nnmod(a, a, p, ctx))
+ goto err;
+ if (!BN_mod_sqr(a, a, p, ctx))
+ goto err;
+ if (!BN_mul(a, a, r, ctx))
+ goto err;
+ if (rand_neg())
+ if (!BN_sub(a, a, p))
+ goto err;
+
+ if (!BN_mod_sqrt(r, a, p, ctx))
+ goto err;
+ if (!BN_mod_sqr(r, r, p, ctx))
+ goto err;
+
+ if (!BN_nnmod(a, a, p, ctx))
+ goto err;
+
+ if (BN_cmp(a, r) != 0) {
+ fprintf(stderr, "BN_mod_sqrt failed: a = ");
+ BN_print_fp(stderr, a);
+ fprintf(stderr, ", r = ");
+ BN_print_fp(stderr, r);
+ fprintf(stderr, ", p = ");
+ BN_print_fp(stderr, p);
+ fprintf(stderr, "\n");
+ goto err;
+ }
+
+ putc('.', stdout);
+ fflush(stdout);
+ }
+
+ putc('\n', stdout);
+ fflush(stderr);
+ }
+ ret = 1;
+err:
+ if (a != NULL)
+ BN_free(a);
+ if (p != NULL)
+ BN_free(p);
+ if (r != NULL)
+ BN_free(r);
+ return ret;
+}
diff --git a/crypto/bn/cmp.c b/crypto/bn/cmp.c
new file mode 100644
index 0000000..fce7233
--- /dev/null
+++ b/crypto/bn/cmp.c
@@ -0,0 +1,200 @@
+/* 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/bn.h>
+
+#include "internal.h"
+
+
+int BN_ucmp(const BIGNUM *a, const BIGNUM *b) {
+ int i;
+ BN_ULONG t1, t2, *ap, *bp;
+
+ i = a->top - b->top;
+ if (i != 0) {
+ return i;
+ }
+
+ ap = a->d;
+ bp = b->d;
+ for (i = a->top - 1; i >= 0; i--) {
+ t1 = ap[i];
+ t2 = bp[i];
+ if (t1 != t2) {
+ return (t1 > t2) ? 1 : -1;
+ }
+ }
+
+ return 0;
+}
+
+int BN_cmp(const BIGNUM *a, const BIGNUM *b) {
+ int i;
+ int gt, lt;
+ BN_ULONG t1, t2;
+
+ if ((a == NULL) || (b == NULL)) {
+ if (a != NULL) {
+ return -1;
+ } else if (b != NULL) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ if (a->neg != b->neg) {
+ if (a->neg) {
+ return -1;
+ }
+ return 1;
+ }
+ if (a->neg == 0) {
+ gt = 1;
+ lt = -1;
+ } else {
+ gt = -1;
+ lt = 1;
+ }
+
+ if (a->top > b->top) {
+ return gt;
+ }
+ if (a->top < b->top) {
+ return lt;
+ }
+
+ for (i = a->top - 1; i >= 0; i--) {
+ t1 = a->d[i];
+ t2 = b->d[i];
+ if (t1 > t2) {
+ return gt;
+ } if (t1 < t2) {
+ return lt;
+ }
+ }
+
+ return 0;
+}
+
+int bn_cmp_words(const BN_ULONG *a, const BN_ULONG *b, int n) {
+ int i;
+ BN_ULONG aa, bb;
+
+ aa = a[n - 1];
+ bb = b[n - 1];
+ if (aa != bb) {
+ return (aa > bb) ? 1 : -1;
+ }
+
+ for (i = n - 2; i >= 0; i--) {
+ aa = a[i];
+ bb = b[i];
+ if (aa != bb) {
+ return (aa > bb) ? 1 : -1;
+ }
+ }
+ return 0;
+}
+
+int bn_cmp_part_words(const BN_ULONG *a, const BN_ULONG *b, int cl, int dl) {
+ int n, i;
+ n = cl - 1;
+
+ if (dl < 0) {
+ for (i = dl; i < 0; i++) {
+ if (b[n - i] != 0) {
+ return -1; /* a < b */
+ }
+ }
+ }
+ if (dl > 0) {
+ for (i = dl; i > 0; i--) {
+ if (a[n + i] != 0) {
+ return 1; /* a > b */
+ }
+ }
+ }
+
+ return bn_cmp_words(a, b, cl);
+}
+
+int BN_abs_is_word(const BIGNUM *bn, BN_ULONG w) {
+ switch (bn->top) {
+ case 1:
+ return bn->d[0] == w;
+ case 0:
+ return w == 0;
+ default:
+ return 0;
+ }
+}
+
+int BN_is_zero(const BIGNUM *bn) {
+ return bn->top == 0;
+}
+
+int BN_is_one(const BIGNUM *bn) {
+ return bn->neg == 0 && BN_abs_is_word(bn, 1);
+}
+
+int BN_is_word(const BIGNUM *bn, BN_ULONG w) {
+ return BN_abs_is_word(bn, w) && (w == 0 || bn->neg == 0);
+}
+
+int BN_is_odd(const BIGNUM *bn) {
+ return bn->top > 0 && (bn->d[0] & 1) == 1;
+}
diff --git a/crypto/bn/convert.c b/crypto/bn/convert.c
new file mode 100644
index 0000000..c6b391a
--- /dev/null
+++ b/crypto/bn/convert.c
@@ -0,0 +1,439 @@
+/* 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/bn.h>
+
+#include <ctype.h>
+#include <stdio.h>
+
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+#include "internal.h"
+
+BIGNUM *BN_bin2bn(const uint8_t *in, size_t len, BIGNUM *ret) {
+ unsigned num_words, m;
+ BN_ULONG word = 0;
+ BIGNUM *bn = NULL;
+
+ if (ret == NULL) {
+ ret = bn = BN_new();
+ }
+
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ if (len == 0) {
+ ret->top = 0;
+ return ret;
+ }
+
+ num_words = ((len - 1) / BN_BYTES) + 1;
+ m = (len - 1) % BN_BYTES;
+ if (bn_wexpand(ret, num_words) == NULL) {
+ if (bn) {
+ BN_free(bn);
+ }
+ return NULL;
+ }
+
+ ret->top = num_words;
+ ret->neg = 0;
+
+ while (len--) {
+ word = (word << 8) | *(in++);
+ if (m-- == 0) {
+ ret->d[--num_words] = word;
+ word = 0;
+ m = BN_BYTES - 1;
+ }
+ }
+
+ /* need to call this due to clear byte at top if avoiding having the top bit
+ * set (-ve number) */
+ bn_correct_top(ret);
+ return ret;
+}
+
+size_t BN_bn2bin(const BIGNUM *in, uint8_t *out) {
+ size_t n, i;
+ BN_ULONG l;
+
+ n = i = BN_num_bytes(in);
+ while (i--) {
+ l = in->d[i / BN_BYTES];
+ *(out++) = (unsigned char)(l >> (8 * (i % BN_BYTES))) & 0xff;
+ }
+ return n;
+}
+
+static const char hextable[] = "0123456789abcdef";
+
+char *BN_bn2hex(const BIGNUM *bn) {
+ int i, j, v, z = 0;
+ char *buf;
+ char *p;
+
+ buf = (char *)OPENSSL_malloc(bn->top * BN_BYTES * 2 + 2);
+ if (buf == NULL) {
+ OPENSSL_PUT_ERROR(BN, BN_bn2hex, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ p = buf;
+ if (bn->neg) {
+ *(p++) = '-';
+ }
+
+ if (BN_is_zero(bn)) {
+ *(p++) = '0';
+ }
+
+ for (i = bn->top - 1; i >= 0; i--) {
+ for (j = BN_BITS2 - 8; j >= 0; j -= 8) {
+ /* strip leading zeros */
+ v = ((int)(bn->d[i] >> (long)j)) & 0xff;
+ if (z || v != 0) {
+ *(p++) = hextable[v >> 4];
+ *(p++) = hextable[v & 0x0f];
+ z = 1;
+ }
+ }
+ }
+ *p = '\0';
+
+ 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' */
+ m = 0;
+ 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);
+ }
+
+ bn->top = h;
+}
+
+/* decode_dec decodes |i| bytes of decimal data from |in| and updates |bn|. */
+static void decode_dec(BIGNUM *bn, const char *in, int i) {
+ int j;
+ BN_ULONG l = 0;
+
+ j = BN_DEC_NUM - (i % BN_DEC_NUM);
+ if (j == BN_DEC_NUM) {
+ j = 0;
+ }
+ l = 0;
+ while (*in) {
+ l *= 10;
+ l += *in - '0';
+ in++;
+ if (++j == BN_DEC_NUM) {
+ BN_mul_word(bn, BN_DEC_CONV);
+ BN_add_word(bn, l);
+ l = 0;
+ j = 0;
+ }
+ }
+}
+
+typedef void (*decode_func) (BIGNUM *bn, const char *in, int i);
+typedef int (*char_test_func) (int c);
+
+static int bn_x2bn(BIGNUM **outp, const char *in, decode_func decode, char_test_func want_char) {
+ BIGNUM *ret = NULL;
+ int neg = 0, i;
+ int num;
+
+ if (in == NULL || *in == 0) {
+ return 0;
+ }
+
+ if (*in == '-') {
+ neg = 1;
+ in++;
+ }
+
+ for (i = 0; want_char((unsigned char)in[i]); i++) {}
+
+ num = i + neg;
+ if (outp == NULL) {
+ return num;
+ }
+
+ /* in is the start of the hex digits, and it is 'i' long */
+ if (*outp == NULL) {
+ ret = BN_new();
+ if (ret == NULL) {
+ return 0;
+ }
+ } else {
+ ret = *outp;
+ BN_zero(ret);
+ }
+ ret->neg = neg;
+
+ /* i is the number of hex digests; */
+ if (bn_expand(ret, i * 4) == NULL) {
+ goto err;
+ }
+
+ decode(ret, in, i);
+
+ bn_correct_top(ret);
+
+ *outp = ret;
+ return num;
+
+err:
+ if (*outp == NULL) {
+ BN_free(ret);
+ }
+
+ return 0;
+}
+
+int BN_hex2bn(BIGNUM **outp, const char *in) {
+ return bn_x2bn(outp, in, decode_hex, isxdigit);
+}
+
+char *BN_bn2dec(const BIGNUM *a) {
+ int i = 0, num, ok = 0;
+ char *buf = NULL;
+ char *p;
+ BIGNUM *t = NULL;
+ BN_ULONG *bn_data = NULL, *lp;
+
+ /* get an upper bound for the length of the decimal integer
+ * num <= (BN_num_bits(a) + 1) * log(2)
+ * <= 3 * BN_num_bits(a) * 0.1001 + log(2) + 1 (rounding error)
+ * <= BN_num_bits(a)/10 + BN_num_bits/1000 + 1 + 1
+ */
+ i = BN_num_bits(a) * 3;
+ num = i / 10 + i / 1000 + 1 + 1;
+ bn_data =
+ (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);
+ goto err;
+ }
+ t = BN_dup(a);
+ if (t == NULL) {
+ goto err;
+ }
+
+#define BUF_REMAIN (num + 3 - (size_t)(p - buf))
+ p = buf;
+ lp = bn_data;
+ if (BN_is_zero(t)) {
+ *(p++) = '0';
+ *(p++) = '\0';
+ } else {
+ if (BN_is_negative(t)) {
+ *p++ = '-';
+ }
+
+ i = 0;
+ while (!BN_is_zero(t)) {
+ *lp = BN_div_word(t, BN_DEC_CONV);
+ lp++;
+ }
+ lp--;
+ /* We now have a series of blocks, BN_DEC_NUM chars
+ * in length, where the last one needs truncation.
+ * The blocks need to be reversed in order. */
+ BIO_snprintf(p, BUF_REMAIN, BN_DEC_FMT1, *lp);
+ while (*p) {
+ p++;
+ }
+ while (lp != bn_data) {
+ lp--;
+ BIO_snprintf(p, BUF_REMAIN, BN_DEC_FMT2, *lp);
+ while (*p) {
+ p++;
+ }
+ }
+ }
+ ok = 1;
+
+err:
+ if (bn_data != NULL) {
+ OPENSSL_free(bn_data);
+ }
+ if (t != NULL) {
+ BN_free(t);
+ }
+ if (!ok && buf) {
+ OPENSSL_free(buf);
+ buf = NULL;
+ }
+
+ return buf;
+}
+
+int BN_dec2bn(BIGNUM **outp, const char *in) {
+ return bn_x2bn(outp, in, decode_dec, isdigit);
+}
+
+int BN_asc2bn(BIGNUM **outp, const char *in) {
+ const char *const orig_in = in;
+ if (*in == '-') {
+ in++;
+ }
+
+ if (in[0] == '0' && (in[1] == 'X' || in[1] == 'x')) {
+ if (!BN_hex2bn(outp, in+2)) {
+ return 0;
+ }
+ } else {
+ if (!BN_dec2bn(outp, in)) {
+ return 0;
+ }
+ }
+
+ if (*orig_in == '-') {
+ (*outp)->neg = 1;
+ }
+
+ return 1;
+}
+
+int BN_print(BIO *bp, const BIGNUM *a) {
+ int i, j, v, z = 0;
+ int ret = 0;
+
+ if (a->neg && BIO_write(bp, "-", 1) != 1) {
+ goto end;
+ }
+
+ if (BN_is_zero(a) && BIO_write(bp, "0", 1) != 1) {
+ goto end;
+ }
+
+ for (i = a->top - 1; i >= 0; i--) {
+ for (j = BN_BITS2 - 4; j >= 0; j -= 4) {
+ /* strip leading zeros */
+ v = ((int)(a->d[i] >> (long)j)) & 0x0f;
+ if (z || v != 0) {
+ if (BIO_write(bp, &hextable[v], 1) != 1) {
+ goto end;
+ }
+ z = 1;
+ }
+ }
+ }
+ ret = 1;
+
+end:
+ return ret;
+}
+
+int BN_print_fp(FILE *fp, const BIGNUM *a) {
+ BIO *b;
+ int ret;
+
+ b = BIO_new(BIO_s_file());
+ if (b == NULL) {
+ return 0;
+ }
+ BIO_set_fp(b, fp, BIO_NOCLOSE);
+ ret = BN_print(b, a);
+ BIO_free(b);
+
+ return ret;
+}
+
+BN_ULONG BN_get_word(const BIGNUM *bn) {
+ switch (bn->top) {
+ case 0:
+ return 0;
+ case 1:
+ return bn->d[0];
+ default:
+ return BN_MASK2;
+ }
+}
diff --git a/crypto/bn/ctx.c b/crypto/bn/ctx.c
new file mode 100644
index 0000000..a89f87d
--- /dev/null
+++ b/crypto/bn/ctx.c
@@ -0,0 +1,313 @@
+/* Written by Ulf Moeller for the OpenSSL project. */
+/* ====================================================================
+ * Copyright (c) 1998-2004 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). */
+
+
+#include <openssl/bn.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+/* How many bignums are in each "pool item"; */
+#define BN_CTX_POOL_SIZE 16
+/* The stack frame info is resizing, set a first-time expansion size; */
+#define BN_CTX_START_FRAMES 32
+
+/* A bundle of bignums that can be linked with other bundles */
+typedef struct bignum_pool_item {
+ /* The bignum values */
+ BIGNUM vals[BN_CTX_POOL_SIZE];
+ /* Linked-list admin */
+ struct bignum_pool_item *prev, *next;
+} BN_POOL_ITEM;
+
+
+typedef struct bignum_pool {
+ /* Linked-list admin */
+ BN_POOL_ITEM *head, *current, *tail;
+ /* Stack depth and allocation size */
+ unsigned used, size;
+} BN_POOL;
+
+static void BN_POOL_init(BN_POOL *);
+static void BN_POOL_finish(BN_POOL *);
+static BIGNUM *BN_POOL_get(BN_POOL *);
+static void BN_POOL_release(BN_POOL *, unsigned int);
+
+/************/
+/* BN_STACK */
+/************/
+
+/* A wrapper to manage the "stack frames" */
+typedef struct bignum_ctx_stack {
+ /* Array of indexes into the bignum stack */
+ unsigned int *indexes;
+ /* Number of stack frames, and the size of the allocated array */
+ unsigned int depth, size;
+} BN_STACK;
+
+static void BN_STACK_init(BN_STACK *);
+static void BN_STACK_finish(BN_STACK *);
+static int BN_STACK_push(BN_STACK *, unsigned int);
+static unsigned int BN_STACK_pop(BN_STACK *);
+
+/**********/
+/* BN_CTX */
+/**********/
+
+/* The opaque BN_CTX type */
+struct bignum_ctx {
+ /* The bignum bundles */
+ BN_POOL pool;
+ /* The "stack frames", if you will */
+ BN_STACK stack;
+ /* The number of bignums currently assigned */
+ unsigned int used;
+ /* Depth of stack overflow */
+ int err_stack;
+ /* Block "gets" until an "end" (compatibility behaviour) */
+ int too_many;
+};
+
+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);
+ return NULL;
+ }
+
+ /* Initialise the structure */
+ BN_POOL_init(&ret->pool);
+ BN_STACK_init(&ret->stack);
+ ret->used = 0;
+ ret->err_stack = 0;
+ ret->too_many = 0;
+ return ret;
+}
+
+void BN_CTX_free(BN_CTX *ctx) {
+ if (ctx == NULL) {
+ return;
+ }
+
+ BN_STACK_finish(&ctx->stack);
+ BN_POOL_finish(&ctx->pool);
+ OPENSSL_free(ctx);
+}
+
+void BN_CTX_start(BN_CTX *ctx) {
+ /* If we're already overflowing ... */
+ if (ctx->err_stack || ctx->too_many) {
+ 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);
+ ctx->err_stack++;
+ }
+}
+
+BIGNUM *BN_CTX_get(BN_CTX *ctx) {
+ BIGNUM *ret;
+ if (ctx->err_stack || ctx->too_many) {
+ return NULL;
+ }
+
+ ret = BN_POOL_get(&ctx->pool);
+ if (ret == NULL) {
+ /* 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);
+ return NULL;
+ }
+
+ /* OK, make sure the returned bignum is "zero" */
+ BN_zero(ret);
+ ctx->used++;
+ return ret;
+}
+
+void BN_CTX_end(BN_CTX *ctx) {
+ if (ctx->err_stack) {
+ ctx->err_stack--;
+ } else {
+ unsigned int fp = BN_STACK_pop(&ctx->stack);
+ /* Does this stack frame have anything to release? */
+ if (fp < ctx->used) {
+ BN_POOL_release(&ctx->pool, ctx->used - fp);
+ }
+
+ ctx->used = fp;
+ /* Unjam "too_many" in case "get" had failed */
+ ctx->too_many = 0;
+ }
+}
+
+/************/
+/* BN_STACK */
+/************/
+
+static void BN_STACK_init(BN_STACK *st) {
+ st->indexes = NULL;
+ st->depth = st->size = 0;
+}
+
+static void BN_STACK_finish(BN_STACK *st) {
+ if (st->size)
+ OPENSSL_free(st->indexes);
+}
+
+static int BN_STACK_push(BN_STACK *st, unsigned int idx) {
+ if (st->depth == st->size)
+ /* Need to expand */
+ {
+ unsigned int newsize =
+ (st->size ? (st->size * 3 / 2) : BN_CTX_START_FRAMES);
+ unsigned int *newitems = OPENSSL_malloc(newsize * sizeof(unsigned int));
+ if (!newitems) {
+ return 0;
+ }
+ if (st->depth) {
+ memcpy(newitems, st->indexes, st->depth * sizeof(unsigned int));
+ }
+ if (st->size) {
+ OPENSSL_free(st->indexes);
+ }
+ st->indexes = newitems;
+ st->size = newsize;
+ }
+
+ st->indexes[(st->depth)++] = idx;
+ return 1;
+}
+
+static unsigned int BN_STACK_pop(BN_STACK *st) {
+ return st->indexes[--(st->depth)];
+}
+
+static void BN_POOL_init(BN_POOL *p) {
+ p->head = p->current = p->tail = NULL;
+ p->used = p->size = 0;
+}
+
+static void BN_POOL_finish(BN_POOL *p) {
+ while (p->head) {
+ unsigned int loop = 0;
+ BIGNUM *bn = p->head->vals;
+ while (loop++ < BN_CTX_POOL_SIZE) {
+ if (bn->d) {
+ BN_clear_free(bn);
+ }
+ bn++;
+ }
+
+ p->current = p->head->next;
+ OPENSSL_free(p->head);
+ p->head = p->current;
+ }
+}
+
+static BIGNUM *BN_POOL_get(BN_POOL *p) {
+ if (p->used == p->size) {
+ BIGNUM *bn;
+ unsigned int loop = 0;
+ BN_POOL_ITEM *item = OPENSSL_malloc(sizeof(BN_POOL_ITEM));
+ if (!item) {
+ return NULL;
+ }
+
+ /* Initialise the structure */
+ bn = item->vals;
+ while (loop++ < BN_CTX_POOL_SIZE) {
+ BN_init(bn++);
+ }
+
+ item->prev = p->tail;
+ item->next = NULL;
+ /* Link it in */
+ if (!p->head) {
+ p->head = p->current = p->tail = item;
+ } else {
+ p->tail->next = item;
+ p->tail = item;
+ p->current = item;
+ }
+
+ p->size += BN_CTX_POOL_SIZE;
+ p->used++;
+ /* Return the first bignum from the new pool */
+ return item->vals;
+ }
+
+ if (!p->used) {
+ p->current = p->head;
+ } else if ((p->used % BN_CTX_POOL_SIZE) == 0) {
+ p->current = p->current->next;
+ }
+
+ return p->current->vals + ((p->used++) % BN_CTX_POOL_SIZE);
+}
+
+static void BN_POOL_release(BN_POOL *p, unsigned int num) {
+ unsigned int offset = (p->used - 1) % BN_CTX_POOL_SIZE;
+ p->used -= num;
+
+ while (num--) {
+ if (!offset) {
+ offset = BN_CTX_POOL_SIZE - 1;
+ p->current = p->current->prev;
+ } else {
+ offset--;
+ }
+ }
+}
diff --git a/crypto/bn/div.c b/crypto/bn/div.c
new file mode 100644
index 0000000..5f92e9e
--- /dev/null
+++ b/crypto/bn/div.c
@@ -0,0 +1,619 @@
+/* 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/bn.h>
+
+#include <limits.h>
+#include <openssl/err.h>
+
+#include "internal.h"
+
+
+#define asm __asm__
+
+#if !defined(OPENSSL_NO_ASM)
+# if defined(__GNUC__) && __GNUC__>=2
+# if defined(OPENSSL_X86)
+ /*
+ * There were two reasons for implementing this template:
+ * - GNU C generates a call to a function (__udivdi3 to be exact)
+ * in reply to ((((BN_ULLONG)n0)<<BN_BITS2)|n1)/d0 (I fail to
+ * understand why...);
+ * - divl doesn't only calculate quotient, but also leaves
+ * remainder in %edx which we can definitely use here:-)
+ *
+ * <appro@fy.chalmers.se>
+ */
+#undef div_asm
+# define div_asm(n0,n1,d0) \
+ ({ asm volatile ( \
+ "divl %4" \
+ : "=a"(q), "=d"(rem) \
+ : "a"(n1), "d"(n0), "g"(d0) \
+ : "cc"); \
+ q; \
+ })
+# define REMAINDER_IS_ALREADY_CALCULATED
+# elif defined(OPENSSL_X86_64)
+ /*
+ * Same story here, but it's 128-bit by 64-bit division. Wow!
+ * <appro@fy.chalmers.se>
+ */
+# undef div_asm
+# define div_asm(n0,n1,d0) \
+ ({ asm volatile ( \
+ "divq %4" \
+ : "=a"(q), "=d"(rem) \
+ : "a"(n1), "d"(n0), "g"(d0) \
+ : "cc"); \
+ q; \
+ })
+# define REMAINDER_IS_ALREADY_CALCULATED
+# endif /* __<cpu> */
+# endif /* __GNUC__ */
+#endif /* OPENSSL_NO_ASM */
+
+/* BN_div computes dv := num / divisor, rounding towards
+ * zero, and sets up rm such that dv*divisor + rm = num holds.
+ * Thus:
+ * dv->neg == num->neg ^ divisor->neg (unless the result is zero)
+ * rm->neg == num->neg (unless the remainder is zero)
+ * If 'dv' or 'rm' is NULL, the respective value is not returned. */
+int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
+ BN_CTX *ctx) {
+ int norm_shift, i, loop;
+ BIGNUM *tmp, wnum, *snum, *sdiv, *res;
+ BN_ULONG *resp, *wnump;
+ BN_ULONG d0, d1;
+ int num_n, div_n;
+ int no_branch = 0;
+
+ /* Invalid zero-padding would have particularly bad consequences
+ * in the case of 'num'. */
+ if (num->top > 0 && num->d[num->top - 1] == 0) {
+ OPENSSL_PUT_ERROR(BN, BN_div, BN_R_NOT_INITIALIZED);
+ return 0;
+ }
+
+ if ((num->flags & BN_FLG_CONSTTIME) != 0 ||
+ (divisor->flags & BN_FLG_CONSTTIME) != 0) {
+ no_branch = 1;
+ }
+
+ if (BN_is_zero(divisor)) {
+ OPENSSL_PUT_ERROR(BN, BN_div, BN_R_DIV_BY_ZERO);
+ return 0;
+ }
+
+ if (!no_branch && BN_ucmp(num, divisor) < 0) {
+ if (rm != NULL) {
+ if (BN_copy(rm, num) == NULL) {
+ return 0;
+ }
+ }
+ if (dv != NULL) {
+ BN_zero(dv);
+ }
+ return 1;
+ }
+
+ BN_CTX_start(ctx);
+ tmp = BN_CTX_get(ctx);
+ snum = BN_CTX_get(ctx);
+ sdiv = BN_CTX_get(ctx);
+ if (dv == NULL) {
+ res = BN_CTX_get(ctx);
+ } else {
+ res = dv;
+ }
+ if (sdiv == NULL || res == NULL || tmp == NULL || snum == NULL) {
+ goto err;
+ }
+
+ /* First we normalise the numbers */
+ norm_shift = BN_BITS2 - ((BN_num_bits(divisor)) % BN_BITS2);
+ if (!(BN_lshift(sdiv, divisor, norm_shift))) {
+ goto err;
+ }
+ sdiv->neg = 0;
+ norm_shift += BN_BITS2;
+ if (!(BN_lshift(snum, num, norm_shift))) {
+ goto err;
+ }
+ snum->neg = 0;
+
+ if (no_branch) {
+ /* Since we don't know whether snum is larger than sdiv,
+ * we pad snum with enough zeroes without changing its
+ * value.
+ */
+ if (snum->top <= sdiv->top + 1) {
+ if (bn_wexpand(snum, sdiv->top + 2) == NULL) {
+ goto err;
+ }
+ for (i = snum->top; i < sdiv->top + 2; i++) {
+ snum->d[i] = 0;
+ }
+ snum->top = sdiv->top + 2;
+ } else {
+ if (bn_wexpand(snum, snum->top + 1) == NULL) {
+ goto err;
+ }
+ snum->d[snum->top] = 0;
+ snum->top++;
+ }
+ }
+
+ div_n = sdiv->top;
+ num_n = snum->top;
+ loop = num_n - div_n;
+ /* Lets setup a 'window' into snum
+ * This is the part that corresponds to the current
+ * 'area' being divided */
+ wnum.neg = 0;
+ wnum.d = &(snum->d[loop]);
+ wnum.top = div_n;
+ /* only needed when BN_ucmp messes up the values between top and max */
+ wnum.dmax = snum->dmax - loop; /* so we don't step out of bounds */
+
+ /* Get the top 2 words of sdiv */
+ /* div_n=sdiv->top; */
+ d0 = sdiv->d[div_n - 1];
+ d1 = (div_n == 1) ? 0 : sdiv->d[div_n - 2];
+
+ /* pointer to the 'top' of snum */
+ wnump = &(snum->d[num_n - 1]);
+
+ /* Setup to 'res' */
+ res->neg = (num->neg ^ divisor->neg);
+ if (!bn_wexpand(res, (loop + 1))) {
+ goto err;
+ }
+ res->top = loop - no_branch;
+ resp = &(res->d[loop - 1]);
+
+ /* space for temp */
+ if (!bn_wexpand(tmp, (div_n + 1))) {
+ goto err;
+ }
+
+ if (!no_branch) {
+ if (BN_ucmp(&wnum, sdiv) >= 0) {
+ bn_sub_words(wnum.d, wnum.d, sdiv->d, div_n);
+ *resp = 1;
+ } else {
+ res->top--;
+ }
+ }
+
+ /* if res->top == 0 then clear the neg value otherwise decrease
+ * the resp pointer */
+ if (res->top == 0) {
+ res->neg = 0;
+ } else {
+ resp--;
+ }
+
+ for (i = 0; i < loop - 1; i++, wnump--, resp--) {
+ BN_ULONG q, l0;
+ /* the first part of the loop uses the top two words of snum and sdiv to
+ * calculate a BN_ULONG q such that | wnum - sdiv * q | < sdiv */
+ BN_ULONG n0, n1, rem = 0;
+
+ n0 = wnump[0];
+ n1 = wnump[-1];
+ if (n0 == d0) {
+ q = BN_MASK2;
+ } else {
+ /* n0 < d0 */
+#ifdef BN_LLONG
+ BN_ULLONG t2;
+
+#if defined(BN_LLONG) && defined(BN_DIV2W) && !defined(div_asm)
+ q = (BN_ULONG)(((((BN_ULLONG)n0) << BN_BITS2) | n1) / d0);
+#else
+ q = div_asm(n0, n1, d0);
+#endif
+
+#ifndef REMAINDER_IS_ALREADY_CALCULATED
+ /* rem doesn't have to be BN_ULLONG. The least we know it's less that d0,
+ * isn't it? */
+ rem = (n1 - q * d0) & BN_MASK2;
+#endif
+
+ t2 = (BN_ULLONG)d1 * q;
+
+ for (;;) {
+ if (t2 <= ((((BN_ULLONG)rem) << BN_BITS2) | wnump[-2]))
+ break;
+ q--;
+ rem += d0;
+ if (rem < d0)
+ break; /* don't let rem overflow */
+ t2 -= d1;
+ }
+#else /* !BN_LLONG */
+ BN_ULONG t2l, t2h;
+
+#if defined(div_asm)
+ q = div_asm(n0, n1, d0);
+#else
+ q = bn_div_words(n0, n1, d0);
+#endif
+
+#ifndef REMAINDER_IS_ALREADY_CALCULATED
+ rem = (n1 - q * d0) & BN_MASK2;
+#endif
+
+#if defined(BN_UMULT_LOHI)
+ BN_UMULT_LOHI(t2l, t2h, d1, q);
+#elif defined(BN_UMULT_HIGH)
+ t2l = d1 * q;
+ t2h = BN_UMULT_HIGH(d1, q);
+#else
+ {
+ BN_ULONG ql, qh;
+ t2l = LBITS(d1);
+ t2h = HBITS(d1);
+ ql = LBITS(q);
+ qh = HBITS(q);
+ mul64(t2l, t2h, ql, qh); /* t2=(BN_ULLONG)d1*q; */
+ }
+#endif
+
+ for (;;) {
+ if ((t2h < rem) || ((t2h == rem) && (t2l <= wnump[-2])))
+ break;
+ q--;
+ rem += d0;
+ if (rem < d0)
+ break; /* don't let rem overflow */
+ if (t2l < d1)
+ t2h--;
+ t2l -= d1;
+ }
+#endif /* !BN_LLONG */
+ }
+
+ l0 = bn_mul_words(tmp->d, sdiv->d, div_n, q);
+ tmp->d[div_n] = l0;
+ wnum.d--;
+ /* ingore top values of the bignums just sub the two
+ * BN_ULONG arrays with bn_sub_words */
+ if (bn_sub_words(wnum.d, wnum.d, tmp->d, div_n + 1)) {
+ /* Note: As we have considered only the leading
+ * two BN_ULONGs in the calculation of q, sdiv * q
+ * might be greater than wnum (but then (q-1) * sdiv
+ * is less or equal than wnum)
+ */
+ q--;
+ if (bn_add_words(wnum.d, wnum.d, sdiv->d, div_n)) {
+ /* we can't have an overflow here (assuming
+ * that q != 0, but if q == 0 then tmp is
+ * zero anyway) */
+ (*wnump)++;
+ }
+ }
+ /* store part of the result */
+ *resp = q;
+ }
+ bn_correct_top(snum);
+ if (rm != NULL) {
+ /* Keep a copy of the neg flag in num because if rm==num
+ * BN_rshift() will overwrite it.
+ */
+ int neg = num->neg;
+ BN_rshift(rm, snum, norm_shift);
+ if (!BN_is_zero(rm)) {
+ rm->neg = neg;
+ }
+ }
+ if (no_branch) {
+ bn_correct_top(res);
+ }
+ BN_CTX_end(ctx);
+ return 1;
+
+err:
+ BN_CTX_end(ctx);
+ return 0;
+}
+
+int BN_nnmod(BIGNUM *r, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx) {
+ if (!(BN_mod(r, m, d, ctx))) {
+ return 0;
+ }
+ if (!r->neg) {
+ return 1;
+ }
+
+ /* now -|d| < r < 0, so we have to set r := r + |d|. */
+ return (d->neg ? BN_sub : BN_add)(r, r, d);
+}
+
+int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
+ BN_CTX *ctx) {
+ if (!BN_add(r, a, b)) {
+ return 0;
+ }
+ return BN_nnmod(r, r, m, ctx);
+}
+
+int BN_mod_add_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+ const BIGNUM *m) {
+ if (!BN_uadd(r, a, b)) {
+ return 0;
+ }
+ if (BN_ucmp(r, m) >= 0) {
+ return BN_usub(r, r, m);
+ }
+ return 1;
+}
+
+int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
+ BN_CTX *ctx) {
+ if (!BN_sub(r, a, b)) {
+ return 0;
+ }
+ return BN_nnmod(r, r, m, ctx);
+}
+
+/* BN_mod_sub variant that may be used if both a and b are non-negative
+ * and less than m */
+int BN_mod_sub_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+ const BIGNUM *m) {
+ if (!BN_sub(r, a, b)) {
+ return 0;
+ }
+ if (r->neg) {
+ return BN_add(r, r, m);
+ }
+ return 1;
+}
+
+int BN_mod_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
+ BN_CTX *ctx) {
+ BIGNUM *t;
+ int ret = 0;
+
+ BN_CTX_start(ctx);
+ t = BN_CTX_get(ctx);
+ if (t == NULL) {
+ goto err;
+ }
+
+ if (a == b) {
+ if (!BN_sqr(t, a, ctx)) {
+ goto err;
+ }
+ } else {
+ if (!BN_mul(t, a, b, ctx)) {
+ goto err;
+ }
+ }
+
+ if (!BN_nnmod(r, t, m, ctx)) {
+ goto err;
+ }
+
+ ret = 1;
+
+err:
+ BN_CTX_end(ctx);
+ return ret;
+}
+
+int BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx) {
+ if (!BN_sqr(r, a, ctx)) {
+ return 0;
+ }
+
+ /* r->neg == 0, thus we don't need BN_nnmod */
+ return BN_mod(r, r, m, ctx);
+}
+
+int BN_mod_lshift(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m,
+ BN_CTX *ctx) {
+ BIGNUM *abs_m = NULL;
+ int ret;
+
+ if (!BN_nnmod(r, a, m, ctx)) {
+ return 0;
+ }
+
+ if (m->neg) {
+ abs_m = BN_dup(m);
+ if (abs_m == NULL) {
+ return 0;
+ }
+ abs_m->neg = 0;
+ }
+
+ ret = BN_mod_lshift_quick(r, r, n, (abs_m ? abs_m : m));
+
+ if (abs_m) {
+ BN_free(abs_m);
+ }
+ return ret;
+}
+
+int BN_mod_lshift_quick(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m) {
+ if (r != a) {
+ if (BN_copy(r, a) == NULL) {
+ return 0;
+ }
+ }
+
+ while (n > 0) {
+ int max_shift;
+
+ /* 0 < r < m */
+ max_shift = BN_num_bits(m) - BN_num_bits(r);
+ /* max_shift >= 0 */
+
+ if (max_shift < 0) {
+ OPENSSL_PUT_ERROR(BN, BN_mod_lshift_quick, BN_R_INPUT_NOT_REDUCED);
+ return 0;
+ }
+
+ if (max_shift > n) {
+ max_shift = n;
+ }
+
+ if (max_shift) {
+ if (!BN_lshift(r, r, max_shift)) {
+ return 0;
+ }
+ n -= max_shift;
+ } else {
+ if (!BN_lshift1(r, r)) {
+ return 0;
+ }
+ --n;
+ }
+
+ /* BN_num_bits(r) <= BN_num_bits(m) */
+ if (BN_cmp(r, m) >= 0) {
+ if (!BN_sub(r, r, m)) {
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+int BN_mod_lshift1(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx) {
+ if (!BN_lshift1(r, a)) {
+ return 0;
+ }
+
+ return BN_nnmod(r, r, m, ctx);
+}
+
+int BN_mod_lshift1_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *m) {
+ if (!BN_lshift1(r, a)) {
+ return 0;
+ }
+ if (BN_cmp(r, m) >= 0) {
+ return BN_sub(r, r, m);
+ }
+
+ return 1;
+}
+
+BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w) {
+ BN_ULONG ret = 0;
+ int i, j;
+
+ w &= BN_MASK2;
+
+ if (!w) {
+ /* actually this an error (division by zero) */
+ return (BN_ULONG) - 1;
+ }
+
+ if (a->top == 0) {
+ return 0;
+ }
+
+ /* normalize input (so bn_div_words doesn't complain) */
+ j = BN_BITS2 - BN_num_bits_word(w);
+ w <<= j;
+ if (!BN_lshift(a, a, j)) {
+ return (BN_ULONG) - 1;
+ }
+
+ for (i = a->top - 1; i >= 0; i--) {
+ BN_ULONG l, d;
+
+ l = a->d[i];
+ d = bn_div_words(ret, l, w);
+ ret = (l - ((d * w) & BN_MASK2)) & BN_MASK2;
+ a->d[i] = d;
+ }
+
+ if ((a->top > 0) && (a->d[a->top - 1] == 0)) {
+ a->top--;
+ }
+
+ ret >>= j;
+ return ret;
+}
+
+BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w) {
+#ifndef BN_LLONG
+ BN_ULONG ret = 0;
+#else
+ BN_ULLONG ret = 0;
+#endif
+ int i;
+
+ if (w == 0) {
+ return (BN_ULONG) -1;
+ }
+
+ w &= BN_MASK2;
+ for (i = a->top - 1; i >= 0; i--) {
+#ifndef BN_LLONG
+ ret = ((ret << BN_BITS4) | ((a->d[i] >> BN_BITS4) & BN_MASK2l)) % w;
+ ret = ((ret << BN_BITS4) | (a->d[i] & BN_MASK2l)) % w;
+#else
+ ret = (BN_ULLONG)(((ret << (BN_ULLONG)BN_BITS2) | a->d[i]) % (BN_ULLONG)w);
+#endif
+ }
+ return (BN_ULONG)ret;
+}
diff --git a/crypto/bn/exponentiation.c b/crypto/bn/exponentiation.c
new file mode 100644
index 0000000..b51f15f
--- /dev/null
+++ b/crypto/bn/exponentiation.c
@@ -0,0 +1,1500 @@
+/* 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.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2005 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). */
+
+#include <openssl/bn.h>
+
+#include <openssl/cpu.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+#include "internal.h"
+
+
+#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64)
+#define OPENSSL_BN_ASM_MONT5
+#define RSAZ_ENABLED
+
+#include "rsaz_exp.h"
+#endif
+
+int BN_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx) {
+ int i, bits, ret = 0;
+ BIGNUM *v, *rr;
+
+ 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);
+ return 0;
+ }
+
+ BN_CTX_start(ctx);
+ if (r == a || r == p) {
+ rr = BN_CTX_get(ctx);
+ } else {
+ rr = r;
+ }
+
+ v = BN_CTX_get(ctx);
+ if (rr == NULL || v == NULL) {
+ goto err;
+ }
+
+ if (BN_copy(v, a) == NULL) {
+ goto err;
+ }
+ bits = BN_num_bits(p);
+
+ if (BN_is_odd(p)) {
+ if (BN_copy(rr, a) == NULL) {
+ goto err;
+ }
+ } else {
+ if (!BN_one(rr)) {
+ goto err;
+ }
+ }
+
+ for (i = 1; i < bits; i++) {
+ if (!BN_sqr(v, v, ctx)) {
+ goto err;
+ }
+ if (BN_is_bit_set(p, i)) {
+ if (!BN_mul(rr, rr, v, ctx)) {
+ goto err;
+ }
+ }
+ }
+ ret = 1;
+
+err:
+ if (r != rr) {
+ BN_copy(r, rr);
+ }
+ BN_CTX_end(ctx);
+ return ret;
+}
+
+/* maximum precomputation table size for *variable* sliding windows */
+#define TABLE_SIZE 32
+
+typedef struct bn_recp_ctx_st {
+ BIGNUM N; /* the divisor */
+ BIGNUM Nr; /* the reciprocal */
+ int num_bits;
+ int shift;
+ int flags;
+} BN_RECP_CTX;
+
+static void BN_RECP_CTX_init(BN_RECP_CTX *recp) {
+ BN_init(&recp->N);
+ BN_init(&recp->Nr);
+ recp->num_bits = 0;
+ recp->flags = 0;
+}
+
+static void BN_RECP_CTX_free(BN_RECP_CTX *recp) {
+ if (recp == NULL) {
+ return;
+ }
+
+ BN_free(&recp->N);
+ BN_free(&recp->Nr);
+}
+
+static int BN_RECP_CTX_set(BN_RECP_CTX *recp, const BIGNUM *d, BN_CTX *ctx) {
+ if (!BN_copy(&(recp->N), d)) {
+ return 0;
+ }
+ BN_zero(&recp->Nr);
+ recp->num_bits = BN_num_bits(d);
+ recp->shift = 0;
+
+ return 1;
+}
+
+/* len is the expected size of the result We actually calculate with an extra
+ * word of precision, so we can do faster division if the remainder is not
+ * required.
+ * r := 2^len / m */
+static int BN_reciprocal(BIGNUM *r, const BIGNUM *m, int len, BN_CTX *ctx) {
+ int ret = -1;
+ BIGNUM *t;
+
+ BN_CTX_start(ctx);
+ t = BN_CTX_get(ctx);
+ if (t == NULL) {
+ goto err;
+ }
+
+ if (!BN_set_bit(t, len)) {
+ goto err;
+ }
+
+ if (!BN_div(r, NULL, t, m, ctx)) {
+ goto err;
+ }
+
+ ret = len;
+
+err:
+ BN_CTX_end(ctx);
+ return ret;
+}
+
+static int BN_div_recp(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m,
+ BN_RECP_CTX *recp, BN_CTX *ctx) {
+ int i, j, ret = 0;
+ BIGNUM *a, *b, *d, *r;
+
+ BN_CTX_start(ctx);
+ a = BN_CTX_get(ctx);
+ b = BN_CTX_get(ctx);
+ if (dv != NULL) {
+ d = dv;
+ } else {
+ d = BN_CTX_get(ctx);
+ }
+
+ if (rem != NULL) {
+ r = rem;
+ } else {
+ r = BN_CTX_get(ctx);
+ }
+
+ if (a == NULL || b == NULL || d == NULL || r == NULL) {
+ goto err;
+ }
+
+ if (BN_ucmp(m, &(recp->N)) < 0) {
+ BN_zero(d);
+ if (!BN_copy(r, m)) {
+ return 0;
+ }
+ BN_CTX_end(ctx);
+ return 1;
+ }
+
+ /* We want the remainder
+ * Given input of ABCDEF / ab
+ * we need multiply ABCDEF by 3 digests of the reciprocal of ab */
+
+ /* i := max(BN_num_bits(m), 2*BN_num_bits(N)) */
+ i = BN_num_bits(m);
+ j = recp->num_bits << 1;
+ if (j > i) {
+ i = j;
+ }
+
+ /* Nr := round(2^i / N) */
+ if (i != recp->shift) {
+ recp->shift =
+ BN_reciprocal(&(recp->Nr), &(recp->N), i,
+ ctx); /* BN_reciprocal returns i, or -1 for an error */
+ }
+
+ if (recp->shift == -1) {
+ goto err;
+ }
+
+ /* d := |round(round(m / 2^BN_num_bits(N)) * recp->Nr / 2^(i -
+ * BN_num_bits(N)))|
+ * = |round(round(m / 2^BN_num_bits(N)) * round(2^i / N) / 2^(i -
+ * BN_num_bits(N)))|
+ * <= |(m / 2^BN_num_bits(N)) * (2^i / N) * (2^BN_num_bits(N) / 2^i)|
+ * = |m/N| */
+ if (!BN_rshift(a, m, recp->num_bits)) {
+ goto err;
+ }
+ if (!BN_mul(b, a, &(recp->Nr), ctx)) {
+ goto err;
+ }
+ if (!BN_rshift(d, b, i - recp->num_bits)) {
+ goto err;
+ }
+ d->neg = 0;
+
+ if (!BN_mul(b, &(recp->N), d, ctx)) {
+ goto err;
+ }
+ if (!BN_usub(r, m, b)) {
+ goto err;
+ }
+ r->neg = 0;
+
+ j = 0;
+ while (BN_ucmp(r, &(recp->N)) >= 0) {
+ if (j++ > 2) {
+ OPENSSL_PUT_ERROR(BN, BN_div_recp, BN_R_BAD_RECIPROCAL);
+ goto err;
+ }
+ if (!BN_usub(r, r, &(recp->N))) {
+ goto err;
+ }
+ if (!BN_add_word(d, 1)) {
+ goto err;
+ }
+ }
+
+ r->neg = BN_is_zero(r) ? 0 : m->neg;
+ d->neg = m->neg ^ recp->N.neg;
+ ret = 1;
+
+err:
+ BN_CTX_end(ctx);
+ return ret;
+}
+
+static int BN_mod_mul_reciprocal(BIGNUM *r, const BIGNUM *x, const BIGNUM *y,
+ BN_RECP_CTX *recp, BN_CTX *ctx) {
+ int ret = 0;
+ BIGNUM *a;
+ const BIGNUM *ca;
+
+ BN_CTX_start(ctx);
+ a = BN_CTX_get(ctx);
+ if (a == NULL) {
+ goto err;
+ }
+
+ if (y != NULL) {
+ if (x == y) {
+ if (!BN_sqr(a, x, ctx)) {
+ goto err;
+ }
+ } else {
+ if (!BN_mul(a, x, y, ctx)) {
+ goto err;
+ }
+ }
+ ca = a;
+ } else {
+ ca = x; /* Just do the mod */
+ }
+
+ ret = BN_div_recp(NULL, r, ca, recp, ctx);
+
+err:
+ BN_CTX_end(ctx);
+ return ret;
+}
+
+/* BN_window_bits_for_exponent_size -- macro for sliding window mod_exp
+ * functions
+ *
+ * For window size 'w' (w >= 2) and a random 'b' bits exponent, the number of
+ * multiplications is a constant plus on average
+ *
+ * 2^(w-1) + (b-w)/(w+1);
+ *
+ * here 2^(w-1) is for precomputing the table (we actually need entries only
+ * for windows that have the lowest bit set), and (b-w)/(w+1) is an
+ * approximation for the expected number of w-bit windows, not counting the
+ * first one.
+ *
+ * Thus we should use
+ *
+ * w >= 6 if b > 671
+ * w = 5 if 671 > b > 239
+ * w = 4 if 239 > b > 79
+ * w = 3 if 79 > b > 23
+ * w <= 2 if 23 > b
+ *
+ * (with draws in between). Very small exponents are often selected
+ * with low Hamming weight, so we use w = 1 for b <= 23. */
+#define BN_window_bits_for_exponent_size(b) \
+ ((b) > 671 ? 6 : \
+ (b) > 239 ? 5 : \
+ (b) > 79 ? 4 : \
+ (b) > 23 ? 3 : 1)
+
+static int mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+ const BIGNUM *m, BN_CTX *ctx) {
+ int i, j, bits, ret = 0, wstart, wend, window, wvalue;
+ int start = 1;
+ BIGNUM *aa;
+ /* Table of variables obtained from 'ctx' */
+ BIGNUM *val[TABLE_SIZE];
+ BN_RECP_CTX recp;
+
+ 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);
+ return 0;
+ }
+
+ bits = BN_num_bits(p);
+
+ if (bits == 0) {
+ ret = BN_one(r);
+ return ret;
+ }
+
+ BN_CTX_start(ctx);
+ aa = BN_CTX_get(ctx);
+ val[0] = BN_CTX_get(ctx);
+ if (!aa || !val[0]) {
+ goto err;
+ }
+
+ BN_RECP_CTX_init(&recp);
+ if (m->neg) {
+ /* ignore sign of 'm' */
+ if (!BN_copy(aa, m)) {
+ goto err;
+ }
+ aa->neg = 0;
+ if (BN_RECP_CTX_set(&recp, aa, ctx) <= 0) {
+ goto err;
+ }
+ } else {
+ if (BN_RECP_CTX_set(&recp, m, ctx) <= 0) {
+ goto err;
+ }
+ }
+
+ if (!BN_nnmod(val[0], a, m, ctx)) {
+ goto err; /* 1 */
+ }
+ if (BN_is_zero(val[0])) {
+ BN_zero(r);
+ ret = 1;
+ goto err;
+ }
+
+ window = BN_window_bits_for_exponent_size(bits);
+ if (window > 1) {
+ if (!BN_mod_mul_reciprocal(aa, val[0], val[0], &recp, ctx)) {
+ goto err; /* 2 */
+ }
+ j = 1 << (window - 1);
+ for (i = 1; i < j; i++) {
+ if (((val[i] = BN_CTX_get(ctx)) == NULL) ||
+ !BN_mod_mul_reciprocal(val[i], val[i - 1], aa, &recp, ctx)) {
+ goto err;
+ }
+ }
+ }
+
+ start = 1; /* This is used to avoid multiplication etc
+ * when there is only the value '1' in the
+ * buffer. */
+ wvalue = 0; /* The 'value' of the window */
+ wstart = bits - 1; /* The top bit of the window */
+ wend = 0; /* The bottom bit of the window */
+
+ if (!BN_one(r)) {
+ goto err;
+ }
+
+ for (;;) {
+ if (BN_is_bit_set(p, wstart) == 0) {
+ if (!start) {
+ if (!BN_mod_mul_reciprocal(r, r, r, &recp, ctx)) {
+ goto err;
+ }
+ }
+ if (wstart == 0) {
+ break;
+ }
+ wstart--;
+ continue;
+ }
+
+ /* We now have wstart on a 'set' bit, we now need to work out
+ * how bit a window to do. To do this we need to scan
+ * forward until the last set bit before the end of the
+ * window */
+ j = wstart;
+ wvalue = 1;
+ wend = 0;
+ for (i = 1; i < window; i++) {
+ if (wstart - i < 0) {
+ break;
+ }
+ if (BN_is_bit_set(p, wstart - i)) {
+ wvalue <<= (i - wend);
+ wvalue |= 1;
+ wend = i;
+ }
+ }
+
+ /* wend is the size of the current window */
+ j = wend + 1;
+ /* add the 'bytes above' */
+ if (!start) {
+ for (i = 0; i < j; i++) {
+ if (!BN_mod_mul_reciprocal(r, r, r, &recp, ctx)) {
+ goto err;
+ }
+ }
+ }
+
+ /* wvalue will be an odd number < 2^window */
+ if (!BN_mod_mul_reciprocal(r, r, val[wvalue >> 1], &recp, ctx)) {
+ goto err;
+ }
+
+ /* move the 'window' down further */
+ wstart -= wend + 1;
+ wvalue = 0;
+ start = 0;
+ if (wstart < 0) {
+ break;
+ }
+ }
+ ret = 1;
+
+err:
+ BN_CTX_end(ctx);
+ BN_RECP_CTX_free(&recp);
+ return ret;
+}
+
+int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m,
+ BN_CTX *ctx) {
+ /* For even modulus m = 2^k*m_odd, it might make sense to compute
+ * a^p mod m_odd and a^p mod 2^k separately (with Montgomery
+ * exponentiation for the odd part), using appropriate exponent
+ * reductions, and combine the results using the CRT.
+ *
+ * For now, we use Montgomery only if the modulus is odd; otherwise,
+ * exponentiation using the reciprocal-based quick remaindering
+ * algorithm is used.
+ *
+ * (Timing obtained with expspeed.c [computations a^p mod m
+ * where a, p, m are of the same length: 256, 512, 1024, 2048,
+ * 4096, 8192 bits], compared to the running time of the
+ * standard algorithm:
+ *
+ * BN_mod_exp_mont 33 .. 40 % [AMD K6-2, Linux, debug configuration]
+ * 55 .. 77 % [UltraSparc processor, but
+ * debug-solaris-sparcv8-gcc conf.]
+ *
+ * BN_mod_exp_recp 50 .. 70 % [AMD K6-2, Linux, debug configuration]
+ * 62 .. 118 % [UltraSparc, debug-solaris-sparcv8-gcc]
+ *
+ * On the Sparc, BN_mod_exp_recp was faster than BN_mod_exp_mont
+ * at 2048 and more bits, but at 512 and 1024 bits, it was
+ * slower even than the standard algorithm!
+ *
+ * "Real" timings [linux-elf, solaris-sparcv9-gcc configurations]
+ * should be obtained when the new Montgomery reduction code
+ * has been integrated into OpenSSL.) */
+
+ if (BN_is_odd(m)) {
+ if (a->top == 1 && !a->neg && BN_get_flags(p, BN_FLG_CONSTTIME) == 0) {
+ BN_ULONG A = a->d[0];
+ return BN_mod_exp_mont_word(r, A, p, m, ctx, NULL);
+ }
+
+ return BN_mod_exp_mont(r, a, p, m, ctx, NULL);
+ }
+
+ return mod_exp_recp(r, a, p, m, ctx);
+}
+
+int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
+ const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont) {
+ int i, j, bits, ret = 0, wstart, wend, window, wvalue;
+ int start = 1;
+ BIGNUM *d, *r;
+ const BIGNUM *aa;
+ /* Table of variables obtained from 'ctx' */
+ BIGNUM *val[TABLE_SIZE];
+ BN_MONT_CTX *mont = NULL;
+
+ if (BN_get_flags(p, BN_FLG_CONSTTIME) != 0) {
+ return BN_mod_exp_mont_consttime(rr, a, p, m, ctx, in_mont);
+ }
+
+ if (!BN_is_odd(m)) {
+ OPENSSL_PUT_ERROR(BN, BN_mod_exp_mont, BN_R_CALLED_WITH_EVEN_MODULUS);
+ return 0;
+ }
+ bits = BN_num_bits(p);
+ if (bits == 0) {
+ ret = BN_one(rr);
+ return ret;
+ }
+
+ BN_CTX_start(ctx);
+ d = BN_CTX_get(ctx);
+ r = BN_CTX_get(ctx);
+ val[0] = BN_CTX_get(ctx);
+ if (!d || !r || !val[0]) {
+ goto err;
+ }
+
+ /* If this is not done, things will break in the montgomery part */
+
+ if (in_mont != NULL) {
+ mont = in_mont;
+ } else {
+ mont = BN_MONT_CTX_new();
+ if (mont == NULL) {
+ goto err;
+ }
+ if (!BN_MONT_CTX_set(mont, m, ctx)) {
+ goto err;
+ }
+ }
+
+ if (a->neg || BN_ucmp(a, m) >= 0) {
+ if (!BN_nnmod(val[0], a, m, ctx)) {
+ goto err;
+ }
+ aa = val[0];
+ } else {
+ aa = a;
+ }
+
+ if (BN_is_zero(aa)) {
+ BN_zero(rr);
+ ret = 1;
+ goto err;
+ }
+ if (!BN_to_montgomery(val[0], aa, mont, ctx)) {
+ goto err; /* 1 */
+ }
+
+ window = BN_window_bits_for_exponent_size(bits);
+ if (window > 1) {
+ if (!BN_mod_mul_montgomery(d, val[0], val[0], mont, ctx)) {
+ goto err; /* 2 */
+ }
+ j = 1 << (window - 1);
+ for (i = 1; i < j; i++) {
+ if (((val[i] = BN_CTX_get(ctx)) == NULL) ||
+ !BN_mod_mul_montgomery(val[i], val[i - 1], d, mont, ctx)) {
+ goto err;
+ }
+ }
+ }
+
+ start = 1; /* This is used to avoid multiplication etc
+ * when there is only the value '1' in the
+ * buffer. */
+ wvalue = 0; /* The 'value' of the window */
+ wstart = bits - 1; /* The top bit of the window */
+ wend = 0; /* The bottom bit of the window */
+
+ j = m->top; /* borrow j */
+ if (m->d[j - 1] & (((BN_ULONG)1) << (BN_BITS2 - 1))) {
+ if (bn_wexpand(r, j) == NULL)
+ goto err;
+ /* 2^(top*BN_BITS2) - m */
+ r->d[0] = (0 - m->d[0]) & BN_MASK2;
+ for (i = 1; i < j; i++)
+ r->d[i] = (~m->d[i]) & BN_MASK2;
+ r->top = j;
+ } else if (!BN_to_montgomery(r, BN_value_one(), mont, ctx)) {
+ goto err;
+ }
+
+ for (;;) {
+ if (BN_is_bit_set(p, wstart) == 0) {
+ if (!start) {
+ if (!BN_mod_mul_montgomery(r, r, r, mont, ctx))
+ goto err;
+ }
+ if (wstart == 0) {
+ break;
+ }
+ wstart--;
+ continue;
+ }
+
+ /* We now have wstart on a 'set' bit, we now need to work out how bit a
+ * window to do. To do this we need to scan forward until the last set bit
+ * before the end of the window */
+ j = wstart;
+ wvalue = 1;
+ wend = 0;
+ for (i = 1; i < window; i++) {
+ if (wstart - i < 0) {
+ break;
+ }
+ if (BN_is_bit_set(p, wstart - i)) {
+ wvalue <<= (i - wend);
+ wvalue |= 1;
+ wend = i;
+ }
+ }
+
+ /* wend is the size of the current window */
+ j = wend + 1;
+ /* add the 'bytes above' */
+ if (!start) {
+ for (i = 0; i < j; i++) {
+ if (!BN_mod_mul_montgomery(r, r, r, mont, ctx)) {
+ goto err;
+ }
+ }
+ }
+
+ /* wvalue will be an odd number < 2^window */
+ if (!BN_mod_mul_montgomery(r, r, val[wvalue >> 1], mont, ctx)) {
+ goto err;
+ }
+
+ /* move the 'window' down further */
+ wstart -= wend + 1;
+ wvalue = 0;
+ start = 0;
+ if (wstart < 0) {
+ break;
+ }
+ }
+
+ if (!BN_from_montgomery(rr, r, mont, ctx)) {
+ goto err;
+ }
+ ret = 1;
+
+err:
+ if (in_mont == NULL && mont != NULL) {
+ BN_MONT_CTX_free(mont);
+ }
+ BN_CTX_end(ctx);
+ return ret;
+}
+
+/* BN_mod_exp_mont_consttime() stores the precomputed powers in a specific
+ * layout so that accessing any of these table values shows the same access
+ * pattern as far as cache lines are concerned. The following functions are
+ * used to transfer a BIGNUM from/to that table. */
+static int copy_to_prebuf(const BIGNUM *b, int top, unsigned char *buf, int idx,
+ int width) {
+ size_t i, j;
+
+ if (top > b->top) {
+ top = b->top; /* this works because 'buf' is explicitly zeroed */
+ }
+ for (i = 0, j = idx; i < top * sizeof b->d[0]; i++, j += width) {
+ buf[j] = ((unsigned char *)b->d)[i];
+ }
+
+ return 1;
+}
+
+static int copy_from_prebuf(BIGNUM *b, int top, unsigned char *buf, int idx,
+ int width) {
+ size_t i, j;
+
+ if (bn_wexpand(b, top) == NULL) {
+ return 0;
+ }
+
+ for (i = 0, j = idx; i < top * sizeof b->d[0]; i++, j += width) {
+ ((unsigned char *)b->d)[i] = buf[j];
+ }
+
+ b->top = top;
+ bn_correct_top(b);
+ return 1;
+}
+
+/* BN_mod_exp_mont_conttime is based on the assumption that the L1 data cache
+ * line width of the target processor is at least the following value. */
+#define MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH (64)
+#define MOD_EXP_CTIME_MIN_CACHE_LINE_MASK \
+ (MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH - 1)
+
+/* Window sizes optimized for fixed window size modular exponentiation
+ * algorithm (BN_mod_exp_mont_consttime).
+ *
+ * To achieve the security goals of BN_mode_exp_mont_consttime, the maximum
+ * size of the window must not exceed
+ * log_2(MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH).
+ *
+ * Window size thresholds are defined for cache line sizes of 32 and 64, cache
+ * line sizes where log_2(32)=5 and log_2(64)=6 respectively. A window size of
+ * 7 should only be used on processors that have a 128 byte or greater cache
+ * line size. */
+#if MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH == 64
+
+#define BN_window_bits_for_ctime_exponent_size(b) \
+ ((b) > 937 ? 6 : (b) > 306 ? 5 : (b) > 89 ? 4 : (b) > 22 ? 3 : 1)
+#define BN_MAX_WINDOW_BITS_FOR_CTIME_EXPONENT_SIZE (6)
+
+#elif MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH == 32
+
+#define BN_window_bits_for_ctime_exponent_size(b) \
+ ((b) > 306 ? 5 : (b) > 89 ? 4 : (b) > 22 ? 3 : 1)
+#define BN_MAX_WINDOW_BITS_FOR_CTIME_EXPONENT_SIZE (5)
+
+#endif
+
+/* Given a pointer value, compute the next address that is a cache line
+ * multiple. */
+#define MOD_EXP_CTIME_ALIGN(x_) \
+ ((unsigned char *)(x_) + \
+ (MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH - \
+ (((size_t)(x_)) & (MOD_EXP_CTIME_MIN_CACHE_LINE_MASK))))
+
+/* This variant of BN_mod_exp_mont() uses fixed windows and the special
+ * precomputation memory layout to limit data-dependency to a minimum
+ * to protect secret exponents (cf. the hyper-threading timing attacks
+ * pointed out by Colin Percival,
+ * http://www.daemonology.net/hyperthreading-considered-harmful/)
+ */
+int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
+ const BIGNUM *m, BN_CTX *ctx,
+ BN_MONT_CTX *in_mont) {
+ int i, bits, ret = 0, window, wvalue;
+ int top;
+ BN_MONT_CTX *mont = NULL;
+
+ int numPowers;
+ unsigned char *powerbufFree = NULL;
+ int powerbufLen = 0;
+ 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);
+ return 0;
+ }
+ bits = BN_num_bits(p);
+ if (bits == 0) {
+ ret = BN_one(rr);
+ return ret;
+ }
+
+ BN_CTX_start(ctx);
+
+ /* Allocate a montgomery context if it was not supplied by the caller.
+ * If this is not done, things will break in the montgomery part.
+ */
+ if (in_mont != NULL)
+ mont = in_mont;
+ else {
+ if ((mont = BN_MONT_CTX_new()) == NULL)
+ goto err;
+ if (!BN_MONT_CTX_set(mont, m, ctx))
+ goto err;
+ }
+
+#ifdef RSAZ_ENABLED
+ /* If the size of the operands allow it, perform the optimized
+ * RSAZ exponentiation. For further information see
+ * crypto/bn/rsaz_exp.c and accompanying assembly modules. */
+ if (((OPENSSL_ia32cap_P[2] & 0x80100) != 0x80100) /* check for MULX/AD*X */
+ && (16 == a->top) && (16 == p->top) && (BN_num_bits(m) == 1024) &&
+ rsaz_avx2_eligible()) {
+ if (NULL == bn_wexpand(rr, 16))
+ goto err;
+ RSAZ_1024_mod_exp_avx2(rr->d, a->d, p->d, m->d, mont->RR.d, mont->n0[0]);
+ rr->top = 16;
+ rr->neg = 0;
+ bn_correct_top(rr);
+ ret = 1;
+ goto err;
+ } else if ((8 == a->top) && (8 == p->top) && (BN_num_bits(m) == 512)) {
+ if (NULL == bn_wexpand(rr, 8))
+ goto err;
+ RSAZ_512_mod_exp(rr->d, a->d, p->d, m->d, mont->n0[0], mont->RR.d);
+ rr->top = 8;
+ rr->neg = 0;
+ bn_correct_top(rr);
+ ret = 1;
+ goto err;
+ }
+#endif
+
+ /* Get the window size to use with size of p. */
+ window = BN_window_bits_for_ctime_exponent_size(bits);
+#if defined(OPENSSL_BN_ASM_MONT5)
+ if (window >= 5) {
+ window = 5; /* ~5% improvement for RSA2048 sign, and even for RSA4096 */
+ if ((top & 7) == 0)
+ powerbufLen += 2 * top * sizeof(m->d[0]);
+ }
+#endif
+ (void)0;
+
+ /* Allocate a buffer large enough to hold all of the pre-computed
+ * powers of am, am itself and tmp.
+ */
+ numPowers = 1 << window;
+ powerbufLen +=
+ sizeof(m->d[0]) *
+ (top * numPowers + ((2 * top) > numPowers ? (2 * top) : numPowers));
+#ifdef alloca
+ if (powerbufLen < 3072)
+ powerbufFree = alloca(powerbufLen + MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH);
+ else
+#endif
+ if ((powerbufFree = (unsigned char *)OPENSSL_malloc(
+ powerbufLen + MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH)) == NULL)
+ goto err;
+
+ powerbuf = MOD_EXP_CTIME_ALIGN(powerbufFree);
+ memset(powerbuf, 0, powerbufLen);
+
+#ifdef alloca
+ if (powerbufLen < 3072)
+ powerbufFree = NULL;
+#endif
+
+ /* lay down tmp and am right after powers table */
+ tmp.d = (BN_ULONG *)(powerbuf + sizeof(m->d[0]) * top * numPowers);
+ am.d = tmp.d + top;
+ tmp.top = am.top = 0;
+ tmp.dmax = am.dmax = top;
+ tmp.neg = am.neg = 0;
+ tmp.flags = am.flags = BN_FLG_STATIC_DATA;
+
+/* prepare a^0 in Montgomery domain */
+/* by Shay Gueron's suggestion */
+ if (m->d[top - 1] & (((BN_ULONG)1) << (BN_BITS2 - 1))) {
+ /* 2^(top*BN_BITS2) - m */
+ tmp.d[0] = (0 - m->d[0]) & BN_MASK2;
+ for (i = 1; i < top; i++)
+ tmp.d[i] = (~m->d[i]) & BN_MASK2;
+ tmp.top = top;
+ } else if (!BN_to_montgomery(&tmp, BN_value_one(), mont, ctx))
+ goto err;
+
+ /* prepare a^1 in Montgomery domain */
+ if (a->neg || BN_ucmp(a, m) >= 0) {
+ if (!BN_mod(&am, a, m, ctx))
+ goto err;
+ if (!BN_to_montgomery(&am, &am, mont, ctx))
+ goto err;
+ } else if (!BN_to_montgomery(&am, a, mont, ctx))
+ goto err;
+
+#if defined(OPENSSL_BN_ASM_MONT5)
+ /* This optimization uses ideas from http://eprint.iacr.org/2011/239,
+ * specifically optimization of cache-timing attack countermeasures
+ * and pre-computation optimization. */
+
+ /* Dedicated window==4 case improves 512-bit RSA sign by ~15%, but as
+ * 512-bit RSA is hardly relevant, we omit it to spare size... */
+ if (window == 5) {
+ void bn_mul_mont_gather5(BN_ULONG * rp, const BN_ULONG * ap,
+ const void * table, const BN_ULONG * np,
+ const BN_ULONG * n0, int num, int power);
+ void bn_scatter5(const BN_ULONG * inp, size_t num, void * table,
+ size_t power);
+ void bn_gather5(BN_ULONG * out, size_t num, void * table, size_t power);
+ void bn_power5(BN_ULONG * rp, const BN_ULONG * ap, const void * table,
+ const BN_ULONG * np, const BN_ULONG * n0, int num,
+ int power);
+ int bn_get_bits5(const BN_ULONG * ap, int off);
+ int bn_from_montgomery(BN_ULONG * rp, const BN_ULONG * ap,
+ const BN_ULONG * not_used, const BN_ULONG * np,
+ const BN_ULONG * n0, int num);
+
+ BN_ULONG *np = mont->N.d, *n0 = mont->n0, *np2;
+
+ /* BN_to_montgomery can contaminate words above .top
+ * [in BN_DEBUG[_DEBUG] build]... */
+ for (i = am.top; i < top; i++)
+ am.d[i] = 0;
+ for (i = tmp.top; i < top; i++)
+ tmp.d[i] = 0;
+
+ if (top & 7)
+ np2 = np;
+ else
+ for (np2 = am.d + top, i = 0; i < top; i++)
+ np2[2 * i] = np[i];
+
+ bn_scatter5(tmp.d, top, powerbuf, 0);
+ bn_scatter5(am.d, am.top, powerbuf, 1);
+ bn_mul_mont(tmp.d, am.d, am.d, np, n0, top);
+ bn_scatter5(tmp.d, top, powerbuf, 2);
+
+ /* same as above, but uses squaring for 1/2 of operations */
+ for (i = 4; i < 32; i *= 2) {
+ bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top);
+ bn_scatter5(tmp.d, top, powerbuf, i);
+ }
+ for (i = 3; i < 8; i += 2) {
+ int j;
+ bn_mul_mont_gather5(tmp.d, am.d, powerbuf, np2, n0, top, i - 1);
+ bn_scatter5(tmp.d, top, powerbuf, i);
+ for (j = 2 * i; j < 32; j *= 2) {
+ bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top);
+ bn_scatter5(tmp.d, top, powerbuf, j);
+ }
+ }
+ for (; i < 16; i += 2) {
+ bn_mul_mont_gather5(tmp.d, am.d, powerbuf, np2, n0, top, i - 1);
+ bn_scatter5(tmp.d, top, powerbuf, i);
+ bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top);
+ bn_scatter5(tmp.d, top, powerbuf, 2 * i);
+ }
+ for (; i < 32; i += 2) {
+ bn_mul_mont_gather5(tmp.d, am.d, powerbuf, np2, n0, top, i - 1);
+ bn_scatter5(tmp.d, top, powerbuf, i);
+ }
+
+ bits--;
+ for (wvalue = 0, i = bits % 5; i >= 0; i--, bits--)
+ wvalue = (wvalue << 1) + BN_is_bit_set(p, bits);
+ bn_gather5(tmp.d, top, powerbuf, wvalue);
+
+ /* Scan the exponent one window at a time starting from the most
+ * significant bits.
+ */
+ if (top & 7)
+ while (bits >= 0) {
+ for (wvalue = 0, i = 0; i < 5; i++, bits--)
+ wvalue = (wvalue << 1) + BN_is_bit_set(p, bits);
+
+ bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top);
+ bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top);
+ bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top);
+ bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top);
+ bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top);
+ bn_mul_mont_gather5(tmp.d, tmp.d, powerbuf, np, n0, top, wvalue);
+ }
+ else {
+ while (bits >= 0) {
+ wvalue = bn_get_bits5(p->d, bits - 4);
+ bits -= 5;
+ bn_power5(tmp.d, tmp.d, powerbuf, np2, n0, top, wvalue);
+ }
+ }
+
+ ret = bn_from_montgomery(tmp.d, tmp.d, NULL, np2, n0, top);
+ tmp.top = top;
+ bn_correct_top(&tmp);
+ if (ret) {
+ if (!BN_copy(rr, &tmp))
+ ret = 0;
+ goto err; /* non-zero ret means it's not error */
+ }
+ } else
+#endif
+ {
+ if (!copy_to_prebuf(&tmp, top, powerbuf, 0, numPowers))
+ goto err;
+ if (!copy_to_prebuf(&am, top, powerbuf, 1, numPowers))
+ goto err;
+
+ /* If the window size is greater than 1, then calculate
+ * val[i=2..2^winsize-1]. Powers are computed as a*a^(i-1)
+ * (even powers could instead be computed as (a^(i/2))^2
+ * to use the slight performance advantage of sqr over mul).
+ */
+ if (window > 1) {
+ if (!BN_mod_mul_montgomery(&tmp, &am, &am, mont, ctx))
+ goto err;
+ if (!copy_to_prebuf(&tmp, top, powerbuf, 2, numPowers))
+ goto err;
+ for (i = 3; i < numPowers; i++) {
+ /* Calculate a^i = a^(i-1) * a */
+ if (!BN_mod_mul_montgomery(&tmp, &am, &tmp, mont, ctx))
+ goto err;
+ if (!copy_to_prebuf(&tmp, top, powerbuf, i, numPowers))
+ goto err;
+ }
+ }
+
+ bits--;
+ for (wvalue = 0, i = bits % window; i >= 0; i--, bits--)
+ wvalue = (wvalue << 1) + BN_is_bit_set(p, bits);
+ if (!copy_from_prebuf(&tmp, top, powerbuf, wvalue, numPowers))
+ goto err;
+
+ /* Scan the exponent one window at a time starting from the most
+ * significant bits.
+ */
+ while (bits >= 0) {
+ wvalue = 0; /* The 'value' of the window */
+
+ /* Scan the window, squaring the result as we go */
+ for (i = 0; i < window; i++, bits--) {
+ if (!BN_mod_mul_montgomery(&tmp, &tmp, &tmp, mont, ctx))
+ goto err;
+ wvalue = (wvalue << 1) + BN_is_bit_set(p, bits);
+ }
+
+ /* Fetch the appropriate pre-computed value from the pre-buf */
+ if (!copy_from_prebuf(&am, top, powerbuf, wvalue, numPowers))
+ goto err;
+
+ /* Multiply the result into the intermediate result */
+ if (!BN_mod_mul_montgomery(&tmp, &tmp, &am, mont, ctx))
+ goto err;
+ }
+ }
+
+ /* Convert the final result from montgomery to standard format */
+ if (!BN_from_montgomery(rr, &tmp, mont, ctx))
+ goto err;
+ ret = 1;
+err:
+ if ((in_mont == NULL) && (mont != NULL))
+ BN_MONT_CTX_free(mont);
+ if (powerbuf != NULL) {
+ OPENSSL_cleanse(powerbuf, powerbufLen);
+ if (powerbufFree)
+ OPENSSL_free(powerbufFree);
+ }
+ BN_CTX_end(ctx);
+ return (ret);
+}
+
+int BN_mod_exp_mont_word(BIGNUM *rr, BN_ULONG a, const BIGNUM *p,
+ const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont) {
+ BN_MONT_CTX *mont = NULL;
+ int b, bits, ret = 0;
+ int r_is_one;
+ BN_ULONG w, next_w;
+ BIGNUM *d, *r, *t;
+ BIGNUM *swap_tmp;
+#define BN_MOD_MUL_WORD(r, w, m) \
+ (BN_mul_word(r, (w)) && \
+ (/* BN_ucmp(r, (m)) < 0 ? 1 :*/ \
+ (BN_mod(t, r, m, ctx) && (swap_tmp = r, r = t, t = swap_tmp, 1))))
+ /* BN_MOD_MUL_WORD is only used with 'w' large, so the BN_ucmp test is
+ * probably more overhead than always using BN_mod (which uses BN_copy if a
+ * similar test returns true). We can use BN_mod and do not need BN_nnmod
+ * because our accumulator is never negative (the result of BN_mod does not
+ * depend on the sign of the modulus). */
+#define BN_TO_MONTGOMERY_WORD(r, w, mont) \
+ (BN_set_word(r, (w)) && BN_to_montgomery(r, r, (mont), ctx))
+
+ 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);
+ return 0;
+ }
+
+ if (!BN_is_odd(m)) {
+ OPENSSL_PUT_ERROR(BN, BN_mod_exp_mont_word, BN_R_CALLED_WITH_EVEN_MODULUS);
+ return 0;
+ }
+
+ if (m->top == 1) {
+ a %= m->d[0]; /* make sure that 'a' is reduced */
+ }
+
+ bits = BN_num_bits(p);
+ if (bits == 0) {
+ ret = BN_one(rr);
+ return ret;
+ }
+ if (a == 0) {
+ BN_zero(rr);
+ ret = 1;
+ return ret;
+ }
+
+ BN_CTX_start(ctx);
+ d = BN_CTX_get(ctx);
+ r = BN_CTX_get(ctx);
+ t = BN_CTX_get(ctx);
+ if (d == NULL || r == NULL || t == NULL) {
+ goto err;
+ }
+
+ if (in_mont != NULL)
+ mont = in_mont;
+ else {
+ if ((mont = BN_MONT_CTX_new()) == NULL) {
+ goto err;
+ }
+ if (!BN_MONT_CTX_set(mont, m, ctx)) {
+ goto err;
+ }
+ }
+
+ r_is_one = 1; /* except for Montgomery factor */
+
+ /* bits-1 >= 0 */
+
+ /* The result is accumulated in the product r*w. */
+ w = a; /* bit 'bits-1' of 'p' is always set */
+ for (b = bits - 2; b >= 0; b--) {
+ /* First, square r*w. */
+ next_w = w * w;
+ if ((next_w / w) != w) {
+ /* overflow */
+ if (r_is_one) {
+ if (!BN_TO_MONTGOMERY_WORD(r, w, mont)) {
+ goto err;
+ }
+ r_is_one = 0;
+ } else {
+ if (!BN_MOD_MUL_WORD(r, w, m)) {
+ goto err;
+ }
+ }
+ next_w = 1;
+ }
+
+ w = next_w;
+ if (!r_is_one) {
+ if (!BN_mod_mul_montgomery(r, r, r, mont, ctx)) {
+ goto err;
+ }
+ }
+
+ /* Second, multiply r*w by 'a' if exponent bit is set. */
+ if (BN_is_bit_set(p, b)) {
+ next_w = w * a;
+ if ((next_w / a) != w) {
+ /* overflow */
+ if (r_is_one) {
+ if (!BN_TO_MONTGOMERY_WORD(r, w, mont)) {
+ goto err;
+ }
+ r_is_one = 0;
+ } else {
+ if (!BN_MOD_MUL_WORD(r, w, m)) {
+ goto err;
+ }
+ }
+ next_w = a;
+ }
+ w = next_w;
+ }
+ }
+
+ /* Finally, set r:=r*w. */
+ if (w != 1) {
+ if (r_is_one) {
+ if (!BN_TO_MONTGOMERY_WORD(r, w, mont)) {
+ goto err;
+ }
+ r_is_one = 0;
+ } else {
+ if (!BN_MOD_MUL_WORD(r, w, m)) {
+ goto err;
+ }
+ }
+ }
+
+ if (r_is_one) {
+ /* can happen only if a == 1*/
+ if (!BN_one(rr)) {
+ goto err;
+ }
+ } else {
+ if (!BN_from_montgomery(rr, r, mont, ctx)) {
+ goto err;
+ }
+ }
+ ret = 1;
+
+err:
+ if (in_mont == NULL && mont != NULL) {
+ BN_MONT_CTX_free(mont);
+ }
+ BN_CTX_end(ctx);
+ return ret;
+}
+
+#define TABLE_SIZE 32
+
+int BN_mod_exp2_mont(BIGNUM *rr, const BIGNUM *a1, const BIGNUM *p1,
+ const BIGNUM *a2, const BIGNUM *p2, const BIGNUM *m,
+ BN_CTX *ctx, BN_MONT_CTX *in_mont) {
+ int i, j, bits, b, bits1, bits2, ret = 0, wpos1, wpos2, window1, window2,
+ wvalue1, wvalue2;
+ int r_is_one = 1;
+ BIGNUM *d, *r;
+ const BIGNUM *a_mod_m;
+ /* Tables of variables obtained from 'ctx' */
+ BIGNUM *val1[TABLE_SIZE], *val2[TABLE_SIZE];
+ BN_MONT_CTX *mont = NULL;
+
+ if (!(m->d[0] & 1)) {
+ OPENSSL_PUT_ERROR(BN, BN_mod_exp2_mont, BN_R_CALLED_WITH_EVEN_MODULUS);
+ return 0;
+ }
+ bits1 = BN_num_bits(p1);
+ bits2 = BN_num_bits(p2);
+ if (bits1 == 0 && bits2 == 0) {
+ ret = BN_one(rr);
+ return ret;
+ }
+
+ bits = (bits1 > bits2) ? bits1 : bits2;
+
+ BN_CTX_start(ctx);
+ d = BN_CTX_get(ctx);
+ r = BN_CTX_get(ctx);
+ val1[0] = BN_CTX_get(ctx);
+ val2[0] = BN_CTX_get(ctx);
+ if (!d || !r || !val1[0] || !val2[0]) {
+ goto err;
+ }
+
+ if (in_mont != NULL) {
+ mont = in_mont;
+ } else {
+ mont = BN_MONT_CTX_new();
+ if (mont == NULL) {
+ goto err;
+ }
+ if (!BN_MONT_CTX_set(mont, m, ctx)) {
+ goto err;
+ }
+ }
+
+ window1 = BN_window_bits_for_exponent_size(bits1);
+ window2 = BN_window_bits_for_exponent_size(bits2);
+
+ /* Build table for a1: val1[i] := a1^(2*i + 1) mod m for i = 0 ..
+ * 2^(window1-1) */
+ if (a1->neg || BN_ucmp(a1, m) >= 0) {
+ if (!BN_mod(val1[0], a1, m, ctx)) {
+ goto err;
+ }
+ a_mod_m = val1[0];
+ } else {
+ a_mod_m = a1;
+ }
+
+ if (BN_is_zero(a_mod_m)) {
+ BN_zero(rr);
+ ret = 1;
+ goto err;
+ }
+
+ if (!BN_to_montgomery(val1[0], a_mod_m, mont, ctx)) {
+ goto err;
+ }
+
+ if (window1 > 1) {
+ if (!BN_mod_mul_montgomery(d, val1[0], val1[0], mont, ctx)) {
+ goto err;
+ }
+
+ j = 1 << (window1 - 1);
+ for (i = 1; i < j; i++) {
+ if (((val1[i] = BN_CTX_get(ctx)) == NULL) ||
+ !BN_mod_mul_montgomery(val1[i], val1[i - 1], d, mont, ctx)) {
+ goto err;
+ }
+ }
+ }
+
+ /* Build table for a2: val2[i] := a2^(2*i + 1) mod m for i = 0 ..
+ * 2^(window2-1) */
+ if (a2->neg || BN_ucmp(a2, m) >= 0) {
+ if (!BN_mod(val2[0], a2, m, ctx)) {
+ goto err;
+ }
+ a_mod_m = val2[0];
+ } else {
+ a_mod_m = a2;
+ }
+
+ if (BN_is_zero(a_mod_m)) {
+ BN_zero(rr);
+ ret = 1;
+ goto err;
+ }
+
+ if (!BN_to_montgomery(val2[0], a_mod_m, mont, ctx)) {
+ goto err;
+ }
+
+ if (window2 > 1) {
+ if (!BN_mod_mul_montgomery(d, val2[0], val2[0], mont, ctx)) {
+ goto err;
+ }
+
+ j = 1 << (window2 - 1);
+ for (i = 1; i < j; i++) {
+ if (((val2[i] = BN_CTX_get(ctx)) == NULL) ||
+ !BN_mod_mul_montgomery(val2[i], val2[i - 1], d, mont, ctx)) {
+ goto err;
+ }
+ }
+ }
+
+ /* Now compute the power product, using independent windows. */
+ r_is_one = 1;
+ wvalue1 = 0; /* The 'value' of the first window */
+ wvalue2 = 0; /* The 'value' of the second window */
+ wpos1 = 0; /* If wvalue1 > 0, the bottom bit of the first window */
+ wpos2 = 0; /* If wvalue2 > 0, the bottom bit of the second window */
+
+ if (!BN_to_montgomery(r, BN_value_one(), mont, ctx)) {
+ goto err;
+ }
+
+ for (b = bits - 1; b >= 0; b--) {
+ if (!r_is_one) {
+ if (!BN_mod_mul_montgomery(r, r, r, mont, ctx)) {
+ goto err;
+ }
+ }
+
+ if (!wvalue1 && BN_is_bit_set(p1, b)) {
+ /* consider bits b-window1+1 .. b for this window */
+ i = b - window1 + 1;
+ while (!BN_is_bit_set(p1, i)) /* works for i<0 */
+ i++;
+ wpos1 = i;
+ wvalue1 = 1;
+ for (i = b - 1; i >= wpos1; i--) {
+ wvalue1 <<= 1;
+ if (BN_is_bit_set(p1, i))
+ wvalue1++;
+ }
+ }
+
+ if (!wvalue2 && BN_is_bit_set(p2, b)) {
+ /* consider bits b-window2+1 .. b for this window */
+ i = b - window2 + 1;
+ while (!BN_is_bit_set(p2, i))
+ i++;
+ wpos2 = i;
+ wvalue2 = 1;
+ for (i = b - 1; i >= wpos2; i--) {
+ wvalue2 <<= 1;
+ if (BN_is_bit_set(p2, i))
+ wvalue2++;
+ }
+ }
+
+ if (wvalue1 && b == wpos1) {
+ /* wvalue1 is odd and < 2^window1 */
+ if (!BN_mod_mul_montgomery(r, r, val1[wvalue1 >> 1], mont, ctx)) {
+ goto err;
+ }
+ wvalue1 = 0;
+ r_is_one = 0;
+ }
+
+ if (wvalue2 && b == wpos2) {
+ /* wvalue2 is odd and < 2^window2 */
+ if (!BN_mod_mul_montgomery(r, r, val2[wvalue2 >> 1], mont, ctx)) {
+ goto err;
+ }
+ wvalue2 = 0;
+ r_is_one = 0;
+ }
+ }
+
+ if (!BN_from_montgomery(rr, r, mont, ctx)) {
+ goto err;
+ }
+ ret = 1;
+
+err:
+ if (in_mont == NULL && mont != NULL) {
+ BN_MONT_CTX_free(mont);
+ }
+ BN_CTX_end(ctx);
+ return ret;
+}
diff --git a/crypto/bn/gcd.c b/crypto/bn/gcd.c
new file mode 100644
index 0000000..2dce296
--- /dev/null
+++ b/crypto/bn/gcd.c
@@ -0,0 +1,704 @@
+/* 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.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2001 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). */
+
+#include <openssl/bn.h>
+
+#include <openssl/err.h>
+
+#include "internal.h"
+
+static BIGNUM *euclid(BIGNUM *a, BIGNUM *b) {
+ BIGNUM *t;
+ int shifts = 0;
+
+ /* 0 <= b <= a */
+ while (!BN_is_zero(b)) {
+ /* 0 < b <= a */
+
+ if (BN_is_odd(a)) {
+ if (BN_is_odd(b)) {
+ if (!BN_sub(a, a, b)) {
+ goto err;
+ }
+ if (!BN_rshift1(a, a)) {
+ goto err;
+ }
+ if (BN_cmp(a, b) < 0) {
+ t = a;
+ a = b;
+ b = t;
+ }
+ } else {
+ /* a odd - b even */
+ if (!BN_rshift1(b, b)) {
+ goto err;
+ }
+ if (BN_cmp(a, b) < 0) {
+ t = a;
+ a = b;
+ b = t;
+ }
+ }
+ } else {
+ /* a is even */
+ if (BN_is_odd(b)) {
+ if (!BN_rshift1(a, a)) {
+ goto err;
+ }
+ if (BN_cmp(a, b) < 0) {
+ t = a;
+ a = b;
+ b = t;
+ }
+ } else {
+ /* a even - b even */
+ if (!BN_rshift1(a, a)) {
+ goto err;
+ }
+ if (!BN_rshift1(b, b)) {
+ goto err;
+ }
+ shifts++;
+ }
+ }
+ /* 0 <= b <= a */
+ }
+
+ if (shifts) {
+ if (!BN_lshift(a, a, shifts)) {
+ goto err;
+ }
+ }
+
+ return a;
+
+err:
+ return NULL;
+}
+
+int BN_gcd(BIGNUM *r, const BIGNUM *in_a, const BIGNUM *in_b, BN_CTX *ctx) {
+ BIGNUM *a, *b, *t;
+ int ret = 0;
+
+ BN_CTX_start(ctx);
+ a = BN_CTX_get(ctx);
+ b = BN_CTX_get(ctx);
+
+ if (a == NULL || b == NULL) {
+ goto err;
+ }
+ if (BN_copy(a, in_a) == NULL) {
+ goto err;
+ }
+ if (BN_copy(b, in_b) == NULL) {
+ goto err;
+ }
+
+ a->neg = 0;
+ b->neg = 0;
+
+ if (BN_cmp(a, b) < 0) {
+ t = a;
+ a = b;
+ b = t;
+ }
+ t = euclid(a, b);
+ if (t == NULL) {
+ goto err;
+ }
+
+ if (BN_copy(r, t) == NULL) {
+ goto err;
+ }
+ ret = 1;
+
+err:
+ BN_CTX_end(ctx);
+ return ret;
+}
+
+/* solves ax == 1 (mod n) */
+static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, 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 *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);
+ }
+
+ BN_CTX_start(ctx);
+ A = BN_CTX_get(ctx);
+ B = BN_CTX_get(ctx);
+ X = BN_CTX_get(ctx);
+ D = BN_CTX_get(ctx);
+ M = BN_CTX_get(ctx);
+ Y = BN_CTX_get(ctx);
+ T = BN_CTX_get(ctx);
+ if (T == NULL) {
+ goto err;
+ }
+
+ if (out == NULL) {
+ R = BN_new();
+ } else {
+ R = out;
+ }
+ if (R == NULL) {
+ goto err;
+ }
+
+ BN_one(X);
+ BN_zero(Y);
+ if (BN_copy(B, a) == NULL) {
+ goto err;
+ }
+ if (BN_copy(A, n) == NULL) {
+ goto err;
+ }
+ A->neg = 0;
+ if (B->neg || (BN_ucmp(B, A) >= 0)) {
+ if (!BN_nnmod(B, B, A, ctx)) {
+ goto err;
+ }
+ }
+ sign = -1;
+ /* From B = a mod |n|, A = |n| it follows that
+ *
+ * 0 <= B < A,
+ * -sign*X*a == B (mod |n|),
+ * sign*Y*a == A (mod |n|).
+ */
+
+ if (BN_is_odd(n) && (BN_num_bits(n) <= (BN_BITS <= 32 ? 450 : 2048))) {
+ /* Binary inversion algorithm; requires odd modulus.
+ * This is faster than the general algorithm if the modulus
+ * is sufficiently small (about 400 .. 500 bits on 32-bit
+ * sytems, but much more on 64-bit systems) */
+ int shift;
+
+ while (!BN_is_zero(B)) {
+ /* 0 < B < |n|,
+ * 0 < A <= |n|,
+ * (1) -sign*X*a == B (mod |n|),
+ * (2) sign*Y*a == A (mod |n|) */
+
+ /* Now divide B by the maximum possible power of two in the integers,
+ * and divide X by the same value mod |n|.
+ * When we're done, (1) still holds. */
+ shift = 0;
+ while (!BN_is_bit_set(B, shift)) {
+ /* note that 0 < B */
+ shift++;
+
+ if (BN_is_odd(X)) {
+ if (!BN_uadd(X, X, n)) {
+ goto err;
+ }
+ }
+ /* now X is even, so we can easily divide it by two */
+ if (!BN_rshift1(X, X)) {
+ goto err;
+ }
+ }
+ if (shift > 0) {
+ if (!BN_rshift(B, B, shift)) {
+ goto err;
+ }
+ }
+
+ /* Same for A and Y. Afterwards, (2) still holds. */
+ shift = 0;
+ while (!BN_is_bit_set(A, shift)) {
+ /* note that 0 < A */
+ shift++;
+
+ if (BN_is_odd(Y)) {
+ if (!BN_uadd(Y, Y, n)) {
+ goto err;
+ }
+ }
+ /* now Y is even */
+ if (!BN_rshift1(Y, Y)) {
+ goto err;
+ }
+ }
+ if (shift > 0) {
+ if (!BN_rshift(A, A, shift)) {
+ goto err;
+ }
+ }
+
+ /* We still have (1) and (2).
+ * Both A and B are odd.
+ * The following computations ensure that
+ *
+ * 0 <= B < |n|,
+ * 0 < A < |n|,
+ * (1) -sign*X*a == B (mod |n|),
+ * (2) sign*Y*a == A (mod |n|),
+ *
+ * and that either A or B is even in the next iteration. */
+ if (BN_ucmp(B, A) >= 0) {
+ /* -sign*(X + Y)*a == B - A (mod |n|) */
+ if (!BN_uadd(X, X, Y)) {
+ goto err;
+ }
+ /* NB: we could use BN_mod_add_quick(X, X, Y, n), but that
+ * actually makes the algorithm slower */
+ if (!BN_usub(B, B, A)) {
+ goto err;
+ }
+ } else {
+ /* sign*(X + Y)*a == A - B (mod |n|) */
+ if (!BN_uadd(Y, Y, X)) {
+ goto err;
+ }
+ /* as above, BN_mod_add_quick(Y, Y, X, n) would slow things down */
+ if (!BN_usub(A, A, B)) {
+ goto err;
+ }
+ }
+ }
+ } else {
+ /* general inversion algorithm */
+
+ while (!BN_is_zero(B)) {
+ BIGNUM *tmp;
+
+ /*
+ * 0 < B < A,
+ * (*) -sign*X*a == B (mod |n|),
+ * sign*Y*a == A (mod |n|) */
+
+ /* (D, M) := (A/B, A%B) ... */
+ if (BN_num_bits(A) == BN_num_bits(B)) {
+ if (!BN_one(D)) {
+ goto err;
+ }
+ if (!BN_sub(M, A, B)) {
+ goto err;
+ }
+ } else if (BN_num_bits(A) == BN_num_bits(B) + 1) {
+ /* A/B is 1, 2, or 3 */
+ if (!BN_lshift1(T, B)) {
+ goto err;
+ }
+ if (BN_ucmp(A, T) < 0) {
+ /* A < 2*B, so D=1 */
+ if (!BN_one(D)) {
+ goto err;
+ }
+ if (!BN_sub(M, A, B)) {
+ goto err;
+ }
+ } else {
+ /* A >= 2*B, so D=2 or D=3 */
+ if (!BN_sub(M, A, T)) {
+ goto err;
+ }
+ if (!BN_add(D, T, B)) {
+ goto err; /* use D (:= 3*B) as temp */
+ }
+ if (BN_ucmp(A, D) < 0) {
+ /* A < 3*B, so D=2 */
+ if (!BN_set_word(D, 2)) {
+ goto err;
+ }
+ /* M (= A - 2*B) already has the correct value */
+ } else {
+ /* only D=3 remains */
+ if (!BN_set_word(D, 3)) {
+ goto err;
+ }
+ /* currently M = A - 2*B, but we need M = A - 3*B */
+ if (!BN_sub(M, M, B)) {
+ goto err;
+ }
+ }
+ }
+ } else {
+ if (!BN_div(D, M, A, B, ctx)) {
+ goto err;
+ }
+ }
+
+ /* Now
+ * A = D*B + M;
+ * thus we have
+ * (**) sign*Y*a == D*B + M (mod |n|). */
+
+ tmp = A; /* keep the BIGNUM object, the value does not matter */
+
+ /* (A, B) := (B, A mod B) ... */
+ A = B;
+ B = M;
+ /* ... so we have 0 <= B < A again */
+
+ /* Since the former M is now B and the former B is now A,
+ * (**) translates into
+ * sign*Y*a == D*A + B (mod |n|),
+ * i.e.
+ * sign*Y*a - D*A == B (mod |n|).
+ * Similarly, (*) translates into
+ * -sign*X*a == A (mod |n|).
+ *
+ * Thus,
+ * sign*Y*a + D*sign*X*a == B (mod |n|),
+ * i.e.
+ * sign*(Y + D*X)*a == B (mod |n|).
+ *
+ * So if we set (X, Y, sign) := (Y + D*X, X, -sign), we arrive back at
+ * -sign*X*a == B (mod |n|),
+ * sign*Y*a == A (mod |n|).
+ * Note that X and Y stay non-negative all the time. */
+
+ /* most of the time D is very small, so we can optimize tmp := D*X+Y */
+ if (BN_is_one(D)) {
+ if (!BN_add(tmp, X, Y)) {
+ goto err;
+ }
+ } else {
+ if (BN_is_word(D, 2)) {
+ if (!BN_lshift1(tmp, X)) {
+ goto err;
+ }
+ } else if (BN_is_word(D, 4)) {
+ if (!BN_lshift(tmp, X, 2)) {
+ goto err;
+ }
+ } else if (D->top == 1) {
+ if (!BN_copy(tmp, X)) {
+ goto err;
+ }
+ if (!BN_mul_word(tmp, D->d[0])) {
+ goto err;
+ }
+ } else {
+ if (!BN_mul(tmp, D, X, ctx)) {
+ goto err;
+ }
+ }
+ if (!BN_add(tmp, tmp, Y)) {
+ goto err;
+ }
+ }
+
+ M = Y; /* keep the BIGNUM object, the value does not matter */
+ Y = X;
+ X = tmp;
+ sign = -sign;
+ }
+ }
+
+ /* The while loop (Euclid's algorithm) ends when
+ * A == gcd(a,n);
+ * we have
+ * sign*Y*a == A (mod |n|),
+ * where Y is non-negative. */
+
+ if (sign < 0) {
+ if (!BN_sub(Y, n, Y)) {
+ goto err;
+ }
+ }
+ /* Now Y*a == A (mod |n|). */
+
+ if (BN_is_one(A)) {
+ /* Y*a == 1 (mod |n|) */
+ if (!Y->neg && BN_ucmp(Y, n) < 0) {
+ if (!BN_copy(R, Y)) {
+ goto err;
+ }
+ } else {
+ if (!BN_nnmod(R, Y, n, ctx)) {
+ goto err;
+ }
+ }
+ } else {
+ OPENSSL_PUT_ERROR(BN, BN_mod_inverse, BN_R_NO_INVERSE);
+ goto err;
+ }
+ ret = R;
+
+err:
+ if (ret == NULL && out == NULL) {
+ BN_free(R);
+ }
+ BN_CTX_end(ctx);
+ return ret;
+}
+
+/* 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) {
+ BIGNUM *A, *B, *X, *Y, *M, *D, *T, *R = NULL;
+ BIGNUM local_A, local_B;
+ BIGNUM *pA, *pB;
+ BIGNUM *ret = NULL;
+ int sign;
+
+ BN_CTX_start(ctx);
+ A = BN_CTX_get(ctx);
+ B = BN_CTX_get(ctx);
+ X = BN_CTX_get(ctx);
+ D = BN_CTX_get(ctx);
+ M = BN_CTX_get(ctx);
+ Y = BN_CTX_get(ctx);
+ T = BN_CTX_get(ctx);
+ if (T == NULL) {
+ goto err;
+ }
+
+ if (out == NULL) {
+ R = BN_new();
+ } else {
+ R = out;
+ }
+ if (R == NULL) {
+ goto err;
+ }
+
+ BN_one(X);
+ BN_zero(Y);
+ if (BN_copy(B, a) == NULL) {
+ goto err;
+ }
+ if (BN_copy(A, n) == NULL) {
+ goto err;
+ }
+ A->neg = 0;
+
+ if (B->neg || (BN_ucmp(B, A) >= 0)) {
+ /* Turn BN_FLG_CONSTTIME flag on, so that when BN_div is invoked,
+ * BN_div_no_branch will be called eventually.
+ */
+ pB = &local_B;
+ BN_with_flags(pB, B, BN_FLG_CONSTTIME);
+ if (!BN_nnmod(B, pB, A, ctx))
+ goto err;
+ }
+ sign = -1;
+ /* From B = a mod |n|, A = |n| it follows that
+ *
+ * 0 <= B < A,
+ * -sign*X*a == B (mod |n|),
+ * sign*Y*a == A (mod |n|).
+ */
+
+ while (!BN_is_zero(B)) {
+ BIGNUM *tmp;
+
+ /*
+ * 0 < B < A,
+ * (*) -sign*X*a == B (mod |n|),
+ * sign*Y*a == A (mod |n|)
+ */
+
+ /* Turn BN_FLG_CONSTTIME flag on, so that when BN_div is invoked,
+ * BN_div_no_branch will be called eventually.
+ */
+ pA = &local_A;
+ BN_with_flags(pA, A, BN_FLG_CONSTTIME);
+
+ /* (D, M) := (A/B, A%B) ... */
+ if (!BN_div(D, M, pA, B, ctx)) {
+ goto err;
+ }
+
+ /* Now
+ * A = D*B + M;
+ * thus we have
+ * (**) sign*Y*a == D*B + M (mod |n|).
+ */
+
+ tmp = A; /* keep the BIGNUM object, the value does not matter */
+
+ /* (A, B) := (B, A mod B) ... */
+ A = B;
+ B = M;
+ /* ... so we have 0 <= B < A again */
+
+ /* Since the former M is now B and the former B is now A,
+ * (**) translates into
+ * sign*Y*a == D*A + B (mod |n|),
+ * i.e.
+ * sign*Y*a - D*A == B (mod |n|).
+ * Similarly, (*) translates into
+ * -sign*X*a == A (mod |n|).
+ *
+ * Thus,
+ * sign*Y*a + D*sign*X*a == B (mod |n|),
+ * i.e.
+ * sign*(Y + D*X)*a == B (mod |n|).
+ *
+ * So if we set (X, Y, sign) := (Y + D*X, X, -sign), we arrive back at
+ * -sign*X*a == B (mod |n|),
+ * sign*Y*a == A (mod |n|).
+ * Note that X and Y stay non-negative all the time.
+ */
+
+ if (!BN_mul(tmp, D, X, ctx)) {
+ goto err;
+ }
+ if (!BN_add(tmp, tmp, Y)) {
+ goto err;
+ }
+
+ M = Y; /* keep the BIGNUM object, the value does not matter */
+ Y = X;
+ X = tmp;
+ sign = -sign;
+ }
+
+ /*
+ * The while loop (Euclid's algorithm) ends when
+ * A == gcd(a,n);
+ * we have
+ * sign*Y*a == A (mod |n|),
+ * where Y is non-negative.
+ */
+
+ if (sign < 0) {
+ if (!BN_sub(Y, n, Y)) {
+ goto err;
+ }
+ }
+ /* Now Y*a == A (mod |n|). */
+
+ if (BN_is_one(A)) {
+ /* Y*a == 1 (mod |n|) */
+ if (!Y->neg && BN_ucmp(Y, n) < 0) {
+ if (!BN_copy(R, Y)) {
+ goto err;
+ }
+ } else {
+ if (!BN_nnmod(R, Y, n, ctx)) {
+ goto err;
+ }
+ }
+ } else {
+ OPENSSL_PUT_ERROR(BN, BN_mod_inverse_no_branch, BN_R_NO_INVERSE);
+ goto err;
+ }
+ ret = R;
+
+err:
+ if (ret == NULL && out == NULL) {
+ BN_free(R);
+ }
+
+ BN_CTX_end(ctx);
+ return ret;
+}
diff --git a/crypto/bn/generic.c b/crypto/bn/generic.c
new file mode 100644
index 0000000..b745750
--- /dev/null
+++ b/crypto/bn/generic.c
@@ -0,0 +1,1189 @@
+/* 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/bn.h>
+
+#include <assert.h>
+
+#include "internal.h"
+
+
+#if defined(OPENSSL_WINDOWS) || defined(OPENSSL_NO_ASM) || \
+ (!defined(OPENSSL_X86_64) && !defined(OPENSSL_X86))
+
+#if defined(OPENSSL_WINDOWS)
+#define alloca _alloca
+#else
+#include <alloca.h>
+#endif
+
+#ifdef BN_LLONG
+#define mul_add(r, a, w, c) \
+ { \
+ BN_ULLONG t; \
+ t = (BN_ULLONG)w * (a) + (r) + (c); \
+ (r) = Lw(t); \
+ (c) = Hw(t); \
+ }
+
+#define mul(r, a, w, c) \
+ { \
+ BN_ULLONG t; \
+ t = (BN_ULLONG)w * (a) + (c); \
+ (r) = Lw(t); \
+ (c) = Hw(t); \
+ }
+
+#define sqr(r0, r1, a) \
+ { \
+ BN_ULLONG t; \
+ t = (BN_ULLONG)(a) * (a); \
+ (r0) = Lw(t); \
+ (r1) = Hw(t); \
+ }
+
+#elif defined(BN_UMULT_LOHI)
+#define mul_add(r, a, w, c) \
+ { \
+ BN_ULONG high, low, ret, tmp = (a); \
+ ret = (r); \
+ BN_UMULT_LOHI(low, high, w, tmp); \
+ ret += (c); \
+ (c) = (ret < (c)) ? 1 : 0; \
+ (c) += high; \
+ ret += low; \
+ (c) += (ret < low) ? 1 : 0; \
+ (r) = ret; \
+ }
+
+#define mul(r, a, w, c) \
+ { \
+ BN_ULONG high, low, ret, ta = (a); \
+ BN_UMULT_LOHI(low, high, w, ta); \
+ ret = low + (c); \
+ (c) = high; \
+ (c) += (ret < low) ? 1 : 0; \
+ (r) = ret; \
+ }
+
+#define sqr(r0, r1, a) \
+ { \
+ BN_ULONG tmp = (a); \
+ BN_UMULT_LOHI(r0, r1, tmp, tmp); \
+ }
+
+#elif defined(BN_UMULT_HIGH)
+#define mul_add(r, a, w, c) \
+ { \
+ BN_ULONG high, low, ret, tmp = (a); \
+ ret = (r); \
+ high = BN_UMULT_HIGH(w, tmp); \
+ ret += (c); \
+ low = (w) * tmp; \
+ (c) = (ret < (c)) ? 1 : 0; \
+ (c) += high; \
+ ret += low; \
+ (c) += (ret < low) ? 1 : 0; \
+ (r) = ret; \
+ }
+
+#define mul(r, a, w, c) \
+ { \
+ BN_ULONG high, low, ret, ta = (a); \
+ low = (w) * ta; \
+ high = BN_UMULT_HIGH(w, ta); \
+ ret = low + (c); \
+ (c) = high; \
+ (c) += (ret < low) ? 1 : 0; \
+ (r) = ret; \
+ }
+
+#define sqr(r0, r1, a) \
+ { \
+ BN_ULONG tmp = (a); \
+ (r0) = tmp * tmp; \
+ (r1) = BN_UMULT_HIGH(tmp, tmp); \
+ }
+
+#else
+/*************************************************************
+ * No long long type
+ */
+
+#define LBITS(a) ((a) & BN_MASK2l)
+#define HBITS(a) (((a) >> BN_BITS4) & BN_MASK2l)
+#define L2HBITS(a) (((a) << BN_BITS4) & BN_MASK2)
+
+#define LLBITS(a) ((a) & BN_MASKl)
+#define LHBITS(a) (((a) >> BN_BITS2) & BN_MASKl)
+#define LL2HBITS(a) ((BN_ULLONG)((a) & BN_MASKl) << BN_BITS2)
+
+#define mul64(l, h, bl, bh) \
+ { \
+ BN_ULONG m, m1, lt, ht; \
+ \
+ lt = l; \
+ ht = h; \
+ m = (bh) * (lt); \
+ lt = (bl) * (lt); \
+ m1 = (bl) * (ht); \
+ ht = (bh) * (ht); \
+ m = (m + m1) & BN_MASK2; \
+ if (m < m1) \
+ ht += L2HBITS((BN_ULONG)1); \
+ ht += HBITS(m); \
+ m1 = L2HBITS(m); \
+ lt = (lt + m1) & BN_MASK2; \
+ if (lt < m1) \
+ ht++; \
+ (l) = lt; \
+ (h) = ht; \
+ }
+
+#define sqr64(lo, ho, in) \
+ { \
+ BN_ULONG l, h, m; \
+ \
+ h = (in); \
+ l = LBITS(h); \
+ h = HBITS(h); \
+ m = (l) * (h); \
+ l *= l; \
+ h *= h; \
+ h += (m & BN_MASK2h1) >> (BN_BITS4 - 1); \
+ m = (m & BN_MASK2l) << (BN_BITS4 + 1); \
+ l = (l + m) & BN_MASK2; \
+ if (l < m) \
+ h++; \
+ (lo) = l; \
+ (ho) = h; \
+ }
+
+#define mul_add(r, a, bl, bh, c) \
+ { \
+ BN_ULONG l, h; \
+ \
+ h = (a); \
+ l = LBITS(h); \
+ h = HBITS(h); \
+ mul64(l, h, (bl), (bh)); \
+ \
+ /* non-multiply part */ \
+ l = (l + (c)) & BN_MASK2; \
+ if (l < (c)) \
+ h++; \
+ (c) = (r); \
+ l = (l + (c)) & BN_MASK2; \
+ if (l < (c)) \
+ h++; \
+ (c) = h & BN_MASK2; \
+ (r) = l; \
+ }
+
+#define mul(r, a, bl, bh, c) \
+ { \
+ BN_ULONG l, h; \
+ \
+ h = (a); \
+ l = LBITS(h); \
+ h = HBITS(h); \
+ mul64(l, h, (bl), (bh)); \
+ \
+ /* non-multiply part */ \
+ l += (c); \
+ if ((l & BN_MASK2) < (c)) \
+ h++; \
+ (c) = h & BN_MASK2; \
+ (r) = l & BN_MASK2; \
+ }
+#endif /* !BN_LLONG */
+
+#if defined(BN_LLONG) || defined(BN_UMULT_HIGH)
+
+BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num,
+ BN_ULONG w) {
+ BN_ULONG c1 = 0;
+
+ assert(num >= 0);
+ if (num <= 0) {
+ return c1;
+ }
+
+ while (num & ~3) {
+ mul_add(rp[0], ap[0], w, c1);
+ mul_add(rp[1], ap[1], w, c1);
+ mul_add(rp[2], ap[2], w, c1);
+ mul_add(rp[3], ap[3], w, c1);
+ ap += 4;
+ rp += 4;
+ num -= 4;
+ }
+
+ while (num) {
+ mul_add(rp[0], ap[0], w, c1);
+ ap++;
+ rp++;
+ num--;
+ }
+
+ return c1;
+}
+
+BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w) {
+ BN_ULONG c1 = 0;
+
+ assert(num >= 0);
+ if (num <= 0) {
+ return c1;
+ }
+
+ while (num & ~3) {
+ mul(rp[0], ap[0], w, c1);
+ mul(rp[1], ap[1], w, c1);
+ mul(rp[2], ap[2], w, c1);
+ mul(rp[3], ap[3], w, c1);
+ ap += 4;
+ rp += 4;
+ num -= 4;
+ }
+ while (num) {
+ mul(rp[0], ap[0], w, c1);
+ ap++;
+ rp++;
+ num--;
+ }
+ return c1;
+}
+
+void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, int n) {
+ assert(n >= 0);
+ if (n <= 0) {
+ return;
+ }
+
+ while (n & ~3) {
+ sqr(r[0], r[1], a[0]);
+ sqr(r[2], r[3], a[1]);
+ sqr(r[4], r[5], a[2]);
+ sqr(r[6], r[7], a[3]);
+ a += 4;
+ r += 8;
+ n -= 4;
+ }
+ while (n) {
+ sqr(r[0], r[1], a[0]);
+ a++;
+ r += 2;
+ n--;
+ }
+}
+
+#else /* !(defined(BN_LLONG) || defined(BN_UMULT_HIGH)) */
+
+BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num,
+ BN_ULONG w) {
+ BN_ULONG c = 0;
+ BN_ULONG bl, bh;
+
+ assert(num >= 0);
+ if (num <= 0) {
+ return (BN_ULONG)0;
+ }
+
+ bl = LBITS(w);
+ bh = HBITS(w);
+
+ while (num & ~3) {
+ mul_add(rp[0], ap[0], bl, bh, c);
+ mul_add(rp[1], ap[1], bl, bh, c);
+ mul_add(rp[2], ap[2], bl, bh, c);
+ mul_add(rp[3], ap[3], bl, bh, c);
+ ap += 4;
+ rp += 4;
+ num -= 4;
+ }
+ while (num) {
+ mul_add(rp[0], ap[0], bl, bh, c);
+ ap++;
+ rp++;
+ num--;
+ }
+ return c;
+}
+
+BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w) {
+ BN_ULONG carry = 0;
+ BN_ULONG bl, bh;
+
+ assert(num >= 0);
+ if (num <= 0) {
+ return (BN_ULONG)0;
+ }
+
+ bl = LBITS(w);
+ bh = HBITS(w);
+
+ while (num & ~3) {
+ mul(rp[0], ap[0], bl, bh, carry);
+ mul(rp[1], ap[1], bl, bh, carry);
+ mul(rp[2], ap[2], bl, bh, carry);
+ mul(rp[3], ap[3], bl, bh, carry);
+ ap += 4;
+ rp += 4;
+ num -= 4;
+ }
+ while (num) {
+ mul(rp[0], ap[0], bl, bh, carry);
+ ap++;
+ rp++;
+ num--;
+ }
+ return carry;
+}
+
+void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, int n) {
+ assert(n >= 0);
+ if (n <= 0) {
+ return;
+ }
+
+ while (n & ~3) {
+ sqr64(r[0], r[1], a[0]);
+ sqr64(r[2], r[3], a[1]);
+ sqr64(r[4], r[5], a[2]);
+ sqr64(r[6], r[7], a[3]);
+ a += 4;
+ r += 8;
+ n -= 4;
+ }
+ while (n) {
+ sqr64(r[0], r[1], a[0]);
+ a++;
+ r += 2;
+ n--;
+ }
+}
+
+#endif /* !(defined(BN_LLONG) || defined(BN_UMULT_HIGH)) */
+
+#if defined(BN_LLONG) && defined(BN_DIV2W)
+
+BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d) {
+ return (BN_ULONG)(((((BN_ULLONG)h) << BN_BITS2) | l) / (BN_ULLONG)d);
+}
+
+#else
+
+/* Divide h,l by d and return the result. */
+BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d) {
+ BN_ULONG dh, dl, q, ret = 0, th, tl, t;
+ int i, count = 2;
+
+ if (d == 0) {
+ return BN_MASK2;
+ }
+
+ i = BN_num_bits_word(d);
+ assert((i == BN_BITS2) || (h <= (BN_ULONG)1 << i));
+
+ i = BN_BITS2 - i;
+ if (h >= d) {
+ h -= d;
+ }
+
+ if (i) {
+ d <<= i;
+ h = (h << i) | (l >> (BN_BITS2 - i));
+ l <<= i;
+ }
+ dh = (d & BN_MASK2h) >> BN_BITS4;
+ dl = (d & BN_MASK2l);
+ for (;;) {
+ if ((h >> BN_BITS4) == dh) {
+ q = BN_MASK2l;
+ } else {
+ q = h / dh;
+ }
+
+ th = q * dh;
+ tl = dl * q;
+ for (;;) {
+ t = h - th;
+ if ((t & BN_MASK2h) ||
+ ((tl) <= ((t << BN_BITS4) | ((l & BN_MASK2h) >> BN_BITS4)))) {
+ break;
+ }
+ q--;
+ th -= dh;
+ tl -= dl;
+ }
+ t = (tl >> BN_BITS4);
+ tl = (tl << BN_BITS4) & BN_MASK2h;
+ th += t;
+
+ if (l < tl) {
+ th++;
+ }
+ l -= tl;
+ if (h < th) {
+ h += d;
+ q--;
+ }
+ h -= th;
+
+ if (--count == 0) {
+ break;
+ }
+
+ ret = q << BN_BITS4;
+ h = ((h << BN_BITS4) | (l >> BN_BITS4)) & BN_MASK2;
+ l = (l & BN_MASK2l) << BN_BITS4;
+ }
+
+ ret |= q;
+ return ret;
+}
+
+#endif /* !defined(BN_LLONG) && defined(BN_DIV2W) */
+
+#ifdef BN_LLONG
+BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
+ int n) {
+ BN_ULLONG ll = 0;
+
+ assert(n >= 0);
+ if (n <= 0) {
+ return (BN_ULONG)0;
+ }
+
+ while (n & ~3) {
+ ll += (BN_ULLONG)a[0] + b[0];
+ r[0] = (BN_ULONG)ll & BN_MASK2;
+ ll >>= BN_BITS2;
+ ll += (BN_ULLONG)a[1] + b[1];
+ r[1] = (BN_ULONG)ll & BN_MASK2;
+ ll >>= BN_BITS2;
+ ll += (BN_ULLONG)a[2] + b[2];
+ r[2] = (BN_ULONG)ll & BN_MASK2;
+ ll >>= BN_BITS2;
+ ll += (BN_ULLONG)a[3] + b[3];
+ r[3] = (BN_ULONG)ll & BN_MASK2;
+ ll >>= BN_BITS2;
+ a += 4;
+ b += 4;
+ r += 4;
+ n -= 4;
+ }
+ while (n) {
+ ll += (BN_ULLONG)a[0] + b[0];
+ r[0] = (BN_ULONG)ll & BN_MASK2;
+ ll >>= BN_BITS2;
+ a++;
+ b++;
+ r++;
+ n--;
+ }
+ return (BN_ULONG)ll;
+}
+
+#else /* !BN_LLONG */
+
+BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
+ int n) {
+ BN_ULONG c, l, t;
+
+ assert(n >= 0);
+ if (n <= 0) {
+ return (BN_ULONG)0;
+ }
+
+ c = 0;
+ while (n & ~3) {
+ t = a[0];
+ t = (t + c) & BN_MASK2;
+ c = (t < c);
+ l = (t + b[0]) & BN_MASK2;
+ c += (l < t);
+ r[0] = l;
+ t = a[1];
+ t = (t + c) & BN_MASK2;
+ c = (t < c);
+ l = (t + b[1]) & BN_MASK2;
+ c += (l < t);
+ r[1] = l;
+ t = a[2];
+ t = (t + c) & BN_MASK2;
+ c = (t < c);
+ l = (t + b[2]) & BN_MASK2;
+ c += (l < t);
+ r[2] = l;
+ t = a[3];
+ t = (t + c) & BN_MASK2;
+ c = (t < c);
+ l = (t + b[3]) & BN_MASK2;
+ c += (l < t);
+ r[3] = l;
+ a += 4;
+ b += 4;
+ r += 4;
+ n -= 4;
+ }
+ while (n) {
+ t = a[0];
+ t = (t + c) & BN_MASK2;
+ c = (t < c);
+ l = (t + b[0]) & BN_MASK2;
+ c += (l < t);
+ r[0] = l;
+ a++;
+ b++;
+ r++;
+ n--;
+ }
+ return (BN_ULONG)c;
+}
+
+#endif /* !BN_LLONG */
+
+BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
+ int n) {
+ BN_ULONG t1, t2;
+ int c = 0;
+
+ assert(n >= 0);
+ if (n <= 0) {
+ return (BN_ULONG)0;
+ }
+
+ while (n & ~3) {
+ t1 = a[0];
+ t2 = b[0];
+ r[0] = (t1 - t2 - c) & BN_MASK2;
+ if (t1 != t2)
+ c = (t1 < t2);
+ t1 = a[1];
+ t2 = b[1];
+ r[1] = (t1 - t2 - c) & BN_MASK2;
+ if (t1 != t2)
+ c = (t1 < t2);
+ t1 = a[2];
+ t2 = b[2];
+ r[2] = (t1 - t2 - c) & BN_MASK2;
+ if (t1 != t2)
+ c = (t1 < t2);
+ t1 = a[3];
+ t2 = b[3];
+ r[3] = (t1 - t2 - c) & BN_MASK2;
+ if (t1 != t2)
+ c = (t1 < t2);
+ a += 4;
+ b += 4;
+ r += 4;
+ n -= 4;
+ }
+ while (n) {
+ t1 = a[0];
+ t2 = b[0];
+ r[0] = (t1 - t2 - c) & BN_MASK2;
+ if (t1 != t2)
+ c = (t1 < t2);
+ a++;
+ b++;
+ r++;
+ n--;
+ }
+ return c;
+}
+
+/* mul_add_c(a,b,c0,c1,c2) -- c+=a*b for three word number c=(c2,c1,c0) */
+/* mul_add_c2(a,b,c0,c1,c2) -- c+=2*a*b for three word number c=(c2,c1,c0) */
+/* sqr_add_c(a,i,c0,c1,c2) -- c+=a[i]^2 for three word number c=(c2,c1,c0) */
+/* sqr_add_c2(a,i,c0,c1,c2) -- c+=2*a[i]*a[j] for three word number c=(c2,c1,c0) */
+
+#ifdef BN_LLONG
+#define mul_add_c(a, b, c0, c1, c2) \
+ t = (BN_ULLONG)a * b; \
+ t1 = (BN_ULONG)Lw(t); \
+ t2 = (BN_ULONG)Hw(t); \
+ c0 = (c0 + t1) & BN_MASK2; \
+ if ((c0) < t1) \
+ t2++; \
+ c1 = (c1 + t2) & BN_MASK2; \
+ if ((c1) < t2) \
+ c2++;
+
+#define mul_add_c2(a, b, c0, c1, c2) \
+ t = (BN_ULLONG)a * b; \
+ tt = (t + t) & BN_MASK; \
+ if (tt < t) \
+ c2++; \
+ t1 = (BN_ULONG)Lw(tt); \
+ t2 = (BN_ULONG)Hw(tt); \
+ c0 = (c0 + t1) & BN_MASK2; \
+ if ((c0 < t1) && (((++t2) & BN_MASK2) == 0)) \
+ c2++; \
+ c1 = (c1 + t2) & BN_MASK2; \
+ if ((c1) < t2) \
+ c2++;
+
+#define sqr_add_c(a, i, c0, c1, c2) \
+ t = (BN_ULLONG)a[i] * a[i]; \
+ t1 = (BN_ULONG)Lw(t); \
+ t2 = (BN_ULONG)Hw(t); \
+ c0 = (c0 + t1) & BN_MASK2; \
+ if ((c0) < t1) \
+ t2++; \
+ c1 = (c1 + t2) & BN_MASK2; \
+ if ((c1) < t2) \
+ c2++;
+
+#define sqr_add_c2(a, i, j, c0, c1, c2) mul_add_c2((a)[i], (a)[j], c0, c1, c2)
+
+#elif defined(BN_UMULT_LOHI)
+
+#define mul_add_c(a, b, c0, c1, c2) \
+ { \
+ BN_ULONG ta = (a), tb = (b); \
+ BN_UMULT_LOHI(t1, t2, ta, tb); \
+ c0 += t1; \
+ t2 += (c0 < t1) ? 1 : 0; \
+ c1 += t2; \
+ c2 += (c1 < t2) ? 1 : 0; \
+ }
+
+#define mul_add_c2(a, b, c0, c1, c2) \
+ { \
+ BN_ULONG ta = (a), tb = (b), t0; \
+ BN_UMULT_LOHI(t0, t1, ta, tb); \
+ t2 = t1 + t1; \
+ c2 += (t2 < t1) ? 1 : 0; \
+ t1 = t0 + t0; \
+ t2 += (t1 < t0) ? 1 : 0; \
+ c0 += t1; \
+ t2 += (c0 < t1) ? 1 : 0; \
+ c1 += t2; \
+ c2 += (c1 < t2) ? 1 : 0; \
+ }
+
+#define sqr_add_c(a, i, c0, c1, c2) \
+ { \
+ BN_ULONG ta = (a)[i]; \
+ BN_UMULT_LOHI(t1, t2, ta, ta); \
+ c0 += t1; \
+ t2 += (c0 < t1) ? 1 : 0; \
+ c1 += t2; \
+ c2 += (c1 < t2) ? 1 : 0; \
+ }
+
+#define sqr_add_c2(a, i, j, c0, c1, c2) mul_add_c2((a)[i], (a)[j], c0, c1, c2)
+
+#elif defined(BN_UMULT_HIGH)
+
+#define mul_add_c(a, b, c0, c1, c2) \
+ { \
+ BN_ULONG ta = (a), tb = (b); \
+ t1 = ta * tb; \
+ t2 = BN_UMULT_HIGH(ta, tb); \
+ c0 += t1; \
+ t2 += (c0 < t1) ? 1 : 0; \
+ c1 += t2; \
+ c2 += (c1 < t2) ? 1 : 0; \
+ }
+
+#define mul_add_c2(a, b, c0, c1, c2) \
+ { \
+ BN_ULONG ta = (a), tb = (b), t0; \
+ t1 = BN_UMULT_HIGH(ta, tb); \
+ t0 = ta * tb; \
+ t2 = t1 + t1; \
+ c2 += (t2 < t1) ? 1 : 0; \
+ t1 = t0 + t0; \
+ t2 += (t1 < t0) ? 1 : 0; \
+ c0 += t1; \
+ t2 += (c0 < t1) ? 1 : 0; \
+ c1 += t2; \
+ c2 += (c1 < t2) ? 1 : 0; \
+ }
+
+#define sqr_add_c(a, i, c0, c1, c2) \
+ { \
+ BN_ULONG ta = (a)[i]; \
+ t1 = ta * ta; \
+ t2 = BN_UMULT_HIGH(ta, ta); \
+ c0 += t1; \
+ t2 += (c0 < t1) ? 1 : 0; \
+ c1 += t2; \
+ c2 += (c1 < t2) ? 1 : 0; \
+ }
+
+#define sqr_add_c2(a, i, j, c0, c1, c2) mul_add_c2((a)[i], (a)[j], c0, c1, c2)
+
+#else /* !BN_LLONG */
+#define mul_add_c(a, b, c0, c1, c2) \
+ t1 = LBITS(a); \
+ t2 = HBITS(a); \
+ bl = LBITS(b); \
+ bh = HBITS(b); \
+ mul64(t1, t2, bl, bh); \
+ c0 = (c0 + t1) & BN_MASK2; \
+ if ((c0) < t1) \
+ t2++; \
+ c1 = (c1 + t2) & BN_MASK2; \
+ if ((c1) < t2) \
+ c2++;
+
+#define mul_add_c2(a, b, c0, c1, c2) \
+ t1 = LBITS(a); \
+ t2 = HBITS(a); \
+ bl = LBITS(b); \
+ bh = HBITS(b); \
+ mul64(t1, t2, bl, bh); \
+ if (t2 & BN_TBIT) \
+ c2++; \
+ t2 = (t2 + t2) & BN_MASK2; \
+ if (t1 & BN_TBIT) \
+ t2++; \
+ t1 = (t1 + t1) & BN_MASK2; \
+ c0 = (c0 + t1) & BN_MASK2; \
+ if ((c0 < t1) && (((++t2) & BN_MASK2) == 0)) \
+ c2++; \
+ c1 = (c1 + t2) & BN_MASK2; \
+ if ((c1) < t2) \
+ c2++;
+
+#define sqr_add_c(a, i, c0, c1, c2) \
+ sqr64(t1, t2, (a)[i]); \
+ c0 = (c0 + t1) & BN_MASK2; \
+ if ((c0) < t1) \
+ t2++; \
+ c1 = (c1 + t2) & BN_MASK2; \
+ if ((c1) < t2) \
+ c2++;
+
+#define sqr_add_c2(a, i, j, c0, c1, c2) mul_add_c2((a)[i], (a)[j], c0, c1, c2)
+#endif /* !BN_LLONG */
+
+void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) {
+#ifdef BN_LLONG
+ BN_ULLONG t;
+#else
+ BN_ULONG bl, bh;
+#endif
+ BN_ULONG t1, t2;
+ BN_ULONG c1, c2, c3;
+
+ c1 = 0;
+ c2 = 0;
+ c3 = 0;
+ mul_add_c(a[0], b[0], c1, c2, c3);
+ r[0] = c1;
+ c1 = 0;
+ mul_add_c(a[0], b[1], c2, c3, c1);
+ mul_add_c(a[1], b[0], c2, c3, c1);
+ r[1] = c2;
+ c2 = 0;
+ mul_add_c(a[2], b[0], c3, c1, c2);
+ mul_add_c(a[1], b[1], c3, c1, c2);
+ mul_add_c(a[0], b[2], c3, c1, c2);
+ r[2] = c3;
+ c3 = 0;
+ mul_add_c(a[0], b[3], c1, c2, c3);
+ mul_add_c(a[1], b[2], c1, c2, c3);
+ mul_add_c(a[2], b[1], c1, c2, c3);
+ mul_add_c(a[3], b[0], c1, c2, c3);
+ r[3] = c1;
+ c1 = 0;
+ mul_add_c(a[4], b[0], c2, c3, c1);
+ mul_add_c(a[3], b[1], c2, c3, c1);
+ mul_add_c(a[2], b[2], c2, c3, c1);
+ mul_add_c(a[1], b[3], c2, c3, c1);
+ mul_add_c(a[0], b[4], c2, c3, c1);
+ r[4] = c2;
+ c2 = 0;
+ mul_add_c(a[0], b[5], c3, c1, c2);
+ mul_add_c(a[1], b[4], c3, c1, c2);
+ mul_add_c(a[2], b[3], c3, c1, c2);
+ mul_add_c(a[3], b[2], c3, c1, c2);
+ mul_add_c(a[4], b[1], c3, c1, c2);
+ mul_add_c(a[5], b[0], c3, c1, c2);
+ r[5] = c3;
+ c3 = 0;
+ mul_add_c(a[6], b[0], c1, c2, c3);
+ mul_add_c(a[5], b[1], c1, c2, c3);
+ mul_add_c(a[4], b[2], c1, c2, c3);
+ mul_add_c(a[3], b[3], c1, c2, c3);
+ mul_add_c(a[2], b[4], c1, c2, c3);
+ mul_add_c(a[1], b[5], c1, c2, c3);
+ mul_add_c(a[0], b[6], c1, c2, c3);
+ r[6] = c1;
+ c1 = 0;
+ mul_add_c(a[0], b[7], c2, c3, c1);
+ mul_add_c(a[1], b[6], c2, c3, c1);
+ mul_add_c(a[2], b[5], c2, c3, c1);
+ mul_add_c(a[3], b[4], c2, c3, c1);
+ mul_add_c(a[4], b[3], c2, c3, c1);
+ mul_add_c(a[5], b[2], c2, c3, c1);
+ mul_add_c(a[6], b[1], c2, c3, c1);
+ mul_add_c(a[7], b[0], c2, c3, c1);
+ r[7] = c2;
+ c2 = 0;
+ mul_add_c(a[7], b[1], c3, c1, c2);
+ mul_add_c(a[6], b[2], c3, c1, c2);
+ mul_add_c(a[5], b[3], c3, c1, c2);
+ mul_add_c(a[4], b[4], c3, c1, c2);
+ mul_add_c(a[3], b[5], c3, c1, c2);
+ mul_add_c(a[2], b[6], c3, c1, c2);
+ mul_add_c(a[1], b[7], c3, c1, c2);
+ r[8] = c3;
+ c3 = 0;
+ mul_add_c(a[2], b[7], c1, c2, c3);
+ mul_add_c(a[3], b[6], c1, c2, c3);
+ mul_add_c(a[4], b[5], c1, c2, c3);
+ mul_add_c(a[5], b[4], c1, c2, c3);
+ mul_add_c(a[6], b[3], c1, c2, c3);
+ mul_add_c(a[7], b[2], c1, c2, c3);
+ r[9] = c1;
+ c1 = 0;
+ mul_add_c(a[7], b[3], c2, c3, c1);
+ mul_add_c(a[6], b[4], c2, c3, c1);
+ mul_add_c(a[5], b[5], c2, c3, c1);
+ mul_add_c(a[4], b[6], c2, c3, c1);
+ mul_add_c(a[3], b[7], c2, c3, c1);
+ r[10] = c2;
+ c2 = 0;
+ mul_add_c(a[4], b[7], c3, c1, c2);
+ mul_add_c(a[5], b[6], c3, c1, c2);
+ mul_add_c(a[6], b[5], c3, c1, c2);
+ mul_add_c(a[7], b[4], c3, c1, c2);
+ r[11] = c3;
+ c3 = 0;
+ mul_add_c(a[7], b[5], c1, c2, c3);
+ mul_add_c(a[6], b[6], c1, c2, c3);
+ mul_add_c(a[5], b[7], c1, c2, c3);
+ r[12] = c1;
+ c1 = 0;
+ mul_add_c(a[6], b[7], c2, c3, c1);
+ mul_add_c(a[7], b[6], c2, c3, c1);
+ r[13] = c2;
+ c2 = 0;
+ mul_add_c(a[7], b[7], c3, c1, c2);
+ r[14] = c3;
+ r[15] = c1;
+}
+
+void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) {
+#ifdef BN_LLONG
+ BN_ULLONG t;
+#else
+ BN_ULONG bl, bh;
+#endif
+ BN_ULONG t1, t2;
+ BN_ULONG c1, c2, c3;
+
+ c1 = 0;
+ c2 = 0;
+ c3 = 0;
+ mul_add_c(a[0], b[0], c1, c2, c3);
+ r[0] = c1;
+ c1 = 0;
+ mul_add_c(a[0], b[1], c2, c3, c1);
+ mul_add_c(a[1], b[0], c2, c3, c1);
+ r[1] = c2;
+ c2 = 0;
+ mul_add_c(a[2], b[0], c3, c1, c2);
+ mul_add_c(a[1], b[1], c3, c1, c2);
+ mul_add_c(a[0], b[2], c3, c1, c2);
+ r[2] = c3;
+ c3 = 0;
+ mul_add_c(a[0], b[3], c1, c2, c3);
+ mul_add_c(a[1], b[2], c1, c2, c3);
+ mul_add_c(a[2], b[1], c1, c2, c3);
+ mul_add_c(a[3], b[0], c1, c2, c3);
+ r[3] = c1;
+ c1 = 0;
+ mul_add_c(a[3], b[1], c2, c3, c1);
+ mul_add_c(a[2], b[2], c2, c3, c1);
+ mul_add_c(a[1], b[3], c2, c3, c1);
+ r[4] = c2;
+ c2 = 0;
+ mul_add_c(a[2], b[3], c3, c1, c2);
+ mul_add_c(a[3], b[2], c3, c1, c2);
+ r[5] = c3;
+ c3 = 0;
+ mul_add_c(a[3], b[3], c1, c2, c3);
+ r[6] = c1;
+ r[7] = c2;
+}
+
+void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a) {
+#ifdef BN_LLONG
+ BN_ULLONG t, tt;
+#else
+ BN_ULONG bl, bh;
+#endif
+ BN_ULONG t1, t2;
+ BN_ULONG c1, c2, c3;
+
+ c1 = 0;
+ c2 = 0;
+ c3 = 0;
+ sqr_add_c(a, 0, c1, c2, c3);
+ r[0] = c1;
+ c1 = 0;
+ sqr_add_c2(a, 1, 0, c2, c3, c1);
+ r[1] = c2;
+ c2 = 0;
+ sqr_add_c(a, 1, c3, c1, c2);
+ sqr_add_c2(a, 2, 0, c3, c1, c2);
+ r[2] = c3;
+ c3 = 0;
+ sqr_add_c2(a, 3, 0, c1, c2, c3);
+ sqr_add_c2(a, 2, 1, c1, c2, c3);
+ r[3] = c1;
+ c1 = 0;
+ sqr_add_c(a, 2, c2, c3, c1);
+ sqr_add_c2(a, 3, 1, c2, c3, c1);
+ sqr_add_c2(a, 4, 0, c2, c3, c1);
+ r[4] = c2;
+ c2 = 0;
+ sqr_add_c2(a, 5, 0, c3, c1, c2);
+ sqr_add_c2(a, 4, 1, c3, c1, c2);
+ sqr_add_c2(a, 3, 2, c3, c1, c2);
+ r[5] = c3;
+ c3 = 0;
+ sqr_add_c(a, 3, c1, c2, c3);
+ sqr_add_c2(a, 4, 2, c1, c2, c3);
+ sqr_add_c2(a, 5, 1, c1, c2, c3);
+ sqr_add_c2(a, 6, 0, c1, c2, c3);
+ r[6] = c1;
+ c1 = 0;
+ sqr_add_c2(a, 7, 0, c2, c3, c1);
+ sqr_add_c2(a, 6, 1, c2, c3, c1);
+ sqr_add_c2(a, 5, 2, c2, c3, c1);
+ sqr_add_c2(a, 4, 3, c2, c3, c1);
+ r[7] = c2;
+ c2 = 0;
+ sqr_add_c(a, 4, c3, c1, c2);
+ sqr_add_c2(a, 5, 3, c3, c1, c2);
+ sqr_add_c2(a, 6, 2, c3, c1, c2);
+ sqr_add_c2(a, 7, 1, c3, c1, c2);
+ r[8] = c3;
+ c3 = 0;
+ sqr_add_c2(a, 7, 2, c1, c2, c3);
+ sqr_add_c2(a, 6, 3, c1, c2, c3);
+ sqr_add_c2(a, 5, 4, c1, c2, c3);
+ r[9] = c1;
+ c1 = 0;
+ sqr_add_c(a, 5, c2, c3, c1);
+ sqr_add_c2(a, 6, 4, c2, c3, c1);
+ sqr_add_c2(a, 7, 3, c2, c3, c1);
+ r[10] = c2;
+ c2 = 0;
+ sqr_add_c2(a, 7, 4, c3, c1, c2);
+ sqr_add_c2(a, 6, 5, c3, c1, c2);
+ r[11] = c3;
+ c3 = 0;
+ sqr_add_c(a, 6, c1, c2, c3);
+ sqr_add_c2(a, 7, 5, c1, c2, c3);
+ r[12] = c1;
+ c1 = 0;
+ sqr_add_c2(a, 7, 6, c2, c3, c1);
+ r[13] = c2;
+ c2 = 0;
+ sqr_add_c(a, 7, c3, c1, c2);
+ r[14] = c3;
+ r[15] = c1;
+}
+
+void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a) {
+#ifdef BN_LLONG
+ BN_ULLONG t, tt;
+#else
+ BN_ULONG bl, bh;
+#endif
+ BN_ULONG t1, t2;
+ BN_ULONG c1, c2, c3;
+
+ c1 = 0;
+ c2 = 0;
+ c3 = 0;
+ sqr_add_c(a, 0, c1, c2, c3);
+ r[0] = c1;
+ c1 = 0;
+ sqr_add_c2(a, 1, 0, c2, c3, c1);
+ r[1] = c2;
+ c2 = 0;
+ sqr_add_c(a, 1, c3, c1, c2);
+ sqr_add_c2(a, 2, 0, c3, c1, c2);
+ r[2] = c3;
+ c3 = 0;
+ sqr_add_c2(a, 3, 0, c1, c2, c3);
+ sqr_add_c2(a, 2, 1, c1, c2, c3);
+ r[3] = c1;
+ c1 = 0;
+ sqr_add_c(a, 2, c2, c3, c1);
+ sqr_add_c2(a, 3, 1, c2, c3, c1);
+ r[4] = c2;
+ c2 = 0;
+ sqr_add_c2(a, 3, 2, c3, c1, c2);
+ r[5] = c3;
+ c3 = 0;
+ sqr_add_c(a, 3, c1, c2, c3);
+ r[6] = c1;
+ r[7] = c2;
+}
+
+#if defined(OPENSSL_NO_ASM) || (!defined(OPENSSL_ARM) && !defined(OPENSSL_X86_64))
+/* This is essentially reference implementation, which may or may not
+ * result in performance improvement. E.g. on IA-32 this routine was
+ * observed to give 40% faster rsa1024 private key operations and 10%
+ * faster rsa4096 ones, while on AMD64 it improves rsa1024 sign only
+ * by 10% and *worsens* rsa4096 sign by 15%. Once again, it's a
+ * reference implementation, one to be used as starting point for
+ * platform-specific assembler. Mentioned numbers apply to compiler
+ * generated code compiled with and without -DOPENSSL_BN_ASM_MONT and
+ * can vary not only from platform to platform, but even for compiler
+ * versions. Assembler vs. assembler improvement coefficients can
+ * [and are known to] differ and are to be documented elsewhere. */
+int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
+ const BN_ULONG *np, const BN_ULONG *n0p, int num) {
+ BN_ULONG c0, c1, ml, *tp, n0;
+#ifdef mul64
+ BN_ULONG mh;
+#endif
+ volatile BN_ULONG *vp;
+ int i = 0, j;
+
+#if 0 /* template for platform-specific implementation */
+ if (ap==bp) return bn_sqr_mont(rp,ap,np,n0p,num);
+#endif
+ vp = tp = alloca((num + 2) * sizeof(BN_ULONG));
+
+ n0 = *n0p;
+
+ c0 = 0;
+ ml = bp[0];
+#ifdef mul64
+ mh = HBITS(ml);
+ ml = LBITS(ml);
+ for (j = 0; j < num; ++j)
+ mul(tp[j], ap[j], ml, mh, c0);
+#else
+ for (j = 0; j < num; ++j)
+ mul(tp[j], ap[j], ml, c0);
+#endif
+
+ tp[num] = c0;
+ tp[num + 1] = 0;
+ goto enter;
+
+ for (i = 0; i < num; i++) {
+ c0 = 0;
+ ml = bp[i];
+#ifdef mul64
+ mh = HBITS(ml);
+ ml = LBITS(ml);
+ for (j = 0; j < num; ++j)
+ mul_add(tp[j], ap[j], ml, mh, c0);
+#else
+ for (j = 0; j < num; ++j)
+ mul_add(tp[j], ap[j], ml, c0);
+#endif
+ c1 = (tp[num] + c0) & BN_MASK2;
+ tp[num] = c1;
+ tp[num + 1] = (c1 < c0 ? 1 : 0);
+ enter:
+ c1 = tp[0];
+ ml = (c1 * n0) & BN_MASK2;
+ c0 = 0;
+#ifdef mul64
+ mh = HBITS(ml);
+ ml = LBITS(ml);
+ mul_add(c1, np[0], ml, mh, c0);
+#else
+ mul_add(c1, ml, np[0], c0);
+#endif
+ for (j = 1; j < num; j++) {
+ c1 = tp[j];
+#ifdef mul64
+ mul_add(c1, np[j], ml, mh, c0);
+#else
+ mul_add(c1, ml, np[j], c0);
+#endif
+ tp[j - 1] = c1 & BN_MASK2;
+ }
+ c1 = (tp[num] + c0) & BN_MASK2;
+ tp[num - 1] = c1;
+ tp[num] = tp[num + 1] + (c1 < c0 ? 1 : 0);
+ }
+
+ if (tp[num] != 0 || tp[num - 1] >= np[num - 1]) {
+ c0 = bn_sub_words(rp, tp, np, num);
+ if (tp[num] != 0 || c0 == 0) {
+ for (i = 0; i < num + 2; i++)
+ vp[i] = 0;
+ return 1;
+ }
+ }
+ for (i = 0; i < num; i++)
+ rp[i] = tp[i], vp[i] = 0;
+ vp[num] = 0;
+ vp[num + 1] = 0;
+ return 1;
+}
+#endif
+
+#endif
diff --git a/crypto/bn/internal.h b/crypto/bn/internal.h
new file mode 100644
index 0000000..3d6d75d
--- /dev/null
+++ b/crypto/bn/internal.h
@@ -0,0 +1,291 @@
+/* Copyright (C) 1995-1997 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.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2006 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).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the Eric Young open source
+ * license provided above.
+ *
+ * The binary polynomial arithmetic software is originally written by
+ * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems
+ * Laboratories. */
+
+#ifndef OPENSSL_HEADER_BN_INTERNAL_H
+#define OPENSSL_HEADER_BN_INTERNAL_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* BN_wexpand ensures that |bn| has at least |words| works of space without
+ * altering its value. It returns one on success or zero on allocation
+ * failure. */
+BIGNUM *bn_wexpand(BIGNUM *bn, unsigned words);
+
+/* 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);
+
+/* bn_correct_top decrements |bn->top| until |bn->d[top-1]| is non-zero or
+ * until |top| is zero. */
+void bn_correct_top(BIGNUM *bn);
+
+#if defined(OPENSSL_64_BIT)
+
+#define BN_ULLONG unsigned long long
+#define BN_LONG long
+#define BN_BITS 128
+#define BN_BYTES 8
+#define BN_BITS4 32
+#define BN_MASK (0xffffffffffffffffffffffffffffffffLL)
+#define BN_MASK2 (0xffffffffffffffffL)
+#define BN_MASK2l (0xffffffffL)
+#define BN_MASK2h (0xffffffff00000000L)
+#define BN_MASK2h1 (0xffffffff80000000L)
+#define BN_TBIT (0x8000000000000000L)
+#define BN_DEC_CONV (10000000000000000000UL)
+#define BN_DEC_FMT1 "%lu"
+#define BN_DEC_FMT2 "%019lu"
+#define BN_DEC_NUM 19
+#define BN_HEX_FMT1 "%lX"
+#define BN_HEX_FMT2 "%016lX"
+
+#elif defined(OPENSSL_32_BIT)
+
+#define BN_ULLONG unsigned long long
+#define BN_MASK (0xffffffffffffffffLL)
+#define BN_LONG int32_t
+#define BN_BITS 64
+#define BN_BYTES 4
+#define BN_BITS4 16
+#define BN_MASK2 (0xffffffffL)
+#define BN_MASK2l (0xffff)
+#define BN_MASK2h1 (0xffff8000L)
+#define BN_MASK2h (0xffff0000L)
+#define BN_TBIT (0x80000000L)
+#define BN_DEC_CONV (1000000000L)
+#define BN_DEC_FMT1 "%u"
+#define BN_DEC_FMT2 "%09u"
+#define BN_DEC_NUM 9
+#define BN_HEX_FMT1 "%X"
+#define BN_HEX_FMT2 "%08X"
+
+#else
+#error "Must define either OPENSSL_32_BIT or OPENSSL_64_BIT"
+#endif
+
+/* Pentium pro 16,16,16,32,64 */
+/* Alpha 16,16,16,16.64 */
+#define BN_MULL_SIZE_NORMAL (16) /* 32 */
+#define BN_MUL_RECURSIVE_SIZE_NORMAL (16) /* 32 less than */
+#define BN_SQR_RECURSIVE_SIZE_NORMAL (16) /* 32 */
+#define BN_MUL_LOW_RECURSIVE_SIZE_NORMAL (32) /* 32 */
+#define BN_MONT_CTX_SET_SIZE_WORD (64) /* 32 */
+
+BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w);
+BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w);
+void bn_sqr_words(BN_ULONG *rp, const BN_ULONG *ap, int num);
+BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d);
+BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,int num);
+BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,int num);
+
+void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b);
+void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b);
+void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a);
+void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a);
+
+/* bn_cmp_words returns a value less than, equal to or greater than zero if
+ * the, length |n|, array |a| is less than, equal to or greater than |b|. */
+int bn_cmp_words(const BN_ULONG *a, const BN_ULONG *b, int n);
+
+/* bn_cmp_words returns a value less than, equal to or greater than zero if the
+ * array |a| is less than, equal to or greater than |b|. The arrays can be of
+ * different lengths: |cl| gives the minimum of the two lengths and |dl| gives
+ * the length of |a| minus the length of |b|. */
+int bn_cmp_part_words(const BN_ULONG *a, const BN_ULONG *b, int cl, int dl);
+
+int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
+ const BN_ULONG *np, const BN_ULONG *n0, int num);
+
+#define LBITS(a) ((a) & BN_MASK2l)
+#define HBITS(a) (((a) >> BN_BITS4) & BN_MASK2l)
+#define L2HBITS(a) (((a) << BN_BITS4) & BN_MASK2)
+
+#define LLBITS(a) ((a) & BN_MASKl)
+#define LHBITS(a) (((a) >> BN_BITS2) & BN_MASKl)
+#define LL2HBITS(a) ((BN_ULLONG)((a) & BN_MASKl) << BN_BITS2)
+
+#define mul64(l, h, bl, bh) \
+ { \
+ BN_ULONG m, m1, lt, ht; \
+ \
+ lt = l; \
+ ht = h; \
+ m = (bh) * (lt); \
+ lt = (bl) * (lt); \
+ m1 = (bl) * (ht); \
+ ht = (bh) * (ht); \
+ m = (m + m1) & BN_MASK2; \
+ if (m < m1) \
+ ht += L2HBITS((BN_ULONG)1); \
+ ht += HBITS(m); \
+ m1 = L2HBITS(m); \
+ lt = (lt + m1) & BN_MASK2; \
+ if (lt < m1) \
+ ht++; \
+ (l) = lt; \
+ (h) = ht; \
+ }
+
+#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64)
+# if defined(__GNUC__) && __GNUC__>=2
+# define BN_UMULT_HIGH(a,b) ({ \
+ register BN_ULONG ret,discard; \
+ __asm__ ("mulq %3" \
+ : "=a"(discard),"=d"(ret) \
+ : "a"(a), "g"(b) \
+ : "cc"); \
+ ret; })
+# define BN_UMULT_LOHI(low,high,a,b) \
+ __asm__ ("mulq %3" \
+ : "=a"(low),"=d"(high) \
+ : "a"(a),"g"(b) \
+ : "cc");
+# endif
+# if defined(_MSC_VER) && _MSC_VER>=1400
+ unsigned __int64 __umulh (unsigned __int64 a,unsigned __int64 b);
+ unsigned __int64 _umul128 (unsigned __int64 a,unsigned __int64 b,
+ unsigned __int64 *h);
+# pragma intrinsic(__umulh,_umul128)
+# define BN_UMULT_HIGH(a,b) __umulh((a),(b))
+# define BN_UMULT_LOHI(low,high,a,b) ((low)=_umul128((a),(b),&(high)))
+# endif
+#elif !defined(OPENSSL_NO_ASM) && defined(OPENSSL_AARCH64)
+# if defined(__GNUC__) && __GNUC__>=2
+# define BN_UMULT_HIGH(a,b) ({ \
+ register BN_ULONG ret; \
+ __asm__ ("umulh %0,%1,%2" \
+ : "=r"(ret) \
+ : "r"(a), "r"(b)); \
+ ret; })
+# endif
+#endif
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_BN_INTERNAL_H */
diff --git a/crypto/bn/kronecker.c b/crypto/bn/kronecker.c
new file mode 100644
index 0000000..23ef79a
--- /dev/null
+++ b/crypto/bn/kronecker.c
@@ -0,0 +1,175 @@
+/* ====================================================================
+ * Copyright (c) 1998-2000 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). */
+
+#include <openssl/bn.h>
+
+#include "internal.h"
+
+
+/* least significant word */
+#define BN_lsw(n) (((n)->top == 0) ? (BN_ULONG) 0 : (n)->d[0])
+
+/* Returns -2 for errors because both -1 and 0 are valid results. */
+int BN_kronecker(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
+ int i;
+ int ret = -2;
+ BIGNUM *A, *B, *tmp;
+ /* In 'tab', only odd-indexed entries are relevant:
+ * For any odd BIGNUM n,
+ * tab[BN_lsw(n) & 7]
+ * is $(-1)^{(n^2-1)/8}$ (using TeX notation).
+ * Note that the sign of n does not matter. */
+ static const int tab[8] = {0, 1, 0, -1, 0, -1, 0, 1};
+
+ BN_CTX_start(ctx);
+ A = BN_CTX_get(ctx);
+ B = BN_CTX_get(ctx);
+ if (B == NULL) {
+ goto end;
+ }
+
+ if (!BN_copy(A, a) ||
+ !BN_copy(B, b)) {
+ goto end;
+ }
+
+ /* Kronecker symbol, imlemented according to Henri Cohen,
+ * "A Course in Computational Algebraic Number Theory"
+ * (algorithm 1.4.10). */
+
+ /* Cohen's step 1: */
+
+ if (BN_is_zero(B)) {
+ ret = BN_abs_is_word(A, 1);
+ goto end;
+ }
+
+ /* Cohen's step 2: */
+
+ if (!BN_is_odd(A) && !BN_is_odd(B)) {
+ ret = 0;
+ goto end;
+ }
+
+ /* now B is non-zero */
+ i = 0;
+ while (!BN_is_bit_set(B, i)) {
+ i++;
+ }
+ if (!BN_rshift(B, B, i)) {
+ goto end;
+ }
+ if (i & 1) {
+ /* i is odd */
+ /* (thus B was even, thus A must be odd!) */
+
+ /* set 'ret' to $(-1)^{(A^2-1)/8}$ */
+ ret = tab[BN_lsw(A) & 7];
+ } else {
+ /* i is even */
+ ret = 1;
+ }
+
+ if (B->neg) {
+ B->neg = 0;
+ if (A->neg) {
+ ret = -ret;
+ }
+ }
+
+ /* now B is positive and odd, so what remains to be done is to compute the
+ * Jacobi symbol (A/B) and multiply it by 'ret' */
+
+ while (1) {
+ /* Cohen's step 3: */
+
+ /* B is positive and odd */
+ if (BN_is_zero(A)) {
+ ret = BN_is_one(B) ? ret : 0;
+ goto end;
+ }
+
+ /* now A is non-zero */
+ i = 0;
+ while (!BN_is_bit_set(A, i)) {
+ i++;
+ }
+ if (!BN_rshift(A, A, i)) {
+ goto end;
+ }
+ if (i & 1) {
+ /* i is odd */
+ /* multiply 'ret' by $(-1)^{(B^2-1)/8}$ */
+ ret = ret * tab[BN_lsw(B) & 7];
+ }
+
+ /* Cohen's step 4: */
+ /* multiply 'ret' by $(-1)^{(A-1)(B-1)/4}$ */
+ if ((A->neg ? ~BN_lsw(A) : BN_lsw(A)) & BN_lsw(B) & 2) {
+ ret = -ret;
+ }
+
+ /* (A, B) := (B mod |A|, |A|) */
+ if (!BN_nnmod(B, B, A, ctx)) {
+ ret = -2;
+ goto end;
+ }
+ tmp = A;
+ A = B;
+ B = tmp;
+ tmp->neg = 0;
+ }
+
+end:
+ BN_CTX_end(ctx);
+ return ret;
+}
diff --git a/crypto/bn/montgomery.c b/crypto/bn/montgomery.c
new file mode 100644
index 0000000..4c803d2
--- /dev/null
+++ b/crypto/bn/montgomery.c
@@ -0,0 +1,561 @@
+/* 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.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2006 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). */
+
+#include <openssl/bn.h>
+
+#include <openssl/mem.h>
+#include <openssl/thread.h>
+
+#include "internal.h"
+
+
+#if !defined(OPENSSL_NO_ASM) && \
+ (defined(OPENSSL_X86) || defined(OPENSSL_X86_64))
+#define OPENSSL_BN_ASM_MONT
+#endif
+
+BN_MONT_CTX *BN_MONT_CTX_new(void) {
+ BN_MONT_CTX *ret = OPENSSL_malloc(sizeof(BN_MONT_CTX));
+
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ BN_MONT_CTX_init(ret);
+ ret->flags = BN_FLG_MALLOCED;
+ return ret;
+}
+
+void BN_MONT_CTX_init(BN_MONT_CTX *mont) {
+ memset(mont, 0, sizeof(BN_MONT_CTX));
+ BN_init(&mont->RR);
+ BN_init(&mont->N);
+ BN_init(&mont->Ni);
+}
+
+void BN_MONT_CTX_free(BN_MONT_CTX *mont) {
+ if (mont == NULL) {
+ return;
+ }
+
+ BN_free(&mont->RR);
+ BN_free(&mont->N);
+ BN_free(&mont->Ni);
+ if (mont->flags & BN_FLG_MALLOCED) {
+ OPENSSL_free(mont);
+ }
+}
+
+BN_MONT_CTX *BN_MONT_CTX_copy(BN_MONT_CTX *to, BN_MONT_CTX *from) {
+ if (to == from) {
+ return to;
+ }
+
+ if (!BN_copy(&to->RR, &from->RR) ||
+ !BN_copy(&to->N, &from->N) ||
+ !BN_copy(&to->Ni, &from->Ni)) {
+ return NULL;
+ }
+ to->ri = from->ri;
+ to->n0[0] = from->n0[0];
+ to->n0[1] = from->n0[1];
+ return to;
+}
+
+int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx) {
+ int ret = 0;
+ BIGNUM *Ri, *R;
+ BIGNUM tmod;
+ BN_ULONG buf[2];
+
+ BN_CTX_start(ctx);
+ Ri = BN_CTX_get(ctx);
+ if (Ri == NULL) {
+ goto err;
+ }
+ R = &mont->RR; /* grab RR as a temp */
+ if (!BN_copy(&mont->N, mod)) {
+ goto err; /* Set N */
+ }
+ mont->N.neg = 0;
+
+ BN_init(&tmod);
+ tmod.d = buf;
+ tmod.dmax = 2;
+ tmod.neg = 0;
+
+ mont->ri = (BN_num_bits(mod) + (BN_BITS2 - 1)) / BN_BITS2 * BN_BITS2;
+
+#if defined(OPENSSL_BN_ASM_MONT) && (BN_BITS2 <= 32)
+ /* Only certain BN_BITS2<=32 platforms actually make use of
+ * n0[1], and we could use the #else case (with a shorter R
+ * value) for the others. However, currently only the assembler
+ * files do know which is which. */
+
+ BN_zero(R);
+ if (!BN_set_bit(R, 2 * BN_BITS2)) {
+ goto err;
+ }
+
+ tmod.top = 0;
+ if ((buf[0] = mod->d[0])) {
+ tmod.top = 1;
+ }
+ if ((buf[1] = mod->top > 1 ? mod->d[1] : 0)) {
+ tmod.top = 2;
+ }
+
+ if (BN_mod_inverse(Ri, R, &tmod, ctx) == NULL) {
+ goto err;
+ }
+ if (!BN_lshift(Ri, Ri, 2 * BN_BITS2)) {
+ goto err; /* R*Ri */
+ }
+ if (!BN_is_zero(Ri)) {
+ if (!BN_sub_word(Ri, 1)) {
+ goto err;
+ }
+ } else {
+ /* if N mod word size == 1 */
+ if (bn_expand(Ri, (int)sizeof(BN_ULONG) * 2) == NULL) {
+ goto err;
+ }
+ /* Ri-- (mod double word size) */
+ Ri->neg = 0;
+ Ri->d[0] = BN_MASK2;
+ Ri->d[1] = BN_MASK2;
+ Ri->top = 2;
+ }
+
+ if (!BN_div(Ri, NULL, Ri, &tmod, ctx)) {
+ goto err;
+ }
+ /* Ni = (R*Ri-1)/N,
+ * keep only couple of least significant words: */
+ mont->n0[0] = (Ri->top > 0) ? Ri->d[0] : 0;
+ mont->n0[1] = (Ri->top > 1) ? Ri->d[1] : 0;
+#else
+ BN_zero(R);
+ if (!BN_set_bit(R, BN_BITS2)) {
+ goto err; /* R */
+ }
+
+ buf[0] = mod->d[0]; /* tmod = N mod word size */
+ buf[1] = 0;
+ tmod.top = buf[0] != 0 ? 1 : 0;
+ /* Ri = R^-1 mod N*/
+ if (BN_mod_inverse(Ri, R, &tmod, ctx) == NULL) {
+ goto err;
+ }
+ if (!BN_lshift(Ri, Ri, BN_BITS2)) {
+ goto err; /* R*Ri */
+ }
+ if (!BN_is_zero(Ri)) {
+ if (!BN_sub_word(Ri, 1)) {
+ goto err;
+ }
+ } else {
+ /* if N mod word size == 1 */
+ if (!BN_set_word(Ri, BN_MASK2)) {
+ goto err; /* Ri-- (mod word size) */
+ }
+ }
+ if (!BN_div(Ri, NULL, Ri, &tmod, ctx)) {
+ goto err;
+ }
+ /* Ni = (R*Ri-1)/N,
+ * keep only least significant word: */
+ mont->n0[0] = (Ri->top > 0) ? Ri->d[0] : 0;
+ mont->n0[1] = 0;
+#endif
+
+ /* setup RR for conversions */
+ BN_zero(&(mont->RR));
+ if (!BN_set_bit(&(mont->RR), mont->ri * 2)) {
+ goto err;
+ }
+ if (!BN_mod(&(mont->RR), &(mont->RR), &(mont->N), ctx)) {
+ goto err;
+ }
+
+ ret = 1;
+
+err:
+ BN_CTX_end(ctx);
+ return ret;
+}
+
+BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, int lock,
+ const BIGNUM *mod, BN_CTX *ctx) {
+ int got_write_lock = 0;
+ BN_MONT_CTX *ret;
+
+ CRYPTO_r_lock(lock);
+ if (!*pmont) {
+ CRYPTO_r_unlock(lock);
+ CRYPTO_w_lock(lock);
+ got_write_lock = 1;
+
+ if (!*pmont) {
+ ret = BN_MONT_CTX_new();
+ if (ret && !BN_MONT_CTX_set(ret, mod, ctx)) {
+ BN_MONT_CTX_free(ret);
+ } else {
+ *pmont = ret;
+ }
+ }
+ }
+
+ ret = *pmont;
+
+ if (got_write_lock) {
+ CRYPTO_w_unlock(lock);
+ } else {
+ CRYPTO_r_unlock(lock);
+ }
+
+ return ret;
+}
+
+int BN_to_montgomery(BIGNUM *ret, const BIGNUM *a, const BN_MONT_CTX *mont,
+ BN_CTX *ctx) {
+ return BN_mod_mul_montgomery(ret, a, &mont->RR, mont, ctx);
+}
+
+#if 0
+static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r,
+ const BN_MONT_CTX *mont) {
+ const BIGNUM *n;
+ BN_ULONG *ap, *np, *rp, n0, v, carry;
+ int nl, max, i;
+
+ n = &mont->N;
+ nl = n->top;
+ if (nl == 0) {
+ ret->top = 0;
+ return 1;
+ }
+
+ max = (2 * nl); /* carry is stored separately */
+ if (bn_wexpand(r, max) == NULL) {
+ return 0;
+ }
+
+ r->neg ^= n->neg;
+ np = n->d;
+ rp = r->d;
+
+ /* clear the top words of T */
+ if (max > r->top) {
+ memset(&rp[r->top], 0, (max - r->top) * sizeof(BN_ULONG));
+ }
+
+ r->top = max;
+ n0 = mont->n0[0];
+
+ for (carry = 0, i = 0; i < nl; i++, rp++) {
+ v = bn_mul_add_words(rp, np, nl, (rp[0] * n0) & BN_MASK2);
+ v = (v + carry + rp[nl]) & BN_MASK2;
+ carry |= (v != rp[nl]);
+ carry &= (v <= rp[nl]);
+ rp[nl] = v;
+ }
+
+ if (bn_wexpand(ret, nl) == NULL) {
+ return 0;
+ }
+ ret->top = nl;
+ ret->neg = r->neg;
+
+ rp = ret->d;
+ ap = &(r->d[nl]);
+
+ {
+ BN_ULONG *nrp;
+ size_t m;
+
+ v = bn_sub_words(rp, ap, np, nl) - carry;
+ /* if subtraction result is real, then trick unconditional memcpy below to
+ * perform in-place "refresh" instead of actual copy. */
+ m = (0 - (size_t)v);
+ nrp = (BN_ULONG *)(((intptr_t)rp & ~m) | ((intptr_t)ap & m));
+
+ for (i = 0, nl -= 4; i < nl; i += 4) {
+ BN_ULONG t1, t2, t3, t4;
+
+ t1 = nrp[i + 0];
+ t2 = nrp[i + 1];
+ t3 = nrp[i + 2];
+ ap[i + 0] = 0;
+ t4 = nrp[i + 3];
+ ap[i + 1] = 0;
+ rp[i + 0] = t1;
+ ap[i + 2] = 0;
+ rp[i + 1] = t2;
+ ap[i + 3] = 0;
+ rp[i + 2] = t3;
+ rp[i + 3] = t4;
+ }
+
+ for (nl += 4; i < nl; i++) {
+ rp[i] = nrp[i], ap[i] = 0;
+ }
+ }
+
+ bn_correct_top(r);
+ bn_correct_top(ret);
+
+ return 1;
+}
+#endif
+
+#define PTR_SIZE_INT size_t
+
+static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, const BN_MONT_CTX *mont)
+ {
+ BIGNUM *n;
+ BN_ULONG *ap,*np,*rp,n0,v,carry;
+ int nl,max,i;
+
+ n= (BIGNUM*) &(mont->N);
+ nl=n->top;
+ if (nl == 0) { ret->top=0; return(1); }
+
+ max=(2*nl); /* carry is stored separately */
+ if (bn_wexpand(r,max) == NULL) return(0);
+
+ r->neg^=n->neg;
+ np=n->d;
+ rp=r->d;
+
+ /* clear the top words of T */
+#if 1
+ for (i=r->top; i<max; i++) /* memset? XXX */
+ rp[i]=0;
+#else
+ memset(&(rp[r->top]),0,(max-r->top)*sizeof(BN_ULONG));
+#endif
+
+ r->top=max;
+ n0=mont->n0[0];
+
+ for (carry=0, i=0; i<nl; i++, rp++)
+ {
+ v=bn_mul_add_words(rp,np,nl,(rp[0]*n0)&BN_MASK2);
+ v = (v+carry+rp[nl])&BN_MASK2;
+ carry |= (v != rp[nl]);
+ carry &= (v <= rp[nl]);
+ rp[nl]=v;
+ }
+
+ if (bn_wexpand(ret,nl) == NULL) return(0);
+ ret->top=nl;
+ ret->neg=r->neg;
+
+ rp=ret->d;
+ ap=&(r->d[nl]);
+
+ {
+ BN_ULONG *nrp;
+ size_t m;
+
+ v=bn_sub_words(rp,ap,np,nl)-carry;
+ /* if subtraction result is real, then
+ * trick unconditional memcpy below to perform in-place
+ * "refresh" instead of actual copy. */
+ m=(0-(size_t)v);
+ nrp=(BN_ULONG *)(((PTR_SIZE_INT)rp&~m)|((PTR_SIZE_INT)ap&m));
+
+ for (i=0,nl-=4; i<nl; i+=4)
+ {
+ BN_ULONG t1,t2,t3,t4;
+
+ t1=nrp[i+0];
+ t2=nrp[i+1];
+ t3=nrp[i+2]; ap[i+0]=0;
+ t4=nrp[i+3]; ap[i+1]=0;
+ rp[i+0]=t1; ap[i+2]=0;
+ rp[i+1]=t2; ap[i+3]=0;
+ rp[i+2]=t3;
+ rp[i+3]=t4;
+ }
+ for (nl+=4; i<nl; i++)
+ rp[i]=nrp[i], ap[i]=0;
+ }
+ bn_correct_top(r);
+ bn_correct_top(ret);
+
+ return(1);
+ }
+
+int BN_from_montgomery(BIGNUM *ret, const BIGNUM *a, const BN_MONT_CTX *mont,
+ BN_CTX *ctx) {
+ int retn = 0;
+ BIGNUM *t;
+
+ BN_CTX_start(ctx);
+ t = BN_CTX_get(ctx);
+ if (t == NULL) {
+ return 0;
+ }
+
+ if (BN_copy(t, a))
+ retn = BN_from_montgomery_word(ret, t, mont);
+ BN_CTX_end(ctx);
+
+ return retn;
+}
+
+int BN_mod_mul_montgomery(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+ const BN_MONT_CTX *mont, BN_CTX *ctx) {
+ BIGNUM *tmp;
+ int ret = 0;
+
+#if defined(OPENSSL_BN_ASM_MONT)
+ int num = mont->N.top;
+
+ if (num > 1 && a->top == num && b->top == num) {
+ if (bn_wexpand(r, num) == NULL) {
+ return 0;
+ }
+ if (bn_mul_mont(r->d, a->d, b->d, mont->N.d, mont->n0, num)) {
+ r->neg = a->neg ^ b->neg;
+ r->top = num;
+ bn_correct_top(r);
+ return 1;
+ }
+ }
+#endif
+
+ BN_CTX_start(ctx);
+ tmp = BN_CTX_get(ctx);
+ if (tmp == NULL) {
+ goto err;
+ }
+
+ if (a == b) {
+ if (!BN_sqr(tmp, a, ctx)) {
+ goto err;
+ }
+ } else {
+ if (!BN_mul(tmp, a, b, ctx)) {
+ goto err;
+ }
+ }
+
+ /* reduce from aRR to aR */
+ if (!BN_from_montgomery_word(r, tmp, mont)) {
+ goto err;
+ }
+
+ ret = 1;
+
+err:
+ BN_CTX_end(ctx);
+ return ret;
+}
diff --git a/crypto/bn/mul.c b/crypto/bn/mul.c
new file mode 100644
index 0000000..af26eba
--- /dev/null
+++ b/crypto/bn/mul.c
@@ -0,0 +1,884 @@
+/* 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/bn.h>
+
+#include <assert.h>
+
+#include "internal.h"
+
+
+void bn_mul_normal(BN_ULONG *r, BN_ULONG *a, int na, BN_ULONG *b, int nb) {
+ BN_ULONG *rr;
+
+ if (na < nb) {
+ int itmp;
+ BN_ULONG *ltmp;
+
+ itmp = na;
+ na = nb;
+ nb = itmp;
+ ltmp = a;
+ a = b;
+ b = ltmp;
+ }
+ rr = &(r[na]);
+ if (nb <= 0) {
+ (void)bn_mul_words(r, a, na, 0);
+ return;
+ } else {
+ rr[0] = bn_mul_words(r, a, na, b[0]);
+ }
+
+ for (;;) {
+ if (--nb <= 0) {
+ return;
+ }
+ rr[1] = bn_mul_add_words(&(r[1]), a, na, b[1]);
+ if (--nb <= 0) {
+ return;
+ }
+ rr[2] = bn_mul_add_words(&(r[2]), a, na, b[2]);
+ if (--nb <= 0) {
+ return;
+ }
+ rr[3] = bn_mul_add_words(&(r[3]), a, na, b[3]);
+ if (--nb <= 0) {
+ return;
+ }
+ rr[4] = bn_mul_add_words(&(r[4]), a, na, b[4]);
+ rr += 4;
+ r += 4;
+ b += 4;
+ }
+}
+
+void bn_mul_low_normal(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n) {
+ bn_mul_words(r, a, n, b[0]);
+
+ for (;;) {
+ if (--n <= 0) {
+ return;
+ }
+ bn_mul_add_words(&(r[1]), a, n, b[1]);
+ if (--n <= 0) {
+ return;
+ }
+ bn_mul_add_words(&(r[2]), a, n, b[2]);
+ if (--n <= 0) {
+ return;
+ }
+ bn_mul_add_words(&(r[3]), a, n, b[3]);
+ if (--n <= 0) {
+ return;
+ }
+ bn_mul_add_words(&(r[4]), a, n, b[4]);
+ r += 4;
+ b += 4;
+ }
+}
+
+#if !defined(OPENSSL_X86)
+/* Here follows specialised variants of bn_add_words() and bn_sub_words(). They
+ * have the property performing operations on arrays of different sizes. The
+ * sizes of those arrays is expressed through cl, which is the common length (
+ * basicall, min(len(a),len(b)) ), and dl, which is the delta between the two
+ * lengths, calculated as len(a)-len(b). All lengths are the number of
+ * BN_ULONGs... For the operations that require a result array as parameter,
+ * it must have the length cl+abs(dl). These functions should probably end up
+ * in bn_asm.c as soon as there are assembler counterparts for the systems that
+ * use assembler files. */
+
+static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a,
+ const BN_ULONG *b, int cl, int dl) {
+ BN_ULONG c, t;
+
+ assert(cl >= 0);
+ c = bn_sub_words(r, a, b, cl);
+
+ if (dl == 0)
+ return c;
+
+ r += cl;
+ a += cl;
+ b += cl;
+
+ if (dl < 0) {
+ for (;;) {
+ t = b[0];
+ r[0] = (0 - t - c) & BN_MASK2;
+ if (t != 0) {
+ c = 1;
+ }
+ if (++dl >= 0) {
+ break;
+ }
+
+ t = b[1];
+ r[1] = (0 - t - c) & BN_MASK2;
+ if (t != 0) {
+ c = 1;
+ }
+ if (++dl >= 0) {
+ break;
+ }
+
+ t = b[2];
+ r[2] = (0 - t - c) & BN_MASK2;
+ if (t != 0) {
+ c = 1;
+ }
+ if (++dl >= 0) {
+ break;
+ }
+
+ t = b[3];
+ r[3] = (0 - t - c) & BN_MASK2;
+ if (t != 0) {
+ c = 1;
+ }
+ if (++dl >= 0) {
+ break;
+ }
+
+ b += 4;
+ r += 4;
+ }
+ } else {
+ int save_dl = dl;
+ while (c) {
+ t = a[0];
+ r[0] = (t - c) & BN_MASK2;
+ if (t != 0) {
+ c = 0;
+ }
+ if (--dl <= 0) {
+ break;
+ }
+
+ t = a[1];
+ r[1] = (t - c) & BN_MASK2;
+ if (t != 0) {
+ c = 0;
+ }
+ if (--dl <= 0) {
+ break;
+ }
+
+ t = a[2];
+ r[2] = (t - c) & BN_MASK2;
+ if (t != 0) {
+ c = 0;
+ }
+ if (--dl <= 0) {
+ break;
+ }
+
+ t = a[3];
+ r[3] = (t - c) & BN_MASK2;
+ if (t != 0) {
+ c = 0;
+ }
+ if (--dl <= 0) {
+ break;
+ }
+
+ save_dl = dl;
+ a += 4;
+ r += 4;
+ }
+ if (dl > 0) {
+ if (save_dl > dl) {
+ switch (save_dl - dl) {
+ case 1:
+ r[1] = a[1];
+ if (--dl <= 0) {
+ break;
+ }
+ case 2:
+ r[2] = a[2];
+ if (--dl <= 0) {
+ break;
+ }
+ case 3:
+ r[3] = a[3];
+ if (--dl <= 0) {
+ break;
+ }
+ }
+ a += 4;
+ r += 4;
+ }
+ }
+
+ if (dl > 0) {
+ for (;;) {
+ r[0] = a[0];
+ if (--dl <= 0) {
+ break;
+ }
+ r[1] = a[1];
+ if (--dl <= 0) {
+ break;
+ }
+ r[2] = a[2];
+ if (--dl <= 0) {
+ break;
+ }
+ r[3] = a[3];
+ if (--dl <= 0) {
+ break;
+ }
+
+ a += 4;
+ r += 4;
+ }
+ }
+ }
+
+ return c;
+}
+#else
+/* On other platforms the function is defined in asm. */
+BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
+ int cl, int dl);
+#endif
+
+/* Karatsuba recursive multiplication algorithm
+ * (cf. Knuth, The Art of Computer Programming, Vol. 2) */
+
+/* r is 2*n2 words in size,
+ * a and b are both n2 words in size.
+ * n2 must be a power of 2.
+ * We multiply and return the result.
+ * t must be 2*n2 words in size
+ * We calculate
+ * a[0]*b[0]
+ * a[0]*b[0]+a[1]*b[1]+(a[0]-a[1])*(b[1]-b[0])
+ * a[1]*b[1]
+ */
+/* dnX may not be positive, but n2/2+dnX has to be */
+static void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2,
+ int dna, int dnb, BN_ULONG *t) {
+ int n = n2 / 2, c1, c2;
+ int tna = n + dna, tnb = n + dnb;
+ unsigned int neg, zero;
+ BN_ULONG ln, lo, *p;
+
+ /* Only call bn_mul_comba 8 if n2 == 8 and the
+ * two arrays are complete [steve]
+ */
+ if (n2 == 8 && dna == 0 && dnb == 0) {
+ bn_mul_comba8(r, a, b);
+ return;
+ }
+
+ /* Else do normal multiply */
+ if (n2 < BN_MUL_RECURSIVE_SIZE_NORMAL) {
+ bn_mul_normal(r, a, n2 + dna, b, n2 + dnb);
+ if ((dna + dnb) < 0)
+ memset(&r[2 * n2 + dna + dnb], 0, sizeof(BN_ULONG) * -(dna + dnb));
+ return;
+ }
+
+ /* r=(a[0]-a[1])*(b[1]-b[0]) */
+ c1 = bn_cmp_part_words(a, &(a[n]), tna, n - tna);
+ c2 = bn_cmp_part_words(&(b[n]), b, tnb, tnb - n);
+ zero = neg = 0;
+ switch (c1 * 3 + c2) {
+ case -4:
+ bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */
+ bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
+ break;
+ case -3:
+ zero = 1;
+ break;
+ case -2:
+ bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */
+ bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n); /* + */
+ neg = 1;
+ break;
+ case -1:
+ case 0:
+ case 1:
+ zero = 1;
+ break;
+ case 2:
+ bn_sub_part_words(t, a, &(a[n]), tna, n - tna); /* + */
+ bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
+ neg = 1;
+ break;
+ case 3:
+ zero = 1;
+ break;
+ case 4:
+ bn_sub_part_words(t, a, &(a[n]), tna, n - tna);
+ bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n);
+ break;
+ }
+
+ if (n == 4 && dna == 0 && dnb == 0) {
+ /* XXX: bn_mul_comba4 could take extra args to do this well */
+ if (!zero) {
+ bn_mul_comba4(&(t[n2]), t, &(t[n]));
+ } else {
+ memset(&(t[n2]), 0, 8 * sizeof(BN_ULONG));
+ }
+
+ bn_mul_comba4(r, a, b);
+ bn_mul_comba4(&(r[n2]), &(a[n]), &(b[n]));
+ } else if (n == 8 && dna == 0 && dnb == 0) {
+ /* XXX: bn_mul_comba8 could take extra args to do this well */
+ if (!zero) {
+ bn_mul_comba8(&(t[n2]), t, &(t[n]));
+ } else {
+ memset(&(t[n2]), 0, 16 * sizeof(BN_ULONG));
+ }
+
+ bn_mul_comba8(r, a, b);
+ bn_mul_comba8(&(r[n2]), &(a[n]), &(b[n]));
+ } else {
+ p = &(t[n2 * 2]);
+ if (!zero) {
+ bn_mul_recursive(&(t[n2]), t, &(t[n]), n, 0, 0, p);
+ } else {
+ memset(&(t[n2]), 0, n2 * sizeof(BN_ULONG));
+ }
+ bn_mul_recursive(r, a, b, n, 0, 0, p);
+ bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]), n, dna, dnb, p);
+ }
+
+ /* t[32] holds (a[0]-a[1])*(b[1]-b[0]), c1 is the sign
+ * r[10] holds (a[0]*b[0])
+ * r[32] holds (b[1]*b[1]) */
+
+ c1 = (int)(bn_add_words(t, r, &(r[n2]), n2));
+
+ if (neg) {
+ /* if t[32] is negative */
+ c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2));
+ } else {
+ /* Might have a carry */
+ c1 += (int)(bn_add_words(&(t[n2]), &(t[n2]), t, n2));
+ }
+
+ /* t[32] holds (a[0]-a[1])*(b[1]-b[0])+(a[0]*b[0])+(a[1]*b[1])
+ * r[10] holds (a[0]*b[0])
+ * r[32] holds (b[1]*b[1])
+ * c1 holds the carry bits */
+ c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2));
+ if (c1) {
+ p = &(r[n + n2]);
+ lo = *p;
+ ln = (lo + c1) & BN_MASK2;
+ *p = ln;
+
+ /* The overflow will stop before we over write
+ * words we should not overwrite */
+ if (ln < (BN_ULONG)c1) {
+ do {
+ p++;
+ lo = *p;
+ ln = (lo + 1) & BN_MASK2;
+ *p = ln;
+ } while (ln == 0);
+ }
+ }
+}
+
+/* n+tn is the word length
+ * t needs to be n*4 is size, as does r */
+/* tnX may not be negative but less than n */
+static void bn_mul_part_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n,
+ int tna, int tnb, BN_ULONG *t) {
+ int i, j, n2 = n * 2;
+ int c1, c2, neg;
+ BN_ULONG ln, lo, *p;
+
+ if (n < 8) {
+ bn_mul_normal(r, a, n + tna, b, n + tnb);
+ return;
+ }
+
+ /* r=(a[0]-a[1])*(b[1]-b[0]) */
+ c1 = bn_cmp_part_words(a, &(a[n]), tna, n - tna);
+ c2 = bn_cmp_part_words(&(b[n]), b, tnb, tnb - n);
+ neg = 0;
+ switch (c1 * 3 + c2) {
+ case -4:
+ bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */
+ bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
+ break;
+ case -3:
+ /* break; */
+ case -2:
+ bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */
+ bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n); /* + */
+ neg = 1;
+ break;
+ case -1:
+ case 0:
+ case 1:
+ /* break; */
+ case 2:
+ bn_sub_part_words(t, a, &(a[n]), tna, n - tna); /* + */
+ bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */
+ neg = 1;
+ break;
+ case 3:
+ /* break; */
+ case 4:
+ bn_sub_part_words(t, a, &(a[n]), tna, n - tna);
+ bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n);
+ break;
+ }
+
+ if (n == 8) {
+ bn_mul_comba8(&(t[n2]), t, &(t[n]));
+ bn_mul_comba8(r, a, b);
+ bn_mul_normal(&(r[n2]), &(a[n]), tna, &(b[n]), tnb);
+ memset(&(r[n2 + tna + tnb]), 0, sizeof(BN_ULONG) * (n2 - tna - tnb));
+ } else {
+ p = &(t[n2 * 2]);
+ bn_mul_recursive(&(t[n2]), t, &(t[n]), n, 0, 0, p);
+ bn_mul_recursive(r, a, b, n, 0, 0, p);
+ i = n / 2;
+ /* If there is only a bottom half to the number,
+ * just do it */
+ if (tna > tnb) {
+ j = tna - i;
+ } else {
+ j = tnb - i;
+ }
+
+ if (j == 0) {
+ bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]), i, tna - i, tnb - i, p);
+ memset(&(r[n2 + i * 2]), 0, sizeof(BN_ULONG) * (n2 - i * 2));
+ } else if (j > 0) {
+ /* eg, n == 16, i == 8 and tn == 11 */
+ bn_mul_part_recursive(&(r[n2]), &(a[n]), &(b[n]), i, tna - i, tnb - i, p);
+ memset(&(r[n2 + tna + tnb]), 0, sizeof(BN_ULONG) * (n2 - tna - tnb));
+ } else {
+ /* (j < 0) eg, n == 16, i == 8 and tn == 5 */
+ memset(&(r[n2]), 0, sizeof(BN_ULONG) * n2);
+ if (tna < BN_MUL_RECURSIVE_SIZE_NORMAL &&
+ tnb < BN_MUL_RECURSIVE_SIZE_NORMAL) {
+ bn_mul_normal(&(r[n2]), &(a[n]), tna, &(b[n]), tnb);
+ } else {
+ for (;;) {
+ i /= 2;
+ /* these simplified conditions work
+ * exclusively because difference
+ * between tna and tnb is 1 or 0 */
+ if (i < tna || i < tnb) {
+ bn_mul_part_recursive(&(r[n2]), &(a[n]), &(b[n]), i, tna - i,
+ tnb - i, p);
+ break;
+ } else if (i == tna || i == tnb) {
+ bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]), i, tna - i, tnb - i,
+ p);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* t[32] holds (a[0]-a[1])*(b[1]-b[0]), c1 is the sign
+ * r[10] holds (a[0]*b[0])
+ * r[32] holds (b[1]*b[1])
+ */
+
+ c1 = (int)(bn_add_words(t, r, &(r[n2]), n2));
+
+ if (neg) {
+ /* if t[32] is negative */
+ c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2));
+ } else {
+ /* Might have a carry */
+ c1 += (int)(bn_add_words(&(t[n2]), &(t[n2]), t, n2));
+ }
+
+ /* t[32] holds (a[0]-a[1])*(b[1]-b[0])+(a[0]*b[0])+(a[1]*b[1])
+ * r[10] holds (a[0]*b[0])
+ * r[32] holds (b[1]*b[1])
+ * c1 holds the carry bits */
+ c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2));
+ if (c1) {
+ p = &(r[n + n2]);
+ lo = *p;
+ ln = (lo + c1) & BN_MASK2;
+ *p = ln;
+
+ /* The overflow will stop before we over write
+ * words we should not overwrite */
+ if (ln < (BN_ULONG)c1) {
+ do {
+ p++;
+ lo = *p;
+ ln = (lo + 1) & BN_MASK2;
+ *p = ln;
+ } while (ln == 0);
+ }
+ }
+}
+
+int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
+ int ret = 0;
+ int top, al, bl;
+ BIGNUM *rr;
+ int i;
+ BIGNUM *t = NULL;
+ int j = 0, k;
+
+ al = a->top;
+ bl = b->top;
+
+ if ((al == 0) || (bl == 0)) {
+ BN_zero(r);
+ return 1;
+ }
+ top = al + bl;
+
+ BN_CTX_start(ctx);
+ if ((r == a) || (r == b)) {
+ if ((rr = BN_CTX_get(ctx)) == NULL) {
+ goto err;
+ }
+ } else {
+ rr = r;
+ }
+ rr->neg = a->neg ^ b->neg;
+
+ i = al - bl;
+ if (i == 0) {
+ if (al == 8) {
+ if (bn_wexpand(rr, 16) == NULL) {
+ goto err;
+ }
+ rr->top = 16;
+ bn_mul_comba8(rr->d, a->d, b->d);
+ goto end;
+ }
+ }
+
+ if ((al >= BN_MULL_SIZE_NORMAL) && (bl >= BN_MULL_SIZE_NORMAL)) {
+ if (i >= -1 && i <= 1) {
+ /* Find out the power of two lower or equal
+ to the longest of the two numbers */
+ if (i >= 0) {
+ j = BN_num_bits_word((BN_ULONG)al);
+ }
+ if (i == -1) {
+ j = BN_num_bits_word((BN_ULONG)bl);
+ }
+ j = 1 << (j - 1);
+ assert(j <= al || j <= bl);
+ k = j + j;
+ t = BN_CTX_get(ctx);
+ if (t == NULL) {
+ goto err;
+ }
+ if (al > j || bl > j) {
+ if (bn_wexpand(t, k * 4) == NULL) {
+ goto err;
+ }
+ if (bn_wexpand(rr, k * 4) == NULL) {
+ goto err;
+ }
+ bn_mul_part_recursive(rr->d, a->d, b->d, j, al - j, bl - j, t->d);
+ } else {
+ /* al <= j || bl <= j */
+ if (bn_wexpand(t, k * 2) == NULL) {
+ goto err;
+ }
+ if (bn_wexpand(rr, k * 2) == NULL) {
+ goto err;
+ }
+ bn_mul_recursive(rr->d, a->d, b->d, j, al - j, bl - j, t->d);
+ }
+ rr->top = top;
+ goto end;
+ }
+ }
+
+ if (bn_wexpand(rr, top) == NULL) {
+ goto err;
+ }
+ rr->top = top;
+ bn_mul_normal(rr->d, a->d, al, b->d, bl);
+
+end:
+ bn_correct_top(rr);
+ if (r != rr) {
+ BN_copy(r, rr);
+ }
+ ret = 1;
+
+err:
+ BN_CTX_end(ctx);
+ return ret;
+}
+
+/* tmp must have 2*n words */
+static void bn_sqr_normal(BN_ULONG *r, const BN_ULONG *a, int n, BN_ULONG *tmp) {
+ int i, j, max;
+ const BN_ULONG *ap;
+ BN_ULONG *rp;
+
+ max = n * 2;
+ ap = a;
+ rp = r;
+ rp[0] = rp[max - 1] = 0;
+ rp++;
+ j = n;
+
+ if (--j > 0) {
+ ap++;
+ rp[j] = bn_mul_words(rp, ap, j, ap[-1]);
+ rp += 2;
+ }
+
+ for (i = n - 2; i > 0; i--) {
+ j--;
+ ap++;
+ rp[j] = bn_mul_add_words(rp, ap, j, ap[-1]);
+ rp += 2;
+ }
+
+ bn_add_words(r, r, r, max);
+
+ /* There will not be a carry */
+
+ bn_sqr_words(tmp, a, n);
+
+ bn_add_words(r, r, tmp, max);
+}
+
+/* r is 2*n words in size,
+ * a and b are both n words in size. (There's not actually a 'b' here ...)
+ * n must be a power of 2.
+ * We multiply and return the result.
+ * t must be 2*n words in size
+ * We calculate
+ * a[0]*b[0]
+ * a[0]*b[0]+a[1]*b[1]+(a[0]-a[1])*(b[1]-b[0])
+ * a[1]*b[1]
+ */
+static void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2, BN_ULONG *t) {
+ int n = n2 / 2;
+ int zero, c1;
+ BN_ULONG ln, lo, *p;
+
+ if (n2 == 4) {
+ bn_sqr_comba4(r, a);
+ return;
+ } else if (n2 == 8) {
+ bn_sqr_comba8(r, a);
+ return;
+ }
+ if (n2 < BN_SQR_RECURSIVE_SIZE_NORMAL) {
+ bn_sqr_normal(r, a, n2, t);
+ return;
+ }
+ /* r=(a[0]-a[1])*(a[1]-a[0]) */
+ c1 = bn_cmp_words(a, &(a[n]), n);
+ zero = 0;
+ if (c1 > 0) {
+ bn_sub_words(t, a, &(a[n]), n);
+ } else if (c1 < 0) {
+ bn_sub_words(t, &(a[n]), a, n);
+ } else {
+ zero = 1;
+ }
+
+ /* The result will always be negative unless it is zero */
+ p = &(t[n2 * 2]);
+
+ if (!zero) {
+ bn_sqr_recursive(&(t[n2]), t, n, p);
+ } else {
+ memset(&(t[n2]), 0, n2 * sizeof(BN_ULONG));
+ }
+ bn_sqr_recursive(r, a, n, p);
+ bn_sqr_recursive(&(r[n2]), &(a[n]), n, p);
+
+ /* t[32] holds (a[0]-a[1])*(a[1]-a[0]), it is negative or zero
+ * r[10] holds (a[0]*b[0])
+ * r[32] holds (b[1]*b[1]) */
+
+ c1 = (int)(bn_add_words(t, r, &(r[n2]), n2));
+
+ /* t[32] is negative */
+ c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2));
+
+ /* t[32] holds (a[0]-a[1])*(a[1]-a[0])+(a[0]*a[0])+(a[1]*a[1])
+ * r[10] holds (a[0]*a[0])
+ * r[32] holds (a[1]*a[1])
+ * c1 holds the carry bits */
+ c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2));
+ if (c1) {
+ p = &(r[n + n2]);
+ lo = *p;
+ ln = (lo + c1) & BN_MASK2;
+ *p = ln;
+
+ /* The overflow will stop before we over write
+ * words we should not overwrite */
+ if (ln < (BN_ULONG)c1) {
+ do {
+ p++;
+ lo = *p;
+ ln = (lo + 1) & BN_MASK2;
+ *p = ln;
+ } while (ln == 0);
+ }
+ }
+}
+
+int BN_mul_word(BIGNUM *bn, BN_ULONG w) {
+ BN_ULONG ll;
+
+ w &= BN_MASK2;
+ if (!bn->top) {
+ return 1;
+ }
+
+ if (w == 0) {
+ BN_zero(bn);
+ return 1;
+ }
+
+ ll = bn_mul_words(bn->d, bn->d, bn->top, w);
+ if (ll) {
+ if (bn_wexpand(bn, bn->top + 1) == NULL) {
+ return 0;
+ }
+ bn->d[bn->top++] = ll;
+ }
+
+ return 1;
+}
+
+int BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) {
+ int max, al;
+ int ret = 0;
+ BIGNUM *tmp, *rr;
+
+ al = a->top;
+ if (al <= 0) {
+ r->top = 0;
+ return 1;
+ }
+
+ BN_CTX_start(ctx);
+ rr = (a != r) ? r : BN_CTX_get(ctx);
+ tmp = BN_CTX_get(ctx);
+ if (!rr || !tmp) {
+ goto err;
+ }
+
+ max = 2 * al; /* Non-zero (from above) */
+ if (bn_wexpand(rr, max) == NULL) {
+ goto err;
+ }
+
+ if (al == 4) {
+ bn_sqr_comba4(rr->d, a->d);
+ } else if (al == 8) {
+ bn_sqr_comba8(rr->d, a->d);
+ } else {
+ if (al < BN_SQR_RECURSIVE_SIZE_NORMAL) {
+ BN_ULONG t[BN_SQR_RECURSIVE_SIZE_NORMAL * 2];
+ bn_sqr_normal(rr->d, a->d, al, t);
+ } else {
+ int j, k;
+
+ j = BN_num_bits_word((BN_ULONG)al);
+ j = 1 << (j - 1);
+ k = j + j;
+ if (al == j) {
+ if (bn_wexpand(tmp, k * 2) == NULL) {
+ goto err;
+ }
+ bn_sqr_recursive(rr->d, a->d, al, tmp->d);
+ } else {
+ if (bn_wexpand(tmp, max) == NULL) {
+ goto err;
+ }
+ bn_sqr_normal(rr->d, a->d, al, tmp->d);
+ }
+ }
+ }
+
+ rr->neg = 0;
+ /* If the most-significant half of the top word of 'a' is zero, then
+ * the square of 'a' will max-1 words. */
+ if (a->d[al - 1] == (a->d[al - 1] & BN_MASK2l)) {
+ rr->top = max - 1;
+ } else {
+ rr->top = max;
+ }
+
+ if (rr != r) {
+ BN_copy(r, rr);
+ }
+ ret = 1;
+
+err:
+ BN_CTX_end(ctx);
+ return ret;
+}
diff --git a/crypto/bn/prime.c b/crypto/bn/prime.c
new file mode 100644
index 0000000..1b8221b
--- /dev/null
+++ b/crypto/bn/prime.c
@@ -0,0 +1,790 @@
+/* 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.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2001 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). */
+
+#include <openssl/bn.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+#include "internal.h"
+
+/* number of Miller-Rabin iterations for an error rate of less than 2^-80
+ * for random 'b'-bit input, b >= 100 (taken from table 4.4 in the Handbook
+ * of Applied Cryptography [Menezes, van Oorschot, Vanstone; CRC Press 1996];
+ * original paper: Damgaard, Landrock, Pomerance: Average case error estimates
+ * for the strong probable prime test. -- Math. Comp. 61 (1993) 177-194) */
+#define BN_prime_checks_for_size(b) ((b) >= 1300 ? 2 : \
+ (b) >= 850 ? 3 : \
+ (b) >= 650 ? 4 : \
+ (b) >= 550 ? 5 : \
+ (b) >= 450 ? 6 : \
+ (b) >= 400 ? 7 : \
+ (b) >= 350 ? 8 : \
+ (b) >= 300 ? 9 : \
+ (b) >= 250 ? 12 : \
+ (b) >= 200 ? 15 : \
+ (b) >= 150 ? 18 : \
+ /* b >= 100 */ 27)
+
+/* The quick sieve algorithm approach to weeding out primes is Philip
+ * Zimmermann's, as implemented in PGP. I have had a read of his comments and
+ * implemented my own version. */
+
+/* NUMPRIMES is the number of primes that fit into a uint16_t. */
+#define NUMPRIMES 2048
+
+/* primes is defined at the bottom of the file and contains all the primes that
+ * fit into a uint16_t. */
+static const uint16_t primes[NUMPRIMES];
+
+static int witness(BIGNUM *w, const BIGNUM *a, const BIGNUM *a1,
+ const BIGNUM *a1_odd, int k, BN_CTX *ctx, BN_MONT_CTX *mont);
+static int probable_prime(BIGNUM *rnd, int bits);
+static int probable_prime_dh(BIGNUM *rnd, int bits, const BIGNUM *add,
+ const BIGNUM *rem, BN_CTX *ctx);
+static int probable_prime_dh_safe(BIGNUM *rnd, int bits, const BIGNUM *add,
+ const BIGNUM *rem, BN_CTX *ctx);
+
+void BN_GENCB_set(BN_GENCB *callback,
+ int (*f)(int event, int n, struct bn_gencb_st *),
+ void *arg) {
+ callback->callback = f;
+ callback->arg = arg;
+}
+
+int BN_GENCB_call(BN_GENCB *callback, int event, int n) {
+ if (!callback) {
+ return 1;
+ }
+
+ return callback->callback(event, n, callback);
+}
+
+int BN_generate_prime_ex(BIGNUM *ret, int bits, int safe, const BIGNUM *add,
+ const BIGNUM *rem, BN_GENCB *cb) {
+ BIGNUM *t;
+ int found = 0;
+ int i, j, c1 = 0;
+ BN_CTX *ctx;
+ int checks = BN_prime_checks_for_size(bits);
+
+ ctx = BN_CTX_new();
+ if (ctx == NULL) {
+ goto err;
+ }
+ BN_CTX_start(ctx);
+ t = BN_CTX_get(ctx);
+ if (!t) {
+ goto err;
+ }
+
+loop:
+ /* make a random number and set the top and bottom bits */
+ if (add == NULL) {
+ if (!probable_prime(ret, bits)) {
+ goto err;
+ }
+ } else {
+ if (safe) {
+ if (!probable_prime_dh_safe(ret, bits, add, rem, ctx)) {
+ goto err;
+ }
+ } else {
+ if (!probable_prime_dh(ret, bits, add, rem, ctx)) {
+ goto err;
+ }
+ }
+ }
+
+ if (!BN_GENCB_call(cb, BN_GENCB_GENERATED, c1++)) {
+ /* aborted */
+ goto err;
+ }
+
+ if (!safe) {
+ i = BN_is_prime_fasttest_ex(ret, checks, ctx, 0, cb);
+ if (i == -1) {
+ goto err;
+ } else if (i == 0) {
+ goto loop;
+ }
+ } else {
+ /* for "safe prime" generation, check that (p-1)/2 is prime. Since a prime
+ * is odd, We just need to divide by 2 */
+ if (!BN_rshift1(t, ret)) {
+ goto err;
+ }
+
+ for (i = 0; i < checks; i++) {
+ j = BN_is_prime_fasttest_ex(ret, 1, ctx, 0, NULL);
+ if (j == -1) {
+ goto err;
+ } else if (j == 0) {
+ goto loop;
+ }
+
+ j = BN_is_prime_fasttest_ex(t, 1, ctx, 0, NULL);
+ if (j == -1) {
+ goto err;
+ } else if (j == 0) {
+ goto loop;
+ }
+
+ if (!BN_GENCB_call(cb, i, c1 - 1)) {
+ goto err;
+ }
+ /* We have a safe prime test pass */
+ }
+ }
+
+ /* we have a prime :-) */
+ found = 1;
+
+err:
+ if (ctx != NULL) {
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ }
+
+ return found;
+}
+
+int BN_primality_test(int *is_probably_prime, const BIGNUM *candidate,
+ int checks, BN_CTX *ctx, int do_trial_division,
+ BN_GENCB *cb) {
+ switch (BN_is_prime_fasttest_ex(candidate, checks, ctx, do_trial_division, cb)) {
+ case 1:
+ *is_probably_prime = 1;
+ return 1;
+ case 0:
+ *is_probably_prime = 0;
+ return 1;
+ default:
+ *is_probably_prime = 0;
+ return 0;
+ }
+}
+
+int BN_is_prime_ex(const BIGNUM *candidate, int checks, BN_CTX *ctx, BN_GENCB *cb) {
+ return BN_is_prime_fasttest_ex(candidate, checks, ctx, 0, cb);
+}
+
+int BN_is_prime_fasttest_ex(const BIGNUM *a, int checks, BN_CTX *ctx_passed,
+ int do_trial_division, BN_GENCB *cb) {
+ int i, j, ret = -1;
+ int k;
+ BN_CTX *ctx = NULL;
+ BIGNUM *A1, *A1_odd, *check; /* taken from ctx */
+ BN_MONT_CTX *mont = NULL;
+ const BIGNUM *A = NULL;
+
+ if (BN_cmp(a, BN_value_one()) <= 0) {
+ return 0;
+ }
+
+ if (checks == BN_prime_checks) {
+ checks = BN_prime_checks_for_size(BN_num_bits(a));
+ }
+
+ /* first look for small factors */
+ if (!BN_is_odd(a)) {
+ /* a is even => a is prime if and only if a == 2 */
+ return BN_is_word(a, 2);
+ }
+
+ if (do_trial_division) {
+ for (i = 1; i < NUMPRIMES; i++) {
+ if (BN_mod_word(a, primes[i]) == 0) {
+ return 0;
+ }
+ }
+
+ if (!BN_GENCB_call(cb, 1, -1)) {
+ goto err;
+ }
+ }
+
+ if (ctx_passed != NULL) {
+ ctx = ctx_passed;
+ } else if ((ctx = BN_CTX_new()) == NULL) {
+ goto err;
+ }
+ BN_CTX_start(ctx);
+
+ /* A := abs(a) */
+ if (a->neg) {
+ BIGNUM *t;
+ if ((t = BN_CTX_get(ctx)) == NULL) {
+ goto err;
+ }
+ BN_copy(t, a);
+ t->neg = 0;
+ A = t;
+ } else {
+ A = a;
+ }
+
+ A1 = BN_CTX_get(ctx);
+ A1_odd = BN_CTX_get(ctx);
+ check = BN_CTX_get(ctx);
+ if (check == NULL) {
+ goto err;
+ }
+
+ /* compute A1 := A - 1 */
+ if (!BN_copy(A1, A)) {
+ goto err;
+ }
+ if (!BN_sub_word(A1, 1)) {
+ goto err;
+ }
+ if (BN_is_zero(A1)) {
+ ret = 0;
+ goto err;
+ }
+
+ /* write A1 as A1_odd * 2^k */
+ k = 1;
+ while (!BN_is_bit_set(A1, k)) {
+ k++;
+ }
+ if (!BN_rshift(A1_odd, A1, k)) {
+ goto err;
+ }
+
+ /* Montgomery setup for computations mod A */
+ mont = BN_MONT_CTX_new();
+ if (mont == NULL) {
+ goto err;
+ }
+ if (!BN_MONT_CTX_set(mont, A, ctx)) {
+ goto err;
+ }
+
+ for (i = 0; i < checks; i++) {
+ if (!BN_pseudo_rand_range(check, A1)) {
+ goto err;
+ }
+ if (!BN_add_word(check, 1)) {
+ goto err;
+ }
+ /* now 1 <= check < A */
+
+ j = witness(check, A, A1, A1_odd, k, ctx, mont);
+ if (j == -1) {
+ goto err;
+ }
+ if (j) {
+ ret = 0;
+ goto err;
+ }
+ if (!BN_GENCB_call(cb, 1, i)) {
+ goto err;
+ }
+ }
+ ret = 1;
+
+err:
+ if (ctx != NULL) {
+ BN_CTX_end(ctx);
+ if (ctx_passed == NULL) {
+ BN_CTX_free(ctx);
+ }
+ }
+ if (mont != NULL) {
+ BN_MONT_CTX_free(mont);
+ }
+
+ return ret;
+}
+
+static int witness(BIGNUM *w, const BIGNUM *a, const BIGNUM *a1,
+ const BIGNUM *a1_odd, int k, BN_CTX *ctx,
+ BN_MONT_CTX *mont) {
+ if (!BN_mod_exp_mont(w, w, a1_odd, a, ctx, mont)) { /* w := w^a1_odd mod a */
+ return -1;
+ }
+ if (BN_is_one(w)) {
+ return 0; /* probably prime */
+ }
+ if (BN_cmp(w, a1) == 0) {
+ return 0; /* w == -1 (mod a), 'a' is probably prime */
+ }
+
+ while (--k) {
+ if (!BN_mod_mul(w, w, w, a, ctx)) { /* w := w^2 mod a */
+ return -1;
+ }
+
+ if (BN_is_one(w)) {
+ return 1; /* 'a' is composite, otherwise a previous 'w' would
+ * have been == -1 (mod 'a') */
+ }
+
+ if (BN_cmp(w, a1) == 0) {
+ return 0; /* w == -1 (mod a), 'a' is probably prime */
+ }
+ }
+
+ /* If we get here, 'w' is the (a-1)/2-th power of the original 'w',
+ * and it is neither -1 nor +1 -- so 'a' cannot be prime */
+ return 1;
+}
+
+static int probable_prime(BIGNUM *rnd, int bits) {
+ int i;
+ uint16_t mods[NUMPRIMES];
+ BN_ULONG delta, maxdelta;
+
+again:
+ if (!BN_rand(rnd, bits, 1, 1)) {
+ return 0;
+ }
+
+ /* we now have a random number 'rand' to test. */
+ for (i = 1; i < NUMPRIMES; i++) {
+ mods[i] = (uint16_t)BN_mod_word(rnd, (BN_ULONG)primes[i]);
+ }
+ maxdelta = BN_MASK2 - primes[NUMPRIMES - 1];
+ delta = 0;
+
+loop:
+ for (i = 1; i < NUMPRIMES; i++) {
+ /* check that rnd is not a prime and also
+ * that gcd(rnd-1,primes) == 1 (except for 2) */
+ if (((mods[i] + delta) % primes[i]) <= 1) {
+ delta += 2;
+ if (delta > maxdelta) {
+ goto again;
+ }
+ goto loop;
+ }
+ }
+
+ if (!BN_add_word(rnd, delta)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int probable_prime_dh(BIGNUM *rnd, int bits, const BIGNUM *add,
+ const BIGNUM *rem, BN_CTX *ctx) {
+ int i, ret = 0;
+ BIGNUM *t1;
+
+ BN_CTX_start(ctx);
+ if ((t1 = BN_CTX_get(ctx)) == NULL) {
+ goto err;
+ }
+
+ if (!BN_rand(rnd, bits, 0, 1)) {
+ goto err;
+ }
+
+ /* we need ((rnd-rem) % add) == 0 */
+
+ if (!BN_mod(t1, rnd, add, ctx)) {
+ goto err;
+ }
+ if (!BN_sub(rnd, rnd, t1)) {
+ goto err;
+ }
+ if (rem == NULL) {
+ if (!BN_add_word(rnd, 1)) {
+ goto err;
+ }
+ } else {
+ if (!BN_add(rnd, rnd, rem)) {
+ goto err;
+ }
+ }
+ /* we now have a random number 'rand' to test. */
+
+loop:
+ for (i = 1; i < NUMPRIMES; i++) {
+ /* check that rnd is a prime */
+ if (BN_mod_word(rnd, (BN_ULONG)primes[i]) <= 1) {
+ if (!BN_add(rnd, rnd, add)) {
+ goto err;
+ }
+ goto loop;
+ }
+ }
+
+ ret = 1;
+
+err:
+ BN_CTX_end(ctx);
+ return ret;
+}
+
+static int probable_prime_dh_safe(BIGNUM *p, int bits, const BIGNUM *padd,
+ const BIGNUM *rem, BN_CTX *ctx) {
+ int i, ret = 0;
+ BIGNUM *t1, *qadd, *q;
+
+ bits--;
+ BN_CTX_start(ctx);
+ t1 = BN_CTX_get(ctx);
+ q = BN_CTX_get(ctx);
+ qadd = BN_CTX_get(ctx);
+ if (qadd == NULL) {
+ goto err;
+ }
+
+ if (!BN_rshift1(qadd, padd)) {
+ goto err;
+ }
+
+ if (!BN_rand(q, bits, 0, 1)) {
+ goto err;
+ }
+
+ /* we need ((rnd-rem) % add) == 0 */
+ if (!BN_mod(t1, q, qadd, ctx)) {
+ goto err;
+ }
+
+ if (!BN_sub(q, q, t1)) {
+ goto err;
+ }
+
+ if (rem == NULL) {
+ if (!BN_add_word(q, 1)) {
+ goto err;
+ }
+ } else {
+ if (!BN_rshift1(t1, rem)) {
+ goto err;
+ }
+ if (!BN_add(q, q, t1)) {
+ goto err;
+ }
+ }
+
+ /* we now have a random number 'rand' to test. */
+ if (!BN_lshift1(p, q)) {
+ goto err;
+ }
+ if (!BN_add_word(p, 1)) {
+ goto err;
+ }
+
+loop:
+ for (i = 1; i < NUMPRIMES; i++) {
+ /* check that p and q are prime */
+ /* check that for p and q
+ * gcd(p-1,primes) == 1 (except for 2) */
+ if ((BN_mod_word(p, (BN_ULONG)primes[i]) == 0) ||
+ (BN_mod_word(q, (BN_ULONG)primes[i]) == 0)) {
+ if (!BN_add(p, p, padd)) {
+ goto err;
+ }
+ if (!BN_add(q, q, qadd)) {
+ goto err;
+ }
+ goto loop;
+ }
+ }
+
+ ret = 1;
+
+err:
+ BN_CTX_end(ctx);
+ return ret;
+}
+
+static const uint16_t primes[NUMPRIMES] = {
+ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31,
+ 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79,
+ 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
+ 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193,
+ 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257,
+ 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317,
+ 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389,
+ 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457,
+ 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523,
+ 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601,
+ 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661,
+ 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743,
+ 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823,
+ 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887,
+ 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977,
+ 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049,
+ 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117,
+ 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213,
+ 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289,
+ 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373,
+ 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453,
+ 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531,
+ 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607,
+ 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693,
+ 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777,
+ 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871,
+ 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951,
+ 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029,
+ 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113,
+ 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213,
+ 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293,
+ 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377,
+ 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447,
+ 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551,
+ 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659,
+ 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713,
+ 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797,
+ 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887,
+ 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971,
+ 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079,
+ 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187,
+ 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271,
+ 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359,
+ 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461,
+ 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539,
+ 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617,
+ 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701,
+ 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797,
+ 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889,
+ 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989,
+ 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073,
+ 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157,
+ 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253,
+ 4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349,
+ 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451,
+ 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547,
+ 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643,
+ 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729,
+ 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817,
+ 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937,
+ 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009,
+ 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101,
+ 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209,
+ 5227, 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309,
+ 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417,
+ 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501,
+ 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581,
+ 5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683,
+ 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783,
+ 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857,
+ 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953,
+ 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073,
+ 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163,
+ 6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263,
+ 6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337,
+ 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427,
+ 6449, 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553,
+ 6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659,
+ 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737,
+ 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833,
+ 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947,
+ 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013,
+ 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127,
+ 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229,
+ 7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333,
+ 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477,
+ 7481, 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547,
+ 7549, 7559, 7561, 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621,
+ 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717,
+ 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829,
+ 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927,
+ 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053,
+ 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111, 8117, 8123, 8147,
+ 8161, 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 8237,
+ 8243, 8263, 8269, 8273, 8287, 8291, 8293, 8297, 8311, 8317, 8329,
+ 8353, 8363, 8369, 8377, 8387, 8389, 8419, 8423, 8429, 8431, 8443,
+ 8447, 8461, 8467, 8501, 8513, 8521, 8527, 8537, 8539, 8543, 8563,
+ 8573, 8581, 8597, 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663,
+ 8669, 8677, 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737,
+ 8741, 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831,
+ 8837, 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, 8929, 8933,
+ 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, 9013, 9029,
+ 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, 9127, 9133, 9137,
+ 9151, 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227,
+ 9239, 9241, 9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337,
+ 9341, 9343, 9349, 9371, 9377, 9391, 9397, 9403, 9413, 9419, 9421,
+ 9431, 9433, 9437, 9439, 9461, 9463, 9467, 9473, 9479, 9491, 9497,
+ 9511, 9521, 9533, 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623,
+ 9629, 9631, 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721,
+ 9733, 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811,
+ 9817, 9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887, 9901,
+ 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973, 10007, 10009, 10037,
+ 10039, 10061, 10067, 10069, 10079, 10091, 10093, 10099, 10103, 10111, 10133,
+ 10139, 10141, 10151, 10159, 10163, 10169, 10177, 10181, 10193, 10211, 10223,
+ 10243, 10247, 10253, 10259, 10267, 10271, 10273, 10289, 10301, 10303, 10313,
+ 10321, 10331, 10333, 10337, 10343, 10357, 10369, 10391, 10399, 10427, 10429,
+ 10433, 10453, 10457, 10459, 10463, 10477, 10487, 10499, 10501, 10513, 10529,
+ 10531, 10559, 10567, 10589, 10597, 10601, 10607, 10613, 10627, 10631, 10639,
+ 10651, 10657, 10663, 10667, 10687, 10691, 10709, 10711, 10723, 10729, 10733,
+ 10739, 10753, 10771, 10781, 10789, 10799, 10831, 10837, 10847, 10853, 10859,
+ 10861, 10867, 10883, 10889, 10891, 10903, 10909, 10937, 10939, 10949, 10957,
+ 10973, 10979, 10987, 10993, 11003, 11027, 11047, 11057, 11059, 11069, 11071,
+ 11083, 11087, 11093, 11113, 11117, 11119, 11131, 11149, 11159, 11161, 11171,
+ 11173, 11177, 11197, 11213, 11239, 11243, 11251, 11257, 11261, 11273, 11279,
+ 11287, 11299, 11311, 11317, 11321, 11329, 11351, 11353, 11369, 11383, 11393,
+ 11399, 11411, 11423, 11437, 11443, 11447, 11467, 11471, 11483, 11489, 11491,
+ 11497, 11503, 11519, 11527, 11549, 11551, 11579, 11587, 11593, 11597, 11617,
+ 11621, 11633, 11657, 11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731,
+ 11743, 11777, 11779, 11783, 11789, 11801, 11807, 11813, 11821, 11827, 11831,
+ 11833, 11839, 11863, 11867, 11887, 11897, 11903, 11909, 11923, 11927, 11933,
+ 11939, 11941, 11953, 11959, 11969, 11971, 11981, 11987, 12007, 12011, 12037,
+ 12041, 12043, 12049, 12071, 12073, 12097, 12101, 12107, 12109, 12113, 12119,
+ 12143, 12149, 12157, 12161, 12163, 12197, 12203, 12211, 12227, 12239, 12241,
+ 12251, 12253, 12263, 12269, 12277, 12281, 12289, 12301, 12323, 12329, 12343,
+ 12347, 12373, 12377, 12379, 12391, 12401, 12409, 12413, 12421, 12433, 12437,
+ 12451, 12457, 12473, 12479, 12487, 12491, 12497, 12503, 12511, 12517, 12527,
+ 12539, 12541, 12547, 12553, 12569, 12577, 12583, 12589, 12601, 12611, 12613,
+ 12619, 12637, 12641, 12647, 12653, 12659, 12671, 12689, 12697, 12703, 12713,
+ 12721, 12739, 12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 12823,
+ 12829, 12841, 12853, 12889, 12893, 12899, 12907, 12911, 12917, 12919, 12923,
+ 12941, 12953, 12959, 12967, 12973, 12979, 12983, 13001, 13003, 13007, 13009,
+ 13033, 13037, 13043, 13049, 13063, 13093, 13099, 13103, 13109, 13121, 13127,
+ 13147, 13151, 13159, 13163, 13171, 13177, 13183, 13187, 13217, 13219, 13229,
+ 13241, 13249, 13259, 13267, 13291, 13297, 13309, 13313, 13327, 13331, 13337,
+ 13339, 13367, 13381, 13397, 13399, 13411, 13417, 13421, 13441, 13451, 13457,
+ 13463, 13469, 13477, 13487, 13499, 13513, 13523, 13537, 13553, 13567, 13577,
+ 13591, 13597, 13613, 13619, 13627, 13633, 13649, 13669, 13679, 13681, 13687,
+ 13691, 13693, 13697, 13709, 13711, 13721, 13723, 13729, 13751, 13757, 13759,
+ 13763, 13781, 13789, 13799, 13807, 13829, 13831, 13841, 13859, 13873, 13877,
+ 13879, 13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 13963, 13967,
+ 13997, 13999, 14009, 14011, 14029, 14033, 14051, 14057, 14071, 14081, 14083,
+ 14087, 14107, 14143, 14149, 14153, 14159, 14173, 14177, 14197, 14207, 14221,
+ 14243, 14249, 14251, 14281, 14293, 14303, 14321, 14323, 14327, 14341, 14347,
+ 14369, 14387, 14389, 14401, 14407, 14411, 14419, 14423, 14431, 14437, 14447,
+ 14449, 14461, 14479, 14489, 14503, 14519, 14533, 14537, 14543, 14549, 14551,
+ 14557, 14561, 14563, 14591, 14593, 14621, 14627, 14629, 14633, 14639, 14653,
+ 14657, 14669, 14683, 14699, 14713, 14717, 14723, 14731, 14737, 14741, 14747,
+ 14753, 14759, 14767, 14771, 14779, 14783, 14797, 14813, 14821, 14827, 14831,
+ 14843, 14851, 14867, 14869, 14879, 14887, 14891, 14897, 14923, 14929, 14939,
+ 14947, 14951, 14957, 14969, 14983, 15013, 15017, 15031, 15053, 15061, 15073,
+ 15077, 15083, 15091, 15101, 15107, 15121, 15131, 15137, 15139, 15149, 15161,
+ 15173, 15187, 15193, 15199, 15217, 15227, 15233, 15241, 15259, 15263, 15269,
+ 15271, 15277, 15287, 15289, 15299, 15307, 15313, 15319, 15329, 15331, 15349,
+ 15359, 15361, 15373, 15377, 15383, 15391, 15401, 15413, 15427, 15439, 15443,
+ 15451, 15461, 15467, 15473, 15493, 15497, 15511, 15527, 15541, 15551, 15559,
+ 15569, 15581, 15583, 15601, 15607, 15619, 15629, 15641, 15643, 15647, 15649,
+ 15661, 15667, 15671, 15679, 15683, 15727, 15731, 15733, 15737, 15739, 15749,
+ 15761, 15767, 15773, 15787, 15791, 15797, 15803, 15809, 15817, 15823, 15859,
+ 15877, 15881, 15887, 15889, 15901, 15907, 15913, 15919, 15923, 15937, 15959,
+ 15971, 15973, 15991, 16001, 16007, 16033, 16057, 16061, 16063, 16067, 16069,
+ 16073, 16087, 16091, 16097, 16103, 16111, 16127, 16139, 16141, 16183, 16187,
+ 16189, 16193, 16217, 16223, 16229, 16231, 16249, 16253, 16267, 16273, 16301,
+ 16319, 16333, 16339, 16349, 16361, 16363, 16369, 16381, 16411, 16417, 16421,
+ 16427, 16433, 16447, 16451, 16453, 16477, 16481, 16487, 16493, 16519, 16529,
+ 16547, 16553, 16561, 16567, 16573, 16603, 16607, 16619, 16631, 16633, 16649,
+ 16651, 16657, 16661, 16673, 16691, 16693, 16699, 16703, 16729, 16741, 16747,
+ 16759, 16763, 16787, 16811, 16823, 16829, 16831, 16843, 16871, 16879, 16883,
+ 16889, 16901, 16903, 16921, 16927, 16931, 16937, 16943, 16963, 16979, 16981,
+ 16987, 16993, 17011, 17021, 17027, 17029, 17033, 17041, 17047, 17053, 17077,
+ 17093, 17099, 17107, 17117, 17123, 17137, 17159, 17167, 17183, 17189, 17191,
+ 17203, 17207, 17209, 17231, 17239, 17257, 17291, 17293, 17299, 17317, 17321,
+ 17327, 17333, 17341, 17351, 17359, 17377, 17383, 17387, 17389, 17393, 17401,
+ 17417, 17419, 17431, 17443, 17449, 17467, 17471, 17477, 17483, 17489, 17491,
+ 17497, 17509, 17519, 17539, 17551, 17569, 17573, 17579, 17581, 17597, 17599,
+ 17609, 17623, 17627, 17657, 17659, 17669, 17681, 17683, 17707, 17713, 17729,
+ 17737, 17747, 17749, 17761, 17783, 17789, 17791, 17807, 17827, 17837, 17839,
+ 17851, 17863, };
diff --git a/crypto/bn/random.c b/crypto/bn/random.c
new file mode 100644
index 0000000..1f1d732
--- /dev/null
+++ b/crypto/bn/random.c
@@ -0,0 +1,237 @@
+/* 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.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2001 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). */
+
+#include <openssl/bn.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/rand.h>
+
+int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) {
+ uint8_t *buf = NULL;
+ int ret = 0, bit, bytes, mask;
+
+ if (bits == 0) {
+ BN_zero(rnd);
+ return 1;
+ }
+
+ bytes = (bits + 7) / 8;
+ bit = (bits - 1) % 8;
+ mask = 0xff << (bit + 1);
+
+ buf = OPENSSL_malloc(bytes);
+ if (buf == NULL) {
+ OPENSSL_PUT_ERROR(BN, BN_rand, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* make a random number and set the top and bottom bits */
+ if (RAND_pseudo_bytes(buf, bytes) <= 0)
+ goto err;
+
+ if (top != -1) {
+ if (top) {
+ if (bit == 0) {
+ buf[0] = 1;
+ buf[1] |= 0x80;
+ } else {
+ buf[0] |= (3 << (bit - 1));
+ }
+ } else {
+ buf[0] |= (1 << bit);
+ }
+ }
+
+ buf[0] &= ~mask;
+
+ /* set bottom bit if requested */
+ if (bottom) {
+ buf[bytes - 1] |= 1;
+ }
+
+ if (!BN_bin2bn(buf, bytes, rnd)) {
+ goto err;
+ }
+
+ ret = 1;
+
+err:
+ if (buf != NULL) {
+ OPENSSL_cleanse(buf, bytes);
+ OPENSSL_free(buf);
+ }
+ return (ret);
+}
+
+int BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom) {
+ return BN_rand(rnd, bits, top, bottom);
+}
+
+int BN_rand_range(BIGNUM *r, const BIGNUM *range) {
+ unsigned n;
+ unsigned count = 100;
+
+ if (range->neg || BN_is_zero(range)) {
+ OPENSSL_PUT_ERROR(BN, BN_rand_range, BN_R_INVALID_RANGE);
+ return 0;
+ }
+
+ n = BN_num_bits(range); /* n > 0 */
+
+ /* BN_is_bit_set(range, n - 1) always holds */
+ if (n == 1) {
+ BN_zero(r);
+ } else if (!BN_is_bit_set(range, n - 2) && !BN_is_bit_set(range, n - 3)) {
+ /* range = 100..._2,
+ * so 3*range (= 11..._2) is exactly one bit longer than range */
+ do {
+ if (!BN_rand(r, n + 1, -1 /* don't set most significant bits */,
+ 0 /* don't set least significant bits */)) {
+ return 0;
+ }
+
+ /* If r < 3*range, use r := r MOD range (which is either r, r - range, or
+ * r - 2*range). Otherwise, iterate again. Since 3*range = 11..._2, each
+ * iteration succeeds with probability >= .75. */
+ if (BN_cmp(r, range) >= 0) {
+ if (!BN_sub(r, r, range)) {
+ return 0;
+ }
+ if (BN_cmp(r, range) >= 0) {
+ if (!BN_sub(r, r, range)) {
+ return 0;
+ }
+ }
+ }
+
+ if (!--count) {
+ OPENSSL_PUT_ERROR(BN, BN_rand_range, BN_R_TOO_MANY_ITERATIONS);
+ return 0;
+ }
+ } while (BN_cmp(r, range) >= 0);
+ } else {
+ do {
+ /* range = 11..._2 or range = 101..._2 */
+ if (!BN_rand(r, n, -1, 0)) {
+ return 0;
+ }
+
+ if (!--count) {
+ OPENSSL_PUT_ERROR(BN, BN_rand_range, BN_R_TOO_MANY_ITERATIONS);
+ return 0;
+ }
+ } while (BN_cmp(r, range) >= 0);
+ }
+
+ return 1;
+}
+
+int BN_pseudo_rand_range(BIGNUM *r, const BIGNUM *range) {
+ return BN_rand_range(r, range);
+}
diff --git a/crypto/bn/rsaz_exp.c b/crypto/bn/rsaz_exp.c
new file mode 100644
index 0000000..43bb351
--- /dev/null
+++ b/crypto/bn/rsaz_exp.c
@@ -0,0 +1,320 @@
+/*****************************************************************************
+* *
+* 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. *
+* *
+******************************************************************************
+* Developers and authors: *
+* Shay Gueron (1, 2), and Vlad Krasnov (1) *
+* (1) Intel Corporation, Israel Development Center, Haifa, Israel *
+* (2) University of Haifa, Israel *
+*****************************************************************************/
+
+#include "rsaz_exp.h"
+
+#include <openssl/mem.h>
+
+/*
+ * See crypto/bn/asm/rsaz-avx2.pl for further details.
+ */
+void rsaz_1024_norm2red_avx2(void *red,const void *norm);
+void rsaz_1024_mul_avx2(void *ret,const void *a,const void *b,const void *n,BN_ULONG k);
+void rsaz_1024_sqr_avx2(void *ret,const void *a,const void *n,BN_ULONG k,int cnt);
+void rsaz_1024_scatter5_avx2(void *tbl,const void *val,int i);
+void rsaz_1024_gather5_avx2(void *val,const void *tbl,int i);
+void rsaz_1024_red2norm_avx2(void *norm,const void *red);
+
+#if defined(__GNUC__)
+# define ALIGN64 __attribute__((aligned(64)))
+#elif defined(_MSC_VER)
+# define ALIGN64 __declspec(align(64))
+#elif defined(__SUNPRO_C)
+# define ALIGN64
+# pragma align 64(one,two80)
+#else
+# define ALIGN64 /* not fatal, might hurt performance a little */
+#endif
+
+ALIGN64 static const BN_ULONG one[40] =
+ {1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+ALIGN64 static const BN_ULONG two80[40] =
+ {0,0,1<<22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+void RSAZ_1024_mod_exp_avx2(BN_ULONG result_norm[16],
+ const BN_ULONG base_norm[16], const BN_ULONG exponent[16],
+ const BN_ULONG m_norm[16], const BN_ULONG RR[16], BN_ULONG k0)
+{
+ unsigned char storage[320*3+32*9*16+64]; /* 5.5KB */
+ unsigned char *p_str = storage + (64-((size_t)storage%64));
+ unsigned char *a_inv, *m, *result,
+ *table_s = p_str+320*3,
+ *R2 = table_s; /* borrow */
+ int index;
+ int wvalue;
+
+ if ((((size_t)p_str&4095)+320)>>12) {
+ result = p_str;
+ a_inv = p_str + 320;
+ m = p_str + 320*2; /* should not cross page */
+ } else {
+ m = p_str; /* should not cross page */
+ result = p_str + 320;
+ a_inv = p_str + 320*2;
+ }
+
+ rsaz_1024_norm2red_avx2(m, m_norm);
+ rsaz_1024_norm2red_avx2(a_inv, base_norm);
+ rsaz_1024_norm2red_avx2(R2, RR);
+
+ rsaz_1024_mul_avx2(R2, R2, R2, m, k0);
+ rsaz_1024_mul_avx2(R2, R2, two80, m, k0);
+
+ /* table[0] = 1 */
+ rsaz_1024_mul_avx2(result, R2, one, m, k0);
+ /* table[1] = a_inv^1 */
+ rsaz_1024_mul_avx2(a_inv, a_inv, R2, m, k0);
+
+ rsaz_1024_scatter5_avx2(table_s,result,0);
+ rsaz_1024_scatter5_avx2(table_s,a_inv,1);
+
+ /* table[2] = a_inv^2 */
+ rsaz_1024_sqr_avx2(result, a_inv, m, k0, 1);
+ rsaz_1024_scatter5_avx2(table_s,result,2);
+#if 0
+ /* this is almost 2x smaller and less than 1% slower */
+ for (index=3; index<32; index++) {
+ rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+ rsaz_1024_scatter5_avx2(table_s,result,index);
+ }
+#else
+ /* table[4] = a_inv^4 */
+ rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+ rsaz_1024_scatter5_avx2(table_s,result,4);
+ /* table[8] = a_inv^8 */
+ rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+ rsaz_1024_scatter5_avx2(table_s,result,8);
+ /* table[16] = a_inv^16 */
+ rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+ rsaz_1024_scatter5_avx2(table_s,result,16);
+ /* table[17] = a_inv^17 */
+ rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+ rsaz_1024_scatter5_avx2(table_s,result,17);
+
+ /* table[3] */
+ rsaz_1024_gather5_avx2(result,table_s,2);
+ rsaz_1024_mul_avx2(result,result,a_inv,m,k0);
+ rsaz_1024_scatter5_avx2(table_s,result,3);
+ /* table[6] */
+ rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+ rsaz_1024_scatter5_avx2(table_s,result,6);
+ /* table[12] */
+ rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+ rsaz_1024_scatter5_avx2(table_s,result,12);
+ /* table[24] */
+ rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+ rsaz_1024_scatter5_avx2(table_s,result,24);
+ /* table[25] */
+ rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+ rsaz_1024_scatter5_avx2(table_s,result,25);
+
+ /* table[5] */
+ rsaz_1024_gather5_avx2(result,table_s,4);
+ rsaz_1024_mul_avx2(result,result,a_inv,m,k0);
+ rsaz_1024_scatter5_avx2(table_s,result,5);
+ /* table[10] */
+ rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+ rsaz_1024_scatter5_avx2(table_s,result,10);
+ /* table[20] */
+ rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+ rsaz_1024_scatter5_avx2(table_s,result,20);
+ /* table[21] */
+ rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+ rsaz_1024_scatter5_avx2(table_s,result,21);
+
+ /* table[7] */
+ rsaz_1024_gather5_avx2(result,table_s,6);
+ rsaz_1024_mul_avx2(result,result,a_inv,m,k0);
+ rsaz_1024_scatter5_avx2(table_s,result,7);
+ /* table[14] */
+ rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+ rsaz_1024_scatter5_avx2(table_s,result,14);
+ /* table[28] */
+ rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+ rsaz_1024_scatter5_avx2(table_s,result,28);
+ /* table[29] */
+ rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+ rsaz_1024_scatter5_avx2(table_s,result,29);
+
+ /* table[9] */
+ rsaz_1024_gather5_avx2(result,table_s,8);
+ rsaz_1024_mul_avx2(result,result,a_inv,m,k0);
+ rsaz_1024_scatter5_avx2(table_s,result,9);
+ /* table[18] */
+ rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+ rsaz_1024_scatter5_avx2(table_s,result,18);
+ /* table[19] */
+ rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+ rsaz_1024_scatter5_avx2(table_s,result,19);
+
+ /* table[11] */
+ rsaz_1024_gather5_avx2(result,table_s,10);
+ rsaz_1024_mul_avx2(result,result,a_inv,m,k0);
+ rsaz_1024_scatter5_avx2(table_s,result,11);
+ /* table[22] */
+ rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+ rsaz_1024_scatter5_avx2(table_s,result,22);
+ /* table[23] */
+ rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+ rsaz_1024_scatter5_avx2(table_s,result,23);
+
+ /* table[13] */
+ rsaz_1024_gather5_avx2(result,table_s,12);
+ rsaz_1024_mul_avx2(result,result,a_inv,m,k0);
+ rsaz_1024_scatter5_avx2(table_s,result,13);
+ /* table[26] */
+ rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+ rsaz_1024_scatter5_avx2(table_s,result,26);
+ /* table[27] */
+ rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+ rsaz_1024_scatter5_avx2(table_s,result,27);
+
+ /* table[15] */
+ rsaz_1024_gather5_avx2(result,table_s,14);
+ rsaz_1024_mul_avx2(result,result,a_inv,m,k0);
+ rsaz_1024_scatter5_avx2(table_s,result,15);
+ /* table[30] */
+ rsaz_1024_sqr_avx2(result, result, m, k0, 1);
+ rsaz_1024_scatter5_avx2(table_s,result,30);
+ /* table[31] */
+ rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+ rsaz_1024_scatter5_avx2(table_s,result,31);
+#endif
+
+ /* load first window */
+ p_str = (unsigned char*)exponent;
+ wvalue = p_str[127] >> 3;
+ rsaz_1024_gather5_avx2(result,table_s,wvalue);
+
+ index = 1014;
+
+ while(index > -1) { /* loop for the remaining 127 windows */
+
+ rsaz_1024_sqr_avx2(result, result, m, k0, 5);
+
+ wvalue = *((unsigned short*)&p_str[index/8]);
+ wvalue = (wvalue>> (index%8)) & 31;
+ index-=5;
+
+ rsaz_1024_gather5_avx2(a_inv,table_s,wvalue); /* borrow a_inv */
+ rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+ }
+
+ /* square four times */
+ rsaz_1024_sqr_avx2(result, result, m, k0, 4);
+
+ wvalue = p_str[0] & 15;
+
+ rsaz_1024_gather5_avx2(a_inv,table_s,wvalue); /* borrow a_inv */
+ rsaz_1024_mul_avx2(result, result, a_inv, m, k0);
+
+ /* from Montgomery */
+ rsaz_1024_mul_avx2(result, result, one, m, k0);
+
+ rsaz_1024_red2norm_avx2(result_norm, result);
+
+ OPENSSL_cleanse(storage,sizeof(storage));
+}
+
+/*
+ * See crypto/bn/rsaz-x86_64.pl for further details.
+ */
+void rsaz_512_mul(void *ret,const void *a,const void *b,const void *n,BN_ULONG k);
+void rsaz_512_mul_scatter4(void *ret,const void *a,const void *n,BN_ULONG k,const void *tbl,unsigned int power);
+void rsaz_512_mul_gather4(void *ret,const void *a,const void *tbl,const void *n,BN_ULONG k,unsigned int power);
+void rsaz_512_mul_by_one(void *ret,const void *a,const void *n,BN_ULONG k);
+void rsaz_512_sqr(void *ret,const void *a,const void *n,BN_ULONG k,int cnt);
+void rsaz_512_scatter4(void *tbl, const BN_ULONG *val, int power);
+void rsaz_512_gather4(BN_ULONG *val, const void *tbl, int power);
+
+void RSAZ_512_mod_exp(BN_ULONG result[8],
+ const BN_ULONG base[8], const BN_ULONG exponent[8],
+ const BN_ULONG m[8], BN_ULONG k0, const BN_ULONG RR[8])
+{
+ unsigned char storage[16*8*8+64*2+64]; /* 1.2KB */
+ unsigned char *table = storage + (64-((size_t)storage%64));
+ BN_ULONG *a_inv = (BN_ULONG *)(table+16*8*8),
+ *temp = (BN_ULONG *)(table+16*8*8+8*8);
+ unsigned char *p_str = (unsigned char*)exponent;
+ int index;
+ unsigned int wvalue;
+
+ /* table[0] = 1_inv */
+ temp[0] = 0-m[0]; temp[1] = ~m[1];
+ temp[2] = ~m[2]; temp[3] = ~m[3];
+ temp[4] = ~m[4]; temp[5] = ~m[5];
+ temp[6] = ~m[6]; temp[7] = ~m[7];
+ rsaz_512_scatter4(table, temp, 0);
+
+ /* table [1] = a_inv^1 */
+ rsaz_512_mul(a_inv, base, RR, m, k0);
+ rsaz_512_scatter4(table, a_inv, 1);
+
+ /* table [2] = a_inv^2 */
+ rsaz_512_sqr(temp, a_inv, m, k0, 1);
+ rsaz_512_scatter4(table, temp, 2);
+
+ for (index=3; index<16; index++)
+ rsaz_512_mul_scatter4(temp, a_inv, m, k0, table, index);
+
+ /* load first window */
+ wvalue = p_str[63];
+
+ rsaz_512_gather4(temp, table, wvalue>>4);
+ rsaz_512_sqr(temp, temp, m, k0, 4);
+ rsaz_512_mul_gather4(temp, temp, table, m, k0, wvalue&0xf);
+
+ for (index=62; index>=0; index--) {
+ wvalue = p_str[index];
+
+ rsaz_512_sqr(temp, temp, m, k0, 4);
+ rsaz_512_mul_gather4(temp, temp, table, m, k0, wvalue>>4);
+
+ rsaz_512_sqr(temp, temp, m, k0, 4);
+ rsaz_512_mul_gather4(temp, temp, table, m, k0, wvalue&0x0f);
+ }
+
+ /* from Montgomery */
+ rsaz_512_mul_by_one(result, temp, m, k0);
+
+ OPENSSL_cleanse(storage,sizeof(storage));
+}
diff --git a/crypto/bn/rsaz_exp.h b/crypto/bn/rsaz_exp.h
new file mode 100644
index 0000000..4241a1f
--- /dev/null
+++ b/crypto/bn/rsaz_exp.h
@@ -0,0 +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
+******************************************************************************
+* 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.
+******************************************************************************/
+
+#ifndef RSAZ_EXP_H
+#define RSAZ_EXP_H
+
+#include <openssl/bn.h>
+
+void RSAZ_1024_mod_exp_avx2(BN_ULONG result[16],
+ const BN_ULONG base_norm[16], const BN_ULONG exponent[16],
+ const BN_ULONG m_norm[16], const BN_ULONG RR[16], BN_ULONG k0);
+int rsaz_avx2_eligible();
+
+void RSAZ_512_mod_exp(BN_ULONG result[8],
+ const BN_ULONG base_norm[8], const BN_ULONG exponent[8],
+ const BN_ULONG m_norm[8], BN_ULONG k0, const BN_ULONG RR[8]);
+#endif
diff --git a/crypto/bn/shift.c b/crypto/bn/shift.c
new file mode 100644
index 0000000..384a697
--- /dev/null
+++ b/crypto/bn/shift.c
@@ -0,0 +1,284 @@
+/* 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/bn.h>
+
+#include "internal.h"
+
+int BN_lshift(BIGNUM *r, const BIGNUM *a, int n) {
+ int i, nw, lb, rb;
+ BN_ULONG *t, *f;
+ BN_ULONG l;
+
+ r->neg = a->neg;
+ nw = n / BN_BITS2;
+ if (bn_wexpand(r, a->top + nw + 1) == NULL) {
+ return 0;
+ }
+ lb = n % BN_BITS2;
+ rb = BN_BITS2 - lb;
+ f = a->d;
+ t = r->d;
+ t[a->top + nw] = 0;
+ if (lb == 0) {
+ for (i = a->top - 1; i >= 0; i--) {
+ t[nw + i] = f[i];
+ }
+ } else {
+ for (i = a->top - 1; i >= 0; i--) {
+ l = f[i];
+ t[nw + i + 1] |= (l >> rb) & BN_MASK2;
+ t[nw + i] = (l << lb) & BN_MASK2;
+ }
+ }
+ memset(t, 0, nw * sizeof(t[0]));
+ r->top = a->top + nw + 1;
+ bn_correct_top(r);
+
+ return 1;
+}
+
+int BN_lshift1(BIGNUM *r, const BIGNUM *a) {
+ BN_ULONG *ap, *rp, t, c;
+ int i;
+
+ if (r != a) {
+ r->neg = a->neg;
+ if (bn_wexpand(r, a->top + 1) == NULL) {
+ return 0;
+ }
+ r->top = a->top;
+ } else {
+ if (bn_wexpand(r, a->top + 1) == NULL) {
+ return 0;
+ }
+ }
+ ap = a->d;
+ rp = r->d;
+ c = 0;
+ for (i = 0; i < a->top; i++) {
+ t = *(ap++);
+ *(rp++) = ((t << 1) | c) & BN_MASK2;
+ c = (t & BN_TBIT) ? 1 : 0;
+ }
+ if (c) {
+ *rp = 1;
+ r->top++;
+ }
+
+ return 1;
+}
+
+int BN_rshift(BIGNUM *r, const BIGNUM *a, int n) {
+ int i, j, nw, lb, rb;
+ BN_ULONG *t, *f;
+ BN_ULONG l, tmp;
+
+ nw = n / BN_BITS2;
+ rb = n % BN_BITS2;
+ lb = BN_BITS2 - rb;
+ if (nw >= a->top || a->top == 0) {
+ BN_zero(r);
+ return 1;
+ }
+ i = (BN_num_bits(a) - n + (BN_BITS2 - 1)) / BN_BITS2;
+ if (r != a) {
+ r->neg = a->neg;
+ if (bn_wexpand(r, i) == NULL) {
+ return 0;
+ }
+ } else {
+ if (n == 0) {
+ return 1; /* or the copying loop will go berserk */
+ }
+ }
+
+ f = &(a->d[nw]);
+ t = r->d;
+ j = a->top - nw;
+ r->top = i;
+
+ if (rb == 0) {
+ for (i = j; i != 0; i--) {
+ *(t++) = *(f++);
+ }
+ } else {
+ l = *(f++);
+ for (i = j - 1; i != 0; i--) {
+ tmp = (l >> rb) & BN_MASK2;
+ l = *(f++);
+ *(t++) = (tmp | (l << lb)) & BN_MASK2;
+ }
+ if ((l = (l >> rb) & BN_MASK2)) {
+ *(t) = l;
+ }
+ }
+
+ return 1;
+}
+
+int BN_rshift1(BIGNUM *r, const BIGNUM *a) {
+ BN_ULONG *ap, *rp, t, c;
+ int i, j;
+
+ if (BN_is_zero(a)) {
+ BN_zero(r);
+ return 1;
+ }
+ i = a->top;
+ ap = a->d;
+ j = i - (ap[i - 1] == 1);
+ if (a != r) {
+ if (bn_wexpand(r, j) == NULL) {
+ return 0;
+ }
+ r->neg = a->neg;
+ }
+ rp = r->d;
+ t = ap[--i];
+ c = (t & 1) ? BN_TBIT : 0;
+ if (t >>= 1) {
+ rp[i] = t;
+ }
+ while (i > 0) {
+ t = ap[--i];
+ rp[i] = ((t >> 1) & BN_MASK2) | c;
+ c = (t & 1) ? BN_TBIT : 0;
+ }
+ r->top = j;
+
+ return 1;
+}
+
+int BN_set_bit(BIGNUM *a, int n) {
+ int i, j, k;
+
+ if (n < 0) {
+ return 0;
+ }
+
+ i = n / BN_BITS2;
+ j = n % BN_BITS2;
+ if (a->top <= i) {
+ if (bn_wexpand(a, i + 1) == NULL) {
+ return 0;
+ }
+ for (k = a->top; k < i + 1; k++) {
+ a->d[k] = 0;
+ }
+ a->top = i + 1;
+ }
+
+ a->d[i] |= (((BN_ULONG)1) << j);
+
+ return 1;
+}
+
+int BN_clear_bit(BIGNUM *a, int n) {
+ int i, j;
+
+ if (n < 0) {
+ return 0;
+ }
+
+ i = n / BN_BITS2;
+ j = n % BN_BITS2;
+ if (a->top <= i) {
+ return 0;
+ }
+
+ a->d[i] &= (~(((BN_ULONG)1) << j));
+ bn_correct_top(a);
+ return 1;
+}
+
+int BN_is_bit_set(const BIGNUM *a, int n) {
+ int i, j;
+
+ if (n < 0) {
+ return 0;
+ }
+ i = n / BN_BITS2;
+ j = n % BN_BITS2;
+ if (a->top <= i) {
+ return 0;
+ }
+
+ return (a->d[i]>>j)&1;
+}
+
+int BN_mask_bits(BIGNUM *a, int n) {
+ int b, w;
+
+ if (n < 0) {
+ return 0;
+ }
+
+ w = n / BN_BITS2;
+ b = n % BN_BITS2;
+ if (w >= a->top) {
+ return 0;
+ }
+ if (b == 0) {
+ a->top = w;
+ } else {
+ a->top = w + 1;
+ a->d[w] &= ~(BN_MASK2 << b);
+ }
+
+ bn_correct_top(a);
+ return 1;
+}
diff --git a/crypto/bn/sqrt.c b/crypto/bn/sqrt.c
new file mode 100644
index 0000000..3ec763b
--- /dev/null
+++ b/crypto/bn/sqrt.c
@@ -0,0 +1,430 @@
+/* Written by Lenka Fibikova <fibikova@exp-math.uni-essen.de>
+ * and Bodo Moeller for the OpenSSL project. */
+/* ====================================================================
+ * Copyright (c) 1998-2000 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). */
+
+#include <openssl/bn.h>
+
+#include <openssl/err.h>
+
+
+/* Returns 'ret' such that
+ * ret^2 == a (mod p),
+ * using the Tonelli/Shanks algorithm (cf. Henri Cohen, "A Course
+ * in Algebraic Computational Number Theory", algorithm 1.5.1).
+ * 'p' must be prime! */
+BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx) {
+ BIGNUM *ret = in;
+ int err = 1;
+ int r;
+ BIGNUM *A, *b, *q, *t, *x, *y;
+ int e, i, j;
+
+ if (!BN_is_odd(p) || BN_abs_is_word(p, 1)) {
+ if (BN_abs_is_word(p, 2)) {
+ if (ret == NULL) {
+ ret = BN_new();
+ }
+ if (ret == NULL) {
+ goto end;
+ }
+ if (!BN_set_word(ret, BN_is_bit_set(a, 0))) {
+ if (ret != in) {
+ BN_free(ret);
+ }
+ return NULL;
+ }
+ return ret;
+ }
+
+ OPENSSL_PUT_ERROR(BN, BN_mod_sqrt, BN_R_P_IS_NOT_PRIME);
+ return (NULL);
+ }
+
+ if (BN_is_zero(a) || BN_is_one(a)) {
+ if (ret == NULL) {
+ ret = BN_new();
+ }
+ if (ret == NULL) {
+ goto end;
+ }
+ if (!BN_set_word(ret, BN_is_one(a))) {
+ if (ret != in) {
+ BN_free(ret);
+ }
+ return NULL;
+ }
+ return ret;
+ }
+
+ BN_CTX_start(ctx);
+ A = BN_CTX_get(ctx);
+ b = BN_CTX_get(ctx);
+ q = BN_CTX_get(ctx);
+ t = BN_CTX_get(ctx);
+ x = BN_CTX_get(ctx);
+ y = BN_CTX_get(ctx);
+ if (y == NULL) {
+ goto end;
+ }
+
+ if (ret == NULL) {
+ ret = BN_new();
+ }
+ if (ret == NULL) {
+ goto end;
+ }
+
+ /* A = a mod p */
+ if (!BN_nnmod(A, a, p, ctx)) {
+ goto end;
+ }
+
+ /* now write |p| - 1 as 2^e*q where q is odd */
+ e = 1;
+ while (!BN_is_bit_set(p, e)) {
+ e++;
+ }
+ /* we'll set q later (if needed) */
+
+ if (e == 1) {
+ /* The easy case: (|p|-1)/2 is odd, so 2 has an inverse
+ * modulo (|p|-1)/2, and square roots can be computed
+ * directly by modular exponentiation.
+ * We have
+ * 2 * (|p|+1)/4 == 1 (mod (|p|-1)/2),
+ * so we can use exponent (|p|+1)/4, i.e. (|p|-3)/4 + 1.
+ */
+ if (!BN_rshift(q, p, 2)) {
+ goto end;
+ }
+ q->neg = 0;
+ if (!BN_add_word(q, 1) ||
+ !BN_mod_exp(ret, A, q, p, ctx)) {
+ goto end;
+ }
+ err = 0;
+ goto vrfy;
+ }
+
+ if (e == 2) {
+ /* |p| == 5 (mod 8)
+ *
+ * In this case 2 is always a non-square since
+ * Legendre(2,p) = (-1)^((p^2-1)/8) for any odd prime.
+ * So if a really is a square, then 2*a is a non-square.
+ * Thus for
+ * b := (2*a)^((|p|-5)/8),
+ * i := (2*a)*b^2
+ * we have
+ * i^2 = (2*a)^((1 + (|p|-5)/4)*2)
+ * = (2*a)^((p-1)/2)
+ * = -1;
+ * so if we set
+ * x := a*b*(i-1),
+ * then
+ * x^2 = a^2 * b^2 * (i^2 - 2*i + 1)
+ * = a^2 * b^2 * (-2*i)
+ * = a*(-i)*(2*a*b^2)
+ * = a*(-i)*i
+ * = a.
+ *
+ * (This is due to A.O.L. Atkin,
+ * <URL:
+ *http://listserv.nodak.edu/scripts/wa.exe?A2=ind9211&L=nmbrthry&O=T&P=562>,
+ * November 1992.)
+ */
+
+ /* t := 2*a */
+ if (!BN_mod_lshift1_quick(t, A, p)) {
+ goto end;
+ }
+
+ /* b := (2*a)^((|p|-5)/8) */
+ if (!BN_rshift(q, p, 3)) {
+ goto end;
+ }
+ q->neg = 0;
+ if (!BN_mod_exp(b, t, q, p, ctx)) {
+ goto end;
+ }
+
+ /* y := b^2 */
+ if (!BN_mod_sqr(y, b, p, ctx)) {
+ goto end;
+ }
+
+ /* t := (2*a)*b^2 - 1*/
+ if (!BN_mod_mul(t, t, y, p, ctx) ||
+ !BN_sub_word(t, 1)) {
+ goto end;
+ }
+
+ /* x = a*b*t */
+ if (!BN_mod_mul(x, A, b, p, ctx) ||
+ !BN_mod_mul(x, x, t, p, ctx)) {
+ goto end;
+ }
+
+ if (!BN_copy(ret, x)) {
+ goto end;
+ }
+ err = 0;
+ goto vrfy;
+ }
+
+ /* e > 2, so we really have to use the Tonelli/Shanks algorithm.
+ * First, find some y that is not a square. */
+ if (!BN_copy(q, p)) {
+ goto end; /* use 'q' as temp */
+ }
+ q->neg = 0;
+ i = 2;
+ do {
+ /* For efficiency, try small numbers first;
+ * if this fails, try random numbers.
+ */
+ if (i < 22) {
+ if (!BN_set_word(y, i)) {
+ goto end;
+ }
+ } else {
+ if (!BN_pseudo_rand(y, BN_num_bits(p), 0, 0)) {
+ goto end;
+ }
+ if (BN_ucmp(y, p) >= 0) {
+ if (!(p->neg ? BN_add : BN_sub)(y, y, p)) {
+ goto end;
+ }
+ }
+ /* now 0 <= y < |p| */
+ if (BN_is_zero(y)) {
+ if (!BN_set_word(y, i)) {
+ goto end;
+ }
+ }
+ }
+
+ r = BN_kronecker(y, q, ctx); /* here 'q' is |p| */
+ if (r < -1) {
+ goto end;
+ }
+ if (r == 0) {
+ /* m divides p */
+ OPENSSL_PUT_ERROR(BN, BN_mod_sqrt, BN_R_P_IS_NOT_PRIME);
+ goto end;
+ }
+ } while (r == 1 && ++i < 82);
+
+ if (r != -1) {
+ /* Many rounds and still no non-square -- this is more likely
+ * a bug than just bad luck.
+ * 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);
+ goto end;
+ }
+
+ /* Here's our actual 'q': */
+ if (!BN_rshift(q, q, e)) {
+ goto end;
+ }
+
+ /* Now that we have some non-square, we can find an element
+ * of order 2^e by computing its q'th power. */
+ if (!BN_mod_exp(y, y, q, p, ctx)) {
+ goto end;
+ }
+ if (BN_is_one(y)) {
+ OPENSSL_PUT_ERROR(BN, BN_mod_sqrt, BN_R_P_IS_NOT_PRIME);
+ goto end;
+ }
+
+ /* Now we know that (if p is indeed prime) there is an integer
+ * k, 0 <= k < 2^e, such that
+ *
+ * a^q * y^k == 1 (mod p).
+ *
+ * As a^q is a square and y is not, k must be even.
+ * q+1 is even, too, so there is an element
+ *
+ * X := a^((q+1)/2) * y^(k/2),
+ *
+ * and it satisfies
+ *
+ * X^2 = a^q * a * y^k
+ * = a,
+ *
+ * so it is the square root that we are looking for.
+ */
+
+ /* t := (q-1)/2 (note that q is odd) */
+ if (!BN_rshift1(t, q)) {
+ goto end;
+ }
+
+ /* x := a^((q-1)/2) */
+ if (BN_is_zero(t)) /* special case: p = 2^e + 1 */
+ {
+ if (!BN_nnmod(t, A, p, ctx)) {
+ goto end;
+ }
+ if (BN_is_zero(t)) {
+ /* special case: a == 0 (mod p) */
+ BN_zero(ret);
+ err = 0;
+ goto end;
+ } else if (!BN_one(x)) {
+ goto end;
+ }
+ } else {
+ if (!BN_mod_exp(x, A, t, p, ctx)) {
+ goto end;
+ }
+ if (BN_is_zero(x)) {
+ /* special case: a == 0 (mod p) */
+ BN_zero(ret);
+ err = 0;
+ goto end;
+ }
+ }
+
+ /* b := a*x^2 (= a^q) */
+ if (!BN_mod_sqr(b, x, p, ctx) ||
+ !BN_mod_mul(b, b, A, p, ctx)) {
+ goto end;
+ }
+
+ /* x := a*x (= a^((q+1)/2)) */
+ if (!BN_mod_mul(x, x, A, p, ctx)) {
+ goto end;
+ }
+
+ while (1) {
+ /* Now b is a^q * y^k for some even k (0 <= k < 2^E
+ * where E refers to the original value of e, which we
+ * don't keep in a variable), and x is a^((q+1)/2) * y^(k/2).
+ *
+ * We have a*b = x^2,
+ * y^2^(e-1) = -1,
+ * b^2^(e-1) = 1.
+ */
+
+ if (BN_is_one(b)) {
+ if (!BN_copy(ret, x)) {
+ goto end;
+ }
+ err = 0;
+ goto vrfy;
+ }
+
+
+ /* find smallest i such that b^(2^i) = 1 */
+ i = 1;
+ if (!BN_mod_sqr(t, b, p, ctx)) {
+ goto end;
+ }
+ while (!BN_is_one(t)) {
+ i++;
+ if (i == e) {
+ OPENSSL_PUT_ERROR(BN, BN_mod_sqrt, BN_R_NOT_A_SQUARE);
+ goto end;
+ }
+ if (!BN_mod_mul(t, t, t, p, ctx)) {
+ goto end;
+ }
+ }
+
+
+ /* t := y^2^(e - i - 1) */
+ if (!BN_copy(t, y)) {
+ goto end;
+ }
+ for (j = e - i - 1; j > 0; j--) {
+ if (!BN_mod_sqr(t, t, p, ctx)) {
+ goto end;
+ }
+ }
+ if (!BN_mod_mul(y, t, t, p, ctx) ||
+ !BN_mod_mul(x, x, t, p, ctx) ||
+ !BN_mod_mul(b, b, y, p, ctx)) {
+ goto end;
+ }
+ e = i;
+ }
+
+vrfy:
+ if (!err) {
+ /* verify the result -- the input might have been not a square
+ * (test added in 0.9.8) */
+
+ if (!BN_mod_sqr(x, ret, p, ctx)) {
+ err = 1;
+ }
+
+ if (!err && 0 != BN_cmp(x, A)) {
+ OPENSSL_PUT_ERROR(BN, BN_mod_sqrt, BN_R_NOT_A_SQUARE);
+ err = 1;
+ }
+ }
+
+end:
+ if (err) {
+ if (ret != NULL && ret != in) {
+ BN_clear_free(ret);
+ }
+ ret = NULL;
+ }
+ BN_CTX_end(ctx);
+ return ret;
+}
diff --git a/crypto/buf/CMakeLists.txt b/crypto/buf/CMakeLists.txt
new file mode 100644
index 0000000..c039260
--- /dev/null
+++ b/crypto/buf/CMakeLists.txt
@@ -0,0 +1,10 @@
+include_directories(. .. ../../include)
+
+add_library(
+ buf
+
+ OBJECT
+
+ buf.c
+ buf_error.c
+)
diff --git a/crypto/buf/buf.c b/crypto/buf/buf.c
new file mode 100644
index 0000000..fe55c0c
--- /dev/null
+++ b/crypto/buf/buf.c
@@ -0,0 +1,218 @@
+/* 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/buf.h>
+
+#include <openssl/mem.h>
+#include <openssl/err.h>
+
+
+BUF_MEM *BUF_MEM_new(void) {
+ BUF_MEM *ret;
+
+ ret = OPENSSL_malloc(sizeof(BUF_MEM));
+ if (ret == NULL) {
+ OPENSSL_PUT_ERROR(BUF, BUF_MEM_new, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ memset(ret, 0, sizeof(BUF_MEM));
+ return ret;
+}
+
+void BUF_MEM_free(BUF_MEM *buf) {
+ if (buf == NULL) {
+ return;
+ }
+
+ if (buf->data != NULL) {
+ OPENSSL_cleanse(buf->data, buf->max);
+ OPENSSL_free(buf->data);
+ }
+
+ OPENSSL_free(buf);
+}
+
+static size_t buf_mem_grow(BUF_MEM *buf, size_t len, char clean) {
+ char *new_buf;
+ size_t n, alloc_size;
+
+ if (buf->length >= len) {
+ buf->length = len;
+ return len;
+ }
+ if (buf->max >= len) {
+ memset(&buf->data[buf->length], 0, len - buf->length);
+ buf->length = len;
+ return len;
+ }
+
+ n = len + 3;
+ if (n < len) {
+ /* overflow */
+ OPENSSL_PUT_ERROR(BUF, buf_mem_grow, 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);
+ return 0;
+ }
+
+ if (buf->data == NULL) {
+ new_buf = OPENSSL_malloc(alloc_size);
+ } else {
+ if (clean) {
+ new_buf = OPENSSL_realloc_clean(buf->data, buf->max, alloc_size);
+ } else {
+ new_buf = OPENSSL_realloc(buf->data, alloc_size);
+ }
+ }
+
+ if (new_buf == NULL) {
+ OPENSSL_PUT_ERROR(BUF, buf_mem_grow, ERR_R_MALLOC_FAILURE);
+ len = 0;
+ } else {
+ buf->data = new_buf;
+ buf->max = alloc_size;
+ memset(&buf->data[buf->length], 0, len - buf->length);
+ buf->length = len;
+ }
+
+ return len;
+}
+
+size_t BUF_MEM_grow(BUF_MEM *buf, size_t len) {
+ return buf_mem_grow(buf, len, 0 /* don't clear old buffer contents. */);
+}
+
+size_t BUF_MEM_grow_clean(BUF_MEM *buf, size_t len) {
+ return buf_mem_grow(buf, len, 1 /* clear old buffer contents. */);
+}
+
+char *BUF_strdup(const char *buf) {
+ if (buf == NULL) {
+ return NULL;
+ }
+
+ return BUF_strndup(buf, strlen(buf));
+}
+
+char *BUF_strndup(const char *buf, size_t size) {
+ char *ret;
+ size_t alloc_size;
+
+ if (buf == NULL) {
+ return NULL;
+ }
+
+ alloc_size = size + 1;
+ if (alloc_size < size) {
+ /* overflow */
+ OPENSSL_PUT_ERROR(BUF, BUF_strndup, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ ret = OPENSSL_malloc(alloc_size);
+ if (ret == NULL) {
+ OPENSSL_PUT_ERROR(BUF, BUF_strndup, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ BUF_strlcpy(ret, buf, alloc_size);
+ return ret;
+}
+
+size_t BUF_strlcpy(char *dst, const char *src, size_t dst_size) {
+ size_t l = 0;
+
+ for (; dst_size > 1 && *src; dst_size--) {
+ *dst++ = *src++;
+ l++;
+ }
+
+ if (dst_size) {
+ *dst = 0;
+ }
+
+ return l + strlen(src);
+}
+
+size_t BUF_strlcat(char *dst, const char *src, size_t dst_size) {
+ size_t l = 0;
+ for (; dst_size > 0 && *dst; dst_size--, dst++) {
+ l++;
+ }
+ return l + BUF_strlcpy(dst, src, dst_size);
+}
+
+void *BUF_memdup(const void *data, size_t dst_size) {
+ void *ret;
+
+ if (data == NULL) {
+ return NULL;
+ }
+
+ ret = OPENSSL_malloc(dst_size);
+ if (ret == NULL) {
+ OPENSSL_PUT_ERROR(BUF, BUF_memdup, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ memcpy(ret, data, dst_size);
+ return ret;
+}
diff --git a/crypto/buf/buf.h b/crypto/buf/buf.h
new file mode 100644
index 0000000..4cfeee4
--- /dev/null
+++ b/crypto/buf/buf.h
@@ -0,0 +1,115 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_BUFFER_H
+#define OPENSSL_HEADER_BUFFER_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* BUF_MEM is a generic buffer object used by OpenSSL. */
+struct buf_mem_st {
+ size_t length; /* current number of bytes */
+ char *data;
+ size_t max; /* size of buffer */
+};
+
+/* BUF_MEM_new creates a new BUF_MEM which has no allocated data buffer. */
+BUF_MEM *BUF_MEM_new(void);
+
+/* BUF_MEM_free frees |buf->data| if needed and then frees |buf| itself. */
+void BUF_MEM_free(BUF_MEM *buf);
+
+/* BUF_MEM_grow ensures that |buf| has length |len| and allocates memory if
+ * needed. If the length of |buf| increased, the new bytes are filled with
+ * zeros. It returns the length of |buf|, or zero if there's an error. */
+size_t BUF_MEM_grow(BUF_MEM *buf, size_t len);
+
+/* BUF_MEM_grow_clean acts the same as |BUF_MEM_grow|, but clears the previous
+ * contents of memory if reallocing. */
+size_t BUF_MEM_grow_clean(BUF_MEM *str, size_t len);
+
+/* BUF_strdup returns an allocated, duplicate of |str|. */
+char *BUF_strdup(const char *str);
+
+/* BUF_strndup returns an allocated, duplicate of |str|, which is, at most,
+ * |size| bytes. The result is always NUL terminated. */
+char *BUF_strndup(const char *str, size_t size);
+
+/* BUF_memdup returns an allocated, duplicate of |size| bytes from |data|. */
+void *BUF_memdup(const void *data, size_t size);
+
+/* BUF_strlcpy acts like strlcpy(3). */
+size_t BUF_strlcpy(char *dst, const char *src, size_t dst_size);
+
+/* BUF_strlcat acts like strlcat(3). */
+size_t BUF_strlcat(char *dst, const char *src, size_t size);
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#define BUF_F_BUF_MEM_new 100
+#define BUF_F_buf_mem_grow 101
+#define BUF_F_BUF_strndup 102
+#define BUF_F_BUF_memdup 103
+
+#endif /* OPENSSL_HEADER_BUFFER_H */
diff --git a/crypto/buf/buf_error.c b/crypto/buf/buf_error.c
new file mode 100644
index 0000000..66be604
--- /dev/null
+++ b/crypto/buf/buf_error.c
@@ -0,0 +1,25 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/err.h>
+
+#include "buf.h"
+
+const ERR_STRING_DATA BUF_error_string_data[] = {
+ {ERR_PACK(ERR_LIB_BUF, BUF_F_BUF_MEM_new, 0), "BUF_MEM_new"},
+ {ERR_PACK(ERR_LIB_BUF, BUF_F_BUF_memdup, 0), "BUF_memdup"},
+ {ERR_PACK(ERR_LIB_BUF, BUF_F_BUF_strndup, 0), "BUF_strndup"},
+ {ERR_PACK(ERR_LIB_BUF, BUF_F_buf_mem_grow, 0), "buf_mem_grow"},
+ {0, NULL},
+};
diff --git a/crypto/bytestring/CMakeLists.txt b/crypto/bytestring/CMakeLists.txt
new file mode 100644
index 0000000..409a0ce
--- /dev/null
+++ b/crypto/bytestring/CMakeLists.txt
@@ -0,0 +1,18 @@
+include_directories(. .. ../../include)
+
+add_library(
+ bytestring
+
+ OBJECT
+
+ cbs.c
+ cbb.c
+)
+
+add_executable(
+ bytestring_test
+
+ bytestring_test.c
+)
+
+target_link_libraries(bytestring_test crypto)
diff --git a/crypto/bytestring/bytestring.h b/crypto/bytestring/bytestring.h
new file mode 100644
index 0000000..8f788a7
--- /dev/null
+++ b/crypto/bytestring/bytestring.h
@@ -0,0 +1,239 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#ifndef OPENSSL_HEADER_BYTESTRING_H
+#define OPENSSL_HEADER_BYTESTRING_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* Bytestrings are used for parsing and building TLS and ASN.1 messages.
+ *
+ * A "CBS" (CRYPTO ByteString) represents a string of bytes in memory and
+ * provides utility functions for safely parsing length-prefixed structures
+ * like TLS and ASN.1 from it.
+ *
+ * A "CBB" (CRYPTO ByteBuilder) is a memory buffer that grows as needed and
+ * provides utility functions for building length-prefixed messages. */
+
+
+/* CRYPTO ByteString */
+
+struct cbs_st {
+ const uint8_t *data;
+ size_t len;
+};
+
+/* CBS_init sets |cbs| to point to |data|. It does not take ownership of
+ * |data|. */
+void CBS_init(CBS *cbs, const uint8_t *data, size_t len);
+
+/* CBS_skip advances |cbs| by |len| bytes. It returns one on success and zero
+ * otherwise. */
+int CBS_skip(CBS *cbs, size_t len);
+
+/* CBS_data returns a pointer to the contains of |cbs|. */
+const uint8_t *CBS_data(const CBS *cbs);
+
+/* CBS_len returns the number of bytes remaining in |cbs|. */
+size_t CBS_len(const CBS *cbs);
+
+/* CBS_get_u8 sets |*out| to the next uint8_t from |cbs| and advances |cbs|. It
+ * returns one on success and zero on error. */
+int CBS_get_u8(CBS *cbs, uint8_t *out);
+
+/* CBS_get_u16 sets |*out| to the next, big-endian uint16_t from |cbs| and
+ * advances |cbs|. It returns one on success and zero on error. */
+int CBS_get_u16(CBS *cbs, uint16_t *out);
+
+/* CBS_get_u24 sets |*out| to the next, big-endian 24-bit value from |cbs| and
+ * advances |cbs|. It returns one on success and zero on error. */
+int CBS_get_u24(CBS *cbs, uint32_t *out);
+
+/* CBS_get_u32 sets |*out| to the next, big-endian uint32_t value from |cbs|
+ * and advances |cbs|. It returns one on success and zero on error. */
+int CBS_get_u32(CBS *cbs, uint32_t *out);
+
+/* CBS_get_bytes sets |*out| to the next |len| bytes from |cbs| and advances
+ * |cbs|. It returns one on success and zero on error. */
+int CBS_get_bytes(CBS *cbs, CBS *out, size_t len);
+
+/* CBS_get_u8_length_prefixed sets |*out| to the contents of an 8-bit,
+ * length-prefixed value from |cbs| and advances |cbs| over it. It returns one
+ * on success and zero on error. */
+int CBS_get_u8_length_prefixed(CBS *cbs, CBS *out);
+
+/* CBS_get_u16_length_prefixed sets |*out| to the contents of a 16-bit,
+ * big-endian, length-prefixed value from |cbs| and advances |cbs| over it. It
+ * returns one on success and zero on error. */
+int CBS_get_u16_length_prefixed(CBS *cbs, CBS *out);
+
+/* CBS_get_u24_length_prefixed sets |*out| to the contents of a 24-bit,
+ * big-endian, length-prefixed value from |cbs| and advances |cbs| over it. It
+ * returns one on success and zero on error. */
+int CBS_get_u24_length_prefixed(CBS *cbs, CBS *out);
+
+
+/* Parsing ASN.1 */
+
+#define CBS_ASN1_BOOLEAN 0x1
+#define CBS_ASN1_INTEGER 0x2
+#define CBS_ASN1_BITSTRING 0x3
+#define CBS_ASN1_OCTETSTRING 0x4
+#define CBS_ASN1_OBJECT 0x6
+#define CBS_ASN1_SEQUENCE (0x10 | CBS_ASN1_CONSTRUCTED)
+#define CBS_ASN1_SET (0x11 | CBS_ASN1_CONSTRUCTED)
+
+#define CBS_ASN1_CONSTRUCTED 0x20
+#define CBS_ASN1_CONTEXT_SPECIFIC 0x80
+
+#define CBS_ASN1_ANY 0x10000
+
+/* CBS_get_asn1 sets |*out| to the contents of DER-encoded, ASN.1 element (not
+ * including tag and length bytes) and advances |cbs| over it. The ASN.1
+ * element must match |tag_value|. It returns one on success and zero
+ * on error.
+ *
+ * Tag numbers greater than 31 are not supported. */
+int CBS_get_asn1(CBS *cbs, CBS *out, unsigned tag_value);
+
+/* CBS_get_asn1_ber sets |*out| to the contents of BER-encoded, ASN.1 element
+ * (not including tag and length bytes) and advances |cbs| over it. The ASN.1
+ * element must match |tag_value|. It returns one on success and zero on error.
+ *
+ * The major difference between this function and |CBS_get_asn1| is that
+ * indefinite-length elements may be processed by this function.
+ *
+ * Tag numbers greater than 31 are not supported. */
+int CBS_get_asn1_ber(CBS *cbs, CBS *out, unsigned tag_value);
+
+/* CBS_get_asn1_element acts like |CBS_get_asn1| but |out| will include the
+ * ASN.1 header bytes too. */
+int CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned tag_value);
+
+
+/* CRYPTO ByteBuilder.
+ *
+ * |CBB| objects allow one to build length-prefixed serialisations. A |CBB|
+ * object is associated with a buffer and new buffers are created with
+ * |CBB_init|. Several |CBB| objects can point at the same buffer when a
+ * length-prefix is pending, however only a single |CBB| can be 'current' at
+ * any one time. For example, if one calls |CBB_add_u8_length_prefixed| then
+ * the new |CBB| points at the same buffer as the original. But if the original
+ * |CBB| is used then the length prefix is written out and the new |CBB| must
+ * not be used again.
+ *
+ * If one needs to force a length prefix to be written out because a |CBB| is
+ * going out of scope, use |CBB_flush|. */
+
+struct cbb_buffer_st {
+ uint8_t *buf;
+ size_t len; /* The number of valid bytes. */
+ size_t cap; /* The size of buf. */
+ char can_resize; /* One iff |buf| is owned by this object. If not then |buf|
+ cannot be resized. */
+};
+
+struct cbb_st {
+ struct cbb_buffer_st *base;
+ /* offset is the offset from the start of |base->buf| to the position of any
+ * pending length-prefix. */
+ size_t offset;
+ /* child points to a child CBB if a length-prefix is pending. */
+ struct cbb_st *child;
+ /* pending_len_len contains the number of bytes in a pending length-prefix,
+ * or zero if no length-prefix is pending. */
+ uint8_t pending_len_len;
+ char pending_is_asn1;
+ /* is_top_level is true iff this is a top-level |CBB| (as opposed to a child
+ * |CBB|). Top-level objects are valid arguments for |CBB_finish|. */
+ char is_top_level;
+};
+
+/* CBB_init initialises |cbb| with |initial_capacity|. Since a |CBB| grows as
+ * needed, the |initial_capacity| is just a hint. It returns one on success or
+ * zero on error. */
+int CBB_init(CBB *cbb, size_t initial_capacity);
+
+/* CBB_init_fixed initialises |cbb| to write to |len| bytes at |buf|. Since
+ * |buf| cannot grow, trying to write more than |len| bytes will cause CBB
+ * functions to fail. It returns one on success or zero on error. */
+int CBB_init_fixed(CBB *cbb, uint8_t *buf, size_t len);
+
+/* CBB_cleanup frees all resources owned by |cbb| and other |CBB| objects
+ * writing to the same buffer. This should be used in an error case where a
+ * serialisation is abandoned. */
+void CBB_cleanup(CBB *cbb);
+
+/* CBB_finish completes any pending length prefix and sets |*out_data| to a
+ * malloced buffer and |*out_len| to the length of that buffer. The caller
+ * takes ownership of the buffer and, unless the buffer was fixed with
+ * |CBB_init_fixed|, must call |OPENSSL_free| when done.
+ *
+ * It can only be called on a "top level" |CBB|, i.e. one initialised with
+ * |CBB_init| or |CBB_init_fixed|. It returns one on success and zero on
+ * error. */
+int CBB_finish(CBB *cbb, uint8_t **out_data, size_t *out_len);
+
+/* CBB_flush causes any pending length prefixes to be written out and any child
+ * |CBB| objects of |cbb| to be invalidated. It returns one on success or zero
+ * on error. */
+int CBB_flush(CBB *cbb);
+
+/* CBB_add_u8_length_prefixed sets |*out_contents| to a new child of |cbb|. The
+ * data written to |*out_contents| will be prefixed in |cbb| with an 8-bit
+ * length. It returns one on success or zero on error. */
+int CBB_add_u8_length_prefixed(CBB *cbb, CBB *out_contents);
+
+/* CBB_add_u16_length_prefixed sets |*out_contents| to a new child of |cbb|.
+ * The data written to |*out_contents| will be prefixed in |cbb| with a 16-bit,
+ * big-endian length. It returns one on success or zero on error. */
+int CBB_add_u16_length_prefixed(CBB *cbb, CBB *out_contents);
+
+/* CBB_add_u24_length_prefixed sets |*out_contents| to a new child of |cbb|.
+ * The data written to |*out_contents| will be prefixed in |cbb| with a 24-bit,
+ * big-endian length. It returns one on success or zero on error. */
+int CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents);
+
+/* CBB_add_asn sets |*out_contents| to a |CBB| into which the contents of an
+ * ASN.1 object can be written. The |tag| argument will be used as the tag for
+ * the object. It returns one on success or zero on error. */
+int CBB_add_asn1(CBB *cbb, CBB *out_contents, uint8_t tag);
+
+/* CBB_add_bytes appends |len| bytes from |data| to |cbb|. It returns one on
+ * success and zero otherwise. */
+int CBB_add_bytes(CBB *cbb, const uint8_t *data, size_t len);
+
+/* CBB_add_u8 appends an 8-bit number from |value| to |cbb|. It returns one on
+ * success and zero otherwise. */
+int CBB_add_u8(CBB *cbb, uint8_t value);
+
+/* CBB_add_u8 appends a 16-bit, big-endian number from |value| to |cbb|. It
+ * returns one on success and zero otherwise. */
+int CBB_add_u16(CBB *cbb, uint16_t value);
+
+/* CBB_add_u24 appends a 24-bit, big-endian number from |value| to |cbb|. It
+ * returns one on success and zero otherwise. */
+int CBB_add_u24(CBB *cbb, uint32_t value);
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_BYTESTRING_H */
diff --git a/crypto/bytestring/bytestring_test.c b/crypto/bytestring/bytestring_test.c
new file mode 100644
index 0000000..fbfe61b
--- /dev/null
+++ b/crypto/bytestring/bytestring_test.c
@@ -0,0 +1,411 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <openssl/bytestring.h>
+
+
+static int test_skip() {
+ static const uint8_t kData[] = {1, 2, 3};
+ CBS data;
+
+ CBS_init(&data, kData, sizeof(kData));
+ return CBS_len(&data) == 3 &&
+ CBS_skip(&data, 1) &&
+ CBS_len(&data) == 2 &&
+ CBS_skip(&data, 2) &&
+ CBS_len(&data) == 0 &&
+ !CBS_skip(&data, 1);
+}
+
+static int test_get_u() {
+ static const uint8_t kData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ uint8_t u8;
+ uint16_t u16;
+ uint32_t u32;
+ CBS data;
+
+ CBS_init(&data, kData, sizeof(kData));
+ return CBS_get_u8(&data, &u8) &&
+ u8 == 1 &&
+ CBS_get_u16(&data, &u16) &&
+ u16 == 0x203 &&
+ CBS_get_u24(&data, &u32) &&
+ u32 == 0x40506 &&
+ CBS_get_u32(&data, &u32) &&
+ u32 == 0x708090a &&
+ !CBS_get_u8(&data, &u8);
+}
+
+static int test_get_prefixed() {
+ static const uint8_t kData[] = {1, 2, 0, 2, 3, 4, 0, 0, 3, 3, 2, 1};
+ uint8_t u8;
+ uint16_t u16;
+ uint32_t u32;
+ CBS data, prefixed;
+
+ CBS_init(&data, kData, sizeof(kData));
+ return CBS_get_u8_length_prefixed(&data, &prefixed) &&
+ CBS_len(&prefixed) == 1 &&
+ CBS_get_u8(&prefixed, &u8) &&
+ u8 == 2 &&
+ CBS_get_u16_length_prefixed(&data, &prefixed) &&
+ CBS_len(&prefixed) == 2 &&
+ CBS_get_u16(&prefixed, &u16) &&
+ u16 == 0x304 &&
+ CBS_get_u24_length_prefixed(&data, &prefixed) &&
+ CBS_len(&prefixed) == 3 &&
+ CBS_get_u24(&prefixed, &u32) &&
+ u32 == 0x30201;
+}
+
+static int test_get_prefixed_bad() {
+ static const uint8_t kData1[] = {2, 1};
+ static const uint8_t kData2[] = {0, 2, 1};
+ static const uint8_t kData3[] = {0, 0, 2, 1};
+ CBS data, prefixed;
+
+ CBS_init(&data, kData1, sizeof(kData1));
+ if (CBS_get_u8_length_prefixed(&data, &prefixed)) {
+ return 0;
+ }
+
+ CBS_init(&data, kData2, sizeof(kData2));
+ if (CBS_get_u16_length_prefixed(&data, &prefixed)) {
+ return 0;
+ }
+
+ CBS_init(&data, kData3, sizeof(kData3));
+ if (CBS_get_u24_length_prefixed(&data, &prefixed)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int test_get_asn1() {
+ static const uint8_t kData1[] = {0x30, 2, 1, 2};
+ static const uint8_t kData2[] = {0x30, 3, 1, 2};
+ static const uint8_t kData3[] = {0x30, 0x80};
+ static const uint8_t kData4[] = {0x30, 0x81, 1, 1};
+ static const uint8_t kData5[] = {0x30, 0x82, 0, 1, 1};
+
+ CBS data, contents;
+
+ CBS_init(&data, kData1, sizeof(kData1));
+ if (!CBS_get_asn1(&data, &contents, 0x30) ||
+ CBS_len(&contents) != 2 ||
+ memcmp(CBS_data(&contents), "\x01\x02", 2) != 0) {
+ return 0;
+ }
+
+ CBS_init(&data, kData2, sizeof(kData2));
+ /* data is truncated */
+ if (CBS_get_asn1(&data, &contents, 0x30)) {
+ return 0;
+ }
+
+ CBS_init(&data, kData3, sizeof(kData3));
+ /* zero byte length of length */
+ if (CBS_get_asn1(&data, &contents, 0x30)) {
+ return 0;
+ }
+
+ CBS_init(&data, kData4, sizeof(kData4));
+ /* long form mistakenly used. */
+ if (CBS_get_asn1(&data, &contents, 0x30)) {
+ return 0;
+ }
+
+ CBS_init(&data, kData5, sizeof(kData5));
+ /* length takes too many bytes. */
+ if (CBS_get_asn1(&data, &contents, 0x30)) {
+ return 0;
+ }
+
+ CBS_init(&data, kData1, sizeof(kData1));
+ /* wrong tag. */
+ if (CBS_get_asn1(&data, &contents, 0x31)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int test_get_indef() {
+ static const uint8_t kData1[] = {0x30, 0x80, 0x00, 0x00};
+ static const uint8_t kDataWithoutEOC[] = {0x30, 0x80, 0x01, 0x00};
+ static const uint8_t kDataWithBadInternalLength[] = {0x30, 0x80, 0x01, 0x01};
+ static const uint8_t kDataNested[] = {0x30, 0x80, 0x30, 0x80, 0x30, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+ CBS data, contents;
+ CBS_init(&data, kData1, sizeof(kData1));
+ if (CBS_get_asn1(&data, &contents, 0x30)) {
+ /* Indefinite lengths should not be supported in DER mode. */
+ fprintf(stderr, "Indefinite length parsed by CBS_get_asn1.\n");
+ return 0;
+ }
+
+ if (!CBS_get_asn1_ber(&data, &contents, 0x30) ||
+ CBS_len(&contents) != 0 ||
+ CBS_len(&data) != 0) {
+ fprintf(stderr, "Simple indefinite length failed.\n");
+ return 0;
+ }
+
+ CBS_init(&data, kDataWithoutEOC, sizeof(kDataWithoutEOC));
+ if (CBS_get_asn1_ber(&data, &contents, 0x30)) {
+ fprintf(stderr, "Parsed without EOC.\n");
+ return 0;
+ }
+
+ CBS_init(&data, kDataWithBadInternalLength,
+ sizeof(kDataWithBadInternalLength));
+ if (CBS_get_asn1_ber(&data, &contents, 0x30)) {
+ fprintf(stderr, "Parsed with internal length.\n");
+ return 0;
+ }
+
+ CBS_init(&data, kDataNested, sizeof(kDataNested));
+ if (!CBS_get_asn1_ber(&data, &contents, 0x30) ||
+ CBS_len(&contents) != 8 ||
+ CBS_len(&data) != 0) {
+ fprintf(stderr, "Nested indefinite lengths failed.\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int test_cbb_basic() {
+ static const uint8_t kExpected[] = {1, 2, 3, 4, 5, 6, 7, 8};
+ uint8_t *buf;
+ size_t buf_len;
+ int ok;
+ CBB cbb;
+
+ if (!CBB_init(&cbb, 100)) {
+ return 0;
+ }
+ CBB_cleanup(&cbb);
+
+ if (!CBB_init(&cbb, 0) ||
+ !CBB_add_u8(&cbb, 1) ||
+ !CBB_add_u16(&cbb, 0x203) ||
+ !CBB_add_u24(&cbb, 0x40506) ||
+ !CBB_add_bytes(&cbb, (const uint8_t*) "\x07\x08", 2) ||
+ !CBB_finish(&cbb, &buf, &buf_len)) {
+ return 0;
+ }
+
+ ok = buf_len == sizeof(kExpected) && memcmp(buf, kExpected, buf_len) == 0;
+ free(buf);
+ return ok;
+}
+
+static int test_cbb_fixed() {
+ CBB cbb;
+ uint8_t buf[1];
+ uint8_t *out_buf;
+ size_t out_size;
+
+ if (!CBB_init_fixed(&cbb, NULL, 0) ||
+ CBB_add_u8(&cbb, 1) ||
+ !CBB_finish(&cbb, &out_buf, &out_size) ||
+ out_buf != NULL ||
+ out_size != 0) {
+ return 0;
+ }
+
+ if (!CBB_init_fixed(&cbb, buf, 1) ||
+ !CBB_add_u8(&cbb, 1) ||
+ CBB_add_u8(&cbb, 2) ||
+ !CBB_finish(&cbb, &out_buf, &out_size) ||
+ out_buf != buf ||
+ out_size != 1 ||
+ buf[0] != 1) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int test_cbb_finish_child() {
+ CBB cbb, child;
+ uint8_t *out_buf;
+ size_t out_size;
+
+ if (!CBB_init(&cbb, 16) ||
+ !CBB_add_u8_length_prefixed(&cbb, &child) ||
+ CBB_finish(&child, &out_buf, &out_size) ||
+ !CBB_finish(&cbb, &out_buf, &out_size) ||
+ out_size != 1 ||
+ out_buf[0] != 0) {
+ return 0;
+ }
+
+ free(out_buf);
+ return 1;
+}
+
+static int test_cbb_prefixed() {
+ static const uint8_t kExpected[] = {0, 1, 1, 0, 2, 2, 3, 0, 0, 3,
+ 4, 5, 6, 5, 4, 1, 0, 1, 2};
+ uint8_t *buf;
+ size_t buf_len;
+ CBB cbb, contents, inner_contents, inner_inner_contents;
+ int ok;
+
+ if (!CBB_init(&cbb, 0) ||
+ !CBB_add_u8_length_prefixed(&cbb, &contents) ||
+ !CBB_add_u8_length_prefixed(&cbb, &contents) ||
+ !CBB_add_u8(&contents, 1) ||
+ !CBB_add_u16_length_prefixed(&cbb, &contents) ||
+ !CBB_add_u16(&contents, 0x203) ||
+ !CBB_add_u24_length_prefixed(&cbb, &contents) ||
+ !CBB_add_u24(&contents, 0x40506) ||
+ !CBB_add_u8_length_prefixed(&cbb, &contents) ||
+ !CBB_add_u8_length_prefixed(&contents, &inner_contents) ||
+ !CBB_add_u8(&inner_contents, 1) ||
+ !CBB_add_u16_length_prefixed(&inner_contents, &inner_inner_contents) ||
+ !CBB_add_u8(&inner_inner_contents, 2) ||
+ !CBB_finish(&cbb, &buf, &buf_len)) {
+ return 0;
+ }
+
+ ok = buf_len == sizeof(kExpected) && memcmp(buf, kExpected, buf_len) == 0;
+ free(buf);
+ return ok;
+}
+
+static int test_cbb_misuse() {
+ CBB cbb, child, contents;
+ uint8_t *buf;
+ size_t buf_len;
+
+ if (!CBB_init(&cbb, 0) ||
+ !CBB_add_u8_length_prefixed(&cbb, &child) ||
+ !CBB_add_u8(&child, 1) ||
+ !CBB_add_u8(&cbb, 2)) {
+ return 0;
+ }
+
+ /* Since we wrote to |cbb|, |child| is now invalid and attempts to write to
+ * it should fail. */
+ if (CBB_add_u8(&child, 1) ||
+ CBB_add_u16(&child, 1) ||
+ CBB_add_u24(&child, 1) ||
+ CBB_add_u8_length_prefixed(&child, &contents) ||
+ CBB_add_u16_length_prefixed(&child, &contents) ||
+ CBB_add_asn1(&child, &contents, 1) ||
+ CBB_add_bytes(&child, (const uint8_t*) "a", 1)) {
+ fprintf(stderr, "CBB operation on invalid CBB did not fail.\n");
+ return 0;
+ }
+
+ if (!CBB_finish(&cbb, &buf, &buf_len) ||
+ buf_len != 3 ||
+ memcmp(buf, "\x01\x01\x02", 3) != 0) {
+ return 0;
+ }
+
+ free(buf);
+
+ return 1;
+}
+
+static int test_cbb_asn1() {
+ static const uint8_t kExpected[] = {0x30, 3, 1, 2, 3};
+ uint8_t *buf, *test_data;
+ size_t buf_len;
+ CBB cbb, contents, inner_contents;
+
+ if (!CBB_init(&cbb, 0) ||
+ !CBB_add_asn1(&cbb, &contents, 0x30) ||
+ !CBB_add_bytes(&contents, (const uint8_t*) "\x01\x02\x03", 3) ||
+ !CBB_finish(&cbb, &buf, &buf_len)) {
+ return 0;
+ }
+
+ if (buf_len != sizeof(kExpected) || memcmp(buf, kExpected, buf_len) != 0) {
+ return 0;
+ }
+ free(buf);
+
+ test_data = calloc(1, 100000);
+
+ if (!CBB_init(&cbb, 0) ||
+ !CBB_add_asn1(&cbb, &contents, 0x30) ||
+ !CBB_add_bytes(&contents, test_data, 130) ||
+ !CBB_finish(&cbb, &buf, &buf_len)) {
+ return 0;
+ }
+
+ if (buf_len != 3 + 130 || memcmp(buf, "\x30\x81\x82", 3) != 0) {
+ return 0;
+ }
+ free(buf);
+
+ if (!CBB_init(&cbb, 0) ||
+ !CBB_add_asn1(&cbb, &contents, 0x30) ||
+ !CBB_add_bytes(&contents, test_data, 1000) ||
+ !CBB_finish(&cbb, &buf, &buf_len)) {
+ return 0;
+ }
+
+ if (buf_len != 4 + 1000 || memcmp(buf, "\x30\x82\x03\xe8", 4) != 0) {
+ return 0;
+ }
+ free(buf);
+
+ if (!CBB_init(&cbb, 0) ||
+ !CBB_add_asn1(&cbb, &contents, 0x30) ||
+ !CBB_add_asn1(&contents, &inner_contents, 0x30) ||
+ !CBB_add_bytes(&inner_contents, test_data, 100000) ||
+ !CBB_finish(&cbb, &buf, &buf_len)) {
+ return 0;
+ }
+
+ if (buf_len != 5 + 5 + 100000 ||
+ memcmp(buf, "\x30\x83\x01\x86\xa5\x30\x83\x01\x86\xa0", 10) != 0) {
+ return 0;
+ }
+ free(buf);
+
+ free(test_data);
+ return 1;
+}
+
+int main() {
+ if (!test_skip() ||
+ !test_get_u() ||
+ !test_get_prefixed() ||
+ !test_get_prefixed_bad() ||
+ !test_get_asn1() ||
+ !test_get_indef() ||
+ !test_cbb_basic() ||
+ !test_cbb_fixed() ||
+ !test_cbb_finish_child() ||
+ !test_cbb_misuse() ||
+ !test_cbb_prefixed() ||
+ !test_cbb_asn1()) {
+ return 1;
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/crypto/bytestring/cbb.c b/crypto/bytestring/cbb.c
new file mode 100644
index 0000000..3e35d5d
--- /dev/null
+++ b/crypto/bytestring/cbb.c
@@ -0,0 +1,317 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/bytestring.h>
+
+#include <openssl/mem.h>
+
+
+static int cbb_init(CBB *cbb, uint8_t *buf, size_t cap) {
+ struct cbb_buffer_st *base;
+
+ base = OPENSSL_malloc(sizeof(struct cbb_buffer_st));
+ if (base == NULL) {
+ OPENSSL_free(buf);
+ return 0;
+ }
+
+ base->buf = buf;
+ base->len = 0;
+ base->cap = cap;
+ base->can_resize = 1;
+
+ memset(cbb, 0, sizeof(CBB));
+ cbb->base = base;
+ cbb->is_top_level = 1;
+ return 1;
+}
+
+int CBB_init(CBB *cbb, size_t initial_capacity) {
+ uint8_t *buf;
+
+ buf = OPENSSL_malloc(initial_capacity);
+ if (initial_capacity > 0 && buf == NULL) {
+ return 0;
+ }
+
+ return cbb_init(cbb, buf, initial_capacity);
+}
+
+int CBB_init_fixed(CBB *cbb, uint8_t *buf, size_t len) {
+ if (!cbb_init(cbb, buf, len)) {
+ return 0;
+ }
+
+ cbb->base->can_resize = 0;
+ return 1;
+}
+
+void CBB_cleanup(CBB *cbb) {
+ if (cbb->base) {
+ if (cbb->base->buf && cbb->base->can_resize) {
+ OPENSSL_free(cbb->base->buf);
+ }
+ OPENSSL_free(cbb->base);
+ }
+ cbb->base = NULL;
+}
+
+static int cbb_buffer_add(struct cbb_buffer_st *base, uint8_t **out,
+ size_t len) {
+ size_t newlen;
+
+ if (base == NULL) {
+ return 0;
+ }
+
+ newlen = base->len + len;
+ if (newlen < base->len) {
+ /* Overflow */
+ return 0;
+ }
+
+ if (newlen > base->cap) {
+ size_t newcap = base->cap * 2;
+ uint8_t *newbuf;
+
+ if (!base->can_resize) {
+ return 0;
+ }
+
+ if (newcap < base->cap || newcap < newlen) {
+ newcap = newlen;
+ }
+ newbuf = OPENSSL_realloc(base->buf, newcap);
+ if (newbuf == NULL) {
+ return 0;
+ }
+
+ base->buf = newbuf;
+ base->cap = newcap;
+ }
+
+ if (out) {
+ *out = base->buf + base->len;
+ }
+ base->len = newlen;
+ return 1;
+}
+
+static int cbb_buffer_add_u(struct cbb_buffer_st *base, uint32_t v,
+ size_t len_len) {
+ uint8_t *buf;
+ size_t i;
+
+ if (len_len == 0) {
+ return 1;
+ }
+ if (!cbb_buffer_add(base, &buf, len_len)) {
+ return 0;
+ }
+
+ for (i = len_len - 1; i < len_len; i--) {
+ buf[i] = v;
+ v >>= 8;
+ }
+ return 1;
+}
+
+int CBB_finish(CBB *cbb, uint8_t **out_data, size_t *out_len) {
+ if (!cbb->is_top_level) {
+ return 0;
+ }
+
+ if (!CBB_flush(cbb)) {
+ return 0;
+ }
+
+ *out_data = cbb->base->buf;
+ *out_len = cbb->base->len;
+ cbb->base->buf = NULL;
+ CBB_cleanup(cbb);
+ return 1;
+}
+
+/* CBB_flush recurses and then writes out any pending length prefix. The
+ * current length of the underlying base is taken to be the length of the
+ * length-prefixed data. */
+int CBB_flush(CBB *cbb) {
+ size_t child_start, i, len;
+
+ if (cbb->base == NULL) {
+ return 0;
+ }
+
+ if (cbb->child == NULL || cbb->pending_len_len == 0) {
+ return 1;
+ }
+
+ child_start = cbb->offset + cbb->pending_len_len;
+
+ if (!CBB_flush(cbb->child) ||
+ child_start < cbb->offset ||
+ cbb->base->len < child_start) {
+ return 0;
+ }
+
+ len = cbb->base->len - child_start;
+
+ if (cbb->pending_is_asn1) {
+ /* For ASN.1 we assume that we'll only need a single byte for the length.
+ * If that turned out to be incorrect, we have to move the contents along
+ * in order to make space. */
+ size_t len_len;
+ uint8_t initial_length_byte;
+
+ if (len > 0xfffffffe) {
+ /* Too large. */
+ return 0;
+ } else if (len > 0xffffff) {
+ len_len = 5;
+ initial_length_byte = 0x80 | 4;
+ } else if (len > 0xffff) {
+ len_len = 4;
+ initial_length_byte = 0x80 | 3;
+ } else if (len > 0xff) {
+ len_len = 3;
+ initial_length_byte = 0x80 | 2;
+ } else if (len > 0x7f) {
+ len_len = 2;
+ initial_length_byte = 0x80 | 1;
+ } else {
+ len_len = 1;
+ initial_length_byte = len;
+ len = 0;
+ }
+
+ if (len_len != 1) {
+ /* We need to move the contents along in order to make space. */
+ size_t extra_bytes = len_len - 1;
+ if (!cbb_buffer_add(cbb->base, NULL, extra_bytes)) {
+ return 0;
+ }
+ memmove(cbb->base->buf + cbb->offset + extra_bytes,
+ cbb->base->buf + cbb->offset, len);
+ }
+ cbb->base->buf[cbb->offset++] = initial_length_byte;
+ cbb->pending_len_len = len_len - 1;
+ }
+
+ for (i = cbb->pending_len_len - 1; i < cbb->pending_len_len; i--) {
+ cbb->base->buf[cbb->offset + i] = len;
+ len >>= 8;
+ }
+ if (len != 0) {
+ return 0;
+ }
+
+ cbb->child->base = NULL;
+ cbb->child = NULL;
+ cbb->pending_len_len = 0;
+ cbb->pending_is_asn1 = 0;
+ cbb->offset = 0;
+
+ return 1;
+}
+
+
+static int cbb_add_length_prefixed(CBB *cbb, CBB *out_contents,
+ size_t len_len) {
+ uint8_t *prefix_bytes;
+
+ if (!CBB_flush(cbb)) {
+ return 0;
+ }
+
+ cbb->offset = cbb->base->len;
+ if (!cbb_buffer_add(cbb->base, &prefix_bytes, len_len)) {
+ return 0;
+ }
+
+ memset(prefix_bytes, 0, len_len);
+ memset(out_contents, 0, sizeof(CBB));
+ out_contents->base = cbb->base;
+ cbb->child = out_contents;
+ cbb->pending_len_len = len_len;
+ cbb->pending_is_asn1 = 0;
+
+ return 1;
+}
+
+int CBB_add_u8_length_prefixed(CBB *cbb, CBB *out_contents) {
+ return cbb_add_length_prefixed(cbb, out_contents, 1);
+}
+
+int CBB_add_u16_length_prefixed(CBB *cbb, CBB *out_contents) {
+ return cbb_add_length_prefixed(cbb, out_contents, 2);
+}
+
+int CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents) {
+ return cbb_add_length_prefixed(cbb, out_contents, 3);
+}
+
+int CBB_add_asn1(CBB *cbb, CBB *out_contents, uint8_t tag) {
+ if (!CBB_flush(cbb) ||
+ !CBB_add_u8(cbb, tag)) {
+ return 0;
+ }
+
+ cbb->offset = cbb->base->len;
+ if (!CBB_add_u8(cbb, 0)) {
+ return 0;
+ }
+
+ memset(out_contents, 0, sizeof(CBB));
+ out_contents->base = cbb->base;
+ cbb->child = out_contents;
+ cbb->pending_len_len = 1;
+ cbb->pending_is_asn1 = 1;
+
+ return 1;
+}
+
+int CBB_add_bytes(CBB *cbb, const uint8_t *data, size_t len) {
+ uint8_t *dest;
+
+ if (!CBB_flush(cbb) ||
+ !cbb_buffer_add(cbb->base, &dest, len)) {
+ return 0;
+ }
+ memcpy(dest, data, len);
+ return 1;
+}
+
+int CBB_add_u8(CBB *cbb, uint8_t value) {
+ if (!CBB_flush(cbb)) {
+ return 0;
+ }
+
+ return cbb_buffer_add_u(cbb->base, value, 1);
+}
+
+int CBB_add_u16(CBB *cbb, uint16_t value) {
+ if (!CBB_flush(cbb)) {
+ return 0;
+ }
+
+ return cbb_buffer_add_u(cbb->base, value, 2);
+}
+
+int CBB_add_u24(CBB *cbb, uint32_t value) {
+ if (!CBB_flush(cbb)) {
+ return 0;
+ }
+
+ return cbb_buffer_add_u(cbb->base, value, 3);
+}
diff --git a/crypto/bytestring/cbs.c b/crypto/bytestring/cbs.c
new file mode 100644
index 0000000..8ab8a74
--- /dev/null
+++ b/crypto/bytestring/cbs.c
@@ -0,0 +1,263 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/bytestring.h>
+
+#include <assert.h>
+
+
+void CBS_init(CBS *cbs, const uint8_t *data, size_t len) {
+ cbs->data = data;
+ cbs->len = len;
+}
+
+static int cbs_get(CBS *cbs, const uint8_t **p, size_t n) {
+ if (cbs->len < n) {
+ return 0;
+ }
+
+ *p = cbs->data;
+ cbs->data += n;
+ cbs->len -= n;
+ return 1;
+}
+
+int CBS_skip(CBS *cbs, size_t len) {
+ const uint8_t *dummy;
+ return cbs_get(cbs, &dummy, len);
+}
+
+const uint8_t *CBS_data(const CBS *cbs) {
+ return cbs->data;
+}
+
+size_t CBS_len(const CBS *cbs) {
+ return cbs->len;
+}
+
+static int cbs_get_u(CBS *cbs, uint32_t *out, size_t len) {
+ uint32_t result = 0;
+ size_t i;
+ const uint8_t *data;
+
+ if (!cbs_get(cbs, &data, len)) {
+ return 0;
+ }
+ for (i = 0; i < len; i++) {
+ result <<= 8;
+ result |= data[i];
+ }
+ *out = result;
+ return 1;
+}
+
+int CBS_get_u8(CBS *cbs, uint8_t *out) {
+ const uint8_t *v;
+ if (!cbs_get(cbs, &v, 1)) {
+ return 0;
+ }
+ *out = *v;
+ return 1;
+}
+
+int CBS_get_u16(CBS *cbs, uint16_t *out) {
+ uint32_t v;
+ if (!cbs_get_u(cbs, &v, 2)) {
+ return 0;
+ }
+ *out = v;
+ return 1;
+}
+
+int CBS_get_u24(CBS *cbs, uint32_t *out) {
+ return cbs_get_u(cbs, out, 3);
+}
+
+int CBS_get_u32(CBS *cbs, uint32_t *out) {
+ return cbs_get_u(cbs, out, 4);
+}
+
+int CBS_get_bytes(CBS *cbs, CBS *out, size_t len) {
+ const uint8_t *v;
+ if (!cbs_get(cbs, &v, len)) {
+ return 0;
+ }
+ CBS_init(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)) {
+ return 0;
+ }
+ return CBS_get_bytes(cbs, out, len);
+}
+
+int CBS_get_u8_length_prefixed(CBS *cbs, CBS *out) {
+ return cbs_get_length_prefixed(cbs, out, 1);
+}
+
+int CBS_get_u16_length_prefixed(CBS *cbs, CBS *out) {
+ return cbs_get_length_prefixed(cbs, out, 2);
+}
+
+int CBS_get_u24_length_prefixed(CBS *cbs, CBS *out) {
+ return cbs_get_length_prefixed(cbs, out, 3);
+}
+
+static int cbs_get_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
+ size_t *out_header_len, unsigned depth,
+ int *was_indefinite_len);
+
+/* cbs_get_asn1_indefinite_len sets |*out| to be a CBS that covers an
+ * indefinite length element in |cbs| and advances |*in|. On entry, |cbs| will
+ * not have had the tag and length byte removed. On exit, |*out| does not cover
+ * the EOC element, but |*in| is skipped over it.
+ *
+ * The |depth| argument counts the number of times the code has recursed trying
+ * to find an indefinite length. */
+static int cbs_get_asn1_indefinite_len(CBS *in, CBS *out, unsigned depth) {
+ static const size_t kEOCLength = 2;
+ size_t header_len;
+ unsigned tag;
+ int was_indefinite_len;
+ CBS orig = *in, child;
+
+ if (!CBS_skip(in, 2 /* tag plus 0x80 byte for indefinite len */)) {
+ return 0;
+ }
+
+ for (;;) {
+ if (!cbs_get_asn1_element(in, &child, &tag, &header_len, depth + 1,
+ &was_indefinite_len)) {
+ return 0;
+ }
+
+ if (!was_indefinite_len && CBS_len(&child) == kEOCLength &&
+ header_len == kEOCLength && tag == 0) {
+ break;
+ }
+ }
+
+ return CBS_get_bytes(&orig, out, CBS_len(&orig) - CBS_len(in) - kEOCLength);
+}
+
+/* MAX_DEPTH the maximum number of levels of indefinite lengths that we'll
+ * support. */
+#define MAX_DEPTH 64
+
+static int cbs_get_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
+ size_t *out_header_len, unsigned depth,
+ int *was_indefinite_len) {
+ uint8_t tag, length_byte;
+ CBS header = *cbs;
+ if (!CBS_get_u8(&header, &tag) ||
+ !CBS_get_u8(&header, &length_byte)) {
+ return 0;
+ }
+
+ if ((tag & 0x1f) == 0x1f) {
+ /* Long form tags are not supported. */
+ return 0;
+ }
+
+ *out_tag = tag;
+ if (was_indefinite_len) {
+ *was_indefinite_len = 0;
+ }
+
+ size_t len;
+ if ((length_byte & 0x80) == 0) {
+ /* Short form length. */
+ len = ((size_t) length_byte) + 2;
+ *out_header_len = 2;
+ } else {
+ /* Long form length. */
+ const size_t num_bytes = length_byte & 0x7f;
+ uint32_t len32;
+
+ if (depth < MAX_DEPTH && num_bytes == 0) {
+ /* indefinite length */
+ *out_header_len = 2;
+ if (was_indefinite_len) {
+ *was_indefinite_len = 1;
+ }
+ return cbs_get_asn1_indefinite_len(cbs, out, depth);
+ }
+
+ if (num_bytes == 0 || num_bytes > 4) {
+ return 0;
+ }
+ if (!cbs_get_u(&header, &len32, num_bytes)) {
+ return 0;
+ }
+ if (len32 < 128) {
+ /* Length should have used short-form encoding. */
+ return 0;
+ }
+ if ((len32 >> ((num_bytes-1)*8)) == 0) {
+ /* Length should have been at least one byte shorter. */
+ return 0;
+ }
+ len = len32;
+ if (len + 2 + num_bytes < len) {
+ /* Overflow. */
+ return 0;
+ }
+ len += 2 + num_bytes;
+ *out_header_len = 2 + num_bytes;
+ }
+
+ return CBS_get_bytes(cbs, out, len);
+}
+
+static int cbs_get_asn1(CBS *cbs, CBS *out, unsigned tag_value, int ber,
+ int skip_header) {
+ size_t header_len;
+ unsigned tag;
+ CBS throwaway;
+
+ if (out == NULL) {
+ out = &throwaway;
+ }
+
+ if (!cbs_get_asn1_element(cbs, out, &tag, &header_len, ber ? 0 : MAX_DEPTH,
+ NULL) ||
+ tag != tag_value) {
+ return 0;
+ }
+
+ if (skip_header && !CBS_skip(out, header_len)) {
+ assert(0);
+ return 0;
+ }
+
+ return 1;
+}
+
+int CBS_get_asn1(CBS *cbs, CBS *out, unsigned tag_value) {
+ return cbs_get_asn1(cbs, out, tag_value, 0 /* DER */,
+ 1 /* skip header */);
+}
+
+int CBS_get_asn1_ber(CBS *cbs, CBS *out, unsigned tag_value) {
+ return cbs_get_asn1(cbs, out, tag_value, 1 /* BER */,
+ 1 /* skip header */);
+}
+
+int CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned tag_value) {
+ return cbs_get_asn1(cbs, out, tag_value, 0 /* DER */,
+ 0 /* include header */);
+}
diff --git a/crypto/cipher/CMakeLists.txt b/crypto/cipher/CMakeLists.txt
new file mode 100644
index 0000000..55a5f87
--- /dev/null
+++ b/crypto/cipher/CMakeLists.txt
@@ -0,0 +1,24 @@
+include_directories(. .. ../../include)
+
+add_library(
+ cipher
+
+ OBJECT
+
+ cipher.c
+ cipher_error.c
+ derive_key.c
+
+ e_null.c
+ e_rc4.c
+ e_des.c
+ e_aes.c
+)
+
+add_executable(
+ cipher_test
+
+ cipher_test.c
+)
+
+target_link_libraries(cipher_test crypto)
diff --git a/crypto/cipher/cipher.c b/crypto/cipher/cipher.c
new file mode 100644
index 0000000..bf5c559
--- /dev/null
+++ b/crypto/cipher/cipher.c
@@ -0,0 +1,596 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/cipher.h>
+
+#include <string.h>
+#include <assert.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+
+#include "internal.h"
+
+
+const EVP_CIPHER *EVP_get_cipherbynid(int nid) {
+ switch (nid) {
+ 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_256_cbc:
+ return EVP_aes_256_cbc();
+ default:
+ return NULL;
+ }
+}
+
+void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx) {
+ memset(ctx, 0, sizeof(EVP_CIPHER_CTX));
+}
+
+EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void) {
+ EVP_CIPHER_CTX *ctx = OPENSSL_malloc(sizeof(EVP_CIPHER_CTX));
+ if (ctx) {
+ EVP_CIPHER_CTX_init(ctx);
+ }
+ return ctx;
+}
+
+int EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
+ const unsigned char *key, const unsigned char *iv, int enc) {
+ if (cipher) {
+ EVP_CIPHER_CTX_init(ctx);
+ }
+ return EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, enc);
+}
+
+int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *c) {
+ if (c->cipher != NULL && c->cipher->cleanup && !c->cipher->cleanup(c)) {
+ return 0;
+ }
+
+ if (c->cipher_data) {
+ OPENSSL_cleanse(c->cipher_data, c->cipher->ctx_size);
+ OPENSSL_free(c->cipher_data);
+ }
+
+ memset(c, 0, sizeof(EVP_CIPHER_CTX));
+ return 1;
+}
+
+void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx) {
+ if (ctx) {
+ EVP_CIPHER_CTX_cleanup(ctx);
+ OPENSSL_free(ctx);
+ }
+}
+
+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);
+ return 0;
+ }
+
+ EVP_CIPHER_CTX_cleanup(out);
+ memcpy(out, in, sizeof(EVP_CIPHER_CTX));
+
+ 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);
+ return 0;
+ }
+ memcpy(out->cipher_data, in->cipher_data, in->cipher->ctx_size);
+ }
+
+ return 1;
+}
+
+int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
+ ENGINE *engine, const uint8_t *key, const uint8_t *iv,
+ int enc) {
+ if (enc == -1) {
+ enc = ctx->encrypt;
+ } else {
+ if (enc) {
+ enc = 1;
+ }
+ ctx->encrypt = enc;
+ }
+
+ if (cipher) {
+ /* Ensure a context left from last time is cleared (the previous check
+ * attempted to avoid this if the same ENGINE and EVP_CIPHER could be
+ * used). */
+ if (ctx->cipher) {
+ EVP_CIPHER_CTX_cleanup(ctx);
+ /* Restore encrypt and flags */
+ ctx->encrypt = enc;
+ }
+
+ ctx->cipher = cipher;
+ if (ctx->cipher->ctx_size) {
+ ctx->cipher_data = OPENSSL_malloc(ctx->cipher->ctx_size);
+ if (!ctx->cipher_data) {
+ OPENSSL_PUT_ERROR(CIPHER, EVP_CipherInit_ex, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ } else {
+ ctx->cipher_data = NULL;
+ }
+
+ ctx->key_len = cipher->key_len;
+ ctx->flags = 0;
+
+ if (ctx->cipher->flags & EVP_CIPH_CTRL_INIT) {
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_INIT, 0, NULL)) {
+ OPENSSL_PUT_ERROR(CIPHER, EVP_CipherInit_ex, CIPHER_R_INITIALIZATION_ERROR);
+ return 0;
+ }
+ }
+ } else if (!ctx->cipher) {
+ OPENSSL_PUT_ERROR(CIPHER, EVP_CipherInit_ex, CIPHER_R_NO_CIPHER_SET);
+ return 0;
+ }
+
+ /* we assume block size is a power of 2 in *cryptUpdate */
+ assert(ctx->cipher->block_size == 1 || ctx->cipher->block_size == 8 ||
+ ctx->cipher->block_size == 16);
+
+ if (!(EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_CUSTOM_IV)) {
+ switch (EVP_CIPHER_CTX_mode(ctx)) {
+ case EVP_CIPH_STREAM_CIPHER:
+ case EVP_CIPH_ECB_MODE:
+ break;
+
+ case EVP_CIPH_CFB_MODE:
+ case EVP_CIPH_OFB_MODE:
+ ctx->num = 0;
+ /* fall-through */
+
+ case EVP_CIPH_CBC_MODE:
+ assert(EVP_CIPHER_CTX_iv_length(ctx) <= sizeof(ctx->iv));
+ if (iv) {
+ memcpy(ctx->oiv, iv, EVP_CIPHER_CTX_iv_length(ctx));
+ }
+ memcpy(ctx->iv, ctx->oiv, EVP_CIPHER_CTX_iv_length(ctx));
+ break;
+
+ case EVP_CIPH_CTR_MODE:
+ ctx->num = 0;
+ /* Don't reuse IV for CTR mode */
+ if (iv) {
+ memcpy(ctx->iv, iv, EVP_CIPHER_CTX_iv_length(ctx));
+ }
+ break;
+
+ default:
+ return 0;
+ }
+ }
+
+ if (key || (ctx->cipher->flags & EVP_CIPH_ALWAYS_CALL_INIT)) {
+ if (!ctx->cipher->init(ctx, key, iv, enc)) {
+ return 0;
+ }
+ }
+
+ ctx->buf_len = 0;
+ ctx->final_used = 0;
+ ctx->block_mask = ctx->cipher->block_size - 1;
+ return 1;
+}
+
+int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
+ ENGINE *impl, const uint8_t *key, const uint8_t *iv) {
+ return EVP_CipherInit_ex(ctx, cipher, impl, key, iv, 1);
+}
+
+int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
+ ENGINE *impl, const uint8_t *key, const uint8_t *iv) {
+ return EVP_CipherInit_ex(ctx, cipher, impl, key, iv, 0);
+}
+
+int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
+ const uint8_t *in, int in_len) {
+ int i, j, bl;
+
+ if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) {
+ i = ctx->cipher->cipher(ctx, out, in, in_len);
+ if (i < 0) {
+ return 0;
+ } else {
+ *out_len = i;
+ }
+ return 1;
+ }
+
+ if (in_len <= 0) {
+ *out_len = 0;
+ return in_len == 0;
+ }
+
+ if (ctx->buf_len == 0 && (in_len & ctx->block_mask) == 0) {
+ if (ctx->cipher->cipher(ctx, out, in, in_len)) {
+ *out_len = in_len;
+ return 1;
+ } else {
+ *out_len = 0;
+ return 0;
+ }
+ }
+
+ i = ctx->buf_len;
+ bl = ctx->cipher->block_size;
+ assert(bl <= (int)sizeof(ctx->buf));
+ if (i != 0) {
+ if (i + in_len < bl) {
+ memcpy(&ctx->buf[i], in, in_len);
+ ctx->buf_len += in_len;
+ *out_len = 0;
+ return 1;
+ } else {
+ j = bl - i;
+ memcpy(&ctx->buf[i], in, j);
+ if (!ctx->cipher->cipher(ctx, out, ctx->buf, bl)) {
+ return 0;
+ }
+ in_len -= j;
+ in += j;
+ out += bl;
+ *out_len = bl;
+ }
+ } else {
+ *out_len = 0;
+ }
+
+ i = in_len & ctx->block_mask;
+ in_len -= i;
+ if (in_len > 0) {
+ if (!ctx->cipher->cipher(ctx, out, in, in_len)) {
+ return 0;
+ }
+ *out_len += in_len;
+ }
+
+ if (i != 0) {
+ memcpy(ctx->buf, &in[in_len], i);
+ }
+ ctx->buf_len = i;
+ return 1;
+}
+
+int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len) {
+ int n, ret;
+ unsigned int i, b, bl;
+
+ if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) {
+ ret = ctx->cipher->cipher(ctx, out, NULL, 0);
+ if (ret < 0) {
+ return 0;
+ } else {
+ *out_len = ret;
+ }
+ return 1;
+ }
+
+ b = ctx->cipher->block_size;
+ assert(b <= sizeof(ctx->buf));
+ if (b == 1) {
+ *out_len = 0;
+ return 1;
+ }
+
+ 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);
+ return 0;
+ }
+ *out_len = 0;
+ return 1;
+ }
+
+ n = b - bl;
+ for (i = bl; i < b; i++) {
+ ctx->buf[i] = n;
+ }
+ ret = ctx->cipher->cipher(ctx, out, ctx->buf, b);
+
+ if (ret) {
+ *out_len = b;
+ }
+
+ return ret;
+}
+
+int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
+ const uint8_t *in, int in_len) {
+ int fix_len;
+ unsigned int b;
+
+ if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) {
+ int r = ctx->cipher->cipher(ctx, out, in, in_len);
+ if (r < 0) {
+ *out_len = 0;
+ return 0;
+ } else {
+ *out_len = r;
+ }
+ return 1;
+ }
+
+ if (in_len <= 0) {
+ *out_len = 0;
+ return in_len == 0;
+ }
+
+ if (ctx->flags & EVP_CIPH_NO_PADDING) {
+ return EVP_EncryptUpdate(ctx, out, out_len, in, in_len);
+ }
+
+ b = ctx->cipher->block_size;
+ assert(b <= sizeof(ctx->final));
+
+ if (ctx->final_used) {
+ memcpy(out, ctx->final, b);
+ out += b;
+ fix_len = 1;
+ } else {
+ fix_len = 0;
+ }
+
+ if (!EVP_EncryptUpdate(ctx, out, out_len, in, in_len)) {
+ return 0;
+ }
+
+ /* if we have 'decrypted' a multiple of block size, make sure
+ * we have a copy of this last block */
+ if (b > 1 && !ctx->buf_len) {
+ *out_len -= b;
+ ctx->final_used = 1;
+ memcpy(ctx->final, &out[*out_len], b);
+ } else {
+ ctx->final_used = 0;
+ }
+
+ if (fix_len) {
+ *out_len += b;
+ }
+
+ return 1;
+}
+
+int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) {
+ int i, n;
+ unsigned int b;
+ *out_len = 0;
+
+ if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) {
+ i = ctx->cipher->cipher(ctx, out, NULL, 0);
+ if (i < 0) {
+ return 0;
+ } else {
+ *out_len = i;
+ }
+ return 1;
+ }
+
+ 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);
+ return 0;
+ }
+ *out_len = 0;
+ return 1;
+ }
+
+ if (b > 1) {
+ if (ctx->buf_len || !ctx->final_used) {
+ OPENSSL_PUT_ERROR(CIPHER, EVP_DecryptFinal_ex,
+ CIPHER_R_WRONG_FINAL_BLOCK_LENGTH);
+ return 0;
+ }
+ assert(b <= sizeof(ctx->final));
+
+ /* The following assumes that the ciphertext has been authenticated.
+ * 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);
+ return 0;
+ }
+
+ for (i = 0; i < n; i++) {
+ if (ctx->final[--b] != n) {
+ OPENSSL_PUT_ERROR(CIPHER, EVP_DecryptFinal_ex, CIPHER_R_BAD_DECRYPT);
+ return 0;
+ }
+ }
+
+ n = ctx->cipher->block_size - n;
+ for (i = 0; i < n; i++) {
+ out[i] = ctx->final[i];
+ }
+ *out_len = n;
+ } else {
+ *out_len = 0;
+ }
+
+ return 1;
+}
+
+int EVP_Cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in,
+ size_t in_len) {
+ return ctx->cipher->cipher(ctx, out, in, in_len);
+}
+
+int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
+ const uint8_t *in, int in_len) {
+ if (ctx->encrypt) {
+ return EVP_EncryptUpdate(ctx, out, out_len, in, in_len);
+ } else {
+ return EVP_DecryptUpdate(ctx, out, out_len, in, in_len);
+ }
+}
+
+int EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len) {
+ if (ctx->encrypt) {
+ return EVP_EncryptFinal_ex(ctx, out, out_len);
+ } else {
+ return EVP_DecryptFinal_ex(ctx, out, out_len);
+ }
+}
+
+const EVP_CIPHER *EVP_CIPHER_CTX_cipher(const EVP_CIPHER_CTX *ctx) {
+ return ctx->cipher;
+}
+
+int EVP_CIPHER_CTX_nid(const EVP_CIPHER_CTX *ctx) {
+ return ctx->cipher->nid;
+}
+
+unsigned EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *ctx) {
+ return ctx->cipher->block_size;
+}
+
+unsigned EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx) {
+ return ctx->key_len;
+}
+
+unsigned EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx) {
+ return ctx->cipher->iv_len;
+}
+
+void *EVP_CIPHER_CTX_get_app_data(const EVP_CIPHER_CTX *ctx) {
+ return ctx->app_data;
+}
+
+void EVP_CIPHER_CTX_set_app_data(EVP_CIPHER_CTX *ctx, void *data) {
+ ctx->app_data = data;
+}
+
+uint32_t EVP_CIPHER_CTX_flags(const EVP_CIPHER_CTX *ctx) {
+ return ctx->cipher->flags & ~EVP_CIPH_MODE_MASK;
+}
+
+uint32_t EVP_CIPHER_CTX_mode(const EVP_CIPHER_CTX *ctx) {
+ return ctx->cipher->flags & EVP_CIPH_MODE_MASK;
+}
+
+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);
+ return 0;
+ }
+
+ if (!ctx->cipher->ctrl) {
+ OPENSSL_PUT_ERROR(CIPHER, EVP_CIPHER_CTX_ctrl, 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);
+ return 0;
+ }
+
+ return ret;
+}
+
+int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int pad) {
+ if (pad) {
+ ctx->flags &= ~EVP_CIPH_NO_PADDING;
+ } else {
+ ctx->flags |= EVP_CIPH_NO_PADDING;
+ }
+ return 1;
+}
+
+int EVP_CIPHER_nid(const EVP_CIPHER *cipher) { return cipher->nid; }
+
+const char *EVP_CIPHER_name(const EVP_CIPHER *cipher) {
+ return OBJ_nid2sn(cipher->nid);
+}
+
+unsigned EVP_CIPHER_block_size(const EVP_CIPHER *cipher) {
+ return cipher->block_size;
+}
+
+unsigned EVP_CIPHER_key_length(const EVP_CIPHER *cipher) {
+ return cipher->key_len;
+}
+
+unsigned EVP_CIPHER_iv_length(const EVP_CIPHER *cipher) {
+ return cipher->iv_len;
+}
+
+uint32_t EVP_CIPHER_flags(const EVP_CIPHER *cipher) {
+ return cipher->flags & ~EVP_CIPH_MODE_MASK;
+}
+
+uint32_t EVP_CIPHER_mode(const EVP_CIPHER *cipher) {
+ return cipher->flags & EVP_CIPH_MODE_MASK;
+}
diff --git a/crypto/cipher/cipher.h b/crypto/cipher/cipher.h
new file mode 100644
index 0000000..2d105d5
--- /dev/null
+++ b/crypto/cipher/cipher.h
@@ -0,0 +1,442 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_CIPHER_H
+#define OPENSSL_HEADER_CIPHER_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* Ciphers. */
+
+
+/* Cipher primitives.
+ *
+ * The following functions return |EVP_CIPHER| objects that implement the named
+ * cipher algorithm. */
+
+const EVP_CIPHER *EVP_rc4(void);
+
+const EVP_CIPHER *EVP_des_cbc(void);
+const EVP_CIPHER *EVP_des_ede3_cbc(void);
+
+const EVP_CIPHER *EVP_aes_128_ecb(void);
+const EVP_CIPHER *EVP_aes_128_cbc(void);
+const EVP_CIPHER *EVP_aes_128_ctr(void);
+const EVP_CIPHER *EVP_aes_128_gcm(void);
+
+const EVP_CIPHER *EVP_aes_256_ecb(void);
+const EVP_CIPHER *EVP_aes_256_cbc(void);
+const EVP_CIPHER *EVP_aes_256_ctr(void);
+const EVP_CIPHER *EVP_aes_256_gcm(void);
+
+/* EVP_enc_null returns a 'cipher' that passes plaintext through as
+ * ciphertext. */
+const EVP_CIPHER *EVP_enc_null(void);
+
+/* EVP_get_cipherbynid returns the cipher corresponding to the given NID, or
+ * NULL if no such cipher is known. */
+const EVP_CIPHER *EVP_get_cipherbynid(int nid);
+
+
+/* Cipher context allocation.
+ *
+ * An |EVP_CIPHER_CTX| represents the state of an encryption or decryption in
+ * progress. */
+
+/* EVP_CIPHER_CTX_init initialises an, already allocated, |EVP_CIPHER_CTX|. */
+void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx);
+
+/* EVP_CIPHER_CTX_new allocates a fresh |EVP_CIPHER_CTX|, calls
+ * |EVP_CIPHER_CTX_init| and returns it, or NULL on allocation failure. */
+EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void);
+
+/* EVP_CIPHER_CTX_cleanup frees any memory referenced by |ctx|. It returns one
+ * on success and zero otherwise. */
+int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *ctx);
+
+/* EVP_CIPHER_CTX_free calls |EVP_CIPHER_CTX_cleanup| on |ctx| and then frees
+ * |ctx| itself. */
+void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx);
+
+/* EVP_CIPHER_CTX_copy sets |out| to be a duplicate of the current state of
+ * |in|. The |out| argument must have been previously initialised. */
+int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in);
+
+
+/* Cipher context configuration. */
+
+/* EVP_CipherInit_ex configures |ctx| for a fresh encryption (or decryption, if
+ * |enc| is zero) operation using |cipher|. If |ctx| has been previously
+ * configured with a cipher then |cipher|, |key| and |iv| may be |NULL| and
+ * |enc| may be -1 to reuse the previous values. The operation will use |key|
+ * as the key and |iv| as the IV (if any). These should have the correct
+ * lengths given by |EVP_CIPHER_key_length| and |EVP_CIPHER_iv_length|. It
+ * returns one on success and zero on error. */
+int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
+ ENGINE *engine, const uint8_t *key, const uint8_t *iv,
+ int enc);
+
+/* EVP_EncryptInit_ex calls |EVP_CipherInit_ex| with |enc| equal to one. */
+int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
+ ENGINE *impl, const uint8_t *key, const uint8_t *iv);
+
+/* EVP_DecryptInit_ex calls |EVP_CipherInit_ex| with |enc| equal to zero. */
+int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
+ ENGINE *impl, const uint8_t *key, const uint8_t *iv);
+
+
+/* Cipher operations. */
+
+/* EVP_EncryptUpdate encrypts |in_len| bytes from |in| to |out|. The number
+ * of output bytes may be up to |in_len| plus the block length minus one and
+ * |out| must have sufficient space. The number of bytes actually output is
+ * written to |*out_len|. It returns one on success and zero otherwise. */
+int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
+ const uint8_t *in, int in_len);
+
+/* EVP_EncryptFinal_ex writes at most a block of ciphertext to |out| and sets
+ * |*out_len| to the number of bytes written. If padding is enabled (the
+ * default) then standard padding is applied to create the final block. If
+ * padding is disabled (with |EVP_CIPHER_CTX_set_padding|) then any partial
+ * block remaining will cause an error. The function returns one on success and
+ * zero otherwise. */
+int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len);
+
+/* EVP_DecryptUpdate decrypts |in_len| bytes from |in| to |out|. The number of
+ * output bytes may be up to |in_len| plus the block length minus one and |out|
+ * must have sufficient space. The number of bytes actually output is written
+ * to |*out_len|. It returns one on success and zero otherwise. */
+int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
+ const uint8_t *in, int in_len);
+
+/* EVP_DecryptFinal_ex writes at most a block of ciphertext to |out| and sets
+ * |*out_len| to the number of bytes written. If padding is enabled (the
+ * default) then padding is removed from the final block.
+ *
+ * WARNING: it is unsafe to call this function with unauthenticted
+ * ciphertext if padding is enabled. */
+int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len);
+
+/* EVP_Cipher performs a one-shot encryption/decryption operation. No partial
+ * blocks etc are maintained between calls. It returns the number of bytes
+ * written or -1 on error.
+ *
+ * WARNING: this differs from the usual return value convention. */
+int EVP_Cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in,
+ size_t in_len);
+
+/* EVP_CipherUpdate calls either |EVP_EncryptUpdate| or |EVP_DecryptUpdate|
+ * depending on how |ctx| has been setup. */
+int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
+ const uint8_t *in, int in_len);
+
+/* EVP_CipherFinal_ex calls either |EVP_EncryptFinal_ex| or
+ * |EVP_DecryptFinal_ex| depending on how |ctx| has been setup. */
+int EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len);
+
+
+/* Cipher context accessors. */
+
+/* EVP_CIPHER_CTX_cipher returns the |EVP_CIPHER| underlying |ctx|, or NULL if
+ * none has been set. */
+const EVP_CIPHER *EVP_CIPHER_CTX_cipher(const EVP_CIPHER_CTX *ctx);
+
+/* EVP_CIPHER_CTX_nid returns a NID identifying the |EVP_CIPHER| underlying
+ * |ctx| (e.g. |NID_rc4|). It will crash if no cipher has been configured. */
+int EVP_CIPHER_CTX_nid(const EVP_CIPHER_CTX *ctx);
+
+/* EVP_CIPHER_CTX_block_size returns the block size, in bytes, of the cipher
+ * underlying |ctx|, or one if the cipher is a stream cipher. It will crash if
+ * no cipher has been configured. */
+unsigned EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *ctx);
+
+/* EVP_CIPHER_CTX_key_length returns the key size, in bytes, of the cipher
+ * underlying |ctx| or zero if no cipher has been configured. */
+unsigned EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx);
+
+/* EVP_CIPHER_CTX_iv_length returns the IV size, in bytes, of the cipher
+ * underlying |ctx|. It will crash if no cipher has been configured. */
+unsigned EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx);
+
+/* EVP_CIPHER_CTX_get_app_data returns the opaque, application data pointer for
+ * |ctx|, or NULL if none has been set. */
+void *EVP_CIPHER_CTX_get_app_data(const EVP_CIPHER_CTX *ctx);
+
+/* EVP_CIPHER_CTX_set_app_data sets the opaque, application data pointer for
+ * |ctx| to |data|. */
+void EVP_CIPHER_CTX_set_app_data(EVP_CIPHER_CTX *ctx, void *data);
+
+/* EVP_CIPHER_CTX_flags returns a value which is the OR of zero or more
+ * |EVP_CIPH_*| flags. It will crash if no cipher has been configured. */
+uint32_t EVP_CIPHER_CTX_flags(const EVP_CIPHER_CTX *ctx);
+
+/* EVP_CIPHER_CTX_mode returns one of the |EVP_CIPH_*| cipher mode values
+ * enumerated below. It will crash if no cipher has been configured. */
+uint32_t EVP_CIPHER_CTX_mode(const EVP_CIPHER_CTX *ctx);
+
+/* EVP_CIPHER_CTX_ctrl is an |ioctl| like function. The |command| argument
+ * should be one of the |EVP_CTRL_*| values. The |arg| and |ptr| arguments are
+ * specific to the command in question. */
+int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int command, int arg, void *ptr);
+
+/* EVP_CIPHER_CTX_set_padding sets whether padding is enabled for |ctx| and
+ * returns one. Pass a non-zero |pad| to enable padding (the default) or zero
+ * to disable. */
+int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int pad);
+
+
+/* Cipher accessors. */
+
+/* EVP_CIPHER_nid returns a NID identifing |cipher|. (For example,
+ * |NID_rc4|.) */
+int EVP_CIPHER_nid(const EVP_CIPHER *cipher);
+
+/* EVP_CIPHER_name returns the short name for |cipher| or NULL if no name is
+ * known. */
+const char *EVP_CIPHER_name(const EVP_CIPHER *cipher);
+
+/* EVP_CIPHER_block_size returns the block size, in bytes, for |cipher|, or one
+ * if |cipher| is a stream cipher. */
+unsigned EVP_CIPHER_block_size(const EVP_CIPHER *cipher);
+
+/* EVP_CIPHER_key_length returns the key size, in bytes, for |cipher|. If
+ * |cipher| can take a variable key length then this function returns the
+ * default key length and |EVP_CIPHER_flags| will return a value with
+ * |EVP_CIPH_VARIABLE_LENGTH| set. */
+unsigned EVP_CIPHER_key_length(const EVP_CIPHER *cipher);
+
+/* EVP_CIPHER_iv_length returns the IV size, in bytes, of |cipher|, or zero if
+ * |cipher| doesn't take an IV. */
+unsigned EVP_CIPHER_iv_length(const EVP_CIPHER *cipher);
+
+/* EVP_CIPHER_flags returns a value which is the OR of zero or more
+ * |EVP_CIPH_*| flags. */
+uint32_t EVP_CIPHER_flags(const EVP_CIPHER *cipher);
+
+/* EVP_CIPHER_mode returns one of the cipher mode values enumerated below. */
+uint32_t EVP_CIPHER_mode(const EVP_CIPHER *cipher);
+
+
+/* Key derivation. */
+
+/* EVP_BytesToKey generates a key and IV for the cipher |type| by iterating
+ * |md| |count| times using |data| and |salt|. On entry, the |key| and |iv|
+ * buffers must have enough space to hold a key and IV for |type|. It returns
+ * the length of the key on success or zero on error. */
+int EVP_BytesToKey(const EVP_CIPHER *type, const EVP_MD *md,
+ const uint8_t *salt, const uint8_t *data, size_t data_len,
+ unsigned count, uint8_t *key, uint8_t *iv);
+
+
+/* Cipher modes (for |EVP_CIPHER_mode|). */
+
+#define EVP_CIPH_STREAM_CIPHER 0x0
+#define EVP_CIPH_ECB_MODE 0x1
+#define EVP_CIPH_CBC_MODE 0x2
+#define EVP_CIPH_CFB_MODE 0x3
+#define EVP_CIPH_OFB_MODE 0x4
+#define EVP_CIPH_CTR_MODE 0x5
+#define EVP_CIPH_GCM_MODE 0x6
+
+
+/* Cipher flags (for |EVP_CIPHER_flags|). */
+
+/* EVP_CIPH_VARIABLE_LENGTH indicates that the cipher takes a variable length
+ * key. */
+#define EVP_CIPH_VARIABLE_LENGTH 0x40
+
+/* EVP_CIPH_ALWAYS_CALL_INIT indicates that the |init| function for the cipher
+ * should always be called when initialising a new operation, even if the key
+ * is NULL to indicate that the same key is being used. */
+#define EVP_CIPH_ALWAYS_CALL_INIT 0x80
+
+/* EVP_CIPH_CUSTOM_IV indicates that the cipher manages the IV itself rather
+ * than keeping it in the |iv| member of |EVP_CIPHER_CTX|. */
+#define EVP_CIPH_CUSTOM_IV 0x100
+
+/* EVP_CIPH_CTRL_INIT indicates that EVP_CTRL_INIT should be used when
+ * initialising an |EVP_CIPHER_CTX|. */
+#define EVP_CIPH_CTRL_INIT 0x200
+
+/* EVP_CIPH_FLAG_CUSTOM_CIPHER indicates that the cipher manages blocking
+ * itself. This causes EVP_(En|De)crypt_ex to be simple wrapper functions. */
+#define EVP_CIPH_FLAG_CUSTOM_CIPHER 0x400
+
+/* EVP_CIPH_FLAG_AEAD_CIPHER specifies that the cipher is an AEAD. This is an
+ * older version of the proper AEAD interface. See aead.h for the current
+ * one. */
+#define EVP_CIPH_FLAG_AEAD_CIPHER 0x800
+
+
+/* Private functions. */
+
+/* EVP_CIPH_NO_PADDING disables padding in block ciphers. */
+#define EVP_CIPH_NO_PADDING 0x800
+
+/* EVP_CIPHER_CTX_ctrl commands. */
+#define EVP_CTRL_INIT 0x0
+#define EVP_CTRL_SET_KEY_LENGTH 0x1
+#define EVP_CTRL_GET_RC2_KEY_BITS 0x2
+#define EVP_CTRL_SET_RC2_KEY_BITS 0x3
+#define EVP_CTRL_GET_RC5_ROUNDS 0x4
+#define EVP_CTRL_SET_RC5_ROUNDS 0x5
+#define EVP_CTRL_RAND_KEY 0x6
+#define EVP_CTRL_PBE_PRF_NID 0x7
+#define EVP_CTRL_COPY 0x8
+#define EVP_CTRL_GCM_SET_IVLEN 0x9
+#define EVP_CTRL_GCM_GET_TAG 0x10
+#define EVP_CTRL_GCM_SET_TAG 0x11
+#define EVP_CTRL_GCM_SET_IV_FIXED 0x12
+#define EVP_CTRL_GCM_IV_GEN 0x13
+#define EVP_CTRL_AEAD_TLS1_AAD 0x16
+#define EVP_CTRL_AEAD_SET_MAC_KEY 0x17
+/* Set the GCM invocation field, decrypt only */
+#define EVP_CTRL_GCM_SET_IV_INV 0x18
+
+/* GCM TLS constants */
+/* Length of fixed part of IV derived from PRF */
+#define EVP_GCM_TLS_FIXED_IV_LEN 4
+/* Length of explicit part of IV part of TLS records */
+#define EVP_GCM_TLS_EXPLICIT_IV_LEN 8
+/* Length of tag for TLS */
+#define EVP_GCM_TLS_TAG_LEN 16
+
+#define EVP_MAX_KEY_LENGTH 64
+#define EVP_MAX_IV_LENGTH 16
+#define EVP_MAX_BLOCK_LENGTH 32
+
+struct evp_cipher_ctx_st {
+ /* cipher contains the underlying cipher for this context. */
+ const EVP_CIPHER *cipher;
+
+ /* app_data is a pointer to opaque, user data. */
+ void *app_data; /* application stuff */
+
+ /* cipher_data points to the |cipher| specific state. */
+ void *cipher_data;
+
+ /* key_len contains the length of the key, which may differ from
+ * |cipher->key_len| if the cipher can take a variable key length. */
+ unsigned key_len;
+
+ /* encrypt is one if encrypting and zero if decrypting. */
+ int encrypt;
+
+ /* flags contains the OR of zero or more |EVP_CIPH_*| flags, above. */
+ uint32_t flags;
+
+ /* oiv contains the original IV value. */
+ uint8_t oiv[EVP_MAX_IV_LENGTH];
+
+ /* iv contains the current IV value, which may have been updated. */
+ uint8_t iv[EVP_MAX_IV_LENGTH];
+
+ /* buf contains a partial block which is used by, for example, CTR mode to
+ * store unused keystream bytes. */
+ uint8_t buf[EVP_MAX_BLOCK_LENGTH];
+
+ /* buf_len contains the number of bytes of a partial block contained in
+ * |buf|. */
+ int buf_len;
+
+ /* num contains the number of bytes of |iv| which are valid for modes that
+ * manage partial blocks themselves. */
+ int num;
+
+ /* final_used is non-zero if the |final| buffer contains plaintext. */
+ int final_used;
+
+ /* block_mask contains |cipher->block_size| minus one. (The block size
+ * assumed to be a power of two.) */
+ int block_mask;
+
+ uint8_t final[EVP_MAX_BLOCK_LENGTH]; /* possible final block */
+} /* EVP_CIPHER_CTX */;
+
+typedef struct evp_cipher_info_st {
+ const EVP_CIPHER *cipher;
+ unsigned char iv[EVP_MAX_IV_LENGTH];
+} EVP_CIPHER_INFO;
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#define CIPHER_F_EVP_CipherInit_ex 100
+#define CIPHER_F_EVP_EncryptFinal_ex 101
+#define CIPHER_F_EVP_DecryptFinal_ex 102
+#define CIPHER_F_EVP_CIPHER_CTX_ctrl 103
+#define CIPHER_F_aes_init_key 104
+#define CIPHER_F_aesni_init_key 105
+#define CIPHER_F_EVP_CIPHER_CTX_copy 106
+#define CIPHER_R_WRAP_MODE_NOT_ALLOWED 100
+#define CIPHER_R_AES_KEY_SETUP_FAILED 101
+#define CIPHER_R_INPUT_NOT_INITIALIZED 102
+#define CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH 103
+#define CIPHER_R_INITIALIZATION_ERROR 104
+#define CIPHER_R_CTRL_NOT_IMPLEMENTED 105
+#define CIPHER_R_NO_CIPHER_SET 106
+#define CIPHER_R_BAD_DECRYPT 107
+#define CIPHER_R_WRONG_FINAL_BLOCK_LENGTH 108
+#define CIPHER_R_CTRL_OPERATION_NOT_IMPLEMENTED 109
+
+#endif /* OPENSSL_HEADER_CIPHER_H */
diff --git a/crypto/cipher/cipher_error.c b/crypto/cipher/cipher_error.c
new file mode 100644
index 0000000..bddecdd
--- /dev/null
+++ b/crypto/cipher/cipher_error.c
@@ -0,0 +1,38 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/err.h>
+
+#include "cipher.h"
+
+const ERR_STRING_DATA CIPHER_error_string_data[] = {
+ {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_EVP_CIPHER_CTX_copy, 0), "EVP_CIPHER_CTX_copy"},
+ {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_EVP_CIPHER_CTX_ctrl, 0), "EVP_CIPHER_CTX_ctrl"},
+ {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_EVP_CipherInit_ex, 0), "EVP_CipherInit_ex"},
+ {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_EVP_DecryptFinal_ex, 0), "EVP_DecryptFinal_ex"},
+ {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_EVP_EncryptFinal_ex, 0), "EVP_EncryptFinal_ex"},
+ {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_aes_init_key, 0), "aes_init_key"},
+ {ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_aesni_init_key, 0), "aesni_init_key"},
+ {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_AES_KEY_SETUP_FAILED), "AES_KEY_SETUP_FAILED"},
+ {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_BAD_DECRYPT), "BAD_DECRYPT"},
+ {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_CTRL_NOT_IMPLEMENTED), "CTRL_NOT_IMPLEMENTED"},
+ {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_CTRL_OPERATION_NOT_IMPLEMENTED), "CTRL_OPERATION_NOT_IMPLEMENTED"},
+ {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH), "DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH"},
+ {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_INITIALIZATION_ERROR), "INITIALIZATION_ERROR"},
+ {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_INPUT_NOT_INITIALIZED), "INPUT_NOT_INITIALIZED"},
+ {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_NO_CIPHER_SET), "NO_CIPHER_SET"},
+ {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_WRAP_MODE_NOT_ALLOWED), "WRAP_MODE_NOT_ALLOWED"},
+ {ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_WRONG_FINAL_BLOCK_LENGTH), "WRONG_FINAL_BLOCK_LENGTH"},
+ {0, NULL},
+};
diff --git a/crypto/cipher/cipher_test.c b/crypto/cipher/cipher_test.c
new file mode 100644
index 0000000..3dadb8a
--- /dev/null
+++ b/crypto/cipher/cipher_test.c
@@ -0,0 +1,409 @@
+/* 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/cipher.h>
+#include <openssl/err.h>
+#include <openssl/bio.h>
+
+
+static void hexdump(FILE *f, const char *title, const uint8_t *s, int l) {
+ int n = 0;
+
+ fprintf(f, "%s", title);
+ for (; n < l; ++n) {
+ if ((n % 16) == 0)
+ fprintf(f, "\n%04x", n);
+ fprintf(f, " %02x", s[n]);
+ }
+ fprintf(f, "\n");
+}
+
+static int convert(uint8_t *s) {
+ uint8_t *d;
+
+ for (d = s; *s; s += 2, ++d) {
+ unsigned int n;
+
+ if (!s[1]) {
+ fprintf(stderr, "Odd number of hex digits!");
+ exit(4);
+ }
+ sscanf((char *)s, "%2x", &n);
+ *d = (uint8_t)n;
+ }
+ return s - d;
+}
+
+static char *sstrsep(char **string, const char *delim) {
+ char isdelim[256];
+ char *token = *string;
+
+ if (**string == 0) {
+ return NULL;
+ }
+
+ memset(isdelim, 0, 256);
+ isdelim[0] = 1;
+
+ while (*delim) {
+ isdelim[(uint8_t)(*delim)] = 1;
+ delim++;
+ }
+
+ while (!isdelim[(uint8_t)(**string)]) {
+ (*string)++;
+ }
+
+ if (**string) {
+ **string = 0;
+ (*string)++;
+ }
+
+ return token;
+}
+
+static uint8_t *ustrsep(char **p, const char *sep) {
+ return (uint8_t *)sstrsep(p, sep);
+}
+
+static void test1(const EVP_CIPHER *c, const uint8_t *key, int kn,
+ const uint8_t *iv, int in, const uint8_t *plaintext, int pn,
+ const uint8_t *ciphertext, int cn, const uint8_t *aad, int an,
+ const uint8_t *tag, int tn, int encdec) {
+ EVP_CIPHER_CTX ctx;
+ uint8_t out[4096];
+ int outl, outl2, mode;
+
+ printf("Testing cipher %s%s\n", EVP_CIPHER_name(c),
+ (encdec == 1 ? "(encrypt)"
+ : (encdec == 0 ? "(decrypt)" : "(encrypt/decrypt)")));
+ hexdump(stdout, "Key", key, kn);
+ if (in) {
+ hexdump(stdout, "IV", iv, in);
+ }
+ hexdump(stdout, "Plaintext", plaintext, pn);
+ hexdump(stdout, "Ciphertext", ciphertext, cn);
+ if (an) {
+ hexdump(stdout, "AAD", aad, an);
+ }
+ if (tn) {
+ hexdump(stdout, "Tag", tag, tn);
+ }
+ mode = EVP_CIPHER_mode(c);
+ if (kn != EVP_CIPHER_key_length(c)) {
+ fprintf(stderr, "Key length doesn't match, got %d expected %lu\n", kn,
+ (unsigned long)EVP_CIPHER_key_length(c));
+ exit(5);
+ }
+ EVP_CIPHER_CTX_init(&ctx);
+ if (encdec != 0) {
+ if (mode == EVP_CIPH_GCM_MODE) {
+ if (!EVP_EncryptInit_ex(&ctx, c, NULL, NULL, NULL)) {
+ fprintf(stderr, "EncryptInit failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(10);
+ }
+ if (!EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_IVLEN, in, NULL)) {
+ fprintf(stderr, "IV length set failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(11);
+ }
+ if (!EVP_EncryptInit_ex(&ctx, NULL, NULL, key, iv)) {
+ fprintf(stderr, "Key/IV set failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(12);
+ }
+ if (an && !EVP_EncryptUpdate(&ctx, NULL, &outl, aad, an)) {
+ fprintf(stderr, "AAD set failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(13);
+ }
+ } else if (!EVP_EncryptInit_ex(&ctx, c, NULL, key, iv)) {
+ fprintf(stderr, "EncryptInit failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(10);
+ }
+ EVP_CIPHER_CTX_set_padding(&ctx, 0);
+
+ if (!EVP_EncryptUpdate(&ctx, out, &outl, plaintext, pn)) {
+ fprintf(stderr, "Encrypt failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(6);
+ }
+ if (!EVP_EncryptFinal_ex(&ctx, out + outl, &outl2)) {
+ fprintf(stderr, "EncryptFinal failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(7);
+ }
+
+ if (outl + outl2 != cn) {
+ fprintf(stderr, "Ciphertext length mismatch got %d expected %d\n",
+ outl + outl2, cn);
+ exit(8);
+ }
+
+ if (memcmp(out, ciphertext, cn)) {
+ fprintf(stderr, "Ciphertext mismatch\n");
+ hexdump(stderr, "Got", out, cn);
+ hexdump(stderr, "Expected", ciphertext, cn);
+ exit(9);
+ }
+ if (mode == EVP_CIPH_GCM_MODE) {
+ uint8_t rtag[16];
+ /* Note: EVP_CTRL_CCM_GET_TAG has same value as
+ * EVP_CTRL_GCM_GET_TAG
+ */
+ if (!EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_GET_TAG, tn, rtag)) {
+ fprintf(stderr, "Get tag failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(14);
+ }
+ if (memcmp(rtag, tag, tn)) {
+ fprintf(stderr, "Tag mismatch\n");
+ hexdump(stderr, "Got", rtag, tn);
+ hexdump(stderr, "Expected", tag, tn);
+ exit(9);
+ }
+ }
+ }
+
+ if (encdec <= 0) {
+ if (mode == EVP_CIPH_GCM_MODE) {
+ if (!EVP_DecryptInit_ex(&ctx, c, NULL, NULL, NULL)) {
+ fprintf(stderr, "EncryptInit failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(10);
+ }
+ if (!EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_IVLEN, in, NULL)) {
+ fprintf(stderr, "IV length set failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(11);
+ }
+ if (!EVP_DecryptInit_ex(&ctx, NULL, NULL, key, iv)) {
+ fprintf(stderr, "Key/IV set failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(12);
+ }
+ if (!EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_TAG, tn, (void *)tag)) {
+ fprintf(stderr, "Set tag failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(14);
+ }
+ if (an && !EVP_DecryptUpdate(&ctx, NULL, &outl, aad, an)) {
+ fprintf(stderr, "AAD set failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(13);
+ }
+ } else if (!EVP_DecryptInit_ex(&ctx, c, NULL, key, iv)) {
+ fprintf(stderr, "DecryptInit failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(11);
+ }
+ EVP_CIPHER_CTX_set_padding(&ctx, 0);
+
+ if (!EVP_DecryptUpdate(&ctx, out, &outl, ciphertext, cn)) {
+ fprintf(stderr, "Decrypt failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(6);
+ }
+ outl2 = 0;
+ if (!EVP_DecryptFinal_ex(&ctx, out + outl, &outl2)) {
+ fprintf(stderr, "DecryptFinal failed\n");
+ BIO_print_errors_fp(stderr);
+ exit(7);
+ }
+
+ if (outl + outl2 != pn) {
+ fprintf(stderr, "Plaintext length mismatch got %d expected %d\n",
+ outl + outl2, pn);
+ exit(8);
+ }
+
+ if (memcmp(out, plaintext, pn)) {
+ fprintf(stderr, "Plaintext mismatch\n");
+ hexdump(stderr, "Got", out, pn);
+ hexdump(stderr, "Expected", plaintext, pn);
+ exit(9);
+ }
+ }
+
+ EVP_CIPHER_CTX_cleanup(&ctx);
+
+ printf("\n");
+}
+
+static int test_cipher(const char *cipher, const uint8_t *key, int kn,
+ const uint8_t *iv, int in, const uint8_t *plaintext,
+ int pn, const uint8_t *ciphertext, int cn,
+ const uint8_t *aad, int an, const uint8_t *tag, int tn,
+ int encdec) {
+ const EVP_CIPHER *c;
+
+ if (strcmp(cipher, "DES-CBC") == 0) {
+ c = EVP_des_cbc();
+ } else if (strcmp(cipher, "DES-EDE3-CBC") == 0) {
+ c = EVP_des_ede3_cbc();
+ } else if (strcmp(cipher, "RC4") == 0) {
+ c = EVP_rc4();
+ } else if (strcmp(cipher, "AES-128-ECB") == 0) {
+ c = EVP_aes_128_ecb();
+ } else if (strcmp(cipher, "AES-256-ECB") == 0) {
+ c = EVP_aes_256_ecb();
+ } else if (strcmp(cipher, "AES-128-CBC") == 0) {
+ c = EVP_aes_128_cbc();
+ } else if (strcmp(cipher, "AES-128-GCM") == 0) {
+ c = EVP_aes_128_gcm();
+ } else if (strcmp(cipher, "AES-256-CBC") == 0) {
+ c = EVP_aes_256_cbc();
+ } else if (strcmp(cipher, "AES-128-CTR") == 0) {
+ c = EVP_aes_128_ctr();
+ } else if (strcmp(cipher, "AES-256-CTR") == 0) {
+ c = EVP_aes_256_ctr();
+ } else if (strcmp(cipher, "AES-256-GCM") == 0) {
+ c = EVP_aes_256_gcm();
+ } else {
+ fprintf(stderr, "Unknown cipher type %s\n", cipher);
+ return 0;
+ }
+
+ test1(c, key, kn, iv, in, plaintext, pn, ciphertext, cn, aad, an, tag, tn,
+ encdec);
+
+ return 1;
+}
+
+int main(int argc, char **argv) {
+ const char *input_file;
+ FILE *f;
+
+ if (argc != 2) {
+ fprintf(stderr, "%s <test file>\n", argv[0]);
+ return 1;
+ }
+
+ input_file = argv[1];
+
+ f = fopen(input_file, "r");
+ if (!f) {
+ perror(input_file);
+ return 2;
+ }
+
+ ERR_load_crypto_strings();
+
+ for (;;) {
+ char line[4096];
+ char *p;
+ char *cipher;
+ uint8_t *iv, *key, *plaintext, *ciphertext, *aad, *tag;
+ int encdec;
+ int kn, in, pn, cn;
+ int an = 0;
+ int tn = 0;
+
+ if (!fgets((char *)line, sizeof line, f)) {
+ break;
+ }
+ if (line[0] == '#' || line[0] == '\n') {
+ continue;
+ }
+ p = line;
+ cipher = sstrsep(&p, ":");
+ key = ustrsep(&p, ":");
+ iv = ustrsep(&p, ":");
+ plaintext = ustrsep(&p, ":");
+ ciphertext = ustrsep(&p, ":");
+ if (p[-1] == '\n') {
+ encdec = -1;
+ p[-1] = '\0';
+ tag = aad = NULL;
+ an = tn = 0;
+ } else {
+ aad = ustrsep(&p, ":");
+ tag = ustrsep(&p, ":");
+ if (tag == NULL) {
+ p = (char *)aad;
+ tag = aad = NULL;
+ an = tn = 0;
+ }
+ if (p[-1] == '\n') {
+ encdec = -1;
+ p[-1] = '\0';
+ } else
+ encdec = atoi(sstrsep(&p, "\n"));
+ }
+
+ kn = convert(key);
+ in = convert(iv);
+ pn = convert(plaintext);
+ cn = convert(ciphertext);
+ if (aad) {
+ an = convert(aad);
+ tn = convert(tag);
+ }
+
+ if (!test_cipher(cipher, key, kn, iv, in, plaintext, pn, ciphertext, cn,
+ aad, an, tag, tn, encdec)) {
+ return 3;
+ }
+ }
+ fclose(f);
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/crypto/cipher/cipher_test.txt b/crypto/cipher/cipher_test.txt
new file mode 100644
index 0000000..b250df3
--- /dev/null
+++ b/crypto/cipher/cipher_test.txt
@@ -0,0 +1,81 @@
+# RC4 tests (from rc4test)
+RC4:0123456789abcdef0123456789abcdef::0123456789abcdef:75b7878099e0c596
+RC4:0123456789abcdef0123456789abcdef::0000000000000000:7494c2e7104b0879
+RC4:00000000000000000000000000000000::0000000000000000:de188941a3375d3a
+RC4:ef012345ef012345ef012345ef012345::0000000000000000000000000000000000000000:d6a141a7ec3c38dfbd615a1162e1c7ba36b67858
+RC4:0123456789abcdef0123456789abcdef::123456789ABCDEF0123456789ABCDEF0123456789ABCDEF012345678:66a0949f8af7d6891f7f832ba833c00c892ebe30143ce28740011ecf
+RC4:ef012345ef012345ef012345ef012345::00000000000000000000:d6a141a7ec3c38dfbd61
+
+# DES EDE3 CBC tests (from destest)
+DES-EDE3-CBC:0123456789abcdeff1e0d3c2b5a49786fedcba9876543210:fedcba9876543210:37363534333231204E6F77206973207468652074696D6520666F722000000000:3FE301C962AC01D02213763C1CBD4CDC799657C064ECF5D41C673812CFDE9675
+
+# AES 128 ECB tests (from FIPS-197 test vectors, encrypt)
+AES-128-ECB:000102030405060708090A0B0C0D0E0F::00112233445566778899AABBCCDDEEFF:69C4E0D86A7B0430D8CDB78070B4C55A:1
+
+# AES 256 ECB tests (from FIPS-197 test vectors, encrypt)
+AES-256-ECB:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F::00112233445566778899AABBCCDDEEFF:8EA2B7CA516745BFEAFC49904B496089:1
+
+# AES 128 CBC tests (from NIST test vectors, decrypt)
+
+# AES tests from NIST document SP800-38A
+# For all ECB encrypts and decrypts, the transformed sequence is
+# AES-bits-ECB:key::plaintext:ciphertext:encdec
+# ECB-AES128.Encrypt and ECB-AES128.Decrypt
+AES-128-ECB:2B7E151628AED2A6ABF7158809CF4F3C::6BC1BEE22E409F96E93D7E117393172A:3AD77BB40D7A3660A89ECAF32466EF97
+AES-128-ECB:2B7E151628AED2A6ABF7158809CF4F3C::AE2D8A571E03AC9C9EB76FAC45AF8E51:F5D3D58503B9699DE785895A96FDBAAF
+AES-128-ECB:2B7E151628AED2A6ABF7158809CF4F3C::30C81C46A35CE411E5FBC1191A0A52EF:43B1CD7F598ECE23881B00E3ED030688
+AES-128-ECB:2B7E151628AED2A6ABF7158809CF4F3C::F69F2445DF4F9B17AD2B417BE66C3710:7B0C785E27E8AD3F8223207104725DD4
+# ECB-AES256.Encrypt and ECB-AES256.Decrypt
+AES-256-ECB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4::6BC1BEE22E409F96E93D7E117393172A:F3EED1BDB5D2A03C064B5A7E3DB181F8
+AES-256-ECB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4::AE2D8A571E03AC9C9EB76FAC45AF8E51:591CCB10D410ED26DC5BA74A31362870
+AES-256-ECB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4::30C81C46A35CE411E5FBC1191A0A52EF:B6ED21B99CA6F4F9F153E7B1BEAFED1D
+AES-256-ECB:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4::F69F2445DF4F9B17AD2B417BE66C3710:23304B7A39F9F3FF067D8D8F9E24ECC7
+# For all CBC encrypts and decrypts, the transformed sequence is
+# AES-bits-CBC:key:IV/ciphertext':plaintext:ciphertext:encdec
+# CBC-AES128.Encrypt and CBC-AES128.Decrypt
+AES-128-CBC:2B7E151628AED2A6ABF7158809CF4F3C:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:7649ABAC8119B246CEE98E9B12E9197D
+AES-128-CBC:2B7E151628AED2A6ABF7158809CF4F3C:7649ABAC8119B246CEE98E9B12E9197D:AE2D8A571E03AC9C9EB76FAC45AF8E51:5086CB9B507219EE95DB113A917678B2
+AES-128-CBC:2B7E151628AED2A6ABF7158809CF4F3C:5086CB9B507219EE95DB113A917678B2:30C81C46A35CE411E5FBC1191A0A52EF:73BED6B8E3C1743B7116E69E22229516
+AES-128-CBC:2B7E151628AED2A6ABF7158809CF4F3C:73BED6B8E3C1743B7116E69E22229516:F69F2445DF4F9B17AD2B417BE66C3710:3FF1CAA1681FAC09120ECA307586E1A7
+# CBC-AES256.Encrypt and CBC-AES256.Decrypt
+AES-256-CBC:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:000102030405060708090A0B0C0D0E0F:6BC1BEE22E409F96E93D7E117393172A:F58C4C04D6E5F1BA779EABFB5F7BFBD6
+AES-256-CBC:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:F58C4C04D6E5F1BA779EABFB5F7BFBD6:AE2D8A571E03AC9C9EB76FAC45AF8E51:9CFC4E967EDB808D679F777BC6702C7D
+AES-256-CBC:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:9CFC4E967EDB808D679F777BC6702C7D:30C81C46A35CE411E5FBC1191A0A52EF:39F23369A9D9BACFA530E26304231461
+AES-256-CBC:603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4:39F23369A9D9BACFA530E26304231461:F69F2445DF4F9B17AD2B417BE66C3710:B2EB05E2C39BE9FCDA6C19078C6A9D1B
+
+# AES Counter test vectors from RFC3686
+AES-128-CTR:AE6852F8121067CC4BF7A5765577F39E:00000030000000000000000000000001:53696E676C6520626C6F636B206D7367:E4095D4FB7A7B3792D6175A3261311B8:1
+AES-128-CTR:7E24067817FAE0D743D6CE1F32539163:006CB6DBC0543B59DA48D90B00000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F:5104A106168A72D9790D41EE8EDAD388EB2E1EFC46DA57C8FCE630DF9141BE28:1
+AES-128-CTR:7691BE035E5020A8AC6E618529F9A0DC:00E0017B27777F3F4A1786F000000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212223:C1CF48A89F2FFDD9CF4652E9EFDB72D74540A42BDE6D7836D59A5CEAAEF3105325B2072F:1
+
+AES-256-CTR:776BEFF2851DB06F4C8A0542C8696F6C6A81AF1EEC96B4D37FC1D689E6C1C104:00000060DB5672C97AA8F0B200000001:53696E676C6520626C6F636B206D7367:145AD01DBF824EC7560863DC71E3E0C0:1
+AES-256-CTR:F6D66D6BD52D59BB0796365879EFF886C66DD51A5B6A99744B50590C87A23884:00FAAC24C1585EF15A43D87500000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F:F05E231B3894612C49EE000B804EB2A9B8306B508F839D6A5530831D9344AF1C:1
+AES-256-CTR:FF7A617CE69148E4F1726E2F43581DE2AA62D9F805532EDFF1EED687FB54153D:001CC5B751A51D70A1C1114800000001:000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212223:EB6C52821D0BBBF7CE7594462ACA4FAAB407DF866569FD07F48CC0B583D6071F1EC0E6B8:1
+
+# AES GCM test vectors from http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf
+AES-128-GCM:00000000000000000000000000000000:000000000000000000000000::::58e2fccefa7e3061367f1d57a4e7455a
+AES-128-GCM:00000000000000000000000000000000:000000000000000000000000:00000000000000000000000000000000:0388dace60b6a392f328c2b971b2fe78::ab6e47d42cec13bdf53a67b21257bddf
+AES-128-GCM:feffe9928665731c6d6a8f9467308308:cafebabefacedbaddecaf888:d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255:42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985::4d5c2af327cd64a62cf35abd2ba6fab4
+AES-128-GCM:feffe9928665731c6d6a8f9467308308:cafebabefacedbaddecaf888:d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39:42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091:feedfacedeadbeeffeedfacedeadbeefabaddad2:5bc94fbc3221a5db94fae95ae7121a47
+AES-128-GCM:feffe9928665731c6d6a8f9467308308:cafebabefacedbad:d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39:61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c742373806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598:feedfacedeadbeeffeedfacedeadbeefabaddad2:3612d2e79e3b0785561be14aaca2fccb
+AES-128-GCM:feffe9928665731c6d6a8f9467308308:9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b:d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39:8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca701e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5:feedfacedeadbeeffeedfacedeadbeefabaddad2:619cc5aefffe0bfa462af43c1699d050
+AES-256-GCM:0000000000000000000000000000000000000000000000000000000000000000:000000000000000000000000::::530f8afbc74536b9a963b4f1c4cb738b
+AES-256-GCM:0000000000000000000000000000000000000000000000000000000000000000:000000000000000000000000:00000000000000000000000000000000:cea7403d4d606b6e074ec5d3baf39d18::d0d1c8a799996bf0265b98b5d48ab919
+AES-256-GCM:feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308:cafebabefacedbaddecaf888:d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255:522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad::b094dac5d93471bdec1a502270e3cc6c
+AES-256-GCM:feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308:cafebabefacedbaddecaf888:d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39:522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662:feedfacedeadbeeffeedfacedeadbeefabaddad2:76fc6ece0f4e1768cddf8853bb2d551b
+AES-256-GCM:feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308:cafebabefacedbad:d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39:c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0feb582d33934a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f:feedfacedeadbeeffeedfacedeadbeefabaddad2:3a337dbf46a792c45e454913fe2ea8f2
+AES-256-GCM:feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308:9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b:d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39:5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf40fc0c3b780f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3f:feedfacedeadbeeffeedfacedeadbeefabaddad2:a44a8266ee1c8eb0c8b5d4cf5ae9f19a
+# local add-ons, primarily streaming ghash tests
+# 128 bytes aad
+AES-128-GCM:00000000000000000000000000000000:000000000000000000000000:::d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad:5fea793a2d6f974d37e68e0cb8ff9492
+# 48 bytes plaintext
+AES-128-GCM:00000000000000000000000000000000:000000000000000000000000:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000:0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0::9dd0a376b08e40eb00c35f29f9ea61a4
+# 80 bytes plaintext
+AES-128-GCM:00000000000000000000000000000000:000000000000000000000000:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000:0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d5270291::98885a3a22bd4742fe7b72172193b163
+# 128 bytes plaintext
+AES-128-GCM:00000000000000000000000000000000:000000000000000000000000:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000:0388dace60b6a392f328c2b971b2fe78f795aaab494b5923f7fd89ff948bc1e0200211214e7394da2089b6acd093abe0c94da219118e297d7b7ebcbcc9c388f28ade7d85a8ee35616f7124a9d527029195b84d1b96c690ff2f2de30bf2ec89e00253786e126504f0dab90c48a30321de3345e6b0461e7c9e6c6b7afedde83f40::cac45f60e31efd3b5a43b98a22ce1aa1
+# 192 bytes plaintext, iv is chosen so that initial counter LSB is 0xFF
+AES-128-GCM:00000000000000000000000000000000:ffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000:56b3373ca9ef6e4a2b64fe1e9a17b61425f10d47a75a5fce13efc6bc784af24f4141bdd48cf7c770887afd573cca5418a9aeffcd7c5ceddfc6a78397b9a85b499da558257267caab2ad0b23ca476a53cb17fb41c4b8b475cb4f3f7165094c229c9e8c4dc0a2a5ff1903e501511221376a1cdb8364c5061a20cae74bc4acd76ceb0abc9fd3217ef9f8c90be402ddf6d8697f4f880dff15bfb7a6b28241ec8fe183c2d59e3f9dfff653c7126f0acb9e64211f42bae12af462b1070bef1ab5e3606::566f8ef683078bfdeeffa869d751a017
+# 80 bytes plaintext, submitted by Intel
+AES-128-GCM:843ffcf5d2b72694d19ed01d01249412:dbcca32ebf9b804617c3aa9e:000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f:6268c6fa2a80b2d137467f092f657ac04d89be2beaa623d61b5a868c8f03ff95d3dcee23ad2f1ab3a6c80eaf4b140eb05de3457f0fbc111a6b43d0763aa422a3013cf1dc37fe417d1fbfc449b75d4cc5:00000000000000000000000000000000101112131415161718191a1b1c1d1e1f:3b629ccfbc1119b7319e1dce2cd6fd6d
+
diff --git a/crypto/cipher/derive_key.c b/crypto/cipher/derive_key.c
new file mode 100644
index 0000000..9e1634a
--- /dev/null
+++ b/crypto/cipher/derive_key.c
@@ -0,0 +1,154 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/cipher.h>
+
+#include <assert.h>
+
+#include <openssl/digest.h>
+#include <openssl/mem.h>
+
+#include "internal.h"
+
+
+#define PKCS5_SALT_LEN 8
+
+int EVP_BytesToKey(const EVP_CIPHER *type, const EVP_MD *md,
+ const uint8_t *salt, const uint8_t *data, size_t data_len,
+ unsigned count, uint8_t *key, uint8_t *iv) {
+ EVP_MD_CTX c;
+ uint8_t md_buf[EVP_MAX_MD_SIZE];
+ unsigned niv, nkey, addmd = 0;
+ unsigned mds = 0, i;
+ int rv = 0;
+
+ nkey = type->key_len;
+ niv = type->iv_len;
+
+ assert(nkey <= EVP_MAX_KEY_LENGTH);
+ assert(niv <= EVP_MAX_IV_LENGTH);
+
+ if (data == NULL) {
+ return nkey;
+ }
+
+ EVP_MD_CTX_init(&c);
+ for (;;) {
+ if (!EVP_DigestInit_ex(&c, md, NULL)) {
+ return 0;
+ }
+ if (addmd++) {
+ if (!EVP_DigestUpdate(&c, md_buf, mds)) {
+ goto err;
+ }
+ }
+ if (!EVP_DigestUpdate(&c, data, data_len)) {
+ goto err;
+ }
+ if (salt != NULL) {
+ if (!EVP_DigestUpdate(&c, salt, PKCS5_SALT_LEN)) {
+ goto err;
+ }
+ }
+ if (!EVP_DigestFinal_ex(&c, md_buf, &mds)) {
+ goto err;
+ }
+
+ for (i = 1; i < count; i++) {
+ if (!EVP_DigestInit_ex(&c, md, NULL) ||
+ !EVP_DigestUpdate(&c, md_buf, mds) ||
+ !EVP_DigestFinal_ex(&c, md_buf, &mds)) {
+ goto err;
+ }
+ }
+
+ i = 0;
+ if (nkey) {
+ for (;;) {
+ if (nkey == 0 || i == mds) {
+ break;
+ }
+ if (key != NULL) {
+ *(key++) = md_buf[i];
+ }
+ nkey--;
+ i++;
+ }
+ }
+
+ if (niv && i != mds) {
+ for (;;) {
+ if (niv == 0 || i == mds) {
+ break;
+ }
+ if (iv != NULL) {
+ *(iv++) = md_buf[i];
+ }
+ niv--;
+ i++;
+ }
+ }
+ if (nkey == 0 && niv == 0) {
+ break;
+ }
+ }
+ rv = type->key_len;
+
+err:
+ EVP_MD_CTX_cleanup(&c);
+ OPENSSL_cleanse(md_buf, EVP_MAX_MD_SIZE);
+ return rv;
+}
diff --git a/crypto/cipher/e_aes.c b/crypto/cipher/e_aes.c
new file mode 100644
index 0000000..c22e306
--- /dev/null
+++ b/crypto/cipher/e_aes.c
@@ -0,0 +1,915 @@
+/* ====================================================================
+ * Copyright (c) 2001-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.
+ * ==================================================================== */
+
+#include <openssl/aes.h>
+#include <openssl/cipher.h>
+#include <openssl/cpu.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/modes.h>
+#include <openssl/rand.h>
+#include <openssl/obj.h>
+
+#include "internal.h"
+#include "../modes/internal.h"
+
+
+typedef struct {
+ union {
+ double align;
+ AES_KEY ks;
+ } ks;
+ block128_f block;
+ union {
+ cbc128_f cbc;
+ ctr128_f ctr;
+ } stream;
+} EVP_AES_KEY;
+
+typedef struct {
+ union {
+ double align;
+ AES_KEY ks;
+ } ks; /* AES key schedule to use */
+ int key_set; /* Set if key initialised */
+ int iv_set; /* Set if an iv is set */
+ GCM128_CONTEXT gcm;
+ uint8_t *iv; /* Temporary IV store */
+ int ivlen; /* IV length */
+ int taglen;
+ int iv_gen; /* It is OK to generate IVs */
+ int tls_aad_len; /* TLS AAD length */
+ ctr128_f ctr;
+} EVP_AES_GCM_CTX;
+
+
+void AES_ctr32_encrypt(const uint8_t *in, uint8_t *out, size_t blocks,
+ const AES_KEY *key, const uint8_t ivec[AES_BLOCK_SIZE]);
+
+
+#if !defined(OPENSSL_NO_ASM) && \
+ (defined(OPENSSL_X86_64) || defined(OPENSSL_X86))
+#define VPAES
+extern unsigned int OPENSSL_ia32cap_P[];
+
+static char vpaes_capable() {
+ return (OPENSSL_ia32cap_P[1] & (1 << (41 - 32))) != 0;
+}
+
+#if defined(OPENSSL_X86_64)
+#define BSAES
+static char bsaes_capable() {
+ return vpaes_capable();
+}
+#endif
+
+#elif !defined(OPENSSL_NO_ASM) && defined(OPENSSL_ARM)
+#include "../arm_arch.h"
+#if __ARM_ARCH__ >= 7
+#define BSAES
+static char bsaes_capable() {
+ return CRYPTO_is_NEON_capable();
+}
+#endif /* __ARM_ARCH__ >= 7 */
+#endif /* OPENSSL_ARM */
+
+#if defined(BSAES)
+/* On platforms where BSAES gets defined (just above), then these functions are
+ * provided by asm. */
+void bsaes_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length,
+ const AES_KEY *key, uint8_t ivec[16], int enc);
+void bsaes_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t len,
+ const AES_KEY *key, const uint8_t ivec[16]);
+#else
+static char bsaes_capable() {
+ return 0;
+}
+
+/* On other platforms, bsaes_capable() will always return false and so the
+ * following will never be called. */
+void bsaes_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length,
+ const AES_KEY *key, uint8_t ivec[16], int enc) {
+ abort();
+}
+
+void bsaes_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t len,
+ const AES_KEY *key, const uint8_t ivec[16]) {
+ abort();
+}
+#endif
+
+#if defined(VPAES)
+/* On platforms where BSAES gets defined (just above), then these functions are
+ * provided by asm. */
+int vpaes_set_encrypt_key(const uint8_t *userKey, int bits, AES_KEY *key);
+int vpaes_set_decrypt_key(const uint8_t *userKey, int bits, AES_KEY *key);
+
+void vpaes_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key);
+void vpaes_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key);
+
+void vpaes_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length,
+ const AES_KEY *key, uint8_t *ivec, int enc);
+#else
+static char vpaes_capable() {
+ return 0;
+}
+
+/* On other platforms, vpaes_capable() will always return false and so the
+ * following will never be called. */
+int vpaes_set_encrypt_key(const uint8_t *userKey, int bits, AES_KEY *key) {
+ abort();
+}
+int vpaes_set_decrypt_key(const uint8_t *userKey, int bits, AES_KEY *key) {
+ abort();
+}
+void vpaes_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
+ abort();
+}
+void vpaes_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
+ abort();
+}
+void vpaes_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length,
+ const AES_KEY *key, uint8_t *ivec, int enc) {
+ abort();
+}
+#endif
+
+#if !defined(OPENSSL_NO_ASM) && \
+ (defined(OPENSSL_X86_64) || defined(OPENSSL_X86))
+int aesni_set_encrypt_key(const uint8_t *userKey, int bits, AES_KEY *key);
+int aesni_set_decrypt_key(const uint8_t *userKey, int bits, AES_KEY *key);
+
+void aesni_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key);
+void aesni_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key);
+
+void aesni_ecb_encrypt(const uint8_t *in, uint8_t *out, size_t length,
+ const AES_KEY *key, int enc);
+void aesni_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length,
+ const AES_KEY *key, uint8_t *ivec, int enc);
+
+void aesni_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t blocks,
+ const void *key, const uint8_t *ivec);
+
+#if defined(OPENSSL_X86_64)
+size_t aesni_gcm_encrypt(const uint8_t *in, uint8_t *out, size_t len,
+ const void *key, uint8_t ivec[16], uint64_t *Xi);
+#define AES_gcm_encrypt aesni_gcm_encrypt
+size_t aesni_gcm_decrypt(const uint8_t *in, uint8_t *out, size_t len,
+ const void *key, uint8_t ivec[16], uint64_t *Xi);
+#define AES_gcm_decrypt aesni_gcm_decrypt
+void gcm_ghash_avx(uint64_t Xi[2], const u128 Htable[16], const uint8_t *in,
+ size_t len);
+#define AES_GCM_ASM(gctx) \
+ (gctx->ctr == aesni_ctr32_encrypt_blocks && gctx->gcm.ghash == gcm_ghash_avx)
+#endif
+
+#else
+
+/* On other platforms, aesni_capable() will always return false and so the
+ * following will never be called. */
+void aesni_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
+ abort();
+}
+int aesni_set_encrypt_key(const uint8_t *userKey, int bits, AES_KEY *key) {
+ abort();
+}
+void aesni_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t blocks,
+ const void *key, const uint8_t *ivec) {
+ abort();
+}
+
+#endif
+
+static int aes_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key,
+ const uint8_t *iv, int enc) {
+ int ret, mode;
+ EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data;
+
+ mode = ctx->cipher->flags & EVP_CIPH_MODE_MASK;
+ if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE) && !enc) {
+ if (bsaes_capable() && mode == EVP_CIPH_CBC_MODE) {
+ ret = AES_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks);
+ dat->block = (block128_f)AES_decrypt;
+ dat->stream.cbc = (cbc128_f)bsaes_cbc_encrypt;
+ } else if (vpaes_capable()) {
+ ret = vpaes_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks);
+ dat->block = (block128_f)vpaes_decrypt;
+ dat->stream.cbc =
+ mode == EVP_CIPH_CBC_MODE ? (cbc128_f)vpaes_cbc_encrypt : NULL;
+ } else {
+ ret = AES_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks);
+ dat->block = (block128_f)AES_decrypt;
+ dat->stream.cbc =
+ mode == EVP_CIPH_CBC_MODE ? (cbc128_f)AES_cbc_encrypt : NULL;
+ }
+ } else if (bsaes_capable() && mode == EVP_CIPH_CTR_MODE) {
+ ret = AES_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks);
+ dat->block = (block128_f)AES_encrypt;
+ dat->stream.ctr = (ctr128_f)bsaes_ctr32_encrypt_blocks;
+ } else if (vpaes_capable()) {
+ ret = vpaes_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks);
+ dat->block = (block128_f)vpaes_encrypt;
+ dat->stream.cbc =
+ mode == EVP_CIPH_CBC_MODE ? (cbc128_f)vpaes_cbc_encrypt : NULL;
+ } else {
+ ret = AES_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks);
+ dat->block = (block128_f)AES_encrypt;
+ dat->stream.cbc =
+ mode == EVP_CIPH_CBC_MODE ? (cbc128_f)AES_cbc_encrypt : NULL;
+ }
+
+ if (ret < 0) {
+ OPENSSL_PUT_ERROR(CIPHER, aes_init_key, CIPHER_R_AES_KEY_SETUP_FAILED);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int aes_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t len) {
+ EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data;
+
+ if (dat->stream.cbc) {
+ (*dat->stream.cbc)(in, out, len, &dat->ks, ctx->iv, ctx->encrypt);
+ } else if (ctx->encrypt) {
+ CRYPTO_cbc128_encrypt(in, out, len, &dat->ks, ctx->iv, dat->block);
+ } else {
+ CRYPTO_cbc128_decrypt(in, out, len, &dat->ks, ctx->iv, dat->block);
+ }
+
+ return 1;
+}
+
+static int aes_ecb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t len) {
+ size_t bl = ctx->cipher->block_size;
+ size_t i;
+ EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data;
+
+ if (len < bl) {
+ return 1;
+ }
+
+ for (i = 0, len -= bl; i <= len; i += bl) {
+ (*dat->block)(in + i, out + i, &dat->ks);
+ }
+
+ return 1;
+}
+
+static int aes_ctr_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t len) {
+ unsigned int num = ctx->num;
+ EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data;
+
+ if (dat->stream.ctr) {
+ CRYPTO_ctr128_encrypt_ctr32(in, out, len, &dat->ks, ctx->iv, ctx->buf, &num,
+ dat->stream.ctr);
+ } else {
+ CRYPTO_ctr128_encrypt(in, out, len, &dat->ks, ctx->iv, ctx->buf, &num,
+ dat->block);
+ }
+ ctx->num = (size_t)num;
+ return 1;
+}
+
+static int aes_gcm_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key,
+ const uint8_t *iv, int enc) {
+ EVP_AES_GCM_CTX *gctx = ctx->cipher_data;
+ if (!iv && !key) {
+ return 1;
+ }
+
+ if (key) {
+ if (bsaes_capable()) {
+ AES_set_encrypt_key(key, ctx->key_len * 8, &gctx->ks.ks);
+ CRYPTO_gcm128_init(&gctx->gcm, &gctx->ks, (block128_f)AES_encrypt);
+ gctx->ctr = (ctr128_f)bsaes_ctr32_encrypt_blocks;
+ } else if (vpaes_capable()) {
+ vpaes_set_encrypt_key(key, ctx->key_len * 8, &gctx->ks.ks);
+ CRYPTO_gcm128_init(&gctx->gcm, &gctx->ks, (block128_f)vpaes_encrypt);
+ gctx->ctr = NULL;
+ } else {
+ AES_set_encrypt_key(key, ctx->key_len * 8, &gctx->ks.ks);
+ CRYPTO_gcm128_init(&gctx->gcm, &gctx->ks, (block128_f)AES_encrypt);
+ gctx->ctr = NULL;
+ }
+
+ /* If we have an iv can set it directly, otherwise use
+ * saved IV. */
+ if (iv == NULL && gctx->iv_set) {
+ iv = gctx->iv;
+ }
+ if (iv) {
+ CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen);
+ gctx->iv_set = 1;
+ }
+ gctx->key_set = 1;
+ } else {
+ /* If key set use IV, otherwise copy */
+ if (gctx->key_set) {
+ CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen);
+ } else {
+ memcpy(gctx->iv, iv, gctx->ivlen);
+ }
+ gctx->iv_set = 1;
+ gctx->iv_gen = 0;
+ }
+ return 1;
+}
+
+static int aes_gcm_cleanup(EVP_CIPHER_CTX *c) {
+ EVP_AES_GCM_CTX *gctx = c->cipher_data;
+ OPENSSL_cleanse(&gctx->gcm, sizeof(gctx->gcm));
+ if (gctx->iv != c->iv) {
+ OPENSSL_free(gctx->iv);
+ }
+ return 1;
+}
+
+/* increment counter (64-bit int) by 1 */
+static void ctr64_inc(uint8_t *counter) {
+ int n = 8;
+ uint8_t c;
+
+ do {
+ --n;
+ c = counter[n];
+ ++c;
+ counter[n] = c;
+ if (c) {
+ return;
+ }
+ } while (n);
+}
+
+static int aes_gcm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr) {
+ EVP_AES_GCM_CTX *gctx = c->cipher_data;
+ switch (type) {
+ case EVP_CTRL_INIT:
+ gctx->key_set = 0;
+ gctx->iv_set = 0;
+ gctx->ivlen = c->cipher->iv_len;
+ gctx->iv = c->iv;
+ gctx->taglen = -1;
+ gctx->iv_gen = 0;
+ gctx->tls_aad_len = -1;
+ return 1;
+
+ case EVP_CTRL_GCM_SET_IVLEN:
+ if (arg <= 0) {
+ return 0;
+ }
+
+ /* Allocate memory for IV if needed */
+ if (arg > EVP_MAX_IV_LENGTH && arg > gctx->ivlen) {
+ if (gctx->iv != c->iv) {
+ OPENSSL_free(gctx->iv);
+ }
+ gctx->iv = OPENSSL_malloc(arg);
+ if (!gctx->iv) {
+ return 0;
+ }
+ }
+ gctx->ivlen = arg;
+ return 1;
+
+ case EVP_CTRL_GCM_SET_TAG:
+ if (arg <= 0 || arg > 16 || c->encrypt) {
+ return 0;
+ }
+ memcpy(c->buf, ptr, arg);
+ gctx->taglen = arg;
+ return 1;
+
+ case EVP_CTRL_GCM_GET_TAG:
+ if (arg <= 0 || arg > 16 || !c->encrypt || gctx->taglen < 0) {
+ return 0;
+ }
+ memcpy(ptr, c->buf, arg);
+ return 1;
+
+ case EVP_CTRL_GCM_SET_IV_FIXED:
+ /* Special case: -1 length restores whole IV */
+ if (arg == -1) {
+ memcpy(gctx->iv, ptr, gctx->ivlen);
+ gctx->iv_gen = 1;
+ return 1;
+ }
+ /* Fixed field must be at least 4 bytes and invocation field
+ * at least 8. */
+ if (arg < 4 || (gctx->ivlen - arg) < 8) {
+ return 0;
+ }
+ if (arg) {
+ memcpy(gctx->iv, ptr, arg);
+ }
+ if (c->encrypt &&
+ RAND_pseudo_bytes(gctx->iv + arg, gctx->ivlen - arg) <= 0) {
+ return 0;
+ }
+ gctx->iv_gen = 1;
+ return 1;
+
+ case EVP_CTRL_GCM_IV_GEN:
+ if (gctx->iv_gen == 0 || gctx->key_set == 0) {
+ return 0;
+ }
+ CRYPTO_gcm128_setiv(&gctx->gcm, gctx->iv, gctx->ivlen);
+ if (arg <= 0 || arg > gctx->ivlen) {
+ arg = gctx->ivlen;
+ }
+ memcpy(ptr, gctx->iv + gctx->ivlen - arg, arg);
+ /* Invocation field will be at least 8 bytes in size and
+ * so no need to check wrap around or increment more than
+ * last 8 bytes. */
+ ctr64_inc(gctx->iv + gctx->ivlen - 8);
+ gctx->iv_set = 1;
+ return 1;
+
+ case EVP_CTRL_GCM_SET_IV_INV:
+ if (gctx->iv_gen == 0 || gctx->key_set == 0 || c->encrypt) {
+ return 0;
+ }
+ memcpy(gctx->iv + gctx->ivlen - arg, ptr, arg);
+ CRYPTO_gcm128_setiv(&gctx->gcm, gctx->iv, gctx->ivlen);
+ gctx->iv_set = 1;
+ return 1;
+
+ case EVP_CTRL_AEAD_TLS1_AAD:
+ /* Save the AAD for later use */
+ if (arg != 13) {
+ return 0;
+ }
+ memcpy(c->buf, ptr, arg);
+ gctx->tls_aad_len = arg;
+ {
+ unsigned int len = c->buf[arg - 2] << 8 | c->buf[arg - 1];
+ /* Correct length for explicit IV */
+ len -= EVP_GCM_TLS_EXPLICIT_IV_LEN;
+ /* If decrypting correct for tag too */
+ if (!c->encrypt)
+ len -= EVP_GCM_TLS_TAG_LEN;
+ c->buf[arg - 2] = len >> 8;
+ c->buf[arg - 1] = len & 0xff;
+ }
+
+ /* Extra padding: tag appended to record */
+ return EVP_GCM_TLS_TAG_LEN;
+
+ default:
+ return -1;
+ }
+}
+
+/* Handle TLS GCM packet format. This consists of the last portion of the IV
+ * followed by the payload and finally the tag. On encrypt generate IV, encrypt
+ * payload and write the tag. On verify retrieve IV, decrypt payload and verify
+ * tag. */
+
+static int aes_gcm_tls_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out,
+ const uint8_t *in, size_t len) {
+ EVP_AES_GCM_CTX *gctx = ctx->cipher_data;
+ int rv = -1;
+ /* Encrypt/decrypt must be performed in place */
+ if (out != in || len < (EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN)) {
+ return -1;
+ }
+ /* Set IV from start of buffer or generate IV and write to start
+ * of buffer.
+ */
+ if (EVP_CIPHER_CTX_ctrl(
+ ctx, ctx->encrypt ? EVP_CTRL_GCM_IV_GEN : EVP_CTRL_GCM_SET_IV_INV,
+ EVP_GCM_TLS_EXPLICIT_IV_LEN, out) <= 0)
+ goto err;
+ /* Use saved AAD */
+ if (!CRYPTO_gcm128_aad(&gctx->gcm, ctx->buf, gctx->tls_aad_len))
+ goto err;
+ /* Fix buffer and length to point to payload */
+ in += EVP_GCM_TLS_EXPLICIT_IV_LEN;
+ out += EVP_GCM_TLS_EXPLICIT_IV_LEN;
+ len -= EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN;
+ if (ctx->encrypt) {
+ /* Encrypt payload */
+ if (gctx->ctr) {
+ size_t bulk = 0;
+#if defined(AES_GCM_ASM)
+ if (len >= 32 && AES_GCM_ASM(gctx)) {
+ if (!CRYPTO_gcm128_encrypt(&gctx->gcm, NULL, NULL, 0))
+ return -1;
+
+ bulk = AES_gcm_encrypt(in, out, len, gctx->gcm.key, gctx->gcm.Yi.c,
+ gctx->gcm.Xi.u);
+ gctx->gcm.len.u[1] += bulk;
+ }
+#endif
+ if (!CRYPTO_gcm128_encrypt_ctr32(&gctx->gcm, in + bulk, out + bulk,
+ len - bulk, gctx->ctr))
+ goto err;
+ } else {
+ size_t bulk = 0;
+ if (!CRYPTO_gcm128_encrypt(&gctx->gcm, in + bulk, out + bulk, len - bulk))
+ goto err;
+ }
+ out += len;
+ /* Finally write tag */
+ CRYPTO_gcm128_tag(&gctx->gcm, out, EVP_GCM_TLS_TAG_LEN);
+ rv = len + EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN;
+ } else {
+ /* Decrypt */
+ if (gctx->ctr) {
+ size_t bulk = 0;
+#if defined(AES_GCM_ASM)
+ if (len >= 16 && AES_GCM_ASM(gctx)) {
+ if (!CRYPTO_gcm128_decrypt(&gctx->gcm, NULL, NULL, 0))
+ return -1;
+
+ bulk = AES_gcm_decrypt(in, out, len, gctx->gcm.key, gctx->gcm.Yi.c,
+ gctx->gcm.Xi.u);
+ gctx->gcm.len.u[1] += bulk;
+ }
+#endif
+ if (!CRYPTO_gcm128_decrypt_ctr32(&gctx->gcm, in + bulk, out + bulk,
+ len - bulk, gctx->ctr))
+ goto err;
+ } else {
+ size_t bulk = 0;
+ if (!CRYPTO_gcm128_decrypt(&gctx->gcm, in + bulk, out + bulk, len - bulk))
+ goto err;
+ }
+ /* Retrieve tag */
+ CRYPTO_gcm128_tag(&gctx->gcm, ctx->buf, EVP_GCM_TLS_TAG_LEN);
+ /* If tag mismatch wipe buffer */
+ if (memcmp(ctx->buf, in + len, EVP_GCM_TLS_TAG_LEN)) {
+ OPENSSL_cleanse(out, len);
+ goto err;
+ }
+ rv = len;
+ }
+
+err:
+ gctx->iv_set = 0;
+ gctx->tls_aad_len = -1;
+ return rv;
+}
+
+static int aes_gcm_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in,
+ size_t len) {
+ EVP_AES_GCM_CTX *gctx = ctx->cipher_data;
+ /* If not set up, return error */
+ if (!gctx->key_set)
+ return -1;
+
+ if (gctx->tls_aad_len >= 0)
+ return aes_gcm_tls_cipher(ctx, out, in, len);
+
+ if (!gctx->iv_set)
+ return -1;
+ if (in) {
+ if (out == NULL) {
+ if (!CRYPTO_gcm128_aad(&gctx->gcm, in, len))
+ return -1;
+ } else if (ctx->encrypt) {
+ if (gctx->ctr) {
+ size_t bulk = 0;
+#if defined(AES_GCM_ASM)
+ if (len >= 32 && AES_GCM_ASM(gctx)) {
+ size_t res = (16 - gctx->gcm.mres) % 16;
+
+ if (!CRYPTO_gcm128_encrypt(&gctx->gcm, in, out, res))
+ return -1;
+
+ bulk = AES_gcm_encrypt(in + res, out + res, len - res, gctx->gcm.key,
+ gctx->gcm.Yi.c, gctx->gcm.Xi.u);
+ gctx->gcm.len.u[1] += bulk;
+ bulk += res;
+ }
+#endif
+ if (!CRYPTO_gcm128_encrypt_ctr32(&gctx->gcm, in + bulk, out + bulk,
+ len - bulk, gctx->ctr))
+ return -1;
+ } else {
+ size_t bulk = 0;
+ if (!CRYPTO_gcm128_encrypt(&gctx->gcm, in + bulk, out + bulk,
+ len - bulk))
+ return -1;
+ }
+ } else {
+ if (gctx->ctr) {
+ size_t bulk = 0;
+#if defined(AES_GCM_ASM)
+ if (len >= 16 && AES_GCM_ASM(gctx)) {
+ size_t res = (16 - gctx->gcm.mres) % 16;
+
+ if (!CRYPTO_gcm128_decrypt(&gctx->gcm, in, out, res))
+ return -1;
+
+ bulk = AES_gcm_decrypt(in + res, out + res, len - res, gctx->gcm.key,
+ gctx->gcm.Yi.c, gctx->gcm.Xi.u);
+ gctx->gcm.len.u[1] += bulk;
+ bulk += res;
+ }
+#endif
+ if (!CRYPTO_gcm128_decrypt_ctr32(&gctx->gcm, in + bulk, out + bulk,
+ len - bulk, gctx->ctr))
+ return -1;
+ } else {
+ size_t bulk = 0;
+ if (!CRYPTO_gcm128_decrypt(&gctx->gcm, in + bulk, out + bulk,
+ len - bulk))
+ return -1;
+ }
+ }
+ return len;
+ } else {
+ if (!ctx->encrypt) {
+ if (gctx->taglen < 0)
+ return -1;
+ if (!CRYPTO_gcm128_finish(&gctx->gcm, ctx->buf, gctx->taglen) != 0)
+ return -1;
+ gctx->iv_set = 0;
+ return 0;
+ }
+ CRYPTO_gcm128_tag(&gctx->gcm, ctx->buf, 16);
+ gctx->taglen = 16;
+ /* Don't reuse the IV */
+ gctx->iv_set = 0;
+ return 0;
+ }
+}
+
+static const EVP_CIPHER aes_128_cbc = {
+ NID_aes_128_cbc, 16 /* block_size */, 16 /* key_size */,
+ 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CBC_MODE,
+ NULL /* app_data */, aes_init_key, aes_cbc_cipher,
+ NULL /* cleanup */, NULL /* ctrl */};
+
+static const EVP_CIPHER aes_128_ctr = {
+ NID_aes_128_ctr, 1 /* block_size */, 16 /* key_size */,
+ 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CTR_MODE,
+ NULL /* app_data */, aes_init_key, aes_ctr_cipher,
+ NULL /* cleanup */, NULL /* ctrl */};
+
+static const EVP_CIPHER aes_128_ecb = {
+ NID_aes_128_ecb, 16 /* block_size */, 16 /* key_size */,
+ 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE,
+ NULL /* app_data */, aes_init_key, aes_ecb_cipher,
+ NULL /* cleanup */, NULL /* ctrl */};
+
+static const EVP_CIPHER aes_128_gcm = {
+ NID_aes_128_gcm, 1 /* block_size */, 16 /* key_size */, 12 /* iv_len */,
+ sizeof(EVP_AES_GCM_CTX),
+ EVP_CIPH_GCM_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER |
+ EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT |
+ EVP_CIPH_FLAG_AEAD_CIPHER,
+ NULL /* app_data */, aes_gcm_init_key, aes_gcm_cipher, aes_gcm_cleanup,
+ aes_gcm_ctrl};
+
+
+static const EVP_CIPHER aes_256_cbc = {
+ NID_aes_128_cbc, 16 /* block_size */, 32 /* key_size */,
+ 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CBC_MODE,
+ NULL /* app_data */, aes_init_key, aes_cbc_cipher,
+ NULL /* cleanup */, NULL /* ctrl */};
+
+static const EVP_CIPHER aes_256_ctr = {
+ NID_aes_128_ctr, 1 /* block_size */, 32 /* key_size */,
+ 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CTR_MODE,
+ NULL /* app_data */, aes_init_key, aes_ctr_cipher,
+ NULL /* cleanup */, NULL /* ctrl */};
+
+static const EVP_CIPHER aes_256_ecb = {
+ NID_aes_128_ecb, 16 /* block_size */, 32 /* key_size */,
+ 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE,
+ NULL /* app_data */, aes_init_key, aes_ecb_cipher,
+ NULL /* cleanup */, NULL /* ctrl */};
+
+static const EVP_CIPHER aes_256_gcm = {
+ NID_aes_128_gcm, 1 /* block_size */, 32 /* key_size */, 12 /* iv_len */,
+ sizeof(EVP_AES_GCM_CTX),
+ EVP_CIPH_GCM_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER |
+ EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT |
+ EVP_CIPH_FLAG_AEAD_CIPHER,
+ NULL /* app_data */, aes_gcm_init_key, aes_gcm_cipher, aes_gcm_cleanup,
+ aes_gcm_ctrl};
+
+#if !defined(OPENSSL_NO_ASM) && \
+ (defined(OPENSSL_X86_64) || defined(OPENSSL_X86))
+
+/* AES-NI section. */
+
+static char aesni_capable() {
+ return (OPENSSL_ia32cap_P[1] & (1 << (57 - 32))) != 0;
+}
+
+static int aesni_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key,
+ const uint8_t *iv, int enc) {
+ int ret, mode;
+ EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data;
+
+ mode = ctx->cipher->flags & EVP_CIPH_MODE_MASK;
+ if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE) && !enc) {
+ ret = aesni_set_decrypt_key(key, ctx->key_len * 8, ctx->cipher_data);
+ dat->block = (block128_f)aesni_decrypt;
+ dat->stream.cbc =
+ mode == EVP_CIPH_CBC_MODE ? (cbc128_f)aesni_cbc_encrypt : NULL;
+ } else {
+ ret = aesni_set_encrypt_key(key, ctx->key_len * 8, ctx->cipher_data);
+ dat->block = (block128_f)aesni_encrypt;
+ if (mode == EVP_CIPH_CBC_MODE) {
+ dat->stream.cbc = (cbc128_f)aesni_cbc_encrypt;
+ } else if (mode == EVP_CIPH_CTR_MODE) {
+ dat->stream.ctr = (ctr128_f)aesni_ctr32_encrypt_blocks;
+ } else {
+ dat->stream.cbc = NULL;
+ }
+ }
+
+ if (ret < 0) {
+ OPENSSL_PUT_ERROR(CIPHER, aesni_init_key, CIPHER_R_AES_KEY_SETUP_FAILED);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int aesni_cbc_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out,
+ const uint8_t *in, size_t len) {
+ aesni_cbc_encrypt(in, out, len, ctx->cipher_data, ctx->iv, ctx->encrypt);
+
+ return 1;
+}
+
+static int aesni_ecb_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out,
+ const uint8_t *in, size_t len) {
+ size_t bl = ctx->cipher->block_size;
+
+ if (len < bl) {
+ return 1;
+ }
+
+ aesni_ecb_encrypt(in, out, len, ctx->cipher_data, ctx->encrypt);
+
+ return 1;
+}
+
+static int aesni_gcm_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key,
+ const uint8_t *iv, int enc) {
+ EVP_AES_GCM_CTX *gctx = ctx->cipher_data;
+ if (!iv && !key)
+ return 1;
+ if (key) {
+ aesni_set_encrypt_key(key, ctx->key_len * 8, &gctx->ks.ks);
+ CRYPTO_gcm128_init(&gctx->gcm, &gctx->ks, (block128_f)aesni_encrypt);
+ gctx->ctr = (ctr128_f)aesni_ctr32_encrypt_blocks;
+ /* If we have an iv can set it directly, otherwise use
+ * saved IV. */
+ if (iv == NULL && gctx->iv_set) {
+ iv = gctx->iv;
+ }
+ if (iv) {
+ CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen);
+ gctx->iv_set = 1;
+ }
+ gctx->key_set = 1;
+ } else {
+ /* If key set use IV, otherwise copy */
+ if (gctx->key_set) {
+ CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen);
+ } else {
+ memcpy(gctx->iv, iv, gctx->ivlen);
+ }
+ gctx->iv_set = 1;
+ gctx->iv_gen = 0;
+ }
+ return 1;
+}
+
+static const EVP_CIPHER aesni_128_cbc = {
+ NID_aes_128_cbc, 16 /* block_size */, 16 /* key_size */,
+ 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CBC_MODE,
+ NULL /* app_data */, aesni_init_key, aesni_cbc_cipher,
+ NULL /* cleanup */, NULL /* ctrl */};
+
+static const EVP_CIPHER aesni_128_ctr = {
+ NID_aes_128_ctr, 1 /* block_size */, 16 /* key_size */,
+ 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CTR_MODE,
+ NULL /* app_data */, aesni_init_key, aes_ctr_cipher,
+ NULL /* cleanup */, NULL /* ctrl */};
+
+static const EVP_CIPHER aesni_128_ecb = {
+ NID_aes_128_ecb, 16 /* block_size */, 16 /* key_size */,
+ 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE,
+ NULL /* app_data */, aesni_init_key, aesni_ecb_cipher,
+ NULL /* cleanup */, NULL /* ctrl */};
+
+static const EVP_CIPHER aesni_128_gcm = {
+ NID_aes_128_gcm, 1 /* block_size */, 16 /* key_size */, 12 /* iv_len */,
+ sizeof(EVP_AES_GCM_CTX),
+ EVP_CIPH_GCM_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER |
+ EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT |
+ EVP_CIPH_FLAG_AEAD_CIPHER,
+ NULL /* app_data */, aesni_gcm_init_key, aes_gcm_cipher, aes_gcm_cleanup,
+ aes_gcm_ctrl};
+
+
+static const EVP_CIPHER aesni_256_cbc = {
+ NID_aes_128_cbc, 16 /* block_size */, 32 /* key_size */,
+ 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CBC_MODE,
+ NULL /* app_data */, aesni_init_key, aesni_cbc_cipher,
+ NULL /* cleanup */, NULL /* ctrl */};
+
+static const EVP_CIPHER aesni_256_ctr = {
+ NID_aes_128_ctr, 1 /* block_size */, 32 /* key_size */,
+ 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CTR_MODE,
+ NULL /* app_data */, aesni_init_key, aes_ctr_cipher,
+ NULL /* cleanup */, NULL /* ctrl */};
+
+static const EVP_CIPHER aesni_256_ecb = {
+ NID_aes_128_ecb, 16 /* block_size */, 32 /* key_size */,
+ 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE,
+ NULL /* app_data */, aesni_init_key, aesni_ecb_cipher,
+ NULL /* cleanup */, NULL /* ctrl */};
+
+static const EVP_CIPHER aesni_256_gcm = {
+ NID_aes_256_gcm, 1 /* block_size */, 32 /* key_size */, 12 /* iv_len */,
+ sizeof(EVP_AES_GCM_CTX),
+ EVP_CIPH_GCM_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER |
+ EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT |
+ EVP_CIPH_FLAG_AEAD_CIPHER,
+ NULL /* app_data */, aesni_gcm_init_key, aes_gcm_cipher, aes_gcm_cleanup,
+ aes_gcm_ctrl};
+
+#define EVP_CIPHER_FUNCTION(keybits, mode) \
+ const EVP_CIPHER *EVP_aes_##keybits##_##mode(void) { \
+ if (aesni_capable()) { \
+ return &aesni_##keybits##_##mode; \
+ } else { \
+ return &aes_##keybits##_##mode; \
+ } \
+ }
+
+#else /* ^^^ OPENSSL_X86_64 || OPENSSL_X86 */
+
+#define EVP_CIPHER_FUNCTION(keybits, mode) \
+ const EVP_CIPHER *EVP_aes_##keybits##_##mode(void) { \
+ return &aes_##keybits##_##mode; \
+ }
+
+#endif
+
+EVP_CIPHER_FUNCTION(128, cbc)
+EVP_CIPHER_FUNCTION(128, ctr)
+EVP_CIPHER_FUNCTION(128, ecb)
+EVP_CIPHER_FUNCTION(128, gcm)
+
+EVP_CIPHER_FUNCTION(256, cbc)
+EVP_CIPHER_FUNCTION(256, ctr)
+EVP_CIPHER_FUNCTION(256, ecb)
+EVP_CIPHER_FUNCTION(256, gcm)
diff --git a/crypto/cipher/e_des.c b/crypto/cipher/e_des.c
new file mode 100644
index 0000000..d4b04f4
--- /dev/null
+++ b/crypto/cipher/e_des.c
@@ -0,0 +1,157 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/cipher.h>
+#include <openssl/des.h>
+#include <openssl/obj.h>
+
+#include "internal.h"
+
+
+#define EVP_MAXCHUNK (1<<30)
+
+typedef struct {
+ union {
+ double align;
+ DES_key_schedule ks;
+ } ks;
+} EVP_DES_KEY;
+
+static int des_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key,
+ const uint8_t *iv, int enc) {
+ DES_cblock *deskey = (DES_cblock *)key;
+ EVP_DES_KEY *dat = (EVP_DES_KEY *)ctx->cipher_data;
+
+ DES_set_key(deskey, &dat->ks.ks);
+ return 1;
+}
+
+static int des_cbc_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in,
+ size_t in_len) {
+ EVP_DES_KEY *dat = (EVP_DES_KEY *)ctx->cipher_data;
+
+ while (in_len >= EVP_MAXCHUNK) {
+ DES_ncbc_encrypt(in, out, EVP_MAXCHUNK, &dat->ks.ks, (DES_cblock *)ctx->iv,
+ ctx->encrypt);
+ in_len -= EVP_MAXCHUNK;
+ in += EVP_MAXCHUNK;
+ out += EVP_MAXCHUNK;
+ }
+
+ if (in_len) {
+ DES_ncbc_encrypt(in, out, (long)in_len, &dat->ks.ks,
+ (DES_cblock *)ctx->iv, ctx->encrypt);
+ }
+
+ return 1;
+}
+
+static const EVP_CIPHER des_cbc = {
+ NID_des_cbc, 8 /* block_size */, 8 /* key_size */,
+ 8 /* iv_len */, sizeof(EVP_DES_KEY), EVP_CIPH_CBC_MODE,
+ NULL /* app_data */, des_init_key, des_cbc_cipher,
+ NULL /* cleanup */, NULL /* ctrl */, };
+
+const EVP_CIPHER *EVP_des_cbc(void) { return &des_cbc; }
+
+
+typedef struct {
+ union {
+ double align;
+ DES_key_schedule ks[3];
+ } ks;
+} DES_EDE_KEY;
+
+
+static int des_ede3_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[2], &dat->ks.ks[2]);
+
+ return 1;
+}
+
+static int des_ede3_cbc_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out,
+ const uint8_t *in, size_t in_len) {
+ DES_EDE_KEY *dat = (DES_EDE_KEY*) ctx->cipher_data;
+
+ while (in_len >= EVP_MAXCHUNK) {
+ DES_ede3_cbc_encrypt(in, out, EVP_MAXCHUNK, &dat->ks.ks[0], &dat->ks.ks[1],
+ &dat->ks.ks[2], (DES_cblock *)ctx->iv, ctx->encrypt);
+ in_len -= EVP_MAXCHUNK;
+ in += EVP_MAXCHUNK;
+ out += EVP_MAXCHUNK;
+ }
+
+ if (in_len) {
+ DES_ede3_cbc_encrypt(in, out, in_len, &dat->ks.ks[0], &dat->ks.ks[1],
+ &dat->ks.ks[2], (DES_cblock *)ctx->iv, ctx->encrypt);
+ }
+
+ return 1;
+}
+
+static const EVP_CIPHER des3_cbc = {
+ NID_des_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; }
diff --git a/crypto/cipher/e_null.c b/crypto/cipher/e_null.c
new file mode 100644
index 0000000..196520d
--- /dev/null
+++ b/crypto/cipher/e_null.c
@@ -0,0 +1,83 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/cipher.h>
+
+#include <openssl/obj.h>
+
+#include "internal.h"
+
+
+static int null_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key,
+ const uint8_t *iv, int enc) {
+ return 1;
+}
+
+static int null_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out,
+ const uint8_t *in, size_t in_len) {
+ if (in != out) {
+ memcpy(out, in, in_len);
+ }
+ return 1;
+}
+
+static const EVP_CIPHER n_cipher = {
+ NID_undef, 1 /* block size */, 0 /* key_len */, 0 /* iv_len */,
+ 0 /* ctx_size */, 0 /* flags */, NULL /* app_data */, null_init_key,
+ null_cipher, NULL /* cleanup */, NULL /* ctrl */,
+};
+
+const EVP_CIPHER *EVP_enc_null(void) { return &n_cipher; }
diff --git a/crypto/cipher/e_rc4.c b/crypto/cipher/e_rc4.c
new file mode 100644
index 0000000..840855a
--- /dev/null
+++ b/crypto/cipher/e_rc4.c
@@ -0,0 +1,87 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/cipher.h>
+#include <openssl/md5.h>
+#include <openssl/obj.h>
+#include <openssl/rc4.h>
+
+#include "internal.h"
+
+
+static int rc4_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key,
+ const uint8_t *iv, int enc) {
+ RC4_KEY *rc4key = (RC4_KEY *)ctx->cipher_data;
+
+ RC4_set_key(rc4key, EVP_CIPHER_CTX_key_length(ctx), key);
+ return 1;
+}
+
+static int rc4_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in,
+ size_t in_len) {
+ RC4_KEY *rc4key = (RC4_KEY *)ctx->cipher_data;
+
+ RC4(rc4key, in_len, in, out);
+ return 1;
+}
+
+static const EVP_CIPHER rc4 = {
+ NID_rc4, 1 /* block_size */, 16 /* key_size */,
+ 0 /* iv_len */, sizeof(RC4_KEY), EVP_CIPH_VARIABLE_LENGTH,
+ NULL /* app_data */, rc4_init_key, rc4_cipher,
+ NULL /* cleanup */, NULL /* ctrl */, };
+
+const EVP_CIPHER *EVP_rc4(void) { return &rc4; }
diff --git a/crypto/cipher/internal.h b/crypto/cipher/internal.h
new file mode 100644
index 0000000..1edc059
--- /dev/null
+++ b/crypto/cipher/internal.h
@@ -0,0 +1,113 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_CIPHER_INTERNAL_H
+#define OPENSSL_HEADER_CIPHER_INTERNAL_H
+
+#include <openssl/base.h>
+
+#include <openssl/asn1t.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+struct evp_cipher_st {
+ /* type contains a NID identifing the cipher. (For example, NID_rc4.) */
+ int nid;
+
+ /* block_size contains the block size, in bytes, of the cipher, or 1 for a
+ * stream cipher. */
+ unsigned block_size;
+
+ /* key_len contains the key size, in bytes, for the cipher. If the cipher
+ * takes a variable key size then this contains the default size. */
+ unsigned key_len;
+
+ /* iv_len contains the IV size, in bytes, or zero if inapplicable. */
+ unsigned iv_len;
+
+ /* ctx_size contains the size, in bytes, of the per-key context for this
+ * cipher. */
+ unsigned ctx_size;
+
+ /* flags contains the OR of a number of flags. See |EVP_CIPH_*|. */
+ uint32_t flags;
+
+ /* app_data is a pointer to opaque, user data. */
+ void *app_data;
+
+ int (*init)(EVP_CIPHER_CTX *ctx, const uint8_t *key, const uint8_t *iv,
+ int enc);
+
+ int (*cipher)(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in,
+ size_t inl);
+
+ int (*cleanup)(EVP_CIPHER_CTX *);
+
+ int (*ctrl)(EVP_CIPHER_CTX *, int type, int arg, void *ptr);
+};
+
+/* EVP_CIPH_MODE_MASK contains the bits of |flags| that represent the mode. */
+#define EVP_CIPH_MODE_MASK 0x3f
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_CIPHER_INTERNAL_H */
diff --git a/crypto/comp/CMakeLists.txt b/crypto/comp/CMakeLists.txt
new file mode 100644
index 0000000..0d543ad
--- /dev/null
+++ b/crypto/comp/CMakeLists.txt
@@ -0,0 +1,10 @@
+include_directories(. .. ../../include)
+
+add_library(
+ comp
+
+ OBJECT
+
+ comp.c
+ zlib.c
+)
diff --git a/crypto/comp/comp.c b/crypto/comp/comp.c
new file mode 100644
index 0000000..e4c9a80
--- /dev/null
+++ b/crypto/comp/comp.c
@@ -0,0 +1,119 @@
+/* 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/comp.h>
+
+#include <openssl/mem.h>
+
+
+COMP_CTX *COMP_CTX_new(COMP_METHOD *meth) {
+ COMP_CTX *ret;
+
+ ret = OPENSSL_malloc(sizeof(COMP_CTX));
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ memset(ret, 0, sizeof(COMP_CTX));
+ ret->meth = meth;
+ if (ret->meth->init != NULL && !ret->meth->init(ret)) {
+ OPENSSL_free(ret);
+ ret = NULL;
+ }
+
+ return ret;
+}
+
+void COMP_CTX_free(COMP_CTX *ctx) {
+ if (ctx == NULL) {
+ return;
+ }
+
+ if (ctx->meth->finish != NULL) {
+ ctx->meth->finish(ctx);
+ }
+
+ OPENSSL_free(ctx);
+}
+
+int COMP_compress_block(COMP_CTX *ctx, uint8_t *out, size_t out_len,
+ uint8_t *in, size_t in_len) {
+ int ret;
+ if (ctx->meth->compress == NULL) {
+ return -1;
+ }
+ ret = ctx->meth->compress(ctx, out, out_len, in, in_len);
+ if (ret > 0) {
+ ctx->compress_in += in_len;
+ ctx->compress_out += ret;
+ }
+ return ret;
+}
+
+int COMP_expand_block(COMP_CTX *ctx, uint8_t *out, size_t out_len, uint8_t *in,
+ size_t in_len) {
+ int ret;
+
+ if (ctx->meth->expand == NULL) {
+ return -1;
+ }
+ ret = ctx->meth->expand(ctx, out, out_len, in, in_len);
+ if (ret > 0) {
+ ctx->expand_in += in_len;
+ ctx->expand_out += ret;
+ }
+ return ret;
+}
diff --git a/crypto/comp/comp.h b/crypto/comp/comp.h
new file mode 100644
index 0000000..12a967a
--- /dev/null
+++ b/crypto/comp/comp.h
@@ -0,0 +1,123 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_COMP_H
+#define OPENSSL_HEADER_COMP_H
+
+#include <openssl/base.h>
+
+#include <openssl/ex_data.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* Compression methods */
+
+/* COMP_zlib returns a method that implements standard, zlib compression. */
+COMP_METHOD *COMP_zlib(void);
+
+
+/* Compression contexts */
+
+/* COMP_CTX_new allocates a fresh |COMP_CTX| which will compress with the given
+ * compression method. It returns the new |COMP_CTX| or NULL on error. */
+COMP_CTX *COMP_CTX_new(COMP_METHOD *meth);
+
+/* COMP_CTX_free frees all data owned by |ctx| and |ctx| itself. */
+void COMP_CTX_free(COMP_CTX *ctx);
+
+
+int COMP_compress_block(COMP_CTX *ctx, uint8_t *out, size_t out_len,
+ uint8_t *in, size_t in_len);
+
+int COMP_expand_block(COMP_CTX *ctx, uint8_t *out, size_t out_len,
+ uint8_t *in, size_t in_len);
+
+
+/* Private functions */
+
+struct comp_ctx_st {
+ COMP_METHOD *meth;
+ unsigned long compress_in;
+ unsigned long compress_out;
+ unsigned long expand_in;
+ unsigned long expand_out;
+
+ CRYPTO_EX_DATA ex_data;
+};
+
+struct comp_method_st {
+ int type; /* NID for compression library */
+ const char *name; /* A text string to identify the library */
+ int (*init)(COMP_CTX *ctx);
+ void (*finish)(COMP_CTX *ctx);
+ int (*compress)(COMP_CTX *ctx, uint8_t *out, unsigned int olen, uint8_t *in,
+ unsigned int ilen);
+ int (*expand)(COMP_CTX *ctx, uint8_t *out, unsigned int olen, uint8_t *in,
+ unsigned int ilen);
+ /* The following two do NOTHING, but are kept for backward compatibility */
+ long (*ctrl)(void);
+ long (*callback_ctrl)(void);
+} /* COMP_METHOD */;
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_HMAC_H */
diff --git a/crypto/comp/zlib.c b/crypto/comp/zlib.c
new file mode 100644
index 0000000..627fdc3
--- /dev/null
+++ b/crypto/comp/zlib.c
@@ -0,0 +1,62 @@
+/* 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/comp.h>
+
+
+COMP_METHOD *COMP_zlib(void) {
+ return NULL;
+}
diff --git a/crypto/conf/CMakeLists.txt b/crypto/conf/CMakeLists.txt
new file mode 100644
index 0000000..05439d5
--- /dev/null
+++ b/crypto/conf/CMakeLists.txt
@@ -0,0 +1,10 @@
+include_directories(. .. ../../include)
+
+add_library(
+ conf
+
+ OBJECT
+
+ conf.c
+ conf_error.c
+)
diff --git a/crypto/conf/conf.c b/crypto/conf/conf.c
new file mode 100644
index 0000000..898a9ba
--- /dev/null
+++ b/crypto/conf/conf.c
@@ -0,0 +1,741 @@
+/* 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/conf.h>
+
+#include <string.h>
+#include <ctype.h>
+
+#include <openssl/bio.h>
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+#include "conf_def.h"
+
+
+static uint32_t conf_value_hash(const CONF_VALUE *v) {
+ return (lh_strhash(v->section) << 2) ^ lh_strhash(v->name);
+}
+
+static int conf_value_cmp(const CONF_VALUE *a, const CONF_VALUE *b) {
+ int i;
+
+ if (a->section != b->section) {
+ i = strcmp(a->section, b->section);
+ if (i) {
+ return i;
+ }
+ }
+
+ if (a->name != NULL && b->name != NULL) {
+ return strcmp(a->name, b->name);
+ } else if (a->name == b->name) {
+ return 0;
+ } else {
+ return (a->name == NULL) ? -1 : 1;
+ }
+}
+
+CONF *NCONF_new() {
+ CONF *conf;
+
+ conf = OPENSSL_malloc(sizeof(CONF));
+ if (conf == NULL) {
+ return NULL;
+ }
+
+ conf->data = lh_CONF_VALUE_new(conf_value_hash, conf_value_cmp);
+ if (conf->data == NULL) {
+ OPENSSL_free(conf);
+ return NULL;
+ }
+
+ return conf;
+}
+
+static void value_free_contents(CONF_VALUE *value) {
+ if (value->section) {
+ OPENSSL_free(value->section);
+ }
+ if (value->name) {
+ OPENSSL_free(value->name);
+ if (value->value) {
+ OPENSSL_free(value->value);
+ }
+ } else {
+ if (value->value) {
+ sk_CONF_VALUE_free((STACK_OF(CONF_VALUE)*)value->value);
+ }
+ }
+}
+
+static void value_free(CONF_VALUE *value) {
+ value_free_contents(value);
+ OPENSSL_free(value);
+}
+
+void NCONF_free(CONF *conf) {
+ if (conf == NULL || conf->data == NULL) {
+ return;
+ }
+
+ lh_CONF_VALUE_doall(conf->data, value_free_contents);
+ 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;
+ CONF_VALUE *v = NULL, *old_value;
+
+ sk = sk_CONF_VALUE_new_null();
+ v = OPENSSL_malloc(sizeof(CONF_VALUE));
+ if (sk == NULL || v == NULL) {
+ goto err;
+ }
+ i = strlen(section) + 1;
+ v->section = OPENSSL_malloc(i);
+ if (v->section == NULL) {
+ goto err;
+ }
+
+ memcpy(v->section, section, i);
+ v->section[i-1] = 0;
+ v->name = NULL;
+ v->value = (char *)sk;
+
+ if (!lh_CONF_VALUE_insert(conf->data, &old_value, v)) {
+ goto err;
+ }
+ if (old_value) {
+ value_free(old_value);
+ }
+ ok = 1;
+
+err:
+ if (!ok) {
+ if (sk != NULL) {
+ sk_CONF_VALUE_free(sk);
+ }
+ if (v != NULL) {
+ OPENSSL_free(v);
+ }
+ v = NULL;
+ }
+ return v;
+}
+
+static int str_copy(CONF *conf, char *section, char **pto, char *from) {
+ int q, r, rr = 0, to = 0, len = 0;
+ char *s, *e, *rp, *rrp, *np, *cp, v;
+ const char *p;
+ BUF_MEM *buf;
+
+ buf = BUF_MEM_new();
+ if (buf == NULL) {
+ return 0;
+ }
+
+ len = strlen(from) + 1;
+ if (!BUF_MEM_grow(buf, len)) {
+ goto err;
+ }
+
+ for (;;) {
+ if (IS_QUOTE(conf, *from)) {
+ q = *from;
+ from++;
+ while (!IS_EOF(conf, *from) && (*from != q)) {
+ if (IS_ESC(conf, *from)) {
+ from++;
+ if (IS_EOF(conf, *from)) {
+ break;
+ }
+ }
+ buf->data[to++] = *(from++);
+ }
+ if (*from == q) {
+ from++;
+ }
+ } else if (IS_DQUOTE(conf, *from)) {
+ q = *from;
+ from++;
+ while (!IS_EOF(conf, *from)) {
+ if (*from == q) {
+ if (*(from + 1) == q) {
+ from++;
+ } else {
+ break;
+ }
+ }
+ buf->data[to++] = *(from++);
+ }
+ if (*from == q) {
+ from++;
+ }
+ } else if (IS_ESC(conf, *from)) {
+ from++;
+ v = *(from++);
+ if (IS_EOF(conf, v)) {
+ break;
+ } else if (v == 'r') {
+ v = '\r';
+ } else if (v == 'n') {
+ v = '\n';
+ } else if (v == 'b') {
+ v = '\b';
+ } else if (v == 't') {
+ v = '\t';
+ }
+ buf->data[to++] = v;
+ } else if (IS_EOF(conf, *from)) {
+ break;
+ } else if (*from == '$') {
+ /* try to expand it */
+ rrp = NULL;
+ s = &(from[1]);
+ if (*s == '{') {
+ q = '}';
+ } else if (*s == '(') {
+ q = ')';
+ } else {
+ q = 0;
+ }
+
+ if (q) {
+ s++;
+ }
+ cp = section;
+ e = np = s;
+ while (IS_ALPHA_NUMERIC(conf, *e)) {
+ e++;
+ }
+ if (e[0] == ':' && e[1] == ':') {
+ cp = np;
+ rrp = e;
+ rr = *e;
+ *rrp = '\0';
+ e += 2;
+ np = e;
+ while (IS_ALPHA_NUMERIC(conf, *e)) {
+ e++;
+ }
+ }
+ r = *e;
+ *e = '\0';
+ rp = e;
+ if (q) {
+ if (r != q) {
+ OPENSSL_PUT_ERROR(CONF, str_copy, CONF_R_NO_CLOSE_BRACE);
+ goto err;
+ }
+ e++;
+ }
+ /* So at this point we have
+ * np which is the start of the name string which is
+ * '\0' terminated.
+ * cp which is the start of the section string which is
+ * '\0' terminated.
+ * e is the 'next point after'.
+ * r and rr are the chars replaced by the '\0'
+ * rp and rrp is where 'r' and 'rr' came from. */
+ p = NCONF_get_string(conf, cp, np);
+ if (rrp != NULL) {
+ *rrp = rr;
+ }
+ *rp = r;
+ if (p == NULL) {
+ OPENSSL_PUT_ERROR(CONF, str_copy, CONF_R_VARIABLE_HAS_NO_VALUE);
+ goto err;
+ }
+ BUF_MEM_grow_clean(buf, (strlen(p) + buf->length - (e - from)));
+ while (*p) {
+ buf->data[to++] = *(p++);
+ }
+
+ /* Since we change the pointer 'from', we also have
+ to change the perceived length of the string it
+ points at. /RL */
+ len -= e - from;
+ from = e;
+
+ /* In case there were no braces or parenthesis around
+ the variable reference, we have to put back the
+ character that was replaced with a '\0'. /RL */
+ *rp = r;
+ } else {
+ buf->data[to++] = *(from++);
+ }
+ }
+
+ buf->data[to] = '\0';
+ if (*pto != NULL) {
+ OPENSSL_free(*pto);
+ }
+ *pto = buf->data;
+ OPENSSL_free(buf);
+ return 1;
+
+err:
+ if (buf != NULL) {
+ BUF_MEM_free(buf);
+ }
+ return 0;
+}
+
+static CONF_VALUE *get_section(const CONF *conf, const char *section) {
+ CONF_VALUE template;
+
+ memset(&template, 0, sizeof(template));
+ template.section = (char *) section;
+ return lh_CONF_VALUE_retrieve(conf->data, &template);
+}
+
+STACK_OF(CONF_VALUE) *NCONF_get_section(const CONF *conf, const char *section) {
+ CONF_VALUE *section_value = get_section(conf, section);
+ if (section_value == NULL) {
+ return NULL;
+ }
+ return (STACK_OF(CONF_VALUE)*) section_value->value;
+}
+
+const char *NCONF_get_string(const CONF *conf, const char *section,
+ const char *name) {
+ CONF_VALUE template, *value;
+
+ memset(&template, 0, sizeof(template));
+ template.section = (char *) section;
+ template.name = (char *) name;
+ value = lh_CONF_VALUE_retrieve(conf->data, &template);
+ if (value == NULL) {
+ return NULL;
+ }
+ return value->value;
+}
+
+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;
+ if (!sk_CONF_VALUE_push(section_stack, value)) {
+ return 0;
+ }
+
+ if (!lh_CONF_VALUE_insert(conf->data, &old_value, value)) {
+ return 0;
+ }
+ if (old_value != NULL) {
+ (void)sk_CONF_VALUE_delete_ptr(section_stack, old_value);
+ value_free(old_value);
+ }
+
+ return 1;
+}
+
+static char *eat_ws(CONF *conf, char *p) {
+ while (IS_WS(conf, *p) && !IS_EOF(conf, *p)) {
+ p++;
+ }
+ return p;
+}
+
+#define scan_esc(conf, p) (((IS_EOF((conf), (p)[1])) ? ((p) + 1) : ((p) + 2)))
+
+static char *eat_alpha_numeric(CONF *conf, char *p) {
+ for (;;) {
+ if (IS_ESC(conf, *p)) {
+ p = scan_esc(conf, p);
+ continue;
+ }
+ if (!IS_ALPHA_NUMERIC_PUNCT(conf, *p)) {
+ return p;
+ }
+ p++;
+ }
+}
+
+static char *scan_quote(CONF *conf, char *p) {
+ int q = *p;
+
+ p++;
+ while (!IS_EOF(conf, *p) && *p != q) {
+ if (IS_ESC(conf, *p)) {
+ p++;
+ if (IS_EOF(conf, *p)) {
+ return p;
+ }
+ }
+ p++;
+ }
+ if (*p == q) {
+ p++;
+ }
+ return p;
+}
+
+
+static char *scan_dquote(CONF *conf, char *p) {
+ int q = *p;
+
+ p++;
+ while (!(IS_EOF(conf, *p))) {
+ if (*p == q) {
+ if (*(p + 1) == q) {
+ p++;
+ } else {
+ break;
+ }
+ }
+ p++;
+ }
+ if (*p == q) {
+ p++;
+ }
+ return p;
+}
+
+static void clear_comments(CONF *conf, char *p) {
+ for (;;) {
+ if (IS_FCOMMENT(conf, *p)) {
+ *p = '\0';
+ return;
+ }
+ if (!IS_WS(conf, *p)) {
+ break;
+ }
+ p++;
+ }
+
+ for (;;) {
+ if (IS_COMMENT(conf, *p)) {
+ *p = '\0';
+ return;
+ }
+ if (IS_DQUOTE(conf, *p)) {
+ p = scan_dquote(conf, p);
+ continue;
+ }
+ if (IS_QUOTE(conf, *p)) {
+ p = scan_quote(conf, p);
+ continue;
+ }
+ if (IS_ESC(conf, *p)) {
+ p = scan_esc(conf, p);
+ continue;
+ }
+ if (IS_EOF(conf, *p)) {
+ return;
+ } else {
+ p++;
+ }
+ }
+}
+
+static int def_load_bio(CONF *conf, BIO *in, long *out_error_line) {
+ static const size_t CONFBUFSIZE = 512;
+ int bufnum = 0, i, ii;
+ BUF_MEM *buff = NULL;
+ char *s, *p, *end;
+ int again;
+ long eline = 0;
+ char btmp[DECIMAL_SIZE(eline) + 1];
+ CONF_VALUE *v = NULL, *tv;
+ CONF_VALUE *sv = NULL;
+ char *section = NULL, *buf;
+ char *start, *psection, *pname;
+
+ if ((buff = BUF_MEM_new()) == NULL) {
+ OPENSSL_PUT_ERROR(CONF, def_load_bio, ERR_R_BUF_LIB);
+ goto err;
+ }
+
+ section = (char *)OPENSSL_malloc(10);
+ if (section == NULL) {
+ OPENSSL_PUT_ERROR(CONF, def_load_bio, 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);
+ goto err;
+ }
+
+ bufnum = 0;
+ again = 0;
+ for (;;) {
+ if (!BUF_MEM_grow(buff, bufnum + CONFBUFSIZE)) {
+ OPENSSL_PUT_ERROR(CONF, def_load_bio, ERR_R_BUF_LIB);
+ goto err;
+ }
+ p = &(buff->data[bufnum]);
+ *p = '\0';
+ BIO_gets(in, p, CONFBUFSIZE - 1);
+ p[CONFBUFSIZE - 1] = '\0';
+ ii = i = strlen(p);
+ if (i == 0 && !again)
+ break;
+ again = 0;
+ while (i > 0) {
+ if ((p[i - 1] != '\r') && (p[i - 1] != '\n'))
+ break;
+ else
+ i--;
+ }
+ /* we removed some trailing stuff so there is a new
+ * line on the end. */
+ if (ii && i == ii)
+ again = 1; /* long line */
+ else {
+ p[i] = '\0';
+ eline++; /* another input line */
+ }
+
+ /* we now have a line with trailing \r\n removed */
+
+ /* i is the number of bytes */
+ bufnum += i;
+
+ v = NULL;
+ /* check for line continuation */
+ if (bufnum >= 1) {
+ /* If we have bytes and the last char '\\' and
+ * second last char is not '\\' */
+ p = &(buff->data[bufnum - 1]);
+ if (IS_ESC(conf, p[0]) && ((bufnum <= 1) || !IS_ESC(conf, p[-1]))) {
+ bufnum--;
+ again = 1;
+ }
+ }
+ if (again)
+ continue;
+ bufnum = 0;
+ buf = buff->data;
+
+ clear_comments(conf, buf);
+ s = eat_ws(conf, buf);
+ if (IS_EOF(conf, *s))
+ continue; /* blank line */
+ if (*s == '[') {
+ char *ss;
+
+ s++;
+ start = eat_ws(conf, s);
+ ss = start;
+ again:
+ end = eat_alpha_numeric(conf, ss);
+ p = eat_ws(conf, end);
+ if (*p != ']') {
+ if (*p != '\0') {
+ ss = p;
+ goto again;
+ }
+ OPENSSL_PUT_ERROR(CONF, def_load_bio, CONF_R_MISSING_CLOSE_SQUARE_BRACKET);
+ goto err;
+ }
+ *end = '\0';
+ if (!str_copy(conf, NULL, §ion, start))
+ goto err;
+ if ((sv = get_section(conf, section)) == NULL)
+ sv = NCONF_new_section(conf, section);
+ if (sv == NULL) {
+ OPENSSL_PUT_ERROR(CONF, def_load_bio, CONF_R_UNABLE_TO_CREATE_NEW_SECTION);
+ goto err;
+ }
+ continue;
+ } else {
+ pname = s;
+ psection = NULL;
+ end = eat_alpha_numeric(conf, s);
+ if ((end[0] == ':') && (end[1] == ':')) {
+ *end = '\0';
+ end += 2;
+ psection = pname;
+ pname = end;
+ end = eat_alpha_numeric(conf, end);
+ }
+ p = eat_ws(conf, end);
+ if (*p != '=') {
+ OPENSSL_PUT_ERROR(CONF, def_load_bio, CONF_R_MISSING_EQUAL_SIGN);
+ goto err;
+ }
+ *end = '\0';
+ p++;
+ start = eat_ws(conf, p);
+ while (!IS_EOF(conf, *p))
+ p++;
+ p--;
+ while ((p != start) && (IS_WS(conf, *p)))
+ p--;
+ p++;
+ *p = '\0';
+
+ if (!(v = (CONF_VALUE *)OPENSSL_malloc(sizeof(CONF_VALUE)))) {
+ OPENSSL_PUT_ERROR(CONF, def_load_bio, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if (psection == NULL)
+ psection = section;
+ v->name = (char *)OPENSSL_malloc(strlen(pname) + 1);
+ v->value = NULL;
+ if (v->name == NULL) {
+ OPENSSL_PUT_ERROR(CONF, def_load_bio, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ BUF_strlcpy(v->name, pname, strlen(pname) + 1);
+ if (!str_copy(conf, psection, &(v->value), start))
+ goto err;
+
+ if (strcmp(psection, section) != 0) {
+ if ((tv = get_section(conf, psection)) == NULL)
+ tv = NCONF_new_section(conf, psection);
+ if (tv == NULL) {
+ OPENSSL_PUT_ERROR(CONF, def_load_bio, 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);
+ goto err;
+ }
+ v = NULL;
+ }
+ }
+ if (buff != NULL)
+ BUF_MEM_free(buff);
+ if (section != NULL)
+ OPENSSL_free(section);
+ return 1;
+
+err:
+ if (buff != NULL)
+ BUF_MEM_free(buff);
+ if (section != NULL)
+ OPENSSL_free(section);
+ if (out_error_line != NULL)
+ *out_error_line = eline;
+ BIO_snprintf(btmp, sizeof btmp, "%ld", eline);
+ ERR_add_error_data(2, "line ", btmp);
+
+ if (v != NULL) {
+ if (v->name != NULL)
+ OPENSSL_free(v->name);
+ if (v->value != NULL)
+ OPENSSL_free(v->value);
+ if (v != NULL)
+ OPENSSL_free(v);
+ }
+ return 0;
+}
+
+int NCONF_load(CONF *conf, const char *filename, long *out_error_line) {
+ BIO *in = BIO_new_file(filename, "rb");
+ int ret;
+
+ if (in == NULL) {
+ OPENSSL_PUT_ERROR(CONF, NCONF_load, ERR_R_SYS_LIB);
+ return 0;
+ }
+
+ ret = def_load_bio(conf, in, out_error_line);
+ BIO_free(in);
+
+ return ret;
+}
+
+int CONF_parse_list(const char *list, char sep, int remove_whitespace,
+ int (*list_cb)(const char *elem, int len, void *usr),
+ void *arg) {
+ int ret;
+ const char *lstart, *tmpend, *p;
+
+ if (list == NULL) {
+ OPENSSL_PUT_ERROR(CONF, CONF_parse_list, CONF_R_LIST_CANNOT_BE_NULL);
+ return 0;
+ }
+
+ lstart = list;
+ for (;;) {
+ if (remove_whitespace) {
+ while (*lstart && isspace((unsigned char)*lstart))
+ lstart++;
+ }
+ p = strchr(lstart, sep);
+ if (p == lstart || !*lstart)
+ ret = list_cb(NULL, 0, arg);
+ else {
+ if (p)
+ tmpend = p - 1;
+ else
+ tmpend = lstart + strlen(lstart) - 1;
+ if (remove_whitespace) {
+ while (isspace((unsigned char)*tmpend))
+ tmpend--;
+ }
+ ret = list_cb(lstart, tmpend - lstart + 1, arg);
+ }
+ if (ret <= 0)
+ return ret;
+ if (p == NULL)
+ return 1;
+ lstart = p + 1;
+ }
+}
diff --git a/crypto/conf/conf.h b/crypto/conf/conf.h
new file mode 100644
index 0000000..51c5525
--- /dev/null
+++ b/crypto/conf/conf.h
@@ -0,0 +1,143 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_CONF_H
+#define OPENSSL_HEADER_CONF_H
+
+#include <openssl/base.h>
+
+#include <openssl/stack.h>
+#include <openssl/lhash.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* Config files look like:
+ *
+ * # Comment
+ *
+ * # This key is in the default section.
+ * key=value
+ *
+ * [section_name]
+ * key2=value2
+ *
+ * Config files are representated by a |CONF|. */
+
+typedef struct {
+ char *section;
+ char *name;
+ char *value;
+} CONF_VALUE;
+
+struct conf_st {
+ LHASH_OF(CONF_VALUE) *data;
+};
+
+
+/* NCONF_new returns a fresh, empty |CONF|, or NULL on error. */
+CONF *NCONF_new();
+
+/* NCONF_free frees all the data owned by |conf| and then |conf| itself. */
+void NCONF_free(CONF *conf);
+
+/* NCONF_load parses the file named |filename| and adds the values found to
+ * |conf|. It returns one on success and zero on error. In the event of an
+ * error, if |out_error_line| is not NULL, |*out_error_line| is set to the
+ * number of the line that contained the error. */
+int NCONF_load(CONF *conf, const char *filename, long *out_error_line);
+
+/* NCONF_get_section returns a stack of values for a given section in |conf|.
+ * If |section| is NULL, the default section is returned. It returns NULL on
+ * error. */
+STACK_OF(CONF_VALUE) *NCONF_get_section(const CONF *conf, const char *section);
+
+/* NCONF_get_string returns the value of the key |name|, in section |section|.
+ * The |section| argument may be NULL to indicate the default section. It
+ * returns the value or NULL on error. */
+const char *NCONF_get_string(const CONF *conf, const char *section,
+ const char *name);
+
+
+/* Utility functions */
+
+/* CONF_parse_list takes a list separated by 'sep' and calls |list_cb| giving
+ * the start and length of each member, optionally stripping leading and
+ * trailing whitespace. This can be used to parse comma separated lists for
+ * example. If |list_cb| returns <= 0, then the iteration is halted and that
+ * value is returned immediately. Otherwise it returns one. */
+int CONF_parse_list(const char *list, char sep, int remove_whitespace,
+ int (*list_cb)(const char *elem, int len, void *usr),
+ void *arg);
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#define CONF_F_CONF_parse_list 100
+#define CONF_F_str_copy 101
+#define CONF_F_def_load_bio 102
+#define CONF_F_NCONF_load 103
+#define CONF_R_MISSING_EQUAL_SIGN 100
+#define CONF_R_LIST_CANNOT_BE_NULL 101
+#define CONF_R_NO_CLOSE_BRACE 102
+#define CONF_R_VARIABLE_HAS_NO_VALUE 103
+#define CONF_R_UNABLE_TO_CREATE_NEW_SECTION 104
+#define CONF_R_MISSING_CLOSE_SQUARE_BRACKET 105
+
+#endif /* OPENSSL_HEADER_THREAD_H */
diff --git a/crypto/conf/conf_def.h b/crypto/conf/conf_def.h
new file mode 100644
index 0000000..2fc035b
--- /dev/null
+++ b/crypto/conf/conf_def.h
@@ -0,0 +1,127 @@
+/* crypto/conf/conf_def.h */
+/* 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.]
+ */
+
+/* THIS FILE WAS AUTOMAGICALLY GENERATED!
+ Please modify and use keysets.pl to regenerate it. */
+
+#define CONF_NUMBER 1
+#define CONF_UPPER 2
+#define CONF_LOWER 4
+#define CONF_UNDER 256
+#define CONF_PUNCTUATION 512
+#define CONF_WS 16
+#define CONF_ESC 32
+#define CONF_QUOTE 64
+#define CONF_DQUOTE 1024
+#define CONF_COMMENT 128
+#define CONF_FCOMMENT 2048
+#define CONF_EOF 8
+#define CONF_HIGHBIT 4096
+#define CONF_ALPHA (CONF_UPPER|CONF_LOWER)
+#define CONF_ALPHA_NUMERIC (CONF_ALPHA|CONF_NUMBER|CONF_UNDER)
+#define CONF_ALPHA_NUMERIC_PUNCT (CONF_ALPHA|CONF_NUMBER|CONF_UNDER| \
+ CONF_PUNCTUATION)
+
+#define KEYTYPES(c) CONF_type_default
+#define IS_COMMENT(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_COMMENT)
+#define IS_FCOMMENT(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_FCOMMENT)
+#define IS_EOF(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_EOF)
+#define IS_ESC(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_ESC)
+#define IS_NUMBER(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_NUMBER)
+#define IS_WS(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_WS)
+#define IS_ALPHA_NUMERIC(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_ALPHA_NUMERIC)
+#define IS_ALPHA_NUMERIC_PUNCT(c,a) \
+ (KEYTYPES(c)[(a)&0xff]&CONF_ALPHA_NUMERIC_PUNCT)
+#define IS_QUOTE(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_QUOTE)
+#define IS_DQUOTE(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_DQUOTE)
+#define IS_HIGHBIT(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_HIGHBIT)
+
+static unsigned short CONF_type_default[256]={
+ 0x0008,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+ 0x0000,0x0010,0x0010,0x0000,0x0000,0x0010,0x0000,0x0000,
+ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+ 0x0010,0x0200,0x0040,0x0080,0x0000,0x0200,0x0200,0x0040,
+ 0x0000,0x0000,0x0200,0x0200,0x0200,0x0200,0x0200,0x0200,
+ 0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,
+ 0x0001,0x0001,0x0000,0x0200,0x0000,0x0000,0x0000,0x0200,
+ 0x0200,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,
+ 0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,
+ 0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,
+ 0x0002,0x0002,0x0002,0x0000,0x0020,0x0000,0x0200,0x0100,
+ 0x0040,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,
+ 0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,
+ 0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,
+ 0x0004,0x0004,0x0004,0x0000,0x0200,0x0000,0x0200,0x0000,
+ 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,
+ 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,
+ 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,
+ 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,
+ 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,
+ 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,
+ 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,
+ 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,
+ 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,
+ 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,
+ 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,
+ 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,
+ 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,
+ 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,
+ 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,
+ 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,
+ };
diff --git a/crypto/conf/conf_error.c b/crypto/conf/conf_error.c
new file mode 100644
index 0000000..b739d19
--- /dev/null
+++ b/crypto/conf/conf_error.c
@@ -0,0 +1,31 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/err.h>
+
+#include "conf.h"
+
+const ERR_STRING_DATA CONF_error_string_data[] = {
+ {ERR_PACK(ERR_LIB_CONF, CONF_F_CONF_parse_list, 0), "CONF_parse_list"},
+ {ERR_PACK(ERR_LIB_CONF, CONF_F_NCONF_load, 0), "NCONF_load"},
+ {ERR_PACK(ERR_LIB_CONF, CONF_F_def_load_bio, 0), "def_load_bio"},
+ {ERR_PACK(ERR_LIB_CONF, CONF_F_str_copy, 0), "str_copy"},
+ {ERR_PACK(ERR_LIB_CONF, 0, CONF_R_LIST_CANNOT_BE_NULL), "LIST_CANNOT_BE_NULL"},
+ {ERR_PACK(ERR_LIB_CONF, 0, CONF_R_MISSING_CLOSE_SQUARE_BRACKET), "MISSING_CLOSE_SQUARE_BRACKET"},
+ {ERR_PACK(ERR_LIB_CONF, 0, CONF_R_MISSING_EQUAL_SIGN), "MISSING_EQUAL_SIGN"},
+ {ERR_PACK(ERR_LIB_CONF, 0, CONF_R_NO_CLOSE_BRACE), "NO_CLOSE_BRACE"},
+ {ERR_PACK(ERR_LIB_CONF, 0, CONF_R_UNABLE_TO_CREATE_NEW_SECTION), "UNABLE_TO_CREATE_NEW_SECTION"},
+ {ERR_PACK(ERR_LIB_CONF, 0, CONF_R_VARIABLE_HAS_NO_VALUE), "VARIABLE_HAS_NO_VALUE"},
+ {0, NULL},
+};
diff --git a/crypto/cpu-arm.c b/crypto/cpu-arm.c
new file mode 100644
index 0000000..8b97fc1
--- /dev/null
+++ b/crypto/cpu-arm.c
@@ -0,0 +1,84 @@
+/* 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/cpu.h>
+
+#if defined(OPENSSL_ARM)
+
+#include <stdio.h>
+#include <inttypes.h>
+
+#include "arm_arch.h"
+
+#if defined(__ARM_NEON__)
+uint32_t OPENSSL_armcap_P = ARMV7_NEON;
+#else
+uint32_t OPENSSL_armcap_P = ARMV7_NEON;
+#endif
+
+char CRYPTO_is_NEON_capable() {
+ return (OPENSSL_armcap_P & ARMV7_NEON) != 0;
+}
+
+void CRYPTO_set_NEON_capable(char neon_capable) {
+ if (neon_capable) {
+ OPENSSL_armcap_P |= ARMV7_NEON;
+ } else {
+ OPENSSL_armcap_P &= ~ARMV7_NEON;
+ }
+}
+
+#endif /* defined(OPENSSL_ARM) */
diff --git a/crypto/cpu-intel.c b/crypto/cpu-intel.c
new file mode 100644
index 0000000..cda80ea
--- /dev/null
+++ b/crypto/cpu-intel.c
@@ -0,0 +1,139 @@
+/* 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.] */
+
+#if !defined(__STDC_FORMAT_MACROS)
+#define __STDC_FORMAT_MACROS
+#endif
+
+#include <openssl/cpu.h>
+
+
+#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64)
+
+#include <stdio.h>
+#include <inttypes.h>
+
+uint32_t OPENSSL_ia32cap_P[4];
+
+/* OPENSSL_ia32_cpuid is defined in cpu-x86_64-asm.pl. */
+extern uint64_t OPENSSL_ia32_cpuid(uint32_t*);
+
+#if !defined(OPENSSL_WINDOWS)
+void OPENSSL_cpuid_setup(void) __attribute__ ((constructor));
+#endif
+
+/* handle_cpu_env applies the value from |in| to the CPUID values in |out[0]|
+ * and |out[1]|. See the comment in |OPENSSL_cpuid_setup| about this. */
+static void handle_cpu_env(uint32_t *out, const char *in) {
+ const int invert = in[0] == '~';
+ uint64_t v;
+
+ if (!sscanf(in + invert, "%" PRIi64, &v)) {
+ return;
+ }
+
+ if (invert) {
+ out[0] &= ~v;
+ out[1] &= ~(v >> 32);
+ } else {
+ out[0] = v;
+ out[1] = v >> 32;
+ }
+}
+
+#if defined(OPENSSL_WINDOWS)
+#pragma section(".CRT$XCU", read)
+void __cdecl OPENSSL_cpuid_setup(void);
+__declspec(allocate(".CRT$XCU")) void(*cpuid_constructor)(void) = OPENSSL_cpuid_setup;
+void __cdecl OPENSSL_cpuid_setup(void) {
+#else
+void OPENSSL_cpuid_setup(void) {
+#endif
+ const char *env1, *env2;
+
+#if defined(OPENSSL_X86_64)
+ 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;
+ }
+
+ /* OPENSSL_ia32cap can contain zero, one or two values, separated with a ':'.
+ * Each value is a 64-bit, unsigned value which may start with "0x" to
+ * indicate a hex value. Prior to the 64-bit value, a '~' may be given.
+ *
+ * If '~' isn't present, then the value is taken as the result of the CPUID.
+ * Otherwise the value is inverted and ANDed with the probed CPUID result.
+ *
+ * The first value determines OPENSSL_ia32cap_P[0] and [1]. The second [2]
+ * and [3]. */
+
+ handle_cpu_env(&OPENSSL_ia32cap_P[0], env1);
+ env2 = strchr(env1, ':');
+ if (env2 != NULL) {
+ handle_cpu_env(&OPENSSL_ia32cap_P[2], env2 + 1);
+ }
+}
+
+#endif /* OPENSSL_X86 || OPENSSL_X86_64 */
diff --git a/crypto/cpu-x86-asm.pl b/crypto/cpu-x86-asm.pl
new file mode 100644
index 0000000..151493a
--- /dev/null
+++ b/crypto/cpu-x86-asm.pl
@@ -0,0 +1,372 @@
+#!/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
+ &and (&HB("eax"),15); # familiy ID
+ &cmp (&HB("eax"),15); # P4?
+ &jne (&label("notintel"));
+ &or ("edx",1<<20); # set reserved bit#20 to engage RC4_CHAR
+&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_cleanse");
+ &mov ("edx",&wparam(0));
+ &mov ("ecx",&wparam(1));
+ &xor ("eax","eax");
+ &cmp ("ecx",7);
+ &jae (&label("lot"));
+ &cmp ("ecx",0);
+ &je (&label("ret"));
+&set_label("little");
+ &mov (&BP(0,"edx"),"al");
+ &sub ("ecx",1);
+ &lea ("edx",&DWP(1,"edx"));
+ &jnz (&label("little"));
+&set_label("ret");
+ &ret ();
+
+&set_label("lot",16);
+ &test ("edx",3);
+ &jz (&label("aligned"));
+ &mov (&BP(0,"edx"),"al");
+ &lea ("ecx",&DWP(-1,"ecx"));
+ &lea ("edx",&DWP(1,"edx"));
+ &jmp (&label("lot"));
+&set_label("aligned");
+ &mov (&DWP(0,"edx"),"eax");
+ &lea ("ecx",&DWP(-4,"ecx"));
+ &test ("ecx",-4);
+ &lea ("edx",&DWP(4,"edx"));
+ &jnz (&label("aligned"));
+ &cmp ("ecx",0);
+ &jne (&label("little"));
+ &ret ();
+&function_end_B("OPENSSL_cleanse");
+
+&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/crypto/cpu-x86_64-asm.pl b/crypto/cpu-x86_64-asm.pl
new file mode 100644
index 0000000..59cfd18
--- /dev/null
+++ b/crypto/cpu-x86_64-asm.pl
@@ -0,0 +1,167 @@
+#!/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
+ and \$15,%ah
+ cmp \$15,%ah # examine Family ID
+ jne .Lnotintel
+ or \$0x00100000,%edx # set reserved bit#20 to engage RC4_CHAR
+.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/crypto/cpu.h b/crypto/cpu.h
new file mode 100644
index 0000000..02f6da2
--- /dev/null
+++ b/crypto/cpu.h
@@ -0,0 +1,103 @@
+/* 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.]
+ *
+ * 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_CPU_H
+#define OPENSSL_HEADER_CPU_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64)
+/* OPENSSL_ia32cap_P contains the Intel CPUID bits when running on an x86 or
+ * x86-64 system.
+ *
+ * Index 0:
+ * EDX for CPUID where EAX = 1
+ * Bit 30 is used to indicate an Intel CPU
+ * Bit 20 is used to indicate RC4_CHAR
+ * Index 1:
+ * ECX for CPUID where EAX = 1
+ * Index 2:
+ * EBX for CPUID where EAX = 7 */
+extern uint32_t OPENSSL_ia32cap_P[4];
+#endif
+
+#if defined(OPENSSL_ARM)
+/* CRYPTO_is_NEON_capable returns true if the current CPU has a NEON unit. Note
+ * that |OPENSSL_armcap_P| also exists and contains the same information in a
+ * form that's easier for assembly to use. */
+char CRYPTO_is_NEON_capable();
+
+/* CRYPTO_set_NEON_capable sets the return value of |CRYPTO_is_NEON_capable|.
+ * By default, unless the code was compiled with |-mfpu=neon|, NEON is assumed
+ * not to be present. It is not autodetected. */
+void CRYPTO_set_NEON_capable(char neon_capable);
+#endif /* OPENSSL_ARM */
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_CPU_H */
diff --git a/crypto/crypto_error.c b/crypto/crypto_error.c
new file mode 100644
index 0000000..483bbe3
--- /dev/null
+++ b/crypto/crypto_error.c
@@ -0,0 +1,25 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/err.h>
+
+#include "crypto_error.h"
+
+const ERR_STRING_DATA CRYPTO_error_string_data[] = {
+ {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_CRYPTO_set_ex_data, 0), "CRYPTO_set_ex_data"},
+ {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_get_class, 0), "get_class"},
+ {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_get_func_pointers, 0), "get_func_pointers"},
+ {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_get_new_index, 0), "get_new_index"},
+ {0, NULL},
+};
diff --git a/crypto/crypto_error.h b/crypto/crypto_error.h
new file mode 100644
index 0000000..fd3d607
--- /dev/null
+++ b/crypto/crypto_error.h
@@ -0,0 +1,5 @@
+#define CRYPTO_F_CRYPTO_set_ex_data 100
+#define CRYPTO_F_get_class 101
+#define CRYPTO_F_get_new_index 102
+#define CRYPTO_F_get_func_pointers 103
+
diff --git a/crypto/des/CMakeLists.txt b/crypto/des/CMakeLists.txt
new file mode 100644
index 0000000..7ece452
--- /dev/null
+++ b/crypto/des/CMakeLists.txt
@@ -0,0 +1,9 @@
+include_directories(. .. ../../include)
+
+add_library(
+ des
+
+ OBJECT
+
+ des.c
+)
diff --git a/crypto/des/des.c b/crypto/des/des.c
new file mode 100644
index 0000000..ca87ee3
--- /dev/null
+++ b/crypto/des/des.c
@@ -0,0 +1,714 @@
+/* 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/des.h>
+
+#include "internal.h"
+
+
+static const uint32_t des_skb[8][64] = {
+ {/* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
+ 0x00000000L, 0x00000010L, 0x20000000L, 0x20000010L, 0x00010000L,
+ 0x00010010L, 0x20010000L, 0x20010010L, 0x00000800L, 0x00000810L,
+ 0x20000800L, 0x20000810L, 0x00010800L, 0x00010810L, 0x20010800L,
+ 0x20010810L, 0x00000020L, 0x00000030L, 0x20000020L, 0x20000030L,
+ 0x00010020L, 0x00010030L, 0x20010020L, 0x20010030L, 0x00000820L,
+ 0x00000830L, 0x20000820L, 0x20000830L, 0x00010820L, 0x00010830L,
+ 0x20010820L, 0x20010830L, 0x00080000L, 0x00080010L, 0x20080000L,
+ 0x20080010L, 0x00090000L, 0x00090010L, 0x20090000L, 0x20090010L,
+ 0x00080800L, 0x00080810L, 0x20080800L, 0x20080810L, 0x00090800L,
+ 0x00090810L, 0x20090800L, 0x20090810L, 0x00080020L, 0x00080030L,
+ 0x20080020L, 0x20080030L, 0x00090020L, 0x00090030L, 0x20090020L,
+ 0x20090030L, 0x00080820L, 0x00080830L, 0x20080820L, 0x20080830L,
+ 0x00090820L, 0x00090830L, 0x20090820L, 0x20090830L, },
+ {/* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 */
+ 0x00000000L, 0x02000000L, 0x00002000L, 0x02002000L, 0x00200000L,
+ 0x02200000L, 0x00202000L, 0x02202000L, 0x00000004L, 0x02000004L,
+ 0x00002004L, 0x02002004L, 0x00200004L, 0x02200004L, 0x00202004L,
+ 0x02202004L, 0x00000400L, 0x02000400L, 0x00002400L, 0x02002400L,
+ 0x00200400L, 0x02200400L, 0x00202400L, 0x02202400L, 0x00000404L,
+ 0x02000404L, 0x00002404L, 0x02002404L, 0x00200404L, 0x02200404L,
+ 0x00202404L, 0x02202404L, 0x10000000L, 0x12000000L, 0x10002000L,
+ 0x12002000L, 0x10200000L, 0x12200000L, 0x10202000L, 0x12202000L,
+ 0x10000004L, 0x12000004L, 0x10002004L, 0x12002004L, 0x10200004L,
+ 0x12200004L, 0x10202004L, 0x12202004L, 0x10000400L, 0x12000400L,
+ 0x10002400L, 0x12002400L, 0x10200400L, 0x12200400L, 0x10202400L,
+ 0x12202400L, 0x10000404L, 0x12000404L, 0x10002404L, 0x12002404L,
+ 0x10200404L, 0x12200404L, 0x10202404L, 0x12202404L, },
+ {/* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 */
+ 0x00000000L, 0x00000001L, 0x00040000L, 0x00040001L, 0x01000000L,
+ 0x01000001L, 0x01040000L, 0x01040001L, 0x00000002L, 0x00000003L,
+ 0x00040002L, 0x00040003L, 0x01000002L, 0x01000003L, 0x01040002L,
+ 0x01040003L, 0x00000200L, 0x00000201L, 0x00040200L, 0x00040201L,
+ 0x01000200L, 0x01000201L, 0x01040200L, 0x01040201L, 0x00000202L,
+ 0x00000203L, 0x00040202L, 0x00040203L, 0x01000202L, 0x01000203L,
+ 0x01040202L, 0x01040203L, 0x08000000L, 0x08000001L, 0x08040000L,
+ 0x08040001L, 0x09000000L, 0x09000001L, 0x09040000L, 0x09040001L,
+ 0x08000002L, 0x08000003L, 0x08040002L, 0x08040003L, 0x09000002L,
+ 0x09000003L, 0x09040002L, 0x09040003L, 0x08000200L, 0x08000201L,
+ 0x08040200L, 0x08040201L, 0x09000200L, 0x09000201L, 0x09040200L,
+ 0x09040201L, 0x08000202L, 0x08000203L, 0x08040202L, 0x08040203L,
+ 0x09000202L, 0x09000203L, 0x09040202L, 0x09040203L, },
+ {/* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 */
+ 0x00000000L, 0x00100000L, 0x00000100L, 0x00100100L, 0x00000008L,
+ 0x00100008L, 0x00000108L, 0x00100108L, 0x00001000L, 0x00101000L,
+ 0x00001100L, 0x00101100L, 0x00001008L, 0x00101008L, 0x00001108L,
+ 0x00101108L, 0x04000000L, 0x04100000L, 0x04000100L, 0x04100100L,
+ 0x04000008L, 0x04100008L, 0x04000108L, 0x04100108L, 0x04001000L,
+ 0x04101000L, 0x04001100L, 0x04101100L, 0x04001008L, 0x04101008L,
+ 0x04001108L, 0x04101108L, 0x00020000L, 0x00120000L, 0x00020100L,
+ 0x00120100L, 0x00020008L, 0x00120008L, 0x00020108L, 0x00120108L,
+ 0x00021000L, 0x00121000L, 0x00021100L, 0x00121100L, 0x00021008L,
+ 0x00121008L, 0x00021108L, 0x00121108L, 0x04020000L, 0x04120000L,
+ 0x04020100L, 0x04120100L, 0x04020008L, 0x04120008L, 0x04020108L,
+ 0x04120108L, 0x04021000L, 0x04121000L, 0x04021100L, 0x04121100L,
+ 0x04021008L, 0x04121008L, 0x04021108L, 0x04121108L, },
+ {/* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
+ 0x00000000L, 0x10000000L, 0x00010000L, 0x10010000L, 0x00000004L,
+ 0x10000004L, 0x00010004L, 0x10010004L, 0x20000000L, 0x30000000L,
+ 0x20010000L, 0x30010000L, 0x20000004L, 0x30000004L, 0x20010004L,
+ 0x30010004L, 0x00100000L, 0x10100000L, 0x00110000L, 0x10110000L,
+ 0x00100004L, 0x10100004L, 0x00110004L, 0x10110004L, 0x20100000L,
+ 0x30100000L, 0x20110000L, 0x30110000L, 0x20100004L, 0x30100004L,
+ 0x20110004L, 0x30110004L, 0x00001000L, 0x10001000L, 0x00011000L,
+ 0x10011000L, 0x00001004L, 0x10001004L, 0x00011004L, 0x10011004L,
+ 0x20001000L, 0x30001000L, 0x20011000L, 0x30011000L, 0x20001004L,
+ 0x30001004L, 0x20011004L, 0x30011004L, 0x00101000L, 0x10101000L,
+ 0x00111000L, 0x10111000L, 0x00101004L, 0x10101004L, 0x00111004L,
+ 0x10111004L, 0x20101000L, 0x30101000L, 0x20111000L, 0x30111000L,
+ 0x20101004L, 0x30101004L, 0x20111004L, 0x30111004L, },
+ {/* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 */
+ 0x00000000L, 0x08000000L, 0x00000008L, 0x08000008L, 0x00000400L,
+ 0x08000400L, 0x00000408L, 0x08000408L, 0x00020000L, 0x08020000L,
+ 0x00020008L, 0x08020008L, 0x00020400L, 0x08020400L, 0x00020408L,
+ 0x08020408L, 0x00000001L, 0x08000001L, 0x00000009L, 0x08000009L,
+ 0x00000401L, 0x08000401L, 0x00000409L, 0x08000409L, 0x00020001L,
+ 0x08020001L, 0x00020009L, 0x08020009L, 0x00020401L, 0x08020401L,
+ 0x00020409L, 0x08020409L, 0x02000000L, 0x0A000000L, 0x02000008L,
+ 0x0A000008L, 0x02000400L, 0x0A000400L, 0x02000408L, 0x0A000408L,
+ 0x02020000L, 0x0A020000L, 0x02020008L, 0x0A020008L, 0x02020400L,
+ 0x0A020400L, 0x02020408L, 0x0A020408L, 0x02000001L, 0x0A000001L,
+ 0x02000009L, 0x0A000009L, 0x02000401L, 0x0A000401L, 0x02000409L,
+ 0x0A000409L, 0x02020001L, 0x0A020001L, 0x02020009L, 0x0A020009L,
+ 0x02020401L, 0x0A020401L, 0x02020409L, 0x0A020409L, },
+ {/* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 */
+ 0x00000000L, 0x00000100L, 0x00080000L, 0x00080100L, 0x01000000L,
+ 0x01000100L, 0x01080000L, 0x01080100L, 0x00000010L, 0x00000110L,
+ 0x00080010L, 0x00080110L, 0x01000010L, 0x01000110L, 0x01080010L,
+ 0x01080110L, 0x00200000L, 0x00200100L, 0x00280000L, 0x00280100L,
+ 0x01200000L, 0x01200100L, 0x01280000L, 0x01280100L, 0x00200010L,
+ 0x00200110L, 0x00280010L, 0x00280110L, 0x01200010L, 0x01200110L,
+ 0x01280010L, 0x01280110L, 0x00000200L, 0x00000300L, 0x00080200L,
+ 0x00080300L, 0x01000200L, 0x01000300L, 0x01080200L, 0x01080300L,
+ 0x00000210L, 0x00000310L, 0x00080210L, 0x00080310L, 0x01000210L,
+ 0x01000310L, 0x01080210L, 0x01080310L, 0x00200200L, 0x00200300L,
+ 0x00280200L, 0x00280300L, 0x01200200L, 0x01200300L, 0x01280200L,
+ 0x01280300L, 0x00200210L, 0x00200310L, 0x00280210L, 0x00280310L,
+ 0x01200210L, 0x01200310L, 0x01280210L, 0x01280310L, },
+ {/* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 */
+ 0x00000000L, 0x04000000L, 0x00040000L, 0x04040000L, 0x00000002L,
+ 0x04000002L, 0x00040002L, 0x04040002L, 0x00002000L, 0x04002000L,
+ 0x00042000L, 0x04042000L, 0x00002002L, 0x04002002L, 0x00042002L,
+ 0x04042002L, 0x00000020L, 0x04000020L, 0x00040020L, 0x04040020L,
+ 0x00000022L, 0x04000022L, 0x00040022L, 0x04040022L, 0x00002020L,
+ 0x04002020L, 0x00042020L, 0x04042020L, 0x00002022L, 0x04002022L,
+ 0x00042022L, 0x04042022L, 0x00000800L, 0x04000800L, 0x00040800L,
+ 0x04040800L, 0x00000802L, 0x04000802L, 0x00040802L, 0x04040802L,
+ 0x00002800L, 0x04002800L, 0x00042800L, 0x04042800L, 0x00002802L,
+ 0x04002802L, 0x00042802L, 0x04042802L, 0x00000820L, 0x04000820L,
+ 0x00040820L, 0x04040820L, 0x00000822L, 0x04000822L, 0x00040822L,
+ 0x04040822L, 0x00002820L, 0x04002820L, 0x00042820L, 0x04042820L,
+ 0x00002822L, 0x04002822L, 0x00042822L, 0x04042822L, }};
+
+static const uint32_t DES_SPtrans[8][64] = {
+ {/* nibble 0 */
+ 0x02080800L, 0x00080000L, 0x02000002L, 0x02080802L, 0x02000000L,
+ 0x00080802L, 0x00080002L, 0x02000002L, 0x00080802L, 0x02080800L,
+ 0x02080000L, 0x00000802L, 0x02000802L, 0x02000000L, 0x00000000L,
+ 0x00080002L, 0x00080000L, 0x00000002L, 0x02000800L, 0x00080800L,
+ 0x02080802L, 0x02080000L, 0x00000802L, 0x02000800L, 0x00000002L,
+ 0x00000800L, 0x00080800L, 0x02080002L, 0x00000800L, 0x02000802L,
+ 0x02080002L, 0x00000000L, 0x00000000L, 0x02080802L, 0x02000800L,
+ 0x00080002L, 0x02080800L, 0x00080000L, 0x00000802L, 0x02000800L,
+ 0x02080002L, 0x00000800L, 0x00080800L, 0x02000002L, 0x00080802L,
+ 0x00000002L, 0x02000002L, 0x02080000L, 0x02080802L, 0x00080800L,
+ 0x02080000L, 0x02000802L, 0x02000000L, 0x00000802L, 0x00080002L,
+ 0x00000000L, 0x00080000L, 0x02000000L, 0x02000802L, 0x02080800L,
+ 0x00000002L, 0x02080002L, 0x00000800L, 0x00080802L, },
+ {/* nibble 1 */
+ 0x40108010L, 0x00000000L, 0x00108000L, 0x40100000L, 0x40000010L,
+ 0x00008010L, 0x40008000L, 0x00108000L, 0x00008000L, 0x40100010L,
+ 0x00000010L, 0x40008000L, 0x00100010L, 0x40108000L, 0x40100000L,
+ 0x00000010L, 0x00100000L, 0x40008010L, 0x40100010L, 0x00008000L,
+ 0x00108010L, 0x40000000L, 0x00000000L, 0x00100010L, 0x40008010L,
+ 0x00108010L, 0x40108000L, 0x40000010L, 0x40000000L, 0x00100000L,
+ 0x00008010L, 0x40108010L, 0x00100010L, 0x40108000L, 0x40008000L,
+ 0x00108010L, 0x40108010L, 0x00100010L, 0x40000010L, 0x00000000L,
+ 0x40000000L, 0x00008010L, 0x00100000L, 0x40100010L, 0x00008000L,
+ 0x40000000L, 0x00108010L, 0x40008010L, 0x40108000L, 0x00008000L,
+ 0x00000000L, 0x40000010L, 0x00000010L, 0x40108010L, 0x00108000L,
+ 0x40100000L, 0x40100010L, 0x00100000L, 0x00008010L, 0x40008000L,
+ 0x40008010L, 0x00000010L, 0x40100000L, 0x00108000L, },
+ {/* nibble 2 */
+ 0x04000001L, 0x04040100L, 0x00000100L, 0x04000101L, 0x00040001L,
+ 0x04000000L, 0x04000101L, 0x00040100L, 0x04000100L, 0x00040000L,
+ 0x04040000L, 0x00000001L, 0x04040101L, 0x00000101L, 0x00000001L,
+ 0x04040001L, 0x00000000L, 0x00040001L, 0x04040100L, 0x00000100L,
+ 0x00000101L, 0x04040101L, 0x00040000L, 0x04000001L, 0x04040001L,
+ 0x04000100L, 0x00040101L, 0x04040000L, 0x00040100L, 0x00000000L,
+ 0x04000000L, 0x00040101L, 0x04040100L, 0x00000100L, 0x00000001L,
+ 0x00040000L, 0x00000101L, 0x00040001L, 0x04040000L, 0x04000101L,
+ 0x00000000L, 0x04040100L, 0x00040100L, 0x04040001L, 0x00040001L,
+ 0x04000000L, 0x04040101L, 0x00000001L, 0x00040101L, 0x04000001L,
+ 0x04000000L, 0x04040101L, 0x00040000L, 0x04000100L, 0x04000101L,
+ 0x00040100L, 0x04000100L, 0x00000000L, 0x04040001L, 0x00000101L,
+ 0x04000001L, 0x00040101L, 0x00000100L, 0x04040000L, },
+ {/* nibble 3 */
+ 0x00401008L, 0x10001000L, 0x00000008L, 0x10401008L, 0x00000000L,
+ 0x10400000L, 0x10001008L, 0x00400008L, 0x10401000L, 0x10000008L,
+ 0x10000000L, 0x00001008L, 0x10000008L, 0x00401008L, 0x00400000L,
+ 0x10000000L, 0x10400008L, 0x00401000L, 0x00001000L, 0x00000008L,
+ 0x00401000L, 0x10001008L, 0x10400000L, 0x00001000L, 0x00001008L,
+ 0x00000000L, 0x00400008L, 0x10401000L, 0x10001000L, 0x10400008L,
+ 0x10401008L, 0x00400000L, 0x10400008L, 0x00001008L, 0x00400000L,
+ 0x10000008L, 0x00401000L, 0x10001000L, 0x00000008L, 0x10400000L,
+ 0x10001008L, 0x00000000L, 0x00001000L, 0x00400008L, 0x00000000L,
+ 0x10400008L, 0x10401000L, 0x00001000L, 0x10000000L, 0x10401008L,
+ 0x00401008L, 0x00400000L, 0x10401008L, 0x00000008L, 0x10001000L,
+ 0x00401008L, 0x00400008L, 0x00401000L, 0x10400000L, 0x10001008L,
+ 0x00001008L, 0x10000000L, 0x10000008L, 0x10401000L, },
+ {/* nibble 4 */
+ 0x08000000L, 0x00010000L, 0x00000400L, 0x08010420L, 0x08010020L,
+ 0x08000400L, 0x00010420L, 0x08010000L, 0x00010000L, 0x00000020L,
+ 0x08000020L, 0x00010400L, 0x08000420L, 0x08010020L, 0x08010400L,
+ 0x00000000L, 0x00010400L, 0x08000000L, 0x00010020L, 0x00000420L,
+ 0x08000400L, 0x00010420L, 0x00000000L, 0x08000020L, 0x00000020L,
+ 0x08000420L, 0x08010420L, 0x00010020L, 0x08010000L, 0x00000400L,
+ 0x00000420L, 0x08010400L, 0x08010400L, 0x08000420L, 0x00010020L,
+ 0x08010000L, 0x00010000L, 0x00000020L, 0x08000020L, 0x08000400L,
+ 0x08000000L, 0x00010400L, 0x08010420L, 0x00000000L, 0x00010420L,
+ 0x08000000L, 0x00000400L, 0x00010020L, 0x08000420L, 0x00000400L,
+ 0x00000000L, 0x08010420L, 0x08010020L, 0x08010400L, 0x00000420L,
+ 0x00010000L, 0x00010400L, 0x08010020L, 0x08000400L, 0x00000420L,
+ 0x00000020L, 0x00010420L, 0x08010000L, 0x08000020L, },
+ {/* nibble 5 */
+ 0x80000040L, 0x00200040L, 0x00000000L, 0x80202000L, 0x00200040L,
+ 0x00002000L, 0x80002040L, 0x00200000L, 0x00002040L, 0x80202040L,
+ 0x00202000L, 0x80000000L, 0x80002000L, 0x80000040L, 0x80200000L,
+ 0x00202040L, 0x00200000L, 0x80002040L, 0x80200040L, 0x00000000L,
+ 0x00002000L, 0x00000040L, 0x80202000L, 0x80200040L, 0x80202040L,
+ 0x80200000L, 0x80000000L, 0x00002040L, 0x00000040L, 0x00202000L,
+ 0x00202040L, 0x80002000L, 0x00002040L, 0x80000000L, 0x80002000L,
+ 0x00202040L, 0x80202000L, 0x00200040L, 0x00000000L, 0x80002000L,
+ 0x80000000L, 0x00002000L, 0x80200040L, 0x00200000L, 0x00200040L,
+ 0x80202040L, 0x00202000L, 0x00000040L, 0x80202040L, 0x00202000L,
+ 0x00200000L, 0x80002040L, 0x80000040L, 0x80200000L, 0x00202040L,
+ 0x00000000L, 0x00002000L, 0x80000040L, 0x80002040L, 0x80202000L,
+ 0x80200000L, 0x00002040L, 0x00000040L, 0x80200040L, },
+ {/* nibble 6 */
+ 0x00004000L, 0x00000200L, 0x01000200L, 0x01000004L, 0x01004204L,
+ 0x00004004L, 0x00004200L, 0x00000000L, 0x01000000L, 0x01000204L,
+ 0x00000204L, 0x01004000L, 0x00000004L, 0x01004200L, 0x01004000L,
+ 0x00000204L, 0x01000204L, 0x00004000L, 0x00004004L, 0x01004204L,
+ 0x00000000L, 0x01000200L, 0x01000004L, 0x00004200L, 0x01004004L,
+ 0x00004204L, 0x01004200L, 0x00000004L, 0x00004204L, 0x01004004L,
+ 0x00000200L, 0x01000000L, 0x00004204L, 0x01004000L, 0x01004004L,
+ 0x00000204L, 0x00004000L, 0x00000200L, 0x01000000L, 0x01004004L,
+ 0x01000204L, 0x00004204L, 0x00004200L, 0x00000000L, 0x00000200L,
+ 0x01000004L, 0x00000004L, 0x01000200L, 0x00000000L, 0x01000204L,
+ 0x01000200L, 0x00004200L, 0x00000204L, 0x00004000L, 0x01004204L,
+ 0x01000000L, 0x01004200L, 0x00000004L, 0x00004004L, 0x01004204L,
+ 0x01000004L, 0x01004200L, 0x01004000L, 0x00004004L, },
+ {/* nibble 7 */
+ 0x20800080L, 0x20820000L, 0x00020080L, 0x00000000L, 0x20020000L,
+ 0x00800080L, 0x20800000L, 0x20820080L, 0x00000080L, 0x20000000L,
+ 0x00820000L, 0x00020080L, 0x00820080L, 0x20020080L, 0x20000080L,
+ 0x20800000L, 0x00020000L, 0x00820080L, 0x00800080L, 0x20020000L,
+ 0x20820080L, 0x20000080L, 0x00000000L, 0x00820000L, 0x20000000L,
+ 0x00800000L, 0x20020080L, 0x20800080L, 0x00800000L, 0x00020000L,
+ 0x20820000L, 0x00000080L, 0x00800000L, 0x00020000L, 0x20000080L,
+ 0x20820080L, 0x00020080L, 0x20000000L, 0x00000000L, 0x00820000L,
+ 0x20800080L, 0x20020080L, 0x20020000L, 0x00800080L, 0x20820000L,
+ 0x00000080L, 0x00800080L, 0x20020000L, 0x20820080L, 0x00800000L,
+ 0x20800000L, 0x20000080L, 0x00820000L, 0x00020080L, 0x20020080L,
+ 0x20800000L, 0x00000080L, 0x20820000L, 0x00820080L, 0x00000000L,
+ 0x20000000L, 0x20800080L, 0x00020000L, 0x00820080L, }};
+
+#define HPERM_OP(a, t, n, m) \
+ ((t) = ((((a) << (16 - (n))) ^ (a)) & (m)), \
+ (a) = (a) ^ (t) ^ (t >> (16 - (n))))
+
+void DES_set_key(const DES_cblock *key, DES_key_schedule *schedule) {
+ static const int shifts2[16] = {0, 0, 1, 1, 1, 1, 1, 1,
+ 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);
+ c2l(in, d);
+
+ /* do PC1 in 47 simple operations :-)
+ * Thanks to John Fletcher (john_fletcher@lccmail.ocf.llnl.gov)
+ * for the inspiration. :-) */
+ PERM_OP(d, c, t, 4, 0x0f0f0f0fL);
+ HPERM_OP(c, t, -2, 0xcccc0000L);
+ HPERM_OP(d, t, -2, 0xcccc0000L);
+ PERM_OP(d, c, t, 1, 0x55555555L);
+ PERM_OP(c, d, t, 8, 0x00ff00ffL);
+ PERM_OP(d, c, t, 1, 0x55555555L);
+ d = (((d & 0x000000ffL) << 16L) | (d & 0x0000ff00L) |
+ ((d & 0x00ff0000L) >> 16L) | ((c & 0xf0000000L) >> 4L));
+ c &= 0x0fffffffL;
+
+ for (i = 0; i < ITERATIONS; i++) {
+ if (shifts2[i]) {
+ c = ((c >> 2L) | (c << 26L));
+ d = ((d >> 2L) | (d << 26L));
+ } else {
+ c = ((c >> 1L) | (c << 27L));
+ d = ((d >> 1L) | (d << 27L));
+ }
+ c &= 0x0fffffffL;
+ d &= 0x0fffffffL;
+ /* could be a few less shifts but I am to lazy at this
+ * point in time to investigate */
+ s = des_skb[0][(c) & 0x3f] |
+ des_skb[1][((c >> 6L) & 0x03) | ((c >> 7L) & 0x3c)] |
+ des_skb[2][((c >> 13L) & 0x0f) | ((c >> 14L) & 0x30)] |
+ des_skb[3][((c >> 20L) & 0x01) | ((c >> 21L) & 0x06) |
+ ((c >> 22L) & 0x38)];
+ t = des_skb[4][(d) & 0x3f] |
+ des_skb[5][((d >> 7L) & 0x03) | ((d >> 8L) & 0x3c)] |
+ des_skb[6][(d >> 15L) & 0x3f] |
+ des_skb[7][((d >> 21L) & 0x0f) | ((d >> 22L) & 0x30)];
+
+ /* table contained 0213 4657 */
+ t2 = ((t << 16L) | (s & 0x0000ffffL)) & 0xffffffffL;
+ *(k++) = ROTATE(t2, 30) & 0xffffffffL;
+
+ t2 = ((s >> 16L) | (t & 0xffff0000L));
+ *(k++) = ROTATE(t2, 26) & 0xffffffffL;
+ }
+}
+
+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];
+
+ IP(r, l);
+ /* Things have been modified so that the initial rotate is done outside
+ * the loop. This required the DES_SPtrans values in sp.h to be
+ * rotated 1 bit to the right. One perl script later and things have a
+ * 5% speed up on a sparc2. Thanks to Richard Outerbridge
+ * <71755.204@CompuServe.COM> for pointing this out. */
+ /* clear the top bits on machines with 8byte longs */
+ /* shift left by 2 */
+ 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 */
+ } 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 */
+ }
+
+ /* rotate and clear the top bits on machines with 8byte longs */
+ l = ROTATE(l, 3) & 0xffffffffL;
+ r = ROTATE(r, 3) & 0xffffffffL;
+
+ FP(r, l);
+ data[0] = l;
+ data[1] = r;
+ l = r = t = u = 0;
+}
+
+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];
+
+ /* Things have been modified so that the initial rotate is done outside the
+ * loop. This required the DES_SPtrans values in sp.h to be rotated 1 bit to
+ * the right. One perl script later and things have a 5% speed up on a
+ * sparc2. Thanks to Richard Outerbridge <71755.204@CompuServe.COM> for
+ * pointing this out. */
+ /* clear the top bits on machines with 8byte longs */
+ 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 */
+ } 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 */
+ }
+ /* rotate and clear the top bits on machines with 8byte longs */
+ data[0] = ROTATE(l, 3) & 0xffffffffL;
+ data[1] = ROTATE(r, 3) & 0xffffffffL;
+ l = r = t = u = 0;
+}
+
+static 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];
+ r = data[1];
+ IP(l, r);
+ data[0] = l;
+ data[1] = r;
+ DES_encrypt2((uint32_t *)data, ks1, DES_ENCRYPT);
+ DES_encrypt2((uint32_t *)data, ks2, DES_DECRYPT);
+ DES_encrypt2((uint32_t *)data, ks3, DES_ENCRYPT);
+ l = data[0];
+ r = data[1];
+ FP(r, l);
+ data[0] = l;
+ 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) {
+ uint32_t l, r;
+
+ l = data[0];
+ r = data[1];
+ IP(l, r);
+ data[0] = l;
+ data[1] = r;
+ DES_encrypt2((uint32_t *)data, ks3, DES_DECRYPT);
+ DES_encrypt2((uint32_t *)data, ks2, DES_ENCRYPT);
+ DES_encrypt2((uint32_t *)data, ks1, DES_DECRYPT);
+ l = data[0];
+ r = data[1];
+ FP(r, l);
+ data[0] = l;
+ data[1] = r;
+}
+
+void DES_ecb_encrypt(const DES_cblock *in_block, DES_cblock *out_block,
+ const DES_key_schedule *schedule, int is_encrypt) {
+ uint32_t l;
+ uint32_t ll[2];
+ const uint8_t *in = in_block->bytes;
+ uint8_t *out = out_block->bytes;
+
+ c2l(in, l);
+ ll[0] = l;
+ c2l(in, l);
+ ll[1] = l;
+ DES_encrypt1(ll, schedule, is_encrypt);
+ l = ll[0];
+ l2c(l, out);
+ l = ll[1];
+ l2c(l, out);
+ l = ll[0] = ll[1] = 0;
+}
+
+void DES_ncbc_encrypt(const uint8_t *in, uint8_t *out, size_t len,
+ const DES_key_schedule *schedule, DES_cblock *ivec,
+ int enc) {
+ uint32_t tin0, tin1;
+ uint32_t tout0, tout1, xor0, xor1;
+ uint32_t tin[2];
+ unsigned char *iv;
+
+ iv = ivec->bytes;
+
+ if (enc) {
+ c2l(iv, tout0);
+ c2l(iv, tout1);
+ for (; len >= 8; len -= 8) {
+ c2l(in, tin0);
+ c2l(in, tin1);
+ tin0 ^= tout0;
+ tin[0] = tin0;
+ tin1 ^= tout1;
+ tin[1] = tin1;
+ DES_encrypt1((uint32_t *)tin, schedule, DES_ENCRYPT);
+ tout0 = tin[0];
+ l2c(tout0, out);
+ tout1 = tin[1];
+ l2c(tout1, out);
+ }
+ if (len != 0) {
+ c2ln(in, tin0, tin1, len);
+ tin0 ^= tout0;
+ tin[0] = tin0;
+ tin1 ^= tout1;
+ tin[1] = tin1;
+ DES_encrypt1((uint32_t *)tin, schedule, DES_ENCRYPT);
+ tout0 = tin[0];
+ l2c(tout0, out);
+ tout1 = tin[1];
+ l2c(tout1, out);
+ }
+ iv = ivec->bytes;
+ l2c(tout0, iv);
+ l2c(tout1, iv);
+ } else {
+ c2l(iv, xor0);
+ c2l(iv, xor1);
+ for (; len >= 8; len -= 8) {
+ c2l(in, tin0);
+ tin[0] = tin0;
+ c2l(in, tin1);
+ tin[1] = tin1;
+ DES_encrypt1((uint32_t *)tin, schedule, DES_DECRYPT);
+ tout0 = tin[0] ^ xor0;
+ tout1 = tin[1] ^ xor1;
+ l2c(tout0, out);
+ l2c(tout1, out);
+ xor0 = tin0;
+ xor1 = tin1;
+ }
+ if (len != 0) {
+ c2l(in, tin0);
+ tin[0] = tin0;
+ c2l(in, tin1);
+ tin[1] = tin1;
+ DES_encrypt1((uint32_t *)tin, schedule, DES_DECRYPT);
+ tout0 = tin[0] ^ xor0;
+ tout1 = tin[1] ^ xor1;
+ l2cn(tout0, tout1, out, len);
+ xor0 = tin0;
+ xor1 = tin1;
+ }
+ iv = ivec->bytes;
+ l2c(xor0, iv);
+ l2c(xor1, iv);
+ }
+ tin0 = tin1 = tout0 = tout1 = xor0 = xor1 = 0;
+ tin[0] = tin[1] = 0;
+}
+
+void DES_ede3_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len,
+ const DES_key_schedule *ks1,
+ const DES_key_schedule *ks2,
+ const DES_key_schedule *ks3, DES_cblock *ivec,
+ int enc) {
+ uint32_t tin0, tin1;
+ uint32_t tout0, tout1, xor0, xor1;
+ uint32_t tin[2];
+ uint8_t *iv;
+
+ iv = ivec->bytes;
+
+ if (enc) {
+ c2l(iv, tout0);
+ c2l(iv, tout1);
+ for (; len >= 8; len -= 8) {
+ c2l(in, tin0);
+ c2l(in, tin1);
+ tin0 ^= tout0;
+ tin1 ^= tout1;
+
+ tin[0] = tin0;
+ tin[1] = tin1;
+ DES_encrypt3((uint32_t *)tin, ks1, ks2, ks3);
+ tout0 = tin[0];
+ tout1 = tin[1];
+
+ l2c(tout0, out);
+ l2c(tout1, out);
+ }
+ if (len != 0) {
+ c2ln(in, tin0, tin1, len);
+ tin0 ^= tout0;
+ tin1 ^= tout1;
+
+ tin[0] = tin0;
+ tin[1] = tin1;
+ DES_encrypt3((uint32_t *)tin, ks1, ks2, ks3);
+ tout0 = tin[0];
+ tout1 = tin[1];
+
+ l2c(tout0, out);
+ l2c(tout1, out);
+ }
+ iv = ivec->bytes;
+ l2c(tout0, iv);
+ l2c(tout1, iv);
+ } else {
+ uint32_t t0, t1;
+
+ c2l(iv, xor0);
+ c2l(iv, xor1);
+ for (; len >= 8; len -= 8) {
+ c2l(in, tin0);
+ c2l(in, tin1);
+
+ t0 = tin0;
+ t1 = tin1;
+
+ tin[0] = tin0;
+ tin[1] = tin1;
+ DES_decrypt3((uint32_t *)tin, ks1, ks2, ks3);
+ tout0 = tin[0];
+ tout1 = tin[1];
+
+ tout0 ^= xor0;
+ tout1 ^= xor1;
+ l2c(tout0, out);
+ l2c(tout1, out);
+ xor0 = t0;
+ xor1 = t1;
+ }
+ if (len != 0) {
+ c2l(in, tin0);
+ c2l(in, tin1);
+
+ t0 = tin0;
+ t1 = tin1;
+
+ tin[0] = tin0;
+ tin[1] = tin1;
+ DES_decrypt3((uint32_t *)tin, ks1, ks2, ks3);
+ tout0 = tin[0];
+ tout1 = tin[1];
+
+ tout0 ^= xor0;
+ tout1 ^= xor1;
+ l2cn(tout0, tout1, out, len);
+ xor0 = t0;
+ xor1 = t1;
+ }
+
+ iv = ivec->bytes;
+ l2c(xor0, iv);
+ l2c(xor1, iv);
+ }
+
+ tin0 = tin1 = tout0 = tout1 = xor0 = xor1 = 0;
+ tin[0] = tin[1] = 0;
+}
diff --git a/crypto/des/des.h b/crypto/des/des.h
new file mode 100644
index 0000000..a43e1d6
--- /dev/null
+++ b/crypto/des/des.h
@@ -0,0 +1,119 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_DES_H
+#define OPENSSL_HEADER_DES_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+typedef struct DES_cblock_st {
+ uint8_t bytes[8];
+} DES_cblock;
+
+typedef struct DES_ks {
+ union {
+ DES_cblock cblock;
+ /* make sure things are correct size on machines with
+ * 8 byte longs */
+ uint32_t deslong[2];
+ } ks[16];
+} DES_key_schedule;
+
+
+#define DES_KEY_SZ (sizeof(DES_cblock))
+#define DES_SCHEDULE_SZ (sizeof(DES_key_schedule))
+
+#define DES_ENCRYPT 1
+#define DES_DECRYPT 0
+
+#define DES_CBC_MODE 0
+#define DES_PCBC_MODE 1
+
+/* DES_set_key performs a key schedule and initialises |schedule| with |key|. */
+void DES_set_key(const DES_cblock *key, DES_key_schedule *schedule);
+
+/* DES_ecb_encrypt encrypts (or decrypts, if |is_encrypt| is |DES_DECRYPT|) a
+ * single DES block (8 bytes) from in to out, using the key configured in
+ * |schedule|. */
+void DES_ecb_encrypt(const DES_cblock *in, DES_cblock *out,
+ const DES_key_schedule *schedule, int is_encrypt);
+
+/* DES_ncbc_encrypt encrypts (or decrypts, if |enc| is |DES_DECRYPT|) |len|
+ * bytes from |in| to |out| with DES in CBC mode. */
+void DES_ncbc_encrypt(const uint8_t *in, uint8_t *out, size_t len,
+ const DES_key_schedule *schedule, DES_cblock *ivec,
+ int enc);
+
+/* DES_ede3_cbc_encrypt encrypts (or decrypts, if |enc| is |DES_DECRYPT|) |len|
+ * bytes from |in| to |out| with 3DES in CBC mode. 3DES uses three keys, thus
+ * the function takes three different |DES_key_schedule|s. */
+void DES_ede3_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len,
+ const DES_key_schedule *ks1,
+ const DES_key_schedule *ks2,
+ const DES_key_schedule *ks3, DES_cblock *ivec,
+ int enc);
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_DES_H */
diff --git a/crypto/des/internal.h b/crypto/des/internal.h
new file mode 100644
index 0000000..d3a5cec
--- /dev/null
+++ b/crypto/des/internal.h
@@ -0,0 +1,229 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_DES_INTERNAL_H
+#define OPENSSL_HEADER_DES_INTERNAL_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+#define c2l(c, l) \
+ (l = ((uint32_t)(*((c)++))), l |= ((uint32_t)(*((c)++))) << 8L, \
+ l |= ((uint32_t)(*((c)++))) << 16L, l |= ((uint32_t)(*((c)++))) << 24L)
+
+#define l2c(l, c) \
+ (*((c)++) = (unsigned char)(((l)) & 0xff), \
+ *((c)++) = (unsigned char)(((l) >> 8L) & 0xff), \
+ *((c)++) = (unsigned char)(((l) >> 16L) & 0xff), \
+ *((c)++) = (unsigned char)(((l) >> 24L) & 0xff))
+
+/* NOTE - c is not incremented as per c2l */
+#define c2ln(c, l1, l2, n) \
+ { \
+ c += n; \
+ l1 = l2 = 0; \
+ switch (n) { \
+ case 8: \
+ l2 = ((uint32_t)(*(--(c)))) << 24L; \
+ case 7: \
+ l2 |= ((uint32_t)(*(--(c)))) << 16L; \
+ case 6: \
+ l2 |= ((uint32_t)(*(--(c)))) << 8L; \
+ case 5: \
+ l2 |= ((uint32_t)(*(--(c)))); \
+ case 4: \
+ l1 = ((uint32_t)(*(--(c)))) << 24L; \
+ case 3: \
+ l1 |= ((uint32_t)(*(--(c)))) << 16L; \
+ case 2: \
+ l1 |= ((uint32_t)(*(--(c)))) << 8L; \
+ case 1: \
+ l1 |= ((uint32_t)(*(--(c)))); \
+ } \
+ }
+
+/* NOTE - c is not incremented as per l2c */
+#define l2cn(l1, l2, c, n) \
+ { \
+ c += n; \
+ switch (n) { \
+ case 8: \
+ *(--(c)) = (unsigned char)(((l2) >> 24L) & 0xff); \
+ case 7: \
+ *(--(c)) = (unsigned char)(((l2) >> 16L) & 0xff); \
+ case 6: \
+ *(--(c)) = (unsigned char)(((l2) >> 8L) & 0xff); \
+ case 5: \
+ *(--(c)) = (unsigned char)(((l2)) & 0xff); \
+ case 4: \
+ *(--(c)) = (unsigned char)(((l1) >> 24L) & 0xff); \
+ case 3: \
+ *(--(c)) = (unsigned char)(((l1) >> 16L) & 0xff); \
+ case 2: \
+ *(--(c)) = (unsigned char)(((l1) >> 8L) & 0xff); \
+ case 1: \
+ *(--(c)) = (unsigned char)(((l1)) & 0xff); \
+ } \
+ }
+
+/* IP and FP
+ * The problem is more of a geometric problem that random bit fiddling.
+ 0 1 2 3 4 5 6 7 62 54 46 38 30 22 14 6
+ 8 9 10 11 12 13 14 15 60 52 44 36 28 20 12 4
+16 17 18 19 20 21 22 23 58 50 42 34 26 18 10 2
+24 25 26 27 28 29 30 31 to 56 48 40 32 24 16 8 0
+
+32 33 34 35 36 37 38 39 63 55 47 39 31 23 15 7
+40 41 42 43 44 45 46 47 61 53 45 37 29 21 13 5
+48 49 50 51 52 53 54 55 59 51 43 35 27 19 11 3
+56 57 58 59 60 61 62 63 57 49 41 33 25 17 9 1
+
+The output has been subject to swaps of the form
+0 1 -> 3 1 but the odd and even bits have been put into
+2 3 2 0
+different words. The main trick is to remember that
+t=((l>>size)^r)&(mask);
+r^=t;
+l^=(t<<size);
+can be used to swap and move bits between words.
+
+So l = 0 1 2 3 r = 16 17 18 19
+ 4 5 6 7 20 21 22 23
+ 8 9 10 11 24 25 26 27
+ 12 13 14 15 28 29 30 31
+becomes (for size == 2 and mask == 0x3333)
+ t = 2^16 3^17 -- -- l = 0 1 16 17 r = 2 3 18 19
+ 6^20 7^21 -- -- 4 5 20 21 6 7 22 23
+ 10^24 11^25 -- -- 8 9 24 25 10 11 24 25
+ 14^28 15^29 -- -- 12 13 28 29 14 15 28 29
+
+Thanks for hints from Richard Outerbridge - he told me IP&FP
+could be done in 15 xor, 10 shifts and 5 ands.
+When I finally started to think of the problem in 2D
+I first got ~42 operations without xors. When I remembered
+how to use xors :-) I got it to its final state.
+*/
+#define PERM_OP(a, b, t, n, m) \
+ ((t) = ((((a) >> (n)) ^ (b)) & (m)), (b) ^= (t), (a) ^= ((t) << (n)))
+
+#define IP(l, r) \
+ { \
+ uint32_t tt; \
+ PERM_OP(r, l, tt, 4, 0x0f0f0f0fL); \
+ PERM_OP(l, r, tt, 16, 0x0000ffffL); \
+ PERM_OP(r, l, tt, 2, 0x33333333L); \
+ PERM_OP(l, r, tt, 8, 0x00ff00ffL); \
+ PERM_OP(r, l, tt, 1, 0x55555555L); \
+ }
+
+#define FP(l, r) \
+ { \
+ uint32_t tt; \
+ PERM_OP(l, r, tt, 1, 0x55555555L); \
+ PERM_OP(r, l, tt, 8, 0x00ff00ffL); \
+ PERM_OP(l, r, tt, 2, 0x33333333L); \
+ PERM_OP(r, l, tt, 16, 0x0000ffffL); \
+ 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 D_ENCRYPT(LL, R, S) \
+ { \
+ LOAD_DATA(R, S, u, t, E0, E1); \
+ t = ROTATE(t, 4); \
+ LL ^= \
+ DES_SPtrans[0][(u >> 2L) & 0x3f] ^ DES_SPtrans[2][(u >> 10L) & 0x3f] ^ \
+ DES_SPtrans[4][(u >> 18L) & 0x3f] ^ \
+ DES_SPtrans[6][(u >> 26L) & 0x3f] ^ DES_SPtrans[1][(t >> 2L) & 0x3f] ^ \
+ DES_SPtrans[3][(t >> 10L) & 0x3f] ^ \
+ DES_SPtrans[5][(t >> 18L) & 0x3f] ^ DES_SPtrans[7][(t >> 26L) & 0x3f]; \
+ }
+
+#define ITERATIONS 16
+#define HALF_ITERATIONS 8
+
+#if defined(_MSC_VER)
+#define ROTATE(a, n) (_lrotr(a, n))
+#elif defined(__ICC)
+#define ROTATE(a, n) (_rotr(a, n))
+#elif defined(__GNUC__) && __GNUC__ >= 2 && !defined(OPENSSL_NO_ASM) && \
+ !defined(__STRICT_ANSI__) && \
+ (defined(OPENSSL_X86) || defined(OPENSSL_X86_64))
+#define ROTATE(a, n) \
+ ({ \
+ unsigned int ret; \
+ asm("rorl %1,%0" : "=r"(ret) : "I"(n), "0"(a) : "cc"); \
+ ret; \
+ })
+#endif
+
+#ifndef ROTATE
+#define ROTATE(a, n) (((a) >> (n)) + ((a) << (32 - (n))))
+#endif
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_DES_INTERNAL_H */
diff --git a/crypto/dh/CMakeLists.txt b/crypto/dh/CMakeLists.txt
new file mode 100644
index 0000000..719606c
--- /dev/null
+++ b/crypto/dh/CMakeLists.txt
@@ -0,0 +1,22 @@
+include_directories(. .. ../../include)
+
+add_library(
+ dh
+
+ OBJECT
+
+ dh.c
+ dh_impl.c
+ params.c
+ check.c
+ dh_asn1.c
+ dh_error.c
+)
+
+add_executable(
+ dh_test
+
+ dh_test.c
+)
+
+target_link_libraries(dh_test crypto)
diff --git a/crypto/dh/check.c b/crypto/dh/check.c
new file mode 100644
index 0000000..f5099d5
--- /dev/null
+++ b/crypto/dh/check.c
@@ -0,0 +1,177 @@
+/* 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/dh.h>
+
+#include <openssl/bn.h>
+
+#include "internal.h"
+
+
+int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *ret) {
+ int ok = 0;
+ BIGNUM q;
+
+ *ret = 0;
+ BN_init(&q);
+ if (!BN_set_word(&q, 1)) {
+ goto err;
+ }
+
+ if (BN_cmp(pub_key, &q) <= 0) {
+ *ret |= DH_CHECK_PUBKEY_TOO_SMALL;
+ }
+ if (!BN_copy(&q, dh->p) ||
+ !BN_sub_word(&q, 1)) {
+ goto err;
+ }
+ if (BN_cmp(pub_key, &q) >= 0) {
+ *ret |= DH_CHECK_PUBKEY_TOO_LARGE;
+ }
+
+ ok = 1;
+
+err:
+ BN_free(&q);
+ return ok;
+}
+
+
+int DH_check(const DH *dh, int *ret) {
+ /* Check that p is a safe prime and if g is 2, 3 or 5, check that it is a
+ * suitable generator where:
+ * for 2, p mod 24 == 11
+ * for 3, p mod 12 == 5
+ * for 5, p mod 10 == 3 or 7
+ * should hold.
+ */
+ int ok = 0;
+ BN_CTX *ctx = NULL;
+ BN_ULONG l;
+ BIGNUM *t1 = NULL, *t2 = NULL;
+
+ *ret = 0;
+ ctx = BN_CTX_new();
+ if (ctx == NULL) {
+ goto err;
+ }
+ BN_CTX_start(ctx);
+ t1 = BN_CTX_get(ctx);
+ t2 = BN_CTX_get(ctx);
+ if (t2 == NULL) {
+ goto err;
+ }
+
+ if (dh->q) {
+ if (BN_cmp(dh->g, BN_value_one()) <= 0) {
+ *ret |= DH_CHECK_NOT_SUITABLE_GENERATOR;
+ } else if (BN_cmp(dh->g, dh->p) >= 0) {
+ *ret |= DH_CHECK_NOT_SUITABLE_GENERATOR;
+ } else {
+ /* Check g^q == 1 mod p */
+ if (!BN_mod_exp(t1, dh->g, dh->q, dh->p, ctx)) {
+ goto err;
+ }
+ if (!BN_is_one(t1)) {
+ *ret |= DH_CHECK_NOT_SUITABLE_GENERATOR;
+ }
+ }
+ if (!BN_is_prime_ex(dh->q, BN_prime_checks, ctx, NULL)) {
+ *ret |= DH_CHECK_Q_NOT_PRIME;
+ }
+ /* Check p == 1 mod q i.e. q divides p - 1 */
+ if (!BN_div(t1, t2, dh->p, dh->q, ctx)) {
+ goto err;
+ }
+ if (!BN_is_one(t2)) {
+ *ret |= DH_CHECK_INVALID_Q_VALUE;
+ }
+ if (dh->j && BN_cmp(dh->j, t1)) {
+ *ret |= DH_CHECK_INVALID_J_VALUE;
+ }
+ } else if (BN_is_word(dh->g, DH_GENERATOR_2)) {
+ l = BN_mod_word(dh->p, 24);
+ if (l != 11) {
+ *ret |= DH_CHECK_NOT_SUITABLE_GENERATOR;
+ }
+ } else if (BN_is_word(dh->g, DH_GENERATOR_5)) {
+ l = BN_mod_word(dh->p, 10);
+ if (l != 3 && l != 7) {
+ *ret |= DH_CHECK_NOT_SUITABLE_GENERATOR;
+ }
+ } else {
+ *ret |= DH_CHECK_UNABLE_TO_CHECK_GENERATOR;
+ }
+
+ if (!BN_is_prime_ex(dh->p, BN_prime_checks, ctx, NULL)) {
+ *ret |= DH_CHECK_P_NOT_PRIME;
+ } else if (!dh->q) {
+ if (!BN_rshift1(t1, dh->p)) {
+ goto err;
+ }
+ if (!BN_is_prime_ex(t1, BN_prime_checks, ctx, NULL)) {
+ *ret |= DH_CHECK_P_NOT_SAFE_PRIME;
+ }
+ }
+ ok = 1;
+
+err:
+ if (ctx != NULL) {
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ }
+ return ok;
+}
diff --git a/crypto/dh/dh.c b/crypto/dh/dh.c
new file mode 100644
index 0000000..3e6ae6d
--- /dev/null
+++ b/crypto/dh/dh.c
@@ -0,0 +1,241 @@
+/* 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/dh.h>
+
+#include <openssl/bn.h>
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/ex_data.h>
+#include <openssl/mem.h>
+#include <openssl/thread.h>
+
+#include "internal.h"
+
+
+extern const DH_METHOD DH_default_method;
+
+DH *DH_new(void) { return DH_new_method(NULL); }
+
+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);
+ return NULL;
+ }
+
+ memset(dh, 0, sizeof(DH));
+
+ if (engine) {
+ dh->meth = ENGINE_get_DH_method(engine);
+ }
+
+ if (dh->meth == NULL) {
+ dh->meth = (DH_METHOD*) &DH_default_method;
+ }
+ METHOD_ref(dh->meth);
+
+ dh->references = 1;
+ if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_DH, dh, &dh->ex_data)) {
+ OPENSSL_free(dh);
+ return NULL;
+ }
+
+ if (dh->meth->init && !dh->meth->init(dh)) {
+ CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DH, dh, &dh->ex_data);
+ METHOD_unref(dh->meth);
+ OPENSSL_free(dh);
+ return NULL;
+ }
+
+ return dh;
+}
+
+void DH_free(DH *dh) {
+ if (dh == NULL) {
+ return;
+ }
+
+ if (CRYPTO_add(&dh->references, -1, CRYPTO_LOCK_DH) > 0) {
+ return;
+ }
+
+ if (dh->meth->finish) {
+ dh->meth->finish(dh);
+ }
+ METHOD_unref(dh->meth);
+
+ CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DH, dh, &dh->ex_data);
+
+ if (dh->method_mont_p) BN_MONT_CTX_free(dh->method_mont_p);
+ if (dh->p != NULL) BN_clear_free(dh->p);
+ if (dh->g != NULL) BN_clear_free(dh->g);
+ if (dh->q != NULL) BN_clear_free(dh->q);
+ if (dh->j != NULL) BN_clear_free(dh->j);
+ if (dh->seed) OPENSSL_free(dh->seed);
+ if (dh->counter != NULL) BN_clear_free(dh->counter);
+ if (dh->pub_key != NULL) BN_clear_free(dh->pub_key);
+ if (dh->priv_key != NULL) BN_clear_free(dh->priv_key);
+
+ OPENSSL_free(dh);
+}
+
+int DH_generate_parameters_ex(DH *dh, int prime_bits, int generator, BN_GENCB *cb) {
+ if (dh->meth->generate_parameters) {
+ return dh->meth->generate_parameters(dh, prime_bits, generator, cb);
+ }
+ return DH_default_method.generate_parameters(dh, prime_bits, generator, cb);
+}
+
+int DH_generate_key(DH *dh) {
+ if (dh->meth->generate_key) {
+ return dh->meth->generate_key(dh);
+ }
+ return DH_default_method.generate_key(dh);
+}
+
+ssize_t DH_compute_key(unsigned char *out, const BIGNUM *peers_key, DH *dh) {
+ if (dh->meth->compute_key) {
+ return dh->meth->compute_key(dh, out, peers_key);
+ }
+ return DH_default_method.compute_key(dh, out, peers_key);
+}
+
+int DH_size(const DH *dh) { return BN_num_bytes(dh->p); }
+
+int DH_up_ref(DH *r) {
+ CRYPTO_add(&r->references, 1, CRYPTO_LOCK_DH);
+ return 1;
+}
+
+static int int_dh_bn_cpy(BIGNUM **dst, const BIGNUM *src) {
+ BIGNUM *a = NULL;
+
+ if (src) {
+ a = BN_dup(src);
+ if (!a) {
+ return 0;
+ }
+ }
+
+ if (*dst) {
+ BN_free(*dst);
+ }
+ *dst = a;
+ return 1;
+}
+
+static int int_dh_param_copy(DH *to, const DH *from, int is_x942) {
+ if (is_x942 == -1) {
+ is_x942 = !!from->q;
+ }
+ if (!int_dh_bn_cpy(&to->p, from->p) ||
+ !int_dh_bn_cpy(&to->g, from->g)) {
+ return 0;
+ }
+
+ if (!is_x942) {
+ return 1;
+ }
+
+ if (!int_dh_bn_cpy(&to->q, from->q) ||
+ !int_dh_bn_cpy(&to->j, from->j)) {
+ return 0;
+ }
+
+ if (to->seed) {
+ OPENSSL_free(to->seed);
+ to->seed = NULL;
+ to->seedlen = 0;
+ }
+ if (from->seed) {
+ to->seed = BUF_memdup(from->seed, from->seedlen);
+ if (!to->seed) {
+ return 0;
+ }
+ to->seedlen = from->seedlen;
+ }
+
+ return 1;
+}
+
+DH *DHparams_dup(const DH *dh) {
+ DH *ret = DH_new();
+ if (!ret) {
+ return NULL;
+ }
+
+ if (!int_dh_param_copy(ret, dh, -1)) {
+ DH_free(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+int DH_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+ CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) {
+ return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_DH, argl, argp, new_func,
+ dup_func, free_func);
+}
+
+int DH_set_ex_data(DH *d, int idx, void *arg) {
+ return (CRYPTO_set_ex_data(&d->ex_data, idx, arg));
+}
+
+void *DH_get_ex_data(DH *d, int idx) {
+ return (CRYPTO_get_ex_data(&d->ex_data, idx));
+}
diff --git a/crypto/dh/dh.h b/crypto/dh/dh.h
new file mode 100644
index 0000000..d1b84f9
--- /dev/null
+++ b/crypto/dh/dh.h
@@ -0,0 +1,259 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_DH_H
+#define OPENSSL_HEADER_DH_H
+
+#include <openssl/base.h>
+
+#include <openssl/engine.h>
+#include <openssl/ex_data.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* DH contains functions for performing Diffie-Hellman key agreement in
+ * multiplicative groups. */
+
+
+/* Allocation and destruction. */
+
+/* DH_new returns a new, empty DH object or NULL on error. */
+DH *DH_new(void);
+
+/* DH_new_method acts the same as |DH_new| but takes an explicit |ENGINE|. */
+DH *DH_new_method(const ENGINE *engine);
+
+/* DH_free decrements the reference count of |dh| and frees it if the reference
+ * count drops to zero. */
+void DH_free(DH *dh);
+
+/* DH_up_ref increments the reference count of |dh|. */
+int DH_up_ref(DH *dh);
+
+
+/* Standard parameters.
+ *
+ * These functions return new DH objects with standard parameters configured
+ * that use the given ENGINE, which may be NULL. They return NULL on allocation
+ * failure. */
+
+/* These parameters are taken from RFC 5114. */
+
+DH *DH_get_1024_160(const ENGINE *engine);
+DH *DH_get_2048_224(const ENGINE *engine);
+DH *DH_get_2048_256(const ENGINE *engine);
+
+
+/* Parameter generation. */
+
+#define DH_GENERATOR_2 2
+#define DH_GENERATOR_5 5
+
+/* DH_generate_parameters_ex generates a suitable Diffie-Hellman group with a
+ * prime that is |prime_bits| long and stores it in |dh|. The generator of the
+ * group will be |generator|, which should be |DH_GENERATOR_2| unless there's a
+ * good reason to use a different value. The |cb| argument contains a callback
+ * function that will be called during the generation. See the documentation in
+ * |bn.h| about this. In addition to the callback invocations from |BN|, |cb|
+ * will also be called with |event| equal to three when the generation is
+ * complete. */
+int DH_generate_parameters_ex(DH *dh, int prime_bits, int generator,
+ BN_GENCB *cb);
+
+
+/* Diffie-Hellman operations. */
+
+/* DH_generate_key generates a new, random, private key and stores it in
+ * |dh|. It returns one on success and zero on error. */
+int DH_generate_key(DH *dh);
+
+/* DH_compute_key calculates the shared key between |dh| and |peers_key| and
+ * writes it as a big-endian integer into |out|, which must have |DH_size|
+ * bytes of space. It returns the number of bytes written, or a negative number
+ * on error. */
+ssize_t DH_compute_key(uint8_t *out, const BIGNUM *peers_key, DH *dh);
+
+
+/* Utility functions. */
+
+/* DH_size returns the number of bytes in the DH group's prime. */
+int DH_size(const DH *dh);
+
+#define DH_CHECK_P_NOT_PRIME 0x01
+#define DH_CHECK_P_NOT_SAFE_PRIME 0x02
+#define DH_CHECK_UNABLE_TO_CHECK_GENERATOR 0x04
+#define DH_CHECK_NOT_SUITABLE_GENERATOR 0x08
+#define DH_CHECK_Q_NOT_PRIME 0x10
+#define DH_CHECK_INVALID_Q_VALUE 0x20
+#define DH_CHECK_INVALID_J_VALUE 0x40
+
+/* DH_check checks the suitability of |dh| as a Diffie-Hellman group. and sets
+ * |DH_CHECK_*| flags in |*out_flags| if it finds any errors. It returns one if
+ * |*out_flags| was successfully set and zero on error.
+ *
+ * Note: these checks may be quite computationally expensive. */
+int DH_check(const DH *dh, int *out_flags);
+
+#define DH_CHECK_PUBKEY_TOO_SMALL 1
+#define DH_CHECK_PUBKEY_TOO_LARGE 2
+
+/* DH_check_pub_key checks the suitability of |pub_key| as a public key for the
+ * DH group in |dh| and sets |DH_CHECK_PUBKEY_*| flags in |*out_flags| if it
+ * finds any errors. It returns one if |*out_flags| was successfully set and
+ * zero on error. */
+int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *out_flags);
+
+/* DHparams_dup allocates a fresh |DH| and copies the parameters from |dh| into
+ * it. It returns the new |DH| or NULL on error. */
+DH *DHparams_dup(const DH *dh);
+
+
+/* ASN.1 functions. */
+
+/* d2i_DHparams parses an ASN.1, DER encoded Diffie-Hellman parameters
+ * structure from |len| bytes at |*inp|. If |ret| is not NULL then, on exit, a
+ * pointer to the result is in |*ret|. If |*ret| is already non-NULL on entry
+ * then the result is written directly into |*ret|, otherwise a fresh |DH| is
+ * allocated. On successful exit, |*inp| is advanced past the DER structure. It
+ * returns the result or NULL on error. */
+DH *d2i_DHparams(DH **ret, const unsigned char **inp, long len);
+
+/* i2d_DHparams marshals |in| to an ASN.1, DER structure. If |outp| is not NULL
+ * then the result is written to |*outp| and |*outp| is advanced just past the
+ * output. It returns the number of bytes in the result, whether written or
+ * not, or a negative value on error. */
+int i2d_DHparams(const DH *in, unsigned char **outp);
+
+
+/* ex_data functions.
+ *
+ * These functions are wrappers. See |ex_data.h| for details. */
+
+int DH_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+ CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+int DH_set_ex_data(DH *d, int idx, void *arg);
+void *DH_get_ex_data(DH *d, int idx);
+
+
+/* dh_method contains function pointers to override the implementation of DH.
+ * See |engine.h| for details. */
+struct dh_method {
+ struct openssl_method_common_st common;
+
+ /* app_data is an opaque pointer for the method to use. */
+ void *app_data;
+
+ /* init is called just before the return of |DH_new_method|. It returns one
+ * on success or zero on error. */
+ int (*init)(DH *dh);
+
+ /* finish is called before |dh| is destructed. */
+ void (*finish)(DH *dh);
+
+ /* generate_parameters is called by |DH_generate_parameters_ex|. */
+ int (*generate_parameters)(DH *dh, int prime_bits, int generator,
+ BN_GENCB *cb);
+
+ /* generate_parameters is called by |DH_generate_key|. */
+ int (*generate_key)(DH *dh);
+
+ /* generate_parameters is called by |DH_compute_key|. */
+ ssize_t (*compute_key)(DH *dh, uint8_t *out, const BIGNUM *pub_key);
+};
+
+struct dh_st {
+ DH_METHOD *meth;
+
+ BIGNUM *p;
+ BIGNUM *g;
+ BIGNUM *pub_key; /* g^x */
+ BIGNUM *priv_key; /* x */
+
+ /* priv_length contains the length, in bits, of the private value. If zero,
+ * the private value will be the same length as |p|. */
+ unsigned priv_length;
+ BN_MONT_CTX *method_mont_p;
+
+ /* Place holders if we want to do X9.42 DH */
+ BIGNUM *q;
+ BIGNUM *j;
+ unsigned char *seed;
+ int seedlen;
+ BIGNUM *counter;
+
+ int flags;
+ int references;
+ CRYPTO_EX_DATA ex_data;
+};
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#define DH_F_generate_parameters 100
+#define DH_F_generate_key 101
+#define DH_F_compute_key 102
+#define DH_F_DH_new_method 103
+#define DH_R_INVALID_PUBKEY 100
+#define DH_R_BAD_GENERATOR 101
+#define DH_R_MODULUS_TOO_LARGE 102
+#define DH_R_NO_PRIVATE_VALUE 103
+
+#endif /* OPENSSL_HEADER_DH_H */
diff --git a/crypto/dh/dh_asn1.c b/crypto/dh/dh_asn1.c
new file mode 100644
index 0000000..73cd4df
--- /dev/null
+++ b/crypto/dh/dh_asn1.c
@@ -0,0 +1,84 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2000.
+ */
+/* ====================================================================
+ * Copyright (c) 2000-2005 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/dh.h>
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+
+#include "internal.h"
+
+/* Override the default free and new methods */
+static int dh_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
+ void *exarg) {
+ if (operation == ASN1_OP_NEW_PRE) {
+ *pval = (ASN1_VALUE *)DH_new();
+ if (*pval) {
+ return 2;
+ }
+ return 0;
+ } else if (operation == ASN1_OP_FREE_PRE) {
+ DH_free((DH *)*pval);
+ *pval = NULL;
+ return 2;
+ }
+ return 1;
+}
+
+ASN1_SEQUENCE_cb(DHparams, dh_cb) = {
+ ASN1_SIMPLE(DH, p, BIGNUM), ASN1_SIMPLE(DH, g, BIGNUM),
+ ASN1_OPT(DH, priv_length, ZLONG)} ASN1_SEQUENCE_END_cb(DH, DHparams);
+
+IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DH, DHparams, DHparams)
diff --git a/crypto/dh/dh_error.c b/crypto/dh/dh_error.c
new file mode 100644
index 0000000..8a7041c
--- /dev/null
+++ b/crypto/dh/dh_error.c
@@ -0,0 +1,29 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/err.h>
+
+#include "dh.h"
+
+const ERR_STRING_DATA DH_error_string_data[] = {
+ {ERR_PACK(ERR_LIB_DH, DH_F_DH_new_method, 0), "DH_new_method"},
+ {ERR_PACK(ERR_LIB_DH, DH_F_compute_key, 0), "compute_key"},
+ {ERR_PACK(ERR_LIB_DH, DH_F_generate_key, 0), "generate_key"},
+ {ERR_PACK(ERR_LIB_DH, DH_F_generate_parameters, 0), "generate_parameters"},
+ {ERR_PACK(ERR_LIB_DH, 0, DH_R_BAD_GENERATOR), "BAD_GENERATOR"},
+ {ERR_PACK(ERR_LIB_DH, 0, DH_R_INVALID_PUBKEY), "INVALID_PUBKEY"},
+ {ERR_PACK(ERR_LIB_DH, 0, DH_R_MODULUS_TOO_LARGE), "MODULUS_TOO_LARGE"},
+ {ERR_PACK(ERR_LIB_DH, 0, DH_R_NO_PRIVATE_VALUE), "NO_PRIVATE_VALUE"},
+ {0, NULL},
+};
diff --git a/crypto/dh/dh_impl.c b/crypto/dh/dh_impl.c
new file mode 100644
index 0000000..edc3db7
--- /dev/null
+++ b/crypto/dh/dh_impl.c
@@ -0,0 +1,323 @@
+/* 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/dh.h>
+
+#include <openssl/bn.h>
+#include <openssl/err.h>
+
+#include "internal.h"
+
+#define OPENSSL_DH_MAX_MODULUS_BITS 10000
+
+static int generate_parameters(DH *ret, int prime_bits, int generator, BN_GENCB *cb) {
+ /* We generate DH parameters as follows
+ * find a prime q which is prime_bits/2 bits long.
+ * p=(2*q)+1 or (p-1)/2 = q
+ * For this case, g is a generator if
+ * g^((p-1)/q) mod p != 1 for values of q which are the factors of p-1.
+ * Since the factors of p-1 are q and 2, we just need to check
+ * g^2 mod p != 1 and g^q mod p != 1.
+ *
+ * Having said all that,
+ * there is another special case method for the generators 2, 3 and 5.
+ * for 2, p mod 24 == 11
+ * for 3, p mod 12 == 5 <<<<< does not work for safe primes.
+ * for 5, p mod 10 == 3 or 7
+ *
+ * Thanks to Phil Karn <karn@qualcomm.com> for the pointers about the
+ * special generators and for answering some of my questions.
+ *
+ * I've implemented the second simple method :-).
+ * Since DH should be using a safe prime (both p and q are prime),
+ * this generator function can take a very very long time to run.
+ */
+
+ /* Actually there is no reason to insist that 'generator' be a generator.
+ * It's just as OK (and in some sense better) to use a generator of the
+ * order-q subgroup.
+ */
+
+ BIGNUM *t1, *t2;
+ int g, ok = 0;
+ BN_CTX *ctx = NULL;
+
+ ctx = BN_CTX_new();
+ if (ctx == NULL) {
+ goto err;
+ }
+ BN_CTX_start(ctx);
+ t1 = BN_CTX_get(ctx);
+ t2 = BN_CTX_get(ctx);
+ if (t1 == NULL || t2 == NULL) {
+ goto err;
+ }
+
+ /* Make sure 'ret' has the necessary elements */
+ if (!ret->p && ((ret->p = BN_new()) == NULL)) {
+ goto err;
+ }
+ if (!ret->g && ((ret->g = BN_new()) == NULL)) {
+ goto err;
+ }
+
+ if (generator <= 1) {
+ OPENSSL_PUT_ERROR(DH, generate_parameters, DH_R_BAD_GENERATOR);
+ goto err;
+ }
+ if (generator == DH_GENERATOR_2) {
+ if (!BN_set_word(t1, 24)) {
+ goto err;
+ }
+ if (!BN_set_word(t2, 11)) {
+ goto err;
+ }
+ g = 2;
+ } else if (generator == DH_GENERATOR_5) {
+ if (!BN_set_word(t1, 10)) {
+ goto err;
+ }
+ if (!BN_set_word(t2, 3)) {
+ goto err;
+ }
+ /* BN_set_word(t3,7); just have to miss
+ * out on these ones :-( */
+ g = 5;
+ } else {
+ /* in the general case, don't worry if 'generator' is a
+ * generator or not: since we are using safe primes,
+ * it will generate either an order-q or an order-2q group,
+ * which both is OK */
+ if (!BN_set_word(t1, 2)) {
+ goto err;
+ }
+ if (!BN_set_word(t2, 1)) {
+ goto err;
+ }
+ g = generator;
+ }
+
+ if (!BN_generate_prime_ex(ret->p, prime_bits, 1, t1, t2, cb)) {
+ goto err;
+ }
+ if (!BN_GENCB_call(cb, 3, 0)) {
+ goto err;
+ }
+ if (!BN_set_word(ret->g, g)) {
+ goto err;
+ }
+ ok = 1;
+
+err:
+ if (!ok) {
+ OPENSSL_PUT_ERROR(DH, generate_parameters, ERR_R_BN_LIB);
+ }
+
+ if (ctx != NULL) {
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ }
+ return ok;
+}
+
+static int generate_key(DH *dh) {
+ int ok = 0;
+ int generate_new_key = 0;
+ unsigned l;
+ BN_CTX *ctx;
+ BN_MONT_CTX *mont = NULL;
+ BIGNUM *pub_key = NULL, *priv_key = NULL;
+ BIGNUM local_priv;
+
+ ctx = BN_CTX_new();
+ if (ctx == NULL) {
+ goto err;
+ }
+
+ if (dh->priv_key == NULL) {
+ priv_key = BN_new();
+ if (priv_key == NULL) {
+ goto err;
+ }
+ generate_new_key = 1;
+ } else {
+ priv_key = dh->priv_key;
+ }
+
+ if (dh->pub_key == NULL) {
+ pub_key = BN_new();
+ if (pub_key == NULL) {
+ goto err;
+ }
+ } else {
+ pub_key = dh->pub_key;
+ }
+
+ mont =
+ BN_MONT_CTX_set_locked(&dh->method_mont_p, CRYPTO_LOCK_DH, dh->p, ctx);
+ if (!mont) {
+ goto err;
+ }
+
+ if (generate_new_key) {
+ if (dh->q) {
+ do {
+ if (!BN_rand_range(priv_key, dh->q)) {
+ goto err;
+ }
+ } while (BN_is_zero(priv_key) || BN_is_one(priv_key));
+ } else {
+ /* secret exponent length */
+ l = dh->priv_length ? dh->priv_length : BN_num_bits(dh->p) - 1;
+ if (!BN_rand(priv_key, l, 0, 0)) {
+ goto err;
+ }
+ }
+ }
+
+ BN_with_flags(&local_priv, priv_key, BN_FLG_CONSTTIME);
+ if (!BN_mod_exp_mont(pub_key, dh->g, &local_priv, dh->p, ctx, mont)) {
+ goto err;
+ }
+
+ dh->pub_key = pub_key;
+ dh->priv_key = priv_key;
+ ok = 1;
+
+err:
+ if (ok != 1) {
+ OPENSSL_PUT_ERROR(DH, generate_key, ERR_R_BN_LIB);
+ }
+
+ if (pub_key != NULL && dh->pub_key == NULL) {
+ BN_free(pub_key);
+ }
+ if (priv_key != NULL && dh->priv_key == NULL) {
+ BN_free(priv_key);
+ }
+ BN_CTX_free(ctx);
+ return ok;
+}
+
+static ssize_t compute_key(DH *dh, unsigned char *out, const BIGNUM *pub_key) {
+ BN_CTX *ctx = NULL;
+ BN_MONT_CTX *mont = NULL;
+ BIGNUM *shared_key;
+ int ret = -1;
+ int check_result;
+ 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);
+ goto err;
+ }
+
+ ctx = BN_CTX_new();
+ if (ctx == NULL) {
+ goto err;
+ }
+ BN_CTX_start(ctx);
+ shared_key = BN_CTX_get(ctx);
+ if (shared_key == NULL) {
+ goto err;
+ }
+
+ if (dh->priv_key == NULL) {
+ OPENSSL_PUT_ERROR(DH, compute_key, DH_R_NO_PRIVATE_VALUE);
+ goto err;
+ }
+
+ mont =
+ BN_MONT_CTX_set_locked(&dh->method_mont_p, CRYPTO_LOCK_DH, dh->p, ctx);
+ if (!mont) {
+ goto err;
+ }
+
+ if (!DH_check_pub_key(dh, pub_key, &check_result) || check_result) {
+ OPENSSL_PUT_ERROR(DH, compute_key, 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);
+ goto err;
+ }
+
+ ret = BN_bn2bin(shared_key, out);
+
+err:
+ if (ctx != NULL) {
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ }
+
+ return ret;
+}
+
+const struct dh_method DH_default_method = {
+ {
+ 0 /* references */,
+ 1 /* is_static */,
+ },
+ NULL /* app_data */,
+ NULL /* init */,
+ NULL /* finish */,
+ generate_parameters,
+ generate_key,
+ compute_key,
+};
diff --git a/crypto/dh/dh_test.c b/crypto/dh/dh_test.c
new file mode 100644
index 0000000..73dbba9
--- /dev/null
+++ b/crypto/dh/dh_test.c
@@ -0,0 +1,498 @@
+/* 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/dh.h>
+
+#include <stdio.h>
+
+#include <openssl/bio.h>
+#include <openssl/bn.h>
+#include <openssl/mem.h>
+
+#include "internal.h"
+
+
+static int cb(int p, int n, BN_GENCB *arg) {
+ char c = '*';
+
+ if (p == 0)
+ c = '.';
+ if (p == 1)
+ c = '+';
+ if (p == 2)
+ c = '*';
+ if (p == 3)
+ c = '\n';
+ BIO_write(arg->arg, &c, 1);
+ (void)BIO_flush(arg->arg);
+
+ return 1;
+}
+
+static int run_rfc5114_tests(void);
+
+int main(int argc, char *argv[]) {
+ BN_GENCB _cb;
+ DH *a;
+ DH *b = NULL;
+ char buf[12];
+ unsigned char *abuf = NULL, *bbuf = NULL;
+ int i, alen, blen, aout, bout, ret = 1;
+ BIO *out;
+
+ out = BIO_new(BIO_s_file());
+ if (out == NULL) {
+ return 1;
+ }
+ BIO_set_fp(out, stdout, BIO_NOCLOSE);
+
+ BN_GENCB_set(&_cb, &cb, out);
+ if (((a = DH_new()) == NULL) ||
+ !DH_generate_parameters_ex(a, 64, DH_GENERATOR_5, &_cb)) {
+ goto err;
+ }
+
+ if (!DH_check(a, &i))
+ goto err;
+ if (i & DH_CHECK_P_NOT_PRIME)
+ BIO_puts(out, "p value is not prime\n");
+ if (i & DH_CHECK_P_NOT_SAFE_PRIME)
+ BIO_puts(out, "p value is not a safe prime\n");
+ if (i & DH_CHECK_UNABLE_TO_CHECK_GENERATOR)
+ BIO_puts(out, "unable to check the generator value\n");
+ if (i & DH_CHECK_NOT_SUITABLE_GENERATOR)
+ BIO_puts(out, "the g value is not a generator\n");
+
+ BIO_puts(out, "\np =");
+ BN_print(out, a->p);
+ BIO_puts(out, "\ng =");
+ BN_print(out, a->g);
+ BIO_puts(out, "\n");
+
+ b = DH_new();
+ if (b == NULL) {
+ goto err;
+ }
+
+ b->p = BN_dup(a->p);
+ b->g = BN_dup(a->g);
+ if (b->p == NULL || b->g == NULL) {
+ goto err;
+ }
+
+ if (!DH_generate_key(a))
+ goto err;
+ BIO_puts(out, "pri 1=");
+ BN_print(out, a->priv_key);
+ BIO_puts(out, "\npub 1=");
+ BN_print(out, a->pub_key);
+ BIO_puts(out, "\n");
+
+ if (!DH_generate_key(b))
+ goto err;
+ BIO_puts(out, "pri 2=");
+ BN_print(out, b->priv_key);
+ BIO_puts(out, "\npub 2=");
+ BN_print(out, b->pub_key);
+ BIO_puts(out, "\n");
+
+ alen = DH_size(a);
+ abuf = (unsigned char *)OPENSSL_malloc(alen);
+ aout = DH_compute_key(abuf, b->pub_key, a);
+
+ BIO_puts(out, "key1 =");
+ for (i = 0; i < aout; i++) {
+ sprintf(buf, "%02X", abuf[i]);
+ BIO_puts(out, buf);
+ }
+ BIO_puts(out, "\n");
+
+ blen = DH_size(b);
+ bbuf = (unsigned char *)OPENSSL_malloc(blen);
+ bout = DH_compute_key(bbuf, a->pub_key, b);
+
+ BIO_puts(out, "key2 =");
+ for (i = 0; i < bout; i++) {
+ sprintf(buf, "%02X", bbuf[i]);
+ BIO_puts(out, buf);
+ }
+ BIO_puts(out, "\n");
+ if ((aout < 4) || (bout != aout) || (memcmp(abuf, bbuf, aout) != 0)) {
+ fprintf(stderr, "Error in DH routines\n");
+ ret = 1;
+ } else
+ ret = 0;
+
+ if (!run_rfc5114_tests())
+ ret = 1;
+
+err:
+ BIO_print_errors_fp(stderr);
+
+ if (abuf != NULL)
+ OPENSSL_free(abuf);
+ if (bbuf != NULL)
+ OPENSSL_free(bbuf);
+ if (b != NULL)
+ DH_free(b);
+ if (a != NULL)
+ DH_free(a);
+ BIO_free(out);
+ return ret;
+}
+
+/* Test data from RFC 5114 */
+
+static const unsigned char dhtest_1024_160_xA[] = {
+ 0xB9, 0xA3, 0xB3, 0xAE, 0x8F, 0xEF, 0xC1, 0xA2, 0x93, 0x04,
+ 0x96, 0x50, 0x70, 0x86, 0xF8, 0x45, 0x5D, 0x48, 0x94, 0x3E};
+static const unsigned char dhtest_1024_160_yA[] = {
+ 0x2A, 0x85, 0x3B, 0x3D, 0x92, 0x19, 0x75, 0x01, 0xB9, 0x01, 0x5B, 0x2D,
+ 0xEB, 0x3E, 0xD8, 0x4F, 0x5E, 0x02, 0x1D, 0xCC, 0x3E, 0x52, 0xF1, 0x09,
+ 0xD3, 0x27, 0x3D, 0x2B, 0x75, 0x21, 0x28, 0x1C, 0xBA, 0xBE, 0x0E, 0x76,
+ 0xFF, 0x57, 0x27, 0xFA, 0x8A, 0xCC, 0xE2, 0x69, 0x56, 0xBA, 0x9A, 0x1F,
+ 0xCA, 0x26, 0xF2, 0x02, 0x28, 0xD8, 0x69, 0x3F, 0xEB, 0x10, 0x84, 0x1D,
+ 0x84, 0xA7, 0x36, 0x00, 0x54, 0xEC, 0xE5, 0xA7, 0xF5, 0xB7, 0xA6, 0x1A,
+ 0xD3, 0xDF, 0xB3, 0xC6, 0x0D, 0x2E, 0x43, 0x10, 0x6D, 0x87, 0x27, 0xDA,
+ 0x37, 0xDF, 0x9C, 0xCE, 0x95, 0xB4, 0x78, 0x75, 0x5D, 0x06, 0xBC, 0xEA,
+ 0x8F, 0x9D, 0x45, 0x96, 0x5F, 0x75, 0xA5, 0xF3, 0xD1, 0xDF, 0x37, 0x01,
+ 0x16, 0x5F, 0xC9, 0xE5, 0x0C, 0x42, 0x79, 0xCE, 0xB0, 0x7F, 0x98, 0x95,
+ 0x40, 0xAE, 0x96, 0xD5, 0xD8, 0x8E, 0xD7, 0x76};
+static const unsigned char dhtest_1024_160_xB[] = {
+ 0x93, 0x92, 0xC9, 0xF9, 0xEB, 0x6A, 0x7A, 0x6A, 0x90, 0x22,
+ 0xF7, 0xD8, 0x3E, 0x72, 0x23, 0xC6, 0x83, 0x5B, 0xBD, 0xDA};
+static const unsigned char dhtest_1024_160_yB[] = {
+ 0x71, 0x7A, 0x6C, 0xB0, 0x53, 0x37, 0x1F, 0xF4, 0xA3, 0xB9, 0x32, 0x94,
+ 0x1C, 0x1E, 0x56, 0x63, 0xF8, 0x61, 0xA1, 0xD6, 0xAD, 0x34, 0xAE, 0x66,
+ 0x57, 0x6D, 0xFB, 0x98, 0xF6, 0xC6, 0xCB, 0xF9, 0xDD, 0xD5, 0xA5, 0x6C,
+ 0x78, 0x33, 0xF6, 0xBC, 0xFD, 0xFF, 0x09, 0x55, 0x82, 0xAD, 0x86, 0x8E,
+ 0x44, 0x0E, 0x8D, 0x09, 0xFD, 0x76, 0x9E, 0x3C, 0xEC, 0xCD, 0xC3, 0xD3,
+ 0xB1, 0xE4, 0xCF, 0xA0, 0x57, 0x77, 0x6C, 0xAA, 0xF9, 0x73, 0x9B, 0x6A,
+ 0x9F, 0xEE, 0x8E, 0x74, 0x11, 0xF8, 0xD6, 0xDA, 0xC0, 0x9D, 0x6A, 0x4E,
+ 0xDB, 0x46, 0xCC, 0x2B, 0x5D, 0x52, 0x03, 0x09, 0x0E, 0xAE, 0x61, 0x26,
+ 0x31, 0x1E, 0x53, 0xFD, 0x2C, 0x14, 0xB5, 0x74, 0xE6, 0xA3, 0x10, 0x9A,
+ 0x3D, 0xA1, 0xBE, 0x41, 0xBD, 0xCE, 0xAA, 0x18, 0x6F, 0x5C, 0xE0, 0x67,
+ 0x16, 0xA2, 0xB6, 0xA0, 0x7B, 0x3C, 0x33, 0xFE};
+static const unsigned char dhtest_1024_160_Z[] = {
+ 0x5C, 0x80, 0x4F, 0x45, 0x4D, 0x30, 0xD9, 0xC4, 0xDF, 0x85, 0x27, 0x1F,
+ 0x93, 0x52, 0x8C, 0x91, 0xDF, 0x6B, 0x48, 0xAB, 0x5F, 0x80, 0xB3, 0xB5,
+ 0x9C, 0xAA, 0xC1, 0xB2, 0x8F, 0x8A, 0xCB, 0xA9, 0xCD, 0x3E, 0x39, 0xF3,
+ 0xCB, 0x61, 0x45, 0x25, 0xD9, 0x52, 0x1D, 0x2E, 0x64, 0x4C, 0x53, 0xB8,
+ 0x07, 0xB8, 0x10, 0xF3, 0x40, 0x06, 0x2F, 0x25, 0x7D, 0x7D, 0x6F, 0xBF,
+ 0xE8, 0xD5, 0xE8, 0xF0, 0x72, 0xE9, 0xB6, 0xE9, 0xAF, 0xDA, 0x94, 0x13,
+ 0xEA, 0xFB, 0x2E, 0x8B, 0x06, 0x99, 0xB1, 0xFB, 0x5A, 0x0C, 0xAC, 0xED,
+ 0xDE, 0xAE, 0xAD, 0x7E, 0x9C, 0xFB, 0xB3, 0x6A, 0xE2, 0xB4, 0x20, 0x83,
+ 0x5B, 0xD8, 0x3A, 0x19, 0xFB, 0x0B, 0x5E, 0x96, 0xBF, 0x8F, 0xA4, 0xD0,
+ 0x9E, 0x34, 0x55, 0x25, 0x16, 0x7E, 0xCD, 0x91, 0x55, 0x41, 0x6F, 0x46,
+ 0xF4, 0x08, 0xED, 0x31, 0xB6, 0x3C, 0x6E, 0x6D};
+static const unsigned char dhtest_2048_224_xA[] = {
+ 0x22, 0xE6, 0x26, 0x01, 0xDB, 0xFF, 0xD0, 0x67, 0x08, 0xA6,
+ 0x80, 0xF7, 0x47, 0xF3, 0x61, 0xF7, 0x6D, 0x8F, 0x4F, 0x72,
+ 0x1A, 0x05, 0x48, 0xE4, 0x83, 0x29, 0x4B, 0x0C};
+static const unsigned char dhtest_2048_224_yA[] = {
+ 0x1B, 0x3A, 0x63, 0x45, 0x1B, 0xD8, 0x86, 0xE6, 0x99, 0xE6, 0x7B, 0x49,
+ 0x4E, 0x28, 0x8B, 0xD7, 0xF8, 0xE0, 0xD3, 0x70, 0xBA, 0xDD, 0xA7, 0xA0,
+ 0xEF, 0xD2, 0xFD, 0xE7, 0xD8, 0xF6, 0x61, 0x45, 0xCC, 0x9F, 0x28, 0x04,
+ 0x19, 0x97, 0x5E, 0xB8, 0x08, 0x87, 0x7C, 0x8A, 0x4C, 0x0C, 0x8E, 0x0B,
+ 0xD4, 0x8D, 0x4A, 0x54, 0x01, 0xEB, 0x1E, 0x87, 0x76, 0xBF, 0xEE, 0xE1,
+ 0x34, 0xC0, 0x38, 0x31, 0xAC, 0x27, 0x3C, 0xD9, 0xD6, 0x35, 0xAB, 0x0C,
+ 0xE0, 0x06, 0xA4, 0x2A, 0x88, 0x7E, 0x3F, 0x52, 0xFB, 0x87, 0x66, 0xB6,
+ 0x50, 0xF3, 0x80, 0x78, 0xBC, 0x8E, 0xE8, 0x58, 0x0C, 0xEF, 0xE2, 0x43,
+ 0x96, 0x8C, 0xFC, 0x4F, 0x8D, 0xC3, 0xDB, 0x08, 0x45, 0x54, 0x17, 0x1D,
+ 0x41, 0xBF, 0x2E, 0x86, 0x1B, 0x7B, 0xB4, 0xD6, 0x9D, 0xD0, 0xE0, 0x1E,
+ 0xA3, 0x87, 0xCB, 0xAA, 0x5C, 0xA6, 0x72, 0xAF, 0xCB, 0xE8, 0xBD, 0xB9,
+ 0xD6, 0x2D, 0x4C, 0xE1, 0x5F, 0x17, 0xDD, 0x36, 0xF9, 0x1E, 0xD1, 0xEE,
+ 0xDD, 0x65, 0xCA, 0x4A, 0x06, 0x45, 0x5C, 0xB9, 0x4C, 0xD4, 0x0A, 0x52,
+ 0xEC, 0x36, 0x0E, 0x84, 0xB3, 0xC9, 0x26, 0xE2, 0x2C, 0x43, 0x80, 0xA3,
+ 0xBF, 0x30, 0x9D, 0x56, 0x84, 0x97, 0x68, 0xB7, 0xF5, 0x2C, 0xFD, 0xF6,
+ 0x55, 0xFD, 0x05, 0x3A, 0x7E, 0xF7, 0x06, 0x97, 0x9E, 0x7E, 0x58, 0x06,
+ 0xB1, 0x7D, 0xFA, 0xE5, 0x3A, 0xD2, 0xA5, 0xBC, 0x56, 0x8E, 0xBB, 0x52,
+ 0x9A, 0x7A, 0x61, 0xD6, 0x8D, 0x25, 0x6F, 0x8F, 0xC9, 0x7C, 0x07, 0x4A,
+ 0x86, 0x1D, 0x82, 0x7E, 0x2E, 0xBC, 0x8C, 0x61, 0x34, 0x55, 0x31, 0x15,
+ 0xB7, 0x0E, 0x71, 0x03, 0x92, 0x0A, 0xA1, 0x6D, 0x85, 0xE5, 0x2B, 0xCB,
+ 0xAB, 0x8D, 0x78, 0x6A, 0x68, 0x17, 0x8F, 0xA8, 0xFF, 0x7C, 0x2F, 0x5C,
+ 0x71, 0x64, 0x8D, 0x6F};
+static const unsigned char dhtest_2048_224_xB[] = {
+ 0x4F, 0xF3, 0xBC, 0x96, 0xC7, 0xFC, 0x6A, 0x6D, 0x71, 0xD3,
+ 0xB3, 0x63, 0x80, 0x0A, 0x7C, 0xDF, 0xEF, 0x6F, 0xC4, 0x1B,
+ 0x44, 0x17, 0xEA, 0x15, 0x35, 0x3B, 0x75, 0x90};
+static const unsigned char dhtest_2048_224_yB[] = {
+ 0x4D, 0xCE, 0xE9, 0x92, 0xA9, 0x76, 0x2A, 0x13, 0xF2, 0xF8, 0x38, 0x44,
+ 0xAD, 0x3D, 0x77, 0xEE, 0x0E, 0x31, 0xC9, 0x71, 0x8B, 0x3D, 0xB6, 0xC2,
+ 0x03, 0x5D, 0x39, 0x61, 0x18, 0x2C, 0x3E, 0x0B, 0xA2, 0x47, 0xEC, 0x41,
+ 0x82, 0xD7, 0x60, 0xCD, 0x48, 0xD9, 0x95, 0x99, 0x97, 0x06, 0x22, 0xA1,
+ 0x88, 0x1B, 0xBA, 0x2D, 0xC8, 0x22, 0x93, 0x9C, 0x78, 0xC3, 0x91, 0x2C,
+ 0x66, 0x61, 0xFA, 0x54, 0x38, 0xB2, 0x07, 0x66, 0x22, 0x2B, 0x75, 0xE2,
+ 0x4C, 0x2E, 0x3A, 0xD0, 0xC7, 0x28, 0x72, 0x36, 0x12, 0x95, 0x25, 0xEE,
+ 0x15, 0xB5, 0xDD, 0x79, 0x98, 0xAA, 0x04, 0xC4, 0xA9, 0x69, 0x6C, 0xAC,
+ 0xD7, 0x17, 0x20, 0x83, 0xA9, 0x7A, 0x81, 0x66, 0x4E, 0xAD, 0x2C, 0x47,
+ 0x9E, 0x44, 0x4E, 0x4C, 0x06, 0x54, 0xCC, 0x19, 0xE2, 0x8D, 0x77, 0x03,
+ 0xCE, 0xE8, 0xDA, 0xCD, 0x61, 0x26, 0xF5, 0xD6, 0x65, 0xEC, 0x52, 0xC6,
+ 0x72, 0x55, 0xDB, 0x92, 0x01, 0x4B, 0x03, 0x7E, 0xB6, 0x21, 0xA2, 0xAC,
+ 0x8E, 0x36, 0x5D, 0xE0, 0x71, 0xFF, 0xC1, 0x40, 0x0A, 0xCF, 0x07, 0x7A,
+ 0x12, 0x91, 0x3D, 0xD8, 0xDE, 0x89, 0x47, 0x34, 0x37, 0xAB, 0x7B, 0xA3,
+ 0x46, 0x74, 0x3C, 0x1B, 0x21, 0x5D, 0xD9, 0xC1, 0x21, 0x64, 0xA7, 0xE4,
+ 0x05, 0x31, 0x18, 0xD1, 0x99, 0xBE, 0xC8, 0xEF, 0x6F, 0xC5, 0x61, 0x17,
+ 0x0C, 0x84, 0xC8, 0x7D, 0x10, 0xEE, 0x9A, 0x67, 0x4A, 0x1F, 0xA8, 0xFF,
+ 0xE1, 0x3B, 0xDF, 0xBA, 0x1D, 0x44, 0xDE, 0x48, 0x94, 0x6D, 0x68, 0xDC,
+ 0x0C, 0xDD, 0x77, 0x76, 0x35, 0xA7, 0xAB, 0x5B, 0xFB, 0x1E, 0x4B, 0xB7,
+ 0xB8, 0x56, 0xF9, 0x68, 0x27, 0x73, 0x4C, 0x18, 0x41, 0x38, 0xE9, 0x15,
+ 0xD9, 0xC3, 0x00, 0x2E, 0xBC, 0xE5, 0x31, 0x20, 0x54, 0x6A, 0x7E, 0x20,
+ 0x02, 0x14, 0x2B, 0x6C};
+static const unsigned char dhtest_2048_224_Z[] = {
+ 0x34, 0xD9, 0xBD, 0xDC, 0x1B, 0x42, 0x17, 0x6C, 0x31, 0x3F, 0xEA, 0x03,
+ 0x4C, 0x21, 0x03, 0x4D, 0x07, 0x4A, 0x63, 0x13, 0xBB, 0x4E, 0xCD, 0xB3,
+ 0x70, 0x3F, 0xFF, 0x42, 0x45, 0x67, 0xA4, 0x6B, 0xDF, 0x75, 0x53, 0x0E,
+ 0xDE, 0x0A, 0x9D, 0xA5, 0x22, 0x9D, 0xE7, 0xD7, 0x67, 0x32, 0x28, 0x6C,
+ 0xBC, 0x0F, 0x91, 0xDA, 0x4C, 0x3C, 0x85, 0x2F, 0xC0, 0x99, 0xC6, 0x79,
+ 0x53, 0x1D, 0x94, 0xC7, 0x8A, 0xB0, 0x3D, 0x9D, 0xEC, 0xB0, 0xA4, 0xE4,
+ 0xCA, 0x8B, 0x2B, 0xB4, 0x59, 0x1C, 0x40, 0x21, 0xCF, 0x8C, 0xE3, 0xA2,
+ 0x0A, 0x54, 0x1D, 0x33, 0x99, 0x40, 0x17, 0xD0, 0x20, 0x0A, 0xE2, 0xC9,
+ 0x51, 0x6E, 0x2F, 0xF5, 0x14, 0x57, 0x79, 0x26, 0x9E, 0x86, 0x2B, 0x0F,
+ 0xB4, 0x74, 0xA2, 0xD5, 0x6D, 0xC3, 0x1E, 0xD5, 0x69, 0xA7, 0x70, 0x0B,
+ 0x4C, 0x4A, 0xB1, 0x6B, 0x22, 0xA4, 0x55, 0x13, 0x53, 0x1E, 0xF5, 0x23,
+ 0xD7, 0x12, 0x12, 0x07, 0x7B, 0x5A, 0x16, 0x9B, 0xDE, 0xFF, 0xAD, 0x7A,
+ 0xD9, 0x60, 0x82, 0x84, 0xC7, 0x79, 0x5B, 0x6D, 0x5A, 0x51, 0x83, 0xB8,
+ 0x70, 0x66, 0xDE, 0x17, 0xD8, 0xD6, 0x71, 0xC9, 0xEB, 0xD8, 0xEC, 0x89,
+ 0x54, 0x4D, 0x45, 0xEC, 0x06, 0x15, 0x93, 0xD4, 0x42, 0xC6, 0x2A, 0xB9,
+ 0xCE, 0x3B, 0x1C, 0xB9, 0x94, 0x3A, 0x1D, 0x23, 0xA5, 0xEA, 0x3B, 0xCF,
+ 0x21, 0xA0, 0x14, 0x71, 0xE6, 0x7E, 0x00, 0x3E, 0x7F, 0x8A, 0x69, 0xC7,
+ 0x28, 0xBE, 0x49, 0x0B, 0x2F, 0xC8, 0x8C, 0xFE, 0xB9, 0x2D, 0xB6, 0xA2,
+ 0x15, 0xE5, 0xD0, 0x3C, 0x17, 0xC4, 0x64, 0xC9, 0xAC, 0x1A, 0x46, 0xE2,
+ 0x03, 0xE1, 0x3F, 0x95, 0x29, 0x95, 0xFB, 0x03, 0xC6, 0x9D, 0x3C, 0xC4,
+ 0x7F, 0xCB, 0x51, 0x0B, 0x69, 0x98, 0xFF, 0xD3, 0xAA, 0x6D, 0xE7, 0x3C,
+ 0xF9, 0xF6, 0x38, 0x69};
+static const unsigned char dhtest_2048_256_xA[] = {
+ 0x08, 0x81, 0x38, 0x2C, 0xDB, 0x87, 0x66, 0x0C, 0x6D, 0xC1, 0x3E,
+ 0x61, 0x49, 0x38, 0xD5, 0xB9, 0xC8, 0xB2, 0xF2, 0x48, 0x58, 0x1C,
+ 0xC5, 0xE3, 0x1B, 0x35, 0x45, 0x43, 0x97, 0xFC, 0xE5, 0x0E};
+static const unsigned char dhtest_2048_256_yA[] = {
+ 0x2E, 0x93, 0x80, 0xC8, 0x32, 0x3A, 0xF9, 0x75, 0x45, 0xBC, 0x49, 0x41,
+ 0xDE, 0xB0, 0xEC, 0x37, 0x42, 0xC6, 0x2F, 0xE0, 0xEC, 0xE8, 0x24, 0xA6,
+ 0xAB, 0xDB, 0xE6, 0x6C, 0x59, 0xBE, 0xE0, 0x24, 0x29, 0x11, 0xBF, 0xB9,
+ 0x67, 0x23, 0x5C, 0xEB, 0xA3, 0x5A, 0xE1, 0x3E, 0x4E, 0xC7, 0x52, 0xBE,
+ 0x63, 0x0B, 0x92, 0xDC, 0x4B, 0xDE, 0x28, 0x47, 0xA9, 0xC6, 0x2C, 0xB8,
+ 0x15, 0x27, 0x45, 0x42, 0x1F, 0xB7, 0xEB, 0x60, 0xA6, 0x3C, 0x0F, 0xE9,
+ 0x15, 0x9F, 0xCC, 0xE7, 0x26, 0xCE, 0x7C, 0xD8, 0x52, 0x3D, 0x74, 0x50,
+ 0x66, 0x7E, 0xF8, 0x40, 0xE4, 0x91, 0x91, 0x21, 0xEB, 0x5F, 0x01, 0xC8,
+ 0xC9, 0xB0, 0xD3, 0xD6, 0x48, 0xA9, 0x3B, 0xFB, 0x75, 0x68, 0x9E, 0x82,
+ 0x44, 0xAC, 0x13, 0x4A, 0xF5, 0x44, 0x71, 0x1C, 0xE7, 0x9A, 0x02, 0xDC,
+ 0xC3, 0x42, 0x26, 0x68, 0x47, 0x80, 0xDD, 0xDC, 0xB4, 0x98, 0x59, 0x41,
+ 0x06, 0xC3, 0x7F, 0x5B, 0xC7, 0x98, 0x56, 0x48, 0x7A, 0xF5, 0xAB, 0x02,
+ 0x2A, 0x2E, 0x5E, 0x42, 0xF0, 0x98, 0x97, 0xC1, 0xA8, 0x5A, 0x11, 0xEA,
+ 0x02, 0x12, 0xAF, 0x04, 0xD9, 0xB4, 0xCE, 0xBC, 0x93, 0x7C, 0x3C, 0x1A,
+ 0x3E, 0x15, 0xA8, 0xA0, 0x34, 0x2E, 0x33, 0x76, 0x15, 0xC8, 0x4E, 0x7F,
+ 0xE3, 0xB8, 0xB9, 0xB8, 0x7F, 0xB1, 0xE7, 0x3A, 0x15, 0xAF, 0x12, 0xA3,
+ 0x0D, 0x74, 0x6E, 0x06, 0xDF, 0xC3, 0x4F, 0x29, 0x0D, 0x79, 0x7C, 0xE5,
+ 0x1A, 0xA1, 0x3A, 0xA7, 0x85, 0xBF, 0x66, 0x58, 0xAF, 0xF5, 0xE4, 0xB0,
+ 0x93, 0x00, 0x3C, 0xBE, 0xAF, 0x66, 0x5B, 0x3C, 0x2E, 0x11, 0x3A, 0x3A,
+ 0x4E, 0x90, 0x52, 0x69, 0x34, 0x1D, 0xC0, 0x71, 0x14, 0x26, 0x68, 0x5F,
+ 0x4E, 0xF3, 0x7E, 0x86, 0x8A, 0x81, 0x26, 0xFF, 0x3F, 0x22, 0x79, 0xB5,
+ 0x7C, 0xA6, 0x7E, 0x29};
+static const unsigned char dhtest_2048_256_xB[] = {
+ 0x7D, 0x62, 0xA7, 0xE3, 0xEF, 0x36, 0xDE, 0x61, 0x7B, 0x13, 0xD1,
+ 0xAF, 0xB8, 0x2C, 0x78, 0x0D, 0x83, 0xA2, 0x3B, 0xD4, 0xEE, 0x67,
+ 0x05, 0x64, 0x51, 0x21, 0xF3, 0x71, 0xF5, 0x46, 0xA5, 0x3D};
+static const unsigned char dhtest_2048_256_yB[] = {
+ 0x57, 0x5F, 0x03, 0x51, 0xBD, 0x2B, 0x1B, 0x81, 0x74, 0x48, 0xBD, 0xF8,
+ 0x7A, 0x6C, 0x36, 0x2C, 0x1E, 0x28, 0x9D, 0x39, 0x03, 0xA3, 0x0B, 0x98,
+ 0x32, 0xC5, 0x74, 0x1F, 0xA2, 0x50, 0x36, 0x3E, 0x7A, 0xCB, 0xC7, 0xF7,
+ 0x7F, 0x3D, 0xAC, 0xBC, 0x1F, 0x13, 0x1A, 0xDD, 0x8E, 0x03, 0x36, 0x7E,
+ 0xFF, 0x8F, 0xBB, 0xB3, 0xE1, 0xC5, 0x78, 0x44, 0x24, 0x80, 0x9B, 0x25,
+ 0xAF, 0xE4, 0xD2, 0x26, 0x2A, 0x1A, 0x6F, 0xD2, 0xFA, 0xB6, 0x41, 0x05,
+ 0xCA, 0x30, 0xA6, 0x74, 0xE0, 0x7F, 0x78, 0x09, 0x85, 0x20, 0x88, 0x63,
+ 0x2F, 0xC0, 0x49, 0x23, 0x37, 0x91, 0xAD, 0x4E, 0xDD, 0x08, 0x3A, 0x97,
+ 0x8B, 0x88, 0x3E, 0xE6, 0x18, 0xBC, 0x5E, 0x0D, 0xD0, 0x47, 0x41, 0x5F,
+ 0x2D, 0x95, 0xE6, 0x83, 0xCF, 0x14, 0x82, 0x6B, 0x5F, 0xBE, 0x10, 0xD3,
+ 0xCE, 0x41, 0xC6, 0xC1, 0x20, 0xC7, 0x8A, 0xB2, 0x00, 0x08, 0xC6, 0x98,
+ 0xBF, 0x7F, 0x0B, 0xCA, 0xB9, 0xD7, 0xF4, 0x07, 0xBE, 0xD0, 0xF4, 0x3A,
+ 0xFB, 0x29, 0x70, 0xF5, 0x7F, 0x8D, 0x12, 0x04, 0x39, 0x63, 0xE6, 0x6D,
+ 0xDD, 0x32, 0x0D, 0x59, 0x9A, 0xD9, 0x93, 0x6C, 0x8F, 0x44, 0x13, 0x7C,
+ 0x08, 0xB1, 0x80, 0xEC, 0x5E, 0x98, 0x5C, 0xEB, 0xE1, 0x86, 0xF3, 0xD5,
+ 0x49, 0x67, 0x7E, 0x80, 0x60, 0x73, 0x31, 0xEE, 0x17, 0xAF, 0x33, 0x80,
+ 0xA7, 0x25, 0xB0, 0x78, 0x23, 0x17, 0xD7, 0xDD, 0x43, 0xF5, 0x9D, 0x7A,
+ 0xF9, 0x56, 0x8A, 0x9B, 0xB6, 0x3A, 0x84, 0xD3, 0x65, 0xF9, 0x22, 0x44,
+ 0xED, 0x12, 0x09, 0x88, 0x21, 0x93, 0x02, 0xF4, 0x29, 0x24, 0xC7, 0xCA,
+ 0x90, 0xB8, 0x9D, 0x24, 0xF7, 0x1B, 0x0A, 0xB6, 0x97, 0x82, 0x3D, 0x7D,
+ 0xEB, 0x1A, 0xFF, 0x5B, 0x0E, 0x8E, 0x4A, 0x45, 0xD4, 0x9F, 0x7F, 0x53,
+ 0x75, 0x7E, 0x19, 0x13};
+static const unsigned char dhtest_2048_256_Z[] = {
+ 0x86, 0xC7, 0x0B, 0xF8, 0xD0, 0xBB, 0x81, 0xBB, 0x01, 0x07, 0x8A, 0x17,
+ 0x21, 0x9C, 0xB7, 0xD2, 0x72, 0x03, 0xDB, 0x2A, 0x19, 0xC8, 0x77, 0xF1,
+ 0xD1, 0xF1, 0x9F, 0xD7, 0xD7, 0x7E, 0xF2, 0x25, 0x46, 0xA6, 0x8F, 0x00,
+ 0x5A, 0xD5, 0x2D, 0xC8, 0x45, 0x53, 0xB7, 0x8F, 0xC6, 0x03, 0x30, 0xBE,
+ 0x51, 0xEA, 0x7C, 0x06, 0x72, 0xCA, 0xC1, 0x51, 0x5E, 0x4B, 0x35, 0xC0,
+ 0x47, 0xB9, 0xA5, 0x51, 0xB8, 0x8F, 0x39, 0xDC, 0x26, 0xDA, 0x14, 0xA0,
+ 0x9E, 0xF7, 0x47, 0x74, 0xD4, 0x7C, 0x76, 0x2D, 0xD1, 0x77, 0xF9, 0xED,
+ 0x5B, 0xC2, 0xF1, 0x1E, 0x52, 0xC8, 0x79, 0xBD, 0x95, 0x09, 0x85, 0x04,
+ 0xCD, 0x9E, 0xEC, 0xD8, 0xA8, 0xF9, 0xB3, 0xEF, 0xBD, 0x1F, 0x00, 0x8A,
+ 0xC5, 0x85, 0x30, 0x97, 0xD9, 0xD1, 0x83, 0x7F, 0x2B, 0x18, 0xF7, 0x7C,
+ 0xD7, 0xBE, 0x01, 0xAF, 0x80, 0xA7, 0xC7, 0xB5, 0xEA, 0x3C, 0xA5, 0x4C,
+ 0xC0, 0x2D, 0x0C, 0x11, 0x6F, 0xEE, 0x3F, 0x95, 0xBB, 0x87, 0x39, 0x93,
+ 0x85, 0x87, 0x5D, 0x7E, 0x86, 0x74, 0x7E, 0x67, 0x6E, 0x72, 0x89, 0x38,
+ 0xAC, 0xBF, 0xF7, 0x09, 0x8E, 0x05, 0xBE, 0x4D, 0xCF, 0xB2, 0x40, 0x52,
+ 0xB8, 0x3A, 0xEF, 0xFB, 0x14, 0x78, 0x3F, 0x02, 0x9A, 0xDB, 0xDE, 0x7F,
+ 0x53, 0xFA, 0xE9, 0x20, 0x84, 0x22, 0x40, 0x90, 0xE0, 0x07, 0xCE, 0xE9,
+ 0x4D, 0x4B, 0xF2, 0xBA, 0xCE, 0x9F, 0xFD, 0x4B, 0x57, 0xD2, 0xAF, 0x7C,
+ 0x72, 0x4D, 0x0C, 0xAA, 0x19, 0xBF, 0x05, 0x01, 0xF6, 0xF1, 0x7B, 0x4A,
+ 0xA1, 0x0F, 0x42, 0x5E, 0x3E, 0xA7, 0x60, 0x80, 0xB4, 0xB9, 0xD6, 0xB3,
+ 0xCE, 0xFE, 0xA1, 0x15, 0xB2, 0xCE, 0xB8, 0x78, 0x9B, 0xB8, 0xA3, 0xB0,
+ 0xEA, 0x87, 0xFE, 0xBE, 0x63, 0xB6, 0xC8, 0xF8, 0x46, 0xEC, 0x6D, 0xB0,
+ 0xC2, 0x6C, 0x5D, 0x7C};
+
+typedef struct {
+ DH *(*get_param)(const ENGINE *engine);
+ const unsigned char *xA;
+ size_t xA_len;
+ const unsigned char *yA;
+ size_t yA_len;
+ const unsigned char *xB;
+ size_t xB_len;
+ const unsigned char *yB;
+ size_t yB_len;
+ const unsigned char *Z;
+ size_t Z_len;
+} rfc5114_td;
+
+#define make_rfc5114_td(pre) \
+ { \
+ DH_get_##pre, dhtest_##pre##_xA, sizeof(dhtest_##pre##_xA), \
+ dhtest_##pre##_yA, sizeof(dhtest_##pre##_yA), dhtest_##pre##_xB, \
+ sizeof(dhtest_##pre##_xB), dhtest_##pre##_yB, \
+ sizeof(dhtest_##pre##_yB), dhtest_##pre##_Z, sizeof(dhtest_##pre##_Z) \
+ }
+
+static const rfc5114_td rfctd[] = {make_rfc5114_td(1024_160),
+ make_rfc5114_td(2048_224),
+ make_rfc5114_td(2048_256)};
+
+static int run_rfc5114_tests(void) {
+ int i;
+ DH *dhA = NULL, *dhB = NULL;
+ unsigned char *Z1 = NULL, *Z2 = NULL;
+
+ for (i = 0; i < (int)(sizeof(rfctd) / sizeof(rfc5114_td)); i++) {
+ const rfc5114_td *td = rfctd + i;
+ /* Set up DH structures setting key components */
+ dhA = td->get_param(NULL);
+ dhB = td->get_param(NULL);
+ if (!dhA || !dhB)
+ goto bad_err;
+
+ dhA->priv_key = BN_bin2bn(td->xA, td->xA_len, NULL);
+ dhA->pub_key = BN_bin2bn(td->yA, td->yA_len, NULL);
+
+ dhB->priv_key = BN_bin2bn(td->xB, td->xB_len, NULL);
+ dhB->pub_key = BN_bin2bn(td->yB, td->yB_len, NULL);
+
+ if (!dhA->priv_key || !dhA->pub_key || !dhB->priv_key || !dhB->pub_key)
+ goto bad_err;
+
+ if ((td->Z_len != (size_t)DH_size(dhA)) ||
+ (td->Z_len != (size_t)DH_size(dhB)))
+ goto err;
+
+ Z1 = OPENSSL_malloc(DH_size(dhA));
+ Z2 = OPENSSL_malloc(DH_size(dhB));
+ /* Work out shared secrets using both sides and compare
+ * with expected values.
+ */
+ if (!DH_compute_key(Z1, dhB->pub_key, dhA))
+ goto bad_err;
+ if (!DH_compute_key(Z2, dhA->pub_key, dhB))
+ goto bad_err;
+
+ if (memcmp(Z1, td->Z, td->Z_len))
+ goto err;
+ if (memcmp(Z2, td->Z, td->Z_len))
+ goto err;
+
+ printf("RFC5114 parameter test %d OK\n", i + 1);
+
+ DH_free(dhA);
+ dhA = NULL;
+ DH_free(dhB);
+ dhB = NULL;
+ OPENSSL_free(Z1);
+ Z1 = NULL;
+ OPENSSL_free(Z2);
+ Z2 = NULL;
+ }
+
+ printf("PASS\n");
+ return 1;
+
+bad_err:
+ fprintf(stderr, "Initalisation error RFC5114 set %d\n", i + 1);
+ BIO_print_errors_fp(stderr);
+
+err:
+ if (Z1 != NULL) {
+ OPENSSL_free(Z1);
+ }
+ if (Z2 != NULL) {
+ OPENSSL_free(Z2);
+ }
+ if (dhA != NULL) {
+ DH_free(dhA);
+ }
+ if (dhB != NULL) {
+ DH_free(dhB);
+ }
+
+ fprintf(stderr, "Test failed RFC5114 set %d\n", i + 1);
+ return 0;
+}
diff --git a/crypto/dh/internal.h b/crypto/dh/internal.h
new file mode 100644
index 0000000..e4c725c
--- /dev/null
+++ b/crypto/dh/internal.h
@@ -0,0 +1,76 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_DH_INTERNAL_H
+#define OPENSSL_HEADER_DH_INTERNAL_H
+
+#include <openssl/base.h>
+
+#include <openssl/bn.h>
+#include <openssl/ex_data.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_DH_INTERNAL_H */
diff --git a/crypto/dh/params.c b/crypto/dh/params.c
new file mode 100644
index 0000000..4b30c04
--- /dev/null
+++ b/crypto/dh/params.c
@@ -0,0 +1,271 @@
+/* ====================================================================
+ * Copyright (c) 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
+ * 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/dh.h>
+
+#include <openssl/bn.h>
+
+#include "internal.h"
+
+
+#if BN_BITS2 == 64
+static const BN_ULONG dh1024_160_p[] = {
+ 0xDF1FB2BC2E4A4371ULL, 0xE68CFDA76D4DA708ULL, 0x45BF37DF365C1A65ULL,
+ 0xA151AF5F0DC8B4BDULL, 0xFAA31A4FF55BCCC0ULL, 0x4EFFD6FAE5644738ULL,
+ 0x98488E9C219A7372ULL, 0xACCBDD7D90C4BD70ULL, 0x24975C3CD49B83BFULL,
+ 0x13ECB4AEA9061123ULL, 0x9838EF1E2EE652C0ULL, 0x6073E28675A23D18ULL,
+ 0x9A6A9DCA52D23B61ULL, 0x52C99FBCFB06A3C6ULL, 0xDE92DE5EAE5D54ECULL,
+ 0xB10B8F96A080E01DULL};
+static const BN_ULONG dh1024_160_g[] = {
+ 0x855E6EEB22B3B2E5ULL, 0x858F4DCEF97C2A24ULL, 0x2D779D5918D08BC8ULL,
+ 0xD662A4D18E73AFA3ULL, 0x1DBF0A0169B6A28AULL, 0xA6A24C087A091F53ULL,
+ 0x909D0D2263F80A76ULL, 0xD7FBD7D3B9A92EE1ULL, 0x5E91547F9E2749F4ULL,
+ 0x160217B4B01B886AULL, 0x777E690F5504F213ULL, 0x266FEA1E5C41564BULL,
+ 0xD6406CFF14266D31ULL, 0xF8104DD258AC507FULL, 0x6765A442EFB99905ULL,
+ 0xA4D1CBD5C3FD3412ULL};
+static const BN_ULONG dh1024_160_q[] = {
+ 0x64B7CB9D49462353ULL, 0x81A8DF278ABA4E7DULL, 0x00000000F518AA87ULL};
+
+static const BN_ULONG dh2048_224_p[] = {
+ 0x0AC4DFFE0C10E64FULL, 0xCF9DE5384E71B81CULL, 0x7EF363E2FFA31F71ULL,
+ 0xE3FB73C16B8E75B9ULL, 0xC9B53DCF4BA80A29ULL, 0x23F10B0E16E79763ULL,
+ 0xC52172E413042E9BULL, 0xBE60E69CC928B2B9ULL, 0x80CD86A1B9E587E8ULL,
+ 0x315D75E198C641A4ULL, 0xCDF93ACC44328387ULL, 0x15987D9ADC0A486DULL,
+ 0x7310F7121FD5A074ULL, 0x278273C7DE31EFDCULL, 0x1602E714415D9330ULL,
+ 0x81286130BC8985DBULL, 0xB3BF8A3170918836ULL, 0x6A00E0A0B9C49708ULL,
+ 0xC6BA0B2C8BBC27BEULL, 0xC9F98D11ED34DBF6ULL, 0x7AD5B7D0B6C12207ULL,
+ 0xD91E8FEF55B7394BULL, 0x9037C9EDEFDA4DF8ULL, 0x6D3F8152AD6AC212ULL,
+ 0x1DE6B85A1274A0A6ULL, 0xEB3D688A309C180EULL, 0xAF9A3C407BA1DF15ULL,
+ 0xE6FA141DF95A56DBULL, 0xB54B1597B61D0A75ULL, 0xA20D64E5683B9FD1ULL,
+ 0xD660FAA79559C51FULL, 0xAD107E1E9123A9D0ULL};
+static const BN_ULONG dh2048_224_g[] = {
+ 0x84B890D3191F2BFAULL, 0x81BC087F2A7065B3ULL, 0x19C418E1F6EC0179ULL,
+ 0x7B5A0F1C71CFFF4CULL, 0xEDFE72FE9B6AA4BDULL, 0x81E1BCFE94B30269ULL,
+ 0x566AFBB48D6C0191ULL, 0xB539CCE3409D13CDULL, 0x6AA21E7F5F2FF381ULL,
+ 0xD9E263E4770589EFULL, 0x10E183EDD19963DDULL, 0xB70A8137150B8EEBULL,
+ 0x051AE3D428C8F8ACULL, 0xBB77A86F0C1AB15BULL, 0x6E3025E316A330EFULL,
+ 0x19529A45D6F83456ULL, 0xF180EB34118E98D1ULL, 0xB5F6C6B250717CBEULL,
+ 0x09939D54DA7460CDULL, 0xE247150422EA1ED4ULL, 0xB8A762D0521BC98AULL,
+ 0xF4D027275AC1348BULL, 0xC17669101999024AULL, 0xBE5E9001A8D66AD7ULL,
+ 0xC57DB17C620A8652ULL, 0xAB739D7700C29F52ULL, 0xDD921F01A70C4AFAULL,
+ 0xA6824A4E10B9A6F0ULL, 0x74866A08CFE4FFE3ULL, 0x6CDEBE7B89998CAFULL,
+ 0x9DF30B5C8FFDAC50ULL, 0xAC4032EF4F2D9AE3ULL};
+static const BN_ULONG dh2048_224_q[] = {
+ 0xBF389A99B36371EBULL, 0x1F80535A4738CEBCULL, 0xC58D93FE99717710ULL,
+ 0x00000000801C0D34ULL};
+
+static const BN_ULONG dh2048_256_p[] = {
+ 0xDB094AE91E1A1597ULL, 0x693877FAD7EF09CAULL, 0x6116D2276E11715FULL,
+ 0xA4B54330C198AF12ULL, 0x75F26375D7014103ULL, 0xC3A3960A54E710C3ULL,
+ 0xDED4010ABD0BE621ULL, 0xC0B857F689962856ULL, 0xB3CA3F7971506026ULL,
+ 0x1CCACB83E6B486F6ULL, 0x67E144E514056425ULL, 0xF6A167B5A41825D9ULL,
+ 0x3AD8347796524D8EULL, 0xF13C6D9A51BFA4ABULL, 0x2D52526735488A0EULL,
+ 0xB63ACAE1CAA6B790ULL, 0x4FDB70C581B23F76ULL, 0xBC39A0BF12307F5CULL,
+ 0xB941F54EB1E59BB8ULL, 0x6C5BFC11D45F9088ULL, 0x22E0B1EF4275BF7BULL,
+ 0x91F9E6725B4758C0ULL, 0x5A8A9D306BCF67EDULL, 0x209E0C6497517ABDULL,
+ 0x3BF4296D830E9A7CULL, 0x16C3D91134096FAAULL, 0xFAF7DF4561B2AA30ULL,
+ 0xE00DF8F1D61957D4ULL, 0x5D2CEED4435E3B00ULL, 0x8CEEF608660DD0F2ULL,
+ 0xFFBBD19C65195999ULL, 0x87A8E61DB4B6663CULL};
+static const BN_ULONG dh2048_256_g[] = {
+ 0x664B4C0F6CC41659ULL, 0x5E2327CFEF98C582ULL, 0xD647D148D4795451ULL,
+ 0x2F63078490F00EF8ULL, 0x184B523D1DB246C3ULL, 0xC7891428CDC67EB6ULL,
+ 0x7FD028370DF92B52ULL, 0xB3353BBB64E0EC37ULL, 0xECD06E1557CD0915ULL,
+ 0xB7D2BBD2DF016199ULL, 0xC8484B1E052588B9ULL, 0xDB2A3B7313D3FE14ULL,
+ 0xD052B985D182EA0AULL, 0xA4BD1BFFE83B9C80ULL, 0xDFC967C1FB3F2E55ULL,
+ 0xB5045AF2767164E1ULL, 0x1D14348F6F2F9193ULL, 0x64E67982428EBC83ULL,
+ 0x8AC376D282D6ED38ULL, 0x777DE62AAAB8A862ULL, 0xDDF463E5E9EC144BULL,
+ 0x0196F931C77A57F2ULL, 0xA55AE31341000A65ULL, 0x901228F8C28CBB18ULL,
+ 0xBC3773BF7E8C6F62ULL, 0xBE3A6C1B0C6B47B1ULL, 0xFF4FED4AAC0BB555ULL,
+ 0x10DBC15077BE463FULL, 0x07F4793A1A0BA125ULL, 0x4CA7B18F21EF2054ULL,
+ 0x2E77506660EDBD48ULL, 0x3FB32C9B73134D0BULL};
+static const BN_ULONG dh2048_256_q[] = {
+ 0xA308B0FE64F5FBD3ULL, 0x99B1A47D1EB3750BULL, 0xB447997640129DA2ULL,
+ 0x8CF83642A709A097ULL};
+
+#elif BN_BITS2 == 32
+
+static const BN_ULONG dh1024_160_p[] = {
+ 0x2E4A4371, 0xDF1FB2BC, 0x6D4DA708, 0xE68CFDA7, 0x365C1A65, 0x45BF37DF,
+ 0x0DC8B4BD, 0xA151AF5F, 0xF55BCCC0, 0xFAA31A4F, 0xE5644738, 0x4EFFD6FA,
+ 0x219A7372, 0x98488E9C, 0x90C4BD70, 0xACCBDD7D, 0xD49B83BF, 0x24975C3C,
+ 0xA9061123, 0x13ECB4AE, 0x2EE652C0, 0x9838EF1E, 0x75A23D18, 0x6073E286,
+ 0x52D23B61, 0x9A6A9DCA, 0xFB06A3C6, 0x52C99FBC, 0xAE5D54EC, 0xDE92DE5E,
+ 0xA080E01D, 0xB10B8F96};
+static const BN_ULONG dh1024_160_g[] = {
+ 0x22B3B2E5, 0x855E6EEB, 0xF97C2A24, 0x858F4DCE, 0x18D08BC8, 0x2D779D59,
+ 0x8E73AFA3, 0xD662A4D1, 0x69B6A28A, 0x1DBF0A01, 0x7A091F53, 0xA6A24C08,
+ 0x63F80A76, 0x909D0D22, 0xB9A92EE1, 0xD7FBD7D3, 0x9E2749F4, 0x5E91547F,
+ 0xB01B886A, 0x160217B4, 0x5504F213, 0x777E690F, 0x5C41564B, 0x266FEA1E,
+ 0x14266D31, 0xD6406CFF, 0x58AC507F, 0xF8104DD2, 0xEFB99905, 0x6765A442,
+ 0xC3FD3412, 0xA4D1CBD5};
+static const BN_ULONG dh1024_160_q[] = {0x49462353, 0x64B7CB9D, 0x8ABA4E7D,
+ 0x81A8DF27, 0xF518AA87};
+
+static const BN_ULONG dh2048_224_p[] = {
+ 0x0C10E64F, 0x0AC4DFFE, 0x4E71B81C, 0xCF9DE538, 0xFFA31F71, 0x7EF363E2,
+ 0x6B8E75B9, 0xE3FB73C1, 0x4BA80A29, 0xC9B53DCF, 0x16E79763, 0x23F10B0E,
+ 0x13042E9B, 0xC52172E4, 0xC928B2B9, 0xBE60E69C, 0xB9E587E8, 0x80CD86A1,
+ 0x98C641A4, 0x315D75E1, 0x44328387, 0xCDF93ACC, 0xDC0A486D, 0x15987D9A,
+ 0x1FD5A074, 0x7310F712, 0xDE31EFDC, 0x278273C7, 0x415D9330, 0x1602E714,
+ 0xBC8985DB, 0x81286130, 0x70918836, 0xB3BF8A31, 0xB9C49708, 0x6A00E0A0,
+ 0x8BBC27BE, 0xC6BA0B2C, 0xED34DBF6, 0xC9F98D11, 0xB6C12207, 0x7AD5B7D0,
+ 0x55B7394B, 0xD91E8FEF, 0xEFDA4DF8, 0x9037C9ED, 0xAD6AC212, 0x6D3F8152,
+ 0x1274A0A6, 0x1DE6B85A, 0x309C180E, 0xEB3D688A, 0x7BA1DF15, 0xAF9A3C40,
+ 0xF95A56DB, 0xE6FA141D, 0xB61D0A75, 0xB54B1597, 0x683B9FD1, 0xA20D64E5,
+ 0x9559C51F, 0xD660FAA7, 0x9123A9D0, 0xAD107E1E};
+static const BN_ULONG dh2048_224_g[] = {
+ 0x191F2BFA, 0x84B890D3, 0x2A7065B3, 0x81BC087F, 0xF6EC0179, 0x19C418E1,
+ 0x71CFFF4C, 0x7B5A0F1C, 0x9B6AA4BD, 0xEDFE72FE, 0x94B30269, 0x81E1BCFE,
+ 0x8D6C0191, 0x566AFBB4, 0x409D13CD, 0xB539CCE3, 0x5F2FF381, 0x6AA21E7F,
+ 0x770589EF, 0xD9E263E4, 0xD19963DD, 0x10E183ED, 0x150B8EEB, 0xB70A8137,
+ 0x28C8F8AC, 0x051AE3D4, 0x0C1AB15B, 0xBB77A86F, 0x16A330EF, 0x6E3025E3,
+ 0xD6F83456, 0x19529A45, 0x118E98D1, 0xF180EB34, 0x50717CBE, 0xB5F6C6B2,
+ 0xDA7460CD, 0x09939D54, 0x22EA1ED4, 0xE2471504, 0x521BC98A, 0xB8A762D0,
+ 0x5AC1348B, 0xF4D02727, 0x1999024A, 0xC1766910, 0xA8D66AD7, 0xBE5E9001,
+ 0x620A8652, 0xC57DB17C, 0x00C29F52, 0xAB739D77, 0xA70C4AFA, 0xDD921F01,
+ 0x10B9A6F0, 0xA6824A4E, 0xCFE4FFE3, 0x74866A08, 0x89998CAF, 0x6CDEBE7B,
+ 0x8FFDAC50, 0x9DF30B5C, 0x4F2D9AE3, 0xAC4032EF};
+static const BN_ULONG dh2048_224_q[] = {0xB36371EB, 0xBF389A99, 0x4738CEBC,
+ 0x1F80535A, 0x99717710, 0xC58D93FE,
+ 0x801C0D34};
+
+static const BN_ULONG dh2048_256_p[] = {
+ 0x1E1A1597, 0xDB094AE9, 0xD7EF09CA, 0x693877FA, 0x6E11715F, 0x6116D227,
+ 0xC198AF12, 0xA4B54330, 0xD7014103, 0x75F26375, 0x54E710C3, 0xC3A3960A,
+ 0xBD0BE621, 0xDED4010A, 0x89962856, 0xC0B857F6, 0x71506026, 0xB3CA3F79,
+ 0xE6B486F6, 0x1CCACB83, 0x14056425, 0x67E144E5, 0xA41825D9, 0xF6A167B5,
+ 0x96524D8E, 0x3AD83477, 0x51BFA4AB, 0xF13C6D9A, 0x35488A0E, 0x2D525267,
+ 0xCAA6B790, 0xB63ACAE1, 0x81B23F76, 0x4FDB70C5, 0x12307F5C, 0xBC39A0BF,
+ 0xB1E59BB8, 0xB941F54E, 0xD45F9088, 0x6C5BFC11, 0x4275BF7B, 0x22E0B1EF,
+ 0x5B4758C0, 0x91F9E672, 0x6BCF67ED, 0x5A8A9D30, 0x97517ABD, 0x209E0C64,
+ 0x830E9A7C, 0x3BF4296D, 0x34096FAA, 0x16C3D911, 0x61B2AA30, 0xFAF7DF45,
+ 0xD61957D4, 0xE00DF8F1, 0x435E3B00, 0x5D2CEED4, 0x660DD0F2, 0x8CEEF608,
+ 0x65195999, 0xFFBBD19C, 0xB4B6663C, 0x87A8E61D};
+static const BN_ULONG dh2048_256_g[] = {
+ 0x6CC41659, 0x664B4C0F, 0xEF98C582, 0x5E2327CF, 0xD4795451, 0xD647D148,
+ 0x90F00EF8, 0x2F630784, 0x1DB246C3, 0x184B523D, 0xCDC67EB6, 0xC7891428,
+ 0x0DF92B52, 0x7FD02837, 0x64E0EC37, 0xB3353BBB, 0x57CD0915, 0xECD06E15,
+ 0xDF016199, 0xB7D2BBD2, 0x052588B9, 0xC8484B1E, 0x13D3FE14, 0xDB2A3B73,
+ 0xD182EA0A, 0xD052B985, 0xE83B9C80, 0xA4BD1BFF, 0xFB3F2E55, 0xDFC967C1,
+ 0x767164E1, 0xB5045AF2, 0x6F2F9193, 0x1D14348F, 0x428EBC83, 0x64E67982,
+ 0x82D6ED38, 0x8AC376D2, 0xAAB8A862, 0x777DE62A, 0xE9EC144B, 0xDDF463E5,
+ 0xC77A57F2, 0x0196F931, 0x41000A65, 0xA55AE313, 0xC28CBB18, 0x901228F8,
+ 0x7E8C6F62, 0xBC3773BF, 0x0C6B47B1, 0xBE3A6C1B, 0xAC0BB555, 0xFF4FED4A,
+ 0x77BE463F, 0x10DBC150, 0x1A0BA125, 0x07F4793A, 0x21EF2054, 0x4CA7B18F,
+ 0x60EDBD48, 0x2E775066, 0x73134D0B, 0x3FB32C9B};
+static const BN_ULONG dh2048_256_q[] = {0x64F5FBD3, 0xA308B0FE, 0x1EB3750B,
+ 0x99B1A47D, 0x40129DA2, 0xB4479976,
+ 0xA709A097, 0x8CF83642};
+
+#else
+#error "unsupported BN_BITS2"
+#endif
+
+#define STATIC_BIGNUM(x) \
+ { \
+ (BN_ULONG *) x, sizeof(x) / sizeof(BN_ULONG), \
+ sizeof(x) / sizeof(BN_ULONG), 0, BN_FLG_STATIC_DATA \
+ }
+
+struct standard_parameters {
+ BIGNUM p, q, g;
+};
+
+static const struct standard_parameters dh1024_160 = {
+ STATIC_BIGNUM(dh1024_160_p),
+ STATIC_BIGNUM(dh1024_160_q),
+ STATIC_BIGNUM(dh1024_160_g),
+};
+
+static const struct standard_parameters dh2048_224 = {
+ STATIC_BIGNUM(dh2048_224_p),
+ STATIC_BIGNUM(dh2048_224_q),
+ STATIC_BIGNUM(dh2048_224_g),
+};
+
+static const struct standard_parameters dh2048_256 = {
+ STATIC_BIGNUM(dh2048_256_p),
+ STATIC_BIGNUM(dh2048_256_q),
+ STATIC_BIGNUM(dh2048_256_g),
+};
+
+static DH *get_standard_parameters(const struct standard_parameters *params,
+ const ENGINE *engine) {
+ DH *dh;
+
+ dh = DH_new_method(engine);
+ if (!dh) {
+ return NULL;
+ }
+
+ dh->p = BN_dup(¶ms->p);
+ dh->q = BN_dup(¶ms->q);
+ dh->g = BN_dup(¶ms->g);
+ if (!dh->p || !dh->q || !dh->g) {
+ DH_free(dh);
+ return NULL;
+ }
+
+ return dh;
+}
+
+DH *DH_get_1024_160(const ENGINE *engine) {
+ return get_standard_parameters(&dh1024_160, engine);
+}
+
+DH *DH_get_2048_224(const ENGINE *engine) {
+ return get_standard_parameters(&dh2048_224, engine);
+}
+
+DH *DH_get_2048_256(const ENGINE *engine) {
+ return get_standard_parameters(&dh2048_256, engine);
+}
diff --git a/crypto/digest/CMakeLists.txt b/crypto/digest/CMakeLists.txt
new file mode 100644
index 0000000..a7ea708
--- /dev/null
+++ b/crypto/digest/CMakeLists.txt
@@ -0,0 +1,11 @@
+include_directories(. .. ../../include)
+
+add_library(
+ digest
+
+ OBJECT
+
+ digest.c
+ digests.c
+ digest_error.c
+)
diff --git a/crypto/digest/digest.c b/crypto/digest/digest.c
new file mode 100644
index 0000000..2bfb0fa
--- /dev/null
+++ b/crypto/digest/digest.c
@@ -0,0 +1,269 @@
+/* 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/digest.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/err.h>
+#include <openssl/obj.h>
+#include <openssl/mem.h>
+
+#include "internal.h"
+
+
+int EVP_MD_type(const EVP_MD *md) { return md->type; }
+
+const char *EVP_MD_name(const EVP_MD *md) { return OBJ_nid2sn(md->type); }
+
+uint32_t EVP_MD_flags(const EVP_MD *md) { return md->flags; }
+
+size_t EVP_MD_size(const EVP_MD *md) { return md->md_size; }
+
+size_t EVP_MD_block_size(const EVP_MD *md) { return md->block_size; }
+
+
+void EVP_MD_CTX_init(EVP_MD_CTX *ctx) { memset(ctx, 0, sizeof(EVP_MD_CTX)); }
+
+EVP_MD_CTX *EVP_MD_CTX_create(void) {
+ EVP_MD_CTX *ctx = OPENSSL_malloc(sizeof(EVP_MD_CTX));
+
+ if (ctx) {
+ EVP_MD_CTX_init(ctx);
+ }
+
+ return ctx;
+}
+
+int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx) {
+ if (ctx->digest && ctx->digest->ctx_size && ctx->md_data) {
+ OPENSSL_cleanse(ctx->md_data, ctx->digest->ctx_size);
+ OPENSSL_free(ctx->md_data);
+ }
+
+ assert(ctx->pctx == NULL || ctx->pctx_ops != NULL);
+ if (ctx->pctx_ops) {
+ ctx->pctx_ops->free(ctx->pctx);
+ }
+
+ EVP_MD_CTX_init(ctx);
+
+ return 1;
+}
+
+void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx) {
+ if (!ctx) {
+ return;
+ }
+
+ EVP_MD_CTX_cleanup(ctx);
+ OPENSSL_free(ctx);
+}
+
+int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in) {
+ 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);
+ return 0;
+ }
+
+ if (out->digest == in->digest) {
+ /* |md_data| will be the correct size in this case so it's removed from
+ * |out| at this point so that |EVP_MD_CTX_cleanup| doesn't free it and
+ * then it's reused. */
+ tmp_buf = out->md_data;
+ out->md_data = NULL;
+ }
+
+ EVP_MD_CTX_cleanup(out);
+ memcpy(out, in, sizeof(EVP_MD_CTX));
+
+ 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);
+ return 0;
+ }
+ }
+ memcpy(out->md_data, in->md_data, in->digest->ctx_size);
+ }
+
+ assert(in->pctx == NULL || in->pctx_ops != NULL);
+ if (in->pctx && in->pctx_ops) {
+ out->pctx = in->pctx_ops->dup(in->pctx);
+ if (!out->pctx) {
+ EVP_MD_CTX_cleanup(out);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+int EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in) {
+ EVP_MD_CTX_init(out);
+ return EVP_MD_CTX_copy_ex(out, in);
+}
+
+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) {
+ OPENSSL_free(ctx->md_data);
+ }
+ ctx->digest = type;
+ if (!(ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) && type->ctx_size) {
+ ctx->update = type->update;
+ ctx->md_data = OPENSSL_malloc(type->ctx_size);
+ if (ctx->md_data == NULL) {
+ OPENSSL_PUT_ERROR(DIGEST, EVP_DigestInit_ex, 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;
+ }
+
+ return ctx->digest->init(ctx);
+}
+
+int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type) {
+ EVP_MD_CTX_init(ctx);
+ return EVP_DigestInit_ex(ctx, type, NULL);
+}
+
+int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) {
+ return ctx->update(ctx, data, len);
+}
+
+int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, uint8_t *md_out, unsigned int *size) {
+ int ret;
+
+ assert(ctx->digest->md_size <= EVP_MAX_MD_SIZE);
+ ret = ctx->digest->final(ctx, md_out);
+ if (size != NULL) {
+ *size = ctx->digest->md_size;
+ }
+ OPENSSL_cleanse(ctx->md_data, ctx->digest->ctx_size);
+
+ return ret;
+}
+
+int EVP_DigestFinal(EVP_MD_CTX *ctx, uint8_t *md, unsigned int *size) {
+ int ret = EVP_DigestFinal_ex(ctx, md, size);
+ EVP_MD_CTX_cleanup(ctx);
+ return ret;
+}
+
+int EVP_Digest(const void *data, size_t count, uint8_t *out_md,
+ unsigned int *out_size, const EVP_MD *type, ENGINE *impl) {
+ EVP_MD_CTX ctx;
+ int ret;
+
+ EVP_MD_CTX_init(&ctx);
+ ret = EVP_DigestInit_ex(&ctx, type, impl) &&
+ EVP_DigestUpdate(&ctx, data, count) &&
+ EVP_DigestFinal_ex(&ctx, out_md, out_size);
+ EVP_MD_CTX_cleanup(&ctx);
+
+ return ret;
+}
+
+
+const EVP_MD *EVP_MD_CTX_md(const EVP_MD_CTX *ctx) {
+ if (ctx == NULL) {
+ return NULL;
+ }
+ return ctx->digest;
+}
+
+unsigned EVP_MD_CTX_size(const EVP_MD_CTX *ctx) {
+ return EVP_MD_size(EVP_MD_CTX_md(ctx));
+}
+
+unsigned EVP_MD_CTX_block_size(const EVP_MD_CTX *ctx) {
+ return EVP_MD_block_size(EVP_MD_CTX_md(ctx));
+}
+
+int EVP_MD_CTX_type(const EVP_MD_CTX *ctx) {
+ 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;
+}
+
+void EVP_MD_CTX_clear_flags(EVP_MD_CTX *ctx, uint32_t flags) {
+ ctx->flags &= ~flags;
+}
+
+uint32_t EVP_MD_CTX_test_flags(const EVP_MD_CTX *ctx, uint32_t flags) {
+ return ctx->flags & flags;
+}
diff --git a/crypto/digest/digest.h b/crypto/digest/digest.h
new file mode 100644
index 0000000..9a91908
--- /dev/null
+++ b/crypto/digest/digest.h
@@ -0,0 +1,267 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_DIGEST_H
+#define OPENSSL_HEADER_DIGEST_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* Digest functions.
+ *
+ * An EVP_MD abstracts the details of a specific hash function allowing code to
+ * deal with the concept of a "hash function" without needing to know exactly
+ * which hash function it is. */
+
+
+/* Hash algorithms.
+ *
+ * The following functions return |EVP_MD| objects that implement the named hash
+ * function. */
+
+const EVP_MD *EVP_md5(void);
+const EVP_MD *EVP_sha1(void);
+const EVP_MD *EVP_sha224(void);
+const EVP_MD *EVP_sha256(void);
+const EVP_MD *EVP_sha384(void);
+const EVP_MD *EVP_sha512(void);
+
+/* EVP_get_digestbynid returns an |EVP_MD| for the given NID, or NULL if no
+ * such digest is known. */
+const EVP_MD *EVP_get_digestbynid(int nid);
+
+/* EVP_get_digestbyobj returns an |EVP_MD| for the given |ASN1_OBJECT|, or NULL
+ * if no such digest is known. */
+const EVP_MD *EVP_get_digestbyobj(const ASN1_OBJECT *obj);
+
+
+/* Digest contexts.
+ *
+ * An EVP_MD_CTX represents the state of a specific digest operation in
+ * progress. */
+
+/* EVP_MD_CTX_init initialises an, already allocated, |EVP_MD_CTX|. */
+void EVP_MD_CTX_init(EVP_MD_CTX *ctx);
+
+/* EVP_MD_CTX_create allocates and initialises a fresh |EVP_MD_CTX| and returns
+ * it, or NULL on allocation failure. */
+EVP_MD_CTX *EVP_MD_CTX_create(void);
+
+/* EVP_MD_CTX_cleanup frees any resources owned by |ctx| and resets it to a
+ * freshly initialised state. It does not free |ctx| itself. It returns one. */
+int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx);
+
+/* EVP_MD_CTX_destroy calls |EVP_MD_CTX_cleanup| and then frees |ctx| itself. */
+void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx);
+
+/* EVP_MD_CTX_copy_ex sets |out|, which must already be initialised, to be a
+ * copy of |in|. It returns one on success and zero on error. */
+int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in);
+
+
+/* Digest operations. */
+
+/* EVP_DigestInit_ex configures |ctx|, which must already have been
+ * initialised, for a fresh hashing operation using |type|. It returns one on
+ * success and zero otherwise. */
+int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *engine);
+
+/* EVP_DigestInit acts like |EVP_DigestInit_ex| except that |ctx| is
+ * initialised before use. */
+int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type);
+
+/* EVP_DigestUpdate hashes |len| bytes from |data| into the hashing operation
+ * in |ctx|. It returns one on success and zero otherwise. */
+int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, size_t len);
+
+/* EVP_MAX_MD_SIZE is the largest digest size supported. Functions that output
+ * a digest generally require the buffer have at least this much space. */
+#define EVP_MAX_MD_SIZE 64 /* SHA-512 is the longest so far. */
+
+/* EVP_DigestFinal_ex finishes the digest in |ctx| and writes the output to
+ * |md_out|. At most |EVP_MAX_MD_SIZE| bytes are written. If |out_size| is not
+ * NULL then |*out_size| is set to the number of bytes written. It returns one
+ * on success and zero otherwise. After this call, the hash cannot be updated
+ * or finished again until |EVP_DigestFinal_ex| is called to start another
+ * hashing operation. */
+int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, uint8_t *md_out,
+ unsigned int *out_size);
+
+/* EVP_DigestFinal acts like |EVP_DigestFinal_ex| except that
+ * |EVP_MD_CTX_cleanup| is called on |ctx| before returning. */
+int EVP_DigestFinal(EVP_MD_CTX *ctx, uint8_t *md_out, unsigned int *out_size);
+
+/* EVP_Digest performs a complete hashing operation in one call. It hashes
+ * |len| bytes from |data| and writes the digest to |md_out|. At most
+ * |EVP_MAX_MD_SIZE| bytes are written. If |out_size| is not NULL then
+ * |*out_size| is set to the number of bytes written. It returns one on success
+ * and zero otherwise. */
+int EVP_Digest(const void *data, size_t len, uint8_t *md_out,
+ unsigned int *md_out_size, const EVP_MD *type, ENGINE *impl);
+
+
+/* Digest function accessors.
+ *
+ * These functions allow code to learn details about an abstract hash
+ * function. */
+
+/* EVP_MD_type returns a NID identifing |md|. (For example, |NID_md5|.) */
+int EVP_MD_type(const EVP_MD *md);
+
+/* EVP_MD_name returns the short name for |md| or NULL if no name is known. */
+const char *EVP_MD_name(const EVP_MD *md);
+
+/* EVP_MD_flags returns the flags for |md|, which is a set of |EVP_MD_FLAG_*|
+ * values, ORed together. */
+uint32_t EVP_MD_flags(const EVP_MD *md);
+
+/* EVP_MD_size returns the digest size of |md|, in bytes. */
+size_t EVP_MD_size(const EVP_MD *md);
+
+/* EVP_MD_block_size returns the native block-size of |md|. */
+size_t EVP_MD_block_size(const EVP_MD *md);
+
+/* EVP_MD_FLAG_PKEY_DIGEST indicates the the digest function is used with a
+ * specific public key in order to verify signatures. (For example,
+ * EVP_dss1.) */
+#define EVP_MD_FLAG_PKEY_DIGEST 1
+
+/* EVP_MD_FLAG_DIGALGID_ABSENT indicates that the parameter type in an X.509
+ * DigestAlgorithmIdentifier representing this digest function should be
+ * undefined rather than NULL. */
+#define EVP_MD_FLAG_DIGALGID_ABSENT 2
+
+
+/* Deprecated functions. */
+
+/* EVP_MD_CTX_copy sets |out|, which must /not/ be initialised, to be a copy of
+ * |in|. It returns one on success and zero on error. */
+int EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in);
+
+
+/* Digest operation accessors. */
+
+/* EVP_MD_CTX_md returns the underlying digest function, or NULL if one has not
+ * been set. */
+const EVP_MD *EVP_MD_CTX_md(const EVP_MD_CTX *ctx);
+
+/* EVP_MD_CTX_size returns the digest size of |ctx|. It will crash if a digest
+ * hasn't been set on |ctx|. */
+unsigned EVP_MD_CTX_size(const EVP_MD_CTX *ctx);
+
+/* EVP_MD_CTX_block_size returns the block size of the digest function used by
+ * |ctx|. It will crash if a digest hasn't been set on |ctx|. */
+unsigned EVP_MD_CTX_block_size(const EVP_MD_CTX *ctx);
+
+/* EVP_MD_CTX_type returns a NID describing the digest function used by |ctx|.
+ * (For example, |NID_md5|.) It will crash if a digest hasn't been set on
+ * |ctx|. */
+int EVP_MD_CTX_type(const EVP_MD_CTX *ctx);
+
+/* EVP_MD_CTX_set_flags ORs |flags| into the flags member of |ctx|. */
+void EVP_MD_CTX_set_flags(EVP_MD_CTX *ctx, uint32_t flags);
+
+/* EVP_MD_CTX_clear_flags clears any bits from the flags member of |ctx| that
+ * are set in |flags|. */
+void EVP_MD_CTX_clear_flags(EVP_MD_CTX *ctx, uint32_t flags);
+
+/* EVP_MD_CTX_test_flags returns the AND of |flags| and the flags member of
+ * |ctx|. */
+uint32_t EVP_MD_CTX_test_flags(const EVP_MD_CTX *ctx, uint32_t flags);
+
+
+struct evp_md_pctx_ops;
+
+struct env_md_ctx_st {
+ /* digest is the underlying digest function, or NULL if not set. */
+ const EVP_MD *digest;
+ /* flags is the OR of a number of |EVP_MD_CTX_FLAG_*| values. */
+ uint32_t flags;
+ /* md_data points to a block of memory that contains the hash-specific
+ * context. */
+ void *md_data;
+ /* update is usually copied from |digest->update| but can differ in some
+ * cases, i.e. HMAC. */
+ int (*update)(EVP_MD_CTX *ctx, const void *data, size_t count);
+
+ /* pctx is an opaque (at this layer) pointer to additional context that
+ * EVP_PKEY functions may store in this object. */
+ EVP_PKEY_CTX *pctx;
+
+ /* pctx_ops, if not NULL, points to a vtable that contains functions to
+ * manipulate |pctx|. */
+ const struct evp_md_pctx_ops *pctx_ops;
+} /* EVP_MD_CTX */;
+
+/* 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. */
+#define EVP_MD_CTX_FLAG_NO_INIT 1
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#define DIGEST_F_EVP_DigestInit_ex 100
+#define DIGEST_F_EVP_MD_CTX_copy_ex 101
+#define DIGEST_R_INPUT_NOT_INITIALIZED 100
+
+#endif /* OPENSSL_HEADER_DIGEST_H */
diff --git a/crypto/digest/digest_error.c b/crypto/digest/digest_error.c
new file mode 100644
index 0000000..e80a5df
--- /dev/null
+++ b/crypto/digest/digest_error.c
@@ -0,0 +1,24 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/err.h>
+
+#include "digest.h"
+
+const ERR_STRING_DATA DIGEST_error_string_data[] = {
+ {ERR_PACK(ERR_LIB_DIGEST, DIGEST_F_EVP_DigestInit_ex, 0), "EVP_DigestInit_ex"},
+ {ERR_PACK(ERR_LIB_DIGEST, DIGEST_F_EVP_MD_CTX_copy_ex, 0), "EVP_MD_CTX_copy_ex"},
+ {ERR_PACK(ERR_LIB_DIGEST, 0, DIGEST_R_INPUT_NOT_INITIALIZED), "INPUT_NOT_INITIALIZED"},
+ {0, NULL},
+};
diff --git a/crypto/digest/digests.c b/crypto/digest/digests.c
new file mode 100644
index 0000000..b757ea8
--- /dev/null
+++ b/crypto/digest/digests.c
@@ -0,0 +1,215 @@
+/* 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/digest.h>
+
+#include <openssl/md5.h>
+#include <openssl/obj.h>
+#include <openssl/sha.h>
+
+#include "internal.h"
+
+
+static int md5_init(EVP_MD_CTX *ctx) { return MD5_Init(ctx->md_data); }
+
+static int md5_update(EVP_MD_CTX *ctx, const void *data, size_t count) {
+ return MD5_Update(ctx->md_data, data, count);
+}
+
+static int md5_final(EVP_MD_CTX *ctx, unsigned char *out) {
+ return MD5_Final(out, ctx->md_data);
+}
+
+static const EVP_MD md5_md = {
+ NID_md5, MD5_DIGEST_LENGTH, 0 /* flags */, md5_init,
+ md5_update, md5_final, 64 /* block size */, sizeof(MD5_CTX),
+};
+
+const EVP_MD *EVP_md5(void) { return &md5_md; }
+
+
+static int sha1_init(EVP_MD_CTX *ctx) { return SHA1_Init(ctx->md_data); }
+
+static int sha1_update(EVP_MD_CTX *ctx, const void *data, size_t count) {
+ return SHA1_Update(ctx->md_data, data, count);
+}
+
+static int sha1_final(EVP_MD_CTX *ctx, unsigned char *md) {
+ return SHA1_Final(md, ctx->md_data);
+}
+
+static const EVP_MD sha1_md = {
+ NID_sha1, SHA_DIGEST_LENGTH, 0 /* flags */, sha1_init,
+ sha1_update, sha1_final, 64 /* block size */, sizeof(SHA_CTX),
+};
+
+const EVP_MD *EVP_sha1(void) { return &sha1_md; }
+
+
+static int sha224_init(EVP_MD_CTX *ctx) { return SHA224_Init(ctx->md_data); }
+
+static int sha224_update(EVP_MD_CTX *ctx, const void *data, size_t count) {
+ return SHA224_Update(ctx->md_data, data, count);
+}
+
+static int sha224_final(EVP_MD_CTX *ctx, unsigned char *md) {
+ return SHA224_Final(md, ctx->md_data);
+}
+
+static const EVP_MD sha224_md = {
+ NID_sha224, SHA224_DIGEST_LENGTH, 0 /* flags */,
+ sha224_init, sha224_update, sha224_final,
+ 64 /* block size */, sizeof(SHA256_CTX),
+};
+
+const EVP_MD *EVP_sha224(void) { return &sha224_md; }
+
+
+static int sha256_init(EVP_MD_CTX *ctx) { return SHA256_Init(ctx->md_data); }
+
+static int sha256_update(EVP_MD_CTX *ctx, const void *data, size_t count) {
+ return SHA256_Update(ctx->md_data, data, count);
+}
+
+static int sha256_final(EVP_MD_CTX *ctx, unsigned char *md) {
+ return SHA256_Final(md, ctx->md_data);
+}
+
+static const EVP_MD sha256_md = {
+ NID_sha256, SHA256_DIGEST_LENGTH, 0 /* flags */,
+ sha256_init, sha256_update, sha256_final,
+ 64 /* block size */, sizeof(SHA256_CTX),
+};
+
+const EVP_MD *EVP_sha256(void) { return &sha256_md; }
+
+
+static int sha384_init(EVP_MD_CTX *ctx) { return SHA384_Init(ctx->md_data); }
+
+static int sha384_update(EVP_MD_CTX *ctx, const void *data, size_t count) {
+ return SHA384_Update(ctx->md_data, data, count);
+}
+
+static int sha384_final(EVP_MD_CTX *ctx, unsigned char *md) {
+ return SHA384_Final(md, ctx->md_data);
+}
+
+static const EVP_MD sha384_md = {
+ NID_sha384, SHA384_DIGEST_LENGTH, 0 /* flags */,
+ sha384_init, sha384_update, sha384_final,
+ 128 /* block size */, sizeof(SHA512_CTX),
+};
+
+const EVP_MD *EVP_sha384(void) { return &sha384_md; }
+
+
+static int sha512_init(EVP_MD_CTX *ctx) { return SHA512_Init(ctx->md_data); }
+
+static int sha512_update(EVP_MD_CTX *ctx, const void *data, size_t count) {
+ return SHA512_Update(ctx->md_data, data, count);
+}
+
+static int sha512_final(EVP_MD_CTX *ctx, unsigned char *md) {
+ return SHA512_Final(md, ctx->md_data);
+}
+
+static const EVP_MD sha512_md = {
+ NID_sha512, SHA512_DIGEST_LENGTH, 0 /* flags */,
+ sha512_init, sha512_update, sha512_final,
+ 128 /* block size */, sizeof(SHA512_CTX),
+};
+
+const EVP_MD *EVP_sha512(void) { return &sha512_md; }
+
+struct nid_to_digest {
+ int nid;
+ const EVP_MD *(*md_func)();
+};
+
+static const struct nid_to_digest nid_to_digest_mapping[] = {
+ { NID_md5, EVP_md5 },
+ { NID_sha1, EVP_sha1 },
+ { NID_sha224, EVP_sha224 },
+ { NID_sha256, EVP_sha256 },
+ { NID_sha384, EVP_sha384 },
+ { NID_sha512, EVP_sha512 },
+ { NID_dsaWithSHA, EVP_sha1 },
+ { NID_dsaWithSHA1, EVP_sha1 },
+ { NID_ecdsa_with_SHA1, EVP_sha1 },
+ { NID_md5WithRSAEncryption, EVP_md5 },
+ { NID_sha1WithRSAEncryption, EVP_sha1 },
+ { NID_sha224WithRSAEncryption, EVP_sha224 },
+ { NID_sha256WithRSAEncryption, EVP_sha256 },
+ { NID_sha384WithRSAEncryption, EVP_sha384 },
+ { NID_sha512WithRSAEncryption, EVP_sha512 },
+};
+
+const EVP_MD* EVP_get_digestbynid(int nid) {
+ unsigned i;
+
+ for (i = 0; i < sizeof(nid_to_digest_mapping) / sizeof(struct nid_to_digest);
+ i++) {
+ if (nid_to_digest_mapping[i].nid == nid) {
+ return nid_to_digest_mapping[i].md_func();
+ }
+ }
+
+ return NULL;
+}
+
+const EVP_MD* EVP_get_digestbyobj(const ASN1_OBJECT *obj) {
+ return EVP_get_digestbynid(OBJ_obj2nid(obj));
+}
diff --git a/crypto/digest/internal.h b/crypto/digest/internal.h
new file mode 100644
index 0000000..94dbfaa
--- /dev/null
+++ b/crypto/digest/internal.h
@@ -0,0 +1,117 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_DIGEST_INTERNAL_H
+#define OPENSSL_HEADER_DIGEST_INTERNAL_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+struct env_md_st {
+ /* type contains a NID identifing the digest function. (For example,
+ * NID_md5.) */
+ int type;
+
+ /* md_size contains the size, in bytes, of the resulting digest. */
+ unsigned md_size;
+
+ /* flags contains the OR of |EVP_MD_FLAG_*| values. */
+ uint32_t flags;
+
+ /* init initialises the state in |ctx->md_data|. It returns one on success
+ * and zero otherwise. */
+ int (*init)(EVP_MD_CTX *ctx);
+
+ /* update hashes |len| bytes of |data| into the state in |ctx->md_data|. */
+ int (*update)(EVP_MD_CTX *ctx, const void *data, size_t count);
+
+ /* final completes the hash and writes |md_size| bytes of digest to |out|. */
+ int (*final)(EVP_MD_CTX *ctx, uint8_t *out);
+
+ /* block_size contains the hash's native block size. */
+ unsigned block_size;
+
+ /* ctx_size contains the size, in bytes, of the state of the hash function. */
+ unsigned ctx_size;
+};
+
+/* 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
+ * functions. */
+struct evp_md_pctx_ops {
+ /* free is called when an |EVP_MD_CTX| is being freed and the |pctx| also
+ * needs to be freed. */
+ void (*free) (EVP_PKEY_CTX *pctx);
+
+ /* 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);
+};
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_DIGEST_INTERNAL */
diff --git a/crypto/digest/md32_common.h b/crypto/digest/md32_common.h
new file mode 100644
index 0000000..d9e8432
--- /dev/null
+++ b/crypto/digest/md32_common.h
@@ -0,0 +1,370 @@
+/* ====================================================================
+ * Copyright (c) 1999-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.
+ * ==================================================================== */
+
+#ifndef OPENSSL_HEADER_MD32_COMMON_H
+#define OPENSSL_HEADER_MD32_COMMON_H
+
+#include <openssl/base.h>
+
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#define asm __asm__
+
+/* This is a generic 32 bit "collector" for message digest algorithms.
+ * Whenever needed it collects input character stream into chunks of
+ * 32 bit values and invokes a block function that performs actual hash
+ * calculations.
+ *
+ * Porting guide.
+ *
+ * Obligatory macros:
+ *
+ * DATA_ORDER_IS_BIG_ENDIAN or DATA_ORDER_IS_LITTLE_ENDIAN
+ * this macro defines byte order of input stream.
+ * HASH_CBLOCK
+ * size of a unit chunk HASH_BLOCK operates on.
+ * HASH_LONG
+ * has to be at lest 32 bit wide, if it's wider, then
+ * HASH_LONG_LOG2 *has to* be defined along
+ * HASH_CTX
+ * context structure that at least contains following
+ * members:
+ * typedef struct {
+ * ...
+ * HASH_LONG Nl,Nh;
+ * either {
+ * HASH_LONG data[HASH_LBLOCK];
+ * unsigned char data[HASH_CBLOCK];
+ * };
+ * unsigned int num;
+ * ...
+ * } HASH_CTX;
+ * data[] vector is expected to be zeroed upon first call to
+ * HASH_UPDATE.
+ * HASH_UPDATE
+ * name of "Update" function, implemented here.
+ * HASH_TRANSFORM
+ * name of "Transform" function, implemented here.
+ * HASH_FINAL
+ * name of "Final" function, implemented here.
+ * HASH_BLOCK_DATA_ORDER
+ * name of "block" function capable of treating *unaligned* input
+ * message in original (data) byte order, implemented externally.
+ * HASH_MAKE_STRING
+ * macro convering context variables to an ASCII hash string.
+ *
+ * MD5 example:
+ *
+ * #define DATA_ORDER_IS_LITTLE_ENDIAN
+ *
+ * #define HASH_LONG MD5_LONG
+ * #define HASH_LONG_LOG2 MD5_LONG_LOG2
+ * #define HASH_CTX MD5_CTX
+ * #define HASH_CBLOCK MD5_CBLOCK
+ * #define HASH_UPDATE MD5_Update
+ * #define HASH_TRANSFORM MD5_Transform
+ * #define HASH_FINAL MD5_Final
+ * #define HASH_BLOCK_DATA_ORDER md5_block_data_order
+ *
+ * <appro@fy.chalmers.se>
+ */
+
+#if !defined(DATA_ORDER_IS_BIG_ENDIAN) && !defined(DATA_ORDER_IS_LITTLE_ENDIAN)
+#error "DATA_ORDER must be defined!"
+#endif
+
+#ifndef HASH_CBLOCK
+#error "HASH_CBLOCK must be defined!"
+#endif
+#ifndef HASH_LONG
+#error "HASH_LONG must be defined!"
+#endif
+#ifndef HASH_CTX
+#error "HASH_CTX must be defined!"
+#endif
+
+#ifndef HASH_UPDATE
+#error "HASH_UPDATE must be defined!"
+#endif
+#ifndef HASH_TRANSFORM
+#error "HASH_TRANSFORM must be defined!"
+#endif
+#ifndef HASH_FINAL
+#error "HASH_FINAL must be defined!"
+#endif
+
+#ifndef HASH_BLOCK_DATA_ORDER
+#error "HASH_BLOCK_DATA_ORDER must be defined!"
+#endif
+
+/*
+ * Engage compiler specific rotate intrinsic function if available.
+ */
+#undef ROTATE
+# if defined(_MSC_VER)
+# define ROTATE(a,n) _lrotl(a,n)
+# elif defined(__ICC)
+# define ROTATE(a,n) _rotl(a,n)
+# elif defined(__GNUC__) && __GNUC__>=2 && !defined(OPENSSL_NO_ASM)
+ /*
+ * Some GNU C inline assembler templates. Note that these are
+ * rotates by *constant* number of bits! But that's exactly
+ * what we need here...
+ * <appro@fy.chalmers.se>
+ */
+# if defined(OPENSSL_X86) || defined(OPENSSL_X86_64)
+# define ROTATE(a,n) ({ register unsigned int ret; \
+ asm ( \
+ "roll %1,%0" \
+ : "=r"(ret) \
+ : "I"(n), "0"((unsigned int)(a)) \
+ : "cc"); \
+ ret; \
+ })
+# endif
+#endif /* PEDANTIC */
+
+#ifndef ROTATE
+#define ROTATE(a,n) (((a)<<(n))|(((a)&0xffffffff)>>(32-(n))))
+#endif
+
+#if defined(DATA_ORDER_IS_BIG_ENDIAN)
+
+#ifndef PEDANTIC
+# if defined(__GNUC__) && __GNUC__>=2 && !defined(OPENSSL_NO_ASM)
+# if defined(OPENSSL_X86) || defined(OPENSSL_X86_64)
+ /*
+ * This gives ~30-40% performance improvement in SHA-256 compiled
+ * with gcc [on P4]. Well, first macro to be frank. We can pull
+ * this trick on x86* platforms only, because these CPUs can fetch
+ * unaligned data without raising an exception.
+ */
+# define HOST_c2l(c,l) ({ unsigned int r=*((const unsigned int *)(c)); \
+ asm ("bswapl %0":"=r"(r):"0"(r)); \
+ (c)+=4; (l)=r; })
+# define HOST_l2c(l,c) ({ unsigned int r=(l); \
+ asm ("bswapl %0":"=r"(r):"0"(r)); \
+ *((unsigned int *)(c))=r; (c)+=4; r; })
+# elif defined(__aarch64__)
+# if defined(__BYTE_ORDER__)
+# if defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
+# define HOST_c2l(c,l) ({ unsigned int r; \
+ asm ("rev %w0,%w1" \
+ :"=r"(r) \
+ :"r"(*((const unsigned int *)(c))));\
+ (c)+=4; (l)=r; })
+# define HOST_l2c(l,c) ({ unsigned int r; \
+ asm ("rev %w0,%w1" \
+ :"=r"(r) \
+ :"r"((unsigned int)(l)));\
+ *((unsigned int *)(c))=r; (c)+=4; r; })
+# elif defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__==__ORDER_BIG_ENDIAN__
+# define HOST_c2l(c,l) ((l)=*((const unsigned int *)(c)), (c)+=4, (l))
+# define HOST_l2c(l,c) (*((unsigned int *)(c))=(l), (c)+=4, (l))
+# endif
+# endif
+# endif
+# endif
+#endif
+
+#ifndef HOST_c2l
+#define HOST_c2l(c,l) (l =(((unsigned long)(*((c)++)))<<24), \
+ l|=(((unsigned long)(*((c)++)))<<16), \
+ l|=(((unsigned long)(*((c)++)))<< 8), \
+ l|=(((unsigned long)(*((c)++))) ), \
+ l)
+#endif
+#ifndef HOST_l2c
+#define HOST_l2c(l,c) (*((c)++)=(unsigned char)(((l)>>24)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+ *((c)++)=(unsigned char)(((l) )&0xff), \
+ l)
+#endif
+
+#elif defined(DATA_ORDER_IS_LITTLE_ENDIAN)
+
+#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64)
+ /* See comment in DATA_ORDER_IS_BIG_ENDIAN section. */
+# define HOST_c2l(c,l) ((l)=*((const unsigned int *)(c)), (c)+=4, l)
+# define HOST_l2c(l,c) (*((unsigned int *)(c))=(l), (c)+=4, l)
+#endif
+
+#ifndef HOST_c2l
+#define HOST_c2l(c,l) (l =(((unsigned long)(*((c)++))) ), \
+ l|=(((unsigned long)(*((c)++)))<< 8), \
+ l|=(((unsigned long)(*((c)++)))<<16), \
+ l|=(((unsigned long)(*((c)++)))<<24), \
+ l)
+#endif
+#ifndef HOST_l2c
+#define HOST_l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>24)&0xff), \
+ l)
+#endif
+
+#endif
+
+int HASH_UPDATE (HASH_CTX *c, const void *data_, size_t len)
+ {
+ const unsigned char *data=data_;
+ unsigned char *p;
+ HASH_LONG l;
+ size_t n;
+
+ if (len==0) return 1;
+
+ l=(c->Nl+(((HASH_LONG)len)<<3))&0xffffffffUL;
+ /* 95-05-24 eay Fixed a bug with the overflow handling, thanks to
+ * Wei Dai <weidai@eskimo.com> for pointing it out. */
+ if (l < c->Nl) /* overflow */
+ c->Nh++;
+ c->Nh+=(HASH_LONG)(len>>29); /* might cause compiler warning on 16-bit */
+ c->Nl=l;
+
+ n = c->num;
+ if (n != 0)
+ {
+ p=(unsigned char *)c->data;
+
+ if (len >= HASH_CBLOCK || len+n >= HASH_CBLOCK)
+ {
+ memcpy (p+n,data,HASH_CBLOCK-n);
+ HASH_BLOCK_DATA_ORDER (c,p,1);
+ n = HASH_CBLOCK-n;
+ data += n;
+ len -= n;
+ c->num = 0;
+ memset (p,0,HASH_CBLOCK); /* keep it zeroed */
+ }
+ else
+ {
+ memcpy (p+n,data,len);
+ c->num += (unsigned int)len;
+ return 1;
+ }
+ }
+
+ n = len/HASH_CBLOCK;
+ if (n > 0)
+ {
+ HASH_BLOCK_DATA_ORDER (c,data,n);
+ n *= HASH_CBLOCK;
+ data += n;
+ len -= n;
+ }
+
+ if (len != 0)
+ {
+ p = (unsigned char *)c->data;
+ c->num = (unsigned int)len;
+ memcpy (p,data,len);
+ }
+ return 1;
+ }
+
+
+void HASH_TRANSFORM (HASH_CTX *c, const unsigned char *data)
+ {
+ HASH_BLOCK_DATA_ORDER (c,data,1);
+ }
+
+
+int HASH_FINAL (unsigned char *md, HASH_CTX *c)
+ {
+ unsigned char *p = (unsigned char *)c->data;
+ size_t n = c->num;
+
+ p[n] = 0x80; /* there is always room for one */
+ n++;
+
+ if (n > (HASH_CBLOCK-8))
+ {
+ memset (p+n,0,HASH_CBLOCK-n);
+ n=0;
+ HASH_BLOCK_DATA_ORDER (c,p,1);
+ }
+ memset (p+n,0,HASH_CBLOCK-8-n);
+
+ p += HASH_CBLOCK-8;
+#if defined(DATA_ORDER_IS_BIG_ENDIAN)
+ (void)HOST_l2c(c->Nh,p);
+ (void)HOST_l2c(c->Nl,p);
+#elif defined(DATA_ORDER_IS_LITTLE_ENDIAN)
+ (void)HOST_l2c(c->Nl,p);
+ (void)HOST_l2c(c->Nh,p);
+#endif
+ p -= HASH_CBLOCK;
+ HASH_BLOCK_DATA_ORDER (c,p,1);
+ c->num=0;
+ memset (p,0,HASH_CBLOCK);
+
+#ifndef HASH_MAKE_STRING
+#error "HASH_MAKE_STRING must be defined!"
+#else
+ HASH_MAKE_STRING(c,md);
+#endif
+
+ return 1;
+ }
+
+#ifndef MD32_REG_T
+#define MD32_REG_T int
+#endif
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_MD32_COMMON_H */
diff --git a/crypto/directory.h b/crypto/directory.h
new file mode 100644
index 0000000..e54df3c
--- /dev/null
+++ b/crypto/directory.h
@@ -0,0 +1,65 @@
+/* Copied from Richard Levitte's (richard@levitte.org) LP library. All
+ * symbol names have been changed, with permission from the author. */
+
+/* $LP: LPlib/source/LPdir.h,v 1.1 2004/06/14 08:56:04 _cvs_levitte Exp $ */
+/*
+ * Copyright (c) 2004, Richard Levitte <richard@levitte.org>
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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.
+ */
+
+#ifndef OPENSSL_HEADER_DIRECTORY_H
+#define OPENSSL_HEADER_DIRECTORY_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* Directory functions abstract the O/S specific operations for opening and
+ * reading directories in the filesystem. */
+
+
+/* OPENSSL_dir_context_st is an opaque structure that represents an open
+ * directory and a position in that directory. */
+typedef struct OPENSSL_dir_context_st OPENSSL_DIR_CTX;
+
+/* OPENSSL_DIR_read reads a single filename from |ctx|. On the first call,
+ * |directory| must be given and |*ctx| must be NULL. Subsequent calls with the
+ * same |*ctx| will return subsequent file names until it returns NULL to
+ * indicate EOF. The strings returned reference a buffer internal to the
+ * |OPENSSL_DIR_CTX| and will be overridden by subsequent calls. */
+const char *OPENSSL_DIR_read(OPENSSL_DIR_CTX **ctx, const char *directory);
+
+/* OPENSSL_DIR_end closes |*ctx|. It returns one on success and zero on
+ * error. */
+int OPENSSL_DIR_end(OPENSSL_DIR_CTX **ctx);
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_DIRECTORY_H */
diff --git a/crypto/directory_posix.c b/crypto/directory_posix.c
new file mode 100644
index 0000000..990f663
--- /dev/null
+++ b/crypto/directory_posix.c
@@ -0,0 +1,89 @@
+/* $LP: LPlib/source/LPdir_unix.c,v 1.11 2004/09/23 22:07:22 _cvs_levitte Exp $ */
+/*
+ * Copyright (c) 2004, Richard Levitte <richard@levitte.org>
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 COPYRIGHT
+ * OWNER 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. */
+
+#define _POSIX_C_SOURCE 1 /* for readdir_r */
+
+#include "directory.h"
+
+
+#if !defined(OPENSSL_WINDOWS)
+
+#include <dirent.h>
+#include <errno.h>
+
+struct OPENSSL_dir_context_st {
+ DIR *dir;
+ struct dirent dirent;
+};
+
+const char *OPENSSL_DIR_read(OPENSSL_DIR_CTX **ctx, const char *directory) {
+ struct dirent *dirent;
+
+ if (ctx == NULL || directory == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ errno = 0;
+ if (*ctx == NULL) {
+ *ctx = malloc(sizeof(OPENSSL_DIR_CTX));
+ if (*ctx == NULL) {
+ errno = ENOMEM;
+ return 0;
+ }
+ memset(*ctx, 0, sizeof(OPENSSL_DIR_CTX));
+
+ (*ctx)->dir = opendir(directory);
+ if ((*ctx)->dir == NULL) {
+ int save_errno = errno; /* Probably not needed, but I'm paranoid */
+ free(*ctx);
+ *ctx = NULL;
+ errno = save_errno;
+ return 0;
+ }
+ }
+
+ if (readdir_r((*ctx)->dir, &(*ctx)->dirent, &dirent) != 0 ||
+ dirent == NULL) {
+ return 0;
+ }
+
+ return (*ctx)->dirent.d_name;
+}
+
+int OPENSSL_DIR_end(OPENSSL_DIR_CTX **ctx) {
+ if (ctx != NULL && *ctx != NULL) {
+ int r = closedir((*ctx)->dir);
+ free(*ctx);
+ *ctx = NULL;
+ return r == 0;
+ }
+
+ errno = EINVAL;
+ return 0;
+}
+
+#endif /* !OPENSSL_WINDOWS */
diff --git a/crypto/directory_win.c b/crypto/directory_win.c
new file mode 100644
index 0000000..4956383
--- /dev/null
+++ b/crypto/directory_win.c
@@ -0,0 +1,138 @@
+/* $LP: LPlib/source/LPdir_win.c,v 1.10 2004/08/26 13:36:05 _cvs_levitte Exp $ */
+/*
+ * Copyright (c) 2004, Richard Levitte <richard@levitte.org>
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 COPYRIGHT
+ * OWNER 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.
+ */
+
+#include "directory.h"
+
+
+#if defined(OPENSSL_WINDOWS)
+
+#include <windows.h>
+#include <tchar.h>
+#include <errno.h>
+
+#ifndef NAME_MAX
+#define NAME_MAX 255
+#endif
+
+struct OPENSSL_dir_context_st {
+ WIN32_FIND_DATA ctx;
+ HANDLE handle;
+ char entry_name[NAME_MAX + 1];
+};
+
+const char *OPENSSL_DIR_read(OPENSSL_DIR_CTX **ctx, const char *directory) {
+ if (ctx == NULL || directory == NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ errno = 0;
+ if (*ctx == NULL) {
+ *ctx = malloc(sizeof(OPENSSL_DIR_CTX));
+ if (*ctx == NULL) {
+ errno = ENOMEM;
+ return 0;
+ }
+ memset(*ctx, 0, sizeof(OPENSSL_DIR_CTX));
+
+ if (sizeof(TCHAR) != sizeof(char)) {
+ TCHAR *wdir = NULL;
+ /* len_0 denotes string length *with* trailing 0 */
+ size_t index = 0, len_0 = strlen(directory) + 1;
+
+ wdir = (TCHAR *)malloc(len_0 * sizeof(TCHAR));
+ if (wdir == NULL) {
+ free(*ctx);
+ *ctx = NULL;
+ errno = ENOMEM;
+ return 0;
+ }
+
+ if (!MultiByteToWideChar(CP_ACP, 0, directory, len_0, (WCHAR *)wdir,
+ len_0)) {
+ for (index = 0; index < len_0; index++) {
+ wdir[index] = (TCHAR)directory[index];
+ }
+ }
+
+ (*ctx)->handle = FindFirstFile(wdir, &(*ctx)->ctx);
+
+ free(wdir);
+ } else {
+ (*ctx)->handle = FindFirstFile((TCHAR *)directory, &(*ctx)->ctx);
+ }
+
+ if ((*ctx)->handle == INVALID_HANDLE_VALUE) {
+ free(*ctx);
+ *ctx = NULL;
+ errno = EINVAL;
+ return 0;
+ }
+ } else {
+ if (FindNextFile((*ctx)->handle, &(*ctx)->ctx) == FALSE) {
+ return 0;
+ }
+ }
+
+ if (sizeof(TCHAR) != sizeof(char)) {
+ TCHAR *wdir = (*ctx)->ctx.cFileName;
+ size_t index, len_0 = 0;
+
+ while (wdir[len_0] && len_0 < (sizeof((*ctx)->entry_name) - 1)) {
+ len_0++;
+ }
+ len_0++;
+
+ if (!WideCharToMultiByte(CP_ACP, 0, (WCHAR *)wdir, len_0,
+ (*ctx)->entry_name, sizeof((*ctx)->entry_name),
+ NULL, 0)) {
+ for (index = 0; index < len_0; index++) {
+ (*ctx)->entry_name[index] = (char)wdir[index];
+ }
+ }
+ } else {
+ strncpy((*ctx)->entry_name, (const char *)(*ctx)->ctx.cFileName,
+ sizeof((*ctx)->entry_name) - 1);
+ }
+
+ (*ctx)->entry_name[sizeof((*ctx)->entry_name) - 1] = '\0';
+
+ return (*ctx)->entry_name;
+}
+
+int OPENSSL_DIR_end(OPENSSL_DIR_CTX **ctx) {
+ if (ctx != NULL && *ctx != NULL) {
+ FindClose((*ctx)->handle);
+ free(*ctx);
+ *ctx = NULL;
+ return 1;
+ }
+ errno = EINVAL;
+ return 0;
+}
+
+#endif /* OPENSSL_WINDOWS */
diff --git a/crypto/dsa/CMakeLists.txt b/crypto/dsa/CMakeLists.txt
new file mode 100644
index 0000000..6dfb2a6
--- /dev/null
+++ b/crypto/dsa/CMakeLists.txt
@@ -0,0 +1,20 @@
+include_directories(. .. ../../include)
+
+add_library(
+ dsa
+
+ OBJECT
+
+ dsa.c
+ dsa_impl.c
+ dsa_asn1.c
+ dsa_error.c
+)
+
+add_executable(
+ dsa_test
+
+ dsa_test.c
+)
+
+target_link_libraries(dsa_test crypto)
diff --git a/crypto/dsa/dsa.c b/crypto/dsa/dsa.c
new file mode 100644
index 0000000..4ae6876
--- /dev/null
+++ b/crypto/dsa/dsa.c
@@ -0,0 +1,334 @@
+/* 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.]
+ *
+ * The DSS routines are based on patches supplied by
+ * Steven Schoch <schoch@sheba.arc.nasa.gov>. */
+
+#include <openssl/dsa.h>
+
+#include <openssl/asn1.h>
+#include <openssl/engine.h>
+#include <openssl/err.h>
+#include <openssl/ex_data.h>
+#include <openssl/mem.h>
+
+#include "internal.h"
+
+extern const DSA_METHOD DSA_default_method;
+
+DSA *DSA_new(void) { return DSA_new_method(NULL); }
+
+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);
+ return NULL;
+ }
+
+ memset(dsa, 0, sizeof(DSA));
+
+ if (engine) {
+ dsa->meth = ENGINE_get_DSA_method(engine);
+ }
+
+ if (dsa->meth == NULL) {
+ dsa->meth = (DSA_METHOD*) &DSA_default_method;
+ }
+ METHOD_ref(dsa->meth);
+
+ dsa->write_params = 1;
+ dsa->references = 1;
+
+ if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_DSA, dsa, &dsa->ex_data)) {
+ METHOD_unref(dsa->meth);
+ OPENSSL_free(dsa);
+ return NULL;
+ }
+
+ if (dsa->meth->init && !dsa->meth->init(dsa)) {
+ CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DSA, dsa, &dsa->ex_data);
+ METHOD_unref(dsa->meth);
+ OPENSSL_free(dsa);
+ return NULL;
+ }
+
+ return dsa;
+}
+
+void DSA_free(DSA *dsa) {
+ if (dsa == NULL) {
+ return;
+ }
+
+ if (CRYPTO_add(&dsa->references, -1, CRYPTO_LOCK_DSA) > 0) {
+ return;
+ }
+
+ if (dsa->meth->finish) {
+ dsa->meth->finish(dsa);
+ }
+ METHOD_unref(dsa->meth);
+
+ CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DSA, dsa, &dsa->ex_data);
+
+ if (dsa->p != NULL)
+ BN_clear_free(dsa->p);
+ if (dsa->q != NULL)
+ BN_clear_free(dsa->q);
+ if (dsa->g != NULL)
+ BN_clear_free(dsa->g);
+ if (dsa->pub_key != NULL)
+ BN_clear_free(dsa->pub_key);
+ if (dsa->priv_key != NULL)
+ BN_clear_free(dsa->priv_key);
+ if (dsa->kinv != NULL)
+ BN_clear_free(dsa->kinv);
+ if (dsa->r != NULL)
+ BN_clear_free(dsa->r);
+ OPENSSL_free(dsa);
+}
+
+int DSA_up_ref(DSA *dsa) {
+ CRYPTO_add(&dsa->references, 1, CRYPTO_LOCK_DSA);
+ return 1;
+}
+
+int DSA_generate_parameters_ex(DSA *dsa, unsigned bits, const uint8_t *seed_in,
+ size_t seed_len, int *out_counter,
+ unsigned long *out_h, BN_GENCB *cb) {
+ if (dsa->meth->generate_parameters) {
+ return dsa->meth->generate_parameters(dsa, bits, seed_in, seed_len,
+ out_counter, out_h, cb);
+ }
+ return DSA_default_method.generate_parameters(dsa, bits, seed_in, seed_len,
+ out_counter, out_h, cb);
+}
+
+int DSA_generate_key(DSA *dsa) {
+ if (dsa->meth->keygen) {
+ return dsa->meth->keygen(dsa);
+ }
+ return DSA_default_method.keygen(dsa);
+}
+
+DSA_SIG *DSA_SIG_new(void) {
+ DSA_SIG *sig;
+ sig = OPENSSL_malloc(sizeof(DSA_SIG));
+ if (!sig) {
+ return NULL;
+ }
+ sig->r = NULL;
+ sig->s = NULL;
+ return sig;
+}
+
+void DSA_SIG_free(DSA_SIG *sig) {
+ if (!sig) {
+ return;
+ }
+
+ if (sig->r) {
+ BN_free(sig->r);
+ }
+ if (sig->s) {
+ BN_free(sig->s);
+ }
+ OPENSSL_free(sig);
+}
+
+DSA_SIG *DSA_do_sign(const uint8_t *digest, size_t digest_len, DSA *dsa) {
+ if (dsa->meth->sign) {
+ return dsa->meth->sign(digest, digest_len, dsa);
+ }
+ return DSA_default_method.sign(digest, digest_len, dsa);
+}
+
+int DSA_do_verify(const uint8_t *digest, size_t digest_len, DSA_SIG *sig,
+ const DSA *dsa) {
+ int valid, ret;
+
+ if (dsa->meth->verify) {
+ ret = dsa->meth->verify(&valid, digest, digest_len, sig, dsa);
+ } else {
+ ret = DSA_default_method.verify(&valid, digest, digest_len, sig, dsa);
+ }
+
+ if (!ret) {
+ return -1;
+ } else if (!valid) {
+ return 0;
+ }
+ return 1;
+}
+
+int DSA_do_check_signature(int *out_valid, const uint8_t *digest,
+ size_t digest_len, DSA_SIG *sig, const DSA *dsa) {
+ if (dsa->meth->verify) {
+ return dsa->meth->verify(out_valid, digest, digest_len, sig, dsa);
+ }
+
+ return DSA_default_method.verify(out_valid, digest, digest_len, sig, dsa);
+}
+
+int DSA_sign(int type, const uint8_t *digest, size_t digest_len,
+ uint8_t *out_sig, unsigned int *out_siglen, DSA *dsa) {
+ DSA_SIG *s;
+
+ s = DSA_do_sign(digest, digest_len, dsa);
+ if (s == NULL) {
+ *out_siglen = 0;
+ return 0;
+ }
+
+ *out_siglen = i2d_DSA_SIG(s, &out_sig);
+ DSA_SIG_free(s);
+ return 1;
+}
+
+int DSA_verify(int type, const uint8_t *digest, size_t digest_len,
+ const uint8_t *sig, size_t sig_len, const DSA *dsa) {
+ DSA_SIG *s = NULL;
+ int ret = -1, valid;
+
+ s = DSA_SIG_new();
+ if (s == NULL) {
+ goto err;
+ }
+
+ if (d2i_DSA_SIG(&s, &sig, sig_len) == NULL) {
+ goto err;
+ }
+
+ if (!DSA_do_check_signature(&valid, digest, digest_len, s, dsa)) {
+ goto err;
+ }
+
+ ret = valid;
+
+err:
+ if (s) {
+ DSA_SIG_free(s);
+ }
+ return ret;
+}
+
+int DSA_check_signature(int *out_valid, const uint8_t *digest,
+ size_t digest_len, const uint8_t *sig, size_t sig_len,
+ const DSA *dsa) {
+ DSA_SIG *s = NULL;
+ int ret = 0;
+
+ s = DSA_SIG_new();
+ if (s == NULL) {
+ goto err;
+ }
+
+ if (d2i_DSA_SIG(&s, &sig, sig_len) == NULL) {
+ goto err;
+ }
+
+ ret = DSA_do_check_signature(out_valid, digest, digest_len, s, dsa);
+
+err:
+ if (s) {
+ DSA_SIG_free(s);
+ }
+ return ret;
+}
+
+int DSA_size(const DSA *dsa) {
+ int ret, i;
+ ASN1_INTEGER bs;
+ unsigned char buf[4]; /* 4 bytes looks really small.
+ However, i2d_ASN1_INTEGER() will not look
+ beyond the first byte, as long as the second
+ parameter is NULL. */
+
+ i = BN_num_bits(dsa->q);
+ bs.length = (i + 7) / 8;
+ bs.data = buf;
+ bs.type = V_ASN1_INTEGER;
+ /* If the top bit is set the asn1 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);
+ return ret;
+}
+
+int DSA_sign_setup(const DSA *dsa, BN_CTX *ctx, BIGNUM **out_kinv,
+ BIGNUM **out_r) {
+ if (dsa->meth->sign_setup) {
+ return dsa->meth->sign_setup(dsa, ctx, out_kinv, out_r);
+ }
+
+ return DSA_default_method.sign_setup(dsa, ctx, out_kinv, out_r);
+}
+
+int DSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+ CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) {
+ return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_DSA, argl, argp, new_func,
+ dup_func, free_func);
+}
+
+int DSA_set_ex_data(DSA *d, int idx, void *arg) {
+ return CRYPTO_set_ex_data(&d->ex_data, idx, arg);
+}
+
+void *DSA_get_ex_data(const DSA *d, int idx) {
+ return CRYPTO_get_ex_data(&d->ex_data, idx);
+}
diff --git a/crypto/dsa/dsa.h b/crypto/dsa/dsa.h
new file mode 100644
index 0000000..857edc0
--- /dev/null
+++ b/crypto/dsa/dsa.h
@@ -0,0 +1,359 @@
+/* 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.]
+ *
+ * The DSS routines are based on patches supplied by
+ * Steven Schoch <schoch@sheba.arc.nasa.gov>. */
+
+#ifndef OPENSSL_HEADER_DSA_H
+#define OPENSSL_HEADER_DSA_H
+
+#include <openssl/base.h>
+
+#include <openssl/engine.h>
+#include <openssl/ex_data.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* DSA contains functions for signing and verifing with the Digital Signature
+ * Algorithm. */
+
+
+/* Allocation and destruction. */
+
+/* DSA_new returns a new, empty DSA object or NULL on error. */
+DSA *DSA_new(void);
+
+/* DSA_new_method acts the same as |DH_new| but takes an explicit |ENGINE|. */
+DSA *DSA_new_method(const ENGINE *engine);
+
+/* DSA_free decrements the reference count of |dsa| and frees it if the
+ * reference count drops to zero. */
+void DSA_free(DSA *dsa);
+
+/* DSA_up_ref increments the reference count of |dsa|. */
+int DSA_up_ref(DSA *dsa);
+
+
+/* Parameter generation. */
+
+/* DSA_generate_parameters_ex generates a set of DSA parameters by following
+ * the procedure given in FIPS 186-4, appendix A.
+ * (http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf)
+ *
+ * The larger prime will have a length of |bits| (e.g. 2048). The |seed| value
+ * allows others to generate and verify the same parameters and should be
+ * random input which is kept for reference. If |out_counter| or |out_h| are
+ * not NULL then the counter and h value used in the generation are written to
+ * them.
+ *
+ * The |cb| argument is passed to |BN_generate_prime_ex| and is thus called
+ * during the generation process in order to indicate progress. See the
+ * comments for that function for details. In addition to the calls made by
+ * |BN_generate_prime_ex|, |DSA_generate_parameters_ex| will call it with
+ * |event| equal to 2 and 3 at different stages of the process.
+ *
+ * It returns one on success and zero otherwise. */
+int DSA_generate_parameters_ex(DSA *dsa, unsigned bits, const uint8_t *seed,
+ size_t seed_len, int *out_counter,
+ unsigned long *out_h, BN_GENCB *cb);
+
+/* DSAparams_dup returns a freshly allocated |DSA| that contains a copy of the
+ * parameters from |dsa|. It returns NULL on error. */
+DSA *DSAparams_dup(const DSA *dsa);
+
+
+/* Key generation. */
+
+/* DSA_generate_key generates a public/private key pair in |dsa|, which must
+ * already have parameters setup. It returns one on success and zero on
+ * error. */
+int DSA_generate_key(DSA *dsa);
+
+
+/* Signatures. */
+
+/* DSA_SIG contains a DSA signature as a pair of integers. */
+typedef struct DSA_SIG_st {
+ BIGNUM *r, *s;
+} DSA_SIG;
+
+/* DSA_SIG_new returns a freshly allocated, DIG_SIG structure or NULL on error.
+ * Both |r| and |s| in the signature will be NULL. */
+DSA_SIG *DSA_SIG_new(void);
+
+/* DSA_SIG_free frees the contents of |sig| and then frees |sig| itself. */
+void DSA_SIG_free(DSA_SIG *sig);
+
+/* DSA_do_sign returns a signature of the hash in |digest| by the key in |dsa|
+ * and returns an allocated, DSA_SIG structure, or NULL on error. */
+DSA_SIG *DSA_do_sign(const uint8_t *digest, size_t digest_len, DSA *dsa);
+
+/* DSA_do_verify verifies that |sig| is a valid signature, by the public key in
+ * |dsa|, of the hash in |digest|. It returns one if so, zero if invalid and -1
+ * on error.
+ *
+ * WARNING: do not use. This function returns -1 for error, 0 for invalid and 1
+ * for valid. However, this is dangerously different to the usual OpenSSL
+ * convention and could be a disaster if a user did |if (DSA_do_verify(...))|.
+ * Because of this, |DSA_check_signature| is a safer version of this.
+ *
+ * TODO(fork): deprecate. */
+int DSA_do_verify(const uint8_t *digest, size_t digest_len, DSA_SIG *sig,
+ const DSA *dsa);
+
+/* DSA_check_signature sets |*out_valid| to zero. Then it verifies that |sig|
+ * is a valid signature, by the public key in |dsa| of the hash in |digest|
+ * and, if so, it sets |*out_valid| to one.
+ *
+ * It returns one if it was able to verify the signature as valid or invalid,
+ * and zero on error. */
+int DSA_do_check_signature(int *out_valid, const uint8_t *digest,
+ size_t digest_len, DSA_SIG *sig, const DSA *dsa);
+
+
+/* ASN.1 signatures.
+ *
+ * These functions also perform DSA signature operations, but deal with ASN.1
+ * encoded signatures as opposed to raw |BIGNUM|s. If you don't know what
+ * encoding a DSA signature is in, it's probably ASN.1. */
+
+/* DSA_sign signs |digest| with the key in |dsa| and writes the resulting
+ * signature, in ASN.1 form, to |out_sig| and the length of the signature to
+ * |*out_siglen|. There must be, at least, |DSA_size(dsa)| bytes of space in
+ * |out_sig|. It returns one on success and zero otherwise.
+ *
+ * (The |type| argument is ignored.) */
+int DSA_sign(int type, const uint8_t *digest, size_t digest_len,
+ uint8_t *out_sig, unsigned int *out_siglen, DSA *dsa);
+
+/* DSA_verify verifies that |sig| is a valid, ASN.1 signature, by the public
+ * key in |dsa|, of the hash in |digest|. It returns one if so, zero if invalid
+ * and -1 on error.
+ *
+ * (The |type| argument is ignored.)
+ *
+ * WARNING: do not use. This function returns -1 for error, 0 for invalid and 1
+ * for valid. However, this is dangerously different to the usual OpenSSL
+ * convention and could be a disaster if a user did |if (DSA_do_verify(...))|.
+ * Because of this, |DSA_check_signature| is a safer version of this.
+ *
+ * TODO(fork): deprecate. */
+int DSA_verify(int type, const uint8_t *digest, size_t digest_len,
+ const uint8_t *sig, size_t sig_len, const DSA *dsa);
+
+/* DSA_check_signature sets |*out_valid| to zero. Then it verifies that |sig|
+ * is a valid, ASN.1 signature, by the public key in |dsa|, of the hash in
+ * |digest|. If so, it sets |*out_valid| to one.
+ *
+ * It returns one if it was able to verify the signature as valid or invalid,
+ * and zero on error. */
+int DSA_check_signature(int *out_valid, const uint8_t *digest,
+ size_t digest_len, const uint8_t *sig, size_t sig_len,
+ const DSA *dsa);
+
+/* DSA_size returns the size, in bytes, of an ASN.1 encoded, DSA signature
+ * generated by |dsa|. Parameters must already have been setup in |dsa|. */
+int DSA_size(const DSA *dsa);
+
+
+/* ASN.1 encoding. */
+
+/* d2i_DSA_SIG parses an ASN.1, DER-encoded, DSA signature from |len| bytes at
+ * |*inp|. If |out_sig| is not NULL then, on exit, a pointer to the result is
+ * in |*out_sig|. If |*out_sig| is already non-NULL on entry then the result is
+ * written directly into |*out_sig|, otherwise a fresh |DSA_SIG| is allocated.
+ * On successful exit, |*inp| is advanced past the DER structure. It returns
+ * the result or NULL on error. */
+DSA_SIG *d2i_DSA_SIG(DSA_SIG **out_sig, const uint8_t **inp, long len);
+
+/* i2d_DSA_SIG marshals |in| to an ASN.1, DER structure. If |outp| is not NULL
+ * then the result is written to |*outp| and |*outp| is advanced just past the
+ * output. It returns the number of bytes in the result, whether written or not,
+ * or a negative value on error. */
+int i2d_DSA_SIG(const DSA_SIG *in, uint8_t **outp);
+
+/* d2i_DSAPublicKey parses an ASN.1, DER-encoded, DSA public key from |len|
+ * bytes at |*inp|. If |out| is not NULL then, on exit, a pointer to the result
+ * is in |*out|. If |*out| is already non-NULL on entry then the result is
+ * written directly into |*out|, otherwise a fresh |DSA| is allocated. On
+ * successful exit, |*inp| is advanced past the DER structure. It returns the
+ * result or NULL on error. */
+DSA *d2i_DSAPublicKey(DSA **out, const uint8_t **inp, long len);
+
+/* i2d_DSAPublicKey marshals a public key from |in| to an ASN.1, DER structure.
+ * If |outp| is not NULL then the result is written to |*outp| and |*outp| is
+ * advanced just past the output. It returns the number of bytes in the result,
+ * whether written or not, or a negative value on error. */
+int i2d_DSAPublicKey(const DSA *in, unsigned char **outp);
+
+/* d2i_DSAPrivateKey parses an ASN.1, DER-encoded, DSA private key from |len|
+ * bytes at |*inp|. If |out| is not NULL then, on exit, a pointer to the result
+ * is in |*out|. If |*out| is already non-NULL on entry then the result is
+ * written directly into |*out|, otherwise a fresh |DSA| is allocated. On
+ * successful exit, |*inp| is advanced past the DER structure. It returns the
+ * result or NULL on error. */
+DSA *d2i_DSAPrivateKey(DSA **out, const uint8_t **inp, long len);
+
+/* i2d_DSAPrivateKey marshals a private key from |in| to an ASN.1, DER structure.
+ * If |outp| is not NULL then the result is written to |*outp| and |*outp| is
+ * advanced just past the output. It returns the number of bytes in the result,
+ * whether written or not, or a negative value on error. */
+int i2d_DSAPrivateKey(const DSA *in, unsigned char **outp);
+
+/* d2i_DSAparams parses ASN.1, DER-encoded, DSA parameters from |len| bytes at
+ * |*inp|. If |out| is not NULL then, on exit, a pointer to the result is in
+ * |*out|. If |*out| is already non-NULL on entry then the result is written
+ * directly into |*out|, otherwise a fresh |DSA| is allocated. On successful
+ * exit, |*inp| is advanced past the DER structure. It returns the result or
+ * NULL on error. */
+DSA *d2i_DSAparams(DSA **out, const uint8_t **inp, long len);
+
+/* i2d_DSAparams marshals DSA parameters from |in| to an ASN.1, DER structure.
+ * If |outp| is not NULL then the result is written to |*outp| and |*outp| is
+ * advanced just past the output. It returns the number of bytes in the result,
+ * whether written or not, or a negative value on error. */
+int i2d_DSAparams(const DSA *in, unsigned char **outp);
+
+
+/* Precomputation. */
+
+/* DSA_sign_setup precomputes the message independent part of the DSA signature
+ * and writes them to |*out_kinv| and |*out_r|. Returns one on success, zero on
+ * error.
+ *
+ * TODO(fork): decide what to do with this. Since making DSA* opaque there's no
+ * way for the user to install them. Also, it forces the DSA* not to be const
+ * when passing to the signing function. */
+int DSA_sign_setup(const DSA *dsa, BN_CTX *ctx, BIGNUM **out_kinv,
+ BIGNUM **out_r);
+
+
+/* ex_data functions.
+ *
+ * These functions are wrappers. See |ex_data.h| for details. */
+
+int DSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+ CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+int DSA_set_ex_data(DSA *d, int idx, void *arg);
+void *DSA_get_ex_data(const DSA *d, int idx);
+
+
+struct dsa_method {
+ struct openssl_method_common_st common;
+
+ void *app_data;
+
+ int (*init)(DSA *dsa);
+ int (*finish)(DSA *dsa);
+
+ DSA_SIG *(*sign)(const uint8_t *digest, size_t digest_len, DSA *dsa);
+
+ int (*sign_setup)(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp);
+
+ int (*verify)(int *out_valid, const uint8_t *digest, size_t digest_len,
+ DSA_SIG *sig, const DSA *dsa);
+
+ /* generate_parameters, if non-NULL, is used to generate DSA parameters. */
+ int (*generate_parameters)(DSA *dsa, unsigned bits, const uint8_t *seed,
+ size_t seed_len, int *counter_ret,
+ unsigned long *h_ret, BN_GENCB *cb);
+
+ /* keygen, if non-NULL, is used to generate DSA keys. */
+ int (*keygen)(DSA *dsa);
+};
+
+struct dsa_st {
+ long version;
+ int write_params;
+ BIGNUM *p;
+ BIGNUM *q; /* == 20 */
+ BIGNUM *g;
+
+ BIGNUM *pub_key; /* y public key */
+ BIGNUM *priv_key; /* x private key */
+
+ BIGNUM *kinv; /* Signing pre-calc */
+ BIGNUM *r; /* Signing pre-calc */
+
+ int flags;
+ /* Normally used to cache montgomery values */
+ BN_MONT_CTX *method_mont_p;
+ int references;
+ CRYPTO_EX_DATA ex_data;
+ DSA_METHOD *meth;
+ /* functional reference if 'meth' is ENGINE-provided */
+ ENGINE *engine;
+};
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#define DSA_F_sign 100
+#define DSA_F_verify 101
+#define DSA_F_dsa_sig_cb 102
+#define DSA_F_DSA_new_method 103
+#define DSA_F_sign_setup 104
+#define DSA_R_NEED_NEW_SETUP_VALUES 100
+#define DSA_R_BAD_Q_VALUE 101
+#define DSA_R_MODULUS_TOO_LARGE 102
+#define DSA_R_MISSING_PARAMETERS 103
+
+#endif /* OPENSSL_HEADER_DSA_H */
diff --git a/crypto/dsa/dsa_asn1.c b/crypto/dsa/dsa_asn1.c
new file mode 100644
index 0000000..72b2cc6
--- /dev/null
+++ b/crypto/dsa/dsa_asn1.c
@@ -0,0 +1,148 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2000. */
+/* ====================================================================
+ * Copyright (c) 2000-2005 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/dsa.h>
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+#include "internal.h"
+
+
+static int dsa_sig_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
+ void *exarg) {
+ if (operation != ASN1_OP_NEW_PRE) {
+ return 1;
+ }
+
+ DSA_SIG *sig;
+ sig = OPENSSL_malloc(sizeof(DSA_SIG));
+ if (!sig) {
+ OPENSSL_PUT_ERROR(DSA, dsa_sig_cb, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ memset(sig, 0, sizeof(DSA_SIG));
+ *pval = (ASN1_VALUE *)sig;
+ return 2;
+}
+
+ASN1_SEQUENCE_cb(DSA_SIG, dsa_sig_cb) = {
+ ASN1_SIMPLE(DSA_SIG, r, CBIGNUM),
+ ASN1_SIMPLE(DSA_SIG, s, CBIGNUM)} ASN1_SEQUENCE_END_cb(DSA_SIG, DSA_SIG);
+
+IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA_SIG, DSA_SIG, DSA_SIG);
+
+
+static int dsa_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
+ void *exarg) {
+ switch (operation) {
+ case ASN1_OP_NEW_PRE:
+ *pval = (ASN1_VALUE *)DSA_new();
+ if (*pval) {
+ return 2;
+ }
+ return 0;
+
+ case ASN1_OP_FREE_PRE:
+ DSA_free((DSA *)*pval);
+ *pval = NULL;
+ return 2;
+
+ default:
+ return 1;
+ }
+}
+
+ASN1_SEQUENCE_cb(DSAPrivateKey, dsa_cb) = {
+ ASN1_SIMPLE(DSA, version, LONG),
+ ASN1_SIMPLE(DSA, p, BIGNUM),
+ ASN1_SIMPLE(DSA, q, BIGNUM),
+ ASN1_SIMPLE(DSA, g, BIGNUM),
+ ASN1_SIMPLE(DSA, pub_key, BIGNUM),
+ ASN1_SIMPLE(DSA, priv_key, BIGNUM)} ASN1_SEQUENCE_END_cb(DSA,
+ DSAPrivateKey);
+
+IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA, DSAPrivateKey, DSAPrivateKey);
+
+ASN1_SEQUENCE_cb(DSAparams, dsa_cb) = {
+ ASN1_SIMPLE(DSA, p, BIGNUM), ASN1_SIMPLE(DSA, q, BIGNUM),
+ ASN1_SIMPLE(DSA, g, BIGNUM), } ASN1_SEQUENCE_END_cb(DSA, DSAparams);
+
+IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA, DSAparams, DSAparams);
+
+
+/* DSA public key is a bit trickier... its effectively a CHOICE type decided by
+ * a field called write_params which can either write out just the public key
+ * as an INTEGER or the parameters and public key in a SEQUENCE. */
+
+ASN1_SEQUENCE(dsa_pub_internal) = {
+ ASN1_SIMPLE(DSA, pub_key, BIGNUM),
+ ASN1_SIMPLE(DSA, p, BIGNUM),
+ ASN1_SIMPLE(DSA, q, BIGNUM),
+ ASN1_SIMPLE(DSA, g, BIGNUM)
+} ASN1_SEQUENCE_END_name(DSA, dsa_pub_internal);
+
+ASN1_CHOICE_cb(DSAPublicKey, dsa_cb) = {
+ ASN1_SIMPLE(DSA, pub_key, BIGNUM),
+ ASN1_EX_COMBINE(0, 0, dsa_pub_internal)
+} ASN1_CHOICE_END_cb(DSA, DSAPublicKey, write_params);
+
+IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA, DSAPublicKey, DSAPublicKey);
+
+DSA *DSAparams_dup(const DSA *dsa) {
+ return ASN1_item_dup(ASN1_ITEM_rptr(DSAparams), (DSA*) dsa);
+}
diff --git a/crypto/dsa/dsa_error.c b/crypto/dsa/dsa_error.c
new file mode 100644
index 0000000..b6e08ae
--- /dev/null
+++ b/crypto/dsa/dsa_error.c
@@ -0,0 +1,30 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/err.h>
+
+#include "dsa.h"
+
+const ERR_STRING_DATA DSA_error_string_data[] = {
+ {ERR_PACK(ERR_LIB_DSA, DSA_F_DSA_new_method, 0), "DSA_new_method"},
+ {ERR_PACK(ERR_LIB_DSA, DSA_F_dsa_sig_cb, 0), "dsa_sig_cb"},
+ {ERR_PACK(ERR_LIB_DSA, DSA_F_sign, 0), "sign"},
+ {ERR_PACK(ERR_LIB_DSA, DSA_F_sign_setup, 0), "sign_setup"},
+ {ERR_PACK(ERR_LIB_DSA, DSA_F_verify, 0), "verify"},
+ {ERR_PACK(ERR_LIB_DSA, 0, DSA_R_BAD_Q_VALUE), "BAD_Q_VALUE"},
+ {ERR_PACK(ERR_LIB_DSA, 0, DSA_R_MISSING_PARAMETERS), "MISSING_PARAMETERS"},
+ {ERR_PACK(ERR_LIB_DSA, 0, DSA_R_MODULUS_TOO_LARGE), "MODULUS_TOO_LARGE"},
+ {ERR_PACK(ERR_LIB_DSA, 0, DSA_R_NEED_NEW_SETUP_VALUES), "NEED_NEW_SETUP_VALUES"},
+ {0, NULL},
+};
diff --git a/crypto/dsa/dsa_impl.c b/crypto/dsa/dsa_impl.c
new file mode 100644
index 0000000..dacc742
--- /dev/null
+++ b/crypto/dsa/dsa_impl.c
@@ -0,0 +1,723 @@
+/* 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.]
+ *
+ * The DSS routines are based on patches supplied by
+ * Steven Schoch <schoch@sheba.arc.nasa.gov>. */
+
+#include <openssl/dsa.h>
+
+#include <openssl/bn.h>
+#include <openssl/digest.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#include <openssl/sha.h>
+
+#include "internal.h"
+
+#define OPENSSL_DSA_MAX_MODULUS_BITS 10000
+
+/* Primality test according to FIPS PUB 186[-1], Appendix 2.1: 50 rounds of
+ * Rabin-Miller */
+#define DSS_prime_checks 50
+
+static int sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp,
+ BIGNUM **rp) {
+ BN_CTX *ctx;
+ BIGNUM k, kq, *K, *kinv = NULL, *r = NULL;
+ int ret = 0;
+
+ if (!dsa->p || !dsa->q || !dsa->g) {
+ OPENSSL_PUT_ERROR(DSA, sign_setup, DSA_R_MISSING_PARAMETERS);
+ return 0;
+ }
+
+ BN_init(&k);
+ BN_init(&kq);
+
+ ctx = ctx_in;
+ if (ctx == NULL) {
+ ctx = BN_CTX_new();
+ if (ctx == NULL) {
+ goto err;
+ }
+ }
+
+ r = BN_new();
+ if (r == NULL) {
+ goto err;
+ }
+
+ /* Get random k */
+ do {
+ if (!BN_rand_range(&k, dsa->q)) {
+ goto err;
+ }
+ } while (BN_is_zero(&k));
+
+ BN_set_flags(&k, BN_FLG_CONSTTIME);
+
+ if (!BN_MONT_CTX_set_locked((BN_MONT_CTX **)&dsa->method_mont_p,
+ CRYPTO_LOCK_DSA, dsa->p, ctx)) {
+ goto err;
+ }
+
+ /* Compute r = (g^k mod p) mod q */
+ if (!BN_copy(&kq, &k))
+ goto err;
+
+ /* We do not want timing information to leak the length of k,
+ * so we compute g^k using an equivalent exponent of fixed length.
+ *
+ * (This is a kludge that we need because the BN_mod_exp_mont()
+ * does not let us specify the desired timing behaviour.) */
+
+ if (!BN_add(&kq, &kq, dsa->q))
+ goto err;
+ if (BN_num_bits(&kq) <= BN_num_bits(dsa->q)) {
+ if (!BN_add(&kq, &kq, dsa->q))
+ goto err;
+ }
+
+ K = &kq;
+
+ if (!BN_mod_exp_mont(r, dsa->g, K, dsa->p, ctx, dsa->method_mont_p)) {
+ goto err;
+ }
+ if (!BN_mod(r, r, dsa->q, ctx)) {
+ goto err;
+ }
+
+ /* Compute part of 's = inv(k) (m + xr) mod q' */
+ kinv = BN_mod_inverse(NULL, &k, dsa->q, ctx);
+ if (kinv == NULL) {
+ goto err;
+ }
+
+ if (*kinvp != NULL) {
+ BN_clear_free(*kinvp);
+ }
+ *kinvp = kinv;
+ kinv = NULL;
+ if (*rp != NULL) {
+ BN_clear_free(*rp);
+ }
+ *rp = r;
+ ret = 1;
+
+err:
+ if (!ret) {
+ OPENSSL_PUT_ERROR(DSA, sign_setup, ERR_R_BN_LIB);
+ if (r != NULL) {
+ BN_clear_free(r);
+ }
+ }
+
+ if (ctx_in == NULL) {
+ BN_CTX_free(ctx);
+ }
+ BN_clear_free(&k);
+ BN_clear_free(&kq);
+ return ret;
+}
+
+static DSA_SIG *sign(const uint8_t *digest, size_t digest_len, DSA *dsa) {
+ BIGNUM *kinv = NULL, *r = NULL, *s = NULL;
+ BIGNUM m;
+ BIGNUM xr;
+ BN_CTX *ctx = NULL;
+ int reason = ERR_R_BN_LIB;
+ DSA_SIG *ret = NULL;
+ int noredo = 0;
+
+ BN_init(&m);
+ BN_init(&xr);
+
+ if (!dsa->p || !dsa->q || !dsa->g) {
+ reason = DSA_R_MISSING_PARAMETERS;
+ goto err;
+ }
+
+ s = BN_new();
+ if (s == NULL) {
+ goto err;
+ }
+ ctx = BN_CTX_new();
+ if (ctx == NULL) {
+ goto err;
+ }
+
+redo:
+ if (dsa->kinv == NULL || dsa->r == NULL) {
+ if (!DSA_sign_setup(dsa, ctx, &kinv, &r)) {
+ goto err;
+ }
+ } else {
+ kinv = dsa->kinv;
+ dsa->kinv = NULL;
+ r = dsa->r;
+ dsa->r = NULL;
+ noredo = 1;
+ }
+
+ if (digest_len > BN_num_bytes(dsa->q)) {
+ /* if the digest length is greater than the size of q use the
+ * BN_num_bits(dsa->q) leftmost bits of the digest, see
+ * fips 186-3, 4.2 */
+ digest_len = BN_num_bytes(dsa->q);
+ }
+
+ if (BN_bin2bn(digest, digest_len, &m) == NULL) {
+ goto err;
+ }
+
+ /* Compute s = inv(k) (m + xr) mod q */
+ if (!BN_mod_mul(&xr, dsa->priv_key, r, dsa->q, ctx)) {
+ goto err; /* s = xr */
+ }
+ if (!BN_add(s, &xr, &m)) {
+ goto err; /* s = m + xr */
+ }
+ if (BN_cmp(s, dsa->q) > 0) {
+ if (!BN_sub(s, s, dsa->q)) {
+ goto err;
+ }
+ }
+ if (!BN_mod_mul(s, s, kinv, dsa->q, ctx)) {
+ goto err;
+ }
+
+ ret = DSA_SIG_new();
+ if (ret == NULL) {
+ goto err;
+ }
+ /* Redo if r or s is zero as required by FIPS 186-3: this is
+ * very unlikely. */
+ if (BN_is_zero(r) || BN_is_zero(s)) {
+ if (noredo) {
+ reason = DSA_R_NEED_NEW_SETUP_VALUES;
+ goto err;
+ }
+ goto redo;
+ }
+ ret->r = r;
+ ret->s = s;
+
+err:
+ if (!ret) {
+ OPENSSL_PUT_ERROR(DSA, sign, reason);
+ BN_free(r);
+ BN_free(s);
+ }
+ if (ctx != NULL) {
+ BN_CTX_free(ctx);
+ }
+ BN_clear_free(&m);
+ BN_clear_free(&xr);
+ if (kinv != NULL) {
+ /* dsa->kinv is NULL now if we used it */
+ BN_clear_free(kinv);
+ }
+
+ return ret;
+}
+
+static int verify(int *out_valid, const uint8_t *dgst, size_t digest_len,
+ DSA_SIG *sig, const DSA *dsa) {
+ BN_CTX *ctx;
+ BIGNUM u1, u2, t1;
+ BN_MONT_CTX *mont = NULL;
+ int ret = 0;
+ unsigned i;
+
+ *out_valid = 0;
+
+ if (!dsa->p || !dsa->q || !dsa->g) {
+ OPENSSL_PUT_ERROR(DSA, verify, 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);
+ return 0;
+ }
+
+ if (BN_num_bits(dsa->p) > OPENSSL_DSA_MAX_MODULUS_BITS) {
+ OPENSSL_PUT_ERROR(DSA, verify, DSA_R_MODULUS_TOO_LARGE);
+ return 0;
+ }
+
+ BN_init(&u1);
+ BN_init(&u2);
+ BN_init(&t1);
+
+ ctx = BN_CTX_new();
+ if (ctx == NULL) {
+ goto err;
+ }
+
+ if (BN_is_zero(sig->r) || BN_is_negative(sig->r) ||
+ BN_ucmp(sig->r, dsa->q) >= 0) {
+ ret = 1;
+ goto err;
+ }
+ if (BN_is_zero(sig->s) || BN_is_negative(sig->s) ||
+ BN_ucmp(sig->s, dsa->q) >= 0) {
+ ret = 1;
+ goto err;
+ }
+
+ /* Calculate W = inv(S) mod Q
+ * save W in u2 */
+ if (BN_mod_inverse(&u2, sig->s, dsa->q, ctx) == NULL) {
+ goto err;
+ }
+
+ /* save M in u1 */
+ if (digest_len > (i >> 3)) {
+ /* if the digest length is greater than the size of q use the
+ * BN_num_bits(dsa->q) leftmost bits of the digest, see
+ * fips 186-3, 4.2 */
+ digest_len = (i >> 3);
+ }
+
+ if (BN_bin2bn(dgst, digest_len, &u1) == NULL) {
+ goto err;
+ }
+
+ /* u1 = M * w mod q */
+ if (!BN_mod_mul(&u1, &u1, &u2, dsa->q, ctx)) {
+ goto err;
+ }
+
+ /* u2 = r * w mod q */
+ if (!BN_mod_mul(&u2, sig->r, &u2, dsa->q, ctx)) {
+ goto err;
+ }
+
+ mont = BN_MONT_CTX_set_locked((BN_MONT_CTX **)&dsa->method_mont_p,
+ CRYPTO_LOCK_DSA, dsa->p, ctx);
+ if (!mont) {
+ goto err;
+ }
+
+ if (!BN_mod_exp2_mont(&t1, dsa->g, &u1, dsa->pub_key, &u2, dsa->p, ctx, mont)) {
+ goto err;
+ }
+
+ /* BN_copy(&u1,&t1); */
+ /* let u1 = u1 mod q */
+ if (!BN_mod(&u1, &t1, dsa->q, ctx)) {
+ goto err;
+ }
+
+ /* V is now in u1. If the signature is correct, it will be
+ * equal to R. */
+ *out_valid = BN_ucmp(&u1, sig->r) == 0;
+ ret = 1;
+
+err:
+ if (ret != 1) {
+ OPENSSL_PUT_ERROR(DSA, verify, ERR_R_BN_LIB);
+ }
+ if (ctx != NULL) {
+ BN_CTX_free(ctx);
+ }
+ BN_free(&u1);
+ BN_free(&u2);
+ BN_free(&t1);
+
+ return ret;
+}
+
+static int keygen(DSA *dsa) {
+ int ok = 0;
+ BN_CTX *ctx = NULL;
+ BIGNUM *pub_key = NULL, *priv_key = NULL;
+ BIGNUM prk;
+
+ ctx = BN_CTX_new();
+ if (ctx == NULL) {
+ goto err;
+ }
+
+ priv_key = dsa->priv_key;
+ if (priv_key == NULL) {
+ priv_key = BN_new();
+ if (priv_key == NULL) {
+ goto err;
+ }
+ }
+
+ do {
+ if (!BN_rand_range(priv_key, dsa->q)) {
+ goto err;
+ }
+ } while (BN_is_zero(priv_key));
+
+ pub_key = dsa->pub_key;
+ if (pub_key == NULL) {
+ pub_key = BN_new();
+ if (pub_key == NULL) {
+ goto err;
+ }
+ }
+
+ BN_init(&prk);
+ BN_with_flags(&prk, priv_key, BN_FLG_CONSTTIME);
+
+ if (!BN_mod_exp(pub_key, dsa->g, &prk, dsa->p, ctx)) {
+ goto err;
+ }
+
+ dsa->priv_key = priv_key;
+ dsa->pub_key = pub_key;
+ ok = 1;
+
+err:
+ if (pub_key != NULL && dsa->pub_key == NULL) {
+ BN_free(pub_key);
+ }
+ if (priv_key != NULL && dsa->priv_key == NULL) {
+ BN_free(priv_key);
+ }
+ if (ctx != NULL) {
+ BN_CTX_free(ctx);
+ }
+
+ return ok;
+}
+
+static int paramgen(DSA *ret, unsigned bits, const uint8_t *seed_in,
+ size_t seed_len, int *counter_ret, unsigned long *h_ret,
+ BN_GENCB *cb) {
+ int ok = 0;
+ unsigned char seed[SHA256_DIGEST_LENGTH];
+ unsigned char md[SHA256_DIGEST_LENGTH];
+ unsigned char buf[SHA256_DIGEST_LENGTH], buf2[SHA256_DIGEST_LENGTH];
+ BIGNUM *r0, *W, *X, *c, *test;
+ BIGNUM *g = NULL, *q = NULL, *p = NULL;
+ BN_MONT_CTX *mont = NULL;
+ int k, n = 0, m = 0;
+ unsigned i;
+ int counter = 0;
+ int r = 0;
+ BN_CTX *ctx = NULL;
+ unsigned int h = 2;
+ unsigned qbits, qsize;
+ const EVP_MD *evpmd;
+
+ if (bits >= 2048) {
+ qbits = 256;
+ evpmd = EVP_sha256();
+ } else {
+ qbits = 160;
+ evpmd = EVP_sha1();
+ }
+ qsize = qbits / 8;
+
+ if (qsize != SHA_DIGEST_LENGTH && qsize != SHA224_DIGEST_LENGTH &&
+ qsize != SHA256_DIGEST_LENGTH)
+ /* invalid q size */
+ return 0;
+
+ if (bits < 512)
+ bits = 512;
+
+ 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)
+ memcpy(seed, seed_in, seed_len);
+
+ if ((ctx = BN_CTX_new()) == NULL)
+ goto err;
+
+ if ((mont = BN_MONT_CTX_new()) == NULL)
+ goto err;
+
+ BN_CTX_start(ctx);
+ r0 = BN_CTX_get(ctx);
+ g = BN_CTX_get(ctx);
+ W = BN_CTX_get(ctx);
+ q = BN_CTX_get(ctx);
+ X = BN_CTX_get(ctx);
+ c = BN_CTX_get(ctx);
+ p = BN_CTX_get(ctx);
+ test = BN_CTX_get(ctx);
+
+ if (!BN_lshift(test, BN_value_one(), bits - 1))
+ goto err;
+
+ for (;;) {
+ for (;;) /* find q */
+ {
+ int seed_is_random;
+
+ /* step 1 */
+ if (!BN_GENCB_call(cb, 0, m++))
+ goto err;
+
+ if (!seed_len) {
+ RAND_pseudo_bytes(seed, qsize);
+ seed_is_random = 1;
+ } else {
+ seed_is_random = 0;
+ seed_len = 0; /* use random seed if 'seed_in' turns out to be bad*/
+ }
+ memcpy(buf, seed, qsize);
+ memcpy(buf2, seed, qsize);
+ /* precompute "SEED + 1" for step 7: */
+ for (i = qsize - 1; i < qsize; i--) {
+ buf[i]++;
+ if (buf[i] != 0)
+ break;
+ }
+
+ /* step 2 */
+ if (!EVP_Digest(seed, qsize, md, NULL, evpmd, NULL))
+ goto err;
+ if (!EVP_Digest(buf, qsize, buf2, NULL, evpmd, NULL))
+ goto err;
+ for (i = 0; i < qsize; i++)
+ md[i] ^= buf2[i];
+
+ /* step 3 */
+ md[0] |= 0x80;
+ md[qsize - 1] |= 0x01;
+ if (!BN_bin2bn(md, qsize, q))
+ goto err;
+
+ /* step 4 */
+ r = BN_is_prime_fasttest_ex(q, DSS_prime_checks, ctx, seed_is_random, cb);
+ if (r > 0)
+ break;
+ if (r != 0)
+ goto err;
+
+ /* do a callback call */
+ /* step 5 */
+ }
+
+ if (!BN_GENCB_call(cb, 2, 0))
+ goto err;
+ if (!BN_GENCB_call(cb, 3, 0))
+ goto err;
+
+ /* step 6 */
+ counter = 0;
+ /* "offset = 2" */
+
+ n = (bits - 1) / 160;
+
+ for (;;) {
+ if ((counter != 0) && !BN_GENCB_call(cb, 0, counter))
+ goto err;
+
+ /* step 7 */
+ BN_zero(W);
+ /* now 'buf' contains "SEED + offset - 1" */
+ for (k = 0; k <= n; k++) {
+ /* obtain "SEED + offset + k" by incrementing: */
+ for (i = qsize - 1; i < qsize; i--) {
+ buf[i]++;
+ if (buf[i] != 0)
+ break;
+ }
+
+ if (!EVP_Digest(buf, qsize, md, NULL, evpmd, NULL))
+ goto err;
+
+ /* step 8 */
+ if (!BN_bin2bn(md, qsize, r0))
+ goto err;
+ if (!BN_lshift(r0, r0, (qsize << 3) * k))
+ goto err;
+ if (!BN_add(W, W, r0))
+ goto err;
+ }
+
+ /* more of step 8 */
+ if (!BN_mask_bits(W, bits - 1))
+ goto err;
+ if (!BN_copy(X, W))
+ goto err;
+ if (!BN_add(X, X, test))
+ goto err;
+
+ /* step 9 */
+ if (!BN_lshift1(r0, q))
+ goto err;
+ if (!BN_mod(c, X, r0, ctx))
+ goto err;
+ if (!BN_sub(r0, c, BN_value_one()))
+ goto err;
+ if (!BN_sub(p, X, r0))
+ goto err;
+
+ /* step 10 */
+ if (BN_cmp(p, test) >= 0) {
+ /* step 11 */
+ r = BN_is_prime_fasttest_ex(p, DSS_prime_checks, ctx, 1, cb);
+ if (r > 0)
+ goto end; /* found it */
+ if (r != 0)
+ goto err;
+ }
+
+ /* step 13 */
+ counter++;
+ /* "offset = offset + n + 1" */
+
+ /* step 14 */
+ if (counter >= 4096)
+ break;
+ }
+ }
+end:
+ if (!BN_GENCB_call(cb, 2, 1))
+ goto err;
+
+ /* We now need to generate g */
+ /* Set r0=(p-1)/q */
+ if (!BN_sub(test, p, BN_value_one()))
+ goto err;
+ if (!BN_div(r0, NULL, test, q, ctx))
+ goto err;
+
+ if (!BN_set_word(test, h))
+ goto err;
+ if (!BN_MONT_CTX_set(mont, p, ctx))
+ goto err;
+
+ for (;;) {
+ /* g=test^r0%p */
+ if (!BN_mod_exp_mont(g, test, r0, p, ctx, mont))
+ goto err;
+ if (!BN_is_one(g))
+ break;
+ if (!BN_add(test, test, BN_value_one()))
+ goto err;
+ h++;
+ }
+
+ if (!BN_GENCB_call(cb, 3, 1))
+ goto err;
+
+ ok = 1;
+
+err:
+ if (ok) {
+ if (ret->p)
+ BN_free(ret->p);
+ if (ret->q)
+ BN_free(ret->q);
+ if (ret->g)
+ BN_free(ret->g);
+ ret->p = BN_dup(p);
+ ret->q = BN_dup(q);
+ ret->g = BN_dup(g);
+ if (ret->p == NULL || ret->q == NULL || ret->g == NULL) {
+ ok = 0;
+ goto err;
+ }
+ if (counter_ret != NULL)
+ *counter_ret = counter;
+ if (h_ret != NULL)
+ *h_ret = h;
+ }
+
+ if (ctx) {
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ }
+
+ if (mont != NULL)
+ BN_MONT_CTX_free(mont);
+
+ return ok;
+}
+
+static int finish(DSA *dsa) {
+ BN_MONT_CTX_free(dsa->method_mont_p);
+ dsa->method_mont_p = NULL;
+ return 1;
+}
+
+const struct dsa_method DSA_default_method = {
+ {
+ 0 /* references */,
+ 1 /* is_static */,
+ },
+ NULL /* app_data */,
+
+ NULL /* init */,
+ finish /* finish */,
+
+ sign,
+ sign_setup,
+ verify,
+
+ paramgen,
+ keygen,
+};
diff --git a/crypto/dsa/dsa_test.c b/crypto/dsa/dsa_test.c
new file mode 100644
index 0000000..8841c12
--- /dev/null
+++ b/crypto/dsa/dsa_test.c
@@ -0,0 +1,214 @@
+/* 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.]
+ *
+ * The DSS routines are based on patches supplied by
+ * Steven Schoch <schoch@sheba.arc.nasa.gov>. */
+
+#include <openssl/dsa.h>
+
+#include <openssl/bio.h>
+#include <openssl/bn.h>
+
+#include "internal.h"
+
+
+static int dsa_cb(int p, int n, BN_GENCB *arg);
+
+/* seed, out_p, out_q, out_g are taken from the updated Appendix 5 to
+ * FIPS PUB 186 and also appear in Appendix 5 to FIPS PIB 186-1 */
+static unsigned char seed[20] = {0xd5, 0x01, 0x4e, 0x4b, 0x60, 0xef, 0x2b,
+ 0xa8, 0xb6, 0x21, 0x1b, 0x40, 0x62, 0xba,
+ 0x32, 0x24, 0xe0, 0x42, 0x7d, 0xd3, };
+
+static unsigned char out_p[] = {
+ 0x8d, 0xf2, 0xa4, 0x94, 0x49, 0x22, 0x76, 0xaa, 0x3d, 0x25, 0x75,
+ 0x9b, 0xb0, 0x68, 0x69, 0xcb, 0xea, 0xc0, 0xd8, 0x3a, 0xfb, 0x8d,
+ 0x0c, 0xf7, 0xcb, 0xb8, 0x32, 0x4f, 0x0d, 0x78, 0x82, 0xe5, 0xd0,
+ 0x76, 0x2f, 0xc5, 0xb7, 0x21, 0x0e, 0xaf, 0xc2, 0xe9, 0xad, 0xac,
+ 0x32, 0xab, 0x7a, 0xac, 0x49, 0x69, 0x3d, 0xfb, 0xf8, 0x37, 0x24,
+ 0xc2, 0xec, 0x07, 0x36, 0xee, 0x31, 0xc8, 0x02, 0x91, };
+
+static unsigned char out_q[] = {0xc7, 0x73, 0x21, 0x8c, 0x73, 0x7e, 0xc8,
+ 0xee, 0x99, 0x3b, 0x4f, 0x2d, 0xed, 0x30,
+ 0xf4, 0x8e, 0xda, 0xce, 0x91, 0x5f, };
+
+static unsigned char out_g[] = {
+ 0x62, 0x6d, 0x02, 0x78, 0x39, 0xea, 0x0a, 0x13, 0x41, 0x31, 0x63,
+ 0xa5, 0x5b, 0x4c, 0xb5, 0x00, 0x29, 0x9d, 0x55, 0x22, 0x95, 0x6c,
+ 0xef, 0xcb, 0x3b, 0xff, 0x10, 0xf3, 0x99, 0xce, 0x2c, 0x2e, 0x71,
+ 0xcb, 0x9d, 0xe5, 0xfa, 0x24, 0xba, 0xbf, 0x58, 0xe5, 0xb7, 0x95,
+ 0x21, 0x92, 0x5c, 0x9c, 0xc4, 0x2e, 0x9f, 0x6f, 0x46, 0x4b, 0x08,
+ 0x8c, 0xc5, 0x72, 0xaf, 0x53, 0xe6, 0xd7, 0x88, 0x02, };
+
+static const uint8_t str1[]="12345678901234567890";
+
+static BIO *bio_err = NULL;
+static BIO *bio_out = NULL;
+
+int main(int argc, char **argv) {
+ BN_GENCB cb;
+ DSA *dsa = NULL;
+ int counter, ok = 0, i, j;
+ unsigned char buf[256];
+ unsigned long h;
+ unsigned char sig[256];
+ unsigned int siglen;
+
+ bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
+ bio_out = BIO_new_fp(stdout, BIO_NOCLOSE);
+
+ BIO_printf(bio_out, "test generation of DSA parameters\n");
+
+ BN_GENCB_set(&cb, dsa_cb, bio_out);
+ dsa = DSA_new();
+ if (dsa == NULL ||
+ !DSA_generate_parameters_ex(dsa, 512, seed, 20, &counter, &h, &cb)) {
+ goto end;
+ }
+
+ BIO_printf(bio_out, "seed\n");
+ for (i = 0; i < 20; i += 4) {
+ BIO_printf(bio_out, "%02X%02X%02X%02X ", seed[i], seed[i + 1], seed[i + 2],
+ seed[i + 3]);
+ }
+ BIO_printf(bio_out, "\ncounter=%d h=%ld\n", counter, h);
+
+ if (counter != 105) {
+ BIO_printf(bio_err, "counter should be 105\n");
+ goto end;
+ }
+ if (h != 2) {
+ BIO_printf(bio_err, "h should be 2\n");
+ goto end;
+ }
+
+ i = BN_bn2bin(dsa->q, buf);
+ j = sizeof(out_q);
+ if (i != j || memcmp(buf, out_q, i) != 0) {
+ BIO_printf(bio_err, "q value is wrong\n");
+ goto end;
+ }
+
+ i = BN_bn2bin(dsa->p, buf);
+ j = sizeof(out_p);
+ if (i != j || memcmp(buf, out_p, i) != 0) {
+ BIO_printf(bio_err, "p value is wrong\n");
+ goto end;
+ }
+
+ i = BN_bn2bin(dsa->g, buf);
+ j = sizeof(out_g);
+ if (i != j || memcmp(buf, out_g, i) != 0) {
+ BIO_printf(bio_err, "g value is wrong\n");
+ goto end;
+ }
+
+ DSA_generate_key(dsa);
+ DSA_sign(0, str1, 20, sig, &siglen, dsa);
+ if (DSA_verify(0, str1, 20, sig, siglen, dsa) == 1) {
+ ok = 1;
+ } else {
+ BIO_printf(bio_err, "verification failure\n");
+ }
+
+end:
+ if (!ok) {
+ BIO_print_errors(bio_err);
+ }
+ if (dsa != NULL) {
+ DSA_free(dsa);
+ }
+
+ BIO_free(bio_err);
+ BIO_free(bio_out);
+
+ if (ok) {
+ printf("PASS\n");
+ }
+
+ return ok == 1 ? 0 : 1;
+}
+
+static int dsa_cb(int p, int n, BN_GENCB *arg) {
+ char c = '*';
+ static int ok = 0, num = 0;
+
+ switch (p) {
+ case 0:
+ c = '.';
+ num++;
+ break;
+ case 1:
+ c = '+';
+ break;
+ case 2:
+ c = '*';
+ ok++;
+ break;
+ case 3:
+ c = '\n';
+ }
+
+ BIO_write(arg->arg, &c, 1);
+ (void)BIO_flush(arg->arg);
+
+ if (!ok && p == 0 && num > 1) {
+ BIO_printf((BIO *)arg, "error in dsatest\n");
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/crypto/dsa/internal.h b/crypto/dsa/internal.h
new file mode 100644
index 0000000..ef99158
--- /dev/null
+++ b/crypto/dsa/internal.h
@@ -0,0 +1,78 @@
+/* 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.]
+ *
+ * The DSS routines are based on patches supplied by
+ * Steven Schoch <schoch@sheba.arc.nasa.gov>. */
+
+#ifndef OPENSSL_HEADER_DSA_INTERNAL_H
+#define OPENSSL_HEADER_DSA_INTERNAL_H
+
+#include <openssl/base.h>
+
+#include <openssl/bn.h>
+#include <openssl/ex_data.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_DSA_INTERNAL_H */
diff --git a/crypto/ec/CMakeLists.txt b/crypto/ec/CMakeLists.txt
new file mode 100644
index 0000000..019916f
--- /dev/null
+++ b/crypto/ec/CMakeLists.txt
@@ -0,0 +1,24 @@
+include_directories(. .. ../../include)
+
+add_library(
+ ec
+
+ OBJECT
+
+ ec.c
+ oct.c
+ simple.c
+ ec_montgomery.c
+ wnaf.c
+ ec_key.c
+ ec_asn1.c
+ ec_error.c
+)
+
+add_executable(
+ example_mul
+
+ example_mul.c
+)
+
+target_link_libraries(example_mul crypto)
diff --git a/crypto/ec/ec.c b/crypto/ec/ec.c
new file mode 100644
index 0000000..ef022bc
--- /dev/null
+++ b/crypto/ec/ec.c
@@ -0,0 +1,872 @@
+/* Originally written by Bodo Moeller for the OpenSSL project.
+ * ====================================================================
+ * Copyright (c) 1998-2005 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).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * The elliptic curve binary polynomial software is originally written by
+ * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems
+ * Laboratories. */
+
+#include <openssl/ec.h>
+
+#include <openssl/bn.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+
+#include "internal.h"
+
+
+/* curve_data contains data about a built-in elliptic curve. */
+struct curve_data {
+ /* comment is a human-readable string describing the curve. */
+ const char *comment;
+ /* param_len is the number of bytes needed to store a field element. */
+ uint8_t param_len;
+ /* cofactor is the cofactor of the group (i.e. the number of elements in the
+ * group divided by the size of the main subgroup. */
+ uint8_t cofactor; /* promoted to BN_ULONG */
+ /* data points to an array of 6*|param_len| bytes which hold the field
+ * elements of the following (in big-endian order): prime, a, b, generator x,
+ * generator y, order. */
+ const uint8_t data[];
+};
+
+static const struct curve_data P224 = {
+ "NIST P-224",
+ 28,
+ 1,
+ {/* p */
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01,
+ /* a */
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFE,
+ /* b */
+ 0xB4, 0x05, 0x0A, 0x85, 0x0C, 0x04, 0xB3, 0xAB, 0xF5, 0x41, 0x32, 0x56,
+ 0x50, 0x44, 0xB0, 0xB7, 0xD7, 0xBF, 0xD8, 0xBA, 0x27, 0x0B, 0x39, 0x43,
+ 0x23, 0x55, 0xFF, 0xB4,
+ /* x */
+ 0xB7, 0x0E, 0x0C, 0xBD, 0x6B, 0xB4, 0xBF, 0x7F, 0x32, 0x13, 0x90, 0xB9,
+ 0x4A, 0x03, 0xC1, 0xD3, 0x56, 0xC2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xD6,
+ 0x11, 0x5C, 0x1D, 0x21,
+ /* y */
+ 0xbd, 0x37, 0x63, 0x88, 0xb5, 0xf7, 0x23, 0xfb, 0x4c, 0x22, 0xdf, 0xe6,
+ 0xcd, 0x43, 0x75, 0xa0, 0x5a, 0x07, 0x47, 0x64, 0x44, 0xd5, 0x81, 0x99,
+ 0x85, 0x00, 0x7e, 0x34,
+ /* order */
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0x16, 0xA2, 0xE0, 0xB8, 0xF0, 0x3E, 0x13, 0xDD, 0x29, 0x45,
+ 0x5C, 0x5C, 0x2A, 0x3D,
+ }};
+
+static const struct curve_data P256 = {
+ "NIST P-256",
+ 32,
+ 1,
+ {/* p */
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ /* a */
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC,
+ /* b */
+ 0x5A, 0xC6, 0x35, 0xD8, 0xAA, 0x3A, 0x93, 0xE7, 0xB3, 0xEB, 0xBD, 0x55,
+ 0x76, 0x98, 0x86, 0xBC, 0x65, 0x1D, 0x06, 0xB0, 0xCC, 0x53, 0xB0, 0xF6,
+ 0x3B, 0xCE, 0x3C, 0x3E, 0x27, 0xD2, 0x60, 0x4B,
+ /* x */
+ 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, 0xBC, 0xE6, 0xE5,
+ 0x63, 0xA4, 0x40, 0xF2, 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0,
+ 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, 0x96,
+ /* y */
+ 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a,
+ 0x7c, 0x0f, 0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce,
+ 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5,
+ /* order */
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84,
+ 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51}};
+
+static const struct curve_data P384 = {
+ "NIST P-384",
+ 48,
+ 1,
+ {/* p */
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ /* a */
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFC,
+ /* b */
+ 0xB3, 0x31, 0x2F, 0xA7, 0xE2, 0x3E, 0xE7, 0xE4, 0x98, 0x8E, 0x05, 0x6B,
+ 0xE3, 0xF8, 0x2D, 0x19, 0x18, 0x1D, 0x9C, 0x6E, 0xFE, 0x81, 0x41, 0x12,
+ 0x03, 0x14, 0x08, 0x8F, 0x50, 0x13, 0x87, 0x5A, 0xC6, 0x56, 0x39, 0x8D,
+ 0x8A, 0x2E, 0xD1, 0x9D, 0x2A, 0x85, 0xC8, 0xED, 0xD3, 0xEC, 0x2A, 0xEF,
+ /* x */
+ 0xAA, 0x87, 0xCA, 0x22, 0xBE, 0x8B, 0x05, 0x37, 0x8E, 0xB1, 0xC7, 0x1E,
+ 0xF3, 0x20, 0xAD, 0x74, 0x6E, 0x1D, 0x3B, 0x62, 0x8B, 0xA7, 0x9B, 0x98,
+ 0x59, 0xF7, 0x41, 0xE0, 0x82, 0x54, 0x2A, 0x38, 0x55, 0x02, 0xF2, 0x5D,
+ 0xBF, 0x55, 0x29, 0x6C, 0x3A, 0x54, 0x5E, 0x38, 0x72, 0x76, 0x0A, 0xB7,
+ /* y */
+ 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f, 0x5d, 0x9e, 0x98, 0xbf,
+ 0x92, 0x92, 0xdc, 0x29, 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c,
+ 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0, 0x0a, 0x60, 0xb1, 0xce,
+ 0x1d, 0x7e, 0x81, 0x9d, 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f,
+ /* order */
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xC7, 0x63, 0x4D, 0x81, 0xF4, 0x37, 0x2D, 0xDF, 0x58, 0x1A, 0x0D, 0xB2,
+ 0x48, 0xB0, 0xA7, 0x7A, 0xEC, 0xEC, 0x19, 0x6A, 0xCC, 0xC5, 0x29, 0x73}};
+
+static const struct curve_data P521 = {
+ "NIST P-521",
+ 66,
+ 1,
+ {/* p */
+ 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ /* a */
+ 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC,
+ /* b */
+ 0x00, 0x51, 0x95, 0x3E, 0xB9, 0x61, 0x8E, 0x1C, 0x9A, 0x1F, 0x92, 0x9A,
+ 0x21, 0xA0, 0xB6, 0x85, 0x40, 0xEE, 0xA2, 0xDA, 0x72, 0x5B, 0x99, 0xB3,
+ 0x15, 0xF3, 0xB8, 0xB4, 0x89, 0x91, 0x8E, 0xF1, 0x09, 0xE1, 0x56, 0x19,
+ 0x39, 0x51, 0xEC, 0x7E, 0x93, 0x7B, 0x16, 0x52, 0xC0, 0xBD, 0x3B, 0xB1,
+ 0xBF, 0x07, 0x35, 0x73, 0xDF, 0x88, 0x3D, 0x2C, 0x34, 0xF1, 0xEF, 0x45,
+ 0x1F, 0xD4, 0x6B, 0x50, 0x3F, 0x00,
+ /* x */
+ 0x00, 0xC6, 0x85, 0x8E, 0x06, 0xB7, 0x04, 0x04, 0xE9, 0xCD, 0x9E, 0x3E,
+ 0xCB, 0x66, 0x23, 0x95, 0xB4, 0x42, 0x9C, 0x64, 0x81, 0x39, 0x05, 0x3F,
+ 0xB5, 0x21, 0xF8, 0x28, 0xAF, 0x60, 0x6B, 0x4D, 0x3D, 0xBA, 0xA1, 0x4B,
+ 0x5E, 0x77, 0xEF, 0xE7, 0x59, 0x28, 0xFE, 0x1D, 0xC1, 0x27, 0xA2, 0xFF,
+ 0xA8, 0xDE, 0x33, 0x48, 0xB3, 0xC1, 0x85, 0x6A, 0x42, 0x9B, 0xF9, 0x7E,
+ 0x7E, 0x31, 0xC2, 0xE5, 0xBD, 0x66,
+ /* y */
+ 0x01, 0x18, 0x39, 0x29, 0x6a, 0x78, 0x9a, 0x3b, 0xc0, 0x04, 0x5c, 0x8a,
+ 0x5f, 0xb4, 0x2c, 0x7d, 0x1b, 0xd9, 0x98, 0xf5, 0x44, 0x49, 0x57, 0x9b,
+ 0x44, 0x68, 0x17, 0xaf, 0xbd, 0x17, 0x27, 0x3e, 0x66, 0x2c, 0x97, 0xee,
+ 0x72, 0x99, 0x5e, 0xf4, 0x26, 0x40, 0xc5, 0x50, 0xb9, 0x01, 0x3f, 0xad,
+ 0x07, 0x61, 0x35, 0x3c, 0x70, 0x86, 0xa2, 0x72, 0xc2, 0x40, 0x88, 0xbe,
+ 0x94, 0x76, 0x9f, 0xd1, 0x66, 0x50,
+ /* order */
+ 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0x51, 0x86,
+ 0x87, 0x83, 0xBF, 0x2F, 0x96, 0x6B, 0x7F, 0xCC, 0x01, 0x48, 0xF7, 0x09,
+ 0xA5, 0xD0, 0x3B, 0xB5, 0xC9, 0xB8, 0x89, 0x9C, 0x47, 0xAE, 0xBB, 0x6F,
+ 0xB7, 0x1E, 0x91, 0x38, 0x64, 0x09}};
+
+struct built_in_curve {
+ int nid;
+ const struct curve_data *data;
+ const EC_METHOD *(*method)(void);
+};
+
+static const struct built_in_curve built_in_curves[] = {
+ {NID_secp224r1, &P224, 0},
+ {NID_X9_62_prime256v1, &P256, 0},
+ {NID_secp384r1, &P384, 0},
+ {NID_secp521r1, &P521, 0},
+ {NID_undef, 0, 0},
+};
+
+EC_GROUP *ec_group_new(const EC_METHOD *meth) {
+ EC_GROUP *ret;
+
+ if (meth == NULL) {
+ OPENSSL_PUT_ERROR(EC, ec_group_new, 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);
+ return NULL;
+ }
+
+ ret = OPENSSL_malloc(sizeof(EC_GROUP));
+ if (ret == NULL) {
+ OPENSSL_PUT_ERROR(EC, ec_group_new, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ memset(ret, 0, sizeof(EC_GROUP));
+
+ ret->meth = meth;
+ BN_init(&ret->order);
+ BN_init(&ret->cofactor);
+ ret->asn1_form = POINT_CONVERSION_UNCOMPRESSED;
+
+ if (!meth->group_init(ret)) {
+ OPENSSL_free(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+static EC_GROUP *ec_group_new_curve_GFp(const BIGNUM *p, const BIGNUM *a,
+ const BIGNUM *b, BN_CTX *ctx) {
+ const EC_METHOD *meth = EC_GFp_mont_method();
+ EC_GROUP *ret;
+
+ ret = ec_group_new(meth);
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ if (ret->meth->group_set_curve == 0) {
+ OPENSSL_PUT_ERROR(EC, ec_group_new_curve_GFp,
+ ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+ if (!ret->meth->group_set_curve(ret, p, a, b, ctx)) {
+ EC_GROUP_free(ret);
+ return NULL;
+ }
+ return ret;
+}
+
+static EC_GROUP *ec_group_new_from_data(const struct built_in_curve *curve) {
+ 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;
+ int ok = 0;
+ unsigned param_len;
+ const EC_METHOD *meth;
+ const struct curve_data *data;
+ const uint8_t *params;
+
+ if ((ctx = BN_CTX_new()) == NULL) {
+ OPENSSL_PUT_ERROR(EC, ec_group_new_from_data, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ data = curve->data;
+ param_len = data->param_len;
+ params = data->data;
+
+ 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);
+ goto err;
+ }
+
+ if (curve->method != 0) {
+ 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);
+ 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);
+ goto err;
+ }
+ }
+
+ if ((P = EC_POINT_new(group)) == NULL) {
+ OPENSSL_PUT_ERROR(EC, ec_group_new_from_data, 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);
+ 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);
+ 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);
+ 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:
+ if (!ok) {
+ EC_GROUP_free(group);
+ group = NULL;
+ }
+ if (P)
+ EC_POINT_free(P);
+ if (ctx)
+ BN_CTX_free(ctx);
+ if (p)
+ BN_free(p);
+ if (a)
+ BN_free(a);
+ if (b)
+ BN_free(b);
+ if (order)
+ BN_free(order);
+ if (x)
+ BN_free(x);
+ if (y)
+ BN_free(y);
+ return group;
+}
+
+EC_GROUP *EC_GROUP_new_by_curve_name(int nid) {
+ unsigned i;
+ const struct built_in_curve *curve;
+ EC_GROUP *ret = NULL;
+
+ for (i = 0; built_in_curves[i].nid != NID_undef; i++) {
+ curve = &built_in_curves[i];
+ if (curve->nid == nid) {
+ ret = ec_group_new_from_data(curve);
+ break;
+ }
+ }
+
+ if (ret == NULL) {
+ OPENSSL_PUT_ERROR(EC, EC_GROUP_new_by_curve_name, EC_R_UNKNOWN_GROUP);
+ return NULL;
+ }
+
+ ret->curve_name = nid;
+ return ret;
+}
+
+void EC_GROUP_free(EC_GROUP *group) {
+ if (!group) {
+ return;
+ }
+
+ if (group->meth->group_finish != 0) {
+ group->meth->group_finish(group);
+ }
+
+ ec_pre_comp_free(group->pre_comp);
+
+ if (group->generator != NULL) {
+ EC_POINT_free(group->generator);
+ }
+ BN_free(&group->order);
+ BN_free(&group->cofactor);
+
+ OPENSSL_free(group);
+}
+
+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);
+ return 0;
+ }
+ if (dest->meth != src->meth) {
+ OPENSSL_PUT_ERROR(EC, EC_GROUP_copy, EC_R_INCOMPATIBLE_OBJECTS);
+ return 0;
+ }
+ if (dest == src) {
+ return 1;
+ }
+
+ ec_pre_comp_free(dest->pre_comp);
+ dest->pre_comp = ec_pre_comp_dup(src->pre_comp);
+
+ if (src->generator != NULL) {
+ if (dest->generator == NULL) {
+ dest->generator = EC_POINT_new(dest);
+ if (dest->generator == NULL) {
+ return 0;
+ }
+ }
+ if (!EC_POINT_copy(dest->generator, src->generator)) {
+ return 0;
+ }
+ } else {
+ /* src->generator == NULL */
+ if (dest->generator != NULL) {
+ EC_POINT_clear_free(dest->generator);
+ dest->generator = NULL;
+ }
+ }
+
+ if (!BN_copy(&dest->order, &src->order) ||
+ !BN_copy(&dest->cofactor, &src->cofactor)) {
+ return 0;
+ }
+
+ dest->curve_name = src->curve_name;
+ dest->asn1_form = src->asn1_form;
+
+ return dest->meth->group_copy(dest, src);
+}
+
+EC_GROUP *EC_GROUP_dup(const EC_GROUP *a) {
+ EC_GROUP *t = NULL;
+ int ok = 0;
+
+ if (a == NULL) {
+ return NULL;
+ }
+
+ t = ec_group_new(a->meth);
+ if (t == NULL) {
+ return NULL;
+ }
+ if (!EC_GROUP_copy(t, a)) {
+ goto err;
+ }
+
+ ok = 1;
+
+err:
+ if (!ok) {
+ if (t) {
+ EC_GROUP_free(t);
+ }
+ return NULL;
+ } else {
+ return t;
+ }
+}
+
+int EC_GROUP_cmp(const EC_GROUP *a, const EC_GROUP *b) {
+ if (a->curve_name == NID_undef || b->curve_name == NID_undef) {
+ return 0;
+ }
+ return a->curve_name == b->curve_name;
+}
+
+const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *group) {
+ return group->generator;
+}
+
+int EC_GROUP_get_order(const EC_GROUP *group, BIGNUM *order, BN_CTX *ctx) {
+ if (!BN_copy(order, &group->order)) {
+ return 0;
+ }
+
+ return !BN_is_zero(order);
+}
+
+int EC_GROUP_get_cofactor(const EC_GROUP *group, BIGNUM *cofactor,
+ BN_CTX *ctx) {
+ if (!BN_copy(cofactor, &group->cofactor)) {
+ return 0;
+ }
+
+ return !BN_is_zero(&group->cofactor);
+}
+
+int EC_GROUP_get_curve_name(const EC_GROUP *group) { return group->curve_name; }
+
+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);
+ return 0;
+ }
+ return group->meth->group_get_degree(group);
+}
+
+void EC_GROUP_set_point_conversion_form(EC_GROUP *group,
+ point_conversion_form_t form) {
+ group->asn1_form = form;
+}
+
+int EC_GROUP_precompute_mult(EC_GROUP *group, BN_CTX *ctx) {
+ if (group->meth->mul == 0) {
+ /* use default */
+ return ec_wNAF_precompute_mult(group, ctx);
+ }
+
+ if (group->meth->precompute_mult != 0) {
+ return group->meth->precompute_mult(group, ctx);
+ }
+
+ return 1; /* nothing to do, so report success */
+}
+
+int EC_GROUP_have_precompute_mult(const EC_GROUP *group) {
+ if (group->meth->mul == 0) {
+ /* use default */
+ return ec_wNAF_have_precompute_mult(group);
+ }
+
+ if (group->meth->have_precompute_mult != 0) {
+ return group->meth->have_precompute_mult(group);
+ }
+
+ return 0; /* cannot tell whether precomputation has been performed */
+}
+
+EC_POINT *EC_POINT_new(const EC_GROUP *group) {
+ EC_POINT *ret;
+
+ if (group == NULL) {
+ OPENSSL_PUT_ERROR(EC, EC_POINT_new, 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);
+ return NULL;
+ }
+
+ ret = OPENSSL_malloc(sizeof *ret);
+ if (ret == NULL) {
+ OPENSSL_PUT_ERROR(EC, EC_POINT_new, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ ret->meth = group->meth;
+
+ if (!ret->meth->point_init(ret)) {
+ OPENSSL_free(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+void EC_POINT_free(EC_POINT *point) {
+ if (!point) {
+ return;
+ }
+
+ if (point->meth->point_finish != 0) {
+ point->meth->point_finish(point);
+ }
+ OPENSSL_free(point);
+}
+
+void EC_POINT_clear_free(EC_POINT *point) {
+ if (!point) {
+ return;
+ }
+
+ if (point->meth->point_clear_finish != 0) {
+ point->meth->point_clear_finish(point);
+ } else if (point->meth->point_finish != 0) {
+ point->meth->point_finish(point);
+ }
+ OPENSSL_cleanse(point, sizeof *point);
+ OPENSSL_free(point);
+}
+
+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);
+ return 0;
+ }
+ if (dest->meth != src->meth) {
+ OPENSSL_PUT_ERROR(EC, EC_POINT_copy, EC_R_INCOMPATIBLE_OBJECTS);
+ return 0;
+ }
+ if (dest == src) {
+ return 1;
+ }
+ return dest->meth->point_copy(dest, src);
+}
+
+EC_POINT *EC_POINT_dup(const EC_POINT *a, const EC_GROUP *group) {
+ EC_POINT *t;
+ int r;
+
+ if (a == NULL) {
+ return NULL;
+ }
+
+ t = EC_POINT_new(group);
+ if (t == NULL) {
+ OPENSSL_PUT_ERROR(EC, EC_POINT_dup, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ r = EC_POINT_copy(t, a);
+ if (!r) {
+ EC_POINT_free(t);
+ return NULL;
+ } else {
+ return t;
+ }
+}
+
+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);
+ return 0;
+ }
+ if (group->meth != point->meth) {
+ OPENSSL_PUT_ERROR(EC, EC_POINT_set_to_infinity, EC_R_INCOMPATIBLE_OBJECTS);
+ return 0;
+ }
+ return group->meth->point_set_to_infinity(group, point);
+}
+
+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);
+ return 0;
+ }
+ if (group->meth != point->meth) {
+ OPENSSL_PUT_ERROR(EC, EC_POINT_is_at_infinity, EC_R_INCOMPATIBLE_OBJECTS);
+ return 0;
+ }
+ return group->meth->is_at_infinity(group, point);
+}
+
+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);
+ return 0;
+ }
+ if (group->meth != point->meth) {
+ OPENSSL_PUT_ERROR(EC, EC_POINT_is_on_curve, EC_R_INCOMPATIBLE_OBJECTS);
+ return 0;
+ }
+ return group->meth->is_on_curve(group, point, ctx);
+}
+
+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);
+ return -1;
+ }
+ if ((group->meth != a->meth) || (a->meth != b->meth)) {
+ OPENSSL_PUT_ERROR(EC, EC_POINT_cmp, EC_R_INCOMPATIBLE_OBJECTS);
+ return -1;
+ }
+ return group->meth->point_cmp(group, a, b, ctx);
+}
+
+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);
+ return 0;
+ }
+ if (group->meth != point->meth) {
+ OPENSSL_PUT_ERROR(EC, EC_POINT_make_affine, EC_R_INCOMPATIBLE_OBJECTS);
+ return 0;
+ }
+ return group->meth->make_affine(group, point, ctx);
+}
+
+int EC_POINTs_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[],
+ BN_CTX *ctx) {
+ 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);
+ 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);
+ return 0;
+ }
+ }
+ return group->meth->points_make_affine(group, num, points, ctx);
+}
+
+int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group,
+ 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);
+ return 0;
+ }
+ if (group->meth != point->meth) {
+ OPENSSL_PUT_ERROR(EC, EC_POINT_get_affine_coordinates_GFp,
+ EC_R_INCOMPATIBLE_OBJECTS);
+ return 0;
+ }
+ return group->meth->point_get_affine_coordinates(group, point, x, y, ctx);
+}
+
+int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *point,
+ 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);
+ return 0;
+ }
+ if (group->meth != point->meth) {
+ OPENSSL_PUT_ERROR(EC, EC_POINT_set_affine_coordinates_GFp,
+ EC_R_INCOMPATIBLE_OBJECTS);
+ return 0;
+ }
+ return group->meth->point_set_affine_coordinates(group, point, x, y, ctx);
+}
+
+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);
+ 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);
+ return 0;
+ }
+ return group->meth->add(group, r, a, b, ctx);
+}
+
+
+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);
+ return 0;
+ }
+ if ((group->meth != r->meth) || (r->meth != a->meth)) {
+ OPENSSL_PUT_ERROR(EC, EC_POINT_dbl, EC_R_INCOMPATIBLE_OBJECTS);
+ return 0;
+ }
+ return group->meth->dbl(group, r, a, ctx);
+}
+
+
+int EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, BN_CTX *ctx) {
+ if (group->meth->dbl == 0) {
+ OPENSSL_PUT_ERROR(EC, EC_POINT_invert, 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);
+ return 0;
+ }
+ return group->meth->invert(group, a, ctx);
+}
+
+int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,
+ const EC_POINT *point, const BIGNUM *p_scalar, BN_CTX *ctx) {
+ /* just a convenient interface to EC_POINTs_mul() */
+
+ const EC_POINT *points[1];
+ const BIGNUM *scalars[1];
+
+ points[0] = point;
+ scalars[0] = p_scalar;
+
+ return EC_POINTs_mul(group, r, g_scalar, (point != NULL && p_scalar != NULL),
+ points, scalars, ctx);
+}
+
+int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
+ size_t num, const EC_POINT *points[], const BIGNUM *scalars[],
+ BN_CTX *ctx) {
+ if (group->meth->mul == 0) {
+ /* use default. Warning, not constant-time. */
+ return ec_wNAF_mul(group, r, scalar, num, points, scalars, ctx);
+ }
+
+ return group->meth->mul(group, r, scalar, num, points, scalars, ctx);
+}
+
+int ec_point_set_Jprojective_coordinates_GFp(const EC_GROUP *group, EC_POINT *point,
+ 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);
+ return 0;
+ }
+ if (group->meth != point->meth) {
+ OPENSSL_PUT_ERROR(EC, ec_point_set_Jprojective_coordinates_GFp,
+ EC_R_INCOMPATIBLE_OBJECTS);
+ return 0;
+ }
+ return group->meth->point_set_Jprojective_coordinates_GFp(group, point, x, y,
+ z, ctx);
+}
diff --git a/crypto/ec/ec.h b/crypto/ec/ec.h
new file mode 100644
index 0000000..368432e
--- /dev/null
+++ b/crypto/ec/ec.h
@@ -0,0 +1,367 @@
+/* Originally written by Bodo Moeller for the OpenSSL project.
+ * ====================================================================
+ * Copyright (c) 1998-2005 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).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * The elliptic curve binary polynomial software is originally written by
+ * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems
+ * Laboratories. */
+
+#ifndef OPENSSL_HEADER_EC_H
+#define OPENSSL_HEADER_EC_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+typedef struct ec_group_st EC_GROUP;
+typedef struct ec_point_st EC_POINT;
+
+/** Enum for the point conversion form as defined in X9.62 (ECDSA)
+ * for the encoding of a elliptic curve point (x,y) */
+typedef enum {
+ /** the point is encoded as z||x, where the octet z specifies
+ * which solution of the quadratic equation y is */
+ POINT_CONVERSION_COMPRESSED = 2,
+ /** the point is encoded as z||x||y, where z is the octet 0x02 */
+ POINT_CONVERSION_UNCOMPRESSED = 4,
+ /** the point is encoded as z||x||y, where the octet z specifies
+ * which solution of the quadratic equation y is */
+ POINT_CONVERSION_HYBRID = 6
+} point_conversion_form_t;
+
+
+/* Elliptic curve groups. */
+
+/* EC_GROUP_new_by_curve_name returns a fresh EC_GROUP object for the elliptic
+ * curve specified by |nid|, or NULL on error.
+ *
+ * The supported NIDs are:
+ * NID_secp224r1,
+ * NID_X9_62_prime256v1,
+ * NID_secp384r1,
+ * NID_secp521r1 */
+EC_GROUP *EC_GROUP_new_by_curve_name(int nid);
+
+/* EC_GROUP_free frees |group| and the data that it points to. */
+void EC_GROUP_free(EC_GROUP *group);
+
+/* EC_GROUP_copy sets |*dest| equal to |*src|. It returns one on success and
+ * zero otherwise. */
+int EC_GROUP_copy(EC_GROUP *dest, const EC_GROUP *src);
+
+/* EC_GROUP_dup returns a fresh |EC_GROUP| which is equal to |a| or NULL on
+ * error. */
+EC_GROUP *EC_GROUP_dup(const EC_GROUP *a);
+
+/* EC_GROUP_cmp returns one if |a| and |b| are the same group and zero
+ * otherwise. */
+int EC_GROUP_cmp(const EC_GROUP *a, const EC_GROUP *b);
+
+/* EC_GROUP_get0_generator returns a pointer to the internal |EC_POINT| object
+ * in |group| that specifies the generator for the group. */
+const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *group);
+
+/* EC_GROUP_get_order sets |*order| to the order of |group| using |ctx|, if
+ * it's not NULL. It returns one on success and zero otherwise. */
+int EC_GROUP_get_order(const EC_GROUP *group, BIGNUM *order, BN_CTX *ctx);
+
+/* EC_GROUP_get_cofactor sets |*cofactor| to the cofactor of |group| using
+ * |ctx|, if it's not NULL. It returns one on success and zero otherwise. */
+int EC_GROUP_get_cofactor(const EC_GROUP *group, BIGNUM *cofactor, BN_CTX *ctx);
+
+/* EC_GROUP_get_curve_name returns a NID that identifies |group|. */
+int EC_GROUP_get_curve_name(const EC_GROUP *group);
+
+/* EC_GROUP_get_degree returns the number of bits needed to represent an
+ * element of the field underlying |group|. */
+int EC_GROUP_get_degree(const EC_GROUP *group);
+
+/* EC_GROUP_set_point_conversion_form sets the form that serialised points will
+ * take as one of the |POINT_CONVERSION_*| values. */
+void EC_GROUP_set_point_conversion_form(EC_GROUP *group,
+ point_conversion_form_t form);
+
+/* EC_GROUP_precompute_mult precomputes multiplies of the generator in order to
+ * speed up operations that involve calculating generator multiples. It returns
+ * one on sucess and zero otherwise. If |ctx| is not NULL, it may be used. */
+int EC_GROUP_precompute_mult(EC_GROUP *group, BN_CTX *ctx);
+
+/* EC_GROUP_have_precompute_mult returns one if |group| contains precomputed
+ * generator multiples. */
+int EC_GROUP_have_precompute_mult(const EC_GROUP *group);
+
+
+/* Points on elliptic curves. */
+
+/* EC_POINT_new returns a fresh |EC_POINT| object in the given group, or NULL
+ * on error. */
+EC_POINT *EC_POINT_new(const EC_GROUP *group);
+
+/* EC_POINT_free frees |point| and the data that it points to. */
+void EC_POINT_free(EC_POINT *point);
+
+/* EC_POINT_clear_free clears the data that |point| points to, frees it and
+ * then frees |point| itself. */
+void EC_POINT_clear_free(EC_POINT *point);
+
+/* EC_POINT_copy sets |*dest| equal to |*src|. It returns one on success and
+ * zero otherwise. */
+int EC_POINT_copy(EC_POINT *dest, const EC_POINT *src);
+
+/* EC_POINT_dup returns a fresh |EC_POINT| that contains the same values as
+ * |src|, or NULL on error. */
+EC_POINT *EC_POINT_dup(const EC_POINT *src, const EC_GROUP *group);
+
+/* EC_POINT_set_to_infinity sets |point| to be the "point at infinity" for the
+ * given group. */
+int EC_POINT_set_to_infinity(const EC_GROUP *group, EC_POINT *point);
+
+/* EC_POINT_is_at_infinity returns one iff |point| is the point at infinity and
+ * zero otherwise. */
+int EC_POINT_is_at_infinity(const EC_GROUP *group, const EC_POINT *point);
+
+/* EC_POINT_is_on_curve returns one if |point| is an element of |group| and
+ * zero otheriwse. If |ctx| is non-NULL, it may be used. */
+int EC_POINT_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
+ BN_CTX *ctx);
+
+/* EC_POINT_cmp returns zero if |a| is equal to |b|, greater than zero is
+ * non-equal and -1 on error. If |ctx| is not NULL, it may be used. */
+int EC_POINT_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b,
+ BN_CTX *ctx);
+
+/* EC_POINT_make_affine converts |point| to affine form, internally. It returns
+ * one on success and zero otherwise. If |ctx| is not NULL, it may be used. */
+int EC_POINT_make_affine(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx);
+
+/* EC_POINTs_make_affine converts |num| points from |points| to affine form,
+ * internally. It returns one on success and zero otherwise. If |ctx| is not
+ * NULL, it may be used. */
+int EC_POINTs_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[],
+ BN_CTX *ctx);
+
+
+/* Point conversion. */
+
+/* EC_POINT_get_affine_coordinates_GFp sets |x| and |y| to the affine value of
+ * |point| using |ctx|, if it's not NULL. It returns one on success and zero
+ * otherwise. */
+int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group,
+ const EC_POINT *point, BIGNUM *x,
+ BIGNUM *y, BN_CTX *ctx);
+
+/* EC_POINT_set_affine_coordinates sets the value of |p| to be (|x|, |y|). The
+ * |ctx| argument may be used if not NULL. */
+int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *point,
+ const BIGNUM *x, const BIGNUM *y,
+ BN_CTX *ctx);
+
+/* EC_POINT_point2oct serialises |point| into the X9.62 form given by |form|
+ * into, at most, |len| bytes at |buf|. It returns the number of bytes written
+ * or zero on error if |buf| is non-NULL, else the number of bytes needed. The
+ * |ctx| argument may be used if not NULL. */
+size_t EC_POINT_point2oct(const EC_GROUP *group, const EC_POINT *point,
+ point_conversion_form_t form, uint8_t *buf,
+ size_t len, BN_CTX *ctx);
+
+/* EC_POINT_oct2point sets |point| from |len| bytes of X9.62 format
+ * serialisation in |buf|. It returns one on success and zero otherwise. The
+ * |ctx| argument may be used if not NULL. */
+int EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *point,
+ const uint8_t *buf, size_t len, BN_CTX *ctx);
+
+/* EC_POINT_set_compressed_coordinates_GFp sets |point| to equal the point with
+ * the given |x| coordinate and the y coordinate specified by |y_bit| (see
+ * X9.62). It returns one on success and zero otherwise. */
+int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group,
+ EC_POINT *point, const BIGNUM *x,
+ int y_bit, BN_CTX *ctx);
+
+
+/* Group operations. */
+
+/* EC_POINT_add sets |r| equal to |a| plus |b|. It returns one on success and
+ * zero otherwise. If |ctx| is not NULL, it may be used. */
+int EC_POINT_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
+ const EC_POINT *b, BN_CTX *ctx);
+
+/* EC_POINT_dbl sets |r| equal to |a| plus |a|. It returns one on success and
+ * zero otherwise. If |ctx| is not NULL, it may be used. */
+int EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
+ BN_CTX *ctx);
+
+/* EC_POINT_dbl sets |a| equal to minus |a|. It returns one on success and zero
+ * otherwise. If |ctx| is not NULL, it may be used. */
+int EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, BN_CTX *ctx);
+
+/* EC_POINT_mul sets r = generator*n + q*m. It returns one on success and zero
+ * otherwise. If |ctx| is not NULL, it may be used. */
+int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *n,
+ const EC_POINT *q, const BIGNUM *m, BN_CTX *ctx);
+
+/* EC_POINTs_mul sets r = generator*n + sum(p[i]*m[i]). It returns one on
+ * success and zero otherwise. If |ctx| is not NULL, it may be used. */
+int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *n,
+ size_t num, const EC_POINT *p[], const BIGNUM *m[],
+ BN_CTX *ctx);
+
+
+/* Old code expects to get EC_KEY from ec.h. */
+#if !defined(OPENSSL_HEADER_EC_KEY_H)
+#include <openssl/ec_key.h>
+#endif
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#define EC_F_ec_pre_comp_new 100
+#define EC_F_ec_GFp_mont_field_decode 101
+#define EC_F_ec_group_new_from_data 102
+#define EC_F_ec_GFp_simple_point_get_affine_coordinates 103
+#define EC_F_ec_GFp_simple_make_affine 104
+#define EC_F_EC_KEY_new_method 105
+#define EC_F_ec_GFp_mont_field_encode 106
+#define EC_F_EC_GROUP_new_by_curve_name 107
+#define EC_F_ec_group_new 108
+#define EC_F_ec_asn1_group2pkparameters 109
+#define EC_F_EC_POINT_set_compressed_coordinates_GFp 110
+#define EC_F_ec_GFp_mont_field_sqr 111
+#define EC_F_EC_POINT_make_affine 112
+#define EC_F_i2d_ECParameters 113
+#define EC_F_ec_wNAF_mul 114
+#define EC_F_EC_GROUP_copy 115
+#define EC_F_EC_POINT_cmp 116
+#define EC_F_ec_GFp_mont_field_mul 117
+#define EC_F_EC_POINT_dup 118
+#define EC_F_EC_POINT_invert 119
+#define EC_F_ec_GFp_simple_point_set_affine_coordinates 120
+#define EC_F_ec_GFp_simple_points_make_affine 121
+#define EC_F_i2o_ECPublicKey 122
+#define EC_F_EC_KEY_check_key 123
+#define EC_F_ec_wNAF_precompute_mult 124
+#define EC_F_EC_POINT_oct2point 125
+#define EC_F_EC_POINT_is_at_infinity 126
+#define EC_F_EC_POINT_get_affine_coordinates_GFp 127
+#define EC_F_ec_point_set_Jprojective_coordinates_GFp 128
+#define EC_F_o2i_ECPublicKey 129
+#define EC_F_ec_GFp_mont_field_set_to_one 130
+#define EC_F_ec_group_new_curve_GFp 131
+#define EC_F_EC_POINT_dbl 132
+#define EC_F_ec_asn1_pkparameters2group 133
+#define EC_F_i2d_ECPKParameters 134
+#define EC_F_EC_KEY_copy 135
+#define EC_F_EC_POINT_new 136
+#define EC_F_EC_POINT_point2oct 137
+#define EC_F_EC_POINT_copy 138
+#define EC_F_EC_POINT_is_on_curve 139
+#define EC_F_ec_GFp_simple_group_set_curve 140
+#define EC_F_i2d_ECPrivateKey 141
+#define EC_F_d2i_ECParameters 142
+#define EC_F_ec_GFp_mont_group_set_curve 143
+#define EC_F_EC_POINT_set_to_infinity 144
+#define EC_F_EC_POINTs_make_affine 145
+#define EC_F_compute_wNAF 146
+#define EC_F_ec_GFp_simple_point2oct 147
+#define EC_F_EC_GROUP_get_degree 148
+#define EC_F_ec_GFp_simple_group_check_discriminant 149
+#define EC_F_d2i_ECPKParameters 150
+#define EC_F_d2i_ECPrivateKey 151
+#define EC_F_ec_GFp_simple_oct2point 152
+#define EC_F_EC_POINT_set_affine_coordinates_GFp 153
+#define EC_F_EC_KEY_set_public_key_affine_coordinates 154
+#define EC_F_EC_KEY_generate_key 155
+#define EC_F_ec_GFp_simple_set_compressed_coordinates 156
+#define EC_F_EC_POINT_add 157
+#define EC_R_PKPARAMETERS2GROUP_FAILURE 100
+#define EC_R_NON_NAMED_CURVE 101
+#define EC_R_COORDINATES_OUT_OF_RANGE 102
+#define EC_R_POINT_AT_INFINITY 103
+#define EC_R_NOT_INITIALIZED 104
+#define EC_R_MISSING_PRIVATE_KEY 105
+#define EC_R_GROUP2PKPARAMETERS_FAILURE 106
+#define EC_R_INVALID_ENCODING 107
+#define EC_R_BUFFER_TOO_SMALL 108
+#define EC_R_D2I_ECPKPARAMETERS_FAILURE 109
+#define EC_R_INVALID_FORM 110
+#define EC_R_INVALID_PRIVATE_KEY 111
+#define EC_R_INVALID_COMPRESSED_POINT 112
+#define EC_R_MISSING_PARAMETERS 113
+#define EC_R_INVALID_FIELD 114
+#define EC_R_INVALID_COMPRESSION_BIT 115
+#define EC_R_GF2M_NOT_SUPPORTED 116
+#define EC_R_POINT_IS_NOT_ON_CURVE 117
+#define EC_R_UNKNOWN_ORDER 118
+#define EC_R_UNKNOWN_GROUP 119
+#define EC_R_WRONG_ORDER 120
+#define EC_R_UNDEFINED_GENERATOR 121
+#define EC_R_INCOMPATIBLE_OBJECTS 122
+#define EC_R_I2D_ECPKPARAMETERS_FAILURE 123
+#define EC_R_EC_GROUP_NEW_BY_NAME_FAILURE 124
+#define EC_R_INVALID_GROUP_ORDER 125
+#define EC_R_SLOT_FULL 126
+
+#endif /* OPENSSL_HEADER_EC_H */
diff --git a/crypto/ec/ec_asn1.c b/crypto/ec/ec_asn1.c
new file mode 100644
index 0000000..7b4f74f
--- /dev/null
+++ b/crypto/ec/ec_asn1.c
@@ -0,0 +1,556 @@
+/* Written by Nils Larsch for the OpenSSL project. */
+/* ====================================================================
+ * Copyright (c) 2000-2003 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/ec.h>
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/bn.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+
+#include "internal.h"
+
+
+typedef struct x9_62_fieldid_st {
+ ASN1_OBJECT *fieldType;
+ union {
+ char *ptr;
+ /* NID_X9_62_prime_field */
+ ASN1_INTEGER *prime;
+ /* anything else */
+ ASN1_TYPE *other;
+ } p;
+} X9_62_FIELDID;
+
+ASN1_ADB_TEMPLATE(fieldID_def) = ASN1_SIMPLE(X9_62_FIELDID, p.other, ASN1_ANY);
+
+ASN1_ADB(X9_62_FIELDID) = {
+ ADB_ENTRY(NID_X9_62_prime_field, ASN1_SIMPLE(X9_62_FIELDID, p.prime, ASN1_INTEGER)),
+} ASN1_ADB_END(X9_62_FIELDID, 0, fieldType, 0, &fieldID_def_tt, NULL);
+
+ASN1_SEQUENCE(X9_62_FIELDID) = {
+ ASN1_SIMPLE(X9_62_FIELDID, fieldType, ASN1_OBJECT),
+ ASN1_ADB_OBJECT(X9_62_FIELDID)
+} ASN1_SEQUENCE_END(X9_62_FIELDID);
+
+typedef struct x9_62_curve_st {
+ ASN1_OCTET_STRING *a;
+ ASN1_OCTET_STRING *b;
+ ASN1_BIT_STRING *seed;
+} X9_62_CURVE;
+
+ASN1_SEQUENCE(X9_62_CURVE) = {
+ ASN1_SIMPLE(X9_62_CURVE, a, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(X9_62_CURVE, b, ASN1_OCTET_STRING),
+ ASN1_OPT(X9_62_CURVE, seed, ASN1_BIT_STRING)
+} ASN1_SEQUENCE_END(X9_62_CURVE);
+
+typedef struct ec_parameters_st {
+ long version;
+ X9_62_FIELDID *fieldID;
+ X9_62_CURVE *curve;
+ ASN1_OCTET_STRING *base;
+ ASN1_INTEGER *order;
+ ASN1_INTEGER *cofactor;
+} ECPARAMETERS;
+
+ASN1_SEQUENCE(ECPARAMETERS) = {
+ ASN1_SIMPLE(ECPARAMETERS, version, LONG),
+ ASN1_SIMPLE(ECPARAMETERS, fieldID, X9_62_FIELDID),
+ ASN1_SIMPLE(ECPARAMETERS, curve, X9_62_CURVE),
+ ASN1_SIMPLE(ECPARAMETERS, base, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(ECPARAMETERS, order, ASN1_INTEGER),
+ ASN1_OPT(ECPARAMETERS, cofactor, ASN1_INTEGER)
+} ASN1_SEQUENCE_END(ECPARAMETERS);
+
+DECLARE_ASN1_ALLOC_FUNCTIONS(ECPARAMETERS);
+IMPLEMENT_ASN1_ALLOC_FUNCTIONS(ECPARAMETERS);
+
+typedef struct ecpk_parameters_st {
+ int type;
+ union {
+ ASN1_OBJECT *named_curve;
+ ECPARAMETERS *parameters;
+ } value;
+} ECPKPARAMETERS;
+
+/* SEC1 ECPrivateKey */
+typedef struct ec_privatekey_st {
+ long version;
+ ASN1_OCTET_STRING *privateKey;
+ ECPKPARAMETERS *parameters;
+ ASN1_BIT_STRING *publicKey;
+} EC_PRIVATEKEY;
+
+ASN1_CHOICE(ECPKPARAMETERS) = {
+ ASN1_SIMPLE(ECPKPARAMETERS, value.named_curve, ASN1_OBJECT),
+ ASN1_SIMPLE(ECPKPARAMETERS, value.parameters, ECPARAMETERS),
+} ASN1_CHOICE_END(ECPKPARAMETERS);
+
+DECLARE_ASN1_FUNCTIONS_const(ECPKPARAMETERS);
+DECLARE_ASN1_ENCODE_FUNCTIONS_const(ECPKPARAMETERS, ECPKPARAMETERS);
+IMPLEMENT_ASN1_FUNCTIONS_const(ECPKPARAMETERS);
+
+ASN1_SEQUENCE(EC_PRIVATEKEY) = {
+ ASN1_SIMPLE(EC_PRIVATEKEY, version, LONG),
+ ASN1_SIMPLE(EC_PRIVATEKEY, privateKey, ASN1_OCTET_STRING),
+ ASN1_EXP_OPT(EC_PRIVATEKEY, parameters, ECPKPARAMETERS, 0),
+ ASN1_EXP_OPT(EC_PRIVATEKEY, publicKey, ASN1_BIT_STRING, 1),
+} ASN1_SEQUENCE_END(EC_PRIVATEKEY);
+
+DECLARE_ASN1_FUNCTIONS_const(EC_PRIVATEKEY);
+DECLARE_ASN1_ENCODE_FUNCTIONS_const(EC_PRIVATEKEY, EC_PRIVATEKEY);
+IMPLEMENT_ASN1_FUNCTIONS_const(EC_PRIVATEKEY);
+
+
+ECPKPARAMETERS *ec_asn1_group2pkparameters(const EC_GROUP *group,
+ ECPKPARAMETERS *params) {
+ int ok = 0, nid;
+ ECPKPARAMETERS *ret = params;
+
+ if (ret == NULL) {
+ ret = ECPKPARAMETERS_new();
+ if (ret == NULL) {
+ OPENSSL_PUT_ERROR(EC, ec_asn1_group2pkparameters, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ } else {
+ if (ret->value.named_curve) {
+ ASN1_OBJECT_free(ret->value.named_curve);
+ }
+ }
+
+ /* use the ASN.1 OID to describe the the elliptic curve parameters. */
+ nid = EC_GROUP_get_curve_name(group);
+ if (nid) {
+ ret->type = 0;
+ ret->value.named_curve = (ASN1_OBJECT*) OBJ_nid2obj(nid);
+ ok = ret->value.named_curve != NULL;
+ }
+
+ if (!ok) {
+ ECPKPARAMETERS_free(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+EC_GROUP *ec_asn1_pkparameters2group(const ECPKPARAMETERS *params) {
+ EC_GROUP *ret = NULL;
+ int nid = 0;
+
+ if (params == NULL) {
+ OPENSSL_PUT_ERROR(EC, ec_asn1_pkparameters2group, EC_R_MISSING_PARAMETERS);
+ return NULL;
+ }
+
+ if (params->type != 0) {
+ OPENSSL_PUT_ERROR(EC, ec_asn1_pkparameters2group, EC_R_NON_NAMED_CURVE);
+ return NULL;
+ }
+
+ nid = OBJ_obj2nid(params->value.named_curve);
+ 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);
+ return NULL;
+ }
+
+ return ret;
+}
+
+static EC_GROUP *d2i_ECPKParameters(EC_GROUP **groupp, const uint8_t **inp,
+ long len) {
+ EC_GROUP *group = NULL;
+ ECPKPARAMETERS *params = NULL;
+
+ params = d2i_ECPKPARAMETERS(NULL, inp, len);
+ if (params == NULL) {
+ OPENSSL_PUT_ERROR(EC, d2i_ECPKParameters, 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);
+ ECPKPARAMETERS_free(params);
+ return NULL;
+ }
+
+ if (groupp && *groupp) {
+ EC_GROUP_free(*groupp);
+ }
+ if (groupp) {
+ *groupp = group;
+ }
+
+ ECPKPARAMETERS_free(params);
+ return group;
+}
+
+static int i2d_ECPKParameters(const EC_GROUP *group, uint8_t **outp) {
+ int ret = 0;
+ ECPKPARAMETERS *tmp = ec_asn1_group2pkparameters(group, NULL);
+ if (tmp == NULL) {
+ OPENSSL_PUT_ERROR(EC, i2d_ECPKParameters, 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);
+ ECPKPARAMETERS_free(tmp);
+ return 0;
+ }
+ ECPKPARAMETERS_free(tmp);
+ return ret;
+}
+
+EC_KEY *d2i_ECPrivateKey(EC_KEY **a, const uint8_t **in, long len) {
+ int ok = 0;
+ EC_KEY *ret = NULL;
+ EC_PRIVATEKEY *priv_key = NULL;
+
+ priv_key = EC_PRIVATEKEY_new();
+ if (priv_key == NULL) {
+ OPENSSL_PUT_ERROR(EC, d2i_ECPrivateKey, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ priv_key = d2i_EC_PRIVATEKEY(&priv_key, in, len);
+ if (priv_key == NULL) {
+ OPENSSL_PUT_ERROR(EC, d2i_ECPrivateKey, ERR_R_EC_LIB);
+ EC_PRIVATEKEY_free(priv_key);
+ return NULL;
+ }
+
+ if (a == NULL || *a == NULL) {
+ ret = EC_KEY_new();
+ if (ret == NULL) {
+ OPENSSL_PUT_ERROR(EC, d2i_ECPrivateKey, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if (a) {
+ *a = ret;
+ }
+ } else {
+ ret = *a;
+ }
+
+ if (priv_key->parameters) {
+ if (ret->group) {
+ EC_GROUP_free(ret->group);
+ }
+ ret->group = ec_asn1_pkparameters2group(priv_key->parameters);
+ }
+
+ if (ret->group == NULL) {
+ OPENSSL_PUT_ERROR(EC, d2i_ECPrivateKey, ERR_R_EC_LIB);
+ goto err;
+ }
+
+ ret->version = priv_key->version;
+
+ if (priv_key->privateKey) {
+ ret->priv_key =
+ 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);
+ goto err;
+ }
+ } else {
+ OPENSSL_PUT_ERROR(EC, d2i_ECPrivateKey, EC_R_MISSING_PRIVATE_KEY);
+ goto err;
+ }
+
+ /* TODO(fork): loading the public key is silly. Why not calculate it? */
+ if (priv_key->publicKey) {
+ const uint8_t *pub_oct;
+ size_t pub_oct_len;
+
+ if (ret->pub_key) {
+ 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);
+ goto err;
+ }
+ pub_oct = M_ASN1_STRING_data(priv_key->publicKey);
+ pub_oct_len = M_ASN1_STRING_length(priv_key->publicKey);
+ /* 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);
+ goto err;
+ }
+ }
+
+ ok = 1;
+
+err:
+ if (!ok) {
+ if (ret) {
+ EC_KEY_free(ret);
+ }
+ ret = NULL;
+ }
+
+ if (priv_key) {
+ EC_PRIVATEKEY_free(priv_key);
+ }
+
+ return ret;
+}
+
+int i2d_ECPrivateKey(const EC_KEY *key, uint8_t **outp) {
+ int ret = 0, ok = 0;
+ uint8_t *buffer = NULL;
+ size_t buf_len = 0, tmp_len;
+ 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);
+ goto err;
+ }
+
+ priv_key = EC_PRIVATEKEY_new();
+ if (priv_key == NULL) {
+ OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ priv_key->version = key->version;
+
+ buf_len = BN_num_bytes(key->priv_key);
+ buffer = OPENSSL_malloc(buf_len);
+ if (buffer == NULL) {
+ OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!BN_bn2bin(key->priv_key, buffer)) {
+ OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, 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);
+ goto err;
+ }
+
+ /* TODO(fork): replace this flexibility with key sensible default? */
+ 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);
+ goto err;
+ }
+ }
+
+ /* TODO(fork): replace this flexibility with key sensible default? */
+ if (!(key->enc_flag & EC_PKEY_NO_PUBKEY)) {
+ priv_key->publicKey = M_ASN1_BIT_STRING_new();
+ if (priv_key->publicKey == NULL) {
+ OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ tmp_len = EC_POINT_point2oct(key->group, key->pub_key, key->conv_form, NULL,
+ 0, NULL);
+
+ 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);
+ goto err;
+ }
+ buffer = tmp_buffer;
+ buf_len = tmp_len;
+ }
+
+ 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);
+ 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);
+ goto err;
+ }
+ }
+
+ ret = i2d_EC_PRIVATEKEY(priv_key, outp);
+ if (ret == 0) {
+ OPENSSL_PUT_ERROR(EC, i2d_ECPrivateKey, ERR_R_EC_LIB);
+ goto err;
+ }
+ ok = 1;
+
+err:
+ if (buffer) {
+ OPENSSL_free(buffer);
+ }
+ if (priv_key) {
+ EC_PRIVATEKEY_free(priv_key);
+ }
+ return (ok ? ret : 0);
+}
+
+int i2d_ECParameters(const EC_KEY *key, uint8_t **outp) {
+ if (key == NULL) {
+ OPENSSL_PUT_ERROR(EC, i2d_ECParameters, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+ return i2d_ECPKParameters(key->group, outp);
+}
+
+EC_KEY *d2i_ECParameters(EC_KEY **key, const uint8_t **inp, long len) {
+ EC_KEY *ret;
+
+ if (inp == NULL || *inp == NULL) {
+ OPENSSL_PUT_ERROR(EC, d2i_ECParameters, 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);
+ return NULL;
+ }
+ if (key) {
+ *key = ret;
+ }
+ } else {
+ ret = *key;
+ }
+
+ if (!d2i_ECPKParameters(&ret->group, inp, len)) {
+ OPENSSL_PUT_ERROR(EC, d2i_ECParameters, ERR_R_EC_LIB);
+ return NULL;
+ }
+
+ return ret;
+}
+
+EC_KEY *o2i_ECPublicKey(EC_KEY **keyp, const uint8_t **inp, long len) {
+ EC_KEY *ret = NULL;
+
+ if (keyp == NULL || *keyp == NULL || (*keyp)->group == NULL) {
+ OPENSSL_PUT_ERROR(EC, o2i_ECPublicKey, 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);
+ return 0;
+ }
+ if (!EC_POINT_oct2point(ret->group, ret->pub_key, *inp, len, NULL)) {
+ OPENSSL_PUT_ERROR(EC, o2i_ECPublicKey, ERR_R_EC_LIB);
+ return 0;
+ }
+ /* save the point conversion form */
+ ret->conv_form = (point_conversion_form_t)(*inp[0] & ~0x01);
+ *inp += len;
+ return ret;
+}
+
+int i2o_ECPublicKey(const EC_KEY *key, uint8_t **outp) {
+ size_t buf_len = 0;
+ int new_buffer = 0;
+
+ if (key == NULL) {
+ OPENSSL_PUT_ERROR(EC, i2o_ECPublicKey, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+
+ buf_len = EC_POINT_point2oct(key->group, key->pub_key, key->conv_form, NULL,
+ 0, NULL);
+
+ if (outp == NULL || buf_len == 0) {
+ /* out == NULL => just return the length of the octet string */
+ return buf_len;
+ }
+
+ if (*outp == NULL) {
+ *outp = OPENSSL_malloc(buf_len);
+ if (*outp == NULL) {
+ OPENSSL_PUT_ERROR(EC, i2o_ECPublicKey, 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_free(*outp);
+ *outp = NULL;
+ return 0;
+ }
+
+ if (!new_buffer) {
+ *outp += buf_len;
+ }
+ return buf_len;
+}
diff --git a/crypto/ec/ec_error.c b/crypto/ec/ec_error.c
new file mode 100644
index 0000000..195b1af
--- /dev/null
+++ b/crypto/ec/ec_error.c
@@ -0,0 +1,106 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/err.h>
+
+#include "ec.h"
+
+const ERR_STRING_DATA EC_error_string_data[] = {
+ {ERR_PACK(ERR_LIB_EC, EC_F_EC_GROUP_copy, 0), "EC_GROUP_copy"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_EC_GROUP_get_degree, 0), "EC_GROUP_get_degree"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_EC_GROUP_new_by_curve_name, 0), "EC_GROUP_new_by_curve_name"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_EC_KEY_check_key, 0), "EC_KEY_check_key"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_EC_KEY_copy, 0), "EC_KEY_copy"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_EC_KEY_generate_key, 0), "EC_KEY_generate_key"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_EC_KEY_new_method, 0), "EC_KEY_new_method"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_EC_KEY_set_public_key_affine_coordinates, 0), "EC_KEY_set_public_key_affine_coordinates"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_EC_POINT_add, 0), "EC_POINT_add"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_EC_POINT_cmp, 0), "EC_POINT_cmp"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_EC_POINT_copy, 0), "EC_POINT_copy"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_EC_POINT_dbl, 0), "EC_POINT_dbl"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_EC_POINT_dup, 0), "EC_POINT_dup"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_EC_POINT_get_affine_coordinates_GFp, 0), "EC_POINT_get_affine_coordinates_GFp"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_EC_POINT_invert, 0), "EC_POINT_invert"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_EC_POINT_is_at_infinity, 0), "EC_POINT_is_at_infinity"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_EC_POINT_is_on_curve, 0), "EC_POINT_is_on_curve"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_EC_POINT_make_affine, 0), "EC_POINT_make_affine"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_EC_POINT_new, 0), "EC_POINT_new"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_EC_POINT_oct2point, 0), "EC_POINT_oct2point"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_EC_POINT_point2oct, 0), "EC_POINT_point2oct"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_EC_POINT_set_affine_coordinates_GFp, 0), "EC_POINT_set_affine_coordinates_GFp"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_EC_POINT_set_compressed_coordinates_GFp, 0), "EC_POINT_set_compressed_coordinates_GFp"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_EC_POINT_set_to_infinity, 0), "EC_POINT_set_to_infinity"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_EC_POINTs_make_affine, 0), "EC_POINTs_make_affine"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_compute_wNAF, 0), "compute_wNAF"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_d2i_ECPKParameters, 0), "d2i_ECPKParameters"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_d2i_ECParameters, 0), "d2i_ECParameters"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_d2i_ECPrivateKey, 0), "d2i_ECPrivateKey"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_ec_GFp_mont_field_decode, 0), "ec_GFp_mont_field_decode"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_ec_GFp_mont_field_encode, 0), "ec_GFp_mont_field_encode"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_ec_GFp_mont_field_mul, 0), "ec_GFp_mont_field_mul"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_ec_GFp_mont_field_set_to_one, 0), "ec_GFp_mont_field_set_to_one"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_ec_GFp_mont_field_sqr, 0), "ec_GFp_mont_field_sqr"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_ec_GFp_mont_group_set_curve, 0), "ec_GFp_mont_group_set_curve"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_ec_GFp_simple_group_check_discriminant, 0), "ec_GFp_simple_group_check_discriminant"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_ec_GFp_simple_group_set_curve, 0), "ec_GFp_simple_group_set_curve"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_ec_GFp_simple_make_affine, 0), "ec_GFp_simple_make_affine"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_ec_GFp_simple_oct2point, 0), "ec_GFp_simple_oct2point"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_ec_GFp_simple_point2oct, 0), "ec_GFp_simple_point2oct"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_ec_GFp_simple_point_get_affine_coordinates, 0), "ec_GFp_simple_point_get_affine_coordinates"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_ec_GFp_simple_point_set_affine_coordinates, 0), "ec_GFp_simple_point_set_affine_coordinates"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_ec_GFp_simple_points_make_affine, 0), "ec_GFp_simple_points_make_affine"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_ec_GFp_simple_set_compressed_coordinates, 0), "ec_GFp_simple_set_compressed_coordinates"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_ec_asn1_group2pkparameters, 0), "ec_asn1_group2pkparameters"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_ec_asn1_pkparameters2group, 0), "ec_asn1_pkparameters2group"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_ec_group_new, 0), "ec_group_new"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_ec_group_new_curve_GFp, 0), "ec_group_new_curve_GFp"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_ec_group_new_from_data, 0), "ec_group_new_from_data"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_ec_point_set_Jprojective_coordinates_GFp, 0), "ec_point_set_Jprojective_coordinates_GFp"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_ec_pre_comp_new, 0), "ec_pre_comp_new"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_ec_wNAF_mul, 0), "ec_wNAF_mul"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_ec_wNAF_precompute_mult, 0), "ec_wNAF_precompute_mult"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_i2d_ECPKParameters, 0), "i2d_ECPKParameters"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_i2d_ECParameters, 0), "i2d_ECParameters"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_i2d_ECPrivateKey, 0), "i2d_ECPrivateKey"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_i2o_ECPublicKey, 0), "i2o_ECPublicKey"},
+ {ERR_PACK(ERR_LIB_EC, EC_F_o2i_ECPublicKey, 0), "o2i_ECPublicKey"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_BUFFER_TOO_SMALL), "BUFFER_TOO_SMALL"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_COORDINATES_OUT_OF_RANGE), "COORDINATES_OUT_OF_RANGE"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_D2I_ECPKPARAMETERS_FAILURE), "D2I_ECPKPARAMETERS_FAILURE"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_EC_GROUP_NEW_BY_NAME_FAILURE), "EC_GROUP_NEW_BY_NAME_FAILURE"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_GF2M_NOT_SUPPORTED), "GF2M_NOT_SUPPORTED"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_GROUP2PKPARAMETERS_FAILURE), "GROUP2PKPARAMETERS_FAILURE"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_I2D_ECPKPARAMETERS_FAILURE), "I2D_ECPKPARAMETERS_FAILURE"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_INCOMPATIBLE_OBJECTS), "INCOMPATIBLE_OBJECTS"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_COMPRESSED_POINT), "INVALID_COMPRESSED_POINT"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_COMPRESSION_BIT), "INVALID_COMPRESSION_BIT"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_ENCODING), "INVALID_ENCODING"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_FIELD), "INVALID_FIELD"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_FORM), "INVALID_FORM"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_GROUP_ORDER), "INVALID_GROUP_ORDER"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_INVALID_PRIVATE_KEY), "INVALID_PRIVATE_KEY"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_MISSING_PARAMETERS), "MISSING_PARAMETERS"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_MISSING_PRIVATE_KEY), "MISSING_PRIVATE_KEY"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_NON_NAMED_CURVE), "NON_NAMED_CURVE"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_NOT_INITIALIZED), "NOT_INITIALIZED"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_PKPARAMETERS2GROUP_FAILURE), "PKPARAMETERS2GROUP_FAILURE"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_POINT_AT_INFINITY), "POINT_AT_INFINITY"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_POINT_IS_NOT_ON_CURVE), "POINT_IS_NOT_ON_CURVE"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_SLOT_FULL), "SLOT_FULL"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_UNDEFINED_GENERATOR), "UNDEFINED_GENERATOR"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_UNKNOWN_GROUP), "UNKNOWN_GROUP"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_UNKNOWN_ORDER), "UNKNOWN_ORDER"},
+ {ERR_PACK(ERR_LIB_EC, 0, EC_R_WRONG_ORDER), "WRONG_ORDER"},
+ {0, NULL},
+};
diff --git a/crypto/ec/ec_key.c b/crypto/ec/ec_key.c
new file mode 100644
index 0000000..9bef698
--- /dev/null
+++ b/crypto/ec/ec_key.c
@@ -0,0 +1,513 @@
+/* Originally written by Bodo Moeller for the OpenSSL project.
+ * ====================================================================
+ * Copyright (c) 1998-2005 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).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * The elliptic curve binary polynomial software is originally written by
+ * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems
+ * Laboratories. */
+
+#include <openssl/ec_key.h>
+
+#include <openssl/ec.h>
+#include <openssl/engine.h>
+#include <openssl/err.h>
+#include <openssl/ex_data.h>
+#include <openssl/mem.h>
+
+#include "internal.h"
+
+
+EC_KEY *EC_KEY_new(void) { return EC_KEY_new_method(NULL); }
+
+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);
+ return NULL;
+ }
+
+ memset(ret, 0, sizeof(EC_KEY));
+
+ if (engine) {
+ ret->ecdsa_meth = ENGINE_get_ECDSA_method(engine);
+ }
+ if (ret->ecdsa_meth) {
+ METHOD_ref(ret->ecdsa_meth);
+ }
+
+ ret->version = 1;
+ ret->conv_form = POINT_CONVERSION_UNCOMPRESSED;
+ ret->references = 1;
+
+ if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_EC_KEY, ret, &ret->ex_data)) {
+ goto err1;
+ }
+
+ if (ret->ecdsa_meth && ret->ecdsa_meth->init && !ret->ecdsa_meth->init(ret)) {
+ goto err2;
+ }
+
+ return ret;
+
+err2:
+ CRYPTO_free_ex_data(CRYPTO_EX_INDEX_EC_KEY, ret, &ret->ex_data);
+err1:
+ if (ret->ecdsa_meth) {
+ METHOD_unref(ret->ecdsa_meth);
+ }
+ OPENSSL_free(ret);
+ return NULL;
+}
+
+EC_KEY *EC_KEY_new_by_curve_name(int nid) {
+ EC_KEY *ret = EC_KEY_new();
+ if (ret == NULL) {
+ return NULL;
+ }
+ ret->group = EC_GROUP_new_by_curve_name(nid);
+ if (ret->group == NULL) {
+ EC_KEY_free(ret);
+ return NULL;
+ }
+ return ret;
+}
+
+void EC_KEY_free(EC_KEY *r) {
+ if (r == NULL) {
+ return;
+ }
+
+ if (CRYPTO_add(&r->references, -1, CRYPTO_LOCK_EC)) {
+ return;
+ }
+
+ if (r->ecdsa_meth) {
+ if (r->ecdsa_meth->finish) {
+ r->ecdsa_meth->finish(r);
+ }
+ METHOD_unref(r->ecdsa_meth);
+ }
+
+ if (r->group != NULL) {
+ EC_GROUP_free(r->group);
+ }
+ if (r->pub_key != NULL) {
+ EC_POINT_free(r->pub_key);
+ }
+ if (r->priv_key != NULL) {
+ BN_clear_free(r->priv_key);
+ }
+
+ CRYPTO_free_ex_data(CRYPTO_EX_INDEX_EC_KEY, r, &r->ex_data);
+
+ OPENSSL_cleanse((void *)r, sizeof(EC_KEY));
+ OPENSSL_free(r);
+}
+
+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);
+ return NULL;
+ }
+ /* copy the parameters */
+ if (src->group) {
+ /* TODO(fork): duplicating the group seems wasteful. */
+ const EC_METHOD *meth = src->group->meth;
+ /* clear the old group */
+ if (dest->group) {
+ EC_GROUP_free(dest->group);
+ }
+ dest->group = ec_group_new(meth);
+ if (dest->group == NULL) {
+ return NULL;
+ }
+ if (!EC_GROUP_copy(dest->group, src->group)) {
+ return NULL;
+ }
+ }
+
+ /* copy the public key */
+ if (src->pub_key && src->group) {
+ if (dest->pub_key) {
+ EC_POINT_free(dest->pub_key);
+ }
+ dest->pub_key = EC_POINT_new(src->group);
+ if (dest->pub_key == NULL) {
+ return NULL;
+ }
+ if (!EC_POINT_copy(dest->pub_key, src->pub_key)) {
+ return NULL;
+ }
+ }
+
+ /* copy the private key */
+ if (src->priv_key) {
+ if (dest->priv_key == NULL) {
+ dest->priv_key = BN_new();
+ if (dest->priv_key == NULL) {
+ return NULL;
+ }
+ }
+ if (!BN_copy(dest->priv_key, src->priv_key)) {
+ return NULL;
+ }
+ }
+ /* copy method/extra data */
+ CRYPTO_free_ex_data(CRYPTO_EX_INDEX_EC_KEY, dest, &dest->ex_data);
+ if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_EC_KEY, &dest->ex_data,
+ &src->ex_data)) {
+ return NULL;
+ }
+
+ /* copy the rest */
+ dest->enc_flag = src->enc_flag;
+ dest->conv_form = src->conv_form;
+ dest->version = src->version;
+ dest->flags = src->flags;
+
+ return dest;
+}
+
+EC_KEY *EC_KEY_dup(const EC_KEY *ec_key) {
+ EC_KEY *ret = EC_KEY_new();
+ if (ret == NULL) {
+ return NULL;
+ }
+ if (EC_KEY_copy(ret, ec_key) == NULL) {
+ EC_KEY_free(ret);
+ return NULL;
+ }
+ return ret;
+}
+
+int EC_KEY_up_ref(EC_KEY *r) {
+ return CRYPTO_add(&r->references, 1, CRYPTO_LOCK_EC) > 1;
+}
+
+const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key) { return key->group; }
+
+int EC_KEY_set_group(EC_KEY *key, const EC_GROUP *group) {
+ if (key->group != NULL) {
+ EC_GROUP_free(key->group);
+ }
+ /* TODO(fork): duplicating the group seems wasteful but see
+ * |EC_KEY_set_conv_form|. */
+ key->group = EC_GROUP_dup(group);
+ return (key->group == NULL) ? 0 : 1;
+}
+
+const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key) {
+ return key->priv_key;
+}
+
+int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *priv_key) {
+ if (key->priv_key) {
+ BN_clear_free(key->priv_key);
+ }
+ key->priv_key = BN_dup(priv_key);
+ return (key->priv_key == NULL) ? 0 : 1;
+}
+
+const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *key) {
+ return key->pub_key;
+}
+
+int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub_key) {
+ if (key->pub_key != NULL) {
+ EC_POINT_free(key->pub_key);
+ }
+ key->pub_key = EC_POINT_dup(pub_key, key->group);
+ return (key->pub_key == NULL) ? 0 : 1;
+}
+
+unsigned int EC_KEY_get_enc_flags(const EC_KEY *key) { return key->enc_flag; }
+
+void EC_KEY_set_enc_flags(EC_KEY *key, unsigned int flags) {
+ key->enc_flag = flags;
+}
+
+point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *key) {
+ return key->conv_form;
+}
+
+void EC_KEY_set_conv_form(EC_KEY *key, point_conversion_form_t cform) {
+ key->conv_form = cform;
+ if (key->group != NULL) {
+ EC_GROUP_set_point_conversion_form(key->group, cform);
+ }
+}
+
+int EC_KEY_precompute_mult(EC_KEY *key, BN_CTX *ctx) {
+ if (key->group == NULL) {
+ return 0;
+ }
+ return EC_GROUP_precompute_mult(key->group, ctx);
+}
+
+int EC_KEY_check_key(const EC_KEY *eckey) {
+ int ok = 0;
+ BN_CTX *ctx = NULL;
+ const BIGNUM *order = NULL;
+ EC_POINT *point = NULL;
+
+ if (!eckey || !eckey->group || !eckey->pub_key) {
+ OPENSSL_PUT_ERROR(EC, EC_KEY_check_key, 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);
+ goto err;
+ }
+
+ ctx = BN_CTX_new();
+ point = EC_POINT_new(eckey->group);
+
+ if (ctx == NULL ||
+ point == NULL) {
+ goto err;
+ }
+
+ /* 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);
+ goto err;
+ }
+ /* testing whether pub_key * order is the point at infinity */
+ /* TODO(fork): can this be skipped if the cofactor is one or if we're about
+ * 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);
+ 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);
+ goto err;
+ }
+ if (!EC_POINT_is_at_infinity(eckey->group, point)) {
+ OPENSSL_PUT_ERROR(EC, EC_KEY_check_key, EC_R_WRONG_ORDER);
+ goto err;
+ }
+ /* in case the priv_key is present :
+ * check if generator * priv_key == pub_key
+ */
+ if (eckey->priv_key) {
+ if (BN_cmp(eckey->priv_key, order) >= 0) {
+ OPENSSL_PUT_ERROR(EC, EC_KEY_check_key, 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);
+ 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);
+ goto err;
+ }
+ }
+ ok = 1;
+
+err:
+ if (ctx != NULL)
+ BN_CTX_free(ctx);
+ if (point != NULL)
+ EC_POINT_free(point);
+ return ok;
+}
+
+int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, BIGNUM *x,
+ BIGNUM *y) {
+ BN_CTX *ctx = NULL;
+ BIGNUM *tx, *ty;
+ EC_POINT *point = NULL;
+ 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);
+ return 0;
+ }
+ ctx = BN_CTX_new();
+ point = EC_POINT_new(key->group);
+
+ if (ctx == NULL ||
+ point == NULL) {
+ goto err;
+ }
+
+ tx = BN_CTX_get(ctx);
+ ty = BN_CTX_get(ctx);
+
+ if (!EC_POINT_set_affine_coordinates_GFp(key->group, point, x, y, ctx) ||
+ !EC_POINT_get_affine_coordinates_GFp(key->group, point, tx, ty, ctx)) {
+ goto err;
+ }
+
+ /* 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);
+ goto err;
+ }
+
+ if (!EC_KEY_set_public_key(key, point)) {
+ goto err;
+ }
+
+ if (EC_KEY_check_key(key) == 0) {
+ goto err;
+ }
+
+ ok = 1;
+
+err:
+ if (ctx)
+ BN_CTX_free(ctx);
+ if (point)
+ EC_POINT_free(point);
+ return ok;
+}
+
+int EC_KEY_generate_key(EC_KEY *eckey) {
+ int ok = 0;
+ BN_CTX *ctx = NULL;
+ BIGNUM *priv_key = NULL, *order = NULL;
+ EC_POINT *pub_key = NULL;
+
+ if (!eckey || !eckey->group) {
+ OPENSSL_PUT_ERROR(EC, EC_KEY_generate_key, ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+
+ order = BN_new();
+ ctx = BN_CTX_new();
+
+ if (order == NULL ||
+ ctx == NULL) {
+ goto err;
+ }
+
+ if (eckey->priv_key == NULL) {
+ priv_key = BN_new();
+ if (priv_key == NULL) {
+ goto err;
+ }
+ } else {
+ priv_key = eckey->priv_key;
+ }
+
+ if (!EC_GROUP_get_order(eckey->group, order, ctx)) {
+ goto err;
+ }
+
+ do {
+ if (!BN_rand_range(priv_key, order)) {
+ goto err;
+ }
+ } while (BN_is_zero(priv_key));
+
+ if (eckey->pub_key == NULL) {
+ pub_key = EC_POINT_new(eckey->group);
+ if (pub_key == NULL) {
+ goto err;
+ }
+ } else {
+ pub_key = eckey->pub_key;
+ }
+
+ if (!EC_POINT_mul(eckey->group, pub_key, priv_key, NULL, NULL, ctx)) {
+ goto err;
+ }
+
+ eckey->priv_key = priv_key;
+ eckey->pub_key = pub_key;
+
+ ok = 1;
+
+err:
+ if (order)
+ BN_free(order);
+ if (pub_key != NULL && eckey->pub_key == NULL)
+ EC_POINT_free(pub_key);
+ if (priv_key != NULL && eckey->priv_key == NULL)
+ BN_free(priv_key);
+ if (ctx != NULL)
+ BN_CTX_free(ctx);
+ return ok;
+}
+
+int EC_KEY_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+ CRYPTO_EX_dup *dup_func,
+ CRYPTO_EX_free *free_func) {
+ return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_EC_KEY, argl, argp, new_func,
+ dup_func, free_func);
+}
+
+int EC_KEY_set_ex_data(EC_KEY *d, int idx, void *arg) {
+ return CRYPTO_set_ex_data(&d->ex_data, idx, arg);
+}
+
+void *EC_KEY_get_ex_data(const EC_KEY *d, int idx) {
+ return CRYPTO_get_ex_data(&d->ex_data, idx);
+}
diff --git a/crypto/ec/ec_key.h b/crypto/ec/ec_key.h
new file mode 100644
index 0000000..ce4846b
--- /dev/null
+++ b/crypto/ec/ec_key.h
@@ -0,0 +1,260 @@
+/* Originally written by Bodo Moeller for the OpenSSL project.
+ * ====================================================================
+ * Copyright (c) 1998-2005 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).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * The elliptic curve binary polynomial software is originally written by
+ * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems
+ * Laboratories. */
+
+#ifndef OPENSSL_HEADER_EC_KEY_H
+#define OPENSSL_HEADER_EC_KEY_H
+
+#include <openssl/base.h>
+
+#include <openssl/ec.h>
+#include <openssl/engine.h>
+#include <openssl/ex_data.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* ec_key.h conatins functions that handle elliptic-curve points that are
+ * public/private keys. */
+
+
+/* EC key objects. */
+
+/* EC_KEY_new returns a fresh |EC_KEY| object or NULL on error. */
+EC_KEY *EC_KEY_new(void);
+
+/* EC_KEY_new_method acts the same as |EC_KEY_new|, but takes an explicit
+ * |ENGINE|. */
+EC_KEY *EC_KEY_new_method(const ENGINE *engine);
+
+/* EC_KEY_new_by_curve_name returns a fresh EC_KEY for group specified by |nid|
+ * or NULL on error. */
+EC_KEY *EC_KEY_new_by_curve_name(int nid);
+
+/* EC_KEY_free frees all the data owned by |key| and |key| itself. */
+void EC_KEY_free(EC_KEY *key);
+
+/* EC_KEY_copy sets |dst| equal to |src| and returns |dst| or NULL on error. */
+EC_KEY *EC_KEY_copy(EC_KEY *dst, const EC_KEY *src);
+
+/* EC_KEY_dup returns a fresh copy of |src| or NULL on error. */
+EC_KEY *EC_KEY_dup(const EC_KEY *src);
+
+/* EC_KEY_up_ref increases the reference count of |key|. It returns one on
+ * success and zero otherwise. */
+int EC_KEY_up_ref(EC_KEY *key);
+
+/* EC_KEY_get0_group returns a pointer to the |EC_GROUP| object inside |key|. */
+const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key);
+
+/* EC_KEY_set_group sets the |EC_GROUP| object that |key| will use to |group|.
+ * It returns one on success and zero otherwise. */
+int EC_KEY_set_group(EC_KEY *key, const EC_GROUP *group);
+
+/* EC_KEY_get0_private_key returns a pointer to the private key inside |key|. */
+const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key);
+
+/* EC_KEY_set_private_key sets the private key of |key| to |priv|. It returns
+ * one on success and zero otherwise. */
+int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *prv);
+
+/* EC_KEY_get0_public_key returns a pointer to the public key point inside
+ * |key|. */
+const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *key);
+
+/* EC_KEY_set_public_key sets the public key of |key| to |pub|, by copying it.
+ * It returns one on success and zero otherwise. */
+int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub);
+
+#define EC_PKEY_NO_PARAMETERS 0x001
+#define EC_PKEY_NO_PUBKEY 0x002
+
+/* EC_KEY_get_enc_flags returns the encoding flags for |key|, which is a
+ * bitwise-OR of |EC_PKEY_*| values. */
+unsigned EC_KEY_get_enc_flags(const EC_KEY *key);
+
+/* EC_KEY_set_enc_flags sets the encoding flags for |key|, which is a
+ * bitwise-OR of |EC_PKEY_*| values. */
+void EC_KEY_set_enc_flags(EC_KEY *key, unsigned flags);
+
+/* EC_KEY_get_conv_form returns the conversation form that will be used by
+ * |key|. */
+point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *key);
+
+/* EC_KEY_set_conv_form sets the conversion form to be used by |key|. */
+void EC_KEY_set_conv_form(EC_KEY *key, point_conversion_form_t cform);
+
+/* EC_KEY_precompute_mult precomputes multiplies of the generator of the
+ * underlying group in order to speed up operations that calculate generator
+ * multiples. If |ctx| is not NULL, it may be used. It returns one on success
+ * and zero otherwise. */
+int EC_KEY_precompute_mult(EC_KEY *key, BN_CTX *ctx);
+
+/* EC_KEY_check_key performs several checks on |key| (possibly including an
+ * expensive check that the public key is in the primary subgroup). It returns
+ * one if all checks pass and zero otherwise. If it returns zero then detail
+ * about the problem can be found on the error stack. */
+int EC_KEY_check_key(const EC_KEY *key);
+
+/* EC_KEY_set_public_key_affine_coordinates sets the public key in |key| to
+ * (|x|, |y|). It returns one on success and zero otherwise. */
+int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, BIGNUM *x, BIGNUM *y);
+
+
+/* Key generation. */
+
+/* EC_KEY_generate_key generates a random, private key, calculates the
+ * corresponding public key and stores both in |key|. It returns one on success
+ * or zero otherwise. */
+int EC_KEY_generate_key(EC_KEY *key);
+
+
+/* Serialisation. */
+
+/* d2i_ECPrivateKey parses an ASN.1, DER-encoded, private key from |len| bytes
+ * at |*inp|. If |out_key| is not NULL then, on exit, a pointer to the result
+ * is in |*out_key|. If |*out_key| is already non-NULL on entry then the result
+ * is written directly into |*out_key|, otherwise a fresh |EC_KEY| is
+ * allocated. On successful exit, |*inp| is advanced past the DER structure. It
+ * returns the result or NULL on error. */
+EC_KEY *d2i_ECPrivateKey(EC_KEY **out_key, const uint8_t **inp, long len);
+
+/* i2d_ECParameters marshals an EC private key from |key| to an ASN.1, DER
+ * structure. If |outp| is not NULL then the result is written to |*outp| and
+ * |*outp| is advanced just past the output. It returns the number of bytes in
+ * the result, whether written or not, or a negative value on error. */
+int i2d_ECPrivateKey(const EC_KEY *key, uint8_t **outp);
+
+/* d2i_ECParameters parses an ASN.1, DER-encoded, set of EC parameters from
+ * |len| bytes at |*inp|. If |out_key| is not NULL then, on exit, a pointer to
+ * the result is in |*out_key|. If |*out_key| is already non-NULL on entry then
+ * the result is written directly into |*out_key|, otherwise a fresh |EC_KEY|
+ * is allocated. On successful exit, |*inp| is advanced past the DER structure.
+ * It returns the result or NULL on error. */
+EC_KEY *d2i_ECParameters(EC_KEY **out_key, const uint8_t **inp, long len);
+
+/* i2d_ECParameters marshals EC parameters from |key| to an ASN.1, DER
+ * structure. If |outp| is not NULL then the result is written to |*outp| and
+ * |*outp| is advanced just past the output. It returns the number of bytes in
+ * the result, whether written or not, or a negative value on error. */
+int i2d_ECParameters(const EC_KEY *key, uint8_t **outp);
+
+/* o2i_ECPublicKey parses an EC point from |len| bytes at |*inp| into
+ * |*out_key|. Note that this differs from the d2i format in that |*out_key|
+ * must be non-NULL. On successful exit, |*inp| is advanced past the DER
+ * structure. It returns |*out_key| or NULL on error. */
+EC_KEY *o2i_ECPublicKey(EC_KEY **out_key, const uint8_t **inp, long len);
+
+/* i2o_ECPublicKey marshals an EC point from |key|. If |outp| is not NULL then
+ * the result is written to |*outp| and |*outp| is advanced just past the
+ * output. It returns the number of bytes in the result, whether written or
+ * not, or a negative value on error. */
+int i2o_ECPublicKey(const EC_KEY *key, unsigned char **outp);
+
+
+/* ex_data functions.
+ *
+ * These functions are wrappers. See |ex_data.h| for details. */
+
+int EC_KEY_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+ CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+int EC_KEY_set_ex_data(EC_KEY *r, int idx, void *arg);
+void *EC_KEY_get_ex_data(const EC_KEY *r, int idx);
+
+
+/* ECDSA method. */
+
+/* ecdsa_method_st is a structure of function pointers for implementing ECDSA.
+ * See engine.h. */
+struct ecdsa_method_st {
+ struct openssl_method_common_st common;
+
+ void *app_data;
+
+ int (*init)(EC_KEY *key);
+ int (*finish)(EC_KEY *key);
+
+ /* size returns the maximum size of the DER encoded, ECDSA signature
+ * resulting from |key|. */
+ size_t (*size)(const EC_KEY *key);
+
+ /* sign matches the arguments and behaviour of |ECDSA_sign|. */
+ int (*sign)(const uint8_t *digest, size_t digest_len, uint8_t *sig,
+ unsigned int *sig_len, EC_KEY *eckey);
+
+ /* verify matches the arguments and behaviour of |ECDSA_verify|. */
+ int (*verify)(const uint8_t *digest, size_t digest_len, const uint8_t *sig,
+ size_t sig_len, EC_KEY *eckey);
+};
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_EC_KEY_H */
diff --git a/crypto/ec/ec_montgomery.c b/crypto/ec/ec_montgomery.c
new file mode 100644
index 0000000..ab04556
--- /dev/null
+++ b/crypto/ec/ec_montgomery.c
@@ -0,0 +1,296 @@
+/* Originally written by Bodo Moeller and Nils Larsch for the OpenSSL project.
+ * ====================================================================
+ * Copyright (c) 1998-2005 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).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * The elliptic curve binary polynomial software is originally written by
+ * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems
+ * Laboratories. */
+
+#include <openssl/ec.h>
+
+#include <openssl/bn.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+#include "internal.h"
+
+
+const EC_METHOD *EC_GFp_mont_method(void) {
+ static const EC_METHOD ret = {EC_FLAGS_DEFAULT_OCT,
+ ec_GFp_mont_group_init,
+ ec_GFp_mont_group_finish,
+ ec_GFp_mont_group_clear_finish,
+ ec_GFp_mont_group_copy,
+ ec_GFp_mont_group_set_curve,
+ ec_GFp_simple_group_get_curve,
+ ec_GFp_simple_group_get_degree,
+ ec_GFp_simple_group_check_discriminant,
+ ec_GFp_simple_point_init,
+ ec_GFp_simple_point_finish,
+ ec_GFp_simple_point_clear_finish,
+ ec_GFp_simple_point_copy,
+ ec_GFp_simple_point_set_to_infinity,
+ ec_GFp_simple_set_Jprojective_coordinates_GFp,
+ ec_GFp_simple_get_Jprojective_coordinates_GFp,
+ ec_GFp_simple_point_set_affine_coordinates,
+ ec_GFp_simple_point_get_affine_coordinates,
+ 0,
+ 0,
+ 0,
+ ec_GFp_simple_add,
+ ec_GFp_simple_dbl,
+ ec_GFp_simple_invert,
+ ec_GFp_simple_is_at_infinity,
+ ec_GFp_simple_is_on_curve,
+ ec_GFp_simple_cmp,
+ ec_GFp_simple_make_affine,
+ ec_GFp_simple_points_make_affine,
+ 0 /* mul */,
+ 0 /* precompute_mult */,
+ 0 /* have_precompute_mult */,
+ ec_GFp_mont_field_mul,
+ ec_GFp_mont_field_sqr,
+ 0 /* field_div */,
+ ec_GFp_mont_field_encode,
+ ec_GFp_mont_field_decode,
+ ec_GFp_mont_field_set_to_one};
+
+ return &ret;
+}
+
+int ec_GFp_mont_group_init(EC_GROUP *group) {
+ int ok;
+
+ ok = ec_GFp_simple_group_init(group);
+ group->field_data1 = NULL;
+ group->field_data2 = NULL;
+ return ok;
+}
+
+void ec_GFp_mont_group_finish(EC_GROUP *group) {
+ if (group->field_data1 != NULL) {
+ BN_MONT_CTX_free(group->field_data1);
+ group->field_data1 = NULL;
+ }
+ if (group->field_data2 != NULL) {
+ BN_free(group->field_data2);
+ group->field_data2 = NULL;
+ }
+ ec_GFp_simple_group_finish(group);
+}
+
+void ec_GFp_mont_group_clear_finish(EC_GROUP *group) {
+ if (group->field_data1 != NULL) {
+ BN_MONT_CTX_free(group->field_data1);
+ group->field_data1 = NULL;
+ }
+ if (group->field_data2 != NULL) {
+ BN_clear_free(group->field_data2);
+ group->field_data2 = NULL;
+ }
+ ec_GFp_simple_group_clear_finish(group);
+}
+
+int ec_GFp_mont_group_copy(EC_GROUP *dest, const EC_GROUP *src) {
+ if (dest->field_data1 != NULL) {
+ BN_MONT_CTX_free(dest->field_data1);
+ dest->field_data1 = NULL;
+ }
+ if (dest->field_data2 != NULL) {
+ BN_clear_free(dest->field_data2);
+ dest->field_data2 = NULL;
+ }
+
+ if (!ec_GFp_simple_group_copy(dest, src))
+ return 0;
+
+ if (src->field_data1 != NULL) {
+ dest->field_data1 = BN_MONT_CTX_new();
+ if (dest->field_data1 == NULL)
+ return 0;
+ if (!BN_MONT_CTX_copy(dest->field_data1, src->field_data1))
+ goto err;
+ }
+ if (src->field_data2 != NULL) {
+ dest->field_data2 = BN_dup(src->field_data2);
+ if (dest->field_data2 == NULL)
+ goto err;
+ }
+
+ return 1;
+
+err:
+ if (dest->field_data1 != NULL) {
+ BN_MONT_CTX_free(dest->field_data1);
+ dest->field_data1 = NULL;
+ }
+ return 0;
+}
+
+int ec_GFp_mont_group_set_curve(EC_GROUP *group, const BIGNUM *p,
+ const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
+ BN_CTX *new_ctx = NULL;
+ BN_MONT_CTX *mont = NULL;
+ BIGNUM *one = NULL;
+ int ret = 0;
+
+ if (group->field_data1 != NULL) {
+ BN_MONT_CTX_free(group->field_data1);
+ group->field_data1 = NULL;
+ }
+ if (group->field_data2 != NULL) {
+ BN_free(group->field_data2);
+ group->field_data2 = NULL;
+ }
+
+ if (ctx == NULL) {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return 0;
+ }
+
+ mont = BN_MONT_CTX_new();
+ if (mont == NULL)
+ goto err;
+ if (!BN_MONT_CTX_set(mont, p, ctx)) {
+ OPENSSL_PUT_ERROR(EC, ec_GFp_mont_group_set_curve, ERR_R_BN_LIB);
+ goto err;
+ }
+ one = BN_new();
+ if (one == NULL)
+ goto err;
+ if (!BN_to_montgomery(one, BN_value_one(), mont, ctx))
+ goto err;
+
+ group->field_data1 = mont;
+ mont = NULL;
+ group->field_data2 = one;
+ one = NULL;
+
+ ret = ec_GFp_simple_group_set_curve(group, p, a, b, ctx);
+
+ if (!ret) {
+ BN_MONT_CTX_free(group->field_data1);
+ group->field_data1 = NULL;
+ BN_free(group->field_data2);
+ group->field_data2 = NULL;
+ }
+
+err:
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ if (mont != NULL)
+ BN_MONT_CTX_free(mont);
+ return ret;
+}
+
+int ec_GFp_mont_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
+ const BIGNUM *b, BN_CTX *ctx) {
+ if (group->field_data1 == NULL) {
+ OPENSSL_PUT_ERROR(EC, ec_GFp_mont_field_mul, EC_R_NOT_INITIALIZED);
+ return 0;
+ }
+
+ return BN_mod_mul_montgomery(r, a, b, group->field_data1, ctx);
+}
+
+int ec_GFp_mont_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
+ BN_CTX *ctx) {
+ if (group->field_data1 == NULL) {
+ OPENSSL_PUT_ERROR(EC, ec_GFp_mont_field_sqr, EC_R_NOT_INITIALIZED);
+ return 0;
+ }
+
+ return BN_mod_mul_montgomery(r, a, a, group->field_data1, ctx);
+}
+
+int ec_GFp_mont_field_encode(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
+ BN_CTX *ctx) {
+ if (group->field_data1 == NULL) {
+ OPENSSL_PUT_ERROR(EC, ec_GFp_mont_field_encode, EC_R_NOT_INITIALIZED);
+ return 0;
+ }
+
+ return BN_to_montgomery(r, a, (BN_MONT_CTX *)group->field_data1, ctx);
+}
+
+int ec_GFp_mont_field_decode(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
+ BN_CTX *ctx) {
+ if (group->field_data1 == NULL) {
+ OPENSSL_PUT_ERROR(EC, ec_GFp_mont_field_decode, EC_R_NOT_INITIALIZED);
+ return 0;
+ }
+
+ return BN_from_montgomery(r, a, group->field_data1, ctx);
+}
+
+int ec_GFp_mont_field_set_to_one(const EC_GROUP *group, BIGNUM *r,
+ BN_CTX *ctx) {
+ if (group->field_data2 == NULL) {
+ OPENSSL_PUT_ERROR(EC, ec_GFp_mont_field_set_to_one, EC_R_NOT_INITIALIZED);
+ return 0;
+ }
+
+ if (!BN_copy(r, group->field_data2))
+ return 0;
+ return 1;
+}
diff --git a/crypto/ec/example_mul.c b/crypto/ec/example_mul.c
new file mode 100644
index 0000000..1e83d61
--- /dev/null
+++ b/crypto/ec/example_mul.c
@@ -0,0 +1,130 @@
+/* Originally written by Bodo Moeller for the OpenSSL project.
+ * ====================================================================
+ * Copyright (c) 1998-2005 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).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * The elliptic curve binary polynomial software is originally written by
+ * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems
+ * Laboratories. */
+
+#include <stdio.h>
+
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+#include <openssl/obj.h>
+
+
+int example_EC_POINT_mul() {
+ /* This example ensures that 10×∞ + G = G, in P-256. */
+ EC_GROUP *group = NULL;
+ EC_POINT *p = NULL, *result = NULL;
+ BIGNUM *n = NULL;
+ int ret = 0;
+ const EC_POINT *generator;
+
+ group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
+ p = EC_POINT_new(group);
+ result = EC_POINT_new(group);
+ n = BN_new();
+
+ if (p == NULL ||
+ result == NULL ||
+ group == NULL ||
+ n == NULL ||
+ !EC_POINT_set_to_infinity(group, p) ||
+ !BN_set_word(n, 10)) {
+ goto err;
+ }
+
+ /* First check that 10×∞ = ∞. */
+ if (!EC_POINT_mul(group, result, NULL, p, n, NULL) ||
+ !EC_POINT_is_at_infinity(group, result)) {
+ goto err;
+ }
+
+ generator = EC_GROUP_get0_generator(group);
+
+ /* Now check that 10×∞ + G = G. */
+ if (!EC_POINT_mul(group, result, BN_value_one(), p, n, NULL) ||
+ EC_POINT_cmp(group, result, generator, NULL) != 0) {
+ goto err;
+ }
+
+ ret = 1;
+
+err:
+ BN_free(n);
+ EC_POINT_free(result);
+ EC_POINT_free(p);
+ EC_GROUP_free(group);
+
+ return ret;
+}
+
+int main() {
+ if (!example_EC_POINT_mul()) {
+ fprintf(stderr, "failed\n");
+ return 1;
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/crypto/ec/internal.h b/crypto/ec/internal.h
new file mode 100644
index 0000000..dc79186
--- /dev/null
+++ b/crypto/ec/internal.h
@@ -0,0 +1,357 @@
+/* Originally written by Bodo Moeller for the OpenSSL project.
+ * ====================================================================
+ * Copyright (c) 1998-2005 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).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * The elliptic curve binary polynomial software is originally written by
+ * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems
+ * Laboratories. */
+
+#ifndef OPENSSL_HEADER_EC_INTERNAL_H
+#define OPENSSL_HEADER_EC_INTERNAL_H
+
+#include <openssl/base.h>
+
+#include <openssl/bn.h>
+#include <openssl/ex_data.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* Use default functions for poin2oct, oct2point and compressed coordinates */
+#define EC_FLAGS_DEFAULT_OCT 0x1
+
+typedef struct ec_method_st EC_METHOD;
+
+struct ec_method_st {
+ /* Various method flags */
+ int flags;
+
+ /* used by EC_GROUP_new, EC_GROUP_free, EC_GROUP_clear_free, EC_GROUP_copy: */
+ int (*group_init)(EC_GROUP *);
+ void (*group_finish)(EC_GROUP *);
+ void (*group_clear_finish)(EC_GROUP *);
+ int (*group_copy)(EC_GROUP *, const EC_GROUP *);
+
+ /* used by EC_GROUP_set_curve_GFp, EC_GROUP_get_curve_GFp, */
+ /* EC_GROUP_set_curve_GF2m, and EC_GROUP_get_curve_GF2m: */
+ int (*group_set_curve)(EC_GROUP *, const BIGNUM *p, const BIGNUM *a,
+ const BIGNUM *b, BN_CTX *);
+ int (*group_get_curve)(const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b,
+ BN_CTX *);
+
+ /* used by EC_GROUP_get_degree: */
+ int (*group_get_degree)(const EC_GROUP *);
+
+ /* used by EC_GROUP_check: */
+ int (*group_check_discriminant)(const EC_GROUP *, BN_CTX *);
+
+ /* used by EC_POINT_new, EC_POINT_free, EC_POINT_clear_free, EC_POINT_copy: */
+ int (*point_init)(EC_POINT *);
+ void (*point_finish)(EC_POINT *);
+ void (*point_clear_finish)(EC_POINT *);
+ int (*point_copy)(EC_POINT *, const EC_POINT *);
+
+ /* used by EC_POINT_set_to_infinity,
+ * EC_POINT_set_Jprojective_coordinates_GFp,
+ * EC_POINT_get_Jprojective_coordinates_GFp,
+ * EC_POINT_set_affine_coordinates_GFp, ..._GF2m,
+ * EC_POINT_get_affine_coordinates_GFp, ..._GF2m,
+ * EC_POINT_set_compressed_coordinates_GFp, ..._GF2m:
+ */
+ int (*point_set_to_infinity)(const EC_GROUP *, EC_POINT *);
+ int (*point_set_Jprojective_coordinates_GFp)(const EC_GROUP *, EC_POINT *,
+ const BIGNUM *x, const BIGNUM *y,
+ const BIGNUM *z, BN_CTX *);
+ int (*point_get_Jprojective_coordinates_GFp)(const EC_GROUP *,
+ const EC_POINT *, BIGNUM *x,
+ BIGNUM *y, BIGNUM *z, BN_CTX *);
+ int (*point_set_affine_coordinates)(const EC_GROUP *, EC_POINT *,
+ const BIGNUM *x, const BIGNUM *y,
+ BN_CTX *);
+ int (*point_get_affine_coordinates)(const EC_GROUP *, const EC_POINT *,
+ BIGNUM *x, BIGNUM *y, BN_CTX *);
+ int (*point_set_compressed_coordinates)(const EC_GROUP *, EC_POINT *,
+ const BIGNUM *x, int y_bit, BN_CTX *);
+
+ /* used by EC_POINT_point2oct, EC_POINT_oct2point: */
+ size_t (*point2oct)(const EC_GROUP *, const EC_POINT *,
+ point_conversion_form_t form, unsigned char *buf,
+ size_t len, BN_CTX *);
+ int (*oct2point)(const EC_GROUP *, EC_POINT *, const unsigned char *buf,
+ size_t len, BN_CTX *);
+
+ /* used by EC_POINT_add, EC_POINT_dbl, ECP_POINT_invert: */
+ int (*add)(const EC_GROUP *, EC_POINT *r, const EC_POINT *a,
+ const EC_POINT *b, BN_CTX *);
+ int (*dbl)(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, BN_CTX *);
+ int (*invert)(const EC_GROUP *, EC_POINT *, BN_CTX *);
+
+ /* used by EC_POINT_is_at_infinity, EC_POINT_is_on_curve, EC_POINT_cmp: */
+ int (*is_at_infinity)(const EC_GROUP *, const EC_POINT *);
+ int (*is_on_curve)(const EC_GROUP *, const EC_POINT *, BN_CTX *);
+ int (*point_cmp)(const EC_GROUP *, const EC_POINT *a, const EC_POINT *b,
+ BN_CTX *);
+
+ /* used by EC_POINT_make_affine, EC_POINTs_make_affine: */
+ int (*make_affine)(const EC_GROUP *, EC_POINT *, BN_CTX *);
+ int (*points_make_affine)(const EC_GROUP *, size_t num, EC_POINT * [],
+ BN_CTX *);
+
+ /* used by EC_POINTs_mul, EC_POINT_mul, EC_POINT_precompute_mult,
+ * EC_POINT_have_precompute_mult
+ * (default implementations are used if the 'mul' pointer is 0): */
+ int (*mul)(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
+ size_t num, const EC_POINT *points[], const BIGNUM *scalars[],
+ BN_CTX *);
+ int (*precompute_mult)(EC_GROUP *group, BN_CTX *);
+ int (*have_precompute_mult)(const EC_GROUP *group);
+
+
+ /* internal functions */
+
+ /* 'field_mul', 'field_sqr', and 'field_div' can be used by 'add' and 'dbl'
+ * so that the same implementations of point operations can be used with
+ * different optimized implementations of expensive field operations: */
+ int (*field_mul)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
+ const BIGNUM *b, BN_CTX *);
+ int (*field_sqr)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *);
+ int (*field_div)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
+ const BIGNUM *b, BN_CTX *);
+
+ int (*field_encode)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
+ BN_CTX *); /* e.g. to Montgomery */
+ int (*field_decode)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
+ BN_CTX *); /* e.g. from Montgomery */
+ int (*field_set_to_one)(const EC_GROUP *, BIGNUM *r, BN_CTX *);
+} /* EC_METHOD */;
+
+const EC_METHOD* EC_GFp_mont_method();
+
+struct ec_pre_comp_st;
+void ec_pre_comp_free(struct ec_pre_comp_st *pre_comp);
+void *ec_pre_comp_dup(struct ec_pre_comp_st *pre_comp);
+
+struct ec_group_st {
+ const EC_METHOD *meth;
+
+ EC_POINT *generator; /* optional */
+ BIGNUM order, cofactor;
+
+ int curve_name; /* optional NID for named curve */
+ point_conversion_form_t asn1_form;
+
+ struct ec_pre_comp_st *pre_comp;
+
+ /* The following members are handled by the method functions,
+ * even if they appear generic */
+
+ BIGNUM field; /* Field specification.
+ * For curves over GF(p), this is the modulus;
+ * for curves over GF(2^m), this is the
+ * irreducible polynomial defining the field. */
+
+ int poly[6]; /* Field specification for curves over GF(2^m).
+ * The irreducible f(t) is then of the form:
+ * t^poly[0] + t^poly[1] + ... + t^poly[k]
+ * where m = poly[0] > poly[1] > ... > poly[k] = 0.
+ * The array is terminated with poly[k+1]=-1.
+ * All elliptic curve irreducibles have at most 5
+ * non-zero terms. */
+
+ BIGNUM a, b; /* Curve coefficients.
+ * (Here the assumption is that BIGNUMs can be used
+ * or abused for all kinds of fields, not just GF(p).)
+ * For characteristic > 3, the curve is defined
+ * by a Weierstrass equation of the form
+ * y^2 = x^3 + a*x + b.
+ * For characteristic 2, the curve is defined by
+ * an equation of the form
+ * y^2 + x*y = x^3 + a*x^2 + b. */
+
+ int a_is_minus3; /* enable optimized point arithmetics for special case */
+
+ void *field_data1; /* method-specific (e.g., Montgomery structure) */
+ void *field_data2; /* method-specific */
+ int (*field_mod_func)(BIGNUM *, const BIGNUM *, const BIGNUM *,
+ BN_CTX *); /* method-specific */
+} /* EC_GROUP */;
+
+struct ec_point_st {
+ const EC_METHOD *meth;
+
+ /* All members except 'meth' are handled by the method functions,
+ * even if they appear generic */
+
+ BIGNUM X;
+ BIGNUM Y;
+ BIGNUM Z; /* Jacobian projective coordinates:
+ * (X, Y, Z) represents (X/Z^2, Y/Z^3) if Z != 0 */
+ int Z_is_one; /* enable optimized point arithmetics for special case */
+} /* EC_POINT */;
+
+EC_GROUP *ec_group_new(const EC_METHOD *meth);
+
+int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
+ size_t num, const EC_POINT *points[], const BIGNUM *scalars[],
+ BN_CTX *);
+int ec_wNAF_precompute_mult(EC_GROUP *group, BN_CTX *);
+int ec_wNAF_have_precompute_mult(const EC_GROUP *group);
+
+/* method functions in simple.c */
+int ec_GFp_simple_group_init(EC_GROUP *);
+void ec_GFp_simple_group_finish(EC_GROUP *);
+void ec_GFp_simple_group_clear_finish(EC_GROUP *);
+int ec_GFp_simple_group_copy(EC_GROUP *, const EC_GROUP *);
+int ec_GFp_simple_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a,
+ const BIGNUM *b, BN_CTX *);
+int ec_GFp_simple_group_get_curve(const EC_GROUP *, BIGNUM *p, BIGNUM *a,
+ BIGNUM *b, BN_CTX *);
+int ec_GFp_simple_group_get_degree(const EC_GROUP *);
+int ec_GFp_simple_group_check_discriminant(const EC_GROUP *, BN_CTX *);
+int ec_GFp_simple_point_init(EC_POINT *);
+void ec_GFp_simple_point_finish(EC_POINT *);
+void ec_GFp_simple_point_clear_finish(EC_POINT *);
+int ec_GFp_simple_point_copy(EC_POINT *, const EC_POINT *);
+int ec_GFp_simple_point_set_to_infinity(const EC_GROUP *, EC_POINT *);
+int ec_GFp_simple_set_Jprojective_coordinates_GFp(const EC_GROUP *, EC_POINT *,
+ const BIGNUM *x,
+ const BIGNUM *y,
+ const BIGNUM *z, BN_CTX *);
+int ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *,
+ const EC_POINT *, BIGNUM *x,
+ BIGNUM *y, BIGNUM *z,
+ BN_CTX *);
+int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *, EC_POINT *,
+ const BIGNUM *x, const BIGNUM *y,
+ BN_CTX *);
+int ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *,
+ const EC_POINT *, BIGNUM *x,
+ BIGNUM *y, BN_CTX *);
+int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *, EC_POINT *,
+ const BIGNUM *x, int y_bit,
+ BN_CTX *);
+int ec_GFp_simple_add(const EC_GROUP *, EC_POINT *r, const EC_POINT *a,
+ const EC_POINT *b, BN_CTX *);
+int ec_GFp_simple_dbl(const EC_GROUP *, EC_POINT *r, const EC_POINT *a,
+ BN_CTX *);
+int ec_GFp_simple_invert(const EC_GROUP *, EC_POINT *, BN_CTX *);
+int ec_GFp_simple_is_at_infinity(const EC_GROUP *, const EC_POINT *);
+int ec_GFp_simple_is_on_curve(const EC_GROUP *, const EC_POINT *, BN_CTX *);
+int ec_GFp_simple_cmp(const EC_GROUP *, const EC_POINT *a, const EC_POINT *b,
+ BN_CTX *);
+int ec_GFp_simple_make_affine(const EC_GROUP *, EC_POINT *, BN_CTX *);
+int ec_GFp_simple_points_make_affine(const EC_GROUP *, size_t num,
+ EC_POINT * [], BN_CTX *);
+int ec_GFp_simple_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
+ const BIGNUM *b, BN_CTX *);
+int ec_GFp_simple_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
+ BN_CTX *);
+
+/* method functions in montgomery.c */
+int ec_GFp_mont_group_init(EC_GROUP *);
+int ec_GFp_mont_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a,
+ const BIGNUM *b, BN_CTX *);
+void ec_GFp_mont_group_finish(EC_GROUP *);
+void ec_GFp_mont_group_clear_finish(EC_GROUP *);
+int ec_GFp_mont_group_copy(EC_GROUP *, const EC_GROUP *);
+int ec_GFp_mont_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
+ const BIGNUM *b, BN_CTX *);
+int ec_GFp_mont_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
+ BN_CTX *);
+int ec_GFp_mont_field_encode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
+ BN_CTX *);
+int ec_GFp_mont_field_decode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
+ BN_CTX *);
+int ec_GFp_mont_field_set_to_one(const EC_GROUP *, BIGNUM *r, BN_CTX *);
+
+int ec_point_set_Jprojective_coordinates_GFp(const EC_GROUP *group,
+ EC_POINT *point, const BIGNUM *x,
+ const BIGNUM *y, const BIGNUM *z,
+ BN_CTX *ctx);
+
+struct ec_key_st {
+ int version;
+
+ EC_GROUP *group;
+
+ EC_POINT *pub_key;
+ BIGNUM *priv_key;
+
+ unsigned int enc_flag;
+ point_conversion_form_t conv_form;
+
+ int references;
+ int flags;
+
+ ECDSA_METHOD *ecdsa_meth;
+
+ CRYPTO_EX_DATA ex_data;
+} /* EC_KEY */;
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_EC_INTERNAL_H */
diff --git a/crypto/ec/oct.c b/crypto/ec/oct.c
new file mode 100644
index 0000000..1c5ea14
--- /dev/null
+++ b/crypto/ec/oct.c
@@ -0,0 +1,495 @@
+/* Originally written by Bodo Moeller for the OpenSSL project.
+ * ====================================================================
+ * Copyright (c) 1998-2005 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).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * The elliptic curve binary polynomial software is originally written by
+ * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems
+ * Laboratories. */
+
+#include <openssl/ec.h>
+
+#include <openssl/bn.h>
+#include <openssl/err.h>
+
+#include "internal.h"
+
+
+static size_t ec_GFp_simple_point2oct(const EC_GROUP *group,
+ const EC_POINT *point,
+ point_conversion_form_t form,
+ uint8_t *buf, size_t len, BN_CTX *ctx) {
+ size_t ret;
+ BN_CTX *new_ctx = NULL;
+ int used_ctx = 0;
+ BIGNUM *x, *y;
+ size_t field_len, i, skip;
+
+ if ((form != POINT_CONVERSION_COMPRESSED) &&
+ (form != POINT_CONVERSION_UNCOMPRESSED) &&
+ (form != POINT_CONVERSION_HYBRID)) {
+ OPENSSL_PUT_ERROR(EC, ec_GFp_simple_point2oct, EC_R_INVALID_FORM);
+ goto err;
+ }
+
+ if (EC_POINT_is_at_infinity(group, point)) {
+ /* 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);
+ return 0;
+ }
+ buf[0] = 0;
+ }
+ return 1;
+ }
+
+
+ /* ret := required output buffer length */
+ field_len = BN_num_bytes(&group->field);
+ ret =
+ (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2 * field_len;
+
+ /* 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);
+ goto err;
+ }
+
+ if (ctx == NULL) {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return 0;
+ }
+
+ BN_CTX_start(ctx);
+ used_ctx = 1;
+ x = BN_CTX_get(ctx);
+ y = BN_CTX_get(ctx);
+ if (y == NULL)
+ goto err;
+
+ if (!EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx))
+ goto err;
+
+ if ((form == POINT_CONVERSION_COMPRESSED ||
+ form == POINT_CONVERSION_HYBRID) &&
+ BN_is_odd(y))
+ buf[0] = form + 1;
+ else
+ buf[0] = form;
+
+ i = 1;
+
+ skip = field_len - BN_num_bytes(x);
+ if (skip > field_len) {
+ OPENSSL_PUT_ERROR(EC, ec_GFp_simple_point2oct, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ while (skip > 0) {
+ buf[i++] = 0;
+ skip--;
+ }
+ skip = BN_bn2bin(x, buf + i);
+ i += skip;
+ if (i != 1 + field_len) {
+ OPENSSL_PUT_ERROR(EC, ec_GFp_simple_point2oct, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ if (form == POINT_CONVERSION_UNCOMPRESSED ||
+ form == POINT_CONVERSION_HYBRID) {
+ skip = field_len - BN_num_bytes(y);
+ if (skip > field_len) {
+ OPENSSL_PUT_ERROR(EC, ec_GFp_simple_point2oct, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ while (skip > 0) {
+ buf[i++] = 0;
+ skip--;
+ }
+ skip = BN_bn2bin(y, buf + i);
+ i += skip;
+ }
+
+ if (i != ret) {
+ OPENSSL_PUT_ERROR(EC, ec_GFp_simple_point2oct, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ }
+
+ if (used_ctx)
+ BN_CTX_end(ctx);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ return ret;
+
+err:
+ if (used_ctx)
+ BN_CTX_end(ctx);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ return 0;
+}
+
+
+static int ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point,
+ const uint8_t *buf, size_t len,
+ BN_CTX *ctx) {
+ point_conversion_form_t form;
+ int y_bit;
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *x, *y;
+ size_t field_len, enc_len;
+ int ret = 0;
+
+ if (len == 0) {
+ OPENSSL_PUT_ERROR(EC, ec_GFp_simple_oct2point, EC_R_BUFFER_TOO_SMALL);
+ return 0;
+ }
+ form = buf[0];
+ y_bit = form & 1;
+ form = form & ~1U;
+ if ((form != 0) && (form != POINT_CONVERSION_COMPRESSED) &&
+ (form != POINT_CONVERSION_UNCOMPRESSED) &&
+ (form != POINT_CONVERSION_HYBRID)) {
+ OPENSSL_PUT_ERROR(EC, ec_GFp_simple_oct2point, 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);
+ return 0;
+ }
+
+ if (form == 0) {
+ if (len != 1) {
+ OPENSSL_PUT_ERROR(EC, ec_GFp_simple_oct2point, EC_R_INVALID_ENCODING);
+ return 0;
+ }
+
+ return EC_POINT_set_to_infinity(group, point);
+ }
+
+ field_len = BN_num_bytes(&group->field);
+ enc_len =
+ (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);
+ return 0;
+ }
+
+ if (ctx == NULL) {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return 0;
+ }
+
+ BN_CTX_start(ctx);
+ x = BN_CTX_get(ctx);
+ y = BN_CTX_get(ctx);
+ if (y == NULL)
+ goto err;
+
+ if (!BN_bin2bn(buf + 1, field_len, x))
+ goto err;
+ if (BN_ucmp(x, &group->field) >= 0) {
+ OPENSSL_PUT_ERROR(EC, ec_GFp_simple_oct2point, EC_R_INVALID_ENCODING);
+ goto err;
+ }
+
+ if (form == POINT_CONVERSION_COMPRESSED) {
+ if (!EC_POINT_set_compressed_coordinates_GFp(group, point, x, y_bit, ctx))
+ goto err;
+ } else {
+ if (!BN_bin2bn(buf + 1 + field_len, field_len, y))
+ goto err;
+ if (BN_ucmp(y, &group->field) >= 0) {
+ OPENSSL_PUT_ERROR(EC, ec_GFp_simple_oct2point, EC_R_INVALID_ENCODING);
+ goto err;
+ }
+ if (form == POINT_CONVERSION_HYBRID) {
+ if (y_bit != BN_is_odd(y)) {
+ OPENSSL_PUT_ERROR(EC, ec_GFp_simple_oct2point, EC_R_INVALID_ENCODING);
+ goto err;
+ }
+ }
+
+ if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx))
+ goto err;
+ }
+
+ if (!EC_POINT_is_on_curve(group, point, ctx)) /* test required by X9.62 */
+ {
+ OPENSSL_PUT_ERROR(EC, ec_GFp_simple_oct2point, EC_R_POINT_IS_NOT_ON_CURVE);
+ goto err;
+ }
+
+ ret = 1;
+
+err:
+ BN_CTX_end(ctx);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ return ret;
+}
+
+int EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *point,
+ 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);
+ return 0;
+ }
+ if (group->meth != point->meth) {
+ OPENSSL_PUT_ERROR(EC, EC_POINT_oct2point, EC_R_INCOMPATIBLE_OBJECTS);
+ return 0;
+ }
+ if (group->meth->flags & EC_FLAGS_DEFAULT_OCT) {
+ return ec_GFp_simple_oct2point(group, point, buf, len, ctx);
+ }
+
+ return group->meth->oct2point(group, point, buf, len, ctx);
+}
+
+size_t EC_POINT_point2oct(const EC_GROUP *group, const EC_POINT *point,
+ point_conversion_form_t form, uint8_t *buf,
+ 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);
+ return 0;
+ }
+ if (group->meth != point->meth) {
+ OPENSSL_PUT_ERROR(EC, EC_POINT_point2oct, EC_R_INCOMPATIBLE_OBJECTS);
+ return 0;
+ }
+ if (group->meth->flags & EC_FLAGS_DEFAULT_OCT) {
+ return ec_GFp_simple_point2oct(group, point, form, buf, len, ctx);
+ }
+
+ return group->meth->point2oct(group, point, form, buf, len, ctx);
+}
+
+int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group,
+ EC_POINT *point, const BIGNUM *x_,
+ int y_bit, BN_CTX *ctx) {
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *tmp1, *tmp2, *x, *y;
+ int ret = 0;
+
+ ERR_clear_error();
+
+ if (ctx == NULL) {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL) {
+ return 0;
+ }
+ }
+
+ y_bit = (y_bit != 0);
+
+ BN_CTX_start(ctx);
+ tmp1 = BN_CTX_get(ctx);
+ tmp2 = BN_CTX_get(ctx);
+ x = BN_CTX_get(ctx);
+ y = BN_CTX_get(ctx);
+ if (y == NULL) {
+ goto err;
+ }
+
+ /* Recover y. We have a Weierstrass equation
+ * y^2 = x^3 + a*x + b,
+ * so y is one of the square roots of x^3 + a*x + b. */
+
+ /* tmp1 := x^3 */
+ if (!BN_nnmod(x, x_, &group->field, ctx)) {
+ goto err;
+ }
+
+ if (group->meth->field_decode == 0) {
+ /* field_{sqr,mul} work on standard representation */
+ if (!group->meth->field_sqr(group, tmp2, x_, ctx) ||
+ !group->meth->field_mul(group, tmp1, tmp2, x_, ctx)) {
+ goto err;
+ }
+ } else {
+ if (!BN_mod_sqr(tmp2, x_, &group->field, ctx) ||
+ !BN_mod_mul(tmp1, tmp2, x_, &group->field, ctx)) {
+ goto err;
+ }
+ }
+
+ /* tmp1 := tmp1 + a*x */
+ if (group->a_is_minus3) {
+ if (!BN_mod_lshift1_quick(tmp2, x, &group->field) ||
+ !BN_mod_add_quick(tmp2, tmp2, x, &group->field) ||
+ !BN_mod_sub_quick(tmp1, tmp1, tmp2, &group->field)) {
+ goto err;
+ }
+ } else {
+ if (group->meth->field_decode) {
+ if (!group->meth->field_decode(group, tmp2, &group->a, ctx) ||
+ !BN_mod_mul(tmp2, tmp2, x, &group->field, ctx)) {
+ goto err;
+ }
+ } else {
+ /* field_mul works on standard representation */
+ if (!group->meth->field_mul(group, tmp2, &group->a, x, ctx)) {
+ goto err;
+ }
+ }
+
+ if (!BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) {
+ goto err;
+ }
+ }
+
+ /* tmp1 := tmp1 + b */
+ if (group->meth->field_decode) {
+ if (!group->meth->field_decode(group, tmp2, &group->b, ctx) ||
+ !BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) {
+ goto err;
+ }
+ } else {
+ if (!BN_mod_add_quick(tmp1, tmp1, &group->b, &group->field)) {
+ goto err;
+ }
+ }
+
+ if (!BN_mod_sqrt(y, tmp1, &group->field, ctx)) {
+ unsigned long err = ERR_peek_last_error();
+
+ 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);
+ } else {
+ OPENSSL_PUT_ERROR(EC, ec_GFp_simple_set_compressed_coordinates, ERR_R_BN_LIB);
+ }
+ goto err;
+ }
+
+ if (y_bit != BN_is_odd(y)) {
+ if (BN_is_zero(y)) {
+ int kron;
+
+ kron = BN_kronecker(x, &group->field, ctx);
+ if (kron == -2) {
+ goto err;
+ }
+
+ if (kron == 1) {
+ OPENSSL_PUT_ERROR(EC, ec_GFp_simple_set_compressed_coordinates,
+ 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);
+ }
+ goto err;
+ }
+ if (!BN_usub(y, &group->field, y)) {
+ goto err;
+ }
+ }
+ if (y_bit != BN_is_odd(y)) {
+ OPENSSL_PUT_ERROR(EC, ec_GFp_simple_set_compressed_coordinates,
+ ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx))
+ goto err;
+
+ ret = 1;
+
+err:
+ BN_CTX_end(ctx);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ return ret;
+}
+
+int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group,
+ EC_POINT *point, const BIGNUM *x,
+ 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);
+ return 0;
+ }
+ if (group->meth != point->meth) {
+ OPENSSL_PUT_ERROR(EC, EC_POINT_set_compressed_coordinates_GFp,
+ EC_R_INCOMPATIBLE_OBJECTS);
+ return 0;
+ }
+ if (group->meth->flags & EC_FLAGS_DEFAULT_OCT) {
+ return ec_GFp_simple_set_compressed_coordinates(group, point, x, y_bit,
+ ctx);
+ }
+ return group->meth->point_set_compressed_coordinates(group, point, x, y_bit,
+ ctx);
+}
diff --git a/crypto/ec/simple.c b/crypto/ec/simple.c
new file mode 100644
index 0000000..144d056
--- /dev/null
+++ b/crypto/ec/simple.c
@@ -0,0 +1,1371 @@
+/* Originally written by Bodo Moeller for the OpenSSL project.
+ * ====================================================================
+ * Copyright (c) 1998-2005 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).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * The elliptic curve binary polynomial software is originally written by
+ * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems
+ * Laboratories. */
+
+#include <openssl/ec.h>
+
+#include <openssl/bn.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+#include "internal.h"
+
+
+const EC_METHOD *EC_GFp_simple_method(void) {
+ static const EC_METHOD ret = {EC_FLAGS_DEFAULT_OCT,
+ ec_GFp_simple_group_init,
+ ec_GFp_simple_group_finish,
+ ec_GFp_simple_group_clear_finish,
+ ec_GFp_simple_group_copy,
+ ec_GFp_simple_group_set_curve,
+ ec_GFp_simple_group_get_curve,
+ ec_GFp_simple_group_get_degree,
+ ec_GFp_simple_group_check_discriminant,
+ ec_GFp_simple_point_init,
+ ec_GFp_simple_point_finish,
+ ec_GFp_simple_point_clear_finish,
+ ec_GFp_simple_point_copy,
+ ec_GFp_simple_point_set_to_infinity,
+ ec_GFp_simple_set_Jprojective_coordinates_GFp,
+ ec_GFp_simple_get_Jprojective_coordinates_GFp,
+ ec_GFp_simple_point_set_affine_coordinates,
+ ec_GFp_simple_point_get_affine_coordinates,
+ 0,
+ 0,
+ 0,
+ ec_GFp_simple_add,
+ ec_GFp_simple_dbl,
+ ec_GFp_simple_invert,
+ ec_GFp_simple_is_at_infinity,
+ ec_GFp_simple_is_on_curve,
+ ec_GFp_simple_cmp,
+ ec_GFp_simple_make_affine,
+ ec_GFp_simple_points_make_affine,
+ 0 /* mul */,
+ 0 /* precompute_mult */,
+ 0 /* have_precompute_mult */,
+ ec_GFp_simple_field_mul,
+ ec_GFp_simple_field_sqr,
+ 0 /* field_div */,
+ 0 /* field_encode */,
+ 0 /* field_decode */,
+ 0 /* field_set_to_one */};
+
+ return &ret;
+}
+
+
+/* Most method functions in this file are designed to work with non-trivial
+ * representations of field elements if necessary (see ecp_mont.c): while
+ * standard modular addition and subtraction are used, the field_mul and
+ * field_sqr methods will be used for multiplication, and field_encode and
+ * field_decode (if defined) will be used for converting between
+ * representations.
+
+ * Functions ec_GFp_simple_points_make_affine() and
+ * ec_GFp_simple_point_get_affine_coordinates() specifically assume that if a
+ * non-trivial representation is used, it is a Montgomery representation (i.e.
+ * 'encoding' means multiplying by some factor R). */
+
+int ec_GFp_simple_group_init(EC_GROUP *group) {
+ BN_init(&group->field);
+ BN_init(&group->a);
+ BN_init(&group->b);
+ group->a_is_minus3 = 0;
+ return 1;
+}
+
+void ec_GFp_simple_group_finish(EC_GROUP *group) {
+ BN_free(&group->field);
+ BN_free(&group->a);
+ BN_free(&group->b);
+}
+
+void ec_GFp_simple_group_clear_finish(EC_GROUP *group) {
+ BN_clear_free(&group->field);
+ BN_clear_free(&group->a);
+ BN_clear_free(&group->b);
+}
+
+int ec_GFp_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src) {
+ if (!BN_copy(&dest->field, &src->field) ||
+ !BN_copy(&dest->a, &src->a) ||
+ !BN_copy(&dest->b, &src->b)) {
+ return 0;
+ }
+
+ dest->a_is_minus3 = src->a_is_minus3;
+ return 1;
+}
+
+int ec_GFp_simple_group_set_curve(EC_GROUP *group, const BIGNUM *p,
+ const BIGNUM *a, const BIGNUM *b,
+ BN_CTX *ctx) {
+ int ret = 0;
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *tmp_a;
+
+ /* 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);
+ return 0;
+ }
+
+ if (ctx == NULL) {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return 0;
+ }
+
+ BN_CTX_start(ctx);
+ tmp_a = BN_CTX_get(ctx);
+ if (tmp_a == NULL)
+ goto err;
+
+ /* group->field */
+ if (!BN_copy(&group->field, p))
+ goto err;
+ BN_set_negative(&group->field, 0);
+
+ /* group->a */
+ if (!BN_nnmod(tmp_a, a, p, ctx))
+ goto err;
+ if (group->meth->field_encode) {
+ if (!group->meth->field_encode(group, &group->a, tmp_a, ctx))
+ goto err;
+ } else if (!BN_copy(&group->a, tmp_a))
+ goto err;
+
+ /* group->b */
+ if (!BN_nnmod(&group->b, b, p, ctx))
+ goto err;
+ if (group->meth->field_encode)
+ if (!group->meth->field_encode(group, &group->b, &group->b, ctx))
+ goto err;
+
+ /* group->a_is_minus3 */
+ if (!BN_add_word(tmp_a, 3))
+ goto err;
+ group->a_is_minus3 = (0 == BN_cmp(tmp_a, &group->field));
+
+ ret = 1;
+
+err:
+ BN_CTX_end(ctx);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ return ret;
+}
+
+int ec_GFp_simple_group_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a,
+ BIGNUM *b, BN_CTX *ctx) {
+ int ret = 0;
+ BN_CTX *new_ctx = NULL;
+
+ if (p != NULL) {
+ if (!BN_copy(p, &group->field))
+ return 0;
+ }
+
+ if (a != NULL || b != NULL) {
+ if (group->meth->field_decode) {
+ if (ctx == NULL) {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return 0;
+ }
+ if (a != NULL) {
+ if (!group->meth->field_decode(group, a, &group->a, ctx))
+ goto err;
+ }
+ if (b != NULL) {
+ if (!group->meth->field_decode(group, b, &group->b, ctx))
+ goto err;
+ }
+ } else {
+ if (a != NULL) {
+ if (!BN_copy(a, &group->a))
+ goto err;
+ }
+ if (b != NULL) {
+ if (!BN_copy(b, &group->b))
+ goto err;
+ }
+ }
+ }
+
+ ret = 1;
+
+err:
+ if (new_ctx)
+ BN_CTX_free(new_ctx);
+ return ret;
+}
+
+int ec_GFp_simple_group_get_degree(const EC_GROUP *group) {
+ return BN_num_bits(&group->field);
+}
+
+int ec_GFp_simple_group_check_discriminant(const EC_GROUP *group, BN_CTX *ctx) {
+ int ret = 0;
+ BIGNUM *a, *b, *order, *tmp_1, *tmp_2;
+ const BIGNUM *p = &group->field;
+ BN_CTX *new_ctx = NULL;
+
+ 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);
+ goto err;
+ }
+ }
+ BN_CTX_start(ctx);
+ a = BN_CTX_get(ctx);
+ b = BN_CTX_get(ctx);
+ tmp_1 = BN_CTX_get(ctx);
+ tmp_2 = BN_CTX_get(ctx);
+ order = BN_CTX_get(ctx);
+ if (order == NULL)
+ goto err;
+
+ if (group->meth->field_decode) {
+ if (!group->meth->field_decode(group, a, &group->a, ctx))
+ goto err;
+ if (!group->meth->field_decode(group, b, &group->b, ctx))
+ goto err;
+ } else {
+ if (!BN_copy(a, &group->a))
+ goto err;
+ if (!BN_copy(b, &group->b))
+ goto err;
+ }
+
+ /* check the discriminant:
+ * y^2 = x^3 + a*x + b is an elliptic curve <=> 4*a^3 + 27*b^2 != 0 (mod p)
+ * 0 =< a, b < p */
+ if (BN_is_zero(a)) {
+ if (BN_is_zero(b))
+ goto err;
+ } else if (!BN_is_zero(b)) {
+ if (!BN_mod_sqr(tmp_1, a, p, ctx))
+ goto err;
+ if (!BN_mod_mul(tmp_2, tmp_1, a, p, ctx))
+ goto err;
+ if (!BN_lshift(tmp_1, tmp_2, 2))
+ goto err;
+ /* tmp_1 = 4*a^3 */
+
+ if (!BN_mod_sqr(tmp_2, b, p, ctx))
+ goto err;
+ if (!BN_mul_word(tmp_2, 27))
+ goto err;
+ /* tmp_2 = 27*b^2 */
+
+ if (!BN_mod_add(a, tmp_1, tmp_2, p, ctx))
+ goto err;
+ if (BN_is_zero(a))
+ goto err;
+ }
+ ret = 1;
+
+err:
+ if (ctx != NULL)
+ BN_CTX_end(ctx);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ return ret;
+}
+
+int ec_GFp_simple_point_init(EC_POINT *point) {
+ BN_init(&point->X);
+ BN_init(&point->Y);
+ BN_init(&point->Z);
+ point->Z_is_one = 0;
+
+ return 1;
+}
+
+void ec_GFp_simple_point_finish(EC_POINT *point) {
+ BN_free(&point->X);
+ BN_free(&point->Y);
+ BN_free(&point->Z);
+}
+
+void ec_GFp_simple_point_clear_finish(EC_POINT *point) {
+ BN_clear_free(&point->X);
+ BN_clear_free(&point->Y);
+ BN_clear_free(&point->Z);
+ point->Z_is_one = 0;
+}
+
+int ec_GFp_simple_point_copy(EC_POINT *dest, const EC_POINT *src) {
+ if (!BN_copy(&dest->X, &src->X))
+ return 0;
+ if (!BN_copy(&dest->Y, &src->Y))
+ return 0;
+ if (!BN_copy(&dest->Z, &src->Z))
+ return 0;
+ dest->Z_is_one = src->Z_is_one;
+
+ return 1;
+}
+
+int ec_GFp_simple_point_set_to_infinity(const EC_GROUP *group,
+ EC_POINT *point) {
+ point->Z_is_one = 0;
+ BN_zero(&point->Z);
+ return 1;
+}
+
+int ec_GFp_simple_set_Jprojective_coordinates_GFp(
+ const EC_GROUP *group, EC_POINT *point, const BIGNUM *x, const BIGNUM *y,
+ const BIGNUM *z, BN_CTX *ctx) {
+ BN_CTX *new_ctx = NULL;
+ int ret = 0;
+
+ if (ctx == NULL) {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return 0;
+ }
+
+ if (x != NULL) {
+ if (!BN_nnmod(&point->X, x, &group->field, ctx))
+ goto err;
+ if (group->meth->field_encode) {
+ if (!group->meth->field_encode(group, &point->X, &point->X, ctx))
+ goto err;
+ }
+ }
+
+ if (y != NULL) {
+ if (!BN_nnmod(&point->Y, y, &group->field, ctx))
+ goto err;
+ if (group->meth->field_encode) {
+ if (!group->meth->field_encode(group, &point->Y, &point->Y, ctx))
+ goto err;
+ }
+ }
+
+ if (z != NULL) {
+ int Z_is_one;
+
+ if (!BN_nnmod(&point->Z, z, &group->field, ctx))
+ goto err;
+ Z_is_one = BN_is_one(&point->Z);
+ if (group->meth->field_encode) {
+ if (Z_is_one && (group->meth->field_set_to_one != 0)) {
+ if (!group->meth->field_set_to_one(group, &point->Z, ctx))
+ goto err;
+ } else {
+ if (!group->meth->field_encode(group, &point->Z, &point->Z, ctx))
+ goto err;
+ }
+ }
+ point->Z_is_one = Z_is_one;
+ }
+
+ ret = 1;
+
+err:
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ return ret;
+}
+
+int ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *group,
+ const EC_POINT *point,
+ BIGNUM *x, BIGNUM *y,
+ BIGNUM *z, BN_CTX *ctx) {
+ BN_CTX *new_ctx = NULL;
+ int ret = 0;
+
+ if (group->meth->field_decode != 0) {
+ if (ctx == NULL) {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return 0;
+ }
+
+ if (x != NULL) {
+ if (!group->meth->field_decode(group, x, &point->X, ctx))
+ goto err;
+ }
+ if (y != NULL) {
+ if (!group->meth->field_decode(group, y, &point->Y, ctx))
+ goto err;
+ }
+ if (z != NULL) {
+ if (!group->meth->field_decode(group, z, &point->Z, ctx))
+ goto err;
+ }
+ } else {
+ if (x != NULL) {
+ if (!BN_copy(x, &point->X))
+ goto err;
+ }
+ if (y != NULL) {
+ if (!BN_copy(y, &point->Y))
+ goto err;
+ }
+ if (z != NULL) {
+ if (!BN_copy(z, &point->Z))
+ goto err;
+ }
+ }
+
+ ret = 1;
+
+err:
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ return ret;
+}
+
+int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *group,
+ EC_POINT *point, const BIGNUM *x,
+ 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);
+ return 0;
+ }
+
+ return ec_point_set_Jprojective_coordinates_GFp(group, point, x, y,
+ BN_value_one(), ctx);
+}
+
+int ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *group,
+ const EC_POINT *point, BIGNUM *x,
+ BIGNUM *y, BN_CTX *ctx) {
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *Z, *Z_1, *Z_2, *Z_3;
+ const BIGNUM *Z_;
+ 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);
+ return 0;
+ }
+
+ if (ctx == NULL) {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return 0;
+ }
+
+ BN_CTX_start(ctx);
+ Z = BN_CTX_get(ctx);
+ Z_1 = BN_CTX_get(ctx);
+ Z_2 = BN_CTX_get(ctx);
+ Z_3 = BN_CTX_get(ctx);
+ if (Z_3 == NULL)
+ goto err;
+
+ /* transform (X, Y, Z) into (x, y) := (X/Z^2, Y/Z^3) */
+
+ if (group->meth->field_decode) {
+ if (!group->meth->field_decode(group, Z, &point->Z, ctx))
+ goto err;
+ Z_ = Z;
+ } else {
+ Z_ = &point->Z;
+ }
+
+ if (BN_is_one(Z_)) {
+ if (group->meth->field_decode) {
+ if (x != NULL) {
+ if (!group->meth->field_decode(group, x, &point->X, ctx))
+ goto err;
+ }
+ if (y != NULL) {
+ if (!group->meth->field_decode(group, y, &point->Y, ctx))
+ goto err;
+ }
+ } else {
+ if (x != NULL) {
+ if (!BN_copy(x, &point->X))
+ goto err;
+ }
+ if (y != NULL) {
+ if (!BN_copy(y, &point->Y))
+ goto err;
+ }
+ }
+ } 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);
+ goto err;
+ }
+
+ if (group->meth->field_encode == 0) {
+ /* field_sqr works on standard representation */
+ if (!group->meth->field_sqr(group, Z_2, Z_1, ctx))
+ goto err;
+ } else {
+ if (!BN_mod_sqr(Z_2, Z_1, &group->field, ctx))
+ goto err;
+ }
+
+ if (x != NULL) {
+ /* in the Montgomery case, field_mul will cancel out Montgomery factor in
+ * X: */
+ if (!group->meth->field_mul(group, x, &point->X, Z_2, ctx))
+ goto err;
+ }
+
+ if (y != NULL) {
+ if (group->meth->field_encode == 0) {
+ /* field_mul works on standard representation */
+ if (!group->meth->field_mul(group, Z_3, Z_2, Z_1, ctx))
+ goto err;
+ } else {
+ if (!BN_mod_mul(Z_3, Z_2, Z_1, &group->field, ctx))
+ goto err;
+ }
+
+ /* in the Montgomery case, field_mul will cancel out Montgomery factor in
+ * Y: */
+ if (!group->meth->field_mul(group, y, &point->Y, Z_3, ctx))
+ goto err;
+ }
+ }
+
+ ret = 1;
+
+err:
+ BN_CTX_end(ctx);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ return ret;
+}
+
+int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
+ const EC_POINT *b, BN_CTX *ctx) {
+ int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *,
+ BN_CTX *);
+ int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
+ const BIGNUM *p;
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *n0, *n1, *n2, *n3, *n4, *n5, *n6;
+ int ret = 0;
+
+ if (a == b)
+ return EC_POINT_dbl(group, r, a, ctx);
+ if (EC_POINT_is_at_infinity(group, a))
+ return EC_POINT_copy(r, b);
+ if (EC_POINT_is_at_infinity(group, b))
+ return EC_POINT_copy(r, a);
+
+ field_mul = group->meth->field_mul;
+ field_sqr = group->meth->field_sqr;
+ p = &group->field;
+
+ if (ctx == NULL) {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return 0;
+ }
+
+ BN_CTX_start(ctx);
+ n0 = BN_CTX_get(ctx);
+ n1 = BN_CTX_get(ctx);
+ n2 = BN_CTX_get(ctx);
+ n3 = BN_CTX_get(ctx);
+ n4 = BN_CTX_get(ctx);
+ n5 = BN_CTX_get(ctx);
+ n6 = BN_CTX_get(ctx);
+ if (n6 == NULL)
+ goto end;
+
+ /* Note that in this function we must not read components of 'a' or 'b'
+ * once we have written the corresponding components of 'r'.
+ * ('r' might be one of 'a' or 'b'.)
+ */
+
+ /* n1, n2 */
+ if (b->Z_is_one) {
+ if (!BN_copy(n1, &a->X))
+ goto end;
+ if (!BN_copy(n2, &a->Y))
+ goto end;
+ /* n1 = X_a */
+ /* n2 = Y_a */
+ } else {
+ if (!field_sqr(group, n0, &b->Z, ctx))
+ goto end;
+ if (!field_mul(group, n1, &a->X, n0, ctx))
+ goto end;
+ /* n1 = X_a * Z_b^2 */
+
+ if (!field_mul(group, n0, n0, &b->Z, ctx))
+ goto end;
+ if (!field_mul(group, n2, &a->Y, n0, ctx))
+ goto end;
+ /* n2 = Y_a * Z_b^3 */
+ }
+
+ /* n3, n4 */
+ if (a->Z_is_one) {
+ if (!BN_copy(n3, &b->X))
+ goto end;
+ if (!BN_copy(n4, &b->Y))
+ goto end;
+ /* n3 = X_b */
+ /* n4 = Y_b */
+ } else {
+ if (!field_sqr(group, n0, &a->Z, ctx))
+ goto end;
+ if (!field_mul(group, n3, &b->X, n0, ctx))
+ goto end;
+ /* n3 = X_b * Z_a^2 */
+
+ if (!field_mul(group, n0, n0, &a->Z, ctx))
+ goto end;
+ if (!field_mul(group, n4, &b->Y, n0, ctx))
+ goto end;
+ /* n4 = Y_b * Z_a^3 */
+ }
+
+ /* n5, n6 */
+ if (!BN_mod_sub_quick(n5, n1, n3, p))
+ goto end;
+ if (!BN_mod_sub_quick(n6, n2, n4, p))
+ goto end;
+ /* n5 = n1 - n3 */
+ /* n6 = n2 - n4 */
+
+ if (BN_is_zero(n5)) {
+ if (BN_is_zero(n6)) {
+ /* a is the same point as b */
+ BN_CTX_end(ctx);
+ ret = EC_POINT_dbl(group, r, a, ctx);
+ ctx = NULL;
+ goto end;
+ } else {
+ /* a is the inverse of b */
+ BN_zero(&r->Z);
+ r->Z_is_one = 0;
+ ret = 1;
+ goto end;
+ }
+ }
+
+ /* 'n7', 'n8' */
+ if (!BN_mod_add_quick(n1, n1, n3, p))
+ goto end;
+ if (!BN_mod_add_quick(n2, n2, n4, p))
+ goto end;
+ /* 'n7' = n1 + n3 */
+ /* 'n8' = n2 + n4 */
+
+ /* Z_r */
+ if (a->Z_is_one && b->Z_is_one) {
+ if (!BN_copy(&r->Z, n5))
+ goto end;
+ } else {
+ if (a->Z_is_one) {
+ if (!BN_copy(n0, &b->Z))
+ goto end;
+ } else if (b->Z_is_one) {
+ if (!BN_copy(n0, &a->Z))
+ goto end;
+ } else {
+ if (!field_mul(group, n0, &a->Z, &b->Z, ctx))
+ goto end;
+ }
+ if (!field_mul(group, &r->Z, n0, n5, ctx))
+ goto end;
+ }
+ r->Z_is_one = 0;
+ /* Z_r = Z_a * Z_b * n5 */
+
+ /* X_r */
+ if (!field_sqr(group, n0, n6, ctx))
+ goto end;
+ if (!field_sqr(group, n4, n5, ctx))
+ goto end;
+ if (!field_mul(group, n3, n1, n4, ctx))
+ goto end;
+ if (!BN_mod_sub_quick(&r->X, n0, n3, p))
+ goto end;
+ /* X_r = n6^2 - n5^2 * 'n7' */
+
+ /* 'n9' */
+ if (!BN_mod_lshift1_quick(n0, &r->X, p))
+ goto end;
+ if (!BN_mod_sub_quick(n0, n3, n0, p))
+ goto end;
+ /* n9 = n5^2 * 'n7' - 2 * X_r */
+
+ /* Y_r */
+ if (!field_mul(group, n0, n0, n6, ctx))
+ goto end;
+ if (!field_mul(group, n5, n4, n5, ctx))
+ goto end; /* now n5 is n5^3 */
+ if (!field_mul(group, n1, n2, n5, ctx))
+ goto end;
+ if (!BN_mod_sub_quick(n0, n0, n1, p))
+ goto end;
+ if (BN_is_odd(n0))
+ if (!BN_add(n0, n0, p))
+ goto end;
+ /* now 0 <= n0 < 2*p, and n0 is even */
+ if (!BN_rshift1(&r->Y, n0))
+ goto end;
+ /* Y_r = (n6 * 'n9' - 'n8' * 'n5^3') / 2 */
+
+ ret = 1;
+
+end:
+ if (ctx) /* otherwise we already called BN_CTX_end */
+ BN_CTX_end(ctx);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ return ret;
+}
+
+int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
+ BN_CTX *ctx) {
+ int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *,
+ BN_CTX *);
+ int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
+ const BIGNUM *p;
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *n0, *n1, *n2, *n3;
+ int ret = 0;
+
+ if (EC_POINT_is_at_infinity(group, a)) {
+ BN_zero(&r->Z);
+ r->Z_is_one = 0;
+ return 1;
+ }
+
+ field_mul = group->meth->field_mul;
+ field_sqr = group->meth->field_sqr;
+ p = &group->field;
+
+ if (ctx == NULL) {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return 0;
+ }
+
+ BN_CTX_start(ctx);
+ n0 = BN_CTX_get(ctx);
+ n1 = BN_CTX_get(ctx);
+ n2 = BN_CTX_get(ctx);
+ n3 = BN_CTX_get(ctx);
+ if (n3 == NULL)
+ goto err;
+
+ /* Note that in this function we must not read components of 'a'
+ * once we have written the corresponding components of 'r'.
+ * ('r' might the same as 'a'.)
+ */
+
+ /* n1 */
+ if (a->Z_is_one) {
+ if (!field_sqr(group, n0, &a->X, ctx))
+ goto err;
+ if (!BN_mod_lshift1_quick(n1, n0, p))
+ goto err;
+ if (!BN_mod_add_quick(n0, n0, n1, p))
+ goto err;
+ if (!BN_mod_add_quick(n1, n0, &group->a, p))
+ goto err;
+ /* n1 = 3 * X_a^2 + a_curve */
+ } else if (group->a_is_minus3) {
+ if (!field_sqr(group, n1, &a->Z, ctx))
+ goto err;
+ if (!BN_mod_add_quick(n0, &a->X, n1, p))
+ goto err;
+ if (!BN_mod_sub_quick(n2, &a->X, n1, p))
+ goto err;
+ if (!field_mul(group, n1, n0, n2, ctx))
+ goto err;
+ if (!BN_mod_lshift1_quick(n0, n1, p))
+ goto err;
+ if (!BN_mod_add_quick(n1, n0, n1, p))
+ goto err;
+ /* n1 = 3 * (X_a + Z_a^2) * (X_a - Z_a^2)
+ * = 3 * X_a^2 - 3 * Z_a^4 */
+ } else {
+ if (!field_sqr(group, n0, &a->X, ctx))
+ goto err;
+ if (!BN_mod_lshift1_quick(n1, n0, p))
+ goto err;
+ if (!BN_mod_add_quick(n0, n0, n1, p))
+ goto err;
+ if (!field_sqr(group, n1, &a->Z, ctx))
+ goto err;
+ if (!field_sqr(group, n1, n1, ctx))
+ goto err;
+ if (!field_mul(group, n1, n1, &group->a, ctx))
+ goto err;
+ if (!BN_mod_add_quick(n1, n1, n0, p))
+ goto err;
+ /* n1 = 3 * X_a^2 + a_curve * Z_a^4 */
+ }
+
+ /* Z_r */
+ if (a->Z_is_one) {
+ if (!BN_copy(n0, &a->Y))
+ goto err;
+ } else {
+ if (!field_mul(group, n0, &a->Y, &a->Z, ctx))
+ goto err;
+ }
+ if (!BN_mod_lshift1_quick(&r->Z, n0, p))
+ goto err;
+ r->Z_is_one = 0;
+ /* Z_r = 2 * Y_a * Z_a */
+
+ /* n2 */
+ if (!field_sqr(group, n3, &a->Y, ctx))
+ goto err;
+ if (!field_mul(group, n2, &a->X, n3, ctx))
+ goto err;
+ if (!BN_mod_lshift_quick(n2, n2, 2, p))
+ goto err;
+ /* n2 = 4 * X_a * Y_a^2 */
+
+ /* X_r */
+ if (!BN_mod_lshift1_quick(n0, n2, p))
+ goto err;
+ if (!field_sqr(group, &r->X, n1, ctx))
+ goto err;
+ if (!BN_mod_sub_quick(&r->X, &r->X, n0, p))
+ goto err;
+ /* X_r = n1^2 - 2 * n2 */
+
+ /* n3 */
+ if (!field_sqr(group, n0, n3, ctx))
+ goto err;
+ if (!BN_mod_lshift_quick(n3, n0, 3, p))
+ goto err;
+ /* n3 = 8 * Y_a^4 */
+
+ /* Y_r */
+ if (!BN_mod_sub_quick(n0, n2, &r->X, p))
+ goto err;
+ if (!field_mul(group, n0, n1, n0, ctx))
+ goto err;
+ if (!BN_mod_sub_quick(&r->Y, n0, n3, p))
+ goto err;
+ /* Y_r = n1 * (n2 - X_r) - n3 */
+
+ ret = 1;
+
+err:
+ BN_CTX_end(ctx);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ return ret;
+}
+
+int ec_GFp_simple_invert(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) {
+ if (EC_POINT_is_at_infinity(group, point) || BN_is_zero(&point->Y))
+ /* point is its own inverse */
+ return 1;
+
+ return BN_usub(&point->Y, &group->field, &point->Y);
+}
+
+int ec_GFp_simple_is_at_infinity(const EC_GROUP *group, const EC_POINT *point) {
+ return !point->Z_is_one && BN_is_zero(&point->Z);
+}
+
+int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
+ BN_CTX *ctx) {
+ int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *,
+ BN_CTX *);
+ int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
+ const BIGNUM *p;
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *rh, *tmp, *Z4, *Z6;
+ int ret = -1;
+
+ if (EC_POINT_is_at_infinity(group, point))
+ return 1;
+
+ field_mul = group->meth->field_mul;
+ field_sqr = group->meth->field_sqr;
+ p = &group->field;
+
+ if (ctx == NULL) {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return -1;
+ }
+
+ BN_CTX_start(ctx);
+ rh = BN_CTX_get(ctx);
+ tmp = BN_CTX_get(ctx);
+ Z4 = BN_CTX_get(ctx);
+ Z6 = BN_CTX_get(ctx);
+ if (Z6 == NULL)
+ goto err;
+
+ /* We have a curve defined by a Weierstrass equation
+ * y^2 = x^3 + a*x + b.
+ * The point to consider is given in Jacobian projective coordinates
+ * where (X, Y, Z) represents (x, y) = (X/Z^2, Y/Z^3).
+ * Substituting this and multiplying by Z^6 transforms the above equation
+ * into
+ * Y^2 = X^3 + a*X*Z^4 + b*Z^6.
+ * To test this, we add up the right-hand side in 'rh'.
+ */
+
+ /* rh := X^2 */
+ if (!field_sqr(group, rh, &point->X, ctx))
+ goto err;
+
+ if (!point->Z_is_one) {
+ if (!field_sqr(group, tmp, &point->Z, ctx))
+ goto err;
+ if (!field_sqr(group, Z4, tmp, ctx))
+ goto err;
+ if (!field_mul(group, Z6, Z4, tmp, ctx))
+ goto err;
+
+ /* rh := (rh + a*Z^4)*X */
+ if (group->a_is_minus3) {
+ if (!BN_mod_lshift1_quick(tmp, Z4, p))
+ goto err;
+ if (!BN_mod_add_quick(tmp, tmp, Z4, p))
+ goto err;
+ if (!BN_mod_sub_quick(rh, rh, tmp, p))
+ goto err;
+ if (!field_mul(group, rh, rh, &point->X, ctx))
+ goto err;
+ } else {
+ if (!field_mul(group, tmp, Z4, &group->a, ctx))
+ goto err;
+ if (!BN_mod_add_quick(rh, rh, tmp, p))
+ goto err;
+ if (!field_mul(group, rh, rh, &point->X, ctx))
+ goto err;
+ }
+
+ /* rh := rh + b*Z^6 */
+ if (!field_mul(group, tmp, &group->b, Z6, ctx))
+ goto err;
+ if (!BN_mod_add_quick(rh, rh, tmp, p))
+ goto err;
+ } else {
+ /* point->Z_is_one */
+
+ /* rh := (rh + a)*X */
+ if (!BN_mod_add_quick(rh, rh, &group->a, p))
+ goto err;
+ if (!field_mul(group, rh, rh, &point->X, ctx))
+ goto err;
+ /* rh := rh + b */
+ if (!BN_mod_add_quick(rh, rh, &group->b, p))
+ goto err;
+ }
+
+ /* 'lh' := Y^2 */
+ if (!field_sqr(group, tmp, &point->Y, ctx))
+ goto err;
+
+ ret = (0 == BN_ucmp(tmp, rh));
+
+err:
+ BN_CTX_end(ctx);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ return ret;
+}
+
+int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a,
+ const EC_POINT *b, BN_CTX *ctx) {
+ /* return values:
+ * -1 error
+ * 0 equal (in affine coordinates)
+ * 1 not equal
+ */
+
+ int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *,
+ BN_CTX *);
+ int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *tmp1, *tmp2, *Za23, *Zb23;
+ const BIGNUM *tmp1_, *tmp2_;
+ int ret = -1;
+
+ if (EC_POINT_is_at_infinity(group, a)) {
+ return EC_POINT_is_at_infinity(group, b) ? 0 : 1;
+ }
+
+ if (EC_POINT_is_at_infinity(group, b))
+ return 1;
+
+ if (a->Z_is_one && b->Z_is_one) {
+ return ((BN_cmp(&a->X, &b->X) == 0) && BN_cmp(&a->Y, &b->Y) == 0) ? 0 : 1;
+ }
+
+ field_mul = group->meth->field_mul;
+ field_sqr = group->meth->field_sqr;
+
+ if (ctx == NULL) {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return -1;
+ }
+
+ BN_CTX_start(ctx);
+ tmp1 = BN_CTX_get(ctx);
+ tmp2 = BN_CTX_get(ctx);
+ Za23 = BN_CTX_get(ctx);
+ Zb23 = BN_CTX_get(ctx);
+ if (Zb23 == NULL)
+ goto end;
+
+ /* We have to decide whether
+ * (X_a/Z_a^2, Y_a/Z_a^3) = (X_b/Z_b^2, Y_b/Z_b^3),
+ * or equivalently, whether
+ * (X_a*Z_b^2, Y_a*Z_b^3) = (X_b*Z_a^2, Y_b*Z_a^3).
+ */
+
+ if (!b->Z_is_one) {
+ if (!field_sqr(group, Zb23, &b->Z, ctx))
+ goto end;
+ if (!field_mul(group, tmp1, &a->X, Zb23, ctx))
+ goto end;
+ tmp1_ = tmp1;
+ } else
+ tmp1_ = &a->X;
+ if (!a->Z_is_one) {
+ if (!field_sqr(group, Za23, &a->Z, ctx))
+ goto end;
+ if (!field_mul(group, tmp2, &b->X, Za23, ctx))
+ goto end;
+ tmp2_ = tmp2;
+ } else
+ tmp2_ = &b->X;
+
+ /* compare X_a*Z_b^2 with X_b*Z_a^2 */
+ if (BN_cmp(tmp1_, tmp2_) != 0) {
+ ret = 1; /* points differ */
+ goto end;
+ }
+
+
+ if (!b->Z_is_one) {
+ if (!field_mul(group, Zb23, Zb23, &b->Z, ctx))
+ goto end;
+ if (!field_mul(group, tmp1, &a->Y, Zb23, ctx))
+ goto end;
+ /* tmp1_ = tmp1 */
+ } else
+ tmp1_ = &a->Y;
+ if (!a->Z_is_one) {
+ if (!field_mul(group, Za23, Za23, &a->Z, ctx))
+ goto end;
+ if (!field_mul(group, tmp2, &b->Y, Za23, ctx))
+ goto end;
+ /* tmp2_ = tmp2 */
+ } else
+ tmp2_ = &b->Y;
+
+ /* compare Y_a*Z_b^3 with Y_b*Z_a^3 */
+ if (BN_cmp(tmp1_, tmp2_) != 0) {
+ ret = 1; /* points differ */
+ goto end;
+ }
+
+ /* points are equal */
+ ret = 0;
+
+end:
+ BN_CTX_end(ctx);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ return ret;
+}
+
+int ec_GFp_simple_make_affine(const EC_GROUP *group, EC_POINT *point,
+ BN_CTX *ctx) {
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *x, *y;
+ int ret = 0;
+
+ if (point->Z_is_one || EC_POINT_is_at_infinity(group, point))
+ return 1;
+
+ if (ctx == NULL) {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return 0;
+ }
+
+ BN_CTX_start(ctx);
+ x = BN_CTX_get(ctx);
+ y = BN_CTX_get(ctx);
+ if (y == NULL)
+ goto err;
+
+ if (!EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx))
+ goto err;
+ if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx))
+ goto err;
+ if (!point->Z_is_one) {
+ OPENSSL_PUT_ERROR(EC, ec_GFp_simple_make_affine, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ ret = 1;
+
+err:
+ BN_CTX_end(ctx);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ return ret;
+}
+
+int ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num,
+ EC_POINT *points[], BN_CTX *ctx) {
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *tmp0, *tmp1;
+ size_t pow2 = 0;
+ BIGNUM **heap = NULL;
+ size_t i;
+ int ret = 0;
+
+ if (num == 0)
+ return 1;
+
+ if (ctx == NULL) {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ return 0;
+ }
+
+ BN_CTX_start(ctx);
+ tmp0 = BN_CTX_get(ctx);
+ tmp1 = BN_CTX_get(ctx);
+ if (tmp0 == NULL || tmp1 == NULL)
+ goto err;
+
+ /* Before converting the individual points, compute inverses of all Z values.
+ * Modular inversion is rather slow, but luckily we can do with a single
+ * explicit inversion, plus about 3 multiplications per input value.
+ */
+
+ pow2 = 1;
+ while (num > pow2)
+ pow2 <<= 1;
+ /* Now pow2 is the smallest power of 2 satifsying pow2 >= num.
+ * We need twice that. */
+ pow2 <<= 1;
+
+ heap = OPENSSL_malloc(pow2 * sizeof heap[0]);
+ if (heap == NULL)
+ goto err;
+
+ /* The array is used as a binary tree, exactly as in heapsort:
+ *
+ * heap[1]
+ * heap[2] heap[3]
+ * heap[4] heap[5] heap[6] heap[7]
+ * heap[8]heap[9] heap[10]heap[11] heap[12]heap[13] heap[14] heap[15]
+ *
+ * We put the Z's in the last line;
+ * then we set each other node to the product of its two child-nodes (where
+ * empty or 0 entries are treated as ones);
+ * then we invert heap[1];
+ * then we invert each other node by replacing it by the product of its
+ * parent (after inversion) and its sibling (before inversion).
+ */
+ heap[0] = NULL;
+ for (i = pow2 / 2 - 1; i > 0; i--)
+ heap[i] = NULL;
+ for (i = 0; i < num; i++)
+ heap[pow2 / 2 + i] = &points[i]->Z;
+ for (i = pow2 / 2 + num; i < pow2; i++)
+ heap[i] = NULL;
+
+ /* set each node to the product of its children */
+ for (i = pow2 / 2 - 1; i > 0; i--) {
+ heap[i] = BN_new();
+ if (heap[i] == NULL)
+ goto err;
+
+ if (heap[2 * i] != NULL) {
+ if ((heap[2 * i + 1] == NULL) || BN_is_zero(heap[2 * i + 1])) {
+ if (!BN_copy(heap[i], heap[2 * i]))
+ goto err;
+ } else {
+ if (BN_is_zero(heap[2 * i])) {
+ if (!BN_copy(heap[i], heap[2 * i + 1]))
+ goto err;
+ } else {
+ if (!group->meth->field_mul(group, heap[i], heap[2 * i],
+ heap[2 * i + 1], ctx))
+ goto err;
+ }
+ }
+ }
+ }
+
+ /* invert heap[1] */
+ if (!BN_is_zero(heap[1])) {
+ if (!BN_mod_inverse(heap[1], heap[1], &group->field, ctx)) {
+ OPENSSL_PUT_ERROR(EC, ec_GFp_simple_points_make_affine, ERR_R_BN_LIB);
+ goto err;
+ }
+ }
+ if (group->meth->field_encode != 0) {
+ /* in the Montgomery case, we just turned R*H (representing H)
+ * into 1/(R*H), but we need R*(1/H) (representing 1/H);
+ * i.e. we have need to multiply by the Montgomery factor twice */
+ if (!group->meth->field_encode(group, heap[1], heap[1], ctx)) {
+ goto err;
+ }
+ if (!group->meth->field_encode(group, heap[1], heap[1], ctx)) {
+ goto err;
+ }
+ }
+
+ /* set other heap[i]'s to their inverses */
+ for (i = 2; i < pow2 / 2 + num; i += 2) {
+ /* i is even */
+ if ((heap[i + 1] != NULL) && !BN_is_zero(heap[i + 1])) {
+ if (!group->meth->field_mul(group, tmp0, heap[i / 2], heap[i + 1], ctx))
+ goto err;
+ if (!group->meth->field_mul(group, tmp1, heap[i / 2], heap[i], ctx))
+ goto err;
+ if (!BN_copy(heap[i], tmp0))
+ goto err;
+ if (!BN_copy(heap[i + 1], tmp1))
+ goto err;
+ } else {
+ if (!BN_copy(heap[i], heap[i / 2]))
+ goto err;
+ }
+ }
+
+ /* we have replaced all non-zero Z's by their inverses, now fix up all the
+ * points */
+ for (i = 0; i < num; i++) {
+ EC_POINT *p = points[i];
+
+ if (!BN_is_zero(&p->Z)) {
+ /* turn (X, Y, 1/Z) into (X/Z^2, Y/Z^3, 1) */
+
+ if (!group->meth->field_sqr(group, tmp1, &p->Z, ctx))
+ goto err;
+ if (!group->meth->field_mul(group, &p->X, &p->X, tmp1, ctx))
+ goto err;
+
+ if (!group->meth->field_mul(group, tmp1, tmp1, &p->Z, ctx))
+ goto err;
+ if (!group->meth->field_mul(group, &p->Y, &p->Y, tmp1, ctx))
+ goto err;
+
+ if (group->meth->field_set_to_one != 0) {
+ if (!group->meth->field_set_to_one(group, &p->Z, ctx))
+ goto err;
+ } else {
+ if (!BN_one(&p->Z))
+ goto err;
+ }
+ p->Z_is_one = 1;
+ }
+ }
+
+ ret = 1;
+
+err:
+ BN_CTX_end(ctx);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ if (heap != NULL) {
+ /* heap[pow2/2] .. heap[pow2-1] have not been allocated locally! */
+ for (i = pow2 / 2 - 1; i > 0; i--) {
+ if (heap[i] != NULL)
+ BN_clear_free(heap[i]);
+ }
+ OPENSSL_free(heap);
+ }
+ return ret;
+}
+
+int ec_GFp_simple_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
+ const BIGNUM *b, BN_CTX *ctx) {
+ return BN_mod_mul(r, a, b, &group->field, ctx);
+}
+
+int ec_GFp_simple_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
+ BN_CTX *ctx) {
+ return BN_mod_sqr(r, a, &group->field, ctx);
+}
diff --git a/crypto/ec/wnaf.c b/crypto/ec/wnaf.c
new file mode 100644
index 0000000..b86107d
--- /dev/null
+++ b/crypto/ec/wnaf.c
@@ -0,0 +1,841 @@
+/* Originally written by Bodo Moeller for the OpenSSL project.
+ * ====================================================================
+ * Copyright (c) 1998-2005 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).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * The elliptic curve binary polynomial software is originally written by
+ * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems
+ * Laboratories. */
+
+#include <openssl/ec.h>
+
+#include <openssl/bn.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+#include "internal.h"
+
+
+/* This file implements the wNAF-based interleaving multi-exponentation method
+ * (<URL:http://www.informatik.tu-darmstadt.de/TI/Mitarbeiter/moeller.html#multiexp>);
+ * for multiplication with precomputation, we use wNAF splitting
+ * (<URL:http://www.informatik.tu-darmstadt.de/TI/Mitarbeiter/moeller.html#fastexp>).
+ * */
+
+/* structure for precomputed multiples of the generator */
+typedef struct ec_pre_comp_st {
+ const EC_GROUP *group; /* parent EC_GROUP object */
+ size_t blocksize; /* block size for wNAF splitting */
+ size_t numblocks; /* max. number of blocks for which we have precomputation */
+ size_t w; /* window size */
+ EC_POINT **points; /* array with pre-calculated multiples of generator:
+ * 'num' pointers to EC_POINT objects followed by a NULL */
+ size_t num; /* numblocks * 2^(w-1) */
+ int references;
+} EC_PRE_COMP;
+
+static EC_PRE_COMP *ec_pre_comp_new(const EC_GROUP *group) {
+ EC_PRE_COMP *ret = NULL;
+
+ if (!group)
+ return NULL;
+
+ ret = (EC_PRE_COMP *)OPENSSL_malloc(sizeof(EC_PRE_COMP));
+ if (!ret) {
+ OPENSSL_PUT_ERROR(EC, ec_pre_comp_new, ERR_R_MALLOC_FAILURE);
+ return ret;
+ }
+ ret->group = group;
+ ret->blocksize = 8; /* default */
+ ret->numblocks = 0;
+ ret->w = 4; /* default */
+ ret->points = NULL;
+ ret->num = 0;
+ ret->references = 1;
+ return ret;
+}
+
+void *ec_pre_comp_dup(EC_PRE_COMP *pre_comp) {
+ if (pre_comp == NULL) {
+ return NULL;
+ }
+
+ CRYPTO_add(&pre_comp->references, 1, CRYPTO_LOCK_EC_PRE_COMP);
+ return pre_comp;
+}
+
+void ec_pre_comp_free(EC_PRE_COMP *pre_comp) {
+ int i;
+
+ if (!pre_comp) {
+ return;
+ }
+
+ i = CRYPTO_add(&pre_comp->references, -1, CRYPTO_LOCK_EC_PRE_COMP);
+ if (i > 0) {
+ return;
+ }
+
+ if (pre_comp->points) {
+ EC_POINT **p;
+
+ for (p = pre_comp->points; *p != NULL; p++) {
+ EC_POINT_free(*p);
+ }
+ OPENSSL_free(pre_comp->points);
+ }
+ OPENSSL_free(pre_comp);
+}
+
+
+/* Determine the modified width-(w+1) Non-Adjacent Form (wNAF) of 'scalar'.
+ * This is an array r[] of values that are either zero or odd with an
+ * absolute value less than 2^w satisfying
+ * scalar = \sum_j r[j]*2^j
+ * where at most one of any w+1 consecutive digits is non-zero
+ * with the exception that the most significant digit may be only
+ * w-1 zeros away from that next non-zero digit.
+ */
+static signed char *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len) {
+ int window_val;
+ int ok = 0;
+ signed char *r = NULL;
+ int sign = 1;
+ int bit, next_bit, mask;
+ size_t len = 0, j;
+
+ if (BN_is_zero(scalar)) {
+ r = OPENSSL_malloc(1);
+ if (!r) {
+ OPENSSL_PUT_ERROR(EC, compute_wNAF, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ r[0] = 0;
+ *ret_len = 1;
+ return r;
+ }
+
+ 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);
+ goto err;
+ }
+ bit = 1 << w; /* at most 128 */
+ next_bit = bit << 1; /* at most 256 */
+ mask = next_bit - 1; /* at most 255 */
+
+ if (BN_is_negative(scalar)) {
+ sign = -1;
+ }
+
+ if (scalar->d == NULL || scalar->top == 0) {
+ OPENSSL_PUT_ERROR(EC, compute_wNAF, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ len = BN_num_bits(scalar);
+ r = OPENSSL_malloc(
+ len +
+ 1); /* modified wNAF may be one digit longer than binary representation
+ * (*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);
+ goto err;
+ }
+ window_val = scalar->d[0] & mask;
+ j = 0;
+ while ((window_val != 0) ||
+ (j + w + 1 < len)) /* if j+w+1 >= len, window_val will not increase */
+ {
+ int digit = 0;
+
+ /* 0 <= window_val <= 2^(w+1) */
+
+ if (window_val & 1) {
+ /* 0 < window_val < 2^(w+1) */
+
+ if (window_val & bit) {
+ digit = window_val - next_bit; /* -2^w < digit < 0 */
+
+#if 1 /* modified wNAF */
+ if (j + w + 1 >= len) {
+ /* special case for generating modified wNAFs:
+ * no new bits will be added into window_val,
+ * so using a positive digit here will decrease
+ * the total length of the representation */
+
+ digit = window_val & (mask >> 1); /* 0 < digit < 2^w */
+ }
+#endif
+ } else {
+ digit = window_val; /* 0 < digit < 2^w */
+ }
+
+ if (digit <= -bit || digit >= bit || !(digit & 1)) {
+ OPENSSL_PUT_ERROR(EC, compute_wNAF, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ window_val -= digit;
+
+ /* now window_val is 0 or 2^(w+1) in standard wNAF generation;
+ * 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);
+ goto err;
+ }
+ }
+
+ r[j++] = sign * digit;
+
+ window_val >>= 1;
+ 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);
+ goto err;
+ }
+ }
+
+ if (j > len + 1) {
+ OPENSSL_PUT_ERROR(EC, compute_wNAF, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ len = j;
+ ok = 1;
+
+err:
+ if (!ok) {
+ OPENSSL_free(r);
+ r = NULL;
+ }
+ if (ok)
+ *ret_len = len;
+ return r;
+}
+
+
+/* TODO: table should be optimised for the wNAF-based implementation,
+ * sometimes smaller windows will give better performance
+ * (thus the boundaries should be increased)
+ */
+#define EC_window_bits_for_scalar_size(b) \
+ ((size_t)((b) >= 2000 ? 6 : (b) >= 800 ? 5 : (b) >= 300 \
+ ? 4 \
+ : (b) >= 70 ? 3 : (b) >= 20 \
+ ? 2 \
+ : 1))
+
+/* Compute
+ * \sum scalars[i]*points[i],
+ * also including
+ * scalar*generator
+ * in the addition if scalar != NULL
+ */
+int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
+ size_t num, const EC_POINT *points[], const BIGNUM *scalars[],
+ BN_CTX *ctx) {
+ BN_CTX *new_ctx = NULL;
+ const EC_POINT *generator = NULL;
+ EC_POINT *tmp = NULL;
+ size_t totalnum;
+ size_t blocksize = 0, numblocks = 0; /* for wNAF splitting */
+ size_t pre_points_per_block = 0;
+ size_t i, j;
+ int k;
+ int r_is_inverted = 0;
+ int r_is_at_infinity = 1;
+ size_t *wsize = NULL; /* individual window sizes */
+ signed char **wNAF = NULL; /* individual wNAFs */
+ size_t *wNAF_len = NULL;
+ size_t max_len = 0;
+ size_t num_val;
+ EC_POINT **val = NULL; /* precomputation */
+ EC_POINT **v;
+ EC_POINT ***val_sub =
+ NULL; /* pointers to sub-arrays of 'val' or 'pre_comp->points' */
+ const EC_PRE_COMP *pre_comp = NULL;
+ int num_scalar = 0; /* flag: will be set to 1 if 'scalar' must be treated like
+ * other scalars,
+ * i.e. precomputation is not available */
+ int ret = 0;
+
+ if (group->meth != r->meth) {
+ OPENSSL_PUT_ERROR(EC, ec_wNAF_mul, EC_R_INCOMPATIBLE_OBJECTS);
+ return 0;
+ }
+
+ if ((scalar == NULL) && (num == 0)) {
+ return EC_POINT_set_to_infinity(group, r);
+ }
+
+ for (i = 0; i < num; i++) {
+ if (group->meth != points[i]->meth) {
+ OPENSSL_PUT_ERROR(EC, ec_wNAF_mul, EC_R_INCOMPATIBLE_OBJECTS);
+ return 0;
+ }
+ }
+
+ if (ctx == NULL) {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ goto err;
+ }
+
+ if (scalar != NULL) {
+ generator = EC_GROUP_get0_generator(group);
+ if (generator == NULL) {
+ OPENSSL_PUT_ERROR(EC, ec_wNAF_mul, EC_R_UNDEFINED_GENERATOR);
+ goto err;
+ }
+
+ /* look if we can use precomputed multiples of generator */
+
+ pre_comp = group->pre_comp;
+
+ if (pre_comp && pre_comp->numblocks &&
+ (EC_POINT_cmp(group, generator, pre_comp->points[0], ctx) == 0)) {
+ blocksize = pre_comp->blocksize;
+
+ /* determine maximum number of blocks that wNAF splitting may yield
+ * (NB: maximum wNAF length is bit length plus one) */
+ numblocks = (BN_num_bits(scalar) / blocksize) + 1;
+
+ /* we cannot use more blocks than we have precomputation for */
+ if (numblocks > pre_comp->numblocks)
+ numblocks = pre_comp->numblocks;
+
+ pre_points_per_block = (size_t)1 << (pre_comp->w - 1);
+
+ /* 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);
+ goto err;
+ }
+ } else {
+ /* can't use precomputation */
+ pre_comp = NULL;
+ numblocks = 1;
+ num_scalar = 1; /* treat 'scalar' like 'num'-th element of 'scalars' */
+ }
+ }
+
+ totalnum = num + numblocks;
+
+ wsize = OPENSSL_malloc(totalnum * sizeof wsize[0]);
+ wNAF_len = OPENSSL_malloc(totalnum * sizeof wNAF_len[0]);
+ wNAF = OPENSSL_malloc((totalnum + 1) *
+ sizeof wNAF[0]); /* includes space for pivot */
+ val_sub = OPENSSL_malloc(totalnum * sizeof val_sub[0]);
+
+ if (!wsize || !wNAF_len || !wNAF || !val_sub) {
+ OPENSSL_PUT_ERROR(EC, ec_wNAF_mul, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ wNAF[0] = NULL; /* preliminary pivot */
+
+ /* num_val will be the total number of temporarily precomputed points */
+ num_val = 0;
+
+ for (i = 0; i < num + num_scalar; i++) {
+ size_t bits;
+
+ bits = i < num ? BN_num_bits(scalars[i]) : BN_num_bits(scalar);
+ wsize[i] = EC_window_bits_for_scalar_size(bits);
+ num_val += (size_t)1 << (wsize[i] - 1);
+ wNAF[i + 1] = NULL; /* make sure we always have a pivot */
+ wNAF[i] =
+ compute_wNAF((i < num ? scalars[i] : scalar), wsize[i], &wNAF_len[i]);
+ if (wNAF[i] == NULL)
+ goto err;
+ if (wNAF_len[i] > max_len)
+ max_len = wNAF_len[i];
+ }
+
+ if (numblocks) {
+ /* we go here iff scalar != NULL */
+
+ if (pre_comp == NULL) {
+ if (num_scalar != 1) {
+ OPENSSL_PUT_ERROR(EC, ec_wNAF_mul, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ /* we have already generated a wNAF for 'scalar' */
+ } else {
+ signed char *tmp_wNAF = NULL;
+ size_t tmp_len = 0;
+
+ if (num_scalar != 0) {
+ OPENSSL_PUT_ERROR(EC, ec_wNAF_mul, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ /* use the window size for which we have precomputation */
+ wsize[num] = pre_comp->w;
+ tmp_wNAF = compute_wNAF(scalar, wsize[num], &tmp_len);
+ if (!tmp_wNAF)
+ goto err;
+
+ if (tmp_len <= max_len) {
+ /* One of the other wNAFs is at least as long
+ * as the wNAF belonging to the generator,
+ * so wNAF splitting will not buy us anything. */
+
+ numblocks = 1;
+ totalnum = num + 1; /* don't use wNAF splitting */
+ wNAF[num] = tmp_wNAF;
+ wNAF[num + 1] = NULL;
+ wNAF_len[num] = tmp_len;
+ if (tmp_len > max_len)
+ max_len = tmp_len;
+ /* pre_comp->points starts with the points that we need here: */
+ val_sub[num] = pre_comp->points;
+ } else {
+ /* don't include tmp_wNAF directly into wNAF array
+ * - use wNAF splitting and include the blocks */
+
+ signed char *pp;
+ EC_POINT **tmp_points;
+
+ if (tmp_len < numblocks * blocksize) {
+ /* 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);
+ goto err;
+ }
+ totalnum = num + numblocks;
+ }
+
+ /* split wNAF in 'numblocks' parts */
+ pp = tmp_wNAF;
+ tmp_points = pre_comp->points;
+
+ for (i = num; i < totalnum; i++) {
+ if (i < totalnum - 1) {
+ wNAF_len[i] = blocksize;
+ if (tmp_len < blocksize) {
+ OPENSSL_PUT_ERROR(EC, ec_wNAF_mul, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ tmp_len -= blocksize;
+ } else
+ /* last block gets whatever is left
+ * (this could be more or less than 'blocksize'!) */
+ wNAF_len[i] = tmp_len;
+
+ 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_free(tmp_wNAF);
+ goto err;
+ }
+ memcpy(wNAF[i], pp, wNAF_len[i]);
+ if (wNAF_len[i] > max_len)
+ max_len = wNAF_len[i];
+
+ if (*tmp_points == NULL) {
+ OPENSSL_PUT_ERROR(EC, ec_wNAF_mul, ERR_R_INTERNAL_ERROR);
+ OPENSSL_free(tmp_wNAF);
+ goto err;
+ }
+ val_sub[i] = tmp_points;
+ tmp_points += pre_points_per_block;
+ pp += blocksize;
+ }
+ OPENSSL_free(tmp_wNAF);
+ }
+ }
+ }
+
+ /* All points we precompute now go into a single array 'val'.
+ * 'val_sub[i]' is a pointer to the subarray for the i-th point,
+ * or to a subarray of 'pre_comp->points' if we already have precomputation.
+ */
+ val = OPENSSL_malloc((num_val + 1) * sizeof val[0]);
+ if (val == NULL) {
+ OPENSSL_PUT_ERROR(EC, ec_wNAF_mul, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ val[num_val] = NULL; /* pivot element */
+
+ /* allocate points for precomputation */
+ v = val;
+ for (i = 0; i < num + num_scalar; i++) {
+ val_sub[i] = v;
+ for (j = 0; j < ((size_t)1 << (wsize[i] - 1)); j++) {
+ *v = EC_POINT_new(group);
+ if (*v == NULL)
+ goto err;
+ v++;
+ }
+ }
+ if (!(v == val + num_val)) {
+ OPENSSL_PUT_ERROR(EC, ec_wNAF_mul, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ if (!(tmp = EC_POINT_new(group)))
+ goto err;
+
+ /* prepare precomputed values:
+ * val_sub[i][0] := points[i]
+ * val_sub[i][1] := 3 * points[i]
+ * val_sub[i][2] := 5 * points[i]
+ * ...
+ */
+ for (i = 0; i < num + num_scalar; i++) {
+ if (i < num) {
+ if (!EC_POINT_copy(val_sub[i][0], points[i]))
+ goto err;
+ } else {
+ if (!EC_POINT_copy(val_sub[i][0], generator))
+ goto err;
+ }
+
+ if (wsize[i] > 1) {
+ if (!EC_POINT_dbl(group, tmp, val_sub[i][0], ctx))
+ goto err;
+ for (j = 1; j < ((size_t)1 << (wsize[i] - 1)); j++) {
+ if (!EC_POINT_add(group, val_sub[i][j], val_sub[i][j - 1], tmp, ctx))
+ goto err;
+ }
+ }
+ }
+
+#if 1 /* optional; EC_window_bits_for_scalar_size assumes we do this step */
+ if (!EC_POINTs_make_affine(group, num_val, val, ctx))
+ goto err;
+#endif
+
+ r_is_at_infinity = 1;
+
+ for (k = max_len - 1; k >= 0; k--) {
+ if (!r_is_at_infinity) {
+ if (!EC_POINT_dbl(group, r, r, ctx))
+ goto err;
+ }
+
+ for (i = 0; i < totalnum; i++) {
+ if (wNAF_len[i] > (size_t)k) {
+ int digit = wNAF[i][k];
+ int is_neg;
+
+ if (digit) {
+ is_neg = digit < 0;
+
+ if (is_neg)
+ digit = -digit;
+
+ if (is_neg != r_is_inverted) {
+ if (!r_is_at_infinity) {
+ if (!EC_POINT_invert(group, r, ctx))
+ goto err;
+ }
+ r_is_inverted = !r_is_inverted;
+ }
+
+ /* digit > 0 */
+
+ if (r_is_at_infinity) {
+ if (!EC_POINT_copy(r, val_sub[i][digit >> 1]))
+ goto err;
+ r_is_at_infinity = 0;
+ } else {
+ if (!EC_POINT_add(group, r, r, val_sub[i][digit >> 1], ctx))
+ goto err;
+ }
+ }
+ }
+ }
+ }
+
+ if (r_is_at_infinity) {
+ if (!EC_POINT_set_to_infinity(group, r))
+ goto err;
+ } else {
+ if (r_is_inverted)
+ if (!EC_POINT_invert(group, r, ctx))
+ goto err;
+ }
+
+ ret = 1;
+
+err:
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ if (tmp != NULL)
+ EC_POINT_free(tmp);
+ if (wsize != NULL)
+ OPENSSL_free(wsize);
+ if (wNAF_len != NULL)
+ OPENSSL_free(wNAF_len);
+ if (wNAF != NULL) {
+ signed char **w;
+
+ for (w = wNAF; *w != NULL; w++)
+ OPENSSL_free(*w);
+
+ OPENSSL_free(wNAF);
+ }
+ if (val != NULL) {
+ for (v = val; *v != NULL; v++)
+ EC_POINT_clear_free(*v);
+
+ OPENSSL_free(val);
+ }
+ if (val_sub != NULL) {
+ OPENSSL_free(val_sub);
+ }
+ return ret;
+}
+
+
+/* ec_wNAF_precompute_mult()
+ * creates an EC_PRE_COMP object with preprecomputed multiples of the generator
+ * for use with wNAF splitting as implemented in ec_wNAF_mul().
+ *
+ * 'pre_comp->points' is an array of multiples of the generator
+ * of the following form:
+ * points[0] = generator;
+ * points[1] = 3 * generator;
+ * ...
+ * points[2^(w-1)-1] = (2^(w-1)-1) * generator;
+ * points[2^(w-1)] = 2^blocksize * generator;
+ * points[2^(w-1)+1] = 3 * 2^blocksize * generator;
+ * ...
+ * points[2^(w-1)*(numblocks-1)-1] = (2^(w-1)) * 2^(blocksize*(numblocks-2)) *
+ *generator
+ * points[2^(w-1)*(numblocks-1)] = 2^(blocksize*(numblocks-1)) *
+ *generator
+ * ...
+ * points[2^(w-1)*numblocks-1] = (2^(w-1)) * 2^(blocksize*(numblocks-1)) *
+ *generator
+ * points[2^(w-1)*numblocks] = NULL
+ */
+int ec_wNAF_precompute_mult(EC_GROUP *group, BN_CTX *ctx) {
+ const EC_POINT *generator;
+ EC_POINT *tmp_point = NULL, *base = NULL, **var;
+ BN_CTX *new_ctx = NULL;
+ BIGNUM *order;
+ size_t i, bits, w, pre_points_per_block, blocksize, numblocks, num;
+ EC_POINT **points = NULL;
+ EC_PRE_COMP *pre_comp;
+ int ret = 0;
+
+ /* if there is an old EC_PRE_COMP object, throw it away */
+ if (group->pre_comp) {
+ ec_pre_comp_free(group->pre_comp);
+ group->pre_comp = NULL;
+ }
+
+ if ((pre_comp = ec_pre_comp_new(group)) == NULL)
+ return 0;
+
+ generator = EC_GROUP_get0_generator(group);
+ if (generator == NULL) {
+ OPENSSL_PUT_ERROR(EC, ec_wNAF_precompute_mult, EC_R_UNDEFINED_GENERATOR);
+ goto err;
+ }
+
+ if (ctx == NULL) {
+ ctx = new_ctx = BN_CTX_new();
+ if (ctx == NULL)
+ goto err;
+ }
+
+ BN_CTX_start(ctx);
+ order = BN_CTX_get(ctx);
+ if (order == NULL)
+ goto err;
+
+ if (!EC_GROUP_get_order(group, order, ctx))
+ goto err;
+ if (BN_is_zero(order)) {
+ OPENSSL_PUT_ERROR(EC, ec_wNAF_precompute_mult, EC_R_UNKNOWN_ORDER);
+ goto err;
+ }
+
+ bits = BN_num_bits(order);
+ /* The following parameters mean we precompute (approximately)
+ * one point per bit.
+ *
+ * TBD: The combination 8, 4 is perfect for 160 bits; for other
+ * bit lengths, other parameter combinations might provide better
+ * efficiency.
+ */
+ blocksize = 8;
+ w = 4;
+ if (EC_window_bits_for_scalar_size(bits) > w) {
+ /* let's not make the window too small ... */
+ w = EC_window_bits_for_scalar_size(bits);
+ }
+
+ numblocks = (bits + blocksize - 1) /
+ blocksize; /* max. number of blocks to use for wNAF splitting */
+
+ pre_points_per_block = (size_t)1 << (w - 1);
+ num = pre_points_per_block *
+ numblocks; /* number of points to compute and store */
+
+ points = OPENSSL_malloc(sizeof(EC_POINT *) * (num + 1));
+ if (!points) {
+ OPENSSL_PUT_ERROR(EC, ec_wNAF_precompute_mult, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ var = points;
+ 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);
+ 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);
+ goto err;
+ }
+
+ if (!EC_POINT_copy(base, generator))
+ goto err;
+
+ /* do the precomputation */
+ for (i = 0; i < numblocks; i++) {
+ size_t j;
+
+ if (!EC_POINT_dbl(group, tmp_point, base, ctx))
+ goto err;
+
+ if (!EC_POINT_copy(*var++, base))
+ goto err;
+
+ for (j = 1; j < pre_points_per_block; j++, var++) {
+ /* calculate odd multiples of the current base point */
+ if (!EC_POINT_add(group, *var, tmp_point, *(var - 1), ctx))
+ goto err;
+ }
+
+ if (i < numblocks - 1) {
+ /* get the next base (multiply current one by 2^blocksize) */
+ size_t k;
+
+ if (blocksize <= 2) {
+ OPENSSL_PUT_ERROR(EC, ec_wNAF_precompute_mult, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ if (!EC_POINT_dbl(group, base, tmp_point, ctx))
+ goto err;
+ for (k = 2; k < blocksize; k++) {
+ if (!EC_POINT_dbl(group, base, base, ctx))
+ goto err;
+ }
+ }
+ }
+
+ if (!EC_POINTs_make_affine(group, num, points, ctx))
+ goto err;
+
+ pre_comp->group = group;
+ pre_comp->blocksize = blocksize;
+ pre_comp->numblocks = numblocks;
+ pre_comp->w = w;
+ pre_comp->points = points;
+ points = NULL;
+ pre_comp->num = num;
+
+ group->pre_comp = pre_comp;
+ pre_comp = NULL;
+
+ ret = 1;
+
+err:
+ if (ctx != NULL)
+ BN_CTX_end(ctx);
+ if (new_ctx != NULL)
+ BN_CTX_free(new_ctx);
+ if (pre_comp)
+ ec_pre_comp_free(pre_comp);
+ if (points) {
+ EC_POINT **p;
+
+ for (p = points; *p != NULL; p++)
+ EC_POINT_free(*p);
+ OPENSSL_free(points);
+ }
+ if (tmp_point)
+ EC_POINT_free(tmp_point);
+ if (base)
+ EC_POINT_free(base);
+ return ret;
+}
+
+
+int ec_wNAF_have_precompute_mult(const EC_GROUP *group) {
+ return group->pre_comp != NULL;
+}
diff --git a/crypto/ecdh/CMakeLists.txt b/crypto/ecdh/CMakeLists.txt
new file mode 100644
index 0000000..0f71368
--- /dev/null
+++ b/crypto/ecdh/CMakeLists.txt
@@ -0,0 +1,10 @@
+include_directories(. .. ../../include)
+
+add_library(
+ ecdh
+
+ OBJECT
+
+ ecdh.c
+ ecdh_error.c
+)
diff --git a/crypto/ecdh/ecdh.c b/crypto/ecdh/ecdh.c
new file mode 100644
index 0000000..c64a0ad
--- /dev/null
+++ b/crypto/ecdh/ecdh.c
@@ -0,0 +1,218 @@
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * The Elliptic Curve Public-Key Crypto Library (ECC Code) included
+ * herein is developed by SUN MICROSYSTEMS, INC., and is contributed
+ * to the OpenSSL project.
+ *
+ * The ECC Code is licensed pursuant to the OpenSSL open source
+ * license provided below.
+ *
+ * The ECDH software is originally written by Douglas Stebila of
+ * Sun Microsystems Laboratories.
+ *
+ */
+/* ====================================================================
+ * Copyright (c) 2000-2002 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/ecdh.h>
+
+#include <openssl/bn.h>
+#include <openssl/digest.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+int ECDH_compute_key(void *out, size_t outlen, const EC_POINT *pub_key,
+ EC_KEY *priv_key, void *(*KDF)(const void *in, size_t inlen,
+ void *out, size_t *outlen)) {
+ BN_CTX *ctx;
+ EC_POINT *tmp = NULL;
+ BIGNUM *x = NULL, *y = NULL;
+ const BIGNUM *priv;
+ const EC_GROUP *group;
+ int ret = -1;
+ size_t buflen, len;
+ uint8_t *buf = NULL;
+
+ if ((ctx = BN_CTX_new()) == NULL) {
+ goto err;
+ }
+ BN_CTX_start(ctx);
+ x = BN_CTX_get(ctx);
+ y = BN_CTX_get(ctx);
+
+ priv = EC_KEY_get0_private_key(priv_key);
+ if (priv == NULL) {
+ OPENSSL_PUT_ERROR(ECDH, ECDH_compute_key, ECDH_R_NO_PRIVATE_VALUE);
+ goto err;
+ }
+
+ group = EC_KEY_get0_group(priv_key);
+
+ tmp = EC_POINT_new(group);
+ if (tmp == NULL) {
+ OPENSSL_PUT_ERROR(ECDH, ECDH_compute_key, 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);
+ 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);
+ goto err;
+ }
+
+ buflen = (EC_GROUP_get_degree(group) + 7) / 8;
+ len = BN_num_bytes(x);
+ if (len > buflen) {
+ OPENSSL_PUT_ERROR(ECDH, ECDH_compute_key, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ buf = OPENSSL_malloc(buflen);
+ if (buf == NULL) {
+ OPENSSL_PUT_ERROR(ECDH, ECDH_compute_key, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ memset(buf, 0, buflen - len);
+ if (len != (size_t)BN_bn2bin(x, buf + buflen - len)) {
+ OPENSSL_PUT_ERROR(ECDH, ECDH_compute_key, ERR_R_BN_LIB);
+ goto err;
+ }
+
+ if (KDF != 0) {
+ if (KDF(buf, buflen, out, &outlen) == NULL) {
+ OPENSSL_PUT_ERROR(ECDH, ECDH_compute_key, ECDH_R_KDF_FAILED);
+ goto err;
+ }
+ ret = outlen;
+ } else {
+ /* no KDF, just copy as much as we can */
+ if (outlen > buflen) {
+ outlen = buflen;
+ }
+ memcpy(out, buf, outlen);
+ ret = outlen;
+ }
+
+err:
+ if (tmp)
+ EC_POINT_free(tmp);
+ if (ctx)
+ BN_CTX_end(ctx);
+ if (ctx)
+ BN_CTX_free(ctx);
+ if (buf)
+ OPENSSL_free(buf);
+ return ret;
+}
+
+/* Key derivation function from X9.62/SECG */
+/* Way more than we will ever need */
+#define ECDH_KDF_MAX (1 << 30)
+
+int ECDH_KDF_X9_62(uint8_t *out, size_t outlen, const uint8_t *Z,
+ size_t Zlen, const uint8_t *sinfo, size_t sinfolen,
+ const EVP_MD *md) {
+ EVP_MD_CTX mctx;
+ int rv = 0;
+ unsigned int i;
+ size_t mdlen;
+ uint8_t ctr[4];
+
+ if (sinfolen > ECDH_KDF_MAX || outlen > ECDH_KDF_MAX || Zlen > ECDH_KDF_MAX) {
+ return 0;
+ }
+ mdlen = EVP_MD_size(md);
+ EVP_MD_CTX_init(&mctx);
+
+ for (i = 1;; i++) {
+ uint8_t mtmp[EVP_MAX_MD_SIZE];
+ EVP_DigestInit_ex(&mctx, md, NULL);
+ ctr[3] = i & 0xFF;
+ ctr[2] = (i >> 8) & 0xFF;
+ ctr[1] = (i >> 16) & 0xFF;
+ ctr[0] = (i >> 24) & 0xFF;
+ if (!EVP_DigestUpdate(&mctx, Z, Zlen) ||
+ !EVP_DigestUpdate(&mctx, ctr, sizeof(ctr)) ||
+ !EVP_DigestUpdate(&mctx, sinfo, sinfolen)) {
+ goto err;
+ }
+
+ if (outlen >= mdlen) {
+ if (!EVP_DigestFinal(&mctx, out, NULL)) {
+ goto err;
+ }
+ outlen -= mdlen;
+ if (outlen == 0) {
+ break;
+ }
+ out += mdlen;
+ } else {
+ if (!EVP_DigestFinal(&mctx, mtmp, NULL)) {
+ goto err;
+ }
+ memcpy(out, mtmp, outlen);
+ OPENSSL_cleanse(mtmp, mdlen);
+ break;
+ }
+ }
+ rv = 1;
+
+err:
+ EVP_MD_CTX_cleanup(&mctx);
+ return rv;
+}
diff --git a/crypto/ecdh/ecdh.h b/crypto/ecdh/ecdh.h
new file mode 100644
index 0000000..48aa08d
--- /dev/null
+++ b/crypto/ecdh/ecdh.h
@@ -0,0 +1,106 @@
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * The Elliptic Curve Public-Key Crypto Library (ECC Code) included
+ * herein is developed by SUN MICROSYSTEMS, INC., and is contributed
+ * to the OpenSSL project.
+ *
+ * The ECC Code is licensed pursuant to the OpenSSL open source
+ * license provided below.
+ *
+ * The ECDH software is originally written by Douglas Stebila of
+ * Sun Microsystems Laboratories.
+ *
+ */
+/* ====================================================================
+ * Copyright (c) 2000-2002 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). */
+
+#ifndef OPENSSL_HEADER_ECDH_H
+#define OPENSSL_HEADER_ECDH_H
+
+#include <openssl/base.h>
+
+#include <openssl/ec_key.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* ECDH_compute_key calculates the shared key between |pub_key| and |priv_key|.
+ * If |KDF| is not NULL, then it is called with the bytes of the shared key and
+ * the parameter |out|. When |KDF| returns, the value of |*outlen| becomes the
+ * return value. Otherwise, as many bytes of the shared key as will fit are
+ * copied directly to, at most, |outlen| bytes at |out|. It returns the number
+ * of bytes written to |out|, or -1 on error. */
+int ECDH_compute_key(void *out, size_t outlen, const EC_POINT *pub_key,
+ EC_KEY *priv_key, void *(*KDF)(const void *in, size_t inlen,
+ void *out, size_t *outlen));
+
+/* ECDH_KDF_X9_62 writes |outlen| bytes to |out| using the KDF from X9.62
+ * applied to |Z| and |sinfo| and using the hash |md|. It returns one on
+ * success and zero otherwise. */
+int ECDH_KDF_X9_62(uint8_t *out, size_t outlen, const uint8_t *Z,
+ size_t Zlen, const uint8_t *sinfo, size_t sinfolen,
+ const EVP_MD *md);
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#define ECDH_F_ECDH_compute_key 100
+#define ECDH_R_POINT_ARITHMETIC_FAILURE 100
+#define ECDH_R_KDF_FAILED 101
+#define ECDH_R_NO_PRIVATE_VALUE 102
+
+#endif /* OPENSSL_HEADER_ECDH_H */
diff --git a/crypto/ecdh/ecdh_error.c b/crypto/ecdh/ecdh_error.c
new file mode 100644
index 0000000..9e53467
--- /dev/null
+++ b/crypto/ecdh/ecdh_error.c
@@ -0,0 +1,25 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/err.h>
+
+#include "ecdh.h"
+
+const ERR_STRING_DATA ECDH_error_string_data[] = {
+ {ERR_PACK(ERR_LIB_ECDH, ECDH_F_ECDH_compute_key, 0), "ECDH_compute_key"},
+ {ERR_PACK(ERR_LIB_ECDH, 0, ECDH_R_KDF_FAILED), "KDF_FAILED"},
+ {ERR_PACK(ERR_LIB_ECDH, 0, ECDH_R_NO_PRIVATE_VALUE), "NO_PRIVATE_VALUE"},
+ {ERR_PACK(ERR_LIB_ECDH, 0, ECDH_R_POINT_ARITHMETIC_FAILURE), "POINT_ARITHMETIC_FAILURE"},
+ {0, NULL},
+};
diff --git a/crypto/ecdsa/CMakeLists.txt b/crypto/ecdsa/CMakeLists.txt
new file mode 100644
index 0000000..3f0caf0
--- /dev/null
+++ b/crypto/ecdsa/CMakeLists.txt
@@ -0,0 +1,20 @@
+include_directories(. .. ../../include)
+
+add_library(
+ ecdsa
+
+ OBJECT
+
+ ecdsa.c
+ ecdsa_asn1.c
+ ecdsa_error.c
+)
+
+
+add_executable(
+ ecdsa_test
+
+ ecdsa_test.c
+)
+
+target_link_libraries(ecdsa_test crypto)
diff --git a/crypto/ecdsa/ecdsa.c b/crypto/ecdsa/ecdsa.c
new file mode 100644
index 0000000..cfe9ef6
--- /dev/null
+++ b/crypto/ecdsa/ecdsa.c
@@ -0,0 +1,465 @@
+/* ====================================================================
+ * Copyright (c) 1998-2005 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). */
+
+#include <openssl/ecdsa.h>
+
+#include <openssl/bn.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/thread.h>
+
+#include "../ec/internal.h"
+
+
+int ECDSA_sign(int type, const uint8_t *digest, size_t digest_len, uint8_t *sig,
+ unsigned int *sig_len, EC_KEY *eckey) {
+ if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) {
+ return eckey->ecdsa_meth->sign(digest, digest_len, sig, sig_len, eckey);
+ }
+
+ return ECDSA_sign_ex(type, digest, digest_len, sig, sig_len, NULL, NULL,
+ eckey);
+}
+
+int ECDSA_verify(int type, const uint8_t *digest, size_t digest_len,
+ const uint8_t *sig, size_t sig_len, EC_KEY *eckey) {
+ ECDSA_SIG *s;
+ int ret = -1;
+
+ if (eckey->ecdsa_meth && eckey->ecdsa_meth->verify) {
+ return eckey->ecdsa_meth->verify(digest, digest_len, sig, sig_len, eckey);
+ }
+
+ s = ECDSA_SIG_new();
+ if (s == NULL || d2i_ECDSA_SIG(&s, &sig, sig_len) == NULL) {
+ goto err;
+ }
+ ret = ECDSA_do_verify(digest, digest_len, s, eckey);
+
+err:
+ if (s != NULL) {
+ ECDSA_SIG_free(s);
+ }
+ return ret;
+}
+
+/* digest_to_bn interprets |digest_len| bytes from |digest| as a big-endian
+ * number and sets |out| to that value. It then truncates |out| so that it's,
+ * at most, as long as |order|. It returns one on success and zero otherwise. */
+static int digest_to_bn(BIGNUM *out, const uint8_t *digest, size_t digest_len,
+ const BIGNUM *order) {
+ size_t num_bits;
+
+ num_bits = BN_num_bits(order);
+ /* Need to truncate digest if it is too long: first truncate whole
+ * bytes. */
+ if (8 * digest_len > num_bits) {
+ digest_len = (num_bits + 7) / 8;
+ }
+ if (!BN_bin2bn(digest, digest_len, out)) {
+ OPENSSL_PUT_ERROR(ECDSA, digest_to_bn, 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);
+ return 0;
+ }
+
+ return 1;
+}
+
+ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, size_t digest_len,
+ EC_KEY *key) {
+ return ECDSA_do_sign_ex(digest, digest_len, NULL, NULL, key);
+}
+
+int ECDSA_do_verify(const uint8_t *digest, size_t digest_len,
+ const ECDSA_SIG *sig, EC_KEY *eckey) {
+ int ret = -1;
+ BN_CTX *ctx;
+ BIGNUM *order, *u1, *u2, *m, *X;
+ EC_POINT *point = NULL;
+ const EC_GROUP *group;
+ const EC_POINT *pub_key;
+
+ if (eckey->ecdsa_meth && eckey->ecdsa_meth->verify) {
+ OPENSSL_PUT_ERROR(ECDSA, ECDSA_sign_ex, ECDSA_R_NOT_IMPLEMENTED);
+ return -1;
+ }
+
+ /* check input values */
+ if (eckey == NULL || (group = EC_KEY_get0_group(eckey)) == NULL ||
+ (pub_key = EC_KEY_get0_public_key(eckey)) == NULL || sig == NULL) {
+ OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ECDSA_R_MISSING_PARAMETERS);
+ return -1;
+ }
+
+ ctx = BN_CTX_new();
+ if (!ctx) {
+ OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+ BN_CTX_start(ctx);
+ order = BN_CTX_get(ctx);
+ u1 = BN_CTX_get(ctx);
+ 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);
+ goto err;
+ }
+
+ if (!EC_GROUP_get_order(group, order, ctx)) {
+ OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, 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);
+ 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);
+ goto err;
+ }
+ if (!digest_to_bn(m, digest, digest_len, order)) {
+ goto err;
+ }
+ /* 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);
+ 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);
+ goto err;
+ }
+
+ point = EC_POINT_new(group);
+ if (point == NULL) {
+ OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, 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);
+ 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);
+ goto err;
+ }
+ if (!BN_nnmod(u1, X, order, ctx)) {
+ OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ERR_R_BN_LIB);
+ goto err;
+ }
+ /* if the signature is correct u1 is equal to sig->r */
+ ret = (BN_ucmp(u1, sig->r) == 0);
+
+err:
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ if (point) {
+ EC_POINT_free(point);
+ }
+ return ret;
+}
+
+int ECDSA_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp,
+ BIGNUM **rp) {
+ BN_CTX *ctx = NULL;
+ BIGNUM *k = NULL, *r = NULL, *order = NULL, *X = NULL;
+ EC_POINT *tmp_point = NULL;
+ const EC_GROUP *group;
+ 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);
+ return 0;
+ }
+
+ if (ctx_in == NULL) {
+ if ((ctx = BN_CTX_new()) == NULL) {
+ OPENSSL_PUT_ERROR(ECDSA, ECDSA_sign_setup, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ } else {
+ ctx = ctx_in;
+ }
+
+ k = BN_new(); /* this value is later returned in *kinvp */
+ r = BN_new(); /* this value is later returned in *rp */
+ order = BN_new();
+ X = BN_new();
+ if (!k || !r || !order || !X) {
+ OPENSSL_PUT_ERROR(ECDSA, ECDSA_sign_setup, 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);
+ goto err;
+ }
+ if (!EC_GROUP_get_order(group, order, ctx)) {
+ OPENSSL_PUT_ERROR(ECDSA, ECDSA_sign_setup, ERR_R_EC_LIB);
+ goto err;
+ }
+
+ do {
+ /* get random k */
+ do {
+ if (!BN_rand_range(k, order)) {
+ OPENSSL_PUT_ERROR(ECDSA, ECDSA_sign_setup,
+ ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED);
+ goto err;
+ }
+ } while (BN_is_zero(k));
+
+ /* We do not want timing information to leak the length of k,
+ * so we compute G*k using an equivalent scalar of fixed
+ * bit-length. */
+
+ if (!BN_add(k, k, order)) {
+ goto err;
+ }
+ if (BN_num_bits(k) <= BN_num_bits(order)) {
+ if (!BN_add(k, k, order)) {
+ goto err;
+ }
+ }
+
+ /* 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);
+ 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);
+ goto err;
+ }
+
+ if (!BN_nnmod(r, X, order, ctx)) {
+ OPENSSL_PUT_ERROR(ECDSA, ECDSA_sign_setup, 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);
+ goto err;
+ }
+ /* clear old values if necessary */
+ if (*rp != NULL) {
+ BN_clear_free(*rp);
+ }
+ if (*kinvp != NULL) {
+ BN_clear_free(*kinvp);
+ }
+
+ /* save the pre-computed values */
+ *rp = r;
+ *kinvp = k;
+ ret = 1;
+
+err:
+ if (!ret) {
+ if (k != NULL) {
+ BN_clear_free(k);
+ }
+ if (r != NULL) {
+ BN_clear_free(r);
+ }
+ }
+ if (ctx_in == NULL)
+ BN_CTX_free(ctx);
+ if (order != NULL)
+ BN_free(order);
+ if (tmp_point != NULL)
+ EC_POINT_free(tmp_point);
+ if (X)
+ BN_clear_free(X);
+ return ret;
+}
+
+ECDSA_SIG *ECDSA_do_sign_ex(const uint8_t *digest, size_t digest_len,
+ const BIGNUM *in_kinv, const BIGNUM *in_r,
+ EC_KEY *eckey) {
+ int ok = 0;
+ BIGNUM *kinv = NULL, *s, *m = NULL, *tmp = NULL, *order = NULL;
+ const BIGNUM *ckinv;
+ BN_CTX *ctx = NULL;
+ const EC_GROUP *group;
+ ECDSA_SIG *ret;
+ const BIGNUM *priv_key;
+
+ if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) {
+ OPENSSL_PUT_ERROR(ECDSA, ECDSA_sign_ex, ECDSA_R_NOT_IMPLEMENTED);
+ return NULL;
+ }
+
+ group = EC_KEY_get0_group(eckey);
+ 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);
+ return NULL;
+ }
+
+ ret = ECDSA_SIG_new();
+ if (!ret) {
+ OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, 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);
+ goto err;
+ }
+
+ if (!EC_GROUP_get_order(group, order, ctx)) {
+ OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, ERR_R_EC_LIB);
+ goto err;
+ }
+ if (!digest_to_bn(m, digest, digest_len, order)) {
+ goto err;
+ }
+ for (;;) {
+ if (in_kinv == NULL || in_r == NULL) {
+ if (!ECDSA_sign_setup(eckey, ctx, &kinv, &ret->r)) {
+ OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, 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);
+ 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);
+ goto err;
+ }
+ if (!BN_mod_add_quick(s, tmp, m, order)) {
+ OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_sign_ex, 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);
+ 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);
+ goto err;
+ }
+ } else {
+ /* s != 0 => we have a valid signature */
+ break;
+ }
+ }
+
+ ok = 1;
+
+err:
+ if (!ok) {
+ ECDSA_SIG_free(ret);
+ ret = NULL;
+ }
+ if (ctx)
+ BN_CTX_free(ctx);
+ if (m)
+ BN_clear_free(m);
+ if (tmp)
+ BN_clear_free(tmp);
+ if (order)
+ BN_free(order);
+ if (kinv)
+ BN_clear_free(kinv);
+ return ret;
+}
+
+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) {
+ ECDSA_SIG *s = NULL;
+
+ if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) {
+ OPENSSL_PUT_ERROR(ECDSA, ECDSA_sign_ex, ECDSA_R_NOT_IMPLEMENTED);
+ *sig_len = 0;
+ return 0;
+ }
+
+ s = ECDSA_do_sign_ex(digest, digest_len, kinv, r, eckey);
+ if (s == NULL) {
+ *sig_len = 0;
+ return 0;
+ }
+ *sig_len = i2d_ECDSA_SIG(s, &sig);
+ ECDSA_SIG_free(s);
+ return 1;
+}
diff --git a/crypto/ecdsa/ecdsa.h b/crypto/ecdsa/ecdsa.h
new file mode 100644
index 0000000..6ad7ad2
--- /dev/null
+++ b/crypto/ecdsa/ecdsa.h
@@ -0,0 +1,187 @@
+/* ====================================================================
+ * Copyright (c) 1998-2005 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_ECDSA_H
+#define OPENSSL_HEADER_ECDSA_H
+
+#include <openssl/base.h>
+
+#include <openssl/ec_key.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* DSA contains functions for signing and verifing with the Digital Signature
+ * Algorithm over elliptic curves. */
+
+
+/* Signing and verifing. */
+
+/* ECDSA_sign signs |digest_len| bytes from |digest| with |key| and writes the
+ * resulting signature to |sig|, which must have |ECDSA_size(key)| bytes of
+ * space. On successful exit, |*sig_len| is set to the actual number of bytes
+ * written. The |type| argument should be zero. It returns one on success and
+ * zero otherwise. */
+int ECDSA_sign(int type, const uint8_t *digest, size_t digest_len, uint8_t *sig,
+ unsigned int *sig_len, EC_KEY *key);
+
+/* ECDSA_verify verifies that |sig_len| bytes from |sig| constitute a valid
+ * signature by |key| of |digest|. (The |type| argument should be zero.) It
+ * returns one on success, zero if the signature is invalid and -1 on error.
+ *
+ * DANGER: this function differs from the usual OpenSSL return value
+ * convention.
+ *
+ * TODO(fork): change this to return the usual 0/1. */
+int ECDSA_verify(int type, const uint8_t *digest, size_t digest_len,
+ const uint8_t *sig, size_t sig_len, EC_KEY *key);
+
+/* ECDSA_size returns the maximum size of an ECDSA signature using |key|. It
+ * returns zero on error. */
+size_t ECDSA_size(const EC_KEY *key);
+
+
+/* Low-level signing and verification.
+ *
+ * Low-level functions handle signatures as |ECDSA_SIG| structures which allow
+ * the two values in an ECDSA signature to be handled separately. */
+
+struct ecdsa_sig_st {
+ BIGNUM *r;
+ BIGNUM *s;
+};
+
+/* ECDSA_SIG_new returns a fresh |ECDSA_SIG| structure or NULL on error. */
+ECDSA_SIG *ECDSA_SIG_new(void);
+
+/* ECDSA_SIG_free frees |sig| its member |BIGNUM|s. */
+void ECDSA_SIG_free(ECDSA_SIG *sig);
+
+/* ECDSA_sign signs |digest_len| bytes from |digest| with |key| and returns the
+ * resulting signature structure, or NULL on error.
+ *
+ * TODO(fork): remove this function. */
+ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, size_t digest_len,
+ EC_KEY *key);
+
+/* ECDSA_verify verifies that |sig| constitutes a valid signature by |key| of
+ * |digest|. It returns one on success, zero if the signature is invalid and -1
+ * on error.
+ *
+ * DANGER: this function differs from the usual OpenSSL return value
+ * convention.
+ *
+ * TODO(fork): remove this function. */
+int ECDSA_do_verify(const uint8_t *digest, size_t digest_len,
+ const ECDSA_SIG *sig, EC_KEY *key);
+
+
+/* Signing with precomputation.
+ *
+ * Parts of the ECDSA signature can be independent of the message to be signed
+ * thus it's possible to precompute them and reduce the signing latency.
+ *
+ * TODO(fork): remove support for this as it cannot support safe-randomness. */
+
+/* ECDSA_sign_setup precomputes parts of an ECDSA signing operation. It sets
+ * |*kinv| and |*rp| to the precomputed values and uses the |ctx| argument, if
+ * not NULL. It returns one on success and zero otherwise. */
+int ECDSA_sign_setup(EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv, BIGNUM **rp);
+
+/* ECDSA_do_sign_ex is the same as |ECDSA_do_sign| but takes precomputed values
+ * as generated by |ECDSA_sign_setup|. */
+ECDSA_SIG *ECDSA_do_sign_ex(const uint8_t *digest, size_t digest_len,
+ const BIGNUM *kinv, const BIGNUM *rp,
+ EC_KEY *eckey);
+
+/* ECDSA_sign_ex is the same as |ECDSA_sign| but takes precomputed values as
+ * generated by |ECDSA_sign_setup|. */
+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 *rp, EC_KEY *eckey);
+
+
+/* ASN.1 functions. */
+
+/* d2i_ECDSA_SIG parses an ASN.1, DER-encoded, signature from |len| bytes at
+ * |*inp|. If |out| is not NULL then, on exit, a pointer to the result is in
+ * |*out|. If |*out| is already non-NULL on entry then the result is written
+ * directly into |*out|, otherwise a fresh |ECDSA_SIG| is allocated. On
+ * successful exit, |*inp| is advanced past the DER structure. It returns the
+ * result or NULL on error. */
+ECDSA_SIG *d2i_ECDSA_SIG(ECDSA_SIG **out, const uint8_t **inp, long len);
+
+/* i2d_ECDSA_SIG marshals a signature from |sig| to an ASN.1, DER
+ * structure. If |outp| is not NULL then the result is written to |*outp| and
+ * |*outp| is advanced just past the output. It returns the number of bytes in
+ * the result, whether written or not, or a negative value on error. */
+int i2d_ECDSA_SIG(const ECDSA_SIG *sig, uint8_t **outp);
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#define ECDSA_F_digest_to_bn 100
+#define ECDSA_F_ECDSA_do_verify 101
+#define ECDSA_F_ECDSA_sign_setup 102
+#define ECDSA_F_ECDSA_do_sign_ex 103
+#define ECDSA_F_ECDSA_sign_ex 104
+#define ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED 100
+#define ECDSA_R_NEED_NEW_SETUP_VALUES 101
+#define ECDSA_R_MISSING_PARAMETERS 102
+#define ECDSA_R_BAD_SIGNATURE 103
+#define ECDSA_R_NOT_IMPLEMENTED 104
+
+#endif /* OPENSSL_HEADER_ECDSA_H */
diff --git a/crypto/ecdsa/ecdsa_asn1.c b/crypto/ecdsa/ecdsa_asn1.c
new file mode 100644
index 0000000..9d68361
--- /dev/null
+++ b/crypto/ecdsa/ecdsa_asn1.c
@@ -0,0 +1,111 @@
+/* ====================================================================
+ * Copyright (c) 1998-2005 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). */
+
+#include <openssl/ecdsa.h>
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/ec_key.h>
+
+#include "../ec/internal.h"
+
+
+ASN1_SEQUENCE(ECDSA_SIG) = {
+ ASN1_SIMPLE(ECDSA_SIG, r, CBIGNUM),
+ ASN1_SIMPLE(ECDSA_SIG, s, CBIGNUM),
+} ASN1_SEQUENCE_END(ECDSA_SIG);
+
+DECLARE_ASN1_FUNCTIONS_const(ECDSA_SIG);
+DECLARE_ASN1_ENCODE_FUNCTIONS_const(ECDSA_SIG, ECDSA_SIG);
+IMPLEMENT_ASN1_FUNCTIONS_const(ECDSA_SIG);
+
+size_t ECDSA_size(const EC_KEY *key) {
+ size_t ret, i;
+ ASN1_INTEGER bs;
+ BIGNUM *order = NULL;
+ unsigned char buf[4];
+ const EC_GROUP *group;
+
+ if (key->ecdsa_meth && key->ecdsa_meth->size) {
+ return key->ecdsa_meth->size(key);
+ }
+
+ if (key == NULL) {
+ return 0;
+ }
+ group = EC_KEY_get0_group(key);
+ if (group == NULL) {
+ return 0;
+ }
+
+ order = BN_new();
+ if (order == NULL) {
+ return 0;
+ }
+ if (!EC_GROUP_get_order(group, order, NULL)) {
+ BN_clear_free(order);
+ return 0;
+ }
+
+ i = BN_num_bits(order);
+ bs.length = (i + 7) / 8;
+ 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;
+}
diff --git a/crypto/ecdsa/ecdsa_error.c b/crypto/ecdsa/ecdsa_error.c
new file mode 100644
index 0000000..4de508a
--- /dev/null
+++ b/crypto/ecdsa/ecdsa_error.c
@@ -0,0 +1,31 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/err.h>
+
+#include "ecdsa.h"
+
+const ERR_STRING_DATA ECDSA_error_string_data[] = {
+ {ERR_PACK(ERR_LIB_ECDSA, ECDSA_F_ECDSA_do_sign_ex, 0), "ECDSA_do_sign_ex"},
+ {ERR_PACK(ERR_LIB_ECDSA, ECDSA_F_ECDSA_do_verify, 0), "ECDSA_do_verify"},
+ {ERR_PACK(ERR_LIB_ECDSA, ECDSA_F_ECDSA_sign_ex, 0), "ECDSA_sign_ex"},
+ {ERR_PACK(ERR_LIB_ECDSA, ECDSA_F_ECDSA_sign_setup, 0), "ECDSA_sign_setup"},
+ {ERR_PACK(ERR_LIB_ECDSA, ECDSA_F_digest_to_bn, 0), "digest_to_bn"},
+ {ERR_PACK(ERR_LIB_ECDSA, 0, ECDSA_R_BAD_SIGNATURE), "BAD_SIGNATURE"},
+ {ERR_PACK(ERR_LIB_ECDSA, 0, ECDSA_R_MISSING_PARAMETERS), "MISSING_PARAMETERS"},
+ {ERR_PACK(ERR_LIB_ECDSA, 0, ECDSA_R_NEED_NEW_SETUP_VALUES), "NEED_NEW_SETUP_VALUES"},
+ {ERR_PACK(ERR_LIB_ECDSA, 0, ECDSA_R_NOT_IMPLEMENTED), "NOT_IMPLEMENTED"},
+ {ERR_PACK(ERR_LIB_ECDSA, 0, ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED), "RANDOM_NUMBER_GENERATION_FAILED"},
+ {0, NULL},
+};
diff --git a/crypto/ecdsa/ecdsa_test.c b/crypto/ecdsa/ecdsa_test.c
new file mode 100644
index 0000000..64480e3
--- /dev/null
+++ b/crypto/ecdsa/ecdsa_test.c
@@ -0,0 +1,309 @@
+/* ====================================================================
+ * Copyright (c) 1998-2005 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). */
+
+#include <openssl/ecdsa.h>
+
+#include <openssl/bio.h>
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/rand.h>
+
+
+int test_builtin(BIO *out) {
+ size_t n = 0;
+ EC_KEY *eckey = NULL, *wrong_eckey = NULL;
+ EC_GROUP *group;
+ ECDSA_SIG *ecdsa_sig = NULL;
+ unsigned char digest[20], wrong_digest[20];
+ unsigned char *signature = NULL;
+ const unsigned char *sig_ptr;
+ unsigned char *sig_ptr2;
+ unsigned char *raw_buf = NULL;
+ unsigned int sig_len, degree, r_len, s_len, bn_len, buf_len;
+ int nid, ret = 0;
+
+ /* fill digest values with some random data */
+ if (!RAND_pseudo_bytes(digest, 20) || !RAND_pseudo_bytes(wrong_digest, 20)) {
+ BIO_printf(out, "ERROR: unable to get random data\n");
+ goto builtin_err;
+ }
+
+ /* create and verify a ecdsa signature with every availble curve
+ * (with ) */
+ BIO_printf(out,
+ "\ntesting ECDSA_sign() and ECDSA_verify() "
+ "with some internal curves:\n");
+
+ static const int kCurveNIDs[] = {NID_secp224r1, NID_X9_62_prime256v1,
+ NID_secp384r1, NID_secp521r1, NID_undef};
+
+ /* now create and verify a signature for every curve */
+ for (n = 0; kCurveNIDs[n] != NID_undef; n++) {
+ unsigned char dirt, offset;
+
+ nid = kCurveNIDs[n];
+ /* create new ecdsa key (== EC_KEY) */
+ eckey = EC_KEY_new();
+ if (eckey == NULL) {
+ goto builtin_err;
+ }
+ group = EC_GROUP_new_by_curve_name(nid);
+ if (group == NULL) {
+ goto builtin_err;
+ }
+ if (!EC_KEY_set_group(eckey, group)) {
+ goto builtin_err;
+ }
+ EC_GROUP_free(group);
+ degree = EC_GROUP_get_degree(EC_KEY_get0_group(eckey));
+ if (degree < 160) {
+ /* Too small to test. */
+ EC_KEY_free(eckey);
+ eckey = NULL;
+ continue;
+ }
+
+ BIO_printf(out, "%s: ", OBJ_nid2sn(nid));
+ /* create key */
+ if (!EC_KEY_generate_key(eckey)) {
+ BIO_printf(out, " failed\n");
+ goto builtin_err;
+ }
+ /* create second key */
+ wrong_eckey = EC_KEY_new();
+ if (wrong_eckey == NULL) {
+ goto builtin_err;
+ }
+ group = EC_GROUP_new_by_curve_name(nid);
+ if (group == NULL) {
+ goto builtin_err;
+ }
+ if (EC_KEY_set_group(wrong_eckey, group) == 0) {
+ goto builtin_err;
+ }
+ EC_GROUP_free(group);
+ if (!EC_KEY_generate_key(wrong_eckey)) {
+ BIO_printf(out, " failed\n");
+ goto builtin_err;
+ }
+
+ BIO_printf(out, ".");
+ (void)BIO_flush(out);
+ /* check key */
+ if (!EC_KEY_check_key(eckey)) {
+ BIO_printf(out, " failed\n");
+ goto builtin_err;
+ }
+ BIO_printf(out, ".");
+ (void)BIO_flush(out);
+ /* create signature */
+ sig_len = ECDSA_size(eckey);
+ signature = OPENSSL_malloc(sig_len);
+ if (signature == NULL) {
+ goto builtin_err;
+ }
+ if (!ECDSA_sign(0, digest, 20, signature, &sig_len, eckey)) {
+ BIO_printf(out, " failed\n");
+ goto builtin_err;
+ }
+ BIO_printf(out, ".");
+ (void)BIO_flush(out);
+ /* verify signature */
+ if (ECDSA_verify(0, digest, 20, signature, sig_len, eckey) != 1) {
+ BIO_printf(out, " failed\n");
+ goto builtin_err;
+ }
+ BIO_printf(out, ".");
+ (void)BIO_flush(out);
+ /* verify signature with the wrong key */
+ if (ECDSA_verify(0, digest, 20, signature, sig_len, wrong_eckey) == 1) {
+ BIO_printf(out, " failed\n");
+ goto builtin_err;
+ }
+ BIO_printf(out, ".");
+ (void)BIO_flush(out);
+ /* wrong digest */
+ if (ECDSA_verify(0, wrong_digest, 20, signature, sig_len, eckey) == 1) {
+ BIO_printf(out, " failed\n");
+ goto builtin_err;
+ }
+ BIO_printf(out, ".");
+ (void)BIO_flush(out);
+ /* wrong length */
+ if (ECDSA_verify(0, digest, 20, signature, sig_len - 1, eckey) == 1) {
+ BIO_printf(out, " failed\n");
+ goto builtin_err;
+ }
+ BIO_printf(out, ".");
+ (void)BIO_flush(out);
+
+ /* Modify a single byte of the signature: to ensure we don't
+ * garble the ASN1 structure, we read the raw signature and
+ * modify a byte in one of the bignums directly. */
+ sig_ptr = signature;
+ ecdsa_sig = d2i_ECDSA_SIG(NULL, &sig_ptr, sig_len);
+ if (ecdsa_sig == NULL) {
+ BIO_printf(out, " failed\n");
+ goto builtin_err;
+ }
+
+ /* Store the two BIGNUMs in raw_buf. */
+ r_len = BN_num_bytes(ecdsa_sig->r);
+ s_len = BN_num_bytes(ecdsa_sig->s);
+ bn_len = (degree + 7) / 8;
+ if (r_len > bn_len || s_len > bn_len) {
+ BIO_printf(out, " failed\n");
+ goto builtin_err;
+ }
+ buf_len = 2 * bn_len;
+ raw_buf = OPENSSL_malloc(buf_len);
+ if (raw_buf == NULL) {
+ goto builtin_err;
+ }
+ /* Pad the bignums with leading zeroes. */
+ memset(raw_buf, 0, buf_len);
+ BN_bn2bin(ecdsa_sig->r, raw_buf + bn_len - r_len);
+ BN_bn2bin(ecdsa_sig->s, raw_buf + buf_len - s_len);
+
+ /* Modify a single byte in the buffer. */
+ offset = raw_buf[10] % buf_len;
+ dirt = raw_buf[11] ? raw_buf[11] : 1;
+ raw_buf[offset] ^= dirt;
+ /* Now read the BIGNUMs back in from raw_buf. */
+ if (BN_bin2bn(raw_buf, bn_len, ecdsa_sig->r) == NULL ||
+ BN_bin2bn(raw_buf + bn_len, bn_len, ecdsa_sig->s) == NULL) {
+ goto builtin_err;
+ }
+
+ sig_ptr2 = signature;
+ sig_len = i2d_ECDSA_SIG(ecdsa_sig, &sig_ptr2);
+ if (ECDSA_verify(0, digest, 20, signature, sig_len, eckey) == 1) {
+ BIO_printf(out, " failed\n");
+ goto builtin_err;
+ }
+ /* Sanity check: undo the modification and verify signature. */
+ raw_buf[offset] ^= dirt;
+ if (BN_bin2bn(raw_buf, bn_len, ecdsa_sig->r) == NULL ||
+ BN_bin2bn(raw_buf + bn_len, bn_len, ecdsa_sig->s) == NULL) {
+ goto builtin_err;
+ }
+
+ sig_ptr2 = signature;
+ sig_len = i2d_ECDSA_SIG(ecdsa_sig, &sig_ptr2);
+ if (ECDSA_verify(0, digest, 20, signature, sig_len, eckey) != 1) {
+ BIO_printf(out, " failed\n");
+ goto builtin_err;
+ }
+ BIO_printf(out, ".");
+ (void)BIO_flush(out);
+
+ BIO_printf(out, " ok\n");
+ /* cleanup */
+ /* clean bogus errors */
+ ERR_clear_error();
+ OPENSSL_free(signature);
+ signature = NULL;
+ EC_KEY_free(eckey);
+ eckey = NULL;
+ EC_KEY_free(wrong_eckey);
+ wrong_eckey = NULL;
+ ECDSA_SIG_free(ecdsa_sig);
+ ecdsa_sig = NULL;
+ OPENSSL_free(raw_buf);
+ raw_buf = NULL;
+ }
+
+ ret = 1;
+builtin_err:
+ if (eckey)
+ EC_KEY_free(eckey);
+ if (wrong_eckey)
+ EC_KEY_free(wrong_eckey);
+ if (ecdsa_sig)
+ ECDSA_SIG_free(ecdsa_sig);
+ if (signature)
+ OPENSSL_free(signature);
+ if (raw_buf)
+ OPENSSL_free(raw_buf);
+
+ return ret;
+}
+
+int main(void) {
+ int ret = 1;
+ BIO *out;
+
+ out = BIO_new_fp(stdout, BIO_NOCLOSE);
+
+ ERR_load_crypto_strings();
+
+ if (!test_builtin(out))
+ goto err;
+
+ ret = 0;
+
+err:
+ if (ret)
+ BIO_printf(out, "\nECDSA test failed\n");
+ else
+ BIO_printf(out, "\nPASS\n");
+ if (ret)
+ BIO_print_errors(out);
+
+ if (out != NULL)
+ BIO_free(out);
+
+ return ret;
+}
diff --git a/crypto/engine/CMakeLists.txt b/crypto/engine/CMakeLists.txt
new file mode 100644
index 0000000..5126e2a
--- /dev/null
+++ b/crypto/engine/CMakeLists.txt
@@ -0,0 +1,9 @@
+include_directories(. .. ../../include)
+
+add_library(
+ engine
+
+ OBJECT
+
+ engine.c
+)
diff --git a/crypto/engine/engine.c b/crypto/engine/engine.c
new file mode 100644
index 0000000..bb0886e
--- /dev/null
+++ b/crypto/engine/engine.c
@@ -0,0 +1,133 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/engine.h>
+
+#include <openssl/dh.h>
+#include <openssl/dsa.h>
+#include <openssl/ec_key.h>
+#include <openssl/mem.h>
+#include <openssl/rsa.h>
+#include <openssl/thread.h>
+
+
+struct engine_st {
+ DH_METHOD *dh_method;
+ DSA_METHOD *dsa_method;
+ RSA_METHOD *rsa_method;
+ ECDSA_METHOD *ecdsa_method;
+};
+
+ENGINE *ENGINE_new() {
+ ENGINE *engine = OPENSSL_malloc(sizeof(ENGINE));
+ if (engine == NULL) {
+ return NULL;
+ }
+
+ memset(engine, 0, sizeof(ENGINE));
+ return engine;
+}
+
+void ENGINE_free(ENGINE *engine) {
+ if (engine->dh_method != NULL) {
+ METHOD_unref(engine->dh_method);
+ }
+
+ OPENSSL_free(engine);
+}
+
+/* set_method takes a pointer to a method and its given size and sets
+ * |*out_member| to point to a copy of it. The copy is |compiled_size| bytes
+ * long and has zero padding if needed. */
+static int set_method(void **out_member, const void *method, size_t method_size,
+ size_t compiled_size) {
+ void *copy = OPENSSL_malloc(compiled_size);
+ if (copy == NULL) {
+ return 0;
+ }
+
+ memset(copy, 0, compiled_size);
+
+ if (method_size > compiled_size) {
+ method_size = compiled_size;
+ }
+ memcpy(copy, method, method_size);
+
+ METHOD_unref(*out_member);
+ *out_member = copy;
+
+ return 1;
+}
+
+int ENGINE_set_DH_method(ENGINE *engine, const DH_METHOD *method,
+ size_t method_size) {
+ return set_method((void **)&engine->dh_method, method, method_size,
+ sizeof(DH_METHOD));
+}
+
+DH_METHOD *ENGINE_get_DH_method(const ENGINE *engine) {
+ return engine->dh_method;
+}
+
+int ENGINE_set_DSA_method(ENGINE *engine, const DSA_METHOD *method,
+ size_t method_size) {
+ return set_method((void **)&engine->dsa_method, method, method_size,
+ sizeof(DSA_METHOD));
+}
+
+DSA_METHOD *ENGINE_get_DSA_method(const ENGINE *engine) {
+ return engine->dsa_method;
+}
+
+int ENGINE_set_RSA_method(ENGINE *engine, const RSA_METHOD *method,
+ size_t method_size) {
+ return set_method((void **)&engine->rsa_method, method, method_size,
+ sizeof(RSA_METHOD));
+}
+
+RSA_METHOD *ENGINE_get_RSA_method(const ENGINE *engine) {
+ return engine->rsa_method;
+}
+
+int ENGINE_set_ECDSA_method(ENGINE *engine, const ECDSA_METHOD *method,
+ size_t method_size) {
+ return set_method((void **)&engine->ecdsa_method, method, method_size,
+ sizeof(ECDSA_METHOD));
+}
+
+ECDSA_METHOD *ENGINE_get_ECDSA_method(const ENGINE *engine) {
+ return engine->ecdsa_method;
+}
+
+void METHOD_ref(void *method_in) {
+ struct openssl_method_common_st *method = method_in;
+
+ if (method->is_static) {
+ return;
+ }
+
+ CRYPTO_add(&method->references, 1, CRYPTO_LOCK_ENGINE);
+}
+
+void METHOD_unref(void *method_in) {
+ struct openssl_method_common_st *method = method_in;
+
+ if (method == NULL || method->is_static) {
+ return;
+ }
+
+ if (CRYPTO_add(&method->references, -1, CRYPTO_LOCK_ENGINE) == 0) {
+ OPENSSL_free(method);
+ }
+}
diff --git a/crypto/engine/engine.h b/crypto/engine/engine.h
new file mode 100644
index 0000000..c97196e
--- /dev/null
+++ b/crypto/engine/engine.h
@@ -0,0 +1,100 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#ifndef OPENSSL_HEADER_ENGINE_H
+#define OPENSSL_HEADER_ENGINE_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* Engines are collections of methods. Methods are tables of function pointers,
+ * defined for certain algorithms, that allow operations on those algorithms to
+ * be overridden via a callback. This can be used, for example, to implement an
+ * RSA* that forwards operations to a hardware module.
+ *
+ * Methods are reference counted but |ENGINE|s are not. When creating a method,
+ * you should zero the whole structure and fill in the function pointers that
+ * you wish before setting it on an |ENGINE|. Any functions pointers that
+ * are NULL indicate that the default behaviour should be used. */
+
+
+/* Allocation and destruction. */
+
+/* ENGINE_new returns an empty ENGINE that uses the default method for all
+ * algorithms. */
+ENGINE *ENGINE_new();
+
+/* ENGINE_free decrements the reference counts for all methods linked from
+ * |engine| and frees |engine| itself. */
+void ENGINE_free(ENGINE *engine);
+
+
+/* Method accessors.
+ *
+ * Method accessors take a method pointer and the size of the structure. The
+ * size allows for ABI compatibility in the case that the method structure is
+ * extended with extra elements at the end. Methods are always copied by the
+ * set functions.
+ *
+ * Set functions return one on success and zero on allocation failure. */
+
+int ENGINE_set_DH_method(ENGINE *engine, const DH_METHOD *method,
+ size_t method_size);
+DH_METHOD *ENGINE_get_DH_method(const ENGINE *engine);
+
+int ENGINE_set_DSA_method(ENGINE *engine, const DSA_METHOD *method,
+ size_t method_size);
+DSA_METHOD *ENGINE_get_DSA_method(const ENGINE *engine);
+
+int ENGINE_set_RSA_method(ENGINE *engine, const RSA_METHOD *method,
+ size_t method_size);
+RSA_METHOD *ENGINE_get_RSA_method(const ENGINE *engine);
+
+int ENGINE_set_ECDSA_method(ENGINE *engine, const ECDSA_METHOD *method,
+ size_t method_size);
+ECDSA_METHOD *ENGINE_get_ECDSA_method(const ENGINE *engine);
+
+
+/* Generic method functions.
+ *
+ * These functions take a void* type but actually operate on all method
+ * structures. */
+
+/* METHOD_ref increments the reference count of |method|. */
+void METHOD_ref(void *method);
+
+/* METHOD_unref decrements the reference count of |method| and frees it if the
+ * reference count drops to zero. */
+void METHOD_unref(void *method);
+
+
+/* Private functions. */
+
+/* openssl_method_common_st contains the common part of all method structures.
+ * This must be the first member of all method structures. */
+struct openssl_method_common_st {
+ int references;
+ char is_static;
+};
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_ENGINE_H */
diff --git a/crypto/err/CMakeLists.txt b/crypto/err/CMakeLists.txt
new file mode 100644
index 0000000..1ac4951
--- /dev/null
+++ b/crypto/err/CMakeLists.txt
@@ -0,0 +1,18 @@
+include_directories(. .. ../../include)
+
+add_library(
+ err
+
+ OBJECT
+
+ err.c
+ err_impl.c
+)
+
+add_executable(
+ err_test
+
+ err_test.c
+)
+
+target_link_libraries(err_test crypto)
diff --git a/crypto/err/err.c b/crypto/err/err.c
new file mode 100644
index 0000000..b78ee6b
--- /dev/null
+++ b/crypto/err/err.c
@@ -0,0 +1,737 @@
+/* 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.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2006 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). */
+
+#include <openssl/err.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include <openssl/lhash.h>
+#include <openssl/mem.h>
+#include <openssl/thread.h>
+
+
+/* err_fns contains a pointer to the current error implementation. */
+static const struct ERR_FNS_st *err_fns = NULL;
+extern const struct ERR_FNS_st openssl_err_default_impl;
+
+#define ERRFN(a) err_fns->a
+
+/* err_fns_check is an internal function that checks whether "err_fns" is set
+ * and if not, sets it to the default. */
+static void err_fns_check(void) {
+ /* In practice, this is not a race problem because loading the error strings
+ * at init time will cause this pointer to be set before the process goes
+ * multithreaded. */
+ if (err_fns) {
+ return;
+ }
+
+ CRYPTO_w_lock(CRYPTO_LOCK_ERR);
+ if (!err_fns) {
+ err_fns = &openssl_err_default_impl;
+ }
+ CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
+}
+
+/* err_clear_data frees the optional |data| member of the given error. */
+static void err_clear_data(struct err_error_st *error) {
+ if (error->data != NULL && (error->flags & ERR_FLAG_MALLOCED) != 0) {
+ OPENSSL_free(error->data);
+ }
+ error->data = NULL;
+ error->flags &= ~ERR_FLAG_MALLOCED;
+}
+
+/* err_clear clears the given queued error. */
+static void err_clear(struct err_error_st *error) {
+ err_clear_data(error);
+ memset(error, 0, sizeof(struct err_error_st));
+}
+
+/* err_get_state gets the ERR_STATE object for the current thread. */
+static ERR_STATE *err_get_state(void) {
+ err_fns_check();
+ return ERRFN(get_state)();
+}
+
+static uint32_t get_error_values(int inc, int top, const char **file, int *line,
+ char **data, int *flags) {
+ unsigned i = 0;
+ ERR_STATE *state;
+ struct err_error_st *error;
+ uint32_t ret;
+
+ state = err_get_state();
+
+ if (state->bottom == state->top) {
+ return 0;
+ }
+
+ if (top) {
+ /* last error */
+ i = state->top;
+ } else {
+ i = (state->bottom + 1) % ERR_NUM_ERRORS;
+ }
+
+ error = &state->errors[i];
+ ret = error->packed;
+
+ if (file != NULL && line != NULL) {
+ if (error->file == NULL) {
+ *file = "NA";
+ *line = 0;
+ } else {
+ *file = error->file;
+ *line = error->line;
+ }
+ }
+
+ if (data != NULL) {
+ if (error->data == NULL) {
+ *data = "";
+ if (flags != NULL) {
+ *flags = 0;
+ }
+ } else {
+ *data = error->data;
+ if (flags != NULL) {
+ *flags = error->flags & ERR_FLAG_PUBLIC_MASK;
+ }
+ error->data = NULL;
+ error->flags = 0;
+ }
+ }
+
+ if (inc) {
+ assert(!top);
+ err_clear(error);
+ state->bottom = i;
+ }
+
+ return ret;
+}
+
+uint32_t ERR_get_error(void) {
+ return get_error_values(1, 0, 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);
+}
+
+uint32_t ERR_get_error_line_data(const char **file, int *line,
+ char **data, int *flags) {
+ return get_error_values(1, 0, file, line, data, flags);
+}
+
+uint32_t ERR_peek_error(void) {
+ return get_error_values(0, 0, 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);
+}
+
+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, (char **) data, flags);
+}
+
+uint32_t ERR_peek_last_error(void) {
+ return get_error_values(0, 1, 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);
+}
+
+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, (char **) data, flags);
+}
+
+void ERR_clear_error(void) {
+ ERR_STATE *const state = err_get_state();
+ unsigned i;
+
+ for (i = 0; i < ERR_NUM_ERRORS; i++) {
+ err_clear(&state->errors[i]);
+ }
+
+ state->top = state->bottom = 0;
+}
+
+void ERR_clear_system_error(void) {
+ 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;
+
+ 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) {
+ BIO_snprintf(lib_buf, sizeof(lib_buf), "lib(%u)", lib);
+ lib_str = lib_buf;
+ }
+
+ if (func_str == NULL) {
+ BIO_snprintf(func_buf, sizeof(func_buf), "func(%u)", func);
+ func_str = func_buf;
+ }
+
+ if (reason_str == NULL) {
+ BIO_snprintf(reason_buf, sizeof(reason_buf), "reason(%u)", reason);
+ reason_str = reason_buf;
+ }
+
+ BIO_snprintf(buf, len, "error:%08" PRIx32 ":%s:%s:%s",
+ packed_error, lib_str, func_str, reason_str);
+
+ if (strlen(buf) == len - 1) {
+ /* output may be truncated; make sure we always have 5 colon-separated
+ * fields, i.e. 4 colons. */
+ static const unsigned num_colons = 4;
+ unsigned i;
+ char *s = buf;
+
+ if (len <= num_colons) {
+ /* In this situation it's not possible to ensure that the correct number
+ * of colons are included in the output. */
+ return;
+ }
+
+ for (i = 0; i < num_colons; i++) {
+ char *colon = strchr(s, ':');
+ char *last_pos = &buf[len - 1] - num_colons + i;
+
+ if (colon == NULL || colon > last_pos) {
+ /* set colon |i| at last possible position (buf[len-1] is the
+ * terminating 0). If we're setting this colon, then all whole of the
+ * rest of the string must be colons in order to have the correct
+ * number. */
+ memset(last_pos, ':', num_colons - i);
+ break;
+ }
+
+ s = colon + 1;
+ }
+ }
+}
+
+/* err_component_error_string returns the error string associated with
+ * |packed_error|, which must be of a special form matching the keys inserted
+ * into the error hash table. */
+static const char *err_component_error_string(uint32_t packed_error) {
+ ERR_STRING_DATA *p;
+
+ err_fns_check();
+ p = ERRFN(get_item)(packed_error);
+
+ if (p == NULL) {
+ return NULL;
+ }
+ return p->string;
+}
+
+const char *ERR_lib_error_string(uint32_t packed_error) {
+ return err_component_error_string(ERR_PACK(ERR_GET_LIB(packed_error), 0, 0));
+}
+
+const char *ERR_func_error_string(uint32_t packed_error) {
+ return err_component_error_string(
+ ERR_PACK(ERR_GET_LIB(packed_error), ERR_GET_FUNC(packed_error), 0));
+}
+
+const char *ERR_reason_error_string(uint32_t packed_error) {
+ const char *reason_str = err_component_error_string(
+ ERR_PACK(ERR_GET_LIB(packed_error), 0, ERR_GET_REASON(packed_error)));
+
+ if (reason_str != NULL) {
+ return reason_str;
+ }
+
+ return err_component_error_string(
+ ERR_PACK(0, 0, ERR_GET_REASON(packed_error)));
+}
+
+void ERR_print_errors_cb(ERR_print_errors_callback_t callback, void *ctx) {
+ CRYPTO_THREADID current_thread;
+ char buf[ERR_ERROR_STRING_BUF_LEN];
+ char buf2[1024];
+ unsigned long thread_hash;
+ const char *file;
+ char *data;
+ int line, flags;
+ uint32_t packed_error;
+
+ CRYPTO_THREADID_current(¤t_thread);
+ thread_hash = CRYPTO_THREADID_hash(¤t_thread);
+
+ for (;;) {
+ 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));
+ 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) {
+ break;
+ }
+ if (flags & ERR_FLAG_MALLOCED) {
+ OPENSSL_free(data);
+ }
+ }
+}
+
+/* err_set_error_data sets the data on the most recent error. The |flags|
+ * argument is a combination of the |ERR_FLAG_*| values. */
+static void err_set_error_data(char *data, int flags) {
+ ERR_STATE *const state = err_get_state();
+ struct err_error_st *error;
+
+ if (state->top == state->bottom) {
+ return;
+ }
+
+ error = &state->errors[state->top];
+
+ err_clear_data(error);
+ error->data = data;
+ error->flags = flags;
+}
+
+void ERR_put_error(int library, int func, int reason, const char *file,
+ unsigned line) {
+ ERR_STATE *const state = err_get_state();
+ struct err_error_st *error;
+
+ if (library == ERR_LIB_SYS && reason == 0) {
+#if defined(WIN32)
+ reason = GetLastError();
+#else
+ reason = errno;
+#endif
+ }
+
+ state->top = (state->top + 1) % ERR_NUM_ERRORS;
+ if (state->top == state->bottom) {
+ state->bottom = (state->bottom + 1) % ERR_NUM_ERRORS;
+ }
+
+ error = &state->errors[state->top];
+ err_clear(error);
+ error->file = file;
+ error->line = line;
+ error->packed = ERR_PACK(library, func, reason);
+}
+
+/* ERR_add_error_data_vdata takes a variable number of const char* pointers,
+ * concatenates them and sets the result as the data on the most recent
+ * error. */
+static void err_add_error_vdata(unsigned num, va_list args) {
+ size_t alloced, new_len, len = 0, substr_len;
+ char *buf;
+ const char *substr;
+ unsigned i;
+
+ alloced = 80;
+ buf = OPENSSL_malloc(alloced + 1);
+ if (buf == NULL) {
+ return;
+ }
+
+ for (i = 0; i < num; i++) {
+ substr = va_arg(args, const char *);
+ if (substr == NULL) {
+ continue;
+ }
+
+ substr_len = strlen(substr);
+ new_len = len + substr_len;
+ if (new_len > alloced) {
+ char *new_buf;
+
+ if (alloced + 20 + 1 < alloced) {
+ /* overflow. */
+ OPENSSL_free(buf);
+ return;
+ }
+
+ alloced = new_len + 20;
+ new_buf = OPENSSL_realloc(buf, alloced + 1);
+ if (new_buf == NULL) {
+ OPENSSL_free(buf);
+ return;
+ }
+ buf = new_buf;
+ }
+
+ memcpy(buf + len, substr, substr_len);
+ len = new_len;
+ }
+
+ buf[len] = 0;
+ err_set_error_data(buf, ERR_FLAG_MALLOCED | ERR_FLAG_STRING);
+}
+
+void ERR_add_error_data(unsigned count, ...) {
+ va_list args;
+ va_start(args, count);
+ err_add_error_vdata(count, args);
+ va_end(args);
+}
+
+void ERR_add_error_dataf(const char *format, ...) {
+ va_list ap;
+ char *buf;
+ static const unsigned buf_len = 256;
+
+ /* A fixed-size buffer is used because va_copy (which would be needed in
+ * order to call vsnprintf twice and measure the buffer) wasn't defined until
+ * C99. */
+ buf = OPENSSL_malloc(buf_len + 1);
+ if (buf == NULL) {
+ return;
+ }
+
+ va_start(ap, format);
+ BIO_vsnprintf(buf, buf_len, format, ap);
+ buf[buf_len] = 0;
+ va_end(ap);
+
+ err_set_error_data(buf, ERR_FLAG_MALLOCED | ERR_FLAG_STRING);
+}
+
+int ERR_set_mark(void) {
+ ERR_STATE *const state = err_get_state();
+
+ if (state->bottom == state->top) {
+ return 0;
+ }
+ state->errors[state->top].flags |= ERR_FLAG_MARK;
+ return 1;
+}
+
+int ERR_pop_to_mark(void) {
+ ERR_STATE *const state = err_get_state();
+ struct err_error_st *error;
+
+ while (state->bottom != state->top) {
+ error = &state->errors[state->top];
+
+ if ((error->flags & ERR_FLAG_MARK) != 0) {
+ break;
+ }
+
+ err_clear(error);
+ if (state->top == 0) {
+ state->top = ERR_NUM_ERRORS - 1;
+ } else {
+ state->top--;
+ }
+ }
+
+ if (state->bottom == state->top) {
+ return 0;
+ }
+
+ error->flags &= ~ERR_FLAG_MARK;
+ return 1;
+}
+
+static const char *const kLibraryNames[ERR_NUM_LIBS] = {
+ "invalid library (0)",
+ "unknown library", /* ERR_LIB_NONE */
+ "system library", /* ERR_LIB_SYS */
+ "bignum routines", /* ERR_LIB_BN */
+ "RSA routines", /* ERR_LIB_RSA */
+ "Diffie-Hellman routines", /* ERR_LIB_DH */
+ "public key routines", /* ERR_LIB_EVP */
+ "memory buffer routines", /* ERR_LIB_BUF */
+ "object identifier routines", /* ERR_LIB_OBJ */
+ "PEM routines", /* ERR_LIB_PEM */
+ "DSA routines", /* ERR_LIB_DSA */
+ "X.509 certificate routines", /* ERR_LIB_X509 */
+ "ASN.1 encoding routines", /* ERR_LIB_ASN1 */
+ "configuration file routines", /* ERR_LIB_CONF */
+ "common libcrypto routines", /* ERR_LIB_CRYPTO */
+ "elliptic curve routines", /* ERR_LIB_EC */
+ "SSL routines", /* ERR_LIB_SSL */
+ "BIO routines", /* ERR_LIB_BIO */
+ "PKCS7 routines", /* ERR_LIB_PKCS7 */
+ "PKCS8 routines", /* ERR_LIB_PKCS8 */
+ "X509 V3 routines", /* ERR_LIB_X509V3 */
+ "PKCS12 routines", /* ERR_LIB_PKCS12 */
+ "random number generator", /* ERR_LIB_RAND */
+ "ENGINE routines", /* ERR_LIB_ENGINE */
+ "OCSP routines", /* ERR_LIB_OCSP */
+ "UI routines", /* ERR_LIB_UI */
+ "COMP routines", /* ERR_LIB_COMP */
+ "ECDSA routines", /* ERR_LIB_ECDSA */
+ "ECDH routines", /* ERR_LIB_ECDH */
+ "HMAC routines", /* ERR_LIB_HMAC */
+ "Digest functions", /* ERR_LIB_DIGEST */
+ "Cipher functions", /* ERR_LIB_CIPHER */
+ "User defined functions", /* ERR_LIB_USER */
+};
+
+#define NUM_SYS_ERRNOS 127
+
+/* kStaticErrors provides storage for ERR_STRING_DATA values that are created
+ * at init time because we assume that ERR_STRING_DATA structures aren't
+ * allocated on the heap. */
+static ERR_STRING_DATA kStaticErrors[ERR_NUM_LIBS * 2 + NUM_SYS_ERRNOS];
+
+static ERR_STRING_DATA kGlobalErrors[] = {
+ {ERR_R_MALLOC_FAILURE, "malloc failure"},
+ {ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED, "function should not be called"},
+ {ERR_R_PASSED_NULL_PARAMETER, "passed a null parameter"},
+ {ERR_R_INTERNAL_ERROR, "internal error"},
+
+ {ERR_PACK(ERR_LIB_SYS, SYS_F_fopen, 0), "fopen"},
+ {ERR_PACK(ERR_LIB_SYS, SYS_F_fclose, 0), "fclose"},
+ {ERR_PACK(ERR_LIB_SYS, SYS_F_fread, 0), "fread"},
+ {ERR_PACK(ERR_LIB_SYS, SYS_F_fwrite, 0), "fwrite"},
+ {ERR_PACK(ERR_LIB_SYS, SYS_F_socket, 0), "socket"},
+ {ERR_PACK(ERR_LIB_SYS, SYS_F_setsockopt, 0), "setsockopt"},
+ {ERR_PACK(ERR_LIB_SYS, SYS_F_connect, 0), "connect"},
+ {ERR_PACK(ERR_LIB_SYS, SYS_F_getaddrinfo, 0), "getaddrinfo"},
+
+ {0, NULL},
+};
+
+
+extern const ERR_STRING_DATA ASN1_error_string_data[];
+extern const ERR_STRING_DATA BIO_error_string_data[];
+extern const ERR_STRING_DATA BN_error_string_data[];
+extern const ERR_STRING_DATA BUF_error_string_data[];
+extern const ERR_STRING_DATA CIPHER_error_string_data[];
+extern const ERR_STRING_DATA CONF_error_string_data[];
+extern const ERR_STRING_DATA CRYPTO_error_string_data[];
+extern const ERR_STRING_DATA DH_error_string_data[];
+extern const ERR_STRING_DATA DIGEST_error_string_data[];
+extern const ERR_STRING_DATA DSA_error_string_data[];
+extern const ERR_STRING_DATA ECDH_error_string_data[];
+extern const ERR_STRING_DATA ECDSA_error_string_data[];
+extern const ERR_STRING_DATA EC_error_string_data[];
+extern const ERR_STRING_DATA EVP_error_string_data[];
+extern const ERR_STRING_DATA OBJ_error_string_data[];
+extern const ERR_STRING_DATA PEM_error_string_data[];
+extern const ERR_STRING_DATA RSA_error_string_data[];
+extern const ERR_STRING_DATA X509V3_error_string_data[];
+extern const ERR_STRING_DATA X509_error_string_data[];
+
+static void err_load_strings(void) {
+ unsigned i, j = 0;
+
+ err_fns_check();
+
+ /* This loop loads strings for the libraries for the ERR_R_*_LIB
+ * reasons. */
+ for (i = ERR_LIB_NONE; i < ERR_NUM_LIBS; i++) {
+ ERR_STRING_DATA *data = &kStaticErrors[j++];
+ data->string = kLibraryNames[i];
+ data->error = ERR_PACK(i, 0, 0);
+ ERRFN(set_item)(data);
+
+ data = &kStaticErrors[j++];
+ data->string = kLibraryNames[i];
+ data->error = ERR_PACK(0, 0, i);
+ ERRFN(set_item)(data);
+ }
+
+ for (i = 1; i < 1 + NUM_SYS_ERRNOS; i++) {
+ /* The "SYS" library sets errno values as the reason for its errors.
+ * Thus we load the first |NUM_SYS_ERRNOS| errno strings as the
+ * reason strings for that library. */
+
+ ERR_STRING_DATA *data = &kStaticErrors[j++];
+ data->string = strerror(i);
+ data->error = ERR_PACK(ERR_LIB_SYS, 0, i);
+ ERRFN(set_item)(data);
+ }
+
+ ERR_load_strings(kGlobalErrors);
+
+ ERR_load_strings(ASN1_error_string_data);
+ ERR_load_strings(BIO_error_string_data);
+ ERR_load_strings(BN_error_string_data);
+ ERR_load_strings(BUF_error_string_data);
+ ERR_load_strings(CIPHER_error_string_data);
+ ERR_load_strings(CONF_error_string_data);
+ ERR_load_strings(CRYPTO_error_string_data);
+ ERR_load_strings(DH_error_string_data);
+ ERR_load_strings(DIGEST_error_string_data);
+ ERR_load_strings(DSA_error_string_data);
+ ERR_load_strings(ECDH_error_string_data);
+ ERR_load_strings(ECDSA_error_string_data);
+ ERR_load_strings(EC_error_string_data);
+ ERR_load_strings(EVP_error_string_data);
+ ERR_load_strings(OBJ_error_string_data);
+ ERR_load_strings(PEM_error_string_data);
+ ERR_load_strings(RSA_error_string_data);
+ ERR_load_strings(X509V3_error_string_data);
+ ERR_load_strings(X509_error_string_data);
+}
+
+void ERR_load_strings(const ERR_STRING_DATA *str) {
+ err_fns_check();
+
+ while (str->error) {
+ ERRFN(set_item)(str);
+ str++;
+ }
+}
+
+void ERR_load_crypto_strings() { err_load_strings(); }
+
+void ERR_free_strings() {
+ err_fns_check();
+ ERRFN(shutdown)();
+}
+
+void ERR_load_BIO_strings() {}
diff --git a/crypto/err/err.h b/crypto/err/err.h
new file mode 100644
index 0000000..411bc9b
--- /dev/null
+++ b/crypto/err/err.h
@@ -0,0 +1,496 @@
+/* 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.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2006 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_ERR_H
+#define OPENSSL_HEADER_ERR_H
+
+#include <openssl/base.h>
+#include <openssl/thread.h>
+#include <openssl/lhash.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* Error queue handling functions.
+ *
+ * Errors in OpenSSL are generally signalled by the return value of a function.
+ * When a function fails it may add an entry to a per-thread error queue,
+ * which is managed by the functions in this header.
+ *
+ * Each error contains:
+ * 1) The library (i.e. ec, pem, rsa) which created it.
+ * 2) A function identifier and reason code.
+ * 3) The file and line number of the call that added the error.
+ * 4) A pointer to some error specific data, which may be NULL.
+ *
+ * The library identifier, function identifier and reason code are packed in a
+ * uint32_t and there exist various functions for unpacking it.
+ *
+ * The typical behaviour is that an error will occur deep in a call queue and
+ * that code will push an error onto the error queue. As the error queue
+ * unwinds, other functions will push their own errors. Thus, the "least
+ * recent" error is the most specific and the other errors will provide a
+ * backtrace of sorts. */
+
+
+/* Startup and shutdown. */
+
+/* ERR_load_crypto_strings initialises the error string hash with builtin
+ * values. If this is not called then the string forms of errors produced by
+ * the functions below will contain numeric identifiers rather than
+ * human-readable strings. */
+void ERR_load_crypto_strings();
+
+/* ERR_free_strings frees any internal error values that have been loaded. This
+ * should only be called at process shutdown. */
+void ERR_free_strings();
+
+
+/* Reading and formatting errors. */
+
+/* ERR_get_error gets the packed error code for the least recent error and
+ * removes that error from the queue. If there are no errors in the queue then
+ * it returns zero. */
+uint32_t ERR_get_error(void);
+
+/* ERR_get_error_line acts like |ERR_get_error|, except that the file and line
+ * number of the call that added the error are also returned. */
+uint32_t ERR_get_error_line(const char **file, int *line);
+
+/* ERR_get_error_line_data acts like |ERR_get_error_line|, but also returns the
+ * error-specific data pointer and flags. The flags are a bitwise-OR of
+ * |ERR_FLAG_*| values. */
+uint32_t ERR_get_error_line_data(const char **file, int *line,
+ char **data, int *flags);
+
+/* The "peek" functions act like the |ERR_get_error| functions, above, but they
+ * do not remove the error from the queue. */
+uint32_t ERR_peek_error(void);
+uint32_t ERR_peek_error_line(const char **file, int *line);
+uint32_t ERR_peek_error_line_data(const char **file, int *line,
+ const char **data, int *flags);
+
+/* The "peek last" functions act like the "peek" functions, above, except that
+ * they return the most recent error. */
+uint32_t ERR_peek_last_error(void);
+uint32_t ERR_peek_last_error_line(const char **file, int *line);
+uint32_t ERR_peek_last_error_line_data(const char **file, int *line,
+ const char **data, int *flags);
+
+/* ERR_error_string generates a human-readable string representing
+ * |packed_error|, places it at |buf| (which must be at least
+ * ERR_ERROR_STRING_BUF_LEN bytes long) and returns |buf|. If |buf| is NULL,
+ * the error string is placed in a static buffer which is returned. (The static
+ * buffer may be overridden by concurrent calls in other threads so this form
+ * is deprecated.)
+ *
+ * The string will have the following format:
+ *
+ * error:[error code]:[library name]:[function name]:[reason string]
+ *
+ * error code is an 8 digit hexadecimal number; library name, function name
+ * and reason string are ASCII text.
+ *
+ * TODO(fork): remove in favour of |ERR_error_string_n|. */
+char *ERR_error_string(uint32_t packed_error, char *buf);
+#define ERR_ERROR_STRING_BUF_LEN 256
+
+/* ERR_error_string_n is a variant of |ERR_error_string| that writes at most
+ * len characters (including the terminating NUL) and truncates the string if
+ * necessary. If |len| is greater than zero then |buf| is always NUL
+ * terminated. */
+void ERR_error_string_n(uint32_t packed_error, char *buf, size_t len);
+
+/* ERR_lib_error_string returns a string representation of the library that
+ * generated |packed_error|. */
+const char *ERR_lib_error_string(uint32_t packed_error);
+
+/* ERR_func_error_string returns a string representation of the function that
+ * generated |packed_error|. */
+const char *ERR_func_error_string(uint32_t packed_error);
+
+/* ERR_reason_error_string returns a string representation of the reason for
+ * |packed_error|. */
+const char *ERR_reason_error_string(uint32_t packed_error);
+
+/* ERR_print_errors_callback_t is the type of a function used by
+ * |ERR_print_errors_cb|. It takes a pointer to a human readable string (and
+ * its length) that describes an entry in the error queue. The |ctx| argument
+ * is an opaque pointer given to |ERR_print_errors_cb|.
+ *
+ * It should return one on success or zero on error, which will stop the
+ * iteration over the error queue. */
+typedef int (*ERR_print_errors_callback_t)(const char *str, size_t len,
+ void *ctx);
+
+/* ERR_print_errors_cb calls |callback| with a string representation of each
+ * error in the current thread's error queue, from the least recent to the most
+ * recent error.
+ *
+ * The string will have the following format (which differs from
+ * |ERR_error_string|):
+ *
+ * [thread id]:error:[error code]:[library name]:[function name]:
+ * [reason string]:[file]:[line number]:[optional string data]
+ *
+ * (All in one line.)
+ *
+ * The callback can return one to continue the iteration or zero to stop it.
+ * The |ctx| argument is an opaque value that is passed through to the
+ * callback. */
+void ERR_print_errors_cb(ERR_print_errors_callback_t callback, void *ctx);
+
+
+/* Clearing errors. */
+
+/* ERR_clear_error clears the error queue for the current thread. */
+void ERR_clear_error(void);
+
+
+/* Private functions. */
+
+/* ERR_clear_system_error clears the system's error value (i.e. errno). */
+void ERR_clear_system_error(void);
+
+/* OPENSSL_PUT_ERROR is used by OpenSSL code to add an error to the error
+ * queue. */
+#define OPENSSL_PUT_ERROR(library, func, reason) \
+ ERR_put_error(ERR_LIB_##library, library##_F_##func, reason, __FILE__, \
+ __LINE__)
+
+/* OPENSSL_PUT_SYSTEM_ERROR is used by OpenSSL code to add an error from the
+ * operating system to the error queue. */
+/* TODO(fork): include errno. */
+#define OPENSSL_PUT_SYSTEM_ERROR(func) \
+ ERR_put_error(ERR_LIB_SYS, SYS_F_##func, 0, __FILE__, __LINE__);
+
+/* ERR_put_error adds an error to the error queue, dropping the least recent
+ * error if neccessary for space reasons. */
+void ERR_put_error(int library, int func, int reason, const char *file,
+ unsigned line);
+
+/* ERR_add_error_data takes a variable number (|count|) of const char*
+ * pointers, concatenates them and sets the result as the data on the most
+ * recent error. */
+void ERR_add_error_data(unsigned count, ...);
+
+/* ERR_add_error_dataf takes a printf-style format and arguments, and sets the
+ * result as the data on the most recent error. */
+void ERR_add_error_dataf(const char *format, ...);
+
+/* ERR_set_mark "marks" the most recent error for use with |ERR_pop_to_mark|.
+ * It returns one if an error was marked and zero if there are no errors. */
+int ERR_set_mark(void);
+
+/* ERR_pop_to_mark removes errors from the most recent to the least recent
+ * until (and not including) a "marked" error. It returns zero if no marked
+ * error was found (and thus all errors were removed) and one otherwise. Errors
+ * are marked using |ERR_set_mark|. */
+int ERR_pop_to_mark(void);
+
+struct err_error_st {
+ /* file contains the filename where the error occured. */
+ const char *file;
+ /* data contains optional data. It must be freed with |OPENSSL_free| if
+ * |flags&ERR_FLAG_MALLOCED|. */
+ char *data;
+ /* packed contains the error library, function and reason, as packed by
+ * ERR_PACK. */
+ uint32_t packed;
+ /* line contains the line number where the error occured. */
+ uint16_t line;
+ /* flags contains a bitwise-OR of ERR_FLAG_* values. */
+ uint8_t flags;
+};
+
+/* ERR_FLAG_MALLOCED means the the |data| member must be freed when no longer
+ * needed. */
+#define ERR_FLAG_MALLOCED 1
+/* ERR_FLAG_STRING means that the |data| member is a NUL-terminated string that
+ * can be printed. */
+#define ERR_FLAG_STRING 2
+
+/* ERR_FLAG_PUBLIC_MASK is applied to the flags field before it is returned
+ * from functions like |ERR_get_error_line_data|. */
+#define ERR_FLAG_PUBLIC_MASK 0xf
+
+/* The following flag values are internal and are masked when flags are
+ * returned from functions like |ERR_get_error_line_data|. */
+
+/* ERR_FLAG_MARK is used to indicate a reversion point in the queue. See
+ * |ERR_pop_to_mark|. */
+#define ERR_FLAG_MARK 16
+
+/* ERR_NUM_ERRORS is the limit of the number of errors in the queue. */
+#define ERR_NUM_ERRORS 16
+
+/* ERR_STATE contains the per-thread, error queue. */
+typedef struct err_state_st {
+ /* tid is the identifier of the thread that owns this queue. */
+ CRYPTO_THREADID tid;
+
+ /* errors contains the ERR_NUM_ERRORS most recent errors, organised as a ring
+ * buffer. */
+ struct err_error_st errors[ERR_NUM_ERRORS];
+ /* top contains the index one past the most recent error. If |top| equals
+ * |bottom| then the queue is empty. */
+ unsigned top;
+ /* bottom contains the index of the last error in the queue. */
+ unsigned bottom;
+} ERR_STATE;
+
+enum {
+ ERR_LIB_NONE = 1,
+ ERR_LIB_SYS,
+ ERR_LIB_BN,
+ ERR_LIB_RSA,
+ ERR_LIB_DH,
+ ERR_LIB_EVP,
+ ERR_LIB_BUF,
+ ERR_LIB_OBJ,
+ ERR_LIB_PEM,
+ ERR_LIB_DSA,
+ ERR_LIB_X509,
+ ERR_LIB_ASN1,
+ ERR_LIB_CONF,
+ ERR_LIB_CRYPTO,
+ ERR_LIB_EC,
+ ERR_LIB_SSL,
+ ERR_LIB_BIO,
+ ERR_LIB_PKCS7,
+ ERR_LIB_PKCS8,
+ ERR_LIB_X509V3,
+ ERR_LIB_PKCS12,
+ ERR_LIB_RAND,
+ ERR_LIB_ENGINE,
+ ERR_LIB_OCSP,
+ ERR_LIB_UI,
+ ERR_LIB_COMP,
+ ERR_LIB_ECDSA,
+ ERR_LIB_ECDH,
+ ERR_LIB_HMAC,
+ ERR_LIB_DIGEST,
+ ERR_LIB_CIPHER,
+ ERR_LIB_USER,
+ ERR_NUM_LIBS
+};
+
+#define ERR_R_SYS_LIB ERR_LIB_SYS
+#define ERR_R_BN_LIB ERR_LIB_BN
+#define ERR_R_RSA_LIB ERR_LIB_RSA
+#define ERR_R_DH_LIB ERR_LIB_DH
+#define ERR_R_EVP_LIB ERR_LIB_EVP
+#define ERR_R_BUF_LIB ERR_LIB_BUF
+#define ERR_R_OBJ_LIB ERR_LIB_OBJ
+#define ERR_R_PEM_LIB ERR_LIB_PEM
+#define ERR_R_DSA_LIB ERR_LIB_DSA
+#define ERR_R_X509_LIB ERR_LIB_X509
+#define ERR_R_ASN1_LIB ERR_LIB_ASN1
+#define ERR_R_CONF_LIB ERR_LIB_CONF
+#define ERR_R_CRYPTO_LIB ERR_LIB_CRYPTO
+#define ERR_R_EC_LIB ERR_LIB_EC
+#define ERR_R_SSL_LIB ERR_LIB_SSL
+#define ERR_R_BIO_LIB ERR_LIB_BIO
+#define ERR_R_PKCS7_LIB ERR_LIB_PKCS7
+#define ERR_R_PKCS8_LIB ERR_LIB_PKCS8
+#define ERR_R_X509V3_LIB ERR_LIB_X509V3
+#define ERR_R_PKCS12_LIB ERR_LIB_PKCS12
+#define ERR_R_RAND_LIB ERR_LIB_RAND
+#define ERR_R_DSO_LIB ERR_LIB_DSO
+#define ERR_R_ENGINE_LIB ERR_LIB_ENGINE
+#define ERR_R_OCSP_LIB ERR_LIB_OCSP
+#define ERR_R_UI_LIB ERR_LIB_UI
+#define ERR_R_COMP_LIB ERR_LIB_COMP
+#define ERR_R_ECDSA_LIB ERR_LIB_ECDSA
+#define ERR_R_ECDH_LIB ERR_LIB_ECDH
+#define ERR_R_STORE_LIB ERR_LIB_STORE
+#define ERR_R_FIPS_LIB ERR_LIB_FIPS
+#define ERR_R_CMS_LIB ERR_LIB_CMS
+#define ERR_R_TS_LIB ERR_LIB_TS
+#define ERR_R_HMAC_LIB ERR_LIB_HMAC
+#define ERR_R_JPAKE_LIB ERR_LIB_JPAKE
+#define ERR_R_USER_LIB ERR_LIB_USER
+#define ERR_R_DIGEST_LIB ERR_LIB_DIGEST
+#define ERR_R_CIPHER_LIB ERR_LIB_CIPHER
+
+/* Global reasons. */
+#define ERR_R_FATAL 64
+#define ERR_R_MALLOC_FAILURE (1 | ERR_R_FATAL)
+#define ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED (2 | ERR_R_FATAL)
+#define ERR_R_PASSED_NULL_PARAMETER (3 | ERR_R_FATAL)
+#define ERR_R_INTERNAL_ERROR (4 | ERR_R_FATAL)
+
+/* System error functions */
+#define SYS_F_fopen 100
+#define SYS_F_fclose 101
+#define SYS_F_fread 102
+#define SYS_F_fwrite 103
+#define SYS_F_socket 104
+#define SYS_F_setsockopt 105
+#define SYS_F_connect 106
+#define SYS_F_getaddrinfo 107
+
+#define ERR_PACK(lib, func, reason) \
+ (((((uint32_t)lib) & 0xff) << 24) | ((((uint32_t)func) & 0xfff) << 12) | \
+ ((((uint32_t)reason) & 0xfff)))
+
+#define ERR_GET_LIB(packed_error) (((packed_error) >> 24) & 0xff)
+#define ERR_GET_FUNC(packed_error) (((packed_error) >> 12) & 0xfff)
+#define ERR_GET_REASON(packed_error) ((packed_error) & 0xfff)
+
+/* ERR_STRING_DATA is the type of an lhash node that contains a mapping from a
+ * library, function or reason code to a string representation of it. */
+typedef struct err_string_data_st {
+ uint32_t error;
+ const char *string;
+} ERR_STRING_DATA;
+
+/* ERR_load_strings loads an array of ERR_STRING_DATA into the hash table. The
+ * array must be terminated by an entry with a NULL string. */
+void ERR_load_strings(const ERR_STRING_DATA *str);
+
+/* ERR_FNS_st is a structure of function pointers that contains the actual
+ * implementation of the error queue handling functions. */
+struct ERR_FNS_st {
+ void (*shutdown)(void);
+ ERR_STRING_DATA *(*get_item)(uint32_t packed_error);
+ ERR_STRING_DATA *(*set_item)(const ERR_STRING_DATA *);
+ ERR_STRING_DATA *(*del_item)(uint32_t packed_error);
+
+ /* get_state returns the ERR_STATE for the current thread. This function
+ * never returns NULL. */
+ ERR_STATE *(*get_state)(void);
+};
+
+/* OPENSSL_DECLARE_ERROR_REASON is used by util/make_errors.h (which generates
+ * the error defines) to recognise that an additional reason value is needed.
+ * This is needed when the reason value is used outside of an
+ * |OPENSSL_PUT_ERROR| macro. The resulting define will be
+ * ${lib}_R_${reason}. */
+#define OPENSSL_DECLARE_ERROR_REASON(lib, reason)
+
+/* OPENSSL_DECLARE_ERROR_FUNCTION is used by util/make_errors.h (which
+ * generates the error * defines to recognise that an additional function value
+ * is needed. This is * needed when the function value is used outside of an
+ * |OPENSSL_PUT_ERROR| * macro. The resulting define will be
+ * ${lib}_F_${reason}. */
+#define OPENSSL_DECLARE_ERROR_FUNCTION(lib, function_name)
+
+/* ERR_load_BIO_strings does nothing.
+ *
+ * TODO(fork): remove. libjingle calls this. */
+void ERR_load_BIO_strings();
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_ERR_H */
diff --git a/crypto/err/err_impl.c b/crypto/err/err_impl.c
new file mode 100644
index 0000000..ff2509d
--- /dev/null
+++ b/crypto/err/err_impl.c
@@ -0,0 +1,280 @@
+/* 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.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2006 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). */
+
+#include <openssl/err.h>
+
+#include <assert.h>
+
+#include <openssl/lhash.h>
+#include <openssl/mem.h>
+
+
+DEFINE_LHASH_OF(ERR_STATE);
+DEFINE_LHASH_OF(ERR_STRING_DATA);
+
+/* state_hash is a map from thread ID to ERR_STATE. It works like thread-local
+ * storage. */
+static LHASH_OF(ERR_STATE) *state_hash = NULL;
+
+/* error_hash maps from a packed error to the string for that library /
+ * function / reason. */
+static LHASH_OF(ERR_STRING_DATA) *error_hash = NULL;
+
+/* err_string_data_hash is an lhash hash function for ERR_STRING_DATA. */
+static uint32_t err_string_data_hash(const ERR_STRING_DATA *a) {
+ return OPENSSL_hash32(&a->error, sizeof(a->error));
+}
+
+/* err_string_data_cmp is an lhash compare function for ERR_STRING_DATA. */
+static int err_string_data_cmp(const ERR_STRING_DATA *a,
+ const ERR_STRING_DATA *b) {
+ return ((int)a->error) - ((int)b->error);
+}
+
+/* error_hash_get_write_locked returns the hash that maps from packed error to
+ * error string and creates it if need be. The caller must hold a write lock on
+ * LOCK_ERR. */
+static LHASH_OF(ERR_STRING_DATA) * error_hash_get_write_locked(void) {
+ if (!error_hash) {
+ error_hash = lh_ERR_STRING_DATA_new(err_string_data_hash, err_string_data_cmp);
+ }
+
+ return error_hash;
+}
+
+/* err_get_item returns an ERR_STRING_DATA with an |error| member that
+ * equals |packed_error|, or NULL if none can be found. */
+static ERR_STRING_DATA *err_get_item(uint32_t packed_error) {
+ ERR_STRING_DATA *ret = NULL, pattern;
+
+ pattern.error = packed_error;
+
+ CRYPTO_r_lock(CRYPTO_LOCK_ERR);
+ if (error_hash) {
+ ret = lh_ERR_STRING_DATA_retrieve(error_hash, &pattern);
+ }
+ CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
+
+ return ret;
+}
+
+/* err_set_item adds an ERR_STRING_DATA to the global hash of error strings and
+ * returns the previous entry with the same |err->error| value, if any. */
+static ERR_STRING_DATA *err_set_item(const ERR_STRING_DATA *err) {
+ ERR_STRING_DATA *old_item = NULL;
+ LHASH_OF(ERR_STRING_DATA) *hash;
+
+ CRYPTO_w_lock(CRYPTO_LOCK_ERR);
+ hash = error_hash_get_write_locked();
+ if (hash) {
+ lh_ERR_STRING_DATA_insert(hash, &old_item, (ERR_STRING_DATA*) err);
+ }
+ CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
+
+ return old_item;
+}
+
+/* err_set_item removes an item from the global hash of error strings for
+ * |packed_error| and returns the removed entry, if any. */
+static ERR_STRING_DATA *err_del_item(uint32_t packed_error) {
+ ERR_STRING_DATA *old_item = NULL, pattern;
+
+ pattern.error = packed_error;
+
+ CRYPTO_w_lock(CRYPTO_LOCK_ERR);
+ if (error_hash) {
+ old_item = lh_ERR_STRING_DATA_delete(error_hash, &pattern);
+ }
+ CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
+
+ return old_item;
+}
+
+
+/* err_state_hash is an lhash hash function for ERR_STATE. */
+static uint32_t err_state_hash(const ERR_STATE *a) {
+ return CRYPTO_THREADID_hash(&a->tid);
+}
+
+/* err_state_cmp is an lhash compare function for ERR_STATE. */
+static int err_state_cmp(const ERR_STATE *a, const ERR_STATE *b) {
+ return CRYPTO_THREADID_cmp(&a->tid, &b->tid);
+}
+
+
+static ERR_STATE *err_get_state(void) {
+ CRYPTO_THREADID tid;
+ ERR_STATE pattern, *state, *race_state;
+ int insert_result;
+ static ERR_STATE fallback;
+
+ CRYPTO_THREADID_current(&tid);
+ memset(&pattern, 0, sizeof(pattern));
+ CRYPTO_THREADID_cpy(&pattern.tid, &tid);
+
+ CRYPTO_r_lock(CRYPTO_LOCK_ERR);
+ if (state_hash == NULL) {
+ CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
+ CRYPTO_w_lock(CRYPTO_LOCK_ERR);
+ if (state_hash == NULL) {
+ state_hash = lh_ERR_STATE_new(err_state_hash, err_state_cmp);
+ }
+ CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
+ CRYPTO_r_lock(CRYPTO_LOCK_ERR);
+ }
+
+ state = lh_ERR_STATE_retrieve(state_hash, &pattern);
+ CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
+ if (state != NULL) {
+ return state;
+ }
+
+ state = OPENSSL_malloc(sizeof(ERR_STATE));
+ if (state == NULL) {
+ CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
+ /* The other error functions don't cope with a failure to get the error
+ * state, so we return a dummy value. */
+ return &fallback;
+ }
+
+ memset(state, 0, sizeof(ERR_STATE));
+ CRYPTO_THREADID_cpy(&state->tid, &tid);
+
+ CRYPTO_w_lock(CRYPTO_LOCK_ERR);
+ insert_result = lh_ERR_STATE_insert(state_hash, &race_state, state);
+ CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
+
+ if (!insert_result) {
+ /* Insertion failed because of malloc failure. */
+ OPENSSL_free(state);
+ return &fallback;
+ }
+
+ /* We cannot have raced with another thread to insert an ERR_STATE because no
+ * other thread should be inserting values for this thread. */
+ assert(race_state == NULL);
+
+ return state;
+}
+
+static void err_shutdown(void) {
+ CRYPTO_w_lock(CRYPTO_LOCK_ERR);
+ if (error_hash) {
+ lh_ERR_STRING_DATA_free(error_hash);
+ error_hash = NULL;
+ }
+ CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
+}
+
+const struct ERR_FNS_st openssl_err_default_impl = {
+ err_shutdown,
+ err_get_item,
+ err_set_item,
+ err_del_item,
+ err_get_state,
+};
diff --git a/crypto/err/err_test.c b/crypto/err/err_test.c
new file mode 100644
index 0000000..adfc9d0
--- /dev/null
+++ b/crypto/err/err_test.c
@@ -0,0 +1,118 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <stdio.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+static int test_overflow() {
+ unsigned i;
+
+ for (i = 0; i < ERR_NUM_ERRORS*2; i++) {
+ ERR_put_error(1, 2, 3, "test", 1);
+ }
+
+ for (i = 0; i < ERR_NUM_ERRORS - 1; i++) {
+ if (ERR_get_error() == 0) {
+ fprintf(stderr, "ERR_get_error failed at %u\n", i);
+ return 0;
+ }
+ }
+
+ if (ERR_get_error() != 0) {
+ fprintf(stderr, "ERR_get_error more than the expected number of values.\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int test_put_error() {
+ uint32_t packed_error;
+ int line, flags;
+ const char *file;
+ char *data;
+
+ if (ERR_get_error() != 0) {
+ fprintf(stderr, "ERR_get_error returned value before an error was added.\n");
+ return 0;
+ }
+
+ ERR_put_error(1, 2, 3, "test", 4);
+ ERR_add_error_data(1, "testing");
+
+ packed_error = ERR_get_error_line_data(&file, &line, &data, &flags);
+ if (strcmp(file, "test") != 0 ||
+ line != 4 ||
+ (flags & ERR_FLAG_STRING) == 0 ||
+ (flags & ERR_FLAG_MALLOCED) == 0 ||
+ ERR_GET_LIB(packed_error) != 1 ||
+ ERR_GET_FUNC(packed_error) != 2 ||
+ ERR_GET_REASON(packed_error) != 3 ||
+ strcmp(data, "testing") != 0) {
+ fprintf(stderr, "Bad error data returned.\n");
+ return 0;
+ }
+
+ OPENSSL_free(data);
+
+ return 1;
+}
+
+static int test_clear_error() {
+ if (ERR_get_error() != 0) {
+ fprintf(stderr, "ERR_get_error returned value before an error was added.\n");
+ return 0;
+ }
+
+ ERR_put_error(1, 2, 3, "test", 4);
+ ERR_clear_error();
+
+ if (ERR_get_error() != 0) {
+ fprintf(stderr, "Error remained after clearing.\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int test_print() {
+ size_t i;
+ char buf[256];
+ uint32_t packed_error;
+
+ ERR_put_error(1, 2, 3, "test", 4);
+ ERR_add_error_data(1, "testing");
+ packed_error = ERR_get_error();
+
+ for (i = 0; i <= sizeof(buf); i++) {
+ ERR_error_string_n(packed_error, buf, i);
+ }
+
+ return 1;
+}
+
+int main() {
+ if (!test_overflow() ||
+ !test_put_error() ||
+ !test_clear_error() ||
+ !test_print()) {
+ return 1;
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/crypto/evp/CMakeLists.txt b/crypto/evp/CMakeLists.txt
new file mode 100644
index 0000000..c3d8d8a
--- /dev/null
+++ b/crypto/evp/CMakeLists.txt
@@ -0,0 +1,30 @@
+include_directories(. .. ../../include)
+
+add_library(
+ evp
+
+ OBJECT
+
+ asn1.c
+ digestsign.c
+ evp.c
+ evp_ctx.c
+ evp_error.c
+ p_ec.c
+ p_ec_asn1.c
+ p_hmac.c
+ p_hmac_asn1.c
+ p_rsa.c
+ p_rsa_asn1.c
+ pbkdf.c
+ sign.c
+)
+
+
+add_executable(
+ example_sign
+
+ example_sign.c
+)
+
+target_link_libraries(example_sign crypto)
diff --git a/crypto/evp/asn1.c b/crypto/evp/asn1.c
new file mode 100644
index 0000000..50bdb06
--- /dev/null
+++ b/crypto/evp/asn1.c
@@ -0,0 +1,170 @@
+/* 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/evp.h>
+
+#include <openssl/asn1.h>
+#include <openssl/err.h>
+#include <openssl/obj.h>
+#include <openssl/x509.h>
+
+#include "internal.h"
+
+
+EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **out, const uint8_t **inp,
+ long len) {
+ EVP_PKEY *ret;
+
+ if (out == NULL || *out == NULL) {
+ ret = EVP_PKEY_new();
+ if (ret == NULL) {
+ OPENSSL_PUT_ERROR(EVP, d2i_PrivateKey, ERR_R_EVP_LIB);
+ return NULL;
+ }
+ } else {
+ ret = *out;
+ }
+
+ if (!EVP_PKEY_set_type(ret, type)) {
+ OPENSSL_PUT_ERROR(EVP, d2i_PrivateKey, EVP_R_UNKNOWN_PUBLIC_KEY_TYPE);
+ goto err;
+ }
+
+ if (!ret->ameth->old_priv_decode ||
+ !ret->ameth->old_priv_decode(ret, inp, len)) {
+ if (ret->ameth->priv_decode) {
+ PKCS8_PRIV_KEY_INFO *p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, inp, len);
+ if (!p8) {
+ goto err;
+ }
+ EVP_PKEY_free(ret);
+ ret = EVP_PKCS82PKEY(p8);
+ PKCS8_PRIV_KEY_INFO_free(p8);
+ } else {
+ OPENSSL_PUT_ERROR(EVP, d2i_PrivateKey, ERR_R_ASN1_LIB);
+ goto err;
+ }
+ }
+
+ if (out != NULL) {
+ *out = ret;
+ }
+ return ret;
+
+err:
+ if (ret != NULL && (out == NULL || *out != ret)) {
+ EVP_PKEY_free(ret);
+ }
+ return NULL;
+}
+
+EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **out, const uint8_t **inp, long len) {
+ STACK_OF(ASN1_TYPE) *inkey;
+ const uint8_t *p;
+ int keytype;
+ p = *inp;
+
+ /* Dirty trick: read in the ASN1 data into out STACK_OF(ASN1_TYPE):
+ * by analyzing it we can determine the passed structure: this
+ * assumes the input is surrounded by an ASN1 SEQUENCE. */
+ inkey = d2i_ASN1_SEQUENCE_ANY(NULL, &p, len);
+ /* Since we only need to discern "traditional format" RSA and DSA
+ * keys we can just count the elements. */
+ if (sk_ASN1_TYPE_num(inkey) == 6) {
+ keytype = EVP_PKEY_DSA;
+ } else if (sk_ASN1_TYPE_num(inkey) == 4) {
+ keytype = EVP_PKEY_EC;
+ } else if (sk_ASN1_TYPE_num(inkey) == 3) {
+ OPENSSL_PUT_ERROR(EVP, d2i_AutoPrivateKey, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
+ return 0;
+
+ /* This seems to be PKCS8, not traditional format */
+ PKCS8_PRIV_KEY_INFO *p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, inp, len);
+ EVP_PKEY *ret;
+
+ sk_ASN1_TYPE_pop_free(inkey, ASN1_TYPE_free);
+ if (!p8) {
+ OPENSSL_PUT_ERROR(EVP, d2i_AutoPrivateKey,
+ EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
+ return NULL;
+ }
+ ret = EVP_PKCS82PKEY(p8);
+ PKCS8_PRIV_KEY_INFO_free(p8);
+ if (out) {
+ *out = ret;
+ }
+ return ret;
+ } else {
+ keytype = EVP_PKEY_RSA;
+ }
+
+ sk_ASN1_TYPE_pop_free(inkey, ASN1_TYPE_free);
+ return d2i_PrivateKey(keytype, out, inp, len);
+}
+
+int i2d_PublicKey(EVP_PKEY *key, uint8_t **outp) {
+ switch (key->type) {
+ case EVP_PKEY_RSA:
+ return i2d_RSAPublicKey(key->pkey.rsa, outp);
+ case EVP_PKEY_DSA:
+ return i2d_DSAPublicKey(key->pkey.dsa, outp);
+ case EVP_PKEY_EC:
+ return i2o_ECPublicKey(key->pkey.ec, outp);
+ default:
+ OPENSSL_PUT_ERROR(EVP, i2d_PublicKey, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
+ return -1;
+ }
+}
diff --git a/crypto/evp/digestsign.c b/crypto/evp/digestsign.c
new file mode 100644
index 0000000..08968ed
--- /dev/null
+++ b/crypto/evp/digestsign.c
@@ -0,0 +1,212 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2006.
+ */
+/* ====================================================================
+ * Copyright (c) 2006,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/digest.h>
+#include <openssl/err.h>
+
+#include "internal.h"
+#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) {
+ int r = EVP_PKEY_CTX_ctrl(ctx->pctx, -1, EVP_PKEY_OP_TYPE_SIG,
+ EVP_PKEY_CTRL_DIGESTINIT, 0, ctx);
+ return r > 0 || r == -2;
+}
+
+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,
+ const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey,
+ int is_verify) {
+ if (ctx->pctx == NULL) {
+ ctx->pctx = EVP_PKEY_CTX_new(pkey, e);
+ }
+ if (ctx->pctx == NULL) {
+ return 0;
+ }
+ ctx->pctx_ops = &md_pctx_ops;
+
+ if (type == NULL) {
+ type = EVP_sha1();
+ }
+
+ if (type == NULL) {
+ OPENSSL_PUT_ERROR(EVP, do_sigver_init, 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) <= 0) {
+ return 0;
+ }
+ ctx->pctx->operation = EVP_PKEY_OP_VERIFYCTX;
+ } else if (EVP_PKEY_verify_init(ctx->pctx) <= 0) {
+ return 0;
+ }
+ } else {
+ if (ctx->pctx->pmeth->signctx_init) {
+ if (ctx->pctx->pmeth->signctx_init(ctx->pctx, ctx) <= 0) {
+ return 0;
+ }
+ ctx->pctx->operation = EVP_PKEY_OP_SIGNCTX;
+ } else if (EVP_PKEY_sign_init(ctx->pctx) <= 0) {
+ return 0;
+ }
+ }
+ if (EVP_PKEY_CTX_set_signature_md(ctx->pctx, type) <= 0) {
+ return 0;
+ }
+ if (pctx) {
+ *pctx = ctx->pctx;
+ }
+ if (!EVP_DigestInit_ex(ctx, type, e)) {
+ return 0;
+ }
+ return 1;
+}
+
+int EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type,
+ ENGINE *e, EVP_PKEY *pkey) {
+ return do_sigver_init(ctx, pctx, type, e, pkey, 0);
+}
+
+int EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
+ const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey) {
+ return do_sigver_init(ctx, pctx, type, e, pkey, 1);
+}
+
+int EVP_DigestSignUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) {
+ return EVP_DigestUpdate(ctx, data, len);
+}
+
+int EVP_DigestVerifyUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) {
+ return EVP_DigestUpdate(ctx, data, len);
+}
+
+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;
+ 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);
+ }
+ EVP_MD_CTX_cleanup(&tmp_ctx);
+ if (has_signctx || !r) {
+ return r;
+ }
+ if (EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, md, mdlen) <= 0) {
+ return 0;
+ }
+ } else {
+ if (has_signctx) {
+ if (ctx->pctx->pmeth->signctx(ctx->pctx, out_sig, out_sig_len, ctx) <= 0) {
+ return 0;
+ }
+ } else {
+ size_t s = EVP_MD_size(ctx->digest);
+ if (EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, NULL, s) <= 0) {
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig,
+ size_t sig_len) {
+ EVP_MD_CTX tmp_ctx;
+ uint8_t md[EVP_MAX_MD_SIZE];
+ int r;
+ unsigned int mdlen;
+ const int has_verifyctx = ctx->pctx->pmeth->verifyctx != NULL;
+
+ EVP_MD_CTX_init(&tmp_ctx);
+ if (!EVP_MD_CTX_copy_ex(&tmp_ctx, ctx)) {
+ return -1;
+ }
+ if (has_verifyctx) {
+ r = tmp_ctx.pctx->pmeth->verifyctx(tmp_ctx.pctx, sig, sig_len, &tmp_ctx);
+ } else {
+ r = EVP_DigestFinal_ex(&tmp_ctx, md, &mdlen);
+ }
+
+ EVP_MD_CTX_cleanup(&tmp_ctx);
+ if (has_verifyctx || !r) {
+ return r;
+ }
+ return EVP_PKEY_verify(ctx->pctx, sig, sig_len, md, mdlen);
+}
diff --git a/crypto/evp/evp.c b/crypto/evp/evp.c
new file mode 100644
index 0000000..1d6fd8c
--- /dev/null
+++ b/crypto/evp/evp.c
@@ -0,0 +1,425 @@
+/* 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/evp.h>
+
+#include <assert.h>
+
+#include <openssl/bio.h>
+#include <openssl/dh.h>
+#include <openssl/dsa.h>
+#include <openssl/ec.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/rsa.h>
+
+#include "internal.h"
+
+
+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() {
+ EVP_PKEY *ret;
+
+ ret = OPENSSL_malloc(sizeof(EVP_PKEY));
+ if (ret == NULL) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_new, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ memset(ret, 0, sizeof(EVP_PKEY));
+ ret->type = EVP_PKEY_NONE;
+ ret->references = 1;
+
+ return ret;
+}
+
+static void free_it(EVP_PKEY *pkey) {
+ if (pkey->ameth && pkey->ameth->pkey_free) {
+ pkey->ameth->pkey_free(pkey);
+ pkey->pkey.ptr = NULL;
+ pkey->type = EVP_PKEY_NONE;
+ }
+}
+
+void EVP_PKEY_free(EVP_PKEY *pkey) {
+ if (pkey == NULL) {
+ return;
+ }
+
+ if (CRYPTO_add(&pkey->references, -1, CRYPTO_LOCK_EVP_PKEY)) {
+ return;
+ }
+
+ free_it(pkey);
+ if (pkey->attributes) {
+ /* TODO(fork): layering: X509_ATTRIBUTE_free is an X.509 function. In
+ * practice this path isn't called but should be removed in the future. */
+ /*sk_X509_ATTRIBUTE_pop_free(pkey->attributes, X509_ATTRIBUTE_free);*/
+ assert(0);
+ }
+ OPENSSL_free(pkey);
+}
+
+int EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
+ if (a->type != b->type) {
+ return -1;
+ }
+
+ if (a->ameth) {
+ int ret;
+ /* Compare parameters if the algorithm has them */
+ if (a->ameth->param_cmp) {
+ ret = a->ameth->param_cmp(a, b);
+ if (ret <= 0)
+ return ret;
+ }
+
+ if (a->ameth->pub_cmp) {
+ return a->ameth->pub_cmp(a, b);
+ }
+ }
+
+ return -2;
+}
+
+EVP_PKEY *EVP_PKEY_dup(EVP_PKEY *pkey) {
+ CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
+ return pkey;
+}
+
+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);
+ goto err;
+ }
+
+ if (EVP_PKEY_missing_parameters(from)) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_copy_parameters, EVP_R_MISSING_PARAMETERS);
+ goto err;
+ }
+
+ if (from->ameth && from->ameth->param_copy) {
+ return from->ameth->param_copy(to, from);
+ }
+
+err:
+ return 0;
+}
+
+int EVP_PKEY_missing_parameters(const EVP_PKEY *pkey) {
+ if (pkey->ameth && pkey->ameth->param_missing) {
+ return pkey->ameth->param_missing(pkey);
+ }
+ return 0;
+}
+
+int EVP_PKEY_size(const EVP_PKEY *pkey) {
+ if (pkey && pkey->ameth && pkey->ameth->pkey_size) {
+ return pkey->ameth->pkey_size(pkey);
+ }
+ return 0;
+}
+
+int EVP_PKEY_bits(EVP_PKEY *pkey) {
+ if (pkey && pkey->ameth && pkey->ameth->pkey_bits) {
+ return pkey->ameth->pkey_bits(pkey);
+ }
+ return 0;
+}
+
+int EVP_PKEY_id(const EVP_PKEY *pkey) {
+ return pkey->type;
+}
+
+/* TODO(fork): remove the first argument. */
+const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(ENGINE **pengine, int nid) {
+ switch (nid) {
+ 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;
+ default:
+ return NULL;
+ }
+}
+
+int EVP_PKEY_type(int nid) {
+ const EVP_PKEY_ASN1_METHOD *meth = EVP_PKEY_asn1_find(NULL, nid);
+ if (meth == NULL) {
+ return NID_undef;
+ }
+ 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) <= 0 ||
+ EVP_PKEY_CTX_ctrl(mac_ctx, -1, EVP_PKEY_OP_KEYGEN,
+ EVP_PKEY_CTRL_SET_MAC_KEY, mac_key_len,
+ (uint8_t *)mac_key) <= 0 ||
+ EVP_PKEY_keygen(mac_ctx, &ret) <= 0) {
+ 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);
+ return 1;
+ }
+ return 0;
+}
+
+int EVP_PKEY_assign_RSA(EVP_PKEY *pkey, RSA *key) {
+ return EVP_PKEY_assign(pkey, EVP_PKEY_RSA, key);
+}
+
+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);
+ return NULL;
+ }
+ RSA_up_ref(pkey->pkey.rsa);
+ return pkey->pkey.rsa;
+}
+
+int EVP_PKEY_set1_DSA(EVP_PKEY *pkey, DSA *key) {
+ if (EVP_PKEY_assign_DSA(pkey, key)) {
+ DSA_up_ref(key);
+ return 1;
+ }
+ return 0;
+}
+
+int EVP_PKEY_assign_DSA(EVP_PKEY *pkey, DSA *key) {
+ return EVP_PKEY_assign(pkey, EVP_PKEY_DSA, key);
+}
+
+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);
+ return NULL;
+ }
+ DSA_up_ref(pkey->pkey.dsa);
+ return pkey->pkey.dsa;
+}
+
+int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey, EC_KEY *key) {
+ if (EVP_PKEY_assign_EC_KEY(pkey, key)) {
+ EC_KEY_up_ref(key);
+ return 1;
+ }
+ return 0;
+}
+
+int EVP_PKEY_assign_EC_KEY(EVP_PKEY *pkey, EC_KEY *key) {
+ return EVP_PKEY_assign(pkey, EVP_PKEY_EC, key);
+}
+
+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);
+ return NULL;
+ }
+ EC_KEY_up_ref(pkey->pkey.ec);
+ return pkey->pkey.ec;
+}
+
+int EVP_PKEY_set1_DH(EVP_PKEY *pkey, DH *key) {
+ if (EVP_PKEY_assign_DH(pkey, key)) {
+ DH_up_ref(key);
+ return 1;
+ }
+ return 0;
+}
+
+int EVP_PKEY_assign_DH(EVP_PKEY *pkey, DH *key) {
+ return EVP_PKEY_assign(pkey, EVP_PKEY_EC, key);
+}
+
+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);
+ return NULL;
+ }
+ DH_up_ref(pkey->pkey.dh);
+ return pkey->pkey.dh;
+}
+
+int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key) {
+ if (!EVP_PKEY_set_type(pkey, type)) {
+ return 0;
+ }
+ pkey->pkey.ptr = key;
+ return key != NULL;
+}
+
+const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find_str(ENGINE **pengine,
+ const char *name,
+ 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", 4) == 0) {
+ return &ec_asn1_meth;
+ }
+ return NULL;
+}
+
+int EVP_PKEY_set_type(EVP_PKEY *pkey, int type) {
+ const EVP_PKEY_ASN1_METHOD *ameth;
+
+ if (pkey && pkey->pkey.ptr) {
+ free_it(pkey);
+ }
+
+ ameth = EVP_PKEY_asn1_find(NULL, type);
+ if (ameth == NULL) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_set_type, EVP_R_UNSUPPORTED_ALGORITHM);
+ ERR_add_error_dataf("algorithm %d (%s)", type, OBJ_nid2sn(type));
+ return 0;
+ }
+
+ if (pkey) {
+ pkey->ameth = ameth;
+ pkey->type = pkey->ameth->pkey_id;
+ }
+
+ return 1;
+}
+
+
+
+int EVP_PKEY_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) {
+ if (a->type != b->type) {
+ return -1;
+ }
+ if (a->ameth && a->ameth->param_cmp) {
+ return a->ameth->param_cmp(a, b);
+ }
+ return -2;
+}
+
+static int print_unsupported(BIO *out, const EVP_PKEY *pkey, int indent,
+ const char *kstr) {
+ BIO_indent(out, indent, 128);
+ BIO_printf(out, "%s algorithm \"%s\" unsupported\n", kstr,
+ OBJ_nid2ln(pkey->type));
+ return 1;
+}
+
+int EVP_PKEY_print_public(BIO *out, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *pctx) {
+ if (pkey->ameth && pkey->ameth->pub_print) {
+ return pkey->ameth->pub_print(out, pkey, indent, pctx);
+ }
+
+ return print_unsupported(out, pkey, indent, "Public Key");
+}
+
+int EVP_PKEY_print_private(BIO *out, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *pctx) {
+ if (pkey->ameth && pkey->ameth->priv_print) {
+ return pkey->ameth->priv_print(out, pkey, indent, pctx);
+ }
+
+ return print_unsupported(out, pkey, indent, "Private Key");
+}
+
+int EVP_PKEY_print_params(BIO *out, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *pctx) {
+ if (pkey->ameth && pkey->ameth->param_print) {
+ return pkey->ameth->param_print(out, pkey, indent, pctx);
+ }
+
+ return print_unsupported(out, pkey, indent, "Parameters");
+}
+
+int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) {
+ return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_CTRL_MD, 0,
+ (void *)md);
+}
+
+int EVP_PKEY_CTX_get_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md) {
+ return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_CTRL_GET_MD,
+ 0, (void *)out_md);
+}
+
+void OpenSSL_add_all_algorithms() {}
+
+void EVP_cleanup() {}
diff --git a/crypto/evp/evp.h b/crypto/evp/evp.h
new file mode 100644
index 0000000..ce40aa5
--- /dev/null
+++ b/crypto/evp/evp.h
@@ -0,0 +1,819 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_EVP_H
+#define OPENSSL_HEADER_EVP_H
+
+#include <openssl/base.h>
+#include <openssl/stack.h>
+
+/* OpenSSL included digest and cipher functions in this header so we include
+ * them for users that still expect that. */
+#include <openssl/cipher.h>
+#include <openssl/digest.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/thread.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* EVP abstracts over public/private key algorithms. */
+
+
+/* Public key objects. */
+
+/* EVP_PKEY_new creates a new, empty public-key object and returns it or NULL
+ * on allocation failure. */
+EVP_PKEY *EVP_PKEY_new();
+
+/* EVP_PKEY_free frees all data referenced by |pkey| and then frees |pkey|
+ * itself. */
+void EVP_PKEY_free(EVP_PKEY *pkey);
+
+/* EVP_PKEY_cmp compares |a| and |b| and returns one if they are equal, zero if
+ * not and a negative number on error.
+ *
+ * WARNING: this differs from the traditional return value of a "cmp"
+ * function. */
+int EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b);
+
+/* EVP_PKEY_dup adds one to the reference count of |pkey| and returns
+ * |pkey|. */
+EVP_PKEY *EVP_PKEY_dup(EVP_PKEY *pkey);
+
+/* EVP_PKEY_copy_parameters sets the parameters of |to| to equal the parameters
+ * of |from|. It returns one on success and zero on error. */
+int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from);
+
+/* EVP_PKEY_missing_parameters returns one if |pkey| is missing needed
+ * parameters or zero if not, or if the algorithm doesn't take parameters. */
+int EVP_PKEY_missing_parameters(const EVP_PKEY *pkey);
+
+/* EVP_PKEY_size returns the "size", in bytes, of |pkey|. For example, for an
+ * RSA key this returns the number of bytes needed to represent the modulus. */
+int EVP_PKEY_size(const EVP_PKEY *pkey);
+
+/* EVP_PKEY_bits returns the "size", in bits, of |pkey|. For example, for an
+ * RSA key, this returns the bit length of the modulus. */
+int EVP_PKEY_bits(EVP_PKEY *pkey);
+
+/* EVP_PKEY_id returns the type of |pkey|, which is one of the |EVP_PKEY_*|
+ * values. */
+int EVP_PKEY_id(const EVP_PKEY *pkey);
+
+/* EVP_PKEY_type returns a canonicalised form of |NID|. For example,
+ * |EVP_PKEY_RSA2| will be turned into |EVP_PKEY_RSA|. */
+int EVP_PKEY_type(int nid);
+
+/* EVP_PKEY_new_mac_key allocates a fresh |EVP_PKEY| of the given type (e.g.
+ * |EVP_PKEY_HMAC|), sets |mac_key| as the MAC key and "generates" a new key,
+ * suitable for signing. It returns the fresh |EVP_PKEY|, or NULL on error. */
+EVP_PKEY *EVP_PKEY_new_mac_key(int type, ENGINE *engine, const uint8_t *mac_key,
+ size_t mac_key_len);
+
+
+/* Getting and setting concrete public key types.
+ *
+ * The following functions get and set the underlying public key in an
+ * |EVP_PKEY| object. The |set1| functions take a additional reference to the
+ * underlying key and return one on success or zero on error. The |assign|
+ * functions adopt the caller's reference. The getters return a fresh reference
+ * to the underlying object. */
+
+int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, RSA *key);
+int EVP_PKEY_assign_RSA(EVP_PKEY *pkey, RSA *key);
+RSA *EVP_PKEY_get1_RSA(EVP_PKEY *pkey);
+
+int EVP_PKEY_set1_DSA(EVP_PKEY *pkey, struct dsa_st *key);
+int EVP_PKEY_assign_DSA(EVP_PKEY *pkey, DSA *key);
+struct dsa_st *EVP_PKEY_get1_DSA(EVP_PKEY *pkey);
+
+int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey, struct ec_key_st *key);
+int EVP_PKEY_assign_EC_KEY(EVP_PKEY *pkey, EC_KEY *key);
+struct ec_key_st *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey);
+
+int EVP_PKEY_set1_DH(EVP_PKEY *pkey, struct dh_st *key);
+int EVP_PKEY_assign_DH(EVP_PKEY *pkey, DH *key);
+struct dh_st *EVP_PKEY_get1_DH(EVP_PKEY *pkey);
+
+#define EVP_PKEY_NONE NID_undef
+#define EVP_PKEY_RSA NID_rsaEncryption
+#define EVP_PKEY_RSA2 NID_rsa
+#define EVP_PKEY_DSA NID_dsa
+#define EVP_PKEY_DH NID_dhKeyAgreement
+#define EVP_PKEY_DHX NID_dhpublicnumber
+#define EVP_PKEY_EC NID_X9_62_id_ecPublicKey
+#define EVP_PKEY_HMAC NID_hmac
+
+/* EVP_PKEY_assign sets the underlying key of |pkey| to |key|, which must be of
+ * the given type. The |type| argument should be one of the |EVP_PKEY_*|
+ * values. */
+int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key);
+
+/* EVP_PKEY_set_type sets the type of |pkey| to |type|, which should be one of
+ * the |EVP_PKEY_*| values. It returns one if sucessful or zero otherwise. If
+ * |pkey| is NULL, it simply reports whether the type is known. */
+int EVP_PKEY_set_type(EVP_PKEY *pkey, int type);
+
+/* EVP_PKEY_cmp_parameters compares the parameters of |a| and |b|. It returns
+ * one if they match, zero if not, or a negative number of on error.
+ *
+ * WARNING: the return value differs from the usual return value convention. */
+int EVP_PKEY_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b);
+
+
+/* ASN.1 functions */
+
+/* d2i_PrivateKey parses an ASN.1, DER-encoded, private key from |len| bytes at
+ * |*inp|. If |out| is not NULL then, on exit, a pointer to the result is in
+ * |*out|. If |*out| is already non-NULL on entry then the result is written
+ * directly into |*out|, otherwise a fresh |EVP_PKEY| is allocated. On
+ * successful exit, |*inp| is advanced past the DER structure. It returns the
+ * result or NULL on error. */
+EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **out, const uint8_t **inp,
+ long len);
+
+/* d2i_AutoPrivateKey acts the same as |d2i_PrivateKey|, but detects the type
+ * of the private key. */
+EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **out, const uint8_t **inp, long len);
+
+/* i2d_PrivateKey marshals a private key from |key| to an ASN.1, DER
+ * structure. If |outp| is not NULL then the result is written to |*outp| and
+ * |*outp| is advanced just past the output. It returns the number of bytes in
+ * the result, whether written or not, or a negative value on error. */
+int i2d_PrivateKey(const EVP_PKEY *key, uint8_t **outp);
+
+/* i2d_PublicKey marshals a public key from |key| to an ASN.1, DER
+ * structure. If |outp| is not NULL then the result is written to |*outp| and
+ * |*outp| is advanced just past the output. It returns the number of bytes in
+ * the result, whether written or not, or a negative value on error. */
+int i2d_PublicKey(EVP_PKEY *key, uint8_t **outp);
+
+
+/* Signing */
+
+/* EVP_DigestSignInit sets up |ctx| for a signing operation with |type| and
+ * |pkey|. The |ctx| argument must have been initialised with
+ * |EVP_MD_CTX_init|. If |pctx| is not NULL, the |EVP_PKEY_CTX| of the signing
+ * operation will be written to |*pctx|; this can be used to set alternative
+ * signing options.
+ *
+ * It returns one on success, or <= 0 on error. WARNING: this differs from the
+ * usual OpenSSL return convention. */
+int EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type,
+ ENGINE *e, EVP_PKEY *pkey);
+
+/* EVP_DigestSignUpdate appends |len| bytes from |data| to the data which will
+ * be signed in |EVP_DigestSignFinal|. It returns one on success and zero
+ * otherwise. */
+int EVP_DigestSignUpdate(EVP_MD_CTX *ctx, const void *data, size_t len);
+
+/* EVP_DigestSignFinal signs the data that has been included by one or more
+ * calls to |EVP_DigestSignUpdate|. If |out_sig| is NULL then |*out_sig_len| is
+ * set to the maximum number of output bytes. Otherwise, on entry,
+ * |*out_sig_len| must contain the length of the |out_sig| buffer. If the call
+ * is successful, the signature is written to |out_sig| and |*out_sig_len| is
+ * set to its length.
+ *
+ * It returns one on success and <= 0 on error. WARNING: this differs from the
+ * usual, OpenSSL return value convention. */
+int EVP_DigestSignFinal(EVP_MD_CTX *ctx, uint8_t *out_sig, size_t *out_sig_len);
+
+
+/* Verifying */
+
+/* EVP_DigestVerifyInit sets up |ctx| for a signature verification operation
+ * with |type| and |pkey|. The |ctx| argument must have been initialised with
+ * |EVP_MD_CTX_init|. If |pctx| is not NULL, the |EVP_PKEY_CTX| of the signing
+ * operation will be written to |*pctx|; this can be used to set alternative
+ * signing options.
+ *
+ * It returns one on success, or <= 0 on error. WARNING: this differs from the
+ * usual OpenSSL return convention. */
+int EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
+ const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey);
+
+/* EVP_DigestVerifyUpdate appends |len| bytes from |data| to the data which
+ * will be verified by |EVP_DigestVerifyFinal|. It returns one on success and
+ * zero otherwise. */
+int EVP_DigestVerifyUpdate(EVP_MD_CTX *ctx, const void *data, size_t len);
+
+/* EVP_DigestVerifyFinal verifies that |sig_len| bytes of |sig| are a valid
+ * signature for the data that has been included by one or more calls to
+ * |EVP_DigestVerifyUpdate|.
+ *
+ * It returns one on success and <= 0 on error. WARNING: this differs from the
+ * usual return value convention. */
+int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig,
+ size_t sig_len);
+
+
+/* Signing (old functions) */
+
+/* EVP_SignInit_ex configures |ctx|, which must already have been initialised,
+ * for a fresh signing operation using the hash function |type|. It returns one
+ * on success and zero otherwise.
+ *
+ * (In order to initialise |ctx|, either obtain it initialised with
+ * |EVP_MD_CTX_create|, or use |EVP_MD_CTX_init|.) */
+int EVP_SignInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl);
+
+/* EVP_SignInit is a deprecated version of |EVP_SignInit_ex|.
+ *
+ * TODO(fork): remove. */
+int EVP_SignInit(EVP_MD_CTX *ctx, const EVP_MD *type);
+
+/* EVP_SignUpdate appends |len| bytes from |data| to the data which will be
+ * signed in |EVP_SignFinal|. */
+int EVP_SignUpdate(EVP_MD_CTX *ctx, const void *data, size_t len);
+
+/* EVP_SignFinal signs the data that has been included by one or more calls to
+ * |EVP_SignUpdate|, using the key |pkey|, and writes it to |sig|. On entry,
+ * |sig| must point to at least |EVP_PKEY_size(pkey)| bytes of space. The
+ * actual size of the signature is written to |*out_sig_len|.
+ *
+ * It returns one on success and zero otherwise.
+ *
+ * It does not modify |ctx|, thus it's possible to continue to use |ctx| in
+ * order to sign a longer message. */
+int EVP_SignFinal(const EVP_MD_CTX *ctx, uint8_t *sig,
+ unsigned int *out_sig_len, EVP_PKEY *pkey);
+
+
+/* Verifying (old functions) */
+
+/* EVP_VerifyInit_ex configures |ctx|, which must already have been
+ * initialised, for a fresh signature verification operation using the hash
+ * function |type|. It returns one on success and zero otherwise.
+ *
+ * (In order to initialise |ctx|, either obtain it initialised with
+ * |EVP_MD_CTX_create|, or use |EVP_MD_CTX_init|.) */
+int EVP_VerifyInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl);
+
+/* EVP_VerifyInit is a deprecated version of |EVP_VerifyInit_ex|.
+ *
+ * TODO(fork): remove. */
+int EVP_VerifyInit(EVP_MD_CTX *ctx, const EVP_MD *type);
+
+/* EVP_VerifyUpdate appends |len| bytes from |data| to the data which will be
+ * signed in |EVP_VerifyFinal|. */
+int EVP_VerifyUpdate(EVP_MD_CTX *ctx, const void *data, size_t len);
+
+/* EVP_VerifyFinal verifies that |sig_len| bytes of |sig| are a valid
+ * signature, by |pkey|, for the data that has been included by one or more
+ * calls to |EVP_VerifyUpdate|.
+ *
+ * It returns one on success and zero otherwise.
+ *
+ * It does not modify |ctx|, thus it's possible to continue to use |ctx| in
+ * order to sign a longer message. */
+int EVP_VerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig, size_t sig_len,
+ EVP_PKEY *pkey);
+
+
+/* Printing */
+
+/* EVP_PKEY_print_public prints a textual representation of the public key in
+ * |pkey| to |out|. Returns one on success or zero otherwise. */
+int EVP_PKEY_print_public(BIO *out, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *pctx);
+
+/* EVP_PKEY_print_public prints a textual representation of the private key in
+ * |pkey| to |out|. Returns one on success or zero otherwise. */
+int EVP_PKEY_print_private(BIO *out, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *pctx);
+
+/* EVP_PKEY_print_public prints a textual representation of the parameters in
+ * |pkey| to |out|. Returns one on success or zero otherwise. */
+int EVP_PKEY_print_params(BIO *out, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *pctx);
+
+
+/* Password stretching.
+ *
+ * Password stretching functions take a low-entropy password and apply a slow
+ * function that results in a key suitable for use in symmetric
+ * cryptography. */
+
+/* PKCS5_PBKDF2_HMAC computes |iterations| iterations of PBKDF2 of |password|
+ * and |salt|, using |digest|, and outputs |key_len| bytes to |out_key|. It
+ * returns one on success and zero on error. */
+int PKCS5_PBKDF2_HMAC(const char *password, int password_len,
+ const uint8_t *salt, size_t salt_len, unsigned iterations,
+ const EVP_MD *digest, size_t key_len, uint8_t *out_key);
+
+/* PKCS5_PBKDF2_HMAC_SHA1 is the same as PKCS5_PBKDF2_HMAC, but with |digest|
+ * fixed to |EVP_sha1|. */
+int PKCS5_PBKDF2_HMAC_SHA1(const char *password, int password_len,
+ const uint8_t *salt, size_t salt_len,
+ unsigned iterations, size_t key_len,
+ uint8_t *out_key);
+
+
+/* Public key contexts.
+ *
+ * |EVP_PKEY_CTX| objects hold the context of an operation (e.g. signing or
+ * encrypting) that uses a public key. */
+
+/* EVP_PKEY_CTX_new allocates a fresh |EVP_PKEY_CTX| for use with |pkey|. It
+ * returns the context or NULL on error. */
+EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e);
+
+/* EVP_PKEY_CTX_new allocates a fresh |EVP_PKEY_CTX| for a key of type |id|
+ * (e.g. |EVP_PKEY_HMAC|). This can be used for key generation where
+ * |EVP_PKEY_CTX_new| can't be used because there isn't an |EVP_PKEY| to pass
+ * it. It returns the context or NULL on error. */
+EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int id, ENGINE *e);
+
+/* EVP_KEY_CTX_free frees |ctx| and the data it owns. */
+void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx);
+
+/* EVP_PKEY_CTX_dup allocates a fresh |EVP_PKEY_CTX| and sets it equal to the
+ * state of |ctx|. It returns the fresh |EVP_PKEY_CTX| or NULL on error. */
+EVP_PKEY_CTX *EVP_PKEY_CTX_dup(EVP_PKEY_CTX *ctx);
+
+/* EVP_PKEY_CTX_get0_pkey returns the |EVP_PKEY| associated with |ctx|. */
+EVP_PKEY *EVP_PKEY_CTX_get0_pkey(EVP_PKEY_CTX *ctx);
+
+/* EVP_PKEY_CTX_set_app_data sets an opaque pointer on |ctx|. */
+void EVP_PKEY_CTX_set_app_data(EVP_PKEY_CTX *ctx, void *data);
+
+/* EVP_PKEY_CTX_get_app_data returns the opaque pointer from |ctx| that was
+ * previously set with |EVP_PKEY_CTX_set_app_data|, or NULL if none has been
+ * set. */
+void *EVP_PKEY_CTX_get_app_data(EVP_PKEY_CTX *ctx);
+
+/* EVP_PKEY_CTX_ctrl performs |cmd| on |ctx|. The |keytype| and |optype|
+ * arguments can be -1 to specify that any type and operation are acceptable,
+ * otherwise |keytype| must match the type of |ctx| and the bits of |optype|
+ * must intersect the operation flags set on |ctx|.
+ *
+ * The |p1| and |p2| arguments depend on the value of |cmd|.
+ *
+ * It returns -2 if |cmd| is not recognised, -1 on error or a |cmd| specific
+ * value otherwise. */
+int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype, int cmd,
+ int p1, void *p2);
+
+/* EVP_PKEY_sign_init initialises an |EVP_PKEY_CTX| for a signing operation. It
+ * should be called before |EVP_PKEY_sign|.
+ *
+ * It returns one on success or <= 0 on error. WARNING: this differs from the
+ * usual return value convention. */
+int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx);
+
+/* EVP_PKEY_sign signs |data_len| bytes from |data| using |ctx|. If |sig| is
+ * NULL, the size of the signature is written to |out_sig_len|. Otherwise,
+ * |*sig_len| must contain the number of bytes of space available at |sig|. If
+ * sufficient, the signature will be written to |sig| and |*sig_len| updated
+ * with the true length.
+ *
+ * It returns one on success or zero on error. (Note: this differs from
+ * OpenSSL, which can also return negative values to indicate an error. ) */
+int EVP_PKEY_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *sig_len,
+ const uint8_t *data, size_t data_len);
+
+/* EVP_PKEY_verify_init initialises an |EVP_PKEY_CTX| for a signature
+ * verification operation. It should be called before |EVP_PKEY_verify|.
+ *
+ * It returns one on success or <= 0 on error. WARNING: this differs from the
+ * usual return value convention. */
+int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx);
+
+/* EVP_PKEY_verify verifies that |sig_len| bytes from |sig| are a valid signature
+ * for |data|.
+ *
+ * It returns one on success or zero on error. (Note: this differs from
+ * OpenSSL, which can also return negative values to indicate an error. ) */
+int EVP_PKEY_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, size_t sig_len,
+ const uint8_t *data, size_t data_len);
+
+/* EVP_PKEY_encrypt_init initialises an |EVP_PKEY_CTX| for an encryption
+ * operation. It should be called before |EVP_PKEY_encrypt|.
+ *
+ * It returns one on success or <= 0 on error. WARNING: this differs from the
+ * usual return value convention. */
+int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx);
+
+/* EVP_PKEY_encrypt encrypts |in_len| bytes from |in| and writes it to |out|.
+ * TODO(fork): need more details on |out_len|.
+ *
+ * It returns one on success or <= 0 on error. (Note: this differs from
+ * OpenSSL, which can also return negative values to indicate an error. ) */
+int EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *out_len,
+ const uint8_t *in, size_t in_len);
+
+/* EVP_PKEY_decrypt_init initialises an |EVP_PKEY_CTX| for a decryption
+ * operation. It should be called before |EVP_PKEY_decrypt|.
+ *
+ * It returns one on success or <= 0 on error. WARNING: this differs from the
+ * usual return value convention. */
+int EVP_PKEY_decrypt_init(EVP_PKEY_CTX *ctx);
+
+/* EVP_PKEY_decrypt decrypts |in_len| bytes from |in|, writes it to |out| and
+ * sets |*outlen| to the number of bytes written.
+ *
+ * It returns one on success or <= 0 on error. (Note: this differs from
+ * OpenSSL, which can also return negative values to indicate an error. ) */
+int EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *out_len,
+ const uint8_t *in, size_t in_len);
+
+/* EVP_PKEY_derive_init initialises an |EVP_PKEY_CTX| for a key derivation
+ * operation. It should be called before |EVP_PKEY_derive_set_peer| and
+ * |EVP_PKEY_derive|.
+ *
+ * It returns one on success or <= 0 on error. WARNING: this differs from the
+ * usual return value convention. */
+int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx);
+
+/* EVP_PKEY_derive_set_peer sets the peer's key to be used for key derivation
+ * by |ctx| to |peer|. It should be called after |EVP_PKEY_derive_init|. (For
+ * example, this is used to set the peer's key in (EC)DH.) It returns one on
+ * success and <= 0 on error. WARNING: this differs from the usual return value
+ * convention. */
+int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer);
+
+/* EVP_PKEY_derive derives a shared key between the two keys configured in
+ * |ctx|. If |key| is non-NULL then, on entry, |out_key_len| must contain the
+ * amount of space at |key|. If sufficient then the shared key will be written
+ * to |key| and |*out_key_len| will be set to the length. If |key| is NULL then
+ * |out_key_len| will be set the length.
+ *
+ * It returns one on success and <= 0 on error. WARNING: this differs from the
+ * usual return convention. */
+int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, uint8_t *key, size_t *out_key_len);
+
+/* EVP_PKEY_keygen_init initialises an |EVP_PKEY_CTX| for a key generation
+ * operation. It should be called before |EVP_PKEY_keygen|.
+ *
+ * It returns one on success or <= 0 on error. WARNING: this differs from the
+ * usual return value convention. */
+int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx);
+
+/* EVP_PKEY_keygen performs a key generation operation using the values from
+ * |ctx| and sets |*ppkey| to a fresh |EVP_PKEY| containing the resulting key.
+ * It returns one on success or <= 0 on error. WARNING: this differs from the
+ * normal return value convention. */
+int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey);
+
+
+/* EVP_PKEY_CTX_ctrl operations.
+ *
+ * These values are passed as the |cmd| argument to
+ * EVP_PKEY_CTX_ctrl */
+
+/* Generic. */
+
+/* EVP_PKEY_CTX_set_signature_md sets |md| as the digest to be used in a
+ * signature operation. It returns one on success or otherwise on error. See
+ * the return values of |EVP_PKEY_CTX_ctrl| for details. */
+int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD *md);
+
+/* EVP_PKEY_CTX_get_signature_md sets |*out_md| to the digest to be used in a
+ * signature operation. It returns one on success or otherwise on error. See
+ * the return values of |EVP_PKEY_CTX_ctrl| for details. */
+int EVP_PKEY_CTX_get_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md);
+
+/* 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. */
+#define EVP_PKEY_CTRL_DIGESTINIT 3
+
+/* 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.
+ * If the return value is <= 0, the key is rejected.
+ * 1: Is called at the end of |EVP_PKEY_derive_set_peer| and |p2| contains a
+ * peer key. If the return value is <= 0, the key is rejected.
+ * 2: Is called with |p2| == NULL to test whether the peer's key was used.
+ * (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
+
+/* EVP_PKEY_ALG_CTRL is the base value from which key-type specific ctrl
+ * commands are numbered. */
+#define EVP_PKEY_ALG_CTRL 0x1000
+
+
+/* RSA specific control functions. */
+
+/* EVP_PKEY_CTX_set_rsa_padding sets the padding type to use. It should be one
+ * of the |RSA_*_PADDING| values. Returns one on success or another value on
+ * error. See |EVP_PKEY_CTX_ctrl| for the other return values, which are
+ * non-standard. */
+int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *ctx, int padding);
+
+/* EVP_PKEY_CTX_get_rsa_padding sets |*out_padding| to the current padding
+ * value, which is one of the |RSA_*_PADDING| values. Returns one on success or
+ * another value on error. See |EVP_PKEY_CTX_ctrl| for the other return values,
+ * which are non-standard. */
+int EVP_PKEY_CTX_get_rsa_padding(EVP_PKEY_CTX *ctx, int *out_padding);
+
+/* EVP_PKEY_CTX_set_rsa_pss_saltlen sets the length of the salt in a PSS-padded
+ * signature. A value of -1 cause the salt to be the same length as the digest
+ * in the signature. A value of -2 causes the salt to be the maximum length
+ * that will fit. Otherwise the value gives the size of the salt in bytes.
+ *
+ * Returns one on success or another value on error. See |EVP_PKEY_CTX_ctrl|
+ * for the other return values, which are non-standard. */
+int EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, int salt_len);
+
+/* EVP_PKEY_CTX_get_rsa_pss_saltlen sets |*out_salt_len| to the salt length of
+ * a PSS-padded signature. See the documentation for
+ * |EVP_PKEY_CTX_set_rsa_pss_saltlen| for details of the special values that it
+ * can take.
+ *
+ * Returns one on success or another value on error. See |EVP_PKEY_CTX_ctrl|
+ * for the other return values, which are non-standard. */
+int EVP_PKEY_CTX_get_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, int *out_salt_len);
+
+/* EVP_PKEY_CTX_set_rsa_keygen_bits sets the size of the desired RSA modulus,
+ * in bits, for key generation. Returns one on success or another value on
+ * error. See |EVP_PKEY_CTX_ctrl| for the other return values, which are
+ * non-standard. */
+int EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX *ctx, int bits);
+
+/* EVP_PKEY_CTX_set_rsa_keygen_pubexp sets |e| as the public exponent for key
+ * generation. Returns one on success or another value on error. See
+ * |EVP_PKEY_CTX_ctrl| for the other return values, which are non-standard. */
+int EVP_PKEY_CTX_set_rsa_keygen_pubexp(EVP_PKEY_CTX *ctx, BIGNUM *e);
+
+/* EVP_PKEY_CTX_set_rsa_oaep_md sets |md| as the digest used in OAEP padding.
+ * Returns one on success or another value on error. See |EVP_PKEY_CTX_ctrl|
+ * for the other return values, which are non-standard. */
+int EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD *md);
+
+/* EVP_PKEY_CTX_get_rsa_oaep_md sets |*out_md| to the digest function used in
+ * OAEP padding. Returns one on success or another value on error. See
+ * |EVP_PKEY_CTX_ctrl| for the other return values, which are non-standard. */
+int EVP_PKEY_CTX_get_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md);
+
+/* EVP_PKEY_CTX_set_rsa_mgf1_md sets |md| as the digest used in MGF1. Returns
+ * one on success or another value on error. See |EVP_PKEY_CTX_ctrl| for the
+ * other return values, which are non-standard. */
+int EVP_PKEY_CTX_set_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD *md);
+
+/* EVP_PKEY_CTX_get_rsa_mgf1_md sets |*out_md| to the digest function used in
+ * MGF1. Returns one on success or another value on error. See
+ * |EVP_PKEY_CTX_ctrl| for the other return values, which are non-standard. */
+int EVP_PKEY_CTX_get_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md);
+
+/* EVP_PKEY_CTX_set0_rsa_oaep_label sets |label_len| bytes from |label| as the
+ * label used in OAEP. DANGER: this call takes ownership of |label| and will
+ * call |free| on it when |ctx| is destroyed.
+ *
+ * Returns one on success or another value on error. See |EVP_PKEY_CTX_ctrl|
+ * for the other return values, which are non-standard. */
+int EVP_PKEY_CTX_set0_rsa_oaep_label(EVP_PKEY_CTX *ctx, const uint8_t *label,
+ size_t label_len);
+
+/* EVP_PKEY_CTX_get0_rsa_oaep_label sets |*out_label| to point to the internal
+ * buffer containing the OAEP label (which may be NULL) and returns the length
+ * of the label or a negative value on error. */
+int EVP_PKEY_CTX_get0_rsa_oaep_label(EVP_PKEY_CTX *ctx,
+ const uint8_t **out_label);
+
+
+/* EC specific */
+
+#define EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID (EVP_PKEY_ALG_CTRL + 1)
+#define EVP_PKEY_CTRL_EC_PARAM_ENC (EVP_PKEY_ALG_CTRL + 2)
+#define EVP_PKEY_CTRL_EC_ECDH_COFACTOR (EVP_PKEY_ALG_CTRL + 3)
+#define EVP_PKEY_CTRL_EC_KDF_TYPE (EVP_PKEY_ALG_CTRL + 4)
+#define EVP_PKEY_CTRL_EC_KDF_MD (EVP_PKEY_ALG_CTRL + 5)
+#define EVP_PKEY_CTRL_GET_EC_KDF_MD (EVP_PKEY_ALG_CTRL + 6)
+#define EVP_PKEY_CTRL_EC_KDF_OUTLEN (EVP_PKEY_ALG_CTRL + 7)
+#define EVP_PKEY_CTRL_GET_EC_KDF_OUTLEN (EVP_PKEY_ALG_CTRL + 8)
+#define EVP_PKEY_CTRL_EC_KDF_UKM (EVP_PKEY_ALG_CTRL + 9)
+#define EVP_PKEY_CTRL_GET_EC_KDF_UKM (EVP_PKEY_ALG_CTRL + 10)
+
+#define EVP_PKEY_ECDH_KDF_NONE 1
+#define EVP_PKEY_ECDH_KDF_X9_62 2
+
+
+/* PKEY ctrl commands.
+ *
+ * These values are passed as the |op| argument to
+ * EVP_PKEY_ASN1_METHOD.pkey_ctrl. */
+
+/* ASN1_PKEY_CTRL_DEFAULT_MD_NID expects |arg2| to be an |int*| and sets the
+ * pointed at int to be the NID of the default hash function used in
+ * signing. */
+#define ASN1_PKEY_CTRL_DEFAULT_MD_NID 0x3
+
+
+/* Private functions */
+
+/* OpenSSL_add_all_algorithms does nothing. */
+void OpenSSL_add_all_algorithms();
+
+/* EVP_cleanup does nothing. */
+void EVP_cleanup();
+
+/* EVP_PKEY_asn1_find returns the ASN.1 method table for the given |nid|, which
+ * should be one of the |EVP_PKEY_*| values. It returns NULL if |nid| is
+ * unknown. */
+const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(ENGINE **pengine, int nid);
+
+/* TODO(fork): move to PEM? */
+const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find_str(ENGINE **pengine,
+ const char *name,
+ size_t len);
+
+struct evp_pkey_st {
+ int references;
+
+ /* type contains one of the EVP_PKEY_* values or NID_undef and determines
+ * which element (if any) of the |pkey| union is valid. */
+ int type;
+
+ /* TODO(fork): document */
+ int save_type;
+
+ union {
+ char *ptr;
+ struct rsa_st *rsa; /* RSA */
+ struct dsa_st *dsa; /* DSA */
+ struct dh_st *dh; /* DH */
+ struct ec_key_st *ec; /* ECC */
+ } pkey;
+
+ ENGINE *engine;
+
+ /* TODO(fork): document */
+ int save_parameters;
+ /* ameth contains a pointer to a method table that contains many ASN.1
+ * methods for the key type. */
+ const EVP_PKEY_ASN1_METHOD *ameth;
+
+ /* TODO(fork): document; */
+ STACK_OF(X509_ATTRIBUTE) * attributes; /* [ 0 ] */
+} /* EVP_PKEY */;
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#define EVP_F_rsa_item_verify 100
+#define EVP_F_do_sigver_init 101
+#define EVP_F_eckey_priv_decode 102
+#define EVP_F_pkey_ec_sign 103
+#define EVP_F_EVP_PKEY_sign_init 104
+#define EVP_F_d2i_PrivateKey 105
+#define EVP_F_rsa_priv_encode 106
+#define EVP_F_rsa_mgf1_to_md 107
+#define EVP_F_EVP_PKEY_get1_DH 108
+#define EVP_F_EVP_PKEY_sign 109
+#define EVP_F_old_ec_priv_decode 110
+#define EVP_F_EVP_PKEY_get1_RSA 111
+#define EVP_F_pkey_ec_ctrl 112
+#define EVP_F_evp_pkey_ctx_new 113
+#define EVP_F_EVP_PKEY_verify 114
+#define EVP_F_EVP_PKEY_encrypt 115
+#define EVP_F_EVP_PKEY_keygen 116
+#define EVP_F_eckey_type2param 117
+#define EVP_F_eckey_priv_encode 118
+#define EVP_F_do_EC_KEY_print 119
+#define EVP_F_pkey_ec_keygen 120
+#define EVP_F_EVP_PKEY_encrypt_init 121
+#define EVP_F_pkey_rsa_ctrl 122
+#define EVP_F_rsa_priv_decode 123
+#define EVP_F_rsa_pss_to_ctx 124
+#define EVP_F_EVP_PKEY_get1_EC_KEY 125
+#define EVP_F_EVP_PKEY_verify_init 126
+#define EVP_F_EVP_PKEY_derive_init 127
+#define EVP_F_eckey_param2type 128
+#define EVP_F_eckey_pub_decode 129
+#define EVP_F_d2i_AutoPrivateKey 130
+#define EVP_F_eckey_param_decode 131
+#define EVP_F_EVP_PKEY_new 132
+#define EVP_F_pkey_ec_derive 133
+#define EVP_F_pkey_ec_paramgen 134
+#define EVP_F_EVP_PKEY_CTX_ctrl 135
+#define EVP_F_EVP_PKEY_decrypt_init 136
+#define EVP_F_EVP_PKEY_decrypt 137
+#define EVP_F_EVP_PKEY_copy_parameters 138
+#define EVP_F_EVP_PKEY_set_type 139
+#define EVP_F_EVP_PKEY_derive 140
+#define EVP_F_EVP_PKEY_keygen_init 141
+#define EVP_F_do_rsa_print 142
+#define EVP_F_old_rsa_priv_decode 143
+#define EVP_F_rsa_algor_to_md 144
+#define EVP_F_eckey_pub_encode 145
+#define EVP_F_EVP_PKEY_derive_set_peer 146
+#define EVP_F_pkey_rsa_sign 147
+#define EVP_F_check_padding_md 148
+#define EVP_F_i2d_PublicKey 149
+#define EVP_F_rsa_pub_decode 150
+#define EVP_F_EVP_PKEY_get1_DSA 151
+#define EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE 100
+#define EVP_R_UNSUPPORTED_SIGNATURE_TYPE 101
+#define EVP_R_INVALID_DIGEST_TYPE 102
+#define EVP_R_EXPECTING_A_DH_KEY 103
+#define EVP_R_OPERATON_NOT_INITIALIZED 104
+#define EVP_R_MISSING_PARAMETERS 105
+#define EVP_R_NO_DEFAULT_DIGEST 106
+#define EVP_R_UNKNOWN_DIGEST 107
+#define EVP_R_KEYS_NOT_SET 108
+#define EVP_R_X931_UNSUPPORTED 109
+#define EVP_R_DIGEST_DOES_NOT_MATCH 110
+#define EVP_R_DIFFERENT_PARAMETERS 111
+#define EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE 112
+#define EVP_R_DIFFERENT_KEY_TYPES 113
+#define EVP_R_NO_PARAMETERS_SET 114
+#define EVP_R_NO_NID_FOR_CURVE 115
+#define EVP_R_NO_OPERATION_SET 116
+#define EVP_R_UNSUPPORTED_ALGORITHM 117
+#define EVP_R_EXPECTING_AN_DSA_KEY 118
+#define EVP_R_UNKNOWN_MASK_DIGEST 119
+#define EVP_R_INVALID_SALT_LENGTH 120
+#define EVP_R_BUFFER_TOO_SMALL 121
+#define EVP_R_INVALID_PADDING_MODE 122
+#define EVP_R_INVALID_MGF1_MD 123
+#define EVP_R_SHARED_INFO_ERROR 124
+#define EVP_R_INVALID_KEYBITS 125
+#define EVP_R_PEER_KEY_ERROR 126
+#define EVP_R_EXPECTING_A_DSA_KEY 127
+#define EVP_R_UNSUPPORTED_MASK_ALGORITHM 128
+#define EVP_R_EXPECTING_AN_EC_KEY_KEY 129
+#define EVP_R_INVALID_TRAILER 130
+#define EVP_R_INVALID_DIGEST_LENGTH 131
+#define EVP_R_COMMAND_NOT_SUPPORTED 132
+#define EVP_R_EXPLICIT_EC_PARAMETERS_NOT_SUPPORTED 133
+#define EVP_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE 134
+#define EVP_R_NO_MDC2_SUPPORT 135
+#define EVP_R_INVALID_CURVE 136
+#define EVP_R_NO_KEY_SET 137
+#define EVP_R_INVALID_PSS_PARAMETERS 138
+#define EVP_R_KDF_PARAMETER_ERROR 139
+#define EVP_R_UNSUPPORTED_MASK_PARAMETER 140
+#define EVP_R_EXPECTING_AN_RSA_KEY 141
+#define EVP_R_INVALID_OPERATION 142
+#define EVP_R_DECODE_ERROR 143
+#define EVP_R_INVALID_PSS_SALTLEN 144
+#define EVP_R_UNKNOWN_PUBLIC_KEY_TYPE 145
+
+#endif /* OPENSSL_HEADER_EVP_H */
diff --git a/crypto/evp/evp_ctx.c b/crypto/evp/evp_ctx.c
new file mode 100644
index 0000000..5c3755a
--- /dev/null
+++ b/crypto/evp/evp_ctx.c
@@ -0,0 +1,548 @@
+/* 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/evp.h>
+
+#include <stdio.h>
+
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+
+#include "internal.h"
+
+
+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 *evp_methods[] = {
+ &rsa_pkey_meth,
+ &hmac_pkey_meth,
+ &ec_pkey_meth,
+};
+
+static const EVP_PKEY_METHOD *evp_pkey_meth_find(int type) {
+ unsigned i;
+
+ for (i = 0; i < sizeof(evp_methods)/sizeof(EVP_PKEY_METHOD*); i++) {
+ if (evp_methods[i]->pkey_id == type) {
+ return evp_methods[i];
+ }
+ }
+
+ return NULL;
+}
+
+static EVP_PKEY_CTX *evp_pkey_ctx_new(EVP_PKEY *pkey, ENGINE *e, int id) {
+ EVP_PKEY_CTX *ret;
+ const EVP_PKEY_METHOD *pmeth;
+
+ if (id == -1) {
+ if (!pkey || !pkey->ameth) {
+ return NULL;
+ }
+ id = pkey->ameth->pkey_id;
+ }
+
+ pmeth = evp_pkey_meth_find(id);
+
+ if (pmeth == NULL) {
+ OPENSSL_PUT_ERROR(EVP, evp_pkey_ctx_new, EVP_R_UNSUPPORTED_ALGORITHM);
+ const char *name = OBJ_nid2sn(id);
+ ERR_add_error_dataf("algorithm %d (%s)", id, name);
+ return NULL;
+ }
+
+ ret = OPENSSL_malloc(sizeof(EVP_PKEY_CTX));
+ if (!ret) {
+ OPENSSL_PUT_ERROR(EVP, evp_pkey_ctx_new, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ memset(ret, 0, sizeof(EVP_PKEY_CTX));
+
+ ret->engine = e;
+ ret->pmeth = pmeth;
+ ret->operation = EVP_PKEY_OP_UNDEFINED;
+
+ if (pkey) {
+ ret->pkey = pkey;
+ CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
+ }
+
+ if (pmeth->init) {
+ if (pmeth->init(ret) <= 0) {
+ EVP_PKEY_CTX_free(ret);
+ return NULL;
+ }
+ }
+
+ return ret;
+}
+
+EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e) {
+ return evp_pkey_ctx_new(pkey, e, -1);
+}
+
+EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int id, ENGINE *e) {
+ return evp_pkey_ctx_new(NULL, e, id);
+}
+
+void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx) {
+ if (ctx == NULL) {
+ return;
+ }
+ if (ctx->pmeth && ctx->pmeth->cleanup) {
+ ctx->pmeth->cleanup(ctx);
+ }
+ if (ctx->pkey) {
+ EVP_PKEY_free(ctx->pkey);
+ }
+ if (ctx->peerkey) {
+ EVP_PKEY_free(ctx->peerkey);
+ }
+ OPENSSL_free(ctx);
+}
+
+EVP_PKEY_CTX *EVP_PKEY_CTX_dup(EVP_PKEY_CTX *pctx) {
+ EVP_PKEY_CTX *rctx;
+
+ if (!pctx->pmeth || !pctx->pmeth->copy) {
+ return NULL;
+ }
+
+ rctx = OPENSSL_malloc(sizeof(EVP_PKEY_CTX));
+ if (!rctx) {
+ return NULL;
+ }
+
+ memset(rctx, 0, sizeof(EVP_PKEY_CTX));
+
+ rctx->pmeth = pctx->pmeth;
+ rctx->engine = pctx->engine;
+ rctx->operation = pctx->operation;
+
+ if (pctx->pkey) {
+ CRYPTO_add(&pctx->pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
+ }
+ rctx->pkey = pctx->pkey;
+
+ if (pctx->peerkey) {
+ CRYPTO_add(&pctx->peerkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
+ }
+ rctx->peerkey = pctx->peerkey;
+
+ if (pctx->pmeth->copy(rctx, pctx) > 0) {
+ return rctx;
+ }
+
+ EVP_PKEY_CTX_free(rctx);
+ return NULL;
+}
+
+EVP_PKEY *EVP_PKEY_CTX_get0_pkey(EVP_PKEY_CTX *ctx) { return ctx->pkey; }
+
+void EVP_PKEY_CTX_set_app_data(EVP_PKEY_CTX *ctx, void *data) {
+ ctx->app_data = data;
+}
+
+void *EVP_PKEY_CTX_get_app_data(EVP_PKEY_CTX *ctx) { return ctx->app_data; }
+
+int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype, int cmd,
+ int p1, void *p2) {
+ int ret;
+ if (!ctx || !ctx->pmeth || !ctx->pmeth->ctrl) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_CTX_ctrl, EVP_R_COMMAND_NOT_SUPPORTED);
+ return -2;
+ }
+ if (keytype != -1 && ctx->pmeth->pkey_id != keytype) {
+ return -1;
+ }
+
+ if (ctx->operation == EVP_PKEY_OP_UNDEFINED) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_CTX_ctrl, EVP_R_NO_OPERATION_SET);
+ return -1;
+ }
+
+ if (optype != -1 && !(ctx->operation & optype)) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_CTX_ctrl, EVP_R_INVALID_OPERATION);
+ return -1;
+ }
+
+ ret = ctx->pmeth->ctrl(ctx, cmd, p1, p2);
+
+ if (ret == -2) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_CTX_ctrl, EVP_R_COMMAND_NOT_SUPPORTED);
+ }
+
+ return ret;
+}
+
+int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx) {
+ int ret;
+ if (!ctx || !ctx->pmeth || !ctx->pmeth->sign) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_sign_init,
+ EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+ return 0;
+ }
+
+ ctx->operation = EVP_PKEY_OP_SIGN;
+ if (!ctx->pmeth->sign_init) {
+ return 1;
+ }
+
+ ret = ctx->pmeth->sign_init(ctx);
+ /* TODO(fork): normalise the return value convention. */
+ if (ret <= 0) {
+ ctx->operation = EVP_PKEY_OP_UNDEFINED;
+ return 0;
+ }
+
+ return ret;
+}
+
+static int check_autoarg(const EVP_PKEY_CTX *ctx, const uint8_t *arg,
+ size_t *arg_len) {
+ size_t size;
+
+ if (0 == (ctx->pmeth->flags & EVP_PKEY_FLAG_AUTOARGLEN)) {
+ return 1;
+ }
+
+ size = EVP_PKEY_size(ctx->pkey);
+ if (arg == NULL) {
+ *arg_len = size;
+ return 1;
+ }
+
+ if (*arg_len < size) {
+ return 0;
+ }
+
+ return 1;
+}
+
+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);
+ return 0;
+ }
+ if (ctx->operation != EVP_PKEY_OP_SIGN) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_sign, EVP_R_OPERATON_NOT_INITIALIZED);
+ return 0;
+ }
+ if (!check_autoarg(ctx, sig, sig_len)) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_sign,
+ EVP_R_BUFFER_TOO_SMALL);
+ return 0;
+ }
+ return ctx->pmeth->sign(ctx, sig, sig_len, data, data_len);
+}
+
+int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx) {
+ int ret;
+
+ if (!ctx || !ctx->pmeth || !ctx->pmeth->verify) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_verify_init,
+ EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+ return -2;
+ }
+ ctx->operation = EVP_PKEY_OP_VERIFY;
+ if (!ctx->pmeth->verify_init) {
+ return 1;
+ }
+ ret = ctx->pmeth->verify_init(ctx);
+ if (ret <= 0) {
+ ctx->operation = EVP_PKEY_OP_UNDEFINED;
+ }
+ return ret;
+}
+
+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);
+ return -2;
+ }
+ if (ctx->operation != EVP_PKEY_OP_VERIFY) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_verify, EVP_R_OPERATON_NOT_INITIALIZED);
+ return -1;
+ }
+ return ctx->pmeth->verify(ctx, sig, sig_len, data, data_len);
+}
+
+int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx) {
+ int ret;
+ if (!ctx || !ctx->pmeth || !ctx->pmeth->encrypt) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_encrypt_init,
+ EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+ return -2;
+ }
+ ctx->operation = EVP_PKEY_OP_ENCRYPT;
+ if (!ctx->pmeth->encrypt_init) {
+ return 1;
+ }
+ ret = ctx->pmeth->encrypt_init(ctx);
+ if (ret <= 0) {
+ ctx->operation = EVP_PKEY_OP_UNDEFINED;
+ }
+ return ret;
+}
+
+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);
+ return -2;
+ }
+ if (ctx->operation != EVP_PKEY_OP_ENCRYPT) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_encrypt, EVP_R_OPERATON_NOT_INITIALIZED);
+ return -1;
+ }
+ if (!check_autoarg(ctx, out, outlen)) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_encrypt, EVP_R_BUFFER_TOO_SMALL);
+ return 0;
+ }
+ return ctx->pmeth->encrypt(ctx, out, outlen, in, inlen);
+}
+
+int EVP_PKEY_decrypt_init(EVP_PKEY_CTX *ctx) {
+ int ret;
+
+ if (!ctx || !ctx->pmeth || !ctx->pmeth->decrypt) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_decrypt_init,
+ EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+ return -2;
+ }
+ ctx->operation = EVP_PKEY_OP_DECRYPT;
+ if (!ctx->pmeth->decrypt_init) {
+ return 1;
+ }
+ ret = ctx->pmeth->decrypt_init(ctx);
+ if (ret <= 0) {
+ ctx->operation = EVP_PKEY_OP_UNDEFINED;
+ }
+ return ret;
+}
+
+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);
+ return -2;
+ }
+ if (ctx->operation != EVP_PKEY_OP_DECRYPT) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_decrypt, EVP_R_OPERATON_NOT_INITIALIZED);
+ return -1;
+ }
+ if (!check_autoarg(ctx, out, outlen)) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_decrypt, EVP_R_BUFFER_TOO_SMALL);
+ return 0;
+ }
+ return ctx->pmeth->decrypt(ctx, out, outlen, in, inlen);
+}
+
+int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx) {
+ int ret;
+ if (!ctx || !ctx->pmeth || !ctx->pmeth->derive) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_derive_init,
+ EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+ return -2;
+ }
+ ctx->operation = EVP_PKEY_OP_DERIVE;
+ if (!ctx->pmeth->derive_init) {
+ return 1;
+ }
+ ret = ctx->pmeth->derive_init(ctx);
+ if (ret <= 0) {
+ ctx->operation = EVP_PKEY_OP_UNDEFINED;
+ }
+ return ret;
+}
+
+int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer) {
+ int ret;
+ 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);
+ return -2;
+ }
+ 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);
+ return -1;
+ }
+
+ ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 0, peer);
+
+ if (ret <= 0) {
+ return ret;
+ }
+
+ if (ret == 2) {
+ return 1;
+ }
+
+ if (!ctx->pkey) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_derive_set_peer, EVP_R_NO_KEY_SET);
+ return -1;
+ }
+
+ if (ctx->pkey->type != peer->type) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_derive_set_peer, EVP_R_DIFFERENT_KEY_TYPES);
+ return -1;
+ }
+
+ /* ran@cryptocom.ru: For clarity. The error is if parameters in peer are
+ * present (!missing) but don't match. EVP_PKEY_cmp_parameters may return
+ * 1 (match), 0 (don't match) and -2 (comparison is not defined). -1
+ * (different key types) is impossible here because it is checked earlier.
+ * -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);
+ return -1;
+ }
+
+ if (ctx->peerkey) {
+ EVP_PKEY_free(ctx->peerkey);
+ }
+ ctx->peerkey = peer;
+
+ ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 1, peer);
+
+ if (ret <= 0) {
+ ctx->peerkey = NULL;
+ return ret;
+ }
+
+ CRYPTO_add(&peer->references, 1, CRYPTO_LOCK_EVP_PKEY);
+ return 1;
+}
+
+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);
+ return -2;
+ }
+ if (ctx->operation != EVP_PKEY_OP_DERIVE) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_derive, EVP_R_OPERATON_NOT_INITIALIZED);
+ return -1;
+ }
+ if (!check_autoarg(ctx, key, out_key_len)) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_derive, EVP_R_BUFFER_TOO_SMALL);
+ return 0;
+ }
+ return ctx->pmeth->derive(ctx, key, out_key_len);
+}
+
+int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx) {
+ int ret;
+ if (!ctx || !ctx->pmeth || !ctx->pmeth->keygen) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_keygen_init,
+ EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+ return -2;
+ }
+ ctx->operation = EVP_PKEY_OP_KEYGEN;
+ if (!ctx->pmeth->keygen_init) {
+ return 1;
+ }
+ ret = ctx->pmeth->keygen_init(ctx);
+ if (ret <= 0) {
+ ctx->operation = EVP_PKEY_OP_UNDEFINED;
+ }
+ return ret;
+}
+
+int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey) {
+ int ret;
+
+ if (!ctx || !ctx->pmeth || !ctx->pmeth->keygen) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_keygen,
+ EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+ return -2;
+ }
+ if (ctx->operation != EVP_PKEY_OP_KEYGEN) {
+ OPENSSL_PUT_ERROR(EVP, EVP_PKEY_keygen, EVP_R_OPERATON_NOT_INITIALIZED);
+ return -1;
+ }
+
+ if (!ppkey) {
+ return -1;
+ }
+
+ if (!*ppkey) {
+ *ppkey = EVP_PKEY_new();
+ }
+
+ ret = ctx->pmeth->keygen(ctx, *ppkey);
+ if (ret <= 0) {
+ EVP_PKEY_free(*ppkey);
+ *ppkey = NULL;
+ }
+ return ret;
+}
diff --git a/crypto/evp/evp_error.c b/crypto/evp/evp_error.c
new file mode 100644
index 0000000..0b4d2f2
--- /dev/null
+++ b/crypto/evp/evp_error.c
@@ -0,0 +1,119 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/err.h>
+
+#include "evp.h"
+
+const ERR_STRING_DATA EVP_error_string_data[] = {
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_CTX_ctrl, 0), "EVP_PKEY_CTX_ctrl"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_copy_parameters, 0), "EVP_PKEY_copy_parameters"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_decrypt, 0), "EVP_PKEY_decrypt"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_decrypt_init, 0), "EVP_PKEY_decrypt_init"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_derive, 0), "EVP_PKEY_derive"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_derive_init, 0), "EVP_PKEY_derive_init"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_derive_set_peer, 0), "EVP_PKEY_derive_set_peer"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_encrypt, 0), "EVP_PKEY_encrypt"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_encrypt_init, 0), "EVP_PKEY_encrypt_init"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_get1_DH, 0), "EVP_PKEY_get1_DH"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_get1_DSA, 0), "EVP_PKEY_get1_DSA"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_get1_EC_KEY, 0), "EVP_PKEY_get1_EC_KEY"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_get1_RSA, 0), "EVP_PKEY_get1_RSA"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_keygen, 0), "EVP_PKEY_keygen"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_keygen_init, 0), "EVP_PKEY_keygen_init"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_new, 0), "EVP_PKEY_new"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_set_type, 0), "EVP_PKEY_set_type"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_sign, 0), "EVP_PKEY_sign"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_sign_init, 0), "EVP_PKEY_sign_init"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_verify, 0), "EVP_PKEY_verify"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_verify_init, 0), "EVP_PKEY_verify_init"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_check_padding_md, 0), "check_padding_md"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_d2i_AutoPrivateKey, 0), "d2i_AutoPrivateKey"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_d2i_PrivateKey, 0), "d2i_PrivateKey"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_do_EC_KEY_print, 0), "do_EC_KEY_print"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_do_rsa_print, 0), "do_rsa_print"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_do_sigver_init, 0), "do_sigver_init"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_eckey_param2type, 0), "eckey_param2type"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_eckey_param_decode, 0), "eckey_param_decode"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_eckey_priv_decode, 0), "eckey_priv_decode"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_eckey_priv_encode, 0), "eckey_priv_encode"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_eckey_pub_decode, 0), "eckey_pub_decode"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_eckey_pub_encode, 0), "eckey_pub_encode"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_eckey_type2param, 0), "eckey_type2param"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_evp_pkey_ctx_new, 0), "evp_pkey_ctx_new"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_i2d_PublicKey, 0), "i2d_PublicKey"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_old_ec_priv_decode, 0), "old_ec_priv_decode"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_old_rsa_priv_decode, 0), "old_rsa_priv_decode"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_pkey_ec_ctrl, 0), "pkey_ec_ctrl"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_pkey_ec_derive, 0), "pkey_ec_derive"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_pkey_ec_keygen, 0), "pkey_ec_keygen"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_pkey_ec_paramgen, 0), "pkey_ec_paramgen"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_pkey_ec_sign, 0), "pkey_ec_sign"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_pkey_rsa_ctrl, 0), "pkey_rsa_ctrl"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_pkey_rsa_sign, 0), "pkey_rsa_sign"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_rsa_algor_to_md, 0), "rsa_algor_to_md"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_rsa_item_verify, 0), "rsa_item_verify"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_rsa_mgf1_to_md, 0), "rsa_mgf1_to_md"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_rsa_priv_decode, 0), "rsa_priv_decode"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_rsa_priv_encode, 0), "rsa_priv_encode"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_rsa_pss_to_ctx, 0), "rsa_pss_to_ctx"},
+ {ERR_PACK(ERR_LIB_EVP, EVP_F_rsa_pub_decode, 0), "rsa_pub_decode"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_BUFFER_TOO_SMALL), "BUFFER_TOO_SMALL"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_COMMAND_NOT_SUPPORTED), "COMMAND_NOT_SUPPORTED"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DECODE_ERROR), "DECODE_ERROR"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DIFFERENT_KEY_TYPES), "DIFFERENT_KEY_TYPES"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DIFFERENT_PARAMETERS), "DIFFERENT_PARAMETERS"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DIGEST_DOES_NOT_MATCH), "DIGEST_DOES_NOT_MATCH"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_AN_DSA_KEY), "EXPECTING_AN_DSA_KEY"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_AN_EC_KEY_KEY), "EXPECTING_AN_EC_KEY_KEY"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_AN_RSA_KEY), "EXPECTING_AN_RSA_KEY"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_A_DH_KEY), "EXPECTING_A_DH_KEY"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPECTING_A_DSA_KEY), "EXPECTING_A_DSA_KEY"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_EXPLICIT_EC_PARAMETERS_NOT_SUPPORTED), "EXPLICIT_EC_PARAMETERS_NOT_SUPPORTED"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE), "ILLEGAL_OR_UNSUPPORTED_PADDING_MODE"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_CURVE), "INVALID_CURVE"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_DIGEST_LENGTH), "INVALID_DIGEST_LENGTH"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_DIGEST_TYPE), "INVALID_DIGEST_TYPE"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_KEYBITS), "INVALID_KEYBITS"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_MGF1_MD), "INVALID_MGF1_MD"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_OPERATION), "INVALID_OPERATION"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_PADDING_MODE), "INVALID_PADDING_MODE"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_PSS_PARAMETERS), "INVALID_PSS_PARAMETERS"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_PSS_SALTLEN), "INVALID_PSS_SALTLEN"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_SALT_LENGTH), "INVALID_SALT_LENGTH"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_INVALID_TRAILER), "INVALID_TRAILER"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_KDF_PARAMETER_ERROR), "KDF_PARAMETER_ERROR"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_KEYS_NOT_SET), "KEYS_NOT_SET"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_MISSING_PARAMETERS), "MISSING_PARAMETERS"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_DEFAULT_DIGEST), "NO_DEFAULT_DIGEST"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_KEY_SET), "NO_KEY_SET"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_MDC2_SUPPORT), "NO_MDC2_SUPPORT"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_NID_FOR_CURVE), "NO_NID_FOR_CURVE"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_OPERATION_SET), "NO_OPERATION_SET"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_PARAMETERS_SET), "NO_PARAMETERS_SET"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE), "OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_OPERATON_NOT_INITIALIZED), "OPERATON_NOT_INITIALIZED"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_PEER_KEY_ERROR), "PEER_KEY_ERROR"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_SHARED_INFO_ERROR), "SHARED_INFO_ERROR"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNKNOWN_DIGEST), "UNKNOWN_DIGEST"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNKNOWN_MASK_DIGEST), "UNKNOWN_MASK_DIGEST"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNKNOWN_PUBLIC_KEY_TYPE), "UNKNOWN_PUBLIC_KEY_TYPE"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_ALGORITHM), "UNSUPPORTED_ALGORITHM"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_MASK_ALGORITHM), "UNSUPPORTED_MASK_ALGORITHM"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_MASK_PARAMETER), "UNSUPPORTED_MASK_PARAMETER"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE), "UNSUPPORTED_PUBLIC_KEY_TYPE"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_SIGNATURE_TYPE), "UNSUPPORTED_SIGNATURE_TYPE"},
+ {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_X931_UNSUPPORTED), "X931_UNSUPPORTED"},
+ {0, NULL},
+};
diff --git a/crypto/evp/example_sign.c b/crypto/evp/example_sign.c
new file mode 100644
index 0000000..4bbe194
--- /dev/null
+++ b/crypto/evp/example_sign.c
@@ -0,0 +1,198 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <openssl/bio.h>
+#include <openssl/digest.h>
+#include <openssl/evp.h>
+#include <openssl/rsa.h>
+
+
+/* kExampleRSAKeyDER is an RSA private key in ASN.1, DER format. Of course, you
+ * should never use this key anywhere but in an example. */
+static const uint8_t kExampleRSAKeyDER[] = {
+ 0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xf8,
+ 0xb8, 0x6c, 0x83, 0xb4, 0xbc, 0xd9, 0xa8, 0x57, 0xc0, 0xa5, 0xb4, 0x59,
+ 0x76, 0x8c, 0x54, 0x1d, 0x79, 0xeb, 0x22, 0x52, 0x04, 0x7e, 0xd3, 0x37,
+ 0xeb, 0x41, 0xfd, 0x83, 0xf9, 0xf0, 0xa6, 0x85, 0x15, 0x34, 0x75, 0x71,
+ 0x5a, 0x84, 0xa8, 0x3c, 0xd2, 0xef, 0x5a, 0x4e, 0xd3, 0xde, 0x97, 0x8a,
+ 0xdd, 0xff, 0xbb, 0xcf, 0x0a, 0xaa, 0x86, 0x92, 0xbe, 0xb8, 0x50, 0xe4,
+ 0xcd, 0x6f, 0x80, 0x33, 0x30, 0x76, 0x13, 0x8f, 0xca, 0x7b, 0xdc, 0xec,
+ 0x5a, 0xca, 0x63, 0xc7, 0x03, 0x25, 0xef, 0xa8, 0x8a, 0x83, 0x58, 0x76,
+ 0x20, 0xfa, 0x16, 0x77, 0xd7, 0x79, 0x92, 0x63, 0x01, 0x48, 0x1a, 0xd8,
+ 0x7b, 0x67, 0xf1, 0x52, 0x55, 0x49, 0x4e, 0xd6, 0x6e, 0x4a, 0x5c, 0xd7,
+ 0x7a, 0x37, 0x36, 0x0c, 0xde, 0xdd, 0x8f, 0x44, 0xe8, 0xc2, 0xa7, 0x2c,
+ 0x2b, 0xb5, 0xaf, 0x64, 0x4b, 0x61, 0x07, 0x02, 0x03, 0x01, 0x00, 0x01,
+ 0x02, 0x81, 0x80, 0x74, 0x88, 0x64, 0x3f, 0x69, 0x45, 0x3a, 0x6d, 0xc7,
+ 0x7f, 0xb9, 0xa3, 0xc0, 0x6e, 0xec, 0xdc, 0xd4, 0x5a, 0xb5, 0x32, 0x85,
+ 0x5f, 0x19, 0xd4, 0xf8, 0xd4, 0x3f, 0x3c, 0xfa, 0xc2, 0xf6, 0x5f, 0xee,
+ 0xe6, 0xba, 0x87, 0x74, 0x2e, 0xc7, 0x0c, 0xd4, 0x42, 0xb8, 0x66, 0x85,
+ 0x9c, 0x7b, 0x24, 0x61, 0xaa, 0x16, 0x11, 0xf6, 0xb5, 0xb6, 0xa4, 0x0a,
+ 0xc9, 0x55, 0x2e, 0x81, 0xa5, 0x47, 0x61, 0xcb, 0x25, 0x8f, 0xc2, 0x15,
+ 0x7b, 0x0e, 0x7c, 0x36, 0x9f, 0x3a, 0xda, 0x58, 0x86, 0x1c, 0x5b, 0x83,
+ 0x79, 0xe6, 0x2b, 0xcc, 0xe6, 0xfa, 0x2c, 0x61, 0xf2, 0x78, 0x80, 0x1b,
+ 0xe2, 0xf3, 0x9d, 0x39, 0x2b, 0x65, 0x57, 0x91, 0x3d, 0x71, 0x99, 0x73,
+ 0xa5, 0xc2, 0x79, 0x20, 0x8c, 0x07, 0x4f, 0xe5, 0xb4, 0x60, 0x1f, 0x99,
+ 0xa2, 0xb1, 0x4f, 0x0c, 0xef, 0xbc, 0x59, 0x53, 0x00, 0x7d, 0xb1, 0x02,
+ 0x41, 0x00, 0xfc, 0x7e, 0x23, 0x65, 0x70, 0xf8, 0xce, 0xd3, 0x40, 0x41,
+ 0x80, 0x6a, 0x1d, 0x01, 0xd6, 0x01, 0xff, 0xb6, 0x1b, 0x3d, 0x3d, 0x59,
+ 0x09, 0x33, 0x79, 0xc0, 0x4f, 0xde, 0x96, 0x27, 0x4b, 0x18, 0xc6, 0xd9,
+ 0x78, 0xf1, 0xf4, 0x35, 0x46, 0xe9, 0x7c, 0x42, 0x7a, 0x5d, 0x9f, 0xef,
+ 0x54, 0xb8, 0xf7, 0x9f, 0xc4, 0x33, 0x6c, 0xf3, 0x8c, 0x32, 0x46, 0x87,
+ 0x67, 0x30, 0x7b, 0xa7, 0xac, 0xe3, 0x02, 0x41, 0x00, 0xfc, 0x2c, 0xdf,
+ 0x0c, 0x0d, 0x88, 0xf5, 0xb1, 0x92, 0xa8, 0x93, 0x47, 0x63, 0x55, 0xf5,
+ 0xca, 0x58, 0x43, 0xba, 0x1c, 0xe5, 0x9e, 0xb6, 0x95, 0x05, 0xcd, 0xb5,
+ 0x82, 0xdf, 0xeb, 0x04, 0x53, 0x9d, 0xbd, 0xc2, 0x38, 0x16, 0xb3, 0x62,
+ 0xdd, 0xa1, 0x46, 0xdb, 0x6d, 0x97, 0x93, 0x9f, 0x8a, 0xc3, 0x9b, 0x64,
+ 0x7e, 0x42, 0xe3, 0x32, 0x57, 0x19, 0x1b, 0xd5, 0x6e, 0x85, 0xfa, 0xb8,
+ 0x8d, 0x02, 0x41, 0x00, 0xbc, 0x3d, 0xde, 0x6d, 0xd6, 0x97, 0xe8, 0xba,
+ 0x9e, 0x81, 0x37, 0x17, 0xe5, 0xa0, 0x64, 0xc9, 0x00, 0xb7, 0xe7, 0xfe,
+ 0xf4, 0x29, 0xd9, 0x2e, 0x43, 0x6b, 0x19, 0x20, 0xbd, 0x99, 0x75, 0xe7,
+ 0x76, 0xf8, 0xd3, 0xae, 0xaf, 0x7e, 0xb8, 0xeb, 0x81, 0xf4, 0x9d, 0xfe,
+ 0x07, 0x2b, 0x0b, 0x63, 0x0b, 0x5a, 0x55, 0x90, 0x71, 0x7d, 0xf1, 0xdb,
+ 0xd9, 0xb1, 0x41, 0x41, 0x68, 0x2f, 0x4e, 0x39, 0x02, 0x40, 0x5a, 0x34,
+ 0x66, 0xd8, 0xf5, 0xe2, 0x7f, 0x18, 0xb5, 0x00, 0x6e, 0x26, 0x84, 0x27,
+ 0x14, 0x93, 0xfb, 0xfc, 0xc6, 0x0f, 0x5e, 0x27, 0xe6, 0xe1, 0xe9, 0xc0,
+ 0x8a, 0xe4, 0x34, 0xda, 0xe9, 0xa2, 0x4b, 0x73, 0xbc, 0x8c, 0xb9, 0xba,
+ 0x13, 0x6c, 0x7a, 0x2b, 0x51, 0x84, 0xa3, 0x4a, 0xe0, 0x30, 0x10, 0x06,
+ 0x7e, 0xed, 0x17, 0x5a, 0x14, 0x00, 0xc9, 0xef, 0x85, 0xea, 0x52, 0x2c,
+ 0xbc, 0x65, 0x02, 0x40, 0x51, 0xe3, 0xf2, 0x83, 0x19, 0x9b, 0xc4, 0x1e,
+ 0x2f, 0x50, 0x3d, 0xdf, 0x5a, 0xa2, 0x18, 0xca, 0x5f, 0x2e, 0x49, 0xaf,
+ 0x6f, 0xcc, 0xfa, 0x65, 0x77, 0x94, 0xb5, 0xa1, 0x0a, 0xa9, 0xd1, 0x8a,
+ 0x39, 0x37, 0xf4, 0x0b, 0xa0, 0xd7, 0x82, 0x27, 0x5e, 0xae, 0x17, 0x17,
+ 0xa1, 0x1e, 0x54, 0x34, 0xbf, 0x6e, 0xc4, 0x8e, 0x99, 0x5d, 0x08, 0xf1,
+ 0x2d, 0x86, 0x9d, 0xa5, 0x20, 0x1b, 0xe5, 0xdf,
+};
+
+static const uint8_t kMsg[] = {1, 2, 3, 4};
+
+static const uint8_t kSignature[] = {
+ 0xa5, 0xf0, 0x8a, 0x47, 0x5d, 0x3c, 0xb3, 0xcc, 0xa9, 0x79, 0xaf, 0x4d,
+ 0x8c, 0xae, 0x4c, 0x14, 0xef, 0xc2, 0x0b, 0x34, 0x36, 0xde, 0xf4, 0x3e,
+ 0x3d, 0xbb, 0x4a, 0x60, 0x5c, 0xc8, 0x91, 0x28, 0xda, 0xfb, 0x7e, 0x04,
+ 0x96, 0x7e, 0x63, 0x13, 0x90, 0xce, 0xb9, 0xb4, 0x62, 0x7a, 0xfd, 0x09,
+ 0x3d, 0xc7, 0x67, 0x78, 0x54, 0x04, 0xeb, 0x52, 0x62, 0x6e, 0x24, 0x67,
+ 0xb4, 0x40, 0xfc, 0x57, 0x62, 0xc6, 0xf1, 0x67, 0xc1, 0x97, 0x8f, 0x6a,
+ 0xa8, 0xae, 0x44, 0x46, 0x5e, 0xab, 0x67, 0x17, 0x53, 0x19, 0x3a, 0xda,
+ 0x5a, 0xc8, 0x16, 0x3e, 0x86, 0xd5, 0xc5, 0x71, 0x2f, 0xfc, 0x23, 0x48,
+ 0xd9, 0x0b, 0x13, 0xdd, 0x7b, 0x5a, 0x25, 0x79, 0xef, 0xa5, 0x7b, 0x04,
+ 0xed, 0x44, 0xf6, 0x18, 0x55, 0xe4, 0x0a, 0xe9, 0x57, 0x79, 0x5d, 0xd7,
+ 0x55, 0xa7, 0xab, 0x45, 0x02, 0x97, 0x60, 0x42,
+};
+
+
+int example_EVP_DigestSignInit() {
+ int ret = 0;
+ EVP_PKEY *pkey = NULL;
+ RSA *rsa = NULL;
+ const uint8_t *derp = kExampleRSAKeyDER;
+ uint8_t *sig = NULL;
+ size_t sig_len;
+ EVP_MD_CTX md_ctx;
+
+ EVP_MD_CTX_init(&md_ctx);
+
+ if (!d2i_RSAPrivateKey(&rsa, &derp, sizeof(kExampleRSAKeyDER))) {
+ goto out;
+ }
+
+ sig_len = RSA_size(rsa);
+
+ pkey = EVP_PKEY_new();
+ sig = malloc(sig_len);
+ if (pkey == NULL ||
+ sig == NULL ||
+ !EVP_PKEY_set1_RSA(pkey, rsa) ||
+ EVP_DigestSignInit(&md_ctx, NULL, EVP_sha256(), NULL, pkey) != 1 ||
+ EVP_DigestSignUpdate(&md_ctx, kMsg, sizeof(kMsg)) != 1 ||
+ EVP_DigestSignFinal(&md_ctx, sig, &sig_len) != 1) {
+ goto out;
+ }
+ ret = 1;
+
+out:
+ if (!ret) {
+ BIO_print_errors_fp(stderr);
+ }
+
+ EVP_MD_CTX_cleanup(&md_ctx);
+ if (pkey) {
+ EVP_PKEY_free(pkey);
+ }
+ if (rsa) {
+ RSA_free(rsa);
+ }
+ if (sig) {
+ free(sig);
+ }
+
+ return ret;
+}
+
+int example_EVP_DigestVerifyInit() {
+ int ret = 0;
+ EVP_PKEY *pkey = NULL;
+ RSA *rsa = NULL;
+ const uint8_t *derp = kExampleRSAKeyDER;
+ EVP_MD_CTX md_ctx;
+
+ EVP_MD_CTX_init(&md_ctx);
+
+ if (!d2i_RSAPrivateKey(&rsa, &derp, sizeof(kExampleRSAKeyDER))) {
+ goto out;
+ }
+
+ pkey = EVP_PKEY_new();
+ if (pkey == NULL ||
+ !EVP_PKEY_set1_RSA(pkey, rsa) ||
+ EVP_DigestVerifyInit(&md_ctx, NULL, EVP_sha256(), NULL, pkey) != 1 ||
+ EVP_DigestVerifyUpdate(&md_ctx, kMsg, sizeof(kMsg)) != 1 ||
+ EVP_DigestVerifyFinal(&md_ctx, kSignature, sizeof(kSignature)) != 1) {
+ goto out;
+ }
+ ret = 1;
+
+out:
+ if (!ret) {
+ BIO_print_errors_fp(stderr);
+ }
+
+ EVP_MD_CTX_cleanup(&md_ctx);
+ if (pkey) {
+ EVP_PKEY_free(pkey);
+ }
+ if (rsa) {
+ RSA_free(rsa);
+ }
+
+ return ret;
+}
+
+int main() {
+ if (!example_EVP_DigestSignInit()) {
+ fprintf(stderr, "EVP_DigestSignInit failed\n");
+ return 1;
+ }
+
+ if (!example_EVP_DigestVerifyInit()) {
+ fprintf(stderr, "EVP_DigestVerifyInit failed\n");
+ return 1;
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/crypto/evp/internal.h b/crypto/evp/internal.h
new file mode 100644
index 0000000..76f206e
--- /dev/null
+++ b/crypto/evp/internal.h
@@ -0,0 +1,233 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_EVP_INTERNAL_H
+#define OPENSSL_HEADER_EVP_INTERNAL_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* These values are flags for EVP_PKEY_ASN1_METHOD.flags. */
+#define ASN1_PKEY_ALIAS 0x1
+#define ASN1_PKEY_DYNAMIC 0x2
+#define ASN1_PKEY_SIGPARAM_NULL 0x4
+
+struct evp_pkey_asn1_method_st {
+ int pkey_id;
+ int pkey_base_id;
+ unsigned long pkey_flags;
+
+ char *pem_str;
+ char *info;
+
+ int (*pub_decode)(EVP_PKEY *pk, X509_PUBKEY *pub);
+ int (*pub_encode)(X509_PUBKEY *pub, const EVP_PKEY *pk);
+ int (*pub_cmp)(const EVP_PKEY *a, const EVP_PKEY *b);
+ int (*pub_print)(BIO *out, const EVP_PKEY *pkey, int indent, ASN1_PCTX *pctx);
+
+ int (*priv_decode)(EVP_PKEY *pk, PKCS8_PRIV_KEY_INFO *p8inf);
+ int (*priv_encode)(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pk);
+ int (*priv_print)(BIO *out, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *pctx);
+
+ 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_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);
+ int (*param_print)(BIO *out, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *pctx);
+ int (*sig_print)(BIO *out, const X509_ALGOR *sigalg, const ASN1_STRING *sig,
+ int indent, ASN1_PCTX *pctx);
+
+
+ void (*pkey_free)(EVP_PKEY *pkey);
+ int (*pkey_ctrl)(EVP_PKEY *pkey, int op, long arg1, void *arg2);
+
+ /* Legacy functions for old PEM */
+
+ int (*old_priv_decode)(EVP_PKEY *pkey, const unsigned char **pder,
+ int derlen);
+ int (*old_priv_encode)(const EVP_PKEY *pkey, unsigned char **pder);
+ /* Custom ASN1 signature verification */
+ int (*item_verify)(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
+ X509_ALGOR *a, ASN1_BIT_STRING *sig, EVP_PKEY *pkey);
+ int (*item_sign)(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
+ X509_ALGOR *alg1, X509_ALGOR *alg2, ASN1_BIT_STRING *sig);
+
+} /* EVP_PKEY_ASN1_METHOD */;
+
+
+typedef int EVP_PKEY_gen_cb(EVP_PKEY_CTX *ctx);
+
+#define EVP_PKEY_OP_UNDEFINED 0
+#define EVP_PKEY_OP_PARAMGEN (1 << 1)
+#define EVP_PKEY_OP_KEYGEN (1 << 2)
+#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_TYPE_SIG \
+ (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY | EVP_PKEY_OP_VERIFYRECOVER | \
+ EVP_PKEY_OP_SIGNCTX | EVP_PKEY_OP_VERIFYCTX)
+
+#define EVP_PKEY_OP_TYPE_CRYPT (EVP_PKEY_OP_ENCRYPT | EVP_PKEY_OP_DECRYPT)
+
+#define EVP_PKEY_OP_TYPE_NOGEN \
+ (EVP_PKEY_OP_SIG | EVP_PKEY_OP_CRYPT | EVP_PKEY_OP_DERIVE)
+
+#define EVP_PKEY_OP_TYPE_GEN (EVP_PKEY_OP_PARAMGEN | EVP_PKEY_OP_KEYGEN)
+
+#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)
+#define EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN (EVP_PKEY_ALG_CTRL + 4)
+#define EVP_PKEY_CTRL_RSA_KEYGEN_BITS (EVP_PKEY_ALG_CTRL + 5)
+#define EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP (EVP_PKEY_ALG_CTRL + 6)
+#define EVP_PKEY_CTRL_RSA_OAEP_MD (EVP_PKEY_ALG_CTRL + 7)
+#define EVP_PKEY_CTRL_GET_RSA_OAEP_MD (EVP_PKEY_ALG_CTRL + 8)
+#define EVP_PKEY_CTRL_RSA_MGF1_MD (EVP_PKEY_ALG_CTRL + 9)
+#define EVP_PKEY_CTRL_GET_RSA_MGF1_MD (EVP_PKEY_ALG_CTRL + 10)
+#define EVP_PKEY_CTRL_RSA_OAEP_LABEL (EVP_PKEY_ALG_CTRL + 11)
+#define EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL (EVP_PKEY_ALG_CTRL + 12)
+
+struct evp_pkey_ctx_st {
+ /* Method associated with this operation */
+ const EVP_PKEY_METHOD *pmeth;
+ /* Engine that implements this method or NULL if builtin */
+ ENGINE *engine;
+ /* Key: may be NULL */
+ EVP_PKEY *pkey;
+ /* Peer key for key agreement, may be NULL */
+ EVP_PKEY *peerkey;
+ /* operation contains one of the |EVP_PKEY_OP_*| values. */
+ int operation;
+ /* Algorithm specific data */
+ void *data;
+ /* Application specific data */
+ void *app_data;
+} /* EVP_PKEY_CTX */;
+
+/* EVP_PKEY_FLAG_AUTOARGLEN causes wrapper functions to automatically check the
+ * argument length to various functions (signing, decrypting etc) is equal to
+ * the value of |EVP_PKEY_size|. */
+#define EVP_PKEY_FLAG_AUTOARGLEN 2
+
+struct evp_pkey_method_st {
+ int pkey_id;
+ int flags;
+
+ int (*init)(EVP_PKEY_CTX *ctx);
+ int (*copy)(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src);
+ void (*cleanup)(EVP_PKEY_CTX *ctx);
+
+ int (*paramgen_init)(EVP_PKEY_CTX *ctx);
+ int (*paramgen)(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey);
+
+ int (*keygen_init)(EVP_PKEY_CTX *ctx);
+ 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 (*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 (*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 (*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 (*derive_init)(EVP_PKEY_CTX *ctx);
+ int (*derive)(EVP_PKEY_CTX *ctx, unsigned char *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 */;
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_EVP_INTERNAL_H */
diff --git a/crypto/evp/p_ec.c b/crypto/evp/p_ec.c
new file mode 100644
index 0000000..2305e6e
--- /dev/null
+++ b/crypto/evp/p_ec.c
@@ -0,0 +1,423 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2006.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 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/bn.h>
+#include <openssl/buf.h>
+#include <openssl/digest.h>
+#include <openssl/ec.h>
+#include <openssl/ec_key.h>
+#include <openssl/ecdh.h>
+#include <openssl/ecdsa.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+
+#include "internal.h"
+#include "../ec/internal.h"
+
+
+typedef struct {
+ /* Key and paramgen group */
+ EC_GROUP *gen_group;
+ /* message digest */
+ const EVP_MD *md;
+ /* Duplicate key if custom cofactor needed */
+ EC_KEY *co_key;
+ /* Cofactor mode */
+ signed char cofactor_mode;
+ /* KDF (if any) to use for ECDH */
+ char kdf_type;
+ /* Message digest to use for key derivation */
+ const EVP_MD *kdf_md;
+ /* User key material */
+ unsigned char *kdf_ukm;
+ size_t kdf_ukmlen;
+ /* KDF output length */
+ size_t kdf_outlen;
+} EC_PKEY_CTX;
+
+
+static int pkey_ec_init(EVP_PKEY_CTX *ctx) {
+ EC_PKEY_CTX *dctx;
+ dctx = OPENSSL_malloc(sizeof(EC_PKEY_CTX));
+ if (!dctx) {
+ return 0;
+ }
+ memset(dctx, 0, sizeof(EC_PKEY_CTX));
+ dctx->cofactor_mode = -1;
+ dctx->kdf_type = EVP_PKEY_ECDH_KDF_NONE;
+
+ ctx->data = dctx;
+
+ return 1;
+}
+
+static int pkey_ec_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) {
+ EC_PKEY_CTX *dctx, *sctx;
+ if (!pkey_ec_init(dst)) {
+ return 0;
+ }
+ sctx = src->data;
+ dctx = dst->data;
+
+ if (sctx->gen_group) {
+ dctx->gen_group = EC_GROUP_dup(sctx->gen_group);
+ if (!dctx->gen_group) {
+ return 0;
+ }
+ }
+ dctx->md = sctx->md;
+
+ if (sctx->co_key) {
+ dctx->co_key = EC_KEY_dup(sctx->co_key);
+ if (!dctx->co_key) {
+ return 0;
+ }
+ }
+ dctx->kdf_type = sctx->kdf_type;
+ dctx->kdf_md = sctx->kdf_md;
+ dctx->kdf_outlen = sctx->kdf_outlen;
+ if (sctx->kdf_ukm) {
+ dctx->kdf_ukm = BUF_memdup(sctx->kdf_ukm, sctx->kdf_ukmlen);
+ if (!dctx->kdf_ukm) {
+ return 0;
+ }
+ } else {
+ dctx->kdf_ukm = NULL;
+ }
+ dctx->kdf_ukmlen = sctx->kdf_ukmlen;
+ return 1;
+}
+
+static void pkey_ec_cleanup(EVP_PKEY_CTX *ctx) {
+ EC_PKEY_CTX *dctx = ctx->data;
+ if (!dctx) {
+ return;
+ }
+
+ if (dctx->gen_group) {
+ EC_GROUP_free(dctx->gen_group);
+ }
+ if (dctx->co_key) {
+ EC_KEY_free(dctx->co_key);
+ }
+ if (dctx->kdf_ukm) {
+ OPENSSL_free(dctx->kdf_ukm);
+ }
+ OPENSSL_free(dctx);
+}
+
+static int pkey_ec_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen,
+ const uint8_t *tbs, size_t tbslen) {
+ int ret, 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);
+ return 0;
+ }
+
+ type = NID_sha1;
+ if (dctx->md) {
+ type = EVP_MD_type(dctx->md);
+ }
+
+ ret = ECDSA_sign(type, tbs, tbslen, sig, &sltmp, ec);
+
+ if (ret <= 0) {
+ return ret;
+ }
+ *siglen = (size_t)sltmp;
+ return 1;
+}
+
+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);
+}
+
+static int pkey_ec_derive(EVP_PKEY_CTX *ctx, uint8_t *key,
+ size_t *keylen) {
+ int ret;
+ size_t outlen;
+ const EC_POINT *pubkey = NULL;
+ EC_KEY *eckey;
+ EC_PKEY_CTX *dctx = ctx->data;
+
+ if (!ctx->pkey || !ctx->peerkey) {
+ OPENSSL_PUT_ERROR(EVP, pkey_ec_derive, EVP_R_KEYS_NOT_SET);
+ return 0;
+ }
+
+ eckey = dctx->co_key ? dctx->co_key : ctx->pkey->pkey.ec;
+
+ if (!key) {
+ const EC_GROUP *group;
+ group = EC_KEY_get0_group(eckey);
+ *keylen = (EC_GROUP_get_degree(group) + 7) / 8;
+ return 1;
+ }
+ pubkey = EC_KEY_get0_public_key(ctx->peerkey->pkey.ec);
+
+ /* NB: unlike PKCS#3 DH, if *outlen is less than maximum size this is
+ * not an error, the result is truncated. */
+
+ outlen = *keylen;
+
+ ret = ECDH_compute_key(key, outlen, pubkey, eckey, 0);
+ if (ret < 0) {
+ return ret;
+ }
+ *keylen = ret;
+ return 1;
+}
+
+static int pkey_ec_kdf_derive(EVP_PKEY_CTX *ctx, uint8_t *key,
+ size_t *keylen) {
+ EC_PKEY_CTX *dctx = ctx->data;
+ uint8_t *ktmp = NULL;
+ size_t ktmplen;
+ int rv = 0;
+
+ if (dctx->kdf_type == EVP_PKEY_ECDH_KDF_NONE) {
+ return pkey_ec_derive(ctx, key, keylen);
+ }
+ if (!key) {
+ *keylen = dctx->kdf_outlen;
+ return 1;
+ }
+ if (*keylen != dctx->kdf_outlen ||
+ !pkey_ec_derive(ctx, NULL, &ktmplen)) {
+ return 0;
+ }
+ ktmp = OPENSSL_malloc(ktmplen);
+ if (!ktmp) {
+ return 0;
+ }
+ if (!pkey_ec_derive(ctx, ktmp, &ktmplen)) {
+ goto err;
+ }
+
+ if (!ECDH_KDF_X9_62(key, *keylen, ktmp, ktmplen, dctx->kdf_ukm,
+ dctx->kdf_ukmlen, dctx->kdf_md)) {
+ goto err;
+ }
+ rv = 1;
+
+err:
+ if (ktmp) {
+ OPENSSL_cleanse(ktmp, ktmplen);
+ OPENSSL_free(ktmp);
+ }
+ return rv;
+}
+
+static int pkey_ec_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) {
+ EC_PKEY_CTX *dctx = ctx->data;
+ EC_GROUP *group;
+
+ switch (type) {
+ 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);
+ return 0;
+ }
+ if (dctx->gen_group)
+ EC_GROUP_free(dctx->gen_group);
+ dctx->gen_group = group;
+ return 1;
+
+ case EVP_PKEY_CTRL_EC_KDF_TYPE:
+ if (p1 == -2)
+ return dctx->kdf_type;
+ if (p1 != EVP_PKEY_ECDH_KDF_NONE && p1 != EVP_PKEY_ECDH_KDF_X9_62)
+ return -2;
+ dctx->kdf_type = p1;
+ return 1;
+
+ case EVP_PKEY_CTRL_EC_KDF_MD:
+ dctx->kdf_md = p2;
+ return 1;
+
+ case EVP_PKEY_CTRL_GET_EC_KDF_MD:
+ *(const EVP_MD **)p2 = dctx->kdf_md;
+ return 1;
+
+ case EVP_PKEY_CTRL_EC_KDF_OUTLEN:
+ if (p1 <= 0)
+ return -2;
+ dctx->kdf_outlen = (size_t)p1;
+ return 1;
+
+ case EVP_PKEY_CTRL_GET_EC_KDF_OUTLEN:
+ *(int *)p2 = dctx->kdf_outlen;
+ return 1;
+
+ case EVP_PKEY_CTRL_EC_KDF_UKM:
+ if (dctx->kdf_ukm)
+ OPENSSL_free(dctx->kdf_ukm);
+ dctx->kdf_ukm = p2;
+ if (p2)
+ dctx->kdf_ukmlen = p1;
+ else
+ dctx->kdf_ukmlen = 0;
+ return 1;
+
+ case EVP_PKEY_CTRL_GET_EC_KDF_UKM:
+ *(unsigned char **)p2 = dctx->kdf_ukm;
+ return dctx->kdf_ukmlen;
+
+ case EVP_PKEY_CTRL_MD:
+ if (EVP_MD_type((const EVP_MD *)p2) != NID_sha1 &&
+ EVP_MD_type((const EVP_MD *)p2) != NID_ecdsa_with_SHA1 &&
+ EVP_MD_type((const EVP_MD *)p2) != NID_sha224 &&
+ 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);
+ return 0;
+ }
+ dctx->md = p2;
+ return 1;
+
+ case EVP_PKEY_CTRL_GET_MD:
+ *(const EVP_MD **)p2 = dctx->md;
+ return 1;
+
+ case EVP_PKEY_CTRL_PEER_KEY:
+ /* Default behaviour is OK */
+ case EVP_PKEY_CTRL_DIGESTINIT:
+ return 1;
+
+ default:
+ return -2;
+ }
+}
+
+static int pkey_ec_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
+ EC_KEY *ec = NULL;
+ EC_PKEY_CTX *dctx = ctx->data;
+ int ret = 0;
+
+ if (dctx->gen_group == NULL) {
+ OPENSSL_PUT_ERROR(EVP, pkey_ec_paramgen, EVP_R_NO_PARAMETERS_SET);
+ return 0;
+ }
+ ec = EC_KEY_new();
+ if (!ec) {
+ return 0;
+ }
+ ret = EC_KEY_set_group(ec, dctx->gen_group);
+ if (ret) {
+ EVP_PKEY_assign_EC_KEY(pkey, ec);
+ } else {
+ EC_KEY_free(ec);
+ }
+ return ret;
+}
+
+static int pkey_ec_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
+ 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);
+ return 0;
+ }
+ ec = EC_KEY_new();
+ if (!ec) {
+ return 0;
+ }
+ EVP_PKEY_assign_EC_KEY(pkey, ec);
+ if (ctx->pkey) {
+ /* Note: if error return, pkey is freed by parent routine */
+ if (!EVP_PKEY_copy_parameters(pkey, ctx->pkey)) {
+ return 0;
+ }
+ } else {
+ if (!EC_KEY_set_group(ec, dctx->gen_group)) {
+ return 0;
+ }
+ }
+ return EC_KEY_generate_key(pkey->pkey.ec);
+}
+
+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_kdf_derive, pkey_ec_ctrl,
+};
diff --git a/crypto/evp/p_ec_asn1.c b/crypto/evp/p_ec_asn1.c
new file mode 100644
index 0000000..d4eec13
--- /dev/null
+++ b/crypto/evp/p_ec_asn1.c
@@ -0,0 +1,577 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2006.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 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/asn1t.h>
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509.h>
+
+#include "internal.h"
+
+
+static int eckey_param2type(int *pptype, void **ppval, EC_KEY *ec_key) {
+ const EC_GROUP *group;
+ int nid;
+
+ if (ec_key == NULL || (group = EC_KEY_get0_group(ec_key)) == NULL) {
+ OPENSSL_PUT_ERROR(EVP, eckey_param2type, 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);
+ return 0;
+ }
+
+ *ppval = (void*) OBJ_nid2obj(nid);
+ *pptype = V_ASN1_OBJECT;
+ return 1;
+}
+
+static int eckey_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) {
+ EC_KEY *ec_key = pkey->pkey.ec;
+ void *pval = NULL;
+ int ptype;
+ uint8_t *penc = NULL, *p;
+ int penclen;
+
+ if (!eckey_param2type(&ptype, &pval, ec_key)) {
+ OPENSSL_PUT_ERROR(EVP, eckey_pub_encode, ERR_R_EC_LIB);
+ return 0;
+ }
+ penclen = i2o_ECPublicKey(ec_key, NULL);
+ if (penclen <= 0) {
+ goto err;
+ }
+ penc = OPENSSL_malloc(penclen);
+ if (!penc) {
+ goto err;
+ }
+ p = penc;
+ penclen = i2o_ECPublicKey(ec_key, &p);
+ if (penclen <= 0) {
+ goto err;
+ }
+ if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_EC), ptype, pval, penc,
+ penclen)) {
+ return 1;
+ }
+
+err:
+ if (ptype == V_ASN1_OBJECT) {
+ ASN1_OBJECT_free(pval);
+ } else {
+ ASN1_STRING_free(pval);
+ }
+ if (penc) {
+ OPENSSL_free(penc);
+ }
+ return 0;
+}
+
+static EC_KEY *eckey_type2param(int ptype, void *pval) {
+ EC_KEY *eckey = NULL;
+
+ if (ptype == V_ASN1_SEQUENCE) {
+ ASN1_STRING *pstr = pval;
+ const uint8_t *pm = pstr->data;
+ int pmlen = pstr->length;
+
+ eckey = d2i_ECParameters(NULL, &pm, pmlen);
+ if (eckey == NULL) {
+ OPENSSL_PUT_ERROR(EVP, eckey_type2param, EVP_R_DECODE_ERROR);
+ goto err;
+ }
+ } else if (ptype == V_ASN1_OBJECT) {
+ ASN1_OBJECT *poid = pval;
+ EC_GROUP *group;
+
+ /* type == V_ASN1_OBJECT => the parameters are given
+ * by an asn1 OID */
+ eckey = EC_KEY_new();
+ if (eckey == NULL) {
+ OPENSSL_PUT_ERROR(EVP, eckey_type2param, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ group = EC_GROUP_new_by_curve_name(OBJ_obj2nid(poid));
+ if (group == NULL) {
+ goto err;
+ }
+ if (EC_KEY_set_group(eckey, group) == 0) {
+ goto err;
+ }
+ EC_GROUP_free(group);
+ } else {
+ OPENSSL_PUT_ERROR(EVP, eckey_type2param, EVP_R_DECODE_ERROR);
+ goto err;
+ }
+
+ return eckey;
+
+err:
+ if (eckey) {
+ EC_KEY_free(eckey);
+ }
+ return NULL;
+}
+
+static int eckey_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) {
+ const uint8_t *p = NULL;
+ void *pval;
+ int ptype, pklen;
+ EC_KEY *eckey = NULL;
+ X509_ALGOR *palg;
+
+ if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey)) {
+ return 0;
+ }
+ X509_ALGOR_get0(NULL, &ptype, &pval, palg);
+
+ eckey = eckey_type2param(ptype, pval);
+ if (!eckey) {
+ OPENSSL_PUT_ERROR(EVP, eckey_pub_decode, 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);
+ goto err;
+ }
+
+ EVP_PKEY_assign_EC_KEY(pkey, eckey);
+ return 1;
+
+err:
+ if (eckey)
+ EC_KEY_free(eckey);
+ return 0;
+}
+
+static int eckey_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
+ int r;
+ const EC_GROUP *group = EC_KEY_get0_group(b->pkey.ec);
+ const EC_POINT *pa = EC_KEY_get0_public_key(a->pkey.ec),
+ *pb = EC_KEY_get0_public_key(b->pkey.ec);
+ r = EC_POINT_cmp(group, pa, pb, NULL);
+ if (r == 0) {
+ return 1;
+ } else if (r == 1) {
+ return 0;
+ } else {
+ return -2;
+ }
+}
+
+static int eckey_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8) {
+ const uint8_t *p = NULL;
+ void *pval;
+ int ptype, pklen;
+ EC_KEY *eckey = NULL;
+ X509_ALGOR *palg;
+
+ if (!PKCS8_pkey_get0(NULL, &p, &pklen, &palg, p8)) {
+ return 0;
+ }
+ X509_ALGOR_get0(NULL, &ptype, &pval, palg);
+
+ eckey = eckey_type2param(ptype, pval);
+
+ if (!eckey)
+ goto ecliberr;
+
+ /* We have parameters now set private key */
+ if (!d2i_ECPrivateKey(&eckey, &p, pklen)) {
+ OPENSSL_PUT_ERROR(EVP, eckey_priv_decode, EVP_R_DECODE_ERROR);
+ goto ecerr;
+ }
+
+ /* calculate public key (if necessary) */
+ if (EC_KEY_get0_public_key(eckey) == NULL) {
+ const BIGNUM *priv_key;
+ const EC_GROUP *group;
+ EC_POINT *pub_key;
+ /* the public key was not included in the SEC1 private
+ * key => calculate the public key */
+ 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);
+ 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);
+ 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);
+ 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);
+ goto ecliberr;
+ }
+ EC_POINT_free(pub_key);
+ }
+
+ EVP_PKEY_assign_EC_KEY(pkey, eckey);
+ return 1;
+
+ecliberr:
+ OPENSSL_PUT_ERROR(EVP, eckey_priv_decode, ERR_R_EC_LIB);
+ecerr:
+ if (eckey)
+ EC_KEY_free(eckey);
+ return 0;
+}
+
+static int eckey_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey) {
+ EC_KEY *ec_key;
+ uint8_t *ep, *p;
+ int eplen, ptype;
+ void *pval;
+ unsigned int tmp_flags, old_flags;
+
+ ec_key = pkey->pkey.ec;
+
+ if (!eckey_param2type(&ptype, &pval, ec_key)) {
+ OPENSSL_PUT_ERROR(EVP, eckey_priv_encode, EVP_R_DECODE_ERROR);
+ return 0;
+ }
+
+ /* set the private key */
+
+ /* do not include the parameters in the SEC1 private key
+ * see PKCS#11 12.11 */
+ old_flags = EC_KEY_get_enc_flags(ec_key);
+ tmp_flags = old_flags | EC_PKEY_NO_PARAMETERS;
+ EC_KEY_set_enc_flags(ec_key, tmp_flags);
+ 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);
+ 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);
+ 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);
+ return 0;
+ }
+ /* restore old encoding flags */
+ EC_KEY_set_enc_flags(ec_key, old_flags);
+
+ if (!PKCS8_pkey_set0(p8, (ASN1_OBJECT *)OBJ_nid2obj(NID_X9_62_id_ecPublicKey),
+ 0, ptype, pval, ep, eplen)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int int_ec_size(const EVP_PKEY *pkey) {
+ return ECDSA_size(pkey->pkey.ec);
+}
+
+static int ec_bits(const EVP_PKEY *pkey) {
+ BIGNUM *order = BN_new();
+ const EC_GROUP *group;
+ int ret;
+
+ if (!order) {
+ ERR_clear_error();
+ return 0;
+ }
+ group = EC_KEY_get0_group(pkey->pkey.ec);
+ if (!EC_GROUP_get_order(group, order, NULL)) {
+ ERR_clear_error();
+ return 0;
+ }
+
+ ret = BN_num_bits(order);
+ BN_free(order);
+ return ret;
+}
+
+static int ec_missing_parameters(const EVP_PKEY *pkey) {
+ return EC_KEY_get0_group(pkey->pkey.ec) == NULL;
+}
+
+static int ec_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) {
+ EC_GROUP *group = EC_GROUP_dup(EC_KEY_get0_group(from->pkey.ec));
+ if (group == NULL ||
+ EC_KEY_set_group(to->pkey.ec, group) == 0) {
+ return 0;
+ }
+ EC_GROUP_free(group);
+ return 1;
+}
+
+static int ec_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) {
+ const EC_GROUP *group_a = EC_KEY_get0_group(a->pkey.ec),
+ *group_b = EC_KEY_get0_group(b->pkey.ec);
+ return EC_GROUP_cmp(group_a, group_b);
+}
+
+static void int_ec_free(EVP_PKEY *pkey) { EC_KEY_free(pkey->pkey.ec); }
+
+static int do_EC_KEY_print(BIO *bp, const EC_KEY *x, int off, int ktype) {
+ uint8_t *buffer = NULL;
+ const char *ecstr;
+ size_t buf_len = 0, i;
+ int ret = 0, reason = ERR_R_BIO_LIB;
+ BIGNUM *order = NULL;
+ BN_CTX *ctx = NULL;
+ const EC_GROUP *group;
+ const EC_POINT *public_key;
+ const BIGNUM *priv_key;
+ uint8_t *pub_key_bytes = NULL;
+ size_t pub_key_bytes_len = 0;
+
+ if (x == NULL || (group = EC_KEY_get0_group(x)) == NULL) {
+ reason = ERR_R_PASSED_NULL_PARAMETER;
+ goto err;
+ }
+
+ ctx = BN_CTX_new();
+ if (ctx == NULL) {
+ reason = ERR_R_MALLOC_FAILURE;
+ goto err;
+ }
+
+ if (ktype > 0) {
+ public_key = EC_KEY_get0_public_key(x);
+ pub_key_bytes_len = EC_POINT_point2oct(
+ group, public_key, EC_KEY_get_conv_form(x), NULL, 0, ctx);
+ if (pub_key_bytes_len == 0) {
+ reason = ERR_R_MALLOC_FAILURE;
+ goto err;
+ }
+ pub_key_bytes = OPENSSL_malloc(pub_key_bytes_len);
+ if (pub_key_bytes == NULL) {
+ reason = ERR_R_MALLOC_FAILURE;
+ goto err;
+ }
+ pub_key_bytes_len =
+ EC_POINT_point2oct(group, public_key, EC_KEY_get_conv_form(x),
+ pub_key_bytes, pub_key_bytes_len, ctx);
+ if (pub_key_bytes_len == 0) {
+ reason = ERR_R_MALLOC_FAILURE;
+ goto err;
+ }
+ buf_len = pub_key_bytes_len;
+ }
+
+ if (ktype == 2) {
+ priv_key = EC_KEY_get0_private_key(x);
+ if (priv_key && (i = (size_t)BN_num_bytes(priv_key)) > buf_len)
+ buf_len = i;
+ } else
+ priv_key = NULL;
+
+ if (ktype > 0) {
+ buf_len += 10;
+ if ((buffer = OPENSSL_malloc(buf_len)) == NULL) {
+ reason = ERR_R_MALLOC_FAILURE;
+ goto err;
+ }
+ }
+ if (ktype == 2)
+ ecstr = "Private-Key";
+ else if (ktype == 1)
+ ecstr = "Public-Key";
+ else
+ ecstr = "ECDSA-Parameters";
+
+ if (!BIO_indent(bp, off, 128))
+ goto err;
+ if ((order = BN_new()) == NULL)
+ goto err;
+ if (!EC_GROUP_get_order(group, order, NULL))
+ goto err;
+ if (BIO_printf(bp, "%s: (%d bit)\n", ecstr, BN_num_bits(order)) <= 0)
+ goto err;
+
+ if ((priv_key != NULL) && !ASN1_bn_print(bp, "priv:", priv_key, buffer, off))
+ goto err;
+ if (pub_key_bytes != NULL) {
+ BIO_hexdump(bp, pub_key_bytes, pub_key_bytes_len, off);
+ }
+ /* TODO(fork): implement */
+ /*
+ if (!ECPKParameters_print(bp, group, off))
+ goto err; */
+ ret = 1;
+
+err:
+ if (!ret)
+ OPENSSL_PUT_ERROR(EVP, do_EC_KEY_print, reason);
+ if (pub_key_bytes)
+ OPENSSL_free(pub_key_bytes);
+ if (order)
+ BN_free(order);
+ if (ctx)
+ BN_CTX_free(ctx);
+ if (buffer != NULL)
+ OPENSSL_free(buffer);
+ return ret;
+}
+
+static int eckey_param_decode(EVP_PKEY *pkey, const uint8_t **pder,
+ int derlen) {
+ EC_KEY *eckey;
+ if (!(eckey = d2i_ECParameters(NULL, pder, derlen))) {
+ OPENSSL_PUT_ERROR(EVP, eckey_param_decode, ERR_R_EC_LIB);
+ return 0;
+ }
+ EVP_PKEY_assign_EC_KEY(pkey, eckey);
+ return 1;
+}
+
+static int eckey_param_encode(const EVP_PKEY *pkey, uint8_t **pder) {
+ return i2d_ECParameters(pkey->pkey.ec, pder);
+}
+
+static int eckey_param_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *ctx) {
+ return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 0);
+}
+
+static int eckey_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *ctx) {
+ return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 1);
+}
+
+
+static int eckey_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *ctx) {
+ return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 2);
+}
+
+static int old_ec_priv_decode(EVP_PKEY *pkey, const uint8_t **pder,
+ int derlen) {
+ EC_KEY *ec;
+ if (!(ec = d2i_ECPrivateKey(NULL, pder, derlen))) {
+ OPENSSL_PUT_ERROR(EVP, old_ec_priv_decode, EVP_R_DECODE_ERROR);
+ return 0;
+ }
+ EVP_PKEY_assign_EC_KEY(pkey, ec);
+ return 1;
+}
+
+static int old_ec_priv_encode(const EVP_PKEY *pkey, uint8_t **pder) {
+ return i2d_ECPrivateKey(pkey->pkey.ec, pder);
+}
+
+static int ec_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2) {
+ switch (op) {
+ case ASN1_PKEY_CTRL_DEFAULT_MD_NID:
+ *(int *)arg2 = NID_sha1;
+ return 2;
+
+ default:
+ return -2;
+ }
+}
+
+const EVP_PKEY_ASN1_METHOD ec_asn1_meth = {
+ EVP_PKEY_EC,
+ EVP_PKEY_EC,
+ 0,
+ "EC",
+ "OpenSSL EC algorithm",
+
+ eckey_pub_decode,
+ eckey_pub_encode,
+ eckey_pub_cmp,
+ eckey_pub_print,
+
+ eckey_priv_decode,
+ eckey_priv_encode,
+ eckey_priv_print,
+
+ int_ec_size,
+ ec_bits,
+
+ eckey_param_decode,
+ eckey_param_encode,
+ ec_missing_parameters,
+ ec_copy_parameters,
+ ec_cmp_parameters,
+ eckey_param_print,
+ 0,
+
+ int_ec_free,
+ ec_pkey_ctrl,
+ old_ec_priv_decode,
+ old_ec_priv_encode
+};
diff --git a/crypto/evp/p_hmac.c b/crypto/evp/p_hmac.c
new file mode 100644
index 0000000..b55db7a
--- /dev/null
+++ b/crypto/evp/p_hmac.c
@@ -0,0 +1,215 @@
+/* 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/hmac.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+
+#include "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(&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;
+
+ 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 int int_update(EVP_MD_CTX *ctx, const void *data, size_t count) {
+ HMAC_PKEY_CTX *hctx = ctx->pctx->data;
+ return HMAC_Update(&hctx->ctx, data, count);
+}
+
+static int hmac_signctx_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx) {
+ HMAC_PKEY_CTX *hctx = ctx->data;
+
+ HMAC_CTX_set_flags(&hctx->ctx, mctx->flags & ~EVP_MD_CTX_FLAG_NO_INIT);
+ 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;
+ int l = EVP_MD_CTX_size(mctx);
+
+ if (l < 0) {
+ return 0;
+ }
+ *siglen = l;
+ if (!sig) {
+ return 1;
+ }
+
+ 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:
+ return -2;
+ }
+ 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/crypto/evp/p_hmac_asn1.c b/crypto/evp/p_hmac_asn1.c
new file mode 100644
index 0000000..cabd737
--- /dev/null
+++ b/crypto/evp/p_hmac_asn1.c
@@ -0,0 +1,99 @@
+/* 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);
+ }
+}
+
+static int hmac_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2) {
+ switch (op) {
+ case ASN1_PKEY_CTRL_DEFAULT_MD_NID:
+ *(int *)arg2 = NID_sha1;
+ return 1;
+
+ default:
+ return -2;
+ }
+}
+
+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 */,
+ 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, hmac_pkey_ctrl, 0 /* old_priv_decode */,
+ 0 /* old_priv_encode */
+};
diff --git a/crypto/evp/p_rsa.c b/crypto/evp/p_rsa.c
new file mode 100644
index 0000000..2fab371
--- /dev/null
+++ b/crypto/evp/p_rsa.c
@@ -0,0 +1,596 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2006.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 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/bn.h>
+#include <openssl/buf.h>
+#include <openssl/digest.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/rsa.h>
+
+#include "../rsa/internal.h"
+#include "internal.h"
+
+
+typedef struct {
+ /* Key gen parameters */
+ int nbits;
+ BIGNUM *pub_exp;
+ /* RSA padding mode */
+ int pad_mode;
+ /* message digest */
+ const EVP_MD *md;
+ /* message digest for MGF1 */
+ const EVP_MD *mgf1md;
+ /* PSS salt length */
+ int saltlen;
+ /* tbuf is a buffer which is either NULL, or is the size of the RSA modulus.
+ * It's used to store the output of RSA operations. */
+ uint8_t *tbuf;
+ /* OAEP label */
+ uint8_t *oaep_label;
+ size_t oaep_labellen;
+} RSA_PKEY_CTX;
+
+static int pkey_rsa_init(EVP_PKEY_CTX *ctx) {
+ RSA_PKEY_CTX *rctx;
+ rctx = OPENSSL_malloc(sizeof(RSA_PKEY_CTX));
+ if (!rctx) {
+ return 0;
+ }
+ memset(rctx, 0, sizeof(RSA_PKEY_CTX));
+
+ rctx->nbits = 2048;
+ rctx->pad_mode = RSA_PKCS1_PADDING;
+ rctx->saltlen = -2;
+
+ ctx->data = rctx;
+
+ return 1;
+}
+
+static int pkey_rsa_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) {
+ RSA_PKEY_CTX *dctx, *sctx;
+ if (!pkey_rsa_init(dst)) {
+ return 0;
+ }
+ sctx = src->data;
+ dctx = dst->data;
+ dctx->nbits = sctx->nbits;
+ if (sctx->pub_exp) {
+ dctx->pub_exp = BN_dup(sctx->pub_exp);
+ if (!dctx->pub_exp) {
+ return 0;
+ }
+ }
+
+ dctx->pad_mode = sctx->pad_mode;
+ dctx->md = sctx->md;
+ dctx->mgf1md = sctx->mgf1md;
+ if (sctx->oaep_label) {
+ if (dctx->oaep_label) {
+ OPENSSL_free(dctx->oaep_label);
+ }
+ dctx->oaep_label = BUF_memdup(sctx->oaep_label, sctx->oaep_labellen);
+ if (!dctx->oaep_label) {
+ return 0;
+ }
+ dctx->oaep_labellen = sctx->oaep_labellen;
+ }
+
+ return 1;
+}
+
+static void pkey_rsa_cleanup(EVP_PKEY_CTX *ctx) {
+ RSA_PKEY_CTX *rctx = ctx->data;
+
+ if (rctx == NULL) {
+ return;
+ }
+
+ if (rctx->pub_exp) {
+ BN_free(rctx->pub_exp);
+ }
+ if (rctx->tbuf) {
+ OPENSSL_free(rctx->tbuf);
+ }
+ if (rctx->oaep_label) {
+ OPENSSL_free(rctx->oaep_label);
+ }
+ OPENSSL_free(rctx);
+}
+
+static int setup_tbuf(RSA_PKEY_CTX *ctx, EVP_PKEY_CTX *pk) {
+ if (ctx->tbuf) {
+ return 1;
+ }
+ ctx->tbuf = OPENSSL_malloc(EVP_PKEY_size(pk->pkey));
+ if (!ctx->tbuf) {
+ return 0;
+ }
+ return 1;
+}
+
+static int pkey_rsa_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen,
+ const uint8_t *tbs, size_t tbslen) {
+ int ret;
+ RSA_PKEY_CTX *rctx = ctx->data;
+ RSA *rsa = ctx->pkey->pkey.rsa;
+
+ if (rctx->md) {
+ if (tbslen != EVP_MD_size(rctx->md)) {
+ OPENSSL_PUT_ERROR(EVP, pkey_rsa_sign, EVP_R_INVALID_DIGEST_LENGTH);
+ return -1;
+ }
+
+ if (EVP_MD_type(rctx->md) == NID_mdc2) {
+ OPENSSL_PUT_ERROR(EVP, pkey_rsa_sign, EVP_R_NO_MDC2_SUPPORT);
+ ret = -1;
+ } else if (rctx->pad_mode == RSA_PKCS1_PADDING) {
+ unsigned int sltmp;
+ ret = RSA_sign(EVP_MD_type(rctx->md), tbs, tbslen, sig, &sltmp, rsa);
+ if (ret <= 0) {
+ return ret;
+ }
+ ret = sltmp;
+ } else if (rctx->pad_mode == RSA_PKCS1_PSS_PADDING) {
+ if (!setup_tbuf(rctx, ctx) ||
+ !RSA_padding_add_PKCS1_PSS_mgf1(rsa, rctx->tbuf, tbs, rctx->md,
+ rctx->mgf1md, rctx->saltlen)) {
+ return -1;
+ }
+ /* TODO(fork): don't use private_encrypt. */
+ ret = RSA_private_encrypt(RSA_size(rsa), rctx->tbuf, sig, rsa,
+ RSA_NO_PADDING);
+ } else {
+ return -1;
+ }
+ } else {
+ /* TODO(fork): don't use private_encrypt. */
+ ret = RSA_private_encrypt(tbslen, tbs, sig, ctx->pkey->pkey.rsa,
+ rctx->pad_mode);
+ }
+
+ if (ret < 0) {
+ return ret;
+ }
+ *siglen = ret;
+
+ return 1;
+}
+
+static int pkey_rsa_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig,
+ size_t siglen, const uint8_t *tbs,
+ size_t tbslen) {
+ RSA_PKEY_CTX *rctx = ctx->data;
+ RSA *rsa = ctx->pkey->pkey.rsa;
+ size_t rslen;
+
+ if (rctx->md) {
+ if (rctx->pad_mode == RSA_PKCS1_PADDING) {
+ return RSA_verify(EVP_MD_type(rctx->md), tbs, tbslen, sig, siglen, rsa);
+ }
+
+ if (rctx->pad_mode == RSA_PKCS1_PSS_PADDING) {
+ int ret;
+ if (!setup_tbuf(rctx, ctx)) {
+ return -1;
+ }
+ /* TODO(fork): don't use public_decrypt. */
+ ret = RSA_public_decrypt(siglen, sig, rctx->tbuf, rsa, RSA_NO_PADDING);
+ if (ret <= 0) {
+ return 0;
+ }
+ ret = RSA_verify_PKCS1_PSS_mgf1(rsa, tbs, rctx->md, rctx->mgf1md,
+ rctx->tbuf, rctx->saltlen);
+ if (ret <= 0) {
+ return 0;
+ }
+ return 1;
+ } else {
+ return -1;
+ }
+ } else {
+ if (!setup_tbuf(rctx, ctx)) {
+ return -1;
+ }
+ rslen = RSA_public_decrypt(siglen, sig, rctx->tbuf, rsa, rctx->pad_mode);
+ if (rslen == 0) {
+ return 0;
+ }
+ }
+
+ if (rslen != tbslen || CRYPTO_memcmp(tbs, rctx->tbuf, rslen) != 0) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int pkey_rsa_encrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen,
+ const uint8_t *in, size_t inlen) {
+ int ret;
+ RSA_PKEY_CTX *rctx = ctx->data;
+
+ if (rctx->pad_mode == RSA_PKCS1_OAEP_PADDING) {
+ int klen = RSA_size(ctx->pkey->pkey.rsa);
+ if (!setup_tbuf(rctx, ctx)) {
+ return -1;
+ }
+ if (!RSA_padding_add_PKCS1_OAEP_mgf1(rctx->tbuf, klen, in, inlen,
+ rctx->oaep_label, rctx->oaep_labellen,
+ rctx->md, rctx->mgf1md)) {
+ return -1;
+ }
+ ret = RSA_public_encrypt(klen, rctx->tbuf, out, ctx->pkey->pkey.rsa,
+ RSA_NO_PADDING);
+ } else {
+ ret =
+ RSA_public_encrypt(inlen, in, out, ctx->pkey->pkey.rsa, rctx->pad_mode);
+ }
+
+ if (ret < 0) {
+ return ret;
+ }
+ *outlen = ret;
+
+ return 1;
+}
+
+static int pkey_rsa_decrypt(EVP_PKEY_CTX *ctx, uint8_t *out,
+ size_t *outlen, const uint8_t *in,
+ size_t inlen) {
+ int ret;
+ RSA_PKEY_CTX *rctx = ctx->data;
+
+ if (rctx->pad_mode == RSA_PKCS1_OAEP_PADDING) {
+ int i;
+ if (!setup_tbuf(rctx, ctx)) {
+ return -1;
+ }
+ ret = RSA_private_decrypt(inlen, in, rctx->tbuf, ctx->pkey->pkey.rsa,
+ RSA_NO_PADDING);
+ if (ret <= 0) {
+ return ret;
+ }
+ for (i = 0; i < ret; i++) {
+ if (rctx->tbuf[i]) {
+ break;
+ }
+ }
+ ret = RSA_padding_check_PKCS1_OAEP_mgf1(
+ out, ret, rctx->tbuf + i, ret - i, ret, rctx->oaep_label,
+ rctx->oaep_labellen, rctx->md, rctx->mgf1md);
+ } else {
+ ret = RSA_private_decrypt(inlen, in, out, ctx->pkey->pkey.rsa,
+ rctx->pad_mode);
+ }
+
+ if (ret < 0) {
+ return ret;
+ }
+ *outlen = ret;
+
+ return 1;
+}
+
+static int check_padding_md(const EVP_MD *md, int padding) {
+ if (!md) {
+ return 1;
+ }
+
+ if (padding == RSA_NO_PADDING) {
+ OPENSSL_PUT_ERROR(EVP, check_padding_md, EVP_R_INVALID_PADDING_MODE);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int is_known_padding(int padding_mode) {
+ switch (padding_mode) {
+ case RSA_PKCS1_PADDING:
+ case RSA_SSLV23_PADDING:
+ case RSA_NO_PADDING:
+ case RSA_PKCS1_OAEP_PADDING:
+ case RSA_PKCS1_PSS_PADDING:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static int pkey_rsa_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) {
+ RSA_PKEY_CTX *rctx = ctx->data;
+ switch (type) {
+ case EVP_PKEY_CTRL_RSA_PADDING:
+ if (!is_known_padding(p1) || !check_padding_md(rctx->md, p1) ||
+ (p1 == RSA_PKCS1_PSS_PADDING &&
+ 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);
+ return -2;
+ }
+ if ((p1 == RSA_PKCS1_PSS_PADDING || p1 == RSA_PKCS1_OAEP_PADDING) &&
+ rctx->md == NULL) {
+ rctx->md = EVP_sha1();
+ }
+ rctx->pad_mode = p1;
+ return 1;
+
+ case EVP_PKEY_CTRL_GET_RSA_PADDING:
+ *(int *)p2 = rctx->pad_mode;
+ return 1;
+
+ 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);
+ return -2;
+ }
+ if (type == EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN) {
+ *(int *)p2 = rctx->saltlen;
+ } else {
+ if (p1 < -2) {
+ return -2;
+ }
+ rctx->saltlen = p1;
+ }
+ return 1;
+
+ case EVP_PKEY_CTRL_RSA_KEYGEN_BITS:
+ if (p1 < 256) {
+ OPENSSL_PUT_ERROR(EVP, pkey_rsa_ctrl, EVP_R_INVALID_KEYBITS);
+ return -2;
+ }
+ rctx->nbits = p1;
+ return 1;
+
+ case EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP:
+ if (!p2) {
+ return -2;
+ }
+ BN_free(rctx->pub_exp);
+ rctx->pub_exp = p2;
+ return 1;
+
+ 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);
+ return -2;
+ }
+ if (type == EVP_PKEY_CTRL_GET_RSA_OAEP_MD) {
+ *(const EVP_MD **)p2 = rctx->md;
+ } else {
+ rctx->md = p2;
+ }
+ return 1;
+
+ case EVP_PKEY_CTRL_MD:
+ if (!check_padding_md(p2, rctx->pad_mode)) {
+ return 0;
+ }
+ rctx->md = p2;
+ return 1;
+
+ case EVP_PKEY_CTRL_GET_MD:
+ *(const EVP_MD **)p2 = rctx->md;
+ return 1;
+
+ case EVP_PKEY_CTRL_RSA_MGF1_MD:
+ 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);
+ return -2;
+ }
+ if (type == EVP_PKEY_CTRL_GET_RSA_MGF1_MD) {
+ if (rctx->mgf1md) {
+ *(const EVP_MD **)p2 = rctx->mgf1md;
+ } else {
+ *(const EVP_MD **)p2 = rctx->md;
+ }
+ } else {
+ rctx->mgf1md = p2;
+ }
+ return 1;
+
+ 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);
+ return -2;
+ }
+ if (rctx->oaep_label) {
+ OPENSSL_free(rctx->oaep_label);
+ }
+ if (p2 && p1 > 0) {
+ /* TODO(fork): this seems wrong. Shouldn't it take a copy of the
+ * buffer? */
+ rctx->oaep_label = p2;
+ rctx->oaep_labellen = p1;
+ } else {
+ rctx->oaep_label = NULL;
+ rctx->oaep_labellen = 0;
+ }
+ return 1;
+
+ 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);
+ return -2;
+ }
+ *(uint8_t **)p2 = rctx->oaep_label;
+ return rctx->oaep_labellen;
+
+ case EVP_PKEY_CTRL_DIGESTINIT:
+ return 1;
+
+ default:
+ return -2;
+ }
+}
+
+static int pkey_rsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
+ RSA *rsa = NULL;
+ RSA_PKEY_CTX *rctx = ctx->data;
+
+ int ret;
+ if (!rctx->pub_exp) {
+ rctx->pub_exp = BN_new();
+ if (!rctx->pub_exp || !BN_set_word(rctx->pub_exp, RSA_F4))
+ return 0;
+ }
+ rsa = RSA_new();
+ if (!rsa) {
+ return 0;
+ }
+
+ ret = RSA_generate_key_ex(rsa, rctx->nbits, rctx->pub_exp, NULL);
+ if (ret > 0) {
+ EVP_PKEY_assign_RSA(pkey, rsa);
+ } else {
+ RSA_free(rsa);
+ }
+ return ret;
+}
+
+const EVP_PKEY_METHOD rsa_pkey_meth = {
+ EVP_PKEY_RSA, EVP_PKEY_FLAG_AUTOARGLEN, 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, 0,
+ 0, 0, 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) {
+ return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, EVP_PKEY_CTRL_RSA_PADDING,
+ padding, NULL);
+}
+
+int EVP_PKEY_CTX_get_rsa_padding(EVP_PKEY_CTX *ctx, int *out_padding) {
+ return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, EVP_PKEY_CTRL_GET_RSA_PADDING,
+ 0, out_padding);
+}
+
+int EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, int salt_len) {
+ return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA,
+ (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY),
+ EVP_PKEY_CTRL_RSA_PSS_SALTLEN, salt_len, NULL);
+}
+
+int EVP_PKEY_CTX_get_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, int *out_salt_len) {
+ return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA,
+ (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY),
+ EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN, 0, out_salt_len);
+}
+
+int EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX *ctx, int bits) {
+ return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_KEYGEN,
+ EVP_PKEY_CTRL_RSA_KEYGEN_BITS, bits, NULL);
+}
+
+int EVP_PKEY_CTX_set_rsa_keygen_pubexp(EVP_PKEY_CTX *ctx, BIGNUM *e) {
+ return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_KEYGEN,
+ EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP, 0, e);
+}
+
+int EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) {
+ return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,
+ EVP_PKEY_CTRL_RSA_OAEP_MD, 0, (void *)md);
+}
+
+int EVP_PKEY_CTX_get_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md) {
+ return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,
+ EVP_PKEY_CTRL_GET_RSA_OAEP_MD, 0, (void*) out_md);
+}
+
+int EVP_PKEY_CTX_set_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) {
+ return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA,
+ EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT,
+ EVP_PKEY_CTRL_RSA_MGF1_MD, 0, (void*) md);
+}
+
+int EVP_PKEY_CTX_get_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md) {
+ return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA,
+ EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT,
+ EVP_PKEY_CTRL_GET_RSA_MGF1_MD, 0, (void*) out_md);
+}
+
+int EVP_PKEY_CTX_set0_rsa_oaep_label(EVP_PKEY_CTX *ctx, const uint8_t *label,
+ size_t label_len) {
+ int label_len_int = label_len;
+ if (((size_t) label_len_int) != label_len) {
+ return -2;
+ }
+
+ return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,
+ EVP_PKEY_CTRL_RSA_OAEP_LABEL, label_len,
+ (void *)label);
+}
+
+int EVP_PKEY_CTX_get0_rsa_oaep_label(EVP_PKEY_CTX *ctx,
+ const uint8_t **out_label) {
+ return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,
+ EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL, 0, (void *) out_label);
+}
diff --git a/crypto/evp/p_rsa_asn1.c b/crypto/evp/p_rsa_asn1.c
new file mode 100644
index 0000000..6b94ed7
--- /dev/null
+++ b/crypto/evp/p_rsa_asn1.c
@@ -0,0 +1,751 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2006.
+ */
+/* ====================================================================
+ * Copyright (c) 2006 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/asn1t.h>
+#include <openssl/digest.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/rsa.h>
+#include <openssl/x509.h>
+
+#include "../rsa/internal.h"
+#include "internal.h"
+
+
+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) {
+ return 0;
+ }
+
+ if (!X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_RSA), V_ASN1_NULL, NULL,
+ encoded, len)) {
+ OPENSSL_free(encoded);
+ return 0;
+ }
+
+ return 1;
+}
+
+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);
+ return 0;
+ }
+ EVP_PKEY_assign_RSA(pkey, rsa);
+ return 1;
+}
+
+static int rsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
+ return BN_cmp(b->pkey.rsa->n, a->pkey.rsa->n) == 0 &&
+ BN_cmp(b->pkey.rsa->e, a->pkey.rsa->e) == 0;
+}
+
+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);
+ 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);
+ return 0;
+ }
+
+ return 1;
+}
+
+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);
+ return 0;
+ }
+
+ rsa = d2i_RSAPrivateKey(NULL, &p, pklen);
+ if (rsa == NULL) {
+ OPENSSL_PUT_ERROR(EVP, rsa_priv_decode, ERR_R_RSA_LIB);
+ return 0;
+ }
+
+ EVP_PKEY_assign_RSA(pkey, rsa);
+ return 1;
+}
+
+static int int_rsa_size(const EVP_PKEY *pkey) {
+ return RSA_size(pkey->pkey.rsa);
+}
+
+static int rsa_bits(const EVP_PKEY *pkey) {
+ return BN_num_bits(pkey->pkey.rsa->n);
+}
+
+static void int_rsa_free(EVP_PKEY *pkey) { RSA_free(pkey->pkey.rsa); }
+
+static void update_buflen(const BIGNUM *b, size_t *pbuflen) {
+ size_t i;
+
+ if (!b) {
+ return;
+ }
+
+ i = BN_num_bytes(b);
+ if (*pbuflen < i) {
+ *pbuflen = i;
+ }
+}
+
+static int do_rsa_print(BIO *out, const RSA *rsa, int off,
+ int include_private) {
+ char *str;
+ const char *s;
+ uint8_t *m = NULL;
+ int ret = 0, mod_len = 0;
+ size_t buf_len = 0;
+
+ update_buflen(rsa->n, &buf_len);
+ update_buflen(rsa->e, &buf_len);
+
+ if (include_private) {
+ update_buflen(rsa->d, &buf_len);
+ update_buflen(rsa->p, &buf_len);
+ update_buflen(rsa->q, &buf_len);
+ update_buflen(rsa->dmp1, &buf_len);
+ update_buflen(rsa->dmq1, &buf_len);
+ update_buflen(rsa->iqmp, &buf_len);
+ }
+
+ m = (uint8_t *)OPENSSL_malloc(buf_len + 10);
+ if (m == NULL) {
+ OPENSSL_PUT_ERROR(EVP, do_rsa_print, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (rsa->n != NULL) {
+ mod_len = BN_num_bits(rsa->n);
+ }
+
+ if (!BIO_indent(out, off, 128)) {
+ goto err;
+ }
+
+ if (include_private && rsa->d) {
+ if (BIO_printf(out, "Private-Key: (%d bit)\n", mod_len) <= 0) {
+ goto err;
+ }
+ str = "modulus:";
+ s = "publicExponent:";
+ } else {
+ if (BIO_printf(out, "Public-Key: (%d bit)\n", mod_len) <= 0) {
+ goto err;
+ }
+ str = "Modulus:";
+ s = "Exponent:";
+ }
+ if (!ASN1_bn_print(out, str, rsa->n, m, off) ||
+ !ASN1_bn_print(out, s, rsa->e, m, off)) {
+ goto err;
+ }
+
+ if (include_private) {
+ if (!ASN1_bn_print(out, "privateExponent:", rsa->d, m, off) ||
+ !ASN1_bn_print(out, "prime1:", rsa->p, m, off) ||
+ !ASN1_bn_print(out, "prime2:", rsa->q, m, off) ||
+ !ASN1_bn_print(out, "exponent1:", rsa->dmp1, m, off) ||
+ !ASN1_bn_print(out, "exponent2:", rsa->dmq1, m, off) ||
+ !ASN1_bn_print(out, "coefficient:", rsa->iqmp, m, off)) {
+ goto err;
+ }
+ }
+ ret = 1;
+
+err:
+ if (m != NULL) {
+ OPENSSL_free(m);
+ }
+ return ret;
+}
+
+static int rsa_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *ctx) {
+ return do_rsa_print(bp, pkey->pkey.rsa, indent, 0);
+}
+
+
+static int rsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent,
+ ASN1_PCTX *ctx) {
+ return do_rsa_print(bp, pkey->pkey.rsa, indent, 1);
+}
+
+/* Given an MGF1 Algorithm ID decode to an Algorithm Identifier */
+static X509_ALGOR *rsa_mgf1_decode(X509_ALGOR *alg) {
+ const uint8_t *p;
+ int plen;
+
+ if (alg == NULL ||
+ OBJ_obj2nid(alg->algorithm) != NID_mgf1 ||
+ alg->parameter->type != V_ASN1_SEQUENCE) {
+ return NULL;
+ }
+
+ p = alg->parameter->value.sequence->data;
+ plen = alg->parameter->value.sequence->length;
+ return d2i_X509_ALGOR(NULL, &p, plen);
+}
+
+static RSA_PSS_PARAMS *rsa_pss_decode(const X509_ALGOR *alg,
+ X509_ALGOR **pmaskHash) {
+ const uint8_t *p;
+ int plen;
+ RSA_PSS_PARAMS *pss;
+
+ *pmaskHash = NULL;
+
+ if (!alg->parameter || alg->parameter->type != V_ASN1_SEQUENCE) {
+ return NULL;
+ }
+ p = alg->parameter->value.sequence->data;
+ plen = alg->parameter->value.sequence->length;
+ pss = d2i_RSA_PSS_PARAMS(NULL, &p, plen);
+
+ if (!pss) {
+ return NULL;
+ }
+
+ *pmaskHash = rsa_mgf1_decode(pss->maskGenAlgorithm);
+
+ return pss;
+}
+
+static int rsa_pss_param_print(BIO *bp, RSA_PSS_PARAMS *pss,
+ X509_ALGOR *maskHash, int indent) {
+ int rv = 0;
+
+ if (!pss) {
+ if (BIO_puts(bp, " (INVALID PSS PARAMETERS)\n") <= 0) {
+ return 0;
+ }
+ return 1;
+ }
+
+ if (BIO_puts(bp, "\n") <= 0 ||
+ !BIO_indent(bp, indent, 128) ||
+ BIO_puts(bp, "Hash Algorithm: ") <= 0) {
+ goto err;
+ }
+
+ if (pss->hashAlgorithm) {
+ if (i2a_ASN1_OBJECT(bp, pss->hashAlgorithm->algorithm) <= 0) {
+ goto err;
+ }
+ } else if (BIO_puts(bp, "sha1 (default)") <= 0) {
+ goto err;
+ }
+
+ if (BIO_puts(bp, "\n") <= 0 ||
+ !BIO_indent(bp, indent, 128) ||
+ BIO_puts(bp, "Mask Algorithm: ") <= 0) {
+ goto err;
+ }
+
+ if (pss->maskGenAlgorithm) {
+ if (i2a_ASN1_OBJECT(bp, pss->maskGenAlgorithm->algorithm) <= 0 ||
+ BIO_puts(bp, " with ") <= 0) {
+ goto err;
+ }
+
+ if (maskHash) {
+ if (i2a_ASN1_OBJECT(bp, maskHash->algorithm) <= 0) {
+ goto err;
+ }
+ } else if (BIO_puts(bp, "INVALID") <= 0) {
+ goto err;
+ }
+ } else if (BIO_puts(bp, "mgf1 with sha1 (default)") <= 0) {
+ goto err;
+ }
+ BIO_puts(bp, "\n");
+
+ if (!BIO_indent(bp, indent, 128) ||
+ BIO_puts(bp, "Salt Length: 0x") <= 0) {
+ goto err;
+ }
+
+ if (pss->saltLength) {
+ if (i2a_ASN1_INTEGER(bp, pss->saltLength) <= 0) {
+ goto err;
+ }
+ } else if (BIO_puts(bp, "0x14 (default)") <= 0) {
+ goto err;
+ }
+ BIO_puts(bp, "\n");
+
+ if (!BIO_indent(bp, indent, 128) ||
+ BIO_puts(bp, "Trailer Field: 0x") <= 0) {
+ goto err;
+ }
+
+ if (pss->trailerField) {
+ if (i2a_ASN1_INTEGER(bp, pss->trailerField) <= 0) {
+ goto err;
+ }
+ } else if (BIO_puts(bp, "BC (default)") <= 0) {
+ goto err;
+ }
+ BIO_puts(bp, "\n");
+
+ rv = 1;
+
+err:
+ return rv;
+}
+
+static int rsa_sig_print(BIO *bp, const X509_ALGOR *sigalg,
+ const ASN1_STRING *sig, int indent, ASN1_PCTX *pctx) {
+ if (OBJ_obj2nid(sigalg->algorithm) == NID_rsassaPss) {
+ int rv;
+ RSA_PSS_PARAMS *pss;
+ X509_ALGOR *maskHash;
+
+ pss = rsa_pss_decode(sigalg, &maskHash);
+ rv = rsa_pss_param_print(bp, pss, maskHash, indent);
+ if (pss) {
+ RSA_PSS_PARAMS_free(pss);
+ }
+ if (maskHash) {
+ X509_ALGOR_free(maskHash);
+ }
+ if (!rv) {
+ return 0;
+ }
+ } else if (!sig && BIO_puts(bp, "\n") <= 0) {
+ return 0;
+ }
+
+ if (sig) {
+ return X509_signature_dump(bp, sig, indent);
+ }
+ return 1;
+}
+
+static int rsa_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2) {
+ X509_ALGOR *alg = NULL;
+ switch (op) {
+ case ASN1_PKEY_CTRL_DEFAULT_MD_NID:
+ *(int *)arg2 = NID_sha1;
+ return 1;
+
+ default:
+ return -2;
+ }
+
+ if (alg) {
+ X509_ALGOR_set0(alg, OBJ_nid2obj(NID_rsaEncryption), V_ASN1_NULL, 0);
+ }
+
+ return 1;
+}
+
+static int old_rsa_priv_decode(EVP_PKEY *pkey, const unsigned char **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);
+ return 0;
+ }
+ EVP_PKEY_assign_RSA(pkey, rsa);
+ return 1;
+}
+
+static int old_rsa_priv_encode(const EVP_PKEY *pkey, unsigned char **pder) {
+ return i2d_RSAPrivateKey(pkey->pkey.rsa, pder);
+}
+
+/* allocate and set algorithm ID from EVP_MD, default SHA1 */
+static int rsa_md_to_algor(X509_ALGOR **palg, const EVP_MD *md) {
+ if (EVP_MD_type(md) == NID_sha1) {
+ return 1;
+ }
+ *palg = X509_ALGOR_new();
+ if (!*palg) {
+ return 0;
+ }
+ X509_ALGOR_set_md(*palg, md);
+ return 1;
+}
+
+/* Allocate and set MGF1 algorithm ID from EVP_MD */
+static int rsa_md_to_mgf1(X509_ALGOR **palg, const EVP_MD *mgf1md) {
+ X509_ALGOR *algtmp = NULL;
+ ASN1_STRING *stmp = NULL;
+ *palg = NULL;
+
+ if (EVP_MD_type(mgf1md) == NID_sha1) {
+ return 1;
+ }
+ /* need to embed algorithm ID inside another */
+ if (!rsa_md_to_algor(&algtmp, mgf1md) ||
+ !ASN1_item_pack(algtmp, ASN1_ITEM_rptr(X509_ALGOR), &stmp)) {
+ goto err;
+ }
+ *palg = X509_ALGOR_new();
+ if (!*palg) {
+ goto err;
+ }
+ X509_ALGOR_set0(*palg, OBJ_nid2obj(NID_mgf1), V_ASN1_SEQUENCE, stmp);
+ stmp = NULL;
+
+err:
+ if (stmp)
+ ASN1_STRING_free(stmp);
+ if (algtmp)
+ X509_ALGOR_free(algtmp);
+ if (*palg)
+ return 1;
+
+ return 0;
+}
+
+/* convert algorithm ID to EVP_MD, default SHA1 */
+static const EVP_MD *rsa_algor_to_md(X509_ALGOR *alg) {
+ const EVP_MD *md;
+ if (!alg) {
+ return EVP_sha1();
+ }
+ md = EVP_get_digestbyobj(alg->algorithm);
+ if (md == NULL) {
+ OPENSSL_PUT_ERROR(EVP, rsa_algor_to_md, EVP_R_UNKNOWN_DIGEST);
+ }
+ return md;
+}
+
+/* convert MGF1 algorithm ID to EVP_MD, default SHA1 */
+static const EVP_MD *rsa_mgf1_to_md(X509_ALGOR *alg, X509_ALGOR *maskHash) {
+ const EVP_MD *md;
+ if (!alg) {
+ return EVP_sha1();
+ }
+ /* 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);
+ return NULL;
+ }
+ if (!maskHash) {
+ OPENSSL_PUT_ERROR(EVP, rsa_mgf1_to_md, 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);
+ return NULL;
+ }
+ return md;
+}
+
+/* rsa_ctx_to_pss converts EVP_PKEY_CTX in PSS mode into corresponding
+ * algorithm parameter, suitable for setting as an AlgorithmIdentifier. */
+static ASN1_STRING *rsa_ctx_to_pss(EVP_PKEY_CTX *pkctx) {
+ const EVP_MD *sigmd, *mgf1md;
+ RSA_PSS_PARAMS *pss = NULL;
+ ASN1_STRING *os = NULL;
+ EVP_PKEY *pk = EVP_PKEY_CTX_get0_pkey(pkctx);
+ int saltlen, rv = 0;
+
+ if (EVP_PKEY_CTX_get_signature_md(pkctx, &sigmd) <= 0 ||
+ EVP_PKEY_CTX_get_rsa_mgf1_md(pkctx, &mgf1md) <= 0 ||
+ !EVP_PKEY_CTX_get_rsa_pss_saltlen(pkctx, &saltlen)) {
+ goto err;
+ }
+
+ if (saltlen == -1) {
+ saltlen = EVP_MD_size(sigmd);
+ } else if (saltlen == -2) {
+ saltlen = EVP_PKEY_size(pk) - EVP_MD_size(sigmd) - 2;
+ if (((EVP_PKEY_bits(pk) - 1) & 0x7) == 0) {
+ saltlen--;
+ }
+ } else {
+ goto err;
+ }
+
+ pss = RSA_PSS_PARAMS_new();
+ if (!pss) {
+ goto err;
+ }
+
+ if (saltlen != 20) {
+ pss->saltLength = ASN1_INTEGER_new();
+ if (!pss->saltLength ||
+ !ASN1_INTEGER_set(pss->saltLength, saltlen)) {
+ goto err;
+ }
+ }
+
+ if (!rsa_md_to_algor(&pss->hashAlgorithm, sigmd) ||
+ !rsa_md_to_mgf1(&pss->maskGenAlgorithm, mgf1md)) {
+ goto err;
+ }
+
+ /* Finally create string with pss parameter encoding. */
+ if (!ASN1_item_pack(pss, ASN1_ITEM_rptr(RSA_PSS_PARAMS), &os)) {
+ goto err;
+ }
+ rv = 1;
+
+err:
+ if (pss)
+ RSA_PSS_PARAMS_free(pss);
+ if (rv)
+ return os;
+ if (os)
+ ASN1_STRING_free(os);
+ return NULL;
+}
+
+/* From PSS AlgorithmIdentifier set public key parameters. If pkey
+ * isn't NULL then the EVP_MD_CTX is setup and initalised. If it
+ * is NULL parameters are passed to pkctx instead. */
+static int rsa_pss_to_ctx(EVP_MD_CTX *ctx, EVP_PKEY_CTX *pkctx,
+ X509_ALGOR *sigalg, EVP_PKEY *pkey) {
+ int ret = -1;
+ int saltlen;
+ const EVP_MD *mgf1md = NULL, *md = NULL;
+ RSA_PSS_PARAMS *pss;
+ X509_ALGOR *maskHash;
+
+ /* 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);
+ return -1;
+ }
+ /* 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);
+ goto err;
+ }
+
+ mgf1md = rsa_mgf1_to_md(pss->maskGenAlgorithm, maskHash);
+ if (!mgf1md) {
+ goto err;
+ }
+ md = rsa_algor_to_md(pss->hashAlgorithm);
+ if (!md) {
+ goto err;
+ }
+
+ saltlen = 20;
+ if (pss->saltLength) {
+ saltlen = ASN1_INTEGER_get(pss->saltLength);
+
+ /* 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);
+ goto err;
+ }
+ }
+
+ /* 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);
+ goto err;
+ }
+
+ if (pkey) {
+ if (!EVP_DigestVerifyInit(ctx, &pkctx, md, NULL, pkey)) {
+ goto err;
+ }
+ } else {
+ const EVP_MD *checkmd;
+ if (EVP_PKEY_CTX_get_signature_md(pkctx, &checkmd) <= 0) {
+ goto err;
+ }
+ if (EVP_MD_type(md) != EVP_MD_type(checkmd)) {
+ OPENSSL_PUT_ERROR(EVP, rsa_pss_to_ctx, EVP_R_DIGEST_DOES_NOT_MATCH);
+ goto err;
+ }
+ }
+
+ if (EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_PSS_PADDING) <= 0 ||
+ EVP_PKEY_CTX_set_rsa_pss_saltlen(pkctx, saltlen) <= 0 ||
+ EVP_PKEY_CTX_set_rsa_mgf1_md(pkctx, mgf1md) <= 0) {
+ goto err;
+ }
+
+ ret = 1;
+
+err:
+ RSA_PSS_PARAMS_free(pss);
+ if (maskHash) {
+ X509_ALGOR_free(maskHash);
+ }
+ return ret;
+}
+
+/* Customised RSA item verification routine. This is called
+ * when a signature is encountered requiring special handling. We
+ * currently only handle PSS. */
+static int rsa_item_verify(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
+ X509_ALGOR *sigalg, ASN1_BIT_STRING *sig,
+ EVP_PKEY *pkey) {
+ /* Sanity check: make sure it is PSS */
+ if (OBJ_obj2nid(sigalg->algorithm) != NID_rsassaPss) {
+ OPENSSL_PUT_ERROR(EVP, rsa_item_verify, EVP_R_UNSUPPORTED_SIGNATURE_TYPE);
+ return -1;
+ }
+ if (rsa_pss_to_ctx(ctx, NULL, sigalg, pkey)) {
+ /* Carry on */
+ return 2;
+ }
+
+ return -1;
+}
+
+static int rsa_item_sign(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
+ X509_ALGOR *alg1, X509_ALGOR *alg2,
+ ASN1_BIT_STRING *sig) {
+ int pad_mode;
+ EVP_PKEY_CTX *pkctx = ctx->pctx;
+ if (EVP_PKEY_CTX_get_rsa_padding(pkctx, &pad_mode) <= 0) {
+ return 0;
+ }
+ if (pad_mode == RSA_PKCS1_PADDING) {
+ return 2;
+ }
+ if (pad_mode == RSA_PKCS1_PSS_PADDING) {
+ ASN1_STRING *os1 = rsa_ctx_to_pss(pkctx);
+ if (!os1) {
+ return 0;
+ }
+ /* Duplicate parameters if we have to */
+ if (alg2) {
+ ASN1_STRING *os2 = ASN1_STRING_dup(os1);
+ if (!os2) {
+ ASN1_STRING_free(os1);
+ return 0;
+ }
+ X509_ALGOR_set0(alg2, OBJ_nid2obj(NID_rsassaPss), V_ASN1_SEQUENCE, os2);
+ }
+ X509_ALGOR_set0(alg1, OBJ_nid2obj(NID_rsassaPss), V_ASN1_SEQUENCE, os1);
+ return 3;
+ }
+ return 2;
+}
+
+const EVP_PKEY_ASN1_METHOD rsa_asn1_meth = {
+ EVP_PKEY_RSA,
+ EVP_PKEY_RSA,
+ ASN1_PKEY_SIGPARAM_NULL,
+
+ "RSA",
+ "OpenSSL RSA method",
+
+ rsa_pub_decode,
+ rsa_pub_encode,
+ rsa_pub_cmp,
+ rsa_pub_print,
+
+ rsa_priv_decode,
+ rsa_priv_encode,
+ rsa_priv_print,
+
+ int_rsa_size,
+ rsa_bits,
+
+ 0,0,0,0,0,0,
+
+ rsa_sig_print,
+ int_rsa_free,
+ rsa_pkey_ctrl,
+
+ old_rsa_priv_decode,
+ old_rsa_priv_encode,
+
+ rsa_item_verify,
+ rsa_item_sign,
+};
+
+const EVP_PKEY_ASN1_METHOD rsa_asn1_meth_2 = {
+ EVP_PKEY_RSA2,
+ EVP_PKEY_RSA,
+ ASN1_PKEY_ALIAS,
+};
diff --git a/crypto/evp/pbkdf.c b/crypto/evp/pbkdf.c
new file mode 100644
index 0000000..4ab10f4
--- /dev/null
+++ b/crypto/evp/pbkdf.c
@@ -0,0 +1,140 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999 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/hmac.h>
+
+
+int PKCS5_PBKDF2_HMAC(const char *password, int password_len,
+ const uint8_t *salt, size_t salt_len, unsigned iterations,
+ const EVP_MD *digest, size_t key_len, uint8_t *out_key) {
+ uint8_t digest_tmp[EVP_MAX_MD_SIZE], *p, itmp[4];
+ size_t cplen, mdlen, tkeylen, k;
+ unsigned j;
+ uint32_t i = 1;
+ HMAC_CTX hctx_tpl, hctx;
+
+ mdlen = EVP_MD_size(digest);
+ HMAC_CTX_init(&hctx_tpl);
+ p = out_key;
+ tkeylen = key_len;
+ if (password == NULL) {
+ password_len = 0;
+ } else if (password_len == -1) {
+ /* TODO(fork): remove this hack. The OpenSSL code took the strlen when the
+ * length is given as -1. */
+ password_len = strlen(password);
+ }
+ if (!HMAC_Init_ex(&hctx_tpl, password, password_len, digest, NULL)) {
+ HMAC_CTX_cleanup(&hctx_tpl);
+ return 0;
+ }
+ while (tkeylen) {
+ if (tkeylen > mdlen) {
+ cplen = mdlen;
+ } else {
+ cplen = tkeylen;
+ }
+ /* We are unlikely to ever use more than 256 blocks (5120 bits!)
+ * but just in case... */
+ itmp[0] = (uint8_t)((i >> 24) & 0xff);
+ itmp[1] = (uint8_t)((i >> 16) & 0xff);
+ itmp[2] = (uint8_t)((i >> 8) & 0xff);
+ itmp[3] = (uint8_t)(i & 0xff);
+ if (!HMAC_CTX_copy(&hctx, &hctx_tpl)) {
+ HMAC_CTX_cleanup(&hctx_tpl);
+ return 0;
+ }
+ if (!HMAC_Update(&hctx, salt, salt_len) ||
+ !HMAC_Update(&hctx, itmp, 4) ||
+ !HMAC_Final(&hctx, digest_tmp, NULL)) {
+ HMAC_CTX_cleanup(&hctx_tpl);
+ HMAC_CTX_cleanup(&hctx);
+ return 0;
+ }
+ HMAC_CTX_cleanup(&hctx);
+ memcpy(p, digest_tmp, cplen);
+ for (j = 1; j < iterations; j++) {
+ if (!HMAC_CTX_copy(&hctx, &hctx_tpl)) {
+ HMAC_CTX_cleanup(&hctx_tpl);
+ return 0;
+ }
+ if (!HMAC_Update(&hctx, digest_tmp, mdlen) ||
+ !HMAC_Final(&hctx, digest_tmp, NULL)) {
+ HMAC_CTX_cleanup(&hctx_tpl);
+ HMAC_CTX_cleanup(&hctx);
+ return 0;
+ }
+ HMAC_CTX_cleanup(&hctx);
+ for (k = 0; k < cplen; k++) {
+ p[k] ^= digest_tmp[k];
+ }
+ }
+ tkeylen -= cplen;
+ i++;
+ p += cplen;
+ }
+ HMAC_CTX_cleanup(&hctx_tpl);
+ return 1;
+}
+
+int PKCS5_PBKDF2_HMAC_SHA1(const char *password, int password_len,
+ const uint8_t *salt, size_t salt_len,
+ unsigned iterations, size_t key_len,
+ uint8_t *out_key) {
+ return PKCS5_PBKDF2_HMAC(password, password_len, salt, salt_len, iterations,
+ EVP_sha1(), key_len, out_key);
+}
diff --git a/crypto/evp/sign.c b/crypto/evp/sign.c
new file mode 100644
index 0000000..c32e5ce
--- /dev/null
+++ b/crypto/evp/sign.c
@@ -0,0 +1,162 @@
+/* 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/evp.h>
+
+#include <openssl/digest.h>
+#include <openssl/err.h>
+
+#include "internal.h"
+
+
+int EVP_SignInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl) {
+ return EVP_DigestInit_ex(ctx, type, impl);
+}
+
+int EVP_SignInit(EVP_MD_CTX *ctx, const EVP_MD *type) {
+ return EVP_DigestInit(ctx, type);
+}
+
+int EVP_SignUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) {
+ return EVP_DigestUpdate(ctx, data, len);
+}
+
+int EVP_SignFinal(const EVP_MD_CTX *ctx, uint8_t *sig,
+ unsigned int *out_sig_len, EVP_PKEY *pkey) {
+ uint8_t m[EVP_MAX_MD_SIZE];
+ unsigned int m_len;
+ int ret = 0;
+ EVP_MD_CTX tmp_ctx;
+ EVP_PKEY_CTX *pkctx = NULL;
+ size_t sig_len = EVP_PKEY_size(pkey);
+
+ *out_sig_len = 0;
+ EVP_MD_CTX_init(&tmp_ctx);
+ if (!EVP_MD_CTX_copy_ex(&tmp_ctx, ctx) ||
+ !EVP_DigestFinal_ex(&tmp_ctx, m, &m_len)) {
+ goto out;
+ }
+ EVP_MD_CTX_cleanup(&tmp_ctx);
+
+/* TODO(fork): this used to be used only with SHA-family hashes. Now we've
+ * removed the flag completely. Why was it added for just those hashes? */
+#if 0
+ if (ctx->digest->flags & EVP_MD_FLAG_PKEY_METHOD_SIGNATURE) {
+#endif
+
+ pkctx = EVP_PKEY_CTX_new(pkey, NULL);
+ if (!pkctx || EVP_PKEY_sign_init(pkctx) <= 0 ||
+ EVP_PKEY_CTX_set_signature_md(pkctx, ctx->digest) <= 0 ||
+ EVP_PKEY_sign(pkctx, sig, &sig_len, m, m_len) <= 0) {
+ goto out;
+ }
+ *out_sig_len = sig_len;
+ ret = 1;
+
+out:
+ if (pkctx) {
+ EVP_PKEY_CTX_free(pkctx);
+ }
+
+ return ret;
+}
+
+int EVP_VerifyInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl) {
+ return EVP_DigestInit_ex(ctx, type, impl);
+}
+
+int EVP_VerifyInit(EVP_MD_CTX *ctx, const EVP_MD *type) {
+ return EVP_DigestInit(ctx, type);
+}
+
+int EVP_VerifyUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) {
+ return EVP_DigestUpdate(ctx, data, len);
+}
+
+int EVP_VerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig, size_t sig_len,
+ EVP_PKEY *pkey) {
+ uint8_t m[EVP_MAX_MD_SIZE];
+ unsigned int m_len;
+ int ret = 0;
+ EVP_MD_CTX tmp_ctx;
+ EVP_PKEY_CTX *pkctx = NULL;
+
+ EVP_MD_CTX_init(&tmp_ctx);
+ if (!EVP_MD_CTX_copy_ex(&tmp_ctx, ctx) ||
+ !EVP_DigestFinal_ex(&tmp_ctx, m, &m_len)) {
+ EVP_MD_CTX_cleanup(&tmp_ctx);
+ goto out;
+ }
+ EVP_MD_CTX_cleanup(&tmp_ctx);
+
+/* TODO(fork): this used to be used only with SHA-family hashes. Now we've
+ * removed the flag completely. Why was it added for just those hashes? */
+#if 0
+ if (ctx->digest->flags & EVP_MD_FLAG_PKEY_METHOD_SIGNATURE) {
+#endif
+ pkctx = EVP_PKEY_CTX_new(pkey, NULL);
+ if (!pkctx ||
+ EVP_PKEY_verify_init(pkctx) <= 0 ||
+ EVP_PKEY_CTX_set_signature_md(pkctx, ctx->digest) <= 0) {
+ goto out;
+ }
+ ret = EVP_PKEY_verify(pkctx, sig, sig_len, m, m_len);
+
+out:
+ EVP_PKEY_CTX_free(pkctx);
+ return ret;
+}
+
diff --git a/crypto/ex_data.c b/crypto/ex_data.c
new file mode 100644
index 0000000..00b8ff3
--- /dev/null
+++ b/crypto/ex_data.c
@@ -0,0 +1,227 @@
+/* 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.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2001 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). */
+
+#include <openssl/ex_data.h>
+
+#include <openssl/err.h>
+#include <openssl/thread.h>
+
+#include "crypto_error.h"
+#include "internal.h"
+
+
+/* global_impl is the implementation that we use at runtime. */
+static const CRYPTO_EX_DATA_IMPL *global_impl = NULL;
+
+/* ex_data_default_impl is a the default implementation, defined in
+ * ex_data_impl.c. */
+extern const CRYPTO_EX_DATA_IMPL ex_data_default_impl;
+
+/* get_impl returns the current ex_data implementatation. */
+static const CRYPTO_EX_DATA_IMPL *get_impl() {
+ const CRYPTO_EX_DATA_IMPL *impl;
+
+ CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA);
+ impl = global_impl;
+ CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA);
+
+ if (impl != NULL) {
+ return impl;
+ }
+
+ CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
+ if (global_impl == NULL) {
+ global_impl = &ex_data_default_impl;
+ }
+ impl = global_impl;
+ CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
+ return impl;
+}
+
+int CRYPTO_get_ex_new_index(int class_value, long argl, void *argp,
+ CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
+ CRYPTO_EX_free *free_func) {
+ const CRYPTO_EX_DATA_IMPL *const impl = get_impl();
+ return impl->get_new_index(class_value, argl, argp, new_func, dup_func,
+ free_func);
+}
+
+int CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int index, void *val) {
+ int n, i;
+
+ 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);
+ return 0;
+ }
+ }
+
+ n = sk_void_num(ad->sk);
+
+ /* 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);
+ return 0;
+ }
+ }
+
+ sk_void_set(ad->sk, index, val);
+ return 1;
+}
+
+void *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int idx) {
+ if (ad->sk == NULL || idx >= sk_void_num(ad->sk)) {
+ return NULL;
+ }
+ return sk_void_value(ad->sk, idx);
+}
+
+int CRYPTO_ex_data_new_class(void) {
+ const CRYPTO_EX_DATA_IMPL *const impl = get_impl();
+ return impl->new_class();
+}
+
+int CRYPTO_new_ex_data(int class_value, void *obj, CRYPTO_EX_DATA *ad) {
+ const CRYPTO_EX_DATA_IMPL *const impl = get_impl();
+ return impl->new_ex_data(class_value, obj, ad);
+}
+
+int CRYPTO_dup_ex_data(int class_value, CRYPTO_EX_DATA *to,
+ const CRYPTO_EX_DATA *from) {
+ const CRYPTO_EX_DATA_IMPL *const impl = get_impl();
+ return impl->dup_ex_data(class_value, to, from);
+}
+
+void CRYPTO_free_ex_data(int class_value, void *obj, CRYPTO_EX_DATA *ad) {
+ const CRYPTO_EX_DATA_IMPL *const impl = get_impl();
+ impl->free_ex_data(class_value, obj, ad);
+}
+
+const CRYPTO_EX_DATA_IMPL *CRYPTO_get_ex_data_implementation(void) {
+ return get_impl();
+}
+
+int CRYPTO_set_ex_data_implementation(const CRYPTO_EX_DATA_IMPL *impl) {
+ int ret = 0;
+
+ CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
+ if (global_impl == NULL) {
+ ret = 1;
+ global_impl = impl;
+ }
+ CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
+
+ return ret;
+}
+
+void CRYPTO_cleanup_all_ex_data(void) {
+ const CRYPTO_EX_DATA_IMPL *const impl = get_impl();
+ impl->cleanup();
+}
diff --git a/crypto/ex_data.h b/crypto/ex_data.h
new file mode 100644
index 0000000..9dfe5cf
--- /dev/null
+++ b/crypto/ex_data.h
@@ -0,0 +1,295 @@
+/* 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.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2001 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_EX_DATA_H
+#define OPENSSL_HEADER_EX_DATA_H
+
+#include <openssl/base.h>
+
+#include <openssl/stack.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* ex_data is a mechanism for associating arbitrary extra data with objects.
+ * The different types of objects which can have data associated with them are
+ * called "classes" and there are predefined classes for all the OpenSSL
+ * objects that support ex_data.
+ *
+ * Within a given class, different users can be assigned indexes in which to
+ * store their data. Each index has callback functions that are called when a
+ * new object of that type is created, freed and duplicated. */
+
+
+typedef struct crypto_ex_data_st CRYPTO_EX_DATA;
+
+/* CRYPTO_EX_new is the type of a callback function that is called whenever a
+ * new object of a given class is created. For example, if this callback has
+ * been passed to |CRYPTO_get_ex_new_index| with a |class| of
+ * |CRYPTO_EX_INDEX_SSL| then it'll be called each time an SSL* is created.
+ *
+ * The callback is passed the new object (i.e. the SSL*) in |parent|. The
+ * arguments |argl| and |argp| contain opaque values that were given to
+ * |CRYPTO_get_ex_new_index|. The callback should return one on success, but
+ * the value is ignored.
+ *
+ * TODO(fork): the |ptr| argument is always NULL, no? */
+typedef int CRYPTO_EX_new(void *parent, void *ptr, CRYPTO_EX_DATA *ad,
+ int index, long argl, void *argp);
+
+/* CRYPTO_EX_free is a callback function that is called when an object of the
+ * class is being destroyed. See |CRYPTO_EX_new| for a discussion of the
+ * arguments.
+ *
+ * If |CRYPTO_get_ex_new_index| was called after the creation of objects of the
+ * class that this applies to then, when those those objects are destroyed,
+ * this callback will be called with a NULL value for |ptr|. */
+typedef void CRYPTO_EX_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad,
+ int index, long argl, void *argp);
+
+/* CRYPTO_EX_dup is a callback function that is called when an object of the
+ * class is being copied and thus the ex_data linked to it also needs to be
+ * copied. On entry, |*from_d| points to the data for this index from the
+ * original object. When the callback returns, |*from_d| will be set as the
+ * data for this index in |to|.
+ *
+ * If |CRYPTO_get_ex_new_index| was called after the creation of objects of the
+ * class that this applies to then, when those those objects are copies, this
+ * callback will be called with a NULL value for |*from_d|. */
+typedef int CRYPTO_EX_dup(CRYPTO_EX_DATA *to, const CRYPTO_EX_DATA *from,
+ void **from_d, int index, long argl, void *argp);
+
+/* CRYPTO_get_ex_new_index allocates a new index for ex_data linked with
+ * objects of the given |class|. This should not be called directly, rather
+ * each class of object should provide a wrapper function that sets
+ * |class_value| correctly.
+ *
+ * The |class_value| argument should be one of |CRYPTO_EX_INDEX_*| or a
+ * user-defined class value returned from |CRYPTO_ex_data_new_class|.
+ *
+ * See the descriptions of the callback typedefs for details of when they are
+ * called. Any of the callback arguments may be NULL. The |argl| and |argp|
+ * arguments are opaque values that are passed to the callbacks.
+ *
+ * It returns the new index, or a negative number on error.
+ *
+ * TODO(fork): this should follow the standard calling convention.
+ *
+ * TODO(fork): replace the class_value with a pointer to EX_CLASS_ITEM. Saves
+ * having that hash table and some of the lock-bouncing. Maybe have every
+ * module have a private global EX_CLASS_ITEM somewhere and any direct callers
+ * of CRYPTO_{get,set}_ex_data{,_index} would have to always call the
+ * wrappers. */
+int CRYPTO_get_ex_new_index(int class_value, long argl, void *argp,
+ CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
+ CRYPTO_EX_free *free_func);
+
+/* CRYPTO_set_ex_data sets an extra data pointer on a given object. This should
+ * not be called directly, rather each class of object should provide a wrapper
+ * function.
+ *
+ * The |index| argument should have been returned from a previous call to
+ * |CRYPTO_get_ex_new_index|. */
+int CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int index, void *val);
+
+/* CRYPTO_set_ex_data return an extra data pointer for a given object, or NULL
+ * if no such index exists. This should not be called directly, rather each
+ * class of object should provide a wrapper function.
+ *
+ * The |index| argument should have been returned from a previous call to
+ * |CRYPTO_get_ex_new_index|. */
+void *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int index);
+
+/* CRYPTO_EX_INDEX_* are the built-in classes of objects.
+ *
+ * User defined classes start at 100.
+ *
+ * TODO(fork): WARNING: these are called "INDEX", but they aren't! */
+#define CRYPTO_EX_INDEX_BIO 0
+#define CRYPTO_EX_INDEX_SSL 1
+#define CRYPTO_EX_INDEX_SSL_CTX 2
+#define CRYPTO_EX_INDEX_SSL_SESSION 3
+#define CRYPTO_EX_INDEX_X509_STORE 4
+#define CRYPTO_EX_INDEX_X509_STORE_CTX 5
+#define CRYPTO_EX_INDEX_RSA 6
+#define CRYPTO_EX_INDEX_DSA 7
+#define CRYPTO_EX_INDEX_DH 8
+#define CRYPTO_EX_INDEX_ENGINE 9
+#define CRYPTO_EX_INDEX_X509 10
+#define CRYPTO_EX_INDEX_UI 11
+#define CRYPTO_EX_INDEX_EC_KEY 12
+#define CRYPTO_EX_INDEX_EC_GROUP 13
+#define CRYPTO_EX_INDEX_COMP 14
+#define CRYPTO_EX_INDEX_STORE 15
+
+
+/* User-defined classes of objects.
+ *
+ * Core OpenSSL code has predefined class values given above (the
+ * |CRYPTO_EX_INDEX_*| values). It's possible to get dynamic class values
+ * assigned for user-defined objects. */
+
+/* CRYPTO_ex_data_new_class returns a fresh class value for a user-defined type
+ * that wishes to use ex_data.
+ *
+ * TODO(fork): hopefully remove this. */
+int CRYPTO_ex_data_new_class(void);
+
+
+/* Embedding, allocating and freeing |CRYPTO_EX_DATA| structures for objects
+ * that embed them. */
+
+/* CRYPTO_new_ex_data initialises a newly allocated |CRYPTO_EX_DATA| which is
+ * embedded inside of |obj| which is of class |class_value|. Returns one on
+ * success and zero otherwise. */
+int CRYPTO_new_ex_data(int class_value, void *obj, CRYPTO_EX_DATA *ad);
+
+/* CRYPTO_dup_ex_data duplicates |from| into a freshly allocated
+ * |CRYPTO_EX_DATA|, |to|. Both of which are inside objects of the given
+ * class. It returns one on success and zero otherwise. */
+int CRYPTO_dup_ex_data(int class_value, CRYPTO_EX_DATA *to,
+ const CRYPTO_EX_DATA *from);
+
+/* CRYPTO_free_ex_data frees |ad|, which is embedded inside |obj|, which is an
+ * object of the given class. */
+void CRYPTO_free_ex_data(int class_value, void *obj, CRYPTO_EX_DATA *ad);
+
+
+/* Handling different ex_data implementations. */
+
+/* CRYPTO_EX_DATA_IMPL is the opaque type of an implementation of ex_data. */
+typedef struct st_CRYPTO_EX_DATA_IMPL CRYPTO_EX_DATA_IMPL;
+
+/* CRYPTO_get_ex_data_implementation returns the current implementation of
+ * ex_data. */
+const CRYPTO_EX_DATA_IMPL *CRYPTO_get_ex_data_implementation(void);
+
+/* CRYPTO_set_ex_data_implementation sets the implementation of ex_data to use,
+ * unless ex_data has already been used and the default implementation
+ * installed. It returns one on success and zero otherwise. */
+int CRYPTO_set_ex_data_implementation(const CRYPTO_EX_DATA_IMPL *impl);
+
+
+/* Private functions. */
+
+/* CRYPTO_cleanup_all_ex_data cleans up all ex_data state. It assumes that no
+ * other threads are executing code that might call ex_data functions. */
+void CRYPTO_cleanup_all_ex_data(void);
+
+struct crypto_ex_data_st {
+ STACK_OF(void) *sk;
+};
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_EX_DATA_H */
diff --git a/crypto/ex_data_impl.c b/crypto/ex_data_impl.c
new file mode 100644
index 0000000..23d1fac
--- /dev/null
+++ b/crypto/ex_data_impl.c
@@ -0,0 +1,400 @@
+/* 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.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2001 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). */
+
+#include <openssl/ex_data.h>
+
+#include <assert.h>
+
+#include <openssl/err.h>
+#include <openssl/lhash.h>
+#include <openssl/mem.h>
+#include <openssl/stack.h>
+#include <openssl/thread.h>
+
+#include "crypto_error.h"
+#include "internal.h"
+
+typedef struct crypto_ex_data_func_st {
+ long argl; /* Arbitary long */
+ void *argp; /* Arbitary void pointer */
+ CRYPTO_EX_new *new_func;
+ CRYPTO_EX_free *free_func;
+ CRYPTO_EX_dup *dup_func;
+} CRYPTO_EX_DATA_FUNCS;
+
+typedef struct st_ex_class_item {
+ STACK_OF(CRYPTO_EX_DATA_FUNCS) *meth;
+ int class_value;
+ /* TODO(fork): isn't |meth_num| just the length of |meth|? */
+ int meth_num;
+} EX_CLASS_ITEM;
+
+static LHASH_OF(EX_CLASS_ITEM) *global_classes = NULL;
+
+static int global_next_class = 100;
+
+static int new_class(void) {
+ int ret;
+ CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
+ ret = global_next_class++;
+ CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
+
+ return ret;
+}
+
+/* class_hash is a hash function used by an LHASH of |EX_CLASS_ITEM|
+ * structures. */
+static uint32_t class_hash(const EX_CLASS_ITEM *a) {
+ return a->class_value;
+}
+
+/* class_cmp is a comparision function for an LHASH of |EX_CLASS_ITEM|
+ * structures. */
+static int class_cmp(const EX_CLASS_ITEM *a, const EX_CLASS_ITEM *b) {
+ return a->class_value - b->class_value;
+}
+
+/* data_funcs_free is a callback function from |sk_pop_free| that frees a
+ * |CRYPTO_EX_DATA_FUNCS|. */
+static void data_funcs_free(CRYPTO_EX_DATA_FUNCS *funcs) {
+ OPENSSL_free(funcs);
+}
+
+/* class_free is a callback function from lh_doall to free the EX_CLASS_ITEM
+ * structures. */
+static void class_free(EX_CLASS_ITEM *item) {
+ sk_CRYPTO_EX_DATA_FUNCS_pop_free(item->meth, data_funcs_free);
+}
+
+static LHASH_OF(EX_CLASS_ITEM) *get_classes() {
+ LHASH_OF(EX_CLASS_ITEM) *ret;
+
+ CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA);
+ ret = global_classes;
+ CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA);
+
+ if (ret != NULL) {
+ return ret;
+ }
+
+ CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
+ if (global_classes == NULL) {
+ global_classes = lh_EX_CLASS_ITEM_new(class_hash, class_cmp);
+ }
+ ret = global_classes;
+ CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
+
+ return ret;
+}
+
+static void cleanup(void) {
+ LHASH_OF(EX_CLASS_ITEM) *classes = get_classes();
+
+ lh_EX_CLASS_ITEM_doall(classes, class_free);
+ lh_EX_CLASS_ITEM_free(classes);
+
+ global_classes = NULL;
+}
+
+static EX_CLASS_ITEM *get_class(int class_value) {
+ LHASH_OF(EX_CLASS_ITEM) *const classes = get_classes();
+ EX_CLASS_ITEM template, *class_item;
+ int ok = 0;
+
+ CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
+ template.class_value = class_value;
+ class_item = lh_EX_CLASS_ITEM_retrieve(classes, &template);
+ if (class_item != NULL) {
+ ok = 1;
+ } else {
+ class_item = OPENSSL_malloc(sizeof(EX_CLASS_ITEM));
+ if (class_item) {
+ class_item->class_value = class_value;
+ class_item->meth_num = 0;
+ class_item->meth = sk_CRYPTO_EX_DATA_FUNCS_new_null();
+ if (class_item->meth != NULL) {
+ EX_CLASS_ITEM *old_data;
+ ok = lh_EX_CLASS_ITEM_insert(classes, &old_data, class_item);
+ assert(old_data == NULL);
+ }
+ }
+ }
+ CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
+
+ if (!ok) {
+ if (class_item) {
+ if (class_item->meth) {
+ sk_CRYPTO_EX_DATA_FUNCS_free(class_item->meth);
+ }
+ OPENSSL_free(class_item);
+ class_item = NULL;
+ }
+
+ OPENSSL_PUT_ERROR(CRYPTO, get_class, ERR_R_MALLOC_FAILURE);
+ }
+
+ return class_item;
+}
+
+static int get_new_index(int class_value, long argl, void *argp,
+ CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
+ CRYPTO_EX_free *free_func) {
+ EX_CLASS_ITEM *const item = get_class(class_value);
+ CRYPTO_EX_DATA_FUNCS *funcs;
+ int ret = -1;
+
+ if (!item) {
+ return -1;
+ }
+
+ funcs = OPENSSL_malloc(sizeof(CRYPTO_EX_DATA_FUNCS));
+ if (funcs == NULL) {
+ OPENSSL_PUT_ERROR(CRYPTO, get_new_index, ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+
+ funcs->argl = argl;
+ funcs->argp = argp;
+ funcs->new_func = new_func;
+ funcs->dup_func = dup_func;
+ funcs->free_func = free_func;
+
+ CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
+ /* TODO(fork): this loop appears to only ever run once. */
+ while (sk_CRYPTO_EX_DATA_FUNCS_num(item->meth) <= item->meth_num) {
+ if (!sk_CRYPTO_EX_DATA_FUNCS_push(item->meth, NULL)) {
+ OPENSSL_PUT_ERROR(CRYPTO, get_new_index, ERR_R_MALLOC_FAILURE);
+ OPENSSL_free(funcs);
+ goto err;
+ }
+ }
+
+ ret = item->meth_num++;
+ (void)sk_CRYPTO_EX_DATA_FUNCS_set(item->meth, ret, funcs);
+
+err:
+ CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
+ return ret;
+}
+
+/* get_func_pointers takes a copy of the CRYPTO_EX_DATA_FUNCS pointers, if any,
+ * for the given class. If there are some pointers, it sets |*out| to point to
+ * a fresh stack of them. Otherwise it sets |*out| to NULL. It returns one on
+ * success or zero on error. */
+static int get_func_pointers(STACK_OF(CRYPTO_EX_DATA_FUNCS) **out,
+ int class_value) {
+ EX_CLASS_ITEM *const item = get_class(class_value);
+ size_t n;
+
+ if (!item) {
+ return 0;
+ }
+
+ *out = NULL;
+
+ /* CRYPTO_EX_DATA_FUNCS structures are static once set, so we can take a
+ * shallow copy of the list under lock and then use the structures without
+ * the lock held. */
+ CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA);
+ n = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth);
+ if (n > 0) {
+ *out = sk_CRYPTO_EX_DATA_FUNCS_dup(item->meth);
+ }
+ CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA);
+
+ if (n > 0 && *out == NULL) {
+ OPENSSL_PUT_ERROR(CRYPTO, get_func_pointers, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int new_ex_data(int class_value, void *obj, CRYPTO_EX_DATA *ad) {
+ STACK_OF(CRYPTO_EX_DATA_FUNCS) *func_pointers;
+ size_t i;
+
+ ad->sk = NULL;
+
+ if (!get_func_pointers(&func_pointers, class_value)) {
+ return 0;
+ }
+
+ 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);
+ if (func_pointer->new_func) {
+ func_pointer->new_func(obj, NULL, ad, i, func_pointer->argl,
+ func_pointer->argp);
+ }
+ }
+
+ sk_CRYPTO_EX_DATA_FUNCS_free(func_pointers);
+
+ return 1;
+}
+
+static int dup_ex_data(int class_value, CRYPTO_EX_DATA *to,
+ const CRYPTO_EX_DATA *from) {
+ STACK_OF(CRYPTO_EX_DATA_FUNCS) *func_pointers;
+ size_t i;
+
+ if (!from->sk) {
+ /* In this case, |from| is blank, which is also the initial state of |to|,
+ * so there's nothing to do. */
+ return 1;
+ }
+
+ if (!get_func_pointers(&func_pointers, class_value)) {
+ return 0;
+ }
+
+ 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);
+ if (func_pointer->dup_func) {
+ func_pointer->dup_func(to, from, &ptr, i, func_pointer->argl,
+ func_pointer->argp);
+ }
+ CRYPTO_set_ex_data(to, i, ptr);
+ }
+
+ sk_CRYPTO_EX_DATA_FUNCS_free(func_pointers);
+
+ return 1;
+}
+
+static void free_ex_data(int class_value, void *obj, CRYPTO_EX_DATA *ad) {
+ STACK_OF(CRYPTO_EX_DATA_FUNCS) *func_pointers;
+ size_t i;
+
+ if (!get_func_pointers(&func_pointers, class_value)) {
+ return;
+ }
+
+ 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);
+ 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);
+ }
+ }
+
+ sk_CRYPTO_EX_DATA_FUNCS_free(func_pointers);
+
+ if (ad->sk) {
+ sk_void_free(ad->sk);
+ ad->sk = NULL;
+ }
+}
+
+const CRYPTO_EX_DATA_IMPL ex_data_default_impl = {
+ new_class, cleanup, get_new_index, new_ex_data, dup_ex_data, free_ex_data};
diff --git a/crypto/header_removed.h b/crypto/header_removed.h
new file mode 100644
index 0000000..1097d8e
--- /dev/null
+++ b/crypto/header_removed.h
@@ -0,0 +1,3 @@
+/* This header is linked to under the names of several headers that have been
+ * removed. It's possible to put a #error in here in order to catch that an
+ * clean up older code. */
diff --git a/crypto/hmac/CMakeLists.txt b/crypto/hmac/CMakeLists.txt
new file mode 100644
index 0000000..d647b0a
--- /dev/null
+++ b/crypto/hmac/CMakeLists.txt
@@ -0,0 +1,18 @@
+include_directories(. .. ../../include)
+
+add_library(
+ hmac
+
+ OBJECT
+
+ hmac.c
+)
+
+
+add_executable(
+ hmac_test
+
+ hmac_test.c
+)
+
+target_link_libraries(hmac_test crypto)
diff --git a/crypto/hmac/hmac.c b/crypto/hmac/hmac.c
new file mode 100644
index 0000000..1d37b9e
--- /dev/null
+++ b/crypto/hmac/hmac.c
@@ -0,0 +1,208 @@
+/* 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/hmac.h>
+
+#include <assert.h>
+
+#include <openssl/mem.h>
+
+
+uint8_t *HMAC(const EVP_MD *evp_md, const void *key, size_t key_len,
+ const uint8_t *data, size_t data_len, uint8_t *out,
+ unsigned int *out_len) {
+ HMAC_CTX ctx;
+ static uint8_t static_out_buffer[EVP_MAX_MD_SIZE];
+
+ /* OpenSSL has traditionally supported using a static buffer if |out| is
+ * NULL. We maintain that but don't document it. This behaviour should be
+ * considered to be deprecated. */
+ if (out == NULL) {
+ out = static_out_buffer;
+ }
+
+ HMAC_CTX_init(&ctx);
+ if (!HMAC_Init(&ctx, key, key_len, evp_md) ||
+ !HMAC_Update(&ctx, data, data_len) ||
+ !HMAC_Final(&ctx, out, out_len)) {
+ out = NULL;
+ }
+
+ HMAC_CTX_cleanup(&ctx);
+ return out;
+}
+
+void HMAC_CTX_init(HMAC_CTX *ctx) {
+ EVP_MD_CTX_init(&ctx->i_ctx);
+ EVP_MD_CTX_init(&ctx->o_ctx);
+ EVP_MD_CTX_init(&ctx->md_ctx);
+}
+
+void HMAC_CTX_cleanup(HMAC_CTX *ctx) {
+ 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));
+}
+
+int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t key_len,
+ const EVP_MD *md, ENGINE *impl) {
+ unsigned i, reset = 0;
+ uint8_t pad[HMAC_MAX_MD_CBLOCK];
+
+ if (md != NULL) {
+ reset = 1;
+ ctx->md = md;
+ } else {
+ md = ctx->md;
+ }
+
+ if (key != NULL) {
+ size_t block_size = EVP_MD_block_size(md);
+ reset = 1;
+ assert(block_size <= sizeof(ctx->key));
+ if (block_size < key_len) {
+ if (!EVP_DigestInit_ex(&ctx->md_ctx, md, impl) ||
+ !EVP_DigestUpdate(&ctx->md_ctx, key, key_len) ||
+ !EVP_DigestFinal_ex(&(ctx->md_ctx), ctx->key, &ctx->key_length)) {
+ goto err;
+ }
+ } else {
+ assert(key_len >= 0 && key_len <= sizeof(ctx->key));
+ memcpy(ctx->key, key, key_len);
+ ctx->key_length = key_len;
+ }
+ if (ctx->key_length != HMAC_MAX_MD_CBLOCK) {
+ memset(&ctx->key[ctx->key_length], 0, sizeof(ctx->key) - ctx->key_length);
+ }
+ }
+
+ if (reset) {
+ for (i = 0; i < HMAC_MAX_MD_CBLOCK; i++) {
+ pad[i] = 0x36 ^ ctx->key[i];
+ }
+ if (!EVP_DigestInit_ex(&ctx->i_ctx, md, impl) ||
+ !EVP_DigestUpdate(&ctx->i_ctx, pad, EVP_MD_block_size(md))) {
+ goto err;
+ }
+
+ for (i = 0; i < HMAC_MAX_MD_CBLOCK; i++) {
+ pad[i] = 0x5c ^ ctx->key[i];
+ }
+ if (!EVP_DigestInit_ex(&ctx->o_ctx, md, impl) ||
+ !EVP_DigestUpdate(&ctx->o_ctx, pad, EVP_MD_block_size(md))) {
+ goto err;
+ }
+ }
+
+ if (!EVP_MD_CTX_copy_ex(&ctx->md_ctx, &ctx->i_ctx)) {
+ goto err;
+ }
+
+ return 1;
+
+err:
+ return 0;
+}
+
+int HMAC_Update(HMAC_CTX *ctx, const uint8_t *data, size_t data_len) {
+ return EVP_DigestUpdate(&ctx->md_ctx, data, data_len);
+}
+
+int HMAC_Final(HMAC_CTX *ctx, uint8_t *out, unsigned int *out_len) {
+ unsigned int i;
+ uint8_t buf[EVP_MAX_MD_SIZE];
+
+ if (!EVP_DigestFinal_ex(&ctx->md_ctx, buf, &i) ||
+ !EVP_MD_CTX_copy_ex(&ctx->md_ctx, &ctx->o_ctx) ||
+ !EVP_DigestUpdate(&ctx->md_ctx, buf, i) ||
+ !EVP_DigestFinal_ex(&ctx->md_ctx, out, out_len)) {
+ *out_len = 0;
+ return 0;
+ }
+
+ return 1;
+}
+
+size_t HMAC_size(const HMAC_CTX *ctx) {
+ return EVP_MD_size(ctx->md);
+}
+
+int HMAC_CTX_copy(HMAC_CTX *dest, const HMAC_CTX *src) {
+ if (!EVP_MD_CTX_copy(&dest->i_ctx, &src->i_ctx) ||
+ !EVP_MD_CTX_copy(&dest->o_ctx, &src->o_ctx) ||
+ !EVP_MD_CTX_copy(&dest->md_ctx, &src->md_ctx)) {
+ return 0;
+ }
+
+ memcpy(dest->key, src->key, HMAC_MAX_MD_CBLOCK);
+ dest->key_length = src->key_length;
+ dest->md = src->md;
+ return 1;
+}
+
+void HMAC_CTX_set_flags(HMAC_CTX *ctx, unsigned long flags) {
+ EVP_MD_CTX_set_flags(&ctx->i_ctx, flags);
+ EVP_MD_CTX_set_flags(&ctx->o_ctx, flags);
+ EVP_MD_CTX_set_flags(&ctx->md_ctx, flags);
+}
+
+int HMAC_Init(HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md) {
+ if (key && md) {
+ HMAC_CTX_init(ctx);
+ }
+ return HMAC_Init_ex(ctx, key, key_len, md, NULL);
+}
diff --git a/crypto/hmac/hmac.h b/crypto/hmac/hmac.h
new file mode 100644
index 0000000..33c9061
--- /dev/null
+++ b/crypto/hmac/hmac.h
@@ -0,0 +1,155 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_HMAC_H
+#define OPENSSL_HEADER_HMAC_H
+
+#include <openssl/base.h>
+
+#include <openssl/digest.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* HMAC contains functions for constructing PRFs from Merkle–Damgård hash
+ * functions using HMAC. */
+
+
+/* One-shot operation. */
+
+/* HMAC calculates the HMAC of |data_len| bytes of |data|, using the given key
+ * and hash function, and writes the result to |out|. On entry, |out| must
+ * contain |EVP_MAX_MD_SIZE| bytes of space. The actual length of the result is
+ * written to |*out_len|. It returns |out| or NULL on error. */
+uint8_t *HMAC(const EVP_MD *evp_md, const void *key, size_t key_len,
+ const uint8_t *data, size_t data_len, uint8_t *out,
+ unsigned int *out_len);
+
+
+/* Incremental operation. */
+
+/* HMAC_CTX_init initialises |ctx| for use in an HMAC operation. It's assumed
+ * that HMAC_CTX objects will be allocated on the stack thus no allocation
+ * function is provided. If needed, allocate |sizeof(HMAC_CTX)| and call
+ * |HMAC_CTX_init| on it. */
+void HMAC_CTX_init(HMAC_CTX *ctx);
+
+/* HMAC_CTX_cleanup frees data owned by |ctx|. */
+void HMAC_CTX_cleanup(HMAC_CTX *ctx);
+
+/* HMAC_Init_ex sets up an initialised |HMAC_CTX| to use |md| as the hash
+ * function and |key| as the key. Any of |md| or |key| can be NULL, in which
+ * case the previous value will be used. It returns one on success or zero
+ * otherwise. */
+int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t key_len,
+ const EVP_MD *md, ENGINE *impl);
+
+/* HMAC_Update hashes |data_len| bytes from |data| into the current HMAC
+ * operation in |ctx|. It returns one on success and zero on error. */
+int HMAC_Update(HMAC_CTX *ctx, const uint8_t *data, size_t data_len);
+
+/* HMAC_Final completes the HMAC operation in |ctx| and writes the result to
+ * |out| and the sets |*out_len| to the length of the result. On entry, |out|
+ * must contain at least |EVP_MAX_MD_SIZE| bytes of space. It returns one on
+ * success or zero on error. */
+int HMAC_Final(HMAC_CTX *ctx, uint8_t *out, unsigned int *out_len);
+
+
+/* Utility functions. */
+
+/* HMAC_size returns the size, in bytes, of the HMAC that will be produced by
+ * |ctx|. On entry, |ctx| must have been setup with |HMAC_Init_ex|. */
+size_t HMAC_size(const HMAC_CTX *ctx);
+
+/* HMAC_CTX_copy sets |dest| equal to |src|. On entry, |dest| must have been
+ * initialised by calling |HMAC_CTX_init|. It returns one on success and zero
+ * on error. */
+int HMAC_CTX_copy(HMAC_CTX *dest, const HMAC_CTX *src);
+
+/* HMAC_CTX_set_flags ORs |flags| into the flags of the underlying digests of
+ * |ctx|, which must have been setup by a call to |HMAC_Init_ex|. See
+ * |EVP_MD_CTX_set_flags|.
+ *
+ * TODO(fork): remove? */
+void HMAC_CTX_set_flags(HMAC_CTX *ctx, unsigned long flags);
+
+
+/* Deprecated functions. */
+
+int HMAC_Init(HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md);
+
+
+/* Private functions */
+
+#define HMAC_MAX_MD_CBLOCK 128 /* largest known is SHA512 */
+
+struct hmac_ctx_st {
+ const EVP_MD *md;
+ EVP_MD_CTX md_ctx;
+ EVP_MD_CTX i_ctx;
+ EVP_MD_CTX o_ctx;
+ unsigned int key_length;
+ unsigned char key[HMAC_MAX_MD_CBLOCK];
+} /* HMAC_CTX */;
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_HMAC_H */
diff --git a/crypto/hmac/hmac_test.c b/crypto/hmac/hmac_test.c
new file mode 100644
index 0000000..e2ae4a6
--- /dev/null
+++ b/crypto/hmac/hmac_test.c
@@ -0,0 +1,151 @@
+/* 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/digest.h>
+#include <openssl/hmac.h>
+
+
+struct test_st {
+ unsigned char key[16];
+ unsigned key_len;
+ unsigned char data[64];
+ unsigned data_len;
+ const char *hex_digest;
+};
+
+#define NUM_TESTS 4
+
+static const struct test_st kTests[NUM_TESTS] = {
+ {
+ "", 0, "More text test vectors to stuff up EBCDIC machines :-)", 54,
+ "e9139d1e6ee064ef8cf514fc7dc83e86",
+ },
+ {
+ {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b,
+ },
+ 16,
+ "Hi There",
+ 8,
+ "9294727a3638bb1c13f48ef8158bfc9d",
+ },
+ {
+ "Jefe", 4, "what do ya want for nothing?", 28,
+ "750c783e6ab0b503eaa86e310a5db738",
+ },
+ {
+ {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa,
+ },
+ 16,
+ {
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd,
+ },
+ 50,
+ "56be34521d144c88dbb8c733f0e8b3f6",
+ },
+};
+
+static char *to_hex(const uint8_t *md, size_t md_len) {
+ size_t i;
+ static char buf[80];
+
+ for (i = 0; i < md_len; i++) {
+ sprintf(&(buf[i * 2]), "%02x", md[i]);
+ }
+ return buf;
+}
+
+int main(int argc, char *argv[]) {
+ unsigned i;
+ char *p;
+ int err = 0;
+ uint8_t out[EVP_MAX_MD_SIZE];
+ unsigned out_len;
+
+ for (i = 0; i < NUM_TESTS; i++) {
+ const struct test_st *test = &kTests[i];
+
+ if (NULL == HMAC(EVP_md5(), test->key, test->key_len, test->data,
+ test->data_len, out, &out_len)) {
+ printf("%u: HMAC failed.\n", i);
+ err++;
+ continue;
+ }
+
+ p = to_hex(out, out_len);
+
+ if (strcmp(p, test->hex_digest) != 0) {
+ printf("%u: got %s instead of %s\n", i, p, test->hex_digest);
+ err++;
+ }
+ }
+
+ if (err) {
+ return 1;
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/crypto/internal.h b/crypto/internal.h
new file mode 100644
index 0000000..8464239
--- /dev/null
+++ b/crypto/internal.h
@@ -0,0 +1,135 @@
+/* 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.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2001 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_CRYPTO_INTERNAL_H
+#define OPENSSL_HEADER_CRYPTO_INTERNAL_H
+
+#include <openssl/base.h>
+
+
+/* st_CRYPTO_EX_DATA_IMPL contains an ex_data implementation. See the comments
+ * in ex_data.h for details of the behaviour of each of the functions. */
+struct st_CRYPTO_EX_DATA_IMPL {
+ int (*new_class)(void);
+ void (*cleanup)(void);
+
+ int (*get_new_index)(int class_value, long argl, void *argp,
+ CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
+ CRYPTO_EX_free *free_func);
+ int (*new_ex_data)(int class_value, void *obj, CRYPTO_EX_DATA *ad);
+ int (*dup_ex_data)(int class_value, CRYPTO_EX_DATA *to,
+ const CRYPTO_EX_DATA *from);
+ void (*free_ex_data)(int class_value, void *obj, CRYPTO_EX_DATA *ad);
+};
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_CRYPTO_INTERNAL_H */
diff --git a/crypto/lhash/CMakeLists.txt b/crypto/lhash/CMakeLists.txt
new file mode 100644
index 0000000..c3bf08e
--- /dev/null
+++ b/crypto/lhash/CMakeLists.txt
@@ -0,0 +1,17 @@
+include_directories(. .. ../../include)
+
+add_library(
+ lhash
+
+ OBJECT
+
+ lhash.c
+)
+
+add_executable(
+ lhash_test
+
+ lhash_test.c
+)
+
+target_link_libraries(lhash_test crypto)
diff --git a/crypto/lhash/lhash.c b/crypto/lhash/lhash.c
new file mode 100644
index 0000000..b601480
--- /dev/null
+++ b/crypto/lhash/lhash.c
@@ -0,0 +1,344 @@
+/* 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 "lhash.h"
+
+#include <assert.h>
+#include <limits.h>
+
+#include <openssl/mem.h>
+
+/* kMinNumBuckets is the minimum size of the buckets array in an |_LHASH|. */
+static const size_t kMinNumBuckets = 16;
+
+/* kMaxAverageChainLength contains the maximum, average chain length. When the
+ * average chain length exceeds this value, the hash table will be resized. */
+static const size_t kMaxAverageChainLength = 2;
+static const size_t kMinAverageChainLength = 1;
+
+_LHASH *lh_new(lhash_hash_func hash, lhash_cmp_func comp) {
+ _LHASH *ret;
+
+ ret = OPENSSL_malloc(sizeof(_LHASH));
+ if (ret == NULL) {
+ return NULL;
+ }
+ memset(ret, 0, sizeof(_LHASH));
+
+ ret->num_buckets = kMinNumBuckets;
+ ret->buckets = OPENSSL_malloc(sizeof(LHASH_ITEM *) * ret->num_buckets);
+ if (ret->buckets == NULL) {
+ OPENSSL_free(ret);
+ return NULL;
+ }
+ memset(ret->buckets, 0, sizeof(LHASH_ITEM *) * ret->num_buckets);
+
+ ret->comp = comp;
+ if (ret->comp == NULL) {
+ ret->comp = (lhash_cmp_func) strcmp;
+ }
+ ret->hash = hash;
+ if (ret->hash == NULL) {
+ ret->hash = (lhash_hash_func) lh_strhash;
+ }
+
+ return ret;
+}
+
+void lh_free(_LHASH *lh) {
+ size_t i;
+ LHASH_ITEM *n, *next;
+
+ if (lh == NULL) {
+ return;
+ }
+
+ for (i = 0; i < lh->num_buckets; i++) {
+ for (n = lh->buckets[i]; n != NULL; n = next) {
+ next = n->next;
+ OPENSSL_free(n);
+ }
+ }
+
+ OPENSSL_free(lh->buckets);
+ OPENSSL_free(lh);
+}
+
+size_t lh_num_items(const _LHASH *lh) { return lh->num_items; }
+
+/* get_next_ptr_and_hash returns a pointer to the pointer that points to the
+ * item equal to |data|. In other words, it searches for an item equal to |data|
+ * and, if it's at the start of a chain, then it returns a pointer to an
+ * element of |lh->buckets|, otherwise it returns a pointer to the |next|
+ * element of the previous item in the chain. If an element equal to |data| is
+ * not found, it returns a pointer that points to a NULL pointer. If |out_hash|
+ * is not NULL, then it also puts the hash value of |data| in |*out_hash|. */
+static LHASH_ITEM **get_next_ptr_and_hash(const _LHASH *lh, uint32_t *out_hash,
+ const void *data) {
+ const uint32_t hash = lh->hash(data);
+ LHASH_ITEM *cur, **ret;
+
+ if (out_hash != NULL) {
+ *out_hash = hash;
+ }
+
+ ret = &lh->buckets[hash % lh->num_buckets];
+ for (cur = *ret; cur != NULL; cur = *ret) {
+ if (lh->comp(cur->data, data) == 0) {
+ break;
+ }
+ ret = &cur->next;
+ }
+
+ return ret;
+}
+
+void *lh_retrieve(const _LHASH *lh, const void *data) {
+ LHASH_ITEM **next_ptr;
+
+ next_ptr = get_next_ptr_and_hash(lh, NULL, data);
+
+ if (*next_ptr == NULL) {
+ return NULL;
+ }
+
+ return (*next_ptr)->data;
+}
+
+/* lh_rebucket allocates a new array of |new_num_buckets| pointers and
+ * redistributes the existing items into it before making it |lh->buckets| and
+ * freeing the old array. */
+static void lh_rebucket(_LHASH *lh, const size_t new_num_buckets) {
+ LHASH_ITEM **new_buckets, *cur, *next;
+ size_t i, alloc_size;
+
+ alloc_size = sizeof(LHASH_ITEM *) * new_num_buckets;
+ if (alloc_size / sizeof(LHASH_ITEM*) != new_num_buckets) {
+ return;
+ }
+
+ new_buckets = OPENSSL_malloc(alloc_size);
+ if (new_buckets == NULL) {
+ return;
+ }
+ memset(new_buckets, 0, alloc_size);
+
+ for (i = 0; i < lh->num_buckets; i++) {
+ for (cur = lh->buckets[i]; cur != NULL; cur = next) {
+ const size_t new_bucket = cur->hash % new_num_buckets;
+ next = cur->next;
+ cur->next = new_buckets[new_bucket];
+ new_buckets[new_bucket] = cur;
+ }
+ }
+
+ OPENSSL_free(lh->buckets);
+
+ lh->num_buckets = new_num_buckets;
+ lh->buckets = new_buckets;
+}
+
+/* lh_maybe_resize resizes the |buckets| array if needed. */
+static void lh_maybe_resize(_LHASH *lh) {
+ size_t avg_chain_length;
+
+ if (lh->callback_depth > 0) {
+ /* Don't resize the hash if we are currently iterating over it. */
+ return;
+ }
+
+ assert(lh->num_buckets >= kMinNumBuckets);
+ avg_chain_length = lh->num_items / lh->num_buckets;
+
+ if (avg_chain_length > kMaxAverageChainLength) {
+ const size_t new_num_buckets = lh->num_buckets * 2;
+
+ if (new_num_buckets > lh->num_buckets) {
+ lh_rebucket(lh, new_num_buckets);
+ }
+ } else if (avg_chain_length < kMinAverageChainLength &&
+ lh->num_buckets > kMinNumBuckets) {
+ size_t new_num_buckets = lh->num_buckets / 2;
+
+ if (new_num_buckets < kMinNumBuckets) {
+ new_num_buckets = kMinNumBuckets;
+ }
+
+ lh_rebucket(lh, new_num_buckets);
+ }
+}
+
+int lh_insert(_LHASH *lh, void **old_data, void *data) {
+ uint32_t hash;
+ LHASH_ITEM **next_ptr, *item;
+
+ *old_data = NULL;
+ next_ptr = get_next_ptr_and_hash(lh, &hash, data);
+
+
+ if (*next_ptr != NULL) {
+ /* An element equal to |data| already exists in the hash table. It will be
+ * replaced. */
+ *old_data = (*next_ptr)->data;
+ (*next_ptr)->data = data;
+ return 1;
+ }
+
+ /* An element equal to |data| doesn't exist in the hash table yet. */
+ item = OPENSSL_malloc(sizeof(LHASH_ITEM));
+ if (item == NULL) {
+ return 0;
+ }
+
+ item->data = data;
+ item->hash = hash;
+ item->next = NULL;
+ *next_ptr = item;
+ lh->num_items++;
+ lh_maybe_resize(lh);
+
+ return 1;
+}
+
+void *lh_delete(_LHASH *lh, const void *data) {
+ LHASH_ITEM **next_ptr, *item, *ret;
+
+ next_ptr = get_next_ptr_and_hash(lh, NULL, data);
+
+ if (*next_ptr == NULL) {
+ /* No such element. */
+ return NULL;
+ }
+
+ item = *next_ptr;
+ *next_ptr = item->next;
+ ret = item->data;
+ OPENSSL_free(item);
+
+ lh->num_items--;
+ lh_maybe_resize(lh);
+
+ return ret;
+}
+
+static void lh_doall_internal(_LHASH *lh, void (*no_arg_func)(void *),
+ void (*arg_func)(void *, void *), void *arg) {
+ size_t i;
+ LHASH_ITEM *cur, *next;
+
+ if (lh == NULL) {
+ return;
+ }
+
+ if (lh->callback_depth < UINT_MAX) {
+ /* |callback_depth| is a saturating counter. */
+ lh->callback_depth++;
+ }
+
+ for (i = 0; i < lh->num_buckets; i++) {
+ for (cur = lh->buckets[i]; cur != NULL; cur = next) {
+ next = cur->next;
+ if (arg_func) {
+ arg_func(cur->data, arg);
+ } else {
+ no_arg_func(cur->data);
+ }
+ }
+ }
+
+ if (lh->callback_depth < UINT_MAX) {
+ lh->callback_depth--;
+ }
+
+ /* The callback may have added or removed elements and the non-zero value of
+ * |callback_depth| will have suppressed any resizing. Thus any needed
+ * resizing is done here. */
+ lh_maybe_resize(lh);
+}
+
+void lh_doall(_LHASH *lh, void (*func)(void *)) {
+ lh_doall_internal(lh, func, NULL, NULL);
+}
+
+void lh_doall_arg(_LHASH *lh, void (*func)(void *, void *), void *arg) {
+ lh_doall_internal(lh, NULL, func, arg);
+}
+
+uint32_t lh_strhash(const char *c) {
+ /* The following hash seems to work very well on normal text strings
+ * no collisions on /usr/dict/words and it distributes on %2^n quite
+ * well, not as good as MD5, but still good. */
+ unsigned long ret = 0;
+ long n;
+ unsigned long v;
+ int r;
+
+ if ((c == NULL) || (*c == '\0')) {
+ return (ret);
+ }
+
+ n = 0x100;
+ while (*c) {
+ v = n | (*c);
+ n += 0x100;
+ r = (int)((v >> 2) ^ v) & 0x0f;
+ ret = (ret << r) | (ret >> (32 - r));
+ ret &= 0xFFFFFFFFL;
+ ret ^= v * v;
+ c++;
+ }
+
+ return ((ret >> 16) ^ ret);
+}
diff --git a/crypto/lhash/lhash.h b/crypto/lhash/lhash.h
new file mode 100644
index 0000000..82842d7
--- /dev/null
+++ b/crypto/lhash/lhash.h
@@ -0,0 +1,193 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_LHASH_H
+#define OPENSSL_HEADER_LHASH_H
+
+#include <openssl/base.h>
+#include <openssl/type_check.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* lhash is a traditional, chaining hash table that automatically expands and
+ * contracts as needed. One should not use the lh_* functions directly, rather
+ * use the type-safe macro wrappers:
+ *
+ * A hash table of a specific type of object has type |LHASH_OF(type)|. This
+ * can be defined (once) with |DEFINE_LHASH_OF(type)| and declared where needed
+ * with |DECLARE_LHASH_OF(type)|. For example:
+ *
+ * struct foo {
+ * int bar;
+ * };
+ *
+ * DEFINE_LHASH_OF(struct foo);
+ *
+ * Although note that the hash table will contain /pointers/ to |foo|.
+ *
+ * A macro will be defined for each of the lh_* functions below. For
+ * LHASH_OF(foo), the macros would be lh_foo_new, lh_foo_num_items etc. */
+
+
+#define LHASH_OF(type) struct lhash_st_##type
+
+#define DEFINE_LHASH_OF(type) LHASH_OF(type) { int dummy; }
+
+#define DECLARE_LHASH_OF(type) LHASH_OF(type);
+
+/* The make_macros.sh script in this directory parses the following lines and
+ * generates the lhash_macros.h file that contains macros for the following
+ * types of stacks:
+ *
+ * LHASH_OF:ASN1_OBJECT
+ * LHASH_OF:CONF_VALUE
+ * LHASH_OF:ERR_STATE
+ * LHASH_OF:ERR_STRING_DATA
+ * LHASH_OF:EX_CLASS_ITEM
+ * LHASH_OF:SSL_SESSION */
+
+#define IN_LHASH_H
+#include <openssl/lhash_macros.h>
+#undef IN_LHASH_H
+
+
+/* lhash_item_st is an element of a hash chain. It points to the opaque data
+ * for this element and to the next item in the chain. The linked-list is NULL
+ * terminated. */
+typedef struct lhash_item_st {
+ void *data;
+ struct lhash_item_st *next;
+ /* hash contains the cached, hash value of |data|. */
+ uint32_t hash;
+} LHASH_ITEM;
+
+/* lhash_cmp_func is a comparision function that returns a value equal, or not
+ * equal, to zero depending on whether |*a| is equal, or not equal to |*b|,
+ * respectively. Note the difference between this and |stack_cmp_func| in that
+ * this takes pointers to the objects directly. */
+typedef int (*lhash_cmp_func)(const void *a, const void *b);
+
+/* lhash_hash_func is a function that maps an object to a uniformly distributed
+ * uint32_t. */
+typedef uint32_t (*lhash_hash_func)(const void *a);
+
+typedef struct lhash_st {
+ /* num_items contains the total number of items in the hash table. */
+ size_t num_items;
+ /* buckets is an array of |num_buckets| pointers. Each points to the head of
+ * a chain of LHASH_ITEM objects that have the same hash value, mod
+ * |num_buckets|. */
+ LHASH_ITEM **buckets;
+ /* num_buckets contains the length of |buckets|. This value is always >=
+ * kMinNumBuckets. */
+ size_t num_buckets;
+ /* callback_depth contains the current depth of |lh_doall| or |lh_doall_arg|
+ * calls. If non-zero then this suppresses resizing of the |buckets| array,
+ * which would otherwise disrupt the iteration. */
+ unsigned callback_depth;
+
+ lhash_cmp_func comp;
+ lhash_hash_func hash;
+} _LHASH;
+
+/* lh_new returns a new, empty hash table or NULL on error. If |comp| is NULL,
+ * |strcmp| will be used. If |hash| is NULL, a generic hash function will be
+ * used. */
+_LHASH *lh_new(lhash_hash_func hash, lhash_cmp_func comp);
+
+/* lh_free frees the hash table itself but none of the elements. See
+ * |lh_doall|. */
+void lh_free(_LHASH *lh);
+
+/* lh_num_items returns the number of items in |lh|. */
+size_t lh_num_items(const _LHASH *lh);
+
+/* lh_retrieve finds an element equal to |data| in the hash table and returns
+ * it. If no such element exists, it returns NULL. */
+void *lh_retrieve(const _LHASH *lh, const void *data);
+
+/* lh_insert inserts |data| into the hash table. If an existing element is
+ * equal to |data| (with respect to the comparison function) then |*old_data|
+ * will be set to that value and it will be replaced. Otherwise, or in the
+ * event of an error, |*old_data| will be set to NULL. It returns one on
+ * success or zero in the case of an allocation error. */
+int lh_insert(_LHASH *lh, void **old_data, void *data);
+
+/* lh_delete removes an element equal to |data| from the hash table and returns
+ * it. If no such element is found, it returns NULL. */
+void *lh_delete(_LHASH *lh, const void *data);
+
+/* lh_doall calls |func| on each element of the hash table.
+ * TODO(fork): rename this */
+void lh_doall(_LHASH *lh, void (*func)(void *));
+
+/* lh_doall_arg calls |func| on each element of the hash table and also passes
+ * |arg| as the second argument.
+ * TODO(fork): rename this */
+void lh_doall_arg(_LHASH *lh, void (*func)(void *, void *), void *arg);
+
+/* lh_strhash is the default hash function which processes NUL-terminated
+ * strings. */
+uint32_t lh_strhash(const char *c);
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_STACK_H */
diff --git a/crypto/lhash/lhash_macros.h b/crypto/lhash/lhash_macros.h
new file mode 100644
index 0000000..f84b5ed
--- /dev/null
+++ b/crypto/lhash/lhash_macros.h
@@ -0,0 +1,248 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#if !defined(IN_LHASH_H)
+#error "Don't include this file directly. Include lhash.h"
+#endif
+
+/* ASN1_OBJECT */
+#define lh_ASN1_OBJECT_new(hash, comp) \
+ ((LHASH_OF(ASN1_OBJECT) *)lh_new( \
+ CHECKED_CAST(lhash_hash_func, uint32_t (*)(const ASN1_OBJECT *), hash), \
+ CHECKED_CAST(lhash_cmp_func, \
+ int (*)(const ASN1_OBJECT *a, const ASN1_OBJECT *b), \
+ comp)))
+
+#define lh_ASN1_OBJECT_free(lh) \
+ lh_free(CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh));
+
+#define lh_ASN1_OBJECT_num_items(lh) \
+ lh_num_items(CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh))
+
+#define lh_ASN1_OBJECT_retrieve(lh, data) \
+ ((ASN1_OBJECT *)lh_retrieve( \
+ CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh), \
+ CHECKED_CAST(void *, ASN1_OBJECT *, data)))
+
+#define lh_ASN1_OBJECT_insert(lh, old_data, data) \
+ lh_insert(CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh), \
+ CHECKED_CAST(void **, ASN1_OBJECT **, old_data), \
+ CHECKED_CAST(void *, ASN1_OBJECT *, data))
+
+#define lh_ASN1_OBJECT_delete(lh, data) \
+ ((ASN1_OBJECT *)lh_delete( \
+ CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh), \
+ CHECKED_CAST(void *, ASN1_OBJECT *, data)))
+
+#define lh_ASN1_OBJECT_doall(lh, func) \
+ lh_doall(CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh), \
+ CHECKED_CAST(void (*)(void *), void (*)(ASN1_OBJECT *), func));
+
+#define lh_ASN1_OBJECT_doall_arg(lh, func, arg) \
+ lh_doall_arg(CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh), \
+ CHECKED_CAST(void (*)(void *, void *), \
+ void (*)(ASN1_OBJECT *, void *), func), \
+ arg);
+
+/* CONF_VALUE */
+#define lh_CONF_VALUE_new(hash, comp) \
+ ((LHASH_OF(CONF_VALUE) *)lh_new( \
+ CHECKED_CAST(lhash_hash_func, uint32_t (*)(const CONF_VALUE *), hash), \
+ CHECKED_CAST(lhash_cmp_func, \
+ int (*)(const CONF_VALUE *a, const CONF_VALUE *b), comp)))
+
+#define lh_CONF_VALUE_free(lh) \
+ lh_free(CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh));
+
+#define lh_CONF_VALUE_num_items(lh) \
+ lh_num_items(CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh))
+
+#define lh_CONF_VALUE_retrieve(lh, data) \
+ ((CONF_VALUE *)lh_retrieve( \
+ CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh), \
+ CHECKED_CAST(void *, CONF_VALUE *, data)))
+
+#define lh_CONF_VALUE_insert(lh, old_data, data) \
+ lh_insert(CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh), \
+ CHECKED_CAST(void **, CONF_VALUE **, old_data), \
+ CHECKED_CAST(void *, CONF_VALUE *, data))
+
+#define lh_CONF_VALUE_delete(lh, data) \
+ ((CONF_VALUE *)lh_delete(CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh), \
+ CHECKED_CAST(void *, CONF_VALUE *, data)))
+
+#define lh_CONF_VALUE_doall(lh, func) \
+ lh_doall(CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh), \
+ CHECKED_CAST(void (*)(void *), void (*)(CONF_VALUE *), func));
+
+#define lh_CONF_VALUE_doall_arg(lh, func, arg) \
+ lh_doall_arg(CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh), \
+ CHECKED_CAST(void (*)(void *, void *), \
+ void (*)(CONF_VALUE *, void *), func), \
+ arg);
+
+/* ERR_STATE */
+#define lh_ERR_STATE_new(hash, comp) \
+ ((LHASH_OF(ERR_STATE) *)lh_new( \
+ CHECKED_CAST(lhash_hash_func, uint32_t (*)(const ERR_STATE *), hash), \
+ CHECKED_CAST(lhash_cmp_func, \
+ int (*)(const ERR_STATE *a, const ERR_STATE *b), comp)))
+
+#define lh_ERR_STATE_free(lh) \
+ lh_free(CHECKED_CAST(_LHASH *, LHASH_OF(ERR_STATE) *, lh));
+
+#define lh_ERR_STATE_num_items(lh) \
+ lh_num_items(CHECKED_CAST(_LHASH *, LHASH_OF(ERR_STATE) *, lh))
+
+#define lh_ERR_STATE_retrieve(lh, data) \
+ ((ERR_STATE *)lh_retrieve(CHECKED_CAST(_LHASH *, LHASH_OF(ERR_STATE) *, lh), \
+ CHECKED_CAST(void *, ERR_STATE *, data)))
+
+#define lh_ERR_STATE_insert(lh, old_data, data) \
+ lh_insert(CHECKED_CAST(_LHASH *, LHASH_OF(ERR_STATE) *, lh), \
+ CHECKED_CAST(void **, ERR_STATE **, old_data), \
+ CHECKED_CAST(void *, ERR_STATE *, data))
+
+#define lh_ERR_STATE_delete(lh, data) \
+ ((ERR_STATE *)lh_delete(CHECKED_CAST(_LHASH *, LHASH_OF(ERR_STATE) *, lh), \
+ CHECKED_CAST(void *, ERR_STATE *, data)))
+
+#define lh_ERR_STATE_doall(lh, func) \
+ lh_doall(CHECKED_CAST(_LHASH *, LHASH_OF(ERR_STATE) *, lh), \
+ CHECKED_CAST(void (*)(void *), void (*)(ERR_STATE *), func));
+
+#define lh_ERR_STATE_doall_arg(lh, func, arg) \
+ lh_doall_arg(CHECKED_CAST(_LHASH *, LHASH_OF(ERR_STATE) *, lh), \
+ CHECKED_CAST(void (*)(void *, void *), \
+ void (*)(ERR_STATE *, void *), func), \
+ arg);
+
+/* ERR_STRING_DATA */
+#define lh_ERR_STRING_DATA_new(hash, comp) \
+ ((LHASH_OF(ERR_STRING_DATA) *)lh_new( \
+ CHECKED_CAST(lhash_hash_func, uint32_t (*)(const ERR_STRING_DATA *), \
+ hash), \
+ CHECKED_CAST( \
+ lhash_cmp_func, \
+ int (*)(const ERR_STRING_DATA *a, const ERR_STRING_DATA *b), comp)))
+
+#define lh_ERR_STRING_DATA_free(lh) \
+ lh_free(CHECKED_CAST(_LHASH *, LHASH_OF(ERR_STRING_DATA) *, lh));
+
+#define lh_ERR_STRING_DATA_num_items(lh) \
+ lh_num_items(CHECKED_CAST(_LHASH *, LHASH_OF(ERR_STRING_DATA) *, lh))
+
+#define lh_ERR_STRING_DATA_retrieve(lh, data) \
+ ((ERR_STRING_DATA *)lh_retrieve( \
+ CHECKED_CAST(_LHASH *, LHASH_OF(ERR_STRING_DATA) *, lh), \
+ CHECKED_CAST(void *, ERR_STRING_DATA *, data)))
+
+#define lh_ERR_STRING_DATA_insert(lh, old_data, data) \
+ lh_insert(CHECKED_CAST(_LHASH *, LHASH_OF(ERR_STRING_DATA) *, lh), \
+ CHECKED_CAST(void **, ERR_STRING_DATA **, old_data), \
+ CHECKED_CAST(void *, ERR_STRING_DATA *, data))
+
+#define lh_ERR_STRING_DATA_delete(lh, data) \
+ ((ERR_STRING_DATA *)lh_delete( \
+ CHECKED_CAST(_LHASH *, LHASH_OF(ERR_STRING_DATA) *, lh), \
+ CHECKED_CAST(void *, ERR_STRING_DATA *, data)))
+
+#define lh_ERR_STRING_DATA_doall(lh, func) \
+ lh_doall(CHECKED_CAST(_LHASH *, LHASH_OF(ERR_STRING_DATA) *, lh), \
+ CHECKED_CAST(void (*)(void *), void (*)(ERR_STRING_DATA *), func));
+
+#define lh_ERR_STRING_DATA_doall_arg(lh, func, arg) \
+ lh_doall_arg(CHECKED_CAST(_LHASH *, LHASH_OF(ERR_STRING_DATA) *, lh), \
+ CHECKED_CAST(void (*)(void *, void *), \
+ void (*)(ERR_STRING_DATA *, void *), func), \
+ arg);
+
+/* EX_CLASS_ITEM */
+#define lh_EX_CLASS_ITEM_new(hash, comp) \
+ ((LHASH_OF(EX_CLASS_ITEM) *)lh_new( \
+ CHECKED_CAST(lhash_hash_func, uint32_t (*)(const EX_CLASS_ITEM *), \
+ hash), \
+ CHECKED_CAST(lhash_cmp_func, \
+ int (*)(const EX_CLASS_ITEM *a, const EX_CLASS_ITEM *b), \
+ comp)))
+
+#define lh_EX_CLASS_ITEM_free(lh) \
+ lh_free(CHECKED_CAST(_LHASH *, LHASH_OF(EX_CLASS_ITEM) *, lh));
+
+#define lh_EX_CLASS_ITEM_num_items(lh) \
+ lh_num_items(CHECKED_CAST(_LHASH *, LHASH_OF(EX_CLASS_ITEM) *, lh))
+
+#define lh_EX_CLASS_ITEM_retrieve(lh, data) \
+ ((EX_CLASS_ITEM *)lh_retrieve( \
+ CHECKED_CAST(_LHASH *, LHASH_OF(EX_CLASS_ITEM) *, lh), \
+ CHECKED_CAST(void *, EX_CLASS_ITEM *, data)))
+
+#define lh_EX_CLASS_ITEM_insert(lh, old_data, data) \
+ lh_insert(CHECKED_CAST(_LHASH *, LHASH_OF(EX_CLASS_ITEM) *, lh), \
+ CHECKED_CAST(void **, EX_CLASS_ITEM **, old_data), \
+ CHECKED_CAST(void *, EX_CLASS_ITEM *, data))
+
+#define lh_EX_CLASS_ITEM_delete(lh, data) \
+ ((EX_CLASS_ITEM *)lh_delete( \
+ CHECKED_CAST(_LHASH *, LHASH_OF(EX_CLASS_ITEM) *, lh), \
+ CHECKED_CAST(void *, EX_CLASS_ITEM *, data)))
+
+#define lh_EX_CLASS_ITEM_doall(lh, func) \
+ lh_doall(CHECKED_CAST(_LHASH *, LHASH_OF(EX_CLASS_ITEM) *, lh), \
+ CHECKED_CAST(void (*)(void *), void (*)(EX_CLASS_ITEM *), func));
+
+#define lh_EX_CLASS_ITEM_doall_arg(lh, func, arg) \
+ lh_doall_arg(CHECKED_CAST(_LHASH *, LHASH_OF(EX_CLASS_ITEM) *, lh), \
+ CHECKED_CAST(void (*)(void *, void *), \
+ void (*)(EX_CLASS_ITEM *, void *), func), \
+ arg);
+
+/* SSL_SESSION */
+#define lh_SSL_SESSION_new(hash, comp) \
+ ((LHASH_OF(SSL_SESSION) *)lh_new( \
+ CHECKED_CAST(lhash_hash_func, uint32_t (*)(const SSL_SESSION *), hash), \
+ CHECKED_CAST(lhash_cmp_func, \
+ int (*)(const SSL_SESSION *a, const SSL_SESSION *b), \
+ comp)))
+
+#define lh_SSL_SESSION_free(lh) \
+ lh_free(CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh));
+
+#define lh_SSL_SESSION_num_items(lh) \
+ lh_num_items(CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh))
+
+#define lh_SSL_SESSION_retrieve(lh, data) \
+ ((SSL_SESSION *)lh_retrieve( \
+ CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh), \
+ CHECKED_CAST(void *, SSL_SESSION *, data)))
+
+#define lh_SSL_SESSION_insert(lh, old_data, data) \
+ lh_insert(CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh), \
+ CHECKED_CAST(void **, SSL_SESSION **, old_data), \
+ CHECKED_CAST(void *, SSL_SESSION *, data))
+
+#define lh_SSL_SESSION_delete(lh, data) \
+ ((SSL_SESSION *)lh_delete( \
+ CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh), \
+ CHECKED_CAST(void *, SSL_SESSION *, data)))
+
+#define lh_SSL_SESSION_doall(lh, func) \
+ lh_doall(CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh), \
+ CHECKED_CAST(void (*)(void *), void (*)(SSL_SESSION *), func));
+
+#define lh_SSL_SESSION_doall_arg(lh, func, arg) \
+ lh_doall_arg(CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh), \
+ CHECKED_CAST(void (*)(void *, void *), \
+ void (*)(SSL_SESSION *, void *), func), \
+ arg);
diff --git a/crypto/lhash/lhash_test.c b/crypto/lhash/lhash_test.c
new file mode 100644
index 0000000..e53a6f6
--- /dev/null
+++ b/crypto/lhash/lhash_test.c
@@ -0,0 +1,191 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#define _POSIX_SOURCE
+#define _BSD_SOURCE
+
+#include <openssl/lhash.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct dummy_lhash_node {
+ char *s;
+ struct dummy_lhash_node *next;
+};
+
+struct dummy_lhash {
+ struct dummy_lhash_node *head;
+};
+
+static void dummy_lh_free(struct dummy_lhash *lh) {
+ struct dummy_lhash_node *cur, *next;
+
+ for (cur = lh->head; cur != NULL; cur = next) {
+ next = cur->next;
+ free(cur->s);
+ free(cur);
+ }
+}
+
+static size_t dummy_lh_num_items(const struct dummy_lhash *lh) {
+ size_t count = 0;
+ struct dummy_lhash_node *cur;
+
+ for (cur = lh->head; cur != NULL; cur = cur->next) {
+ count++;
+ }
+
+ return count;
+}
+
+static char *dummy_lh_retrieve(struct dummy_lhash *lh, const char *s) {
+ struct dummy_lhash_node *cur;
+
+ for (cur = lh->head; cur != NULL; cur = cur->next) {
+ if (strcmp(cur->s, s) == 0) {
+ return cur->s;
+ }
+ }
+
+ return NULL;
+}
+
+static int dummy_lh_insert(struct dummy_lhash *lh, char **old_data, char *s) {
+ struct dummy_lhash_node *node, *cur;
+
+ for (cur = lh->head; cur != NULL; cur = cur->next) {
+ if (strcmp(cur->s, s) == 0) {
+ *old_data = cur->s;
+ cur->s = s;
+ return 1;
+ }
+ }
+
+ node = malloc(sizeof(struct dummy_lhash_node));
+ *old_data = NULL;
+ node->s = s;
+ node->next = lh->head;
+ lh->head = node;
+ return 1;
+}
+
+static char *dummy_lh_delete(struct dummy_lhash *lh, const void *s) {
+ struct dummy_lhash_node *cur, **next_ptr;
+ char *ret;
+
+ next_ptr = &lh->head;
+ for (cur = lh->head; cur != NULL; cur = cur->next) {
+ if (strcmp(cur->s, s) == 0) {
+ ret = cur->s;
+ *next_ptr = cur->next;
+ free(cur);
+ return ret;
+ }
+ next_ptr = &cur->next;
+ }
+
+ return NULL;
+}
+
+static char *rand_string(unsigned *rand_state) {
+ unsigned len = 1 + (rand_r(rand_state) % 3);
+ char *ret = malloc(len + 1);
+ unsigned i;
+
+ for (i = 0; i < len; i++) {
+ ret[i] = '0' + (rand_r(rand_state) & 7);
+ }
+ ret[i] = 0;
+
+ return ret;
+}
+
+int main(int argc, char **argv) {
+ _LHASH *lh = lh_new(NULL, NULL);
+ struct dummy_lhash dummy_lh = {NULL};
+ unsigned rand_state = 0;
+ unsigned i;
+
+ for (i = 0; i < 100000; i++) {
+ unsigned action;
+ char *s, *s1, *s2;
+
+ if (dummy_lh_num_items(&dummy_lh) != lh_num_items(lh)) {
+ fprintf(stderr, "Length mismatch\n");
+ return 1;
+ }
+
+ action = rand_r(&rand_state) % 3;
+ switch (action) {
+ case 0:
+ s = rand_string(&rand_state);
+ s1 = (char *)lh_retrieve(lh, s);
+ s2 = dummy_lh_retrieve(&dummy_lh, s);
+ if (s1 != NULL && (s2 == NULL || strcmp(s1, s2) != 0)) {
+ fprintf(stderr, "lh_retrieve failure\n");
+ abort();
+ }
+ free(s);
+ break;
+
+ case 1:
+ s = rand_string(&rand_state);
+ lh_insert(lh, (void **)&s1, s);
+ dummy_lh_insert(&dummy_lh, &s2, strdup(s));
+
+ if (s1 != NULL && (s2 == NULL || strcmp(s1, s2) != 0)) {
+ fprintf(stderr, "lh_insert failure\n");
+ abort();
+ }
+
+ if (s1) {
+ free(s1);
+ }
+ if (s2) {
+ free(s2);
+ }
+ break;
+
+ case 2:
+ s = rand_string(&rand_state);
+ s1 = lh_delete(lh, s);
+ s2 = dummy_lh_delete(&dummy_lh, s);
+
+ if (s1 != NULL && (s2 == NULL || strcmp(s1, s2) != 0)) {
+ fprintf(stderr, "lh_insert failure\n");
+ abort();
+ }
+
+ if (s1) {
+ free(s1);
+ }
+ if (s2) {
+ free(s2);
+ }
+ free(s);
+ break;
+
+ default:
+ abort();
+ }
+ }
+
+ lh_doall(lh, free);
+ lh_free(lh);
+ dummy_lh_free(&dummy_lh);
+ printf("PASS\n");
+ return 0;
+}
diff --git a/crypto/lhash/make_macros.sh b/crypto/lhash/make_macros.sh
new file mode 100644
index 0000000..79d1e57
--- /dev/null
+++ b/crypto/lhash/make_macros.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+
+cat > lhash_macros.h << EOF
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#if !defined(IN_LHASH_H)
+#error "Don't include this file directly. Include lhash.h"
+#endif
+
+EOF
+
+output_lhash () {
+ type=$1
+
+ cat >> lhash_macros.h << EOF
+/* ${type} */
+#define lh_${type}_new(hash, comp)\\
+((LHASH_OF(${type})*) lh_new(CHECKED_CAST(lhash_hash_func, uint32_t (*) (const ${type} *), hash), CHECKED_CAST(lhash_cmp_func, int (*) (const ${type} *a, const ${type} *b), comp)))
+
+#define lh_${type}_free(lh)\\
+ lh_free(CHECKED_CAST(_LHASH*, LHASH_OF(${type})*, lh));
+
+#define lh_${type}_num_items(lh)\\
+ lh_num_items(CHECKED_CAST(_LHASH*, LHASH_OF(${type})*, lh))
+
+#define lh_${type}_retrieve(lh, data)\\
+ ((${type}*) lh_retrieve(CHECKED_CAST(_LHASH*, LHASH_OF(${type})*, lh), CHECKED_CAST(void*, ${type}*, data)))
+
+#define lh_${type}_insert(lh, old_data, data)\\
+ lh_insert(CHECKED_CAST(_LHASH*, LHASH_OF(${type})*, lh), CHECKED_CAST(void**, ${type}**, old_data), CHECKED_CAST(void*, ${type}*, data))
+
+#define lh_${type}_delete(lh, data)\\
+ ((${type}*) lh_delete(CHECKED_CAST(_LHASH*, LHASH_OF(${type})*, lh), CHECKED_CAST(void*, ${type}*, data)))
+
+#define lh_${type}_doall(lh, func)\\
+ lh_doall(CHECKED_CAST(_LHASH*, LHASH_OF(${type})*, lh), CHECKED_CAST(void (*)(void*), void (*) (${type}*), func));
+
+#define lh_${type}_doall_arg(lh, func, arg)\\
+ lh_doall_arg(CHECKED_CAST(_LHASH*, LHASH_OF(${type})*, lh), CHECKED_CAST(void (*)(void*, void*), void (*) (${type}*, void*), func), arg);
+
+
+EOF
+}
+
+lhash_types=$(cat lhash.h | grep '^ \* LHASH_OF:' | sed -e 's/.*LHASH_OF://' -e 's/ .*//')
+
+for type in $lhash_types; do
+ echo Hash of ${type}
+ output_lhash "${type}"
+done
+
+clang-format -i lhash_macros.h
diff --git a/crypto/md5/CMakeLists.txt b/crypto/md5/CMakeLists.txt
new file mode 100644
index 0000000..ce2f8dc
--- /dev/null
+++ b/crypto/md5/CMakeLists.txt
@@ -0,0 +1,38 @@
+include_directories(. .. ../../include)
+
+if (${ARCH} STREQUAL "x86_64")
+ set(
+ MD5_ARCH_SOURCES
+
+ md5-x86_64.${ASM_EXT}
+ )
+endif()
+
+if (${ARCH} STREQUAL "x86")
+ set(
+ MD5_ARCH_SOURCES
+
+ md5-586.${ASM_EXT}
+ )
+endif()
+
+add_library(
+ md5
+
+ OBJECT
+
+ md5.c
+
+ ${MD5_ARCH_SOURCES}
+)
+
+perlasm(md5-x86_64.${ASM_EXT} asm/md5-x86_64.pl)
+perlasm(md5-586.${ASM_EXT} asm/md5-586.pl)
+
+add_executable(
+ md5_test
+
+ md5_test.c
+)
+
+target_link_libraries(md5_test crypto)
diff --git a/crypto/md5/asm/md5-586.pl b/crypto/md5/asm/md5-586.pl
new file mode 100644
index 0000000..6cb66bb
--- /dev/null
+++ b/crypto/md5/asm/md5-586.pl
@@ -0,0 +1,307 @@
+#!/usr/local/bin/perl
+
+# Normal is the
+# md5_block_x86(MD5_CTX *c, ULONG *X);
+# version, non-normal is the
+# md5_block_x86(MD5_CTX *c, ULONG *X,int blocks);
+
+$normal=0;
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+push(@INC,"${dir}","${dir}../../perlasm");
+require "x86asm.pl";
+
+&asm_init($ARGV[0],$0);
+
+$A="eax";
+$B="ebx";
+$C="ecx";
+$D="edx";
+$tmp1="edi";
+$tmp2="ebp";
+$X="esi";
+
+# What we need to load into $tmp for the next round
+%Ltmp1=("R0",&Np($C), "R1",&Np($C), "R2",&Np($C), "R3",&Np($D));
+@xo=(
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, # R0
+ 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, # R1
+ 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, # R2
+ 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9, # R3
+ );
+
+&md5_block("md5_block_asm_data_order");
+&asm_finish();
+
+sub Np
+ {
+ local($p)=@_;
+ local(%n)=($A,$D,$B,$A,$C,$B,$D,$C);
+ return($n{$p});
+ }
+
+sub R0
+ {
+ local($pos,$a,$b,$c,$d,$K,$ki,$s,$t)=@_;
+
+ &mov($tmp1,$C) if $pos < 0;
+ &mov($tmp2,&DWP($xo[$ki]*4,$K,"",0)) if $pos < 0; # very first one
+
+ # body proper
+
+ &comment("R0 $ki");
+ &xor($tmp1,$d); # F function - part 2
+
+ &and($tmp1,$b); # F function - part 3
+ &lea($a,&DWP($t,$a,$tmp2,1));
+
+ &xor($tmp1,$d); # F function - part 4
+
+ &add($a,$tmp1);
+ &mov($tmp1,&Np($c)) if $pos < 1; # next tmp1 for R0
+ &mov($tmp1,&Np($c)) if $pos == 1; # next tmp1 for R1
+
+ &rotl($a,$s);
+
+ &mov($tmp2,&DWP($xo[$ki+1]*4,$K,"",0)) if ($pos != 2);
+
+ &add($a,$b);
+ }
+
+sub R1
+ {
+ local($pos,$a,$b,$c,$d,$K,$ki,$s,$t)=@_;
+
+ &comment("R1 $ki");
+
+ &lea($a,&DWP($t,$a,$tmp2,1));
+
+ &xor($tmp1,$b); # G function - part 2
+ &and($tmp1,$d); # G function - part 3
+
+ &mov($tmp2,&DWP($xo[$ki+1]*4,$K,"",0)) if ($pos != 2);
+ &xor($tmp1,$c); # G function - part 4
+
+ &add($a,$tmp1);
+ &mov($tmp1,&Np($c)) if $pos < 1; # G function - part 1
+ &mov($tmp1,&Np($c)) if $pos == 1; # G function - part 1
+
+ &rotl($a,$s);
+
+ &add($a,$b);
+ }
+
+sub R2
+ {
+ local($n,$pos,$a,$b,$c,$d,$K,$ki,$s,$t)=@_;
+ # This one is different, only 3 logical operations
+
+if (($n & 1) == 0)
+ {
+ &comment("R2 $ki");
+ # make sure to do 'D' first, not 'B', else we clash with
+ # the last add from the previous round.
+
+ &xor($tmp1,$d); # H function - part 2
+
+ &xor($tmp1,$b); # H function - part 3
+ &lea($a,&DWP($t,$a,$tmp2,1));
+
+ &add($a,$tmp1);
+
+ &rotl($a,$s);
+
+ &mov($tmp2,&DWP($xo[$ki+1]*4,$K,"",0));
+ &mov($tmp1,&Np($c));
+ }
+else
+ {
+ &comment("R2 $ki");
+ # make sure to do 'D' first, not 'B', else we clash with
+ # the last add from the previous round.
+
+ &lea($a,&DWP($t,$a,$tmp2,1));
+
+ &add($b,$c); # MOVED FORWARD
+ &xor($tmp1,$d); # H function - part 2
+
+ &xor($tmp1,$b); # H function - part 3
+ &mov($tmp2,&DWP($xo[$ki+1]*4,$K,"",0)) if ($pos != 2);
+
+ &add($a,$tmp1);
+ &mov($tmp1,&Np($c)) if $pos < 1; # H function - part 1
+ &mov($tmp1,-1) if $pos == 1; # I function - part 1
+
+ &rotl($a,$s);
+
+ &add($a,$b);
+ }
+ }
+
+sub R3
+ {
+ local($pos,$a,$b,$c,$d,$K,$ki,$s,$t)=@_;
+
+ &comment("R3 $ki");
+
+ # ¬($tmp1)
+ &xor($tmp1,$d) if $pos < 0; # I function - part 2
+
+ &or($tmp1,$b); # I function - part 3
+ &lea($a,&DWP($t,$a,$tmp2,1));
+
+ &xor($tmp1,$c); # I function - part 4
+ &mov($tmp2,&DWP($xo[$ki+1]*4,$K,"",0)) if $pos != 2; # load X/k value
+ &mov($tmp2,&wparam(0)) if $pos == 2;
+
+ &add($a,$tmp1);
+ &mov($tmp1,-1) if $pos < 1; # H function - part 1
+ &add($K,64) if $pos >=1 && !$normal;
+
+ &rotl($a,$s);
+
+ &xor($tmp1,&Np($d)) if $pos <= 0; # I function - part = first time
+ &mov($tmp1,&DWP( 0,$tmp2,"",0)) if $pos > 0;
+ &add($a,$b);
+ }
+
+
+sub md5_block
+ {
+ local($name)=@_;
+
+ &function_begin_B($name,"",3);
+
+ # parameter 1 is the MD5_CTX structure.
+ # A 0
+ # B 4
+ # C 8
+ # D 12
+
+ &push("esi");
+ &push("edi");
+ &mov($tmp1, &wparam(0)); # edi
+ &mov($X, &wparam(1)); # esi
+ &mov($C, &wparam(2));
+ &push("ebp");
+ &shl($C, 6);
+ &push("ebx");
+ &add($C, $X); # offset we end at
+ &sub($C, 64);
+ &mov($A, &DWP( 0,$tmp1,"",0));
+ &push($C); # Put on the TOS
+ &mov($B, &DWP( 4,$tmp1,"",0));
+ &mov($C, &DWP( 8,$tmp1,"",0));
+ &mov($D, &DWP(12,$tmp1,"",0));
+
+ &set_label("start") unless $normal;
+ &comment("");
+ &comment("R0 section");
+
+ &R0(-2,$A,$B,$C,$D,$X, 0, 7,0xd76aa478);
+ &R0( 0,$D,$A,$B,$C,$X, 1,12,0xe8c7b756);
+ &R0( 0,$C,$D,$A,$B,$X, 2,17,0x242070db);
+ &R0( 0,$B,$C,$D,$A,$X, 3,22,0xc1bdceee);
+ &R0( 0,$A,$B,$C,$D,$X, 4, 7,0xf57c0faf);
+ &R0( 0,$D,$A,$B,$C,$X, 5,12,0x4787c62a);
+ &R0( 0,$C,$D,$A,$B,$X, 6,17,0xa8304613);
+ &R0( 0,$B,$C,$D,$A,$X, 7,22,0xfd469501);
+ &R0( 0,$A,$B,$C,$D,$X, 8, 7,0x698098d8);
+ &R0( 0,$D,$A,$B,$C,$X, 9,12,0x8b44f7af);
+ &R0( 0,$C,$D,$A,$B,$X,10,17,0xffff5bb1);
+ &R0( 0,$B,$C,$D,$A,$X,11,22,0x895cd7be);
+ &R0( 0,$A,$B,$C,$D,$X,12, 7,0x6b901122);
+ &R0( 0,$D,$A,$B,$C,$X,13,12,0xfd987193);
+ &R0( 0,$C,$D,$A,$B,$X,14,17,0xa679438e);
+ &R0( 1,$B,$C,$D,$A,$X,15,22,0x49b40821);
+
+ &comment("");
+ &comment("R1 section");
+ &R1(-1,$A,$B,$C,$D,$X,16, 5,0xf61e2562);
+ &R1( 0,$D,$A,$B,$C,$X,17, 9,0xc040b340);
+ &R1( 0,$C,$D,$A,$B,$X,18,14,0x265e5a51);
+ &R1( 0,$B,$C,$D,$A,$X,19,20,0xe9b6c7aa);
+ &R1( 0,$A,$B,$C,$D,$X,20, 5,0xd62f105d);
+ &R1( 0,$D,$A,$B,$C,$X,21, 9,0x02441453);
+ &R1( 0,$C,$D,$A,$B,$X,22,14,0xd8a1e681);
+ &R1( 0,$B,$C,$D,$A,$X,23,20,0xe7d3fbc8);
+ &R1( 0,$A,$B,$C,$D,$X,24, 5,0x21e1cde6);
+ &R1( 0,$D,$A,$B,$C,$X,25, 9,0xc33707d6);
+ &R1( 0,$C,$D,$A,$B,$X,26,14,0xf4d50d87);
+ &R1( 0,$B,$C,$D,$A,$X,27,20,0x455a14ed);
+ &R1( 0,$A,$B,$C,$D,$X,28, 5,0xa9e3e905);
+ &R1( 0,$D,$A,$B,$C,$X,29, 9,0xfcefa3f8);
+ &R1( 0,$C,$D,$A,$B,$X,30,14,0x676f02d9);
+ &R1( 1,$B,$C,$D,$A,$X,31,20,0x8d2a4c8a);
+
+ &comment("");
+ &comment("R2 section");
+ &R2( 0,-1,$A,$B,$C,$D,$X,32, 4,0xfffa3942);
+ &R2( 1, 0,$D,$A,$B,$C,$X,33,11,0x8771f681);
+ &R2( 2, 0,$C,$D,$A,$B,$X,34,16,0x6d9d6122);
+ &R2( 3, 0,$B,$C,$D,$A,$X,35,23,0xfde5380c);
+ &R2( 4, 0,$A,$B,$C,$D,$X,36, 4,0xa4beea44);
+ &R2( 5, 0,$D,$A,$B,$C,$X,37,11,0x4bdecfa9);
+ &R2( 6, 0,$C,$D,$A,$B,$X,38,16,0xf6bb4b60);
+ &R2( 7, 0,$B,$C,$D,$A,$X,39,23,0xbebfbc70);
+ &R2( 8, 0,$A,$B,$C,$D,$X,40, 4,0x289b7ec6);
+ &R2( 9, 0,$D,$A,$B,$C,$X,41,11,0xeaa127fa);
+ &R2(10, 0,$C,$D,$A,$B,$X,42,16,0xd4ef3085);
+ &R2(11, 0,$B,$C,$D,$A,$X,43,23,0x04881d05);
+ &R2(12, 0,$A,$B,$C,$D,$X,44, 4,0xd9d4d039);
+ &R2(13, 0,$D,$A,$B,$C,$X,45,11,0xe6db99e5);
+ &R2(14, 0,$C,$D,$A,$B,$X,46,16,0x1fa27cf8);
+ &R2(15, 1,$B,$C,$D,$A,$X,47,23,0xc4ac5665);
+
+ &comment("");
+ &comment("R3 section");
+ &R3(-1,$A,$B,$C,$D,$X,48, 6,0xf4292244);
+ &R3( 0,$D,$A,$B,$C,$X,49,10,0x432aff97);
+ &R3( 0,$C,$D,$A,$B,$X,50,15,0xab9423a7);
+ &R3( 0,$B,$C,$D,$A,$X,51,21,0xfc93a039);
+ &R3( 0,$A,$B,$C,$D,$X,52, 6,0x655b59c3);
+ &R3( 0,$D,$A,$B,$C,$X,53,10,0x8f0ccc92);
+ &R3( 0,$C,$D,$A,$B,$X,54,15,0xffeff47d);
+ &R3( 0,$B,$C,$D,$A,$X,55,21,0x85845dd1);
+ &R3( 0,$A,$B,$C,$D,$X,56, 6,0x6fa87e4f);
+ &R3( 0,$D,$A,$B,$C,$X,57,10,0xfe2ce6e0);
+ &R3( 0,$C,$D,$A,$B,$X,58,15,0xa3014314);
+ &R3( 0,$B,$C,$D,$A,$X,59,21,0x4e0811a1);
+ &R3( 0,$A,$B,$C,$D,$X,60, 6,0xf7537e82);
+ &R3( 0,$D,$A,$B,$C,$X,61,10,0xbd3af235);
+ &R3( 0,$C,$D,$A,$B,$X,62,15,0x2ad7d2bb);
+ &R3( 2,$B,$C,$D,$A,$X,63,21,0xeb86d391);
+
+ # &mov($tmp2,&wparam(0)); # done in the last R3
+ # &mov($tmp1, &DWP( 0,$tmp2,"",0)); # done is the last R3
+
+ &add($A,$tmp1);
+ &mov($tmp1, &DWP( 4,$tmp2,"",0));
+
+ &add($B,$tmp1);
+ &mov($tmp1, &DWP( 8,$tmp2,"",0));
+
+ &add($C,$tmp1);
+ &mov($tmp1, &DWP(12,$tmp2,"",0));
+
+ &add($D,$tmp1);
+ &mov(&DWP( 0,$tmp2,"",0),$A);
+
+ &mov(&DWP( 4,$tmp2,"",0),$B);
+ &mov($tmp1,&swtmp(0)) unless $normal;
+
+ &mov(&DWP( 8,$tmp2,"",0),$C);
+ &mov(&DWP(12,$tmp2,"",0),$D);
+
+ &cmp($tmp1,$X) unless $normal; # check count
+ &jae(&label("start")) unless $normal;
+
+ &pop("eax"); # pop the temp variable off the stack
+ &pop("ebx");
+ &pop("ebp");
+ &pop("edi");
+ &pop("esi");
+ &ret();
+ &function_end_B($name);
+ }
+
diff --git a/crypto/md5/asm/md5-x86_64.pl b/crypto/md5/asm/md5-x86_64.pl
new file mode 100644
index 0000000..fc684e0
--- /dev/null
+++ b/crypto/md5/asm/md5-x86_64.pl
@@ -0,0 +1,370 @@
+#!/usr/bin/perl -w
+#
+# MD5 optimized for AMD64.
+#
+# Author: Marc Bevand <bevand_m (at) epita.fr>
+# Licence: I hereby disclaim the copyright on this code and place it
+# in the public domain.
+#
+
+use strict;
+
+my $code;
+
+# round1_step() does:
+# dst = x + ((dst + F(x,y,z) + X[k] + T_i) <<< s)
+# %r10d = X[k_next]
+# %r11d = z' (copy of z for the next step)
+# Each round1_step() takes about 5.3 clocks (9 instructions, 1.7 IPC)
+sub round1_step
+{
+ my ($pos, $dst, $x, $y, $z, $k_next, $T_i, $s) = @_;
+ $code .= " mov 0*4(%rsi), %r10d /* (NEXT STEP) X[0] */\n" if ($pos == -1);
+ $code .= " mov %edx, %r11d /* (NEXT STEP) z' = %edx */\n" if ($pos == -1);
+ $code .= <<EOF;
+ xor $y, %r11d /* y ^ ... */
+ lea $T_i($dst,%r10d),$dst /* Const + dst + ... */
+ and $x, %r11d /* x & ... */
+ xor $z, %r11d /* z ^ ... */
+ mov $k_next*4(%rsi),%r10d /* (NEXT STEP) X[$k_next] */
+ add %r11d, $dst /* dst += ... */
+ rol \$$s, $dst /* dst <<< s */
+ mov $y, %r11d /* (NEXT STEP) z' = $y */
+ add $x, $dst /* dst += x */
+EOF
+}
+
+# round2_step() does:
+# dst = x + ((dst + G(x,y,z) + X[k] + T_i) <<< s)
+# %r10d = X[k_next]
+# %r11d = z' (copy of z for the next step)
+# %r12d = z' (copy of z for the next step)
+# Each round2_step() takes about 5.4 clocks (11 instructions, 2.0 IPC)
+sub round2_step
+{
+ my ($pos, $dst, $x, $y, $z, $k_next, $T_i, $s) = @_;
+ $code .= " mov 1*4(%rsi), %r10d /* (NEXT STEP) X[1] */\n" if ($pos == -1);
+ $code .= " mov %edx, %r11d /* (NEXT STEP) z' = %edx */\n" if ($pos == -1);
+ $code .= " mov %edx, %r12d /* (NEXT STEP) z' = %edx */\n" if ($pos == -1);
+ $code .= <<EOF;
+ not %r11d /* not z */
+ lea $T_i($dst,%r10d),$dst /* Const + dst + ... */
+ and $x, %r12d /* x & z */
+ and $y, %r11d /* y & (not z) */
+ mov $k_next*4(%rsi),%r10d /* (NEXT STEP) X[$k_next] */
+ or %r11d, %r12d /* (y & (not z)) | (x & z) */
+ mov $y, %r11d /* (NEXT STEP) z' = $y */
+ add %r12d, $dst /* dst += ... */
+ mov $y, %r12d /* (NEXT STEP) z' = $y */
+ rol \$$s, $dst /* dst <<< s */
+ add $x, $dst /* dst += x */
+EOF
+}
+
+# round3_step() does:
+# dst = x + ((dst + H(x,y,z) + X[k] + T_i) <<< s)
+# %r10d = X[k_next]
+# %r11d = y' (copy of y for the next step)
+# Each round3_step() takes about 4.2 clocks (8 instructions, 1.9 IPC)
+sub round3_step
+{
+ my ($pos, $dst, $x, $y, $z, $k_next, $T_i, $s) = @_;
+ $code .= " mov 5*4(%rsi), %r10d /* (NEXT STEP) X[5] */\n" if ($pos == -1);
+ $code .= " mov %ecx, %r11d /* (NEXT STEP) y' = %ecx */\n" if ($pos == -1);
+ $code .= <<EOF;
+ lea $T_i($dst,%r10d),$dst /* Const + dst + ... */
+ mov $k_next*4(%rsi),%r10d /* (NEXT STEP) X[$k_next] */
+ xor $z, %r11d /* z ^ ... */
+ xor $x, %r11d /* x ^ ... */
+ add %r11d, $dst /* dst += ... */
+ rol \$$s, $dst /* dst <<< s */
+ mov $x, %r11d /* (NEXT STEP) y' = $x */
+ add $x, $dst /* dst += x */
+EOF
+}
+
+# round4_step() does:
+# dst = x + ((dst + I(x,y,z) + X[k] + T_i) <<< s)
+# %r10d = X[k_next]
+# %r11d = not z' (copy of not z for the next step)
+# Each round4_step() takes about 5.2 clocks (9 instructions, 1.7 IPC)
+sub round4_step
+{
+ my ($pos, $dst, $x, $y, $z, $k_next, $T_i, $s) = @_;
+ $code .= " mov 0*4(%rsi), %r10d /* (NEXT STEP) X[0] */\n" if ($pos == -1);
+ $code .= " mov \$0xffffffff, %r11d\n" if ($pos == -1);
+ $code .= " xor %edx, %r11d /* (NEXT STEP) not z' = not %edx*/\n"
+ if ($pos == -1);
+ $code .= <<EOF;
+ lea $T_i($dst,%r10d),$dst /* Const + dst + ... */
+ or $x, %r11d /* x | ... */
+ xor $y, %r11d /* y ^ ... */
+ add %r11d, $dst /* dst += ... */
+ mov $k_next*4(%rsi),%r10d /* (NEXT STEP) X[$k_next] */
+ mov \$0xffffffff, %r11d
+ rol \$$s, $dst /* dst <<< s */
+ xor $y, %r11d /* (NEXT STEP) not z' = not $y */
+ add $x, $dst /* dst += x */
+EOF
+}
+
+my $flavour = shift;
+my $output = shift || "";
+if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
+
+my $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; my $dir=$1; my $xlate;
+( $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";
+
+no warnings qw(uninitialized);
+open OUT,"| \"$^X\" $xlate $flavour $output";
+*STDOUT=*OUT;
+
+$code .= <<EOF;
+.text
+.align 16
+
+.globl md5_block_asm_data_order
+.type md5_block_asm_data_order,\@function,3
+md5_block_asm_data_order:
+ push %rbp
+ push %rbx
+ push %r12
+ push %r14
+ push %r15
+.Lprologue:
+
+ # rdi = arg #1 (ctx, MD5_CTX pointer)
+ # rsi = arg #2 (ptr, data pointer)
+ # rdx = arg #3 (nbr, number of 16-word blocks to process)
+ mov %rdi, %rbp # rbp = ctx
+ shl \$6, %rdx # rdx = nbr in bytes
+ lea (%rsi,%rdx), %rdi # rdi = end
+ mov 0*4(%rbp), %eax # eax = ctx->A
+ mov 1*4(%rbp), %ebx # ebx = ctx->B
+ mov 2*4(%rbp), %ecx # ecx = ctx->C
+ mov 3*4(%rbp), %edx # edx = ctx->D
+ # end is 'rdi'
+ # ptr is 'rsi'
+ # A is 'eax'
+ # B is 'ebx'
+ # C is 'ecx'
+ # D is 'edx'
+
+ cmp %rdi, %rsi # cmp end with ptr
+ je .Lend # jmp if ptr == end
+
+ # BEGIN of loop over 16-word blocks
+.Lloop: # save old values of A, B, C, D
+ mov %eax, %r8d
+ mov %ebx, %r9d
+ mov %ecx, %r14d
+ mov %edx, %r15d
+EOF
+round1_step(-1,'%eax','%ebx','%ecx','%edx', '1','0xd76aa478', '7');
+round1_step( 0,'%edx','%eax','%ebx','%ecx', '2','0xe8c7b756','12');
+round1_step( 0,'%ecx','%edx','%eax','%ebx', '3','0x242070db','17');
+round1_step( 0,'%ebx','%ecx','%edx','%eax', '4','0xc1bdceee','22');
+round1_step( 0,'%eax','%ebx','%ecx','%edx', '5','0xf57c0faf', '7');
+round1_step( 0,'%edx','%eax','%ebx','%ecx', '6','0x4787c62a','12');
+round1_step( 0,'%ecx','%edx','%eax','%ebx', '7','0xa8304613','17');
+round1_step( 0,'%ebx','%ecx','%edx','%eax', '8','0xfd469501','22');
+round1_step( 0,'%eax','%ebx','%ecx','%edx', '9','0x698098d8', '7');
+round1_step( 0,'%edx','%eax','%ebx','%ecx','10','0x8b44f7af','12');
+round1_step( 0,'%ecx','%edx','%eax','%ebx','11','0xffff5bb1','17');
+round1_step( 0,'%ebx','%ecx','%edx','%eax','12','0x895cd7be','22');
+round1_step( 0,'%eax','%ebx','%ecx','%edx','13','0x6b901122', '7');
+round1_step( 0,'%edx','%eax','%ebx','%ecx','14','0xfd987193','12');
+round1_step( 0,'%ecx','%edx','%eax','%ebx','15','0xa679438e','17');
+round1_step( 1,'%ebx','%ecx','%edx','%eax', '0','0x49b40821','22');
+
+round2_step(-1,'%eax','%ebx','%ecx','%edx', '6','0xf61e2562', '5');
+round2_step( 0,'%edx','%eax','%ebx','%ecx','11','0xc040b340', '9');
+round2_step( 0,'%ecx','%edx','%eax','%ebx', '0','0x265e5a51','14');
+round2_step( 0,'%ebx','%ecx','%edx','%eax', '5','0xe9b6c7aa','20');
+round2_step( 0,'%eax','%ebx','%ecx','%edx','10','0xd62f105d', '5');
+round2_step( 0,'%edx','%eax','%ebx','%ecx','15', '0x2441453', '9');
+round2_step( 0,'%ecx','%edx','%eax','%ebx', '4','0xd8a1e681','14');
+round2_step( 0,'%ebx','%ecx','%edx','%eax', '9','0xe7d3fbc8','20');
+round2_step( 0,'%eax','%ebx','%ecx','%edx','14','0x21e1cde6', '5');
+round2_step( 0,'%edx','%eax','%ebx','%ecx', '3','0xc33707d6', '9');
+round2_step( 0,'%ecx','%edx','%eax','%ebx', '8','0xf4d50d87','14');
+round2_step( 0,'%ebx','%ecx','%edx','%eax','13','0x455a14ed','20');
+round2_step( 0,'%eax','%ebx','%ecx','%edx', '2','0xa9e3e905', '5');
+round2_step( 0,'%edx','%eax','%ebx','%ecx', '7','0xfcefa3f8', '9');
+round2_step( 0,'%ecx','%edx','%eax','%ebx','12','0x676f02d9','14');
+round2_step( 1,'%ebx','%ecx','%edx','%eax', '0','0x8d2a4c8a','20');
+
+round3_step(-1,'%eax','%ebx','%ecx','%edx', '8','0xfffa3942', '4');
+round3_step( 0,'%edx','%eax','%ebx','%ecx','11','0x8771f681','11');
+round3_step( 0,'%ecx','%edx','%eax','%ebx','14','0x6d9d6122','16');
+round3_step( 0,'%ebx','%ecx','%edx','%eax', '1','0xfde5380c','23');
+round3_step( 0,'%eax','%ebx','%ecx','%edx', '4','0xa4beea44', '4');
+round3_step( 0,'%edx','%eax','%ebx','%ecx', '7','0x4bdecfa9','11');
+round3_step( 0,'%ecx','%edx','%eax','%ebx','10','0xf6bb4b60','16');
+round3_step( 0,'%ebx','%ecx','%edx','%eax','13','0xbebfbc70','23');
+round3_step( 0,'%eax','%ebx','%ecx','%edx', '0','0x289b7ec6', '4');
+round3_step( 0,'%edx','%eax','%ebx','%ecx', '3','0xeaa127fa','11');
+round3_step( 0,'%ecx','%edx','%eax','%ebx', '6','0xd4ef3085','16');
+round3_step( 0,'%ebx','%ecx','%edx','%eax', '9', '0x4881d05','23');
+round3_step( 0,'%eax','%ebx','%ecx','%edx','12','0xd9d4d039', '4');
+round3_step( 0,'%edx','%eax','%ebx','%ecx','15','0xe6db99e5','11');
+round3_step( 0,'%ecx','%edx','%eax','%ebx', '2','0x1fa27cf8','16');
+round3_step( 1,'%ebx','%ecx','%edx','%eax', '0','0xc4ac5665','23');
+
+round4_step(-1,'%eax','%ebx','%ecx','%edx', '7','0xf4292244', '6');
+round4_step( 0,'%edx','%eax','%ebx','%ecx','14','0x432aff97','10');
+round4_step( 0,'%ecx','%edx','%eax','%ebx', '5','0xab9423a7','15');
+round4_step( 0,'%ebx','%ecx','%edx','%eax','12','0xfc93a039','21');
+round4_step( 0,'%eax','%ebx','%ecx','%edx', '3','0x655b59c3', '6');
+round4_step( 0,'%edx','%eax','%ebx','%ecx','10','0x8f0ccc92','10');
+round4_step( 0,'%ecx','%edx','%eax','%ebx', '1','0xffeff47d','15');
+round4_step( 0,'%ebx','%ecx','%edx','%eax', '8','0x85845dd1','21');
+round4_step( 0,'%eax','%ebx','%ecx','%edx','15','0x6fa87e4f', '6');
+round4_step( 0,'%edx','%eax','%ebx','%ecx', '6','0xfe2ce6e0','10');
+round4_step( 0,'%ecx','%edx','%eax','%ebx','13','0xa3014314','15');
+round4_step( 0,'%ebx','%ecx','%edx','%eax', '4','0x4e0811a1','21');
+round4_step( 0,'%eax','%ebx','%ecx','%edx','11','0xf7537e82', '6');
+round4_step( 0,'%edx','%eax','%ebx','%ecx', '2','0xbd3af235','10');
+round4_step( 0,'%ecx','%edx','%eax','%ebx', '9','0x2ad7d2bb','15');
+round4_step( 1,'%ebx','%ecx','%edx','%eax', '0','0xeb86d391','21');
+$code .= <<EOF;
+ # add old values of A, B, C, D
+ add %r8d, %eax
+ add %r9d, %ebx
+ add %r14d, %ecx
+ add %r15d, %edx
+
+ # loop control
+ add \$64, %rsi # ptr += 64
+ cmp %rdi, %rsi # cmp end with ptr
+ jb .Lloop # jmp if ptr < end
+ # END of loop over 16-word blocks
+
+.Lend:
+ mov %eax, 0*4(%rbp) # ctx->A = A
+ mov %ebx, 1*4(%rbp) # ctx->B = B
+ mov %ecx, 2*4(%rbp) # ctx->C = C
+ mov %edx, 3*4(%rbp) # ctx->D = D
+
+ mov (%rsp),%r15
+ mov 8(%rsp),%r14
+ mov 16(%rsp),%r12
+ mov 24(%rsp),%rbx
+ mov 32(%rsp),%rbp
+ add \$40,%rsp
+.Lepilogue:
+ ret
+.size md5_block_asm_data_order,.-md5_block_asm_data_order
+EOF
+
+# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
+# CONTEXT *context,DISPATCHER_CONTEXT *disp)
+if ($win64) {
+my $rec="%rcx";
+my $frame="%rdx";
+my $context="%r8";
+my $disp="%r9";
+
+$code.=<<___;
+.extern __imp_RtlVirtualUnwind
+.type se_handler,\@abi-omnipotent
+.align 16
+se_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 120($context),%rax # pull context->Rax
+ mov 248($context),%rbx # pull context->Rip
+
+ lea .Lprologue(%rip),%r10
+ cmp %r10,%rbx # context->Rip<.Lprologue
+ jb .Lin_prologue
+
+ mov 152($context),%rax # pull context->Rsp
+
+ lea .Lepilogue(%rip),%r10
+ cmp %r10,%rbx # context->Rip>=.Lepilogue
+ jae .Lin_prologue
+
+ lea 40(%rax),%rax
+
+ mov -8(%rax),%rbp
+ mov -16(%rax),%rbx
+ mov -24(%rax),%r12
+ mov -32(%rax),%r14
+ mov -40(%rax),%r15
+ mov %rbx,144($context) # restore context->Rbx
+ mov %rbp,160($context) # restore context->Rbp
+ mov %r12,216($context) # restore context->R12
+ mov %r14,232($context) # restore context->R14
+ mov %r15,240($context) # restore context->R15
+
+.Lin_prologue:
+ mov 8(%rax),%rdi
+ mov 16(%rax),%rsi
+ mov %rax,152($context) # restore context->Rsp
+ mov %rsi,168($context) # restore context->Rsi
+ mov %rdi,176($context) # restore context->Rdi
+
+ mov 40($disp),%rdi # disp->ContextRecord
+ mov $context,%rsi # context
+ mov \$154,%ecx # sizeof(CONTEXT)
+ .long 0xa548f3fc # cld; rep movsq
+
+ mov $disp,%rsi
+ xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER
+ mov 8(%rsi),%rdx # arg2, disp->ImageBase
+ mov 0(%rsi),%r8 # arg3, disp->ControlPc
+ mov 16(%rsi),%r9 # arg4, disp->FunctionEntry
+ mov 40(%rsi),%r10 # disp->ContextRecord
+ lea 56(%rsi),%r11 # &disp->HandlerData
+ lea 24(%rsi),%r12 # &disp->EstablisherFrame
+ mov %r10,32(%rsp) # arg5
+ mov %r11,40(%rsp) # arg6
+ mov %r12,48(%rsp) # arg7
+ mov %rcx,56(%rsp) # arg8, (NULL)
+ call *__imp_RtlVirtualUnwind(%rip)
+
+ mov \$1,%eax # ExceptionContinueSearch
+ add \$64,%rsp
+ popfq
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+ pop %rdi
+ pop %rsi
+ ret
+.size se_handler,.-se_handler
+
+.section .pdata
+.align 4
+ .rva .LSEH_begin_md5_block_asm_data_order
+ .rva .LSEH_end_md5_block_asm_data_order
+ .rva .LSEH_info_md5_block_asm_data_order
+
+.section .xdata
+.align 8
+.LSEH_info_md5_block_asm_data_order:
+ .byte 9,0,0,0
+ .rva se_handler
+___
+}
+
+print $code;
+
+close STDOUT;
diff --git a/crypto/md5/md5.c b/crypto/md5/md5.c
new file mode 100644
index 0000000..e20b86b
--- /dev/null
+++ b/crypto/md5/md5.c
@@ -0,0 +1,274 @@
+/* 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/md5.h>
+
+#include <string.h>
+
+#include <openssl/mem.h>
+
+
+uint8_t *MD5(const uint8_t *data, size_t len, uint8_t *out) {
+ MD5_CTX ctx;
+ static uint8_t digest[MD5_DIGEST_LENGTH];
+
+ /* TODO(fork): remove this static buffer. */
+ if (out == NULL) {
+ out = digest;
+ }
+
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, data, len);
+ MD5_Final(out, &ctx);
+
+ return out;
+}
+
+int MD5_Init(MD5_CTX *md5) {
+ memset(md5, 0, sizeof(MD5_CTX));
+ md5->A = 0x67452301UL;
+ md5->B = 0xefcdab89UL;
+ md5->C = 0x98badcfeUL;
+ md5->D = 0x10325476UL;
+ return 1;
+}
+
+#if !defined(OPENSSL_NO_ASM) && \
+ (defined(OPENSSL_X86_64) || defined(OPENSSL_X86))
+#define MD5_ASM
+#define md5_block_data_order md5_block_asm_data_order
+#endif
+
+
+void md5_block_data_order(MD5_CTX *md5, const void *p, size_t num);
+
+#define DATA_ORDER_IS_LITTLE_ENDIAN
+
+#define HASH_LONG uint32_t
+#define HASH_CTX MD5_CTX
+#define HASH_CBLOCK 64
+#define HASH_UPDATE MD5_Update
+#define HASH_TRANSFORM MD5_Transform
+#define HASH_FINAL MD5_Final
+#define HASH_MAKE_STRING(c, s) \
+ do { \
+ unsigned long ll; \
+ ll = (c)->A; \
+ (void) HOST_l2c(ll, (s)); \
+ ll = (c)->B; \
+ (void) HOST_l2c(ll, (s)); \
+ ll = (c)->C; \
+ (void) HOST_l2c(ll, (s)); \
+ ll = (c)->D; \
+ (void) HOST_l2c(ll, (s)); \
+ } while (0)
+#define HASH_BLOCK_DATA_ORDER md5_block_data_order
+
+#include "../digest/md32_common.h"
+
+/* As pointed out by Wei Dai <weidai@eskimo.com>, the above can be
+ * simplified to the code below. Wei attributes these optimizations
+ * to Peter Gutmann's SHS code, and he attributes it to Rich Schroeppel.
+ */
+#define F(b,c,d) ((((c) ^ (d)) & (b)) ^ (d))
+#define G(b,c,d) ((((b) ^ (c)) & (d)) ^ (c))
+#define H(b,c,d) ((b) ^ (c) ^ (d))
+#define I(b,c,d) (((~(d)) | (b)) ^ (c))
+
+#define R0(a,b,c,d,k,s,t) { \
+ a+=((k)+(t)+F((b),(c),(d))); \
+ a=ROTATE(a,s); \
+ a+=b; };\
+
+#define R1(a,b,c,d,k,s,t) { \
+ a+=((k)+(t)+G((b),(c),(d))); \
+ a=ROTATE(a,s); \
+ a+=b; };
+
+#define R2(a,b,c,d,k,s,t) { \
+ a+=((k)+(t)+H((b),(c),(d))); \
+ a=ROTATE(a,s); \
+ a+=b; };
+
+#define R3(a,b,c,d,k,s,t) { \
+ a+=((k)+(t)+I((b),(c),(d))); \
+ a=ROTATE(a,s); \
+ a+=b; };
+
+#ifndef md5_block_data_order
+#ifdef X
+#undef X
+#endif
+void md5_block_data_order(MD5_CTX *md5, const void *in_data, size_t num) {
+ const uint8_t *data = in_data;
+ uint32_t A, B, C, D, l;
+ uint32_t XX0, XX1, XX2, XX3, XX4, XX5, XX6, XX7, XX8, XX9, XX10, XX11, XX12,
+ XX13, XX14, XX15;
+#define X(i) XX##i
+
+ A = md5->A;
+ B = md5->B;
+ C = md5->C;
+ D = md5->D;
+
+ for (; num--;) {
+ HOST_c2l(data, l);
+ X(0) = l;
+ HOST_c2l(data, l);
+ X(1) = l;
+ /* Round 0 */
+ R0(A, B, C, D, X(0), 7, 0xd76aa478L);
+ HOST_c2l(data, l);
+ X(2) = l;
+ R0(D, A, B, C, X(1), 12, 0xe8c7b756L);
+ HOST_c2l(data, l);
+ X(3) = l;
+ R0(C, D, A, B, X(2), 17, 0x242070dbL);
+ HOST_c2l(data, l);
+ X(4) = l;
+ R0(B, C, D, A, X(3), 22, 0xc1bdceeeL);
+ HOST_c2l(data, l);
+ X(5) = l;
+ R0(A, B, C, D, X(4), 7, 0xf57c0fafL);
+ HOST_c2l(data, l);
+ X(6) = l;
+ R0(D, A, B, C, X(5), 12, 0x4787c62aL);
+ HOST_c2l(data, l);
+ X(7) = l;
+ R0(C, D, A, B, X(6), 17, 0xa8304613L);
+ HOST_c2l(data, l);
+ X(8) = l;
+ R0(B, C, D, A, X(7), 22, 0xfd469501L);
+ HOST_c2l(data, l);
+ X(9) = l;
+ R0(A, B, C, D, X(8), 7, 0x698098d8L);
+ HOST_c2l(data, l);
+ X(10) = l;
+ R0(D, A, B, C, X(9), 12, 0x8b44f7afL);
+ HOST_c2l(data, l);
+ X(11) = l;
+ R0(C, D, A, B, X(10), 17, 0xffff5bb1L);
+ HOST_c2l(data, l);
+ X(12) = l;
+ R0(B, C, D, A, X(11), 22, 0x895cd7beL);
+ HOST_c2l(data, l);
+ X(13) = l;
+ R0(A, B, C, D, X(12), 7, 0x6b901122L);
+ HOST_c2l(data, l);
+ X(14) = l;
+ R0(D, A, B, C, X(13), 12, 0xfd987193L);
+ HOST_c2l(data, l);
+ X(15) = l;
+ R0(C, D, A, B, X(14), 17, 0xa679438eL);
+ R0(B, C, D, A, X(15), 22, 0x49b40821L);
+ /* Round 1 */
+ R1(A, B, C, D, X(1), 5, 0xf61e2562L);
+ R1(D, A, B, C, X(6), 9, 0xc040b340L);
+ R1(C, D, A, B, X(11), 14, 0x265e5a51L);
+ R1(B, C, D, A, X(0), 20, 0xe9b6c7aaL);
+ R1(A, B, C, D, X(5), 5, 0xd62f105dL);
+ R1(D, A, B, C, X(10), 9, 0x02441453L);
+ R1(C, D, A, B, X(15), 14, 0xd8a1e681L);
+ R1(B, C, D, A, X(4), 20, 0xe7d3fbc8L);
+ R1(A, B, C, D, X(9), 5, 0x21e1cde6L);
+ R1(D, A, B, C, X(14), 9, 0xc33707d6L);
+ R1(C, D, A, B, X(3), 14, 0xf4d50d87L);
+ R1(B, C, D, A, X(8), 20, 0x455a14edL);
+ R1(A, B, C, D, X(13), 5, 0xa9e3e905L);
+ R1(D, A, B, C, X(2), 9, 0xfcefa3f8L);
+ R1(C, D, A, B, X(7), 14, 0x676f02d9L);
+ R1(B, C, D, A, X(12), 20, 0x8d2a4c8aL);
+ /* Round 2 */
+ R2(A, B, C, D, X(5), 4, 0xfffa3942L);
+ R2(D, A, B, C, X(8), 11, 0x8771f681L);
+ R2(C, D, A, B, X(11), 16, 0x6d9d6122L);
+ R2(B, C, D, A, X(14), 23, 0xfde5380cL);
+ R2(A, B, C, D, X(1), 4, 0xa4beea44L);
+ R2(D, A, B, C, X(4), 11, 0x4bdecfa9L);
+ R2(C, D, A, B, X(7), 16, 0xf6bb4b60L);
+ R2(B, C, D, A, X(10), 23, 0xbebfbc70L);
+ R2(A, B, C, D, X(13), 4, 0x289b7ec6L);
+ R2(D, A, B, C, X(0), 11, 0xeaa127faL);
+ R2(C, D, A, B, X(3), 16, 0xd4ef3085L);
+ R2(B, C, D, A, X(6), 23, 0x04881d05L);
+ R2(A, B, C, D, X(9), 4, 0xd9d4d039L);
+ R2(D, A, B, C, X(12), 11, 0xe6db99e5L);
+ R2(C, D, A, B, X(15), 16, 0x1fa27cf8L);
+ R2(B, C, D, A, X(2), 23, 0xc4ac5665L);
+ /* Round 3 */
+ R3(A, B, C, D, X(0), 6, 0xf4292244L);
+ R3(D, A, B, C, X(7), 10, 0x432aff97L);
+ R3(C, D, A, B, X(14), 15, 0xab9423a7L);
+ R3(B, C, D, A, X(5), 21, 0xfc93a039L);
+ R3(A, B, C, D, X(12), 6, 0x655b59c3L);
+ R3(D, A, B, C, X(3), 10, 0x8f0ccc92L);
+ R3(C, D, A, B, X(10), 15, 0xffeff47dL);
+ R3(B, C, D, A, X(1), 21, 0x85845dd1L);
+ R3(A, B, C, D, X(8), 6, 0x6fa87e4fL);
+ R3(D, A, B, C, X(15), 10, 0xfe2ce6e0L);
+ R3(C, D, A, B, X(6), 15, 0xa3014314L);
+ R3(B, C, D, A, X(13), 21, 0x4e0811a1L);
+ R3(A, B, C, D, X(4), 6, 0xf7537e82L);
+ R3(D, A, B, C, X(11), 10, 0xbd3af235L);
+ R3(C, D, A, B, X(2), 15, 0x2ad7d2bbL);
+ R3(B, C, D, A, X(9), 21, 0xeb86d391L);
+
+ A = md5->A += A;
+ B = md5->B += B;
+ C = md5->C += C;
+ D = md5->D += D;
+ }
+}
+#endif
diff --git a/crypto/md5/md5.h b/crypto/md5/md5.h
new file mode 100644
index 0000000..7a1a00f
--- /dev/null
+++ b/crypto/md5/md5.h
@@ -0,0 +1,106 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_MD5_H
+#define OPENSSL_HEADER_MD5_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* MD5. */
+
+
+/* MD5_CBLOCK is the block size of MD5. */
+#define MD5_CBLOCK 64
+
+/* MD5_DIGEST_LENGTH is the length of an MD5 digest. */
+#define MD5_DIGEST_LENGTH 16
+
+/* MD51_Init initialises |md5| and returns 1. */
+int MD5_Init(MD5_CTX *md5);
+
+/* MD5_Update adds |len| bytes from |data| to |md5| and returns one. */
+int MD5_Update(MD5_CTX *md5, const void *data, size_t len);
+
+/* MD5_Final adds the final padding to |md5| and writes the resulting digest to
+ * |md|, which must have at least |MD5_DIGEST_LENGTH| bytes of space. It
+ * returns one. */
+int MD5_Final(uint8_t *md, MD5_CTX *md5);
+
+/* MD5 writes the digest of |len| bytes from |data| to |out| and returns |out|.
+ * There must be at least |MD5_DIGEST_LENGTH| bytes of space in |out|. */
+uint8_t *MD5(const uint8_t *data, size_t len, uint8_t *out);
+
+/* MD5_Transform is a low-level function that performs a single, MD5 block
+ * transformation using the state from |md5| and 64 bytes from |block|. */
+void MD5_Transform(MD5_CTX *md5, const uint8_t *block);
+
+struct md5_state_st {
+ uint32_t A, B, C, D;
+ uint32_t Nl, Nh;
+ uint32_t data[16];
+ unsigned int num;
+};
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_MD5_H */
diff --git a/crypto/md5/md5_test.c b/crypto/md5/md5_test.c
new file mode 100644
index 0000000..eb5984c
--- /dev/null
+++ b/crypto/md5/md5_test.c
@@ -0,0 +1,100 @@
+/* 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/md5.h>
+#include <openssl/digest.h>
+
+
+static const char *const test[] = {
+ "", "a", "abc", "message digest", "abcdefghijklmnopqrstuvwxyz",
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ "12345678901234567890123456789012345678901234567890123456789012345678901234"
+ "567890",
+ NULL, };
+
+static const char *const expected[] = {
+ "d41d8cd98f00b204e9800998ecf8427e", "0cc175b9c0f1b6a831c399e269772661",
+ "900150983cd24fb0d6963f7d28e17f72", "f96b697d7cb7938d525a2f31aaf161d0",
+ "c3fcd3d76192e4007dfb496cca67e13b", "d174ab98d277d9f5a5611c2c9f419d9f",
+ "57edf4a22be3c955ac49da2e2107b67a", };
+
+int main(int argc, char **argv) {
+ size_t i, j;
+ uint8_t md[MD5_DIGEST_LENGTH];
+ char md_hex[sizeof(md) * 2 + 1];
+ int ok = 1;
+
+ for (i = 0; test[i] != NULL; i++) {
+ EVP_Digest(test[i], strlen(test[i]), md, NULL, EVP_md5(), NULL);
+ for (j = 0; j < sizeof(md); j++) {
+ sprintf(&md_hex[j * 2], "%02x", md[j]);
+ }
+ md_hex[MD5_DIGEST_LENGTH * 2] = 0;
+
+ if (strcmp(md_hex, expected[i]) != 0) {
+ fprintf(stderr, "#%u: got %s, wanted %s\n", (unsigned)i, md_hex,
+ expected[i]);
+ ok = 0;
+ }
+ }
+
+ if (ok) {
+ printf("PASS\n");
+ }
+
+ return ok ? 0 : 1;
+}
diff --git a/crypto/mem.c b/crypto/mem.c
new file mode 100644
index 0000000..8a8482c
--- /dev/null
+++ b/crypto/mem.c
@@ -0,0 +1,140 @@
+/* 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.] */
+
+#define _BSD_SOURCE /* needed for strdup, snprintf, vprintf etc */
+
+#include <openssl/mem.h>
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+
+void *OPENSSL_realloc_clean(void *ptr, size_t old_size, size_t new_size) {
+ void *ret = NULL;
+
+ if (ptr == NULL) {
+ return OPENSSL_malloc(new_size);
+ }
+
+ if (new_size == 0) {
+ return NULL;
+ }
+
+ /* We don't support shrinking the buffer. Note the memcpy that copies
+ * |old_size| bytes to the new buffer, below. */
+ if (new_size < old_size) {
+ return NULL;
+ }
+
+ ret = OPENSSL_malloc(new_size);
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ memcpy(ret, ptr, old_size);
+ OPENSSL_cleanse(ptr, old_size);
+ OPENSSL_free(ptr);
+ return ret;
+}
+
+int CRYPTO_memcmp(const void *in_a, const void *in_b, size_t len) {
+ size_t i;
+ const uint8_t *a = in_a;
+ const uint8_t *b = in_b;
+ uint8_t x = 0;
+
+ for (i = 0; i < len; i++) {
+ x |= a[i] ^ b[i];
+ }
+
+ return x;
+}
+
+uint32_t OPENSSL_hash32(const void *ptr, size_t len) {
+ /* These are the FNV-1a parameters for 32 bits. */
+ static const uint32_t kPrime = 16777619u;
+ static const uint32_t kOffsetBasis = 2166136261u;
+
+ const uint8_t *in = ptr;
+ size_t i;
+ uint32_t h = kOffsetBasis;
+
+ for (i = 0; i < len; i++) {
+ h ^= in[i];
+ h *= kPrime;
+ }
+
+ return h;
+}
+
+char *OPENSSL_strdup(const char *s) { return strdup(s); }
+
+int BIO_snprintf(char *buf, size_t n, const char *format, ...) {
+ va_list args;
+ int ret;
+
+ va_start(args, format);
+
+ ret = BIO_vsnprintf(buf, n, format, args);
+
+ va_end(args);
+ return ret;
+}
+
+int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args) {
+ return vsnprintf(buf, n, format, args);
+}
diff --git a/crypto/mem.h b/crypto/mem.h
new file mode 100644
index 0000000..134fef8
--- /dev/null
+++ b/crypto/mem.h
@@ -0,0 +1,126 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_MEM_H
+#define OPENSSL_HEADER_MEM_H
+
+#include <openssl/base.h>
+
+#include <stdarg.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* OpenSSL has, historically, had a complex set of malloc debugging options.
+ * However, that was written in a time before Valgrind and ASAN. Since we now
+ * have those tools, the OpenSSL allocation functions are simply macros around
+ * the standard memory functions. */
+
+
+#define OPENSSL_malloc malloc
+#define OPENSSL_realloc realloc
+#define OPENSSL_free free
+
+/* OPENSSL_realloc_clean acts like |realloc|, but clears the previous memory
+ * buffer. Because this is implemented as a wrapper around |malloc|, it needs
+ * to be given the size of the buffer pointed to by |ptr|. */
+void *OPENSSL_realloc_clean(void *ptr, size_t old_size, size_t new_size);
+
+/* OPENSSL_cleanse zeros out |len| bytes of memory at |ptr|. This is similar to
+ * |memset_s| from C11. */
+void OPENSSL_cleanse(void *ptr, size_t len);
+
+/* CRYPTO_memcmp returns zero iff the |len| bytes at |a| and |b| are equal. It
+ * takes an amount of time dependent on |len|, but independent of the contents
+ * of |a| and |b|. Unlike memcmp, it cannot be used to put elements into a
+ * defined order as the return value when a != b is undefined, other than to be
+ * non-zero. */
+int CRYPTO_memcmp(const void *a, const void *b, size_t len);
+
+/* OPENSSL_hash32 implements the 32 bit, FNV-1a hash. */
+uint32_t OPENSSL_hash32(const void *ptr, size_t len);
+
+/* OPENSSL_strdup has the same behaviour as strdup(3). */
+char *OPENSSL_strdup(const char *s);
+
+/* DECIMAL_SIZE returns an upper bound for the length of the decimal
+ * representation of the given type. */
+#define DECIMAL_SIZE(type) ((sizeof(type)*8+2)/3+1)
+
+/* Printf functions.
+ *
+ * These functions are either OpenSSL wrappers for standard functions (i.e.
+ * |BIO_snprintf| and |BIO_vsnprintf|) which don't exist in C89, or are
+ * versions of printf functions that output to a BIO rather than a FILE. */
+#ifdef __GNUC__
+#define __bio_h__attr__ __attribute__
+#else
+#define __bio_h__attr__(x)
+#endif
+int BIO_snprintf(char *buf, size_t n, const char *format, ...)
+ __bio_h__attr__((__format__(__printf__, 3, 4)));
+
+int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args)
+ __bio_h__attr__((__format__(__printf__, 3, 0)));
+#undef __bio_h__attr__
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_MEM_H */
diff --git a/crypto/mem_clear.c b/crypto/mem_clear.c
new file mode 100644
index 0000000..c13ecd8
--- /dev/null
+++ b/crypto/mem_clear.c
@@ -0,0 +1,69 @@
+/* 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/mem.h>
+
+#include <string.h>
+
+
+#if !defined(OPENSSL_X86)
+
+/* OPENSSL_cleanse is given its own compilation unit in the hopes that the
+ * compiler won't be able to optimise it away. */
+/* TODO(fork): this is fragile. Preferably we would be able to use memset_s
+ * on platforms with it. */
+void OPENSSL_cleanse(void *ptr, size_t len) { memset(ptr, 0, len); }
+
+#endif
diff --git a/crypto/modes/CMakeLists.txt b/crypto/modes/CMakeLists.txt
new file mode 100644
index 0000000..4b18e3a
--- /dev/null
+++ b/crypto/modes/CMakeLists.txt
@@ -0,0 +1,53 @@
+include_directories(. .. ../../include)
+
+if (${ARCH} STREQUAL "x86_64")
+ set(
+ MODES_ARCH_SOURCES
+
+ aesni-gcm-x86_64.${ASM_EXT}
+ ghash-x86_64.${ASM_EXT}
+ )
+endif()
+
+if (${ARCH} STREQUAL "x86")
+ set(
+ MODES_ARCH_SOURCES
+
+ ghash-x86.${ASM_EXT}
+ )
+endif()
+
+if (${ARCH} STREQUAL "arm")
+ set(
+ MODES_ARCH_SOURCES
+
+ ghash-armv4.${ASM_EXT}
+ )
+endif()
+
+add_library(
+ modes
+
+ OBJECT
+
+ cbc.c
+ ctr.c
+ ofb.c
+ cfb.c
+ gcm.c
+
+ ${MODES_ARCH_SOURCES}
+)
+
+perlasm(aesni-gcm-x86_64.${ASM_EXT} asm/aesni-gcm-x86_64.pl)
+perlasm(ghash-x86_64.${ASM_EXT} asm/ghash-x86_64.pl)
+perlasm(ghash-x86.${ASM_EXT} asm/ghash-x86.pl)
+perlasm(ghash-armv4.${ASM_EXT} asm/ghash-armv4.pl)
+
+add_executable(
+ gcm_test
+
+ gcm_test.c
+)
+
+target_link_libraries(gcm_test crypto)
diff --git a/crypto/modes/asm/aesni-gcm-x86_64.pl b/crypto/modes/asm/aesni-gcm-x86_64.pl
new file mode 100644
index 0000000..497b6e5
--- /dev/null
+++ b/crypto/modes/asm/aesni-gcm-x86_64.pl
@@ -0,0 +1,1050 @@
+#!/usr/bin/env perl
+#
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+#
+#
+# AES-NI-CTR+GHASH stitch.
+#
+# February 2013
+#
+# OpenSSL GCM implementation is organized in such way that its
+# performance is rather close to the sum of its streamed components,
+# in the context parallelized AES-NI CTR and modulo-scheduled
+# PCLMULQDQ-enabled GHASH. Unfortunately, as no stitch implementation
+# was observed to perform significantly better than the sum of the
+# components on contemporary CPUs, the effort was deemed impossible to
+# justify. This module is based on combination of Intel submissions,
+# [1] and [2], with MOVBE twist suggested by Ilya Albrekht and Max
+# Locktyukhin of Intel Corp. who verified that it reduces shuffles
+# pressure with notable relative improvement, achieving 1.0 cycle per
+# byte processed with 128-bit key on Haswell processor.
+#
+# [1] http://rt.openssl.org/Ticket/Display.html?id=2900&user=guest&pass=guest
+# [2] http://www.intel.com/content/dam/www/public/us/en/documents/software-support/enabling-high-performance-gcm.pdf
+
+$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";
+
+if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
+ =~ /GNU assembler version ([2-9]\.[0-9]+)/) {
+ $avx = ($1>=2.19) + ($1>=2.22);
+}
+
+if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
+ `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
+ $avx = ($1>=2.09) + ($1>=2.10);
+}
+
+if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
+ `ml64 2>&1` =~ /Version ([0-9]+)\./) {
+ $avx = ($1>=10) + ($1>=11);
+}
+
+open OUT,"| \"$^X\" $xlate $flavour $output";
+*STDOUT=*OUT;
+
+if ($avx>1) {{{
+
+($inp,$out,$len,$key,$ivp,$Xip)=("%rdi","%rsi","%rdx","%rcx","%r8","%r9");
+
+($Ii,$T1,$T2,$Hkey,
+ $Z0,$Z1,$Z2,$Z3,$Xi) = map("%xmm$_",(0..8));
+
+($inout0,$inout1,$inout2,$inout3,$inout4,$inout5,$rndkey) = map("%xmm$_",(9..15));
+
+($counter,$rounds,$ret,$const,$in0,$end0)=("%ebx","%ebp","%r10","%r11","%r14","%r15");
+
+$code=<<___;
+.text
+
+.type _aesni_ctr32_ghash_6x,\@abi-omnipotent
+.align 32
+_aesni_ctr32_ghash_6x:
+ vmovdqu 0x20($const),$T2 # borrow $T2, .Lone_msb
+ sub \$6,$len
+ vpxor $Z0,$Z0,$Z0 # $Z0 = 0
+ vmovdqu 0x00-0x80($key),$rndkey
+ vpaddb $T2,$T1,$inout1
+ vpaddb $T2,$inout1,$inout2
+ vpaddb $T2,$inout2,$inout3
+ vpaddb $T2,$inout3,$inout4
+ vpaddb $T2,$inout4,$inout5
+ vpxor $rndkey,$T1,$inout0
+ vmovdqu $Z0,16+8(%rsp) # "$Z3" = 0
+ jmp .Loop6x
+
+.align 32
+.Loop6x:
+ add \$100663296,$counter
+ jc .Lhandle_ctr32 # discard $inout[1-5]?
+ vmovdqu 0x00-0x20($Xip),$Hkey # $Hkey^1
+ vpaddb $T2,$inout5,$T1 # next counter value
+ vpxor $rndkey,$inout1,$inout1
+ vpxor $rndkey,$inout2,$inout2
+
+.Lresume_ctr32:
+ vmovdqu $T1,($ivp) # save next counter value
+ vpclmulqdq \$0x10,$Hkey,$Z3,$Z1
+ vpxor $rndkey,$inout3,$inout3
+ vmovups 0x10-0x80($key),$T2 # borrow $T2 for $rndkey
+ vpclmulqdq \$0x01,$Hkey,$Z3,$Z2
+ xor %r12,%r12
+ cmp $in0,$end0
+
+ vaesenc $T2,$inout0,$inout0
+ vmovdqu 0x30+8(%rsp),$Ii # I[4]
+ vpxor $rndkey,$inout4,$inout4
+ vpclmulqdq \$0x00,$Hkey,$Z3,$T1
+ vaesenc $T2,$inout1,$inout1
+ vpxor $rndkey,$inout5,$inout5
+ setnc %r12b
+ vpclmulqdq \$0x11,$Hkey,$Z3,$Z3
+ vaesenc $T2,$inout2,$inout2
+ vmovdqu 0x10-0x20($Xip),$Hkey # $Hkey^2
+ neg %r12
+ vaesenc $T2,$inout3,$inout3
+ vpxor $Z1,$Z2,$Z2
+ vpclmulqdq \$0x00,$Hkey,$Ii,$Z1
+ vpxor $Z0,$Xi,$Xi # modulo-scheduled
+ vaesenc $T2,$inout4,$inout4
+ vpxor $Z1,$T1,$Z0
+ and \$0x60,%r12
+ vmovups 0x20-0x80($key),$rndkey
+ vpclmulqdq \$0x10,$Hkey,$Ii,$T1
+ vaesenc $T2,$inout5,$inout5
+
+ vpclmulqdq \$0x01,$Hkey,$Ii,$T2
+ lea ($in0,%r12),$in0
+ vaesenc $rndkey,$inout0,$inout0
+ vpxor 16+8(%rsp),$Xi,$Xi # modulo-scheduled [vpxor $Z3,$Xi,$Xi]
+ vpclmulqdq \$0x11,$Hkey,$Ii,$Hkey
+ vmovdqu 0x40+8(%rsp),$Ii # I[3]
+ vaesenc $rndkey,$inout1,$inout1
+ movbe 0x58($in0),%r13
+ vaesenc $rndkey,$inout2,$inout2
+ movbe 0x50($in0),%r12
+ vaesenc $rndkey,$inout3,$inout3
+ mov %r13,0x20+8(%rsp)
+ vaesenc $rndkey,$inout4,$inout4
+ mov %r12,0x28+8(%rsp)
+ vmovdqu 0x30-0x20($Xip),$Z1 # borrow $Z1 for $Hkey^3
+ vaesenc $rndkey,$inout5,$inout5
+
+ vmovups 0x30-0x80($key),$rndkey
+ vpxor $T1,$Z2,$Z2
+ vpclmulqdq \$0x00,$Z1,$Ii,$T1
+ vaesenc $rndkey,$inout0,$inout0
+ vpxor $T2,$Z2,$Z2
+ vpclmulqdq \$0x10,$Z1,$Ii,$T2
+ vaesenc $rndkey,$inout1,$inout1
+ vpxor $Hkey,$Z3,$Z3
+ vpclmulqdq \$0x01,$Z1,$Ii,$Hkey
+ vaesenc $rndkey,$inout2,$inout2
+ vpclmulqdq \$0x11,$Z1,$Ii,$Z1
+ vmovdqu 0x50+8(%rsp),$Ii # I[2]
+ vaesenc $rndkey,$inout3,$inout3
+ vaesenc $rndkey,$inout4,$inout4
+ vpxor $T1,$Z0,$Z0
+ vmovdqu 0x40-0x20($Xip),$T1 # borrow $T1 for $Hkey^4
+ vaesenc $rndkey,$inout5,$inout5
+
+ vmovups 0x40-0x80($key),$rndkey
+ vpxor $T2,$Z2,$Z2
+ vpclmulqdq \$0x00,$T1,$Ii,$T2
+ vaesenc $rndkey,$inout0,$inout0
+ vpxor $Hkey,$Z2,$Z2
+ vpclmulqdq \$0x10,$T1,$Ii,$Hkey
+ vaesenc $rndkey,$inout1,$inout1
+ movbe 0x48($in0),%r13
+ vpxor $Z1,$Z3,$Z3
+ vpclmulqdq \$0x01,$T1,$Ii,$Z1
+ vaesenc $rndkey,$inout2,$inout2
+ movbe 0x40($in0),%r12
+ vpclmulqdq \$0x11,$T1,$Ii,$T1
+ vmovdqu 0x60+8(%rsp),$Ii # I[1]
+ vaesenc $rndkey,$inout3,$inout3
+ mov %r13,0x30+8(%rsp)
+ vaesenc $rndkey,$inout4,$inout4
+ mov %r12,0x38+8(%rsp)
+ vpxor $T2,$Z0,$Z0
+ vmovdqu 0x60-0x20($Xip),$T2 # borrow $T2 for $Hkey^5
+ vaesenc $rndkey,$inout5,$inout5
+
+ vmovups 0x50-0x80($key),$rndkey
+ vpxor $Hkey,$Z2,$Z2
+ vpclmulqdq \$0x00,$T2,$Ii,$Hkey
+ vaesenc $rndkey,$inout0,$inout0
+ vpxor $Z1,$Z2,$Z2
+ vpclmulqdq \$0x10,$T2,$Ii,$Z1
+ vaesenc $rndkey,$inout1,$inout1
+ movbe 0x38($in0),%r13
+ vpxor $T1,$Z3,$Z3
+ vpclmulqdq \$0x01,$T2,$Ii,$T1
+ vpxor 0x70+8(%rsp),$Xi,$Xi # accumulate I[0]
+ vaesenc $rndkey,$inout2,$inout2
+ movbe 0x30($in0),%r12
+ vpclmulqdq \$0x11,$T2,$Ii,$T2
+ vaesenc $rndkey,$inout3,$inout3
+ mov %r13,0x40+8(%rsp)
+ vaesenc $rndkey,$inout4,$inout4
+ mov %r12,0x48+8(%rsp)
+ vpxor $Hkey,$Z0,$Z0
+ vmovdqu 0x70-0x20($Xip),$Hkey # $Hkey^6
+ vaesenc $rndkey,$inout5,$inout5
+
+ vmovups 0x60-0x80($key),$rndkey
+ vpxor $Z1,$Z2,$Z2
+ vpclmulqdq \$0x10,$Hkey,$Xi,$Z1
+ vaesenc $rndkey,$inout0,$inout0
+ vpxor $T1,$Z2,$Z2
+ vpclmulqdq \$0x01,$Hkey,$Xi,$T1
+ vaesenc $rndkey,$inout1,$inout1
+ movbe 0x28($in0),%r13
+ vpxor $T2,$Z3,$Z3
+ vpclmulqdq \$0x00,$Hkey,$Xi,$T2
+ vaesenc $rndkey,$inout2,$inout2
+ movbe 0x20($in0),%r12
+ vpclmulqdq \$0x11,$Hkey,$Xi,$Xi
+ vaesenc $rndkey,$inout3,$inout3
+ mov %r13,0x50+8(%rsp)
+ vaesenc $rndkey,$inout4,$inout4
+ mov %r12,0x58+8(%rsp)
+ vpxor $Z1,$Z2,$Z2
+ vaesenc $rndkey,$inout5,$inout5
+ vpxor $T1,$Z2,$Z2
+
+ vmovups 0x70-0x80($key),$rndkey
+ vpslldq \$8,$Z2,$Z1
+ vpxor $T2,$Z0,$Z0
+ vmovdqu 0x10($const),$Hkey # .Lpoly
+
+ vaesenc $rndkey,$inout0,$inout0
+ vpxor $Xi,$Z3,$Z3
+ vaesenc $rndkey,$inout1,$inout1
+ vpxor $Z1,$Z0,$Z0
+ movbe 0x18($in0),%r13
+ vaesenc $rndkey,$inout2,$inout2
+ movbe 0x10($in0),%r12
+ vpalignr \$8,$Z0,$Z0,$Ii # 1st phase
+ vpclmulqdq \$0x10,$Hkey,$Z0,$Z0
+ mov %r13,0x60+8(%rsp)
+ vaesenc $rndkey,$inout3,$inout3
+ mov %r12,0x68+8(%rsp)
+ vaesenc $rndkey,$inout4,$inout4
+ vmovups 0x80-0x80($key),$T1 # borrow $T1 for $rndkey
+ vaesenc $rndkey,$inout5,$inout5
+
+ vaesenc $T1,$inout0,$inout0
+ vmovups 0x90-0x80($key),$rndkey
+ vaesenc $T1,$inout1,$inout1
+ vpsrldq \$8,$Z2,$Z2
+ vaesenc $T1,$inout2,$inout2
+ vpxor $Z2,$Z3,$Z3
+ vaesenc $T1,$inout3,$inout3
+ vpxor $Ii,$Z0,$Z0
+ movbe 0x08($in0),%r13
+ vaesenc $T1,$inout4,$inout4
+ movbe 0x00($in0),%r12
+ vaesenc $T1,$inout5,$inout5
+ vmovups 0xa0-0x80($key),$T1
+ cmp \$11,$rounds
+ jb .Lenc_tail # 128-bit key
+
+ vaesenc $rndkey,$inout0,$inout0
+ vaesenc $rndkey,$inout1,$inout1
+ vaesenc $rndkey,$inout2,$inout2
+ vaesenc $rndkey,$inout3,$inout3
+ vaesenc $rndkey,$inout4,$inout4
+ vaesenc $rndkey,$inout5,$inout5
+
+ vaesenc $T1,$inout0,$inout0
+ vaesenc $T1,$inout1,$inout1
+ vaesenc $T1,$inout2,$inout2
+ vaesenc $T1,$inout3,$inout3
+ vaesenc $T1,$inout4,$inout4
+ vmovups 0xb0-0x80($key),$rndkey
+ vaesenc $T1,$inout5,$inout5
+ vmovups 0xc0-0x80($key),$T1
+ je .Lenc_tail # 192-bit key
+
+ vaesenc $rndkey,$inout0,$inout0
+ vaesenc $rndkey,$inout1,$inout1
+ vaesenc $rndkey,$inout2,$inout2
+ vaesenc $rndkey,$inout3,$inout3
+ vaesenc $rndkey,$inout4,$inout4
+ vaesenc $rndkey,$inout5,$inout5
+
+ vaesenc $T1,$inout0,$inout0
+ vaesenc $T1,$inout1,$inout1
+ vaesenc $T1,$inout2,$inout2
+ vaesenc $T1,$inout3,$inout3
+ vaesenc $T1,$inout4,$inout4
+ vmovups 0xd0-0x80($key),$rndkey
+ vaesenc $T1,$inout5,$inout5
+ vmovups 0xe0-0x80($key),$T1
+ jmp .Lenc_tail # 256-bit key
+
+.align 32
+.Lhandle_ctr32:
+ vmovdqu ($const),$Ii # borrow $Ii for .Lbswap_mask
+ vpshufb $Ii,$T1,$Z2 # byte-swap counter
+ vmovdqu 0x30($const),$Z1 # borrow $Z1, .Ltwo_lsb
+ vpaddd 0x40($const),$Z2,$inout1 # .Lone_lsb
+ vpaddd $Z1,$Z2,$inout2
+ vmovdqu 0x00-0x20($Xip),$Hkey # $Hkey^1
+ vpaddd $Z1,$inout1,$inout3
+ vpshufb $Ii,$inout1,$inout1
+ vpaddd $Z1,$inout2,$inout4
+ vpshufb $Ii,$inout2,$inout2
+ vpxor $rndkey,$inout1,$inout1
+ vpaddd $Z1,$inout3,$inout5
+ vpshufb $Ii,$inout3,$inout3
+ vpxor $rndkey,$inout2,$inout2
+ vpaddd $Z1,$inout4,$T1 # byte-swapped next counter value
+ vpshufb $Ii,$inout4,$inout4
+ vpshufb $Ii,$inout5,$inout5
+ vpshufb $Ii,$T1,$T1 # next counter value
+ jmp .Lresume_ctr32
+
+.align 32
+.Lenc_tail:
+ vaesenc $rndkey,$inout0,$inout0
+ vmovdqu $Z3,16+8(%rsp) # postpone vpxor $Z3,$Xi,$Xi
+ vpalignr \$8,$Z0,$Z0,$Xi # 2nd phase
+ vaesenc $rndkey,$inout1,$inout1
+ vpclmulqdq \$0x10,$Hkey,$Z0,$Z0
+ vpxor 0x00($inp),$T1,$T2
+ vaesenc $rndkey,$inout2,$inout2
+ vpxor 0x10($inp),$T1,$Ii
+ vaesenc $rndkey,$inout3,$inout3
+ vpxor 0x20($inp),$T1,$Z1
+ vaesenc $rndkey,$inout4,$inout4
+ vpxor 0x30($inp),$T1,$Z2
+ vaesenc $rndkey,$inout5,$inout5
+ vpxor 0x40($inp),$T1,$Z3
+ vpxor 0x50($inp),$T1,$Hkey
+ vmovdqu ($ivp),$T1 # load next counter value
+
+ vaesenclast $T2,$inout0,$inout0
+ vmovdqu 0x20($const),$T2 # borrow $T2, .Lone_msb
+ vaesenclast $Ii,$inout1,$inout1
+ vpaddb $T2,$T1,$Ii
+ mov %r13,0x70+8(%rsp)
+ lea 0x60($inp),$inp
+ vaesenclast $Z1,$inout2,$inout2
+ vpaddb $T2,$Ii,$Z1
+ mov %r12,0x78+8(%rsp)
+ lea 0x60($out),$out
+ vmovdqu 0x00-0x80($key),$rndkey
+ vaesenclast $Z2,$inout3,$inout3
+ vpaddb $T2,$Z1,$Z2
+ vaesenclast $Z3, $inout4,$inout4
+ vpaddb $T2,$Z2,$Z3
+ vaesenclast $Hkey,$inout5,$inout5
+ vpaddb $T2,$Z3,$Hkey
+
+ add \$0x60,$ret
+ sub \$0x6,$len
+ jc .L6x_done
+
+ vmovups $inout0,-0x60($out) # save output
+ vpxor $rndkey,$T1,$inout0
+ vmovups $inout1,-0x50($out)
+ vmovdqa $Ii,$inout1 # 0 latency
+ vmovups $inout2,-0x40($out)
+ vmovdqa $Z1,$inout2 # 0 latency
+ vmovups $inout3,-0x30($out)
+ vmovdqa $Z2,$inout3 # 0 latency
+ vmovups $inout4,-0x20($out)
+ vmovdqa $Z3,$inout4 # 0 latency
+ vmovups $inout5,-0x10($out)
+ vmovdqa $Hkey,$inout5 # 0 latency
+ vmovdqu 0x20+8(%rsp),$Z3 # I[5]
+ jmp .Loop6x
+
+.L6x_done:
+ vpxor 16+8(%rsp),$Xi,$Xi # modulo-scheduled
+ vpxor $Z0,$Xi,$Xi # modulo-scheduled
+
+ ret
+.size _aesni_ctr32_ghash_6x,.-_aesni_ctr32_ghash_6x
+___
+######################################################################
+#
+# size_t aesni_gcm_[en|de]crypt(const void *inp, void *out, size_t len,
+# const AES_KEY *key, unsigned char iv[16],
+# struct { u128 Xi,H,Htbl[9]; } *Xip);
+$code.=<<___;
+.globl aesni_gcm_decrypt
+.type aesni_gcm_decrypt,\@function,6
+.align 32
+aesni_gcm_decrypt:
+ xor $ret,$ret
+ cmp \$0x60,$len # minimal accepted length
+ jb .Lgcm_dec_abort
+
+ lea (%rsp),%rax # save stack pointer
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+___
+$code.=<<___ if ($win64);
+ lea -0xa8(%rsp),%rsp
+ movaps %xmm6,-0xd8(%rax)
+ movaps %xmm7,-0xc8(%rax)
+ movaps %xmm8,-0xb8(%rax)
+ movaps %xmm9,-0xa8(%rax)
+ movaps %xmm10,-0x98(%rax)
+ movaps %xmm11,-0x88(%rax)
+ movaps %xmm12,-0x78(%rax)
+ movaps %xmm13,-0x68(%rax)
+ movaps %xmm14,-0x58(%rax)
+ movaps %xmm15,-0x48(%rax)
+.Lgcm_dec_body:
+___
+$code.=<<___;
+ vzeroupper
+
+ vmovdqu ($ivp),$T1 # input counter value
+ add \$-128,%rsp
+ mov 12($ivp),$counter
+ lea .Lbswap_mask(%rip),$const
+ lea -0x80($key),$in0 # borrow $in0
+ mov \$0xf80,$end0 # borrow $end0
+ vmovdqu ($Xip),$Xi # load Xi
+ and \$-128,%rsp # ensure stack alignment
+ vmovdqu ($const),$Ii # borrow $Ii for .Lbswap_mask
+ lea 0x80($key),$key # size optimization
+ lea 0x20+0x20($Xip),$Xip # size optimization
+ mov 0xf0-0x80($key),$rounds
+ vpshufb $Ii,$Xi,$Xi
+
+ and $end0,$in0
+ and %rsp,$end0
+ sub $in0,$end0
+ jc .Ldec_no_key_aliasing
+ cmp \$768,$end0
+ jnc .Ldec_no_key_aliasing
+ sub $end0,%rsp # avoid aliasing with key
+.Ldec_no_key_aliasing:
+
+ vmovdqu 0x50($inp),$Z3 # I[5]
+ lea ($inp),$in0
+ vmovdqu 0x40($inp),$Z0
+ lea -0xc0($inp,$len),$end0
+ vmovdqu 0x30($inp),$Z1
+ shr \$4,$len
+ xor $ret,$ret
+ vmovdqu 0x20($inp),$Z2
+ vpshufb $Ii,$Z3,$Z3 # passed to _aesni_ctr32_ghash_6x
+ vmovdqu 0x10($inp),$T2
+ vpshufb $Ii,$Z0,$Z0
+ vmovdqu ($inp),$Hkey
+ vpshufb $Ii,$Z1,$Z1
+ vmovdqu $Z0,0x30(%rsp)
+ vpshufb $Ii,$Z2,$Z2
+ vmovdqu $Z1,0x40(%rsp)
+ vpshufb $Ii,$T2,$T2
+ vmovdqu $Z2,0x50(%rsp)
+ vpshufb $Ii,$Hkey,$Hkey
+ vmovdqu $T2,0x60(%rsp)
+ vmovdqu $Hkey,0x70(%rsp)
+
+ call _aesni_ctr32_ghash_6x
+
+ vmovups $inout0,-0x60($out) # save output
+ vmovups $inout1,-0x50($out)
+ vmovups $inout2,-0x40($out)
+ vmovups $inout3,-0x30($out)
+ vmovups $inout4,-0x20($out)
+ vmovups $inout5,-0x10($out)
+
+ vpshufb ($const),$Xi,$Xi # .Lbswap_mask
+ vmovdqu $Xi,-0x40($Xip) # output Xi
+
+ vzeroupper
+___
+$code.=<<___ if ($win64);
+ movaps -0xd8(%rax),%xmm6
+ movaps -0xd8(%rax),%xmm7
+ movaps -0xb8(%rax),%xmm8
+ movaps -0xa8(%rax),%xmm9
+ movaps -0x98(%rax),%xmm10
+ movaps -0x88(%rax),%xmm11
+ movaps -0x78(%rax),%xmm12
+ movaps -0x68(%rax),%xmm13
+ movaps -0x58(%rax),%xmm14
+ movaps -0x48(%rax),%xmm15
+___
+$code.=<<___;
+ mov -48(%rax),%r15
+ mov -40(%rax),%r14
+ mov -32(%rax),%r13
+ mov -24(%rax),%r12
+ mov -16(%rax),%rbp
+ mov -8(%rax),%rbx
+ lea (%rax),%rsp # restore %rsp
+.Lgcm_dec_abort:
+ mov $ret,%rax # return value
+ ret
+.size aesni_gcm_decrypt,.-aesni_gcm_decrypt
+___
+
+$code.=<<___;
+.type _aesni_ctr32_6x,\@abi-omnipotent
+.align 32
+_aesni_ctr32_6x:
+ vmovdqu 0x00-0x80($key),$Z0 # borrow $Z0 for $rndkey
+ vmovdqu 0x20($const),$T2 # borrow $T2, .Lone_msb
+ lea -1($rounds),%r13
+ vmovups 0x10-0x80($key),$rndkey
+ lea 0x20-0x80($key),%r12
+ vpxor $Z0,$T1,$inout0
+ add \$100663296,$counter
+ jc .Lhandle_ctr32_2
+ vpaddb $T2,$T1,$inout1
+ vpaddb $T2,$inout1,$inout2
+ vpxor $Z0,$inout1,$inout1
+ vpaddb $T2,$inout2,$inout3
+ vpxor $Z0,$inout2,$inout2
+ vpaddb $T2,$inout3,$inout4
+ vpxor $Z0,$inout3,$inout3
+ vpaddb $T2,$inout4,$inout5
+ vpxor $Z0,$inout4,$inout4
+ vpaddb $T2,$inout5,$T1
+ vpxor $Z0,$inout5,$inout5
+ jmp .Loop_ctr32
+
+.align 16
+.Loop_ctr32:
+ vaesenc $rndkey,$inout0,$inout0
+ vaesenc $rndkey,$inout1,$inout1
+ vaesenc $rndkey,$inout2,$inout2
+ vaesenc $rndkey,$inout3,$inout3
+ vaesenc $rndkey,$inout4,$inout4
+ vaesenc $rndkey,$inout5,$inout5
+ vmovups (%r12),$rndkey
+ lea 0x10(%r12),%r12
+ dec %r13d
+ jnz .Loop_ctr32
+
+ vmovdqu (%r12),$Hkey # last round key
+ vaesenc $rndkey,$inout0,$inout0
+ vpxor 0x00($inp),$Hkey,$Z0
+ vaesenc $rndkey,$inout1,$inout1
+ vpxor 0x10($inp),$Hkey,$Z1
+ vaesenc $rndkey,$inout2,$inout2
+ vpxor 0x20($inp),$Hkey,$Z2
+ vaesenc $rndkey,$inout3,$inout3
+ vpxor 0x30($inp),$Hkey,$Xi
+ vaesenc $rndkey,$inout4,$inout4
+ vpxor 0x40($inp),$Hkey,$T2
+ vaesenc $rndkey,$inout5,$inout5
+ vpxor 0x50($inp),$Hkey,$Hkey
+ lea 0x60($inp),$inp
+
+ vaesenclast $Z0,$inout0,$inout0
+ vaesenclast $Z1,$inout1,$inout1
+ vaesenclast $Z2,$inout2,$inout2
+ vaesenclast $Xi,$inout3,$inout3
+ vaesenclast $T2,$inout4,$inout4
+ vaesenclast $Hkey,$inout5,$inout5
+ vmovups $inout0,0x00($out)
+ vmovups $inout1,0x10($out)
+ vmovups $inout2,0x20($out)
+ vmovups $inout3,0x30($out)
+ vmovups $inout4,0x40($out)
+ vmovups $inout5,0x50($out)
+ lea 0x60($out),$out
+
+ ret
+.align 32
+.Lhandle_ctr32_2:
+ vpshufb $Ii,$T1,$Z2 # byte-swap counter
+ vmovdqu 0x30($const),$Z1 # borrow $Z1, .Ltwo_lsb
+ vpaddd 0x40($const),$Z2,$inout1 # .Lone_lsb
+ vpaddd $Z1,$Z2,$inout2
+ vpaddd $Z1,$inout1,$inout3
+ vpshufb $Ii,$inout1,$inout1
+ vpaddd $Z1,$inout2,$inout4
+ vpshufb $Ii,$inout2,$inout2
+ vpxor $Z0,$inout1,$inout1
+ vpaddd $Z1,$inout3,$inout5
+ vpshufb $Ii,$inout3,$inout3
+ vpxor $Z0,$inout2,$inout2
+ vpaddd $Z1,$inout4,$T1 # byte-swapped next counter value
+ vpshufb $Ii,$inout4,$inout4
+ vpxor $Z0,$inout3,$inout3
+ vpshufb $Ii,$inout5,$inout5
+ vpxor $Z0,$inout4,$inout4
+ vpshufb $Ii,$T1,$T1 # next counter value
+ vpxor $Z0,$inout5,$inout5
+ jmp .Loop_ctr32
+.size _aesni_ctr32_6x,.-_aesni_ctr32_6x
+
+.globl aesni_gcm_encrypt
+.type aesni_gcm_encrypt,\@function,6
+.align 32
+aesni_gcm_encrypt:
+ xor $ret,$ret
+ cmp \$0x60*3,$len # minimal accepted length
+ jb .Lgcm_enc_abort
+
+ lea (%rsp),%rax # save stack pointer
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+___
+$code.=<<___ if ($win64);
+ lea -0xa8(%rsp),%rsp
+ movaps %xmm6,-0xd8(%rax)
+ movaps %xmm7,-0xc8(%rax)
+ movaps %xmm8,-0xb8(%rax)
+ movaps %xmm9,-0xa8(%rax)
+ movaps %xmm10,-0x98(%rax)
+ movaps %xmm11,-0x88(%rax)
+ movaps %xmm12,-0x78(%rax)
+ movaps %xmm13,-0x68(%rax)
+ movaps %xmm14,-0x58(%rax)
+ movaps %xmm15,-0x48(%rax)
+.Lgcm_enc_body:
+___
+$code.=<<___;
+ vzeroupper
+
+ vmovdqu ($ivp),$T1 # input counter value
+ add \$-128,%rsp
+ mov 12($ivp),$counter
+ lea .Lbswap_mask(%rip),$const
+ lea -0x80($key),$in0 # borrow $in0
+ mov \$0xf80,$end0 # borrow $end0
+ lea 0x80($key),$key # size optimization
+ vmovdqu ($const),$Ii # borrow $Ii for .Lbswap_mask
+ and \$-128,%rsp # ensure stack alignment
+ mov 0xf0-0x80($key),$rounds
+
+ and $end0,$in0
+ and %rsp,$end0
+ sub $in0,$end0
+ jc .Lenc_no_key_aliasing
+ cmp \$768,$end0
+ jnc .Lenc_no_key_aliasing
+ sub $end0,%rsp # avoid aliasing with key
+.Lenc_no_key_aliasing:
+
+ lea ($out),$in0
+ lea -0xc0($out,$len),$end0
+ shr \$4,$len
+
+ call _aesni_ctr32_6x
+ vpshufb $Ii,$inout0,$Xi # save bswapped output on stack
+ vpshufb $Ii,$inout1,$T2
+ vmovdqu $Xi,0x70(%rsp)
+ vpshufb $Ii,$inout2,$Z0
+ vmovdqu $T2,0x60(%rsp)
+ vpshufb $Ii,$inout3,$Z1
+ vmovdqu $Z0,0x50(%rsp)
+ vpshufb $Ii,$inout4,$Z2
+ vmovdqu $Z1,0x40(%rsp)
+ vpshufb $Ii,$inout5,$Z3 # passed to _aesni_ctr32_ghash_6x
+ vmovdqu $Z2,0x30(%rsp)
+
+ call _aesni_ctr32_6x
+
+ vmovdqu ($Xip),$Xi # load Xi
+ lea 0x20+0x20($Xip),$Xip # size optimization
+ sub \$12,$len
+ mov \$0x60*2,$ret
+ vpshufb $Ii,$Xi,$Xi
+
+ call _aesni_ctr32_ghash_6x
+ vmovdqu 0x20(%rsp),$Z3 # I[5]
+ vmovdqu ($const),$Ii # borrow $Ii for .Lbswap_mask
+ vmovdqu 0x00-0x20($Xip),$Hkey # $Hkey^1
+ vpunpckhqdq $Z3,$Z3,$T1
+ vmovdqu 0x20-0x20($Xip),$rndkey # borrow $rndkey for $HK
+ vmovups $inout0,-0x60($out) # save output
+ vpshufb $Ii,$inout0,$inout0 # but keep bswapped copy
+ vpxor $Z3,$T1,$T1
+ vmovups $inout1,-0x50($out)
+ vpshufb $Ii,$inout1,$inout1
+ vmovups $inout2,-0x40($out)
+ vpshufb $Ii,$inout2,$inout2
+ vmovups $inout3,-0x30($out)
+ vpshufb $Ii,$inout3,$inout3
+ vmovups $inout4,-0x20($out)
+ vpshufb $Ii,$inout4,$inout4
+ vmovups $inout5,-0x10($out)
+ vpshufb $Ii,$inout5,$inout5
+ vmovdqu $inout0,0x10(%rsp) # free $inout0
+___
+{ my ($HK,$T3)=($rndkey,$inout0);
+
+$code.=<<___;
+ vmovdqu 0x30(%rsp),$Z2 # I[4]
+ vmovdqu 0x10-0x20($Xip),$Ii # borrow $Ii for $Hkey^2
+ vpunpckhqdq $Z2,$Z2,$T2
+ vpclmulqdq \$0x00,$Hkey,$Z3,$Z1
+ vpxor $Z2,$T2,$T2
+ vpclmulqdq \$0x11,$Hkey,$Z3,$Z3
+ vpclmulqdq \$0x00,$HK,$T1,$T1
+
+ vmovdqu 0x40(%rsp),$T3 # I[3]
+ vpclmulqdq \$0x00,$Ii,$Z2,$Z0
+ vmovdqu 0x30-0x20($Xip),$Hkey # $Hkey^3
+ vpxor $Z1,$Z0,$Z0
+ vpunpckhqdq $T3,$T3,$Z1
+ vpclmulqdq \$0x11,$Ii,$Z2,$Z2
+ vpxor $T3,$Z1,$Z1
+ vpxor $Z3,$Z2,$Z2
+ vpclmulqdq \$0x10,$HK,$T2,$T2
+ vmovdqu 0x50-0x20($Xip),$HK
+ vpxor $T1,$T2,$T2
+
+ vmovdqu 0x50(%rsp),$T1 # I[2]
+ vpclmulqdq \$0x00,$Hkey,$T3,$Z3
+ vmovdqu 0x40-0x20($Xip),$Ii # borrow $Ii for $Hkey^4
+ vpxor $Z0,$Z3,$Z3
+ vpunpckhqdq $T1,$T1,$Z0
+ vpclmulqdq \$0x11,$Hkey,$T3,$T3
+ vpxor $T1,$Z0,$Z0
+ vpxor $Z2,$T3,$T3
+ vpclmulqdq \$0x00,$HK,$Z1,$Z1
+ vpxor $T2,$Z1,$Z1
+
+ vmovdqu 0x60(%rsp),$T2 # I[1]
+ vpclmulqdq \$0x00,$Ii,$T1,$Z2
+ vmovdqu 0x60-0x20($Xip),$Hkey # $Hkey^5
+ vpxor $Z3,$Z2,$Z2
+ vpunpckhqdq $T2,$T2,$Z3
+ vpclmulqdq \$0x11,$Ii,$T1,$T1
+ vpxor $T2,$Z3,$Z3
+ vpxor $T3,$T1,$T1
+ vpclmulqdq \$0x10,$HK,$Z0,$Z0
+ vmovdqu 0x80-0x20($Xip),$HK
+ vpxor $Z1,$Z0,$Z0
+
+ vpxor 0x70(%rsp),$Xi,$Xi # accumulate I[0]
+ vpclmulqdq \$0x00,$Hkey,$T2,$Z1
+ vmovdqu 0x70-0x20($Xip),$Ii # borrow $Ii for $Hkey^6
+ vpunpckhqdq $Xi,$Xi,$T3
+ vpxor $Z2,$Z1,$Z1
+ vpclmulqdq \$0x11,$Hkey,$T2,$T2
+ vpxor $Xi,$T3,$T3
+ vpxor $T1,$T2,$T2
+ vpclmulqdq \$0x00,$HK,$Z3,$Z3
+ vpxor $Z0,$Z3,$Z0
+
+ vpclmulqdq \$0x00,$Ii,$Xi,$Z2
+ vmovdqu 0x00-0x20($Xip),$Hkey # $Hkey^1
+ vpunpckhqdq $inout5,$inout5,$T1
+ vpclmulqdq \$0x11,$Ii,$Xi,$Xi
+ vpxor $inout5,$T1,$T1
+ vpxor $Z1,$Z2,$Z1
+ vpclmulqdq \$0x10,$HK,$T3,$T3
+ vmovdqu 0x20-0x20($Xip),$HK
+ vpxor $T2,$Xi,$Z3
+ vpxor $Z0,$T3,$Z2
+
+ vmovdqu 0x10-0x20($Xip),$Ii # borrow $Ii for $Hkey^2
+ vpxor $Z1,$Z3,$T3 # aggregated Karatsuba post-processing
+ vpclmulqdq \$0x00,$Hkey,$inout5,$Z0
+ vpxor $T3,$Z2,$Z2
+ vpunpckhqdq $inout4,$inout4,$T2
+ vpclmulqdq \$0x11,$Hkey,$inout5,$inout5
+ vpxor $inout4,$T2,$T2
+ vpslldq \$8,$Z2,$T3
+ vpclmulqdq \$0x00,$HK,$T1,$T1
+ vpxor $T3,$Z1,$Xi
+ vpsrldq \$8,$Z2,$Z2
+ vpxor $Z2,$Z3,$Z3
+
+ vpclmulqdq \$0x00,$Ii,$inout4,$Z1
+ vmovdqu 0x30-0x20($Xip),$Hkey # $Hkey^3
+ vpxor $Z0,$Z1,$Z1
+ vpunpckhqdq $inout3,$inout3,$T3
+ vpclmulqdq \$0x11,$Ii,$inout4,$inout4
+ vpxor $inout3,$T3,$T3
+ vpxor $inout5,$inout4,$inout4
+ vpalignr \$8,$Xi,$Xi,$inout5 # 1st phase
+ vpclmulqdq \$0x10,$HK,$T2,$T2
+ vmovdqu 0x50-0x20($Xip),$HK
+ vpxor $T1,$T2,$T2
+
+ vpclmulqdq \$0x00,$Hkey,$inout3,$Z0
+ vmovdqu 0x40-0x20($Xip),$Ii # borrow $Ii for $Hkey^4
+ vpxor $Z1,$Z0,$Z0
+ vpunpckhqdq $inout2,$inout2,$T1
+ vpclmulqdq \$0x11,$Hkey,$inout3,$inout3
+ vpxor $inout2,$T1,$T1
+ vpxor $inout4,$inout3,$inout3
+ vxorps 0x10(%rsp),$Z3,$Z3 # accumulate $inout0
+ vpclmulqdq \$0x00,$HK,$T3,$T3
+ vpxor $T2,$T3,$T3
+
+ vpclmulqdq \$0x10,0x10($const),$Xi,$Xi
+ vxorps $inout5,$Xi,$Xi
+
+ vpclmulqdq \$0x00,$Ii,$inout2,$Z1
+ vmovdqu 0x60-0x20($Xip),$Hkey # $Hkey^5
+ vpxor $Z0,$Z1,$Z1
+ vpunpckhqdq $inout1,$inout1,$T2
+ vpclmulqdq \$0x11,$Ii,$inout2,$inout2
+ vpxor $inout1,$T2,$T2
+ vpalignr \$8,$Xi,$Xi,$inout5 # 2nd phase
+ vpxor $inout3,$inout2,$inout2
+ vpclmulqdq \$0x10,$HK,$T1,$T1
+ vmovdqu 0x80-0x20($Xip),$HK
+ vpxor $T3,$T1,$T1
+
+ vxorps $Z3,$inout5,$inout5
+ vpclmulqdq \$0x10,0x10($const),$Xi,$Xi
+ vxorps $inout5,$Xi,$Xi
+
+ vpclmulqdq \$0x00,$Hkey,$inout1,$Z0
+ vmovdqu 0x70-0x20($Xip),$Ii # borrow $Ii for $Hkey^6
+ vpxor $Z1,$Z0,$Z0
+ vpunpckhqdq $Xi,$Xi,$T3
+ vpclmulqdq \$0x11,$Hkey,$inout1,$inout1
+ vpxor $Xi,$T3,$T3
+ vpxor $inout2,$inout1,$inout1
+ vpclmulqdq \$0x00,$HK,$T2,$T2
+ vpxor $T1,$T2,$T2
+
+ vpclmulqdq \$0x00,$Ii,$Xi,$Z1
+ vpclmulqdq \$0x11,$Ii,$Xi,$Z3
+ vpxor $Z0,$Z1,$Z1
+ vpclmulqdq \$0x10,$HK,$T3,$Z2
+ vpxor $inout1,$Z3,$Z3
+ vpxor $T2,$Z2,$Z2
+
+ vpxor $Z1,$Z3,$Z0 # aggregated Karatsuba post-processing
+ vpxor $Z0,$Z2,$Z2
+ vpslldq \$8,$Z2,$T1
+ vmovdqu 0x10($const),$Hkey # .Lpoly
+ vpsrldq \$8,$Z2,$Z2
+ vpxor $T1,$Z1,$Xi
+ vpxor $Z2,$Z3,$Z3
+
+ vpalignr \$8,$Xi,$Xi,$T2 # 1st phase
+ vpclmulqdq \$0x10,$Hkey,$Xi,$Xi
+ vpxor $T2,$Xi,$Xi
+
+ vpalignr \$8,$Xi,$Xi,$T2 # 2nd phase
+ vpclmulqdq \$0x10,$Hkey,$Xi,$Xi
+ vpxor $Z3,$T2,$T2
+ vpxor $T2,$Xi,$Xi
+___
+}
+$code.=<<___;
+ vpshufb ($const),$Xi,$Xi # .Lbswap_mask
+ vmovdqu $Xi,-0x40($Xip) # output Xi
+
+ vzeroupper
+___
+$code.=<<___ if ($win64);
+ movaps -0xd8(%rax),%xmm6
+ movaps -0xc8(%rax),%xmm7
+ movaps -0xb8(%rax),%xmm8
+ movaps -0xa8(%rax),%xmm9
+ movaps -0x98(%rax),%xmm10
+ movaps -0x88(%rax),%xmm11
+ movaps -0x78(%rax),%xmm12
+ movaps -0x68(%rax),%xmm13
+ movaps -0x58(%rax),%xmm14
+ movaps -0x48(%rax),%xmm15
+___
+$code.=<<___;
+ mov -48(%rax),%r15
+ mov -40(%rax),%r14
+ mov -32(%rax),%r13
+ mov -24(%rax),%r12
+ mov -16(%rax),%rbp
+ mov -8(%rax),%rbx
+ lea (%rax),%rsp # restore %rsp
+.Lgcm_enc_abort:
+ mov $ret,%rax # return value
+ ret
+.size aesni_gcm_encrypt,.-aesni_gcm_encrypt
+___
+
+$code.=<<___;
+.align 64
+.Lbswap_mask:
+ .byte 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0
+.Lpoly:
+ .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xc2
+.Lone_msb:
+ .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
+.Ltwo_lsb:
+ .byte 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+.Lone_lsb:
+ .byte 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+.asciz "AES-NI GCM module for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
+.align 64
+___
+if ($win64) {
+$rec="%rcx";
+$frame="%rdx";
+$context="%r8";
+$disp="%r9";
+
+$code.=<<___
+.extern __imp_RtlVirtualUnwind
+.type gcm_se_handler,\@abi-omnipotent
+.align 16
+gcm_se_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 120($context),%rax # pull context->Rax
+ mov 248($context),%rbx # pull context->Rip
+
+ mov 8($disp),%rsi # disp->ImageBase
+ mov 56($disp),%r11 # disp->HandlerData
+
+ mov 0(%r11),%r10d # HandlerData[0]
+ lea (%rsi,%r10),%r10 # prologue label
+ cmp %r10,%rbx # context->Rip<prologue label
+ jb .Lcommon_seh_tail
+
+ mov 152($context),%rax # pull context->Rsp
+
+ mov 4(%r11),%r10d # HandlerData[1]
+ lea (%rsi,%r10),%r10 # epilogue label
+ cmp %r10,%rbx # context->Rip>=epilogue label
+ jae .Lcommon_seh_tail
+
+ mov 120($context),%rax # pull context->Rax
+
+ mov -48(%rax),%r15
+ mov -40(%rax),%r14
+ mov -32(%rax),%r13
+ mov -24(%rax),%r12
+ mov -16(%rax),%rbp
+ mov -8(%rax),%rbx
+ mov %r15,240($context)
+ mov %r14,232($context)
+ mov %r13,224($context)
+ mov %r12,216($context)
+ mov %rbp,160($context)
+ mov %rbx,144($context)
+
+ lea -0xd8(%rax),%rsi # %xmm save area
+ lea 512($context),%rdi # & context.Xmm6
+ mov \$20,%ecx # 10*sizeof(%xmm0)/sizeof(%rax)
+ .long 0xa548f3fc # cld; rep movsq
+
+.Lcommon_seh_tail:
+ mov 8(%rax),%rdi
+ mov 16(%rax),%rsi
+ mov %rax,152($context) # restore context->Rsp
+ mov %rsi,168($context) # restore context->Rsi
+ mov %rdi,176($context) # restore context->Rdi
+
+ mov 40($disp),%rdi # disp->ContextRecord
+ mov $context,%rsi # context
+ mov \$154,%ecx # sizeof(CONTEXT)
+ .long 0xa548f3fc # cld; rep movsq
+
+ mov $disp,%rsi
+ xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER
+ mov 8(%rsi),%rdx # arg2, disp->ImageBase
+ mov 0(%rsi),%r8 # arg3, disp->ControlPc
+ mov 16(%rsi),%r9 # arg4, disp->FunctionEntry
+ mov 40(%rsi),%r10 # disp->ContextRecord
+ lea 56(%rsi),%r11 # &disp->HandlerData
+ lea 24(%rsi),%r12 # &disp->EstablisherFrame
+ mov %r10,32(%rsp) # arg5
+ mov %r11,40(%rsp) # arg6
+ mov %r12,48(%rsp) # arg7
+ mov %rcx,56(%rsp) # arg8, (NULL)
+ call *__imp_RtlVirtualUnwind(%rip)
+
+ mov \$1,%eax # ExceptionContinueSearch
+ add \$64,%rsp
+ popfq
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+ pop %rdi
+ pop %rsi
+ ret
+.size gcm_se_handler,.-gcm_se_handler
+
+.section .pdata
+.align 4
+ .rva .LSEH_begin_aesni_gcm_decrypt
+ .rva .LSEH_end_aesni_gcm_decrypt
+ .rva .LSEH_gcm_dec_info
+
+ .rva .LSEH_begin_aesni_gcm_encrypt
+ .rva .LSEH_end_aesni_gcm_encrypt
+ .rva .LSEH_gcm_enc_info
+.section .xdata
+.align 8
+.LSEH_gcm_dec_info:
+ .byte 9,0,0,0
+ .rva gcm_se_handler
+ .rva .Lgcm_dec_body,.Lgcm_dec_abort
+.LSEH_gcm_enc_info:
+ .byte 9,0,0,0
+ .rva gcm_se_handler
+ .rva .Lgcm_enc_body,.Lgcm_enc_abort
+___
+}
+}}} else {{{
+$code=<<___; # assembler is too old
+.text
+
+.globl aesni_gcm_encrypt
+.type aesni_gcm_encrypt,\@abi-omnipotent
+aesni_gcm_encrypt:
+ xor %eax,%eax
+ ret
+.size aesni_gcm_encrypt,.-aesni_gcm_encrypt
+
+.globl aesni_gcm_decrypt
+.type aesni_gcm_decrypt,\@abi-omnipotent
+aesni_gcm_decrypt:
+ xor %eax,%eax
+ ret
+.size aesni_gcm_decrypt,.-aesni_gcm_decrypt
+___
+}}}
+
+$code =~ s/\`([^\`]*)\`/eval($1)/gem;
+
+print $code;
+
+close STDOUT;
diff --git a/crypto/modes/asm/ghash-armv4.pl b/crypto/modes/asm/ghash-armv4.pl
new file mode 100644
index 0000000..8e4a52f
--- /dev/null
+++ b/crypto/modes/asm/ghash-armv4.pl
@@ -0,0 +1,432 @@
+#!/usr/bin/env perl
+#
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+#
+# April 2010
+#
+# The module implements "4-bit" GCM GHASH function and underlying
+# single multiplication operation in GF(2^128). "4-bit" means that it
+# uses 256 bytes per-key table [+32 bytes shared table]. There is no
+# experimental performance data available yet. The only approximation
+# that can be made at this point is based on code size. Inner loop is
+# 32 instructions long and on single-issue core should execute in <40
+# cycles. Having verified that gcc 3.4 didn't unroll corresponding
+# loop, this assembler loop body was found to be ~3x smaller than
+# compiler-generated one...
+#
+# July 2010
+#
+# Rescheduling for dual-issue pipeline resulted in 8.5% improvement on
+# Cortex A8 core and ~25 cycles per processed byte (which was observed
+# to be ~3 times faster than gcc-generated code:-)
+#
+# February 2011
+#
+# Profiler-assisted and platform-specific optimization resulted in 7%
+# improvement on Cortex A8 core and ~23.5 cycles per byte.
+#
+# March 2011
+#
+# Add NEON implementation featuring polynomial multiplication, i.e. no
+# lookup tables involved. On Cortex A8 it was measured to process one
+# byte in 15 cycles or 55% faster than integer-only code.
+
+# ====================================================================
+# Note about "528B" variant. In ARM case it makes lesser sense to
+# implement it for following reasons:
+#
+# - performance improvement won't be anywhere near 50%, because 128-
+# bit shift operation is neatly fused with 128-bit xor here, and
+# "538B" variant would eliminate only 4-5 instructions out of 32
+# in the inner loop (meaning that estimated improvement is ~15%);
+# - ARM-based systems are often embedded ones and extra memory
+# consumption might be unappreciated (for so little improvement);
+#
+# Byte order [in]dependence. =========================================
+#
+# Caller is expected to maintain specific *dword* order in Htable,
+# namely with *least* significant dword of 128-bit value at *lower*
+# address. This differs completely from C code and has everything to
+# do with ldm instruction and order in which dwords are "consumed" by
+# algorithm. *Byte* order within these dwords in turn is whatever
+# *native* byte order on current platform. See gcm128.c for working
+# example...
+
+while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {}
+open STDOUT,">$output";
+
+$Xi="r0"; # argument block
+$Htbl="r1";
+$inp="r2";
+$len="r3";
+
+$Zll="r4"; # variables
+$Zlh="r5";
+$Zhl="r6";
+$Zhh="r7";
+$Tll="r8";
+$Tlh="r9";
+$Thl="r10";
+$Thh="r11";
+$nlo="r12";
+################# r13 is stack pointer
+$nhi="r14";
+################# r15 is program counter
+
+$rem_4bit=$inp; # used in gcm_gmult_4bit
+$cnt=$len;
+
+sub Zsmash() {
+ my $i=12;
+ my @args=@_;
+ for ($Zll,$Zlh,$Zhl,$Zhh) {
+ $code.=<<___;
+#if __ARM_ARCH__>=7 && defined(__ARMEL__)
+ rev $_,$_
+ str $_,[$Xi,#$i]
+#elif defined(__ARMEB__)
+ str $_,[$Xi,#$i]
+#else
+ mov $Tlh,$_,lsr#8
+ strb $_,[$Xi,#$i+3]
+ mov $Thl,$_,lsr#16
+ strb $Tlh,[$Xi,#$i+2]
+ mov $Thh,$_,lsr#24
+ strb $Thl,[$Xi,#$i+1]
+ strb $Thh,[$Xi,#$i]
+#endif
+___
+ $code.="\t".shift(@args)."\n";
+ $i-=4;
+ }
+}
+
+$code=<<___;
+#if defined(__arm__)
+#include "arm_arch.h"
+
+.text
+.code 32
+
+.type rem_4bit,%object
+.align 5
+rem_4bit:
+.short 0x0000,0x1C20,0x3840,0x2460
+.short 0x7080,0x6CA0,0x48C0,0x54E0
+.short 0xE100,0xFD20,0xD940,0xC560
+.short 0x9180,0x8DA0,0xA9C0,0xB5E0
+.size rem_4bit,.-rem_4bit
+
+.type rem_4bit_get,%function
+rem_4bit_get:
+ sub $rem_4bit,pc,#8
+ sub $rem_4bit,$rem_4bit,#32 @ &rem_4bit
+ b .Lrem_4bit_got
+ nop
+.size rem_4bit_get,.-rem_4bit_get
+
+.global gcm_ghash_4bit
+.type gcm_ghash_4bit,%function
+gcm_ghash_4bit:
+ sub r12,pc,#8
+ add $len,$inp,$len @ $len to point at the end
+ stmdb sp!,{r3-r11,lr} @ save $len/end too
+ sub r12,r12,#48 @ &rem_4bit
+
+ ldmia r12,{r4-r11} @ copy rem_4bit ...
+ stmdb sp!,{r4-r11} @ ... to stack
+
+ ldrb $nlo,[$inp,#15]
+ ldrb $nhi,[$Xi,#15]
+.Louter:
+ eor $nlo,$nlo,$nhi
+ and $nhi,$nlo,#0xf0
+ and $nlo,$nlo,#0x0f
+ mov $cnt,#14
+
+ add $Zhh,$Htbl,$nlo,lsl#4
+ ldmia $Zhh,{$Zll-$Zhh} @ load Htbl[nlo]
+ add $Thh,$Htbl,$nhi
+ ldrb $nlo,[$inp,#14]
+
+ and $nhi,$Zll,#0xf @ rem
+ ldmia $Thh,{$Tll-$Thh} @ load Htbl[nhi]
+ add $nhi,$nhi,$nhi
+ eor $Zll,$Tll,$Zll,lsr#4
+ ldrh $Tll,[sp,$nhi] @ rem_4bit[rem]
+ eor $Zll,$Zll,$Zlh,lsl#28
+ ldrb $nhi,[$Xi,#14]
+ eor $Zlh,$Tlh,$Zlh,lsr#4
+ eor $Zlh,$Zlh,$Zhl,lsl#28
+ eor $Zhl,$Thl,$Zhl,lsr#4
+ eor $Zhl,$Zhl,$Zhh,lsl#28
+ eor $Zhh,$Thh,$Zhh,lsr#4
+ eor $nlo,$nlo,$nhi
+ and $nhi,$nlo,#0xf0
+ and $nlo,$nlo,#0x0f
+ eor $Zhh,$Zhh,$Tll,lsl#16
+
+.Linner:
+ add $Thh,$Htbl,$nlo,lsl#4
+ and $nlo,$Zll,#0xf @ rem
+ subs $cnt,$cnt,#1
+ add $nlo,$nlo,$nlo
+ ldmia $Thh,{$Tll-$Thh} @ load Htbl[nlo]
+ eor $Zll,$Tll,$Zll,lsr#4
+ eor $Zll,$Zll,$Zlh,lsl#28
+ eor $Zlh,$Tlh,$Zlh,lsr#4
+ eor $Zlh,$Zlh,$Zhl,lsl#28
+ ldrh $Tll,[sp,$nlo] @ rem_4bit[rem]
+ eor $Zhl,$Thl,$Zhl,lsr#4
+ ldrplb $nlo,[$inp,$cnt]
+ eor $Zhl,$Zhl,$Zhh,lsl#28
+ eor $Zhh,$Thh,$Zhh,lsr#4
+
+ add $Thh,$Htbl,$nhi
+ and $nhi,$Zll,#0xf @ rem
+ eor $Zhh,$Zhh,$Tll,lsl#16 @ ^= rem_4bit[rem]
+ add $nhi,$nhi,$nhi
+ ldmia $Thh,{$Tll-$Thh} @ load Htbl[nhi]
+ eor $Zll,$Tll,$Zll,lsr#4
+ ldrplb $Tll,[$Xi,$cnt]
+ eor $Zll,$Zll,$Zlh,lsl#28
+ eor $Zlh,$Tlh,$Zlh,lsr#4
+ ldrh $Tlh,[sp,$nhi]
+ eor $Zlh,$Zlh,$Zhl,lsl#28
+ eor $Zhl,$Thl,$Zhl,lsr#4
+ eor $Zhl,$Zhl,$Zhh,lsl#28
+ eorpl $nlo,$nlo,$Tll
+ eor $Zhh,$Thh,$Zhh,lsr#4
+ andpl $nhi,$nlo,#0xf0
+ andpl $nlo,$nlo,#0x0f
+ eor $Zhh,$Zhh,$Tlh,lsl#16 @ ^= rem_4bit[rem]
+ bpl .Linner
+
+ ldr $len,[sp,#32] @ re-load $len/end
+ add $inp,$inp,#16
+ mov $nhi,$Zll
+___
+ &Zsmash("cmp\t$inp,$len","ldrneb\t$nlo,[$inp,#15]");
+$code.=<<___;
+ bne .Louter
+
+ add sp,sp,#36
+#if __ARM_ARCH__>=5
+ ldmia sp!,{r4-r11,pc}
+#else
+ ldmia sp!,{r4-r11,lr}
+ tst lr,#1
+ moveq pc,lr @ be binary compatible with V4, yet
+ bx lr @ interoperable with Thumb ISA:-)
+#endif
+.size gcm_ghash_4bit,.-gcm_ghash_4bit
+
+.global gcm_gmult_4bit
+.type gcm_gmult_4bit,%function
+gcm_gmult_4bit:
+ stmdb sp!,{r4-r11,lr}
+ ldrb $nlo,[$Xi,#15]
+ b rem_4bit_get
+.Lrem_4bit_got:
+ and $nhi,$nlo,#0xf0
+ and $nlo,$nlo,#0x0f
+ mov $cnt,#14
+
+ add $Zhh,$Htbl,$nlo,lsl#4
+ ldmia $Zhh,{$Zll-$Zhh} @ load Htbl[nlo]
+ ldrb $nlo,[$Xi,#14]
+
+ add $Thh,$Htbl,$nhi
+ and $nhi,$Zll,#0xf @ rem
+ ldmia $Thh,{$Tll-$Thh} @ load Htbl[nhi]
+ add $nhi,$nhi,$nhi
+ eor $Zll,$Tll,$Zll,lsr#4
+ ldrh $Tll,[$rem_4bit,$nhi] @ rem_4bit[rem]
+ eor $Zll,$Zll,$Zlh,lsl#28
+ eor $Zlh,$Tlh,$Zlh,lsr#4
+ eor $Zlh,$Zlh,$Zhl,lsl#28
+ eor $Zhl,$Thl,$Zhl,lsr#4
+ eor $Zhl,$Zhl,$Zhh,lsl#28
+ eor $Zhh,$Thh,$Zhh,lsr#4
+ and $nhi,$nlo,#0xf0
+ eor $Zhh,$Zhh,$Tll,lsl#16
+ and $nlo,$nlo,#0x0f
+
+.Loop:
+ add $Thh,$Htbl,$nlo,lsl#4
+ and $nlo,$Zll,#0xf @ rem
+ subs $cnt,$cnt,#1
+ add $nlo,$nlo,$nlo
+ ldmia $Thh,{$Tll-$Thh} @ load Htbl[nlo]
+ eor $Zll,$Tll,$Zll,lsr#4
+ eor $Zll,$Zll,$Zlh,lsl#28
+ eor $Zlh,$Tlh,$Zlh,lsr#4
+ eor $Zlh,$Zlh,$Zhl,lsl#28
+ ldrh $Tll,[$rem_4bit,$nlo] @ rem_4bit[rem]
+ eor $Zhl,$Thl,$Zhl,lsr#4
+ ldrplb $nlo,[$Xi,$cnt]
+ eor $Zhl,$Zhl,$Zhh,lsl#28
+ eor $Zhh,$Thh,$Zhh,lsr#4
+
+ add $Thh,$Htbl,$nhi
+ and $nhi,$Zll,#0xf @ rem
+ eor $Zhh,$Zhh,$Tll,lsl#16 @ ^= rem_4bit[rem]
+ add $nhi,$nhi,$nhi
+ ldmia $Thh,{$Tll-$Thh} @ load Htbl[nhi]
+ eor $Zll,$Tll,$Zll,lsr#4
+ eor $Zll,$Zll,$Zlh,lsl#28
+ eor $Zlh,$Tlh,$Zlh,lsr#4
+ ldrh $Tll,[$rem_4bit,$nhi] @ rem_4bit[rem]
+ eor $Zlh,$Zlh,$Zhl,lsl#28
+ eor $Zhl,$Thl,$Zhl,lsr#4
+ eor $Zhl,$Zhl,$Zhh,lsl#28
+ eor $Zhh,$Thh,$Zhh,lsr#4
+ andpl $nhi,$nlo,#0xf0
+ andpl $nlo,$nlo,#0x0f
+ eor $Zhh,$Zhh,$Tll,lsl#16 @ ^= rem_4bit[rem]
+ bpl .Loop
+___
+ &Zsmash();
+$code.=<<___;
+#if __ARM_ARCH__>=5
+ ldmia sp!,{r4-r11,pc}
+#else
+ ldmia sp!,{r4-r11,lr}
+ tst lr,#1
+ moveq pc,lr @ be binary compatible with V4, yet
+ bx lr @ interoperable with Thumb ISA:-)
+#endif
+.size gcm_gmult_4bit,.-gcm_gmult_4bit
+___
+{
+my $cnt=$Htbl; # $Htbl is used once in the very beginning
+
+my ($Hhi, $Hlo, $Zo, $T, $xi, $mod) = map("d$_",(0..7));
+my ($Qhi, $Qlo, $Z, $R, $zero, $Qpost, $IN) = map("q$_",(8..15));
+
+# Z:Zo keeps 128-bit result shifted by 1 to the right, with bottom bit
+# in Zo. Or should I say "top bit", because GHASH is specified in
+# reverse bit order? Otherwise straightforward 128-bt H by one input
+# byte multiplication and modulo-reduction, times 16.
+
+sub Dlo() { shift=~m|q([1]?[0-9])|?"d".($1*2):""; }
+sub Dhi() { shift=~m|q([1]?[0-9])|?"d".($1*2+1):""; }
+sub Q() { shift=~m|d([1-3]?[02468])|?"q".($1/2):""; }
+
+$code.=<<___;
+#if __ARM_ARCH__>=7
+.fpu neon
+
+.global gcm_gmult_neon
+.type gcm_gmult_neon,%function
+.align 4
+gcm_gmult_neon:
+ sub $Htbl,#16 @ point at H in GCM128_CTX
+ vld1.64 `&Dhi("$IN")`,[$Xi,:64]!@ load Xi
+ vmov.i32 $mod,#0xe1 @ our irreducible polynomial
+ vld1.64 `&Dlo("$IN")`,[$Xi,:64]!
+ vshr.u64 $mod,#32
+ vldmia $Htbl,{$Hhi-$Hlo} @ load H
+ veor $zero,$zero
+#ifdef __ARMEL__
+ vrev64.8 $IN,$IN
+#endif
+ veor $Qpost,$Qpost
+ veor $R,$R
+ mov $cnt,#16
+ veor $Z,$Z
+ mov $len,#16
+ veor $Zo,$Zo
+ vdup.8 $xi,`&Dlo("$IN")`[0] @ broadcast lowest byte
+ b .Linner_neon
+.size gcm_gmult_neon,.-gcm_gmult_neon
+
+.global gcm_ghash_neon
+.type gcm_ghash_neon,%function
+.align 4
+gcm_ghash_neon:
+ vld1.64 `&Dhi("$Z")`,[$Xi,:64]! @ load Xi
+ vmov.i32 $mod,#0xe1 @ our irreducible polynomial
+ vld1.64 `&Dlo("$Z")`,[$Xi,:64]!
+ vshr.u64 $mod,#32
+ vldmia $Xi,{$Hhi-$Hlo} @ load H
+ veor $zero,$zero
+ nop
+#ifdef __ARMEL__
+ vrev64.8 $Z,$Z
+#endif
+.Louter_neon:
+ vld1.64 `&Dhi($IN)`,[$inp]! @ load inp
+ veor $Qpost,$Qpost
+ vld1.64 `&Dlo($IN)`,[$inp]!
+ veor $R,$R
+ mov $cnt,#16
+#ifdef __ARMEL__
+ vrev64.8 $IN,$IN
+#endif
+ veor $Zo,$Zo
+ veor $IN,$Z @ inp^=Xi
+ veor $Z,$Z
+ vdup.8 $xi,`&Dlo("$IN")`[0] @ broadcast lowest byte
+.Linner_neon:
+ subs $cnt,$cnt,#1
+ vmull.p8 $Qlo,$Hlo,$xi @ H.lo·Xi[i]
+ vmull.p8 $Qhi,$Hhi,$xi @ H.hi·Xi[i]
+ vext.8 $IN,$zero,#1 @ IN>>=8
+
+ veor $Z,$Qpost @ modulo-scheduled part
+ vshl.i64 `&Dlo("$R")`,#48
+ vdup.8 $xi,`&Dlo("$IN")`[0] @ broadcast lowest byte
+ veor $T,`&Dlo("$Qlo")`,`&Dlo("$Z")`
+
+ veor `&Dhi("$Z")`,`&Dlo("$R")`
+ vuzp.8 $Qlo,$Qhi
+ vsli.8 $Zo,$T,#1 @ compose the "carry" byte
+ vext.8 $Z,$zero,#1 @ Z>>=8
+
+ vmull.p8 $R,$Zo,$mod @ "carry"·0xe1
+ vshr.u8 $Zo,$T,#7 @ save Z's bottom bit
+ vext.8 $Qpost,$Qlo,$zero,#1 @ Qlo>>=8
+ veor $Z,$Qhi
+ bne .Linner_neon
+
+ veor $Z,$Qpost @ modulo-scheduled artefact
+ vshl.i64 `&Dlo("$R")`,#48
+ veor `&Dhi("$Z")`,`&Dlo("$R")`
+
+ @ finalization, normalize Z:Zo
+ vand $Zo,$mod @ suffices to mask the bit
+ vshr.u64 `&Dhi(&Q("$Zo"))`,`&Dlo("$Z")`,#63
+ vshl.i64 $Z,#1
+ subs $len,#16
+ vorr $Z,`&Q("$Zo")` @ Z=Z:Zo<<1
+ bne .Louter_neon
+
+#ifdef __ARMEL__
+ vrev64.8 $Z,$Z
+#endif
+ sub $Xi,#16
+ vst1.64 `&Dhi("$Z")`,[$Xi,:64]! @ write out Xi
+ vst1.64 `&Dlo("$Z")`,[$Xi,:64]
+
+ bx lr
+.size gcm_ghash_neon,.-gcm_ghash_neon
+#endif
+___
+}
+$code.=<<___;
+.asciz "GHASH for ARMv4/NEON, CRYPTOGAMS by <appro\@openssl.org>"
+.align 2
+
+#endif
+___
+
+$code =~ s/\`([^\`]*)\`/eval $1/gem;
+$code =~ s/\bbx\s+lr\b/.word\t0xe12fff1e/gm; # make it possible to compile with -march=armv4
+print $code;
+close STDOUT; # enforce flush
diff --git a/crypto/modes/asm/ghash-x86.pl b/crypto/modes/asm/ghash-x86.pl
new file mode 100644
index 0000000..d47e325
--- /dev/null
+++ b/crypto/modes/asm/ghash-x86.pl
@@ -0,0 +1,1391 @@
+#!/usr/bin/env perl
+#
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+#
+# March, May, June 2010
+#
+# The module implements "4-bit" GCM GHASH function and underlying
+# single multiplication operation in GF(2^128). "4-bit" means that it
+# uses 256 bytes per-key table [+64/128 bytes fixed table]. It has two
+# code paths: vanilla x86 and vanilla SSE. Former will be executed on
+# 486 and Pentium, latter on all others. SSE GHASH features so called
+# "528B" variant of "4-bit" method utilizing additional 256+16 bytes
+# of per-key storage [+512 bytes shared table]. Performance results
+# are for streamed GHASH subroutine and are expressed in cycles per
+# processed byte, less is better:
+#
+# gcc 2.95.3(*) SSE assembler x86 assembler
+#
+# Pentium 105/111(**) - 50
+# PIII 68 /75 12.2 24
+# P4 125/125 17.8 84(***)
+# Opteron 66 /70 10.1 30
+# Core2 54 /67 8.4 18
+# Atom 105/105 16.8 53
+# VIA Nano 69 /71 13.0 27
+#
+# (*) gcc 3.4.x was observed to generate few percent slower code,
+# which is one of reasons why 2.95.3 results were chosen,
+# another reason is lack of 3.4.x results for older CPUs;
+# comparison with SSE results is not completely fair, because C
+# results are for vanilla "256B" implementation, while
+# assembler results are for "528B";-)
+# (**) second number is result for code compiled with -fPIC flag,
+# which is actually more relevant, because assembler code is
+# position-independent;
+# (***) see comment in non-MMX routine for further details;
+#
+# To summarize, it's >2-5 times faster than gcc-generated code. To
+# anchor it to something else SHA1 assembler processes one byte in
+# ~7 cycles on contemporary x86 cores. As for choice of MMX/SSE
+# in particular, see comment at the end of the file...
+
+# May 2010
+#
+# Add PCLMULQDQ version performing at 2.10 cycles per processed byte.
+# The question is how close is it to theoretical limit? The pclmulqdq
+# instruction latency appears to be 14 cycles and there can't be more
+# than 2 of them executing at any given time. This means that single
+# Karatsuba multiplication would take 28 cycles *plus* few cycles for
+# pre- and post-processing. Then multiplication has to be followed by
+# modulo-reduction. Given that aggregated reduction method [see
+# "Carry-less Multiplication and Its Usage for Computing the GCM Mode"
+# white paper by Intel] allows you to perform reduction only once in
+# a while we can assume that asymptotic performance can be estimated
+# as (28+Tmod/Naggr)/16, where Tmod is time to perform reduction
+# and Naggr is the aggregation factor.
+#
+# Before we proceed to this implementation let's have closer look at
+# the best-performing code suggested by Intel in their white paper.
+# By tracing inter-register dependencies Tmod is estimated as ~19
+# cycles and Naggr chosen by Intel is 4, resulting in 2.05 cycles per
+# processed byte. As implied, this is quite optimistic estimate,
+# because it does not account for Karatsuba pre- and post-processing,
+# which for a single multiplication is ~5 cycles. Unfortunately Intel
+# does not provide performance data for GHASH alone. But benchmarking
+# AES_GCM_encrypt ripped out of Fig. 15 of the white paper with aadt
+# alone resulted in 2.46 cycles per byte of out 16KB buffer. Note that
+# the result accounts even for pre-computing of degrees of the hash
+# key H, but its portion is negligible at 16KB buffer size.
+#
+# Moving on to the implementation in question. Tmod is estimated as
+# ~13 cycles and Naggr is 2, giving asymptotic performance of ...
+# 2.16. How is it possible that measured performance is better than
+# optimistic theoretical estimate? There is one thing Intel failed
+# to recognize. By serializing GHASH with CTR in same subroutine
+# former's performance is really limited to above (Tmul + Tmod/Naggr)
+# equation. But if GHASH procedure is detached, the modulo-reduction
+# can be interleaved with Naggr-1 multiplications at instruction level
+# and under ideal conditions even disappear from the equation. So that
+# optimistic theoretical estimate for this implementation is ...
+# 28/16=1.75, and not 2.16. Well, it's probably way too optimistic,
+# at least for such small Naggr. I'd argue that (28+Tproc/Naggr),
+# where Tproc is time required for Karatsuba pre- and post-processing,
+# is more realistic estimate. In this case it gives ... 1.91 cycles.
+# Or in other words, depending on how well we can interleave reduction
+# and one of the two multiplications the performance should be betwen
+# 1.91 and 2.16. As already mentioned, this implementation processes
+# one byte out of 8KB buffer in 2.10 cycles, while x86_64 counterpart
+# - in 2.02. x86_64 performance is better, because larger register
+# bank allows to interleave reduction and multiplication better.
+#
+# Does it make sense to increase Naggr? To start with it's virtually
+# impossible in 32-bit mode, because of limited register bank
+# capacity. Otherwise improvement has to be weighed agiainst slower
+# setup, as well as code size and complexity increase. As even
+# optimistic estimate doesn't promise 30% performance improvement,
+# there are currently no plans to increase Naggr.
+#
+# Special thanks to David Woodhouse <dwmw2@infradead.org> for
+# providing access to a Westmere-based system on behalf of Intel
+# Open Source Technology Centre.
+
+# January 2010
+#
+# Tweaked to optimize transitions between integer and FP operations
+# on same XMM register, PCLMULQDQ subroutine was measured to process
+# one byte in 2.07 cycles on Sandy Bridge, and in 2.12 - on Westmere.
+# The minor regression on Westmere is outweighed by ~15% improvement
+# on Sandy Bridge. Strangely enough attempt to modify 64-bit code in
+# similar manner resulted in almost 20% degradation on Sandy Bridge,
+# where original 64-bit code processes one byte in 1.95 cycles.
+
+#####################################################################
+# For reference, AMD Bulldozer processes one byte in 1.98 cycles in
+# 32-bit mode and 1.89 in 64-bit.
+
+# February 2013
+#
+# Overhaul: aggregate Karatsuba post-processing, improve ILP in
+# reduction_alg9. Resulting performance is 1.96 cycles per byte on
+# Westmere, 1.95 - on Sandy/Ivy Bridge, 1.76 - on Bulldozer.
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+push(@INC,"${dir}","${dir}../../perlasm");
+require "x86asm.pl";
+
+&asm_init($ARGV[0],"ghash-x86.pl",$x86only = $ARGV[$#ARGV] eq "386");
+
+$sse2=1;
+#for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); }
+
+($Zhh,$Zhl,$Zlh,$Zll) = ("ebp","edx","ecx","ebx");
+$inp = "edi";
+$Htbl = "esi";
+
+$unroll = 0; # Affects x86 loop. Folded loop performs ~7% worse
+ # than unrolled, which has to be weighted against
+ # 2.5x x86-specific code size reduction.
+
+sub x86_loop {
+ my $off = shift;
+ my $rem = "eax";
+
+ &mov ($Zhh,&DWP(4,$Htbl,$Zll));
+ &mov ($Zhl,&DWP(0,$Htbl,$Zll));
+ &mov ($Zlh,&DWP(12,$Htbl,$Zll));
+ &mov ($Zll,&DWP(8,$Htbl,$Zll));
+ &xor ($rem,$rem); # avoid partial register stalls on PIII
+
+ # shrd practically kills P4, 2.5x deterioration, but P4 has
+ # MMX code-path to execute. shrd runs tad faster [than twice
+ # the shifts, move's and or's] on pre-MMX Pentium (as well as
+ # PIII and Core2), *but* minimizes code size, spares register
+ # and thus allows to fold the loop...
+ if (!$unroll) {
+ my $cnt = $inp;
+ &mov ($cnt,15);
+ &jmp (&label("x86_loop"));
+ &set_label("x86_loop",16);
+ for($i=1;$i<=2;$i++) {
+ &mov (&LB($rem),&LB($Zll));
+ &shrd ($Zll,$Zlh,4);
+ &and (&LB($rem),0xf);
+ &shrd ($Zlh,$Zhl,4);
+ &shrd ($Zhl,$Zhh,4);
+ &shr ($Zhh,4);
+ &xor ($Zhh,&DWP($off+16,"esp",$rem,4));
+
+ &mov (&LB($rem),&BP($off,"esp",$cnt));
+ if ($i&1) {
+ &and (&LB($rem),0xf0);
+ } else {
+ &shl (&LB($rem),4);
+ }
+
+ &xor ($Zll,&DWP(8,$Htbl,$rem));
+ &xor ($Zlh,&DWP(12,$Htbl,$rem));
+ &xor ($Zhl,&DWP(0,$Htbl,$rem));
+ &xor ($Zhh,&DWP(4,$Htbl,$rem));
+
+ if ($i&1) {
+ &dec ($cnt);
+ &js (&label("x86_break"));
+ } else {
+ &jmp (&label("x86_loop"));
+ }
+ }
+ &set_label("x86_break",16);
+ } else {
+ for($i=1;$i<32;$i++) {
+ &comment($i);
+ &mov (&LB($rem),&LB($Zll));
+ &shrd ($Zll,$Zlh,4);
+ &and (&LB($rem),0xf);
+ &shrd ($Zlh,$Zhl,4);
+ &shrd ($Zhl,$Zhh,4);
+ &shr ($Zhh,4);
+ &xor ($Zhh,&DWP($off+16,"esp",$rem,4));
+
+ if ($i&1) {
+ &mov (&LB($rem),&BP($off+15-($i>>1),"esp"));
+ &and (&LB($rem),0xf0);
+ } else {
+ &mov (&LB($rem),&BP($off+15-($i>>1),"esp"));
+ &shl (&LB($rem),4);
+ }
+
+ &xor ($Zll,&DWP(8,$Htbl,$rem));
+ &xor ($Zlh,&DWP(12,$Htbl,$rem));
+ &xor ($Zhl,&DWP(0,$Htbl,$rem));
+ &xor ($Zhh,&DWP(4,$Htbl,$rem));
+ }
+ }
+ &bswap ($Zll);
+ &bswap ($Zlh);
+ &bswap ($Zhl);
+ if (!$x86only) {
+ &bswap ($Zhh);
+ } else {
+ &mov ("eax",$Zhh);
+ &bswap ("eax");
+ &mov ($Zhh,"eax");
+ }
+}
+
+if ($unroll) {
+ &function_begin_B("_x86_gmult_4bit_inner");
+ &x86_loop(4);
+ &ret ();
+ &function_end_B("_x86_gmult_4bit_inner");
+}
+
+sub deposit_rem_4bit {
+ my $bias = shift;
+
+ &mov (&DWP($bias+0, "esp"),0x0000<<16);
+ &mov (&DWP($bias+4, "esp"),0x1C20<<16);
+ &mov (&DWP($bias+8, "esp"),0x3840<<16);
+ &mov (&DWP($bias+12,"esp"),0x2460<<16);
+ &mov (&DWP($bias+16,"esp"),0x7080<<16);
+ &mov (&DWP($bias+20,"esp"),0x6CA0<<16);
+ &mov (&DWP($bias+24,"esp"),0x48C0<<16);
+ &mov (&DWP($bias+28,"esp"),0x54E0<<16);
+ &mov (&DWP($bias+32,"esp"),0xE100<<16);
+ &mov (&DWP($bias+36,"esp"),0xFD20<<16);
+ &mov (&DWP($bias+40,"esp"),0xD940<<16);
+ &mov (&DWP($bias+44,"esp"),0xC560<<16);
+ &mov (&DWP($bias+48,"esp"),0x9180<<16);
+ &mov (&DWP($bias+52,"esp"),0x8DA0<<16);
+ &mov (&DWP($bias+56,"esp"),0xA9C0<<16);
+ &mov (&DWP($bias+60,"esp"),0xB5E0<<16);
+}
+
+$suffix = $x86only ? "" : "_x86";
+
+&function_begin("gcm_gmult_4bit".$suffix);
+ &stack_push(16+4+1); # +1 for stack alignment
+ &mov ($inp,&wparam(0)); # load Xi
+ &mov ($Htbl,&wparam(1)); # load Htable
+
+ &mov ($Zhh,&DWP(0,$inp)); # load Xi[16]
+ &mov ($Zhl,&DWP(4,$inp));
+ &mov ($Zlh,&DWP(8,$inp));
+ &mov ($Zll,&DWP(12,$inp));
+
+ &deposit_rem_4bit(16);
+
+ &mov (&DWP(0,"esp"),$Zhh); # copy Xi[16] on stack
+ &mov (&DWP(4,"esp"),$Zhl);
+ &mov (&DWP(8,"esp"),$Zlh);
+ &mov (&DWP(12,"esp"),$Zll);
+ &shr ($Zll,20);
+ &and ($Zll,0xf0);
+
+ if ($unroll) {
+ &call ("_x86_gmult_4bit_inner");
+ } else {
+ &x86_loop(0);
+ &mov ($inp,&wparam(0));
+ }
+
+ &mov (&DWP(12,$inp),$Zll);
+ &mov (&DWP(8,$inp),$Zlh);
+ &mov (&DWP(4,$inp),$Zhl);
+ &mov (&DWP(0,$inp),$Zhh);
+ &stack_pop(16+4+1);
+&function_end("gcm_gmult_4bit".$suffix);
+
+&function_begin("gcm_ghash_4bit".$suffix);
+ &stack_push(16+4+1); # +1 for 64-bit alignment
+ &mov ($Zll,&wparam(0)); # load Xi
+ &mov ($Htbl,&wparam(1)); # load Htable
+ &mov ($inp,&wparam(2)); # load in
+ &mov ("ecx",&wparam(3)); # load len
+ &add ("ecx",$inp);
+ &mov (&wparam(3),"ecx");
+
+ &mov ($Zhh,&DWP(0,$Zll)); # load Xi[16]
+ &mov ($Zhl,&DWP(4,$Zll));
+ &mov ($Zlh,&DWP(8,$Zll));
+ &mov ($Zll,&DWP(12,$Zll));
+
+ &deposit_rem_4bit(16);
+
+ &set_label("x86_outer_loop",16);
+ &xor ($Zll,&DWP(12,$inp)); # xor with input
+ &xor ($Zlh,&DWP(8,$inp));
+ &xor ($Zhl,&DWP(4,$inp));
+ &xor ($Zhh,&DWP(0,$inp));
+ &mov (&DWP(12,"esp"),$Zll); # dump it on stack
+ &mov (&DWP(8,"esp"),$Zlh);
+ &mov (&DWP(4,"esp"),$Zhl);
+ &mov (&DWP(0,"esp"),$Zhh);
+
+ &shr ($Zll,20);
+ &and ($Zll,0xf0);
+
+ if ($unroll) {
+ &call ("_x86_gmult_4bit_inner");
+ } else {
+ &x86_loop(0);
+ &mov ($inp,&wparam(2));
+ }
+ &lea ($inp,&DWP(16,$inp));
+ &cmp ($inp,&wparam(3));
+ &mov (&wparam(2),$inp) if (!$unroll);
+ &jb (&label("x86_outer_loop"));
+
+ &mov ($inp,&wparam(0)); # load Xi
+ &mov (&DWP(12,$inp),$Zll);
+ &mov (&DWP(8,$inp),$Zlh);
+ &mov (&DWP(4,$inp),$Zhl);
+ &mov (&DWP(0,$inp),$Zhh);
+ &stack_pop(16+4+1);
+&function_end("gcm_ghash_4bit".$suffix);
+
+if (!$x86only) {{{
+
+&static_label("rem_4bit");
+
+if (!$sse2) {{ # pure-MMX "May" version...
+
+$S=12; # shift factor for rem_4bit
+
+&function_begin_B("_mmx_gmult_4bit_inner");
+# MMX version performs 3.5 times better on P4 (see comment in non-MMX
+# routine for further details), 100% better on Opteron, ~70% better
+# on Core2 and PIII... In other words effort is considered to be well
+# spent... Since initial release the loop was unrolled in order to
+# "liberate" register previously used as loop counter. Instead it's
+# used to optimize critical path in 'Z.hi ^= rem_4bit[Z.lo&0xf]'.
+# The path involves move of Z.lo from MMX to integer register,
+# 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.
+{
+ my $cnt;
+ my $rem_4bit = "eax";
+ my @rem = ($Zhh,$Zll);
+ my $nhi = $Zhl;
+ my $nlo = $Zlh;
+
+ my ($Zlo,$Zhi) = ("mm0","mm1");
+ my $tmp = "mm2";
+
+ &xor ($nlo,$nlo); # avoid partial register stalls on PIII
+ &mov ($nhi,$Zll);
+ &mov (&LB($nlo),&LB($nhi));
+ &shl (&LB($nlo),4);
+ &and ($nhi,0xf0);
+ &movq ($Zlo,&QWP(8,$Htbl,$nlo));
+ &movq ($Zhi,&QWP(0,$Htbl,$nlo));
+ &movd ($rem[0],$Zlo);
+
+ for ($cnt=28;$cnt>=-2;$cnt--) {
+ my $odd = $cnt&1;
+ my $nix = $odd ? $nlo : $nhi;
+
+ &shl (&LB($nlo),4) if ($odd);
+ &psrlq ($Zlo,4);
+ &movq ($tmp,$Zhi);
+ &psrlq ($Zhi,4);
+ &pxor ($Zlo,&QWP(8,$Htbl,$nix));
+ &mov (&LB($nlo),&BP($cnt/2,$inp)) if (!$odd && $cnt>=0);
+ &psllq ($tmp,60);
+ &and ($nhi,0xf0) if ($odd);
+ &pxor ($Zhi,&QWP(0,$rem_4bit,$rem[1],8)) if ($cnt<28);
+ &and ($rem[0],0xf);
+ &pxor ($Zhi,&QWP(0,$Htbl,$nix));
+ &mov ($nhi,$nlo) if (!$odd && $cnt>=0);
+ &movd ($rem[1],$Zlo);
+ &pxor ($Zlo,$tmp);
+
+ push (@rem,shift(@rem)); # "rotate" registers
+ }
+
+ &mov ($inp,&DWP(4,$rem_4bit,$rem[1],8)); # last rem_4bit[rem]
+
+ &psrlq ($Zlo,32); # lower part of Zlo is already there
+ &movd ($Zhl,$Zhi);
+ &psrlq ($Zhi,32);
+ &movd ($Zlh,$Zlo);
+ &movd ($Zhh,$Zhi);
+ &shl ($inp,4); # compensate for rem_4bit[i] being >>4
+
+ &bswap ($Zll);
+ &bswap ($Zhl);
+ &bswap ($Zlh);
+ &xor ($Zhh,$inp);
+ &bswap ($Zhh);
+
+ &ret ();
+}
+&function_end_B("_mmx_gmult_4bit_inner");
+
+&function_begin("gcm_gmult_4bit_mmx");
+ &mov ($inp,&wparam(0)); # load Xi
+ &mov ($Htbl,&wparam(1)); # load Htable
+
+ &call (&label("pic_point"));
+ &set_label("pic_point");
+ &blindpop("eax");
+ &lea ("eax",&DWP(&label("rem_4bit")."-".&label("pic_point"),"eax"));
+
+ &movz ($Zll,&BP(15,$inp));
+
+ &call ("_mmx_gmult_4bit_inner");
+
+ &mov ($inp,&wparam(0)); # load Xi
+ &emms ();
+ &mov (&DWP(12,$inp),$Zll);
+ &mov (&DWP(4,$inp),$Zhl);
+ &mov (&DWP(8,$inp),$Zlh);
+ &mov (&DWP(0,$inp),$Zhh);
+&function_end("gcm_gmult_4bit_mmx");
+
+# Streamed version performs 20% better on P4, 7% on Opteron,
+# 10% on Core2 and PIII...
+&function_begin("gcm_ghash_4bit_mmx");
+ &mov ($Zhh,&wparam(0)); # load Xi
+ &mov ($Htbl,&wparam(1)); # load Htable
+ &mov ($inp,&wparam(2)); # load in
+ &mov ($Zlh,&wparam(3)); # load len
+
+ &call (&label("pic_point"));
+ &set_label("pic_point");
+ &blindpop("eax");
+ &lea ("eax",&DWP(&label("rem_4bit")."-".&label("pic_point"),"eax"));
+
+ &add ($Zlh,$inp);
+ &mov (&wparam(3),$Zlh); # len to point at the end of input
+ &stack_push(4+1); # +1 for stack alignment
+
+ &mov ($Zll,&DWP(12,$Zhh)); # load Xi[16]
+ &mov ($Zhl,&DWP(4,$Zhh));
+ &mov ($Zlh,&DWP(8,$Zhh));
+ &mov ($Zhh,&DWP(0,$Zhh));
+ &jmp (&label("mmx_outer_loop"));
+
+ &set_label("mmx_outer_loop",16);
+ &xor ($Zll,&DWP(12,$inp));
+ &xor ($Zhl,&DWP(4,$inp));
+ &xor ($Zlh,&DWP(8,$inp));
+ &xor ($Zhh,&DWP(0,$inp));
+ &mov (&wparam(2),$inp);
+ &mov (&DWP(12,"esp"),$Zll);
+ &mov (&DWP(4,"esp"),$Zhl);
+ &mov (&DWP(8,"esp"),$Zlh);
+ &mov (&DWP(0,"esp"),$Zhh);
+
+ &mov ($inp,"esp");
+ &shr ($Zll,24);
+
+ &call ("_mmx_gmult_4bit_inner");
+
+ &mov ($inp,&wparam(2));
+ &lea ($inp,&DWP(16,$inp));
+ &cmp ($inp,&wparam(3));
+ &jb (&label("mmx_outer_loop"));
+
+ &mov ($inp,&wparam(0)); # load Xi
+ &emms ();
+ &mov (&DWP(12,$inp),$Zll);
+ &mov (&DWP(4,$inp),$Zhl);
+ &mov (&DWP(8,$inp),$Zlh);
+ &mov (&DWP(0,$inp),$Zhh);
+
+ &stack_pop(4+1);
+&function_end("gcm_ghash_4bit_mmx");
+
+}} else {{ # "June" MMX version...
+ # ... has slower "April" gcm_gmult_4bit_mmx with folded
+ # loop. This is done to conserve code size...
+$S=16; # shift factor for rem_4bit
+
+sub mmx_loop() {
+# MMX version performs 2.8 times better on P4 (see comment in non-MMX
+# routine for further details), 40% better on Opteron and Core2, 50%
+# better on PIII... In other words effort is considered to be well
+# spent...
+ my $inp = shift;
+ my $rem_4bit = shift;
+ my $cnt = $Zhh;
+ my $nhi = $Zhl;
+ my $nlo = $Zlh;
+ my $rem = $Zll;
+
+ my ($Zlo,$Zhi) = ("mm0","mm1");
+ my $tmp = "mm2";
+
+ &xor ($nlo,$nlo); # avoid partial register stalls on PIII
+ &mov ($nhi,$Zll);
+ &mov (&LB($nlo),&LB($nhi));
+ &mov ($cnt,14);
+ &shl (&LB($nlo),4);
+ &and ($nhi,0xf0);
+ &movq ($Zlo,&QWP(8,$Htbl,$nlo));
+ &movq ($Zhi,&QWP(0,$Htbl,$nlo));
+ &movd ($rem,$Zlo);
+ &jmp (&label("mmx_loop"));
+
+ &set_label("mmx_loop",16);
+ &psrlq ($Zlo,4);
+ &and ($rem,0xf);
+ &movq ($tmp,$Zhi);
+ &psrlq ($Zhi,4);
+ &pxor ($Zlo,&QWP(8,$Htbl,$nhi));
+ &mov (&LB($nlo),&BP(0,$inp,$cnt));
+ &psllq ($tmp,60);
+ &pxor ($Zhi,&QWP(0,$rem_4bit,$rem,8));
+ &dec ($cnt);
+ &movd ($rem,$Zlo);
+ &pxor ($Zhi,&QWP(0,$Htbl,$nhi));
+ &mov ($nhi,$nlo);
+ &pxor ($Zlo,$tmp);
+ &js (&label("mmx_break"));
+
+ &shl (&LB($nlo),4);
+ &and ($rem,0xf);
+ &psrlq ($Zlo,4);
+ &and ($nhi,0xf0);
+ &movq ($tmp,$Zhi);
+ &psrlq ($Zhi,4);
+ &pxor ($Zlo,&QWP(8,$Htbl,$nlo));
+ &psllq ($tmp,60);
+ &pxor ($Zhi,&QWP(0,$rem_4bit,$rem,8));
+ &movd ($rem,$Zlo);
+ &pxor ($Zhi,&QWP(0,$Htbl,$nlo));
+ &pxor ($Zlo,$tmp);
+ &jmp (&label("mmx_loop"));
+
+ &set_label("mmx_break",16);
+ &shl (&LB($nlo),4);
+ &and ($rem,0xf);
+ &psrlq ($Zlo,4);
+ &and ($nhi,0xf0);
+ &movq ($tmp,$Zhi);
+ &psrlq ($Zhi,4);
+ &pxor ($Zlo,&QWP(8,$Htbl,$nlo));
+ &psllq ($tmp,60);
+ &pxor ($Zhi,&QWP(0,$rem_4bit,$rem,8));
+ &movd ($rem,$Zlo);
+ &pxor ($Zhi,&QWP(0,$Htbl,$nlo));
+ &pxor ($Zlo,$tmp);
+
+ &psrlq ($Zlo,4);
+ &and ($rem,0xf);
+ &movq ($tmp,$Zhi);
+ &psrlq ($Zhi,4);
+ &pxor ($Zlo,&QWP(8,$Htbl,$nhi));
+ &psllq ($tmp,60);
+ &pxor ($Zhi,&QWP(0,$rem_4bit,$rem,8));
+ &movd ($rem,$Zlo);
+ &pxor ($Zhi,&QWP(0,$Htbl,$nhi));
+ &pxor ($Zlo,$tmp);
+
+ &psrlq ($Zlo,32); # lower part of Zlo is already there
+ &movd ($Zhl,$Zhi);
+ &psrlq ($Zhi,32);
+ &movd ($Zlh,$Zlo);
+ &movd ($Zhh,$Zhi);
+
+ &bswap ($Zll);
+ &bswap ($Zhl);
+ &bswap ($Zlh);
+ &bswap ($Zhh);
+}
+
+&function_begin("gcm_gmult_4bit_mmx");
+ &mov ($inp,&wparam(0)); # load Xi
+ &mov ($Htbl,&wparam(1)); # load Htable
+
+ &call (&label("pic_point"));
+ &set_label("pic_point");
+ &blindpop("eax");
+ &lea ("eax",&DWP(&label("rem_4bit")."-".&label("pic_point"),"eax"));
+
+ &movz ($Zll,&BP(15,$inp));
+
+ &mmx_loop($inp,"eax");
+
+ &emms ();
+ &mov (&DWP(12,$inp),$Zll);
+ &mov (&DWP(4,$inp),$Zhl);
+ &mov (&DWP(8,$inp),$Zlh);
+ &mov (&DWP(0,$inp),$Zhh);
+&function_end("gcm_gmult_4bit_mmx");
+
+######################################################################
+# Below subroutine is "528B" variant of "4-bit" GCM GHASH function
+# (see gcm128.c for details). It provides further 20-40% performance
+# improvement over above mentioned "May" version.
+
+&static_label("rem_8bit");
+
+&function_begin("gcm_ghash_4bit_mmx");
+{ my ($Zlo,$Zhi) = ("mm7","mm6");
+ my $rem_8bit = "esi";
+ my $Htbl = "ebx";
+
+ # parameter block
+ &mov ("eax",&wparam(0)); # Xi
+ &mov ("ebx",&wparam(1)); # Htable
+ &mov ("ecx",&wparam(2)); # inp
+ &mov ("edx",&wparam(3)); # len
+ &mov ("ebp","esp"); # original %esp
+ &call (&label("pic_point"));
+ &set_label ("pic_point");
+ &blindpop ($rem_8bit);
+ &lea ($rem_8bit,&DWP(&label("rem_8bit")."-".&label("pic_point"),$rem_8bit));
+
+ &sub ("esp",512+16+16); # allocate stack frame...
+ &and ("esp",-64); # ...and align it
+ &sub ("esp",16); # place for (u8)(H[]<<4)
+
+ &add ("edx","ecx"); # pointer to the end of input
+ &mov (&DWP(528+16+0,"esp"),"eax"); # save Xi
+ &mov (&DWP(528+16+8,"esp"),"edx"); # save inp+len
+ &mov (&DWP(528+16+12,"esp"),"ebp"); # save original %esp
+
+ { my @lo = ("mm0","mm1","mm2");
+ my @hi = ("mm3","mm4","mm5");
+ my @tmp = ("mm6","mm7");
+ my ($off1,$off2,$i) = (0,0,);
+
+ &add ($Htbl,128); # optimize for size
+ &lea ("edi",&DWP(16+128,"esp"));
+ &lea ("ebp",&DWP(16+256+128,"esp"));
+
+ # decompose Htable (low and high parts are kept separately),
+ # generate Htable[]>>4, (u8)(Htable[]<<4), save to stack...
+ for ($i=0;$i<18;$i++) {
+
+ &mov ("edx",&DWP(16*$i+8-128,$Htbl)) if ($i<16);
+ &movq ($lo[0],&QWP(16*$i+8-128,$Htbl)) if ($i<16);
+ &psllq ($tmp[1],60) if ($i>1);
+ &movq ($hi[0],&QWP(16*$i+0-128,$Htbl)) if ($i<16);
+ &por ($lo[2],$tmp[1]) if ($i>1);
+ &movq (&QWP($off1-128,"edi"),$lo[1]) if ($i>0 && $i<17);
+ &psrlq ($lo[1],4) if ($i>0 && $i<17);
+ &movq (&QWP($off1,"edi"),$hi[1]) if ($i>0 && $i<17);
+ &movq ($tmp[0],$hi[1]) if ($i>0 && $i<17);
+ &movq (&QWP($off2-128,"ebp"),$lo[2]) if ($i>1);
+ &psrlq ($hi[1],4) if ($i>0 && $i<17);
+ &movq (&QWP($off2,"ebp"),$hi[2]) if ($i>1);
+ &shl ("edx",4) if ($i<16);
+ &mov (&BP($i,"esp"),&LB("edx")) if ($i<16);
+
+ unshift (@lo,pop(@lo)); # "rotate" registers
+ unshift (@hi,pop(@hi));
+ unshift (@tmp,pop(@tmp));
+ $off1 += 8 if ($i>0);
+ $off2 += 8 if ($i>1);
+ }
+ }
+
+ &movq ($Zhi,&QWP(0,"eax"));
+ &mov ("ebx",&DWP(8,"eax"));
+ &mov ("edx",&DWP(12,"eax")); # load Xi
+
+&set_label("outer",16);
+ { my $nlo = "eax";
+ my $dat = "edx";
+ my @nhi = ("edi","ebp");
+ my @rem = ("ebx","ecx");
+ my @red = ("mm0","mm1","mm2");
+ my $tmp = "mm3";
+
+ &xor ($dat,&DWP(12,"ecx")); # merge input data
+ &xor ("ebx",&DWP(8,"ecx"));
+ &pxor ($Zhi,&QWP(0,"ecx"));
+ &lea ("ecx",&DWP(16,"ecx")); # inp+=16
+ #&mov (&DWP(528+12,"esp"),$dat); # save inp^Xi
+ &mov (&DWP(528+8,"esp"),"ebx");
+ &movq (&QWP(528+0,"esp"),$Zhi);
+ &mov (&DWP(528+16+4,"esp"),"ecx"); # save inp
+
+ &xor ($nlo,$nlo);
+ &rol ($dat,8);
+ &mov (&LB($nlo),&LB($dat));
+ &mov ($nhi[1],$nlo);
+ &and (&LB($nlo),0x0f);
+ &shr ($nhi[1],4);
+ &pxor ($red[0],$red[0]);
+ &rol ($dat,8); # next byte
+ &pxor ($red[1],$red[1]);
+ &pxor ($red[2],$red[2]);
+
+ # Just like in "May" verson modulo-schedule for critical path in
+ # 'Z.hi ^= rem_8bit[Z.lo&0xff^((u8)H[nhi]<<4)]<<48'. Final 'pxor'
+ # is scheduled so late that rem_8bit[] has to be shifted *right*
+ # by 16, which is why last argument to pinsrw is 2, which
+ # corresponds to <<32=<<48>>16...
+ for ($j=11,$i=0;$i<15;$i++) {
+
+ if ($i>0) {
+ &pxor ($Zlo,&QWP(16,"esp",$nlo,8)); # Z^=H[nlo]
+ &rol ($dat,8); # next byte
+ &pxor ($Zhi,&QWP(16+128,"esp",$nlo,8));
+
+ &pxor ($Zlo,$tmp);
+ &pxor ($Zhi,&QWP(16+256+128,"esp",$nhi[0],8));
+ &xor (&LB($rem[1]),&BP(0,"esp",$nhi[0])); # rem^(H[nhi]<<4)
+ } else {
+ &movq ($Zlo,&QWP(16,"esp",$nlo,8));
+ &movq ($Zhi,&QWP(16+128,"esp",$nlo,8));
+ }
+
+ &mov (&LB($nlo),&LB($dat));
+ &mov ($dat,&DWP(528+$j,"esp")) if (--$j%4==0);
+
+ &movd ($rem[0],$Zlo);
+ &movz ($rem[1],&LB($rem[1])) if ($i>0);
+ &psrlq ($Zlo,8); # Z>>=8
+
+ &movq ($tmp,$Zhi);
+ &mov ($nhi[0],$nlo);
+ &psrlq ($Zhi,8);
+
+ &pxor ($Zlo,&QWP(16+256+0,"esp",$nhi[1],8)); # Z^=H[nhi]>>4
+ &and (&LB($nlo),0x0f);
+ &psllq ($tmp,56);
+
+ &pxor ($Zhi,$red[1]) if ($i>1);
+ &shr ($nhi[0],4);
+ &pinsrw ($red[0],&WP(0,$rem_8bit,$rem[1],2),2) if ($i>0);
+
+ unshift (@red,pop(@red)); # "rotate" registers
+ unshift (@rem,pop(@rem));
+ unshift (@nhi,pop(@nhi));
+ }
+
+ &pxor ($Zlo,&QWP(16,"esp",$nlo,8)); # Z^=H[nlo]
+ &pxor ($Zhi,&QWP(16+128,"esp",$nlo,8));
+ &xor (&LB($rem[1]),&BP(0,"esp",$nhi[0])); # rem^(H[nhi]<<4)
+
+ &pxor ($Zlo,$tmp);
+ &pxor ($Zhi,&QWP(16+256+128,"esp",$nhi[0],8));
+ &movz ($rem[1],&LB($rem[1]));
+
+ &pxor ($red[2],$red[2]); # clear 2nd word
+ &psllq ($red[1],4);
+
+ &movd ($rem[0],$Zlo);
+ &psrlq ($Zlo,4); # Z>>=4
+
+ &movq ($tmp,$Zhi);
+ &psrlq ($Zhi,4);
+ &shl ($rem[0],4); # rem<<4
+
+ &pxor ($Zlo,&QWP(16,"esp",$nhi[1],8)); # Z^=H[nhi]
+ &psllq ($tmp,60);
+ &movz ($rem[0],&LB($rem[0]));
+
+ &pxor ($Zlo,$tmp);
+ &pxor ($Zhi,&QWP(16+128,"esp",$nhi[1],8));
+
+ &pinsrw ($red[0],&WP(0,$rem_8bit,$rem[1],2),2);
+ &pxor ($Zhi,$red[1]);
+
+ &movd ($dat,$Zlo);
+ &pinsrw ($red[2],&WP(0,$rem_8bit,$rem[0],2),3); # last is <<48
+
+ &psllq ($red[0],12); # correct by <<16>>4
+ &pxor ($Zhi,$red[0]);
+ &psrlq ($Zlo,32);
+ &pxor ($Zhi,$red[2]);
+
+ &mov ("ecx",&DWP(528+16+4,"esp")); # restore inp
+ &movd ("ebx",$Zlo);
+ &movq ($tmp,$Zhi); # 01234567
+ &psllw ($Zhi,8); # 1.3.5.7.
+ &psrlw ($tmp,8); # .0.2.4.6
+ &por ($Zhi,$tmp); # 10325476
+ &bswap ($dat);
+ &pshufw ($Zhi,$Zhi,0b00011011); # 76543210
+ &bswap ("ebx");
+
+ &cmp ("ecx",&DWP(528+16+8,"esp")); # are we done?
+ &jne (&label("outer"));
+ }
+
+ &mov ("eax",&DWP(528+16+0,"esp")); # restore Xi
+ &mov (&DWP(12,"eax"),"edx");
+ &mov (&DWP(8,"eax"),"ebx");
+ &movq (&QWP(0,"eax"),$Zhi);
+
+ &mov ("esp",&DWP(528+16+12,"esp")); # restore original %esp
+ &emms ();
+}
+&function_end("gcm_ghash_4bit_mmx");
+}}
+
+if ($sse2) {{
+######################################################################
+# PCLMULQDQ version.
+
+$Xip="eax";
+$Htbl="edx";
+$const="ecx";
+$inp="esi";
+$len="ebx";
+
+($Xi,$Xhi)=("xmm0","xmm1"); $Hkey="xmm2";
+($T1,$T2,$T3)=("xmm3","xmm4","xmm5");
+($Xn,$Xhn)=("xmm6","xmm7");
+
+&static_label("bswap");
+
+sub clmul64x64_T2 { # minimal "register" pressure
+my ($Xhi,$Xi,$Hkey,$HK)=@_;
+
+ &movdqa ($Xhi,$Xi); #
+ &pshufd ($T1,$Xi,0b01001110);
+ &pshufd ($T2,$Hkey,0b01001110) if (!defined($HK));
+ &pxor ($T1,$Xi); #
+ &pxor ($T2,$Hkey) if (!defined($HK));
+ $HK=$T2 if (!defined($HK));
+
+ &pclmulqdq ($Xi,$Hkey,0x00); #######
+ &pclmulqdq ($Xhi,$Hkey,0x11); #######
+ &pclmulqdq ($T1,$HK,0x00); #######
+ &xorps ($T1,$Xi); #
+ &xorps ($T1,$Xhi); #
+
+ &movdqa ($T2,$T1); #
+ &psrldq ($T1,8);
+ &pslldq ($T2,8); #
+ &pxor ($Xhi,$T1);
+ &pxor ($Xi,$T2); #
+}
+
+sub clmul64x64_T3 {
+# Even though this subroutine offers visually better ILP, it
+# was empirically found to be a tad slower than above version.
+# At least in gcm_ghash_clmul context. But it's just as well,
+# because loop modulo-scheduling is possible only thanks to
+# minimized "register" pressure...
+my ($Xhi,$Xi,$Hkey)=@_;
+
+ &movdqa ($T1,$Xi); #
+ &movdqa ($Xhi,$Xi);
+ &pclmulqdq ($Xi,$Hkey,0x00); #######
+ &pclmulqdq ($Xhi,$Hkey,0x11); #######
+ &pshufd ($T2,$T1,0b01001110); #
+ &pshufd ($T3,$Hkey,0b01001110);
+ &pxor ($T2,$T1); #
+ &pxor ($T3,$Hkey);
+ &pclmulqdq ($T2,$T3,0x00); #######
+ &pxor ($T2,$Xi); #
+ &pxor ($T2,$Xhi); #
+
+ &movdqa ($T3,$T2); #
+ &psrldq ($T2,8);
+ &pslldq ($T3,8); #
+ &pxor ($Xhi,$T2);
+ &pxor ($Xi,$T3); #
+}
+
+if (1) { # Algorithm 9 with <<1 twist.
+ # Reduction is shorter and uses only two
+ # temporary registers, which makes it better
+ # candidate for interleaving with 64x64
+ # multiplication. Pre-modulo-scheduled loop
+ # was found to be ~20% faster than Algorithm 5
+ # below. Algorithm 9 was therefore chosen for
+ # further optimization...
+
+sub reduction_alg9 { # 17/11 times faster than Intel version
+my ($Xhi,$Xi) = @_;
+
+ # 1st phase
+ &movdqa ($T2,$Xi); #
+ &movdqa ($T1,$Xi);
+ &psllq ($Xi,5);
+ &pxor ($T1,$Xi); #
+ &psllq ($Xi,1);
+ &pxor ($Xi,$T1); #
+ &psllq ($Xi,57); #
+ &movdqa ($T1,$Xi); #
+ &pslldq ($Xi,8);
+ &psrldq ($T1,8); #
+ &pxor ($Xi,$T2);
+ &pxor ($Xhi,$T1); #
+
+ # 2nd phase
+ &movdqa ($T2,$Xi);
+ &psrlq ($Xi,1);
+ &pxor ($Xhi,$T2); #
+ &pxor ($T2,$Xi);
+ &psrlq ($Xi,5);
+ &pxor ($Xi,$T2); #
+ &psrlq ($Xi,1); #
+ &pxor ($Xi,$Xhi) #
+}
+
+&function_begin_B("gcm_init_clmul");
+ &mov ($Htbl,&wparam(0));
+ &mov ($Xip,&wparam(1));
+
+ &call (&label("pic"));
+&set_label("pic");
+ &blindpop ($const);
+ &lea ($const,&DWP(&label("bswap")."-".&label("pic"),$const));
+
+ &movdqu ($Hkey,&QWP(0,$Xip));
+ &pshufd ($Hkey,$Hkey,0b01001110);# dword swap
+
+ # <<1 twist
+ &pshufd ($T2,$Hkey,0b11111111); # broadcast uppermost dword
+ &movdqa ($T1,$Hkey);
+ &psllq ($Hkey,1);
+ &pxor ($T3,$T3); #
+ &psrlq ($T1,63);
+ &pcmpgtd ($T3,$T2); # broadcast carry bit
+ &pslldq ($T1,8);
+ &por ($Hkey,$T1); # H<<=1
+
+ # magic reduction
+ &pand ($T3,&QWP(16,$const)); # 0x1c2_polynomial
+ &pxor ($Hkey,$T3); # if(carry) H^=0x1c2_polynomial
+
+ # calculate H^2
+ &movdqa ($Xi,$Hkey);
+ &clmul64x64_T2 ($Xhi,$Xi,$Hkey);
+ &reduction_alg9 ($Xhi,$Xi);
+
+ &pshufd ($T1,$Hkey,0b01001110);
+ &pshufd ($T2,$Xi,0b01001110);
+ &pxor ($T1,$Hkey); # Karatsuba pre-processing
+ &movdqu (&QWP(0,$Htbl),$Hkey); # save H
+ &pxor ($T2,$Xi); # Karatsuba pre-processing
+ &movdqu (&QWP(16,$Htbl),$Xi); # save H^2
+ &palignr ($T2,$T1,8); # low part is H.lo^H.hi
+ &movdqu (&QWP(32,$Htbl),$T2); # save Karatsuba "salt"
+
+ &ret ();
+&function_end_B("gcm_init_clmul");
+
+&function_begin_B("gcm_gmult_clmul");
+ &mov ($Xip,&wparam(0));
+ &mov ($Htbl,&wparam(1));
+
+ &call (&label("pic"));
+&set_label("pic");
+ &blindpop ($const);
+ &lea ($const,&DWP(&label("bswap")."-".&label("pic"),$const));
+
+ &movdqu ($Xi,&QWP(0,$Xip));
+ &movdqa ($T3,&QWP(0,$const));
+ &movups ($Hkey,&QWP(0,$Htbl));
+ &pshufb ($Xi,$T3);
+ &movups ($T2,&QWP(32,$Htbl));
+
+ &clmul64x64_T2 ($Xhi,$Xi,$Hkey,$T2);
+ &reduction_alg9 ($Xhi,$Xi);
+
+ &pshufb ($Xi,$T3);
+ &movdqu (&QWP(0,$Xip),$Xi);
+
+ &ret ();
+&function_end_B("gcm_gmult_clmul");
+
+&function_begin("gcm_ghash_clmul");
+ &mov ($Xip,&wparam(0));
+ &mov ($Htbl,&wparam(1));
+ &mov ($inp,&wparam(2));
+ &mov ($len,&wparam(3));
+
+ &call (&label("pic"));
+&set_label("pic");
+ &blindpop ($const);
+ &lea ($const,&DWP(&label("bswap")."-".&label("pic"),$const));
+
+ &movdqu ($Xi,&QWP(0,$Xip));
+ &movdqa ($T3,&QWP(0,$const));
+ &movdqu ($Hkey,&QWP(0,$Htbl));
+ &pshufb ($Xi,$T3);
+
+ &sub ($len,0x10);
+ &jz (&label("odd_tail"));
+
+ #######
+ # Xi+2 =[H*(Ii+1 + Xi+1)] mod P =
+ # [(H*Ii+1) + (H*Xi+1)] mod P =
+ # [(H*Ii+1) + H^2*(Ii+Xi)] mod P
+ #
+ &movdqu ($T1,&QWP(0,$inp)); # Ii
+ &movdqu ($Xn,&QWP(16,$inp)); # Ii+1
+ &pshufb ($T1,$T3);
+ &pshufb ($Xn,$T3);
+ &movdqu ($T3,&QWP(32,$Htbl));
+ &pxor ($Xi,$T1); # Ii+Xi
+
+ &pshufd ($T1,$Xn,0b01001110); # H*Ii+1
+ &movdqa ($Xhn,$Xn);
+ &pxor ($T1,$Xn); #
+
+ &pclmulqdq ($Xn,$Hkey,0x00); #######
+ &pclmulqdq ($Xhn,$Hkey,0x11); #######
+ &movups ($Hkey,&QWP(16,$Htbl)); # load H^2
+ &pclmulqdq ($T1,$T3,0x00); #######
+
+ &lea ($inp,&DWP(32,$inp)); # i+=2
+ &sub ($len,0x20);
+ &jbe (&label("even_tail"));
+ &jmp (&label("mod_loop"));
+
+&set_label("mod_loop",32);
+ &pshufd ($T2,$Xi,0b01001110); # H^2*(Ii+Xi)
+ &movdqa ($Xhi,$Xi);
+ &pxor ($T2,$Xi); #
+
+ &pclmulqdq ($Xi,$Hkey,0x00); #######
+ &pclmulqdq ($Xhi,$Hkey,0x11); #######
+ &movups ($Hkey,&QWP(0,$Htbl)); # load H
+ &pclmulqdq ($T2,$T3,0x10); #######
+ &movdqa ($T3,&QWP(0,$const));
+
+ &xorps ($Xi,$Xn); # (H*Ii+1) + H^2*(Ii+Xi)
+ &xorps ($Xhi,$Xhn);
+ &movdqu ($Xhn,&QWP(0,$inp)); # Ii
+ &pxor ($T1,$Xi); # aggregated Karatsuba post-processing
+ &movdqu ($Xn,&QWP(16,$inp)); # Ii+1
+ &pxor ($T1,$Xhi); #
+
+ &pxor ($T2,$T1); #
+ &pshufb ($Xhn,$T3);
+
+ &movdqa ($T1,$T2); #
+ &psrldq ($T2,8);
+ &pslldq ($T1,8); #
+ &pxor ($Xhi,$T2);
+ &pxor ($Xi,$T1); #
+ &pshufb ($Xn,$T3);
+ &pxor ($Xhi,$Xhn); # "Ii+Xi", consume early
+
+ &movdqa ($Xhn,$Xn); #&clmul64x64_TX ($Xhn,$Xn,$Hkey); H*Ii+1
+ &movdqa ($T2,$Xi); #&reduction_alg9($Xhi,$Xi); 1st phase
+ &movdqa ($T1,$Xi);
+ &psllq ($Xi,5);
+ &pxor ($T1,$Xi); #
+ &psllq ($Xi,1);
+ &pxor ($Xi,$T1); #
+ &movups ($T3,&QWP(32,$Htbl));
+ &pclmulqdq ($Xn,$Hkey,0x00); #######
+ &psllq ($Xi,57); #
+ &movdqa ($T1,$Xi); #
+ &pslldq ($Xi,8);
+ &psrldq ($T1,8); #
+ &pxor ($Xi,$T2);
+ &pxor ($Xhi,$T1); #
+ &pshufd ($T1,$Xhn,0b01001110);
+ &movdqa ($T2,$Xi); # 2nd phase
+ &psrlq ($Xi,1);
+ &pxor ($T1,$Xhn);
+ &pclmulqdq ($Xhn,$Hkey,0x11); #######
+ &movups ($Hkey,&QWP(16,$Htbl)); # load H^2
+ &pxor ($Xhi,$T2); #
+ &pxor ($T2,$Xi);
+ &psrlq ($Xi,5);
+ &pxor ($Xi,$T2); #
+ &psrlq ($Xi,1); #
+ &pxor ($Xi,$Xhi) #
+ &pclmulqdq ($T1,$T3,0x00); #######
+
+ &lea ($inp,&DWP(32,$inp));
+ &sub ($len,0x20);
+ &ja (&label("mod_loop"));
+
+&set_label("even_tail");
+ &pshufd ($T2,$Xi,0b01001110); # H^2*(Ii+Xi)
+ &movdqa ($Xhi,$Xi);
+ &pxor ($T2,$Xi); #
+
+ &pclmulqdq ($Xi,$Hkey,0x00); #######
+ &pclmulqdq ($Xhi,$Hkey,0x11); #######
+ &pclmulqdq ($T2,$T3,0x10); #######
+ &movdqa ($T3,&QWP(0,$const));
+
+ &xorps ($Xi,$Xn); # (H*Ii+1) + H^2*(Ii+Xi)
+ &xorps ($Xhi,$Xhn);
+ &pxor ($T1,$Xi); # aggregated Karatsuba post-processing
+ &pxor ($T1,$Xhi); #
+
+ &pxor ($T2,$T1); #
+
+ &movdqa ($T1,$T2); #
+ &psrldq ($T2,8);
+ &pslldq ($T1,8); #
+ &pxor ($Xhi,$T2);
+ &pxor ($Xi,$T1); #
+
+ &reduction_alg9 ($Xhi,$Xi);
+
+ &test ($len,$len);
+ &jnz (&label("done"));
+
+ &movups ($Hkey,&QWP(0,$Htbl)); # load H
+&set_label("odd_tail");
+ &movdqu ($T1,&QWP(0,$inp)); # Ii
+ &pshufb ($T1,$T3);
+ &pxor ($Xi,$T1); # Ii+Xi
+
+ &clmul64x64_T2 ($Xhi,$Xi,$Hkey); # H*(Ii+Xi)
+ &reduction_alg9 ($Xhi,$Xi);
+
+&set_label("done");
+ &pshufb ($Xi,$T3);
+ &movdqu (&QWP(0,$Xip),$Xi);
+&function_end("gcm_ghash_clmul");
+
+} else { # Algorith 5. Kept for reference purposes.
+
+sub reduction_alg5 { # 19/16 times faster than Intel version
+my ($Xhi,$Xi)=@_;
+
+ # <<1
+ &movdqa ($T1,$Xi); #
+ &movdqa ($T2,$Xhi);
+ &pslld ($Xi,1);
+ &pslld ($Xhi,1); #
+ &psrld ($T1,31);
+ &psrld ($T2,31); #
+ &movdqa ($T3,$T1);
+ &pslldq ($T1,4);
+ &psrldq ($T3,12); #
+ &pslldq ($T2,4);
+ &por ($Xhi,$T3); #
+ &por ($Xi,$T1);
+ &por ($Xhi,$T2); #
+
+ # 1st phase
+ &movdqa ($T1,$Xi);
+ &movdqa ($T2,$Xi);
+ &movdqa ($T3,$Xi); #
+ &pslld ($T1,31);
+ &pslld ($T2,30);
+ &pslld ($Xi,25); #
+ &pxor ($T1,$T2);
+ &pxor ($T1,$Xi); #
+ &movdqa ($T2,$T1); #
+ &pslldq ($T1,12);
+ &psrldq ($T2,4); #
+ &pxor ($T3,$T1);
+
+ # 2nd phase
+ &pxor ($Xhi,$T3); #
+ &movdqa ($Xi,$T3);
+ &movdqa ($T1,$T3);
+ &psrld ($Xi,1); #
+ &psrld ($T1,2);
+ &psrld ($T3,7); #
+ &pxor ($Xi,$T1);
+ &pxor ($Xhi,$T2);
+ &pxor ($Xi,$T3); #
+ &pxor ($Xi,$Xhi); #
+}
+
+&function_begin_B("gcm_init_clmul");
+ &mov ($Htbl,&wparam(0));
+ &mov ($Xip,&wparam(1));
+
+ &call (&label("pic"));
+&set_label("pic");
+ &blindpop ($const);
+ &lea ($const,&DWP(&label("bswap")."-".&label("pic"),$const));
+
+ &movdqu ($Hkey,&QWP(0,$Xip));
+ &pshufd ($Hkey,$Hkey,0b01001110);# dword swap
+
+ # calculate H^2
+ &movdqa ($Xi,$Hkey);
+ &clmul64x64_T3 ($Xhi,$Xi,$Hkey);
+ &reduction_alg5 ($Xhi,$Xi);
+
+ &movdqu (&QWP(0,$Htbl),$Hkey); # save H
+ &movdqu (&QWP(16,$Htbl),$Xi); # save H^2
+
+ &ret ();
+&function_end_B("gcm_init_clmul");
+
+&function_begin_B("gcm_gmult_clmul");
+ &mov ($Xip,&wparam(0));
+ &mov ($Htbl,&wparam(1));
+
+ &call (&label("pic"));
+&set_label("pic");
+ &blindpop ($const);
+ &lea ($const,&DWP(&label("bswap")."-".&label("pic"),$const));
+
+ &movdqu ($Xi,&QWP(0,$Xip));
+ &movdqa ($Xn,&QWP(0,$const));
+ &movdqu ($Hkey,&QWP(0,$Htbl));
+ &pshufb ($Xi,$Xn);
+
+ &clmul64x64_T3 ($Xhi,$Xi,$Hkey);
+ &reduction_alg5 ($Xhi,$Xi);
+
+ &pshufb ($Xi,$Xn);
+ &movdqu (&QWP(0,$Xip),$Xi);
+
+ &ret ();
+&function_end_B("gcm_gmult_clmul");
+
+&function_begin("gcm_ghash_clmul");
+ &mov ($Xip,&wparam(0));
+ &mov ($Htbl,&wparam(1));
+ &mov ($inp,&wparam(2));
+ &mov ($len,&wparam(3));
+
+ &call (&label("pic"));
+&set_label("pic");
+ &blindpop ($const);
+ &lea ($const,&DWP(&label("bswap")."-".&label("pic"),$const));
+
+ &movdqu ($Xi,&QWP(0,$Xip));
+ &movdqa ($T3,&QWP(0,$const));
+ &movdqu ($Hkey,&QWP(0,$Htbl));
+ &pshufb ($Xi,$T3);
+
+ &sub ($len,0x10);
+ &jz (&label("odd_tail"));
+
+ #######
+ # Xi+2 =[H*(Ii+1 + Xi+1)] mod P =
+ # [(H*Ii+1) + (H*Xi+1)] mod P =
+ # [(H*Ii+1) + H^2*(Ii+Xi)] mod P
+ #
+ &movdqu ($T1,&QWP(0,$inp)); # Ii
+ &movdqu ($Xn,&QWP(16,$inp)); # Ii+1
+ &pshufb ($T1,$T3);
+ &pshufb ($Xn,$T3);
+ &pxor ($Xi,$T1); # Ii+Xi
+
+ &clmul64x64_T3 ($Xhn,$Xn,$Hkey); # H*Ii+1
+ &movdqu ($Hkey,&QWP(16,$Htbl)); # load H^2
+
+ &sub ($len,0x20);
+ &lea ($inp,&DWP(32,$inp)); # i+=2
+ &jbe (&label("even_tail"));
+
+&set_label("mod_loop");
+ &clmul64x64_T3 ($Xhi,$Xi,$Hkey); # H^2*(Ii+Xi)
+ &movdqu ($Hkey,&QWP(0,$Htbl)); # load H
+
+ &pxor ($Xi,$Xn); # (H*Ii+1) + H^2*(Ii+Xi)
+ &pxor ($Xhi,$Xhn);
+
+ &reduction_alg5 ($Xhi,$Xi);
+
+ #######
+ &movdqa ($T3,&QWP(0,$const));
+ &movdqu ($T1,&QWP(0,$inp)); # Ii
+ &movdqu ($Xn,&QWP(16,$inp)); # Ii+1
+ &pshufb ($T1,$T3);
+ &pshufb ($Xn,$T3);
+ &pxor ($Xi,$T1); # Ii+Xi
+
+ &clmul64x64_T3 ($Xhn,$Xn,$Hkey); # H*Ii+1
+ &movdqu ($Hkey,&QWP(16,$Htbl)); # load H^2
+
+ &sub ($len,0x20);
+ &lea ($inp,&DWP(32,$inp));
+ &ja (&label("mod_loop"));
+
+&set_label("even_tail");
+ &clmul64x64_T3 ($Xhi,$Xi,$Hkey); # H^2*(Ii+Xi)
+
+ &pxor ($Xi,$Xn); # (H*Ii+1) + H^2*(Ii+Xi)
+ &pxor ($Xhi,$Xhn);
+
+ &reduction_alg5 ($Xhi,$Xi);
+
+ &movdqa ($T3,&QWP(0,$const));
+ &test ($len,$len);
+ &jnz (&label("done"));
+
+ &movdqu ($Hkey,&QWP(0,$Htbl)); # load H
+&set_label("odd_tail");
+ &movdqu ($T1,&QWP(0,$inp)); # Ii
+ &pshufb ($T1,$T3);
+ &pxor ($Xi,$T1); # Ii+Xi
+
+ &clmul64x64_T3 ($Xhi,$Xi,$Hkey); # H*(Ii+Xi)
+ &reduction_alg5 ($Xhi,$Xi);
+
+ &movdqa ($T3,&QWP(0,$const));
+&set_label("done");
+ &pshufb ($Xi,$T3);
+ &movdqu (&QWP(0,$Xip),$Xi);
+&function_end("gcm_ghash_clmul");
+
+}
+
+&set_label("bswap",64);
+ &data_byte(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0);
+ &data_byte(1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xc2); # 0x1c2_polynomial
+&set_label("rem_8bit",64);
+ &data_short(0x0000,0x01C2,0x0384,0x0246,0x0708,0x06CA,0x048C,0x054E);
+ &data_short(0x0E10,0x0FD2,0x0D94,0x0C56,0x0918,0x08DA,0x0A9C,0x0B5E);
+ &data_short(0x1C20,0x1DE2,0x1FA4,0x1E66,0x1B28,0x1AEA,0x18AC,0x196E);
+ &data_short(0x1230,0x13F2,0x11B4,0x1076,0x1538,0x14FA,0x16BC,0x177E);
+ &data_short(0x3840,0x3982,0x3BC4,0x3A06,0x3F48,0x3E8A,0x3CCC,0x3D0E);
+ &data_short(0x3650,0x3792,0x35D4,0x3416,0x3158,0x309A,0x32DC,0x331E);
+ &data_short(0x2460,0x25A2,0x27E4,0x2626,0x2368,0x22AA,0x20EC,0x212E);
+ &data_short(0x2A70,0x2BB2,0x29F4,0x2836,0x2D78,0x2CBA,0x2EFC,0x2F3E);
+ &data_short(0x7080,0x7142,0x7304,0x72C6,0x7788,0x764A,0x740C,0x75CE);
+ &data_short(0x7E90,0x7F52,0x7D14,0x7CD6,0x7998,0x785A,0x7A1C,0x7BDE);
+ &data_short(0x6CA0,0x6D62,0x6F24,0x6EE6,0x6BA8,0x6A6A,0x682C,0x69EE);
+ &data_short(0x62B0,0x6372,0x6134,0x60F6,0x65B8,0x647A,0x663C,0x67FE);
+ &data_short(0x48C0,0x4902,0x4B44,0x4A86,0x4FC8,0x4E0A,0x4C4C,0x4D8E);
+ &data_short(0x46D0,0x4712,0x4554,0x4496,0x41D8,0x401A,0x425C,0x439E);
+ &data_short(0x54E0,0x5522,0x5764,0x56A6,0x53E8,0x522A,0x506C,0x51AE);
+ &data_short(0x5AF0,0x5B32,0x5974,0x58B6,0x5DF8,0x5C3A,0x5E7C,0x5FBE);
+ &data_short(0xE100,0xE0C2,0xE284,0xE346,0xE608,0xE7CA,0xE58C,0xE44E);
+ &data_short(0xEF10,0xEED2,0xEC94,0xED56,0xE818,0xE9DA,0xEB9C,0xEA5E);
+ &data_short(0xFD20,0xFCE2,0xFEA4,0xFF66,0xFA28,0xFBEA,0xF9AC,0xF86E);
+ &data_short(0xF330,0xF2F2,0xF0B4,0xF176,0xF438,0xF5FA,0xF7BC,0xF67E);
+ &data_short(0xD940,0xD882,0xDAC4,0xDB06,0xDE48,0xDF8A,0xDDCC,0xDC0E);
+ &data_short(0xD750,0xD692,0xD4D4,0xD516,0xD058,0xD19A,0xD3DC,0xD21E);
+ &data_short(0xC560,0xC4A2,0xC6E4,0xC726,0xC268,0xC3AA,0xC1EC,0xC02E);
+ &data_short(0xCB70,0xCAB2,0xC8F4,0xC936,0xCC78,0xCDBA,0xCFFC,0xCE3E);
+ &data_short(0x9180,0x9042,0x9204,0x93C6,0x9688,0x974A,0x950C,0x94CE);
+ &data_short(0x9F90,0x9E52,0x9C14,0x9DD6,0x9898,0x995A,0x9B1C,0x9ADE);
+ &data_short(0x8DA0,0x8C62,0x8E24,0x8FE6,0x8AA8,0x8B6A,0x892C,0x88EE);
+ &data_short(0x83B0,0x8272,0x8034,0x81F6,0x84B8,0x857A,0x873C,0x86FE);
+ &data_short(0xA9C0,0xA802,0xAA44,0xAB86,0xAEC8,0xAF0A,0xAD4C,0xAC8E);
+ &data_short(0xA7D0,0xA612,0xA454,0xA596,0xA0D8,0xA11A,0xA35C,0xA29E);
+ &data_short(0xB5E0,0xB422,0xB664,0xB7A6,0xB2E8,0xB32A,0xB16C,0xB0AE);
+ &data_short(0xBBF0,0xBA32,0xB874,0xB9B6,0xBCF8,0xBD3A,0xBF7C,0xBEBE);
+}} # $sse2
+
+&set_label("rem_4bit",64);
+ &data_word(0,0x0000<<$S,0,0x1C20<<$S,0,0x3840<<$S,0,0x2460<<$S);
+ &data_word(0,0x7080<<$S,0,0x6CA0<<$S,0,0x48C0<<$S,0,0x54E0<<$S);
+ &data_word(0,0xE100<<$S,0,0xFD20<<$S,0,0xD940<<$S,0,0xC560<<$S);
+ &data_word(0,0x9180<<$S,0,0x8DA0<<$S,0,0xA9C0<<$S,0,0xB5E0<<$S);
+}}} # !$x86only
+
+&asciz("GHASH for x86, CRYPTOGAMS by <appro\@openssl.org>");
+&asm_finish();
+
+# A question was risen about choice of vanilla MMX. Or rather why wasn't
+# SSE2 chosen instead? In addition to the fact that MMX runs on legacy
+# CPUs such as PIII, "4-bit" MMX version was observed to provide better
+# performance than *corresponding* SSE2 one even on contemporary CPUs.
+# SSE2 results were provided by Peter-Michael Hager. He maintains SSE2
+# implementation featuring full range of lookup-table sizes, but with
+# per-invocation lookup table setup. Latter means that table size is
+# chosen depending on how much data is to be hashed in every given call,
+# more data - larger table. Best reported result for Core2 is ~4 cycles
+# per processed byte out of 64KB block. This number accounts even for
+# 64KB table setup overhead. As discussed in gcm128.c we choose to be
+# more conservative in respect to lookup table sizes, but how do the
+# results compare? Minimalistic "256B" MMX version delivers ~11 cycles
+# on same platform. As also discussed in gcm128.c, next in line "8-bit
+# Shoup's" or "4KB" method should deliver twice the performance of
+# "256B" one, in other words not worse than ~6 cycles per byte. It
+# should be also be noted that in SSE2 case improvement can be "super-
+# linear," i.e. more than twice, mostly because >>8 maps to single
+# instruction on SSE2 register. This is unlike "4-bit" case when >>4
+# maps to same amount of instructions in both MMX and SSE2 cases.
+# Bottom line is that switch to SSE2 is considered to be justifiable
+# only in case we choose to implement "8-bit" method...
diff --git a/crypto/modes/asm/ghash-x86_64.pl b/crypto/modes/asm/ghash-x86_64.pl
new file mode 100644
index 0000000..7904248
--- /dev/null
+++ b/crypto/modes/asm/ghash-x86_64.pl
@@ -0,0 +1,1736 @@
+#!/usr/bin/env perl
+#
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+#
+# March, June 2010
+#
+# The module implements "4-bit" GCM GHASH function and underlying
+# single multiplication operation in GF(2^128). "4-bit" means that
+# it uses 256 bytes per-key table [+128 bytes shared table]. GHASH
+# function features so called "528B" variant utilizing additional
+# 256+16 bytes of per-key storage [+512 bytes shared table].
+# Performance results are for this streamed GHASH subroutine and are
+# expressed in cycles per processed byte, less is better:
+#
+# gcc 3.4.x(*) assembler
+#
+# P4 28.6 14.0 +100%
+# Opteron 19.3 7.7 +150%
+# Core2 17.8 8.1(**) +120%
+# Atom 31.6 16.8 +88%
+# VIA Nano 21.8 10.1 +115%
+#
+# (*) comparison is not completely fair, because C results are
+# for vanilla "256B" implementation, while assembler results
+# are for "528B";-)
+# (**) it's mystery [to me] why Core2 result is not same as for
+# Opteron;
+
+# May 2010
+#
+# Add PCLMULQDQ version performing at 2.02 cycles per processed byte.
+# See ghash-x86.pl for background information and details about coding
+# techniques.
+#
+# Special thanks to David Woodhouse <dwmw2@infradead.org> for
+# providing access to a Westmere-based system on behalf of Intel
+# Open Source Technology Centre.
+
+# December 2012
+#
+# Overhaul: aggregate Karatsuba post-processing, improve ILP in
+# reduction_alg9, increase reduction aggregate factor to 4x. As for
+# the latter. ghash-x86.pl discusses that it makes lesser sense to
+# increase aggregate factor. Then why increase here? Critical path
+# consists of 3 independent pclmulqdq instructions, Karatsuba post-
+# processing and reduction. "On top" of this we lay down aggregated
+# multiplication operations, triplets of independent pclmulqdq's. As
+# issue rate for pclmulqdq is limited, it makes lesser sense to
+# aggregate more multiplications than it takes to perform remaining
+# non-multiplication operations. 2x is near-optimal coefficient for
+# contemporary Intel CPUs (therefore modest improvement coefficient),
+# but not for Bulldozer. Latter is because logical SIMD operations
+# are twice as slow in comparison to Intel, so that critical path is
+# longer. A CPU with higher pclmulqdq issue rate would also benefit
+# from higher aggregate factor...
+#
+# Westmere 1.76(+14%)
+# Sandy Bridge 1.79(+9%)
+# Ivy Bridge 1.79(+8%)
+# Haswell 0.55(+93%) (if system doesn't support AVX)
+# Bulldozer 1.52(+25%)
+
+# March 2013
+#
+# ... 8x aggregate factor AVX code path is using reduction algorithm
+# suggested by Shay Gueron[1]. Even though contemporary AVX-capable
+# CPUs such as Sandy and Ivy Bridge can execute it, the code performs
+# sub-optimally in comparison to above mentioned version. But thanks
+# to Ilya Albrekht and Max Locktyukhin of Intel Corp. we knew that
+# it performs in 0.41 cycles per byte on Haswell processor.
+#
+# [1] http://rt.openssl.org/Ticket/Display.html?id=2900&user=guest&pass=guest
+
+$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";
+
+if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
+ =~ /GNU assembler version ([2-9]\.[0-9]+)/) {
+ $avx = ($1>=2.19) + ($1>=2.22);
+}
+
+if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
+ `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
+ $avx = ($1>=2.09) + ($1>=2.10);
+}
+
+if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
+ `ml64 2>&1` =~ /Version ([0-9]+)\./) {
+ $avx = ($1>=10) + ($1>=11);
+}
+
+open OUT,"| \"$^X\" $xlate $flavour $output";
+*STDOUT=*OUT;
+
+$do4xaggr=1;
+
+# common register layout
+$nlo="%rax";
+$nhi="%rbx";
+$Zlo="%r8";
+$Zhi="%r9";
+$tmp="%r10";
+$rem_4bit = "%r11";
+
+$Xi="%rdi";
+$Htbl="%rsi";
+
+# per-function register layout
+$cnt="%rcx";
+$rem="%rdx";
+
+sub LB() { my $r=shift; $r =~ s/%[er]([a-d])x/%\1l/ or
+ $r =~ s/%[er]([sd]i)/%\1l/ or
+ $r =~ s/%[er](bp)/%\1l/ or
+ $r =~ s/%(r[0-9]+)[d]?/%\1b/; $r; }
+
+sub AUTOLOAD() # thunk [simplified] 32-bit style perlasm
+{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://;
+ my $arg = pop;
+ $arg = "\$$arg" if ($arg*1 eq $arg);
+ $code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n";
+}
+
+{ my $N;
+ sub loop() {
+ my $inp = shift;
+
+ $N++;
+$code.=<<___;
+ xor $nlo,$nlo
+ xor $nhi,$nhi
+ mov `&LB("$Zlo")`,`&LB("$nlo")`
+ mov `&LB("$Zlo")`,`&LB("$nhi")`
+ shl \$4,`&LB("$nlo")`
+ mov \$14,$cnt
+ mov 8($Htbl,$nlo),$Zlo
+ mov ($Htbl,$nlo),$Zhi
+ and \$0xf0,`&LB("$nhi")`
+ mov $Zlo,$rem
+ jmp .Loop$N
+
+.align 16
+.Loop$N:
+ shr \$4,$Zlo
+ and \$0xf,$rem
+ mov $Zhi,$tmp
+ mov ($inp,$cnt),`&LB("$nlo")`
+ shr \$4,$Zhi
+ xor 8($Htbl,$nhi),$Zlo
+ shl \$60,$tmp
+ xor ($Htbl,$nhi),$Zhi
+ mov `&LB("$nlo")`,`&LB("$nhi")`
+ xor ($rem_4bit,$rem,8),$Zhi
+ mov $Zlo,$rem
+ shl \$4,`&LB("$nlo")`
+ xor $tmp,$Zlo
+ dec $cnt
+ js .Lbreak$N
+
+ shr \$4,$Zlo
+ and \$0xf,$rem
+ mov $Zhi,$tmp
+ shr \$4,$Zhi
+ xor 8($Htbl,$nlo),$Zlo
+ shl \$60,$tmp
+ xor ($Htbl,$nlo),$Zhi
+ and \$0xf0,`&LB("$nhi")`
+ xor ($rem_4bit,$rem,8),$Zhi
+ mov $Zlo,$rem
+ xor $tmp,$Zlo
+ jmp .Loop$N
+
+.align 16
+.Lbreak$N:
+ shr \$4,$Zlo
+ and \$0xf,$rem
+ mov $Zhi,$tmp
+ shr \$4,$Zhi
+ xor 8($Htbl,$nlo),$Zlo
+ shl \$60,$tmp
+ xor ($Htbl,$nlo),$Zhi
+ and \$0xf0,`&LB("$nhi")`
+ xor ($rem_4bit,$rem,8),$Zhi
+ mov $Zlo,$rem
+ xor $tmp,$Zlo
+
+ shr \$4,$Zlo
+ and \$0xf,$rem
+ mov $Zhi,$tmp
+ shr \$4,$Zhi
+ xor 8($Htbl,$nhi),$Zlo
+ shl \$60,$tmp
+ xor ($Htbl,$nhi),$Zhi
+ xor $tmp,$Zlo
+ xor ($rem_4bit,$rem,8),$Zhi
+
+ bswap $Zlo
+ bswap $Zhi
+___
+}}
+
+$code=<<___;
+.text
+
+.globl gcm_gmult_4bit
+.type gcm_gmult_4bit,\@function,2
+.align 16
+gcm_gmult_4bit:
+ push %rbx
+ push %rbp # %rbp and %r12 are pushed exclusively in
+ push %r12 # order to reuse Win64 exception handler...
+.Lgmult_prologue:
+
+ movzb 15($Xi),$Zlo
+ lea .Lrem_4bit(%rip),$rem_4bit
+___
+ &loop ($Xi);
+$code.=<<___;
+ mov $Zlo,8($Xi)
+ mov $Zhi,($Xi)
+
+ mov 16(%rsp),%rbx
+ lea 24(%rsp),%rsp
+.Lgmult_epilogue:
+ ret
+.size gcm_gmult_4bit,.-gcm_gmult_4bit
+___
+
+# per-function register layout
+$inp="%rdx";
+$len="%rcx";
+$rem_8bit=$rem_4bit;
+
+$code.=<<___;
+.globl gcm_ghash_4bit
+.type gcm_ghash_4bit,\@function,4
+.align 16
+gcm_ghash_4bit:
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ sub \$280,%rsp
+.Lghash_prologue:
+ mov $inp,%r14 # reassign couple of args
+ mov $len,%r15
+___
+{ my $inp="%r14";
+ my $dat="%edx";
+ my $len="%r15";
+ my @nhi=("%ebx","%ecx");
+ my @rem=("%r12","%r13");
+ my $Hshr4="%rbp";
+
+ &sub ($Htbl,-128); # size optimization
+ &lea ($Hshr4,"16+128(%rsp)");
+ { my @lo =($nlo,$nhi);
+ my @hi =($Zlo,$Zhi);
+
+ &xor ($dat,$dat);
+ for ($i=0,$j=-2;$i<18;$i++,$j++) {
+ &mov ("$j(%rsp)",&LB($dat)) if ($i>1);
+ &or ($lo[0],$tmp) if ($i>1);
+ &mov (&LB($dat),&LB($lo[1])) if ($i>0 && $i<17);
+ &shr ($lo[1],4) if ($i>0 && $i<17);
+ &mov ($tmp,$hi[1]) if ($i>0 && $i<17);
+ &shr ($hi[1],4) if ($i>0 && $i<17);
+ &mov ("8*$j($Hshr4)",$hi[0]) if ($i>1);
+ &mov ($hi[0],"16*$i+0-128($Htbl)") if ($i<16);
+ &shl (&LB($dat),4) if ($i>0 && $i<17);
+ &mov ("8*$j-128($Hshr4)",$lo[0]) if ($i>1);
+ &mov ($lo[0],"16*$i+8-128($Htbl)") if ($i<16);
+ &shl ($tmp,60) if ($i>0 && $i<17);
+
+ push (@lo,shift(@lo));
+ push (@hi,shift(@hi));
+ }
+ }
+ &add ($Htbl,-128);
+ &mov ($Zlo,"8($Xi)");
+ &mov ($Zhi,"0($Xi)");
+ &add ($len,$inp); # pointer to the end of data
+ &lea ($rem_8bit,".Lrem_8bit(%rip)");
+ &jmp (".Louter_loop");
+
+$code.=".align 16\n.Louter_loop:\n";
+ &xor ($Zhi,"($inp)");
+ &mov ("%rdx","8($inp)");
+ &lea ($inp,"16($inp)");
+ &xor ("%rdx",$Zlo);
+ &mov ("($Xi)",$Zhi);
+ &mov ("8($Xi)","%rdx");
+ &shr ("%rdx",32);
+
+ &xor ($nlo,$nlo);
+ &rol ($dat,8);
+ &mov (&LB($nlo),&LB($dat));
+ &movz ($nhi[0],&LB($dat));
+ &shl (&LB($nlo),4);
+ &shr ($nhi[0],4);
+
+ for ($j=11,$i=0;$i<15;$i++) {
+ &rol ($dat,8);
+ &xor ($Zlo,"8($Htbl,$nlo)") if ($i>0);
+ &xor ($Zhi,"($Htbl,$nlo)") if ($i>0);
+ &mov ($Zlo,"8($Htbl,$nlo)") if ($i==0);
+ &mov ($Zhi,"($Htbl,$nlo)") if ($i==0);
+
+ &mov (&LB($nlo),&LB($dat));
+ &xor ($Zlo,$tmp) if ($i>0);
+ &movzw ($rem[1],"($rem_8bit,$rem[1],2)") if ($i>0);
+
+ &movz ($nhi[1],&LB($dat));
+ &shl (&LB($nlo),4);
+ &movzb ($rem[0],"(%rsp,$nhi[0])");
+
+ &shr ($nhi[1],4) if ($i<14);
+ &and ($nhi[1],0xf0) if ($i==14);
+ &shl ($rem[1],48) if ($i>0);
+ &xor ($rem[0],$Zlo);
+
+ &mov ($tmp,$Zhi);
+ &xor ($Zhi,$rem[1]) if ($i>0);
+ &shr ($Zlo,8);
+
+ &movz ($rem[0],&LB($rem[0]));
+ &mov ($dat,"$j($Xi)") if (--$j%4==0);
+ &shr ($Zhi,8);
+
+ &xor ($Zlo,"-128($Hshr4,$nhi[0],8)");
+ &shl ($tmp,56);
+ &xor ($Zhi,"($Hshr4,$nhi[0],8)");
+
+ unshift (@nhi,pop(@nhi)); # "rotate" registers
+ unshift (@rem,pop(@rem));
+ }
+ &movzw ($rem[1],"($rem_8bit,$rem[1],2)");
+ &xor ($Zlo,"8($Htbl,$nlo)");
+ &xor ($Zhi,"($Htbl,$nlo)");
+
+ &shl ($rem[1],48);
+ &xor ($Zlo,$tmp);
+
+ &xor ($Zhi,$rem[1]);
+ &movz ($rem[0],&LB($Zlo));
+ &shr ($Zlo,4);
+
+ &mov ($tmp,$Zhi);
+ &shl (&LB($rem[0]),4);
+ &shr ($Zhi,4);
+
+ &xor ($Zlo,"8($Htbl,$nhi[0])");
+ &movzw ($rem[0],"($rem_8bit,$rem[0],2)");
+ &shl ($tmp,60);
+
+ &xor ($Zhi,"($Htbl,$nhi[0])");
+ &xor ($Zlo,$tmp);
+ &shl ($rem[0],48);
+
+ &bswap ($Zlo);
+ &xor ($Zhi,$rem[0]);
+
+ &bswap ($Zhi);
+ &cmp ($inp,$len);
+ &jb (".Louter_loop");
+}
+$code.=<<___;
+ mov $Zlo,8($Xi)
+ mov $Zhi,($Xi)
+
+ lea 280(%rsp),%rsi
+ mov 0(%rsi),%r15
+ mov 8(%rsi),%r14
+ mov 16(%rsi),%r13
+ mov 24(%rsi),%r12
+ mov 32(%rsi),%rbp
+ mov 40(%rsi),%rbx
+ lea 48(%rsi),%rsp
+.Lghash_epilogue:
+ ret
+.size gcm_ghash_4bit,.-gcm_ghash_4bit
+___
+
+######################################################################
+# PCLMULQDQ version.
+
+@_4args=$win64? ("%rcx","%rdx","%r8", "%r9") : # Win64 order
+ ("%rdi","%rsi","%rdx","%rcx"); # Unix order
+
+($Xi,$Xhi)=("%xmm0","%xmm1"); $Hkey="%xmm2";
+($T1,$T2,$T3)=("%xmm3","%xmm4","%xmm5");
+
+sub clmul64x64_T2 { # minimal register pressure
+my ($Xhi,$Xi,$Hkey,$HK)=@_;
+
+if (!defined($HK)) { $HK = $T2;
+$code.=<<___;
+ movdqa $Xi,$Xhi #
+ pshufd \$0b01001110,$Xi,$T1
+ pshufd \$0b01001110,$Hkey,$T2
+ pxor $Xi,$T1 #
+ pxor $Hkey,$T2
+___
+} else {
+$code.=<<___;
+ movdqa $Xi,$Xhi #
+ pshufd \$0b01001110,$Xi,$T1
+ pxor $Xi,$T1 #
+___
+}
+$code.=<<___;
+ pclmulqdq \$0x00,$Hkey,$Xi #######
+ pclmulqdq \$0x11,$Hkey,$Xhi #######
+ pclmulqdq \$0x00,$HK,$T1 #######
+ pxor $Xi,$T1 #
+ pxor $Xhi,$T1 #
+
+ movdqa $T1,$T2 #
+ psrldq \$8,$T1
+ pslldq \$8,$T2 #
+ pxor $T1,$Xhi
+ pxor $T2,$Xi #
+___
+}
+
+sub reduction_alg9 { # 17/11 times faster than Intel version
+my ($Xhi,$Xi) = @_;
+
+$code.=<<___;
+ # 1st phase
+ movdqa $Xi,$T2 #
+ movdqa $Xi,$T1
+ psllq \$5,$Xi
+ pxor $Xi,$T1 #
+ psllq \$1,$Xi
+ pxor $T1,$Xi #
+ psllq \$57,$Xi #
+ movdqa $Xi,$T1 #
+ pslldq \$8,$Xi
+ psrldq \$8,$T1 #
+ pxor $T2,$Xi
+ pxor $T1,$Xhi #
+
+ # 2nd phase
+ movdqa $Xi,$T2
+ psrlq \$1,$Xi
+ pxor $T2,$Xhi #
+ pxor $Xi,$T2
+ psrlq \$5,$Xi
+ pxor $T2,$Xi #
+ psrlq \$1,$Xi #
+ pxor $Xhi,$Xi #
+___
+}
+
+{ my ($Htbl,$Xip)=@_4args;
+ my $HK="%xmm6";
+
+$code.=<<___;
+.globl gcm_init_clmul
+.type gcm_init_clmul,\@abi-omnipotent
+.align 16
+gcm_init_clmul:
+.L_init_clmul:
+___
+$code.=<<___ if ($win64);
+.LSEH_begin_gcm_init_clmul:
+ # I can't trust assembler to use specific encoding:-(
+ .byte 0x48,0x83,0xec,0x18 #sub $0x18,%rsp
+ .byte 0x0f,0x29,0x34,0x24 #movaps %xmm6,(%rsp)
+___
+$code.=<<___;
+ movdqu ($Xip),$Hkey
+ pshufd \$0b01001110,$Hkey,$Hkey # dword swap
+
+ # <<1 twist
+ pshufd \$0b11111111,$Hkey,$T2 # broadcast uppermost dword
+ movdqa $Hkey,$T1
+ psllq \$1,$Hkey
+ pxor $T3,$T3 #
+ psrlq \$63,$T1
+ pcmpgtd $T2,$T3 # broadcast carry bit
+ pslldq \$8,$T1
+ por $T1,$Hkey # H<<=1
+
+ # magic reduction
+ pand .L0x1c2_polynomial(%rip),$T3
+ pxor $T3,$Hkey # if(carry) H^=0x1c2_polynomial
+
+ # calculate H^2
+ pshufd \$0b01001110,$Hkey,$HK
+ movdqa $Hkey,$Xi
+ pxor $Hkey,$HK
+___
+ &clmul64x64_T2 ($Xhi,$Xi,$Hkey,$HK);
+ &reduction_alg9 ($Xhi,$Xi);
+$code.=<<___;
+ pshufd \$0b01001110,$Hkey,$T1
+ pshufd \$0b01001110,$Xi,$T2
+ pxor $Hkey,$T1 # Karatsuba pre-processing
+ movdqu $Hkey,0x00($Htbl) # save H
+ pxor $Xi,$T2 # Karatsuba pre-processing
+ movdqu $Xi,0x10($Htbl) # save H^2
+ palignr \$8,$T1,$T2 # low part is H.lo^H.hi...
+ movdqu $T2,0x20($Htbl) # save Karatsuba "salt"
+___
+if ($do4xaggr) {
+ &clmul64x64_T2 ($Xhi,$Xi,$Hkey,$HK); # H^3
+ &reduction_alg9 ($Xhi,$Xi);
+$code.=<<___;
+ movdqa $Xi,$T3
+___
+ &clmul64x64_T2 ($Xhi,$Xi,$Hkey,$HK); # H^4
+ &reduction_alg9 ($Xhi,$Xi);
+$code.=<<___;
+ pshufd \$0b01001110,$T3,$T1
+ pshufd \$0b01001110,$Xi,$T2
+ pxor $T3,$T1 # Karatsuba pre-processing
+ movdqu $T3,0x30($Htbl) # save H^3
+ pxor $Xi,$T2 # Karatsuba pre-processing
+ movdqu $Xi,0x40($Htbl) # save H^4
+ palignr \$8,$T1,$T2 # low part is H^3.lo^H^3.hi...
+ movdqu $T2,0x50($Htbl) # save Karatsuba "salt"
+___
+}
+$code.=<<___ if ($win64);
+ movaps (%rsp),%xmm6
+ lea 0x18(%rsp),%rsp
+.LSEH_end_gcm_init_clmul:
+___
+$code.=<<___;
+ ret
+.size gcm_init_clmul,.-gcm_init_clmul
+___
+}
+
+{ my ($Xip,$Htbl)=@_4args;
+
+$code.=<<___;
+.globl gcm_gmult_clmul
+.type gcm_gmult_clmul,\@abi-omnipotent
+.align 16
+gcm_gmult_clmul:
+.L_gmult_clmul:
+ movdqu ($Xip),$Xi
+ movdqa .Lbswap_mask(%rip),$T3
+ movdqu ($Htbl),$Hkey
+ movdqu 0x20($Htbl),$T2
+ pshufb $T3,$Xi
+___
+ &clmul64x64_T2 ($Xhi,$Xi,$Hkey,$T2);
+$code.=<<___ if (0 || (&reduction_alg9($Xhi,$Xi)&&0));
+ # 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 \$0x07,%r11d
+ movq %rax,$T1
+ movq %r10,$T2
+ movq %r11,$T3 # borrow $T3
+ pand $Xi,$T3
+ pshufb $T3,$T2 # ($Xi&7)·0xE0
+ movq %rax,$T3
+ pclmulqdq \$0x00,$Xi,$T1 # ·(0xE1<<1)
+ pxor $Xi,$T2
+ pslldq \$15,$T2
+ paddd $T2,$T2 # <<(64+56+1)
+ pxor $T2,$Xi
+ pclmulqdq \$0x01,$T3,$Xi
+ movdqa .Lbswap_mask(%rip),$T3 # reload $T3
+ psrldq \$1,$T1
+ pxor $T1,$Xhi
+ pslldq \$7,$Xi
+ pxor $Xhi,$Xi
+___
+$code.=<<___;
+ pshufb $T3,$Xi
+ movdqu $Xi,($Xip)
+ ret
+.size gcm_gmult_clmul,.-gcm_gmult_clmul
+___
+}
+
+{ my ($Xip,$Htbl,$inp,$len)=@_4args;
+ my ($Xln,$Xmn,$Xhn,$Hkey2,$HK) = map("%xmm$_",(6..10));
+
+$code.=<<___;
+.globl gcm_ghash_clmul
+.type gcm_ghash_clmul,\@abi-omnipotent
+.align 32
+gcm_ghash_clmul:
+.L_ghash_clmul:
+___
+$code.=<<___ if ($win64);
+ lea -0x88(%rsp),%rax
+.LSEH_begin_gcm_ghash_clmul:
+ # I can't trust assembler to use specific encoding:-(
+ .byte 0x48,0x8d,0x60,0xe0 #lea -0x20(%rax),%rsp
+ .byte 0x0f,0x29,0x70,0xe0 #movaps %xmm6,-0x20(%rax)
+ .byte 0x0f,0x29,0x78,0xf0 #movaps %xmm7,-0x10(%rax)
+ .byte 0x44,0x0f,0x29,0x00 #movaps %xmm8,0(%rax)
+ .byte 0x44,0x0f,0x29,0x48,0x10 #movaps %xmm9,0x10(%rax)
+ .byte 0x44,0x0f,0x29,0x50,0x20 #movaps %xmm10,0x20(%rax)
+ .byte 0x44,0x0f,0x29,0x58,0x30 #movaps %xmm11,0x30(%rax)
+ .byte 0x44,0x0f,0x29,0x60,0x40 #movaps %xmm12,0x40(%rax)
+ .byte 0x44,0x0f,0x29,0x68,0x50 #movaps %xmm13,0x50(%rax)
+ .byte 0x44,0x0f,0x29,0x70,0x60 #movaps %xmm14,0x60(%rax)
+ .byte 0x44,0x0f,0x29,0x78,0x70 #movaps %xmm15,0x70(%rax)
+___
+$code.=<<___;
+ movdqa .Lbswap_mask(%rip),$T3
+ mov \$0xA040608020C0E000,%rax # ((7..0)·0xE0)&0xff
+
+ movdqu ($Xip),$Xi
+ movdqu ($Htbl),$Hkey
+ movdqu 0x20($Htbl),$HK
+ pshufb $T3,$Xi
+
+ sub \$0x10,$len
+ jz .Lodd_tail
+
+ movdqu 0x10($Htbl),$Hkey2
+___
+if ($do4xaggr) {
+my ($Xl,$Xm,$Xh,$Hkey3,$Hkey4)=map("%xmm$_",(11..15));
+
+$code.=<<___;
+ cmp \$0x30,$len
+ jb .Lskip4x
+
+ sub \$0x30,$len
+ movdqu 0x30($Htbl),$Hkey3
+ movdqu 0x40($Htbl),$Hkey4
+
+ #######
+ # Xi+4 =[(H*Ii+3) + (H^2*Ii+2) + (H^3*Ii+1) + H^4*(Ii+Xi)] mod P
+ #
+ movdqu 0x30($inp),$Xln
+ movdqu 0x20($inp),$Xl
+ pshufb $T3,$Xln
+ pshufb $T3,$Xl
+ movdqa $Xln,$Xhn
+ pshufd \$0b01001110,$Xln,$Xmn
+ pxor $Xln,$Xmn
+ pclmulqdq \$0x00,$Hkey,$Xln
+ pclmulqdq \$0x11,$Hkey,$Xhn
+ pclmulqdq \$0x00,$HK,$Xmn
+
+ movdqa $Xl,$Xh
+ pshufd \$0b01001110,$Xl,$Xm
+ pxor $Xl,$Xm
+ pclmulqdq \$0x00,$Hkey2,$Xl
+ pclmulqdq \$0x11,$Hkey2,$Xh
+ xorps $Xl,$Xln
+ pclmulqdq \$0x10,$HK,$Xm
+ xorps $Xh,$Xhn
+ movups 0x50($Htbl),$HK
+ xorps $Xm,$Xmn
+
+ movdqu 0x10($inp),$Xl
+ movdqu 0($inp),$T1
+ pshufb $T3,$Xl
+ pshufb $T3,$T1
+ movdqa $Xl,$Xh
+ pshufd \$0b01001110,$Xl,$Xm
+ pxor $T1,$Xi
+ pxor $Xl,$Xm
+ pclmulqdq \$0x00,$Hkey3,$Xl
+ movdqa $Xi,$Xhi
+ pshufd \$0b01001110,$Xi,$T1
+ pxor $Xi,$T1
+ pclmulqdq \$0x11,$Hkey3,$Xh
+ xorps $Xl,$Xln
+ pclmulqdq \$0x00,$HK,$Xm
+ xorps $Xh,$Xhn
+
+ lea 0x40($inp),$inp
+ sub \$0x40,$len
+ jc .Ltail4x
+
+ jmp .Lmod4_loop
+.align 32
+.Lmod4_loop:
+ pclmulqdq \$0x00,$Hkey4,$Xi
+ xorps $Xm,$Xmn
+ movdqu 0x30($inp),$Xl
+ pshufb $T3,$Xl
+ pclmulqdq \$0x11,$Hkey4,$Xhi
+ xorps $Xln,$Xi
+ movdqu 0x20($inp),$Xln
+ movdqa $Xl,$Xh
+ pshufd \$0b01001110,$Xl,$Xm
+ pclmulqdq \$0x10,$HK,$T1
+ xorps $Xhn,$Xhi
+ pxor $Xl,$Xm
+ pshufb $T3,$Xln
+ movups 0x20($Htbl),$HK
+ pclmulqdq \$0x00,$Hkey,$Xl
+ xorps $Xmn,$T1
+ movdqa $Xln,$Xhn
+ pshufd \$0b01001110,$Xln,$Xmn
+
+ pxor $Xi,$T1 # aggregated Karatsuba post-processing
+ pxor $Xln,$Xmn
+ pxor $Xhi,$T1 #
+ movdqa $T1,$T2 #
+ pslldq \$8,$T1
+ pclmulqdq \$0x11,$Hkey,$Xh
+ psrldq \$8,$T2 #
+ pxor $T1,$Xi
+ movdqa .L7_mask(%rip),$T1
+ pxor $T2,$Xhi #
+ movq %rax,$T2
+
+ pand $Xi,$T1 # 1st phase
+ pshufb $T1,$T2 #
+ pclmulqdq \$0x00,$HK,$Xm
+ pxor $Xi,$T2 #
+ psllq \$57,$T2 #
+ movdqa $T2,$T1 #
+ pslldq \$8,$T2
+ pclmulqdq \$0x00,$Hkey2,$Xln
+ psrldq \$8,$T1 #
+ pxor $T2,$Xi
+ pxor $T1,$Xhi #
+ movdqu 0($inp),$T1
+
+ movdqa $Xi,$T2 # 2nd phase
+ psrlq \$1,$Xi
+ pclmulqdq \$0x11,$Hkey2,$Xhn
+ xorps $Xl,$Xln
+ movdqu 0x10($inp),$Xl
+ pshufb $T3,$Xl
+ pclmulqdq \$0x10,$HK,$Xmn
+ xorps $Xh,$Xhn
+ movups 0x50($Htbl),$HK
+ pshufb $T3,$T1
+ pxor $T2,$Xhi #
+ pxor $Xi,$T2
+ psrlq \$5,$Xi
+
+ movdqa $Xl,$Xh
+ pxor $Xm,$Xmn
+ pshufd \$0b01001110,$Xl,$Xm
+ pxor $Xl,$Xm
+ pclmulqdq \$0x00,$Hkey3,$Xl
+ pxor $T2,$Xi #
+ pxor $T1,$Xhi
+ psrlq \$1,$Xi #
+ pclmulqdq \$0x11,$Hkey3,$Xh
+ xorps $Xl,$Xln
+ pxor $Xhi,$Xi #
+
+ pclmulqdq \$0x00,$HK,$Xm
+ xorps $Xh,$Xhn
+
+ movdqa $Xi,$Xhi
+ pshufd \$0b01001110,$Xi,$T1
+ pxor $Xi,$T1
+
+ lea 0x40($inp),$inp
+ sub \$0x40,$len
+ jnc .Lmod4_loop
+
+.Ltail4x:
+ pclmulqdq \$0x00,$Hkey4,$Xi
+ xorps $Xm,$Xmn
+ pclmulqdq \$0x11,$Hkey4,$Xhi
+ xorps $Xln,$Xi
+ pclmulqdq \$0x10,$HK,$T1
+ xorps $Xhn,$Xhi
+ pxor $Xi,$Xhi # aggregated Karatsuba post-processing
+ pxor $Xmn,$T1
+
+ pxor $Xhi,$T1 #
+ pxor $Xi,$Xhi
+
+ movdqa $T1,$T2 #
+ psrldq \$8,$T1
+ pslldq \$8,$T2 #
+ pxor $T1,$Xhi
+ pxor $T2,$Xi #
+___
+ &reduction_alg9($Xhi,$Xi);
+$code.=<<___;
+ add \$0x40,$len
+ jz .Ldone
+ movdqu 0x20($Htbl),$HK
+ sub \$0x10,$len
+ jz .Lodd_tail
+.Lskip4x:
+___
+}
+$code.=<<___;
+ #######
+ # Xi+2 =[H*(Ii+1 + Xi+1)] mod P =
+ # [(H*Ii+1) + (H*Xi+1)] mod P =
+ # [(H*Ii+1) + H^2*(Ii+Xi)] mod P
+ #
+ movdqu ($inp),$T1 # Ii
+ movdqu 16($inp),$Xln # Ii+1
+ pshufb $T3,$T1
+ pshufb $T3,$Xln
+ pxor $T1,$Xi # Ii+Xi
+
+ movdqa $Xln,$Xhn
+ pshufd \$0b01001110,$Xln,$T1
+ pxor $Xln,$T1
+ pclmulqdq \$0x00,$Hkey,$Xln
+ pclmulqdq \$0x11,$Hkey,$Xhn
+ pclmulqdq \$0x00,$HK,$T1
+
+ lea 32($inp),$inp # i+=2
+ sub \$0x20,$len
+ jbe .Leven_tail
+ jmp .Lmod_loop
+
+.align 32
+.Lmod_loop:
+ movdqa $Xi,$Xhi
+ pshufd \$0b01001110,$Xi,$T2 #
+ pxor $Xi,$T2 #
+
+ pclmulqdq \$0x00,$Hkey2,$Xi
+ pclmulqdq \$0x11,$Hkey2,$Xhi
+ pclmulqdq \$0x10,$HK,$T2
+
+ pxor $Xln,$Xi # (H*Ii+1) + H^2*(Ii+Xi)
+ pxor $Xhn,$Xhi
+ movdqu ($inp),$Xhn # Ii
+ pshufb $T3,$Xhn
+ movdqu 16($inp),$Xln # Ii+1
+
+ pxor $Xi,$T1 # aggregated Karatsuba post-processing
+ pxor $Xhi,$T1
+ pxor $Xhn,$Xhi # "Ii+Xi", consume early
+ pxor $T1,$T2
+ pshufb $T3,$Xln
+ movdqa $T2,$T1 #
+ psrldq \$8,$T1
+ pslldq \$8,$T2 #
+ pxor $T1,$Xhi
+ pxor $T2,$Xi #
+
+ movdqa $Xln,$Xhn #
+
+ movdqa $Xi,$T2 # 1st phase
+ movdqa $Xi,$T1
+ psllq \$5,$Xi
+ pclmulqdq \$0x00,$Hkey,$Xln #######
+ pxor $Xi,$T1 #
+ psllq \$1,$Xi
+ pxor $T1,$Xi #
+ psllq \$57,$Xi #
+ movdqa $Xi,$T1 #
+ pslldq \$8,$Xi
+ psrldq \$8,$T1 #
+ pxor $T2,$Xi
+ pxor $T1,$Xhi #
+ pshufd \$0b01001110,$Xhn,$T1
+ pxor $Xhn,$T1 #
+
+ pclmulqdq \$0x11,$Hkey,$Xhn #######
+ movdqa $Xi,$T2 # 2nd phase
+ psrlq \$1,$Xi
+ pxor $T2,$Xhi #
+ pxor $Xi,$T2
+ psrlq \$5,$Xi
+ pxor $T2,$Xi #
+ psrlq \$1,$Xi #
+ pclmulqdq \$0x00,$HK,$T1 #######
+ pxor $Xhi,$Xi #
+
+ lea 32($inp),$inp
+ sub \$0x20,$len
+ ja .Lmod_loop
+
+.Leven_tail:
+ movdqa $Xi,$Xhi
+ pshufd \$0b01001110,$Xi,$T2 #
+ pxor $Xi,$T2 #
+
+ pclmulqdq \$0x00,$Hkey2,$Xi
+ pclmulqdq \$0x11,$Hkey2,$Xhi
+ pclmulqdq \$0x10,$HK,$T2
+
+ pxor $Xln,$Xi # (H*Ii+1) + H^2*(Ii+Xi)
+ pxor $Xhn,$Xhi
+ pxor $Xi,$T1
+ pxor $Xhi,$T1
+ pxor $T1,$T2
+ movdqa $T2,$T1 #
+ psrldq \$8,$T1
+ pslldq \$8,$T2 #
+ pxor $T1,$Xhi
+ pxor $T2,$Xi #
+___
+ &reduction_alg9 ($Xhi,$Xi);
+$code.=<<___;
+ test $len,$len
+ jnz .Ldone
+
+.Lodd_tail:
+ movdqu ($inp),$T1 # Ii
+ pshufb $T3,$T1
+ pxor $T1,$Xi # Ii+Xi
+___
+ &clmul64x64_T2 ($Xhi,$Xi,$Hkey,$HK); # H*(Ii+Xi)
+ &reduction_alg9 ($Xhi,$Xi);
+$code.=<<___;
+.Ldone:
+ pshufb $T3,$Xi
+ movdqu $Xi,($Xip)
+___
+$code.=<<___ if ($win64);
+ movaps (%rsp),%xmm6
+ movaps 0x10(%rsp),%xmm7
+ movaps 0x20(%rsp),%xmm8
+ movaps 0x30(%rsp),%xmm9
+ movaps 0x40(%rsp),%xmm10
+ movaps 0x50(%rsp),%xmm11
+ movaps 0x60(%rsp),%xmm12
+ movaps 0x70(%rsp),%xmm13
+ movaps 0x80(%rsp),%xmm14
+ movaps 0x90(%rsp),%xmm15
+ lea 0xa8(%rsp),%rsp
+.LSEH_end_gcm_ghash_clmul:
+___
+$code.=<<___;
+ ret
+.size gcm_ghash_clmul,.-gcm_ghash_clmul
+___
+}
+
+$code.=<<___;
+.globl gcm_init_avx
+.type gcm_init_avx,\@abi-omnipotent
+.align 32
+gcm_init_avx:
+___
+if ($avx) {
+my ($Htbl,$Xip)=@_4args;
+my $HK="%xmm6";
+
+$code.=<<___ if ($win64);
+.LSEH_begin_gcm_init_avx:
+ # I can't trust assembler to use specific encoding:-(
+ .byte 0x48,0x83,0xec,0x18 #sub $0x18,%rsp
+ .byte 0x0f,0x29,0x34,0x24 #movaps %xmm6,(%rsp)
+___
+$code.=<<___;
+ vzeroupper
+
+ vmovdqu ($Xip),$Hkey
+ vpshufd \$0b01001110,$Hkey,$Hkey # dword swap
+
+ # <<1 twist
+ vpshufd \$0b11111111,$Hkey,$T2 # broadcast uppermost dword
+ vpsrlq \$63,$Hkey,$T1
+ vpsllq \$1,$Hkey,$Hkey
+ vpxor $T3,$T3,$T3 #
+ vpcmpgtd $T2,$T3,$T3 # broadcast carry bit
+ vpslldq \$8,$T1,$T1
+ vpor $T1,$Hkey,$Hkey # H<<=1
+
+ # magic reduction
+ vpand .L0x1c2_polynomial(%rip),$T3,$T3
+ vpxor $T3,$Hkey,$Hkey # if(carry) H^=0x1c2_polynomial
+
+ vpunpckhqdq $Hkey,$Hkey,$HK
+ vmovdqa $Hkey,$Xi
+ vpxor $Hkey,$HK,$HK
+ mov \$4,%r10 # up to H^8
+ jmp .Linit_start_avx
+___
+
+sub clmul64x64_avx {
+my ($Xhi,$Xi,$Hkey,$HK)=@_;
+
+if (!defined($HK)) { $HK = $T2;
+$code.=<<___;
+ vpunpckhqdq $Xi,$Xi,$T1
+ vpunpckhqdq $Hkey,$Hkey,$T2
+ vpxor $Xi,$T1,$T1 #
+ vpxor $Hkey,$T2,$T2
+___
+} else {
+$code.=<<___;
+ vpunpckhqdq $Xi,$Xi,$T1
+ vpxor $Xi,$T1,$T1 #
+___
+}
+$code.=<<___;
+ vpclmulqdq \$0x11,$Hkey,$Xi,$Xhi #######
+ vpclmulqdq \$0x00,$Hkey,$Xi,$Xi #######
+ vpclmulqdq \$0x00,$HK,$T1,$T1 #######
+ vpxor $Xi,$Xhi,$T2 #
+ vpxor $T2,$T1,$T1 #
+
+ vpslldq \$8,$T1,$T2 #
+ vpsrldq \$8,$T1,$T1
+ vpxor $T2,$Xi,$Xi #
+ vpxor $T1,$Xhi,$Xhi
+___
+}
+
+sub reduction_avx {
+my ($Xhi,$Xi) = @_;
+
+$code.=<<___;
+ vpsllq \$57,$Xi,$T1 # 1st phase
+ vpsllq \$62,$Xi,$T2
+ vpxor $T1,$T2,$T2 #
+ vpsllq \$63,$Xi,$T1
+ vpxor $T1,$T2,$T2 #
+ vpslldq \$8,$T2,$T1 #
+ vpsrldq \$8,$T2,$T2
+ vpxor $T1,$Xi,$Xi #
+ vpxor $T2,$Xhi,$Xhi
+
+ vpsrlq \$1,$Xi,$T2 # 2nd phase
+ vpxor $Xi,$Xhi,$Xhi
+ vpxor $T2,$Xi,$Xi #
+ vpsrlq \$5,$T2,$T2
+ vpxor $T2,$Xi,$Xi #
+ vpsrlq \$1,$Xi,$Xi #
+ vpxor $Xhi,$Xi,$Xi #
+___
+}
+
+$code.=<<___;
+.align 32
+.Linit_loop_avx:
+ vpalignr \$8,$T1,$T2,$T3 # low part is H.lo^H.hi...
+ vmovdqu $T3,-0x10($Htbl) # save Karatsuba "salt"
+___
+ &clmul64x64_avx ($Xhi,$Xi,$Hkey,$HK); # calculate H^3,5,7
+ &reduction_avx ($Xhi,$Xi);
+$code.=<<___;
+.Linit_start_avx:
+ vmovdqa $Xi,$T3
+___
+ &clmul64x64_avx ($Xhi,$Xi,$Hkey,$HK); # calculate H^2,4,6,8
+ &reduction_avx ($Xhi,$Xi);
+$code.=<<___;
+ vpshufd \$0b01001110,$T3,$T1
+ vpshufd \$0b01001110,$Xi,$T2
+ vpxor $T3,$T1,$T1 # Karatsuba pre-processing
+ vmovdqu $T3,0x00($Htbl) # save H^1,3,5,7
+ vpxor $Xi,$T2,$T2 # Karatsuba pre-processing
+ vmovdqu $Xi,0x10($Htbl) # save H^2,4,6,8
+ lea 0x30($Htbl),$Htbl
+ sub \$1,%r10
+ jnz .Linit_loop_avx
+
+ vpalignr \$8,$T2,$T1,$T3 # last "salt" is flipped
+ vmovdqu $T3,-0x10($Htbl)
+
+ vzeroupper
+___
+$code.=<<___ if ($win64);
+ movaps (%rsp),%xmm6
+ lea 0x18(%rsp),%rsp
+.LSEH_end_gcm_init_avx:
+___
+$code.=<<___;
+ ret
+.size gcm_init_avx,.-gcm_init_avx
+___
+} else {
+$code.=<<___;
+ jmp .L_init_clmul
+.size gcm_init_avx,.-gcm_init_avx
+___
+}
+
+$code.=<<___;
+.globl gcm_gmult_avx
+.type gcm_gmult_avx,\@abi-omnipotent
+.align 32
+gcm_gmult_avx:
+ jmp .L_gmult_clmul
+.size gcm_gmult_avx,.-gcm_gmult_avx
+___
+
+$code.=<<___;
+.globl gcm_ghash_avx
+.type gcm_ghash_avx,\@abi-omnipotent
+.align 32
+gcm_ghash_avx:
+___
+if ($avx) {
+my ($Xip,$Htbl,$inp,$len)=@_4args;
+my ($Xlo,$Xhi,$Xmi,
+ $Zlo,$Zhi,$Zmi,
+ $Hkey,$HK,$T1,$T2,
+ $Xi,$Xo,$Tred,$bswap,$Ii,$Ij) = map("%xmm$_",(0..15));
+
+$code.=<<___ if ($win64);
+ lea -0x88(%rsp),%rax
+.LSEH_begin_gcm_ghash_avx:
+ # I can't trust assembler to use specific encoding:-(
+ .byte 0x48,0x8d,0x60,0xe0 #lea -0x20(%rax),%rsp
+ .byte 0x0f,0x29,0x70,0xe0 #movaps %xmm6,-0x20(%rax)
+ .byte 0x0f,0x29,0x78,0xf0 #movaps %xmm7,-0x10(%rax)
+ .byte 0x44,0x0f,0x29,0x00 #movaps %xmm8,0(%rax)
+ .byte 0x44,0x0f,0x29,0x48,0x10 #movaps %xmm9,0x10(%rax)
+ .byte 0x44,0x0f,0x29,0x50,0x20 #movaps %xmm10,0x20(%rax)
+ .byte 0x44,0x0f,0x29,0x58,0x30 #movaps %xmm11,0x30(%rax)
+ .byte 0x44,0x0f,0x29,0x60,0x40 #movaps %xmm12,0x40(%rax)
+ .byte 0x44,0x0f,0x29,0x68,0x50 #movaps %xmm13,0x50(%rax)
+ .byte 0x44,0x0f,0x29,0x70,0x60 #movaps %xmm14,0x60(%rax)
+ .byte 0x44,0x0f,0x29,0x78,0x70 #movaps %xmm15,0x70(%rax)
+___
+$code.=<<___;
+ vzeroupper
+
+ vmovdqu ($Xip),$Xi # load $Xi
+ lea .L0x1c2_polynomial(%rip),%r10
+ lea 0x40($Htbl),$Htbl # size optimization
+ vmovdqu .Lbswap_mask(%rip),$bswap
+ vpshufb $bswap,$Xi,$Xi
+ cmp \$0x80,$len
+ jb .Lshort_avx
+ sub \$0x80,$len
+
+ vmovdqu 0x70($inp),$Ii # I[7]
+ vmovdqu 0x00-0x40($Htbl),$Hkey # $Hkey^1
+ vpshufb $bswap,$Ii,$Ii
+ vmovdqu 0x20-0x40($Htbl),$HK
+
+ vpunpckhqdq $Ii,$Ii,$T2
+ vmovdqu 0x60($inp),$Ij # I[6]
+ vpclmulqdq \$0x00,$Hkey,$Ii,$Xlo
+ vpxor $Ii,$T2,$T2
+ vpshufb $bswap,$Ij,$Ij
+ vpclmulqdq \$0x11,$Hkey,$Ii,$Xhi
+ vmovdqu 0x10-0x40($Htbl),$Hkey # $Hkey^2
+ vpunpckhqdq $Ij,$Ij,$T1
+ vmovdqu 0x50($inp),$Ii # I[5]
+ vpclmulqdq \$0x00,$HK,$T2,$Xmi
+ vpxor $Ij,$T1,$T1
+
+ vpshufb $bswap,$Ii,$Ii
+ vpclmulqdq \$0x00,$Hkey,$Ij,$Zlo
+ vpunpckhqdq $Ii,$Ii,$T2
+ vpclmulqdq \$0x11,$Hkey,$Ij,$Zhi
+ vmovdqu 0x30-0x40($Htbl),$Hkey # $Hkey^3
+ vpxor $Ii,$T2,$T2
+ vmovdqu 0x40($inp),$Ij # I[4]
+ vpclmulqdq \$0x10,$HK,$T1,$Zmi
+ vmovdqu 0x50-0x40($Htbl),$HK
+
+ vpshufb $bswap,$Ij,$Ij
+ vpxor $Xlo,$Zlo,$Zlo
+ vpclmulqdq \$0x00,$Hkey,$Ii,$Xlo
+ vpxor $Xhi,$Zhi,$Zhi
+ vpunpckhqdq $Ij,$Ij,$T1
+ vpclmulqdq \$0x11,$Hkey,$Ii,$Xhi
+ vmovdqu 0x40-0x40($Htbl),$Hkey # $Hkey^4
+ vpxor $Xmi,$Zmi,$Zmi
+ vpclmulqdq \$0x00,$HK,$T2,$Xmi
+ vpxor $Ij,$T1,$T1
+
+ vmovdqu 0x30($inp),$Ii # I[3]
+ vpxor $Zlo,$Xlo,$Xlo
+ vpclmulqdq \$0x00,$Hkey,$Ij,$Zlo
+ vpxor $Zhi,$Xhi,$Xhi
+ vpshufb $bswap,$Ii,$Ii
+ vpclmulqdq \$0x11,$Hkey,$Ij,$Zhi
+ vmovdqu 0x60-0x40($Htbl),$Hkey # $Hkey^5
+ vpxor $Zmi,$Xmi,$Xmi
+ vpunpckhqdq $Ii,$Ii,$T2
+ vpclmulqdq \$0x10,$HK,$T1,$Zmi
+ vmovdqu 0x80-0x40($Htbl),$HK
+ vpxor $Ii,$T2,$T2
+
+ vmovdqu 0x20($inp),$Ij # I[2]
+ vpxor $Xlo,$Zlo,$Zlo
+ vpclmulqdq \$0x00,$Hkey,$Ii,$Xlo
+ vpxor $Xhi,$Zhi,$Zhi
+ vpshufb $bswap,$Ij,$Ij
+ vpclmulqdq \$0x11,$Hkey,$Ii,$Xhi
+ vmovdqu 0x70-0x40($Htbl),$Hkey # $Hkey^6
+ vpxor $Xmi,$Zmi,$Zmi
+ vpunpckhqdq $Ij,$Ij,$T1
+ vpclmulqdq \$0x00,$HK,$T2,$Xmi
+ vpxor $Ij,$T1,$T1
+
+ vmovdqu 0x10($inp),$Ii # I[1]
+ vpxor $Zlo,$Xlo,$Xlo
+ vpclmulqdq \$0x00,$Hkey,$Ij,$Zlo
+ vpxor $Zhi,$Xhi,$Xhi
+ vpshufb $bswap,$Ii,$Ii
+ vpclmulqdq \$0x11,$Hkey,$Ij,$Zhi
+ vmovdqu 0x90-0x40($Htbl),$Hkey # $Hkey^7
+ vpxor $Zmi,$Xmi,$Xmi
+ vpunpckhqdq $Ii,$Ii,$T2
+ vpclmulqdq \$0x10,$HK,$T1,$Zmi
+ vmovdqu 0xb0-0x40($Htbl),$HK
+ vpxor $Ii,$T2,$T2
+
+ vmovdqu ($inp),$Ij # I[0]
+ vpxor $Xlo,$Zlo,$Zlo
+ vpclmulqdq \$0x00,$Hkey,$Ii,$Xlo
+ vpxor $Xhi,$Zhi,$Zhi
+ vpshufb $bswap,$Ij,$Ij
+ vpclmulqdq \$0x11,$Hkey,$Ii,$Xhi
+ vmovdqu 0xa0-0x40($Htbl),$Hkey # $Hkey^8
+ vpxor $Xmi,$Zmi,$Zmi
+ vpclmulqdq \$0x10,$HK,$T2,$Xmi
+
+ lea 0x80($inp),$inp
+ cmp \$0x80,$len
+ jb .Ltail_avx
+
+ vpxor $Xi,$Ij,$Ij # accumulate $Xi
+ sub \$0x80,$len
+ jmp .Loop8x_avx
+
+.align 32
+.Loop8x_avx:
+ vpunpckhqdq $Ij,$Ij,$T1
+ vmovdqu 0x70($inp),$Ii # I[7]
+ vpxor $Xlo,$Zlo,$Zlo
+ vpxor $Ij,$T1,$T1
+ vpclmulqdq \$0x00,$Hkey,$Ij,$Xi
+ vpshufb $bswap,$Ii,$Ii
+ vpxor $Xhi,$Zhi,$Zhi
+ vpclmulqdq \$0x11,$Hkey,$Ij,$Xo
+ vmovdqu 0x00-0x40($Htbl),$Hkey # $Hkey^1
+ vpunpckhqdq $Ii,$Ii,$T2
+ vpxor $Xmi,$Zmi,$Zmi
+ vpclmulqdq \$0x00,$HK,$T1,$Tred
+ vmovdqu 0x20-0x40($Htbl),$HK
+ vpxor $Ii,$T2,$T2
+
+ vmovdqu 0x60($inp),$Ij # I[6]
+ vpclmulqdq \$0x00,$Hkey,$Ii,$Xlo
+ vpxor $Zlo,$Xi,$Xi # collect result
+ vpshufb $bswap,$Ij,$Ij
+ vpclmulqdq \$0x11,$Hkey,$Ii,$Xhi
+ vxorps $Zhi,$Xo,$Xo
+ vmovdqu 0x10-0x40($Htbl),$Hkey # $Hkey^2
+ vpunpckhqdq $Ij,$Ij,$T1
+ vpclmulqdq \$0x00,$HK, $T2,$Xmi
+ vpxor $Zmi,$Tred,$Tred
+ vxorps $Ij,$T1,$T1
+
+ vmovdqu 0x50($inp),$Ii # I[5]
+ vpxor $Xi,$Tred,$Tred # aggregated Karatsuba post-processing
+ vpclmulqdq \$0x00,$Hkey,$Ij,$Zlo
+ vpxor $Xo,$Tred,$Tred
+ vpslldq \$8,$Tred,$T2
+ vpxor $Xlo,$Zlo,$Zlo
+ vpclmulqdq \$0x11,$Hkey,$Ij,$Zhi
+ vpsrldq \$8,$Tred,$Tred
+ vpxor $T2, $Xi, $Xi
+ vmovdqu 0x30-0x40($Htbl),$Hkey # $Hkey^3
+ vpshufb $bswap,$Ii,$Ii
+ vxorps $Tred,$Xo, $Xo
+ vpxor $Xhi,$Zhi,$Zhi
+ vpunpckhqdq $Ii,$Ii,$T2
+ vpclmulqdq \$0x10,$HK, $T1,$Zmi
+ vmovdqu 0x50-0x40($Htbl),$HK
+ vpxor $Ii,$T2,$T2
+ vpxor $Xmi,$Zmi,$Zmi
+
+ vmovdqu 0x40($inp),$Ij # I[4]
+ vpalignr \$8,$Xi,$Xi,$Tred # 1st phase
+ vpclmulqdq \$0x00,$Hkey,$Ii,$Xlo
+ vpshufb $bswap,$Ij,$Ij
+ vpxor $Zlo,$Xlo,$Xlo
+ vpclmulqdq \$0x11,$Hkey,$Ii,$Xhi
+ vmovdqu 0x40-0x40($Htbl),$Hkey # $Hkey^4
+ vpunpckhqdq $Ij,$Ij,$T1
+ vpxor $Zhi,$Xhi,$Xhi
+ vpclmulqdq \$0x00,$HK, $T2,$Xmi
+ vxorps $Ij,$T1,$T1
+ vpxor $Zmi,$Xmi,$Xmi
+
+ vmovdqu 0x30($inp),$Ii # I[3]
+ vpclmulqdq \$0x10,(%r10),$Xi,$Xi
+ vpclmulqdq \$0x00,$Hkey,$Ij,$Zlo
+ vpshufb $bswap,$Ii,$Ii
+ vpxor $Xlo,$Zlo,$Zlo
+ vpclmulqdq \$0x11,$Hkey,$Ij,$Zhi
+ vmovdqu 0x60-0x40($Htbl),$Hkey # $Hkey^5
+ vpunpckhqdq $Ii,$Ii,$T2
+ vpxor $Xhi,$Zhi,$Zhi
+ vpclmulqdq \$0x10,$HK, $T1,$Zmi
+ vmovdqu 0x80-0x40($Htbl),$HK
+ vpxor $Ii,$T2,$T2
+ vpxor $Xmi,$Zmi,$Zmi
+
+ vmovdqu 0x20($inp),$Ij # I[2]
+ vpclmulqdq \$0x00,$Hkey,$Ii,$Xlo
+ vpshufb $bswap,$Ij,$Ij
+ vpxor $Zlo,$Xlo,$Xlo
+ vpclmulqdq \$0x11,$Hkey,$Ii,$Xhi
+ vmovdqu 0x70-0x40($Htbl),$Hkey # $Hkey^6
+ vpunpckhqdq $Ij,$Ij,$T1
+ vpxor $Zhi,$Xhi,$Xhi
+ vpclmulqdq \$0x00,$HK, $T2,$Xmi
+ vpxor $Ij,$T1,$T1
+ vpxor $Zmi,$Xmi,$Xmi
+ vxorps $Tred,$Xi,$Xi
+
+ vmovdqu 0x10($inp),$Ii # I[1]
+ vpalignr \$8,$Xi,$Xi,$Tred # 2nd phase
+ vpclmulqdq \$0x00,$Hkey,$Ij,$Zlo
+ vpshufb $bswap,$Ii,$Ii
+ vpxor $Xlo,$Zlo,$Zlo
+ vpclmulqdq \$0x11,$Hkey,$Ij,$Zhi
+ vmovdqu 0x90-0x40($Htbl),$Hkey # $Hkey^7
+ vpclmulqdq \$0x10,(%r10),$Xi,$Xi
+ vxorps $Xo,$Tred,$Tred
+ vpunpckhqdq $Ii,$Ii,$T2
+ vpxor $Xhi,$Zhi,$Zhi
+ vpclmulqdq \$0x10,$HK, $T1,$Zmi
+ vmovdqu 0xb0-0x40($Htbl),$HK
+ vpxor $Ii,$T2,$T2
+ vpxor $Xmi,$Zmi,$Zmi
+
+ vmovdqu ($inp),$Ij # I[0]
+ vpclmulqdq \$0x00,$Hkey,$Ii,$Xlo
+ vpshufb $bswap,$Ij,$Ij
+ vpclmulqdq \$0x11,$Hkey,$Ii,$Xhi
+ vmovdqu 0xa0-0x40($Htbl),$Hkey # $Hkey^8
+ vpxor $Tred,$Ij,$Ij
+ vpclmulqdq \$0x10,$HK, $T2,$Xmi
+ vpxor $Xi,$Ij,$Ij # accumulate $Xi
+
+ lea 0x80($inp),$inp
+ sub \$0x80,$len
+ jnc .Loop8x_avx
+
+ add \$0x80,$len
+ jmp .Ltail_no_xor_avx
+
+.align 32
+.Lshort_avx:
+ vmovdqu -0x10($inp,$len),$Ii # very last word
+ lea ($inp,$len),$inp
+ vmovdqu 0x00-0x40($Htbl),$Hkey # $Hkey^1
+ vmovdqu 0x20-0x40($Htbl),$HK
+ vpshufb $bswap,$Ii,$Ij
+
+ vmovdqa $Xlo,$Zlo # subtle way to zero $Zlo,
+ vmovdqa $Xhi,$Zhi # $Zhi and
+ vmovdqa $Xmi,$Zmi # $Zmi
+ sub \$0x10,$len
+ jz .Ltail_avx
+
+ vpunpckhqdq $Ij,$Ij,$T1
+ vpxor $Xlo,$Zlo,$Zlo
+ vpclmulqdq \$0x00,$Hkey,$Ij,$Xlo
+ vpxor $Ij,$T1,$T1
+ vmovdqu -0x20($inp),$Ii
+ vpxor $Xhi,$Zhi,$Zhi
+ vpclmulqdq \$0x11,$Hkey,$Ij,$Xhi
+ vmovdqu 0x10-0x40($Htbl),$Hkey # $Hkey^2
+ vpshufb $bswap,$Ii,$Ij
+ vpxor $Xmi,$Zmi,$Zmi
+ vpclmulqdq \$0x00,$HK,$T1,$Xmi
+ vpsrldq \$8,$HK,$HK
+ sub \$0x10,$len
+ jz .Ltail_avx
+
+ vpunpckhqdq $Ij,$Ij,$T1
+ vpxor $Xlo,$Zlo,$Zlo
+ vpclmulqdq \$0x00,$Hkey,$Ij,$Xlo
+ vpxor $Ij,$T1,$T1
+ vmovdqu -0x30($inp),$Ii
+ vpxor $Xhi,$Zhi,$Zhi
+ vpclmulqdq \$0x11,$Hkey,$Ij,$Xhi
+ vmovdqu 0x30-0x40($Htbl),$Hkey # $Hkey^3
+ vpshufb $bswap,$Ii,$Ij
+ vpxor $Xmi,$Zmi,$Zmi
+ vpclmulqdq \$0x00,$HK,$T1,$Xmi
+ vmovdqu 0x50-0x40($Htbl),$HK
+ sub \$0x10,$len
+ jz .Ltail_avx
+
+ vpunpckhqdq $Ij,$Ij,$T1
+ vpxor $Xlo,$Zlo,$Zlo
+ vpclmulqdq \$0x00,$Hkey,$Ij,$Xlo
+ vpxor $Ij,$T1,$T1
+ vmovdqu -0x40($inp),$Ii
+ vpxor $Xhi,$Zhi,$Zhi
+ vpclmulqdq \$0x11,$Hkey,$Ij,$Xhi
+ vmovdqu 0x40-0x40($Htbl),$Hkey # $Hkey^4
+ vpshufb $bswap,$Ii,$Ij
+ vpxor $Xmi,$Zmi,$Zmi
+ vpclmulqdq \$0x00,$HK,$T1,$Xmi
+ vpsrldq \$8,$HK,$HK
+ sub \$0x10,$len
+ jz .Ltail_avx
+
+ vpunpckhqdq $Ij,$Ij,$T1
+ vpxor $Xlo,$Zlo,$Zlo
+ vpclmulqdq \$0x00,$Hkey,$Ij,$Xlo
+ vpxor $Ij,$T1,$T1
+ vmovdqu -0x50($inp),$Ii
+ vpxor $Xhi,$Zhi,$Zhi
+ vpclmulqdq \$0x11,$Hkey,$Ij,$Xhi
+ vmovdqu 0x60-0x40($Htbl),$Hkey # $Hkey^5
+ vpshufb $bswap,$Ii,$Ij
+ vpxor $Xmi,$Zmi,$Zmi
+ vpclmulqdq \$0x00,$HK,$T1,$Xmi
+ vmovdqu 0x80-0x40($Htbl),$HK
+ sub \$0x10,$len
+ jz .Ltail_avx
+
+ vpunpckhqdq $Ij,$Ij,$T1
+ vpxor $Xlo,$Zlo,$Zlo
+ vpclmulqdq \$0x00,$Hkey,$Ij,$Xlo
+ vpxor $Ij,$T1,$T1
+ vmovdqu -0x60($inp),$Ii
+ vpxor $Xhi,$Zhi,$Zhi
+ vpclmulqdq \$0x11,$Hkey,$Ij,$Xhi
+ vmovdqu 0x70-0x40($Htbl),$Hkey # $Hkey^6
+ vpshufb $bswap,$Ii,$Ij
+ vpxor $Xmi,$Zmi,$Zmi
+ vpclmulqdq \$0x00,$HK,$T1,$Xmi
+ vpsrldq \$8,$HK,$HK
+ sub \$0x10,$len
+ jz .Ltail_avx
+
+ vpunpckhqdq $Ij,$Ij,$T1
+ vpxor $Xlo,$Zlo,$Zlo
+ vpclmulqdq \$0x00,$Hkey,$Ij,$Xlo
+ vpxor $Ij,$T1,$T1
+ vmovdqu -0x70($inp),$Ii
+ vpxor $Xhi,$Zhi,$Zhi
+ vpclmulqdq \$0x11,$Hkey,$Ij,$Xhi
+ vmovdqu 0x90-0x40($Htbl),$Hkey # $Hkey^7
+ vpshufb $bswap,$Ii,$Ij
+ vpxor $Xmi,$Zmi,$Zmi
+ vpclmulqdq \$0x00,$HK,$T1,$Xmi
+ vmovq 0xb8-0x40($Htbl),$HK
+ sub \$0x10,$len
+ jmp .Ltail_avx
+
+.align 32
+.Ltail_avx:
+ vpxor $Xi,$Ij,$Ij # accumulate $Xi
+.Ltail_no_xor_avx:
+ vpunpckhqdq $Ij,$Ij,$T1
+ vpxor $Xlo,$Zlo,$Zlo
+ vpclmulqdq \$0x00,$Hkey,$Ij,$Xlo
+ vpxor $Ij,$T1,$T1
+ vpxor $Xhi,$Zhi,$Zhi
+ vpclmulqdq \$0x11,$Hkey,$Ij,$Xhi
+ vpxor $Xmi,$Zmi,$Zmi
+ vpclmulqdq \$0x00,$HK,$T1,$Xmi
+
+ vmovdqu (%r10),$Tred
+
+ vpxor $Xlo,$Zlo,$Xi
+ vpxor $Xhi,$Zhi,$Xo
+ vpxor $Xmi,$Zmi,$Zmi
+
+ vpxor $Xi, $Zmi,$Zmi # aggregated Karatsuba post-processing
+ vpxor $Xo, $Zmi,$Zmi
+ vpslldq \$8, $Zmi,$T2
+ vpsrldq \$8, $Zmi,$Zmi
+ vpxor $T2, $Xi, $Xi
+ vpxor $Zmi,$Xo, $Xo
+
+ vpclmulqdq \$0x10,$Tred,$Xi,$T2 # 1st phase
+ vpalignr \$8,$Xi,$Xi,$Xi
+ vpxor $T2,$Xi,$Xi
+
+ vpclmulqdq \$0x10,$Tred,$Xi,$T2 # 2nd phase
+ vpalignr \$8,$Xi,$Xi,$Xi
+ vpxor $Xo,$Xi,$Xi
+ vpxor $T2,$Xi,$Xi
+
+ cmp \$0,$len
+ jne .Lshort_avx
+
+ vpshufb $bswap,$Xi,$Xi
+ vmovdqu $Xi,($Xip)
+ vzeroupper
+___
+$code.=<<___ if ($win64);
+ movaps (%rsp),%xmm6
+ movaps 0x10(%rsp),%xmm7
+ movaps 0x20(%rsp),%xmm8
+ movaps 0x30(%rsp),%xmm9
+ movaps 0x40(%rsp),%xmm10
+ movaps 0x50(%rsp),%xmm11
+ movaps 0x60(%rsp),%xmm12
+ movaps 0x70(%rsp),%xmm13
+ movaps 0x80(%rsp),%xmm14
+ movaps 0x90(%rsp),%xmm15
+ lea 0xa8(%rsp),%rsp
+.LSEH_end_gcm_ghash_avx:
+___
+$code.=<<___;
+ ret
+.size gcm_ghash_avx,.-gcm_ghash_avx
+___
+} else {
+$code.=<<___;
+ jmp .L_ghash_clmul
+.size gcm_ghash_avx,.-gcm_ghash_avx
+___
+}
+
+$code.=<<___;
+.align 64
+.Lbswap_mask:
+ .byte 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0
+.L0x1c2_polynomial:
+ .byte 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xc2
+.L7_mask:
+ .long 7,0,7,0
+.L7_mask_poly:
+ .long 7,0,`0xE1<<1`,0
+.align 64
+.type .Lrem_4bit,\@object
+.Lrem_4bit:
+ .long 0,`0x0000<<16`,0,`0x1C20<<16`,0,`0x3840<<16`,0,`0x2460<<16`
+ .long 0,`0x7080<<16`,0,`0x6CA0<<16`,0,`0x48C0<<16`,0,`0x54E0<<16`
+ .long 0,`0xE100<<16`,0,`0xFD20<<16`,0,`0xD940<<16`,0,`0xC560<<16`
+ .long 0,`0x9180<<16`,0,`0x8DA0<<16`,0,`0xA9C0<<16`,0,`0xB5E0<<16`
+.type .Lrem_8bit,\@object
+.Lrem_8bit:
+ .value 0x0000,0x01C2,0x0384,0x0246,0x0708,0x06CA,0x048C,0x054E
+ .value 0x0E10,0x0FD2,0x0D94,0x0C56,0x0918,0x08DA,0x0A9C,0x0B5E
+ .value 0x1C20,0x1DE2,0x1FA4,0x1E66,0x1B28,0x1AEA,0x18AC,0x196E
+ .value 0x1230,0x13F2,0x11B4,0x1076,0x1538,0x14FA,0x16BC,0x177E
+ .value 0x3840,0x3982,0x3BC4,0x3A06,0x3F48,0x3E8A,0x3CCC,0x3D0E
+ .value 0x3650,0x3792,0x35D4,0x3416,0x3158,0x309A,0x32DC,0x331E
+ .value 0x2460,0x25A2,0x27E4,0x2626,0x2368,0x22AA,0x20EC,0x212E
+ .value 0x2A70,0x2BB2,0x29F4,0x2836,0x2D78,0x2CBA,0x2EFC,0x2F3E
+ .value 0x7080,0x7142,0x7304,0x72C6,0x7788,0x764A,0x740C,0x75CE
+ .value 0x7E90,0x7F52,0x7D14,0x7CD6,0x7998,0x785A,0x7A1C,0x7BDE
+ .value 0x6CA0,0x6D62,0x6F24,0x6EE6,0x6BA8,0x6A6A,0x682C,0x69EE
+ .value 0x62B0,0x6372,0x6134,0x60F6,0x65B8,0x647A,0x663C,0x67FE
+ .value 0x48C0,0x4902,0x4B44,0x4A86,0x4FC8,0x4E0A,0x4C4C,0x4D8E
+ .value 0x46D0,0x4712,0x4554,0x4496,0x41D8,0x401A,0x425C,0x439E
+ .value 0x54E0,0x5522,0x5764,0x56A6,0x53E8,0x522A,0x506C,0x51AE
+ .value 0x5AF0,0x5B32,0x5974,0x58B6,0x5DF8,0x5C3A,0x5E7C,0x5FBE
+ .value 0xE100,0xE0C2,0xE284,0xE346,0xE608,0xE7CA,0xE58C,0xE44E
+ .value 0xEF10,0xEED2,0xEC94,0xED56,0xE818,0xE9DA,0xEB9C,0xEA5E
+ .value 0xFD20,0xFCE2,0xFEA4,0xFF66,0xFA28,0xFBEA,0xF9AC,0xF86E
+ .value 0xF330,0xF2F2,0xF0B4,0xF176,0xF438,0xF5FA,0xF7BC,0xF67E
+ .value 0xD940,0xD882,0xDAC4,0xDB06,0xDE48,0xDF8A,0xDDCC,0xDC0E
+ .value 0xD750,0xD692,0xD4D4,0xD516,0xD058,0xD19A,0xD3DC,0xD21E
+ .value 0xC560,0xC4A2,0xC6E4,0xC726,0xC268,0xC3AA,0xC1EC,0xC02E
+ .value 0xCB70,0xCAB2,0xC8F4,0xC936,0xCC78,0xCDBA,0xCFFC,0xCE3E
+ .value 0x9180,0x9042,0x9204,0x93C6,0x9688,0x974A,0x950C,0x94CE
+ .value 0x9F90,0x9E52,0x9C14,0x9DD6,0x9898,0x995A,0x9B1C,0x9ADE
+ .value 0x8DA0,0x8C62,0x8E24,0x8FE6,0x8AA8,0x8B6A,0x892C,0x88EE
+ .value 0x83B0,0x8272,0x8034,0x81F6,0x84B8,0x857A,0x873C,0x86FE
+ .value 0xA9C0,0xA802,0xAA44,0xAB86,0xAEC8,0xAF0A,0xAD4C,0xAC8E
+ .value 0xA7D0,0xA612,0xA454,0xA596,0xA0D8,0xA11A,0xA35C,0xA29E
+ .value 0xB5E0,0xB422,0xB664,0xB7A6,0xB2E8,0xB32A,0xB16C,0xB0AE
+ .value 0xBBF0,0xBA32,0xB874,0xB9B6,0xBCF8,0xBD3A,0xBF7C,0xBEBE
+
+.asciz "GHASH for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
+.align 64
+___
+
+# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
+# CONTEXT *context,DISPATCHER_CONTEXT *disp)
+if ($win64) {
+$rec="%rcx";
+$frame="%rdx";
+$context="%r8";
+$disp="%r9";
+
+$code.=<<___;
+.extern __imp_RtlVirtualUnwind
+.type se_handler,\@abi-omnipotent
+.align 16
+se_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 120($context),%rax # pull context->Rax
+ mov 248($context),%rbx # pull context->Rip
+
+ mov 8($disp),%rsi # disp->ImageBase
+ mov 56($disp),%r11 # disp->HandlerData
+
+ mov 0(%r11),%r10d # HandlerData[0]
+ lea (%rsi,%r10),%r10 # prologue label
+ cmp %r10,%rbx # context->Rip<prologue label
+ jb .Lin_prologue
+
+ mov 152($context),%rax # pull context->Rsp
+
+ mov 4(%r11),%r10d # HandlerData[1]
+ lea (%rsi,%r10),%r10 # epilogue label
+ cmp %r10,%rbx # context->Rip>=epilogue label
+ jae .Lin_prologue
+
+ lea 24(%rax),%rax # adjust "rsp"
+
+ mov -8(%rax),%rbx
+ mov -16(%rax),%rbp
+ mov -24(%rax),%r12
+ mov %rbx,144($context) # restore context->Rbx
+ mov %rbp,160($context) # restore context->Rbp
+ mov %r12,216($context) # restore context->R12
+
+.Lin_prologue:
+ mov 8(%rax),%rdi
+ mov 16(%rax),%rsi
+ mov %rax,152($context) # restore context->Rsp
+ mov %rsi,168($context) # restore context->Rsi
+ mov %rdi,176($context) # restore context->Rdi
+
+ mov 40($disp),%rdi # disp->ContextRecord
+ mov $context,%rsi # context
+ mov \$`1232/8`,%ecx # sizeof(CONTEXT)
+ .long 0xa548f3fc # cld; rep movsq
+
+ mov $disp,%rsi
+ xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER
+ mov 8(%rsi),%rdx # arg2, disp->ImageBase
+ mov 0(%rsi),%r8 # arg3, disp->ControlPc
+ mov 16(%rsi),%r9 # arg4, disp->FunctionEntry
+ mov 40(%rsi),%r10 # disp->ContextRecord
+ lea 56(%rsi),%r11 # &disp->HandlerData
+ lea 24(%rsi),%r12 # &disp->EstablisherFrame
+ mov %r10,32(%rsp) # arg5
+ mov %r11,40(%rsp) # arg6
+ mov %r12,48(%rsp) # arg7
+ mov %rcx,56(%rsp) # arg8, (NULL)
+ call *__imp_RtlVirtualUnwind(%rip)
+
+ mov \$1,%eax # ExceptionContinueSearch
+ add \$64,%rsp
+ popfq
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+ pop %rdi
+ pop %rsi
+ ret
+.size se_handler,.-se_handler
+
+.section .pdata
+.align 4
+ .rva .LSEH_begin_gcm_gmult_4bit
+ .rva .LSEH_end_gcm_gmult_4bit
+ .rva .LSEH_info_gcm_gmult_4bit
+
+ .rva .LSEH_begin_gcm_ghash_4bit
+ .rva .LSEH_end_gcm_ghash_4bit
+ .rva .LSEH_info_gcm_ghash_4bit
+
+ .rva .LSEH_begin_gcm_init_clmul
+ .rva .LSEH_end_gcm_init_clmul
+ .rva .LSEH_info_gcm_init_clmul
+
+ .rva .LSEH_begin_gcm_ghash_clmul
+ .rva .LSEH_end_gcm_ghash_clmul
+ .rva .LSEH_info_gcm_ghash_clmul
+___
+$code.=<<___ if ($avx);
+ .rva .LSEH_begin_gcm_init_avx
+ .rva .LSEH_end_gcm_init_avx
+ .rva .LSEH_info_gcm_init_clmul
+
+ .rva .LSEH_begin_gcm_ghash_avx
+ .rva .LSEH_end_gcm_ghash_avx
+ .rva .LSEH_info_gcm_ghash_clmul
+___
+$code.=<<___;
+.section .xdata
+.align 8
+.LSEH_info_gcm_gmult_4bit:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lgmult_prologue,.Lgmult_epilogue # HandlerData
+.LSEH_info_gcm_ghash_4bit:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lghash_prologue,.Lghash_epilogue # HandlerData
+.LSEH_info_gcm_init_clmul:
+ .byte 0x01,0x08,0x03,0x00
+ .byte 0x08,0x68,0x00,0x00 #movaps 0x00(rsp),xmm6
+ .byte 0x04,0x22,0x00,0x00 #sub rsp,0x18
+.LSEH_info_gcm_ghash_clmul:
+ .byte 0x01,0x33,0x16,0x00
+ .byte 0x33,0xf8,0x09,0x00 #movaps 0x90(rsp),xmm15
+ .byte 0x2e,0xe8,0x08,0x00 #movaps 0x80(rsp),xmm14
+ .byte 0x29,0xd8,0x07,0x00 #movaps 0x70(rsp),xmm13
+ .byte 0x24,0xc8,0x06,0x00 #movaps 0x60(rsp),xmm12
+ .byte 0x1f,0xb8,0x05,0x00 #movaps 0x50(rsp),xmm11
+ .byte 0x1a,0xa8,0x04,0x00 #movaps 0x40(rsp),xmm10
+ .byte 0x15,0x98,0x03,0x00 #movaps 0x30(rsp),xmm9
+ .byte 0x10,0x88,0x02,0x00 #movaps 0x20(rsp),xmm8
+ .byte 0x0c,0x78,0x01,0x00 #movaps 0x10(rsp),xmm7
+ .byte 0x08,0x68,0x00,0x00 #movaps 0x00(rsp),xmm6
+ .byte 0x04,0x01,0x15,0x00 #sub rsp,0xa8
+___
+}
+
+$code =~ s/\`([^\`]*)\`/eval($1)/gem;
+
+print $code;
+
+close STDOUT;
diff --git a/crypto/modes/cbc.c b/crypto/modes/cbc.c
new file mode 100644
index 0000000..83d58f0
--- /dev/null
+++ b/crypto/modes/cbc.c
@@ -0,0 +1,202 @@
+/* ====================================================================
+ * Copyright (c) 2008 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.
+ * ==================================================================== */
+#include <openssl/modes.h>
+
+#include <assert.h>
+
+#include "internal.h"
+
+
+#ifndef STRICT_ALIGNMENT
+# define STRICT_ALIGNMENT 0
+#endif
+
+void CRYPTO_cbc128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
+ const void *key, uint8_t ivec[16],
+ block128_f block) {
+ size_t n;
+ const uint8_t *iv = ivec;
+
+ assert(in && out && key && ivec);
+
+ if (STRICT_ALIGNMENT &&
+ ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
+ while (len >= 16) {
+ for (n = 0; n < 16; ++n) {
+ out[n] = in[n] ^ iv[n];
+ }
+ (*block)(out, out, key);
+ iv = out;
+ len -= 16;
+ in += 16;
+ out += 16;
+ }
+ } else {
+ while (len >= 16) {
+ for (n = 0; n < 16; n += sizeof(size_t)) {
+ *(size_t *)(out + n) = *(size_t *)(in + n) ^ *(size_t *)(iv + n);
+ }
+ (*block)(out, out, key);
+ iv = out;
+ len -= 16;
+ in += 16;
+ out += 16;
+ }
+ }
+
+ while (len) {
+ for (n = 0; n < 16 && n < len; ++n) {
+ out[n] = in[n] ^ iv[n];
+ }
+ for (; n < 16; ++n) {
+ out[n] = iv[n];
+ }
+ (*block)(out, out, key);
+ iv = out;
+ if (len <= 16) {
+ break;
+ }
+ len -= 16;
+ in += 16;
+ out += 16;
+ }
+
+ memcpy(ivec, iv, 16);
+}
+
+void CRYPTO_cbc128_decrypt(const uint8_t *in, uint8_t *out, size_t len,
+ const void *key, uint8_t ivec[16],
+ block128_f block) {
+ size_t n;
+ union {
+ size_t t[16 / sizeof(size_t)];
+ uint8_t c[16];
+ } tmp;
+
+ assert(in && out && key && ivec);
+
+ if (in != out) {
+ const uint8_t *iv = ivec;
+
+ if (STRICT_ALIGNMENT &&
+ ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
+ while (len >= 16) {
+ (*block)(in, out, key);
+ for (n = 0; n < 16; ++n)
+ out[n] ^= iv[n];
+ iv = in;
+ len -= 16;
+ in += 16;
+ out += 16;
+ }
+ } else if (16 % sizeof(size_t) == 0) { /* always true */
+ while (len >= 16) {
+ size_t *out_t = (size_t *)out, *iv_t = (size_t *)iv;
+
+ (*block)(in, out, key);
+ for (n = 0; n < 16 / sizeof(size_t); n++)
+ out_t[n] ^= iv_t[n];
+ iv = in;
+ len -= 16;
+ in += 16;
+ out += 16;
+ }
+ }
+ memcpy(ivec, iv, 16);
+ } else {
+ if (STRICT_ALIGNMENT &&
+ ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
+ uint8_t c;
+ while (len >= 16) {
+ (*block)(in, tmp.c, key);
+ for (n = 0; n < 16; ++n) {
+ c = in[n];
+ out[n] = tmp.c[n] ^ ivec[n];
+ ivec[n] = c;
+ }
+ len -= 16;
+ in += 16;
+ out += 16;
+ }
+ } else if (16 % sizeof(size_t) == 0) { /* always true */
+ while (len >= 16) {
+ size_t c, *out_t = (size_t *)out, *ivec_t = (size_t *)ivec;
+ const size_t *in_t = (const size_t *)in;
+
+ (*block)(in, tmp.c, key);
+ for (n = 0; n < 16 / sizeof(size_t); n++) {
+ c = in_t[n];
+ out_t[n] = tmp.t[n] ^ ivec_t[n];
+ ivec_t[n] = c;
+ }
+ len -= 16;
+ in += 16;
+ out += 16;
+ }
+ }
+ }
+
+ while (len) {
+ uint8_t c;
+ (*block)(in, tmp.c, key);
+ for (n = 0; n < 16 && n < len; ++n) {
+ c = in[n];
+ out[n] = tmp.c[n] ^ ivec[n];
+ ivec[n] = c;
+ }
+ if (len <= 16) {
+ for (; n < 16; ++n) {
+ ivec[n] = in[n];
+ }
+ break;
+ }
+ len -= 16;
+ in += 16;
+ out += 16;
+ }
+}
diff --git a/crypto/modes/cfb.c b/crypto/modes/cfb.c
new file mode 100644
index 0000000..2ae4f5e
--- /dev/null
+++ b/crypto/modes/cfb.c
@@ -0,0 +1,227 @@
+/* ====================================================================
+ * Copyright (c) 2008 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.
+ * ==================================================================== */
+
+#include <openssl/modes.h>
+
+#include <assert.h>
+
+#include "internal.h"
+
+
+void CRYPTO_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
+ const void *key, uint8_t ivec[16], int *num, int enc,
+ block128_f block) {
+ unsigned int n;
+ size_t l = 0;
+
+ assert(in && out && key && ivec && num);
+ assert((16 % sizeof(size_t)) == 0);
+
+ n = *num;
+
+ if (enc) {
+ while (n && len) {
+ *(out++) = ivec[n] ^= *(in++);
+ --len;
+ n = (n + 1) % 16;
+ }
+ if (STRICT_ALIGNMENT && ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
+ while (l < len) {
+ if (n == 0) {
+ (*block)(ivec, ivec, key);
+ }
+ out[l] = ivec[n] ^= in[l];
+ ++l;
+ n = (n + 1) % 16;
+ }
+ *num = n;
+ return;
+ }
+ while (len >= 16) {
+ (*block)(ivec, ivec, key);
+ for (; n < 16; n += sizeof(size_t)) {
+ *(size_t *)(out + n) = *(size_t *)(ivec + n) ^= *(size_t *)(in + n);
+ }
+ len -= 16;
+ out += 16;
+ in += 16;
+ n = 0;
+ }
+ if (len) {
+ (*block)(ivec, ivec, key);
+ while (len--) {
+ out[n] = ivec[n] ^= in[n];
+ ++n;
+ }
+ }
+ *num = n;
+ return;
+ } else {
+ while (n && len) {
+ uint8_t c;
+ *(out++) = ivec[n] ^ (c = *(in++));
+ ivec[n] = c;
+ --len;
+ n = (n + 1) % 16;
+ }
+ if (STRICT_ALIGNMENT && ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
+ while (l < len) {
+ unsigned char c;
+ if (n == 0) {
+ (*block)(ivec, ivec, key);
+ }
+ out[l] = ivec[n] ^ (c = in[l]);
+ ivec[n] = c;
+ ++l;
+ n = (n + 1) % 16;
+ }
+ *num = n;
+ return;
+ }
+ while (len >= 16) {
+ (*block)(ivec, ivec, key);
+ for (; n < 16; n += sizeof(size_t)) {
+ size_t t = *(size_t *)(in + n);
+ *(size_t *)(out + n) = *(size_t *)(ivec + n) ^ t;
+ *(size_t *)(ivec + n) = t;
+ }
+ len -= 16;
+ out += 16;
+ in += 16;
+ n = 0;
+ }
+ if (len) {
+ (*block)(ivec, ivec, key);
+ while (len--) {
+ uint8_t c;
+ out[n] = ivec[n] ^ (c = in[n]);
+ ivec[n] = c;
+ ++n;
+ }
+ }
+ *num = n;
+ return;
+ }
+}
+
+
+/* This expects a single block of size nbits for both in and out. Note that
+ it corrupts any extra bits in the last byte of out */
+static void cfbr_encrypt_block(const uint8_t *in, uint8_t *out, unsigned nbits,
+ const void *key, uint8_t ivec[16], int enc,
+ block128_f block) {
+ int n, rem, num;
+ uint8_t ovec[16 * 2 + 1]; /* +1 because we dererefence (but don't use) one
+ byte off the end */
+
+ if (nbits <= 0 || nbits > 128) {
+ return;
+ }
+
+ /* fill in the first half of the new IV with the current IV */
+ memcpy(ovec, ivec, 16);
+ /* construct the new IV */
+ (*block)(ivec, ivec, key);
+ num = (nbits + 7) / 8;
+ if (enc) {
+ /* encrypt the input */
+ for (n = 0; n < num; ++n) {
+ out[n] = (ovec[16 + n] = in[n] ^ ivec[n]);
+ }
+ } else {
+ /* decrypt the input */
+ for (n = 0; n < num; ++n) {
+ out[n] = (ovec[16 + n] = in[n]) ^ ivec[n];
+ }
+ }
+ /* shift ovec left... */
+ rem = nbits % 8;
+ num = nbits / 8;
+ if (rem == 0) {
+ memcpy(ivec, ovec + num, 16);
+ } else {
+ for (n = 0; n < 16; ++n) {
+ ivec[n] = ovec[n + num] << rem | ovec[n + num + 1] >> (8 - rem);
+ }
+ }
+
+ /* it is not necessary to cleanse ovec, since the IV is not secret */
+}
+
+/* N.B. This expects the input to be packed, MS bit first */
+void CRYPTO_cfb128_1_encrypt(const uint8_t *in, uint8_t *out, size_t bits,
+ const void *key, uint8_t ivec[16], int *num,
+ int enc, block128_f block) {
+ size_t n;
+ uint8_t c[1], d[1];
+
+ assert(in && out && key && ivec && num);
+ assert(*num == 0);
+
+ for (n = 0; n < bits; ++n) {
+ c[0] = (in[n / 8] & (1 << (7 - n % 8))) ? 0x80 : 0;
+ cfbr_encrypt_block(c, d, 1, key, ivec, enc, block);
+ out[n / 8] = (out[n / 8] & ~(1 << (unsigned int)(7 - n % 8))) |
+ ((d[0] & 0x80) >> (unsigned int)(n % 8));
+ }
+}
+
+void CRYPTO_cfb128_8_encrypt(const unsigned char *in, unsigned char *out,
+ size_t length, const void *key,
+ unsigned char ivec[16], int *num, int enc,
+ block128_f block) {
+ size_t n;
+
+ assert(in && out && key && ivec && num);
+ assert(*num == 0);
+
+ for (n = 0; n < length; ++n) {
+ cfbr_encrypt_block(&in[n], &out[n], 8, key, ivec, enc, block);
+ }
+}
+
diff --git a/crypto/modes/ctr.c b/crypto/modes/ctr.c
new file mode 100644
index 0000000..4aca5b7
--- /dev/null
+++ b/crypto/modes/ctr.c
@@ -0,0 +1,217 @@
+/* ====================================================================
+ * Copyright (c) 2008 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.
+ * ==================================================================== */
+#include <openssl/modes.h>
+
+#include <assert.h>
+
+#include "internal.h"
+
+
+/* NOTE: the IV/counter CTR mode is big-endian. The code itself
+ * is endian-neutral. */
+
+/* increment counter (128-bit int) by 1 */
+static void ctr128_inc(uint8_t *counter) {
+ uint32_t n = 16;
+ uint8_t c;
+
+ do {
+ --n;
+ c = counter[n];
+ ++c;
+ counter[n] = c;
+ if (c) {
+ return;
+ }
+ } while (n);
+}
+
+/* The input encrypted as though 128bit counter mode is being used. The extra
+ * state information to record how much of the 128bit block we have used is
+ * contained in *num, and the encrypted counter is kept in ecount_buf. Both
+ * *num and ecount_buf must be initialised with zeros before the first call to
+ * CRYPTO_ctr128_encrypt().
+ *
+ * This algorithm assumes that the counter is in the x lower bits of the IV
+ * (ivec), and that the application has full control over overflow and the rest
+ * of the IV. This implementation takes NO responsibility for checking that
+ * the counter doesn't overflow into the rest of the IV when incremented. */
+void CRYPTO_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
+ const void *key, uint8_t ivec[16],
+ uint8_t ecount_buf[16], unsigned int *num,
+ block128_f block) {
+ unsigned int n;
+ size_t l=0;
+
+ assert(in && out && key && ecount_buf && num);
+ assert(*num < 16);
+ assert((16 % sizeof(size_t)) == 0);
+
+ n = *num;
+
+ while (n && len) {
+ *(out++) = *(in++) ^ ecount_buf[n];
+ --len;
+ n = (n + 1) % 16;
+ }
+
+ if (STRICT_ALIGNMENT &&
+ ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
+ while (l < len) {
+ if (n == 0) {
+ (*block)(ivec, ecount_buf, key);
+ ctr128_inc(ivec);
+ }
+ out[l] = in[l] ^ ecount_buf[n];
+ ++l;
+ n = (n + 1) % 16;
+ }
+
+ *num = n;
+ return;
+ }
+
+ while (len >= 16) {
+ (*block)(ivec, ecount_buf, key);
+ ctr128_inc(ivec);
+ for (; n < 16; n += sizeof(size_t))
+ *(size_t *)(out + n) = *(size_t *)(in + n) ^ *(size_t *)(ecount_buf + n);
+ len -= 16;
+ out += 16;
+ in += 16;
+ n = 0;
+ }
+ if (len) {
+ (*block)(ivec, ecount_buf, key);
+ ctr128_inc(ivec);
+ while (len--) {
+ out[n] = in[n] ^ ecount_buf[n];
+ ++n;
+ }
+ }
+ *num = n;
+}
+
+/* increment upper 96 bits of 128-bit counter by 1 */
+static void ctr96_inc(uint8_t *counter) {
+ uint32_t n = 12;
+ uint8_t c;
+
+ do {
+ --n;
+ c = counter[n];
+ ++c;
+ counter[n] = c;
+ if (c) {
+ return;
+ }
+ } while (n);
+}
+
+void CRYPTO_ctr128_encrypt_ctr32(const uint8_t *in, uint8_t *out,
+ size_t len, const void *key,
+ uint8_t ivec[16],
+ uint8_t ecount_buf[16],
+ unsigned int *num, ctr128_f func) {
+ unsigned int n, ctr32;
+
+ assert(in && out && key && ecount_buf && num);
+ assert(*num < 16);
+
+ n = *num;
+
+ while (n && len) {
+ *(out++) = *(in++) ^ ecount_buf[n];
+ --len;
+ n = (n + 1) % 16;
+ }
+
+ ctr32 = GETU32(ivec + 12);
+ while (len >= 16) {
+ size_t blocks = len / 16;
+ /* 1<<28 is just a not-so-small yet not-so-large number...
+ * Below condition is practically never met, but it has to
+ * be checked for code correctness. */
+ if (sizeof(size_t) > sizeof(unsigned int) && blocks > (1U << 28))
+ blocks = (1U << 28);
+ /* As (*func) operates on 32-bit counter, caller
+ * has to handle overflow. 'if' below detects the
+ * overflow, which is then handled by limiting the
+ * amount of blocks to the exact overflow point... */
+ ctr32 += (uint32_t)blocks;
+ if (ctr32 < blocks) {
+ blocks -= ctr32;
+ ctr32 = 0;
+ }
+ (*func)(in, out, blocks, key, ivec);
+ /* (*func) does not update ivec, caller does: */
+ PUTU32(ivec + 12, ctr32);
+ /* ... overflow was detected, propogate carry. */
+ if (ctr32 == 0)
+ ctr96_inc(ivec);
+ blocks *= 16;
+ len -= blocks;
+ out += blocks;
+ in += blocks;
+ }
+ if (len) {
+ memset(ecount_buf, 0, 16);
+ (*func)(ecount_buf, ecount_buf, 1, key, ivec);
+ ++ctr32;
+ PUTU32(ivec + 12, ctr32);
+ if (ctr32 == 0) {
+ ctr96_inc(ivec);
+ }
+ while (len--) {
+ out[n] = in[n] ^ ecount_buf[n];
+ ++n;
+ }
+ }
+
+ *num = n;
+}
diff --git a/crypto/modes/gcm.c b/crypto/modes/gcm.c
new file mode 100644
index 0000000..b950d9f
--- /dev/null
+++ b/crypto/modes/gcm.c
@@ -0,0 +1,1189 @@
+/* ====================================================================
+ * Copyright (c) 2008 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.
+ * ==================================================================== */
+
+#include <openssl/modes.h>
+
+#include <assert.h>
+
+#include <openssl/mem.h>
+#include <openssl/cpu.h>
+
+#include "internal.h"
+
+
+#if !defined(OPENSSL_NO_ASM) && \
+ (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || defined(OPENSSL_ARM))
+#define GHASH_ASM
+#endif
+
+#if defined(BSWAP4) && STRICT_ALIGNMENT == 1
+/* redefine, because alignment is ensured */
+#undef GETU32
+#define GETU32(p) BSWAP4(*(const uint32_t *)(p))
+#undef PUTU32
+#define PUTU32(p, v) *(uint32_t *)(p) = BSWAP4(v)
+#endif
+
+#define PACK(s) ((size_t)(s) << (sizeof(size_t) * 8 - 16))
+#define REDUCE1BIT(V) \
+ do { \
+ if (sizeof(size_t) == 8) { \
+ uint64_t T = U64(0xe100000000000000) & (0 - (V.lo & 1)); \
+ V.lo = (V.hi << 63) | (V.lo >> 1); \
+ V.hi = (V.hi >> 1) ^ T; \
+ } else { \
+ uint32_t T = 0xe1000000U & (0 - (uint32_t)(V.lo & 1)); \
+ V.lo = (V.hi << 63) | (V.lo >> 1); \
+ V.hi = (V.hi >> 1) ^ ((uint64_t)T << 32); \
+ } \
+ } while (0)
+
+
+static void gcm_init_4bit(u128 Htable[16], uint64_t H[2]) {
+ u128 V;
+
+ Htable[0].hi = 0;
+ Htable[0].lo = 0;
+ V.hi = H[0];
+ V.lo = H[1];
+
+ Htable[8] = V;
+ REDUCE1BIT(V);
+ Htable[4] = V;
+ REDUCE1BIT(V);
+ Htable[2] = V;
+ REDUCE1BIT(V);
+ Htable[1] = V;
+ Htable[3].hi = V.hi ^ Htable[2].hi, Htable[3].lo = V.lo ^ Htable[2].lo;
+ V = Htable[4];
+ Htable[5].hi = V.hi ^ Htable[1].hi, Htable[5].lo = V.lo ^ Htable[1].lo;
+ Htable[6].hi = V.hi ^ Htable[2].hi, Htable[6].lo = V.lo ^ Htable[2].lo;
+ Htable[7].hi = V.hi ^ Htable[3].hi, Htable[7].lo = V.lo ^ Htable[3].lo;
+ V = Htable[8];
+ Htable[9].hi = V.hi ^ Htable[1].hi, Htable[9].lo = V.lo ^ Htable[1].lo;
+ Htable[10].hi = V.hi ^ Htable[2].hi, Htable[10].lo = V.lo ^ Htable[2].lo;
+ Htable[11].hi = V.hi ^ Htable[3].hi, Htable[11].lo = V.lo ^ Htable[3].lo;
+ Htable[12].hi = V.hi ^ Htable[4].hi, Htable[12].lo = V.lo ^ Htable[4].lo;
+ Htable[13].hi = V.hi ^ Htable[5].hi, Htable[13].lo = V.lo ^ Htable[5].lo;
+ Htable[14].hi = V.hi ^ Htable[6].hi, Htable[14].lo = V.lo ^ Htable[6].lo;
+ Htable[15].hi = V.hi ^ Htable[7].hi, Htable[15].lo = V.lo ^ Htable[7].lo;
+
+#if defined(GHASH_ASM)
+ /* ARM assembler expects specific dword order in Htable. */
+ {
+ int j;
+ const union {
+ long one;
+ char little;
+ } is_endian = {1};
+
+ if (is_endian.little) {
+ for (j = 0; j < 16; ++j) {
+ V = Htable[j];
+ Htable[j].hi = V.lo;
+ Htable[j].lo = V.hi;
+ }
+ } else {
+ for (j = 0; j < 16; ++j) {
+ V = Htable[j];
+ Htable[j].hi = V.lo << 32 | V.lo >> 32;
+ Htable[j].lo = V.hi << 32 | V.hi >> 32;
+ }
+ }
+ }
+#endif
+}
+
+#if !defined(GHASH_ASM)
+static const size_t rem_4bit[16] = {
+ PACK(0x0000), PACK(0x1C20), PACK(0x3840), PACK(0x2460),
+ PACK(0x7080), PACK(0x6CA0), PACK(0x48C0), PACK(0x54E0),
+ PACK(0xE100), PACK(0xFD20), PACK(0xD940), PACK(0xC560),
+ PACK(0x9180), PACK(0x8DA0), PACK(0xA9C0), PACK(0xB5E0)};
+
+static void gcm_gmult_4bit(uint64_t Xi[2], const u128 Htable[16]) {
+ u128 Z;
+ int cnt = 15;
+ size_t rem, nlo, nhi;
+ const union {
+ long one;
+ char little;
+ } is_endian = {1};
+
+ nlo = ((const uint8_t *)Xi)[15];
+ nhi = nlo >> 4;
+ nlo &= 0xf;
+
+ Z.hi = Htable[nlo].hi;
+ Z.lo = Htable[nlo].lo;
+
+ while (1) {
+ rem = (size_t)Z.lo & 0xf;
+ Z.lo = (Z.hi << 60) | (Z.lo >> 4);
+ Z.hi = (Z.hi >> 4);
+ if (sizeof(size_t) == 8) {
+ Z.hi ^= rem_4bit[rem];
+ } else {
+ Z.hi ^= (uint64_t)rem_4bit[rem] << 32;
+ }
+
+ Z.hi ^= Htable[nhi].hi;
+ Z.lo ^= Htable[nhi].lo;
+
+ if (--cnt < 0) {
+ break;
+ }
+
+ nlo = ((const uint8_t *)Xi)[cnt];
+ nhi = nlo >> 4;
+ nlo &= 0xf;
+
+ rem = (size_t)Z.lo & 0xf;
+ Z.lo = (Z.hi << 60) | (Z.lo >> 4);
+ Z.hi = (Z.hi >> 4);
+ if (sizeof(size_t) == 8) {
+ Z.hi ^= rem_4bit[rem];
+ } else {
+ Z.hi ^= (uint64_t)rem_4bit[rem] << 32;
+ }
+
+ Z.hi ^= Htable[nlo].hi;
+ Z.lo ^= Htable[nlo].lo;
+ }
+
+ if (is_endian.little) {
+#ifdef BSWAP8
+ Xi[0] = BSWAP8(Z.hi);
+ Xi[1] = BSWAP8(Z.lo);
+#else
+ uint8_t *p = (uint8_t *)Xi;
+ uint32_t v;
+ v = (uint32_t)(Z.hi >> 32);
+ PUTU32(p, v);
+ v = (uint32_t)(Z.hi);
+ PUTU32(p + 4, v);
+ v = (uint32_t)(Z.lo >> 32);
+ PUTU32(p + 8, v);
+ v = (uint32_t)(Z.lo);
+ PUTU32(p + 12, v);
+#endif
+ } else {
+ Xi[0] = Z.hi;
+ Xi[1] = Z.lo;
+ }
+}
+
+/* Streamed gcm_mult_4bit, see CRYPTO_gcm128_[en|de]crypt for
+ * details... Compiler-generated code doesn't seem to give any
+ * performance improvement, at least not on x86[_64]. It's here
+ * mostly as reference and a placeholder for possible future
+ * non-trivial optimization[s]... */
+static void gcm_ghash_4bit(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp,
+ size_t len) {
+ u128 Z;
+ int cnt;
+ size_t rem, nlo, nhi;
+ const union {
+ long one;
+ char little;
+ } is_endian = {1};
+
+ do {
+ cnt = 15;
+ nlo = ((const uint8_t *)Xi)[15];
+ nlo ^= inp[15];
+ nhi = nlo >> 4;
+ nlo &= 0xf;
+
+ Z.hi = Htable[nlo].hi;
+ Z.lo = Htable[nlo].lo;
+
+ while (1) {
+ rem = (size_t)Z.lo & 0xf;
+ Z.lo = (Z.hi << 60) | (Z.lo >> 4);
+ Z.hi = (Z.hi >> 4);
+ if (sizeof(size_t) == 8) {
+ Z.hi ^= rem_4bit[rem];
+ } else {
+ Z.hi ^= (uint64_t)rem_4bit[rem] << 32;
+ }
+
+ Z.hi ^= Htable[nhi].hi;
+ Z.lo ^= Htable[nhi].lo;
+
+ if (--cnt < 0) {
+ break;
+ }
+
+ nlo = ((const uint8_t *)Xi)[cnt];
+ nlo ^= inp[cnt];
+ nhi = nlo >> 4;
+ nlo &= 0xf;
+
+ rem = (size_t)Z.lo & 0xf;
+ Z.lo = (Z.hi << 60) | (Z.lo >> 4);
+ Z.hi = (Z.hi >> 4);
+ if (sizeof(size_t) == 8) {
+ Z.hi ^= rem_4bit[rem];
+ } else {
+ Z.hi ^= (uint64_t)rem_4bit[rem] << 32;
+ }
+
+ Z.hi ^= Htable[nlo].hi;
+ Z.lo ^= Htable[nlo].lo;
+ }
+
+ if (is_endian.little) {
+#ifdef BSWAP8
+ Xi[0] = BSWAP8(Z.hi);
+ Xi[1] = BSWAP8(Z.lo);
+#else
+ uint8_t *p = (uint8_t *)Xi;
+ uint32_t v;
+ v = (uint32_t)(Z.hi >> 32);
+ PUTU32(p, v);
+ v = (uint32_t)(Z.hi);
+ PUTU32(p + 4, v);
+ v = (uint32_t)(Z.lo >> 32);
+ PUTU32(p + 8, v);
+ v = (uint32_t)(Z.lo);
+ PUTU32(p + 12, v);
+#endif
+ } else {
+ Xi[0] = Z.hi;
+ Xi[1] = Z.lo;
+ }
+ } while (inp += 16, len -= 16);
+}
+#else /* GHASH_ASM */
+void gcm_gmult_4bit(uint64_t Xi[2], const u128 Htable[16]);
+void gcm_ghash_4bit(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp,
+ size_t len);
+#endif
+
+#define GCM_MUL(ctx, Xi) gcm_gmult_4bit(ctx->Xi.u, ctx->Htable)
+#if defined(GHASH_ASM)
+#define GHASH(ctx, in, len) gcm_ghash_4bit((ctx)->Xi.u, (ctx)->Htable, in, len)
+/* GHASH_CHUNK is "stride parameter" missioned to mitigate cache
+ * trashing effect. In other words idea is to hash data while it's
+ * still in L1 cache after encryption pass... */
+#define GHASH_CHUNK (3 * 1024)
+#endif
+
+
+#if defined(GHASH_ASM)
+#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64)
+#define GHASH_ASM_X86_OR_64
+#define GCM_FUNCREF_4BIT
+void gcm_init_clmul(u128 Htable[16], const uint64_t Xi[2]);
+void gcm_gmult_clmul(uint64_t Xi[2], const u128 Htable[16]);
+void gcm_ghash_clmul(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp,
+ size_t len);
+
+#if defined(OPENSSL_X86)
+#define gcm_init_avx gcm_init_clmul
+#define gcm_gmult_avx gcm_gmult_clmul
+#define gcm_ghash_avx gcm_ghash_clmul
+#else
+void gcm_init_avx(u128 Htable[16], const uint64_t Xi[2]);
+void gcm_gmult_avx(uint64_t Xi[2], const u128 Htable[16]);
+void gcm_ghash_avx(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, size_t len);
+#endif
+
+#if defined(OPENSSL_X86)
+#define GHASH_ASM_X86
+void gcm_gmult_4bit_mmx(uint64_t Xi[2], const u128 Htable[16]);
+void gcm_ghash_4bit_mmx(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp,
+ size_t len);
+
+void gcm_gmult_4bit_x86(uint64_t Xi[2], const u128 Htable[16]);
+void gcm_ghash_4bit_x86(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp,
+ size_t len);
+#endif
+#elif defined(OPENSSL_ARM)
+#include "../arm_arch.h"
+#if __ARM_ARCH__ >= 7
+#define GHASH_ASM_ARM
+#define GCM_FUNCREF_4BIT
+void gcm_gmult_neon(uint64_t Xi[2], const u128 Htable[16]);
+void gcm_ghash_neon(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp,
+ size_t len);
+#endif
+#endif
+#endif
+
+#ifdef GCM_FUNCREF_4BIT
+#undef GCM_MUL
+#define GCM_MUL(ctx, Xi) (*gcm_gmult_p)(ctx->Xi.u, ctx->Htable)
+#ifdef GHASH
+#undef GHASH
+#define GHASH(ctx, in, len) (*gcm_ghash_p)(ctx->Xi.u, ctx->Htable, in, len)
+#endif
+#endif
+
+GCM128_CONTEXT *CRYPTO_gcm128_new(void *key, block128_f block) {
+ GCM128_CONTEXT *ret;
+
+ ret = (GCM128_CONTEXT *)OPENSSL_malloc(sizeof(GCM128_CONTEXT));
+ if (ret != NULL) {
+ CRYPTO_gcm128_init(ret, key, block);
+ }
+
+ return ret;
+}
+
+void CRYPTO_gcm128_init(GCM128_CONTEXT *ctx, void *key, block128_f block) {
+ const union {
+ long one;
+ char little;
+ } is_endian = {1};
+
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->block = block;
+ ctx->key = key;
+
+ (*block)(ctx->H.c, ctx->H.c, key);
+
+ if (is_endian.little) {
+/* H is stored in host byte order */
+#ifdef BSWAP8
+ ctx->H.u[0] = BSWAP8(ctx->H.u[0]);
+ ctx->H.u[1] = BSWAP8(ctx->H.u[1]);
+#else
+ uint8_t *p = ctx->H.c;
+ uint64_t hi, lo;
+ hi = (uint64_t)GETU32(p) << 32 | GETU32(p + 4);
+ lo = (uint64_t)GETU32(p + 8) << 32 | GETU32(p + 12);
+ ctx->H.u[0] = hi;
+ ctx->H.u[1] = lo;
+#endif
+ }
+
+#if defined(GHASH_ASM_X86_OR_64)
+ if (OPENSSL_ia32cap_P[0] & (1 << 24) && /* check FXSR bit */
+ OPENSSL_ia32cap_P[1] & (1 << 1)) { /* check PCLMULQDQ bit */
+ if (((OPENSSL_ia32cap_P[1] >> 22) & 0x41) == 0x41) { /* AVX+MOVBE */
+ gcm_init_avx(ctx->Htable, ctx->H.u);
+ ctx->gmult = gcm_gmult_avx;
+ ctx->ghash = gcm_ghash_avx;
+ } else {
+ gcm_init_clmul(ctx->Htable, ctx->H.u);
+ ctx->gmult = gcm_gmult_clmul;
+ ctx->ghash = gcm_ghash_clmul;
+ }
+ return;
+ }
+ gcm_init_4bit(ctx->Htable, ctx->H.u);
+#if defined(GHASH_ASM_X86) /* x86 only */
+ if (OPENSSL_ia32cap_P[0] & (1 << 25)) { /* check SSE bit */
+ ctx->gmult = gcm_gmult_4bit_mmx;
+ ctx->ghash = gcm_ghash_4bit_mmx;
+ } else {
+ ctx->gmult = gcm_gmult_4bit_x86;
+ ctx->ghash = gcm_ghash_4bit_x86;
+ }
+#else
+ ctx->gmult = gcm_gmult_4bit;
+ ctx->ghash = gcm_ghash_4bit;
+#endif
+#elif defined(GHASH_ASM_ARM)
+ if (CRYPTO_is_NEON_capable()) {
+ ctx->gmult = gcm_gmult_neon;
+ ctx->ghash = gcm_ghash_neon;
+ } else {
+ gcm_init_4bit(ctx->Htable, ctx->H.u);
+ ctx->gmult = gcm_gmult_4bit;
+ ctx->ghash = gcm_ghash_4bit;
+ }
+#else
+ ctx->gmult = gcm_gmult_4bit;
+ ctx->ghash = gcm_ghash_4bit;
+ gcm_init_4bit(ctx->Htable, ctx->H.u);
+#endif
+}
+
+void CRYPTO_gcm128_setiv(GCM128_CONTEXT *ctx, const uint8_t *iv, size_t len) {
+ const union {
+ long one;
+ char little;
+ } is_endian = {1};
+ unsigned int ctr;
+#ifdef GCM_FUNCREF_4BIT
+ void (*gcm_gmult_p)(uint64_t Xi[2], const u128 Htable[16]) = ctx->gmult;
+#endif
+
+ ctx->Yi.u[0] = 0;
+ ctx->Yi.u[1] = 0;
+ ctx->Xi.u[0] = 0;
+ ctx->Xi.u[1] = 0;
+ ctx->len.u[0] = 0; /* AAD length */
+ ctx->len.u[1] = 0; /* message length */
+ ctx->ares = 0;
+ ctx->mres = 0;
+
+ if (len == 12) {
+ memcpy(ctx->Yi.c, iv, 12);
+ ctx->Yi.c[15] = 1;
+ ctr = 1;
+ } else {
+ size_t i;
+ uint64_t len0 = len;
+
+ while (len >= 16) {
+ for (i = 0; i < 16; ++i) {
+ ctx->Yi.c[i] ^= iv[i];
+ }
+ GCM_MUL(ctx, Yi);
+ iv += 16;
+ len -= 16;
+ }
+ if (len) {
+ for (i = 0; i < len; ++i) {
+ ctx->Yi.c[i] ^= iv[i];
+ }
+ GCM_MUL(ctx, Yi);
+ }
+ len0 <<= 3;
+ if (is_endian.little) {
+#ifdef BSWAP8
+ ctx->Yi.u[1] ^= BSWAP8(len0);
+#else
+ ctx->Yi.c[8] ^= (uint8_t)(len0 >> 56);
+ ctx->Yi.c[9] ^= (uint8_t)(len0 >> 48);
+ ctx->Yi.c[10] ^= (uint8_t)(len0 >> 40);
+ ctx->Yi.c[11] ^= (uint8_t)(len0 >> 32);
+ ctx->Yi.c[12] ^= (uint8_t)(len0 >> 24);
+ ctx->Yi.c[13] ^= (uint8_t)(len0 >> 16);
+ ctx->Yi.c[14] ^= (uint8_t)(len0 >> 8);
+ ctx->Yi.c[15] ^= (uint8_t)(len0);
+#endif
+ } else {
+ ctx->Yi.u[1] ^= len0;
+ }
+
+ GCM_MUL(ctx, Yi);
+
+ if (is_endian.little) {
+ ctr = GETU32(ctx->Yi.c + 12);
+ } else {
+ ctr = ctx->Yi.d[3];
+ }
+ }
+
+ (*ctx->block)(ctx->Yi.c, ctx->EK0.c, ctx->key);
+ ++ctr;
+ if (is_endian.little) {
+ PUTU32(ctx->Yi.c + 12, ctr);
+ } else {
+ ctx->Yi.d[3] = ctr;
+ }
+}
+
+int CRYPTO_gcm128_aad(GCM128_CONTEXT *ctx, const uint8_t *aad, size_t len) {
+ size_t i;
+ unsigned int n;
+ uint64_t alen = ctx->len.u[0];
+#ifdef GCM_FUNCREF_4BIT
+ void (*gcm_gmult_p)(uint64_t Xi[2], const u128 Htable[16]) = ctx->gmult;
+#ifdef GHASH
+ void (*gcm_ghash_p)(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp,
+ size_t len) = ctx->ghash;
+#endif
+#endif
+
+ if (ctx->len.u[1]) {
+ return 0;
+ }
+
+ alen += len;
+ if (alen > (U64(1) << 61) || (sizeof(len) == 8 && alen < len)) {
+ return 0;
+ }
+ ctx->len.u[0] = alen;
+
+ n = ctx->ares;
+ if (n) {
+ while (n && len) {
+ ctx->Xi.c[n] ^= *(aad++);
+ --len;
+ n = (n + 1) % 16;
+ }
+ if (n == 0) {
+ GCM_MUL(ctx, Xi);
+ } else {
+ ctx->ares = n;
+ return 1;
+ }
+ }
+
+#ifdef GHASH
+ if ((i = (len & (size_t) - 16))) {
+ GHASH(ctx, aad, i);
+ aad += i;
+ len -= i;
+ }
+#else
+ while (len >= 16) {
+ for (i = 0; i < 16; ++i) {
+ ctx->Xi.c[i] ^= aad[i];
+ }
+ GCM_MUL(ctx, Xi);
+ aad += 16;
+ len -= 16;
+ }
+#endif
+ if (len) {
+ n = (unsigned int)len;
+ for (i = 0; i < len; ++i)
+ ctx->Xi.c[i] ^= aad[i];
+ }
+
+ ctx->ares = n;
+ return 1;
+}
+
+int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const unsigned char *in,
+ unsigned char *out, size_t len) {
+ const union {
+ long one;
+ char little;
+ } is_endian = {1};
+ unsigned int n, ctr;
+ size_t i;
+ uint64_t mlen = ctx->len.u[1];
+ block128_f block = ctx->block;
+ void *key = ctx->key;
+#ifdef GCM_FUNCREF_4BIT
+ void (*gcm_gmult_p)(uint64_t Xi[2], const u128 Htable[16]) = ctx->gmult;
+#ifdef GHASH
+ void (*gcm_ghash_p)(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp,
+ size_t len) = ctx->ghash;
+#endif
+#endif
+
+ mlen += len;
+ if (mlen > ((U64(1) << 36) - 32) || (sizeof(len) == 8 && mlen < len)) {
+ return 0;
+ }
+ ctx->len.u[1] = mlen;
+
+ if (ctx->ares) {
+ /* First call to encrypt finalizes GHASH(AAD) */
+ GCM_MUL(ctx, Xi);
+ ctx->ares = 0;
+ }
+
+ if (is_endian.little) {
+ ctr = GETU32(ctx->Yi.c + 12);
+ } else {
+ ctr = ctx->Yi.d[3];
+ }
+
+ n = ctx->mres;
+ if (n) {
+ while (n && len) {
+ ctx->Xi.c[n] ^= *(out++) = *(in++) ^ ctx->EKi.c[n];
+ --len;
+ n = (n + 1) % 16;
+ }
+ if (n == 0) {
+ GCM_MUL(ctx, Xi);
+ } else {
+ ctx->mres = n;
+ return 1;
+ }
+ }
+ if (STRICT_ALIGNMENT && ((size_t)in | (size_t)out) % sizeof(size_t) != 0) {
+ for (i = 0; i < len; ++i) {
+ if (n == 0) {
+ (*block)(ctx->Yi.c, ctx->EKi.c, key);
+ ++ctr;
+ if (is_endian.little) {
+ PUTU32(ctx->Yi.c + 12, ctr);
+ } else {
+ ctx->Yi.d[3] = ctr;
+ }
+ }
+ ctx->Xi.c[n] ^= out[i] = in[i] ^ ctx->EKi.c[n];
+ n = (n + 1) % 16;
+ if (n == 0) {
+ GCM_MUL(ctx, Xi);
+ }
+ }
+
+ ctx->mres = n;
+ return 1;
+ }
+#if defined(GHASH) && defined(GHASH_CHUNK)
+ while (len >= GHASH_CHUNK) {
+ size_t j = GHASH_CHUNK;
+
+ while (j) {
+ size_t *out_t = (size_t *)out;
+ const size_t *in_t = (const size_t *)in;
+
+ (*block)(ctx->Yi.c, ctx->EKi.c, key);
+ ++ctr;
+ if (is_endian.little) {
+ PUTU32(ctx->Yi.c + 12, ctr);
+ } else {
+ ctx->Yi.d[3] = ctr;
+ }
+ for (i = 0; i < 16 / sizeof(size_t); ++i) {
+ out_t[i] = in_t[i] ^ ctx->EKi.t[i];
+ }
+ out += 16;
+ in += 16;
+ j -= 16;
+ }
+ GHASH(ctx, out - GHASH_CHUNK, GHASH_CHUNK);
+ len -= GHASH_CHUNK;
+ }
+ if ((i = (len & (size_t) - 16))) {
+ size_t j = i;
+
+ while (len >= 16) {
+ size_t *out_t = (size_t *)out;
+ const size_t *in_t = (const size_t *)in;
+
+ (*block)(ctx->Yi.c, ctx->EKi.c, key);
+ ++ctr;
+ if (is_endian.little) {
+ PUTU32(ctx->Yi.c + 12, ctr);
+ } else {
+ ctx->Yi.d[3] = ctr;
+ }
+ for (i = 0; i < 16 / sizeof(size_t); ++i) {
+ out_t[i] = in_t[i] ^ ctx->EKi.t[i];
+ }
+ out += 16;
+ in += 16;
+ len -= 16;
+ }
+ GHASH(ctx, out - j, j);
+ }
+#else
+ while (len >= 16) {
+ size_t *out_t = (size_t *)out;
+ const size_t *in_t = (const size_t *)in;
+
+ (*block)(ctx->Yi.c, ctx->EKi.c, key);
+ ++ctr;
+ if (is_endian.little) {
+ PUTU32(ctx->Yi.c + 12, ctr);
+ } else {
+ ctx->Yi.d[3] = ctr;
+ }
+ for (i = 0; i < 16 / sizeof(size_t); ++i) {
+ ctx->Xi.t[i] ^= out_t[i] = in_t[i] ^ ctx->EKi.t[i];
+ }
+ GCM_MUL(ctx, Xi);
+ out += 16;
+ in += 16;
+ len -= 16;
+ }
+#endif
+ if (len) {
+ (*block)(ctx->Yi.c, ctx->EKi.c, key);
+ ++ctr;
+ if (is_endian.little) {
+ PUTU32(ctx->Yi.c + 12, ctr);
+ } else {
+ ctx->Yi.d[3] = ctr;
+ }
+ while (len--) {
+ ctx->Xi.c[n] ^= out[n] = in[n] ^ ctx->EKi.c[n];
+ ++n;
+ }
+ }
+
+ ctx->mres = n;
+ return 1;
+}
+
+int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const unsigned char *in,
+ unsigned char *out, size_t len) {
+ const union {
+ long one;
+ char little;
+ } is_endian = {1};
+ unsigned int n, ctr;
+ size_t i;
+ uint64_t mlen = ctx->len.u[1];
+ block128_f block = ctx->block;
+ void *key = ctx->key;
+#ifdef GCM_FUNCREF_4BIT
+ void (*gcm_gmult_p)(uint64_t Xi[2], const u128 Htable[16]) = ctx->gmult;
+#ifdef GHASH
+ void (*gcm_ghash_p)(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp,
+ size_t len) = ctx->ghash;
+#endif
+#endif
+
+ mlen += len;
+ if (mlen > ((U64(1) << 36) - 32) || (sizeof(len) == 8 && mlen < len)) {
+ return 0;
+ }
+ ctx->len.u[1] = mlen;
+
+ if (ctx->ares) {
+ /* First call to decrypt finalizes GHASH(AAD) */
+ GCM_MUL(ctx, Xi);
+ ctx->ares = 0;
+ }
+
+ if (is_endian.little) {
+ ctr = GETU32(ctx->Yi.c + 12);
+ } else {
+ ctr = ctx->Yi.d[3];
+ }
+
+ n = ctx->mres;
+ if (n) {
+ while (n && len) {
+ uint8_t c = *(in++);
+ *(out++) = c ^ ctx->EKi.c[n];
+ ctx->Xi.c[n] ^= c;
+ --len;
+ n = (n + 1) % 16;
+ }
+ if (n == 0) {
+ GCM_MUL(ctx, Xi);
+ } else {
+ ctx->mres = n;
+ return 1;
+ }
+ }
+ if (STRICT_ALIGNMENT && ((size_t)in | (size_t)out) % sizeof(size_t) != 0) {
+ for (i = 0; i < len; ++i) {
+ uint8_t c;
+ if (n == 0) {
+ (*block)(ctx->Yi.c, ctx->EKi.c, key);
+ ++ctr;
+ if (is_endian.little) {
+ PUTU32(ctx->Yi.c + 12, ctr);
+ } else {
+ ctx->Yi.d[3] = ctr;
+ }
+ }
+ c = in[i];
+ out[i] = c ^ ctx->EKi.c[n];
+ ctx->Xi.c[n] ^= c;
+ n = (n + 1) % 16;
+ if (n == 0) {
+ GCM_MUL(ctx, Xi);
+ }
+ }
+
+ ctx->mres = n;
+ return 1;
+ }
+#if defined(GHASH) && defined(GHASH_CHUNK)
+ while (len >= GHASH_CHUNK) {
+ size_t j = GHASH_CHUNK;
+
+ GHASH(ctx, in, GHASH_CHUNK);
+ while (j) {
+ size_t *out_t = (size_t *)out;
+ const size_t *in_t = (const size_t *)in;
+
+ (*block)(ctx->Yi.c, ctx->EKi.c, key);
+ ++ctr;
+ if (is_endian.little) {
+ PUTU32(ctx->Yi.c + 12, ctr);
+ } else {
+ ctx->Yi.d[3] = ctr;
+ }
+ for (i = 0; i < 16 / sizeof(size_t); ++i) {
+ out_t[i] = in_t[i] ^ ctx->EKi.t[i];
+ }
+ out += 16;
+ in += 16;
+ j -= 16;
+ }
+ len -= GHASH_CHUNK;
+ }
+ if ((i = (len & (size_t) - 16))) {
+ GHASH(ctx, in, i);
+ while (len >= 16) {
+ size_t *out_t = (size_t *)out;
+ const size_t *in_t = (const size_t *)in;
+
+ (*block)(ctx->Yi.c, ctx->EKi.c, key);
+ ++ctr;
+ if (is_endian.little) {
+ PUTU32(ctx->Yi.c + 12, ctr);
+ } else {
+ ctx->Yi.d[3] = ctr;
+ }
+ for (i = 0; i < 16 / sizeof(size_t); ++i) {
+ out_t[i] = in_t[i] ^ ctx->EKi.t[i];
+ }
+ out += 16;
+ in += 16;
+ len -= 16;
+ }
+ }
+#else
+ while (len >= 16) {
+ size_t *out_t = (size_t *)out;
+ const size_t *in_t = (const size_t *)in;
+
+ (*block)(ctx->Yi.c, ctx->EKi.c, key);
+ ++ctr;
+ if (is_endian.little) {
+ PUTU32(ctx->Yi.c + 12, ctr);
+ } else {
+ ctx->Yi.d[3] = ctr;
+ }
+ for (i = 0; i < 16 / sizeof(size_t); ++i) {
+ size_t c = in_t[i];
+ out_t[i] = c ^ ctx->EKi.t[i];
+ ctx->Xi.t[i] ^= c;
+ }
+ GCM_MUL(ctx, Xi);
+ out += 16;
+ in += 16;
+ len -= 16;
+ }
+#endif
+ if (len) {
+ (*block)(ctx->Yi.c, ctx->EKi.c, key);
+ ++ctr;
+ if (is_endian.little) {
+ PUTU32(ctx->Yi.c + 12, ctr);
+ } else {
+ ctx->Yi.d[3] = ctr;
+ }
+ while (len--) {
+ uint8_t c = in[n];
+ ctx->Xi.c[n] ^= c;
+ out[n] = c ^ ctx->EKi.c[n];
+ ++n;
+ }
+ }
+
+ ctx->mres = n;
+ return 1;
+}
+
+int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx, const uint8_t *in,
+ uint8_t *out, size_t len, ctr128_f stream) {
+ const union {
+ long one;
+ char little;
+ } is_endian = {1};
+ unsigned int n, ctr;
+ size_t i;
+ uint64_t mlen = ctx->len.u[1];
+ void *key = ctx->key;
+#ifdef GCM_FUNCREF_4BIT
+ void (*gcm_gmult_p)(uint64_t Xi[2], const u128 Htable[16]) = ctx->gmult;
+#ifdef GHASH
+ void (*gcm_ghash_p)(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp,
+ size_t len) = ctx->ghash;
+#endif
+#endif
+
+ mlen += len;
+ if (mlen > ((U64(1) << 36) - 32) || (sizeof(len) == 8 && mlen < len)) {
+ return 0;
+ }
+ ctx->len.u[1] = mlen;
+
+ if (ctx->ares) {
+ /* First call to encrypt finalizes GHASH(AAD) */
+ GCM_MUL(ctx, Xi);
+ ctx->ares = 0;
+ }
+
+ if (is_endian.little) {
+ ctr = GETU32(ctx->Yi.c + 12);
+ } else {
+ ctr = ctx->Yi.d[3];
+ }
+
+ n = ctx->mres;
+ if (n) {
+ while (n && len) {
+ ctx->Xi.c[n] ^= *(out++) = *(in++) ^ ctx->EKi.c[n];
+ --len;
+ n = (n + 1) % 16;
+ }
+ if (n == 0) {
+ GCM_MUL(ctx, Xi);
+ } else {
+ ctx->mres = n;
+ return 1;
+ }
+ }
+#if defined(GHASH)
+ while (len >= GHASH_CHUNK) {
+ (*stream)(in, out, GHASH_CHUNK / 16, key, ctx->Yi.c);
+ ctr += GHASH_CHUNK / 16;
+ if (is_endian.little) {
+ PUTU32(ctx->Yi.c + 12, ctr);
+ } else {
+ ctx->Yi.d[3] = ctr;
+ }
+ GHASH(ctx, out, GHASH_CHUNK);
+ out += GHASH_CHUNK;
+ in += GHASH_CHUNK;
+ len -= GHASH_CHUNK;
+ }
+#endif
+ if ((i = (len & (size_t) - 16))) {
+ size_t j = i / 16;
+
+ (*stream)(in, out, j, key, ctx->Yi.c);
+ ctr += (unsigned int)j;
+ if (is_endian.little) {
+ PUTU32(ctx->Yi.c + 12, ctr);
+ } else {
+ ctx->Yi.d[3] = ctr;
+ }
+ in += i;
+ len -= i;
+#if defined(GHASH)
+ GHASH(ctx, out, i);
+ out += i;
+#else
+ while (j--) {
+ for (i = 0; i < 16; ++i) {
+ ctx->Xi.c[i] ^= out[i];
+ }
+ GCM_MUL(ctx, Xi);
+ out += 16;
+ }
+#endif
+ }
+ if (len) {
+ (*ctx->block)(ctx->Yi.c, ctx->EKi.c, key);
+ ++ctr;
+ if (is_endian.little) {
+ PUTU32(ctx->Yi.c + 12, ctr);
+ } else {
+ ctx->Yi.d[3] = ctr;
+ }
+ while (len--) {
+ ctx->Xi.c[n] ^= out[n] = in[n] ^ ctx->EKi.c[n];
+ ++n;
+ }
+ }
+
+ ctx->mres = n;
+ return 1;
+}
+
+int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx, const uint8_t *in,
+ uint8_t *out, size_t len,
+ ctr128_f stream) {
+ const union {
+ long one;
+ char little;
+ } is_endian = {1};
+ unsigned int n, ctr;
+ size_t i;
+ uint64_t mlen = ctx->len.u[1];
+ void *key = ctx->key;
+#ifdef GCM_FUNCREF_4BIT
+ void (*gcm_gmult_p)(uint64_t Xi[2], const u128 Htable[16]) = ctx->gmult;
+#ifdef GHASH
+ void (*gcm_ghash_p)(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp,
+ size_t len) = ctx->ghash;
+#endif
+#endif
+
+ mlen += len;
+ if (mlen > ((U64(1) << 36) - 32) || (sizeof(len) == 8 && mlen < len)) {
+ return 0;
+ }
+ ctx->len.u[1] = mlen;
+
+ if (ctx->ares) {
+ /* First call to decrypt finalizes GHASH(AAD) */
+ GCM_MUL(ctx, Xi);
+ ctx->ares = 0;
+ }
+
+ if (is_endian.little) {
+ ctr = GETU32(ctx->Yi.c + 12);
+ } else {
+ ctr = ctx->Yi.d[3];
+ }
+
+ n = ctx->mres;
+ if (n) {
+ while (n && len) {
+ uint8_t c = *(in++);
+ *(out++) = c ^ ctx->EKi.c[n];
+ ctx->Xi.c[n] ^= c;
+ --len;
+ n = (n + 1) % 16;
+ }
+ if (n == 0) {
+ GCM_MUL(ctx, Xi);
+ } else {
+ ctx->mres = n;
+ return 1;
+ }
+ }
+#if defined(GHASH)
+ while (len >= GHASH_CHUNK) {
+ GHASH(ctx, in, GHASH_CHUNK);
+ (*stream)(in, out, GHASH_CHUNK / 16, key, ctx->Yi.c);
+ ctr += GHASH_CHUNK / 16;
+ if (is_endian.little)
+ PUTU32(ctx->Yi.c + 12, ctr);
+ else
+ ctx->Yi.d[3] = ctr;
+ out += GHASH_CHUNK;
+ in += GHASH_CHUNK;
+ len -= GHASH_CHUNK;
+ }
+#endif
+ if ((i = (len & (size_t) - 16))) {
+ size_t j = i / 16;
+
+#if defined(GHASH)
+ GHASH(ctx, in, i);
+#else
+ while (j--) {
+ size_t k;
+ for (k = 0; k < 16; ++k)
+ ctx->Xi.c[k] ^= in[k];
+ GCM_MUL(ctx, Xi);
+ in += 16;
+ }
+ j = i / 16;
+ in -= i;
+#endif
+ (*stream)(in, out, j, key, ctx->Yi.c);
+ ctr += (unsigned int)j;
+ if (is_endian.little)
+ PUTU32(ctx->Yi.c + 12, ctr);
+ else
+ ctx->Yi.d[3] = ctr;
+ out += i;
+ in += i;
+ len -= i;
+ }
+ if (len) {
+ (*ctx->block)(ctx->Yi.c, ctx->EKi.c, key);
+ ++ctr;
+ if (is_endian.little)
+ PUTU32(ctx->Yi.c + 12, ctr);
+ else
+ ctx->Yi.d[3] = ctr;
+ while (len--) {
+ uint8_t c = in[n];
+ ctx->Xi.c[n] ^= c;
+ out[n] = c ^ ctx->EKi.c[n];
+ ++n;
+ }
+ }
+
+ ctx->mres = n;
+ return 1;
+}
+
+int CRYPTO_gcm128_finish(GCM128_CONTEXT *ctx, const uint8_t *tag, size_t len) {
+ const union {
+ long one;
+ char little;
+ } is_endian = {1};
+ uint64_t alen = ctx->len.u[0] << 3;
+ uint64_t clen = ctx->len.u[1] << 3;
+#ifdef GCM_FUNCREF_4BIT
+ void (*gcm_gmult_p)(uint64_t Xi[2], const u128 Htable[16]) = ctx->gmult;
+#endif
+
+ if (ctx->mres || ctx->ares) {
+ GCM_MUL(ctx, Xi);
+ }
+
+ if (is_endian.little) {
+#ifdef BSWAP8
+ alen = BSWAP8(alen);
+ clen = BSWAP8(clen);
+#else
+ uint8_t *p = ctx->len.c;
+
+ ctx->len.u[0] = alen;
+ ctx->len.u[1] = clen;
+
+ alen = (uint64_t)GETU32(p) << 32 | GETU32(p + 4);
+ clen = (uint64_t)GETU32(p + 8) << 32 | GETU32(p + 12);
+#endif
+ }
+
+ ctx->Xi.u[0] ^= alen;
+ ctx->Xi.u[1] ^= clen;
+ GCM_MUL(ctx, Xi);
+
+ ctx->Xi.u[0] ^= ctx->EK0.u[0];
+ ctx->Xi.u[1] ^= ctx->EK0.u[1];
+
+ if (tag && len <= sizeof(ctx->Xi)) {
+ return CRYPTO_memcmp(ctx->Xi.c, tag, len) == 0;
+ } else {
+ return 0;
+ }
+}
+
+void CRYPTO_gcm128_tag(GCM128_CONTEXT *ctx, unsigned char *tag, size_t len) {
+ CRYPTO_gcm128_finish(ctx, NULL, 0);
+ memcpy(tag, ctx->Xi.c, len <= sizeof(ctx->Xi.c) ? len : sizeof(ctx->Xi.c));
+}
+
+void CRYPTO_gcm128_release(GCM128_CONTEXT *ctx) {
+ if (ctx) {
+ OPENSSL_cleanse(ctx, sizeof(*ctx));
+ OPENSSL_free(ctx);
+ }
+}
diff --git a/crypto/modes/gcm_test.c b/crypto/modes/gcm_test.c
new file mode 100644
index 0000000..8c52b85
--- /dev/null
+++ b/crypto/modes/gcm_test.c
@@ -0,0 +1,431 @@
+/* ====================================================================
+ * Copyright (c) 2008 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.
+ * ==================================================================== */
+
+#include <stdio.h>
+
+#include <openssl/aes.h>
+#include <openssl/mem.h>
+#include <openssl/modes.h>
+
+#include "internal.h"
+
+
+struct test_case {
+ const char *key;
+ const char *plaintext;
+ const char *additional_data;
+ const char *nonce;
+ const char *ciphertext;
+ const char *tag;
+};
+
+static const struct test_case test_cases[] = {
+ {
+ "00000000000000000000000000000000",
+ NULL,
+ NULL,
+ "000000000000000000000000",
+ NULL,
+ "58e2fccefa7e3061367f1d57a4e7455a",
+ },
+ {
+ "00000000000000000000000000000000",
+ "00000000000000000000000000000000",
+ NULL,
+ "000000000000000000000000",
+ "0388dace60b6a392f328c2b971b2fe78",
+ "ab6e47d42cec13bdf53a67b21257bddf",
+ },
+ {
+ "feffe9928665731c6d6a8f9467308308",
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
+ NULL,
+ "cafebabefacedbaddecaf888",
+ "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985",
+ "4d5c2af327cd64a62cf35abd2ba6fab4",
+ },
+ {
+ "feffe9928665731c6d6a8f9467308308",
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "cafebabefacedbaddecaf888",
+ "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091",
+ "5bc94fbc3221a5db94fae95ae7121a47",
+ },
+ {
+ "feffe9928665731c6d6a8f9467308308",
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "cafebabefacedbad",
+ "61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c742373806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598",
+ "3612d2e79e3b0785561be14aaca2fccb",
+ },
+ {
+ "feffe9928665731c6d6a8f9467308308",
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
+ "8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca701e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5",
+ "619cc5aefffe0bfa462af43c1699d050",
+ },
+ {
+ "000000000000000000000000000000000000000000000000",
+ NULL,
+ NULL,
+ "000000000000000000000000",
+ NULL,
+ "cd33b28ac773f74ba00ed1f312572435",
+ },
+ {
+ "000000000000000000000000000000000000000000000000",
+ "00000000000000000000000000000000",
+ NULL,
+ "000000000000000000000000",
+ "98e7247c07f0fe411c267e4384b0f600",
+ "2ff58d80033927ab8ef4d4587514f0fb",
+ },
+ {
+ "feffe9928665731c6d6a8f9467308308feffe9928665731c",
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
+ NULL,
+ "cafebabefacedbaddecaf888",
+ "3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710acade256",
+ "9924a7c8587336bfb118024db8674a14",
+ },
+ {
+ "feffe9928665731c6d6a8f9467308308feffe9928665731c",
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "cafebabefacedbaddecaf888",
+ "3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710",
+ "2519498e80f1478f37ba55bd6d27618c",
+ },
+ {
+ "feffe9928665731c6d6a8f9467308308feffe9928665731c",
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "cafebabefacedbad",
+ "0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7",
+ "65dcc57fcf623a24094fcca40d3533f8",
+ },
+ {
+ "feffe9928665731c6d6a8f9467308308feffe9928665731c",
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "cafebabefacedbad",
+ "0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7",
+ "65dcc57fcf623a24094fcca40d3533f8",
+ },
+ {
+ "feffe9928665731c6d6a8f9467308308feffe9928665731c",
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
+ "d27e88681ce3243c4830165a8fdcf9ff1de9a1d8e6b447ef6ef7b79828666e4581e79012af34ddd9e2f037589b292db3e67c036745fa22e7e9b7373b",
+ "dcf566ff291c25bbb8568fc3d376a6d9",
+ },
+ {
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ NULL,
+ NULL,
+ "000000000000000000000000",
+ NULL,
+ "530f8afbc74536b9a963b4f1c4cb738b",
+ },
+ {
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "00000000000000000000000000000000",
+ NULL,
+ "000000000000000000000000",
+ "cea7403d4d606b6e074ec5d3baf39d18",
+ "d0d1c8a799996bf0265b98b5d48ab919",
+ },
+ {
+ "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
+ NULL,
+ "cafebabefacedbaddecaf888",
+ "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad",
+ "b094dac5d93471bdec1a502270e3cc6c",
+ },
+ {
+ "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "cafebabefacedbaddecaf888",
+ "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662",
+ "76fc6ece0f4e1768cddf8853bb2d551b",
+ },
+ {
+ "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "cafebabefacedbad",
+ "c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0feb582d33934a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f",
+ "3a337dbf46a792c45e454913fe2ea8f2",
+ },
+ {
+ "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
+ "5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf40fc0c3b780f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3f",
+ "a44a8266ee1c8eb0c8b5d4cf5ae9f19a",
+ },
+ {
+ "00000000000000000000000000000000",
+ NULL,
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad",
+ "000000000000000000000000",
+ NULL,
+ "5fea793a2d6f974d37e68e0cb8ff9492",
+ },
+ {
+ "00000000000000000000000000000000",
+ "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ NULL,
+ /* This nonce results in 0xfff in counter LSB. */
+ "ffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "56b3373ca9ef6e4a2b64fe1e9a17b61425f10d47a75a5fce13efc6bc784af24f4141bdd48cf7c770887afd573cca5418a9aeffcd7c5ceddfc6a78397b9a85b499da558257267caab2ad0b23ca476a53cb17fb41c4b8b475cb4f3f7165094c229c9e8c4dc0a2a5ff1903e501511221376a1cdb8364c5061a20cae74bc4acd76ceb0abc9fd3217ef9f8c90be402ddf6d8697f4f880dff15bfb7a6b28241ec8fe183c2d59e3f9dfff653c7126f0acb9e64211f42bae12af462b1070bef1ab5e3606872ca10dee15b3249b1a1b958f23134c4bccb7d03200bce420a2f8eb66dcf3644d1423c1b5699003c13ecef4bf38a3b60eedc34033bac1902783dc6d89e2e774188a439c7ebcc0672dbda4ddcfb2794613b0be41315ef778708a70ee7d75165c",
+ "8b307f6b33286d0ab026a9ed3fe1e85f",
+ },
+};
+
+static int from_hex(uint8_t *out, char in) {
+ if (in >= '0' && in <= '9') {
+ *out = in - '0';
+ return 1;
+ }
+ if (in >= 'a' && in <= 'f') {
+ *out = in - 'a' + 10;
+ return 1;
+ }
+ if (in >= 'A' && in <= 'F') {
+ *out = in - 'A' + 10;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int decode_hex(uint8_t **out, size_t *out_len, const char *in,
+ unsigned test_num, const char *description) {
+ uint8_t *buf = NULL;
+ size_t i;
+
+ if (in == NULL) {
+ *out = NULL;
+ *out_len = 0;
+ return 1;
+ }
+
+ size_t len = strlen(in);
+ if (len & 1) {
+ fprintf(stderr, "%u: Odd-length %s input.\n", test_num, description);
+ goto err;
+ }
+
+ buf = OPENSSL_malloc(len / 2);
+ if (buf == NULL) {
+ fprintf(stderr, "%u: malloc failure.\n", test_num);
+ goto err;
+ }
+
+ for (i = 0; i < len; i += 2) {
+ uint8_t v, v2;
+ if (!from_hex(&v, in[i]) ||
+ !from_hex(&v2, in[i+1])) {
+ fprintf(stderr, "%u: invalid hex digit in %s around offset %u.\n",
+ test_num, description, (unsigned)i);
+ goto err;
+ }
+ buf[i/2] = (v << 4) | v2;
+ }
+
+ *out = buf;
+ *out_len = len/2;
+ return 1;
+
+err:
+ if (buf) {
+ OPENSSL_free(buf);
+ }
+ 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;
+ uint8_t *key = NULL, *plaintext = NULL, *additional_data = NULL,
+ *nonce = NULL, *ciphertext = NULL, *tag = NULL, *out = NULL;
+ int ret = 0;
+ AES_KEY aes_key;
+ GCM128_CONTEXT ctx;
+
+ if (!decode_hex(&key, &key_len, test->key, test_num, "key") ||
+ !decode_hex(&plaintext, &plaintext_len, test->plaintext, test_num,
+ "plaintext") ||
+ !decode_hex(&additional_data, &additional_data_len, test->additional_data,
+ test_num, "additional_data") ||
+ !decode_hex(&nonce, &nonce_len, test->nonce, test_num, "nonce") ||
+ !decode_hex(&ciphertext, &ciphertext_len, test->ciphertext, test_num,
+ "ciphertext") ||
+ !decode_hex(&tag, &tag_len, test->tag, test_num, "tag")) {
+ goto out;
+ }
+
+ if (plaintext_len != ciphertext_len) {
+ fprintf(stderr, "%u: plaintext and ciphertext have differing lengths.\n",
+ test_num);
+ goto out;
+ }
+
+ if (key_len != 16 && key_len != 24 && key_len != 32) {
+ fprintf(stderr, "%u: bad key length.\n", test_num);
+ goto out;
+ }
+
+ if (tag_len != 16) {
+ fprintf(stderr, "%u: bad tag length.\n", test_num);
+ goto out;
+ }
+
+ out = OPENSSL_malloc(plaintext_len);
+ if (AES_set_encrypt_key(key, key_len*8, &aes_key)) {
+ fprintf(stderr, "%u: AES_set_encrypt_key failed.\n", test_num);
+ goto out;
+ }
+
+ CRYPTO_gcm128_init(&ctx, &aes_key, (block128_f) AES_encrypt);
+ CRYPTO_gcm128_setiv(&ctx, nonce, nonce_len);
+ memset(out, 0, plaintext_len);
+ if (additional_data) {
+ CRYPTO_gcm128_aad(&ctx, additional_data, additional_data_len);
+ }
+ if (plaintext) {
+ CRYPTO_gcm128_encrypt(&ctx, plaintext, out, plaintext_len);
+ }
+ 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);
+ goto out;
+ }
+
+ CRYPTO_gcm128_setiv(&ctx, nonce, nonce_len);
+ memset(out, 0, plaintext_len);
+ if (additional_data) {
+ CRYPTO_gcm128_aad(&ctx, additional_data, additional_data_len);
+ }
+ if (ciphertext) {
+ CRYPTO_gcm128_decrypt(&ctx, ciphertext, out, plaintext_len);
+ }
+ if (!CRYPTO_gcm128_finish(&ctx, tag, tag_len)) {
+ fprintf(stderr, "%u: decrypt failed.\n", test_num);
+ goto out;
+ }
+ if (plaintext && memcmp(out, plaintext, plaintext_len)) {
+ fprintf(stderr, "%u: plaintext doesn't match.\n", test_num);
+ goto out;
+ }
+
+ ret = 1;
+
+out:
+ if (key) {
+ OPENSSL_free(key);
+ }
+ if (plaintext) {
+ OPENSSL_free(plaintext);
+ }
+ if (additional_data) {
+ OPENSSL_free(additional_data);
+ }
+ if (nonce) {
+ OPENSSL_free(nonce);
+ }
+ if (ciphertext) {
+ OPENSSL_free(ciphertext);
+ }
+ if (tag) {
+ OPENSSL_free(tag);
+ }
+ if (out) {
+ OPENSSL_free(out);
+ }
+ return ret;
+}
+
+int main() {
+ int ret = 0;
+ unsigned i;
+
+ for (i = 0; i < sizeof(test_cases) / sizeof(struct test_case); i++) {
+ if (!run_test_case(i, &test_cases[i])) {
+ ret = 1;
+ }
+ }
+
+ if (ret == 0) {
+ printf("PASS\n");
+ }
+
+ return ret;
+}
diff --git a/crypto/modes/internal.h b/crypto/modes/internal.h
new file mode 100644
index 0000000..4fa0ec6
--- /dev/null
+++ b/crypto/modes/internal.h
@@ -0,0 +1,201 @@
+/* ====================================================================
+ * Copyright (c) 2008 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.
+ * ==================================================================== */
+
+#ifndef OPENSSL_HEADER_MODES_INTERNAL_H
+#define OPENSSL_HEADER_MODES_INTERNAL_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+#define asm __asm__
+
+#define STRICT_ALIGNMENT 1
+#if defined(OPENSSL_X86_64) || defined(OPENSSL_X86) || defined(OPENSSL_AARCH64)
+#undef STRICT_ALIGNMENT
+#define STRICT_ALIGNMENT 0
+#endif
+
+#if !defined(PEDANTIC) && !defined(OPENSSL_NO_ASM)
+#if defined(__GNUC__) && __GNUC__ >= 2
+#if defined(OPENSSL_X86_64)
+#define BSWAP8(x) \
+ ({ \
+ uint64_t ret = (x); \
+ asm("bswapq %0" : "+r"(ret)); \
+ ret; \
+ })
+#define BSWAP4(x) \
+ ({ \
+ uint32_t ret = (x); \
+ asm("bswapl %0" : "+r"(ret)); \
+ ret; \
+ })
+#elif defined(OPENSSL_X86)
+#define BSWAP8(x) \
+ ({ \
+ uint32_t lo = (uint64_t)(x) >> 32, hi = (x); \
+ asm("bswapl %0; bswapl %1" : "+r"(hi), "+r"(lo)); \
+ (uint64_t) hi << 32 | lo; \
+ })
+#define BSWAP4(x) \
+ ({ \
+ uint32_t ret = (x); \
+ asm("bswapl %0" : "+r"(ret)); \
+ ret; \
+ })
+#elif defined(OPENSSL_AARCH64)
+#define BSWAP8(x) \
+ ({ \
+ uint64_t ret; \
+ asm("rev %0,%1" : "=r"(ret) : "r"(x)); \
+ ret; \
+ })
+#define BSWAP4(x) \
+ ({ \
+ uint32_t ret; \
+ asm("rev %w0,%w1" : "=r"(ret) : "r"(x)); \
+ ret; \
+ })
+#elif defined(OPENSSL_ARM) && !defined(STRICT_ALIGNMENT)
+#define BSWAP8(x) \
+ ({ \
+ uint32_t lo = (uint64_t)(x) >> 32, hi = (x); \
+ asm("rev %0,%0; rev %1,%1" : "+r"(hi), "+r"(lo)); \
+ (uint64_t) hi << 32 | lo; \
+ })
+#define BSWAP4(x) \
+ ({ \
+ uint32_t ret; \
+ asm("rev %0,%1" : "=r"(ret) : "r"((uint32_t)(x))); \
+ ret; \
+ })
+#endif
+#elif defined(_MSC_VER)
+#if _MSC_VER >= 1300
+#pragma intrinsic(_byteswap_uint64, _byteswap_ulong)
+#define BSWAP8(x) _byteswap_uint64((uint64_t)(x))
+#define BSWAP4(x) _byteswap_ulong((uint32_t)(x))
+#elif defined(OPENSSL_X86)
+__inline uint32_t _bswap4(uint32_t val) {
+ _asm mov eax, val
+ _asm bswap eax
+}
+#define BSWAP4(x) _bswap4(x)
+#endif
+#endif
+#endif
+
+#if defined(BSWAP4) && !defined(STRICT_ALIGNMENT)
+#define GETU32(p) BSWAP4(*(const uint32_t *)(p))
+#define PUTU32(p, v) *(uint32_t *)(p) = BSWAP4(v)
+#else
+#define GETU32(p) \
+ ((uint32_t)(p)[0] << 24 | (uint32_t)(p)[1] << 16 | (uint32_t)(p)[2] << 8 | (uint32_t)(p)[3])
+#define PUTU32(p, v) \
+ ((p)[0] = (uint8_t)((v) >> 24), (p)[1] = (uint8_t)((v) >> 16), \
+ (p)[2] = (uint8_t)((v) >> 8), (p)[3] = (uint8_t)(v))
+#endif
+
+
+/* GCM definitions */
+typedef struct { uint64_t hi,lo; } u128;
+
+struct gcm128_context {
+ /* Following 6 names follow names in GCM specification */
+ union {
+ uint64_t u[2];
+ uint32_t d[4];
+ uint8_t c[16];
+ size_t t[16 / sizeof(size_t)];
+ } Yi, EKi, EK0, len, Xi, H;
+
+ /* Relative position of Xi, H and pre-computed Htable is used in some
+ * assembler modules, i.e. don't change the order! */
+ u128 Htable[16];
+ void (*gmult)(uint64_t Xi[2], const u128 Htable[16]);
+ void (*ghash)(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp,
+ size_t len);
+
+ unsigned int mres, ares;
+ block128_f block;
+ void *key;
+};
+
+struct xts128_context {
+ void *key1, *key2;
+ block128_f block1, block2;
+};
+
+struct ccm128_context {
+ union {
+ uint64_t u[2];
+ uint8_t c[16];
+ } nonce, cmac;
+ uint64_t blocks;
+ block128_f block;
+ void *key;
+};
+
+#if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__)
+#define U64(C) C##UI64
+#elif defined(__arch64__)
+#define U64(C) C##UL
+#else
+#define U64(C) C##ULL
+#endif
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_MODES_INTERNAL_H */
diff --git a/crypto/modes/modes.h b/crypto/modes/modes.h
new file mode 100644
index 0000000..c3a11ba
--- /dev/null
+++ b/crypto/modes/modes.h
@@ -0,0 +1,217 @@
+/* ====================================================================
+ * Copyright (c) 2008 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.
+ * ==================================================================== */
+
+#ifndef OPENSSL_HEADER_MODES_H
+#define OPENSSL_HEADER_MODES_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* modes.h contains functions that implement various block-cipher modes. */
+
+
+/* block128_f is the type of a 128-bit, block cipher. */
+typedef void (*block128_f)(const uint8_t in[16], uint8_t out[16],
+ const void *key);
+
+
+/* CTR. */
+
+/* ctr128_f is the type of a function that performs CTR-mode encryption. */
+typedef void (*ctr128_f)(const uint8_t *in, uint8_t *out, size_t blocks,
+ const void *key, const uint8_t ivec[16]);
+
+/* CRYPTO_ctr128_encrypt encrypts (or decrypts, it's the same in CTR mode)
+ * |len| bytes from |in| to |out| using |block| in counter mode. There's no
+ * requirement that |len| be a multiple of any value and any partial blocks are
+ * stored in |ecount_buf| and |*num|, which must be zeroed before the initial
+ * call. The counter is a 128-bit, big-endian value in |ivec| and is
+ * incremented by this function. */
+void CRYPTO_ctr128_encrypt(const uint8_t *in, uint8_t *out,
+ size_t len, const void *key, uint8_t ivec[16],
+ uint8_t ecount_buf[16], unsigned int *num,
+ block128_f block);
+
+/* CRYPTO_ctr128_encrypt_ctr32 acts like |CRYPTO_ctr128_encrypt| but takes
+ * |ctr|, a function that performs CTR mode but only deals with the lower 32
+ * bits of the counter. This is useful when |ctr| can be an optimised
+ * function. */
+void CRYPTO_ctr128_encrypt_ctr32(const uint8_t *in, uint8_t *out,
+ size_t len, const void *key,
+ uint8_t ivec[16],
+ uint8_t ecount_buf[16],
+ unsigned int *num, ctr128_f ctr);
+
+
+/* GCM. */
+
+typedef struct gcm128_context GCM128_CONTEXT;
+
+/* CRYPTO_gcm128_new allocates a fresh |GCM128_CONTEXT| and calls
+ * |CRYPTO_gcm128_init|. It returns the new context, or NULL on error. */
+GCM128_CONTEXT *CRYPTO_gcm128_new(void *key, block128_f block);
+
+/* CRYPTO_gcm128_init initialises |ctx| to use |block| (typically AES) with the
+ * given key. */
+void CRYPTO_gcm128_init(GCM128_CONTEXT *ctx, void *key, block128_f block);
+
+/* CRYPTO_gcm128_setiv sets the IV (nonce) for |ctx|. */
+void CRYPTO_gcm128_setiv(GCM128_CONTEXT *ctx, const uint8_t *iv, size_t len);
+
+/* CRYPTO_gcm128_aad sets the authenticated data for an instance of GCM. This
+ * must be called before and data is encrypted. It returns one on success and
+ * zero otherwise. */
+int CRYPTO_gcm128_aad(GCM128_CONTEXT *ctx, const uint8_t *aad, size_t len);
+
+/* CRYPTO_gcm128_encrypt encrypts |len| bytes from |in| to |out|. It returns
+ * one on success and zero otherwise. */
+int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const uint8_t *in, uint8_t *out,
+ size_t len);
+
+/* CRYPTO_gcm128_decrypt decrypts |len| bytes from |in| to |out|. It returns
+ * one on success and zero otherwise. */
+int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const uint8_t *in, uint8_t *out,
+ size_t len);
+
+/* CRYPTO_gcm128_encrypt_ctr32 encrypts |len| bytes from |in| to |out| using a
+ * CTR function that only handles the bottom 32 bits of the nonce, like
+ * |CRYPTO_ctr128_encrypt_ctr32|. It returns one on success and zero
+ * otherwise. */
+int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx, const uint8_t *in,
+ uint8_t *out, size_t len, ctr128_f stream);
+
+/* CRYPTO_gcm128_decrypt_ctr32 decrypts |len| bytes from |in| to |out| using a
+ * CTR function that only handles the bottom 32 bits of the nonce, like
+ * |CRYPTO_ctr128_encrypt_ctr32|. It returns one on success and zero
+ * otherwise. */
+int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx, const uint8_t *in,
+ uint8_t *out, size_t len, ctr128_f stream);
+
+/* CRYPTO_gcm128_finish calculates the authenticator and compares it against
+ * |len| bytes of |tag|. It returns one on success and zero otherwise. */
+int CRYPTO_gcm128_finish(GCM128_CONTEXT *ctx, const uint8_t *tag, size_t len);
+
+/* CRYPTO_gcm128_tag calculates the authenticator and copies it into |tag|. The
+ * minimum of |len| and 16 bytes are copied into |tag|. */
+void CRYPTO_gcm128_tag(GCM128_CONTEXT *ctx, uint8_t *tag, size_t len);
+
+/* CRYPTO_gcm128_release clears and frees |ctx|. */
+void CRYPTO_gcm128_release(GCM128_CONTEXT *ctx);
+
+
+/* CBC. */
+
+/* cbc128_f is the type of a function that performs CBC-mode encryption. */
+typedef void (*cbc128_f)(const uint8_t *in, uint8_t *out, size_t len,
+ const void *key, uint8_t ivec[16], int enc);
+
+/* CRYPTO_cbc128_encrypt encrypts |len| bytes from |in| to |out| using the
+ * given IV and block cipher in CBC mode. The input need not be a multiple of
+ * 128 bits long, but the output will round up to the nearest 128 bit multiple,
+ * zero padding the input if needed. The IV will be updated on return. */
+void CRYPTO_cbc128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
+ const void *key, uint8_t ivec[16], block128_f block);
+
+/* CRYPTO_cbc128_decrypt decrypts |len| bytes from |in| to |out| using the
+ * given IV and block cipher in CBC mode. If |len| is not a multiple of 128
+ * bits then only that many bytes will be written, but a multiple of 128 bits
+ * is always read from |in|. The IV will be updated on return. */
+void CRYPTO_cbc128_decrypt(const uint8_t *in, uint8_t *out, size_t len,
+ const void *key, uint8_t ivec[16], block128_f block);
+
+
+/* OFB. */
+
+/* CRYPTO_ofb128_encrypt encrypts (or decrypts, it's the same with OFB mode)
+ * |len| bytes from |in| to |out| using |block| in OFB mode. There's no
+ * requirement that |len| be a multiple of any value and any partial blocks are
+ * stored in |ivec| and |*num|, the latter must be zero before the initial
+ * call. */
+void CRYPTO_ofb128_encrypt(const uint8_t *in, uint8_t *out,
+ size_t len, const void *key, uint8_t ivec[16],
+ int *num, block128_f block);
+
+
+/* CFB. */
+
+/* CRYPTO_cfb128_encrypt encrypts (or decrypts, if |enc| is zero) |len| bytes
+ * from |in| to |out| using |block| in CFB mode. There's no requirement that
+ * |len| be a multiple of any value and any partial blocks are stored in |ivec|
+ * and |*num|, the latter must be zero before the initial call. */
+void CRYPTO_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
+ const void *key, uint8_t ivec[16], int *num, int enc,
+ block128_f block);
+
+/* CRYPTO_cfb128_8_encrypt encrypts (or decrypts, if |enc| is zero) |len| bytes
+ * from |in| to |out| using |block| in CFB-8 mode. Prior to the first call
+ * |num| should be set to zero. */
+void CRYPTO_cfb128_8_encrypt(const uint8_t *in, uint8_t *out, size_t len,
+ const void *key, uint8_t ivec[16], int *num,
+ int enc, block128_f block);
+
+/* CRYPTO_cfb128_1_encrypt encrypts (or decrypts, if |enc| is zero) |len| bytes
+ * from |in| to |out| using |block| in CFB-1 mode. Prior to the first call
+ * |num| should be set to zero. */
+void CRYPTO_cfb128_1_encrypt(const uint8_t *in, uint8_t *out, size_t bits,
+ const void *key, uint8_t ivec[16], int *num,
+ int enc, block128_f block);
+
+size_t CRYPTO_cts128_encrypt_block(const uint8_t *in, uint8_t *out, size_t len,
+ const void *key, uint8_t ivec[16],
+ block128_f block);
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_MODES_H */
diff --git a/crypto/modes/ofb.c b/crypto/modes/ofb.c
new file mode 100644
index 0000000..455c069
--- /dev/null
+++ b/crypto/modes/ofb.c
@@ -0,0 +1,106 @@
+/* ====================================================================
+ * Copyright (c) 2008 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.
+ * ==================================================================== */
+
+#include <openssl/modes.h>
+
+#include <assert.h>
+
+#include "internal.h"
+
+
+void CRYPTO_ofb128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
+ const void *key, uint8_t ivec[16], int *num,
+ block128_f block) {
+ unsigned int n;
+ size_t l=0;
+
+ assert(in && out && key && ivec && num);
+ assert((16 % sizeof(size_t)) == 0);
+
+ n = *num;
+
+ while (n && len) {
+ *(out++) = *(in++) ^ ivec[n];
+ --len;
+ n = (n + 1) % 16;
+ }
+
+ if (STRICT_ALIGNMENT &&
+ ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
+ while (l < len) {
+ if (n == 0) {
+ (*block)(ivec, ivec, key);
+ }
+ out[l] = in[l] ^ ivec[n];
+ ++l;
+ n = (n + 1) % 16;
+ }
+
+ *num = n;
+ return;
+ }
+
+ while (len >= 16) {
+ (*block)(ivec, ivec, key);
+ for (; n < 16; n += sizeof(size_t)) {
+ *(size_t *)(out + n) = *(size_t *)(in + n) ^ *(size_t *)(ivec + n);
+ }
+ len -= 16;
+ out += 16;
+ in += 16;
+ n = 0;
+ }
+ if (len) {
+ (*block)(ivec, ivec, key);
+ while (len--) {
+ out[n] = in[n] ^ ivec[n];
+ ++n;
+ }
+ }
+ *num = n;
+}
diff --git a/crypto/obj/CMakeLists.txt b/crypto/obj/CMakeLists.txt
new file mode 100644
index 0000000..d812b37
--- /dev/null
+++ b/crypto/obj/CMakeLists.txt
@@ -0,0 +1,11 @@
+include_directories(. .. ../../include)
+
+add_library(
+ obj
+
+ OBJECT
+
+ obj.c
+ obj_xref.c
+ obj_error.c
+)
diff --git a/crypto/obj/obj.c b/crypto/obj/obj.c
new file mode 100644
index 0000000..970346d
--- /dev/null
+++ b/crypto/obj/obj.c
@@ -0,0 +1,658 @@
+/* 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/obj.h>
+
+#include <limits.h>
+
+#include <openssl/asn1.h>
+#include <openssl/buf.h>
+#include <openssl/bytestring.h>
+#include <openssl/err.h>
+#include <openssl/lhash.h>
+#include <openssl/mem.h>
+#include <openssl/thread.h>
+
+#include "obj_dat.h"
+
+/* These globals are protected by CRYPTO_LOCK_OBJ. */
+static LHASH_OF(ASN1_OBJECT) *global_added_by_data = NULL;
+static LHASH_OF(ASN1_OBJECT) *global_added_by_nid = NULL;
+static LHASH_OF(ASN1_OBJECT) *global_added_by_short_name = NULL;
+static LHASH_OF(ASN1_OBJECT) *global_added_by_long_name = NULL;
+
+static unsigned global_next_nid = NUM_NID;
+
+static int obj_next_nid() {
+ int ret;
+
+ CRYPTO_w_lock(CRYPTO_LOCK_OBJ);
+ ret = global_next_nid++;
+ CRYPTO_w_unlock(CRYPTO_LOCK_OBJ);
+
+ return ret;
+}
+
+ASN1_OBJECT *OBJ_dup(const ASN1_OBJECT *o) {
+ ASN1_OBJECT *r;
+ unsigned char *data = NULL;
+ char *sn = NULL, *ln = NULL;
+
+ if (o == NULL) {
+ return NULL;
+ }
+
+ if (!(o->flags & ASN1_OBJECT_FLAG_DYNAMIC)) {
+ /* TODO(fork): this is a little dangerous. */
+ return (ASN1_OBJECT *)o;
+ }
+
+ r = ASN1_OBJECT_new();
+ if (r == NULL) {
+ OPENSSL_PUT_ERROR(OBJ, OBJ_dup, ERR_R_ASN1_LIB);
+ return NULL;
+ }
+ r->ln = r->sn = NULL;
+
+ data = OPENSSL_malloc(o->length);
+ if (data == NULL) {
+ goto err;
+ }
+ if (o->data != NULL) {
+ memcpy(data, o->data, o->length);
+ }
+
+ /* once data is attached to an object, it remains const */
+ r->data = data;
+ r->length = o->length;
+ r->nid = o->nid;
+
+ if (o->ln != NULL) {
+ ln = OPENSSL_strdup(o->ln);
+ if (ln == NULL) {
+ goto err;
+ }
+ }
+
+ if (o->sn != NULL) {
+ sn = OPENSSL_strdup(o->sn);
+ if (sn) {
+ goto err;
+ }
+ }
+
+ r->sn = sn;
+ r->ln = ln;
+
+ r->flags =
+ o->flags | (ASN1_OBJECT_FLAG_DYNAMIC | ASN1_OBJECT_FLAG_DYNAMIC_STRINGS |
+ ASN1_OBJECT_FLAG_DYNAMIC_DATA);
+ return r;
+
+err:
+ OPENSSL_PUT_ERROR(OBJ, OBJ_dup, ERR_R_MALLOC_FAILURE);
+ if (ln != NULL) {
+ OPENSSL_free(ln);
+ }
+ if (sn != NULL) {
+ OPENSSL_free(sn);
+ }
+ if (data != NULL) {
+ OPENSSL_free(data);
+ }
+ OPENSSL_free(r);
+ return NULL;
+}
+
+int OBJ_cmp(const ASN1_OBJECT *a, const ASN1_OBJECT *b) {
+ int ret;
+
+ ret = a->length - b->length;
+ if (ret) {
+ return ret;
+ }
+ return memcmp(a->data, b->data, a->length);
+}
+
+/* nids_cmp is called to search the kNIDsInOIDOrder array. The |key| argument
+ * is an |ASN1_OBJECT|* that we're looking for and |element| is a pointer to an
+ * unsigned int in the array. */
+static int obj_cmp(const void *key, const void *element) {
+ int j;
+ unsigned nid = *((unsigned*) element);
+ const ASN1_OBJECT *a = key;
+ const ASN1_OBJECT *b = &kObjects[nid];
+
+ j = a->length - b->length;
+ if (j) {
+ return j;
+ }
+ return memcmp(a->data, b->data, a->length);
+}
+
+int OBJ_obj2nid(const ASN1_OBJECT *obj) {
+ const unsigned int *nid_ptr;
+
+ if (obj == NULL) {
+ return NID_undef;
+ }
+
+ if (obj->nid != 0) {
+ return obj->nid;
+ }
+
+ CRYPTO_r_lock(CRYPTO_LOCK_OBJ);
+ if (global_added_by_data != NULL) {
+ ASN1_OBJECT *match;
+
+ match = lh_ASN1_OBJECT_retrieve(global_added_by_data, obj);
+ if (match != NULL) {
+ CRYPTO_r_unlock(CRYPTO_LOCK_OBJ);
+ return match->nid;
+ }
+ }
+ CRYPTO_r_unlock(CRYPTO_LOCK_OBJ);
+
+ nid_ptr = bsearch(obj, kNIDsInOIDOrder, NUM_OBJ, sizeof(unsigned), obj_cmp);
+ if (nid_ptr == NULL) {
+ return NID_undef;
+ }
+
+ return kObjects[*nid_ptr].nid;
+}
+
+int OBJ_cbs2nid(const CBS *cbs) {
+ ASN1_OBJECT obj;
+ memset(&obj, 0, sizeof(obj));
+ obj.data = CBS_data(cbs);
+ obj.length = CBS_len(cbs);
+
+ return OBJ_obj2nid(&obj);
+}
+
+/* short_name_cmp is called to search the kNIDsInShortNameOrder array. The
+ * |key| argument is name that we're looking for and |element| is a pointer to
+ * an unsigned int in the array. */
+static int short_name_cmp(const void *key, const void *element) {
+ const char *name = (const char *) key;
+ unsigned nid = *((unsigned*) element);
+
+ return strcmp(name, kObjects[nid].sn);
+}
+
+int OBJ_sn2nid(const char *short_name) {
+ const unsigned int *nid_ptr;
+
+ CRYPTO_r_lock(CRYPTO_LOCK_OBJ);
+ if (global_added_by_short_name != NULL) {
+ ASN1_OBJECT *match, template;
+
+ template.sn = short_name;
+ match = lh_ASN1_OBJECT_retrieve(global_added_by_short_name, &template);
+ if (match != NULL) {
+ CRYPTO_r_unlock(CRYPTO_LOCK_OBJ);
+ return match->nid;
+ }
+ }
+ CRYPTO_r_unlock(CRYPTO_LOCK_OBJ);
+
+ nid_ptr = bsearch(short_name, kNIDsInShortNameOrder, NUM_SN, sizeof(unsigned), short_name_cmp);
+ if (nid_ptr == NULL) {
+ return NID_undef;
+ }
+
+ return kObjects[*nid_ptr].nid;
+}
+
+/* long_name_cmp is called to search the kNIDsInLongNameOrder array. The
+ * |key| argument is name that we're looking for and |element| is a pointer to
+ * an unsigned int in the array. */
+static int long_name_cmp(const void *key, const void *element) {
+ const char *name = (const char *) key;
+ unsigned nid = *((unsigned*) element);
+
+ return strcmp(name, kObjects[nid].ln);
+}
+
+int OBJ_ln2nid(const char *long_name) {
+ const unsigned int *nid_ptr;
+
+ CRYPTO_r_lock(CRYPTO_LOCK_OBJ);
+ if (global_added_by_long_name != NULL) {
+ ASN1_OBJECT *match, template;
+
+ template.ln = long_name;
+ match = lh_ASN1_OBJECT_retrieve(global_added_by_long_name, &template);
+ if (match != NULL) {
+ CRYPTO_r_unlock(CRYPTO_LOCK_OBJ);
+ return match->nid;
+ }
+ }
+ CRYPTO_r_unlock(CRYPTO_LOCK_OBJ);
+
+ nid_ptr = bsearch(long_name, kNIDsInLongNameOrder, NUM_LN, sizeof(unsigned), long_name_cmp);
+ if (nid_ptr == NULL) {
+ return NID_undef;
+ }
+
+ return kObjects[*nid_ptr].nid;
+}
+
+int OBJ_txt2nid(const char *s) {
+ ASN1_OBJECT *obj;
+ int nid;
+
+ obj = OBJ_txt2obj(s, 0 /* search names */);
+ nid = OBJ_obj2nid(obj);
+ ASN1_OBJECT_free(obj);
+ return nid;
+}
+
+const ASN1_OBJECT *OBJ_nid2obj(int nid) {
+ if (nid >= 0 && nid < NUM_NID) {
+ if (nid != NID_undef && kObjects[nid].nid == NID_undef) {
+ goto err;
+ }
+ return &kObjects[nid];
+ }
+
+ CRYPTO_r_lock(CRYPTO_LOCK_OBJ);
+ if (global_added_by_nid != NULL) {
+ ASN1_OBJECT *match, template;
+
+ template.nid = nid;
+ match = lh_ASN1_OBJECT_retrieve(global_added_by_nid, &template);
+ if (match != NULL) {
+ CRYPTO_r_unlock(CRYPTO_LOCK_OBJ);
+ return match;
+ }
+ }
+ CRYPTO_r_unlock(CRYPTO_LOCK_OBJ);
+
+err:
+ OPENSSL_PUT_ERROR(OBJ, OBJ_nid2obj, OBJ_R_UNKNOWN_NID);
+ return NULL;
+}
+
+const char *OBJ_nid2sn(int nid) {
+ const ASN1_OBJECT *obj = OBJ_nid2obj(nid);
+ if (obj == NULL) {
+ return NULL;
+ }
+
+ return obj->sn;
+}
+
+const char *OBJ_nid2ln(int nid) {
+ const ASN1_OBJECT *obj = OBJ_nid2obj(nid);
+ if (obj == NULL) {
+ return NULL;
+ }
+
+ return obj->ln;
+}
+
+ASN1_OBJECT *OBJ_txt2obj(const char *s, int dont_search_names) {
+ int nid = NID_undef;
+ ASN1_OBJECT *op = NULL;
+ unsigned char *buf;
+ unsigned char *p;
+ const unsigned char *bufp;
+ int contents_len, total_len;
+
+ if (!dont_search_names) {
+ nid = OBJ_sn2nid(s);
+ if (nid == NID_undef) {
+ nid = OBJ_ln2nid(s);
+ }
+
+ if (nid != NID_undef) {
+ return (ASN1_OBJECT*) OBJ_nid2obj(nid);
+ }
+ }
+
+ /* Work out size of content octets */
+ contents_len = a2d_ASN1_OBJECT(NULL, 0, s, -1);
+ if (contents_len <= 0) {
+ return NULL;
+ }
+ /* Work out total size */
+ total_len = ASN1_object_size(0, contents_len, V_ASN1_OBJECT);
+
+ buf = OPENSSL_malloc(total_len);
+ if (buf == NULL) {
+ OPENSSL_PUT_ERROR(OBJ, OBJ_txt2obj, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ p = buf;
+ /* Write out tag+length */
+ ASN1_put_object(&p, 0, contents_len, V_ASN1_OBJECT, V_ASN1_UNIVERSAL);
+ /* Write out contents */
+ a2d_ASN1_OBJECT(p, contents_len, s, -1);
+
+ bufp = buf;
+ op = d2i_ASN1_OBJECT(NULL, &bufp, total_len);
+ OPENSSL_free(buf);
+
+ return op;
+}
+
+int OBJ_obj2txt(char *out, int out_len, const ASN1_OBJECT *obj, int dont_return_name) {
+ int i, n = 0, len, nid, first, use_bn;
+ BIGNUM *bl;
+ unsigned long l;
+ const unsigned char *p;
+ char tbuf[DECIMAL_SIZE(i) + DECIMAL_SIZE(l) + 2];
+
+ if (out && out_len > 0) {
+ out[0] = 0;
+ }
+
+ if (obj == NULL || obj->data == NULL) {
+ return 0;
+ }
+
+ if (!dont_return_name && (nid = OBJ_obj2nid(obj)) != NID_undef) {
+ const char *s;
+ s = OBJ_nid2ln(nid);
+ if (s == NULL) {
+ s = OBJ_nid2sn(nid);
+ }
+ if (s) {
+ if (out) {
+ BUF_strlcpy(out, s, out_len);
+ }
+ return strlen(s);
+ }
+ }
+
+ len = obj->length;
+ p = obj->data;
+
+ first = 1;
+ bl = NULL;
+
+ while (len > 0) {
+ l = 0;
+ use_bn = 0;
+ for (;;) {
+ unsigned char c = *p++;
+ len--;
+ if (len == 0 && (c & 0x80)) {
+ goto err;
+ }
+ if (use_bn) {
+ if (!BN_add_word(bl, c & 0x7f)) {
+ goto err;
+ }
+ } else {
+ l |= c & 0x7f;
+ }
+ if (!(c & 0x80)) {
+ break;
+ }
+ if (!use_bn && (l > (ULONG_MAX >> 7L))) {
+ if (!bl && !(bl = BN_new())) {
+ goto err;
+ }
+ if (!BN_set_word(bl, l)) {
+ goto err;
+ }
+ use_bn = 1;
+ }
+ if (use_bn) {
+ if (!BN_lshift(bl, bl, 7)) {
+ goto err;
+ }
+ } else {
+ l <<= 7L;
+ }
+ }
+
+ if (first) {
+ first = 0;
+ if (l >= 80) {
+ i = 2;
+ if (use_bn) {
+ if (!BN_sub_word(bl, 80)) {
+ goto err;
+ }
+ } else {
+ l -= 80;
+ }
+ } else {
+ i = (int)(l / 40);
+ l -= (long)(i * 40);
+ }
+ if (out && out_len > 1) {
+ *out++ = i + '0';
+ *out = '0';
+ out_len--;
+ }
+ n++;
+ }
+
+ if (use_bn) {
+ char *bndec;
+ bndec = BN_bn2dec(bl);
+ if (!bndec) {
+ goto err;
+ }
+ i = strlen(bndec);
+ if (out) {
+ if (out_len > 1) {
+ *out++ = '.';
+ *out = 0;
+ out_len--;
+ }
+ BUF_strlcpy(out, bndec, out_len);
+ if (i > out_len) {
+ out += out_len;
+ out_len = 0;
+ } else {
+ out += i;
+ out_len -= i;
+ }
+ }
+ n++;
+ n += i;
+ OPENSSL_free(bndec);
+ } else {
+ BIO_snprintf(tbuf, sizeof(tbuf), ".%lu", l);
+ i = strlen(tbuf);
+ if (out && out_len > 0) {
+ BUF_strlcpy(out, tbuf, out_len);
+ if (i > out_len) {
+ out += out_len;
+ out_len = 0;
+ } else {
+ out += i;
+ out_len -= i;
+ }
+ }
+ n += i;
+ }
+ }
+
+ if (bl) {
+ BN_free(bl);
+ }
+ return n;
+
+err:
+ if (bl) {
+ BN_free(bl);
+ }
+ return -1;
+}
+
+static uint32_t hash_nid(const ASN1_OBJECT *obj) {
+ return obj->nid;
+}
+
+static int cmp_nid(const ASN1_OBJECT *a, const ASN1_OBJECT *b) {
+ return a->nid - b->nid;
+}
+
+static uint32_t hash_data(const ASN1_OBJECT *obj) {
+ return OPENSSL_hash32(obj->data, obj->length);
+}
+
+static int cmp_data(const ASN1_OBJECT *a, const ASN1_OBJECT *b) {
+ int i = a->length - b->length;
+ if (i) {
+ return i;
+ }
+ return memcmp(a->data, b->data, a->length);
+}
+
+static uint32_t hash_short_name(const ASN1_OBJECT *obj) {
+ return lh_strhash(obj->sn);
+}
+
+static int cmp_short_name(const ASN1_OBJECT *a, const ASN1_OBJECT *b) {
+ return strcmp(a->sn, b->sn);
+}
+
+static uint32_t hash_long_name(const ASN1_OBJECT *obj) {
+ return lh_strhash(obj->ln);
+}
+
+static int cmp_long_name(const ASN1_OBJECT *a, const ASN1_OBJECT *b) {
+ return strcmp(a->ln, b->ln);
+}
+
+/* obj_add_object inserts |obj| into the various global hashes for run-time
+ * added objects. It returns one on success or zero otherwise. */
+static int obj_add_object(ASN1_OBJECT *obj) {
+ int ok;
+ ASN1_OBJECT *old_object;
+
+ obj->flags &= ~(ASN1_OBJECT_FLAG_DYNAMIC | ASN1_OBJECT_FLAG_DYNAMIC_STRINGS |
+ ASN1_OBJECT_FLAG_DYNAMIC_DATA);
+
+ CRYPTO_w_lock(CRYPTO_LOCK_OBJ);
+ if (global_added_by_nid == NULL) {
+ global_added_by_nid = lh_ASN1_OBJECT_new(hash_nid, cmp_nid);
+ global_added_by_data = lh_ASN1_OBJECT_new(hash_data, cmp_data);
+ global_added_by_short_name = lh_ASN1_OBJECT_new(hash_short_name, cmp_short_name);
+ global_added_by_long_name = lh_ASN1_OBJECT_new(hash_long_name, cmp_long_name);
+ }
+
+ /* We don't pay attention to |old_object| (which contains any previous object
+ * that was evicted from the hashes) because we don't have a reference count
+ * on ASN1_OBJECT values. Also, we should never have duplicates nids and so
+ * should always have objects in |global_added_by_nid|. */
+
+ ok = lh_ASN1_OBJECT_insert(global_added_by_nid, &old_object, obj);
+ if (obj->length != 0 && obj->data != NULL) {
+ ok &= lh_ASN1_OBJECT_insert(global_added_by_data, &old_object, obj);
+ }
+ if (obj->sn != NULL) {
+ ok &= lh_ASN1_OBJECT_insert(global_added_by_short_name, &old_object, obj);
+ }
+ if (obj->ln != NULL) {
+ ok &= lh_ASN1_OBJECT_insert(global_added_by_long_name, &old_object, obj);
+ }
+ CRYPTO_w_unlock(CRYPTO_LOCK_OBJ);
+
+ return ok;
+}
+
+int OBJ_create(const char *oid, const char *short_name, const char *long_name) {
+ int ret = NID_undef;
+ ASN1_OBJECT *op = NULL;
+ unsigned char *buf = NULL;
+ int len;
+
+ len = a2d_ASN1_OBJECT(NULL, 0, oid, -1);
+ if (len <= 0) {
+ goto err;
+ }
+
+ buf = OPENSSL_malloc(len);
+ if (buf == NULL) {
+ OPENSSL_PUT_ERROR(OBJ, OBJ_create, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ len = a2d_ASN1_OBJECT(buf, len, oid, -1);
+ if (len == 0) {
+ goto err;
+ }
+
+ op = (ASN1_OBJECT *)ASN1_OBJECT_create(obj_next_nid(), buf, len, short_name,
+ long_name);
+ if (op == NULL) {
+ goto err;
+ }
+
+ if (obj_add_object(op)) {
+ ret = op->nid;
+ }
+ op = NULL;
+
+err:
+ if (op != NULL) {
+ ASN1_OBJECT_free(op);
+ }
+ if (buf != NULL) {
+ OPENSSL_free(buf);
+ }
+
+ return ret;
+}
diff --git a/crypto/obj/obj.h b/crypto/obj/obj.h
new file mode 100644
index 0000000..7c9772a
--- /dev/null
+++ b/crypto/obj/obj.h
@@ -0,0 +1,193 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_OBJECTS_H
+#define OPENSSL_HEADER_OBJECTS_H
+
+#include <openssl/base.h>
+
+#include <openssl/obj_mac.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* The objects library deals with the registration and indexing of ASN.1 object
+ * identifiers. These values are often written as a dotted sequence of numbers,
+ * e.g. 1.2.840.113549.1.9.16.3.9.
+ *
+ * Internally, OpenSSL likes to deal with these values by numbering them with
+ * numbers called "nids". OpenSSL has a large, built-in database of common
+ * object identifiers and also has both short and long names for them.
+ *
+ * This library provides functions for translating between object identifiers,
+ * nids, short names and long names.
+ *
+ * The nid values should not be used outside of a single process: they are not
+ * stable identifiers. */
+
+
+/* Basic operations. */
+
+/* OBJ_dup returns a duplicate copy of |obj| or NULL on allocation failure. */
+ASN1_OBJECT *OBJ_dup(const ASN1_OBJECT *obj);
+
+/* OBJ_cmp returns a value less than, equal to or greater than zero if |a| is
+ * less than, equal to or greater than |b|, respectively. */
+int OBJ_cmp(const ASN1_OBJECT *a, const ASN1_OBJECT *b);
+
+
+/* Looking up nids. */
+
+/* OBJ_obj2nid returns the nid corresponding to |obj|, or |NID_undef| if no
+ * such object is known. */
+int OBJ_obj2nid(const ASN1_OBJECT *obj);
+
+/* OBJ_cbs2nid returns the nid corresponding to the DER data in |cbs|, or
+ * |NID_undef| if no such object is known. */
+int OBJ_cbs2nid(const CBS *cbs);
+
+/* OBJ_sn2nid returns the nid corresponding to |short_name|, or |NID_undef| if
+ * no such short name is known. */
+int OBJ_sn2nid(const char *short_name);
+
+/* OBJ_ln2nid returns the nid corresponding to |long_name|, or |NID_undef| if
+ * no such long name is known. */
+int OBJ_ln2nid(const char *long_name);
+
+/* OBJ_txt2nid returns the nid corresponding to |s|, which may be a short name,
+ * long name, or an ASCII string containing a dotted sequence of numbers. It
+ * returns the nid or NID_undef if unknown. */
+int OBJ_txt2nid(const char *s);
+
+
+/* Getting information about nids. */
+
+/* OBJ_nid2obj returns the ASN1_OBJECT corresponding to |nid|, or NULL if |nid|
+ * is unknown. */
+const ASN1_OBJECT *OBJ_nid2obj(int nid);
+
+/* OBJ_nid2sn returns the short name for |nid|, or NULL if |nid| is unknown. */
+const char *OBJ_nid2sn(int nid);
+
+/* OBJ_nid2sn returns the long name for |nid|, or NULL if |nid| is unknown. */
+const char *OBJ_nid2ln(int nid);
+
+
+/* Dealing with textual representations of object identifiers. */
+
+/* OBJ_txt2obj returns an ASN1_OBJECT for the textual respresentation in |s|.
+ * If |dont_search_names| is zero, then |s| will be matched against the long
+ * and short names of a known objects to find a match. Otherwise |s| must
+ * contain an ASCII string with a dotted sequence of numbers. The resulting
+ * object need not be previously known. It returns NULL on error. */
+ASN1_OBJECT *OBJ_txt2obj(const char *s, int dont_search_names);
+
+/* OBJ_obj2txt converts |obj| to a textual representation. If
+ * |dont_return_name| is zero then |obj| will be matched against known objects
+ * and the long (preferably) or short name will be used if found. Otherwise
+ * |obj| will be converted into a dotted sequence of integers. If |out| is not
+ * NULL, then at most |out_len| bytes of the textual form will be written
+ * there. If |out_len| is at least one, then string written to |out| will
+ * always be NUL terminated. It returns the number of characters that could
+ * have been written, not including the final NUL, or -1 on error. */
+int OBJ_obj2txt(char *out, int out_len, const ASN1_OBJECT *obj,
+ int dont_return_name);
+
+
+/* Adding objects at runtime. */
+
+/* OBJ_create adds a known object and returns the nid of the new object, or
+ * NID_undef on error. */
+int OBJ_create(const char *oid, const char *short_name, const char *long_name);
+
+
+/* Handling signature algorithm identifiers.
+ *
+ * Some NIDs (e.g. sha256WithRSAEncryption) specify both a digest algorithm and
+ * a public key algorithm. The following functions map between pairs of digest
+ * and public-key algorithms and the NIDs that specify their combination.
+ *
+ * Sometimes the combination NID leaves the digest unspecified (e.g.
+ * rsassaPss). In these cases, the digest NID is |NID_undef|. */
+
+/* OBJ_find_sigid_algs finds the digest and public-key NIDs that correspond to
+ * the signing algorithm |sign_nid|. If successful, it sets |*out_digest_nid|
+ * and |*out_pkey_nid| and returns one. Otherwise it returns zero. Any of
+ * |out_digest_nid| or |out_pkey_nid| can be NULL if the caller doesn't need
+ * that output value. */
+int OBJ_find_sigid_algs(int sign_nid, int *out_digest_nid, int *out_pkey_nid);
+
+/* OBJ_find_sigid_by_algs finds the signature NID that corresponds to the
+ * combination of |digest_nid| and |pkey_nid|. If success, it sets
+ * |*out_sign_nid| and returns one. Otherwise it returns zero. The
+ * |out_sign_nid| argument can be NULL if the caller only wishes to learn
+ * whether the combination is valid. */
+int OBJ_find_sigid_by_algs(int *out_sign_nid, int digest_nid, int pkey_nid);
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#define OBJ_F_OBJ_txt2obj 100
+#define OBJ_F_OBJ_create 101
+#define OBJ_F_OBJ_dup 102
+#define OBJ_F_OBJ_nid2obj 103
+#define OBJ_R_UNKNOWN_NID 100
+
+#endif /* OPENSSL_HEADER_OBJECTS_H */
diff --git a/crypto/obj/obj_dat.h b/crypto/obj/obj_dat.h
new file mode 100644
index 0000000..3863f5d
--- /dev/null
+++ b/crypto/obj/obj_dat.h
@@ -0,0 +1,5275 @@
+/* crypto/objects/obj_dat.h */
+
+/* THIS FILE IS GENERATED FROM objects.h by obj_dat.pl via the
+ * following command:
+ * perl obj_dat.pl obj_mac.h obj_dat.h
+ */
+
+/* Copyright (C) 1995-1997 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.]
+ */
+
+#define NUM_NID 951
+#define NUM_SN 941
+#define NUM_LN 941
+#define NUM_OBJ 883
+
+static const unsigned char lvalues[6188]={
+0x00, /* [ 0] OBJ_undef */
+0x2A,0x86,0x48,0x86,0xF7,0x0D, /* [ 1] OBJ_rsadsi */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, /* [ 7] OBJ_pkcs */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x02, /* [ 14] OBJ_md2 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x05, /* [ 22] OBJ_md5 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x03,0x04, /* [ 30] OBJ_rc4 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,/* [ 38] OBJ_rsaEncryption */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x02,/* [ 47] OBJ_md2WithRSAEncryption */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x04,/* [ 56] OBJ_md5WithRSAEncryption */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x01,/* [ 65] OBJ_pbeWithMD2AndDES_CBC */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x03,/* [ 74] OBJ_pbeWithMD5AndDES_CBC */
+0x55, /* [ 83] OBJ_X500 */
+0x55,0x04, /* [ 84] OBJ_X509 */
+0x55,0x04,0x03, /* [ 86] OBJ_commonName */
+0x55,0x04,0x06, /* [ 89] OBJ_countryName */
+0x55,0x04,0x07, /* [ 92] OBJ_localityName */
+0x55,0x04,0x08, /* [ 95] OBJ_stateOrProvinceName */
+0x55,0x04,0x0A, /* [ 98] OBJ_organizationName */
+0x55,0x04,0x0B, /* [101] OBJ_organizationalUnitName */
+0x55,0x08,0x01,0x01, /* [104] OBJ_rsa */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07, /* [108] OBJ_pkcs7 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07,0x01,/* [116] OBJ_pkcs7_data */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07,0x02,/* [125] OBJ_pkcs7_signed */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07,0x03,/* [134] OBJ_pkcs7_enveloped */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07,0x04,/* [143] OBJ_pkcs7_signedAndEnveloped */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07,0x05,/* [152] OBJ_pkcs7_digest */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07,0x06,/* [161] OBJ_pkcs7_encrypted */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x03, /* [170] OBJ_pkcs3 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x03,0x01,/* [178] OBJ_dhKeyAgreement */
+0x2B,0x0E,0x03,0x02,0x06, /* [187] OBJ_des_ecb */
+0x2B,0x0E,0x03,0x02,0x09, /* [192] OBJ_des_cfb64 */
+0x2B,0x0E,0x03,0x02,0x07, /* [197] OBJ_des_cbc */
+0x2B,0x0E,0x03,0x02,0x11, /* [202] OBJ_des_ede_ecb */
+0x2B,0x06,0x01,0x04,0x01,0x81,0x3C,0x07,0x01,0x01,0x02,/* [207] OBJ_idea_cbc */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x03,0x02, /* [218] OBJ_rc2_cbc */
+0x2B,0x0E,0x03,0x02,0x12, /* [226] OBJ_sha */
+0x2B,0x0E,0x03,0x02,0x0F, /* [231] OBJ_shaWithRSAEncryption */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x03,0x07, /* [236] OBJ_des_ede3_cbc */
+0x2B,0x0E,0x03,0x02,0x08, /* [244] OBJ_des_ofb64 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09, /* [249] OBJ_pkcs9 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x01,/* [257] OBJ_pkcs9_emailAddress */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x02,/* [266] OBJ_pkcs9_unstructuredName */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x03,/* [275] OBJ_pkcs9_contentType */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x04,/* [284] OBJ_pkcs9_messageDigest */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x05,/* [293] OBJ_pkcs9_signingTime */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x06,/* [302] OBJ_pkcs9_countersignature */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x07,/* [311] OBJ_pkcs9_challengePassword */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x08,/* [320] OBJ_pkcs9_unstructuredAddress */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x09,/* [329] OBJ_pkcs9_extCertAttributes */
+0x60,0x86,0x48,0x01,0x86,0xF8,0x42, /* [338] OBJ_netscape */
+0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01, /* [345] OBJ_netscape_cert_extension */
+0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x02, /* [353] OBJ_netscape_data_type */
+0x2B,0x0E,0x03,0x02,0x1A, /* [361] OBJ_sha1 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,/* [366] OBJ_sha1WithRSAEncryption */
+0x2B,0x0E,0x03,0x02,0x0D, /* [375] OBJ_dsaWithSHA */
+0x2B,0x0E,0x03,0x02,0x0C, /* [380] OBJ_dsa_2 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x0B,/* [385] OBJ_pbeWithSHA1AndRC2_CBC */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x0C,/* [394] OBJ_id_pbkdf2 */
+0x2B,0x0E,0x03,0x02,0x1B, /* [403] OBJ_dsaWithSHA1_2 */
+0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x01,/* [408] OBJ_netscape_cert_type */
+0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x02,/* [417] OBJ_netscape_base_url */
+0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x03,/* [426] OBJ_netscape_revocation_url */
+0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x04,/* [435] OBJ_netscape_ca_revocation_url */
+0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x07,/* [444] OBJ_netscape_renewal_url */
+0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x08,/* [453] OBJ_netscape_ca_policy_url */
+0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x0C,/* [462] OBJ_netscape_ssl_server_name */
+0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x01,0x0D,/* [471] OBJ_netscape_comment */
+0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x02,0x05,/* [480] OBJ_netscape_cert_sequence */
+0x55,0x1D, /* [489] OBJ_id_ce */
+0x55,0x1D,0x0E, /* [491] OBJ_subject_key_identifier */
+0x55,0x1D,0x0F, /* [494] OBJ_key_usage */
+0x55,0x1D,0x10, /* [497] OBJ_private_key_usage_period */
+0x55,0x1D,0x11, /* [500] OBJ_subject_alt_name */
+0x55,0x1D,0x12, /* [503] OBJ_issuer_alt_name */
+0x55,0x1D,0x13, /* [506] OBJ_basic_constraints */
+0x55,0x1D,0x14, /* [509] OBJ_crl_number */
+0x55,0x1D,0x20, /* [512] OBJ_certificate_policies */
+0x55,0x1D,0x23, /* [515] OBJ_authority_key_identifier */
+0x2B,0x06,0x01,0x04,0x01,0x97,0x55,0x01,0x02,/* [518] OBJ_bf_cbc */
+0x55,0x08,0x03,0x65, /* [527] OBJ_mdc2 */
+0x55,0x08,0x03,0x64, /* [531] OBJ_mdc2WithRSA */
+0x55,0x04,0x2A, /* [535] OBJ_givenName */
+0x55,0x04,0x04, /* [538] OBJ_surname */
+0x55,0x04,0x2B, /* [541] OBJ_initials */
+0x55,0x1D,0x1F, /* [544] OBJ_crl_distribution_points */
+0x2B,0x0E,0x03,0x02,0x03, /* [547] OBJ_md5WithRSA */
+0x55,0x04,0x05, /* [552] OBJ_serialNumber */
+0x55,0x04,0x0C, /* [555] OBJ_title */
+0x55,0x04,0x0D, /* [558] OBJ_description */
+0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07,0x42,0x0A,/* [561] OBJ_cast5_cbc */
+0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07,0x42,0x0C,/* [570] OBJ_pbeWithMD5AndCast5_CBC */
+0x2A,0x86,0x48,0xCE,0x38,0x04,0x03, /* [579] OBJ_dsaWithSHA1 */
+0x2B,0x0E,0x03,0x02,0x1D, /* [586] OBJ_sha1WithRSA */
+0x2A,0x86,0x48,0xCE,0x38,0x04,0x01, /* [591] OBJ_dsa */
+0x2B,0x24,0x03,0x02,0x01, /* [598] OBJ_ripemd160 */
+0x2B,0x24,0x03,0x03,0x01,0x02, /* [603] OBJ_ripemd160WithRSA */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x03,0x08, /* [609] OBJ_rc5_cbc */
+0x29,0x01,0x01,0x85,0x1A,0x01, /* [617] OBJ_rle_compression */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x08,/* [623] OBJ_zlib_compression */
+0x55,0x1D,0x25, /* [634] OBJ_ext_key_usage */
+0x2B,0x06,0x01,0x05,0x05,0x07, /* [637] OBJ_id_pkix */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x03, /* [643] OBJ_id_kp */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x01, /* [650] OBJ_server_auth */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x02, /* [658] OBJ_client_auth */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x03, /* [666] OBJ_code_sign */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x04, /* [674] OBJ_email_protect */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x08, /* [682] OBJ_time_stamp */
+0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x02,0x01,0x15,/* [690] OBJ_ms_code_ind */
+0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x02,0x01,0x16,/* [700] OBJ_ms_code_com */
+0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x0A,0x03,0x01,/* [710] OBJ_ms_ctl_sign */
+0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x0A,0x03,0x03,/* [720] OBJ_ms_sgc */
+0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x0A,0x03,0x04,/* [730] OBJ_ms_efs */
+0x60,0x86,0x48,0x01,0x86,0xF8,0x42,0x04,0x01,/* [740] OBJ_ns_sgc */
+0x55,0x1D,0x1B, /* [749] OBJ_delta_crl */
+0x55,0x1D,0x15, /* [752] OBJ_crl_reason */
+0x55,0x1D,0x18, /* [755] OBJ_invalidity_date */
+0x2B,0x65,0x01,0x04,0x01, /* [758] OBJ_sxnet */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x01,0x01,/* [763] OBJ_pbe_WithSHA1And128BitRC4 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x01,0x02,/* [773] OBJ_pbe_WithSHA1And40BitRC4 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x01,0x03,/* [783] OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x01,0x04,/* [793] OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x01,0x05,/* [803] OBJ_pbe_WithSHA1And128BitRC2_CBC */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x01,0x06,/* [813] OBJ_pbe_WithSHA1And40BitRC2_CBC */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x0A,0x01,0x01,/* [823] OBJ_keyBag */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x0A,0x01,0x02,/* [834] OBJ_pkcs8ShroudedKeyBag */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x0A,0x01,0x03,/* [845] OBJ_certBag */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x0A,0x01,0x04,/* [856] OBJ_crlBag */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x0A,0x01,0x05,/* [867] OBJ_secretBag */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x0C,0x0A,0x01,0x06,/* [878] OBJ_safeContentsBag */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x14,/* [889] OBJ_friendlyName */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x15,/* [898] OBJ_localKeyID */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x16,0x01,/* [907] OBJ_x509Certificate */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x16,0x02,/* [917] OBJ_sdsiCertificate */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x17,0x01,/* [927] OBJ_x509Crl */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x0D,/* [937] OBJ_pbes2 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x0E,/* [946] OBJ_pbmac1 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x07, /* [955] OBJ_hmacWithSHA1 */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01, /* [963] OBJ_id_qt_cps */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x02, /* [971] OBJ_id_qt_unotice */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x0F,/* [979] OBJ_SMIMECapabilities */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x04,/* [988] OBJ_pbeWithMD2AndRC2_CBC */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x06,/* [997] OBJ_pbeWithMD5AndRC2_CBC */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05,0x0A,/* [1006] OBJ_pbeWithSHA1AndDES_CBC */
+0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x02,0x01,0x0E,/* [1015] OBJ_ms_ext_req */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x0E,/* [1025] OBJ_ext_req */
+0x55,0x04,0x29, /* [1034] OBJ_name */
+0x55,0x04,0x2E, /* [1037] OBJ_dnQualifier */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x01, /* [1040] OBJ_id_pe */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x30, /* [1047] OBJ_id_ad */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01, /* [1054] OBJ_info_access */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01, /* [1062] OBJ_ad_OCSP */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02, /* [1070] OBJ_ad_ca_issuers */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x09, /* [1078] OBJ_OCSP_sign */
+0x28, /* [1086] OBJ_iso */
+0x2A, /* [1087] OBJ_member_body */
+0x2A,0x86,0x48, /* [1088] OBJ_ISO_US */
+0x2A,0x86,0x48,0xCE,0x38, /* [1091] OBJ_X9_57 */
+0x2A,0x86,0x48,0xCE,0x38,0x04, /* [1096] OBJ_X9cm */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01, /* [1102] OBJ_pkcs1 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x05, /* [1110] OBJ_pkcs5 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,/* [1118] OBJ_SMIME */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,/* [1127] OBJ_id_smime_mod */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,/* [1137] OBJ_id_smime_ct */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,/* [1147] OBJ_id_smime_aa */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,/* [1157] OBJ_id_smime_alg */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x04,/* [1167] OBJ_id_smime_cd */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x05,/* [1177] OBJ_id_smime_spq */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x06,/* [1187] OBJ_id_smime_cti */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,0x01,/* [1197] OBJ_id_smime_mod_cms */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,0x02,/* [1208] OBJ_id_smime_mod_ess */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,0x03,/* [1219] OBJ_id_smime_mod_oid */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,0x04,/* [1230] OBJ_id_smime_mod_msg_v3 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,0x05,/* [1241] OBJ_id_smime_mod_ets_eSignature_88 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,0x06,/* [1252] OBJ_id_smime_mod_ets_eSignature_97 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,0x07,/* [1263] OBJ_id_smime_mod_ets_eSigPolicy_88 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x00,0x08,/* [1274] OBJ_id_smime_mod_ets_eSigPolicy_97 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x01,/* [1285] OBJ_id_smime_ct_receipt */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x02,/* [1296] OBJ_id_smime_ct_authData */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x03,/* [1307] OBJ_id_smime_ct_publishCert */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x04,/* [1318] OBJ_id_smime_ct_TSTInfo */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x05,/* [1329] OBJ_id_smime_ct_TDTInfo */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x06,/* [1340] OBJ_id_smime_ct_contentInfo */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x07,/* [1351] OBJ_id_smime_ct_DVCSRequestData */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x08,/* [1362] OBJ_id_smime_ct_DVCSResponseData */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x01,/* [1373] OBJ_id_smime_aa_receiptRequest */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x02,/* [1384] OBJ_id_smime_aa_securityLabel */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x03,/* [1395] OBJ_id_smime_aa_mlExpandHistory */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x04,/* [1406] OBJ_id_smime_aa_contentHint */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x05,/* [1417] OBJ_id_smime_aa_msgSigDigest */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x06,/* [1428] OBJ_id_smime_aa_encapContentType */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x07,/* [1439] OBJ_id_smime_aa_contentIdentifier */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x08,/* [1450] OBJ_id_smime_aa_macValue */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x09,/* [1461] OBJ_id_smime_aa_equivalentLabels */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x0A,/* [1472] OBJ_id_smime_aa_contentReference */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x0B,/* [1483] OBJ_id_smime_aa_encrypKeyPref */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x0C,/* [1494] OBJ_id_smime_aa_signingCertificate */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x0D,/* [1505] OBJ_id_smime_aa_smimeEncryptCerts */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x0E,/* [1516] OBJ_id_smime_aa_timeStampToken */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x0F,/* [1527] OBJ_id_smime_aa_ets_sigPolicyId */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x10,/* [1538] OBJ_id_smime_aa_ets_commitmentType */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x11,/* [1549] OBJ_id_smime_aa_ets_signerLocation */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x12,/* [1560] OBJ_id_smime_aa_ets_signerAttr */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x13,/* [1571] OBJ_id_smime_aa_ets_otherSigCert */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x14,/* [1582] OBJ_id_smime_aa_ets_contentTimestamp */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x15,/* [1593] OBJ_id_smime_aa_ets_CertificateRefs */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x16,/* [1604] OBJ_id_smime_aa_ets_RevocationRefs */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x17,/* [1615] OBJ_id_smime_aa_ets_certValues */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x18,/* [1626] OBJ_id_smime_aa_ets_revocationValues */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x19,/* [1637] OBJ_id_smime_aa_ets_escTimeStamp */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x1A,/* [1648] OBJ_id_smime_aa_ets_certCRLTimestamp */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x1B,/* [1659] OBJ_id_smime_aa_ets_archiveTimeStamp */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x1C,/* [1670] OBJ_id_smime_aa_signatureType */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x02,0x1D,/* [1681] OBJ_id_smime_aa_dvcs_dvc */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x01,/* [1692] OBJ_id_smime_alg_ESDHwith3DES */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x02,/* [1703] OBJ_id_smime_alg_ESDHwithRC2 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x03,/* [1714] OBJ_id_smime_alg_3DESwrap */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x04,/* [1725] OBJ_id_smime_alg_RC2wrap */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x05,/* [1736] OBJ_id_smime_alg_ESDH */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x06,/* [1747] OBJ_id_smime_alg_CMS3DESwrap */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x07,/* [1758] OBJ_id_smime_alg_CMSRC2wrap */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x04,0x01,/* [1769] OBJ_id_smime_cd_ldap */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x05,0x01,/* [1780] OBJ_id_smime_spq_ets_sqt_uri */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x05,0x02,/* [1791] OBJ_id_smime_spq_ets_sqt_unotice */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x06,0x01,/* [1802] OBJ_id_smime_cti_ets_proofOfOrigin */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x06,0x02,/* [1813] OBJ_id_smime_cti_ets_proofOfReceipt */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x06,0x03,/* [1824] OBJ_id_smime_cti_ets_proofOfDelivery */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x06,0x04,/* [1835] OBJ_id_smime_cti_ets_proofOfSender */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x06,0x05,/* [1846] OBJ_id_smime_cti_ets_proofOfApproval */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x06,0x06,/* [1857] OBJ_id_smime_cti_ets_proofOfCreation */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x04, /* [1868] OBJ_md4 */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x00, /* [1876] OBJ_id_pkix_mod */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x02, /* [1883] OBJ_id_qt */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x04, /* [1890] OBJ_id_it */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x05, /* [1897] OBJ_id_pkip */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x06, /* [1904] OBJ_id_alg */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x07, /* [1911] OBJ_id_cmc */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x08, /* [1918] OBJ_id_on */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x09, /* [1925] OBJ_id_pda */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x0A, /* [1932] OBJ_id_aca */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x0B, /* [1939] OBJ_id_qcs */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x0C, /* [1946] OBJ_id_cct */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x01, /* [1953] OBJ_id_pkix1_explicit_88 */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x02, /* [1961] OBJ_id_pkix1_implicit_88 */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x03, /* [1969] OBJ_id_pkix1_explicit_93 */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x04, /* [1977] OBJ_id_pkix1_implicit_93 */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x05, /* [1985] OBJ_id_mod_crmf */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x06, /* [1993] OBJ_id_mod_cmc */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x07, /* [2001] OBJ_id_mod_kea_profile_88 */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x08, /* [2009] OBJ_id_mod_kea_profile_93 */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x09, /* [2017] OBJ_id_mod_cmp */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x0A, /* [2025] OBJ_id_mod_qualified_cert_88 */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x0B, /* [2033] OBJ_id_mod_qualified_cert_93 */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x0C, /* [2041] OBJ_id_mod_attribute_cert */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x0D, /* [2049] OBJ_id_mod_timestamp_protocol */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x0E, /* [2057] OBJ_id_mod_ocsp */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x0F, /* [2065] OBJ_id_mod_dvcs */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x00,0x10, /* [2073] OBJ_id_mod_cmp2000 */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x02, /* [2081] OBJ_biometricInfo */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x03, /* [2089] OBJ_qcStatements */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x04, /* [2097] OBJ_ac_auditEntity */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x05, /* [2105] OBJ_ac_targeting */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x06, /* [2113] OBJ_aaControls */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x07, /* [2121] OBJ_sbgp_ipAddrBlock */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x08, /* [2129] OBJ_sbgp_autonomousSysNum */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x09, /* [2137] OBJ_sbgp_routerIdentifier */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x03, /* [2145] OBJ_textNotice */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x05, /* [2153] OBJ_ipsecEndSystem */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x06, /* [2161] OBJ_ipsecTunnel */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x07, /* [2169] OBJ_ipsecUser */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x0A, /* [2177] OBJ_dvcs */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x01, /* [2185] OBJ_id_it_caProtEncCert */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x02, /* [2193] OBJ_id_it_signKeyPairTypes */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x03, /* [2201] OBJ_id_it_encKeyPairTypes */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x04, /* [2209] OBJ_id_it_preferredSymmAlg */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x05, /* [2217] OBJ_id_it_caKeyUpdateInfo */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x06, /* [2225] OBJ_id_it_currentCRL */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x07, /* [2233] OBJ_id_it_unsupportedOIDs */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x08, /* [2241] OBJ_id_it_subscriptionRequest */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x09, /* [2249] OBJ_id_it_subscriptionResponse */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x0A, /* [2257] OBJ_id_it_keyPairParamReq */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x0B, /* [2265] OBJ_id_it_keyPairParamRep */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x0C, /* [2273] OBJ_id_it_revPassphrase */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x0D, /* [2281] OBJ_id_it_implicitConfirm */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x0E, /* [2289] OBJ_id_it_confirmWaitTime */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x0F, /* [2297] OBJ_id_it_origPKIMessage */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x01, /* [2305] OBJ_id_regCtrl */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x02, /* [2313] OBJ_id_regInfo */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x01,0x01,/* [2321] OBJ_id_regCtrl_regToken */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x01,0x02,/* [2330] OBJ_id_regCtrl_authenticator */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x01,0x03,/* [2339] OBJ_id_regCtrl_pkiPublicationInfo */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x01,0x04,/* [2348] OBJ_id_regCtrl_pkiArchiveOptions */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x01,0x05,/* [2357] OBJ_id_regCtrl_oldCertID */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x01,0x06,/* [2366] OBJ_id_regCtrl_protocolEncrKey */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x02,0x01,/* [2375] OBJ_id_regInfo_utf8Pairs */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x05,0x02,0x02,/* [2384] OBJ_id_regInfo_certReq */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x01, /* [2393] OBJ_id_alg_des40 */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x02, /* [2401] OBJ_id_alg_noSignature */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x03, /* [2409] OBJ_id_alg_dh_sig_hmac_sha1 */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x04, /* [2417] OBJ_id_alg_dh_pop */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x01, /* [2425] OBJ_id_cmc_statusInfo */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x02, /* [2433] OBJ_id_cmc_identification */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x03, /* [2441] OBJ_id_cmc_identityProof */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x04, /* [2449] OBJ_id_cmc_dataReturn */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x05, /* [2457] OBJ_id_cmc_transactionId */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x06, /* [2465] OBJ_id_cmc_senderNonce */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x07, /* [2473] OBJ_id_cmc_recipientNonce */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x08, /* [2481] OBJ_id_cmc_addExtensions */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x09, /* [2489] OBJ_id_cmc_encryptedPOP */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x0A, /* [2497] OBJ_id_cmc_decryptedPOP */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x0B, /* [2505] OBJ_id_cmc_lraPOPWitness */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x0F, /* [2513] OBJ_id_cmc_getCert */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x10, /* [2521] OBJ_id_cmc_getCRL */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x11, /* [2529] OBJ_id_cmc_revokeRequest */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x12, /* [2537] OBJ_id_cmc_regInfo */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x13, /* [2545] OBJ_id_cmc_responseInfo */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x15, /* [2553] OBJ_id_cmc_queryPending */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x16, /* [2561] OBJ_id_cmc_popLinkRandom */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x17, /* [2569] OBJ_id_cmc_popLinkWitness */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x07,0x18, /* [2577] OBJ_id_cmc_confirmCertAcceptance */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x08,0x01, /* [2585] OBJ_id_on_personalData */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x09,0x01, /* [2593] OBJ_id_pda_dateOfBirth */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x09,0x02, /* [2601] OBJ_id_pda_placeOfBirth */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x09,0x03, /* [2609] OBJ_id_pda_gender */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x09,0x04, /* [2617] OBJ_id_pda_countryOfCitizenship */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x09,0x05, /* [2625] OBJ_id_pda_countryOfResidence */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x0A,0x01, /* [2633] OBJ_id_aca_authenticationInfo */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x0A,0x02, /* [2641] OBJ_id_aca_accessIdentity */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x0A,0x03, /* [2649] OBJ_id_aca_chargingIdentity */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x0A,0x04, /* [2657] OBJ_id_aca_group */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x0A,0x05, /* [2665] OBJ_id_aca_role */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x0B,0x01, /* [2673] OBJ_id_qcs_pkixQCSyntax_v1 */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x0C,0x01, /* [2681] OBJ_id_cct_crs */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x0C,0x02, /* [2689] OBJ_id_cct_PKIData */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x0C,0x03, /* [2697] OBJ_id_cct_PKIResponse */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x03, /* [2705] OBJ_ad_timeStamping */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x04, /* [2713] OBJ_ad_dvcs */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x01,/* [2721] OBJ_id_pkix_OCSP_basic */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x02,/* [2730] OBJ_id_pkix_OCSP_Nonce */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x03,/* [2739] OBJ_id_pkix_OCSP_CrlID */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x04,/* [2748] OBJ_id_pkix_OCSP_acceptableResponses */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x05,/* [2757] OBJ_id_pkix_OCSP_noCheck */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x06,/* [2766] OBJ_id_pkix_OCSP_archiveCutoff */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x07,/* [2775] OBJ_id_pkix_OCSP_serviceLocator */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x08,/* [2784] OBJ_id_pkix_OCSP_extendedStatus */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x09,/* [2793] OBJ_id_pkix_OCSP_valid */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x0A,/* [2802] OBJ_id_pkix_OCSP_path */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x0B,/* [2811] OBJ_id_pkix_OCSP_trustRoot */
+0x2B,0x0E,0x03,0x02, /* [2820] OBJ_algorithm */
+0x2B,0x0E,0x03,0x02,0x0B, /* [2824] OBJ_rsaSignature */
+0x55,0x08, /* [2829] OBJ_X500algorithms */
+0x2B, /* [2831] OBJ_org */
+0x2B,0x06, /* [2832] OBJ_dod */
+0x2B,0x06,0x01, /* [2834] OBJ_iana */
+0x2B,0x06,0x01,0x01, /* [2837] OBJ_Directory */
+0x2B,0x06,0x01,0x02, /* [2841] OBJ_Management */
+0x2B,0x06,0x01,0x03, /* [2845] OBJ_Experimental */
+0x2B,0x06,0x01,0x04, /* [2849] OBJ_Private */
+0x2B,0x06,0x01,0x05, /* [2853] OBJ_Security */
+0x2B,0x06,0x01,0x06, /* [2857] OBJ_SNMPv2 */
+0x2B,0x06,0x01,0x07, /* [2861] OBJ_Mail */
+0x2B,0x06,0x01,0x04,0x01, /* [2865] OBJ_Enterprises */
+0x2B,0x06,0x01,0x04,0x01,0x8B,0x3A,0x82,0x58,/* [2870] OBJ_dcObject */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x19,/* [2879] OBJ_domainComponent */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x0D,/* [2889] OBJ_Domain */
+0x00, /* [2899] OBJ_joint_iso_ccitt */
+0x55,0x01,0x05, /* [2900] OBJ_selected_attribute_types */
+0x55,0x01,0x05,0x37, /* [2903] OBJ_clearance */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x03,/* [2907] OBJ_md4WithRSAEncryption */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x0A, /* [2916] OBJ_ac_proxying */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x0B, /* [2924] OBJ_sinfo_access */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x0A,0x06, /* [2932] OBJ_id_aca_encAttrs */
+0x55,0x04,0x48, /* [2940] OBJ_role */
+0x55,0x1D,0x24, /* [2943] OBJ_policy_constraints */
+0x55,0x1D,0x37, /* [2946] OBJ_target_information */
+0x55,0x1D,0x38, /* [2949] OBJ_no_rev_avail */
+0x00, /* [2952] OBJ_ccitt */
+0x2A,0x86,0x48,0xCE,0x3D, /* [2953] OBJ_ansi_X9_62 */
+0x2A,0x86,0x48,0xCE,0x3D,0x01,0x01, /* [2958] OBJ_X9_62_prime_field */
+0x2A,0x86,0x48,0xCE,0x3D,0x01,0x02, /* [2965] OBJ_X9_62_characteristic_two_field */
+0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01, /* [2972] OBJ_X9_62_id_ecPublicKey */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x01, /* [2979] OBJ_X9_62_prime192v1 */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x02, /* [2987] OBJ_X9_62_prime192v2 */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x03, /* [2995] OBJ_X9_62_prime192v3 */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x04, /* [3003] OBJ_X9_62_prime239v1 */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x05, /* [3011] OBJ_X9_62_prime239v2 */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x06, /* [3019] OBJ_X9_62_prime239v3 */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x07, /* [3027] OBJ_X9_62_prime256v1 */
+0x2A,0x86,0x48,0xCE,0x3D,0x04,0x01, /* [3035] OBJ_ecdsa_with_SHA1 */
+0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x11,0x01,/* [3042] OBJ_ms_csp_name */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x01,/* [3051] OBJ_aes_128_ecb */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x02,/* [3060] OBJ_aes_128_cbc */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x03,/* [3069] OBJ_aes_128_ofb128 */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x04,/* [3078] OBJ_aes_128_cfb128 */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x15,/* [3087] OBJ_aes_192_ecb */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x16,/* [3096] OBJ_aes_192_cbc */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x17,/* [3105] OBJ_aes_192_ofb128 */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x18,/* [3114] OBJ_aes_192_cfb128 */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x29,/* [3123] OBJ_aes_256_ecb */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x2A,/* [3132] OBJ_aes_256_cbc */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x2B,/* [3141] OBJ_aes_256_ofb128 */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x2C,/* [3150] OBJ_aes_256_cfb128 */
+0x55,0x1D,0x17, /* [3159] OBJ_hold_instruction_code */
+0x2A,0x86,0x48,0xCE,0x38,0x02,0x01, /* [3162] OBJ_hold_instruction_none */
+0x2A,0x86,0x48,0xCE,0x38,0x02,0x02, /* [3169] OBJ_hold_instruction_call_issuer */
+0x2A,0x86,0x48,0xCE,0x38,0x02,0x03, /* [3176] OBJ_hold_instruction_reject */
+0x09, /* [3183] OBJ_data */
+0x09,0x92,0x26, /* [3184] OBJ_pss */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C, /* [3187] OBJ_ucl */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64, /* [3194] OBJ_pilot */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,/* [3202] OBJ_pilotAttributeType */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x03,/* [3211] OBJ_pilotAttributeSyntax */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,/* [3220] OBJ_pilotObjectClass */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x0A,/* [3229] OBJ_pilotGroups */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x03,0x04,/* [3238] OBJ_iA5StringSyntax */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x03,0x05,/* [3248] OBJ_caseIgnoreIA5StringSyntax */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x03,/* [3258] OBJ_pilotObject */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x04,/* [3268] OBJ_pilotPerson */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x05,/* [3278] OBJ_account */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x06,/* [3288] OBJ_document */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x07,/* [3298] OBJ_room */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x09,/* [3308] OBJ_documentSeries */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x0E,/* [3318] OBJ_rFC822localPart */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x0F,/* [3328] OBJ_dNSDomain */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x11,/* [3338] OBJ_domainRelatedObject */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x12,/* [3348] OBJ_friendlyCountry */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x13,/* [3358] OBJ_simpleSecurityObject */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x14,/* [3368] OBJ_pilotOrganization */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x15,/* [3378] OBJ_pilotDSA */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x04,0x16,/* [3388] OBJ_qualityLabelledData */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x01,/* [3398] OBJ_userId */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x02,/* [3408] OBJ_textEncodedORAddress */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x03,/* [3418] OBJ_rfc822Mailbox */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x04,/* [3428] OBJ_info */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x05,/* [3438] OBJ_favouriteDrink */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x06,/* [3448] OBJ_roomNumber */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x07,/* [3458] OBJ_photo */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x08,/* [3468] OBJ_userClass */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x09,/* [3478] OBJ_host */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x0A,/* [3488] OBJ_manager */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x0B,/* [3498] OBJ_documentIdentifier */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x0C,/* [3508] OBJ_documentTitle */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x0D,/* [3518] OBJ_documentVersion */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x0E,/* [3528] OBJ_documentAuthor */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x0F,/* [3538] OBJ_documentLocation */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x14,/* [3548] OBJ_homeTelephoneNumber */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x15,/* [3558] OBJ_secretary */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x16,/* [3568] OBJ_otherMailbox */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x17,/* [3578] OBJ_lastModifiedTime */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x18,/* [3588] OBJ_lastModifiedBy */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x1A,/* [3598] OBJ_aRecord */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x1B,/* [3608] OBJ_pilotAttributeType27 */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x1C,/* [3618] OBJ_mXRecord */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x1D,/* [3628] OBJ_nSRecord */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x1E,/* [3638] OBJ_sOARecord */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x1F,/* [3648] OBJ_cNAMERecord */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x25,/* [3658] OBJ_associatedDomain */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x26,/* [3668] OBJ_associatedName */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x27,/* [3678] OBJ_homePostalAddress */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x28,/* [3688] OBJ_personalTitle */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x29,/* [3698] OBJ_mobileTelephoneNumber */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x2A,/* [3708] OBJ_pagerTelephoneNumber */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x2B,/* [3718] OBJ_friendlyCountryName */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x2D,/* [3728] OBJ_organizationalStatus */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x2E,/* [3738] OBJ_janetMailbox */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x2F,/* [3748] OBJ_mailPreferenceOption */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x30,/* [3758] OBJ_buildingName */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x31,/* [3768] OBJ_dSAQuality */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x32,/* [3778] OBJ_singleLevelQuality */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x33,/* [3788] OBJ_subtreeMinimumQuality */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x34,/* [3798] OBJ_subtreeMaximumQuality */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x35,/* [3808] OBJ_personalSignature */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x36,/* [3818] OBJ_dITRedirect */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x37,/* [3828] OBJ_audio */
+0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x38,/* [3838] OBJ_documentPublisher */
+0x55,0x04,0x2D, /* [3848] OBJ_x500UniqueIdentifier */
+0x2B,0x06,0x01,0x07,0x01, /* [3851] OBJ_mime_mhs */
+0x2B,0x06,0x01,0x07,0x01,0x01, /* [3856] OBJ_mime_mhs_headings */
+0x2B,0x06,0x01,0x07,0x01,0x02, /* [3862] OBJ_mime_mhs_bodies */
+0x2B,0x06,0x01,0x07,0x01,0x01,0x01, /* [3868] OBJ_id_hex_partial_message */
+0x2B,0x06,0x01,0x07,0x01,0x01,0x02, /* [3875] OBJ_id_hex_multipart_message */
+0x55,0x04,0x2C, /* [3882] OBJ_generationQualifier */
+0x55,0x04,0x41, /* [3885] OBJ_pseudonym */
+0x67,0x2A, /* [3888] OBJ_id_set */
+0x67,0x2A,0x00, /* [3890] OBJ_set_ctype */
+0x67,0x2A,0x01, /* [3893] OBJ_set_msgExt */
+0x67,0x2A,0x03, /* [3896] OBJ_set_attr */
+0x67,0x2A,0x05, /* [3899] OBJ_set_policy */
+0x67,0x2A,0x07, /* [3902] OBJ_set_certExt */
+0x67,0x2A,0x08, /* [3905] OBJ_set_brand */
+0x67,0x2A,0x00,0x00, /* [3908] OBJ_setct_PANData */
+0x67,0x2A,0x00,0x01, /* [3912] OBJ_setct_PANToken */
+0x67,0x2A,0x00,0x02, /* [3916] OBJ_setct_PANOnly */
+0x67,0x2A,0x00,0x03, /* [3920] OBJ_setct_OIData */
+0x67,0x2A,0x00,0x04, /* [3924] OBJ_setct_PI */
+0x67,0x2A,0x00,0x05, /* [3928] OBJ_setct_PIData */
+0x67,0x2A,0x00,0x06, /* [3932] OBJ_setct_PIDataUnsigned */
+0x67,0x2A,0x00,0x07, /* [3936] OBJ_setct_HODInput */
+0x67,0x2A,0x00,0x08, /* [3940] OBJ_setct_AuthResBaggage */
+0x67,0x2A,0x00,0x09, /* [3944] OBJ_setct_AuthRevReqBaggage */
+0x67,0x2A,0x00,0x0A, /* [3948] OBJ_setct_AuthRevResBaggage */
+0x67,0x2A,0x00,0x0B, /* [3952] OBJ_setct_CapTokenSeq */
+0x67,0x2A,0x00,0x0C, /* [3956] OBJ_setct_PInitResData */
+0x67,0x2A,0x00,0x0D, /* [3960] OBJ_setct_PI_TBS */
+0x67,0x2A,0x00,0x0E, /* [3964] OBJ_setct_PResData */
+0x67,0x2A,0x00,0x10, /* [3968] OBJ_setct_AuthReqTBS */
+0x67,0x2A,0x00,0x11, /* [3972] OBJ_setct_AuthResTBS */
+0x67,0x2A,0x00,0x12, /* [3976] OBJ_setct_AuthResTBSX */
+0x67,0x2A,0x00,0x13, /* [3980] OBJ_setct_AuthTokenTBS */
+0x67,0x2A,0x00,0x14, /* [3984] OBJ_setct_CapTokenData */
+0x67,0x2A,0x00,0x15, /* [3988] OBJ_setct_CapTokenTBS */
+0x67,0x2A,0x00,0x16, /* [3992] OBJ_setct_AcqCardCodeMsg */
+0x67,0x2A,0x00,0x17, /* [3996] OBJ_setct_AuthRevReqTBS */
+0x67,0x2A,0x00,0x18, /* [4000] OBJ_setct_AuthRevResData */
+0x67,0x2A,0x00,0x19, /* [4004] OBJ_setct_AuthRevResTBS */
+0x67,0x2A,0x00,0x1A, /* [4008] OBJ_setct_CapReqTBS */
+0x67,0x2A,0x00,0x1B, /* [4012] OBJ_setct_CapReqTBSX */
+0x67,0x2A,0x00,0x1C, /* [4016] OBJ_setct_CapResData */
+0x67,0x2A,0x00,0x1D, /* [4020] OBJ_setct_CapRevReqTBS */
+0x67,0x2A,0x00,0x1E, /* [4024] OBJ_setct_CapRevReqTBSX */
+0x67,0x2A,0x00,0x1F, /* [4028] OBJ_setct_CapRevResData */
+0x67,0x2A,0x00,0x20, /* [4032] OBJ_setct_CredReqTBS */
+0x67,0x2A,0x00,0x21, /* [4036] OBJ_setct_CredReqTBSX */
+0x67,0x2A,0x00,0x22, /* [4040] OBJ_setct_CredResData */
+0x67,0x2A,0x00,0x23, /* [4044] OBJ_setct_CredRevReqTBS */
+0x67,0x2A,0x00,0x24, /* [4048] OBJ_setct_CredRevReqTBSX */
+0x67,0x2A,0x00,0x25, /* [4052] OBJ_setct_CredRevResData */
+0x67,0x2A,0x00,0x26, /* [4056] OBJ_setct_PCertReqData */
+0x67,0x2A,0x00,0x27, /* [4060] OBJ_setct_PCertResTBS */
+0x67,0x2A,0x00,0x28, /* [4064] OBJ_setct_BatchAdminReqData */
+0x67,0x2A,0x00,0x29, /* [4068] OBJ_setct_BatchAdminResData */
+0x67,0x2A,0x00,0x2A, /* [4072] OBJ_setct_CardCInitResTBS */
+0x67,0x2A,0x00,0x2B, /* [4076] OBJ_setct_MeAqCInitResTBS */
+0x67,0x2A,0x00,0x2C, /* [4080] OBJ_setct_RegFormResTBS */
+0x67,0x2A,0x00,0x2D, /* [4084] OBJ_setct_CertReqData */
+0x67,0x2A,0x00,0x2E, /* [4088] OBJ_setct_CertReqTBS */
+0x67,0x2A,0x00,0x2F, /* [4092] OBJ_setct_CertResData */
+0x67,0x2A,0x00,0x30, /* [4096] OBJ_setct_CertInqReqTBS */
+0x67,0x2A,0x00,0x31, /* [4100] OBJ_setct_ErrorTBS */
+0x67,0x2A,0x00,0x32, /* [4104] OBJ_setct_PIDualSignedTBE */
+0x67,0x2A,0x00,0x33, /* [4108] OBJ_setct_PIUnsignedTBE */
+0x67,0x2A,0x00,0x34, /* [4112] OBJ_setct_AuthReqTBE */
+0x67,0x2A,0x00,0x35, /* [4116] OBJ_setct_AuthResTBE */
+0x67,0x2A,0x00,0x36, /* [4120] OBJ_setct_AuthResTBEX */
+0x67,0x2A,0x00,0x37, /* [4124] OBJ_setct_AuthTokenTBE */
+0x67,0x2A,0x00,0x38, /* [4128] OBJ_setct_CapTokenTBE */
+0x67,0x2A,0x00,0x39, /* [4132] OBJ_setct_CapTokenTBEX */
+0x67,0x2A,0x00,0x3A, /* [4136] OBJ_setct_AcqCardCodeMsgTBE */
+0x67,0x2A,0x00,0x3B, /* [4140] OBJ_setct_AuthRevReqTBE */
+0x67,0x2A,0x00,0x3C, /* [4144] OBJ_setct_AuthRevResTBE */
+0x67,0x2A,0x00,0x3D, /* [4148] OBJ_setct_AuthRevResTBEB */
+0x67,0x2A,0x00,0x3E, /* [4152] OBJ_setct_CapReqTBE */
+0x67,0x2A,0x00,0x3F, /* [4156] OBJ_setct_CapReqTBEX */
+0x67,0x2A,0x00,0x40, /* [4160] OBJ_setct_CapResTBE */
+0x67,0x2A,0x00,0x41, /* [4164] OBJ_setct_CapRevReqTBE */
+0x67,0x2A,0x00,0x42, /* [4168] OBJ_setct_CapRevReqTBEX */
+0x67,0x2A,0x00,0x43, /* [4172] OBJ_setct_CapRevResTBE */
+0x67,0x2A,0x00,0x44, /* [4176] OBJ_setct_CredReqTBE */
+0x67,0x2A,0x00,0x45, /* [4180] OBJ_setct_CredReqTBEX */
+0x67,0x2A,0x00,0x46, /* [4184] OBJ_setct_CredResTBE */
+0x67,0x2A,0x00,0x47, /* [4188] OBJ_setct_CredRevReqTBE */
+0x67,0x2A,0x00,0x48, /* [4192] OBJ_setct_CredRevReqTBEX */
+0x67,0x2A,0x00,0x49, /* [4196] OBJ_setct_CredRevResTBE */
+0x67,0x2A,0x00,0x4A, /* [4200] OBJ_setct_BatchAdminReqTBE */
+0x67,0x2A,0x00,0x4B, /* [4204] OBJ_setct_BatchAdminResTBE */
+0x67,0x2A,0x00,0x4C, /* [4208] OBJ_setct_RegFormReqTBE */
+0x67,0x2A,0x00,0x4D, /* [4212] OBJ_setct_CertReqTBE */
+0x67,0x2A,0x00,0x4E, /* [4216] OBJ_setct_CertReqTBEX */
+0x67,0x2A,0x00,0x4F, /* [4220] OBJ_setct_CertResTBE */
+0x67,0x2A,0x00,0x50, /* [4224] OBJ_setct_CRLNotificationTBS */
+0x67,0x2A,0x00,0x51, /* [4228] OBJ_setct_CRLNotificationResTBS */
+0x67,0x2A,0x00,0x52, /* [4232] OBJ_setct_BCIDistributionTBS */
+0x67,0x2A,0x01,0x01, /* [4236] OBJ_setext_genCrypt */
+0x67,0x2A,0x01,0x03, /* [4240] OBJ_setext_miAuth */
+0x67,0x2A,0x01,0x04, /* [4244] OBJ_setext_pinSecure */
+0x67,0x2A,0x01,0x05, /* [4248] OBJ_setext_pinAny */
+0x67,0x2A,0x01,0x07, /* [4252] OBJ_setext_track2 */
+0x67,0x2A,0x01,0x08, /* [4256] OBJ_setext_cv */
+0x67,0x2A,0x05,0x00, /* [4260] OBJ_set_policy_root */
+0x67,0x2A,0x07,0x00, /* [4264] OBJ_setCext_hashedRoot */
+0x67,0x2A,0x07,0x01, /* [4268] OBJ_setCext_certType */
+0x67,0x2A,0x07,0x02, /* [4272] OBJ_setCext_merchData */
+0x67,0x2A,0x07,0x03, /* [4276] OBJ_setCext_cCertRequired */
+0x67,0x2A,0x07,0x04, /* [4280] OBJ_setCext_tunneling */
+0x67,0x2A,0x07,0x05, /* [4284] OBJ_setCext_setExt */
+0x67,0x2A,0x07,0x06, /* [4288] OBJ_setCext_setQualf */
+0x67,0x2A,0x07,0x07, /* [4292] OBJ_setCext_PGWYcapabilities */
+0x67,0x2A,0x07,0x08, /* [4296] OBJ_setCext_TokenIdentifier */
+0x67,0x2A,0x07,0x09, /* [4300] OBJ_setCext_Track2Data */
+0x67,0x2A,0x07,0x0A, /* [4304] OBJ_setCext_TokenType */
+0x67,0x2A,0x07,0x0B, /* [4308] OBJ_setCext_IssuerCapabilities */
+0x67,0x2A,0x03,0x00, /* [4312] OBJ_setAttr_Cert */
+0x67,0x2A,0x03,0x01, /* [4316] OBJ_setAttr_PGWYcap */
+0x67,0x2A,0x03,0x02, /* [4320] OBJ_setAttr_TokenType */
+0x67,0x2A,0x03,0x03, /* [4324] OBJ_setAttr_IssCap */
+0x67,0x2A,0x03,0x00,0x00, /* [4328] OBJ_set_rootKeyThumb */
+0x67,0x2A,0x03,0x00,0x01, /* [4333] OBJ_set_addPolicy */
+0x67,0x2A,0x03,0x02,0x01, /* [4338] OBJ_setAttr_Token_EMV */
+0x67,0x2A,0x03,0x02,0x02, /* [4343] OBJ_setAttr_Token_B0Prime */
+0x67,0x2A,0x03,0x03,0x03, /* [4348] OBJ_setAttr_IssCap_CVM */
+0x67,0x2A,0x03,0x03,0x04, /* [4353] OBJ_setAttr_IssCap_T2 */
+0x67,0x2A,0x03,0x03,0x05, /* [4358] OBJ_setAttr_IssCap_Sig */
+0x67,0x2A,0x03,0x03,0x03,0x01, /* [4363] OBJ_setAttr_GenCryptgrm */
+0x67,0x2A,0x03,0x03,0x04,0x01, /* [4369] OBJ_setAttr_T2Enc */
+0x67,0x2A,0x03,0x03,0x04,0x02, /* [4375] OBJ_setAttr_T2cleartxt */
+0x67,0x2A,0x03,0x03,0x05,0x01, /* [4381] OBJ_setAttr_TokICCsig */
+0x67,0x2A,0x03,0x03,0x05,0x02, /* [4387] OBJ_setAttr_SecDevSig */
+0x67,0x2A,0x08,0x01, /* [4393] OBJ_set_brand_IATA_ATA */
+0x67,0x2A,0x08,0x1E, /* [4397] OBJ_set_brand_Diners */
+0x67,0x2A,0x08,0x22, /* [4401] OBJ_set_brand_AmericanExpress */
+0x67,0x2A,0x08,0x23, /* [4405] OBJ_set_brand_JCB */
+0x67,0x2A,0x08,0x04, /* [4409] OBJ_set_brand_Visa */
+0x67,0x2A,0x08,0x05, /* [4413] OBJ_set_brand_MasterCard */
+0x67,0x2A,0x08,0xAE,0x7B, /* [4417] OBJ_set_brand_Novus */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x03,0x0A, /* [4422] OBJ_des_cdmf */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x06,/* [4430] OBJ_rsaOAEPEncryptionSET */
+0x00, /* [4439] OBJ_itu_t */
+0x50, /* [4440] OBJ_joint_iso_itu_t */
+0x67, /* [4441] OBJ_international_organizations */
+0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x14,0x02,0x02,/* [4442] OBJ_ms_smartcard_login */
+0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x14,0x02,0x03,/* [4452] OBJ_ms_upn */
+0x55,0x04,0x09, /* [4462] OBJ_streetAddress */
+0x55,0x04,0x11, /* [4465] OBJ_postalCode */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x15, /* [4468] OBJ_id_ppl */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x0E, /* [4475] OBJ_proxyCertInfo */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x15,0x00, /* [4483] OBJ_id_ppl_anyLanguage */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x15,0x01, /* [4491] OBJ_id_ppl_inheritAll */
+0x55,0x1D,0x1E, /* [4499] OBJ_name_constraints */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x15,0x02, /* [4502] OBJ_Independent */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,/* [4510] OBJ_sha256WithRSAEncryption */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0C,/* [4519] OBJ_sha384WithRSAEncryption */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0D,/* [4528] OBJ_sha512WithRSAEncryption */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0E,/* [4537] OBJ_sha224WithRSAEncryption */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,/* [4546] OBJ_sha256 */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,/* [4555] OBJ_sha384 */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,/* [4564] OBJ_sha512 */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x04,/* [4573] OBJ_sha224 */
+0x2B, /* [4582] OBJ_identified_organization */
+0x2B,0x81,0x04, /* [4583] OBJ_certicom_arc */
+0x67,0x2B, /* [4586] OBJ_wap */
+0x67,0x2B,0x01, /* [4588] OBJ_wap_wsg */
+0x2A,0x86,0x48,0xCE,0x3D,0x01,0x02,0x03, /* [4591] OBJ_X9_62_id_characteristic_two_basis */
+0x2A,0x86,0x48,0xCE,0x3D,0x01,0x02,0x03,0x01,/* [4599] OBJ_X9_62_onBasis */
+0x2A,0x86,0x48,0xCE,0x3D,0x01,0x02,0x03,0x02,/* [4608] OBJ_X9_62_tpBasis */
+0x2A,0x86,0x48,0xCE,0x3D,0x01,0x02,0x03,0x03,/* [4617] OBJ_X9_62_ppBasis */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x01, /* [4626] OBJ_X9_62_c2pnb163v1 */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x02, /* [4634] OBJ_X9_62_c2pnb163v2 */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x03, /* [4642] OBJ_X9_62_c2pnb163v3 */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x04, /* [4650] OBJ_X9_62_c2pnb176v1 */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x05, /* [4658] OBJ_X9_62_c2tnb191v1 */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x06, /* [4666] OBJ_X9_62_c2tnb191v2 */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x07, /* [4674] OBJ_X9_62_c2tnb191v3 */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x08, /* [4682] OBJ_X9_62_c2onb191v4 */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x09, /* [4690] OBJ_X9_62_c2onb191v5 */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x0A, /* [4698] OBJ_X9_62_c2pnb208w1 */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x0B, /* [4706] OBJ_X9_62_c2tnb239v1 */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x0C, /* [4714] OBJ_X9_62_c2tnb239v2 */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x0D, /* [4722] OBJ_X9_62_c2tnb239v3 */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x0E, /* [4730] OBJ_X9_62_c2onb239v4 */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x0F, /* [4738] OBJ_X9_62_c2onb239v5 */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x10, /* [4746] OBJ_X9_62_c2pnb272w1 */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x11, /* [4754] OBJ_X9_62_c2pnb304w1 */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x12, /* [4762] OBJ_X9_62_c2tnb359v1 */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x13, /* [4770] OBJ_X9_62_c2pnb368w1 */
+0x2A,0x86,0x48,0xCE,0x3D,0x03,0x00,0x14, /* [4778] OBJ_X9_62_c2tnb431r1 */
+0x2B,0x81,0x04,0x00,0x06, /* [4786] OBJ_secp112r1 */
+0x2B,0x81,0x04,0x00,0x07, /* [4791] OBJ_secp112r2 */
+0x2B,0x81,0x04,0x00,0x1C, /* [4796] OBJ_secp128r1 */
+0x2B,0x81,0x04,0x00,0x1D, /* [4801] OBJ_secp128r2 */
+0x2B,0x81,0x04,0x00,0x09, /* [4806] OBJ_secp160k1 */
+0x2B,0x81,0x04,0x00,0x08, /* [4811] OBJ_secp160r1 */
+0x2B,0x81,0x04,0x00,0x1E, /* [4816] OBJ_secp160r2 */
+0x2B,0x81,0x04,0x00,0x1F, /* [4821] OBJ_secp192k1 */
+0x2B,0x81,0x04,0x00,0x20, /* [4826] OBJ_secp224k1 */
+0x2B,0x81,0x04,0x00,0x21, /* [4831] OBJ_secp224r1 */
+0x2B,0x81,0x04,0x00,0x0A, /* [4836] OBJ_secp256k1 */
+0x2B,0x81,0x04,0x00,0x22, /* [4841] OBJ_secp384r1 */
+0x2B,0x81,0x04,0x00,0x23, /* [4846] OBJ_secp521r1 */
+0x2B,0x81,0x04,0x00,0x04, /* [4851] OBJ_sect113r1 */
+0x2B,0x81,0x04,0x00,0x05, /* [4856] OBJ_sect113r2 */
+0x2B,0x81,0x04,0x00,0x16, /* [4861] OBJ_sect131r1 */
+0x2B,0x81,0x04,0x00,0x17, /* [4866] OBJ_sect131r2 */
+0x2B,0x81,0x04,0x00,0x01, /* [4871] OBJ_sect163k1 */
+0x2B,0x81,0x04,0x00,0x02, /* [4876] OBJ_sect163r1 */
+0x2B,0x81,0x04,0x00,0x0F, /* [4881] OBJ_sect163r2 */
+0x2B,0x81,0x04,0x00,0x18, /* [4886] OBJ_sect193r1 */
+0x2B,0x81,0x04,0x00,0x19, /* [4891] OBJ_sect193r2 */
+0x2B,0x81,0x04,0x00,0x1A, /* [4896] OBJ_sect233k1 */
+0x2B,0x81,0x04,0x00,0x1B, /* [4901] OBJ_sect233r1 */
+0x2B,0x81,0x04,0x00,0x03, /* [4906] OBJ_sect239k1 */
+0x2B,0x81,0x04,0x00,0x10, /* [4911] OBJ_sect283k1 */
+0x2B,0x81,0x04,0x00,0x11, /* [4916] OBJ_sect283r1 */
+0x2B,0x81,0x04,0x00,0x24, /* [4921] OBJ_sect409k1 */
+0x2B,0x81,0x04,0x00,0x25, /* [4926] OBJ_sect409r1 */
+0x2B,0x81,0x04,0x00,0x26, /* [4931] OBJ_sect571k1 */
+0x2B,0x81,0x04,0x00,0x27, /* [4936] OBJ_sect571r1 */
+0x67,0x2B,0x01,0x04,0x01, /* [4941] OBJ_wap_wsg_idm_ecid_wtls1 */
+0x67,0x2B,0x01,0x04,0x03, /* [4946] OBJ_wap_wsg_idm_ecid_wtls3 */
+0x67,0x2B,0x01,0x04,0x04, /* [4951] OBJ_wap_wsg_idm_ecid_wtls4 */
+0x67,0x2B,0x01,0x04,0x05, /* [4956] OBJ_wap_wsg_idm_ecid_wtls5 */
+0x67,0x2B,0x01,0x04,0x06, /* [4961] OBJ_wap_wsg_idm_ecid_wtls6 */
+0x67,0x2B,0x01,0x04,0x07, /* [4966] OBJ_wap_wsg_idm_ecid_wtls7 */
+0x67,0x2B,0x01,0x04,0x08, /* [4971] OBJ_wap_wsg_idm_ecid_wtls8 */
+0x67,0x2B,0x01,0x04,0x09, /* [4976] OBJ_wap_wsg_idm_ecid_wtls9 */
+0x67,0x2B,0x01,0x04,0x0A, /* [4981] OBJ_wap_wsg_idm_ecid_wtls10 */
+0x67,0x2B,0x01,0x04,0x0B, /* [4986] OBJ_wap_wsg_idm_ecid_wtls11 */
+0x67,0x2B,0x01,0x04,0x0C, /* [4991] OBJ_wap_wsg_idm_ecid_wtls12 */
+0x55,0x1D,0x20,0x00, /* [4996] OBJ_any_policy */
+0x55,0x1D,0x21, /* [5000] OBJ_policy_mappings */
+0x55,0x1D,0x36, /* [5003] OBJ_inhibit_any_policy */
+0x2A,0x83,0x08,0x8C,0x9A,0x4B,0x3D,0x01,0x01,0x01,0x02,/* [5006] OBJ_camellia_128_cbc */
+0x2A,0x83,0x08,0x8C,0x9A,0x4B,0x3D,0x01,0x01,0x01,0x03,/* [5017] OBJ_camellia_192_cbc */
+0x2A,0x83,0x08,0x8C,0x9A,0x4B,0x3D,0x01,0x01,0x01,0x04,/* [5028] OBJ_camellia_256_cbc */
+0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x01, /* [5039] OBJ_camellia_128_ecb */
+0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x15, /* [5047] OBJ_camellia_192_ecb */
+0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x29, /* [5055] OBJ_camellia_256_ecb */
+0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x04, /* [5063] OBJ_camellia_128_cfb128 */
+0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x18, /* [5071] OBJ_camellia_192_cfb128 */
+0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x2C, /* [5079] OBJ_camellia_256_cfb128 */
+0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x03, /* [5087] OBJ_camellia_128_ofb128 */
+0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x17, /* [5095] OBJ_camellia_192_ofb128 */
+0x03,0xA2,0x31,0x05,0x03,0x01,0x09,0x2B, /* [5103] OBJ_camellia_256_ofb128 */
+0x55,0x1D,0x09, /* [5111] OBJ_subject_directory_attributes */
+0x55,0x1D,0x1C, /* [5114] OBJ_issuing_distribution_point */
+0x55,0x1D,0x1D, /* [5117] OBJ_certificate_issuer */
+0x2A,0x83,0x1A,0x8C,0x9A,0x44, /* [5120] OBJ_kisa */
+0x2A,0x83,0x1A,0x8C,0x9A,0x44,0x01,0x03, /* [5126] OBJ_seed_ecb */
+0x2A,0x83,0x1A,0x8C,0x9A,0x44,0x01,0x04, /* [5134] OBJ_seed_cbc */
+0x2A,0x83,0x1A,0x8C,0x9A,0x44,0x01,0x06, /* [5142] OBJ_seed_ofb128 */
+0x2A,0x83,0x1A,0x8C,0x9A,0x44,0x01,0x05, /* [5150] OBJ_seed_cfb128 */
+0x2B,0x06,0x01,0x05,0x05,0x08,0x01,0x01, /* [5158] OBJ_hmac_md5 */
+0x2B,0x06,0x01,0x05,0x05,0x08,0x01,0x02, /* [5166] OBJ_hmac_sha1 */
+0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07,0x42,0x0D,/* [5174] OBJ_id_PasswordBasedMAC */
+0x2A,0x86,0x48,0x86,0xF6,0x7D,0x07,0x42,0x1E,/* [5183] OBJ_id_DHBasedMac */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x04,0x10, /* [5192] OBJ_id_it_suppLangTags */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x05, /* [5200] OBJ_caRepository */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x09,/* [5208] OBJ_id_smime_ct_compressedData */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x1B,/* [5219] OBJ_id_ct_asciiTextWithCRLF */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x05,/* [5230] OBJ_id_aes128_wrap */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x19,/* [5239] OBJ_id_aes192_wrap */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x2D,/* [5248] OBJ_id_aes256_wrap */
+0x2A,0x86,0x48,0xCE,0x3D,0x04,0x02, /* [5257] OBJ_ecdsa_with_Recommended */
+0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03, /* [5264] OBJ_ecdsa_with_Specified */
+0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x01, /* [5271] OBJ_ecdsa_with_SHA224 */
+0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x02, /* [5279] OBJ_ecdsa_with_SHA256 */
+0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03, /* [5287] OBJ_ecdsa_with_SHA384 */
+0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x04, /* [5295] OBJ_ecdsa_with_SHA512 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x06, /* [5303] OBJ_hmacWithMD5 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x08, /* [5311] OBJ_hmacWithSHA224 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x09, /* [5319] OBJ_hmacWithSHA256 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x0A, /* [5327] OBJ_hmacWithSHA384 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x0B, /* [5335] OBJ_hmacWithSHA512 */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x01,/* [5343] OBJ_dsa_with_SHA224 */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x03,0x02,/* [5352] OBJ_dsa_with_SHA256 */
+0x28,0xCF,0x06,0x03,0x00,0x37, /* [5361] OBJ_whirlpool */
+0x2A,0x85,0x03,0x02,0x02, /* [5367] OBJ_cryptopro */
+0x2A,0x85,0x03,0x02,0x09, /* [5372] OBJ_cryptocom */
+0x2A,0x85,0x03,0x02,0x02,0x03, /* [5377] OBJ_id_GostR3411_94_with_GostR3410_2001 */
+0x2A,0x85,0x03,0x02,0x02,0x04, /* [5383] OBJ_id_GostR3411_94_with_GostR3410_94 */
+0x2A,0x85,0x03,0x02,0x02,0x09, /* [5389] OBJ_id_GostR3411_94 */
+0x2A,0x85,0x03,0x02,0x02,0x0A, /* [5395] OBJ_id_HMACGostR3411_94 */
+0x2A,0x85,0x03,0x02,0x02,0x13, /* [5401] OBJ_id_GostR3410_2001 */
+0x2A,0x85,0x03,0x02,0x02,0x14, /* [5407] OBJ_id_GostR3410_94 */
+0x2A,0x85,0x03,0x02,0x02,0x15, /* [5413] OBJ_id_Gost28147_89 */
+0x2A,0x85,0x03,0x02,0x02,0x16, /* [5419] OBJ_id_Gost28147_89_MAC */
+0x2A,0x85,0x03,0x02,0x02,0x17, /* [5425] OBJ_id_GostR3411_94_prf */
+0x2A,0x85,0x03,0x02,0x02,0x62, /* [5431] OBJ_id_GostR3410_2001DH */
+0x2A,0x85,0x03,0x02,0x02,0x63, /* [5437] OBJ_id_GostR3410_94DH */
+0x2A,0x85,0x03,0x02,0x02,0x0E,0x01, /* [5443] OBJ_id_Gost28147_89_CryptoPro_KeyMeshing */
+0x2A,0x85,0x03,0x02,0x02,0x0E,0x00, /* [5450] OBJ_id_Gost28147_89_None_KeyMeshing */
+0x2A,0x85,0x03,0x02,0x02,0x1E,0x00, /* [5457] OBJ_id_GostR3411_94_TestParamSet */
+0x2A,0x85,0x03,0x02,0x02,0x1E,0x01, /* [5464] OBJ_id_GostR3411_94_CryptoProParamSet */
+0x2A,0x85,0x03,0x02,0x02,0x1F,0x00, /* [5471] OBJ_id_Gost28147_89_TestParamSet */
+0x2A,0x85,0x03,0x02,0x02,0x1F,0x01, /* [5478] OBJ_id_Gost28147_89_CryptoPro_A_ParamSet */
+0x2A,0x85,0x03,0x02,0x02,0x1F,0x02, /* [5485] OBJ_id_Gost28147_89_CryptoPro_B_ParamSet */
+0x2A,0x85,0x03,0x02,0x02,0x1F,0x03, /* [5492] OBJ_id_Gost28147_89_CryptoPro_C_ParamSet */
+0x2A,0x85,0x03,0x02,0x02,0x1F,0x04, /* [5499] OBJ_id_Gost28147_89_CryptoPro_D_ParamSet */
+0x2A,0x85,0x03,0x02,0x02,0x1F,0x05, /* [5506] OBJ_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet */
+0x2A,0x85,0x03,0x02,0x02,0x1F,0x06, /* [5513] OBJ_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet */
+0x2A,0x85,0x03,0x02,0x02,0x1F,0x07, /* [5520] OBJ_id_Gost28147_89_CryptoPro_RIC_1_ParamSet */
+0x2A,0x85,0x03,0x02,0x02,0x20,0x00, /* [5527] OBJ_id_GostR3410_94_TestParamSet */
+0x2A,0x85,0x03,0x02,0x02,0x20,0x02, /* [5534] OBJ_id_GostR3410_94_CryptoPro_A_ParamSet */
+0x2A,0x85,0x03,0x02,0x02,0x20,0x03, /* [5541] OBJ_id_GostR3410_94_CryptoPro_B_ParamSet */
+0x2A,0x85,0x03,0x02,0x02,0x20,0x04, /* [5548] OBJ_id_GostR3410_94_CryptoPro_C_ParamSet */
+0x2A,0x85,0x03,0x02,0x02,0x20,0x05, /* [5555] OBJ_id_GostR3410_94_CryptoPro_D_ParamSet */
+0x2A,0x85,0x03,0x02,0x02,0x21,0x01, /* [5562] OBJ_id_GostR3410_94_CryptoPro_XchA_ParamSet */
+0x2A,0x85,0x03,0x02,0x02,0x21,0x02, /* [5569] OBJ_id_GostR3410_94_CryptoPro_XchB_ParamSet */
+0x2A,0x85,0x03,0x02,0x02,0x21,0x03, /* [5576] OBJ_id_GostR3410_94_CryptoPro_XchC_ParamSet */
+0x2A,0x85,0x03,0x02,0x02,0x23,0x00, /* [5583] OBJ_id_GostR3410_2001_TestParamSet */
+0x2A,0x85,0x03,0x02,0x02,0x23,0x01, /* [5590] OBJ_id_GostR3410_2001_CryptoPro_A_ParamSet */
+0x2A,0x85,0x03,0x02,0x02,0x23,0x02, /* [5597] OBJ_id_GostR3410_2001_CryptoPro_B_ParamSet */
+0x2A,0x85,0x03,0x02,0x02,0x23,0x03, /* [5604] OBJ_id_GostR3410_2001_CryptoPro_C_ParamSet */
+0x2A,0x85,0x03,0x02,0x02,0x24,0x00, /* [5611] OBJ_id_GostR3410_2001_CryptoPro_XchA_ParamSet */
+0x2A,0x85,0x03,0x02,0x02,0x24,0x01, /* [5618] OBJ_id_GostR3410_2001_CryptoPro_XchB_ParamSet */
+0x2A,0x85,0x03,0x02,0x02,0x14,0x01, /* [5625] OBJ_id_GostR3410_94_a */
+0x2A,0x85,0x03,0x02,0x02,0x14,0x02, /* [5632] OBJ_id_GostR3410_94_aBis */
+0x2A,0x85,0x03,0x02,0x02,0x14,0x03, /* [5639] OBJ_id_GostR3410_94_b */
+0x2A,0x85,0x03,0x02,0x02,0x14,0x04, /* [5646] OBJ_id_GostR3410_94_bBis */
+0x2A,0x85,0x03,0x02,0x09,0x01,0x06,0x01, /* [5653] OBJ_id_Gost28147_89_cc */
+0x2A,0x85,0x03,0x02,0x09,0x01,0x05,0x03, /* [5661] OBJ_id_GostR3410_94_cc */
+0x2A,0x85,0x03,0x02,0x09,0x01,0x05,0x04, /* [5669] OBJ_id_GostR3410_2001_cc */
+0x2A,0x85,0x03,0x02,0x09,0x01,0x03,0x03, /* [5677] OBJ_id_GostR3411_94_with_GostR3410_94_cc */
+0x2A,0x85,0x03,0x02,0x09,0x01,0x03,0x04, /* [5685] OBJ_id_GostR3411_94_with_GostR3410_2001_cc */
+0x2A,0x85,0x03,0x02,0x09,0x01,0x08,0x01, /* [5693] OBJ_id_GostR3410_2001_ParamSet_cc */
+0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x11,0x02,/* [5701] OBJ_LocalKeySet */
+0x55,0x1D,0x2E, /* [5710] OBJ_freshest_crl */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x08,0x03, /* [5713] OBJ_id_on_permanentIdentifier */
+0x55,0x04,0x0E, /* [5721] OBJ_searchGuide */
+0x55,0x04,0x0F, /* [5724] OBJ_businessCategory */
+0x55,0x04,0x10, /* [5727] OBJ_postalAddress */
+0x55,0x04,0x12, /* [5730] OBJ_postOfficeBox */
+0x55,0x04,0x13, /* [5733] OBJ_physicalDeliveryOfficeName */
+0x55,0x04,0x14, /* [5736] OBJ_telephoneNumber */
+0x55,0x04,0x15, /* [5739] OBJ_telexNumber */
+0x55,0x04,0x16, /* [5742] OBJ_teletexTerminalIdentifier */
+0x55,0x04,0x17, /* [5745] OBJ_facsimileTelephoneNumber */
+0x55,0x04,0x18, /* [5748] OBJ_x121Address */
+0x55,0x04,0x19, /* [5751] OBJ_internationaliSDNNumber */
+0x55,0x04,0x1A, /* [5754] OBJ_registeredAddress */
+0x55,0x04,0x1B, /* [5757] OBJ_destinationIndicator */
+0x55,0x04,0x1C, /* [5760] OBJ_preferredDeliveryMethod */
+0x55,0x04,0x1D, /* [5763] OBJ_presentationAddress */
+0x55,0x04,0x1E, /* [5766] OBJ_supportedApplicationContext */
+0x55,0x04,0x1F, /* [5769] OBJ_member */
+0x55,0x04,0x20, /* [5772] OBJ_owner */
+0x55,0x04,0x21, /* [5775] OBJ_roleOccupant */
+0x55,0x04,0x22, /* [5778] OBJ_seeAlso */
+0x55,0x04,0x23, /* [5781] OBJ_userPassword */
+0x55,0x04,0x24, /* [5784] OBJ_userCertificate */
+0x55,0x04,0x25, /* [5787] OBJ_cACertificate */
+0x55,0x04,0x26, /* [5790] OBJ_authorityRevocationList */
+0x55,0x04,0x27, /* [5793] OBJ_certificateRevocationList */
+0x55,0x04,0x28, /* [5796] OBJ_crossCertificatePair */
+0x55,0x04,0x2F, /* [5799] OBJ_enhancedSearchGuide */
+0x55,0x04,0x30, /* [5802] OBJ_protocolInformation */
+0x55,0x04,0x31, /* [5805] OBJ_distinguishedName */
+0x55,0x04,0x32, /* [5808] OBJ_uniqueMember */
+0x55,0x04,0x33, /* [5811] OBJ_houseIdentifier */
+0x55,0x04,0x34, /* [5814] OBJ_supportedAlgorithms */
+0x55,0x04,0x35, /* [5817] OBJ_deltaRevocationList */
+0x55,0x04,0x36, /* [5820] OBJ_dmdName */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x09,/* [5823] OBJ_id_alg_PWRI_KEK */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x06,/* [5834] OBJ_aes_128_gcm */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x07,/* [5843] OBJ_aes_128_ccm */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x08,/* [5852] OBJ_id_aes128_wrap_pad */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x1A,/* [5861] OBJ_aes_192_gcm */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x1B,/* [5870] OBJ_aes_192_ccm */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x1C,/* [5879] OBJ_id_aes192_wrap_pad */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x2E,/* [5888] OBJ_aes_256_gcm */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x2F,/* [5897] OBJ_aes_256_ccm */
+0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x01,0x30,/* [5906] OBJ_id_aes256_wrap_pad */
+0x2A,0x83,0x08,0x8C,0x9A,0x4B,0x3D,0x01,0x01,0x03,0x02,/* [5915] OBJ_id_camellia128_wrap */
+0x2A,0x83,0x08,0x8C,0x9A,0x4B,0x3D,0x01,0x01,0x03,0x03,/* [5926] OBJ_id_camellia192_wrap */
+0x2A,0x83,0x08,0x8C,0x9A,0x4B,0x3D,0x01,0x01,0x03,0x04,/* [5937] OBJ_id_camellia256_wrap */
+0x55,0x1D,0x25,0x00, /* [5948] OBJ_anyExtendedKeyUsage */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x08,/* [5952] OBJ_mgf1 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0A,/* [5961] OBJ_rsassaPss */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x07,/* [5970] OBJ_rsaesOaep */
+0x2A,0x86,0x48,0xCE,0x3E,0x02,0x01, /* [5979] OBJ_dhpublicnumber */
+0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x01,/* [5986] OBJ_brainpoolP160r1 */
+0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x02,/* [5995] OBJ_brainpoolP160t1 */
+0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x03,/* [6004] OBJ_brainpoolP192r1 */
+0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x04,/* [6013] OBJ_brainpoolP192t1 */
+0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x05,/* [6022] OBJ_brainpoolP224r1 */
+0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x06,/* [6031] OBJ_brainpoolP224t1 */
+0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x07,/* [6040] OBJ_brainpoolP256r1 */
+0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x08,/* [6049] OBJ_brainpoolP256t1 */
+0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x09,/* [6058] OBJ_brainpoolP320r1 */
+0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x0A,/* [6067] OBJ_brainpoolP320t1 */
+0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x0B,/* [6076] OBJ_brainpoolP384r1 */
+0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x0C,/* [6085] OBJ_brainpoolP384t1 */
+0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x0D,/* [6094] OBJ_brainpoolP512r1 */
+0x2B,0x24,0x03,0x03,0x02,0x08,0x01,0x01,0x0E,/* [6103] OBJ_brainpoolP512t1 */
+0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x09,/* [6112] OBJ_pSpecified */
+0x2B,0x81,0x05,0x10,0x86,0x48,0x3F,0x00,0x02,/* [6121] OBJ_dhSinglePass_stdDH_sha1kdf_scheme */
+0x2B,0x81,0x04,0x01,0x0B,0x00, /* [6130] OBJ_dhSinglePass_stdDH_sha224kdf_scheme */
+0x2B,0x81,0x04,0x01,0x0B,0x01, /* [6136] OBJ_dhSinglePass_stdDH_sha256kdf_scheme */
+0x2B,0x81,0x04,0x01,0x0B,0x02, /* [6142] OBJ_dhSinglePass_stdDH_sha384kdf_scheme */
+0x2B,0x81,0x04,0x01,0x0B,0x03, /* [6148] OBJ_dhSinglePass_stdDH_sha512kdf_scheme */
+0x2B,0x81,0x05,0x10,0x86,0x48,0x3F,0x00,0x03,/* [6154] OBJ_dhSinglePass_cofactorDH_sha1kdf_scheme */
+0x2B,0x81,0x04,0x01,0x0E,0x00, /* [6163] OBJ_dhSinglePass_cofactorDH_sha224kdf_scheme */
+0x2B,0x81,0x04,0x01,0x0E,0x01, /* [6169] OBJ_dhSinglePass_cofactorDH_sha256kdf_scheme */
+0x2B,0x81,0x04,0x01,0x0E,0x02, /* [6175] OBJ_dhSinglePass_cofactorDH_sha384kdf_scheme */
+0x2B,0x81,0x04,0x01,0x0E,0x03, /* [6181] OBJ_dhSinglePass_cofactorDH_sha512kdf_scheme */
+};
+
+static const ASN1_OBJECT kObjects[NUM_NID]={
+{"UNDEF","undefined",NID_undef,1,&(lvalues[0]),0},
+{"rsadsi","RSA Data Security, Inc.",NID_rsadsi,6,&(lvalues[1]),0},
+{"pkcs","RSA Data Security, Inc. PKCS",NID_pkcs,7,&(lvalues[7]),0},
+{"MD2","md2",NID_md2,8,&(lvalues[14]),0},
+{"MD5","md5",NID_md5,8,&(lvalues[22]),0},
+{"RC4","rc4",NID_rc4,8,&(lvalues[30]),0},
+{"rsaEncryption","rsaEncryption",NID_rsaEncryption,9,&(lvalues[38]),0},
+{"RSA-MD2","md2WithRSAEncryption",NID_md2WithRSAEncryption,9,
+ &(lvalues[47]),0},
+{"RSA-MD5","md5WithRSAEncryption",NID_md5WithRSAEncryption,9,
+ &(lvalues[56]),0},
+{"PBE-MD2-DES","pbeWithMD2AndDES-CBC",NID_pbeWithMD2AndDES_CBC,9,
+ &(lvalues[65]),0},
+{"PBE-MD5-DES","pbeWithMD5AndDES-CBC",NID_pbeWithMD5AndDES_CBC,9,
+ &(lvalues[74]),0},
+{"X500","directory services (X.500)",NID_X500,1,&(lvalues[83]),0},
+{"X509","X509",NID_X509,2,&(lvalues[84]),0},
+{"CN","commonName",NID_commonName,3,&(lvalues[86]),0},
+{"C","countryName",NID_countryName,3,&(lvalues[89]),0},
+{"L","localityName",NID_localityName,3,&(lvalues[92]),0},
+{"ST","stateOrProvinceName",NID_stateOrProvinceName,3,&(lvalues[95]),0},
+{"O","organizationName",NID_organizationName,3,&(lvalues[98]),0},
+{"OU","organizationalUnitName",NID_organizationalUnitName,3,
+ &(lvalues[101]),0},
+{"RSA","rsa",NID_rsa,4,&(lvalues[104]),0},
+{"pkcs7","pkcs7",NID_pkcs7,8,&(lvalues[108]),0},
+{"pkcs7-data","pkcs7-data",NID_pkcs7_data,9,&(lvalues[116]),0},
+{"pkcs7-signedData","pkcs7-signedData",NID_pkcs7_signed,9,
+ &(lvalues[125]),0},
+{"pkcs7-envelopedData","pkcs7-envelopedData",NID_pkcs7_enveloped,9,
+ &(lvalues[134]),0},
+{"pkcs7-signedAndEnvelopedData","pkcs7-signedAndEnvelopedData",
+ NID_pkcs7_signedAndEnveloped,9,&(lvalues[143]),0},
+{"pkcs7-digestData","pkcs7-digestData",NID_pkcs7_digest,9,
+ &(lvalues[152]),0},
+{"pkcs7-encryptedData","pkcs7-encryptedData",NID_pkcs7_encrypted,9,
+ &(lvalues[161]),0},
+{"pkcs3","pkcs3",NID_pkcs3,8,&(lvalues[170]),0},
+{"dhKeyAgreement","dhKeyAgreement",NID_dhKeyAgreement,9,
+ &(lvalues[178]),0},
+{"DES-ECB","des-ecb",NID_des_ecb,5,&(lvalues[187]),0},
+{"DES-CFB","des-cfb",NID_des_cfb64,5,&(lvalues[192]),0},
+{"DES-CBC","des-cbc",NID_des_cbc,5,&(lvalues[197]),0},
+{"DES-EDE","des-ede",NID_des_ede_ecb,5,&(lvalues[202]),0},
+{"DES-EDE3","des-ede3",NID_des_ede3_ecb,0,NULL,0},
+{"IDEA-CBC","idea-cbc",NID_idea_cbc,11,&(lvalues[207]),0},
+{"IDEA-CFB","idea-cfb",NID_idea_cfb64,0,NULL,0},
+{"IDEA-ECB","idea-ecb",NID_idea_ecb,0,NULL,0},
+{"RC2-CBC","rc2-cbc",NID_rc2_cbc,8,&(lvalues[218]),0},
+{"RC2-ECB","rc2-ecb",NID_rc2_ecb,0,NULL,0},
+{"RC2-CFB","rc2-cfb",NID_rc2_cfb64,0,NULL,0},
+{"RC2-OFB","rc2-ofb",NID_rc2_ofb64,0,NULL,0},
+{"SHA","sha",NID_sha,5,&(lvalues[226]),0},
+{"RSA-SHA","shaWithRSAEncryption",NID_shaWithRSAEncryption,5,
+ &(lvalues[231]),0},
+{"DES-EDE-CBC","des-ede-cbc",NID_des_ede_cbc,0,NULL,0},
+{"DES-EDE3-CBC","des-ede3-cbc",NID_des_ede3_cbc,8,&(lvalues[236]),0},
+{"DES-OFB","des-ofb",NID_des_ofb64,5,&(lvalues[244]),0},
+{"IDEA-OFB","idea-ofb",NID_idea_ofb64,0,NULL,0},
+{"pkcs9","pkcs9",NID_pkcs9,8,&(lvalues[249]),0},
+{"emailAddress","emailAddress",NID_pkcs9_emailAddress,9,
+ &(lvalues[257]),0},
+{"unstructuredName","unstructuredName",NID_pkcs9_unstructuredName,9,
+ &(lvalues[266]),0},
+{"contentType","contentType",NID_pkcs9_contentType,9,&(lvalues[275]),0},
+{"messageDigest","messageDigest",NID_pkcs9_messageDigest,9,
+ &(lvalues[284]),0},
+{"signingTime","signingTime",NID_pkcs9_signingTime,9,&(lvalues[293]),0},
+{"countersignature","countersignature",NID_pkcs9_countersignature,9,
+ &(lvalues[302]),0},
+{"challengePassword","challengePassword",NID_pkcs9_challengePassword,
+ 9,&(lvalues[311]),0},
+{"unstructuredAddress","unstructuredAddress",
+ NID_pkcs9_unstructuredAddress,9,&(lvalues[320]),0},
+{"extendedCertificateAttributes","extendedCertificateAttributes",
+ NID_pkcs9_extCertAttributes,9,&(lvalues[329]),0},
+{"Netscape","Netscape Communications Corp.",NID_netscape,7,
+ &(lvalues[338]),0},
+{"nsCertExt","Netscape Certificate Extension",
+ NID_netscape_cert_extension,8,&(lvalues[345]),0},
+{"nsDataType","Netscape Data Type",NID_netscape_data_type,8,
+ &(lvalues[353]),0},
+{"DES-EDE-CFB","des-ede-cfb",NID_des_ede_cfb64,0,NULL,0},
+{"DES-EDE3-CFB","des-ede3-cfb",NID_des_ede3_cfb64,0,NULL,0},
+{"DES-EDE-OFB","des-ede-ofb",NID_des_ede_ofb64,0,NULL,0},
+{"DES-EDE3-OFB","des-ede3-ofb",NID_des_ede3_ofb64,0,NULL,0},
+{"SHA1","sha1",NID_sha1,5,&(lvalues[361]),0},
+{"RSA-SHA1","sha1WithRSAEncryption",NID_sha1WithRSAEncryption,9,
+ &(lvalues[366]),0},
+{"DSA-SHA","dsaWithSHA",NID_dsaWithSHA,5,&(lvalues[375]),0},
+{"DSA-old","dsaEncryption-old",NID_dsa_2,5,&(lvalues[380]),0},
+{"PBE-SHA1-RC2-64","pbeWithSHA1AndRC2-CBC",NID_pbeWithSHA1AndRC2_CBC,
+ 9,&(lvalues[385]),0},
+{"PBKDF2","PBKDF2",NID_id_pbkdf2,9,&(lvalues[394]),0},
+{"DSA-SHA1-old","dsaWithSHA1-old",NID_dsaWithSHA1_2,5,&(lvalues[403]),0},
+{"nsCertType","Netscape Cert Type",NID_netscape_cert_type,9,
+ &(lvalues[408]),0},
+{"nsBaseUrl","Netscape Base Url",NID_netscape_base_url,9,
+ &(lvalues[417]),0},
+{"nsRevocationUrl","Netscape Revocation Url",
+ NID_netscape_revocation_url,9,&(lvalues[426]),0},
+{"nsCaRevocationUrl","Netscape CA Revocation Url",
+ NID_netscape_ca_revocation_url,9,&(lvalues[435]),0},
+{"nsRenewalUrl","Netscape Renewal Url",NID_netscape_renewal_url,9,
+ &(lvalues[444]),0},
+{"nsCaPolicyUrl","Netscape CA Policy Url",NID_netscape_ca_policy_url,
+ 9,&(lvalues[453]),0},
+{"nsSslServerName","Netscape SSL Server Name",
+ NID_netscape_ssl_server_name,9,&(lvalues[462]),0},
+{"nsComment","Netscape Comment",NID_netscape_comment,9,&(lvalues[471]),0},
+{"nsCertSequence","Netscape Certificate Sequence",
+ NID_netscape_cert_sequence,9,&(lvalues[480]),0},
+{"DESX-CBC","desx-cbc",NID_desx_cbc,0,NULL,0},
+{"id-ce","id-ce",NID_id_ce,2,&(lvalues[489]),0},
+{"subjectKeyIdentifier","X509v3 Subject Key Identifier",
+ NID_subject_key_identifier,3,&(lvalues[491]),0},
+{"keyUsage","X509v3 Key Usage",NID_key_usage,3,&(lvalues[494]),0},
+{"privateKeyUsagePeriod","X509v3 Private Key Usage Period",
+ NID_private_key_usage_period,3,&(lvalues[497]),0},
+{"subjectAltName","X509v3 Subject Alternative Name",
+ NID_subject_alt_name,3,&(lvalues[500]),0},
+{"issuerAltName","X509v3 Issuer Alternative Name",NID_issuer_alt_name,
+ 3,&(lvalues[503]),0},
+{"basicConstraints","X509v3 Basic Constraints",NID_basic_constraints,
+ 3,&(lvalues[506]),0},
+{"crlNumber","X509v3 CRL Number",NID_crl_number,3,&(lvalues[509]),0},
+{"certificatePolicies","X509v3 Certificate Policies",
+ NID_certificate_policies,3,&(lvalues[512]),0},
+{"authorityKeyIdentifier","X509v3 Authority Key Identifier",
+ NID_authority_key_identifier,3,&(lvalues[515]),0},
+{"BF-CBC","bf-cbc",NID_bf_cbc,9,&(lvalues[518]),0},
+{"BF-ECB","bf-ecb",NID_bf_ecb,0,NULL,0},
+{"BF-CFB","bf-cfb",NID_bf_cfb64,0,NULL,0},
+{"BF-OFB","bf-ofb",NID_bf_ofb64,0,NULL,0},
+{"MDC2","mdc2",NID_mdc2,4,&(lvalues[527]),0},
+{"RSA-MDC2","mdc2WithRSA",NID_mdc2WithRSA,4,&(lvalues[531]),0},
+{"RC4-40","rc4-40",NID_rc4_40,0,NULL,0},
+{"RC2-40-CBC","rc2-40-cbc",NID_rc2_40_cbc,0,NULL,0},
+{"GN","givenName",NID_givenName,3,&(lvalues[535]),0},
+{"SN","surname",NID_surname,3,&(lvalues[538]),0},
+{"initials","initials",NID_initials,3,&(lvalues[541]),0},
+{NULL,NULL,NID_undef,0,NULL,0},
+{"crlDistributionPoints","X509v3 CRL Distribution Points",
+ NID_crl_distribution_points,3,&(lvalues[544]),0},
+{"RSA-NP-MD5","md5WithRSA",NID_md5WithRSA,5,&(lvalues[547]),0},
+{"serialNumber","serialNumber",NID_serialNumber,3,&(lvalues[552]),0},
+{"title","title",NID_title,3,&(lvalues[555]),0},
+{"description","description",NID_description,3,&(lvalues[558]),0},
+{"CAST5-CBC","cast5-cbc",NID_cast5_cbc,9,&(lvalues[561]),0},
+{"CAST5-ECB","cast5-ecb",NID_cast5_ecb,0,NULL,0},
+{"CAST5-CFB","cast5-cfb",NID_cast5_cfb64,0,NULL,0},
+{"CAST5-OFB","cast5-ofb",NID_cast5_ofb64,0,NULL,0},
+{"pbeWithMD5AndCast5CBC","pbeWithMD5AndCast5CBC",
+ NID_pbeWithMD5AndCast5_CBC,9,&(lvalues[570]),0},
+{"DSA-SHA1","dsaWithSHA1",NID_dsaWithSHA1,7,&(lvalues[579]),0},
+{"MD5-SHA1","md5-sha1",NID_md5_sha1,0,NULL,0},
+{"RSA-SHA1-2","sha1WithRSA",NID_sha1WithRSA,5,&(lvalues[586]),0},
+{"DSA","dsaEncryption",NID_dsa,7,&(lvalues[591]),0},
+{"RIPEMD160","ripemd160",NID_ripemd160,5,&(lvalues[598]),0},
+{NULL,NULL,NID_undef,0,NULL,0},
+{"RSA-RIPEMD160","ripemd160WithRSA",NID_ripemd160WithRSA,6,
+ &(lvalues[603]),0},
+{"RC5-CBC","rc5-cbc",NID_rc5_cbc,8,&(lvalues[609]),0},
+{"RC5-ECB","rc5-ecb",NID_rc5_ecb,0,NULL,0},
+{"RC5-CFB","rc5-cfb",NID_rc5_cfb64,0,NULL,0},
+{"RC5-OFB","rc5-ofb",NID_rc5_ofb64,0,NULL,0},
+{"RLE","run length compression",NID_rle_compression,6,&(lvalues[617]),0},
+{"ZLIB","zlib compression",NID_zlib_compression,11,&(lvalues[623]),0},
+{"extendedKeyUsage","X509v3 Extended Key Usage",NID_ext_key_usage,3,
+ &(lvalues[634]),0},
+{"PKIX","PKIX",NID_id_pkix,6,&(lvalues[637]),0},
+{"id-kp","id-kp",NID_id_kp,7,&(lvalues[643]),0},
+{"serverAuth","TLS Web Server Authentication",NID_server_auth,8,
+ &(lvalues[650]),0},
+{"clientAuth","TLS Web Client Authentication",NID_client_auth,8,
+ &(lvalues[658]),0},
+{"codeSigning","Code Signing",NID_code_sign,8,&(lvalues[666]),0},
+{"emailProtection","E-mail Protection",NID_email_protect,8,
+ &(lvalues[674]),0},
+{"timeStamping","Time Stamping",NID_time_stamp,8,&(lvalues[682]),0},
+{"msCodeInd","Microsoft Individual Code Signing",NID_ms_code_ind,10,
+ &(lvalues[690]),0},
+{"msCodeCom","Microsoft Commercial Code Signing",NID_ms_code_com,10,
+ &(lvalues[700]),0},
+{"msCTLSign","Microsoft Trust List Signing",NID_ms_ctl_sign,10,
+ &(lvalues[710]),0},
+{"msSGC","Microsoft Server Gated Crypto",NID_ms_sgc,10,&(lvalues[720]),0},
+{"msEFS","Microsoft Encrypted File System",NID_ms_efs,10,
+ &(lvalues[730]),0},
+{"nsSGC","Netscape Server Gated Crypto",NID_ns_sgc,9,&(lvalues[740]),0},
+{"deltaCRL","X509v3 Delta CRL Indicator",NID_delta_crl,3,
+ &(lvalues[749]),0},
+{"CRLReason","X509v3 CRL Reason Code",NID_crl_reason,3,&(lvalues[752]),0},
+{"invalidityDate","Invalidity Date",NID_invalidity_date,3,
+ &(lvalues[755]),0},
+{"SXNetID","Strong Extranet ID",NID_sxnet,5,&(lvalues[758]),0},
+{"PBE-SHA1-RC4-128","pbeWithSHA1And128BitRC4",
+ NID_pbe_WithSHA1And128BitRC4,10,&(lvalues[763]),0},
+{"PBE-SHA1-RC4-40","pbeWithSHA1And40BitRC4",
+ NID_pbe_WithSHA1And40BitRC4,10,&(lvalues[773]),0},
+{"PBE-SHA1-3DES","pbeWithSHA1And3-KeyTripleDES-CBC",
+ NID_pbe_WithSHA1And3_Key_TripleDES_CBC,10,&(lvalues[783]),0},
+{"PBE-SHA1-2DES","pbeWithSHA1And2-KeyTripleDES-CBC",
+ NID_pbe_WithSHA1And2_Key_TripleDES_CBC,10,&(lvalues[793]),0},
+{"PBE-SHA1-RC2-128","pbeWithSHA1And128BitRC2-CBC",
+ NID_pbe_WithSHA1And128BitRC2_CBC,10,&(lvalues[803]),0},
+{"PBE-SHA1-RC2-40","pbeWithSHA1And40BitRC2-CBC",
+ NID_pbe_WithSHA1And40BitRC2_CBC,10,&(lvalues[813]),0},
+{"keyBag","keyBag",NID_keyBag,11,&(lvalues[823]),0},
+{"pkcs8ShroudedKeyBag","pkcs8ShroudedKeyBag",NID_pkcs8ShroudedKeyBag,
+ 11,&(lvalues[834]),0},
+{"certBag","certBag",NID_certBag,11,&(lvalues[845]),0},
+{"crlBag","crlBag",NID_crlBag,11,&(lvalues[856]),0},
+{"secretBag","secretBag",NID_secretBag,11,&(lvalues[867]),0},
+{"safeContentsBag","safeContentsBag",NID_safeContentsBag,11,
+ &(lvalues[878]),0},
+{"friendlyName","friendlyName",NID_friendlyName,9,&(lvalues[889]),0},
+{"localKeyID","localKeyID",NID_localKeyID,9,&(lvalues[898]),0},
+{"x509Certificate","x509Certificate",NID_x509Certificate,10,
+ &(lvalues[907]),0},
+{"sdsiCertificate","sdsiCertificate",NID_sdsiCertificate,10,
+ &(lvalues[917]),0},
+{"x509Crl","x509Crl",NID_x509Crl,10,&(lvalues[927]),0},
+{"PBES2","PBES2",NID_pbes2,9,&(lvalues[937]),0},
+{"PBMAC1","PBMAC1",NID_pbmac1,9,&(lvalues[946]),0},
+{"hmacWithSHA1","hmacWithSHA1",NID_hmacWithSHA1,8,&(lvalues[955]),0},
+{"id-qt-cps","Policy Qualifier CPS",NID_id_qt_cps,8,&(lvalues[963]),0},
+{"id-qt-unotice","Policy Qualifier User Notice",NID_id_qt_unotice,8,
+ &(lvalues[971]),0},
+{"RC2-64-CBC","rc2-64-cbc",NID_rc2_64_cbc,0,NULL,0},
+{"SMIME-CAPS","S/MIME Capabilities",NID_SMIMECapabilities,9,
+ &(lvalues[979]),0},
+{"PBE-MD2-RC2-64","pbeWithMD2AndRC2-CBC",NID_pbeWithMD2AndRC2_CBC,9,
+ &(lvalues[988]),0},
+{"PBE-MD5-RC2-64","pbeWithMD5AndRC2-CBC",NID_pbeWithMD5AndRC2_CBC,9,
+ &(lvalues[997]),0},
+{"PBE-SHA1-DES","pbeWithSHA1AndDES-CBC",NID_pbeWithSHA1AndDES_CBC,9,
+ &(lvalues[1006]),0},
+{"msExtReq","Microsoft Extension Request",NID_ms_ext_req,10,
+ &(lvalues[1015]),0},
+{"extReq","Extension Request",NID_ext_req,9,&(lvalues[1025]),0},
+{"name","name",NID_name,3,&(lvalues[1034]),0},
+{"dnQualifier","dnQualifier",NID_dnQualifier,3,&(lvalues[1037]),0},
+{"id-pe","id-pe",NID_id_pe,7,&(lvalues[1040]),0},
+{"id-ad","id-ad",NID_id_ad,7,&(lvalues[1047]),0},
+{"authorityInfoAccess","Authority Information Access",NID_info_access,
+ 8,&(lvalues[1054]),0},
+{"OCSP","OCSP",NID_ad_OCSP,8,&(lvalues[1062]),0},
+{"caIssuers","CA Issuers",NID_ad_ca_issuers,8,&(lvalues[1070]),0},
+{"OCSPSigning","OCSP Signing",NID_OCSP_sign,8,&(lvalues[1078]),0},
+{"ISO","iso",NID_iso,1,&(lvalues[1086]),0},
+{"member-body","ISO Member Body",NID_member_body,1,&(lvalues[1087]),0},
+{"ISO-US","ISO US Member Body",NID_ISO_US,3,&(lvalues[1088]),0},
+{"X9-57","X9.57",NID_X9_57,5,&(lvalues[1091]),0},
+{"X9cm","X9.57 CM ?",NID_X9cm,6,&(lvalues[1096]),0},
+{"pkcs1","pkcs1",NID_pkcs1,8,&(lvalues[1102]),0},
+{"pkcs5","pkcs5",NID_pkcs5,8,&(lvalues[1110]),0},
+{"SMIME","S/MIME",NID_SMIME,9,&(lvalues[1118]),0},
+{"id-smime-mod","id-smime-mod",NID_id_smime_mod,10,&(lvalues[1127]),0},
+{"id-smime-ct","id-smime-ct",NID_id_smime_ct,10,&(lvalues[1137]),0},
+{"id-smime-aa","id-smime-aa",NID_id_smime_aa,10,&(lvalues[1147]),0},
+{"id-smime-alg","id-smime-alg",NID_id_smime_alg,10,&(lvalues[1157]),0},
+{"id-smime-cd","id-smime-cd",NID_id_smime_cd,10,&(lvalues[1167]),0},
+{"id-smime-spq","id-smime-spq",NID_id_smime_spq,10,&(lvalues[1177]),0},
+{"id-smime-cti","id-smime-cti",NID_id_smime_cti,10,&(lvalues[1187]),0},
+{"id-smime-mod-cms","id-smime-mod-cms",NID_id_smime_mod_cms,11,
+ &(lvalues[1197]),0},
+{"id-smime-mod-ess","id-smime-mod-ess",NID_id_smime_mod_ess,11,
+ &(lvalues[1208]),0},
+{"id-smime-mod-oid","id-smime-mod-oid",NID_id_smime_mod_oid,11,
+ &(lvalues[1219]),0},
+{"id-smime-mod-msg-v3","id-smime-mod-msg-v3",NID_id_smime_mod_msg_v3,
+ 11,&(lvalues[1230]),0},
+{"id-smime-mod-ets-eSignature-88","id-smime-mod-ets-eSignature-88",
+ NID_id_smime_mod_ets_eSignature_88,11,&(lvalues[1241]),0},
+{"id-smime-mod-ets-eSignature-97","id-smime-mod-ets-eSignature-97",
+ NID_id_smime_mod_ets_eSignature_97,11,&(lvalues[1252]),0},
+{"id-smime-mod-ets-eSigPolicy-88","id-smime-mod-ets-eSigPolicy-88",
+ NID_id_smime_mod_ets_eSigPolicy_88,11,&(lvalues[1263]),0},
+{"id-smime-mod-ets-eSigPolicy-97","id-smime-mod-ets-eSigPolicy-97",
+ NID_id_smime_mod_ets_eSigPolicy_97,11,&(lvalues[1274]),0},
+{"id-smime-ct-receipt","id-smime-ct-receipt",NID_id_smime_ct_receipt,
+ 11,&(lvalues[1285]),0},
+{"id-smime-ct-authData","id-smime-ct-authData",
+ NID_id_smime_ct_authData,11,&(lvalues[1296]),0},
+{"id-smime-ct-publishCert","id-smime-ct-publishCert",
+ NID_id_smime_ct_publishCert,11,&(lvalues[1307]),0},
+{"id-smime-ct-TSTInfo","id-smime-ct-TSTInfo",NID_id_smime_ct_TSTInfo,
+ 11,&(lvalues[1318]),0},
+{"id-smime-ct-TDTInfo","id-smime-ct-TDTInfo",NID_id_smime_ct_TDTInfo,
+ 11,&(lvalues[1329]),0},
+{"id-smime-ct-contentInfo","id-smime-ct-contentInfo",
+ NID_id_smime_ct_contentInfo,11,&(lvalues[1340]),0},
+{"id-smime-ct-DVCSRequestData","id-smime-ct-DVCSRequestData",
+ NID_id_smime_ct_DVCSRequestData,11,&(lvalues[1351]),0},
+{"id-smime-ct-DVCSResponseData","id-smime-ct-DVCSResponseData",
+ NID_id_smime_ct_DVCSResponseData,11,&(lvalues[1362]),0},
+{"id-smime-aa-receiptRequest","id-smime-aa-receiptRequest",
+ NID_id_smime_aa_receiptRequest,11,&(lvalues[1373]),0},
+{"id-smime-aa-securityLabel","id-smime-aa-securityLabel",
+ NID_id_smime_aa_securityLabel,11,&(lvalues[1384]),0},
+{"id-smime-aa-mlExpandHistory","id-smime-aa-mlExpandHistory",
+ NID_id_smime_aa_mlExpandHistory,11,&(lvalues[1395]),0},
+{"id-smime-aa-contentHint","id-smime-aa-contentHint",
+ NID_id_smime_aa_contentHint,11,&(lvalues[1406]),0},
+{"id-smime-aa-msgSigDigest","id-smime-aa-msgSigDigest",
+ NID_id_smime_aa_msgSigDigest,11,&(lvalues[1417]),0},
+{"id-smime-aa-encapContentType","id-smime-aa-encapContentType",
+ NID_id_smime_aa_encapContentType,11,&(lvalues[1428]),0},
+{"id-smime-aa-contentIdentifier","id-smime-aa-contentIdentifier",
+ NID_id_smime_aa_contentIdentifier,11,&(lvalues[1439]),0},
+{"id-smime-aa-macValue","id-smime-aa-macValue",
+ NID_id_smime_aa_macValue,11,&(lvalues[1450]),0},
+{"id-smime-aa-equivalentLabels","id-smime-aa-equivalentLabels",
+ NID_id_smime_aa_equivalentLabels,11,&(lvalues[1461]),0},
+{"id-smime-aa-contentReference","id-smime-aa-contentReference",
+ NID_id_smime_aa_contentReference,11,&(lvalues[1472]),0},
+{"id-smime-aa-encrypKeyPref","id-smime-aa-encrypKeyPref",
+ NID_id_smime_aa_encrypKeyPref,11,&(lvalues[1483]),0},
+{"id-smime-aa-signingCertificate","id-smime-aa-signingCertificate",
+ NID_id_smime_aa_signingCertificate,11,&(lvalues[1494]),0},
+{"id-smime-aa-smimeEncryptCerts","id-smime-aa-smimeEncryptCerts",
+ NID_id_smime_aa_smimeEncryptCerts,11,&(lvalues[1505]),0},
+{"id-smime-aa-timeStampToken","id-smime-aa-timeStampToken",
+ NID_id_smime_aa_timeStampToken,11,&(lvalues[1516]),0},
+{"id-smime-aa-ets-sigPolicyId","id-smime-aa-ets-sigPolicyId",
+ NID_id_smime_aa_ets_sigPolicyId,11,&(lvalues[1527]),0},
+{"id-smime-aa-ets-commitmentType","id-smime-aa-ets-commitmentType",
+ NID_id_smime_aa_ets_commitmentType,11,&(lvalues[1538]),0},
+{"id-smime-aa-ets-signerLocation","id-smime-aa-ets-signerLocation",
+ NID_id_smime_aa_ets_signerLocation,11,&(lvalues[1549]),0},
+{"id-smime-aa-ets-signerAttr","id-smime-aa-ets-signerAttr",
+ NID_id_smime_aa_ets_signerAttr,11,&(lvalues[1560]),0},
+{"id-smime-aa-ets-otherSigCert","id-smime-aa-ets-otherSigCert",
+ NID_id_smime_aa_ets_otherSigCert,11,&(lvalues[1571]),0},
+{"id-smime-aa-ets-contentTimestamp",
+ "id-smime-aa-ets-contentTimestamp",
+ NID_id_smime_aa_ets_contentTimestamp,11,&(lvalues[1582]),0},
+{"id-smime-aa-ets-CertificateRefs","id-smime-aa-ets-CertificateRefs",
+ NID_id_smime_aa_ets_CertificateRefs,11,&(lvalues[1593]),0},
+{"id-smime-aa-ets-RevocationRefs","id-smime-aa-ets-RevocationRefs",
+ NID_id_smime_aa_ets_RevocationRefs,11,&(lvalues[1604]),0},
+{"id-smime-aa-ets-certValues","id-smime-aa-ets-certValues",
+ NID_id_smime_aa_ets_certValues,11,&(lvalues[1615]),0},
+{"id-smime-aa-ets-revocationValues",
+ "id-smime-aa-ets-revocationValues",
+ NID_id_smime_aa_ets_revocationValues,11,&(lvalues[1626]),0},
+{"id-smime-aa-ets-escTimeStamp","id-smime-aa-ets-escTimeStamp",
+ NID_id_smime_aa_ets_escTimeStamp,11,&(lvalues[1637]),0},
+{"id-smime-aa-ets-certCRLTimestamp",
+ "id-smime-aa-ets-certCRLTimestamp",
+ NID_id_smime_aa_ets_certCRLTimestamp,11,&(lvalues[1648]),0},
+{"id-smime-aa-ets-archiveTimeStamp",
+ "id-smime-aa-ets-archiveTimeStamp",
+ NID_id_smime_aa_ets_archiveTimeStamp,11,&(lvalues[1659]),0},
+{"id-smime-aa-signatureType","id-smime-aa-signatureType",
+ NID_id_smime_aa_signatureType,11,&(lvalues[1670]),0},
+{"id-smime-aa-dvcs-dvc","id-smime-aa-dvcs-dvc",
+ NID_id_smime_aa_dvcs_dvc,11,&(lvalues[1681]),0},
+{"id-smime-alg-ESDHwith3DES","id-smime-alg-ESDHwith3DES",
+ NID_id_smime_alg_ESDHwith3DES,11,&(lvalues[1692]),0},
+{"id-smime-alg-ESDHwithRC2","id-smime-alg-ESDHwithRC2",
+ NID_id_smime_alg_ESDHwithRC2,11,&(lvalues[1703]),0},
+{"id-smime-alg-3DESwrap","id-smime-alg-3DESwrap",
+ NID_id_smime_alg_3DESwrap,11,&(lvalues[1714]),0},
+{"id-smime-alg-RC2wrap","id-smime-alg-RC2wrap",
+ NID_id_smime_alg_RC2wrap,11,&(lvalues[1725]),0},
+{"id-smime-alg-ESDH","id-smime-alg-ESDH",NID_id_smime_alg_ESDH,11,
+ &(lvalues[1736]),0},
+{"id-smime-alg-CMS3DESwrap","id-smime-alg-CMS3DESwrap",
+ NID_id_smime_alg_CMS3DESwrap,11,&(lvalues[1747]),0},
+{"id-smime-alg-CMSRC2wrap","id-smime-alg-CMSRC2wrap",
+ NID_id_smime_alg_CMSRC2wrap,11,&(lvalues[1758]),0},
+{"id-smime-cd-ldap","id-smime-cd-ldap",NID_id_smime_cd_ldap,11,
+ &(lvalues[1769]),0},
+{"id-smime-spq-ets-sqt-uri","id-smime-spq-ets-sqt-uri",
+ NID_id_smime_spq_ets_sqt_uri,11,&(lvalues[1780]),0},
+{"id-smime-spq-ets-sqt-unotice","id-smime-spq-ets-sqt-unotice",
+ NID_id_smime_spq_ets_sqt_unotice,11,&(lvalues[1791]),0},
+{"id-smime-cti-ets-proofOfOrigin","id-smime-cti-ets-proofOfOrigin",
+ NID_id_smime_cti_ets_proofOfOrigin,11,&(lvalues[1802]),0},
+{"id-smime-cti-ets-proofOfReceipt","id-smime-cti-ets-proofOfReceipt",
+ NID_id_smime_cti_ets_proofOfReceipt,11,&(lvalues[1813]),0},
+{"id-smime-cti-ets-proofOfDelivery",
+ "id-smime-cti-ets-proofOfDelivery",
+ NID_id_smime_cti_ets_proofOfDelivery,11,&(lvalues[1824]),0},
+{"id-smime-cti-ets-proofOfSender","id-smime-cti-ets-proofOfSender",
+ NID_id_smime_cti_ets_proofOfSender,11,&(lvalues[1835]),0},
+{"id-smime-cti-ets-proofOfApproval",
+ "id-smime-cti-ets-proofOfApproval",
+ NID_id_smime_cti_ets_proofOfApproval,11,&(lvalues[1846]),0},
+{"id-smime-cti-ets-proofOfCreation",
+ "id-smime-cti-ets-proofOfCreation",
+ NID_id_smime_cti_ets_proofOfCreation,11,&(lvalues[1857]),0},
+{"MD4","md4",NID_md4,8,&(lvalues[1868]),0},
+{"id-pkix-mod","id-pkix-mod",NID_id_pkix_mod,7,&(lvalues[1876]),0},
+{"id-qt","id-qt",NID_id_qt,7,&(lvalues[1883]),0},
+{"id-it","id-it",NID_id_it,7,&(lvalues[1890]),0},
+{"id-pkip","id-pkip",NID_id_pkip,7,&(lvalues[1897]),0},
+{"id-alg","id-alg",NID_id_alg,7,&(lvalues[1904]),0},
+{"id-cmc","id-cmc",NID_id_cmc,7,&(lvalues[1911]),0},
+{"id-on","id-on",NID_id_on,7,&(lvalues[1918]),0},
+{"id-pda","id-pda",NID_id_pda,7,&(lvalues[1925]),0},
+{"id-aca","id-aca",NID_id_aca,7,&(lvalues[1932]),0},
+{"id-qcs","id-qcs",NID_id_qcs,7,&(lvalues[1939]),0},
+{"id-cct","id-cct",NID_id_cct,7,&(lvalues[1946]),0},
+{"id-pkix1-explicit-88","id-pkix1-explicit-88",
+ NID_id_pkix1_explicit_88,8,&(lvalues[1953]),0},
+{"id-pkix1-implicit-88","id-pkix1-implicit-88",
+ NID_id_pkix1_implicit_88,8,&(lvalues[1961]),0},
+{"id-pkix1-explicit-93","id-pkix1-explicit-93",
+ NID_id_pkix1_explicit_93,8,&(lvalues[1969]),0},
+{"id-pkix1-implicit-93","id-pkix1-implicit-93",
+ NID_id_pkix1_implicit_93,8,&(lvalues[1977]),0},
+{"id-mod-crmf","id-mod-crmf",NID_id_mod_crmf,8,&(lvalues[1985]),0},
+{"id-mod-cmc","id-mod-cmc",NID_id_mod_cmc,8,&(lvalues[1993]),0},
+{"id-mod-kea-profile-88","id-mod-kea-profile-88",
+ NID_id_mod_kea_profile_88,8,&(lvalues[2001]),0},
+{"id-mod-kea-profile-93","id-mod-kea-profile-93",
+ NID_id_mod_kea_profile_93,8,&(lvalues[2009]),0},
+{"id-mod-cmp","id-mod-cmp",NID_id_mod_cmp,8,&(lvalues[2017]),0},
+{"id-mod-qualified-cert-88","id-mod-qualified-cert-88",
+ NID_id_mod_qualified_cert_88,8,&(lvalues[2025]),0},
+{"id-mod-qualified-cert-93","id-mod-qualified-cert-93",
+ NID_id_mod_qualified_cert_93,8,&(lvalues[2033]),0},
+{"id-mod-attribute-cert","id-mod-attribute-cert",
+ NID_id_mod_attribute_cert,8,&(lvalues[2041]),0},
+{"id-mod-timestamp-protocol","id-mod-timestamp-protocol",
+ NID_id_mod_timestamp_protocol,8,&(lvalues[2049]),0},
+{"id-mod-ocsp","id-mod-ocsp",NID_id_mod_ocsp,8,&(lvalues[2057]),0},
+{"id-mod-dvcs","id-mod-dvcs",NID_id_mod_dvcs,8,&(lvalues[2065]),0},
+{"id-mod-cmp2000","id-mod-cmp2000",NID_id_mod_cmp2000,8,
+ &(lvalues[2073]),0},
+{"biometricInfo","Biometric Info",NID_biometricInfo,8,&(lvalues[2081]),0},
+{"qcStatements","qcStatements",NID_qcStatements,8,&(lvalues[2089]),0},
+{"ac-auditEntity","ac-auditEntity",NID_ac_auditEntity,8,
+ &(lvalues[2097]),0},
+{"ac-targeting","ac-targeting",NID_ac_targeting,8,&(lvalues[2105]),0},
+{"aaControls","aaControls",NID_aaControls,8,&(lvalues[2113]),0},
+{"sbgp-ipAddrBlock","sbgp-ipAddrBlock",NID_sbgp_ipAddrBlock,8,
+ &(lvalues[2121]),0},
+{"sbgp-autonomousSysNum","sbgp-autonomousSysNum",
+ NID_sbgp_autonomousSysNum,8,&(lvalues[2129]),0},
+{"sbgp-routerIdentifier","sbgp-routerIdentifier",
+ NID_sbgp_routerIdentifier,8,&(lvalues[2137]),0},
+{"textNotice","textNotice",NID_textNotice,8,&(lvalues[2145]),0},
+{"ipsecEndSystem","IPSec End System",NID_ipsecEndSystem,8,
+ &(lvalues[2153]),0},
+{"ipsecTunnel","IPSec Tunnel",NID_ipsecTunnel,8,&(lvalues[2161]),0},
+{"ipsecUser","IPSec User",NID_ipsecUser,8,&(lvalues[2169]),0},
+{"DVCS","dvcs",NID_dvcs,8,&(lvalues[2177]),0},
+{"id-it-caProtEncCert","id-it-caProtEncCert",NID_id_it_caProtEncCert,
+ 8,&(lvalues[2185]),0},
+{"id-it-signKeyPairTypes","id-it-signKeyPairTypes",
+ NID_id_it_signKeyPairTypes,8,&(lvalues[2193]),0},
+{"id-it-encKeyPairTypes","id-it-encKeyPairTypes",
+ NID_id_it_encKeyPairTypes,8,&(lvalues[2201]),0},
+{"id-it-preferredSymmAlg","id-it-preferredSymmAlg",
+ NID_id_it_preferredSymmAlg,8,&(lvalues[2209]),0},
+{"id-it-caKeyUpdateInfo","id-it-caKeyUpdateInfo",
+ NID_id_it_caKeyUpdateInfo,8,&(lvalues[2217]),0},
+{"id-it-currentCRL","id-it-currentCRL",NID_id_it_currentCRL,8,
+ &(lvalues[2225]),0},
+{"id-it-unsupportedOIDs","id-it-unsupportedOIDs",
+ NID_id_it_unsupportedOIDs,8,&(lvalues[2233]),0},
+{"id-it-subscriptionRequest","id-it-subscriptionRequest",
+ NID_id_it_subscriptionRequest,8,&(lvalues[2241]),0},
+{"id-it-subscriptionResponse","id-it-subscriptionResponse",
+ NID_id_it_subscriptionResponse,8,&(lvalues[2249]),0},
+{"id-it-keyPairParamReq","id-it-keyPairParamReq",
+ NID_id_it_keyPairParamReq,8,&(lvalues[2257]),0},
+{"id-it-keyPairParamRep","id-it-keyPairParamRep",
+ NID_id_it_keyPairParamRep,8,&(lvalues[2265]),0},
+{"id-it-revPassphrase","id-it-revPassphrase",NID_id_it_revPassphrase,
+ 8,&(lvalues[2273]),0},
+{"id-it-implicitConfirm","id-it-implicitConfirm",
+ NID_id_it_implicitConfirm,8,&(lvalues[2281]),0},
+{"id-it-confirmWaitTime","id-it-confirmWaitTime",
+ NID_id_it_confirmWaitTime,8,&(lvalues[2289]),0},
+{"id-it-origPKIMessage","id-it-origPKIMessage",
+ NID_id_it_origPKIMessage,8,&(lvalues[2297]),0},
+{"id-regCtrl","id-regCtrl",NID_id_regCtrl,8,&(lvalues[2305]),0},
+{"id-regInfo","id-regInfo",NID_id_regInfo,8,&(lvalues[2313]),0},
+{"id-regCtrl-regToken","id-regCtrl-regToken",NID_id_regCtrl_regToken,
+ 9,&(lvalues[2321]),0},
+{"id-regCtrl-authenticator","id-regCtrl-authenticator",
+ NID_id_regCtrl_authenticator,9,&(lvalues[2330]),0},
+{"id-regCtrl-pkiPublicationInfo","id-regCtrl-pkiPublicationInfo",
+ NID_id_regCtrl_pkiPublicationInfo,9,&(lvalues[2339]),0},
+{"id-regCtrl-pkiArchiveOptions","id-regCtrl-pkiArchiveOptions",
+ NID_id_regCtrl_pkiArchiveOptions,9,&(lvalues[2348]),0},
+{"id-regCtrl-oldCertID","id-regCtrl-oldCertID",
+ NID_id_regCtrl_oldCertID,9,&(lvalues[2357]),0},
+{"id-regCtrl-protocolEncrKey","id-regCtrl-protocolEncrKey",
+ NID_id_regCtrl_protocolEncrKey,9,&(lvalues[2366]),0},
+{"id-regInfo-utf8Pairs","id-regInfo-utf8Pairs",
+ NID_id_regInfo_utf8Pairs,9,&(lvalues[2375]),0},
+{"id-regInfo-certReq","id-regInfo-certReq",NID_id_regInfo_certReq,9,
+ &(lvalues[2384]),0},
+{"id-alg-des40","id-alg-des40",NID_id_alg_des40,8,&(lvalues[2393]),0},
+{"id-alg-noSignature","id-alg-noSignature",NID_id_alg_noSignature,8,
+ &(lvalues[2401]),0},
+{"id-alg-dh-sig-hmac-sha1","id-alg-dh-sig-hmac-sha1",
+ NID_id_alg_dh_sig_hmac_sha1,8,&(lvalues[2409]),0},
+{"id-alg-dh-pop","id-alg-dh-pop",NID_id_alg_dh_pop,8,&(lvalues[2417]),0},
+{"id-cmc-statusInfo","id-cmc-statusInfo",NID_id_cmc_statusInfo,8,
+ &(lvalues[2425]),0},
+{"id-cmc-identification","id-cmc-identification",
+ NID_id_cmc_identification,8,&(lvalues[2433]),0},
+{"id-cmc-identityProof","id-cmc-identityProof",
+ NID_id_cmc_identityProof,8,&(lvalues[2441]),0},
+{"id-cmc-dataReturn","id-cmc-dataReturn",NID_id_cmc_dataReturn,8,
+ &(lvalues[2449]),0},
+{"id-cmc-transactionId","id-cmc-transactionId",
+ NID_id_cmc_transactionId,8,&(lvalues[2457]),0},
+{"id-cmc-senderNonce","id-cmc-senderNonce",NID_id_cmc_senderNonce,8,
+ &(lvalues[2465]),0},
+{"id-cmc-recipientNonce","id-cmc-recipientNonce",
+ NID_id_cmc_recipientNonce,8,&(lvalues[2473]),0},
+{"id-cmc-addExtensions","id-cmc-addExtensions",
+ NID_id_cmc_addExtensions,8,&(lvalues[2481]),0},
+{"id-cmc-encryptedPOP","id-cmc-encryptedPOP",NID_id_cmc_encryptedPOP,
+ 8,&(lvalues[2489]),0},
+{"id-cmc-decryptedPOP","id-cmc-decryptedPOP",NID_id_cmc_decryptedPOP,
+ 8,&(lvalues[2497]),0},
+{"id-cmc-lraPOPWitness","id-cmc-lraPOPWitness",
+ NID_id_cmc_lraPOPWitness,8,&(lvalues[2505]),0},
+{"id-cmc-getCert","id-cmc-getCert",NID_id_cmc_getCert,8,
+ &(lvalues[2513]),0},
+{"id-cmc-getCRL","id-cmc-getCRL",NID_id_cmc_getCRL,8,&(lvalues[2521]),0},
+{"id-cmc-revokeRequest","id-cmc-revokeRequest",
+ NID_id_cmc_revokeRequest,8,&(lvalues[2529]),0},
+{"id-cmc-regInfo","id-cmc-regInfo",NID_id_cmc_regInfo,8,
+ &(lvalues[2537]),0},
+{"id-cmc-responseInfo","id-cmc-responseInfo",NID_id_cmc_responseInfo,
+ 8,&(lvalues[2545]),0},
+{"id-cmc-queryPending","id-cmc-queryPending",NID_id_cmc_queryPending,
+ 8,&(lvalues[2553]),0},
+{"id-cmc-popLinkRandom","id-cmc-popLinkRandom",
+ NID_id_cmc_popLinkRandom,8,&(lvalues[2561]),0},
+{"id-cmc-popLinkWitness","id-cmc-popLinkWitness",
+ NID_id_cmc_popLinkWitness,8,&(lvalues[2569]),0},
+{"id-cmc-confirmCertAcceptance","id-cmc-confirmCertAcceptance",
+ NID_id_cmc_confirmCertAcceptance,8,&(lvalues[2577]),0},
+{"id-on-personalData","id-on-personalData",NID_id_on_personalData,8,
+ &(lvalues[2585]),0},
+{"id-pda-dateOfBirth","id-pda-dateOfBirth",NID_id_pda_dateOfBirth,8,
+ &(lvalues[2593]),0},
+{"id-pda-placeOfBirth","id-pda-placeOfBirth",NID_id_pda_placeOfBirth,
+ 8,&(lvalues[2601]),0},
+{NULL,NULL,NID_undef,0,NULL,0},
+{"id-pda-gender","id-pda-gender",NID_id_pda_gender,8,&(lvalues[2609]),0},
+{"id-pda-countryOfCitizenship","id-pda-countryOfCitizenship",
+ NID_id_pda_countryOfCitizenship,8,&(lvalues[2617]),0},
+{"id-pda-countryOfResidence","id-pda-countryOfResidence",
+ NID_id_pda_countryOfResidence,8,&(lvalues[2625]),0},
+{"id-aca-authenticationInfo","id-aca-authenticationInfo",
+ NID_id_aca_authenticationInfo,8,&(lvalues[2633]),0},
+{"id-aca-accessIdentity","id-aca-accessIdentity",
+ NID_id_aca_accessIdentity,8,&(lvalues[2641]),0},
+{"id-aca-chargingIdentity","id-aca-chargingIdentity",
+ NID_id_aca_chargingIdentity,8,&(lvalues[2649]),0},
+{"id-aca-group","id-aca-group",NID_id_aca_group,8,&(lvalues[2657]),0},
+{"id-aca-role","id-aca-role",NID_id_aca_role,8,&(lvalues[2665]),0},
+{"id-qcs-pkixQCSyntax-v1","id-qcs-pkixQCSyntax-v1",
+ NID_id_qcs_pkixQCSyntax_v1,8,&(lvalues[2673]),0},
+{"id-cct-crs","id-cct-crs",NID_id_cct_crs,8,&(lvalues[2681]),0},
+{"id-cct-PKIData","id-cct-PKIData",NID_id_cct_PKIData,8,
+ &(lvalues[2689]),0},
+{"id-cct-PKIResponse","id-cct-PKIResponse",NID_id_cct_PKIResponse,8,
+ &(lvalues[2697]),0},
+{"ad_timestamping","AD Time Stamping",NID_ad_timeStamping,8,
+ &(lvalues[2705]),0},
+{"AD_DVCS","ad dvcs",NID_ad_dvcs,8,&(lvalues[2713]),0},
+{"basicOCSPResponse","Basic OCSP Response",NID_id_pkix_OCSP_basic,9,
+ &(lvalues[2721]),0},
+{"Nonce","OCSP Nonce",NID_id_pkix_OCSP_Nonce,9,&(lvalues[2730]),0},
+{"CrlID","OCSP CRL ID",NID_id_pkix_OCSP_CrlID,9,&(lvalues[2739]),0},
+{"acceptableResponses","Acceptable OCSP Responses",
+ NID_id_pkix_OCSP_acceptableResponses,9,&(lvalues[2748]),0},
+{"noCheck","OCSP No Check",NID_id_pkix_OCSP_noCheck,9,&(lvalues[2757]),0},
+{"archiveCutoff","OCSP Archive Cutoff",NID_id_pkix_OCSP_archiveCutoff,
+ 9,&(lvalues[2766]),0},
+{"serviceLocator","OCSP Service Locator",
+ NID_id_pkix_OCSP_serviceLocator,9,&(lvalues[2775]),0},
+{"extendedStatus","Extended OCSP Status",
+ NID_id_pkix_OCSP_extendedStatus,9,&(lvalues[2784]),0},
+{"valid","valid",NID_id_pkix_OCSP_valid,9,&(lvalues[2793]),0},
+{"path","path",NID_id_pkix_OCSP_path,9,&(lvalues[2802]),0},
+{"trustRoot","Trust Root",NID_id_pkix_OCSP_trustRoot,9,
+ &(lvalues[2811]),0},
+{"algorithm","algorithm",NID_algorithm,4,&(lvalues[2820]),0},
+{"rsaSignature","rsaSignature",NID_rsaSignature,5,&(lvalues[2824]),0},
+{"X500algorithms","directory services - algorithms",
+ NID_X500algorithms,2,&(lvalues[2829]),0},
+{"ORG","org",NID_org,1,&(lvalues[2831]),0},
+{"DOD","dod",NID_dod,2,&(lvalues[2832]),0},
+{"IANA","iana",NID_iana,3,&(lvalues[2834]),0},
+{"directory","Directory",NID_Directory,4,&(lvalues[2837]),0},
+{"mgmt","Management",NID_Management,4,&(lvalues[2841]),0},
+{"experimental","Experimental",NID_Experimental,4,&(lvalues[2845]),0},
+{"private","Private",NID_Private,4,&(lvalues[2849]),0},
+{"security","Security",NID_Security,4,&(lvalues[2853]),0},
+{"snmpv2","SNMPv2",NID_SNMPv2,4,&(lvalues[2857]),0},
+{"Mail","Mail",NID_Mail,4,&(lvalues[2861]),0},
+{"enterprises","Enterprises",NID_Enterprises,5,&(lvalues[2865]),0},
+{"dcobject","dcObject",NID_dcObject,9,&(lvalues[2870]),0},
+{"DC","domainComponent",NID_domainComponent,10,&(lvalues[2879]),0},
+{"domain","Domain",NID_Domain,10,&(lvalues[2889]),0},
+{"NULL","NULL",NID_joint_iso_ccitt,1,&(lvalues[2899]),0},
+{"selected-attribute-types","Selected Attribute Types",
+ NID_selected_attribute_types,3,&(lvalues[2900]),0},
+{"clearance","clearance",NID_clearance,4,&(lvalues[2903]),0},
+{"RSA-MD4","md4WithRSAEncryption",NID_md4WithRSAEncryption,9,
+ &(lvalues[2907]),0},
+{"ac-proxying","ac-proxying",NID_ac_proxying,8,&(lvalues[2916]),0},
+{"subjectInfoAccess","Subject Information Access",NID_sinfo_access,8,
+ &(lvalues[2924]),0},
+{"id-aca-encAttrs","id-aca-encAttrs",NID_id_aca_encAttrs,8,
+ &(lvalues[2932]),0},
+{"role","role",NID_role,3,&(lvalues[2940]),0},
+{"policyConstraints","X509v3 Policy Constraints",
+ NID_policy_constraints,3,&(lvalues[2943]),0},
+{"targetInformation","X509v3 AC Targeting",NID_target_information,3,
+ &(lvalues[2946]),0},
+{"noRevAvail","X509v3 No Revocation Available",NID_no_rev_avail,3,
+ &(lvalues[2949]),0},
+{"NULL","NULL",NID_ccitt,1,&(lvalues[2952]),0},
+{"ansi-X9-62","ANSI X9.62",NID_ansi_X9_62,5,&(lvalues[2953]),0},
+{"prime-field","prime-field",NID_X9_62_prime_field,7,&(lvalues[2958]),0},
+{"characteristic-two-field","characteristic-two-field",
+ NID_X9_62_characteristic_two_field,7,&(lvalues[2965]),0},
+{"id-ecPublicKey","id-ecPublicKey",NID_X9_62_id_ecPublicKey,7,
+ &(lvalues[2972]),0},
+{"prime192v1","prime192v1",NID_X9_62_prime192v1,8,&(lvalues[2979]),0},
+{"prime192v2","prime192v2",NID_X9_62_prime192v2,8,&(lvalues[2987]),0},
+{"prime192v3","prime192v3",NID_X9_62_prime192v3,8,&(lvalues[2995]),0},
+{"prime239v1","prime239v1",NID_X9_62_prime239v1,8,&(lvalues[3003]),0},
+{"prime239v2","prime239v2",NID_X9_62_prime239v2,8,&(lvalues[3011]),0},
+{"prime239v3","prime239v3",NID_X9_62_prime239v3,8,&(lvalues[3019]),0},
+{"prime256v1","prime256v1",NID_X9_62_prime256v1,8,&(lvalues[3027]),0},
+{"ecdsa-with-SHA1","ecdsa-with-SHA1",NID_ecdsa_with_SHA1,7,
+ &(lvalues[3035]),0},
+{"CSPName","Microsoft CSP Name",NID_ms_csp_name,9,&(lvalues[3042]),0},
+{"AES-128-ECB","aes-128-ecb",NID_aes_128_ecb,9,&(lvalues[3051]),0},
+{"AES-128-CBC","aes-128-cbc",NID_aes_128_cbc,9,&(lvalues[3060]),0},
+{"AES-128-OFB","aes-128-ofb",NID_aes_128_ofb128,9,&(lvalues[3069]),0},
+{"AES-128-CFB","aes-128-cfb",NID_aes_128_cfb128,9,&(lvalues[3078]),0},
+{"AES-192-ECB","aes-192-ecb",NID_aes_192_ecb,9,&(lvalues[3087]),0},
+{"AES-192-CBC","aes-192-cbc",NID_aes_192_cbc,9,&(lvalues[3096]),0},
+{"AES-192-OFB","aes-192-ofb",NID_aes_192_ofb128,9,&(lvalues[3105]),0},
+{"AES-192-CFB","aes-192-cfb",NID_aes_192_cfb128,9,&(lvalues[3114]),0},
+{"AES-256-ECB","aes-256-ecb",NID_aes_256_ecb,9,&(lvalues[3123]),0},
+{"AES-256-CBC","aes-256-cbc",NID_aes_256_cbc,9,&(lvalues[3132]),0},
+{"AES-256-OFB","aes-256-ofb",NID_aes_256_ofb128,9,&(lvalues[3141]),0},
+{"AES-256-CFB","aes-256-cfb",NID_aes_256_cfb128,9,&(lvalues[3150]),0},
+{"holdInstructionCode","Hold Instruction Code",
+ NID_hold_instruction_code,3,&(lvalues[3159]),0},
+{"holdInstructionNone","Hold Instruction None",
+ NID_hold_instruction_none,7,&(lvalues[3162]),0},
+{"holdInstructionCallIssuer","Hold Instruction Call Issuer",
+ NID_hold_instruction_call_issuer,7,&(lvalues[3169]),0},
+{"holdInstructionReject","Hold Instruction Reject",
+ NID_hold_instruction_reject,7,&(lvalues[3176]),0},
+{"data","data",NID_data,1,&(lvalues[3183]),0},
+{"pss","pss",NID_pss,3,&(lvalues[3184]),0},
+{"ucl","ucl",NID_ucl,7,&(lvalues[3187]),0},
+{"pilot","pilot",NID_pilot,8,&(lvalues[3194]),0},
+{"pilotAttributeType","pilotAttributeType",NID_pilotAttributeType,9,
+ &(lvalues[3202]),0},
+{"pilotAttributeSyntax","pilotAttributeSyntax",
+ NID_pilotAttributeSyntax,9,&(lvalues[3211]),0},
+{"pilotObjectClass","pilotObjectClass",NID_pilotObjectClass,9,
+ &(lvalues[3220]),0},
+{"pilotGroups","pilotGroups",NID_pilotGroups,9,&(lvalues[3229]),0},
+{"iA5StringSyntax","iA5StringSyntax",NID_iA5StringSyntax,10,
+ &(lvalues[3238]),0},
+{"caseIgnoreIA5StringSyntax","caseIgnoreIA5StringSyntax",
+ NID_caseIgnoreIA5StringSyntax,10,&(lvalues[3248]),0},
+{"pilotObject","pilotObject",NID_pilotObject,10,&(lvalues[3258]),0},
+{"pilotPerson","pilotPerson",NID_pilotPerson,10,&(lvalues[3268]),0},
+{"account","account",NID_account,10,&(lvalues[3278]),0},
+{"document","document",NID_document,10,&(lvalues[3288]),0},
+{"room","room",NID_room,10,&(lvalues[3298]),0},
+{"documentSeries","documentSeries",NID_documentSeries,10,
+ &(lvalues[3308]),0},
+{"rFC822localPart","rFC822localPart",NID_rFC822localPart,10,
+ &(lvalues[3318]),0},
+{"dNSDomain","dNSDomain",NID_dNSDomain,10,&(lvalues[3328]),0},
+{"domainRelatedObject","domainRelatedObject",NID_domainRelatedObject,
+ 10,&(lvalues[3338]),0},
+{"friendlyCountry","friendlyCountry",NID_friendlyCountry,10,
+ &(lvalues[3348]),0},
+{"simpleSecurityObject","simpleSecurityObject",
+ NID_simpleSecurityObject,10,&(lvalues[3358]),0},
+{"pilotOrganization","pilotOrganization",NID_pilotOrganization,10,
+ &(lvalues[3368]),0},
+{"pilotDSA","pilotDSA",NID_pilotDSA,10,&(lvalues[3378]),0},
+{"qualityLabelledData","qualityLabelledData",NID_qualityLabelledData,
+ 10,&(lvalues[3388]),0},
+{"UID","userId",NID_userId,10,&(lvalues[3398]),0},
+{"textEncodedORAddress","textEncodedORAddress",
+ NID_textEncodedORAddress,10,&(lvalues[3408]),0},
+{"mail","rfc822Mailbox",NID_rfc822Mailbox,10,&(lvalues[3418]),0},
+{"info","info",NID_info,10,&(lvalues[3428]),0},
+{"favouriteDrink","favouriteDrink",NID_favouriteDrink,10,
+ &(lvalues[3438]),0},
+{"roomNumber","roomNumber",NID_roomNumber,10,&(lvalues[3448]),0},
+{"photo","photo",NID_photo,10,&(lvalues[3458]),0},
+{"userClass","userClass",NID_userClass,10,&(lvalues[3468]),0},
+{"host","host",NID_host,10,&(lvalues[3478]),0},
+{"manager","manager",NID_manager,10,&(lvalues[3488]),0},
+{"documentIdentifier","documentIdentifier",NID_documentIdentifier,10,
+ &(lvalues[3498]),0},
+{"documentTitle","documentTitle",NID_documentTitle,10,&(lvalues[3508]),0},
+{"documentVersion","documentVersion",NID_documentVersion,10,
+ &(lvalues[3518]),0},
+{"documentAuthor","documentAuthor",NID_documentAuthor,10,
+ &(lvalues[3528]),0},
+{"documentLocation","documentLocation",NID_documentLocation,10,
+ &(lvalues[3538]),0},
+{"homeTelephoneNumber","homeTelephoneNumber",NID_homeTelephoneNumber,
+ 10,&(lvalues[3548]),0},
+{"secretary","secretary",NID_secretary,10,&(lvalues[3558]),0},
+{"otherMailbox","otherMailbox",NID_otherMailbox,10,&(lvalues[3568]),0},
+{"lastModifiedTime","lastModifiedTime",NID_lastModifiedTime,10,
+ &(lvalues[3578]),0},
+{"lastModifiedBy","lastModifiedBy",NID_lastModifiedBy,10,
+ &(lvalues[3588]),0},
+{"aRecord","aRecord",NID_aRecord,10,&(lvalues[3598]),0},
+{"pilotAttributeType27","pilotAttributeType27",
+ NID_pilotAttributeType27,10,&(lvalues[3608]),0},
+{"mXRecord","mXRecord",NID_mXRecord,10,&(lvalues[3618]),0},
+{"nSRecord","nSRecord",NID_nSRecord,10,&(lvalues[3628]),0},
+{"sOARecord","sOARecord",NID_sOARecord,10,&(lvalues[3638]),0},
+{"cNAMERecord","cNAMERecord",NID_cNAMERecord,10,&(lvalues[3648]),0},
+{"associatedDomain","associatedDomain",NID_associatedDomain,10,
+ &(lvalues[3658]),0},
+{"associatedName","associatedName",NID_associatedName,10,
+ &(lvalues[3668]),0},
+{"homePostalAddress","homePostalAddress",NID_homePostalAddress,10,
+ &(lvalues[3678]),0},
+{"personalTitle","personalTitle",NID_personalTitle,10,&(lvalues[3688]),0},
+{"mobileTelephoneNumber","mobileTelephoneNumber",
+ NID_mobileTelephoneNumber,10,&(lvalues[3698]),0},
+{"pagerTelephoneNumber","pagerTelephoneNumber",
+ NID_pagerTelephoneNumber,10,&(lvalues[3708]),0},
+{"friendlyCountryName","friendlyCountryName",NID_friendlyCountryName,
+ 10,&(lvalues[3718]),0},
+{"organizationalStatus","organizationalStatus",
+ NID_organizationalStatus,10,&(lvalues[3728]),0},
+{"janetMailbox","janetMailbox",NID_janetMailbox,10,&(lvalues[3738]),0},
+{"mailPreferenceOption","mailPreferenceOption",
+ NID_mailPreferenceOption,10,&(lvalues[3748]),0},
+{"buildingName","buildingName",NID_buildingName,10,&(lvalues[3758]),0},
+{"dSAQuality","dSAQuality",NID_dSAQuality,10,&(lvalues[3768]),0},
+{"singleLevelQuality","singleLevelQuality",NID_singleLevelQuality,10,
+ &(lvalues[3778]),0},
+{"subtreeMinimumQuality","subtreeMinimumQuality",
+ NID_subtreeMinimumQuality,10,&(lvalues[3788]),0},
+{"subtreeMaximumQuality","subtreeMaximumQuality",
+ NID_subtreeMaximumQuality,10,&(lvalues[3798]),0},
+{"personalSignature","personalSignature",NID_personalSignature,10,
+ &(lvalues[3808]),0},
+{"dITRedirect","dITRedirect",NID_dITRedirect,10,&(lvalues[3818]),0},
+{"audio","audio",NID_audio,10,&(lvalues[3828]),0},
+{"documentPublisher","documentPublisher",NID_documentPublisher,10,
+ &(lvalues[3838]),0},
+{"x500UniqueIdentifier","x500UniqueIdentifier",
+ NID_x500UniqueIdentifier,3,&(lvalues[3848]),0},
+{"mime-mhs","MIME MHS",NID_mime_mhs,5,&(lvalues[3851]),0},
+{"mime-mhs-headings","mime-mhs-headings",NID_mime_mhs_headings,6,
+ &(lvalues[3856]),0},
+{"mime-mhs-bodies","mime-mhs-bodies",NID_mime_mhs_bodies,6,
+ &(lvalues[3862]),0},
+{"id-hex-partial-message","id-hex-partial-message",
+ NID_id_hex_partial_message,7,&(lvalues[3868]),0},
+{"id-hex-multipart-message","id-hex-multipart-message",
+ NID_id_hex_multipart_message,7,&(lvalues[3875]),0},
+{"generationQualifier","generationQualifier",NID_generationQualifier,
+ 3,&(lvalues[3882]),0},
+{"pseudonym","pseudonym",NID_pseudonym,3,&(lvalues[3885]),0},
+{NULL,NULL,NID_undef,0,NULL,0},
+{"id-set","Secure Electronic Transactions",NID_id_set,2,
+ &(lvalues[3888]),0},
+{"set-ctype","content types",NID_set_ctype,3,&(lvalues[3890]),0},
+{"set-msgExt","message extensions",NID_set_msgExt,3,&(lvalues[3893]),0},
+{"set-attr","set-attr",NID_set_attr,3,&(lvalues[3896]),0},
+{"set-policy","set-policy",NID_set_policy,3,&(lvalues[3899]),0},
+{"set-certExt","certificate extensions",NID_set_certExt,3,
+ &(lvalues[3902]),0},
+{"set-brand","set-brand",NID_set_brand,3,&(lvalues[3905]),0},
+{"setct-PANData","setct-PANData",NID_setct_PANData,4,&(lvalues[3908]),0},
+{"setct-PANToken","setct-PANToken",NID_setct_PANToken,4,
+ &(lvalues[3912]),0},
+{"setct-PANOnly","setct-PANOnly",NID_setct_PANOnly,4,&(lvalues[3916]),0},
+{"setct-OIData","setct-OIData",NID_setct_OIData,4,&(lvalues[3920]),0},
+{"setct-PI","setct-PI",NID_setct_PI,4,&(lvalues[3924]),0},
+{"setct-PIData","setct-PIData",NID_setct_PIData,4,&(lvalues[3928]),0},
+{"setct-PIDataUnsigned","setct-PIDataUnsigned",
+ NID_setct_PIDataUnsigned,4,&(lvalues[3932]),0},
+{"setct-HODInput","setct-HODInput",NID_setct_HODInput,4,
+ &(lvalues[3936]),0},
+{"setct-AuthResBaggage","setct-AuthResBaggage",
+ NID_setct_AuthResBaggage,4,&(lvalues[3940]),0},
+{"setct-AuthRevReqBaggage","setct-AuthRevReqBaggage",
+ NID_setct_AuthRevReqBaggage,4,&(lvalues[3944]),0},
+{"setct-AuthRevResBaggage","setct-AuthRevResBaggage",
+ NID_setct_AuthRevResBaggage,4,&(lvalues[3948]),0},
+{"setct-CapTokenSeq","setct-CapTokenSeq",NID_setct_CapTokenSeq,4,
+ &(lvalues[3952]),0},
+{"setct-PInitResData","setct-PInitResData",NID_setct_PInitResData,4,
+ &(lvalues[3956]),0},
+{"setct-PI-TBS","setct-PI-TBS",NID_setct_PI_TBS,4,&(lvalues[3960]),0},
+{"setct-PResData","setct-PResData",NID_setct_PResData,4,
+ &(lvalues[3964]),0},
+{"setct-AuthReqTBS","setct-AuthReqTBS",NID_setct_AuthReqTBS,4,
+ &(lvalues[3968]),0},
+{"setct-AuthResTBS","setct-AuthResTBS",NID_setct_AuthResTBS,4,
+ &(lvalues[3972]),0},
+{"setct-AuthResTBSX","setct-AuthResTBSX",NID_setct_AuthResTBSX,4,
+ &(lvalues[3976]),0},
+{"setct-AuthTokenTBS","setct-AuthTokenTBS",NID_setct_AuthTokenTBS,4,
+ &(lvalues[3980]),0},
+{"setct-CapTokenData","setct-CapTokenData",NID_setct_CapTokenData,4,
+ &(lvalues[3984]),0},
+{"setct-CapTokenTBS","setct-CapTokenTBS",NID_setct_CapTokenTBS,4,
+ &(lvalues[3988]),0},
+{"setct-AcqCardCodeMsg","setct-AcqCardCodeMsg",
+ NID_setct_AcqCardCodeMsg,4,&(lvalues[3992]),0},
+{"setct-AuthRevReqTBS","setct-AuthRevReqTBS",NID_setct_AuthRevReqTBS,
+ 4,&(lvalues[3996]),0},
+{"setct-AuthRevResData","setct-AuthRevResData",
+ NID_setct_AuthRevResData,4,&(lvalues[4000]),0},
+{"setct-AuthRevResTBS","setct-AuthRevResTBS",NID_setct_AuthRevResTBS,
+ 4,&(lvalues[4004]),0},
+{"setct-CapReqTBS","setct-CapReqTBS",NID_setct_CapReqTBS,4,
+ &(lvalues[4008]),0},
+{"setct-CapReqTBSX","setct-CapReqTBSX",NID_setct_CapReqTBSX,4,
+ &(lvalues[4012]),0},
+{"setct-CapResData","setct-CapResData",NID_setct_CapResData,4,
+ &(lvalues[4016]),0},
+{"setct-CapRevReqTBS","setct-CapRevReqTBS",NID_setct_CapRevReqTBS,4,
+ &(lvalues[4020]),0},
+{"setct-CapRevReqTBSX","setct-CapRevReqTBSX",NID_setct_CapRevReqTBSX,
+ 4,&(lvalues[4024]),0},
+{"setct-CapRevResData","setct-CapRevResData",NID_setct_CapRevResData,
+ 4,&(lvalues[4028]),0},
+{"setct-CredReqTBS","setct-CredReqTBS",NID_setct_CredReqTBS,4,
+ &(lvalues[4032]),0},
+{"setct-CredReqTBSX","setct-CredReqTBSX",NID_setct_CredReqTBSX,4,
+ &(lvalues[4036]),0},
+{"setct-CredResData","setct-CredResData",NID_setct_CredResData,4,
+ &(lvalues[4040]),0},
+{"setct-CredRevReqTBS","setct-CredRevReqTBS",NID_setct_CredRevReqTBS,
+ 4,&(lvalues[4044]),0},
+{"setct-CredRevReqTBSX","setct-CredRevReqTBSX",
+ NID_setct_CredRevReqTBSX,4,&(lvalues[4048]),0},
+{"setct-CredRevResData","setct-CredRevResData",
+ NID_setct_CredRevResData,4,&(lvalues[4052]),0},
+{"setct-PCertReqData","setct-PCertReqData",NID_setct_PCertReqData,4,
+ &(lvalues[4056]),0},
+{"setct-PCertResTBS","setct-PCertResTBS",NID_setct_PCertResTBS,4,
+ &(lvalues[4060]),0},
+{"setct-BatchAdminReqData","setct-BatchAdminReqData",
+ NID_setct_BatchAdminReqData,4,&(lvalues[4064]),0},
+{"setct-BatchAdminResData","setct-BatchAdminResData",
+ NID_setct_BatchAdminResData,4,&(lvalues[4068]),0},
+{"setct-CardCInitResTBS","setct-CardCInitResTBS",
+ NID_setct_CardCInitResTBS,4,&(lvalues[4072]),0},
+{"setct-MeAqCInitResTBS","setct-MeAqCInitResTBS",
+ NID_setct_MeAqCInitResTBS,4,&(lvalues[4076]),0},
+{"setct-RegFormResTBS","setct-RegFormResTBS",NID_setct_RegFormResTBS,
+ 4,&(lvalues[4080]),0},
+{"setct-CertReqData","setct-CertReqData",NID_setct_CertReqData,4,
+ &(lvalues[4084]),0},
+{"setct-CertReqTBS","setct-CertReqTBS",NID_setct_CertReqTBS,4,
+ &(lvalues[4088]),0},
+{"setct-CertResData","setct-CertResData",NID_setct_CertResData,4,
+ &(lvalues[4092]),0},
+{"setct-CertInqReqTBS","setct-CertInqReqTBS",NID_setct_CertInqReqTBS,
+ 4,&(lvalues[4096]),0},
+{"setct-ErrorTBS","setct-ErrorTBS",NID_setct_ErrorTBS,4,
+ &(lvalues[4100]),0},
+{"setct-PIDualSignedTBE","setct-PIDualSignedTBE",
+ NID_setct_PIDualSignedTBE,4,&(lvalues[4104]),0},
+{"setct-PIUnsignedTBE","setct-PIUnsignedTBE",NID_setct_PIUnsignedTBE,
+ 4,&(lvalues[4108]),0},
+{"setct-AuthReqTBE","setct-AuthReqTBE",NID_setct_AuthReqTBE,4,
+ &(lvalues[4112]),0},
+{"setct-AuthResTBE","setct-AuthResTBE",NID_setct_AuthResTBE,4,
+ &(lvalues[4116]),0},
+{"setct-AuthResTBEX","setct-AuthResTBEX",NID_setct_AuthResTBEX,4,
+ &(lvalues[4120]),0},
+{"setct-AuthTokenTBE","setct-AuthTokenTBE",NID_setct_AuthTokenTBE,4,
+ &(lvalues[4124]),0},
+{"setct-CapTokenTBE","setct-CapTokenTBE",NID_setct_CapTokenTBE,4,
+ &(lvalues[4128]),0},
+{"setct-CapTokenTBEX","setct-CapTokenTBEX",NID_setct_CapTokenTBEX,4,
+ &(lvalues[4132]),0},
+{"setct-AcqCardCodeMsgTBE","setct-AcqCardCodeMsgTBE",
+ NID_setct_AcqCardCodeMsgTBE,4,&(lvalues[4136]),0},
+{"setct-AuthRevReqTBE","setct-AuthRevReqTBE",NID_setct_AuthRevReqTBE,
+ 4,&(lvalues[4140]),0},
+{"setct-AuthRevResTBE","setct-AuthRevResTBE",NID_setct_AuthRevResTBE,
+ 4,&(lvalues[4144]),0},
+{"setct-AuthRevResTBEB","setct-AuthRevResTBEB",
+ NID_setct_AuthRevResTBEB,4,&(lvalues[4148]),0},
+{"setct-CapReqTBE","setct-CapReqTBE",NID_setct_CapReqTBE,4,
+ &(lvalues[4152]),0},
+{"setct-CapReqTBEX","setct-CapReqTBEX",NID_setct_CapReqTBEX,4,
+ &(lvalues[4156]),0},
+{"setct-CapResTBE","setct-CapResTBE",NID_setct_CapResTBE,4,
+ &(lvalues[4160]),0},
+{"setct-CapRevReqTBE","setct-CapRevReqTBE",NID_setct_CapRevReqTBE,4,
+ &(lvalues[4164]),0},
+{"setct-CapRevReqTBEX","setct-CapRevReqTBEX",NID_setct_CapRevReqTBEX,
+ 4,&(lvalues[4168]),0},
+{"setct-CapRevResTBE","setct-CapRevResTBE",NID_setct_CapRevResTBE,4,
+ &(lvalues[4172]),0},
+{"setct-CredReqTBE","setct-CredReqTBE",NID_setct_CredReqTBE,4,
+ &(lvalues[4176]),0},
+{"setct-CredReqTBEX","setct-CredReqTBEX",NID_setct_CredReqTBEX,4,
+ &(lvalues[4180]),0},
+{"setct-CredResTBE","setct-CredResTBE",NID_setct_CredResTBE,4,
+ &(lvalues[4184]),0},
+{"setct-CredRevReqTBE","setct-CredRevReqTBE",NID_setct_CredRevReqTBE,
+ 4,&(lvalues[4188]),0},
+{"setct-CredRevReqTBEX","setct-CredRevReqTBEX",
+ NID_setct_CredRevReqTBEX,4,&(lvalues[4192]),0},
+{"setct-CredRevResTBE","setct-CredRevResTBE",NID_setct_CredRevResTBE,
+ 4,&(lvalues[4196]),0},
+{"setct-BatchAdminReqTBE","setct-BatchAdminReqTBE",
+ NID_setct_BatchAdminReqTBE,4,&(lvalues[4200]),0},
+{"setct-BatchAdminResTBE","setct-BatchAdminResTBE",
+ NID_setct_BatchAdminResTBE,4,&(lvalues[4204]),0},
+{"setct-RegFormReqTBE","setct-RegFormReqTBE",NID_setct_RegFormReqTBE,
+ 4,&(lvalues[4208]),0},
+{"setct-CertReqTBE","setct-CertReqTBE",NID_setct_CertReqTBE,4,
+ &(lvalues[4212]),0},
+{"setct-CertReqTBEX","setct-CertReqTBEX",NID_setct_CertReqTBEX,4,
+ &(lvalues[4216]),0},
+{"setct-CertResTBE","setct-CertResTBE",NID_setct_CertResTBE,4,
+ &(lvalues[4220]),0},
+{"setct-CRLNotificationTBS","setct-CRLNotificationTBS",
+ NID_setct_CRLNotificationTBS,4,&(lvalues[4224]),0},
+{"setct-CRLNotificationResTBS","setct-CRLNotificationResTBS",
+ NID_setct_CRLNotificationResTBS,4,&(lvalues[4228]),0},
+{"setct-BCIDistributionTBS","setct-BCIDistributionTBS",
+ NID_setct_BCIDistributionTBS,4,&(lvalues[4232]),0},
+{"setext-genCrypt","generic cryptogram",NID_setext_genCrypt,4,
+ &(lvalues[4236]),0},
+{"setext-miAuth","merchant initiated auth",NID_setext_miAuth,4,
+ &(lvalues[4240]),0},
+{"setext-pinSecure","setext-pinSecure",NID_setext_pinSecure,4,
+ &(lvalues[4244]),0},
+{"setext-pinAny","setext-pinAny",NID_setext_pinAny,4,&(lvalues[4248]),0},
+{"setext-track2","setext-track2",NID_setext_track2,4,&(lvalues[4252]),0},
+{"setext-cv","additional verification",NID_setext_cv,4,
+ &(lvalues[4256]),0},
+{"set-policy-root","set-policy-root",NID_set_policy_root,4,
+ &(lvalues[4260]),0},
+{"setCext-hashedRoot","setCext-hashedRoot",NID_setCext_hashedRoot,4,
+ &(lvalues[4264]),0},
+{"setCext-certType","setCext-certType",NID_setCext_certType,4,
+ &(lvalues[4268]),0},
+{"setCext-merchData","setCext-merchData",NID_setCext_merchData,4,
+ &(lvalues[4272]),0},
+{"setCext-cCertRequired","setCext-cCertRequired",
+ NID_setCext_cCertRequired,4,&(lvalues[4276]),0},
+{"setCext-tunneling","setCext-tunneling",NID_setCext_tunneling,4,
+ &(lvalues[4280]),0},
+{"setCext-setExt","setCext-setExt",NID_setCext_setExt,4,
+ &(lvalues[4284]),0},
+{"setCext-setQualf","setCext-setQualf",NID_setCext_setQualf,4,
+ &(lvalues[4288]),0},
+{"setCext-PGWYcapabilities","setCext-PGWYcapabilities",
+ NID_setCext_PGWYcapabilities,4,&(lvalues[4292]),0},
+{"setCext-TokenIdentifier","setCext-TokenIdentifier",
+ NID_setCext_TokenIdentifier,4,&(lvalues[4296]),0},
+{"setCext-Track2Data","setCext-Track2Data",NID_setCext_Track2Data,4,
+ &(lvalues[4300]),0},
+{"setCext-TokenType","setCext-TokenType",NID_setCext_TokenType,4,
+ &(lvalues[4304]),0},
+{"setCext-IssuerCapabilities","setCext-IssuerCapabilities",
+ NID_setCext_IssuerCapabilities,4,&(lvalues[4308]),0},
+{"setAttr-Cert","setAttr-Cert",NID_setAttr_Cert,4,&(lvalues[4312]),0},
+{"setAttr-PGWYcap","payment gateway capabilities",NID_setAttr_PGWYcap,
+ 4,&(lvalues[4316]),0},
+{"setAttr-TokenType","setAttr-TokenType",NID_setAttr_TokenType,4,
+ &(lvalues[4320]),0},
+{"setAttr-IssCap","issuer capabilities",NID_setAttr_IssCap,4,
+ &(lvalues[4324]),0},
+{"set-rootKeyThumb","set-rootKeyThumb",NID_set_rootKeyThumb,5,
+ &(lvalues[4328]),0},
+{"set-addPolicy","set-addPolicy",NID_set_addPolicy,5,&(lvalues[4333]),0},
+{"setAttr-Token-EMV","setAttr-Token-EMV",NID_setAttr_Token_EMV,5,
+ &(lvalues[4338]),0},
+{"setAttr-Token-B0Prime","setAttr-Token-B0Prime",
+ NID_setAttr_Token_B0Prime,5,&(lvalues[4343]),0},
+{"setAttr-IssCap-CVM","setAttr-IssCap-CVM",NID_setAttr_IssCap_CVM,5,
+ &(lvalues[4348]),0},
+{"setAttr-IssCap-T2","setAttr-IssCap-T2",NID_setAttr_IssCap_T2,5,
+ &(lvalues[4353]),0},
+{"setAttr-IssCap-Sig","setAttr-IssCap-Sig",NID_setAttr_IssCap_Sig,5,
+ &(lvalues[4358]),0},
+{"setAttr-GenCryptgrm","generate cryptogram",NID_setAttr_GenCryptgrm,
+ 6,&(lvalues[4363]),0},
+{"setAttr-T2Enc","encrypted track 2",NID_setAttr_T2Enc,6,
+ &(lvalues[4369]),0},
+{"setAttr-T2cleartxt","cleartext track 2",NID_setAttr_T2cleartxt,6,
+ &(lvalues[4375]),0},
+{"setAttr-TokICCsig","ICC or token signature",NID_setAttr_TokICCsig,6,
+ &(lvalues[4381]),0},
+{"setAttr-SecDevSig","secure device signature",NID_setAttr_SecDevSig,
+ 6,&(lvalues[4387]),0},
+{"set-brand-IATA-ATA","set-brand-IATA-ATA",NID_set_brand_IATA_ATA,4,
+ &(lvalues[4393]),0},
+{"set-brand-Diners","set-brand-Diners",NID_set_brand_Diners,4,
+ &(lvalues[4397]),0},
+{"set-brand-AmericanExpress","set-brand-AmericanExpress",
+ NID_set_brand_AmericanExpress,4,&(lvalues[4401]),0},
+{"set-brand-JCB","set-brand-JCB",NID_set_brand_JCB,4,&(lvalues[4405]),0},
+{"set-brand-Visa","set-brand-Visa",NID_set_brand_Visa,4,
+ &(lvalues[4409]),0},
+{"set-brand-MasterCard","set-brand-MasterCard",
+ NID_set_brand_MasterCard,4,&(lvalues[4413]),0},
+{"set-brand-Novus","set-brand-Novus",NID_set_brand_Novus,5,
+ &(lvalues[4417]),0},
+{"DES-CDMF","des-cdmf",NID_des_cdmf,8,&(lvalues[4422]),0},
+{"rsaOAEPEncryptionSET","rsaOAEPEncryptionSET",
+ NID_rsaOAEPEncryptionSET,9,&(lvalues[4430]),0},
+{"ITU-T","itu-t",NID_itu_t,1,&(lvalues[4439]),0},
+{"JOINT-ISO-ITU-T","joint-iso-itu-t",NID_joint_iso_itu_t,1,
+ &(lvalues[4440]),0},
+{"international-organizations","International Organizations",
+ NID_international_organizations,1,&(lvalues[4441]),0},
+{"msSmartcardLogin","Microsoft Smartcardlogin",NID_ms_smartcard_login,
+ 10,&(lvalues[4442]),0},
+{"msUPN","Microsoft Universal Principal Name",NID_ms_upn,10,
+ &(lvalues[4452]),0},
+{"AES-128-CFB1","aes-128-cfb1",NID_aes_128_cfb1,0,NULL,0},
+{"AES-192-CFB1","aes-192-cfb1",NID_aes_192_cfb1,0,NULL,0},
+{"AES-256-CFB1","aes-256-cfb1",NID_aes_256_cfb1,0,NULL,0},
+{"AES-128-CFB8","aes-128-cfb8",NID_aes_128_cfb8,0,NULL,0},
+{"AES-192-CFB8","aes-192-cfb8",NID_aes_192_cfb8,0,NULL,0},
+{"AES-256-CFB8","aes-256-cfb8",NID_aes_256_cfb8,0,NULL,0},
+{"DES-CFB1","des-cfb1",NID_des_cfb1,0,NULL,0},
+{"DES-CFB8","des-cfb8",NID_des_cfb8,0,NULL,0},
+{"DES-EDE3-CFB1","des-ede3-cfb1",NID_des_ede3_cfb1,0,NULL,0},
+{"DES-EDE3-CFB8","des-ede3-cfb8",NID_des_ede3_cfb8,0,NULL,0},
+{"street","streetAddress",NID_streetAddress,3,&(lvalues[4462]),0},
+{"postalCode","postalCode",NID_postalCode,3,&(lvalues[4465]),0},
+{"id-ppl","id-ppl",NID_id_ppl,7,&(lvalues[4468]),0},
+{"proxyCertInfo","Proxy Certificate Information",NID_proxyCertInfo,8,
+ &(lvalues[4475]),0},
+{"id-ppl-anyLanguage","Any language",NID_id_ppl_anyLanguage,8,
+ &(lvalues[4483]),0},
+{"id-ppl-inheritAll","Inherit all",NID_id_ppl_inheritAll,8,
+ &(lvalues[4491]),0},
+{"nameConstraints","X509v3 Name Constraints",NID_name_constraints,3,
+ &(lvalues[4499]),0},
+{"id-ppl-independent","Independent",NID_Independent,8,&(lvalues[4502]),0},
+{"RSA-SHA256","sha256WithRSAEncryption",NID_sha256WithRSAEncryption,9,
+ &(lvalues[4510]),0},
+{"RSA-SHA384","sha384WithRSAEncryption",NID_sha384WithRSAEncryption,9,
+ &(lvalues[4519]),0},
+{"RSA-SHA512","sha512WithRSAEncryption",NID_sha512WithRSAEncryption,9,
+ &(lvalues[4528]),0},
+{"RSA-SHA224","sha224WithRSAEncryption",NID_sha224WithRSAEncryption,9,
+ &(lvalues[4537]),0},
+{"SHA256","sha256",NID_sha256,9,&(lvalues[4546]),0},
+{"SHA384","sha384",NID_sha384,9,&(lvalues[4555]),0},
+{"SHA512","sha512",NID_sha512,9,&(lvalues[4564]),0},
+{"SHA224","sha224",NID_sha224,9,&(lvalues[4573]),0},
+{"identified-organization","identified-organization",
+ NID_identified_organization,1,&(lvalues[4582]),0},
+{"certicom-arc","certicom-arc",NID_certicom_arc,3,&(lvalues[4583]),0},
+{"wap","wap",NID_wap,2,&(lvalues[4586]),0},
+{"wap-wsg","wap-wsg",NID_wap_wsg,3,&(lvalues[4588]),0},
+{"id-characteristic-two-basis","id-characteristic-two-basis",
+ NID_X9_62_id_characteristic_two_basis,8,&(lvalues[4591]),0},
+{"onBasis","onBasis",NID_X9_62_onBasis,9,&(lvalues[4599]),0},
+{"tpBasis","tpBasis",NID_X9_62_tpBasis,9,&(lvalues[4608]),0},
+{"ppBasis","ppBasis",NID_X9_62_ppBasis,9,&(lvalues[4617]),0},
+{"c2pnb163v1","c2pnb163v1",NID_X9_62_c2pnb163v1,8,&(lvalues[4626]),0},
+{"c2pnb163v2","c2pnb163v2",NID_X9_62_c2pnb163v2,8,&(lvalues[4634]),0},
+{"c2pnb163v3","c2pnb163v3",NID_X9_62_c2pnb163v3,8,&(lvalues[4642]),0},
+{"c2pnb176v1","c2pnb176v1",NID_X9_62_c2pnb176v1,8,&(lvalues[4650]),0},
+{"c2tnb191v1","c2tnb191v1",NID_X9_62_c2tnb191v1,8,&(lvalues[4658]),0},
+{"c2tnb191v2","c2tnb191v2",NID_X9_62_c2tnb191v2,8,&(lvalues[4666]),0},
+{"c2tnb191v3","c2tnb191v3",NID_X9_62_c2tnb191v3,8,&(lvalues[4674]),0},
+{"c2onb191v4","c2onb191v4",NID_X9_62_c2onb191v4,8,&(lvalues[4682]),0},
+{"c2onb191v5","c2onb191v5",NID_X9_62_c2onb191v5,8,&(lvalues[4690]),0},
+{"c2pnb208w1","c2pnb208w1",NID_X9_62_c2pnb208w1,8,&(lvalues[4698]),0},
+{"c2tnb239v1","c2tnb239v1",NID_X9_62_c2tnb239v1,8,&(lvalues[4706]),0},
+{"c2tnb239v2","c2tnb239v2",NID_X9_62_c2tnb239v2,8,&(lvalues[4714]),0},
+{"c2tnb239v3","c2tnb239v3",NID_X9_62_c2tnb239v3,8,&(lvalues[4722]),0},
+{"c2onb239v4","c2onb239v4",NID_X9_62_c2onb239v4,8,&(lvalues[4730]),0},
+{"c2onb239v5","c2onb239v5",NID_X9_62_c2onb239v5,8,&(lvalues[4738]),0},
+{"c2pnb272w1","c2pnb272w1",NID_X9_62_c2pnb272w1,8,&(lvalues[4746]),0},
+{"c2pnb304w1","c2pnb304w1",NID_X9_62_c2pnb304w1,8,&(lvalues[4754]),0},
+{"c2tnb359v1","c2tnb359v1",NID_X9_62_c2tnb359v1,8,&(lvalues[4762]),0},
+{"c2pnb368w1","c2pnb368w1",NID_X9_62_c2pnb368w1,8,&(lvalues[4770]),0},
+{"c2tnb431r1","c2tnb431r1",NID_X9_62_c2tnb431r1,8,&(lvalues[4778]),0},
+{"secp112r1","secp112r1",NID_secp112r1,5,&(lvalues[4786]),0},
+{"secp112r2","secp112r2",NID_secp112r2,5,&(lvalues[4791]),0},
+{"secp128r1","secp128r1",NID_secp128r1,5,&(lvalues[4796]),0},
+{"secp128r2","secp128r2",NID_secp128r2,5,&(lvalues[4801]),0},
+{"secp160k1","secp160k1",NID_secp160k1,5,&(lvalues[4806]),0},
+{"secp160r1","secp160r1",NID_secp160r1,5,&(lvalues[4811]),0},
+{"secp160r2","secp160r2",NID_secp160r2,5,&(lvalues[4816]),0},
+{"secp192k1","secp192k1",NID_secp192k1,5,&(lvalues[4821]),0},
+{"secp224k1","secp224k1",NID_secp224k1,5,&(lvalues[4826]),0},
+{"secp224r1","secp224r1",NID_secp224r1,5,&(lvalues[4831]),0},
+{"secp256k1","secp256k1",NID_secp256k1,5,&(lvalues[4836]),0},
+{"secp384r1","secp384r1",NID_secp384r1,5,&(lvalues[4841]),0},
+{"secp521r1","secp521r1",NID_secp521r1,5,&(lvalues[4846]),0},
+{"sect113r1","sect113r1",NID_sect113r1,5,&(lvalues[4851]),0},
+{"sect113r2","sect113r2",NID_sect113r2,5,&(lvalues[4856]),0},
+{"sect131r1","sect131r1",NID_sect131r1,5,&(lvalues[4861]),0},
+{"sect131r2","sect131r2",NID_sect131r2,5,&(lvalues[4866]),0},
+{"sect163k1","sect163k1",NID_sect163k1,5,&(lvalues[4871]),0},
+{"sect163r1","sect163r1",NID_sect163r1,5,&(lvalues[4876]),0},
+{"sect163r2","sect163r2",NID_sect163r2,5,&(lvalues[4881]),0},
+{"sect193r1","sect193r1",NID_sect193r1,5,&(lvalues[4886]),0},
+{"sect193r2","sect193r2",NID_sect193r2,5,&(lvalues[4891]),0},
+{"sect233k1","sect233k1",NID_sect233k1,5,&(lvalues[4896]),0},
+{"sect233r1","sect233r1",NID_sect233r1,5,&(lvalues[4901]),0},
+{"sect239k1","sect239k1",NID_sect239k1,5,&(lvalues[4906]),0},
+{"sect283k1","sect283k1",NID_sect283k1,5,&(lvalues[4911]),0},
+{"sect283r1","sect283r1",NID_sect283r1,5,&(lvalues[4916]),0},
+{"sect409k1","sect409k1",NID_sect409k1,5,&(lvalues[4921]),0},
+{"sect409r1","sect409r1",NID_sect409r1,5,&(lvalues[4926]),0},
+{"sect571k1","sect571k1",NID_sect571k1,5,&(lvalues[4931]),0},
+{"sect571r1","sect571r1",NID_sect571r1,5,&(lvalues[4936]),0},
+{"wap-wsg-idm-ecid-wtls1","wap-wsg-idm-ecid-wtls1",
+ NID_wap_wsg_idm_ecid_wtls1,5,&(lvalues[4941]),0},
+{"wap-wsg-idm-ecid-wtls3","wap-wsg-idm-ecid-wtls3",
+ NID_wap_wsg_idm_ecid_wtls3,5,&(lvalues[4946]),0},
+{"wap-wsg-idm-ecid-wtls4","wap-wsg-idm-ecid-wtls4",
+ NID_wap_wsg_idm_ecid_wtls4,5,&(lvalues[4951]),0},
+{"wap-wsg-idm-ecid-wtls5","wap-wsg-idm-ecid-wtls5",
+ NID_wap_wsg_idm_ecid_wtls5,5,&(lvalues[4956]),0},
+{"wap-wsg-idm-ecid-wtls6","wap-wsg-idm-ecid-wtls6",
+ NID_wap_wsg_idm_ecid_wtls6,5,&(lvalues[4961]),0},
+{"wap-wsg-idm-ecid-wtls7","wap-wsg-idm-ecid-wtls7",
+ NID_wap_wsg_idm_ecid_wtls7,5,&(lvalues[4966]),0},
+{"wap-wsg-idm-ecid-wtls8","wap-wsg-idm-ecid-wtls8",
+ NID_wap_wsg_idm_ecid_wtls8,5,&(lvalues[4971]),0},
+{"wap-wsg-idm-ecid-wtls9","wap-wsg-idm-ecid-wtls9",
+ NID_wap_wsg_idm_ecid_wtls9,5,&(lvalues[4976]),0},
+{"wap-wsg-idm-ecid-wtls10","wap-wsg-idm-ecid-wtls10",
+ NID_wap_wsg_idm_ecid_wtls10,5,&(lvalues[4981]),0},
+{"wap-wsg-idm-ecid-wtls11","wap-wsg-idm-ecid-wtls11",
+ NID_wap_wsg_idm_ecid_wtls11,5,&(lvalues[4986]),0},
+{"wap-wsg-idm-ecid-wtls12","wap-wsg-idm-ecid-wtls12",
+ NID_wap_wsg_idm_ecid_wtls12,5,&(lvalues[4991]),0},
+{"anyPolicy","X509v3 Any Policy",NID_any_policy,4,&(lvalues[4996]),0},
+{"policyMappings","X509v3 Policy Mappings",NID_policy_mappings,3,
+ &(lvalues[5000]),0},
+{"inhibitAnyPolicy","X509v3 Inhibit Any Policy",
+ NID_inhibit_any_policy,3,&(lvalues[5003]),0},
+{"Oakley-EC2N-3","ipsec3",NID_ipsec3,0,NULL,0},
+{"Oakley-EC2N-4","ipsec4",NID_ipsec4,0,NULL,0},
+{"CAMELLIA-128-CBC","camellia-128-cbc",NID_camellia_128_cbc,11,
+ &(lvalues[5006]),0},
+{"CAMELLIA-192-CBC","camellia-192-cbc",NID_camellia_192_cbc,11,
+ &(lvalues[5017]),0},
+{"CAMELLIA-256-CBC","camellia-256-cbc",NID_camellia_256_cbc,11,
+ &(lvalues[5028]),0},
+{"CAMELLIA-128-ECB","camellia-128-ecb",NID_camellia_128_ecb,8,
+ &(lvalues[5039]),0},
+{"CAMELLIA-192-ECB","camellia-192-ecb",NID_camellia_192_ecb,8,
+ &(lvalues[5047]),0},
+{"CAMELLIA-256-ECB","camellia-256-ecb",NID_camellia_256_ecb,8,
+ &(lvalues[5055]),0},
+{"CAMELLIA-128-CFB","camellia-128-cfb",NID_camellia_128_cfb128,8,
+ &(lvalues[5063]),0},
+{"CAMELLIA-192-CFB","camellia-192-cfb",NID_camellia_192_cfb128,8,
+ &(lvalues[5071]),0},
+{"CAMELLIA-256-CFB","camellia-256-cfb",NID_camellia_256_cfb128,8,
+ &(lvalues[5079]),0},
+{"CAMELLIA-128-CFB1","camellia-128-cfb1",NID_camellia_128_cfb1,0,NULL,0},
+{"CAMELLIA-192-CFB1","camellia-192-cfb1",NID_camellia_192_cfb1,0,NULL,0},
+{"CAMELLIA-256-CFB1","camellia-256-cfb1",NID_camellia_256_cfb1,0,NULL,0},
+{"CAMELLIA-128-CFB8","camellia-128-cfb8",NID_camellia_128_cfb8,0,NULL,0},
+{"CAMELLIA-192-CFB8","camellia-192-cfb8",NID_camellia_192_cfb8,0,NULL,0},
+{"CAMELLIA-256-CFB8","camellia-256-cfb8",NID_camellia_256_cfb8,0,NULL,0},
+{"CAMELLIA-128-OFB","camellia-128-ofb",NID_camellia_128_ofb128,8,
+ &(lvalues[5087]),0},
+{"CAMELLIA-192-OFB","camellia-192-ofb",NID_camellia_192_ofb128,8,
+ &(lvalues[5095]),0},
+{"CAMELLIA-256-OFB","camellia-256-ofb",NID_camellia_256_ofb128,8,
+ &(lvalues[5103]),0},
+{"subjectDirectoryAttributes","X509v3 Subject Directory Attributes",
+ NID_subject_directory_attributes,3,&(lvalues[5111]),0},
+{"issuingDistributionPoint","X509v3 Issuing Distrubution Point",
+ NID_issuing_distribution_point,3,&(lvalues[5114]),0},
+{"certificateIssuer","X509v3 Certificate Issuer",
+ NID_certificate_issuer,3,&(lvalues[5117]),0},
+{NULL,NULL,NID_undef,0,NULL,0},
+{"KISA","kisa",NID_kisa,6,&(lvalues[5120]),0},
+{NULL,NULL,NID_undef,0,NULL,0},
+{NULL,NULL,NID_undef,0,NULL,0},
+{"SEED-ECB","seed-ecb",NID_seed_ecb,8,&(lvalues[5126]),0},
+{"SEED-CBC","seed-cbc",NID_seed_cbc,8,&(lvalues[5134]),0},
+{"SEED-OFB","seed-ofb",NID_seed_ofb128,8,&(lvalues[5142]),0},
+{"SEED-CFB","seed-cfb",NID_seed_cfb128,8,&(lvalues[5150]),0},
+{"HMAC-MD5","hmac-md5",NID_hmac_md5,8,&(lvalues[5158]),0},
+{"HMAC-SHA1","hmac-sha1",NID_hmac_sha1,8,&(lvalues[5166]),0},
+{"id-PasswordBasedMAC","password based MAC",NID_id_PasswordBasedMAC,9,
+ &(lvalues[5174]),0},
+{"id-DHBasedMac","Diffie-Hellman based MAC",NID_id_DHBasedMac,9,
+ &(lvalues[5183]),0},
+{"id-it-suppLangTags","id-it-suppLangTags",NID_id_it_suppLangTags,8,
+ &(lvalues[5192]),0},
+{"caRepository","CA Repository",NID_caRepository,8,&(lvalues[5200]),0},
+{"id-smime-ct-compressedData","id-smime-ct-compressedData",
+ NID_id_smime_ct_compressedData,11,&(lvalues[5208]),0},
+{"id-ct-asciiTextWithCRLF","id-ct-asciiTextWithCRLF",
+ NID_id_ct_asciiTextWithCRLF,11,&(lvalues[5219]),0},
+{"id-aes128-wrap","id-aes128-wrap",NID_id_aes128_wrap,9,
+ &(lvalues[5230]),0},
+{"id-aes192-wrap","id-aes192-wrap",NID_id_aes192_wrap,9,
+ &(lvalues[5239]),0},
+{"id-aes256-wrap","id-aes256-wrap",NID_id_aes256_wrap,9,
+ &(lvalues[5248]),0},
+{"ecdsa-with-Recommended","ecdsa-with-Recommended",
+ NID_ecdsa_with_Recommended,7,&(lvalues[5257]),0},
+{"ecdsa-with-Specified","ecdsa-with-Specified",
+ NID_ecdsa_with_Specified,7,&(lvalues[5264]),0},
+{"ecdsa-with-SHA224","ecdsa-with-SHA224",NID_ecdsa_with_SHA224,8,
+ &(lvalues[5271]),0},
+{"ecdsa-with-SHA256","ecdsa-with-SHA256",NID_ecdsa_with_SHA256,8,
+ &(lvalues[5279]),0},
+{"ecdsa-with-SHA384","ecdsa-with-SHA384",NID_ecdsa_with_SHA384,8,
+ &(lvalues[5287]),0},
+{"ecdsa-with-SHA512","ecdsa-with-SHA512",NID_ecdsa_with_SHA512,8,
+ &(lvalues[5295]),0},
+{"hmacWithMD5","hmacWithMD5",NID_hmacWithMD5,8,&(lvalues[5303]),0},
+{"hmacWithSHA224","hmacWithSHA224",NID_hmacWithSHA224,8,
+ &(lvalues[5311]),0},
+{"hmacWithSHA256","hmacWithSHA256",NID_hmacWithSHA256,8,
+ &(lvalues[5319]),0},
+{"hmacWithSHA384","hmacWithSHA384",NID_hmacWithSHA384,8,
+ &(lvalues[5327]),0},
+{"hmacWithSHA512","hmacWithSHA512",NID_hmacWithSHA512,8,
+ &(lvalues[5335]),0},
+{"dsa_with_SHA224","dsa_with_SHA224",NID_dsa_with_SHA224,9,
+ &(lvalues[5343]),0},
+{"dsa_with_SHA256","dsa_with_SHA256",NID_dsa_with_SHA256,9,
+ &(lvalues[5352]),0},
+{"whirlpool","whirlpool",NID_whirlpool,6,&(lvalues[5361]),0},
+{"cryptopro","cryptopro",NID_cryptopro,5,&(lvalues[5367]),0},
+{"cryptocom","cryptocom",NID_cryptocom,5,&(lvalues[5372]),0},
+{"id-GostR3411-94-with-GostR3410-2001",
+ "GOST R 34.11-94 with GOST R 34.10-2001",
+ NID_id_GostR3411_94_with_GostR3410_2001,6,&(lvalues[5377]),0},
+{"id-GostR3411-94-with-GostR3410-94",
+ "GOST R 34.11-94 with GOST R 34.10-94",
+ NID_id_GostR3411_94_with_GostR3410_94,6,&(lvalues[5383]),0},
+{"md_gost94","GOST R 34.11-94",NID_id_GostR3411_94,6,&(lvalues[5389]),0},
+{"id-HMACGostR3411-94","HMAC GOST 34.11-94",NID_id_HMACGostR3411_94,6,
+ &(lvalues[5395]),0},
+{"gost2001","GOST R 34.10-2001",NID_id_GostR3410_2001,6,
+ &(lvalues[5401]),0},
+{"gost94","GOST R 34.10-94",NID_id_GostR3410_94,6,&(lvalues[5407]),0},
+{"gost89","GOST 28147-89",NID_id_Gost28147_89,6,&(lvalues[5413]),0},
+{"gost89-cnt","gost89-cnt",NID_gost89_cnt,0,NULL,0},
+{"gost-mac","GOST 28147-89 MAC",NID_id_Gost28147_89_MAC,6,
+ &(lvalues[5419]),0},
+{"prf-gostr3411-94","GOST R 34.11-94 PRF",NID_id_GostR3411_94_prf,6,
+ &(lvalues[5425]),0},
+{"id-GostR3410-2001DH","GOST R 34.10-2001 DH",NID_id_GostR3410_2001DH,
+ 6,&(lvalues[5431]),0},
+{"id-GostR3410-94DH","GOST R 34.10-94 DH",NID_id_GostR3410_94DH,6,
+ &(lvalues[5437]),0},
+{"id-Gost28147-89-CryptoPro-KeyMeshing",
+ "id-Gost28147-89-CryptoPro-KeyMeshing",
+ NID_id_Gost28147_89_CryptoPro_KeyMeshing,7,&(lvalues[5443]),0},
+{"id-Gost28147-89-None-KeyMeshing","id-Gost28147-89-None-KeyMeshing",
+ NID_id_Gost28147_89_None_KeyMeshing,7,&(lvalues[5450]),0},
+{"id-GostR3411-94-TestParamSet","id-GostR3411-94-TestParamSet",
+ NID_id_GostR3411_94_TestParamSet,7,&(lvalues[5457]),0},
+{"id-GostR3411-94-CryptoProParamSet",
+ "id-GostR3411-94-CryptoProParamSet",
+ NID_id_GostR3411_94_CryptoProParamSet,7,&(lvalues[5464]),0},
+{"id-Gost28147-89-TestParamSet","id-Gost28147-89-TestParamSet",
+ NID_id_Gost28147_89_TestParamSet,7,&(lvalues[5471]),0},
+{"id-Gost28147-89-CryptoPro-A-ParamSet",
+ "id-Gost28147-89-CryptoPro-A-ParamSet",
+ NID_id_Gost28147_89_CryptoPro_A_ParamSet,7,&(lvalues[5478]),0},
+{"id-Gost28147-89-CryptoPro-B-ParamSet",
+ "id-Gost28147-89-CryptoPro-B-ParamSet",
+ NID_id_Gost28147_89_CryptoPro_B_ParamSet,7,&(lvalues[5485]),0},
+{"id-Gost28147-89-CryptoPro-C-ParamSet",
+ "id-Gost28147-89-CryptoPro-C-ParamSet",
+ NID_id_Gost28147_89_CryptoPro_C_ParamSet,7,&(lvalues[5492]),0},
+{"id-Gost28147-89-CryptoPro-D-ParamSet",
+ "id-Gost28147-89-CryptoPro-D-ParamSet",
+ NID_id_Gost28147_89_CryptoPro_D_ParamSet,7,&(lvalues[5499]),0},
+{"id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet",
+ "id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet",
+ NID_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet,7,&(lvalues[5506]),
+ 0},
+{"id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet",
+ "id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet",
+ NID_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet,7,&(lvalues[5513]),
+ 0},
+{"id-Gost28147-89-CryptoPro-RIC-1-ParamSet",
+ "id-Gost28147-89-CryptoPro-RIC-1-ParamSet",
+ NID_id_Gost28147_89_CryptoPro_RIC_1_ParamSet,7,&(lvalues[5520]),0},
+{"id-GostR3410-94-TestParamSet","id-GostR3410-94-TestParamSet",
+ NID_id_GostR3410_94_TestParamSet,7,&(lvalues[5527]),0},
+{"id-GostR3410-94-CryptoPro-A-ParamSet",
+ "id-GostR3410-94-CryptoPro-A-ParamSet",
+ NID_id_GostR3410_94_CryptoPro_A_ParamSet,7,&(lvalues[5534]),0},
+{"id-GostR3410-94-CryptoPro-B-ParamSet",
+ "id-GostR3410-94-CryptoPro-B-ParamSet",
+ NID_id_GostR3410_94_CryptoPro_B_ParamSet,7,&(lvalues[5541]),0},
+{"id-GostR3410-94-CryptoPro-C-ParamSet",
+ "id-GostR3410-94-CryptoPro-C-ParamSet",
+ NID_id_GostR3410_94_CryptoPro_C_ParamSet,7,&(lvalues[5548]),0},
+{"id-GostR3410-94-CryptoPro-D-ParamSet",
+ "id-GostR3410-94-CryptoPro-D-ParamSet",
+ NID_id_GostR3410_94_CryptoPro_D_ParamSet,7,&(lvalues[5555]),0},
+{"id-GostR3410-94-CryptoPro-XchA-ParamSet",
+ "id-GostR3410-94-CryptoPro-XchA-ParamSet",
+ NID_id_GostR3410_94_CryptoPro_XchA_ParamSet,7,&(lvalues[5562]),0},
+{"id-GostR3410-94-CryptoPro-XchB-ParamSet",
+ "id-GostR3410-94-CryptoPro-XchB-ParamSet",
+ NID_id_GostR3410_94_CryptoPro_XchB_ParamSet,7,&(lvalues[5569]),0},
+{"id-GostR3410-94-CryptoPro-XchC-ParamSet",
+ "id-GostR3410-94-CryptoPro-XchC-ParamSet",
+ NID_id_GostR3410_94_CryptoPro_XchC_ParamSet,7,&(lvalues[5576]),0},
+{"id-GostR3410-2001-TestParamSet","id-GostR3410-2001-TestParamSet",
+ NID_id_GostR3410_2001_TestParamSet,7,&(lvalues[5583]),0},
+{"id-GostR3410-2001-CryptoPro-A-ParamSet",
+ "id-GostR3410-2001-CryptoPro-A-ParamSet",
+ NID_id_GostR3410_2001_CryptoPro_A_ParamSet,7,&(lvalues[5590]),0},
+{"id-GostR3410-2001-CryptoPro-B-ParamSet",
+ "id-GostR3410-2001-CryptoPro-B-ParamSet",
+ NID_id_GostR3410_2001_CryptoPro_B_ParamSet,7,&(lvalues[5597]),0},
+{"id-GostR3410-2001-CryptoPro-C-ParamSet",
+ "id-GostR3410-2001-CryptoPro-C-ParamSet",
+ NID_id_GostR3410_2001_CryptoPro_C_ParamSet,7,&(lvalues[5604]),0},
+{"id-GostR3410-2001-CryptoPro-XchA-ParamSet",
+ "id-GostR3410-2001-CryptoPro-XchA-ParamSet",
+ NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet,7,&(lvalues[5611]),0},
+
+{"id-GostR3410-2001-CryptoPro-XchB-ParamSet",
+ "id-GostR3410-2001-CryptoPro-XchB-ParamSet",
+ NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet,7,&(lvalues[5618]),0},
+
+{"id-GostR3410-94-a","id-GostR3410-94-a",NID_id_GostR3410_94_a,7,
+ &(lvalues[5625]),0},
+{"id-GostR3410-94-aBis","id-GostR3410-94-aBis",
+ NID_id_GostR3410_94_aBis,7,&(lvalues[5632]),0},
+{"id-GostR3410-94-b","id-GostR3410-94-b",NID_id_GostR3410_94_b,7,
+ &(lvalues[5639]),0},
+{"id-GostR3410-94-bBis","id-GostR3410-94-bBis",
+ NID_id_GostR3410_94_bBis,7,&(lvalues[5646]),0},
+{"id-Gost28147-89-cc","GOST 28147-89 Cryptocom ParamSet",
+ NID_id_Gost28147_89_cc,8,&(lvalues[5653]),0},
+{"gost94cc","GOST 34.10-94 Cryptocom",NID_id_GostR3410_94_cc,8,
+ &(lvalues[5661]),0},
+{"gost2001cc","GOST 34.10-2001 Cryptocom",NID_id_GostR3410_2001_cc,8,
+ &(lvalues[5669]),0},
+{"id-GostR3411-94-with-GostR3410-94-cc",
+ "GOST R 34.11-94 with GOST R 34.10-94 Cryptocom",
+ NID_id_GostR3411_94_with_GostR3410_94_cc,8,&(lvalues[5677]),0},
+{"id-GostR3411-94-with-GostR3410-2001-cc",
+ "GOST R 34.11-94 with GOST R 34.10-2001 Cryptocom",
+ NID_id_GostR3411_94_with_GostR3410_2001_cc,8,&(lvalues[5685]),0},
+{"id-GostR3410-2001-ParamSet-cc",
+ "GOST R 3410-2001 Parameter Set Cryptocom",
+ NID_id_GostR3410_2001_ParamSet_cc,8,&(lvalues[5693]),0},
+{"HMAC","hmac",NID_hmac,0,NULL,0},
+{"LocalKeySet","Microsoft Local Key set",NID_LocalKeySet,9,
+ &(lvalues[5701]),0},
+{"freshestCRL","X509v3 Freshest CRL",NID_freshest_crl,3,
+ &(lvalues[5710]),0},
+{"id-on-permanentIdentifier","Permanent Identifier",
+ NID_id_on_permanentIdentifier,8,&(lvalues[5713]),0},
+{"searchGuide","searchGuide",NID_searchGuide,3,&(lvalues[5721]),0},
+{"businessCategory","businessCategory",NID_businessCategory,3,
+ &(lvalues[5724]),0},
+{"postalAddress","postalAddress",NID_postalAddress,3,&(lvalues[5727]),0},
+{"postOfficeBox","postOfficeBox",NID_postOfficeBox,3,&(lvalues[5730]),0},
+{"physicalDeliveryOfficeName","physicalDeliveryOfficeName",
+ NID_physicalDeliveryOfficeName,3,&(lvalues[5733]),0},
+{"telephoneNumber","telephoneNumber",NID_telephoneNumber,3,
+ &(lvalues[5736]),0},
+{"telexNumber","telexNumber",NID_telexNumber,3,&(lvalues[5739]),0},
+{"teletexTerminalIdentifier","teletexTerminalIdentifier",
+ NID_teletexTerminalIdentifier,3,&(lvalues[5742]),0},
+{"facsimileTelephoneNumber","facsimileTelephoneNumber",
+ NID_facsimileTelephoneNumber,3,&(lvalues[5745]),0},
+{"x121Address","x121Address",NID_x121Address,3,&(lvalues[5748]),0},
+{"internationaliSDNNumber","internationaliSDNNumber",
+ NID_internationaliSDNNumber,3,&(lvalues[5751]),0},
+{"registeredAddress","registeredAddress",NID_registeredAddress,3,
+ &(lvalues[5754]),0},
+{"destinationIndicator","destinationIndicator",
+ NID_destinationIndicator,3,&(lvalues[5757]),0},
+{"preferredDeliveryMethod","preferredDeliveryMethod",
+ NID_preferredDeliveryMethod,3,&(lvalues[5760]),0},
+{"presentationAddress","presentationAddress",NID_presentationAddress,
+ 3,&(lvalues[5763]),0},
+{"supportedApplicationContext","supportedApplicationContext",
+ NID_supportedApplicationContext,3,&(lvalues[5766]),0},
+{"member","member",NID_member,3,&(lvalues[5769]),0},
+{"owner","owner",NID_owner,3,&(lvalues[5772]),0},
+{"roleOccupant","roleOccupant",NID_roleOccupant,3,&(lvalues[5775]),0},
+{"seeAlso","seeAlso",NID_seeAlso,3,&(lvalues[5778]),0},
+{"userPassword","userPassword",NID_userPassword,3,&(lvalues[5781]),0},
+{"userCertificate","userCertificate",NID_userCertificate,3,
+ &(lvalues[5784]),0},
+{"cACertificate","cACertificate",NID_cACertificate,3,&(lvalues[5787]),0},
+{"authorityRevocationList","authorityRevocationList",
+ NID_authorityRevocationList,3,&(lvalues[5790]),0},
+{"certificateRevocationList","certificateRevocationList",
+ NID_certificateRevocationList,3,&(lvalues[5793]),0},
+{"crossCertificatePair","crossCertificatePair",
+ NID_crossCertificatePair,3,&(lvalues[5796]),0},
+{"enhancedSearchGuide","enhancedSearchGuide",NID_enhancedSearchGuide,
+ 3,&(lvalues[5799]),0},
+{"protocolInformation","protocolInformation",NID_protocolInformation,
+ 3,&(lvalues[5802]),0},
+{"distinguishedName","distinguishedName",NID_distinguishedName,3,
+ &(lvalues[5805]),0},
+{"uniqueMember","uniqueMember",NID_uniqueMember,3,&(lvalues[5808]),0},
+{"houseIdentifier","houseIdentifier",NID_houseIdentifier,3,
+ &(lvalues[5811]),0},
+{"supportedAlgorithms","supportedAlgorithms",NID_supportedAlgorithms,
+ 3,&(lvalues[5814]),0},
+{"deltaRevocationList","deltaRevocationList",NID_deltaRevocationList,
+ 3,&(lvalues[5817]),0},
+{"dmdName","dmdName",NID_dmdName,3,&(lvalues[5820]),0},
+{"id-alg-PWRI-KEK","id-alg-PWRI-KEK",NID_id_alg_PWRI_KEK,11,
+ &(lvalues[5823]),0},
+{"CMAC","cmac",NID_cmac,0,NULL,0},
+{"id-aes128-GCM","aes-128-gcm",NID_aes_128_gcm,9,&(lvalues[5834]),0},
+{"id-aes128-CCM","aes-128-ccm",NID_aes_128_ccm,9,&(lvalues[5843]),0},
+{"id-aes128-wrap-pad","id-aes128-wrap-pad",NID_id_aes128_wrap_pad,9,
+ &(lvalues[5852]),0},
+{"id-aes192-GCM","aes-192-gcm",NID_aes_192_gcm,9,&(lvalues[5861]),0},
+{"id-aes192-CCM","aes-192-ccm",NID_aes_192_ccm,9,&(lvalues[5870]),0},
+{"id-aes192-wrap-pad","id-aes192-wrap-pad",NID_id_aes192_wrap_pad,9,
+ &(lvalues[5879]),0},
+{"id-aes256-GCM","aes-256-gcm",NID_aes_256_gcm,9,&(lvalues[5888]),0},
+{"id-aes256-CCM","aes-256-ccm",NID_aes_256_ccm,9,&(lvalues[5897]),0},
+{"id-aes256-wrap-pad","id-aes256-wrap-pad",NID_id_aes256_wrap_pad,9,
+ &(lvalues[5906]),0},
+{"AES-128-CTR","aes-128-ctr",NID_aes_128_ctr,0,NULL,0},
+{"AES-192-CTR","aes-192-ctr",NID_aes_192_ctr,0,NULL,0},
+{"AES-256-CTR","aes-256-ctr",NID_aes_256_ctr,0,NULL,0},
+{"id-camellia128-wrap","id-camellia128-wrap",NID_id_camellia128_wrap,
+ 11,&(lvalues[5915]),0},
+{"id-camellia192-wrap","id-camellia192-wrap",NID_id_camellia192_wrap,
+ 11,&(lvalues[5926]),0},
+{"id-camellia256-wrap","id-camellia256-wrap",NID_id_camellia256_wrap,
+ 11,&(lvalues[5937]),0},
+{"anyExtendedKeyUsage","Any Extended Key Usage",
+ NID_anyExtendedKeyUsage,4,&(lvalues[5948]),0},
+{"MGF1","mgf1",NID_mgf1,9,&(lvalues[5952]),0},
+{"RSASSA-PSS","rsassaPss",NID_rsassaPss,9,&(lvalues[5961]),0},
+{"AES-128-XTS","aes-128-xts",NID_aes_128_xts,0,NULL,0},
+{"AES-256-XTS","aes-256-xts",NID_aes_256_xts,0,NULL,0},
+{"RC4-HMAC-MD5","rc4-hmac-md5",NID_rc4_hmac_md5,0,NULL,0},
+{"AES-128-CBC-HMAC-SHA1","aes-128-cbc-hmac-sha1",
+ NID_aes_128_cbc_hmac_sha1,0,NULL,0},
+{"AES-192-CBC-HMAC-SHA1","aes-192-cbc-hmac-sha1",
+ NID_aes_192_cbc_hmac_sha1,0,NULL,0},
+{"AES-256-CBC-HMAC-SHA1","aes-256-cbc-hmac-sha1",
+ NID_aes_256_cbc_hmac_sha1,0,NULL,0},
+{"RSAES-OAEP","rsaesOaep",NID_rsaesOaep,9,&(lvalues[5970]),0},
+{"dhpublicnumber","X9.42 DH",NID_dhpublicnumber,7,&(lvalues[5979]),0},
+{"brainpoolP160r1","brainpoolP160r1",NID_brainpoolP160r1,9,
+ &(lvalues[5986]),0},
+{"brainpoolP160t1","brainpoolP160t1",NID_brainpoolP160t1,9,
+ &(lvalues[5995]),0},
+{"brainpoolP192r1","brainpoolP192r1",NID_brainpoolP192r1,9,
+ &(lvalues[6004]),0},
+{"brainpoolP192t1","brainpoolP192t1",NID_brainpoolP192t1,9,
+ &(lvalues[6013]),0},
+{"brainpoolP224r1","brainpoolP224r1",NID_brainpoolP224r1,9,
+ &(lvalues[6022]),0},
+{"brainpoolP224t1","brainpoolP224t1",NID_brainpoolP224t1,9,
+ &(lvalues[6031]),0},
+{"brainpoolP256r1","brainpoolP256r1",NID_brainpoolP256r1,9,
+ &(lvalues[6040]),0},
+{"brainpoolP256t1","brainpoolP256t1",NID_brainpoolP256t1,9,
+ &(lvalues[6049]),0},
+{"brainpoolP320r1","brainpoolP320r1",NID_brainpoolP320r1,9,
+ &(lvalues[6058]),0},
+{"brainpoolP320t1","brainpoolP320t1",NID_brainpoolP320t1,9,
+ &(lvalues[6067]),0},
+{"brainpoolP384r1","brainpoolP384r1",NID_brainpoolP384r1,9,
+ &(lvalues[6076]),0},
+{"brainpoolP384t1","brainpoolP384t1",NID_brainpoolP384t1,9,
+ &(lvalues[6085]),0},
+{"brainpoolP512r1","brainpoolP512r1",NID_brainpoolP512r1,9,
+ &(lvalues[6094]),0},
+{"brainpoolP512t1","brainpoolP512t1",NID_brainpoolP512t1,9,
+ &(lvalues[6103]),0},
+{"PSPECIFIED","pSpecified",NID_pSpecified,9,&(lvalues[6112]),0},
+{NULL,NULL,NID_undef,0,NULL,0},
+{NULL,NULL,NID_undef,0,NULL,0},
+{NULL,NULL,NID_undef,0,NULL,0},
+{"dhSinglePass-stdDH-sha1kdf-scheme",
+ "dhSinglePass-stdDH-sha1kdf-scheme",
+ NID_dhSinglePass_stdDH_sha1kdf_scheme,9,&(lvalues[6121]),0},
+{"dhSinglePass-stdDH-sha224kdf-scheme",
+ "dhSinglePass-stdDH-sha224kdf-scheme",
+ NID_dhSinglePass_stdDH_sha224kdf_scheme,6,&(lvalues[6130]),0},
+{"dhSinglePass-stdDH-sha256kdf-scheme",
+ "dhSinglePass-stdDH-sha256kdf-scheme",
+ NID_dhSinglePass_stdDH_sha256kdf_scheme,6,&(lvalues[6136]),0},
+{"dhSinglePass-stdDH-sha384kdf-scheme",
+ "dhSinglePass-stdDH-sha384kdf-scheme",
+ NID_dhSinglePass_stdDH_sha384kdf_scheme,6,&(lvalues[6142]),0},
+{"dhSinglePass-stdDH-sha512kdf-scheme",
+ "dhSinglePass-stdDH-sha512kdf-scheme",
+ NID_dhSinglePass_stdDH_sha512kdf_scheme,6,&(lvalues[6148]),0},
+{"dhSinglePass-cofactorDH-sha1kdf-scheme",
+ "dhSinglePass-cofactorDH-sha1kdf-scheme",
+ NID_dhSinglePass_cofactorDH_sha1kdf_scheme,9,&(lvalues[6154]),0},
+{"dhSinglePass-cofactorDH-sha224kdf-scheme",
+ "dhSinglePass-cofactorDH-sha224kdf-scheme",
+ NID_dhSinglePass_cofactorDH_sha224kdf_scheme,6,&(lvalues[6163]),0},
+{"dhSinglePass-cofactorDH-sha256kdf-scheme",
+ "dhSinglePass-cofactorDH-sha256kdf-scheme",
+ NID_dhSinglePass_cofactorDH_sha256kdf_scheme,6,&(lvalues[6169]),0},
+{"dhSinglePass-cofactorDH-sha384kdf-scheme",
+ "dhSinglePass-cofactorDH-sha384kdf-scheme",
+ NID_dhSinglePass_cofactorDH_sha384kdf_scheme,6,&(lvalues[6175]),0},
+{"dhSinglePass-cofactorDH-sha512kdf-scheme",
+ "dhSinglePass-cofactorDH-sha512kdf-scheme",
+ NID_dhSinglePass_cofactorDH_sha512kdf_scheme,6,&(lvalues[6181]),0},
+{"dh-std-kdf","dh-std-kdf",NID_dh_std_kdf,0,NULL,0},
+{"dh-cofactor-kdf","dh-cofactor-kdf",NID_dh_cofactor_kdf,0,NULL,0},
+};
+
+static const unsigned int kNIDsInShortNameOrder[NUM_SN]={
+364, /* "AD_DVCS" */
+419, /* "AES-128-CBC" */
+916, /* "AES-128-CBC-HMAC-SHA1" */
+421, /* "AES-128-CFB" */
+650, /* "AES-128-CFB1" */
+653, /* "AES-128-CFB8" */
+904, /* "AES-128-CTR" */
+418, /* "AES-128-ECB" */
+420, /* "AES-128-OFB" */
+913, /* "AES-128-XTS" */
+423, /* "AES-192-CBC" */
+917, /* "AES-192-CBC-HMAC-SHA1" */
+425, /* "AES-192-CFB" */
+651, /* "AES-192-CFB1" */
+654, /* "AES-192-CFB8" */
+905, /* "AES-192-CTR" */
+422, /* "AES-192-ECB" */
+424, /* "AES-192-OFB" */
+427, /* "AES-256-CBC" */
+918, /* "AES-256-CBC-HMAC-SHA1" */
+429, /* "AES-256-CFB" */
+652, /* "AES-256-CFB1" */
+655, /* "AES-256-CFB8" */
+906, /* "AES-256-CTR" */
+426, /* "AES-256-ECB" */
+428, /* "AES-256-OFB" */
+914, /* "AES-256-XTS" */
+91, /* "BF-CBC" */
+93, /* "BF-CFB" */
+92, /* "BF-ECB" */
+94, /* "BF-OFB" */
+14, /* "C" */
+751, /* "CAMELLIA-128-CBC" */
+757, /* "CAMELLIA-128-CFB" */
+760, /* "CAMELLIA-128-CFB1" */
+763, /* "CAMELLIA-128-CFB8" */
+754, /* "CAMELLIA-128-ECB" */
+766, /* "CAMELLIA-128-OFB" */
+752, /* "CAMELLIA-192-CBC" */
+758, /* "CAMELLIA-192-CFB" */
+761, /* "CAMELLIA-192-CFB1" */
+764, /* "CAMELLIA-192-CFB8" */
+755, /* "CAMELLIA-192-ECB" */
+767, /* "CAMELLIA-192-OFB" */
+753, /* "CAMELLIA-256-CBC" */
+759, /* "CAMELLIA-256-CFB" */
+762, /* "CAMELLIA-256-CFB1" */
+765, /* "CAMELLIA-256-CFB8" */
+756, /* "CAMELLIA-256-ECB" */
+768, /* "CAMELLIA-256-OFB" */
+108, /* "CAST5-CBC" */
+110, /* "CAST5-CFB" */
+109, /* "CAST5-ECB" */
+111, /* "CAST5-OFB" */
+894, /* "CMAC" */
+13, /* "CN" */
+141, /* "CRLReason" */
+417, /* "CSPName" */
+367, /* "CrlID" */
+391, /* "DC" */
+31, /* "DES-CBC" */
+643, /* "DES-CDMF" */
+30, /* "DES-CFB" */
+656, /* "DES-CFB1" */
+657, /* "DES-CFB8" */
+29, /* "DES-ECB" */
+32, /* "DES-EDE" */
+43, /* "DES-EDE-CBC" */
+60, /* "DES-EDE-CFB" */
+62, /* "DES-EDE-OFB" */
+33, /* "DES-EDE3" */
+44, /* "DES-EDE3-CBC" */
+61, /* "DES-EDE3-CFB" */
+658, /* "DES-EDE3-CFB1" */
+659, /* "DES-EDE3-CFB8" */
+63, /* "DES-EDE3-OFB" */
+45, /* "DES-OFB" */
+80, /* "DESX-CBC" */
+380, /* "DOD" */
+116, /* "DSA" */
+66, /* "DSA-SHA" */
+113, /* "DSA-SHA1" */
+70, /* "DSA-SHA1-old" */
+67, /* "DSA-old" */
+297, /* "DVCS" */
+99, /* "GN" */
+855, /* "HMAC" */
+780, /* "HMAC-MD5" */
+781, /* "HMAC-SHA1" */
+381, /* "IANA" */
+34, /* "IDEA-CBC" */
+35, /* "IDEA-CFB" */
+36, /* "IDEA-ECB" */
+46, /* "IDEA-OFB" */
+181, /* "ISO" */
+183, /* "ISO-US" */
+645, /* "ITU-T" */
+646, /* "JOINT-ISO-ITU-T" */
+773, /* "KISA" */
+15, /* "L" */
+856, /* "LocalKeySet" */
+ 3, /* "MD2" */
+257, /* "MD4" */
+ 4, /* "MD5" */
+114, /* "MD5-SHA1" */
+95, /* "MDC2" */
+911, /* "MGF1" */
+388, /* "Mail" */
+393, /* "NULL" */
+404, /* "NULL" */
+57, /* "Netscape" */
+366, /* "Nonce" */
+17, /* "O" */
+178, /* "OCSP" */
+180, /* "OCSPSigning" */
+379, /* "ORG" */
+18, /* "OU" */
+749, /* "Oakley-EC2N-3" */
+750, /* "Oakley-EC2N-4" */
+ 9, /* "PBE-MD2-DES" */
+168, /* "PBE-MD2-RC2-64" */
+10, /* "PBE-MD5-DES" */
+169, /* "PBE-MD5-RC2-64" */
+147, /* "PBE-SHA1-2DES" */
+146, /* "PBE-SHA1-3DES" */
+170, /* "PBE-SHA1-DES" */
+148, /* "PBE-SHA1-RC2-128" */
+149, /* "PBE-SHA1-RC2-40" */
+68, /* "PBE-SHA1-RC2-64" */
+144, /* "PBE-SHA1-RC4-128" */
+145, /* "PBE-SHA1-RC4-40" */
+161, /* "PBES2" */
+69, /* "PBKDF2" */
+162, /* "PBMAC1" */
+127, /* "PKIX" */
+935, /* "PSPECIFIED" */
+98, /* "RC2-40-CBC" */
+166, /* "RC2-64-CBC" */
+37, /* "RC2-CBC" */
+39, /* "RC2-CFB" */
+38, /* "RC2-ECB" */
+40, /* "RC2-OFB" */
+ 5, /* "RC4" */
+97, /* "RC4-40" */
+915, /* "RC4-HMAC-MD5" */
+120, /* "RC5-CBC" */
+122, /* "RC5-CFB" */
+121, /* "RC5-ECB" */
+123, /* "RC5-OFB" */
+117, /* "RIPEMD160" */
+124, /* "RLE" */
+19, /* "RSA" */
+ 7, /* "RSA-MD2" */
+396, /* "RSA-MD4" */
+ 8, /* "RSA-MD5" */
+96, /* "RSA-MDC2" */
+104, /* "RSA-NP-MD5" */
+119, /* "RSA-RIPEMD160" */
+42, /* "RSA-SHA" */
+65, /* "RSA-SHA1" */
+115, /* "RSA-SHA1-2" */
+671, /* "RSA-SHA224" */
+668, /* "RSA-SHA256" */
+669, /* "RSA-SHA384" */
+670, /* "RSA-SHA512" */
+919, /* "RSAES-OAEP" */
+912, /* "RSASSA-PSS" */
+777, /* "SEED-CBC" */
+779, /* "SEED-CFB" */
+776, /* "SEED-ECB" */
+778, /* "SEED-OFB" */
+41, /* "SHA" */
+64, /* "SHA1" */
+675, /* "SHA224" */
+672, /* "SHA256" */
+673, /* "SHA384" */
+674, /* "SHA512" */
+188, /* "SMIME" */
+167, /* "SMIME-CAPS" */
+100, /* "SN" */
+16, /* "ST" */
+143, /* "SXNetID" */
+458, /* "UID" */
+ 0, /* "UNDEF" */
+11, /* "X500" */
+378, /* "X500algorithms" */
+12, /* "X509" */
+184, /* "X9-57" */
+185, /* "X9cm" */
+125, /* "ZLIB" */
+478, /* "aRecord" */
+289, /* "aaControls" */
+287, /* "ac-auditEntity" */
+397, /* "ac-proxying" */
+288, /* "ac-targeting" */
+368, /* "acceptableResponses" */
+446, /* "account" */
+363, /* "ad_timestamping" */
+376, /* "algorithm" */
+405, /* "ansi-X9-62" */
+910, /* "anyExtendedKeyUsage" */
+746, /* "anyPolicy" */
+370, /* "archiveCutoff" */
+484, /* "associatedDomain" */
+485, /* "associatedName" */
+501, /* "audio" */
+177, /* "authorityInfoAccess" */
+90, /* "authorityKeyIdentifier" */
+882, /* "authorityRevocationList" */
+87, /* "basicConstraints" */
+365, /* "basicOCSPResponse" */
+285, /* "biometricInfo" */
+921, /* "brainpoolP160r1" */
+922, /* "brainpoolP160t1" */
+923, /* "brainpoolP192r1" */
+924, /* "brainpoolP192t1" */
+925, /* "brainpoolP224r1" */
+926, /* "brainpoolP224t1" */
+927, /* "brainpoolP256r1" */
+928, /* "brainpoolP256t1" */
+929, /* "brainpoolP320r1" */
+930, /* "brainpoolP320t1" */
+931, /* "brainpoolP384r1" */
+932, /* "brainpoolP384t1" */
+933, /* "brainpoolP512r1" */
+934, /* "brainpoolP512t1" */
+494, /* "buildingName" */
+860, /* "businessCategory" */
+691, /* "c2onb191v4" */
+692, /* "c2onb191v5" */
+697, /* "c2onb239v4" */
+698, /* "c2onb239v5" */
+684, /* "c2pnb163v1" */
+685, /* "c2pnb163v2" */
+686, /* "c2pnb163v3" */
+687, /* "c2pnb176v1" */
+693, /* "c2pnb208w1" */
+699, /* "c2pnb272w1" */
+700, /* "c2pnb304w1" */
+702, /* "c2pnb368w1" */
+688, /* "c2tnb191v1" */
+689, /* "c2tnb191v2" */
+690, /* "c2tnb191v3" */
+694, /* "c2tnb239v1" */
+695, /* "c2tnb239v2" */
+696, /* "c2tnb239v3" */
+701, /* "c2tnb359v1" */
+703, /* "c2tnb431r1" */
+881, /* "cACertificate" */
+483, /* "cNAMERecord" */
+179, /* "caIssuers" */
+785, /* "caRepository" */
+443, /* "caseIgnoreIA5StringSyntax" */
+152, /* "certBag" */
+677, /* "certicom-arc" */
+771, /* "certificateIssuer" */
+89, /* "certificatePolicies" */
+883, /* "certificateRevocationList" */
+54, /* "challengePassword" */
+407, /* "characteristic-two-field" */
+395, /* "clearance" */
+130, /* "clientAuth" */
+131, /* "codeSigning" */
+50, /* "contentType" */
+53, /* "countersignature" */
+153, /* "crlBag" */
+103, /* "crlDistributionPoints" */
+88, /* "crlNumber" */
+884, /* "crossCertificatePair" */
+806, /* "cryptocom" */
+805, /* "cryptopro" */
+500, /* "dITRedirect" */
+451, /* "dNSDomain" */
+495, /* "dSAQuality" */
+434, /* "data" */
+390, /* "dcobject" */
+140, /* "deltaCRL" */
+891, /* "deltaRevocationList" */
+107, /* "description" */
+871, /* "destinationIndicator" */
+950, /* "dh-cofactor-kdf" */
+949, /* "dh-std-kdf" */
+28, /* "dhKeyAgreement" */
+944, /* "dhSinglePass-cofactorDH-sha1kdf-scheme" */
+945, /* "dhSinglePass-cofactorDH-sha224kdf-scheme" */
+946, /* "dhSinglePass-cofactorDH-sha256kdf-scheme" */
+947, /* "dhSinglePass-cofactorDH-sha384kdf-scheme" */
+948, /* "dhSinglePass-cofactorDH-sha512kdf-scheme" */
+939, /* "dhSinglePass-stdDH-sha1kdf-scheme" */
+940, /* "dhSinglePass-stdDH-sha224kdf-scheme" */
+941, /* "dhSinglePass-stdDH-sha256kdf-scheme" */
+942, /* "dhSinglePass-stdDH-sha384kdf-scheme" */
+943, /* "dhSinglePass-stdDH-sha512kdf-scheme" */
+920, /* "dhpublicnumber" */
+382, /* "directory" */
+887, /* "distinguishedName" */
+892, /* "dmdName" */
+174, /* "dnQualifier" */
+447, /* "document" */
+471, /* "documentAuthor" */
+468, /* "documentIdentifier" */
+472, /* "documentLocation" */
+502, /* "documentPublisher" */
+449, /* "documentSeries" */
+469, /* "documentTitle" */
+470, /* "documentVersion" */
+392, /* "domain" */
+452, /* "domainRelatedObject" */
+802, /* "dsa_with_SHA224" */
+803, /* "dsa_with_SHA256" */
+791, /* "ecdsa-with-Recommended" */
+416, /* "ecdsa-with-SHA1" */
+793, /* "ecdsa-with-SHA224" */
+794, /* "ecdsa-with-SHA256" */
+795, /* "ecdsa-with-SHA384" */
+796, /* "ecdsa-with-SHA512" */
+792, /* "ecdsa-with-Specified" */
+48, /* "emailAddress" */
+132, /* "emailProtection" */
+885, /* "enhancedSearchGuide" */
+389, /* "enterprises" */
+384, /* "experimental" */
+172, /* "extReq" */
+56, /* "extendedCertificateAttributes" */
+126, /* "extendedKeyUsage" */
+372, /* "extendedStatus" */
+867, /* "facsimileTelephoneNumber" */
+462, /* "favouriteDrink" */
+857, /* "freshestCRL" */
+453, /* "friendlyCountry" */
+490, /* "friendlyCountryName" */
+156, /* "friendlyName" */
+509, /* "generationQualifier" */
+815, /* "gost-mac" */
+811, /* "gost2001" */
+851, /* "gost2001cc" */
+813, /* "gost89" */
+814, /* "gost89-cnt" */
+812, /* "gost94" */
+850, /* "gost94cc" */
+797, /* "hmacWithMD5" */
+163, /* "hmacWithSHA1" */
+798, /* "hmacWithSHA224" */
+799, /* "hmacWithSHA256" */
+800, /* "hmacWithSHA384" */
+801, /* "hmacWithSHA512" */
+432, /* "holdInstructionCallIssuer" */
+430, /* "holdInstructionCode" */
+431, /* "holdInstructionNone" */
+433, /* "holdInstructionReject" */
+486, /* "homePostalAddress" */
+473, /* "homeTelephoneNumber" */
+466, /* "host" */
+889, /* "houseIdentifier" */
+442, /* "iA5StringSyntax" */
+783, /* "id-DHBasedMac" */
+824, /* "id-Gost28147-89-CryptoPro-A-ParamSet" */
+825, /* "id-Gost28147-89-CryptoPro-B-ParamSet" */
+826, /* "id-Gost28147-89-CryptoPro-C-ParamSet" */
+827, /* "id-Gost28147-89-CryptoPro-D-ParamSet" */
+819, /* "id-Gost28147-89-CryptoPro-KeyMeshing" */
+829, /* "id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet" */
+828, /* "id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet" */
+830, /* "id-Gost28147-89-CryptoPro-RIC-1-ParamSet" */
+820, /* "id-Gost28147-89-None-KeyMeshing" */
+823, /* "id-Gost28147-89-TestParamSet" */
+849, /* "id-Gost28147-89-cc" */
+840, /* "id-GostR3410-2001-CryptoPro-A-ParamSet" */
+841, /* "id-GostR3410-2001-CryptoPro-B-ParamSet" */
+842, /* "id-GostR3410-2001-CryptoPro-C-ParamSet" */
+843, /* "id-GostR3410-2001-CryptoPro-XchA-ParamSet" */
+844, /* "id-GostR3410-2001-CryptoPro-XchB-ParamSet" */
+854, /* "id-GostR3410-2001-ParamSet-cc" */
+839, /* "id-GostR3410-2001-TestParamSet" */
+817, /* "id-GostR3410-2001DH" */
+832, /* "id-GostR3410-94-CryptoPro-A-ParamSet" */
+833, /* "id-GostR3410-94-CryptoPro-B-ParamSet" */
+834, /* "id-GostR3410-94-CryptoPro-C-ParamSet" */
+835, /* "id-GostR3410-94-CryptoPro-D-ParamSet" */
+836, /* "id-GostR3410-94-CryptoPro-XchA-ParamSet" */
+837, /* "id-GostR3410-94-CryptoPro-XchB-ParamSet" */
+838, /* "id-GostR3410-94-CryptoPro-XchC-ParamSet" */
+831, /* "id-GostR3410-94-TestParamSet" */
+845, /* "id-GostR3410-94-a" */
+846, /* "id-GostR3410-94-aBis" */
+847, /* "id-GostR3410-94-b" */
+848, /* "id-GostR3410-94-bBis" */
+818, /* "id-GostR3410-94DH" */
+822, /* "id-GostR3411-94-CryptoProParamSet" */
+821, /* "id-GostR3411-94-TestParamSet" */
+807, /* "id-GostR3411-94-with-GostR3410-2001" */
+853, /* "id-GostR3411-94-with-GostR3410-2001-cc" */
+808, /* "id-GostR3411-94-with-GostR3410-94" */
+852, /* "id-GostR3411-94-with-GostR3410-94-cc" */
+810, /* "id-HMACGostR3411-94" */
+782, /* "id-PasswordBasedMAC" */
+266, /* "id-aca" */
+355, /* "id-aca-accessIdentity" */
+354, /* "id-aca-authenticationInfo" */
+356, /* "id-aca-chargingIdentity" */
+399, /* "id-aca-encAttrs" */
+357, /* "id-aca-group" */
+358, /* "id-aca-role" */
+176, /* "id-ad" */
+896, /* "id-aes128-CCM" */
+895, /* "id-aes128-GCM" */
+788, /* "id-aes128-wrap" */
+897, /* "id-aes128-wrap-pad" */
+899, /* "id-aes192-CCM" */
+898, /* "id-aes192-GCM" */
+789, /* "id-aes192-wrap" */
+900, /* "id-aes192-wrap-pad" */
+902, /* "id-aes256-CCM" */
+901, /* "id-aes256-GCM" */
+790, /* "id-aes256-wrap" */
+903, /* "id-aes256-wrap-pad" */
+262, /* "id-alg" */
+893, /* "id-alg-PWRI-KEK" */
+323, /* "id-alg-des40" */
+326, /* "id-alg-dh-pop" */
+325, /* "id-alg-dh-sig-hmac-sha1" */
+324, /* "id-alg-noSignature" */
+907, /* "id-camellia128-wrap" */
+908, /* "id-camellia192-wrap" */
+909, /* "id-camellia256-wrap" */
+268, /* "id-cct" */
+361, /* "id-cct-PKIData" */
+362, /* "id-cct-PKIResponse" */
+360, /* "id-cct-crs" */
+81, /* "id-ce" */
+680, /* "id-characteristic-two-basis" */
+263, /* "id-cmc" */
+334, /* "id-cmc-addExtensions" */
+346, /* "id-cmc-confirmCertAcceptance" */
+330, /* "id-cmc-dataReturn" */
+336, /* "id-cmc-decryptedPOP" */
+335, /* "id-cmc-encryptedPOP" */
+339, /* "id-cmc-getCRL" */
+338, /* "id-cmc-getCert" */
+328, /* "id-cmc-identification" */
+329, /* "id-cmc-identityProof" */
+337, /* "id-cmc-lraPOPWitness" */
+344, /* "id-cmc-popLinkRandom" */
+345, /* "id-cmc-popLinkWitness" */
+343, /* "id-cmc-queryPending" */
+333, /* "id-cmc-recipientNonce" */
+341, /* "id-cmc-regInfo" */
+342, /* "id-cmc-responseInfo" */
+340, /* "id-cmc-revokeRequest" */
+332, /* "id-cmc-senderNonce" */
+327, /* "id-cmc-statusInfo" */
+331, /* "id-cmc-transactionId" */
+787, /* "id-ct-asciiTextWithCRLF" */
+408, /* "id-ecPublicKey" */
+508, /* "id-hex-multipart-message" */
+507, /* "id-hex-partial-message" */
+260, /* "id-it" */
+302, /* "id-it-caKeyUpdateInfo" */
+298, /* "id-it-caProtEncCert" */
+311, /* "id-it-confirmWaitTime" */
+303, /* "id-it-currentCRL" */
+300, /* "id-it-encKeyPairTypes" */
+310, /* "id-it-implicitConfirm" */
+308, /* "id-it-keyPairParamRep" */
+307, /* "id-it-keyPairParamReq" */
+312, /* "id-it-origPKIMessage" */
+301, /* "id-it-preferredSymmAlg" */
+309, /* "id-it-revPassphrase" */
+299, /* "id-it-signKeyPairTypes" */
+305, /* "id-it-subscriptionRequest" */
+306, /* "id-it-subscriptionResponse" */
+784, /* "id-it-suppLangTags" */
+304, /* "id-it-unsupportedOIDs" */
+128, /* "id-kp" */
+280, /* "id-mod-attribute-cert" */
+274, /* "id-mod-cmc" */
+277, /* "id-mod-cmp" */
+284, /* "id-mod-cmp2000" */
+273, /* "id-mod-crmf" */
+283, /* "id-mod-dvcs" */
+275, /* "id-mod-kea-profile-88" */
+276, /* "id-mod-kea-profile-93" */
+282, /* "id-mod-ocsp" */
+278, /* "id-mod-qualified-cert-88" */
+279, /* "id-mod-qualified-cert-93" */
+281, /* "id-mod-timestamp-protocol" */
+264, /* "id-on" */
+858, /* "id-on-permanentIdentifier" */
+347, /* "id-on-personalData" */
+265, /* "id-pda" */
+352, /* "id-pda-countryOfCitizenship" */
+353, /* "id-pda-countryOfResidence" */
+348, /* "id-pda-dateOfBirth" */
+351, /* "id-pda-gender" */
+349, /* "id-pda-placeOfBirth" */
+175, /* "id-pe" */
+261, /* "id-pkip" */
+258, /* "id-pkix-mod" */
+269, /* "id-pkix1-explicit-88" */
+271, /* "id-pkix1-explicit-93" */
+270, /* "id-pkix1-implicit-88" */
+272, /* "id-pkix1-implicit-93" */
+662, /* "id-ppl" */
+664, /* "id-ppl-anyLanguage" */
+667, /* "id-ppl-independent" */
+665, /* "id-ppl-inheritAll" */
+267, /* "id-qcs" */
+359, /* "id-qcs-pkixQCSyntax-v1" */
+259, /* "id-qt" */
+164, /* "id-qt-cps" */
+165, /* "id-qt-unotice" */
+313, /* "id-regCtrl" */
+316, /* "id-regCtrl-authenticator" */
+319, /* "id-regCtrl-oldCertID" */
+318, /* "id-regCtrl-pkiArchiveOptions" */
+317, /* "id-regCtrl-pkiPublicationInfo" */
+320, /* "id-regCtrl-protocolEncrKey" */
+315, /* "id-regCtrl-regToken" */
+314, /* "id-regInfo" */
+322, /* "id-regInfo-certReq" */
+321, /* "id-regInfo-utf8Pairs" */
+512, /* "id-set" */
+191, /* "id-smime-aa" */
+215, /* "id-smime-aa-contentHint" */
+218, /* "id-smime-aa-contentIdentifier" */
+221, /* "id-smime-aa-contentReference" */
+240, /* "id-smime-aa-dvcs-dvc" */
+217, /* "id-smime-aa-encapContentType" */
+222, /* "id-smime-aa-encrypKeyPref" */
+220, /* "id-smime-aa-equivalentLabels" */
+232, /* "id-smime-aa-ets-CertificateRefs" */
+233, /* "id-smime-aa-ets-RevocationRefs" */
+238, /* "id-smime-aa-ets-archiveTimeStamp" */
+237, /* "id-smime-aa-ets-certCRLTimestamp" */
+234, /* "id-smime-aa-ets-certValues" */
+227, /* "id-smime-aa-ets-commitmentType" */
+231, /* "id-smime-aa-ets-contentTimestamp" */
+236, /* "id-smime-aa-ets-escTimeStamp" */
+230, /* "id-smime-aa-ets-otherSigCert" */
+235, /* "id-smime-aa-ets-revocationValues" */
+226, /* "id-smime-aa-ets-sigPolicyId" */
+229, /* "id-smime-aa-ets-signerAttr" */
+228, /* "id-smime-aa-ets-signerLocation" */
+219, /* "id-smime-aa-macValue" */
+214, /* "id-smime-aa-mlExpandHistory" */
+216, /* "id-smime-aa-msgSigDigest" */
+212, /* "id-smime-aa-receiptRequest" */
+213, /* "id-smime-aa-securityLabel" */
+239, /* "id-smime-aa-signatureType" */
+223, /* "id-smime-aa-signingCertificate" */
+224, /* "id-smime-aa-smimeEncryptCerts" */
+225, /* "id-smime-aa-timeStampToken" */
+192, /* "id-smime-alg" */
+243, /* "id-smime-alg-3DESwrap" */
+246, /* "id-smime-alg-CMS3DESwrap" */
+247, /* "id-smime-alg-CMSRC2wrap" */
+245, /* "id-smime-alg-ESDH" */
+241, /* "id-smime-alg-ESDHwith3DES" */
+242, /* "id-smime-alg-ESDHwithRC2" */
+244, /* "id-smime-alg-RC2wrap" */
+193, /* "id-smime-cd" */
+248, /* "id-smime-cd-ldap" */
+190, /* "id-smime-ct" */
+210, /* "id-smime-ct-DVCSRequestData" */
+211, /* "id-smime-ct-DVCSResponseData" */
+208, /* "id-smime-ct-TDTInfo" */
+207, /* "id-smime-ct-TSTInfo" */
+205, /* "id-smime-ct-authData" */
+786, /* "id-smime-ct-compressedData" */
+209, /* "id-smime-ct-contentInfo" */
+206, /* "id-smime-ct-publishCert" */
+204, /* "id-smime-ct-receipt" */
+195, /* "id-smime-cti" */
+255, /* "id-smime-cti-ets-proofOfApproval" */
+256, /* "id-smime-cti-ets-proofOfCreation" */
+253, /* "id-smime-cti-ets-proofOfDelivery" */
+251, /* "id-smime-cti-ets-proofOfOrigin" */
+252, /* "id-smime-cti-ets-proofOfReceipt" */
+254, /* "id-smime-cti-ets-proofOfSender" */
+189, /* "id-smime-mod" */
+196, /* "id-smime-mod-cms" */
+197, /* "id-smime-mod-ess" */
+202, /* "id-smime-mod-ets-eSigPolicy-88" */
+203, /* "id-smime-mod-ets-eSigPolicy-97" */
+200, /* "id-smime-mod-ets-eSignature-88" */
+201, /* "id-smime-mod-ets-eSignature-97" */
+199, /* "id-smime-mod-msg-v3" */
+198, /* "id-smime-mod-oid" */
+194, /* "id-smime-spq" */
+250, /* "id-smime-spq-ets-sqt-unotice" */
+249, /* "id-smime-spq-ets-sqt-uri" */
+676, /* "identified-organization" */
+461, /* "info" */
+748, /* "inhibitAnyPolicy" */
+101, /* "initials" */
+647, /* "international-organizations" */
+869, /* "internationaliSDNNumber" */
+142, /* "invalidityDate" */
+294, /* "ipsecEndSystem" */
+295, /* "ipsecTunnel" */
+296, /* "ipsecUser" */
+86, /* "issuerAltName" */
+770, /* "issuingDistributionPoint" */
+492, /* "janetMailbox" */
+150, /* "keyBag" */
+83, /* "keyUsage" */
+477, /* "lastModifiedBy" */
+476, /* "lastModifiedTime" */
+157, /* "localKeyID" */
+480, /* "mXRecord" */
+460, /* "mail" */
+493, /* "mailPreferenceOption" */
+467, /* "manager" */
+809, /* "md_gost94" */
+875, /* "member" */
+182, /* "member-body" */
+51, /* "messageDigest" */
+383, /* "mgmt" */
+504, /* "mime-mhs" */
+506, /* "mime-mhs-bodies" */
+505, /* "mime-mhs-headings" */
+488, /* "mobileTelephoneNumber" */
+136, /* "msCTLSign" */
+135, /* "msCodeCom" */
+134, /* "msCodeInd" */
+138, /* "msEFS" */
+171, /* "msExtReq" */
+137, /* "msSGC" */
+648, /* "msSmartcardLogin" */
+649, /* "msUPN" */
+481, /* "nSRecord" */
+173, /* "name" */
+666, /* "nameConstraints" */
+369, /* "noCheck" */
+403, /* "noRevAvail" */
+72, /* "nsBaseUrl" */
+76, /* "nsCaPolicyUrl" */
+74, /* "nsCaRevocationUrl" */
+58, /* "nsCertExt" */
+79, /* "nsCertSequence" */
+71, /* "nsCertType" */
+78, /* "nsComment" */
+59, /* "nsDataType" */
+75, /* "nsRenewalUrl" */
+73, /* "nsRevocationUrl" */
+139, /* "nsSGC" */
+77, /* "nsSslServerName" */
+681, /* "onBasis" */
+491, /* "organizationalStatus" */
+475, /* "otherMailbox" */
+876, /* "owner" */
+489, /* "pagerTelephoneNumber" */
+374, /* "path" */
+112, /* "pbeWithMD5AndCast5CBC" */
+499, /* "personalSignature" */
+487, /* "personalTitle" */
+464, /* "photo" */
+863, /* "physicalDeliveryOfficeName" */
+437, /* "pilot" */
+439, /* "pilotAttributeSyntax" */
+438, /* "pilotAttributeType" */
+479, /* "pilotAttributeType27" */
+456, /* "pilotDSA" */
+441, /* "pilotGroups" */
+444, /* "pilotObject" */
+440, /* "pilotObjectClass" */
+455, /* "pilotOrganization" */
+445, /* "pilotPerson" */
+ 2, /* "pkcs" */
+186, /* "pkcs1" */
+27, /* "pkcs3" */
+187, /* "pkcs5" */
+20, /* "pkcs7" */
+21, /* "pkcs7-data" */
+25, /* "pkcs7-digestData" */
+26, /* "pkcs7-encryptedData" */
+23, /* "pkcs7-envelopedData" */
+24, /* "pkcs7-signedAndEnvelopedData" */
+22, /* "pkcs7-signedData" */
+151, /* "pkcs8ShroudedKeyBag" */
+47, /* "pkcs9" */
+401, /* "policyConstraints" */
+747, /* "policyMappings" */
+862, /* "postOfficeBox" */
+861, /* "postalAddress" */
+661, /* "postalCode" */
+683, /* "ppBasis" */
+872, /* "preferredDeliveryMethod" */
+873, /* "presentationAddress" */
+816, /* "prf-gostr3411-94" */
+406, /* "prime-field" */
+409, /* "prime192v1" */
+410, /* "prime192v2" */
+411, /* "prime192v3" */
+412, /* "prime239v1" */
+413, /* "prime239v2" */
+414, /* "prime239v3" */
+415, /* "prime256v1" */
+385, /* "private" */
+84, /* "privateKeyUsagePeriod" */
+886, /* "protocolInformation" */
+663, /* "proxyCertInfo" */
+510, /* "pseudonym" */
+435, /* "pss" */
+286, /* "qcStatements" */
+457, /* "qualityLabelledData" */
+450, /* "rFC822localPart" */
+870, /* "registeredAddress" */
+400, /* "role" */
+877, /* "roleOccupant" */
+448, /* "room" */
+463, /* "roomNumber" */
+ 6, /* "rsaEncryption" */
+644, /* "rsaOAEPEncryptionSET" */
+377, /* "rsaSignature" */
+ 1, /* "rsadsi" */
+482, /* "sOARecord" */
+155, /* "safeContentsBag" */
+291, /* "sbgp-autonomousSysNum" */
+290, /* "sbgp-ipAddrBlock" */
+292, /* "sbgp-routerIdentifier" */
+159, /* "sdsiCertificate" */
+859, /* "searchGuide" */
+704, /* "secp112r1" */
+705, /* "secp112r2" */
+706, /* "secp128r1" */
+707, /* "secp128r2" */
+708, /* "secp160k1" */
+709, /* "secp160r1" */
+710, /* "secp160r2" */
+711, /* "secp192k1" */
+712, /* "secp224k1" */
+713, /* "secp224r1" */
+714, /* "secp256k1" */
+715, /* "secp384r1" */
+716, /* "secp521r1" */
+154, /* "secretBag" */
+474, /* "secretary" */
+717, /* "sect113r1" */
+718, /* "sect113r2" */
+719, /* "sect131r1" */
+720, /* "sect131r2" */
+721, /* "sect163k1" */
+722, /* "sect163r1" */
+723, /* "sect163r2" */
+724, /* "sect193r1" */
+725, /* "sect193r2" */
+726, /* "sect233k1" */
+727, /* "sect233r1" */
+728, /* "sect239k1" */
+729, /* "sect283k1" */
+730, /* "sect283r1" */
+731, /* "sect409k1" */
+732, /* "sect409r1" */
+733, /* "sect571k1" */
+734, /* "sect571r1" */
+386, /* "security" */
+878, /* "seeAlso" */
+394, /* "selected-attribute-types" */
+105, /* "serialNumber" */
+129, /* "serverAuth" */
+371, /* "serviceLocator" */
+625, /* "set-addPolicy" */
+515, /* "set-attr" */
+518, /* "set-brand" */
+638, /* "set-brand-AmericanExpress" */
+637, /* "set-brand-Diners" */
+636, /* "set-brand-IATA-ATA" */
+639, /* "set-brand-JCB" */
+641, /* "set-brand-MasterCard" */
+642, /* "set-brand-Novus" */
+640, /* "set-brand-Visa" */
+517, /* "set-certExt" */
+513, /* "set-ctype" */
+514, /* "set-msgExt" */
+516, /* "set-policy" */
+607, /* "set-policy-root" */
+624, /* "set-rootKeyThumb" */
+620, /* "setAttr-Cert" */
+631, /* "setAttr-GenCryptgrm" */
+623, /* "setAttr-IssCap" */
+628, /* "setAttr-IssCap-CVM" */
+630, /* "setAttr-IssCap-Sig" */
+629, /* "setAttr-IssCap-T2" */
+621, /* "setAttr-PGWYcap" */
+635, /* "setAttr-SecDevSig" */
+632, /* "setAttr-T2Enc" */
+633, /* "setAttr-T2cleartxt" */
+634, /* "setAttr-TokICCsig" */
+627, /* "setAttr-Token-B0Prime" */
+626, /* "setAttr-Token-EMV" */
+622, /* "setAttr-TokenType" */
+619, /* "setCext-IssuerCapabilities" */
+615, /* "setCext-PGWYcapabilities" */
+616, /* "setCext-TokenIdentifier" */
+618, /* "setCext-TokenType" */
+617, /* "setCext-Track2Data" */
+611, /* "setCext-cCertRequired" */
+609, /* "setCext-certType" */
+608, /* "setCext-hashedRoot" */
+610, /* "setCext-merchData" */
+613, /* "setCext-setExt" */
+614, /* "setCext-setQualf" */
+612, /* "setCext-tunneling" */
+540, /* "setct-AcqCardCodeMsg" */
+576, /* "setct-AcqCardCodeMsgTBE" */
+570, /* "setct-AuthReqTBE" */
+534, /* "setct-AuthReqTBS" */
+527, /* "setct-AuthResBaggage" */
+571, /* "setct-AuthResTBE" */
+572, /* "setct-AuthResTBEX" */
+535, /* "setct-AuthResTBS" */
+536, /* "setct-AuthResTBSX" */
+528, /* "setct-AuthRevReqBaggage" */
+577, /* "setct-AuthRevReqTBE" */
+541, /* "setct-AuthRevReqTBS" */
+529, /* "setct-AuthRevResBaggage" */
+542, /* "setct-AuthRevResData" */
+578, /* "setct-AuthRevResTBE" */
+579, /* "setct-AuthRevResTBEB" */
+543, /* "setct-AuthRevResTBS" */
+573, /* "setct-AuthTokenTBE" */
+537, /* "setct-AuthTokenTBS" */
+600, /* "setct-BCIDistributionTBS" */
+558, /* "setct-BatchAdminReqData" */
+592, /* "setct-BatchAdminReqTBE" */
+559, /* "setct-BatchAdminResData" */
+593, /* "setct-BatchAdminResTBE" */
+599, /* "setct-CRLNotificationResTBS" */
+598, /* "setct-CRLNotificationTBS" */
+580, /* "setct-CapReqTBE" */
+581, /* "setct-CapReqTBEX" */
+544, /* "setct-CapReqTBS" */
+545, /* "setct-CapReqTBSX" */
+546, /* "setct-CapResData" */
+582, /* "setct-CapResTBE" */
+583, /* "setct-CapRevReqTBE" */
+584, /* "setct-CapRevReqTBEX" */
+547, /* "setct-CapRevReqTBS" */
+548, /* "setct-CapRevReqTBSX" */
+549, /* "setct-CapRevResData" */
+585, /* "setct-CapRevResTBE" */
+538, /* "setct-CapTokenData" */
+530, /* "setct-CapTokenSeq" */
+574, /* "setct-CapTokenTBE" */
+575, /* "setct-CapTokenTBEX" */
+539, /* "setct-CapTokenTBS" */
+560, /* "setct-CardCInitResTBS" */
+566, /* "setct-CertInqReqTBS" */
+563, /* "setct-CertReqData" */
+595, /* "setct-CertReqTBE" */
+596, /* "setct-CertReqTBEX" */
+564, /* "setct-CertReqTBS" */
+565, /* "setct-CertResData" */
+597, /* "setct-CertResTBE" */
+586, /* "setct-CredReqTBE" */
+587, /* "setct-CredReqTBEX" */
+550, /* "setct-CredReqTBS" */
+551, /* "setct-CredReqTBSX" */
+552, /* "setct-CredResData" */
+588, /* "setct-CredResTBE" */
+589, /* "setct-CredRevReqTBE" */
+590, /* "setct-CredRevReqTBEX" */
+553, /* "setct-CredRevReqTBS" */
+554, /* "setct-CredRevReqTBSX" */
+555, /* "setct-CredRevResData" */
+591, /* "setct-CredRevResTBE" */
+567, /* "setct-ErrorTBS" */
+526, /* "setct-HODInput" */
+561, /* "setct-MeAqCInitResTBS" */
+522, /* "setct-OIData" */
+519, /* "setct-PANData" */
+521, /* "setct-PANOnly" */
+520, /* "setct-PANToken" */
+556, /* "setct-PCertReqData" */
+557, /* "setct-PCertResTBS" */
+523, /* "setct-PI" */
+532, /* "setct-PI-TBS" */
+524, /* "setct-PIData" */
+525, /* "setct-PIDataUnsigned" */
+568, /* "setct-PIDualSignedTBE" */
+569, /* "setct-PIUnsignedTBE" */
+531, /* "setct-PInitResData" */
+533, /* "setct-PResData" */
+594, /* "setct-RegFormReqTBE" */
+562, /* "setct-RegFormResTBS" */
+606, /* "setext-cv" */
+601, /* "setext-genCrypt" */
+602, /* "setext-miAuth" */
+604, /* "setext-pinAny" */
+603, /* "setext-pinSecure" */
+605, /* "setext-track2" */
+52, /* "signingTime" */
+454, /* "simpleSecurityObject" */
+496, /* "singleLevelQuality" */
+387, /* "snmpv2" */
+660, /* "street" */
+85, /* "subjectAltName" */
+769, /* "subjectDirectoryAttributes" */
+398, /* "subjectInfoAccess" */
+82, /* "subjectKeyIdentifier" */
+498, /* "subtreeMaximumQuality" */
+497, /* "subtreeMinimumQuality" */
+890, /* "supportedAlgorithms" */
+874, /* "supportedApplicationContext" */
+402, /* "targetInformation" */
+864, /* "telephoneNumber" */
+866, /* "teletexTerminalIdentifier" */
+865, /* "telexNumber" */
+459, /* "textEncodedORAddress" */
+293, /* "textNotice" */
+133, /* "timeStamping" */
+106, /* "title" */
+682, /* "tpBasis" */
+375, /* "trustRoot" */
+436, /* "ucl" */
+888, /* "uniqueMember" */
+55, /* "unstructuredAddress" */
+49, /* "unstructuredName" */
+880, /* "userCertificate" */
+465, /* "userClass" */
+879, /* "userPassword" */
+373, /* "valid" */
+678, /* "wap" */
+679, /* "wap-wsg" */
+735, /* "wap-wsg-idm-ecid-wtls1" */
+743, /* "wap-wsg-idm-ecid-wtls10" */
+744, /* "wap-wsg-idm-ecid-wtls11" */
+745, /* "wap-wsg-idm-ecid-wtls12" */
+736, /* "wap-wsg-idm-ecid-wtls3" */
+737, /* "wap-wsg-idm-ecid-wtls4" */
+738, /* "wap-wsg-idm-ecid-wtls5" */
+739, /* "wap-wsg-idm-ecid-wtls6" */
+740, /* "wap-wsg-idm-ecid-wtls7" */
+741, /* "wap-wsg-idm-ecid-wtls8" */
+742, /* "wap-wsg-idm-ecid-wtls9" */
+804, /* "whirlpool" */
+868, /* "x121Address" */
+503, /* "x500UniqueIdentifier" */
+158, /* "x509Certificate" */
+160, /* "x509Crl" */
+};
+
+static const unsigned int kNIDsInLongNameOrder[NUM_LN]={
+363, /* "AD Time Stamping" */
+405, /* "ANSI X9.62" */
+368, /* "Acceptable OCSP Responses" */
+910, /* "Any Extended Key Usage" */
+664, /* "Any language" */
+177, /* "Authority Information Access" */
+365, /* "Basic OCSP Response" */
+285, /* "Biometric Info" */
+179, /* "CA Issuers" */
+785, /* "CA Repository" */
+131, /* "Code Signing" */
+783, /* "Diffie-Hellman based MAC" */
+382, /* "Directory" */
+392, /* "Domain" */
+132, /* "E-mail Protection" */
+389, /* "Enterprises" */
+384, /* "Experimental" */
+372, /* "Extended OCSP Status" */
+172, /* "Extension Request" */
+813, /* "GOST 28147-89" */
+849, /* "GOST 28147-89 Cryptocom ParamSet" */
+815, /* "GOST 28147-89 MAC" */
+851, /* "GOST 34.10-2001 Cryptocom" */
+850, /* "GOST 34.10-94 Cryptocom" */
+811, /* "GOST R 34.10-2001" */
+817, /* "GOST R 34.10-2001 DH" */
+812, /* "GOST R 34.10-94" */
+818, /* "GOST R 34.10-94 DH" */
+809, /* "GOST R 34.11-94" */
+816, /* "GOST R 34.11-94 PRF" */
+807, /* "GOST R 34.11-94 with GOST R 34.10-2001" */
+853, /* "GOST R 34.11-94 with GOST R 34.10-2001 Cryptocom" */
+808, /* "GOST R 34.11-94 with GOST R 34.10-94" */
+852, /* "GOST R 34.11-94 with GOST R 34.10-94 Cryptocom" */
+854, /* "GOST R 3410-2001 Parameter Set Cryptocom" */
+810, /* "HMAC GOST 34.11-94" */
+432, /* "Hold Instruction Call Issuer" */
+430, /* "Hold Instruction Code" */
+431, /* "Hold Instruction None" */
+433, /* "Hold Instruction Reject" */
+634, /* "ICC or token signature" */
+294, /* "IPSec End System" */
+295, /* "IPSec Tunnel" */
+296, /* "IPSec User" */
+182, /* "ISO Member Body" */
+183, /* "ISO US Member Body" */
+667, /* "Independent" */
+665, /* "Inherit all" */
+647, /* "International Organizations" */
+142, /* "Invalidity Date" */
+504, /* "MIME MHS" */
+388, /* "Mail" */
+383, /* "Management" */
+417, /* "Microsoft CSP Name" */
+135, /* "Microsoft Commercial Code Signing" */
+138, /* "Microsoft Encrypted File System" */
+171, /* "Microsoft Extension Request" */
+134, /* "Microsoft Individual Code Signing" */
+856, /* "Microsoft Local Key set" */
+137, /* "Microsoft Server Gated Crypto" */
+648, /* "Microsoft Smartcardlogin" */
+136, /* "Microsoft Trust List Signing" */
+649, /* "Microsoft Universal Principal Name" */
+393, /* "NULL" */
+404, /* "NULL" */
+72, /* "Netscape Base Url" */
+76, /* "Netscape CA Policy Url" */
+74, /* "Netscape CA Revocation Url" */
+71, /* "Netscape Cert Type" */
+58, /* "Netscape Certificate Extension" */
+79, /* "Netscape Certificate Sequence" */
+78, /* "Netscape Comment" */
+57, /* "Netscape Communications Corp." */
+59, /* "Netscape Data Type" */
+75, /* "Netscape Renewal Url" */
+73, /* "Netscape Revocation Url" */
+77, /* "Netscape SSL Server Name" */
+139, /* "Netscape Server Gated Crypto" */
+178, /* "OCSP" */
+370, /* "OCSP Archive Cutoff" */
+367, /* "OCSP CRL ID" */
+369, /* "OCSP No Check" */
+366, /* "OCSP Nonce" */
+371, /* "OCSP Service Locator" */
+180, /* "OCSP Signing" */
+161, /* "PBES2" */
+69, /* "PBKDF2" */
+162, /* "PBMAC1" */
+127, /* "PKIX" */
+858, /* "Permanent Identifier" */
+164, /* "Policy Qualifier CPS" */
+165, /* "Policy Qualifier User Notice" */
+385, /* "Private" */
+663, /* "Proxy Certificate Information" */
+ 1, /* "RSA Data Security, Inc." */
+ 2, /* "RSA Data Security, Inc. PKCS" */
+188, /* "S/MIME" */
+167, /* "S/MIME Capabilities" */
+387, /* "SNMPv2" */
+512, /* "Secure Electronic Transactions" */
+386, /* "Security" */
+394, /* "Selected Attribute Types" */
+143, /* "Strong Extranet ID" */
+398, /* "Subject Information Access" */
+130, /* "TLS Web Client Authentication" */
+129, /* "TLS Web Server Authentication" */
+133, /* "Time Stamping" */
+375, /* "Trust Root" */
+12, /* "X509" */
+402, /* "X509v3 AC Targeting" */
+746, /* "X509v3 Any Policy" */
+90, /* "X509v3 Authority Key Identifier" */
+87, /* "X509v3 Basic Constraints" */
+103, /* "X509v3 CRL Distribution Points" */
+88, /* "X509v3 CRL Number" */
+141, /* "X509v3 CRL Reason Code" */
+771, /* "X509v3 Certificate Issuer" */
+89, /* "X509v3 Certificate Policies" */
+140, /* "X509v3 Delta CRL Indicator" */
+126, /* "X509v3 Extended Key Usage" */
+857, /* "X509v3 Freshest CRL" */
+748, /* "X509v3 Inhibit Any Policy" */
+86, /* "X509v3 Issuer Alternative Name" */
+770, /* "X509v3 Issuing Distrubution Point" */
+83, /* "X509v3 Key Usage" */
+666, /* "X509v3 Name Constraints" */
+403, /* "X509v3 No Revocation Available" */
+401, /* "X509v3 Policy Constraints" */
+747, /* "X509v3 Policy Mappings" */
+84, /* "X509v3 Private Key Usage Period" */
+85, /* "X509v3 Subject Alternative Name" */
+769, /* "X509v3 Subject Directory Attributes" */
+82, /* "X509v3 Subject Key Identifier" */
+920, /* "X9.42 DH" */
+184, /* "X9.57" */
+185, /* "X9.57 CM ?" */
+478, /* "aRecord" */
+289, /* "aaControls" */
+287, /* "ac-auditEntity" */
+397, /* "ac-proxying" */
+288, /* "ac-targeting" */
+446, /* "account" */
+364, /* "ad dvcs" */
+606, /* "additional verification" */
+419, /* "aes-128-cbc" */
+916, /* "aes-128-cbc-hmac-sha1" */
+896, /* "aes-128-ccm" */
+421, /* "aes-128-cfb" */
+650, /* "aes-128-cfb1" */
+653, /* "aes-128-cfb8" */
+904, /* "aes-128-ctr" */
+418, /* "aes-128-ecb" */
+895, /* "aes-128-gcm" */
+420, /* "aes-128-ofb" */
+913, /* "aes-128-xts" */
+423, /* "aes-192-cbc" */
+917, /* "aes-192-cbc-hmac-sha1" */
+899, /* "aes-192-ccm" */
+425, /* "aes-192-cfb" */
+651, /* "aes-192-cfb1" */
+654, /* "aes-192-cfb8" */
+905, /* "aes-192-ctr" */
+422, /* "aes-192-ecb" */
+898, /* "aes-192-gcm" */
+424, /* "aes-192-ofb" */
+427, /* "aes-256-cbc" */
+918, /* "aes-256-cbc-hmac-sha1" */
+902, /* "aes-256-ccm" */
+429, /* "aes-256-cfb" */
+652, /* "aes-256-cfb1" */
+655, /* "aes-256-cfb8" */
+906, /* "aes-256-ctr" */
+426, /* "aes-256-ecb" */
+901, /* "aes-256-gcm" */
+428, /* "aes-256-ofb" */
+914, /* "aes-256-xts" */
+376, /* "algorithm" */
+484, /* "associatedDomain" */
+485, /* "associatedName" */
+501, /* "audio" */
+882, /* "authorityRevocationList" */
+91, /* "bf-cbc" */
+93, /* "bf-cfb" */
+92, /* "bf-ecb" */
+94, /* "bf-ofb" */
+921, /* "brainpoolP160r1" */
+922, /* "brainpoolP160t1" */
+923, /* "brainpoolP192r1" */
+924, /* "brainpoolP192t1" */
+925, /* "brainpoolP224r1" */
+926, /* "brainpoolP224t1" */
+927, /* "brainpoolP256r1" */
+928, /* "brainpoolP256t1" */
+929, /* "brainpoolP320r1" */
+930, /* "brainpoolP320t1" */
+931, /* "brainpoolP384r1" */
+932, /* "brainpoolP384t1" */
+933, /* "brainpoolP512r1" */
+934, /* "brainpoolP512t1" */
+494, /* "buildingName" */
+860, /* "businessCategory" */
+691, /* "c2onb191v4" */
+692, /* "c2onb191v5" */
+697, /* "c2onb239v4" */
+698, /* "c2onb239v5" */
+684, /* "c2pnb163v1" */
+685, /* "c2pnb163v2" */
+686, /* "c2pnb163v3" */
+687, /* "c2pnb176v1" */
+693, /* "c2pnb208w1" */
+699, /* "c2pnb272w1" */
+700, /* "c2pnb304w1" */
+702, /* "c2pnb368w1" */
+688, /* "c2tnb191v1" */
+689, /* "c2tnb191v2" */
+690, /* "c2tnb191v3" */
+694, /* "c2tnb239v1" */
+695, /* "c2tnb239v2" */
+696, /* "c2tnb239v3" */
+701, /* "c2tnb359v1" */
+703, /* "c2tnb431r1" */
+881, /* "cACertificate" */
+483, /* "cNAMERecord" */
+751, /* "camellia-128-cbc" */
+757, /* "camellia-128-cfb" */
+760, /* "camellia-128-cfb1" */
+763, /* "camellia-128-cfb8" */
+754, /* "camellia-128-ecb" */
+766, /* "camellia-128-ofb" */
+752, /* "camellia-192-cbc" */
+758, /* "camellia-192-cfb" */
+761, /* "camellia-192-cfb1" */
+764, /* "camellia-192-cfb8" */
+755, /* "camellia-192-ecb" */
+767, /* "camellia-192-ofb" */
+753, /* "camellia-256-cbc" */
+759, /* "camellia-256-cfb" */
+762, /* "camellia-256-cfb1" */
+765, /* "camellia-256-cfb8" */
+756, /* "camellia-256-ecb" */
+768, /* "camellia-256-ofb" */
+443, /* "caseIgnoreIA5StringSyntax" */
+108, /* "cast5-cbc" */
+110, /* "cast5-cfb" */
+109, /* "cast5-ecb" */
+111, /* "cast5-ofb" */
+152, /* "certBag" */
+677, /* "certicom-arc" */
+517, /* "certificate extensions" */
+883, /* "certificateRevocationList" */
+54, /* "challengePassword" */
+407, /* "characteristic-two-field" */
+395, /* "clearance" */
+633, /* "cleartext track 2" */
+894, /* "cmac" */
+13, /* "commonName" */
+513, /* "content types" */
+50, /* "contentType" */
+53, /* "countersignature" */
+14, /* "countryName" */
+153, /* "crlBag" */
+884, /* "crossCertificatePair" */
+806, /* "cryptocom" */
+805, /* "cryptopro" */
+500, /* "dITRedirect" */
+451, /* "dNSDomain" */
+495, /* "dSAQuality" */
+434, /* "data" */
+390, /* "dcObject" */
+891, /* "deltaRevocationList" */
+31, /* "des-cbc" */
+643, /* "des-cdmf" */
+30, /* "des-cfb" */
+656, /* "des-cfb1" */
+657, /* "des-cfb8" */
+29, /* "des-ecb" */
+32, /* "des-ede" */
+43, /* "des-ede-cbc" */
+60, /* "des-ede-cfb" */
+62, /* "des-ede-ofb" */
+33, /* "des-ede3" */
+44, /* "des-ede3-cbc" */
+61, /* "des-ede3-cfb" */
+658, /* "des-ede3-cfb1" */
+659, /* "des-ede3-cfb8" */
+63, /* "des-ede3-ofb" */
+45, /* "des-ofb" */
+107, /* "description" */
+871, /* "destinationIndicator" */
+80, /* "desx-cbc" */
+950, /* "dh-cofactor-kdf" */
+949, /* "dh-std-kdf" */
+28, /* "dhKeyAgreement" */
+944, /* "dhSinglePass-cofactorDH-sha1kdf-scheme" */
+945, /* "dhSinglePass-cofactorDH-sha224kdf-scheme" */
+946, /* "dhSinglePass-cofactorDH-sha256kdf-scheme" */
+947, /* "dhSinglePass-cofactorDH-sha384kdf-scheme" */
+948, /* "dhSinglePass-cofactorDH-sha512kdf-scheme" */
+939, /* "dhSinglePass-stdDH-sha1kdf-scheme" */
+940, /* "dhSinglePass-stdDH-sha224kdf-scheme" */
+941, /* "dhSinglePass-stdDH-sha256kdf-scheme" */
+942, /* "dhSinglePass-stdDH-sha384kdf-scheme" */
+943, /* "dhSinglePass-stdDH-sha512kdf-scheme" */
+11, /* "directory services (X.500)" */
+378, /* "directory services - algorithms" */
+887, /* "distinguishedName" */
+892, /* "dmdName" */
+174, /* "dnQualifier" */
+447, /* "document" */
+471, /* "documentAuthor" */
+468, /* "documentIdentifier" */
+472, /* "documentLocation" */
+502, /* "documentPublisher" */
+449, /* "documentSeries" */
+469, /* "documentTitle" */
+470, /* "documentVersion" */
+380, /* "dod" */
+391, /* "domainComponent" */
+452, /* "domainRelatedObject" */
+116, /* "dsaEncryption" */
+67, /* "dsaEncryption-old" */
+66, /* "dsaWithSHA" */
+113, /* "dsaWithSHA1" */
+70, /* "dsaWithSHA1-old" */
+802, /* "dsa_with_SHA224" */
+803, /* "dsa_with_SHA256" */
+297, /* "dvcs" */
+791, /* "ecdsa-with-Recommended" */
+416, /* "ecdsa-with-SHA1" */
+793, /* "ecdsa-with-SHA224" */
+794, /* "ecdsa-with-SHA256" */
+795, /* "ecdsa-with-SHA384" */
+796, /* "ecdsa-with-SHA512" */
+792, /* "ecdsa-with-Specified" */
+48, /* "emailAddress" */
+632, /* "encrypted track 2" */
+885, /* "enhancedSearchGuide" */
+56, /* "extendedCertificateAttributes" */
+867, /* "facsimileTelephoneNumber" */
+462, /* "favouriteDrink" */
+453, /* "friendlyCountry" */
+490, /* "friendlyCountryName" */
+156, /* "friendlyName" */
+631, /* "generate cryptogram" */
+509, /* "generationQualifier" */
+601, /* "generic cryptogram" */
+99, /* "givenName" */
+814, /* "gost89-cnt" */
+855, /* "hmac" */
+780, /* "hmac-md5" */
+781, /* "hmac-sha1" */
+797, /* "hmacWithMD5" */
+163, /* "hmacWithSHA1" */
+798, /* "hmacWithSHA224" */
+799, /* "hmacWithSHA256" */
+800, /* "hmacWithSHA384" */
+801, /* "hmacWithSHA512" */
+486, /* "homePostalAddress" */
+473, /* "homeTelephoneNumber" */
+466, /* "host" */
+889, /* "houseIdentifier" */
+442, /* "iA5StringSyntax" */
+381, /* "iana" */
+824, /* "id-Gost28147-89-CryptoPro-A-ParamSet" */
+825, /* "id-Gost28147-89-CryptoPro-B-ParamSet" */
+826, /* "id-Gost28147-89-CryptoPro-C-ParamSet" */
+827, /* "id-Gost28147-89-CryptoPro-D-ParamSet" */
+819, /* "id-Gost28147-89-CryptoPro-KeyMeshing" */
+829, /* "id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet" */
+828, /* "id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet" */
+830, /* "id-Gost28147-89-CryptoPro-RIC-1-ParamSet" */
+820, /* "id-Gost28147-89-None-KeyMeshing" */
+823, /* "id-Gost28147-89-TestParamSet" */
+840, /* "id-GostR3410-2001-CryptoPro-A-ParamSet" */
+841, /* "id-GostR3410-2001-CryptoPro-B-ParamSet" */
+842, /* "id-GostR3410-2001-CryptoPro-C-ParamSet" */
+843, /* "id-GostR3410-2001-CryptoPro-XchA-ParamSet" */
+844, /* "id-GostR3410-2001-CryptoPro-XchB-ParamSet" */
+839, /* "id-GostR3410-2001-TestParamSet" */
+832, /* "id-GostR3410-94-CryptoPro-A-ParamSet" */
+833, /* "id-GostR3410-94-CryptoPro-B-ParamSet" */
+834, /* "id-GostR3410-94-CryptoPro-C-ParamSet" */
+835, /* "id-GostR3410-94-CryptoPro-D-ParamSet" */
+836, /* "id-GostR3410-94-CryptoPro-XchA-ParamSet" */
+837, /* "id-GostR3410-94-CryptoPro-XchB-ParamSet" */
+838, /* "id-GostR3410-94-CryptoPro-XchC-ParamSet" */
+831, /* "id-GostR3410-94-TestParamSet" */
+845, /* "id-GostR3410-94-a" */
+846, /* "id-GostR3410-94-aBis" */
+847, /* "id-GostR3410-94-b" */
+848, /* "id-GostR3410-94-bBis" */
+822, /* "id-GostR3411-94-CryptoProParamSet" */
+821, /* "id-GostR3411-94-TestParamSet" */
+266, /* "id-aca" */
+355, /* "id-aca-accessIdentity" */
+354, /* "id-aca-authenticationInfo" */
+356, /* "id-aca-chargingIdentity" */
+399, /* "id-aca-encAttrs" */
+357, /* "id-aca-group" */
+358, /* "id-aca-role" */
+176, /* "id-ad" */
+788, /* "id-aes128-wrap" */
+897, /* "id-aes128-wrap-pad" */
+789, /* "id-aes192-wrap" */
+900, /* "id-aes192-wrap-pad" */
+790, /* "id-aes256-wrap" */
+903, /* "id-aes256-wrap-pad" */
+262, /* "id-alg" */
+893, /* "id-alg-PWRI-KEK" */
+323, /* "id-alg-des40" */
+326, /* "id-alg-dh-pop" */
+325, /* "id-alg-dh-sig-hmac-sha1" */
+324, /* "id-alg-noSignature" */
+907, /* "id-camellia128-wrap" */
+908, /* "id-camellia192-wrap" */
+909, /* "id-camellia256-wrap" */
+268, /* "id-cct" */
+361, /* "id-cct-PKIData" */
+362, /* "id-cct-PKIResponse" */
+360, /* "id-cct-crs" */
+81, /* "id-ce" */
+680, /* "id-characteristic-two-basis" */
+263, /* "id-cmc" */
+334, /* "id-cmc-addExtensions" */
+346, /* "id-cmc-confirmCertAcceptance" */
+330, /* "id-cmc-dataReturn" */
+336, /* "id-cmc-decryptedPOP" */
+335, /* "id-cmc-encryptedPOP" */
+339, /* "id-cmc-getCRL" */
+338, /* "id-cmc-getCert" */
+328, /* "id-cmc-identification" */
+329, /* "id-cmc-identityProof" */
+337, /* "id-cmc-lraPOPWitness" */
+344, /* "id-cmc-popLinkRandom" */
+345, /* "id-cmc-popLinkWitness" */
+343, /* "id-cmc-queryPending" */
+333, /* "id-cmc-recipientNonce" */
+341, /* "id-cmc-regInfo" */
+342, /* "id-cmc-responseInfo" */
+340, /* "id-cmc-revokeRequest" */
+332, /* "id-cmc-senderNonce" */
+327, /* "id-cmc-statusInfo" */
+331, /* "id-cmc-transactionId" */
+787, /* "id-ct-asciiTextWithCRLF" */
+408, /* "id-ecPublicKey" */
+508, /* "id-hex-multipart-message" */
+507, /* "id-hex-partial-message" */
+260, /* "id-it" */
+302, /* "id-it-caKeyUpdateInfo" */
+298, /* "id-it-caProtEncCert" */
+311, /* "id-it-confirmWaitTime" */
+303, /* "id-it-currentCRL" */
+300, /* "id-it-encKeyPairTypes" */
+310, /* "id-it-implicitConfirm" */
+308, /* "id-it-keyPairParamRep" */
+307, /* "id-it-keyPairParamReq" */
+312, /* "id-it-origPKIMessage" */
+301, /* "id-it-preferredSymmAlg" */
+309, /* "id-it-revPassphrase" */
+299, /* "id-it-signKeyPairTypes" */
+305, /* "id-it-subscriptionRequest" */
+306, /* "id-it-subscriptionResponse" */
+784, /* "id-it-suppLangTags" */
+304, /* "id-it-unsupportedOIDs" */
+128, /* "id-kp" */
+280, /* "id-mod-attribute-cert" */
+274, /* "id-mod-cmc" */
+277, /* "id-mod-cmp" */
+284, /* "id-mod-cmp2000" */
+273, /* "id-mod-crmf" */
+283, /* "id-mod-dvcs" */
+275, /* "id-mod-kea-profile-88" */
+276, /* "id-mod-kea-profile-93" */
+282, /* "id-mod-ocsp" */
+278, /* "id-mod-qualified-cert-88" */
+279, /* "id-mod-qualified-cert-93" */
+281, /* "id-mod-timestamp-protocol" */
+264, /* "id-on" */
+347, /* "id-on-personalData" */
+265, /* "id-pda" */
+352, /* "id-pda-countryOfCitizenship" */
+353, /* "id-pda-countryOfResidence" */
+348, /* "id-pda-dateOfBirth" */
+351, /* "id-pda-gender" */
+349, /* "id-pda-placeOfBirth" */
+175, /* "id-pe" */
+261, /* "id-pkip" */
+258, /* "id-pkix-mod" */
+269, /* "id-pkix1-explicit-88" */
+271, /* "id-pkix1-explicit-93" */
+270, /* "id-pkix1-implicit-88" */
+272, /* "id-pkix1-implicit-93" */
+662, /* "id-ppl" */
+267, /* "id-qcs" */
+359, /* "id-qcs-pkixQCSyntax-v1" */
+259, /* "id-qt" */
+313, /* "id-regCtrl" */
+316, /* "id-regCtrl-authenticator" */
+319, /* "id-regCtrl-oldCertID" */
+318, /* "id-regCtrl-pkiArchiveOptions" */
+317, /* "id-regCtrl-pkiPublicationInfo" */
+320, /* "id-regCtrl-protocolEncrKey" */
+315, /* "id-regCtrl-regToken" */
+314, /* "id-regInfo" */
+322, /* "id-regInfo-certReq" */
+321, /* "id-regInfo-utf8Pairs" */
+191, /* "id-smime-aa" */
+215, /* "id-smime-aa-contentHint" */
+218, /* "id-smime-aa-contentIdentifier" */
+221, /* "id-smime-aa-contentReference" */
+240, /* "id-smime-aa-dvcs-dvc" */
+217, /* "id-smime-aa-encapContentType" */
+222, /* "id-smime-aa-encrypKeyPref" */
+220, /* "id-smime-aa-equivalentLabels" */
+232, /* "id-smime-aa-ets-CertificateRefs" */
+233, /* "id-smime-aa-ets-RevocationRefs" */
+238, /* "id-smime-aa-ets-archiveTimeStamp" */
+237, /* "id-smime-aa-ets-certCRLTimestamp" */
+234, /* "id-smime-aa-ets-certValues" */
+227, /* "id-smime-aa-ets-commitmentType" */
+231, /* "id-smime-aa-ets-contentTimestamp" */
+236, /* "id-smime-aa-ets-escTimeStamp" */
+230, /* "id-smime-aa-ets-otherSigCert" */
+235, /* "id-smime-aa-ets-revocationValues" */
+226, /* "id-smime-aa-ets-sigPolicyId" */
+229, /* "id-smime-aa-ets-signerAttr" */
+228, /* "id-smime-aa-ets-signerLocation" */
+219, /* "id-smime-aa-macValue" */
+214, /* "id-smime-aa-mlExpandHistory" */
+216, /* "id-smime-aa-msgSigDigest" */
+212, /* "id-smime-aa-receiptRequest" */
+213, /* "id-smime-aa-securityLabel" */
+239, /* "id-smime-aa-signatureType" */
+223, /* "id-smime-aa-signingCertificate" */
+224, /* "id-smime-aa-smimeEncryptCerts" */
+225, /* "id-smime-aa-timeStampToken" */
+192, /* "id-smime-alg" */
+243, /* "id-smime-alg-3DESwrap" */
+246, /* "id-smime-alg-CMS3DESwrap" */
+247, /* "id-smime-alg-CMSRC2wrap" */
+245, /* "id-smime-alg-ESDH" */
+241, /* "id-smime-alg-ESDHwith3DES" */
+242, /* "id-smime-alg-ESDHwithRC2" */
+244, /* "id-smime-alg-RC2wrap" */
+193, /* "id-smime-cd" */
+248, /* "id-smime-cd-ldap" */
+190, /* "id-smime-ct" */
+210, /* "id-smime-ct-DVCSRequestData" */
+211, /* "id-smime-ct-DVCSResponseData" */
+208, /* "id-smime-ct-TDTInfo" */
+207, /* "id-smime-ct-TSTInfo" */
+205, /* "id-smime-ct-authData" */
+786, /* "id-smime-ct-compressedData" */
+209, /* "id-smime-ct-contentInfo" */
+206, /* "id-smime-ct-publishCert" */
+204, /* "id-smime-ct-receipt" */
+195, /* "id-smime-cti" */
+255, /* "id-smime-cti-ets-proofOfApproval" */
+256, /* "id-smime-cti-ets-proofOfCreation" */
+253, /* "id-smime-cti-ets-proofOfDelivery" */
+251, /* "id-smime-cti-ets-proofOfOrigin" */
+252, /* "id-smime-cti-ets-proofOfReceipt" */
+254, /* "id-smime-cti-ets-proofOfSender" */
+189, /* "id-smime-mod" */
+196, /* "id-smime-mod-cms" */
+197, /* "id-smime-mod-ess" */
+202, /* "id-smime-mod-ets-eSigPolicy-88" */
+203, /* "id-smime-mod-ets-eSigPolicy-97" */
+200, /* "id-smime-mod-ets-eSignature-88" */
+201, /* "id-smime-mod-ets-eSignature-97" */
+199, /* "id-smime-mod-msg-v3" */
+198, /* "id-smime-mod-oid" */
+194, /* "id-smime-spq" */
+250, /* "id-smime-spq-ets-sqt-unotice" */
+249, /* "id-smime-spq-ets-sqt-uri" */
+34, /* "idea-cbc" */
+35, /* "idea-cfb" */
+36, /* "idea-ecb" */
+46, /* "idea-ofb" */
+676, /* "identified-organization" */
+461, /* "info" */
+101, /* "initials" */
+869, /* "internationaliSDNNumber" */
+749, /* "ipsec3" */
+750, /* "ipsec4" */
+181, /* "iso" */
+623, /* "issuer capabilities" */
+645, /* "itu-t" */
+492, /* "janetMailbox" */
+646, /* "joint-iso-itu-t" */
+150, /* "keyBag" */
+773, /* "kisa" */
+477, /* "lastModifiedBy" */
+476, /* "lastModifiedTime" */
+157, /* "localKeyID" */
+15, /* "localityName" */
+480, /* "mXRecord" */
+493, /* "mailPreferenceOption" */
+467, /* "manager" */
+ 3, /* "md2" */
+ 7, /* "md2WithRSAEncryption" */
+257, /* "md4" */
+396, /* "md4WithRSAEncryption" */
+ 4, /* "md5" */
+114, /* "md5-sha1" */
+104, /* "md5WithRSA" */
+ 8, /* "md5WithRSAEncryption" */
+95, /* "mdc2" */
+96, /* "mdc2WithRSA" */
+875, /* "member" */
+602, /* "merchant initiated auth" */
+514, /* "message extensions" */
+51, /* "messageDigest" */
+911, /* "mgf1" */
+506, /* "mime-mhs-bodies" */
+505, /* "mime-mhs-headings" */
+488, /* "mobileTelephoneNumber" */
+481, /* "nSRecord" */
+173, /* "name" */
+681, /* "onBasis" */
+379, /* "org" */
+17, /* "organizationName" */
+491, /* "organizationalStatus" */
+18, /* "organizationalUnitName" */
+475, /* "otherMailbox" */
+876, /* "owner" */
+935, /* "pSpecified" */
+489, /* "pagerTelephoneNumber" */
+782, /* "password based MAC" */
+374, /* "path" */
+621, /* "payment gateway capabilities" */
+ 9, /* "pbeWithMD2AndDES-CBC" */
+168, /* "pbeWithMD2AndRC2-CBC" */
+112, /* "pbeWithMD5AndCast5CBC" */
+10, /* "pbeWithMD5AndDES-CBC" */
+169, /* "pbeWithMD5AndRC2-CBC" */
+148, /* "pbeWithSHA1And128BitRC2-CBC" */
+144, /* "pbeWithSHA1And128BitRC4" */
+147, /* "pbeWithSHA1And2-KeyTripleDES-CBC" */
+146, /* "pbeWithSHA1And3-KeyTripleDES-CBC" */
+149, /* "pbeWithSHA1And40BitRC2-CBC" */
+145, /* "pbeWithSHA1And40BitRC4" */
+170, /* "pbeWithSHA1AndDES-CBC" */
+68, /* "pbeWithSHA1AndRC2-CBC" */
+499, /* "personalSignature" */
+487, /* "personalTitle" */
+464, /* "photo" */
+863, /* "physicalDeliveryOfficeName" */
+437, /* "pilot" */
+439, /* "pilotAttributeSyntax" */
+438, /* "pilotAttributeType" */
+479, /* "pilotAttributeType27" */
+456, /* "pilotDSA" */
+441, /* "pilotGroups" */
+444, /* "pilotObject" */
+440, /* "pilotObjectClass" */
+455, /* "pilotOrganization" */
+445, /* "pilotPerson" */
+186, /* "pkcs1" */
+27, /* "pkcs3" */
+187, /* "pkcs5" */
+20, /* "pkcs7" */
+21, /* "pkcs7-data" */
+25, /* "pkcs7-digestData" */
+26, /* "pkcs7-encryptedData" */
+23, /* "pkcs7-envelopedData" */
+24, /* "pkcs7-signedAndEnvelopedData" */
+22, /* "pkcs7-signedData" */
+151, /* "pkcs8ShroudedKeyBag" */
+47, /* "pkcs9" */
+862, /* "postOfficeBox" */
+861, /* "postalAddress" */
+661, /* "postalCode" */
+683, /* "ppBasis" */
+872, /* "preferredDeliveryMethod" */
+873, /* "presentationAddress" */
+406, /* "prime-field" */
+409, /* "prime192v1" */
+410, /* "prime192v2" */
+411, /* "prime192v3" */
+412, /* "prime239v1" */
+413, /* "prime239v2" */
+414, /* "prime239v3" */
+415, /* "prime256v1" */
+886, /* "protocolInformation" */
+510, /* "pseudonym" */
+435, /* "pss" */
+286, /* "qcStatements" */
+457, /* "qualityLabelledData" */
+450, /* "rFC822localPart" */
+98, /* "rc2-40-cbc" */
+166, /* "rc2-64-cbc" */
+37, /* "rc2-cbc" */
+39, /* "rc2-cfb" */
+38, /* "rc2-ecb" */
+40, /* "rc2-ofb" */
+ 5, /* "rc4" */
+97, /* "rc4-40" */
+915, /* "rc4-hmac-md5" */
+120, /* "rc5-cbc" */
+122, /* "rc5-cfb" */
+121, /* "rc5-ecb" */
+123, /* "rc5-ofb" */
+870, /* "registeredAddress" */
+460, /* "rfc822Mailbox" */
+117, /* "ripemd160" */
+119, /* "ripemd160WithRSA" */
+400, /* "role" */
+877, /* "roleOccupant" */
+448, /* "room" */
+463, /* "roomNumber" */
+19, /* "rsa" */
+ 6, /* "rsaEncryption" */
+644, /* "rsaOAEPEncryptionSET" */
+377, /* "rsaSignature" */
+919, /* "rsaesOaep" */
+912, /* "rsassaPss" */
+124, /* "run length compression" */
+482, /* "sOARecord" */
+155, /* "safeContentsBag" */
+291, /* "sbgp-autonomousSysNum" */
+290, /* "sbgp-ipAddrBlock" */
+292, /* "sbgp-routerIdentifier" */
+159, /* "sdsiCertificate" */
+859, /* "searchGuide" */
+704, /* "secp112r1" */
+705, /* "secp112r2" */
+706, /* "secp128r1" */
+707, /* "secp128r2" */
+708, /* "secp160k1" */
+709, /* "secp160r1" */
+710, /* "secp160r2" */
+711, /* "secp192k1" */
+712, /* "secp224k1" */
+713, /* "secp224r1" */
+714, /* "secp256k1" */
+715, /* "secp384r1" */
+716, /* "secp521r1" */
+154, /* "secretBag" */
+474, /* "secretary" */
+717, /* "sect113r1" */
+718, /* "sect113r2" */
+719, /* "sect131r1" */
+720, /* "sect131r2" */
+721, /* "sect163k1" */
+722, /* "sect163r1" */
+723, /* "sect163r2" */
+724, /* "sect193r1" */
+725, /* "sect193r2" */
+726, /* "sect233k1" */
+727, /* "sect233r1" */
+728, /* "sect239k1" */
+729, /* "sect283k1" */
+730, /* "sect283r1" */
+731, /* "sect409k1" */
+732, /* "sect409r1" */
+733, /* "sect571k1" */
+734, /* "sect571r1" */
+635, /* "secure device signature" */
+878, /* "seeAlso" */
+777, /* "seed-cbc" */
+779, /* "seed-cfb" */
+776, /* "seed-ecb" */
+778, /* "seed-ofb" */
+105, /* "serialNumber" */
+625, /* "set-addPolicy" */
+515, /* "set-attr" */
+518, /* "set-brand" */
+638, /* "set-brand-AmericanExpress" */
+637, /* "set-brand-Diners" */
+636, /* "set-brand-IATA-ATA" */
+639, /* "set-brand-JCB" */
+641, /* "set-brand-MasterCard" */
+642, /* "set-brand-Novus" */
+640, /* "set-brand-Visa" */
+516, /* "set-policy" */
+607, /* "set-policy-root" */
+624, /* "set-rootKeyThumb" */
+620, /* "setAttr-Cert" */
+628, /* "setAttr-IssCap-CVM" */
+630, /* "setAttr-IssCap-Sig" */
+629, /* "setAttr-IssCap-T2" */
+627, /* "setAttr-Token-B0Prime" */
+626, /* "setAttr-Token-EMV" */
+622, /* "setAttr-TokenType" */
+619, /* "setCext-IssuerCapabilities" */
+615, /* "setCext-PGWYcapabilities" */
+616, /* "setCext-TokenIdentifier" */
+618, /* "setCext-TokenType" */
+617, /* "setCext-Track2Data" */
+611, /* "setCext-cCertRequired" */
+609, /* "setCext-certType" */
+608, /* "setCext-hashedRoot" */
+610, /* "setCext-merchData" */
+613, /* "setCext-setExt" */
+614, /* "setCext-setQualf" */
+612, /* "setCext-tunneling" */
+540, /* "setct-AcqCardCodeMsg" */
+576, /* "setct-AcqCardCodeMsgTBE" */
+570, /* "setct-AuthReqTBE" */
+534, /* "setct-AuthReqTBS" */
+527, /* "setct-AuthResBaggage" */
+571, /* "setct-AuthResTBE" */
+572, /* "setct-AuthResTBEX" */
+535, /* "setct-AuthResTBS" */
+536, /* "setct-AuthResTBSX" */
+528, /* "setct-AuthRevReqBaggage" */
+577, /* "setct-AuthRevReqTBE" */
+541, /* "setct-AuthRevReqTBS" */
+529, /* "setct-AuthRevResBaggage" */
+542, /* "setct-AuthRevResData" */
+578, /* "setct-AuthRevResTBE" */
+579, /* "setct-AuthRevResTBEB" */
+543, /* "setct-AuthRevResTBS" */
+573, /* "setct-AuthTokenTBE" */
+537, /* "setct-AuthTokenTBS" */
+600, /* "setct-BCIDistributionTBS" */
+558, /* "setct-BatchAdminReqData" */
+592, /* "setct-BatchAdminReqTBE" */
+559, /* "setct-BatchAdminResData" */
+593, /* "setct-BatchAdminResTBE" */
+599, /* "setct-CRLNotificationResTBS" */
+598, /* "setct-CRLNotificationTBS" */
+580, /* "setct-CapReqTBE" */
+581, /* "setct-CapReqTBEX" */
+544, /* "setct-CapReqTBS" */
+545, /* "setct-CapReqTBSX" */
+546, /* "setct-CapResData" */
+582, /* "setct-CapResTBE" */
+583, /* "setct-CapRevReqTBE" */
+584, /* "setct-CapRevReqTBEX" */
+547, /* "setct-CapRevReqTBS" */
+548, /* "setct-CapRevReqTBSX" */
+549, /* "setct-CapRevResData" */
+585, /* "setct-CapRevResTBE" */
+538, /* "setct-CapTokenData" */
+530, /* "setct-CapTokenSeq" */
+574, /* "setct-CapTokenTBE" */
+575, /* "setct-CapTokenTBEX" */
+539, /* "setct-CapTokenTBS" */
+560, /* "setct-CardCInitResTBS" */
+566, /* "setct-CertInqReqTBS" */
+563, /* "setct-CertReqData" */
+595, /* "setct-CertReqTBE" */
+596, /* "setct-CertReqTBEX" */
+564, /* "setct-CertReqTBS" */
+565, /* "setct-CertResData" */
+597, /* "setct-CertResTBE" */
+586, /* "setct-CredReqTBE" */
+587, /* "setct-CredReqTBEX" */
+550, /* "setct-CredReqTBS" */
+551, /* "setct-CredReqTBSX" */
+552, /* "setct-CredResData" */
+588, /* "setct-CredResTBE" */
+589, /* "setct-CredRevReqTBE" */
+590, /* "setct-CredRevReqTBEX" */
+553, /* "setct-CredRevReqTBS" */
+554, /* "setct-CredRevReqTBSX" */
+555, /* "setct-CredRevResData" */
+591, /* "setct-CredRevResTBE" */
+567, /* "setct-ErrorTBS" */
+526, /* "setct-HODInput" */
+561, /* "setct-MeAqCInitResTBS" */
+522, /* "setct-OIData" */
+519, /* "setct-PANData" */
+521, /* "setct-PANOnly" */
+520, /* "setct-PANToken" */
+556, /* "setct-PCertReqData" */
+557, /* "setct-PCertResTBS" */
+523, /* "setct-PI" */
+532, /* "setct-PI-TBS" */
+524, /* "setct-PIData" */
+525, /* "setct-PIDataUnsigned" */
+568, /* "setct-PIDualSignedTBE" */
+569, /* "setct-PIUnsignedTBE" */
+531, /* "setct-PInitResData" */
+533, /* "setct-PResData" */
+594, /* "setct-RegFormReqTBE" */
+562, /* "setct-RegFormResTBS" */
+604, /* "setext-pinAny" */
+603, /* "setext-pinSecure" */
+605, /* "setext-track2" */
+41, /* "sha" */
+64, /* "sha1" */
+115, /* "sha1WithRSA" */
+65, /* "sha1WithRSAEncryption" */
+675, /* "sha224" */
+671, /* "sha224WithRSAEncryption" */
+672, /* "sha256" */
+668, /* "sha256WithRSAEncryption" */
+673, /* "sha384" */
+669, /* "sha384WithRSAEncryption" */
+674, /* "sha512" */
+670, /* "sha512WithRSAEncryption" */
+42, /* "shaWithRSAEncryption" */
+52, /* "signingTime" */
+454, /* "simpleSecurityObject" */
+496, /* "singleLevelQuality" */
+16, /* "stateOrProvinceName" */
+660, /* "streetAddress" */
+498, /* "subtreeMaximumQuality" */
+497, /* "subtreeMinimumQuality" */
+890, /* "supportedAlgorithms" */
+874, /* "supportedApplicationContext" */
+100, /* "surname" */
+864, /* "telephoneNumber" */
+866, /* "teletexTerminalIdentifier" */
+865, /* "telexNumber" */
+459, /* "textEncodedORAddress" */
+293, /* "textNotice" */
+106, /* "title" */
+682, /* "tpBasis" */
+436, /* "ucl" */
+ 0, /* "undefined" */
+888, /* "uniqueMember" */
+55, /* "unstructuredAddress" */
+49, /* "unstructuredName" */
+880, /* "userCertificate" */
+465, /* "userClass" */
+458, /* "userId" */
+879, /* "userPassword" */
+373, /* "valid" */
+678, /* "wap" */
+679, /* "wap-wsg" */
+735, /* "wap-wsg-idm-ecid-wtls1" */
+743, /* "wap-wsg-idm-ecid-wtls10" */
+744, /* "wap-wsg-idm-ecid-wtls11" */
+745, /* "wap-wsg-idm-ecid-wtls12" */
+736, /* "wap-wsg-idm-ecid-wtls3" */
+737, /* "wap-wsg-idm-ecid-wtls4" */
+738, /* "wap-wsg-idm-ecid-wtls5" */
+739, /* "wap-wsg-idm-ecid-wtls6" */
+740, /* "wap-wsg-idm-ecid-wtls7" */
+741, /* "wap-wsg-idm-ecid-wtls8" */
+742, /* "wap-wsg-idm-ecid-wtls9" */
+804, /* "whirlpool" */
+868, /* "x121Address" */
+503, /* "x500UniqueIdentifier" */
+158, /* "x509Certificate" */
+160, /* "x509Crl" */
+125, /* "zlib compression" */
+};
+
+static const unsigned int kNIDsInOIDOrder[NUM_OBJ]={
+ 0, /* OBJ_undef 0 */
+393, /* OBJ_joint_iso_ccitt OBJ_joint_iso_itu_t */
+404, /* OBJ_ccitt OBJ_itu_t */
+645, /* OBJ_itu_t 0 */
+434, /* OBJ_data 0 9 */
+181, /* OBJ_iso 1 */
+182, /* OBJ_member_body 1 2 */
+379, /* OBJ_org 1 3 */
+676, /* OBJ_identified_organization 1 3 */
+646, /* OBJ_joint_iso_itu_t 2 */
+11, /* OBJ_X500 2 5 */
+647, /* OBJ_international_organizations 2 23 */
+380, /* OBJ_dod 1 3 6 */
+12, /* OBJ_X509 2 5 4 */
+378, /* OBJ_X500algorithms 2 5 8 */
+81, /* OBJ_id_ce 2 5 29 */
+512, /* OBJ_id_set 2 23 42 */
+678, /* OBJ_wap 2 23 43 */
+435, /* OBJ_pss 0 9 2342 */
+183, /* OBJ_ISO_US 1 2 840 */
+381, /* OBJ_iana 1 3 6 1 */
+677, /* OBJ_certicom_arc 1 3 132 */
+394, /* OBJ_selected_attribute_types 2 5 1 5 */
+13, /* OBJ_commonName 2 5 4 3 */
+100, /* OBJ_surname 2 5 4 4 */
+105, /* OBJ_serialNumber 2 5 4 5 */
+14, /* OBJ_countryName 2 5 4 6 */
+15, /* OBJ_localityName 2 5 4 7 */
+16, /* OBJ_stateOrProvinceName 2 5 4 8 */
+660, /* OBJ_streetAddress 2 5 4 9 */
+17, /* OBJ_organizationName 2 5 4 10 */
+18, /* OBJ_organizationalUnitName 2 5 4 11 */
+106, /* OBJ_title 2 5 4 12 */
+107, /* OBJ_description 2 5 4 13 */
+859, /* OBJ_searchGuide 2 5 4 14 */
+860, /* OBJ_businessCategory 2 5 4 15 */
+861, /* OBJ_postalAddress 2 5 4 16 */
+661, /* OBJ_postalCode 2 5 4 17 */
+862, /* OBJ_postOfficeBox 2 5 4 18 */
+863, /* OBJ_physicalDeliveryOfficeName 2 5 4 19 */
+864, /* OBJ_telephoneNumber 2 5 4 20 */
+865, /* OBJ_telexNumber 2 5 4 21 */
+866, /* OBJ_teletexTerminalIdentifier 2 5 4 22 */
+867, /* OBJ_facsimileTelephoneNumber 2 5 4 23 */
+868, /* OBJ_x121Address 2 5 4 24 */
+869, /* OBJ_internationaliSDNNumber 2 5 4 25 */
+870, /* OBJ_registeredAddress 2 5 4 26 */
+871, /* OBJ_destinationIndicator 2 5 4 27 */
+872, /* OBJ_preferredDeliveryMethod 2 5 4 28 */
+873, /* OBJ_presentationAddress 2 5 4 29 */
+874, /* OBJ_supportedApplicationContext 2 5 4 30 */
+875, /* OBJ_member 2 5 4 31 */
+876, /* OBJ_owner 2 5 4 32 */
+877, /* OBJ_roleOccupant 2 5 4 33 */
+878, /* OBJ_seeAlso 2 5 4 34 */
+879, /* OBJ_userPassword 2 5 4 35 */
+880, /* OBJ_userCertificate 2 5 4 36 */
+881, /* OBJ_cACertificate 2 5 4 37 */
+882, /* OBJ_authorityRevocationList 2 5 4 38 */
+883, /* OBJ_certificateRevocationList 2 5 4 39 */
+884, /* OBJ_crossCertificatePair 2 5 4 40 */
+173, /* OBJ_name 2 5 4 41 */
+99, /* OBJ_givenName 2 5 4 42 */
+101, /* OBJ_initials 2 5 4 43 */
+509, /* OBJ_generationQualifier 2 5 4 44 */
+503, /* OBJ_x500UniqueIdentifier 2 5 4 45 */
+174, /* OBJ_dnQualifier 2 5 4 46 */
+885, /* OBJ_enhancedSearchGuide 2 5 4 47 */
+886, /* OBJ_protocolInformation 2 5 4 48 */
+887, /* OBJ_distinguishedName 2 5 4 49 */
+888, /* OBJ_uniqueMember 2 5 4 50 */
+889, /* OBJ_houseIdentifier 2 5 4 51 */
+890, /* OBJ_supportedAlgorithms 2 5 4 52 */
+891, /* OBJ_deltaRevocationList 2 5 4 53 */
+892, /* OBJ_dmdName 2 5 4 54 */
+510, /* OBJ_pseudonym 2 5 4 65 */
+400, /* OBJ_role 2 5 4 72 */
+769, /* OBJ_subject_directory_attributes 2 5 29 9 */
+82, /* OBJ_subject_key_identifier 2 5 29 14 */
+83, /* OBJ_key_usage 2 5 29 15 */
+84, /* OBJ_private_key_usage_period 2 5 29 16 */
+85, /* OBJ_subject_alt_name 2 5 29 17 */
+86, /* OBJ_issuer_alt_name 2 5 29 18 */
+87, /* OBJ_basic_constraints 2 5 29 19 */
+88, /* OBJ_crl_number 2 5 29 20 */
+141, /* OBJ_crl_reason 2 5 29 21 */
+430, /* OBJ_hold_instruction_code 2 5 29 23 */
+142, /* OBJ_invalidity_date 2 5 29 24 */
+140, /* OBJ_delta_crl 2 5 29 27 */
+770, /* OBJ_issuing_distribution_point 2 5 29 28 */
+771, /* OBJ_certificate_issuer 2 5 29 29 */
+666, /* OBJ_name_constraints 2 5 29 30 */
+103, /* OBJ_crl_distribution_points 2 5 29 31 */
+89, /* OBJ_certificate_policies 2 5 29 32 */
+747, /* OBJ_policy_mappings 2 5 29 33 */
+90, /* OBJ_authority_key_identifier 2 5 29 35 */
+401, /* OBJ_policy_constraints 2 5 29 36 */
+126, /* OBJ_ext_key_usage 2 5 29 37 */
+857, /* OBJ_freshest_crl 2 5 29 46 */
+748, /* OBJ_inhibit_any_policy 2 5 29 54 */
+402, /* OBJ_target_information 2 5 29 55 */
+403, /* OBJ_no_rev_avail 2 5 29 56 */
+513, /* OBJ_set_ctype 2 23 42 0 */
+514, /* OBJ_set_msgExt 2 23 42 1 */
+515, /* OBJ_set_attr 2 23 42 3 */
+516, /* OBJ_set_policy 2 23 42 5 */
+517, /* OBJ_set_certExt 2 23 42 7 */
+518, /* OBJ_set_brand 2 23 42 8 */
+679, /* OBJ_wap_wsg 2 23 43 1 */
+382, /* OBJ_Directory 1 3 6 1 1 */
+383, /* OBJ_Management 1 3 6 1 2 */
+384, /* OBJ_Experimental 1 3 6 1 3 */
+385, /* OBJ_Private 1 3 6 1 4 */
+386, /* OBJ_Security 1 3 6 1 5 */
+387, /* OBJ_SNMPv2 1 3 6 1 6 */
+388, /* OBJ_Mail 1 3 6 1 7 */
+376, /* OBJ_algorithm 1 3 14 3 2 */
+395, /* OBJ_clearance 2 5 1 5 55 */
+19, /* OBJ_rsa 2 5 8 1 1 */
+96, /* OBJ_mdc2WithRSA 2 5 8 3 100 */
+95, /* OBJ_mdc2 2 5 8 3 101 */
+746, /* OBJ_any_policy 2 5 29 32 0 */
+910, /* OBJ_anyExtendedKeyUsage 2 5 29 37 0 */
+519, /* OBJ_setct_PANData 2 23 42 0 0 */
+520, /* OBJ_setct_PANToken 2 23 42 0 1 */
+521, /* OBJ_setct_PANOnly 2 23 42 0 2 */
+522, /* OBJ_setct_OIData 2 23 42 0 3 */
+523, /* OBJ_setct_PI 2 23 42 0 4 */
+524, /* OBJ_setct_PIData 2 23 42 0 5 */
+525, /* OBJ_setct_PIDataUnsigned 2 23 42 0 6 */
+526, /* OBJ_setct_HODInput 2 23 42 0 7 */
+527, /* OBJ_setct_AuthResBaggage 2 23 42 0 8 */
+528, /* OBJ_setct_AuthRevReqBaggage 2 23 42 0 9 */
+529, /* OBJ_setct_AuthRevResBaggage 2 23 42 0 10 */
+530, /* OBJ_setct_CapTokenSeq 2 23 42 0 11 */
+531, /* OBJ_setct_PInitResData 2 23 42 0 12 */
+532, /* OBJ_setct_PI_TBS 2 23 42 0 13 */
+533, /* OBJ_setct_PResData 2 23 42 0 14 */
+534, /* OBJ_setct_AuthReqTBS 2 23 42 0 16 */
+535, /* OBJ_setct_AuthResTBS 2 23 42 0 17 */
+536, /* OBJ_setct_AuthResTBSX 2 23 42 0 18 */
+537, /* OBJ_setct_AuthTokenTBS 2 23 42 0 19 */
+538, /* OBJ_setct_CapTokenData 2 23 42 0 20 */
+539, /* OBJ_setct_CapTokenTBS 2 23 42 0 21 */
+540, /* OBJ_setct_AcqCardCodeMsg 2 23 42 0 22 */
+541, /* OBJ_setct_AuthRevReqTBS 2 23 42 0 23 */
+542, /* OBJ_setct_AuthRevResData 2 23 42 0 24 */
+543, /* OBJ_setct_AuthRevResTBS 2 23 42 0 25 */
+544, /* OBJ_setct_CapReqTBS 2 23 42 0 26 */
+545, /* OBJ_setct_CapReqTBSX 2 23 42 0 27 */
+546, /* OBJ_setct_CapResData 2 23 42 0 28 */
+547, /* OBJ_setct_CapRevReqTBS 2 23 42 0 29 */
+548, /* OBJ_setct_CapRevReqTBSX 2 23 42 0 30 */
+549, /* OBJ_setct_CapRevResData 2 23 42 0 31 */
+550, /* OBJ_setct_CredReqTBS 2 23 42 0 32 */
+551, /* OBJ_setct_CredReqTBSX 2 23 42 0 33 */
+552, /* OBJ_setct_CredResData 2 23 42 0 34 */
+553, /* OBJ_setct_CredRevReqTBS 2 23 42 0 35 */
+554, /* OBJ_setct_CredRevReqTBSX 2 23 42 0 36 */
+555, /* OBJ_setct_CredRevResData 2 23 42 0 37 */
+556, /* OBJ_setct_PCertReqData 2 23 42 0 38 */
+557, /* OBJ_setct_PCertResTBS 2 23 42 0 39 */
+558, /* OBJ_setct_BatchAdminReqData 2 23 42 0 40 */
+559, /* OBJ_setct_BatchAdminResData 2 23 42 0 41 */
+560, /* OBJ_setct_CardCInitResTBS 2 23 42 0 42 */
+561, /* OBJ_setct_MeAqCInitResTBS 2 23 42 0 43 */
+562, /* OBJ_setct_RegFormResTBS 2 23 42 0 44 */
+563, /* OBJ_setct_CertReqData 2 23 42 0 45 */
+564, /* OBJ_setct_CertReqTBS 2 23 42 0 46 */
+565, /* OBJ_setct_CertResData 2 23 42 0 47 */
+566, /* OBJ_setct_CertInqReqTBS 2 23 42 0 48 */
+567, /* OBJ_setct_ErrorTBS 2 23 42 0 49 */
+568, /* OBJ_setct_PIDualSignedTBE 2 23 42 0 50 */
+569, /* OBJ_setct_PIUnsignedTBE 2 23 42 0 51 */
+570, /* OBJ_setct_AuthReqTBE 2 23 42 0 52 */
+571, /* OBJ_setct_AuthResTBE 2 23 42 0 53 */
+572, /* OBJ_setct_AuthResTBEX 2 23 42 0 54 */
+573, /* OBJ_setct_AuthTokenTBE 2 23 42 0 55 */
+574, /* OBJ_setct_CapTokenTBE 2 23 42 0 56 */
+575, /* OBJ_setct_CapTokenTBEX 2 23 42 0 57 */
+576, /* OBJ_setct_AcqCardCodeMsgTBE 2 23 42 0 58 */
+577, /* OBJ_setct_AuthRevReqTBE 2 23 42 0 59 */
+578, /* OBJ_setct_AuthRevResTBE 2 23 42 0 60 */
+579, /* OBJ_setct_AuthRevResTBEB 2 23 42 0 61 */
+580, /* OBJ_setct_CapReqTBE 2 23 42 0 62 */
+581, /* OBJ_setct_CapReqTBEX 2 23 42 0 63 */
+582, /* OBJ_setct_CapResTBE 2 23 42 0 64 */
+583, /* OBJ_setct_CapRevReqTBE 2 23 42 0 65 */
+584, /* OBJ_setct_CapRevReqTBEX 2 23 42 0 66 */
+585, /* OBJ_setct_CapRevResTBE 2 23 42 0 67 */
+586, /* OBJ_setct_CredReqTBE 2 23 42 0 68 */
+587, /* OBJ_setct_CredReqTBEX 2 23 42 0 69 */
+588, /* OBJ_setct_CredResTBE 2 23 42 0 70 */
+589, /* OBJ_setct_CredRevReqTBE 2 23 42 0 71 */
+590, /* OBJ_setct_CredRevReqTBEX 2 23 42 0 72 */
+591, /* OBJ_setct_CredRevResTBE 2 23 42 0 73 */
+592, /* OBJ_setct_BatchAdminReqTBE 2 23 42 0 74 */
+593, /* OBJ_setct_BatchAdminResTBE 2 23 42 0 75 */
+594, /* OBJ_setct_RegFormReqTBE 2 23 42 0 76 */
+595, /* OBJ_setct_CertReqTBE 2 23 42 0 77 */
+596, /* OBJ_setct_CertReqTBEX 2 23 42 0 78 */
+597, /* OBJ_setct_CertResTBE 2 23 42 0 79 */
+598, /* OBJ_setct_CRLNotificationTBS 2 23 42 0 80 */
+599, /* OBJ_setct_CRLNotificationResTBS 2 23 42 0 81 */
+600, /* OBJ_setct_BCIDistributionTBS 2 23 42 0 82 */
+601, /* OBJ_setext_genCrypt 2 23 42 1 1 */
+602, /* OBJ_setext_miAuth 2 23 42 1 3 */
+603, /* OBJ_setext_pinSecure 2 23 42 1 4 */
+604, /* OBJ_setext_pinAny 2 23 42 1 5 */
+605, /* OBJ_setext_track2 2 23 42 1 7 */
+606, /* OBJ_setext_cv 2 23 42 1 8 */
+620, /* OBJ_setAttr_Cert 2 23 42 3 0 */
+621, /* OBJ_setAttr_PGWYcap 2 23 42 3 1 */
+622, /* OBJ_setAttr_TokenType 2 23 42 3 2 */
+623, /* OBJ_setAttr_IssCap 2 23 42 3 3 */
+607, /* OBJ_set_policy_root 2 23 42 5 0 */
+608, /* OBJ_setCext_hashedRoot 2 23 42 7 0 */
+609, /* OBJ_setCext_certType 2 23 42 7 1 */
+610, /* OBJ_setCext_merchData 2 23 42 7 2 */
+611, /* OBJ_setCext_cCertRequired 2 23 42 7 3 */
+612, /* OBJ_setCext_tunneling 2 23 42 7 4 */
+613, /* OBJ_setCext_setExt 2 23 42 7 5 */
+614, /* OBJ_setCext_setQualf 2 23 42 7 6 */
+615, /* OBJ_setCext_PGWYcapabilities 2 23 42 7 7 */
+616, /* OBJ_setCext_TokenIdentifier 2 23 42 7 8 */
+617, /* OBJ_setCext_Track2Data 2 23 42 7 9 */
+618, /* OBJ_setCext_TokenType 2 23 42 7 10 */
+619, /* OBJ_setCext_IssuerCapabilities 2 23 42 7 11 */
+636, /* OBJ_set_brand_IATA_ATA 2 23 42 8 1 */
+640, /* OBJ_set_brand_Visa 2 23 42 8 4 */
+641, /* OBJ_set_brand_MasterCard 2 23 42 8 5 */
+637, /* OBJ_set_brand_Diners 2 23 42 8 30 */
+638, /* OBJ_set_brand_AmericanExpress 2 23 42 8 34 */
+639, /* OBJ_set_brand_JCB 2 23 42 8 35 */
+805, /* OBJ_cryptopro 1 2 643 2 2 */
+806, /* OBJ_cryptocom 1 2 643 2 9 */
+184, /* OBJ_X9_57 1 2 840 10040 */
+405, /* OBJ_ansi_X9_62 1 2 840 10045 */
+389, /* OBJ_Enterprises 1 3 6 1 4 1 */
+504, /* OBJ_mime_mhs 1 3 6 1 7 1 */
+104, /* OBJ_md5WithRSA 1 3 14 3 2 3 */
+29, /* OBJ_des_ecb 1 3 14 3 2 6 */
+31, /* OBJ_des_cbc 1 3 14 3 2 7 */
+45, /* OBJ_des_ofb64 1 3 14 3 2 8 */
+30, /* OBJ_des_cfb64 1 3 14 3 2 9 */
+377, /* OBJ_rsaSignature 1 3 14 3 2 11 */
+67, /* OBJ_dsa_2 1 3 14 3 2 12 */
+66, /* OBJ_dsaWithSHA 1 3 14 3 2 13 */
+42, /* OBJ_shaWithRSAEncryption 1 3 14 3 2 15 */
+32, /* OBJ_des_ede_ecb 1 3 14 3 2 17 */
+41, /* OBJ_sha 1 3 14 3 2 18 */
+64, /* OBJ_sha1 1 3 14 3 2 26 */
+70, /* OBJ_dsaWithSHA1_2 1 3 14 3 2 27 */
+115, /* OBJ_sha1WithRSA 1 3 14 3 2 29 */
+117, /* OBJ_ripemd160 1 3 36 3 2 1 */
+143, /* OBJ_sxnet 1 3 101 1 4 1 */
+721, /* OBJ_sect163k1 1 3 132 0 1 */
+722, /* OBJ_sect163r1 1 3 132 0 2 */
+728, /* OBJ_sect239k1 1 3 132 0 3 */
+717, /* OBJ_sect113r1 1 3 132 0 4 */
+718, /* OBJ_sect113r2 1 3 132 0 5 */
+704, /* OBJ_secp112r1 1 3 132 0 6 */
+705, /* OBJ_secp112r2 1 3 132 0 7 */
+709, /* OBJ_secp160r1 1 3 132 0 8 */
+708, /* OBJ_secp160k1 1 3 132 0 9 */
+714, /* OBJ_secp256k1 1 3 132 0 10 */
+723, /* OBJ_sect163r2 1 3 132 0 15 */
+729, /* OBJ_sect283k1 1 3 132 0 16 */
+730, /* OBJ_sect283r1 1 3 132 0 17 */
+719, /* OBJ_sect131r1 1 3 132 0 22 */
+720, /* OBJ_sect131r2 1 3 132 0 23 */
+724, /* OBJ_sect193r1 1 3 132 0 24 */
+725, /* OBJ_sect193r2 1 3 132 0 25 */
+726, /* OBJ_sect233k1 1 3 132 0 26 */
+727, /* OBJ_sect233r1 1 3 132 0 27 */
+706, /* OBJ_secp128r1 1 3 132 0 28 */
+707, /* OBJ_secp128r2 1 3 132 0 29 */
+710, /* OBJ_secp160r2 1 3 132 0 30 */
+711, /* OBJ_secp192k1 1 3 132 0 31 */
+712, /* OBJ_secp224k1 1 3 132 0 32 */
+713, /* OBJ_secp224r1 1 3 132 0 33 */
+715, /* OBJ_secp384r1 1 3 132 0 34 */
+716, /* OBJ_secp521r1 1 3 132 0 35 */
+731, /* OBJ_sect409k1 1 3 132 0 36 */
+732, /* OBJ_sect409r1 1 3 132 0 37 */
+733, /* OBJ_sect571k1 1 3 132 0 38 */
+734, /* OBJ_sect571r1 1 3 132 0 39 */
+624, /* OBJ_set_rootKeyThumb 2 23 42 3 0 0 */
+625, /* OBJ_set_addPolicy 2 23 42 3 0 1 */
+626, /* OBJ_setAttr_Token_EMV 2 23 42 3 2 1 */
+627, /* OBJ_setAttr_Token_B0Prime 2 23 42 3 2 2 */
+628, /* OBJ_setAttr_IssCap_CVM 2 23 42 3 3 3 */
+629, /* OBJ_setAttr_IssCap_T2 2 23 42 3 3 4 */
+630, /* OBJ_setAttr_IssCap_Sig 2 23 42 3 3 5 */
+642, /* OBJ_set_brand_Novus 2 23 42 8 6011 */
+735, /* OBJ_wap_wsg_idm_ecid_wtls1 2 23 43 1 4 1 */
+736, /* OBJ_wap_wsg_idm_ecid_wtls3 2 23 43 1 4 3 */
+737, /* OBJ_wap_wsg_idm_ecid_wtls4 2 23 43 1 4 4 */
+738, /* OBJ_wap_wsg_idm_ecid_wtls5 2 23 43 1 4 5 */
+739, /* OBJ_wap_wsg_idm_ecid_wtls6 2 23 43 1 4 6 */
+740, /* OBJ_wap_wsg_idm_ecid_wtls7 2 23 43 1 4 7 */
+741, /* OBJ_wap_wsg_idm_ecid_wtls8 2 23 43 1 4 8 */
+742, /* OBJ_wap_wsg_idm_ecid_wtls9 2 23 43 1 4 9 */
+743, /* OBJ_wap_wsg_idm_ecid_wtls10 2 23 43 1 4 10 */
+744, /* OBJ_wap_wsg_idm_ecid_wtls11 2 23 43 1 4 11 */
+745, /* OBJ_wap_wsg_idm_ecid_wtls12 2 23 43 1 4 12 */
+804, /* OBJ_whirlpool 1 0 10118 3 0 55 */
+124, /* OBJ_rle_compression 1 1 1 1 666 1 */
+773, /* OBJ_kisa 1 2 410 200004 */
+807, /* OBJ_id_GostR3411_94_with_GostR3410_2001 1 2 643 2 2 3 */
+808, /* OBJ_id_GostR3411_94_with_GostR3410_94 1 2 643 2 2 4 */
+809, /* OBJ_id_GostR3411_94 1 2 643 2 2 9 */
+810, /* OBJ_id_HMACGostR3411_94 1 2 643 2 2 10 */
+811, /* OBJ_id_GostR3410_2001 1 2 643 2 2 19 */
+812, /* OBJ_id_GostR3410_94 1 2 643 2 2 20 */
+813, /* OBJ_id_Gost28147_89 1 2 643 2 2 21 */
+815, /* OBJ_id_Gost28147_89_MAC 1 2 643 2 2 22 */
+816, /* OBJ_id_GostR3411_94_prf 1 2 643 2 2 23 */
+817, /* OBJ_id_GostR3410_2001DH 1 2 643 2 2 98 */
+818, /* OBJ_id_GostR3410_94DH 1 2 643 2 2 99 */
+ 1, /* OBJ_rsadsi 1 2 840 113549 */
+185, /* OBJ_X9cm 1 2 840 10040 4 */
+127, /* OBJ_id_pkix 1 3 6 1 5 5 7 */
+505, /* OBJ_mime_mhs_headings 1 3 6 1 7 1 1 */
+506, /* OBJ_mime_mhs_bodies 1 3 6 1 7 1 2 */
+119, /* OBJ_ripemd160WithRSA 1 3 36 3 3 1 2 */
+940, /* OBJ_dhSinglePass_stdDH_sha224kdf_scheme 1 3 132 1 11 0 */
+941, /* OBJ_dhSinglePass_stdDH_sha256kdf_scheme 1 3 132 1 11 1 */
+942, /* OBJ_dhSinglePass_stdDH_sha384kdf_scheme 1 3 132 1 11 2 */
+943, /* OBJ_dhSinglePass_stdDH_sha512kdf_scheme 1 3 132 1 11 3 */
+945, /* OBJ_dhSinglePass_cofactorDH_sha224kdf_scheme 1 3 132 1 14 0 */
+946, /* OBJ_dhSinglePass_cofactorDH_sha256kdf_scheme 1 3 132 1 14 1 */
+947, /* OBJ_dhSinglePass_cofactorDH_sha384kdf_scheme 1 3 132 1 14 2 */
+948, /* OBJ_dhSinglePass_cofactorDH_sha512kdf_scheme 1 3 132 1 14 3 */
+631, /* OBJ_setAttr_GenCryptgrm 2 23 42 3 3 3 1 */
+632, /* OBJ_setAttr_T2Enc 2 23 42 3 3 4 1 */
+633, /* OBJ_setAttr_T2cleartxt 2 23 42 3 3 4 2 */
+634, /* OBJ_setAttr_TokICCsig 2 23 42 3 3 5 1 */
+635, /* OBJ_setAttr_SecDevSig 2 23 42 3 3 5 2 */
+436, /* OBJ_ucl 0 9 2342 19200300 */
+820, /* OBJ_id_Gost28147_89_None_KeyMeshing 1 2 643 2 2 14 0 */
+819, /* OBJ_id_Gost28147_89_CryptoPro_KeyMeshing 1 2 643 2 2 14 1 */
+845, /* OBJ_id_GostR3410_94_a 1 2 643 2 2 20 1 */
+846, /* OBJ_id_GostR3410_94_aBis 1 2 643 2 2 20 2 */
+847, /* OBJ_id_GostR3410_94_b 1 2 643 2 2 20 3 */
+848, /* OBJ_id_GostR3410_94_bBis 1 2 643 2 2 20 4 */
+821, /* OBJ_id_GostR3411_94_TestParamSet 1 2 643 2 2 30 0 */
+822, /* OBJ_id_GostR3411_94_CryptoProParamSet 1 2 643 2 2 30 1 */
+823, /* OBJ_id_Gost28147_89_TestParamSet 1 2 643 2 2 31 0 */
+824, /* OBJ_id_Gost28147_89_CryptoPro_A_ParamSet 1 2 643 2 2 31 1 */
+825, /* OBJ_id_Gost28147_89_CryptoPro_B_ParamSet 1 2 643 2 2 31 2 */
+826, /* OBJ_id_Gost28147_89_CryptoPro_C_ParamSet 1 2 643 2 2 31 3 */
+827, /* OBJ_id_Gost28147_89_CryptoPro_D_ParamSet 1 2 643 2 2 31 4 */
+828, /* OBJ_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet 1 2 643 2 2 31 5 */
+829, /* OBJ_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet 1 2 643 2 2 31 6 */
+830, /* OBJ_id_Gost28147_89_CryptoPro_RIC_1_ParamSet 1 2 643 2 2 31 7 */
+831, /* OBJ_id_GostR3410_94_TestParamSet 1 2 643 2 2 32 0 */
+832, /* OBJ_id_GostR3410_94_CryptoPro_A_ParamSet 1 2 643 2 2 32 2 */
+833, /* OBJ_id_GostR3410_94_CryptoPro_B_ParamSet 1 2 643 2 2 32 3 */
+834, /* OBJ_id_GostR3410_94_CryptoPro_C_ParamSet 1 2 643 2 2 32 4 */
+835, /* OBJ_id_GostR3410_94_CryptoPro_D_ParamSet 1 2 643 2 2 32 5 */
+836, /* OBJ_id_GostR3410_94_CryptoPro_XchA_ParamSet 1 2 643 2 2 33 1 */
+837, /* OBJ_id_GostR3410_94_CryptoPro_XchB_ParamSet 1 2 643 2 2 33 2 */
+838, /* OBJ_id_GostR3410_94_CryptoPro_XchC_ParamSet 1 2 643 2 2 33 3 */
+839, /* OBJ_id_GostR3410_2001_TestParamSet 1 2 643 2 2 35 0 */
+840, /* OBJ_id_GostR3410_2001_CryptoPro_A_ParamSet 1 2 643 2 2 35 1 */
+841, /* OBJ_id_GostR3410_2001_CryptoPro_B_ParamSet 1 2 643 2 2 35 2 */
+842, /* OBJ_id_GostR3410_2001_CryptoPro_C_ParamSet 1 2 643 2 2 35 3 */
+843, /* OBJ_id_GostR3410_2001_CryptoPro_XchA_ParamSet 1 2 643 2 2 36 0 */
+844, /* OBJ_id_GostR3410_2001_CryptoPro_XchB_ParamSet 1 2 643 2 2 36 1 */
+ 2, /* OBJ_pkcs 1 2 840 113549 1 */
+431, /* OBJ_hold_instruction_none 1 2 840 10040 2 1 */
+432, /* OBJ_hold_instruction_call_issuer 1 2 840 10040 2 2 */
+433, /* OBJ_hold_instruction_reject 1 2 840 10040 2 3 */
+116, /* OBJ_dsa 1 2 840 10040 4 1 */
+113, /* OBJ_dsaWithSHA1 1 2 840 10040 4 3 */
+406, /* OBJ_X9_62_prime_field 1 2 840 10045 1 1 */
+407, /* OBJ_X9_62_characteristic_two_field 1 2 840 10045 1 2 */
+408, /* OBJ_X9_62_id_ecPublicKey 1 2 840 10045 2 1 */
+416, /* OBJ_ecdsa_with_SHA1 1 2 840 10045 4 1 */
+791, /* OBJ_ecdsa_with_Recommended 1 2 840 10045 4 2 */
+792, /* OBJ_ecdsa_with_Specified 1 2 840 10045 4 3 */
+920, /* OBJ_dhpublicnumber 1 2 840 10046 2 1 */
+258, /* OBJ_id_pkix_mod 1 3 6 1 5 5 7 0 */
+175, /* OBJ_id_pe 1 3 6 1 5 5 7 1 */
+259, /* OBJ_id_qt 1 3 6 1 5 5 7 2 */
+128, /* OBJ_id_kp 1 3 6 1 5 5 7 3 */
+260, /* OBJ_id_it 1 3 6 1 5 5 7 4 */
+261, /* OBJ_id_pkip 1 3 6 1 5 5 7 5 */
+262, /* OBJ_id_alg 1 3 6 1 5 5 7 6 */
+263, /* OBJ_id_cmc 1 3 6 1 5 5 7 7 */
+264, /* OBJ_id_on 1 3 6 1 5 5 7 8 */
+265, /* OBJ_id_pda 1 3 6 1 5 5 7 9 */
+266, /* OBJ_id_aca 1 3 6 1 5 5 7 10 */
+267, /* OBJ_id_qcs 1 3 6 1 5 5 7 11 */
+268, /* OBJ_id_cct 1 3 6 1 5 5 7 12 */
+662, /* OBJ_id_ppl 1 3 6 1 5 5 7 21 */
+176, /* OBJ_id_ad 1 3 6 1 5 5 7 48 */
+507, /* OBJ_id_hex_partial_message 1 3 6 1 7 1 1 1 */
+508, /* OBJ_id_hex_multipart_message 1 3 6 1 7 1 1 2 */
+57, /* OBJ_netscape 2 16 840 1 113730 */
+754, /* OBJ_camellia_128_ecb 0 3 4401 5 3 1 9 1 */
+766, /* OBJ_camellia_128_ofb128 0 3 4401 5 3 1 9 3 */
+757, /* OBJ_camellia_128_cfb128 0 3 4401 5 3 1 9 4 */
+755, /* OBJ_camellia_192_ecb 0 3 4401 5 3 1 9 21 */
+767, /* OBJ_camellia_192_ofb128 0 3 4401 5 3 1 9 23 */
+758, /* OBJ_camellia_192_cfb128 0 3 4401 5 3 1 9 24 */
+756, /* OBJ_camellia_256_ecb 0 3 4401 5 3 1 9 41 */
+768, /* OBJ_camellia_256_ofb128 0 3 4401 5 3 1 9 43 */
+759, /* OBJ_camellia_256_cfb128 0 3 4401 5 3 1 9 44 */
+437, /* OBJ_pilot 0 9 2342 19200300 100 */
+776, /* OBJ_seed_ecb 1 2 410 200004 1 3 */
+777, /* OBJ_seed_cbc 1 2 410 200004 1 4 */
+779, /* OBJ_seed_cfb128 1 2 410 200004 1 5 */
+778, /* OBJ_seed_ofb128 1 2 410 200004 1 6 */
+852, /* OBJ_id_GostR3411_94_with_GostR3410_94_cc 1 2 643 2 9 1 3 3 */
+853, /* OBJ_id_GostR3411_94_with_GostR3410_2001_cc 1 2 643 2 9 1 3 4 */
+850, /* OBJ_id_GostR3410_94_cc 1 2 643 2 9 1 5 3 */
+851, /* OBJ_id_GostR3410_2001_cc 1 2 643 2 9 1 5 4 */
+849, /* OBJ_id_Gost28147_89_cc 1 2 643 2 9 1 6 1 */
+854, /* OBJ_id_GostR3410_2001_ParamSet_cc 1 2 643 2 9 1 8 1 */
+186, /* OBJ_pkcs1 1 2 840 113549 1 1 */
+27, /* OBJ_pkcs3 1 2 840 113549 1 3 */
+187, /* OBJ_pkcs5 1 2 840 113549 1 5 */
+20, /* OBJ_pkcs7 1 2 840 113549 1 7 */
+47, /* OBJ_pkcs9 1 2 840 113549 1 9 */
+ 3, /* OBJ_md2 1 2 840 113549 2 2 */
+257, /* OBJ_md4 1 2 840 113549 2 4 */
+ 4, /* OBJ_md5 1 2 840 113549 2 5 */
+797, /* OBJ_hmacWithMD5 1 2 840 113549 2 6 */
+163, /* OBJ_hmacWithSHA1 1 2 840 113549 2 7 */
+798, /* OBJ_hmacWithSHA224 1 2 840 113549 2 8 */
+799, /* OBJ_hmacWithSHA256 1 2 840 113549 2 9 */
+800, /* OBJ_hmacWithSHA384 1 2 840 113549 2 10 */
+801, /* OBJ_hmacWithSHA512 1 2 840 113549 2 11 */
+37, /* OBJ_rc2_cbc 1 2 840 113549 3 2 */
+ 5, /* OBJ_rc4 1 2 840 113549 3 4 */
+44, /* OBJ_des_ede3_cbc 1 2 840 113549 3 7 */
+120, /* OBJ_rc5_cbc 1 2 840 113549 3 8 */
+643, /* OBJ_des_cdmf 1 2 840 113549 3 10 */
+680, /* OBJ_X9_62_id_characteristic_two_basis 1 2 840 10045 1 2 3 */
+684, /* OBJ_X9_62_c2pnb163v1 1 2 840 10045 3 0 1 */
+685, /* OBJ_X9_62_c2pnb163v2 1 2 840 10045 3 0 2 */
+686, /* OBJ_X9_62_c2pnb163v3 1 2 840 10045 3 0 3 */
+687, /* OBJ_X9_62_c2pnb176v1 1 2 840 10045 3 0 4 */
+688, /* OBJ_X9_62_c2tnb191v1 1 2 840 10045 3 0 5 */
+689, /* OBJ_X9_62_c2tnb191v2 1 2 840 10045 3 0 6 */
+690, /* OBJ_X9_62_c2tnb191v3 1 2 840 10045 3 0 7 */
+691, /* OBJ_X9_62_c2onb191v4 1 2 840 10045 3 0 8 */
+692, /* OBJ_X9_62_c2onb191v5 1 2 840 10045 3 0 9 */
+693, /* OBJ_X9_62_c2pnb208w1 1 2 840 10045 3 0 10 */
+694, /* OBJ_X9_62_c2tnb239v1 1 2 840 10045 3 0 11 */
+695, /* OBJ_X9_62_c2tnb239v2 1 2 840 10045 3 0 12 */
+696, /* OBJ_X9_62_c2tnb239v3 1 2 840 10045 3 0 13 */
+697, /* OBJ_X9_62_c2onb239v4 1 2 840 10045 3 0 14 */
+698, /* OBJ_X9_62_c2onb239v5 1 2 840 10045 3 0 15 */
+699, /* OBJ_X9_62_c2pnb272w1 1 2 840 10045 3 0 16 */
+700, /* OBJ_X9_62_c2pnb304w1 1 2 840 10045 3 0 17 */
+701, /* OBJ_X9_62_c2tnb359v1 1 2 840 10045 3 0 18 */
+702, /* OBJ_X9_62_c2pnb368w1 1 2 840 10045 3 0 19 */
+703, /* OBJ_X9_62_c2tnb431r1 1 2 840 10045 3 0 20 */
+409, /* OBJ_X9_62_prime192v1 1 2 840 10045 3 1 1 */
+410, /* OBJ_X9_62_prime192v2 1 2 840 10045 3 1 2 */
+411, /* OBJ_X9_62_prime192v3 1 2 840 10045 3 1 3 */
+412, /* OBJ_X9_62_prime239v1 1 2 840 10045 3 1 4 */
+413, /* OBJ_X9_62_prime239v2 1 2 840 10045 3 1 5 */
+414, /* OBJ_X9_62_prime239v3 1 2 840 10045 3 1 6 */
+415, /* OBJ_X9_62_prime256v1 1 2 840 10045 3 1 7 */
+793, /* OBJ_ecdsa_with_SHA224 1 2 840 10045 4 3 1 */
+794, /* OBJ_ecdsa_with_SHA256 1 2 840 10045 4 3 2 */
+795, /* OBJ_ecdsa_with_SHA384 1 2 840 10045 4 3 3 */
+796, /* OBJ_ecdsa_with_SHA512 1 2 840 10045 4 3 4 */
+269, /* OBJ_id_pkix1_explicit_88 1 3 6 1 5 5 7 0 1 */
+270, /* OBJ_id_pkix1_implicit_88 1 3 6 1 5 5 7 0 2 */
+271, /* OBJ_id_pkix1_explicit_93 1 3 6 1 5 5 7 0 3 */
+272, /* OBJ_id_pkix1_implicit_93 1 3 6 1 5 5 7 0 4 */
+273, /* OBJ_id_mod_crmf 1 3 6 1 5 5 7 0 5 */
+274, /* OBJ_id_mod_cmc 1 3 6 1 5 5 7 0 6 */
+275, /* OBJ_id_mod_kea_profile_88 1 3 6 1 5 5 7 0 7 */
+276, /* OBJ_id_mod_kea_profile_93 1 3 6 1 5 5 7 0 8 */
+277, /* OBJ_id_mod_cmp 1 3 6 1 5 5 7 0 9 */
+278, /* OBJ_id_mod_qualified_cert_88 1 3 6 1 5 5 7 0 10 */
+279, /* OBJ_id_mod_qualified_cert_93 1 3 6 1 5 5 7 0 11 */
+280, /* OBJ_id_mod_attribute_cert 1 3 6 1 5 5 7 0 12 */
+281, /* OBJ_id_mod_timestamp_protocol 1 3 6 1 5 5 7 0 13 */
+282, /* OBJ_id_mod_ocsp 1 3 6 1 5 5 7 0 14 */
+283, /* OBJ_id_mod_dvcs 1 3 6 1 5 5 7 0 15 */
+284, /* OBJ_id_mod_cmp2000 1 3 6 1 5 5 7 0 16 */
+177, /* OBJ_info_access 1 3 6 1 5 5 7 1 1 */
+285, /* OBJ_biometricInfo 1 3 6 1 5 5 7 1 2 */
+286, /* OBJ_qcStatements 1 3 6 1 5 5 7 1 3 */
+287, /* OBJ_ac_auditEntity 1 3 6 1 5 5 7 1 4 */
+288, /* OBJ_ac_targeting 1 3 6 1 5 5 7 1 5 */
+289, /* OBJ_aaControls 1 3 6 1 5 5 7 1 6 */
+290, /* OBJ_sbgp_ipAddrBlock 1 3 6 1 5 5 7 1 7 */
+291, /* OBJ_sbgp_autonomousSysNum 1 3 6 1 5 5 7 1 8 */
+292, /* OBJ_sbgp_routerIdentifier 1 3 6 1 5 5 7 1 9 */
+397, /* OBJ_ac_proxying 1 3 6 1 5 5 7 1 10 */
+398, /* OBJ_sinfo_access 1 3 6 1 5 5 7 1 11 */
+663, /* OBJ_proxyCertInfo 1 3 6 1 5 5 7 1 14 */
+164, /* OBJ_id_qt_cps 1 3 6 1 5 5 7 2 1 */
+165, /* OBJ_id_qt_unotice 1 3 6 1 5 5 7 2 2 */
+293, /* OBJ_textNotice 1 3 6 1 5 5 7 2 3 */
+129, /* OBJ_server_auth 1 3 6 1 5 5 7 3 1 */
+130, /* OBJ_client_auth 1 3 6 1 5 5 7 3 2 */
+131, /* OBJ_code_sign 1 3 6 1 5 5 7 3 3 */
+132, /* OBJ_email_protect 1 3 6 1 5 5 7 3 4 */
+294, /* OBJ_ipsecEndSystem 1 3 6 1 5 5 7 3 5 */
+295, /* OBJ_ipsecTunnel 1 3 6 1 5 5 7 3 6 */
+296, /* OBJ_ipsecUser 1 3 6 1 5 5 7 3 7 */
+133, /* OBJ_time_stamp 1 3 6 1 5 5 7 3 8 */
+180, /* OBJ_OCSP_sign 1 3 6 1 5 5 7 3 9 */
+297, /* OBJ_dvcs 1 3 6 1 5 5 7 3 10 */
+298, /* OBJ_id_it_caProtEncCert 1 3 6 1 5 5 7 4 1 */
+299, /* OBJ_id_it_signKeyPairTypes 1 3 6 1 5 5 7 4 2 */
+300, /* OBJ_id_it_encKeyPairTypes 1 3 6 1 5 5 7 4 3 */
+301, /* OBJ_id_it_preferredSymmAlg 1 3 6 1 5 5 7 4 4 */
+302, /* OBJ_id_it_caKeyUpdateInfo 1 3 6 1 5 5 7 4 5 */
+303, /* OBJ_id_it_currentCRL 1 3 6 1 5 5 7 4 6 */
+304, /* OBJ_id_it_unsupportedOIDs 1 3 6 1 5 5 7 4 7 */
+305, /* OBJ_id_it_subscriptionRequest 1 3 6 1 5 5 7 4 8 */
+306, /* OBJ_id_it_subscriptionResponse 1 3 6 1 5 5 7 4 9 */
+307, /* OBJ_id_it_keyPairParamReq 1 3 6 1 5 5 7 4 10 */
+308, /* OBJ_id_it_keyPairParamRep 1 3 6 1 5 5 7 4 11 */
+309, /* OBJ_id_it_revPassphrase 1 3 6 1 5 5 7 4 12 */
+310, /* OBJ_id_it_implicitConfirm 1 3 6 1 5 5 7 4 13 */
+311, /* OBJ_id_it_confirmWaitTime 1 3 6 1 5 5 7 4 14 */
+312, /* OBJ_id_it_origPKIMessage 1 3 6 1 5 5 7 4 15 */
+784, /* OBJ_id_it_suppLangTags 1 3 6 1 5 5 7 4 16 */
+313, /* OBJ_id_regCtrl 1 3 6 1 5 5 7 5 1 */
+314, /* OBJ_id_regInfo 1 3 6 1 5 5 7 5 2 */
+323, /* OBJ_id_alg_des40 1 3 6 1 5 5 7 6 1 */
+324, /* OBJ_id_alg_noSignature 1 3 6 1 5 5 7 6 2 */
+325, /* OBJ_id_alg_dh_sig_hmac_sha1 1 3 6 1 5 5 7 6 3 */
+326, /* OBJ_id_alg_dh_pop 1 3 6 1 5 5 7 6 4 */
+327, /* OBJ_id_cmc_statusInfo 1 3 6 1 5 5 7 7 1 */
+328, /* OBJ_id_cmc_identification 1 3 6 1 5 5 7 7 2 */
+329, /* OBJ_id_cmc_identityProof 1 3 6 1 5 5 7 7 3 */
+330, /* OBJ_id_cmc_dataReturn 1 3 6 1 5 5 7 7 4 */
+331, /* OBJ_id_cmc_transactionId 1 3 6 1 5 5 7 7 5 */
+332, /* OBJ_id_cmc_senderNonce 1 3 6 1 5 5 7 7 6 */
+333, /* OBJ_id_cmc_recipientNonce 1 3 6 1 5 5 7 7 7 */
+334, /* OBJ_id_cmc_addExtensions 1 3 6 1 5 5 7 7 8 */
+335, /* OBJ_id_cmc_encryptedPOP 1 3 6 1 5 5 7 7 9 */
+336, /* OBJ_id_cmc_decryptedPOP 1 3 6 1 5 5 7 7 10 */
+337, /* OBJ_id_cmc_lraPOPWitness 1 3 6 1 5 5 7 7 11 */
+338, /* OBJ_id_cmc_getCert 1 3 6 1 5 5 7 7 15 */
+339, /* OBJ_id_cmc_getCRL 1 3 6 1 5 5 7 7 16 */
+340, /* OBJ_id_cmc_revokeRequest 1 3 6 1 5 5 7 7 17 */
+341, /* OBJ_id_cmc_regInfo 1 3 6 1 5 5 7 7 18 */
+342, /* OBJ_id_cmc_responseInfo 1 3 6 1 5 5 7 7 19 */
+343, /* OBJ_id_cmc_queryPending 1 3 6 1 5 5 7 7 21 */
+344, /* OBJ_id_cmc_popLinkRandom 1 3 6 1 5 5 7 7 22 */
+345, /* OBJ_id_cmc_popLinkWitness 1 3 6 1 5 5 7 7 23 */
+346, /* OBJ_id_cmc_confirmCertAcceptance 1 3 6 1 5 5 7 7 24 */
+347, /* OBJ_id_on_personalData 1 3 6 1 5 5 7 8 1 */
+858, /* OBJ_id_on_permanentIdentifier 1 3 6 1 5 5 7 8 3 */
+348, /* OBJ_id_pda_dateOfBirth 1 3 6 1 5 5 7 9 1 */
+349, /* OBJ_id_pda_placeOfBirth 1 3 6 1 5 5 7 9 2 */
+351, /* OBJ_id_pda_gender 1 3 6 1 5 5 7 9 3 */
+352, /* OBJ_id_pda_countryOfCitizenship 1 3 6 1 5 5 7 9 4 */
+353, /* OBJ_id_pda_countryOfResidence 1 3 6 1 5 5 7 9 5 */
+354, /* OBJ_id_aca_authenticationInfo 1 3 6 1 5 5 7 10 1 */
+355, /* OBJ_id_aca_accessIdentity 1 3 6 1 5 5 7 10 2 */
+356, /* OBJ_id_aca_chargingIdentity 1 3 6 1 5 5 7 10 3 */
+357, /* OBJ_id_aca_group 1 3 6 1 5 5 7 10 4 */
+358, /* OBJ_id_aca_role 1 3 6 1 5 5 7 10 5 */
+399, /* OBJ_id_aca_encAttrs 1 3 6 1 5 5 7 10 6 */
+359, /* OBJ_id_qcs_pkixQCSyntax_v1 1 3 6 1 5 5 7 11 1 */
+360, /* OBJ_id_cct_crs 1 3 6 1 5 5 7 12 1 */
+361, /* OBJ_id_cct_PKIData 1 3 6 1 5 5 7 12 2 */
+362, /* OBJ_id_cct_PKIResponse 1 3 6 1 5 5 7 12 3 */
+664, /* OBJ_id_ppl_anyLanguage 1 3 6 1 5 5 7 21 0 */
+665, /* OBJ_id_ppl_inheritAll 1 3 6 1 5 5 7 21 1 */
+667, /* OBJ_Independent 1 3 6 1 5 5 7 21 2 */
+178, /* OBJ_ad_OCSP 1 3 6 1 5 5 7 48 1 */
+179, /* OBJ_ad_ca_issuers 1 3 6 1 5 5 7 48 2 */
+363, /* OBJ_ad_timeStamping 1 3 6 1 5 5 7 48 3 */
+364, /* OBJ_ad_dvcs 1 3 6 1 5 5 7 48 4 */
+785, /* OBJ_caRepository 1 3 6 1 5 5 7 48 5 */
+780, /* OBJ_hmac_md5 1 3 6 1 5 5 8 1 1 */
+781, /* OBJ_hmac_sha1 1 3 6 1 5 5 8 1 2 */
+58, /* OBJ_netscape_cert_extension 2 16 840 1 113730 1 */
+59, /* OBJ_netscape_data_type 2 16 840 1 113730 2 */
+438, /* OBJ_pilotAttributeType 0 9 2342 19200300 100 1 */
+439, /* OBJ_pilotAttributeSyntax 0 9 2342 19200300 100 3 */
+440, /* OBJ_pilotObjectClass 0 9 2342 19200300 100 4 */
+441, /* OBJ_pilotGroups 0 9 2342 19200300 100 10 */
+108, /* OBJ_cast5_cbc 1 2 840 113533 7 66 10 */
+112, /* OBJ_pbeWithMD5AndCast5_CBC 1 2 840 113533 7 66 12 */
+782, /* OBJ_id_PasswordBasedMAC 1 2 840 113533 7 66 13 */
+783, /* OBJ_id_DHBasedMac 1 2 840 113533 7 66 30 */
+ 6, /* OBJ_rsaEncryption 1 2 840 113549 1 1 1 */
+ 7, /* OBJ_md2WithRSAEncryption 1 2 840 113549 1 1 2 */
+396, /* OBJ_md4WithRSAEncryption 1 2 840 113549 1 1 3 */
+ 8, /* OBJ_md5WithRSAEncryption 1 2 840 113549 1 1 4 */
+65, /* OBJ_sha1WithRSAEncryption 1 2 840 113549 1 1 5 */
+644, /* OBJ_rsaOAEPEncryptionSET 1 2 840 113549 1 1 6 */
+919, /* OBJ_rsaesOaep 1 2 840 113549 1 1 7 */
+911, /* OBJ_mgf1 1 2 840 113549 1 1 8 */
+935, /* OBJ_pSpecified 1 2 840 113549 1 1 9 */
+912, /* OBJ_rsassaPss 1 2 840 113549 1 1 10 */
+668, /* OBJ_sha256WithRSAEncryption 1 2 840 113549 1 1 11 */
+669, /* OBJ_sha384WithRSAEncryption 1 2 840 113549 1 1 12 */
+670, /* OBJ_sha512WithRSAEncryption 1 2 840 113549 1 1 13 */
+671, /* OBJ_sha224WithRSAEncryption 1 2 840 113549 1 1 14 */
+28, /* OBJ_dhKeyAgreement 1 2 840 113549 1 3 1 */
+ 9, /* OBJ_pbeWithMD2AndDES_CBC 1 2 840 113549 1 5 1 */
+10, /* OBJ_pbeWithMD5AndDES_CBC 1 2 840 113549 1 5 3 */
+168, /* OBJ_pbeWithMD2AndRC2_CBC 1 2 840 113549 1 5 4 */
+169, /* OBJ_pbeWithMD5AndRC2_CBC 1 2 840 113549 1 5 6 */
+170, /* OBJ_pbeWithSHA1AndDES_CBC 1 2 840 113549 1 5 10 */
+68, /* OBJ_pbeWithSHA1AndRC2_CBC 1 2 840 113549 1 5 11 */
+69, /* OBJ_id_pbkdf2 1 2 840 113549 1 5 12 */
+161, /* OBJ_pbes2 1 2 840 113549 1 5 13 */
+162, /* OBJ_pbmac1 1 2 840 113549 1 5 14 */
+21, /* OBJ_pkcs7_data 1 2 840 113549 1 7 1 */
+22, /* OBJ_pkcs7_signed 1 2 840 113549 1 7 2 */
+23, /* OBJ_pkcs7_enveloped 1 2 840 113549 1 7 3 */
+24, /* OBJ_pkcs7_signedAndEnveloped 1 2 840 113549 1 7 4 */
+25, /* OBJ_pkcs7_digest 1 2 840 113549 1 7 5 */
+26, /* OBJ_pkcs7_encrypted 1 2 840 113549 1 7 6 */
+48, /* OBJ_pkcs9_emailAddress 1 2 840 113549 1 9 1 */
+49, /* OBJ_pkcs9_unstructuredName 1 2 840 113549 1 9 2 */
+50, /* OBJ_pkcs9_contentType 1 2 840 113549 1 9 3 */
+51, /* OBJ_pkcs9_messageDigest 1 2 840 113549 1 9 4 */
+52, /* OBJ_pkcs9_signingTime 1 2 840 113549 1 9 5 */
+53, /* OBJ_pkcs9_countersignature 1 2 840 113549 1 9 6 */
+54, /* OBJ_pkcs9_challengePassword 1 2 840 113549 1 9 7 */
+55, /* OBJ_pkcs9_unstructuredAddress 1 2 840 113549 1 9 8 */
+56, /* OBJ_pkcs9_extCertAttributes 1 2 840 113549 1 9 9 */
+172, /* OBJ_ext_req 1 2 840 113549 1 9 14 */
+167, /* OBJ_SMIMECapabilities 1 2 840 113549 1 9 15 */
+188, /* OBJ_SMIME 1 2 840 113549 1 9 16 */
+156, /* OBJ_friendlyName 1 2 840 113549 1 9 20 */
+157, /* OBJ_localKeyID 1 2 840 113549 1 9 21 */
+681, /* OBJ_X9_62_onBasis 1 2 840 10045 1 2 3 1 */
+682, /* OBJ_X9_62_tpBasis 1 2 840 10045 1 2 3 2 */
+683, /* OBJ_X9_62_ppBasis 1 2 840 10045 1 2 3 3 */
+417, /* OBJ_ms_csp_name 1 3 6 1 4 1 311 17 1 */
+856, /* OBJ_LocalKeySet 1 3 6 1 4 1 311 17 2 */
+390, /* OBJ_dcObject 1 3 6 1 4 1 1466 344 */
+91, /* OBJ_bf_cbc 1 3 6 1 4 1 3029 1 2 */
+315, /* OBJ_id_regCtrl_regToken 1 3 6 1 5 5 7 5 1 1 */
+316, /* OBJ_id_regCtrl_authenticator 1 3 6 1 5 5 7 5 1 2 */
+317, /* OBJ_id_regCtrl_pkiPublicationInfo 1 3 6 1 5 5 7 5 1 3 */
+318, /* OBJ_id_regCtrl_pkiArchiveOptions 1 3 6 1 5 5 7 5 1 4 */
+319, /* OBJ_id_regCtrl_oldCertID 1 3 6 1 5 5 7 5 1 5 */
+320, /* OBJ_id_regCtrl_protocolEncrKey 1 3 6 1 5 5 7 5 1 6 */
+321, /* OBJ_id_regInfo_utf8Pairs 1 3 6 1 5 5 7 5 2 1 */
+322, /* OBJ_id_regInfo_certReq 1 3 6 1 5 5 7 5 2 2 */
+365, /* OBJ_id_pkix_OCSP_basic 1 3 6 1 5 5 7 48 1 1 */
+366, /* OBJ_id_pkix_OCSP_Nonce 1 3 6 1 5 5 7 48 1 2 */
+367, /* OBJ_id_pkix_OCSP_CrlID 1 3 6 1 5 5 7 48 1 3 */
+368, /* OBJ_id_pkix_OCSP_acceptableResponses 1 3 6 1 5 5 7 48 1 4 */
+369, /* OBJ_id_pkix_OCSP_noCheck 1 3 6 1 5 5 7 48 1 5 */
+370, /* OBJ_id_pkix_OCSP_archiveCutoff 1 3 6 1 5 5 7 48 1 6 */
+371, /* OBJ_id_pkix_OCSP_serviceLocator 1 3 6 1 5 5 7 48 1 7 */
+372, /* OBJ_id_pkix_OCSP_extendedStatus 1 3 6 1 5 5 7 48 1 8 */
+373, /* OBJ_id_pkix_OCSP_valid 1 3 6 1 5 5 7 48 1 9 */
+374, /* OBJ_id_pkix_OCSP_path 1 3 6 1 5 5 7 48 1 10 */
+375, /* OBJ_id_pkix_OCSP_trustRoot 1 3 6 1 5 5 7 48 1 11 */
+921, /* OBJ_brainpoolP160r1 1 3 36 3 3 2 8 1 1 1 */
+922, /* OBJ_brainpoolP160t1 1 3 36 3 3 2 8 1 1 2 */
+923, /* OBJ_brainpoolP192r1 1 3 36 3 3 2 8 1 1 3 */
+924, /* OBJ_brainpoolP192t1 1 3 36 3 3 2 8 1 1 4 */
+925, /* OBJ_brainpoolP224r1 1 3 36 3 3 2 8 1 1 5 */
+926, /* OBJ_brainpoolP224t1 1 3 36 3 3 2 8 1 1 6 */
+927, /* OBJ_brainpoolP256r1 1 3 36 3 3 2 8 1 1 7 */
+928, /* OBJ_brainpoolP256t1 1 3 36 3 3 2 8 1 1 8 */
+929, /* OBJ_brainpoolP320r1 1 3 36 3 3 2 8 1 1 9 */
+930, /* OBJ_brainpoolP320t1 1 3 36 3 3 2 8 1 1 10 */
+931, /* OBJ_brainpoolP384r1 1 3 36 3 3 2 8 1 1 11 */
+932, /* OBJ_brainpoolP384t1 1 3 36 3 3 2 8 1 1 12 */
+933, /* OBJ_brainpoolP512r1 1 3 36 3 3 2 8 1 1 13 */
+934, /* OBJ_brainpoolP512t1 1 3 36 3 3 2 8 1 1 14 */
+939, /* OBJ_dhSinglePass_stdDH_sha1kdf_scheme 1 3 133 16 840 63 0 2 */
+944, /* OBJ_dhSinglePass_cofactorDH_sha1kdf_scheme 1 3 133 16 840 63 0 3 */
+418, /* OBJ_aes_128_ecb 2 16 840 1 101 3 4 1 1 */
+419, /* OBJ_aes_128_cbc 2 16 840 1 101 3 4 1 2 */
+420, /* OBJ_aes_128_ofb128 2 16 840 1 101 3 4 1 3 */
+421, /* OBJ_aes_128_cfb128 2 16 840 1 101 3 4 1 4 */
+788, /* OBJ_id_aes128_wrap 2 16 840 1 101 3 4 1 5 */
+895, /* OBJ_aes_128_gcm 2 16 840 1 101 3 4 1 6 */
+896, /* OBJ_aes_128_ccm 2 16 840 1 101 3 4 1 7 */
+897, /* OBJ_id_aes128_wrap_pad 2 16 840 1 101 3 4 1 8 */
+422, /* OBJ_aes_192_ecb 2 16 840 1 101 3 4 1 21 */
+423, /* OBJ_aes_192_cbc 2 16 840 1 101 3 4 1 22 */
+424, /* OBJ_aes_192_ofb128 2 16 840 1 101 3 4 1 23 */
+425, /* OBJ_aes_192_cfb128 2 16 840 1 101 3 4 1 24 */
+789, /* OBJ_id_aes192_wrap 2 16 840 1 101 3 4 1 25 */
+898, /* OBJ_aes_192_gcm 2 16 840 1 101 3 4 1 26 */
+899, /* OBJ_aes_192_ccm 2 16 840 1 101 3 4 1 27 */
+900, /* OBJ_id_aes192_wrap_pad 2 16 840 1 101 3 4 1 28 */
+426, /* OBJ_aes_256_ecb 2 16 840 1 101 3 4 1 41 */
+427, /* OBJ_aes_256_cbc 2 16 840 1 101 3 4 1 42 */
+428, /* OBJ_aes_256_ofb128 2 16 840 1 101 3 4 1 43 */
+429, /* OBJ_aes_256_cfb128 2 16 840 1 101 3 4 1 44 */
+790, /* OBJ_id_aes256_wrap 2 16 840 1 101 3 4 1 45 */
+901, /* OBJ_aes_256_gcm 2 16 840 1 101 3 4 1 46 */
+902, /* OBJ_aes_256_ccm 2 16 840 1 101 3 4 1 47 */
+903, /* OBJ_id_aes256_wrap_pad 2 16 840 1 101 3 4 1 48 */
+672, /* OBJ_sha256 2 16 840 1 101 3 4 2 1 */
+673, /* OBJ_sha384 2 16 840 1 101 3 4 2 2 */
+674, /* OBJ_sha512 2 16 840 1 101 3 4 2 3 */
+675, /* OBJ_sha224 2 16 840 1 101 3 4 2 4 */
+802, /* OBJ_dsa_with_SHA224 2 16 840 1 101 3 4 3 1 */
+803, /* OBJ_dsa_with_SHA256 2 16 840 1 101 3 4 3 2 */
+71, /* OBJ_netscape_cert_type 2 16 840 1 113730 1 1 */
+72, /* OBJ_netscape_base_url 2 16 840 1 113730 1 2 */
+73, /* OBJ_netscape_revocation_url 2 16 840 1 113730 1 3 */
+74, /* OBJ_netscape_ca_revocation_url 2 16 840 1 113730 1 4 */
+75, /* OBJ_netscape_renewal_url 2 16 840 1 113730 1 7 */
+76, /* OBJ_netscape_ca_policy_url 2 16 840 1 113730 1 8 */
+77, /* OBJ_netscape_ssl_server_name 2 16 840 1 113730 1 12 */
+78, /* OBJ_netscape_comment 2 16 840 1 113730 1 13 */
+79, /* OBJ_netscape_cert_sequence 2 16 840 1 113730 2 5 */
+139, /* OBJ_ns_sgc 2 16 840 1 113730 4 1 */
+458, /* OBJ_userId 0 9 2342 19200300 100 1 1 */
+459, /* OBJ_textEncodedORAddress 0 9 2342 19200300 100 1 2 */
+460, /* OBJ_rfc822Mailbox 0 9 2342 19200300 100 1 3 */
+461, /* OBJ_info 0 9 2342 19200300 100 1 4 */
+462, /* OBJ_favouriteDrink 0 9 2342 19200300 100 1 5 */
+463, /* OBJ_roomNumber 0 9 2342 19200300 100 1 6 */
+464, /* OBJ_photo 0 9 2342 19200300 100 1 7 */
+465, /* OBJ_userClass 0 9 2342 19200300 100 1 8 */
+466, /* OBJ_host 0 9 2342 19200300 100 1 9 */
+467, /* OBJ_manager 0 9 2342 19200300 100 1 10 */
+468, /* OBJ_documentIdentifier 0 9 2342 19200300 100 1 11 */
+469, /* OBJ_documentTitle 0 9 2342 19200300 100 1 12 */
+470, /* OBJ_documentVersion 0 9 2342 19200300 100 1 13 */
+471, /* OBJ_documentAuthor 0 9 2342 19200300 100 1 14 */
+472, /* OBJ_documentLocation 0 9 2342 19200300 100 1 15 */
+473, /* OBJ_homeTelephoneNumber 0 9 2342 19200300 100 1 20 */
+474, /* OBJ_secretary 0 9 2342 19200300 100 1 21 */
+475, /* OBJ_otherMailbox 0 9 2342 19200300 100 1 22 */
+476, /* OBJ_lastModifiedTime 0 9 2342 19200300 100 1 23 */
+477, /* OBJ_lastModifiedBy 0 9 2342 19200300 100 1 24 */
+391, /* OBJ_domainComponent 0 9 2342 19200300 100 1 25 */
+478, /* OBJ_aRecord 0 9 2342 19200300 100 1 26 */
+479, /* OBJ_pilotAttributeType27 0 9 2342 19200300 100 1 27 */
+480, /* OBJ_mXRecord 0 9 2342 19200300 100 1 28 */
+481, /* OBJ_nSRecord 0 9 2342 19200300 100 1 29 */
+482, /* OBJ_sOARecord 0 9 2342 19200300 100 1 30 */
+483, /* OBJ_cNAMERecord 0 9 2342 19200300 100 1 31 */
+484, /* OBJ_associatedDomain 0 9 2342 19200300 100 1 37 */
+485, /* OBJ_associatedName 0 9 2342 19200300 100 1 38 */
+486, /* OBJ_homePostalAddress 0 9 2342 19200300 100 1 39 */
+487, /* OBJ_personalTitle 0 9 2342 19200300 100 1 40 */
+488, /* OBJ_mobileTelephoneNumber 0 9 2342 19200300 100 1 41 */
+489, /* OBJ_pagerTelephoneNumber 0 9 2342 19200300 100 1 42 */
+490, /* OBJ_friendlyCountryName 0 9 2342 19200300 100 1 43 */
+491, /* OBJ_organizationalStatus 0 9 2342 19200300 100 1 45 */
+492, /* OBJ_janetMailbox 0 9 2342 19200300 100 1 46 */
+493, /* OBJ_mailPreferenceOption 0 9 2342 19200300 100 1 47 */
+494, /* OBJ_buildingName 0 9 2342 19200300 100 1 48 */
+495, /* OBJ_dSAQuality 0 9 2342 19200300 100 1 49 */
+496, /* OBJ_singleLevelQuality 0 9 2342 19200300 100 1 50 */
+497, /* OBJ_subtreeMinimumQuality 0 9 2342 19200300 100 1 51 */
+498, /* OBJ_subtreeMaximumQuality 0 9 2342 19200300 100 1 52 */
+499, /* OBJ_personalSignature 0 9 2342 19200300 100 1 53 */
+500, /* OBJ_dITRedirect 0 9 2342 19200300 100 1 54 */
+501, /* OBJ_audio 0 9 2342 19200300 100 1 55 */
+502, /* OBJ_documentPublisher 0 9 2342 19200300 100 1 56 */
+442, /* OBJ_iA5StringSyntax 0 9 2342 19200300 100 3 4 */
+443, /* OBJ_caseIgnoreIA5StringSyntax 0 9 2342 19200300 100 3 5 */
+444, /* OBJ_pilotObject 0 9 2342 19200300 100 4 3 */
+445, /* OBJ_pilotPerson 0 9 2342 19200300 100 4 4 */
+446, /* OBJ_account 0 9 2342 19200300 100 4 5 */
+447, /* OBJ_document 0 9 2342 19200300 100 4 6 */
+448, /* OBJ_room 0 9 2342 19200300 100 4 7 */
+449, /* OBJ_documentSeries 0 9 2342 19200300 100 4 9 */
+392, /* OBJ_Domain 0 9 2342 19200300 100 4 13 */
+450, /* OBJ_rFC822localPart 0 9 2342 19200300 100 4 14 */
+451, /* OBJ_dNSDomain 0 9 2342 19200300 100 4 15 */
+452, /* OBJ_domainRelatedObject 0 9 2342 19200300 100 4 17 */
+453, /* OBJ_friendlyCountry 0 9 2342 19200300 100 4 18 */
+454, /* OBJ_simpleSecurityObject 0 9 2342 19200300 100 4 19 */
+455, /* OBJ_pilotOrganization 0 9 2342 19200300 100 4 20 */
+456, /* OBJ_pilotDSA 0 9 2342 19200300 100 4 21 */
+457, /* OBJ_qualityLabelledData 0 9 2342 19200300 100 4 22 */
+189, /* OBJ_id_smime_mod 1 2 840 113549 1 9 16 0 */
+190, /* OBJ_id_smime_ct 1 2 840 113549 1 9 16 1 */
+191, /* OBJ_id_smime_aa 1 2 840 113549 1 9 16 2 */
+192, /* OBJ_id_smime_alg 1 2 840 113549 1 9 16 3 */
+193, /* OBJ_id_smime_cd 1 2 840 113549 1 9 16 4 */
+194, /* OBJ_id_smime_spq 1 2 840 113549 1 9 16 5 */
+195, /* OBJ_id_smime_cti 1 2 840 113549 1 9 16 6 */
+158, /* OBJ_x509Certificate 1 2 840 113549 1 9 22 1 */
+159, /* OBJ_sdsiCertificate 1 2 840 113549 1 9 22 2 */
+160, /* OBJ_x509Crl 1 2 840 113549 1 9 23 1 */
+144, /* OBJ_pbe_WithSHA1And128BitRC4 1 2 840 113549 1 12 1 1 */
+145, /* OBJ_pbe_WithSHA1And40BitRC4 1 2 840 113549 1 12 1 2 */
+146, /* OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC 1 2 840 113549 1 12 1 3 */
+147, /* OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC 1 2 840 113549 1 12 1 4 */
+148, /* OBJ_pbe_WithSHA1And128BitRC2_CBC 1 2 840 113549 1 12 1 5 */
+149, /* OBJ_pbe_WithSHA1And40BitRC2_CBC 1 2 840 113549 1 12 1 6 */
+171, /* OBJ_ms_ext_req 1 3 6 1 4 1 311 2 1 14 */
+134, /* OBJ_ms_code_ind 1 3 6 1 4 1 311 2 1 21 */
+135, /* OBJ_ms_code_com 1 3 6 1 4 1 311 2 1 22 */
+136, /* OBJ_ms_ctl_sign 1 3 6 1 4 1 311 10 3 1 */
+137, /* OBJ_ms_sgc 1 3 6 1 4 1 311 10 3 3 */
+138, /* OBJ_ms_efs 1 3 6 1 4 1 311 10 3 4 */
+648, /* OBJ_ms_smartcard_login 1 3 6 1 4 1 311 20 2 2 */
+649, /* OBJ_ms_upn 1 3 6 1 4 1 311 20 2 3 */
+751, /* OBJ_camellia_128_cbc 1 2 392 200011 61 1 1 1 2 */
+752, /* OBJ_camellia_192_cbc 1 2 392 200011 61 1 1 1 3 */
+753, /* OBJ_camellia_256_cbc 1 2 392 200011 61 1 1 1 4 */
+907, /* OBJ_id_camellia128_wrap 1 2 392 200011 61 1 1 3 2 */
+908, /* OBJ_id_camellia192_wrap 1 2 392 200011 61 1 1 3 3 */
+909, /* OBJ_id_camellia256_wrap 1 2 392 200011 61 1 1 3 4 */
+196, /* OBJ_id_smime_mod_cms 1 2 840 113549 1 9 16 0 1 */
+197, /* OBJ_id_smime_mod_ess 1 2 840 113549 1 9 16 0 2 */
+198, /* OBJ_id_smime_mod_oid 1 2 840 113549 1 9 16 0 3 */
+199, /* OBJ_id_smime_mod_msg_v3 1 2 840 113549 1 9 16 0 4 */
+200, /* OBJ_id_smime_mod_ets_eSignature_88 1 2 840 113549 1 9 16 0 5 */
+201, /* OBJ_id_smime_mod_ets_eSignature_97 1 2 840 113549 1 9 16 0 6 */
+202, /* OBJ_id_smime_mod_ets_eSigPolicy_88 1 2 840 113549 1 9 16 0 7 */
+203, /* OBJ_id_smime_mod_ets_eSigPolicy_97 1 2 840 113549 1 9 16 0 8 */
+204, /* OBJ_id_smime_ct_receipt 1 2 840 113549 1 9 16 1 1 */
+205, /* OBJ_id_smime_ct_authData 1 2 840 113549 1 9 16 1 2 */
+206, /* OBJ_id_smime_ct_publishCert 1 2 840 113549 1 9 16 1 3 */
+207, /* OBJ_id_smime_ct_TSTInfo 1 2 840 113549 1 9 16 1 4 */
+208, /* OBJ_id_smime_ct_TDTInfo 1 2 840 113549 1 9 16 1 5 */
+209, /* OBJ_id_smime_ct_contentInfo 1 2 840 113549 1 9 16 1 6 */
+210, /* OBJ_id_smime_ct_DVCSRequestData 1 2 840 113549 1 9 16 1 7 */
+211, /* OBJ_id_smime_ct_DVCSResponseData 1 2 840 113549 1 9 16 1 8 */
+786, /* OBJ_id_smime_ct_compressedData 1 2 840 113549 1 9 16 1 9 */
+787, /* OBJ_id_ct_asciiTextWithCRLF 1 2 840 113549 1 9 16 1 27 */
+212, /* OBJ_id_smime_aa_receiptRequest 1 2 840 113549 1 9 16 2 1 */
+213, /* OBJ_id_smime_aa_securityLabel 1 2 840 113549 1 9 16 2 2 */
+214, /* OBJ_id_smime_aa_mlExpandHistory 1 2 840 113549 1 9 16 2 3 */
+215, /* OBJ_id_smime_aa_contentHint 1 2 840 113549 1 9 16 2 4 */
+216, /* OBJ_id_smime_aa_msgSigDigest 1 2 840 113549 1 9 16 2 5 */
+217, /* OBJ_id_smime_aa_encapContentType 1 2 840 113549 1 9 16 2 6 */
+218, /* OBJ_id_smime_aa_contentIdentifier 1 2 840 113549 1 9 16 2 7 */
+219, /* OBJ_id_smime_aa_macValue 1 2 840 113549 1 9 16 2 8 */
+220, /* OBJ_id_smime_aa_equivalentLabels 1 2 840 113549 1 9 16 2 9 */
+221, /* OBJ_id_smime_aa_contentReference 1 2 840 113549 1 9 16 2 10 */
+222, /* OBJ_id_smime_aa_encrypKeyPref 1 2 840 113549 1 9 16 2 11 */
+223, /* OBJ_id_smime_aa_signingCertificate 1 2 840 113549 1 9 16 2 12 */
+224, /* OBJ_id_smime_aa_smimeEncryptCerts 1 2 840 113549 1 9 16 2 13 */
+225, /* OBJ_id_smime_aa_timeStampToken 1 2 840 113549 1 9 16 2 14 */
+226, /* OBJ_id_smime_aa_ets_sigPolicyId 1 2 840 113549 1 9 16 2 15 */
+227, /* OBJ_id_smime_aa_ets_commitmentType 1 2 840 113549 1 9 16 2 16 */
+228, /* OBJ_id_smime_aa_ets_signerLocation 1 2 840 113549 1 9 16 2 17 */
+229, /* OBJ_id_smime_aa_ets_signerAttr 1 2 840 113549 1 9 16 2 18 */
+230, /* OBJ_id_smime_aa_ets_otherSigCert 1 2 840 113549 1 9 16 2 19 */
+231, /* OBJ_id_smime_aa_ets_contentTimestamp 1 2 840 113549 1 9 16 2 20 */
+232, /* OBJ_id_smime_aa_ets_CertificateRefs 1 2 840 113549 1 9 16 2 21 */
+233, /* OBJ_id_smime_aa_ets_RevocationRefs 1 2 840 113549 1 9 16 2 22 */
+234, /* OBJ_id_smime_aa_ets_certValues 1 2 840 113549 1 9 16 2 23 */
+235, /* OBJ_id_smime_aa_ets_revocationValues 1 2 840 113549 1 9 16 2 24 */
+236, /* OBJ_id_smime_aa_ets_escTimeStamp 1 2 840 113549 1 9 16 2 25 */
+237, /* OBJ_id_smime_aa_ets_certCRLTimestamp 1 2 840 113549 1 9 16 2 26 */
+238, /* OBJ_id_smime_aa_ets_archiveTimeStamp 1 2 840 113549 1 9 16 2 27 */
+239, /* OBJ_id_smime_aa_signatureType 1 2 840 113549 1 9 16 2 28 */
+240, /* OBJ_id_smime_aa_dvcs_dvc 1 2 840 113549 1 9 16 2 29 */
+241, /* OBJ_id_smime_alg_ESDHwith3DES 1 2 840 113549 1 9 16 3 1 */
+242, /* OBJ_id_smime_alg_ESDHwithRC2 1 2 840 113549 1 9 16 3 2 */
+243, /* OBJ_id_smime_alg_3DESwrap 1 2 840 113549 1 9 16 3 3 */
+244, /* OBJ_id_smime_alg_RC2wrap 1 2 840 113549 1 9 16 3 4 */
+245, /* OBJ_id_smime_alg_ESDH 1 2 840 113549 1 9 16 3 5 */
+246, /* OBJ_id_smime_alg_CMS3DESwrap 1 2 840 113549 1 9 16 3 6 */
+247, /* OBJ_id_smime_alg_CMSRC2wrap 1 2 840 113549 1 9 16 3 7 */
+125, /* OBJ_zlib_compression 1 2 840 113549 1 9 16 3 8 */
+893, /* OBJ_id_alg_PWRI_KEK 1 2 840 113549 1 9 16 3 9 */
+248, /* OBJ_id_smime_cd_ldap 1 2 840 113549 1 9 16 4 1 */
+249, /* OBJ_id_smime_spq_ets_sqt_uri 1 2 840 113549 1 9 16 5 1 */
+250, /* OBJ_id_smime_spq_ets_sqt_unotice 1 2 840 113549 1 9 16 5 2 */
+251, /* OBJ_id_smime_cti_ets_proofOfOrigin 1 2 840 113549 1 9 16 6 1 */
+252, /* OBJ_id_smime_cti_ets_proofOfReceipt 1 2 840 113549 1 9 16 6 2 */
+253, /* OBJ_id_smime_cti_ets_proofOfDelivery 1 2 840 113549 1 9 16 6 3 */
+254, /* OBJ_id_smime_cti_ets_proofOfSender 1 2 840 113549 1 9 16 6 4 */
+255, /* OBJ_id_smime_cti_ets_proofOfApproval 1 2 840 113549 1 9 16 6 5 */
+256, /* OBJ_id_smime_cti_ets_proofOfCreation 1 2 840 113549 1 9 16 6 6 */
+150, /* OBJ_keyBag 1 2 840 113549 1 12 10 1 1 */
+151, /* OBJ_pkcs8ShroudedKeyBag 1 2 840 113549 1 12 10 1 2 */
+152, /* OBJ_certBag 1 2 840 113549 1 12 10 1 3 */
+153, /* OBJ_crlBag 1 2 840 113549 1 12 10 1 4 */
+154, /* OBJ_secretBag 1 2 840 113549 1 12 10 1 5 */
+155, /* OBJ_safeContentsBag 1 2 840 113549 1 12 10 1 6 */
+34, /* OBJ_idea_cbc 1 3 6 1 4 1 188 7 1 1 2 */
+};
+
diff --git a/crypto/obj/obj_dat.pl b/crypto/obj/obj_dat.pl
new file mode 100644
index 0000000..227bfb1
--- /dev/null
+++ b/crypto/obj/obj_dat.pl
@@ -0,0 +1,303 @@
+#!/usr/local/bin/perl
+
+# fixes bug in floating point emulation on sparc64 when
+# this script produces off-by-one output on sparc64
+use integer;
+
+sub obj_cmp
+ {
+ local(@a,@b,$_,$r);
+
+ $A=$obj_len{$obj{$nid{$a}}};
+ $B=$obj_len{$obj{$nid{$b}}};
+
+ $r=($A-$B);
+ return($r) if $r != 0;
+
+ $A=$obj_der{$obj{$nid{$a}}};
+ $B=$obj_der{$obj{$nid{$b}}};
+
+ return($A cmp $B);
+ }
+
+sub expand_obj
+ {
+ local(*v)=@_;
+ local($k,$d);
+ local($i);
+
+ do {
+ $i=0;
+ foreach $k (keys %v)
+ {
+ if (($v{$k} =~ s/(OBJ_[^,]+),/$v{$1},/))
+ { $i++; }
+ }
+ } while($i);
+ foreach $k (keys %v)
+ {
+ @a=split(/,/,$v{$k});
+ $objn{$k}=$#a+1;
+ }
+ return(%objn);
+ }
+
+open (IN,"$ARGV[0]") || die "Can't open input file $ARGV[0]";
+open (OUT,">$ARGV[1]") || die "Can't open output file $ARGV[1]";
+
+while (<IN>)
+ {
+ next unless /^\#define\s+(\S+)\s+(.*)$/;
+ $v=$1;
+ $d=$2;
+ $d =~ s/^\"//;
+ $d =~ s/\"$//;
+ if ($v =~ /^SN_(.*)$/)
+ {
+ if(defined $snames{$d})
+ {
+ print "WARNING: Duplicate short name \"$d\"\n";
+ }
+ else
+ { $snames{$d} = "X"; }
+ $sn{$1}=$d;
+ }
+ elsif ($v =~ /^LN_(.*)$/)
+ {
+ if(defined $lnames{$d})
+ {
+ print "WARNING: Duplicate long name \"$d\"\n";
+ }
+ else
+ { $lnames{$d} = "X"; }
+ $ln{$1}=$d;
+ }
+ elsif ($v =~ /^NID_(.*)$/)
+ { $nid{$d}=$1; }
+ elsif ($v =~ /^OBJ_(.*)$/)
+ {
+ $obj{$1}=$v;
+ $objd{$v}=$d;
+ }
+ }
+close IN;
+
+%ob=&expand_obj(*objd);
+
+@a=sort { $a <=> $b } keys %nid;
+$n=$a[$#a]+1;
+
+@lvalues=();
+$lvalues=0;
+
+for ($i=0; $i<$n; $i++)
+ {
+ if (!defined($nid{$i}))
+ {
+ push(@out,"{NULL,NULL,NID_undef,0,NULL,0},\n");
+ }
+ else
+ {
+ $sn=defined($sn{$nid{$i}})?"$sn{$nid{$i}}":"NULL";
+ $ln=defined($ln{$nid{$i}})?"$ln{$nid{$i}}":"NULL";
+
+ if ($sn eq "NULL") {
+ $sn=$ln;
+ $sn{$nid{$i}} = $ln;
+ }
+
+ if ($ln eq "NULL") {
+ $ln=$sn;
+ $ln{$nid{$i}} = $sn;
+ }
+
+ $out ="{";
+ $out.="\"$sn\"";
+ $out.=","."\"$ln\"";
+ $out.=",NID_$nid{$i},";
+ if (defined($obj{$nid{$i}}))
+ {
+ $v=$objd{$obj{$nid{$i}}};
+ $v =~ s/L//g;
+ $v =~ s/,/ /g;
+ $r=&der_it($v);
+ $z="";
+ $length=0;
+ foreach (unpack("C*",$r))
+ {
+ $z.=sprintf("0x%02X,",$_);
+ $length++;
+ }
+ $obj_der{$obj{$nid{$i}}}=$z;
+ $obj_len{$obj{$nid{$i}}}=$length;
+
+ push(@lvalues,sprintf("%-45s/* [%3d] %s */\n",
+ $z,$lvalues,$obj{$nid{$i}}));
+ $out.="$length,&(lvalues[$lvalues]),0";
+ $lvalues+=$length;
+ }
+ else
+ {
+ $out.="0,NULL,0";
+ }
+ $out.="},\n";
+ push(@out,$out);
+ }
+ }
+
+@a=grep(defined($sn{$nid{$_}}),0 .. $n);
+foreach (sort { $sn{$nid{$a}} cmp $sn{$nid{$b}} } @a)
+ {
+ push(@sn,sprintf("%2d,\t/* \"$sn{$nid{$_}}\" */\n",$_));
+ }
+
+@a=grep(defined($ln{$nid{$_}}),0 .. $n);
+foreach (sort { $ln{$nid{$a}} cmp $ln{$nid{$b}} } @a)
+ {
+ push(@ln,sprintf("%2d,\t/* \"$ln{$nid{$_}}\" */\n",$_));
+ }
+
+@a=grep(defined($obj{$nid{$_}}),0 .. $n);
+foreach (sort obj_cmp @a)
+ {
+ $m=$obj{$nid{$_}};
+ $v=$objd{$m};
+ $v =~ s/L//g;
+ $v =~ s/,/ /g;
+ push(@ob,sprintf("%2d,\t/* %-32s %s */\n",$_,$m,$v));
+ }
+
+print OUT <<'EOF';
+/* THIS FILE IS GENERATED FROM objects.h by obj_dat.pl via the
+ * following command:
+ * perl obj_dat.pl obj_mac.h obj_dat.h */
+
+/* Copyright (C) 1995-1997 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.] */
+
+EOF
+
+printf OUT "#define NUM_NID %d\n",$n;
+printf OUT "#define NUM_SN %d\n",$#sn+1;
+printf OUT "#define NUM_LN %d\n",$#ln+1;
+printf OUT "#define NUM_OBJ %d\n\n",$#ob+1;
+
+printf OUT "static const unsigned char lvalues[%d]={\n",$lvalues+1;
+print OUT @lvalues;
+print OUT "};\n\n";
+
+printf OUT "static const ASN1_OBJECT kObjects[NUM_NID]={\n";
+foreach (@out)
+ {
+ if (length($_) > 75)
+ {
+ $out="";
+ foreach (split(/,/))
+ {
+ $t=$out.$_.",";
+ if (length($t) > 70)
+ {
+ print OUT "$out\n";
+ $t="\t$_,";
+ }
+ $out=$t;
+ }
+ chop $out;
+ print OUT "$out";
+ }
+ else
+ { print OUT $_; }
+ }
+print OUT "};\n\n";
+
+printf OUT "static const unsigned int kNIDsInShortNameOrder[NUM_SN]={\n";
+print OUT @sn;
+print OUT "};\n\n";
+
+printf OUT "static const unsigned int kNIDsInLongNameOrder[NUM_LN]={\n";
+print OUT @ln;
+print OUT "};\n\n";
+
+printf OUT "static const unsigned int kNIDsInOIDOrder[NUM_OBJ]={\n";
+print OUT @ob;
+print OUT "};\n\n";
+
+close OUT;
+
+sub der_it
+ {
+ local($v)=@_;
+ local(@a,$i,$ret,@r);
+
+ @a=split(/\s+/,$v);
+ $ret.=pack("C*",$a[0]*40+$a[1]);
+ shift @a;
+ shift @a;
+ foreach (@a)
+ {
+ @r=();
+ $t=0;
+ while ($_ >= 128)
+ {
+ $x=$_%128;
+ $_/=128;
+ push(@r,((($t++)?0x80:0)|$x));
+ }
+ push(@r,((($t++)?0x80:0)|$_));
+ $ret.=pack("C*",reverse(@r));
+ }
+ return($ret);
+ }
diff --git a/crypto/obj/obj_error.c b/crypto/obj/obj_error.c
new file mode 100644
index 0000000..c98f10f
--- /dev/null
+++ b/crypto/obj/obj_error.c
@@ -0,0 +1,26 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/err.h>
+
+#include "obj.h"
+
+const ERR_STRING_DATA OBJ_error_string_data[] = {
+ {ERR_PACK(ERR_LIB_OBJ, OBJ_F_OBJ_create, 0), "OBJ_create"},
+ {ERR_PACK(ERR_LIB_OBJ, OBJ_F_OBJ_dup, 0), "OBJ_dup"},
+ {ERR_PACK(ERR_LIB_OBJ, OBJ_F_OBJ_nid2obj, 0), "OBJ_nid2obj"},
+ {ERR_PACK(ERR_LIB_OBJ, OBJ_F_OBJ_txt2obj, 0), "OBJ_txt2obj"},
+ {ERR_PACK(ERR_LIB_OBJ, 0, OBJ_R_UNKNOWN_NID), "UNKNOWN_NID"},
+ {0, NULL},
+};
diff --git a/crypto/obj/obj_mac.h b/crypto/obj/obj_mac.h
new file mode 100644
index 0000000..b5ad56d
--- /dev/null
+++ b/crypto/obj/obj_mac.h
@@ -0,0 +1,4148 @@
+/* crypto/objects/obj_mac.h */
+
+/* THIS FILE IS GENERATED FROM objects.txt by objects.pl via the
+ * following command:
+ * perl objects.pl objects.txt obj_mac.num obj_mac.h
+ */
+
+/* Copyright (C) 1995-1997 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.]
+ */
+
+#define SN_undef "UNDEF"
+#define LN_undef "undefined"
+#define NID_undef 0
+#define OBJ_undef 0L
+
+#define SN_itu_t "ITU-T"
+#define LN_itu_t "itu-t"
+#define NID_itu_t 645
+#define OBJ_itu_t 0L
+
+#define NID_ccitt 404
+#define OBJ_ccitt OBJ_itu_t
+
+#define SN_iso "ISO"
+#define LN_iso "iso"
+#define NID_iso 181
+#define OBJ_iso 1L
+
+#define SN_joint_iso_itu_t "JOINT-ISO-ITU-T"
+#define LN_joint_iso_itu_t "joint-iso-itu-t"
+#define NID_joint_iso_itu_t 646
+#define OBJ_joint_iso_itu_t 2L
+
+#define NID_joint_iso_ccitt 393
+#define OBJ_joint_iso_ccitt OBJ_joint_iso_itu_t
+
+#define SN_member_body "member-body"
+#define LN_member_body "ISO Member Body"
+#define NID_member_body 182
+#define OBJ_member_body OBJ_iso,2L
+
+#define SN_identified_organization "identified-organization"
+#define NID_identified_organization 676
+#define OBJ_identified_organization OBJ_iso,3L
+
+#define SN_hmac_md5 "HMAC-MD5"
+#define LN_hmac_md5 "hmac-md5"
+#define NID_hmac_md5 780
+#define OBJ_hmac_md5 OBJ_identified_organization,6L,1L,5L,5L,8L,1L,1L
+
+#define SN_hmac_sha1 "HMAC-SHA1"
+#define LN_hmac_sha1 "hmac-sha1"
+#define NID_hmac_sha1 781
+#define OBJ_hmac_sha1 OBJ_identified_organization,6L,1L,5L,5L,8L,1L,2L
+
+#define SN_certicom_arc "certicom-arc"
+#define NID_certicom_arc 677
+#define OBJ_certicom_arc OBJ_identified_organization,132L
+
+#define SN_international_organizations "international-organizations"
+#define LN_international_organizations "International Organizations"
+#define NID_international_organizations 647
+#define OBJ_international_organizations OBJ_joint_iso_itu_t,23L
+
+#define SN_wap "wap"
+#define NID_wap 678
+#define OBJ_wap OBJ_international_organizations,43L
+
+#define SN_wap_wsg "wap-wsg"
+#define NID_wap_wsg 679
+#define OBJ_wap_wsg OBJ_wap,1L
+
+#define SN_selected_attribute_types "selected-attribute-types"
+#define LN_selected_attribute_types "Selected Attribute Types"
+#define NID_selected_attribute_types 394
+#define OBJ_selected_attribute_types OBJ_joint_iso_itu_t,5L,1L,5L
+
+#define SN_clearance "clearance"
+#define NID_clearance 395
+#define OBJ_clearance OBJ_selected_attribute_types,55L
+
+#define SN_ISO_US "ISO-US"
+#define LN_ISO_US "ISO US Member Body"
+#define NID_ISO_US 183
+#define OBJ_ISO_US OBJ_member_body,840L
+
+#define SN_X9_57 "X9-57"
+#define LN_X9_57 "X9.57"
+#define NID_X9_57 184
+#define OBJ_X9_57 OBJ_ISO_US,10040L
+
+#define SN_X9cm "X9cm"
+#define LN_X9cm "X9.57 CM ?"
+#define NID_X9cm 185
+#define OBJ_X9cm OBJ_X9_57,4L
+
+#define SN_dsa "DSA"
+#define LN_dsa "dsaEncryption"
+#define NID_dsa 116
+#define OBJ_dsa OBJ_X9cm,1L
+
+#define SN_dsaWithSHA1 "DSA-SHA1"
+#define LN_dsaWithSHA1 "dsaWithSHA1"
+#define NID_dsaWithSHA1 113
+#define OBJ_dsaWithSHA1 OBJ_X9cm,3L
+
+#define SN_ansi_X9_62 "ansi-X9-62"
+#define LN_ansi_X9_62 "ANSI X9.62"
+#define NID_ansi_X9_62 405
+#define OBJ_ansi_X9_62 OBJ_ISO_US,10045L
+
+#define OBJ_X9_62_id_fieldType OBJ_ansi_X9_62,1L
+
+#define SN_X9_62_prime_field "prime-field"
+#define NID_X9_62_prime_field 406
+#define OBJ_X9_62_prime_field OBJ_X9_62_id_fieldType,1L
+
+#define SN_X9_62_characteristic_two_field "characteristic-two-field"
+#define NID_X9_62_characteristic_two_field 407
+#define OBJ_X9_62_characteristic_two_field OBJ_X9_62_id_fieldType,2L
+
+#define SN_X9_62_id_characteristic_two_basis "id-characteristic-two-basis"
+#define NID_X9_62_id_characteristic_two_basis 680
+#define OBJ_X9_62_id_characteristic_two_basis OBJ_X9_62_characteristic_two_field,3L
+
+#define SN_X9_62_onBasis "onBasis"
+#define NID_X9_62_onBasis 681
+#define OBJ_X9_62_onBasis OBJ_X9_62_id_characteristic_two_basis,1L
+
+#define SN_X9_62_tpBasis "tpBasis"
+#define NID_X9_62_tpBasis 682
+#define OBJ_X9_62_tpBasis OBJ_X9_62_id_characteristic_two_basis,2L
+
+#define SN_X9_62_ppBasis "ppBasis"
+#define NID_X9_62_ppBasis 683
+#define OBJ_X9_62_ppBasis OBJ_X9_62_id_characteristic_two_basis,3L
+
+#define OBJ_X9_62_id_publicKeyType OBJ_ansi_X9_62,2L
+
+#define SN_X9_62_id_ecPublicKey "id-ecPublicKey"
+#define NID_X9_62_id_ecPublicKey 408
+#define OBJ_X9_62_id_ecPublicKey OBJ_X9_62_id_publicKeyType,1L
+
+#define OBJ_X9_62_ellipticCurve OBJ_ansi_X9_62,3L
+
+#define OBJ_X9_62_c_TwoCurve OBJ_X9_62_ellipticCurve,0L
+
+#define SN_X9_62_c2pnb163v1 "c2pnb163v1"
+#define NID_X9_62_c2pnb163v1 684
+#define OBJ_X9_62_c2pnb163v1 OBJ_X9_62_c_TwoCurve,1L
+
+#define SN_X9_62_c2pnb163v2 "c2pnb163v2"
+#define NID_X9_62_c2pnb163v2 685
+#define OBJ_X9_62_c2pnb163v2 OBJ_X9_62_c_TwoCurve,2L
+
+#define SN_X9_62_c2pnb163v3 "c2pnb163v3"
+#define NID_X9_62_c2pnb163v3 686
+#define OBJ_X9_62_c2pnb163v3 OBJ_X9_62_c_TwoCurve,3L
+
+#define SN_X9_62_c2pnb176v1 "c2pnb176v1"
+#define NID_X9_62_c2pnb176v1 687
+#define OBJ_X9_62_c2pnb176v1 OBJ_X9_62_c_TwoCurve,4L
+
+#define SN_X9_62_c2tnb191v1 "c2tnb191v1"
+#define NID_X9_62_c2tnb191v1 688
+#define OBJ_X9_62_c2tnb191v1 OBJ_X9_62_c_TwoCurve,5L
+
+#define SN_X9_62_c2tnb191v2 "c2tnb191v2"
+#define NID_X9_62_c2tnb191v2 689
+#define OBJ_X9_62_c2tnb191v2 OBJ_X9_62_c_TwoCurve,6L
+
+#define SN_X9_62_c2tnb191v3 "c2tnb191v3"
+#define NID_X9_62_c2tnb191v3 690
+#define OBJ_X9_62_c2tnb191v3 OBJ_X9_62_c_TwoCurve,7L
+
+#define SN_X9_62_c2onb191v4 "c2onb191v4"
+#define NID_X9_62_c2onb191v4 691
+#define OBJ_X9_62_c2onb191v4 OBJ_X9_62_c_TwoCurve,8L
+
+#define SN_X9_62_c2onb191v5 "c2onb191v5"
+#define NID_X9_62_c2onb191v5 692
+#define OBJ_X9_62_c2onb191v5 OBJ_X9_62_c_TwoCurve,9L
+
+#define SN_X9_62_c2pnb208w1 "c2pnb208w1"
+#define NID_X9_62_c2pnb208w1 693
+#define OBJ_X9_62_c2pnb208w1 OBJ_X9_62_c_TwoCurve,10L
+
+#define SN_X9_62_c2tnb239v1 "c2tnb239v1"
+#define NID_X9_62_c2tnb239v1 694
+#define OBJ_X9_62_c2tnb239v1 OBJ_X9_62_c_TwoCurve,11L
+
+#define SN_X9_62_c2tnb239v2 "c2tnb239v2"
+#define NID_X9_62_c2tnb239v2 695
+#define OBJ_X9_62_c2tnb239v2 OBJ_X9_62_c_TwoCurve,12L
+
+#define SN_X9_62_c2tnb239v3 "c2tnb239v3"
+#define NID_X9_62_c2tnb239v3 696
+#define OBJ_X9_62_c2tnb239v3 OBJ_X9_62_c_TwoCurve,13L
+
+#define SN_X9_62_c2onb239v4 "c2onb239v4"
+#define NID_X9_62_c2onb239v4 697
+#define OBJ_X9_62_c2onb239v4 OBJ_X9_62_c_TwoCurve,14L
+
+#define SN_X9_62_c2onb239v5 "c2onb239v5"
+#define NID_X9_62_c2onb239v5 698
+#define OBJ_X9_62_c2onb239v5 OBJ_X9_62_c_TwoCurve,15L
+
+#define SN_X9_62_c2pnb272w1 "c2pnb272w1"
+#define NID_X9_62_c2pnb272w1 699
+#define OBJ_X9_62_c2pnb272w1 OBJ_X9_62_c_TwoCurve,16L
+
+#define SN_X9_62_c2pnb304w1 "c2pnb304w1"
+#define NID_X9_62_c2pnb304w1 700
+#define OBJ_X9_62_c2pnb304w1 OBJ_X9_62_c_TwoCurve,17L
+
+#define SN_X9_62_c2tnb359v1 "c2tnb359v1"
+#define NID_X9_62_c2tnb359v1 701
+#define OBJ_X9_62_c2tnb359v1 OBJ_X9_62_c_TwoCurve,18L
+
+#define SN_X9_62_c2pnb368w1 "c2pnb368w1"
+#define NID_X9_62_c2pnb368w1 702
+#define OBJ_X9_62_c2pnb368w1 OBJ_X9_62_c_TwoCurve,19L
+
+#define SN_X9_62_c2tnb431r1 "c2tnb431r1"
+#define NID_X9_62_c2tnb431r1 703
+#define OBJ_X9_62_c2tnb431r1 OBJ_X9_62_c_TwoCurve,20L
+
+#define OBJ_X9_62_primeCurve OBJ_X9_62_ellipticCurve,1L
+
+#define SN_X9_62_prime192v1 "prime192v1"
+#define NID_X9_62_prime192v1 409
+#define OBJ_X9_62_prime192v1 OBJ_X9_62_primeCurve,1L
+
+#define SN_X9_62_prime192v2 "prime192v2"
+#define NID_X9_62_prime192v2 410
+#define OBJ_X9_62_prime192v2 OBJ_X9_62_primeCurve,2L
+
+#define SN_X9_62_prime192v3 "prime192v3"
+#define NID_X9_62_prime192v3 411
+#define OBJ_X9_62_prime192v3 OBJ_X9_62_primeCurve,3L
+
+#define SN_X9_62_prime239v1 "prime239v1"
+#define NID_X9_62_prime239v1 412
+#define OBJ_X9_62_prime239v1 OBJ_X9_62_primeCurve,4L
+
+#define SN_X9_62_prime239v2 "prime239v2"
+#define NID_X9_62_prime239v2 413
+#define OBJ_X9_62_prime239v2 OBJ_X9_62_primeCurve,5L
+
+#define SN_X9_62_prime239v3 "prime239v3"
+#define NID_X9_62_prime239v3 414
+#define OBJ_X9_62_prime239v3 OBJ_X9_62_primeCurve,6L
+
+#define SN_X9_62_prime256v1 "prime256v1"
+#define NID_X9_62_prime256v1 415
+#define OBJ_X9_62_prime256v1 OBJ_X9_62_primeCurve,7L
+
+#define OBJ_X9_62_id_ecSigType OBJ_ansi_X9_62,4L
+
+#define SN_ecdsa_with_SHA1 "ecdsa-with-SHA1"
+#define NID_ecdsa_with_SHA1 416
+#define OBJ_ecdsa_with_SHA1 OBJ_X9_62_id_ecSigType,1L
+
+#define SN_ecdsa_with_Recommended "ecdsa-with-Recommended"
+#define NID_ecdsa_with_Recommended 791
+#define OBJ_ecdsa_with_Recommended OBJ_X9_62_id_ecSigType,2L
+
+#define SN_ecdsa_with_Specified "ecdsa-with-Specified"
+#define NID_ecdsa_with_Specified 792
+#define OBJ_ecdsa_with_Specified OBJ_X9_62_id_ecSigType,3L
+
+#define SN_ecdsa_with_SHA224 "ecdsa-with-SHA224"
+#define NID_ecdsa_with_SHA224 793
+#define OBJ_ecdsa_with_SHA224 OBJ_ecdsa_with_Specified,1L
+
+#define SN_ecdsa_with_SHA256 "ecdsa-with-SHA256"
+#define NID_ecdsa_with_SHA256 794
+#define OBJ_ecdsa_with_SHA256 OBJ_ecdsa_with_Specified,2L
+
+#define SN_ecdsa_with_SHA384 "ecdsa-with-SHA384"
+#define NID_ecdsa_with_SHA384 795
+#define OBJ_ecdsa_with_SHA384 OBJ_ecdsa_with_Specified,3L
+
+#define SN_ecdsa_with_SHA512 "ecdsa-with-SHA512"
+#define NID_ecdsa_with_SHA512 796
+#define OBJ_ecdsa_with_SHA512 OBJ_ecdsa_with_Specified,4L
+
+#define OBJ_secg_ellipticCurve OBJ_certicom_arc,0L
+
+#define SN_secp112r1 "secp112r1"
+#define NID_secp112r1 704
+#define OBJ_secp112r1 OBJ_secg_ellipticCurve,6L
+
+#define SN_secp112r2 "secp112r2"
+#define NID_secp112r2 705
+#define OBJ_secp112r2 OBJ_secg_ellipticCurve,7L
+
+#define SN_secp128r1 "secp128r1"
+#define NID_secp128r1 706
+#define OBJ_secp128r1 OBJ_secg_ellipticCurve,28L
+
+#define SN_secp128r2 "secp128r2"
+#define NID_secp128r2 707
+#define OBJ_secp128r2 OBJ_secg_ellipticCurve,29L
+
+#define SN_secp160k1 "secp160k1"
+#define NID_secp160k1 708
+#define OBJ_secp160k1 OBJ_secg_ellipticCurve,9L
+
+#define SN_secp160r1 "secp160r1"
+#define NID_secp160r1 709
+#define OBJ_secp160r1 OBJ_secg_ellipticCurve,8L
+
+#define SN_secp160r2 "secp160r2"
+#define NID_secp160r2 710
+#define OBJ_secp160r2 OBJ_secg_ellipticCurve,30L
+
+#define SN_secp192k1 "secp192k1"
+#define NID_secp192k1 711
+#define OBJ_secp192k1 OBJ_secg_ellipticCurve,31L
+
+#define SN_secp224k1 "secp224k1"
+#define NID_secp224k1 712
+#define OBJ_secp224k1 OBJ_secg_ellipticCurve,32L
+
+#define SN_secp224r1 "secp224r1"
+#define NID_secp224r1 713
+#define OBJ_secp224r1 OBJ_secg_ellipticCurve,33L
+
+#define SN_secp256k1 "secp256k1"
+#define NID_secp256k1 714
+#define OBJ_secp256k1 OBJ_secg_ellipticCurve,10L
+
+#define SN_secp384r1 "secp384r1"
+#define NID_secp384r1 715
+#define OBJ_secp384r1 OBJ_secg_ellipticCurve,34L
+
+#define SN_secp521r1 "secp521r1"
+#define NID_secp521r1 716
+#define OBJ_secp521r1 OBJ_secg_ellipticCurve,35L
+
+#define SN_sect113r1 "sect113r1"
+#define NID_sect113r1 717
+#define OBJ_sect113r1 OBJ_secg_ellipticCurve,4L
+
+#define SN_sect113r2 "sect113r2"
+#define NID_sect113r2 718
+#define OBJ_sect113r2 OBJ_secg_ellipticCurve,5L
+
+#define SN_sect131r1 "sect131r1"
+#define NID_sect131r1 719
+#define OBJ_sect131r1 OBJ_secg_ellipticCurve,22L
+
+#define SN_sect131r2 "sect131r2"
+#define NID_sect131r2 720
+#define OBJ_sect131r2 OBJ_secg_ellipticCurve,23L
+
+#define SN_sect163k1 "sect163k1"
+#define NID_sect163k1 721
+#define OBJ_sect163k1 OBJ_secg_ellipticCurve,1L
+
+#define SN_sect163r1 "sect163r1"
+#define NID_sect163r1 722
+#define OBJ_sect163r1 OBJ_secg_ellipticCurve,2L
+
+#define SN_sect163r2 "sect163r2"
+#define NID_sect163r2 723
+#define OBJ_sect163r2 OBJ_secg_ellipticCurve,15L
+
+#define SN_sect193r1 "sect193r1"
+#define NID_sect193r1 724
+#define OBJ_sect193r1 OBJ_secg_ellipticCurve,24L
+
+#define SN_sect193r2 "sect193r2"
+#define NID_sect193r2 725
+#define OBJ_sect193r2 OBJ_secg_ellipticCurve,25L
+
+#define SN_sect233k1 "sect233k1"
+#define NID_sect233k1 726
+#define OBJ_sect233k1 OBJ_secg_ellipticCurve,26L
+
+#define SN_sect233r1 "sect233r1"
+#define NID_sect233r1 727
+#define OBJ_sect233r1 OBJ_secg_ellipticCurve,27L
+
+#define SN_sect239k1 "sect239k1"
+#define NID_sect239k1 728
+#define OBJ_sect239k1 OBJ_secg_ellipticCurve,3L
+
+#define SN_sect283k1 "sect283k1"
+#define NID_sect283k1 729
+#define OBJ_sect283k1 OBJ_secg_ellipticCurve,16L
+
+#define SN_sect283r1 "sect283r1"
+#define NID_sect283r1 730
+#define OBJ_sect283r1 OBJ_secg_ellipticCurve,17L
+
+#define SN_sect409k1 "sect409k1"
+#define NID_sect409k1 731
+#define OBJ_sect409k1 OBJ_secg_ellipticCurve,36L
+
+#define SN_sect409r1 "sect409r1"
+#define NID_sect409r1 732
+#define OBJ_sect409r1 OBJ_secg_ellipticCurve,37L
+
+#define SN_sect571k1 "sect571k1"
+#define NID_sect571k1 733
+#define OBJ_sect571k1 OBJ_secg_ellipticCurve,38L
+
+#define SN_sect571r1 "sect571r1"
+#define NID_sect571r1 734
+#define OBJ_sect571r1 OBJ_secg_ellipticCurve,39L
+
+#define OBJ_wap_wsg_idm_ecid OBJ_wap_wsg,4L
+
+#define SN_wap_wsg_idm_ecid_wtls1 "wap-wsg-idm-ecid-wtls1"
+#define NID_wap_wsg_idm_ecid_wtls1 735
+#define OBJ_wap_wsg_idm_ecid_wtls1 OBJ_wap_wsg_idm_ecid,1L
+
+#define SN_wap_wsg_idm_ecid_wtls3 "wap-wsg-idm-ecid-wtls3"
+#define NID_wap_wsg_idm_ecid_wtls3 736
+#define OBJ_wap_wsg_idm_ecid_wtls3 OBJ_wap_wsg_idm_ecid,3L
+
+#define SN_wap_wsg_idm_ecid_wtls4 "wap-wsg-idm-ecid-wtls4"
+#define NID_wap_wsg_idm_ecid_wtls4 737
+#define OBJ_wap_wsg_idm_ecid_wtls4 OBJ_wap_wsg_idm_ecid,4L
+
+#define SN_wap_wsg_idm_ecid_wtls5 "wap-wsg-idm-ecid-wtls5"
+#define NID_wap_wsg_idm_ecid_wtls5 738
+#define OBJ_wap_wsg_idm_ecid_wtls5 OBJ_wap_wsg_idm_ecid,5L
+
+#define SN_wap_wsg_idm_ecid_wtls6 "wap-wsg-idm-ecid-wtls6"
+#define NID_wap_wsg_idm_ecid_wtls6 739
+#define OBJ_wap_wsg_idm_ecid_wtls6 OBJ_wap_wsg_idm_ecid,6L
+
+#define SN_wap_wsg_idm_ecid_wtls7 "wap-wsg-idm-ecid-wtls7"
+#define NID_wap_wsg_idm_ecid_wtls7 740
+#define OBJ_wap_wsg_idm_ecid_wtls7 OBJ_wap_wsg_idm_ecid,7L
+
+#define SN_wap_wsg_idm_ecid_wtls8 "wap-wsg-idm-ecid-wtls8"
+#define NID_wap_wsg_idm_ecid_wtls8 741
+#define OBJ_wap_wsg_idm_ecid_wtls8 OBJ_wap_wsg_idm_ecid,8L
+
+#define SN_wap_wsg_idm_ecid_wtls9 "wap-wsg-idm-ecid-wtls9"
+#define NID_wap_wsg_idm_ecid_wtls9 742
+#define OBJ_wap_wsg_idm_ecid_wtls9 OBJ_wap_wsg_idm_ecid,9L
+
+#define SN_wap_wsg_idm_ecid_wtls10 "wap-wsg-idm-ecid-wtls10"
+#define NID_wap_wsg_idm_ecid_wtls10 743
+#define OBJ_wap_wsg_idm_ecid_wtls10 OBJ_wap_wsg_idm_ecid,10L
+
+#define SN_wap_wsg_idm_ecid_wtls11 "wap-wsg-idm-ecid-wtls11"
+#define NID_wap_wsg_idm_ecid_wtls11 744
+#define OBJ_wap_wsg_idm_ecid_wtls11 OBJ_wap_wsg_idm_ecid,11L
+
+#define SN_wap_wsg_idm_ecid_wtls12 "wap-wsg-idm-ecid-wtls12"
+#define NID_wap_wsg_idm_ecid_wtls12 745
+#define OBJ_wap_wsg_idm_ecid_wtls12 OBJ_wap_wsg_idm_ecid,12L
+
+#define SN_cast5_cbc "CAST5-CBC"
+#define LN_cast5_cbc "cast5-cbc"
+#define NID_cast5_cbc 108
+#define OBJ_cast5_cbc OBJ_ISO_US,113533L,7L,66L,10L
+
+#define SN_cast5_ecb "CAST5-ECB"
+#define LN_cast5_ecb "cast5-ecb"
+#define NID_cast5_ecb 109
+
+#define SN_cast5_cfb64 "CAST5-CFB"
+#define LN_cast5_cfb64 "cast5-cfb"
+#define NID_cast5_cfb64 110
+
+#define SN_cast5_ofb64 "CAST5-OFB"
+#define LN_cast5_ofb64 "cast5-ofb"
+#define NID_cast5_ofb64 111
+
+#define LN_pbeWithMD5AndCast5_CBC "pbeWithMD5AndCast5CBC"
+#define NID_pbeWithMD5AndCast5_CBC 112
+#define OBJ_pbeWithMD5AndCast5_CBC OBJ_ISO_US,113533L,7L,66L,12L
+
+#define SN_id_PasswordBasedMAC "id-PasswordBasedMAC"
+#define LN_id_PasswordBasedMAC "password based MAC"
+#define NID_id_PasswordBasedMAC 782
+#define OBJ_id_PasswordBasedMAC OBJ_ISO_US,113533L,7L,66L,13L
+
+#define SN_id_DHBasedMac "id-DHBasedMac"
+#define LN_id_DHBasedMac "Diffie-Hellman based MAC"
+#define NID_id_DHBasedMac 783
+#define OBJ_id_DHBasedMac OBJ_ISO_US,113533L,7L,66L,30L
+
+#define SN_rsadsi "rsadsi"
+#define LN_rsadsi "RSA Data Security, Inc."
+#define NID_rsadsi 1
+#define OBJ_rsadsi OBJ_ISO_US,113549L
+
+#define SN_pkcs "pkcs"
+#define LN_pkcs "RSA Data Security, Inc. PKCS"
+#define NID_pkcs 2
+#define OBJ_pkcs OBJ_rsadsi,1L
+
+#define SN_pkcs1 "pkcs1"
+#define NID_pkcs1 186
+#define OBJ_pkcs1 OBJ_pkcs,1L
+
+#define LN_rsaEncryption "rsaEncryption"
+#define NID_rsaEncryption 6
+#define OBJ_rsaEncryption OBJ_pkcs1,1L
+
+#define SN_md2WithRSAEncryption "RSA-MD2"
+#define LN_md2WithRSAEncryption "md2WithRSAEncryption"
+#define NID_md2WithRSAEncryption 7
+#define OBJ_md2WithRSAEncryption OBJ_pkcs1,2L
+
+#define SN_md4WithRSAEncryption "RSA-MD4"
+#define LN_md4WithRSAEncryption "md4WithRSAEncryption"
+#define NID_md4WithRSAEncryption 396
+#define OBJ_md4WithRSAEncryption OBJ_pkcs1,3L
+
+#define SN_md5WithRSAEncryption "RSA-MD5"
+#define LN_md5WithRSAEncryption "md5WithRSAEncryption"
+#define NID_md5WithRSAEncryption 8
+#define OBJ_md5WithRSAEncryption OBJ_pkcs1,4L
+
+#define SN_sha1WithRSAEncryption "RSA-SHA1"
+#define LN_sha1WithRSAEncryption "sha1WithRSAEncryption"
+#define NID_sha1WithRSAEncryption 65
+#define OBJ_sha1WithRSAEncryption OBJ_pkcs1,5L
+
+#define SN_rsaesOaep "RSAES-OAEP"
+#define LN_rsaesOaep "rsaesOaep"
+#define NID_rsaesOaep 919
+#define OBJ_rsaesOaep OBJ_pkcs1,7L
+
+#define SN_mgf1 "MGF1"
+#define LN_mgf1 "mgf1"
+#define NID_mgf1 911
+#define OBJ_mgf1 OBJ_pkcs1,8L
+
+#define SN_pSpecified "PSPECIFIED"
+#define LN_pSpecified "pSpecified"
+#define NID_pSpecified 935
+#define OBJ_pSpecified OBJ_pkcs1,9L
+
+#define SN_rsassaPss "RSASSA-PSS"
+#define LN_rsassaPss "rsassaPss"
+#define NID_rsassaPss 912
+#define OBJ_rsassaPss OBJ_pkcs1,10L
+
+#define SN_sha256WithRSAEncryption "RSA-SHA256"
+#define LN_sha256WithRSAEncryption "sha256WithRSAEncryption"
+#define NID_sha256WithRSAEncryption 668
+#define OBJ_sha256WithRSAEncryption OBJ_pkcs1,11L
+
+#define SN_sha384WithRSAEncryption "RSA-SHA384"
+#define LN_sha384WithRSAEncryption "sha384WithRSAEncryption"
+#define NID_sha384WithRSAEncryption 669
+#define OBJ_sha384WithRSAEncryption OBJ_pkcs1,12L
+
+#define SN_sha512WithRSAEncryption "RSA-SHA512"
+#define LN_sha512WithRSAEncryption "sha512WithRSAEncryption"
+#define NID_sha512WithRSAEncryption 670
+#define OBJ_sha512WithRSAEncryption OBJ_pkcs1,13L
+
+#define SN_sha224WithRSAEncryption "RSA-SHA224"
+#define LN_sha224WithRSAEncryption "sha224WithRSAEncryption"
+#define NID_sha224WithRSAEncryption 671
+#define OBJ_sha224WithRSAEncryption OBJ_pkcs1,14L
+
+#define SN_pkcs3 "pkcs3"
+#define NID_pkcs3 27
+#define OBJ_pkcs3 OBJ_pkcs,3L
+
+#define LN_dhKeyAgreement "dhKeyAgreement"
+#define NID_dhKeyAgreement 28
+#define OBJ_dhKeyAgreement OBJ_pkcs3,1L
+
+#define SN_pkcs5 "pkcs5"
+#define NID_pkcs5 187
+#define OBJ_pkcs5 OBJ_pkcs,5L
+
+#define SN_pbeWithMD2AndDES_CBC "PBE-MD2-DES"
+#define LN_pbeWithMD2AndDES_CBC "pbeWithMD2AndDES-CBC"
+#define NID_pbeWithMD2AndDES_CBC 9
+#define OBJ_pbeWithMD2AndDES_CBC OBJ_pkcs5,1L
+
+#define SN_pbeWithMD5AndDES_CBC "PBE-MD5-DES"
+#define LN_pbeWithMD5AndDES_CBC "pbeWithMD5AndDES-CBC"
+#define NID_pbeWithMD5AndDES_CBC 10
+#define OBJ_pbeWithMD5AndDES_CBC OBJ_pkcs5,3L
+
+#define SN_pbeWithMD2AndRC2_CBC "PBE-MD2-RC2-64"
+#define LN_pbeWithMD2AndRC2_CBC "pbeWithMD2AndRC2-CBC"
+#define NID_pbeWithMD2AndRC2_CBC 168
+#define OBJ_pbeWithMD2AndRC2_CBC OBJ_pkcs5,4L
+
+#define SN_pbeWithMD5AndRC2_CBC "PBE-MD5-RC2-64"
+#define LN_pbeWithMD5AndRC2_CBC "pbeWithMD5AndRC2-CBC"
+#define NID_pbeWithMD5AndRC2_CBC 169
+#define OBJ_pbeWithMD5AndRC2_CBC OBJ_pkcs5,6L
+
+#define SN_pbeWithSHA1AndDES_CBC "PBE-SHA1-DES"
+#define LN_pbeWithSHA1AndDES_CBC "pbeWithSHA1AndDES-CBC"
+#define NID_pbeWithSHA1AndDES_CBC 170
+#define OBJ_pbeWithSHA1AndDES_CBC OBJ_pkcs5,10L
+
+#define SN_pbeWithSHA1AndRC2_CBC "PBE-SHA1-RC2-64"
+#define LN_pbeWithSHA1AndRC2_CBC "pbeWithSHA1AndRC2-CBC"
+#define NID_pbeWithSHA1AndRC2_CBC 68
+#define OBJ_pbeWithSHA1AndRC2_CBC OBJ_pkcs5,11L
+
+#define LN_id_pbkdf2 "PBKDF2"
+#define NID_id_pbkdf2 69
+#define OBJ_id_pbkdf2 OBJ_pkcs5,12L
+
+#define LN_pbes2 "PBES2"
+#define NID_pbes2 161
+#define OBJ_pbes2 OBJ_pkcs5,13L
+
+#define LN_pbmac1 "PBMAC1"
+#define NID_pbmac1 162
+#define OBJ_pbmac1 OBJ_pkcs5,14L
+
+#define SN_pkcs7 "pkcs7"
+#define NID_pkcs7 20
+#define OBJ_pkcs7 OBJ_pkcs,7L
+
+#define LN_pkcs7_data "pkcs7-data"
+#define NID_pkcs7_data 21
+#define OBJ_pkcs7_data OBJ_pkcs7,1L
+
+#define LN_pkcs7_signed "pkcs7-signedData"
+#define NID_pkcs7_signed 22
+#define OBJ_pkcs7_signed OBJ_pkcs7,2L
+
+#define LN_pkcs7_enveloped "pkcs7-envelopedData"
+#define NID_pkcs7_enveloped 23
+#define OBJ_pkcs7_enveloped OBJ_pkcs7,3L
+
+#define LN_pkcs7_signedAndEnveloped "pkcs7-signedAndEnvelopedData"
+#define NID_pkcs7_signedAndEnveloped 24
+#define OBJ_pkcs7_signedAndEnveloped OBJ_pkcs7,4L
+
+#define LN_pkcs7_digest "pkcs7-digestData"
+#define NID_pkcs7_digest 25
+#define OBJ_pkcs7_digest OBJ_pkcs7,5L
+
+#define LN_pkcs7_encrypted "pkcs7-encryptedData"
+#define NID_pkcs7_encrypted 26
+#define OBJ_pkcs7_encrypted OBJ_pkcs7,6L
+
+#define SN_pkcs9 "pkcs9"
+#define NID_pkcs9 47
+#define OBJ_pkcs9 OBJ_pkcs,9L
+
+#define LN_pkcs9_emailAddress "emailAddress"
+#define NID_pkcs9_emailAddress 48
+#define OBJ_pkcs9_emailAddress OBJ_pkcs9,1L
+
+#define LN_pkcs9_unstructuredName "unstructuredName"
+#define NID_pkcs9_unstructuredName 49
+#define OBJ_pkcs9_unstructuredName OBJ_pkcs9,2L
+
+#define LN_pkcs9_contentType "contentType"
+#define NID_pkcs9_contentType 50
+#define OBJ_pkcs9_contentType OBJ_pkcs9,3L
+
+#define LN_pkcs9_messageDigest "messageDigest"
+#define NID_pkcs9_messageDigest 51
+#define OBJ_pkcs9_messageDigest OBJ_pkcs9,4L
+
+#define LN_pkcs9_signingTime "signingTime"
+#define NID_pkcs9_signingTime 52
+#define OBJ_pkcs9_signingTime OBJ_pkcs9,5L
+
+#define LN_pkcs9_countersignature "countersignature"
+#define NID_pkcs9_countersignature 53
+#define OBJ_pkcs9_countersignature OBJ_pkcs9,6L
+
+#define LN_pkcs9_challengePassword "challengePassword"
+#define NID_pkcs9_challengePassword 54
+#define OBJ_pkcs9_challengePassword OBJ_pkcs9,7L
+
+#define LN_pkcs9_unstructuredAddress "unstructuredAddress"
+#define NID_pkcs9_unstructuredAddress 55
+#define OBJ_pkcs9_unstructuredAddress OBJ_pkcs9,8L
+
+#define LN_pkcs9_extCertAttributes "extendedCertificateAttributes"
+#define NID_pkcs9_extCertAttributes 56
+#define OBJ_pkcs9_extCertAttributes OBJ_pkcs9,9L
+
+#define SN_ext_req "extReq"
+#define LN_ext_req "Extension Request"
+#define NID_ext_req 172
+#define OBJ_ext_req OBJ_pkcs9,14L
+
+#define SN_SMIMECapabilities "SMIME-CAPS"
+#define LN_SMIMECapabilities "S/MIME Capabilities"
+#define NID_SMIMECapabilities 167
+#define OBJ_SMIMECapabilities OBJ_pkcs9,15L
+
+#define SN_SMIME "SMIME"
+#define LN_SMIME "S/MIME"
+#define NID_SMIME 188
+#define OBJ_SMIME OBJ_pkcs9,16L
+
+#define SN_id_smime_mod "id-smime-mod"
+#define NID_id_smime_mod 189
+#define OBJ_id_smime_mod OBJ_SMIME,0L
+
+#define SN_id_smime_ct "id-smime-ct"
+#define NID_id_smime_ct 190
+#define OBJ_id_smime_ct OBJ_SMIME,1L
+
+#define SN_id_smime_aa "id-smime-aa"
+#define NID_id_smime_aa 191
+#define OBJ_id_smime_aa OBJ_SMIME,2L
+
+#define SN_id_smime_alg "id-smime-alg"
+#define NID_id_smime_alg 192
+#define OBJ_id_smime_alg OBJ_SMIME,3L
+
+#define SN_id_smime_cd "id-smime-cd"
+#define NID_id_smime_cd 193
+#define OBJ_id_smime_cd OBJ_SMIME,4L
+
+#define SN_id_smime_spq "id-smime-spq"
+#define NID_id_smime_spq 194
+#define OBJ_id_smime_spq OBJ_SMIME,5L
+
+#define SN_id_smime_cti "id-smime-cti"
+#define NID_id_smime_cti 195
+#define OBJ_id_smime_cti OBJ_SMIME,6L
+
+#define SN_id_smime_mod_cms "id-smime-mod-cms"
+#define NID_id_smime_mod_cms 196
+#define OBJ_id_smime_mod_cms OBJ_id_smime_mod,1L
+
+#define SN_id_smime_mod_ess "id-smime-mod-ess"
+#define NID_id_smime_mod_ess 197
+#define OBJ_id_smime_mod_ess OBJ_id_smime_mod,2L
+
+#define SN_id_smime_mod_oid "id-smime-mod-oid"
+#define NID_id_smime_mod_oid 198
+#define OBJ_id_smime_mod_oid OBJ_id_smime_mod,3L
+
+#define SN_id_smime_mod_msg_v3 "id-smime-mod-msg-v3"
+#define NID_id_smime_mod_msg_v3 199
+#define OBJ_id_smime_mod_msg_v3 OBJ_id_smime_mod,4L
+
+#define SN_id_smime_mod_ets_eSignature_88 "id-smime-mod-ets-eSignature-88"
+#define NID_id_smime_mod_ets_eSignature_88 200
+#define OBJ_id_smime_mod_ets_eSignature_88 OBJ_id_smime_mod,5L
+
+#define SN_id_smime_mod_ets_eSignature_97 "id-smime-mod-ets-eSignature-97"
+#define NID_id_smime_mod_ets_eSignature_97 201
+#define OBJ_id_smime_mod_ets_eSignature_97 OBJ_id_smime_mod,6L
+
+#define SN_id_smime_mod_ets_eSigPolicy_88 "id-smime-mod-ets-eSigPolicy-88"
+#define NID_id_smime_mod_ets_eSigPolicy_88 202
+#define OBJ_id_smime_mod_ets_eSigPolicy_88 OBJ_id_smime_mod,7L
+
+#define SN_id_smime_mod_ets_eSigPolicy_97 "id-smime-mod-ets-eSigPolicy-97"
+#define NID_id_smime_mod_ets_eSigPolicy_97 203
+#define OBJ_id_smime_mod_ets_eSigPolicy_97 OBJ_id_smime_mod,8L
+
+#define SN_id_smime_ct_receipt "id-smime-ct-receipt"
+#define NID_id_smime_ct_receipt 204
+#define OBJ_id_smime_ct_receipt OBJ_id_smime_ct,1L
+
+#define SN_id_smime_ct_authData "id-smime-ct-authData"
+#define NID_id_smime_ct_authData 205
+#define OBJ_id_smime_ct_authData OBJ_id_smime_ct,2L
+
+#define SN_id_smime_ct_publishCert "id-smime-ct-publishCert"
+#define NID_id_smime_ct_publishCert 206
+#define OBJ_id_smime_ct_publishCert OBJ_id_smime_ct,3L
+
+#define SN_id_smime_ct_TSTInfo "id-smime-ct-TSTInfo"
+#define NID_id_smime_ct_TSTInfo 207
+#define OBJ_id_smime_ct_TSTInfo OBJ_id_smime_ct,4L
+
+#define SN_id_smime_ct_TDTInfo "id-smime-ct-TDTInfo"
+#define NID_id_smime_ct_TDTInfo 208
+#define OBJ_id_smime_ct_TDTInfo OBJ_id_smime_ct,5L
+
+#define SN_id_smime_ct_contentInfo "id-smime-ct-contentInfo"
+#define NID_id_smime_ct_contentInfo 209
+#define OBJ_id_smime_ct_contentInfo OBJ_id_smime_ct,6L
+
+#define SN_id_smime_ct_DVCSRequestData "id-smime-ct-DVCSRequestData"
+#define NID_id_smime_ct_DVCSRequestData 210
+#define OBJ_id_smime_ct_DVCSRequestData OBJ_id_smime_ct,7L
+
+#define SN_id_smime_ct_DVCSResponseData "id-smime-ct-DVCSResponseData"
+#define NID_id_smime_ct_DVCSResponseData 211
+#define OBJ_id_smime_ct_DVCSResponseData OBJ_id_smime_ct,8L
+
+#define SN_id_smime_ct_compressedData "id-smime-ct-compressedData"
+#define NID_id_smime_ct_compressedData 786
+#define OBJ_id_smime_ct_compressedData OBJ_id_smime_ct,9L
+
+#define SN_id_ct_asciiTextWithCRLF "id-ct-asciiTextWithCRLF"
+#define NID_id_ct_asciiTextWithCRLF 787
+#define OBJ_id_ct_asciiTextWithCRLF OBJ_id_smime_ct,27L
+
+#define SN_id_smime_aa_receiptRequest "id-smime-aa-receiptRequest"
+#define NID_id_smime_aa_receiptRequest 212
+#define OBJ_id_smime_aa_receiptRequest OBJ_id_smime_aa,1L
+
+#define SN_id_smime_aa_securityLabel "id-smime-aa-securityLabel"
+#define NID_id_smime_aa_securityLabel 213
+#define OBJ_id_smime_aa_securityLabel OBJ_id_smime_aa,2L
+
+#define SN_id_smime_aa_mlExpandHistory "id-smime-aa-mlExpandHistory"
+#define NID_id_smime_aa_mlExpandHistory 214
+#define OBJ_id_smime_aa_mlExpandHistory OBJ_id_smime_aa,3L
+
+#define SN_id_smime_aa_contentHint "id-smime-aa-contentHint"
+#define NID_id_smime_aa_contentHint 215
+#define OBJ_id_smime_aa_contentHint OBJ_id_smime_aa,4L
+
+#define SN_id_smime_aa_msgSigDigest "id-smime-aa-msgSigDigest"
+#define NID_id_smime_aa_msgSigDigest 216
+#define OBJ_id_smime_aa_msgSigDigest OBJ_id_smime_aa,5L
+
+#define SN_id_smime_aa_encapContentType "id-smime-aa-encapContentType"
+#define NID_id_smime_aa_encapContentType 217
+#define OBJ_id_smime_aa_encapContentType OBJ_id_smime_aa,6L
+
+#define SN_id_smime_aa_contentIdentifier "id-smime-aa-contentIdentifier"
+#define NID_id_smime_aa_contentIdentifier 218
+#define OBJ_id_smime_aa_contentIdentifier OBJ_id_smime_aa,7L
+
+#define SN_id_smime_aa_macValue "id-smime-aa-macValue"
+#define NID_id_smime_aa_macValue 219
+#define OBJ_id_smime_aa_macValue OBJ_id_smime_aa,8L
+
+#define SN_id_smime_aa_equivalentLabels "id-smime-aa-equivalentLabels"
+#define NID_id_smime_aa_equivalentLabels 220
+#define OBJ_id_smime_aa_equivalentLabels OBJ_id_smime_aa,9L
+
+#define SN_id_smime_aa_contentReference "id-smime-aa-contentReference"
+#define NID_id_smime_aa_contentReference 221
+#define OBJ_id_smime_aa_contentReference OBJ_id_smime_aa,10L
+
+#define SN_id_smime_aa_encrypKeyPref "id-smime-aa-encrypKeyPref"
+#define NID_id_smime_aa_encrypKeyPref 222
+#define OBJ_id_smime_aa_encrypKeyPref OBJ_id_smime_aa,11L
+
+#define SN_id_smime_aa_signingCertificate "id-smime-aa-signingCertificate"
+#define NID_id_smime_aa_signingCertificate 223
+#define OBJ_id_smime_aa_signingCertificate OBJ_id_smime_aa,12L
+
+#define SN_id_smime_aa_smimeEncryptCerts "id-smime-aa-smimeEncryptCerts"
+#define NID_id_smime_aa_smimeEncryptCerts 224
+#define OBJ_id_smime_aa_smimeEncryptCerts OBJ_id_smime_aa,13L
+
+#define SN_id_smime_aa_timeStampToken "id-smime-aa-timeStampToken"
+#define NID_id_smime_aa_timeStampToken 225
+#define OBJ_id_smime_aa_timeStampToken OBJ_id_smime_aa,14L
+
+#define SN_id_smime_aa_ets_sigPolicyId "id-smime-aa-ets-sigPolicyId"
+#define NID_id_smime_aa_ets_sigPolicyId 226
+#define OBJ_id_smime_aa_ets_sigPolicyId OBJ_id_smime_aa,15L
+
+#define SN_id_smime_aa_ets_commitmentType "id-smime-aa-ets-commitmentType"
+#define NID_id_smime_aa_ets_commitmentType 227
+#define OBJ_id_smime_aa_ets_commitmentType OBJ_id_smime_aa,16L
+
+#define SN_id_smime_aa_ets_signerLocation "id-smime-aa-ets-signerLocation"
+#define NID_id_smime_aa_ets_signerLocation 228
+#define OBJ_id_smime_aa_ets_signerLocation OBJ_id_smime_aa,17L
+
+#define SN_id_smime_aa_ets_signerAttr "id-smime-aa-ets-signerAttr"
+#define NID_id_smime_aa_ets_signerAttr 229
+#define OBJ_id_smime_aa_ets_signerAttr OBJ_id_smime_aa,18L
+
+#define SN_id_smime_aa_ets_otherSigCert "id-smime-aa-ets-otherSigCert"
+#define NID_id_smime_aa_ets_otherSigCert 230
+#define OBJ_id_smime_aa_ets_otherSigCert OBJ_id_smime_aa,19L
+
+#define SN_id_smime_aa_ets_contentTimestamp "id-smime-aa-ets-contentTimestamp"
+#define NID_id_smime_aa_ets_contentTimestamp 231
+#define OBJ_id_smime_aa_ets_contentTimestamp OBJ_id_smime_aa,20L
+
+#define SN_id_smime_aa_ets_CertificateRefs "id-smime-aa-ets-CertificateRefs"
+#define NID_id_smime_aa_ets_CertificateRefs 232
+#define OBJ_id_smime_aa_ets_CertificateRefs OBJ_id_smime_aa,21L
+
+#define SN_id_smime_aa_ets_RevocationRefs "id-smime-aa-ets-RevocationRefs"
+#define NID_id_smime_aa_ets_RevocationRefs 233
+#define OBJ_id_smime_aa_ets_RevocationRefs OBJ_id_smime_aa,22L
+
+#define SN_id_smime_aa_ets_certValues "id-smime-aa-ets-certValues"
+#define NID_id_smime_aa_ets_certValues 234
+#define OBJ_id_smime_aa_ets_certValues OBJ_id_smime_aa,23L
+
+#define SN_id_smime_aa_ets_revocationValues "id-smime-aa-ets-revocationValues"
+#define NID_id_smime_aa_ets_revocationValues 235
+#define OBJ_id_smime_aa_ets_revocationValues OBJ_id_smime_aa,24L
+
+#define SN_id_smime_aa_ets_escTimeStamp "id-smime-aa-ets-escTimeStamp"
+#define NID_id_smime_aa_ets_escTimeStamp 236
+#define OBJ_id_smime_aa_ets_escTimeStamp OBJ_id_smime_aa,25L
+
+#define SN_id_smime_aa_ets_certCRLTimestamp "id-smime-aa-ets-certCRLTimestamp"
+#define NID_id_smime_aa_ets_certCRLTimestamp 237
+#define OBJ_id_smime_aa_ets_certCRLTimestamp OBJ_id_smime_aa,26L
+
+#define SN_id_smime_aa_ets_archiveTimeStamp "id-smime-aa-ets-archiveTimeStamp"
+#define NID_id_smime_aa_ets_archiveTimeStamp 238
+#define OBJ_id_smime_aa_ets_archiveTimeStamp OBJ_id_smime_aa,27L
+
+#define SN_id_smime_aa_signatureType "id-smime-aa-signatureType"
+#define NID_id_smime_aa_signatureType 239
+#define OBJ_id_smime_aa_signatureType OBJ_id_smime_aa,28L
+
+#define SN_id_smime_aa_dvcs_dvc "id-smime-aa-dvcs-dvc"
+#define NID_id_smime_aa_dvcs_dvc 240
+#define OBJ_id_smime_aa_dvcs_dvc OBJ_id_smime_aa,29L
+
+#define SN_id_smime_alg_ESDHwith3DES "id-smime-alg-ESDHwith3DES"
+#define NID_id_smime_alg_ESDHwith3DES 241
+#define OBJ_id_smime_alg_ESDHwith3DES OBJ_id_smime_alg,1L
+
+#define SN_id_smime_alg_ESDHwithRC2 "id-smime-alg-ESDHwithRC2"
+#define NID_id_smime_alg_ESDHwithRC2 242
+#define OBJ_id_smime_alg_ESDHwithRC2 OBJ_id_smime_alg,2L
+
+#define SN_id_smime_alg_3DESwrap "id-smime-alg-3DESwrap"
+#define NID_id_smime_alg_3DESwrap 243
+#define OBJ_id_smime_alg_3DESwrap OBJ_id_smime_alg,3L
+
+#define SN_id_smime_alg_RC2wrap "id-smime-alg-RC2wrap"
+#define NID_id_smime_alg_RC2wrap 244
+#define OBJ_id_smime_alg_RC2wrap OBJ_id_smime_alg,4L
+
+#define SN_id_smime_alg_ESDH "id-smime-alg-ESDH"
+#define NID_id_smime_alg_ESDH 245
+#define OBJ_id_smime_alg_ESDH OBJ_id_smime_alg,5L
+
+#define SN_id_smime_alg_CMS3DESwrap "id-smime-alg-CMS3DESwrap"
+#define NID_id_smime_alg_CMS3DESwrap 246
+#define OBJ_id_smime_alg_CMS3DESwrap OBJ_id_smime_alg,6L
+
+#define SN_id_smime_alg_CMSRC2wrap "id-smime-alg-CMSRC2wrap"
+#define NID_id_smime_alg_CMSRC2wrap 247
+#define OBJ_id_smime_alg_CMSRC2wrap OBJ_id_smime_alg,7L
+
+#define SN_id_alg_PWRI_KEK "id-alg-PWRI-KEK"
+#define NID_id_alg_PWRI_KEK 893
+#define OBJ_id_alg_PWRI_KEK OBJ_id_smime_alg,9L
+
+#define SN_id_smime_cd_ldap "id-smime-cd-ldap"
+#define NID_id_smime_cd_ldap 248
+#define OBJ_id_smime_cd_ldap OBJ_id_smime_cd,1L
+
+#define SN_id_smime_spq_ets_sqt_uri "id-smime-spq-ets-sqt-uri"
+#define NID_id_smime_spq_ets_sqt_uri 249
+#define OBJ_id_smime_spq_ets_sqt_uri OBJ_id_smime_spq,1L
+
+#define SN_id_smime_spq_ets_sqt_unotice "id-smime-spq-ets-sqt-unotice"
+#define NID_id_smime_spq_ets_sqt_unotice 250
+#define OBJ_id_smime_spq_ets_sqt_unotice OBJ_id_smime_spq,2L
+
+#define SN_id_smime_cti_ets_proofOfOrigin "id-smime-cti-ets-proofOfOrigin"
+#define NID_id_smime_cti_ets_proofOfOrigin 251
+#define OBJ_id_smime_cti_ets_proofOfOrigin OBJ_id_smime_cti,1L
+
+#define SN_id_smime_cti_ets_proofOfReceipt "id-smime-cti-ets-proofOfReceipt"
+#define NID_id_smime_cti_ets_proofOfReceipt 252
+#define OBJ_id_smime_cti_ets_proofOfReceipt OBJ_id_smime_cti,2L
+
+#define SN_id_smime_cti_ets_proofOfDelivery "id-smime-cti-ets-proofOfDelivery"
+#define NID_id_smime_cti_ets_proofOfDelivery 253
+#define OBJ_id_smime_cti_ets_proofOfDelivery OBJ_id_smime_cti,3L
+
+#define SN_id_smime_cti_ets_proofOfSender "id-smime-cti-ets-proofOfSender"
+#define NID_id_smime_cti_ets_proofOfSender 254
+#define OBJ_id_smime_cti_ets_proofOfSender OBJ_id_smime_cti,4L
+
+#define SN_id_smime_cti_ets_proofOfApproval "id-smime-cti-ets-proofOfApproval"
+#define NID_id_smime_cti_ets_proofOfApproval 255
+#define OBJ_id_smime_cti_ets_proofOfApproval OBJ_id_smime_cti,5L
+
+#define SN_id_smime_cti_ets_proofOfCreation "id-smime-cti-ets-proofOfCreation"
+#define NID_id_smime_cti_ets_proofOfCreation 256
+#define OBJ_id_smime_cti_ets_proofOfCreation OBJ_id_smime_cti,6L
+
+#define LN_friendlyName "friendlyName"
+#define NID_friendlyName 156
+#define OBJ_friendlyName OBJ_pkcs9,20L
+
+#define LN_localKeyID "localKeyID"
+#define NID_localKeyID 157
+#define OBJ_localKeyID OBJ_pkcs9,21L
+
+#define SN_ms_csp_name "CSPName"
+#define LN_ms_csp_name "Microsoft CSP Name"
+#define NID_ms_csp_name 417
+#define OBJ_ms_csp_name 1L,3L,6L,1L,4L,1L,311L,17L,1L
+
+#define SN_LocalKeySet "LocalKeySet"
+#define LN_LocalKeySet "Microsoft Local Key set"
+#define NID_LocalKeySet 856
+#define OBJ_LocalKeySet 1L,3L,6L,1L,4L,1L,311L,17L,2L
+
+#define OBJ_certTypes OBJ_pkcs9,22L
+
+#define LN_x509Certificate "x509Certificate"
+#define NID_x509Certificate 158
+#define OBJ_x509Certificate OBJ_certTypes,1L
+
+#define LN_sdsiCertificate "sdsiCertificate"
+#define NID_sdsiCertificate 159
+#define OBJ_sdsiCertificate OBJ_certTypes,2L
+
+#define OBJ_crlTypes OBJ_pkcs9,23L
+
+#define LN_x509Crl "x509Crl"
+#define NID_x509Crl 160
+#define OBJ_x509Crl OBJ_crlTypes,1L
+
+#define OBJ_pkcs12 OBJ_pkcs,12L
+
+#define OBJ_pkcs12_pbeids OBJ_pkcs12,1L
+
+#define SN_pbe_WithSHA1And128BitRC4 "PBE-SHA1-RC4-128"
+#define LN_pbe_WithSHA1And128BitRC4 "pbeWithSHA1And128BitRC4"
+#define NID_pbe_WithSHA1And128BitRC4 144
+#define OBJ_pbe_WithSHA1And128BitRC4 OBJ_pkcs12_pbeids,1L
+
+#define SN_pbe_WithSHA1And40BitRC4 "PBE-SHA1-RC4-40"
+#define LN_pbe_WithSHA1And40BitRC4 "pbeWithSHA1And40BitRC4"
+#define NID_pbe_WithSHA1And40BitRC4 145
+#define OBJ_pbe_WithSHA1And40BitRC4 OBJ_pkcs12_pbeids,2L
+
+#define SN_pbe_WithSHA1And3_Key_TripleDES_CBC "PBE-SHA1-3DES"
+#define LN_pbe_WithSHA1And3_Key_TripleDES_CBC "pbeWithSHA1And3-KeyTripleDES-CBC"
+#define NID_pbe_WithSHA1And3_Key_TripleDES_CBC 146
+#define OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC OBJ_pkcs12_pbeids,3L
+
+#define SN_pbe_WithSHA1And2_Key_TripleDES_CBC "PBE-SHA1-2DES"
+#define LN_pbe_WithSHA1And2_Key_TripleDES_CBC "pbeWithSHA1And2-KeyTripleDES-CBC"
+#define NID_pbe_WithSHA1And2_Key_TripleDES_CBC 147
+#define OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC OBJ_pkcs12_pbeids,4L
+
+#define SN_pbe_WithSHA1And128BitRC2_CBC "PBE-SHA1-RC2-128"
+#define LN_pbe_WithSHA1And128BitRC2_CBC "pbeWithSHA1And128BitRC2-CBC"
+#define NID_pbe_WithSHA1And128BitRC2_CBC 148
+#define OBJ_pbe_WithSHA1And128BitRC2_CBC OBJ_pkcs12_pbeids,5L
+
+#define SN_pbe_WithSHA1And40BitRC2_CBC "PBE-SHA1-RC2-40"
+#define LN_pbe_WithSHA1And40BitRC2_CBC "pbeWithSHA1And40BitRC2-CBC"
+#define NID_pbe_WithSHA1And40BitRC2_CBC 149
+#define OBJ_pbe_WithSHA1And40BitRC2_CBC OBJ_pkcs12_pbeids,6L
+
+#define OBJ_pkcs12_Version1 OBJ_pkcs12,10L
+
+#define OBJ_pkcs12_BagIds OBJ_pkcs12_Version1,1L
+
+#define LN_keyBag "keyBag"
+#define NID_keyBag 150
+#define OBJ_keyBag OBJ_pkcs12_BagIds,1L
+
+#define LN_pkcs8ShroudedKeyBag "pkcs8ShroudedKeyBag"
+#define NID_pkcs8ShroudedKeyBag 151
+#define OBJ_pkcs8ShroudedKeyBag OBJ_pkcs12_BagIds,2L
+
+#define LN_certBag "certBag"
+#define NID_certBag 152
+#define OBJ_certBag OBJ_pkcs12_BagIds,3L
+
+#define LN_crlBag "crlBag"
+#define NID_crlBag 153
+#define OBJ_crlBag OBJ_pkcs12_BagIds,4L
+
+#define LN_secretBag "secretBag"
+#define NID_secretBag 154
+#define OBJ_secretBag OBJ_pkcs12_BagIds,5L
+
+#define LN_safeContentsBag "safeContentsBag"
+#define NID_safeContentsBag 155
+#define OBJ_safeContentsBag OBJ_pkcs12_BagIds,6L
+
+#define SN_md2 "MD2"
+#define LN_md2 "md2"
+#define NID_md2 3
+#define OBJ_md2 OBJ_rsadsi,2L,2L
+
+#define SN_md4 "MD4"
+#define LN_md4 "md4"
+#define NID_md4 257
+#define OBJ_md4 OBJ_rsadsi,2L,4L
+
+#define SN_md5 "MD5"
+#define LN_md5 "md5"
+#define NID_md5 4
+#define OBJ_md5 OBJ_rsadsi,2L,5L
+
+#define SN_md5_sha1 "MD5-SHA1"
+#define LN_md5_sha1 "md5-sha1"
+#define NID_md5_sha1 114
+
+#define LN_hmacWithMD5 "hmacWithMD5"
+#define NID_hmacWithMD5 797
+#define OBJ_hmacWithMD5 OBJ_rsadsi,2L,6L
+
+#define LN_hmacWithSHA1 "hmacWithSHA1"
+#define NID_hmacWithSHA1 163
+#define OBJ_hmacWithSHA1 OBJ_rsadsi,2L,7L
+
+#define LN_hmacWithSHA224 "hmacWithSHA224"
+#define NID_hmacWithSHA224 798
+#define OBJ_hmacWithSHA224 OBJ_rsadsi,2L,8L
+
+#define LN_hmacWithSHA256 "hmacWithSHA256"
+#define NID_hmacWithSHA256 799
+#define OBJ_hmacWithSHA256 OBJ_rsadsi,2L,9L
+
+#define LN_hmacWithSHA384 "hmacWithSHA384"
+#define NID_hmacWithSHA384 800
+#define OBJ_hmacWithSHA384 OBJ_rsadsi,2L,10L
+
+#define LN_hmacWithSHA512 "hmacWithSHA512"
+#define NID_hmacWithSHA512 801
+#define OBJ_hmacWithSHA512 OBJ_rsadsi,2L,11L
+
+#define SN_rc2_cbc "RC2-CBC"
+#define LN_rc2_cbc "rc2-cbc"
+#define NID_rc2_cbc 37
+#define OBJ_rc2_cbc OBJ_rsadsi,3L,2L
+
+#define SN_rc2_ecb "RC2-ECB"
+#define LN_rc2_ecb "rc2-ecb"
+#define NID_rc2_ecb 38
+
+#define SN_rc2_cfb64 "RC2-CFB"
+#define LN_rc2_cfb64 "rc2-cfb"
+#define NID_rc2_cfb64 39
+
+#define SN_rc2_ofb64 "RC2-OFB"
+#define LN_rc2_ofb64 "rc2-ofb"
+#define NID_rc2_ofb64 40
+
+#define SN_rc2_40_cbc "RC2-40-CBC"
+#define LN_rc2_40_cbc "rc2-40-cbc"
+#define NID_rc2_40_cbc 98
+
+#define SN_rc2_64_cbc "RC2-64-CBC"
+#define LN_rc2_64_cbc "rc2-64-cbc"
+#define NID_rc2_64_cbc 166
+
+#define SN_rc4 "RC4"
+#define LN_rc4 "rc4"
+#define NID_rc4 5
+#define OBJ_rc4 OBJ_rsadsi,3L,4L
+
+#define SN_rc4_40 "RC4-40"
+#define LN_rc4_40 "rc4-40"
+#define NID_rc4_40 97
+
+#define SN_des_ede3_cbc "DES-EDE3-CBC"
+#define LN_des_ede3_cbc "des-ede3-cbc"
+#define NID_des_ede3_cbc 44
+#define OBJ_des_ede3_cbc OBJ_rsadsi,3L,7L
+
+#define SN_rc5_cbc "RC5-CBC"
+#define LN_rc5_cbc "rc5-cbc"
+#define NID_rc5_cbc 120
+#define OBJ_rc5_cbc OBJ_rsadsi,3L,8L
+
+#define SN_rc5_ecb "RC5-ECB"
+#define LN_rc5_ecb "rc5-ecb"
+#define NID_rc5_ecb 121
+
+#define SN_rc5_cfb64 "RC5-CFB"
+#define LN_rc5_cfb64 "rc5-cfb"
+#define NID_rc5_cfb64 122
+
+#define SN_rc5_ofb64 "RC5-OFB"
+#define LN_rc5_ofb64 "rc5-ofb"
+#define NID_rc5_ofb64 123
+
+#define SN_ms_ext_req "msExtReq"
+#define LN_ms_ext_req "Microsoft Extension Request"
+#define NID_ms_ext_req 171
+#define OBJ_ms_ext_req 1L,3L,6L,1L,4L,1L,311L,2L,1L,14L
+
+#define SN_ms_code_ind "msCodeInd"
+#define LN_ms_code_ind "Microsoft Individual Code Signing"
+#define NID_ms_code_ind 134
+#define OBJ_ms_code_ind 1L,3L,6L,1L,4L,1L,311L,2L,1L,21L
+
+#define SN_ms_code_com "msCodeCom"
+#define LN_ms_code_com "Microsoft Commercial Code Signing"
+#define NID_ms_code_com 135
+#define OBJ_ms_code_com 1L,3L,6L,1L,4L,1L,311L,2L,1L,22L
+
+#define SN_ms_ctl_sign "msCTLSign"
+#define LN_ms_ctl_sign "Microsoft Trust List Signing"
+#define NID_ms_ctl_sign 136
+#define OBJ_ms_ctl_sign 1L,3L,6L,1L,4L,1L,311L,10L,3L,1L
+
+#define SN_ms_sgc "msSGC"
+#define LN_ms_sgc "Microsoft Server Gated Crypto"
+#define NID_ms_sgc 137
+#define OBJ_ms_sgc 1L,3L,6L,1L,4L,1L,311L,10L,3L,3L
+
+#define SN_ms_efs "msEFS"
+#define LN_ms_efs "Microsoft Encrypted File System"
+#define NID_ms_efs 138
+#define OBJ_ms_efs 1L,3L,6L,1L,4L,1L,311L,10L,3L,4L
+
+#define SN_ms_smartcard_login "msSmartcardLogin"
+#define LN_ms_smartcard_login "Microsoft Smartcardlogin"
+#define NID_ms_smartcard_login 648
+#define OBJ_ms_smartcard_login 1L,3L,6L,1L,4L,1L,311L,20L,2L,2L
+
+#define SN_ms_upn "msUPN"
+#define LN_ms_upn "Microsoft Universal Principal Name"
+#define NID_ms_upn 649
+#define OBJ_ms_upn 1L,3L,6L,1L,4L,1L,311L,20L,2L,3L
+
+#define SN_idea_cbc "IDEA-CBC"
+#define LN_idea_cbc "idea-cbc"
+#define NID_idea_cbc 34
+#define OBJ_idea_cbc 1L,3L,6L,1L,4L,1L,188L,7L,1L,1L,2L
+
+#define SN_idea_ecb "IDEA-ECB"
+#define LN_idea_ecb "idea-ecb"
+#define NID_idea_ecb 36
+
+#define SN_idea_cfb64 "IDEA-CFB"
+#define LN_idea_cfb64 "idea-cfb"
+#define NID_idea_cfb64 35
+
+#define SN_idea_ofb64 "IDEA-OFB"
+#define LN_idea_ofb64 "idea-ofb"
+#define NID_idea_ofb64 46
+
+#define SN_bf_cbc "BF-CBC"
+#define LN_bf_cbc "bf-cbc"
+#define NID_bf_cbc 91
+#define OBJ_bf_cbc 1L,3L,6L,1L,4L,1L,3029L,1L,2L
+
+#define SN_bf_ecb "BF-ECB"
+#define LN_bf_ecb "bf-ecb"
+#define NID_bf_ecb 92
+
+#define SN_bf_cfb64 "BF-CFB"
+#define LN_bf_cfb64 "bf-cfb"
+#define NID_bf_cfb64 93
+
+#define SN_bf_ofb64 "BF-OFB"
+#define LN_bf_ofb64 "bf-ofb"
+#define NID_bf_ofb64 94
+
+#define SN_id_pkix "PKIX"
+#define NID_id_pkix 127
+#define OBJ_id_pkix 1L,3L,6L,1L,5L,5L,7L
+
+#define SN_id_pkix_mod "id-pkix-mod"
+#define NID_id_pkix_mod 258
+#define OBJ_id_pkix_mod OBJ_id_pkix,0L
+
+#define SN_id_pe "id-pe"
+#define NID_id_pe 175
+#define OBJ_id_pe OBJ_id_pkix,1L
+
+#define SN_id_qt "id-qt"
+#define NID_id_qt 259
+#define OBJ_id_qt OBJ_id_pkix,2L
+
+#define SN_id_kp "id-kp"
+#define NID_id_kp 128
+#define OBJ_id_kp OBJ_id_pkix,3L
+
+#define SN_id_it "id-it"
+#define NID_id_it 260
+#define OBJ_id_it OBJ_id_pkix,4L
+
+#define SN_id_pkip "id-pkip"
+#define NID_id_pkip 261
+#define OBJ_id_pkip OBJ_id_pkix,5L
+
+#define SN_id_alg "id-alg"
+#define NID_id_alg 262
+#define OBJ_id_alg OBJ_id_pkix,6L
+
+#define SN_id_cmc "id-cmc"
+#define NID_id_cmc 263
+#define OBJ_id_cmc OBJ_id_pkix,7L
+
+#define SN_id_on "id-on"
+#define NID_id_on 264
+#define OBJ_id_on OBJ_id_pkix,8L
+
+#define SN_id_pda "id-pda"
+#define NID_id_pda 265
+#define OBJ_id_pda OBJ_id_pkix,9L
+
+#define SN_id_aca "id-aca"
+#define NID_id_aca 266
+#define OBJ_id_aca OBJ_id_pkix,10L
+
+#define SN_id_qcs "id-qcs"
+#define NID_id_qcs 267
+#define OBJ_id_qcs OBJ_id_pkix,11L
+
+#define SN_id_cct "id-cct"
+#define NID_id_cct 268
+#define OBJ_id_cct OBJ_id_pkix,12L
+
+#define SN_id_ppl "id-ppl"
+#define NID_id_ppl 662
+#define OBJ_id_ppl OBJ_id_pkix,21L
+
+#define SN_id_ad "id-ad"
+#define NID_id_ad 176
+#define OBJ_id_ad OBJ_id_pkix,48L
+
+#define SN_id_pkix1_explicit_88 "id-pkix1-explicit-88"
+#define NID_id_pkix1_explicit_88 269
+#define OBJ_id_pkix1_explicit_88 OBJ_id_pkix_mod,1L
+
+#define SN_id_pkix1_implicit_88 "id-pkix1-implicit-88"
+#define NID_id_pkix1_implicit_88 270
+#define OBJ_id_pkix1_implicit_88 OBJ_id_pkix_mod,2L
+
+#define SN_id_pkix1_explicit_93 "id-pkix1-explicit-93"
+#define NID_id_pkix1_explicit_93 271
+#define OBJ_id_pkix1_explicit_93 OBJ_id_pkix_mod,3L
+
+#define SN_id_pkix1_implicit_93 "id-pkix1-implicit-93"
+#define NID_id_pkix1_implicit_93 272
+#define OBJ_id_pkix1_implicit_93 OBJ_id_pkix_mod,4L
+
+#define SN_id_mod_crmf "id-mod-crmf"
+#define NID_id_mod_crmf 273
+#define OBJ_id_mod_crmf OBJ_id_pkix_mod,5L
+
+#define SN_id_mod_cmc "id-mod-cmc"
+#define NID_id_mod_cmc 274
+#define OBJ_id_mod_cmc OBJ_id_pkix_mod,6L
+
+#define SN_id_mod_kea_profile_88 "id-mod-kea-profile-88"
+#define NID_id_mod_kea_profile_88 275
+#define OBJ_id_mod_kea_profile_88 OBJ_id_pkix_mod,7L
+
+#define SN_id_mod_kea_profile_93 "id-mod-kea-profile-93"
+#define NID_id_mod_kea_profile_93 276
+#define OBJ_id_mod_kea_profile_93 OBJ_id_pkix_mod,8L
+
+#define SN_id_mod_cmp "id-mod-cmp"
+#define NID_id_mod_cmp 277
+#define OBJ_id_mod_cmp OBJ_id_pkix_mod,9L
+
+#define SN_id_mod_qualified_cert_88 "id-mod-qualified-cert-88"
+#define NID_id_mod_qualified_cert_88 278
+#define OBJ_id_mod_qualified_cert_88 OBJ_id_pkix_mod,10L
+
+#define SN_id_mod_qualified_cert_93 "id-mod-qualified-cert-93"
+#define NID_id_mod_qualified_cert_93 279
+#define OBJ_id_mod_qualified_cert_93 OBJ_id_pkix_mod,11L
+
+#define SN_id_mod_attribute_cert "id-mod-attribute-cert"
+#define NID_id_mod_attribute_cert 280
+#define OBJ_id_mod_attribute_cert OBJ_id_pkix_mod,12L
+
+#define SN_id_mod_timestamp_protocol "id-mod-timestamp-protocol"
+#define NID_id_mod_timestamp_protocol 281
+#define OBJ_id_mod_timestamp_protocol OBJ_id_pkix_mod,13L
+
+#define SN_id_mod_ocsp "id-mod-ocsp"
+#define NID_id_mod_ocsp 282
+#define OBJ_id_mod_ocsp OBJ_id_pkix_mod,14L
+
+#define SN_id_mod_dvcs "id-mod-dvcs"
+#define NID_id_mod_dvcs 283
+#define OBJ_id_mod_dvcs OBJ_id_pkix_mod,15L
+
+#define SN_id_mod_cmp2000 "id-mod-cmp2000"
+#define NID_id_mod_cmp2000 284
+#define OBJ_id_mod_cmp2000 OBJ_id_pkix_mod,16L
+
+#define SN_info_access "authorityInfoAccess"
+#define LN_info_access "Authority Information Access"
+#define NID_info_access 177
+#define OBJ_info_access OBJ_id_pe,1L
+
+#define SN_biometricInfo "biometricInfo"
+#define LN_biometricInfo "Biometric Info"
+#define NID_biometricInfo 285
+#define OBJ_biometricInfo OBJ_id_pe,2L
+
+#define SN_qcStatements "qcStatements"
+#define NID_qcStatements 286
+#define OBJ_qcStatements OBJ_id_pe,3L
+
+#define SN_ac_auditEntity "ac-auditEntity"
+#define NID_ac_auditEntity 287
+#define OBJ_ac_auditEntity OBJ_id_pe,4L
+
+#define SN_ac_targeting "ac-targeting"
+#define NID_ac_targeting 288
+#define OBJ_ac_targeting OBJ_id_pe,5L
+
+#define SN_aaControls "aaControls"
+#define NID_aaControls 289
+#define OBJ_aaControls OBJ_id_pe,6L
+
+#define SN_sbgp_ipAddrBlock "sbgp-ipAddrBlock"
+#define NID_sbgp_ipAddrBlock 290
+#define OBJ_sbgp_ipAddrBlock OBJ_id_pe,7L
+
+#define SN_sbgp_autonomousSysNum "sbgp-autonomousSysNum"
+#define NID_sbgp_autonomousSysNum 291
+#define OBJ_sbgp_autonomousSysNum OBJ_id_pe,8L
+
+#define SN_sbgp_routerIdentifier "sbgp-routerIdentifier"
+#define NID_sbgp_routerIdentifier 292
+#define OBJ_sbgp_routerIdentifier OBJ_id_pe,9L
+
+#define SN_ac_proxying "ac-proxying"
+#define NID_ac_proxying 397
+#define OBJ_ac_proxying OBJ_id_pe,10L
+
+#define SN_sinfo_access "subjectInfoAccess"
+#define LN_sinfo_access "Subject Information Access"
+#define NID_sinfo_access 398
+#define OBJ_sinfo_access OBJ_id_pe,11L
+
+#define SN_proxyCertInfo "proxyCertInfo"
+#define LN_proxyCertInfo "Proxy Certificate Information"
+#define NID_proxyCertInfo 663
+#define OBJ_proxyCertInfo OBJ_id_pe,14L
+
+#define SN_id_qt_cps "id-qt-cps"
+#define LN_id_qt_cps "Policy Qualifier CPS"
+#define NID_id_qt_cps 164
+#define OBJ_id_qt_cps OBJ_id_qt,1L
+
+#define SN_id_qt_unotice "id-qt-unotice"
+#define LN_id_qt_unotice "Policy Qualifier User Notice"
+#define NID_id_qt_unotice 165
+#define OBJ_id_qt_unotice OBJ_id_qt,2L
+
+#define SN_textNotice "textNotice"
+#define NID_textNotice 293
+#define OBJ_textNotice OBJ_id_qt,3L
+
+#define SN_server_auth "serverAuth"
+#define LN_server_auth "TLS Web Server Authentication"
+#define NID_server_auth 129
+#define OBJ_server_auth OBJ_id_kp,1L
+
+#define SN_client_auth "clientAuth"
+#define LN_client_auth "TLS Web Client Authentication"
+#define NID_client_auth 130
+#define OBJ_client_auth OBJ_id_kp,2L
+
+#define SN_code_sign "codeSigning"
+#define LN_code_sign "Code Signing"
+#define NID_code_sign 131
+#define OBJ_code_sign OBJ_id_kp,3L
+
+#define SN_email_protect "emailProtection"
+#define LN_email_protect "E-mail Protection"
+#define NID_email_protect 132
+#define OBJ_email_protect OBJ_id_kp,4L
+
+#define SN_ipsecEndSystem "ipsecEndSystem"
+#define LN_ipsecEndSystem "IPSec End System"
+#define NID_ipsecEndSystem 294
+#define OBJ_ipsecEndSystem OBJ_id_kp,5L
+
+#define SN_ipsecTunnel "ipsecTunnel"
+#define LN_ipsecTunnel "IPSec Tunnel"
+#define NID_ipsecTunnel 295
+#define OBJ_ipsecTunnel OBJ_id_kp,6L
+
+#define SN_ipsecUser "ipsecUser"
+#define LN_ipsecUser "IPSec User"
+#define NID_ipsecUser 296
+#define OBJ_ipsecUser OBJ_id_kp,7L
+
+#define SN_time_stamp "timeStamping"
+#define LN_time_stamp "Time Stamping"
+#define NID_time_stamp 133
+#define OBJ_time_stamp OBJ_id_kp,8L
+
+#define SN_OCSP_sign "OCSPSigning"
+#define LN_OCSP_sign "OCSP Signing"
+#define NID_OCSP_sign 180
+#define OBJ_OCSP_sign OBJ_id_kp,9L
+
+#define SN_dvcs "DVCS"
+#define LN_dvcs "dvcs"
+#define NID_dvcs 297
+#define OBJ_dvcs OBJ_id_kp,10L
+
+#define SN_id_it_caProtEncCert "id-it-caProtEncCert"
+#define NID_id_it_caProtEncCert 298
+#define OBJ_id_it_caProtEncCert OBJ_id_it,1L
+
+#define SN_id_it_signKeyPairTypes "id-it-signKeyPairTypes"
+#define NID_id_it_signKeyPairTypes 299
+#define OBJ_id_it_signKeyPairTypes OBJ_id_it,2L
+
+#define SN_id_it_encKeyPairTypes "id-it-encKeyPairTypes"
+#define NID_id_it_encKeyPairTypes 300
+#define OBJ_id_it_encKeyPairTypes OBJ_id_it,3L
+
+#define SN_id_it_preferredSymmAlg "id-it-preferredSymmAlg"
+#define NID_id_it_preferredSymmAlg 301
+#define OBJ_id_it_preferredSymmAlg OBJ_id_it,4L
+
+#define SN_id_it_caKeyUpdateInfo "id-it-caKeyUpdateInfo"
+#define NID_id_it_caKeyUpdateInfo 302
+#define OBJ_id_it_caKeyUpdateInfo OBJ_id_it,5L
+
+#define SN_id_it_currentCRL "id-it-currentCRL"
+#define NID_id_it_currentCRL 303
+#define OBJ_id_it_currentCRL OBJ_id_it,6L
+
+#define SN_id_it_unsupportedOIDs "id-it-unsupportedOIDs"
+#define NID_id_it_unsupportedOIDs 304
+#define OBJ_id_it_unsupportedOIDs OBJ_id_it,7L
+
+#define SN_id_it_subscriptionRequest "id-it-subscriptionRequest"
+#define NID_id_it_subscriptionRequest 305
+#define OBJ_id_it_subscriptionRequest OBJ_id_it,8L
+
+#define SN_id_it_subscriptionResponse "id-it-subscriptionResponse"
+#define NID_id_it_subscriptionResponse 306
+#define OBJ_id_it_subscriptionResponse OBJ_id_it,9L
+
+#define SN_id_it_keyPairParamReq "id-it-keyPairParamReq"
+#define NID_id_it_keyPairParamReq 307
+#define OBJ_id_it_keyPairParamReq OBJ_id_it,10L
+
+#define SN_id_it_keyPairParamRep "id-it-keyPairParamRep"
+#define NID_id_it_keyPairParamRep 308
+#define OBJ_id_it_keyPairParamRep OBJ_id_it,11L
+
+#define SN_id_it_revPassphrase "id-it-revPassphrase"
+#define NID_id_it_revPassphrase 309
+#define OBJ_id_it_revPassphrase OBJ_id_it,12L
+
+#define SN_id_it_implicitConfirm "id-it-implicitConfirm"
+#define NID_id_it_implicitConfirm 310
+#define OBJ_id_it_implicitConfirm OBJ_id_it,13L
+
+#define SN_id_it_confirmWaitTime "id-it-confirmWaitTime"
+#define NID_id_it_confirmWaitTime 311
+#define OBJ_id_it_confirmWaitTime OBJ_id_it,14L
+
+#define SN_id_it_origPKIMessage "id-it-origPKIMessage"
+#define NID_id_it_origPKIMessage 312
+#define OBJ_id_it_origPKIMessage OBJ_id_it,15L
+
+#define SN_id_it_suppLangTags "id-it-suppLangTags"
+#define NID_id_it_suppLangTags 784
+#define OBJ_id_it_suppLangTags OBJ_id_it,16L
+
+#define SN_id_regCtrl "id-regCtrl"
+#define NID_id_regCtrl 313
+#define OBJ_id_regCtrl OBJ_id_pkip,1L
+
+#define SN_id_regInfo "id-regInfo"
+#define NID_id_regInfo 314
+#define OBJ_id_regInfo OBJ_id_pkip,2L
+
+#define SN_id_regCtrl_regToken "id-regCtrl-regToken"
+#define NID_id_regCtrl_regToken 315
+#define OBJ_id_regCtrl_regToken OBJ_id_regCtrl,1L
+
+#define SN_id_regCtrl_authenticator "id-regCtrl-authenticator"
+#define NID_id_regCtrl_authenticator 316
+#define OBJ_id_regCtrl_authenticator OBJ_id_regCtrl,2L
+
+#define SN_id_regCtrl_pkiPublicationInfo "id-regCtrl-pkiPublicationInfo"
+#define NID_id_regCtrl_pkiPublicationInfo 317
+#define OBJ_id_regCtrl_pkiPublicationInfo OBJ_id_regCtrl,3L
+
+#define SN_id_regCtrl_pkiArchiveOptions "id-regCtrl-pkiArchiveOptions"
+#define NID_id_regCtrl_pkiArchiveOptions 318
+#define OBJ_id_regCtrl_pkiArchiveOptions OBJ_id_regCtrl,4L
+
+#define SN_id_regCtrl_oldCertID "id-regCtrl-oldCertID"
+#define NID_id_regCtrl_oldCertID 319
+#define OBJ_id_regCtrl_oldCertID OBJ_id_regCtrl,5L
+
+#define SN_id_regCtrl_protocolEncrKey "id-regCtrl-protocolEncrKey"
+#define NID_id_regCtrl_protocolEncrKey 320
+#define OBJ_id_regCtrl_protocolEncrKey OBJ_id_regCtrl,6L
+
+#define SN_id_regInfo_utf8Pairs "id-regInfo-utf8Pairs"
+#define NID_id_regInfo_utf8Pairs 321
+#define OBJ_id_regInfo_utf8Pairs OBJ_id_regInfo,1L
+
+#define SN_id_regInfo_certReq "id-regInfo-certReq"
+#define NID_id_regInfo_certReq 322
+#define OBJ_id_regInfo_certReq OBJ_id_regInfo,2L
+
+#define SN_id_alg_des40 "id-alg-des40"
+#define NID_id_alg_des40 323
+#define OBJ_id_alg_des40 OBJ_id_alg,1L
+
+#define SN_id_alg_noSignature "id-alg-noSignature"
+#define NID_id_alg_noSignature 324
+#define OBJ_id_alg_noSignature OBJ_id_alg,2L
+
+#define SN_id_alg_dh_sig_hmac_sha1 "id-alg-dh-sig-hmac-sha1"
+#define NID_id_alg_dh_sig_hmac_sha1 325
+#define OBJ_id_alg_dh_sig_hmac_sha1 OBJ_id_alg,3L
+
+#define SN_id_alg_dh_pop "id-alg-dh-pop"
+#define NID_id_alg_dh_pop 326
+#define OBJ_id_alg_dh_pop OBJ_id_alg,4L
+
+#define SN_id_cmc_statusInfo "id-cmc-statusInfo"
+#define NID_id_cmc_statusInfo 327
+#define OBJ_id_cmc_statusInfo OBJ_id_cmc,1L
+
+#define SN_id_cmc_identification "id-cmc-identification"
+#define NID_id_cmc_identification 328
+#define OBJ_id_cmc_identification OBJ_id_cmc,2L
+
+#define SN_id_cmc_identityProof "id-cmc-identityProof"
+#define NID_id_cmc_identityProof 329
+#define OBJ_id_cmc_identityProof OBJ_id_cmc,3L
+
+#define SN_id_cmc_dataReturn "id-cmc-dataReturn"
+#define NID_id_cmc_dataReturn 330
+#define OBJ_id_cmc_dataReturn OBJ_id_cmc,4L
+
+#define SN_id_cmc_transactionId "id-cmc-transactionId"
+#define NID_id_cmc_transactionId 331
+#define OBJ_id_cmc_transactionId OBJ_id_cmc,5L
+
+#define SN_id_cmc_senderNonce "id-cmc-senderNonce"
+#define NID_id_cmc_senderNonce 332
+#define OBJ_id_cmc_senderNonce OBJ_id_cmc,6L
+
+#define SN_id_cmc_recipientNonce "id-cmc-recipientNonce"
+#define NID_id_cmc_recipientNonce 333
+#define OBJ_id_cmc_recipientNonce OBJ_id_cmc,7L
+
+#define SN_id_cmc_addExtensions "id-cmc-addExtensions"
+#define NID_id_cmc_addExtensions 334
+#define OBJ_id_cmc_addExtensions OBJ_id_cmc,8L
+
+#define SN_id_cmc_encryptedPOP "id-cmc-encryptedPOP"
+#define NID_id_cmc_encryptedPOP 335
+#define OBJ_id_cmc_encryptedPOP OBJ_id_cmc,9L
+
+#define SN_id_cmc_decryptedPOP "id-cmc-decryptedPOP"
+#define NID_id_cmc_decryptedPOP 336
+#define OBJ_id_cmc_decryptedPOP OBJ_id_cmc,10L
+
+#define SN_id_cmc_lraPOPWitness "id-cmc-lraPOPWitness"
+#define NID_id_cmc_lraPOPWitness 337
+#define OBJ_id_cmc_lraPOPWitness OBJ_id_cmc,11L
+
+#define SN_id_cmc_getCert "id-cmc-getCert"
+#define NID_id_cmc_getCert 338
+#define OBJ_id_cmc_getCert OBJ_id_cmc,15L
+
+#define SN_id_cmc_getCRL "id-cmc-getCRL"
+#define NID_id_cmc_getCRL 339
+#define OBJ_id_cmc_getCRL OBJ_id_cmc,16L
+
+#define SN_id_cmc_revokeRequest "id-cmc-revokeRequest"
+#define NID_id_cmc_revokeRequest 340
+#define OBJ_id_cmc_revokeRequest OBJ_id_cmc,17L
+
+#define SN_id_cmc_regInfo "id-cmc-regInfo"
+#define NID_id_cmc_regInfo 341
+#define OBJ_id_cmc_regInfo OBJ_id_cmc,18L
+
+#define SN_id_cmc_responseInfo "id-cmc-responseInfo"
+#define NID_id_cmc_responseInfo 342
+#define OBJ_id_cmc_responseInfo OBJ_id_cmc,19L
+
+#define SN_id_cmc_queryPending "id-cmc-queryPending"
+#define NID_id_cmc_queryPending 343
+#define OBJ_id_cmc_queryPending OBJ_id_cmc,21L
+
+#define SN_id_cmc_popLinkRandom "id-cmc-popLinkRandom"
+#define NID_id_cmc_popLinkRandom 344
+#define OBJ_id_cmc_popLinkRandom OBJ_id_cmc,22L
+
+#define SN_id_cmc_popLinkWitness "id-cmc-popLinkWitness"
+#define NID_id_cmc_popLinkWitness 345
+#define OBJ_id_cmc_popLinkWitness OBJ_id_cmc,23L
+
+#define SN_id_cmc_confirmCertAcceptance "id-cmc-confirmCertAcceptance"
+#define NID_id_cmc_confirmCertAcceptance 346
+#define OBJ_id_cmc_confirmCertAcceptance OBJ_id_cmc,24L
+
+#define SN_id_on_personalData "id-on-personalData"
+#define NID_id_on_personalData 347
+#define OBJ_id_on_personalData OBJ_id_on,1L
+
+#define SN_id_on_permanentIdentifier "id-on-permanentIdentifier"
+#define LN_id_on_permanentIdentifier "Permanent Identifier"
+#define NID_id_on_permanentIdentifier 858
+#define OBJ_id_on_permanentIdentifier OBJ_id_on,3L
+
+#define SN_id_pda_dateOfBirth "id-pda-dateOfBirth"
+#define NID_id_pda_dateOfBirth 348
+#define OBJ_id_pda_dateOfBirth OBJ_id_pda,1L
+
+#define SN_id_pda_placeOfBirth "id-pda-placeOfBirth"
+#define NID_id_pda_placeOfBirth 349
+#define OBJ_id_pda_placeOfBirth OBJ_id_pda,2L
+
+#define SN_id_pda_gender "id-pda-gender"
+#define NID_id_pda_gender 351
+#define OBJ_id_pda_gender OBJ_id_pda,3L
+
+#define SN_id_pda_countryOfCitizenship "id-pda-countryOfCitizenship"
+#define NID_id_pda_countryOfCitizenship 352
+#define OBJ_id_pda_countryOfCitizenship OBJ_id_pda,4L
+
+#define SN_id_pda_countryOfResidence "id-pda-countryOfResidence"
+#define NID_id_pda_countryOfResidence 353
+#define OBJ_id_pda_countryOfResidence OBJ_id_pda,5L
+
+#define SN_id_aca_authenticationInfo "id-aca-authenticationInfo"
+#define NID_id_aca_authenticationInfo 354
+#define OBJ_id_aca_authenticationInfo OBJ_id_aca,1L
+
+#define SN_id_aca_accessIdentity "id-aca-accessIdentity"
+#define NID_id_aca_accessIdentity 355
+#define OBJ_id_aca_accessIdentity OBJ_id_aca,2L
+
+#define SN_id_aca_chargingIdentity "id-aca-chargingIdentity"
+#define NID_id_aca_chargingIdentity 356
+#define OBJ_id_aca_chargingIdentity OBJ_id_aca,3L
+
+#define SN_id_aca_group "id-aca-group"
+#define NID_id_aca_group 357
+#define OBJ_id_aca_group OBJ_id_aca,4L
+
+#define SN_id_aca_role "id-aca-role"
+#define NID_id_aca_role 358
+#define OBJ_id_aca_role OBJ_id_aca,5L
+
+#define SN_id_aca_encAttrs "id-aca-encAttrs"
+#define NID_id_aca_encAttrs 399
+#define OBJ_id_aca_encAttrs OBJ_id_aca,6L
+
+#define SN_id_qcs_pkixQCSyntax_v1 "id-qcs-pkixQCSyntax-v1"
+#define NID_id_qcs_pkixQCSyntax_v1 359
+#define OBJ_id_qcs_pkixQCSyntax_v1 OBJ_id_qcs,1L
+
+#define SN_id_cct_crs "id-cct-crs"
+#define NID_id_cct_crs 360
+#define OBJ_id_cct_crs OBJ_id_cct,1L
+
+#define SN_id_cct_PKIData "id-cct-PKIData"
+#define NID_id_cct_PKIData 361
+#define OBJ_id_cct_PKIData OBJ_id_cct,2L
+
+#define SN_id_cct_PKIResponse "id-cct-PKIResponse"
+#define NID_id_cct_PKIResponse 362
+#define OBJ_id_cct_PKIResponse OBJ_id_cct,3L
+
+#define SN_id_ppl_anyLanguage "id-ppl-anyLanguage"
+#define LN_id_ppl_anyLanguage "Any language"
+#define NID_id_ppl_anyLanguage 664
+#define OBJ_id_ppl_anyLanguage OBJ_id_ppl,0L
+
+#define SN_id_ppl_inheritAll "id-ppl-inheritAll"
+#define LN_id_ppl_inheritAll "Inherit all"
+#define NID_id_ppl_inheritAll 665
+#define OBJ_id_ppl_inheritAll OBJ_id_ppl,1L
+
+#define SN_Independent "id-ppl-independent"
+#define LN_Independent "Independent"
+#define NID_Independent 667
+#define OBJ_Independent OBJ_id_ppl,2L
+
+#define SN_ad_OCSP "OCSP"
+#define LN_ad_OCSP "OCSP"
+#define NID_ad_OCSP 178
+#define OBJ_ad_OCSP OBJ_id_ad,1L
+
+#define SN_ad_ca_issuers "caIssuers"
+#define LN_ad_ca_issuers "CA Issuers"
+#define NID_ad_ca_issuers 179
+#define OBJ_ad_ca_issuers OBJ_id_ad,2L
+
+#define SN_ad_timeStamping "ad_timestamping"
+#define LN_ad_timeStamping "AD Time Stamping"
+#define NID_ad_timeStamping 363
+#define OBJ_ad_timeStamping OBJ_id_ad,3L
+
+#define SN_ad_dvcs "AD_DVCS"
+#define LN_ad_dvcs "ad dvcs"
+#define NID_ad_dvcs 364
+#define OBJ_ad_dvcs OBJ_id_ad,4L
+
+#define SN_caRepository "caRepository"
+#define LN_caRepository "CA Repository"
+#define NID_caRepository 785
+#define OBJ_caRepository OBJ_id_ad,5L
+
+#define OBJ_id_pkix_OCSP OBJ_ad_OCSP
+
+#define SN_id_pkix_OCSP_basic "basicOCSPResponse"
+#define LN_id_pkix_OCSP_basic "Basic OCSP Response"
+#define NID_id_pkix_OCSP_basic 365
+#define OBJ_id_pkix_OCSP_basic OBJ_id_pkix_OCSP,1L
+
+#define SN_id_pkix_OCSP_Nonce "Nonce"
+#define LN_id_pkix_OCSP_Nonce "OCSP Nonce"
+#define NID_id_pkix_OCSP_Nonce 366
+#define OBJ_id_pkix_OCSP_Nonce OBJ_id_pkix_OCSP,2L
+
+#define SN_id_pkix_OCSP_CrlID "CrlID"
+#define LN_id_pkix_OCSP_CrlID "OCSP CRL ID"
+#define NID_id_pkix_OCSP_CrlID 367
+#define OBJ_id_pkix_OCSP_CrlID OBJ_id_pkix_OCSP,3L
+
+#define SN_id_pkix_OCSP_acceptableResponses "acceptableResponses"
+#define LN_id_pkix_OCSP_acceptableResponses "Acceptable OCSP Responses"
+#define NID_id_pkix_OCSP_acceptableResponses 368
+#define OBJ_id_pkix_OCSP_acceptableResponses OBJ_id_pkix_OCSP,4L
+
+#define SN_id_pkix_OCSP_noCheck "noCheck"
+#define LN_id_pkix_OCSP_noCheck "OCSP No Check"
+#define NID_id_pkix_OCSP_noCheck 369
+#define OBJ_id_pkix_OCSP_noCheck OBJ_id_pkix_OCSP,5L
+
+#define SN_id_pkix_OCSP_archiveCutoff "archiveCutoff"
+#define LN_id_pkix_OCSP_archiveCutoff "OCSP Archive Cutoff"
+#define NID_id_pkix_OCSP_archiveCutoff 370
+#define OBJ_id_pkix_OCSP_archiveCutoff OBJ_id_pkix_OCSP,6L
+
+#define SN_id_pkix_OCSP_serviceLocator "serviceLocator"
+#define LN_id_pkix_OCSP_serviceLocator "OCSP Service Locator"
+#define NID_id_pkix_OCSP_serviceLocator 371
+#define OBJ_id_pkix_OCSP_serviceLocator OBJ_id_pkix_OCSP,7L
+
+#define SN_id_pkix_OCSP_extendedStatus "extendedStatus"
+#define LN_id_pkix_OCSP_extendedStatus "Extended OCSP Status"
+#define NID_id_pkix_OCSP_extendedStatus 372
+#define OBJ_id_pkix_OCSP_extendedStatus OBJ_id_pkix_OCSP,8L
+
+#define SN_id_pkix_OCSP_valid "valid"
+#define NID_id_pkix_OCSP_valid 373
+#define OBJ_id_pkix_OCSP_valid OBJ_id_pkix_OCSP,9L
+
+#define SN_id_pkix_OCSP_path "path"
+#define NID_id_pkix_OCSP_path 374
+#define OBJ_id_pkix_OCSP_path OBJ_id_pkix_OCSP,10L
+
+#define SN_id_pkix_OCSP_trustRoot "trustRoot"
+#define LN_id_pkix_OCSP_trustRoot "Trust Root"
+#define NID_id_pkix_OCSP_trustRoot 375
+#define OBJ_id_pkix_OCSP_trustRoot OBJ_id_pkix_OCSP,11L
+
+#define SN_algorithm "algorithm"
+#define LN_algorithm "algorithm"
+#define NID_algorithm 376
+#define OBJ_algorithm 1L,3L,14L,3L,2L
+
+#define SN_md5WithRSA "RSA-NP-MD5"
+#define LN_md5WithRSA "md5WithRSA"
+#define NID_md5WithRSA 104
+#define OBJ_md5WithRSA OBJ_algorithm,3L
+
+#define SN_des_ecb "DES-ECB"
+#define LN_des_ecb "des-ecb"
+#define NID_des_ecb 29
+#define OBJ_des_ecb OBJ_algorithm,6L
+
+#define SN_des_cbc "DES-CBC"
+#define LN_des_cbc "des-cbc"
+#define NID_des_cbc 31
+#define OBJ_des_cbc OBJ_algorithm,7L
+
+#define SN_des_ofb64 "DES-OFB"
+#define LN_des_ofb64 "des-ofb"
+#define NID_des_ofb64 45
+#define OBJ_des_ofb64 OBJ_algorithm,8L
+
+#define SN_des_cfb64 "DES-CFB"
+#define LN_des_cfb64 "des-cfb"
+#define NID_des_cfb64 30
+#define OBJ_des_cfb64 OBJ_algorithm,9L
+
+#define SN_rsaSignature "rsaSignature"
+#define NID_rsaSignature 377
+#define OBJ_rsaSignature OBJ_algorithm,11L
+
+#define SN_dsa_2 "DSA-old"
+#define LN_dsa_2 "dsaEncryption-old"
+#define NID_dsa_2 67
+#define OBJ_dsa_2 OBJ_algorithm,12L
+
+#define SN_dsaWithSHA "DSA-SHA"
+#define LN_dsaWithSHA "dsaWithSHA"
+#define NID_dsaWithSHA 66
+#define OBJ_dsaWithSHA OBJ_algorithm,13L
+
+#define SN_shaWithRSAEncryption "RSA-SHA"
+#define LN_shaWithRSAEncryption "shaWithRSAEncryption"
+#define NID_shaWithRSAEncryption 42
+#define OBJ_shaWithRSAEncryption OBJ_algorithm,15L
+
+#define SN_des_ede_ecb "DES-EDE"
+#define LN_des_ede_ecb "des-ede"
+#define NID_des_ede_ecb 32
+#define OBJ_des_ede_ecb OBJ_algorithm,17L
+
+#define SN_des_ede3_ecb "DES-EDE3"
+#define LN_des_ede3_ecb "des-ede3"
+#define NID_des_ede3_ecb 33
+
+#define SN_des_ede_cbc "DES-EDE-CBC"
+#define LN_des_ede_cbc "des-ede-cbc"
+#define NID_des_ede_cbc 43
+
+#define SN_des_ede_cfb64 "DES-EDE-CFB"
+#define LN_des_ede_cfb64 "des-ede-cfb"
+#define NID_des_ede_cfb64 60
+
+#define SN_des_ede3_cfb64 "DES-EDE3-CFB"
+#define LN_des_ede3_cfb64 "des-ede3-cfb"
+#define NID_des_ede3_cfb64 61
+
+#define SN_des_ede_ofb64 "DES-EDE-OFB"
+#define LN_des_ede_ofb64 "des-ede-ofb"
+#define NID_des_ede_ofb64 62
+
+#define SN_des_ede3_ofb64 "DES-EDE3-OFB"
+#define LN_des_ede3_ofb64 "des-ede3-ofb"
+#define NID_des_ede3_ofb64 63
+
+#define SN_desx_cbc "DESX-CBC"
+#define LN_desx_cbc "desx-cbc"
+#define NID_desx_cbc 80
+
+#define SN_sha "SHA"
+#define LN_sha "sha"
+#define NID_sha 41
+#define OBJ_sha OBJ_algorithm,18L
+
+#define SN_sha1 "SHA1"
+#define LN_sha1 "sha1"
+#define NID_sha1 64
+#define OBJ_sha1 OBJ_algorithm,26L
+
+#define SN_dsaWithSHA1_2 "DSA-SHA1-old"
+#define LN_dsaWithSHA1_2 "dsaWithSHA1-old"
+#define NID_dsaWithSHA1_2 70
+#define OBJ_dsaWithSHA1_2 OBJ_algorithm,27L
+
+#define SN_sha1WithRSA "RSA-SHA1-2"
+#define LN_sha1WithRSA "sha1WithRSA"
+#define NID_sha1WithRSA 115
+#define OBJ_sha1WithRSA OBJ_algorithm,29L
+
+#define SN_ripemd160 "RIPEMD160"
+#define LN_ripemd160 "ripemd160"
+#define NID_ripemd160 117
+#define OBJ_ripemd160 1L,3L,36L,3L,2L,1L
+
+#define SN_ripemd160WithRSA "RSA-RIPEMD160"
+#define LN_ripemd160WithRSA "ripemd160WithRSA"
+#define NID_ripemd160WithRSA 119
+#define OBJ_ripemd160WithRSA 1L,3L,36L,3L,3L,1L,2L
+
+#define SN_sxnet "SXNetID"
+#define LN_sxnet "Strong Extranet ID"
+#define NID_sxnet 143
+#define OBJ_sxnet 1L,3L,101L,1L,4L,1L
+
+#define SN_X500 "X500"
+#define LN_X500 "directory services (X.500)"
+#define NID_X500 11
+#define OBJ_X500 2L,5L
+
+#define SN_X509 "X509"
+#define NID_X509 12
+#define OBJ_X509 OBJ_X500,4L
+
+#define SN_commonName "CN"
+#define LN_commonName "commonName"
+#define NID_commonName 13
+#define OBJ_commonName OBJ_X509,3L
+
+#define SN_surname "SN"
+#define LN_surname "surname"
+#define NID_surname 100
+#define OBJ_surname OBJ_X509,4L
+
+#define LN_serialNumber "serialNumber"
+#define NID_serialNumber 105
+#define OBJ_serialNumber OBJ_X509,5L
+
+#define SN_countryName "C"
+#define LN_countryName "countryName"
+#define NID_countryName 14
+#define OBJ_countryName OBJ_X509,6L
+
+#define SN_localityName "L"
+#define LN_localityName "localityName"
+#define NID_localityName 15
+#define OBJ_localityName OBJ_X509,7L
+
+#define SN_stateOrProvinceName "ST"
+#define LN_stateOrProvinceName "stateOrProvinceName"
+#define NID_stateOrProvinceName 16
+#define OBJ_stateOrProvinceName OBJ_X509,8L
+
+#define SN_streetAddress "street"
+#define LN_streetAddress "streetAddress"
+#define NID_streetAddress 660
+#define OBJ_streetAddress OBJ_X509,9L
+
+#define SN_organizationName "O"
+#define LN_organizationName "organizationName"
+#define NID_organizationName 17
+#define OBJ_organizationName OBJ_X509,10L
+
+#define SN_organizationalUnitName "OU"
+#define LN_organizationalUnitName "organizationalUnitName"
+#define NID_organizationalUnitName 18
+#define OBJ_organizationalUnitName OBJ_X509,11L
+
+#define SN_title "title"
+#define LN_title "title"
+#define NID_title 106
+#define OBJ_title OBJ_X509,12L
+
+#define LN_description "description"
+#define NID_description 107
+#define OBJ_description OBJ_X509,13L
+
+#define LN_searchGuide "searchGuide"
+#define NID_searchGuide 859
+#define OBJ_searchGuide OBJ_X509,14L
+
+#define LN_businessCategory "businessCategory"
+#define NID_businessCategory 860
+#define OBJ_businessCategory OBJ_X509,15L
+
+#define LN_postalAddress "postalAddress"
+#define NID_postalAddress 861
+#define OBJ_postalAddress OBJ_X509,16L
+
+#define LN_postalCode "postalCode"
+#define NID_postalCode 661
+#define OBJ_postalCode OBJ_X509,17L
+
+#define LN_postOfficeBox "postOfficeBox"
+#define NID_postOfficeBox 862
+#define OBJ_postOfficeBox OBJ_X509,18L
+
+#define LN_physicalDeliveryOfficeName "physicalDeliveryOfficeName"
+#define NID_physicalDeliveryOfficeName 863
+#define OBJ_physicalDeliveryOfficeName OBJ_X509,19L
+
+#define LN_telephoneNumber "telephoneNumber"
+#define NID_telephoneNumber 864
+#define OBJ_telephoneNumber OBJ_X509,20L
+
+#define LN_telexNumber "telexNumber"
+#define NID_telexNumber 865
+#define OBJ_telexNumber OBJ_X509,21L
+
+#define LN_teletexTerminalIdentifier "teletexTerminalIdentifier"
+#define NID_teletexTerminalIdentifier 866
+#define OBJ_teletexTerminalIdentifier OBJ_X509,22L
+
+#define LN_facsimileTelephoneNumber "facsimileTelephoneNumber"
+#define NID_facsimileTelephoneNumber 867
+#define OBJ_facsimileTelephoneNumber OBJ_X509,23L
+
+#define LN_x121Address "x121Address"
+#define NID_x121Address 868
+#define OBJ_x121Address OBJ_X509,24L
+
+#define LN_internationaliSDNNumber "internationaliSDNNumber"
+#define NID_internationaliSDNNumber 869
+#define OBJ_internationaliSDNNumber OBJ_X509,25L
+
+#define LN_registeredAddress "registeredAddress"
+#define NID_registeredAddress 870
+#define OBJ_registeredAddress OBJ_X509,26L
+
+#define LN_destinationIndicator "destinationIndicator"
+#define NID_destinationIndicator 871
+#define OBJ_destinationIndicator OBJ_X509,27L
+
+#define LN_preferredDeliveryMethod "preferredDeliveryMethod"
+#define NID_preferredDeliveryMethod 872
+#define OBJ_preferredDeliveryMethod OBJ_X509,28L
+
+#define LN_presentationAddress "presentationAddress"
+#define NID_presentationAddress 873
+#define OBJ_presentationAddress OBJ_X509,29L
+
+#define LN_supportedApplicationContext "supportedApplicationContext"
+#define NID_supportedApplicationContext 874
+#define OBJ_supportedApplicationContext OBJ_X509,30L
+
+#define SN_member "member"
+#define NID_member 875
+#define OBJ_member OBJ_X509,31L
+
+#define SN_owner "owner"
+#define NID_owner 876
+#define OBJ_owner OBJ_X509,32L
+
+#define LN_roleOccupant "roleOccupant"
+#define NID_roleOccupant 877
+#define OBJ_roleOccupant OBJ_X509,33L
+
+#define SN_seeAlso "seeAlso"
+#define NID_seeAlso 878
+#define OBJ_seeAlso OBJ_X509,34L
+
+#define LN_userPassword "userPassword"
+#define NID_userPassword 879
+#define OBJ_userPassword OBJ_X509,35L
+
+#define LN_userCertificate "userCertificate"
+#define NID_userCertificate 880
+#define OBJ_userCertificate OBJ_X509,36L
+
+#define LN_cACertificate "cACertificate"
+#define NID_cACertificate 881
+#define OBJ_cACertificate OBJ_X509,37L
+
+#define LN_authorityRevocationList "authorityRevocationList"
+#define NID_authorityRevocationList 882
+#define OBJ_authorityRevocationList OBJ_X509,38L
+
+#define LN_certificateRevocationList "certificateRevocationList"
+#define NID_certificateRevocationList 883
+#define OBJ_certificateRevocationList OBJ_X509,39L
+
+#define LN_crossCertificatePair "crossCertificatePair"
+#define NID_crossCertificatePair 884
+#define OBJ_crossCertificatePair OBJ_X509,40L
+
+#define SN_name "name"
+#define LN_name "name"
+#define NID_name 173
+#define OBJ_name OBJ_X509,41L
+
+#define SN_givenName "GN"
+#define LN_givenName "givenName"
+#define NID_givenName 99
+#define OBJ_givenName OBJ_X509,42L
+
+#define SN_initials "initials"
+#define LN_initials "initials"
+#define NID_initials 101
+#define OBJ_initials OBJ_X509,43L
+
+#define LN_generationQualifier "generationQualifier"
+#define NID_generationQualifier 509
+#define OBJ_generationQualifier OBJ_X509,44L
+
+#define LN_x500UniqueIdentifier "x500UniqueIdentifier"
+#define NID_x500UniqueIdentifier 503
+#define OBJ_x500UniqueIdentifier OBJ_X509,45L
+
+#define SN_dnQualifier "dnQualifier"
+#define LN_dnQualifier "dnQualifier"
+#define NID_dnQualifier 174
+#define OBJ_dnQualifier OBJ_X509,46L
+
+#define LN_enhancedSearchGuide "enhancedSearchGuide"
+#define NID_enhancedSearchGuide 885
+#define OBJ_enhancedSearchGuide OBJ_X509,47L
+
+#define LN_protocolInformation "protocolInformation"
+#define NID_protocolInformation 886
+#define OBJ_protocolInformation OBJ_X509,48L
+
+#define LN_distinguishedName "distinguishedName"
+#define NID_distinguishedName 887
+#define OBJ_distinguishedName OBJ_X509,49L
+
+#define LN_uniqueMember "uniqueMember"
+#define NID_uniqueMember 888
+#define OBJ_uniqueMember OBJ_X509,50L
+
+#define LN_houseIdentifier "houseIdentifier"
+#define NID_houseIdentifier 889
+#define OBJ_houseIdentifier OBJ_X509,51L
+
+#define LN_supportedAlgorithms "supportedAlgorithms"
+#define NID_supportedAlgorithms 890
+#define OBJ_supportedAlgorithms OBJ_X509,52L
+
+#define LN_deltaRevocationList "deltaRevocationList"
+#define NID_deltaRevocationList 891
+#define OBJ_deltaRevocationList OBJ_X509,53L
+
+#define SN_dmdName "dmdName"
+#define NID_dmdName 892
+#define OBJ_dmdName OBJ_X509,54L
+
+#define LN_pseudonym "pseudonym"
+#define NID_pseudonym 510
+#define OBJ_pseudonym OBJ_X509,65L
+
+#define SN_role "role"
+#define LN_role "role"
+#define NID_role 400
+#define OBJ_role OBJ_X509,72L
+
+#define SN_X500algorithms "X500algorithms"
+#define LN_X500algorithms "directory services - algorithms"
+#define NID_X500algorithms 378
+#define OBJ_X500algorithms OBJ_X500,8L
+
+#define SN_rsa "RSA"
+#define LN_rsa "rsa"
+#define NID_rsa 19
+#define OBJ_rsa OBJ_X500algorithms,1L,1L
+
+#define SN_mdc2WithRSA "RSA-MDC2"
+#define LN_mdc2WithRSA "mdc2WithRSA"
+#define NID_mdc2WithRSA 96
+#define OBJ_mdc2WithRSA OBJ_X500algorithms,3L,100L
+
+#define SN_mdc2 "MDC2"
+#define LN_mdc2 "mdc2"
+#define NID_mdc2 95
+#define OBJ_mdc2 OBJ_X500algorithms,3L,101L
+
+#define SN_id_ce "id-ce"
+#define NID_id_ce 81
+#define OBJ_id_ce OBJ_X500,29L
+
+#define SN_subject_directory_attributes "subjectDirectoryAttributes"
+#define LN_subject_directory_attributes "X509v3 Subject Directory Attributes"
+#define NID_subject_directory_attributes 769
+#define OBJ_subject_directory_attributes OBJ_id_ce,9L
+
+#define SN_subject_key_identifier "subjectKeyIdentifier"
+#define LN_subject_key_identifier "X509v3 Subject Key Identifier"
+#define NID_subject_key_identifier 82
+#define OBJ_subject_key_identifier OBJ_id_ce,14L
+
+#define SN_key_usage "keyUsage"
+#define LN_key_usage "X509v3 Key Usage"
+#define NID_key_usage 83
+#define OBJ_key_usage OBJ_id_ce,15L
+
+#define SN_private_key_usage_period "privateKeyUsagePeriod"
+#define LN_private_key_usage_period "X509v3 Private Key Usage Period"
+#define NID_private_key_usage_period 84
+#define OBJ_private_key_usage_period OBJ_id_ce,16L
+
+#define SN_subject_alt_name "subjectAltName"
+#define LN_subject_alt_name "X509v3 Subject Alternative Name"
+#define NID_subject_alt_name 85
+#define OBJ_subject_alt_name OBJ_id_ce,17L
+
+#define SN_issuer_alt_name "issuerAltName"
+#define LN_issuer_alt_name "X509v3 Issuer Alternative Name"
+#define NID_issuer_alt_name 86
+#define OBJ_issuer_alt_name OBJ_id_ce,18L
+
+#define SN_basic_constraints "basicConstraints"
+#define LN_basic_constraints "X509v3 Basic Constraints"
+#define NID_basic_constraints 87
+#define OBJ_basic_constraints OBJ_id_ce,19L
+
+#define SN_crl_number "crlNumber"
+#define LN_crl_number "X509v3 CRL Number"
+#define NID_crl_number 88
+#define OBJ_crl_number OBJ_id_ce,20L
+
+#define SN_crl_reason "CRLReason"
+#define LN_crl_reason "X509v3 CRL Reason Code"
+#define NID_crl_reason 141
+#define OBJ_crl_reason OBJ_id_ce,21L
+
+#define SN_invalidity_date "invalidityDate"
+#define LN_invalidity_date "Invalidity Date"
+#define NID_invalidity_date 142
+#define OBJ_invalidity_date OBJ_id_ce,24L
+
+#define SN_delta_crl "deltaCRL"
+#define LN_delta_crl "X509v3 Delta CRL Indicator"
+#define NID_delta_crl 140
+#define OBJ_delta_crl OBJ_id_ce,27L
+
+#define SN_issuing_distribution_point "issuingDistributionPoint"
+#define LN_issuing_distribution_point "X509v3 Issuing Distrubution Point"
+#define NID_issuing_distribution_point 770
+#define OBJ_issuing_distribution_point OBJ_id_ce,28L
+
+#define SN_certificate_issuer "certificateIssuer"
+#define LN_certificate_issuer "X509v3 Certificate Issuer"
+#define NID_certificate_issuer 771
+#define OBJ_certificate_issuer OBJ_id_ce,29L
+
+#define SN_name_constraints "nameConstraints"
+#define LN_name_constraints "X509v3 Name Constraints"
+#define NID_name_constraints 666
+#define OBJ_name_constraints OBJ_id_ce,30L
+
+#define SN_crl_distribution_points "crlDistributionPoints"
+#define LN_crl_distribution_points "X509v3 CRL Distribution Points"
+#define NID_crl_distribution_points 103
+#define OBJ_crl_distribution_points OBJ_id_ce,31L
+
+#define SN_certificate_policies "certificatePolicies"
+#define LN_certificate_policies "X509v3 Certificate Policies"
+#define NID_certificate_policies 89
+#define OBJ_certificate_policies OBJ_id_ce,32L
+
+#define SN_any_policy "anyPolicy"
+#define LN_any_policy "X509v3 Any Policy"
+#define NID_any_policy 746
+#define OBJ_any_policy OBJ_certificate_policies,0L
+
+#define SN_policy_mappings "policyMappings"
+#define LN_policy_mappings "X509v3 Policy Mappings"
+#define NID_policy_mappings 747
+#define OBJ_policy_mappings OBJ_id_ce,33L
+
+#define SN_authority_key_identifier "authorityKeyIdentifier"
+#define LN_authority_key_identifier "X509v3 Authority Key Identifier"
+#define NID_authority_key_identifier 90
+#define OBJ_authority_key_identifier OBJ_id_ce,35L
+
+#define SN_policy_constraints "policyConstraints"
+#define LN_policy_constraints "X509v3 Policy Constraints"
+#define NID_policy_constraints 401
+#define OBJ_policy_constraints OBJ_id_ce,36L
+
+#define SN_ext_key_usage "extendedKeyUsage"
+#define LN_ext_key_usage "X509v3 Extended Key Usage"
+#define NID_ext_key_usage 126
+#define OBJ_ext_key_usage OBJ_id_ce,37L
+
+#define SN_freshest_crl "freshestCRL"
+#define LN_freshest_crl "X509v3 Freshest CRL"
+#define NID_freshest_crl 857
+#define OBJ_freshest_crl OBJ_id_ce,46L
+
+#define SN_inhibit_any_policy "inhibitAnyPolicy"
+#define LN_inhibit_any_policy "X509v3 Inhibit Any Policy"
+#define NID_inhibit_any_policy 748
+#define OBJ_inhibit_any_policy OBJ_id_ce,54L
+
+#define SN_target_information "targetInformation"
+#define LN_target_information "X509v3 AC Targeting"
+#define NID_target_information 402
+#define OBJ_target_information OBJ_id_ce,55L
+
+#define SN_no_rev_avail "noRevAvail"
+#define LN_no_rev_avail "X509v3 No Revocation Available"
+#define NID_no_rev_avail 403
+#define OBJ_no_rev_avail OBJ_id_ce,56L
+
+#define SN_anyExtendedKeyUsage "anyExtendedKeyUsage"
+#define LN_anyExtendedKeyUsage "Any Extended Key Usage"
+#define NID_anyExtendedKeyUsage 910
+#define OBJ_anyExtendedKeyUsage OBJ_ext_key_usage,0L
+
+#define SN_netscape "Netscape"
+#define LN_netscape "Netscape Communications Corp."
+#define NID_netscape 57
+#define OBJ_netscape 2L,16L,840L,1L,113730L
+
+#define SN_netscape_cert_extension "nsCertExt"
+#define LN_netscape_cert_extension "Netscape Certificate Extension"
+#define NID_netscape_cert_extension 58
+#define OBJ_netscape_cert_extension OBJ_netscape,1L
+
+#define SN_netscape_data_type "nsDataType"
+#define LN_netscape_data_type "Netscape Data Type"
+#define NID_netscape_data_type 59
+#define OBJ_netscape_data_type OBJ_netscape,2L
+
+#define SN_netscape_cert_type "nsCertType"
+#define LN_netscape_cert_type "Netscape Cert Type"
+#define NID_netscape_cert_type 71
+#define OBJ_netscape_cert_type OBJ_netscape_cert_extension,1L
+
+#define SN_netscape_base_url "nsBaseUrl"
+#define LN_netscape_base_url "Netscape Base Url"
+#define NID_netscape_base_url 72
+#define OBJ_netscape_base_url OBJ_netscape_cert_extension,2L
+
+#define SN_netscape_revocation_url "nsRevocationUrl"
+#define LN_netscape_revocation_url "Netscape Revocation Url"
+#define NID_netscape_revocation_url 73
+#define OBJ_netscape_revocation_url OBJ_netscape_cert_extension,3L
+
+#define SN_netscape_ca_revocation_url "nsCaRevocationUrl"
+#define LN_netscape_ca_revocation_url "Netscape CA Revocation Url"
+#define NID_netscape_ca_revocation_url 74
+#define OBJ_netscape_ca_revocation_url OBJ_netscape_cert_extension,4L
+
+#define SN_netscape_renewal_url "nsRenewalUrl"
+#define LN_netscape_renewal_url "Netscape Renewal Url"
+#define NID_netscape_renewal_url 75
+#define OBJ_netscape_renewal_url OBJ_netscape_cert_extension,7L
+
+#define SN_netscape_ca_policy_url "nsCaPolicyUrl"
+#define LN_netscape_ca_policy_url "Netscape CA Policy Url"
+#define NID_netscape_ca_policy_url 76
+#define OBJ_netscape_ca_policy_url OBJ_netscape_cert_extension,8L
+
+#define SN_netscape_ssl_server_name "nsSslServerName"
+#define LN_netscape_ssl_server_name "Netscape SSL Server Name"
+#define NID_netscape_ssl_server_name 77
+#define OBJ_netscape_ssl_server_name OBJ_netscape_cert_extension,12L
+
+#define SN_netscape_comment "nsComment"
+#define LN_netscape_comment "Netscape Comment"
+#define NID_netscape_comment 78
+#define OBJ_netscape_comment OBJ_netscape_cert_extension,13L
+
+#define SN_netscape_cert_sequence "nsCertSequence"
+#define LN_netscape_cert_sequence "Netscape Certificate Sequence"
+#define NID_netscape_cert_sequence 79
+#define OBJ_netscape_cert_sequence OBJ_netscape_data_type,5L
+
+#define SN_ns_sgc "nsSGC"
+#define LN_ns_sgc "Netscape Server Gated Crypto"
+#define NID_ns_sgc 139
+#define OBJ_ns_sgc OBJ_netscape,4L,1L
+
+#define SN_org "ORG"
+#define LN_org "org"
+#define NID_org 379
+#define OBJ_org OBJ_iso,3L
+
+#define SN_dod "DOD"
+#define LN_dod "dod"
+#define NID_dod 380
+#define OBJ_dod OBJ_org,6L
+
+#define SN_iana "IANA"
+#define LN_iana "iana"
+#define NID_iana 381
+#define OBJ_iana OBJ_dod,1L
+
+#define OBJ_internet OBJ_iana
+
+#define SN_Directory "directory"
+#define LN_Directory "Directory"
+#define NID_Directory 382
+#define OBJ_Directory OBJ_internet,1L
+
+#define SN_Management "mgmt"
+#define LN_Management "Management"
+#define NID_Management 383
+#define OBJ_Management OBJ_internet,2L
+
+#define SN_Experimental "experimental"
+#define LN_Experimental "Experimental"
+#define NID_Experimental 384
+#define OBJ_Experimental OBJ_internet,3L
+
+#define SN_Private "private"
+#define LN_Private "Private"
+#define NID_Private 385
+#define OBJ_Private OBJ_internet,4L
+
+#define SN_Security "security"
+#define LN_Security "Security"
+#define NID_Security 386
+#define OBJ_Security OBJ_internet,5L
+
+#define SN_SNMPv2 "snmpv2"
+#define LN_SNMPv2 "SNMPv2"
+#define NID_SNMPv2 387
+#define OBJ_SNMPv2 OBJ_internet,6L
+
+#define LN_Mail "Mail"
+#define NID_Mail 388
+#define OBJ_Mail OBJ_internet,7L
+
+#define SN_Enterprises "enterprises"
+#define LN_Enterprises "Enterprises"
+#define NID_Enterprises 389
+#define OBJ_Enterprises OBJ_Private,1L
+
+#define SN_dcObject "dcobject"
+#define LN_dcObject "dcObject"
+#define NID_dcObject 390
+#define OBJ_dcObject OBJ_Enterprises,1466L,344L
+
+#define SN_mime_mhs "mime-mhs"
+#define LN_mime_mhs "MIME MHS"
+#define NID_mime_mhs 504
+#define OBJ_mime_mhs OBJ_Mail,1L
+
+#define SN_mime_mhs_headings "mime-mhs-headings"
+#define LN_mime_mhs_headings "mime-mhs-headings"
+#define NID_mime_mhs_headings 505
+#define OBJ_mime_mhs_headings OBJ_mime_mhs,1L
+
+#define SN_mime_mhs_bodies "mime-mhs-bodies"
+#define LN_mime_mhs_bodies "mime-mhs-bodies"
+#define NID_mime_mhs_bodies 506
+#define OBJ_mime_mhs_bodies OBJ_mime_mhs,2L
+
+#define SN_id_hex_partial_message "id-hex-partial-message"
+#define LN_id_hex_partial_message "id-hex-partial-message"
+#define NID_id_hex_partial_message 507
+#define OBJ_id_hex_partial_message OBJ_mime_mhs_headings,1L
+
+#define SN_id_hex_multipart_message "id-hex-multipart-message"
+#define LN_id_hex_multipart_message "id-hex-multipart-message"
+#define NID_id_hex_multipart_message 508
+#define OBJ_id_hex_multipart_message OBJ_mime_mhs_headings,2L
+
+#define SN_rle_compression "RLE"
+#define LN_rle_compression "run length compression"
+#define NID_rle_compression 124
+#define OBJ_rle_compression 1L,1L,1L,1L,666L,1L
+
+#define SN_zlib_compression "ZLIB"
+#define LN_zlib_compression "zlib compression"
+#define NID_zlib_compression 125
+#define OBJ_zlib_compression OBJ_id_smime_alg,8L
+
+#define OBJ_csor 2L,16L,840L,1L,101L,3L
+
+#define OBJ_nistAlgorithms OBJ_csor,4L
+
+#define OBJ_aes OBJ_nistAlgorithms,1L
+
+#define SN_aes_128_ecb "AES-128-ECB"
+#define LN_aes_128_ecb "aes-128-ecb"
+#define NID_aes_128_ecb 418
+#define OBJ_aes_128_ecb OBJ_aes,1L
+
+#define SN_aes_128_cbc "AES-128-CBC"
+#define LN_aes_128_cbc "aes-128-cbc"
+#define NID_aes_128_cbc 419
+#define OBJ_aes_128_cbc OBJ_aes,2L
+
+#define SN_aes_128_ofb128 "AES-128-OFB"
+#define LN_aes_128_ofb128 "aes-128-ofb"
+#define NID_aes_128_ofb128 420
+#define OBJ_aes_128_ofb128 OBJ_aes,3L
+
+#define SN_aes_128_cfb128 "AES-128-CFB"
+#define LN_aes_128_cfb128 "aes-128-cfb"
+#define NID_aes_128_cfb128 421
+#define OBJ_aes_128_cfb128 OBJ_aes,4L
+
+#define SN_id_aes128_wrap "id-aes128-wrap"
+#define NID_id_aes128_wrap 788
+#define OBJ_id_aes128_wrap OBJ_aes,5L
+
+#define SN_aes_128_gcm "id-aes128-GCM"
+#define LN_aes_128_gcm "aes-128-gcm"
+#define NID_aes_128_gcm 895
+#define OBJ_aes_128_gcm OBJ_aes,6L
+
+#define SN_aes_128_ccm "id-aes128-CCM"
+#define LN_aes_128_ccm "aes-128-ccm"
+#define NID_aes_128_ccm 896
+#define OBJ_aes_128_ccm OBJ_aes,7L
+
+#define SN_id_aes128_wrap_pad "id-aes128-wrap-pad"
+#define NID_id_aes128_wrap_pad 897
+#define OBJ_id_aes128_wrap_pad OBJ_aes,8L
+
+#define SN_aes_192_ecb "AES-192-ECB"
+#define LN_aes_192_ecb "aes-192-ecb"
+#define NID_aes_192_ecb 422
+#define OBJ_aes_192_ecb OBJ_aes,21L
+
+#define SN_aes_192_cbc "AES-192-CBC"
+#define LN_aes_192_cbc "aes-192-cbc"
+#define NID_aes_192_cbc 423
+#define OBJ_aes_192_cbc OBJ_aes,22L
+
+#define SN_aes_192_ofb128 "AES-192-OFB"
+#define LN_aes_192_ofb128 "aes-192-ofb"
+#define NID_aes_192_ofb128 424
+#define OBJ_aes_192_ofb128 OBJ_aes,23L
+
+#define SN_aes_192_cfb128 "AES-192-CFB"
+#define LN_aes_192_cfb128 "aes-192-cfb"
+#define NID_aes_192_cfb128 425
+#define OBJ_aes_192_cfb128 OBJ_aes,24L
+
+#define SN_id_aes192_wrap "id-aes192-wrap"
+#define NID_id_aes192_wrap 789
+#define OBJ_id_aes192_wrap OBJ_aes,25L
+
+#define SN_aes_192_gcm "id-aes192-GCM"
+#define LN_aes_192_gcm "aes-192-gcm"
+#define NID_aes_192_gcm 898
+#define OBJ_aes_192_gcm OBJ_aes,26L
+
+#define SN_aes_192_ccm "id-aes192-CCM"
+#define LN_aes_192_ccm "aes-192-ccm"
+#define NID_aes_192_ccm 899
+#define OBJ_aes_192_ccm OBJ_aes,27L
+
+#define SN_id_aes192_wrap_pad "id-aes192-wrap-pad"
+#define NID_id_aes192_wrap_pad 900
+#define OBJ_id_aes192_wrap_pad OBJ_aes,28L
+
+#define SN_aes_256_ecb "AES-256-ECB"
+#define LN_aes_256_ecb "aes-256-ecb"
+#define NID_aes_256_ecb 426
+#define OBJ_aes_256_ecb OBJ_aes,41L
+
+#define SN_aes_256_cbc "AES-256-CBC"
+#define LN_aes_256_cbc "aes-256-cbc"
+#define NID_aes_256_cbc 427
+#define OBJ_aes_256_cbc OBJ_aes,42L
+
+#define SN_aes_256_ofb128 "AES-256-OFB"
+#define LN_aes_256_ofb128 "aes-256-ofb"
+#define NID_aes_256_ofb128 428
+#define OBJ_aes_256_ofb128 OBJ_aes,43L
+
+#define SN_aes_256_cfb128 "AES-256-CFB"
+#define LN_aes_256_cfb128 "aes-256-cfb"
+#define NID_aes_256_cfb128 429
+#define OBJ_aes_256_cfb128 OBJ_aes,44L
+
+#define SN_id_aes256_wrap "id-aes256-wrap"
+#define NID_id_aes256_wrap 790
+#define OBJ_id_aes256_wrap OBJ_aes,45L
+
+#define SN_aes_256_gcm "id-aes256-GCM"
+#define LN_aes_256_gcm "aes-256-gcm"
+#define NID_aes_256_gcm 901
+#define OBJ_aes_256_gcm OBJ_aes,46L
+
+#define SN_aes_256_ccm "id-aes256-CCM"
+#define LN_aes_256_ccm "aes-256-ccm"
+#define NID_aes_256_ccm 902
+#define OBJ_aes_256_ccm OBJ_aes,47L
+
+#define SN_id_aes256_wrap_pad "id-aes256-wrap-pad"
+#define NID_id_aes256_wrap_pad 903
+#define OBJ_id_aes256_wrap_pad OBJ_aes,48L
+
+#define SN_aes_128_cfb1 "AES-128-CFB1"
+#define LN_aes_128_cfb1 "aes-128-cfb1"
+#define NID_aes_128_cfb1 650
+
+#define SN_aes_192_cfb1 "AES-192-CFB1"
+#define LN_aes_192_cfb1 "aes-192-cfb1"
+#define NID_aes_192_cfb1 651
+
+#define SN_aes_256_cfb1 "AES-256-CFB1"
+#define LN_aes_256_cfb1 "aes-256-cfb1"
+#define NID_aes_256_cfb1 652
+
+#define SN_aes_128_cfb8 "AES-128-CFB8"
+#define LN_aes_128_cfb8 "aes-128-cfb8"
+#define NID_aes_128_cfb8 653
+
+#define SN_aes_192_cfb8 "AES-192-CFB8"
+#define LN_aes_192_cfb8 "aes-192-cfb8"
+#define NID_aes_192_cfb8 654
+
+#define SN_aes_256_cfb8 "AES-256-CFB8"
+#define LN_aes_256_cfb8 "aes-256-cfb8"
+#define NID_aes_256_cfb8 655
+
+#define SN_aes_128_ctr "AES-128-CTR"
+#define LN_aes_128_ctr "aes-128-ctr"
+#define NID_aes_128_ctr 904
+
+#define SN_aes_192_ctr "AES-192-CTR"
+#define LN_aes_192_ctr "aes-192-ctr"
+#define NID_aes_192_ctr 905
+
+#define SN_aes_256_ctr "AES-256-CTR"
+#define LN_aes_256_ctr "aes-256-ctr"
+#define NID_aes_256_ctr 906
+
+#define SN_aes_128_xts "AES-128-XTS"
+#define LN_aes_128_xts "aes-128-xts"
+#define NID_aes_128_xts 913
+
+#define SN_aes_256_xts "AES-256-XTS"
+#define LN_aes_256_xts "aes-256-xts"
+#define NID_aes_256_xts 914
+
+#define SN_des_cfb1 "DES-CFB1"
+#define LN_des_cfb1 "des-cfb1"
+#define NID_des_cfb1 656
+
+#define SN_des_cfb8 "DES-CFB8"
+#define LN_des_cfb8 "des-cfb8"
+#define NID_des_cfb8 657
+
+#define SN_des_ede3_cfb1 "DES-EDE3-CFB1"
+#define LN_des_ede3_cfb1 "des-ede3-cfb1"
+#define NID_des_ede3_cfb1 658
+
+#define SN_des_ede3_cfb8 "DES-EDE3-CFB8"
+#define LN_des_ede3_cfb8 "des-ede3-cfb8"
+#define NID_des_ede3_cfb8 659
+
+#define OBJ_nist_hashalgs OBJ_nistAlgorithms,2L
+
+#define SN_sha256 "SHA256"
+#define LN_sha256 "sha256"
+#define NID_sha256 672
+#define OBJ_sha256 OBJ_nist_hashalgs,1L
+
+#define SN_sha384 "SHA384"
+#define LN_sha384 "sha384"
+#define NID_sha384 673
+#define OBJ_sha384 OBJ_nist_hashalgs,2L
+
+#define SN_sha512 "SHA512"
+#define LN_sha512 "sha512"
+#define NID_sha512 674
+#define OBJ_sha512 OBJ_nist_hashalgs,3L
+
+#define SN_sha224 "SHA224"
+#define LN_sha224 "sha224"
+#define NID_sha224 675
+#define OBJ_sha224 OBJ_nist_hashalgs,4L
+
+#define OBJ_dsa_with_sha2 OBJ_nistAlgorithms,3L
+
+#define SN_dsa_with_SHA224 "dsa_with_SHA224"
+#define NID_dsa_with_SHA224 802
+#define OBJ_dsa_with_SHA224 OBJ_dsa_with_sha2,1L
+
+#define SN_dsa_with_SHA256 "dsa_with_SHA256"
+#define NID_dsa_with_SHA256 803
+#define OBJ_dsa_with_SHA256 OBJ_dsa_with_sha2,2L
+
+#define SN_hold_instruction_code "holdInstructionCode"
+#define LN_hold_instruction_code "Hold Instruction Code"
+#define NID_hold_instruction_code 430
+#define OBJ_hold_instruction_code OBJ_id_ce,23L
+
+#define OBJ_holdInstruction OBJ_X9_57,2L
+
+#define SN_hold_instruction_none "holdInstructionNone"
+#define LN_hold_instruction_none "Hold Instruction None"
+#define NID_hold_instruction_none 431
+#define OBJ_hold_instruction_none OBJ_holdInstruction,1L
+
+#define SN_hold_instruction_call_issuer "holdInstructionCallIssuer"
+#define LN_hold_instruction_call_issuer "Hold Instruction Call Issuer"
+#define NID_hold_instruction_call_issuer 432
+#define OBJ_hold_instruction_call_issuer OBJ_holdInstruction,2L
+
+#define SN_hold_instruction_reject "holdInstructionReject"
+#define LN_hold_instruction_reject "Hold Instruction Reject"
+#define NID_hold_instruction_reject 433
+#define OBJ_hold_instruction_reject OBJ_holdInstruction,3L
+
+#define SN_data "data"
+#define NID_data 434
+#define OBJ_data OBJ_itu_t,9L
+
+#define SN_pss "pss"
+#define NID_pss 435
+#define OBJ_pss OBJ_data,2342L
+
+#define SN_ucl "ucl"
+#define NID_ucl 436
+#define OBJ_ucl OBJ_pss,19200300L
+
+#define SN_pilot "pilot"
+#define NID_pilot 437
+#define OBJ_pilot OBJ_ucl,100L
+
+#define LN_pilotAttributeType "pilotAttributeType"
+#define NID_pilotAttributeType 438
+#define OBJ_pilotAttributeType OBJ_pilot,1L
+
+#define LN_pilotAttributeSyntax "pilotAttributeSyntax"
+#define NID_pilotAttributeSyntax 439
+#define OBJ_pilotAttributeSyntax OBJ_pilot,3L
+
+#define LN_pilotObjectClass "pilotObjectClass"
+#define NID_pilotObjectClass 440
+#define OBJ_pilotObjectClass OBJ_pilot,4L
+
+#define LN_pilotGroups "pilotGroups"
+#define NID_pilotGroups 441
+#define OBJ_pilotGroups OBJ_pilot,10L
+
+#define LN_iA5StringSyntax "iA5StringSyntax"
+#define NID_iA5StringSyntax 442
+#define OBJ_iA5StringSyntax OBJ_pilotAttributeSyntax,4L
+
+#define LN_caseIgnoreIA5StringSyntax "caseIgnoreIA5StringSyntax"
+#define NID_caseIgnoreIA5StringSyntax 443
+#define OBJ_caseIgnoreIA5StringSyntax OBJ_pilotAttributeSyntax,5L
+
+#define LN_pilotObject "pilotObject"
+#define NID_pilotObject 444
+#define OBJ_pilotObject OBJ_pilotObjectClass,3L
+
+#define LN_pilotPerson "pilotPerson"
+#define NID_pilotPerson 445
+#define OBJ_pilotPerson OBJ_pilotObjectClass,4L
+
+#define SN_account "account"
+#define NID_account 446
+#define OBJ_account OBJ_pilotObjectClass,5L
+
+#define SN_document "document"
+#define NID_document 447
+#define OBJ_document OBJ_pilotObjectClass,6L
+
+#define SN_room "room"
+#define NID_room 448
+#define OBJ_room OBJ_pilotObjectClass,7L
+
+#define LN_documentSeries "documentSeries"
+#define NID_documentSeries 449
+#define OBJ_documentSeries OBJ_pilotObjectClass,9L
+
+#define SN_Domain "domain"
+#define LN_Domain "Domain"
+#define NID_Domain 392
+#define OBJ_Domain OBJ_pilotObjectClass,13L
+
+#define LN_rFC822localPart "rFC822localPart"
+#define NID_rFC822localPart 450
+#define OBJ_rFC822localPart OBJ_pilotObjectClass,14L
+
+#define LN_dNSDomain "dNSDomain"
+#define NID_dNSDomain 451
+#define OBJ_dNSDomain OBJ_pilotObjectClass,15L
+
+#define LN_domainRelatedObject "domainRelatedObject"
+#define NID_domainRelatedObject 452
+#define OBJ_domainRelatedObject OBJ_pilotObjectClass,17L
+
+#define LN_friendlyCountry "friendlyCountry"
+#define NID_friendlyCountry 453
+#define OBJ_friendlyCountry OBJ_pilotObjectClass,18L
+
+#define LN_simpleSecurityObject "simpleSecurityObject"
+#define NID_simpleSecurityObject 454
+#define OBJ_simpleSecurityObject OBJ_pilotObjectClass,19L
+
+#define LN_pilotOrganization "pilotOrganization"
+#define NID_pilotOrganization 455
+#define OBJ_pilotOrganization OBJ_pilotObjectClass,20L
+
+#define LN_pilotDSA "pilotDSA"
+#define NID_pilotDSA 456
+#define OBJ_pilotDSA OBJ_pilotObjectClass,21L
+
+#define LN_qualityLabelledData "qualityLabelledData"
+#define NID_qualityLabelledData 457
+#define OBJ_qualityLabelledData OBJ_pilotObjectClass,22L
+
+#define SN_userId "UID"
+#define LN_userId "userId"
+#define NID_userId 458
+#define OBJ_userId OBJ_pilotAttributeType,1L
+
+#define LN_textEncodedORAddress "textEncodedORAddress"
+#define NID_textEncodedORAddress 459
+#define OBJ_textEncodedORAddress OBJ_pilotAttributeType,2L
+
+#define SN_rfc822Mailbox "mail"
+#define LN_rfc822Mailbox "rfc822Mailbox"
+#define NID_rfc822Mailbox 460
+#define OBJ_rfc822Mailbox OBJ_pilotAttributeType,3L
+
+#define SN_info "info"
+#define NID_info 461
+#define OBJ_info OBJ_pilotAttributeType,4L
+
+#define LN_favouriteDrink "favouriteDrink"
+#define NID_favouriteDrink 462
+#define OBJ_favouriteDrink OBJ_pilotAttributeType,5L
+
+#define LN_roomNumber "roomNumber"
+#define NID_roomNumber 463
+#define OBJ_roomNumber OBJ_pilotAttributeType,6L
+
+#define SN_photo "photo"
+#define NID_photo 464
+#define OBJ_photo OBJ_pilotAttributeType,7L
+
+#define LN_userClass "userClass"
+#define NID_userClass 465
+#define OBJ_userClass OBJ_pilotAttributeType,8L
+
+#define SN_host "host"
+#define NID_host 466
+#define OBJ_host OBJ_pilotAttributeType,9L
+
+#define SN_manager "manager"
+#define NID_manager 467
+#define OBJ_manager OBJ_pilotAttributeType,10L
+
+#define LN_documentIdentifier "documentIdentifier"
+#define NID_documentIdentifier 468
+#define OBJ_documentIdentifier OBJ_pilotAttributeType,11L
+
+#define LN_documentTitle "documentTitle"
+#define NID_documentTitle 469
+#define OBJ_documentTitle OBJ_pilotAttributeType,12L
+
+#define LN_documentVersion "documentVersion"
+#define NID_documentVersion 470
+#define OBJ_documentVersion OBJ_pilotAttributeType,13L
+
+#define LN_documentAuthor "documentAuthor"
+#define NID_documentAuthor 471
+#define OBJ_documentAuthor OBJ_pilotAttributeType,14L
+
+#define LN_documentLocation "documentLocation"
+#define NID_documentLocation 472
+#define OBJ_documentLocation OBJ_pilotAttributeType,15L
+
+#define LN_homeTelephoneNumber "homeTelephoneNumber"
+#define NID_homeTelephoneNumber 473
+#define OBJ_homeTelephoneNumber OBJ_pilotAttributeType,20L
+
+#define SN_secretary "secretary"
+#define NID_secretary 474
+#define OBJ_secretary OBJ_pilotAttributeType,21L
+
+#define LN_otherMailbox "otherMailbox"
+#define NID_otherMailbox 475
+#define OBJ_otherMailbox OBJ_pilotAttributeType,22L
+
+#define LN_lastModifiedTime "lastModifiedTime"
+#define NID_lastModifiedTime 476
+#define OBJ_lastModifiedTime OBJ_pilotAttributeType,23L
+
+#define LN_lastModifiedBy "lastModifiedBy"
+#define NID_lastModifiedBy 477
+#define OBJ_lastModifiedBy OBJ_pilotAttributeType,24L
+
+#define SN_domainComponent "DC"
+#define LN_domainComponent "domainComponent"
+#define NID_domainComponent 391
+#define OBJ_domainComponent OBJ_pilotAttributeType,25L
+
+#define LN_aRecord "aRecord"
+#define NID_aRecord 478
+#define OBJ_aRecord OBJ_pilotAttributeType,26L
+
+#define LN_pilotAttributeType27 "pilotAttributeType27"
+#define NID_pilotAttributeType27 479
+#define OBJ_pilotAttributeType27 OBJ_pilotAttributeType,27L
+
+#define LN_mXRecord "mXRecord"
+#define NID_mXRecord 480
+#define OBJ_mXRecord OBJ_pilotAttributeType,28L
+
+#define LN_nSRecord "nSRecord"
+#define NID_nSRecord 481
+#define OBJ_nSRecord OBJ_pilotAttributeType,29L
+
+#define LN_sOARecord "sOARecord"
+#define NID_sOARecord 482
+#define OBJ_sOARecord OBJ_pilotAttributeType,30L
+
+#define LN_cNAMERecord "cNAMERecord"
+#define NID_cNAMERecord 483
+#define OBJ_cNAMERecord OBJ_pilotAttributeType,31L
+
+#define LN_associatedDomain "associatedDomain"
+#define NID_associatedDomain 484
+#define OBJ_associatedDomain OBJ_pilotAttributeType,37L
+
+#define LN_associatedName "associatedName"
+#define NID_associatedName 485
+#define OBJ_associatedName OBJ_pilotAttributeType,38L
+
+#define LN_homePostalAddress "homePostalAddress"
+#define NID_homePostalAddress 486
+#define OBJ_homePostalAddress OBJ_pilotAttributeType,39L
+
+#define LN_personalTitle "personalTitle"
+#define NID_personalTitle 487
+#define OBJ_personalTitle OBJ_pilotAttributeType,40L
+
+#define LN_mobileTelephoneNumber "mobileTelephoneNumber"
+#define NID_mobileTelephoneNumber 488
+#define OBJ_mobileTelephoneNumber OBJ_pilotAttributeType,41L
+
+#define LN_pagerTelephoneNumber "pagerTelephoneNumber"
+#define NID_pagerTelephoneNumber 489
+#define OBJ_pagerTelephoneNumber OBJ_pilotAttributeType,42L
+
+#define LN_friendlyCountryName "friendlyCountryName"
+#define NID_friendlyCountryName 490
+#define OBJ_friendlyCountryName OBJ_pilotAttributeType,43L
+
+#define LN_organizationalStatus "organizationalStatus"
+#define NID_organizationalStatus 491
+#define OBJ_organizationalStatus OBJ_pilotAttributeType,45L
+
+#define LN_janetMailbox "janetMailbox"
+#define NID_janetMailbox 492
+#define OBJ_janetMailbox OBJ_pilotAttributeType,46L
+
+#define LN_mailPreferenceOption "mailPreferenceOption"
+#define NID_mailPreferenceOption 493
+#define OBJ_mailPreferenceOption OBJ_pilotAttributeType,47L
+
+#define LN_buildingName "buildingName"
+#define NID_buildingName 494
+#define OBJ_buildingName OBJ_pilotAttributeType,48L
+
+#define LN_dSAQuality "dSAQuality"
+#define NID_dSAQuality 495
+#define OBJ_dSAQuality OBJ_pilotAttributeType,49L
+
+#define LN_singleLevelQuality "singleLevelQuality"
+#define NID_singleLevelQuality 496
+#define OBJ_singleLevelQuality OBJ_pilotAttributeType,50L
+
+#define LN_subtreeMinimumQuality "subtreeMinimumQuality"
+#define NID_subtreeMinimumQuality 497
+#define OBJ_subtreeMinimumQuality OBJ_pilotAttributeType,51L
+
+#define LN_subtreeMaximumQuality "subtreeMaximumQuality"
+#define NID_subtreeMaximumQuality 498
+#define OBJ_subtreeMaximumQuality OBJ_pilotAttributeType,52L
+
+#define LN_personalSignature "personalSignature"
+#define NID_personalSignature 499
+#define OBJ_personalSignature OBJ_pilotAttributeType,53L
+
+#define LN_dITRedirect "dITRedirect"
+#define NID_dITRedirect 500
+#define OBJ_dITRedirect OBJ_pilotAttributeType,54L
+
+#define SN_audio "audio"
+#define NID_audio 501
+#define OBJ_audio OBJ_pilotAttributeType,55L
+
+#define LN_documentPublisher "documentPublisher"
+#define NID_documentPublisher 502
+#define OBJ_documentPublisher OBJ_pilotAttributeType,56L
+
+#define SN_id_set "id-set"
+#define LN_id_set "Secure Electronic Transactions"
+#define NID_id_set 512
+#define OBJ_id_set OBJ_international_organizations,42L
+
+#define SN_set_ctype "set-ctype"
+#define LN_set_ctype "content types"
+#define NID_set_ctype 513
+#define OBJ_set_ctype OBJ_id_set,0L
+
+#define SN_set_msgExt "set-msgExt"
+#define LN_set_msgExt "message extensions"
+#define NID_set_msgExt 514
+#define OBJ_set_msgExt OBJ_id_set,1L
+
+#define SN_set_attr "set-attr"
+#define NID_set_attr 515
+#define OBJ_set_attr OBJ_id_set,3L
+
+#define SN_set_policy "set-policy"
+#define NID_set_policy 516
+#define OBJ_set_policy OBJ_id_set,5L
+
+#define SN_set_certExt "set-certExt"
+#define LN_set_certExt "certificate extensions"
+#define NID_set_certExt 517
+#define OBJ_set_certExt OBJ_id_set,7L
+
+#define SN_set_brand "set-brand"
+#define NID_set_brand 518
+#define OBJ_set_brand OBJ_id_set,8L
+
+#define SN_setct_PANData "setct-PANData"
+#define NID_setct_PANData 519
+#define OBJ_setct_PANData OBJ_set_ctype,0L
+
+#define SN_setct_PANToken "setct-PANToken"
+#define NID_setct_PANToken 520
+#define OBJ_setct_PANToken OBJ_set_ctype,1L
+
+#define SN_setct_PANOnly "setct-PANOnly"
+#define NID_setct_PANOnly 521
+#define OBJ_setct_PANOnly OBJ_set_ctype,2L
+
+#define SN_setct_OIData "setct-OIData"
+#define NID_setct_OIData 522
+#define OBJ_setct_OIData OBJ_set_ctype,3L
+
+#define SN_setct_PI "setct-PI"
+#define NID_setct_PI 523
+#define OBJ_setct_PI OBJ_set_ctype,4L
+
+#define SN_setct_PIData "setct-PIData"
+#define NID_setct_PIData 524
+#define OBJ_setct_PIData OBJ_set_ctype,5L
+
+#define SN_setct_PIDataUnsigned "setct-PIDataUnsigned"
+#define NID_setct_PIDataUnsigned 525
+#define OBJ_setct_PIDataUnsigned OBJ_set_ctype,6L
+
+#define SN_setct_HODInput "setct-HODInput"
+#define NID_setct_HODInput 526
+#define OBJ_setct_HODInput OBJ_set_ctype,7L
+
+#define SN_setct_AuthResBaggage "setct-AuthResBaggage"
+#define NID_setct_AuthResBaggage 527
+#define OBJ_setct_AuthResBaggage OBJ_set_ctype,8L
+
+#define SN_setct_AuthRevReqBaggage "setct-AuthRevReqBaggage"
+#define NID_setct_AuthRevReqBaggage 528
+#define OBJ_setct_AuthRevReqBaggage OBJ_set_ctype,9L
+
+#define SN_setct_AuthRevResBaggage "setct-AuthRevResBaggage"
+#define NID_setct_AuthRevResBaggage 529
+#define OBJ_setct_AuthRevResBaggage OBJ_set_ctype,10L
+
+#define SN_setct_CapTokenSeq "setct-CapTokenSeq"
+#define NID_setct_CapTokenSeq 530
+#define OBJ_setct_CapTokenSeq OBJ_set_ctype,11L
+
+#define SN_setct_PInitResData "setct-PInitResData"
+#define NID_setct_PInitResData 531
+#define OBJ_setct_PInitResData OBJ_set_ctype,12L
+
+#define SN_setct_PI_TBS "setct-PI-TBS"
+#define NID_setct_PI_TBS 532
+#define OBJ_setct_PI_TBS OBJ_set_ctype,13L
+
+#define SN_setct_PResData "setct-PResData"
+#define NID_setct_PResData 533
+#define OBJ_setct_PResData OBJ_set_ctype,14L
+
+#define SN_setct_AuthReqTBS "setct-AuthReqTBS"
+#define NID_setct_AuthReqTBS 534
+#define OBJ_setct_AuthReqTBS OBJ_set_ctype,16L
+
+#define SN_setct_AuthResTBS "setct-AuthResTBS"
+#define NID_setct_AuthResTBS 535
+#define OBJ_setct_AuthResTBS OBJ_set_ctype,17L
+
+#define SN_setct_AuthResTBSX "setct-AuthResTBSX"
+#define NID_setct_AuthResTBSX 536
+#define OBJ_setct_AuthResTBSX OBJ_set_ctype,18L
+
+#define SN_setct_AuthTokenTBS "setct-AuthTokenTBS"
+#define NID_setct_AuthTokenTBS 537
+#define OBJ_setct_AuthTokenTBS OBJ_set_ctype,19L
+
+#define SN_setct_CapTokenData "setct-CapTokenData"
+#define NID_setct_CapTokenData 538
+#define OBJ_setct_CapTokenData OBJ_set_ctype,20L
+
+#define SN_setct_CapTokenTBS "setct-CapTokenTBS"
+#define NID_setct_CapTokenTBS 539
+#define OBJ_setct_CapTokenTBS OBJ_set_ctype,21L
+
+#define SN_setct_AcqCardCodeMsg "setct-AcqCardCodeMsg"
+#define NID_setct_AcqCardCodeMsg 540
+#define OBJ_setct_AcqCardCodeMsg OBJ_set_ctype,22L
+
+#define SN_setct_AuthRevReqTBS "setct-AuthRevReqTBS"
+#define NID_setct_AuthRevReqTBS 541
+#define OBJ_setct_AuthRevReqTBS OBJ_set_ctype,23L
+
+#define SN_setct_AuthRevResData "setct-AuthRevResData"
+#define NID_setct_AuthRevResData 542
+#define OBJ_setct_AuthRevResData OBJ_set_ctype,24L
+
+#define SN_setct_AuthRevResTBS "setct-AuthRevResTBS"
+#define NID_setct_AuthRevResTBS 543
+#define OBJ_setct_AuthRevResTBS OBJ_set_ctype,25L
+
+#define SN_setct_CapReqTBS "setct-CapReqTBS"
+#define NID_setct_CapReqTBS 544
+#define OBJ_setct_CapReqTBS OBJ_set_ctype,26L
+
+#define SN_setct_CapReqTBSX "setct-CapReqTBSX"
+#define NID_setct_CapReqTBSX 545
+#define OBJ_setct_CapReqTBSX OBJ_set_ctype,27L
+
+#define SN_setct_CapResData "setct-CapResData"
+#define NID_setct_CapResData 546
+#define OBJ_setct_CapResData OBJ_set_ctype,28L
+
+#define SN_setct_CapRevReqTBS "setct-CapRevReqTBS"
+#define NID_setct_CapRevReqTBS 547
+#define OBJ_setct_CapRevReqTBS OBJ_set_ctype,29L
+
+#define SN_setct_CapRevReqTBSX "setct-CapRevReqTBSX"
+#define NID_setct_CapRevReqTBSX 548
+#define OBJ_setct_CapRevReqTBSX OBJ_set_ctype,30L
+
+#define SN_setct_CapRevResData "setct-CapRevResData"
+#define NID_setct_CapRevResData 549
+#define OBJ_setct_CapRevResData OBJ_set_ctype,31L
+
+#define SN_setct_CredReqTBS "setct-CredReqTBS"
+#define NID_setct_CredReqTBS 550
+#define OBJ_setct_CredReqTBS OBJ_set_ctype,32L
+
+#define SN_setct_CredReqTBSX "setct-CredReqTBSX"
+#define NID_setct_CredReqTBSX 551
+#define OBJ_setct_CredReqTBSX OBJ_set_ctype,33L
+
+#define SN_setct_CredResData "setct-CredResData"
+#define NID_setct_CredResData 552
+#define OBJ_setct_CredResData OBJ_set_ctype,34L
+
+#define SN_setct_CredRevReqTBS "setct-CredRevReqTBS"
+#define NID_setct_CredRevReqTBS 553
+#define OBJ_setct_CredRevReqTBS OBJ_set_ctype,35L
+
+#define SN_setct_CredRevReqTBSX "setct-CredRevReqTBSX"
+#define NID_setct_CredRevReqTBSX 554
+#define OBJ_setct_CredRevReqTBSX OBJ_set_ctype,36L
+
+#define SN_setct_CredRevResData "setct-CredRevResData"
+#define NID_setct_CredRevResData 555
+#define OBJ_setct_CredRevResData OBJ_set_ctype,37L
+
+#define SN_setct_PCertReqData "setct-PCertReqData"
+#define NID_setct_PCertReqData 556
+#define OBJ_setct_PCertReqData OBJ_set_ctype,38L
+
+#define SN_setct_PCertResTBS "setct-PCertResTBS"
+#define NID_setct_PCertResTBS 557
+#define OBJ_setct_PCertResTBS OBJ_set_ctype,39L
+
+#define SN_setct_BatchAdminReqData "setct-BatchAdminReqData"
+#define NID_setct_BatchAdminReqData 558
+#define OBJ_setct_BatchAdminReqData OBJ_set_ctype,40L
+
+#define SN_setct_BatchAdminResData "setct-BatchAdminResData"
+#define NID_setct_BatchAdminResData 559
+#define OBJ_setct_BatchAdminResData OBJ_set_ctype,41L
+
+#define SN_setct_CardCInitResTBS "setct-CardCInitResTBS"
+#define NID_setct_CardCInitResTBS 560
+#define OBJ_setct_CardCInitResTBS OBJ_set_ctype,42L
+
+#define SN_setct_MeAqCInitResTBS "setct-MeAqCInitResTBS"
+#define NID_setct_MeAqCInitResTBS 561
+#define OBJ_setct_MeAqCInitResTBS OBJ_set_ctype,43L
+
+#define SN_setct_RegFormResTBS "setct-RegFormResTBS"
+#define NID_setct_RegFormResTBS 562
+#define OBJ_setct_RegFormResTBS OBJ_set_ctype,44L
+
+#define SN_setct_CertReqData "setct-CertReqData"
+#define NID_setct_CertReqData 563
+#define OBJ_setct_CertReqData OBJ_set_ctype,45L
+
+#define SN_setct_CertReqTBS "setct-CertReqTBS"
+#define NID_setct_CertReqTBS 564
+#define OBJ_setct_CertReqTBS OBJ_set_ctype,46L
+
+#define SN_setct_CertResData "setct-CertResData"
+#define NID_setct_CertResData 565
+#define OBJ_setct_CertResData OBJ_set_ctype,47L
+
+#define SN_setct_CertInqReqTBS "setct-CertInqReqTBS"
+#define NID_setct_CertInqReqTBS 566
+#define OBJ_setct_CertInqReqTBS OBJ_set_ctype,48L
+
+#define SN_setct_ErrorTBS "setct-ErrorTBS"
+#define NID_setct_ErrorTBS 567
+#define OBJ_setct_ErrorTBS OBJ_set_ctype,49L
+
+#define SN_setct_PIDualSignedTBE "setct-PIDualSignedTBE"
+#define NID_setct_PIDualSignedTBE 568
+#define OBJ_setct_PIDualSignedTBE OBJ_set_ctype,50L
+
+#define SN_setct_PIUnsignedTBE "setct-PIUnsignedTBE"
+#define NID_setct_PIUnsignedTBE 569
+#define OBJ_setct_PIUnsignedTBE OBJ_set_ctype,51L
+
+#define SN_setct_AuthReqTBE "setct-AuthReqTBE"
+#define NID_setct_AuthReqTBE 570
+#define OBJ_setct_AuthReqTBE OBJ_set_ctype,52L
+
+#define SN_setct_AuthResTBE "setct-AuthResTBE"
+#define NID_setct_AuthResTBE 571
+#define OBJ_setct_AuthResTBE OBJ_set_ctype,53L
+
+#define SN_setct_AuthResTBEX "setct-AuthResTBEX"
+#define NID_setct_AuthResTBEX 572
+#define OBJ_setct_AuthResTBEX OBJ_set_ctype,54L
+
+#define SN_setct_AuthTokenTBE "setct-AuthTokenTBE"
+#define NID_setct_AuthTokenTBE 573
+#define OBJ_setct_AuthTokenTBE OBJ_set_ctype,55L
+
+#define SN_setct_CapTokenTBE "setct-CapTokenTBE"
+#define NID_setct_CapTokenTBE 574
+#define OBJ_setct_CapTokenTBE OBJ_set_ctype,56L
+
+#define SN_setct_CapTokenTBEX "setct-CapTokenTBEX"
+#define NID_setct_CapTokenTBEX 575
+#define OBJ_setct_CapTokenTBEX OBJ_set_ctype,57L
+
+#define SN_setct_AcqCardCodeMsgTBE "setct-AcqCardCodeMsgTBE"
+#define NID_setct_AcqCardCodeMsgTBE 576
+#define OBJ_setct_AcqCardCodeMsgTBE OBJ_set_ctype,58L
+
+#define SN_setct_AuthRevReqTBE "setct-AuthRevReqTBE"
+#define NID_setct_AuthRevReqTBE 577
+#define OBJ_setct_AuthRevReqTBE OBJ_set_ctype,59L
+
+#define SN_setct_AuthRevResTBE "setct-AuthRevResTBE"
+#define NID_setct_AuthRevResTBE 578
+#define OBJ_setct_AuthRevResTBE OBJ_set_ctype,60L
+
+#define SN_setct_AuthRevResTBEB "setct-AuthRevResTBEB"
+#define NID_setct_AuthRevResTBEB 579
+#define OBJ_setct_AuthRevResTBEB OBJ_set_ctype,61L
+
+#define SN_setct_CapReqTBE "setct-CapReqTBE"
+#define NID_setct_CapReqTBE 580
+#define OBJ_setct_CapReqTBE OBJ_set_ctype,62L
+
+#define SN_setct_CapReqTBEX "setct-CapReqTBEX"
+#define NID_setct_CapReqTBEX 581
+#define OBJ_setct_CapReqTBEX OBJ_set_ctype,63L
+
+#define SN_setct_CapResTBE "setct-CapResTBE"
+#define NID_setct_CapResTBE 582
+#define OBJ_setct_CapResTBE OBJ_set_ctype,64L
+
+#define SN_setct_CapRevReqTBE "setct-CapRevReqTBE"
+#define NID_setct_CapRevReqTBE 583
+#define OBJ_setct_CapRevReqTBE OBJ_set_ctype,65L
+
+#define SN_setct_CapRevReqTBEX "setct-CapRevReqTBEX"
+#define NID_setct_CapRevReqTBEX 584
+#define OBJ_setct_CapRevReqTBEX OBJ_set_ctype,66L
+
+#define SN_setct_CapRevResTBE "setct-CapRevResTBE"
+#define NID_setct_CapRevResTBE 585
+#define OBJ_setct_CapRevResTBE OBJ_set_ctype,67L
+
+#define SN_setct_CredReqTBE "setct-CredReqTBE"
+#define NID_setct_CredReqTBE 586
+#define OBJ_setct_CredReqTBE OBJ_set_ctype,68L
+
+#define SN_setct_CredReqTBEX "setct-CredReqTBEX"
+#define NID_setct_CredReqTBEX 587
+#define OBJ_setct_CredReqTBEX OBJ_set_ctype,69L
+
+#define SN_setct_CredResTBE "setct-CredResTBE"
+#define NID_setct_CredResTBE 588
+#define OBJ_setct_CredResTBE OBJ_set_ctype,70L
+
+#define SN_setct_CredRevReqTBE "setct-CredRevReqTBE"
+#define NID_setct_CredRevReqTBE 589
+#define OBJ_setct_CredRevReqTBE OBJ_set_ctype,71L
+
+#define SN_setct_CredRevReqTBEX "setct-CredRevReqTBEX"
+#define NID_setct_CredRevReqTBEX 590
+#define OBJ_setct_CredRevReqTBEX OBJ_set_ctype,72L
+
+#define SN_setct_CredRevResTBE "setct-CredRevResTBE"
+#define NID_setct_CredRevResTBE 591
+#define OBJ_setct_CredRevResTBE OBJ_set_ctype,73L
+
+#define SN_setct_BatchAdminReqTBE "setct-BatchAdminReqTBE"
+#define NID_setct_BatchAdminReqTBE 592
+#define OBJ_setct_BatchAdminReqTBE OBJ_set_ctype,74L
+
+#define SN_setct_BatchAdminResTBE "setct-BatchAdminResTBE"
+#define NID_setct_BatchAdminResTBE 593
+#define OBJ_setct_BatchAdminResTBE OBJ_set_ctype,75L
+
+#define SN_setct_RegFormReqTBE "setct-RegFormReqTBE"
+#define NID_setct_RegFormReqTBE 594
+#define OBJ_setct_RegFormReqTBE OBJ_set_ctype,76L
+
+#define SN_setct_CertReqTBE "setct-CertReqTBE"
+#define NID_setct_CertReqTBE 595
+#define OBJ_setct_CertReqTBE OBJ_set_ctype,77L
+
+#define SN_setct_CertReqTBEX "setct-CertReqTBEX"
+#define NID_setct_CertReqTBEX 596
+#define OBJ_setct_CertReqTBEX OBJ_set_ctype,78L
+
+#define SN_setct_CertResTBE "setct-CertResTBE"
+#define NID_setct_CertResTBE 597
+#define OBJ_setct_CertResTBE OBJ_set_ctype,79L
+
+#define SN_setct_CRLNotificationTBS "setct-CRLNotificationTBS"
+#define NID_setct_CRLNotificationTBS 598
+#define OBJ_setct_CRLNotificationTBS OBJ_set_ctype,80L
+
+#define SN_setct_CRLNotificationResTBS "setct-CRLNotificationResTBS"
+#define NID_setct_CRLNotificationResTBS 599
+#define OBJ_setct_CRLNotificationResTBS OBJ_set_ctype,81L
+
+#define SN_setct_BCIDistributionTBS "setct-BCIDistributionTBS"
+#define NID_setct_BCIDistributionTBS 600
+#define OBJ_setct_BCIDistributionTBS OBJ_set_ctype,82L
+
+#define SN_setext_genCrypt "setext-genCrypt"
+#define LN_setext_genCrypt "generic cryptogram"
+#define NID_setext_genCrypt 601
+#define OBJ_setext_genCrypt OBJ_set_msgExt,1L
+
+#define SN_setext_miAuth "setext-miAuth"
+#define LN_setext_miAuth "merchant initiated auth"
+#define NID_setext_miAuth 602
+#define OBJ_setext_miAuth OBJ_set_msgExt,3L
+
+#define SN_setext_pinSecure "setext-pinSecure"
+#define NID_setext_pinSecure 603
+#define OBJ_setext_pinSecure OBJ_set_msgExt,4L
+
+#define SN_setext_pinAny "setext-pinAny"
+#define NID_setext_pinAny 604
+#define OBJ_setext_pinAny OBJ_set_msgExt,5L
+
+#define SN_setext_track2 "setext-track2"
+#define NID_setext_track2 605
+#define OBJ_setext_track2 OBJ_set_msgExt,7L
+
+#define SN_setext_cv "setext-cv"
+#define LN_setext_cv "additional verification"
+#define NID_setext_cv 606
+#define OBJ_setext_cv OBJ_set_msgExt,8L
+
+#define SN_set_policy_root "set-policy-root"
+#define NID_set_policy_root 607
+#define OBJ_set_policy_root OBJ_set_policy,0L
+
+#define SN_setCext_hashedRoot "setCext-hashedRoot"
+#define NID_setCext_hashedRoot 608
+#define OBJ_setCext_hashedRoot OBJ_set_certExt,0L
+
+#define SN_setCext_certType "setCext-certType"
+#define NID_setCext_certType 609
+#define OBJ_setCext_certType OBJ_set_certExt,1L
+
+#define SN_setCext_merchData "setCext-merchData"
+#define NID_setCext_merchData 610
+#define OBJ_setCext_merchData OBJ_set_certExt,2L
+
+#define SN_setCext_cCertRequired "setCext-cCertRequired"
+#define NID_setCext_cCertRequired 611
+#define OBJ_setCext_cCertRequired OBJ_set_certExt,3L
+
+#define SN_setCext_tunneling "setCext-tunneling"
+#define NID_setCext_tunneling 612
+#define OBJ_setCext_tunneling OBJ_set_certExt,4L
+
+#define SN_setCext_setExt "setCext-setExt"
+#define NID_setCext_setExt 613
+#define OBJ_setCext_setExt OBJ_set_certExt,5L
+
+#define SN_setCext_setQualf "setCext-setQualf"
+#define NID_setCext_setQualf 614
+#define OBJ_setCext_setQualf OBJ_set_certExt,6L
+
+#define SN_setCext_PGWYcapabilities "setCext-PGWYcapabilities"
+#define NID_setCext_PGWYcapabilities 615
+#define OBJ_setCext_PGWYcapabilities OBJ_set_certExt,7L
+
+#define SN_setCext_TokenIdentifier "setCext-TokenIdentifier"
+#define NID_setCext_TokenIdentifier 616
+#define OBJ_setCext_TokenIdentifier OBJ_set_certExt,8L
+
+#define SN_setCext_Track2Data "setCext-Track2Data"
+#define NID_setCext_Track2Data 617
+#define OBJ_setCext_Track2Data OBJ_set_certExt,9L
+
+#define SN_setCext_TokenType "setCext-TokenType"
+#define NID_setCext_TokenType 618
+#define OBJ_setCext_TokenType OBJ_set_certExt,10L
+
+#define SN_setCext_IssuerCapabilities "setCext-IssuerCapabilities"
+#define NID_setCext_IssuerCapabilities 619
+#define OBJ_setCext_IssuerCapabilities OBJ_set_certExt,11L
+
+#define SN_setAttr_Cert "setAttr-Cert"
+#define NID_setAttr_Cert 620
+#define OBJ_setAttr_Cert OBJ_set_attr,0L
+
+#define SN_setAttr_PGWYcap "setAttr-PGWYcap"
+#define LN_setAttr_PGWYcap "payment gateway capabilities"
+#define NID_setAttr_PGWYcap 621
+#define OBJ_setAttr_PGWYcap OBJ_set_attr,1L
+
+#define SN_setAttr_TokenType "setAttr-TokenType"
+#define NID_setAttr_TokenType 622
+#define OBJ_setAttr_TokenType OBJ_set_attr,2L
+
+#define SN_setAttr_IssCap "setAttr-IssCap"
+#define LN_setAttr_IssCap "issuer capabilities"
+#define NID_setAttr_IssCap 623
+#define OBJ_setAttr_IssCap OBJ_set_attr,3L
+
+#define SN_set_rootKeyThumb "set-rootKeyThumb"
+#define NID_set_rootKeyThumb 624
+#define OBJ_set_rootKeyThumb OBJ_setAttr_Cert,0L
+
+#define SN_set_addPolicy "set-addPolicy"
+#define NID_set_addPolicy 625
+#define OBJ_set_addPolicy OBJ_setAttr_Cert,1L
+
+#define SN_setAttr_Token_EMV "setAttr-Token-EMV"
+#define NID_setAttr_Token_EMV 626
+#define OBJ_setAttr_Token_EMV OBJ_setAttr_TokenType,1L
+
+#define SN_setAttr_Token_B0Prime "setAttr-Token-B0Prime"
+#define NID_setAttr_Token_B0Prime 627
+#define OBJ_setAttr_Token_B0Prime OBJ_setAttr_TokenType,2L
+
+#define SN_setAttr_IssCap_CVM "setAttr-IssCap-CVM"
+#define NID_setAttr_IssCap_CVM 628
+#define OBJ_setAttr_IssCap_CVM OBJ_setAttr_IssCap,3L
+
+#define SN_setAttr_IssCap_T2 "setAttr-IssCap-T2"
+#define NID_setAttr_IssCap_T2 629
+#define OBJ_setAttr_IssCap_T2 OBJ_setAttr_IssCap,4L
+
+#define SN_setAttr_IssCap_Sig "setAttr-IssCap-Sig"
+#define NID_setAttr_IssCap_Sig 630
+#define OBJ_setAttr_IssCap_Sig OBJ_setAttr_IssCap,5L
+
+#define SN_setAttr_GenCryptgrm "setAttr-GenCryptgrm"
+#define LN_setAttr_GenCryptgrm "generate cryptogram"
+#define NID_setAttr_GenCryptgrm 631
+#define OBJ_setAttr_GenCryptgrm OBJ_setAttr_IssCap_CVM,1L
+
+#define SN_setAttr_T2Enc "setAttr-T2Enc"
+#define LN_setAttr_T2Enc "encrypted track 2"
+#define NID_setAttr_T2Enc 632
+#define OBJ_setAttr_T2Enc OBJ_setAttr_IssCap_T2,1L
+
+#define SN_setAttr_T2cleartxt "setAttr-T2cleartxt"
+#define LN_setAttr_T2cleartxt "cleartext track 2"
+#define NID_setAttr_T2cleartxt 633
+#define OBJ_setAttr_T2cleartxt OBJ_setAttr_IssCap_T2,2L
+
+#define SN_setAttr_TokICCsig "setAttr-TokICCsig"
+#define LN_setAttr_TokICCsig "ICC or token signature"
+#define NID_setAttr_TokICCsig 634
+#define OBJ_setAttr_TokICCsig OBJ_setAttr_IssCap_Sig,1L
+
+#define SN_setAttr_SecDevSig "setAttr-SecDevSig"
+#define LN_setAttr_SecDevSig "secure device signature"
+#define NID_setAttr_SecDevSig 635
+#define OBJ_setAttr_SecDevSig OBJ_setAttr_IssCap_Sig,2L
+
+#define SN_set_brand_IATA_ATA "set-brand-IATA-ATA"
+#define NID_set_brand_IATA_ATA 636
+#define OBJ_set_brand_IATA_ATA OBJ_set_brand,1L
+
+#define SN_set_brand_Diners "set-brand-Diners"
+#define NID_set_brand_Diners 637
+#define OBJ_set_brand_Diners OBJ_set_brand,30L
+
+#define SN_set_brand_AmericanExpress "set-brand-AmericanExpress"
+#define NID_set_brand_AmericanExpress 638
+#define OBJ_set_brand_AmericanExpress OBJ_set_brand,34L
+
+#define SN_set_brand_JCB "set-brand-JCB"
+#define NID_set_brand_JCB 639
+#define OBJ_set_brand_JCB OBJ_set_brand,35L
+
+#define SN_set_brand_Visa "set-brand-Visa"
+#define NID_set_brand_Visa 640
+#define OBJ_set_brand_Visa OBJ_set_brand,4L
+
+#define SN_set_brand_MasterCard "set-brand-MasterCard"
+#define NID_set_brand_MasterCard 641
+#define OBJ_set_brand_MasterCard OBJ_set_brand,5L
+
+#define SN_set_brand_Novus "set-brand-Novus"
+#define NID_set_brand_Novus 642
+#define OBJ_set_brand_Novus OBJ_set_brand,6011L
+
+#define SN_des_cdmf "DES-CDMF"
+#define LN_des_cdmf "des-cdmf"
+#define NID_des_cdmf 643
+#define OBJ_des_cdmf OBJ_rsadsi,3L,10L
+
+#define SN_rsaOAEPEncryptionSET "rsaOAEPEncryptionSET"
+#define NID_rsaOAEPEncryptionSET 644
+#define OBJ_rsaOAEPEncryptionSET OBJ_rsadsi,1L,1L,6L
+
+#define SN_ipsec3 "Oakley-EC2N-3"
+#define LN_ipsec3 "ipsec3"
+#define NID_ipsec3 749
+
+#define SN_ipsec4 "Oakley-EC2N-4"
+#define LN_ipsec4 "ipsec4"
+#define NID_ipsec4 750
+
+#define SN_whirlpool "whirlpool"
+#define NID_whirlpool 804
+#define OBJ_whirlpool OBJ_iso,0L,10118L,3L,0L,55L
+
+#define SN_cryptopro "cryptopro"
+#define NID_cryptopro 805
+#define OBJ_cryptopro OBJ_member_body,643L,2L,2L
+
+#define SN_cryptocom "cryptocom"
+#define NID_cryptocom 806
+#define OBJ_cryptocom OBJ_member_body,643L,2L,9L
+
+#define SN_id_GostR3411_94_with_GostR3410_2001 "id-GostR3411-94-with-GostR3410-2001"
+#define LN_id_GostR3411_94_with_GostR3410_2001 "GOST R 34.11-94 with GOST R 34.10-2001"
+#define NID_id_GostR3411_94_with_GostR3410_2001 807
+#define OBJ_id_GostR3411_94_with_GostR3410_2001 OBJ_cryptopro,3L
+
+#define SN_id_GostR3411_94_with_GostR3410_94 "id-GostR3411-94-with-GostR3410-94"
+#define LN_id_GostR3411_94_with_GostR3410_94 "GOST R 34.11-94 with GOST R 34.10-94"
+#define NID_id_GostR3411_94_with_GostR3410_94 808
+#define OBJ_id_GostR3411_94_with_GostR3410_94 OBJ_cryptopro,4L
+
+#define SN_id_GostR3411_94 "md_gost94"
+#define LN_id_GostR3411_94 "GOST R 34.11-94"
+#define NID_id_GostR3411_94 809
+#define OBJ_id_GostR3411_94 OBJ_cryptopro,9L
+
+#define SN_id_HMACGostR3411_94 "id-HMACGostR3411-94"
+#define LN_id_HMACGostR3411_94 "HMAC GOST 34.11-94"
+#define NID_id_HMACGostR3411_94 810
+#define OBJ_id_HMACGostR3411_94 OBJ_cryptopro,10L
+
+#define SN_id_GostR3410_2001 "gost2001"
+#define LN_id_GostR3410_2001 "GOST R 34.10-2001"
+#define NID_id_GostR3410_2001 811
+#define OBJ_id_GostR3410_2001 OBJ_cryptopro,19L
+
+#define SN_id_GostR3410_94 "gost94"
+#define LN_id_GostR3410_94 "GOST R 34.10-94"
+#define NID_id_GostR3410_94 812
+#define OBJ_id_GostR3410_94 OBJ_cryptopro,20L
+
+#define SN_id_Gost28147_89 "gost89"
+#define LN_id_Gost28147_89 "GOST 28147-89"
+#define NID_id_Gost28147_89 813
+#define OBJ_id_Gost28147_89 OBJ_cryptopro,21L
+
+#define SN_gost89_cnt "gost89-cnt"
+#define NID_gost89_cnt 814
+
+#define SN_id_Gost28147_89_MAC "gost-mac"
+#define LN_id_Gost28147_89_MAC "GOST 28147-89 MAC"
+#define NID_id_Gost28147_89_MAC 815
+#define OBJ_id_Gost28147_89_MAC OBJ_cryptopro,22L
+
+#define SN_id_GostR3411_94_prf "prf-gostr3411-94"
+#define LN_id_GostR3411_94_prf "GOST R 34.11-94 PRF"
+#define NID_id_GostR3411_94_prf 816
+#define OBJ_id_GostR3411_94_prf OBJ_cryptopro,23L
+
+#define SN_id_GostR3410_2001DH "id-GostR3410-2001DH"
+#define LN_id_GostR3410_2001DH "GOST R 34.10-2001 DH"
+#define NID_id_GostR3410_2001DH 817
+#define OBJ_id_GostR3410_2001DH OBJ_cryptopro,98L
+
+#define SN_id_GostR3410_94DH "id-GostR3410-94DH"
+#define LN_id_GostR3410_94DH "GOST R 34.10-94 DH"
+#define NID_id_GostR3410_94DH 818
+#define OBJ_id_GostR3410_94DH OBJ_cryptopro,99L
+
+#define SN_id_Gost28147_89_CryptoPro_KeyMeshing "id-Gost28147-89-CryptoPro-KeyMeshing"
+#define NID_id_Gost28147_89_CryptoPro_KeyMeshing 819
+#define OBJ_id_Gost28147_89_CryptoPro_KeyMeshing OBJ_cryptopro,14L,1L
+
+#define SN_id_Gost28147_89_None_KeyMeshing "id-Gost28147-89-None-KeyMeshing"
+#define NID_id_Gost28147_89_None_KeyMeshing 820
+#define OBJ_id_Gost28147_89_None_KeyMeshing OBJ_cryptopro,14L,0L
+
+#define SN_id_GostR3411_94_TestParamSet "id-GostR3411-94-TestParamSet"
+#define NID_id_GostR3411_94_TestParamSet 821
+#define OBJ_id_GostR3411_94_TestParamSet OBJ_cryptopro,30L,0L
+
+#define SN_id_GostR3411_94_CryptoProParamSet "id-GostR3411-94-CryptoProParamSet"
+#define NID_id_GostR3411_94_CryptoProParamSet 822
+#define OBJ_id_GostR3411_94_CryptoProParamSet OBJ_cryptopro,30L,1L
+
+#define SN_id_Gost28147_89_TestParamSet "id-Gost28147-89-TestParamSet"
+#define NID_id_Gost28147_89_TestParamSet 823
+#define OBJ_id_Gost28147_89_TestParamSet OBJ_cryptopro,31L,0L
+
+#define SN_id_Gost28147_89_CryptoPro_A_ParamSet "id-Gost28147-89-CryptoPro-A-ParamSet"
+#define NID_id_Gost28147_89_CryptoPro_A_ParamSet 824
+#define OBJ_id_Gost28147_89_CryptoPro_A_ParamSet OBJ_cryptopro,31L,1L
+
+#define SN_id_Gost28147_89_CryptoPro_B_ParamSet "id-Gost28147-89-CryptoPro-B-ParamSet"
+#define NID_id_Gost28147_89_CryptoPro_B_ParamSet 825
+#define OBJ_id_Gost28147_89_CryptoPro_B_ParamSet OBJ_cryptopro,31L,2L
+
+#define SN_id_Gost28147_89_CryptoPro_C_ParamSet "id-Gost28147-89-CryptoPro-C-ParamSet"
+#define NID_id_Gost28147_89_CryptoPro_C_ParamSet 826
+#define OBJ_id_Gost28147_89_CryptoPro_C_ParamSet OBJ_cryptopro,31L,3L
+
+#define SN_id_Gost28147_89_CryptoPro_D_ParamSet "id-Gost28147-89-CryptoPro-D-ParamSet"
+#define NID_id_Gost28147_89_CryptoPro_D_ParamSet 827
+#define OBJ_id_Gost28147_89_CryptoPro_D_ParamSet OBJ_cryptopro,31L,4L
+
+#define SN_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet "id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet"
+#define NID_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet 828
+#define OBJ_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet OBJ_cryptopro,31L,5L
+
+#define SN_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet "id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet"
+#define NID_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet 829
+#define OBJ_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet OBJ_cryptopro,31L,6L
+
+#define SN_id_Gost28147_89_CryptoPro_RIC_1_ParamSet "id-Gost28147-89-CryptoPro-RIC-1-ParamSet"
+#define NID_id_Gost28147_89_CryptoPro_RIC_1_ParamSet 830
+#define OBJ_id_Gost28147_89_CryptoPro_RIC_1_ParamSet OBJ_cryptopro,31L,7L
+
+#define SN_id_GostR3410_94_TestParamSet "id-GostR3410-94-TestParamSet"
+#define NID_id_GostR3410_94_TestParamSet 831
+#define OBJ_id_GostR3410_94_TestParamSet OBJ_cryptopro,32L,0L
+
+#define SN_id_GostR3410_94_CryptoPro_A_ParamSet "id-GostR3410-94-CryptoPro-A-ParamSet"
+#define NID_id_GostR3410_94_CryptoPro_A_ParamSet 832
+#define OBJ_id_GostR3410_94_CryptoPro_A_ParamSet OBJ_cryptopro,32L,2L
+
+#define SN_id_GostR3410_94_CryptoPro_B_ParamSet "id-GostR3410-94-CryptoPro-B-ParamSet"
+#define NID_id_GostR3410_94_CryptoPro_B_ParamSet 833
+#define OBJ_id_GostR3410_94_CryptoPro_B_ParamSet OBJ_cryptopro,32L,3L
+
+#define SN_id_GostR3410_94_CryptoPro_C_ParamSet "id-GostR3410-94-CryptoPro-C-ParamSet"
+#define NID_id_GostR3410_94_CryptoPro_C_ParamSet 834
+#define OBJ_id_GostR3410_94_CryptoPro_C_ParamSet OBJ_cryptopro,32L,4L
+
+#define SN_id_GostR3410_94_CryptoPro_D_ParamSet "id-GostR3410-94-CryptoPro-D-ParamSet"
+#define NID_id_GostR3410_94_CryptoPro_D_ParamSet 835
+#define OBJ_id_GostR3410_94_CryptoPro_D_ParamSet OBJ_cryptopro,32L,5L
+
+#define SN_id_GostR3410_94_CryptoPro_XchA_ParamSet "id-GostR3410-94-CryptoPro-XchA-ParamSet"
+#define NID_id_GostR3410_94_CryptoPro_XchA_ParamSet 836
+#define OBJ_id_GostR3410_94_CryptoPro_XchA_ParamSet OBJ_cryptopro,33L,1L
+
+#define SN_id_GostR3410_94_CryptoPro_XchB_ParamSet "id-GostR3410-94-CryptoPro-XchB-ParamSet"
+#define NID_id_GostR3410_94_CryptoPro_XchB_ParamSet 837
+#define OBJ_id_GostR3410_94_CryptoPro_XchB_ParamSet OBJ_cryptopro,33L,2L
+
+#define SN_id_GostR3410_94_CryptoPro_XchC_ParamSet "id-GostR3410-94-CryptoPro-XchC-ParamSet"
+#define NID_id_GostR3410_94_CryptoPro_XchC_ParamSet 838
+#define OBJ_id_GostR3410_94_CryptoPro_XchC_ParamSet OBJ_cryptopro,33L,3L
+
+#define SN_id_GostR3410_2001_TestParamSet "id-GostR3410-2001-TestParamSet"
+#define NID_id_GostR3410_2001_TestParamSet 839
+#define OBJ_id_GostR3410_2001_TestParamSet OBJ_cryptopro,35L,0L
+
+#define SN_id_GostR3410_2001_CryptoPro_A_ParamSet "id-GostR3410-2001-CryptoPro-A-ParamSet"
+#define NID_id_GostR3410_2001_CryptoPro_A_ParamSet 840
+#define OBJ_id_GostR3410_2001_CryptoPro_A_ParamSet OBJ_cryptopro,35L,1L
+
+#define SN_id_GostR3410_2001_CryptoPro_B_ParamSet "id-GostR3410-2001-CryptoPro-B-ParamSet"
+#define NID_id_GostR3410_2001_CryptoPro_B_ParamSet 841
+#define OBJ_id_GostR3410_2001_CryptoPro_B_ParamSet OBJ_cryptopro,35L,2L
+
+#define SN_id_GostR3410_2001_CryptoPro_C_ParamSet "id-GostR3410-2001-CryptoPro-C-ParamSet"
+#define NID_id_GostR3410_2001_CryptoPro_C_ParamSet 842
+#define OBJ_id_GostR3410_2001_CryptoPro_C_ParamSet OBJ_cryptopro,35L,3L
+
+#define SN_id_GostR3410_2001_CryptoPro_XchA_ParamSet "id-GostR3410-2001-CryptoPro-XchA-ParamSet"
+#define NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet 843
+#define OBJ_id_GostR3410_2001_CryptoPro_XchA_ParamSet OBJ_cryptopro,36L,0L
+
+#define SN_id_GostR3410_2001_CryptoPro_XchB_ParamSet "id-GostR3410-2001-CryptoPro-XchB-ParamSet"
+#define NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet 844
+#define OBJ_id_GostR3410_2001_CryptoPro_XchB_ParamSet OBJ_cryptopro,36L,1L
+
+#define SN_id_GostR3410_94_a "id-GostR3410-94-a"
+#define NID_id_GostR3410_94_a 845
+#define OBJ_id_GostR3410_94_a OBJ_id_GostR3410_94,1L
+
+#define SN_id_GostR3410_94_aBis "id-GostR3410-94-aBis"
+#define NID_id_GostR3410_94_aBis 846
+#define OBJ_id_GostR3410_94_aBis OBJ_id_GostR3410_94,2L
+
+#define SN_id_GostR3410_94_b "id-GostR3410-94-b"
+#define NID_id_GostR3410_94_b 847
+#define OBJ_id_GostR3410_94_b OBJ_id_GostR3410_94,3L
+
+#define SN_id_GostR3410_94_bBis "id-GostR3410-94-bBis"
+#define NID_id_GostR3410_94_bBis 848
+#define OBJ_id_GostR3410_94_bBis OBJ_id_GostR3410_94,4L
+
+#define SN_id_Gost28147_89_cc "id-Gost28147-89-cc"
+#define LN_id_Gost28147_89_cc "GOST 28147-89 Cryptocom ParamSet"
+#define NID_id_Gost28147_89_cc 849
+#define OBJ_id_Gost28147_89_cc OBJ_cryptocom,1L,6L,1L
+
+#define SN_id_GostR3410_94_cc "gost94cc"
+#define LN_id_GostR3410_94_cc "GOST 34.10-94 Cryptocom"
+#define NID_id_GostR3410_94_cc 850
+#define OBJ_id_GostR3410_94_cc OBJ_cryptocom,1L,5L,3L
+
+#define SN_id_GostR3410_2001_cc "gost2001cc"
+#define LN_id_GostR3410_2001_cc "GOST 34.10-2001 Cryptocom"
+#define NID_id_GostR3410_2001_cc 851
+#define OBJ_id_GostR3410_2001_cc OBJ_cryptocom,1L,5L,4L
+
+#define SN_id_GostR3411_94_with_GostR3410_94_cc "id-GostR3411-94-with-GostR3410-94-cc"
+#define LN_id_GostR3411_94_with_GostR3410_94_cc "GOST R 34.11-94 with GOST R 34.10-94 Cryptocom"
+#define NID_id_GostR3411_94_with_GostR3410_94_cc 852
+#define OBJ_id_GostR3411_94_with_GostR3410_94_cc OBJ_cryptocom,1L,3L,3L
+
+#define SN_id_GostR3411_94_with_GostR3410_2001_cc "id-GostR3411-94-with-GostR3410-2001-cc"
+#define LN_id_GostR3411_94_with_GostR3410_2001_cc "GOST R 34.11-94 with GOST R 34.10-2001 Cryptocom"
+#define NID_id_GostR3411_94_with_GostR3410_2001_cc 853
+#define OBJ_id_GostR3411_94_with_GostR3410_2001_cc OBJ_cryptocom,1L,3L,4L
+
+#define SN_id_GostR3410_2001_ParamSet_cc "id-GostR3410-2001-ParamSet-cc"
+#define LN_id_GostR3410_2001_ParamSet_cc "GOST R 3410-2001 Parameter Set Cryptocom"
+#define NID_id_GostR3410_2001_ParamSet_cc 854
+#define OBJ_id_GostR3410_2001_ParamSet_cc OBJ_cryptocom,1L,8L,1L
+
+#define SN_camellia_128_cbc "CAMELLIA-128-CBC"
+#define LN_camellia_128_cbc "camellia-128-cbc"
+#define NID_camellia_128_cbc 751
+#define OBJ_camellia_128_cbc 1L,2L,392L,200011L,61L,1L,1L,1L,2L
+
+#define SN_camellia_192_cbc "CAMELLIA-192-CBC"
+#define LN_camellia_192_cbc "camellia-192-cbc"
+#define NID_camellia_192_cbc 752
+#define OBJ_camellia_192_cbc 1L,2L,392L,200011L,61L,1L,1L,1L,3L
+
+#define SN_camellia_256_cbc "CAMELLIA-256-CBC"
+#define LN_camellia_256_cbc "camellia-256-cbc"
+#define NID_camellia_256_cbc 753
+#define OBJ_camellia_256_cbc 1L,2L,392L,200011L,61L,1L,1L,1L,4L
+
+#define SN_id_camellia128_wrap "id-camellia128-wrap"
+#define NID_id_camellia128_wrap 907
+#define OBJ_id_camellia128_wrap 1L,2L,392L,200011L,61L,1L,1L,3L,2L
+
+#define SN_id_camellia192_wrap "id-camellia192-wrap"
+#define NID_id_camellia192_wrap 908
+#define OBJ_id_camellia192_wrap 1L,2L,392L,200011L,61L,1L,1L,3L,3L
+
+#define SN_id_camellia256_wrap "id-camellia256-wrap"
+#define NID_id_camellia256_wrap 909
+#define OBJ_id_camellia256_wrap 1L,2L,392L,200011L,61L,1L,1L,3L,4L
+
+#define OBJ_ntt_ds 0L,3L,4401L,5L
+
+#define OBJ_camellia OBJ_ntt_ds,3L,1L,9L
+
+#define SN_camellia_128_ecb "CAMELLIA-128-ECB"
+#define LN_camellia_128_ecb "camellia-128-ecb"
+#define NID_camellia_128_ecb 754
+#define OBJ_camellia_128_ecb OBJ_camellia,1L
+
+#define SN_camellia_128_ofb128 "CAMELLIA-128-OFB"
+#define LN_camellia_128_ofb128 "camellia-128-ofb"
+#define NID_camellia_128_ofb128 766
+#define OBJ_camellia_128_ofb128 OBJ_camellia,3L
+
+#define SN_camellia_128_cfb128 "CAMELLIA-128-CFB"
+#define LN_camellia_128_cfb128 "camellia-128-cfb"
+#define NID_camellia_128_cfb128 757
+#define OBJ_camellia_128_cfb128 OBJ_camellia,4L
+
+#define SN_camellia_192_ecb "CAMELLIA-192-ECB"
+#define LN_camellia_192_ecb "camellia-192-ecb"
+#define NID_camellia_192_ecb 755
+#define OBJ_camellia_192_ecb OBJ_camellia,21L
+
+#define SN_camellia_192_ofb128 "CAMELLIA-192-OFB"
+#define LN_camellia_192_ofb128 "camellia-192-ofb"
+#define NID_camellia_192_ofb128 767
+#define OBJ_camellia_192_ofb128 OBJ_camellia,23L
+
+#define SN_camellia_192_cfb128 "CAMELLIA-192-CFB"
+#define LN_camellia_192_cfb128 "camellia-192-cfb"
+#define NID_camellia_192_cfb128 758
+#define OBJ_camellia_192_cfb128 OBJ_camellia,24L
+
+#define SN_camellia_256_ecb "CAMELLIA-256-ECB"
+#define LN_camellia_256_ecb "camellia-256-ecb"
+#define NID_camellia_256_ecb 756
+#define OBJ_camellia_256_ecb OBJ_camellia,41L
+
+#define SN_camellia_256_ofb128 "CAMELLIA-256-OFB"
+#define LN_camellia_256_ofb128 "camellia-256-ofb"
+#define NID_camellia_256_ofb128 768
+#define OBJ_camellia_256_ofb128 OBJ_camellia,43L
+
+#define SN_camellia_256_cfb128 "CAMELLIA-256-CFB"
+#define LN_camellia_256_cfb128 "camellia-256-cfb"
+#define NID_camellia_256_cfb128 759
+#define OBJ_camellia_256_cfb128 OBJ_camellia,44L
+
+#define SN_camellia_128_cfb1 "CAMELLIA-128-CFB1"
+#define LN_camellia_128_cfb1 "camellia-128-cfb1"
+#define NID_camellia_128_cfb1 760
+
+#define SN_camellia_192_cfb1 "CAMELLIA-192-CFB1"
+#define LN_camellia_192_cfb1 "camellia-192-cfb1"
+#define NID_camellia_192_cfb1 761
+
+#define SN_camellia_256_cfb1 "CAMELLIA-256-CFB1"
+#define LN_camellia_256_cfb1 "camellia-256-cfb1"
+#define NID_camellia_256_cfb1 762
+
+#define SN_camellia_128_cfb8 "CAMELLIA-128-CFB8"
+#define LN_camellia_128_cfb8 "camellia-128-cfb8"
+#define NID_camellia_128_cfb8 763
+
+#define SN_camellia_192_cfb8 "CAMELLIA-192-CFB8"
+#define LN_camellia_192_cfb8 "camellia-192-cfb8"
+#define NID_camellia_192_cfb8 764
+
+#define SN_camellia_256_cfb8 "CAMELLIA-256-CFB8"
+#define LN_camellia_256_cfb8 "camellia-256-cfb8"
+#define NID_camellia_256_cfb8 765
+
+#define SN_kisa "KISA"
+#define LN_kisa "kisa"
+#define NID_kisa 773
+#define OBJ_kisa OBJ_member_body,410L,200004L
+
+#define SN_seed_ecb "SEED-ECB"
+#define LN_seed_ecb "seed-ecb"
+#define NID_seed_ecb 776
+#define OBJ_seed_ecb OBJ_kisa,1L,3L
+
+#define SN_seed_cbc "SEED-CBC"
+#define LN_seed_cbc "seed-cbc"
+#define NID_seed_cbc 777
+#define OBJ_seed_cbc OBJ_kisa,1L,4L
+
+#define SN_seed_cfb128 "SEED-CFB"
+#define LN_seed_cfb128 "seed-cfb"
+#define NID_seed_cfb128 779
+#define OBJ_seed_cfb128 OBJ_kisa,1L,5L
+
+#define SN_seed_ofb128 "SEED-OFB"
+#define LN_seed_ofb128 "seed-ofb"
+#define NID_seed_ofb128 778
+#define OBJ_seed_ofb128 OBJ_kisa,1L,6L
+
+#define SN_hmac "HMAC"
+#define LN_hmac "hmac"
+#define NID_hmac 855
+
+#define SN_cmac "CMAC"
+#define LN_cmac "cmac"
+#define NID_cmac 894
+
+#define SN_rc4_hmac_md5 "RC4-HMAC-MD5"
+#define LN_rc4_hmac_md5 "rc4-hmac-md5"
+#define NID_rc4_hmac_md5 915
+
+#define SN_aes_128_cbc_hmac_sha1 "AES-128-CBC-HMAC-SHA1"
+#define LN_aes_128_cbc_hmac_sha1 "aes-128-cbc-hmac-sha1"
+#define NID_aes_128_cbc_hmac_sha1 916
+
+#define SN_aes_192_cbc_hmac_sha1 "AES-192-CBC-HMAC-SHA1"
+#define LN_aes_192_cbc_hmac_sha1 "aes-192-cbc-hmac-sha1"
+#define NID_aes_192_cbc_hmac_sha1 917
+
+#define SN_aes_256_cbc_hmac_sha1 "AES-256-CBC-HMAC-SHA1"
+#define LN_aes_256_cbc_hmac_sha1 "aes-256-cbc-hmac-sha1"
+#define NID_aes_256_cbc_hmac_sha1 918
+
+#define SN_dhpublicnumber "dhpublicnumber"
+#define LN_dhpublicnumber "X9.42 DH"
+#define NID_dhpublicnumber 920
+#define OBJ_dhpublicnumber OBJ_ISO_US,10046L,2L,1L
+
+#define SN_brainpoolP160r1 "brainpoolP160r1"
+#define NID_brainpoolP160r1 921
+#define OBJ_brainpoolP160r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,1L
+
+#define SN_brainpoolP160t1 "brainpoolP160t1"
+#define NID_brainpoolP160t1 922
+#define OBJ_brainpoolP160t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,2L
+
+#define SN_brainpoolP192r1 "brainpoolP192r1"
+#define NID_brainpoolP192r1 923
+#define OBJ_brainpoolP192r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,3L
+
+#define SN_brainpoolP192t1 "brainpoolP192t1"
+#define NID_brainpoolP192t1 924
+#define OBJ_brainpoolP192t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,4L
+
+#define SN_brainpoolP224r1 "brainpoolP224r1"
+#define NID_brainpoolP224r1 925
+#define OBJ_brainpoolP224r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,5L
+
+#define SN_brainpoolP224t1 "brainpoolP224t1"
+#define NID_brainpoolP224t1 926
+#define OBJ_brainpoolP224t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,6L
+
+#define SN_brainpoolP256r1 "brainpoolP256r1"
+#define NID_brainpoolP256r1 927
+#define OBJ_brainpoolP256r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,7L
+
+#define SN_brainpoolP256t1 "brainpoolP256t1"
+#define NID_brainpoolP256t1 928
+#define OBJ_brainpoolP256t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,8L
+
+#define SN_brainpoolP320r1 "brainpoolP320r1"
+#define NID_brainpoolP320r1 929
+#define OBJ_brainpoolP320r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,9L
+
+#define SN_brainpoolP320t1 "brainpoolP320t1"
+#define NID_brainpoolP320t1 930
+#define OBJ_brainpoolP320t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,10L
+
+#define SN_brainpoolP384r1 "brainpoolP384r1"
+#define NID_brainpoolP384r1 931
+#define OBJ_brainpoolP384r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,11L
+
+#define SN_brainpoolP384t1 "brainpoolP384t1"
+#define NID_brainpoolP384t1 932
+#define OBJ_brainpoolP384t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,12L
+
+#define SN_brainpoolP512r1 "brainpoolP512r1"
+#define NID_brainpoolP512r1 933
+#define OBJ_brainpoolP512r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,13L
+
+#define SN_brainpoolP512t1 "brainpoolP512t1"
+#define NID_brainpoolP512t1 934
+#define OBJ_brainpoolP512t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,14L
+
+#define OBJ_x9_63_scheme 1L,3L,133L,16L,840L,63L,0L
+
+#define OBJ_secg_scheme OBJ_certicom_arc,1L
+
+#define SN_dhSinglePass_stdDH_sha1kdf_scheme "dhSinglePass-stdDH-sha1kdf-scheme"
+#define NID_dhSinglePass_stdDH_sha1kdf_scheme 939
+#define OBJ_dhSinglePass_stdDH_sha1kdf_scheme OBJ_x9_63_scheme,2L
+
+#define SN_dhSinglePass_stdDH_sha224kdf_scheme "dhSinglePass-stdDH-sha224kdf-scheme"
+#define NID_dhSinglePass_stdDH_sha224kdf_scheme 940
+#define OBJ_dhSinglePass_stdDH_sha224kdf_scheme OBJ_secg_scheme,11L,0L
+
+#define SN_dhSinglePass_stdDH_sha256kdf_scheme "dhSinglePass-stdDH-sha256kdf-scheme"
+#define NID_dhSinglePass_stdDH_sha256kdf_scheme 941
+#define OBJ_dhSinglePass_stdDH_sha256kdf_scheme OBJ_secg_scheme,11L,1L
+
+#define SN_dhSinglePass_stdDH_sha384kdf_scheme "dhSinglePass-stdDH-sha384kdf-scheme"
+#define NID_dhSinglePass_stdDH_sha384kdf_scheme 942
+#define OBJ_dhSinglePass_stdDH_sha384kdf_scheme OBJ_secg_scheme,11L,2L
+
+#define SN_dhSinglePass_stdDH_sha512kdf_scheme "dhSinglePass-stdDH-sha512kdf-scheme"
+#define NID_dhSinglePass_stdDH_sha512kdf_scheme 943
+#define OBJ_dhSinglePass_stdDH_sha512kdf_scheme OBJ_secg_scheme,11L,3L
+
+#define SN_dhSinglePass_cofactorDH_sha1kdf_scheme "dhSinglePass-cofactorDH-sha1kdf-scheme"
+#define NID_dhSinglePass_cofactorDH_sha1kdf_scheme 944
+#define OBJ_dhSinglePass_cofactorDH_sha1kdf_scheme OBJ_x9_63_scheme,3L
+
+#define SN_dhSinglePass_cofactorDH_sha224kdf_scheme "dhSinglePass-cofactorDH-sha224kdf-scheme"
+#define NID_dhSinglePass_cofactorDH_sha224kdf_scheme 945
+#define OBJ_dhSinglePass_cofactorDH_sha224kdf_scheme OBJ_secg_scheme,14L,0L
+
+#define SN_dhSinglePass_cofactorDH_sha256kdf_scheme "dhSinglePass-cofactorDH-sha256kdf-scheme"
+#define NID_dhSinglePass_cofactorDH_sha256kdf_scheme 946
+#define OBJ_dhSinglePass_cofactorDH_sha256kdf_scheme OBJ_secg_scheme,14L,1L
+
+#define SN_dhSinglePass_cofactorDH_sha384kdf_scheme "dhSinglePass-cofactorDH-sha384kdf-scheme"
+#define NID_dhSinglePass_cofactorDH_sha384kdf_scheme 947
+#define OBJ_dhSinglePass_cofactorDH_sha384kdf_scheme OBJ_secg_scheme,14L,2L
+
+#define SN_dhSinglePass_cofactorDH_sha512kdf_scheme "dhSinglePass-cofactorDH-sha512kdf-scheme"
+#define NID_dhSinglePass_cofactorDH_sha512kdf_scheme 948
+#define OBJ_dhSinglePass_cofactorDH_sha512kdf_scheme OBJ_secg_scheme,14L,3L
+
+#define SN_dh_std_kdf "dh-std-kdf"
+#define NID_dh_std_kdf 949
+
+#define SN_dh_cofactor_kdf "dh-cofactor-kdf"
+#define NID_dh_cofactor_kdf 950
+
diff --git a/crypto/obj/obj_mac.num b/crypto/obj/obj_mac.num
new file mode 100644
index 0000000..dbca56a
--- /dev/null
+++ b/crypto/obj/obj_mac.num
@@ -0,0 +1,938 @@
+itu_t 1
+iso 2
+joint_iso_itu_t 3
+member_body 4
+identified_organization 5
+hmac_md5 6
+hmac_sha1 7
+certicom_arc 8
+international_organizations 9
+wap 10
+wap_wsg 11
+selected_attribute_types 12
+clearance 13
+ISO_US 14
+X9_57 15
+X9cm 16
+dsa 17
+dsaWithSHA1 18
+ansi_X9_62 19
+X9_62_prime_field 20
+X9_62_characteristic_two_field 21
+X9_62_id_characteristic_two_basis 22
+X9_62_onBasis 23
+X9_62_tpBasis 24
+X9_62_ppBasis 25
+X9_62_id_ecPublicKey 26
+X9_62_c2pnb163v1 27
+X9_62_c2pnb163v2 28
+X9_62_c2pnb163v3 29
+X9_62_c2pnb176v1 30
+X9_62_c2tnb191v1 31
+X9_62_c2tnb191v2 32
+X9_62_c2tnb191v3 33
+X9_62_c2onb191v4 34
+X9_62_c2onb191v5 35
+X9_62_c2pnb208w1 36
+X9_62_c2tnb239v1 37
+X9_62_c2tnb239v2 38
+X9_62_c2tnb239v3 39
+X9_62_c2onb239v4 40
+X9_62_c2onb239v5 41
+X9_62_c2pnb272w1 42
+X9_62_c2pnb304w1 43
+X9_62_c2tnb359v1 44
+X9_62_c2pnb368w1 45
+X9_62_c2tnb431r1 46
+X9_62_prime192v1 47
+X9_62_prime192v2 48
+X9_62_prime192v3 49
+X9_62_prime239v1 50
+X9_62_prime239v2 51
+X9_62_prime239v3 52
+X9_62_prime256v1 53
+ecdsa_with_SHA1 54
+ecdsa_with_Recommended 55
+ecdsa_with_Specified 56
+ecdsa_with_SHA224 57
+ecdsa_with_SHA256 58
+ecdsa_with_SHA384 59
+ecdsa_with_SHA512 60
+secp112r1 61
+secp112r2 62
+secp128r1 63
+secp128r2 64
+secp160k1 65
+secp160r1 66
+secp160r2 67
+secp192k1 68
+secp224k1 69
+secp224r1 70
+secp256k1 71
+secp384r1 72
+secp521r1 73
+sect113r1 74
+sect113r2 75
+sect131r1 76
+sect131r2 77
+sect163k1 78
+sect163r1 79
+sect163r2 80
+sect193r1 81
+sect193r2 82
+sect233k1 83
+sect233r1 84
+sect239k1 85
+sect283k1 86
+sect283r1 87
+sect409k1 88
+sect409r1 89
+sect571k1 90
+sect571r1 91
+wap_wsg_idm_ecid_wtls1 92
+wap_wsg_idm_ecid_wtls3 93
+wap_wsg_idm_ecid_wtls4 94
+wap_wsg_idm_ecid_wtls5 95
+wap_wsg_idm_ecid_wtls6 96
+wap_wsg_idm_ecid_wtls7 97
+wap_wsg_idm_ecid_wtls8 98
+wap_wsg_idm_ecid_wtls9 99
+wap_wsg_idm_ecid_wtls10 100
+wap_wsg_idm_ecid_wtls11 101
+wap_wsg_idm_ecid_wtls12 102
+cast5_cbc 103
+cast5_ecb 104
+cast5_cfb64 105
+cast5_ofb64 106
+pbeWithMD5AndCast5_CBC 107
+id_PasswordBasedMAC 108
+id_DHBasedMac 109
+rsadsi 110
+pkcs 111
+pkcs1 112
+rsaEncryption 113
+md2WithRSAEncryption 114
+md4WithRSAEncryption 115
+md5WithRSAEncryption 116
+sha1WithRSAEncryption 117
+rsaesOaep 118
+mgf1 119
+pSpecified 120
+rsassaPss 121
+sha256WithRSAEncryption 122
+sha384WithRSAEncryption 123
+sha512WithRSAEncryption 124
+sha224WithRSAEncryption 125
+pkcs3 126
+dhKeyAgreement 127
+pkcs5 128
+pbeWithMD2AndDES_CBC 129
+pbeWithMD5AndDES_CBC 130
+pbeWithMD2AndRC2_CBC 131
+pbeWithMD5AndRC2_CBC 132
+pbeWithSHA1AndDES_CBC 133
+pbeWithSHA1AndRC2_CBC 134
+id_pbkdf2 135
+pbes2 136
+pbmac1 137
+pkcs7 138
+pkcs7_data 139
+pkcs7_signed 140
+pkcs7_enveloped 141
+pkcs7_signedAndEnveloped 142
+pkcs7_digest 143
+pkcs7_encrypted 144
+pkcs9 145
+pkcs9_emailAddress 146
+pkcs9_unstructuredName 147
+pkcs9_contentType 148
+pkcs9_messageDigest 149
+pkcs9_signingTime 150
+pkcs9_countersignature 151
+pkcs9_challengePassword 152
+pkcs9_unstructuredAddress 153
+pkcs9_extCertAttributes 154
+ext_req 155
+SMIMECapabilities 156
+SMIME 157
+id_smime_mod 158
+id_smime_ct 159
+id_smime_aa 160
+id_smime_alg 161
+id_smime_cd 162
+id_smime_spq 163
+id_smime_cti 164
+id_smime_mod_cms 165
+id_smime_mod_ess 166
+id_smime_mod_oid 167
+id_smime_mod_msg_v3 168
+id_smime_mod_ets_eSignature_88 169
+id_smime_mod_ets_eSignature_97 170
+id_smime_mod_ets_eSigPolicy_88 171
+id_smime_mod_ets_eSigPolicy_97 172
+id_smime_ct_receipt 173
+id_smime_ct_authData 174
+id_smime_ct_publishCert 175
+id_smime_ct_TSTInfo 176
+id_smime_ct_TDTInfo 177
+id_smime_ct_contentInfo 178
+id_smime_ct_DVCSRequestData 179
+id_smime_ct_DVCSResponseData 180
+id_smime_ct_compressedData 181
+id_ct_asciiTextWithCRLF 182
+id_smime_aa_receiptRequest 183
+id_smime_aa_securityLabel 184
+id_smime_aa_mlExpandHistory 185
+id_smime_aa_contentHint 186
+id_smime_aa_msgSigDigest 187
+id_smime_aa_encapContentType 188
+id_smime_aa_contentIdentifier 189
+id_smime_aa_macValue 190
+id_smime_aa_equivalentLabels 191
+id_smime_aa_contentReference 192
+id_smime_aa_encrypKeyPref 193
+id_smime_aa_signingCertificate 194
+id_smime_aa_smimeEncryptCerts 195
+id_smime_aa_timeStampToken 196
+id_smime_aa_ets_sigPolicyId 197
+id_smime_aa_ets_commitmentType 198
+id_smime_aa_ets_signerLocation 199
+id_smime_aa_ets_signerAttr 200
+id_smime_aa_ets_otherSigCert 201
+id_smime_aa_ets_contentTimestamp 202
+id_smime_aa_ets_CertificateRefs 203
+id_smime_aa_ets_RevocationRefs 204
+id_smime_aa_ets_certValues 205
+id_smime_aa_ets_revocationValues 206
+id_smime_aa_ets_escTimeStamp 207
+id_smime_aa_ets_certCRLTimestamp 208
+id_smime_aa_ets_archiveTimeStamp 209
+id_smime_aa_signatureType 210
+id_smime_aa_dvcs_dvc 211
+id_smime_alg_ESDHwith3DES 212
+id_smime_alg_ESDHwithRC2 213
+id_smime_alg_3DESwrap 214
+id_smime_alg_RC2wrap 215
+id_smime_alg_ESDH 216
+id_smime_alg_CMS3DESwrap 217
+id_smime_alg_CMSRC2wrap 218
+id_alg_PWRI_KEK 219
+id_smime_cd_ldap 220
+id_smime_spq_ets_sqt_uri 221
+id_smime_spq_ets_sqt_unotice 222
+id_smime_cti_ets_proofOfOrigin 223
+id_smime_cti_ets_proofOfReceipt 224
+id_smime_cti_ets_proofOfDelivery 225
+id_smime_cti_ets_proofOfSender 226
+id_smime_cti_ets_proofOfApproval 227
+id_smime_cti_ets_proofOfCreation 228
+friendlyName 229
+localKeyID 230
+ms_csp_name 231
+LocalKeySet 232
+x509Certificate 233
+sdsiCertificate 234
+x509Crl 235
+pbe_WithSHA1And128BitRC4 236
+pbe_WithSHA1And40BitRC4 237
+pbe_WithSHA1And3_Key_TripleDES_CBC 238
+pbe_WithSHA1And2_Key_TripleDES_CBC 239
+pbe_WithSHA1And128BitRC2_CBC 240
+pbe_WithSHA1And40BitRC2_CBC 241
+keyBag 242
+pkcs8ShroudedKeyBag 243
+certBag 244
+crlBag 245
+secretBag 246
+safeContentsBag 247
+md2 248
+md4 249
+md5 250
+md5_sha1 251
+hmacWithMD5 252
+hmacWithSHA1 253
+hmacWithSHA224 254
+hmacWithSHA256 255
+hmacWithSHA384 256
+hmacWithSHA512 257
+rc2_cbc 258
+rc2_ecb 259
+rc2_cfb64 260
+rc2_ofb64 261
+rc2_40_cbc 262
+rc2_64_cbc 263
+rc4 264
+rc4_40 265
+des_ede3_cbc 266
+rc5_cbc 267
+rc5_ecb 268
+rc5_cfb64 269
+rc5_ofb64 270
+ms_ext_req 271
+ms_code_ind 272
+ms_code_com 273
+ms_ctl_sign 274
+ms_sgc 275
+ms_efs 276
+ms_smartcard_login 277
+ms_upn 278
+idea_cbc 279
+idea_ecb 280
+idea_cfb64 281
+idea_ofb64 282
+bf_cbc 283
+bf_ecb 284
+bf_cfb64 285
+bf_ofb64 286
+id_pkix 287
+id_pkix_mod 288
+id_pe 289
+id_qt 290
+id_kp 291
+id_it 292
+id_pkip 293
+id_alg 294
+id_cmc 295
+id_on 296
+id_pda 297
+id_aca 298
+id_qcs 299
+id_cct 300
+id_ppl 301
+id_ad 302
+id_pkix1_explicit_88 303
+id_pkix1_implicit_88 304
+id_pkix1_explicit_93 305
+id_pkix1_implicit_93 306
+id_mod_crmf 307
+id_mod_cmc 308
+id_mod_kea_profile_88 309
+id_mod_kea_profile_93 310
+id_mod_cmp 311
+id_mod_qualified_cert_88 312
+id_mod_qualified_cert_93 313
+id_mod_attribute_cert 314
+id_mod_timestamp_protocol 315
+id_mod_ocsp 316
+id_mod_dvcs 317
+id_mod_cmp2000 318
+info_access 319
+biometricInfo 320
+qcStatements 321
+ac_auditEntity 322
+ac_targeting 323
+aaControls 324
+sbgp_ipAddrBlock 325
+sbgp_autonomousSysNum 326
+sbgp_routerIdentifier 327
+ac_proxying 328
+sinfo_access 329
+proxyCertInfo 330
+id_qt_cps 331
+id_qt_unotice 332
+textNotice 333
+server_auth 334
+client_auth 335
+code_sign 336
+email_protect 337
+ipsecEndSystem 338
+ipsecTunnel 339
+ipsecUser 340
+time_stamp 341
+OCSP_sign 342
+dvcs 343
+id_it_caProtEncCert 344
+id_it_signKeyPairTypes 345
+id_it_encKeyPairTypes 346
+id_it_preferredSymmAlg 347
+id_it_caKeyUpdateInfo 348
+id_it_currentCRL 349
+id_it_unsupportedOIDs 350
+id_it_subscriptionRequest 351
+id_it_subscriptionResponse 352
+id_it_keyPairParamReq 353
+id_it_keyPairParamRep 354
+id_it_revPassphrase 355
+id_it_implicitConfirm 356
+id_it_confirmWaitTime 357
+id_it_origPKIMessage 358
+id_it_suppLangTags 359
+id_regCtrl 360
+id_regInfo 361
+id_regCtrl_regToken 362
+id_regCtrl_authenticator 363
+id_regCtrl_pkiPublicationInfo 364
+id_regCtrl_pkiArchiveOptions 365
+id_regCtrl_oldCertID 366
+id_regCtrl_protocolEncrKey 367
+id_regInfo_utf8Pairs 368
+id_regInfo_certReq 369
+id_alg_des40 370
+id_alg_noSignature 371
+id_alg_dh_sig_hmac_sha1 372
+id_alg_dh_pop 373
+id_cmc_statusInfo 374
+id_cmc_identification 375
+id_cmc_identityProof 376
+id_cmc_dataReturn 377
+id_cmc_transactionId 378
+id_cmc_senderNonce 379
+id_cmc_recipientNonce 380
+id_cmc_addExtensions 381
+id_cmc_encryptedPOP 382
+id_cmc_decryptedPOP 383
+id_cmc_lraPOPWitness 384
+id_cmc_getCert 385
+id_cmc_getCRL 386
+id_cmc_revokeRequest 387
+id_cmc_regInfo 388
+id_cmc_responseInfo 389
+id_cmc_queryPending 390
+id_cmc_popLinkRandom 391
+id_cmc_popLinkWitness 392
+id_cmc_confirmCertAcceptance 393
+id_on_personalData 394
+id_on_permanentIdentifier 395
+id_pda_dateOfBirth 396
+id_pda_placeOfBirth 397
+id_pda_gender 398
+id_pda_countryOfCitizenship 399
+id_pda_countryOfResidence 400
+id_aca_authenticationInfo 401
+id_aca_accessIdentity 402
+id_aca_chargingIdentity 403
+id_aca_group 404
+id_aca_role 405
+id_aca_encAttrs 406
+id_qcs_pkixQCSyntax_v1 407
+id_cct_crs 408
+id_cct_PKIData 409
+id_cct_PKIResponse 410
+id_ppl_anyLanguage 411
+id_ppl_inheritAll 412
+Independent 413
+ad_OCSP 414
+ad_ca_issuers 415
+ad_timeStamping 416
+ad_dvcs 417
+caRepository 418
+id_pkix_OCSP_basic 419
+id_pkix_OCSP_Nonce 420
+id_pkix_OCSP_CrlID 421
+id_pkix_OCSP_acceptableResponses 422
+id_pkix_OCSP_noCheck 423
+id_pkix_OCSP_archiveCutoff 424
+id_pkix_OCSP_serviceLocator 425
+id_pkix_OCSP_extendedStatus 426
+id_pkix_OCSP_valid 427
+id_pkix_OCSP_path 428
+id_pkix_OCSP_trustRoot 429
+algorithm 430
+md5WithRSA 431
+des_ecb 432
+des_cbc 433
+des_ofb64 434
+des_cfb64 435
+rsaSignature 436
+dsa_2 437
+dsaWithSHA 438
+shaWithRSAEncryption 439
+des_ede_ecb 440
+des_ede3_ecb 441
+des_ede_cbc 442
+des_ede_cfb64 443
+des_ede3_cfb64 444
+des_ede_ofb64 445
+des_ede3_ofb64 446
+desx_cbc 447
+sha 448
+sha1 449
+dsaWithSHA1_2 450
+sha1WithRSA 451
+ripemd160 452
+ripemd160WithRSA 453
+sxnet 454
+X500 455
+X509 456
+commonName 457
+surname 458
+serialNumber 459
+countryName 460
+localityName 461
+stateOrProvinceName 462
+streetAddress 463
+organizationName 464
+organizationalUnitName 465
+title 466
+description 467
+searchGuide 468
+businessCategory 469
+postalAddress 470
+postalCode 471
+postOfficeBox 472
+physicalDeliveryOfficeName 473
+telephoneNumber 474
+telexNumber 475
+teletexTerminalIdentifier 476
+facsimileTelephoneNumber 477
+x121Address 478
+internationaliSDNNumber 479
+registeredAddress 480
+destinationIndicator 481
+preferredDeliveryMethod 482
+presentationAddress 483
+supportedApplicationContext 484
+member 485
+owner 486
+roleOccupant 487
+seeAlso 488
+userPassword 489
+userCertificate 490
+cACertificate 491
+authorityRevocationList 492
+certificateRevocationList 493
+crossCertificatePair 494
+name 495
+givenName 496
+initials 497
+generationQualifier 498
+x500UniqueIdentifier 499
+dnQualifier 500
+enhancedSearchGuide 501
+protocolInformation 502
+distinguishedName 503
+uniqueMember 504
+houseIdentifier 505
+supportedAlgorithms 506
+deltaRevocationList 507
+dmdName 508
+pseudonym 509
+role 510
+X500algorithms 511
+rsa 512
+mdc2WithRSA 513
+mdc2 514
+id_ce 515
+subject_directory_attributes 516
+subject_key_identifier 517
+key_usage 518
+private_key_usage_period 519
+subject_alt_name 520
+issuer_alt_name 521
+basic_constraints 522
+crl_number 523
+crl_reason 524
+invalidity_date 525
+delta_crl 526
+issuing_distribution_point 527
+certificate_issuer 528
+name_constraints 529
+crl_distribution_points 530
+certificate_policies 531
+any_policy 532
+policy_mappings 533
+authority_key_identifier 534
+policy_constraints 535
+ext_key_usage 536
+freshest_crl 537
+inhibit_any_policy 538
+target_information 539
+no_rev_avail 540
+anyExtendedKeyUsage 541
+netscape 542
+netscape_cert_extension 543
+netscape_data_type 544
+netscape_cert_type 545
+netscape_base_url 546
+netscape_revocation_url 547
+netscape_ca_revocation_url 548
+netscape_renewal_url 549
+netscape_ca_policy_url 550
+netscape_ssl_server_name 551
+netscape_comment 552
+netscape_cert_sequence 553
+ns_sgc 554
+org 555
+dod 556
+iana 557
+Directory 558
+Management 559
+Experimental 560
+Private 561
+Security 562
+SNMPv2 563
+Mail 564
+Enterprises 565
+dcObject 566
+mime_mhs 567
+mime_mhs_headings 568
+mime_mhs_bodies 569
+id_hex_partial_message 570
+id_hex_multipart_message 571
+rle_compression 572
+zlib_compression 573
+aes_128_ecb 574
+aes_128_cbc 575
+aes_128_ofb128 576
+aes_128_cfb128 577
+id_aes128_wrap 578
+aes_128_gcm 579
+aes_128_ccm 580
+id_aes128_wrap_pad 581
+aes_192_ecb 582
+aes_192_cbc 583
+aes_192_ofb128 584
+aes_192_cfb128 585
+id_aes192_wrap 586
+aes_192_gcm 587
+aes_192_ccm 588
+id_aes192_wrap_pad 589
+aes_256_ecb 590
+aes_256_cbc 591
+aes_256_ofb128 592
+aes_256_cfb128 593
+id_aes256_wrap 594
+aes_256_gcm 595
+aes_256_ccm 596
+id_aes256_wrap_pad 597
+aes_128_cfb1 598
+aes_192_cfb1 599
+aes_256_cfb1 600
+aes_128_cfb8 601
+aes_192_cfb8 602
+aes_256_cfb8 603
+aes_128_ctr 604
+aes_192_ctr 605
+aes_256_ctr 606
+aes_128_xts 607
+aes_256_xts 608
+des_cfb1 609
+des_cfb8 610
+des_ede3_cfb1 611
+des_ede3_cfb8 612
+sha256 613
+sha384 614
+sha512 615
+sha224 616
+dsa_with_SHA224 617
+dsa_with_SHA256 618
+hold_instruction_code 619
+hold_instruction_none 620
+hold_instruction_call_issuer 621
+hold_instruction_reject 622
+data 623
+pss 624
+ucl 625
+pilot 626
+pilotAttributeType 627
+pilotAttributeSyntax 628
+pilotObjectClass 629
+pilotGroups 630
+iA5StringSyntax 631
+caseIgnoreIA5StringSyntax 632
+pilotObject 633
+pilotPerson 634
+account 635
+document 636
+room 637
+documentSeries 638
+Domain 639
+rFC822localPart 640
+dNSDomain 641
+domainRelatedObject 642
+friendlyCountry 643
+simpleSecurityObject 644
+pilotOrganization 645
+pilotDSA 646
+qualityLabelledData 647
+userId 648
+textEncodedORAddress 649
+rfc822Mailbox 650
+info 651
+favouriteDrink 652
+roomNumber 653
+photo 654
+userClass 655
+host 656
+manager 657
+documentIdentifier 658
+documentTitle 659
+documentVersion 660
+documentAuthor 661
+documentLocation 662
+homeTelephoneNumber 663
+secretary 664
+otherMailbox 665
+lastModifiedTime 666
+lastModifiedBy 667
+domainComponent 668
+aRecord 669
+pilotAttributeType27 670
+mXRecord 671
+nSRecord 672
+sOARecord 673
+cNAMERecord 674
+associatedDomain 675
+associatedName 676
+homePostalAddress 677
+personalTitle 678
+mobileTelephoneNumber 679
+pagerTelephoneNumber 680
+friendlyCountryName 681
+organizationalStatus 682
+janetMailbox 683
+mailPreferenceOption 684
+buildingName 685
+dSAQuality 686
+singleLevelQuality 687
+subtreeMinimumQuality 688
+subtreeMaximumQuality 689
+personalSignature 690
+dITRedirect 691
+audio 692
+documentPublisher 693
+id_set 694
+set_ctype 695
+set_msgExt 696
+set_attr 697
+set_policy 698
+set_certExt 699
+set_brand 700
+setct_PANData 701
+setct_PANToken 702
+setct_PANOnly 703
+setct_OIData 704
+setct_PI 705
+setct_PIData 706
+setct_PIDataUnsigned 707
+setct_HODInput 708
+setct_AuthResBaggage 709
+setct_AuthRevReqBaggage 710
+setct_AuthRevResBaggage 711
+setct_CapTokenSeq 712
+setct_PInitResData 713
+setct_PI_TBS 714
+setct_PResData 715
+setct_AuthReqTBS 716
+setct_AuthResTBS 717
+setct_AuthResTBSX 718
+setct_AuthTokenTBS 719
+setct_CapTokenData 720
+setct_CapTokenTBS 721
+setct_AcqCardCodeMsg 722
+setct_AuthRevReqTBS 723
+setct_AuthRevResData 724
+setct_AuthRevResTBS 725
+setct_CapReqTBS 726
+setct_CapReqTBSX 727
+setct_CapResData 728
+setct_CapRevReqTBS 729
+setct_CapRevReqTBSX 730
+setct_CapRevResData 731
+setct_CredReqTBS 732
+setct_CredReqTBSX 733
+setct_CredResData 734
+setct_CredRevReqTBS 735
+setct_CredRevReqTBSX 736
+setct_CredRevResData 737
+setct_PCertReqData 738
+setct_PCertResTBS 739
+setct_BatchAdminReqData 740
+setct_BatchAdminResData 741
+setct_CardCInitResTBS 742
+setct_MeAqCInitResTBS 743
+setct_RegFormResTBS 744
+setct_CertReqData 745
+setct_CertReqTBS 746
+setct_CertResData 747
+setct_CertInqReqTBS 748
+setct_ErrorTBS 749
+setct_PIDualSignedTBE 750
+setct_PIUnsignedTBE 751
+setct_AuthReqTBE 752
+setct_AuthResTBE 753
+setct_AuthResTBEX 754
+setct_AuthTokenTBE 755
+setct_CapTokenTBE 756
+setct_CapTokenTBEX 757
+setct_AcqCardCodeMsgTBE 758
+setct_AuthRevReqTBE 759
+setct_AuthRevResTBE 760
+setct_AuthRevResTBEB 761
+setct_CapReqTBE 762
+setct_CapReqTBEX 763
+setct_CapResTBE 764
+setct_CapRevReqTBE 765
+setct_CapRevReqTBEX 766
+setct_CapRevResTBE 767
+setct_CredReqTBE 768
+setct_CredReqTBEX 769
+setct_CredResTBE 770
+setct_CredRevReqTBE 771
+setct_CredRevReqTBEX 772
+setct_CredRevResTBE 773
+setct_BatchAdminReqTBE 774
+setct_BatchAdminResTBE 775
+setct_RegFormReqTBE 776
+setct_CertReqTBE 777
+setct_CertReqTBEX 778
+setct_CertResTBE 779
+setct_CRLNotificationTBS 780
+setct_CRLNotificationResTBS 781
+setct_BCIDistributionTBS 782
+setext_genCrypt 783
+setext_miAuth 784
+setext_pinSecure 785
+setext_pinAny 786
+setext_track2 787
+setext_cv 788
+set_policy_root 789
+setCext_hashedRoot 790
+setCext_certType 791
+setCext_merchData 792
+setCext_cCertRequired 793
+setCext_tunneling 794
+setCext_setExt 795
+setCext_setQualf 796
+setCext_PGWYcapabilities 797
+setCext_TokenIdentifier 798
+setCext_Track2Data 799
+setCext_TokenType 800
+setCext_IssuerCapabilities 801
+setAttr_Cert 802
+setAttr_PGWYcap 803
+setAttr_TokenType 804
+setAttr_IssCap 805
+set_rootKeyThumb 806
+set_addPolicy 807
+setAttr_Token_EMV 808
+setAttr_Token_B0Prime 809
+setAttr_IssCap_CVM 810
+setAttr_IssCap_T2 811
+setAttr_IssCap_Sig 812
+setAttr_GenCryptgrm 813
+setAttr_T2Enc 814
+setAttr_T2cleartxt 815
+setAttr_TokICCsig 816
+setAttr_SecDevSig 817
+set_brand_IATA_ATA 818
+set_brand_Diners 819
+set_brand_AmericanExpress 820
+set_brand_JCB 821
+set_brand_Visa 822
+set_brand_MasterCard 823
+set_brand_Novus 824
+des_cdmf 825
+rsaOAEPEncryptionSET 826
+ipsec3 827
+ipsec4 828
+whirlpool 829
+cryptopro 830
+cryptocom 831
+id_GostR3411_94_with_GostR3410_2001 832
+id_GostR3411_94_with_GostR3410_94 833
+id_GostR3411_94 834
+id_HMACGostR3411_94 835
+id_GostR3410_2001 836
+id_GostR3410_94 837
+id_Gost28147_89 838
+gost89_cnt 839
+id_Gost28147_89_MAC 840
+id_GostR3411_94_prf 841
+id_GostR3410_2001DH 842
+id_GostR3410_94DH 843
+id_Gost28147_89_CryptoPro_KeyMeshing 844
+id_Gost28147_89_None_KeyMeshing 845
+id_GostR3411_94_TestParamSet 846
+id_GostR3411_94_CryptoProParamSet 847
+id_Gost28147_89_TestParamSet 848
+id_Gost28147_89_CryptoPro_A_ParamSet 849
+id_Gost28147_89_CryptoPro_B_ParamSet 850
+id_Gost28147_89_CryptoPro_C_ParamSet 851
+id_Gost28147_89_CryptoPro_D_ParamSet 852
+id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet 853
+id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet 854
+id_Gost28147_89_CryptoPro_RIC_1_ParamSet 855
+id_GostR3410_94_TestParamSet 856
+id_GostR3410_94_CryptoPro_A_ParamSet 857
+id_GostR3410_94_CryptoPro_B_ParamSet 858
+id_GostR3410_94_CryptoPro_C_ParamSet 859
+id_GostR3410_94_CryptoPro_D_ParamSet 860
+id_GostR3410_94_CryptoPro_XchA_ParamSet 861
+id_GostR3410_94_CryptoPro_XchB_ParamSet 862
+id_GostR3410_94_CryptoPro_XchC_ParamSet 863
+id_GostR3410_2001_TestParamSet 864
+id_GostR3410_2001_CryptoPro_A_ParamSet 865
+id_GostR3410_2001_CryptoPro_B_ParamSet 866
+id_GostR3410_2001_CryptoPro_C_ParamSet 867
+id_GostR3410_2001_CryptoPro_XchA_ParamSet 868
+id_GostR3410_2001_CryptoPro_XchB_ParamSet 869
+id_GostR3410_94_a 870
+id_GostR3410_94_aBis 871
+id_GostR3410_94_b 872
+id_GostR3410_94_bBis 873
+id_Gost28147_89_cc 874
+id_GostR3410_94_cc 875
+id_GostR3410_2001_cc 876
+id_GostR3411_94_with_GostR3410_94_cc 877
+id_GostR3411_94_with_GostR3410_2001_cc 878
+id_GostR3410_2001_ParamSet_cc 879
+camellia_128_cbc 880
+camellia_192_cbc 881
+camellia_256_cbc 882
+id_camellia128_wrap 883
+id_camellia192_wrap 884
+id_camellia256_wrap 885
+camellia_128_ecb 886
+camellia_128_ofb128 887
+camellia_128_cfb128 888
+camellia_192_ecb 889
+camellia_192_ofb128 890
+camellia_192_cfb128 891
+camellia_256_ecb 892
+camellia_256_ofb128 893
+camellia_256_cfb128 894
+camellia_128_cfb1 895
+camellia_192_cfb1 896
+camellia_256_cfb1 897
+camellia_128_cfb8 898
+camellia_192_cfb8 899
+camellia_256_cfb8 900
+kisa 901
+seed_ecb 902
+seed_cbc 903
+seed_cfb128 904
+seed_ofb128 905
+hmac 906
+cmac 907
+rc4_hmac_md5 908
+aes_128_cbc_hmac_sha1 909
+aes_192_cbc_hmac_sha1 910
+aes_256_cbc_hmac_sha1 911
+dhpublicnumber 912
+brainpoolP160r1 913
+brainpoolP160t1 914
+brainpoolP192r1 915
+brainpoolP192t1 916
+brainpoolP224r1 917
+brainpoolP224t1 918
+brainpoolP256r1 919
+brainpoolP256t1 920
+brainpoolP320r1 921
+brainpoolP320t1 922
+brainpoolP384r1 923
+brainpoolP384t1 924
+brainpoolP512r1 925
+brainpoolP512t1 926
+dhSinglePass_stdDH_sha1kdf_scheme 927
+dhSinglePass_stdDH_sha224kdf_scheme 928
+dhSinglePass_stdDH_sha256kdf_scheme 929
+dhSinglePass_stdDH_sha384kdf_scheme 930
+dhSinglePass_stdDH_sha512kdf_scheme 931
+dhSinglePass_cofactorDH_sha1kdf_scheme 932
+dhSinglePass_cofactorDH_sha224kdf_scheme 933
+dhSinglePass_cofactorDH_sha256kdf_scheme 934
+dhSinglePass_cofactorDH_sha384kdf_scheme 935
+dhSinglePass_cofactorDH_sha512kdf_scheme 936
+dh_std_kdf 937
+dh_cofactor_kdf 938
diff --git a/crypto/obj/obj_xref.c b/crypto/obj/obj_xref.c
new file mode 100644
index 0000000..70babea
--- /dev/null
+++ b/crypto/obj/obj_xref.c
@@ -0,0 +1,124 @@
+/* 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/obj.h>
+
+#include <stdlib.h>
+
+#include "obj_xref.h"
+
+
+static int nid_triple_cmp_by_sign_id(const void *in_a, const void *in_b) {
+ const nid_triple *a = in_a;
+ const nid_triple *b = in_b;
+
+ return a->sign_id - b->sign_id;
+}
+
+int OBJ_find_sigid_algs(int sign_nid, int *out_digest_nid, int *out_pkey_nid) {
+ nid_triple key;
+ const nid_triple *triple;
+
+ key.sign_id = sign_nid;
+
+ triple = bsearch(&key, sigoid_srt, sizeof(sigoid_srt) / sizeof(nid_triple),
+ sizeof(nid_triple), nid_triple_cmp_by_sign_id);
+
+ if (triple == NULL) {
+ return 0;
+ }
+ if (out_digest_nid) {
+ *out_digest_nid = triple->hash_id;
+ }
+ if (out_pkey_nid) {
+ *out_pkey_nid = triple->pkey_id;
+ }
+
+ return 1;
+}
+
+static int nid_triple_cmp_by_digest_and_hash(const void *in_a,
+ const void *in_b) {
+ const nid_triple *a = *((nid_triple**) in_a);
+ const nid_triple *b = *((nid_triple**) in_b);
+
+ int ret = a->hash_id - b->hash_id;
+ if (ret) {
+ return ret;
+ }
+ return a->pkey_id - b->pkey_id;
+}
+
+int OBJ_find_sigid_by_algs(int *out_sign_nid, int digest_nid, int pkey_nid) {
+ nid_triple key, *pkey;
+ const nid_triple **triple;
+
+ key.hash_id = digest_nid;
+ key.pkey_id = pkey_nid;
+ pkey = &key;
+
+ triple = bsearch(&pkey, sigoid_srt_xref,
+ sizeof(sigoid_srt_xref) / sizeof(nid_triple *),
+ sizeof(nid_triple *), nid_triple_cmp_by_digest_and_hash);
+
+ if (triple == NULL) {
+ return 0;
+ }
+ if (out_sign_nid) {
+ *out_sign_nid = (*triple)->sign_id;
+ }
+ return 1;
+}
diff --git a/crypto/obj/obj_xref.h b/crypto/obj/obj_xref.h
new file mode 100644
index 0000000..cfd628a
--- /dev/null
+++ b/crypto/obj/obj_xref.h
@@ -0,0 +1,97 @@
+/* AUTOGENERATED BY objxref.pl, DO NOT EDIT */
+
+typedef struct
+ {
+ int sign_id;
+ int hash_id;
+ int pkey_id;
+ } nid_triple;
+
+static const nid_triple sigoid_srt[] =
+ {
+ {NID_md2WithRSAEncryption, NID_md2, NID_rsaEncryption},
+ {NID_md5WithRSAEncryption, NID_md5, NID_rsaEncryption},
+ {NID_shaWithRSAEncryption, NID_sha, NID_rsaEncryption},
+ {NID_sha1WithRSAEncryption, NID_sha1, NID_rsaEncryption},
+ {NID_dsaWithSHA, NID_sha, NID_dsa},
+ {NID_dsaWithSHA1_2, NID_sha1, NID_dsa_2},
+ {NID_mdc2WithRSA, NID_mdc2, NID_rsaEncryption},
+ {NID_md5WithRSA, NID_md5, NID_rsa},
+ {NID_dsaWithSHA1, NID_sha1, NID_dsa},
+ {NID_sha1WithRSA, NID_sha1, NID_rsa},
+ {NID_ripemd160WithRSA, NID_ripemd160, NID_rsaEncryption},
+ {NID_md4WithRSAEncryption, NID_md4, NID_rsaEncryption},
+ {NID_ecdsa_with_SHA1, NID_sha1, NID_X9_62_id_ecPublicKey},
+ {NID_sha256WithRSAEncryption, NID_sha256, NID_rsaEncryption},
+ {NID_sha384WithRSAEncryption, NID_sha384, NID_rsaEncryption},
+ {NID_sha512WithRSAEncryption, NID_sha512, NID_rsaEncryption},
+ {NID_sha224WithRSAEncryption, NID_sha224, NID_rsaEncryption},
+ {NID_ecdsa_with_Recommended, NID_undef, NID_X9_62_id_ecPublicKey},
+ {NID_ecdsa_with_Specified, NID_undef, NID_X9_62_id_ecPublicKey},
+ {NID_ecdsa_with_SHA224, NID_sha224, NID_X9_62_id_ecPublicKey},
+ {NID_ecdsa_with_SHA256, NID_sha256, NID_X9_62_id_ecPublicKey},
+ {NID_ecdsa_with_SHA384, NID_sha384, NID_X9_62_id_ecPublicKey},
+ {NID_ecdsa_with_SHA512, NID_sha512, NID_X9_62_id_ecPublicKey},
+ {NID_dsa_with_SHA224, NID_sha224, NID_dsa},
+ {NID_dsa_with_SHA256, NID_sha256, NID_dsa},
+ {NID_id_GostR3411_94_with_GostR3410_2001, NID_id_GostR3411_94, NID_id_GostR3410_2001},
+ {NID_id_GostR3411_94_with_GostR3410_94, NID_id_GostR3411_94, NID_id_GostR3410_94},
+ {NID_id_GostR3411_94_with_GostR3410_94_cc, NID_id_GostR3411_94, NID_id_GostR3410_94_cc},
+ {NID_id_GostR3411_94_with_GostR3410_2001_cc, NID_id_GostR3411_94, NID_id_GostR3410_2001_cc},
+ {NID_rsassaPss, NID_undef, NID_rsaEncryption},
+ {NID_dhSinglePass_stdDH_sha1kdf_scheme, NID_sha1, NID_dh_std_kdf},
+ {NID_dhSinglePass_stdDH_sha224kdf_scheme, NID_sha224, NID_dh_std_kdf},
+ {NID_dhSinglePass_stdDH_sha256kdf_scheme, NID_sha256, NID_dh_std_kdf},
+ {NID_dhSinglePass_stdDH_sha384kdf_scheme, NID_sha384, NID_dh_std_kdf},
+ {NID_dhSinglePass_stdDH_sha512kdf_scheme, NID_sha512, NID_dh_std_kdf},
+ {NID_dhSinglePass_cofactorDH_sha1kdf_scheme, NID_sha1, NID_dh_cofactor_kdf},
+ {NID_dhSinglePass_cofactorDH_sha224kdf_scheme, NID_sha224, NID_dh_cofactor_kdf},
+ {NID_dhSinglePass_cofactorDH_sha256kdf_scheme, NID_sha256, NID_dh_cofactor_kdf},
+ {NID_dhSinglePass_cofactorDH_sha384kdf_scheme, NID_sha384, NID_dh_cofactor_kdf},
+ {NID_dhSinglePass_cofactorDH_sha512kdf_scheme, NID_sha512, NID_dh_cofactor_kdf},
+ };
+
+static const nid_triple * const sigoid_srt_xref[] =
+ {
+ &sigoid_srt[29],
+ &sigoid_srt[17],
+ &sigoid_srt[18],
+ &sigoid_srt[0],
+ &sigoid_srt[1],
+ &sigoid_srt[7],
+ &sigoid_srt[2],
+ &sigoid_srt[4],
+ &sigoid_srt[3],
+ &sigoid_srt[9],
+ &sigoid_srt[5],
+ &sigoid_srt[8],
+ &sigoid_srt[12],
+ &sigoid_srt[30],
+ &sigoid_srt[35],
+ &sigoid_srt[6],
+ &sigoid_srt[10],
+ &sigoid_srt[11],
+ &sigoid_srt[13],
+ &sigoid_srt[24],
+ &sigoid_srt[20],
+ &sigoid_srt[32],
+ &sigoid_srt[37],
+ &sigoid_srt[14],
+ &sigoid_srt[21],
+ &sigoid_srt[33],
+ &sigoid_srt[38],
+ &sigoid_srt[15],
+ &sigoid_srt[22],
+ &sigoid_srt[34],
+ &sigoid_srt[39],
+ &sigoid_srt[16],
+ &sigoid_srt[23],
+ &sigoid_srt[19],
+ &sigoid_srt[31],
+ &sigoid_srt[36],
+ &sigoid_srt[25],
+ &sigoid_srt[26],
+ &sigoid_srt[27],
+ &sigoid_srt[28],
+ };
+
diff --git a/crypto/obj/obj_xref.pl b/crypto/obj/obj_xref.pl
new file mode 100644
index 0000000..731d3ae
--- /dev/null
+++ b/crypto/obj/obj_xref.pl
@@ -0,0 +1,107 @@
+#!/usr/local/bin/perl
+
+use strict;
+
+my %xref_tbl;
+my %oid_tbl;
+
+my ($mac_file, $xref_file) = @ARGV;
+
+open(IN, $mac_file) || die "Can't open $mac_file";
+
+# Read in OID nid values for a lookup table.
+
+while (<IN>)
+ {
+ chomp;
+ my ($name, $num) = /^(\S+)\s+(\S+)$/;
+ $oid_tbl{$name} = $num;
+ }
+close IN;
+
+open(IN, $xref_file) || die "Can't open $xref_file";
+
+my $ln = 1;
+
+while (<IN>)
+ {
+ chomp;
+ s/#.*$//;
+ next if (/^\S*$/);
+ my ($xr, $p1, $p2) = /^(\S+)\s+(\S+)\s+(\S+)/;
+ check_oid($xr);
+ check_oid($p1);
+ check_oid($p2);
+ $xref_tbl{$xr} = [$p1, $p2, $ln];
+ }
+
+my @xrkeys = keys %xref_tbl;
+
+my @srt1 = sort { $oid_tbl{$a} <=> $oid_tbl{$b}} @xrkeys;
+
+for(my $i = 0; $i <= $#srt1; $i++)
+ {
+ $xref_tbl{$srt1[$i]}[2] = $i;
+ }
+
+my @srt2 = sort
+ {
+ my$ap1 = $oid_tbl{$xref_tbl{$a}[0]};
+ my$bp1 = $oid_tbl{$xref_tbl{$b}[0]};
+ return $ap1 - $bp1 if ($ap1 != $bp1);
+ my$ap2 = $oid_tbl{$xref_tbl{$a}[1]};
+ my$bp2 = $oid_tbl{$xref_tbl{$b}[1]};
+
+ return $ap2 - $bp2;
+ } @xrkeys;
+
+my $pname = $0;
+
+$pname =~ s|^.[^/]/||;
+
+print <<EOF;
+/* AUTOGENERATED BY $pname, DO NOT EDIT */
+
+typedef struct
+ {
+ int sign_id;
+ int hash_id;
+ int pkey_id;
+ } nid_triple;
+
+static const nid_triple sigoid_srt[] =
+ {
+EOF
+
+foreach (@srt1)
+ {
+ my $xr = $_;
+ my ($p1, $p2) = @{$xref_tbl{$_}};
+ print "\t{NID_$xr, NID_$p1, NID_$p2},\n";
+ }
+
+print "\t};";
+print <<EOF;
+
+
+static const nid_triple * const sigoid_srt_xref[] =
+ {
+EOF
+
+foreach (@srt2)
+ {
+ my $x = $xref_tbl{$_}[2];
+ print "\t\&sigoid_srt\[$x\],\n";
+ }
+
+print "\t};\n\n";
+
+sub check_oid
+ {
+ my ($chk) = @_;
+ if (!exists $oid_tbl{$chk})
+ {
+ die "Not Found \"$chk\"\n";
+ }
+ }
+
diff --git a/crypto/obj/obj_xref.txt b/crypto/obj/obj_xref.txt
new file mode 100644
index 0000000..19c9422
--- /dev/null
+++ b/crypto/obj/obj_xref.txt
@@ -0,0 +1,58 @@
+# OID cross reference table.
+# Links signatures OIDs to their corresponding public key algorithms
+# and digests.
+
+md2WithRSAEncryption md2 rsaEncryption
+md5WithRSAEncryption md5 rsaEncryption
+shaWithRSAEncryption sha rsaEncryption
+sha1WithRSAEncryption sha1 rsaEncryption
+md4WithRSAEncryption md4 rsaEncryption
+sha256WithRSAEncryption sha256 rsaEncryption
+sha384WithRSAEncryption sha384 rsaEncryption
+sha512WithRSAEncryption sha512 rsaEncryption
+sha224WithRSAEncryption sha224 rsaEncryption
+mdc2WithRSA mdc2 rsaEncryption
+ripemd160WithRSA ripemd160 rsaEncryption
+# For PSS the digest algorithm can vary and depends on the included
+# AlgorithmIdentifier. The digest "undef" indicates the public key
+# method should handle this explicitly.
+rsassaPss undef rsaEncryption
+
+# Alternative deprecated OIDs. By using the older "rsa" OID this
+# type will be recognized by not normally used.
+
+md5WithRSA md5 rsa
+sha1WithRSA sha1 rsa
+
+dsaWithSHA sha dsa
+dsaWithSHA1 sha1 dsa
+
+dsaWithSHA1_2 sha1 dsa_2
+
+ecdsa_with_SHA1 sha1 X9_62_id_ecPublicKey
+ecdsa_with_SHA224 sha224 X9_62_id_ecPublicKey
+ecdsa_with_SHA256 sha256 X9_62_id_ecPublicKey
+ecdsa_with_SHA384 sha384 X9_62_id_ecPublicKey
+ecdsa_with_SHA512 sha512 X9_62_id_ecPublicKey
+ecdsa_with_Recommended undef X9_62_id_ecPublicKey
+ecdsa_with_Specified undef X9_62_id_ecPublicKey
+
+dsa_with_SHA224 sha224 dsa
+dsa_with_SHA256 sha256 dsa
+
+id_GostR3411_94_with_GostR3410_2001 id_GostR3411_94 id_GostR3410_2001
+id_GostR3411_94_with_GostR3410_94 id_GostR3411_94 id_GostR3410_94
+id_GostR3411_94_with_GostR3410_94_cc id_GostR3411_94 id_GostR3410_94_cc
+id_GostR3411_94_with_GostR3410_2001_cc id_GostR3411_94 id_GostR3410_2001_cc
+# ECDH KDFs and their corresponding message digests and schemes
+dhSinglePass_stdDH_sha1kdf_scheme sha1 dh_std_kdf
+dhSinglePass_stdDH_sha224kdf_scheme sha224 dh_std_kdf
+dhSinglePass_stdDH_sha256kdf_scheme sha256 dh_std_kdf
+dhSinglePass_stdDH_sha384kdf_scheme sha384 dh_std_kdf
+dhSinglePass_stdDH_sha512kdf_scheme sha512 dh_std_kdf
+
+dhSinglePass_cofactorDH_sha1kdf_scheme sha1 dh_cofactor_kdf
+dhSinglePass_cofactorDH_sha224kdf_scheme sha224 dh_cofactor_kdf
+dhSinglePass_cofactorDH_sha256kdf_scheme sha256 dh_cofactor_kdf
+dhSinglePass_cofactorDH_sha384kdf_scheme sha384 dh_cofactor_kdf
+dhSinglePass_cofactorDH_sha512kdf_scheme sha512 dh_cofactor_kdf
diff --git a/crypto/obj/objects.pl b/crypto/obj/objects.pl
new file mode 100644
index 0000000..4b8b394
--- /dev/null
+++ b/crypto/obj/objects.pl
@@ -0,0 +1,228 @@
+#!/usr/local/bin/perl
+
+open (NUMIN,"$ARGV[1]") || die "Can't open number file $ARGV[1]";
+$max_nid=0;
+$o=0;
+while(<NUMIN>)
+ {
+ chop;
+ $o++;
+ s/#.*$//;
+ next if /^\s*$/;
+ $_ = 'X'.$_;
+ ($Cname,$mynum) = split;
+ $Cname =~ s/^X//;
+ if (defined($nidn{$mynum}))
+ { die "$ARGV[1]:$o:There's already an object with NID ",$mynum," on line ",$order{$mynum},"\n"; }
+ if (defined($nid{$Cname}))
+ { die "$ARGV[1]:$o:There's already an object with name ",$Cname," on line ",$order{$nid{$Cname}},"\n"; }
+ $nid{$Cname} = $mynum;
+ $nidn{$mynum} = $Cname;
+ $order{$mynum} = $o;
+ $max_nid = $mynum if $mynum > $max_nid;
+ }
+close NUMIN;
+
+open (IN,"$ARGV[0]") || die "Can't open input file $ARGV[0]";
+$Cname="";
+$o=0;
+while (<IN>)
+ {
+ chop;
+ $o++;
+ if (/^!module\s+(.*)$/)
+ {
+ $module = $1."-";
+ $module =~ s/\./_/g;
+ $module =~ s/-/_/g;
+ }
+ if (/^!global$/)
+ { $module = ""; }
+ if (/^!Cname\s+(.*)$/)
+ { $Cname = $1; }
+ if (/^!Alias\s+(.+?)\s+(.*)$/)
+ {
+ $Cname = $module.$1;
+ $myoid = $2;
+ $myoid = &process_oid($myoid);
+ $Cname =~ s/-/_/g;
+ $ordern{$o} = $Cname;
+ $order{$Cname} = $o;
+ $obj{$Cname} = $myoid;
+ $_ = "";
+ $Cname = "";
+ }
+ s/!.*$//;
+ s/#.*$//;
+ next if /^\s*$/;
+ ($myoid,$mysn,$myln) = split ':';
+ $mysn =~ s/^\s*//;
+ $mysn =~ s/\s*$//;
+ $myln =~ s/^\s*//;
+ $myln =~ s/\s*$//;
+ $myoid =~ s/^\s*//;
+ $myoid =~ s/\s*$//;
+ if ($myoid ne "")
+ {
+ $myoid = &process_oid($myoid);
+ }
+
+ if ($Cname eq "" && !($myln =~ / /))
+ {
+ $Cname = $myln;
+ $Cname =~ s/\./_/g;
+ $Cname =~ s/-/_/g;
+ if ($Cname ne "" && defined($ln{$module.$Cname}))
+ { die "objects.txt:$o:There's already an object with long name ",$ln{$module.$Cname}," on line ",$order{$module.$Cname},"\n"; }
+ }
+ if ($Cname eq "")
+ {
+ $Cname = $mysn;
+ $Cname =~ s/-/_/g;
+ if ($Cname ne "" && defined($sn{$module.$Cname}))
+ { die "objects.txt:$o:There's already an object with short name ",$sn{$module.$Cname}," on line ",$order{$module.$Cname},"\n"; }
+ }
+ if ($Cname eq "")
+ {
+ $Cname = $myln;
+ $Cname =~ s/-/_/g;
+ $Cname =~ s/\./_/g;
+ $Cname =~ s/ /_/g;
+ if ($Cname ne "" && defined($ln{$module.$Cname}))
+ { die "objects.txt:$o:There's already an object with long name ",$ln{$module.$Cname}," on line ",$order{$module.$Cname},"\n"; }
+ }
+ $Cname =~ s/\./_/g;
+ $Cname =~ s/-/_/g;
+ $Cname = $module.$Cname;
+ $ordern{$o} = $Cname;
+ $order{$Cname} = $o;
+ $sn{$Cname} = $mysn;
+ $ln{$Cname} = $myln;
+ $obj{$Cname} = $myoid;
+ if (!defined($nid{$Cname}))
+ {
+ $max_nid++;
+ $nid{$Cname} = $max_nid;
+ $nidn{$max_nid} = $Cname;
+print STDERR "Added OID $Cname\n";
+ }
+ $Cname="";
+ }
+close IN;
+
+open (NUMOUT,">$ARGV[1]") || die "Can't open output file $ARGV[1]";
+foreach (sort { $a <=> $b } keys %nidn)
+ {
+ print NUMOUT $nidn{$_},"\t\t",$_,"\n";
+ }
+close NUMOUT;
+
+open (OUT,">$ARGV[2]") || die "Can't open output file $ARGV[2]";
+print OUT <<'EOF';
+/* THIS FILE IS GENERATED FROM objects.txt by objects.pl via the
+ * following command:
+ * perl objects.pl objects.txt obj_mac.num obj_mac.h */
+
+/* Copyright (C) 1995-1997 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.] */
+
+#define SN_undef "UNDEF"
+#define LN_undef "undefined"
+#define NID_undef 0
+#define OBJ_undef 0L
+
+EOF
+
+foreach (sort { $a <=> $b } keys %ordern)
+ {
+ $Cname=$ordern{$_};
+ print OUT "#define SN_",$Cname,"\t\t\"",$sn{$Cname},"\"\n" if $sn{$Cname} ne "";
+ print OUT "#define LN_",$Cname,"\t\t\"",$ln{$Cname},"\"\n" if $ln{$Cname} ne "";
+ print OUT "#define NID_",$Cname,"\t\t",$nid{$Cname},"\n" if $nid{$Cname} ne "";
+ print OUT "#define OBJ_",$Cname,"\t\t",$obj{$Cname},"\n" if $obj{$Cname} ne "";
+ print OUT "\n";
+ }
+
+close OUT;
+
+sub process_oid
+ {
+ local($oid)=@_;
+ local(@a,$oid_pref);
+
+ @a = split(/\s+/,$myoid);
+ $pref_oid = "";
+ $pref_sep = "";
+ if (!($a[0] =~ /^[0-9]+$/))
+ {
+ $a[0] =~ s/-/_/g;
+ if (!defined($obj{$a[0]}))
+ { die "$ARGV[0]:$o:Undefined identifier ",$a[0],"\n"; }
+ $pref_oid = "OBJ_" . $a[0];
+ $pref_sep = ",";
+ shift @a;
+ }
+ $oids = join('L,',@a) . "L";
+ if ($oids ne "L")
+ {
+ $oids = $pref_oid . $pref_sep . $oids;
+ }
+ else
+ {
+ $oids = $pref_oid;
+ }
+ return($oids);
+ }
diff --git a/crypto/obj/objects.txt b/crypto/obj/objects.txt
new file mode 100644
index 0000000..aeffc6c
--- /dev/null
+++ b/crypto/obj/objects.txt
@@ -0,0 +1,1334 @@
+# CCITT was renamed to ITU-T quite some time ago
+0 : ITU-T : itu-t
+!Alias ccitt itu-t
+
+1 : ISO : iso
+
+2 : JOINT-ISO-ITU-T : joint-iso-itu-t
+!Alias joint-iso-ccitt joint-iso-itu-t
+
+iso 2 : member-body : ISO Member Body
+
+iso 3 : identified-organization
+
+# HMAC OIDs
+identified-organization 6 1 5 5 8 1 1 : HMAC-MD5 : hmac-md5
+identified-organization 6 1 5 5 8 1 2 : HMAC-SHA1 : hmac-sha1
+
+identified-organization 132 : certicom-arc
+
+joint-iso-itu-t 23 : international-organizations : International Organizations
+
+international-organizations 43 : wap
+wap 1 : wap-wsg
+
+joint-iso-itu-t 5 1 5 : selected-attribute-types : Selected Attribute Types
+
+selected-attribute-types 55 : clearance
+
+member-body 840 : ISO-US : ISO US Member Body
+ISO-US 10040 : X9-57 : X9.57
+X9-57 4 : X9cm : X9.57 CM ?
+
+!Cname dsa
+X9cm 1 : DSA : dsaEncryption
+X9cm 3 : DSA-SHA1 : dsaWithSHA1
+
+
+ISO-US 10045 : ansi-X9-62 : ANSI X9.62
+!module X9-62
+!Alias id-fieldType ansi-X9-62 1
+X9-62_id-fieldType 1 : prime-field
+X9-62_id-fieldType 2 : characteristic-two-field
+X9-62_characteristic-two-field 3 : id-characteristic-two-basis
+X9-62_id-characteristic-two-basis 1 : onBasis
+X9-62_id-characteristic-two-basis 2 : tpBasis
+X9-62_id-characteristic-two-basis 3 : ppBasis
+!Alias id-publicKeyType ansi-X9-62 2
+X9-62_id-publicKeyType 1 : id-ecPublicKey
+!Alias ellipticCurve ansi-X9-62 3
+!Alias c-TwoCurve X9-62_ellipticCurve 0
+X9-62_c-TwoCurve 1 : c2pnb163v1
+X9-62_c-TwoCurve 2 : c2pnb163v2
+X9-62_c-TwoCurve 3 : c2pnb163v3
+X9-62_c-TwoCurve 4 : c2pnb176v1
+X9-62_c-TwoCurve 5 : c2tnb191v1
+X9-62_c-TwoCurve 6 : c2tnb191v2
+X9-62_c-TwoCurve 7 : c2tnb191v3
+X9-62_c-TwoCurve 8 : c2onb191v4
+X9-62_c-TwoCurve 9 : c2onb191v5
+X9-62_c-TwoCurve 10 : c2pnb208w1
+X9-62_c-TwoCurve 11 : c2tnb239v1
+X9-62_c-TwoCurve 12 : c2tnb239v2
+X9-62_c-TwoCurve 13 : c2tnb239v3
+X9-62_c-TwoCurve 14 : c2onb239v4
+X9-62_c-TwoCurve 15 : c2onb239v5
+X9-62_c-TwoCurve 16 : c2pnb272w1
+X9-62_c-TwoCurve 17 : c2pnb304w1
+X9-62_c-TwoCurve 18 : c2tnb359v1
+X9-62_c-TwoCurve 19 : c2pnb368w1
+X9-62_c-TwoCurve 20 : c2tnb431r1
+!Alias primeCurve X9-62_ellipticCurve 1
+X9-62_primeCurve 1 : prime192v1
+X9-62_primeCurve 2 : prime192v2
+X9-62_primeCurve 3 : prime192v3
+X9-62_primeCurve 4 : prime239v1
+X9-62_primeCurve 5 : prime239v2
+X9-62_primeCurve 6 : prime239v3
+X9-62_primeCurve 7 : prime256v1
+!Alias id-ecSigType ansi-X9-62 4
+!global
+X9-62_id-ecSigType 1 : ecdsa-with-SHA1
+X9-62_id-ecSigType 2 : ecdsa-with-Recommended
+X9-62_id-ecSigType 3 : ecdsa-with-Specified
+ecdsa-with-Specified 1 : ecdsa-with-SHA224
+ecdsa-with-Specified 2 : ecdsa-with-SHA256
+ecdsa-with-Specified 3 : ecdsa-with-SHA384
+ecdsa-with-Specified 4 : ecdsa-with-SHA512
+
+# SECG curve OIDs from "SEC 2: Recommended Elliptic Curve Domain Parameters"
+# (http://www.secg.org/)
+!Alias secg_ellipticCurve certicom-arc 0
+# SECG prime curves OIDs
+secg-ellipticCurve 6 : secp112r1
+secg-ellipticCurve 7 : secp112r2
+secg-ellipticCurve 28 : secp128r1
+secg-ellipticCurve 29 : secp128r2
+secg-ellipticCurve 9 : secp160k1
+secg-ellipticCurve 8 : secp160r1
+secg-ellipticCurve 30 : secp160r2
+secg-ellipticCurve 31 : secp192k1
+# NOTE: the curve secp192r1 is the same as prime192v1 defined above
+# and is therefore omitted
+secg-ellipticCurve 32 : secp224k1
+secg-ellipticCurve 33 : secp224r1
+secg-ellipticCurve 10 : secp256k1
+# NOTE: the curve secp256r1 is the same as prime256v1 defined above
+# and is therefore omitted
+secg-ellipticCurve 34 : secp384r1
+secg-ellipticCurve 35 : secp521r1
+# SECG characteristic two curves OIDs
+secg-ellipticCurve 4 : sect113r1
+secg-ellipticCurve 5 : sect113r2
+secg-ellipticCurve 22 : sect131r1
+secg-ellipticCurve 23 : sect131r2
+secg-ellipticCurve 1 : sect163k1
+secg-ellipticCurve 2 : sect163r1
+secg-ellipticCurve 15 : sect163r2
+secg-ellipticCurve 24 : sect193r1
+secg-ellipticCurve 25 : sect193r2
+secg-ellipticCurve 26 : sect233k1
+secg-ellipticCurve 27 : sect233r1
+secg-ellipticCurve 3 : sect239k1
+secg-ellipticCurve 16 : sect283k1
+secg-ellipticCurve 17 : sect283r1
+secg-ellipticCurve 36 : sect409k1
+secg-ellipticCurve 37 : sect409r1
+secg-ellipticCurve 38 : sect571k1
+secg-ellipticCurve 39 : sect571r1
+
+# WAP/TLS curve OIDs (http://www.wapforum.org/)
+!Alias wap-wsg-idm-ecid wap-wsg 4
+wap-wsg-idm-ecid 1 : wap-wsg-idm-ecid-wtls1
+wap-wsg-idm-ecid 3 : wap-wsg-idm-ecid-wtls3
+wap-wsg-idm-ecid 4 : wap-wsg-idm-ecid-wtls4
+wap-wsg-idm-ecid 5 : wap-wsg-idm-ecid-wtls5
+wap-wsg-idm-ecid 6 : wap-wsg-idm-ecid-wtls6
+wap-wsg-idm-ecid 7 : wap-wsg-idm-ecid-wtls7
+wap-wsg-idm-ecid 8 : wap-wsg-idm-ecid-wtls8
+wap-wsg-idm-ecid 9 : wap-wsg-idm-ecid-wtls9
+wap-wsg-idm-ecid 10 : wap-wsg-idm-ecid-wtls10
+wap-wsg-idm-ecid 11 : wap-wsg-idm-ecid-wtls11
+wap-wsg-idm-ecid 12 : wap-wsg-idm-ecid-wtls12
+
+
+ISO-US 113533 7 66 10 : CAST5-CBC : cast5-cbc
+ : CAST5-ECB : cast5-ecb
+!Cname cast5-cfb64
+ : CAST5-CFB : cast5-cfb
+!Cname cast5-ofb64
+ : CAST5-OFB : cast5-ofb
+!Cname pbeWithMD5AndCast5-CBC
+ISO-US 113533 7 66 12 : : pbeWithMD5AndCast5CBC
+
+# Macs for CMP and CRMF
+ISO-US 113533 7 66 13 : id-PasswordBasedMAC : password based MAC
+ISO-US 113533 7 66 30 : id-DHBasedMac : Diffie-Hellman based MAC
+
+ISO-US 113549 : rsadsi : RSA Data Security, Inc.
+
+rsadsi 1 : pkcs : RSA Data Security, Inc. PKCS
+
+pkcs 1 : pkcs1
+pkcs1 1 : : rsaEncryption
+pkcs1 2 : RSA-MD2 : md2WithRSAEncryption
+pkcs1 3 : RSA-MD4 : md4WithRSAEncryption
+pkcs1 4 : RSA-MD5 : md5WithRSAEncryption
+pkcs1 5 : RSA-SHA1 : sha1WithRSAEncryption
+# According to PKCS #1 version 2.1
+pkcs1 7 : RSAES-OAEP : rsaesOaep
+pkcs1 8 : MGF1 : mgf1
+pkcs1 9 : PSPECIFIED : pSpecified
+pkcs1 10 : RSASSA-PSS : rsassaPss
+
+pkcs1 11 : RSA-SHA256 : sha256WithRSAEncryption
+pkcs1 12 : RSA-SHA384 : sha384WithRSAEncryption
+pkcs1 13 : RSA-SHA512 : sha512WithRSAEncryption
+pkcs1 14 : RSA-SHA224 : sha224WithRSAEncryption
+
+pkcs 3 : pkcs3
+pkcs3 1 : : dhKeyAgreement
+
+pkcs 5 : pkcs5
+pkcs5 1 : PBE-MD2-DES : pbeWithMD2AndDES-CBC
+pkcs5 3 : PBE-MD5-DES : pbeWithMD5AndDES-CBC
+pkcs5 4 : PBE-MD2-RC2-64 : pbeWithMD2AndRC2-CBC
+pkcs5 6 : PBE-MD5-RC2-64 : pbeWithMD5AndRC2-CBC
+pkcs5 10 : PBE-SHA1-DES : pbeWithSHA1AndDES-CBC
+pkcs5 11 : PBE-SHA1-RC2-64 : pbeWithSHA1AndRC2-CBC
+!Cname id_pbkdf2
+pkcs5 12 : : PBKDF2
+!Cname pbes2
+pkcs5 13 : : PBES2
+!Cname pbmac1
+pkcs5 14 : : PBMAC1
+
+pkcs 7 : pkcs7
+pkcs7 1 : : pkcs7-data
+!Cname pkcs7-signed
+pkcs7 2 : : pkcs7-signedData
+!Cname pkcs7-enveloped
+pkcs7 3 : : pkcs7-envelopedData
+!Cname pkcs7-signedAndEnveloped
+pkcs7 4 : : pkcs7-signedAndEnvelopedData
+!Cname pkcs7-digest
+pkcs7 5 : : pkcs7-digestData
+!Cname pkcs7-encrypted
+pkcs7 6 : : pkcs7-encryptedData
+
+pkcs 9 : pkcs9
+!module pkcs9
+pkcs9 1 : : emailAddress
+pkcs9 2 : : unstructuredName
+pkcs9 3 : : contentType
+pkcs9 4 : : messageDigest
+pkcs9 5 : : signingTime
+pkcs9 6 : : countersignature
+pkcs9 7 : : challengePassword
+pkcs9 8 : : unstructuredAddress
+!Cname extCertAttributes
+pkcs9 9 : : extendedCertificateAttributes
+!global
+
+!Cname ext-req
+pkcs9 14 : extReq : Extension Request
+
+!Cname SMIMECapabilities
+pkcs9 15 : SMIME-CAPS : S/MIME Capabilities
+
+# S/MIME
+!Cname SMIME
+pkcs9 16 : SMIME : S/MIME
+SMIME 0 : id-smime-mod
+SMIME 1 : id-smime-ct
+SMIME 2 : id-smime-aa
+SMIME 3 : id-smime-alg
+SMIME 4 : id-smime-cd
+SMIME 5 : id-smime-spq
+SMIME 6 : id-smime-cti
+
+# S/MIME Modules
+id-smime-mod 1 : id-smime-mod-cms
+id-smime-mod 2 : id-smime-mod-ess
+id-smime-mod 3 : id-smime-mod-oid
+id-smime-mod 4 : id-smime-mod-msg-v3
+id-smime-mod 5 : id-smime-mod-ets-eSignature-88
+id-smime-mod 6 : id-smime-mod-ets-eSignature-97
+id-smime-mod 7 : id-smime-mod-ets-eSigPolicy-88
+id-smime-mod 8 : id-smime-mod-ets-eSigPolicy-97
+
+# S/MIME Content Types
+id-smime-ct 1 : id-smime-ct-receipt
+id-smime-ct 2 : id-smime-ct-authData
+id-smime-ct 3 : id-smime-ct-publishCert
+id-smime-ct 4 : id-smime-ct-TSTInfo
+id-smime-ct 5 : id-smime-ct-TDTInfo
+id-smime-ct 6 : id-smime-ct-contentInfo
+id-smime-ct 7 : id-smime-ct-DVCSRequestData
+id-smime-ct 8 : id-smime-ct-DVCSResponseData
+id-smime-ct 9 : id-smime-ct-compressedData
+id-smime-ct 27 : id-ct-asciiTextWithCRLF
+
+# S/MIME Attributes
+id-smime-aa 1 : id-smime-aa-receiptRequest
+id-smime-aa 2 : id-smime-aa-securityLabel
+id-smime-aa 3 : id-smime-aa-mlExpandHistory
+id-smime-aa 4 : id-smime-aa-contentHint
+id-smime-aa 5 : id-smime-aa-msgSigDigest
+# obsolete
+id-smime-aa 6 : id-smime-aa-encapContentType
+id-smime-aa 7 : id-smime-aa-contentIdentifier
+# obsolete
+id-smime-aa 8 : id-smime-aa-macValue
+id-smime-aa 9 : id-smime-aa-equivalentLabels
+id-smime-aa 10 : id-smime-aa-contentReference
+id-smime-aa 11 : id-smime-aa-encrypKeyPref
+id-smime-aa 12 : id-smime-aa-signingCertificate
+id-smime-aa 13 : id-smime-aa-smimeEncryptCerts
+id-smime-aa 14 : id-smime-aa-timeStampToken
+id-smime-aa 15 : id-smime-aa-ets-sigPolicyId
+id-smime-aa 16 : id-smime-aa-ets-commitmentType
+id-smime-aa 17 : id-smime-aa-ets-signerLocation
+id-smime-aa 18 : id-smime-aa-ets-signerAttr
+id-smime-aa 19 : id-smime-aa-ets-otherSigCert
+id-smime-aa 20 : id-smime-aa-ets-contentTimestamp
+id-smime-aa 21 : id-smime-aa-ets-CertificateRefs
+id-smime-aa 22 : id-smime-aa-ets-RevocationRefs
+id-smime-aa 23 : id-smime-aa-ets-certValues
+id-smime-aa 24 : id-smime-aa-ets-revocationValues
+id-smime-aa 25 : id-smime-aa-ets-escTimeStamp
+id-smime-aa 26 : id-smime-aa-ets-certCRLTimestamp
+id-smime-aa 27 : id-smime-aa-ets-archiveTimeStamp
+id-smime-aa 28 : id-smime-aa-signatureType
+id-smime-aa 29 : id-smime-aa-dvcs-dvc
+
+# S/MIME Algorithm Identifiers
+# obsolete
+id-smime-alg 1 : id-smime-alg-ESDHwith3DES
+# obsolete
+id-smime-alg 2 : id-smime-alg-ESDHwithRC2
+# obsolete
+id-smime-alg 3 : id-smime-alg-3DESwrap
+# obsolete
+id-smime-alg 4 : id-smime-alg-RC2wrap
+id-smime-alg 5 : id-smime-alg-ESDH
+id-smime-alg 6 : id-smime-alg-CMS3DESwrap
+id-smime-alg 7 : id-smime-alg-CMSRC2wrap
+id-smime-alg 9 : id-alg-PWRI-KEK
+
+# S/MIME Certificate Distribution
+id-smime-cd 1 : id-smime-cd-ldap
+
+# S/MIME Signature Policy Qualifier
+id-smime-spq 1 : id-smime-spq-ets-sqt-uri
+id-smime-spq 2 : id-smime-spq-ets-sqt-unotice
+
+# S/MIME Commitment Type Identifier
+id-smime-cti 1 : id-smime-cti-ets-proofOfOrigin
+id-smime-cti 2 : id-smime-cti-ets-proofOfReceipt
+id-smime-cti 3 : id-smime-cti-ets-proofOfDelivery
+id-smime-cti 4 : id-smime-cti-ets-proofOfSender
+id-smime-cti 5 : id-smime-cti-ets-proofOfApproval
+id-smime-cti 6 : id-smime-cti-ets-proofOfCreation
+
+pkcs9 20 : : friendlyName
+pkcs9 21 : : localKeyID
+!Cname ms-csp-name
+1 3 6 1 4 1 311 17 1 : CSPName : Microsoft CSP Name
+1 3 6 1 4 1 311 17 2 : LocalKeySet : Microsoft Local Key set
+!Alias certTypes pkcs9 22
+certTypes 1 : : x509Certificate
+certTypes 2 : : sdsiCertificate
+!Alias crlTypes pkcs9 23
+crlTypes 1 : : x509Crl
+
+!Alias pkcs12 pkcs 12
+!Alias pkcs12-pbeids pkcs12 1
+
+!Cname pbe-WithSHA1And128BitRC4
+pkcs12-pbeids 1 : PBE-SHA1-RC4-128 : pbeWithSHA1And128BitRC4
+!Cname pbe-WithSHA1And40BitRC4
+pkcs12-pbeids 2 : PBE-SHA1-RC4-40 : pbeWithSHA1And40BitRC4
+!Cname pbe-WithSHA1And3_Key_TripleDES-CBC
+pkcs12-pbeids 3 : PBE-SHA1-3DES : pbeWithSHA1And3-KeyTripleDES-CBC
+!Cname pbe-WithSHA1And2_Key_TripleDES-CBC
+pkcs12-pbeids 4 : PBE-SHA1-2DES : pbeWithSHA1And2-KeyTripleDES-CBC
+!Cname pbe-WithSHA1And128BitRC2-CBC
+pkcs12-pbeids 5 : PBE-SHA1-RC2-128 : pbeWithSHA1And128BitRC2-CBC
+!Cname pbe-WithSHA1And40BitRC2-CBC
+pkcs12-pbeids 6 : PBE-SHA1-RC2-40 : pbeWithSHA1And40BitRC2-CBC
+
+!Alias pkcs12-Version1 pkcs12 10
+!Alias pkcs12-BagIds pkcs12-Version1 1
+pkcs12-BagIds 1 : : keyBag
+pkcs12-BagIds 2 : : pkcs8ShroudedKeyBag
+pkcs12-BagIds 3 : : certBag
+pkcs12-BagIds 4 : : crlBag
+pkcs12-BagIds 5 : : secretBag
+pkcs12-BagIds 6 : : safeContentsBag
+
+rsadsi 2 2 : MD2 : md2
+rsadsi 2 4 : MD4 : md4
+rsadsi 2 5 : MD5 : md5
+ : MD5-SHA1 : md5-sha1
+rsadsi 2 6 : : hmacWithMD5
+rsadsi 2 7 : : hmacWithSHA1
+
+# From RFC4231
+rsadsi 2 8 : : hmacWithSHA224
+rsadsi 2 9 : : hmacWithSHA256
+rsadsi 2 10 : : hmacWithSHA384
+rsadsi 2 11 : : hmacWithSHA512
+
+rsadsi 3 2 : RC2-CBC : rc2-cbc
+ : RC2-ECB : rc2-ecb
+!Cname rc2-cfb64
+ : RC2-CFB : rc2-cfb
+!Cname rc2-ofb64
+ : RC2-OFB : rc2-ofb
+ : RC2-40-CBC : rc2-40-cbc
+ : RC2-64-CBC : rc2-64-cbc
+rsadsi 3 4 : RC4 : rc4
+ : RC4-40 : rc4-40
+rsadsi 3 7 : DES-EDE3-CBC : des-ede3-cbc
+rsadsi 3 8 : RC5-CBC : rc5-cbc
+ : RC5-ECB : rc5-ecb
+!Cname rc5-cfb64
+ : RC5-CFB : rc5-cfb
+!Cname rc5-ofb64
+ : RC5-OFB : rc5-ofb
+
+!Cname ms-ext-req
+1 3 6 1 4 1 311 2 1 14 : msExtReq : Microsoft Extension Request
+!Cname ms-code-ind
+1 3 6 1 4 1 311 2 1 21 : msCodeInd : Microsoft Individual Code Signing
+!Cname ms-code-com
+1 3 6 1 4 1 311 2 1 22 : msCodeCom : Microsoft Commercial Code Signing
+!Cname ms-ctl-sign
+1 3 6 1 4 1 311 10 3 1 : msCTLSign : Microsoft Trust List Signing
+!Cname ms-sgc
+1 3 6 1 4 1 311 10 3 3 : msSGC : Microsoft Server Gated Crypto
+!Cname ms-efs
+1 3 6 1 4 1 311 10 3 4 : msEFS : Microsoft Encrypted File System
+!Cname ms-smartcard-login
+1 3 6 1 4 1 311 20 2 2 : msSmartcardLogin : Microsoft Smartcardlogin
+!Cname ms-upn
+1 3 6 1 4 1 311 20 2 3 : msUPN : Microsoft Universal Principal Name
+
+1 3 6 1 4 1 188 7 1 1 2 : IDEA-CBC : idea-cbc
+ : IDEA-ECB : idea-ecb
+!Cname idea-cfb64
+ : IDEA-CFB : idea-cfb
+!Cname idea-ofb64
+ : IDEA-OFB : idea-ofb
+
+1 3 6 1 4 1 3029 1 2 : BF-CBC : bf-cbc
+ : BF-ECB : bf-ecb
+!Cname bf-cfb64
+ : BF-CFB : bf-cfb
+!Cname bf-ofb64
+ : BF-OFB : bf-ofb
+
+!Cname id-pkix
+1 3 6 1 5 5 7 : PKIX
+
+# PKIX Arcs
+id-pkix 0 : id-pkix-mod
+id-pkix 1 : id-pe
+id-pkix 2 : id-qt
+id-pkix 3 : id-kp
+id-pkix 4 : id-it
+id-pkix 5 : id-pkip
+id-pkix 6 : id-alg
+id-pkix 7 : id-cmc
+id-pkix 8 : id-on
+id-pkix 9 : id-pda
+id-pkix 10 : id-aca
+id-pkix 11 : id-qcs
+id-pkix 12 : id-cct
+id-pkix 21 : id-ppl
+id-pkix 48 : id-ad
+
+# PKIX Modules
+id-pkix-mod 1 : id-pkix1-explicit-88
+id-pkix-mod 2 : id-pkix1-implicit-88
+id-pkix-mod 3 : id-pkix1-explicit-93
+id-pkix-mod 4 : id-pkix1-implicit-93
+id-pkix-mod 5 : id-mod-crmf
+id-pkix-mod 6 : id-mod-cmc
+id-pkix-mod 7 : id-mod-kea-profile-88
+id-pkix-mod 8 : id-mod-kea-profile-93
+id-pkix-mod 9 : id-mod-cmp
+id-pkix-mod 10 : id-mod-qualified-cert-88
+id-pkix-mod 11 : id-mod-qualified-cert-93
+id-pkix-mod 12 : id-mod-attribute-cert
+id-pkix-mod 13 : id-mod-timestamp-protocol
+id-pkix-mod 14 : id-mod-ocsp
+id-pkix-mod 15 : id-mod-dvcs
+id-pkix-mod 16 : id-mod-cmp2000
+
+# PKIX Private Extensions
+!Cname info-access
+id-pe 1 : authorityInfoAccess : Authority Information Access
+id-pe 2 : biometricInfo : Biometric Info
+id-pe 3 : qcStatements
+id-pe 4 : ac-auditEntity
+id-pe 5 : ac-targeting
+id-pe 6 : aaControls
+id-pe 7 : sbgp-ipAddrBlock
+id-pe 8 : sbgp-autonomousSysNum
+id-pe 9 : sbgp-routerIdentifier
+id-pe 10 : ac-proxying
+!Cname sinfo-access
+id-pe 11 : subjectInfoAccess : Subject Information Access
+id-pe 14 : proxyCertInfo : Proxy Certificate Information
+
+# PKIX policyQualifiers for Internet policy qualifiers
+id-qt 1 : id-qt-cps : Policy Qualifier CPS
+id-qt 2 : id-qt-unotice : Policy Qualifier User Notice
+id-qt 3 : textNotice
+
+# PKIX key purpose identifiers
+!Cname server-auth
+id-kp 1 : serverAuth : TLS Web Server Authentication
+!Cname client-auth
+id-kp 2 : clientAuth : TLS Web Client Authentication
+!Cname code-sign
+id-kp 3 : codeSigning : Code Signing
+!Cname email-protect
+id-kp 4 : emailProtection : E-mail Protection
+id-kp 5 : ipsecEndSystem : IPSec End System
+id-kp 6 : ipsecTunnel : IPSec Tunnel
+id-kp 7 : ipsecUser : IPSec User
+!Cname time-stamp
+id-kp 8 : timeStamping : Time Stamping
+# From OCSP spec RFC2560
+!Cname OCSP-sign
+id-kp 9 : OCSPSigning : OCSP Signing
+id-kp 10 : DVCS : dvcs
+
+# CMP information types
+id-it 1 : id-it-caProtEncCert
+id-it 2 : id-it-signKeyPairTypes
+id-it 3 : id-it-encKeyPairTypes
+id-it 4 : id-it-preferredSymmAlg
+id-it 5 : id-it-caKeyUpdateInfo
+id-it 6 : id-it-currentCRL
+id-it 7 : id-it-unsupportedOIDs
+# obsolete
+id-it 8 : id-it-subscriptionRequest
+# obsolete
+id-it 9 : id-it-subscriptionResponse
+id-it 10 : id-it-keyPairParamReq
+id-it 11 : id-it-keyPairParamRep
+id-it 12 : id-it-revPassphrase
+id-it 13 : id-it-implicitConfirm
+id-it 14 : id-it-confirmWaitTime
+id-it 15 : id-it-origPKIMessage
+id-it 16 : id-it-suppLangTags
+
+# CRMF registration
+id-pkip 1 : id-regCtrl
+id-pkip 2 : id-regInfo
+
+# CRMF registration controls
+id-regCtrl 1 : id-regCtrl-regToken
+id-regCtrl 2 : id-regCtrl-authenticator
+id-regCtrl 3 : id-regCtrl-pkiPublicationInfo
+id-regCtrl 4 : id-regCtrl-pkiArchiveOptions
+id-regCtrl 5 : id-regCtrl-oldCertID
+id-regCtrl 6 : id-regCtrl-protocolEncrKey
+
+# CRMF registration information
+id-regInfo 1 : id-regInfo-utf8Pairs
+id-regInfo 2 : id-regInfo-certReq
+
+# algorithms
+id-alg 1 : id-alg-des40
+id-alg 2 : id-alg-noSignature
+id-alg 3 : id-alg-dh-sig-hmac-sha1
+id-alg 4 : id-alg-dh-pop
+
+# CMC controls
+id-cmc 1 : id-cmc-statusInfo
+id-cmc 2 : id-cmc-identification
+id-cmc 3 : id-cmc-identityProof
+id-cmc 4 : id-cmc-dataReturn
+id-cmc 5 : id-cmc-transactionId
+id-cmc 6 : id-cmc-senderNonce
+id-cmc 7 : id-cmc-recipientNonce
+id-cmc 8 : id-cmc-addExtensions
+id-cmc 9 : id-cmc-encryptedPOP
+id-cmc 10 : id-cmc-decryptedPOP
+id-cmc 11 : id-cmc-lraPOPWitness
+id-cmc 15 : id-cmc-getCert
+id-cmc 16 : id-cmc-getCRL
+id-cmc 17 : id-cmc-revokeRequest
+id-cmc 18 : id-cmc-regInfo
+id-cmc 19 : id-cmc-responseInfo
+id-cmc 21 : id-cmc-queryPending
+id-cmc 22 : id-cmc-popLinkRandom
+id-cmc 23 : id-cmc-popLinkWitness
+id-cmc 24 : id-cmc-confirmCertAcceptance
+
+# other names
+id-on 1 : id-on-personalData
+id-on 3 : id-on-permanentIdentifier : Permanent Identifier
+
+# personal data attributes
+id-pda 1 : id-pda-dateOfBirth
+id-pda 2 : id-pda-placeOfBirth
+id-pda 3 : id-pda-gender
+id-pda 4 : id-pda-countryOfCitizenship
+id-pda 5 : id-pda-countryOfResidence
+
+# attribute certificate attributes
+id-aca 1 : id-aca-authenticationInfo
+id-aca 2 : id-aca-accessIdentity
+id-aca 3 : id-aca-chargingIdentity
+id-aca 4 : id-aca-group
+# attention : the following seems to be obsolete, replace by 'role'
+id-aca 5 : id-aca-role
+id-aca 6 : id-aca-encAttrs
+
+# qualified certificate statements
+id-qcs 1 : id-qcs-pkixQCSyntax-v1
+
+# CMC content types
+id-cct 1 : id-cct-crs
+id-cct 2 : id-cct-PKIData
+id-cct 3 : id-cct-PKIResponse
+
+# Predefined Proxy Certificate policy languages
+id-ppl 0 : id-ppl-anyLanguage : Any language
+id-ppl 1 : id-ppl-inheritAll : Inherit all
+id-ppl 2 : id-ppl-independent : Independent
+
+# access descriptors for authority info access extension
+!Cname ad-OCSP
+id-ad 1 : OCSP : OCSP
+!Cname ad-ca-issuers
+id-ad 2 : caIssuers : CA Issuers
+!Cname ad-timeStamping
+id-ad 3 : ad_timestamping : AD Time Stamping
+!Cname ad-dvcs
+id-ad 4 : AD_DVCS : ad dvcs
+id-ad 5 : caRepository : CA Repository
+
+
+!Alias id-pkix-OCSP ad-OCSP
+!module id-pkix-OCSP
+!Cname basic
+id-pkix-OCSP 1 : basicOCSPResponse : Basic OCSP Response
+id-pkix-OCSP 2 : Nonce : OCSP Nonce
+id-pkix-OCSP 3 : CrlID : OCSP CRL ID
+id-pkix-OCSP 4 : acceptableResponses : Acceptable OCSP Responses
+id-pkix-OCSP 5 : noCheck : OCSP No Check
+id-pkix-OCSP 6 : archiveCutoff : OCSP Archive Cutoff
+id-pkix-OCSP 7 : serviceLocator : OCSP Service Locator
+id-pkix-OCSP 8 : extendedStatus : Extended OCSP Status
+id-pkix-OCSP 9 : valid
+id-pkix-OCSP 10 : path
+id-pkix-OCSP 11 : trustRoot : Trust Root
+!global
+
+1 3 14 3 2 : algorithm : algorithm
+algorithm 3 : RSA-NP-MD5 : md5WithRSA
+algorithm 6 : DES-ECB : des-ecb
+algorithm 7 : DES-CBC : des-cbc
+!Cname des-ofb64
+algorithm 8 : DES-OFB : des-ofb
+!Cname des-cfb64
+algorithm 9 : DES-CFB : des-cfb
+algorithm 11 : rsaSignature
+!Cname dsa-2
+algorithm 12 : DSA-old : dsaEncryption-old
+algorithm 13 : DSA-SHA : dsaWithSHA
+algorithm 15 : RSA-SHA : shaWithRSAEncryption
+!Cname des-ede-ecb
+algorithm 17 : DES-EDE : des-ede
+!Cname des-ede3-ecb
+ : DES-EDE3 : des-ede3
+ : DES-EDE-CBC : des-ede-cbc
+!Cname des-ede-cfb64
+ : DES-EDE-CFB : des-ede-cfb
+!Cname des-ede3-cfb64
+ : DES-EDE3-CFB : des-ede3-cfb
+!Cname des-ede-ofb64
+ : DES-EDE-OFB : des-ede-ofb
+!Cname des-ede3-ofb64
+ : DES-EDE3-OFB : des-ede3-ofb
+ : DESX-CBC : desx-cbc
+algorithm 18 : SHA : sha
+algorithm 26 : SHA1 : sha1
+!Cname dsaWithSHA1-2
+algorithm 27 : DSA-SHA1-old : dsaWithSHA1-old
+algorithm 29 : RSA-SHA1-2 : sha1WithRSA
+
+1 3 36 3 2 1 : RIPEMD160 : ripemd160
+1 3 36 3 3 1 2 : RSA-RIPEMD160 : ripemd160WithRSA
+
+!Cname sxnet
+1 3 101 1 4 1 : SXNetID : Strong Extranet ID
+
+2 5 : X500 : directory services (X.500)
+
+X500 4 : X509
+X509 3 : CN : commonName
+X509 4 : SN : surname
+X509 5 : : serialNumber
+X509 6 : C : countryName
+X509 7 : L : localityName
+X509 8 : ST : stateOrProvinceName
+X509 9 : street : streetAddress
+X509 10 : O : organizationName
+X509 11 : OU : organizationalUnitName
+X509 12 : title : title
+X509 13 : : description
+X509 14 : : searchGuide
+X509 15 : : businessCategory
+X509 16 : : postalAddress
+X509 17 : : postalCode
+X509 18 : : postOfficeBox
+X509 19 : : physicalDeliveryOfficeName
+X509 20 : : telephoneNumber
+X509 21 : : telexNumber
+X509 22 : : teletexTerminalIdentifier
+X509 23 : : facsimileTelephoneNumber
+X509 24 : : x121Address
+X509 25 : : internationaliSDNNumber
+X509 26 : : registeredAddress
+X509 27 : : destinationIndicator
+X509 28 : : preferredDeliveryMethod
+X509 29 : : presentationAddress
+X509 30 : : supportedApplicationContext
+X509 31 : member :
+X509 32 : owner :
+X509 33 : : roleOccupant
+X509 34 : seeAlso :
+X509 35 : : userPassword
+X509 36 : : userCertificate
+X509 37 : : cACertificate
+X509 38 : : authorityRevocationList
+X509 39 : : certificateRevocationList
+X509 40 : : crossCertificatePair
+X509 41 : name : name
+X509 42 : GN : givenName
+X509 43 : initials : initials
+X509 44 : : generationQualifier
+X509 45 : : x500UniqueIdentifier
+X509 46 : dnQualifier : dnQualifier
+X509 47 : : enhancedSearchGuide
+X509 48 : : protocolInformation
+X509 49 : : distinguishedName
+X509 50 : : uniqueMember
+X509 51 : : houseIdentifier
+X509 52 : : supportedAlgorithms
+X509 53 : : deltaRevocationList
+X509 54 : dmdName :
+X509 65 : : pseudonym
+X509 72 : role : role
+
+X500 8 : X500algorithms : directory services - algorithms
+X500algorithms 1 1 : RSA : rsa
+X500algorithms 3 100 : RSA-MDC2 : mdc2WithRSA
+X500algorithms 3 101 : MDC2 : mdc2
+
+X500 29 : id-ce
+!Cname subject-directory-attributes
+id-ce 9 : subjectDirectoryAttributes : X509v3 Subject Directory Attributes
+!Cname subject-key-identifier
+id-ce 14 : subjectKeyIdentifier : X509v3 Subject Key Identifier
+!Cname key-usage
+id-ce 15 : keyUsage : X509v3 Key Usage
+!Cname private-key-usage-period
+id-ce 16 : privateKeyUsagePeriod : X509v3 Private Key Usage Period
+!Cname subject-alt-name
+id-ce 17 : subjectAltName : X509v3 Subject Alternative Name
+!Cname issuer-alt-name
+id-ce 18 : issuerAltName : X509v3 Issuer Alternative Name
+!Cname basic-constraints
+id-ce 19 : basicConstraints : X509v3 Basic Constraints
+!Cname crl-number
+id-ce 20 : crlNumber : X509v3 CRL Number
+!Cname crl-reason
+id-ce 21 : CRLReason : X509v3 CRL Reason Code
+!Cname invalidity-date
+id-ce 24 : invalidityDate : Invalidity Date
+!Cname delta-crl
+id-ce 27 : deltaCRL : X509v3 Delta CRL Indicator
+!Cname issuing-distribution-point
+id-ce 28 : issuingDistributionPoint : X509v3 Issuing Distrubution Point
+!Cname certificate-issuer
+id-ce 29 : certificateIssuer : X509v3 Certificate Issuer
+!Cname name-constraints
+id-ce 30 : nameConstraints : X509v3 Name Constraints
+!Cname crl-distribution-points
+id-ce 31 : crlDistributionPoints : X509v3 CRL Distribution Points
+!Cname certificate-policies
+id-ce 32 : certificatePolicies : X509v3 Certificate Policies
+!Cname any-policy
+certificate-policies 0 : anyPolicy : X509v3 Any Policy
+!Cname policy-mappings
+id-ce 33 : policyMappings : X509v3 Policy Mappings
+!Cname authority-key-identifier
+id-ce 35 : authorityKeyIdentifier : X509v3 Authority Key Identifier
+!Cname policy-constraints
+id-ce 36 : policyConstraints : X509v3 Policy Constraints
+!Cname ext-key-usage
+id-ce 37 : extendedKeyUsage : X509v3 Extended Key Usage
+!Cname freshest-crl
+id-ce 46 : freshestCRL : X509v3 Freshest CRL
+!Cname inhibit-any-policy
+id-ce 54 : inhibitAnyPolicy : X509v3 Inhibit Any Policy
+!Cname target-information
+id-ce 55 : targetInformation : X509v3 AC Targeting
+!Cname no-rev-avail
+id-ce 56 : noRevAvail : X509v3 No Revocation Available
+
+# From RFC5280
+ext-key-usage 0 : anyExtendedKeyUsage : Any Extended Key Usage
+
+
+!Cname netscape
+2 16 840 1 113730 : Netscape : Netscape Communications Corp.
+!Cname netscape-cert-extension
+netscape 1 : nsCertExt : Netscape Certificate Extension
+!Cname netscape-data-type
+netscape 2 : nsDataType : Netscape Data Type
+!Cname netscape-cert-type
+netscape-cert-extension 1 : nsCertType : Netscape Cert Type
+!Cname netscape-base-url
+netscape-cert-extension 2 : nsBaseUrl : Netscape Base Url
+!Cname netscape-revocation-url
+netscape-cert-extension 3 : nsRevocationUrl : Netscape Revocation Url
+!Cname netscape-ca-revocation-url
+netscape-cert-extension 4 : nsCaRevocationUrl : Netscape CA Revocation Url
+!Cname netscape-renewal-url
+netscape-cert-extension 7 : nsRenewalUrl : Netscape Renewal Url
+!Cname netscape-ca-policy-url
+netscape-cert-extension 8 : nsCaPolicyUrl : Netscape CA Policy Url
+!Cname netscape-ssl-server-name
+netscape-cert-extension 12 : nsSslServerName : Netscape SSL Server Name
+!Cname netscape-comment
+netscape-cert-extension 13 : nsComment : Netscape Comment
+!Cname netscape-cert-sequence
+netscape-data-type 5 : nsCertSequence : Netscape Certificate Sequence
+!Cname ns-sgc
+netscape 4 1 : nsSGC : Netscape Server Gated Crypto
+
+# iso(1)
+iso 3 : ORG : org
+org 6 : DOD : dod
+dod 1 : IANA : iana
+!Alias internet iana
+
+internet 1 : directory : Directory
+internet 2 : mgmt : Management
+internet 3 : experimental : Experimental
+internet 4 : private : Private
+internet 5 : security : Security
+internet 6 : snmpv2 : SNMPv2
+# Documents refer to "internet 7" as "mail". This however leads to ambiguities
+# with RFC2798, Section 9.1.3, where "mail" is defined as the short name for
+# rfc822Mailbox. The short name is therefore here left out for a reason.
+# Subclasses of "mail", e.g. "MIME MHS" don't consitute a problem, as
+# references are realized via long name "Mail" (with capital M).
+internet 7 : : Mail
+
+Private 1 : enterprises : Enterprises
+
+# RFC 2247
+Enterprises 1466 344 : dcobject : dcObject
+
+# RFC 1495
+Mail 1 : mime-mhs : MIME MHS
+mime-mhs 1 : mime-mhs-headings : mime-mhs-headings
+mime-mhs 2 : mime-mhs-bodies : mime-mhs-bodies
+mime-mhs-headings 1 : id-hex-partial-message : id-hex-partial-message
+mime-mhs-headings 2 : id-hex-multipart-message : id-hex-multipart-message
+
+# What the hell are these OIDs, really?
+!Cname rle-compression
+1 1 1 1 666 1 : RLE : run length compression
+!Cname zlib-compression
+id-smime-alg 8 : ZLIB : zlib compression
+
+# AES aka Rijndael
+
+!Alias csor 2 16 840 1 101 3
+!Alias nistAlgorithms csor 4
+!Alias aes nistAlgorithms 1
+
+aes 1 : AES-128-ECB : aes-128-ecb
+aes 2 : AES-128-CBC : aes-128-cbc
+!Cname aes-128-ofb128
+aes 3 : AES-128-OFB : aes-128-ofb
+!Cname aes-128-cfb128
+aes 4 : AES-128-CFB : aes-128-cfb
+aes 5 : id-aes128-wrap
+aes 6 : id-aes128-GCM : aes-128-gcm
+aes 7 : id-aes128-CCM : aes-128-ccm
+aes 8 : id-aes128-wrap-pad
+
+aes 21 : AES-192-ECB : aes-192-ecb
+aes 22 : AES-192-CBC : aes-192-cbc
+!Cname aes-192-ofb128
+aes 23 : AES-192-OFB : aes-192-ofb
+!Cname aes-192-cfb128
+aes 24 : AES-192-CFB : aes-192-cfb
+aes 25 : id-aes192-wrap
+aes 26 : id-aes192-GCM : aes-192-gcm
+aes 27 : id-aes192-CCM : aes-192-ccm
+aes 28 : id-aes192-wrap-pad
+
+aes 41 : AES-256-ECB : aes-256-ecb
+aes 42 : AES-256-CBC : aes-256-cbc
+!Cname aes-256-ofb128
+aes 43 : AES-256-OFB : aes-256-ofb
+!Cname aes-256-cfb128
+aes 44 : AES-256-CFB : aes-256-cfb
+aes 45 : id-aes256-wrap
+aes 46 : id-aes256-GCM : aes-256-gcm
+aes 47 : id-aes256-CCM : aes-256-ccm
+aes 48 : id-aes256-wrap-pad
+
+# There are no OIDs for these modes...
+
+ : AES-128-CFB1 : aes-128-cfb1
+ : AES-192-CFB1 : aes-192-cfb1
+ : AES-256-CFB1 : aes-256-cfb1
+ : AES-128-CFB8 : aes-128-cfb8
+ : AES-192-CFB8 : aes-192-cfb8
+ : AES-256-CFB8 : aes-256-cfb8
+ : AES-128-CTR : aes-128-ctr
+ : AES-192-CTR : aes-192-ctr
+ : AES-256-CTR : aes-256-ctr
+ : AES-128-XTS : aes-128-xts
+ : AES-256-XTS : aes-256-xts
+ : DES-CFB1 : des-cfb1
+ : DES-CFB8 : des-cfb8
+ : DES-EDE3-CFB1 : des-ede3-cfb1
+ : DES-EDE3-CFB8 : des-ede3-cfb8
+
+# OIDs for SHA224, SHA256, SHA385 and SHA512, according to x9.84.
+!Alias nist_hashalgs nistAlgorithms 2
+nist_hashalgs 1 : SHA256 : sha256
+nist_hashalgs 2 : SHA384 : sha384
+nist_hashalgs 3 : SHA512 : sha512
+nist_hashalgs 4 : SHA224 : sha224
+
+# OIDs for dsa-with-sha224 and dsa-with-sha256
+!Alias dsa_with_sha2 nistAlgorithms 3
+dsa_with_sha2 1 : dsa_with_SHA224
+dsa_with_sha2 2 : dsa_with_SHA256
+
+# Hold instruction CRL entry extension
+!Cname hold-instruction-code
+id-ce 23 : holdInstructionCode : Hold Instruction Code
+!Alias holdInstruction X9-57 2
+!Cname hold-instruction-none
+holdInstruction 1 : holdInstructionNone : Hold Instruction None
+!Cname hold-instruction-call-issuer
+holdInstruction 2 : holdInstructionCallIssuer : Hold Instruction Call Issuer
+!Cname hold-instruction-reject
+holdInstruction 3 : holdInstructionReject : Hold Instruction Reject
+
+# OID's from ITU-T. Most of this is defined in RFC 1274. A couple of
+# them are also mentioned in RFC 2247
+itu-t 9 : data
+data 2342 : pss
+pss 19200300 : ucl
+ucl 100 : pilot
+pilot 1 : : pilotAttributeType
+pilot 3 : : pilotAttributeSyntax
+pilot 4 : : pilotObjectClass
+pilot 10 : : pilotGroups
+pilotAttributeSyntax 4 : : iA5StringSyntax
+pilotAttributeSyntax 5 : : caseIgnoreIA5StringSyntax
+pilotObjectClass 3 : : pilotObject
+pilotObjectClass 4 : : pilotPerson
+pilotObjectClass 5 : account
+pilotObjectClass 6 : document
+pilotObjectClass 7 : room
+pilotObjectClass 9 : : documentSeries
+pilotObjectClass 13 : domain : Domain
+pilotObjectClass 14 : : rFC822localPart
+pilotObjectClass 15 : : dNSDomain
+pilotObjectClass 17 : : domainRelatedObject
+pilotObjectClass 18 : : friendlyCountry
+pilotObjectClass 19 : : simpleSecurityObject
+pilotObjectClass 20 : : pilotOrganization
+pilotObjectClass 21 : : pilotDSA
+pilotObjectClass 22 : : qualityLabelledData
+pilotAttributeType 1 : UID : userId
+pilotAttributeType 2 : : textEncodedORAddress
+pilotAttributeType 3 : mail : rfc822Mailbox
+pilotAttributeType 4 : info
+pilotAttributeType 5 : : favouriteDrink
+pilotAttributeType 6 : : roomNumber
+pilotAttributeType 7 : photo
+pilotAttributeType 8 : : userClass
+pilotAttributeType 9 : host
+pilotAttributeType 10 : manager
+pilotAttributeType 11 : : documentIdentifier
+pilotAttributeType 12 : : documentTitle
+pilotAttributeType 13 : : documentVersion
+pilotAttributeType 14 : : documentAuthor
+pilotAttributeType 15 : : documentLocation
+pilotAttributeType 20 : : homeTelephoneNumber
+pilotAttributeType 21 : secretary
+pilotAttributeType 22 : : otherMailbox
+pilotAttributeType 23 : : lastModifiedTime
+pilotAttributeType 24 : : lastModifiedBy
+pilotAttributeType 25 : DC : domainComponent
+pilotAttributeType 26 : : aRecord
+pilotAttributeType 27 : : pilotAttributeType27
+pilotAttributeType 28 : : mXRecord
+pilotAttributeType 29 : : nSRecord
+pilotAttributeType 30 : : sOARecord
+pilotAttributeType 31 : : cNAMERecord
+pilotAttributeType 37 : : associatedDomain
+pilotAttributeType 38 : : associatedName
+pilotAttributeType 39 : : homePostalAddress
+pilotAttributeType 40 : : personalTitle
+pilotAttributeType 41 : : mobileTelephoneNumber
+pilotAttributeType 42 : : pagerTelephoneNumber
+pilotAttributeType 43 : : friendlyCountryName
+# The following clashes with 2.5.4.45, so commented away
+#pilotAttributeType 44 : uid : uniqueIdentifier
+pilotAttributeType 45 : : organizationalStatus
+pilotAttributeType 46 : : janetMailbox
+pilotAttributeType 47 : : mailPreferenceOption
+pilotAttributeType 48 : : buildingName
+pilotAttributeType 49 : : dSAQuality
+pilotAttributeType 50 : : singleLevelQuality
+pilotAttributeType 51 : : subtreeMinimumQuality
+pilotAttributeType 52 : : subtreeMaximumQuality
+pilotAttributeType 53 : : personalSignature
+pilotAttributeType 54 : : dITRedirect
+pilotAttributeType 55 : audio
+pilotAttributeType 56 : : documentPublisher
+
+international-organizations 42 : id-set : Secure Electronic Transactions
+
+id-set 0 : set-ctype : content types
+id-set 1 : set-msgExt : message extensions
+id-set 3 : set-attr
+id-set 5 : set-policy
+id-set 7 : set-certExt : certificate extensions
+id-set 8 : set-brand
+
+set-ctype 0 : setct-PANData
+set-ctype 1 : setct-PANToken
+set-ctype 2 : setct-PANOnly
+set-ctype 3 : setct-OIData
+set-ctype 4 : setct-PI
+set-ctype 5 : setct-PIData
+set-ctype 6 : setct-PIDataUnsigned
+set-ctype 7 : setct-HODInput
+set-ctype 8 : setct-AuthResBaggage
+set-ctype 9 : setct-AuthRevReqBaggage
+set-ctype 10 : setct-AuthRevResBaggage
+set-ctype 11 : setct-CapTokenSeq
+set-ctype 12 : setct-PInitResData
+set-ctype 13 : setct-PI-TBS
+set-ctype 14 : setct-PResData
+set-ctype 16 : setct-AuthReqTBS
+set-ctype 17 : setct-AuthResTBS
+set-ctype 18 : setct-AuthResTBSX
+set-ctype 19 : setct-AuthTokenTBS
+set-ctype 20 : setct-CapTokenData
+set-ctype 21 : setct-CapTokenTBS
+set-ctype 22 : setct-AcqCardCodeMsg
+set-ctype 23 : setct-AuthRevReqTBS
+set-ctype 24 : setct-AuthRevResData
+set-ctype 25 : setct-AuthRevResTBS
+set-ctype 26 : setct-CapReqTBS
+set-ctype 27 : setct-CapReqTBSX
+set-ctype 28 : setct-CapResData
+set-ctype 29 : setct-CapRevReqTBS
+set-ctype 30 : setct-CapRevReqTBSX
+set-ctype 31 : setct-CapRevResData
+set-ctype 32 : setct-CredReqTBS
+set-ctype 33 : setct-CredReqTBSX
+set-ctype 34 : setct-CredResData
+set-ctype 35 : setct-CredRevReqTBS
+set-ctype 36 : setct-CredRevReqTBSX
+set-ctype 37 : setct-CredRevResData
+set-ctype 38 : setct-PCertReqData
+set-ctype 39 : setct-PCertResTBS
+set-ctype 40 : setct-BatchAdminReqData
+set-ctype 41 : setct-BatchAdminResData
+set-ctype 42 : setct-CardCInitResTBS
+set-ctype 43 : setct-MeAqCInitResTBS
+set-ctype 44 : setct-RegFormResTBS
+set-ctype 45 : setct-CertReqData
+set-ctype 46 : setct-CertReqTBS
+set-ctype 47 : setct-CertResData
+set-ctype 48 : setct-CertInqReqTBS
+set-ctype 49 : setct-ErrorTBS
+set-ctype 50 : setct-PIDualSignedTBE
+set-ctype 51 : setct-PIUnsignedTBE
+set-ctype 52 : setct-AuthReqTBE
+set-ctype 53 : setct-AuthResTBE
+set-ctype 54 : setct-AuthResTBEX
+set-ctype 55 : setct-AuthTokenTBE
+set-ctype 56 : setct-CapTokenTBE
+set-ctype 57 : setct-CapTokenTBEX
+set-ctype 58 : setct-AcqCardCodeMsgTBE
+set-ctype 59 : setct-AuthRevReqTBE
+set-ctype 60 : setct-AuthRevResTBE
+set-ctype 61 : setct-AuthRevResTBEB
+set-ctype 62 : setct-CapReqTBE
+set-ctype 63 : setct-CapReqTBEX
+set-ctype 64 : setct-CapResTBE
+set-ctype 65 : setct-CapRevReqTBE
+set-ctype 66 : setct-CapRevReqTBEX
+set-ctype 67 : setct-CapRevResTBE
+set-ctype 68 : setct-CredReqTBE
+set-ctype 69 : setct-CredReqTBEX
+set-ctype 70 : setct-CredResTBE
+set-ctype 71 : setct-CredRevReqTBE
+set-ctype 72 : setct-CredRevReqTBEX
+set-ctype 73 : setct-CredRevResTBE
+set-ctype 74 : setct-BatchAdminReqTBE
+set-ctype 75 : setct-BatchAdminResTBE
+set-ctype 76 : setct-RegFormReqTBE
+set-ctype 77 : setct-CertReqTBE
+set-ctype 78 : setct-CertReqTBEX
+set-ctype 79 : setct-CertResTBE
+set-ctype 80 : setct-CRLNotificationTBS
+set-ctype 81 : setct-CRLNotificationResTBS
+set-ctype 82 : setct-BCIDistributionTBS
+
+set-msgExt 1 : setext-genCrypt : generic cryptogram
+set-msgExt 3 : setext-miAuth : merchant initiated auth
+set-msgExt 4 : setext-pinSecure
+set-msgExt 5 : setext-pinAny
+set-msgExt 7 : setext-track2
+set-msgExt 8 : setext-cv : additional verification
+
+set-policy 0 : set-policy-root
+
+set-certExt 0 : setCext-hashedRoot
+set-certExt 1 : setCext-certType
+set-certExt 2 : setCext-merchData
+set-certExt 3 : setCext-cCertRequired
+set-certExt 4 : setCext-tunneling
+set-certExt 5 : setCext-setExt
+set-certExt 6 : setCext-setQualf
+set-certExt 7 : setCext-PGWYcapabilities
+set-certExt 8 : setCext-TokenIdentifier
+set-certExt 9 : setCext-Track2Data
+set-certExt 10 : setCext-TokenType
+set-certExt 11 : setCext-IssuerCapabilities
+
+set-attr 0 : setAttr-Cert
+set-attr 1 : setAttr-PGWYcap : payment gateway capabilities
+set-attr 2 : setAttr-TokenType
+set-attr 3 : setAttr-IssCap : issuer capabilities
+
+setAttr-Cert 0 : set-rootKeyThumb
+setAttr-Cert 1 : set-addPolicy
+
+setAttr-TokenType 1 : setAttr-Token-EMV
+setAttr-TokenType 2 : setAttr-Token-B0Prime
+
+setAttr-IssCap 3 : setAttr-IssCap-CVM
+setAttr-IssCap 4 : setAttr-IssCap-T2
+setAttr-IssCap 5 : setAttr-IssCap-Sig
+
+setAttr-IssCap-CVM 1 : setAttr-GenCryptgrm : generate cryptogram
+setAttr-IssCap-T2 1 : setAttr-T2Enc : encrypted track 2
+setAttr-IssCap-T2 2 : setAttr-T2cleartxt : cleartext track 2
+
+setAttr-IssCap-Sig 1 : setAttr-TokICCsig : ICC or token signature
+setAttr-IssCap-Sig 2 : setAttr-SecDevSig : secure device signature
+
+set-brand 1 : set-brand-IATA-ATA
+set-brand 30 : set-brand-Diners
+set-brand 34 : set-brand-AmericanExpress
+set-brand 35 : set-brand-JCB
+set-brand 4 : set-brand-Visa
+set-brand 5 : set-brand-MasterCard
+set-brand 6011 : set-brand-Novus
+
+rsadsi 3 10 : DES-CDMF : des-cdmf
+rsadsi 1 1 6 : rsaOAEPEncryptionSET
+
+ : Oakley-EC2N-3 : ipsec3
+ : Oakley-EC2N-4 : ipsec4
+
+iso 0 10118 3 0 55 : whirlpool
+
+# GOST OIDs
+
+member-body 643 2 2 : cryptopro
+member-body 643 2 9 : cryptocom
+
+cryptopro 3 : id-GostR3411-94-with-GostR3410-2001 : GOST R 34.11-94 with GOST R 34.10-2001
+cryptopro 4 : id-GostR3411-94-with-GostR3410-94 : GOST R 34.11-94 with GOST R 34.10-94
+!Cname id-GostR3411-94
+cryptopro 9 : md_gost94 : GOST R 34.11-94
+cryptopro 10 : id-HMACGostR3411-94 : HMAC GOST 34.11-94
+!Cname id-GostR3410-2001
+cryptopro 19 : gost2001 : GOST R 34.10-2001
+!Cname id-GostR3410-94
+cryptopro 20 : gost94 : GOST R 34.10-94
+!Cname id-Gost28147-89
+cryptopro 21 : gost89 : GOST 28147-89
+ : gost89-cnt
+!Cname id-Gost28147-89-MAC
+cryptopro 22 : gost-mac : GOST 28147-89 MAC
+!Cname id-GostR3411-94-prf
+cryptopro 23 : prf-gostr3411-94 : GOST R 34.11-94 PRF
+cryptopro 98 : id-GostR3410-2001DH : GOST R 34.10-2001 DH
+cryptopro 99 : id-GostR3410-94DH : GOST R 34.10-94 DH
+
+cryptopro 14 1 : id-Gost28147-89-CryptoPro-KeyMeshing
+cryptopro 14 0 : id-Gost28147-89-None-KeyMeshing
+
+# GOST parameter set OIDs
+
+cryptopro 30 0 : id-GostR3411-94-TestParamSet
+cryptopro 30 1 : id-GostR3411-94-CryptoProParamSet
+
+cryptopro 31 0 : id-Gost28147-89-TestParamSet
+cryptopro 31 1 : id-Gost28147-89-CryptoPro-A-ParamSet
+cryptopro 31 2 : id-Gost28147-89-CryptoPro-B-ParamSet
+cryptopro 31 3 : id-Gost28147-89-CryptoPro-C-ParamSet
+cryptopro 31 4 : id-Gost28147-89-CryptoPro-D-ParamSet
+cryptopro 31 5 : id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet
+cryptopro 31 6 : id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet
+cryptopro 31 7 : id-Gost28147-89-CryptoPro-RIC-1-ParamSet
+
+cryptopro 32 0 : id-GostR3410-94-TestParamSet
+cryptopro 32 2 : id-GostR3410-94-CryptoPro-A-ParamSet
+cryptopro 32 3 : id-GostR3410-94-CryptoPro-B-ParamSet
+cryptopro 32 4 : id-GostR3410-94-CryptoPro-C-ParamSet
+cryptopro 32 5 : id-GostR3410-94-CryptoPro-D-ParamSet
+
+cryptopro 33 1 : id-GostR3410-94-CryptoPro-XchA-ParamSet
+cryptopro 33 2 : id-GostR3410-94-CryptoPro-XchB-ParamSet
+cryptopro 33 3 : id-GostR3410-94-CryptoPro-XchC-ParamSet
+
+cryptopro 35 0 : id-GostR3410-2001-TestParamSet
+cryptopro 35 1 : id-GostR3410-2001-CryptoPro-A-ParamSet
+cryptopro 35 2 : id-GostR3410-2001-CryptoPro-B-ParamSet
+cryptopro 35 3 : id-GostR3410-2001-CryptoPro-C-ParamSet
+
+cryptopro 36 0 : id-GostR3410-2001-CryptoPro-XchA-ParamSet
+cryptopro 36 1 : id-GostR3410-2001-CryptoPro-XchB-ParamSet
+
+id-GostR3410-94 1 : id-GostR3410-94-a
+id-GostR3410-94 2 : id-GostR3410-94-aBis
+id-GostR3410-94 3 : id-GostR3410-94-b
+id-GostR3410-94 4 : id-GostR3410-94-bBis
+
+# Cryptocom LTD GOST OIDs
+
+cryptocom 1 6 1 : id-Gost28147-89-cc : GOST 28147-89 Cryptocom ParamSet
+!Cname id-GostR3410-94-cc
+cryptocom 1 5 3 : gost94cc : GOST 34.10-94 Cryptocom
+!Cname id-GostR3410-2001-cc
+cryptocom 1 5 4 : gost2001cc : GOST 34.10-2001 Cryptocom
+
+cryptocom 1 3 3 : id-GostR3411-94-with-GostR3410-94-cc : GOST R 34.11-94 with GOST R 34.10-94 Cryptocom
+cryptocom 1 3 4 : id-GostR3411-94-with-GostR3410-2001-cc : GOST R 34.11-94 with GOST R 34.10-2001 Cryptocom
+
+cryptocom 1 8 1 : id-GostR3410-2001-ParamSet-cc : GOST R 3410-2001 Parameter Set Cryptocom
+
+# Definitions for Camellia cipher - CBC MODE
+
+1 2 392 200011 61 1 1 1 2 : CAMELLIA-128-CBC : camellia-128-cbc
+1 2 392 200011 61 1 1 1 3 : CAMELLIA-192-CBC : camellia-192-cbc
+1 2 392 200011 61 1 1 1 4 : CAMELLIA-256-CBC : camellia-256-cbc
+1 2 392 200011 61 1 1 3 2 : id-camellia128-wrap
+1 2 392 200011 61 1 1 3 3 : id-camellia192-wrap
+1 2 392 200011 61 1 1 3 4 : id-camellia256-wrap
+
+# Definitions for Camellia cipher - ECB, CFB, OFB MODE
+
+!Alias ntt-ds 0 3 4401 5
+!Alias camellia ntt-ds 3 1 9
+
+camellia 1 : CAMELLIA-128-ECB : camellia-128-ecb
+!Cname camellia-128-ofb128
+camellia 3 : CAMELLIA-128-OFB : camellia-128-ofb
+!Cname camellia-128-cfb128
+camellia 4 : CAMELLIA-128-CFB : camellia-128-cfb
+
+camellia 21 : CAMELLIA-192-ECB : camellia-192-ecb
+!Cname camellia-192-ofb128
+camellia 23 : CAMELLIA-192-OFB : camellia-192-ofb
+!Cname camellia-192-cfb128
+camellia 24 : CAMELLIA-192-CFB : camellia-192-cfb
+
+camellia 41 : CAMELLIA-256-ECB : camellia-256-ecb
+!Cname camellia-256-ofb128
+camellia 43 : CAMELLIA-256-OFB : camellia-256-ofb
+!Cname camellia-256-cfb128
+camellia 44 : CAMELLIA-256-CFB : camellia-256-cfb
+
+# There are no OIDs for these modes...
+
+ : CAMELLIA-128-CFB1 : camellia-128-cfb1
+ : CAMELLIA-192-CFB1 : camellia-192-cfb1
+ : CAMELLIA-256-CFB1 : camellia-256-cfb1
+ : CAMELLIA-128-CFB8 : camellia-128-cfb8
+ : CAMELLIA-192-CFB8 : camellia-192-cfb8
+ : CAMELLIA-256-CFB8 : camellia-256-cfb8
+
+# Definitions for SEED cipher - ECB, CBC, OFB mode
+
+member-body 410 200004 : KISA : kisa
+kisa 1 3 : SEED-ECB : seed-ecb
+kisa 1 4 : SEED-CBC : seed-cbc
+!Cname seed-cfb128
+kisa 1 5 : SEED-CFB : seed-cfb
+!Cname seed-ofb128
+kisa 1 6 : SEED-OFB : seed-ofb
+
+# There is no OID that just denotes "HMAC" oddly enough...
+
+ : HMAC : hmac
+# Nor CMAC either
+ : CMAC : cmac
+
+# Synthetic composite ciphersuites
+ : RC4-HMAC-MD5 : rc4-hmac-md5
+ : AES-128-CBC-HMAC-SHA1 : aes-128-cbc-hmac-sha1
+ : AES-192-CBC-HMAC-SHA1 : aes-192-cbc-hmac-sha1
+ : AES-256-CBC-HMAC-SHA1 : aes-256-cbc-hmac-sha1
+
+ISO-US 10046 2 1 : dhpublicnumber : X9.42 DH
+
+# RFC 5639 curve OIDs (see http://www.ietf.org/rfc/rfc5639.txt)
+# versionOne OBJECT IDENTIFIER ::= {
+# iso(1) identifified-organization(3) teletrust(36) algorithm(3)
+# signature-algorithm(3) ecSign(2) ecStdCurvesAndGeneration(8)
+# ellipticCurve(1) 1 }
+1 3 36 3 3 2 8 1 1 1 : brainpoolP160r1
+1 3 36 3 3 2 8 1 1 2 : brainpoolP160t1
+1 3 36 3 3 2 8 1 1 3 : brainpoolP192r1
+1 3 36 3 3 2 8 1 1 4 : brainpoolP192t1
+1 3 36 3 3 2 8 1 1 5 : brainpoolP224r1
+1 3 36 3 3 2 8 1 1 6 : brainpoolP224t1
+1 3 36 3 3 2 8 1 1 7 : brainpoolP256r1
+1 3 36 3 3 2 8 1 1 8 : brainpoolP256t1
+1 3 36 3 3 2 8 1 1 9 : brainpoolP320r1
+1 3 36 3 3 2 8 1 1 10 : brainpoolP320t1
+1 3 36 3 3 2 8 1 1 11 : brainpoolP384r1
+1 3 36 3 3 2 8 1 1 12 : brainpoolP384t1
+1 3 36 3 3 2 8 1 1 13 : brainpoolP512r1
+1 3 36 3 3 2 8 1 1 14 : brainpoolP512t1
+
+# ECDH schemes from RFC5753
+!Alias x9-63-scheme 1 3 133 16 840 63 0
+!Alias secg-scheme certicom-arc 1
+
+x9-63-scheme 2 : dhSinglePass-stdDH-sha1kdf-scheme
+secg-scheme 11 0 : dhSinglePass-stdDH-sha224kdf-scheme
+secg-scheme 11 1 : dhSinglePass-stdDH-sha256kdf-scheme
+secg-scheme 11 2 : dhSinglePass-stdDH-sha384kdf-scheme
+secg-scheme 11 3 : dhSinglePass-stdDH-sha512kdf-scheme
+
+x9-63-scheme 3 : dhSinglePass-cofactorDH-sha1kdf-scheme
+secg-scheme 14 0 : dhSinglePass-cofactorDH-sha224kdf-scheme
+secg-scheme 14 1 : dhSinglePass-cofactorDH-sha256kdf-scheme
+secg-scheme 14 2 : dhSinglePass-cofactorDH-sha384kdf-scheme
+secg-scheme 14 3 : dhSinglePass-cofactorDH-sha512kdf-scheme
+# NIDs for use with lookup tables.
+ : dh-std-kdf
+ : dh-cofactor-kdf
diff --git a/crypto/pem/CMakeLists.txt b/crypto/pem/CMakeLists.txt
new file mode 100644
index 0000000..a24d330
--- /dev/null
+++ b/crypto/pem/CMakeLists.txt
@@ -0,0 +1,17 @@
+include_directories(. .. ../../include)
+
+add_library(
+ pem
+
+ OBJECT
+
+ pem_all.c
+ pem_error.c
+ pem_info.c
+ pem_lib.c
+ pem_oth.c
+ pem_pk8.c
+ pem_pkey.c
+ pem_x509.c
+ pem_xaux.c
+)
diff --git a/crypto/pem/pem.h b/crypto/pem/pem.h
new file mode 100644
index 0000000..469fbd2
--- /dev/null
+++ b/crypto/pem/pem.h
@@ -0,0 +1,615 @@
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_PEM_H
+#define OPENSSL_HEADER_PEM_H
+
+#include <openssl/base64.h>
+#include <openssl/bio.h>
+#include <openssl/cipher.h>
+#include <openssl/digest.h>
+#include <openssl/evp.h>
+#include <openssl/stack.h>
+#include <openssl/x509.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define PEM_BUFSIZE 1024
+
+#define PEM_OBJ_UNDEF 0
+#define PEM_OBJ_X509 1
+#define PEM_OBJ_X509_REQ 2
+#define PEM_OBJ_CRL 3
+#define PEM_OBJ_SSL_SESSION 4
+#define PEM_OBJ_PRIV_KEY 10
+#define PEM_OBJ_PRIV_RSA 11
+#define PEM_OBJ_PRIV_DSA 12
+#define PEM_OBJ_PRIV_DH 13
+#define PEM_OBJ_PUB_RSA 14
+#define PEM_OBJ_PUB_DSA 15
+#define PEM_OBJ_PUB_DH 16
+#define PEM_OBJ_DHPARAMS 17
+#define PEM_OBJ_DSAPARAMS 18
+#define PEM_OBJ_PRIV_RSA_PUBLIC 19
+#define PEM_OBJ_PRIV_ECDSA 20
+#define PEM_OBJ_PUB_ECDSA 21
+#define PEM_OBJ_ECPARAMETERS 22
+
+#define PEM_ERROR 30
+#define PEM_DEK_DES_CBC 40
+#define PEM_DEK_IDEA_CBC 45
+#define PEM_DEK_DES_EDE 50
+#define PEM_DEK_DES_ECB 60
+#define PEM_DEK_RSA 70
+#define PEM_DEK_RSA_MD2 80
+#define PEM_DEK_RSA_MD5 90
+
+#define PEM_MD_MD2 NID_md2
+#define PEM_MD_MD5 NID_md5
+#define PEM_MD_SHA NID_sha
+#define PEM_MD_MD2_RSA NID_md2WithRSAEncryption
+#define PEM_MD_MD5_RSA NID_md5WithRSAEncryption
+#define PEM_MD_SHA_RSA NID_sha1WithRSAEncryption
+
+#define PEM_STRING_X509_OLD "X509 CERTIFICATE"
+#define PEM_STRING_X509 "CERTIFICATE"
+#define PEM_STRING_X509_PAIR "CERTIFICATE PAIR"
+#define PEM_STRING_X509_TRUSTED "TRUSTED CERTIFICATE"
+#define PEM_STRING_X509_REQ_OLD "NEW CERTIFICATE REQUEST"
+#define PEM_STRING_X509_REQ "CERTIFICATE REQUEST"
+#define PEM_STRING_X509_CRL "X509 CRL"
+#define PEM_STRING_EVP_PKEY "ANY PRIVATE KEY"
+#define PEM_STRING_PUBLIC "PUBLIC KEY"
+#define PEM_STRING_RSA "RSA PRIVATE KEY"
+#define PEM_STRING_RSA_PUBLIC "RSA PUBLIC KEY"
+#define PEM_STRING_DSA "DSA PRIVATE KEY"
+#define PEM_STRING_DSA_PUBLIC "DSA PUBLIC KEY"
+#define PEM_STRING_PKCS7 "PKCS7"
+#define PEM_STRING_PKCS7_SIGNED "PKCS #7 SIGNED DATA"
+#define PEM_STRING_PKCS8 "ENCRYPTED PRIVATE KEY"
+#define PEM_STRING_PKCS8INF "PRIVATE KEY"
+#define PEM_STRING_DHPARAMS "DH PARAMETERS"
+#define PEM_STRING_DHXPARAMS "X9.42 DH PARAMETERS"
+#define PEM_STRING_SSL_SESSION "SSL SESSION PARAMETERS"
+#define PEM_STRING_DSAPARAMS "DSA PARAMETERS"
+#define PEM_STRING_ECDSA_PUBLIC "ECDSA PUBLIC KEY"
+#define PEM_STRING_ECPARAMETERS "EC PARAMETERS"
+#define PEM_STRING_ECPRIVATEKEY "EC PRIVATE KEY"
+#define PEM_STRING_PARAMETERS "PARAMETERS"
+#define PEM_STRING_CMS "CMS"
+
+ /* Note that this structure is initialised by PEM_SealInit and cleaned up
+ by PEM_SealFinal (at least for now) */
+typedef struct PEM_Encode_Seal_st
+ {
+ EVP_ENCODE_CTX encode;
+ EVP_MD_CTX md;
+ EVP_CIPHER_CTX cipher;
+ } PEM_ENCODE_SEAL_CTX;
+
+/* enc_type is one off */
+#define PEM_TYPE_ENCRYPTED 10
+#define PEM_TYPE_MIC_ONLY 20
+#define PEM_TYPE_MIC_CLEAR 30
+#define PEM_TYPE_CLEAR 40
+
+typedef struct pem_recip_st
+ {
+ char *name;
+ X509_NAME *dn;
+
+ int cipher;
+ int key_enc;
+ /* char iv[8]; unused and wrong size */
+ } PEM_USER;
+
+typedef struct pem_ctx_st
+ {
+ int type; /* what type of object */
+
+ struct {
+ int version;
+ int mode;
+ } proc_type;
+
+ char *domain;
+
+ struct {
+ int cipher;
+ /* unused, and wrong size
+ unsigned char iv[8]; */
+ } DEK_info;
+
+ PEM_USER *originator;
+
+ int num_recipient;
+ PEM_USER **recipient;
+
+ /* XXX(ben): don#t think this is used!
+ STACK *x509_chain; / * certificate chain */
+ EVP_MD *md; /* signature type */
+
+ int md_enc; /* is the md encrypted or not? */
+ int md_len; /* length of md_data */
+ char *md_data; /* message digest, could be pkey encrypted */
+
+ EVP_CIPHER *dec; /* date encryption cipher */
+ int key_len; /* key length */
+ unsigned char *key; /* key */
+ /* unused, and wrong size
+ unsigned char iv[8]; */
+
+
+ int data_enc; /* is the data encrypted */
+ int data_len;
+ unsigned char *data;
+ } PEM_CTX;
+
+/* These macros make the PEM_read/PEM_write functions easier to maintain and
+ * write. Now they are all implemented with either:
+ * IMPLEMENT_PEM_rw(...) or IMPLEMENT_PEM_rw_cb(...)
+ */
+
+#ifdef OPENSSL_NO_FP_API
+
+#define IMPLEMENT_PEM_read_fp(name, type, str, asn1) /**/
+#define IMPLEMENT_PEM_write_fp(name, type, str, asn1) /**/
+#define IMPLEMENT_PEM_write_fp_const(name, type, str, asn1) /**/
+#define IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1) /**/
+#define IMPLEMENT_PEM_write_cb_fp_const(name, type, str, asn1) /**/
+
+#else
+
+#define IMPLEMENT_PEM_read_fp(name, type, str, asn1) \
+type *PEM_read_##name(FILE *fp, type **x, pem_password_cb *cb, void *u)\
+{ \
+return PEM_ASN1_read((d2i_of_void *)d2i_##asn1, str,fp,(void **)x,cb,u); \
+}
+
+#define IMPLEMENT_PEM_write_fp(name, type, str, asn1) \
+int PEM_write_##name(FILE *fp, type *x) \
+{ \
+return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,x,NULL,NULL,0,NULL,NULL); \
+}
+
+#define IMPLEMENT_PEM_write_fp_const(name, type, str, asn1) \
+int PEM_write_##name(FILE *fp, const type *x) \
+{ \
+return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,(void *)x,NULL,NULL,0,NULL,NULL); \
+}
+
+#define IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1) \
+int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \
+ unsigned char *kstr, int klen, pem_password_cb *cb, \
+ void *u) \
+ { \
+ return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,x,enc,kstr,klen,cb,u); \
+ }
+
+#define IMPLEMENT_PEM_write_cb_fp_const(name, type, str, asn1) \
+int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \
+ unsigned char *kstr, int klen, pem_password_cb *cb, \
+ void *u) \
+ { \
+ return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,x,enc,kstr,klen,cb,u); \
+ }
+
+#endif
+
+#define IMPLEMENT_PEM_read_bio(name, type, str, asn1) \
+type *PEM_read_bio_##name(BIO *bp, type **x, pem_password_cb *cb, void *u)\
+{ \
+return PEM_ASN1_read_bio((d2i_of_void *)d2i_##asn1, str,bp,(void **)x,cb,u); \
+}
+
+#define IMPLEMENT_PEM_write_bio(name, type, str, asn1) \
+int PEM_write_bio_##name(BIO *bp, type *x) \
+{ \
+return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,x,NULL,NULL,0,NULL,NULL); \
+}
+
+#define IMPLEMENT_PEM_write_bio_const(name, type, str, asn1) \
+int PEM_write_bio_##name(BIO *bp, const type *x) \
+{ \
+return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,(void *)x,NULL,NULL,0,NULL,NULL); \
+}
+
+#define IMPLEMENT_PEM_write_cb_bio(name, type, str, asn1) \
+int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \
+ unsigned char *kstr, int klen, pem_password_cb *cb, void *u) \
+ { \
+ return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,x,enc,kstr,klen,cb,u); \
+ }
+
+#define IMPLEMENT_PEM_write_cb_bio_const(name, type, str, asn1) \
+int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \
+ unsigned char *kstr, int klen, pem_password_cb *cb, void *u) \
+ { \
+ return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,(void *)x,enc,kstr,klen,cb,u); \
+ }
+
+#define IMPLEMENT_PEM_write(name, type, str, asn1) \
+ IMPLEMENT_PEM_write_bio(name, type, str, asn1) \
+ IMPLEMENT_PEM_write_fp(name, type, str, asn1)
+
+#define IMPLEMENT_PEM_write_const(name, type, str, asn1) \
+ IMPLEMENT_PEM_write_bio_const(name, type, str, asn1) \
+ IMPLEMENT_PEM_write_fp_const(name, type, str, asn1)
+
+#define IMPLEMENT_PEM_write_cb(name, type, str, asn1) \
+ IMPLEMENT_PEM_write_cb_bio(name, type, str, asn1) \
+ IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1)
+
+#define IMPLEMENT_PEM_write_cb_const(name, type, str, asn1) \
+ IMPLEMENT_PEM_write_cb_bio_const(name, type, str, asn1) \
+ IMPLEMENT_PEM_write_cb_fp_const(name, type, str, asn1)
+
+#define IMPLEMENT_PEM_read(name, type, str, asn1) \
+ IMPLEMENT_PEM_read_bio(name, type, str, asn1) \
+ IMPLEMENT_PEM_read_fp(name, type, str, asn1)
+
+#define IMPLEMENT_PEM_rw(name, type, str, asn1) \
+ IMPLEMENT_PEM_read(name, type, str, asn1) \
+ IMPLEMENT_PEM_write(name, type, str, asn1)
+
+#define IMPLEMENT_PEM_rw_const(name, type, str, asn1) \
+ IMPLEMENT_PEM_read(name, type, str, asn1) \
+ IMPLEMENT_PEM_write_const(name, type, str, asn1)
+
+#define IMPLEMENT_PEM_rw_cb(name, type, str, asn1) \
+ IMPLEMENT_PEM_read(name, type, str, asn1) \
+ IMPLEMENT_PEM_write_cb(name, type, str, asn1)
+
+/* These are the same except they are for the declarations */
+
+#if defined(OPENSSL_NO_FP_API)
+
+#define DECLARE_PEM_read_fp(name, type) /**/
+#define DECLARE_PEM_write_fp(name, type) /**/
+#define DECLARE_PEM_write_cb_fp(name, type) /**/
+
+#else
+
+#define DECLARE_PEM_read_fp(name, type) \
+ type *PEM_read_##name(FILE *fp, type **x, pem_password_cb *cb, void *u);
+
+#define DECLARE_PEM_write_fp(name, type) \
+ int PEM_write_##name(FILE *fp, type *x);
+
+#define DECLARE_PEM_write_fp_const(name, type) \
+ int PEM_write_##name(FILE *fp, const type *x);
+
+#define DECLARE_PEM_write_cb_fp(name, type) \
+ int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \
+ unsigned char *kstr, int klen, pem_password_cb *cb, void *u);
+
+#endif
+
+#ifndef OPENSSL_NO_BIO
+#define DECLARE_PEM_read_bio(name, type) \
+ type *PEM_read_bio_##name(BIO *bp, type **x, pem_password_cb *cb, void *u);
+
+#define DECLARE_PEM_write_bio(name, type) \
+ int PEM_write_bio_##name(BIO *bp, type *x);
+
+#define DECLARE_PEM_write_bio_const(name, type) \
+ int PEM_write_bio_##name(BIO *bp, const type *x);
+
+#define DECLARE_PEM_write_cb_bio(name, type) \
+ int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \
+ unsigned char *kstr, int klen, pem_password_cb *cb, void *u);
+
+#else
+
+#define DECLARE_PEM_read_bio(name, type) /**/
+#define DECLARE_PEM_write_bio(name, type) /**/
+#define DECLARE_PEM_write_bio_const(name, type) /**/
+#define DECLARE_PEM_write_cb_bio(name, type) /**/
+
+#endif
+
+#define DECLARE_PEM_write(name, type) \
+ DECLARE_PEM_write_bio(name, type) \
+ DECLARE_PEM_write_fp(name, type)
+
+#define DECLARE_PEM_write_const(name, type) \
+ DECLARE_PEM_write_bio_const(name, type) \
+ DECLARE_PEM_write_fp_const(name, type)
+
+#define DECLARE_PEM_write_cb(name, type) \
+ DECLARE_PEM_write_cb_bio(name, type) \
+ DECLARE_PEM_write_cb_fp(name, type)
+
+#define DECLARE_PEM_read(name, type) \
+ DECLARE_PEM_read_bio(name, type) \
+ DECLARE_PEM_read_fp(name, type)
+
+#define DECLARE_PEM_rw(name, type) \
+ DECLARE_PEM_read(name, type) \
+ DECLARE_PEM_write(name, type)
+
+#define DECLARE_PEM_rw_const(name, type) \
+ DECLARE_PEM_read(name, type) \
+ DECLARE_PEM_write_const(name, type)
+
+#define DECLARE_PEM_rw_cb(name, type) \
+ DECLARE_PEM_read(name, type) \
+ DECLARE_PEM_write_cb(name, type)
+
+#if 1
+/* "userdata": new with OpenSSL 0.9.4 */
+typedef int pem_password_cb(char *buf, int size, int rwflag, void *userdata);
+#else
+/* OpenSSL 0.9.3, 0.9.3a */
+typedef int pem_password_cb(char *buf, int size, int rwflag);
+#endif
+
+int PEM_get_EVP_CIPHER_INFO(char *header, EVP_CIPHER_INFO *cipher);
+int PEM_do_header (EVP_CIPHER_INFO *cipher, unsigned char *data,long *len,
+ pem_password_cb *callback,void *u);
+
+#ifndef OPENSSL_NO_BIO
+int PEM_read_bio(BIO *bp, char **name, char **header,
+ unsigned char **data,long *len);
+int PEM_write_bio(BIO *bp,const char *name, const char *hdr,
+ const unsigned char *data, long len);
+int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm, const char *name, BIO *bp,
+ pem_password_cb *cb, void *u);
+void * PEM_ASN1_read_bio(d2i_of_void *d2i, const char *name, BIO *bp,
+ void **x, pem_password_cb *cb, void *u);
+int PEM_ASN1_write_bio(i2d_of_void *i2d,const char *name,BIO *bp, void *x,
+ const EVP_CIPHER *enc,unsigned char *kstr,int klen,
+ pem_password_cb *cb, void *u);
+
+STACK_OF(X509_INFO) * PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *u);
+int PEM_X509_INFO_write_bio(BIO *bp,X509_INFO *xi, EVP_CIPHER *enc,
+ unsigned char *kstr, int klen, pem_password_cb *cd, void *u);
+#endif
+
+int PEM_read(FILE *fp, char **name, char **header,
+ unsigned char **data,long *len);
+int PEM_write(FILE *fp, const char *name, const char *hdr,
+ const unsigned char *data, long len);
+void * PEM_ASN1_read(d2i_of_void *d2i, const char *name, FILE *fp, void **x,
+ pem_password_cb *cb, void *u);
+int PEM_ASN1_write(i2d_of_void *i2d,const char *name,FILE *fp,
+ void *x,const EVP_CIPHER *enc,unsigned char *kstr,
+ int klen,pem_password_cb *callback, void *u);
+STACK_OF(X509_INFO) * PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk,
+ pem_password_cb *cb, void *u);
+
+int PEM_SealInit(PEM_ENCODE_SEAL_CTX *ctx, EVP_CIPHER *type,
+ EVP_MD *md_type, unsigned char **ek, int *ekl,
+ unsigned char *iv, EVP_PKEY **pubk, int npubk);
+void PEM_SealUpdate(PEM_ENCODE_SEAL_CTX *ctx, unsigned char *out, int *outl,
+ unsigned char *in, int inl);
+int PEM_SealFinal(PEM_ENCODE_SEAL_CTX *ctx, unsigned char *sig,int *sigl,
+ unsigned char *out, int *outl, EVP_PKEY *priv);
+
+void PEM_SignInit(EVP_MD_CTX *ctx, EVP_MD *type);
+void PEM_SignUpdate(EVP_MD_CTX *ctx,unsigned char *d,unsigned int cnt);
+int PEM_SignFinal(EVP_MD_CTX *ctx, unsigned char *sigret,
+ unsigned int *siglen, EVP_PKEY *pkey);
+
+int PEM_def_callback(char *buf, int num, int w, void *key);
+void PEM_proc_type(char *buf, int type);
+void PEM_dek_info(char *buf, const char *type, int len, char *str);
+
+
+DECLARE_PEM_rw(X509, X509)
+
+DECLARE_PEM_rw(X509_AUX, X509)
+
+DECLARE_PEM_rw(X509_CERT_PAIR, X509_CERT_PAIR)
+
+DECLARE_PEM_rw(X509_REQ, X509_REQ)
+DECLARE_PEM_write(X509_REQ_NEW, X509_REQ)
+
+DECLARE_PEM_rw(X509_CRL, X509_CRL)
+
+/* DECLARE_PEM_rw(PKCS7, PKCS7) */
+
+DECLARE_PEM_rw(NETSCAPE_CERT_SEQUENCE, NETSCAPE_CERT_SEQUENCE)
+
+DECLARE_PEM_rw(PKCS8, X509_SIG)
+
+DECLARE_PEM_rw(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO)
+
+#ifndef OPENSSL_NO_RSA
+
+DECLARE_PEM_rw_cb(RSAPrivateKey, RSA)
+
+DECLARE_PEM_rw_const(RSAPublicKey, RSA)
+DECLARE_PEM_rw(RSA_PUBKEY, RSA)
+
+#endif
+
+#ifndef OPENSSL_NO_DSA
+
+DECLARE_PEM_rw_cb(DSAPrivateKey, DSA)
+
+DECLARE_PEM_rw(DSA_PUBKEY, DSA)
+
+DECLARE_PEM_rw_const(DSAparams, DSA)
+
+#endif
+
+#ifndef OPENSSL_NO_EC
+DECLARE_PEM_rw_const(ECPKParameters, EC_GROUP)
+DECLARE_PEM_rw_cb(ECPrivateKey, EC_KEY)
+DECLARE_PEM_rw(EC_PUBKEY, EC_KEY)
+#endif
+
+#ifndef OPENSSL_NO_DH
+
+DECLARE_PEM_rw_const(DHparams, DH)
+DECLARE_PEM_write_const(DHxparams, DH)
+
+#endif
+
+DECLARE_PEM_rw_cb(PrivateKey, EVP_PKEY)
+
+DECLARE_PEM_rw(PUBKEY, EVP_PKEY)
+
+int PEM_write_bio_PKCS8PrivateKey_nid(BIO *bp, EVP_PKEY *x, int nid,
+ char *kstr, int klen,
+ pem_password_cb *cb, void *u);
+int PEM_write_bio_PKCS8PrivateKey(BIO *, EVP_PKEY *, const EVP_CIPHER *,
+ char *, int, pem_password_cb *, void *);
+int i2d_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc,
+ char *kstr, int klen,
+ pem_password_cb *cb, void *u);
+int i2d_PKCS8PrivateKey_nid_bio(BIO *bp, EVP_PKEY *x, int nid,
+ char *kstr, int klen,
+ pem_password_cb *cb, void *u);
+EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, void *u);
+
+int i2d_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc,
+ char *kstr, int klen,
+ pem_password_cb *cb, void *u);
+int i2d_PKCS8PrivateKey_nid_fp(FILE *fp, EVP_PKEY *x, int nid,
+ char *kstr, int klen,
+ pem_password_cb *cb, void *u);
+int PEM_write_PKCS8PrivateKey_nid(FILE *fp, EVP_PKEY *x, int nid,
+ char *kstr, int klen,
+ pem_password_cb *cb, void *u);
+
+EVP_PKEY *d2i_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, void *u);
+
+int PEM_write_PKCS8PrivateKey(FILE *fp,EVP_PKEY *x,const EVP_CIPHER *enc,
+ char *kstr,int klen, pem_password_cb *cd, void *u);
+
+EVP_PKEY *PEM_read_bio_Parameters(BIO *bp, EVP_PKEY **x);
+int PEM_write_bio_Parameters(BIO *bp, EVP_PKEY *x);
+
+
+EVP_PKEY *b2i_PrivateKey(const unsigned char **in, long length);
+EVP_PKEY *b2i_PublicKey(const unsigned char **in, long length);
+EVP_PKEY *b2i_PrivateKey_bio(BIO *in);
+EVP_PKEY *b2i_PublicKey_bio(BIO *in);
+int i2b_PrivateKey_bio(BIO *out, EVP_PKEY *pk);
+int i2b_PublicKey_bio(BIO *out, EVP_PKEY *pk);
+#ifndef OPENSSL_NO_RC4
+EVP_PKEY *b2i_PVK_bio(BIO *in, pem_password_cb *cb, void *u);
+int i2b_PVK_bio(BIO *out, EVP_PKEY *pk, int enclevel,
+ pem_password_cb *cb, void *u);
+#endif
+
+
+void ERR_load_PEM_strings(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#define PEM_F_PEM_read_bio_DHparams 100
+#define PEM_F_load_iv 101
+#define PEM_F_PEM_write 102
+#define PEM_F_do_pk8pkey_fp 103
+#define PEM_F_PEM_read_PrivateKey 104
+#define PEM_F_PEM_read_DHparams 105
+#define PEM_F_PEM_ASN1_read_bio 106
+#define PEM_F_PEM_ASN1_read 107
+#define PEM_F_PEM_get_EVP_CIPHER_INFO 108
+#define PEM_F_PEM_X509_INFO_read 109
+#define PEM_F_PEM_read_bio_Parameters 110
+#define PEM_F_PEM_read 111
+#define PEM_F_PEM_X509_INFO_read_bio 112
+#define PEM_F_PEM_X509_INFO_write_bio 113
+#define PEM_F_PEM_ASN1_write 114
+#define PEM_F_d2i_PKCS8PrivateKey_bio 115
+#define PEM_F_d2i_PKCS8PrivateKey_fp 116
+#define PEM_F_PEM_read_bio_PrivateKey 117
+#define PEM_F_PEM_write_PrivateKey 118
+#define PEM_F_PEM_ASN1_write_bio 119
+#define PEM_F_PEM_do_header 120
+#define PEM_F_PEM_write_bio 121
+#define PEM_F_do_pk8pkey 122
+#define PEM_F_PEM_read_bio 123
+#define PEM_R_NO_START_LINE 100
+#define PEM_R_NOT_PROC_TYPE 101
+#define PEM_R_SHORT_HEADER 102
+#define PEM_R_BAD_IV_CHARS 103
+#define PEM_R_ERROR_CONVERTING_PRIVATE_KEY 104
+#define PEM_R_BAD_END_LINE 105
+#define PEM_R_CIPHER_IS_NULL 106
+#define PEM_R_BAD_MAGIC_NUMBER 107
+#define PEM_R_BAD_DECRYPT 108
+#define PEM_R_UNSUPPORTED_ENCRYPTION 109
+#define PEM_R_PVK_DATA_TOO_SHORT 110
+#define PEM_R_PROBLEMS_GETTING_PASSWORD 111
+#define PEM_R_KEYBLOB_HEADER_PARSE_ERROR 112
+#define PEM_R_BIO_WRITE_FAILURE 113
+#define PEM_R_INCONSISTENT_HEADER 114
+#define PEM_R_PUBLIC_KEY_NO_RSA 115
+#define PEM_R_EXPECTING_PUBLIC_KEY_BLOB 116
+#define PEM_R_KEYBLOB_TOO_SHORT 117
+#define PEM_R_BAD_BASE64_DECODE 118
+#define PEM_R_READ_KEY 119
+#define PEM_R_BAD_PASSWORD_READ 120
+#define PEM_R_UNSUPPORTED_KEY_COMPONENTS 121
+#define PEM_R_UNSUPPORTED_CIPHER 122
+#define PEM_R_NOT_ENCRYPTED 123
+#define PEM_R_NOT_DEK_INFO 124
+#define PEM_R_BAD_VERSION_NUMBER 125
+#define PEM_R_EXPECTING_PRIVATE_KEY_BLOB 126
+#define PEM_R_PVK_TOO_SHORT 127
+
+#endif /* OPENSSL_HEADER_PEM_H */
diff --git a/crypto/pem/pem_all.c b/crypto/pem/pem_all.c
new file mode 100644
index 0000000..ccdc2e8
--- /dev/null
+++ b/crypto/pem/pem_all.c
@@ -0,0 +1,442 @@
+/* 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.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2002 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). */
+
+#include <stdio.h>
+
+#include <openssl/bio.h>
+#include <openssl/dh.h>
+#include <openssl/dsa.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+/*#include <openssl/pkcs7.h> */
+#include <openssl/rsa.h>
+#include <openssl/x509.h>
+
+
+static RSA *pkey_get_rsa(EVP_PKEY *key, RSA **rsa);
+static DSA *pkey_get_dsa(EVP_PKEY *key, DSA **dsa);
+static EC_KEY *pkey_get_eckey(EVP_PKEY *key, EC_KEY **eckey);
+
+
+IMPLEMENT_PEM_rw(X509_REQ, X509_REQ, PEM_STRING_X509_REQ, X509_REQ)
+
+IMPLEMENT_PEM_write(X509_REQ_NEW, X509_REQ, PEM_STRING_X509_REQ_OLD, X509_REQ)
+
+IMPLEMENT_PEM_rw(X509_CRL, X509_CRL, PEM_STRING_X509_CRL, X509_CRL)
+
+
+#ifndef OPENSSL_NO_RSA
+
+/* We treat RSA or DSA private keys as a special case.
+ *
+ * For private keys we read in an EVP_PKEY structure with
+ * PEM_read_bio_PrivateKey() and extract the relevant private
+ * key: this means can handle "traditional" and PKCS#8 formats
+ * transparently.
+ */
+
+static RSA *pkey_get_rsa(EVP_PKEY *key, RSA **rsa)
+{
+ RSA *rtmp;
+ if(!key) return NULL;
+ rtmp = EVP_PKEY_get1_RSA(key);
+ EVP_PKEY_free(key);
+ if(!rtmp) return NULL;
+ if(rsa) {
+ RSA_free(*rsa);
+ *rsa = rtmp;
+ }
+ return rtmp;
+}
+
+RSA *PEM_read_bio_RSAPrivateKey(BIO *bp, RSA **rsa, pem_password_cb *cb,
+ void *u)
+{
+ EVP_PKEY *pktmp;
+ pktmp = PEM_read_bio_PrivateKey(bp, NULL, cb, u);
+ return pkey_get_rsa(pktmp, rsa);
+}
+
+#ifndef OPENSSL_NO_FP_API
+
+RSA *PEM_read_RSAPrivateKey(FILE *fp, RSA **rsa, pem_password_cb *cb,
+ void *u)
+{
+ EVP_PKEY *pktmp;
+ pktmp = PEM_read_PrivateKey(fp, NULL, cb, u);
+ return pkey_get_rsa(pktmp, rsa);
+}
+
+#endif
+
+#ifdef OPENSSL_FIPS
+
+int PEM_write_bio_RSAPrivateKey(BIO *bp, RSA *x, const EVP_CIPHER *enc,
+ unsigned char *kstr, int klen,
+ pem_password_cb *cb, void *u)
+{
+ if (FIPS_mode())
+ {
+ EVP_PKEY *k;
+ int ret;
+ k = EVP_PKEY_new();
+ if (!k)
+ return 0;
+ EVP_PKEY_set1_RSA(k, x);
+
+ ret = PEM_write_bio_PrivateKey(bp, k, enc, kstr, klen, cb, u);
+ EVP_PKEY_free(k);
+ return ret;
+ }
+ else
+ return PEM_ASN1_write_bio((i2d_of_void *)i2d_RSAPrivateKey,
+ PEM_STRING_RSA,bp,x,enc,kstr,klen,cb,u);
+}
+
+#ifndef OPENSSL_NO_FP_API
+int PEM_write_RSAPrivateKey(FILE *fp, RSA *x, const EVP_CIPHER *enc,
+ unsigned char *kstr, int klen,
+ pem_password_cb *cb, void *u)
+{
+ if (FIPS_mode())
+ {
+ EVP_PKEY *k;
+ int ret;
+ k = EVP_PKEY_new();
+ if (!k)
+ return 0;
+
+ EVP_PKEY_set1_RSA(k, x);
+
+ ret = PEM_write_PrivateKey(fp, k, enc, kstr, klen, cb, u);
+ EVP_PKEY_free(k);
+ return ret;
+ }
+ else
+ return PEM_ASN1_write((i2d_of_void *)i2d_RSAPrivateKey,
+ PEM_STRING_RSA,fp,x,enc,kstr,klen,cb,u);
+}
+#endif
+
+#else
+
+IMPLEMENT_PEM_write_cb_const(RSAPrivateKey, RSA, PEM_STRING_RSA, RSAPrivateKey)
+
+#endif
+
+IMPLEMENT_PEM_rw_const(RSAPublicKey, RSA, PEM_STRING_RSA_PUBLIC, RSAPublicKey)
+IMPLEMENT_PEM_rw(RSA_PUBKEY, RSA, PEM_STRING_PUBLIC, RSA_PUBKEY)
+
+#endif
+
+#ifndef OPENSSL_NO_DSA
+
+static DSA *pkey_get_dsa(EVP_PKEY *key, DSA **dsa)
+{
+ DSA *dtmp;
+ if(!key) return NULL;
+ dtmp = EVP_PKEY_get1_DSA(key);
+ EVP_PKEY_free(key);
+ if(!dtmp) return NULL;
+ if(dsa) {
+ DSA_free(*dsa);
+ *dsa = dtmp;
+ }
+ return dtmp;
+}
+
+DSA *PEM_read_bio_DSAPrivateKey(BIO *bp, DSA **dsa, pem_password_cb *cb,
+ void *u)
+{
+ EVP_PKEY *pktmp;
+ pktmp = PEM_read_bio_PrivateKey(bp, NULL, cb, u);
+ return pkey_get_dsa(pktmp, dsa); /* will free pktmp */
+}
+
+#ifdef OPENSSL_FIPS
+
+int PEM_write_bio_DSAPrivateKey(BIO *bp, DSA *x, const EVP_CIPHER *enc,
+ unsigned char *kstr, int klen,
+ pem_password_cb *cb, void *u)
+{
+ if (FIPS_mode())
+ {
+ EVP_PKEY *k;
+ int ret;
+ k = EVP_PKEY_new();
+ if (!k)
+ return 0;
+ EVP_PKEY_set1_DSA(k, x);
+
+ ret = PEM_write_bio_PrivateKey(bp, k, enc, kstr, klen, cb, u);
+ EVP_PKEY_free(k);
+ return ret;
+ }
+ else
+ return PEM_ASN1_write_bio((i2d_of_void *)i2d_DSAPrivateKey,
+ PEM_STRING_DSA,bp,x,enc,kstr,klen,cb,u);
+}
+
+#ifndef OPENSSL_NO_FP_API
+int PEM_write_DSAPrivateKey(FILE *fp, DSA *x, const EVP_CIPHER *enc,
+ unsigned char *kstr, int klen,
+ pem_password_cb *cb, void *u)
+{
+ if (FIPS_mode())
+ {
+ EVP_PKEY *k;
+ int ret;
+ k = EVP_PKEY_new();
+ if (!k)
+ return 0;
+ EVP_PKEY_set1_DSA(k, x);
+ ret = PEM_write_PrivateKey(fp, k, enc, kstr, klen, cb, u);
+ EVP_PKEY_free(k);
+ return ret;
+ }
+ else
+ return PEM_ASN1_write((i2d_of_void *)i2d_DSAPrivateKey,
+ PEM_STRING_DSA,fp,x,enc,kstr,klen,cb,u);
+}
+#endif
+
+#else
+
+IMPLEMENT_PEM_write_cb_const(DSAPrivateKey, DSA, PEM_STRING_DSA, DSAPrivateKey)
+
+#endif
+
+IMPLEMENT_PEM_rw(DSA_PUBKEY, DSA, PEM_STRING_PUBLIC, DSA_PUBKEY)
+
+#ifndef OPENSSL_NO_FP_API
+
+DSA *PEM_read_DSAPrivateKey(FILE *fp, DSA **dsa, pem_password_cb *cb,
+ void *u)
+{
+ EVP_PKEY *pktmp;
+ pktmp = PEM_read_PrivateKey(fp, NULL, cb, u);
+ return pkey_get_dsa(pktmp, dsa); /* will free pktmp */
+}
+
+#endif
+
+IMPLEMENT_PEM_rw_const(DSAparams, DSA, PEM_STRING_DSAPARAMS, DSAparams)
+
+#endif
+
+
+#ifndef OPENSSL_NO_EC
+static EC_KEY *pkey_get_eckey(EVP_PKEY *key, EC_KEY **eckey)
+{
+ EC_KEY *dtmp;
+ if(!key) return NULL;
+ dtmp = EVP_PKEY_get1_EC_KEY(key);
+ EVP_PKEY_free(key);
+ if(!dtmp) return NULL;
+ if(eckey)
+ {
+ EC_KEY_free(*eckey);
+ *eckey = dtmp;
+ }
+ return dtmp;
+}
+
+EC_KEY *PEM_read_bio_ECPrivateKey(BIO *bp, EC_KEY **key, pem_password_cb *cb,
+ void *u)
+{
+ EVP_PKEY *pktmp;
+ pktmp = PEM_read_bio_PrivateKey(bp, NULL, cb, u);
+ return pkey_get_eckey(pktmp, key); /* will free pktmp */
+}
+
+/* TODO(fork): remove this code? */
+/* IMPLEMENT_PEM_rw_const(ECPKParameters, EC_GROUP, PEM_STRING_ECPARAMETERS, ECPKParameters) */
+
+
+
+#ifdef OPENSSL_FIPS
+
+int PEM_write_bio_ECPrivateKey(BIO *bp, EC_KEY *x, const EVP_CIPHER *enc,
+ unsigned char *kstr, int klen,
+ pem_password_cb *cb, void *u)
+{
+ if (FIPS_mode())
+ {
+ EVP_PKEY *k;
+ int ret;
+ k = EVP_PKEY_new();
+ if (!k)
+ return 0;
+ EVP_PKEY_set1_EC_KEY(k, x);
+
+ ret = PEM_write_bio_PrivateKey(bp, k, enc, kstr, klen, cb, u);
+ EVP_PKEY_free(k);
+ return ret;
+ }
+ else
+ return PEM_ASN1_write_bio((i2d_of_void *)i2d_ECPrivateKey,
+ PEM_STRING_ECPRIVATEKEY,
+ bp,x,enc,kstr,klen,cb,u);
+}
+
+#ifndef OPENSSL_NO_FP_API
+int PEM_write_ECPrivateKey(FILE *fp, EC_KEY *x, const EVP_CIPHER *enc,
+ unsigned char *kstr, int klen,
+ pem_password_cb *cb, void *u)
+{
+ if (FIPS_mode())
+ {
+ EVP_PKEY *k;
+ int ret;
+ k = EVP_PKEY_new();
+ if (!k)
+ return 0;
+ EVP_PKEY_set1_EC_KEY(k, x);
+ ret = PEM_write_PrivateKey(fp, k, enc, kstr, klen, cb, u);
+ EVP_PKEY_free(k);
+ return ret;
+ }
+ else
+ return PEM_ASN1_write((i2d_of_void *)i2d_ECPrivateKey,
+ PEM_STRING_ECPRIVATEKEY,
+ fp,x,enc,kstr,klen,cb,u);
+}
+#endif
+
+#else
+
+IMPLEMENT_PEM_write_cb(ECPrivateKey, EC_KEY, PEM_STRING_ECPRIVATEKEY, ECPrivateKey)
+
+#endif
+
+IMPLEMENT_PEM_rw(EC_PUBKEY, EC_KEY, PEM_STRING_PUBLIC, EC_PUBKEY)
+
+#ifndef OPENSSL_NO_FP_API
+
+EC_KEY *PEM_read_ECPrivateKey(FILE *fp, EC_KEY **eckey, pem_password_cb *cb,
+ void *u)
+{
+ EVP_PKEY *pktmp;
+ pktmp = PEM_read_PrivateKey(fp, NULL, cb, u);
+ return pkey_get_eckey(pktmp, eckey); /* will free pktmp */
+}
+
+#endif
+
+#endif
+
+#ifndef OPENSSL_NO_DH
+
+IMPLEMENT_PEM_write_const(DHparams, DH, PEM_STRING_DHPARAMS, DHparams)
+
+/* TODO(fork): remove this code? */
+/* IMPLEMENT_PEM_write_const(DHxparams, DH, PEM_STRING_DHXPARAMS, DHxparams) */
+
+#endif
+
+IMPLEMENT_PEM_rw(PUBKEY, EVP_PKEY, PEM_STRING_PUBLIC, PUBKEY)
diff --git a/crypto/pem/pem_error.c b/crypto/pem/pem_error.c
new file mode 100644
index 0000000..99c9b32
--- /dev/null
+++ b/crypto/pem/pem_error.c
@@ -0,0 +1,73 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/err.h>
+
+#include "pem.h"
+
+const ERR_STRING_DATA PEM_error_string_data[] = {
+ {ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_ASN1_read, 0), "PEM_ASN1_read"},
+ {ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_ASN1_read_bio, 0), "PEM_ASN1_read_bio"},
+ {ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_ASN1_write, 0), "PEM_ASN1_write"},
+ {ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_ASN1_write_bio, 0), "PEM_ASN1_write_bio"},
+ {ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_X509_INFO_read, 0), "PEM_X509_INFO_read"},
+ {ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_X509_INFO_read_bio, 0), "PEM_X509_INFO_read_bio"},
+ {ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_X509_INFO_write_bio, 0), "PEM_X509_INFO_write_bio"},
+ {ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_do_header, 0), "PEM_do_header"},
+ {ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_get_EVP_CIPHER_INFO, 0), "PEM_get_EVP_CIPHER_INFO"},
+ {ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_read, 0), "PEM_read"},
+ {ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_read_DHparams, 0), "PEM_read_DHparams"},
+ {ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_read_PrivateKey, 0), "PEM_read_PrivateKey"},
+ {ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_read_bio, 0), "PEM_read_bio"},
+ {ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_read_bio_DHparams, 0), "PEM_read_bio_DHparams"},
+ {ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_read_bio_Parameters, 0), "PEM_read_bio_Parameters"},
+ {ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_read_bio_PrivateKey, 0), "PEM_read_bio_PrivateKey"},
+ {ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_write, 0), "PEM_write"},
+ {ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_write_PrivateKey, 0), "PEM_write_PrivateKey"},
+ {ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_write_bio, 0), "PEM_write_bio"},
+ {ERR_PACK(ERR_LIB_PEM, PEM_F_d2i_PKCS8PrivateKey_bio, 0), "d2i_PKCS8PrivateKey_bio"},
+ {ERR_PACK(ERR_LIB_PEM, PEM_F_d2i_PKCS8PrivateKey_fp, 0), "d2i_PKCS8PrivateKey_fp"},
+ {ERR_PACK(ERR_LIB_PEM, PEM_F_do_pk8pkey, 0), "do_pk8pkey"},
+ {ERR_PACK(ERR_LIB_PEM, PEM_F_do_pk8pkey_fp, 0), "do_pk8pkey_fp"},
+ {ERR_PACK(ERR_LIB_PEM, PEM_F_load_iv, 0), "load_iv"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_BAD_BASE64_DECODE), "BAD_BASE64_DECODE"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_BAD_DECRYPT), "BAD_DECRYPT"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_BAD_END_LINE), "BAD_END_LINE"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_BAD_IV_CHARS), "BAD_IV_CHARS"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_BAD_MAGIC_NUMBER), "BAD_MAGIC_NUMBER"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_BAD_PASSWORD_READ), "BAD_PASSWORD_READ"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_BAD_VERSION_NUMBER), "BAD_VERSION_NUMBER"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_BIO_WRITE_FAILURE), "BIO_WRITE_FAILURE"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_CIPHER_IS_NULL), "CIPHER_IS_NULL"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_ERROR_CONVERTING_PRIVATE_KEY), "ERROR_CONVERTING_PRIVATE_KEY"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_EXPECTING_PRIVATE_KEY_BLOB), "EXPECTING_PRIVATE_KEY_BLOB"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_EXPECTING_PUBLIC_KEY_BLOB), "EXPECTING_PUBLIC_KEY_BLOB"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_INCONSISTENT_HEADER), "INCONSISTENT_HEADER"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_KEYBLOB_HEADER_PARSE_ERROR), "KEYBLOB_HEADER_PARSE_ERROR"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_KEYBLOB_TOO_SHORT), "KEYBLOB_TOO_SHORT"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_NOT_DEK_INFO), "NOT_DEK_INFO"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_NOT_ENCRYPTED), "NOT_ENCRYPTED"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_NOT_PROC_TYPE), "NOT_PROC_TYPE"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_NO_START_LINE), "NO_START_LINE"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_PROBLEMS_GETTING_PASSWORD), "PROBLEMS_GETTING_PASSWORD"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_PUBLIC_KEY_NO_RSA), "PUBLIC_KEY_NO_RSA"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_PVK_DATA_TOO_SHORT), "PVK_DATA_TOO_SHORT"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_PVK_TOO_SHORT), "PVK_TOO_SHORT"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_READ_KEY), "READ_KEY"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_SHORT_HEADER), "SHORT_HEADER"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_UNSUPPORTED_CIPHER), "UNSUPPORTED_CIPHER"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_UNSUPPORTED_ENCRYPTION), "UNSUPPORTED_ENCRYPTION"},
+ {ERR_PACK(ERR_LIB_PEM, 0, PEM_R_UNSUPPORTED_KEY_COMPONENTS), "UNSUPPORTED_KEY_COMPONENTS"},
+ {0, NULL},
+};
diff --git a/crypto/pem/pem_info.c b/crypto/pem/pem_info.c
new file mode 100644
index 0000000..9536e49
--- /dev/null
+++ b/crypto/pem/pem_info.c
@@ -0,0 +1,409 @@
+/* crypto/pem/pem_info.c */
+/* 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/pem.h>
+
+#include <stdio.h>
+#include <assert.h>
+
+#include <openssl/buf.h>
+#include <openssl/dsa.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/rsa.h>
+#include <openssl/x509.h>
+
+
+#ifndef OPENSSL_NO_FP_API
+STACK_OF(X509_INFO) *PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *u)
+ {
+ BIO *b;
+ STACK_OF(X509_INFO) *ret;
+
+ if ((b=BIO_new(BIO_s_file())) == NULL)
+ {
+ OPENSSL_PUT_ERROR(PEM, PEM_X509_INFO_read, ERR_R_BUF_LIB);
+ return(0);
+ }
+ BIO_set_fp(b,fp,BIO_NOCLOSE);
+ ret=PEM_X509_INFO_read_bio(b,sk,cb,u);
+ BIO_free(b);
+ return(ret);
+ }
+#endif
+
+STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *u)
+ {
+ X509_INFO *xi=NULL;
+ char *name=NULL,*header=NULL;
+ void *pp;
+ unsigned char *data=NULL;
+ const unsigned char *p;
+ long len,error=0;
+ int ok=0;
+ STACK_OF(X509_INFO) *ret=NULL;
+ unsigned int i,raw,ptype;
+ d2i_of_void *d2i = 0;
+
+ if (sk == NULL)
+ {
+ if ((ret=sk_X509_INFO_new_null()) == NULL)
+ {
+ OPENSSL_PUT_ERROR(PEM, PEM_X509_INFO_read_bio, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+ else
+ ret=sk;
+
+ if ((xi=X509_INFO_new()) == NULL) goto err;
+ for (;;)
+ {
+ raw=0;
+ ptype = 0;
+ i=PEM_read_bio(bp,&name,&header,&data,&len);
+ if (i == 0)
+ {
+ error=ERR_GET_REASON(ERR_peek_last_error());
+ if (error == PEM_R_NO_START_LINE)
+ {
+ ERR_clear_error();
+ break;
+ }
+ goto err;
+ }
+start:
+ if ( (strcmp(name,PEM_STRING_X509) == 0) ||
+ (strcmp(name,PEM_STRING_X509_OLD) == 0))
+ {
+ d2i=(D2I_OF(void))d2i_X509;
+ if (xi->x509 != NULL)
+ {
+ if (!sk_X509_INFO_push(ret,xi)) goto err;
+ if ((xi=X509_INFO_new()) == NULL) goto err;
+ goto start;
+ }
+ pp=&(xi->x509);
+ }
+ else if ((strcmp(name,PEM_STRING_X509_TRUSTED) == 0))
+ {
+ d2i=(D2I_OF(void))d2i_X509_AUX;
+ if (xi->x509 != NULL)
+ {
+ if (!sk_X509_INFO_push(ret,xi)) goto err;
+ if ((xi=X509_INFO_new()) == NULL) goto err;
+ goto start;
+ }
+ pp=&(xi->x509);
+ }
+ else if (strcmp(name,PEM_STRING_X509_CRL) == 0)
+ {
+ d2i=(D2I_OF(void))d2i_X509_CRL;
+ if (xi->crl != NULL)
+ {
+ if (!sk_X509_INFO_push(ret,xi)) goto err;
+ if ((xi=X509_INFO_new()) == NULL) goto err;
+ goto start;
+ }
+ pp=&(xi->crl);
+ }
+ else
+#ifndef OPENSSL_NO_RSA
+ if (strcmp(name,PEM_STRING_RSA) == 0)
+ {
+ d2i=(D2I_OF(void))d2i_RSAPrivateKey;
+ if (xi->x_pkey != NULL)
+ {
+ if (!sk_X509_INFO_push(ret,xi)) goto err;
+ if ((xi=X509_INFO_new()) == NULL) goto err;
+ goto start;
+ }
+
+ xi->enc_data=NULL;
+ xi->enc_len=0;
+
+ xi->x_pkey=X509_PKEY_new();
+ ptype=EVP_PKEY_RSA;
+ pp=&xi->x_pkey->dec_pkey;
+ if ((int)strlen(header) > 10) /* assume encrypted */
+ raw=1;
+ }
+ else
+#endif
+#ifndef OPENSSL_NO_DSA
+ if (strcmp(name,PEM_STRING_DSA) == 0)
+ {
+ d2i=(D2I_OF(void))d2i_DSAPrivateKey;
+ if (xi->x_pkey != NULL)
+ {
+ if (!sk_X509_INFO_push(ret,xi)) goto err;
+ if ((xi=X509_INFO_new()) == NULL) goto err;
+ goto start;
+ }
+
+ xi->enc_data=NULL;
+ xi->enc_len=0;
+
+ xi->x_pkey=X509_PKEY_new();
+ ptype = EVP_PKEY_DSA;
+ pp=&xi->x_pkey->dec_pkey;
+ if ((int)strlen(header) > 10) /* assume encrypted */
+ raw=1;
+ }
+ else
+#endif
+#ifndef OPENSSL_NO_EC
+ if (strcmp(name,PEM_STRING_ECPRIVATEKEY) == 0)
+ {
+ d2i=(D2I_OF(void))d2i_ECPrivateKey;
+ if (xi->x_pkey != NULL)
+ {
+ if (!sk_X509_INFO_push(ret,xi)) goto err;
+ if ((xi=X509_INFO_new()) == NULL) goto err;
+ goto start;
+ }
+
+ xi->enc_data=NULL;
+ xi->enc_len=0;
+
+ xi->x_pkey=X509_PKEY_new();
+ ptype = EVP_PKEY_EC;
+ pp=&xi->x_pkey->dec_pkey;
+ if ((int)strlen(header) > 10) /* assume encrypted */
+ raw=1;
+ }
+ else
+#endif
+ {
+ d2i=NULL;
+ pp=NULL;
+ }
+
+ if (d2i != NULL)
+ {
+ if (!raw)
+ {
+ EVP_CIPHER_INFO cipher;
+
+ if (!PEM_get_EVP_CIPHER_INFO(header,&cipher))
+ goto err;
+ if (!PEM_do_header(&cipher,data,&len,cb,u))
+ goto err;
+ p=data;
+ if (ptype)
+ {
+ if (!d2i_PrivateKey(ptype, pp, &p, len))
+ {
+ OPENSSL_PUT_ERROR(PEM, PEM_X509_INFO_read_bio, 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);
+ goto err;
+ }
+ }
+ else
+ { /* encrypted RSA data */
+ if (!PEM_get_EVP_CIPHER_INFO(header,
+ &xi->enc_cipher)) goto err;
+ xi->enc_data=(char *)data;
+ xi->enc_len=(int)len;
+ data=NULL;
+ }
+ }
+ else {
+ /* unknown */
+ }
+ if (name != NULL) OPENSSL_free(name);
+ if (header != NULL) OPENSSL_free(header);
+ if (data != NULL) OPENSSL_free(data);
+ name=NULL;
+ header=NULL;
+ data=NULL;
+ }
+
+ /* if the last one hasn't been pushed yet and there is anything
+ * in it then add it to the stack ...
+ */
+ if ((xi->x509 != NULL) || (xi->crl != NULL) ||
+ (xi->x_pkey != NULL) || (xi->enc_data != NULL))
+ {
+ if (!sk_X509_INFO_push(ret,xi)) goto err;
+ xi=NULL;
+ }
+ ok=1;
+err:
+ if (xi != NULL) X509_INFO_free(xi);
+ if (!ok)
+ {
+ for (i=0; ((int)i)<sk_X509_INFO_num(ret); i++)
+ {
+ xi=sk_X509_INFO_value(ret,i);
+ X509_INFO_free(xi);
+ }
+ if (ret != sk) sk_X509_INFO_free(ret);
+ ret=NULL;
+ }
+
+ if (name != NULL) OPENSSL_free(name);
+ if (header != NULL) OPENSSL_free(header);
+ if (data != NULL) OPENSSL_free(data);
+ return(ret);
+ }
+
+
+/* A TJH addition */
+int PEM_X509_INFO_write_bio(BIO *bp, X509_INFO *xi, EVP_CIPHER *enc,
+ unsigned char *kstr, int klen, pem_password_cb *cb, void *u)
+ {
+ EVP_CIPHER_CTX ctx;
+ int i,ret=0;
+ unsigned char *data=NULL;
+ const char *objstr=NULL;
+ char buf[PEM_BUFSIZE];
+ unsigned char *iv=NULL;
+ unsigned iv_len = 0;
+
+ if (enc != NULL)
+ {
+ iv_len = EVP_CIPHER_iv_length(enc);
+ objstr=OBJ_nid2sn(EVP_CIPHER_nid(enc));
+ if (objstr == NULL)
+ {
+ OPENSSL_PUT_ERROR(PEM, PEM_X509_INFO_write_bio, PEM_R_UNSUPPORTED_CIPHER);
+ goto err;
+ }
+ }
+
+ /* now for the fun part ... if we have a private key then
+ * we have to be able to handle a not-yet-decrypted key
+ * being written out correctly ... if it is decrypted or
+ * it is non-encrypted then we use the base code
+ */
+ if (xi->x_pkey!=NULL)
+ {
+ if ( (xi->enc_data!=NULL) && (xi->enc_len>0) )
+ {
+ if (enc == NULL)
+ {
+ OPENSSL_PUT_ERROR(PEM, PEM_X509_INFO_write_bio, PEM_R_CIPHER_IS_NULL);
+ goto err;
+ }
+
+ /* copy from weirdo names into more normal things */
+ iv=xi->enc_cipher.iv;
+ data=(unsigned char *)xi->enc_data;
+ i=xi->enc_len;
+
+ /* we take the encryption data from the
+ * internal stuff rather than what the
+ * user has passed us ... as we have to
+ * match exactly for some strange reason
+ */
+ objstr=OBJ_nid2sn(
+ EVP_CIPHER_nid(xi->enc_cipher.cipher));
+ if (objstr == NULL)
+ {
+ OPENSSL_PUT_ERROR(PEM, PEM_X509_INFO_write_bio, PEM_R_UNSUPPORTED_CIPHER);
+ goto err;
+ }
+
+ /* create the right magic header stuff */
+ assert(strlen(objstr)+23+2*iv_len+13 <= sizeof buf);
+ buf[0]='\0';
+ PEM_proc_type(buf,PEM_TYPE_ENCRYPTED);
+ PEM_dek_info(buf,objstr,iv_len,(char *)iv);
+
+ /* use the normal code to write things out */
+ i=PEM_write_bio(bp,PEM_STRING_RSA,buf,data,i);
+ if (i <= 0) goto err;
+ }
+ else
+ {
+ /* Add DSA/DH */
+#ifndef OPENSSL_NO_RSA
+ /* normal optionally encrypted stuff */
+ if (PEM_write_bio_RSAPrivateKey(bp,
+ xi->x_pkey->dec_pkey->pkey.rsa,
+ enc,kstr,klen,cb,u)<=0)
+ goto err;
+#endif
+ }
+ }
+
+ /* if we have a certificate then write it out now */
+ if ((xi->x509 != NULL) && (PEM_write_bio_X509(bp,xi->x509) <= 0))
+ goto err;
+
+ /* we are ignoring anything else that is loaded into the X509_INFO
+ * structure for the moment ... as I don't need it so I'm not
+ * coding it here and Eric can do it when this makes it into the
+ * base library --tjh
+ */
+
+ ret=1;
+
+err:
+ OPENSSL_cleanse((char *)&ctx,sizeof(ctx));
+ OPENSSL_cleanse(buf,PEM_BUFSIZE);
+ return(ret);
+ }
diff --git a/crypto/pem/pem_lib.c b/crypto/pem/pem_lib.c
new file mode 100644
index 0000000..23efd0a
--- /dev/null
+++ b/crypto/pem/pem_lib.c
@@ -0,0 +1,825 @@
+/* crypto/pem/pem_lib.c */
+/* 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 <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#include <openssl/base64.h>
+#include <openssl/buf.h>
+#include <openssl/des.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/pem.h>
+#include <openssl/rand.h>
+#include <openssl/x509.h>
+
+#include "../evp/internal.h"
+
+
+#define MIN_LENGTH 4
+
+static int load_iv(char **fromp,unsigned char *to, int num);
+static int check_pem(const char *nm, const char *name);
+int pem_check_suffix(const char *pem_str, const char *suffix);
+
+void PEM_proc_type(char *buf, int type)
+ {
+ const char *str;
+
+ if (type == PEM_TYPE_ENCRYPTED)
+ str="ENCRYPTED";
+ else if (type == PEM_TYPE_MIC_CLEAR)
+ str="MIC-CLEAR";
+ else if (type == PEM_TYPE_MIC_ONLY)
+ str="MIC-ONLY";
+ else
+ str="BAD-TYPE";
+
+ BUF_strlcat(buf,"Proc-Type: 4,",PEM_BUFSIZE);
+ BUF_strlcat(buf,str,PEM_BUFSIZE);
+ BUF_strlcat(buf,"\n",PEM_BUFSIZE);
+ }
+
+void PEM_dek_info(char *buf, const char *type, int len, char *str)
+ {
+ static const unsigned char map[17]="0123456789ABCDEF";
+ long i;
+ int j;
+
+ BUF_strlcat(buf,"DEK-Info: ",PEM_BUFSIZE);
+ BUF_strlcat(buf,type,PEM_BUFSIZE);
+ BUF_strlcat(buf,",",PEM_BUFSIZE);
+ j=strlen(buf);
+ if (j + (len * 2) + 1 > PEM_BUFSIZE)
+ return;
+ for (i=0; i<len; i++)
+ {
+ buf[j+i*2] =map[(str[i]>>4)&0x0f];
+ buf[j+i*2+1]=map[(str[i] )&0x0f];
+ }
+ buf[j+i*2]='\n';
+ buf[j+i*2+1]='\0';
+ }
+
+#ifndef OPENSSL_NO_FP_API
+void *PEM_ASN1_read(d2i_of_void *d2i, const char *name, FILE *fp, void **x,
+ pem_password_cb *cb, void *u)
+ {
+ BIO *b;
+ void *ret;
+
+ if ((b=BIO_new(BIO_s_file())) == NULL)
+ {
+ OPENSSL_PUT_ERROR(PEM, PEM_ASN1_read, ERR_R_BUF_LIB);
+ return(0);
+ }
+ BIO_set_fp(b,fp,BIO_NOCLOSE);
+ ret=PEM_ASN1_read_bio(d2i,name,b,x,cb,u);
+ BIO_free(b);
+ return(ret);
+ }
+#endif
+
+static int check_pem(const char *nm, const char *name)
+{
+ /* Normal matching nm and name */
+ if (!strcmp(nm,name)) return 1;
+
+ /* Make PEM_STRING_EVP_PKEY match any private key */
+
+ if(!strcmp(name,PEM_STRING_EVP_PKEY))
+ {
+ int slen;
+ const EVP_PKEY_ASN1_METHOD *ameth;
+ if(!strcmp(nm,PEM_STRING_PKCS8))
+ return 1;
+ if(!strcmp(nm,PEM_STRING_PKCS8INF))
+ return 1;
+ slen = pem_check_suffix(nm, "PRIVATE KEY");
+ if (slen > 0)
+ {
+ /* NB: ENGINE implementations wont contain
+ * a deprecated old private key decode function
+ * so don't look for them.
+ */
+ ameth = EVP_PKEY_asn1_find_str(NULL, nm, slen);
+ if (ameth && ameth->old_priv_decode)
+ return 1;
+ }
+ return 0;
+ }
+
+ if(!strcmp(name,PEM_STRING_PARAMETERS))
+ {
+ int slen;
+ const EVP_PKEY_ASN1_METHOD *ameth;
+ slen = pem_check_suffix(nm, "PARAMETERS");
+ if (slen > 0)
+ {
+ ENGINE *e;
+ ameth = EVP_PKEY_asn1_find_str(&e, nm, slen);
+ if (ameth)
+ {
+ int r;
+ if (ameth->param_decode)
+ r = 1;
+ else
+ r = 0;
+ return r;
+ }
+ }
+ return 0;
+ }
+ /* If reading DH parameters handle X9.42 DH format too */
+ if(!strcmp(nm,PEM_STRING_DHXPARAMS) &&
+ !strcmp(name,PEM_STRING_DHPARAMS)) return 1;
+
+ /* Permit older strings */
+
+ if(!strcmp(nm,PEM_STRING_X509_OLD) &&
+ !strcmp(name,PEM_STRING_X509)) return 1;
+
+ if(!strcmp(nm,PEM_STRING_X509_REQ_OLD) &&
+ !strcmp(name,PEM_STRING_X509_REQ)) return 1;
+
+ /* Allow normal certs to be read as trusted certs */
+ if(!strcmp(nm,PEM_STRING_X509) &&
+ !strcmp(name,PEM_STRING_X509_TRUSTED)) return 1;
+
+ if(!strcmp(nm,PEM_STRING_X509_OLD) &&
+ !strcmp(name,PEM_STRING_X509_TRUSTED)) return 1;
+
+ /* Some CAs use PKCS#7 with CERTIFICATE headers */
+ if(!strcmp(nm, PEM_STRING_X509) &&
+ !strcmp(name, PEM_STRING_PKCS7)) return 1;
+
+ if(!strcmp(nm, PEM_STRING_PKCS7_SIGNED) &&
+ !strcmp(name, PEM_STRING_PKCS7)) return 1;
+
+#ifndef OPENSSL_NO_CMS
+ if(!strcmp(nm, PEM_STRING_X509) &&
+ !strcmp(name, PEM_STRING_CMS)) return 1;
+ /* Allow CMS to be read from PKCS#7 headers */
+ if(!strcmp(nm, PEM_STRING_PKCS7) &&
+ !strcmp(name, PEM_STRING_CMS)) return 1;
+#endif
+
+ return 0;
+}
+
+int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm, const char *name, BIO *bp,
+ pem_password_cb *cb, void *u)
+ {
+ EVP_CIPHER_INFO cipher;
+ char *nm=NULL,*header=NULL;
+ unsigned char *data=NULL;
+ long len;
+ int ret = 0;
+
+ for (;;)
+ {
+ if (!PEM_read_bio(bp,&nm,&header,&data,&len)) {
+ if(ERR_GET_REASON(ERR_peek_error()) ==
+ PEM_R_NO_START_LINE)
+ ERR_add_error_data(2, "Expecting: ", name);
+ return 0;
+ }
+ if(check_pem(nm, name)) break;
+ OPENSSL_free(nm);
+ OPENSSL_free(header);
+ OPENSSL_free(data);
+ }
+ if (!PEM_get_EVP_CIPHER_INFO(header,&cipher)) goto err;
+ if (!PEM_do_header(&cipher,data,&len,cb,u)) goto err;
+
+ *pdata = data;
+ *plen = len;
+
+ if (pnm)
+ *pnm = nm;
+
+ ret = 1;
+
+err:
+ if (!ret || !pnm) OPENSSL_free(nm);
+ OPENSSL_free(header);
+ if (!ret) OPENSSL_free(data);
+ return ret;
+ }
+
+#ifndef OPENSSL_NO_FP_API
+int PEM_ASN1_write(i2d_of_void *i2d, const char *name, FILE *fp,
+ void *x, const EVP_CIPHER *enc, unsigned char *kstr,
+ int klen, pem_password_cb *callback, void *u)
+ {
+ BIO *b;
+ int ret;
+
+ if ((b=BIO_new(BIO_s_file())) == NULL)
+ {
+ OPENSSL_PUT_ERROR(PEM, PEM_ASN1_write, ERR_R_BUF_LIB);
+ return(0);
+ }
+ BIO_set_fp(b,fp,BIO_NOCLOSE);
+ ret=PEM_ASN1_write_bio(i2d,name,b,x,enc,kstr,klen,callback,u);
+ BIO_free(b);
+ return(ret);
+ }
+#endif
+
+int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp,
+ void *x, const EVP_CIPHER *enc, unsigned char *kstr,
+ int klen, pem_password_cb *callback, void *u)
+ {
+ EVP_CIPHER_CTX ctx;
+ int dsize=0,i,j,ret=0;
+ unsigned char *p,*data=NULL;
+ const char *objstr=NULL;
+ char buf[PEM_BUFSIZE];
+ unsigned char key[EVP_MAX_KEY_LENGTH];
+ unsigned char iv[EVP_MAX_IV_LENGTH];
+
+ if (enc != NULL)
+ {
+ objstr=OBJ_nid2sn(EVP_CIPHER_nid(enc));
+ if (objstr == NULL)
+ {
+ OPENSSL_PUT_ERROR(PEM, PEM_ASN1_write_bio, PEM_R_UNSUPPORTED_CIPHER);
+ goto err;
+ }
+ }
+
+ if ((dsize=i2d(x,NULL)) < 0)
+ {
+ OPENSSL_PUT_ERROR(PEM, PEM_ASN1_write_bio, ERR_R_ASN1_LIB);
+ dsize=0;
+ goto err;
+ }
+ /* dzise + 8 bytes are needed */
+ /* actually it needs the cipher block size extra... */
+ data=(unsigned char *)OPENSSL_malloc((unsigned int)dsize+20);
+ if (data == NULL)
+ {
+ OPENSSL_PUT_ERROR(PEM, PEM_ASN1_write_bio, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ p=data;
+ i=i2d(x,&p);
+
+ if (enc != NULL)
+ {
+ const unsigned iv_len = EVP_CIPHER_iv_length(enc);
+
+ if (kstr == NULL)
+ {
+ klen = 0;
+ if (callback)
+ klen=(*callback)(buf,PEM_BUFSIZE,1,u);
+ if (klen <= 0)
+ {
+ OPENSSL_PUT_ERROR(PEM, PEM_ASN1_write_bio, PEM_R_READ_KEY);
+ goto err;
+ }
+#ifdef CHARSET_EBCDIC
+ /* Convert the pass phrase from EBCDIC */
+ ebcdic2ascii(buf, buf, klen);
+#endif
+ kstr=(unsigned char *)buf;
+ }
+ assert(iv_len <= (int)sizeof(iv));
+ if (RAND_pseudo_bytes(iv,iv_len) < 0) /* Generate a salt */
+ goto err;
+ /* The 'iv' is used as the iv and as a salt. It is
+ * NOT taken from the BytesToKey function */
+ if (!EVP_BytesToKey(enc,EVP_md5(),iv,kstr,klen,1,key,NULL))
+ goto err;
+
+ if (kstr == (unsigned char *)buf) OPENSSL_cleanse(buf,PEM_BUFSIZE);
+
+ assert(strlen(objstr)+23+2*iv_len+13 <= sizeof buf);
+
+ buf[0]='\0';
+ PEM_proc_type(buf,PEM_TYPE_ENCRYPTED);
+ PEM_dek_info(buf,objstr,iv_len,(char *)iv);
+ /* k=strlen(buf); */
+
+ EVP_CIPHER_CTX_init(&ctx);
+ ret = 1;
+ if (!EVP_EncryptInit_ex(&ctx,enc,NULL,key,iv)
+ || !EVP_EncryptUpdate(&ctx,data,&j,data,i)
+ || !EVP_EncryptFinal_ex(&ctx,&(data[j]),&i))
+ ret = 0;
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ if (ret == 0)
+ goto err;
+ i+=j;
+ }
+ else
+ {
+ ret=1;
+ buf[0]='\0';
+ }
+ i=PEM_write_bio(bp,name,buf,data,i);
+ if (i <= 0) ret=0;
+err:
+ OPENSSL_cleanse(key,sizeof(key));
+ OPENSSL_cleanse(iv,sizeof(iv));
+ OPENSSL_cleanse((char *)&ctx,sizeof(ctx));
+ OPENSSL_cleanse(buf,PEM_BUFSIZE);
+ if (data != NULL)
+ {
+ OPENSSL_cleanse(data,(unsigned int)dsize);
+ OPENSSL_free(data);
+ }
+ return(ret);
+ }
+
+int PEM_do_header(EVP_CIPHER_INFO *cipher, unsigned char *data, long *plen,
+ pem_password_cb *callback,void *u)
+ {
+ int i,j,o,klen;
+ long len;
+ EVP_CIPHER_CTX ctx;
+ unsigned char key[EVP_MAX_KEY_LENGTH];
+ char buf[PEM_BUFSIZE];
+
+ len= *plen;
+
+ if (cipher->cipher == NULL) return(1);
+
+ klen = 0;
+ if (callback)
+ klen=callback(buf,PEM_BUFSIZE,0,u);
+ if (klen <= 0)
+ {
+ OPENSSL_PUT_ERROR(PEM, PEM_do_header, PEM_R_BAD_PASSWORD_READ);
+ return(0);
+ }
+#ifdef CHARSET_EBCDIC
+ /* Convert the pass phrase from EBCDIC */
+ ebcdic2ascii(buf, buf, klen);
+#endif
+
+ if (!EVP_BytesToKey(cipher->cipher,EVP_md5(),&(cipher->iv[0]),
+ (unsigned char *)buf,klen,1,key,NULL))
+ return 0;
+
+ j=(int)len;
+ EVP_CIPHER_CTX_init(&ctx);
+ o = EVP_DecryptInit_ex(&ctx,cipher->cipher,NULL, key,&(cipher->iv[0]));
+ if (o)
+ o = EVP_DecryptUpdate(&ctx,data,&i,data,j);
+ if (o)
+ o = EVP_DecryptFinal_ex(&ctx,&(data[i]),&j);
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ OPENSSL_cleanse((char *)buf,sizeof(buf));
+ OPENSSL_cleanse((char *)key,sizeof(key));
+ if (!o)
+ {
+ OPENSSL_PUT_ERROR(PEM, PEM_do_header, PEM_R_BAD_DECRYPT);
+ return(0);
+ }
+ j+=i;
+ *plen=j;
+ return(1);
+ }
+
+static const EVP_CIPHER* cipher_by_name(const char *name) {
+ if (strcmp(name, "DES-CBC") == 0) {
+ return EVP_des_cbc();
+ } else if (strcmp(name, "AES-128-CBC") == 0) {
+ return EVP_aes_128_cbc();
+ } else if (strcmp(name, "AES-256-CBC") == 0) {
+ return EVP_aes_256_cbc();
+ } else {
+ return NULL;
+ }
+}
+
+int PEM_get_EVP_CIPHER_INFO(char *header, EVP_CIPHER_INFO *cipher)
+ {
+ const EVP_CIPHER *enc=NULL;
+ char *p,c;
+ char **header_pp = &header;
+
+ cipher->cipher=NULL;
+ 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); }
+ 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); }
+ for (; (*header != '\n') && (*header != '\0'); header++)
+ ;
+ if (*header == '\0')
+ { OPENSSL_PUT_ERROR(PEM, PEM_get_EVP_CIPHER_INFO, 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); }
+ header+=10;
+
+ p=header;
+ for (;;)
+ {
+ c= *header;
+#ifndef CHARSET_EBCDIC
+ if (!( ((c >= 'A') && (c <= 'Z')) || (c == '-') ||
+ ((c >= '0') && (c <= '9'))))
+ break;
+#else
+ if (!( isupper(c) || (c == '-') ||
+ isdigit(c)))
+ break;
+#endif
+ header++;
+ }
+ *header='\0';
+ cipher->cipher=enc=cipher_by_name(p);
+ *header=c;
+ header++;
+
+ if (enc == NULL)
+ {
+ OPENSSL_PUT_ERROR(PEM, PEM_get_EVP_CIPHER_INFO, PEM_R_UNSUPPORTED_ENCRYPTION);
+ return(0);
+ }
+ if (!load_iv(header_pp,&(cipher->iv[0]),EVP_CIPHER_iv_length(enc)))
+ return(0);
+
+ return(1);
+ }
+
+static int load_iv(char **fromp, unsigned char *to, int num)
+ {
+ int v,i;
+ char *from;
+
+ from= *fromp;
+ for (i=0; i<num; i++) to[i]=0;
+ num*=2;
+ for (i=0; i<num; i++)
+ {
+ if ((*from >= '0') && (*from <= '9'))
+ v= *from-'0';
+ else if ((*from >= 'A') && (*from <= 'F'))
+ v= *from-'A'+10;
+ else if ((*from >= 'a') && (*from <= 'f'))
+ v= *from-'a'+10;
+ else
+ {
+ OPENSSL_PUT_ERROR(PEM, load_iv, PEM_R_BAD_IV_CHARS);
+ return(0);
+ }
+ from++;
+ to[i/2]|=v<<(long)((!(i&1))*4);
+ }
+
+ *fromp=from;
+ return(1);
+ }
+
+#ifndef OPENSSL_NO_FP_API
+int PEM_write(FILE *fp, const char *name, const char *header,
+ const unsigned char *data, long len)
+ {
+ BIO *b;
+ int ret;
+
+ if ((b=BIO_new(BIO_s_file())) == NULL)
+ {
+ OPENSSL_PUT_ERROR(PEM, PEM_write, ERR_R_BUF_LIB);
+ return(0);
+ }
+ BIO_set_fp(b,fp,BIO_NOCLOSE);
+ ret=PEM_write_bio(b, name, header, data,len);
+ BIO_free(b);
+ return(ret);
+ }
+#endif
+
+int PEM_write_bio(BIO *bp, const char *name, const char *header,
+ const unsigned char *data, long len)
+ {
+ int nlen,n,i,j,outl;
+ unsigned char *buf = NULL;
+ EVP_ENCODE_CTX ctx;
+ int reason=ERR_R_BUF_LIB;
+
+ EVP_EncodeInit(&ctx);
+ nlen=strlen(name);
+
+ if ( (BIO_write(bp,"-----BEGIN ",11) != 11) ||
+ (BIO_write(bp,name,nlen) != nlen) ||
+ (BIO_write(bp,"-----\n",6) != 6))
+ goto err;
+
+ i=strlen(header);
+ if (i > 0)
+ {
+ if ( (BIO_write(bp,header,i) != i) ||
+ (BIO_write(bp,"\n",1) != 1))
+ goto err;
+ }
+
+ buf = OPENSSL_malloc(PEM_BUFSIZE*8);
+ if (buf == NULL)
+ {
+ reason=ERR_R_MALLOC_FAILURE;
+ goto err;
+ }
+
+ i=j=0;
+ while (len > 0)
+ {
+ n=(int)((len>(PEM_BUFSIZE*5))?(PEM_BUFSIZE*5):len);
+ EVP_EncodeUpdate(&ctx,buf,&outl,&(data[j]),n);
+ if ((outl) && (BIO_write(bp,(char *)buf,outl) != outl))
+ goto err;
+ i+=outl;
+ len-=n;
+ j+=n;
+ }
+ EVP_EncodeFinal(&ctx,buf,&outl);
+ if ((outl > 0) && (BIO_write(bp,(char *)buf,outl) != outl)) goto err;
+ OPENSSL_cleanse(buf, PEM_BUFSIZE*8);
+ OPENSSL_free(buf);
+ buf = NULL;
+ if ( (BIO_write(bp,"-----END ",9) != 9) ||
+ (BIO_write(bp,name,nlen) != nlen) ||
+ (BIO_write(bp,"-----\n",6) != 6))
+ goto err;
+ return(i+outl);
+err:
+ if (buf) {
+ OPENSSL_cleanse(buf, PEM_BUFSIZE*8);
+ OPENSSL_free(buf);
+ }
+ OPENSSL_PUT_ERROR(PEM, PEM_write_bio, reason);
+ return(0);
+ }
+
+#ifndef OPENSSL_NO_FP_API
+int PEM_read(FILE *fp, char **name, char **header, unsigned char **data,
+ long *len)
+ {
+ BIO *b;
+ int ret;
+
+ if ((b=BIO_new(BIO_s_file())) == NULL)
+ {
+ OPENSSL_PUT_ERROR(PEM, PEM_read, ERR_R_BUF_LIB);
+ return(0);
+ }
+ BIO_set_fp(b,fp,BIO_NOCLOSE);
+ ret=PEM_read_bio(b, name, header, data,len);
+ BIO_free(b);
+ return(ret);
+ }
+#endif
+
+int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data,
+ long *len)
+ {
+ EVP_ENCODE_CTX ctx;
+ int end=0,i,k,bl=0,hl=0,nohead=0;
+ char buf[256];
+ BUF_MEM *nameB;
+ BUF_MEM *headerB;
+ BUF_MEM *dataB,*tmpB;
+
+ nameB=BUF_MEM_new();
+ headerB=BUF_MEM_new();
+ dataB=BUF_MEM_new();
+ if ((nameB == NULL) || (headerB == NULL) || (dataB == NULL))
+ {
+ BUF_MEM_free(nameB);
+ BUF_MEM_free(headerB);
+ BUF_MEM_free(dataB);
+ OPENSSL_PUT_ERROR(PEM, PEM_read_bio, ERR_R_MALLOC_FAILURE);
+ return(0);
+ }
+
+ buf[254]='\0';
+ for (;;)
+ {
+ i=BIO_gets(bp,buf,254);
+
+ if (i <= 0)
+ {
+ OPENSSL_PUT_ERROR(PEM, PEM_read_bio, PEM_R_NO_START_LINE);
+ goto err;
+ }
+
+ while ((i >= 0) && (buf[i] <= ' ')) i--;
+ buf[++i]='\n'; buf[++i]='\0';
+
+ if (strncmp(buf,"-----BEGIN ",11) == 0)
+ {
+ i=strlen(&(buf[11]));
+
+ if (strncmp(&(buf[11+i-6]),"-----\n",6) != 0)
+ continue;
+ if (!BUF_MEM_grow(nameB,i+9))
+ {
+ OPENSSL_PUT_ERROR(PEM, PEM_read_bio, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ memcpy(nameB->data,&(buf[11]),i-6);
+ nameB->data[i-6]='\0';
+ break;
+ }
+ }
+ hl=0;
+ if (!BUF_MEM_grow(headerB,256))
+ { OPENSSL_PUT_ERROR(PEM, PEM_read_bio, ERR_R_MALLOC_FAILURE); goto err; }
+ headerB->data[0]='\0';
+ for (;;)
+ {
+ i=BIO_gets(bp,buf,254);
+ if (i <= 0) break;
+
+ while ((i >= 0) && (buf[i] <= ' ')) i--;
+ buf[++i]='\n'; buf[++i]='\0';
+
+ 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; }
+ if (strncmp(buf,"-----END ",9) == 0)
+ {
+ nohead=1;
+ break;
+ }
+ memcpy(&(headerB->data[hl]),buf,i);
+ headerB->data[hl+i]='\0';
+ hl+=i;
+ }
+
+ bl=0;
+ if (!BUF_MEM_grow(dataB,1024))
+ { OPENSSL_PUT_ERROR(PEM, PEM_read_bio, ERR_R_MALLOC_FAILURE); goto err; }
+ dataB->data[0]='\0';
+ if (!nohead)
+ {
+ for (;;)
+ {
+ i=BIO_gets(bp,buf,254);
+ if (i <= 0) break;
+
+ while ((i >= 0) && (buf[i] <= ' ')) i--;
+ buf[++i]='\n'; buf[++i]='\0';
+
+ if (i != 65) end=1;
+ if (strncmp(buf,"-----END ",9) == 0)
+ break;
+ if (i > 65) break;
+ if (!BUF_MEM_grow_clean(dataB,i+bl+9))
+ {
+ OPENSSL_PUT_ERROR(PEM, PEM_read_bio, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ memcpy(&(dataB->data[bl]),buf,i);
+ dataB->data[bl+i]='\0';
+ bl+=i;
+ if (end)
+ {
+ buf[0]='\0';
+ i=BIO_gets(bp,buf,254);
+ if (i <= 0) break;
+
+ while ((i >= 0) && (buf[i] <= ' ')) i--;
+ buf[++i]='\n'; buf[++i]='\0';
+
+ break;
+ }
+ }
+ }
+ else
+ {
+ tmpB=headerB;
+ headerB=dataB;
+ dataB=tmpB;
+ bl=hl;
+ }
+ i=strlen(nameB->data);
+ if ( (strncmp(buf,"-----END ",9) != 0) ||
+ (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);
+ goto err;
+ }
+
+ EVP_DecodeInit(&ctx);
+ i=EVP_DecodeUpdate(&ctx,
+ (unsigned char *)dataB->data,&bl,
+ (unsigned char *)dataB->data,bl);
+ if (i < 0)
+ {
+ OPENSSL_PUT_ERROR(PEM, PEM_read_bio, 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);
+ goto err;
+ }
+ bl+=k;
+
+ if (bl == 0) goto err;
+ *name=nameB->data;
+ *header=headerB->data;
+ *data=(unsigned char *)dataB->data;
+ *len=bl;
+ OPENSSL_free(nameB);
+ OPENSSL_free(headerB);
+ OPENSSL_free(dataB);
+ return(1);
+err:
+ BUF_MEM_free(nameB);
+ BUF_MEM_free(headerB);
+ BUF_MEM_free(dataB);
+ return(0);
+ }
+
+/* Check pem string and return prefix length.
+ * If for example the pem_str == "RSA PRIVATE KEY" and suffix = "PRIVATE KEY"
+ * the return value is 3 for the string "RSA".
+ */
+
+int pem_check_suffix(const char *pem_str, const char *suffix)
+ {
+ int pem_len = strlen(pem_str);
+ int suffix_len = strlen(suffix);
+ const char *p;
+ if (suffix_len + 1 >= pem_len)
+ return 0;
+ p = pem_str + pem_len - suffix_len;
+ if (strcmp(p, suffix))
+ return 0;
+ p--;
+ if (*p != ' ')
+ return 0;
+ return p - pem_str;
+ }
+
diff --git a/crypto/pem/pem_oth.c b/crypto/pem/pem_oth.c
new file mode 100644
index 0000000..20d12b6
--- /dev/null
+++ b/crypto/pem/pem_oth.c
@@ -0,0 +1,89 @@
+/* crypto/pem/pem_oth.c */
+/* 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/pem.h>
+
+#include <stdio.h>
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/evp.h>
+#include <openssl/obj.h>
+#include <openssl/rand.h>
+#include <openssl/x509.h>
+
+
+/* Handle 'other' PEMs: not private keys */
+
+void *PEM_ASN1_read_bio(d2i_of_void *d2i, const char *name, BIO *bp, void **x,
+ pem_password_cb *cb, void *u)
+ {
+ const unsigned char *p=NULL;
+ unsigned char *data=NULL;
+ long len;
+ char *ret=NULL;
+
+ if (!PEM_bytes_read_bio(&data, &len, NULL, name, bp, cb, u))
+ return NULL;
+ p = data;
+ ret=d2i(x,&p,len);
+ if (ret == NULL)
+ OPENSSL_PUT_ERROR(PEM, PEM_ASN1_read_bio, ERR_R_ASN1_LIB);
+ OPENSSL_free(data);
+ return ret;
+ }
diff --git a/crypto/pem/pem_pk8.c b/crypto/pem/pem_pk8.c
new file mode 100644
index 0000000..18cfb92
--- /dev/null
+++ b/crypto/pem/pem_pk8.c
@@ -0,0 +1,243 @@
+/* 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/pem.h>
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/obj.h>
+#include <openssl/pkcs8.h>
+#include <openssl/rand.h>
+#include <openssl/x509.h>
+
+
+static int do_pk8pkey(BIO *bp, EVP_PKEY *x, int isder,
+ int nid, const EVP_CIPHER *enc,
+ char *kstr, int klen,
+ pem_password_cb *cb, void *u);
+static int do_pk8pkey_fp(FILE *bp, EVP_PKEY *x, int isder,
+ int nid, const EVP_CIPHER *enc,
+ char *kstr, int klen,
+ pem_password_cb *cb, void *u);
+
+/* These functions write a private key in PKCS#8 format: it is a "drop in"
+ * replacement for PEM_write_bio_PrivateKey() and friends. As usual if 'enc'
+ * is NULL then it uses the unencrypted private key form. The 'nid' versions
+ * uses PKCS#5 v1.5 PBE algorithms whereas the others use PKCS#5 v2.0.
+ */
+
+int PEM_write_bio_PKCS8PrivateKey_nid(BIO *bp, EVP_PKEY *x, int nid,
+ char *kstr, int klen,
+ pem_password_cb *cb, void *u)
+{
+ return do_pk8pkey(bp, x, 0, nid, NULL, kstr, klen, cb, u);
+}
+
+int PEM_write_bio_PKCS8PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc,
+ char *kstr, int klen,
+ pem_password_cb *cb, void *u)
+{
+ return do_pk8pkey(bp, x, 0, -1, enc, kstr, klen, cb, u);
+}
+
+int i2d_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc,
+ char *kstr, int klen,
+ pem_password_cb *cb, void *u)
+{
+ return do_pk8pkey(bp, x, 1, -1, enc, kstr, klen, cb, u);
+}
+
+int i2d_PKCS8PrivateKey_nid_bio(BIO *bp, EVP_PKEY *x, int nid,
+ char *kstr, int klen,
+ pem_password_cb *cb, void *u)
+{
+ return do_pk8pkey(bp, x, 1, nid, NULL, kstr, klen, cb, u);
+}
+
+static int do_pk8pkey(BIO *bp, EVP_PKEY *x, int isder, int nid, const EVP_CIPHER *enc,
+ char *kstr, int klen,
+ pem_password_cb *cb, void *u)
+{
+ X509_SIG *p8;
+ PKCS8_PRIV_KEY_INFO *p8inf;
+ char buf[PEM_BUFSIZE];
+ int ret;
+ if(!(p8inf = EVP_PKEY2PKCS8(x))) {
+ OPENSSL_PUT_ERROR(PEM, do_pk8pkey, PEM_R_ERROR_CONVERTING_PRIVATE_KEY);
+ return 0;
+ }
+ if(enc || (nid != -1)) {
+ if(!kstr) {
+ klen = 0;
+ if (cb)
+ klen = cb(buf, PEM_BUFSIZE, 1, u);
+ if(klen <= 0) {
+ OPENSSL_PUT_ERROR(PEM, do_pk8pkey, PEM_R_READ_KEY);
+ PKCS8_PRIV_KEY_INFO_free(p8inf);
+ return 0;
+ }
+
+ kstr = buf;
+ }
+ p8 = PKCS8_encrypt(nid, enc, kstr, klen, NULL, 0, 0, p8inf);
+ if(kstr == buf) OPENSSL_cleanse(buf, klen);
+ PKCS8_PRIV_KEY_INFO_free(p8inf);
+ if(isder) ret = i2d_PKCS8_bio(bp, p8);
+ else ret = PEM_write_bio_PKCS8(bp, p8);
+ X509_SIG_free(p8);
+ return ret;
+ } else {
+ if(isder) ret = i2d_PKCS8_PRIV_KEY_INFO_bio(bp, p8inf);
+ else ret = PEM_write_bio_PKCS8_PRIV_KEY_INFO(bp, p8inf);
+ PKCS8_PRIV_KEY_INFO_free(p8inf);
+ return ret;
+ }
+}
+
+EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, void *u)
+{
+ PKCS8_PRIV_KEY_INFO *p8inf = NULL;
+ X509_SIG *p8 = NULL;
+ int klen;
+ EVP_PKEY *ret;
+ char psbuf[PEM_BUFSIZE];
+ p8 = d2i_PKCS8_bio(bp, NULL);
+ if(!p8) return NULL;
+
+ klen = 0;
+ if (cb)
+ klen=cb(psbuf,PEM_BUFSIZE,0,u);
+ if (klen <= 0) {
+ OPENSSL_PUT_ERROR(PEM, d2i_PKCS8PrivateKey_bio, PEM_R_BAD_PASSWORD_READ);
+ X509_SIG_free(p8);
+ return NULL;
+ }
+ p8inf = PKCS8_decrypt(p8, psbuf, klen);
+ X509_SIG_free(p8);
+ if(!p8inf) return NULL;
+ ret = EVP_PKCS82PKEY(p8inf);
+ PKCS8_PRIV_KEY_INFO_free(p8inf);
+ if(!ret) return NULL;
+ if(x) {
+ if(*x) EVP_PKEY_free(*x);
+ *x = ret;
+ }
+ return ret;
+}
+
+#ifndef OPENSSL_NO_FP_API
+
+int i2d_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc,
+ char *kstr, int klen,
+ pem_password_cb *cb, void *u)
+{
+ return do_pk8pkey_fp(fp, x, 1, -1, enc, kstr, klen, cb, u);
+}
+
+int i2d_PKCS8PrivateKey_nid_fp(FILE *fp, EVP_PKEY *x, int nid,
+ char *kstr, int klen,
+ pem_password_cb *cb, void *u)
+{
+ return do_pk8pkey_fp(fp, x, 1, nid, NULL, kstr, klen, cb, u);
+}
+
+int PEM_write_PKCS8PrivateKey_nid(FILE *fp, EVP_PKEY *x, int nid,
+ char *kstr, int klen,
+ pem_password_cb *cb, void *u)
+{
+ return do_pk8pkey_fp(fp, x, 0, nid, NULL, kstr, klen, cb, u);
+}
+
+int PEM_write_PKCS8PrivateKey(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc,
+ char *kstr, int klen, pem_password_cb *cb, void *u)
+{
+ return do_pk8pkey_fp(fp, x, 0, -1, enc, kstr, klen, cb, u);
+}
+
+static int do_pk8pkey_fp(FILE *fp, EVP_PKEY *x, int isder, int nid, const EVP_CIPHER *enc,
+ char *kstr, int klen,
+ pem_password_cb *cb, void *u)
+{
+ BIO *bp;
+ int ret;
+ if(!(bp = BIO_new_fp(fp, BIO_NOCLOSE))) {
+ OPENSSL_PUT_ERROR(PEM, do_pk8pkey_fp, ERR_R_BUF_LIB);
+ return(0);
+ }
+ ret = do_pk8pkey(bp, x, isder, nid, enc, kstr, klen, cb, u);
+ BIO_free(bp);
+ return ret;
+}
+
+EVP_PKEY *d2i_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, void *u)
+{
+ BIO *bp;
+ EVP_PKEY *ret;
+ if(!(bp = BIO_new_fp(fp, BIO_NOCLOSE))) {
+ OPENSSL_PUT_ERROR(PEM, d2i_PKCS8PrivateKey_fp, ERR_R_BUF_LIB);
+ return NULL;
+ }
+ ret = d2i_PKCS8PrivateKey_bio(bp, x, cb, u);
+ BIO_free(bp);
+ return ret;
+}
+
+#endif
+
+IMPLEMENT_PEM_rw(PKCS8, X509_SIG, PEM_STRING_PKCS8, X509_SIG)
+IMPLEMENT_PEM_rw(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO, PEM_STRING_PKCS8INF,
+ PKCS8_PRIV_KEY_INFO)
diff --git a/crypto/pem/pem_pkey.c b/crypto/pem/pem_pkey.c
new file mode 100644
index 0000000..7900f4b
--- /dev/null
+++ b/crypto/pem/pem_pkey.c
@@ -0,0 +1,313 @@
+/* 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/pem.h>
+
+#include <stdio.h>
+
+#include <openssl/buf.h>
+#include <openssl/dh.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/pkcs8.h>
+#include <openssl/rand.h>
+#include <openssl/x509.h>
+
+#include "../evp/internal.h"
+
+
+int pem_check_suffix(const char *pem_str, const char *suffix);
+
+EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, void *u)
+ {
+ char *nm=NULL;
+ const unsigned char *p=NULL;
+ unsigned char *data=NULL;
+ long len;
+ int slen;
+ EVP_PKEY *ret=NULL;
+
+ if (!PEM_bytes_read_bio(&data, &len, &nm, PEM_STRING_EVP_PKEY, bp, cb, u))
+ return NULL;
+ p = data;
+
+ if (strcmp(nm,PEM_STRING_PKCS8INF) == 0) {
+ PKCS8_PRIV_KEY_INFO *p8inf;
+ p8inf=d2i_PKCS8_PRIV_KEY_INFO(NULL, &p, len);
+ if(!p8inf) goto p8err;
+ ret = EVP_PKCS82PKEY(p8inf);
+ if(x) {
+ if(*x) EVP_PKEY_free((EVP_PKEY *)*x);
+ *x = ret;
+ }
+ PKCS8_PRIV_KEY_INFO_free(p8inf);
+ } else if (strcmp(nm,PEM_STRING_PKCS8) == 0) {
+ PKCS8_PRIV_KEY_INFO *p8inf;
+ X509_SIG *p8;
+ int klen;
+ char psbuf[PEM_BUFSIZE];
+ p8 = d2i_X509_SIG(NULL, &p, len);
+ if(!p8) goto p8err;
+
+ klen = 0;
+ if (cb) klen=cb(psbuf,PEM_BUFSIZE,0,u);
+ if (klen <= 0) {
+ OPENSSL_PUT_ERROR(PEM, PEM_read_bio_PrivateKey, PEM_R_BAD_PASSWORD_READ);
+ X509_SIG_free(p8);
+ goto err;
+ }
+ p8inf = PKCS8_decrypt(p8, psbuf, klen);
+ X509_SIG_free(p8);
+ if(!p8inf) goto p8err;
+ ret = EVP_PKCS82PKEY(p8inf);
+ if(x) {
+ if(*x) EVP_PKEY_free((EVP_PKEY *)*x);
+ *x = ret;
+ }
+ PKCS8_PRIV_KEY_INFO_free(p8inf);
+ } else if ((slen = pem_check_suffix(nm, "PRIVATE KEY")) > 0)
+ {
+ const EVP_PKEY_ASN1_METHOD *ameth;
+ ameth = EVP_PKEY_asn1_find_str(NULL, nm, slen);
+ if (!ameth || !ameth->old_priv_decode)
+ goto p8err;
+ ret=d2i_PrivateKey(ameth->pkey_id,x,&p,len);
+ }
+p8err:
+ if (ret == NULL)
+ OPENSSL_PUT_ERROR(PEM, PEM_read_bio_PrivateKey, ERR_R_ASN1_LIB);
+
+err:
+ OPENSSL_free(nm);
+ OPENSSL_cleanse(data, len);
+ OPENSSL_free(data);
+ return(ret);
+ }
+
+int PEM_write_bio_PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc,
+ unsigned char *kstr, int klen,
+ pem_password_cb *cb, void *u)
+ {
+ char pem_str[80];
+ if (!x->ameth || x->ameth->priv_encode)
+ return PEM_write_bio_PKCS8PrivateKey(bp, x, enc,
+ (char *)kstr, klen,
+ cb, u);
+
+ BIO_snprintf(pem_str, 80, "%s PRIVATE KEY", x->ameth->pem_str);
+ return PEM_ASN1_write_bio((i2d_of_void *)i2d_PrivateKey,
+ pem_str,bp,x,enc,kstr,klen,cb,u);
+ }
+
+static const int public_key_type_from_str(const char *name, size_t len) {
+ if (len == 3 && memcmp(name, "RSA", 3) == 0) {
+ return EVP_PKEY_RSA;
+ } else if (len == 2 && memcmp(name, "DH", 2) == 0) {
+ return EVP_PKEY_DH;
+ } else if (len == 2 && memcmp(name, "EC", 2) == 0) {
+ return EVP_PKEY_EC;
+ }
+ return NID_undef;
+}
+
+static int set_pkey_type_from_str(EVP_PKEY *pkey, const char *name, size_t len) {
+ int nid = public_key_type_from_str(name, len);
+ if (nid == NID_undef) {
+ return 0;
+ }
+ return EVP_PKEY_set_type(pkey, nid);
+}
+
+EVP_PKEY *PEM_read_bio_Parameters(BIO *bp, EVP_PKEY **x)
+ {
+ char *nm=NULL;
+ const unsigned char *p=NULL;
+ unsigned char *data=NULL;
+ long len;
+ int slen;
+ EVP_PKEY *ret=NULL;
+
+ if (!PEM_bytes_read_bio(&data, &len, &nm, PEM_STRING_PARAMETERS,
+ bp, 0, NULL))
+ return NULL;
+ p = data;
+
+ if ((slen = pem_check_suffix(nm, "PARAMETERS")) > 0)
+ {
+ ret = EVP_PKEY_new();
+ if (!ret)
+ goto err;
+ if (!set_pkey_type_from_str(ret, nm, slen)
+ || !ret->ameth->param_decode
+ || !ret->ameth->param_decode(ret, &p, len))
+ {
+ EVP_PKEY_free(ret);
+ ret = NULL;
+ goto err;
+ }
+ if(x)
+ {
+ if(*x) EVP_PKEY_free((EVP_PKEY *)*x);
+ *x = ret;
+ }
+ }
+err:
+ if (ret == NULL)
+ OPENSSL_PUT_ERROR(PEM, PEM_read_bio_Parameters, ERR_R_ASN1_LIB);
+ OPENSSL_free(nm);
+ OPENSSL_free(data);
+ return(ret);
+ }
+
+int PEM_write_bio_Parameters(BIO *bp, EVP_PKEY *x)
+ {
+ char pem_str[80];
+ if (!x->ameth || !x->ameth->param_encode)
+ return 0;
+
+ BIO_snprintf(pem_str, 80, "%s PARAMETERS", x->ameth->pem_str);
+ return PEM_ASN1_write_bio(
+ (i2d_of_void *)x->ameth->param_encode,
+ pem_str,bp,x,NULL,NULL,0,0,NULL);
+ }
+
+#ifndef OPENSSL_NO_FP_API
+EVP_PKEY *PEM_read_PrivateKey(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, void *u)
+ {
+ BIO *b;
+ EVP_PKEY *ret;
+
+ if ((b=BIO_new(BIO_s_file())) == NULL)
+ {
+ OPENSSL_PUT_ERROR(PEM, PEM_read_PrivateKey, ERR_R_BUF_LIB);
+ return(0);
+ }
+ BIO_set_fp(b,fp,BIO_NOCLOSE);
+ ret=PEM_read_bio_PrivateKey(b,x,cb,u);
+ BIO_free(b);
+ return(ret);
+ }
+
+int PEM_write_PrivateKey(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc,
+ unsigned char *kstr, int klen,
+ pem_password_cb *cb, void *u)
+ {
+ BIO *b;
+ int ret;
+
+ if ((b=BIO_new_fp(fp, BIO_NOCLOSE)) == NULL)
+ {
+ OPENSSL_PUT_ERROR(PEM, PEM_write_PrivateKey, ERR_R_BUF_LIB);
+ return 0;
+ }
+ ret=PEM_write_bio_PrivateKey(b, x, enc, kstr, klen, cb, u);
+ BIO_free(b);
+ return ret;
+ }
+
+#endif
+
+#ifndef OPENSSL_NO_DH
+
+/* Transparently read in PKCS#3 or X9.42 DH parameters */
+
+DH *PEM_read_bio_DHparams(BIO *bp, DH **x, pem_password_cb *cb, void *u)
+ {
+ char *nm=NULL;
+ const unsigned char *p=NULL;
+ unsigned char *data=NULL;
+ long len;
+ DH *ret=NULL;
+
+ if (!PEM_bytes_read_bio(&data, &len, &nm, PEM_STRING_DHPARAMS,
+ bp, cb, u))
+ return NULL;
+ p = data;
+
+ /* TODO(fork): remove? */
+ /*if (!strcmp(nm, PEM_STRING_DHXPARAMS))
+ ret = d2i_DHxparams(x, &p, len);
+ else */
+ ret = d2i_DHparams(x, &p, len);
+
+ if (ret == NULL)
+ OPENSSL_PUT_ERROR(PEM, PEM_read_bio_DHparams, ERR_R_ASN1_LIB);
+ OPENSSL_free(nm);
+ OPENSSL_free(data);
+ return ret;
+ }
+
+#ifndef OPENSSL_NO_FP_API
+DH *PEM_read_DHparams(FILE *fp, DH **x, pem_password_cb *cb, void *u)
+ {
+ BIO *b;
+ DH *ret;
+
+ if ((b=BIO_new(BIO_s_file())) == NULL)
+ {
+ OPENSSL_PUT_ERROR(PEM, PEM_read_DHparams, ERR_R_BUF_LIB);
+ return(0);
+ }
+ BIO_set_fp(b,fp,BIO_NOCLOSE);
+ ret=PEM_read_bio_DHparams(b,x,cb,u);
+ BIO_free(b);
+ return(ret);
+ }
+#endif
+
+#endif
diff --git a/crypto/pem/pem_x509.c b/crypto/pem/pem_x509.c
new file mode 100644
index 0000000..f463047
--- /dev/null
+++ b/crypto/pem/pem_x509.c
@@ -0,0 +1,65 @@
+/* pem_x509.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2001.
+ */
+/* ====================================================================
+ * Copyright (c) 2001 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 <stdio.h>
+
+#include <openssl/bio.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <openssl/x509.h>
+
+
+IMPLEMENT_PEM_rw(X509, X509, PEM_STRING_X509, X509)
diff --git a/crypto/pem/pem_xaux.c b/crypto/pem/pem_xaux.c
new file mode 100644
index 0000000..8dabd41
--- /dev/null
+++ b/crypto/pem/pem_xaux.c
@@ -0,0 +1,66 @@
+/* pem_xaux.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2001.
+ */
+/* ====================================================================
+ * Copyright (c) 2001 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 <stdio.h>
+
+#include <openssl/bio.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <openssl/x509.h>
+
+
+IMPLEMENT_PEM_rw(X509_AUX, X509, PEM_STRING_X509_TRUSTED, X509_AUX)
+IMPLEMENT_PEM_rw(X509_CERT_PAIR, X509_CERT_PAIR, PEM_STRING_X509_PAIR, X509_CERT_PAIR)
diff --git a/crypto/perlasm/cbc.pl b/crypto/perlasm/cbc.pl
new file mode 100644
index 0000000..24561e7
--- /dev/null
+++ b/crypto/perlasm/cbc.pl
@@ -0,0 +1,349 @@
+#!/usr/local/bin/perl
+
+# void des_ncbc_encrypt(input, output, length, schedule, ivec, enc)
+# des_cblock (*input);
+# des_cblock (*output);
+# long length;
+# des_key_schedule schedule;
+# des_cblock (*ivec);
+# int enc;
+#
+# calls
+# des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT);
+#
+
+#&cbc("des_ncbc_encrypt","des_encrypt",0);
+#&cbc("BF_cbc_encrypt","BF_encrypt","BF_encrypt",
+# 1,4,5,3,5,-1);
+#&cbc("des_ncbc_encrypt","des_encrypt","des_encrypt",
+# 0,4,5,3,5,-1);
+#&cbc("des_ede3_cbc_encrypt","des_encrypt3","des_decrypt3",
+# 0,6,7,3,4,5);
+#
+# When doing a cipher that needs bigendian order,
+# for encrypt, the iv is kept in bigendian form,
+# while for decrypt, it is kept in little endian.
+sub cbc
+ {
+ local($name,$enc_func,$dec_func,$swap,$iv_off,$enc_off,$p1,$p2,$p3)=@_;
+ # name is the function name
+ # enc_func and dec_func and the functions to call for encrypt/decrypt
+ # swap is true if byte order needs to be reversed
+ # iv_off is parameter number for the iv
+ # enc_off is parameter number for the encrypt/decrypt flag
+ # p1,p2,p3 are the offsets for parameters to be passed to the
+ # underlying calls.
+
+ &function_begin_B($name,"");
+ &comment("");
+
+ $in="esi";
+ $out="edi";
+ $count="ebp";
+
+ &push("ebp");
+ &push("ebx");
+ &push("esi");
+ &push("edi");
+
+ $data_off=4;
+ $data_off+=4 if ($p1 > 0);
+ $data_off+=4 if ($p2 > 0);
+ $data_off+=4 if ($p3 > 0);
+
+ &mov($count, &wparam(2)); # length
+
+ &comment("getting iv ptr from parameter $iv_off");
+ &mov("ebx", &wparam($iv_off)); # Get iv ptr
+
+ &mov($in, &DWP(0,"ebx","",0));# iv[0]
+ &mov($out, &DWP(4,"ebx","",0));# iv[1]
+
+ &push($out);
+ &push($in);
+ &push($out); # used in decrypt for iv[1]
+ &push($in); # used in decrypt for iv[0]
+
+ &mov("ebx", "esp"); # This is the address of tin[2]
+
+ &mov($in, &wparam(0)); # in
+ &mov($out, &wparam(1)); # out
+
+ # We have loaded them all, how lets push things
+ &comment("getting encrypt flag from parameter $enc_off");
+ &mov("ecx", &wparam($enc_off)); # Get enc flag
+ if ($p3 > 0)
+ {
+ &comment("get and push parameter $p3");
+ if ($enc_off != $p3)
+ { &mov("eax", &wparam($p3)); &push("eax"); }
+ else { &push("ecx"); }
+ }
+ if ($p2 > 0)
+ {
+ &comment("get and push parameter $p2");
+ if ($enc_off != $p2)
+ { &mov("eax", &wparam($p2)); &push("eax"); }
+ else { &push("ecx"); }
+ }
+ if ($p1 > 0)
+ {
+ &comment("get and push parameter $p1");
+ if ($enc_off != $p1)
+ { &mov("eax", &wparam($p1)); &push("eax"); }
+ else { &push("ecx"); }
+ }
+ &push("ebx"); # push data/iv
+
+ &cmp("ecx",0);
+ &jz(&label("decrypt"));
+
+ &and($count,0xfffffff8);
+ &mov("eax", &DWP($data_off,"esp","",0)); # load iv[0]
+ &mov("ebx", &DWP($data_off+4,"esp","",0)); # load iv[1]
+
+ &jz(&label("encrypt_finish"));
+
+ #############################################################
+
+ &set_label("encrypt_loop");
+ # encrypt start
+ # "eax" and "ebx" hold iv (or the last cipher text)
+
+ &mov("ecx", &DWP(0,$in,"",0)); # load first 4 bytes
+ &mov("edx", &DWP(4,$in,"",0)); # second 4 bytes
+
+ &xor("eax", "ecx");
+ &xor("ebx", "edx");
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov(&DWP($data_off,"esp","",0), "eax"); # put in array for call
+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
+
+ &call($enc_func);
+
+ &mov("eax", &DWP($data_off,"esp","",0));
+ &mov("ebx", &DWP($data_off+4,"esp","",0));
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov(&DWP(0,$out,"",0),"eax");
+ &mov(&DWP(4,$out,"",0),"ebx");
+
+ # eax and ebx are the next iv.
+
+ &add($in, 8);
+ &add($out, 8);
+
+ &sub($count, 8);
+ &jnz(&label("encrypt_loop"));
+
+###################################################################3
+ &set_label("encrypt_finish");
+ &mov($count, &wparam(2)); # length
+ &and($count, 7);
+ &jz(&label("finish"));
+ &call(&label("PIC_point"));
+&set_label("PIC_point");
+ &blindpop("edx");
+ &lea("ecx",&DWP(&label("cbc_enc_jmp_table")."-".&label("PIC_point"),"edx"));
+ &mov($count,&DWP(0,"ecx",$count,4));
+ &add($count,"edx");
+ &xor("ecx","ecx");
+ &xor("edx","edx");
+ #&mov($count,&DWP(&label("cbc_enc_jmp_table"),"",$count,4));
+ &jmp_ptr($count);
+
+&set_label("ej7");
+ &movb(&HB("edx"), &BP(6,$in,"",0));
+ &shl("edx",8);
+&set_label("ej6");
+ &movb(&HB("edx"), &BP(5,$in,"",0));
+&set_label("ej5");
+ &movb(&LB("edx"), &BP(4,$in,"",0));
+&set_label("ej4");
+ &mov("ecx", &DWP(0,$in,"",0));
+ &jmp(&label("ejend"));
+&set_label("ej3");
+ &movb(&HB("ecx"), &BP(2,$in,"",0));
+ &shl("ecx",8);
+&set_label("ej2");
+ &movb(&HB("ecx"), &BP(1,$in,"",0));
+&set_label("ej1");
+ &movb(&LB("ecx"), &BP(0,$in,"",0));
+&set_label("ejend");
+
+ &xor("eax", "ecx");
+ &xor("ebx", "edx");
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov(&DWP($data_off,"esp","",0), "eax"); # put in array for call
+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
+
+ &call($enc_func);
+
+ &mov("eax", &DWP($data_off,"esp","",0));
+ &mov("ebx", &DWP($data_off+4,"esp","",0));
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov(&DWP(0,$out,"",0),"eax");
+ &mov(&DWP(4,$out,"",0),"ebx");
+
+ &jmp(&label("finish"));
+
+ #############################################################
+ #############################################################
+ &set_label("decrypt",1);
+ # decrypt start
+ &and($count,0xfffffff8);
+ # The next 2 instructions are only for if the jz is taken
+ &mov("eax", &DWP($data_off+8,"esp","",0)); # get iv[0]
+ &mov("ebx", &DWP($data_off+12,"esp","",0)); # get iv[1]
+ &jz(&label("decrypt_finish"));
+
+ &set_label("decrypt_loop");
+ &mov("eax", &DWP(0,$in,"",0)); # load first 4 bytes
+ &mov("ebx", &DWP(4,$in,"",0)); # second 4 bytes
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov(&DWP($data_off,"esp","",0), "eax"); # put back
+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
+
+ &call($dec_func);
+
+ &mov("eax", &DWP($data_off,"esp","",0)); # get return
+ &mov("ebx", &DWP($data_off+4,"esp","",0)); #
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov("ecx", &DWP($data_off+8,"esp","",0)); # get iv[0]
+ &mov("edx", &DWP($data_off+12,"esp","",0)); # get iv[1]
+
+ &xor("ecx", "eax");
+ &xor("edx", "ebx");
+
+ &mov("eax", &DWP(0,$in,"",0)); # get old cipher text,
+ &mov("ebx", &DWP(4,$in,"",0)); # next iv actually
+
+ &mov(&DWP(0,$out,"",0),"ecx");
+ &mov(&DWP(4,$out,"",0),"edx");
+
+ &mov(&DWP($data_off+8,"esp","",0), "eax"); # save iv
+ &mov(&DWP($data_off+12,"esp","",0), "ebx"); #
+
+ &add($in, 8);
+ &add($out, 8);
+
+ &sub($count, 8);
+ &jnz(&label("decrypt_loop"));
+############################ ENDIT #######################3
+ &set_label("decrypt_finish");
+ &mov($count, &wparam(2)); # length
+ &and($count, 7);
+ &jz(&label("finish"));
+
+ &mov("eax", &DWP(0,$in,"",0)); # load first 4 bytes
+ &mov("ebx", &DWP(4,$in,"",0)); # second 4 bytes
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov(&DWP($data_off,"esp","",0), "eax"); # put back
+ &mov(&DWP($data_off+4,"esp","",0), "ebx"); #
+
+ &call($dec_func);
+
+ &mov("eax", &DWP($data_off,"esp","",0)); # get return
+ &mov("ebx", &DWP($data_off+4,"esp","",0)); #
+
+ &bswap("eax") if $swap;
+ &bswap("ebx") if $swap;
+
+ &mov("ecx", &DWP($data_off+8,"esp","",0)); # get iv[0]
+ &mov("edx", &DWP($data_off+12,"esp","",0)); # get iv[1]
+
+ &xor("ecx", "eax");
+ &xor("edx", "ebx");
+
+ # this is for when we exit
+ &mov("eax", &DWP(0,$in,"",0)); # get old cipher text,
+ &mov("ebx", &DWP(4,$in,"",0)); # next iv actually
+
+&set_label("dj7");
+ &rotr("edx", 16);
+ &movb(&BP(6,$out,"",0), &LB("edx"));
+ &shr("edx",16);
+&set_label("dj6");
+ &movb(&BP(5,$out,"",0), &HB("edx"));
+&set_label("dj5");
+ &movb(&BP(4,$out,"",0), &LB("edx"));
+&set_label("dj4");
+ &mov(&DWP(0,$out,"",0), "ecx");
+ &jmp(&label("djend"));
+&set_label("dj3");
+ &rotr("ecx", 16);
+ &movb(&BP(2,$out,"",0), &LB("ecx"));
+ &shl("ecx",16);
+&set_label("dj2");
+ &movb(&BP(1,$in,"",0), &HB("ecx"));
+&set_label("dj1");
+ &movb(&BP(0,$in,"",0), &LB("ecx"));
+&set_label("djend");
+
+ # final iv is still in eax:ebx
+ &jmp(&label("finish"));
+
+
+############################ FINISH #######################3
+ &set_label("finish",1);
+ &mov("ecx", &wparam($iv_off)); # Get iv ptr
+
+ #################################################
+ $total=16+4;
+ $total+=4 if ($p1 > 0);
+ $total+=4 if ($p2 > 0);
+ $total+=4 if ($p3 > 0);
+ &add("esp",$total);
+
+ &mov(&DWP(0,"ecx","",0), "eax"); # save iv
+ &mov(&DWP(4,"ecx","",0), "ebx"); # save iv
+
+ &function_end_A($name);
+
+ &align(64);
+ &set_label("cbc_enc_jmp_table");
+ &data_word("0");
+ &data_word(&label("ej1")."-".&label("PIC_point"));
+ &data_word(&label("ej2")."-".&label("PIC_point"));
+ &data_word(&label("ej3")."-".&label("PIC_point"));
+ &data_word(&label("ej4")."-".&label("PIC_point"));
+ &data_word(&label("ej5")."-".&label("PIC_point"));
+ &data_word(&label("ej6")."-".&label("PIC_point"));
+ &data_word(&label("ej7")."-".&label("PIC_point"));
+ # not used
+ #&set_label("cbc_dec_jmp_table",1);
+ #&data_word("0");
+ #&data_word(&label("dj1")."-".&label("PIC_point"));
+ #&data_word(&label("dj2")."-".&label("PIC_point"));
+ #&data_word(&label("dj3")."-".&label("PIC_point"));
+ #&data_word(&label("dj4")."-".&label("PIC_point"));
+ #&data_word(&label("dj5")."-".&label("PIC_point"));
+ #&data_word(&label("dj6")."-".&label("PIC_point"));
+ #&data_word(&label("dj7")."-".&label("PIC_point"));
+ &align(64);
+
+ &function_end_B($name);
+
+ }
+
+1;
diff --git a/crypto/perlasm/ppc-xlate.pl b/crypto/perlasm/ppc-xlate.pl
new file mode 100755
index 0000000..3ed7bd9
--- /dev/null
+++ b/crypto/perlasm/ppc-xlate.pl
@@ -0,0 +1,161 @@
+#!/usr/bin/env perl
+
+# PowerPC assembler distiller by <appro>.
+
+my $flavour = shift;
+my $output = shift;
+open STDOUT,">$output" || die "can't open $output: $!";
+
+my %GLOBALS;
+my $dotinlocallabels=($flavour=~/linux/)?1:0;
+
+################################################################
+# directives which need special treatment on different platforms
+################################################################
+my $globl = sub {
+ my $junk = shift;
+ my $name = shift;
+ my $global = \$GLOBALS{$name};
+ my $ret;
+
+ $name =~ s|^[\.\_]||;
+
+ SWITCH: for ($flavour) {
+ /aix/ && do { $name = ".$name";
+ last;
+ };
+ /osx/ && do { $name = "_$name";
+ last;
+ };
+ /linux.*32/ && do { $ret .= ".globl $name\n";
+ $ret .= ".type $name,\@function";
+ last;
+ };
+ /linux.*64/ && do { $ret .= ".globl $name\n";
+ $ret .= ".type $name,\@function\n";
+ $ret .= ".section \".opd\",\"aw\"\n";
+ $ret .= ".align 3\n";
+ $ret .= "$name:\n";
+ $ret .= ".quad .$name,.TOC.\@tocbase,0\n";
+ $ret .= ".previous\n";
+
+ $name = ".$name";
+ last;
+ };
+ }
+
+ $ret = ".globl $name" if (!$ret);
+ $$global = $name;
+ $ret;
+};
+my $text = sub {
+ ($flavour =~ /aix/) ? ".csect" : ".text";
+};
+my $machine = sub {
+ my $junk = shift;
+ my $arch = shift;
+ if ($flavour =~ /osx/)
+ { $arch =~ s/\"//g;
+ $arch = ($flavour=~/64/) ? "ppc970-64" : "ppc970" if ($arch eq "any");
+ }
+ ".machine $arch";
+};
+my $size = sub {
+ if ($flavour =~ /linux/)
+ { shift;
+ my $name = shift; $name =~ s|^[\.\_]||;
+ my $ret = ".size $name,.-".($flavour=~/64/?".":"").$name;
+ $ret .= "\n.size .$name,.-.$name" if ($flavour=~/64/);
+ $ret;
+ }
+ else
+ { ""; }
+};
+my $asciz = sub {
+ shift;
+ my $line = join(",",@_);
+ if ($line =~ /^"(.*)"$/)
+ { ".byte " . join(",",unpack("C*",$1),0) . "\n.align 2"; }
+ else
+ { ""; }
+};
+
+################################################################
+# simplified mnemonics not handled by at least one assembler
+################################################################
+my $cmplw = sub {
+ my $f = shift;
+ my $cr = 0; $cr = shift if ($#_>1);
+ # Some out-of-date 32-bit GNU assembler just can't handle cmplw...
+ ($flavour =~ /linux.*32/) ?
+ " .long ".sprintf "0x%x",31<<26|$cr<<23|$_[0]<<16|$_[1]<<11|64 :
+ " cmplw ".join(',',$cr,@_);
+};
+my $bdnz = sub {
+ my $f = shift;
+ my $bo = $f=~/[\+\-]/ ? 16+9 : 16; # optional "to be taken" hint
+ " bc $bo,0,".shift;
+} if ($flavour!~/linux/);
+my $bltlr = sub {
+ my $f = shift;
+ my $bo = $f=~/\-/ ? 12+2 : 12; # optional "not to be taken" hint
+ ($flavour =~ /linux/) ? # GNU as doesn't allow most recent hints
+ " .long ".sprintf "0x%x",19<<26|$bo<<21|16<<1 :
+ " bclr $bo,0";
+};
+my $bnelr = sub {
+ my $f = shift;
+ my $bo = $f=~/\-/ ? 4+2 : 4; # optional "not to be taken" hint
+ ($flavour =~ /linux/) ? # GNU as doesn't allow most recent hints
+ " .long ".sprintf "0x%x",19<<26|$bo<<21|2<<16|16<<1 :
+ " bclr $bo,2";
+};
+my $beqlr = sub {
+ my $f = shift;
+ my $bo = $f=~/-/ ? 12+2 : 12; # optional "not to be taken" hint
+ ($flavour =~ /linux/) ? # GNU as doesn't allow most recent hints
+ " .long ".sprintf "0x%X",19<<26|$bo<<21|2<<16|16<<1 :
+ " bclr $bo,2";
+};
+# GNU assembler can't handle extrdi rA,rS,16,48, or when sum of last two
+# arguments is 64, with "operand out of range" error.
+my $extrdi = sub {
+ my ($f,$ra,$rs,$n,$b) = @_;
+ $b = ($b+$n)&63; $n = 64-$n;
+ " rldicl $ra,$rs,$b,$n";
+};
+
+while($line=<>) {
+
+ $line =~ s|[#!;].*$||; # get rid of asm-style comments...
+ $line =~ s|/\*.*\*/||; # ... and C-style comments...
+ $line =~ s|^\s+||; # ... and skip white spaces in beginning...
+ $line =~ s|\s+$||; # ... and at the end
+
+ {
+ $line =~ s|\b\.L(\w+)|L$1|g; # common denominator for Locallabel
+ $line =~ s|\bL(\w+)|\.L$1|g if ($dotinlocallabels);
+ }
+
+ {
+ $line =~ s|(^[\.\w]+)\:\s*||;
+ my $label = $1;
+ printf "%s:",($GLOBALS{$label} or $label) if ($label);
+ }
+
+ {
+ $line =~ s|^\s*(\.?)(\w+)([\.\+\-]?)\s*||;
+ my $c = $1; $c = "\t" if ($c eq "");
+ my $mnemonic = $2;
+ my $f = $3;
+ my $opcode = eval("\$$mnemonic");
+ $line =~ s|\bc?[rf]([0-9]+)\b|$1|g if ($c ne "." and $flavour !~ /osx/);
+ if (ref($opcode) eq 'CODE') { $line = &$opcode($f,split(',',$line)); }
+ elsif ($mnemonic) { $line = $c.$mnemonic.$f."\t".$line; }
+ }
+
+ print $line if ($line);
+ print "\n";
+}
+
+close STDOUT;
diff --git a/crypto/perlasm/readme b/crypto/perlasm/readme
new file mode 100644
index 0000000..f02bbee
--- /dev/null
+++ b/crypto/perlasm/readme
@@ -0,0 +1,124 @@
+The perl scripts in this directory are my 'hack' to generate
+multiple different assembler formats via the one origional script.
+
+The way to use this library is to start with adding the path to this directory
+and then include it.
+
+push(@INC,"perlasm","../../perlasm");
+require "x86asm.pl";
+
+The first thing we do is setup the file and type of assember
+
+&asm_init($ARGV[0],$0);
+
+The first argument is the 'type'. Currently
+'cpp', 'sol', 'a.out', 'elf' or 'win32'.
+Argument 2 is the file name.
+
+The reciprocal function is
+&asm_finish() which should be called at the end.
+
+There are 2 main 'packages'. x86ms.pl, which is the microsoft assembler,
+and x86unix.pl which is the unix (gas) version.
+
+Functions of interest are:
+&external_label("des_SPtrans"); declare and external variable
+&LB(reg); Low byte for a register
+&HB(reg); High byte for a register
+&BP(off,base,index,scale) Byte pointer addressing
+&DWP(off,base,index,scale) Word pointer addressing
+&stack_push(num) Basically a 'sub esp, num*4' with extra
+&stack_pop(num) inverse of stack_push
+&function_begin(name,extra) Start a function with pushing of
+ edi, esi, ebx and ebp. extra is extra win32
+ external info that may be required.
+&function_begin_B(name,extra) Same as norma function_begin but no pushing.
+&function_end(name) Call at end of function.
+&function_end_A(name) Standard pop and ret, for use inside functions
+&function_end_B(name) Call at end but with poping or 'ret'.
+&swtmp(num) Address on stack temp word.
+&wparam(num) Parameter number num, that was push
+ in C convention. This all works over pushes
+ and pops.
+&comment("hello there") Put in a comment.
+&label("loop") Refer to a label, normally a jmp target.
+&set_label("loop") Set a label at this point.
+&data_word(word) Put in a word of data.
+
+So how does this all hold together? Given
+
+int calc(int len, int *data)
+ {
+ int i,j=0;
+
+ for (i=0; i<len; i++)
+ {
+ j+=other(data[i]);
+ }
+ }
+
+So a very simple version of this function could be coded as
+
+ push(@INC,"perlasm","../../perlasm");
+ require "x86asm.pl";
+
+ &asm_init($ARGV[0],"cacl.pl");
+
+ &external_label("other");
+
+ $tmp1= "eax";
+ $j= "edi";
+ $data= "esi";
+ $i= "ebp";
+
+ &comment("a simple function");
+ &function_begin("calc");
+ &mov( $data, &wparam(1)); # data
+ &xor( $j, $j);
+ &xor( $i, $i);
+
+ &set_label("loop");
+ &cmp( $i, &wparam(0));
+ &jge( &label("end"));
+
+ &mov( $tmp1, &DWP(0,$data,$i,4));
+ &push( $tmp1);
+ &call( "other");
+ &add( $j, "eax");
+ &pop( $tmp1);
+ &inc( $i);
+ &jmp( &label("loop"));
+
+ &set_label("end");
+ &mov( "eax", $j);
+
+ &function_end("calc");
+
+ &asm_finish();
+
+The above example is very very unoptimised but gives an idea of how
+things work.
+
+There is also a cbc mode function generator in cbc.pl
+
+&cbc( $name,
+ $encrypt_function_name,
+ $decrypt_function_name,
+ $true_if_byte_swap_needed,
+ $parameter_number_for_iv,
+ $parameter_number_for_encrypt_flag,
+ $first_parameter_to_pass,
+ $second_parameter_to_pass,
+ $third_parameter_to_pass);
+
+So for example, given
+void BF_encrypt(BF_LONG *data,BF_KEY *key);
+void BF_decrypt(BF_LONG *data,BF_KEY *key);
+void BF_cbc_encrypt(unsigned char *in, unsigned char *out, long length,
+ BF_KEY *ks, unsigned char *iv, int enc);
+
+&cbc("BF_cbc_encrypt","BF_encrypt","BF_encrypt",1,4,5,3,-1,-1);
+
+&cbc("des_ncbc_encrypt","des_encrypt","des_encrypt",0,4,5,3,5,-1);
+&cbc("des_ede3_cbc_encrypt","des_encrypt3","des_decrypt3",0,6,7,3,4,5);
+
diff --git a/crypto/perlasm/sparcv9_modes.pl b/crypto/perlasm/sparcv9_modes.pl
new file mode 100644
index 0000000..6b47bb1
--- /dev/null
+++ b/crypto/perlasm/sparcv9_modes.pl
@@ -0,0 +1,1680 @@
+#!/usr/bin/env perl
+
+# Specific modes implementations for SPARC Architecture 2011. There
+# is T4 dependency though, an ASI value that is not specified in the
+# Architecture Manual. But as SPARC universe is rather monocultural,
+# we imply that processor capable of executing crypto instructions
+# can handle the ASI in question as well. This means that we ought to
+# keep eyes open when new processors emerge...
+#
+# As for above mentioned ASI. It's so called "block initializing
+# store" which cancels "read" in "read-update-write" on cache lines.
+# This is "cooperative" optimization, as it reduces overall pressure
+# on memory interface. Benefits can't be observed/quantified with
+# usual benchmarks, on the contrary you can notice that single-thread
+# performance for parallelizable modes is ~1.5% worse for largest
+# block sizes [though few percent better for not so long ones]. All
+# this based on suggestions from David Miller.
+
+sub asm_init { # to be called with @ARGV as argument
+ for (@_) { $::abibits=64 if (/\-m64/ || /\-xarch\=v9/); }
+ if ($::abibits==64) { $::bias=2047; $::frame=192; $::size_t_cc="%xcc"; }
+ else { $::bias=0; $::frame=112; $::size_t_cc="%icc"; }
+}
+
+# unified interface
+my ($inp,$out,$len,$key,$ivec)=map("%i$_",(0..5));
+# local variables
+my ($ileft,$iright,$ooff,$omask,$ivoff,$blk_init)=map("%l$_",(0..7));
+
+sub alg_cbc_encrypt_implement {
+my ($alg,$bits) = @_;
+
+$::code.=<<___;
+.globl ${alg}${bits}_t4_cbc_encrypt
+.align 32
+${alg}${bits}_t4_cbc_encrypt:
+ save %sp, -$::frame, %sp
+ sub $inp, $out, $blk_init ! $inp!=$out
+___
+$::code.=<<___ if (!$::evp);
+ andcc $ivec, 7, $ivoff
+ alignaddr $ivec, %g0, $ivec
+
+ ldd [$ivec + 0], %f0 ! load ivec
+ bz,pt %icc, 1f
+ ldd [$ivec + 8], %f2
+ ldd [$ivec + 16], %f4
+ faligndata %f0, %f2, %f0
+ faligndata %f2, %f4, %f2
+1:
+___
+$::code.=<<___ if ($::evp);
+ ld [$ivec + 0], %f0
+ ld [$ivec + 4], %f1
+ ld [$ivec + 8], %f2
+ ld [$ivec + 12], %f3
+___
+$::code.=<<___;
+ prefetch [$inp], 20
+ prefetch [$inp + 63], 20
+ call _${alg}${bits}_load_enckey
+ and $inp, 7, $ileft
+ andn $inp, 7, $inp
+ sll $ileft, 3, $ileft
+ mov 64, $iright
+ mov 0xff, $omask
+ sub $iright, $ileft, $iright
+ and $out, 7, $ooff
+ cmp $len, 127
+ movrnz $ooff, 0, $blk_init ! if ( $out&7 ||
+ movleu $::size_t_cc, 0, $blk_init ! $len<128 ||
+ brnz,pn $blk_init, .L${bits}cbc_enc_blk ! $inp==$out)
+ srl $omask, $ooff, $omask
+
+ alignaddrl $out, %g0, $out
+ srlx $len, 4, $len
+ prefetch [$out], 22
+
+.L${bits}_cbc_enc_loop:
+ ldx [$inp + 0], %o0
+ brz,pt $ileft, 4f
+ ldx [$inp + 8], %o1
+
+ ldx [$inp + 16], %o2
+ sllx %o0, $ileft, %o0
+ srlx %o1, $iright, %g1
+ sllx %o1, $ileft, %o1
+ or %g1, %o0, %o0
+ srlx %o2, $iright, %o2
+ or %o2, %o1, %o1
+4:
+ xor %g4, %o0, %o0 ! ^= rk[0]
+ xor %g5, %o1, %o1
+ movxtod %o0, %f12
+ movxtod %o1, %f14
+
+ fxor %f12, %f0, %f0 ! ^= ivec
+ fxor %f14, %f2, %f2
+ prefetch [$out + 63], 22
+ prefetch [$inp + 16+63], 20
+ call _${alg}${bits}_encrypt_1x
+ add $inp, 16, $inp
+
+ brnz,pn $ooff, 2f
+ sub $len, 1, $len
+
+ std %f0, [$out + 0]
+ std %f2, [$out + 8]
+ brnz,pt $len, .L${bits}_cbc_enc_loop
+ add $out, 16, $out
+___
+$::code.=<<___ if ($::evp);
+ st %f0, [$ivec + 0]
+ st %f1, [$ivec + 4]
+ st %f2, [$ivec + 8]
+ st %f3, [$ivec + 12]
+___
+$::code.=<<___ if (!$::evp);
+ brnz,pn $ivoff, 3f
+ nop
+
+ std %f0, [$ivec + 0] ! write out ivec
+ std %f2, [$ivec + 8]
+___
+$::code.=<<___;
+ ret
+ restore
+
+.align 16
+2: ldxa [$inp]0x82, %o0 ! avoid read-after-write hazard
+ ! and ~3x deterioration
+ ! in inp==out case
+ faligndata %f0, %f0, %f4 ! handle unaligned output
+ faligndata %f0, %f2, %f6
+ faligndata %f2, %f2, %f8
+
+ stda %f4, [$out + $omask]0xc0 ! partial store
+ std %f6, [$out + 8]
+ add $out, 16, $out
+ orn %g0, $omask, $omask
+ stda %f8, [$out + $omask]0xc0 ! partial store
+
+ brnz,pt $len, .L${bits}_cbc_enc_loop+4
+ orn %g0, $omask, $omask
+___
+$::code.=<<___ if ($::evp);
+ st %f0, [$ivec + 0]
+ st %f1, [$ivec + 4]
+ st %f2, [$ivec + 8]
+ st %f3, [$ivec + 12]
+___
+$::code.=<<___ if (!$::evp);
+ brnz,pn $ivoff, 3f
+ nop
+
+ std %f0, [$ivec + 0] ! write out ivec
+ std %f2, [$ivec + 8]
+ ret
+ restore
+
+.align 16
+3: alignaddrl $ivec, $ivoff, %g0 ! handle unaligned ivec
+ mov 0xff, $omask
+ srl $omask, $ivoff, $omask
+ faligndata %f0, %f0, %f4
+ faligndata %f0, %f2, %f6
+ faligndata %f2, %f2, %f8
+ stda %f4, [$ivec + $omask]0xc0
+ std %f6, [$ivec + 8]
+ add $ivec, 16, $ivec
+ orn %g0, $omask, $omask
+ stda %f8, [$ivec + $omask]0xc0
+___
+$::code.=<<___;
+ ret
+ restore
+
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+.align 32
+.L${bits}cbc_enc_blk:
+ add $out, $len, $blk_init
+ and $blk_init, 63, $blk_init ! tail
+ sub $len, $blk_init, $len
+ add $blk_init, 15, $blk_init ! round up to 16n
+ srlx $len, 4, $len
+ srl $blk_init, 4, $blk_init
+
+.L${bits}_cbc_enc_blk_loop:
+ ldx [$inp + 0], %o0
+ brz,pt $ileft, 5f
+ ldx [$inp + 8], %o1
+
+ ldx [$inp + 16], %o2
+ sllx %o0, $ileft, %o0
+ srlx %o1, $iright, %g1
+ sllx %o1, $ileft, %o1
+ or %g1, %o0, %o0
+ srlx %o2, $iright, %o2
+ or %o2, %o1, %o1
+5:
+ xor %g4, %o0, %o0 ! ^= rk[0]
+ xor %g5, %o1, %o1
+ movxtod %o0, %f12
+ movxtod %o1, %f14
+
+ fxor %f12, %f0, %f0 ! ^= ivec
+ fxor %f14, %f2, %f2
+ prefetch [$inp + 16+63], 20
+ call _${alg}${bits}_encrypt_1x
+ add $inp, 16, $inp
+ sub $len, 1, $len
+
+ stda %f0, [$out]0xe2 ! ASI_BLK_INIT, T4-specific
+ add $out, 8, $out
+ stda %f2, [$out]0xe2 ! ASI_BLK_INIT, T4-specific
+ brnz,pt $len, .L${bits}_cbc_enc_blk_loop
+ add $out, 8, $out
+
+ membar #StoreLoad|#StoreStore
+ brnz,pt $blk_init, .L${bits}_cbc_enc_loop
+ mov $blk_init, $len
+___
+$::code.=<<___ if ($::evp);
+ st %f0, [$ivec + 0]
+ st %f1, [$ivec + 4]
+ st %f2, [$ivec + 8]
+ st %f3, [$ivec + 12]
+___
+$::code.=<<___ if (!$::evp);
+ brnz,pn $ivoff, 3b
+ nop
+
+ std %f0, [$ivec + 0] ! write out ivec
+ std %f2, [$ivec + 8]
+___
+$::code.=<<___;
+ ret
+ restore
+.type ${alg}${bits}_t4_cbc_encrypt,#function
+.size ${alg}${bits}_t4_cbc_encrypt,.-${alg}${bits}_t4_cbc_encrypt
+___
+}
+
+sub alg_cbc_decrypt_implement {
+my ($alg,$bits) = @_;
+
+$::code.=<<___;
+.globl ${alg}${bits}_t4_cbc_decrypt
+.align 32
+${alg}${bits}_t4_cbc_decrypt:
+ save %sp, -$::frame, %sp
+ sub $inp, $out, $blk_init ! $inp!=$out
+___
+$::code.=<<___ if (!$::evp);
+ andcc $ivec, 7, $ivoff
+ alignaddr $ivec, %g0, $ivec
+
+ ldd [$ivec + 0], %f12 ! load ivec
+ bz,pt %icc, 1f
+ ldd [$ivec + 8], %f14
+ ldd [$ivec + 16], %f0
+ faligndata %f12, %f14, %f12
+ faligndata %f14, %f0, %f14
+1:
+___
+$::code.=<<___ if ($::evp);
+ ld [$ivec + 0], %f12 ! load ivec
+ ld [$ivec + 4], %f13
+ ld [$ivec + 8], %f14
+ ld [$ivec + 12], %f15
+___
+$::code.=<<___;
+ prefetch [$inp], 20
+ prefetch [$inp + 63], 20
+ call _${alg}${bits}_load_deckey
+ and $inp, 7, $ileft
+ andn $inp, 7, $inp
+ sll $ileft, 3, $ileft
+ mov 64, $iright
+ mov 0xff, $omask
+ sub $iright, $ileft, $iright
+ and $out, 7, $ooff
+ cmp $len, 255
+ movrnz $ooff, 0, $blk_init ! if ( $out&7 ||
+ movleu $::size_t_cc, 0, $blk_init ! $len<256 ||
+ brnz,pn $blk_init, .L${bits}cbc_dec_blk ! $inp==$out)
+ srl $omask, $ooff, $omask
+
+ andcc $len, 16, %g0 ! is number of blocks even?
+ srlx $len, 4, $len
+ alignaddrl $out, %g0, $out
+ bz %icc, .L${bits}_cbc_dec_loop2x
+ prefetch [$out], 22
+.L${bits}_cbc_dec_loop:
+ ldx [$inp + 0], %o0
+ brz,pt $ileft, 4f
+ ldx [$inp + 8], %o1
+
+ ldx [$inp + 16], %o2
+ sllx %o0, $ileft, %o0
+ srlx %o1, $iright, %g1
+ sllx %o1, $ileft, %o1
+ or %g1, %o0, %o0
+ srlx %o2, $iright, %o2
+ or %o2, %o1, %o1
+4:
+ xor %g4, %o0, %o2 ! ^= rk[0]
+ xor %g5, %o1, %o3
+ movxtod %o2, %f0
+ movxtod %o3, %f2
+
+ prefetch [$out + 63], 22
+ prefetch [$inp + 16+63], 20
+ call _${alg}${bits}_decrypt_1x
+ add $inp, 16, $inp
+
+ fxor %f12, %f0, %f0 ! ^= ivec
+ fxor %f14, %f2, %f2
+ movxtod %o0, %f12
+ movxtod %o1, %f14
+
+ brnz,pn $ooff, 2f
+ sub $len, 1, $len
+
+ std %f0, [$out + 0]
+ std %f2, [$out + 8]
+ brnz,pt $len, .L${bits}_cbc_dec_loop2x
+ add $out, 16, $out
+___
+$::code.=<<___ if ($::evp);
+ st %f12, [$ivec + 0]
+ st %f13, [$ivec + 4]
+ st %f14, [$ivec + 8]
+ st %f15, [$ivec + 12]
+___
+$::code.=<<___ if (!$::evp);
+ brnz,pn $ivoff, .L${bits}_cbc_dec_unaligned_ivec
+ nop
+
+ std %f12, [$ivec + 0] ! write out ivec
+ std %f14, [$ivec + 8]
+___
+$::code.=<<___;
+ ret
+ restore
+
+.align 16
+2: ldxa [$inp]0x82, %o0 ! avoid read-after-write hazard
+ ! and ~3x deterioration
+ ! in inp==out case
+ faligndata %f0, %f0, %f4 ! handle unaligned output
+ faligndata %f0, %f2, %f6
+ faligndata %f2, %f2, %f8
+
+ stda %f4, [$out + $omask]0xc0 ! partial store
+ std %f6, [$out + 8]
+ add $out, 16, $out
+ orn %g0, $omask, $omask
+ stda %f8, [$out + $omask]0xc0 ! partial store
+
+ brnz,pt $len, .L${bits}_cbc_dec_loop2x+4
+ orn %g0, $omask, $omask
+___
+$::code.=<<___ if ($::evp);
+ st %f12, [$ivec + 0]
+ st %f13, [$ivec + 4]
+ st %f14, [$ivec + 8]
+ st %f15, [$ivec + 12]
+___
+$::code.=<<___ if (!$::evp);
+ brnz,pn $ivoff, .L${bits}_cbc_dec_unaligned_ivec
+ nop
+
+ std %f12, [$ivec + 0] ! write out ivec
+ std %f14, [$ivec + 8]
+___
+$::code.=<<___;
+ ret
+ restore
+
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+.align 32
+.L${bits}_cbc_dec_loop2x:
+ ldx [$inp + 0], %o0
+ ldx [$inp + 8], %o1
+ ldx [$inp + 16], %o2
+ brz,pt $ileft, 4f
+ ldx [$inp + 24], %o3
+
+ ldx [$inp + 32], %o4
+ sllx %o0, $ileft, %o0
+ srlx %o1, $iright, %g1
+ or %g1, %o0, %o0
+ sllx %o1, $ileft, %o1
+ srlx %o2, $iright, %g1
+ or %g1, %o1, %o1
+ sllx %o2, $ileft, %o2
+ srlx %o3, $iright, %g1
+ or %g1, %o2, %o2
+ sllx %o3, $ileft, %o3
+ srlx %o4, $iright, %o4
+ or %o4, %o3, %o3
+4:
+ xor %g4, %o0, %o4 ! ^= rk[0]
+ xor %g5, %o1, %o5
+ movxtod %o4, %f0
+ movxtod %o5, %f2
+ xor %g4, %o2, %o4
+ xor %g5, %o3, %o5
+ movxtod %o4, %f4
+ movxtod %o5, %f6
+
+ prefetch [$out + 63], 22
+ prefetch [$inp + 32+63], 20
+ call _${alg}${bits}_decrypt_2x
+ add $inp, 32, $inp
+
+ movxtod %o0, %f8
+ movxtod %o1, %f10
+ fxor %f12, %f0, %f0 ! ^= ivec
+ fxor %f14, %f2, %f2
+ movxtod %o2, %f12
+ movxtod %o3, %f14
+ fxor %f8, %f4, %f4
+ fxor %f10, %f6, %f6
+
+ brnz,pn $ooff, 2f
+ sub $len, 2, $len
+
+ std %f0, [$out + 0]
+ std %f2, [$out + 8]
+ std %f4, [$out + 16]
+ std %f6, [$out + 24]
+ brnz,pt $len, .L${bits}_cbc_dec_loop2x
+ add $out, 32, $out
+___
+$::code.=<<___ if ($::evp);
+ st %f12, [$ivec + 0]
+ st %f13, [$ivec + 4]
+ st %f14, [$ivec + 8]
+ st %f15, [$ivec + 12]
+___
+$::code.=<<___ if (!$::evp);
+ brnz,pn $ivoff, .L${bits}_cbc_dec_unaligned_ivec
+ nop
+
+ std %f12, [$ivec + 0] ! write out ivec
+ std %f14, [$ivec + 8]
+___
+$::code.=<<___;
+ ret
+ restore
+
+.align 16
+2: ldxa [$inp]0x82, %o0 ! avoid read-after-write hazard
+ ! and ~3x deterioration
+ ! in inp==out case
+ faligndata %f0, %f0, %f8 ! handle unaligned output
+ faligndata %f0, %f2, %f0
+ faligndata %f2, %f4, %f2
+ faligndata %f4, %f6, %f4
+ faligndata %f6, %f6, %f6
+ stda %f8, [$out + $omask]0xc0 ! partial store
+ std %f0, [$out + 8]
+ std %f2, [$out + 16]
+ std %f4, [$out + 24]
+ add $out, 32, $out
+ orn %g0, $omask, $omask
+ stda %f6, [$out + $omask]0xc0 ! partial store
+
+ brnz,pt $len, .L${bits}_cbc_dec_loop2x+4
+ orn %g0, $omask, $omask
+___
+$::code.=<<___ if ($::evp);
+ st %f12, [$ivec + 0]
+ st %f13, [$ivec + 4]
+ st %f14, [$ivec + 8]
+ st %f15, [$ivec + 12]
+___
+$::code.=<<___ if (!$::evp);
+ brnz,pn $ivoff, .L${bits}_cbc_dec_unaligned_ivec
+ nop
+
+ std %f12, [$ivec + 0] ! write out ivec
+ std %f14, [$ivec + 8]
+ ret
+ restore
+
+.align 16
+.L${bits}_cbc_dec_unaligned_ivec:
+ alignaddrl $ivec, $ivoff, %g0 ! handle unaligned ivec
+ mov 0xff, $omask
+ srl $omask, $ivoff, $omask
+ faligndata %f12, %f12, %f0
+ faligndata %f12, %f14, %f2
+ faligndata %f14, %f14, %f4
+ stda %f0, [$ivec + $omask]0xc0
+ std %f2, [$ivec + 8]
+ add $ivec, 16, $ivec
+ orn %g0, $omask, $omask
+ stda %f4, [$ivec + $omask]0xc0
+___
+$::code.=<<___;
+ ret
+ restore
+
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+.align 32
+.L${bits}cbc_dec_blk:
+ add $out, $len, $blk_init
+ and $blk_init, 63, $blk_init ! tail
+ sub $len, $blk_init, $len
+ add $blk_init, 15, $blk_init ! round up to 16n
+ srlx $len, 4, $len
+ srl $blk_init, 4, $blk_init
+ sub $len, 1, $len
+ add $blk_init, 1, $blk_init
+
+.L${bits}_cbc_dec_blk_loop2x:
+ ldx [$inp + 0], %o0
+ ldx [$inp + 8], %o1
+ ldx [$inp + 16], %o2
+ brz,pt $ileft, 5f
+ ldx [$inp + 24], %o3
+
+ ldx [$inp + 32], %o4
+ sllx %o0, $ileft, %o0
+ srlx %o1, $iright, %g1
+ or %g1, %o0, %o0
+ sllx %o1, $ileft, %o1
+ srlx %o2, $iright, %g1
+ or %g1, %o1, %o1
+ sllx %o2, $ileft, %o2
+ srlx %o3, $iright, %g1
+ or %g1, %o2, %o2
+ sllx %o3, $ileft, %o3
+ srlx %o4, $iright, %o4
+ or %o4, %o3, %o3
+5:
+ xor %g4, %o0, %o4 ! ^= rk[0]
+ xor %g5, %o1, %o5
+ movxtod %o4, %f0
+ movxtod %o5, %f2
+ xor %g4, %o2, %o4
+ xor %g5, %o3, %o5
+ movxtod %o4, %f4
+ movxtod %o5, %f6
+
+ prefetch [$inp + 32+63], 20
+ call _${alg}${bits}_decrypt_2x
+ add $inp, 32, $inp
+ subcc $len, 2, $len
+
+ movxtod %o0, %f8
+ movxtod %o1, %f10
+ fxor %f12, %f0, %f0 ! ^= ivec
+ fxor %f14, %f2, %f2
+ movxtod %o2, %f12
+ movxtod %o3, %f14
+ fxor %f8, %f4, %f4
+ fxor %f10, %f6, %f6
+
+ stda %f0, [$out]0xe2 ! ASI_BLK_INIT, T4-specific
+ add $out, 8, $out
+ stda %f2, [$out]0xe2 ! ASI_BLK_INIT, T4-specific
+ add $out, 8, $out
+ stda %f4, [$out]0xe2 ! ASI_BLK_INIT, T4-specific
+ add $out, 8, $out
+ stda %f6, [$out]0xe2 ! ASI_BLK_INIT, T4-specific
+ bgu,pt $::size_t_cc, .L${bits}_cbc_dec_blk_loop2x
+ add $out, 8, $out
+
+ add $blk_init, $len, $len
+ andcc $len, 1, %g0 ! is number of blocks even?
+ membar #StoreLoad|#StoreStore
+ bnz,pt %icc, .L${bits}_cbc_dec_loop
+ srl $len, 0, $len
+ brnz,pn $len, .L${bits}_cbc_dec_loop2x
+ nop
+___
+$::code.=<<___ if ($::evp);
+ st %f12, [$ivec + 0] ! write out ivec
+ st %f13, [$ivec + 4]
+ st %f14, [$ivec + 8]
+ st %f15, [$ivec + 12]
+___
+$::code.=<<___ if (!$::evp);
+ brnz,pn $ivoff, 3b
+ nop
+
+ std %f12, [$ivec + 0] ! write out ivec
+ std %f14, [$ivec + 8]
+___
+$::code.=<<___;
+ ret
+ restore
+.type ${alg}${bits}_t4_cbc_decrypt,#function
+.size ${alg}${bits}_t4_cbc_decrypt,.-${alg}${bits}_t4_cbc_decrypt
+___
+}
+
+sub alg_ctr32_implement {
+my ($alg,$bits) = @_;
+
+$::code.=<<___;
+.globl ${alg}${bits}_t4_ctr32_encrypt
+.align 32
+${alg}${bits}_t4_ctr32_encrypt:
+ save %sp, -$::frame, %sp
+
+ prefetch [$inp], 20
+ prefetch [$inp + 63], 20
+ call _${alg}${bits}_load_enckey
+ sllx $len, 4, $len
+
+ ld [$ivec + 0], %l4 ! counter
+ ld [$ivec + 4], %l5
+ ld [$ivec + 8], %l6
+ ld [$ivec + 12], %l7
+
+ sllx %l4, 32, %o5
+ or %l5, %o5, %o5
+ sllx %l6, 32, %g1
+ xor %o5, %g4, %g4 ! ^= rk[0]
+ xor %g1, %g5, %g5
+ movxtod %g4, %f14 ! most significant 64 bits
+
+ sub $inp, $out, $blk_init ! $inp!=$out
+ and $inp, 7, $ileft
+ andn $inp, 7, $inp
+ sll $ileft, 3, $ileft
+ mov 64, $iright
+ mov 0xff, $omask
+ sub $iright, $ileft, $iright
+ and $out, 7, $ooff
+ cmp $len, 255
+ movrnz $ooff, 0, $blk_init ! if ( $out&7 ||
+ movleu $::size_t_cc, 0, $blk_init ! $len<256 ||
+ brnz,pn $blk_init, .L${bits}_ctr32_blk ! $inp==$out)
+ srl $omask, $ooff, $omask
+
+ andcc $len, 16, %g0 ! is number of blocks even?
+ alignaddrl $out, %g0, $out
+ bz %icc, .L${bits}_ctr32_loop2x
+ srlx $len, 4, $len
+.L${bits}_ctr32_loop:
+ ldx [$inp + 0], %o0
+ brz,pt $ileft, 4f
+ ldx [$inp + 8], %o1
+
+ ldx [$inp + 16], %o2
+ sllx %o0, $ileft, %o0
+ srlx %o1, $iright, %g1
+ sllx %o1, $ileft, %o1
+ or %g1, %o0, %o0
+ srlx %o2, $iright, %o2
+ or %o2, %o1, %o1
+4:
+ xor %g5, %l7, %g1 ! ^= rk[0]
+ add %l7, 1, %l7
+ movxtod %g1, %f2
+ srl %l7, 0, %l7 ! clruw
+ prefetch [$out + 63], 22
+ prefetch [$inp + 16+63], 20
+___
+$::code.=<<___ if ($alg eq "aes");
+ aes_eround01 %f16, %f14, %f2, %f4
+ aes_eround23 %f18, %f14, %f2, %f2
+___
+$::code.=<<___ if ($alg eq "cmll");
+ camellia_f %f16, %f2, %f14, %f2
+ camellia_f %f18, %f14, %f2, %f0
+___
+$::code.=<<___;
+ call _${alg}${bits}_encrypt_1x+8
+ add $inp, 16, $inp
+
+ movxtod %o0, %f10
+ movxtod %o1, %f12
+ fxor %f10, %f0, %f0 ! ^= inp
+ fxor %f12, %f2, %f2
+
+ brnz,pn $ooff, 2f
+ sub $len, 1, $len
+
+ std %f0, [$out + 0]
+ std %f2, [$out + 8]
+ brnz,pt $len, .L${bits}_ctr32_loop2x
+ add $out, 16, $out
+
+ ret
+ restore
+
+.align 16
+2: ldxa [$inp]0x82, %o0 ! avoid read-after-write hazard
+ ! and ~3x deterioration
+ ! in inp==out case
+ faligndata %f0, %f0, %f4 ! handle unaligned output
+ faligndata %f0, %f2, %f6
+ faligndata %f2, %f2, %f8
+ stda %f4, [$out + $omask]0xc0 ! partial store
+ std %f6, [$out + 8]
+ add $out, 16, $out
+ orn %g0, $omask, $omask
+ stda %f8, [$out + $omask]0xc0 ! partial store
+
+ brnz,pt $len, .L${bits}_ctr32_loop2x+4
+ orn %g0, $omask, $omask
+
+ ret
+ restore
+
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+.align 32
+.L${bits}_ctr32_loop2x:
+ ldx [$inp + 0], %o0
+ ldx [$inp + 8], %o1
+ ldx [$inp + 16], %o2
+ brz,pt $ileft, 4f
+ ldx [$inp + 24], %o3
+
+ ldx [$inp + 32], %o4
+ sllx %o0, $ileft, %o0
+ srlx %o1, $iright, %g1
+ or %g1, %o0, %o0
+ sllx %o1, $ileft, %o1
+ srlx %o2, $iright, %g1
+ or %g1, %o1, %o1
+ sllx %o2, $ileft, %o2
+ srlx %o3, $iright, %g1
+ or %g1, %o2, %o2
+ sllx %o3, $ileft, %o3
+ srlx %o4, $iright, %o4
+ or %o4, %o3, %o3
+4:
+ xor %g5, %l7, %g1 ! ^= rk[0]
+ add %l7, 1, %l7
+ movxtod %g1, %f2
+ srl %l7, 0, %l7 ! clruw
+ xor %g5, %l7, %g1
+ add %l7, 1, %l7
+ movxtod %g1, %f6
+ srl %l7, 0, %l7 ! clruw
+ prefetch [$out + 63], 22
+ prefetch [$inp + 32+63], 20
+___
+$::code.=<<___ if ($alg eq "aes");
+ aes_eround01 %f16, %f14, %f2, %f8
+ aes_eround23 %f18, %f14, %f2, %f2
+ aes_eround01 %f16, %f14, %f6, %f10
+ aes_eround23 %f18, %f14, %f6, %f6
+___
+$::code.=<<___ if ($alg eq "cmll");
+ camellia_f %f16, %f2, %f14, %f2
+ camellia_f %f16, %f6, %f14, %f6
+ camellia_f %f18, %f14, %f2, %f0
+ camellia_f %f18, %f14, %f6, %f4
+___
+$::code.=<<___;
+ call _${alg}${bits}_encrypt_2x+16
+ add $inp, 32, $inp
+
+ movxtod %o0, %f8
+ movxtod %o1, %f10
+ movxtod %o2, %f12
+ fxor %f8, %f0, %f0 ! ^= inp
+ movxtod %o3, %f8
+ fxor %f10, %f2, %f2
+ fxor %f12, %f4, %f4
+ fxor %f8, %f6, %f6
+
+ brnz,pn $ooff, 2f
+ sub $len, 2, $len
+
+ std %f0, [$out + 0]
+ std %f2, [$out + 8]
+ std %f4, [$out + 16]
+ std %f6, [$out + 24]
+ brnz,pt $len, .L${bits}_ctr32_loop2x
+ add $out, 32, $out
+
+ ret
+ restore
+
+.align 16
+2: ldxa [$inp]0x82, %o0 ! avoid read-after-write hazard
+ ! and ~3x deterioration
+ ! in inp==out case
+ faligndata %f0, %f0, %f8 ! handle unaligned output
+ faligndata %f0, %f2, %f0
+ faligndata %f2, %f4, %f2
+ faligndata %f4, %f6, %f4
+ faligndata %f6, %f6, %f6
+
+ stda %f8, [$out + $omask]0xc0 ! partial store
+ std %f0, [$out + 8]
+ std %f2, [$out + 16]
+ std %f4, [$out + 24]
+ add $out, 32, $out
+ orn %g0, $omask, $omask
+ stda %f6, [$out + $omask]0xc0 ! partial store
+
+ brnz,pt $len, .L${bits}_ctr32_loop2x+4
+ orn %g0, $omask, $omask
+
+ ret
+ restore
+
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+.align 32
+.L${bits}_ctr32_blk:
+ add $out, $len, $blk_init
+ and $blk_init, 63, $blk_init ! tail
+ sub $len, $blk_init, $len
+ add $blk_init, 15, $blk_init ! round up to 16n
+ srlx $len, 4, $len
+ srl $blk_init, 4, $blk_init
+ sub $len, 1, $len
+ add $blk_init, 1, $blk_init
+
+.L${bits}_ctr32_blk_loop2x:
+ ldx [$inp + 0], %o0
+ ldx [$inp + 8], %o1
+ ldx [$inp + 16], %o2
+ brz,pt $ileft, 5f
+ ldx [$inp + 24], %o3
+
+ ldx [$inp + 32], %o4
+ sllx %o0, $ileft, %o0
+ srlx %o1, $iright, %g1
+ or %g1, %o0, %o0
+ sllx %o1, $ileft, %o1
+ srlx %o2, $iright, %g1
+ or %g1, %o1, %o1
+ sllx %o2, $ileft, %o2
+ srlx %o3, $iright, %g1
+ or %g1, %o2, %o2
+ sllx %o3, $ileft, %o3
+ srlx %o4, $iright, %o4
+ or %o4, %o3, %o3
+5:
+ xor %g5, %l7, %g1 ! ^= rk[0]
+ add %l7, 1, %l7
+ movxtod %g1, %f2
+ srl %l7, 0, %l7 ! clruw
+ xor %g5, %l7, %g1
+ add %l7, 1, %l7
+ movxtod %g1, %f6
+ srl %l7, 0, %l7 ! clruw
+ prefetch [$inp + 32+63], 20
+___
+$::code.=<<___ if ($alg eq "aes");
+ aes_eround01 %f16, %f14, %f2, %f8
+ aes_eround23 %f18, %f14, %f2, %f2
+ aes_eround01 %f16, %f14, %f6, %f10
+ aes_eround23 %f18, %f14, %f6, %f6
+___
+$::code.=<<___ if ($alg eq "cmll");
+ camellia_f %f16, %f2, %f14, %f2
+ camellia_f %f16, %f6, %f14, %f6
+ camellia_f %f18, %f14, %f2, %f0
+ camellia_f %f18, %f14, %f6, %f4
+___
+$::code.=<<___;
+ call _${alg}${bits}_encrypt_2x+16
+ add $inp, 32, $inp
+ subcc $len, 2, $len
+
+ movxtod %o0, %f8
+ movxtod %o1, %f10
+ movxtod %o2, %f12
+ fxor %f8, %f0, %f0 ! ^= inp
+ movxtod %o3, %f8
+ fxor %f10, %f2, %f2
+ fxor %f12, %f4, %f4
+ fxor %f8, %f6, %f6
+
+ stda %f0, [$out]0xe2 ! ASI_BLK_INIT, T4-specific
+ add $out, 8, $out
+ stda %f2, [$out]0xe2 ! ASI_BLK_INIT, T4-specific
+ add $out, 8, $out
+ stda %f4, [$out]0xe2 ! ASI_BLK_INIT, T4-specific
+ add $out, 8, $out
+ stda %f6, [$out]0xe2 ! ASI_BLK_INIT, T4-specific
+ bgu,pt $::size_t_cc, .L${bits}_ctr32_blk_loop2x
+ add $out, 8, $out
+
+ add $blk_init, $len, $len
+ andcc $len, 1, %g0 ! is number of blocks even?
+ membar #StoreLoad|#StoreStore
+ bnz,pt %icc, .L${bits}_ctr32_loop
+ srl $len, 0, $len
+ brnz,pn $len, .L${bits}_ctr32_loop2x
+ nop
+
+ ret
+ restore
+.type ${alg}${bits}_t4_ctr32_encrypt,#function
+.size ${alg}${bits}_t4_ctr32_encrypt,.-${alg}${bits}_t4_ctr32_encrypt
+___
+}
+
+sub alg_xts_implement {
+my ($alg,$bits,$dir) = @_;
+my ($inp,$out,$len,$key1,$key2,$ivec)=map("%i$_",(0..5));
+my $rem=$ivec;
+
+$::code.=<<___;
+.globl ${alg}${bits}_t4_xts_${dir}crypt
+.align 32
+${alg}${bits}_t4_xts_${dir}crypt:
+ save %sp, -$::frame-16, %sp
+
+ mov $ivec, %o0
+ add %fp, $::bias-16, %o1
+ call ${alg}_t4_encrypt
+ mov $key2, %o2
+
+ add %fp, $::bias-16, %l7
+ ldxa [%l7]0x88, %g2
+ add %fp, $::bias-8, %l7
+ ldxa [%l7]0x88, %g3 ! %g3:%g2 is tweak
+
+ sethi %hi(0x76543210), %l7
+ or %l7, %lo(0x76543210), %l7
+ bmask %l7, %g0, %g0 ! byte swap mask
+
+ prefetch [$inp], 20
+ prefetch [$inp + 63], 20
+ call _${alg}${bits}_load_${dir}ckey
+ and $len, 15, $rem
+ and $len, -16, $len
+___
+$code.=<<___ if ($dir eq "de");
+ mov 0, %l7
+ movrnz $rem, 16, %l7
+ sub $len, %l7, $len
+___
+$code.=<<___;
+
+ sub $inp, $out, $blk_init ! $inp!=$out
+ and $inp, 7, $ileft
+ andn $inp, 7, $inp
+ sll $ileft, 3, $ileft
+ mov 64, $iright
+ mov 0xff, $omask
+ sub $iright, $ileft, $iright
+ and $out, 7, $ooff
+ cmp $len, 255
+ movrnz $ooff, 0, $blk_init ! if ( $out&7 ||
+ movleu $::size_t_cc, 0, $blk_init ! $len<256 ||
+ brnz,pn $blk_init, .L${bits}_xts_${dir}blk ! $inp==$out)
+ srl $omask, $ooff, $omask
+
+ andcc $len, 16, %g0 ! is number of blocks even?
+___
+$code.=<<___ if ($dir eq "de");
+ brz,pn $len, .L${bits}_xts_${dir}steal
+___
+$code.=<<___;
+ alignaddrl $out, %g0, $out
+ bz %icc, .L${bits}_xts_${dir}loop2x
+ srlx $len, 4, $len
+.L${bits}_xts_${dir}loop:
+ ldx [$inp + 0], %o0
+ brz,pt $ileft, 4f
+ ldx [$inp + 8], %o1
+
+ ldx [$inp + 16], %o2
+ sllx %o0, $ileft, %o0
+ srlx %o1, $iright, %g1
+ sllx %o1, $ileft, %o1
+ or %g1, %o0, %o0
+ srlx %o2, $iright, %o2
+ or %o2, %o1, %o1
+4:
+ movxtod %g2, %f12
+ movxtod %g3, %f14
+ bshuffle %f12, %f12, %f12
+ bshuffle %f14, %f14, %f14
+
+ xor %g4, %o0, %o0 ! ^= rk[0]
+ xor %g5, %o1, %o1
+ movxtod %o0, %f0
+ movxtod %o1, %f2
+
+ fxor %f12, %f0, %f0 ! ^= tweak[0]
+ fxor %f14, %f2, %f2
+
+ prefetch [$out + 63], 22
+ prefetch [$inp + 16+63], 20
+ call _${alg}${bits}_${dir}crypt_1x
+ add $inp, 16, $inp
+
+ fxor %f12, %f0, %f0 ! ^= tweak[0]
+ fxor %f14, %f2, %f2
+
+ srax %g3, 63, %l7 ! next tweak value
+ addcc %g2, %g2, %g2
+ and %l7, 0x87, %l7
+ addxc %g3, %g3, %g3
+ xor %l7, %g2, %g2
+
+ brnz,pn $ooff, 2f
+ sub $len, 1, $len
+
+ std %f0, [$out + 0]
+ std %f2, [$out + 8]
+ brnz,pt $len, .L${bits}_xts_${dir}loop2x
+ add $out, 16, $out
+
+ brnz,pn $rem, .L${bits}_xts_${dir}steal
+ nop
+
+ ret
+ restore
+
+.align 16
+2: ldxa [$inp]0x82, %o0 ! avoid read-after-write hazard
+ ! and ~3x deterioration
+ ! in inp==out case
+ faligndata %f0, %f0, %f4 ! handle unaligned output
+ faligndata %f0, %f2, %f6
+ faligndata %f2, %f2, %f8
+ stda %f4, [$out + $omask]0xc0 ! partial store
+ std %f6, [$out + 8]
+ add $out, 16, $out
+ orn %g0, $omask, $omask
+ stda %f8, [$out + $omask]0xc0 ! partial store
+
+ brnz,pt $len, .L${bits}_xts_${dir}loop2x+4
+ orn %g0, $omask, $omask
+
+ brnz,pn $rem, .L${bits}_xts_${dir}steal
+ nop
+
+ ret
+ restore
+
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+.align 32
+.L${bits}_xts_${dir}loop2x:
+ ldx [$inp + 0], %o0
+ ldx [$inp + 8], %o1
+ ldx [$inp + 16], %o2
+ brz,pt $ileft, 4f
+ ldx [$inp + 24], %o3
+
+ ldx [$inp + 32], %o4
+ sllx %o0, $ileft, %o0
+ srlx %o1, $iright, %g1
+ or %g1, %o0, %o0
+ sllx %o1, $ileft, %o1
+ srlx %o2, $iright, %g1
+ or %g1, %o1, %o1
+ sllx %o2, $ileft, %o2
+ srlx %o3, $iright, %g1
+ or %g1, %o2, %o2
+ sllx %o3, $ileft, %o3
+ srlx %o4, $iright, %o4
+ or %o4, %o3, %o3
+4:
+ movxtod %g2, %f12
+ movxtod %g3, %f14
+ bshuffle %f12, %f12, %f12
+ bshuffle %f14, %f14, %f14
+
+ srax %g3, 63, %l7 ! next tweak value
+ addcc %g2, %g2, %g2
+ and %l7, 0x87, %l7
+ addxc %g3, %g3, %g3
+ xor %l7, %g2, %g2
+
+ movxtod %g2, %f8
+ movxtod %g3, %f10
+ bshuffle %f8, %f8, %f8
+ bshuffle %f10, %f10, %f10
+
+ xor %g4, %o0, %o0 ! ^= rk[0]
+ xor %g5, %o1, %o1
+ xor %g4, %o2, %o2 ! ^= rk[0]
+ xor %g5, %o3, %o3
+ movxtod %o0, %f0
+ movxtod %o1, %f2
+ movxtod %o2, %f4
+ movxtod %o3, %f6
+
+ fxor %f12, %f0, %f0 ! ^= tweak[0]
+ fxor %f14, %f2, %f2
+ fxor %f8, %f4, %f4 ! ^= tweak[0]
+ fxor %f10, %f6, %f6
+
+ prefetch [$out + 63], 22
+ prefetch [$inp + 32+63], 20
+ call _${alg}${bits}_${dir}crypt_2x
+ add $inp, 32, $inp
+
+ movxtod %g2, %f8
+ movxtod %g3, %f10
+
+ srax %g3, 63, %l7 ! next tweak value
+ addcc %g2, %g2, %g2
+ and %l7, 0x87, %l7
+ addxc %g3, %g3, %g3
+ xor %l7, %g2, %g2
+
+ bshuffle %f8, %f8, %f8
+ bshuffle %f10, %f10, %f10
+
+ fxor %f12, %f0, %f0 ! ^= tweak[0]
+ fxor %f14, %f2, %f2
+ fxor %f8, %f4, %f4
+ fxor %f10, %f6, %f6
+
+ brnz,pn $ooff, 2f
+ sub $len, 2, $len
+
+ std %f0, [$out + 0]
+ std %f2, [$out + 8]
+ std %f4, [$out + 16]
+ std %f6, [$out + 24]
+ brnz,pt $len, .L${bits}_xts_${dir}loop2x
+ add $out, 32, $out
+
+ fsrc2 %f4, %f0
+ fsrc2 %f6, %f2
+ brnz,pn $rem, .L${bits}_xts_${dir}steal
+ nop
+
+ ret
+ restore
+
+.align 16
+2: ldxa [$inp]0x82, %o0 ! avoid read-after-write hazard
+ ! and ~3x deterioration
+ ! in inp==out case
+ faligndata %f0, %f0, %f8 ! handle unaligned output
+ faligndata %f0, %f2, %f10
+ faligndata %f2, %f4, %f12
+ faligndata %f4, %f6, %f14
+ faligndata %f6, %f6, %f0
+
+ stda %f8, [$out + $omask]0xc0 ! partial store
+ std %f10, [$out + 8]
+ std %f12, [$out + 16]
+ std %f14, [$out + 24]
+ add $out, 32, $out
+ orn %g0, $omask, $omask
+ stda %f0, [$out + $omask]0xc0 ! partial store
+
+ brnz,pt $len, .L${bits}_xts_${dir}loop2x+4
+ orn %g0, $omask, $omask
+
+ fsrc2 %f4, %f0
+ fsrc2 %f6, %f2
+ brnz,pn $rem, .L${bits}_xts_${dir}steal
+ nop
+
+ ret
+ restore
+
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+.align 32
+.L${bits}_xts_${dir}blk:
+ add $out, $len, $blk_init
+ and $blk_init, 63, $blk_init ! tail
+ sub $len, $blk_init, $len
+ add $blk_init, 15, $blk_init ! round up to 16n
+ srlx $len, 4, $len
+ srl $blk_init, 4, $blk_init
+ sub $len, 1, $len
+ add $blk_init, 1, $blk_init
+
+.L${bits}_xts_${dir}blk2x:
+ ldx [$inp + 0], %o0
+ ldx [$inp + 8], %o1
+ ldx [$inp + 16], %o2
+ brz,pt $ileft, 5f
+ ldx [$inp + 24], %o3
+
+ ldx [$inp + 32], %o4
+ sllx %o0, $ileft, %o0
+ srlx %o1, $iright, %g1
+ or %g1, %o0, %o0
+ sllx %o1, $ileft, %o1
+ srlx %o2, $iright, %g1
+ or %g1, %o1, %o1
+ sllx %o2, $ileft, %o2
+ srlx %o3, $iright, %g1
+ or %g1, %o2, %o2
+ sllx %o3, $ileft, %o3
+ srlx %o4, $iright, %o4
+ or %o4, %o3, %o3
+5:
+ movxtod %g2, %f12
+ movxtod %g3, %f14
+ bshuffle %f12, %f12, %f12
+ bshuffle %f14, %f14, %f14
+
+ srax %g3, 63, %l7 ! next tweak value
+ addcc %g2, %g2, %g2
+ and %l7, 0x87, %l7
+ addxc %g3, %g3, %g3
+ xor %l7, %g2, %g2
+
+ movxtod %g2, %f8
+ movxtod %g3, %f10
+ bshuffle %f8, %f8, %f8
+ bshuffle %f10, %f10, %f10
+
+ xor %g4, %o0, %o0 ! ^= rk[0]
+ xor %g5, %o1, %o1
+ xor %g4, %o2, %o2 ! ^= rk[0]
+ xor %g5, %o3, %o3
+ movxtod %o0, %f0
+ movxtod %o1, %f2
+ movxtod %o2, %f4
+ movxtod %o3, %f6
+
+ fxor %f12, %f0, %f0 ! ^= tweak[0]
+ fxor %f14, %f2, %f2
+ fxor %f8, %f4, %f4 ! ^= tweak[0]
+ fxor %f10, %f6, %f6
+
+ prefetch [$inp + 32+63], 20
+ call _${alg}${bits}_${dir}crypt_2x
+ add $inp, 32, $inp
+
+ movxtod %g2, %f8
+ movxtod %g3, %f10
+
+ srax %g3, 63, %l7 ! next tweak value
+ addcc %g2, %g2, %g2
+ and %l7, 0x87, %l7
+ addxc %g3, %g3, %g3
+ xor %l7, %g2, %g2
+
+ bshuffle %f8, %f8, %f8
+ bshuffle %f10, %f10, %f10
+
+ fxor %f12, %f0, %f0 ! ^= tweak[0]
+ fxor %f14, %f2, %f2
+ fxor %f8, %f4, %f4
+ fxor %f10, %f6, %f6
+
+ stda %f0, [$out]0xe2 ! ASI_BLK_INIT, T4-specific
+ add $out, 8, $out
+ stda %f2, [$out]0xe2 ! ASI_BLK_INIT, T4-specific
+ add $out, 8, $out
+ stda %f4, [$out]0xe2 ! ASI_BLK_INIT, T4-specific
+ add $out, 8, $out
+ stda %f6, [$out]0xe2 ! ASI_BLK_INIT, T4-specific
+ bgu,pt $::size_t_cc, .L${bits}_xts_${dir}blk2x
+ add $out, 8, $out
+
+ add $blk_init, $len, $len
+ andcc $len, 1, %g0 ! is number of blocks even?
+ membar #StoreLoad|#StoreStore
+ bnz,pt %icc, .L${bits}_xts_${dir}loop
+ srl $len, 0, $len
+ brnz,pn $len, .L${bits}_xts_${dir}loop2x
+ nop
+
+ fsrc2 %f4, %f0
+ fsrc2 %f6, %f2
+ brnz,pn $rem, .L${bits}_xts_${dir}steal
+ nop
+
+ ret
+ restore
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+___
+$code.=<<___ if ($dir eq "en");
+.align 32
+.L${bits}_xts_${dir}steal:
+ std %f0, [%fp + $::bias-16] ! copy of output
+ std %f2, [%fp + $::bias-8]
+
+ srl $ileft, 3, $ileft
+ add %fp, $::bias-16, %l7
+ add $inp, $ileft, $inp ! original $inp+$len&-15
+ add $out, $ooff, $out ! original $out+$len&-15
+ mov 0, $ileft
+ nop ! align
+
+.L${bits}_xts_${dir}stealing:
+ ldub [$inp + $ileft], %o0
+ ldub [%l7 + $ileft], %o1
+ dec $rem
+ stb %o0, [%l7 + $ileft]
+ stb %o1, [$out + $ileft]
+ brnz $rem, .L${bits}_xts_${dir}stealing
+ inc $ileft
+
+ mov %l7, $inp
+ sub $out, 16, $out
+ mov 0, $ileft
+ sub $out, $ooff, $out
+ ba .L${bits}_xts_${dir}loop ! one more time
+ mov 1, $len ! $rem is 0
+___
+$code.=<<___ if ($dir eq "de");
+.align 32
+.L${bits}_xts_${dir}steal:
+ ldx [$inp + 0], %o0
+ brz,pt $ileft, 8f
+ ldx [$inp + 8], %o1
+
+ ldx [$inp + 16], %o2
+ sllx %o0, $ileft, %o0
+ srlx %o1, $iright, %g1
+ sllx %o1, $ileft, %o1
+ or %g1, %o0, %o0
+ srlx %o2, $iright, %o2
+ or %o2, %o1, %o1
+8:
+ srax %g3, 63, %l7 ! next tweak value
+ addcc %g2, %g2, %o2
+ and %l7, 0x87, %l7
+ addxc %g3, %g3, %o3
+ xor %l7, %o2, %o2
+
+ movxtod %o2, %f12
+ movxtod %o3, %f14
+ bshuffle %f12, %f12, %f12
+ bshuffle %f14, %f14, %f14
+
+ xor %g4, %o0, %o0 ! ^= rk[0]
+ xor %g5, %o1, %o1
+ movxtod %o0, %f0
+ movxtod %o1, %f2
+
+ fxor %f12, %f0, %f0 ! ^= tweak[0]
+ fxor %f14, %f2, %f2
+
+ call _${alg}${bits}_${dir}crypt_1x
+ add $inp, 16, $inp
+
+ fxor %f12, %f0, %f0 ! ^= tweak[0]
+ fxor %f14, %f2, %f2
+
+ std %f0, [%fp + $::bias-16]
+ std %f2, [%fp + $::bias-8]
+
+ srl $ileft, 3, $ileft
+ add %fp, $::bias-16, %l7
+ add $inp, $ileft, $inp ! original $inp+$len&-15
+ add $out, $ooff, $out ! original $out+$len&-15
+ mov 0, $ileft
+ add $out, 16, $out
+ nop ! align
+
+.L${bits}_xts_${dir}stealing:
+ ldub [$inp + $ileft], %o0
+ ldub [%l7 + $ileft], %o1
+ dec $rem
+ stb %o0, [%l7 + $ileft]
+ stb %o1, [$out + $ileft]
+ brnz $rem, .L${bits}_xts_${dir}stealing
+ inc $ileft
+
+ mov %l7, $inp
+ sub $out, 16, $out
+ mov 0, $ileft
+ sub $out, $ooff, $out
+ ba .L${bits}_xts_${dir}loop ! one more time
+ mov 1, $len ! $rem is 0
+___
+$code.=<<___;
+ ret
+ restore
+.type ${alg}${bits}_t4_xts_${dir}crypt,#function
+.size ${alg}${bits}_t4_xts_${dir}crypt,.-${alg}${bits}_t4_xts_${dir}crypt
+___
+}
+
+# Purpose of these subroutines is to explicitly encode VIS instructions,
+# so that one can compile the module without having to specify VIS
+# extentions on compiler command line, e.g. -xarch=v9 vs. -xarch=v9a.
+# Idea is to reserve for option to produce "universal" binary and let
+# programmer detect if current CPU is VIS capable at run-time.
+sub unvis {
+my ($mnemonic,$rs1,$rs2,$rd)=@_;
+my ($ref,$opf);
+my %visopf = ( "faligndata" => 0x048,
+ "bshuffle" => 0x04c,
+ "fnot2" => 0x066,
+ "fxor" => 0x06c,
+ "fsrc2" => 0x078 );
+
+ $ref = "$mnemonic\t$rs1,$rs2,$rd";
+
+ if ($opf=$visopf{$mnemonic}) {
+ foreach ($rs1,$rs2,$rd) {
+ return $ref if (!/%f([0-9]{1,2})/);
+ $_=$1;
+ if ($1>=32) {
+ return $ref if ($1&1);
+ # re-encode for upper double register addressing
+ $_=($1|$1>>5)&31;
+ }
+ }
+
+ return sprintf ".word\t0x%08x !%s",
+ 0x81b00000|$rd<<25|$rs1<<14|$opf<<5|$rs2,
+ $ref;
+ } else {
+ return $ref;
+ }
+}
+
+sub unvis3 {
+my ($mnemonic,$rs1,$rs2,$rd)=@_;
+my %bias = ( "g" => 0, "o" => 8, "l" => 16, "i" => 24 );
+my ($ref,$opf);
+my %visopf = ( "addxc" => 0x011,
+ "addxccc" => 0x013,
+ "umulxhi" => 0x016,
+ "alignaddr" => 0x018,
+ "bmask" => 0x019,
+ "alignaddrl" => 0x01a );
+
+ $ref = "$mnemonic\t$rs1,$rs2,$rd";
+
+ if ($opf=$visopf{$mnemonic}) {
+ foreach ($rs1,$rs2,$rd) {
+ return $ref if (!/%([goli])([0-9])/);
+ $_=$bias{$1}+$2;
+ }
+
+ return sprintf ".word\t0x%08x !%s",
+ 0x81b00000|$rd<<25|$rs1<<14|$opf<<5|$rs2,
+ $ref;
+ } else {
+ return $ref;
+ }
+}
+
+sub unaes_round { # 4-argument instructions
+my ($mnemonic,$rs1,$rs2,$rs3,$rd)=@_;
+my ($ref,$opf);
+my %aesopf = ( "aes_eround01" => 0,
+ "aes_eround23" => 1,
+ "aes_dround01" => 2,
+ "aes_dround23" => 3,
+ "aes_eround01_l"=> 4,
+ "aes_eround23_l"=> 5,
+ "aes_dround01_l"=> 6,
+ "aes_dround23_l"=> 7,
+ "aes_kexpand1" => 8 );
+
+ $ref = "$mnemonic\t$rs1,$rs2,$rs3,$rd";
+
+ if (defined($opf=$aesopf{$mnemonic})) {
+ $rs3 = ($rs3 =~ /%f([0-6]*[02468])/) ? (($1|$1>>5)&31) : $rs3;
+ foreach ($rs1,$rs2,$rd) {
+ return $ref if (!/%f([0-9]{1,2})/);
+ $_=$1;
+ if ($1>=32) {
+ return $ref if ($1&1);
+ # re-encode for upper double register addressing
+ $_=($1|$1>>5)&31;
+ }
+ }
+
+ return sprintf ".word\t0x%08x !%s",
+ 2<<30|$rd<<25|0x19<<19|$rs1<<14|$rs3<<9|$opf<<5|$rs2,
+ $ref;
+ } else {
+ return $ref;
+ }
+}
+
+sub unaes_kexpand { # 3-argument instructions
+my ($mnemonic,$rs1,$rs2,$rd)=@_;
+my ($ref,$opf);
+my %aesopf = ( "aes_kexpand0" => 0x130,
+ "aes_kexpand2" => 0x131 );
+
+ $ref = "$mnemonic\t$rs1,$rs2,$rd";
+
+ if (defined($opf=$aesopf{$mnemonic})) {
+ foreach ($rs1,$rs2,$rd) {
+ return $ref if (!/%f([0-9]{1,2})/);
+ $_=$1;
+ if ($1>=32) {
+ return $ref if ($1&1);
+ # re-encode for upper double register addressing
+ $_=($1|$1>>5)&31;
+ }
+ }
+
+ return sprintf ".word\t0x%08x !%s",
+ 2<<30|$rd<<25|0x36<<19|$rs1<<14|$opf<<5|$rs2,
+ $ref;
+ } else {
+ return $ref;
+ }
+}
+
+sub uncamellia_f { # 4-argument instructions
+my ($mnemonic,$rs1,$rs2,$rs3,$rd)=@_;
+my ($ref,$opf);
+
+ $ref = "$mnemonic\t$rs1,$rs2,$rs3,$rd";
+
+ if (1) {
+ $rs3 = ($rs3 =~ /%f([0-6]*[02468])/) ? (($1|$1>>5)&31) : $rs3;
+ foreach ($rs1,$rs2,$rd) {
+ return $ref if (!/%f([0-9]{1,2})/);
+ $_=$1;
+ if ($1>=32) {
+ return $ref if ($1&1);
+ # re-encode for upper double register addressing
+ $_=($1|$1>>5)&31;
+ }
+ }
+
+ return sprintf ".word\t0x%08x !%s",
+ 2<<30|$rd<<25|0x19<<19|$rs1<<14|$rs3<<9|0xc<<5|$rs2,
+ $ref;
+ } else {
+ return $ref;
+ }
+}
+
+sub uncamellia3 { # 3-argument instructions
+my ($mnemonic,$rs1,$rs2,$rd)=@_;
+my ($ref,$opf);
+my %cmllopf = ( "camellia_fl" => 0x13c,
+ "camellia_fli" => 0x13d );
+
+ $ref = "$mnemonic\t$rs1,$rs2,$rd";
+
+ if (defined($opf=$cmllopf{$mnemonic})) {
+ foreach ($rs1,$rs2,$rd) {
+ return $ref if (!/%f([0-9]{1,2})/);
+ $_=$1;
+ if ($1>=32) {
+ return $ref if ($1&1);
+ # re-encode for upper double register addressing
+ $_=($1|$1>>5)&31;
+ }
+ }
+
+ return sprintf ".word\t0x%08x !%s",
+ 2<<30|$rd<<25|0x36<<19|$rs1<<14|$opf<<5|$rs2,
+ $ref;
+ } else {
+ return $ref;
+ }
+}
+
+sub unmovxtox { # 2-argument instructions
+my ($mnemonic,$rs,$rd)=@_;
+my %bias = ( "g" => 0, "o" => 8, "l" => 16, "i" => 24, "f" => 0 );
+my ($ref,$opf);
+my %movxopf = ( "movdtox" => 0x110,
+ "movstouw" => 0x111,
+ "movstosw" => 0x113,
+ "movxtod" => 0x118,
+ "movwtos" => 0x119 );
+
+ $ref = "$mnemonic\t$rs,$rd";
+
+ if (defined($opf=$movxopf{$mnemonic})) {
+ foreach ($rs,$rd) {
+ return $ref if (!/%([fgoli])([0-9]{1,2})/);
+ $_=$bias{$1}+$2;
+ if ($2>=32) {
+ return $ref if ($2&1);
+ # re-encode for upper double register addressing
+ $_=($2|$2>>5)&31;
+ }
+ }
+
+ return sprintf ".word\t0x%08x !%s",
+ 2<<30|$rd<<25|0x36<<19|$opf<<5|$rs,
+ $ref;
+ } else {
+ return $ref;
+ }
+}
+
+sub undes {
+my ($mnemonic)=shift;
+my @args=@_;
+my ($ref,$opf);
+my %desopf = ( "des_round" => 0b1001,
+ "des_ip" => 0b100110100,
+ "des_iip" => 0b100110101,
+ "des_kexpand" => 0b100110110 );
+
+ $ref = "$mnemonic\t".join(",",@_);
+
+ if (defined($opf=$desopf{$mnemonic})) { # 4-arg
+ if ($mnemonic eq "des_round") {
+ foreach (@args[0..3]) {
+ return $ref if (!/%f([0-9]{1,2})/);
+ $_=$1;
+ if ($1>=32) {
+ return $ref if ($1&1);
+ # re-encode for upper double register addressing
+ $_=($1|$1>>5)&31;
+ }
+ }
+ return sprintf ".word\t0x%08x !%s",
+ 2<<30|0b011001<<19|$opf<<5|$args[0]<<14|$args[1]|$args[2]<<9|$args[3]<<25,
+ $ref;
+ } elsif ($mnemonic eq "des_kexpand") { # 3-arg
+ foreach (@args[0..2]) {
+ return $ref if (!/(%f)?([0-9]{1,2})/);
+ $_=$2;
+ if ($2>=32) {
+ return $ref if ($2&1);
+ # re-encode for upper double register addressing
+ $_=($2|$2>>5)&31;
+ }
+ }
+ return sprintf ".word\t0x%08x !%s",
+ 2<<30|0b110110<<19|$opf<<5|$args[0]<<14|$args[1]|$args[2]<<25,
+ $ref;
+ } else { # 2-arg
+ foreach (@args[0..1]) {
+ return $ref if (!/%f([0-9]{1,2})/);
+ $_=$1;
+ if ($1>=32) {
+ return $ref if ($2&1);
+ # re-encode for upper double register addressing
+ $_=($1|$1>>5)&31;
+ }
+ }
+ return sprintf ".word\t0x%08x !%s",
+ 2<<30|0b110110<<19|$opf<<5|$args[0]<<14|$args[1]<<25,
+ $ref;
+ }
+ } else {
+ return $ref;
+ }
+}
+
+sub emit_assembler {
+ foreach (split("\n",$::code)) {
+ s/\`([^\`]*)\`/eval $1/ge;
+
+ s/\b(f[a-z]+2[sd]*)\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2})\s*$/$1\t%f0,$2,$3/go;
+
+ s/\b(aes_[edk][^\s]*)\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2}),\s*([%fx0-9]+),\s*(%f[0-9]{1,2})/
+ &unaes_round($1,$2,$3,$4,$5)
+ /geo or
+ s/\b(aes_kexpand[02])\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2}),\s*(%f[0-9]{1,2})/
+ &unaes_kexpand($1,$2,$3,$4)
+ /geo or
+ s/\b(camellia_f)\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2}),\s*([%fx0-9]+),\s*(%f[0-9]{1,2})/
+ &uncamellia_f($1,$2,$3,$4,$5)
+ /geo or
+ s/\b(camellia_[^s]+)\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2}),\s*(%f[0-9]{1,2})/
+ &uncamellia3($1,$2,$3,$4)
+ /geo or
+ s/\b(des_\w+)\s+(%f[0-9]{1,2}),\s*([%fx0-9]+)(?:,\s*(%f[0-9]{1,2})(?:,\s*(%f[0-9]{1,2}))?)?/
+ &undes($1,$2,$3,$4,$5)
+ /geo or
+ s/\b(mov[ds]to\w+)\s+(%f[0-9]{1,2}),\s*(%[goli][0-7])/
+ &unmovxtox($1,$2,$3)
+ /geo or
+ s/\b(mov[xw]to[ds])\s+(%[goli][0-7]),\s*(%f[0-9]{1,2})/
+ &unmovxtox($1,$2,$3)
+ /geo or
+ s/\b([fb][^\s]*)\s+(%f[0-9]{1,2}),\s*(%f[0-9]{1,2}),\s*(%f[0-9]{1,2})/
+ &unvis($1,$2,$3,$4)
+ /geo or
+ s/\b(umulxhi|bmask|addxc[c]{0,2}|alignaddr[l]*)\s+(%[goli][0-7]),\s*(%[goli][0-7]),\s*(%[goli][0-7])/
+ &unvis3($1,$2,$3,$4)
+ /geo;
+
+ print $_,"\n";
+ }
+}
+
+1;
diff --git a/crypto/perlasm/x86_64-xlate.pl b/crypto/perlasm/x86_64-xlate.pl
new file mode 100755
index 0000000..24ff1b4
--- /dev/null
+++ b/crypto/perlasm/x86_64-xlate.pl
@@ -0,0 +1,1151 @@
+#!/usr/bin/env perl
+
+# Ascetic x86_64 AT&T to MASM/NASM assembler translator by <appro>.
+#
+# Why AT&T to MASM and not vice versa? Several reasons. Because AT&T
+# format is way easier to parse. Because it's simpler to "gear" from
+# Unix ABI to Windows one [see cross-reference "card" at the end of
+# file]. Because Linux targets were available first...
+#
+# In addition the script also "distills" code suitable for GNU
+# assembler, so that it can be compiled with more rigid assemblers,
+# such as Solaris /usr/ccs/bin/as.
+#
+# This translator is not designed to convert *arbitrary* assembler
+# code from AT&T format to MASM one. It's designed to convert just
+# enough to provide for dual-ABI OpenSSL modules development...
+# There *are* limitations and you might have to modify your assembler
+# code or this script to achieve the desired result...
+#
+# Currently recognized limitations:
+#
+# - can't use multiple ops per line;
+#
+# Dual-ABI styling rules.
+#
+# 1. Adhere to Unix register and stack layout [see cross-reference
+# ABI "card" at the end for explanation].
+# 2. Forget about "red zone," stick to more traditional blended
+# stack frame allocation. If volatile storage is actually required
+# that is. If not, just leave the stack as is.
+# 3. Functions tagged with ".type name,@function" get crafted with
+# unified Win64 prologue and epilogue automatically. If you want
+# to take care of ABI differences yourself, tag functions as
+# ".type name,@abi-omnipotent" instead.
+# 4. To optimize the Win64 prologue you can specify number of input
+# arguments as ".type name,@function,N." Keep in mind that if N is
+# larger than 6, then you *have to* write "abi-omnipotent" code,
+# because >6 cases can't be addressed with unified prologue.
+# 5. Name local labels as .L*, do *not* use dynamic labels such as 1:
+# (sorry about latter).
+# 6. Don't use [or hand-code with .byte] "rep ret." "ret" mnemonic is
+# required to identify the spots, where to inject Win64 epilogue!
+# But on the pros, it's then prefixed with rep automatically:-)
+# 7. Stick to explicit ip-relative addressing. If you have to use
+# GOTPCREL addressing, stick to mov symbol@GOTPCREL(%rip),%r??.
+# Both are recognized and translated to proper Win64 addressing
+# modes. To support legacy code a synthetic directive, .picmeup,
+# is implemented. It puts address of the *next* instruction into
+# target register, e.g.:
+#
+# .picmeup %rax
+# lea .Label-.(%rax),%rax
+#
+# 8. In order to provide for structured exception handling unified
+# Win64 prologue copies %rsp value to %rax. For further details
+# see SEH paragraph at the end.
+# 9. .init segment is allowed to contain calls to functions only.
+# a. If function accepts more than 4 arguments *and* >4th argument
+# is declared as non 64-bit value, do clear its upper part.
+
+my $flavour = shift;
+my $output = shift;
+if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
+
+open STDOUT,">$output" || die "can't open $output: $!"
+ if (defined($output));
+
+my $gas=1; $gas=0 if ($output =~ /\.asm$/);
+my $elf=1; $elf=0 if (!$gas);
+my $win64=0;
+my $prefix="";
+my $decor=".L";
+
+my $masmref=8 + 50727*2**-32; # 8.00.50727 shipped with VS2005
+my $masm=0;
+my $PTR=" PTR";
+
+my $nasmref=2.03;
+my $nasm=0;
+
+if ($flavour eq "mingw64") { $gas=1; $elf=0; $win64=1;
+ $prefix=`echo __USER_LABEL_PREFIX__ | $ENV{CC} -E -P -`;
+ chomp($prefix);
+ }
+elsif ($flavour eq "macosx") { $gas=1; $elf=0; $prefix="_"; $decor="L\$"; }
+elsif ($flavour eq "masm") { $gas=0; $elf=0; $masm=$masmref; $win64=1; $decor="\$L\$"; }
+elsif ($flavour eq "nasm") { $gas=0; $elf=0; $nasm=$nasmref; $win64=1; $decor="\$L\$"; $PTR=""; }
+elsif (!$gas)
+{ if ($ENV{ASM} =~ m/nasm/ && `nasm -v` =~ m/version ([0-9]+)\.([0-9]+)/i)
+ { $nasm = $1 + $2*0.01; $PTR=""; }
+ elsif (`ml64 2>&1` =~ m/Version ([0-9]+)\.([0-9]+)(\.([0-9]+))?/)
+ { $masm = $1 + $2*2**-16 + $4*2**-32; }
+ die "no assembler found on %PATH" if (!($nasm || $masm));
+ $win64=1;
+ $elf=0;
+ $decor="\$L\$";
+}
+
+my $current_segment;
+my $current_function;
+my %globals;
+
+{ package opcode; # pick up opcodes
+ sub re {
+ my $self = shift; # single instance in enough...
+ local *line = shift;
+ undef $ret;
+
+ if ($line =~ /^([a-z][a-z0-9]*)/i) {
+ $self->{op} = $1;
+ $ret = $self;
+ $line = substr($line,@+[0]); $line =~ s/^\s+//;
+
+ undef $self->{sz};
+ undef $self->{arg_sz};
+ if ($self->{op} =~ /^(movz)x?([bw]).*/) { # movz is pain...
+ $self->{op} = $1;
+ $self->{sz} = $2;
+ } elsif ($self->{op} =~ /call|jmp/) {
+ $self->{sz} = "";
+ } elsif ($self->{op} =~ /^p/ && $' !~ /^(ush|op|insrw)/) { # SSEn
+ $self->{sz} = "";
+ } elsif ($self->{op} eq "vpbroadcastq") {
+ $self->{arg_sz} = "q";
+ } elsif ($self->{op} eq "vpbroadcastb") {
+ $self->{arg_sz} = "b";
+ } elsif ($self->{op} =~ /^vinserti128/) {
+ $self->{arg_sz} = "x";
+ } elsif ($self->{op} =~ /^v/) { # VEX
+ $self->{sz} = "";
+ } elsif ($self->{op} =~ /movq/ && $line =~ /%xmm/) {
+ $self->{sz} = "";
+ } elsif ($self->{op} =~ /([a-z]{3,})([qlwb])$/) {
+ $self->{op} = $1;
+ $self->{sz} = $2;
+ }
+ }
+ $ret;
+ }
+ sub size {
+ my $self = shift;
+ my $sz = shift;
+ $self->{sz} = $sz if (defined($sz) && !defined($self->{sz}));
+ $self->{sz};
+ }
+ sub arg_size {
+ my $self = shift;
+ $self->{arg_sz};
+ }
+ sub out {
+ my $self = shift;
+ if ($gas) {
+ if ($self->{op} eq "movz") { # movz is pain...
+ sprintf "%s%s%s",$self->{op},$self->{sz},shift;
+ } elsif ($self->{op} =~ /^set/) {
+ "$self->{op}";
+ } elsif ($self->{op} eq "ret") {
+ my $epilogue = "";
+ if ($win64 && $current_function->{abi} eq "svr4") {
+ $epilogue = "movq 8(%rsp),%rdi\n\t" .
+ "movq 16(%rsp),%rsi\n\t";
+ }
+ $epilogue . ".byte 0xf3,0xc3";
+ } elsif ($self->{op} eq "call" && !$elf && $current_segment eq ".init") {
+ ".p2align\t3\n\t.quad";
+ } else {
+ "$self->{op}$self->{sz}";
+ }
+ } else {
+ $self->{op} =~ s/^movz/movzx/;
+ if ($self->{op} eq "ret") {
+ $self->{op} = "";
+ if ($win64 && $current_function->{abi} eq "svr4") {
+ $self->{op} = "mov rdi,QWORD${PTR}[8+rsp]\t;WIN64 epilogue\n\t".
+ "mov rsi,QWORD${PTR}[16+rsp]\n\t";
+ }
+ $self->{op} .= "DB\t0F3h,0C3h\t\t;repret";
+ } elsif ($self->{op} =~ /^(pop|push)f/) {
+ $self->{op} .= $self->{sz};
+ } elsif ($self->{op} eq "call" && $current_segment eq ".CRT\$XCU") {
+ $self->{op} = "\tDQ";
+ }
+ $self->{op};
+ }
+ }
+ sub mnemonic {
+ my $self=shift;
+ my $op=shift;
+ $self->{op}=$op if (defined($op));
+ $self->{op};
+ }
+}
+{ package const; # pick up constants, which start with $
+ sub re {
+ my $self = shift; # single instance in enough...
+ local *line = shift;
+ undef $ret;
+
+ if ($line =~ /^\$([^,]+)/) {
+ $self->{value} = $1;
+ $ret = $self;
+ $line = substr($line,@+[0]); $line =~ s/^\s+//;
+ }
+ $ret;
+ }
+ sub out {
+ my $self = shift;
+
+ if ($gas) {
+ # Solaris /usr/ccs/bin/as can't handle multiplications
+ # in $self->{value}
+ $self->{value} =~ s/(?<![\w\$\.])(0x?[0-9a-f]+)/oct($1)/egi;
+ $self->{value} =~ s/([0-9]+\s*[\*\/\%]\s*[0-9]+)/eval($1)/eg;
+ sprintf "\$%s",$self->{value};
+ } else {
+ $self->{value} =~ s/(0b[0-1]+)/oct($1)/eig;
+ $self->{value} =~ s/0x([0-9a-f]+)/0$1h/ig if ($masm);
+ sprintf "%s",$self->{value};
+ }
+ }
+}
+{ package ea; # pick up effective addresses: expr(%reg,%reg,scale)
+ sub re {
+ my $self = shift; # single instance in enough...
+ local *line = shift;
+ undef $ret;
+
+ # optional * ---vvv--- appears in indirect jmp/call
+ if ($line =~ /^(\*?)([^\(,]*)\(([%\w,]+)\)/) {
+ $self->{asterisk} = $1;
+ $self->{label} = $2;
+ ($self->{base},$self->{index},$self->{scale})=split(/,/,$3);
+ $self->{scale} = 1 if (!defined($self->{scale}));
+ $ret = $self;
+ $line = substr($line,@+[0]); $line =~ s/^\s+//;
+
+ if ($win64 && $self->{label} =~ s/\@GOTPCREL//) {
+ die if (opcode->mnemonic() ne "mov");
+ opcode->mnemonic("lea");
+ }
+ $self->{base} =~ s/^%//;
+ $self->{index} =~ s/^%// if (defined($self->{index}));
+ }
+ $ret;
+ }
+ sub size {}
+ sub out {
+ my $self = shift;
+ my $sz = shift;
+
+ $self->{label} =~ s/([_a-z][_a-z0-9]*)/$globals{$1} or $1/gei;
+ $self->{label} =~ s/\.L/$decor/g;
+
+ # Silently convert all EAs to 64-bit. This is required for
+ # elder GNU assembler and results in more compact code,
+ # *but* most importantly AES module depends on this feature!
+ $self->{index} =~ s/^[er](.?[0-9xpi])[d]?$/r\1/;
+ $self->{base} =~ s/^[er](.?[0-9xpi])[d]?$/r\1/;
+
+ # Solaris /usr/ccs/bin/as can't handle multiplications
+ # in $self->{label}, new gas requires sign extension...
+ use integer;
+ $self->{label} =~ s/(?<![\w\$\.])(0x?[0-9a-f]+)/oct($1)/egi;
+ $self->{label} =~ s/\b([0-9]+\s*[\*\/\%]\s*[0-9]+)\b/eval($1)/eg;
+ $self->{label} =~ s/\b([0-9]+)\b/$1<<32>>32/eg;
+
+ if (!$self->{label} && $self->{index} && $self->{scale}==1 &&
+ $self->{base} =~ /(rbp|r13)/) {
+ $self->{base} = $self->{index}; $self->{index} = $1;
+ }
+
+ if ($gas) {
+ $self->{label} =~ s/^___imp_/__imp__/ if ($flavour eq "mingw64");
+
+ if (defined($self->{index})) {
+ sprintf "%s%s(%s,%%%s,%d)",$self->{asterisk},
+ $self->{label},
+ $self->{base}?"%$self->{base}":"",
+ $self->{index},$self->{scale};
+ } else {
+ sprintf "%s%s(%%%s)", $self->{asterisk},$self->{label},$self->{base};
+ }
+ } else {
+ %szmap = ( b=>"BYTE$PTR", w=>"WORD$PTR", l=>"DWORD$PTR",
+ q=>"QWORD$PTR",o=>"OWORD$PTR",x=>"XMMWORD$PTR",
+ y=>"YMMWORD$PTR" );
+
+ $self->{label} =~ s/\./\$/g;
+ $self->{label} =~ s/(?<![\w\$\.])0x([0-9a-f]+)/0$1h/ig;
+ $self->{label} = "($self->{label})" if ($self->{label} =~ /[\*\+\-\/]/);
+ $sz="q" if ($self->{asterisk} || opcode->mnemonic() =~ /^v?movq$/);
+ $sz="l" if (opcode->mnemonic() =~ /^v?movd$/);
+
+ if (defined($self->{index})) {
+ sprintf "%s[%s%s*%d%s]",$szmap{$sz},
+ $self->{label}?"$self->{label}+":"",
+ $self->{index},$self->{scale},
+ $self->{base}?"+$self->{base}":"";
+ } elsif ($self->{base} eq "rip") {
+ sprintf "%s[%s]",$szmap{$sz},$self->{label};
+ } else {
+ sprintf "%s[%s%s]",$szmap{$sz},
+ $self->{label}?"$self->{label}+":"",
+ $self->{base};
+ }
+ }
+ }
+}
+{ package register; # pick up registers, which start with %.
+ sub re {
+ my $class = shift; # muliple instances...
+ my $self = {};
+ local *line = shift;
+ undef $ret;
+
+ # optional * ---vvv--- appears in indirect jmp/call
+ if ($line =~ /^(\*?)%(\w+)/) {
+ bless $self,$class;
+ $self->{asterisk} = $1;
+ $self->{value} = $2;
+ $ret = $self;
+ $line = substr($line,@+[0]); $line =~ s/^\s+//;
+ }
+ $ret;
+ }
+ sub size {
+ my $self = shift;
+ undef $ret;
+
+ if ($self->{value} =~ /^r[\d]+b$/i) { $ret="b"; }
+ elsif ($self->{value} =~ /^r[\d]+w$/i) { $ret="w"; }
+ elsif ($self->{value} =~ /^r[\d]+d$/i) { $ret="l"; }
+ elsif ($self->{value} =~ /^r[\w]+$/i) { $ret="q"; }
+ elsif ($self->{value} =~ /^[a-d][hl]$/i){ $ret="b"; }
+ elsif ($self->{value} =~ /^[\w]{2}l$/i) { $ret="b"; }
+ elsif ($self->{value} =~ /^[\w]{2}$/i) { $ret="w"; }
+ elsif ($self->{value} =~ /^e[a-z]{2}$/i){ $ret="l"; }
+
+ $ret;
+ }
+ sub out {
+ my $self = shift;
+ if ($gas) { sprintf "%s%%%s",$self->{asterisk},$self->{value}; }
+ else { $self->{value}; }
+ }
+}
+{ package label; # pick up labels, which end with :
+ sub re {
+ my $self = shift; # single instance is enough...
+ local *line = shift;
+ undef $ret;
+
+ if ($line =~ /(^[\.\w]+)\:/) {
+ $self->{value} = $1;
+ $ret = $self;
+ $line = substr($line,@+[0]); $line =~ s/^\s+//;
+
+ $self->{value} =~ s/^\.L/$decor/;
+ }
+ $ret;
+ }
+ sub out {
+ my $self = shift;
+
+ if ($gas) {
+ my $func = ($globals{$self->{value}} or $self->{value}) . ":";
+ if ($win64 &&
+ $current_function->{name} eq $self->{value} &&
+ $current_function->{abi} eq "svr4") {
+ $func .= "\n";
+ $func .= " movq %rdi,8(%rsp)\n";
+ $func .= " movq %rsi,16(%rsp)\n";
+ $func .= " movq %rsp,%rax\n";
+ $func .= "${decor}SEH_begin_$current_function->{name}:\n";
+ my $narg = $current_function->{narg};
+ $narg=6 if (!defined($narg));
+ $func .= " movq %rcx,%rdi\n" if ($narg>0);
+ $func .= " movq %rdx,%rsi\n" if ($narg>1);
+ $func .= " movq %r8,%rdx\n" if ($narg>2);
+ $func .= " movq %r9,%rcx\n" if ($narg>3);
+ $func .= " movq 40(%rsp),%r8\n" if ($narg>4);
+ $func .= " movq 48(%rsp),%r9\n" if ($narg>5);
+ }
+ $func;
+ } elsif ($self->{value} ne "$current_function->{name}") {
+ $self->{value} .= ":" if ($masm && $ret!~m/^\$/);
+ $self->{value} . ":";
+ } elsif ($win64 && $current_function->{abi} eq "svr4") {
+ my $func = "$current_function->{name}" .
+ ($nasm ? ":" : "\tPROC $current_function->{scope}") .
+ "\n";
+ $func .= " mov QWORD${PTR}[8+rsp],rdi\t;WIN64 prologue\n";
+ $func .= " mov QWORD${PTR}[16+rsp],rsi\n";
+ $func .= " mov rax,rsp\n";
+ $func .= "${decor}SEH_begin_$current_function->{name}:";
+ $func .= ":" if ($masm);
+ $func .= "\n";
+ my $narg = $current_function->{narg};
+ $narg=6 if (!defined($narg));
+ $func .= " mov rdi,rcx\n" if ($narg>0);
+ $func .= " mov rsi,rdx\n" if ($narg>1);
+ $func .= " mov rdx,r8\n" if ($narg>2);
+ $func .= " mov rcx,r9\n" if ($narg>3);
+ $func .= " mov r8,QWORD${PTR}[40+rsp]\n" if ($narg>4);
+ $func .= " mov r9,QWORD${PTR}[48+rsp]\n" if ($narg>5);
+ $func .= "\n";
+ } else {
+ "$current_function->{name}".
+ ($nasm ? ":" : "\tPROC $current_function->{scope}");
+ }
+ }
+}
+{ package expr; # pick up expressioins
+ sub re {
+ my $self = shift; # single instance is enough...
+ local *line = shift;
+ undef $ret;
+
+ if ($line =~ /(^[^,]+)/) {
+ $self->{value} = $1;
+ $ret = $self;
+ $line = substr($line,@+[0]); $line =~ s/^\s+//;
+
+ $self->{value} =~ s/\@PLT// if (!$elf);
+ $self->{value} =~ s/([_a-z][_a-z0-9]*)/$globals{$1} or $1/gei;
+ $self->{value} =~ s/\.L/$decor/g;
+ }
+ $ret;
+ }
+ sub out {
+ my $self = shift;
+ if ($nasm && opcode->mnemonic()=~m/^j(?![re]cxz)/) {
+ "NEAR ".$self->{value};
+ } else {
+ $self->{value};
+ }
+ }
+}
+{ package directive; # pick up directives, which start with .
+ sub re {
+ my $self = shift; # single instance is enough...
+ local *line = shift;
+ undef $ret;
+ my $dir;
+ my %opcode = # lea 2f-1f(%rip),%dst; 1: nop; 2:
+ ( "%rax"=>0x01058d48, "%rcx"=>0x010d8d48,
+ "%rdx"=>0x01158d48, "%rbx"=>0x011d8d48,
+ "%rsp"=>0x01258d48, "%rbp"=>0x012d8d48,
+ "%rsi"=>0x01358d48, "%rdi"=>0x013d8d48,
+ "%r8" =>0x01058d4c, "%r9" =>0x010d8d4c,
+ "%r10"=>0x01158d4c, "%r11"=>0x011d8d4c,
+ "%r12"=>0x01258d4c, "%r13"=>0x012d8d4c,
+ "%r14"=>0x01358d4c, "%r15"=>0x013d8d4c );
+
+ if ($line =~ /^\s*(\.\w+)/) {
+ $dir = $1;
+ $ret = $self;
+ undef $self->{value};
+ $line = substr($line,@+[0]); $line =~ s/^\s+//;
+
+ SWITCH: for ($dir) {
+ /\.picmeup/ && do { if ($line =~ /(%r[\w]+)/i) {
+ $dir="\t.long";
+ $line=sprintf "0x%x,0x90000000",$opcode{$1};
+ }
+ last;
+ };
+ /\.global|\.globl|\.extern/
+ && do { $globals{$line} = $prefix . $line;
+ $line = $globals{$line} if ($prefix);
+ last;
+ };
+ /\.type/ && do { ($sym,$type,$narg) = split(',',$line);
+ if ($type eq "\@function") {
+ undef $current_function;
+ $current_function->{name} = $sym;
+ $current_function->{abi} = "svr4";
+ $current_function->{narg} = $narg;
+ $current_function->{scope} = defined($globals{$sym})?"PUBLIC":"PRIVATE";
+ } elsif ($type eq "\@abi-omnipotent") {
+ undef $current_function;
+ $current_function->{name} = $sym;
+ $current_function->{scope} = defined($globals{$sym})?"PUBLIC":"PRIVATE";
+ }
+ $line =~ s/\@abi\-omnipotent/\@function/;
+ $line =~ s/\@function.*/\@function/;
+ last;
+ };
+ /\.asciz/ && do { if ($line =~ /^"(.*)"$/) {
+ $dir = ".byte";
+ $line = join(",",unpack("C*",$1),0);
+ }
+ last;
+ };
+ /\.rva|\.long|\.quad/
+ && do { $line =~ s/([_a-z][_a-z0-9]*)/$globals{$1} or $1/gei;
+ $line =~ s/\.L/$decor/g;
+ last;
+ };
+ }
+
+ if ($gas) {
+ $self->{value} = $dir . "\t" . $line;
+
+ if ($dir =~ /\.extern/) {
+ $self->{value} = ""; # swallow extern
+ } elsif (!$elf && $dir =~ /\.type/) {
+ $self->{value} = "";
+ $self->{value} = ".def\t" . ($globals{$1} or $1) . ";\t" .
+ (defined($globals{$1})?".scl 2;":".scl 3;") .
+ "\t.type 32;\t.endef"
+ if ($win64 && $line =~ /([^,]+),\@function/);
+ } elsif (!$elf && $dir =~ /\.size/) {
+ $self->{value} = "";
+ if (defined($current_function)) {
+ $self->{value} .= "${decor}SEH_end_$current_function->{name}:"
+ if ($win64 && $current_function->{abi} eq "svr4");
+ undef $current_function;
+ }
+ } elsif (!$elf && $dir =~ /\.align/) {
+ $self->{value} = ".p2align\t" . (log($line)/log(2));
+ } elsif ($dir eq ".section") {
+ $current_segment=$line;
+ if (!$elf && $current_segment eq ".init") {
+ if ($flavour eq "macosx") { $self->{value} = ".mod_init_func"; }
+ elsif ($flavour eq "mingw64") { $self->{value} = ".section\t.ctors"; }
+ }
+ } elsif ($dir =~ /\.(text|data)/) {
+ $current_segment=".$1";
+ } elsif ($dir =~ /\.hidden/) {
+ if ($flavour eq "macosx") { $self->{value} = ".private_extern\t$prefix$line"; }
+ elsif ($flavour eq "mingw64") { $self->{value} = ""; }
+ } elsif ($dir =~ /\.comm/) {
+ $self->{value} = "$dir\t$prefix$line";
+ $self->{value} =~ s|,([0-9]+),([0-9]+)$|",$1,".log($2)/log(2)|e if ($flavour eq "macosx");
+ }
+ $line = "";
+ return $self;
+ }
+
+ # non-gas case or nasm/masm
+ SWITCH: for ($dir) {
+ /\.text/ && do { my $v=undef;
+ if ($nasm) {
+ $v="section .text code align=64\n";
+ } else {
+ $v="$current_segment\tENDS\n" if ($current_segment);
+ $current_segment = ".text\$";
+ $v.="$current_segment\tSEGMENT ";
+ $v.=$masm>=$masmref ? "ALIGN(64)" : "PAGE";
+ $v.=" 'CODE'";
+ }
+ $self->{value} = $v;
+ last;
+ };
+ /\.data/ && do { my $v=undef;
+ if ($nasm) {
+ $v="section .data data align=8\n";
+ } else {
+ $v="$current_segment\tENDS\n" if ($current_segment);
+ $current_segment = "_DATA";
+ $v.="$current_segment\tSEGMENT";
+ }
+ $self->{value} = $v;
+ last;
+ };
+ /\.section/ && do { my $v=undef;
+ $line =~ s/([^,]*).*/$1/;
+ $line = ".CRT\$XCU" if ($line eq ".init");
+ if ($nasm) {
+ $v="section $line";
+ if ($line=~/\.([px])data/) {
+ $v.=" rdata align=";
+ $v.=$1 eq "p"? 4 : 8;
+ } elsif ($line=~/\.CRT\$/i) {
+ $v.=" rdata align=8";
+ }
+ } else {
+ $v="$current_segment\tENDS\n" if ($current_segment);
+ $v.="$line\tSEGMENT";
+ if ($line=~/\.([px])data/) {
+ $v.=" READONLY";
+ $v.=" ALIGN(".($1 eq "p" ? 4 : 8).")" if ($masm>=$masmref);
+ } elsif ($line=~/\.CRT\$/i) {
+ $v.=" READONLY ";
+ $v.=$masm>=$masmref ? "ALIGN(8)" : "DWORD";
+ }
+ }
+ $current_segment = $line;
+ $self->{value} = $v;
+ last;
+ };
+ /\.extern/ && do { $self->{value} = "EXTERN\t".$line;
+ $self->{value} .= ":NEAR" if ($masm);
+ last;
+ };
+ /\.globl|.global/
+ && do { $self->{value} = $masm?"PUBLIC":"global";
+ $self->{value} .= "\t".$line;
+ last;
+ };
+ /\.size/ && do { if (defined($current_function)) {
+ undef $self->{value};
+ if ($current_function->{abi} eq "svr4") {
+ $self->{value}="${decor}SEH_end_$current_function->{name}:";
+ $self->{value}.=":\n" if($masm);
+ }
+ $self->{value}.="$current_function->{name}\tENDP" if($masm && $current_function->{name});
+ undef $current_function;
+ }
+ last;
+ };
+ /\.align/ && do { $self->{value} = "ALIGN\t".$line; last; };
+ /\.(value|long|rva|quad)/
+ && do { my $sz = substr($1,0,1);
+ my @arr = split(/,\s*/,$line);
+ my $last = pop(@arr);
+ my $conv = sub { my $var=shift;
+ $var=~s/^(0b[0-1]+)/oct($1)/eig;
+ $var=~s/^0x([0-9a-f]+)/0$1h/ig if ($masm);
+ if ($sz eq "D" && ($current_segment=~/.[px]data/ || $dir eq ".rva"))
+ { $var=~s/([_a-z\$\@][_a-z0-9\$\@]*)/$nasm?"$1 wrt ..imagebase":"imagerel $1"/egi; }
+ $var;
+ };
+
+ $sz =~ tr/bvlrq/BWDDQ/;
+ $self->{value} = "\tD$sz\t";
+ for (@arr) { $self->{value} .= &$conv($_).","; }
+ $self->{value} .= &$conv($last);
+ last;
+ };
+ /\.byte/ && do { my @str=split(/,\s*/,$line);
+ map(s/(0b[0-1]+)/oct($1)/eig,@str);
+ map(s/0x([0-9a-f]+)/0$1h/ig,@str) if ($masm);
+ while ($#str>15) {
+ $self->{value}.="DB\t"
+ .join(",",@str[0..15])."\n";
+ foreach (0..15) { shift @str; }
+ }
+ $self->{value}.="DB\t"
+ .join(",",@str) if (@str);
+ last;
+ };
+ /\.comm/ && do { my @str=split(/,\s*/,$line);
+ my $v=undef;
+ if ($nasm) {
+ $v.="common $prefix@str[0] @str[1]";
+ } else {
+ $v="$current_segment\tENDS\n" if ($current_segment);
+ $current_segment = "_DATA";
+ $v.="$current_segment\tSEGMENT\n";
+ $v.="COMM @str[0]:DWORD:".@str[1]/4;
+ }
+ $self->{value} = $v;
+ last;
+ };
+ }
+ $line = "";
+ }
+
+ $ret;
+ }
+ sub out {
+ my $self = shift;
+ $self->{value};
+ }
+}
+
+sub rex {
+ local *opcode=shift;
+ my ($dst,$src,$rex)=@_;
+
+ $rex|=0x04 if($dst>=8);
+ $rex|=0x01 if($src>=8);
+ push @opcode,($rex|0x40) if ($rex);
+}
+
+# older gas and ml64 don't handle SSE>2 instructions
+my %regrm = ( "%eax"=>0, "%ecx"=>1, "%edx"=>2, "%ebx"=>3,
+ "%esp"=>4, "%ebp"=>5, "%esi"=>6, "%edi"=>7 );
+
+my $movq = sub { # elderly gas can't handle inter-register movq
+ my $arg = shift;
+ my @opcode=(0x66);
+ if ($arg =~ /%xmm([0-9]+),\s*%r(\w+)/) {
+ my ($src,$dst)=($1,$2);
+ if ($dst !~ /[0-9]+/) { $dst = $regrm{"%e$dst"}; }
+ rex(\@opcode,$src,$dst,0x8);
+ push @opcode,0x0f,0x7e;
+ push @opcode,0xc0|(($src&7)<<3)|($dst&7); # ModR/M
+ @opcode;
+ } elsif ($arg =~ /%r(\w+),\s*%xmm([0-9]+)/) {
+ my ($src,$dst)=($2,$1);
+ if ($dst !~ /[0-9]+/) { $dst = $regrm{"%e$dst"}; }
+ rex(\@opcode,$src,$dst,0x8);
+ push @opcode,0x0f,0x6e;
+ push @opcode,0xc0|(($src&7)<<3)|($dst&7); # ModR/M
+ @opcode;
+ } else {
+ ();
+ }
+};
+
+my $pextrd = sub {
+ if (shift =~ /\$([0-9]+),\s*%xmm([0-9]+),\s*(%\w+)/) {
+ my @opcode=(0x66);
+ $imm=$1;
+ $src=$2;
+ $dst=$3;
+ if ($dst =~ /%r([0-9]+)d/) { $dst = $1; }
+ elsif ($dst =~ /%e/) { $dst = $regrm{$dst}; }
+ rex(\@opcode,$src,$dst);
+ push @opcode,0x0f,0x3a,0x16;
+ push @opcode,0xc0|(($src&7)<<3)|($dst&7); # ModR/M
+ push @opcode,$imm;
+ @opcode;
+ } else {
+ ();
+ }
+};
+
+my $pinsrd = sub {
+ if (shift =~ /\$([0-9]+),\s*(%\w+),\s*%xmm([0-9]+)/) {
+ my @opcode=(0x66);
+ $imm=$1;
+ $src=$2;
+ $dst=$3;
+ if ($src =~ /%r([0-9]+)/) { $src = $1; }
+ elsif ($src =~ /%e/) { $src = $regrm{$src}; }
+ rex(\@opcode,$dst,$src);
+ push @opcode,0x0f,0x3a,0x22;
+ push @opcode,0xc0|(($dst&7)<<3)|($src&7); # ModR/M
+ push @opcode,$imm;
+ @opcode;
+ } else {
+ ();
+ }
+};
+
+my $pshufb = sub {
+ if (shift =~ /%xmm([0-9]+),\s*%xmm([0-9]+)/) {
+ my @opcode=(0x66);
+ rex(\@opcode,$2,$1);
+ push @opcode,0x0f,0x38,0x00;
+ push @opcode,0xc0|($1&7)|(($2&7)<<3); # ModR/M
+ @opcode;
+ } else {
+ ();
+ }
+};
+
+my $palignr = sub {
+ if (shift =~ /\$([0-9]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) {
+ my @opcode=(0x66);
+ rex(\@opcode,$3,$2);
+ push @opcode,0x0f,0x3a,0x0f;
+ push @opcode,0xc0|($2&7)|(($3&7)<<3); # ModR/M
+ push @opcode,$1;
+ @opcode;
+ } else {
+ ();
+ }
+};
+
+my $pclmulqdq = sub {
+ if (shift =~ /\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) {
+ my @opcode=(0x66);
+ rex(\@opcode,$3,$2);
+ push @opcode,0x0f,0x3a,0x44;
+ push @opcode,0xc0|($2&7)|(($3&7)<<3); # ModR/M
+ my $c=$1;
+ push @opcode,$c=~/^0/?oct($c):$c;
+ @opcode;
+ } else {
+ ();
+ }
+};
+
+my $rdrand = sub {
+ if (shift =~ /%[er](\w+)/) {
+ my @opcode=();
+ my $dst=$1;
+ if ($dst !~ /[0-9]+/) { $dst = $regrm{"%e$dst"}; }
+ rex(\@opcode,0,$1,8);
+ push @opcode,0x0f,0xc7,0xf0|($dst&7);
+ @opcode;
+ } else {
+ ();
+ }
+};
+
+sub rxb {
+ local *opcode=shift;
+ my ($dst,$src1,$src2,$rxb)=@_;
+
+ $rxb|=0x7<<5;
+ $rxb&=~(0x04<<5) if($dst>=8);
+ $rxb&=~(0x01<<5) if($src1>=8);
+ $rxb&=~(0x02<<5) if($src2>=8);
+ push @opcode,$rxb;
+}
+
+my $vprotd = sub {
+ if (shift =~ /\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) {
+ my @opcode=(0x8f);
+ rxb(\@opcode,$3,$2,-1,0x08);
+ push @opcode,0x78,0xc2;
+ push @opcode,0xc0|($2&7)|(($3&7)<<3); # ModR/M
+ my $c=$1;
+ push @opcode,$c=~/^0/?oct($c):$c;
+ @opcode;
+ } else {
+ ();
+ }
+};
+
+my $vprotq = sub {
+ if (shift =~ /\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) {
+ my @opcode=(0x8f);
+ rxb(\@opcode,$3,$2,-1,0x08);
+ push @opcode,0x78,0xc3;
+ push @opcode,0xc0|($2&7)|(($3&7)<<3); # ModR/M
+ my $c=$1;
+ push @opcode,$c=~/^0/?oct($c):$c;
+ @opcode;
+ } else {
+ ();
+ }
+};
+
+if ($nasm) {
+ print <<___;
+default rel
+%define XMMWORD
+___
+} elsif ($masm) {
+ print <<___;
+OPTION DOTNAME
+___
+}
+
+print STDOUT "#if defined(__x86_64__)\n" if ($gas);
+
+while($line=<>) {
+
+ chomp($line);
+
+ $line =~ s|[#!].*$||; # get rid of asm-style comments...
+ $line =~ s|/\*.*\*/||; # ... and C-style comments...
+ $line =~ s|^\s+||; # ... and skip white spaces in beginning
+ $line =~ s|\s+$||; # ... and at the end
+
+ undef $label;
+ undef $opcode;
+ undef @args;
+
+ if ($label=label->re(\$line)) { print $label->out(); }
+
+ if (directive->re(\$line)) {
+ printf "%s",directive->out();
+ } elsif ($opcode=opcode->re(\$line)) {
+ my $asm = eval("\$".$opcode->mnemonic());
+ undef @bytes;
+
+ if ((ref($asm) eq 'CODE') && scalar(@bytes=&$asm($line))) {
+ print $gas?".byte\t":"DB\t",join(',',@bytes),"\n";
+ next;
+ }
+
+ ARGUMENT: while (1) {
+ my $arg;
+
+ if ($arg=register->re(\$line)) { opcode->size($arg->size()); }
+ elsif ($arg=const->re(\$line)) { }
+ elsif ($arg=ea->re(\$line)) { }
+ elsif ($arg=expr->re(\$line)) { }
+ else { last ARGUMENT; }
+
+ push @args,$arg;
+
+ last ARGUMENT if ($line !~ /^,/);
+
+ $line =~ s/^,\s*//;
+ } # ARGUMENT:
+
+ if ($#args>=0) {
+ my $insn;
+ my $sz=opcode->size();
+ my $arg_sz=opcode->arg_size();
+
+ if ($gas) {
+ $insn = $opcode->out($#args>=1?$args[$#args]->size():$sz);
+ @args = map($_->out($sz),@args);
+ printf "\t%s\t%s",$insn,join(",",@args);
+ } else {
+ $insn = $opcode->out();
+ foreach (@args) {
+ my $arg = $_->out();
+ # $insn.=$sz compensates for movq, pinsrw, ...
+ if ($arg =~ /^xmm[0-9]+$/) { $insn.=$sz; $sz="x" if(!$sz); last; }
+ if ($arg =~ /^ymm[0-9]+$/) { $insn.=$sz; $sz="y" if(!$sz); last; }
+ if ($arg =~ /^mm[0-9]+$/) { $insn.=$sz; $sz="q" if(!$sz); last; }
+ }
+ $sz=$arg_sz if($arg_sz);
+ @args = reverse(@args);
+ undef $sz if ($nasm && $opcode->mnemonic() eq "lea");
+
+ if ($insn eq "movq" && $#args == 1 && $args[0]->out($sz) eq "xmm0" && $args[1]->out($sz) eq "rax") {
+ # I have no clue why MASM can't parse this instruction.
+ printf "DB 66h, 48h, 0fh, 6eh, 0c0h";
+ } else {
+ printf "\t%s\t%s",$insn,join(",",map($_->out($sz),@args));
+ }
+ }
+ } else {
+ printf "\t%s",$opcode->out();
+ }
+ }
+
+ print $line,"\n";
+}
+
+print "\n$current_segment\tENDS\n" if ($current_segment && $masm);
+print "END\n" if ($masm);
+print "#endif" if ($gas);
+
+
+close STDOUT;
+
+#################################################
+# Cross-reference x86_64 ABI "card"
+#
+# Unix Win64
+# %rax * *
+# %rbx - -
+# %rcx #4 #1
+# %rdx #3 #2
+# %rsi #2 -
+# %rdi #1 -
+# %rbp - -
+# %rsp - -
+# %r8 #5 #3
+# %r9 #6 #4
+# %r10 * *
+# %r11 * *
+# %r12 - -
+# %r13 - -
+# %r14 - -
+# %r15 - -
+#
+# (*) volatile register
+# (-) preserved by callee
+# (#) Nth argument, volatile
+#
+# In Unix terms top of stack is argument transfer area for arguments
+# which could not be accomodated in registers. Or in other words 7th
+# [integer] argument resides at 8(%rsp) upon function entry point.
+# 128 bytes above %rsp constitute a "red zone" which is not touched
+# by signal handlers and can be used as temporal storage without
+# allocating a frame.
+#
+# In Win64 terms N*8 bytes on top of stack is argument transfer area,
+# which belongs to/can be overwritten by callee. N is the number of
+# arguments passed to callee, *but* not less than 4! This means that
+# upon function entry point 5th argument resides at 40(%rsp), as well
+# as that 32 bytes from 8(%rsp) can always be used as temporal
+# storage [without allocating a frame]. One can actually argue that
+# one can assume a "red zone" above stack pointer under Win64 as well.
+# Point is that at apparently no occasion Windows kernel would alter
+# the area above user stack pointer in true asynchronous manner...
+#
+# All the above means that if assembler programmer adheres to Unix
+# register and stack layout, but disregards the "red zone" existense,
+# it's possible to use following prologue and epilogue to "gear" from
+# Unix to Win64 ABI in leaf functions with not more than 6 arguments.
+#
+# omnipotent_function:
+# ifdef WIN64
+# movq %rdi,8(%rsp)
+# movq %rsi,16(%rsp)
+# movq %rcx,%rdi ; if 1st argument is actually present
+# movq %rdx,%rsi ; if 2nd argument is actually ...
+# movq %r8,%rdx ; if 3rd argument is ...
+# movq %r9,%rcx ; if 4th argument ...
+# movq 40(%rsp),%r8 ; if 5th ...
+# movq 48(%rsp),%r9 ; if 6th ...
+# endif
+# ...
+# ifdef WIN64
+# movq 8(%rsp),%rdi
+# movq 16(%rsp),%rsi
+# endif
+# ret
+#
+#################################################
+# Win64 SEH, Structured Exception Handling.
+#
+# Unlike on Unix systems(*) lack of Win64 stack unwinding information
+# has undesired side-effect at run-time: if an exception is raised in
+# assembler subroutine such as those in question (basically we're
+# referring to segmentation violations caused by malformed input
+# parameters), the application is briskly terminated without invoking
+# any exception handlers, most notably without generating memory dump
+# or any user notification whatsoever. This poses a problem. It's
+# possible to address it by registering custom language-specific
+# handler that would restore processor context to the state at
+# subroutine entry point and return "exception is not handled, keep
+# unwinding" code. Writing such handler can be a challenge... But it's
+# doable, though requires certain coding convention. Consider following
+# snippet:
+#
+# .type function,@function
+# function:
+# movq %rsp,%rax # copy rsp to volatile register
+# pushq %r15 # save non-volatile registers
+# pushq %rbx
+# pushq %rbp
+# movq %rsp,%r11
+# subq %rdi,%r11 # prepare [variable] stack frame
+# andq $-64,%r11
+# movq %rax,0(%r11) # check for exceptions
+# movq %r11,%rsp # allocate [variable] stack frame
+# movq %rax,0(%rsp) # save original rsp value
+# magic_point:
+# ...
+# movq 0(%rsp),%rcx # pull original rsp value
+# movq -24(%rcx),%rbp # restore non-volatile registers
+# movq -16(%rcx),%rbx
+# movq -8(%rcx),%r15
+# movq %rcx,%rsp # restore original rsp
+# ret
+# .size function,.-function
+#
+# The key is that up to magic_point copy of original rsp value remains
+# in chosen volatile register and no non-volatile register, except for
+# rsp, is modified. While past magic_point rsp remains constant till
+# the very end of the function. In this case custom language-specific
+# exception handler would look like this:
+#
+# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
+# CONTEXT *context,DISPATCHER_CONTEXT *disp)
+# { ULONG64 *rsp = (ULONG64 *)context->Rax;
+# if (context->Rip >= magic_point)
+# { rsp = ((ULONG64 **)context->Rsp)[0];
+# context->Rbp = rsp[-3];
+# context->Rbx = rsp[-2];
+# context->R15 = rsp[-1];
+# }
+# context->Rsp = (ULONG64)rsp;
+# context->Rdi = rsp[1];
+# context->Rsi = rsp[2];
+#
+# memcpy (disp->ContextRecord,context,sizeof(CONTEXT));
+# RtlVirtualUnwind(UNW_FLAG_NHANDLER,disp->ImageBase,
+# dips->ControlPc,disp->FunctionEntry,disp->ContextRecord,
+# &disp->HandlerData,&disp->EstablisherFrame,NULL);
+# return ExceptionContinueSearch;
+# }
+#
+# It's appropriate to implement this handler in assembler, directly in
+# function's module. In order to do that one has to know members'
+# offsets in CONTEXT and DISPATCHER_CONTEXT structures and some constant
+# values. Here they are:
+#
+# CONTEXT.Rax 120
+# CONTEXT.Rcx 128
+# CONTEXT.Rdx 136
+# CONTEXT.Rbx 144
+# CONTEXT.Rsp 152
+# CONTEXT.Rbp 160
+# CONTEXT.Rsi 168
+# CONTEXT.Rdi 176
+# CONTEXT.R8 184
+# CONTEXT.R9 192
+# CONTEXT.R10 200
+# CONTEXT.R11 208
+# CONTEXT.R12 216
+# CONTEXT.R13 224
+# CONTEXT.R14 232
+# CONTEXT.R15 240
+# CONTEXT.Rip 248
+# CONTEXT.Xmm6 512
+# sizeof(CONTEXT) 1232
+# DISPATCHER_CONTEXT.ControlPc 0
+# DISPATCHER_CONTEXT.ImageBase 8
+# DISPATCHER_CONTEXT.FunctionEntry 16
+# DISPATCHER_CONTEXT.EstablisherFrame 24
+# DISPATCHER_CONTEXT.TargetIp 32
+# DISPATCHER_CONTEXT.ContextRecord 40
+# DISPATCHER_CONTEXT.LanguageHandler 48
+# DISPATCHER_CONTEXT.HandlerData 56
+# UNW_FLAG_NHANDLER 0
+# ExceptionContinueSearch 1
+#
+# In order to tie the handler to the function one has to compose
+# couple of structures: one for .xdata segment and one for .pdata.
+#
+# UNWIND_INFO structure for .xdata segment would be
+#
+# function_unwind_info:
+# .byte 9,0,0,0
+# .rva handler
+#
+# This structure designates exception handler for a function with
+# zero-length prologue, no stack frame or frame register.
+#
+# To facilitate composing of .pdata structures, auto-generated "gear"
+# prologue copies rsp value to rax and denotes next instruction with
+# .LSEH_begin_{function_name} label. This essentially defines the SEH
+# styling rule mentioned in the beginning. Position of this label is
+# chosen in such manner that possible exceptions raised in the "gear"
+# prologue would be accounted to caller and unwound from latter's frame.
+# End of function is marked with respective .LSEH_end_{function_name}
+# label. To summarize, .pdata segment would contain
+#
+# .rva .LSEH_begin_function
+# .rva .LSEH_end_function
+# .rva function_unwind_info
+#
+# Reference to functon_unwind_info from .xdata segment is the anchor.
+# In case you wonder why references are 32-bit .rvas and not 64-bit
+# .quads. References put into these two segments are required to be
+# *relative* to the base address of the current binary module, a.k.a.
+# image base. No Win64 module, be it .exe or .dll, can be larger than
+# 2GB and thus such relative references can be and are accommodated in
+# 32 bits.
+#
+# Having reviewed the example function code, one can argue that "movq
+# %rsp,%rax" above is redundant. It is not! Keep in mind that on Unix
+# rax would contain an undefined value. If this "offends" you, use
+# another register and refrain from modifying rax till magic_point is
+# reached, i.e. as if it was a non-volatile register. If more registers
+# are required prior [variable] frame setup is completed, note that
+# nobody says that you can have only one "magic point." You can
+# "liberate" non-volatile registers by denoting last stack off-load
+# instruction and reflecting it in finer grade unwind logic in handler.
+# After all, isn't it why it's called *language-specific* handler...
+#
+# Attentive reader can notice that exceptions would be mishandled in
+# auto-generated "gear" epilogue. Well, exception effectively can't
+# occur there, because if memory area used by it was subject to
+# segmentation violation, then it would be raised upon call to the
+# function (and as already mentioned be accounted to caller, which is
+# not a problem). If you're still not comfortable, then define tail
+# "magic point" just prior ret instruction and have handler treat it...
+#
+# (*) Note that we're talking about run-time, not debug-time. Lack of
+# unwind information makes debugging hard on both Windows and
+# Unix. "Unlike" referes to the fact that on Unix signal handler
+# will always be invoked, core dumped and appropriate exit code
+# returned to parent (for user notification).
diff --git a/crypto/perlasm/x86asm.pl b/crypto/perlasm/x86asm.pl
new file mode 100644
index 0000000..7236bea
--- /dev/null
+++ b/crypto/perlasm/x86asm.pl
@@ -0,0 +1,290 @@
+#!/usr/bin/env perl
+
+# require 'x86asm.pl';
+# &asm_init(<flavor>,"des-586.pl"[,$i386only]);
+# &function_begin("foo");
+# ...
+# &function_end("foo");
+# &asm_finish
+
+$out=();
+$i386=0;
+
+# AUTOLOAD is this context has quite unpleasant side effect, namely
+# that typos in function calls effectively go to assembler output,
+# but on the pros side we don't have to implement one subroutine per
+# each opcode...
+sub ::AUTOLOAD
+{ my $opcode = $AUTOLOAD;
+
+ die "more than 4 arguments passed to $opcode" if ($#_>3);
+
+ $opcode =~ s/.*:://;
+ if ($opcode =~ /^push/) { $stack+=4; }
+ elsif ($opcode =~ /^pop/) { $stack-=4; }
+
+ &generic($opcode,@_) or die "undefined subroutine \&$AUTOLOAD";
+}
+
+sub ::emit
+{ my $opcode=shift;
+
+ if ($#_==-1) { push(@out,"\t$opcode\n"); }
+ else { push(@out,"\t$opcode\t".join(',',@_)."\n"); }
+}
+
+sub ::LB
+{ $_[0] =~ m/^e?([a-d])x$/o or die "$_[0] does not have a 'low byte'";
+ $1."l";
+}
+sub ::HB
+{ $_[0] =~ m/^e?([a-d])x$/o or die "$_[0] does not have a 'high byte'";
+ $1."h";
+}
+sub ::stack_push{ my $num=$_[0]*4; $stack+=$num; &sub("esp",$num); }
+sub ::stack_pop { my $num=$_[0]*4; $stack-=$num; &add("esp",$num); }
+sub ::blindpop { &pop($_[0]); $stack+=4; }
+sub ::wparam { &DWP($stack+4*$_[0],"esp"); }
+sub ::swtmp { &DWP(4*$_[0],"esp"); }
+
+sub ::bswap
+{ if ($i386) # emulate bswap for i386
+ { &comment("bswap @_");
+ &xchg(&HB(@_),&LB(@_));
+ &ror (@_,16);
+ &xchg(&HB(@_),&LB(@_));
+ }
+ else
+ { &generic("bswap",@_); }
+}
+# These are made-up opcodes introduced over the years essentially
+# by ignorance, just alias them to real ones...
+sub ::movb { &mov(@_); }
+sub ::xorb { &xor(@_); }
+sub ::rotl { &rol(@_); }
+sub ::rotr { &ror(@_); }
+sub ::exch { &xchg(@_); }
+sub ::halt { &hlt; }
+sub ::movz { &movzx(@_); }
+sub ::pushf { &pushfd; }
+sub ::popf { &popfd; }
+
+# 3 argument instructions
+sub ::movq
+{ my($p1,$p2,$optimize)=@_;
+
+ if ($optimize && $p1=~/^mm[0-7]$/ && $p2=~/^mm[0-7]$/)
+ # movq between mmx registers can sink Intel CPUs
+ { &::pshufw($p1,$p2,0xe4); }
+ else
+ { &::generic("movq",@_); }
+}
+
+# SSE>2 instructions
+my %regrm = ( "eax"=>0, "ecx"=>1, "edx"=>2, "ebx"=>3,
+ "esp"=>4, "ebp"=>5, "esi"=>6, "edi"=>7 );
+sub ::pextrd
+{ my($dst,$src,$imm)=@_;
+ if ("$dst:$src" =~ /(e[a-dsd][ixp]):xmm([0-7])/)
+ { &::data_byte(0x66,0x0f,0x3a,0x16,0xc0|($2<<3)|$regrm{$1},$imm); }
+ else
+ { &::generic("pextrd",@_); }
+}
+
+sub ::pinsrd
+{ my($dst,$src,$imm)=@_;
+ if ("$dst:$src" =~ /xmm([0-7]):(e[a-dsd][ixp])/)
+ { &::data_byte(0x66,0x0f,0x3a,0x22,0xc0|($1<<3)|$regrm{$2},$imm); }
+ else
+ { &::generic("pinsrd",@_); }
+}
+
+sub ::pshufb
+{ my($dst,$src)=@_;
+ if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/)
+ { &data_byte(0x66,0x0f,0x38,0x00,0xc0|($1<<3)|$2); }
+ else
+ { &::generic("pshufb",@_); }
+}
+
+sub ::palignr
+{ my($dst,$src,$imm)=@_;
+ if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/)
+ { &::data_byte(0x66,0x0f,0x3a,0x0f,0xc0|($1<<3)|$2,$imm); }
+ else
+ { &::generic("palignr",@_); }
+}
+
+sub ::pclmulqdq
+{ my($dst,$src,$imm)=@_;
+ if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/)
+ { &::data_byte(0x66,0x0f,0x3a,0x44,0xc0|($1<<3)|$2,$imm); }
+ else
+ { &::generic("pclmulqdq",@_); }
+}
+
+sub ::rdrand
+{ my ($dst)=@_;
+ if ($dst =~ /(e[a-dsd][ixp])/)
+ { &::data_byte(0x0f,0xc7,0xf0|$regrm{$dst}); }
+ else
+ { &::generic("rdrand",@_); }
+}
+
+sub rxb {
+ local *opcode=shift;
+ my ($dst,$src1,$src2,$rxb)=@_;
+
+ $rxb|=0x7<<5;
+ $rxb&=~(0x04<<5) if($dst>=8);
+ $rxb&=~(0x01<<5) if($src1>=8);
+ $rxb&=~(0x02<<5) if($src2>=8);
+ push @opcode,$rxb;
+}
+
+sub ::vprotd
+{ my $args=join(',',@_);
+ if ($args =~ /xmm([0-7]),xmm([0-7]),([x0-9a-f]+)/)
+ { my @opcode=(0x8f);
+ rxb(\@opcode,$1,$2,-1,0x08);
+ push @opcode,0x78,0xc2;
+ push @opcode,0xc0|($2&7)|(($1&7)<<3); # ModR/M
+ my $c=$3;
+ push @opcode,$c=~/^0/?oct($c):$c;
+ &::data_byte(@opcode);
+ }
+ else
+ { &::generic("vprotd",@_); }
+}
+
+# label management
+$lbdecor="L"; # local label decoration, set by package
+$label="000";
+
+sub ::islabel # see is argument is a known label
+{ my $i;
+ foreach $i (values %label) { return $i if ($i eq $_[0]); }
+ $label{$_[0]}; # can be undef
+}
+
+sub ::label # instantiate a function-scope label
+{ if (!defined($label{$_[0]}))
+ { $label{$_[0]}="${lbdecor}${label}${_[0]}"; $label++; }
+ $label{$_[0]};
+}
+
+sub ::LABEL # instantiate a file-scope label
+{ $label{$_[0]}=$_[1] if (!defined($label{$_[0]}));
+ $label{$_[0]};
+}
+
+sub ::static_label { &::LABEL($_[0],$lbdecor.$_[0]); }
+
+sub ::set_label_B { push(@out,"@_:\n"); }
+sub ::set_label
+{ my $label=&::label($_[0]);
+ &::align($_[1]) if ($_[1]>1);
+ &::set_label_B($label);
+ $label;
+}
+
+sub ::wipe_labels # wipes function-scope labels
+{ foreach $i (keys %label)
+ { delete $label{$i} if ($label{$i} =~ /^\Q${lbdecor}\E[0-9]{3}/); }
+}
+
+# subroutine management
+sub ::function_begin
+{ &function_begin_B(@_);
+ $stack=4;
+ &push("ebp");
+ &push("ebx");
+ &push("esi");
+ &push("edi");
+}
+
+sub ::function_end
+{ &pop("edi");
+ &pop("esi");
+ &pop("ebx");
+ &pop("ebp");
+ &ret();
+ &function_end_B(@_);
+ $stack=0;
+ &wipe_labels();
+}
+
+sub ::function_end_A
+{ &pop("edi");
+ &pop("esi");
+ &pop("ebx");
+ &pop("ebp");
+ &ret();
+ $stack+=16; # readjust esp as if we didn't pop anything
+}
+
+sub ::asciz
+{ my @str=unpack("C*",shift);
+ push @str,0;
+ while ($#str>15) {
+ &data_byte(@str[0..15]);
+ foreach (0..15) { shift @str; }
+ }
+ &data_byte(@str) if (@str);
+}
+
+sub ::asm_finish
+{ &file_end();
+ print "#if defined(__i386__)\n";
+ print @out;
+ print "#endif";
+}
+
+sub ::asm_init
+{ my ($type,$fn,$cpu)=@_;
+
+ $filename=$fn;
+ $i386=$cpu;
+
+ $elf=$cpp=$coff=$aout=$macosx=$win32=$netware=$mwerks=$android=0;
+ if (($type eq "elf"))
+ { $elf=1; require "x86gas.pl"; }
+ elsif (($type eq "a\.out"))
+ { $aout=1; require "x86gas.pl"; }
+ elsif (($type eq "coff" or $type eq "gaswin"))
+ { $coff=1; require "x86gas.pl"; }
+ elsif (($type eq "win32n"))
+ { $win32=1; require "x86nasm.pl"; }
+ elsif (($type eq "nw-nasm"))
+ { $netware=1; require "x86nasm.pl"; }
+ #elsif (($type eq "nw-mwasm"))
+ #{ $netware=1; $mwerks=1; require "x86nasm.pl"; }
+ elsif (($type eq "win32"))
+ { $win32=1; require "x86masm.pl"; }
+ elsif (($type eq "macosx"))
+ { $aout=1; $macosx=1; require "x86gas.pl"; }
+ elsif (($type eq "android"))
+ { $elf=1; $android=1; require "x86gas.pl"; }
+ else
+ { print STDERR <<"EOF";
+Pick one target type from
+ elf - Linux, FreeBSD, Solaris x86, etc.
+ a.out - DJGPP, elder OpenBSD, etc.
+ coff - GAS/COFF such as Win32 targets
+ win32n - Windows 95/Windows NT NASM format
+ nw-nasm - NetWare NASM format
+ macosx - Mac OS X
+EOF
+ exit(1);
+ }
+
+ $pic=0;
+ for (@ARGV) { $pic=1 if (/\-[fK]PIC/i); }
+
+ $filename =~ s/\.pl$//;
+ &file($filename);
+}
+
+sub ::hidden {}
+
+1;
diff --git a/crypto/perlasm/x86gas.pl b/crypto/perlasm/x86gas.pl
new file mode 100644
index 0000000..8bf6cef
--- /dev/null
+++ b/crypto/perlasm/x86gas.pl
@@ -0,0 +1,258 @@
+#!/usr/bin/env perl
+
+package x86gas;
+
+*out=\@::out;
+
+$::lbdecor=$::aout?"L":".L"; # local label decoration
+$nmdecor=($::aout or $::coff)?"_":""; # external name decoration
+
+$initseg="";
+
+$align=16;
+$align=log($align)/log(2) if ($::aout);
+$com_start="#" if ($::aout or $::coff);
+
+sub opsize()
+{ my $reg=shift;
+ if ($reg =~ m/^%e/o) { "l"; }
+ elsif ($reg =~ m/^%[a-d][hl]$/o) { "b"; }
+ elsif ($reg =~ m/^%[xm]/o) { undef; }
+ else { "w"; }
+}
+
+# swap arguments;
+# expand opcode with size suffix;
+# prefix numeric constants with $;
+sub ::generic
+{ my($opcode,@arg)=@_;
+ my($suffix,$dst,$src);
+
+ @arg=reverse(@arg);
+
+ for (@arg)
+ { s/^(\*?)(e?[a-dsixphl]{2})$/$1%$2/o; # gp registers
+ s/^([xy]?mm[0-7])$/%$1/o; # xmm/mmx registers
+ s/^(\-?[0-9]+)$/\$$1/o; # constants
+ s/^(\-?0x[0-9a-f]+)$/\$$1/o; # constants
+ }
+
+ $dst = $arg[$#arg] if ($#arg>=0);
+ $src = $arg[$#arg-1] if ($#arg>=1);
+ if ($dst =~ m/^%/o) { $suffix=&opsize($dst); }
+ elsif ($src =~ m/^%/o) { $suffix=&opsize($src); }
+ else { $suffix="l"; }
+ undef $suffix if ($dst =~ m/^%[xm]/o || $src =~ m/^%[xm]/o);
+
+ if ($#_==0) { &::emit($opcode); }
+ elsif ($#_==1 && $opcode =~ m/^(call|clflush|j|loop|set)/o)
+ { &::emit($opcode,@arg); }
+ else { &::emit($opcode.$suffix,@arg);}
+
+ 1;
+}
+#
+# opcodes not covered by ::generic above, mostly inconsistent namings...
+#
+sub ::movzx { &::movzb(@_); }
+sub ::pushfd { &::pushfl; }
+sub ::popfd { &::popfl; }
+sub ::cpuid { &::emit(".byte\t0x0f,0xa2"); }
+sub ::rdtsc { &::emit(".byte\t0x0f,0x31"); }
+
+sub ::call { &::emit("call",(&::islabel($_[0]) or "$nmdecor$_[0]")); }
+sub ::call_ptr { &::generic("call","*$_[0]"); }
+sub ::jmp_ptr { &::generic("jmp","*$_[0]"); }
+
+*::bswap = sub { &::emit("bswap","%$_[0]"); } if (!$::i386);
+
+sub ::DWP
+{ my($addr,$reg1,$reg2,$idx)=@_;
+ my $ret="";
+
+ if (!defined($idx) && 1*$reg2) { $idx=$reg2; $reg2=$reg1; undef $reg1; }
+
+ $addr =~ s/^\s+//;
+ # prepend global references with optional underscore
+ $addr =~ s/^([^\+\-0-9][^\+\-]*)/&::islabel($1) or "$nmdecor$1"/ige;
+
+ $reg1 = "%$reg1" if ($reg1);
+ $reg2 = "%$reg2" if ($reg2);
+
+ $ret .= $addr if (($addr ne "") && ($addr ne 0));
+
+ if ($reg2)
+ { $idx!= 0 or $idx=1;
+ $ret .= "($reg1,$reg2,$idx)";
+ }
+ elsif ($reg1)
+ { $ret .= "($reg1)"; }
+
+ $ret;
+}
+sub ::QWP { &::DWP(@_); }
+sub ::BP { &::DWP(@_); }
+sub ::WP { &::DWP(@_); }
+sub ::BC { @_; }
+sub ::DWC { @_; }
+
+sub ::file
+{ push(@out,".file\t\"$_[0].S\"\n.text\n"); }
+
+sub ::function_begin_B
+{ my $func=shift;
+ my $global=($func !~ /^_/);
+ my $begin="${::lbdecor}_${func}_begin";
+
+ &::LABEL($func,$global?"$begin":"$nmdecor$func");
+ $func=$nmdecor.$func;
+
+ push(@out,".globl\t$func\n") if ($global);
+ if ($::coff)
+ { push(@out,".def\t$func;\t.scl\t".(3-$global).";\t.type\t32;\t.endef\n"); }
+ elsif (($::aout and !$::pic) or $::macosx)
+ { }
+ else
+ { push(@out,".type $func,\@function\n"); }
+ push(@out,".align\t$align\n");
+ push(@out,"$func:\n");
+ push(@out,"$begin:\n") if ($global);
+ $::stack=4;
+}
+
+sub ::function_end_B
+{ my $func=shift;
+ push(@out,".size\t$nmdecor$func,.-".&::LABEL($func)."\n") if ($::elf);
+ $::stack=0;
+ &::wipe_labels();
+}
+
+sub ::comment
+ {
+ if (!defined($com_start) or $::elf)
+ { # Regarding $::elf above...
+ # GNU and SVR4 as'es use different comment delimiters,
+ push(@out,"\n"); # so we just skip ELF comments...
+ return;
+ }
+ foreach (@_)
+ {
+ if (/^\s*$/)
+ { push(@out,"\n"); }
+ else
+ { push(@out,"\t$com_start $_ $com_end\n"); }
+ }
+ }
+
+sub ::external_label
+{ foreach(@_) { &::LABEL($_,$nmdecor.$_); } }
+
+sub ::public_label
+{ push(@out,".globl\t".&::LABEL($_[0],$nmdecor.$_[0])."\n"); }
+
+sub ::file_end
+{ if ($::macosx)
+ { if (%non_lazy_ptr)
+ { push(@out,".section __IMPORT,__pointers,non_lazy_symbol_pointers\n");
+ foreach $i (keys %non_lazy_ptr)
+ { push(@out,"$non_lazy_ptr{$i}:\n.indirect_symbol\t$i\n.long\t0\n"); }
+ }
+ }
+ if (0 && grep {/\b${nmdecor}OPENSSL_ia32cap_P\b/i} @out) {
+ my $tmp=".comm\t${nmdecor}OPENSSL_ia32cap_P,16";
+ if ($::macosx) { push (@out,"$tmp,2\n"); }
+ elsif ($::elf) { push (@out,"$tmp,4\n"); }
+ else { push (@out,"$tmp\n"); }
+ }
+ push(@out,$initseg) if ($initseg);
+}
+
+sub ::data_byte { push(@out,".byte\t".join(',',@_)."\n"); }
+sub ::data_short{ push(@out,".value\t".join(',',@_)."\n"); }
+sub ::data_word { push(@out,".long\t".join(',',@_)."\n"); }
+
+sub ::align
+{ my $val=$_[0];
+ if ($::aout)
+ { $val=int(log($val)/log(2));
+ $val.=",0x90";
+ }
+ push(@out,".align\t$val\n");
+}
+
+sub ::picmeup
+{ my($dst,$sym,$base,$reflabel)=@_;
+
+ if (defined($base) && $sym eq "OPENSSL_ia32cap_P" && !$::macosx)
+ { &::lea($dst,&::DWP("$sym-$reflabel",$base)); }
+ elsif (($::pic && ($::elf || $::aout)) || $::macosx)
+ { if (!defined($base))
+ { &::call(&::label("PIC_me_up"));
+ &::set_label("PIC_me_up");
+ &::blindpop($dst);
+ $base=$dst;
+ $reflabel=&::label("PIC_me_up");
+ }
+ if ($::macosx)
+ { my $indirect=&::static_label("$nmdecor$sym\$non_lazy_ptr");
+ &::mov($dst,&::DWP("$indirect-$reflabel",$base));
+ $non_lazy_ptr{"$nmdecor$sym"}=$indirect;
+ }
+ else
+ { &::lea($dst,&::DWP("_GLOBAL_OFFSET_TABLE_+[.-$reflabel]",
+ $base));
+ &::mov($dst,&::DWP("$sym\@GOT",$dst));
+ }
+ }
+ else
+ { &::lea($dst,&::DWP($sym)); }
+}
+
+sub ::initseg
+{ my $f=$nmdecor.shift;
+
+ if ($::android)
+ { $initseg.=<<___;
+.section .init_array
+.align 4
+.long $f
+___
+ }
+ elsif ($::elf)
+ { $initseg.=<<___;
+.section .init
+ call $f
+___
+ }
+ elsif ($::coff)
+ { $initseg.=<<___; # applies to both Cygwin and Mingw
+.section .ctors
+.long $f
+___
+ }
+ elsif ($::macosx)
+ { $initseg.=<<___;
+.mod_init_func
+.align 2
+.long $f
+___
+ }
+ elsif ($::aout)
+ { my $ctor="${nmdecor}_GLOBAL_\$I\$$f";
+ $initseg.=".text\n";
+ $initseg.=".type $ctor,\@function\n" if ($::pic);
+ $initseg.=<<___; # OpenBSD way...
+.globl $ctor
+.align 2
+$ctor:
+ jmp $f
+___
+ }
+}
+
+sub ::dataseg
+{ push(@out,".data\n"); }
+
+*::hidden = sub { push(@out,".hidden\t$nmdecor$_[0]\n"); } if ($::elf);
+
+1;
diff --git a/crypto/perlasm/x86masm.pl b/crypto/perlasm/x86masm.pl
new file mode 100644
index 0000000..1741342
--- /dev/null
+++ b/crypto/perlasm/x86masm.pl
@@ -0,0 +1,200 @@
+#!/usr/bin/env perl
+
+package x86masm;
+
+*out=\@::out;
+
+$::lbdecor="\$L"; # local label decoration
+$nmdecor="_"; # external name decoration
+
+$initseg="";
+$segment="";
+
+sub ::generic
+{ my ($opcode,@arg)=@_;
+
+ # fix hexadecimal constants
+ for (@arg) { s/(?<![\w\$\.])0x([0-9a-f]+)/0$1h/oi; }
+
+ if ($opcode =~ /lea/ && @arg[1] =~ s/.*PTR\s+(\(.*\))$/OFFSET $1/) # no []
+ { $opcode="mov"; }
+ elsif ($opcode !~ /movq/)
+ { # fix xmm references
+ $arg[0] =~ s/\b[A-Z]+WORD\s+PTR/XMMWORD PTR/i if ($arg[1]=~/\bxmm[0-7]\b/i);
+ $arg[1] =~ s/\b[A-Z]+WORD\s+PTR/XMMWORD PTR/i if ($arg[0]=~/\bxmm[0-7]\b/i);
+ }
+
+ &::emit($opcode,@arg);
+ 1;
+}
+#
+# opcodes not covered by ::generic above, mostly inconsistent namings...
+#
+sub ::call { &::emit("call",(&::islabel($_[0]) or "$nmdecor$_[0]")); }
+sub ::call_ptr { &::emit("call",@_); }
+sub ::jmp_ptr { &::emit("jmp",@_); }
+sub ::lock { &::data_byte(0xf0); }
+
+sub get_mem
+{ my($size,$addr,$reg1,$reg2,$idx)=@_;
+ my($post,$ret);
+
+ if (!defined($idx) && 1*$reg2) { $idx=$reg2; $reg2=$reg1; undef $reg1; }
+
+ $ret .= "$size PTR " if ($size ne "");
+
+ $addr =~ s/^\s+//;
+ # prepend global references with optional underscore
+ $addr =~ s/^([^\+\-0-9][^\+\-]*)/&::islabel($1) or "$nmdecor$1"/ige;
+ # put address arithmetic expression in parenthesis
+ $addr="($addr)" if ($addr =~ /^.+[\-\+].+$/);
+
+ if (($addr ne "") && ($addr ne 0))
+ { if ($addr !~ /^-/) { $ret .= "$addr"; }
+ else { $post=$addr; }
+ }
+ $ret .= "[";
+
+ if ($reg2 ne "")
+ { $idx!=0 or $idx=1;
+ $ret .= "$reg2*$idx";
+ $ret .= "+$reg1" if ($reg1 ne "");
+ }
+ else
+ { $ret .= "$reg1"; }
+
+ $ret .= "$post]";
+ $ret =~ s/\+\]/]/; # in case $addr was the only argument
+ $ret =~ s/\[\s*\]//;
+
+ $ret;
+}
+sub ::BP { &get_mem("BYTE",@_); }
+sub ::WP { &get_mem("WORD",@_); }
+sub ::DWP { &get_mem("DWORD",@_); }
+sub ::QWP { &get_mem("QWORD",@_); }
+sub ::BC { "@_"; }
+sub ::DWC { "@_"; }
+
+sub ::file
+{ my $tmp=<<___;
+TITLE $_[0].asm
+IF \@Version LT 800
+ECHO MASM version 8.00 or later is strongly recommended.
+ENDIF
+.486
+.MODEL FLAT
+OPTION DOTNAME
+IF \@Version LT 800
+.text\$ SEGMENT PAGE 'CODE'
+ELSE
+.text\$ SEGMENT ALIGN(64) 'CODE'
+ENDIF
+___
+ push(@out,$tmp);
+ $segment = ".text\$";
+}
+
+sub ::function_begin_B
+{ my $func=shift;
+ my $global=($func !~ /^_/);
+ my $begin="${::lbdecor}_${func}_begin";
+
+ &::LABEL($func,$global?"$begin":"$nmdecor$func");
+ $func="ALIGN\t16\n".$nmdecor.$func."\tPROC";
+
+ if ($global) { $func.=" PUBLIC\n${begin}::\n"; }
+ else { $func.=" PRIVATE\n"; }
+ push(@out,$func);
+ $::stack=4;
+}
+sub ::function_end_B
+{ my $func=shift;
+
+ push(@out,"$nmdecor$func ENDP\n");
+ $::stack=0;
+ &::wipe_labels();
+}
+
+sub ::file_end
+{ my $xmmheader=<<___;
+.686
+.XMM
+IF \@Version LT 800
+XMMWORD STRUCT 16
+DQ 2 dup (?)
+XMMWORD ENDS
+ENDIF
+___
+ if (grep {/\b[x]?mm[0-7]\b/i} @out) {
+ grep {s/\.[3-7]86/$xmmheader/} @out;
+ }
+
+ push(@out,"$segment ENDS\n");
+
+ if (grep {/\b${nmdecor}OPENSSL_ia32cap_P\b/i} @out)
+ { my $comm=<<___;
+.bss SEGMENT 'BSS'
+COMM ${nmdecor}OPENSSL_ia32cap_P:DWORD:4
+.bss ENDS
+___
+ # comment out OPENSSL_ia32cap_P declarations
+ grep {s/(^EXTERN\s+${nmdecor}OPENSSL_ia32cap_P)/\;$1/} @out;
+ push (@out,$comm);
+ }
+ push (@out,$initseg) if ($initseg);
+ push (@out,"END\n");
+}
+
+sub ::comment { foreach (@_) { push(@out,"\t; $_\n"); } }
+
+*::set_label_B = sub
+{ my $l=shift; push(@out,$l.($l=~/^\Q${::lbdecor}\E[0-9]{3}/?":\n":"::\n")); };
+
+sub ::external_label
+{ foreach(@_)
+ { push(@out, "EXTERN\t".&::LABEL($_,$nmdecor.$_).":NEAR\n"); }
+}
+
+sub ::public_label
+{ push(@out,"PUBLIC\t".&::LABEL($_[0],$nmdecor.$_[0])."\n"); }
+
+sub ::data_byte
+{ push(@out,("DB\t").join(',',@_)."\n"); }
+
+sub ::data_short
+{ push(@out,("DW\t").join(',',@_)."\n"); }
+
+sub ::data_word
+{ push(@out,("DD\t").join(',',@_)."\n"); }
+
+sub ::align
+{ push(@out,"ALIGN\t$_[0]\n"); }
+
+sub ::picmeup
+{ my($dst,$sym)=@_;
+ &::lea($dst,&::DWP($sym));
+}
+
+sub ::initseg
+{ my $f=$nmdecor.shift;
+
+ $initseg.=<<___;
+.CRT\$XCU SEGMENT DWORD PUBLIC 'DATA'
+EXTERN $f:NEAR
+DD $f
+.CRT\$XCU ENDS
+___
+}
+
+sub ::dataseg
+{ push(@out,"$segment\tENDS\n_DATA\tSEGMENT\n"); $segment="_DATA"; }
+
+sub ::safeseh
+{ my $nm=shift;
+ push(@out,"IF \@Version GE 710\n");
+ push(@out,".SAFESEH ".&::LABEL($nm,$nmdecor.$nm)."\n");
+ push(@out,"ENDIF\n");
+}
+
+1;
diff --git a/crypto/perlasm/x86nasm.pl b/crypto/perlasm/x86nasm.pl
new file mode 100644
index 0000000..5d92f60
--- /dev/null
+++ b/crypto/perlasm/x86nasm.pl
@@ -0,0 +1,179 @@
+#!/usr/bin/env perl
+
+package x86nasm;
+
+*out=\@::out;
+
+$::lbdecor="L\$"; # local label decoration
+$nmdecor=$::netware?"":"_"; # external name decoration
+$drdecor=$::mwerks?".":""; # directive decoration
+
+$initseg="";
+
+sub ::generic
+{ my $opcode=shift;
+ my $tmp;
+
+ if (!$::mwerks)
+ { if ($opcode =~ m/^j/o && $#_==0) # optimize jumps
+ { $_[0] = "NEAR $_[0]"; }
+ elsif ($opcode eq "lea" && $#_==1) # wipe storage qualifier from lea
+ { $_[1] =~ s/^[^\[]*\[/\[/o; }
+ elsif ($opcode eq "clflush" && $#_==0)
+ { $_[0] =~ s/^[^\[]*\[/\[/o; }
+ }
+ &::emit($opcode,@_);
+ 1;
+}
+#
+# opcodes not covered by ::generic above, mostly inconsistent namings...
+#
+sub ::call { &::emit("call",(&::islabel($_[0]) or "$nmdecor$_[0]")); }
+sub ::call_ptr { &::emit("call",@_); }
+sub ::jmp_ptr { &::emit("jmp",@_); }
+
+sub get_mem
+{ my($size,$addr,$reg1,$reg2,$idx)=@_;
+ my($post,$ret);
+
+ if (!defined($idx) && 1*$reg2) { $idx=$reg2; $reg2=$reg1; undef $reg1; }
+
+ if ($size ne "")
+ { $ret .= "$size";
+ $ret .= " PTR" if ($::mwerks);
+ $ret .= " ";
+ }
+ $ret .= "[";
+
+ $addr =~ s/^\s+//;
+ # prepend global references with optional underscore
+ $addr =~ s/^([^\+\-0-9][^\+\-]*)/::islabel($1) or "$nmdecor$1"/ige;
+ # put address arithmetic expression in parenthesis
+ $addr="($addr)" if ($addr =~ /^.+[\-\+].+$/);
+
+ if (($addr ne "") && ($addr ne 0))
+ { if ($addr !~ /^-/) { $ret .= "$addr+"; }
+ else { $post=$addr; }
+ }
+
+ if ($reg2 ne "")
+ { $idx!=0 or $idx=1;
+ $ret .= "$reg2*$idx";
+ $ret .= "+$reg1" if ($reg1 ne "");
+ }
+ else
+ { $ret .= "$reg1"; }
+
+ $ret .= "$post]";
+ $ret =~ s/\+\]/]/; # in case $addr was the only argument
+
+ $ret;
+}
+sub ::BP { &get_mem("BYTE",@_); }
+sub ::DWP { &get_mem("DWORD",@_); }
+sub ::WP { &get_mem("WORD",@_); }
+sub ::QWP { &get_mem("",@_); }
+sub ::BC { (($::mwerks)?"":"BYTE ")."@_"; }
+sub ::DWC { (($::mwerks)?"":"DWORD ")."@_"; }
+
+sub ::file
+{ if ($::mwerks) { push(@out,".section\t.text,64\n"); }
+ else
+ { my $tmp=<<___;
+%ifidn __OUTPUT_FORMAT__,obj
+section code use32 class=code align=64
+%elifidn __OUTPUT_FORMAT__,win32
+\$\@feat.00 equ 1
+section .text code align=64
+%else
+section .text code
+%endif
+___
+ push(@out,$tmp);
+ }
+}
+
+sub ::function_begin_B
+{ my $func=shift;
+ my $global=($func !~ /^_/);
+ my $begin="${::lbdecor}_${func}_begin";
+
+ $begin =~ s/^\@/./ if ($::mwerks); # the torture never stops
+
+ &::LABEL($func,$global?"$begin":"$nmdecor$func");
+ $func=$nmdecor.$func;
+
+ push(@out,"${drdecor}global $func\n") if ($global);
+ push(@out,"${drdecor}align 16\n");
+ push(@out,"$func:\n");
+ push(@out,"$begin:\n") if ($global);
+ $::stack=4;
+}
+
+sub ::function_end_B
+{ $::stack=0;
+ &::wipe_labels();
+}
+
+sub ::file_end
+{ if (grep {/\b${nmdecor}OPENSSL_ia32cap_P\b/i} @out)
+ { my $comm=<<___;
+${drdecor}segment .bss
+${drdecor}common ${nmdecor}OPENSSL_ia32cap_P 16
+___
+ # comment out OPENSSL_ia32cap_P declarations
+ grep {s/(^extern\s+${nmdecor}OPENSSL_ia32cap_P)/\;$1/} @out;
+ push (@out,$comm)
+ }
+ push (@out,$initseg) if ($initseg);
+}
+
+sub ::comment { foreach (@_) { push(@out,"\t; $_\n"); } }
+
+sub ::external_label
+{ foreach(@_)
+ { push(@out,"${drdecor}extern\t".&::LABEL($_,$nmdecor.$_)."\n"); }
+}
+
+sub ::public_label
+{ push(@out,"${drdecor}global\t".&::LABEL($_[0],$nmdecor.$_[0])."\n"); }
+
+sub ::data_byte
+{ push(@out,(($::mwerks)?".byte\t":"db\t").join(',',@_)."\n"); }
+sub ::data_short
+{ push(@out,(($::mwerks)?".word\t":"dw\t").join(',',@_)."\n"); }
+sub ::data_word
+{ push(@out,(($::mwerks)?".long\t":"dd\t").join(',',@_)."\n"); }
+
+sub ::align
+{ push(@out,"${drdecor}align\t$_[0]\n"); }
+
+sub ::picmeup
+{ my($dst,$sym)=@_;
+ &::lea($dst,&::DWP($sym));
+}
+
+sub ::initseg
+{ my $f=$nmdecor.shift;
+ if ($::win32)
+ { $initseg=<<___;
+segment .CRT\$XCU data align=4
+extern $f
+dd $f
+___
+ }
+}
+
+sub ::dataseg
+{ if ($mwerks) { push(@out,".section\t.data,4\n"); }
+ else { push(@out,"section\t.data align=4\n"); }
+}
+
+sub ::safeseh
+{ my $nm=shift;
+ push(@out,"%if __NASM_VERSION_ID__ >= 0x02030000\n");
+ push(@out,"safeseh ".&::LABEL($nm,$nmdecor.$nm)."\n");
+ push(@out,"%endif\n");
+}
+
+1;
diff --git a/crypto/pkcs8/CMakeLists.txt b/crypto/pkcs8/CMakeLists.txt
new file mode 100644
index 0000000..b89af85
--- /dev/null
+++ b/crypto/pkcs8/CMakeLists.txt
@@ -0,0 +1,13 @@
+include_directories(. .. ../../include)
+
+add_library(
+ pkcs8
+
+ OBJECT
+
+ pkcs8.c
+ p8_pkey.c
+ p5_pbe.c
+ p5_pbev2.c
+ pkcs8_error.c
+)
diff --git a/crypto/pkcs8/internal.h b/crypto/pkcs8/internal.h
new file mode 100644
index 0000000..44ca4f7
--- /dev/null
+++ b/crypto/pkcs8/internal.h
@@ -0,0 +1,74 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999 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). */
+
+#ifndef OPENSSL_HEADER_PKCS8_INTERNAL_H
+#define OPENSSL_HEADER_PKCS8_INTERNAL_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+#define PKCS5_DEFAULT_ITERATIONS 2048
+#define PKCS5_SALT_LEN 8
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_PKCS8_INTERNAL_H */
diff --git a/crypto/pkcs8/p5_pbe.c b/crypto/pkcs8/p5_pbe.c
new file mode 100644
index 0000000..9cdff4c
--- /dev/null
+++ b/crypto/pkcs8/p5_pbe.c
@@ -0,0 +1,148 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999 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/asn1t.h>
+#include <openssl/err.h>
+#include <openssl/pkcs8.h>
+#include <openssl/rand.h>
+#include <openssl/x509.h>
+
+#include "internal.h"
+
+
+/* PKCS#5 password based encryption structure */
+
+ASN1_SEQUENCE(PBEPARAM) = {
+ ASN1_SIMPLE(PBEPARAM, salt, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(PBEPARAM, iter, ASN1_INTEGER)
+} ASN1_SEQUENCE_END(PBEPARAM)
+
+IMPLEMENT_ASN1_FUNCTIONS(PBEPARAM)
+
+
+/* Set an algorithm identifier for a PKCS#5 PBE algorithm */
+
+int PKCS5_pbe_set0_algor(X509_ALGOR *algor, int alg, int iter,
+ const unsigned char *salt, int saltlen)
+ {
+ PBEPARAM *pbe=NULL;
+ ASN1_STRING *pbe_str=NULL;
+ unsigned char *sstr;
+
+ pbe = PBEPARAM_new();
+ if (!pbe)
+ {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS5_pbe_set0_algor, 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);
+ 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);
+ goto err;
+ }
+ sstr = ASN1_STRING_data(pbe->salt);
+ if (salt)
+ memcpy(sstr, salt, saltlen);
+ else if (RAND_pseudo_bytes(sstr, saltlen) < 0)
+ goto err;
+
+ if(!ASN1_item_pack(pbe, ASN1_ITEM_rptr(PBEPARAM), &pbe_str))
+ {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS5_pbe_set0_algor, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ PBEPARAM_free(pbe);
+ pbe = NULL;
+
+ if (X509_ALGOR_set0(algor, OBJ_nid2obj(alg), V_ASN1_SEQUENCE, pbe_str))
+ return 1;
+
+err:
+ if (pbe != NULL)
+ PBEPARAM_free(pbe);
+ if (pbe_str != NULL)
+ ASN1_STRING_free(pbe_str);
+ return 0;
+ }
+
+/* Return an algorithm identifier for a PKCS#5 PBE algorithm */
+
+X509_ALGOR *PKCS5_pbe_set(int alg, int iter,
+ const unsigned char *salt, int saltlen)
+ {
+ X509_ALGOR *ret;
+ ret = X509_ALGOR_new();
+ if (!ret)
+ {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS5_pbe_set, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ if (PKCS5_pbe_set0_algor(ret, alg, iter, salt, saltlen))
+ return ret;
+
+ X509_ALGOR_free(ret);
+ return NULL;
+ }
diff --git a/crypto/pkcs8/p5_pbev2.c b/crypto/pkcs8/p5_pbev2.c
new file mode 100644
index 0000000..66746df
--- /dev/null
+++ b/crypto/pkcs8/p5_pbev2.c
@@ -0,0 +1,298 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999-2004.
+ */
+/* ====================================================================
+ * Copyright (c) 1999 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/asn1t.h>
+#include <openssl/cipher.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/pkcs8.h>
+#include <openssl/rand.h>
+#include <openssl/x509.h>
+
+#include "internal.h"
+
+
+/* PKCS#5 v2.0 password based encryption structures */
+
+ASN1_SEQUENCE(PBE2PARAM) = {
+ ASN1_SIMPLE(PBE2PARAM, keyfunc, X509_ALGOR),
+ ASN1_SIMPLE(PBE2PARAM, encryption, X509_ALGOR)
+} ASN1_SEQUENCE_END(PBE2PARAM)
+
+IMPLEMENT_ASN1_FUNCTIONS(PBE2PARAM)
+
+ASN1_SEQUENCE(PBKDF2PARAM) = {
+ ASN1_SIMPLE(PBKDF2PARAM, salt, ASN1_ANY),
+ ASN1_SIMPLE(PBKDF2PARAM, iter, ASN1_INTEGER),
+ ASN1_OPT(PBKDF2PARAM, keylength, ASN1_INTEGER),
+ ASN1_OPT(PBKDF2PARAM, prf, X509_ALGOR)
+} ASN1_SEQUENCE_END(PBKDF2PARAM)
+
+IMPLEMENT_ASN1_FUNCTIONS(PBKDF2PARAM);
+
+static int ASN1_TYPE_set_octetstring(ASN1_TYPE *a, unsigned char *data, int len)
+ {
+ ASN1_STRING *os;
+
+ if ((os=M_ASN1_OCTET_STRING_new()) == NULL) return(0);
+ if (!M_ASN1_OCTET_STRING_set(os,data,len)) return(0);
+ ASN1_TYPE_set(a,V_ASN1_OCTET_STRING,os);
+ return(1);
+ }
+
+static int param_to_asn1(EVP_CIPHER_CTX *c, ASN1_TYPE *type)
+ {
+ unsigned iv_len;
+
+ iv_len = EVP_CIPHER_CTX_iv_length(c);
+ return ASN1_TYPE_set_octetstring(type, c->oiv, iv_len);
+ }
+
+/* Return an algorithm identifier for a PKCS#5 v2.0 PBE algorithm:
+ * yes I know this is horrible!
+ *
+ * Extended version to allow application supplied PRF NID and IV. */
+
+X509_ALGOR *PKCS5_pbe2_set_iv(const EVP_CIPHER *cipher, int iter,
+ unsigned char *salt, int saltlen,
+ unsigned char *aiv, int prf_nid)
+{
+ X509_ALGOR *scheme = NULL, *kalg = NULL, *ret = NULL;
+ int alg_nid, keylen;
+ EVP_CIPHER_CTX ctx;
+ unsigned char iv[EVP_MAX_IV_LENGTH];
+ PBE2PARAM *pbe2 = NULL;
+ const ASN1_OBJECT *obj;
+
+ 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);
+ goto err;
+ }
+ obj = OBJ_nid2obj(alg_nid);
+
+ if(!(pbe2 = PBE2PARAM_new())) goto merr;
+
+ /* Setup the AlgorithmIdentifier for the encryption scheme */
+ scheme = pbe2->encryption;
+
+ scheme->algorithm = (ASN1_OBJECT*) obj;
+ if(!(scheme->parameter = ASN1_TYPE_new())) goto merr;
+
+ /* Create random IV */
+ if (EVP_CIPHER_iv_length(cipher))
+ {
+ if (aiv)
+ memcpy(iv, aiv, EVP_CIPHER_iv_length(cipher));
+ else if (RAND_pseudo_bytes(iv, EVP_CIPHER_iv_length(cipher)) < 0)
+ goto err;
+ }
+
+ EVP_CIPHER_CTX_init(&ctx);
+
+ /* Dummy cipherinit to just setup the IV, and PRF */
+ 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);
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ goto err;
+ }
+ /* If prf NID unspecified see if cipher has a preference.
+ * An error is OK here: just means use default PRF.
+ */
+ if ((prf_nid == -1) &&
+ EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_PBE_PRF_NID, 0, &prf_nid) <= 0)
+ {
+ ERR_clear_error();
+ prf_nid = NID_hmacWithSHA1;
+ }
+ EVP_CIPHER_CTX_cleanup(&ctx);
+
+ /* If its RC2 then we'd better setup the key length */
+
+ if(alg_nid == NID_rc2_cbc)
+ keylen = EVP_CIPHER_key_length(cipher);
+ else
+ keylen = -1;
+
+ /* Setup keyfunc */
+
+ X509_ALGOR_free(pbe2->keyfunc);
+
+ pbe2->keyfunc = PKCS5_pbkdf2_set(iter, salt, saltlen, prf_nid, keylen);
+
+ if (!pbe2->keyfunc)
+ goto merr;
+
+ /* Now set up top level AlgorithmIdentifier */
+
+ if(!(ret = X509_ALGOR_new())) goto merr;
+ if(!(ret->parameter = ASN1_TYPE_new())) goto merr;
+
+ ret->algorithm = (ASN1_OBJECT*) OBJ_nid2obj(NID_pbes2);
+
+ /* Encode PBE2PARAM into parameter */
+
+ if(!ASN1_item_pack(pbe2, ASN1_ITEM_rptr(PBE2PARAM),
+ &ret->parameter->value.sequence)) goto merr;
+ ret->parameter->type = V_ASN1_SEQUENCE;
+
+ PBE2PARAM_free(pbe2);
+ pbe2 = NULL;
+
+ return ret;
+
+ merr:
+ OPENSSL_PUT_ERROR(PKCS8, PKCS5_pbe2_set_iv, ERR_R_MALLOC_FAILURE);
+
+ err:
+ PBE2PARAM_free(pbe2);
+ /* Note 'scheme' is freed as part of pbe2 */
+ X509_ALGOR_free(kalg);
+ X509_ALGOR_free(ret);
+
+ return NULL;
+
+}
+
+X509_ALGOR *PKCS5_pbe2_set(const EVP_CIPHER *cipher, int iter,
+ unsigned char *salt, int saltlen)
+ {
+ return PKCS5_pbe2_set_iv(cipher, iter, salt, saltlen, NULL, -1);
+ }
+
+X509_ALGOR *PKCS5_pbkdf2_set(int iter, unsigned char *salt, int saltlen,
+ int prf_nid, int keylen)
+ {
+ X509_ALGOR *keyfunc = NULL;
+ PBKDF2PARAM *kdf = NULL;
+ ASN1_OCTET_STRING *osalt = NULL;
+
+ if(!(kdf = PBKDF2PARAM_new()))
+ goto merr;
+ if(!(osalt = M_ASN1_OCTET_STRING_new()))
+ goto merr;
+
+ kdf->salt->value.octet_string = osalt;
+ kdf->salt->type = V_ASN1_OCTET_STRING;
+
+ if (!saltlen)
+ saltlen = PKCS5_SALT_LEN;
+ if (!(osalt->data = OPENSSL_malloc (saltlen)))
+ goto merr;
+
+ osalt->length = saltlen;
+
+ if (salt)
+ memcpy (osalt->data, salt, saltlen);
+ else if (RAND_pseudo_bytes (osalt->data, saltlen) < 0)
+ goto merr;
+
+ if(iter <= 0)
+ iter = PKCS5_DEFAULT_ITERATIONS;
+
+ if(!ASN1_INTEGER_set(kdf->iter, iter))
+ goto merr;
+
+ /* If have a key len set it up */
+
+ if(keylen > 0)
+ {
+ if(!(kdf->keylength = M_ASN1_INTEGER_new()))
+ goto merr;
+ if(!ASN1_INTEGER_set (kdf->keylength, keylen))
+ goto merr;
+ }
+
+ /* prf can stay NULL if we are using hmacWithSHA1 */
+ if (prf_nid > 0 && prf_nid != NID_hmacWithSHA1)
+ {
+ kdf->prf = X509_ALGOR_new();
+ if (!kdf->prf)
+ goto merr;
+ X509_ALGOR_set0(kdf->prf, OBJ_nid2obj(prf_nid),
+ V_ASN1_NULL, NULL);
+ }
+
+ /* Finally setup the keyfunc structure */
+
+ keyfunc = X509_ALGOR_new();
+ if (!keyfunc)
+ goto merr;
+
+ keyfunc->algorithm = (ASN1_OBJECT*) OBJ_nid2obj(NID_id_pbkdf2);
+
+ /* Encode PBKDF2PARAM into parameter of pbe2 */
+
+ if(!(keyfunc->parameter = ASN1_TYPE_new()))
+ goto merr;
+
+ if(!ASN1_item_pack(kdf, ASN1_ITEM_rptr(PBKDF2PARAM),
+ &keyfunc->parameter->value.sequence))
+ goto merr;
+ keyfunc->parameter->type = V_ASN1_SEQUENCE;
+
+ PBKDF2PARAM_free(kdf);
+ return keyfunc;
+
+ merr:
+ OPENSSL_PUT_ERROR(PKCS8, PKCS5_pbkdf2_set, ERR_R_MALLOC_FAILURE);
+ PBKDF2PARAM_free(kdf);
+ X509_ALGOR_free(keyfunc);
+ return NULL;
+ }
+
diff --git a/crypto/pkcs8/p8_pkey.c b/crypto/pkcs8/p8_pkey.c
new file mode 100644
index 0000000..9095ffd
--- /dev/null
+++ b/crypto/pkcs8/p8_pkey.c
@@ -0,0 +1,84 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2005 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 <stdio.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/mem.h>
+#include <openssl/x509.h>
+
+/* Minor tweak to operation: zero private key data */
+static int pkey_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
+ void *exarg)
+{
+ /* Since the structure must still be valid use ASN1_OP_FREE_PRE */
+ if(operation == ASN1_OP_FREE_PRE) {
+ PKCS8_PRIV_KEY_INFO *key = (PKCS8_PRIV_KEY_INFO *)*pval;
+ if (key->pkey->value.octet_string)
+ OPENSSL_cleanse(key->pkey->value.octet_string->data,
+ key->pkey->value.octet_string->length);
+ }
+ return 1;
+}
+
+ASN1_SEQUENCE_cb(PKCS8_PRIV_KEY_INFO, pkey_cb) = {
+ ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, version, ASN1_INTEGER),
+ ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, pkeyalg, X509_ALGOR),
+ ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, pkey, ASN1_ANY),
+ ASN1_IMP_SET_OF_OPT(PKCS8_PRIV_KEY_INFO, attributes, X509_ATTRIBUTE, 0)
+} ASN1_SEQUENCE_END_cb(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO)
+
+IMPLEMENT_ASN1_FUNCTIONS(PKCS8_PRIV_KEY_INFO)
diff --git a/crypto/pkcs8/pkcs8.c b/crypto/pkcs8/pkcs8.c
new file mode 100644
index 0000000..310af83
--- /dev/null
+++ b/crypto/pkcs8/pkcs8.c
@@ -0,0 +1,580 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999 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/pkcs8.h>
+
+#include <openssl/asn1.h>
+#include <openssl/bn.h>
+#include <openssl/cipher.h>
+#include <openssl/digest.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/x509.h>
+
+#include "../evp/internal.h"
+
+
+#define PKCS12_KEY_ID 1
+#define PKCS12_IV_ID 2
+
+static int ascii_to_ucs2(const char *ascii, size_t ascii_len,
+ uint8_t **out, size_t *out_len) {
+ uint8_t *unitmp;
+ size_t ulen, i;
+
+ ulen = ascii_len * 2 + 2;
+ if (ulen < ascii_len) {
+ return 0;
+ }
+ unitmp = OPENSSL_malloc(ulen);
+ if (unitmp == NULL) {
+ return 0;
+ }
+ for (i = 0; i < ulen - 2; i += 2) {
+ unitmp[i] = 0;
+ unitmp[i + 1] = ascii[i >> 1];
+ }
+
+ /* Make result double null terminated */
+ unitmp[ulen - 2] = 0;
+ unitmp[ulen - 1] = 0;
+ *out_len = ulen;
+ *out = unitmp;
+ return 1;
+}
+
+static int pkcs12_key_gen_uni(uint8_t *pass, size_t pass_len, uint8_t *salt,
+ size_t salt_len, int id, int iterations,
+ size_t out_len, uint8_t *out,
+ const EVP_MD *md_type) {
+ uint8_t *B, *D, *I, *p, *Ai;
+ int Slen, Plen, Ilen, Ijlen;
+ int i, j, v;
+ size_t u;
+ int ret = 0;
+ BIGNUM *Ij, *Bpl1; /* These hold Ij and B + 1 */
+ EVP_MD_CTX ctx;
+
+ EVP_MD_CTX_init(&ctx);
+ v = EVP_MD_block_size(md_type);
+ u = EVP_MD_size(md_type);
+ D = OPENSSL_malloc(v);
+ Ai = OPENSSL_malloc(u);
+ B = OPENSSL_malloc(v + 1);
+ Slen = v * ((salt_len + v - 1) / v);
+ if (pass_len)
+ Plen = v * ((pass_len + v - 1) / v);
+ else
+ Plen = 0;
+ Ilen = Slen + Plen;
+ I = OPENSSL_malloc(Ilen);
+ Ij = BN_new();
+ Bpl1 = BN_new();
+ if (!D || !Ai || !B || !I || !Ij || !Bpl1)
+ goto err;
+ for (i = 0; i < v; i++)
+ D[i] = id;
+ p = I;
+ for (i = 0; i < Slen; i++)
+ *p++ = salt[i % salt_len];
+ for (i = 0; i < Plen; i++)
+ *p++ = pass[i % pass_len];
+ for (;;) {
+ if (!EVP_DigestInit_ex(&ctx, md_type, NULL) ||
+ !EVP_DigestUpdate(&ctx, D, v) ||
+ !EVP_DigestUpdate(&ctx, I, Ilen) ||
+ !EVP_DigestFinal_ex(&ctx, Ai, NULL)) {
+ goto err;
+ }
+ for (j = 1; j < iterations; j++) {
+ if (!EVP_DigestInit_ex(&ctx, md_type, NULL) ||
+ !EVP_DigestUpdate(&ctx, Ai, u) ||
+ !EVP_DigestFinal_ex(&ctx, Ai, NULL)) {
+ goto err;
+ }
+ }
+ memcpy(out, Ai, out_len < u ? out_len : u);
+ if (u >= out_len) {
+ ret = 1;
+ goto end;
+ }
+ out_len -= u;
+ out += u;
+ for (j = 0; j < v; j++)
+ B[j] = Ai[j % u];
+ /* Work out B + 1 first then can use B as tmp space */
+ if (!BN_bin2bn(B, v, Bpl1))
+ goto err;
+ if (!BN_add_word(Bpl1, 1))
+ goto err;
+ for (j = 0; j < Ilen; j += v) {
+ if (!BN_bin2bn(I + j, v, Ij))
+ goto err;
+ if (!BN_add(Ij, Ij, Bpl1))
+ goto err;
+ if (!BN_bn2bin(Ij, B))
+ goto err;
+ Ijlen = BN_num_bytes(Ij);
+ /* If more than 2^(v*8) - 1 cut off MSB */
+ if (Ijlen > v) {
+ if (!BN_bn2bin(Ij, B))
+ goto err;
+ memcpy(I + j, B + 1, v);
+ /* If less than v bytes pad with zeroes */
+ } else if (Ijlen < v) {
+ memset(I + j, 0, v - Ijlen);
+ if (!BN_bn2bin(Ij, I + j + v - Ijlen))
+ goto err;
+ } else if (!BN_bn2bin(Ij, I + j)) {
+ goto err;
+ }
+ }
+ }
+
+err:
+ OPENSSL_PUT_ERROR(PKCS8, pkcs12_key_gen_uni, ERR_R_MALLOC_FAILURE);
+
+end:
+ OPENSSL_free(Ai);
+ OPENSSL_free(B);
+ OPENSSL_free(D);
+ OPENSSL_free(I);
+ BN_free(Ij);
+ BN_free(Bpl1);
+ EVP_MD_CTX_cleanup(&ctx);
+
+ return ret;
+}
+
+static int pkcs12_key_gen_asc(const char *pass, size_t pass_len, uint8_t *salt,
+ size_t salt_len, int id, int iterations,
+ int out_len, uint8_t *out,
+ const EVP_MD *md_type) {
+ int ret;
+ uint8_t *ucs2_pass = NULL;
+ size_t ucs2_pass_len = 0;
+
+ if (pass && !ascii_to_ucs2(pass, pass_len, &ucs2_pass, &ucs2_pass_len)) {
+ OPENSSL_PUT_ERROR(PKCS8, pkcs12_key_gen_asc, PKCS8_R_DECODE_ERROR);
+ return 0;
+ }
+ ret = pkcs12_key_gen_uni(ucs2_pass, ucs2_pass_len, salt, salt_len, id,
+ iterations, out_len, out, md_type);
+
+ if (ucs2_pass) {
+ OPENSSL_cleanse(ucs2_pass, ucs2_pass_len);
+ OPENSSL_free(ucs2_pass);
+ }
+
+ return ret;
+}
+
+static int pkcs12_pbe_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass,
+ size_t pass_len, ASN1_TYPE *param,
+ const EVP_CIPHER *cipher, const EVP_MD *md,
+ int is_encrypt) {
+ PBEPARAM *pbe;
+ int salt_len, iterations, ret;
+ uint8_t *salt;
+ const uint8_t *pbuf;
+ uint8_t key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
+
+ /* 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);
+ 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);
+ return 0;
+ }
+
+ if (!pbe->iter) {
+ iterations = 1;
+ } else {
+ iterations = ASN1_INTEGER_get(pbe->iter);
+ }
+ salt = pbe->salt->data;
+ salt_len = pbe->salt->length;
+ if (!pkcs12_key_gen_asc(pass, pass_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);
+ PBEPARAM_free(pbe);
+ return 0;
+ }
+ if (!pkcs12_key_gen_asc(pass, pass_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);
+ PBEPARAM_free(pbe);
+ return 0;
+ }
+ PBEPARAM_free(pbe);
+ ret = EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, is_encrypt);
+ OPENSSL_cleanse(key, EVP_MAX_KEY_LENGTH);
+ OPENSSL_cleanse(iv, EVP_MAX_IV_LENGTH);
+ return ret;
+}
+
+typedef int (*keygen_func)(EVP_CIPHER_CTX *ctx, const char *pass,
+ size_t pass_len, ASN1_TYPE *param,
+ const EVP_CIPHER *cipher, const EVP_MD *md,
+ int is_encrypt);
+
+struct pbe_suite {
+ int pbe_nid;
+ int cipher_nid;
+ int md_nid;
+ keygen_func keygen;
+};
+
+static const struct pbe_suite kBuiltinPBE[] = {
+ {
+ NID_pbe_WithSHA1And128BitRC4, NID_rc4, NID_sha1, pkcs12_pbe_keyivgen,
+ },
+ {
+ NID_pbe_WithSHA1And3_Key_TripleDES_CBC, NID_des_ede3_cbc, NID_sha1,
+ pkcs12_pbe_keyivgen,
+ },
+};
+
+static int pbe_cipher_init(ASN1_OBJECT *pbe_obj, const char *pass,
+ size_t pass_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++) {
+ suite = &kBuiltinPBE[i];
+ if (suite->pbe_nid == pbe_nid) {
+ break;
+ }
+ }
+
+ if (suite == NULL) {
+ char obj_str[80];
+ OPENSSL_PUT_ERROR(PKCS8, pbe_cipher_init, PKCS8_R_UNKNOWN_ALGORITHM);
+ if (!pbe_obj) {
+ strncpy(obj_str, "NULL", sizeof(obj_str));
+ } else {
+ i2t_ASN1_OBJECT(obj_str, sizeof(obj_str), pbe_obj);
+ }
+ ERR_add_error_data(2, "TYPE=", obj_str);
+ return 0;
+ }
+
+ if (suite->cipher_nid == -1) {
+ cipher = NULL;
+ } else {
+ cipher = EVP_get_cipherbynid(suite->cipher_nid);
+ if (!cipher) {
+ OPENSSL_PUT_ERROR(PKCS8, pbe_cipher_init, PKCS8_R_UNKNOWN_CIPHER);
+ return 0;
+ }
+ }
+
+ if (suite->md_nid == -1) {
+ md = NULL;
+ } else {
+ md = EVP_get_digestbynid(suite->md_nid);
+ if (!md) {
+ OPENSSL_PUT_ERROR(PKCS8, pbe_cipher_init, PKCS8_R_UNKNOWN_DIGEST);
+ return 0;
+ }
+ }
+
+ if (!suite->keygen(ctx, pass, pass_len, param, cipher, md, is_encrypt)) {
+ OPENSSL_PUT_ERROR(PKCS8, pbe_cipher_init, PKCS8_R_KEYGEN_FAILURE);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int pbe_crypt(const X509_ALGOR *algor, const char *pass, size_t pass_len,
+ uint8_t *in, size_t in_len, uint8_t **out, size_t *out_len,
+ int is_encrypt) {
+ uint8_t *buf;
+ int n, ret = 0;
+ EVP_CIPHER_CTX ctx;
+ unsigned block_size;
+
+ EVP_CIPHER_CTX_init(&ctx);
+
+ if (!pbe_cipher_init(algor->algorithm, pass, pass_len, algor->parameter, &ctx,
+ is_encrypt)) {
+ OPENSSL_PUT_ERROR(PKCS8, pbe_crypt, 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);
+ goto err;
+ }
+
+ buf = OPENSSL_malloc(in_len + block_size);
+ if (buf == NULL) {
+ OPENSSL_PUT_ERROR(PKCS8, pbe_crypt, 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);
+ 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);
+ goto err;
+ }
+ *out_len += n;
+ *out = buf;
+ ret = 1;
+
+err:
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ return ret;
+}
+
+static void *pkcs12_item_decrypt_d2i(X509_ALGOR *algor, const ASN1_ITEM *it,
+ const char *pass, size_t pass_len,
+ ASN1_OCTET_STRING *oct) {
+ uint8_t *out;
+ const uint8_t *p;
+ void *ret;
+ size_t out_len;
+
+ if (!pbe_crypt(algor, pass, pass_len, oct->data, oct->length, &out, &out_len,
+ 0 /* decrypt */)) {
+ OPENSSL_PUT_ERROR(PKCS8, pkcs12_item_decrypt_d2i, 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_free(out);
+ return ret;
+}
+
+PKCS8_PRIV_KEY_INFO *PKCS8_decrypt(X509_SIG *pkcs8, const char *pass,
+ int pass_len) {
+ if (pass && pass_len == -1) {
+ pass_len = strlen(pass);
+ }
+ return pkcs12_item_decrypt_d2i(pkcs8->algor,
+ ASN1_ITEM_rptr(PKCS8_PRIV_KEY_INFO), pass,
+ pass_len, pkcs8->digest);
+}
+
+static ASN1_OCTET_STRING *pkcs12_item_i2d_encrypt(X509_ALGOR *algor,
+ const ASN1_ITEM *it,
+ const char *pass,
+ size_t passlen, void *obj) {
+ ASN1_OCTET_STRING *oct;
+ uint8_t *in = NULL;
+ int in_len;
+ size_t crypt_len;
+
+ oct = M_ASN1_OCTET_STRING_new();
+ if (oct == NULL) {
+ OPENSSL_PUT_ERROR(PKCS8, pkcs12_item_i2d_encrypt, 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);
+ return NULL;
+ }
+ if (!pbe_crypt(algor, pass, passlen, in, in_len, &oct->data, &crypt_len,
+ 1 /* encrypt */)) {
+ OPENSSL_PUT_ERROR(PKCS8, pkcs12_item_i2d_encrypt, PKCS8_R_ENCRYPT_ERROR);
+ OPENSSL_free(in);
+ return NULL;
+ }
+ oct->length = crypt_len;
+ OPENSSL_cleanse(in, in_len);
+ OPENSSL_free(in);
+ return oct;
+}
+
+X509_SIG *PKCS8_encrypt(int pbe_nid, const EVP_CIPHER *cipher, const char *pass,
+ int pass_len, uint8_t *salt, size_t salt_len,
+ int iterations, PKCS8_PRIV_KEY_INFO *p8inf) {
+ X509_SIG *pkcs8 = NULL;
+ X509_ALGOR *pbe;
+
+ if (pass && pass_len == -1) {
+ pass_len = strlen(pass);
+ }
+
+ pkcs8 = X509_SIG_new();
+ if (pkcs8 == NULL) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_encrypt, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ 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, ERR_R_ASN1_LIB);
+ goto err;
+ }
+
+ X509_ALGOR_free(pkcs8->algor);
+ pkcs8->algor = pbe;
+ M_ASN1_OCTET_STRING_free(pkcs8->digest);
+ pkcs8->digest = pkcs12_item_i2d_encrypt(
+ pbe, ASN1_ITEM_rptr(PKCS8_PRIV_KEY_INFO), pass, pass_len, p8inf);
+ if (!pkcs8->digest) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_encrypt, PKCS8_R_ENCRYPT_ERROR);
+ goto err;
+ }
+
+ return pkcs8;
+
+err:
+ X509_SIG_free(pkcs8);
+ return NULL;
+}
+
+EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8) {
+ EVP_PKEY *pkey = NULL;
+ ASN1_OBJECT *algoid;
+ char obj_tmp[80];
+
+ if (!PKCS8_pkey_get0(&algoid, NULL, NULL, NULL, p8))
+ return NULL;
+
+ pkey = EVP_PKEY_new();
+ if (pkey == NULL) {
+ OPENSSL_PUT_ERROR(PKCS8, EVP_PKCS82PKEY, 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);
+ i2t_ASN1_OBJECT(obj_tmp, 80, algoid);
+ ERR_add_error_data(2, "TYPE=", obj_tmp);
+ goto error;
+ }
+
+ if (pkey->ameth->priv_decode) {
+ if (!pkey->ameth->priv_decode(pkey, p8)) {
+ OPENSSL_PUT_ERROR(PKCS8, EVP_PKCS82PKEY, PKCS8_R_PRIVATE_KEY_DECODE_ERROR);
+ goto error;
+ }
+ } else {
+ OPENSSL_PUT_ERROR(PKCS8, EVP_PKCS82PKEY, PKCS8_R_METHOD_NOT_SUPPORTED);
+ goto error;
+ }
+
+ return pkey;
+
+error:
+ EVP_PKEY_free(pkey);
+ return NULL;
+}
+
+PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey) {
+ PKCS8_PRIV_KEY_INFO *p8;
+
+ p8 = PKCS8_PRIV_KEY_INFO_new();
+ if (p8 == NULL) {
+ OPENSSL_PUT_ERROR(PKCS8, EVP_PKEY2PKCS8, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ p8->broken = PKCS8_OK;
+
+ 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);
+ goto error;
+ }
+ } else {
+ OPENSSL_PUT_ERROR(PKCS8, EVP_PKEY2PKCS8, PKCS8_R_METHOD_NOT_SUPPORTED);
+ goto error;
+ }
+ } else {
+ OPENSSL_PUT_ERROR(PKCS8, EVP_PKEY2PKCS8,
+ PKCS8_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM);
+ goto error;
+ }
+ return p8;
+
+error:
+ PKCS8_PRIV_KEY_INFO_free(p8);
+ return NULL;
+}
diff --git a/crypto/pkcs8/pkcs8.h b/crypto/pkcs8/pkcs8.h
new file mode 100644
index 0000000..9c4f60c
--- /dev/null
+++ b/crypto/pkcs8/pkcs8.h
@@ -0,0 +1,112 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999 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). */
+
+
+#ifndef OPENSSL_HEADER_PKCS8_H
+#define OPENSSL_HEADER_PKCS8_H
+
+#include <openssl/base.h>
+
+#include <openssl/x509.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+X509_SIG *PKCS8_encrypt(int pbe_nid, const EVP_CIPHER *cipher, const char *pass,
+ int pass_len, uint8_t *salt, size_t salt_len, int iterations,
+ PKCS8_PRIV_KEY_INFO *p8inf);
+
+PKCS8_PRIV_KEY_INFO *PKCS8_decrypt(X509_SIG *pkcs8, const char *pass,
+ int pass_len);
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#define PKCS8_F_PKCS8_encrypt 100
+#define PKCS8_F_EVP_PKEY2PKCS8 101
+#define PKCS8_F_EVP_PKCS82PKEY 102
+#define PKCS8_F_PKCS5_pbe_set0_algor 103
+#define PKCS8_F_pbe_crypt 104
+#define PKCS8_F_pkcs12_item_decrypt_d2i 105
+#define PKCS8_F_PKCS5_pbe_set 106
+#define PKCS8_F_pkcs12_key_gen_uni 107
+#define PKCS8_F_pkcs12_key_gen_asc 108
+#define PKCS8_F_pkcs12_pbe_keyivgen 109
+#define PKCS8_F_pbe_cipher_init 110
+#define PKCS8_F_pkcs12_item_i2d_encrypt 111
+#define PKCS8_F_PKCS5_pbe2_set_iv 112
+#define PKCS8_F_PKCS5_pbkdf2_set 113
+#define PKCS8_R_ERROR_SETTING_CIPHER_PARAMS 100
+#define PKCS8_R_PRIVATE_KEY_ENCODE_ERROR 101
+#define PKCS8_R_UNKNOWN_ALGORITHM 102
+#define PKCS8_R_UNKNOWN_CIPHER 103
+#define PKCS8_R_UNKNOWN_DIGEST 104
+#define PKCS8_R_ENCODE_ERROR 105
+#define PKCS8_R_DECODE_ERROR 106
+#define PKCS8_R_ENCRYPT_ERROR 107
+#define PKCS8_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM 108
+#define PKCS8_R_PRIVATE_KEY_DECODE_ERROR 109
+#define PKCS8_R_UNKNOWN_CIPHER_ALGORITHM 110
+#define PKCS8_R_KEYGEN_FAILURE 111
+#define PKCS8_R_TOO_LONG 112
+#define PKCS8_R_CRYPT_ERROR 113
+#define PKCS8_R_METHOD_NOT_SUPPORTED 114
+#define PKCS8_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER 115
+#define PKCS8_R_KEY_GEN_ERROR 116
+
+#endif /* OPENSSL_HEADER_PKCS8_H */
diff --git a/crypto/pkcs8/pkcs8_error.c b/crypto/pkcs8/pkcs8_error.c
new file mode 100644
index 0000000..02129f0
--- /dev/null
+++ b/crypto/pkcs8/pkcs8_error.c
@@ -0,0 +1,52 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/err.h>
+
+#include "pkcs8.h"
+
+const ERR_STRING_DATA PKCS8_error_string_data[] = {
+ {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_EVP_PKCS82PKEY, 0), "EVP_PKCS82PKEY"},
+ {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_EVP_PKEY2PKCS8, 0), "EVP_PKEY2PKCS8"},
+ {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_PKCS5_pbe2_set_iv, 0), "PKCS5_pbe2_set_iv"},
+ {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_PKCS5_pbe_set, 0), "PKCS5_pbe_set"},
+ {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_PKCS5_pbe_set0_algor, 0), "PKCS5_pbe_set0_algor"},
+ {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_PKCS5_pbkdf2_set, 0), "PKCS5_pbkdf2_set"},
+ {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_PKCS8_encrypt, 0), "PKCS8_encrypt"},
+ {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_pbe_cipher_init, 0), "pbe_cipher_init"},
+ {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_pbe_crypt, 0), "pbe_crypt"},
+ {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_pkcs12_item_decrypt_d2i, 0), "pkcs12_item_decrypt_d2i"},
+ {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_pkcs12_item_i2d_encrypt, 0), "pkcs12_item_i2d_encrypt"},
+ {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_pkcs12_key_gen_asc, 0), "pkcs12_key_gen_asc"},
+ {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_pkcs12_key_gen_uni, 0), "pkcs12_key_gen_uni"},
+ {ERR_PACK(ERR_LIB_PKCS8, PKCS8_F_pkcs12_pbe_keyivgen, 0), "pkcs12_pbe_keyivgen"},
+ {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER), "CIPHER_HAS_NO_OBJECT_IDENTIFIER"},
+ {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_CRYPT_ERROR), "CRYPT_ERROR"},
+ {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_DECODE_ERROR), "DECODE_ERROR"},
+ {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_ENCODE_ERROR), "ENCODE_ERROR"},
+ {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_ENCRYPT_ERROR), "ENCRYPT_ERROR"},
+ {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_ERROR_SETTING_CIPHER_PARAMS), "ERROR_SETTING_CIPHER_PARAMS"},
+ {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_KEYGEN_FAILURE), "KEYGEN_FAILURE"},
+ {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_KEY_GEN_ERROR), "KEY_GEN_ERROR"},
+ {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_METHOD_NOT_SUPPORTED), "METHOD_NOT_SUPPORTED"},
+ {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_PRIVATE_KEY_DECODE_ERROR), "PRIVATE_KEY_DECODE_ERROR"},
+ {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_PRIVATE_KEY_ENCODE_ERROR), "PRIVATE_KEY_ENCODE_ERROR"},
+ {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_TOO_LONG), "TOO_LONG"},
+ {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_UNKNOWN_ALGORITHM), "UNKNOWN_ALGORITHM"},
+ {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_UNKNOWN_CIPHER), "UNKNOWN_CIPHER"},
+ {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_UNKNOWN_CIPHER_ALGORITHM), "UNKNOWN_CIPHER_ALGORITHM"},
+ {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_UNKNOWN_DIGEST), "UNKNOWN_DIGEST"},
+ {ERR_PACK(ERR_LIB_PKCS8, 0, PKCS8_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM), "UNSUPPORTED_PRIVATE_KEY_ALGORITHM"},
+ {0, NULL},
+};
diff --git a/crypto/rand/CMakeLists.txt b/crypto/rand/CMakeLists.txt
new file mode 100644
index 0000000..eb24613
--- /dev/null
+++ b/crypto/rand/CMakeLists.txt
@@ -0,0 +1,11 @@
+include_directories(. .. ../../include)
+
+add_library(
+ rand
+
+ OBJECT
+
+ rand.c
+ urandom.c
+ windows.c
+)
diff --git a/crypto/rand/rand.c b/crypto/rand/rand.c
new file mode 100644
index 0000000..6780b6c
--- /dev/null
+++ b/crypto/rand/rand.c
@@ -0,0 +1,28 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/rand.h>
+
+
+int RAND_pseudo_bytes(uint8_t *buf, size_t len) {
+ return RAND_bytes(buf, len);
+}
+
+void RAND_seed(const void *buf, int num) {}
+
+void RAND_add(const void *buf, int num, double entropy) {}
+
+int RAND_poll(void) {
+ return 1;
+}
diff --git a/crypto/rand/rand.h b/crypto/rand/rand.h
new file mode 100644
index 0000000..62e1037
--- /dev/null
+++ b/crypto/rand/rand.h
@@ -0,0 +1,53 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#ifndef OPENSSL_HEADER_RAND_H
+#define OPENSSL_HEADER_RAND_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* RAND_bytes writes |len| bytes of random data to |buf|. It returns one on
+ * success and zero on otherwise. */
+int RAND_bytes(uint8_t *buf, size_t len);
+
+/* RAND_cleanup frees any resources used by the RNG. This is not safe if other
+ * threads might still be calling |RAND_bytes|. */
+void RAND_cleanup();
+
+
+/* Deprecated functions */
+
+/* RAND_pseudo_bytes is a wrapper around |RAND_bytes|. */
+int RAND_pseudo_bytes(uint8_t *buf, size_t len);
+
+/* RAND_seed does nothing. */
+void RAND_seed(const void *buf, int num);
+
+/* RAND_add does nothing. */
+void RAND_add(const void *buf, int num, double entropy);
+
+/* RAND_poll returns one. */
+int RAND_poll(void);
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_RAND_H */
diff --git a/crypto/rand/urandom.c b/crypto/rand/urandom.c
new file mode 100644
index 0000000..44fe1d6
--- /dev/null
+++ b/crypto/rand/urandom.c
@@ -0,0 +1,241 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/rand.h>
+
+#if !defined(OPENSSL_WINDOWS)
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <openssl/thread.h>
+#include <openssl/mem.h>
+
+
+/* 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.
+ */
+
+/* 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)
+
+/* rand_buffer contains unused, random bytes. These structures form a linked
+ * list via the |next| pointer, which is NULL in the final element. */
+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[];
+};
+
+/* 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);
+
+/* list_head is the start of a global, linked-list of rand_buffer objects. It's
+ * protected by CRYPTO_LOCK_RAND. */
+static struct rand_buffer *list_head;
+
+/* urandom_fd is a file descriptor to /dev/urandom. It's protected by
+ * CRYPTO_LOCK_RAND. */
+static int urandom_fd = -2;
+
+/* urandom_buffering controls whether buffering is enabled (1) or not (0). This
+ * is protected by CRYPTO_LOCK_RAND. */
+static int urandom_buffering = 0;
+
+/* urandom_get_fd_locked returns a file descriptor to /dev/urandom. The caller
+ * of this function must hold CRYPTO_LOCK_RAND. */
+static int urandom_get_fd_locked() {
+ if (urandom_fd != -2)
+ return urandom_fd;
+
+ urandom_fd = open("/dev/urandom", O_RDONLY | O_NOCTTY);
+ return urandom_fd;
+}
+
+/* RAND_cleanup frees all buffers, closes any cached file descriptor
+ * and resets the global state. */
+void RAND_cleanup(void) {
+ struct rand_buffer *cur;
+
+ CRYPTO_w_lock(CRYPTO_LOCK_RAND);
+ while ((cur = list_head)) {
+ list_head = cur->next;
+ OPENSSL_free(cur);
+ }
+ if (urandom_fd >= 0) {
+ close(urandom_fd);
+ }
+ urandom_fd = -2;
+ list_head = NULL;
+ CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
+}
+
+/* read_full reads exactly |len| bytes from |fd| into |out| and returns 1. In
+ * the case of an error it returns 0. */
+static char read_full(int fd, uint8_t *out, size_t len) {
+ ssize_t r;
+
+ while (len > 0) {
+ do {
+ r = read(fd, out, len);
+ } while (r == -1 && errno == EINTR);
+
+ if (r <= 0) {
+ return 0;
+ }
+ out += r;
+ len -= r;
+ }
+
+ return 1;
+}
+
+/* urandom_rand_pseudo_bytes puts |num| random bytes into |out|. It returns
+ * one on success and zero otherwise. */
+int RAND_bytes(uint8_t *out, size_t requested) {
+ int fd;
+ struct rand_buffer *buf;
+ size_t todo;
+ pid_t pid, ppid;
+
+ if (requested == 0) {
+ return 1;
+ }
+
+ CRYPTO_w_lock(CRYPTO_LOCK_RAND);
+ fd = urandom_get_fd_locked();
+
+ if (fd < 0) {
+ CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
+ abort();
+ return 0;
+ }
+
+ /* 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_w_unlock(CRYPTO_LOCK_RAND);
+ if (!read_full(fd, out, requested)) {
+ abort();
+ return 0;
+ }
+ return 1;
+ }
+
+ 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_w_unlock(CRYPTO_LOCK_RAND);
+ return 1;
+ }
+
+ /* 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_w_unlock(CRYPTO_LOCK_RAND);
+
+ if (!buf) {
+ buf = (struct rand_buffer *)OPENSSL_malloc(BUF_SIZE);
+ /* 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_w_lock(CRYPTO_LOCK_RAND);
+ }
+
+ 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 0;
+ }
+
+ buf->used = 0;
+ }
+
+ CRYPTO_w_lock(CRYPTO_LOCK_RAND);
+ assert(list_head != buf);
+ buf->next = list_head;
+ list_head = buf;
+ CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
+ return 1;
+}
+
+#endif /* !OPENSSL_WINDOWS */
diff --git a/crypto/rand/windows.c b/crypto/rand/windows.c
new file mode 100644
index 0000000..967dd9b
--- /dev/null
+++ b/crypto/rand/windows.c
@@ -0,0 +1,71 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/rand.h>
+
+#include <openssl/thread.h>
+
+
+#if defined(OPENSSL_WINDOWS)
+
+#include <stdlib.h>
+#include <Windows.h>
+#include <Wincrypt.h>
+
+static char global_provider_init;
+static HCRYPTPROV global_provider;
+
+void RAND_cleanup(void) {
+ CRYPTO_w_lock(CRYPTO_LOCK_RAND);
+ CryptReleaseContext(global_provider, 0);
+ global_provider_init = 0;
+ CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
+}
+
+int RAND_bytes(uint8_t *out, size_t requested) {
+ HCRYPTPROV provider = 0;
+ int ok;
+
+ CRYPTO_r_lock(CRYPTO_LOCK_RAND);
+ if (!global_provider_init) {
+ CRYPTO_r_unlock(CRYPTO_LOCK_RAND);
+ CRYPTO_w_lock(CRYPTO_LOCK_RAND);
+ if (!global_provider_init) {
+ if (CryptAcquireContext(&global_provider, NULL, NULL, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
+ global_provider_init = 1;
+ }
+ }
+ CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
+ CRYPTO_r_lock(CRYPTO_LOCK_RAND);
+ }
+
+ ok = global_provider_init;
+ provider = global_provider;
+ CRYPTO_r_unlock(CRYPTO_LOCK_RAND);
+
+ if (!ok) {
+ abort();
+ return ok;
+ }
+
+ if (TRUE != CryptGenRandom(provider, requested, out)) {
+ abort();
+ return 0;
+ }
+
+ return 1;
+}
+
+#endif /* OPENSSL_WINDOWS */
diff --git a/crypto/rc4/CMakeLists.txt b/crypto/rc4/CMakeLists.txt
new file mode 100644
index 0000000..0072832
--- /dev/null
+++ b/crypto/rc4/CMakeLists.txt
@@ -0,0 +1,29 @@
+include_directories(. .. ../../include)
+
+if (${ARCH} STREQUAL "x86_64")
+ set(
+ RC4_ARCH_SOURCES
+
+ rc4-x86_64.${ASM_EXT}
+ )
+endif()
+
+if (${ARCH} STREQUAL "x86")
+ set(
+ RC4_ARCH_SOURCES
+
+ rc4-586.${ASM_EXT}
+ )
+endif()
+
+add_library(
+ rc4
+
+ OBJECT
+
+ rc4.c
+ ${RC4_ARCH_SOURCES}
+)
+
+perlasm(rc4-x86_64.${ASM_EXT} asm/rc4-x86_64.pl)
+perlasm(rc4-586.${ASM_EXT} asm/rc4-586.pl)
diff --git a/crypto/rc4/asm/rc4-586.pl b/crypto/rc4/asm/rc4-586.pl
new file mode 100644
index 0000000..84f1a79
--- /dev/null
+++ b/crypto/rc4/asm/rc4-586.pl
@@ -0,0 +1,410 @@
+#!/usr/bin/env perl
+
+# ====================================================================
+# [Re]written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+
+# At some point it became apparent that the original SSLeay RC4
+# assembler implementation performs suboptimally on latest IA-32
+# microarchitectures. After re-tuning performance has changed as
+# following:
+#
+# Pentium -10%
+# Pentium III +12%
+# AMD +50%(*)
+# P4 +250%(**)
+#
+# (*) This number is actually a trade-off:-) It's possible to
+# achieve +72%, but at the cost of -48% off PIII performance.
+# In other words code performing further 13% faster on AMD
+# would perform almost 2 times slower on Intel PIII...
+# For reference! This code delivers ~80% of rc4-amd64.pl
+# performance on the same Opteron machine.
+# (**) This number requires compressed key schedule set up by
+# RC4_set_key [see commentary below for further details].
+#
+# <appro@fy.chalmers.se>
+
+# May 2011
+#
+# Optimize for Core2 and Westmere [and incidentally Opteron]. Current
+# performance in cycles per processed byte (less is better) and
+# improvement relative to previous version of this module is:
+#
+# Pentium 10.2 # original numbers
+# Pentium III 7.8(*)
+# Intel P4 7.5
+#
+# Opteron 6.1/+20% # new MMX numbers
+# Core2 5.3/+67%(**)
+# Westmere 5.1/+94%(**)
+# Sandy Bridge 5.0/+8%
+# Atom 12.6/+6%
+#
+# (*) PIII can actually deliver 6.6 cycles per byte with MMX code,
+# but this specific code performs poorly on Core2. And vice
+# versa, below MMX/SSE code delivering 5.8/7.1 on Core2 performs
+# poorly on PIII, at 8.0/14.5:-( As PIII is not a "hot" CPU
+# [anymore], I chose to discard PIII-specific code path and opt
+# for original IALU-only code, which is why MMX/SSE code path
+# is guarded by SSE2 bit (see below), not MMX/SSE.
+# (**) Performance vs. block size on Core2 and Westmere had a maximum
+# at ... 64 bytes block size. And it was quite a maximum, 40-60%
+# in comparison to largest 8KB block size. Above improvement
+# coefficients are for the largest block size.
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+push(@INC,"${dir}","${dir}../../perlasm");
+require "x86asm.pl";
+
+&asm_init($ARGV[0],"rc4-586.pl");
+
+$xx="eax";
+$yy="ebx";
+$tx="ecx";
+$ty="edx";
+$inp="esi";
+$out="ebp";
+$dat="edi";
+
+sub RC4_loop {
+ my $i=shift;
+ my $func = ($i==0)?*mov:*or;
+
+ &add (&LB($yy),&LB($tx));
+ &mov ($ty,&DWP(0,$dat,$yy,4));
+ &mov (&DWP(0,$dat,$yy,4),$tx);
+ &mov (&DWP(0,$dat,$xx,4),$ty);
+ &add ($ty,$tx);
+ &inc (&LB($xx));
+ &and ($ty,0xff);
+ &ror ($out,8) if ($i!=0);
+ if ($i<3) {
+ &mov ($tx,&DWP(0,$dat,$xx,4));
+ } else {
+ &mov ($tx,&wparam(3)); # reload [re-biased] out
+ }
+ &$func ($out,&DWP(0,$dat,$ty,4));
+}
+
+if ($alt=0) {
+ # >20% faster on Atom and Sandy Bridge[!], 8% faster on Opteron,
+ # but ~40% slower on Core2 and Westmere... Attempt to add movz
+ # brings down Opteron by 25%, Atom and Sandy Bridge by 15%, yet
+ # on Core2 with movz it's almost 20% slower than below alternative
+ # code... Yes, it's a total mess...
+ my @XX=($xx,$out);
+ $RC4_loop_mmx = sub { # SSE actually...
+ my $i=shift;
+ my $j=$i<=0?0:$i>>1;
+ my $mm=$i<=0?"mm0":"mm".($i&1);
+
+ &add (&LB($yy),&LB($tx));
+ &lea (@XX[1],&DWP(1,@XX[0]));
+ &pxor ("mm2","mm0") if ($i==0);
+ &psllq ("mm1",8) if ($i==0);
+ &and (@XX[1],0xff);
+ &pxor ("mm0","mm0") if ($i<=0);
+ &mov ($ty,&DWP(0,$dat,$yy,4));
+ &mov (&DWP(0,$dat,$yy,4),$tx);
+ &pxor ("mm1","mm2") if ($i==0);
+ &mov (&DWP(0,$dat,$XX[0],4),$ty);
+ &add (&LB($ty),&LB($tx));
+ &movd (@XX[0],"mm7") if ($i==0);
+ &mov ($tx,&DWP(0,$dat,@XX[1],4));
+ &pxor ("mm1","mm1") if ($i==1);
+ &movq ("mm2",&QWP(0,$inp)) if ($i==1);
+ &movq (&QWP(-8,(@XX[0],$inp)),"mm1") if ($i==0);
+ &pinsrw ($mm,&DWP(0,$dat,$ty,4),$j);
+
+ push (@XX,shift(@XX)) if ($i>=0);
+ }
+} else {
+ # Using pinsrw here improves performane on Intel CPUs by 2-3%, but
+ # brings down AMD by 7%...
+ $RC4_loop_mmx = sub {
+ my $i=shift;
+
+ &add (&LB($yy),&LB($tx));
+ &psllq ("mm1",8*(($i-1)&7)) if (abs($i)!=1);
+ &mov ($ty,&DWP(0,$dat,$yy,4));
+ &mov (&DWP(0,$dat,$yy,4),$tx);
+ &mov (&DWP(0,$dat,$xx,4),$ty);
+ &inc ($xx);
+ &add ($ty,$tx);
+ &movz ($xx,&LB($xx)); # (*)
+ &movz ($ty,&LB($ty)); # (*)
+ &pxor ("mm2",$i==1?"mm0":"mm1") if ($i>=0);
+ &movq ("mm0",&QWP(0,$inp)) if ($i<=0);
+ &movq (&QWP(-8,($out,$inp)),"mm2") if ($i==0);
+ &mov ($tx,&DWP(0,$dat,$xx,4));
+ &movd ($i>0?"mm1":"mm2",&DWP(0,$dat,$ty,4));
+
+ # (*) This is the key to Core2 and Westmere performance.
+ # Whithout movz out-of-order execution logic confuses
+ # itself and fails to reorder loads and stores. Problem
+ # appears to be fixed in Sandy Bridge...
+ }
+}
+
+&external_label("OPENSSL_ia32cap_P");
+
+# void RC4(RC4_KEY *key,size_t len,const unsigned char *inp,unsigned char *out);
+&function_begin("RC4");
+ &mov ($dat,&wparam(0)); # load key schedule pointer
+ &mov ($ty, &wparam(1)); # load len
+ &mov ($inp,&wparam(2)); # load inp
+ &mov ($out,&wparam(3)); # load out
+
+ &xor ($xx,$xx); # avoid partial register stalls
+ &xor ($yy,$yy);
+
+ &cmp ($ty,0); # safety net
+ &je (&label("abort"));
+
+ &mov (&LB($xx),&BP(0,$dat)); # load key->x
+ &mov (&LB($yy),&BP(4,$dat)); # load key->y
+ &add ($dat,8);
+
+ &lea ($tx,&DWP(0,$inp,$ty));
+ &sub ($out,$inp); # re-bias out
+ &mov (&wparam(1),$tx); # save input+len
+
+ &inc (&LB($xx));
+
+ # detect compressed key schedule...
+ &cmp (&DWP(256,$dat),-1);
+ &je (&label("RC4_CHAR"));
+
+ &mov ($tx,&DWP(0,$dat,$xx,4));
+
+ &and ($ty,-4); # how many 4-byte chunks?
+ &jz (&label("loop1"));
+
+ &test ($ty,-8);
+ &mov (&wparam(3),$out); # $out as accumulator in these loops
+ &jz (&label("go4loop4"));
+
+ &picmeup($out,"OPENSSL_ia32cap_P");
+ &bt (&DWP(0,$out),26); # check SSE2 bit [could have been MMX]
+ &jnc (&label("go4loop4"));
+
+ &mov ($out,&wparam(3)) if (!$alt);
+ &movd ("mm7",&wparam(3)) if ($alt);
+ &and ($ty,-8);
+ &lea ($ty,&DWP(-8,$inp,$ty));
+ &mov (&DWP(-4,$dat),$ty); # save input+(len/8)*8-8
+
+ &$RC4_loop_mmx(-1);
+ &jmp(&label("loop_mmx_enter"));
+
+ &set_label("loop_mmx",16);
+ &$RC4_loop_mmx(0);
+ &set_label("loop_mmx_enter");
+ for ($i=1;$i<8;$i++) { &$RC4_loop_mmx($i); }
+ &mov ($ty,$yy);
+ &xor ($yy,$yy); # this is second key to Core2
+ &mov (&LB($yy),&LB($ty)); # and Westmere performance...
+ &cmp ($inp,&DWP(-4,$dat));
+ &lea ($inp,&DWP(8,$inp));
+ &jb (&label("loop_mmx"));
+
+ if ($alt) {
+ &movd ($out,"mm7");
+ &pxor ("mm2","mm0");
+ &psllq ("mm1",8);
+ &pxor ("mm1","mm2");
+ &movq (&QWP(-8,$out,$inp),"mm1");
+ } else {
+ &psllq ("mm1",56);
+ &pxor ("mm2","mm1");
+ &movq (&QWP(-8,$out,$inp),"mm2");
+ }
+ &emms ();
+
+ &cmp ($inp,&wparam(1)); # compare to input+len
+ &je (&label("done"));
+ &jmp (&label("loop1"));
+
+&set_label("go4loop4",16);
+ &lea ($ty,&DWP(-4,$inp,$ty));
+ &mov (&wparam(2),$ty); # save input+(len/4)*4-4
+
+ &set_label("loop4");
+ for ($i=0;$i<4;$i++) { RC4_loop($i); }
+ &ror ($out,8);
+ &xor ($out,&DWP(0,$inp));
+ &cmp ($inp,&wparam(2)); # compare to input+(len/4)*4-4
+ &mov (&DWP(0,$tx,$inp),$out);# $tx holds re-biased out here
+ &lea ($inp,&DWP(4,$inp));
+ &mov ($tx,&DWP(0,$dat,$xx,4));
+ &jb (&label("loop4"));
+
+ &cmp ($inp,&wparam(1)); # compare to input+len
+ &je (&label("done"));
+ &mov ($out,&wparam(3)); # restore $out
+
+ &set_label("loop1",16);
+ &add (&LB($yy),&LB($tx));
+ &mov ($ty,&DWP(0,$dat,$yy,4));
+ &mov (&DWP(0,$dat,$yy,4),$tx);
+ &mov (&DWP(0,$dat,$xx,4),$ty);
+ &add ($ty,$tx);
+ &inc (&LB($xx));
+ &and ($ty,0xff);
+ &mov ($ty,&DWP(0,$dat,$ty,4));
+ &xor (&LB($ty),&BP(0,$inp));
+ &lea ($inp,&DWP(1,$inp));
+ &mov ($tx,&DWP(0,$dat,$xx,4));
+ &cmp ($inp,&wparam(1)); # compare to input+len
+ &mov (&BP(-1,$out,$inp),&LB($ty));
+ &jb (&label("loop1"));
+
+ &jmp (&label("done"));
+
+# this is essentially Intel P4 specific codepath...
+&set_label("RC4_CHAR",16);
+ &movz ($tx,&BP(0,$dat,$xx));
+ # strangely enough unrolled loop performs over 20% slower...
+ &set_label("cloop1");
+ &add (&LB($yy),&LB($tx));
+ &movz ($ty,&BP(0,$dat,$yy));
+ &mov (&BP(0,$dat,$yy),&LB($tx));
+ &mov (&BP(0,$dat,$xx),&LB($ty));
+ &add (&LB($ty),&LB($tx));
+ &movz ($ty,&BP(0,$dat,$ty));
+ &add (&LB($xx),1);
+ &xor (&LB($ty),&BP(0,$inp));
+ &lea ($inp,&DWP(1,$inp));
+ &movz ($tx,&BP(0,$dat,$xx));
+ &cmp ($inp,&wparam(1));
+ &mov (&BP(-1,$out,$inp),&LB($ty));
+ &jb (&label("cloop1"));
+
+&set_label("done");
+ &dec (&LB($xx));
+ &mov (&DWP(-4,$dat),$yy); # save key->y
+ &mov (&BP(-8,$dat),&LB($xx)); # save key->x
+&set_label("abort");
+&function_end("RC4");
+
+########################################################################
+
+$inp="esi";
+$out="edi";
+$idi="ebp";
+$ido="ecx";
+$idx="edx";
+
+# void RC4_set_key(RC4_KEY *key,int len,const unsigned char *data);
+&function_begin("RC4_set_key");
+ &mov ($out,&wparam(0)); # load key
+ &mov ($idi,&wparam(1)); # load len
+ &mov ($inp,&wparam(2)); # load data
+ &picmeup($idx,"OPENSSL_ia32cap_P");
+
+ &lea ($out,&DWP(2*4,$out)); # &key->data
+ &lea ($inp,&DWP(0,$inp,$idi)); # $inp to point at the end
+ &neg ($idi);
+ &xor ("eax","eax");
+ &mov (&DWP(-4,$out),$idi); # borrow key->y
+
+ &bt (&DWP(0,$idx),20); # check for bit#20
+ &jc (&label("c1stloop"));
+
+&set_label("w1stloop",16);
+ &mov (&DWP(0,$out,"eax",4),"eax"); # key->data[i]=i;
+ &add (&LB("eax"),1); # i++;
+ &jnc (&label("w1stloop"));
+
+ &xor ($ido,$ido);
+ &xor ($idx,$idx);
+
+&set_label("w2ndloop",16);
+ &mov ("eax",&DWP(0,$out,$ido,4));
+ &add (&LB($idx),&BP(0,$inp,$idi));
+ &add (&LB($idx),&LB("eax"));
+ &add ($idi,1);
+ &mov ("ebx",&DWP(0,$out,$idx,4));
+ &jnz (&label("wnowrap"));
+ &mov ($idi,&DWP(-4,$out));
+ &set_label("wnowrap");
+ &mov (&DWP(0,$out,$idx,4),"eax");
+ &mov (&DWP(0,$out,$ido,4),"ebx");
+ &add (&LB($ido),1);
+ &jnc (&label("w2ndloop"));
+&jmp (&label("exit"));
+
+# Unlike all other x86 [and x86_64] implementations, Intel P4 core
+# [including EM64T] was found to perform poorly with above "32-bit" key
+# schedule, a.k.a. RC4_INT. Performance improvement for IA-32 hand-coded
+# assembler turned out to be 3.5x if re-coded for compressed 8-bit one,
+# a.k.a. RC4_CHAR! It's however inappropriate to just switch to 8-bit
+# schedule for x86[_64], because non-P4 implementations suffer from
+# significant performance losses then, e.g. PIII exhibits >2x
+# deterioration, and so does Opteron. In order to assure optimal
+# all-round performance, we detect P4 at run-time and set up compressed
+# key schedule, which is recognized by RC4 procedure.
+
+&set_label("c1stloop",16);
+ &mov (&BP(0,$out,"eax"),&LB("eax")); # key->data[i]=i;
+ &add (&LB("eax"),1); # i++;
+ &jnc (&label("c1stloop"));
+
+ &xor ($ido,$ido);
+ &xor ($idx,$idx);
+ &xor ("ebx","ebx");
+
+&set_label("c2ndloop",16);
+ &mov (&LB("eax"),&BP(0,$out,$ido));
+ &add (&LB($idx),&BP(0,$inp,$idi));
+ &add (&LB($idx),&LB("eax"));
+ &add ($idi,1);
+ &mov (&LB("ebx"),&BP(0,$out,$idx));
+ &jnz (&label("cnowrap"));
+ &mov ($idi,&DWP(-4,$out));
+ &set_label("cnowrap");
+ &mov (&BP(0,$out,$idx),&LB("eax"));
+ &mov (&BP(0,$out,$ido),&LB("ebx"));
+ &add (&LB($ido),1);
+ &jnc (&label("c2ndloop"));
+
+ &mov (&DWP(256,$out),-1); # mark schedule as compressed
+
+&set_label("exit");
+ &xor ("eax","eax");
+ &mov (&DWP(-8,$out),"eax"); # key->x=0;
+ &mov (&DWP(-4,$out),"eax"); # key->y=0;
+&function_end("RC4_set_key");
+
+# const char *RC4_options(void);
+&function_begin_B("RC4_options");
+ &call (&label("pic_point"));
+&set_label("pic_point");
+ &blindpop("eax");
+ &lea ("eax",&DWP(&label("opts")."-".&label("pic_point"),"eax"));
+ &picmeup("edx","OPENSSL_ia32cap_P");
+ &mov ("edx",&DWP(0,"edx"));
+ &bt ("edx",20);
+ &jc (&label("1xchar"));
+ &bt ("edx",26);
+ &jnc (&label("ret"));
+ &add ("eax",25);
+ &ret ();
+&set_label("1xchar");
+ &add ("eax",12);
+&set_label("ret");
+ &ret ();
+&set_label("opts",64);
+&asciz ("rc4(4x,int)");
+&asciz ("rc4(1x,char)");
+&asciz ("rc4(8x,mmx)");
+&asciz ("RC4 for x86, CRYPTOGAMS by <appro\@openssl.org>");
+&align (64);
+&function_end_B("RC4_options");
+
+&asm_finish();
+
diff --git a/crypto/rc4/asm/rc4-x86_64.pl b/crypto/rc4/asm/rc4-x86_64.pl
new file mode 100644
index 0000000..c7da8fa
--- /dev/null
+++ b/crypto/rc4/asm/rc4-x86_64.pl
@@ -0,0 +1,677 @@
+#!/usr/bin/env perl
+#
+# ====================================================================
+# Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+#
+# July 2004
+#
+# 2.22x RC4 tune-up:-) It should be noted though that my hand [as in
+# "hand-coded assembler"] doesn't stand for the whole improvement
+# coefficient. It turned out that eliminating RC4_CHAR from config
+# line results in ~40% improvement (yes, even for C implementation).
+# Presumably it has everything to do with AMD cache architecture and
+# RAW or whatever penalties. Once again! The module *requires* config
+# line *without* RC4_CHAR! As for coding "secret," I bet on partial
+# register arithmetics. For example instead of 'inc %r8; and $255,%r8'
+# I simply 'inc %r8b'. Even though optimization manual discourages
+# to operate on partial registers, it turned out to be the best bet.
+# At least for AMD... How IA32E would perform remains to be seen...
+
+# November 2004
+#
+# As was shown by Marc Bevand reordering of couple of load operations
+# results in even higher performance gain of 3.3x:-) At least on
+# Opteron... For reference, 1x in this case is RC4_CHAR C-code
+# compiled with gcc 3.3.2, which performs at ~54MBps per 1GHz clock.
+# Latter means that if you want to *estimate* what to expect from
+# *your* Opteron, then multiply 54 by 3.3 and clock frequency in GHz.
+
+# November 2004
+#
+# Intel P4 EM64T core was found to run the AMD64 code really slow...
+# The only way to achieve comparable performance on P4 was to keep
+# RC4_CHAR. Kind of ironic, huh? As it's apparently impossible to
+# compose blended code, which would perform even within 30% marginal
+# on either AMD and Intel platforms, I implement both cases. See
+# rc4_skey.c for further details...
+
+# April 2005
+#
+# P4 EM64T core appears to be "allergic" to 64-bit inc/dec. Replacing
+# those with add/sub results in 50% performance improvement of folded
+# loop...
+
+# May 2005
+#
+# As was shown by Zou Nanhai loop unrolling can improve Intel EM64T
+# performance by >30% [unlike P4 32-bit case that is]. But this is
+# provided that loads are reordered even more aggressively! Both code
+# pathes, AMD64 and EM64T, reorder loads in essentially same manner
+# as my IA-64 implementation. On Opteron this resulted in modest 5%
+# improvement [I had to test it], while final Intel P4 performance
+# 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
+# is not implemented, then this final RC4_CHAR code-path should be
+# preferred, as it provides better *all-round* performance].
+
+# March 2007
+#
+# Intel Core2 was observed to perform poorly on both code paths:-( It
+# apparently suffers from some kind of partial register stall, which
+# occurs in 64-bit mode only [as virtually identical 32-bit loop was
+# observed to outperform 64-bit one by almost 50%]. Adding two movzb to
+# cloop1 boosts its performance by 80%! This loop appears to be optimal
+# fit for Core2 and therefore the code was modified to skip cloop8 on
+# this CPU.
+
+# May 2010
+#
+# Intel Westmere was observed to perform suboptimally. Adding yet
+# another movzb to cloop1 improved performance by almost 50%! Core2
+# performance is improved too, but nominally...
+
+# May 2011
+#
+# The only code path that was not modified is P4-specific one. Non-P4
+# Intel code path optimization is heavily based on submission by Maxim
+# Perminov, Maxim Locktyukhin and Jim Guilford of Intel. I've used
+# some of the ideas even in attempt to optmize the original RC4_INT
+# code path... Current performance in cycles per processed byte (less
+# is better) and improvement coefficients relative to previous
+# version of this module are:
+#
+# Opteron 5.3/+0%(*)
+# P4 6.5
+# Core2 6.2/+15%(**)
+# Westmere 4.2/+60%
+# Sandy Bridge 4.2/+120%
+# Atom 9.3/+80%
+#
+# (*) But corresponding loop has less instructions, which should have
+# positive effect on upcoming Bulldozer, which has one less ALU.
+# For reference, Intel code runs at 6.8 cpb rate on Opteron.
+# (**) Note that Core2 result is ~15% lower than corresponding result
+# for 32-bit code, meaning that it's possible to improve it,
+# but more than likely at the cost of the others (see rc4-586.pl
+# to get the idea)...
+
+$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;
+
+$dat="%rdi"; # arg1
+$len="%rsi"; # arg2
+$inp="%rdx"; # arg3
+$out="%rcx"; # arg4
+
+{
+$code=<<___;
+.text
+.extern OPENSSL_ia32cap_P
+
+.globl RC4
+.type RC4,\@function,4
+.align 16
+RC4: or $len,$len
+ jne .Lentry
+ ret
+.Lentry:
+ push %rbx
+ push %r12
+ push %r13
+.Lprologue:
+ mov $len,%r11
+ mov $inp,%r12
+ mov $out,%r13
+___
+my $len="%r11"; # reassign input arguments
+my $inp="%r12";
+my $out="%r13";
+
+my @XX=("%r10","%rsi");
+my @TX=("%rax","%rbx");
+my $YY="%rcx";
+my $TY="%rdx";
+
+$code.=<<___;
+ xor $XX[0],$XX[0]
+ xor $YY,$YY
+
+ lea 8($dat),$dat
+ mov -8($dat),$XX[0]#b
+ mov -4($dat),$YY#b
+ cmpl \$-1,256($dat)
+ je .LRC4_CHAR
+ mov OPENSSL_ia32cap_P(%rip),%r8d
+ xor $TX[1],$TX[1]
+ inc $XX[0]#b
+ sub $XX[0],$TX[1]
+ sub $inp,$out
+ movl ($dat,$XX[0],4),$TX[0]#d
+ test \$-16,$len
+ jz .Lloop1
+ bt \$30,%r8d # Intel CPU?
+ jc .Lintel
+ and \$7,$TX[1]
+ lea 1($XX[0]),$XX[1]
+ jz .Loop8
+ sub $TX[1],$len
+.Loop8_warmup:
+ add $TX[0]#b,$YY#b
+ movl ($dat,$YY,4),$TY#d
+ movl $TX[0]#d,($dat,$YY,4)
+ movl $TY#d,($dat,$XX[0],4)
+ add $TY#b,$TX[0]#b
+ inc $XX[0]#b
+ movl ($dat,$TX[0],4),$TY#d
+ movl ($dat,$XX[0],4),$TX[0]#d
+ xorb ($inp),$TY#b
+ movb $TY#b,($out,$inp)
+ lea 1($inp),$inp
+ dec $TX[1]
+ jnz .Loop8_warmup
+
+ lea 1($XX[0]),$XX[1]
+ jmp .Loop8
+.align 16
+.Loop8:
+___
+for ($i=0;$i<8;$i++) {
+$code.=<<___ if ($i==7);
+ add \$8,$XX[1]#b
+___
+$code.=<<___;
+ add $TX[0]#b,$YY#b
+ movl ($dat,$YY,4),$TY#d
+ movl $TX[0]#d,($dat,$YY,4)
+ movl `4*($i==7?-1:$i)`($dat,$XX[1],4),$TX[1]#d
+ ror \$8,%r8 # ror is redundant when $i=0
+ movl $TY#d,4*$i($dat,$XX[0],4)
+ add $TX[0]#b,$TY#b
+ movb ($dat,$TY,4),%r8b
+___
+push(@TX,shift(@TX)); #push(@XX,shift(@XX)); # "rotate" registers
+}
+$code.=<<___;
+ add \$8,$XX[0]#b
+ ror \$8,%r8
+ sub \$8,$len
+
+ xor ($inp),%r8
+ mov %r8,($out,$inp)
+ lea 8($inp),$inp
+
+ test \$-8,$len
+ jnz .Loop8
+ cmp \$0,$len
+ jne .Lloop1
+ jmp .Lexit
+
+.align 16
+.Lintel:
+ test \$-32,$len
+ jz .Lloop1
+ and \$15,$TX[1]
+ jz .Loop16_is_hot
+ sub $TX[1],$len
+.Loop16_warmup:
+ add $TX[0]#b,$YY#b
+ movl ($dat,$YY,4),$TY#d
+ movl $TX[0]#d,($dat,$YY,4)
+ movl $TY#d,($dat,$XX[0],4)
+ add $TY#b,$TX[0]#b
+ inc $XX[0]#b
+ movl ($dat,$TX[0],4),$TY#d
+ movl ($dat,$XX[0],4),$TX[0]#d
+ xorb ($inp),$TY#b
+ movb $TY#b,($out,$inp)
+ lea 1($inp),$inp
+ dec $TX[1]
+ jnz .Loop16_warmup
+
+ mov $YY,$TX[1]
+ xor $YY,$YY
+ mov $TX[1]#b,$YY#b
+
+.Loop16_is_hot:
+ lea ($dat,$XX[0],4),$XX[1]
+___
+sub RC4_loop {
+ my $i=shift;
+ my $j=$i<0?0:$i;
+ my $xmm="%xmm".($j&1);
+
+ $code.=" add \$16,$XX[0]#b\n" if ($i==15);
+ $code.=" movdqu ($inp),%xmm2\n" if ($i==15);
+ $code.=" add $TX[0]#b,$YY#b\n" if ($i<=0);
+ $code.=" movl ($dat,$YY,4),$TY#d\n";
+ $code.=" pxor %xmm0,%xmm2\n" if ($i==0);
+ $code.=" psllq \$8,%xmm1\n" if ($i==0);
+ $code.=" pxor $xmm,$xmm\n" if ($i<=1);
+ $code.=" movl $TX[0]#d,($dat,$YY,4)\n";
+ $code.=" add $TY#b,$TX[0]#b\n";
+ $code.=" movl `4*($j+1)`($XX[1]),$TX[1]#d\n" if ($i<15);
+ $code.=" movz $TX[0]#b,$TX[0]#d\n";
+ $code.=" movl $TY#d,4*$j($XX[1])\n";
+ $code.=" pxor %xmm1,%xmm2\n" if ($i==0);
+ $code.=" lea ($dat,$XX[0],4),$XX[1]\n" if ($i==15);
+ $code.=" add $TX[1]#b,$YY#b\n" if ($i<15);
+ $code.=" pinsrw \$`($j>>1)&7`,($dat,$TX[0],4),$xmm\n";
+ $code.=" movdqu %xmm2,($out,$inp)\n" if ($i==0);
+ $code.=" lea 16($inp),$inp\n" if ($i==0);
+ $code.=" movl ($XX[1]),$TX[1]#d\n" if ($i==15);
+}
+ RC4_loop(-1);
+$code.=<<___;
+ jmp .Loop16_enter
+.align 16
+.Loop16:
+___
+
+for ($i=0;$i<16;$i++) {
+ $code.=".Loop16_enter:\n" if ($i==1);
+ RC4_loop($i);
+ push(@TX,shift(@TX)); # "rotate" registers
+}
+$code.=<<___;
+ mov $YY,$TX[1]
+ xor $YY,$YY # keyword to partial register
+ sub \$16,$len
+ mov $TX[1]#b,$YY#b
+ test \$-16,$len
+ jnz .Loop16
+
+ psllq \$8,%xmm1
+ pxor %xmm0,%xmm2
+ pxor %xmm1,%xmm2
+ movdqu %xmm2,($out,$inp)
+ lea 16($inp),$inp
+
+ cmp \$0,$len
+ jne .Lloop1
+ jmp .Lexit
+
+.align 16
+.Lloop1:
+ add $TX[0]#b,$YY#b
+ movl ($dat,$YY,4),$TY#d
+ movl $TX[0]#d,($dat,$YY,4)
+ movl $TY#d,($dat,$XX[0],4)
+ add $TY#b,$TX[0]#b
+ inc $XX[0]#b
+ movl ($dat,$TX[0],4),$TY#d
+ movl ($dat,$XX[0],4),$TX[0]#d
+ xorb ($inp),$TY#b
+ movb $TY#b,($out,$inp)
+ lea 1($inp),$inp
+ dec $len
+ jnz .Lloop1
+ jmp .Lexit
+
+.align 16
+.LRC4_CHAR:
+ add \$1,$XX[0]#b
+ movzb ($dat,$XX[0]),$TX[0]#d
+ test \$-8,$len
+ jz .Lcloop1
+ jmp .Lcloop8
+.align 16
+.Lcloop8:
+ mov ($inp),%r8d
+ mov 4($inp),%r9d
+___
+# unroll 2x4-wise, because 64-bit rotates kill Intel P4...
+for ($i=0;$i<4;$i++) {
+$code.=<<___;
+ add $TX[0]#b,$YY#b
+ lea 1($XX[0]),$XX[1]
+ movzb ($dat,$YY),$TY#d
+ movzb $XX[1]#b,$XX[1]#d
+ movzb ($dat,$XX[1]),$TX[1]#d
+ movb $TX[0]#b,($dat,$YY)
+ cmp $XX[1],$YY
+ movb $TY#b,($dat,$XX[0])
+ jne .Lcmov$i # Intel cmov is sloooow...
+ mov $TX[0],$TX[1]
+.Lcmov$i:
+ add $TX[0]#b,$TY#b
+ xor ($dat,$TY),%r8b
+ ror \$8,%r8d
+___
+push(@TX,shift(@TX)); push(@XX,shift(@XX)); # "rotate" registers
+}
+for ($i=4;$i<8;$i++) {
+$code.=<<___;
+ add $TX[0]#b,$YY#b
+ lea 1($XX[0]),$XX[1]
+ movzb ($dat,$YY),$TY#d
+ movzb $XX[1]#b,$XX[1]#d
+ movzb ($dat,$XX[1]),$TX[1]#d
+ movb $TX[0]#b,($dat,$YY)
+ cmp $XX[1],$YY
+ movb $TY#b,($dat,$XX[0])
+ jne .Lcmov$i # Intel cmov is sloooow...
+ mov $TX[0],$TX[1]
+.Lcmov$i:
+ add $TX[0]#b,$TY#b
+ xor ($dat,$TY),%r9b
+ ror \$8,%r9d
+___
+push(@TX,shift(@TX)); push(@XX,shift(@XX)); # "rotate" registers
+}
+$code.=<<___;
+ lea -8($len),$len
+ mov %r8d,($out)
+ lea 8($inp),$inp
+ mov %r9d,4($out)
+ lea 8($out),$out
+
+ test \$-8,$len
+ jnz .Lcloop8
+ cmp \$0,$len
+ jne .Lcloop1
+ jmp .Lexit
+___
+$code.=<<___;
+.align 16
+.Lcloop1:
+ add $TX[0]#b,$YY#b
+ movzb $YY#b,$YY#d
+ movzb ($dat,$YY),$TY#d
+ movb $TX[0]#b,($dat,$YY)
+ movb $TY#b,($dat,$XX[0])
+ add $TX[0]#b,$TY#b
+ add \$1,$XX[0]#b
+ movzb $TY#b,$TY#d
+ movzb $XX[0]#b,$XX[0]#d
+ movzb ($dat,$TY),$TY#d
+ movzb ($dat,$XX[0]),$TX[0]#d
+ xorb ($inp),$TY#b
+ lea 1($inp),$inp
+ movb $TY#b,($out)
+ lea 1($out),$out
+ sub \$1,$len
+ jnz .Lcloop1
+ jmp .Lexit
+
+.align 16
+.Lexit:
+ sub \$1,$XX[0]#b
+ movl $XX[0]#d,-8($dat)
+ movl $YY#d,-4($dat)
+
+ mov (%rsp),%r13
+ mov 8(%rsp),%r12
+ mov 16(%rsp),%rbx
+ add \$24,%rsp
+.Lepilogue:
+ ret
+.size RC4,.-RC4
+___
+}
+
+$idx="%r8";
+$ido="%r9";
+
+$code.=<<___;
+.globl RC4_set_key
+.type RC4_set_key,\@function,3
+.align 16
+RC4_set_key:
+ lea 8($dat),$dat
+ lea ($inp,$len),$inp
+ neg $len
+ mov $len,%rcx
+ xor %eax,%eax
+ xor $ido,$ido
+ xor %r10,%r10
+ xor %r11,%r11
+
+ mov OPENSSL_ia32cap_P(%rip),$idx#d
+ bt \$20,$idx#d # RC4_CHAR?
+ jc .Lc1stloop
+ jmp .Lw1stloop
+
+.align 16
+.Lw1stloop:
+ mov %eax,($dat,%rax,4)
+ add \$1,%al
+ jnc .Lw1stloop
+
+ xor $ido,$ido
+ xor $idx,$idx
+.align 16
+.Lw2ndloop:
+ mov ($dat,$ido,4),%r10d
+ add ($inp,$len,1),$idx#b
+ add %r10b,$idx#b
+ add \$1,$len
+ mov ($dat,$idx,4),%r11d
+ cmovz %rcx,$len
+ mov %r10d,($dat,$idx,4)
+ mov %r11d,($dat,$ido,4)
+ add \$1,$ido#b
+ jnc .Lw2ndloop
+ jmp .Lexit_key
+
+.align 16
+.Lc1stloop:
+ mov %al,($dat,%rax)
+ add \$1,%al
+ jnc .Lc1stloop
+
+ xor $ido,$ido
+ xor $idx,$idx
+.align 16
+.Lc2ndloop:
+ mov ($dat,$ido),%r10b
+ add ($inp,$len),$idx#b
+ add %r10b,$idx#b
+ add \$1,$len
+ mov ($dat,$idx),%r11b
+ jnz .Lcnowrap
+ mov %rcx,$len
+.Lcnowrap:
+ mov %r10b,($dat,$idx)
+ mov %r11b,($dat,$ido)
+ add \$1,$ido#b
+ jnc .Lc2ndloop
+ movl \$-1,256($dat)
+
+.align 16
+.Lexit_key:
+ xor %eax,%eax
+ mov %eax,-8($dat)
+ mov %eax,-4($dat)
+ ret
+.size RC4_set_key,.-RC4_set_key
+
+.globl RC4_options
+.type RC4_options,\@abi-omnipotent
+.align 16
+RC4_options:
+ lea .Lopts(%rip),%rax
+ mov OPENSSL_ia32cap_P(%rip),%edx
+ bt \$20,%edx
+ jc .L8xchar
+ bt \$30,%edx
+ jnc .Ldone
+ add \$25,%rax
+ ret
+.L8xchar:
+ add \$12,%rax
+.Ldone:
+ ret
+.align 64
+.Lopts:
+.asciz "rc4(8x,int)"
+.asciz "rc4(8x,char)"
+.asciz "rc4(16x,int)"
+.asciz "RC4 for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
+.align 64
+.size RC4_options,.-RC4_options
+___
+
+# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
+# CONTEXT *context,DISPATCHER_CONTEXT *disp)
+if ($win64) {
+$rec="%rcx";
+$frame="%rdx";
+$context="%r8";
+$disp="%r9";
+
+$code.=<<___;
+.extern __imp_RtlVirtualUnwind
+.type stream_se_handler,\@abi-omnipotent
+.align 16
+stream_se_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 120($context),%rax # pull context->Rax
+ mov 248($context),%rbx # pull context->Rip
+
+ lea .Lprologue(%rip),%r10
+ cmp %r10,%rbx # context->Rip<prologue label
+ jb .Lin_prologue
+
+ mov 152($context),%rax # pull context->Rsp
+
+ lea .Lepilogue(%rip),%r10
+ cmp %r10,%rbx # context->Rip>=epilogue label
+ jae .Lin_prologue
+
+ lea 24(%rax),%rax
+
+ mov -8(%rax),%rbx
+ mov -16(%rax),%r12
+ mov -24(%rax),%r13
+ mov %rbx,144($context) # restore context->Rbx
+ mov %r12,216($context) # restore context->R12
+ mov %r13,224($context) # restore context->R13
+
+.Lin_prologue:
+ mov 8(%rax),%rdi
+ mov 16(%rax),%rsi
+ mov %rax,152($context) # restore context->Rsp
+ mov %rsi,168($context) # restore context->Rsi
+ mov %rdi,176($context) # restore context->Rdi
+
+ jmp .Lcommon_seh_exit
+.size stream_se_handler,.-stream_se_handler
+
+.type key_se_handler,\@abi-omnipotent
+.align 16
+key_se_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 152($context),%rax # pull context->Rsp
+ mov 8(%rax),%rdi
+ mov 16(%rax),%rsi
+ mov %rsi,168($context) # restore context->Rsi
+ mov %rdi,176($context) # restore context->Rdi
+
+.Lcommon_seh_exit:
+
+ mov 40($disp),%rdi # disp->ContextRecord
+ mov $context,%rsi # context
+ mov \$154,%ecx # sizeof(CONTEXT)
+ .long 0xa548f3fc # cld; rep movsq
+
+ mov $disp,%rsi
+ xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER
+ mov 8(%rsi),%rdx # arg2, disp->ImageBase
+ mov 0(%rsi),%r8 # arg3, disp->ControlPc
+ mov 16(%rsi),%r9 # arg4, disp->FunctionEntry
+ mov 40(%rsi),%r10 # disp->ContextRecord
+ lea 56(%rsi),%r11 # &disp->HandlerData
+ lea 24(%rsi),%r12 # &disp->EstablisherFrame
+ mov %r10,32(%rsp) # arg5
+ mov %r11,40(%rsp) # arg6
+ mov %r12,48(%rsp) # arg7
+ mov %rcx,56(%rsp) # arg8, (NULL)
+ call *__imp_RtlVirtualUnwind(%rip)
+
+ mov \$1,%eax # ExceptionContinueSearch
+ add \$64,%rsp
+ popfq
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+ pop %rdi
+ pop %rsi
+ ret
+.size key_se_handler,.-key_se_handler
+
+.section .pdata
+.align 4
+ .rva .LSEH_begin_RC4
+ .rva .LSEH_end_RC4
+ .rva .LSEH_info_RC4
+
+ .rva .LSEH_begin_RC4_set_key
+ .rva .LSEH_end_RC4_set_key
+ .rva .LSEH_info_RC4_set_key
+
+.section .xdata
+.align 8
+.LSEH_info_RC4:
+ .byte 9,0,0,0
+ .rva stream_se_handler
+.LSEH_info_RC4_set_key:
+ .byte 9,0,0,0
+ .rva key_se_handler
+___
+}
+
+sub reg_part {
+my ($reg,$conv)=@_;
+ if ($reg =~ /%r[0-9]+/) { $reg .= $conv; }
+ elsif ($conv eq "b") { $reg =~ s/%[er]([^x]+)x?/%$1l/; }
+ elsif ($conv eq "w") { $reg =~ s/%[er](.+)/%$1/; }
+ elsif ($conv eq "d") { $reg =~ s/%[er](.+)/%e$1/; }
+ return $reg;
+}
+
+$code =~ s/(%[a-z0-9]+)#([bwd])/reg_part($1,$2)/gem;
+$code =~ s/\`([^\`]*)\`/eval $1/gem;
+
+print $code;
+
+close STDOUT;
diff --git a/crypto/rc4/rc4.c b/crypto/rc4/rc4.c
new file mode 100644
index 0000000..a93f96e
--- /dev/null
+++ b/crypto/rc4/rc4.c
@@ -0,0 +1,348 @@
+/* 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/rc4.h>
+
+
+#if defined(OPENSSL_NO_ASM) || \
+ (!defined(OPENSSL_X86_64) && !defined(OPENSSL_X86))
+
+#define RC4_CHUNK unsigned long
+#define RC4_INT uint32_t
+
+
+/* RC4 as implemented from a posting from
+ * Newsgroups: sci.crypt
+ * From: sterndark@netcom.com (David Sterndark)
+ * Subject: RC4 Algorithm revealed.
+ * Message-ID: <sternCvKL4B.Hyy@netcom.com>
+ * Date: Wed, 14 Sep 1994 06:35:31 GMT */
+
+void RC4(RC4_KEY *key, size_t len, const uint8_t *in, uint8_t *out) {
+ register RC4_INT *d;
+ register RC4_INT x, y, tx, ty;
+ size_t i;
+
+ x = key->x;
+ y = key->y;
+ d = key->data;
+
+#if defined(RC4_CHUNK)
+/* The original reason for implementing this(*) was the fact that
+ * pre-21164a Alpha CPUs don't have byte load/store instructions
+ * and e.g. a byte store has to be done with 64-bit load, shift,
+ * and, or and finally 64-bit store. Peaking data and operating
+ * at natural word size made it possible to reduce amount of
+ * instructions as well as to perform early read-ahead without
+ * suffering from RAW (read-after-write) hazard. This resulted
+ * in ~40%(**) performance improvement on 21064 box with gcc.
+ * But it's not only Alpha users who win here:-) Thanks to the
+ * early-n-wide read-ahead this implementation also exhibits
+ * >40% speed-up on SPARC and 20-30% on 64-bit MIPS (depending
+ * on sizeof(RC4_INT)).
+ *
+ * (*) "this" means code which recognizes the case when input
+ * and output pointers appear to be aligned at natural CPU
+ * word boundary
+ * (**) i.e. according to 'apps/openssl speed rc4' benchmark,
+ * crypto/rc4/rc4speed.c exhibits almost 70% speed-up...
+ *
+ * Cavets.
+ *
+ * - RC4_CHUNK="unsigned long long" should be a #1 choice for
+ * UltraSPARC. Unfortunately gcc generates very slow code
+ * (2.5-3 times slower than one generated by Sun's WorkShop
+ * C) and therefore gcc (at least 2.95 and earlier) should
+ * always be told that RC4_CHUNK="unsigned long".
+ *
+ * <appro@fy.chalmers.se> */
+
+#define RC4_STEP \
+ (x = (x + 1) & 0xff, tx = d[x], y = (tx + y) & 0xff, ty = d[y], d[y] = tx, \
+ d[x] = ty, (RC4_CHUNK)d[(tx + ty) & 0xff])
+
+ if ((((size_t)in & (sizeof(RC4_CHUNK) - 1)) |
+ ((size_t)out & (sizeof(RC4_CHUNK) - 1))) == 0) {
+ RC4_CHUNK ichunk, otp;
+ const union {
+ long one;
+ char little;
+ } is_endian = {1};
+
+ /* I reckon we can afford to implement both endian
+ * cases and to decide which way to take at run-time
+ * because the machine code appears to be very compact
+ * and redundant 1-2KB is perfectly tolerable (i.e.
+ * in case the compiler fails to eliminate it:-). By
+ * suggestion from Terrel Larson <terr@terralogic.net>
+ * who also stands for the is_endian union:-)
+ *
+ * Special notes.
+ *
+ * - is_endian is declared automatic as doing otherwise
+ * (declaring static) prevents gcc from eliminating
+ * the redundant code;
+ * - compilers (those I've tried) don't seem to have
+ * problems eliminating either the operators guarded
+ * by "if (sizeof(RC4_CHUNK)==8)" or the condition
+ * expressions themselves so I've got 'em to replace
+ * corresponding #ifdefs from the previous version;
+ * - I chose to let the redundant switch cases when
+ * sizeof(RC4_CHUNK)!=8 be (were also #ifdefed
+ * before);
+ * - in case you wonder "&(sizeof(RC4_CHUNK)*8-1)" in
+ * [LB]ESHFT guards against "shift is out of range"
+ * warnings when sizeof(RC4_CHUNK)!=8
+ *
+ * <appro@fy.chalmers.se> */
+ if (!is_endian.little) { /* BIG-ENDIAN CASE */
+#define BESHFT(c) \
+ (((sizeof(RC4_CHUNK) - (c) - 1) * 8) & (sizeof(RC4_CHUNK) * 8 - 1))
+ for (; len & (0 - sizeof(RC4_CHUNK)); len -= sizeof(RC4_CHUNK)) {
+ ichunk = *(RC4_CHUNK *)in;
+ otp = RC4_STEP << BESHFT(0);
+ otp |= RC4_STEP << BESHFT(1);
+ otp |= RC4_STEP << BESHFT(2);
+ otp |= RC4_STEP << BESHFT(3);
+ if (sizeof(RC4_CHUNK) == 8) {
+ otp |= RC4_STEP << BESHFT(4);
+ otp |= RC4_STEP << BESHFT(5);
+ otp |= RC4_STEP << BESHFT(6);
+ otp |= RC4_STEP << BESHFT(7);
+ }
+ *(RC4_CHUNK *)out = otp ^ ichunk;
+ in += sizeof(RC4_CHUNK);
+ out += sizeof(RC4_CHUNK);
+ }
+ if (len) {
+ RC4_CHUNK mask = (RC4_CHUNK) - 1, ochunk;
+
+ ichunk = *(RC4_CHUNK *)in;
+ ochunk = *(RC4_CHUNK *)out;
+ otp = 0;
+ i = BESHFT(0);
+ mask <<= (sizeof(RC4_CHUNK) - len) << 3;
+ switch (len & (sizeof(RC4_CHUNK) - 1)) {
+ case 7:
+ otp = RC4_STEP << i, i -= 8;
+ case 6:
+ otp |= RC4_STEP << i, i -= 8;
+ case 5:
+ otp |= RC4_STEP << i, i -= 8;
+ case 4:
+ otp |= RC4_STEP << i, i -= 8;
+ case 3:
+ otp |= RC4_STEP << i, i -= 8;
+ case 2:
+ otp |= RC4_STEP << i, i -= 8;
+ case 1:
+ otp |= RC4_STEP << i, i -= 8;
+ }
+ ochunk &= ~mask;
+ ochunk |= (otp ^ ichunk) & mask;
+ *(RC4_CHUNK *)out = ochunk;
+ }
+ key->x = x;
+ key->y = y;
+ return;
+ } else { /* LITTLE-ENDIAN CASE */
+#define LESHFT(c) (((c) * 8) & (sizeof(RC4_CHUNK) * 8 - 1))
+ for (; len & (0 - sizeof(RC4_CHUNK)); len -= sizeof(RC4_CHUNK)) {
+ ichunk = *(RC4_CHUNK *)in;
+ otp = RC4_STEP;
+ otp |= RC4_STEP << 8;
+ otp |= RC4_STEP << 16;
+ otp |= RC4_STEP << 24;
+ if (sizeof(RC4_CHUNK) == 8) {
+ otp |= RC4_STEP << LESHFT(4);
+ otp |= RC4_STEP << LESHFT(5);
+ otp |= RC4_STEP << LESHFT(6);
+ otp |= RC4_STEP << LESHFT(7);
+ }
+ *(RC4_CHUNK *)out = otp ^ ichunk;
+ in += sizeof(RC4_CHUNK);
+ out += sizeof(RC4_CHUNK);
+ }
+ if (len) {
+ RC4_CHUNK mask = (RC4_CHUNK) - 1, ochunk;
+
+ ichunk = *(RC4_CHUNK *)in;
+ ochunk = *(RC4_CHUNK *)out;
+ otp = 0;
+ i = 0;
+ mask >>= (sizeof(RC4_CHUNK) - len) << 3;
+ switch (len & (sizeof(RC4_CHUNK) - 1)) {
+ case 7:
+ otp = RC4_STEP, i += 8;
+ case 6:
+ otp |= RC4_STEP << i, i += 8;
+ case 5:
+ otp |= RC4_STEP << i, i += 8;
+ case 4:
+ otp |= RC4_STEP << i, i += 8;
+ case 3:
+ otp |= RC4_STEP << i, i += 8;
+ case 2:
+ otp |= RC4_STEP << i, i += 8;
+ case 1:
+ otp |= RC4_STEP << i, i += 8;
+ }
+ ochunk &= ~mask;
+ ochunk |= (otp ^ ichunk) & mask;
+ *(RC4_CHUNK *)out = ochunk;
+ }
+ key->x = x;
+ key->y = y;
+ return;
+ }
+ }
+#endif
+#define LOOP(in, out) \
+ x = ((x + 1) & 0xff); \
+ tx = d[x]; \
+ y = (tx + y) & 0xff; \
+ d[x] = ty = d[y]; \
+ d[y] = tx; \
+ (out) = d[(tx + ty) & 0xff] ^ (in);
+
+#ifndef RC4_INDEX
+#define RC4_LOOP(a, b, i) LOOP(*((a)++), *((b)++))
+#else
+#define RC4_LOOP(a, b, i) LOOP(a[i], b[i])
+#endif
+
+ i = len >> 3;
+ if (i) {
+ for (;;) {
+ RC4_LOOP(in, out, 0);
+ RC4_LOOP(in, out, 1);
+ RC4_LOOP(in, out, 2);
+ RC4_LOOP(in, out, 3);
+ RC4_LOOP(in, out, 4);
+ RC4_LOOP(in, out, 5);
+ RC4_LOOP(in, out, 6);
+ RC4_LOOP(in, out, 7);
+#ifdef RC4_INDEX
+ in += 8;
+ out += 8;
+#endif
+ if (--i == 0)
+ break;
+ }
+ }
+ i = len & 0x07;
+ if (i) {
+ for (;;) {
+ RC4_LOOP(in, out, 0);
+ if (--i == 0)
+ break;
+ RC4_LOOP(in, out, 1);
+ if (--i == 0)
+ break;
+ RC4_LOOP(in, out, 2);
+ if (--i == 0)
+ break;
+ RC4_LOOP(in, out, 3);
+ if (--i == 0)
+ break;
+ RC4_LOOP(in, out, 4);
+ if (--i == 0)
+ break;
+ RC4_LOOP(in, out, 5);
+ if (--i == 0)
+ break;
+ RC4_LOOP(in, out, 6);
+ if (--i == 0)
+ break;
+ }
+ }
+ key->x = x;
+ key->y = y;
+}
+
+void RC4_set_key(RC4_KEY *rc4key, unsigned len, const uint8_t *key) {
+ register RC4_INT tmp;
+ register int id1, id2;
+ register RC4_INT *d;
+ unsigned int i;
+
+ d = &rc4key->data[0];
+ rc4key->x = 0;
+ rc4key->y = 0;
+ id1 = id2 = 0;
+
+#define SK_LOOP(d, n) \
+ { \
+ tmp = d[(n)]; \
+ id2 = (key[id1] + tmp + id2) & 0xff; \
+ if (++id1 == len) \
+ id1 = 0; \
+ d[(n)] = d[id2]; \
+ d[id2] = tmp; \
+ }
+
+ for (i = 0; i < 256; i++) {
+ d[i] = i;
+ }
+ for (i = 0; i < 256; i += 4) {
+ SK_LOOP(d, i + 0);
+ SK_LOOP(d, i + 1);
+ SK_LOOP(d, i + 2);
+ SK_LOOP(d, i + 3);
+ }
+}
+
+#endif
diff --git a/crypto/rc4/rc4.h b/crypto/rc4/rc4.h
new file mode 100644
index 0000000..4b87e8b
--- /dev/null
+++ b/crypto/rc4/rc4.h
@@ -0,0 +1,88 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_RC4_H
+#define OPENSSL_HEADER_RC4_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+typedef struct rc4_key_st {
+ uint32_t x, y;
+ /* data is sometimes used as an array of 32-bit values and sometimes as 8-bit
+ * values, depending on the platform. */
+ uint32_t data[256];
+} RC4_KEY;
+
+
+/* RC4_set_key performs an RC4 key schedule and initialises |rc4key| with |len|
+ * bytes of key material from |key|. */
+void RC4_set_key(RC4_KEY *rc4key, unsigned len, const uint8_t *key);
+
+/* RC4 encrypts (or decrypts, it's the same with RC4) |len| bytes from |in| to
+ * |out|. */
+void RC4(RC4_KEY *key, size_t len, const uint8_t *in, uint8_t *out);
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_RC4_H */
diff --git a/crypto/rsa/CMakeLists.txt b/crypto/rsa/CMakeLists.txt
new file mode 100644
index 0000000..82e6c50
--- /dev/null
+++ b/crypto/rsa/CMakeLists.txt
@@ -0,0 +1,22 @@
+include_directories(. .. ../../include)
+
+add_library(
+ rsa
+
+ OBJECT
+
+ rsa.c
+ rsa_impl.c
+ blinding.c
+ padding.c
+ rsa_asn1.c
+ rsa_error.c
+)
+
+add_executable(
+ rsa_test
+
+ rsa_test.c
+)
+
+target_link_libraries(rsa_test crypto)
diff --git a/crypto/rsa/blinding.c b/crypto/rsa/blinding.c
new file mode 100644
index 0000000..04f672a
--- /dev/null
+++ b/crypto/rsa/blinding.c
@@ -0,0 +1,468 @@
+/* ====================================================================
+ * Copyright (c) 1998-2006 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).
+ *
+ * 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 <openssl/bn.h>
+#include <openssl/mem.h>
+#include <openssl/err.h>
+
+#include "internal.h"
+
+#define BN_BLINDING_COUNTER 32
+
+struct bn_blinding_st {
+ BIGNUM *A;
+ BIGNUM *Ai;
+ BIGNUM *e;
+ BIGNUM *mod; /* just a reference */
+ CRYPTO_THREADID tid;
+ int counter;
+ unsigned long flags;
+ BN_MONT_CTX *m_ctx;
+ int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+ const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
+};
+
+BN_BLINDING *BN_BLINDING_new(const BIGNUM *A, const BIGNUM *Ai, BIGNUM *mod) {
+ BN_BLINDING *ret = NULL;
+
+ ret = (BN_BLINDING*) OPENSSL_malloc(sizeof(BN_BLINDING));
+ if (ret == NULL) {
+ OPENSSL_PUT_ERROR(RSA, BN_BLINDING_new, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ memset(ret, 0, sizeof(BN_BLINDING));
+ if (A != NULL) {
+ ret->A = BN_dup(A);
+ if (ret->A == NULL) {
+ goto err;
+ }
+ }
+ if (Ai != NULL) {
+ ret->Ai = BN_dup(Ai);
+ if (ret->Ai == NULL) {
+ goto err;
+ }
+ }
+
+ /* save a copy of mod in the BN_BLINDING structure */
+ ret->mod = BN_dup(mod);
+ if (ret->mod == NULL) {
+ goto err;
+ }
+ if (BN_get_flags(mod, BN_FLG_CONSTTIME) != 0) {
+ BN_set_flags(ret->mod, BN_FLG_CONSTTIME);
+ }
+
+ /* Set the counter to the special value -1
+ * to indicate that this is never-used fresh blinding
+ * that does not need updating before first use. */
+ ret->counter = -1;
+ CRYPTO_THREADID_current(&ret->tid);
+ return ret;
+
+err:
+ if (ret != NULL) {
+ BN_BLINDING_free(ret);
+ }
+ return NULL;
+}
+
+void BN_BLINDING_free(BN_BLINDING *r) {
+ if (r == NULL) {
+ return;
+ }
+
+ if (r->A != NULL)
+ BN_free(r->A);
+ if (r->Ai != NULL)
+ BN_free(r->Ai);
+ if (r->e != NULL)
+ BN_free(r->e);
+ if (r->mod != NULL)
+ BN_free(r->mod);
+ OPENSSL_free(r);
+}
+
+int BN_BLINDING_update(BN_BLINDING *b, BN_CTX *ctx) {
+ int ret = 0;
+
+ if (b->A == NULL || b->Ai == NULL) {
+ OPENSSL_PUT_ERROR(RSA, BN_BLINDING_update, RSA_R_BN_NOT_INITIALIZED);
+ goto err;
+ }
+
+ if (b->counter == -1) {
+ b->counter = 0;
+ }
+
+ if (++b->counter == BN_BLINDING_COUNTER && b->e != NULL &&
+ !(b->flags & BN_BLINDING_NO_RECREATE)) {
+ /* re-create blinding parameters */
+ if (!BN_BLINDING_create_param(b, NULL, NULL, ctx, NULL, NULL)) {
+ goto err;
+ }
+ } else if (!(b->flags & BN_BLINDING_NO_UPDATE)) {
+ if (!BN_mod_mul(b->A, b->A, b->A, b->mod, ctx)) {
+ goto err;
+ }
+ if (!BN_mod_mul(b->Ai, b->Ai, b->Ai, b->mod, ctx)) {
+ goto err;
+ }
+ }
+
+ ret = 1;
+
+err:
+ if (b->counter == BN_BLINDING_COUNTER) {
+ b->counter = 0;
+ }
+ return ret;
+}
+
+int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx) {
+ return BN_BLINDING_convert_ex(n, NULL, b, ctx);
+}
+
+int BN_BLINDING_convert_ex(BIGNUM *n, BIGNUM *r, BN_BLINDING *b, BN_CTX *ctx) {
+ int ret = 1;
+
+ if (b->A == NULL || b->Ai == NULL) {
+ OPENSSL_PUT_ERROR(RSA, BN_BLINDING_convert_ex, RSA_R_BN_NOT_INITIALIZED);
+ return 0;
+ }
+
+ if (b->counter == -1) {
+ /* Fresh blinding, doesn't need updating. */
+ b->counter = 0;
+ } else if (!BN_BLINDING_update(b, ctx)) {
+ return 0;
+ }
+
+ if (r != NULL) {
+ if (!BN_copy(r, b->Ai)) {
+ ret = 0;
+ }
+ }
+
+ if (!BN_mod_mul(n, n, b->A, b->mod, ctx)) {
+ ret = 0;
+ }
+
+ return ret;
+}
+
+int BN_BLINDING_invert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx) {
+ return BN_BLINDING_invert_ex(n, NULL, b, ctx);
+}
+
+int BN_BLINDING_invert_ex(BIGNUM *n, const BIGNUM *r, BN_BLINDING *b,
+ BN_CTX *ctx) {
+ int ret;
+
+ if (r != NULL) {
+ 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);
+ return 0;
+ }
+ ret = BN_mod_mul(n, n, b->Ai, b->mod, ctx);
+ }
+
+ return ret;
+}
+
+CRYPTO_THREADID *BN_BLINDING_thread_id(BN_BLINDING *b) { return &b->tid; }
+
+unsigned long BN_BLINDING_get_flags(const BN_BLINDING *b) { return b->flags; }
+
+void BN_BLINDING_set_flags(BN_BLINDING *b, unsigned long flags) {
+ b->flags = flags;
+}
+
+BN_BLINDING *BN_BLINDING_create_param(
+ BN_BLINDING *b, const BIGNUM *e, BIGNUM *m, BN_CTX *ctx,
+ int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+ const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx),
+ BN_MONT_CTX *m_ctx) {
+ int retry_counter = 32;
+ BN_BLINDING *ret = NULL;
+
+ if (b == NULL) {
+ ret = BN_BLINDING_new(NULL, NULL, m);
+ } else {
+ ret = b;
+ }
+
+ if (ret == NULL) {
+ goto err;
+ }
+
+ if (ret->A == NULL && (ret->A = BN_new()) == NULL) {
+ goto err;
+ }
+ if (ret->Ai == NULL && (ret->Ai = BN_new()) == NULL) {
+ goto err;
+ }
+
+ if (e != NULL) {
+ if (ret->e != NULL) {
+ BN_free(ret->e);
+ }
+ ret->e = BN_dup(e);
+ }
+ if (ret->e == NULL) {
+ goto err;
+ }
+
+ if (bn_mod_exp != NULL) {
+ ret->bn_mod_exp = bn_mod_exp;
+ }
+ if (m_ctx != NULL) {
+ ret->m_ctx = m_ctx;
+ }
+
+ do {
+ if (!BN_rand_range(ret->A, ret->mod)) {
+ goto err;
+ }
+ if (BN_mod_inverse(ret->Ai, 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 (retry_counter-- == 0) {
+ OPENSSL_PUT_ERROR(RSA, BN_BLINDING_create_param,
+ RSA_R_TOO_MANY_ITERATIONS);
+ goto err;
+ }
+ ERR_clear_error();
+ } else {
+ goto err;
+ }
+ } else {
+ break;
+ }
+ } while (1);
+
+ if (ret->bn_mod_exp != NULL && ret->m_ctx != NULL) {
+ if (!ret->bn_mod_exp(ret->A, ret->A, ret->e, ret->mod, ctx, ret->m_ctx)) {
+ goto err;
+ }
+ } else {
+ if (!BN_mod_exp(ret->A, ret->A, ret->e, ret->mod, ctx)) {
+ goto err;
+ }
+ }
+
+ return ret;
+
+err:
+ if (b == NULL && ret != NULL) {
+ BN_BLINDING_free(ret);
+ ret = NULL;
+ }
+
+ return ret;
+}
+
+static BIGNUM *rsa_get_public_exp(const BIGNUM *d, const BIGNUM *p,
+ const BIGNUM *q, BN_CTX *ctx) {
+ BIGNUM *ret = NULL, *r0, *r1, *r2;
+
+ if (d == NULL || p == NULL || q == NULL) {
+ return NULL;
+ }
+
+ BN_CTX_start(ctx);
+ r0 = BN_CTX_get(ctx);
+ r1 = BN_CTX_get(ctx);
+ r2 = BN_CTX_get(ctx);
+ if (r2 == NULL) {
+ goto err;
+ }
+
+ if (!BN_sub(r1, p, BN_value_one())) {
+ goto err;
+ }
+ if (!BN_sub(r2, q, BN_value_one())) {
+ goto err;
+ }
+ if (!BN_mul(r0, r1, r2, ctx)) {
+ goto err;
+ }
+
+ ret = BN_mod_inverse(NULL, d, r0, ctx);
+
+err:
+ BN_CTX_end(ctx);
+ return ret;
+}
+
+BN_BLINDING *rsa_setup_blinding(RSA *rsa, BN_CTX *in_ctx) {
+ BIGNUM local_n;
+ BIGNUM *e, *n;
+ BN_CTX *ctx;
+ BN_BLINDING *ret = NULL;
+
+ if (in_ctx == NULL) {
+ ctx = BN_CTX_new();
+ if (ctx == NULL) {
+ return 0;
+ }
+ } else {
+ ctx = in_ctx;
+ }
+
+ BN_CTX_start(ctx);
+ e = BN_CTX_get(ctx);
+ if (e == NULL) {
+ OPENSSL_PUT_ERROR(RSA, rsa_setup_blinding, 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);
+ goto err;
+ }
+ } else {
+ e = rsa->e;
+ }
+
+ n = &local_n;
+ BN_with_flags(n, rsa->n, BN_FLG_CONSTTIME);
+
+ if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) {
+ if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_n, CRYPTO_LOCK_RSA, rsa->n,
+ ctx)) {
+ goto err;
+ }
+ }
+
+ ret = BN_BLINDING_create_param(NULL, e, n, ctx, rsa->meth->bn_mod_exp,
+ rsa->_method_mod_n);
+ if (ret == NULL) {
+ OPENSSL_PUT_ERROR(RSA, rsa_setup_blinding, ERR_R_BN_LIB);
+ goto err;
+ }
+ CRYPTO_THREADID_current(BN_BLINDING_thread_id(ret));
+
+err:
+ BN_CTX_end(ctx);
+ if (in_ctx == NULL) {
+ BN_CTX_free(ctx);
+ }
+ if (rsa->e == NULL) {
+ BN_free(e);
+ }
+
+ return ret;
+}
diff --git a/crypto/rsa/internal.h b/crypto/rsa/internal.h
new file mode 100644
index 0000000..f697940
--- /dev/null
+++ b/crypto/rsa/internal.h
@@ -0,0 +1,157 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_RSA_INTERNAL_H
+#define OPENSSL_HEADER_RSA_INTERNAL_H
+
+#include <openssl/base.h>
+
+#include <openssl/asn1.h>
+#include <openssl/thread.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+#define RSA_PKCS1_PADDING_SIZE 11
+
+
+/* BN_BLINDING flags */
+#define BN_BLINDING_NO_UPDATE 0x00000001
+#define BN_BLINDING_NO_RECREATE 0x00000002
+
+BN_BLINDING *BN_BLINDING_new(const BIGNUM *A, const BIGNUM *Ai, BIGNUM *mod);
+void BN_BLINDING_free(BN_BLINDING *b);
+int BN_BLINDING_update(BN_BLINDING *b, BN_CTX *ctx);
+int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx);
+int BN_BLINDING_invert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx);
+int BN_BLINDING_convert_ex(BIGNUM *n, BIGNUM *r, BN_BLINDING *b, BN_CTX *);
+int BN_BLINDING_invert_ex(BIGNUM *n, const BIGNUM *r, BN_BLINDING *b, BN_CTX *);
+CRYPTO_THREADID *BN_BLINDING_thread_id(BN_BLINDING *);
+unsigned long BN_BLINDING_get_flags(const BN_BLINDING *);
+void BN_BLINDING_set_flags(BN_BLINDING *, unsigned long);
+BN_BLINDING *BN_BLINDING_create_param(
+ BN_BLINDING *b, const BIGNUM *e, BIGNUM *m, BN_CTX *ctx,
+ int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+ const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx),
+ BN_MONT_CTX *m_ctx);
+BN_BLINDING *rsa_setup_blinding(RSA *rsa, BN_CTX *in_ctx);
+
+
+int RSA_padding_add_PKCS1_type_1(uint8_t *to, unsigned to_len,
+ const uint8_t *from, unsigned from_len);
+int RSA_padding_check_PKCS1_type_1(uint8_t *to, unsigned to_len,
+ const uint8_t *from, unsigned from_len,
+ unsigned rsa_len);
+int RSA_padding_add_PKCS1_type_2(uint8_t *to, unsigned to_len,
+ const uint8_t *from, unsigned from_len);
+int RSA_padding_check_PKCS1_type_2(uint8_t *to, unsigned to_len,
+ const uint8_t *from, unsigned from_len,
+ unsigned rsa_len);
+int RSA_padding_add_PKCS1_OAEP_mgf1(uint8_t *to, unsigned to_len,
+ const uint8_t *from, unsigned from_len,
+ const uint8_t *param, unsigned plen,
+ const EVP_MD *md, const EVP_MD *mgf1md);
+int RSA_padding_check_PKCS1_OAEP_mgf1(uint8_t *to, unsigned to_len,
+ const uint8_t *from, unsigned from_len,
+ unsigned num, const uint8_t *param,
+ unsigned plen, const EVP_MD *md,
+ const EVP_MD *mgf1md);
+int RSA_padding_add_PKCS1_OAEP(uint8_t *to, unsigned to_len,
+ const uint8_t *from, unsigned from_len,
+ const uint8_t *p, unsigned pl);
+int RSA_padding_check_PKCS1_OAEP(uint8_t *to, unsigned to_len,
+ const uint8_t *from, unsigned from_len,
+ unsigned rsa_len, const uint8_t *p, unsigned pl);
+int RSA_padding_add_SSLv23(uint8_t *to, unsigned to_len, const uint8_t *from,
+ unsigned from_len);
+int RSA_padding_check_SSLv23(uint8_t *to, unsigned to_len, const uint8_t *from,
+ unsigned from_len, unsigned rsa_len);
+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, unsigned rsa_len);
+
+/* RSA_verify_PKCS1_PSS_mgf1 */
+int RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const uint8_t *mHash,
+ const EVP_MD *Hash, const EVP_MD *mgf1Hash,
+ const uint8_t *EM, int sLen);
+
+int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, uint8_t *EM, const uint8_t *mHash,
+ const EVP_MD *Hash, const EVP_MD *mgf1Hash,
+ int sLen);
+
+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)
+
+typedef struct rsa_oaep_params_st {
+ X509_ALGOR *hashFunc;
+ X509_ALGOR *maskGenFunc;
+ X509_ALGOR *pSourceFunc;
+} RSA_OAEP_PARAMS;
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_RSA_INTERNAL_H */
diff --git a/crypto/rsa/padding.c b/crypto/rsa/padding.c
new file mode 100644
index 0000000..203f4fb
--- /dev/null
+++ b/crypto/rsa/padding.c
@@ -0,0 +1,827 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2005.
+ */
+/* ====================================================================
+ * Copyright (c) 2005 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/rsa.h>
+
+#include <openssl/digest.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/rand.h>
+#include <openssl/sha.h>
+
+#include "internal.h"
+
+/* TODO(fork): don't the check functions have to be constant time? */
+
+int RSA_padding_add_PKCS1_type_1(uint8_t *to, unsigned tlen,
+ const uint8_t *from, unsigned flen) {
+ unsigned j;
+ uint8_t *p;
+
+ 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);
+ return 0;
+ }
+
+ p = (uint8_t *)to;
+
+ *(p++) = 0;
+ *(p++) = 1; /* Private Key BT (Block Type) */
+
+ /* pad out with 0xff data */
+ j = tlen - 3 - flen;
+ memset(p, 0xff, j);
+ p += j;
+ *(p++) = 0;
+ memcpy(p, from, (unsigned int)flen);
+ return 1;
+}
+
+int RSA_padding_check_PKCS1_type_1(uint8_t *to, unsigned tlen, const uint8_t *from,
+ unsigned flen, unsigned num) {
+ unsigned i, j;
+ const uint8_t *p;
+
+ if (flen == 0) {
+ OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_1,
+ RSA_R_EMPTY_PUBLIC_KEY);
+ return -1;
+ }
+
+ p = from;
+ if ((num != (flen + 1)) || (*(p++) != 1)) {
+ OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_1,
+ RSA_R_BLOCK_TYPE_IS_NOT_01);
+ return -1;
+ }
+
+ /* scan over padding data */
+ j = flen - 1; /* one for type. */
+ for (i = 0; i < j; i++) {
+ if (*p != 0xff) /* should decrypt to 0xff */
+ {
+ if (*p == 0) {
+ p++;
+ break;
+ } else {
+ OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_1,
+ RSA_R_BAD_FIXED_HEADER_DECRYPT);
+ return -1;
+ }
+ }
+ p++;
+ }
+
+ if (i == j) {
+ OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_1,
+ 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);
+ 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);
+ return -1;
+ }
+ memcpy(to, p, j);
+
+ return j;
+}
+
+int RSA_padding_add_PKCS1_type_2(uint8_t *to, unsigned tlen,
+ const uint8_t *from, unsigned flen) {
+ unsigned i, j;
+ uint8_t *p;
+
+ if (flen > (tlen - 11)) {
+ OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_type_2,
+ RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
+ return 0;
+ }
+
+ p = (unsigned char *)to;
+
+ *(p++) = 0;
+ *(p++) = 2; /* Public Key BT (Block Type) */
+
+ /* pad out with non-zero random data */
+ j = tlen - 3 - flen;
+
+ if (RAND_pseudo_bytes(p, j) <= 0) {
+ return 0;
+ }
+
+ for (i = 0; i < j; i++) {
+ if (*p == 0) {
+ do {
+ if (RAND_pseudo_bytes(p, 1) <= 0) {
+ return 0;
+ }
+ } while (*p == 0);
+ }
+ p++;
+ }
+
+ *(p++) = 0;
+
+ memcpy(p, from, (unsigned int)flen);
+ return 1;
+}
+
+int RSA_padding_check_PKCS1_type_2(uint8_t *to, unsigned tlen, const uint8_t *from,
+ unsigned flen, unsigned num) {
+ unsigned i, j;
+ const uint8_t *p;
+
+ if (flen == 0) {
+ OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_2,
+ RSA_R_EMPTY_PUBLIC_KEY);
+ return -1;
+ }
+
+ p = from;
+ if ((num != (flen + 1)) || (*(p++) != 2)) {
+ OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_2,
+ RSA_R_BLOCK_TYPE_IS_NOT_02);
+ return -1;
+ }
+
+ /* scan over padding data */
+ j = flen - 1; /* one for type. */
+ for (i = 0; i < j; i++) {
+ if (*(p++) == 0) {
+ break;
+ }
+ }
+
+ if (i == j) {
+ OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_2,
+ RSA_R_NULL_BEFORE_BLOCK_MISSING);
+ return -1;
+ }
+
+ if (i < 8) {
+ OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_2,
+ 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_2,
+ RSA_R_DATA_TOO_LARGE);
+ return -1;
+ }
+ memcpy(to, p, (unsigned int)j);
+
+ return j;
+}
+
+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);
+ return 0;
+ }
+
+ if (flen < tlen) {
+ OPENSSL_PUT_ERROR(RSA, RSA_padding_add_none,
+ RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE);
+ return 0;
+ }
+
+ memcpy(to, from, (unsigned int)flen);
+ return 1;
+}
+
+int RSA_padding_check_none(uint8_t *to, unsigned tlen, const uint8_t *from,
+ unsigned flen, unsigned num) {
+ if (flen > tlen) {
+ OPENSSL_PUT_ERROR(RSA, RSA_padding_check_none, RSA_R_DATA_TOO_LARGE);
+ return -1;
+ }
+
+ memset(to, 0, tlen - flen);
+ memcpy(to + tlen - flen, from, flen);
+ return tlen;
+}
+
+int RSA_padding_add_SSLv23(uint8_t *to, unsigned tlen, const uint8_t *from,
+ unsigned flen) {
+ unsigned i, j;
+ uint8_t *p;
+
+ if (flen > (tlen - 11)) {
+ OPENSSL_PUT_ERROR(RSA, RSA_padding_add_SSLv23,
+ RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
+ return 0;
+ }
+
+ p = to;
+
+ *(p++) = 0;
+ *(p++) = 2; /* Public Key BT (Block Type) */
+
+ /* pad out with non-zero random data */
+ j = tlen - 3 - 8 - flen;
+
+ if (RAND_pseudo_bytes(p, j) <= 0) {
+ return 0;
+ }
+
+ for (i = 0; i < j; i++) {
+ if (*p == '\0') {
+ do {
+ if (RAND_pseudo_bytes(p, 1) <= 0)
+ return 0;
+ } while (*p == '\0');
+ }
+ p++;
+ }
+
+ memset(p, 3, 8);
+ p += 8;
+ *(p++) = '\0';
+
+ memcpy(p, from, flen);
+ return 1;
+}
+
+int RSA_padding_check_SSLv23(uint8_t *to, unsigned tlen, const uint8_t *from,
+ unsigned flen, unsigned num) {
+ unsigned i, j, k;
+ const uint8_t *p;
+
+ p = from;
+ if (flen < 10) {
+ OPENSSL_PUT_ERROR(RSA, RSA_padding_check_SSLv23, RSA_R_DATA_TOO_SMALL);
+ return -1;
+ }
+ if ((num != (flen + 1)) || (*(p++) != 02)) {
+ OPENSSL_PUT_ERROR(RSA, RSA_padding_check_SSLv23,
+ RSA_R_BLOCK_TYPE_IS_NOT_02);
+ return -1;
+ }
+
+ /* scan over padding data */
+ j = flen - 1; /* one for type */
+ for (i = 0; i < j; i++) {
+ if (*(p++) == 0) {
+ break;
+ }
+ }
+
+ if ((i == j) || (i < 8)) {
+ OPENSSL_PUT_ERROR(RSA, RSA_padding_check_SSLv23,
+ RSA_R_NULL_BEFORE_BLOCK_MISSING);
+ return -1;
+ }
+
+ for (k = -9; k < -1; k++) {
+ if (p[k] != 0x03) {
+ break;
+ }
+ }
+
+ if (k == -1) {
+ OPENSSL_PUT_ERROR(RSA, RSA_padding_check_SSLv23,
+ RSA_R_SSLV3_ROLLBACK_ATTACK);
+ return -1;
+ }
+
+ i++; /* Skip over the '\0' */
+ j -= i;
+ if (j > tlen) {
+ OPENSSL_PUT_ERROR(RSA, RSA_padding_check_SSLv23, RSA_R_DATA_TOO_LARGE);
+ return -1;
+ }
+ memcpy(to, p, (unsigned int)j);
+
+ return j;
+}
+
+int PKCS1_MGF1(uint8_t *mask, unsigned len, const uint8_t *seed,
+ unsigned seedlen, const EVP_MD *dgst) {
+ unsigned outlen = 0;
+ uint32_t i;
+ uint8_t cnt[4];
+ EVP_MD_CTX c;
+ uint8_t md[EVP_MAX_MD_SIZE];
+ unsigned mdlen;
+ int ret = -1;
+
+ EVP_MD_CTX_init(&c);
+ mdlen = EVP_MD_size(dgst);
+
+ for (i = 0; outlen < len; i++) {
+ cnt[0] = (uint8_t)((i >> 24) & 255);
+ cnt[1] = (uint8_t)((i >> 16) & 255);
+ cnt[2] = (uint8_t)((i >> 8)) & 255;
+ cnt[3] = (uint8_t)(i & 255);
+ if (!EVP_DigestInit_ex(&c, dgst, NULL) ||
+ !EVP_DigestUpdate(&c, seed, seedlen) || !EVP_DigestUpdate(&c, cnt, 4)) {
+ goto err;
+ }
+
+ if (outlen + mdlen <= len) {
+ if (!EVP_DigestFinal_ex(&c, mask + outlen, NULL)) {
+ goto err;
+ }
+ outlen += mdlen;
+ } else {
+ if (!EVP_DigestFinal_ex(&c, md, NULL)) {
+ goto err;
+ }
+ memcpy(mask + outlen, md, len - outlen);
+ outlen = len;
+ }
+ }
+ ret = 0;
+
+err:
+ EVP_MD_CTX_cleanup(&c);
+ return ret;
+}
+
+int RSA_padding_add_PKCS1_OAEP_mgf1(uint8_t *to, unsigned tlen,
+ const uint8_t *from, unsigned flen,
+ const uint8_t *param, unsigned plen,
+ const EVP_MD *md, const EVP_MD *mgf1md) {
+ unsigned i, emlen = tlen - 1, mdlen;
+ uint8_t *db, *seed;
+ uint8_t *dbmask = NULL, seedmask[SHA_DIGEST_LENGTH];
+ int ret = 0;
+
+ if (md == NULL) {
+ md = EVP_sha1();
+ }
+ if (mgf1md == NULL) {
+ mgf1md = md;
+ }
+
+ mdlen = EVP_MD_size(md);
+
+ if (flen > emlen - 2 * mdlen - 1) {
+ OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_OAEP_mgf1,
+ 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);
+ return 0;
+ }
+
+ to[0] = 0;
+ seed = to + 1;
+ db = to + mdlen + 1;
+
+ if (!EVP_Digest((void *)param, plen, db, NULL, md, NULL)) {
+ return 0;
+ }
+ memset(db + mdlen, 0, emlen - flen - 2 * mdlen - 1);
+ db[emlen - flen - mdlen - 1] = 0x01;
+ memcpy(db + emlen - flen - mdlen, from, (unsigned int)flen);
+ if (RAND_pseudo_bytes(seed, mdlen) <= 0) {
+ return 0;
+ }
+
+ dbmask = OPENSSL_malloc(emlen - mdlen);
+ if (dbmask == NULL) {
+ OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_OAEP_mgf1,
+ ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ if (PKCS1_MGF1(dbmask, emlen - mdlen, seed, mdlen, mgf1md) < 0) {
+ goto out;
+ }
+ for (i = 0; i < emlen - mdlen; i++) {
+ db[i] ^= dbmask[i];
+ }
+
+ if (PKCS1_MGF1(seedmask, mdlen, db, emlen - mdlen, mgf1md) < 0) {
+ goto out;
+ }
+ for (i = 0; i < SHA_DIGEST_LENGTH; i++) {
+ seed[i] ^= seedmask[i];
+ }
+ ret = 1;
+
+out:
+ if (dbmask != NULL) {
+ OPENSSL_free(dbmask);
+ }
+ return ret;
+}
+
+int RSA_padding_check_PKCS1_OAEP_mgf1(uint8_t *to, unsigned tlen,
+ const uint8_t *from, unsigned flen,
+ unsigned num, const uint8_t *param,
+ unsigned plen, const EVP_MD *md,
+ const EVP_MD *mgf1md) {
+ unsigned i, dblen, mlen = -1, bad, mdlen;
+ const uint8_t *maskeddb;
+ unsigned lzero;
+ uint8_t *db = NULL, seed[SHA_DIGEST_LENGTH], phash[SHA_DIGEST_LENGTH];
+ uint8_t *padded_from;
+
+ if (md == NULL) {
+ md = EVP_sha1();
+ }
+ if (mgf1md == NULL) {
+ mgf1md = md;
+ }
+
+ mdlen = EVP_MD_size(md);
+
+ if (--num < 2 * mdlen + 1) {
+ /* 'num' is the length of the modulus, i.e. does not depend on the
+ * particular ciphertext. */
+ goto decoding_err;
+ }
+
+ /* TODO(fork): this code differs significantly between 1.0.1 and 1.0.2. We
+ * need to understand why and pick the best one. */
+
+ /* lzero is the number of leading zeros. We must not leak in the case
+ * that this is negative. See James H. Manger, "A Chosen Ciphertext
+ * Attack on RSA Optimal Asymmetric Encryption Padding (OAEP) [...]",
+ * CRYPTO 2001). */
+ lzero = num - flen;
+ /* If lzero is negative then the MSB will be set and this arithmetic
+ * right shift will set bad to all ones. Otherwise it'll be all
+ * zeros. */
+ bad = ((int)lzero) >> (sizeof(int) * 8 - 1);
+ lzero &= ~bad;
+ flen = (bad & num) | (~bad & flen);
+
+ dblen = num - mdlen;
+ db = OPENSSL_malloc(dblen + num);
+ if (db == NULL) {
+ OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_OAEP_mgf1,
+ ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+
+ /* Always do this zero-padding copy (even when lzero == 0) to avoid
+ * leaking timing info about the value of lzero. This sadly leaks
+ * side-channel information, but it's not possible to have a fixed
+ * memory access pattern since we can't read out of the bounds of
+ * |from|. */
+ padded_from = db + dblen;
+ memset(padded_from, 0, num);
+ memcpy(padded_from + lzero, from, flen);
+
+ maskeddb = padded_from + mdlen;
+
+ if (PKCS1_MGF1(seed, mdlen, maskeddb, dblen, mgf1md)) {
+ return -1;
+ }
+ for (i = 0; i < mdlen; i++) {
+ seed[i] ^= padded_from[i];
+ }
+
+ if (PKCS1_MGF1(db, dblen, seed, mdlen, mgf1md)) {
+ return -1;
+ }
+ for (i = 0; i < dblen; i++) {
+ db[i] ^= maskeddb[i];
+ }
+
+ if (!EVP_Digest((void *)param, plen, phash, NULL, md, NULL)) {
+ return -1;
+ }
+
+ if (CRYPTO_memcmp(db, phash, mdlen) != 0 || bad) {
+ goto decoding_err;
+ } else {
+ /* At this point we consider timing side-channels to be moot
+ * because the plaintext contained the correct phash. */
+ for (i = mdlen; i < dblen; i++) {
+ if (db[i] != 0x00) {
+ break;
+ }
+ }
+
+ if (i == dblen || db[i] != 0x01) {
+ goto decoding_err;
+ } else {
+ /* everything looks OK */
+
+ mlen = dblen - ++i;
+ if (tlen < mlen) {
+ OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_OAEP_mgf1,
+ RSA_R_DATA_TOO_LARGE);
+ mlen = -1;
+ } else {
+ memcpy(to, db + i, mlen);
+ }
+ }
+ }
+
+ OPENSSL_free(db);
+ return mlen;
+
+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);
+ if (db != NULL) {
+ OPENSSL_free(db);
+ }
+ return -1;
+}
+
+int RSA_padding_add_PKCS1_OAEP(uint8_t *to, unsigned tlen,
+ const uint8_t *from, unsigned flen,
+ const uint8_t *param, unsigned plen) {
+ return RSA_padding_add_PKCS1_OAEP_mgf1(to, tlen, from, flen, param, plen,
+ NULL, NULL);
+}
+
+int RSA_padding_check_PKCS1_OAEP(uint8_t *to, unsigned tlen,
+ const uint8_t *from, unsigned flen,
+ unsigned num, const uint8_t *param,
+ unsigned plen) {
+ return RSA_padding_check_PKCS1_OAEP_mgf1(to, tlen, from, flen, num, param,
+ plen, NULL, NULL);
+}
+
+static const unsigned char zeroes[] = {0,0,0,0,0,0,0,0};
+
+int RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const uint8_t *mHash,
+ const EVP_MD *Hash, const EVP_MD *mgf1Hash,
+ const uint8_t *EM, int sLen) {
+ int i;
+ int ret = 0;
+ int maskedDBLen, MSBits, emLen;
+ size_t hLen;
+ const uint8_t *H;
+ uint8_t *DB = NULL;
+ EVP_MD_CTX ctx;
+ uint8_t H_[EVP_MAX_MD_SIZE];
+ EVP_MD_CTX_init(&ctx);
+
+ if (mgf1Hash == NULL) {
+ mgf1Hash = Hash;
+ }
+
+ hLen = EVP_MD_size(Hash);
+
+ /* Negative sLen has special meanings:
+ * -1 sLen == hLen
+ * -2 salt length is autorecovered from signature
+ * -N reserved */
+ if (sLen == -1) {
+ sLen = hLen;
+ } else if (sLen == -2) {
+ sLen = -2;
+ } else if (sLen < -2) {
+ OPENSSL_PUT_ERROR(RSA, RSA_verify_PKCS1_PSS_mgf1, 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);
+ goto err;
+ }
+ if (MSBits == 0) {
+ EM++;
+ emLen--;
+ }
+ 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);
+ goto err;
+ }
+ if (EM[emLen - 1] != 0xbc) {
+ OPENSSL_PUT_ERROR(RSA, RSA_verify_PKCS1_PSS_mgf1, 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);
+ goto err;
+ }
+ if (PKCS1_MGF1(DB, maskedDBLen, H, hLen, mgf1Hash) < 0) {
+ goto err;
+ }
+ for (i = 0; i < maskedDBLen; i++) {
+ DB[i] ^= EM[i];
+ }
+ if (MSBits) {
+ DB[0] &= 0xFF >> (8 - MSBits);
+ }
+ for (i = 0; DB[i] == 0 && i < (maskedDBLen - 1); i++)
+ ;
+ if (DB[i++] != 0x1) {
+ OPENSSL_PUT_ERROR(RSA, RSA_verify_PKCS1_PSS_mgf1,
+ 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);
+ goto err;
+ }
+ if (!EVP_DigestInit_ex(&ctx, Hash, NULL) ||
+ !EVP_DigestUpdate(&ctx, zeroes, sizeof zeroes) ||
+ !EVP_DigestUpdate(&ctx, mHash, hLen)) {
+ goto err;
+ }
+ if (maskedDBLen - i) {
+ if (!EVP_DigestUpdate(&ctx, DB + i, maskedDBLen - i)) {
+ goto err;
+ }
+ }
+ if (!EVP_DigestFinal_ex(&ctx, H_, NULL)) {
+ goto err;
+ }
+ if (memcmp(H_, H, hLen)) {
+ OPENSSL_PUT_ERROR(RSA, RSA_verify_PKCS1_PSS_mgf1, RSA_R_BAD_SIGNATURE);
+ ret = 0;
+ } else {
+ ret = 1;
+ }
+
+err:
+ if (DB) {
+ OPENSSL_free(DB);
+ }
+ EVP_MD_CTX_cleanup(&ctx);
+
+ return ret;
+}
+
+int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, unsigned char *EM,
+ const unsigned char *mHash,
+ const EVP_MD *Hash, const EVP_MD *mgf1Hash,
+ int sLen) {
+ int i;
+ int ret = 0;
+ int maskedDBLen, MSBits, emLen;
+ size_t hLen;
+ unsigned char *H, *salt = NULL, *p;
+ EVP_MD_CTX ctx;
+
+ if (mgf1Hash == NULL) {
+ mgf1Hash = Hash;
+ }
+
+ hLen = EVP_MD_size(Hash);
+
+ /* Negative sLen has special meanings:
+ * -1 sLen == hLen
+ * -2 salt length is maximized
+ * -N reserved */
+ if (sLen == -1) {
+ sLen = hLen;
+ } 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);
+ goto err;
+ }
+
+ MSBits = (BN_num_bits(rsa->n) - 1) & 0x7;
+ emLen = RSA_size(rsa);
+ if (MSBits == 0) {
+ *EM++ = 0;
+ emLen--;
+ }
+ if (sLen == -2) {
+ 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);
+ 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);
+ goto err;
+ }
+ if (RAND_pseudo_bytes(salt, sLen) <= 0) {
+ goto err;
+ }
+ }
+ maskedDBLen = emLen - hLen - 1;
+ H = EM + maskedDBLen;
+ EVP_MD_CTX_init(&ctx);
+ if (!EVP_DigestInit_ex(&ctx, Hash, NULL) ||
+ !EVP_DigestUpdate(&ctx, zeroes, sizeof zeroes) ||
+ !EVP_DigestUpdate(&ctx, mHash, hLen)) {
+ goto err;
+ }
+ if (sLen && !EVP_DigestUpdate(&ctx, salt, sLen)) {
+ goto err;
+ }
+ if (!EVP_DigestFinal_ex(&ctx, H, NULL)) {
+ goto err;
+ }
+ EVP_MD_CTX_cleanup(&ctx);
+
+ /* Generate dbMask in place then perform XOR on it */
+ if (PKCS1_MGF1(EM, maskedDBLen, H, hLen, mgf1Hash)) {
+ goto err;
+ }
+
+ p = EM;
+
+ /* Initial PS XORs with all zeroes which is a NOP so just update
+ * pointer. Note from a test above this value is guaranteed to
+ * be non-negative. */
+ p += emLen - sLen - hLen - 2;
+ *p++ ^= 0x1;
+ if (sLen > 0) {
+ for (i = 0; i < sLen; i++) {
+ *p++ ^= salt[i];
+ }
+ }
+ if (MSBits) {
+ EM[0] &= 0xFF >> (8 - MSBits);
+ }
+
+ /* H is already in place so just set final 0xbc */
+
+ EM[emLen - 1] = 0xbc;
+
+ ret = 1;
+
+err:
+ if (salt) {
+ OPENSSL_free(salt);
+ }
+
+ return ret;
+}
diff --git a/crypto/rsa/rsa.c b/crypto/rsa/rsa.c
new file mode 100644
index 0000000..061bc49c
--- /dev/null
+++ b/crypto/rsa/rsa.c
@@ -0,0 +1,488 @@
+/* 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 <openssl/bn.h>
+#include <openssl/engine.h>
+#include <openssl/err.h>
+#include <openssl/ex_data.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+
+#include "internal.h"
+
+
+extern const RSA_METHOD RSA_default_method;
+
+RSA *RSA_new(void) { return RSA_new_method(NULL); }
+
+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);
+ return NULL;
+ }
+
+ memset(rsa, 0, sizeof(RSA));
+
+ if (engine) {
+ rsa->meth = ENGINE_get_RSA_method(engine);
+ }
+
+ if (rsa->meth == NULL) {
+ rsa->meth = (RSA_METHOD*) &RSA_default_method;
+ }
+ METHOD_ref(rsa->meth);
+
+ rsa->references = 1;
+ rsa->flags = rsa->meth->flags;
+
+ if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_RSA, rsa, &rsa->ex_data)) {
+ METHOD_unref(rsa->meth);
+ OPENSSL_free(rsa);
+ return NULL;
+ }
+
+ if (rsa->meth->init && !rsa->meth->init(rsa)) {
+ CRYPTO_free_ex_data(CRYPTO_EX_INDEX_RSA, rsa, &rsa->ex_data);
+ METHOD_unref(rsa->meth);
+ OPENSSL_free(rsa);
+ return NULL;
+ }
+
+ return rsa;
+}
+
+void RSA_free(RSA *rsa) {
+ unsigned u;
+
+ if (rsa == NULL) {
+ return;
+ }
+
+ if (CRYPTO_add(&rsa->references, -1, CRYPTO_LOCK_RSA) > 0) {
+ return;
+ }
+
+ if (rsa->meth->finish) {
+ rsa->meth->finish(rsa);
+ }
+ METHOD_unref(rsa->meth);
+
+ CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DSA, rsa, &rsa->ex_data);
+
+ if (rsa->n != NULL)
+ BN_clear_free(rsa->n);
+ if (rsa->e != NULL)
+ BN_clear_free(rsa->e);
+ if (rsa->d != NULL)
+ BN_clear_free(rsa->d);
+ if (rsa->p != NULL)
+ BN_clear_free(rsa->p);
+ if (rsa->q != NULL)
+ BN_clear_free(rsa->q);
+ if (rsa->dmp1 != NULL)
+ BN_clear_free(rsa->dmp1);
+ if (rsa->dmq1 != NULL)
+ BN_clear_free(rsa->dmq1);
+ if (rsa->iqmp != NULL)
+ BN_clear_free(rsa->iqmp);
+ for (u = 0; u < rsa->num_blindings; u++) {
+ BN_BLINDING_free(rsa->blindings[u]);
+ }
+ if (rsa->blindings != NULL)
+ OPENSSL_free(rsa->blindings);
+ if (rsa->blindings_inuse != NULL)
+ OPENSSL_free(rsa->blindings_inuse);
+ OPENSSL_free(rsa);
+}
+
+int RSA_up_ref(RSA *rsa) {
+ CRYPTO_add(&rsa->references, 1, CRYPTO_LOCK_RSA);
+ return 1;
+}
+
+int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb) {
+ if (rsa->meth->keygen) {
+ return rsa->meth->keygen(rsa, bits, e_value, cb);
+ }
+
+ return RSA_default_method.keygen(rsa, bits, 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) {
+ return rsa->meth->encrypt(rsa, out_len, out, max_out, in, in_len, padding);
+ }
+
+ return RSA_default_method.encrypt(rsa, out_len, out, max_out, in, in_len,
+ padding);
+}
+
+int RSA_public_encrypt(int flen, const uint8_t *from, uint8_t *to, RSA *rsa,
+ int padding) {
+ size_t out_len;
+
+ if (!RSA_encrypt(rsa, &out_len, to, RSA_size(rsa), from, flen, padding)) {
+ return -1;
+ }
+
+ return out_len;
+}
+
+int RSA_sign_raw(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->sign_raw) {
+ return rsa->meth->sign_raw(rsa, out_len, out, max_out, in, in_len, padding);
+ }
+
+ return RSA_default_method.sign_raw(rsa, out_len, out, max_out, in, in_len,
+ padding);
+}
+
+int RSA_private_encrypt(int flen, const uint8_t *from, uint8_t *to, RSA *rsa,
+ int padding) {
+ size_t out_len;
+
+ if (!RSA_sign_raw(rsa, &out_len, to, RSA_size(rsa), from, flen, padding)) {
+ return -1;
+ }
+
+ return out_len;
+}
+
+int RSA_decrypt(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->decrypt) {
+ return rsa->meth->decrypt(rsa, out_len, out, max_out, in, in_len, padding);
+ }
+
+ return RSA_default_method.decrypt(rsa, out_len, out, max_out, in, in_len,
+ padding);
+}
+
+int RSA_private_decrypt(int flen, const uint8_t *from, uint8_t *to, RSA *rsa,
+ int padding) {
+ size_t out_len;
+
+ if (!RSA_decrypt(rsa, &out_len, to, RSA_size(rsa), from, flen, padding)) {
+ return -1;
+ }
+
+ return out_len;
+}
+
+int RSA_verify_raw(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->verify_raw) {
+ return rsa->meth->verify_raw(rsa, out_len, out, max_out, in, in_len, padding);
+ }
+
+ return RSA_default_method.verify_raw(rsa, out_len, out, max_out, in, in_len,
+ padding);
+}
+
+int RSA_public_decrypt(int flen, const uint8_t *from, uint8_t *to, RSA *rsa,
+ int padding) {
+ size_t out_len;
+
+ if (!RSA_verify_raw(rsa, &out_len, to, RSA_size(rsa), from, flen, padding)) {
+ return -1;
+ }
+
+ return out_len;
+}
+
+unsigned RSA_size(const RSA *rsa) {
+ return BN_num_bytes(rsa->n);
+}
+
+int RSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+ CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) {
+ return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_RSA, argl, argp, new_func,
+ dup_func, free_func);
+}
+
+int RSA_set_ex_data(RSA *d, int idx, void *arg) {
+ return CRYPTO_set_ex_data(&d->ex_data, idx, arg);
+}
+
+void *RSA_get_ex_data(const RSA *d, int idx) {
+ return CRYPTO_get_ex_data(&d->ex_data, idx);
+}
+
+/* SSL_SIG_LENGTH is the size of an SSL/TLS (prior to TLS 1.2) signature: it's
+ * the length of an MD5 and SHA1 hash. */
+static const unsigned SSL_SIG_LENGTH = 36;
+
+/* pkcs1_sig_prefix contains the ASN.1, DER encoded prefix for a hash that is
+ * to be signed with PKCS#1. */
+struct pkcs1_sig_prefix {
+ /* nid identifies the hash function. */
+ int nid;
+ /* len is the number of bytes of |bytes| which are valid. */
+ uint8_t len;
+ /* bytes contains the DER bytes. */
+ uint8_t bytes[19];
+};
+
+/* kPKCS1SigPrefixes contains the ASN.1 prefixes for PKCS#1 signatures with
+ * different hash functions. */
+static const struct pkcs1_sig_prefix kPKCS1SigPrefixes[] = {
+ {
+ NID_md5,
+ 18,
+ {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x02, 0x05, 0x05, 0x00, 0x04, 0x10},
+ },
+ {
+ NID_sha1,
+ 15,
+ {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05,
+ 0x00, 0x04, 0x14},
+ },
+ {
+ NID_sha224,
+ 19,
+ {0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
+ 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1c},
+ },
+ {
+ NID_sha256,
+ 19,
+ {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
+ 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20},
+ },
+ {
+ NID_sha384,
+ 19,
+ {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
+ 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30},
+ },
+ {
+ NID_sha512,
+ 19,
+ {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
+ 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40},
+ },
+ {
+ NID_ripemd160,
+ 14,
+ {0x30, 0x20, 0x30, 0x08, 0x06, 0x06, 0x28, 0xcf, 0x06, 0x03, 0x00, 0x31,
+ 0x04, 0x14},
+ },
+ {
+ NID_undef, 0, {0},
+ },
+};
+
+/* 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) {
+ unsigned i;
+ const uint8_t* prefix = NULL;
+ unsigned prefix_len;
+ uint8_t *signed_msg;
+ unsigned signed_msg_len;
+
+ if (hash_nid == NID_md5_sha1) {
+ /* Special case: SSL signature, just check the length. */
+ if (msg_len != SSL_SIG_LENGTH) {
+ OPENSSL_PUT_ERROR(RSA, RSA_sign, RSA_R_INVALID_MESSAGE_LENGTH);
+ return 0;
+ }
+
+ *out_msg = (uint8_t*) msg;
+ *out_msg_len = SSL_SIG_LENGTH;
+ *is_alloced = 0;
+ return 1;
+ }
+
+ for (i = 0; kPKCS1SigPrefixes[i].nid != NID_undef; i++) {
+ const struct pkcs1_sig_prefix *sig_prefix = &kPKCS1SigPrefixes[i];
+ if (sig_prefix->nid == hash_nid) {
+ prefix = sig_prefix->bytes;
+ prefix_len = sig_prefix->len;
+ break;
+ }
+ }
+
+ if (prefix == NULL) {
+ OPENSSL_PUT_ERROR(RSA, RSA_sign, RSA_R_UNKNOWN_ALGORITHM_TYPE);
+ return 0;
+ }
+
+ signed_msg_len = prefix_len + msg_len;
+ if (signed_msg_len < prefix_len) {
+ OPENSSL_PUT_ERROR(RSA, RSA_sign, RSA_R_TOO_LONG);
+ return 0;
+ }
+
+ signed_msg = OPENSSL_malloc(signed_msg_len);
+ if (!signed_msg) {
+ OPENSSL_PUT_ERROR(RSA, RSA_sign, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ memcpy(signed_msg, prefix, prefix_len);
+ memcpy(signed_msg + prefix_len, msg, msg_len);
+
+ *out_msg = signed_msg;
+ *out_msg_len = signed_msg_len;
+ *is_alloced = 1;
+
+ return 1;
+}
+
+int RSA_sign(int hash_nid, const uint8_t *in, unsigned in_len, uint8_t *out,
+ unsigned *out_len, RSA *rsa) {
+ const unsigned rsa_size = RSA_size(rsa);
+ int ret = 0;
+ uint8_t *signed_msg;
+ size_t signed_msg_len;
+ int signed_msg_is_alloced = 0;
+ size_t size_t_out_len;
+
+ if (rsa->meth->sign) {
+ 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)) {
+ 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);
+ goto finish;
+ }
+
+ if (RSA_sign_raw(rsa, &size_t_out_len, out, rsa_size, signed_msg,
+ signed_msg_len, RSA_PKCS1_PADDING)) {
+ *out_len = size_t_out_len;
+ ret = 1;
+ }
+
+finish:
+ if (signed_msg_is_alloced) {
+ OPENSSL_free(signed_msg);
+ }
+ return ret;
+}
+
+int RSA_verify(int hash_nid, const uint8_t *msg, size_t msg_len,
+ const uint8_t *sig, size_t sig_len, RSA *rsa) {
+ const size_t rsa_size = RSA_size(rsa);
+ uint8_t *buf = NULL;
+ int ret = 0;
+ uint8_t *signed_msg = NULL;
+ size_t signed_msg_len, len;
+ int signed_msg_is_alloced = 0;
+
+ if (rsa->meth->verify) {
+ return rsa->meth->verify(hash_nid, msg, msg_len, sig, sig_len, rsa);
+ }
+
+ if (sig_len != rsa_size) {
+ OPENSSL_PUT_ERROR(RSA, RSA_verify, 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);
+ return 0;
+ }
+
+ buf = OPENSSL_malloc(rsa_size);
+ if (!buf) {
+ OPENSSL_PUT_ERROR(RSA, RSA_verify, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ if (!RSA_verify_raw(rsa, &len, buf, rsa_size, sig, sig_len,
+ RSA_PKCS1_PADDING)) {
+ goto out;
+ }
+
+ if (!pkcs1_prefixed_msg(&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);
+ goto out;
+ }
+
+ ret = 1;
+
+out:
+ if (buf != NULL) {
+ OPENSSL_free(buf);
+ }
+ if (signed_msg_is_alloced) {
+ OPENSSL_free(signed_msg);
+ }
+ return ret;
+}
diff --git a/crypto/rsa/rsa.h b/crypto/rsa/rsa.h
new file mode 100644
index 0000000..27bc04a
--- /dev/null
+++ b/crypto/rsa/rsa.h
@@ -0,0 +1,459 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_RSA_H
+#define OPENSSL_HEADER_RSA_H
+
+#include <openssl/base.h>
+
+#include <openssl/engine.h>
+#include <openssl/ex_data.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* rsa.h contains functions for handling encryption and signature using RSA. */
+
+
+/* Allocation and destruction. */
+
+/* RSA_new returns a new, empty RSA object or NULL on error. */
+RSA *RSA_new(void);
+
+/* RSA_new_method acts the same as |DH_new| but takes an explicit |ENGINE|. */
+RSA *RSA_new_method(const ENGINE *engine);
+
+/* RSA_free decrements the reference count of |rsa| and frees it if the
+ * reference count drops to zero. */
+void RSA_free(RSA *rsa);
+
+/* RSA_up_ref increments the reference count of |rsa|. */
+int RSA_up_ref(RSA *rsa);
+
+
+/* Key generation. */
+
+/* RSA_generate_key_ex generates a new RSA key where the modulus has size
+ * |bits| and the public exponent is |e|. If unsure, |RSA_F4| is a good value
+ * for |e|. If |cb| is not NULL then it is called during the key generation
+ * process. In addition to the calls documented for |BN_generate_prime_ex|, it
+ * is called with event=2 when the n'th prime is rejected as unsuitable and
+ * with event=3 when a suitable value for |p| is found. */
+int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb);
+
+
+/* Encryption / Decryption */
+
+/* Padding types for encryption. */
+#define RSA_PKCS1_PADDING 1
+#define RSA_SSLV23_PADDING 2
+#define RSA_NO_PADDING 3
+#define RSA_PKCS1_OAEP_PADDING 4
+/* RSA_PKCS1_PSS_PADDING can only be used via the EVP interface. */
+#define RSA_PKCS1_PSS_PADDING 6
+
+/* RSA_encrypt encrypts |in_len| bytes from |in| to the public key from |rsa|
+ * and writes, at most, |max_out| bytes of encrypted data to |out|. The
+ * |max_out| argument must be, at least, |RSA_size| in order to ensure success.
+ *
+ * It returns 1 on success or zero on error.
+ *
+ * The |padding| argument must be one of the |RSA_*_PADDING| values. If in
+ * doubt, |RSA_PKCS1_PADDING| is the most common but |RSA_PKCS1_OAEP_PADDING|
+ * is the most secure. */
+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);
+
+/* RSA_decrypt decrypts |in_len| bytes from |in| with the private key from
+ * |rsa| and writes, at most, |max_out| bytes of plaintext to |out|. The
+ * |max_out| argument must be, at least, |RSA_size| in order to ensure success.
+ *
+ * It returns 1 on success or zero on error.
+ *
+ * The |padding| argument must be one of the |RSA_*_PADDING| values. If in
+ * doubt, |RSA_PKCS1_PADDING| is the most common but |RSA_PKCS1_OAEP_PADDING|
+ * is the most secure. */
+int RSA_decrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
+ const uint8_t *in, size_t in_len, int padding);
+
+/* RSA_public_encrypt encrypts |flen| bytes from |from| to the public key in
+ * |rsa| and writes the encrypted data to |to|. The |to| buffer must have at
+ * least |RSA_size| bytes of space. It returns the number of bytes written, or
+ * -1 on error. The |padding| argument must be one of the |RSA_*_PADDING|
+ * values. If in doubt, |RSA_PKCS1_PADDING| is the most common but
+ * |RSA_PKCS1_OAEP_PADDING| is the most secure.
+ *
+ * WARNING: this function is dangerous because it breaks the usual return value
+ * convention. Use |RSA_encrypt| instead. */
+int RSA_public_encrypt(int flen, const uint8_t *from, uint8_t *to, RSA *rsa,
+ int padding);
+
+/* RSA_private_decrypt decrypts |flen| bytes from |from| with the public key in
+ * |rsa| and writes the plaintext to |to|. The |to| buffer must have at
+ * least |RSA_size| bytes of space. It returns the number of bytes written, or
+ * -1 on error. The |padding| argument must be one of the |RSA_*_PADDING|
+ * values. If in doubt, |RSA_PKCS1_PADDING| is the most common but
+ * |RSA_PKCS1_OAEP_PADDING| is the most secure.
+ *
+ * WARNING: this function is dangerous because it breaks the usual return value
+ * convention. Use |RSA_decrypt| instead. */
+int RSA_private_decrypt(int flen, const uint8_t *from, uint8_t *to, RSA *rsa,
+ int padding);
+
+
+/* Signing / Verification */
+
+/* RSA_sign signs |in_len| bytes of digest from |in| with |rsa| and writes, at
+ * most, |RSA_size(rsa)| bytes to |out|. On successful return, the actual
+ * number of bytes written is written to |*out_len|.
+ *
+ * The |hash_nid| argument identifies the hash function used to calculate |in|
+ * and is embedded in the resulting signature. For example, it might be
+ * |NID_sha256|.
+ *
+ * It returns 1 on success and zero on error. */
+int RSA_sign(int hash_nid, const uint8_t *in, unsigned int in_len, uint8_t *out,
+ unsigned int *out_len, RSA *rsa);
+
+/* RSA_sign_raw signs |in_len| bytes from |in| with the public key from |rsa|
+ * and writes, at most, |max_out| bytes of encrypted data to |out|. The
+ * |max_out| argument must be, at least, |RSA_size| in order to ensure success.
+ *
+ * It returns 1 on success or zero on error.
+ *
+ * The |padding| argument must be one of the |RSA_*_PADDING| values. If in
+ * doubt, |RSA_PKCS1_PADDING| is the most common. */
+int RSA_sign_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
+ const uint8_t *in, size_t in_len, int padding);
+
+/* RSA_verify verifies that |sig_len| bytes from |sig| are a valid, PKCS#1
+ * signature of |msg_len| bytes at |msg| by |rsa|.
+ *
+ * The |hash_nid| argument identifies the hash function used to calculate |in|
+ * and is embedded in the resulting signature in order to prevent hash
+ * confusion attacks. For example, it might be |NID_sha256|.
+ *
+ * It returns one if the signature is valid and zero otherwise.
+ *
+ * WARNING: this differs from the original, OpenSSL function which additionally
+ * returned -1 on error. */
+int RSA_verify(int hash_nid, const uint8_t *msg, size_t msg_len,
+ const uint8_t *sig, size_t sig_len, RSA *rsa);
+
+/* RSA_verify_raw verifies |in_len| bytes of signature from |in| using the
+ * public key from |rsa| and writes, at most, |max_out| bytes of plaintext to
+ * |out|. The |max_out| argument must be, at least, |RSA_size| in order to
+ * ensure success.
+ *
+ * It returns 1 on success or zero on error.
+ *
+ * The |padding| argument must be one of the |RSA_*_PADDING| values. If in
+ * doubt, |RSA_PKCS1_PADDING| is the most common. */
+int RSA_verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
+ const uint8_t *in, size_t in_len, int padding);
+
+/* RSA_private_encrypt encrypts |flen| bytes from |from| with the private key in
+ * |rsa| and writes the encrypted data to |to|. The |to| buffer must have at
+ * least |RSA_size| bytes of space. It returns the number of bytes written, or
+ * -1 on error. The |padding| argument must be one of the |RSA_*_PADDING|
+ * values. If in doubt, |RSA_PKCS1_PADDING| is the most common.
+ *
+ * WARNING: this function is dangerous because it breaks the usual return value
+ * convention. Use |RSA_sign_raw| instead. */
+int RSA_private_encrypt(int flen, const uint8_t *from, uint8_t *to, RSA *rsa,
+ int padding);
+
+/* RSA_private_encrypt verifies |flen| bytes of signature from |from| using the
+ * public key in |rsa| and writes the plaintext to |to|. The |to| buffer must
+ * have at least |RSA_size| bytes of space. It returns the number of bytes
+ * written, or -1 on error. The |padding| argument must be one of the
+ * |RSA_*_PADDING| values. If in doubt, |RSA_PKCS1_PADDING| is the most common.
+ *
+ * WARNING: this function is dangerous because it breaks the usual return value
+ * convention. Use |RSA_verify_raw| instead. */
+int RSA_public_decrypt(int flen, const uint8_t *from, uint8_t *to, RSA *rsa,
+ int padding);
+
+
+/* Utility functions. */
+
+/* RSA_size returns the number of bytes in the modulus, which is also the size
+ * of a signature of encrypted value using |rsa|. */
+unsigned RSA_size(const RSA *rsa);
+
+/* RSAPublicKey_dup allocates a fresh |RSA| and copies the private key from
+ * |rsa| into it. It returns the fresh |RSA| object, or NULL on error. */
+RSA *RSAPublicKey_dup(const RSA *rsa);
+
+/* RSAPrivateKey_dup allocates a fresh |RSA| and copies the private key from
+ * |rsa| into it. It returns the fresh |RSA| object, or NULL on error. */
+RSA *RSAPrivateKey_dup(const RSA *rsa);
+
+
+/* ASN.1 functions. */
+
+/* d2i_RSAPublicKey parses an ASN.1, DER-encoded, RSA public key from |len|
+ * bytes at |*inp|. If |out| is not NULL then, on exit, a pointer to the result
+ * is in |*out|. If |*out| is already non-NULL on entry then the result is
+ * written directly into |*out|, otherwise a fresh |RSA| is allocated. On
+ * successful exit, |*inp| is advanced past the DER structure. It returns the
+ * result or NULL on error. */
+RSA *d2i_RSAPublicKey(RSA **out, const uint8_t **inp, long len);
+
+/* i2d_RSAPublicKey marshals |in| to an ASN.1, DER structure. If |outp| is not
+ * NULL then the result is written to |*outp| and |*outp| is advanced just past
+ * the output. It returns the number of bytes in the result, whether written or
+ * not, or a negative value on error. */
+int i2d_RSAPublicKey(const RSA *in, uint8_t **outp);
+
+/* d2i_RSAPrivateKey parses an ASN.1, DER-encoded, RSA private key from |len|
+ * bytes at |*inp|. If |out| is not NULL then, on exit, a pointer to the result
+ * is in |*out|. If |*out| is already non-NULL on entry then the result is
+ * written directly into |*out|, otherwise a fresh |RSA| is allocated. On
+ * successful exit, |*inp| is advanced past the DER structure. It returns the
+ * result or NULL on error. */
+RSA *d2i_RSAPrivateKey(RSA **out, const uint8_t **inp, long len);
+
+/* i2d_RSAPrivateKey marshals |in| to an ASN.1, DER structure. If |outp| is not
+ * NULL then the result is written to |*outp| and |*outp| is advanced just past
+ * the output. It returns the number of bytes in the result, whether written or
+ * not, or a negative value on error. */
+int i2d_RSAPrivateKey(const RSA *in, uint8_t **outp);
+
+
+/* ex_data functions.
+ *
+ * These functions are wrappers. See |ex_data.h| for details. */
+
+int RSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+ CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+int RSA_set_ex_data(RSA *r, int idx, void *arg);
+void *RSA_get_ex_data(const RSA *r, int idx);
+
+
+/* RSA_FLAG_CACHE_PUBLIC causes a precomputed Montgomery context to be created,
+ * on demand, for the public key operations. */
+#define RSA_FLAG_CACHE_PUBLIC 2
+
+/* RSA_FLAG_CACHE_PRIVATE causes a precomputed Montgomery context to be
+ * created, on demand, for the private key operations. */
+#define RSA_FLAG_CACHE_PRIVATE 4
+
+/* RSA_FLAG_NO_BLINDING disables blinding of private operations. */
+#define RSA_FLAG_NO_BLINDING 8
+
+/* RSA_FLAG_EXT_PKEY means that private key operations will be handled by
+ * |mod_exp| and that they do not depend on the private key components being
+ * present: for example a key stored in external hardware. */
+#define RSA_FLAG_EXT_PKEY 0x20
+
+/* RSA_FLAG_SIGN_VER causes the |sign| and |verify| functions of |rsa_meth_st|
+ * to be called when set. */
+#define RSA_FLAG_SIGN_VER 0x40
+
+
+/* RSA public exponent values. */
+
+#define RSA_3 0x3
+#define RSA_F4 0x10001
+
+
+struct rsa_meth_st {
+ struct openssl_method_common_st common;
+
+ void *app_data;
+
+ int (*init)(RSA *rsa);
+ int (*finish)(RSA *rsa);
+
+ int (*sign)(int type, const uint8_t *m, unsigned int m_length,
+ uint8_t *sigret, unsigned int *siglen, const RSA *rsa);
+
+ int (*verify)(int dtype, const uint8_t *m, unsigned int m_length,
+ const uint8_t *sigbuf, unsigned int siglen, const RSA *rsa);
+
+
+ /* These functions mirror the |RSA_*| functions of the same name. */
+ int (*encrypt)(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
+ const uint8_t *in, size_t in_len, int padding);
+ int (*sign_raw)(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
+ const uint8_t *in, size_t in_len, int padding);
+
+ int (*decrypt)(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
+ const uint8_t *in, size_t in_len, int padding);
+ int (*verify_raw)(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
+ const uint8_t *in, size_t in_len, int padding);
+
+ int (*mod_exp)(BIGNUM *r0, const BIGNUM *I, RSA *rsa,
+ BN_CTX *ctx); /* Can be null */
+ int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+ const BIGNUM *m, BN_CTX *ctx,
+ BN_MONT_CTX *m_ctx);
+
+ int flags;
+
+ int (*keygen)(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb);
+};
+
+
+/* Private functions. */
+
+typedef struct bn_blinding_st BN_BLINDING;
+
+struct rsa_st {
+ /* version is only used during ASN.1 (de)serialisation. */
+ long version;
+ RSA_METHOD *meth;
+
+ BIGNUM *n;
+ BIGNUM *e;
+ BIGNUM *d;
+ BIGNUM *p;
+ BIGNUM *q;
+ BIGNUM *dmp1;
+ BIGNUM *dmq1;
+ BIGNUM *iqmp;
+ /* be careful using this if the RSA structure is shared */
+ CRYPTO_EX_DATA ex_data;
+ int references;
+ int flags;
+
+ /* Used to cache montgomery values */
+ BN_MONT_CTX *_method_mod_n;
+ BN_MONT_CTX *_method_mod_p;
+ BN_MONT_CTX *_method_mod_q;
+
+ /* num_blindings contains the size of the |blindings| and |blindings_inuse|
+ * arrays. This member and the |blindings_inuse| array are protected by
+ * CRYPTO_LOCK_RSA_BLINDING. */
+ unsigned num_blindings;
+ /* blindings is an array of BN_BLINDING structures that can be reserved by a
+ * thread by locking CRYPTO_LOCK_RSA_BLINDING and changing the corresponding
+ * element in |blindings_inuse| from 0 to 1. */
+ BN_BLINDING **blindings;
+ unsigned char *blindings_inuse;
+};
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#define RSA_F_RSA_padding_check_none 100
+#define RSA_F_RSA_padding_add_none 101
+#define RSA_F_RSA_padding_check_PKCS1_OAEP_mgf1 102
+#define RSA_F_RSA_verify_PKCS1_PSS_mgf1 103
+#define RSA_F_RSA_padding_add_PKCS1_PSS_mgf1 104
+#define RSA_F_RSA_verify 105
+#define RSA_F_rsa_setup_blinding 106
+#define RSA_F_verify_raw 107
+#define RSA_F_RSA_padding_add_PKCS1_type_1 108
+#define RSA_F_keygen 109
+#define RSA_F_RSA_padding_add_PKCS1_OAEP_mgf1 110
+#define RSA_F_pkcs1_prefixed_msg 111
+#define RSA_F_BN_BLINDING_update 112
+#define RSA_F_RSA_padding_check_SSLv23 113
+#define RSA_F_RSA_padding_add_SSLv23 114
+#define RSA_F_BN_BLINDING_new 115
+#define RSA_F_RSA_padding_add_PKCS1_type_2 116
+#define RSA_F_BN_BLINDING_convert_ex 117
+#define RSA_F_BN_BLINDING_invert_ex 118
+#define RSA_F_encrypt 119
+#define RSA_F_sign_raw 120
+#define RSA_F_RSA_new_method 121
+#define RSA_F_RSA_padding_check_PKCS1_type_1 122
+#define RSA_F_RSA_sign 123
+#define RSA_F_BN_BLINDING_create_param 124
+#define RSA_F_decrypt 125
+#define RSA_F_RSA_padding_check_PKCS1_type_2 126
+#define RSA_R_INVALID_MESSAGE_LENGTH 100
+#define RSA_R_DATA_GREATER_THAN_MOD_LEN 101
+#define RSA_R_NO_PUBLIC_EXPONENT 102
+#define RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE 103
+#define RSA_R_BLOCK_TYPE_IS_NOT_01 104
+#define RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE 105
+#define RSA_R_UNKNOWN_PADDING_TYPE 106
+#define RSA_R_TOO_MANY_ITERATIONS 107
+#define RSA_R_SLEN_RECOVERY_FAILED 108
+#define RSA_R_WRONG_SIGNATURE_LENGTH 109
+#define RSA_R_MODULUS_TOO_LARGE 110
+#define RSA_R_NULL_BEFORE_BLOCK_MISSING 111
+#define RSA_R_DATA_TOO_LARGE 112
+#define RSA_R_OUTPUT_BUFFER_TOO_SMALL 113
+#define RSA_R_SLEN_CHECK_FAILED 114
+#define RSA_R_FIRST_OCTET_INVALID 115
+#define RSA_R_BAD_E_VALUE 116
+#define RSA_R_DATA_TOO_LARGE_FOR_MODULUS 117
+#define RSA_R_EMPTY_PUBLIC_KEY 118
+#define RSA_R_BAD_PAD_BYTE_COUNT 119
+#define RSA_R_OAEP_DECODING_ERROR 120
+#define RSA_R_TOO_LONG 121
+#define RSA_R_BAD_FIXED_HEADER_DECRYPT 122
+#define RSA_R_DATA_TOO_SMALL 123
+#define RSA_R_UNKNOWN_ALGORITHM_TYPE 124
+#define RSA_R_PADDING_CHECK_FAILED 125
+#define RSA_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD 126
+#define RSA_R_BLOCK_TYPE_IS_NOT_02 127
+#define RSA_R_LAST_OCTET_INVALID 128
+#define RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY 129
+#define RSA_R_SSLV3_ROLLBACK_ATTACK 130
+#define RSA_R_KEY_SIZE_TOO_SMALL 131
+#define RSA_R_BAD_SIGNATURE 132
+#define RSA_R_BN_NOT_INITIALIZED 133
+
+#endif /* OPENSSL_HEADER_RSA_H */
diff --git a/crypto/rsa/rsa_asn1.c b/crypto/rsa/rsa_asn1.c
new file mode 100644
index 0000000..924cb8a
--- /dev/null
+++ b/crypto/rsa/rsa_asn1.c
@@ -0,0 +1,125 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2000.
+ */
+/* ====================================================================
+ * Copyright (c) 2000-2005 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/rsa.h>
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.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;
+ }
+ return 0;
+ } else if (operation == ASN1_OP_FREE_PRE) {
+ RSA_free((RSA *)*pval);
+ *pval = NULL;
+ return 2;
+ }
+ 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);
+
+ASN1_SEQUENCE_cb(RSAPublicKey, rsa_cb) = {
+ ASN1_SIMPLE(RSA, n, BIGNUM),
+ ASN1_SIMPLE(RSA, e, BIGNUM),
+} ASN1_SEQUENCE_END_cb(RSA, RSAPublicKey);
+
+ASN1_SEQUENCE(RSA_PSS_PARAMS) = {
+ ASN1_EXP_OPT(RSA_PSS_PARAMS, hashAlgorithm, X509_ALGOR,0),
+ ASN1_EXP_OPT(RSA_PSS_PARAMS, maskGenAlgorithm, X509_ALGOR,1),
+ ASN1_EXP_OPT(RSA_PSS_PARAMS, saltLength, ASN1_INTEGER,2),
+ ASN1_EXP_OPT(RSA_PSS_PARAMS, trailerField, ASN1_INTEGER,3),
+} ASN1_SEQUENCE_END(RSA_PSS_PARAMS);
+
+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);
+}
+
+RSA *RSAPrivateKey_dup(const RSA *rsa) {
+ return ASN1_item_dup(ASN1_ITEM_rptr(RSAPrivateKey), (RSA *) rsa);
+}
diff --git a/crypto/rsa/rsa_error.c b/crypto/rsa/rsa_error.c
new file mode 100644
index 0000000..d8b10d5
--- /dev/null
+++ b/crypto/rsa/rsa_error.c
@@ -0,0 +1,82 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/err.h>
+
+#include "rsa.h"
+
+const ERR_STRING_DATA RSA_error_string_data[] = {
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_BN_BLINDING_convert_ex, 0), "BN_BLINDING_convert_ex"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_BN_BLINDING_create_param, 0), "BN_BLINDING_create_param"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_BN_BLINDING_invert_ex, 0), "BN_BLINDING_invert_ex"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_BN_BLINDING_new, 0), "BN_BLINDING_new"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_BN_BLINDING_update, 0), "BN_BLINDING_update"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_new_method, 0), "RSA_new_method"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_padding_add_PKCS1_OAEP_mgf1, 0), "RSA_padding_add_PKCS1_OAEP_mgf1"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_padding_add_PKCS1_PSS_mgf1, 0), "RSA_padding_add_PKCS1_PSS_mgf1"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_padding_add_PKCS1_type_1, 0), "RSA_padding_add_PKCS1_type_1"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_padding_add_PKCS1_type_2, 0), "RSA_padding_add_PKCS1_type_2"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_padding_add_SSLv23, 0), "RSA_padding_add_SSLv23"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_padding_add_none, 0), "RSA_padding_add_none"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_padding_check_PKCS1_OAEP_mgf1, 0), "RSA_padding_check_PKCS1_OAEP_mgf1"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_padding_check_PKCS1_type_1, 0), "RSA_padding_check_PKCS1_type_1"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_padding_check_PKCS1_type_2, 0), "RSA_padding_check_PKCS1_type_2"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_padding_check_SSLv23, 0), "RSA_padding_check_SSLv23"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_padding_check_none, 0), "RSA_padding_check_none"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_sign, 0), "RSA_sign"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_verify, 0), "RSA_verify"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_verify_PKCS1_PSS_mgf1, 0), "RSA_verify_PKCS1_PSS_mgf1"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_decrypt, 0), "decrypt"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_encrypt, 0), "encrypt"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_keygen, 0), "keygen"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_pkcs1_prefixed_msg, 0), "pkcs1_prefixed_msg"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_rsa_setup_blinding, 0), "rsa_setup_blinding"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_sign_raw, 0), "sign_raw"},
+ {ERR_PACK(ERR_LIB_RSA, RSA_F_verify_raw, 0), "verify_raw"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_BAD_E_VALUE), "BAD_E_VALUE"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_BAD_FIXED_HEADER_DECRYPT), "BAD_FIXED_HEADER_DECRYPT"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_BAD_PAD_BYTE_COUNT), "BAD_PAD_BYTE_COUNT"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_BAD_SIGNATURE), "BAD_SIGNATURE"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_BLOCK_TYPE_IS_NOT_01), "BLOCK_TYPE_IS_NOT_01"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_BLOCK_TYPE_IS_NOT_02), "BLOCK_TYPE_IS_NOT_02"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_BN_NOT_INITIALIZED), "BN_NOT_INITIALIZED"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_DATA_GREATER_THAN_MOD_LEN), "DATA_GREATER_THAN_MOD_LEN"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_DATA_TOO_LARGE), "DATA_TOO_LARGE"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE), "DATA_TOO_LARGE_FOR_KEY_SIZE"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_DATA_TOO_LARGE_FOR_MODULUS), "DATA_TOO_LARGE_FOR_MODULUS"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_DATA_TOO_SMALL), "DATA_TOO_SMALL"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE), "DATA_TOO_SMALL_FOR_KEY_SIZE"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY), "DIGEST_TOO_BIG_FOR_RSA_KEY"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_EMPTY_PUBLIC_KEY), "EMPTY_PUBLIC_KEY"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_FIRST_OCTET_INVALID), "FIRST_OCTET_INVALID"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_INVALID_MESSAGE_LENGTH), "INVALID_MESSAGE_LENGTH"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_KEY_SIZE_TOO_SMALL), "KEY_SIZE_TOO_SMALL"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_LAST_OCTET_INVALID), "LAST_OCTET_INVALID"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_MODULUS_TOO_LARGE), "MODULUS_TOO_LARGE"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_NO_PUBLIC_EXPONENT), "NO_PUBLIC_EXPONENT"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_NULL_BEFORE_BLOCK_MISSING), "NULL_BEFORE_BLOCK_MISSING"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_OAEP_DECODING_ERROR), "OAEP_DECODING_ERROR"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_OUTPUT_BUFFER_TOO_SMALL), "OUTPUT_BUFFER_TOO_SMALL"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_PADDING_CHECK_FAILED), "PADDING_CHECK_FAILED"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_SLEN_CHECK_FAILED), "SLEN_CHECK_FAILED"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_SLEN_RECOVERY_FAILED), "SLEN_RECOVERY_FAILED"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_SSLV3_ROLLBACK_ATTACK), "SSLV3_ROLLBACK_ATTACK"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD), "THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_TOO_LONG), "TOO_LONG"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_TOO_MANY_ITERATIONS), "TOO_MANY_ITERATIONS"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_UNKNOWN_ALGORITHM_TYPE), "UNKNOWN_ALGORITHM_TYPE"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_UNKNOWN_PADDING_TYPE), "UNKNOWN_PADDING_TYPE"},
+ {ERR_PACK(ERR_LIB_RSA, 0, RSA_R_WRONG_SIGNATURE_LENGTH), "WRONG_SIGNATURE_LENGTH"},
+ {0, NULL},
+};
diff --git a/crypto/rsa/rsa_impl.c b/crypto/rsa/rsa_impl.c
new file mode 100644
index 0000000..e7aed9f
--- /dev/null
+++ b/crypto/rsa/rsa_impl.c
@@ -0,0 +1,1006 @@
+/* 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 <openssl/bn.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+#include "internal.h"
+
+
+#define OPENSSL_RSA_MAX_MODULUS_BITS 16384
+#define OPENSSL_RSA_SMALL_MODULUS_BITS 3072
+#define OPENSSL_RSA_MAX_PUBEXP_BITS \
+ 64 /* exponent limit enforced for "large" modulus only */
+
+
+static int finish(RSA *rsa) {
+ if (rsa->_method_mod_n != NULL) {
+ BN_MONT_CTX_free(rsa->_method_mod_n);
+ }
+ if (rsa->_method_mod_p != NULL) {
+ BN_MONT_CTX_free(rsa->_method_mod_p);
+ }
+ if (rsa->_method_mod_q != NULL) {
+ BN_MONT_CTX_free(rsa->_method_mod_q);
+ }
+
+ return 1;
+}
+
+static int encrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
+ const uint8_t *in, size_t in_len, int padding) {
+ const unsigned rsa_size = RSA_size(rsa);
+ unsigned i, j, k;
+ BIGNUM *f, *result;
+ uint8_t *buf = NULL;
+ BN_CTX *ctx = NULL;
+ int ret = 0;
+
+ if (rsa_size > OPENSSL_RSA_MAX_MODULUS_BITS) {
+ OPENSSL_PUT_ERROR(RSA, encrypt, RSA_R_MODULUS_TOO_LARGE);
+ return 0;
+ }
+
+ if (max_out < rsa_size) {
+ OPENSSL_PUT_ERROR(RSA, encrypt, 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);
+ 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);
+ return 0;
+ }
+
+ ctx = BN_CTX_new();
+ if (ctx == NULL) {
+ goto err;
+ }
+
+ 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, encrypt, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ switch (padding) {
+ case RSA_PKCS1_PADDING:
+ i = RSA_padding_add_PKCS1_type_2(buf, rsa_size, in, in_len);
+ break;
+ case RSA_PKCS1_OAEP_PADDING:
+ i = RSA_padding_add_PKCS1_OAEP(buf, rsa_size, in, in_len, NULL, 0);
+ break;
+ case RSA_SSLV23_PADDING:
+ i = RSA_padding_add_SSLv23(buf, rsa_size, in, in_len);
+ break;
+ case RSA_NO_PADDING:
+ i = RSA_padding_add_none(buf, rsa_size, in, in_len);
+ break;
+ default:
+ OPENSSL_PUT_ERROR(RSA, encrypt, RSA_R_UNKNOWN_PADDING_TYPE);
+ goto err;
+ }
+
+ if (i <= 0) {
+ goto err;
+ }
+
+ if (BN_bin2bn(buf, rsa_size, f) == NULL) {
+ goto err;
+ }
+
+ 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);
+ goto err;
+ }
+
+ if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) {
+ if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_n, CRYPTO_LOCK_RSA, rsa->n,
+ ctx)) {
+ goto err;
+ }
+ }
+
+ if (!rsa->meth->bn_mod_exp(result, f, rsa->e, rsa->n, ctx, rsa->_method_mod_n)) {
+ goto err;
+ }
+
+ /* put in leading 0 bytes if the number is less than the length of the
+ * modulus */
+ j = BN_num_bytes(result);
+ i = BN_bn2bin(result, &(out[rsa_size - j]));
+ for (k = 0; k < rsa_size - i; k++) {
+ out[k] = 0;
+ }
+
+ *out_len = rsa_size;
+ ret = 1;
+
+err:
+ if (ctx != NULL) {
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ }
+ if (buf != NULL) {
+ OPENSSL_cleanse(buf, rsa_size);
+ OPENSSL_free(buf);
+ }
+
+ return ret;
+}
+
+/* MAX_BLINDINGS_PER_RSA defines the maximum number of cached BN_BLINDINGs per
+ * RSA*. Then this limit is exceeded, BN_BLINDING objects will be created and
+ * destroyed as needed. */
+#define MAX_BLINDINGS_PER_RSA 1024
+
+/* rsa_blinding_get returns a BN_BLINDING to use with |rsa|. It does this by
+ * allocating one of the cached BN_BLINDING objects in |rsa->blindings|. If
+ * none are free, the cache will be extended by a extra element and the new
+ * BN_BLINDING is returned.
+ *
+ * On success, the index of the assigned BN_BLINDING is written to
+ * |*index_used| and must be passed to |rsa_blinding_release| when finished. */
+static BN_BLINDING *rsa_blinding_get(RSA *rsa, unsigned *index_used,
+ BN_CTX *ctx) {
+ BN_BLINDING *ret = NULL;
+ BN_BLINDING **new_blindings;
+ uint8_t *new_blindings_inuse;
+ char overflow = 0;
+
+ CRYPTO_w_lock(CRYPTO_LOCK_RSA_BLINDING);
+ if (rsa->num_blindings > 0) {
+ unsigned i, starting_index;
+ CRYPTO_THREADID threadid;
+
+ /* We start searching the array at a value based on the
+ * threadid in order to try avoid bouncing the BN_BLINDING
+ * values around different threads. It's harmless if
+ * threadid.val is always set to zero. */
+ CRYPTO_THREADID_current(&threadid);
+ starting_index = threadid.val % rsa->num_blindings;
+
+ for (i = starting_index;;) {
+ if (rsa->blindings_inuse[i] == 0) {
+ rsa->blindings_inuse[i] = 1;
+ ret = rsa->blindings[i];
+ *index_used = i;
+ break;
+ }
+ i++;
+ if (i == rsa->num_blindings) {
+ i = 0;
+ }
+ if (i == starting_index) {
+ break;
+ }
+ }
+ }
+
+ if (ret != NULL) {
+ CRYPTO_w_unlock(CRYPTO_LOCK_RSA_BLINDING);
+ return ret;
+ }
+
+ overflow = rsa->num_blindings >= MAX_BLINDINGS_PER_RSA;
+
+ /* We didn't find a free BN_BLINDING to use so increase the length of
+ * the arrays by one and use the newly created element. */
+
+ CRYPTO_w_unlock(CRYPTO_LOCK_RSA_BLINDING);
+ ret = rsa_setup_blinding(rsa, ctx);
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ if (overflow) {
+ /* We cannot add any more cached BN_BLINDINGs so we use |ret|
+ * and mark it for destruction in |rsa_blinding_release|. */
+ *index_used = MAX_BLINDINGS_PER_RSA;
+ return ret;
+ }
+
+ CRYPTO_w_lock(CRYPTO_LOCK_RSA_BLINDING);
+
+ new_blindings =
+ OPENSSL_malloc(sizeof(BN_BLINDING *) * (rsa->num_blindings + 1));
+ if (new_blindings == NULL) {
+ goto err1;
+ }
+ memcpy(new_blindings, rsa->blindings,
+ sizeof(BN_BLINDING *) * rsa->num_blindings);
+ new_blindings[rsa->num_blindings] = ret;
+
+ new_blindings_inuse = OPENSSL_malloc(rsa->num_blindings + 1);
+ if (new_blindings_inuse == NULL) {
+ goto err2;
+ }
+ memcpy(new_blindings_inuse, rsa->blindings_inuse, rsa->num_blindings);
+ new_blindings_inuse[rsa->num_blindings] = 1;
+ *index_used = rsa->num_blindings;
+
+ if (rsa->blindings != NULL) {
+ OPENSSL_free(rsa->blindings);
+ }
+ rsa->blindings = new_blindings;
+ if (rsa->blindings_inuse != NULL) {
+ OPENSSL_free(rsa->blindings_inuse);
+ }
+ rsa->blindings_inuse = new_blindings_inuse;
+ rsa->num_blindings++;
+
+ CRYPTO_w_unlock(CRYPTO_LOCK_RSA_BLINDING);
+ return ret;
+
+err2:
+ OPENSSL_free(new_blindings);
+
+err1:
+ CRYPTO_w_unlock(CRYPTO_LOCK_RSA_BLINDING);
+ BN_BLINDING_free(ret);
+ return NULL;
+}
+
+/* rsa_blinding_release marks the cached BN_BLINDING at the given index as free
+ * for other threads to use. */
+static void rsa_blinding_release(RSA *rsa, BN_BLINDING *blinding,
+ unsigned blinding_index) {
+ if (blinding_index == MAX_BLINDINGS_PER_RSA) {
+ /* This blinding wasn't cached. */
+ BN_BLINDING_free(blinding);
+ return;
+ }
+
+ CRYPTO_w_lock(CRYPTO_LOCK_RSA_BLINDING);
+ rsa->blindings_inuse[blinding_index] = 0;
+ CRYPTO_w_unlock(CRYPTO_LOCK_RSA_BLINDING);
+}
+
+/* signing */
+static int sign_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
+ const uint8_t *in, size_t in_len, int padding) {
+ const unsigned rsa_size = RSA_size(rsa);
+ BIGNUM *f, *result;
+ unsigned i, j, k;
+ uint8_t *buf = NULL;
+ BN_CTX *ctx = NULL;
+ unsigned blinding_index = 0;
+ BN_BLINDING *blinding = NULL;
+ int ret = 0;
+
+ if (max_out < rsa_size) {
+ OPENSSL_PUT_ERROR(RSA, sign_raw, RSA_R_OUTPUT_BUFFER_TOO_SMALL);
+ return 0;
+ }
+
+ ctx = BN_CTX_new();
+ if (ctx == NULL) {
+ goto err;
+ }
+ 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, sign_raw, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ switch (padding) {
+ case RSA_PKCS1_PADDING:
+ i = RSA_padding_add_PKCS1_type_1(buf, rsa_size, in, in_len);
+ break;
+ case RSA_NO_PADDING:
+ i = RSA_padding_add_none(buf, rsa_size, in, in_len);
+ break;
+ default:
+ OPENSSL_PUT_ERROR(RSA, sign_raw, RSA_R_UNKNOWN_PADDING_TYPE);
+ goto err;
+ }
+ if (i <= 0) {
+ goto err;
+ }
+
+ if (BN_bin2bn(buf, rsa_size, f) == NULL) {
+ goto err;
+ }
+
+ if (BN_ucmp(f, rsa->n) >= 0) {
+ /* usually the padding functions would catch this */
+ OPENSSL_PUT_ERROR(RSA, sign_raw, 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, sign_raw, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ if (!BN_BLINDING_convert_ex(f, NULL, blinding, ctx)) {
+ goto err;
+ }
+ }
+
+ if ((rsa->flags & RSA_FLAG_EXT_PKEY) ||
+ ((rsa->p != NULL) && (rsa->q != NULL) && (rsa->dmp1 != NULL) &&
+ (rsa->dmq1 != NULL) && (rsa->iqmp != NULL))) {
+ if (!rsa->meth->mod_exp(result, f, rsa, ctx)) {
+ goto err;
+ }
+ } else {
+ BIGNUM local_d;
+ BIGNUM *d = NULL;
+
+ BN_init(&local_d);
+ d = &local_d;
+ BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME);
+
+ if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) {
+ if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_n, CRYPTO_LOCK_RSA, rsa->n,
+ ctx)) {
+ goto err;
+ }
+ }
+
+ if (!rsa->meth->bn_mod_exp(result, f, d, rsa->n, ctx, rsa->_method_mod_n)) {
+ goto err;
+ }
+ }
+
+ if (blinding) {
+ if (!BN_BLINDING_invert_ex(result, NULL, blinding, ctx)) {
+ goto err;
+ }
+ }
+
+ /* put in leading 0 bytes if the number is less than the
+ * length of the modulus */
+ j = BN_num_bytes(result);
+ i = BN_bn2bin(result, &(out[rsa_size - j]));
+ for (k = 0; k < rsa_size - i; k++) {
+ out[k] = 0;
+ }
+
+ *out_len = rsa_size;
+ ret = 1;
+
+err:
+ if (ctx != NULL) {
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ }
+ if (buf != NULL) {
+ OPENSSL_cleanse(buf, rsa_size);
+ OPENSSL_free(buf);
+ }
+ if (blinding != NULL) {
+ rsa_blinding_release(rsa, blinding, blinding_index);
+ }
+
+ return ret;
+}
+
+static int decrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
+ const uint8_t *in, size_t in_len, int padding) {
+ const unsigned rsa_size = RSA_size(rsa);
+ unsigned j;
+ BIGNUM *f, *result;
+ int r = -1;
+ uint8_t *buf = NULL;
+ BN_CTX *ctx = NULL;
+ unsigned blinding_index;
+ BN_BLINDING *blinding = NULL;
+ int ret = 0;
+
+ if (max_out < rsa_size) {
+ OPENSSL_PUT_ERROR(RSA, decrypt, RSA_R_OUTPUT_BUFFER_TOO_SMALL);
+ return 0;
+ }
+
+ ctx = BN_CTX_new();
+ if (ctx == NULL) {
+ goto err;
+ }
+ 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, decrypt, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* This check was for equality but PGP does evil things
+ * and chops off the top '0' bytes.
+ * TODO(fork): investigate this. */
+ if (in_len > rsa_size) {
+ OPENSSL_PUT_ERROR(RSA, decrypt, RSA_R_DATA_GREATER_THAN_MOD_LEN);
+ goto err;
+ }
+
+ /* make data into a big number */
+ if (BN_bin2bn(in, (int)in_len, f) == NULL) {
+ goto err;
+ }
+
+ if (BN_ucmp(f, rsa->n) >= 0) {
+ OPENSSL_PUT_ERROR(RSA, decrypt, 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, decrypt, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ if (!BN_BLINDING_convert_ex(f, NULL, blinding, ctx)) {
+ goto err;
+ }
+ }
+
+ /* do the decrypt */
+ if ((rsa->flags & RSA_FLAG_EXT_PKEY) ||
+ ((rsa->p != NULL) && (rsa->q != NULL) && (rsa->dmp1 != NULL) &&
+ (rsa->dmq1 != NULL) && (rsa->iqmp != NULL))) {
+ if (!rsa->meth->mod_exp(result, f, rsa, ctx)) {
+ goto err;
+ }
+ } else {
+ BIGNUM local_d;
+ BIGNUM *d = NULL;
+
+ d = &local_d;
+ BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME);
+
+ if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) {
+ if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_n, CRYPTO_LOCK_RSA, rsa->n,
+ ctx)) {
+ goto err;
+ }
+ }
+ if (!rsa->meth->bn_mod_exp(result, f, d, rsa->n, ctx, rsa->_method_mod_n)) {
+ goto err;
+ }
+ }
+
+ if (blinding) {
+ if (!BN_BLINDING_invert_ex(result, NULL, blinding, ctx)) {
+ goto err;
+ }
+ }
+
+ j = BN_bn2bin(result, buf); /* j is only used with no-padding mode */
+
+ switch (padding) {
+ case RSA_PKCS1_PADDING:
+ r = RSA_padding_check_PKCS1_type_2(out, rsa_size, buf, j, rsa_size);
+ break;
+ case RSA_PKCS1_OAEP_PADDING:
+ r = RSA_padding_check_PKCS1_OAEP(out, rsa_size, buf, j, rsa_size, NULL, 0);
+ break;
+ case RSA_SSLV23_PADDING:
+ r = RSA_padding_check_SSLv23(out, rsa_size, buf, j, rsa_size);
+ break;
+ case RSA_NO_PADDING:
+ r = RSA_padding_check_none(out, rsa_size, buf, j, rsa_size);
+ break;
+ default:
+ OPENSSL_PUT_ERROR(RSA, decrypt, RSA_R_UNKNOWN_PADDING_TYPE);
+ goto err;
+ }
+
+ if (r < 0) {
+ OPENSSL_PUT_ERROR(RSA, decrypt, RSA_R_PADDING_CHECK_FAILED);
+ } else {
+ *out_len = r;
+ ret = 1;
+ }
+
+err:
+ if (ctx != NULL) {
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ }
+ if (buf != NULL) {
+ OPENSSL_cleanse(buf, rsa_size);
+ OPENSSL_free(buf);
+ }
+ if (blinding != NULL) {
+ rsa_blinding_release(rsa, blinding, blinding_index);
+ }
+
+ return ret;
+}
+
+static int verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
+ const uint8_t *in, size_t in_len, int padding) {
+ const unsigned rsa_size = RSA_size(rsa);
+ BIGNUM *f, *result;
+ int ret = 0;
+ int i, r = -1;
+ uint8_t *buf = NULL;
+ 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);
+ return 0;
+ }
+
+ if (BN_ucmp(rsa->n, rsa->e) <= 0) {
+ OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_BAD_E_VALUE);
+ return 0;
+ }
+
+ if (max_out < rsa_size) {
+ OPENSSL_PUT_ERROR(RSA, verify_raw, 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);
+ return 0;
+ }
+
+ ctx = BN_CTX_new();
+ if (ctx == NULL) {
+ goto err;
+ }
+
+ 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);
+ goto err;
+ }
+
+ /* This check was for equality but PGP does evil things
+ * and chops off the top '0' bytes.
+ * TODO(fork): investigate */
+ if (in_len > rsa_size) {
+ OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_DATA_GREATER_THAN_MOD_LEN);
+ goto err;
+ }
+
+ if (BN_bin2bn(in, in_len, f) == NULL) {
+ goto err;
+ }
+
+ if (BN_ucmp(f, rsa->n) >= 0) {
+ OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
+ goto err;
+ }
+
+ if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) {
+ if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_n, CRYPTO_LOCK_RSA, rsa->n,
+ ctx)) {
+ goto err;
+ }
+ }
+
+ if (!rsa->meth->bn_mod_exp(result, f, rsa->e, rsa->n, ctx,
+ rsa->_method_mod_n)) {
+ goto err;
+ }
+
+ i = BN_bn2bin(result, buf);
+
+ switch (padding) {
+ case RSA_PKCS1_PADDING:
+ r = RSA_padding_check_PKCS1_type_1(out, rsa_size, buf, i, rsa_size);
+ break;
+ case RSA_NO_PADDING:
+ r = RSA_padding_check_none(out, rsa_size, buf, i, rsa_size);
+ break;
+ default:
+ OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_UNKNOWN_PADDING_TYPE);
+ goto err;
+ }
+
+ if (r < 0) {
+ OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_PADDING_CHECK_FAILED);
+ } else {
+ *out_len = r;
+ ret = 1;
+ }
+
+err:
+ if (ctx != NULL) {
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ }
+ if (buf != NULL) {
+ OPENSSL_cleanse(buf, rsa_size);
+ OPENSSL_free(buf);
+ }
+ return ret;
+}
+
+static int mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) {
+ BIGNUM *r1, *m1, *vrfy;
+ BIGNUM local_dmp1, local_dmq1, local_c, local_r1;
+ BIGNUM *dmp1, *dmq1, *c, *pr1;
+ int ret = 0;
+
+ BN_CTX_start(ctx);
+ r1 = BN_CTX_get(ctx);
+ m1 = BN_CTX_get(ctx);
+ vrfy = BN_CTX_get(ctx);
+
+ {
+ BIGNUM local_p, local_q;
+ BIGNUM *p = NULL, *q = NULL;
+
+ /* Make sure BN_mod_inverse in Montgomery intialization uses the
+ * BN_FLG_CONSTTIME flag (unless RSA_FLAG_NO_CONSTTIME is set) */
+ BN_init(&local_p);
+ p = &local_p;
+ BN_with_flags(p, rsa->p, BN_FLG_CONSTTIME);
+
+ BN_init(&local_q);
+ q = &local_q;
+ BN_with_flags(q, rsa->q, BN_FLG_CONSTTIME);
+
+ if (rsa->flags & RSA_FLAG_CACHE_PRIVATE) {
+ if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_p, CRYPTO_LOCK_RSA, p, ctx)) {
+ goto err;
+ }
+ if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_q, CRYPTO_LOCK_RSA, q, ctx)) {
+ goto err;
+ }
+ }
+ }
+
+ if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) {
+ if (!BN_MONT_CTX_set_locked(&rsa->_method_mod_n, CRYPTO_LOCK_RSA, rsa->n,
+ ctx)) {
+ goto err;
+ }
+ }
+
+ /* compute I mod q */
+ c = &local_c;
+ BN_with_flags(c, I, BN_FLG_CONSTTIME);
+ if (!BN_mod(r1, c, rsa->q, ctx)) {
+ goto err;
+ }
+
+ /* compute r1^dmq1 mod q */
+ dmq1 = &local_dmq1;
+ BN_with_flags(dmq1, rsa->dmq1, BN_FLG_CONSTTIME);
+ if (!rsa->meth->bn_mod_exp(m1, r1, dmq1, rsa->q, ctx, rsa->_method_mod_q)) {
+ goto err;
+ }
+
+ /* compute I mod p */
+ c = &local_c;
+ BN_with_flags(c, I, BN_FLG_CONSTTIME);
+ if (!BN_mod(r1, c, rsa->p, ctx)) {
+ goto err;
+ }
+
+ /* compute r1^dmp1 mod p */
+ dmp1 = &local_dmp1;
+ BN_with_flags(dmp1, rsa->dmp1, BN_FLG_CONSTTIME);
+ if (!rsa->meth->bn_mod_exp(r0, r1, dmp1, rsa->p, ctx, rsa->_method_mod_p)) {
+ goto err;
+ }
+
+ if (!BN_sub(r0, r0, m1)) {
+ goto err;
+ }
+ /* This will help stop the size of r0 increasing, which does
+ * affect the multiply if it optimised for a power of 2 size */
+ if (BN_is_negative(r0)) {
+ if (!BN_add(r0, r0, rsa->p)) {
+ goto err;
+ }
+ }
+
+ if (!BN_mul(r1, r0, rsa->iqmp, ctx)) {
+ goto err;
+ }
+
+ /* Turn BN_FLG_CONSTTIME flag on before division operation */
+ pr1 = &local_r1;
+ BN_with_flags(pr1, r1, BN_FLG_CONSTTIME);
+
+ if (!BN_mod(r0, pr1, rsa->p, ctx)) {
+ goto err;
+ }
+
+ /* If p < q it is occasionally possible for the correction of
+ * adding 'p' if r0 is negative above to leave the result still
+ * negative. This can break the private key operations: the following
+ * second correction should *always* correct this rare occurrence.
+ * This will *never* happen with OpenSSL generated keys because
+ * they ensure p > q [steve] */
+ if (BN_is_negative(r0)) {
+ if (!BN_add(r0, r0, rsa->p)) {
+ goto err;
+ }
+ }
+ if (!BN_mul(r1, r0, rsa->q, ctx)) {
+ goto err;
+ }
+ if (!BN_add(r0, r1, 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)) {
+ goto err;
+ }
+ /* If 'I' was greater than (or equal to) rsa->n, the operation
+ * will be equivalent to using 'I mod n'. However, the result of
+ * the verify will *always* be less than 'n' so we don't check
+ * for absolute equality, just congruency. */
+ if (!BN_sub(vrfy, vrfy, I)) {
+ goto err;
+ }
+ if (!BN_mod(vrfy, vrfy, rsa->n, ctx)) {
+ goto err;
+ }
+ if (BN_is_negative(vrfy)) {
+ if (!BN_add(vrfy, vrfy, rsa->n)) {
+ goto err;
+ }
+ }
+ if (!BN_is_zero(vrfy)) {
+ /* 'I' and 'vrfy' aren't congruent mod n. Don't leak
+ * miscalculated CRT output, just do a raw (slower)
+ * mod_exp and return that instead. */
+
+ BIGNUM local_d;
+ BIGNUM *d = NULL;
+
+ d = &local_d;
+ BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME);
+ if (!rsa->meth->bn_mod_exp(r0, I, d, rsa->n, ctx, rsa->_method_mod_n)) {
+ goto err;
+ }
+ }
+ }
+ ret = 1;
+
+err:
+ BN_CTX_end(ctx);
+ return ret;
+}
+
+static int keygen(RSA *rsa, int bits, 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;
+ BN_CTX *ctx = NULL;
+
+ ctx = BN_CTX_new();
+ if (ctx == NULL) {
+ goto err;
+ }
+ BN_CTX_start(ctx);
+ r0 = BN_CTX_get(ctx);
+ r1 = BN_CTX_get(ctx);
+ r2 = BN_CTX_get(ctx);
+ r3 = BN_CTX_get(ctx);
+ if (r3 == NULL) {
+ goto err;
+ }
+
+ bitsp = (bits + 1) / 2;
+ bitsq = bits - bitsp;
+
+ /* We need the RSA components non-NULL */
+ if (!rsa->n && ((rsa->n = BN_new()) == NULL))
+ goto err;
+ if (!rsa->d && ((rsa->d = BN_new()) == NULL))
+ goto err;
+ if (!rsa->e && ((rsa->e = BN_new()) == NULL))
+ goto err;
+ if (!rsa->p && ((rsa->p = BN_new()) == NULL))
+ goto err;
+ if (!rsa->q && ((rsa->q = BN_new()) == NULL))
+ goto err;
+ if (!rsa->dmp1 && ((rsa->dmp1 = BN_new()) == NULL))
+ goto err;
+ if (!rsa->dmq1 && ((rsa->dmq1 = BN_new()) == NULL))
+ goto err;
+ if (!rsa->iqmp && ((rsa->iqmp = BN_new()) == NULL))
+ goto err;
+
+ BN_copy(rsa->e, e_value);
+
+ /* generate p and q */
+ for (;;) {
+ if (!BN_generate_prime_ex(rsa->p, bitsp, 0, NULL, NULL, cb))
+ goto err;
+ if (!BN_sub(r2, rsa->p, BN_value_one()))
+ goto err;
+ if (!BN_gcd(r1, r2, rsa->e, ctx))
+ goto err;
+ if (BN_is_one(r1))
+ break;
+ if (!BN_GENCB_call(cb, 2, n++))
+ goto err;
+ }
+ if (!BN_GENCB_call(cb, 3, 0))
+ goto err;
+ 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))
+ 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);
+ goto err;
+ }
+ if (!BN_sub(r2, rsa->q, BN_value_one()))
+ goto err;
+ if (!BN_gcd(r1, r2, rsa->e, ctx))
+ goto err;
+ if (BN_is_one(r1))
+ break;
+ if (!BN_GENCB_call(cb, 2, n++))
+ 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 */
+ if (!BN_sub(r2, rsa->q, BN_value_one()))
+ goto err; /* q-1 */
+ if (!BN_mul(r0, r1, r2, ctx))
+ goto err; /* (p-1)(q-1) */
+ pr0 = &local_r0;
+ BN_with_flags(pr0, r0, BN_FLG_CONSTTIME);
+ if (!BN_mod_inverse(rsa->d, rsa->e, pr0, ctx))
+ goto err; /* d */
+
+ /* set up d for correct BN_FLG_CONSTTIME flag */
+ d = &local_d;
+ BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME);
+
+ /* calculate d mod (p-1) */
+ if (!BN_mod(rsa->dmp1, d, r1, ctx))
+ goto err;
+
+ /* calculate d mod (q-1) */
+ if (!BN_mod(rsa->dmq1, d, r2, ctx))
+ goto err;
+
+ /* calculate inverse of q mod p */
+ p = &local_p;
+ BN_with_flags(p, rsa->p, BN_FLG_CONSTTIME);
+
+ if (!BN_mod_inverse(rsa->iqmp, rsa->q, p, ctx))
+ goto err;
+
+ ok = 1;
+
+err:
+ if (ok == -1) {
+ OPENSSL_PUT_ERROR(RSA, keygen, ERR_LIB_BN);
+ ok = 0;
+ }
+ if (ctx != NULL) {
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ }
+
+ return ok;
+}
+
+const struct rsa_meth_st RSA_default_method = {
+ {
+ 0 /* references */,
+ 1 /* is_static */,
+ },
+ NULL /* app_data */,
+
+ NULL /* init */,
+ finish,
+
+ NULL /* sign */,
+ NULL /* verify */,
+
+ encrypt,
+ sign_raw,
+ decrypt,
+ verify_raw,
+
+ mod_exp /* mod_exp */,
+ BN_mod_exp_mont /* bn_mod_exp */,
+
+ RSA_FLAG_CACHE_PUBLIC | RSA_FLAG_CACHE_PRIVATE,
+
+ keygen,
+};
diff --git a/crypto/rsa/rsa_test.c b/crypto/rsa/rsa_test.c
new file mode 100644
index 0000000..e8d6d20
--- /dev/null
+++ b/crypto/rsa/rsa_test.c
@@ -0,0 +1,391 @@
+/* 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 <openssl/bio.h>
+#include <openssl/bn.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_only_d_given() {
+ 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_sign(NID_md5, kDummyHash, sizeof(kDummyHash), buf, &buf_len, key)) {
+ fprintf(stderr, "RSA_sign failed with only d given.\n");
+ BIO_print_errors_fp(stderr);
+ goto err;
+ }
+
+ if (!RSA_verify(NID_md5, kDummyHash, sizeof(kDummyHash), buf, buf_len, key)) {
+ fprintf(stderr, "RSA_verify failed with only d given.\n");
+ BIO_print_errors_fp(stderr);
+ goto err;
+ }
+
+ ret = 1;
+
+err:
+ RSA_free(key);
+ return ret;
+}
+
+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;
+
+ 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();
+ return 1;
+ }
+
+ 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()) {
+ err = 1;
+ }
+
+ if (err == 0) {
+ printf("PASS\n");
+ }
+ return err;
+}
diff --git a/crypto/sha/CMakeLists.txt b/crypto/sha/CMakeLists.txt
new file mode 100644
index 0000000..848c048
--- /dev/null
+++ b/crypto/sha/CMakeLists.txt
@@ -0,0 +1,61 @@
+include_directories(. .. ../../include)
+
+if (${ARCH} STREQUAL "x86_64")
+ set(
+ SHA_ARCH_SOURCES
+
+ sha1-x86_64.${ASM_EXT}
+ sha256-x86_64.${ASM_EXT}
+ sha512-x86_64.${ASM_EXT}
+ )
+endif()
+
+if (${ARCH} STREQUAL "x86")
+ set(
+ SHA_ARCH_SOURCES
+
+ sha1-586.${ASM_EXT}
+ sha256-586.${ASM_EXT}
+ sha512-586.${ASM_EXT}
+ )
+endif()
+
+if (${ARCH} STREQUAL "arm")
+ set(
+ SHA_ARCH_SOURCES
+
+ sha1-armv4-large.${ASM_EXT}
+ sha256-armv4.${ASM_EXT}
+ sha512-armv4.${ASM_EXT}
+ )
+endif()
+
+add_library(
+ sha
+
+ OBJECT
+
+ sha1.c
+ sha256.c
+ sha512.c
+
+ ${SHA_ARCH_SOURCES}
+)
+
+perlasm(sha1-x86_64.${ASM_EXT} asm/sha1-x86_64.pl)
+perlasm(sha256-x86_64.${ASM_EXT} asm/sha512-x86_64.pl sha256)
+perlasm(sha512-x86_64.${ASM_EXT} asm/sha512-x86_64.pl sha512)
+perlasm(sha1-586.${ASM_EXT} asm/sha1-586.pl)
+perlasm(sha256-586.${ASM_EXT} asm/sha256-586.pl)
+perlasm(sha512-586.${ASM_EXT} asm/sha512-586.pl)
+perlasm(sha1-armv4-large.${ASM_EXT} asm/sha1-armv4-large.pl)
+perlasm(sha256-armv4.${ASM_EXT} asm/sha256-armv4.pl)
+perlasm(sha512-armv4.${ASM_EXT} asm/sha512-armv4.pl)
+
+add_executable(
+ sha1_test
+
+ sha1_test.c
+)
+
+target_link_libraries(sha1_test crypto)
diff --git a/crypto/sha/asm/sha1-586.pl b/crypto/sha/asm/sha1-586.pl
new file mode 100644
index 0000000..632dbbe
--- /dev/null
+++ b/crypto/sha/asm/sha1-586.pl
@@ -0,0 +1,1266 @@
+#!/usr/bin/env perl
+
+# ====================================================================
+# [Re]written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+
+# "[Re]written" was achieved in two major overhauls. In 2004 BODY_*
+# functions were re-implemented to address P4 performance issue [see
+# commentary below], and in 2006 the rest was rewritten in order to
+# gain freedom to liberate licensing terms.
+
+# January, September 2004.
+#
+# It was noted that Intel IA-32 C compiler generates code which
+# performs ~30% *faster* on P4 CPU than original *hand-coded*
+# SHA1 assembler implementation. To address this problem (and
+# prove that humans are still better than machines:-), the
+# original code was overhauled, which resulted in following
+# performance changes:
+#
+# compared with original compared with Intel cc
+# assembler impl. generated code
+# Pentium -16% +48%
+# PIII/AMD +8% +16%
+# P4 +85%(!) +45%
+#
+# As you can see Pentium came out as looser:-( Yet I reckoned that
+# improvement on P4 outweights the loss and incorporate this
+# re-tuned code to 0.9.7 and later.
+# ----------------------------------------------------------------
+# <appro@fy.chalmers.se>
+
+# August 2009.
+#
+# George Spelvin has tipped that F_40_59(b,c,d) can be rewritten as
+# '(c&d) + (b&(c^d))', which allows to accumulate partial results
+# and lighten "pressure" on scratch registers. This resulted in
+# >12% performance improvement on contemporary AMD cores (with no
+# degradation on other CPUs:-). Also, the code was revised to maximize
+# "distance" between instructions producing input to 'lea' instruction
+# and the 'lea' instruction itself, which is essential for Intel Atom
+# core and resulted in ~15% improvement.
+
+# October 2010.
+#
+# Add SSSE3, Supplemental[!] SSE3, implementation. The idea behind it
+# is to offload message schedule denoted by Wt in NIST specification,
+# or Xupdate in OpenSSL source, to SIMD unit. The idea is not novel,
+# and in SSE2 context was first explored by Dean Gaudet in 2004, see
+# http://arctic.org/~dean/crypto/sha1.html. Since then several things
+# have changed that made it interesting again:
+#
+# a) XMM units became faster and wider;
+# b) instruction set became more versatile;
+# c) an important observation was made by Max Locktykhin, which made
+# it possible to reduce amount of instructions required to perform
+# the operation in question, for further details see
+# http://software.intel.com/en-us/articles/improving-the-performance-of-the-secure-hash-algorithm-1/.
+
+# April 2011.
+#
+# Add AVX code path, probably most controversial... The thing is that
+# 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
+# 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
+# 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
+# [according to its optimization manual]. Which is why AVX code path
+# is guarded by *both* AVX and synthetic bit denoting Intel CPUs.
+# One can argue that it's unfair to AMD, but without 'sh[rl]d' it
+# makes no sense to keep the AVX code path. If somebody feels that
+# strongly, it's probably more appropriate to discuss possibility of
+# using vector rotate XOP on AMD...
+
+######################################################################
+# Current performance is summarized in following table. Numbers are
+# CPU clock cycles spent to process single byte (less is better).
+#
+# x86 SSSE3 AVX
+# Pentium 15.7 -
+# PIII 11.5 -
+# P4 10.6 -
+# AMD K8 7.1 -
+# Core2 7.3 6.0/+22% -
+# Atom 12.5 9.3(*)/+35% -
+# Westmere 7.3 5.5/+33% -
+# Sandy Bridge 8.8 6.2/+40% 5.1(**)/+73%
+# Ivy Bridge 7.2 4.8/+51% 4.7(**)/+53%
+# Bulldozer 11.6 6.0/+92%
+# VIA Nano 10.6 7.4/+43%
+#
+# (*) Loop is 1056 instructions long and expected result is ~8.25.
+# It remains mystery [to me] why ILP is limited to 1.7.
+#
+# (**) As per above comment, the result is for AVX *plus* sh[rl]d.
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+push(@INC,"${dir}","${dir}../../perlasm");
+require "x86asm.pl";
+
+&asm_init($ARGV[0],"sha1-586.pl",$ARGV[$#ARGV] eq "386");
+
+$xmm=$ymm=0;
+for (@ARGV) { $xmm=1 if (/-DOPENSSL_IA32_SSE2/); }
+
+$ymm=1 if ($xmm &&
+ `$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
+ =~ /GNU assembler version ([2-9]\.[0-9]+)/ &&
+ $1>=2.19); # first version supporting AVX
+
+$ymm=1 if ($xmm && !$ymm && $ARGV[0] eq "win32n" &&
+ `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/ &&
+ $1>=2.03); # first version supporting AVX
+
+$ymm=1 if ($xmm && !$ymm && $ARGV[0] eq "win32" &&
+ `ml 2>&1` =~ /Version ([0-9]+)\./ &&
+ $1>=10); # first version supporting AVX
+
+&external_label("OPENSSL_ia32cap_P") if ($xmm);
+
+
+$A="eax";
+$B="ebx";
+$C="ecx";
+$D="edx";
+$E="edi";
+$T="esi";
+$tmp1="ebp";
+
+@V=($A,$B,$C,$D,$E,$T);
+
+$alt=0; # 1 denotes alternative IALU implementation, which performs
+ # 8% *worse* on P4, same on Westmere and Atom, 2% better on
+ # Sandy Bridge...
+
+sub BODY_00_15
+ {
+ local($n,$a,$b,$c,$d,$e,$f)=@_;
+
+ &comment("00_15 $n");
+
+ &mov($f,$c); # f to hold F_00_19(b,c,d)
+ if ($n==0) { &mov($tmp1,$a); }
+ else { &mov($a,$tmp1); }
+ &rotl($tmp1,5); # tmp1=ROTATE(a,5)
+ &xor($f,$d);
+ &add($tmp1,$e); # tmp1+=e;
+ &mov($e,&swtmp($n%16)); # e becomes volatile and is loaded
+ # with xi, also note that e becomes
+ # f in next round...
+ &and($f,$b);
+ &rotr($b,2); # b=ROTATE(b,30)
+ &xor($f,$d); # f holds F_00_19(b,c,d)
+ &lea($tmp1,&DWP(0x5a827999,$tmp1,$e)); # tmp1+=K_00_19+xi
+
+ if ($n==15) { &mov($e,&swtmp(($n+1)%16));# pre-fetch f for next round
+ &add($f,$tmp1); } # f+=tmp1
+ else { &add($tmp1,$f); } # f becomes a in next round
+ &mov($tmp1,$a) if ($alt && $n==15);
+ }
+
+sub BODY_16_19
+ {
+ local($n,$a,$b,$c,$d,$e,$f)=@_;
+
+ &comment("16_19 $n");
+
+if ($alt) {
+ &xor($c,$d);
+ &xor($f,&swtmp(($n+2)%16)); # f to hold Xupdate(xi,xa,xb,xc,xd)
+ &and($tmp1,$c); # tmp1 to hold F_00_19(b,c,d), b&=c^d
+ &xor($f,&swtmp(($n+8)%16));
+ &xor($tmp1,$d); # tmp1=F_00_19(b,c,d)
+ &xor($f,&swtmp(($n+13)%16)); # f holds xa^xb^xc^xd
+ &rotl($f,1); # f=ROTATE(f,1)
+ &add($e,$tmp1); # e+=F_00_19(b,c,d)
+ &xor($c,$d); # restore $c
+ &mov($tmp1,$a); # b in next round
+ &rotr($b,$n==16?2:7); # b=ROTATE(b,30)
+ &mov(&swtmp($n%16),$f); # xi=f
+ &rotl($a,5); # ROTATE(a,5)
+ &lea($f,&DWP(0x5a827999,$f,$e));# f+=F_00_19(b,c,d)+e
+ &mov($e,&swtmp(($n+1)%16)); # pre-fetch f for next round
+ &add($f,$a); # f+=ROTATE(a,5)
+} else {
+ &mov($tmp1,$c); # tmp1 to hold F_00_19(b,c,d)
+ &xor($f,&swtmp(($n+2)%16)); # f to hold Xupdate(xi,xa,xb,xc,xd)
+ &xor($tmp1,$d);
+ &xor($f,&swtmp(($n+8)%16));
+ &and($tmp1,$b);
+ &xor($f,&swtmp(($n+13)%16)); # f holds xa^xb^xc^xd
+ &rotl($f,1); # f=ROTATE(f,1)
+ &xor($tmp1,$d); # tmp1=F_00_19(b,c,d)
+ &add($e,$tmp1); # e+=F_00_19(b,c,d)
+ &mov($tmp1,$a);
+ &rotr($b,2); # b=ROTATE(b,30)
+ &mov(&swtmp($n%16),$f); # xi=f
+ &rotl($tmp1,5); # ROTATE(a,5)
+ &lea($f,&DWP(0x5a827999,$f,$e));# f+=F_00_19(b,c,d)+e
+ &mov($e,&swtmp(($n+1)%16)); # pre-fetch f for next round
+ &add($f,$tmp1); # f+=ROTATE(a,5)
+}
+ }
+
+sub BODY_20_39
+ {
+ local($n,$a,$b,$c,$d,$e,$f)=@_;
+ local $K=($n<40)?0x6ed9eba1:0xca62c1d6;
+
+ &comment("20_39 $n");
+
+if ($alt) {
+ &xor($tmp1,$c); # tmp1 to hold F_20_39(b,c,d), b^=c
+ &xor($f,&swtmp(($n+2)%16)); # f to hold Xupdate(xi,xa,xb,xc,xd)
+ &xor($tmp1,$d); # tmp1 holds F_20_39(b,c,d)
+ &xor($f,&swtmp(($n+8)%16));
+ &add($e,$tmp1); # e+=F_20_39(b,c,d)
+ &xor($f,&swtmp(($n+13)%16)); # f holds xa^xb^xc^xd
+ &rotl($f,1); # f=ROTATE(f,1)
+ &mov($tmp1,$a); # b in next round
+ &rotr($b,7); # b=ROTATE(b,30)
+ &mov(&swtmp($n%16),$f) if($n<77);# xi=f
+ &rotl($a,5); # ROTATE(a,5)
+ &xor($b,$c) if($n==39);# warm up for BODY_40_59
+ &and($tmp1,$b) if($n==39);
+ &lea($f,&DWP($K,$f,$e)); # f+=e+K_XX_YY
+ &mov($e,&swtmp(($n+1)%16)) if($n<79);# pre-fetch f for next round
+ &add($f,$a); # f+=ROTATE(a,5)
+ &rotr($a,5) if ($n==79);
+} else {
+ &mov($tmp1,$b); # tmp1 to hold F_20_39(b,c,d)
+ &xor($f,&swtmp(($n+2)%16)); # f to hold Xupdate(xi,xa,xb,xc,xd)
+ &xor($tmp1,$c);
+ &xor($f,&swtmp(($n+8)%16));
+ &xor($tmp1,$d); # tmp1 holds F_20_39(b,c,d)
+ &xor($f,&swtmp(($n+13)%16)); # f holds xa^xb^xc^xd
+ &rotl($f,1); # f=ROTATE(f,1)
+ &add($e,$tmp1); # e+=F_20_39(b,c,d)
+ &rotr($b,2); # b=ROTATE(b,30)
+ &mov($tmp1,$a);
+ &rotl($tmp1,5); # ROTATE(a,5)
+ &mov(&swtmp($n%16),$f) if($n<77);# xi=f
+ &lea($f,&DWP($K,$f,$e)); # f+=e+K_XX_YY
+ &mov($e,&swtmp(($n+1)%16)) if($n<79);# pre-fetch f for next round
+ &add($f,$tmp1); # f+=ROTATE(a,5)
+}
+ }
+
+sub BODY_40_59
+ {
+ local($n,$a,$b,$c,$d,$e,$f)=@_;
+
+ &comment("40_59 $n");
+
+if ($alt) {
+ &add($e,$tmp1); # e+=b&(c^d)
+ &xor($f,&swtmp(($n+2)%16)); # f to hold Xupdate(xi,xa,xb,xc,xd)
+ &mov($tmp1,$d);
+ &xor($f,&swtmp(($n+8)%16));
+ &xor($c,$d); # restore $c
+ &xor($f,&swtmp(($n+13)%16)); # f holds xa^xb^xc^xd
+ &rotl($f,1); # f=ROTATE(f,1)
+ &and($tmp1,$c);
+ &rotr($b,7); # b=ROTATE(b,30)
+ &add($e,$tmp1); # e+=c&d
+ &mov($tmp1,$a); # b in next round
+ &mov(&swtmp($n%16),$f); # xi=f
+ &rotl($a,5); # ROTATE(a,5)
+ &xor($b,$c) if ($n<59);
+ &and($tmp1,$b) if ($n<59);# tmp1 to hold F_40_59(b,c,d)
+ &lea($f,&DWP(0x8f1bbcdc,$f,$e));# f+=K_40_59+e+(b&(c^d))
+ &mov($e,&swtmp(($n+1)%16)); # pre-fetch f for next round
+ &add($f,$a); # f+=ROTATE(a,5)
+} else {
+ &mov($tmp1,$c); # tmp1 to hold F_40_59(b,c,d)
+ &xor($f,&swtmp(($n+2)%16)); # f to hold Xupdate(xi,xa,xb,xc,xd)
+ &xor($tmp1,$d);
+ &xor($f,&swtmp(($n+8)%16));
+ &and($tmp1,$b);
+ &xor($f,&swtmp(($n+13)%16)); # f holds xa^xb^xc^xd
+ &rotl($f,1); # f=ROTATE(f,1)
+ &add($tmp1,$e); # b&(c^d)+=e
+ &rotr($b,2); # b=ROTATE(b,30)
+ &mov($e,$a); # e becomes volatile
+ &rotl($e,5); # ROTATE(a,5)
+ &mov(&swtmp($n%16),$f); # xi=f
+ &lea($f,&DWP(0x8f1bbcdc,$f,$tmp1));# f+=K_40_59+e+(b&(c^d))
+ &mov($tmp1,$c);
+ &add($f,$e); # f+=ROTATE(a,5)
+ &and($tmp1,$d);
+ &mov($e,&swtmp(($n+1)%16)); # pre-fetch f for next round
+ &add($f,$tmp1); # f+=c&d
+}
+ }
+
+&function_begin("sha1_block_data_order");
+if ($xmm) {
+ &static_label("ssse3_shortcut");
+ &static_label("avx_shortcut") if ($ymm);
+ &static_label("K_XX_XX");
+
+ &call (&label("pic_point")); # make it PIC!
+ &set_label("pic_point");
+ &blindpop($tmp1);
+ &picmeup($T,"OPENSSL_ia32cap_P",$tmp1,&label("pic_point"));
+ &lea ($tmp1,&DWP(&label("K_XX_XX")."-".&label("pic_point"),$tmp1));
+
+ &mov ($A,&DWP(0,$T));
+ &mov ($D,&DWP(4,$T));
+ &test ($D,1<<9); # check SSSE3 bit
+ &jz (&label("x86"));
+ &test ($A,1<<24); # check FXSR bit
+ &jz (&label("x86"));
+ if ($ymm) {
+ &and ($D,1<<28); # mask AVX bit
+ &and ($A,1<<30); # mask "Intel CPU" bit
+ &or ($A,$D);
+ &cmp ($A,1<<28|1<<30);
+ &je (&label("avx_shortcut"));
+ }
+ &jmp (&label("ssse3_shortcut"));
+ &set_label("x86",16);
+}
+ &mov($tmp1,&wparam(0)); # SHA_CTX *c
+ &mov($T,&wparam(1)); # const void *input
+ &mov($A,&wparam(2)); # size_t num
+ &stack_push(16+3); # allocate X[16]
+ &shl($A,6);
+ &add($A,$T);
+ &mov(&wparam(2),$A); # pointer beyond the end of input
+ &mov($E,&DWP(16,$tmp1));# pre-load E
+ &jmp(&label("loop"));
+
+&set_label("loop",16);
+
+ # copy input chunk to X, but reversing byte order!
+ for ($i=0; $i<16; $i+=4)
+ {
+ &mov($A,&DWP(4*($i+0),$T));
+ &mov($B,&DWP(4*($i+1),$T));
+ &mov($C,&DWP(4*($i+2),$T));
+ &mov($D,&DWP(4*($i+3),$T));
+ &bswap($A);
+ &bswap($B);
+ &bswap($C);
+ &bswap($D);
+ &mov(&swtmp($i+0),$A);
+ &mov(&swtmp($i+1),$B);
+ &mov(&swtmp($i+2),$C);
+ &mov(&swtmp($i+3),$D);
+ }
+ &mov(&wparam(1),$T); # redundant in 1st spin
+
+ &mov($A,&DWP(0,$tmp1)); # load SHA_CTX
+ &mov($B,&DWP(4,$tmp1));
+ &mov($C,&DWP(8,$tmp1));
+ &mov($D,&DWP(12,$tmp1));
+ # E is pre-loaded
+
+ for($i=0;$i<16;$i++) { &BODY_00_15($i,@V); unshift(@V,pop(@V)); }
+ for(;$i<20;$i++) { &BODY_16_19($i,@V); unshift(@V,pop(@V)); }
+ for(;$i<40;$i++) { &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
+ for(;$i<60;$i++) { &BODY_40_59($i,@V); unshift(@V,pop(@V)); }
+ for(;$i<80;$i++) { &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
+
+ (($V[5] eq $D) and ($V[0] eq $E)) or die; # double-check
+
+ &mov($tmp1,&wparam(0)); # re-load SHA_CTX*
+ &mov($D,&wparam(1)); # D is last "T" and is discarded
+
+ &add($E,&DWP(0,$tmp1)); # E is last "A"...
+ &add($T,&DWP(4,$tmp1));
+ &add($A,&DWP(8,$tmp1));
+ &add($B,&DWP(12,$tmp1));
+ &add($C,&DWP(16,$tmp1));
+
+ &mov(&DWP(0,$tmp1),$E); # update SHA_CTX
+ &add($D,64); # advance input pointer
+ &mov(&DWP(4,$tmp1),$T);
+ &cmp($D,&wparam(2)); # have we reached the end yet?
+ &mov(&DWP(8,$tmp1),$A);
+ &mov($E,$C); # C is last "E" which needs to be "pre-loaded"
+ &mov(&DWP(12,$tmp1),$B);
+ &mov($T,$D); # input pointer
+ &mov(&DWP(16,$tmp1),$C);
+ &jb(&label("loop"));
+
+ &stack_pop(16+3);
+&function_end("sha1_block_data_order");
+
+if ($xmm) {
+######################################################################
+# The SSSE3 implementation.
+#
+# %xmm[0-7] are used as ring @X[] buffer containing quadruples of last
+# 32 elements of the message schedule or Xupdate outputs. First 4
+# quadruples are simply byte-swapped input, next 4 are calculated
+# according to method originally suggested by Dean Gaudet (modulo
+# being implemented in SSSE3). Once 8 quadruples or 32 elements are
+# collected, it switches to routine proposed by Max Locktyukhin.
+#
+# Calculations inevitably require temporary reqisters, and there are
+# no %xmm registers left to spare. For this reason part of the ring
+# buffer, X[2..4] to be specific, is offloaded to 3 quadriples ring
+# buffer on the stack. Keep in mind that X[2] is alias X[-6], X[3] -
+# X[-5], and X[4] - X[-4]...
+#
+# Another notable optimization is aggressive stack frame compression
+# aiming to minimize amount of 9-byte instructions...
+#
+# Yet another notable optimization is "jumping" $B variable. It means
+# that there is no register permanently allocated for $B value. This
+# allowed to eliminate one instruction from body_20_39...
+#
+my $Xi=4; # 4xSIMD Xupdate round, start pre-seeded
+my @X=map("xmm$_",(4..7,0..3)); # pre-seeded for $Xi=4
+my @V=($A,$B,$C,$D,$E);
+my $j=0; # hash round
+my $rx=0;
+my @T=($T,$tmp1);
+my $inp;
+
+my $_rol=sub { &rol(@_) };
+my $_ror=sub { &ror(@_) };
+
+&function_begin("_sha1_block_data_order_ssse3");
+ &call (&label("pic_point")); # make it PIC!
+ &set_label("pic_point");
+ &blindpop($tmp1);
+ &lea ($tmp1,&DWP(&label("K_XX_XX")."-".&label("pic_point"),$tmp1));
+&set_label("ssse3_shortcut");
+
+ &movdqa (@X[3],&QWP(0,$tmp1)); # K_00_19
+ &movdqa (@X[4],&QWP(16,$tmp1)); # K_20_39
+ &movdqa (@X[5],&QWP(32,$tmp1)); # K_40_59
+ &movdqa (@X[6],&QWP(48,$tmp1)); # K_60_79
+ &movdqa (@X[2],&QWP(64,$tmp1)); # pbswap mask
+
+ &mov ($E,&wparam(0)); # load argument block
+ &mov ($inp=@T[1],&wparam(1));
+ &mov ($D,&wparam(2));
+ &mov (@T[0],"esp");
+
+ # stack frame layout
+ #
+ # +0 X[0]+K X[1]+K X[2]+K X[3]+K # XMM->IALU xfer area
+ # X[4]+K X[5]+K X[6]+K X[7]+K
+ # X[8]+K X[9]+K X[10]+K X[11]+K
+ # X[12]+K X[13]+K X[14]+K X[15]+K
+ #
+ # +64 X[0] X[1] X[2] X[3] # XMM->XMM backtrace area
+ # X[4] X[5] X[6] X[7]
+ # X[8] X[9] X[10] X[11] # even borrowed for K_00_19
+ #
+ # +112 K_20_39 K_20_39 K_20_39 K_20_39 # constants
+ # K_40_59 K_40_59 K_40_59 K_40_59
+ # K_60_79 K_60_79 K_60_79 K_60_79
+ # K_00_19 K_00_19 K_00_19 K_00_19
+ # pbswap mask
+ #
+ # +192 ctx # argument block
+ # +196 inp
+ # +200 end
+ # +204 esp
+ &sub ("esp",208);
+ &and ("esp",-64);
+
+ &movdqa (&QWP(112+0,"esp"),@X[4]); # copy constants
+ &movdqa (&QWP(112+16,"esp"),@X[5]);
+ &movdqa (&QWP(112+32,"esp"),@X[6]);
+ &shl ($D,6); # len*64
+ &movdqa (&QWP(112+48,"esp"),@X[3]);
+ &add ($D,$inp); # end of input
+ &movdqa (&QWP(112+64,"esp"),@X[2]);
+ &add ($inp,64);
+ &mov (&DWP(192+0,"esp"),$E); # save argument block
+ &mov (&DWP(192+4,"esp"),$inp);
+ &mov (&DWP(192+8,"esp"),$D);
+ &mov (&DWP(192+12,"esp"),@T[0]); # save original %esp
+
+ &mov ($A,&DWP(0,$E)); # load context
+ &mov ($B,&DWP(4,$E));
+ &mov ($C,&DWP(8,$E));
+ &mov ($D,&DWP(12,$E));
+ &mov ($E,&DWP(16,$E));
+ &mov (@T[0],$B); # magic seed
+
+ &movdqu (@X[-4&7],&QWP(-64,$inp)); # load input to %xmm[0-3]
+ &movdqu (@X[-3&7],&QWP(-48,$inp));
+ &movdqu (@X[-2&7],&QWP(-32,$inp));
+ &movdqu (@X[-1&7],&QWP(-16,$inp));
+ &pshufb (@X[-4&7],@X[2]); # byte swap
+ &pshufb (@X[-3&7],@X[2]);
+ &pshufb (@X[-2&7],@X[2]);
+ &movdqa (&QWP(112-16,"esp"),@X[3]); # borrow last backtrace slot
+ &pshufb (@X[-1&7],@X[2]);
+ &paddd (@X[-4&7],@X[3]); # add K_00_19
+ &paddd (@X[-3&7],@X[3]);
+ &paddd (@X[-2&7],@X[3]);
+ &movdqa (&QWP(0,"esp"),@X[-4&7]); # X[]+K xfer to IALU
+ &psubd (@X[-4&7],@X[3]); # restore X[]
+ &movdqa (&QWP(0+16,"esp"),@X[-3&7]);
+ &psubd (@X[-3&7],@X[3]);
+ &movdqa (&QWP(0+32,"esp"),@X[-2&7]);
+ &mov (@T[1],$C);
+ &psubd (@X[-2&7],@X[3]);
+ &xor (@T[1],$D);
+ &movdqa (@X[0],@X[-3&7]);
+ &and (@T[0],@T[1]);
+ &jmp (&label("loop"));
+
+######################################################################
+# SSE instruction sequence is first broken to groups of indepentent
+# instructions, independent in respect to their inputs and shifter
+# (not all architectures have more than one). Then IALU instructions
+# are "knitted in" between the SSE groups. Distance is maintained for
+# SSE latency of 2 in hope that it fits better upcoming AMD Bulldozer
+# [which allegedly also implements SSSE3]...
+#
+# Temporary registers usage. X[2] is volatile at the entry and at the
+# end is restored from backtrace ring buffer. X[3] is expected to
+# contain current K_XX_XX constant and is used to caclulate X[-1]+K
+# from previous round, it becomes volatile the moment the value is
+# saved to stack for transfer to IALU. X[4] becomes volatile whenever
+# X[-4] is accumulated and offloaded to backtrace ring buffer, at the
+# end it is loaded with next K_XX_XX [which becomes X[3] in next
+# round]...
+#
+sub Xupdate_ssse3_16_31() # recall that $Xi starts wtih 4
+{ use integer;
+ my $body = shift;
+ my @insns = (&$body,&$body,&$body,&$body); # 40 instructions
+ my ($a,$b,$c,$d,$e);
+
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &palignr(@X[0],@X[-4&7],8); # compose "X[-14]" in "X[0]"
+ &movdqa (@X[2],@X[-1&7]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &paddd (@X[3],@X[-1&7]);
+ &movdqa (&QWP(64+16*(($Xi-4)%3),"esp"),@X[-4&7]);# save X[] to backtrace buffer
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &psrldq (@X[2],4); # "X[-3]", 3 dwords
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &pxor (@X[0],@X[-4&7]); # "X[0]"^="X[-16]"
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &pxor (@X[2],@X[-2&7]); # "X[-3]"^"X[-8]"
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &pxor (@X[0],@X[2]); # "X[0]"^="X[-3]"^"X[-8]"
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &movdqa (&QWP(0+16*(($Xi-1)&3),"esp"),@X[3]); # X[]+K xfer to IALU
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &movdqa (@X[4],@X[0]);
+ &movdqa (@X[2],@X[0]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &pslldq (@X[4],12); # "X[0]"<<96, extract one dword
+ &paddd (@X[0],@X[0]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &psrld (@X[2],31);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &movdqa (@X[3],@X[4]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &psrld (@X[4],30);
+ &por (@X[0],@X[2]); # "X[0]"<<<=1
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &movdqa (@X[2],&QWP(64+16*(($Xi-6)%3),"esp")) if ($Xi>5); # restore X[] from backtrace buffer
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &pslld (@X[3],2);
+ &pxor (@X[0],@X[4]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &movdqa (@X[4],&QWP(112-16+16*(($Xi)/5),"esp")); # K_XX_XX
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &pxor (@X[0],@X[3]); # "X[0]"^=("X[0]"<<96)<<<2
+ &movdqa (@X[1],@X[-2&7]) if ($Xi<7);
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ foreach (@insns) { eval; } # remaining instructions [if any]
+
+ $Xi++; push(@X,shift(@X)); # "rotate" X[]
+}
+
+sub Xupdate_ssse3_32_79()
+{ use integer;
+ my $body = shift;
+ my @insns = (&$body,&$body,&$body,&$body); # 32 to 44 instructions
+ my ($a,$b,$c,$d,$e);
+
+ &movdqa (@X[2],@X[-1&7]) if ($Xi==8);
+ eval(shift(@insns)); # body_20_39
+ &pxor (@X[0],@X[-4&7]); # "X[0]"="X[-32]"^"X[-16]"
+ &palignr(@X[2],@X[-2&7],8); # compose "X[-6]"
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # rol
+
+ &pxor (@X[0],@X[-7&7]); # "X[0]"^="X[-28]"
+ &movdqa (&QWP(64+16*(($Xi-4)%3),"esp"),@X[-4&7]); # save X[] to backtrace buffer
+ eval(shift(@insns));
+ eval(shift(@insns));
+ if ($Xi%5) {
+ &movdqa (@X[4],@X[3]); # "perpetuate" K_XX_XX...
+ } else { # ... or load next one
+ &movdqa (@X[4],&QWP(112-16+16*($Xi/5),"esp"));
+ }
+ &paddd (@X[3],@X[-1&7]);
+ eval(shift(@insns)); # ror
+ eval(shift(@insns));
+
+ &pxor (@X[0],@X[2]); # "X[0]"^="X[-6]"
+ eval(shift(@insns)); # body_20_39
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # rol
+
+ &movdqa (@X[2],@X[0]);
+ &movdqa (&QWP(0+16*(($Xi-1)&3),"esp"),@X[3]); # X[]+K xfer to IALU
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # ror
+ eval(shift(@insns));
+
+ &pslld (@X[0],2);
+ eval(shift(@insns)); # body_20_39
+ eval(shift(@insns));
+ &psrld (@X[2],30);
+ eval(shift(@insns));
+ eval(shift(@insns)); # rol
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # ror
+ eval(shift(@insns));
+
+ &por (@X[0],@X[2]); # "X[0]"<<<=2
+ eval(shift(@insns)); # body_20_39
+ eval(shift(@insns));
+ &movdqa (@X[2],&QWP(64+16*(($Xi-6)%3),"esp")) if($Xi<19); # restore X[] from backtrace buffer
+ eval(shift(@insns));
+ eval(shift(@insns)); # rol
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # ror
+ &movdqa (@X[3],@X[0]) if ($Xi<19);
+ eval(shift(@insns));
+
+ foreach (@insns) { eval; } # remaining instructions
+
+ $Xi++; push(@X,shift(@X)); # "rotate" X[]
+}
+
+sub Xuplast_ssse3_80()
+{ use integer;
+ my $body = shift;
+ my @insns = (&$body,&$body,&$body,&$body); # 32 instructions
+ my ($a,$b,$c,$d,$e);
+
+ eval(shift(@insns));
+ &paddd (@X[3],@X[-1&7]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &movdqa (&QWP(0+16*(($Xi-1)&3),"esp"),@X[3]); # X[]+K xfer IALU
+
+ foreach (@insns) { eval; } # remaining instructions
+
+ &mov ($inp=@T[1],&DWP(192+4,"esp"));
+ &cmp ($inp,&DWP(192+8,"esp"));
+ &je (&label("done"));
+
+ &movdqa (@X[3],&QWP(112+48,"esp")); # K_00_19
+ &movdqa (@X[2],&QWP(112+64,"esp")); # pbswap mask
+ &movdqu (@X[-4&7],&QWP(0,$inp)); # load input
+ &movdqu (@X[-3&7],&QWP(16,$inp));
+ &movdqu (@X[-2&7],&QWP(32,$inp));
+ &movdqu (@X[-1&7],&QWP(48,$inp));
+ &add ($inp,64);
+ &pshufb (@X[-4&7],@X[2]); # byte swap
+ &mov (&DWP(192+4,"esp"),$inp);
+ &movdqa (&QWP(112-16,"esp"),@X[3]); # borrow last backtrace slot
+
+ $Xi=0;
+}
+
+sub Xloop_ssse3()
+{ use integer;
+ my $body = shift;
+ my @insns = (&$body,&$body,&$body,&$body); # 32 instructions
+ my ($a,$b,$c,$d,$e);
+
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &pshufb (@X[($Xi-3)&7],@X[2]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &paddd (@X[($Xi-4)&7],@X[3]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &movdqa (&QWP(0+16*$Xi,"esp"),@X[($Xi-4)&7]); # X[]+K xfer to IALU
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &psubd (@X[($Xi-4)&7],@X[3]);
+
+ foreach (@insns) { eval; }
+ $Xi++;
+}
+
+sub Xtail_ssse3()
+{ use integer;
+ my $body = shift;
+ my @insns = (&$body,&$body,&$body,&$body); # 32 instructions
+ my ($a,$b,$c,$d,$e);
+
+ foreach (@insns) { eval; }
+}
+
+sub body_00_19 () { # ((c^d)&b)^d
+ # on start @T[0]=(c^d)&b
+ return &body_20_39() if ($rx==19); $rx++;
+ (
+ '($a,$b,$c,$d,$e)=@V;'.
+ '&$_ror ($b,$j?7:2);', # $b>>>2
+ '&xor (@T[0],$d);',
+ '&mov (@T[1],$a);', # $b in next round
+
+ '&add ($e,&DWP(4*($j&15),"esp"));', # X[]+K xfer
+ '&xor ($b,$c);', # $c^$d for next round
+
+ '&$_rol ($a,5);',
+ '&add ($e,@T[0]);',
+ '&and (@T[1],$b);', # ($b&($c^$d)) for next round
+
+ '&xor ($b,$c);', # restore $b
+ '&add ($e,$a);' .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
+ );
+}
+
+sub body_20_39 () { # b^d^c
+ # on entry @T[0]=b^d
+ return &body_40_59() if ($rx==39); $rx++;
+ (
+ '($a,$b,$c,$d,$e)=@V;'.
+ '&add ($e,&DWP(4*($j&15),"esp"));', # X[]+K xfer
+ '&xor (@T[0],$d) if($j==19);'.
+ '&xor (@T[0],$c) if($j> 19);', # ($b^$d^$c)
+ '&mov (@T[1],$a);', # $b in next round
+
+ '&$_rol ($a,5);',
+ '&add ($e,@T[0]);',
+ '&xor (@T[1],$c) if ($j< 79);', # $b^$d for next round
+
+ '&$_ror ($b,7);', # $b>>>2
+ '&add ($e,$a);' .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
+ );
+}
+
+sub body_40_59 () { # ((b^c)&(c^d))^c
+ # on entry @T[0]=(b^c), (c^=d)
+ $rx++;
+ (
+ '($a,$b,$c,$d,$e)=@V;'.
+ '&add ($e,&DWP(4*($j&15),"esp"));', # X[]+K xfer
+ '&and (@T[0],$c) if ($j>=40);', # (b^c)&(c^d)
+ '&xor ($c,$d) if ($j>=40);', # restore $c
+
+ '&$_ror ($b,7);', # $b>>>2
+ '&mov (@T[1],$a);', # $b for next round
+ '&xor (@T[0],$c);',
+
+ '&$_rol ($a,5);',
+ '&add ($e,@T[0]);',
+ '&xor (@T[1],$c) if ($j==59);'.
+ '&xor (@T[1],$b) if ($j< 59);', # b^c for next round
+
+ '&xor ($b,$c) if ($j< 59);', # c^d for next round
+ '&add ($e,$a);' .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
+ );
+}
+
+&set_label("loop",16);
+ &Xupdate_ssse3_16_31(\&body_00_19);
+ &Xupdate_ssse3_16_31(\&body_00_19);
+ &Xupdate_ssse3_16_31(\&body_00_19);
+ &Xupdate_ssse3_16_31(\&body_00_19);
+ &Xupdate_ssse3_32_79(\&body_00_19);
+ &Xupdate_ssse3_32_79(\&body_20_39);
+ &Xupdate_ssse3_32_79(\&body_20_39);
+ &Xupdate_ssse3_32_79(\&body_20_39);
+ &Xupdate_ssse3_32_79(\&body_20_39);
+ &Xupdate_ssse3_32_79(\&body_20_39);
+ &Xupdate_ssse3_32_79(\&body_40_59);
+ &Xupdate_ssse3_32_79(\&body_40_59);
+ &Xupdate_ssse3_32_79(\&body_40_59);
+ &Xupdate_ssse3_32_79(\&body_40_59);
+ &Xupdate_ssse3_32_79(\&body_40_59);
+ &Xupdate_ssse3_32_79(\&body_20_39);
+ &Xuplast_ssse3_80(\&body_20_39); # can jump to "done"
+
+ $saved_j=$j; @saved_V=@V;
+
+ &Xloop_ssse3(\&body_20_39);
+ &Xloop_ssse3(\&body_20_39);
+ &Xloop_ssse3(\&body_20_39);
+
+ &mov (@T[1],&DWP(192,"esp")); # update context
+ &add ($A,&DWP(0,@T[1]));
+ &add (@T[0],&DWP(4,@T[1])); # $b
+ &add ($C,&DWP(8,@T[1]));
+ &mov (&DWP(0,@T[1]),$A);
+ &add ($D,&DWP(12,@T[1]));
+ &mov (&DWP(4,@T[1]),@T[0]);
+ &add ($E,&DWP(16,@T[1]));
+ &mov (&DWP(8,@T[1]),$C);
+ &mov ($B,$C);
+ &mov (&DWP(12,@T[1]),$D);
+ &xor ($B,$D);
+ &mov (&DWP(16,@T[1]),$E);
+ &and ($B,@T[0]);
+ &movdqa (@X[0],@X[-3&7]);
+ &xchg ($B,@T[0]);
+
+ &jmp (&label("loop"));
+
+&set_label("done",16); $j=$saved_j; @V=@saved_V;
+
+ &Xtail_ssse3(\&body_20_39);
+ &Xtail_ssse3(\&body_20_39);
+ &Xtail_ssse3(\&body_20_39);
+
+ &mov (@T[1],&DWP(192,"esp")); # update context
+ &add ($A,&DWP(0,@T[1]));
+ &mov ("esp",&DWP(192+12,"esp")); # restore %esp
+ &add (@T[0],&DWP(4,@T[1])); # $b
+ &add ($C,&DWP(8,@T[1]));
+ &mov (&DWP(0,@T[1]),$A);
+ &add ($D,&DWP(12,@T[1]));
+ &mov (&DWP(4,@T[1]),@T[0]);
+ &add ($E,&DWP(16,@T[1]));
+ &mov (&DWP(8,@T[1]),$C);
+ &mov (&DWP(12,@T[1]),$D);
+ &mov (&DWP(16,@T[1]),$E);
+
+&function_end("_sha1_block_data_order_ssse3");
+
+$rx=0; # reset
+
+if ($ymm) {
+my $Xi=4; # 4xSIMD Xupdate round, start pre-seeded
+my @X=map("xmm$_",(4..7,0..3)); # pre-seeded for $Xi=4
+my @V=($A,$B,$C,$D,$E);
+my $j=0; # hash round
+my @T=($T,$tmp1);
+my $inp;
+
+my $_rol=sub { &shld(@_[0],@_) };
+my $_ror=sub { &shrd(@_[0],@_) };
+
+&function_begin("_sha1_block_data_order_avx");
+ &call (&label("pic_point")); # make it PIC!
+ &set_label("pic_point");
+ &blindpop($tmp1);
+ &lea ($tmp1,&DWP(&label("K_XX_XX")."-".&label("pic_point"),$tmp1));
+&set_label("avx_shortcut");
+ &vzeroall();
+
+ &vmovdqa(@X[3],&QWP(0,$tmp1)); # K_00_19
+ &vmovdqa(@X[4],&QWP(16,$tmp1)); # K_20_39
+ &vmovdqa(@X[5],&QWP(32,$tmp1)); # K_40_59
+ &vmovdqa(@X[6],&QWP(48,$tmp1)); # K_60_79
+ &vmovdqa(@X[2],&QWP(64,$tmp1)); # pbswap mask
+
+ &mov ($E,&wparam(0)); # load argument block
+ &mov ($inp=@T[1],&wparam(1));
+ &mov ($D,&wparam(2));
+ &mov (@T[0],"esp");
+
+ # stack frame layout
+ #
+ # +0 X[0]+K X[1]+K X[2]+K X[3]+K # XMM->IALU xfer area
+ # X[4]+K X[5]+K X[6]+K X[7]+K
+ # X[8]+K X[9]+K X[10]+K X[11]+K
+ # X[12]+K X[13]+K X[14]+K X[15]+K
+ #
+ # +64 X[0] X[1] X[2] X[3] # XMM->XMM backtrace area
+ # X[4] X[5] X[6] X[7]
+ # X[8] X[9] X[10] X[11] # even borrowed for K_00_19
+ #
+ # +112 K_20_39 K_20_39 K_20_39 K_20_39 # constants
+ # K_40_59 K_40_59 K_40_59 K_40_59
+ # K_60_79 K_60_79 K_60_79 K_60_79
+ # K_00_19 K_00_19 K_00_19 K_00_19
+ # pbswap mask
+ #
+ # +192 ctx # argument block
+ # +196 inp
+ # +200 end
+ # +204 esp
+ &sub ("esp",208);
+ &and ("esp",-64);
+
+ &vmovdqa(&QWP(112+0,"esp"),@X[4]); # copy constants
+ &vmovdqa(&QWP(112+16,"esp"),@X[5]);
+ &vmovdqa(&QWP(112+32,"esp"),@X[6]);
+ &shl ($D,6); # len*64
+ &vmovdqa(&QWP(112+48,"esp"),@X[3]);
+ &add ($D,$inp); # end of input
+ &vmovdqa(&QWP(112+64,"esp"),@X[2]);
+ &add ($inp,64);
+ &mov (&DWP(192+0,"esp"),$E); # save argument block
+ &mov (&DWP(192+4,"esp"),$inp);
+ &mov (&DWP(192+8,"esp"),$D);
+ &mov (&DWP(192+12,"esp"),@T[0]); # save original %esp
+
+ &mov ($A,&DWP(0,$E)); # load context
+ &mov ($B,&DWP(4,$E));
+ &mov ($C,&DWP(8,$E));
+ &mov ($D,&DWP(12,$E));
+ &mov ($E,&DWP(16,$E));
+ &mov (@T[0],$B); # magic seed
+
+ &vmovdqu(@X[-4&7],&QWP(-64,$inp)); # load input to %xmm[0-3]
+ &vmovdqu(@X[-3&7],&QWP(-48,$inp));
+ &vmovdqu(@X[-2&7],&QWP(-32,$inp));
+ &vmovdqu(@X[-1&7],&QWP(-16,$inp));
+ &vpshufb(@X[-4&7],@X[-4&7],@X[2]); # byte swap
+ &vpshufb(@X[-3&7],@X[-3&7],@X[2]);
+ &vpshufb(@X[-2&7],@X[-2&7],@X[2]);
+ &vmovdqa(&QWP(112-16,"esp"),@X[3]); # borrow last backtrace slot
+ &vpshufb(@X[-1&7],@X[-1&7],@X[2]);
+ &vpaddd (@X[0],@X[-4&7],@X[3]); # add K_00_19
+ &vpaddd (@X[1],@X[-3&7],@X[3]);
+ &vpaddd (@X[2],@X[-2&7],@X[3]);
+ &vmovdqa(&QWP(0,"esp"),@X[0]); # X[]+K xfer to IALU
+ &mov (@T[1],$C);
+ &vmovdqa(&QWP(0+16,"esp"),@X[1]);
+ &xor (@T[1],$D);
+ &vmovdqa(&QWP(0+32,"esp"),@X[2]);
+ &and (@T[0],@T[1]);
+ &jmp (&label("loop"));
+
+sub Xupdate_avx_16_31() # recall that $Xi starts wtih 4
+{ use integer;
+ my $body = shift;
+ my @insns = (&$body,&$body,&$body,&$body); # 40 instructions
+ my ($a,$b,$c,$d,$e);
+
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpalignr(@X[0],@X[-3&7],@X[-4&7],8); # compose "X[-14]" in "X[0]"
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpaddd (@X[3],@X[3],@X[-1&7]);
+ &vmovdqa (&QWP(64+16*(($Xi-4)%3),"esp"),@X[-4&7]);# save X[] to backtrace buffer
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpsrldq(@X[2],@X[-1&7],4); # "X[-3]", 3 dwords
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpxor (@X[0],@X[0],@X[-4&7]); # "X[0]"^="X[-16]"
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpxor (@X[2],@X[2],@X[-2&7]); # "X[-3]"^"X[-8]"
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vmovdqa (&QWP(0+16*(($Xi-1)&3),"esp"),@X[3]); # X[]+K xfer to IALU
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpxor (@X[0],@X[0],@X[2]); # "X[0]"^="X[-3]"^"X[-8]"
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpsrld (@X[2],@X[0],31);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpslldq(@X[4],@X[0],12); # "X[0]"<<96, extract one dword
+ &vpaddd (@X[0],@X[0],@X[0]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpsrld (@X[3],@X[4],30);
+ &vpor (@X[0],@X[0],@X[2]); # "X[0]"<<<=1
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpslld (@X[4],@X[4],2);
+ &vmovdqa (@X[2],&QWP(64+16*(($Xi-6)%3),"esp")) if ($Xi>5); # restore X[] from backtrace buffer
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpxor (@X[0],@X[0],@X[3]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpxor (@X[0],@X[0],@X[4]); # "X[0]"^=("X[0]"<<96)<<<2
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vmovdqa (@X[4],&QWP(112-16+16*(($Xi)/5),"esp")); # K_XX_XX
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ foreach (@insns) { eval; } # remaining instructions [if any]
+
+ $Xi++; push(@X,shift(@X)); # "rotate" X[]
+}
+
+sub Xupdate_avx_32_79()
+{ use integer;
+ my $body = shift;
+ my @insns = (&$body,&$body,&$body,&$body); # 32 to 44 instructions
+ my ($a,$b,$c,$d,$e);
+
+ &vpalignr(@X[2],@X[-1&7],@X[-2&7],8); # compose "X[-6]"
+ &vpxor (@X[0],@X[0],@X[-4&7]); # "X[0]"="X[-32]"^"X[-16]"
+ eval(shift(@insns)); # body_20_39
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # rol
+
+ &vpxor (@X[0],@X[0],@X[-7&7]); # "X[0]"^="X[-28]"
+ &vmovdqa (&QWP(64+16*(($Xi-4)%3),"esp"),@X[-4&7]); # save X[] to backtrace buffer
+ eval(shift(@insns));
+ eval(shift(@insns));
+ if ($Xi%5) {
+ &vmovdqa (@X[4],@X[3]); # "perpetuate" K_XX_XX...
+ } else { # ... or load next one
+ &vmovdqa (@X[4],&QWP(112-16+16*($Xi/5),"esp"));
+ }
+ &vpaddd (@X[3],@X[3],@X[-1&7]);
+ eval(shift(@insns)); # ror
+ eval(shift(@insns));
+
+ &vpxor (@X[0],@X[0],@X[2]); # "X[0]"^="X[-6]"
+ eval(shift(@insns)); # body_20_39
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # rol
+
+ &vpsrld (@X[2],@X[0],30);
+ &vmovdqa (&QWP(0+16*(($Xi-1)&3),"esp"),@X[3]); # X[]+K xfer to IALU
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # ror
+ eval(shift(@insns));
+
+ &vpslld (@X[0],@X[0],2);
+ eval(shift(@insns)); # body_20_39
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # rol
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # ror
+ eval(shift(@insns));
+
+ &vpor (@X[0],@X[0],@X[2]); # "X[0]"<<<=2
+ eval(shift(@insns)); # body_20_39
+ eval(shift(@insns));
+ &vmovdqa (@X[2],&QWP(64+16*(($Xi-6)%3),"esp")) if($Xi<19); # restore X[] from backtrace buffer
+ eval(shift(@insns));
+ eval(shift(@insns)); # rol
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # ror
+ eval(shift(@insns));
+
+ foreach (@insns) { eval; } # remaining instructions
+
+ $Xi++; push(@X,shift(@X)); # "rotate" X[]
+}
+
+sub Xuplast_avx_80()
+{ use integer;
+ my $body = shift;
+ my @insns = (&$body,&$body,&$body,&$body); # 32 instructions
+ my ($a,$b,$c,$d,$e);
+
+ eval(shift(@insns));
+ &vpaddd (@X[3],@X[3],@X[-1&7]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vmovdqa (&QWP(0+16*(($Xi-1)&3),"esp"),@X[3]); # X[]+K xfer IALU
+
+ foreach (@insns) { eval; } # remaining instructions
+
+ &mov ($inp=@T[1],&DWP(192+4,"esp"));
+ &cmp ($inp,&DWP(192+8,"esp"));
+ &je (&label("done"));
+
+ &vmovdqa(@X[3],&QWP(112+48,"esp")); # K_00_19
+ &vmovdqa(@X[2],&QWP(112+64,"esp")); # pbswap mask
+ &vmovdqu(@X[-4&7],&QWP(0,$inp)); # load input
+ &vmovdqu(@X[-3&7],&QWP(16,$inp));
+ &vmovdqu(@X[-2&7],&QWP(32,$inp));
+ &vmovdqu(@X[-1&7],&QWP(48,$inp));
+ &add ($inp,64);
+ &vpshufb(@X[-4&7],@X[-4&7],@X[2]); # byte swap
+ &mov (&DWP(192+4,"esp"),$inp);
+ &vmovdqa(&QWP(112-16,"esp"),@X[3]); # borrow last backtrace slot
+
+ $Xi=0;
+}
+
+sub Xloop_avx()
+{ use integer;
+ my $body = shift;
+ my @insns = (&$body,&$body,&$body,&$body); # 32 instructions
+ my ($a,$b,$c,$d,$e);
+
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpshufb (@X[($Xi-3)&7],@X[($Xi-3)&7],@X[2]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpaddd (@X[$Xi&7],@X[($Xi-4)&7],@X[3]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vmovdqa (&QWP(0+16*$Xi,"esp"),@X[$Xi&7]); # X[]+K xfer to IALU
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ foreach (@insns) { eval; }
+ $Xi++;
+}
+
+sub Xtail_avx()
+{ use integer;
+ my $body = shift;
+ my @insns = (&$body,&$body,&$body,&$body); # 32 instructions
+ my ($a,$b,$c,$d,$e);
+
+ foreach (@insns) { eval; }
+}
+
+&set_label("loop",16);
+ &Xupdate_avx_16_31(\&body_00_19);
+ &Xupdate_avx_16_31(\&body_00_19);
+ &Xupdate_avx_16_31(\&body_00_19);
+ &Xupdate_avx_16_31(\&body_00_19);
+ &Xupdate_avx_32_79(\&body_00_19);
+ &Xupdate_avx_32_79(\&body_20_39);
+ &Xupdate_avx_32_79(\&body_20_39);
+ &Xupdate_avx_32_79(\&body_20_39);
+ &Xupdate_avx_32_79(\&body_20_39);
+ &Xupdate_avx_32_79(\&body_20_39);
+ &Xupdate_avx_32_79(\&body_40_59);
+ &Xupdate_avx_32_79(\&body_40_59);
+ &Xupdate_avx_32_79(\&body_40_59);
+ &Xupdate_avx_32_79(\&body_40_59);
+ &Xupdate_avx_32_79(\&body_40_59);
+ &Xupdate_avx_32_79(\&body_20_39);
+ &Xuplast_avx_80(\&body_20_39); # can jump to "done"
+
+ $saved_j=$j; @saved_V=@V;
+
+ &Xloop_avx(\&body_20_39);
+ &Xloop_avx(\&body_20_39);
+ &Xloop_avx(\&body_20_39);
+
+ &mov (@T[1],&DWP(192,"esp")); # update context
+ &add ($A,&DWP(0,@T[1]));
+ &add (@T[0],&DWP(4,@T[1])); # $b
+ &add ($C,&DWP(8,@T[1]));
+ &mov (&DWP(0,@T[1]),$A);
+ &add ($D,&DWP(12,@T[1]));
+ &mov (&DWP(4,@T[1]),@T[0]);
+ &add ($E,&DWP(16,@T[1]));
+ &mov ($B,$C);
+ &mov (&DWP(8,@T[1]),$C);
+ &xor ($B,$D);
+ &mov (&DWP(12,@T[1]),$D);
+ &and ($B,@T[0]);
+ &mov (&DWP(16,@T[1]),$E);
+ &xchg ($B,@T[0]);
+
+ &jmp (&label("loop"));
+
+&set_label("done",16); $j=$saved_j; @V=@saved_V;
+
+ &Xtail_avx(\&body_20_39);
+ &Xtail_avx(\&body_20_39);
+ &Xtail_avx(\&body_20_39);
+
+ &vzeroall();
+
+ &mov (@T[1],&DWP(192,"esp")); # update context
+ &add ($A,&DWP(0,@T[1]));
+ &mov ("esp",&DWP(192+12,"esp")); # restore %esp
+ &add (@T[0],&DWP(4,@T[1])); # $b
+ &add ($C,&DWP(8,@T[1]));
+ &mov (&DWP(0,@T[1]),$A);
+ &add ($D,&DWP(12,@T[1]));
+ &mov (&DWP(4,@T[1]),@T[0]);
+ &add ($E,&DWP(16,@T[1]));
+ &mov (&DWP(8,@T[1]),$C);
+ &mov (&DWP(12,@T[1]),$D);
+ &mov (&DWP(16,@T[1]),$E);
+&function_end("_sha1_block_data_order_avx");
+}
+&set_label("K_XX_XX",64);
+&data_word(0x5a827999,0x5a827999,0x5a827999,0x5a827999); # K_00_19
+&data_word(0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1); # K_20_39
+&data_word(0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc); # K_40_59
+&data_word(0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6); # K_60_79
+&data_word(0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f); # pbswap mask
+}
+&asciz("SHA1 block transform for x86, CRYPTOGAMS by <appro\@openssl.org>");
+
+&asm_finish();
diff --git a/crypto/sha/asm/sha1-armv4-large.pl b/crypto/sha/asm/sha1-armv4-large.pl
new file mode 100644
index 0000000..6643731
--- /dev/null
+++ b/crypto/sha/asm/sha1-armv4-large.pl
@@ -0,0 +1,251 @@
+#!/usr/bin/env perl
+
+# ====================================================================
+# Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+
+# sha1_block procedure for ARMv4.
+#
+# January 2007.
+
+# Size/performance trade-off
+# ====================================================================
+# impl size in bytes comp cycles[*] measured performance
+# ====================================================================
+# thumb 304 3212 4420
+# armv4-small 392/+29% 1958/+64% 2250/+96%
+# armv4-compact 740/+89% 1552/+26% 1840/+22%
+# armv4-large 1420/+92% 1307/+19% 1370/+34%[***]
+# full unroll ~5100/+260% ~1260/+4% ~1300/+5%
+# ====================================================================
+# thumb = same as 'small' but in Thumb instructions[**] and
+# with recurring code in two private functions;
+# small = detached Xload/update, loops are folded;
+# compact = detached Xload/update, 5x unroll;
+# large = interleaved Xload/update, 5x unroll;
+# full unroll = interleaved Xload/update, full unroll, estimated[!];
+#
+# [*] Manually counted instructions in "grand" loop body. Measured
+# performance is affected by prologue and epilogue overhead,
+# i-cache availability, branch penalties, etc.
+# [**] While each Thumb instruction is twice smaller, they are not as
+# diverse as ARM ones: e.g., there are only two arithmetic
+# instructions with 3 arguments, no [fixed] rotate, addressing
+# modes are limited. As result it takes more instructions to do
+# the same job in Thumb, therefore the code is never twice as
+# small and always slower.
+# [***] which is also ~35% better than compiler generated code. Dual-
+# issue Cortex A8 core was measured to process input block in
+# ~990 cycles.
+
+# August 2010.
+#
+# Rescheduling for dual-issue pipeline resulted in 13% improvement on
+# Cortex A8 core and in absolute terms ~870 cycles per input block
+# [or 13.6 cycles per byte].
+
+# February 2011.
+#
+# Profiler-assisted and platform-specific optimization resulted in 10%
+# improvement on Cortex A8 core and 12.2 cycles per byte.
+
+while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {}
+open STDOUT,">$output";
+
+$ctx="r0";
+$inp="r1";
+$len="r2";
+$a="r3";
+$b="r4";
+$c="r5";
+$d="r6";
+$e="r7";
+$K="r8";
+$t0="r9";
+$t1="r10";
+$t2="r11";
+$t3="r12";
+$Xi="r14";
+@V=($a,$b,$c,$d,$e);
+
+sub Xupdate {
+my ($a,$b,$c,$d,$e,$opt1,$opt2)=@_;
+$code.=<<___;
+ ldr $t0,[$Xi,#15*4]
+ ldr $t1,[$Xi,#13*4]
+ ldr $t2,[$Xi,#7*4]
+ add $e,$K,$e,ror#2 @ E+=K_xx_xx
+ ldr $t3,[$Xi,#2*4]
+ eor $t0,$t0,$t1
+ eor $t2,$t2,$t3 @ 1 cycle stall
+ eor $t1,$c,$d @ F_xx_xx
+ mov $t0,$t0,ror#31
+ add $e,$e,$a,ror#27 @ E+=ROR(A,27)
+ eor $t0,$t0,$t2,ror#31
+ str $t0,[$Xi,#-4]!
+ $opt1 @ F_xx_xx
+ $opt2 @ F_xx_xx
+ add $e,$e,$t0 @ E+=X[i]
+___
+}
+
+sub BODY_00_15 {
+my ($a,$b,$c,$d,$e)=@_;
+$code.=<<___;
+#if __ARM_ARCH__<7
+ ldrb $t1,[$inp,#2]
+ ldrb $t0,[$inp,#3]
+ ldrb $t2,[$inp,#1]
+ add $e,$K,$e,ror#2 @ E+=K_00_19
+ ldrb $t3,[$inp],#4
+ orr $t0,$t0,$t1,lsl#8
+ eor $t1,$c,$d @ F_xx_xx
+ orr $t0,$t0,$t2,lsl#16
+ add $e,$e,$a,ror#27 @ E+=ROR(A,27)
+ orr $t0,$t0,$t3,lsl#24
+#else
+ ldr $t0,[$inp],#4 @ handles unaligned
+ add $e,$K,$e,ror#2 @ E+=K_00_19
+ eor $t1,$c,$d @ F_xx_xx
+ add $e,$e,$a,ror#27 @ E+=ROR(A,27)
+#ifdef __ARMEL__
+ rev $t0,$t0 @ byte swap
+#endif
+#endif
+ and $t1,$b,$t1,ror#2
+ add $e,$e,$t0 @ E+=X[i]
+ eor $t1,$t1,$d,ror#2 @ F_00_19(B,C,D)
+ str $t0,[$Xi,#-4]!
+ add $e,$e,$t1 @ E+=F_00_19(B,C,D)
+___
+}
+
+sub BODY_16_19 {
+my ($a,$b,$c,$d,$e)=@_;
+ &Xupdate(@_,"and $t1,$b,$t1,ror#2");
+$code.=<<___;
+ eor $t1,$t1,$d,ror#2 @ F_00_19(B,C,D)
+ add $e,$e,$t1 @ E+=F_00_19(B,C,D)
+___
+}
+
+sub BODY_20_39 {
+my ($a,$b,$c,$d,$e)=@_;
+ &Xupdate(@_,"eor $t1,$b,$t1,ror#2");
+$code.=<<___;
+ add $e,$e,$t1 @ E+=F_20_39(B,C,D)
+___
+}
+
+sub BODY_40_59 {
+my ($a,$b,$c,$d,$e)=@_;
+ &Xupdate(@_,"and $t1,$b,$t1,ror#2","and $t2,$c,$d");
+$code.=<<___;
+ add $e,$e,$t1 @ E+=F_40_59(B,C,D)
+ add $e,$e,$t2,ror#2
+___
+}
+
+$code=<<___;
+#if defined(__arm__)
+#include "arm_arch.h"
+
+.text
+
+.global sha1_block_data_order
+.type sha1_block_data_order,%function
+
+.align 2
+sha1_block_data_order:
+ stmdb sp!,{r4-r12,lr}
+ add $len,$inp,$len,lsl#6 @ $len to point at the end of $inp
+ ldmia $ctx,{$a,$b,$c,$d,$e}
+.Lloop:
+ ldr $K,.LK_00_19
+ mov $Xi,sp
+ sub sp,sp,#15*4
+ mov $c,$c,ror#30
+ mov $d,$d,ror#30
+ mov $e,$e,ror#30 @ [6]
+.L_00_15:
+___
+for($i=0;$i<5;$i++) {
+ &BODY_00_15(@V); unshift(@V,pop(@V));
+}
+$code.=<<___;
+ teq $Xi,sp
+ bne .L_00_15 @ [((11+4)*5+2)*3]
+ sub sp,sp,#25*4
+___
+ &BODY_00_15(@V); unshift(@V,pop(@V));
+ &BODY_16_19(@V); unshift(@V,pop(@V));
+ &BODY_16_19(@V); unshift(@V,pop(@V));
+ &BODY_16_19(@V); unshift(@V,pop(@V));
+ &BODY_16_19(@V); unshift(@V,pop(@V));
+$code.=<<___;
+
+ ldr $K,.LK_20_39 @ [+15+16*4]
+ cmn sp,#0 @ [+3], clear carry to denote 20_39
+.L_20_39_or_60_79:
+___
+for($i=0;$i<5;$i++) {
+ &BODY_20_39(@V); unshift(@V,pop(@V));
+}
+$code.=<<___;
+ teq $Xi,sp @ preserve carry
+ bne .L_20_39_or_60_79 @ [+((12+3)*5+2)*4]
+ bcs .L_done @ [+((12+3)*5+2)*4], spare 300 bytes
+
+ ldr $K,.LK_40_59
+ sub sp,sp,#20*4 @ [+2]
+.L_40_59:
+___
+for($i=0;$i<5;$i++) {
+ &BODY_40_59(@V); unshift(@V,pop(@V));
+}
+$code.=<<___;
+ teq $Xi,sp
+ bne .L_40_59 @ [+((12+5)*5+2)*4]
+
+ ldr $K,.LK_60_79
+ sub sp,sp,#20*4
+ cmp sp,#0 @ set carry to denote 60_79
+ b .L_20_39_or_60_79 @ [+4], spare 300 bytes
+.L_done:
+ add sp,sp,#80*4 @ "deallocate" stack frame
+ ldmia $ctx,{$K,$t0,$t1,$t2,$t3}
+ add $a,$K,$a
+ add $b,$t0,$b
+ add $c,$t1,$c,ror#2
+ add $d,$t2,$d,ror#2
+ add $e,$t3,$e,ror#2
+ stmia $ctx,{$a,$b,$c,$d,$e}
+ teq $inp,$len
+ bne .Lloop @ [+18], total 1307
+
+#if __ARM_ARCH__>=5
+ ldmia sp!,{r4-r12,pc}
+#else
+ ldmia sp!,{r4-r12,lr}
+ tst lr,#1
+ moveq pc,lr @ be binary compatible with V4, yet
+ bx lr @ interoperable with Thumb ISA:-)
+#endif
+.align 2
+.LK_00_19: .word 0x5a827999
+.LK_20_39: .word 0x6ed9eba1
+.LK_40_59: .word 0x8f1bbcdc
+.LK_60_79: .word 0xca62c1d6
+.size sha1_block_data_order,.-sha1_block_data_order
+.asciz "SHA1 block transform for ARMv4, CRYPTOGAMS by <appro\@openssl.org>"
+.align 2
+
+#endif
+___
+
+$code =~ s/\bbx\s+lr\b/.word\t0xe12fff1e/gm; # make it possible to compile with -march=armv4
+print $code;
+close STDOUT; # enforce flush
diff --git a/crypto/sha/asm/sha1-x86_64.pl b/crypto/sha/asm/sha1-x86_64.pl
new file mode 100644
index 0000000..194b5ff
--- /dev/null
+++ b/crypto/sha/asm/sha1-x86_64.pl
@@ -0,0 +1,1837 @@
+#!/usr/bin/env perl
+#
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+#
+# sha1_block procedure for x86_64.
+#
+# It was brought to my attention that on EM64T compiler-generated code
+# was far behind 32-bit assembler implementation. This is unlike on
+# Opteron where compiler-generated code was only 15% behind 32-bit
+# assembler, which originally made it hard to motivate the effort.
+# There was suggestion to mechanically translate 32-bit code, but I
+# dismissed it, reasoning that x86_64 offers enough register bank
+# capacity to fully utilize SHA-1 parallelism. Therefore this fresh
+# implementation:-) However! While 64-bit code does perform better
+# on Opteron, I failed to beat 32-bit assembler on EM64T core. Well,
+# x86_64 does offer larger *addressable* bank, but out-of-order core
+# reaches for even more registers through dynamic aliasing, and EM64T
+# core must have managed to run-time optimize even 32-bit code just as
+# good as 64-bit one. Performance improvement is summarized in the
+# following table:
+#
+# gcc 3.4 32-bit asm cycles/byte
+# Opteron +45% +20% 6.8
+# Xeon P4 +65% +0% 9.9
+# Core2 +60% +10% 7.0
+
+# August 2009.
+#
+# The code was revised to minimize code size and to maximize
+# "distance" between instructions producing input to 'lea'
+# instruction and the 'lea' instruction itself, which is essential
+# for Intel Atom core.
+
+# October 2010.
+#
+# Add SSSE3, Supplemental[!] SSE3, implementation. The idea behind it
+# is to offload message schedule denoted by Wt in NIST specification,
+# or Xupdate in OpenSSL source, to SIMD unit. See sha1-586.pl module
+# for background and implementation details. The only difference from
+# 32-bit code is that 64-bit code doesn't have to spill @X[] elements
+# to free temporary registers.
+
+# April 2011.
+#
+# Add AVX code path. See sha1-586.pl for further information.
+
+# May 2013.
+#
+# Add AVX2+BMI code path. Initial attempt (utilizing BMI instructions
+# and loading pair of consecutive blocks to 256-bit %ymm registers)
+# did not provide impressive performance improvement till a crucial
+# hint regarding the number of Xupdate iterations to pre-compute in
+# advance was provided by Ilya Albrekht of Intel Corp.
+
+######################################################################
+# Current performance is summarized in following table. Numbers are
+# CPU clock cycles spent to process single byte (less is better).
+#
+# x86_64 SSSE3 AVX[2]
+# P4 9.8 -
+# Opteron 6.65 -
+# Core2 6.70 6.05/+11% -
+# Westmere 7.08 5.44/+30% -
+# Sandy Bridge 7.93 6.16/+28% 4.99/+59%
+# Ivy Bridge 6.30 4.63/+36% 4.60/+37%
+# Haswell 5.98 4.12/+45% 3.57/+67%
+# Bulldozer 10.9 5.95/+82%
+# VIA Nano 10.2 7.46/+37%
+# Atom 11.0 9.61/+14%
+
+$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";
+
+if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
+ =~ /GNU assembler version ([2-9]\.[0-9]+)/) {
+ $avx = ($1>=2.19) + ($1>=2.22);
+}
+
+if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
+ `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
+ $avx = ($1>=2.09) + ($1>=2.10);
+}
+
+if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
+ `ml64 2>&1` =~ /Version ([0-9]+)\./) {
+ $avx = ($1>=10) + ($1>=11);
+}
+
+open OUT,"| \"$^X\" $xlate $flavour $output";
+*STDOUT=*OUT;
+
+$ctx="%rdi"; # 1st arg
+$inp="%rsi"; # 2nd arg
+$num="%rdx"; # 3rd arg
+
+# reassign arguments in order to produce more compact code
+$ctx="%r8";
+$inp="%r9";
+$num="%r10";
+
+$t0="%eax";
+$t1="%ebx";
+$t2="%ecx";
+@xi=("%edx","%ebp");
+$A="%esi";
+$B="%edi";
+$C="%r11d";
+$D="%r12d";
+$E="%r13d";
+
+@V=($A,$B,$C,$D,$E);
+
+sub BODY_00_19 {
+my ($i,$a,$b,$c,$d,$e)=@_;
+my $j=$i+1;
+$code.=<<___ if ($i==0);
+ mov `4*$i`($inp),$xi[0]
+ bswap $xi[0]
+ mov $xi[0],`4*$i`(%rsp)
+___
+$code.=<<___ if ($i<15);
+ mov $c,$t0
+ mov `4*$j`($inp),$xi[1]
+ mov $a,$t2
+ xor $d,$t0
+ bswap $xi[1]
+ rol \$5,$t2
+ lea 0x5a827999($xi[0],$e),$e
+ and $b,$t0
+ mov $xi[1],`4*$j`(%rsp)
+ add $t2,$e
+ xor $d,$t0
+ rol \$30,$b
+ add $t0,$e
+___
+$code.=<<___ if ($i>=15);
+ mov `4*($j%16)`(%rsp),$xi[1]
+ mov $c,$t0
+ mov $a,$t2
+ xor `4*(($j+2)%16)`(%rsp),$xi[1]
+ xor $d,$t0
+ rol \$5,$t2
+ xor `4*(($j+8)%16)`(%rsp),$xi[1]
+ and $b,$t0
+ lea 0x5a827999($xi[0],$e),$e
+ xor `4*(($j+13)%16)`(%rsp),$xi[1]
+ xor $d,$t0
+ rol \$1,$xi[1]
+ add $t2,$e
+ rol \$30,$b
+ mov $xi[1],`4*($j%16)`(%rsp)
+ add $t0,$e
+___
+unshift(@xi,pop(@xi));
+}
+
+sub BODY_20_39 {
+my ($i,$a,$b,$c,$d,$e)=@_;
+my $j=$i+1;
+my $K=($i<40)?0x6ed9eba1:0xca62c1d6;
+$code.=<<___ if ($i<79);
+ mov `4*($j%16)`(%rsp),$xi[1]
+ mov $c,$t0
+ mov $a,$t2
+ xor `4*(($j+2)%16)`(%rsp),$xi[1]
+ xor $b,$t0
+ rol \$5,$t2
+ lea $K($xi[0],$e),$e
+ xor `4*(($j+8)%16)`(%rsp),$xi[1]
+ xor $d,$t0
+ add $t2,$e
+ xor `4*(($j+13)%16)`(%rsp),$xi[1]
+ rol \$30,$b
+ add $t0,$e
+ rol \$1,$xi[1]
+___
+$code.=<<___ if ($i<76);
+ mov $xi[1],`4*($j%16)`(%rsp)
+___
+$code.=<<___ if ($i==79);
+ mov $c,$t0
+ mov $a,$t2
+ xor $b,$t0
+ lea $K($xi[0],$e),$e
+ rol \$5,$t2
+ xor $d,$t0
+ add $t2,$e
+ rol \$30,$b
+ add $t0,$e
+___
+unshift(@xi,pop(@xi));
+}
+
+sub BODY_40_59 {
+my ($i,$a,$b,$c,$d,$e)=@_;
+my $j=$i+1;
+$code.=<<___;
+ mov `4*($j%16)`(%rsp),$xi[1]
+ mov $c,$t0
+ mov $c,$t1
+ xor `4*(($j+2)%16)`(%rsp),$xi[1]
+ and $d,$t0
+ mov $a,$t2
+ xor `4*(($j+8)%16)`(%rsp),$xi[1]
+ xor $d,$t1
+ lea 0x8f1bbcdc($xi[0],$e),$e
+ rol \$5,$t2
+ xor `4*(($j+13)%16)`(%rsp),$xi[1]
+ add $t0,$e
+ and $b,$t1
+ rol \$1,$xi[1]
+ add $t1,$e
+ rol \$30,$b
+ mov $xi[1],`4*($j%16)`(%rsp)
+ add $t2,$e
+___
+unshift(@xi,pop(@xi));
+}
+
+$code.=<<___;
+.text
+.extern OPENSSL_ia32cap_P
+
+.globl sha1_block_data_order
+.type sha1_block_data_order,\@function,3
+.align 16
+sha1_block_data_order:
+ mov OPENSSL_ia32cap_P+0(%rip),%r9d
+ mov OPENSSL_ia32cap_P+4(%rip),%r8d
+ mov OPENSSL_ia32cap_P+8(%rip),%r10d
+ test \$`1<<9`,%r8d # check SSSE3 bit
+ jz .Lialu
+___
+$code.=<<___ if ($avx>1);
+ and \$`1<<3|1<<5|1<<8`,%r10d # check AVX2+BMI1+BMI2
+ cmp \$`1<<3|1<<5|1<<8`,%r10d
+ je _avx2_shortcut
+___
+$code.=<<___ if ($avx);
+ and \$`1<<28`,%r8d # mask AVX bit
+ and \$`1<<30`,%r9d # mask "Intel CPU" bit
+ or %r9d,%r8d
+ cmp \$`1<<28|1<<30`,%r8d
+ je _avx_shortcut
+___
+$code.=<<___;
+ jmp _ssse3_shortcut
+
+.align 16
+.Lialu:
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ mov %rsp,%r11
+ mov %rdi,$ctx # reassigned argument
+ sub \$`8+16*4`,%rsp
+ mov %rsi,$inp # reassigned argument
+ and \$-64,%rsp
+ mov %rdx,$num # reassigned argument
+ mov %r11,`16*4`(%rsp)
+.Lprologue:
+
+ mov 0($ctx),$A
+ mov 4($ctx),$B
+ mov 8($ctx),$C
+ mov 12($ctx),$D
+ mov 16($ctx),$E
+ jmp .Lloop
+
+.align 16
+.Lloop:
+___
+for($i=0;$i<20;$i++) { &BODY_00_19($i,@V); unshift(@V,pop(@V)); }
+for(;$i<40;$i++) { &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
+for(;$i<60;$i++) { &BODY_40_59($i,@V); unshift(@V,pop(@V)); }
+for(;$i<80;$i++) { &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
+$code.=<<___;
+ add 0($ctx),$A
+ add 4($ctx),$B
+ add 8($ctx),$C
+ add 12($ctx),$D
+ add 16($ctx),$E
+ mov $A,0($ctx)
+ mov $B,4($ctx)
+ mov $C,8($ctx)
+ mov $D,12($ctx)
+ mov $E,16($ctx)
+
+ sub \$1,$num
+ lea `16*4`($inp),$inp
+ jnz .Lloop
+
+ mov `16*4`(%rsp),%rsi
+ mov (%rsi),%r13
+ mov 8(%rsi),%r12
+ mov 16(%rsi),%rbp
+ mov 24(%rsi),%rbx
+ lea 32(%rsi),%rsp
+.Lepilogue:
+ ret
+.size sha1_block_data_order,.-sha1_block_data_order
+___
+{{{
+my $Xi=4;
+my @X=map("%xmm$_",(4..7,0..3));
+my @Tx=map("%xmm$_",(8..10));
+my $Kx="%xmm11";
+my @V=($A,$B,$C,$D,$E)=("%eax","%ebx","%ecx","%edx","%ebp"); # size optimization
+my @T=("%esi","%edi");
+my $j=0;
+my $rx=0;
+my $K_XX_XX="%r11";
+
+my $_rol=sub { &rol(@_) };
+my $_ror=sub { &ror(@_) };
+
+{ my $sn;
+sub align32() {
+ ++$sn;
+$code.=<<___;
+ jmp .Lalign32_$sn # see "Decoded ICache" in manual
+.align 32
+.Lalign32_$sn:
+___
+}
+}
+
+$code.=<<___;
+.type sha1_block_data_order_ssse3,\@function,3
+.align 16
+sha1_block_data_order_ssse3:
+_ssse3_shortcut:
+ mov %rsp,%rax
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13 # redundant, done to share Win64 SE handler
+ push %r14
+ lea `-64-($win64?6*16:0)`(%rsp),%rsp
+___
+$code.=<<___ if ($win64);
+ movaps %xmm6,-40-6*16(%rax)
+ movaps %xmm7,-40-5*16(%rax)
+ movaps %xmm8,-40-4*16(%rax)
+ movaps %xmm9,-40-3*16(%rax)
+ movaps %xmm10,-40-2*16(%rax)
+ movaps %xmm11,-40-1*16(%rax)
+.Lprologue_ssse3:
+___
+$code.=<<___;
+ mov %rax,%r14 # original %rsp
+ and \$-64,%rsp
+ mov %rdi,$ctx # reassigned argument
+ mov %rsi,$inp # reassigned argument
+ mov %rdx,$num # reassigned argument
+
+ shl \$6,$num
+ add $inp,$num
+ lea K_XX_XX+64(%rip),$K_XX_XX
+
+ mov 0($ctx),$A # load context
+ mov 4($ctx),$B
+ mov 8($ctx),$C
+ mov 12($ctx),$D
+ mov $B,@T[0] # magic seed
+ mov 16($ctx),$E
+ mov $C,@T[1]
+ xor $D,@T[1]
+ and @T[1],@T[0]
+
+ movdqa 64($K_XX_XX),@X[2] # pbswap mask
+ movdqa -64($K_XX_XX),@Tx[1] # K_00_19
+ movdqu 0($inp),@X[-4&7] # load input to %xmm[0-3]
+ movdqu 16($inp),@X[-3&7]
+ movdqu 32($inp),@X[-2&7]
+ movdqu 48($inp),@X[-1&7]
+ pshufb @X[2],@X[-4&7] # byte swap
+ add \$64,$inp
+ pshufb @X[2],@X[-3&7]
+ pshufb @X[2],@X[-2&7]
+ pshufb @X[2],@X[-1&7]
+ paddd @Tx[1],@X[-4&7] # add K_00_19
+ paddd @Tx[1],@X[-3&7]
+ paddd @Tx[1],@X[-2&7]
+ movdqa @X[-4&7],0(%rsp) # X[]+K xfer to IALU
+ psubd @Tx[1],@X[-4&7] # restore X[]
+ movdqa @X[-3&7],16(%rsp)
+ psubd @Tx[1],@X[-3&7]
+ movdqa @X[-2&7],32(%rsp)
+ psubd @Tx[1],@X[-2&7]
+ jmp .Loop_ssse3
+___
+
+sub AUTOLOAD() # thunk [simplified] 32-bit style perlasm
+{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://;
+ my $arg = pop;
+ $arg = "\$$arg" if ($arg*1 eq $arg);
+ $code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n";
+}
+
+sub Xupdate_ssse3_16_31() # recall that $Xi starts wtih 4
+{ use integer;
+ my $body = shift;
+ my @insns = (&$body,&$body,&$body,&$body); # 40 instructions
+ my ($a,$b,$c,$d,$e);
+
+ &movdqa (@X[0],@X[-3&7]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &movdqa (@Tx[0],@X[-1&7]);
+ &palignr(@X[0],@X[-4&7],8); # compose "X[-14]" in "X[0]"
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &paddd (@Tx[1],@X[-1&7]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &psrldq (@Tx[0],4); # "X[-3]", 3 dwords
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &pxor (@X[0],@X[-4&7]); # "X[0]"^="X[-16]"
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &pxor (@Tx[0],@X[-2&7]); # "X[-3]"^"X[-8]"
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &pxor (@X[0],@Tx[0]); # "X[0]"^="X[-3]"^"X[-8]"
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &movdqa (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &movdqa (@Tx[2],@X[0]);
+ &movdqa (@Tx[0],@X[0]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &pslldq (@Tx[2],12); # "X[0]"<<96, extract one dword
+ &paddd (@X[0],@X[0]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &psrld (@Tx[0],31);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &movdqa (@Tx[1],@Tx[2]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &psrld (@Tx[2],30);
+ &por (@X[0],@Tx[0]); # "X[0]"<<<=1
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &pslld (@Tx[1],2);
+ &pxor (@X[0],@Tx[2]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &movdqa (@Tx[2],eval(2*16*(($Xi)/5)-64)."($K_XX_XX)"); # K_XX_XX
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &pxor (@X[0],@Tx[1]); # "X[0]"^=("X[0]">>96)<<<2
+
+ foreach (@insns) { eval; } # remaining instructions [if any]
+
+ $Xi++; push(@X,shift(@X)); # "rotate" X[]
+ push(@Tx,shift(@Tx));
+}
+
+sub Xupdate_ssse3_32_79()
+{ use integer;
+ my $body = shift;
+ my @insns = (&$body,&$body,&$body,&$body); # 32 to 44 instructions
+ my ($a,$b,$c,$d,$e);
+
+ &movdqa (@Tx[0],@X[-1&7]) if ($Xi==8);
+ eval(shift(@insns)); # body_20_39
+ &pxor (@X[0],@X[-4&7]); # "X[0]"="X[-32]"^"X[-16]"
+ &palignr(@Tx[0],@X[-2&7],8); # compose "X[-6]"
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # rol
+
+ &pxor (@X[0],@X[-7&7]); # "X[0]"^="X[-28]"
+ eval(shift(@insns));
+ eval(shift(@insns)) if (@insns[0] !~ /&ro[rl]/);
+ if ($Xi%5) {
+ &movdqa (@Tx[2],@Tx[1]);# "perpetuate" K_XX_XX...
+ } else { # ... or load next one
+ &movdqa (@Tx[2],eval(2*16*($Xi/5)-64)."($K_XX_XX)");
+ }
+ &paddd (@Tx[1],@X[-1&7]);
+ eval(shift(@insns)); # ror
+ eval(shift(@insns));
+
+ &pxor (@X[0],@Tx[0]); # "X[0]"^="X[-6]"
+ eval(shift(@insns)); # body_20_39
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # rol
+
+ &movdqa (@Tx[0],@X[0]);
+ &movdqa (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # ror
+ eval(shift(@insns));
+
+ &pslld (@X[0],2);
+ eval(shift(@insns)); # body_20_39
+ eval(shift(@insns));
+ &psrld (@Tx[0],30);
+ eval(shift(@insns));
+ eval(shift(@insns)); # rol
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # ror
+ eval(shift(@insns));
+
+ &por (@X[0],@Tx[0]); # "X[0]"<<<=2
+ eval(shift(@insns)); # body_20_39
+ eval(shift(@insns));
+ &movdqa (@Tx[1],@X[0]) if ($Xi<19);
+ eval(shift(@insns));
+ eval(shift(@insns)); # rol
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # rol
+ eval(shift(@insns));
+
+ foreach (@insns) { eval; } # remaining instructions
+
+ $Xi++; push(@X,shift(@X)); # "rotate" X[]
+ push(@Tx,shift(@Tx));
+}
+
+sub Xuplast_ssse3_80()
+{ use integer;
+ my $body = shift;
+ my @insns = (&$body,&$body,&$body,&$body); # 32 instructions
+ my ($a,$b,$c,$d,$e);
+
+ eval(shift(@insns));
+ &paddd (@Tx[1],@X[-1&7]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &movdqa (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer IALU
+
+ foreach (@insns) { eval; } # remaining instructions
+
+ &cmp ($inp,$num);
+ &je (".Ldone_ssse3");
+
+ unshift(@Tx,pop(@Tx));
+
+ &movdqa (@X[2],"64($K_XX_XX)"); # pbswap mask
+ &movdqa (@Tx[1],"-64($K_XX_XX)"); # K_00_19
+ &movdqu (@X[-4&7],"0($inp)"); # load input
+ &movdqu (@X[-3&7],"16($inp)");
+ &movdqu (@X[-2&7],"32($inp)");
+ &movdqu (@X[-1&7],"48($inp)");
+ &pshufb (@X[-4&7],@X[2]); # byte swap
+ &add ($inp,64);
+
+ $Xi=0;
+}
+
+sub Xloop_ssse3()
+{ use integer;
+ my $body = shift;
+ my @insns = (&$body,&$body,&$body,&$body); # 32 instructions
+ my ($a,$b,$c,$d,$e);
+
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &pshufb (@X[($Xi-3)&7],@X[2]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &paddd (@X[($Xi-4)&7],@Tx[1]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &movdqa (eval(16*$Xi)."(%rsp)",@X[($Xi-4)&7]); # X[]+K xfer to IALU
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &psubd (@X[($Xi-4)&7],@Tx[1]);
+
+ foreach (@insns) { eval; }
+ $Xi++;
+}
+
+sub Xtail_ssse3()
+{ use integer;
+ my $body = shift;
+ my @insns = (&$body,&$body,&$body,&$body); # 32 instructions
+ my ($a,$b,$c,$d,$e);
+
+ foreach (@insns) { eval; }
+}
+
+sub body_00_19 () { # ((c^d)&b)^d
+ # on start @T[0]=(c^d)&b
+ return &body_20_39() if ($rx==19); $rx++;
+ (
+ '($a,$b,$c,$d,$e)=@V;'.
+ '&$_ror ($b,$j?7:2)', # $b>>>2
+ '&xor (@T[0],$d)',
+ '&mov (@T[1],$a)', # $b for next round
+
+ '&add ($e,eval(4*($j&15))."(%rsp)")', # X[]+K xfer
+ '&xor ($b,$c)', # $c^$d for next round
+
+ '&$_rol ($a,5)',
+ '&add ($e,@T[0])',
+ '&and (@T[1],$b)', # ($b&($c^$d)) for next round
+
+ '&xor ($b,$c)', # restore $b
+ '&add ($e,$a);' .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
+ );
+}
+
+sub body_20_39 () { # b^d^c
+ # on entry @T[0]=b^d
+ return &body_40_59() if ($rx==39); $rx++;
+ (
+ '($a,$b,$c,$d,$e)=@V;'.
+ '&add ($e,eval(4*($j&15))."(%rsp)")', # X[]+K xfer
+ '&xor (@T[0],$d) if($j==19);'.
+ '&xor (@T[0],$c) if($j> 19)', # ($b^$d^$c)
+ '&mov (@T[1],$a)', # $b for next round
+
+ '&$_rol ($a,5)',
+ '&add ($e,@T[0])',
+ '&xor (@T[1],$c) if ($j< 79)', # $b^$d for next round
+
+ '&$_ror ($b,7)', # $b>>>2
+ '&add ($e,$a);' .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
+ );
+}
+
+sub body_40_59 () { # ((b^c)&(c^d))^c
+ # on entry @T[0]=(b^c), (c^=d)
+ $rx++;
+ (
+ '($a,$b,$c,$d,$e)=@V;'.
+ '&add ($e,eval(4*($j&15))."(%rsp)")', # X[]+K xfer
+ '&and (@T[0],$c) if ($j>=40)', # (b^c)&(c^d)
+ '&xor ($c,$d) if ($j>=40)', # restore $c
+
+ '&$_ror ($b,7)', # $b>>>2
+ '&mov (@T[1],$a)', # $b for next round
+ '&xor (@T[0],$c)',
+
+ '&$_rol ($a,5)',
+ '&add ($e,@T[0])',
+ '&xor (@T[1],$c) if ($j==59);'.
+ '&xor (@T[1],$b) if ($j< 59)', # b^c for next round
+
+ '&xor ($b,$c) if ($j< 59)', # c^d for next round
+ '&add ($e,$a);' .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
+ );
+}
+$code.=<<___;
+.align 16
+.Loop_ssse3:
+___
+ &Xupdate_ssse3_16_31(\&body_00_19);
+ &Xupdate_ssse3_16_31(\&body_00_19);
+ &Xupdate_ssse3_16_31(\&body_00_19);
+ &Xupdate_ssse3_16_31(\&body_00_19);
+ &Xupdate_ssse3_32_79(\&body_00_19);
+ &Xupdate_ssse3_32_79(\&body_20_39);
+ &Xupdate_ssse3_32_79(\&body_20_39);
+ &Xupdate_ssse3_32_79(\&body_20_39);
+ &Xupdate_ssse3_32_79(\&body_20_39);
+ &Xupdate_ssse3_32_79(\&body_20_39);
+ &Xupdate_ssse3_32_79(\&body_40_59);
+ &Xupdate_ssse3_32_79(\&body_40_59);
+ &Xupdate_ssse3_32_79(\&body_40_59);
+ &Xupdate_ssse3_32_79(\&body_40_59);
+ &Xupdate_ssse3_32_79(\&body_40_59);
+ &Xupdate_ssse3_32_79(\&body_20_39);
+ &Xuplast_ssse3_80(\&body_20_39); # can jump to "done"
+
+ $saved_j=$j; @saved_V=@V;
+
+ &Xloop_ssse3(\&body_20_39);
+ &Xloop_ssse3(\&body_20_39);
+ &Xloop_ssse3(\&body_20_39);
+
+$code.=<<___;
+ add 0($ctx),$A # update context
+ add 4($ctx),@T[0]
+ add 8($ctx),$C
+ add 12($ctx),$D
+ mov $A,0($ctx)
+ add 16($ctx),$E
+ mov @T[0],4($ctx)
+ mov @T[0],$B # magic seed
+ mov $C,8($ctx)
+ mov $C,@T[1]
+ mov $D,12($ctx)
+ xor $D,@T[1]
+ mov $E,16($ctx)
+ and @T[1],@T[0]
+ jmp .Loop_ssse3
+
+.align 16
+.Ldone_ssse3:
+___
+ $j=$saved_j; @V=@saved_V;
+
+ &Xtail_ssse3(\&body_20_39);
+ &Xtail_ssse3(\&body_20_39);
+ &Xtail_ssse3(\&body_20_39);
+
+$code.=<<___;
+ add 0($ctx),$A # update context
+ add 4($ctx),@T[0]
+ add 8($ctx),$C
+ mov $A,0($ctx)
+ add 12($ctx),$D
+ mov @T[0],4($ctx)
+ add 16($ctx),$E
+ mov $C,8($ctx)
+ mov $D,12($ctx)
+ mov $E,16($ctx)
+___
+$code.=<<___ if ($win64);
+ movaps -40-6*16(%r14),%xmm6
+ movaps -40-5*16(%r14),%xmm7
+ movaps -40-4*16(%r14),%xmm8
+ movaps -40-3*16(%r14),%xmm9
+ movaps -40-2*16(%r14),%xmm10
+ movaps -40-1*16(%r14),%xmm11
+___
+$code.=<<___;
+ lea (%r14),%rsi
+ mov -40(%rsi),%r14
+ mov -32(%rsi),%r13
+ mov -24(%rsi),%r12
+ mov -16(%rsi),%rbp
+ mov -8(%rsi),%rbx
+ lea (%rsi),%rsp
+.Lepilogue_ssse3:
+ ret
+.size sha1_block_data_order_ssse3,.-sha1_block_data_order_ssse3
+___
+
+if ($avx) {
+$Xi=4; # reset variables
+@X=map("%xmm$_",(4..7,0..3));
+@Tx=map("%xmm$_",(8..10));
+$j=0;
+$rx=0;
+
+my $done_avx_label=".Ldone_avx";
+
+my $_rol=sub { &shld(@_[0],@_) };
+my $_ror=sub { &shrd(@_[0],@_) };
+
+$code.=<<___;
+.type sha1_block_data_order_avx,\@function,3
+.align 16
+sha1_block_data_order_avx:
+_avx_shortcut:
+ mov %rsp,%rax
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13 # redundant, done to share Win64 SE handler
+ push %r14
+ lea `-64-($win64?6*16:0)`(%rsp),%rsp
+ vzeroupper
+___
+$code.=<<___ if ($win64);
+ vmovaps %xmm6,-40-6*16(%rax)
+ vmovaps %xmm7,-40-5*16(%rax)
+ vmovaps %xmm8,-40-4*16(%rax)
+ vmovaps %xmm9,-40-3*16(%rax)
+ vmovaps %xmm10,-40-2*16(%rax)
+ vmovaps %xmm11,-40-1*16(%rax)
+.Lprologue_avx:
+___
+$code.=<<___;
+ mov %rax,%r14 # original %rsp
+ and \$-64,%rsp
+ mov %rdi,$ctx # reassigned argument
+ mov %rsi,$inp # reassigned argument
+ mov %rdx,$num # reassigned argument
+
+ shl \$6,$num
+ add $inp,$num
+ lea K_XX_XX+64(%rip),$K_XX_XX
+
+ mov 0($ctx),$A # load context
+ mov 4($ctx),$B
+ mov 8($ctx),$C
+ mov 12($ctx),$D
+ mov $B,@T[0] # magic seed
+ mov 16($ctx),$E
+ mov $C,@T[1]
+ xor $D,@T[1]
+ and @T[1],@T[0]
+
+ vmovdqa 64($K_XX_XX),@X[2] # pbswap mask
+ vmovdqa -64($K_XX_XX),$Kx # K_00_19
+ vmovdqu 0($inp),@X[-4&7] # load input to %xmm[0-3]
+ vmovdqu 16($inp),@X[-3&7]
+ vmovdqu 32($inp),@X[-2&7]
+ vmovdqu 48($inp),@X[-1&7]
+ vpshufb @X[2],@X[-4&7],@X[-4&7] # byte swap
+ add \$64,$inp
+ vpshufb @X[2],@X[-3&7],@X[-3&7]
+ vpshufb @X[2],@X[-2&7],@X[-2&7]
+ vpshufb @X[2],@X[-1&7],@X[-1&7]
+ vpaddd $Kx,@X[-4&7],@X[0] # add K_00_19
+ vpaddd $Kx,@X[-3&7],@X[1]
+ vpaddd $Kx,@X[-2&7],@X[2]
+ vmovdqa @X[0],0(%rsp) # X[]+K xfer to IALU
+ vmovdqa @X[1],16(%rsp)
+ vmovdqa @X[2],32(%rsp)
+ jmp .Loop_avx
+___
+
+sub Xupdate_avx_16_31() # recall that $Xi starts wtih 4
+{ use integer;
+ my $body = shift;
+ my @insns = (&$body,&$body,&$body,&$body); # 40 instructions
+ my ($a,$b,$c,$d,$e);
+
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpalignr(@X[0],@X[-3&7],@X[-4&7],8); # compose "X[-14]" in "X[0]"
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpaddd (@Tx[1],$Kx,@X[-1&7]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpsrldq(@Tx[0],@X[-1&7],4); # "X[-3]", 3 dwords
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpxor (@X[0],@X[0],@X[-4&7]); # "X[0]"^="X[-16]"
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpxor (@Tx[0],@Tx[0],@X[-2&7]); # "X[-3]"^"X[-8]"
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpxor (@X[0],@X[0],@Tx[0]); # "X[0]"^="X[-3]"^"X[-8]"
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vmovdqa (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpsrld (@Tx[0],@X[0],31);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpslldq(@Tx[2],@X[0],12); # "X[0]"<<96, extract one dword
+ &vpaddd (@X[0],@X[0],@X[0]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpsrld (@Tx[1],@Tx[2],30);
+ &vpor (@X[0],@X[0],@Tx[0]); # "X[0]"<<<=1
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpslld (@Tx[2],@Tx[2],2);
+ &vpxor (@X[0],@X[0],@Tx[1]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpxor (@X[0],@X[0],@Tx[2]); # "X[0]"^=("X[0]">>96)<<<2
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vmovdqa ($Kx,eval(2*16*(($Xi)/5)-64)."($K_XX_XX)") if ($Xi%5==0); # K_XX_XX
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+
+ foreach (@insns) { eval; } # remaining instructions [if any]
+
+ $Xi++; push(@X,shift(@X)); # "rotate" X[]
+}
+
+sub Xupdate_avx_32_79()
+{ use integer;
+ my $body = shift;
+ my @insns = (&$body,&$body,&$body,&$body); # 32 to 44 instructions
+ my ($a,$b,$c,$d,$e);
+
+ &vpalignr(@Tx[0],@X[-1&7],@X[-2&7],8); # compose "X[-6]"
+ &vpxor (@X[0],@X[0],@X[-4&7]); # "X[0]"="X[-32]"^"X[-16]"
+ eval(shift(@insns)); # body_20_39
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # rol
+
+ &vpxor (@X[0],@X[0],@X[-7&7]); # "X[0]"^="X[-28]"
+ eval(shift(@insns));
+ eval(shift(@insns)) if (@insns[0] !~ /&ro[rl]/);
+ &vpaddd (@Tx[1],$Kx,@X[-1&7]);
+ &vmovdqa ($Kx,eval(2*16*($Xi/5)-64)."($K_XX_XX)") if ($Xi%5==0);
+ eval(shift(@insns)); # ror
+ eval(shift(@insns));
+
+ &vpxor (@X[0],@X[0],@Tx[0]); # "X[0]"^="X[-6]"
+ eval(shift(@insns)); # body_20_39
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # rol
+
+ &vpsrld (@Tx[0],@X[0],30);
+ &vmovdqa (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # ror
+ eval(shift(@insns));
+
+ &vpslld (@X[0],@X[0],2);
+ eval(shift(@insns)); # body_20_39
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # rol
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # ror
+ eval(shift(@insns));
+
+ &vpor (@X[0],@X[0],@Tx[0]); # "X[0]"<<<=2
+ eval(shift(@insns)); # body_20_39
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # rol
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # rol
+ eval(shift(@insns));
+
+ foreach (@insns) { eval; } # remaining instructions
+
+ $Xi++; push(@X,shift(@X)); # "rotate" X[]
+}
+
+sub Xuplast_avx_80()
+{ use integer;
+ my $body = shift;
+ my @insns = (&$body,&$body,&$body,&$body); # 32 instructions
+ my ($a,$b,$c,$d,$e);
+
+ eval(shift(@insns));
+ &vpaddd (@Tx[1],$Kx,@X[-1&7]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vmovdqa (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer IALU
+
+ foreach (@insns) { eval; } # remaining instructions
+
+ &cmp ($inp,$num);
+ &je ($done_avx_label);
+
+ &vmovdqa(@X[2],"64($K_XX_XX)"); # pbswap mask
+ &vmovdqa($Kx,"-64($K_XX_XX)"); # K_00_19
+ &vmovdqu(@X[-4&7],"0($inp)"); # load input
+ &vmovdqu(@X[-3&7],"16($inp)");
+ &vmovdqu(@X[-2&7],"32($inp)");
+ &vmovdqu(@X[-1&7],"48($inp)");
+ &vpshufb(@X[-4&7],@X[-4&7],@X[2]); # byte swap
+ &add ($inp,64);
+
+ $Xi=0;
+}
+
+sub Xloop_avx()
+{ use integer;
+ my $body = shift;
+ my @insns = (&$body,&$body,&$body,&$body); # 32 instructions
+ my ($a,$b,$c,$d,$e);
+
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpshufb(@X[($Xi-3)&7],@X[($Xi-3)&7],@X[2]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpaddd (@X[$Xi&7],@X[($Xi-4)&7],$Kx);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vmovdqa(eval(16*$Xi)."(%rsp)",@X[$Xi&7]); # X[]+K xfer to IALU
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ foreach (@insns) { eval; }
+ $Xi++;
+}
+
+sub Xtail_avx()
+{ use integer;
+ my $body = shift;
+ my @insns = (&$body,&$body,&$body,&$body); # 32 instructions
+ my ($a,$b,$c,$d,$e);
+
+ foreach (@insns) { eval; }
+}
+
+$code.=<<___;
+.align 16
+.Loop_avx:
+___
+ &Xupdate_avx_16_31(\&body_00_19);
+ &Xupdate_avx_16_31(\&body_00_19);
+ &Xupdate_avx_16_31(\&body_00_19);
+ &Xupdate_avx_16_31(\&body_00_19);
+ &Xupdate_avx_32_79(\&body_00_19);
+ &Xupdate_avx_32_79(\&body_20_39);
+ &Xupdate_avx_32_79(\&body_20_39);
+ &Xupdate_avx_32_79(\&body_20_39);
+ &Xupdate_avx_32_79(\&body_20_39);
+ &Xupdate_avx_32_79(\&body_20_39);
+ &Xupdate_avx_32_79(\&body_40_59);
+ &Xupdate_avx_32_79(\&body_40_59);
+ &Xupdate_avx_32_79(\&body_40_59);
+ &Xupdate_avx_32_79(\&body_40_59);
+ &Xupdate_avx_32_79(\&body_40_59);
+ &Xupdate_avx_32_79(\&body_20_39);
+ &Xuplast_avx_80(\&body_20_39); # can jump to "done"
+
+ $saved_j=$j; @saved_V=@V;
+
+ &Xloop_avx(\&body_20_39);
+ &Xloop_avx(\&body_20_39);
+ &Xloop_avx(\&body_20_39);
+
+$code.=<<___;
+ add 0($ctx),$A # update context
+ add 4($ctx),@T[0]
+ add 8($ctx),$C
+ add 12($ctx),$D
+ mov $A,0($ctx)
+ add 16($ctx),$E
+ mov @T[0],4($ctx)
+ mov @T[0],$B # magic seed
+ mov $C,8($ctx)
+ mov $C,@T[1]
+ mov $D,12($ctx)
+ xor $D,@T[1]
+ mov $E,16($ctx)
+ and @T[1],@T[0]
+ jmp .Loop_avx
+
+.align 16
+$done_avx_label:
+___
+ $j=$saved_j; @V=@saved_V;
+
+ &Xtail_avx(\&body_20_39);
+ &Xtail_avx(\&body_20_39);
+ &Xtail_avx(\&body_20_39);
+
+$code.=<<___;
+ vzeroupper
+
+ add 0($ctx),$A # update context
+ add 4($ctx),@T[0]
+ add 8($ctx),$C
+ mov $A,0($ctx)
+ add 12($ctx),$D
+ mov @T[0],4($ctx)
+ add 16($ctx),$E
+ mov $C,8($ctx)
+ mov $D,12($ctx)
+ mov $E,16($ctx)
+___
+$code.=<<___ if ($win64);
+ movaps -40-6*16(%r14),%xmm6
+ movaps -40-5*16(%r14),%xmm7
+ movaps -40-4*16(%r14),%xmm8
+ movaps -40-3*16(%r14),%xmm9
+ movaps -40-2*16(%r14),%xmm10
+ movaps -40-1*16(%r14),%xmm11
+___
+$code.=<<___;
+ lea (%r14),%rsi
+ mov -40(%rsi),%r14
+ mov -32(%rsi),%r13
+ mov -24(%rsi),%r12
+ mov -16(%rsi),%rbp
+ mov -8(%rsi),%rbx
+ lea (%rsi),%rsp
+.Lepilogue_avx:
+ ret
+.size sha1_block_data_order_avx,.-sha1_block_data_order_avx
+___
+
+if ($avx>1) {
+use integer;
+$Xi=4; # reset variables
+@X=map("%ymm$_",(4..7,0..3));
+@Tx=map("%ymm$_",(8..10));
+$Kx="%ymm11";
+$j=0;
+
+my @ROTX=("%eax","%ebp","%ebx","%ecx","%edx","%esi");
+my ($a5,$t0)=("%r12d","%edi");
+
+my ($A,$F,$B,$C,$D,$E)=@ROTX;
+my $rx=0;
+my $frame="%r13";
+
+$code.=<<___;
+.type sha1_block_data_order_avx2,\@function,3
+.align 16
+sha1_block_data_order_avx2:
+_avx2_shortcut:
+ mov %rsp,%rax
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ vzeroupper
+___
+$code.=<<___ if ($win64);
+ lea -6*16(%rsp),%rsp
+ vmovaps %xmm6,-40-6*16(%rax)
+ vmovaps %xmm7,-40-5*16(%rax)
+ vmovaps %xmm8,-40-4*16(%rax)
+ vmovaps %xmm9,-40-3*16(%rax)
+ vmovaps %xmm10,-40-2*16(%rax)
+ vmovaps %xmm11,-40-1*16(%rax)
+.Lprologue_avx2:
+___
+$code.=<<___;
+ mov %rax,%r14 # original %rsp
+ mov %rdi,$ctx # reassigned argument
+ mov %rsi,$inp # reassigned argument
+ mov %rdx,$num # reassigned argument
+
+ lea -640(%rsp),%rsp
+ shl \$6,$num
+ lea 64($inp),$frame
+ and \$-128,%rsp
+ add $inp,$num
+ lea K_XX_XX+64(%rip),$K_XX_XX
+
+ mov 0($ctx),$A # load context
+ cmp $num,$frame
+ cmovae $inp,$frame # next or same block
+ mov 4($ctx),$F
+ mov 8($ctx),$C
+ mov 12($ctx),$D
+ mov 16($ctx),$E
+ vmovdqu 64($K_XX_XX),@X[2] # pbswap mask
+
+ vmovdqu ($inp),%xmm0
+ vmovdqu 16($inp),%xmm1
+ vmovdqu 32($inp),%xmm2
+ vmovdqu 48($inp),%xmm3
+ lea 64($inp),$inp
+ vinserti128 \$1,($frame),@X[-4&7],@X[-4&7]
+ vinserti128 \$1,16($frame),@X[-3&7],@X[-3&7]
+ vpshufb @X[2],@X[-4&7],@X[-4&7]
+ vinserti128 \$1,32($frame),@X[-2&7],@X[-2&7]
+ vpshufb @X[2],@X[-3&7],@X[-3&7]
+ vinserti128 \$1,48($frame),@X[-1&7],@X[-1&7]
+ vpshufb @X[2],@X[-2&7],@X[-2&7]
+ vmovdqu -64($K_XX_XX),$Kx # K_00_19
+ vpshufb @X[2],@X[-1&7],@X[-1&7]
+
+ vpaddd $Kx,@X[-4&7],@X[0] # add K_00_19
+ vpaddd $Kx,@X[-3&7],@X[1]
+ vmovdqu @X[0],0(%rsp) # X[]+K xfer to IALU
+ vpaddd $Kx,@X[-2&7],@X[2]
+ vmovdqu @X[1],32(%rsp)
+ vpaddd $Kx,@X[-1&7],@X[3]
+ vmovdqu @X[2],64(%rsp)
+ vmovdqu @X[3],96(%rsp)
+___
+for (;$Xi<8;$Xi++) { # Xupdate_avx2_16_31
+ use integer;
+
+ &vpalignr(@X[0],@X[-3&7],@X[-4&7],8); # compose "X[-14]" in "X[0]"
+ &vpsrldq(@Tx[0],@X[-1&7],4); # "X[-3]", 3 dwords
+ &vpxor (@X[0],@X[0],@X[-4&7]); # "X[0]"^="X[-16]"
+ &vpxor (@Tx[0],@Tx[0],@X[-2&7]); # "X[-3]"^"X[-8]"
+ &vpxor (@X[0],@X[0],@Tx[0]); # "X[0]"^="X[-3]"^"X[-8]"
+ &vpsrld (@Tx[0],@X[0],31);
+ &vmovdqu($Kx,eval(2*16*(($Xi)/5)-64)."($K_XX_XX)") if ($Xi%5==0); # K_XX_XX
+ &vpslldq(@Tx[2],@X[0],12); # "X[0]"<<96, extract one dword
+ &vpaddd (@X[0],@X[0],@X[0]);
+ &vpsrld (@Tx[1],@Tx[2],30);
+ &vpor (@X[0],@X[0],@Tx[0]); # "X[0]"<<<=1
+ &vpslld (@Tx[2],@Tx[2],2);
+ &vpxor (@X[0],@X[0],@Tx[1]);
+ &vpxor (@X[0],@X[0],@Tx[2]); # "X[0]"^=("X[0]">>96)<<<2
+ &vpaddd (@Tx[1],@X[0],$Kx);
+ &vmovdqu("32*$Xi(%rsp)",@Tx[1]); # X[]+K xfer to IALU
+
+ push(@X,shift(@X)); # "rotate" X[]
+}
+$code.=<<___;
+ lea 128(%rsp),$frame
+ jmp .Loop_avx2
+.align 32
+.Loop_avx2:
+ rorx \$2,$F,$B
+ andn $D,$F,$t0
+ and $C,$F
+ xor $t0,$F
+___
+sub bodyx_00_19 () { # 8 instructions, 3 cycles critical path
+ # at start $f=(b&c)^(~b&d), $b>>>=2
+ return &bodyx_20_39() if ($rx==19); $rx++;
+ (
+ '($a,$f,$b,$c,$d,$e)=@ROTX;'.
+
+ '&add ($e,((32*($j/4)+4*($j%4))%256-128)."($frame)");'. # e+=X[i]+K
+ '&lea ($frame,"256($frame)") if ($j%32==31);',
+ '&andn ($t0,$a,$c)', # ~b&d for next round
+
+ '&add ($e,$f)', # e+=(b&c)^(~b&d)
+ '&rorx ($a5,$a,27)', # a<<<5
+ '&rorx ($f,$a,2)', # b>>>2 for next round
+ '&and ($a,$b)', # b&c for next round
+
+ '&add ($e,$a5)', # e+=a<<<5
+ '&xor ($a,$t0);'. # f=(b&c)^(~b&d) for next round
+
+ 'unshift(@ROTX,pop(@ROTX)); $j++;'
+ )
+}
+
+sub bodyx_20_39 () { # 7 instructions, 2 cycles critical path
+ # on entry $f=b^c^d, $b>>>=2
+ return &bodyx_40_59() if ($rx==39); $rx++;
+ (
+ '($a,$f,$b,$c,$d,$e)=@ROTX;'.
+
+ '&add ($e,((32*($j/4)+4*($j%4))%256-128)."($frame)");'. # e+=X[i]+K
+ '&lea ($frame,"256($frame)") if ($j%32==31);',
+
+ '&lea ($e,"($e,$f)")', # e+=b^c^d
+ '&rorx ($a5,$a,27)', # a<<<5
+ '&rorx ($f,$a,2) if ($j<79)', # b>>>2 in next round
+ '&xor ($a,$b) if ($j<79)', # b^c for next round
+
+ '&add ($e,$a5)', # e+=a<<<5
+ '&xor ($a,$c) if ($j<79);'. # f=b^c^d for next round
+
+ 'unshift(@ROTX,pop(@ROTX)); $j++;'
+ )
+}
+
+sub bodyx_40_59 () { # 10 instructions, 3 cycles critical path
+ # on entry $f=((b^c)&(c^d)), $b>>>=2
+ $rx++;
+ (
+ '($a,$f,$b,$c,$d,$e)=@ROTX;'.
+
+ '&add ($e,((32*($j/4)+4*($j%4))%256-128)."($frame)");'. # e+=X[i]+K
+ '&lea ($frame,"256($frame)") if ($j%32==31);',
+ '&xor ($f,$c) if ($j>39)', # (b^c)&(c^d)^c
+ '&mov ($t0,$b) if ($j<59)', # count on zero latency
+ '&xor ($t0,$c) if ($j<59)', # c^d for next round
+
+ '&lea ($e,"($e,$f)")', # e+=(b^c)&(c^d)^c
+ '&rorx ($a5,$a,27)', # a<<<5
+ '&rorx ($f,$a,2)', # b>>>2 in next round
+ '&xor ($a,$b)', # b^c for next round
+
+ '&add ($e,$a5)', # e+=a<<<5
+ '&and ($a,$t0) if ($j< 59);'. # f=(b^c)&(c^d) for next round
+ '&xor ($a,$c) if ($j==59);'. # f=b^c^d for next round
+
+ 'unshift(@ROTX,pop(@ROTX)); $j++;'
+ )
+}
+
+sub Xupdate_avx2_16_31() # recall that $Xi starts wtih 4
+{ use integer;
+ my $body = shift;
+ my @insns = (&$body,&$body,&$body,&$body,&$body); # 35 instructions
+ my ($a,$b,$c,$d,$e);
+
+ &vpalignr(@X[0],@X[-3&7],@X[-4&7],8); # compose "X[-14]" in "X[0]"
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpsrldq(@Tx[0],@X[-1&7],4); # "X[-3]", 3 dwords
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpxor (@X[0],@X[0],@X[-4&7]); # "X[0]"^="X[-16]"
+ &vpxor (@Tx[0],@Tx[0],@X[-2&7]); # "X[-3]"^"X[-8]"
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpxor (@X[0],@X[0],@Tx[0]); # "X[0]"^="X[-3]"^"X[-8]"
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpsrld (@Tx[0],@X[0],31);
+ &vmovdqu($Kx,eval(2*16*(($Xi)/5)-64)."($K_XX_XX)") if ($Xi%5==0); # K_XX_XX
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpslldq(@Tx[2],@X[0],12); # "X[0]"<<96, extract one dword
+ &vpaddd (@X[0],@X[0],@X[0]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpsrld (@Tx[1],@Tx[2],30);
+ &vpor (@X[0],@X[0],@Tx[0]); # "X[0]"<<<=1
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpslld (@Tx[2],@Tx[2],2);
+ &vpxor (@X[0],@X[0],@Tx[1]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpxor (@X[0],@X[0],@Tx[2]); # "X[0]"^=("X[0]">>96)<<<2
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpaddd (@Tx[1],@X[0],$Kx);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vmovdqu(eval(32*($Xi))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU
+
+ foreach (@insns) { eval; } # remaining instructions [if any]
+
+ $Xi++;
+ push(@X,shift(@X)); # "rotate" X[]
+}
+
+sub Xupdate_avx2_32_79()
+{ use integer;
+ my $body = shift;
+ my @insns = (&$body,&$body,&$body,&$body,&$body); # 35 to 50 instructions
+ my ($a,$b,$c,$d,$e);
+
+ &vpalignr(@Tx[0],@X[-1&7],@X[-2&7],8); # compose "X[-6]"
+ &vpxor (@X[0],@X[0],@X[-4&7]); # "X[0]"="X[-32]"^"X[-16]"
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpxor (@X[0],@X[0],@X[-7&7]); # "X[0]"^="X[-28]"
+ &vmovdqu($Kx,eval(2*16*($Xi/5)-64)."($K_XX_XX)") if ($Xi%5==0);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpxor (@X[0],@X[0],@Tx[0]); # "X[0]"^="X[-6]"
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpsrld (@Tx[0],@X[0],30);
+ &vpslld (@X[0],@X[0],2);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ #&vpslld (@X[0],@X[0],2);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpor (@X[0],@X[0],@Tx[0]); # "X[0]"<<<=2
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vpaddd (@Tx[1],@X[0],$Kx);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ &vmovdqu("32*$Xi(%rsp)",@Tx[1]); # X[]+K xfer to IALU
+
+ foreach (@insns) { eval; } # remaining instructions
+
+ $Xi++;
+ push(@X,shift(@X)); # "rotate" X[]
+}
+
+sub Xloop_avx2()
+{ use integer;
+ my $body = shift;
+ my @insns = (&$body,&$body,&$body,&$body,&$body); # 32 instructions
+ my ($a,$b,$c,$d,$e);
+
+ foreach (@insns) { eval; }
+}
+
+ &align32();
+ &Xupdate_avx2_32_79(\&bodyx_00_19);
+ &Xupdate_avx2_32_79(\&bodyx_00_19);
+ &Xupdate_avx2_32_79(\&bodyx_00_19);
+ &Xupdate_avx2_32_79(\&bodyx_00_19);
+
+ &Xupdate_avx2_32_79(\&bodyx_20_39);
+ &Xupdate_avx2_32_79(\&bodyx_20_39);
+ &Xupdate_avx2_32_79(\&bodyx_20_39);
+ &Xupdate_avx2_32_79(\&bodyx_20_39);
+
+ &align32();
+ &Xupdate_avx2_32_79(\&bodyx_40_59);
+ &Xupdate_avx2_32_79(\&bodyx_40_59);
+ &Xupdate_avx2_32_79(\&bodyx_40_59);
+ &Xupdate_avx2_32_79(\&bodyx_40_59);
+
+ &Xloop_avx2(\&bodyx_20_39);
+ &Xloop_avx2(\&bodyx_20_39);
+ &Xloop_avx2(\&bodyx_20_39);
+ &Xloop_avx2(\&bodyx_20_39);
+
+$code.=<<___;
+ lea 128($inp),$frame
+ lea 128($inp),%rdi # borrow $t0
+ cmp $num,$frame
+ cmovae $inp,$frame # next or previous block
+
+ # output is d-e-[a]-f-b-c => A=d,F=e,C=f,D=b,E=c
+ add 0($ctx),@ROTX[0] # update context
+ add 4($ctx),@ROTX[1]
+ add 8($ctx),@ROTX[3]
+ mov @ROTX[0],0($ctx)
+ add 12($ctx),@ROTX[4]
+ mov @ROTX[1],4($ctx)
+ mov @ROTX[0],$A # A=d
+ add 16($ctx),@ROTX[5]
+ mov @ROTX[3],$a5
+ mov @ROTX[3],8($ctx)
+ mov @ROTX[4],$D # D=b
+ #xchg @ROTX[5],$F # F=c, C=f
+ mov @ROTX[4],12($ctx)
+ mov @ROTX[1],$F # F=e
+ mov @ROTX[5],16($ctx)
+ #mov $F,16($ctx)
+ mov @ROTX[5],$E # E=c
+ mov $a5,$C # C=f
+ #xchg $F,$E # E=c, F=e
+
+ cmp $num,$inp
+ je .Ldone_avx2
+___
+
+$Xi=4; # reset variables
+@X=map("%ymm$_",(4..7,0..3));
+
+$code.=<<___;
+ vmovdqu 64($K_XX_XX),@X[2] # pbswap mask
+ cmp $num,%rdi # borrowed $t0
+ ja .Last_avx2
+
+ vmovdqu -64(%rdi),%xmm0 # low part of @X[-4&7]
+ vmovdqu -48(%rdi),%xmm1
+ vmovdqu -32(%rdi),%xmm2
+ vmovdqu -16(%rdi),%xmm3
+ vinserti128 \$1,0($frame),@X[-4&7],@X[-4&7]
+ vinserti128 \$1,16($frame),@X[-3&7],@X[-3&7]
+ vinserti128 \$1,32($frame),@X[-2&7],@X[-2&7]
+ vinserti128 \$1,48($frame),@X[-1&7],@X[-1&7]
+ jmp .Last_avx2
+
+.align 32
+.Last_avx2:
+ lea 128+16(%rsp),$frame
+ rorx \$2,$F,$B
+ andn $D,$F,$t0
+ and $C,$F
+ xor $t0,$F
+ sub \$-128,$inp
+___
+ $rx=$j=0; @ROTX=($A,$F,$B,$C,$D,$E);
+
+ &Xloop_avx2 (\&bodyx_00_19);
+ &Xloop_avx2 (\&bodyx_00_19);
+ &Xloop_avx2 (\&bodyx_00_19);
+ &Xloop_avx2 (\&bodyx_00_19);
+
+ &Xloop_avx2 (\&bodyx_20_39);
+ &vmovdqu ($Kx,"-64($K_XX_XX)"); # K_00_19
+ &vpshufb (@X[-4&7],@X[-4&7],@X[2]); # byte swap
+ &Xloop_avx2 (\&bodyx_20_39);
+ &vpshufb (@X[-3&7],@X[-3&7],@X[2]);
+ &vpaddd (@Tx[0],@X[-4&7],$Kx); # add K_00_19
+ &Xloop_avx2 (\&bodyx_20_39);
+ &vmovdqu ("0(%rsp)",@Tx[0]);
+ &vpshufb (@X[-2&7],@X[-2&7],@X[2]);
+ &vpaddd (@Tx[1],@X[-3&7],$Kx);
+ &Xloop_avx2 (\&bodyx_20_39);
+ &vmovdqu ("32(%rsp)",@Tx[1]);
+ &vpshufb (@X[-1&7],@X[-1&7],@X[2]);
+ &vpaddd (@X[2],@X[-2&7],$Kx);
+
+ &Xloop_avx2 (\&bodyx_40_59);
+ &align32 ();
+ &vmovdqu ("64(%rsp)",@X[2]);
+ &vpaddd (@X[3],@X[-1&7],$Kx);
+ &Xloop_avx2 (\&bodyx_40_59);
+ &vmovdqu ("96(%rsp)",@X[3]);
+ &Xloop_avx2 (\&bodyx_40_59);
+ &Xupdate_avx2_16_31(\&bodyx_40_59);
+
+ &Xupdate_avx2_16_31(\&bodyx_20_39);
+ &Xupdate_avx2_16_31(\&bodyx_20_39);
+ &Xupdate_avx2_16_31(\&bodyx_20_39);
+ &Xloop_avx2 (\&bodyx_20_39);
+
+$code.=<<___;
+ lea 128(%rsp),$frame
+
+ # output is d-e-[a]-f-b-c => A=d,F=e,C=f,D=b,E=c
+ add 0($ctx),@ROTX[0] # update context
+ add 4($ctx),@ROTX[1]
+ add 8($ctx),@ROTX[3]
+ mov @ROTX[0],0($ctx)
+ add 12($ctx),@ROTX[4]
+ mov @ROTX[1],4($ctx)
+ mov @ROTX[0],$A # A=d
+ add 16($ctx),@ROTX[5]
+ mov @ROTX[3],$a5
+ mov @ROTX[3],8($ctx)
+ mov @ROTX[4],$D # D=b
+ #xchg @ROTX[5],$F # F=c, C=f
+ mov @ROTX[4],12($ctx)
+ mov @ROTX[1],$F # F=e
+ mov @ROTX[5],16($ctx)
+ #mov $F,16($ctx)
+ mov @ROTX[5],$E # E=c
+ mov $a5,$C # C=f
+ #xchg $F,$E # E=c, F=e
+
+ cmp $num,$inp
+ jbe .Loop_avx2
+
+.Ldone_avx2:
+ vzeroupper
+___
+$code.=<<___ if ($win64);
+ movaps -40-6*16(%r14),%xmm6
+ movaps -40-5*16(%r14),%xmm7
+ movaps -40-4*16(%r14),%xmm8
+ movaps -40-3*16(%r14),%xmm9
+ movaps -40-2*16(%r14),%xmm10
+ movaps -40-1*16(%r14),%xmm11
+___
+$code.=<<___;
+ lea (%r14),%rsi
+ mov -40(%rsi),%r14
+ mov -32(%rsi),%r13
+ mov -24(%rsi),%r12
+ mov -16(%rsi),%rbp
+ mov -8(%rsi),%rbx
+ lea (%rsi),%rsp
+.Lepilogue_avx2:
+ ret
+.size sha1_block_data_order_avx2,.-sha1_block_data_order_avx2
+___
+}
+}
+$code.=<<___;
+.align 64
+K_XX_XX:
+.long 0x5a827999,0x5a827999,0x5a827999,0x5a827999 # K_00_19
+.long 0x5a827999,0x5a827999,0x5a827999,0x5a827999 # K_00_19
+.long 0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1 # K_20_39
+.long 0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1 # K_20_39
+.long 0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc # K_40_59
+.long 0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc # K_40_59
+.long 0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6 # K_60_79
+.long 0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6 # K_60_79
+.long 0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f # pbswap mask
+.long 0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f # pbswap mask
+___
+}}}
+$code.=<<___;
+.asciz "SHA1 block transform for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
+.align 64
+___
+
+# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
+# CONTEXT *context,DISPATCHER_CONTEXT *disp)
+if ($win64) {
+$rec="%rcx";
+$frame="%rdx";
+$context="%r8";
+$disp="%r9";
+
+$code.=<<___;
+.extern __imp_RtlVirtualUnwind
+.type se_handler,\@abi-omnipotent
+.align 16
+se_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 120($context),%rax # pull context->Rax
+ mov 248($context),%rbx # pull context->Rip
+
+ lea .Lprologue(%rip),%r10
+ cmp %r10,%rbx # context->Rip<.Lprologue
+ jb .Lcommon_seh_tail
+
+ mov 152($context),%rax # pull context->Rsp
+
+ lea .Lepilogue(%rip),%r10
+ cmp %r10,%rbx # context->Rip>=.Lepilogue
+ jae .Lcommon_seh_tail
+
+ mov `16*4`(%rax),%rax # pull saved stack pointer
+ lea 32(%rax),%rax
+
+ mov -8(%rax),%rbx
+ mov -16(%rax),%rbp
+ mov -24(%rax),%r12
+ mov -32(%rax),%r13
+ mov %rbx,144($context) # restore context->Rbx
+ mov %rbp,160($context) # restore context->Rbp
+ mov %r12,216($context) # restore context->R12
+ mov %r13,224($context) # restore context->R13
+
+ jmp .Lcommon_seh_tail
+.size se_handler,.-se_handler
+
+.type ssse3_handler,\@abi-omnipotent
+.align 16
+ssse3_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 120($context),%rax # pull context->Rax
+ mov 248($context),%rbx # pull context->Rip
+
+ mov 8($disp),%rsi # disp->ImageBase
+ mov 56($disp),%r11 # disp->HandlerData
+
+ mov 0(%r11),%r10d # HandlerData[0]
+ lea (%rsi,%r10),%r10 # prologue label
+ cmp %r10,%rbx # context->Rip<prologue label
+ jb .Lcommon_seh_tail
+
+ mov 152($context),%rax # pull context->Rsp
+
+ mov 4(%r11),%r10d # HandlerData[1]
+ lea (%rsi,%r10),%r10 # epilogue label
+ cmp %r10,%rbx # context->Rip>=epilogue label
+ jae .Lcommon_seh_tail
+
+ mov 232($context),%rax # pull context->R14
+
+ lea -40-6*16(%rax),%rsi
+ lea 512($context),%rdi # &context.Xmm6
+ mov \$12,%ecx
+ .long 0xa548f3fc # cld; rep movsq
+
+ mov -8(%rax),%rbx
+ mov -16(%rax),%rbp
+ mov -24(%rax),%r12
+ mov -32(%rax),%r13
+ mov -40(%rax),%r14
+ mov %rbx,144($context) # restore context->Rbx
+ mov %rbp,160($context) # restore context->Rbp
+ mov %r12,216($context) # restore cotnext->R12
+ mov %r13,224($context) # restore cotnext->R13
+ mov %r14,232($context) # restore cotnext->R14
+
+.Lcommon_seh_tail:
+ mov 8(%rax),%rdi
+ mov 16(%rax),%rsi
+ mov %rax,152($context) # restore context->Rsp
+ mov %rsi,168($context) # restore context->Rsi
+ mov %rdi,176($context) # restore context->Rdi
+
+ mov 40($disp),%rdi # disp->ContextRecord
+ mov $context,%rsi # context
+ mov \$154,%ecx # sizeof(CONTEXT)
+ .long 0xa548f3fc # cld; rep movsq
+
+ mov $disp,%rsi
+ xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER
+ mov 8(%rsi),%rdx # arg2, disp->ImageBase
+ mov 0(%rsi),%r8 # arg3, disp->ControlPc
+ mov 16(%rsi),%r9 # arg4, disp->FunctionEntry
+ mov 40(%rsi),%r10 # disp->ContextRecord
+ lea 56(%rsi),%r11 # &disp->HandlerData
+ lea 24(%rsi),%r12 # &disp->EstablisherFrame
+ mov %r10,32(%rsp) # arg5
+ mov %r11,40(%rsp) # arg6
+ mov %r12,48(%rsp) # arg7
+ mov %rcx,56(%rsp) # arg8, (NULL)
+ call *__imp_RtlVirtualUnwind(%rip)
+
+ mov \$1,%eax # ExceptionContinueSearch
+ add \$64,%rsp
+ popfq
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+ pop %rdi
+ pop %rsi
+ ret
+.size ssse3_handler,.-ssse3_handler
+
+.section .pdata
+.align 4
+ .rva .LSEH_begin_sha1_block_data_order
+ .rva .LSEH_end_sha1_block_data_order
+ .rva .LSEH_info_sha1_block_data_order
+ .rva .LSEH_begin_sha1_block_data_order_ssse3
+ .rva .LSEH_end_sha1_block_data_order_ssse3
+ .rva .LSEH_info_sha1_block_data_order_ssse3
+___
+$code.=<<___ if ($avx);
+ .rva .LSEH_begin_sha1_block_data_order_avx
+ .rva .LSEH_end_sha1_block_data_order_avx
+ .rva .LSEH_info_sha1_block_data_order_avx
+___
+$code.=<<___ if ($avx>1);
+ .rva .LSEH_begin_sha1_block_data_order_avx2
+ .rva .LSEH_end_sha1_block_data_order_avx2
+ .rva .LSEH_info_sha1_block_data_order_avx2
+___
+$code.=<<___;
+.section .xdata
+.align 8
+.LSEH_info_sha1_block_data_order:
+ .byte 9,0,0,0
+ .rva se_handler
+.LSEH_info_sha1_block_data_order_ssse3:
+ .byte 9,0,0,0
+ .rva ssse3_handler
+ .rva .Lprologue_ssse3,.Lepilogue_ssse3 # HandlerData[]
+___
+$code.=<<___ if ($avx);
+.LSEH_info_sha1_block_data_order_avx:
+ .byte 9,0,0,0
+ .rva ssse3_handler
+ .rva .Lprologue_avx,.Lepilogue_avx # HandlerData[]
+___
+$code.=<<___ if ($avx>1);
+.LSEH_info_sha1_block_data_order_avx2:
+ .byte 9,0,0,0
+ .rva ssse3_handler
+ .rva .Lprologue_avx2,.Lepilogue_avx2 # HandlerData[]
+___
+}
+
+####################################################################
+
+$code =~ s/\`([^\`]*)\`/eval $1/gem;
+
+print $code;
+
+close STDOUT;
diff --git a/crypto/sha/asm/sha256-586.pl b/crypto/sha/asm/sha256-586.pl
new file mode 100644
index 0000000..bd48b63
--- /dev/null
+++ b/crypto/sha/asm/sha256-586.pl
@@ -0,0 +1,1125 @@
+#!/usr/bin/env perl
+#
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+#
+# 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
+# it's 5 times smaller and optimizies amount of writes.
+#
+# May 2012.
+#
+# Optimization including two of Pavel Semjanov's ideas, alternative
+# Maj and full unroll, resulted in ~20-25% improvement on most CPUs,
+# ~7% on Pentium, ~40% on Atom. As fully unrolled loop body is almost
+# 15x larger, 8KB vs. 560B, it's fired only for longer inputs. But not
+# on P4, where it kills performance, nor Sandy Bridge, where folded
+# loop is approximately as fast...
+#
+# June 2012.
+#
+# Add AMD XOP-specific code path, >30% improvement on Bulldozer over
+# May version, >60% over original. Add AVX+shrd code path, >25%
+# improvement on Sandy Bridge over May version, 60% over original.
+#
+# May 2013.
+#
+# Replace AMD XOP code path with SSSE3 to cover more processors.
+# (Biggest improvement coefficient is on upcoming Atom Silvermont,
+# not shown.) Add AVX+BMI code path.
+#
+# Performance in clock cycles per processed byte (less is better):
+#
+# gcc icc x86 asm(*) SIMD x86_64 asm(**)
+# Pentium 46 57 40/38 - -
+# PIII 36 33 27/24 - -
+# P4 41 38 28 - 17.3
+# AMD K8 27 25 19/15.5 - 14.9
+# Core2 26 23 18/15.6 14.3 13.8
+# Westmere 27 - 19/15.7 13.4 12.3
+# Sandy Bridge 25 - 15.9 12.4 11.6
+# Ivy Bridge 24 - 15.0 11.4 10.3
+# Haswell 22 - 13.9 9.46 7.80
+# Bulldozer 36 - 27/22 17.0 13.6
+# VIA Nano 36 - 25/22 16.8 16.5
+# Atom 50 - 30/25 21.9 18.9
+#
+# (*) numbers after slash are for unrolled loop, where applicable;
+# (**) x86_64 assembly performance is presented for reference
+# purposes, results are best-available;
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+push(@INC,"${dir}","${dir}../../perlasm");
+require "x86asm.pl";
+
+&asm_init($ARGV[0],"sha512-586.pl",$ARGV[$#ARGV] eq "386");
+
+$xmm=$avx=0;
+for (@ARGV) { $xmm=1 if (/-DOPENSSL_IA32_SSE2/); }
+
+if ($xmm && `$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
+ =~ /GNU assembler version ([2-9]\.[0-9]+)/) {
+ $avx = ($1>=2.19) + ($1>=2.22);
+}
+
+if ($xmm && !$avx && $ARGV[0] eq "win32n" &&
+ `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
+ $avx = ($1>=2.03) + ($1>=2.10);
+}
+
+if ($xmm && !$avx && $ARGV[0] eq "win32" &&
+ `ml 2>&1` =~ /Version ([0-9]+)\./) {
+ $avx = ($1>=10) + ($1>=11);
+}
+
+$unroll_after = 64*4; # If pre-evicted from L1P cache first spin of
+ # fully unrolled loop was measured to run about
+ # 3-4x slower. If slowdown coefficient is N and
+ # unrolled loop is m times faster, then you break
+ # even at (N-1)/(m-1) blocks. Then it needs to be
+ # adjusted for probability of code being evicted,
+ # code size/cache size=1/4. Typical m is 1.15...
+
+$A="eax";
+$E="edx";
+$T="ebx";
+$Aoff=&DWP(4,"esp");
+$Boff=&DWP(8,"esp");
+$Coff=&DWP(12,"esp");
+$Doff=&DWP(16,"esp");
+$Eoff=&DWP(20,"esp");
+$Foff=&DWP(24,"esp");
+$Goff=&DWP(28,"esp");
+$Hoff=&DWP(32,"esp");
+$Xoff=&DWP(36,"esp");
+$K256="ebp";
+
+sub BODY_16_63() {
+ &mov ($T,"ecx"); # "ecx" is preloaded
+ &mov ("esi",&DWP(4*(9+15+16-14),"esp"));
+ &ror ("ecx",18-7);
+ &mov ("edi","esi");
+ &ror ("esi",19-17);
+ &xor ("ecx",$T);
+ &shr ($T,3);
+ &ror ("ecx",7);
+ &xor ("esi","edi");
+ &xor ($T,"ecx"); # T = sigma0(X[-15])
+ &ror ("esi",17);
+ &add ($T,&DWP(4*(9+15+16),"esp")); # T += X[-16]
+ &shr ("edi",10);
+ &add ($T,&DWP(4*(9+15+16-9),"esp")); # T += X[-7]
+ #&xor ("edi","esi") # sigma1(X[-2])
+ # &add ($T,"edi"); # T += sigma1(X[-2])
+ # &mov (&DWP(4*(9+15),"esp"),$T); # save X[0]
+
+ &BODY_00_15(1);
+}
+sub BODY_00_15() {
+ my $in_16_63=shift;
+
+ &mov ("ecx",$E);
+ &xor ("edi","esi") if ($in_16_63); # sigma1(X[-2])
+ &mov ("esi",$Foff);
+ &ror ("ecx",25-11);
+ &add ($T,"edi") if ($in_16_63); # T += sigma1(X[-2])
+ &mov ("edi",$Goff);
+ &xor ("ecx",$E);
+ &xor ("esi","edi");
+ &mov ($T,&DWP(4*(9+15),"esp")) if (!$in_16_63);
+ &mov (&DWP(4*(9+15),"esp"),$T) if ($in_16_63); # save X[0]
+ &ror ("ecx",11-6);
+ &and ("esi",$E);
+ &mov ($Eoff,$E); # modulo-scheduled
+ &xor ($E,"ecx");
+ &add ($T,$Hoff); # T += h
+ &xor ("esi","edi"); # Ch(e,f,g)
+ &ror ($E,6); # Sigma1(e)
+ &mov ("ecx",$A);
+ &add ($T,"esi"); # T += Ch(e,f,g)
+
+ &ror ("ecx",22-13);
+ &add ($T,$E); # T += Sigma1(e)
+ &mov ("edi",$Boff);
+ &xor ("ecx",$A);
+ &mov ($Aoff,$A); # modulo-scheduled
+ &lea ("esp",&DWP(-4,"esp"));
+ &ror ("ecx",13-2);
+ &mov ("esi",&DWP(0,$K256));
+ &xor ("ecx",$A);
+ &mov ($E,$Eoff); # e in next iteration, d in this one
+ &xor ($A,"edi"); # a ^= b
+ &ror ("ecx",2); # Sigma0(a)
+
+ &add ($T,"esi"); # T+= K[i]
+ &mov (&DWP(0,"esp"),$A); # (b^c) in next round
+ &add ($E,$T); # d += T
+ &and ($A,&DWP(4,"esp")); # a &= (b^c)
+ &add ($T,"ecx"); # T += Sigma0(a)
+ &xor ($A,"edi"); # h = Maj(a,b,c) = Ch(a^b,c,b)
+ &mov ("ecx",&DWP(4*(9+15+16-1),"esp")) if ($in_16_63); # preload T
+ &add ($K256,4);
+ &add ($A,$T); # h += T
+}
+
+&external_label("OPENSSL_ia32cap_P") if (!$i386);
+
+&function_begin("sha256_block_data_order");
+ &mov ("esi",wparam(0)); # ctx
+ &mov ("edi",wparam(1)); # inp
+ &mov ("eax",wparam(2)); # num
+ &mov ("ebx","esp"); # saved sp
+
+ &call (&label("pic_point")); # make it PIC!
+&set_label("pic_point");
+ &blindpop($K256);
+ &lea ($K256,&DWP(&label("K256")."-".&label("pic_point"),$K256));
+
+ &sub ("esp",16);
+ &and ("esp",-64);
+
+ &shl ("eax",6);
+ &add ("eax","edi");
+ &mov (&DWP(0,"esp"),"esi"); # ctx
+ &mov (&DWP(4,"esp"),"edi"); # inp
+ &mov (&DWP(8,"esp"),"eax"); # inp+num*128
+ &mov (&DWP(12,"esp"),"ebx"); # saved sp
+ if (!$i386) {
+ &picmeup("edx","OPENSSL_ia32cap_P",$K256,&label("K256"));
+ &mov ("ecx",&DWP(0,"edx"));
+ &mov ("ebx",&DWP(4,"edx"));
+ &test ("ecx",1<<20); # check for P4
+ &jnz (&label("loop"));
+ &and ("ecx",1<<30); # mask "Intel CPU" bit
+ &and ("ebx",1<<28|1<<9); # mask AVX and SSSE3 bits
+ &or ("ecx","ebx");
+ &and ("ecx",1<<28|1<<30);
+ &cmp ("ecx",1<<28|1<<30);
+ if ($xmm) {
+ &je (&label("AVX")) if ($avx);
+ &test ("ebx",1<<9); # check for SSSE3
+ &jnz (&label("SSSE3"));
+ } else {
+ &je (&label("loop_shrd"));
+ }
+ if ($unroll_after) {
+ &sub ("eax","edi");
+ &cmp ("eax",$unroll_after);
+ &jae (&label("unrolled"));
+ } }
+ &jmp (&label("loop"));
+
+sub COMPACT_LOOP() {
+my $suffix=shift;
+
+&set_label("loop$suffix",$suffix?32:16);
+ # copy input block to stack reversing byte and dword order
+ for($i=0;$i<4;$i++) {
+ &mov ("eax",&DWP($i*16+0,"edi"));
+ &mov ("ebx",&DWP($i*16+4,"edi"));
+ &mov ("ecx",&DWP($i*16+8,"edi"));
+ &bswap ("eax");
+ &mov ("edx",&DWP($i*16+12,"edi"));
+ &bswap ("ebx");
+ &push ("eax");
+ &bswap ("ecx");
+ &push ("ebx");
+ &bswap ("edx");
+ &push ("ecx");
+ &push ("edx");
+ }
+ &add ("edi",64);
+ &lea ("esp",&DWP(-4*9,"esp"));# place for A,B,C,D,E,F,G,H
+ &mov (&DWP(4*(9+16)+4,"esp"),"edi");
+
+ # copy ctx->h[0-7] to A,B,C,D,E,F,G,H on stack
+ &mov ($A,&DWP(0,"esi"));
+ &mov ("ebx",&DWP(4,"esi"));
+ &mov ("ecx",&DWP(8,"esi"));
+ &mov ("edi",&DWP(12,"esi"));
+ # &mov ($Aoff,$A);
+ &mov ($Boff,"ebx");
+ &xor ("ebx","ecx");
+ &mov ($Coff,"ecx");
+ &mov ($Doff,"edi");
+ &mov (&DWP(0,"esp"),"ebx"); # magic
+ &mov ($E,&DWP(16,"esi"));
+ &mov ("ebx",&DWP(20,"esi"));
+ &mov ("ecx",&DWP(24,"esi"));
+ &mov ("edi",&DWP(28,"esi"));
+ # &mov ($Eoff,$E);
+ &mov ($Foff,"ebx");
+ &mov ($Goff,"ecx");
+ &mov ($Hoff,"edi");
+
+&set_label("00_15$suffix",16);
+
+ &BODY_00_15();
+
+ &cmp ("esi",0xc19bf174);
+ &jne (&label("00_15$suffix"));
+
+ &mov ("ecx",&DWP(4*(9+15+16-1),"esp")); # preloaded in BODY_00_15(1)
+ &jmp (&label("16_63$suffix"));
+
+&set_label("16_63$suffix",16);
+
+ &BODY_16_63();
+
+ &cmp ("esi",0xc67178f2);
+ &jne (&label("16_63$suffix"));
+
+ &mov ("esi",&DWP(4*(9+16+64)+0,"esp"));#ctx
+ # &mov ($A,$Aoff);
+ &mov ("ebx",$Boff);
+ # &mov ("edi",$Coff);
+ &mov ("ecx",$Doff);
+ &add ($A,&DWP(0,"esi"));
+ &add ("ebx",&DWP(4,"esi"));
+ &add ("edi",&DWP(8,"esi"));
+ &add ("ecx",&DWP(12,"esi"));
+ &mov (&DWP(0,"esi"),$A);
+ &mov (&DWP(4,"esi"),"ebx");
+ &mov (&DWP(8,"esi"),"edi");
+ &mov (&DWP(12,"esi"),"ecx");
+ # &mov ($E,$Eoff);
+ &mov ("eax",$Foff);
+ &mov ("ebx",$Goff);
+ &mov ("ecx",$Hoff);
+ &mov ("edi",&DWP(4*(9+16+64)+4,"esp"));#inp
+ &add ($E,&DWP(16,"esi"));
+ &add ("eax",&DWP(20,"esi"));
+ &add ("ebx",&DWP(24,"esi"));
+ &add ("ecx",&DWP(28,"esi"));
+ &mov (&DWP(16,"esi"),$E);
+ &mov (&DWP(20,"esi"),"eax");
+ &mov (&DWP(24,"esi"),"ebx");
+ &mov (&DWP(28,"esi"),"ecx");
+
+ &lea ("esp",&DWP(4*(9+16+64),"esp"));# destroy frame
+ &sub ($K256,4*64); # rewind K
+
+ &cmp ("edi",&DWP(8,"esp")); # are we done yet?
+ &jb (&label("loop$suffix"));
+}
+ &COMPACT_LOOP();
+ &mov ("esp",&DWP(12,"esp")); # restore sp
+&function_end_A();
+ if (!$i386 && !$xmm) {
+ # ~20% improvement on Sandy Bridge
+ local *ror = sub { &shrd(@_[0],@_) };
+ &COMPACT_LOOP("_shrd");
+ &mov ("esp",&DWP(12,"esp")); # restore sp
+&function_end_A();
+ }
+
+&set_label("K256",64); # Yes! I keep it in the code segment!
+@K256=( 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,
+ 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
+ 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,
+ 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
+ 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,
+ 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
+ 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,
+ 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
+ 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,
+ 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
+ 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,
+ 0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
+ 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,
+ 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
+ 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,
+ 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 );
+&data_word(@K256);
+&data_word(0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f); # byte swap mask
+&asciz("SHA256 block transform for x86, CRYPTOGAMS by <appro\@openssl.org>");
+
+($a,$b,$c,$d,$e,$f,$g,$h)=(0..7); # offsets
+sub off { &DWP(4*(((shift)-$i)&7),"esp"); }
+
+if (!$i386 && $unroll_after) {
+my @AH=($A,$K256);
+
+&set_label("unrolled",16);
+ &lea ("esp",&DWP(-96,"esp"));
+ # copy ctx->h[0-7] to A,B,C,D,E,F,G,H on stack
+ &mov ($AH[0],&DWP(0,"esi"));
+ &mov ($AH[1],&DWP(4,"esi"));
+ &mov ("ecx",&DWP(8,"esi"));
+ &mov ("ebx",&DWP(12,"esi"));
+ #&mov (&DWP(0,"esp"),$AH[0]);
+ &mov (&DWP(4,"esp"),$AH[1]);
+ &xor ($AH[1],"ecx"); # magic
+ &mov (&DWP(8,"esp"),"ecx");
+ &mov (&DWP(12,"esp"),"ebx");
+ &mov ($E,&DWP(16,"esi"));
+ &mov ("ebx",&DWP(20,"esi"));
+ &mov ("ecx",&DWP(24,"esi"));
+ &mov ("esi",&DWP(28,"esi"));
+ #&mov (&DWP(16,"esp"),$E);
+ &mov (&DWP(20,"esp"),"ebx");
+ &mov (&DWP(24,"esp"),"ecx");
+ &mov (&DWP(28,"esp"),"esi");
+ &jmp (&label("grand_loop"));
+
+&set_label("grand_loop",16);
+ # copy input block to stack reversing byte order
+ for($i=0;$i<5;$i++) {
+ &mov ("ebx",&DWP(12*$i+0,"edi"));
+ &mov ("ecx",&DWP(12*$i+4,"edi"));
+ &bswap ("ebx");
+ &mov ("esi",&DWP(12*$i+8,"edi"));
+ &bswap ("ecx");
+ &mov (&DWP(32+12*$i+0,"esp"),"ebx");
+ &bswap ("esi");
+ &mov (&DWP(32+12*$i+4,"esp"),"ecx");
+ &mov (&DWP(32+12*$i+8,"esp"),"esi");
+ }
+ &mov ("ebx",&DWP($i*12,"edi"));
+ &add ("edi",64);
+ &bswap ("ebx");
+ &mov (&DWP(96+4,"esp"),"edi");
+ &mov (&DWP(32+12*$i,"esp"),"ebx");
+
+ my ($t1,$t2) = ("ecx","esi");
+
+ for ($i=0;$i<64;$i++) {
+
+ if ($i>=16) {
+ &mov ($T,$t1); # $t1 is preloaded
+ # &mov ($t2,&DWP(32+4*(($i+14)&15),"esp"));
+ &ror ($t1,18-7);
+ &mov ("edi",$t2);
+ &ror ($t2,19-17);
+ &xor ($t1,$T);
+ &shr ($T,3);
+ &ror ($t1,7);
+ &xor ($t2,"edi");
+ &xor ($T,$t1); # T = sigma0(X[-15])
+ &ror ($t2,17);
+ &add ($T,&DWP(32+4*($i&15),"esp")); # T += X[-16]
+ &shr ("edi",10);
+ &add ($T,&DWP(32+4*(($i+9)&15),"esp")); # T += X[-7]
+ #&xor ("edi",$t2) # sigma1(X[-2])
+ # &add ($T,"edi"); # T += sigma1(X[-2])
+ # &mov (&DWP(4*(9+15),"esp"),$T); # save X[0]
+ }
+ &mov ($t1,$E);
+ &xor ("edi",$t2) if ($i>=16); # sigma1(X[-2])
+ &mov ($t2,&off($f));
+ &ror ($E,25-11);
+ &add ($T,"edi") if ($i>=16); # T += sigma1(X[-2])
+ &mov ("edi",&off($g));
+ &xor ($E,$t1);
+ &mov ($T,&DWP(32+4*($i&15),"esp")) if ($i<16); # X[i]
+ &mov (&DWP(32+4*($i&15),"esp"),$T) if ($i>=16 && $i<62); # save X[0]
+ &xor ($t2,"edi");
+ &ror ($E,11-6);
+ &and ($t2,$t1);
+ &mov (&off($e),$t1); # save $E, modulo-scheduled
+ &xor ($E,$t1);
+ &add ($T,&off($h)); # T += h
+ &xor ("edi",$t2); # Ch(e,f,g)
+ &ror ($E,6); # Sigma1(e)
+ &mov ($t1,$AH[0]);
+ &add ($T,"edi"); # T += Ch(e,f,g)
+
+ &ror ($t1,22-13);
+ &mov ($t2,$AH[0]);
+ &mov ("edi",&off($b));
+ &xor ($t1,$AH[0]);
+ &mov (&off($a),$AH[0]); # save $A, modulo-scheduled
+ &xor ($AH[0],"edi"); # a ^= b, (b^c) in next round
+ &ror ($t1,13-2);
+ &and ($AH[1],$AH[0]); # (b^c) &= (a^b)
+ &lea ($E,&DWP(@K256[$i],$T,$E)); # T += Sigma1(1)+K[i]
+ &xor ($t1,$t2);
+ &xor ($AH[1],"edi"); # h = Maj(a,b,c) = Ch(a^b,c,b)
+ &mov ($t2,&DWP(32+4*(($i+2)&15),"esp")) if ($i>=15 && $i<63);
+ &ror ($t1,2); # Sigma0(a)
+
+ &add ($AH[1],$E); # h += T
+ &add ($E,&off($d)); # d += T
+ &add ($AH[1],$t1); # h += Sigma0(a)
+ &mov ($t1,&DWP(32+4*(($i+15)&15),"esp")) if ($i>=15 && $i<63);
+
+ @AH = reverse(@AH); # rotate(a,h)
+ ($t1,$t2) = ($t2,$t1); # rotate(t1,t2)
+ }
+ &mov ("esi",&DWP(96,"esp")); #ctx
+ #&mov ($AH[0],&DWP(0,"esp"));
+ &xor ($AH[1],"edi"); #&mov ($AH[1],&DWP(4,"esp"));
+ #&mov ("edi", &DWP(8,"esp"));
+ &mov ("ecx",&DWP(12,"esp"));
+ &add ($AH[0],&DWP(0,"esi"));
+ &add ($AH[1],&DWP(4,"esi"));
+ &add ("edi",&DWP(8,"esi"));
+ &add ("ecx",&DWP(12,"esi"));
+ &mov (&DWP(0,"esi"),$AH[0]);
+ &mov (&DWP(4,"esi"),$AH[1]);
+ &mov (&DWP(8,"esi"),"edi");
+ &mov (&DWP(12,"esi"),"ecx");
+ #&mov (&DWP(0,"esp"),$AH[0]);
+ &mov (&DWP(4,"esp"),$AH[1]);
+ &xor ($AH[1],"edi"); # magic
+ &mov (&DWP(8,"esp"),"edi");
+ &mov (&DWP(12,"esp"),"ecx");
+ #&mov ($E,&DWP(16,"esp"));
+ &mov ("edi",&DWP(20,"esp"));
+ &mov ("ebx",&DWP(24,"esp"));
+ &mov ("ecx",&DWP(28,"esp"));
+ &add ($E,&DWP(16,"esi"));
+ &add ("edi",&DWP(20,"esi"));
+ &add ("ebx",&DWP(24,"esi"));
+ &add ("ecx",&DWP(28,"esi"));
+ &mov (&DWP(16,"esi"),$E);
+ &mov (&DWP(20,"esi"),"edi");
+ &mov (&DWP(24,"esi"),"ebx");
+ &mov (&DWP(28,"esi"),"ecx");
+ #&mov (&DWP(16,"esp"),$E);
+ &mov (&DWP(20,"esp"),"edi");
+ &mov ("edi",&DWP(96+4,"esp")); # inp
+ &mov (&DWP(24,"esp"),"ebx");
+ &mov (&DWP(28,"esp"),"ecx");
+
+ &cmp ("edi",&DWP(96+8,"esp")); # are we done yet?
+ &jb (&label("grand_loop"));
+
+ &mov ("esp",&DWP(96+12,"esp")); # restore sp
+&function_end_A();
+}
+ if (!$i386 && $xmm) {{{
+my @X = map("xmm$_",(0..3));
+my ($t0,$t1,$t2,$t3) = map("xmm$_",(4..7));
+my @AH = ($A,$T);
+
+&set_label("SSSE3",32);
+ &lea ("esp",&DWP(-96,"esp"));
+ # copy ctx->h[0-7] to A,B,C,D,E,F,G,H on stack
+ &mov ($AH[0],&DWP(0,"esi"));
+ &mov ($AH[1],&DWP(4,"esi"));
+ &mov ("ecx",&DWP(8,"esi"));
+ &mov ("edi",&DWP(12,"esi"));
+ #&mov (&DWP(0,"esp"),$AH[0]);
+ &mov (&DWP(4,"esp"),$AH[1]);
+ &xor ($AH[1],"ecx"); # magic
+ &mov (&DWP(8,"esp"),"ecx");
+ &mov (&DWP(12,"esp"),"edi");
+ &mov ($E,&DWP(16,"esi"));
+ &mov ("edi",&DWP(20,"esi"));
+ &mov ("ecx",&DWP(24,"esi"));
+ &mov ("esi",&DWP(28,"esi"));
+ #&mov (&DWP(16,"esp"),$E);
+ &mov (&DWP(20,"esp"),"edi");
+ &mov ("edi",&DWP(96+4,"esp")); # inp
+ &mov (&DWP(24,"esp"),"ecx");
+ &mov (&DWP(28,"esp"),"esi");
+ &movdqa ($t3,&QWP(256,$K256));
+ &jmp (&label("grand_ssse3"));
+
+&set_label("grand_ssse3",16);
+ # load input, reverse byte order, add K256[0..15], save to stack
+ &movdqu (@X[0],&QWP(0,"edi"));
+ &movdqu (@X[1],&QWP(16,"edi"));
+ &movdqu (@X[2],&QWP(32,"edi"));
+ &movdqu (@X[3],&QWP(48,"edi"));
+ &add ("edi",64);
+ &pshufb (@X[0],$t3);
+ &mov (&DWP(96+4,"esp"),"edi");
+ &pshufb (@X[1],$t3);
+ &movdqa ($t0,&QWP(0,$K256));
+ &pshufb (@X[2],$t3);
+ &movdqa ($t1,&QWP(16,$K256));
+ &paddd ($t0,@X[0]);
+ &pshufb (@X[3],$t3);
+ &movdqa ($t2,&QWP(32,$K256));
+ &paddd ($t1,@X[1]);
+ &movdqa ($t3,&QWP(48,$K256));
+ &movdqa (&QWP(32+0,"esp"),$t0);
+ &paddd ($t2,@X[2]);
+ &movdqa (&QWP(32+16,"esp"),$t1);
+ &paddd ($t3,@X[3]);
+ &movdqa (&QWP(32+32,"esp"),$t2);
+ &movdqa (&QWP(32+48,"esp"),$t3);
+ &jmp (&label("ssse3_00_47"));
+
+&set_label("ssse3_00_47",16);
+ &add ($K256,64);
+
+sub SSSE3_00_47 () {
+my $j = shift;
+my $body = shift;
+my @X = @_;
+my @insns = (&$body,&$body,&$body,&$body); # 120 instructions
+
+ eval(shift(@insns));
+ &movdqa ($t0,@X[1]);
+ eval(shift(@insns)); # @
+ eval(shift(@insns));
+ &movdqa ($t3,@X[3]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &palignr ($t0,@X[0],4); # X[1..4]
+ eval(shift(@insns));
+ eval(shift(@insns)); # @
+ eval(shift(@insns));
+ &palignr ($t3,@X[2],4); # X[9..12]
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &movdqa ($t1,$t0);
+ eval(shift(@insns)); # @
+ eval(shift(@insns));
+ &movdqa ($t2,$t0);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &psrld ($t0,3);
+ eval(shift(@insns));
+ eval(shift(@insns)); # @
+ &paddd (@X[0],$t3); # X[0..3] += X[9..12]
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &psrld ($t2,7);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # @
+ eval(shift(@insns));
+ &pshufd ($t3,@X[3],0b11111010); # X[14..15]
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &pslld ($t1,32-18);
+ eval(shift(@insns));
+ eval(shift(@insns)); # @
+ &pxor ($t0,$t2);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &psrld ($t2,18-7);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # @
+ &pxor ($t0,$t1);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &pslld ($t1,18-7);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # @
+ &pxor ($t0,$t2);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &movdqa ($t2,$t3);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # @
+ &pxor ($t0,$t1); # sigma0(X[1..4])
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &psrld ($t3,10);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # @
+ &paddd (@X[0],$t0); # X[0..3] += sigma0(X[1..4])
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &psrlq ($t2,17);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # @
+ &pxor ($t3,$t2);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &psrlq ($t2,19-17);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # @
+ &pxor ($t3,$t2);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &pshufd ($t3,$t3,0b10000000);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # @
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # @
+ eval(shift(@insns));
+ &psrldq ($t3,8);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &paddd (@X[0],$t3); # X[0..1] += sigma1(X[14..15])
+ eval(shift(@insns)); # @
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # @
+ eval(shift(@insns));
+ &pshufd ($t3,@X[0],0b01010000); # X[16..17]
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &movdqa ($t2,$t3);
+ eval(shift(@insns)); # @
+ &psrld ($t3,10);
+ eval(shift(@insns));
+ &psrlq ($t2,17);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # @
+ &pxor ($t3,$t2);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &psrlq ($t2,19-17);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # @
+ &pxor ($t3,$t2);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &pshufd ($t3,$t3,0b00001000);
+ eval(shift(@insns));
+ eval(shift(@insns)); # @
+ &movdqa ($t2,&QWP(16*$j,$K256));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &pslldq ($t3,8);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # @
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); # @
+ &paddd (@X[0],$t3); # X[2..3] += sigma1(X[16..17])
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &paddd ($t2,@X[0]);
+ eval(shift(@insns)); # @
+
+ foreach (@insns) { eval; } # remaining instructions
+
+ &movdqa (&QWP(32+16*$j,"esp"),$t2);
+}
+
+sub body_00_15 () {
+ (
+ '&mov ("ecx",$E);',
+ '&ror ($E,25-11);',
+ '&mov ("esi",&off($f));',
+ '&xor ($E,"ecx");',
+ '&mov ("edi",&off($g));',
+ '&xor ("esi","edi");',
+ '&ror ($E,11-6);',
+ '&and ("esi","ecx");',
+ '&mov (&off($e),"ecx");', # save $E, modulo-scheduled
+ '&xor ($E,"ecx");',
+ '&xor ("edi","esi");', # Ch(e,f,g)
+ '&ror ($E,6);', # T = Sigma1(e)
+ '&mov ("ecx",$AH[0]);',
+ '&add ($E,"edi");', # T += Ch(e,f,g)
+ '&mov ("edi",&off($b));',
+ '&mov ("esi",$AH[0]);',
+
+ '&ror ("ecx",22-13);',
+ '&mov (&off($a),$AH[0]);', # save $A, modulo-scheduled
+ '&xor ("ecx",$AH[0]);',
+ '&xor ($AH[0],"edi");', # a ^= b, (b^c) in next round
+ '&add ($E,&off($h));', # T += h
+ '&ror ("ecx",13-2);',
+ '&and ($AH[1],$AH[0]);', # (b^c) &= (a^b)
+ '&xor ("ecx","esi");',
+ '&add ($E,&DWP(32+4*($i&15),"esp"));', # T += K[i]+X[i]
+ '&xor ($AH[1],"edi");', # h = Maj(a,b,c) = Ch(a^b,c,b)
+ '&ror ("ecx",2);', # Sigma0(a)
+
+ '&add ($AH[1],$E);', # h += T
+ '&add ($E,&off($d));', # d += T
+ '&add ($AH[1],"ecx");'. # h += Sigma0(a)
+
+ '@AH = reverse(@AH); $i++;' # rotate(a,h)
+ );
+}
+
+ for ($i=0,$j=0; $j<4; $j++) {
+ &SSSE3_00_47($j,\&body_00_15,@X);
+ push(@X,shift(@X)); # rotate(@X)
+ }
+ &cmp (&DWP(16*$j,$K256),0x00010203);
+ &jne (&label("ssse3_00_47"));
+
+ for ($i=0; $i<16; ) {
+ foreach(body_00_15()) { eval; }
+ }
+
+ &mov ("esi",&DWP(96,"esp")); #ctx
+ #&mov ($AH[0],&DWP(0,"esp"));
+ &xor ($AH[1],"edi"); #&mov ($AH[1],&DWP(4,"esp"));
+ #&mov ("edi", &DWP(8,"esp"));
+ &mov ("ecx",&DWP(12,"esp"));
+ &add ($AH[0],&DWP(0,"esi"));
+ &add ($AH[1],&DWP(4,"esi"));
+ &add ("edi",&DWP(8,"esi"));
+ &add ("ecx",&DWP(12,"esi"));
+ &mov (&DWP(0,"esi"),$AH[0]);
+ &mov (&DWP(4,"esi"),$AH[1]);
+ &mov (&DWP(8,"esi"),"edi");
+ &mov (&DWP(12,"esi"),"ecx");
+ #&mov (&DWP(0,"esp"),$AH[0]);
+ &mov (&DWP(4,"esp"),$AH[1]);
+ &xor ($AH[1],"edi"); # magic
+ &mov (&DWP(8,"esp"),"edi");
+ &mov (&DWP(12,"esp"),"ecx");
+ #&mov ($E,&DWP(16,"esp"));
+ &mov ("edi",&DWP(20,"esp"));
+ &mov ("ecx",&DWP(24,"esp"));
+ &add ($E,&DWP(16,"esi"));
+ &add ("edi",&DWP(20,"esi"));
+ &add ("ecx",&DWP(24,"esi"));
+ &mov (&DWP(16,"esi"),$E);
+ &mov (&DWP(20,"esi"),"edi");
+ &mov (&DWP(20,"esp"),"edi");
+ &mov ("edi",&DWP(28,"esp"));
+ &mov (&DWP(24,"esi"),"ecx");
+ #&mov (&DWP(16,"esp"),$E);
+ &add ("edi",&DWP(28,"esi"));
+ &mov (&DWP(24,"esp"),"ecx");
+ &mov (&DWP(28,"esi"),"edi");
+ &mov (&DWP(28,"esp"),"edi");
+ &mov ("edi",&DWP(96+4,"esp")); # inp
+
+ &movdqa ($t3,&QWP(64,$K256));
+ &sub ($K256,3*64); # rewind K
+ &cmp ("edi",&DWP(96+8,"esp")); # are we done yet?
+ &jb (&label("grand_ssse3"));
+
+ &mov ("esp",&DWP(96+12,"esp")); # restore sp
+&function_end_A();
+ if ($avx) {
+&set_label("AVX",32);
+ if ($avx>1) {
+ &mov ("edx",&DWP(8,"edx"));
+ &and ("edx",1<<8|1<<3); # check for BMI2+BMI1
+ &cmp ("edx",1<<8|1<<3);
+ &je (&label("AVX_BMI"));
+ }
+ &lea ("esp",&DWP(-96,"esp"));
+ &vzeroall ();
+ # copy ctx->h[0-7] to A,B,C,D,E,F,G,H on stack
+ &mov ($AH[0],&DWP(0,"esi"));
+ &mov ($AH[1],&DWP(4,"esi"));
+ &mov ("ecx",&DWP(8,"esi"));
+ &mov ("edi",&DWP(12,"esi"));
+ #&mov (&DWP(0,"esp"),$AH[0]);
+ &mov (&DWP(4,"esp"),$AH[1]);
+ &xor ($AH[1],"ecx"); # magic
+ &mov (&DWP(8,"esp"),"ecx");
+ &mov (&DWP(12,"esp"),"edi");
+ &mov ($E,&DWP(16,"esi"));
+ &mov ("edi",&DWP(20,"esi"));
+ &mov ("ecx",&DWP(24,"esi"));
+ &mov ("esi",&DWP(28,"esi"));
+ #&mov (&DWP(16,"esp"),$E);
+ &mov (&DWP(20,"esp"),"edi");
+ &mov ("edi",&DWP(96+4,"esp")); # inp
+ &mov (&DWP(24,"esp"),"ecx");
+ &mov (&DWP(28,"esp"),"esi");
+ &vmovdqa ($t3,&QWP(256,$K256));
+ &jmp (&label("grand_avx"));
+
+&set_label("grand_avx",32);
+ # load input, reverse byte order, add K256[0..15], save to stack
+ &vmovdqu (@X[0],&QWP(0,"edi"));
+ &vmovdqu (@X[1],&QWP(16,"edi"));
+ &vmovdqu (@X[2],&QWP(32,"edi"));
+ &vmovdqu (@X[3],&QWP(48,"edi"));
+ &add ("edi",64);
+ &vpshufb (@X[0],@X[0],$t3);
+ &mov (&DWP(96+4,"esp"),"edi");
+ &vpshufb (@X[1],@X[1],$t3);
+ &vpshufb (@X[2],@X[2],$t3);
+ &vpaddd ($t0,@X[0],&QWP(0,$K256));
+ &vpshufb (@X[3],@X[3],$t3);
+ &vpaddd ($t1,@X[1],&QWP(16,$K256));
+ &vpaddd ($t2,@X[2],&QWP(32,$K256));
+ &vpaddd ($t3,@X[3],&QWP(48,$K256));
+ &vmovdqa (&QWP(32+0,"esp"),$t0);
+ &vmovdqa (&QWP(32+16,"esp"),$t1);
+ &vmovdqa (&QWP(32+32,"esp"),$t2);
+ &vmovdqa (&QWP(32+48,"esp"),$t3);
+ &jmp (&label("avx_00_47"));
+
+&set_label("avx_00_47",16);
+ &add ($K256,64);
+
+sub Xupdate_AVX () {
+ (
+ '&vpalignr ($t0,@X[1],@X[0],4);', # X[1..4]
+ '&vpalignr ($t3,@X[3],@X[2],4);', # X[9..12]
+ '&vpsrld ($t2,$t0,7);',
+ '&vpaddd (@X[0],@X[0],$t3);', # X[0..3] += X[9..16]
+ '&vpsrld ($t3,$t0,3);',
+ '&vpslld ($t1,$t0,14);',
+ '&vpxor ($t0,$t3,$t2);',
+ '&vpshufd ($t3,@X[3],0b11111010)',# X[14..15]
+ '&vpsrld ($t2,$t2,18-7);',
+ '&vpxor ($t0,$t0,$t1);',
+ '&vpslld ($t1,$t1,25-14);',
+ '&vpxor ($t0,$t0,$t2);',
+ '&vpsrld ($t2,$t3,10);',
+ '&vpxor ($t0,$t0,$t1);', # sigma0(X[1..4])
+ '&vpsrlq ($t1,$t3,17);',
+ '&vpaddd (@X[0],@X[0],$t0);', # X[0..3] += sigma0(X[1..4])
+ '&vpxor ($t2,$t2,$t1);',
+ '&vpsrlq ($t3,$t3,19);',
+ '&vpxor ($t2,$t2,$t3);', # sigma1(X[14..15]
+ '&vpshufd ($t3,$t2,0b10000100);',
+ '&vpsrldq ($t3,$t3,8);',
+ '&vpaddd (@X[0],@X[0],$t3);', # X[0..1] += sigma1(X[14..15])
+ '&vpshufd ($t3,@X[0],0b01010000)',# X[16..17]
+ '&vpsrld ($t2,$t3,10);',
+ '&vpsrlq ($t1,$t3,17);',
+ '&vpxor ($t2,$t2,$t1);',
+ '&vpsrlq ($t3,$t3,19);',
+ '&vpxor ($t2,$t2,$t3);', # sigma1(X[16..17]
+ '&vpshufd ($t3,$t2,0b11101000);',
+ '&vpslldq ($t3,$t3,8);',
+ '&vpaddd (@X[0],@X[0],$t3);' # X[2..3] += sigma1(X[16..17])
+ );
+}
+
+local *ror = sub { &shrd(@_[0],@_) };
+sub AVX_00_47 () {
+my $j = shift;
+my $body = shift;
+my @X = @_;
+my @insns = (&$body,&$body,&$body,&$body); # 120 instructions
+my $insn;
+
+ foreach (Xupdate_AVX()) { # 31 instructions
+ eval;
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval($insn = shift(@insns));
+ eval(shift(@insns)) if ($insn =~ /rorx/ && @insns[0] =~ /rorx/);
+ }
+ &vpaddd ($t2,@X[0],&QWP(16*$j,$K256));
+ foreach (@insns) { eval; } # remaining instructions
+ &vmovdqa (&QWP(32+16*$j,"esp"),$t2);
+}
+
+ for ($i=0,$j=0; $j<4; $j++) {
+ &AVX_00_47($j,\&body_00_15,@X);
+ push(@X,shift(@X)); # rotate(@X)
+ }
+ &cmp (&DWP(16*$j,$K256),0x00010203);
+ &jne (&label("avx_00_47"));
+
+ for ($i=0; $i<16; ) {
+ foreach(body_00_15()) { eval; }
+ }
+
+ &mov ("esi",&DWP(96,"esp")); #ctx
+ #&mov ($AH[0],&DWP(0,"esp"));
+ &xor ($AH[1],"edi"); #&mov ($AH[1],&DWP(4,"esp"));
+ #&mov ("edi", &DWP(8,"esp"));
+ &mov ("ecx",&DWP(12,"esp"));
+ &add ($AH[0],&DWP(0,"esi"));
+ &add ($AH[1],&DWP(4,"esi"));
+ &add ("edi",&DWP(8,"esi"));
+ &add ("ecx",&DWP(12,"esi"));
+ &mov (&DWP(0,"esi"),$AH[0]);
+ &mov (&DWP(4,"esi"),$AH[1]);
+ &mov (&DWP(8,"esi"),"edi");
+ &mov (&DWP(12,"esi"),"ecx");
+ #&mov (&DWP(0,"esp"),$AH[0]);
+ &mov (&DWP(4,"esp"),$AH[1]);
+ &xor ($AH[1],"edi"); # magic
+ &mov (&DWP(8,"esp"),"edi");
+ &mov (&DWP(12,"esp"),"ecx");
+ #&mov ($E,&DWP(16,"esp"));
+ &mov ("edi",&DWP(20,"esp"));
+ &mov ("ecx",&DWP(24,"esp"));
+ &add ($E,&DWP(16,"esi"));
+ &add ("edi",&DWP(20,"esi"));
+ &add ("ecx",&DWP(24,"esi"));
+ &mov (&DWP(16,"esi"),$E);
+ &mov (&DWP(20,"esi"),"edi");
+ &mov (&DWP(20,"esp"),"edi");
+ &mov ("edi",&DWP(28,"esp"));
+ &mov (&DWP(24,"esi"),"ecx");
+ #&mov (&DWP(16,"esp"),$E);
+ &add ("edi",&DWP(28,"esi"));
+ &mov (&DWP(24,"esp"),"ecx");
+ &mov (&DWP(28,"esi"),"edi");
+ &mov (&DWP(28,"esp"),"edi");
+ &mov ("edi",&DWP(96+4,"esp")); # inp
+
+ &vmovdqa ($t3,&QWP(64,$K256));
+ &sub ($K256,3*64); # rewind K
+ &cmp ("edi",&DWP(96+8,"esp")); # are we done yet?
+ &jb (&label("grand_avx"));
+
+ &mov ("esp",&DWP(96+12,"esp")); # restore sp
+ &vzeroall ();
+&function_end_A();
+ if ($avx>1) {
+sub bodyx_00_15 () { # +10%
+ (
+ '&rorx ("ecx",$E,6)',
+ '&rorx ("esi",$E,11)',
+ '&mov (&off($e),$E)', # save $E, modulo-scheduled
+ '&rorx ("edi",$E,25)',
+ '&xor ("ecx","esi")',
+ '&andn ("esi",$E,&off($g))',
+ '&xor ("ecx","edi")', # Sigma1(e)
+ '&and ($E,&off($f))',
+ '&mov (&off($a),$AH[0]);', # save $A, modulo-scheduled
+ '&or ($E,"esi")', # T = Ch(e,f,g)
+
+ '&rorx ("edi",$AH[0],2)',
+ '&rorx ("esi",$AH[0],13)',
+ '&lea ($E,&DWP(0,$E,"ecx"))', # T += Sigma1(e)
+ '&rorx ("ecx",$AH[0],22)',
+ '&xor ("esi","edi")',
+ '&mov ("edi",&off($b))',
+ '&xor ("ecx","esi")', # Sigma0(a)
+
+ '&xor ($AH[0],"edi")', # a ^= b, (b^c) in next round
+ '&add ($E,&off($h))', # T += h
+ '&and ($AH[1],$AH[0])', # (b^c) &= (a^b)
+ '&add ($E,&DWP(32+4*($i&15),"esp"))', # T += K[i]+X[i]
+ '&xor ($AH[1],"edi")', # h = Maj(a,b,c) = Ch(a^b,c,b)
+
+ '&add ("ecx",$E)', # h += T
+ '&add ($E,&off($d))', # d += T
+ '&lea ($AH[1],&DWP(0,$AH[1],"ecx"));'. # h += Sigma0(a)
+
+ '@AH = reverse(@AH); $i++;' # rotate(a,h)
+ );
+}
+
+&set_label("AVX_BMI",32);
+ &lea ("esp",&DWP(-96,"esp"));
+ &vzeroall ();
+ # copy ctx->h[0-7] to A,B,C,D,E,F,G,H on stack
+ &mov ($AH[0],&DWP(0,"esi"));
+ &mov ($AH[1],&DWP(4,"esi"));
+ &mov ("ecx",&DWP(8,"esi"));
+ &mov ("edi",&DWP(12,"esi"));
+ #&mov (&DWP(0,"esp"),$AH[0]);
+ &mov (&DWP(4,"esp"),$AH[1]);
+ &xor ($AH[1],"ecx"); # magic
+ &mov (&DWP(8,"esp"),"ecx");
+ &mov (&DWP(12,"esp"),"edi");
+ &mov ($E,&DWP(16,"esi"));
+ &mov ("edi",&DWP(20,"esi"));
+ &mov ("ecx",&DWP(24,"esi"));
+ &mov ("esi",&DWP(28,"esi"));
+ #&mov (&DWP(16,"esp"),$E);
+ &mov (&DWP(20,"esp"),"edi");
+ &mov ("edi",&DWP(96+4,"esp")); # inp
+ &mov (&DWP(24,"esp"),"ecx");
+ &mov (&DWP(28,"esp"),"esi");
+ &vmovdqa ($t3,&QWP(256,$K256));
+ &jmp (&label("grand_avx_bmi"));
+
+&set_label("grand_avx_bmi",32);
+ # load input, reverse byte order, add K256[0..15], save to stack
+ &vmovdqu (@X[0],&QWP(0,"edi"));
+ &vmovdqu (@X[1],&QWP(16,"edi"));
+ &vmovdqu (@X[2],&QWP(32,"edi"));
+ &vmovdqu (@X[3],&QWP(48,"edi"));
+ &add ("edi",64);
+ &vpshufb (@X[0],@X[0],$t3);
+ &mov (&DWP(96+4,"esp"),"edi");
+ &vpshufb (@X[1],@X[1],$t3);
+ &vpshufb (@X[2],@X[2],$t3);
+ &vpaddd ($t0,@X[0],&QWP(0,$K256));
+ &vpshufb (@X[3],@X[3],$t3);
+ &vpaddd ($t1,@X[1],&QWP(16,$K256));
+ &vpaddd ($t2,@X[2],&QWP(32,$K256));
+ &vpaddd ($t3,@X[3],&QWP(48,$K256));
+ &vmovdqa (&QWP(32+0,"esp"),$t0);
+ &vmovdqa (&QWP(32+16,"esp"),$t1);
+ &vmovdqa (&QWP(32+32,"esp"),$t2);
+ &vmovdqa (&QWP(32+48,"esp"),$t3);
+ &jmp (&label("avx_bmi_00_47"));
+
+&set_label("avx_bmi_00_47",16);
+ &add ($K256,64);
+
+ for ($i=0,$j=0; $j<4; $j++) {
+ &AVX_00_47($j,\&bodyx_00_15,@X);
+ push(@X,shift(@X)); # rotate(@X)
+ }
+ &cmp (&DWP(16*$j,$K256),0x00010203);
+ &jne (&label("avx_bmi_00_47"));
+
+ for ($i=0; $i<16; ) {
+ foreach(bodyx_00_15()) { eval; }
+ }
+
+ &mov ("esi",&DWP(96,"esp")); #ctx
+ #&mov ($AH[0],&DWP(0,"esp"));
+ &xor ($AH[1],"edi"); #&mov ($AH[1],&DWP(4,"esp"));
+ #&mov ("edi", &DWP(8,"esp"));
+ &mov ("ecx",&DWP(12,"esp"));
+ &add ($AH[0],&DWP(0,"esi"));
+ &add ($AH[1],&DWP(4,"esi"));
+ &add ("edi",&DWP(8,"esi"));
+ &add ("ecx",&DWP(12,"esi"));
+ &mov (&DWP(0,"esi"),$AH[0]);
+ &mov (&DWP(4,"esi"),$AH[1]);
+ &mov (&DWP(8,"esi"),"edi");
+ &mov (&DWP(12,"esi"),"ecx");
+ #&mov (&DWP(0,"esp"),$AH[0]);
+ &mov (&DWP(4,"esp"),$AH[1]);
+ &xor ($AH[1],"edi"); # magic
+ &mov (&DWP(8,"esp"),"edi");
+ &mov (&DWP(12,"esp"),"ecx");
+ #&mov ($E,&DWP(16,"esp"));
+ &mov ("edi",&DWP(20,"esp"));
+ &mov ("ecx",&DWP(24,"esp"));
+ &add ($E,&DWP(16,"esi"));
+ &add ("edi",&DWP(20,"esi"));
+ &add ("ecx",&DWP(24,"esi"));
+ &mov (&DWP(16,"esi"),$E);
+ &mov (&DWP(20,"esi"),"edi");
+ &mov (&DWP(20,"esp"),"edi");
+ &mov ("edi",&DWP(28,"esp"));
+ &mov (&DWP(24,"esi"),"ecx");
+ #&mov (&DWP(16,"esp"),$E);
+ &add ("edi",&DWP(28,"esi"));
+ &mov (&DWP(24,"esp"),"ecx");
+ &mov (&DWP(28,"esi"),"edi");
+ &mov (&DWP(28,"esp"),"edi");
+ &mov ("edi",&DWP(96+4,"esp")); # inp
+
+ &vmovdqa ($t3,&QWP(64,$K256));
+ &sub ($K256,3*64); # rewind K
+ &cmp ("edi",&DWP(96+8,"esp")); # are we done yet?
+ &jb (&label("grand_avx_bmi"));
+
+ &mov ("esp",&DWP(96+12,"esp")); # restore sp
+ &vzeroall ();
+&function_end_A();
+ }
+ }
+ }}}
+&function_end_B("sha256_block_data_order");
+
+&asm_finish();
diff --git a/crypto/sha/asm/sha256-armv4.pl b/crypto/sha/asm/sha256-armv4.pl
new file mode 100644
index 0000000..1b2a098
--- /dev/null
+++ b/crypto/sha/asm/sha256-armv4.pl
@@ -0,0 +1,540 @@
+#!/usr/bin/env perl
+
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+
+# SHA256 block procedure for ARMv4. May 2007.
+
+# Performance is ~2x better than gcc 3.4 generated code and in "abso-
+# lute" terms is ~2250 cycles per 64-byte block or ~35 cycles per
+# byte [on single-issue Xscale PXA250 core].
+
+# July 2010.
+#
+# Rescheduling for dual-issue pipeline resulted in 22% improvement on
+# Cortex A8 core and ~20 cycles per processed byte.
+
+# February 2011.
+#
+# Profiler-assisted and platform-specific optimization resulted in 16%
+# improvement on Cortex A8 core and ~15.4 cycles per processed byte.
+
+# September 2013.
+#
+# Add NEON implementation. On Cortex A8 it was measured to process one
+# byte in 12.5 cycles or 23% faster than integer-only code. Snapdragon
+# S4 does it in 12.5 cycles too, but it's 50% faster than integer-only
+# code (meaning that latter performs sub-optimally, nothing was done
+# about it).
+
+while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {}
+open STDOUT,">$output";
+
+$ctx="r0"; $t0="r0";
+$inp="r1"; $t4="r1";
+$len="r2"; $t1="r2";
+$T1="r3"; $t3="r3";
+$A="r4";
+$B="r5";
+$C="r6";
+$D="r7";
+$E="r8";
+$F="r9";
+$G="r10";
+$H="r11";
+@V=($A,$B,$C,$D,$E,$F,$G,$H);
+$t2="r12";
+$Ktbl="r14";
+
+@Sigma0=( 2,13,22);
+@Sigma1=( 6,11,25);
+@sigma0=( 7,18, 3);
+@sigma1=(17,19,10);
+
+sub BODY_00_15 {
+my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_;
+
+$code.=<<___ if ($i<16);
+#if __ARM_ARCH__>=7
+ @ ldr $t1,[$inp],#4 @ $i
+# if $i==15
+ str $inp,[sp,#17*4] @ make room for $t4
+# endif
+ eor $t0,$e,$e,ror#`$Sigma1[1]-$Sigma1[0]`
+ add $a,$a,$t2 @ h+=Maj(a,b,c) from the past
+ eor $t0,$t0,$e,ror#`$Sigma1[2]-$Sigma1[0]` @ Sigma1(e)
+ rev $t1,$t1
+#else
+ @ ldrb $t1,[$inp,#3] @ $i
+ add $a,$a,$t2 @ h+=Maj(a,b,c) from the past
+ ldrb $t2,[$inp,#2]
+ ldrb $t0,[$inp,#1]
+ orr $t1,$t1,$t2,lsl#8
+ ldrb $t2,[$inp],#4
+ orr $t1,$t1,$t0,lsl#16
+# if $i==15
+ str $inp,[sp,#17*4] @ make room for $t4
+# endif
+ eor $t0,$e,$e,ror#`$Sigma1[1]-$Sigma1[0]`
+ orr $t1,$t1,$t2,lsl#24
+ eor $t0,$t0,$e,ror#`$Sigma1[2]-$Sigma1[0]` @ Sigma1(e)
+#endif
+___
+$code.=<<___;
+ ldr $t2,[$Ktbl],#4 @ *K256++
+ add $h,$h,$t1 @ h+=X[i]
+ str $t1,[sp,#`$i%16`*4]
+ eor $t1,$f,$g
+ add $h,$h,$t0,ror#$Sigma1[0] @ h+=Sigma1(e)
+ and $t1,$t1,$e
+ add $h,$h,$t2 @ h+=K256[i]
+ eor $t1,$t1,$g @ Ch(e,f,g)
+ eor $t0,$a,$a,ror#`$Sigma0[1]-$Sigma0[0]`
+ add $h,$h,$t1 @ h+=Ch(e,f,g)
+#if $i==31
+ and $t2,$t2,#0xff
+ cmp $t2,#0xf2 @ done?
+#endif
+#if $i<15
+# if __ARM_ARCH__>=7
+ ldr $t1,[$inp],#4 @ prefetch
+# else
+ ldrb $t1,[$inp,#3]
+# endif
+ eor $t2,$a,$b @ a^b, b^c in next round
+#else
+ ldr $t1,[sp,#`($i+2)%16`*4] @ from future BODY_16_xx
+ eor $t2,$a,$b @ a^b, b^c in next round
+ ldr $t4,[sp,#`($i+15)%16`*4] @ from future BODY_16_xx
+#endif
+ eor $t0,$t0,$a,ror#`$Sigma0[2]-$Sigma0[0]` @ Sigma0(a)
+ and $t3,$t3,$t2 @ (b^c)&=(a^b)
+ add $d,$d,$h @ d+=h
+ eor $t3,$t3,$b @ Maj(a,b,c)
+ add $h,$h,$t0,ror#$Sigma0[0] @ h+=Sigma0(a)
+ @ add $h,$h,$t3 @ h+=Maj(a,b,c)
+___
+ ($t2,$t3)=($t3,$t2);
+}
+
+sub BODY_16_XX {
+my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_;
+
+$code.=<<___;
+ @ ldr $t1,[sp,#`($i+1)%16`*4] @ $i
+ @ ldr $t4,[sp,#`($i+14)%16`*4]
+ mov $t0,$t1,ror#$sigma0[0]
+ add $a,$a,$t2 @ h+=Maj(a,b,c) from the past
+ mov $t2,$t4,ror#$sigma1[0]
+ eor $t0,$t0,$t1,ror#$sigma0[1]
+ eor $t2,$t2,$t4,ror#$sigma1[1]
+ eor $t0,$t0,$t1,lsr#$sigma0[2] @ sigma0(X[i+1])
+ ldr $t1,[sp,#`($i+0)%16`*4]
+ eor $t2,$t2,$t4,lsr#$sigma1[2] @ sigma1(X[i+14])
+ ldr $t4,[sp,#`($i+9)%16`*4]
+
+ add $t2,$t2,$t0
+ eor $t0,$e,$e,ror#`$Sigma1[1]-$Sigma1[0]` @ from BODY_00_15
+ add $t1,$t1,$t2
+ eor $t0,$t0,$e,ror#`$Sigma1[2]-$Sigma1[0]` @ Sigma1(e)
+ add $t1,$t1,$t4 @ X[i]
+___
+ &BODY_00_15(@_);
+}
+
+$code=<<___;
+#if defined(__arm__)
+#include "arm_arch.h"
+
+.text
+.code 32
+
+.type K256,%object
+.align 5
+K256:
+.word 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
+.word 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
+.word 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
+.word 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
+.word 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
+.word 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
+.word 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
+.word 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
+.word 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
+.word 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
+.word 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
+.word 0xd192e819,0xd6990624,0xf40e3585,0x106aa070
+.word 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
+.word 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
+.word 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
+.word 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
+.size K256,.-K256
+.word 0 @ terminator
+.LOPENSSL_armcap:
+.word OPENSSL_armcap_P-sha256_block_data_order
+.align 5
+
+.global sha256_block_data_order
+.type sha256_block_data_order,%function
+sha256_block_data_order:
+ sub r3,pc,#8 @ sha256_block_data_order
+ add $len,$inp,$len,lsl#6 @ len to point at the end of inp
+#if __ARM_ARCH__>=7
+ ldr r12,.LOPENSSL_armcap
+ ldr r12,[r3,r12] @ OPENSSL_armcap_P
+ tst r12,#1
+ bne .LNEON
+#endif
+ stmdb sp!,{$ctx,$inp,$len,r4-r11,lr}
+ ldmia $ctx,{$A,$B,$C,$D,$E,$F,$G,$H}
+ sub $Ktbl,r3,#256+32 @ K256
+ sub sp,sp,#16*4 @ alloca(X[16])
+.Loop:
+# if __ARM_ARCH__>=7
+ ldr $t1,[$inp],#4
+# else
+ ldrb $t1,[$inp,#3]
+# endif
+ eor $t3,$B,$C @ magic
+ eor $t2,$t2,$t2
+___
+for($i=0;$i<16;$i++) { &BODY_00_15($i,@V); unshift(@V,pop(@V)); }
+$code.=".Lrounds_16_xx:\n";
+for (;$i<32;$i++) { &BODY_16_XX($i,@V); unshift(@V,pop(@V)); }
+$code.=<<___;
+ ldreq $t3,[sp,#16*4] @ pull ctx
+ bne .Lrounds_16_xx
+
+ add $A,$A,$t2 @ h+=Maj(a,b,c) from the past
+ ldr $t0,[$t3,#0]
+ ldr $t1,[$t3,#4]
+ ldr $t2,[$t3,#8]
+ add $A,$A,$t0
+ ldr $t0,[$t3,#12]
+ add $B,$B,$t1
+ ldr $t1,[$t3,#16]
+ add $C,$C,$t2
+ ldr $t2,[$t3,#20]
+ add $D,$D,$t0
+ ldr $t0,[$t3,#24]
+ add $E,$E,$t1
+ ldr $t1,[$t3,#28]
+ add $F,$F,$t2
+ ldr $inp,[sp,#17*4] @ pull inp
+ ldr $t2,[sp,#18*4] @ pull inp+len
+ add $G,$G,$t0
+ add $H,$H,$t1
+ stmia $t3,{$A,$B,$C,$D,$E,$F,$G,$H}
+ cmp $inp,$t2
+ sub $Ktbl,$Ktbl,#256 @ rewind Ktbl
+ bne .Loop
+
+ add sp,sp,#`16+3`*4 @ destroy frame
+#if __ARM_ARCH__>=5
+ ldmia sp!,{r4-r11,pc}
+#else
+ ldmia sp!,{r4-r11,lr}
+ tst lr,#1
+ moveq pc,lr @ be binary compatible with V4, yet
+ bx lr @ interoperable with Thumb ISA:-)
+#endif
+___
+######################################################################
+# NEON stuff
+#
+{{{
+my @X=map("q$_",(0..3));
+my ($T0,$T1,$T2,$T3,$T4,$T5)=("q8","q9","q10","q11","d24","d25");
+my $Xfer=$t4;
+my $j=0;
+
+sub Dlo() { shift=~m|q([1]?[0-9])|?"d".($1*2):""; }
+sub Dhi() { shift=~m|q([1]?[0-9])|?"d".($1*2+1):""; }
+
+sub AUTOLOAD() # thunk [simplified] x86-style perlasm
+{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; $opcode =~ s/_/\./;
+ my $arg = pop;
+ $arg = "#$arg" if ($arg*1 eq $arg);
+ $code .= "\t$opcode\t".join(',',@_,$arg)."\n";
+}
+
+sub Xupdate()
+{ use integer;
+ my $body = shift;
+ my @insns = (&$body,&$body,&$body,&$body);
+ my ($a,$b,$c,$d,$e,$f,$g,$h);
+
+ &vext_8 ($T0,@X[0],@X[1],4); # X[1..4]
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vext_8 ($T1,@X[2],@X[3],4); # X[9..12]
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vshr_u32 ($T2,$T0,$sigma0[0]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vadd_i32 (@X[0],@X[0],$T1); # X[0..3] += X[9..12]
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vshr_u32 ($T1,$T0,$sigma0[2]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vsli_32 ($T2,$T0,32-$sigma0[0]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vshr_u32 ($T3,$T0,$sigma0[1]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &veor ($T1,$T1,$T2);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vsli_32 ($T3,$T0,32-$sigma0[1]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vshr_u32 ($T4,&Dhi(@X[3]),$sigma1[0]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &veor ($T1,$T1,$T3); # sigma0(X[1..4])
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vsli_32 ($T4,&Dhi(@X[3]),32-$sigma1[0]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vshr_u32 ($T5,&Dhi(@X[3]),$sigma1[2]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vadd_i32 (@X[0],@X[0],$T1); # X[0..3] += sigma0(X[1..4])
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &veor ($T5,$T5,$T4);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vshr_u32 ($T4,&Dhi(@X[3]),$sigma1[1]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vsli_32 ($T4,&Dhi(@X[3]),32-$sigma1[1]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &veor ($T5,$T5,$T4); # sigma1(X[14..15])
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vadd_i32 (&Dlo(@X[0]),&Dlo(@X[0]),$T5);# X[0..1] += sigma1(X[14..15])
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vshr_u32 ($T4,&Dlo(@X[0]),$sigma1[0]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vsli_32 ($T4,&Dlo(@X[0]),32-$sigma1[0]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vshr_u32 ($T5,&Dlo(@X[0]),$sigma1[2]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &veor ($T5,$T5,$T4);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vshr_u32 ($T4,&Dlo(@X[0]),$sigma1[1]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vld1_32 ("{$T0}","[$Ktbl,:128]!");
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vsli_32 ($T4,&Dlo(@X[0]),32-$sigma1[1]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &veor ($T5,$T5,$T4); # sigma1(X[16..17])
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vadd_i32 (&Dhi(@X[0]),&Dhi(@X[0]),$T5);# X[2..3] += sigma1(X[16..17])
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vadd_i32 ($T0,$T0,@X[0]);
+ while($#insns>=2) { eval(shift(@insns)); }
+ &vst1_32 ("{$T0}","[$Xfer,:128]!");
+ eval(shift(@insns));
+ eval(shift(@insns));
+
+ push(@X,shift(@X)); # "rotate" X[]
+}
+
+sub Xpreload()
+{ use integer;
+ my $body = shift;
+ my @insns = (&$body,&$body,&$body,&$body);
+ my ($a,$b,$c,$d,$e,$f,$g,$h);
+
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vld1_32 ("{$T0}","[$Ktbl,:128]!");
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vrev32_8 (@X[0],@X[0]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vadd_i32 ($T0,$T0,@X[0]);
+ foreach (@insns) { eval; } # remaining instructions
+ &vst1_32 ("{$T0}","[$Xfer,:128]!");
+
+ push(@X,shift(@X)); # "rotate" X[]
+}
+
+sub body_00_15 () {
+ (
+ '($a,$b,$c,$d,$e,$f,$g,$h)=@V;'.
+ '&add ($h,$h,$t1)', # h+=X[i]+K[i]
+ '&eor ($t1,$f,$g)',
+ '&eor ($t0,$e,$e,"ror#".($Sigma1[1]-$Sigma1[0]))',
+ '&add ($a,$a,$t2)', # h+=Maj(a,b,c) from the past
+ '&and ($t1,$t1,$e)',
+ '&eor ($t2,$t0,$e,"ror#".($Sigma1[2]-$Sigma1[0]))', # Sigma1(e)
+ '&eor ($t0,$a,$a,"ror#".($Sigma0[1]-$Sigma0[0]))',
+ '&eor ($t1,$t1,$g)', # Ch(e,f,g)
+ '&add ($h,$h,$t2,"ror#$Sigma1[0]")', # h+=Sigma1(e)
+ '&eor ($t2,$a,$b)', # a^b, b^c in next round
+ '&eor ($t0,$t0,$a,"ror#".($Sigma0[2]-$Sigma0[0]))', # Sigma0(a)
+ '&add ($h,$h,$t1)', # h+=Ch(e,f,g)
+ '&ldr ($t1,sprintf "[sp,#%d]",4*(($j+1)&15)) if (($j&15)!=15);'.
+ '&ldr ($t1,"[$Ktbl]") if ($j==15);'.
+ '&ldr ($t1,"[sp,#64]") if ($j==31)',
+ '&and ($t3,$t3,$t2)', # (b^c)&=(a^b)
+ '&add ($d,$d,$h)', # d+=h
+ '&add ($h,$h,$t0,"ror#$Sigma0[0]");'. # h+=Sigma0(a)
+ '&eor ($t3,$t3,$b)', # Maj(a,b,c)
+ '$j++; unshift(@V,pop(@V)); ($t2,$t3)=($t3,$t2);'
+ )
+}
+
+$code.=<<___;
+#if __ARM_ARCH__>=7
+.fpu neon
+.align 4
+.LNEON:
+ stmdb sp!,{r4-r12,lr}
+
+ mov $t2,sp
+ sub sp,sp,#16*4+16 @ alloca
+ sub $Ktbl,r3,#256+32 @ K256
+ bic sp,sp,#15 @ align for 128-bit stores
+
+ vld1.8 {@X[0]},[$inp]!
+ vld1.8 {@X[1]},[$inp]!
+ vld1.8 {@X[2]},[$inp]!
+ vld1.8 {@X[3]},[$inp]!
+ vld1.32 {$T0},[$Ktbl,:128]!
+ vld1.32 {$T1},[$Ktbl,:128]!
+ vld1.32 {$T2},[$Ktbl,:128]!
+ vld1.32 {$T3},[$Ktbl,:128]!
+ vrev32.8 @X[0],@X[0] @ yes, even on
+ str $ctx,[sp,#64]
+ vrev32.8 @X[1],@X[1] @ big-endian
+ str $inp,[sp,#68]
+ mov $Xfer,sp
+ vrev32.8 @X[2],@X[2]
+ str $len,[sp,#72]
+ vrev32.8 @X[3],@X[3]
+ str $t2,[sp,#76] @ save original sp
+ vadd.i32 $T0,$T0,@X[0]
+ vadd.i32 $T1,$T1,@X[1]
+ vst1.32 {$T0},[$Xfer,:128]!
+ vadd.i32 $T2,$T2,@X[2]
+ vst1.32 {$T1},[$Xfer,:128]!
+ vadd.i32 $T3,$T3,@X[3]
+ vst1.32 {$T2},[$Xfer,:128]!
+ vst1.32 {$T3},[$Xfer,:128]!
+
+ ldmia $ctx,{$A-$H}
+ sub $Xfer,$Xfer,#64
+ ldr $t1,[sp,#0]
+ eor $t2,$t2,$t2
+ eor $t3,$B,$C
+ b .L_00_48
+
+.align 4
+.L_00_48:
+___
+ &Xupdate(\&body_00_15);
+ &Xupdate(\&body_00_15);
+ &Xupdate(\&body_00_15);
+ &Xupdate(\&body_00_15);
+$code.=<<___;
+ teq $t1,#0 @ check for K256 terminator
+ ldr $t1,[sp,#0]
+ sub $Xfer,$Xfer,#64
+ bne .L_00_48
+
+ ldr $inp,[sp,#68]
+ ldr $t0,[sp,#72]
+ sub $Ktbl,$Ktbl,#256 @ rewind $Ktbl
+ teq $inp,$t0
+ subeq $inp,$inp,#64 @ avoid SEGV
+ vld1.8 {@X[0]},[$inp]! @ load next input block
+ vld1.8 {@X[1]},[$inp]!
+ vld1.8 {@X[2]},[$inp]!
+ vld1.8 {@X[3]},[$inp]!
+ strne $inp,[sp,#68]
+ mov $Xfer,sp
+___
+ &Xpreload(\&body_00_15);
+ &Xpreload(\&body_00_15);
+ &Xpreload(\&body_00_15);
+ &Xpreload(\&body_00_15);
+$code.=<<___;
+ ldr $t0,[$t1,#0]
+ add $A,$A,$t2 @ h+=Maj(a,b,c) from the past
+ ldr $t2,[$t1,#4]
+ ldr $t3,[$t1,#8]
+ ldr $t4,[$t1,#12]
+ add $A,$A,$t0 @ accumulate
+ ldr $t0,[$t1,#16]
+ add $B,$B,$t2
+ ldr $t2,[$t1,#20]
+ add $C,$C,$t3
+ ldr $t3,[$t1,#24]
+ add $D,$D,$t4
+ ldr $t4,[$t1,#28]
+ add $E,$E,$t0
+ str $A,[$t1],#4
+ add $F,$F,$t2
+ str $B,[$t1],#4
+ add $G,$G,$t3
+ str $C,[$t1],#4
+ add $H,$H,$t4
+ str $D,[$t1],#4
+ stmia $t1,{$E-$H}
+
+ movne $Xfer,sp
+ ldrne $t1,[sp,#0]
+ eorne $t2,$t2,$t2
+ ldreq sp,[sp,#76] @ restore original sp
+ eorne $t3,$B,$C
+ bne .L_00_48
+
+ ldmia sp!,{r4-r12,pc}
+#endif
+___
+}}}
+$code.=<<___;
+.size sha256_block_data_order,.-sha256_block_data_order
+.asciz "SHA256 block transform for ARMv4/NEON, CRYPTOGAMS by <appro\@openssl.org>"
+.align 2
+.comm OPENSSL_armcap_P,4,4
+
+#endif
+___
+
+$code =~ s/\`([^\`]*)\`/eval $1/gem;
+$code =~ s/\bbx\s+lr\b/.word\t0xe12fff1e/gm; # make it possible to compile with -march=armv4
+print $code;
+close STDOUT; # enforce flush
diff --git a/crypto/sha/asm/sha512-586.pl b/crypto/sha/asm/sha512-586.pl
new file mode 100644
index 0000000..9fc7929
--- /dev/null
+++ b/crypto/sha/asm/sha512-586.pl
@@ -0,0 +1,910 @@
+#!/usr/bin/env perl
+#
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+#
+# SHA512 block transform for x86. September 2007.
+#
+# May 2013.
+#
+# Add SSSE3 code path, 20-25% improvement [over original SSE2 code].
+#
+# Performance in clock cycles per processed byte (less is better):
+#
+# gcc icc x86 asm SIMD(*) x86_64(**)
+# Pentium 100 97 61 - -
+# PIII 75 77 56 - -
+# P4 116 95 82 34.6 30.8
+# AMD K8 54 55 36 20.7 9.57
+# Core2 66 57 40 15.9 9.97
+# Westmere 70 - 38 12.2 9.58
+# Sandy Bridge 58 - 35 11.9 11.2
+# Ivy Bridge 50 - 33 11.5 8.17
+# Haswell 46 - 29 11.3 7.66
+# Bulldozer 121 - 50 14.0 13.5
+# VIA Nano 91 - 52 33 14.7
+# Atom 126 - 68 48(***) 14.7
+#
+# (*) whichever best applicable.
+# (**) x86_64 assembler performance is presented for reference
+# purposes, the results are for integer-only code.
+# (***) paddq is increadibly slow on Atom.
+#
+# 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%
+# 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
+# though it does not use 128-bit operations. The latter means that
+# SSE2-aware kernel is no longer required to execute the code. Another
+# difference is that new code optimizes amount of writes, but at the
+# cost of increased data cache "footprint" by 1/2KB.
+
+$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
+push(@INC,"${dir}","${dir}../../perlasm");
+require "x86asm.pl";
+
+&asm_init($ARGV[0],"sha512-586.pl",$ARGV[$#ARGV] eq "386");
+
+$sse2=0;
+for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); }
+
+&external_label("OPENSSL_ia32cap_P") if ($sse2);
+
+$Tlo=&DWP(0,"esp"); $Thi=&DWP(4,"esp");
+$Alo=&DWP(8,"esp"); $Ahi=&DWP(8+4,"esp");
+$Blo=&DWP(16,"esp"); $Bhi=&DWP(16+4,"esp");
+$Clo=&DWP(24,"esp"); $Chi=&DWP(24+4,"esp");
+$Dlo=&DWP(32,"esp"); $Dhi=&DWP(32+4,"esp");
+$Elo=&DWP(40,"esp"); $Ehi=&DWP(40+4,"esp");
+$Flo=&DWP(48,"esp"); $Fhi=&DWP(48+4,"esp");
+$Glo=&DWP(56,"esp"); $Ghi=&DWP(56+4,"esp");
+$Hlo=&DWP(64,"esp"); $Hhi=&DWP(64+4,"esp");
+$K512="ebp";
+
+$Asse2=&QWP(0,"esp");
+$Bsse2=&QWP(8,"esp");
+$Csse2=&QWP(16,"esp");
+$Dsse2=&QWP(24,"esp");
+$Esse2=&QWP(32,"esp");
+$Fsse2=&QWP(40,"esp");
+$Gsse2=&QWP(48,"esp");
+$Hsse2=&QWP(56,"esp");
+
+$A="mm0"; # B-D and
+$E="mm4"; # F-H are commonly loaded to respectively mm1-mm3 and
+ # mm5-mm7, but it's done on on-demand basis...
+$BxC="mm2"; # ... except for B^C
+
+sub BODY_00_15_sse2 {
+ my $phase=shift;
+
+ #&movq ("mm5",$Fsse2); # load f
+ #&movq ("mm6",$Gsse2); # load g
+
+ &movq ("mm1",$E); # %mm1 is sliding right
+ &pxor ("mm5","mm6"); # f^=g
+ &psrlq ("mm1",14);
+ &movq ($Esse2,$E); # modulo-scheduled save e
+ &pand ("mm5",$E); # f&=e
+ &psllq ($E,23); # $E is sliding left
+ &movq ($A,"mm3") if ($phase<2);
+ &movq (&QWP(8*9,"esp"),"mm7") # save X[i]
+ &movq ("mm3","mm1"); # %mm3 is T1
+ &psrlq ("mm1",4);
+ &pxor ("mm5","mm6"); # Ch(e,f,g)
+ &pxor ("mm3",$E);
+ &psllq ($E,23);
+ &pxor ("mm3","mm1");
+ &movq ($Asse2,$A); # modulo-scheduled save a
+ &paddq ("mm7","mm5"); # X[i]+=Ch(e,f,g)
+ &pxor ("mm3",$E);
+ &psrlq ("mm1",23);
+ &paddq ("mm7",$Hsse2); # X[i]+=h
+ &pxor ("mm3","mm1");
+ &psllq ($E,4);
+ &paddq ("mm7",QWP(0,$K512)); # X[i]+=K512[i]
+ &pxor ("mm3",$E); # T1=Sigma1_512(e)
+
+ &movq ($E,$Dsse2); # e = load d, e in next round
+ &paddq ("mm3","mm7"); # T1+=X[i]
+ &movq ("mm5",$A); # %mm5 is sliding right
+ &psrlq ("mm5",28);
+ &paddq ($E,"mm3"); # d += T1
+ &movq ("mm6",$A); # %mm6 is sliding left
+ &movq ("mm7","mm5");
+ &psllq ("mm6",25);
+ &movq ("mm1",$Bsse2); # load b
+ &psrlq ("mm5",6);
+ &pxor ("mm7","mm6");
+ &sub ("esp",8);
+ &psllq ("mm6",5);
+ &pxor ("mm7","mm5");
+ &pxor ($A,"mm1"); # a^b, b^c in next round
+ &psrlq ("mm5",5);
+ &pxor ("mm7","mm6");
+ &pand ($BxC,$A); # (b^c)&(a^b)
+ &psllq ("mm6",6);
+ &pxor ("mm7","mm5");
+ &pxor ($BxC,"mm1"); # [h=]Maj(a,b,c)
+ &pxor ("mm6","mm7"); # Sigma0_512(a)
+ &movq ("mm7",&QWP(8*(9+16-1),"esp")) if ($phase!=0); # pre-fetch
+ &movq ("mm5",$Fsse2) if ($phase==0); # load f
+
+ if ($phase>1) {
+ &paddq ($BxC,"mm6"); # h+=Sigma0(a)
+ &add ($K512,8);
+ #&paddq ($BxC,"mm3"); # h+=T1
+
+ ($A,$BxC) = ($BxC,$A); # rotate registers
+ } else {
+ &paddq ("mm3",$BxC); # T1+=Maj(a,b,c)
+ &movq ($BxC,$A);
+ &add ($K512,8);
+ &paddq ("mm3","mm6"); # T1+=Sigma0(a)
+ &movq ("mm6",$Gsse2) if ($phase==0); # load g
+ #&movq ($A,"mm3"); # h=T1
+ }
+}
+
+sub BODY_00_15_x86 {
+ #define Sigma1(x) (ROTR((x),14) ^ ROTR((x),18) ^ ROTR((x),41))
+ # LO lo>>14^hi<<18 ^ lo>>18^hi<<14 ^ hi>>9^lo<<23
+ # HI hi>>14^lo<<18 ^ hi>>18^lo<<14 ^ lo>>9^hi<<23
+ &mov ("ecx",$Elo);
+ &mov ("edx",$Ehi);
+ &mov ("esi","ecx");
+
+ &shr ("ecx",9); # lo>>9
+ &mov ("edi","edx");
+ &shr ("edx",9); # hi>>9
+ &mov ("ebx","ecx");
+ &shl ("esi",14); # lo<<14
+ &mov ("eax","edx");
+ &shl ("edi",14); # hi<<14
+ &xor ("ebx","esi");
+
+ &shr ("ecx",14-9); # lo>>14
+ &xor ("eax","edi");
+ &shr ("edx",14-9); # hi>>14
+ &xor ("eax","ecx");
+ &shl ("esi",18-14); # lo<<18
+ &xor ("ebx","edx");
+ &shl ("edi",18-14); # hi<<18
+ &xor ("ebx","esi");
+
+ &shr ("ecx",18-14); # lo>>18
+ &xor ("eax","edi");
+ &shr ("edx",18-14); # hi>>18
+ &xor ("eax","ecx");
+ &shl ("esi",23-18); # lo<<23
+ &xor ("ebx","edx");
+ &shl ("edi",23-18); # hi<<23
+ &xor ("eax","esi");
+ &xor ("ebx","edi"); # T1 = Sigma1(e)
+
+ &mov ("ecx",$Flo);
+ &mov ("edx",$Fhi);
+ &mov ("esi",$Glo);
+ &mov ("edi",$Ghi);
+ &add ("eax",$Hlo);
+ &adc ("ebx",$Hhi); # T1 += h
+ &xor ("ecx","esi");
+ &xor ("edx","edi");
+ &and ("ecx",$Elo);
+ &and ("edx",$Ehi);
+ &add ("eax",&DWP(8*(9+15)+0,"esp"));
+ &adc ("ebx",&DWP(8*(9+15)+4,"esp")); # T1 += X[0]
+ &xor ("ecx","esi");
+ &xor ("edx","edi"); # Ch(e,f,g) = (f^g)&e)^g
+
+ &mov ("esi",&DWP(0,$K512));
+ &mov ("edi",&DWP(4,$K512)); # K[i]
+ &add ("eax","ecx");
+ &adc ("ebx","edx"); # T1 += Ch(e,f,g)
+ &mov ("ecx",$Dlo);
+ &mov ("edx",$Dhi);
+ &add ("eax","esi");
+ &adc ("ebx","edi"); # T1 += K[i]
+ &mov ($Tlo,"eax");
+ &mov ($Thi,"ebx"); # put T1 away
+ &add ("eax","ecx");
+ &adc ("ebx","edx"); # d += T1
+
+ #define Sigma0(x) (ROTR((x),28) ^ ROTR((x),34) ^ ROTR((x),39))
+ # LO lo>>28^hi<<4 ^ hi>>2^lo<<30 ^ hi>>7^lo<<25
+ # HI hi>>28^lo<<4 ^ lo>>2^hi<<30 ^ lo>>7^hi<<25
+ &mov ("ecx",$Alo);
+ &mov ("edx",$Ahi);
+ &mov ($Dlo,"eax");
+ &mov ($Dhi,"ebx");
+ &mov ("esi","ecx");
+
+ &shr ("ecx",2); # lo>>2
+ &mov ("edi","edx");
+ &shr ("edx",2); # hi>>2
+ &mov ("ebx","ecx");
+ &shl ("esi",4); # lo<<4
+ &mov ("eax","edx");
+ &shl ("edi",4); # hi<<4
+ &xor ("ebx","esi");
+
+ &shr ("ecx",7-2); # lo>>7
+ &xor ("eax","edi");
+ &shr ("edx",7-2); # hi>>7
+ &xor ("ebx","ecx");
+ &shl ("esi",25-4); # lo<<25
+ &xor ("eax","edx");
+ &shl ("edi",25-4); # hi<<25
+ &xor ("eax","esi");
+
+ &shr ("ecx",28-7); # lo>>28
+ &xor ("ebx","edi");
+ &shr ("edx",28-7); # hi>>28
+ &xor ("eax","ecx");
+ &shl ("esi",30-25); # lo<<30
+ &xor ("ebx","edx");
+ &shl ("edi",30-25); # hi<<30
+ &xor ("eax","esi");
+ &xor ("ebx","edi"); # Sigma0(a)
+
+ &mov ("ecx",$Alo);
+ &mov ("edx",$Ahi);
+ &mov ("esi",$Blo);
+ &mov ("edi",$Bhi);
+ &add ("eax",$Tlo);
+ &adc ("ebx",$Thi); # T1 = Sigma0(a)+T1
+ &or ("ecx","esi");
+ &or ("edx","edi");
+ &and ("ecx",$Clo);
+ &and ("edx",$Chi);
+ &and ("esi",$Alo);
+ &and ("edi",$Ahi);
+ &or ("ecx","esi");
+ &or ("edx","edi"); # Maj(a,b,c) = ((a|b)&c)|(a&b)
+
+ &add ("eax","ecx");
+ &adc ("ebx","edx"); # T1 += Maj(a,b,c)
+ &mov ($Tlo,"eax");
+ &mov ($Thi,"ebx");
+
+ &mov (&LB("edx"),&BP(0,$K512)); # pre-fetch LSB of *K
+ &sub ("esp",8);
+ &lea ($K512,&DWP(8,$K512)); # K++
+}
+
+
+&function_begin("sha512_block_data_order");
+ &mov ("esi",wparam(0)); # ctx
+ &mov ("edi",wparam(1)); # inp
+ &mov ("eax",wparam(2)); # num
+ &mov ("ebx","esp"); # saved sp
+
+ &call (&label("pic_point")); # make it PIC!
+&set_label("pic_point");
+ &blindpop($K512);
+ &lea ($K512,&DWP(&label("K512")."-".&label("pic_point"),$K512));
+
+ &sub ("esp",16);
+ &and ("esp",-64);
+
+ &shl ("eax",7);
+ &add ("eax","edi");
+ &mov (&DWP(0,"esp"),"esi"); # ctx
+ &mov (&DWP(4,"esp"),"edi"); # inp
+ &mov (&DWP(8,"esp"),"eax"); # inp+num*128
+ &mov (&DWP(12,"esp"),"ebx"); # saved sp
+
+if ($sse2) {
+ &picmeup("edx","OPENSSL_ia32cap_P",$K512,&label("K512"));
+ &mov ("ecx",&DWP(0,"edx"));
+ &test ("ecx",1<<26);
+ &jz (&label("loop_x86"));
+
+ &mov ("edx",&DWP(4,"edx"));
+
+ # load ctx->h[0-7]
+ &movq ($A,&QWP(0,"esi"));
+ &and ("ecx",1<<24); # XMM registers availability
+ &movq ("mm1",&QWP(8,"esi"));
+ &and ("edx",1<<9); # SSSE3 bit
+ &movq ($BxC,&QWP(16,"esi"));
+ &or ("ecx","edx");
+ &movq ("mm3",&QWP(24,"esi"));
+ &movq ($E,&QWP(32,"esi"));
+ &movq ("mm5",&QWP(40,"esi"));
+ &movq ("mm6",&QWP(48,"esi"));
+ &movq ("mm7",&QWP(56,"esi"));
+ &cmp ("ecx",1<<24|1<<9);
+ &je (&label("SSSE3"));
+ &sub ("esp",8*10);
+ &jmp (&label("loop_sse2"));
+
+&set_label("loop_sse2",16);
+ #&movq ($Asse2,$A);
+ &movq ($Bsse2,"mm1");
+ &movq ($Csse2,$BxC);
+ &movq ($Dsse2,"mm3");
+ #&movq ($Esse2,$E);
+ &movq ($Fsse2,"mm5");
+ &movq ($Gsse2,"mm6");
+ &pxor ($BxC,"mm1"); # magic
+ &movq ($Hsse2,"mm7");
+ &movq ("mm3",$A); # magic
+
+ &mov ("eax",&DWP(0,"edi"));
+ &mov ("ebx",&DWP(4,"edi"));
+ &add ("edi",8);
+ &mov ("edx",15); # counter
+ &bswap ("eax");
+ &bswap ("ebx");
+ &jmp (&label("00_14_sse2"));
+
+&set_label("00_14_sse2",16);
+ &movd ("mm1","eax");
+ &mov ("eax",&DWP(0,"edi"));
+ &movd ("mm7","ebx");
+ &mov ("ebx",&DWP(4,"edi"));
+ &add ("edi",8);
+ &bswap ("eax");
+ &bswap ("ebx");
+ &punpckldq("mm7","mm1");
+
+ &BODY_00_15_sse2();
+
+ &dec ("edx");
+ &jnz (&label("00_14_sse2"));
+
+ &movd ("mm1","eax");
+ &movd ("mm7","ebx");
+ &punpckldq("mm7","mm1");
+
+ &BODY_00_15_sse2(1);
+
+ &pxor ($A,$A); # A is in %mm3
+ &mov ("edx",32); # counter
+ &jmp (&label("16_79_sse2"));
+
+&set_label("16_79_sse2",16);
+ for ($j=0;$j<2;$j++) { # 2x unroll
+ #&movq ("mm7",&QWP(8*(9+16-1),"esp")); # prefetched in BODY_00_15
+ &movq ("mm5",&QWP(8*(9+16-14),"esp"));
+ &movq ("mm1","mm7");
+ &psrlq ("mm7",1);
+ &movq ("mm6","mm5");
+ &psrlq ("mm5",6);
+ &psllq ("mm1",56);
+ &paddq ($A,"mm3"); # from BODY_00_15
+ &movq ("mm3","mm7");
+ &psrlq ("mm7",7-1);
+ &pxor ("mm3","mm1");
+ &psllq ("mm1",63-56);
+ &pxor ("mm3","mm7");
+ &psrlq ("mm7",8-7);
+ &pxor ("mm3","mm1");
+ &movq ("mm1","mm5");
+ &psrlq ("mm5",19-6);
+ &pxor ("mm7","mm3"); # sigma0
+
+ &psllq ("mm6",3);
+ &pxor ("mm1","mm5");
+ &paddq ("mm7",&QWP(8*(9+16),"esp"));
+ &pxor ("mm1","mm6");
+ &psrlq ("mm5",61-19);
+ &paddq ("mm7",&QWP(8*(9+16-9),"esp"));
+ &pxor ("mm1","mm5");
+ &psllq ("mm6",45-3);
+ &movq ("mm5",$Fsse2); # load f
+ &pxor ("mm1","mm6"); # sigma1
+ &movq ("mm6",$Gsse2); # load g
+
+ &paddq ("mm7","mm1"); # X[i]
+ #&movq (&QWP(8*9,"esp"),"mm7"); # moved to BODY_00_15
+
+ &BODY_00_15_sse2(2);
+ }
+ &dec ("edx");
+ &jnz (&label("16_79_sse2"));
+
+ #&movq ($A,$Asse2);
+ &paddq ($A,"mm3"); # from BODY_00_15
+ &movq ("mm1",$Bsse2);
+ #&movq ($BxC,$Csse2);
+ &movq ("mm3",$Dsse2);
+ #&movq ($E,$Esse2);
+ &movq ("mm5",$Fsse2);
+ &movq ("mm6",$Gsse2);
+ &movq ("mm7",$Hsse2);
+
+ &pxor ($BxC,"mm1"); # de-magic
+ &paddq ($A,&QWP(0,"esi"));
+ &paddq ("mm1",&QWP(8,"esi"));
+ &paddq ($BxC,&QWP(16,"esi"));
+ &paddq ("mm3",&QWP(24,"esi"));
+ &paddq ($E,&QWP(32,"esi"));
+ &paddq ("mm5",&QWP(40,"esi"));
+ &paddq ("mm6",&QWP(48,"esi"));
+ &paddq ("mm7",&QWP(56,"esi"));
+
+ &mov ("eax",8*80);
+ &movq (&QWP(0,"esi"),$A);
+ &movq (&QWP(8,"esi"),"mm1");
+ &movq (&QWP(16,"esi"),$BxC);
+ &movq (&QWP(24,"esi"),"mm3");
+ &movq (&QWP(32,"esi"),$E);
+ &movq (&QWP(40,"esi"),"mm5");
+ &movq (&QWP(48,"esi"),"mm6");
+ &movq (&QWP(56,"esi"),"mm7");
+
+ &lea ("esp",&DWP(0,"esp","eax")); # destroy frame
+ &sub ($K512,"eax"); # rewind K
+
+ &cmp ("edi",&DWP(8*10+8,"esp")); # are we done yet?
+ &jb (&label("loop_sse2"));
+
+ &mov ("esp",&DWP(8*10+12,"esp")); # restore sp
+ &emms ();
+&function_end_A();
+
+&set_label("SSSE3",32);
+{ my ($cnt,$frame)=("ecx","edx");
+ my @X=map("xmm$_",(0..7));
+ my $j;
+ my $i=0;
+
+ &lea ($frame,&DWP(-64,"esp"));
+ &sub ("esp",256);
+
+ # fixed stack frame layout
+ #
+ # +0 A B C D E F G H # backing store
+ # +64 X[0]+K[i] .. X[15]+K[i] # XMM->MM xfer area
+ # +192 # XMM off-load ring buffer
+ # +256 # saved parameters
+
+ &movdqa (@X[1],&QWP(80*8,$K512)); # byte swap mask
+ &movdqu (@X[0],&QWP(0,"edi"));
+ &pshufb (@X[0],@X[1]);
+ for ($j=0;$j<8;$j++) {
+ &movdqa (&QWP(16*(($j-1)%4),$frame),@X[3]) if ($j>4); # off-load
+ &movdqa (@X[3],&QWP(16*($j%8),$K512));
+ &movdqa (@X[2],@X[1]) if ($j<7); # perpetuate byte swap mask
+ &movdqu (@X[1],&QWP(16*($j+1),"edi")) if ($j<7); # next input
+ &movdqa (@X[1],&QWP(16*(($j+1)%4),$frame)) if ($j==7);# restore @X[0]
+ &paddq (@X[3],@X[0]);
+ &pshufb (@X[1],@X[2]) if ($j<7);
+ &movdqa (&QWP(16*($j%8)-128,$frame),@X[3]); # xfer X[i]+K[i]
+
+ push(@X,shift(@X)); # rotate(@X)
+ }
+ #&jmp (&label("loop_ssse3"));
+ &nop ();
+
+&set_label("loop_ssse3",32);
+ &movdqa (@X[2],&QWP(16*(($j+1)%4),$frame)); # pre-restore @X[1]
+ &movdqa (&QWP(16*(($j-1)%4),$frame),@X[3]); # off-load @X[3]
+ &lea ($K512,&DWP(16*8,$K512));
+
+ #&movq ($Asse2,$A); # off-load A-H
+ &movq ($Bsse2,"mm1");
+ &mov ("ebx","edi");
+ &movq ($Csse2,$BxC);
+ &lea ("edi",&DWP(128,"edi")); # advance input
+ &movq ($Dsse2,"mm3");
+ &cmp ("edi","eax");
+ #&movq ($Esse2,$E);
+ &movq ($Fsse2,"mm5");
+ &cmovb ("ebx","edi");
+ &movq ($Gsse2,"mm6");
+ &mov ("ecx",4); # loop counter
+ &pxor ($BxC,"mm1"); # magic
+ &movq ($Hsse2,"mm7");
+ &pxor ("mm3","mm3"); # magic
+
+ &jmp (&label("00_47_ssse3"));
+
+sub BODY_00_15_ssse3 { # "phase-less" copy of BODY_00_15_sse2
+ (
+ '&movq ("mm1",$E)', # %mm1 is sliding right
+ '&movq ("mm7",&QWP(((-8*$i)%128)-128,$frame))',# X[i]+K[i]
+ '&pxor ("mm5","mm6")', # f^=g
+ '&psrlq ("mm1",14)',
+ '&movq (&QWP(8*($i+4)%64,"esp"),$E)', # modulo-scheduled save e
+ '&pand ("mm5",$E)', # f&=e
+ '&psllq ($E,23)', # $E is sliding left
+ '&paddq ($A,"mm3")', # [h+=Maj(a,b,c)]
+ '&movq ("mm3","mm1")', # %mm3 is T1
+ '&psrlq("mm1",4)',
+ '&pxor ("mm5","mm6")', # Ch(e,f,g)
+ '&pxor ("mm3",$E)',
+ '&psllq($E,23)',
+ '&pxor ("mm3","mm1")',
+ '&movq (&QWP(8*$i%64,"esp"),$A)', # modulo-scheduled save a
+ '&paddq("mm7","mm5")', # X[i]+=Ch(e,f,g)
+ '&pxor ("mm3",$E)',
+ '&psrlq("mm1",23)',
+ '&paddq("mm7",&QWP(8*($i+7)%64,"esp"))', # X[i]+=h
+ '&pxor ("mm3","mm1")',
+ '&psllq($E,4)',
+ '&pxor ("mm3",$E)', # T1=Sigma1_512(e)
+
+ '&movq ($E,&QWP(8*($i+3)%64,"esp"))', # e = load d, e in next round
+ '&paddq ("mm3","mm7")', # T1+=X[i]
+ '&movq ("mm5",$A)', # %mm5 is sliding right
+ '&psrlq("mm5",28)',
+ '&paddq ($E,"mm3")', # d += T1
+ '&movq ("mm6",$A)', # %mm6 is sliding left
+ '&movq ("mm7","mm5")',
+ '&psllq("mm6",25)',
+ '&movq ("mm1",&QWP(8*($i+1)%64,"esp"))', # load b
+ '&psrlq("mm5",6)',
+ '&pxor ("mm7","mm6")',
+ '&psllq("mm6",5)',
+ '&pxor ("mm7","mm5")',
+ '&pxor ($A,"mm1")', # a^b, b^c in next round
+ '&psrlq("mm5",5)',
+ '&pxor ("mm7","mm6")',
+ '&pand ($BxC,$A)', # (b^c)&(a^b)
+ '&psllq("mm6",6)',
+ '&pxor ("mm7","mm5")',
+ '&pxor ($BxC,"mm1")', # [h=]Maj(a,b,c)
+ '&pxor ("mm6","mm7")', # Sigma0_512(a)
+ '&movq ("mm5",&QWP(8*($i+5-1)%64,"esp"))', # pre-load f
+ '&paddq ($BxC,"mm6")', # h+=Sigma0(a)
+ '&movq ("mm6",&QWP(8*($i+6-1)%64,"esp"))', # pre-load g
+
+ '($A,$BxC) = ($BxC,$A); $i--;'
+ );
+}
+
+&set_label("00_47_ssse3",32);
+
+ for(;$j<16;$j++) {
+ my ($t0,$t2,$t1)=@X[2..4];
+ my @insns = (&BODY_00_15_ssse3(),&BODY_00_15_ssse3());
+
+ &movdqa ($t2,@X[5]);
+ &movdqa (@X[1],$t0); # restore @X[1]
+ &palignr ($t0,@X[0],8); # X[1..2]
+ &movdqa (&QWP(16*($j%4),$frame),@X[4]); # off-load @X[4]
+ &palignr ($t2,@X[4],8); # X[9..10]
+
+ &movdqa ($t1,$t0);
+ &psrlq ($t0,7);
+ &paddq (@X[0],$t2); # X[0..1] += X[9..10]
+ &movdqa ($t2,$t1);
+ &psrlq ($t1,1);
+ &psllq ($t2,64-8);
+ &pxor ($t0,$t1);
+ &psrlq ($t1,8-1);
+ &pxor ($t0,$t2);
+ &psllq ($t2,8-1);
+ &pxor ($t0,$t1);
+ &movdqa ($t1,@X[7]);
+ &pxor ($t0,$t2); # sigma0(X[1..2])
+ &movdqa ($t2,@X[7]);
+ &psrlq ($t1,6);
+ &paddq (@X[0],$t0); # X[0..1] += sigma0(X[1..2])
+
+ &movdqa ($t0,@X[7]);
+ &psrlq ($t2,19);
+ &psllq ($t0,64-61);
+ &pxor ($t1,$t2);
+ &psrlq ($t2,61-19);
+ &pxor ($t1,$t0);
+ &psllq ($t0,61-19);
+ &pxor ($t1,$t2);
+ &movdqa ($t2,&QWP(16*(($j+2)%4),$frame));# pre-restore @X[1]
+ &pxor ($t1,$t0); # sigma0(X[1..2])
+ &movdqa ($t0,&QWP(16*($j%8),$K512));
+ eval(shift(@insns));
+ &paddq (@X[0],$t1); # X[0..1] += sigma0(X[14..15])
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &paddq ($t0,@X[0]);
+ foreach(@insns) { eval; }
+ &movdqa (&QWP(16*($j%8)-128,$frame),$t0);# xfer X[i]+K[i]
+
+ push(@X,shift(@X)); # rotate(@X)
+ }
+ &lea ($K512,&DWP(16*8,$K512));
+ &dec ("ecx");
+ &jnz (&label("00_47_ssse3"));
+
+ &movdqa (@X[1],&QWP(0,$K512)); # byte swap mask
+ &lea ($K512,&DWP(-80*8,$K512)); # rewind
+ &movdqu (@X[0],&QWP(0,"ebx"));
+ &pshufb (@X[0],@X[1]);
+
+ for ($j=0;$j<8;$j++) { # load next or same block
+ my @insns = (&BODY_00_15_ssse3(),&BODY_00_15_ssse3());
+
+ &movdqa (&QWP(16*(($j-1)%4),$frame),@X[3]) if ($j>4); # off-load
+ &movdqa (@X[3],&QWP(16*($j%8),$K512));
+ &movdqa (@X[2],@X[1]) if ($j<7); # perpetuate byte swap mask
+ &movdqu (@X[1],&QWP(16*($j+1),"ebx")) if ($j<7); # next input
+ &movdqa (@X[1],&QWP(16*(($j+1)%4),$frame)) if ($j==7);# restore @X[0]
+ &paddq (@X[3],@X[0]);
+ &pshufb (@X[1],@X[2]) if ($j<7);
+ foreach(@insns) { eval; }
+ &movdqa (&QWP(16*($j%8)-128,$frame),@X[3]);# xfer X[i]+K[i]
+
+ push(@X,shift(@X)); # rotate(@X)
+ }
+
+ #&movq ($A,$Asse2); # load A-H
+ &movq ("mm1",$Bsse2);
+ &paddq ($A,"mm3"); # from BODY_00_15
+ #&movq ($BxC,$Csse2);
+ &movq ("mm3",$Dsse2);
+ #&movq ($E,$Esse2);
+ #&movq ("mm5",$Fsse2);
+ #&movq ("mm6",$Gsse2);
+ &movq ("mm7",$Hsse2);
+
+ &pxor ($BxC,"mm1"); # de-magic
+ &paddq ($A,&QWP(0,"esi"));
+ &paddq ("mm1",&QWP(8,"esi"));
+ &paddq ($BxC,&QWP(16,"esi"));
+ &paddq ("mm3",&QWP(24,"esi"));
+ &paddq ($E,&QWP(32,"esi"));
+ &paddq ("mm5",&QWP(40,"esi"));
+ &paddq ("mm6",&QWP(48,"esi"));
+ &paddq ("mm7",&QWP(56,"esi"));
+
+ &movq (&QWP(0,"esi"),$A);
+ &movq (&QWP(8,"esi"),"mm1");
+ &movq (&QWP(16,"esi"),$BxC);
+ &movq (&QWP(24,"esi"),"mm3");
+ &movq (&QWP(32,"esi"),$E);
+ &movq (&QWP(40,"esi"),"mm5");
+ &movq (&QWP(48,"esi"),"mm6");
+ &movq (&QWP(56,"esi"),"mm7");
+
+ &cmp ("edi","eax") # are we done yet?
+ &jb (&label("loop_ssse3"));
+
+ &mov ("esp",&DWP(64+12,$frame)); # restore sp
+ &emms ();
+}
+&function_end_A();
+}
+&set_label("loop_x86",16);
+ # copy input block to stack reversing byte and qword order
+ for ($i=0;$i<8;$i++) {
+ &mov ("eax",&DWP($i*16+0,"edi"));
+ &mov ("ebx",&DWP($i*16+4,"edi"));
+ &mov ("ecx",&DWP($i*16+8,"edi"));
+ &mov ("edx",&DWP($i*16+12,"edi"));
+ &bswap ("eax");
+ &bswap ("ebx");
+ &bswap ("ecx");
+ &bswap ("edx");
+ &push ("eax");
+ &push ("ebx");
+ &push ("ecx");
+ &push ("edx");
+ }
+ &add ("edi",128);
+ &sub ("esp",9*8); # place for T,A,B,C,D,E,F,G,H
+ &mov (&DWP(8*(9+16)+4,"esp"),"edi");
+
+ # copy ctx->h[0-7] to A,B,C,D,E,F,G,H on stack
+ &lea ("edi",&DWP(8,"esp"));
+ &mov ("ecx",16);
+ &data_word(0xA5F3F689); # rep movsd
+
+&set_label("00_15_x86",16);
+ &BODY_00_15_x86();
+
+ &cmp (&LB("edx"),0x94);
+ &jne (&label("00_15_x86"));
+
+&set_label("16_79_x86",16);
+ #define sigma0(x) (ROTR((x),1) ^ ROTR((x),8) ^ ((x)>>7))
+ # LO lo>>1^hi<<31 ^ lo>>8^hi<<24 ^ lo>>7^hi<<25
+ # HI hi>>1^lo<<31 ^ hi>>8^lo<<24 ^ hi>>7
+ &mov ("ecx",&DWP(8*(9+15+16-1)+0,"esp"));
+ &mov ("edx",&DWP(8*(9+15+16-1)+4,"esp"));
+ &mov ("esi","ecx");
+
+ &shr ("ecx",1); # lo>>1
+ &mov ("edi","edx");
+ &shr ("edx",1); # hi>>1
+ &mov ("eax","ecx");
+ &shl ("esi",24); # lo<<24
+ &mov ("ebx","edx");
+ &shl ("edi",24); # hi<<24
+ &xor ("ebx","esi");
+
+ &shr ("ecx",7-1); # lo>>7
+ &xor ("eax","edi");
+ &shr ("edx",7-1); # hi>>7
+ &xor ("eax","ecx");
+ &shl ("esi",31-24); # lo<<31
+ &xor ("ebx","edx");
+ &shl ("edi",25-24); # hi<<25
+ &xor ("ebx","esi");
+
+ &shr ("ecx",8-7); # lo>>8
+ &xor ("eax","edi");
+ &shr ("edx",8-7); # hi>>8
+ &xor ("eax","ecx");
+ &shl ("edi",31-25); # hi<<31
+ &xor ("ebx","edx");
+ &xor ("eax","edi"); # T1 = sigma0(X[-15])
+
+ &mov (&DWP(0,"esp"),"eax");
+ &mov (&DWP(4,"esp"),"ebx"); # put T1 away
+
+ #define sigma1(x) (ROTR((x),19) ^ ROTR((x),61) ^ ((x)>>6))
+ # LO lo>>19^hi<<13 ^ hi>>29^lo<<3 ^ lo>>6^hi<<26
+ # HI hi>>19^lo<<13 ^ lo>>29^hi<<3 ^ hi>>6
+ &mov ("ecx",&DWP(8*(9+15+16-14)+0,"esp"));
+ &mov ("edx",&DWP(8*(9+15+16-14)+4,"esp"));
+ &mov ("esi","ecx");
+
+ &shr ("ecx",6); # lo>>6
+ &mov ("edi","edx");
+ &shr ("edx",6); # hi>>6
+ &mov ("eax","ecx");
+ &shl ("esi",3); # lo<<3
+ &mov ("ebx","edx");
+ &shl ("edi",3); # hi<<3
+ &xor ("eax","esi");
+
+ &shr ("ecx",19-6); # lo>>19
+ &xor ("ebx","edi");
+ &shr ("edx",19-6); # hi>>19
+ &xor ("eax","ecx");
+ &shl ("esi",13-3); # lo<<13
+ &xor ("ebx","edx");
+ &shl ("edi",13-3); # hi<<13
+ &xor ("ebx","esi");
+
+ &shr ("ecx",29-19); # lo>>29
+ &xor ("eax","edi");
+ &shr ("edx",29-19); # hi>>29
+ &xor ("ebx","ecx");
+ &shl ("edi",26-13); # hi<<26
+ &xor ("eax","edx");
+ &xor ("eax","edi"); # sigma1(X[-2])
+
+ &mov ("ecx",&DWP(8*(9+15+16)+0,"esp"));
+ &mov ("edx",&DWP(8*(9+15+16)+4,"esp"));
+ &add ("eax",&DWP(0,"esp"));
+ &adc ("ebx",&DWP(4,"esp")); # T1 = sigma1(X[-2])+T1
+ &mov ("esi",&DWP(8*(9+15+16-9)+0,"esp"));
+ &mov ("edi",&DWP(8*(9+15+16-9)+4,"esp"));
+ &add ("eax","ecx");
+ &adc ("ebx","edx"); # T1 += X[-16]
+ &add ("eax","esi");
+ &adc ("ebx","edi"); # T1 += X[-7]
+ &mov (&DWP(8*(9+15)+0,"esp"),"eax");
+ &mov (&DWP(8*(9+15)+4,"esp"),"ebx"); # save X[0]
+
+ &BODY_00_15_x86();
+
+ &cmp (&LB("edx"),0x17);
+ &jne (&label("16_79_x86"));
+
+ &mov ("esi",&DWP(8*(9+16+80)+0,"esp"));# ctx
+ &mov ("edi",&DWP(8*(9+16+80)+4,"esp"));# inp
+ for($i=0;$i<4;$i++) {
+ &mov ("eax",&DWP($i*16+0,"esi"));
+ &mov ("ebx",&DWP($i*16+4,"esi"));
+ &mov ("ecx",&DWP($i*16+8,"esi"));
+ &mov ("edx",&DWP($i*16+12,"esi"));
+ &add ("eax",&DWP(8+($i*16)+0,"esp"));
+ &adc ("ebx",&DWP(8+($i*16)+4,"esp"));
+ &mov (&DWP($i*16+0,"esi"),"eax");
+ &mov (&DWP($i*16+4,"esi"),"ebx");
+ &add ("ecx",&DWP(8+($i*16)+8,"esp"));
+ &adc ("edx",&DWP(8+($i*16)+12,"esp"));
+ &mov (&DWP($i*16+8,"esi"),"ecx");
+ &mov (&DWP($i*16+12,"esi"),"edx");
+ }
+ &add ("esp",8*(9+16+80)); # destroy frame
+ &sub ($K512,8*80); # rewind K
+
+ &cmp ("edi",&DWP(8,"esp")); # are we done yet?
+ &jb (&label("loop_x86"));
+
+ &mov ("esp",&DWP(12,"esp")); # restore sp
+&function_end_A();
+
+&set_label("K512",64); # Yes! I keep it in the code segment!
+ &data_word(0xd728ae22,0x428a2f98); # u64
+ &data_word(0x23ef65cd,0x71374491); # u64
+ &data_word(0xec4d3b2f,0xb5c0fbcf); # u64
+ &data_word(0x8189dbbc,0xe9b5dba5); # u64
+ &data_word(0xf348b538,0x3956c25b); # u64
+ &data_word(0xb605d019,0x59f111f1); # u64
+ &data_word(0xaf194f9b,0x923f82a4); # u64
+ &data_word(0xda6d8118,0xab1c5ed5); # u64
+ &data_word(0xa3030242,0xd807aa98); # u64
+ &data_word(0x45706fbe,0x12835b01); # u64
+ &data_word(0x4ee4b28c,0x243185be); # u64
+ &data_word(0xd5ffb4e2,0x550c7dc3); # u64
+ &data_word(0xf27b896f,0x72be5d74); # u64
+ &data_word(0x3b1696b1,0x80deb1fe); # u64
+ &data_word(0x25c71235,0x9bdc06a7); # u64
+ &data_word(0xcf692694,0xc19bf174); # u64
+ &data_word(0x9ef14ad2,0xe49b69c1); # u64
+ &data_word(0x384f25e3,0xefbe4786); # u64
+ &data_word(0x8b8cd5b5,0x0fc19dc6); # u64
+ &data_word(0x77ac9c65,0x240ca1cc); # u64
+ &data_word(0x592b0275,0x2de92c6f); # u64
+ &data_word(0x6ea6e483,0x4a7484aa); # u64
+ &data_word(0xbd41fbd4,0x5cb0a9dc); # u64
+ &data_word(0x831153b5,0x76f988da); # u64
+ &data_word(0xee66dfab,0x983e5152); # u64
+ &data_word(0x2db43210,0xa831c66d); # u64
+ &data_word(0x98fb213f,0xb00327c8); # u64
+ &data_word(0xbeef0ee4,0xbf597fc7); # u64
+ &data_word(0x3da88fc2,0xc6e00bf3); # u64
+ &data_word(0x930aa725,0xd5a79147); # u64
+ &data_word(0xe003826f,0x06ca6351); # u64
+ &data_word(0x0a0e6e70,0x14292967); # u64
+ &data_word(0x46d22ffc,0x27b70a85); # u64
+ &data_word(0x5c26c926,0x2e1b2138); # u64
+ &data_word(0x5ac42aed,0x4d2c6dfc); # u64
+ &data_word(0x9d95b3df,0x53380d13); # u64
+ &data_word(0x8baf63de,0x650a7354); # u64
+ &data_word(0x3c77b2a8,0x766a0abb); # u64
+ &data_word(0x47edaee6,0x81c2c92e); # u64
+ &data_word(0x1482353b,0x92722c85); # u64
+ &data_word(0x4cf10364,0xa2bfe8a1); # u64
+ &data_word(0xbc423001,0xa81a664b); # u64
+ &data_word(0xd0f89791,0xc24b8b70); # u64
+ &data_word(0x0654be30,0xc76c51a3); # u64
+ &data_word(0xd6ef5218,0xd192e819); # u64
+ &data_word(0x5565a910,0xd6990624); # u64
+ &data_word(0x5771202a,0xf40e3585); # u64
+ &data_word(0x32bbd1b8,0x106aa070); # u64
+ &data_word(0xb8d2d0c8,0x19a4c116); # u64
+ &data_word(0x5141ab53,0x1e376c08); # u64
+ &data_word(0xdf8eeb99,0x2748774c); # u64
+ &data_word(0xe19b48a8,0x34b0bcb5); # u64
+ &data_word(0xc5c95a63,0x391c0cb3); # u64
+ &data_word(0xe3418acb,0x4ed8aa4a); # u64
+ &data_word(0x7763e373,0x5b9cca4f); # u64
+ &data_word(0xd6b2b8a3,0x682e6ff3); # u64
+ &data_word(0x5defb2fc,0x748f82ee); # u64
+ &data_word(0x43172f60,0x78a5636f); # u64
+ &data_word(0xa1f0ab72,0x84c87814); # u64
+ &data_word(0x1a6439ec,0x8cc70208); # u64
+ &data_word(0x23631e28,0x90befffa); # u64
+ &data_word(0xde82bde9,0xa4506ceb); # u64
+ &data_word(0xb2c67915,0xbef9a3f7); # u64
+ &data_word(0xe372532b,0xc67178f2); # u64
+ &data_word(0xea26619c,0xca273ece); # u64
+ &data_word(0x21c0c207,0xd186b8c7); # u64
+ &data_word(0xcde0eb1e,0xeada7dd6); # u64
+ &data_word(0xee6ed178,0xf57d4f7f); # u64
+ &data_word(0x72176fba,0x06f067aa); # u64
+ &data_word(0xa2c898a6,0x0a637dc5); # u64
+ &data_word(0xbef90dae,0x113f9804); # u64
+ &data_word(0x131c471b,0x1b710b35); # u64
+ &data_word(0x23047d84,0x28db77f5); # u64
+ &data_word(0x40c72493,0x32caab7b); # u64
+ &data_word(0x15c9bebc,0x3c9ebe0a); # u64
+ &data_word(0x9c100d4c,0x431d67c4); # u64
+ &data_word(0xcb3e42b6,0x4cc5d4be); # u64
+ &data_word(0xfc657e2a,0x597f299c); # u64
+ &data_word(0x3ad6faec,0x5fcb6fab); # u64
+ &data_word(0x4a475817,0x6c44198c); # u64
+
+ &data_word(0x04050607,0x00010203); # byte swap
+ &data_word(0x0c0d0e0f,0x08090a0b); # mask
+&function_end_B("sha512_block_data_order");
+&asciz("SHA512 block transform for x86, CRYPTOGAMS by <appro\@openssl.org>");
+
+&asm_finish();
diff --git a/crypto/sha/asm/sha512-armv4.pl b/crypto/sha/asm/sha512-armv4.pl
new file mode 100644
index 0000000..ae2cbfc
--- /dev/null
+++ b/crypto/sha/asm/sha512-armv4.pl
@@ -0,0 +1,604 @@
+#!/usr/bin/env perl
+
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. The module is, however, dual licensed under OpenSSL and
+# CRYPTOGAMS licenses depending on where you obtain it. For further
+# details see http://www.openssl.org/~appro/cryptogams/.
+# ====================================================================
+
+# SHA512 block procedure for ARMv4. September 2007.
+
+# This code is ~4.5 (four and a half) times faster than code generated
+# by gcc 3.4 and it spends ~72 clock cycles per byte [on single-issue
+# Xscale PXA250 core].
+#
+# July 2010.
+#
+# Rescheduling for dual-issue pipeline resulted in 6% improvement on
+# Cortex A8 core and ~40 cycles per processed byte.
+
+# February 2011.
+#
+# Profiler-assisted and platform-specific optimization resulted in 7%
+# improvement on Coxtex A8 core and ~38 cycles per byte.
+
+# March 2011.
+#
+# Add NEON implementation. On Cortex A8 it was measured to process
+# one byte in 23.3 cycles or ~60% faster than integer-only code.
+
+# August 2012.
+#
+# Improve NEON performance by 12% on Snapdragon S4. In absolute
+# terms it's 22.6 cycles per byte, which is disappointing result.
+# Technical writers asserted that 3-way S4 pipeline can sustain
+# multiple NEON instructions per cycle, but dual NEON issue could
+# not be observed, and for NEON-only sequences IPC(*) was found to
+# be limited by 1:-( 0.33 and 0.66 were measured for sequences with
+# ILPs(*) of 1 and 2 respectively. This in turn means that you can
+# even find yourself striving, as I did here, for achieving IPC
+# adequate to one delivered by Cortex A8 [for reference, it's
+# 0.5 for ILP of 1, and 1 for higher ILPs].
+#
+# (*) ILP, instruction-level parallelism, how many instructions
+# *can* execute at the same time. IPC, instructions per cycle,
+# indicates how many instructions actually execute.
+
+# Byte order [in]dependence. =========================================
+#
+# Originally caller was expected to maintain specific *dword* order in
+# h[0-7], namely with most significant dword at *lower* address, which
+# was reflected in below two parameters as 0 and 4. Now caller is
+# expected to maintain native byte order for whole 64-bit values.
+$hi="HI";
+$lo="LO";
+# ====================================================================
+
+while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {}
+open STDOUT,">$output";
+
+$ctx="r0"; # parameter block
+$inp="r1";
+$len="r2";
+
+$Tlo="r3";
+$Thi="r4";
+$Alo="r5";
+$Ahi="r6";
+$Elo="r7";
+$Ehi="r8";
+$t0="r9";
+$t1="r10";
+$t2="r11";
+$t3="r12";
+############ r13 is stack pointer
+$Ktbl="r14";
+############ r15 is program counter
+
+$Aoff=8*0;
+$Boff=8*1;
+$Coff=8*2;
+$Doff=8*3;
+$Eoff=8*4;
+$Foff=8*5;
+$Goff=8*6;
+$Hoff=8*7;
+$Xoff=8*8;
+
+sub BODY_00_15() {
+my $magic = shift;
+$code.=<<___;
+ @ Sigma1(x) (ROTR((x),14) ^ ROTR((x),18) ^ ROTR((x),41))
+ @ LO lo>>14^hi<<18 ^ lo>>18^hi<<14 ^ hi>>9^lo<<23
+ @ HI hi>>14^lo<<18 ^ hi>>18^lo<<14 ^ lo>>9^hi<<23
+ mov $t0,$Elo,lsr#14
+ str $Tlo,[sp,#$Xoff+0]
+ mov $t1,$Ehi,lsr#14
+ str $Thi,[sp,#$Xoff+4]
+ eor $t0,$t0,$Ehi,lsl#18
+ ldr $t2,[sp,#$Hoff+0] @ h.lo
+ eor $t1,$t1,$Elo,lsl#18
+ ldr $t3,[sp,#$Hoff+4] @ h.hi
+ eor $t0,$t0,$Elo,lsr#18
+ eor $t1,$t1,$Ehi,lsr#18
+ eor $t0,$t0,$Ehi,lsl#14
+ eor $t1,$t1,$Elo,lsl#14
+ eor $t0,$t0,$Ehi,lsr#9
+ eor $t1,$t1,$Elo,lsr#9
+ eor $t0,$t0,$Elo,lsl#23
+ eor $t1,$t1,$Ehi,lsl#23 @ Sigma1(e)
+ adds $Tlo,$Tlo,$t0
+ ldr $t0,[sp,#$Foff+0] @ f.lo
+ adc $Thi,$Thi,$t1 @ T += Sigma1(e)
+ ldr $t1,[sp,#$Foff+4] @ f.hi
+ adds $Tlo,$Tlo,$t2
+ ldr $t2,[sp,#$Goff+0] @ g.lo
+ adc $Thi,$Thi,$t3 @ T += h
+ ldr $t3,[sp,#$Goff+4] @ g.hi
+
+ eor $t0,$t0,$t2
+ str $Elo,[sp,#$Eoff+0]
+ eor $t1,$t1,$t3
+ str $Ehi,[sp,#$Eoff+4]
+ and $t0,$t0,$Elo
+ str $Alo,[sp,#$Aoff+0]
+ and $t1,$t1,$Ehi
+ str $Ahi,[sp,#$Aoff+4]
+ eor $t0,$t0,$t2
+ ldr $t2,[$Ktbl,#$lo] @ K[i].lo
+ eor $t1,$t1,$t3 @ Ch(e,f,g)
+ ldr $t3,[$Ktbl,#$hi] @ K[i].hi
+
+ adds $Tlo,$Tlo,$t0
+ ldr $Elo,[sp,#$Doff+0] @ d.lo
+ adc $Thi,$Thi,$t1 @ T += Ch(e,f,g)
+ ldr $Ehi,[sp,#$Doff+4] @ d.hi
+ adds $Tlo,$Tlo,$t2
+ and $t0,$t2,#0xff
+ adc $Thi,$Thi,$t3 @ T += K[i]
+ adds $Elo,$Elo,$Tlo
+ ldr $t2,[sp,#$Boff+0] @ b.lo
+ adc $Ehi,$Ehi,$Thi @ d += T
+ teq $t0,#$magic
+
+ ldr $t3,[sp,#$Coff+0] @ c.lo
+ orreq $Ktbl,$Ktbl,#1
+ @ Sigma0(x) (ROTR((x),28) ^ ROTR((x),34) ^ ROTR((x),39))
+ @ LO lo>>28^hi<<4 ^ hi>>2^lo<<30 ^ hi>>7^lo<<25
+ @ HI hi>>28^lo<<4 ^ lo>>2^hi<<30 ^ lo>>7^hi<<25
+ mov $t0,$Alo,lsr#28
+ mov $t1,$Ahi,lsr#28
+ eor $t0,$t0,$Ahi,lsl#4
+ eor $t1,$t1,$Alo,lsl#4
+ eor $t0,$t0,$Ahi,lsr#2
+ eor $t1,$t1,$Alo,lsr#2
+ eor $t0,$t0,$Alo,lsl#30
+ eor $t1,$t1,$Ahi,lsl#30
+ eor $t0,$t0,$Ahi,lsr#7
+ eor $t1,$t1,$Alo,lsr#7
+ eor $t0,$t0,$Alo,lsl#25
+ eor $t1,$t1,$Ahi,lsl#25 @ Sigma0(a)
+ adds $Tlo,$Tlo,$t0
+ and $t0,$Alo,$t2
+ adc $Thi,$Thi,$t1 @ T += Sigma0(a)
+
+ ldr $t1,[sp,#$Boff+4] @ b.hi
+ orr $Alo,$Alo,$t2
+ ldr $t2,[sp,#$Coff+4] @ c.hi
+ and $Alo,$Alo,$t3
+ and $t3,$Ahi,$t1
+ orr $Ahi,$Ahi,$t1
+ orr $Alo,$Alo,$t0 @ Maj(a,b,c).lo
+ and $Ahi,$Ahi,$t2
+ adds $Alo,$Alo,$Tlo
+ orr $Ahi,$Ahi,$t3 @ Maj(a,b,c).hi
+ sub sp,sp,#8
+ adc $Ahi,$Ahi,$Thi @ h += T
+ tst $Ktbl,#1
+ add $Ktbl,$Ktbl,#8
+___
+}
+$code=<<___;
+#if defined(__arm__)
+#include "arm_arch.h"
+#ifdef __ARMEL__
+# define LO 0
+# define HI 4
+# define WORD64(hi0,lo0,hi1,lo1) .word lo0,hi0, lo1,hi1
+#else
+# define HI 0
+# define LO 4
+# define WORD64(hi0,lo0,hi1,lo1) .word hi0,lo0, hi1,lo1
+#endif
+
+.text
+.code 32
+.type K512,%object
+.align 5
+K512:
+WORD64(0x428a2f98,0xd728ae22, 0x71374491,0x23ef65cd)
+WORD64(0xb5c0fbcf,0xec4d3b2f, 0xe9b5dba5,0x8189dbbc)
+WORD64(0x3956c25b,0xf348b538, 0x59f111f1,0xb605d019)
+WORD64(0x923f82a4,0xaf194f9b, 0xab1c5ed5,0xda6d8118)
+WORD64(0xd807aa98,0xa3030242, 0x12835b01,0x45706fbe)
+WORD64(0x243185be,0x4ee4b28c, 0x550c7dc3,0xd5ffb4e2)
+WORD64(0x72be5d74,0xf27b896f, 0x80deb1fe,0x3b1696b1)
+WORD64(0x9bdc06a7,0x25c71235, 0xc19bf174,0xcf692694)
+WORD64(0xe49b69c1,0x9ef14ad2, 0xefbe4786,0x384f25e3)
+WORD64(0x0fc19dc6,0x8b8cd5b5, 0x240ca1cc,0x77ac9c65)
+WORD64(0x2de92c6f,0x592b0275, 0x4a7484aa,0x6ea6e483)
+WORD64(0x5cb0a9dc,0xbd41fbd4, 0x76f988da,0x831153b5)
+WORD64(0x983e5152,0xee66dfab, 0xa831c66d,0x2db43210)
+WORD64(0xb00327c8,0x98fb213f, 0xbf597fc7,0xbeef0ee4)
+WORD64(0xc6e00bf3,0x3da88fc2, 0xd5a79147,0x930aa725)
+WORD64(0x06ca6351,0xe003826f, 0x14292967,0x0a0e6e70)
+WORD64(0x27b70a85,0x46d22ffc, 0x2e1b2138,0x5c26c926)
+WORD64(0x4d2c6dfc,0x5ac42aed, 0x53380d13,0x9d95b3df)
+WORD64(0x650a7354,0x8baf63de, 0x766a0abb,0x3c77b2a8)
+WORD64(0x81c2c92e,0x47edaee6, 0x92722c85,0x1482353b)
+WORD64(0xa2bfe8a1,0x4cf10364, 0xa81a664b,0xbc423001)
+WORD64(0xc24b8b70,0xd0f89791, 0xc76c51a3,0x0654be30)
+WORD64(0xd192e819,0xd6ef5218, 0xd6990624,0x5565a910)
+WORD64(0xf40e3585,0x5771202a, 0x106aa070,0x32bbd1b8)
+WORD64(0x19a4c116,0xb8d2d0c8, 0x1e376c08,0x5141ab53)
+WORD64(0x2748774c,0xdf8eeb99, 0x34b0bcb5,0xe19b48a8)
+WORD64(0x391c0cb3,0xc5c95a63, 0x4ed8aa4a,0xe3418acb)
+WORD64(0x5b9cca4f,0x7763e373, 0x682e6ff3,0xd6b2b8a3)
+WORD64(0x748f82ee,0x5defb2fc, 0x78a5636f,0x43172f60)
+WORD64(0x84c87814,0xa1f0ab72, 0x8cc70208,0x1a6439ec)
+WORD64(0x90befffa,0x23631e28, 0xa4506ceb,0xde82bde9)
+WORD64(0xbef9a3f7,0xb2c67915, 0xc67178f2,0xe372532b)
+WORD64(0xca273ece,0xea26619c, 0xd186b8c7,0x21c0c207)
+WORD64(0xeada7dd6,0xcde0eb1e, 0xf57d4f7f,0xee6ed178)
+WORD64(0x06f067aa,0x72176fba, 0x0a637dc5,0xa2c898a6)
+WORD64(0x113f9804,0xbef90dae, 0x1b710b35,0x131c471b)
+WORD64(0x28db77f5,0x23047d84, 0x32caab7b,0x40c72493)
+WORD64(0x3c9ebe0a,0x15c9bebc, 0x431d67c4,0x9c100d4c)
+WORD64(0x4cc5d4be,0xcb3e42b6, 0x597f299c,0xfc657e2a)
+WORD64(0x5fcb6fab,0x3ad6faec, 0x6c44198c,0x4a475817)
+.size K512,.-K512
+.LOPENSSL_armcap:
+.word OPENSSL_armcap_P-sha512_block_data_order
+.skip 32-4
+
+.global sha512_block_data_order
+.type sha512_block_data_order,%function
+sha512_block_data_order:
+ sub r3,pc,#8 @ sha512_block_data_order
+ add $len,$inp,$len,lsl#7 @ len to point at the end of inp
+#if __ARM_ARCH__>=7
+ ldr r12,.LOPENSSL_armcap
+ ldr r12,[r3,r12] @ OPENSSL_armcap_P
+ tst r12,#1
+ bne .LNEON
+#endif
+ stmdb sp!,{r4-r12,lr}
+ sub $Ktbl,r3,#672 @ K512
+ sub sp,sp,#9*8
+
+ ldr $Elo,[$ctx,#$Eoff+$lo]
+ ldr $Ehi,[$ctx,#$Eoff+$hi]
+ ldr $t0, [$ctx,#$Goff+$lo]
+ ldr $t1, [$ctx,#$Goff+$hi]
+ ldr $t2, [$ctx,#$Hoff+$lo]
+ ldr $t3, [$ctx,#$Hoff+$hi]
+.Loop:
+ str $t0, [sp,#$Goff+0]
+ str $t1, [sp,#$Goff+4]
+ str $t2, [sp,#$Hoff+0]
+ str $t3, [sp,#$Hoff+4]
+ ldr $Alo,[$ctx,#$Aoff+$lo]
+ ldr $Ahi,[$ctx,#$Aoff+$hi]
+ ldr $Tlo,[$ctx,#$Boff+$lo]
+ ldr $Thi,[$ctx,#$Boff+$hi]
+ ldr $t0, [$ctx,#$Coff+$lo]
+ ldr $t1, [$ctx,#$Coff+$hi]
+ ldr $t2, [$ctx,#$Doff+$lo]
+ ldr $t3, [$ctx,#$Doff+$hi]
+ str $Tlo,[sp,#$Boff+0]
+ str $Thi,[sp,#$Boff+4]
+ str $t0, [sp,#$Coff+0]
+ str $t1, [sp,#$Coff+4]
+ str $t2, [sp,#$Doff+0]
+ str $t3, [sp,#$Doff+4]
+ ldr $Tlo,[$ctx,#$Foff+$lo]
+ ldr $Thi,[$ctx,#$Foff+$hi]
+ str $Tlo,[sp,#$Foff+0]
+ str $Thi,[sp,#$Foff+4]
+
+.L00_15:
+#if __ARM_ARCH__<7
+ ldrb $Tlo,[$inp,#7]
+ ldrb $t0, [$inp,#6]
+ ldrb $t1, [$inp,#5]
+ ldrb $t2, [$inp,#4]
+ ldrb $Thi,[$inp,#3]
+ ldrb $t3, [$inp,#2]
+ orr $Tlo,$Tlo,$t0,lsl#8
+ ldrb $t0, [$inp,#1]
+ orr $Tlo,$Tlo,$t1,lsl#16
+ ldrb $t1, [$inp],#8
+ orr $Tlo,$Tlo,$t2,lsl#24
+ orr $Thi,$Thi,$t3,lsl#8
+ orr $Thi,$Thi,$t0,lsl#16
+ orr $Thi,$Thi,$t1,lsl#24
+#else
+ ldr $Tlo,[$inp,#4]
+ ldr $Thi,[$inp],#8
+#ifdef __ARMEL__
+ rev $Tlo,$Tlo
+ rev $Thi,$Thi
+#endif
+#endif
+___
+ &BODY_00_15(0x94);
+$code.=<<___;
+ tst $Ktbl,#1
+ beq .L00_15
+ ldr $t0,[sp,#`$Xoff+8*(16-1)`+0]
+ ldr $t1,[sp,#`$Xoff+8*(16-1)`+4]
+ bic $Ktbl,$Ktbl,#1
+.L16_79:
+ @ sigma0(x) (ROTR((x),1) ^ ROTR((x),8) ^ ((x)>>7))
+ @ LO lo>>1^hi<<31 ^ lo>>8^hi<<24 ^ lo>>7^hi<<25
+ @ HI hi>>1^lo<<31 ^ hi>>8^lo<<24 ^ hi>>7
+ mov $Tlo,$t0,lsr#1
+ ldr $t2,[sp,#`$Xoff+8*(16-14)`+0]
+ mov $Thi,$t1,lsr#1
+ ldr $t3,[sp,#`$Xoff+8*(16-14)`+4]
+ eor $Tlo,$Tlo,$t1,lsl#31
+ eor $Thi,$Thi,$t0,lsl#31
+ eor $Tlo,$Tlo,$t0,lsr#8
+ eor $Thi,$Thi,$t1,lsr#8
+ eor $Tlo,$Tlo,$t1,lsl#24
+ eor $Thi,$Thi,$t0,lsl#24
+ eor $Tlo,$Tlo,$t0,lsr#7
+ eor $Thi,$Thi,$t1,lsr#7
+ eor $Tlo,$Tlo,$t1,lsl#25
+
+ @ sigma1(x) (ROTR((x),19) ^ ROTR((x),61) ^ ((x)>>6))
+ @ LO lo>>19^hi<<13 ^ hi>>29^lo<<3 ^ lo>>6^hi<<26
+ @ HI hi>>19^lo<<13 ^ lo>>29^hi<<3 ^ hi>>6
+ mov $t0,$t2,lsr#19
+ mov $t1,$t3,lsr#19
+ eor $t0,$t0,$t3,lsl#13
+ eor $t1,$t1,$t2,lsl#13
+ eor $t0,$t0,$t3,lsr#29
+ eor $t1,$t1,$t2,lsr#29
+ eor $t0,$t0,$t2,lsl#3
+ eor $t1,$t1,$t3,lsl#3
+ eor $t0,$t0,$t2,lsr#6
+ eor $t1,$t1,$t3,lsr#6
+ ldr $t2,[sp,#`$Xoff+8*(16-9)`+0]
+ eor $t0,$t0,$t3,lsl#26
+
+ ldr $t3,[sp,#`$Xoff+8*(16-9)`+4]
+ adds $Tlo,$Tlo,$t0
+ ldr $t0,[sp,#`$Xoff+8*16`+0]
+ adc $Thi,$Thi,$t1
+
+ ldr $t1,[sp,#`$Xoff+8*16`+4]
+ adds $Tlo,$Tlo,$t2
+ adc $Thi,$Thi,$t3
+ adds $Tlo,$Tlo,$t0
+ adc $Thi,$Thi,$t1
+___
+ &BODY_00_15(0x17);
+$code.=<<___;
+ ldreq $t0,[sp,#`$Xoff+8*(16-1)`+0]
+ ldreq $t1,[sp,#`$Xoff+8*(16-1)`+4]
+ beq .L16_79
+ bic $Ktbl,$Ktbl,#1
+
+ ldr $Tlo,[sp,#$Boff+0]
+ ldr $Thi,[sp,#$Boff+4]
+ ldr $t0, [$ctx,#$Aoff+$lo]
+ ldr $t1, [$ctx,#$Aoff+$hi]
+ ldr $t2, [$ctx,#$Boff+$lo]
+ ldr $t3, [$ctx,#$Boff+$hi]
+ adds $t0,$Alo,$t0
+ str $t0, [$ctx,#$Aoff+$lo]
+ adc $t1,$Ahi,$t1
+ str $t1, [$ctx,#$Aoff+$hi]
+ adds $t2,$Tlo,$t2
+ str $t2, [$ctx,#$Boff+$lo]
+ adc $t3,$Thi,$t3
+ str $t3, [$ctx,#$Boff+$hi]
+
+ ldr $Alo,[sp,#$Coff+0]
+ ldr $Ahi,[sp,#$Coff+4]
+ ldr $Tlo,[sp,#$Doff+0]
+ ldr $Thi,[sp,#$Doff+4]
+ ldr $t0, [$ctx,#$Coff+$lo]
+ ldr $t1, [$ctx,#$Coff+$hi]
+ ldr $t2, [$ctx,#$Doff+$lo]
+ ldr $t3, [$ctx,#$Doff+$hi]
+ adds $t0,$Alo,$t0
+ str $t0, [$ctx,#$Coff+$lo]
+ adc $t1,$Ahi,$t1
+ str $t1, [$ctx,#$Coff+$hi]
+ adds $t2,$Tlo,$t2
+ str $t2, [$ctx,#$Doff+$lo]
+ adc $t3,$Thi,$t3
+ str $t3, [$ctx,#$Doff+$hi]
+
+ ldr $Tlo,[sp,#$Foff+0]
+ ldr $Thi,[sp,#$Foff+4]
+ ldr $t0, [$ctx,#$Eoff+$lo]
+ ldr $t1, [$ctx,#$Eoff+$hi]
+ ldr $t2, [$ctx,#$Foff+$lo]
+ ldr $t3, [$ctx,#$Foff+$hi]
+ adds $Elo,$Elo,$t0
+ str $Elo,[$ctx,#$Eoff+$lo]
+ adc $Ehi,$Ehi,$t1
+ str $Ehi,[$ctx,#$Eoff+$hi]
+ adds $t2,$Tlo,$t2
+ str $t2, [$ctx,#$Foff+$lo]
+ adc $t3,$Thi,$t3
+ str $t3, [$ctx,#$Foff+$hi]
+
+ ldr $Alo,[sp,#$Goff+0]
+ ldr $Ahi,[sp,#$Goff+4]
+ ldr $Tlo,[sp,#$Hoff+0]
+ ldr $Thi,[sp,#$Hoff+4]
+ ldr $t0, [$ctx,#$Goff+$lo]
+ ldr $t1, [$ctx,#$Goff+$hi]
+ ldr $t2, [$ctx,#$Hoff+$lo]
+ ldr $t3, [$ctx,#$Hoff+$hi]
+ adds $t0,$Alo,$t0
+ str $t0, [$ctx,#$Goff+$lo]
+ adc $t1,$Ahi,$t1
+ str $t1, [$ctx,#$Goff+$hi]
+ adds $t2,$Tlo,$t2
+ str $t2, [$ctx,#$Hoff+$lo]
+ adc $t3,$Thi,$t3
+ str $t3, [$ctx,#$Hoff+$hi]
+
+ add sp,sp,#640
+ sub $Ktbl,$Ktbl,#640
+
+ teq $inp,$len
+ bne .Loop
+
+ add sp,sp,#8*9 @ destroy frame
+#if __ARM_ARCH__>=5
+ ldmia sp!,{r4-r12,pc}
+#else
+ ldmia sp!,{r4-r12,lr}
+ tst lr,#1
+ moveq pc,lr @ be binary compatible with V4, yet
+ bx lr @ interoperable with Thumb ISA:-)
+#endif
+___
+
+{
+my @Sigma0=(28,34,39);
+my @Sigma1=(14,18,41);
+my @sigma0=(1, 8, 7);
+my @sigma1=(19,61,6);
+
+my $Ktbl="r3";
+my $cnt="r12"; # volatile register known as ip, intra-procedure-call scratch
+
+my @X=map("d$_",(0..15));
+my @V=($A,$B,$C,$D,$E,$F,$G,$H)=map("d$_",(16..23));
+
+sub NEON_00_15() {
+my $i=shift;
+my ($a,$b,$c,$d,$e,$f,$g,$h)=@_;
+my ($t0,$t1,$t2,$T1,$K,$Ch,$Maj)=map("d$_",(24..31)); # temps
+
+$code.=<<___ if ($i<16 || $i&1);
+ vshr.u64 $t0,$e,#@Sigma1[0] @ $i
+#if $i<16
+ vld1.64 {@X[$i%16]},[$inp]! @ handles unaligned
+#endif
+ vshr.u64 $t1,$e,#@Sigma1[1]
+#if $i>0
+ vadd.i64 $a,$Maj @ h+=Maj from the past
+#endif
+ vshr.u64 $t2,$e,#@Sigma1[2]
+___
+$code.=<<___;
+ vld1.64 {$K},[$Ktbl,:64]! @ K[i++]
+ vsli.64 $t0,$e,#`64-@Sigma1[0]`
+ vsli.64 $t1,$e,#`64-@Sigma1[1]`
+ vmov $Ch,$e
+ vsli.64 $t2,$e,#`64-@Sigma1[2]`
+#if $i<16 && defined(__ARMEL__)
+ vrev64.8 @X[$i],@X[$i]
+#endif
+ veor $t1,$t0
+ vbsl $Ch,$f,$g @ Ch(e,f,g)
+ vshr.u64 $t0,$a,#@Sigma0[0]
+ veor $t2,$t1 @ Sigma1(e)
+ vadd.i64 $T1,$Ch,$h
+ vshr.u64 $t1,$a,#@Sigma0[1]
+ vsli.64 $t0,$a,#`64-@Sigma0[0]`
+ vadd.i64 $T1,$t2
+ vshr.u64 $t2,$a,#@Sigma0[2]
+ vadd.i64 $K,@X[$i%16]
+ vsli.64 $t1,$a,#`64-@Sigma0[1]`
+ veor $Maj,$a,$b
+ vsli.64 $t2,$a,#`64-@Sigma0[2]`
+ veor $h,$t0,$t1
+ vadd.i64 $T1,$K
+ vbsl $Maj,$c,$b @ Maj(a,b,c)
+ veor $h,$t2 @ Sigma0(a)
+ vadd.i64 $d,$T1
+ vadd.i64 $Maj,$T1
+ @ vadd.i64 $h,$Maj
+___
+}
+
+sub NEON_16_79() {
+my $i=shift;
+
+if ($i&1) { &NEON_00_15($i,@_); return; }
+
+# 2x-vectorized, therefore runs every 2nd round
+my @X=map("q$_",(0..7)); # view @X as 128-bit vector
+my ($t0,$t1,$s0,$s1) = map("q$_",(12..15)); # temps
+my ($d0,$d1,$d2) = map("d$_",(24..26)); # temps from NEON_00_15
+my $e=@_[4]; # $e from NEON_00_15
+$i /= 2;
+$code.=<<___;
+ vshr.u64 $t0,@X[($i+7)%8],#@sigma1[0]
+ vshr.u64 $t1,@X[($i+7)%8],#@sigma1[1]
+ vadd.i64 @_[0],d30 @ h+=Maj from the past
+ vshr.u64 $s1,@X[($i+7)%8],#@sigma1[2]
+ vsli.64 $t0,@X[($i+7)%8],#`64-@sigma1[0]`
+ vext.8 $s0,@X[$i%8],@X[($i+1)%8],#8 @ X[i+1]
+ vsli.64 $t1,@X[($i+7)%8],#`64-@sigma1[1]`
+ veor $s1,$t0
+ vshr.u64 $t0,$s0,#@sigma0[0]
+ veor $s1,$t1 @ sigma1(X[i+14])
+ vshr.u64 $t1,$s0,#@sigma0[1]
+ vadd.i64 @X[$i%8],$s1
+ vshr.u64 $s1,$s0,#@sigma0[2]
+ vsli.64 $t0,$s0,#`64-@sigma0[0]`
+ vsli.64 $t1,$s0,#`64-@sigma0[1]`
+ vext.8 $s0,@X[($i+4)%8],@X[($i+5)%8],#8 @ X[i+9]
+ veor $s1,$t0
+ vshr.u64 $d0,$e,#@Sigma1[0] @ from NEON_00_15
+ vadd.i64 @X[$i%8],$s0
+ vshr.u64 $d1,$e,#@Sigma1[1] @ from NEON_00_15
+ veor $s1,$t1 @ sigma0(X[i+1])
+ vshr.u64 $d2,$e,#@Sigma1[2] @ from NEON_00_15
+ vadd.i64 @X[$i%8],$s1
+___
+ &NEON_00_15(2*$i,@_);
+}
+
+$code.=<<___;
+#if __ARM_ARCH__>=7
+.fpu neon
+
+.align 4
+.LNEON:
+ dmb @ errata #451034 on early Cortex A8
+ vstmdb sp!,{d8-d15} @ ABI specification says so
+ sub $Ktbl,r3,#672 @ K512
+ vldmia $ctx,{$A-$H} @ load context
+.Loop_neon:
+___
+for($i=0;$i<16;$i++) { &NEON_00_15($i,@V); unshift(@V,pop(@V)); }
+$code.=<<___;
+ mov $cnt,#4
+.L16_79_neon:
+ subs $cnt,#1
+___
+for(;$i<32;$i++) { &NEON_16_79($i,@V); unshift(@V,pop(@V)); }
+$code.=<<___;
+ bne .L16_79_neon
+
+ vadd.i64 $A,d30 @ h+=Maj from the past
+ vldmia $ctx,{d24-d31} @ load context to temp
+ vadd.i64 q8,q12 @ vectorized accumulate
+ vadd.i64 q9,q13
+ vadd.i64 q10,q14
+ vadd.i64 q11,q15
+ vstmia $ctx,{$A-$H} @ save context
+ teq $inp,$len
+ sub $Ktbl,#640 @ rewind K512
+ bne .Loop_neon
+
+ vldmia sp!,{d8-d15} @ epilogue
+ bx lr
+#endif
+___
+}
+$code.=<<___;
+.size sha512_block_data_order,.-sha512_block_data_order
+.asciz "SHA512 block transform for ARMv4/NEON, CRYPTOGAMS by <appro\@openssl.org>"
+.align 2
+.comm OPENSSL_armcap_P,4,4
+
+#endif
+___
+
+$code =~ s/\`([^\`]*)\`/eval $1/gem;
+$code =~ s/\bbx\s+lr\b/.word\t0xe12fff1e/gm; # make it possible to compile with -march=armv4
+print $code;
+close STDOUT; # enforce flush
diff --git a/crypto/sha/asm/sha512-x86_64.pl b/crypto/sha/asm/sha512-x86_64.pl
new file mode 100644
index 0000000..0c1285f
--- /dev/null
+++ b/crypto/sha/asm/sha512-x86_64.pl
@@ -0,0 +1,2152 @@
+#!/usr/bin/env perl
+#
+# ====================================================================
+# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+# project. Rights for redistribution and usage in source and binary
+# forms are granted according to the OpenSSL license.
+# ====================================================================
+#
+# sha256/512_block procedure for x86_64.
+#
+# 40% improvement over compiler-generated code on Opteron. On EM64T
+# sha256 was observed to run >80% faster and sha512 - >40%. No magical
+# tricks, just straight implementation... I really wonder why gcc
+# [being armed with inline assembler] fails to generate as fast code.
+# The only thing which is cool about this module is that it's very
+# same instruction sequence used for both SHA-256 and SHA-512. In
+# former case the instructions operate on 32-bit operands, while in
+# latter - on 64-bit ones. All I had to do is to get one flavor right,
+# the other one passed the test right away:-)
+#
+# sha256_block runs in ~1005 cycles on Opteron, which gives you
+# asymptotic performance of 64*1000/1005=63.7MBps times CPU clock
+# frequency in GHz. sha512_block runs in ~1275 cycles, which results
+# in 128*1000/1275=100MBps per GHz. Is there room for improvement?
+# Well, if you compare it to IA-64 implementation, which maintains
+# X[16] in register bank[!], tends to 4 instructions per CPU clock
+# cycle and runs in 1003 cycles, 1275 is very good result for 3-way
+# issue Opteron pipeline and X[16] maintained in memory. So that *if*
+# there is a way to improve it, *then* the only way would be to try to
+# offload X[16] updates to SSE unit, but that would require "deeper"
+# loop unroll, which in turn would naturally cause size blow-up, not
+# to mention increased complexity! And once again, only *if* it's
+# actually possible to noticeably improve overall ILP, instruction
+# level parallelism, on a given CPU implementation in this case.
+#
+# Special note on Intel EM64T. While Opteron CPU exhibits perfect
+# perfromance ratio of 1.5 between 64- and 32-bit flavors [see above],
+# [currently available] EM64T CPUs apparently are far from it. On the
+# contrary, 64-bit version, sha512_block, is ~30% *slower* than 32-bit
+# sha256_block:-( This is presumably because 64-bit shifts/rotates
+# apparently are not atomic instructions, but implemented in microcode.
+#
+# May 2012.
+#
+# Optimization including one of Pavel Semjanov's ideas, alternative
+# Maj, resulted in >=5% improvement on most CPUs, +20% SHA256 and
+# unfortunately -2% SHA512 on P4 [which nobody should care about
+# that much].
+#
+# June 2012.
+#
+# Add SIMD code paths, see below for improvement coefficients. SSSE3
+# code path was not attempted for SHA512, because improvement is not
+# estimated to be high enough, noticeably less than 9%, to justify
+# the effort, not on pre-AVX processors. [Obviously with exclusion
+# for VIA Nano, but it has SHA512 instruction that is faster and
+# should be used instead.] For reference, corresponding estimated
+# upper limit for improvement for SSSE3 SHA256 is 28%. The fact that
+# higher coefficients are observed on VIA Nano and Bulldozer has more
+# to do with specifics of their architecture [which is topic for
+# separate discussion].
+#
+# November 2012.
+#
+# Add AVX2 code path. Two consecutive input blocks are loaded to
+# 256-bit %ymm registers, with data from first block to least
+# significant 128-bit halves and data from second to most significant.
+# The data is then processed with same SIMD instruction sequence as
+# for AVX, but with %ymm as operands. Side effect is increased stack
+# frame, 448 additional bytes in SHA256 and 1152 in SHA512.
+
+######################################################################
+# Current performance in cycles per processed byte (less is better):
+#
+# SHA256 SSSE3 AVX/XOP(*) SHA512 AVX/XOP(*)
+#
+# AMD K8 14.9 - - 9.57 -
+# P4 17.3 - - 30.8 -
+# Core 2 15.6 13.8(+13%) - 9.97 -
+# Westmere 14.8 12.3(+19%) - 9.58 -
+# Sandy Bridge 17.4 14.2(+23%) 11.6(+50%(**)) 11.2 8.10(+38%(**))
+# Ivy Bridge 12.6 10.5(+20%) 10.3(+22%) 8.17 7.22(+13%)
+# Haswell 12.2 9.28(+31%) 7.80(+56%) 7.66 5.40(+42%)
+# Bulldozer 21.1 13.6(+54%) 13.6(+54%(***)) 13.5 8.58(+57%)
+# VIA Nano 23.0 16.5(+39%) - 14.7 -
+# Atom 23.0 18.9(+22%) - 14.7 -
+#
+# (*) whichever best applicable;
+# (**) switch from ror to shrd stands for fair share of improvement;
+# (***) execution time is fully determined by remaining integer-only
+# part, body_00_15; reducing the amount of SIMD instructions
+# below certain limit makes no difference/sense; to conserve
+# space SHA256 XOP code path is therefore omitted;
+
+$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";
+
+if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
+ =~ /GNU assembler version ([2-9]\.[0-9]+)/) {
+ $avx = ($1>=2.19) + ($1>=2.22);
+}
+
+if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
+ `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
+ $avx = ($1>=2.09) + ($1>=2.10);
+}
+
+if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
+ `ml64 2>&1` =~ /Version ([0-9]+)\./) {
+ $avx = ($1>=10) + ($1>=11);
+}
+
+open OUT,"| \"$^X\" $xlate $flavour";
+*STDOUT=*OUT;
+
+if ($output =~ /512/) {
+ $func="sha512_block_data_order";
+ $TABLE="K512";
+ $SZ=8;
+ @ROT=($A,$B,$C,$D,$E,$F,$G,$H)=("%rax","%rbx","%rcx","%rdx",
+ "%r8", "%r9", "%r10","%r11");
+ ($T1,$a0,$a1,$a2,$a3)=("%r12","%r13","%r14","%r15","%rdi");
+ @Sigma0=(28,34,39);
+ @Sigma1=(14,18,41);
+ @sigma0=(1, 8, 7);
+ @sigma1=(19,61, 6);
+ $rounds=80;
+} else {
+ $func="sha256_block_data_order";
+ $TABLE="K256";
+ $SZ=4;
+ @ROT=($A,$B,$C,$D,$E,$F,$G,$H)=("%eax","%ebx","%ecx","%edx",
+ "%r8d","%r9d","%r10d","%r11d");
+ ($T1,$a0,$a1,$a2,$a3)=("%r12d","%r13d","%r14d","%r15d","%edi");
+ @Sigma0=( 2,13,22);
+ @Sigma1=( 6,11,25);
+ @sigma0=( 7,18, 3);
+ @sigma1=(17,19,10);
+ $rounds=64;
+}
+
+$ctx="%rdi"; # 1st arg, zapped by $a3
+$inp="%rsi"; # 2nd arg
+$Tbl="%rbp";
+
+$_ctx="16*$SZ+0*8(%rsp)";
+$_inp="16*$SZ+1*8(%rsp)";
+$_end="16*$SZ+2*8(%rsp)";
+$_rsp="16*$SZ+3*8(%rsp)";
+$framesz="16*$SZ+4*8";
+
+
+sub ROUND_00_15()
+{ my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_;
+ my $STRIDE=$SZ;
+ $STRIDE += 16 if ($i%(16/$SZ)==(16/$SZ-1));
+
+$code.=<<___;
+ ror \$`$Sigma1[2]-$Sigma1[1]`,$a0
+ mov $f,$a2
+
+ xor $e,$a0
+ ror \$`$Sigma0[2]-$Sigma0[1]`,$a1
+ xor $g,$a2 # f^g
+
+ mov $T1,`$SZ*($i&0xf)`(%rsp)
+ xor $a,$a1
+ and $e,$a2 # (f^g)&e
+
+ ror \$`$Sigma1[1]-$Sigma1[0]`,$a0
+ add $h,$T1 # T1+=h
+ xor $g,$a2 # Ch(e,f,g)=((f^g)&e)^g
+
+ ror \$`$Sigma0[1]-$Sigma0[0]`,$a1
+ xor $e,$a0
+ add $a2,$T1 # T1+=Ch(e,f,g)
+
+ mov $a,$a2
+ add ($Tbl),$T1 # T1+=K[round]
+ xor $a,$a1
+
+ xor $b,$a2 # a^b, b^c in next round
+ ror \$$Sigma1[0],$a0 # Sigma1(e)
+ mov $b,$h
+
+ and $a2,$a3
+ ror \$$Sigma0[0],$a1 # Sigma0(a)
+ add $a0,$T1 # T1+=Sigma1(e)
+
+ xor $a3,$h # h=Maj(a,b,c)=Ch(a^b,c,b)
+ add $T1,$d # d+=T1
+ add $T1,$h # h+=T1
+
+ lea $STRIDE($Tbl),$Tbl # round++
+___
+$code.=<<___ if ($i<15);
+ add $a1,$h # h+=Sigma0(a)
+___
+ ($a2,$a3) = ($a3,$a2);
+}
+
+sub ROUND_16_XX()
+{ my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_;
+
+$code.=<<___;
+ mov `$SZ*(($i+1)&0xf)`(%rsp),$a0
+ mov `$SZ*(($i+14)&0xf)`(%rsp),$a2
+
+ mov $a0,$T1
+ ror \$`$sigma0[1]-$sigma0[0]`,$a0
+ add $a1,$a # modulo-scheduled h+=Sigma0(a)
+ mov $a2,$a1
+ ror \$`$sigma1[1]-$sigma1[0]`,$a2
+
+ xor $T1,$a0
+ shr \$$sigma0[2],$T1
+ ror \$$sigma0[0],$a0
+ xor $a1,$a2
+ shr \$$sigma1[2],$a1
+
+ ror \$$sigma1[0],$a2
+ xor $a0,$T1 # sigma0(X[(i+1)&0xf])
+ xor $a1,$a2 # sigma1(X[(i+14)&0xf])
+ add `$SZ*(($i+9)&0xf)`(%rsp),$T1
+
+ add `$SZ*($i&0xf)`(%rsp),$T1
+ mov $e,$a0
+ add $a2,$T1
+ mov $a,$a1
+___
+ &ROUND_00_15(@_);
+}
+
+$code=<<___;
+.text
+
+.extern OPENSSL_ia32cap_P
+.globl $func
+.type $func,\@function,3
+.align 16
+$func:
+___
+$code.=<<___ if ($SZ==4 || $avx);
+ lea OPENSSL_ia32cap_P(%rip),%r11
+ mov 0(%r11),%r9d
+ mov 4(%r11),%r10d
+ mov 8(%r11),%r11d
+___
+$code.=<<___ if ($avx && $SZ==8);
+ test \$`1<<11`,%r10d # check for XOP
+ jnz .Lxop_shortcut
+___
+$code.=<<___ if ($avx>1);
+ and \$`1<<8|1<<5|1<<3`,%r11d # check for BMI2+AVX2+BMI1
+ cmp \$`1<<8|1<<5|1<<3`,%r11d
+ je .Lavx2_shortcut
+___
+$code.=<<___ if ($avx);
+ and \$`1<<30`,%r9d # mask "Intel CPU" bit
+ and \$`1<<28|1<<9`,%r10d # mask AVX and SSSE3 bits
+ or %r9d,%r10d
+ cmp \$`1<<28|1<<9|1<<30`,%r10d
+ je .Lavx_shortcut
+___
+$code.=<<___ if ($SZ==4);
+ test \$`1<<9`,%r10d
+ jnz .Lssse3_shortcut
+___
+$code.=<<___;
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ mov %rsp,%r11 # copy %rsp
+ shl \$4,%rdx # num*16
+ sub \$$framesz,%rsp
+ lea ($inp,%rdx,$SZ),%rdx # inp+num*16*$SZ
+ and \$-64,%rsp # align stack frame
+ mov $ctx,$_ctx # save ctx, 1st arg
+ mov $inp,$_inp # save inp, 2nd arh
+ mov %rdx,$_end # save end pointer, "3rd" arg
+ mov %r11,$_rsp # save copy of %rsp
+.Lprologue:
+
+ mov $SZ*0($ctx),$A
+ mov $SZ*1($ctx),$B
+ mov $SZ*2($ctx),$C
+ mov $SZ*3($ctx),$D
+ mov $SZ*4($ctx),$E
+ mov $SZ*5($ctx),$F
+ mov $SZ*6($ctx),$G
+ mov $SZ*7($ctx),$H
+ jmp .Lloop
+
+.align 16
+.Lloop:
+ mov $B,$a3
+ lea $TABLE(%rip),$Tbl
+ xor $C,$a3 # magic
+___
+ for($i=0;$i<16;$i++) {
+ $code.=" mov $SZ*$i($inp),$T1\n";
+ $code.=" mov @ROT[4],$a0\n";
+ $code.=" mov @ROT[0],$a1\n";
+ $code.=" bswap $T1\n";
+ &ROUND_00_15($i,@ROT);
+ unshift(@ROT,pop(@ROT));
+ }
+$code.=<<___;
+ jmp .Lrounds_16_xx
+.align 16
+.Lrounds_16_xx:
+___
+ for(;$i<32;$i++) {
+ &ROUND_16_XX($i,@ROT);
+ unshift(@ROT,pop(@ROT));
+ }
+
+$code.=<<___;
+ cmpb \$0,`$SZ-1`($Tbl)
+ jnz .Lrounds_16_xx
+
+ mov $_ctx,$ctx
+ add $a1,$A # modulo-scheduled h+=Sigma0(a)
+ lea 16*$SZ($inp),$inp
+
+ add $SZ*0($ctx),$A
+ add $SZ*1($ctx),$B
+ add $SZ*2($ctx),$C
+ add $SZ*3($ctx),$D
+ add $SZ*4($ctx),$E
+ add $SZ*5($ctx),$F
+ add $SZ*6($ctx),$G
+ add $SZ*7($ctx),$H
+
+ cmp $_end,$inp
+
+ mov $A,$SZ*0($ctx)
+ mov $B,$SZ*1($ctx)
+ mov $C,$SZ*2($ctx)
+ mov $D,$SZ*3($ctx)
+ mov $E,$SZ*4($ctx)
+ mov $F,$SZ*5($ctx)
+ mov $G,$SZ*6($ctx)
+ mov $H,$SZ*7($ctx)
+ jb .Lloop
+
+ mov $_rsp,%rsi
+ mov (%rsi),%r15
+ mov 8(%rsi),%r14
+ mov 16(%rsi),%r13
+ mov 24(%rsi),%r12
+ mov 32(%rsi),%rbp
+ mov 40(%rsi),%rbx
+ lea 48(%rsi),%rsp
+.Lepilogue:
+ ret
+.size $func,.-$func
+___
+
+if ($SZ==4) {
+$code.=<<___;
+.align 64
+.type $TABLE,\@object
+$TABLE:
+ .long 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
+ .long 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
+ .long 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
+ .long 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
+ .long 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
+ .long 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
+ .long 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
+ .long 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
+ .long 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
+ .long 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
+ .long 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
+ .long 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
+ .long 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
+ .long 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
+ .long 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
+ .long 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
+ .long 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
+ .long 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
+ .long 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
+ .long 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
+ .long 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
+ .long 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
+ .long 0xd192e819,0xd6990624,0xf40e3585,0x106aa070
+ .long 0xd192e819,0xd6990624,0xf40e3585,0x106aa070
+ .long 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
+ .long 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
+ .long 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
+ .long 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
+ .long 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
+ .long 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
+ .long 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
+ .long 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
+
+ .long 0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f
+ .long 0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f
+ .long 0x03020100,0x0b0a0908,0xffffffff,0xffffffff
+ .long 0x03020100,0x0b0a0908,0xffffffff,0xffffffff
+ .long 0xffffffff,0xffffffff,0x03020100,0x0b0a0908
+ .long 0xffffffff,0xffffffff,0x03020100,0x0b0a0908
+ .asciz "SHA256 block transform for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
+___
+} else {
+$code.=<<___;
+.align 64
+.type $TABLE,\@object
+$TABLE:
+ .quad 0x428a2f98d728ae22,0x7137449123ef65cd
+ .quad 0x428a2f98d728ae22,0x7137449123ef65cd
+ .quad 0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc
+ .quad 0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc
+ .quad 0x3956c25bf348b538,0x59f111f1b605d019
+ .quad 0x3956c25bf348b538,0x59f111f1b605d019
+ .quad 0x923f82a4af194f9b,0xab1c5ed5da6d8118
+ .quad 0x923f82a4af194f9b,0xab1c5ed5da6d8118
+ .quad 0xd807aa98a3030242,0x12835b0145706fbe
+ .quad 0xd807aa98a3030242,0x12835b0145706fbe
+ .quad 0x243185be4ee4b28c,0x550c7dc3d5ffb4e2
+ .quad 0x243185be4ee4b28c,0x550c7dc3d5ffb4e2
+ .quad 0x72be5d74f27b896f,0x80deb1fe3b1696b1
+ .quad 0x72be5d74f27b896f,0x80deb1fe3b1696b1
+ .quad 0x9bdc06a725c71235,0xc19bf174cf692694
+ .quad 0x9bdc06a725c71235,0xc19bf174cf692694
+ .quad 0xe49b69c19ef14ad2,0xefbe4786384f25e3
+ .quad 0xe49b69c19ef14ad2,0xefbe4786384f25e3
+ .quad 0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65
+ .quad 0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65
+ .quad 0x2de92c6f592b0275,0x4a7484aa6ea6e483
+ .quad 0x2de92c6f592b0275,0x4a7484aa6ea6e483
+ .quad 0x5cb0a9dcbd41fbd4,0x76f988da831153b5
+ .quad 0x5cb0a9dcbd41fbd4,0x76f988da831153b5
+ .quad 0x983e5152ee66dfab,0xa831c66d2db43210
+ .quad 0x983e5152ee66dfab,0xa831c66d2db43210
+ .quad 0xb00327c898fb213f,0xbf597fc7beef0ee4
+ .quad 0xb00327c898fb213f,0xbf597fc7beef0ee4
+ .quad 0xc6e00bf33da88fc2,0xd5a79147930aa725
+ .quad 0xc6e00bf33da88fc2,0xd5a79147930aa725
+ .quad 0x06ca6351e003826f,0x142929670a0e6e70
+ .quad 0x06ca6351e003826f,0x142929670a0e6e70
+ .quad 0x27b70a8546d22ffc,0x2e1b21385c26c926
+ .quad 0x27b70a8546d22ffc,0x2e1b21385c26c926
+ .quad 0x4d2c6dfc5ac42aed,0x53380d139d95b3df
+ .quad 0x4d2c6dfc5ac42aed,0x53380d139d95b3df
+ .quad 0x650a73548baf63de,0x766a0abb3c77b2a8
+ .quad 0x650a73548baf63de,0x766a0abb3c77b2a8
+ .quad 0x81c2c92e47edaee6,0x92722c851482353b
+ .quad 0x81c2c92e47edaee6,0x92722c851482353b
+ .quad 0xa2bfe8a14cf10364,0xa81a664bbc423001
+ .quad 0xa2bfe8a14cf10364,0xa81a664bbc423001
+ .quad 0xc24b8b70d0f89791,0xc76c51a30654be30
+ .quad 0xc24b8b70d0f89791,0xc76c51a30654be30
+ .quad 0xd192e819d6ef5218,0xd69906245565a910
+ .quad 0xd192e819d6ef5218,0xd69906245565a910
+ .quad 0xf40e35855771202a,0x106aa07032bbd1b8
+ .quad 0xf40e35855771202a,0x106aa07032bbd1b8
+ .quad 0x19a4c116b8d2d0c8,0x1e376c085141ab53
+ .quad 0x19a4c116b8d2d0c8,0x1e376c085141ab53
+ .quad 0x2748774cdf8eeb99,0x34b0bcb5e19b48a8
+ .quad 0x2748774cdf8eeb99,0x34b0bcb5e19b48a8
+ .quad 0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb
+ .quad 0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb
+ .quad 0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3
+ .quad 0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3
+ .quad 0x748f82ee5defb2fc,0x78a5636f43172f60
+ .quad 0x748f82ee5defb2fc,0x78a5636f43172f60
+ .quad 0x84c87814a1f0ab72,0x8cc702081a6439ec
+ .quad 0x84c87814a1f0ab72,0x8cc702081a6439ec
+ .quad 0x90befffa23631e28,0xa4506cebde82bde9
+ .quad 0x90befffa23631e28,0xa4506cebde82bde9
+ .quad 0xbef9a3f7b2c67915,0xc67178f2e372532b
+ .quad 0xbef9a3f7b2c67915,0xc67178f2e372532b
+ .quad 0xca273eceea26619c,0xd186b8c721c0c207
+ .quad 0xca273eceea26619c,0xd186b8c721c0c207
+ .quad 0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178
+ .quad 0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178
+ .quad 0x06f067aa72176fba,0x0a637dc5a2c898a6
+ .quad 0x06f067aa72176fba,0x0a637dc5a2c898a6
+ .quad 0x113f9804bef90dae,0x1b710b35131c471b
+ .quad 0x113f9804bef90dae,0x1b710b35131c471b
+ .quad 0x28db77f523047d84,0x32caab7b40c72493
+ .quad 0x28db77f523047d84,0x32caab7b40c72493
+ .quad 0x3c9ebe0a15c9bebc,0x431d67c49c100d4c
+ .quad 0x3c9ebe0a15c9bebc,0x431d67c49c100d4c
+ .quad 0x4cc5d4becb3e42b6,0x597f299cfc657e2a
+ .quad 0x4cc5d4becb3e42b6,0x597f299cfc657e2a
+ .quad 0x5fcb6fab3ad6faec,0x6c44198c4a475817
+ .quad 0x5fcb6fab3ad6faec,0x6c44198c4a475817
+
+ .quad 0x0001020304050607,0x08090a0b0c0d0e0f
+ .quad 0x0001020304050607,0x08090a0b0c0d0e0f
+ .asciz "SHA512 block transform for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
+___
+}
+
+######################################################################
+# SIMD code paths
+#
+{{{
+
+my $a4=$T1;
+my ($a,$b,$c,$d,$e,$f,$g,$h);
+
+sub AUTOLOAD() # thunk [simplified] 32-bit style perlasm
+{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://;
+ my $arg = pop;
+ $arg = "\$$arg" if ($arg*1 eq $arg);
+ $code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n";
+}
+
+sub body_00_15 () {
+ (
+ '($a,$b,$c,$d,$e,$f,$g,$h)=@ROT;'.
+
+ '&ror ($a0,$Sigma1[2]-$Sigma1[1])',
+ '&mov ($a,$a1)',
+ '&mov ($a4,$f)',
+
+ '&ror ($a1,$Sigma0[2]-$Sigma0[1])',
+ '&xor ($a0,$e)',
+ '&xor ($a4,$g)', # f^g
+
+ '&ror ($a0,$Sigma1[1]-$Sigma1[0])',
+ '&xor ($a1,$a)',
+ '&and ($a4,$e)', # (f^g)&e
+
+ '&xor ($a0,$e)',
+ '&add ($h,$SZ*($i&15)."(%rsp)")', # h+=X[i]+K[i]
+ '&mov ($a2,$a)',
+
+ '&xor ($a4,$g)', # Ch(e,f,g)=((f^g)&e)^g
+ '&ror ($a1,$Sigma0[1]-$Sigma0[0])',
+ '&xor ($a2,$b)', # a^b, b^c in next round
+
+ '&add ($h,$a4)', # h+=Ch(e,f,g)
+ '&ror ($a0,$Sigma1[0])', # Sigma1(e)
+ '&and ($a3,$a2)', # (b^c)&(a^b)
+
+ '&xor ($a1,$a)',
+ '&add ($h,$a0)', # h+=Sigma1(e)
+ '&xor ($a3,$b)', # Maj(a,b,c)=Ch(a^b,c,b)
+
+ '&ror ($a1,$Sigma0[0])', # Sigma0(a)
+ '&add ($d,$h)', # d+=h
+ '&add ($h,$a3)', # h+=Maj(a,b,c)
+
+ '&mov ($a0,$d)',
+ '&add ($a1,$h);'. # h+=Sigma0(a)
+ '($a2,$a3) = ($a3,$a2); unshift(@ROT,pop(@ROT)); $i++;'
+ );
+}
+
+######################################################################
+# SSSE3 code path
+#
+if ($SZ==4) { # SHA256 only
+my @X = map("%xmm$_",(0..3));
+my ($t0,$t1,$t2,$t3, $t4,$t5) = map("%xmm$_",(4..9));
+
+$code.=<<___;
+.type ${func}_ssse3,\@function,3
+.align 64
+${func}_ssse3:
+.Lssse3_shortcut:
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ mov %rsp,%r11 # copy %rsp
+ shl \$4,%rdx # num*16
+ sub \$`$framesz+$win64*16*4`,%rsp
+ lea ($inp,%rdx,$SZ),%rdx # inp+num*16*$SZ
+ and \$-64,%rsp # align stack frame
+ mov $ctx,$_ctx # save ctx, 1st arg
+ mov $inp,$_inp # save inp, 2nd arh
+ mov %rdx,$_end # save end pointer, "3rd" arg
+ mov %r11,$_rsp # save copy of %rsp
+___
+$code.=<<___ if ($win64);
+ movaps %xmm6,16*$SZ+32(%rsp)
+ movaps %xmm7,16*$SZ+48(%rsp)
+ movaps %xmm8,16*$SZ+64(%rsp)
+ movaps %xmm9,16*$SZ+80(%rsp)
+___
+$code.=<<___;
+.Lprologue_ssse3:
+
+ mov $SZ*0($ctx),$A
+ mov $SZ*1($ctx),$B
+ mov $SZ*2($ctx),$C
+ mov $SZ*3($ctx),$D
+ mov $SZ*4($ctx),$E
+ mov $SZ*5($ctx),$F
+ mov $SZ*6($ctx),$G
+ mov $SZ*7($ctx),$H
+___
+
+$code.=<<___;
+ #movdqa $TABLE+`$SZ*2*$rounds`+32(%rip),$t4
+ #movdqa $TABLE+`$SZ*2*$rounds`+64(%rip),$t5
+ jmp .Lloop_ssse3
+.align 16
+.Lloop_ssse3:
+ movdqa $TABLE+`$SZ*2*$rounds`(%rip),$t3
+ movdqu 0x00($inp),@X[0]
+ movdqu 0x10($inp),@X[1]
+ movdqu 0x20($inp),@X[2]
+ movdqu 0x30($inp),@X[3]
+ pshufb $t3,@X[0]
+ lea $TABLE(%rip),$Tbl
+ pshufb $t3,@X[1]
+ movdqa 0x00($Tbl),$t0
+ pshufb $t3,@X[2]
+ movdqa 0x20($Tbl),$t1
+ paddd @X[0],$t0
+ movdqa 0x40($Tbl),$t2
+ pshufb $t3,@X[3]
+ movdqa 0x60($Tbl),$t3
+ paddd @X[1],$t1
+ paddd @X[2],$t2
+ paddd @X[3],$t3
+ movdqa $t0,0x00(%rsp)
+ mov $A,$a1
+ movdqa $t1,0x10(%rsp)
+ mov $B,$a3
+ movdqa $t2,0x20(%rsp)
+ xor $C,$a3 # magic
+ movdqa $t3,0x30(%rsp)
+ mov $E,$a0
+ jmp .Lssse3_00_47
+
+.align 16
+.Lssse3_00_47:
+ sub \$-16*2*$SZ,$Tbl # size optimization
+___
+sub Xupdate_256_SSSE3 () {
+ (
+ '&movdqa ($t0,@X[1]);',
+ '&movdqa ($t3,@X[3])',
+ '&palignr ($t0,@X[0],$SZ)', # X[1..4]
+ '&palignr ($t3,@X[2],$SZ);', # X[9..12]
+ '&movdqa ($t1,$t0)',
+ '&movdqa ($t2,$t0);',
+ '&psrld ($t0,$sigma0[2])',
+ '&paddd (@X[0],$t3);', # X[0..3] += X[9..12]
+ '&psrld ($t2,$sigma0[0])',
+ '&pshufd ($t3,@X[3],0b11111010)',# X[14..15]
+ '&pslld ($t1,8*$SZ-$sigma0[1]);'.
+ '&pxor ($t0,$t2)',
+ '&psrld ($t2,$sigma0[1]-$sigma0[0]);'.
+ '&pxor ($t0,$t1)',
+ '&pslld ($t1,$sigma0[1]-$sigma0[0]);'.
+ '&pxor ($t0,$t2);',
+ '&movdqa ($t2,$t3)',
+ '&pxor ($t0,$t1);', # sigma0(X[1..4])
+ '&psrld ($t3,$sigma1[2])',
+ '&paddd (@X[0],$t0);', # X[0..3] += sigma0(X[1..4])
+ '&psrlq ($t2,$sigma1[0])',
+ '&pxor ($t3,$t2);',
+ '&psrlq ($t2,$sigma1[1]-$sigma1[0])',
+ '&pxor ($t3,$t2)',
+ '&pshufb ($t3,$t4)', # sigma1(X[14..15])
+ '&paddd (@X[0],$t3)', # X[0..1] += sigma1(X[14..15])
+ '&pshufd ($t3,@X[0],0b01010000)',# X[16..17]
+ '&movdqa ($t2,$t3);',
+ '&psrld ($t3,$sigma1[2])',
+ '&psrlq ($t2,$sigma1[0])',
+ '&pxor ($t3,$t2);',
+ '&psrlq ($t2,$sigma1[1]-$sigma1[0])',
+ '&pxor ($t3,$t2);',
+ '&movdqa ($t2,16*2*$j."($Tbl)")',
+ '&pshufb ($t3,$t5)',
+ '&paddd (@X[0],$t3)' # X[2..3] += sigma1(X[16..17])
+ );
+}
+
+sub SSSE3_256_00_47 () {
+my $j = shift;
+my $body = shift;
+my @X = @_;
+my @insns = (&$body,&$body,&$body,&$body); # 104 instructions
+
+ if (0) {
+ foreach (Xupdate_256_SSSE3()) { # 36 instructions
+ eval;
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ }
+ } else { # squeeze extra 4% on Westmere and 19% on Atom
+ eval(shift(@insns)); #@
+ &movdqa ($t0,@X[1]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &movdqa ($t3,@X[3]);
+ eval(shift(@insns)); #@
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); #@
+ eval(shift(@insns));
+ &palignr ($t0,@X[0],$SZ); # X[1..4]
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &palignr ($t3,@X[2],$SZ); # X[9..12]
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); #@
+ &movdqa ($t1,$t0);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &movdqa ($t2,$t0);
+ eval(shift(@insns)); #@
+ eval(shift(@insns));
+ &psrld ($t0,$sigma0[2]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &paddd (@X[0],$t3); # X[0..3] += X[9..12]
+ eval(shift(@insns)); #@
+ eval(shift(@insns));
+ &psrld ($t2,$sigma0[0]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &pshufd ($t3,@X[3],0b11111010); # X[4..15]
+ eval(shift(@insns));
+ eval(shift(@insns)); #@
+ &pslld ($t1,8*$SZ-$sigma0[1]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &pxor ($t0,$t2);
+ eval(shift(@insns)); #@
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); #@
+ &psrld ($t2,$sigma0[1]-$sigma0[0]);
+ eval(shift(@insns));
+ &pxor ($t0,$t1);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &pslld ($t1,$sigma0[1]-$sigma0[0]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &pxor ($t0,$t2);
+ eval(shift(@insns));
+ eval(shift(@insns)); #@
+ &movdqa ($t2,$t3);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &pxor ($t0,$t1); # sigma0(X[1..4])
+ eval(shift(@insns)); #@
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &psrld ($t3,$sigma1[2]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &paddd (@X[0],$t0); # X[0..3] += sigma0(X[1..4])
+ eval(shift(@insns)); #@
+ eval(shift(@insns));
+ &psrlq ($t2,$sigma1[0]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &pxor ($t3,$t2);
+ eval(shift(@insns)); #@
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); #@
+ &psrlq ($t2,$sigma1[1]-$sigma1[0]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &pxor ($t3,$t2);
+ eval(shift(@insns)); #@
+ eval(shift(@insns));
+ eval(shift(@insns));
+ #&pshufb ($t3,$t4); # sigma1(X[14..15])
+ &pshufd ($t3,$t3,0b10000000);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &psrldq ($t3,8);
+ eval(shift(@insns));
+ eval(shift(@insns)); #@
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); #@
+ &paddd (@X[0],$t3); # X[0..1] += sigma1(X[14..15])
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &pshufd ($t3,@X[0],0b01010000); # X[16..17]
+ eval(shift(@insns));
+ eval(shift(@insns)); #@
+ eval(shift(@insns));
+ &movdqa ($t2,$t3);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &psrld ($t3,$sigma1[2]);
+ eval(shift(@insns));
+ eval(shift(@insns)); #@
+ &psrlq ($t2,$sigma1[0]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &pxor ($t3,$t2);
+ eval(shift(@insns)); #@
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); #@
+ eval(shift(@insns));
+ &psrlq ($t2,$sigma1[1]-$sigma1[0]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &pxor ($t3,$t2);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns)); #@
+ #&pshufb ($t3,$t5);
+ &pshufd ($t3,$t3,0b00001000);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &movdqa ($t2,16*2*$j."($Tbl)");
+ eval(shift(@insns)); #@
+ eval(shift(@insns));
+ &pslldq ($t3,8);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &paddd (@X[0],$t3); # X[2..3] += sigma1(X[16..17])
+ eval(shift(@insns)); #@
+ eval(shift(@insns));
+ eval(shift(@insns));
+ }
+ &paddd ($t2,@X[0]);
+ foreach (@insns) { eval; } # remaining instructions
+ &movdqa (16*$j."(%rsp)",$t2);
+}
+
+ for ($i=0,$j=0; $j<4; $j++) {
+ &SSSE3_256_00_47($j,\&body_00_15,@X);
+ push(@X,shift(@X)); # rotate(@X)
+ }
+ &cmpb ($SZ-1+16*2*$SZ."($Tbl)",0);
+ &jne (".Lssse3_00_47");
+
+ for ($i=0; $i<16; ) {
+ foreach(body_00_15()) { eval; }
+ }
+$code.=<<___;
+ mov $_ctx,$ctx
+ mov $a1,$A
+
+ add $SZ*0($ctx),$A
+ lea 16*$SZ($inp),$inp
+ add $SZ*1($ctx),$B
+ add $SZ*2($ctx),$C
+ add $SZ*3($ctx),$D
+ add $SZ*4($ctx),$E
+ add $SZ*5($ctx),$F
+ add $SZ*6($ctx),$G
+ add $SZ*7($ctx),$H
+
+ cmp $_end,$inp
+
+ mov $A,$SZ*0($ctx)
+ mov $B,$SZ*1($ctx)
+ mov $C,$SZ*2($ctx)
+ mov $D,$SZ*3($ctx)
+ mov $E,$SZ*4($ctx)
+ mov $F,$SZ*5($ctx)
+ mov $G,$SZ*6($ctx)
+ mov $H,$SZ*7($ctx)
+ jb .Lloop_ssse3
+
+ mov $_rsp,%rsi
+___
+$code.=<<___ if ($win64);
+ movaps 16*$SZ+32(%rsp),%xmm6
+ movaps 16*$SZ+48(%rsp),%xmm7
+ movaps 16*$SZ+64(%rsp),%xmm8
+ movaps 16*$SZ+80(%rsp),%xmm9
+___
+$code.=<<___;
+ mov (%rsi),%r15
+ mov 8(%rsi),%r14
+ mov 16(%rsi),%r13
+ mov 24(%rsi),%r12
+ mov 32(%rsi),%rbp
+ mov 40(%rsi),%rbx
+ lea 48(%rsi),%rsp
+.Lepilogue_ssse3:
+ ret
+.size ${func}_ssse3,.-${func}_ssse3
+___
+}
+
+if ($avx) {{
+######################################################################
+# XOP code path
+#
+if ($SZ==8) { # SHA512 only
+$code.=<<___;
+.type ${func}_xop,\@function,3
+.align 64
+${func}_xop:
+.Lxop_shortcut:
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ mov %rsp,%r11 # copy %rsp
+ shl \$4,%rdx # num*16
+ sub \$`$framesz+$win64*16*($SZ==4?4:6)`,%rsp
+ lea ($inp,%rdx,$SZ),%rdx # inp+num*16*$SZ
+ and \$-64,%rsp # align stack frame
+ mov $ctx,$_ctx # save ctx, 1st arg
+ mov $inp,$_inp # save inp, 2nd arh
+ mov %rdx,$_end # save end pointer, "3rd" arg
+ mov %r11,$_rsp # save copy of %rsp
+___
+$code.=<<___ if ($win64);
+ movaps %xmm6,16*$SZ+32(%rsp)
+ movaps %xmm7,16*$SZ+48(%rsp)
+ movaps %xmm8,16*$SZ+64(%rsp)
+ movaps %xmm9,16*$SZ+80(%rsp)
+___
+$code.=<<___ if ($win64 && $SZ>4);
+ movaps %xmm10,16*$SZ+96(%rsp)
+ movaps %xmm11,16*$SZ+112(%rsp)
+___
+$code.=<<___;
+.Lprologue_xop:
+
+ vzeroupper
+ mov $SZ*0($ctx),$A
+ mov $SZ*1($ctx),$B
+ mov $SZ*2($ctx),$C
+ mov $SZ*3($ctx),$D
+ mov $SZ*4($ctx),$E
+ mov $SZ*5($ctx),$F
+ mov $SZ*6($ctx),$G
+ mov $SZ*7($ctx),$H
+ jmp .Lloop_xop
+___
+ if ($SZ==4) { # SHA256
+ my @X = map("%xmm$_",(0..3));
+ my ($t0,$t1,$t2,$t3) = map("%xmm$_",(4..7));
+
+$code.=<<___;
+.align 16
+.Lloop_xop:
+ vmovdqa $TABLE+`$SZ*2*$rounds`(%rip),$t3
+ vmovdqu 0x00($inp),@X[0]
+ vmovdqu 0x10($inp),@X[1]
+ vmovdqu 0x20($inp),@X[2]
+ vmovdqu 0x30($inp),@X[3]
+ vpshufb $t3,@X[0],@X[0]
+ lea $TABLE(%rip),$Tbl
+ vpshufb $t3,@X[1],@X[1]
+ vpshufb $t3,@X[2],@X[2]
+ vpaddd 0x00($Tbl),@X[0],$t0
+ vpshufb $t3,@X[3],@X[3]
+ vpaddd 0x20($Tbl),@X[1],$t1
+ vpaddd 0x40($Tbl),@X[2],$t2
+ vpaddd 0x60($Tbl),@X[3],$t3
+ vmovdqa $t0,0x00(%rsp)
+ mov $A,$a1
+ vmovdqa $t1,0x10(%rsp)
+ mov $B,$a3
+ vmovdqa $t2,0x20(%rsp)
+ xor $C,$a3 # magic
+ vmovdqa $t3,0x30(%rsp)
+ mov $E,$a0
+ jmp .Lxop_00_47
+
+.align 16
+.Lxop_00_47:
+ sub \$-16*2*$SZ,$Tbl # size optimization
+___
+sub XOP_256_00_47 () {
+my $j = shift;
+my $body = shift;
+my @X = @_;
+my @insns = (&$body,&$body,&$body,&$body); # 104 instructions
+
+ &vpalignr ($t0,@X[1],@X[0],$SZ); # X[1..4]
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpalignr ($t3,@X[3],@X[2],$SZ); # X[9..12]
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vprotd ($t1,$t0,8*$SZ-$sigma0[1]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpsrld ($t0,$t0,$sigma0[2]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpaddd (@X[0],@X[0],$t3); # X[0..3] += X[9..12]
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vprotd ($t2,$t1,$sigma0[1]-$sigma0[0]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpxor ($t0,$t0,$t1);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vprotd ($t3,@X[3],8*$SZ-$sigma1[1]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpxor ($t0,$t0,$t2); # sigma0(X[1..4])
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpsrld ($t2,@X[3],$sigma1[2]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpaddd (@X[0],@X[0],$t0); # X[0..3] += sigma0(X[1..4])
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vprotd ($t1,$t3,$sigma1[1]-$sigma1[0]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpxor ($t3,$t3,$t2);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpxor ($t3,$t3,$t1); # sigma1(X[14..15])
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpsrldq ($t3,$t3,8);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpaddd (@X[0],@X[0],$t3); # X[0..1] += sigma1(X[14..15])
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vprotd ($t3,@X[0],8*$SZ-$sigma1[1]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpsrld ($t2,@X[0],$sigma1[2]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vprotd ($t1,$t3,$sigma1[1]-$sigma1[0]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpxor ($t3,$t3,$t2);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpxor ($t3,$t3,$t1); # sigma1(X[16..17])
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpslldq ($t3,$t3,8); # 22 instructions
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpaddd (@X[0],@X[0],$t3); # X[2..3] += sigma1(X[16..17])
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpaddd ($t2,@X[0],16*2*$j."($Tbl)");
+ foreach (@insns) { eval; } # remaining instructions
+ &vmovdqa (16*$j."(%rsp)",$t2);
+}
+
+ for ($i=0,$j=0; $j<4; $j++) {
+ &XOP_256_00_47($j,\&body_00_15,@X);
+ push(@X,shift(@X)); # rotate(@X)
+ }
+ &cmpb ($SZ-1+16*2*$SZ."($Tbl)",0);
+ &jne (".Lxop_00_47");
+
+ for ($i=0; $i<16; ) {
+ foreach(body_00_15()) { eval; }
+ }
+
+ } else { # SHA512
+ my @X = map("%xmm$_",(0..7));
+ my ($t0,$t1,$t2,$t3) = map("%xmm$_",(8..11));
+
+$code.=<<___;
+.align 16
+.Lloop_xop:
+ vmovdqa $TABLE+`$SZ*2*$rounds`(%rip),$t3
+ vmovdqu 0x00($inp),@X[0]
+ lea $TABLE+0x80(%rip),$Tbl # size optimization
+ vmovdqu 0x10($inp),@X[1]
+ vmovdqu 0x20($inp),@X[2]
+ vpshufb $t3,@X[0],@X[0]
+ vmovdqu 0x30($inp),@X[3]
+ vpshufb $t3,@X[1],@X[1]
+ vmovdqu 0x40($inp),@X[4]
+ vpshufb $t3,@X[2],@X[2]
+ vmovdqu 0x50($inp),@X[5]
+ vpshufb $t3,@X[3],@X[3]
+ vmovdqu 0x60($inp),@X[6]
+ vpshufb $t3,@X[4],@X[4]
+ vmovdqu 0x70($inp),@X[7]
+ vpshufb $t3,@X[5],@X[5]
+ vpaddq -0x80($Tbl),@X[0],$t0
+ vpshufb $t3,@X[6],@X[6]
+ vpaddq -0x60($Tbl),@X[1],$t1
+ vpshufb $t3,@X[7],@X[7]
+ vpaddq -0x40($Tbl),@X[2],$t2
+ vpaddq -0x20($Tbl),@X[3],$t3
+ vmovdqa $t0,0x00(%rsp)
+ vpaddq 0x00($Tbl),@X[4],$t0
+ vmovdqa $t1,0x10(%rsp)
+ vpaddq 0x20($Tbl),@X[5],$t1
+ vmovdqa $t2,0x20(%rsp)
+ vpaddq 0x40($Tbl),@X[6],$t2
+ vmovdqa $t3,0x30(%rsp)
+ vpaddq 0x60($Tbl),@X[7],$t3
+ vmovdqa $t0,0x40(%rsp)
+ mov $A,$a1
+ vmovdqa $t1,0x50(%rsp)
+ mov $B,$a3
+ vmovdqa $t2,0x60(%rsp)
+ xor $C,$a3 # magic
+ vmovdqa $t3,0x70(%rsp)
+ mov $E,$a0
+ jmp .Lxop_00_47
+
+.align 16
+.Lxop_00_47:
+ add \$16*2*$SZ,$Tbl
+___
+sub XOP_512_00_47 () {
+my $j = shift;
+my $body = shift;
+my @X = @_;
+my @insns = (&$body,&$body); # 52 instructions
+
+ &vpalignr ($t0,@X[1],@X[0],$SZ); # X[1..2]
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpalignr ($t3,@X[5],@X[4],$SZ); # X[9..10]
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vprotq ($t1,$t0,8*$SZ-$sigma0[1]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpsrlq ($t0,$t0,$sigma0[2]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpaddq (@X[0],@X[0],$t3); # X[0..1] += X[9..10]
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vprotq ($t2,$t1,$sigma0[1]-$sigma0[0]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpxor ($t0,$t0,$t1);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vprotq ($t3,@X[7],8*$SZ-$sigma1[1]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpxor ($t0,$t0,$t2); # sigma0(X[1..2])
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpsrlq ($t2,@X[7],$sigma1[2]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpaddq (@X[0],@X[0],$t0); # X[0..1] += sigma0(X[1..2])
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vprotq ($t1,$t3,$sigma1[1]-$sigma1[0]);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpxor ($t3,$t3,$t2);
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpxor ($t3,$t3,$t1); # sigma1(X[14..15])
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpaddq (@X[0],@X[0],$t3); # X[0..1] += sigma1(X[14..15])
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ &vpaddq ($t2,@X[0],16*2*$j-0x80."($Tbl)");
+ foreach (@insns) { eval; } # remaining instructions
+ &vmovdqa (16*$j."(%rsp)",$t2);
+}
+
+ for ($i=0,$j=0; $j<8; $j++) {
+ &XOP_512_00_47($j,\&body_00_15,@X);
+ push(@X,shift(@X)); # rotate(@X)
+ }
+ &cmpb ($SZ-1+16*2*$SZ-0x80."($Tbl)",0);
+ &jne (".Lxop_00_47");
+
+ for ($i=0; $i<16; ) {
+ foreach(body_00_15()) { eval; }
+ }
+}
+$code.=<<___;
+ mov $_ctx,$ctx
+ mov $a1,$A
+
+ add $SZ*0($ctx),$A
+ lea 16*$SZ($inp),$inp
+ add $SZ*1($ctx),$B
+ add $SZ*2($ctx),$C
+ add $SZ*3($ctx),$D
+ add $SZ*4($ctx),$E
+ add $SZ*5($ctx),$F
+ add $SZ*6($ctx),$G
+ add $SZ*7($ctx),$H
+
+ cmp $_end,$inp
+
+ mov $A,$SZ*0($ctx)
+ mov $B,$SZ*1($ctx)
+ mov $C,$SZ*2($ctx)
+ mov $D,$SZ*3($ctx)
+ mov $E,$SZ*4($ctx)
+ mov $F,$SZ*5($ctx)
+ mov $G,$SZ*6($ctx)
+ mov $H,$SZ*7($ctx)
+ jb .Lloop_xop
+
+ mov $_rsp,%rsi
+ vzeroupper
+___
+$code.=<<___ if ($win64);
+ movaps 16*$SZ+32(%rsp),%xmm6
+ movaps 16*$SZ+48(%rsp),%xmm7
+ movaps 16*$SZ+64(%rsp),%xmm8
+ movaps 16*$SZ+80(%rsp),%xmm9
+___
+$code.=<<___ if ($win64 && $SZ>4);
+ movaps 16*$SZ+96(%rsp),%xmm10
+ movaps 16*$SZ+112(%rsp),%xmm11
+___
+$code.=<<___;
+ mov (%rsi),%r15
+ mov 8(%rsi),%r14
+ mov 16(%rsi),%r13
+ mov 24(%rsi),%r12
+ mov 32(%rsi),%rbp
+ mov 40(%rsi),%rbx
+ lea 48(%rsi),%rsp
+.Lepilogue_xop:
+ ret
+.size ${func}_xop,.-${func}_xop
+___
+}
+######################################################################
+# AVX+shrd code path
+#
+local *ror = sub { &shrd(@_[0],@_) };
+
+$code.=<<___;
+.type ${func}_avx,\@function,3
+.align 64
+${func}_avx:
+.Lavx_shortcut:
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ mov %rsp,%r11 # copy %rsp
+ shl \$4,%rdx # num*16
+ sub \$`$framesz+$win64*16*($SZ==4?4:6)`,%rsp
+ lea ($inp,%rdx,$SZ),%rdx # inp+num*16*$SZ
+ and \$-64,%rsp # align stack frame
+ mov $ctx,$_ctx # save ctx, 1st arg
+ mov $inp,$_inp # save inp, 2nd arh
+ mov %rdx,$_end # save end pointer, "3rd" arg
+ mov %r11,$_rsp # save copy of %rsp
+___
+$code.=<<___ if ($win64);
+ movaps %xmm6,16*$SZ+32(%rsp)
+ movaps %xmm7,16*$SZ+48(%rsp)
+ movaps %xmm8,16*$SZ+64(%rsp)
+ movaps %xmm9,16*$SZ+80(%rsp)
+___
+$code.=<<___ if ($win64 && $SZ>4);
+ movaps %xmm10,16*$SZ+96(%rsp)
+ movaps %xmm11,16*$SZ+112(%rsp)
+___
+$code.=<<___;
+.Lprologue_avx:
+
+ vzeroupper
+ mov $SZ*0($ctx),$A
+ mov $SZ*1($ctx),$B
+ mov $SZ*2($ctx),$C
+ mov $SZ*3($ctx),$D
+ mov $SZ*4($ctx),$E
+ mov $SZ*5($ctx),$F
+ mov $SZ*6($ctx),$G
+ mov $SZ*7($ctx),$H
+___
+ if ($SZ==4) { # SHA256
+ my @X = map("%xmm$_",(0..3));
+ my ($t0,$t1,$t2,$t3, $t4,$t5) = map("%xmm$_",(4..9));
+
+$code.=<<___;
+ vmovdqa $TABLE+`$SZ*2*$rounds`+32(%rip),$t4
+ vmovdqa $TABLE+`$SZ*2*$rounds`+64(%rip),$t5
+ jmp .Lloop_avx
+.align 16
+.Lloop_avx:
+ vmovdqa $TABLE+`$SZ*2*$rounds`(%rip),$t3
+ vmovdqu 0x00($inp),@X[0]
+ vmovdqu 0x10($inp),@X[1]
+ vmovdqu 0x20($inp),@X[2]
+ vmovdqu 0x30($inp),@X[3]
+ vpshufb $t3,@X[0],@X[0]
+ lea $TABLE(%rip),$Tbl
+ vpshufb $t3,@X[1],@X[1]
+ vpshufb $t3,@X[2],@X[2]
+ vpaddd 0x00($Tbl),@X[0],$t0
+ vpshufb $t3,@X[3],@X[3]
+ vpaddd 0x20($Tbl),@X[1],$t1
+ vpaddd 0x40($Tbl),@X[2],$t2
+ vpaddd 0x60($Tbl),@X[3],$t3
+ vmovdqa $t0,0x00(%rsp)
+ mov $A,$a1
+ vmovdqa $t1,0x10(%rsp)
+ mov $B,$a3
+ vmovdqa $t2,0x20(%rsp)
+ xor $C,$a3 # magic
+ vmovdqa $t3,0x30(%rsp)
+ mov $E,$a0
+ jmp .Lavx_00_47
+
+.align 16
+.Lavx_00_47:
+ sub \$-16*2*$SZ,$Tbl # size optimization
+___
+sub Xupdate_256_AVX () {
+ (
+ '&vpalignr ($t0,@X[1],@X[0],$SZ)', # X[1..4]
+ '&vpalignr ($t3,@X[3],@X[2],$SZ)', # X[9..12]
+ '&vpsrld ($t2,$t0,$sigma0[0]);',
+ '&vpaddd (@X[0],@X[0],$t3)', # X[0..3] += X[9..12]
+ '&vpsrld ($t3,$t0,$sigma0[2])',
+ '&vpslld ($t1,$t0,8*$SZ-$sigma0[1]);',
+ '&vpxor ($t0,$t3,$t2)',
+ '&vpshufd ($t3,@X[3],0b11111010)',# X[14..15]
+ '&vpsrld ($t2,$t2,$sigma0[1]-$sigma0[0]);',
+ '&vpxor ($t0,$t0,$t1)',
+ '&vpslld ($t1,$t1,$sigma0[1]-$sigma0[0]);',
+ '&vpxor ($t0,$t0,$t2)',
+ '&vpsrld ($t2,$t3,$sigma1[2]);',
+ '&vpxor ($t0,$t0,$t1)', # sigma0(X[1..4])
+ '&vpsrlq ($t3,$t3,$sigma1[0]);',
+ '&vpaddd (@X[0],@X[0],$t0)', # X[0..3] += sigma0(X[1..4])
+ '&vpxor ($t2,$t2,$t3);',
+ '&vpsrlq ($t3,$t3,$sigma1[1]-$sigma1[0])',
+ '&vpxor ($t2,$t2,$t3)',
+ '&vpshufb ($t2,$t2,$t4)', # sigma1(X[14..15])
+ '&vpaddd (@X[0],@X[0],$t2)', # X[0..1] += sigma1(X[14..15])
+ '&vpshufd ($t3,@X[0],0b01010000)',# X[16..17]
+ '&vpsrld ($t2,$t3,$sigma1[2])',
+ '&vpsrlq ($t3,$t3,$sigma1[0])',
+ '&vpxor ($t2,$t2,$t3);',
+ '&vpsrlq ($t3,$t3,$sigma1[1]-$sigma1[0])',
+ '&vpxor ($t2,$t2,$t3)',
+ '&vpshufb ($t2,$t2,$t5)',
+ '&vpaddd (@X[0],@X[0],$t2)' # X[2..3] += sigma1(X[16..17])
+ );
+}
+
+sub AVX_256_00_47 () {
+my $j = shift;
+my $body = shift;
+my @X = @_;
+my @insns = (&$body,&$body,&$body,&$body); # 104 instructions
+
+ foreach (Xupdate_256_AVX()) { # 29 instructions
+ eval;
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ }
+ &vpaddd ($t2,@X[0],16*2*$j."($Tbl)");
+ foreach (@insns) { eval; } # remaining instructions
+ &vmovdqa (16*$j."(%rsp)",$t2);
+}
+
+ for ($i=0,$j=0; $j<4; $j++) {
+ &AVX_256_00_47($j,\&body_00_15,@X);
+ push(@X,shift(@X)); # rotate(@X)
+ }
+ &cmpb ($SZ-1+16*2*$SZ."($Tbl)",0);
+ &jne (".Lavx_00_47");
+
+ for ($i=0; $i<16; ) {
+ foreach(body_00_15()) { eval; }
+ }
+
+ } else { # SHA512
+ my @X = map("%xmm$_",(0..7));
+ my ($t0,$t1,$t2,$t3) = map("%xmm$_",(8..11));
+
+$code.=<<___;
+ jmp .Lloop_avx
+.align 16
+.Lloop_avx:
+ vmovdqa $TABLE+`$SZ*2*$rounds`(%rip),$t3
+ vmovdqu 0x00($inp),@X[0]
+ lea $TABLE+0x80(%rip),$Tbl # size optimization
+ vmovdqu 0x10($inp),@X[1]
+ vmovdqu 0x20($inp),@X[2]
+ vpshufb $t3,@X[0],@X[0]
+ vmovdqu 0x30($inp),@X[3]
+ vpshufb $t3,@X[1],@X[1]
+ vmovdqu 0x40($inp),@X[4]
+ vpshufb $t3,@X[2],@X[2]
+ vmovdqu 0x50($inp),@X[5]
+ vpshufb $t3,@X[3],@X[3]
+ vmovdqu 0x60($inp),@X[6]
+ vpshufb $t3,@X[4],@X[4]
+ vmovdqu 0x70($inp),@X[7]
+ vpshufb $t3,@X[5],@X[5]
+ vpaddq -0x80($Tbl),@X[0],$t0
+ vpshufb $t3,@X[6],@X[6]
+ vpaddq -0x60($Tbl),@X[1],$t1
+ vpshufb $t3,@X[7],@X[7]
+ vpaddq -0x40($Tbl),@X[2],$t2
+ vpaddq -0x20($Tbl),@X[3],$t3
+ vmovdqa $t0,0x00(%rsp)
+ vpaddq 0x00($Tbl),@X[4],$t0
+ vmovdqa $t1,0x10(%rsp)
+ vpaddq 0x20($Tbl),@X[5],$t1
+ vmovdqa $t2,0x20(%rsp)
+ vpaddq 0x40($Tbl),@X[6],$t2
+ vmovdqa $t3,0x30(%rsp)
+ vpaddq 0x60($Tbl),@X[7],$t3
+ vmovdqa $t0,0x40(%rsp)
+ mov $A,$a1
+ vmovdqa $t1,0x50(%rsp)
+ mov $B,$a3
+ vmovdqa $t2,0x60(%rsp)
+ xor $C,$a3 # magic
+ vmovdqa $t3,0x70(%rsp)
+ mov $E,$a0
+ jmp .Lavx_00_47
+
+.align 16
+.Lavx_00_47:
+ add \$16*2*$SZ,$Tbl
+___
+sub Xupdate_512_AVX () {
+ (
+ '&vpalignr ($t0,@X[1],@X[0],$SZ)', # X[1..2]
+ '&vpalignr ($t3,@X[5],@X[4],$SZ)', # X[9..10]
+ '&vpsrlq ($t2,$t0,$sigma0[0])',
+ '&vpaddq (@X[0],@X[0],$t3);', # X[0..1] += X[9..10]
+ '&vpsrlq ($t3,$t0,$sigma0[2])',
+ '&vpsllq ($t1,$t0,8*$SZ-$sigma0[1]);',
+ '&vpxor ($t0,$t3,$t2)',
+ '&vpsrlq ($t2,$t2,$sigma0[1]-$sigma0[0]);',
+ '&vpxor ($t0,$t0,$t1)',
+ '&vpsllq ($t1,$t1,$sigma0[1]-$sigma0[0]);',
+ '&vpxor ($t0,$t0,$t2)',
+ '&vpsrlq ($t3,@X[7],$sigma1[2]);',
+ '&vpxor ($t0,$t0,$t1)', # sigma0(X[1..2])
+ '&vpsllq ($t2,@X[7],8*$SZ-$sigma1[1]);',
+ '&vpaddq (@X[0],@X[0],$t0)', # X[0..1] += sigma0(X[1..2])
+ '&vpsrlq ($t1,@X[7],$sigma1[0]);',
+ '&vpxor ($t3,$t3,$t2)',
+ '&vpsllq ($t2,$t2,$sigma1[1]-$sigma1[0]);',
+ '&vpxor ($t3,$t3,$t1)',
+ '&vpsrlq ($t1,$t1,$sigma1[1]-$sigma1[0]);',
+ '&vpxor ($t3,$t3,$t2)',
+ '&vpxor ($t3,$t3,$t1)', # sigma1(X[14..15])
+ '&vpaddq (@X[0],@X[0],$t3)', # X[0..1] += sigma1(X[14..15])
+ );
+}
+
+sub AVX_512_00_47 () {
+my $j = shift;
+my $body = shift;
+my @X = @_;
+my @insns = (&$body,&$body); # 52 instructions
+
+ foreach (Xupdate_512_AVX()) { # 23 instructions
+ eval;
+ eval(shift(@insns));
+ eval(shift(@insns));
+ }
+ &vpaddq ($t2,@X[0],16*2*$j-0x80."($Tbl)");
+ foreach (@insns) { eval; } # remaining instructions
+ &vmovdqa (16*$j."(%rsp)",$t2);
+}
+
+ for ($i=0,$j=0; $j<8; $j++) {
+ &AVX_512_00_47($j,\&body_00_15,@X);
+ push(@X,shift(@X)); # rotate(@X)
+ }
+ &cmpb ($SZ-1+16*2*$SZ-0x80."($Tbl)",0);
+ &jne (".Lavx_00_47");
+
+ for ($i=0; $i<16; ) {
+ foreach(body_00_15()) { eval; }
+ }
+}
+$code.=<<___;
+ mov $_ctx,$ctx
+ mov $a1,$A
+
+ add $SZ*0($ctx),$A
+ lea 16*$SZ($inp),$inp
+ add $SZ*1($ctx),$B
+ add $SZ*2($ctx),$C
+ add $SZ*3($ctx),$D
+ add $SZ*4($ctx),$E
+ add $SZ*5($ctx),$F
+ add $SZ*6($ctx),$G
+ add $SZ*7($ctx),$H
+
+ cmp $_end,$inp
+
+ mov $A,$SZ*0($ctx)
+ mov $B,$SZ*1($ctx)
+ mov $C,$SZ*2($ctx)
+ mov $D,$SZ*3($ctx)
+ mov $E,$SZ*4($ctx)
+ mov $F,$SZ*5($ctx)
+ mov $G,$SZ*6($ctx)
+ mov $H,$SZ*7($ctx)
+ jb .Lloop_avx
+
+ mov $_rsp,%rsi
+ vzeroupper
+___
+$code.=<<___ if ($win64);
+ movaps 16*$SZ+32(%rsp),%xmm6
+ movaps 16*$SZ+48(%rsp),%xmm7
+ movaps 16*$SZ+64(%rsp),%xmm8
+ movaps 16*$SZ+80(%rsp),%xmm9
+___
+$code.=<<___ if ($win64 && $SZ>4);
+ movaps 16*$SZ+96(%rsp),%xmm10
+ movaps 16*$SZ+112(%rsp),%xmm11
+___
+$code.=<<___;
+ mov (%rsi),%r15
+ mov 8(%rsi),%r14
+ mov 16(%rsi),%r13
+ mov 24(%rsi),%r12
+ mov 32(%rsi),%rbp
+ mov 40(%rsi),%rbx
+ lea 48(%rsi),%rsp
+.Lepilogue_avx:
+ ret
+.size ${func}_avx,.-${func}_avx
+___
+
+if ($avx>1) {{
+######################################################################
+# AVX2+BMI code path
+#
+my $a5=$SZ==4?"%esi":"%rsi"; # zap $inp
+my $PUSH8=8*2*$SZ;
+use integer;
+
+sub bodyx_00_15 () {
+ # at start $a1 should be zero, $a3 - $b^$c and $a4 copy of $f
+ (
+ '($a,$b,$c,$d,$e,$f,$g,$h)=@ROT;'.
+
+ '&add ($h,(32*($i/(16/$SZ))+$SZ*($i%(16/$SZ)))%$PUSH8.$base)', # h+=X[i]+K[i]
+ '&and ($a4,$e)', # f&e
+ '&rorx ($a0,$e,$Sigma1[2])',
+ '&rorx ($a2,$e,$Sigma1[1])',
+
+ '&lea ($a,"($a,$a1)")', # h+=Sigma0(a) from the past
+ '&lea ($h,"($h,$a4)")',
+ '&andn ($a4,$e,$g)', # ~e&g
+ '&xor ($a0,$a2)',
+
+ '&rorx ($a1,$e,$Sigma1[0])',
+ '&lea ($h,"($h,$a4)")', # h+=Ch(e,f,g)=(e&f)+(~e&g)
+ '&xor ($a0,$a1)', # Sigma1(e)
+ '&mov ($a2,$a)',
+
+ '&rorx ($a4,$a,$Sigma0[2])',
+ '&lea ($h,"($h,$a0)")', # h+=Sigma1(e)
+ '&xor ($a2,$b)', # a^b, b^c in next round
+ '&rorx ($a1,$a,$Sigma0[1])',
+
+ '&rorx ($a0,$a,$Sigma0[0])',
+ '&lea ($d,"($d,$h)")', # d+=h
+ '&and ($a3,$a2)', # (b^c)&(a^b)
+ '&xor ($a1,$a4)',
+
+ '&xor ($a3,$b)', # Maj(a,b,c)=Ch(a^b,c,b)
+ '&xor ($a1,$a0)', # Sigma0(a)
+ '&lea ($h,"($h,$a3)");'. # h+=Maj(a,b,c)
+ '&mov ($a4,$e)', # copy of f in future
+
+ '($a2,$a3) = ($a3,$a2); unshift(@ROT,pop(@ROT)); $i++;'
+ );
+ # and at the finish one has to $a+=$a1
+}
+
+$code.=<<___;
+.type ${func}_avx2,\@function,3
+.align 64
+${func}_avx2:
+.Lavx2_shortcut:
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ mov %rsp,%r11 # copy %rsp
+ sub \$`2*$SZ*$rounds+4*8+$win64*16*($SZ==4?4:6)`,%rsp
+ shl \$4,%rdx # num*16
+ and \$-256*$SZ,%rsp # align stack frame
+ lea ($inp,%rdx,$SZ),%rdx # inp+num*16*$SZ
+ add \$`2*$SZ*($rounds-8)`,%rsp
+ mov $ctx,$_ctx # save ctx, 1st arg
+ mov $inp,$_inp # save inp, 2nd arh
+ mov %rdx,$_end # save end pointer, "3rd" arg
+ mov %r11,$_rsp # save copy of %rsp
+___
+$code.=<<___ if ($win64);
+ movaps %xmm6,16*$SZ+32(%rsp)
+ movaps %xmm7,16*$SZ+48(%rsp)
+ movaps %xmm8,16*$SZ+64(%rsp)
+ movaps %xmm9,16*$SZ+80(%rsp)
+___
+$code.=<<___ if ($win64 && $SZ>4);
+ movaps %xmm10,16*$SZ+96(%rsp)
+ movaps %xmm11,16*$SZ+112(%rsp)
+___
+$code.=<<___;
+.Lprologue_avx2:
+
+ vzeroupper
+ sub \$-16*$SZ,$inp # inp++, size optimization
+ mov $SZ*0($ctx),$A
+ mov $inp,%r12 # borrow $T1
+ mov $SZ*1($ctx),$B
+ cmp %rdx,$inp # $_end
+ mov $SZ*2($ctx),$C
+ cmove %rsp,%r12 # next block or random data
+ mov $SZ*3($ctx),$D
+ mov $SZ*4($ctx),$E
+ mov $SZ*5($ctx),$F
+ mov $SZ*6($ctx),$G
+ mov $SZ*7($ctx),$H
+___
+ if ($SZ==4) { # SHA256
+ my @X = map("%ymm$_",(0..3));
+ my ($t0,$t1,$t2,$t3, $t4,$t5) = map("%ymm$_",(4..9));
+
+$code.=<<___;
+ vmovdqa $TABLE+`$SZ*2*$rounds`+32(%rip),$t4
+ vmovdqa $TABLE+`$SZ*2*$rounds`+64(%rip),$t5
+ jmp .Loop_avx2
+.align 16
+.Loop_avx2:
+ vmovdqa $TABLE+`$SZ*2*$rounds`(%rip),$t3
+ vmovdqu -16*$SZ+0($inp),%xmm0
+ vmovdqu -16*$SZ+16($inp),%xmm1
+ vmovdqu -16*$SZ+32($inp),%xmm2
+ vmovdqu -16*$SZ+48($inp),%xmm3
+ #mov $inp,$_inp # offload $inp
+ vinserti128 \$1,(%r12),@X[0],@X[0]
+ vinserti128 \$1,16(%r12),@X[1],@X[1]
+ vpshufb $t3,@X[0],@X[0]
+ vinserti128 \$1,32(%r12),@X[2],@X[2]
+ vpshufb $t3,@X[1],@X[1]
+ vinserti128 \$1,48(%r12),@X[3],@X[3]
+
+ lea $TABLE(%rip),$Tbl
+ vpshufb $t3,@X[2],@X[2]
+ vpaddd 0x00($Tbl),@X[0],$t0
+ vpshufb $t3,@X[3],@X[3]
+ vpaddd 0x20($Tbl),@X[1],$t1
+ vpaddd 0x40($Tbl),@X[2],$t2
+ vpaddd 0x60($Tbl),@X[3],$t3
+ vmovdqa $t0,0x00(%rsp)
+ xor $a1,$a1
+ vmovdqa $t1,0x20(%rsp)
+ lea -$PUSH8(%rsp),%rsp
+ mov $B,$a3
+ vmovdqa $t2,0x00(%rsp)
+ xor $C,$a3 # magic
+ vmovdqa $t3,0x20(%rsp)
+ mov $F,$a4
+ sub \$-16*2*$SZ,$Tbl # size optimization
+ jmp .Lavx2_00_47
+
+.align 16
+.Lavx2_00_47:
+___
+
+sub AVX2_256_00_47 () {
+my $j = shift;
+my $body = shift;
+my @X = @_;
+my @insns = (&$body,&$body,&$body,&$body); # 96 instructions
+my $base = "+2*$PUSH8(%rsp)";
+
+ &lea ("%rsp","-$PUSH8(%rsp)") if (($j%2)==0);
+ foreach (Xupdate_256_AVX()) { # 29 instructions
+ eval;
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ }
+ &vpaddd ($t2,@X[0],16*2*$j."($Tbl)");
+ foreach (@insns) { eval; } # remaining instructions
+ &vmovdqa ((32*$j)%$PUSH8."(%rsp)",$t2);
+}
+
+ for ($i=0,$j=0; $j<4; $j++) {
+ &AVX2_256_00_47($j,\&bodyx_00_15,@X);
+ push(@X,shift(@X)); # rotate(@X)
+ }
+ &lea ($Tbl,16*2*$SZ."($Tbl)");
+ &cmpb (($SZ-1)."($Tbl)",0);
+ &jne (".Lavx2_00_47");
+
+ for ($i=0; $i<16; ) {
+ my $base=$i<8?"+$PUSH8(%rsp)":"(%rsp)";
+ foreach(bodyx_00_15()) { eval; }
+ }
+ } else { # SHA512
+ my @X = map("%ymm$_",(0..7));
+ my ($t0,$t1,$t2,$t3) = map("%ymm$_",(8..11));
+
+$code.=<<___;
+ jmp .Loop_avx2
+.align 16
+.Loop_avx2:
+ vmovdqu -16*$SZ($inp),%xmm0
+ vmovdqu -16*$SZ+16($inp),%xmm1
+ vmovdqu -16*$SZ+32($inp),%xmm2
+ lea $TABLE+0x80(%rip),$Tbl # size optimization
+ vmovdqu -16*$SZ+48($inp),%xmm3
+ vmovdqu -16*$SZ+64($inp),%xmm4
+ vmovdqu -16*$SZ+80($inp),%xmm5
+ vmovdqu -16*$SZ+96($inp),%xmm6
+ vmovdqu -16*$SZ+112($inp),%xmm7
+ #mov $inp,$_inp # offload $inp
+ vmovdqa `$SZ*2*$rounds-0x80`($Tbl),$t2
+ vinserti128 \$1,(%r12),@X[0],@X[0]
+ vinserti128 \$1,16(%r12),@X[1],@X[1]
+ vpshufb $t2,@X[0],@X[0]
+ vinserti128 \$1,32(%r12),@X[2],@X[2]
+ vpshufb $t2,@X[1],@X[1]
+ vinserti128 \$1,48(%r12),@X[3],@X[3]
+ vpshufb $t2,@X[2],@X[2]
+ vinserti128 \$1,64(%r12),@X[4],@X[4]
+ vpshufb $t2,@X[3],@X[3]
+ vinserti128 \$1,80(%r12),@X[5],@X[5]
+ vpshufb $t2,@X[4],@X[4]
+ vinserti128 \$1,96(%r12),@X[6],@X[6]
+ vpshufb $t2,@X[5],@X[5]
+ vinserti128 \$1,112(%r12),@X[7],@X[7]
+
+ vpaddq -0x80($Tbl),@X[0],$t0
+ vpshufb $t2,@X[6],@X[6]
+ vpaddq -0x60($Tbl),@X[1],$t1
+ vpshufb $t2,@X[7],@X[7]
+ vpaddq -0x40($Tbl),@X[2],$t2
+ vpaddq -0x20($Tbl),@X[3],$t3
+ vmovdqa $t0,0x00(%rsp)
+ vpaddq 0x00($Tbl),@X[4],$t0
+ vmovdqa $t1,0x20(%rsp)
+ vpaddq 0x20($Tbl),@X[5],$t1
+ vmovdqa $t2,0x40(%rsp)
+ vpaddq 0x40($Tbl),@X[6],$t2
+ vmovdqa $t3,0x60(%rsp)
+ lea -$PUSH8(%rsp),%rsp
+ vpaddq 0x60($Tbl),@X[7],$t3
+ vmovdqa $t0,0x00(%rsp)
+ xor $a1,$a1
+ vmovdqa $t1,0x20(%rsp)
+ mov $B,$a3
+ vmovdqa $t2,0x40(%rsp)
+ xor $C,$a3 # magic
+ vmovdqa $t3,0x60(%rsp)
+ mov $F,$a4
+ add \$16*2*$SZ,$Tbl
+ jmp .Lavx2_00_47
+
+.align 16
+.Lavx2_00_47:
+___
+
+sub AVX2_512_00_47 () {
+my $j = shift;
+my $body = shift;
+my @X = @_;
+my @insns = (&$body,&$body); # 48 instructions
+my $base = "+2*$PUSH8(%rsp)";
+
+ &lea ("%rsp","-$PUSH8(%rsp)") if (($j%4)==0);
+ foreach (Xupdate_512_AVX()) { # 23 instructions
+ eval;
+ if ($_ !~ /\;$/) {
+ eval(shift(@insns));
+ eval(shift(@insns));
+ eval(shift(@insns));
+ }
+ }
+ &vpaddq ($t2,@X[0],16*2*$j-0x80."($Tbl)");
+ foreach (@insns) { eval; } # remaining instructions
+ &vmovdqa ((32*$j)%$PUSH8."(%rsp)",$t2);
+}
+
+ for ($i=0,$j=0; $j<8; $j++) {
+ &AVX2_512_00_47($j,\&bodyx_00_15,@X);
+ push(@X,shift(@X)); # rotate(@X)
+ }
+ &lea ($Tbl,16*2*$SZ."($Tbl)");
+ &cmpb (($SZ-1-0x80)."($Tbl)",0);
+ &jne (".Lavx2_00_47");
+
+ for ($i=0; $i<16; ) {
+ my $base=$i<8?"+$PUSH8(%rsp)":"(%rsp)";
+ foreach(bodyx_00_15()) { eval; }
+ }
+}
+$code.=<<___;
+ mov `2*$SZ*$rounds`(%rsp),$ctx # $_ctx
+ add $a1,$A
+ #mov `2*$SZ*$rounds+8`(%rsp),$inp # $_inp
+ lea `2*$SZ*($rounds-8)`(%rsp),$Tbl
+
+ add $SZ*0($ctx),$A
+ add $SZ*1($ctx),$B
+ add $SZ*2($ctx),$C
+ add $SZ*3($ctx),$D
+ add $SZ*4($ctx),$E
+ add $SZ*5($ctx),$F
+ add $SZ*6($ctx),$G
+ add $SZ*7($ctx),$H
+
+ mov $A,$SZ*0($ctx)
+ mov $B,$SZ*1($ctx)
+ mov $C,$SZ*2($ctx)
+ mov $D,$SZ*3($ctx)
+ mov $E,$SZ*4($ctx)
+ mov $F,$SZ*5($ctx)
+ mov $G,$SZ*6($ctx)
+ mov $H,$SZ*7($ctx)
+
+ cmp `$PUSH8+2*8`($Tbl),$inp # $_end
+ je .Ldone_avx2
+
+ xor $a1,$a1
+ mov $B,$a3
+ xor $C,$a3 # magic
+ mov $F,$a4
+ jmp .Lower_avx2
+.align 16
+.Lower_avx2:
+___
+ for ($i=0; $i<8; ) {
+ my $base="+16($Tbl)";
+ foreach(bodyx_00_15()) { eval; }
+ }
+$code.=<<___;
+ lea -$PUSH8($Tbl),$Tbl
+ cmp %rsp,$Tbl
+ jae .Lower_avx2
+
+ mov `2*$SZ*$rounds`(%rsp),$ctx # $_ctx
+ add $a1,$A
+ #mov `2*$SZ*$rounds+8`(%rsp),$inp # $_inp
+ lea `2*$SZ*($rounds-8)`(%rsp),%rsp
+
+ add $SZ*0($ctx),$A
+ add $SZ*1($ctx),$B
+ add $SZ*2($ctx),$C
+ add $SZ*3($ctx),$D
+ add $SZ*4($ctx),$E
+ add $SZ*5($ctx),$F
+ lea `2*16*$SZ`($inp),$inp # inp+=2
+ add $SZ*6($ctx),$G
+ mov $inp,%r12
+ add $SZ*7($ctx),$H
+ cmp $_end,$inp
+
+ mov $A,$SZ*0($ctx)
+ cmove %rsp,%r12 # next block or stale data
+ mov $B,$SZ*1($ctx)
+ mov $C,$SZ*2($ctx)
+ mov $D,$SZ*3($ctx)
+ mov $E,$SZ*4($ctx)
+ mov $F,$SZ*5($ctx)
+ mov $G,$SZ*6($ctx)
+ mov $H,$SZ*7($ctx)
+
+ jbe .Loop_avx2
+ lea (%rsp),$Tbl
+
+.Ldone_avx2:
+ lea ($Tbl),%rsp
+ mov $_rsp,%rsi
+ vzeroupper
+___
+$code.=<<___ if ($win64);
+ movaps 16*$SZ+32(%rsp),%xmm6
+ movaps 16*$SZ+48(%rsp),%xmm7
+ movaps 16*$SZ+64(%rsp),%xmm8
+ movaps 16*$SZ+80(%rsp),%xmm9
+___
+$code.=<<___ if ($win64 && $SZ>4);
+ movaps 16*$SZ+96(%rsp),%xmm10
+ movaps 16*$SZ+112(%rsp),%xmm11
+___
+$code.=<<___;
+ mov (%rsi),%r15
+ mov 8(%rsi),%r14
+ mov 16(%rsi),%r13
+ mov 24(%rsi),%r12
+ mov 32(%rsi),%rbp
+ mov 40(%rsi),%rbx
+ lea 48(%rsi),%rsp
+.Lepilogue_avx2:
+ ret
+.size ${func}_avx2,.-${func}_avx2
+___
+}}
+}}}}}
+
+# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
+# CONTEXT *context,DISPATCHER_CONTEXT *disp)
+if ($win64) {
+$rec="%rcx";
+$frame="%rdx";
+$context="%r8";
+$disp="%r9";
+
+$code.=<<___;
+.extern __imp_RtlVirtualUnwind
+.type se_handler,\@abi-omnipotent
+.align 16
+se_handler:
+ push %rsi
+ push %rdi
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ pushfq
+ sub \$64,%rsp
+
+ mov 120($context),%rax # pull context->Rax
+ mov 248($context),%rbx # pull context->Rip
+
+ mov 8($disp),%rsi # disp->ImageBase
+ mov 56($disp),%r11 # disp->HanderlData
+
+ mov 0(%r11),%r10d # HandlerData[0]
+ lea (%rsi,%r10),%r10 # prologue label
+ cmp %r10,%rbx # context->Rip<prologue label
+ jb .Lin_prologue
+
+ mov 152($context),%rax # pull context->Rsp
+
+ mov 4(%r11),%r10d # HandlerData[1]
+ lea (%rsi,%r10),%r10 # epilogue label
+ cmp %r10,%rbx # context->Rip>=epilogue label
+ jae .Lin_prologue
+___
+$code.=<<___ if ($avx>1);
+ lea .Lavx2_shortcut(%rip),%r10
+ cmp %r10,%rbx # context->Rip<avx2_shortcut
+ jb .Lnot_in_avx2
+
+ and \$-256*$SZ,%rax
+ add \$`2*$SZ*($rounds-8)`,%rax
+.Lnot_in_avx2:
+___
+$code.=<<___;
+ mov %rax,%rsi # put aside Rsp
+ mov 16*$SZ+3*8(%rax),%rax # pull $_rsp
+ lea 48(%rax),%rax
+
+ mov -8(%rax),%rbx
+ mov -16(%rax),%rbp
+ mov -24(%rax),%r12
+ mov -32(%rax),%r13
+ mov -40(%rax),%r14
+ mov -48(%rax),%r15
+ mov %rbx,144($context) # restore context->Rbx
+ mov %rbp,160($context) # restore context->Rbp
+ mov %r12,216($context) # restore context->R12
+ mov %r13,224($context) # restore context->R13
+ mov %r14,232($context) # restore context->R14
+ mov %r15,240($context) # restore context->R15
+
+ lea .Lepilogue(%rip),%r10
+ cmp %r10,%rbx
+ jb .Lin_prologue # non-AVX code
+
+ lea 16*$SZ+4*8(%rsi),%rsi # Xmm6- save area
+ lea 512($context),%rdi # &context.Xmm6
+ mov \$`$SZ==4?8:12`,%ecx
+ .long 0xa548f3fc # cld; rep movsq
+
+.Lin_prologue:
+ mov 8(%rax),%rdi
+ mov 16(%rax),%rsi
+ mov %rax,152($context) # restore context->Rsp
+ mov %rsi,168($context) # restore context->Rsi
+ mov %rdi,176($context) # restore context->Rdi
+
+ mov 40($disp),%rdi # disp->ContextRecord
+ mov $context,%rsi # context
+ mov \$154,%ecx # sizeof(CONTEXT)
+ .long 0xa548f3fc # cld; rep movsq
+
+ mov $disp,%rsi
+ xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER
+ mov 8(%rsi),%rdx # arg2, disp->ImageBase
+ mov 0(%rsi),%r8 # arg3, disp->ControlPc
+ mov 16(%rsi),%r9 # arg4, disp->FunctionEntry
+ mov 40(%rsi),%r10 # disp->ContextRecord
+ lea 56(%rsi),%r11 # &disp->HandlerData
+ lea 24(%rsi),%r12 # &disp->EstablisherFrame
+ mov %r10,32(%rsp) # arg5
+ mov %r11,40(%rsp) # arg6
+ mov %r12,48(%rsp) # arg7
+ mov %rcx,56(%rsp) # arg8, (NULL)
+ call *__imp_RtlVirtualUnwind(%rip)
+
+ mov \$1,%eax # ExceptionContinueSearch
+ add \$64,%rsp
+ popfq
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+ pop %rdi
+ pop %rsi
+ ret
+.size se_handler,.-se_handler
+
+.section .pdata
+.align 4
+ .rva .LSEH_begin_$func
+ .rva .LSEH_end_$func
+ .rva .LSEH_info_$func
+___
+$code.=<<___ if ($SZ==4);
+ .rva .LSEH_begin_${func}_ssse3
+ .rva .LSEH_end_${func}_ssse3
+ .rva .LSEH_info_${func}_ssse3
+___
+$code.=<<___ if ($avx && $SZ==8);
+ .rva .LSEH_begin_${func}_xop
+ .rva .LSEH_end_${func}_xop
+ .rva .LSEH_info_${func}_xop
+___
+$code.=<<___ if ($avx);
+ .rva .LSEH_begin_${func}_avx
+ .rva .LSEH_end_${func}_avx
+ .rva .LSEH_info_${func}_avx
+___
+$code.=<<___ if ($avx>1);
+ .rva .LSEH_begin_${func}_avx2
+ .rva .LSEH_end_${func}_avx2
+ .rva .LSEH_info_${func}_avx2
+___
+$code.=<<___;
+.section .xdata
+.align 8
+.LSEH_info_$func:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lprologue,.Lepilogue # HandlerData[]
+___
+$code.=<<___ if ($SZ==4);
+.LSEH_info_${func}_ssse3:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lprologue_ssse3,.Lepilogue_ssse3 # HandlerData[]
+___
+$code.=<<___ if ($avx && $SZ==8);
+.LSEH_info_${func}_xop:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lprologue_xop,.Lepilogue_xop # HandlerData[]
+___
+$code.=<<___ if ($avx);
+.LSEH_info_${func}_avx:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lprologue_avx,.Lepilogue_avx # HandlerData[]
+___
+$code.=<<___ if ($avx>1);
+.LSEH_info_${func}_avx2:
+ .byte 9,0,0,0
+ .rva se_handler
+ .rva .Lprologue_avx2,.Lepilogue_avx2 # HandlerData[]
+___
+}
+
+$code =~ s/\`([^\`]*)\`/eval $1/gem;
+print $code;
+close STDOUT;
diff --git a/crypto/sha/sha.h b/crypto/sha/sha.h
new file mode 100644
index 0000000..2eda284
--- /dev/null
+++ b/crypto/sha/sha.h
@@ -0,0 +1,237 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_SHA_H
+#define OPENSSL_HEADER_SHA_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* SHA-1. */
+
+
+/* SHA_CBLOCK is the block size of SHA-1. */
+#define SHA_CBLOCK 64
+
+/* SHA_DIGEST_LENGTH is the length of a SHA-1 digest. */
+#define SHA_DIGEST_LENGTH 20
+
+/* TODO(fork): remove */
+#define SHA_LBLOCK 16
+#define SHA_LONG uint32_t
+
+/* SHA1_Init initialises |sha| and returns one. */
+int SHA1_Init(SHA_CTX *sha);
+
+/* SHA1_Update adds |len| bytes from |data| to |sha| and returns one. */
+int SHA1_Update(SHA_CTX *sha, const void *data, size_t len);
+
+/* SHA1_Final adds the final padding to |sha| and writes the resulting digest
+ * to |md|, which must have at least |SHA_DIGEST_LENGTH| bytes of space. It
+ * returns one. */
+int SHA1_Final(uint8_t *md, SHA_CTX *sha);
+
+/* SHA1 writes the digest of |len| bytes from |data| to |out| and returns
+ * |out|. There must be at least |SHA_DIGEST_LENGTH| bytes of space in
+ * |out|. */
+uint8_t *SHA1(const uint8_t *data, size_t len, uint8_t *out);
+
+/* SHA1_Transform is a low-level function that performs a single, SHA-1 block
+ * transformation using the state from |sha| and 64 bytes from |block|. */
+void SHA1_Transform(SHA_CTX *sha, const uint8_t *block);
+
+struct sha_state_st {
+ uint32_t h0, h1, h2, h3, h4;
+ uint32_t Nl, Nh;
+ uint32_t data[16];
+ unsigned int num;
+};
+
+
+/* SHA-224. */
+
+/* SHA224_CBLOCK is the block size of SHA-224. */
+#define SHA224_CBLOCK 64
+
+/* SHA224_DIGEST_LENGTH is the length of a SHA-224 digest. */
+#define SHA224_DIGEST_LENGTH 28
+
+/* SHA224_Init initialises |sha| and returns 1. */
+int SHA224_Init(SHA256_CTX *sha);
+
+/* SHA224_Update adds |len| bytes from |data| to |sha|. */
+int SHA224_Update(SHA256_CTX *sha, const void *data, size_t len);
+
+/* SHA224_Final adds the final padding to |sha| and writes the resulting digest
+ * to |md|, which must have at least |SHA_DIGEST_LENGTH| bytes of space. */
+int SHA224_Final(uint8_t *md, SHA256_CTX *sha);
+
+/* SHA224 writes the digest of |len| bytes from |data| to |out| and returns
+ * |out|. There must be at least |SHA_DIGEST_LENGTH| bytes of space in
+ * |out|. */
+uint8_t *SHA224(const uint8_t *data, size_t len, uint8_t *out);
+
+
+/* SHA-256. */
+
+/* SHA256_CBLOCK is the block size of SHA-256. */
+#define SHA256_CBLOCK 64
+
+/* SHA256_DIGEST_LENGTH is the length of a SHA-256 digest. */
+#define SHA256_DIGEST_LENGTH 32
+
+/* SHA256_Init initialises |sha| and returns 1. */
+int SHA256_Init(SHA256_CTX *sha);
+
+/* SHA256_Update adds |len| bytes from |data| to |sha|. */
+int SHA256_Update(SHA256_CTX *sha, const void *data, size_t len);
+
+/* SHA256_Final adds the final padding to |sha| and writes the resulting digest
+ * to |md|, which must have at least |SHA_DIGEST_LENGTH| bytes of space. */
+int SHA256_Final(uint8_t *md, SHA256_CTX *sha);
+
+/* SHA256 writes the digest of |len| bytes from |data| to |out| and returns
+ * |out|. There must be at least |SHA_DIGEST_LENGTH| bytes of space in
+ * |out|. */
+uint8_t *SHA256(const uint8_t *data, size_t len ,uint8_t *out);
+
+/* SHA256_Transform is a low-level function that performs a single, SHA-1 block
+ * transformation using the state from |sha| and 64 bytes from |block|. */
+void SHA256_Transform(SHA256_CTX *sha, const uint8_t *data);
+
+struct sha256_state_st {
+ uint32_t h[8];
+ uint32_t Nl, Nh;
+ uint32_t data[16];
+ unsigned int num, md_len;
+};
+
+
+/* SHA-384. */
+
+/* SHA384_CBLOCK is the block size of SHA-384. */
+#define SHA384_CBLOCK 128
+
+/* SHA384_DIGEST_LENGTH is the length of a SHA-384 digest. */
+#define SHA384_DIGEST_LENGTH 48
+
+/* SHA384_Init initialises |sha| and returns 1. */
+int SHA384_Init(SHA512_CTX *sha);
+
+/* SHA384_Update adds |len| bytes from |data| to |sha|. */
+int SHA384_Update(SHA512_CTX *sha, const void *data, size_t len);
+
+/* SHA384_Final adds the final padding to |sha| and writes the resulting digest
+ * to |md|, which must have at least |SHA_DIGEST_LENGTH| bytes of space. */
+int SHA384_Final(uint8_t *md, SHA512_CTX *sha);
+
+/* SHA384 writes the digest of |len| bytes from |data| to |out| and returns
+ * |out|. There must be at least |SHA_DIGEST_LENGTH| bytes of space in
+ * |out|. */
+uint8_t *SHA384(const uint8_t *data, size_t len ,uint8_t *out);
+
+/* SHA384_Transform is a low-level function that performs a single, SHA-1 block
+ * transformation using the state from |sha| and 64 bytes from |block|. */
+void SHA384_Transform(SHA512_CTX *sha, const uint8_t *data);
+
+
+/* SHA-512. */
+
+/* SHA512_CBLOCK is the block size of SHA-512. */
+#define SHA512_CBLOCK 128
+
+/* SHA512_DIGEST_LENGTH is the length of a SHA-512 digest. */
+#define SHA512_DIGEST_LENGTH 64
+
+/* SHA512_Init initialises |sha| and returns 1. */
+int SHA512_Init(SHA512_CTX *sha);
+
+/* SHA512_Update adds |len| bytes from |data| to |sha|. */
+int SHA512_Update(SHA512_CTX *sha, const void *data, size_t len);
+
+/* SHA512_Final adds the final padding to |sha| and writes the resulting digest
+ * to |md|, which must have at least |SHA_DIGEST_LENGTH| bytes of space. */
+int SHA512_Final(uint8_t *md, SHA512_CTX *sha);
+
+/* SHA512 writes the digest of |len| bytes from |data| to |out| and returns
+ * |out|. There must be at least |SHA_DIGEST_LENGTH| bytes of space in
+ * |out|. */
+uint8_t *SHA512(const uint8_t *data, size_t len ,uint8_t *out);
+
+/* SHA512_Transform is a low-level function that performs a single, SHA-1 block
+ * transformation using the state from |sha| and 64 bytes from |block|. */
+void SHA512_Transform(SHA512_CTX *sha, const uint8_t *data);
+
+struct sha512_state_st {
+ uint64_t h[8];
+ uint64_t Nl, Nh;
+ union {
+ uint64_t d[16];
+ uint8_t p[64];
+ } u;
+ unsigned int num, md_len;
+};
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_SHA_H */
diff --git a/crypto/sha/sha1.c b/crypto/sha/sha1.c
new file mode 100644
index 0000000..3148739
--- /dev/null
+++ b/crypto/sha/sha1.c
@@ -0,0 +1,379 @@
+/* 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/sha.h>
+
+#include <string.h>
+
+#include <openssl/mem.h>
+
+
+#if !defined(OPENSSL_NO_ASM) && \
+ (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || defined(OPENSSL_ARM))
+#define SHA1_ASM
+#endif
+
+int SHA1_Init(SHA_CTX *sha) {
+ memset(sha, 0, sizeof(SHA_CTX));
+ sha->h0 = 0x67452301UL;
+ sha->h1 = 0xefcdab89UL;
+ sha->h2 = 0x98badcfeUL;
+ sha->h3 = 0x10325476UL;
+ sha->h4 = 0xc3d2e1f0UL;
+ return 1;
+}
+
+uint8_t *SHA1(const uint8_t *data, size_t len, uint8_t *out) {
+ SHA_CTX ctx;
+ static uint8_t buf[SHA_DIGEST_LENGTH];
+
+ /* TODO(fork): remove this static buffer. */
+ if (out == NULL) {
+ out = buf;
+ }
+ if (!SHA1_Init(&ctx)) {
+ return NULL;
+ }
+ SHA1_Update(&ctx, data, len);
+ SHA1_Final(out, &ctx);
+ OPENSSL_cleanse(&ctx, sizeof(ctx));
+ return out;
+}
+
+#define DATA_ORDER_IS_BIG_ENDIAN
+
+#define HASH_LONG uint32_t
+#define HASH_CTX SHA_CTX
+#define HASH_CBLOCK 64
+#define HASH_MAKE_STRING(c, s) \
+ do { \
+ unsigned long ll; \
+ ll = (c)->h0; \
+ (void) HOST_l2c(ll, (s)); \
+ ll = (c)->h1; \
+ (void) HOST_l2c(ll, (s)); \
+ ll = (c)->h2; \
+ (void) HOST_l2c(ll, (s)); \
+ ll = (c)->h3; \
+ (void) HOST_l2c(ll, (s)); \
+ ll = (c)->h4; \
+ (void) HOST_l2c(ll, (s)); \
+ } while (0)
+
+#define HASH_UPDATE SHA1_Update
+#define HASH_TRANSFORM SHA1_Transform
+#define HASH_FINAL SHA1_Final
+#define HASH_BLOCK_DATA_ORDER sha1_block_data_order
+#define Xupdate(a, ix, ia, ib, ic, id) \
+ ((a) = (ia ^ ib ^ ic ^ id), ix = (a) = ROTATE((a), 1))
+
+#ifndef SHA1_ASM
+static
+#endif
+void sha1_block_data_order(SHA_CTX *c, const void *p, size_t num);
+
+#include "../digest/md32_common.h"
+
+#define K_00_19 0x5a827999UL
+#define K_20_39 0x6ed9eba1UL
+#define K_40_59 0x8f1bbcdcUL
+#define K_60_79 0xca62c1d6UL
+
+/* As pointed out by Wei Dai <weidai@eskimo.com>, F() below can be simplified
+ * to the code in F_00_19. Wei attributes these optimisations to Peter
+ * Gutmann's SHS code, and he attributes it to Rich Schroeppel. #define
+ * F(x,y,z) (((x) & (y)) | ((~(x)) & (z))) I've just become aware of another
+ * tweak to be made, again from Wei Dai, in F_40_59, (x&a)|(y&a) -> (x|y)&a */
+#define F_00_19(b, c, d) ((((c) ^ (d)) & (b)) ^ (d))
+#define F_20_39(b, c, d) ((b) ^ (c) ^ (d))
+#define F_40_59(b, c, d) (((b) & (c)) | (((b) | (c)) & (d)))
+#define F_60_79(b, c, d) F_20_39(b, c, d)
+
+#define BODY_00_15(i, a, b, c, d, e, f, xi) \
+ (f) = xi + (e) + K_00_19 + ROTATE((a), 5) + F_00_19((b), (c), (d)); \
+ (b) = ROTATE((b), 30);
+
+#define BODY_16_19(i, a, b, c, d, e, f, xi, xa, xb, xc, xd) \
+ Xupdate(f, xi, xa, xb, xc, xd); \
+ (f) += (e) + K_00_19 + ROTATE((a), 5) + F_00_19((b), (c), (d)); \
+ (b) = ROTATE((b), 30);
+
+#define BODY_20_31(i, a, b, c, d, e, f, xi, xa, xb, xc, xd) \
+ Xupdate(f, xi, xa, xb, xc, xd); \
+ (f) += (e) + K_20_39 + ROTATE((a), 5) + F_20_39((b), (c), (d)); \
+ (b) = ROTATE((b), 30);
+
+#define BODY_32_39(i, a, b, c, d, e, f, xa, xb, xc, xd) \
+ Xupdate(f, xa, xa, xb, xc, xd); \
+ (f) += (e) + K_20_39 + ROTATE((a), 5) + F_20_39((b), (c), (d)); \
+ (b) = ROTATE((b), 30);
+
+#define BODY_40_59(i, a, b, c, d, e, f, xa, xb, xc, xd) \
+ Xupdate(f, xa, xa, xb, xc, xd); \
+ (f) += (e) + K_40_59 + ROTATE((a), 5) + F_40_59((b), (c), (d)); \
+ (b) = ROTATE((b), 30);
+
+#define BODY_60_79(i, a, b, c, d, e, f, xa, xb, xc, xd) \
+ Xupdate(f, xa, xa, xb, xc, xd); \
+ (f) = xa + (e) + K_60_79 + ROTATE((a), 5) + F_60_79((b), (c), (d)); \
+ (b) = ROTATE((b), 30);
+
+#ifdef X
+#undef X
+#endif
+
+/* Originally X was an array. As it's automatic it's natural
+* to expect RISC compiler to accomodate at least part of it in
+* the register bank, isn't it? Unfortunately not all compilers
+* "find" this expectation reasonable:-( On order to make such
+* compilers generate better code I replace X[] with a bunch of
+* X0, X1, etc. See the function body below...
+* <appro@fy.chalmers.se> */
+#define X(i) XX##i
+
+#if !defined(SHA1_ASM)
+static void HASH_BLOCK_DATA_ORDER(SHA_CTX *c, const void *p, size_t num) {
+ const uint8_t *data = p;
+ register unsigned MD32_REG_T A, B, C, D, E, T, l;
+ unsigned MD32_REG_T XX0, XX1, XX2, XX3, XX4, XX5, XX6, XX7, XX8, XX9, XX10,
+ XX11, XX12, XX13, XX14, XX15;
+
+ A = c->h0;
+ B = c->h1;
+ C = c->h2;
+ D = c->h3;
+ E = c->h4;
+
+ for (;;) {
+ const union {
+ long one;
+ char little;
+ } is_endian = {1};
+
+ if (!is_endian.little && ((size_t)p % 4) == 0) {
+ const uint32_t *W = (const uint32_t *)data;
+
+ X(0) = W[0];
+ X(1) = W[1];
+ BODY_00_15(0, A, B, C, D, E, T, X(0));
+ X(2) = W[2];
+ BODY_00_15(1, T, A, B, C, D, E, X(1));
+ X(3) = W[3];
+ BODY_00_15(2, E, T, A, B, C, D, X(2));
+ X(4) = W[4];
+ BODY_00_15(3, D, E, T, A, B, C, X(3));
+ X(5) = W[5];
+ BODY_00_15(4, C, D, E, T, A, B, X(4));
+ X(6) = W[6];
+ BODY_00_15(5, B, C, D, E, T, A, X(5));
+ X(7) = W[7];
+ BODY_00_15(6, A, B, C, D, E, T, X(6));
+ X(8) = W[8];
+ BODY_00_15(7, T, A, B, C, D, E, X(7));
+ X(9) = W[9];
+ BODY_00_15(8, E, T, A, B, C, D, X(8));
+ X(10) = W[10];
+ BODY_00_15(9, D, E, T, A, B, C, X(9));
+ X(11) = W[11];
+ BODY_00_15(10, C, D, E, T, A, B, X(10));
+ X(12) = W[12];
+ BODY_00_15(11, B, C, D, E, T, A, X(11));
+ X(13) = W[13];
+ BODY_00_15(12, A, B, C, D, E, T, X(12));
+ X(14) = W[14];
+ BODY_00_15(13, T, A, B, C, D, E, X(13));
+ X(15) = W[15];
+ BODY_00_15(14, E, T, A, B, C, D, X(14));
+ BODY_00_15(15, D, E, T, A, B, C, X(15));
+
+ data += HASH_CBLOCK;
+ } else {
+ (void)HOST_c2l(data, l);
+ X(0) = l;
+ (void)HOST_c2l(data, l);
+ X(1) = l;
+ BODY_00_15(0, A, B, C, D, E, T, X(0));
+ (void)HOST_c2l(data, l);
+ X(2) = l;
+ BODY_00_15(1, T, A, B, C, D, E, X(1));
+ (void)HOST_c2l(data, l);
+ X(3) = l;
+ BODY_00_15(2, E, T, A, B, C, D, X(2));
+ (void)HOST_c2l(data, l);
+ X(4) = l;
+ BODY_00_15(3, D, E, T, A, B, C, X(3));
+ (void)HOST_c2l(data, l);
+ X(5) = l;
+ BODY_00_15(4, C, D, E, T, A, B, X(4));
+ (void)HOST_c2l(data, l);
+ X(6) = l;
+ BODY_00_15(5, B, C, D, E, T, A, X(5));
+ (void)HOST_c2l(data, l);
+ X(7) = l;
+ BODY_00_15(6, A, B, C, D, E, T, X(6));
+ (void)HOST_c2l(data, l);
+ X(8) = l;
+ BODY_00_15(7, T, A, B, C, D, E, X(7));
+ (void)HOST_c2l(data, l);
+ X(9) = l;
+ BODY_00_15(8, E, T, A, B, C, D, X(8));
+ (void)HOST_c2l(data, l);
+ X(10) = l;
+ BODY_00_15(9, D, E, T, A, B, C, X(9));
+ (void)HOST_c2l(data, l);
+ X(11) = l;
+ BODY_00_15(10, C, D, E, T, A, B, X(10));
+ (void)HOST_c2l(data, l);
+ X(12) = l;
+ BODY_00_15(11, B, C, D, E, T, A, X(11));
+ (void)HOST_c2l(data, l);
+ X(13) = l;
+ BODY_00_15(12, A, B, C, D, E, T, X(12));
+ (void)HOST_c2l(data, l);
+ X(14) = l;
+ BODY_00_15(13, T, A, B, C, D, E, X(13));
+ (void)HOST_c2l(data, l);
+ X(15) = l;
+ BODY_00_15(14, E, T, A, B, C, D, X(14));
+ BODY_00_15(15, D, E, T, A, B, C, X(15));
+ }
+
+ BODY_16_19(16, C, D, E, T, A, B, X(0), X(0), X(2), X(8), X(13));
+ BODY_16_19(17, B, C, D, E, T, A, X(1), X(1), X(3), X(9), X(14));
+ BODY_16_19(18, A, B, C, D, E, T, X(2), X(2), X(4), X(10), X(15));
+ BODY_16_19(19, T, A, B, C, D, E, X(3), X(3), X(5), X(11), X(0));
+
+ BODY_20_31(20, E, T, A, B, C, D, X(4), X(4), X(6), X(12), X(1));
+ BODY_20_31(21, D, E, T, A, B, C, X(5), X(5), X(7), X(13), X(2));
+ BODY_20_31(22, C, D, E, T, A, B, X(6), X(6), X(8), X(14), X(3));
+ BODY_20_31(23, B, C, D, E, T, A, X(7), X(7), X(9), X(15), X(4));
+ BODY_20_31(24, A, B, C, D, E, T, X(8), X(8), X(10), X(0), X(5));
+ BODY_20_31(25, T, A, B, C, D, E, X(9), X(9), X(11), X(1), X(6));
+ BODY_20_31(26, E, T, A, B, C, D, X(10), X(10), X(12), X(2), X(7));
+ BODY_20_31(27, D, E, T, A, B, C, X(11), X(11), X(13), X(3), X(8));
+ BODY_20_31(28, C, D, E, T, A, B, X(12), X(12), X(14), X(4), X(9));
+ BODY_20_31(29, B, C, D, E, T, A, X(13), X(13), X(15), X(5), X(10));
+ BODY_20_31(30, A, B, C, D, E, T, X(14), X(14), X(0), X(6), X(11));
+ BODY_20_31(31, T, A, B, C, D, E, X(15), X(15), X(1), X(7), X(12));
+
+ BODY_32_39(32, E, T, A, B, C, D, X(0), X(2), X(8), X(13));
+ BODY_32_39(33, D, E, T, A, B, C, X(1), X(3), X(9), X(14));
+ BODY_32_39(34, C, D, E, T, A, B, X(2), X(4), X(10), X(15));
+ BODY_32_39(35, B, C, D, E, T, A, X(3), X(5), X(11), X(0));
+ BODY_32_39(36, A, B, C, D, E, T, X(4), X(6), X(12), X(1));
+ BODY_32_39(37, T, A, B, C, D, E, X(5), X(7), X(13), X(2));
+ BODY_32_39(38, E, T, A, B, C, D, X(6), X(8), X(14), X(3));
+ BODY_32_39(39, D, E, T, A, B, C, X(7), X(9), X(15), X(4));
+
+ BODY_40_59(40, C, D, E, T, A, B, X(8), X(10), X(0), X(5));
+ BODY_40_59(41, B, C, D, E, T, A, X(9), X(11), X(1), X(6));
+ BODY_40_59(42, A, B, C, D, E, T, X(10), X(12), X(2), X(7));
+ BODY_40_59(43, T, A, B, C, D, E, X(11), X(13), X(3), X(8));
+ BODY_40_59(44, E, T, A, B, C, D, X(12), X(14), X(4), X(9));
+ BODY_40_59(45, D, E, T, A, B, C, X(13), X(15), X(5), X(10));
+ BODY_40_59(46, C, D, E, T, A, B, X(14), X(0), X(6), X(11));
+ BODY_40_59(47, B, C, D, E, T, A, X(15), X(1), X(7), X(12));
+ BODY_40_59(48, A, B, C, D, E, T, X(0), X(2), X(8), X(13));
+ BODY_40_59(49, T, A, B, C, D, E, X(1), X(3), X(9), X(14));
+ BODY_40_59(50, E, T, A, B, C, D, X(2), X(4), X(10), X(15));
+ BODY_40_59(51, D, E, T, A, B, C, X(3), X(5), X(11), X(0));
+ BODY_40_59(52, C, D, E, T, A, B, X(4), X(6), X(12), X(1));
+ BODY_40_59(53, B, C, D, E, T, A, X(5), X(7), X(13), X(2));
+ BODY_40_59(54, A, B, C, D, E, T, X(6), X(8), X(14), X(3));
+ BODY_40_59(55, T, A, B, C, D, E, X(7), X(9), X(15), X(4));
+ BODY_40_59(56, E, T, A, B, C, D, X(8), X(10), X(0), X(5));
+ BODY_40_59(57, D, E, T, A, B, C, X(9), X(11), X(1), X(6));
+ BODY_40_59(58, C, D, E, T, A, B, X(10), X(12), X(2), X(7));
+ BODY_40_59(59, B, C, D, E, T, A, X(11), X(13), X(3), X(8));
+
+ BODY_60_79(60, A, B, C, D, E, T, X(12), X(14), X(4), X(9));
+ BODY_60_79(61, T, A, B, C, D, E, X(13), X(15), X(5), X(10));
+ BODY_60_79(62, E, T, A, B, C, D, X(14), X(0), X(6), X(11));
+ BODY_60_79(63, D, E, T, A, B, C, X(15), X(1), X(7), X(12));
+ BODY_60_79(64, C, D, E, T, A, B, X(0), X(2), X(8), X(13));
+ BODY_60_79(65, B, C, D, E, T, A, X(1), X(3), X(9), X(14));
+ BODY_60_79(66, A, B, C, D, E, T, X(2), X(4), X(10), X(15));
+ BODY_60_79(67, T, A, B, C, D, E, X(3), X(5), X(11), X(0));
+ BODY_60_79(68, E, T, A, B, C, D, X(4), X(6), X(12), X(1));
+ BODY_60_79(69, D, E, T, A, B, C, X(5), X(7), X(13), X(2));
+ BODY_60_79(70, C, D, E, T, A, B, X(6), X(8), X(14), X(3));
+ BODY_60_79(71, B, C, D, E, T, A, X(7), X(9), X(15), X(4));
+ BODY_60_79(72, A, B, C, D, E, T, X(8), X(10), X(0), X(5));
+ BODY_60_79(73, T, A, B, C, D, E, X(9), X(11), X(1), X(6));
+ BODY_60_79(74, E, T, A, B, C, D, X(10), X(12), X(2), X(7));
+ BODY_60_79(75, D, E, T, A, B, C, X(11), X(13), X(3), X(8));
+ BODY_60_79(76, C, D, E, T, A, B, X(12), X(14), X(4), X(9));
+ BODY_60_79(77, B, C, D, E, T, A, X(13), X(15), X(5), X(10));
+ BODY_60_79(78, A, B, C, D, E, T, X(14), X(0), X(6), X(11));
+ BODY_60_79(79, T, A, B, C, D, E, X(15), X(1), X(7), X(12));
+
+ c->h0 = (c->h0 + E) & 0xffffffffL;
+ c->h1 = (c->h1 + T) & 0xffffffffL;
+ c->h2 = (c->h2 + A) & 0xffffffffL;
+ c->h3 = (c->h3 + B) & 0xffffffffL;
+ c->h4 = (c->h4 + C) & 0xffffffffL;
+
+ if (--num == 0)
+ break;
+
+ A = c->h0;
+ B = c->h1;
+ C = c->h2;
+ D = c->h3;
+ E = c->h4;
+ }
+}
+#endif
diff --git a/crypto/sha/sha1_test.c b/crypto/sha/sha1_test.c
new file mode 100644
index 0000000..72ef9e1
--- /dev/null
+++ b/crypto/sha/sha1_test.c
@@ -0,0 +1,125 @@
+/* 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/sha.h>
+#include <openssl/digest.h>
+
+
+static const char *const test[] = {
+ "abc", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", NULL, };
+
+static const char *const expected[] = {
+ "a9993e364706816aba3e25717850c26c9cd0d89d",
+ "84983e441c3bd26ebaae4aa1f95129e5e54670f1", };
+
+static int test_incremental() {
+ EVP_MD_CTX ctx;
+ char buf[1000];
+ uint8_t md[SHA_DIGEST_LENGTH];
+ char md_hex[sizeof(md) * 2 + 1];
+ size_t i;
+ static const char expected[] = "34aa973cd4c4daa4f61eeb2bdbad27316534016f";
+
+ memset(buf, 'a', sizeof(buf));
+ EVP_MD_CTX_init(&ctx);
+ EVP_DigestInit_ex(&ctx, EVP_sha1(), NULL);
+ for (i = 0; i < 1000; i++) {
+ EVP_DigestUpdate(&ctx, buf, sizeof(buf));
+ }
+ EVP_DigestFinal_ex(&ctx, md, NULL);
+ EVP_MD_CTX_cleanup(&ctx);
+
+ for (i = 0; i < sizeof(md); i++) {
+ sprintf(&md_hex[i * 2], "%02x", md[i]);
+ }
+
+ if (strcmp(md_hex, expected) != 0) {
+ fprintf(stderr, "test_incremental: got %s, wanted %s\n", md_hex, expected);
+ return 0;
+ }
+
+ return 1;
+}
+
+int main(int argc, char **argv) {
+ size_t i, j;
+ uint8_t md[SHA_DIGEST_LENGTH];
+ char md_hex[sizeof(md) * 2 + 1];
+ int ok = 1;
+
+ for (i = 0; test[i] != NULL; i++) {
+ EVP_Digest(test[i], strlen(test[i]), md, NULL, EVP_sha1(), NULL);
+ for (j = 0; j < sizeof(md); j++) {
+ sprintf(&md_hex[j * 2], "%02x", md[j]);
+ }
+
+ if (strcmp(md_hex, expected[i]) != 0) {
+ fprintf(stderr, "#%u: got %s, wanted %s\n", (unsigned)i, md_hex,
+ expected[i]);
+ ok = 0;
+ }
+ }
+
+ ok &= test_incremental();
+
+ if (ok) {
+ printf("PASS\n");
+ }
+
+ return ok ? 0 : 1;
+}
diff --git a/crypto/sha/sha256.c b/crypto/sha/sha256.c
new file mode 100644
index 0000000..0685784
--- /dev/null
+++ b/crypto/sha/sha256.c
@@ -0,0 +1,365 @@
+/* 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/sha.h>
+
+#include <string.h>
+
+#include <openssl/mem.h>
+
+
+#if !defined(OPENSSL_NO_ASM) && \
+ (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || defined(OPENSSL_ARM))
+#define SHA256_ASM
+#endif
+
+int SHA224_Init(SHA256_CTX *sha) {
+ memset(sha, 0, sizeof(SHA256_CTX));
+ sha->h[0] = 0xc1059ed8UL;
+ sha->h[1] = 0x367cd507UL;
+ sha->h[2] = 0x3070dd17UL;
+ sha->h[3] = 0xf70e5939UL;
+ sha->h[4] = 0xffc00b31UL;
+ sha->h[5] = 0x68581511UL;
+ sha->h[6] = 0x64f98fa7UL;
+ sha->h[7] = 0xbefa4fa4UL;
+ sha->md_len = SHA224_DIGEST_LENGTH;
+ return 1;
+}
+
+int SHA256_Init(SHA256_CTX *sha) {
+ memset(sha, 0, sizeof(SHA256_CTX));
+ sha->h[0] = 0x6a09e667UL;
+ sha->h[1] = 0xbb67ae85UL;
+ sha->h[2] = 0x3c6ef372UL;
+ sha->h[3] = 0xa54ff53aUL;
+ sha->h[4] = 0x510e527fUL;
+ sha->h[5] = 0x9b05688cUL;
+ sha->h[6] = 0x1f83d9abUL;
+ sha->h[7] = 0x5be0cd19UL;
+ sha->md_len = SHA256_DIGEST_LENGTH;
+ return 1;
+}
+
+uint8_t *SHA224(const uint8_t *data, size_t len, uint8_t *out) {
+ SHA256_CTX ctx;
+ static uint8_t buf[SHA224_DIGEST_LENGTH];
+
+ /* TODO(fork): remove this static buffer. */
+ if (out == NULL) {
+ out = buf;
+ }
+ SHA224_Init(&ctx);
+ SHA256_Update(&ctx, data, len);
+ SHA256_Final(out, &ctx);
+ OPENSSL_cleanse(&ctx, sizeof(ctx));
+ return out;
+}
+
+uint8_t *SHA256(const uint8_t *data, size_t len, uint8_t *out) {
+ SHA256_CTX ctx;
+ static uint8_t buf[SHA256_DIGEST_LENGTH];
+
+ /* TODO(fork): remove this static buffer. */
+ if (out == NULL) {
+ out = buf;
+ }
+ SHA256_Init(&ctx);
+ SHA256_Update(&ctx, data, len);
+ SHA256_Final(out, &ctx);
+ OPENSSL_cleanse(&ctx, sizeof(ctx));
+ return out;
+}
+
+int SHA224_Update(SHA256_CTX *ctx, const void *data, size_t len) {
+ return SHA256_Update(ctx, data, len);
+}
+
+int SHA224_Final(uint8_t *md, SHA256_CTX *ctx) {
+ return SHA256_Final(md, ctx);
+}
+
+#define DATA_ORDER_IS_BIG_ENDIAN
+
+#define HASH_LONG uint32_t
+#define HASH_CTX SHA256_CTX
+#define HASH_CBLOCK 64
+
+/* Note that FIPS180-2 discusses "Truncation of the Hash Function Output."
+ * default: case below covers for it. It's not clear however if it's permitted
+ * to truncate to amount of bytes not divisible by 4. I bet not, but if it is,
+ * then default: case shall be extended. For reference. Idea behind separate
+ * cases for pre-defined lenghts is to let the compiler decide if it's
+ * appropriate to unroll small loops. */
+#define HASH_MAKE_STRING(c, s) \
+ do { \
+ unsigned long ll; \
+ unsigned int nn; \
+ switch ((c)->md_len) { \
+ case SHA224_DIGEST_LENGTH: \
+ for (nn = 0; nn < SHA224_DIGEST_LENGTH / 4; nn++) { \
+ ll = (c)->h[nn]; \
+ (void) HOST_l2c(ll, (s)); \
+ } \
+ break; \
+ case SHA256_DIGEST_LENGTH: \
+ for (nn = 0; nn < SHA256_DIGEST_LENGTH / 4; nn++) { \
+ ll = (c)->h[nn]; \
+ (void) HOST_l2c(ll, (s)); \
+ } \
+ break; \
+ default: \
+ if ((c)->md_len > SHA256_DIGEST_LENGTH) \
+ return 0; \
+ for (nn = 0; nn < (c)->md_len / 4; nn++) { \
+ ll = (c)->h[nn]; \
+ (void) HOST_l2c(ll, (s)); \
+ } \
+ break; \
+ } \
+ } while (0)
+
+
+#define HASH_UPDATE SHA256_Update
+#define HASH_TRANSFORM SHA256_Transform
+#define HASH_FINAL SHA256_Final
+#define HASH_BLOCK_DATA_ORDER sha256_block_data_order
+#ifndef SHA256_ASM
+static
+#endif
+void sha256_block_data_order(SHA256_CTX *ctx, const void *in, size_t num);
+
+#include "../digest/md32_common.h"
+
+#ifndef SHA256_ASM
+static const HASH_LONG K256[64] = {
+ 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
+ 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
+ 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
+ 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+ 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
+ 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
+ 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
+ 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+ 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
+ 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
+ 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
+ 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+ 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL};
+
+/* FIPS specification refers to right rotations, while our ROTATE macro
+ * is left one. This is why you might notice that rotation coefficients
+ * differ from those observed in FIPS document by 32-N... */
+#define Sigma0(x) (ROTATE((x), 30) ^ ROTATE((x), 19) ^ ROTATE((x), 10))
+#define Sigma1(x) (ROTATE((x), 26) ^ ROTATE((x), 21) ^ ROTATE((x), 7))
+#define sigma0(x) (ROTATE((x), 25) ^ ROTATE((x), 14) ^ ((x) >> 3))
+#define sigma1(x) (ROTATE((x), 15) ^ ROTATE((x), 13) ^ ((x) >> 10))
+
+#define Ch(x, y, z) (((x) & (y)) ^ ((~(x)) & (z)))
+#define Maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+
+#define ROUND_00_15(i, a, b, c, d, e, f, g, h) \
+ do { \
+ T1 += h + Sigma1(e) + Ch(e, f, g) + K256[i]; \
+ h = Sigma0(a) + Maj(a, b, c); \
+ d += T1; \
+ h += T1; \
+ } while (0)
+
+#define ROUND_16_63(i, a, b, c, d, e, f, g, h, X) \
+ do { \
+ s0 = X[(i + 1) & 0x0f]; \
+ s0 = sigma0(s0); \
+ s1 = X[(i + 14) & 0x0f]; \
+ s1 = sigma1(s1); \
+ T1 = X[(i) & 0x0f] += s0 + s1 + X[(i + 9) & 0x0f]; \
+ ROUND_00_15(i, a, b, c, d, e, f, g, h); \
+ } while (0)
+
+static void sha256_block_data_order(SHA256_CTX *ctx, const void *in,
+ size_t num) {
+ unsigned MD32_REG_T a, b, c, d, e, f, g, h, s0, s1, T1;
+ HASH_LONG X[16];
+ int i;
+ const uint8_t *data = in;
+ const union {
+ long one;
+ char little;
+ } is_endian = {1};
+
+ while (num--) {
+ a = ctx->h[0];
+ b = ctx->h[1];
+ c = ctx->h[2];
+ d = ctx->h[3];
+ e = ctx->h[4];
+ f = ctx->h[5];
+ g = ctx->h[6];
+ h = ctx->h[7];
+
+ if (!is_endian.little && sizeof(HASH_LONG) == 4 && ((size_t)in % 4) == 0) {
+ const HASH_LONG *W = (const HASH_LONG *)data;
+
+ T1 = X[0] = W[0];
+ ROUND_00_15(0, a, b, c, d, e, f, g, h);
+ T1 = X[1] = W[1];
+ ROUND_00_15(1, h, a, b, c, d, e, f, g);
+ T1 = X[2] = W[2];
+ ROUND_00_15(2, g, h, a, b, c, d, e, f);
+ T1 = X[3] = W[3];
+ ROUND_00_15(3, f, g, h, a, b, c, d, e);
+ T1 = X[4] = W[4];
+ ROUND_00_15(4, e, f, g, h, a, b, c, d);
+ T1 = X[5] = W[5];
+ ROUND_00_15(5, d, e, f, g, h, a, b, c);
+ T1 = X[6] = W[6];
+ ROUND_00_15(6, c, d, e, f, g, h, a, b);
+ T1 = X[7] = W[7];
+ ROUND_00_15(7, b, c, d, e, f, g, h, a);
+ T1 = X[8] = W[8];
+ ROUND_00_15(8, a, b, c, d, e, f, g, h);
+ T1 = X[9] = W[9];
+ ROUND_00_15(9, h, a, b, c, d, e, f, g);
+ T1 = X[10] = W[10];
+ ROUND_00_15(10, g, h, a, b, c, d, e, f);
+ T1 = X[11] = W[11];
+ ROUND_00_15(11, f, g, h, a, b, c, d, e);
+ T1 = X[12] = W[12];
+ ROUND_00_15(12, e, f, g, h, a, b, c, d);
+ T1 = X[13] = W[13];
+ ROUND_00_15(13, d, e, f, g, h, a, b, c);
+ T1 = X[14] = W[14];
+ ROUND_00_15(14, c, d, e, f, g, h, a, b);
+ T1 = X[15] = W[15];
+ ROUND_00_15(15, b, c, d, e, f, g, h, a);
+
+ data += HASH_CBLOCK;
+ } else {
+ HASH_LONG l;
+
+ HOST_c2l(data, l);
+ T1 = X[0] = l;
+ ROUND_00_15(0, a, b, c, d, e, f, g, h);
+ HOST_c2l(data, l);
+ T1 = X[1] = l;
+ ROUND_00_15(1, h, a, b, c, d, e, f, g);
+ HOST_c2l(data, l);
+ T1 = X[2] = l;
+ ROUND_00_15(2, g, h, a, b, c, d, e, f);
+ HOST_c2l(data, l);
+ T1 = X[3] = l;
+ ROUND_00_15(3, f, g, h, a, b, c, d, e);
+ HOST_c2l(data, l);
+ T1 = X[4] = l;
+ ROUND_00_15(4, e, f, g, h, a, b, c, d);
+ HOST_c2l(data, l);
+ T1 = X[5] = l;
+ ROUND_00_15(5, d, e, f, g, h, a, b, c);
+ HOST_c2l(data, l);
+ T1 = X[6] = l;
+ ROUND_00_15(6, c, d, e, f, g, h, a, b);
+ HOST_c2l(data, l);
+ T1 = X[7] = l;
+ ROUND_00_15(7, b, c, d, e, f, g, h, a);
+ HOST_c2l(data, l);
+ T1 = X[8] = l;
+ ROUND_00_15(8, a, b, c, d, e, f, g, h);
+ HOST_c2l(data, l);
+ T1 = X[9] = l;
+ ROUND_00_15(9, h, a, b, c, d, e, f, g);
+ HOST_c2l(data, l);
+ T1 = X[10] = l;
+ ROUND_00_15(10, g, h, a, b, c, d, e, f);
+ HOST_c2l(data, l);
+ T1 = X[11] = l;
+ ROUND_00_15(11, f, g, h, a, b, c, d, e);
+ HOST_c2l(data, l);
+ T1 = X[12] = l;
+ ROUND_00_15(12, e, f, g, h, a, b, c, d);
+ HOST_c2l(data, l);
+ T1 = X[13] = l;
+ ROUND_00_15(13, d, e, f, g, h, a, b, c);
+ HOST_c2l(data, l);
+ T1 = X[14] = l;
+ ROUND_00_15(14, c, d, e, f, g, h, a, b);
+ HOST_c2l(data, l);
+ T1 = X[15] = l;
+ ROUND_00_15(15, b, c, d, e, f, g, h, a);
+ }
+
+ for (i = 16; i < 64; i += 8) {
+ ROUND_16_63(i + 0, a, b, c, d, e, f, g, h, X);
+ ROUND_16_63(i + 1, h, a, b, c, d, e, f, g, X);
+ ROUND_16_63(i + 2, g, h, a, b, c, d, e, f, X);
+ ROUND_16_63(i + 3, f, g, h, a, b, c, d, e, X);
+ ROUND_16_63(i + 4, e, f, g, h, a, b, c, d, X);
+ ROUND_16_63(i + 5, d, e, f, g, h, a, b, c, X);
+ ROUND_16_63(i + 6, c, d, e, f, g, h, a, b, X);
+ ROUND_16_63(i + 7, b, c, d, e, f, g, h, a, X);
+ }
+
+ ctx->h[0] += a;
+ ctx->h[1] += b;
+ ctx->h[2] += c;
+ ctx->h[3] += d;
+ ctx->h[4] += e;
+ ctx->h[5] += f;
+ ctx->h[6] += g;
+ ctx->h[7] += h;
+ }
+}
+
+#endif /* SHA256_ASM */
diff --git a/crypto/sha/sha512.c b/crypto/sha/sha512.c
new file mode 100644
index 0000000..dcaac6f
--- /dev/null
+++ b/crypto/sha/sha512.c
@@ -0,0 +1,590 @@
+/* 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/sha.h>
+
+#include <string.h>
+
+#include <openssl/mem.h>
+
+
+/* IMPLEMENTATION NOTES.
+ *
+ * As you might have noticed 32-bit hash algorithms:
+ *
+ * - permit SHA_LONG to be wider than 32-bit (case on CRAY);
+ * - optimized versions implement two transform functions: one operating
+ * on [aligned] data in host byte order and one - on data in input
+ * stream byte order;
+ * - share common byte-order neutral collector and padding function
+ * implementations, ../md32_common.h;
+ *
+ * Neither of the above applies to this SHA-512 implementations. Reasons
+ * [in reverse order] are:
+ *
+ * - it's the only 64-bit hash algorithm for the moment of this writing,
+ * there is no need for common collector/padding implementation [yet];
+ * - by supporting only one transform function [which operates on
+ * *aligned* data in input stream byte order, big-endian in this case]
+ * we minimize burden of maintenance in two ways: a) collector/padding
+ * function is simpler; b) only one transform function to stare at;
+ * - SHA_LONG64 is required to be exactly 64-bit in order to be able to
+ * apply a number of optimizations to mitigate potential performance
+ * penalties caused by previous design decision; */
+
+#if !defined(OPENSSL_NO_ASM) && \
+ (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || defined(OPENSSL_ARM))
+#define SHA512_BLOCK_CAN_MANAGE_UNALIGNED_DATA
+#define SHA512_ASM
+#endif
+
+int SHA384_Init(SHA512_CTX *sha) {
+ sha->h[0] = 0xcbbb9d5dc1059ed8;
+ sha->h[1] = 0x629a292a367cd507;
+ sha->h[2] = 0x9159015a3070dd17;
+ sha->h[3] = 0x152fecd8f70e5939;
+ sha->h[4] = 0x67332667ffc00b31;
+ sha->h[5] = 0x8eb44a8768581511;
+ sha->h[6] = 0xdb0c2e0d64f98fa7;
+ sha->h[7] = 0x47b5481dbefa4fa4;
+
+ sha->Nl = 0;
+ sha->Nh = 0;
+ sha->num = 0;
+ sha->md_len = SHA384_DIGEST_LENGTH;
+ return 1;
+}
+
+
+int SHA512_Init(SHA512_CTX *sha) {
+ sha->h[0] = 0x6a09e667f3bcc908;
+ sha->h[1] = 0xbb67ae8584caa73b;
+ sha->h[2] = 0x3c6ef372fe94f82b;
+ sha->h[3] = 0xa54ff53a5f1d36f1;
+ sha->h[4] = 0x510e527fade682d1;
+ sha->h[5] = 0x9b05688c2b3e6c1f;
+ sha->h[6] = 0x1f83d9abfb41bd6b;
+ sha->h[7] = 0x5be0cd19137e2179;
+
+ sha->Nl = 0;
+ sha->Nh = 0;
+ sha->num = 0;
+ sha->md_len = SHA512_DIGEST_LENGTH;
+ return 1;
+}
+
+uint8_t *SHA384(const uint8_t *data, size_t len, uint8_t *out) {
+ SHA512_CTX ctx;
+ static uint8_t buf[SHA384_DIGEST_LENGTH];
+
+ /* TODO(fork): remove this static buffer. */
+ if (out == NULL) {
+ out = buf;
+ }
+
+ SHA384_Init(&ctx);
+ SHA512_Update(&ctx, data, len);
+ SHA512_Final(out, &ctx);
+ OPENSSL_cleanse(&ctx, sizeof(ctx));
+ return out;
+}
+
+uint8_t *SHA512(const uint8_t *data, size_t len, uint8_t *out) {
+ SHA512_CTX ctx;
+ static uint8_t buf[SHA512_DIGEST_LENGTH];
+
+ /* TODO(fork): remove this static buffer. */
+ if (out == NULL) {
+ out = buf;
+ }
+ SHA512_Init(&ctx);
+ SHA512_Update(&ctx, data, len);
+ SHA512_Final(out, &ctx);
+ OPENSSL_cleanse(&ctx, sizeof(ctx));
+ return out;
+}
+
+#if !defined(SHA512_ASM)
+static
+#endif
+void sha512_block_data_order(SHA512_CTX *ctx, const void *in, size_t num);
+
+
+int SHA384_Final(unsigned char *md, SHA512_CTX *sha) {
+ return SHA512_Final(md, sha);
+}
+
+int SHA384_Update(SHA512_CTX *sha, const void *data, size_t len) {
+ return SHA512_Update(sha, data, len);
+}
+
+void SHA512_Transform(SHA512_CTX *c, const unsigned char *data) {
+#ifndef SHA512_BLOCK_CAN_MANAGE_UNALIGNED_DATA
+ if ((size_t)data % sizeof(c->u.d[0]) != 0) {
+ memcpy(c->u.p, data, sizeof(c->u.p));
+ data = c->u.p;
+ }
+#endif
+ sha512_block_data_order(c, data, 1);
+}
+
+int SHA512_Update(SHA512_CTX *c, const void *in_data, size_t len) {
+ uint64_t l;
+ uint8_t *p = c->u.p;
+ const uint8_t *data = (const uint8_t *)in_data;
+
+ if (len == 0)
+ return 1;
+
+ l = (c->Nl + (((uint64_t)len) << 3)) & 0xffffffffffffffff;
+ if (l < c->Nl) {
+ c->Nh++;
+ }
+ if (sizeof(len) >= 8) {
+ c->Nh += (((uint64_t)len) >> 61);
+ }
+ c->Nl = l;
+
+ if (c->num != 0) {
+ size_t n = sizeof(c->u) - c->num;
+
+ if (len < n) {
+ memcpy(p + c->num, data, len);
+ c->num += (unsigned int)len;
+ return 1;
+ } else {
+ memcpy(p + c->num, data, n), c->num = 0;
+ len -= n;
+ data += n;
+ sha512_block_data_order(c, p, 1);
+ }
+ }
+
+ if (len >= sizeof(c->u)) {
+#ifndef SHA512_BLOCK_CAN_MANAGE_UNALIGNED_DATA
+ if ((size_t)data % sizeof(c->u.d[0]) != 0)
+ while (len >= sizeof(c->u))
+ memcpy(p, data, sizeof(c->u)), sha512_block_data_order(c, p, 1),
+ len -= sizeof(c->u), data += sizeof(c->u);
+ else
+#endif
+ sha512_block_data_order(c, data, len / sizeof(c->u)), data += len,
+ len %= sizeof(c->u), data -= len;
+ }
+
+ if (len != 0) {
+ memcpy(p, data, len);
+ c->num = (int)len;
+ }
+
+ return 1;
+}
+
+int SHA512_Final(unsigned char *md, SHA512_CTX *sha) {
+ uint8_t *p = (uint8_t *)sha->u.p;
+ size_t n = sha->num;
+
+ p[n] = 0x80; /* There always is a room for one */
+ n++;
+ if (n > (sizeof(sha->u) - 16)) {
+ memset(p + n, 0, sizeof(sha->u) - n);
+ n = 0;
+ sha512_block_data_order(sha, p, 1);
+ }
+
+ memset(p + n, 0, sizeof(sha->u) - 16 - n);
+ p[sizeof(sha->u) - 1] = (uint8_t)(sha->Nl);
+ p[sizeof(sha->u) - 2] = (uint8_t)(sha->Nl >> 8);
+ p[sizeof(sha->u) - 3] = (uint8_t)(sha->Nl >> 16);
+ p[sizeof(sha->u) - 4] = (uint8_t)(sha->Nl >> 24);
+ p[sizeof(sha->u) - 5] = (uint8_t)(sha->Nl >> 32);
+ p[sizeof(sha->u) - 6] = (uint8_t)(sha->Nl >> 40);
+ p[sizeof(sha->u) - 7] = (uint8_t)(sha->Nl >> 48);
+ p[sizeof(sha->u) - 8] = (uint8_t)(sha->Nl >> 56);
+ p[sizeof(sha->u) - 9] = (uint8_t)(sha->Nh);
+ p[sizeof(sha->u) - 10] = (uint8_t)(sha->Nh >> 8);
+ p[sizeof(sha->u) - 11] = (uint8_t)(sha->Nh >> 16);
+ p[sizeof(sha->u) - 12] = (uint8_t)(sha->Nh >> 24);
+ p[sizeof(sha->u) - 13] = (uint8_t)(sha->Nh >> 32);
+ p[sizeof(sha->u) - 14] = (uint8_t)(sha->Nh >> 40);
+ p[sizeof(sha->u) - 15] = (uint8_t)(sha->Nh >> 48);
+ p[sizeof(sha->u) - 16] = (uint8_t)(sha->Nh >> 56);
+
+ sha512_block_data_order(sha, p, 1);
+
+ if (md == 0) {
+ return 0;
+ }
+
+ switch (sha->md_len) {
+ /* Let compiler decide if it's appropriate to unroll... */
+ case SHA384_DIGEST_LENGTH:
+ for (n = 0; n < SHA384_DIGEST_LENGTH / 8; n++) {
+ uint64_t t = sha->h[n];
+
+ *(md++) = (uint8_t)(t >> 56);
+ *(md++) = (uint8_t)(t >> 48);
+ *(md++) = (uint8_t)(t >> 40);
+ *(md++) = (uint8_t)(t >> 32);
+ *(md++) = (uint8_t)(t >> 24);
+ *(md++) = (uint8_t)(t >> 16);
+ *(md++) = (uint8_t)(t >> 8);
+ *(md++) = (uint8_t)(t);
+ }
+ break;
+ case SHA512_DIGEST_LENGTH:
+ for (n = 0; n < SHA512_DIGEST_LENGTH / 8; n++) {
+ uint64_t t = sha->h[n];
+
+ *(md++) = (uint8_t)(t >> 56);
+ *(md++) = (uint8_t)(t >> 48);
+ *(md++) = (uint8_t)(t >> 40);
+ *(md++) = (uint8_t)(t >> 32);
+ *(md++) = (uint8_t)(t >> 24);
+ *(md++) = (uint8_t)(t >> 16);
+ *(md++) = (uint8_t)(t >> 8);
+ *(md++) = (uint8_t)(t);
+ }
+ break;
+ /* ... as well as make sure md_len is not abused. */
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+#ifndef SHA512_ASM
+static const uint64_t K512[80] = {
+ 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f,
+ 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019,
+ 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242,
+ 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
+ 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235,
+ 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3,
+ 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 0x2de92c6f592b0275,
+ 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
+ 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f,
+ 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725,
+ 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc,
+ 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
+ 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6,
+ 0x92722c851482353b, 0xa2bfe8a14cf10364, 0xa81a664bbc423001,
+ 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218,
+ 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
+ 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99,
+ 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb,
+ 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc,
+ 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
+ 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915,
+ 0xc67178f2e372532b, 0xca273eceea26619c, 0xd186b8c721c0c207,
+ 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba,
+ 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
+ 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc,
+ 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a,
+ 0x5fcb6fab3ad6faec, 0x6c44198c4a475817};
+
+#if defined(__GNUC__) && __GNUC__ >= 2 && !defined(OPENSSL_NO_ASM)
+#if defined(__x86_64) || defined(__x86_64__)
+#define ROTR(a, n) \
+ ({ \
+ uint64_t ret; \
+ asm("rorq %1,%0" : "=r"(ret) : "J"(n), "0"(a) : "cc"); \
+ ret; \
+ })
+#define PULL64(x) \
+ ({ \
+ uint64_t ret = *((const uint64_t *)(&(x))); \
+ asm("bswapq %0" : "=r"(ret) : "0"(ret)); \
+ ret; \
+ })
+#elif(defined(__i386) || defined(__i386__))
+#define PULL64(x) \
+ ({ \
+ const unsigned int *p = (const unsigned int *)(&(x)); \
+ unsigned int hi = p[0], lo = p[1]; \
+ asm("bswapl %0; bswapl %1;" : "=r"(lo), "=r"(hi) : "0"(lo), "1"(hi)); \
+ ((uint64_t)hi) << 32 | lo; \
+ })
+#elif(defined(_ARCH_PPC) && defined(__64BIT__)) || defined(_ARCH_PPC64)
+#define ROTR(a, n) \
+ ({ \
+ uint64_t ret; \
+ asm("rotrdi %0,%1,%2" : "=r"(ret) : "r"(a), "K"(n)); \
+ ret; \
+ })
+#elif defined(__aarch64__)
+#define ROTR(a, n) \
+ ({ \
+ uint64_t ret; \
+ asm("ror %0,%1,%2" : "=r"(ret) : "r"(a), "I"(n)); \
+ ret; \
+ })
+#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
+ __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define PULL64(x) \
+ ({ \
+ uint64_t ret; \
+ asm("rev %0,%1" : "=r"(ret) : "r"(*((const uint64_t *)(&(x))))); \
+ ret; \
+ })
+#endif
+#endif
+#elif defined(_MSC_VER)
+#if defined(_WIN64) /* applies to both IA-64 and AMD64 */
+#pragma intrinsic(_rotr64)
+#define ROTR(a, n) _rotr64((a), n)
+#endif
+#if defined(_M_IX86) && !defined(OPENSSL_NO_ASM)
+static uint64_t __fastcall __pull64be(const void *x) {
+ _asm mov edx, [ecx + 0]
+ _asm mov eax, [ecx + 4]
+ _asm bswap edx
+ _asm bswap eax
+}
+#define PULL64(x) __pull64be(&(x))
+#if _MSC_VER <= 1200
+#pragma inline_depth(0)
+#endif
+#endif
+#endif
+
+#ifndef PULL64
+#define B(x, j) \
+ (((uint64_t)(*(((const unsigned char *)(&x)) + j))) << ((7 - j) * 8))
+#define PULL64(x) \
+ (B(x, 0) | B(x, 1) | B(x, 2) | B(x, 3) | B(x, 4) | B(x, 5) | B(x, 6) | \
+ B(x, 7))
+#endif
+
+#ifndef ROTR
+#define ROTR(x, s) (((x) >> s) | (x) << (64 - s))
+#endif
+
+#define Sigma0(x) (ROTR((x), 28) ^ ROTR((x), 34) ^ ROTR((x), 39))
+#define Sigma1(x) (ROTR((x), 14) ^ ROTR((x), 18) ^ ROTR((x), 41))
+#define sigma0(x) (ROTR((x), 1) ^ ROTR((x), 8) ^ ((x) >> 7))
+#define sigma1(x) (ROTR((x), 19) ^ ROTR((x), 61) ^ ((x) >> 6))
+
+#define Ch(x, y, z) (((x) & (y)) ^ ((~(x)) & (z)))
+#define Maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+
+
+#if defined(__i386) || defined(__i386__) || defined(_M_IX86)
+/*
+ * This code should give better results on 32-bit CPU with less than
+ * ~24 registers, both size and performance wise...
+ */
+static void sha512_block_data_order(SHA512_CTX *ctx, const void *in,
+ size_t num) {
+ const uint64_t *W = in;
+ uint64_t A, E, T;
+ uint64_t X[9 + 80], *F;
+ int i;
+
+ while (num--) {
+ F = X + 80;
+ A = ctx->h[0];
+ F[1] = ctx->h[1];
+ F[2] = ctx->h[2];
+ F[3] = ctx->h[3];
+ E = ctx->h[4];
+ F[5] = ctx->h[5];
+ F[6] = ctx->h[6];
+ F[7] = ctx->h[7];
+
+ for (i = 0; i < 16; i++, F--) {
+ T = PULL64(W[i]);
+ F[0] = A;
+ F[4] = E;
+ F[8] = T;
+ T += F[7] + Sigma1(E) + Ch(E, F[5], F[6]) + K512[i];
+ E = F[3] + T;
+ A = T + Sigma0(A) + Maj(A, F[1], F[2]);
+ }
+
+ for (; i < 80; i++, F--) {
+ T = sigma0(F[8 + 16 - 1]);
+ T += sigma1(F[8 + 16 - 14]);
+ T += F[8 + 16] + F[8 + 16 - 9];
+
+ F[0] = A;
+ F[4] = E;
+ F[8] = T;
+ T += F[7] + Sigma1(E) + Ch(E, F[5], F[6]) + K512[i];
+ E = F[3] + T;
+ A = T + Sigma0(A) + Maj(A, F[1], F[2]);
+ }
+
+ ctx->h[0] += A;
+ ctx->h[1] += F[1];
+ ctx->h[2] += F[2];
+ ctx->h[3] += F[3];
+ ctx->h[4] += E;
+ ctx->h[5] += F[5];
+ ctx->h[6] += F[6];
+ ctx->h[7] += F[7];
+
+ W += 16;
+ }
+}
+
+#else
+
+#define ROUND_00_15(i, a, b, c, d, e, f, g, h) \
+ do { \
+ T1 += h + Sigma1(e) + Ch(e, f, g) + K512[i]; \
+ h = Sigma0(a) + Maj(a, b, c); \
+ d += T1; \
+ h += T1; \
+ } while (0)
+
+#define ROUND_16_80(i, j, a, b, c, d, e, f, g, h, X) \
+ do { \
+ s0 = X[(j + 1) & 0x0f]; \
+ s0 = sigma0(s0); \
+ s1 = X[(j + 14) & 0x0f]; \
+ s1 = sigma1(s1); \
+ T1 = X[(j) & 0x0f] += s0 + s1 + X[(j + 9) & 0x0f]; \
+ ROUND_00_15(i + j, a, b, c, d, e, f, g, h); \
+ } while (0)
+
+static void sha512_block_data_order(SHA512_CTX *ctx, const void *in,
+ size_t num) {
+ const uint64_t *W = in;
+ uint64_t a, b, c, d, e, f, g, h, s0, s1, T1;
+ uint64_t X[16];
+ int i;
+
+ while (num--) {
+
+ a = ctx->h[0];
+ b = ctx->h[1];
+ c = ctx->h[2];
+ d = ctx->h[3];
+ e = ctx->h[4];
+ f = ctx->h[5];
+ g = ctx->h[6];
+ h = ctx->h[7];
+
+ T1 = X[0] = PULL64(W[0]);
+ ROUND_00_15(0, a, b, c, d, e, f, g, h);
+ T1 = X[1] = PULL64(W[1]);
+ ROUND_00_15(1, h, a, b, c, d, e, f, g);
+ T1 = X[2] = PULL64(W[2]);
+ ROUND_00_15(2, g, h, a, b, c, d, e, f);
+ T1 = X[3] = PULL64(W[3]);
+ ROUND_00_15(3, f, g, h, a, b, c, d, e);
+ T1 = X[4] = PULL64(W[4]);
+ ROUND_00_15(4, e, f, g, h, a, b, c, d);
+ T1 = X[5] = PULL64(W[5]);
+ ROUND_00_15(5, d, e, f, g, h, a, b, c);
+ T1 = X[6] = PULL64(W[6]);
+ ROUND_00_15(6, c, d, e, f, g, h, a, b);
+ T1 = X[7] = PULL64(W[7]);
+ ROUND_00_15(7, b, c, d, e, f, g, h, a);
+ T1 = X[8] = PULL64(W[8]);
+ ROUND_00_15(8, a, b, c, d, e, f, g, h);
+ T1 = X[9] = PULL64(W[9]);
+ ROUND_00_15(9, h, a, b, c, d, e, f, g);
+ T1 = X[10] = PULL64(W[10]);
+ ROUND_00_15(10, g, h, a, b, c, d, e, f);
+ T1 = X[11] = PULL64(W[11]);
+ ROUND_00_15(11, f, g, h, a, b, c, d, e);
+ T1 = X[12] = PULL64(W[12]);
+ ROUND_00_15(12, e, f, g, h, a, b, c, d);
+ T1 = X[13] = PULL64(W[13]);
+ ROUND_00_15(13, d, e, f, g, h, a, b, c);
+ T1 = X[14] = PULL64(W[14]);
+ ROUND_00_15(14, c, d, e, f, g, h, a, b);
+ T1 = X[15] = PULL64(W[15]);
+ ROUND_00_15(15, b, c, d, e, f, g, h, a);
+
+ for (i = 16; i < 80; i += 16) {
+ ROUND_16_80(i, 0, a, b, c, d, e, f, g, h, X);
+ ROUND_16_80(i, 1, h, a, b, c, d, e, f, g, X);
+ ROUND_16_80(i, 2, g, h, a, b, c, d, e, f, X);
+ ROUND_16_80(i, 3, f, g, h, a, b, c, d, e, X);
+ ROUND_16_80(i, 4, e, f, g, h, a, b, c, d, X);
+ ROUND_16_80(i, 5, d, e, f, g, h, a, b, c, X);
+ ROUND_16_80(i, 6, c, d, e, f, g, h, a, b, X);
+ ROUND_16_80(i, 7, b, c, d, e, f, g, h, a, X);
+ ROUND_16_80(i, 8, a, b, c, d, e, f, g, h, X);
+ ROUND_16_80(i, 9, h, a, b, c, d, e, f, g, X);
+ ROUND_16_80(i, 10, g, h, a, b, c, d, e, f, X);
+ ROUND_16_80(i, 11, f, g, h, a, b, c, d, e, X);
+ ROUND_16_80(i, 12, e, f, g, h, a, b, c, d, X);
+ ROUND_16_80(i, 13, d, e, f, g, h, a, b, c, X);
+ ROUND_16_80(i, 14, c, d, e, f, g, h, a, b, X);
+ ROUND_16_80(i, 15, b, c, d, e, f, g, h, a, X);
+ }
+
+ ctx->h[0] += a;
+ ctx->h[1] += b;
+ ctx->h[2] += c;
+ ctx->h[3] += d;
+ ctx->h[4] += e;
+ ctx->h[5] += f;
+ ctx->h[6] += g;
+ ctx->h[7] += h;
+
+ W += 16;
+ }
+}
+
+#endif
+
+#endif /* SHA512_ASM */
diff --git a/crypto/stack/CMakeLists.txt b/crypto/stack/CMakeLists.txt
new file mode 100644
index 0000000..62645c5
--- /dev/null
+++ b/crypto/stack/CMakeLists.txt
@@ -0,0 +1,9 @@
+include_directories(. .. ../../include)
+
+add_library(
+ stack
+
+ OBJECT
+
+ stack.c
+)
diff --git a/crypto/stack/make_macros.sh b/crypto/stack/make_macros.sh
new file mode 100644
index 0000000..84ca478
--- /dev/null
+++ b/crypto/stack/make_macros.sh
@@ -0,0 +1,104 @@
+#!/bin/sh
+
+cat > stack_macros.h << EOF
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#if !defined(IN_STACK_H)
+#error "Don't include this file directly. Include stack.h."
+#endif
+
+EOF
+
+output_stack () {
+ type=$1
+ star=$2
+
+ cat >> stack_macros.h << EOF
+/* ${type} */
+#define sk_${type}_new(comp)\\
+ ((STACK_OF(${type})*) sk_new(CHECKED_CAST(stack_cmp_func, int (*) (const ${type} *${star}a, const ${type} *${star}b), comp)))
+
+#define sk_${type}_new_null()\\
+ ((STACK_OF(${type})*) sk_new_null())
+
+#define sk_${type}_num(sk)\\
+ sk_num(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk))
+
+#define sk_${type}_zero(sk)\\
+ sk_zero(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk));
+
+#define sk_${type}_value(sk, i)\\
+ ((${type}${star}) sk_value(CHECKED_CAST(_STACK*, const STACK_OF(${type})*, sk), (i)))
+
+#define sk_${type}_set(sk, i, p)\\
+ ((${type}${star}) sk_set(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), (i), CHECKED_CAST(void*, ${type}${star}, p)))
+
+#define sk_${type}_free(sk)\\
+ sk_free(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk))
+
+#define sk_${type}_pop_free(sk, free_func)\\
+ sk_pop_free(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), CHECKED_CAST(void (*) (void*), void (*) (${type}${star}), free_func))
+
+#define sk_${type}_insert(sk, p, where)\\
+ sk_insert(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), CHECKED_CAST(void*, ${type}${star}, p), (where))
+
+#define sk_${type}_delete(sk, where)\\
+ ((${type}${star}) sk_delete(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), (where)))
+
+#define sk_${type}_delete_ptr(sk, p)\\
+ ((${type}${star}) sk_delete_ptr(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), CHECKED_CAST(void*, ${type}${star}, p)))
+
+#define sk_${type}_find(sk, out_index, p)\\
+ sk_find(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), (out_index), CHECKED_CAST(void*, ${type}${star}, p))
+
+#define sk_${type}_shift(sk)\\
+ ((${type}${star}) sk_shift(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk)))
+
+#define sk_${type}_push(sk, p)\\
+ sk_push(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), CHECKED_CAST(void*, ${type}${star}, p))
+
+#define sk_${type}_pop(sk)\\
+ ((${type}${star}) sk_pop(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk)))
+
+#define sk_${type}_dup(sk)\\
+ ((STACK_OF(${type})*) sk_dup(CHECKED_CAST(_STACK*, const STACK_OF(${type})*, sk)))
+
+#define sk_${type}_sort(sk)\\
+ sk_sort(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk))
+
+#define sk_${type}_is_sorted(sk)\\
+ sk_is_sorted(CHECKED_CAST(_STACK*, const STACK_OF(${type})*, sk))
+
+#define sk_${type}_set_cmp_func(sk, comp)\\
+ ((int (*) (const ${type} **a, const ${type} **b)) sk_set_cmp_func(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), CHECKED_CAST(stack_cmp_func, int (*) (const ${type} **a, const ${type} **b), comp)))
+
+
+EOF
+}
+
+stack_types=$(cat stack.h | grep '^ \* STACK_OF:' | sed -e 's/.*STACK_OF://' -e 's/ .*//')
+special_stack_types=$(cat stack.h | grep '^ \* SPECIAL_STACK_OF:' | sed -e 's/.*SPECIAL_STACK_OF://' -e 's/ .*//')
+
+for type in $stack_types; do
+ echo Stack of ${type}
+ output_stack "${type}" "*"
+done
+
+for type in $special_stack_types; do
+ echo Stack of ${type}
+ output_stack "${type}" ""
+done
+
+clang-format -i stack_macros.h
diff --git a/crypto/stack/stack.c b/crypto/stack/stack.c
new file mode 100644
index 0000000..074b1e1
--- /dev/null
+++ b/crypto/stack/stack.c
@@ -0,0 +1,360 @@
+/* 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 "stack.h"
+
+#include <openssl/mem.h>
+
+/* kMinSize is the number of pointers that will be initially allocated in a new
+ * stack. */
+static const size_t kMinSize = 4;
+
+_STACK *sk_new(stack_cmp_func comp) {
+ _STACK *ret;
+
+ ret = OPENSSL_malloc(sizeof(_STACK));
+ if (ret == NULL) {
+ goto err;
+ }
+ memset(ret, 0, sizeof(_STACK));
+
+ ret->data = OPENSSL_malloc(sizeof(void *) * kMinSize);
+ if (ret->data == NULL) {
+ goto err;
+ }
+
+ memset(ret->data, 0, sizeof(void *) * kMinSize);
+
+ ret->comp = comp;
+ ret->num_alloc = kMinSize;
+
+ return ret;
+
+err:
+ if (ret) {
+ OPENSSL_free(ret);
+ }
+ return NULL;
+}
+
+_STACK *sk_new_null(void) { return sk_new(NULL); }
+
+size_t sk_num(const _STACK *sk) {
+ if (sk == NULL) {
+ return 0;
+ }
+ return sk->num;
+}
+
+void sk_zero(_STACK *sk) {
+ if (sk == NULL || sk->num == 0) {
+ return;
+ }
+ memset(sk->data, 0, sizeof(void*) * sk->num);
+ sk->num = 0;
+ sk->sorted = 0;
+}
+
+void *sk_value(const _STACK *sk, size_t i) {
+ if (!sk || i >= sk->num) {
+ return NULL;
+ }
+ return sk->data[i];
+}
+
+void *sk_set(_STACK *sk, size_t i, void *value) {
+ if (!sk || i >= sk->num) {
+ return NULL;
+ }
+ return sk->data[i] = value;
+}
+
+void sk_free(_STACK *sk) {
+ if (sk == NULL) {
+ return;
+ }
+ OPENSSL_free(sk->data);
+ OPENSSL_free(sk);
+}
+
+void sk_pop_free(_STACK *sk, void (*func)(void *)) {
+ size_t i;
+
+ if (sk == NULL) {
+ return;
+ }
+
+ for (i = 0; i < sk->num; i++) {
+ if (sk->data[i] != NULL) {
+ func(sk->data[i]);
+ }
+ }
+ sk_free(sk);
+}
+
+size_t sk_insert(_STACK *sk, void *p, size_t where) {
+ if (sk == NULL) {
+ return 0;
+ }
+
+ if (sk->num_alloc <= sk->num + 1) {
+ /* Attempt to double the size of the array. */
+ size_t new_alloc = sk->num_alloc << 1;
+ size_t alloc_size = new_alloc * sizeof(void *);
+ void **data;
+
+ /* If the doubling overflowed, try to increment. */
+ if (new_alloc < sk->num_alloc || alloc_size / sizeof(void *) != new_alloc) {
+ new_alloc = sk->num_alloc + 1;
+ alloc_size = new_alloc * sizeof(void *);
+ }
+
+ /* If the increment also overflowed, fail. */
+ if (new_alloc < sk->num_alloc || alloc_size / sizeof(void *) != new_alloc) {
+ return 0;
+ }
+
+ data = OPENSSL_realloc(sk->data, alloc_size);
+ if (data == NULL) {
+ return 0;
+ }
+
+ sk->data = data;
+ sk->num_alloc = new_alloc;
+ }
+
+ if (where >= sk->num) {
+ sk->data[sk->num] = p;
+ } else {
+ memmove(&sk->data[where + 1], &sk->data[where],
+ sizeof(void *) * (sk->num - where));
+ sk->data[where] = p;
+ }
+
+ sk->num++;
+ sk->sorted = 0;
+
+ return sk->num;
+}
+
+void *sk_delete(_STACK *sk, size_t where) {
+ void *ret;
+
+ if (!sk || where >= sk->num) {
+ return NULL;
+ }
+
+ ret = sk->data[where];
+
+ if (where != sk->num - 1) {
+ memmove(&sk->data[where], &sk->data[where + 1],
+ sizeof(void *) * (sk->num - where - 1));
+ }
+
+ sk->num--;
+ return ret;
+}
+
+void *sk_delete_ptr(_STACK *sk, void *p) {
+ size_t i;
+
+ if (sk == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; i < sk->num; i++) {
+ if (sk->data[i] == p) {
+ return sk_delete(sk, i);
+ }
+ }
+
+ return NULL;
+}
+
+int sk_find(_STACK *sk, size_t *out_index, void *p) {
+ const void *const *r;
+ size_t i;
+ int (*comp_func)(const void *,const void *);
+
+ if (sk == NULL) {
+ return -1;
+ }
+
+ if (sk->comp == NULL) {
+ /* Use pointer equality when no comparison function has been set. */
+ for (i = 0; i < sk->num; i++) {
+ if (sk->data[i] == p) {
+ if (out_index) {
+ *out_index = i;
+ }
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ if (p == NULL) {
+ return 0;
+ }
+
+ sk_sort(sk);
+
+ /* sk->comp is a function that takes pointers to pointers to elements, but
+ * qsort and bsearch take a comparison function that just takes pointers to
+ * elements. However, since we're passing an array of pointers to
+ * qsort/bsearch, we can just cast the comparison function and everything
+ * works. */
+ comp_func=(int (*)(const void *,const void *))(sk->comp);
+ r = bsearch(&p, sk->data, sk->num, sizeof(void *), comp_func);
+ if (r == NULL) {
+ return 0;
+ }
+ i = ((void **)r) - sk->data;
+ /* This function always returns the first result. */
+ while (i > 0 && sk->comp((const void**) &p, (const void**) &sk->data[i-1]) == 0) {
+ i--;
+ }
+ if (out_index) {
+ *out_index = i;
+ }
+ return 1;
+}
+
+void *sk_shift(_STACK *sk) {
+ if (sk == NULL) {
+ return NULL;
+ }
+ if (sk->num == 0) {
+ return NULL;
+ }
+ return sk_delete(sk, 0);
+}
+
+size_t sk_push(_STACK *sk, void *p) { return (sk_insert(sk, p, sk->num)); }
+
+void *sk_pop(_STACK *sk) {
+ if (sk == NULL) {
+ return NULL;
+ }
+ if (sk->num == 0) {
+ return NULL;
+ }
+ return sk_delete(sk, sk->num - 1);
+}
+
+_STACK *sk_dup(const _STACK *sk) {
+ _STACK *ret;
+ void **s;
+
+ if (sk == NULL) {
+ return NULL;
+ }
+
+ ret = sk_new(sk->comp);
+ if (ret == NULL) {
+ goto err;
+ }
+
+ s = (void **)OPENSSL_realloc(ret->data, sizeof(void *) * sk->num_alloc);
+ if (s == NULL) {
+ goto err;
+ }
+ ret->data = s;
+
+ ret->num = sk->num;
+ memcpy(ret->data, sk->data, sizeof(void *) * sk->num);
+ ret->sorted = sk->sorted;
+ ret->num_alloc = sk->num_alloc;
+ ret->comp = sk->comp;
+ return ret;
+
+err:
+ if (ret) {
+ sk_free(ret);
+ }
+ return NULL;
+}
+
+void sk_sort(_STACK *sk) {
+ int (*comp_func)(const void *,const void *);
+
+ if (sk == NULL || sk->sorted) {
+ return;
+ }
+
+ /* See the comment in sk_find about this cast. */
+ comp_func = (int (*)(const void *, const void *))(sk->comp);
+ qsort(sk->data, sk->num, sizeof(void *), comp_func);
+ sk->sorted = 1;
+}
+
+int sk_is_sorted(const _STACK *sk) {
+ if (!sk) {
+ return 1;
+ }
+ return sk->sorted;
+}
+
+stack_cmp_func sk_set_cmp_func(_STACK *sk, stack_cmp_func comp) {
+ stack_cmp_func old = sk->comp;
+
+ if (sk->comp != comp) {
+ sk->sorted = 0;
+ }
+ sk->comp = comp;
+
+ return old;
+}
diff --git a/crypto/stack/stack.h b/crypto/stack/stack.h
new file mode 100644
index 0000000..53bf167
--- /dev/null
+++ b/crypto/stack/stack.h
@@ -0,0 +1,291 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_STACK_H
+#define OPENSSL_HEADER_STACK_H
+
+#include <openssl/base.h>
+
+#include <openssl/type_check.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* A stack, in OpenSSL, is an array of pointers. They are the most commonly
+ * used collection object.
+ *
+ * This file defines macros for type safe use of the stack functions. A stack
+ * of a specific type of object has type |STACK_OF(type)|. This can be defined
+ * (once) with |DEFINE_STACK_OF(type)| and declared where needed with
+ * |DECLARE_STACK_OF(type)|. For example:
+ *
+ * struct foo {
+ * int bar;
+ * };
+ *
+ * DEFINE_STACK_OF(struct foo);
+ *
+ * Although note that the stack will contain /pointers/ to |foo|.
+ *
+ * A macro will be defined for each of the sk_* functions below. For
+ * STACK_OF(foo), the macros would be sk_foo_new, sk_foo_pop etc. */
+
+
+/* stack_cmp_func is a comparision function that returns a value < 0, 0 or > 0
+ * if |*a| is less than, equal to or greater than |*b|, respectively. Note the
+ * extra indirection - the function is given a pointer to a pointer to the
+ * element. This differs from the usual qsort/bsearch comparision function. */
+typedef int (*stack_cmp_func)(const void **a, const void **b);
+
+/* stack_st contains an array of pointers. It is not designed to be used
+ * directly, rather the wrapper macros should be used. */
+typedef struct stack_st {
+ /* num contains the number of valid pointers in |data|. */
+ size_t num;
+ void **data;
+ /* sorted is non-zero if the values pointed to by |data| are in ascending
+ * order, based on |comp|. */
+ size_t sorted;
+ /* num_alloc contains the number of pointers allocated in the buffer pointed
+ * to by |data|, which may be larger than |num|. */
+ size_t num_alloc;
+ /* comp is an optional comparision function. */
+ stack_cmp_func comp;
+} _STACK;
+
+
+#define STACK_OF(type) struct stack_st_##type
+
+#define DEFINE_STACK_OF(type) \
+STACK_OF(type) {\
+ _STACK stack; \
+};
+
+#define DECLARE_STACK_OF(type) STACK_OF(type);
+
+/* The make_macros.sh script in this directory parses the following lines and
+ * generates the stack_macros.h file that contains macros for the following
+ * types of stacks:
+ *
+ * STACK_OF:ACCESS_DESCRIPTION
+ * STACK_OF:ASN1_ADB_TABLE
+ * STACK_OF:ASN1_GENERALSTRING
+ * STACK_OF:ASN1_INTEGER
+ * STACK_OF:ASN1_OBJECT
+ * STACK_OF:ASN1_STRING_TABLE
+ * STACK_OF:ASN1_TYPE
+ * STACK_OF:ASN1_VALUE
+ * STACK_OF:BIO
+ * STACK_OF:BY_DIR_ENTRY
+ * STACK_OF:BY_DIR_HASH
+ * STACK_OF:CONF_VALUE
+ * STACK_OF:CRYPTO_EX_DATA_FUNCS
+ * STACK_OF:DIST_POINT
+ * STACK_OF:GENERAL_NAME
+ * STACK_OF:GENERAL_NAMES
+ * STACK_OF:GENERAL_SUBTREE
+ * STACK_OF:MIME_HEADER
+ * STACK_OF:PKCS7_SIGNER_INFO
+ * STACK_OF:PKCS7_RECIP_INFO
+ * STACK_OF:POLICYINFO
+ * STACK_OF:POLICYQUALINFO
+ * STACK_OF:POLICY_MAPPING
+ * STACK_OF:SRTP_PROTECTION_PROFILE
+ * STACK_OF:SSL_CIPHER
+ * STACK_OF:SSL_COMP
+ * STACK_OF:STACK_OF_X509_NAME_ENTRY
+ * STACK_OF:SXNETID
+ * STACK_OF:X509
+ * STACK_OF:X509V3_EXT_METHOD
+ * STACK_OF:X509_ALGOR
+ * STACK_OF:X509_ATTRIBUTE
+ * STACK_OF:X509_CRL
+ * STACK_OF:X509_EXTENSION
+ * STACK_OF:X509_INFO
+ * STACK_OF:X509_LOOKUP
+ * STACK_OF:X509_NAME
+ * STACK_OF:X509_NAME_ENTRY
+ * STACK_OF:X509_NAME_ENTRY
+ * STACK_OF:X509_OBJECT
+ * STACK_OF:X509_POLICY_DATA
+ * STACK_OF:X509_POLICY_NODE
+ * STACK_OF:X509_PURPOSE
+ * STACK_OF:X509_REVOKED
+ * STACK_OF:X509_TRUST
+ * STACK_OF:X509_VERIFY_PARAM
+ * STACK_OF:void */
+
+
+/* Some stacks are special because, although we would like STACK_OF(char *),
+ * that would actually be a stack of pointers to char*, but we just want to
+ * point to the string directly. In this case we call them "special" and use
+ * |DEFINE_SPECIAL_STACK_OF(type)| */
+#define DEFINE_SPECIAL_STACK_OF(type, inner) \
+ STACK_OF(type) { _STACK special_stack; }; \
+ OPENSSL_COMPILE_ASSERT(sizeof(type) == sizeof(void *), \
+ special_stack_of_non_pointer_##type);
+
+typedef char *OPENSSL_STRING;
+
+DEFINE_SPECIAL_STACK_OF(OPENSSL_STRING, char)
+DEFINE_SPECIAL_STACK_OF(OPENSSL_BLOCK, uint8_t)
+
+/* The make_macros.sh script in this directory parses the following lines and
+ * generates the stack_macros.h file that contains macros for the following
+ * types of stacks:
+ *
+ * SPECIAL_STACK_OF:OPENSSL_STRING
+ * SPECIAL_STACK_OF:OPENSSL_BLOCK */
+
+#define IN_STACK_H
+#include <openssl/stack_macros.h>
+#undef IN_STACK_H
+
+
+/* These are the raw stack functions, you shouldn't be using them. Rather you
+ * should be using the type stack macros implemented above. */
+
+/* sk_new creates a new, empty stack with the given comparision function, which
+ * may be zero. It returns the new stack or NULL on allocation failure. */
+_STACK *sk_new(stack_cmp_func comp);
+
+/* sk_new_null creates a new, empty stack. It returns the new stack or NULL on
+ * allocation failure. */
+_STACK *sk_new_null(void);
+
+/* sk_num returns the number of elements in |s|. */
+size_t sk_num(const _STACK *sk);
+
+/* sk_zero resets |sk| to the empty state but does nothing to free the
+ * individual elements themselves. */
+void sk_zero(_STACK *sk);
+
+/* sk_value returns the |i|th pointer in |sk|, or NULL if |i| is out of
+ * range. */
+void *sk_value(const _STACK *sk, size_t i);
+
+/* sk_set sets the |i|th pointer in |sk| to |p| and returns |p|. If |i| is out
+ * of range, it returns NULL. */
+void *sk_set(_STACK *sk, size_t i, void *p);
+
+/* sk_free frees the given stack and array of pointers, but does nothing to
+ * free the individual elements. Also see |sk_pop_free|. */
+void sk_free(_STACK *sk);
+
+/* sk_pop_free calls |free_func| on each element in the stack and then frees
+ * the stack itself. */
+void sk_pop_free(_STACK *sk, void (*free_func)(void *));
+
+/* sk_insert inserts |p| into the stack at index |where|, moving existing
+ * elements if needed. It returns the length of the new stack, or zero on
+ * error. */
+size_t sk_insert(_STACK *sk, void *p, size_t where);
+
+/* sk_delete removes the pointer at index |where|, moving other elements down
+ * if needed. It returns the removed pointer, or NULL if |where| is out of
+ * range. */
+void *sk_delete(_STACK *sk, size_t where);
+
+/* sk_delete_ptr removes, at most, one instance of |p| from the stack based on
+ * pointer equality. If an instance of |p| is found then |p| is returned,
+ * otherwise it returns NULL. */
+void *sk_delete_ptr(_STACK *sk, void *p);
+
+/* sk_find returns the first value in the stack equal to |p|. If a comparision
+ * function has been set on the stack, then equality is defined by it and the
+ * stack will be sorted if need be so that a binary search can be used.
+ * Otherwise pointer equality is used. If a matching element is found, its
+ * index is written to |*out_index| (if |out_index| is not NULL) and one is
+ * returned. Otherwise zero is returned. */
+int sk_find(_STACK *sk, size_t *out_index, void *p);
+
+/* sk_shift removes and returns the first element in the stack, or returns NULL
+ * if the stack is empty. */
+void *sk_shift(_STACK *sk);
+
+/* sk_push appends |p| to the stack and returns the length of the new stack, or
+ * 0 on allocation failure. */
+size_t sk_push(_STACK *sk, void *p);
+
+/* sk_pop returns and removes the last element on the stack, or NULL if the
+ * stack is empty. */
+void *sk_pop(_STACK *sk);
+
+/* sk_dup performs a shallow copy of a stack and returns the new stack, or NULL
+ * on error. */
+_STACK *sk_dup(const _STACK *sk);
+
+/* sk_sort sorts the elements of |sk| into ascending order based on the
+ * comparison function. The stack maintains a |sorted| flag and sorting an
+ * already sorted stack is a no-op. */
+void sk_sort(_STACK *sk);
+
+/* sk_is_sorted returns one if |sk| is known to be sorted and zero
+ * otherwise. */
+int sk_is_sorted(const _STACK *sk);
+
+/* sk_set_cmp_func sets the comparison function to be used by |sk| and returns
+ * the previous one. */
+stack_cmp_func sk_set_cmp_func(_STACK *sk, stack_cmp_func comp);
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_STACK_H */
diff --git a/crypto/stack/stack_macros.h b/crypto/stack/stack_macros.h
new file mode 100644
index 0000000..52924c8
--- /dev/null
+++ b/crypto/stack/stack_macros.h
@@ -0,0 +1,3731 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#if !defined(IN_STACK_H)
+#error "Don't include this file directly. Include stack.h."
+#endif
+
+/* ACCESS_DESCRIPTION */
+#define sk_ACCESS_DESCRIPTION_new(comp) \
+ ((STACK_OF(ACCESS_DESCRIPTION) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, \
+ int (*)(const ACCESS_DESCRIPTION **a, const ACCESS_DESCRIPTION **b), \
+ comp)))
+
+#define sk_ACCESS_DESCRIPTION_new_null() \
+ ((STACK_OF(ACCESS_DESCRIPTION) *)sk_new_null())
+
+#define sk_ACCESS_DESCRIPTION_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk))
+
+#define sk_ACCESS_DESCRIPTION_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk));
+
+#define sk_ACCESS_DESCRIPTION_value(sk, i) \
+ ((ACCESS_DESCRIPTION *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(ACCESS_DESCRIPTION) *, sk), (i)))
+
+#define sk_ACCESS_DESCRIPTION_set(sk, i, p) \
+ ((ACCESS_DESCRIPTION *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), (i), \
+ CHECKED_CAST(void *, ACCESS_DESCRIPTION *, p)))
+
+#define sk_ACCESS_DESCRIPTION_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk))
+
+#define sk_ACCESS_DESCRIPTION_pop_free(sk, free_func) \
+ sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(ACCESS_DESCRIPTION *), \
+ free_func))
+
+#define sk_ACCESS_DESCRIPTION_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), \
+ CHECKED_CAST(void *, ACCESS_DESCRIPTION *, p), (where))
+
+#define sk_ACCESS_DESCRIPTION_delete(sk, where) \
+ ((ACCESS_DESCRIPTION *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), (where)))
+
+#define sk_ACCESS_DESCRIPTION_delete_ptr(sk, p) \
+ ((ACCESS_DESCRIPTION *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), \
+ CHECKED_CAST(void *, ACCESS_DESCRIPTION *, p)))
+
+#define sk_ACCESS_DESCRIPTION_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), \
+ (out_index), CHECKED_CAST(void *, ACCESS_DESCRIPTION *, p))
+
+#define sk_ACCESS_DESCRIPTION_shift(sk) \
+ ((ACCESS_DESCRIPTION *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk)))
+
+#define sk_ACCESS_DESCRIPTION_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), \
+ CHECKED_CAST(void *, ACCESS_DESCRIPTION *, p))
+
+#define sk_ACCESS_DESCRIPTION_pop(sk) \
+ ((ACCESS_DESCRIPTION *)sk_pop( \
+ CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk)))
+
+#define sk_ACCESS_DESCRIPTION_dup(sk) \
+ ((STACK_OF(ACCESS_DESCRIPTION) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(ACCESS_DESCRIPTION) *, sk)))
+
+#define sk_ACCESS_DESCRIPTION_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk))
+
+#define sk_ACCESS_DESCRIPTION_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ACCESS_DESCRIPTION) *, sk))
+
+#define sk_ACCESS_DESCRIPTION_set_cmp_func(sk, comp) \
+ ((int (*)(const ACCESS_DESCRIPTION **a, const ACCESS_DESCRIPTION **b)) \
+ sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), \
+ CHECKED_CAST(stack_cmp_func, int (*)(const ACCESS_DESCRIPTION **a, \
+ const ACCESS_DESCRIPTION **b), \
+ comp)))
+
+/* ASN1_ADB_TABLE */
+#define sk_ASN1_ADB_TABLE_new(comp) \
+ ((STACK_OF(ASN1_ADB_TABLE) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, \
+ int (*)(const ASN1_ADB_TABLE **a, const ASN1_ADB_TABLE **b), comp)))
+
+#define sk_ASN1_ADB_TABLE_new_null() ((STACK_OF(ASN1_ADB_TABLE) *)sk_new_null())
+
+#define sk_ASN1_ADB_TABLE_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk))
+
+#define sk_ASN1_ADB_TABLE_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk));
+
+#define sk_ASN1_ADB_TABLE_value(sk, i) \
+ ((ASN1_ADB_TABLE *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(ASN1_ADB_TABLE) *, sk), (i)))
+
+#define sk_ASN1_ADB_TABLE_set(sk, i, p) \
+ ((ASN1_ADB_TABLE *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), (i), \
+ CHECKED_CAST(void *, ASN1_ADB_TABLE *, p)))
+
+#define sk_ASN1_ADB_TABLE_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk))
+
+#define sk_ASN1_ADB_TABLE_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(ASN1_ADB_TABLE *), free_func))
+
+#define sk_ASN1_ADB_TABLE_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), \
+ CHECKED_CAST(void *, ASN1_ADB_TABLE *, p), (where))
+
+#define sk_ASN1_ADB_TABLE_delete(sk, where) \
+ ((ASN1_ADB_TABLE *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), (where)))
+
+#define sk_ASN1_ADB_TABLE_delete_ptr(sk, p) \
+ ((ASN1_ADB_TABLE *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), \
+ CHECKED_CAST(void *, ASN1_ADB_TABLE *, p)))
+
+#define sk_ASN1_ADB_TABLE_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), (out_index), \
+ CHECKED_CAST(void *, ASN1_ADB_TABLE *, p))
+
+#define sk_ASN1_ADB_TABLE_shift(sk) \
+ ((ASN1_ADB_TABLE *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk)))
+
+#define sk_ASN1_ADB_TABLE_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), \
+ CHECKED_CAST(void *, ASN1_ADB_TABLE *, p))
+
+#define sk_ASN1_ADB_TABLE_pop(sk) \
+ ((ASN1_ADB_TABLE *)sk_pop( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk)))
+
+#define sk_ASN1_ADB_TABLE_dup(sk) \
+ ((STACK_OF(ASN1_ADB_TABLE) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(ASN1_ADB_TABLE) *, sk)))
+
+#define sk_ASN1_ADB_TABLE_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk))
+
+#define sk_ASN1_ADB_TABLE_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_ADB_TABLE) *, sk))
+
+#define sk_ASN1_ADB_TABLE_set_cmp_func(sk, comp) \
+ ((int (*)(const ASN1_ADB_TABLE **a, const ASN1_ADB_TABLE **b)) \
+ sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), \
+ CHECKED_CAST(stack_cmp_func, int (*)(const ASN1_ADB_TABLE **a, \
+ const ASN1_ADB_TABLE **b), \
+ comp)))
+
+/* ASN1_GENERALSTRING */
+#define sk_ASN1_GENERALSTRING_new(comp) \
+ ((STACK_OF(ASN1_GENERALSTRING) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, \
+ int (*)(const ASN1_GENERALSTRING **a, const ASN1_GENERALSTRING **b), \
+ comp)))
+
+#define sk_ASN1_GENERALSTRING_new_null() \
+ ((STACK_OF(ASN1_GENERALSTRING) *)sk_new_null())
+
+#define sk_ASN1_GENERALSTRING_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk))
+
+#define sk_ASN1_GENERALSTRING_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk));
+
+#define sk_ASN1_GENERALSTRING_value(sk, i) \
+ ((ASN1_GENERALSTRING *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(ASN1_GENERALSTRING) *, sk), (i)))
+
+#define sk_ASN1_GENERALSTRING_set(sk, i, p) \
+ ((ASN1_GENERALSTRING *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), (i), \
+ CHECKED_CAST(void *, ASN1_GENERALSTRING *, p)))
+
+#define sk_ASN1_GENERALSTRING_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk))
+
+#define sk_ASN1_GENERALSTRING_pop_free(sk, free_func) \
+ sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(ASN1_GENERALSTRING *), \
+ free_func))
+
+#define sk_ASN1_GENERALSTRING_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), \
+ CHECKED_CAST(void *, ASN1_GENERALSTRING *, p), (where))
+
+#define sk_ASN1_GENERALSTRING_delete(sk, where) \
+ ((ASN1_GENERALSTRING *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), (where)))
+
+#define sk_ASN1_GENERALSTRING_delete_ptr(sk, p) \
+ ((ASN1_GENERALSTRING *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), \
+ CHECKED_CAST(void *, ASN1_GENERALSTRING *, p)))
+
+#define sk_ASN1_GENERALSTRING_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), \
+ (out_index), CHECKED_CAST(void *, ASN1_GENERALSTRING *, p))
+
+#define sk_ASN1_GENERALSTRING_shift(sk) \
+ ((ASN1_GENERALSTRING *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk)))
+
+#define sk_ASN1_GENERALSTRING_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), \
+ CHECKED_CAST(void *, ASN1_GENERALSTRING *, p))
+
+#define sk_ASN1_GENERALSTRING_pop(sk) \
+ ((ASN1_GENERALSTRING *)sk_pop( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk)))
+
+#define sk_ASN1_GENERALSTRING_dup(sk) \
+ ((STACK_OF(ASN1_GENERALSTRING) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(ASN1_GENERALSTRING) *, sk)))
+
+#define sk_ASN1_GENERALSTRING_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk))
+
+#define sk_ASN1_GENERALSTRING_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_GENERALSTRING) *, sk))
+
+#define sk_ASN1_GENERALSTRING_set_cmp_func(sk, comp) \
+ ((int (*)(const ASN1_GENERALSTRING **a, const ASN1_GENERALSTRING **b)) \
+ sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), \
+ CHECKED_CAST(stack_cmp_func, int (*)(const ASN1_GENERALSTRING **a, \
+ const ASN1_GENERALSTRING **b), \
+ comp)))
+
+/* ASN1_INTEGER */
+#define sk_ASN1_INTEGER_new(comp) \
+ ((STACK_OF(ASN1_INTEGER) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, int (*)(const ASN1_INTEGER **a, const ASN1_INTEGER **b), \
+ comp)))
+
+#define sk_ASN1_INTEGER_new_null() ((STACK_OF(ASN1_INTEGER) *)sk_new_null())
+
+#define sk_ASN1_INTEGER_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk))
+
+#define sk_ASN1_INTEGER_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk));
+
+#define sk_ASN1_INTEGER_value(sk, i) \
+ ((ASN1_INTEGER *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(ASN1_INTEGER) *, sk), (i)))
+
+#define sk_ASN1_INTEGER_set(sk, i, p) \
+ ((ASN1_INTEGER *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), (i), \
+ CHECKED_CAST(void *, ASN1_INTEGER *, p)))
+
+#define sk_ASN1_INTEGER_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk))
+
+#define sk_ASN1_INTEGER_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(ASN1_INTEGER *), free_func))
+
+#define sk_ASN1_INTEGER_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), \
+ CHECKED_CAST(void *, ASN1_INTEGER *, p), (where))
+
+#define sk_ASN1_INTEGER_delete(sk, where) \
+ ((ASN1_INTEGER *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), (where)))
+
+#define sk_ASN1_INTEGER_delete_ptr(sk, p) \
+ ((ASN1_INTEGER *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), \
+ CHECKED_CAST(void *, ASN1_INTEGER *, p)))
+
+#define sk_ASN1_INTEGER_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), (out_index), \
+ CHECKED_CAST(void *, ASN1_INTEGER *, p))
+
+#define sk_ASN1_INTEGER_shift(sk) \
+ ((ASN1_INTEGER *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk)))
+
+#define sk_ASN1_INTEGER_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), \
+ CHECKED_CAST(void *, ASN1_INTEGER *, p))
+
+#define sk_ASN1_INTEGER_pop(sk) \
+ ((ASN1_INTEGER *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk)))
+
+#define sk_ASN1_INTEGER_dup(sk) \
+ ((STACK_OF(ASN1_INTEGER) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(ASN1_INTEGER) *, sk)))
+
+#define sk_ASN1_INTEGER_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk))
+
+#define sk_ASN1_INTEGER_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_INTEGER) *, sk))
+
+#define sk_ASN1_INTEGER_set_cmp_func(sk, comp) \
+ ((int (*)(const ASN1_INTEGER **a, const ASN1_INTEGER **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const ASN1_INTEGER **a, const ASN1_INTEGER **b), \
+ comp)))
+
+/* ASN1_OBJECT */
+#define sk_ASN1_OBJECT_new(comp) \
+ ((STACK_OF(ASN1_OBJECT) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, int (*)(const ASN1_OBJECT **a, const ASN1_OBJECT **b), \
+ comp)))
+
+#define sk_ASN1_OBJECT_new_null() ((STACK_OF(ASN1_OBJECT) *)sk_new_null())
+
+#define sk_ASN1_OBJECT_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk))
+
+#define sk_ASN1_OBJECT_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk));
+
+#define sk_ASN1_OBJECT_value(sk, i) \
+ ((ASN1_OBJECT *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(ASN1_OBJECT) *, sk), (i)))
+
+#define sk_ASN1_OBJECT_set(sk, i, p) \
+ ((ASN1_OBJECT *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), \
+ (i), CHECKED_CAST(void *, ASN1_OBJECT *, p)))
+
+#define sk_ASN1_OBJECT_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk))
+
+#define sk_ASN1_OBJECT_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(ASN1_OBJECT *), free_func))
+
+#define sk_ASN1_OBJECT_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), \
+ CHECKED_CAST(void *, ASN1_OBJECT *, p), (where))
+
+#define sk_ASN1_OBJECT_delete(sk, where) \
+ ((ASN1_OBJECT *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), (where)))
+
+#define sk_ASN1_OBJECT_delete_ptr(sk, p) \
+ ((ASN1_OBJECT *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), \
+ CHECKED_CAST(void *, ASN1_OBJECT *, p)))
+
+#define sk_ASN1_OBJECT_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), (out_index), \
+ CHECKED_CAST(void *, ASN1_OBJECT *, p))
+
+#define sk_ASN1_OBJECT_shift(sk) \
+ ((ASN1_OBJECT *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk)))
+
+#define sk_ASN1_OBJECT_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), \
+ CHECKED_CAST(void *, ASN1_OBJECT *, p))
+
+#define sk_ASN1_OBJECT_pop(sk) \
+ ((ASN1_OBJECT *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk)))
+
+#define sk_ASN1_OBJECT_dup(sk) \
+ ((STACK_OF(ASN1_OBJECT) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(ASN1_OBJECT) *, sk)))
+
+#define sk_ASN1_OBJECT_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk))
+
+#define sk_ASN1_OBJECT_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_OBJECT) *, sk))
+
+#define sk_ASN1_OBJECT_set_cmp_func(sk, comp) \
+ ((int (*)(const ASN1_OBJECT **a, const ASN1_OBJECT **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const ASN1_OBJECT **a, const ASN1_OBJECT **b), \
+ comp)))
+
+/* ASN1_STRING_TABLE */
+#define sk_ASN1_STRING_TABLE_new(comp) \
+ ((STACK_OF(ASN1_STRING_TABLE) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, \
+ int (*)(const ASN1_STRING_TABLE **a, const ASN1_STRING_TABLE **b), \
+ comp)))
+
+#define sk_ASN1_STRING_TABLE_new_null() \
+ ((STACK_OF(ASN1_STRING_TABLE) *)sk_new_null())
+
+#define sk_ASN1_STRING_TABLE_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk))
+
+#define sk_ASN1_STRING_TABLE_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk));
+
+#define sk_ASN1_STRING_TABLE_value(sk, i) \
+ ((ASN1_STRING_TABLE *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(ASN1_STRING_TABLE) *, sk), (i)))
+
+#define sk_ASN1_STRING_TABLE_set(sk, i, p) \
+ ((ASN1_STRING_TABLE *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), (i), \
+ CHECKED_CAST(void *, ASN1_STRING_TABLE *, p)))
+
+#define sk_ASN1_STRING_TABLE_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk))
+
+#define sk_ASN1_STRING_TABLE_pop_free(sk, free_func) \
+ sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(ASN1_STRING_TABLE *), \
+ free_func))
+
+#define sk_ASN1_STRING_TABLE_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), \
+ CHECKED_CAST(void *, ASN1_STRING_TABLE *, p), (where))
+
+#define sk_ASN1_STRING_TABLE_delete(sk, where) \
+ ((ASN1_STRING_TABLE *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), (where)))
+
+#define sk_ASN1_STRING_TABLE_delete_ptr(sk, p) \
+ ((ASN1_STRING_TABLE *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), \
+ CHECKED_CAST(void *, ASN1_STRING_TABLE *, p)))
+
+#define sk_ASN1_STRING_TABLE_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), \
+ (out_index), CHECKED_CAST(void *, ASN1_STRING_TABLE *, p))
+
+#define sk_ASN1_STRING_TABLE_shift(sk) \
+ ((ASN1_STRING_TABLE *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk)))
+
+#define sk_ASN1_STRING_TABLE_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), \
+ CHECKED_CAST(void *, ASN1_STRING_TABLE *, p))
+
+#define sk_ASN1_STRING_TABLE_pop(sk) \
+ ((ASN1_STRING_TABLE *)sk_pop( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk)))
+
+#define sk_ASN1_STRING_TABLE_dup(sk) \
+ ((STACK_OF(ASN1_STRING_TABLE) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(ASN1_STRING_TABLE) *, sk)))
+
+#define sk_ASN1_STRING_TABLE_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk))
+
+#define sk_ASN1_STRING_TABLE_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_STRING_TABLE) *, sk))
+
+#define sk_ASN1_STRING_TABLE_set_cmp_func(sk, comp) \
+ ((int (*)(const ASN1_STRING_TABLE **a, const ASN1_STRING_TABLE **b)) \
+ sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), \
+ CHECKED_CAST(stack_cmp_func, int (*)(const ASN1_STRING_TABLE **a, \
+ const ASN1_STRING_TABLE **b), \
+ comp)))
+
+/* ASN1_TYPE */
+#define sk_ASN1_TYPE_new(comp) \
+ ((STACK_OF(ASN1_TYPE) *)sk_new( \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const ASN1_TYPE **a, const ASN1_TYPE **b), comp)))
+
+#define sk_ASN1_TYPE_new_null() ((STACK_OF(ASN1_TYPE) *)sk_new_null())
+
+#define sk_ASN1_TYPE_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk))
+
+#define sk_ASN1_TYPE_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk));
+
+#define sk_ASN1_TYPE_value(sk, i) \
+ ((ASN1_TYPE *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(ASN1_TYPE) *, sk), (i)))
+
+#define sk_ASN1_TYPE_set(sk, i, p) \
+ ((ASN1_TYPE *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), (i), \
+ CHECKED_CAST(void *, ASN1_TYPE *, p)))
+
+#define sk_ASN1_TYPE_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk))
+
+#define sk_ASN1_TYPE_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(ASN1_TYPE *), free_func))
+
+#define sk_ASN1_TYPE_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), \
+ CHECKED_CAST(void *, ASN1_TYPE *, p), (where))
+
+#define sk_ASN1_TYPE_delete(sk, where) \
+ ((ASN1_TYPE *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), \
+ (where)))
+
+#define sk_ASN1_TYPE_delete_ptr(sk, p) \
+ ((ASN1_TYPE *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), \
+ CHECKED_CAST(void *, ASN1_TYPE *, p)))
+
+#define sk_ASN1_TYPE_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), (out_index), \
+ CHECKED_CAST(void *, ASN1_TYPE *, p))
+
+#define sk_ASN1_TYPE_shift(sk) \
+ ((ASN1_TYPE *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk)))
+
+#define sk_ASN1_TYPE_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), \
+ CHECKED_CAST(void *, ASN1_TYPE *, p))
+
+#define sk_ASN1_TYPE_pop(sk) \
+ ((ASN1_TYPE *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk)))
+
+#define sk_ASN1_TYPE_dup(sk) \
+ ((STACK_OF(ASN1_TYPE) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(ASN1_TYPE) *, sk)))
+
+#define sk_ASN1_TYPE_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk))
+
+#define sk_ASN1_TYPE_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_TYPE) *, sk))
+
+#define sk_ASN1_TYPE_set_cmp_func(sk, comp) \
+ ((int (*)(const ASN1_TYPE **a, const ASN1_TYPE **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const ASN1_TYPE **a, const ASN1_TYPE **b), comp)))
+
+/* ASN1_VALUE */
+#define sk_ASN1_VALUE_new(comp) \
+ ((STACK_OF(ASN1_VALUE) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, int (*)(const ASN1_VALUE **a, const ASN1_VALUE **b), \
+ comp)))
+
+#define sk_ASN1_VALUE_new_null() ((STACK_OF(ASN1_VALUE) *)sk_new_null())
+
+#define sk_ASN1_VALUE_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk))
+
+#define sk_ASN1_VALUE_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk));
+
+#define sk_ASN1_VALUE_value(sk, i) \
+ ((ASN1_VALUE *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(ASN1_VALUE) *, sk), (i)))
+
+#define sk_ASN1_VALUE_set(sk, i, p) \
+ ((ASN1_VALUE *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \
+ (i), CHECKED_CAST(void *, ASN1_VALUE *, p)))
+
+#define sk_ASN1_VALUE_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk))
+
+#define sk_ASN1_VALUE_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(ASN1_VALUE *), free_func))
+
+#define sk_ASN1_VALUE_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \
+ CHECKED_CAST(void *, ASN1_VALUE *, p), (where))
+
+#define sk_ASN1_VALUE_delete(sk, where) \
+ ((ASN1_VALUE *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \
+ (where)))
+
+#define sk_ASN1_VALUE_delete_ptr(sk, p) \
+ ((ASN1_VALUE *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \
+ CHECKED_CAST(void *, ASN1_VALUE *, p)))
+
+#define sk_ASN1_VALUE_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), (out_index), \
+ CHECKED_CAST(void *, ASN1_VALUE *, p))
+
+#define sk_ASN1_VALUE_shift(sk) \
+ ((ASN1_VALUE *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk)))
+
+#define sk_ASN1_VALUE_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \
+ CHECKED_CAST(void *, ASN1_VALUE *, p))
+
+#define sk_ASN1_VALUE_pop(sk) \
+ ((ASN1_VALUE *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk)))
+
+#define sk_ASN1_VALUE_dup(sk) \
+ ((STACK_OF(ASN1_VALUE) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(ASN1_VALUE) *, sk)))
+
+#define sk_ASN1_VALUE_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk))
+
+#define sk_ASN1_VALUE_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_VALUE) *, sk))
+
+#define sk_ASN1_VALUE_set_cmp_func(sk, comp) \
+ ((int (*)(const ASN1_VALUE **a, const ASN1_VALUE **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const ASN1_VALUE **a, const ASN1_VALUE **b), \
+ comp)))
+
+/* BIO */
+#define sk_BIO_new(comp) \
+ ((STACK_OF(BIO) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, int (*)(const BIO **a, const BIO **b), comp)))
+
+#define sk_BIO_new_null() ((STACK_OF(BIO) *)sk_new_null())
+
+#define sk_BIO_num(sk) sk_num(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk))
+
+#define sk_BIO_zero(sk) sk_zero(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk));
+
+#define sk_BIO_value(sk, i) \
+ ((BIO *)sk_value(CHECKED_CAST(_STACK *, const STACK_OF(BIO) *, sk), (i)))
+
+#define sk_BIO_set(sk, i, p) \
+ ((BIO *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), (i), \
+ CHECKED_CAST(void *, BIO *, p)))
+
+#define sk_BIO_free(sk) sk_free(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk))
+
+#define sk_BIO_pop_free(sk, free_func) \
+ sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(BIO *), free_func))
+
+#define sk_BIO_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), \
+ CHECKED_CAST(void *, BIO *, p), (where))
+
+#define sk_BIO_delete(sk, where) \
+ ((BIO *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), (where)))
+
+#define sk_BIO_delete_ptr(sk, p) \
+ ((BIO *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), \
+ CHECKED_CAST(void *, BIO *, p)))
+
+#define sk_BIO_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), (out_index), \
+ CHECKED_CAST(void *, BIO *, p))
+
+#define sk_BIO_shift(sk) \
+ ((BIO *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk)))
+
+#define sk_BIO_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), \
+ CHECKED_CAST(void *, BIO *, p))
+
+#define sk_BIO_pop(sk) \
+ ((BIO *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk)))
+
+#define sk_BIO_dup(sk) \
+ ((STACK_OF(BIO) *)sk_dup(CHECKED_CAST(_STACK *, const STACK_OF(BIO) *, sk)))
+
+#define sk_BIO_sort(sk) sk_sort(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk))
+
+#define sk_BIO_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(BIO) *, sk))
+
+#define sk_BIO_set_cmp_func(sk, comp) \
+ ((int (*)(const BIO **a, const BIO **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), \
+ CHECKED_CAST(stack_cmp_func, int (*)(const BIO **a, const BIO **b), \
+ comp)))
+
+/* BY_DIR_ENTRY */
+#define sk_BY_DIR_ENTRY_new(comp) \
+ ((STACK_OF(BY_DIR_ENTRY) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, int (*)(const BY_DIR_ENTRY **a, const BY_DIR_ENTRY **b), \
+ comp)))
+
+#define sk_BY_DIR_ENTRY_new_null() ((STACK_OF(BY_DIR_ENTRY) *)sk_new_null())
+
+#define sk_BY_DIR_ENTRY_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk))
+
+#define sk_BY_DIR_ENTRY_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk));
+
+#define sk_BY_DIR_ENTRY_value(sk, i) \
+ ((BY_DIR_ENTRY *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_ENTRY) *, sk), (i)))
+
+#define sk_BY_DIR_ENTRY_set(sk, i, p) \
+ ((BY_DIR_ENTRY *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), (i), \
+ CHECKED_CAST(void *, BY_DIR_ENTRY *, p)))
+
+#define sk_BY_DIR_ENTRY_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk))
+
+#define sk_BY_DIR_ENTRY_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(BY_DIR_ENTRY *), free_func))
+
+#define sk_BY_DIR_ENTRY_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), \
+ CHECKED_CAST(void *, BY_DIR_ENTRY *, p), (where))
+
+#define sk_BY_DIR_ENTRY_delete(sk, where) \
+ ((BY_DIR_ENTRY *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), (where)))
+
+#define sk_BY_DIR_ENTRY_delete_ptr(sk, p) \
+ ((BY_DIR_ENTRY *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), \
+ CHECKED_CAST(void *, BY_DIR_ENTRY *, p)))
+
+#define sk_BY_DIR_ENTRY_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), (out_index), \
+ CHECKED_CAST(void *, BY_DIR_ENTRY *, p))
+
+#define sk_BY_DIR_ENTRY_shift(sk) \
+ ((BY_DIR_ENTRY *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk)))
+
+#define sk_BY_DIR_ENTRY_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), \
+ CHECKED_CAST(void *, BY_DIR_ENTRY *, p))
+
+#define sk_BY_DIR_ENTRY_pop(sk) \
+ ((BY_DIR_ENTRY *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk)))
+
+#define sk_BY_DIR_ENTRY_dup(sk) \
+ ((STACK_OF(BY_DIR_ENTRY) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_ENTRY) *, sk)))
+
+#define sk_BY_DIR_ENTRY_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk))
+
+#define sk_BY_DIR_ENTRY_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_ENTRY) *, sk))
+
+#define sk_BY_DIR_ENTRY_set_cmp_func(sk, comp) \
+ ((int (*)(const BY_DIR_ENTRY **a, const BY_DIR_ENTRY **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const BY_DIR_ENTRY **a, const BY_DIR_ENTRY **b), \
+ comp)))
+
+/* BY_DIR_HASH */
+#define sk_BY_DIR_HASH_new(comp) \
+ ((STACK_OF(BY_DIR_HASH) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, int (*)(const BY_DIR_HASH **a, const BY_DIR_HASH **b), \
+ comp)))
+
+#define sk_BY_DIR_HASH_new_null() ((STACK_OF(BY_DIR_HASH) *)sk_new_null())
+
+#define sk_BY_DIR_HASH_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk))
+
+#define sk_BY_DIR_HASH_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk));
+
+#define sk_BY_DIR_HASH_value(sk, i) \
+ ((BY_DIR_HASH *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_HASH) *, sk), (i)))
+
+#define sk_BY_DIR_HASH_set(sk, i, p) \
+ ((BY_DIR_HASH *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), \
+ (i), CHECKED_CAST(void *, BY_DIR_HASH *, p)))
+
+#define sk_BY_DIR_HASH_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk))
+
+#define sk_BY_DIR_HASH_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(BY_DIR_HASH *), free_func))
+
+#define sk_BY_DIR_HASH_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), \
+ CHECKED_CAST(void *, BY_DIR_HASH *, p), (where))
+
+#define sk_BY_DIR_HASH_delete(sk, where) \
+ ((BY_DIR_HASH *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), (where)))
+
+#define sk_BY_DIR_HASH_delete_ptr(sk, p) \
+ ((BY_DIR_HASH *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), \
+ CHECKED_CAST(void *, BY_DIR_HASH *, p)))
+
+#define sk_BY_DIR_HASH_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), (out_index), \
+ CHECKED_CAST(void *, BY_DIR_HASH *, p))
+
+#define sk_BY_DIR_HASH_shift(sk) \
+ ((BY_DIR_HASH *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk)))
+
+#define sk_BY_DIR_HASH_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), \
+ CHECKED_CAST(void *, BY_DIR_HASH *, p))
+
+#define sk_BY_DIR_HASH_pop(sk) \
+ ((BY_DIR_HASH *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk)))
+
+#define sk_BY_DIR_HASH_dup(sk) \
+ ((STACK_OF(BY_DIR_HASH) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_HASH) *, sk)))
+
+#define sk_BY_DIR_HASH_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk))
+
+#define sk_BY_DIR_HASH_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_HASH) *, sk))
+
+#define sk_BY_DIR_HASH_set_cmp_func(sk, comp) \
+ ((int (*)(const BY_DIR_HASH **a, const BY_DIR_HASH **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const BY_DIR_HASH **a, const BY_DIR_HASH **b), \
+ comp)))
+
+/* CONF_VALUE */
+#define sk_CONF_VALUE_new(comp) \
+ ((STACK_OF(CONF_VALUE) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, int (*)(const CONF_VALUE **a, const CONF_VALUE **b), \
+ comp)))
+
+#define sk_CONF_VALUE_new_null() ((STACK_OF(CONF_VALUE) *)sk_new_null())
+
+#define sk_CONF_VALUE_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk))
+
+#define sk_CONF_VALUE_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk));
+
+#define sk_CONF_VALUE_value(sk, i) \
+ ((CONF_VALUE *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(CONF_VALUE) *, sk), (i)))
+
+#define sk_CONF_VALUE_set(sk, i, p) \
+ ((CONF_VALUE *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \
+ (i), CHECKED_CAST(void *, CONF_VALUE *, p)))
+
+#define sk_CONF_VALUE_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk))
+
+#define sk_CONF_VALUE_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(CONF_VALUE *), free_func))
+
+#define sk_CONF_VALUE_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \
+ CHECKED_CAST(void *, CONF_VALUE *, p), (where))
+
+#define sk_CONF_VALUE_delete(sk, where) \
+ ((CONF_VALUE *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \
+ (where)))
+
+#define sk_CONF_VALUE_delete_ptr(sk, p) \
+ ((CONF_VALUE *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \
+ CHECKED_CAST(void *, CONF_VALUE *, p)))
+
+#define sk_CONF_VALUE_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), (out_index), \
+ CHECKED_CAST(void *, CONF_VALUE *, p))
+
+#define sk_CONF_VALUE_shift(sk) \
+ ((CONF_VALUE *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk)))
+
+#define sk_CONF_VALUE_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \
+ CHECKED_CAST(void *, CONF_VALUE *, p))
+
+#define sk_CONF_VALUE_pop(sk) \
+ ((CONF_VALUE *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk)))
+
+#define sk_CONF_VALUE_dup(sk) \
+ ((STACK_OF(CONF_VALUE) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(CONF_VALUE) *, sk)))
+
+#define sk_CONF_VALUE_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk))
+
+#define sk_CONF_VALUE_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(CONF_VALUE) *, sk))
+
+#define sk_CONF_VALUE_set_cmp_func(sk, comp) \
+ ((int (*)(const CONF_VALUE **a, const CONF_VALUE **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const CONF_VALUE **a, const CONF_VALUE **b), \
+ comp)))
+
+/* CRYPTO_EX_DATA_FUNCS */
+#define sk_CRYPTO_EX_DATA_FUNCS_new(comp) \
+ ((STACK_OF(CRYPTO_EX_DATA_FUNCS) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, \
+ int (*)(const CRYPTO_EX_DATA_FUNCS **a, const CRYPTO_EX_DATA_FUNCS **b), \
+ comp)))
+
+#define sk_CRYPTO_EX_DATA_FUNCS_new_null() \
+ ((STACK_OF(CRYPTO_EX_DATA_FUNCS) *)sk_new_null())
+
+#define sk_CRYPTO_EX_DATA_FUNCS_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk))
+
+#define sk_CRYPTO_EX_DATA_FUNCS_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk));
+
+#define sk_CRYPTO_EX_DATA_FUNCS_value(sk, i) \
+ ((CRYPTO_EX_DATA_FUNCS *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \
+ (i)))
+
+#define sk_CRYPTO_EX_DATA_FUNCS_set(sk, i, p) \
+ ((CRYPTO_EX_DATA_FUNCS *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), (i), \
+ CHECKED_CAST(void *, CRYPTO_EX_DATA_FUNCS *, p)))
+
+#define sk_CRYPTO_EX_DATA_FUNCS_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk))
+
+#define sk_CRYPTO_EX_DATA_FUNCS_pop_free(sk, free_func) \
+ sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(CRYPTO_EX_DATA_FUNCS *), \
+ free_func))
+
+#define sk_CRYPTO_EX_DATA_FUNCS_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \
+ CHECKED_CAST(void *, CRYPTO_EX_DATA_FUNCS *, p), (where))
+
+#define sk_CRYPTO_EX_DATA_FUNCS_delete(sk, where) \
+ ((CRYPTO_EX_DATA_FUNCS *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), (where)))
+
+#define sk_CRYPTO_EX_DATA_FUNCS_delete_ptr(sk, p) \
+ ((CRYPTO_EX_DATA_FUNCS *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \
+ CHECKED_CAST(void *, CRYPTO_EX_DATA_FUNCS *, p)))
+
+#define sk_CRYPTO_EX_DATA_FUNCS_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \
+ (out_index), CHECKED_CAST(void *, CRYPTO_EX_DATA_FUNCS *, p))
+
+#define sk_CRYPTO_EX_DATA_FUNCS_shift(sk) \
+ ((CRYPTO_EX_DATA_FUNCS *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk)))
+
+#define sk_CRYPTO_EX_DATA_FUNCS_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \
+ CHECKED_CAST(void *, CRYPTO_EX_DATA_FUNCS *, p))
+
+#define sk_CRYPTO_EX_DATA_FUNCS_pop(sk) \
+ ((CRYPTO_EX_DATA_FUNCS *)sk_pop( \
+ CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk)))
+
+#define sk_CRYPTO_EX_DATA_FUNCS_dup(sk) \
+ ((STACK_OF(CRYPTO_EX_DATA_FUNCS) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk)))
+
+#define sk_CRYPTO_EX_DATA_FUNCS_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk))
+
+#define sk_CRYPTO_EX_DATA_FUNCS_is_sorted(sk) \
+ sk_is_sorted( \
+ CHECKED_CAST(_STACK *, const STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk))
+
+#define sk_CRYPTO_EX_DATA_FUNCS_set_cmp_func(sk, comp) \
+ ((int (*)(const CRYPTO_EX_DATA_FUNCS **a, const CRYPTO_EX_DATA_FUNCS **b)) \
+ sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \
+ CHECKED_CAST(stack_cmp_func, int (*)(const CRYPTO_EX_DATA_FUNCS **a, \
+ const CRYPTO_EX_DATA_FUNCS **b), \
+ comp)))
+
+/* DIST_POINT */
+#define sk_DIST_POINT_new(comp) \
+ ((STACK_OF(DIST_POINT) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, int (*)(const DIST_POINT **a, const DIST_POINT **b), \
+ comp)))
+
+#define sk_DIST_POINT_new_null() ((STACK_OF(DIST_POINT) *)sk_new_null())
+
+#define sk_DIST_POINT_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk))
+
+#define sk_DIST_POINT_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk));
+
+#define sk_DIST_POINT_value(sk, i) \
+ ((DIST_POINT *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(DIST_POINT) *, sk), (i)))
+
+#define sk_DIST_POINT_set(sk, i, p) \
+ ((DIST_POINT *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \
+ (i), CHECKED_CAST(void *, DIST_POINT *, p)))
+
+#define sk_DIST_POINT_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk))
+
+#define sk_DIST_POINT_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(DIST_POINT *), free_func))
+
+#define sk_DIST_POINT_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \
+ CHECKED_CAST(void *, DIST_POINT *, p), (where))
+
+#define sk_DIST_POINT_delete(sk, where) \
+ ((DIST_POINT *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \
+ (where)))
+
+#define sk_DIST_POINT_delete_ptr(sk, p) \
+ ((DIST_POINT *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \
+ CHECKED_CAST(void *, DIST_POINT *, p)))
+
+#define sk_DIST_POINT_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), (out_index), \
+ CHECKED_CAST(void *, DIST_POINT *, p))
+
+#define sk_DIST_POINT_shift(sk) \
+ ((DIST_POINT *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk)))
+
+#define sk_DIST_POINT_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \
+ CHECKED_CAST(void *, DIST_POINT *, p))
+
+#define sk_DIST_POINT_pop(sk) \
+ ((DIST_POINT *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk)))
+
+#define sk_DIST_POINT_dup(sk) \
+ ((STACK_OF(DIST_POINT) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(DIST_POINT) *, sk)))
+
+#define sk_DIST_POINT_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk))
+
+#define sk_DIST_POINT_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(DIST_POINT) *, sk))
+
+#define sk_DIST_POINT_set_cmp_func(sk, comp) \
+ ((int (*)(const DIST_POINT **a, const DIST_POINT **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const DIST_POINT **a, const DIST_POINT **b), \
+ comp)))
+
+/* GENERAL_NAME */
+#define sk_GENERAL_NAME_new(comp) \
+ ((STACK_OF(GENERAL_NAME) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, int (*)(const GENERAL_NAME **a, const GENERAL_NAME **b), \
+ comp)))
+
+#define sk_GENERAL_NAME_new_null() ((STACK_OF(GENERAL_NAME) *)sk_new_null())
+
+#define sk_GENERAL_NAME_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk))
+
+#define sk_GENERAL_NAME_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk));
+
+#define sk_GENERAL_NAME_value(sk, i) \
+ ((GENERAL_NAME *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAME) *, sk), (i)))
+
+#define sk_GENERAL_NAME_set(sk, i, p) \
+ ((GENERAL_NAME *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), (i), \
+ CHECKED_CAST(void *, GENERAL_NAME *, p)))
+
+#define sk_GENERAL_NAME_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk))
+
+#define sk_GENERAL_NAME_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(GENERAL_NAME *), free_func))
+
+#define sk_GENERAL_NAME_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), \
+ CHECKED_CAST(void *, GENERAL_NAME *, p), (where))
+
+#define sk_GENERAL_NAME_delete(sk, where) \
+ ((GENERAL_NAME *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), (where)))
+
+#define sk_GENERAL_NAME_delete_ptr(sk, p) \
+ ((GENERAL_NAME *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), \
+ CHECKED_CAST(void *, GENERAL_NAME *, p)))
+
+#define sk_GENERAL_NAME_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), (out_index), \
+ CHECKED_CAST(void *, GENERAL_NAME *, p))
+
+#define sk_GENERAL_NAME_shift(sk) \
+ ((GENERAL_NAME *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk)))
+
+#define sk_GENERAL_NAME_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), \
+ CHECKED_CAST(void *, GENERAL_NAME *, p))
+
+#define sk_GENERAL_NAME_pop(sk) \
+ ((GENERAL_NAME *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk)))
+
+#define sk_GENERAL_NAME_dup(sk) \
+ ((STACK_OF(GENERAL_NAME) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAME) *, sk)))
+
+#define sk_GENERAL_NAME_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk))
+
+#define sk_GENERAL_NAME_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAME) *, sk))
+
+#define sk_GENERAL_NAME_set_cmp_func(sk, comp) \
+ ((int (*)(const GENERAL_NAME **a, const GENERAL_NAME **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const GENERAL_NAME **a, const GENERAL_NAME **b), \
+ comp)))
+
+/* GENERAL_NAMES */
+#define sk_GENERAL_NAMES_new(comp) \
+ ((STACK_OF(GENERAL_NAMES) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, \
+ int (*)(const GENERAL_NAMES **a, const GENERAL_NAMES **b), comp)))
+
+#define sk_GENERAL_NAMES_new_null() ((STACK_OF(GENERAL_NAMES) *)sk_new_null())
+
+#define sk_GENERAL_NAMES_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk))
+
+#define sk_GENERAL_NAMES_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk));
+
+#define sk_GENERAL_NAMES_value(sk, i) \
+ ((GENERAL_NAMES *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAMES) *, sk), (i)))
+
+#define sk_GENERAL_NAMES_set(sk, i, p) \
+ ((GENERAL_NAMES *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), (i), \
+ CHECKED_CAST(void *, GENERAL_NAMES *, p)))
+
+#define sk_GENERAL_NAMES_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk))
+
+#define sk_GENERAL_NAMES_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(GENERAL_NAMES *), free_func))
+
+#define sk_GENERAL_NAMES_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), \
+ CHECKED_CAST(void *, GENERAL_NAMES *, p), (where))
+
+#define sk_GENERAL_NAMES_delete(sk, where) \
+ ((GENERAL_NAMES *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), (where)))
+
+#define sk_GENERAL_NAMES_delete_ptr(sk, p) \
+ ((GENERAL_NAMES *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), \
+ CHECKED_CAST(void *, GENERAL_NAMES *, p)))
+
+#define sk_GENERAL_NAMES_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), (out_index), \
+ CHECKED_CAST(void *, GENERAL_NAMES *, p))
+
+#define sk_GENERAL_NAMES_shift(sk) \
+ ((GENERAL_NAMES *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk)))
+
+#define sk_GENERAL_NAMES_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), \
+ CHECKED_CAST(void *, GENERAL_NAMES *, p))
+
+#define sk_GENERAL_NAMES_pop(sk) \
+ ((GENERAL_NAMES *)sk_pop( \
+ CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk)))
+
+#define sk_GENERAL_NAMES_dup(sk) \
+ ((STACK_OF(GENERAL_NAMES) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAMES) *, sk)))
+
+#define sk_GENERAL_NAMES_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk))
+
+#define sk_GENERAL_NAMES_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAMES) *, sk))
+
+#define sk_GENERAL_NAMES_set_cmp_func(sk, comp) \
+ ((int (*)(const GENERAL_NAMES **a, const GENERAL_NAMES **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const GENERAL_NAMES **a, const GENERAL_NAMES **b), \
+ comp)))
+
+/* GENERAL_SUBTREE */
+#define sk_GENERAL_SUBTREE_new(comp) \
+ ((STACK_OF(GENERAL_SUBTREE) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, \
+ int (*)(const GENERAL_SUBTREE **a, const GENERAL_SUBTREE **b), comp)))
+
+#define sk_GENERAL_SUBTREE_new_null() \
+ ((STACK_OF(GENERAL_SUBTREE) *)sk_new_null())
+
+#define sk_GENERAL_SUBTREE_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk))
+
+#define sk_GENERAL_SUBTREE_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk));
+
+#define sk_GENERAL_SUBTREE_value(sk, i) \
+ ((GENERAL_SUBTREE *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_SUBTREE) *, sk), (i)))
+
+#define sk_GENERAL_SUBTREE_set(sk, i, p) \
+ ((GENERAL_SUBTREE *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), (i), \
+ CHECKED_CAST(void *, GENERAL_SUBTREE *, p)))
+
+#define sk_GENERAL_SUBTREE_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk))
+
+#define sk_GENERAL_SUBTREE_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(GENERAL_SUBTREE *), free_func))
+
+#define sk_GENERAL_SUBTREE_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), \
+ CHECKED_CAST(void *, GENERAL_SUBTREE *, p), (where))
+
+#define sk_GENERAL_SUBTREE_delete(sk, where) \
+ ((GENERAL_SUBTREE *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), (where)))
+
+#define sk_GENERAL_SUBTREE_delete_ptr(sk, p) \
+ ((GENERAL_SUBTREE *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), \
+ CHECKED_CAST(void *, GENERAL_SUBTREE *, p)))
+
+#define sk_GENERAL_SUBTREE_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), \
+ (out_index), CHECKED_CAST(void *, GENERAL_SUBTREE *, p))
+
+#define sk_GENERAL_SUBTREE_shift(sk) \
+ ((GENERAL_SUBTREE *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk)))
+
+#define sk_GENERAL_SUBTREE_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), \
+ CHECKED_CAST(void *, GENERAL_SUBTREE *, p))
+
+#define sk_GENERAL_SUBTREE_pop(sk) \
+ ((GENERAL_SUBTREE *)sk_pop( \
+ CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk)))
+
+#define sk_GENERAL_SUBTREE_dup(sk) \
+ ((STACK_OF(GENERAL_SUBTREE) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_SUBTREE) *, sk)))
+
+#define sk_GENERAL_SUBTREE_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk))
+
+#define sk_GENERAL_SUBTREE_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_SUBTREE) *, sk))
+
+#define sk_GENERAL_SUBTREE_set_cmp_func(sk, comp) \
+ ((int (*)(const GENERAL_SUBTREE **a, const GENERAL_SUBTREE **b)) \
+ sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), \
+ CHECKED_CAST(stack_cmp_func, int (*)(const GENERAL_SUBTREE **a, \
+ const GENERAL_SUBTREE **b), \
+ comp)))
+
+/* MIME_HEADER */
+#define sk_MIME_HEADER_new(comp) \
+ ((STACK_OF(MIME_HEADER) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, int (*)(const MIME_HEADER **a, const MIME_HEADER **b), \
+ comp)))
+
+#define sk_MIME_HEADER_new_null() ((STACK_OF(MIME_HEADER) *)sk_new_null())
+
+#define sk_MIME_HEADER_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk))
+
+#define sk_MIME_HEADER_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk));
+
+#define sk_MIME_HEADER_value(sk, i) \
+ ((MIME_HEADER *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(MIME_HEADER) *, sk), (i)))
+
+#define sk_MIME_HEADER_set(sk, i, p) \
+ ((MIME_HEADER *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk), \
+ (i), CHECKED_CAST(void *, MIME_HEADER *, p)))
+
+#define sk_MIME_HEADER_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk))
+
+#define sk_MIME_HEADER_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(MIME_HEADER *), free_func))
+
+#define sk_MIME_HEADER_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk), \
+ CHECKED_CAST(void *, MIME_HEADER *, p), (where))
+
+#define sk_MIME_HEADER_delete(sk, where) \
+ ((MIME_HEADER *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk), (where)))
+
+#define sk_MIME_HEADER_delete_ptr(sk, p) \
+ ((MIME_HEADER *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk), \
+ CHECKED_CAST(void *, MIME_HEADER *, p)))
+
+#define sk_MIME_HEADER_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk), (out_index), \
+ CHECKED_CAST(void *, MIME_HEADER *, p))
+
+#define sk_MIME_HEADER_shift(sk) \
+ ((MIME_HEADER *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk)))
+
+#define sk_MIME_HEADER_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk), \
+ CHECKED_CAST(void *, MIME_HEADER *, p))
+
+#define sk_MIME_HEADER_pop(sk) \
+ ((MIME_HEADER *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk)))
+
+#define sk_MIME_HEADER_dup(sk) \
+ ((STACK_OF(MIME_HEADER) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(MIME_HEADER) *, sk)))
+
+#define sk_MIME_HEADER_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk))
+
+#define sk_MIME_HEADER_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(MIME_HEADER) *, sk))
+
+#define sk_MIME_HEADER_set_cmp_func(sk, comp) \
+ ((int (*)(const MIME_HEADER **a, const MIME_HEADER **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const MIME_HEADER **a, const MIME_HEADER **b), \
+ comp)))
+
+/* PKCS7_SIGNER_INFO */
+#define sk_PKCS7_SIGNER_INFO_new(comp) \
+ ((STACK_OF(PKCS7_SIGNER_INFO) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, \
+ int (*)(const PKCS7_SIGNER_INFO **a, const PKCS7_SIGNER_INFO **b), \
+ comp)))
+
+#define sk_PKCS7_SIGNER_INFO_new_null() \
+ ((STACK_OF(PKCS7_SIGNER_INFO) *)sk_new_null())
+
+#define sk_PKCS7_SIGNER_INFO_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk))
+
+#define sk_PKCS7_SIGNER_INFO_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk));
+
+#define sk_PKCS7_SIGNER_INFO_value(sk, i) \
+ ((PKCS7_SIGNER_INFO *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(PKCS7_SIGNER_INFO) *, sk), (i)))
+
+#define sk_PKCS7_SIGNER_INFO_set(sk, i, p) \
+ ((PKCS7_SIGNER_INFO *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk), (i), \
+ CHECKED_CAST(void *, PKCS7_SIGNER_INFO *, p)))
+
+#define sk_PKCS7_SIGNER_INFO_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk))
+
+#define sk_PKCS7_SIGNER_INFO_pop_free(sk, free_func) \
+ sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(PKCS7_SIGNER_INFO *), \
+ free_func))
+
+#define sk_PKCS7_SIGNER_INFO_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk), \
+ CHECKED_CAST(void *, PKCS7_SIGNER_INFO *, p), (where))
+
+#define sk_PKCS7_SIGNER_INFO_delete(sk, where) \
+ ((PKCS7_SIGNER_INFO *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk), (where)))
+
+#define sk_PKCS7_SIGNER_INFO_delete_ptr(sk, p) \
+ ((PKCS7_SIGNER_INFO *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk), \
+ CHECKED_CAST(void *, PKCS7_SIGNER_INFO *, p)))
+
+#define sk_PKCS7_SIGNER_INFO_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk), \
+ (out_index), CHECKED_CAST(void *, PKCS7_SIGNER_INFO *, p))
+
+#define sk_PKCS7_SIGNER_INFO_shift(sk) \
+ ((PKCS7_SIGNER_INFO *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk)))
+
+#define sk_PKCS7_SIGNER_INFO_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk), \
+ CHECKED_CAST(void *, PKCS7_SIGNER_INFO *, p))
+
+#define sk_PKCS7_SIGNER_INFO_pop(sk) \
+ ((PKCS7_SIGNER_INFO *)sk_pop( \
+ CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk)))
+
+#define sk_PKCS7_SIGNER_INFO_dup(sk) \
+ ((STACK_OF(PKCS7_SIGNER_INFO) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(PKCS7_SIGNER_INFO) *, sk)))
+
+#define sk_PKCS7_SIGNER_INFO_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk))
+
+#define sk_PKCS7_SIGNER_INFO_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(PKCS7_SIGNER_INFO) *, sk))
+
+#define sk_PKCS7_SIGNER_INFO_set_cmp_func(sk, comp) \
+ ((int (*)(const PKCS7_SIGNER_INFO **a, const PKCS7_SIGNER_INFO **b)) \
+ sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk), \
+ CHECKED_CAST(stack_cmp_func, int (*)(const PKCS7_SIGNER_INFO **a, \
+ const PKCS7_SIGNER_INFO **b), \
+ comp)))
+
+/* PKCS7_RECIP_INFO */
+#define sk_PKCS7_RECIP_INFO_new(comp) \
+ ((STACK_OF(PKCS7_RECIP_INFO) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, \
+ int (*)(const PKCS7_RECIP_INFO **a, const PKCS7_RECIP_INFO **b), comp)))
+
+#define sk_PKCS7_RECIP_INFO_new_null() \
+ ((STACK_OF(PKCS7_RECIP_INFO) *)sk_new_null())
+
+#define sk_PKCS7_RECIP_INFO_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk))
+
+#define sk_PKCS7_RECIP_INFO_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk));
+
+#define sk_PKCS7_RECIP_INFO_value(sk, i) \
+ ((PKCS7_RECIP_INFO *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(PKCS7_RECIP_INFO) *, sk), (i)))
+
+#define sk_PKCS7_RECIP_INFO_set(sk, i, p) \
+ ((PKCS7_RECIP_INFO *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), (i), \
+ CHECKED_CAST(void *, PKCS7_RECIP_INFO *, p)))
+
+#define sk_PKCS7_RECIP_INFO_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk))
+
+#define sk_PKCS7_RECIP_INFO_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(PKCS7_RECIP_INFO *), free_func))
+
+#define sk_PKCS7_RECIP_INFO_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \
+ CHECKED_CAST(void *, PKCS7_RECIP_INFO *, p), (where))
+
+#define sk_PKCS7_RECIP_INFO_delete(sk, where) \
+ ((PKCS7_RECIP_INFO *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), (where)))
+
+#define sk_PKCS7_RECIP_INFO_delete_ptr(sk, p) \
+ ((PKCS7_RECIP_INFO *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \
+ CHECKED_CAST(void *, PKCS7_RECIP_INFO *, p)))
+
+#define sk_PKCS7_RECIP_INFO_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \
+ (out_index), CHECKED_CAST(void *, PKCS7_RECIP_INFO *, p))
+
+#define sk_PKCS7_RECIP_INFO_shift(sk) \
+ ((PKCS7_RECIP_INFO *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk)))
+
+#define sk_PKCS7_RECIP_INFO_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \
+ CHECKED_CAST(void *, PKCS7_RECIP_INFO *, p))
+
+#define sk_PKCS7_RECIP_INFO_pop(sk) \
+ ((PKCS7_RECIP_INFO *)sk_pop( \
+ CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk)))
+
+#define sk_PKCS7_RECIP_INFO_dup(sk) \
+ ((STACK_OF(PKCS7_RECIP_INFO) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(PKCS7_RECIP_INFO) *, sk)))
+
+#define sk_PKCS7_RECIP_INFO_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk))
+
+#define sk_PKCS7_RECIP_INFO_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(PKCS7_RECIP_INFO) *, sk))
+
+#define sk_PKCS7_RECIP_INFO_set_cmp_func(sk, comp) \
+ ((int (*)(const PKCS7_RECIP_INFO **a, const PKCS7_RECIP_INFO **b)) \
+ sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \
+ CHECKED_CAST(stack_cmp_func, int (*)(const PKCS7_RECIP_INFO **a, \
+ const PKCS7_RECIP_INFO **b), \
+ comp)))
+
+/* POLICYINFO */
+#define sk_POLICYINFO_new(comp) \
+ ((STACK_OF(POLICYINFO) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, int (*)(const POLICYINFO **a, const POLICYINFO **b), \
+ comp)))
+
+#define sk_POLICYINFO_new_null() ((STACK_OF(POLICYINFO) *)sk_new_null())
+
+#define sk_POLICYINFO_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk))
+
+#define sk_POLICYINFO_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk));
+
+#define sk_POLICYINFO_value(sk, i) \
+ ((POLICYINFO *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(POLICYINFO) *, sk), (i)))
+
+#define sk_POLICYINFO_set(sk, i, p) \
+ ((POLICYINFO *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \
+ (i), CHECKED_CAST(void *, POLICYINFO *, p)))
+
+#define sk_POLICYINFO_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk))
+
+#define sk_POLICYINFO_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(POLICYINFO *), free_func))
+
+#define sk_POLICYINFO_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \
+ CHECKED_CAST(void *, POLICYINFO *, p), (where))
+
+#define sk_POLICYINFO_delete(sk, where) \
+ ((POLICYINFO *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \
+ (where)))
+
+#define sk_POLICYINFO_delete_ptr(sk, p) \
+ ((POLICYINFO *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \
+ CHECKED_CAST(void *, POLICYINFO *, p)))
+
+#define sk_POLICYINFO_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), (out_index), \
+ CHECKED_CAST(void *, POLICYINFO *, p))
+
+#define sk_POLICYINFO_shift(sk) \
+ ((POLICYINFO *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk)))
+
+#define sk_POLICYINFO_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \
+ CHECKED_CAST(void *, POLICYINFO *, p))
+
+#define sk_POLICYINFO_pop(sk) \
+ ((POLICYINFO *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk)))
+
+#define sk_POLICYINFO_dup(sk) \
+ ((STACK_OF(POLICYINFO) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(POLICYINFO) *, sk)))
+
+#define sk_POLICYINFO_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk))
+
+#define sk_POLICYINFO_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(POLICYINFO) *, sk))
+
+#define sk_POLICYINFO_set_cmp_func(sk, comp) \
+ ((int (*)(const POLICYINFO **a, const POLICYINFO **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const POLICYINFO **a, const POLICYINFO **b), \
+ comp)))
+
+/* POLICYQUALINFO */
+#define sk_POLICYQUALINFO_new(comp) \
+ ((STACK_OF(POLICYQUALINFO) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, \
+ int (*)(const POLICYQUALINFO **a, const POLICYQUALINFO **b), comp)))
+
+#define sk_POLICYQUALINFO_new_null() ((STACK_OF(POLICYQUALINFO) *)sk_new_null())
+
+#define sk_POLICYQUALINFO_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk))
+
+#define sk_POLICYQUALINFO_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk));
+
+#define sk_POLICYQUALINFO_value(sk, i) \
+ ((POLICYQUALINFO *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(POLICYQUALINFO) *, sk), (i)))
+
+#define sk_POLICYQUALINFO_set(sk, i, p) \
+ ((POLICYQUALINFO *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), (i), \
+ CHECKED_CAST(void *, POLICYQUALINFO *, p)))
+
+#define sk_POLICYQUALINFO_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk))
+
+#define sk_POLICYQUALINFO_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(POLICYQUALINFO *), free_func))
+
+#define sk_POLICYQUALINFO_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \
+ CHECKED_CAST(void *, POLICYQUALINFO *, p), (where))
+
+#define sk_POLICYQUALINFO_delete(sk, where) \
+ ((POLICYQUALINFO *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), (where)))
+
+#define sk_POLICYQUALINFO_delete_ptr(sk, p) \
+ ((POLICYQUALINFO *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \
+ CHECKED_CAST(void *, POLICYQUALINFO *, p)))
+
+#define sk_POLICYQUALINFO_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), (out_index), \
+ CHECKED_CAST(void *, POLICYQUALINFO *, p))
+
+#define sk_POLICYQUALINFO_shift(sk) \
+ ((POLICYQUALINFO *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk)))
+
+#define sk_POLICYQUALINFO_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \
+ CHECKED_CAST(void *, POLICYQUALINFO *, p))
+
+#define sk_POLICYQUALINFO_pop(sk) \
+ ((POLICYQUALINFO *)sk_pop( \
+ CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk)))
+
+#define sk_POLICYQUALINFO_dup(sk) \
+ ((STACK_OF(POLICYQUALINFO) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(POLICYQUALINFO) *, sk)))
+
+#define sk_POLICYQUALINFO_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk))
+
+#define sk_POLICYQUALINFO_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(POLICYQUALINFO) *, sk))
+
+#define sk_POLICYQUALINFO_set_cmp_func(sk, comp) \
+ ((int (*)(const POLICYQUALINFO **a, const POLICYQUALINFO **b)) \
+ sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \
+ CHECKED_CAST(stack_cmp_func, int (*)(const POLICYQUALINFO **a, \
+ const POLICYQUALINFO **b), \
+ comp)))
+
+/* POLICY_MAPPING */
+#define sk_POLICY_MAPPING_new(comp) \
+ ((STACK_OF(POLICY_MAPPING) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, \
+ int (*)(const POLICY_MAPPING **a, const POLICY_MAPPING **b), comp)))
+
+#define sk_POLICY_MAPPING_new_null() ((STACK_OF(POLICY_MAPPING) *)sk_new_null())
+
+#define sk_POLICY_MAPPING_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk))
+
+#define sk_POLICY_MAPPING_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk));
+
+#define sk_POLICY_MAPPING_value(sk, i) \
+ ((POLICY_MAPPING *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(POLICY_MAPPING) *, sk), (i)))
+
+#define sk_POLICY_MAPPING_set(sk, i, p) \
+ ((POLICY_MAPPING *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), (i), \
+ CHECKED_CAST(void *, POLICY_MAPPING *, p)))
+
+#define sk_POLICY_MAPPING_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk))
+
+#define sk_POLICY_MAPPING_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(POLICY_MAPPING *), free_func))
+
+#define sk_POLICY_MAPPING_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), \
+ CHECKED_CAST(void *, POLICY_MAPPING *, p), (where))
+
+#define sk_POLICY_MAPPING_delete(sk, where) \
+ ((POLICY_MAPPING *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), (where)))
+
+#define sk_POLICY_MAPPING_delete_ptr(sk, p) \
+ ((POLICY_MAPPING *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), \
+ CHECKED_CAST(void *, POLICY_MAPPING *, p)))
+
+#define sk_POLICY_MAPPING_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), (out_index), \
+ CHECKED_CAST(void *, POLICY_MAPPING *, p))
+
+#define sk_POLICY_MAPPING_shift(sk) \
+ ((POLICY_MAPPING *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk)))
+
+#define sk_POLICY_MAPPING_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), \
+ CHECKED_CAST(void *, POLICY_MAPPING *, p))
+
+#define sk_POLICY_MAPPING_pop(sk) \
+ ((POLICY_MAPPING *)sk_pop( \
+ CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk)))
+
+#define sk_POLICY_MAPPING_dup(sk) \
+ ((STACK_OF(POLICY_MAPPING) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(POLICY_MAPPING) *, sk)))
+
+#define sk_POLICY_MAPPING_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk))
+
+#define sk_POLICY_MAPPING_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(POLICY_MAPPING) *, sk))
+
+#define sk_POLICY_MAPPING_set_cmp_func(sk, comp) \
+ ((int (*)(const POLICY_MAPPING **a, const POLICY_MAPPING **b)) \
+ sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), \
+ CHECKED_CAST(stack_cmp_func, int (*)(const POLICY_MAPPING **a, \
+ const POLICY_MAPPING **b), \
+ comp)))
+
+/* SRTP_PROTECTION_PROFILE */
+#define sk_SRTP_PROTECTION_PROFILE_new(comp) \
+ ((STACK_OF(SRTP_PROTECTION_PROFILE) *)sk_new( \
+ CHECKED_CAST(stack_cmp_func, int (*)(const SRTP_PROTECTION_PROFILE **a, \
+ const SRTP_PROTECTION_PROFILE **b), \
+ comp)))
+
+#define sk_SRTP_PROTECTION_PROFILE_new_null() \
+ ((STACK_OF(SRTP_PROTECTION_PROFILE) *)sk_new_null())
+
+#define sk_SRTP_PROTECTION_PROFILE_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk))
+
+#define sk_SRTP_PROTECTION_PROFILE_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk));
+
+#define sk_SRTP_PROTECTION_PROFILE_value(sk, i) \
+ ((SRTP_PROTECTION_PROFILE *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \
+ (i)))
+
+#define sk_SRTP_PROTECTION_PROFILE_set(sk, i, p) \
+ ((SRTP_PROTECTION_PROFILE *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), (i), \
+ CHECKED_CAST(void *, SRTP_PROTECTION_PROFILE *, p)))
+
+#define sk_SRTP_PROTECTION_PROFILE_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk))
+
+#define sk_SRTP_PROTECTION_PROFILE_pop_free(sk, free_func) \
+ sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \
+ CHECKED_CAST(void (*)(void *), \
+ void (*)(SRTP_PROTECTION_PROFILE *), free_func))
+
+#define sk_SRTP_PROTECTION_PROFILE_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \
+ CHECKED_CAST(void *, SRTP_PROTECTION_PROFILE *, p), (where))
+
+#define sk_SRTP_PROTECTION_PROFILE_delete(sk, where) \
+ ((SRTP_PROTECTION_PROFILE *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \
+ (where)))
+
+#define sk_SRTP_PROTECTION_PROFILE_delete_ptr(sk, p) \
+ ((SRTP_PROTECTION_PROFILE *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \
+ CHECKED_CAST(void *, SRTP_PROTECTION_PROFILE *, p)))
+
+#define sk_SRTP_PROTECTION_PROFILE_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \
+ (out_index), CHECKED_CAST(void *, SRTP_PROTECTION_PROFILE *, p))
+
+#define sk_SRTP_PROTECTION_PROFILE_shift(sk) \
+ ((SRTP_PROTECTION_PROFILE *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk)))
+
+#define sk_SRTP_PROTECTION_PROFILE_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \
+ CHECKED_CAST(void *, SRTP_PROTECTION_PROFILE *, p))
+
+#define sk_SRTP_PROTECTION_PROFILE_pop(sk) \
+ ((SRTP_PROTECTION_PROFILE *)sk_pop( \
+ CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk)))
+
+#define sk_SRTP_PROTECTION_PROFILE_dup(sk) \
+ ((STACK_OF(SRTP_PROTECTION_PROFILE) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(SRTP_PROTECTION_PROFILE) *, sk)))
+
+#define sk_SRTP_PROTECTION_PROFILE_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk))
+
+#define sk_SRTP_PROTECTION_PROFILE_is_sorted(sk) \
+ sk_is_sorted( \
+ CHECKED_CAST(_STACK *, const STACK_OF(SRTP_PROTECTION_PROFILE) *, sk))
+
+#define sk_SRTP_PROTECTION_PROFILE_set_cmp_func(sk, comp) \
+ ((int (*)(const SRTP_PROTECTION_PROFILE **a, \
+ const SRTP_PROTECTION_PROFILE **b)) \
+ sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const SRTP_PROTECTION_PROFILE **a, \
+ const SRTP_PROTECTION_PROFILE **b), \
+ comp)))
+
+/* SSL_CIPHER */
+#define sk_SSL_CIPHER_new(comp) \
+ ((STACK_OF(SSL_CIPHER) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, int (*)(const SSL_CIPHER **a, const SSL_CIPHER **b), \
+ comp)))
+
+#define sk_SSL_CIPHER_new_null() ((STACK_OF(SSL_CIPHER) *)sk_new_null())
+
+#define sk_SSL_CIPHER_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk))
+
+#define sk_SSL_CIPHER_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk));
+
+#define sk_SSL_CIPHER_value(sk, i) \
+ ((SSL_CIPHER *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(SSL_CIPHER) *, sk), (i)))
+
+#define sk_SSL_CIPHER_set(sk, i, p) \
+ ((SSL_CIPHER *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), \
+ (i), CHECKED_CAST(void *, SSL_CIPHER *, p)))
+
+#define sk_SSL_CIPHER_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk))
+
+#define sk_SSL_CIPHER_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(SSL_CIPHER *), free_func))
+
+#define sk_SSL_CIPHER_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), \
+ CHECKED_CAST(void *, SSL_CIPHER *, p), (where))
+
+#define sk_SSL_CIPHER_delete(sk, where) \
+ ((SSL_CIPHER *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), \
+ (where)))
+
+#define sk_SSL_CIPHER_delete_ptr(sk, p) \
+ ((SSL_CIPHER *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), \
+ CHECKED_CAST(void *, SSL_CIPHER *, p)))
+
+#define sk_SSL_CIPHER_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), (out_index), \
+ CHECKED_CAST(void *, SSL_CIPHER *, p))
+
+#define sk_SSL_CIPHER_shift(sk) \
+ ((SSL_CIPHER *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk)))
+
+#define sk_SSL_CIPHER_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), \
+ CHECKED_CAST(void *, SSL_CIPHER *, p))
+
+#define sk_SSL_CIPHER_pop(sk) \
+ ((SSL_CIPHER *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk)))
+
+#define sk_SSL_CIPHER_dup(sk) \
+ ((STACK_OF(SSL_CIPHER) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(SSL_CIPHER) *, sk)))
+
+#define sk_SSL_CIPHER_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk))
+
+#define sk_SSL_CIPHER_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(SSL_CIPHER) *, sk))
+
+#define sk_SSL_CIPHER_set_cmp_func(sk, comp) \
+ ((int (*)(const SSL_CIPHER **a, const SSL_CIPHER **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const SSL_CIPHER **a, const SSL_CIPHER **b), \
+ comp)))
+
+/* SSL_COMP */
+#define sk_SSL_COMP_new(comp) \
+ ((STACK_OF(SSL_COMP) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, int (*)(const SSL_COMP **a, const SSL_COMP **b), comp)))
+
+#define sk_SSL_COMP_new_null() ((STACK_OF(SSL_COMP) *)sk_new_null())
+
+#define sk_SSL_COMP_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk))
+
+#define sk_SSL_COMP_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk));
+
+#define sk_SSL_COMP_value(sk, i) \
+ ((SSL_COMP *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(SSL_COMP) *, sk), (i)))
+
+#define sk_SSL_COMP_set(sk, i, p) \
+ ((SSL_COMP *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), (i), \
+ CHECKED_CAST(void *, SSL_COMP *, p)))
+
+#define sk_SSL_COMP_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk))
+
+#define sk_SSL_COMP_pop_free(sk, free_func) \
+ sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(SSL_COMP *), free_func))
+
+#define sk_SSL_COMP_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), \
+ CHECKED_CAST(void *, SSL_COMP *, p), (where))
+
+#define sk_SSL_COMP_delete(sk, where) \
+ ((SSL_COMP *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), \
+ (where)))
+
+#define sk_SSL_COMP_delete_ptr(sk, p) \
+ ((SSL_COMP *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), \
+ CHECKED_CAST(void *, SSL_COMP *, p)))
+
+#define sk_SSL_COMP_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), (out_index), \
+ CHECKED_CAST(void *, SSL_COMP *, p))
+
+#define sk_SSL_COMP_shift(sk) \
+ ((SSL_COMP *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk)))
+
+#define sk_SSL_COMP_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), \
+ CHECKED_CAST(void *, SSL_COMP *, p))
+
+#define sk_SSL_COMP_pop(sk) \
+ ((SSL_COMP *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk)))
+
+#define sk_SSL_COMP_dup(sk) \
+ ((STACK_OF(SSL_COMP) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(SSL_COMP) *, sk)))
+
+#define sk_SSL_COMP_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk))
+
+#define sk_SSL_COMP_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(SSL_COMP) *, sk))
+
+#define sk_SSL_COMP_set_cmp_func(sk, comp) \
+ ((int (*)(const SSL_COMP **a, const SSL_COMP **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const SSL_COMP **a, const SSL_COMP **b), comp)))
+
+/* STACK_OF_X509_NAME_ENTRY */
+#define sk_STACK_OF_X509_NAME_ENTRY_new(comp) \
+ ((STACK_OF(STACK_OF_X509_NAME_ENTRY) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, int (*)(const STACK_OF_X509_NAME_ENTRY **a, \
+ const STACK_OF_X509_NAME_ENTRY **b), \
+ comp)))
+
+#define sk_STACK_OF_X509_NAME_ENTRY_new_null() \
+ ((STACK_OF(STACK_OF_X509_NAME_ENTRY) *)sk_new_null())
+
+#define sk_STACK_OF_X509_NAME_ENTRY_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk))
+
+#define sk_STACK_OF_X509_NAME_ENTRY_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk));
+
+#define sk_STACK_OF_X509_NAME_ENTRY_value(sk, i) \
+ ((STACK_OF_X509_NAME_ENTRY *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \
+ (i)))
+
+#define sk_STACK_OF_X509_NAME_ENTRY_set(sk, i, p) \
+ ((STACK_OF_X509_NAME_ENTRY *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), (i), \
+ CHECKED_CAST(void *, STACK_OF_X509_NAME_ENTRY *, p)))
+
+#define sk_STACK_OF_X509_NAME_ENTRY_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk))
+
+#define sk_STACK_OF_X509_NAME_ENTRY_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(STACK_OF_X509_NAME_ENTRY *), \
+ free_func))
+
+#define sk_STACK_OF_X509_NAME_ENTRY_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \
+ CHECKED_CAST(void *, STACK_OF_X509_NAME_ENTRY *, p), (where))
+
+#define sk_STACK_OF_X509_NAME_ENTRY_delete(sk, where) \
+ ((STACK_OF_X509_NAME_ENTRY *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \
+ (where)))
+
+#define sk_STACK_OF_X509_NAME_ENTRY_delete_ptr(sk, p) \
+ ((STACK_OF_X509_NAME_ENTRY *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \
+ CHECKED_CAST(void *, STACK_OF_X509_NAME_ENTRY *, p)))
+
+#define sk_STACK_OF_X509_NAME_ENTRY_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \
+ (out_index), CHECKED_CAST(void *, STACK_OF_X509_NAME_ENTRY *, p))
+
+#define sk_STACK_OF_X509_NAME_ENTRY_shift(sk) \
+ ((STACK_OF_X509_NAME_ENTRY *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk)))
+
+#define sk_STACK_OF_X509_NAME_ENTRY_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \
+ CHECKED_CAST(void *, STACK_OF_X509_NAME_ENTRY *, p))
+
+#define sk_STACK_OF_X509_NAME_ENTRY_pop(sk) \
+ ((STACK_OF_X509_NAME_ENTRY *)sk_pop( \
+ CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk)))
+
+#define sk_STACK_OF_X509_NAME_ENTRY_dup(sk) \
+ ((STACK_OF(STACK_OF_X509_NAME_ENTRY) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk)))
+
+#define sk_STACK_OF_X509_NAME_ENTRY_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk))
+
+#define sk_STACK_OF_X509_NAME_ENTRY_is_sorted(sk) \
+ sk_is_sorted( \
+ CHECKED_CAST(_STACK *, const STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk))
+
+#define sk_STACK_OF_X509_NAME_ENTRY_set_cmp_func(sk, comp) \
+ ((int (*)(const STACK_OF_X509_NAME_ENTRY **a, \
+ const STACK_OF_X509_NAME_ENTRY **b)) \
+ sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const STACK_OF_X509_NAME_ENTRY **a, \
+ const STACK_OF_X509_NAME_ENTRY **b), \
+ comp)))
+
+/* SXNETID */
+#define sk_SXNETID_new(comp) \
+ ((STACK_OF(SXNETID) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, int (*)(const SXNETID **a, const SXNETID **b), comp)))
+
+#define sk_SXNETID_new_null() ((STACK_OF(SXNETID) *)sk_new_null())
+
+#define sk_SXNETID_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk))
+
+#define sk_SXNETID_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk));
+
+#define sk_SXNETID_value(sk, i) \
+ ((SXNETID *)sk_value(CHECKED_CAST(_STACK *, const STACK_OF(SXNETID) *, sk), \
+ (i)))
+
+#define sk_SXNETID_set(sk, i, p) \
+ ((SXNETID *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), (i), \
+ CHECKED_CAST(void *, SXNETID *, p)))
+
+#define sk_SXNETID_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk))
+
+#define sk_SXNETID_pop_free(sk, free_func) \
+ sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(SXNETID *), free_func))
+
+#define sk_SXNETID_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), \
+ CHECKED_CAST(void *, SXNETID *, p), (where))
+
+#define sk_SXNETID_delete(sk, where) \
+ ((SXNETID *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), \
+ (where)))
+
+#define sk_SXNETID_delete_ptr(sk, p) \
+ ((SXNETID *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), \
+ CHECKED_CAST(void *, SXNETID *, p)))
+
+#define sk_SXNETID_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), (out_index), \
+ CHECKED_CAST(void *, SXNETID *, p))
+
+#define sk_SXNETID_shift(sk) \
+ ((SXNETID *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk)))
+
+#define sk_SXNETID_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), \
+ CHECKED_CAST(void *, SXNETID *, p))
+
+#define sk_SXNETID_pop(sk) \
+ ((SXNETID *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk)))
+
+#define sk_SXNETID_dup(sk) \
+ ((STACK_OF(SXNETID) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(SXNETID) *, sk)))
+
+#define sk_SXNETID_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk))
+
+#define sk_SXNETID_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(SXNETID) *, sk))
+
+#define sk_SXNETID_set_cmp_func(sk, comp) \
+ ((int (*)(const SXNETID **a, const SXNETID **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const SXNETID **a, const SXNETID **b), comp)))
+
+/* X509 */
+#define sk_X509_new(comp) \
+ ((STACK_OF(X509) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, int (*)(const X509 **a, const X509 **b), comp)))
+
+#define sk_X509_new_null() ((STACK_OF(X509) *)sk_new_null())
+
+#define sk_X509_num(sk) sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk))
+
+#define sk_X509_zero(sk) sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk));
+
+#define sk_X509_value(sk, i) \
+ ((X509 *)sk_value(CHECKED_CAST(_STACK *, const STACK_OF(X509) *, sk), (i)))
+
+#define sk_X509_set(sk, i, p) \
+ ((X509 *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), (i), \
+ CHECKED_CAST(void *, X509 *, p)))
+
+#define sk_X509_free(sk) sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk))
+
+#define sk_X509_pop_free(sk, free_func) \
+ sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(X509 *), free_func))
+
+#define sk_X509_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), \
+ CHECKED_CAST(void *, X509 *, p), (where))
+
+#define sk_X509_delete(sk, where) \
+ ((X509 *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), (where)))
+
+#define sk_X509_delete_ptr(sk, p) \
+ ((X509 *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), \
+ CHECKED_CAST(void *, X509 *, p)))
+
+#define sk_X509_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), (out_index), \
+ CHECKED_CAST(void *, X509 *, p))
+
+#define sk_X509_shift(sk) \
+ ((X509 *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk)))
+
+#define sk_X509_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), \
+ CHECKED_CAST(void *, X509 *, p))
+
+#define sk_X509_pop(sk) \
+ ((X509 *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk)))
+
+#define sk_X509_dup(sk) \
+ ((STACK_OF(X509) *)sk_dup(CHECKED_CAST(_STACK *, const STACK_OF(X509) *, sk)))
+
+#define sk_X509_sort(sk) sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk))
+
+#define sk_X509_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509) *, sk))
+
+#define sk_X509_set_cmp_func(sk, comp) \
+ ((int (*)(const X509 **a, const X509 **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), \
+ CHECKED_CAST(stack_cmp_func, int (*)(const X509 **a, const X509 **b), \
+ comp)))
+
+/* X509V3_EXT_METHOD */
+#define sk_X509V3_EXT_METHOD_new(comp) \
+ ((STACK_OF(X509V3_EXT_METHOD) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, \
+ int (*)(const X509V3_EXT_METHOD **a, const X509V3_EXT_METHOD **b), \
+ comp)))
+
+#define sk_X509V3_EXT_METHOD_new_null() \
+ ((STACK_OF(X509V3_EXT_METHOD) *)sk_new_null())
+
+#define sk_X509V3_EXT_METHOD_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk))
+
+#define sk_X509V3_EXT_METHOD_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk));
+
+#define sk_X509V3_EXT_METHOD_value(sk, i) \
+ ((X509V3_EXT_METHOD *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509V3_EXT_METHOD) *, sk), (i)))
+
+#define sk_X509V3_EXT_METHOD_set(sk, i, p) \
+ ((X509V3_EXT_METHOD *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), (i), \
+ CHECKED_CAST(void *, X509V3_EXT_METHOD *, p)))
+
+#define sk_X509V3_EXT_METHOD_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk))
+
+#define sk_X509V3_EXT_METHOD_pop_free(sk, free_func) \
+ sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(X509V3_EXT_METHOD *), \
+ free_func))
+
+#define sk_X509V3_EXT_METHOD_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), \
+ CHECKED_CAST(void *, X509V3_EXT_METHOD *, p), (where))
+
+#define sk_X509V3_EXT_METHOD_delete(sk, where) \
+ ((X509V3_EXT_METHOD *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), (where)))
+
+#define sk_X509V3_EXT_METHOD_delete_ptr(sk, p) \
+ ((X509V3_EXT_METHOD *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), \
+ CHECKED_CAST(void *, X509V3_EXT_METHOD *, p)))
+
+#define sk_X509V3_EXT_METHOD_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), \
+ (out_index), CHECKED_CAST(void *, X509V3_EXT_METHOD *, p))
+
+#define sk_X509V3_EXT_METHOD_shift(sk) \
+ ((X509V3_EXT_METHOD *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk)))
+
+#define sk_X509V3_EXT_METHOD_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), \
+ CHECKED_CAST(void *, X509V3_EXT_METHOD *, p))
+
+#define sk_X509V3_EXT_METHOD_pop(sk) \
+ ((X509V3_EXT_METHOD *)sk_pop( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk)))
+
+#define sk_X509V3_EXT_METHOD_dup(sk) \
+ ((STACK_OF(X509V3_EXT_METHOD) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509V3_EXT_METHOD) *, sk)))
+
+#define sk_X509V3_EXT_METHOD_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk))
+
+#define sk_X509V3_EXT_METHOD_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509V3_EXT_METHOD) *, sk))
+
+#define sk_X509V3_EXT_METHOD_set_cmp_func(sk, comp) \
+ ((int (*)(const X509V3_EXT_METHOD **a, const X509V3_EXT_METHOD **b)) \
+ sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), \
+ CHECKED_CAST(stack_cmp_func, int (*)(const X509V3_EXT_METHOD **a, \
+ const X509V3_EXT_METHOD **b), \
+ comp)))
+
+/* X509_ALGOR */
+#define sk_X509_ALGOR_new(comp) \
+ ((STACK_OF(X509_ALGOR) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, int (*)(const X509_ALGOR **a, const X509_ALGOR **b), \
+ comp)))
+
+#define sk_X509_ALGOR_new_null() ((STACK_OF(X509_ALGOR) *)sk_new_null())
+
+#define sk_X509_ALGOR_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk))
+
+#define sk_X509_ALGOR_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk));
+
+#define sk_X509_ALGOR_value(sk, i) \
+ ((X509_ALGOR *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_ALGOR) *, sk), (i)))
+
+#define sk_X509_ALGOR_set(sk, i, p) \
+ ((X509_ALGOR *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \
+ (i), CHECKED_CAST(void *, X509_ALGOR *, p)))
+
+#define sk_X509_ALGOR_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk))
+
+#define sk_X509_ALGOR_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(X509_ALGOR *), free_func))
+
+#define sk_X509_ALGOR_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \
+ CHECKED_CAST(void *, X509_ALGOR *, p), (where))
+
+#define sk_X509_ALGOR_delete(sk, where) \
+ ((X509_ALGOR *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \
+ (where)))
+
+#define sk_X509_ALGOR_delete_ptr(sk, p) \
+ ((X509_ALGOR *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \
+ CHECKED_CAST(void *, X509_ALGOR *, p)))
+
+#define sk_X509_ALGOR_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), (out_index), \
+ CHECKED_CAST(void *, X509_ALGOR *, p))
+
+#define sk_X509_ALGOR_shift(sk) \
+ ((X509_ALGOR *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk)))
+
+#define sk_X509_ALGOR_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \
+ CHECKED_CAST(void *, X509_ALGOR *, p))
+
+#define sk_X509_ALGOR_pop(sk) \
+ ((X509_ALGOR *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk)))
+
+#define sk_X509_ALGOR_dup(sk) \
+ ((STACK_OF(X509_ALGOR) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_ALGOR) *, sk)))
+
+#define sk_X509_ALGOR_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk))
+
+#define sk_X509_ALGOR_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_ALGOR) *, sk))
+
+#define sk_X509_ALGOR_set_cmp_func(sk, comp) \
+ ((int (*)(const X509_ALGOR **a, const X509_ALGOR **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const X509_ALGOR **a, const X509_ALGOR **b), \
+ comp)))
+
+/* X509_ATTRIBUTE */
+#define sk_X509_ATTRIBUTE_new(comp) \
+ ((STACK_OF(X509_ATTRIBUTE) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, \
+ int (*)(const X509_ATTRIBUTE **a, const X509_ATTRIBUTE **b), comp)))
+
+#define sk_X509_ATTRIBUTE_new_null() ((STACK_OF(X509_ATTRIBUTE) *)sk_new_null())
+
+#define sk_X509_ATTRIBUTE_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk))
+
+#define sk_X509_ATTRIBUTE_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk));
+
+#define sk_X509_ATTRIBUTE_value(sk, i) \
+ ((X509_ATTRIBUTE *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk), (i)))
+
+#define sk_X509_ATTRIBUTE_set(sk, i, p) \
+ ((X509_ATTRIBUTE *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), (i), \
+ CHECKED_CAST(void *, X509_ATTRIBUTE *, p)))
+
+#define sk_X509_ATTRIBUTE_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk))
+
+#define sk_X509_ATTRIBUTE_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(X509_ATTRIBUTE *), free_func))
+
+#define sk_X509_ATTRIBUTE_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \
+ CHECKED_CAST(void *, X509_ATTRIBUTE *, p), (where))
+
+#define sk_X509_ATTRIBUTE_delete(sk, where) \
+ ((X509_ATTRIBUTE *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), (where)))
+
+#define sk_X509_ATTRIBUTE_delete_ptr(sk, p) \
+ ((X509_ATTRIBUTE *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \
+ CHECKED_CAST(void *, X509_ATTRIBUTE *, p)))
+
+#define sk_X509_ATTRIBUTE_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), (out_index), \
+ CHECKED_CAST(void *, X509_ATTRIBUTE *, p))
+
+#define sk_X509_ATTRIBUTE_shift(sk) \
+ ((X509_ATTRIBUTE *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk)))
+
+#define sk_X509_ATTRIBUTE_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \
+ CHECKED_CAST(void *, X509_ATTRIBUTE *, p))
+
+#define sk_X509_ATTRIBUTE_pop(sk) \
+ ((X509_ATTRIBUTE *)sk_pop( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk)))
+
+#define sk_X509_ATTRIBUTE_dup(sk) \
+ ((STACK_OF(X509_ATTRIBUTE) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk)))
+
+#define sk_X509_ATTRIBUTE_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk))
+
+#define sk_X509_ATTRIBUTE_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk))
+
+#define sk_X509_ATTRIBUTE_set_cmp_func(sk, comp) \
+ ((int (*)(const X509_ATTRIBUTE **a, const X509_ATTRIBUTE **b)) \
+ sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \
+ CHECKED_CAST(stack_cmp_func, int (*)(const X509_ATTRIBUTE **a, \
+ const X509_ATTRIBUTE **b), \
+ comp)))
+
+/* X509_CRL */
+#define sk_X509_CRL_new(comp) \
+ ((STACK_OF(X509_CRL) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, int (*)(const X509_CRL **a, const X509_CRL **b), comp)))
+
+#define sk_X509_CRL_new_null() ((STACK_OF(X509_CRL) *)sk_new_null())
+
+#define sk_X509_CRL_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk))
+
+#define sk_X509_CRL_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk));
+
+#define sk_X509_CRL_value(sk, i) \
+ ((X509_CRL *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_CRL) *, sk), (i)))
+
+#define sk_X509_CRL_set(sk, i, p) \
+ ((X509_CRL *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), (i), \
+ CHECKED_CAST(void *, X509_CRL *, p)))
+
+#define sk_X509_CRL_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk))
+
+#define sk_X509_CRL_pop_free(sk, free_func) \
+ sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(X509_CRL *), free_func))
+
+#define sk_X509_CRL_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \
+ CHECKED_CAST(void *, X509_CRL *, p), (where))
+
+#define sk_X509_CRL_delete(sk, where) \
+ ((X509_CRL *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \
+ (where)))
+
+#define sk_X509_CRL_delete_ptr(sk, p) \
+ ((X509_CRL *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \
+ CHECKED_CAST(void *, X509_CRL *, p)))
+
+#define sk_X509_CRL_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), (out_index), \
+ CHECKED_CAST(void *, X509_CRL *, p))
+
+#define sk_X509_CRL_shift(sk) \
+ ((X509_CRL *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk)))
+
+#define sk_X509_CRL_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \
+ CHECKED_CAST(void *, X509_CRL *, p))
+
+#define sk_X509_CRL_pop(sk) \
+ ((X509_CRL *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk)))
+
+#define sk_X509_CRL_dup(sk) \
+ ((STACK_OF(X509_CRL) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_CRL) *, sk)))
+
+#define sk_X509_CRL_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk))
+
+#define sk_X509_CRL_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_CRL) *, sk))
+
+#define sk_X509_CRL_set_cmp_func(sk, comp) \
+ ((int (*)(const X509_CRL **a, const X509_CRL **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const X509_CRL **a, const X509_CRL **b), comp)))
+
+/* X509_EXTENSION */
+#define sk_X509_EXTENSION_new(comp) \
+ ((STACK_OF(X509_EXTENSION) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, \
+ int (*)(const X509_EXTENSION **a, const X509_EXTENSION **b), comp)))
+
+#define sk_X509_EXTENSION_new_null() ((STACK_OF(X509_EXTENSION) *)sk_new_null())
+
+#define sk_X509_EXTENSION_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk))
+
+#define sk_X509_EXTENSION_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk));
+
+#define sk_X509_EXTENSION_value(sk, i) \
+ ((X509_EXTENSION *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_EXTENSION) *, sk), (i)))
+
+#define sk_X509_EXTENSION_set(sk, i, p) \
+ ((X509_EXTENSION *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), (i), \
+ CHECKED_CAST(void *, X509_EXTENSION *, p)))
+
+#define sk_X509_EXTENSION_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk))
+
+#define sk_X509_EXTENSION_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(X509_EXTENSION *), free_func))
+
+#define sk_X509_EXTENSION_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \
+ CHECKED_CAST(void *, X509_EXTENSION *, p), (where))
+
+#define sk_X509_EXTENSION_delete(sk, where) \
+ ((X509_EXTENSION *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), (where)))
+
+#define sk_X509_EXTENSION_delete_ptr(sk, p) \
+ ((X509_EXTENSION *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \
+ CHECKED_CAST(void *, X509_EXTENSION *, p)))
+
+#define sk_X509_EXTENSION_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), (out_index), \
+ CHECKED_CAST(void *, X509_EXTENSION *, p))
+
+#define sk_X509_EXTENSION_shift(sk) \
+ ((X509_EXTENSION *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk)))
+
+#define sk_X509_EXTENSION_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \
+ CHECKED_CAST(void *, X509_EXTENSION *, p))
+
+#define sk_X509_EXTENSION_pop(sk) \
+ ((X509_EXTENSION *)sk_pop( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk)))
+
+#define sk_X509_EXTENSION_dup(sk) \
+ ((STACK_OF(X509_EXTENSION) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_EXTENSION) *, sk)))
+
+#define sk_X509_EXTENSION_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk))
+
+#define sk_X509_EXTENSION_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_EXTENSION) *, sk))
+
+#define sk_X509_EXTENSION_set_cmp_func(sk, comp) \
+ ((int (*)(const X509_EXTENSION **a, const X509_EXTENSION **b)) \
+ sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \
+ CHECKED_CAST(stack_cmp_func, int (*)(const X509_EXTENSION **a, \
+ const X509_EXTENSION **b), \
+ comp)))
+
+/* X509_INFO */
+#define sk_X509_INFO_new(comp) \
+ ((STACK_OF(X509_INFO) *)sk_new( \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const X509_INFO **a, const X509_INFO **b), comp)))
+
+#define sk_X509_INFO_new_null() ((STACK_OF(X509_INFO) *)sk_new_null())
+
+#define sk_X509_INFO_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk))
+
+#define sk_X509_INFO_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk));
+
+#define sk_X509_INFO_value(sk, i) \
+ ((X509_INFO *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_INFO) *, sk), (i)))
+
+#define sk_X509_INFO_set(sk, i, p) \
+ ((X509_INFO *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), (i), \
+ CHECKED_CAST(void *, X509_INFO *, p)))
+
+#define sk_X509_INFO_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk))
+
+#define sk_X509_INFO_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(X509_INFO *), free_func))
+
+#define sk_X509_INFO_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \
+ CHECKED_CAST(void *, X509_INFO *, p), (where))
+
+#define sk_X509_INFO_delete(sk, where) \
+ ((X509_INFO *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \
+ (where)))
+
+#define sk_X509_INFO_delete_ptr(sk, p) \
+ ((X509_INFO *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \
+ CHECKED_CAST(void *, X509_INFO *, p)))
+
+#define sk_X509_INFO_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), (out_index), \
+ CHECKED_CAST(void *, X509_INFO *, p))
+
+#define sk_X509_INFO_shift(sk) \
+ ((X509_INFO *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk)))
+
+#define sk_X509_INFO_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \
+ CHECKED_CAST(void *, X509_INFO *, p))
+
+#define sk_X509_INFO_pop(sk) \
+ ((X509_INFO *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk)))
+
+#define sk_X509_INFO_dup(sk) \
+ ((STACK_OF(X509_INFO) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_INFO) *, sk)))
+
+#define sk_X509_INFO_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk))
+
+#define sk_X509_INFO_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_INFO) *, sk))
+
+#define sk_X509_INFO_set_cmp_func(sk, comp) \
+ ((int (*)(const X509_INFO **a, const X509_INFO **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const X509_INFO **a, const X509_INFO **b), comp)))
+
+/* X509_LOOKUP */
+#define sk_X509_LOOKUP_new(comp) \
+ ((STACK_OF(X509_LOOKUP) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, int (*)(const X509_LOOKUP **a, const X509_LOOKUP **b), \
+ comp)))
+
+#define sk_X509_LOOKUP_new_null() ((STACK_OF(X509_LOOKUP) *)sk_new_null())
+
+#define sk_X509_LOOKUP_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk))
+
+#define sk_X509_LOOKUP_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk));
+
+#define sk_X509_LOOKUP_value(sk, i) \
+ ((X509_LOOKUP *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_LOOKUP) *, sk), (i)))
+
+#define sk_X509_LOOKUP_set(sk, i, p) \
+ ((X509_LOOKUP *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \
+ (i), CHECKED_CAST(void *, X509_LOOKUP *, p)))
+
+#define sk_X509_LOOKUP_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk))
+
+#define sk_X509_LOOKUP_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(X509_LOOKUP *), free_func))
+
+#define sk_X509_LOOKUP_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \
+ CHECKED_CAST(void *, X509_LOOKUP *, p), (where))
+
+#define sk_X509_LOOKUP_delete(sk, where) \
+ ((X509_LOOKUP *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), (where)))
+
+#define sk_X509_LOOKUP_delete_ptr(sk, p) \
+ ((X509_LOOKUP *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \
+ CHECKED_CAST(void *, X509_LOOKUP *, p)))
+
+#define sk_X509_LOOKUP_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), (out_index), \
+ CHECKED_CAST(void *, X509_LOOKUP *, p))
+
+#define sk_X509_LOOKUP_shift(sk) \
+ ((X509_LOOKUP *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk)))
+
+#define sk_X509_LOOKUP_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \
+ CHECKED_CAST(void *, X509_LOOKUP *, p))
+
+#define sk_X509_LOOKUP_pop(sk) \
+ ((X509_LOOKUP *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk)))
+
+#define sk_X509_LOOKUP_dup(sk) \
+ ((STACK_OF(X509_LOOKUP) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_LOOKUP) *, sk)))
+
+#define sk_X509_LOOKUP_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk))
+
+#define sk_X509_LOOKUP_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_LOOKUP) *, sk))
+
+#define sk_X509_LOOKUP_set_cmp_func(sk, comp) \
+ ((int (*)(const X509_LOOKUP **a, const X509_LOOKUP **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const X509_LOOKUP **a, const X509_LOOKUP **b), \
+ comp)))
+
+/* X509_NAME */
+#define sk_X509_NAME_new(comp) \
+ ((STACK_OF(X509_NAME) *)sk_new( \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const X509_NAME **a, const X509_NAME **b), comp)))
+
+#define sk_X509_NAME_new_null() ((STACK_OF(X509_NAME) *)sk_new_null())
+
+#define sk_X509_NAME_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk))
+
+#define sk_X509_NAME_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk));
+
+#define sk_X509_NAME_value(sk, i) \
+ ((X509_NAME *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME) *, sk), (i)))
+
+#define sk_X509_NAME_set(sk, i, p) \
+ ((X509_NAME *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), (i), \
+ CHECKED_CAST(void *, X509_NAME *, p)))
+
+#define sk_X509_NAME_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk))
+
+#define sk_X509_NAME_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(X509_NAME *), free_func))
+
+#define sk_X509_NAME_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \
+ CHECKED_CAST(void *, X509_NAME *, p), (where))
+
+#define sk_X509_NAME_delete(sk, where) \
+ ((X509_NAME *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \
+ (where)))
+
+#define sk_X509_NAME_delete_ptr(sk, p) \
+ ((X509_NAME *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \
+ CHECKED_CAST(void *, X509_NAME *, p)))
+
+#define sk_X509_NAME_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), (out_index), \
+ CHECKED_CAST(void *, X509_NAME *, p))
+
+#define sk_X509_NAME_shift(sk) \
+ ((X509_NAME *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk)))
+
+#define sk_X509_NAME_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \
+ CHECKED_CAST(void *, X509_NAME *, p))
+
+#define sk_X509_NAME_pop(sk) \
+ ((X509_NAME *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk)))
+
+#define sk_X509_NAME_dup(sk) \
+ ((STACK_OF(X509_NAME) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME) *, sk)))
+
+#define sk_X509_NAME_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk))
+
+#define sk_X509_NAME_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME) *, sk))
+
+#define sk_X509_NAME_set_cmp_func(sk, comp) \
+ ((int (*)(const X509_NAME **a, const X509_NAME **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const X509_NAME **a, const X509_NAME **b), comp)))
+
+/* X509_NAME_ENTRY */
+#define sk_X509_NAME_ENTRY_new(comp) \
+ ((STACK_OF(X509_NAME_ENTRY) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, \
+ int (*)(const X509_NAME_ENTRY **a, const X509_NAME_ENTRY **b), comp)))
+
+#define sk_X509_NAME_ENTRY_new_null() \
+ ((STACK_OF(X509_NAME_ENTRY) *)sk_new_null())
+
+#define sk_X509_NAME_ENTRY_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk))
+
+#define sk_X509_NAME_ENTRY_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk));
+
+#define sk_X509_NAME_ENTRY_value(sk, i) \
+ ((X509_NAME_ENTRY *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk), (i)))
+
+#define sk_X509_NAME_ENTRY_set(sk, i, p) \
+ ((X509_NAME_ENTRY *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), (i), \
+ CHECKED_CAST(void *, X509_NAME_ENTRY *, p)))
+
+#define sk_X509_NAME_ENTRY_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk))
+
+#define sk_X509_NAME_ENTRY_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(X509_NAME_ENTRY *), free_func))
+
+#define sk_X509_NAME_ENTRY_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \
+ CHECKED_CAST(void *, X509_NAME_ENTRY *, p), (where))
+
+#define sk_X509_NAME_ENTRY_delete(sk, where) \
+ ((X509_NAME_ENTRY *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), (where)))
+
+#define sk_X509_NAME_ENTRY_delete_ptr(sk, p) \
+ ((X509_NAME_ENTRY *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \
+ CHECKED_CAST(void *, X509_NAME_ENTRY *, p)))
+
+#define sk_X509_NAME_ENTRY_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \
+ (out_index), CHECKED_CAST(void *, X509_NAME_ENTRY *, p))
+
+#define sk_X509_NAME_ENTRY_shift(sk) \
+ ((X509_NAME_ENTRY *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk)))
+
+#define sk_X509_NAME_ENTRY_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \
+ CHECKED_CAST(void *, X509_NAME_ENTRY *, p))
+
+#define sk_X509_NAME_ENTRY_pop(sk) \
+ ((X509_NAME_ENTRY *)sk_pop( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk)))
+
+#define sk_X509_NAME_ENTRY_dup(sk) \
+ ((STACK_OF(X509_NAME_ENTRY) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk)))
+
+#define sk_X509_NAME_ENTRY_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk))
+
+#define sk_X509_NAME_ENTRY_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk))
+
+#define sk_X509_NAME_ENTRY_set_cmp_func(sk, comp) \
+ ((int (*)(const X509_NAME_ENTRY **a, const X509_NAME_ENTRY **b)) \
+ sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \
+ CHECKED_CAST(stack_cmp_func, int (*)(const X509_NAME_ENTRY **a, \
+ const X509_NAME_ENTRY **b), \
+ comp)))
+
+/* X509_NAME_ENTRY */
+#define sk_X509_NAME_ENTRY_new(comp) \
+ ((STACK_OF(X509_NAME_ENTRY) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, \
+ int (*)(const X509_NAME_ENTRY **a, const X509_NAME_ENTRY **b), comp)))
+
+#define sk_X509_NAME_ENTRY_new_null() \
+ ((STACK_OF(X509_NAME_ENTRY) *)sk_new_null())
+
+#define sk_X509_NAME_ENTRY_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk))
+
+#define sk_X509_NAME_ENTRY_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk));
+
+#define sk_X509_NAME_ENTRY_value(sk, i) \
+ ((X509_NAME_ENTRY *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk), (i)))
+
+#define sk_X509_NAME_ENTRY_set(sk, i, p) \
+ ((X509_NAME_ENTRY *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), (i), \
+ CHECKED_CAST(void *, X509_NAME_ENTRY *, p)))
+
+#define sk_X509_NAME_ENTRY_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk))
+
+#define sk_X509_NAME_ENTRY_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(X509_NAME_ENTRY *), free_func))
+
+#define sk_X509_NAME_ENTRY_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \
+ CHECKED_CAST(void *, X509_NAME_ENTRY *, p), (where))
+
+#define sk_X509_NAME_ENTRY_delete(sk, where) \
+ ((X509_NAME_ENTRY *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), (where)))
+
+#define sk_X509_NAME_ENTRY_delete_ptr(sk, p) \
+ ((X509_NAME_ENTRY *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \
+ CHECKED_CAST(void *, X509_NAME_ENTRY *, p)))
+
+#define sk_X509_NAME_ENTRY_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \
+ (out_index), CHECKED_CAST(void *, X509_NAME_ENTRY *, p))
+
+#define sk_X509_NAME_ENTRY_shift(sk) \
+ ((X509_NAME_ENTRY *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk)))
+
+#define sk_X509_NAME_ENTRY_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \
+ CHECKED_CAST(void *, X509_NAME_ENTRY *, p))
+
+#define sk_X509_NAME_ENTRY_pop(sk) \
+ ((X509_NAME_ENTRY *)sk_pop( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk)))
+
+#define sk_X509_NAME_ENTRY_dup(sk) \
+ ((STACK_OF(X509_NAME_ENTRY) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk)))
+
+#define sk_X509_NAME_ENTRY_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk))
+
+#define sk_X509_NAME_ENTRY_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk))
+
+#define sk_X509_NAME_ENTRY_set_cmp_func(sk, comp) \
+ ((int (*)(const X509_NAME_ENTRY **a, const X509_NAME_ENTRY **b)) \
+ sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \
+ CHECKED_CAST(stack_cmp_func, int (*)(const X509_NAME_ENTRY **a, \
+ const X509_NAME_ENTRY **b), \
+ comp)))
+
+/* X509_OBJECT */
+#define sk_X509_OBJECT_new(comp) \
+ ((STACK_OF(X509_OBJECT) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, int (*)(const X509_OBJECT **a, const X509_OBJECT **b), \
+ comp)))
+
+#define sk_X509_OBJECT_new_null() ((STACK_OF(X509_OBJECT) *)sk_new_null())
+
+#define sk_X509_OBJECT_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk))
+
+#define sk_X509_OBJECT_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk));
+
+#define sk_X509_OBJECT_value(sk, i) \
+ ((X509_OBJECT *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_OBJECT) *, sk), (i)))
+
+#define sk_X509_OBJECT_set(sk, i, p) \
+ ((X509_OBJECT *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \
+ (i), CHECKED_CAST(void *, X509_OBJECT *, p)))
+
+#define sk_X509_OBJECT_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk))
+
+#define sk_X509_OBJECT_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(X509_OBJECT *), free_func))
+
+#define sk_X509_OBJECT_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \
+ CHECKED_CAST(void *, X509_OBJECT *, p), (where))
+
+#define sk_X509_OBJECT_delete(sk, where) \
+ ((X509_OBJECT *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), (where)))
+
+#define sk_X509_OBJECT_delete_ptr(sk, p) \
+ ((X509_OBJECT *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \
+ CHECKED_CAST(void *, X509_OBJECT *, p)))
+
+#define sk_X509_OBJECT_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), (out_index), \
+ CHECKED_CAST(void *, X509_OBJECT *, p))
+
+#define sk_X509_OBJECT_shift(sk) \
+ ((X509_OBJECT *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk)))
+
+#define sk_X509_OBJECT_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \
+ CHECKED_CAST(void *, X509_OBJECT *, p))
+
+#define sk_X509_OBJECT_pop(sk) \
+ ((X509_OBJECT *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk)))
+
+#define sk_X509_OBJECT_dup(sk) \
+ ((STACK_OF(X509_OBJECT) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_OBJECT) *, sk)))
+
+#define sk_X509_OBJECT_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk))
+
+#define sk_X509_OBJECT_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_OBJECT) *, sk))
+
+#define sk_X509_OBJECT_set_cmp_func(sk, comp) \
+ ((int (*)(const X509_OBJECT **a, const X509_OBJECT **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const X509_OBJECT **a, const X509_OBJECT **b), \
+ comp)))
+
+/* X509_POLICY_DATA */
+#define sk_X509_POLICY_DATA_new(comp) \
+ ((STACK_OF(X509_POLICY_DATA) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, \
+ int (*)(const X509_POLICY_DATA **a, const X509_POLICY_DATA **b), comp)))
+
+#define sk_X509_POLICY_DATA_new_null() \
+ ((STACK_OF(X509_POLICY_DATA) *)sk_new_null())
+
+#define sk_X509_POLICY_DATA_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk))
+
+#define sk_X509_POLICY_DATA_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk));
+
+#define sk_X509_POLICY_DATA_value(sk, i) \
+ ((X509_POLICY_DATA *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_DATA) *, sk), (i)))
+
+#define sk_X509_POLICY_DATA_set(sk, i, p) \
+ ((X509_POLICY_DATA *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), (i), \
+ CHECKED_CAST(void *, X509_POLICY_DATA *, p)))
+
+#define sk_X509_POLICY_DATA_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk))
+
+#define sk_X509_POLICY_DATA_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(X509_POLICY_DATA *), free_func))
+
+#define sk_X509_POLICY_DATA_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \
+ CHECKED_CAST(void *, X509_POLICY_DATA *, p), (where))
+
+#define sk_X509_POLICY_DATA_delete(sk, where) \
+ ((X509_POLICY_DATA *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), (where)))
+
+#define sk_X509_POLICY_DATA_delete_ptr(sk, p) \
+ ((X509_POLICY_DATA *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \
+ CHECKED_CAST(void *, X509_POLICY_DATA *, p)))
+
+#define sk_X509_POLICY_DATA_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \
+ (out_index), CHECKED_CAST(void *, X509_POLICY_DATA *, p))
+
+#define sk_X509_POLICY_DATA_shift(sk) \
+ ((X509_POLICY_DATA *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk)))
+
+#define sk_X509_POLICY_DATA_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \
+ CHECKED_CAST(void *, X509_POLICY_DATA *, p))
+
+#define sk_X509_POLICY_DATA_pop(sk) \
+ ((X509_POLICY_DATA *)sk_pop( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk)))
+
+#define sk_X509_POLICY_DATA_dup(sk) \
+ ((STACK_OF(X509_POLICY_DATA) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_DATA) *, sk)))
+
+#define sk_X509_POLICY_DATA_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk))
+
+#define sk_X509_POLICY_DATA_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_DATA) *, sk))
+
+#define sk_X509_POLICY_DATA_set_cmp_func(sk, comp) \
+ ((int (*)(const X509_POLICY_DATA **a, const X509_POLICY_DATA **b)) \
+ sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \
+ CHECKED_CAST(stack_cmp_func, int (*)(const X509_POLICY_DATA **a, \
+ const X509_POLICY_DATA **b), \
+ comp)))
+
+/* X509_POLICY_NODE */
+#define sk_X509_POLICY_NODE_new(comp) \
+ ((STACK_OF(X509_POLICY_NODE) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, \
+ int (*)(const X509_POLICY_NODE **a, const X509_POLICY_NODE **b), comp)))
+
+#define sk_X509_POLICY_NODE_new_null() \
+ ((STACK_OF(X509_POLICY_NODE) *)sk_new_null())
+
+#define sk_X509_POLICY_NODE_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk))
+
+#define sk_X509_POLICY_NODE_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk));
+
+#define sk_X509_POLICY_NODE_value(sk, i) \
+ ((X509_POLICY_NODE *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_NODE) *, sk), (i)))
+
+#define sk_X509_POLICY_NODE_set(sk, i, p) \
+ ((X509_POLICY_NODE *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), (i), \
+ CHECKED_CAST(void *, X509_POLICY_NODE *, p)))
+
+#define sk_X509_POLICY_NODE_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk))
+
+#define sk_X509_POLICY_NODE_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(X509_POLICY_NODE *), free_func))
+
+#define sk_X509_POLICY_NODE_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \
+ CHECKED_CAST(void *, X509_POLICY_NODE *, p), (where))
+
+#define sk_X509_POLICY_NODE_delete(sk, where) \
+ ((X509_POLICY_NODE *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), (where)))
+
+#define sk_X509_POLICY_NODE_delete_ptr(sk, p) \
+ ((X509_POLICY_NODE *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \
+ CHECKED_CAST(void *, X509_POLICY_NODE *, p)))
+
+#define sk_X509_POLICY_NODE_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \
+ (out_index), CHECKED_CAST(void *, X509_POLICY_NODE *, p))
+
+#define sk_X509_POLICY_NODE_shift(sk) \
+ ((X509_POLICY_NODE *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk)))
+
+#define sk_X509_POLICY_NODE_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \
+ CHECKED_CAST(void *, X509_POLICY_NODE *, p))
+
+#define sk_X509_POLICY_NODE_pop(sk) \
+ ((X509_POLICY_NODE *)sk_pop( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk)))
+
+#define sk_X509_POLICY_NODE_dup(sk) \
+ ((STACK_OF(X509_POLICY_NODE) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_NODE) *, sk)))
+
+#define sk_X509_POLICY_NODE_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk))
+
+#define sk_X509_POLICY_NODE_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_NODE) *, sk))
+
+#define sk_X509_POLICY_NODE_set_cmp_func(sk, comp) \
+ ((int (*)(const X509_POLICY_NODE **a, const X509_POLICY_NODE **b)) \
+ sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \
+ CHECKED_CAST(stack_cmp_func, int (*)(const X509_POLICY_NODE **a, \
+ const X509_POLICY_NODE **b), \
+ comp)))
+
+/* X509_PURPOSE */
+#define sk_X509_PURPOSE_new(comp) \
+ ((STACK_OF(X509_PURPOSE) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, int (*)(const X509_PURPOSE **a, const X509_PURPOSE **b), \
+ comp)))
+
+#define sk_X509_PURPOSE_new_null() ((STACK_OF(X509_PURPOSE) *)sk_new_null())
+
+#define sk_X509_PURPOSE_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk))
+
+#define sk_X509_PURPOSE_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk));
+
+#define sk_X509_PURPOSE_value(sk, i) \
+ ((X509_PURPOSE *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_PURPOSE) *, sk), (i)))
+
+#define sk_X509_PURPOSE_set(sk, i, p) \
+ ((X509_PURPOSE *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), (i), \
+ CHECKED_CAST(void *, X509_PURPOSE *, p)))
+
+#define sk_X509_PURPOSE_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk))
+
+#define sk_X509_PURPOSE_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(X509_PURPOSE *), free_func))
+
+#define sk_X509_PURPOSE_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \
+ CHECKED_CAST(void *, X509_PURPOSE *, p), (where))
+
+#define sk_X509_PURPOSE_delete(sk, where) \
+ ((X509_PURPOSE *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), (where)))
+
+#define sk_X509_PURPOSE_delete_ptr(sk, p) \
+ ((X509_PURPOSE *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \
+ CHECKED_CAST(void *, X509_PURPOSE *, p)))
+
+#define sk_X509_PURPOSE_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), (out_index), \
+ CHECKED_CAST(void *, X509_PURPOSE *, p))
+
+#define sk_X509_PURPOSE_shift(sk) \
+ ((X509_PURPOSE *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk)))
+
+#define sk_X509_PURPOSE_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \
+ CHECKED_CAST(void *, X509_PURPOSE *, p))
+
+#define sk_X509_PURPOSE_pop(sk) \
+ ((X509_PURPOSE *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk)))
+
+#define sk_X509_PURPOSE_dup(sk) \
+ ((STACK_OF(X509_PURPOSE) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_PURPOSE) *, sk)))
+
+#define sk_X509_PURPOSE_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk))
+
+#define sk_X509_PURPOSE_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_PURPOSE) *, sk))
+
+#define sk_X509_PURPOSE_set_cmp_func(sk, comp) \
+ ((int (*)(const X509_PURPOSE **a, const X509_PURPOSE **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const X509_PURPOSE **a, const X509_PURPOSE **b), \
+ comp)))
+
+/* X509_REVOKED */
+#define sk_X509_REVOKED_new(comp) \
+ ((STACK_OF(X509_REVOKED) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, int (*)(const X509_REVOKED **a, const X509_REVOKED **b), \
+ comp)))
+
+#define sk_X509_REVOKED_new_null() ((STACK_OF(X509_REVOKED) *)sk_new_null())
+
+#define sk_X509_REVOKED_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk))
+
+#define sk_X509_REVOKED_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk));
+
+#define sk_X509_REVOKED_value(sk, i) \
+ ((X509_REVOKED *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_REVOKED) *, sk), (i)))
+
+#define sk_X509_REVOKED_set(sk, i, p) \
+ ((X509_REVOKED *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), (i), \
+ CHECKED_CAST(void *, X509_REVOKED *, p)))
+
+#define sk_X509_REVOKED_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk))
+
+#define sk_X509_REVOKED_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(X509_REVOKED *), free_func))
+
+#define sk_X509_REVOKED_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \
+ CHECKED_CAST(void *, X509_REVOKED *, p), (where))
+
+#define sk_X509_REVOKED_delete(sk, where) \
+ ((X509_REVOKED *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), (where)))
+
+#define sk_X509_REVOKED_delete_ptr(sk, p) \
+ ((X509_REVOKED *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \
+ CHECKED_CAST(void *, X509_REVOKED *, p)))
+
+#define sk_X509_REVOKED_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), (out_index), \
+ CHECKED_CAST(void *, X509_REVOKED *, p))
+
+#define sk_X509_REVOKED_shift(sk) \
+ ((X509_REVOKED *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk)))
+
+#define sk_X509_REVOKED_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \
+ CHECKED_CAST(void *, X509_REVOKED *, p))
+
+#define sk_X509_REVOKED_pop(sk) \
+ ((X509_REVOKED *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk)))
+
+#define sk_X509_REVOKED_dup(sk) \
+ ((STACK_OF(X509_REVOKED) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_REVOKED) *, sk)))
+
+#define sk_X509_REVOKED_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk))
+
+#define sk_X509_REVOKED_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_REVOKED) *, sk))
+
+#define sk_X509_REVOKED_set_cmp_func(sk, comp) \
+ ((int (*)(const X509_REVOKED **a, const X509_REVOKED **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const X509_REVOKED **a, const X509_REVOKED **b), \
+ comp)))
+
+/* X509_TRUST */
+#define sk_X509_TRUST_new(comp) \
+ ((STACK_OF(X509_TRUST) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, int (*)(const X509_TRUST **a, const X509_TRUST **b), \
+ comp)))
+
+#define sk_X509_TRUST_new_null() ((STACK_OF(X509_TRUST) *)sk_new_null())
+
+#define sk_X509_TRUST_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk))
+
+#define sk_X509_TRUST_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk));
+
+#define sk_X509_TRUST_value(sk, i) \
+ ((X509_TRUST *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_TRUST) *, sk), (i)))
+
+#define sk_X509_TRUST_set(sk, i, p) \
+ ((X509_TRUST *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \
+ (i), CHECKED_CAST(void *, X509_TRUST *, p)))
+
+#define sk_X509_TRUST_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk))
+
+#define sk_X509_TRUST_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(X509_TRUST *), free_func))
+
+#define sk_X509_TRUST_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \
+ CHECKED_CAST(void *, X509_TRUST *, p), (where))
+
+#define sk_X509_TRUST_delete(sk, where) \
+ ((X509_TRUST *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \
+ (where)))
+
+#define sk_X509_TRUST_delete_ptr(sk, p) \
+ ((X509_TRUST *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \
+ CHECKED_CAST(void *, X509_TRUST *, p)))
+
+#define sk_X509_TRUST_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), (out_index), \
+ CHECKED_CAST(void *, X509_TRUST *, p))
+
+#define sk_X509_TRUST_shift(sk) \
+ ((X509_TRUST *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk)))
+
+#define sk_X509_TRUST_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \
+ CHECKED_CAST(void *, X509_TRUST *, p))
+
+#define sk_X509_TRUST_pop(sk) \
+ ((X509_TRUST *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk)))
+
+#define sk_X509_TRUST_dup(sk) \
+ ((STACK_OF(X509_TRUST) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_TRUST) *, sk)))
+
+#define sk_X509_TRUST_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk))
+
+#define sk_X509_TRUST_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_TRUST) *, sk))
+
+#define sk_X509_TRUST_set_cmp_func(sk, comp) \
+ ((int (*)(const X509_TRUST **a, const X509_TRUST **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const X509_TRUST **a, const X509_TRUST **b), \
+ comp)))
+
+/* X509_VERIFY_PARAM */
+#define sk_X509_VERIFY_PARAM_new(comp) \
+ ((STACK_OF(X509_VERIFY_PARAM) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, \
+ int (*)(const X509_VERIFY_PARAM **a, const X509_VERIFY_PARAM **b), \
+ comp)))
+
+#define sk_X509_VERIFY_PARAM_new_null() \
+ ((STACK_OF(X509_VERIFY_PARAM) *)sk_new_null())
+
+#define sk_X509_VERIFY_PARAM_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk))
+
+#define sk_X509_VERIFY_PARAM_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk));
+
+#define sk_X509_VERIFY_PARAM_value(sk, i) \
+ ((X509_VERIFY_PARAM *)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_VERIFY_PARAM) *, sk), (i)))
+
+#define sk_X509_VERIFY_PARAM_set(sk, i, p) \
+ ((X509_VERIFY_PARAM *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), (i), \
+ CHECKED_CAST(void *, X509_VERIFY_PARAM *, p)))
+
+#define sk_X509_VERIFY_PARAM_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk))
+
+#define sk_X509_VERIFY_PARAM_pop_free(sk, free_func) \
+ sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(X509_VERIFY_PARAM *), \
+ free_func))
+
+#define sk_X509_VERIFY_PARAM_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), \
+ CHECKED_CAST(void *, X509_VERIFY_PARAM *, p), (where))
+
+#define sk_X509_VERIFY_PARAM_delete(sk, where) \
+ ((X509_VERIFY_PARAM *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), (where)))
+
+#define sk_X509_VERIFY_PARAM_delete_ptr(sk, p) \
+ ((X509_VERIFY_PARAM *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), \
+ CHECKED_CAST(void *, X509_VERIFY_PARAM *, p)))
+
+#define sk_X509_VERIFY_PARAM_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), \
+ (out_index), CHECKED_CAST(void *, X509_VERIFY_PARAM *, p))
+
+#define sk_X509_VERIFY_PARAM_shift(sk) \
+ ((X509_VERIFY_PARAM *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk)))
+
+#define sk_X509_VERIFY_PARAM_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), \
+ CHECKED_CAST(void *, X509_VERIFY_PARAM *, p))
+
+#define sk_X509_VERIFY_PARAM_pop(sk) \
+ ((X509_VERIFY_PARAM *)sk_pop( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk)))
+
+#define sk_X509_VERIFY_PARAM_dup(sk) \
+ ((STACK_OF(X509_VERIFY_PARAM) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(X509_VERIFY_PARAM) *, sk)))
+
+#define sk_X509_VERIFY_PARAM_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk))
+
+#define sk_X509_VERIFY_PARAM_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_VERIFY_PARAM) *, sk))
+
+#define sk_X509_VERIFY_PARAM_set_cmp_func(sk, comp) \
+ ((int (*)(const X509_VERIFY_PARAM **a, const X509_VERIFY_PARAM **b)) \
+ sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), \
+ CHECKED_CAST(stack_cmp_func, int (*)(const X509_VERIFY_PARAM **a, \
+ const X509_VERIFY_PARAM **b), \
+ comp)))
+
+/* void */
+#define sk_void_new(comp) \
+ ((STACK_OF(void)*)sk_new(CHECKED_CAST( \
+ stack_cmp_func, int (*)(const void **a, const void **b), comp)))
+
+#define sk_void_new_null() ((STACK_OF(void)*)sk_new_null())
+
+#define sk_void_num(sk) sk_num(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk))
+
+#define sk_void_zero(sk) sk_zero(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk));
+
+#define sk_void_value(sk, i) \
+ ((void *)sk_value(CHECKED_CAST(_STACK *, const STACK_OF(void)*, sk), (i)))
+
+#define sk_void_set(sk, i, p) \
+ ((void *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), (i), \
+ CHECKED_CAST(void *, void *, p)))
+
+#define sk_void_free(sk) sk_free(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk))
+
+#define sk_void_pop_free(sk, free_func) \
+ sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(void *), free_func))
+
+#define sk_void_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), \
+ CHECKED_CAST(void *, void *, p), (where))
+
+#define sk_void_delete(sk, where) \
+ ((void *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), (where)))
+
+#define sk_void_delete_ptr(sk, p) \
+ ((void *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), \
+ CHECKED_CAST(void *, void *, p)))
+
+#define sk_void_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), (out_index), \
+ CHECKED_CAST(void *, void *, p))
+
+#define sk_void_shift(sk) \
+ ((void *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk)))
+
+#define sk_void_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), \
+ CHECKED_CAST(void *, void *, p))
+
+#define sk_void_pop(sk) \
+ ((void *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk)))
+
+#define sk_void_dup(sk) \
+ ((STACK_OF(void)*)sk_dup(CHECKED_CAST(_STACK *, const STACK_OF(void)*, sk)))
+
+#define sk_void_sort(sk) sk_sort(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk))
+
+#define sk_void_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(void)*, sk))
+
+#define sk_void_set_cmp_func(sk, comp) \
+ ((int (*)(const void **a, const void **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), \
+ CHECKED_CAST(stack_cmp_func, int (*)(const void **a, const void **b), \
+ comp)))
+
+/* OPENSSL_STRING */
+#define sk_OPENSSL_STRING_new(comp) \
+ ((STACK_OF(OPENSSL_STRING) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, \
+ int (*)(const OPENSSL_STRING *a, const OPENSSL_STRING *b), comp)))
+
+#define sk_OPENSSL_STRING_new_null() ((STACK_OF(OPENSSL_STRING) *)sk_new_null())
+
+#define sk_OPENSSL_STRING_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk))
+
+#define sk_OPENSSL_STRING_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk));
+
+#define sk_OPENSSL_STRING_value(sk, i) \
+ ((OPENSSL_STRING)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_STRING) *, sk), (i)))
+
+#define sk_OPENSSL_STRING_set(sk, i, p) \
+ ((OPENSSL_STRING)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), (i), \
+ CHECKED_CAST(void *, OPENSSL_STRING, p)))
+
+#define sk_OPENSSL_STRING_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk))
+
+#define sk_OPENSSL_STRING_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(OPENSSL_STRING), free_func))
+
+#define sk_OPENSSL_STRING_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), \
+ CHECKED_CAST(void *, OPENSSL_STRING, p), (where))
+
+#define sk_OPENSSL_STRING_delete(sk, where) \
+ ((OPENSSL_STRING)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), (where)))
+
+#define sk_OPENSSL_STRING_delete_ptr(sk, p) \
+ ((OPENSSL_STRING)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), \
+ CHECKED_CAST(void *, OPENSSL_STRING, p)))
+
+#define sk_OPENSSL_STRING_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), (out_index), \
+ CHECKED_CAST(void *, OPENSSL_STRING, p))
+
+#define sk_OPENSSL_STRING_shift(sk) \
+ ((OPENSSL_STRING)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk)))
+
+#define sk_OPENSSL_STRING_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), \
+ CHECKED_CAST(void *, OPENSSL_STRING, p))
+
+#define sk_OPENSSL_STRING_pop(sk) \
+ ((OPENSSL_STRING)sk_pop( \
+ CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk)))
+
+#define sk_OPENSSL_STRING_dup(sk) \
+ ((STACK_OF(OPENSSL_STRING) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_STRING) *, sk)))
+
+#define sk_OPENSSL_STRING_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk))
+
+#define sk_OPENSSL_STRING_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_STRING) *, sk))
+
+#define sk_OPENSSL_STRING_set_cmp_func(sk, comp) \
+ ((int (*)(const OPENSSL_STRING **a, const OPENSSL_STRING **b)) \
+ sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), \
+ CHECKED_CAST(stack_cmp_func, int (*)(const OPENSSL_STRING **a, \
+ const OPENSSL_STRING **b), \
+ comp)))
+
+/* OPENSSL_BLOCK */
+#define sk_OPENSSL_BLOCK_new(comp) \
+ ((STACK_OF(OPENSSL_BLOCK) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, int (*)(const OPENSSL_BLOCK *a, const OPENSSL_BLOCK *b), \
+ comp)))
+
+#define sk_OPENSSL_BLOCK_new_null() ((STACK_OF(OPENSSL_BLOCK) *)sk_new_null())
+
+#define sk_OPENSSL_BLOCK_num(sk) \
+ sk_num(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk))
+
+#define sk_OPENSSL_BLOCK_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk));
+
+#define sk_OPENSSL_BLOCK_value(sk, i) \
+ ((OPENSSL_BLOCK)sk_value( \
+ CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_BLOCK) *, sk), (i)))
+
+#define sk_OPENSSL_BLOCK_set(sk, i, p) \
+ ((OPENSSL_BLOCK)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), (i), \
+ CHECKED_CAST(void *, OPENSSL_BLOCK, p)))
+
+#define sk_OPENSSL_BLOCK_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk))
+
+#define sk_OPENSSL_BLOCK_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(OPENSSL_BLOCK), free_func))
+
+#define sk_OPENSSL_BLOCK_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), \
+ CHECKED_CAST(void *, OPENSSL_BLOCK, p), (where))
+
+#define sk_OPENSSL_BLOCK_delete(sk, where) \
+ ((OPENSSL_BLOCK)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), (where)))
+
+#define sk_OPENSSL_BLOCK_delete_ptr(sk, p) \
+ ((OPENSSL_BLOCK)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), \
+ CHECKED_CAST(void *, OPENSSL_BLOCK, p)))
+
+#define sk_OPENSSL_BLOCK_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), (out_index), \
+ CHECKED_CAST(void *, OPENSSL_BLOCK, p))
+
+#define sk_OPENSSL_BLOCK_shift(sk) \
+ ((OPENSSL_BLOCK)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk)))
+
+#define sk_OPENSSL_BLOCK_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), \
+ CHECKED_CAST(void *, OPENSSL_BLOCK, p))
+
+#define sk_OPENSSL_BLOCK_pop(sk) \
+ ((OPENSSL_BLOCK)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk)))
+
+#define sk_OPENSSL_BLOCK_dup(sk) \
+ ((STACK_OF(OPENSSL_BLOCK) *)sk_dup( \
+ CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_BLOCK) *, sk)))
+
+#define sk_OPENSSL_BLOCK_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk))
+
+#define sk_OPENSSL_BLOCK_is_sorted(sk) \
+ sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_BLOCK) *, sk))
+
+#define sk_OPENSSL_BLOCK_set_cmp_func(sk, comp) \
+ ((int (*)(const OPENSSL_BLOCK **a, const OPENSSL_BLOCK **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const OPENSSL_BLOCK **a, const OPENSSL_BLOCK **b), \
+ comp)))
diff --git a/crypto/thread.c b/crypto/thread.c
new file mode 100644
index 0000000..1c9926c
--- /dev/null
+++ b/crypto/thread.c
@@ -0,0 +1,195 @@
+/* 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/thread.h>
+
+#include <errno.h>
+
+#include <openssl/mem.h>
+#include <openssl/type_check.h>
+
+/* lock_names contains the names of all the locks defined in thread.h. */
+static const char *const lock_names[] = {
+ "<<ERROR>>", "err", "ex_data", "x509",
+ "x509_info", "x509_pkey", "x509_crl", "x509_req",
+ "dsa", "rsa", "evp_pkey", "x509_store",
+ "ssl_ctx", "ssl_cert", "ssl_session", "ssl_sess_cert",
+ "ssl", "ssl_method", "rand", "rand2",
+ "debug_malloc", "BIO", "gethostbyname", "getservbyname",
+ "readdir", "RSA_blinding", "dh", "debug_malloc2",
+ "dso", "dynlock", "engine", "ui",
+ "ecdsa", "ec", "ecdh", "bn",
+ "ec_pre_comp", "store", "comp", "fips",
+ "fips2", "obj",
+};
+
+OPENSSL_COMPILE_ASSERT(CRYPTO_NUM_LOCKS ==
+ sizeof(lock_names) / sizeof(lock_names[0]),
+ CRYPTO_NUM_LOCKS_inconsistent);
+
+static void (*locking_callback)(int mode, int lock_num, const char *file,
+ int line) = 0;
+static int (*add_lock_callback)(int *pointer, int amount, int lock_num,
+ const char *file, int line) = 0;
+static void (*threadid_callback)(CRYPTO_THREADID *) = 0;
+
+
+int CRYPTO_num_locks(void) { return CRYPTO_NUM_LOCKS; }
+
+void CRYPTO_set_locking_callback(void (*func)(int mode, int lock_num,
+ const char *file, int line)) {
+ locking_callback = func;
+}
+
+void CRYPTO_set_add_lock_callback(int (*func)(int *num, int mount, int lock_num,
+ const char *file, int line)) {
+ add_lock_callback = func;
+}
+
+const char *CRYPTO_get_lock_name(int lock_num) {
+ if (lock_num >= 0 && lock_num < CRYPTO_NUM_LOCKS) {
+ return lock_names[lock_num];
+ } else {
+ return "ERROR";
+ }
+}
+
+int CRYPTO_THREADID_set_callback(void (*func)(CRYPTO_THREADID *)) {
+ if (threadid_callback) {
+ return 0;
+ }
+ threadid_callback = func;
+ return 1;
+}
+
+void CRYPTO_THREADID_set_numeric(CRYPTO_THREADID *id, unsigned long val) {
+ memset(id, 0, sizeof(*id));
+ id->val = val;
+}
+
+void CRYPTO_THREADID_set_pointer(CRYPTO_THREADID *id, void *ptr) {
+ memset(id, 0, sizeof(*id));
+ id->ptr = ptr;
+}
+
+void (*CRYPTO_get_locking_callback(void))(int mode, int lock_num,
+ const char *file, int line) {
+ return locking_callback;
+}
+
+int (*CRYPTO_get_add_lock_callback(void))(int *num, int mount, int lock_num,
+ const char *file, int line) {
+ return add_lock_callback;
+}
+
+void CRYPTO_lock(int mode, int lock_num, const char *file, int line) {
+ if (locking_callback != NULL) {
+ locking_callback(mode, lock_num, file, line);
+ }
+}
+
+int CRYPTO_add_lock(int *pointer, int amount, int lock_num, const char *file,
+ int line) {
+ int ret = 0;
+
+ if (add_lock_callback != NULL) {
+ ret = add_lock_callback(pointer, amount, lock_num, file, line);
+ } else {
+ CRYPTO_lock(CRYPTO_LOCK | CRYPTO_WRITE, lock_num, file, line);
+ ret = *pointer + amount;
+ *pointer = ret;
+ CRYPTO_lock(CRYPTO_UNLOCK | CRYPTO_WRITE, lock_num, file, line);
+ }
+
+ return ret;
+}
+
+void CRYPTO_THREADID_current(CRYPTO_THREADID *id) {
+ if (threadid_callback) {
+ threadid_callback(id);
+ return;
+ }
+
+#if defined(OPENSSL_SYS_WIN32)
+ CRYPTO_THREADID_set_numeric(id, (unsigned long)GetCurrentThreadId());
+#else
+ /* For everything else, default to using the address of 'errno' */
+ CRYPTO_THREADID_set_pointer(id, (void *)&errno);
+#endif
+}
+
+int CRYPTO_THREADID_cmp(const CRYPTO_THREADID *a, const CRYPTO_THREADID *b) {
+ return memcmp(a, b, sizeof(*a));
+}
+
+void CRYPTO_THREADID_cpy(CRYPTO_THREADID *dest, const CRYPTO_THREADID *src) {
+ memcpy(dest, src, sizeof(*src));
+}
+
+uint32_t CRYPTO_THREADID_hash(const CRYPTO_THREADID *id) {
+ return OPENSSL_hash32(id, sizeof(CRYPTO_THREADID));
+}
+
+void CRYPTO_set_id_callback(unsigned long (*func)(void)) {}
+
+void CRYPTO_set_dynlock_create_callback(struct CRYPTO_dynlock_value *(
+ *dyn_create_function)(const char *file, int line)) {}
+
+void CRYPTO_set_dynlock_lock_callback(void (*dyn_lock_function)(
+ int mode, struct CRYPTO_dynlock_value *l, const char *file, int line)) {}
+
+void CRYPTO_set_dynlock_destroy_callback(void (*dyn_destroy_function)(
+ struct CRYPTO_dynlock_value *l, const char *file, int line)) {}
diff --git a/crypto/thread.h b/crypto/thread.h
new file mode 100644
index 0000000..ef06f1e
--- /dev/null
+++ b/crypto/thread.h
@@ -0,0 +1,270 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_THREAD_H
+#define OPENSSL_HEADER_THREAD_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* Functions to support multithreading.
+ *
+ * OpenSSL can safely be used in multi-threaded applications provided that at
+ * least two callback functions are set with |CRYPTO_set_locking_callback| and
+ * |CRYPTO_THREADID_set_callback|.
+ *
+ * The locking callback performs mutual exclusion. Rather than using a single
+ * lock for all, shared data-structures, OpenSSL requires that the locking
+ * callback support a fixed (at run-time) number of different locks, given by
+ * |CRYPTO_num_locks|.
+ *
+ * The thread ID callback is called to record the currently executing thread's
+ * identifier in a |CRYPTO_THREADID| structure. If this callback is not
+ * provided then the address of |errno| is used as the thread identifier. This
+ * is sufficient only if the system has a thread-local |errno| value. */
+
+
+/* CRYPTO_num_locks returns the number of static locks that the callback
+ * function passed to |CRYPTO_set_locking_callback| must be able to handle. */
+int CRYPTO_num_locks(void);
+
+/* CRYPTO_set_locking_callback sets a callback function that implements locking
+ * on behalf of OpenSSL. The callback is called whenever OpenSSL needs to lock
+ * or unlock a lock, and locks are specified as a number between zero and
+ * |CRYPTO_num_locks()-1|.
+ *
+ * The mode argument to the callback is a bitwise-OR of either CRYPTO_LOCK or
+ * CRYPTO_UNLOCK, to denote the action, and CRYPTO_READ or CRYPTO_WRITE, to
+ * indicate the type of lock. The |file| and |line| arguments give the location
+ * in the OpenSSL source where the locking action originated. */
+void CRYPTO_set_locking_callback(void (*func)(int mode, int lock_num,
+ const char *file, int line));
+
+/* CRYPTO_set_add_lock_callback sets an optional callback which is used when
+ * OpenSSL needs to add a fixed amount to an integer. For example, this is used
+ * when maintaining reference counts. Normally the reference counts are
+ * maintained by performing the addition under a lock but, if this callback
+ * has been set, the application is free to implement the operation using
+ * faster methods (i.e. atomic operations).
+ *
+ * The callback is given a pointer to the integer to be altered (|num|), the
+ * amount to add to the integer (|amount|, which may be negative), the number
+ * of the lock which would have been taken to protect the operation and the
+ * position in the OpenSSL code where the operation originated. */
+void CRYPTO_set_add_lock_callback(int (*func)(int *num, int amount,
+ int lock_num, const char *file,
+ int line));
+
+/* CRYPTO_get_lock_name returns the name of the lock given by |lock_num|. This
+ * can be used in a locking callback for debugging purposes. */
+const char *CRYPTO_get_lock_name(int lock_num);
+
+
+/* CRYPTO_THREADID identifies a thread in a multithreaded program. This
+ * structure should not be used directly. Rather applications should use
+ * |CRYPTO_THREADID_set_numeric| and |CRYPTO_THREADID_set_pointer|. */
+typedef struct crypto_threadid_st {
+ void *ptr;
+ unsigned long val;
+} CRYPTO_THREADID;
+
+/* CRYPTO_THREADID_set_callback sets a callback function that stores an
+ * identifier of the currently executing thread into |threadid|. The
+ * CRYPTO_THREADID structure should not be accessed directly. Rather one of
+ * |CRYPTO_THREADID_set_numeric| or |CRYPTO_THREADID_set_pointer| should be
+ * used depending on whether thread IDs are numbers or pointers on the host
+ * system. */
+int CRYPTO_THREADID_set_callback(
+ void (*threadid_func)(CRYPTO_THREADID *threadid));
+
+void CRYPTO_THREADID_set_numeric(CRYPTO_THREADID *id, unsigned long val);
+void CRYPTO_THREADID_set_pointer(CRYPTO_THREADID *id, void *ptr);
+
+
+/* Private functions: */
+
+/* CRYPTO_get_locking_callback returns the callback, if any, that was most
+ * recently set using |CRYPTO_set_locking_callback|. */
+void (*CRYPTO_get_locking_callback(void))(int mode, int lock_num,
+ const char *file, int line);
+
+/* CRYPTO_get_add_lock_callback returns the callback, if any, that was most
+ * recently set using |CRYPTO_set_add_lock_callback|. */
+int (*CRYPTO_get_add_lock_callback(void))(int *num, int amount, int lock_num,
+ const char *file, int line);
+
+/* CRYPTO_lock locks or unlocks the lock specified by |lock_num| (one of
+ * |CRYPTO_LOCK_*|). Don't call this directly, rather use one of the
+ * CRYPTO_[rw]_(un)lock macros. */
+void CRYPTO_lock(int mode, int lock_num, const char *file, int line);
+
+/* CRYPTO_add_lock adds |amount| to |*pointer|, protected by the lock specified
+ * by |lock_num|. It returns the new value of |*pointer|. Don't call this
+ * function directly, rather use the |CRYPTO_add_lock| macro.
+ *
+ * TODO(fork): rename to CRYPTO_add_locked. */
+int CRYPTO_add_lock(int *pointer, int amount, int lock_num, const char *file,
+ int line);
+
+
+/* CRYPTO_THREADID_current stores the current thread identifier in |id|. */
+void CRYPTO_THREADID_current(CRYPTO_THREADID *id);
+
+/* CRYPTO_THREADID_cmp returns < 0, 0 or > 0 if |a| is less than, equal to or
+ * greater than |b|, respectively. */
+int CRYPTO_THREADID_cmp(const CRYPTO_THREADID *a, const CRYPTO_THREADID *b);
+
+/* CRYPTO_THREADID_cpy sets |*dest| equal to |*src|. */
+void CRYPTO_THREADID_cpy(CRYPTO_THREADID *dest, const CRYPTO_THREADID *src);
+
+/* CRYPTO_THREADID_hash returns a hash of the numeric value of |id|. */
+uint32_t CRYPTO_THREADID_hash(const CRYPTO_THREADID *id);
+
+/* These are the locks used by OpenSSL. These values should match up with the
+ * table in thread.c. */
+#define CRYPTO_LOCK_ERR 1
+#define CRYPTO_LOCK_EX_DATA 2
+#define CRYPTO_LOCK_X509 3
+#define CRYPTO_LOCK_X509_INFO 4
+#define CRYPTO_LOCK_X509_PKEY 5
+#define CRYPTO_LOCK_X509_CRL 6
+#define CRYPTO_LOCK_X509_REQ 7
+#define CRYPTO_LOCK_DSA 8
+#define CRYPTO_LOCK_RSA 9
+#define CRYPTO_LOCK_EVP_PKEY 10
+#define CRYPTO_LOCK_X509_STORE 11
+#define CRYPTO_LOCK_SSL_CTX 12
+#define CRYPTO_LOCK_SSL_CERT 13
+#define CRYPTO_LOCK_SSL_SESSION 14
+#define CRYPTO_LOCK_SSL_SESS_CERT 15
+#define CRYPTO_LOCK_SSL 16
+#define CRYPTO_LOCK_SSL_METHOD 17
+#define CRYPTO_LOCK_RAND 18
+#define CRYPTO_LOCK_RAND2 19
+#define CRYPTO_LOCK_MALLOC 20
+#define CRYPTO_LOCK_BIO 21
+#define CRYPTO_LOCK_GETHOSTBYNAME 22
+#define CRYPTO_LOCK_GETSERVBYNAME 23
+#define CRYPTO_LOCK_READDIR 24
+#define CRYPTO_LOCK_RSA_BLINDING 25
+#define CRYPTO_LOCK_DH 26
+#define CRYPTO_LOCK_MALLOC2 27
+#define CRYPTO_LOCK_DSO 28
+#define CRYPTO_LOCK_DYNLOCK 29
+#define CRYPTO_LOCK_ENGINE 30
+#define CRYPTO_LOCK_UI 31
+#define CRYPTO_LOCK_ECDSA 32
+#define CRYPTO_LOCK_EC 33
+#define CRYPTO_LOCK_ECDH 34
+#define CRYPTO_LOCK_BN 35
+#define CRYPTO_LOCK_EC_PRE_COMP 36
+#define CRYPTO_LOCK_STORE 37
+#define CRYPTO_LOCK_COMP 38
+#define CRYPTO_LOCK_FIPS 39
+#define CRYPTO_LOCK_FIPS2 40
+#define CRYPTO_LOCK_OBJ 40
+#define CRYPTO_NUM_LOCKS 42
+
+#define CRYPTO_LOCK 1
+#define CRYPTO_UNLOCK 2
+#define CRYPTO_READ 4
+#define CRYPTO_WRITE 8
+
+#define CRYPTO_w_lock(lock_num) \
+ CRYPTO_lock(CRYPTO_LOCK | CRYPTO_WRITE, lock_num, __FILE__, __LINE__)
+#define CRYPTO_w_unlock(lock_num) \
+ CRYPTO_lock(CRYPTO_UNLOCK | CRYPTO_WRITE, lock_num, __FILE__, __LINE__)
+#define CRYPTO_r_lock(lock_num) \
+ CRYPTO_lock(CRYPTO_LOCK | CRYPTO_READ, lock_num, __FILE__, __LINE__)
+#define CRYPTO_r_unlock(lock_num) \
+ CRYPTO_lock(CRYPTO_UNLOCK | CRYPTO_READ, lock_num, __FILE__, __LINE__)
+#define CRYPTO_add(addr, amount, lock_num) \
+ CRYPTO_add_lock(addr, amount, lock_num, __FILE__, __LINE__)
+
+
+/* Private functions.
+ *
+ * Some old code calls these functions and so no-op implementations are
+ * provided.
+ *
+ * TODO(fork): cleanup callers and remove. */
+
+void CRYPTO_set_id_callback(unsigned long (*func)(void));
+
+typedef struct {
+ int references;
+ struct CRYPTO_dynlock_value *data;
+} CRYPTO_dynlock;
+
+void CRYPTO_set_dynlock_create_callback(struct CRYPTO_dynlock_value *(
+ *dyn_create_function)(const char *file, int line));
+
+void CRYPTO_set_dynlock_lock_callback(void (*dyn_lock_function)(
+ int mode, struct CRYPTO_dynlock_value *l, const char *file, int line));
+
+void CRYPTO_set_dynlock_destroy_callback(void (*dyn_destroy_function)(
+ struct CRYPTO_dynlock_value *l, const char *file, int line));
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_THREAD_H */
diff --git a/crypto/time_support.c b/crypto/time_support.c
new file mode 100644
index 0000000..5c6e9c0
--- /dev/null
+++ b/crypto/time_support.c
@@ -0,0 +1,198 @@
+/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL
+ * project 2001.
+ * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2008.
+ */
+/* ====================================================================
+ * Copyright (c) 2001 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). */
+
+#define _BSD_SOURCE /* for gmtime_r */
+
+#include <openssl/time_support.h>
+
+#define SECS_PER_DAY (24 * 60 * 60)
+
+struct tm *OPENSSL_gmtime(const time_t *time, struct tm *result) {
+#if defined(OPENSSL_WINDOWS)
+ if (_gmtime_s(result, time)) {
+ return NULL;
+ }
+ return result;
+#else
+ return gmtime_r(time, result);
+#endif
+}
+
+/* Convert date to and from julian day Uses Fliegel & Van Flandern algorithm */
+static long date_to_julian(int y, int m, int d) {
+ return (1461 * (y + 4800 + (m - 14) / 12)) / 4 +
+ (367 * (m - 2 - 12 * ((m - 14) / 12))) / 12 -
+ (3 * ((y + 4900 + (m - 14) / 12) / 100)) / 4 + d - 32075;
+}
+
+static void julian_to_date(long jd, int *y, int *m, int *d) {
+ long L = jd + 68569;
+ long n = (4 * L) / 146097;
+ long i, j;
+
+ L = L - (146097 * n + 3) / 4;
+ i = (4000 * (L + 1)) / 1461001;
+ L = L - (1461 * i) / 4 + 31;
+ j = (80 * L) / 2447;
+ *d = L - (2447 * j) / 80;
+ L = j / 11;
+ *m = j + 2 - (12 * L);
+ *y = 100 * (n - 49) + i + L;
+}
+
+/* Convert tm structure and offset into julian day and seconds */
+static int julian_adj(const struct tm *tm, int off_day, long offset_sec,
+ long *pday, int *psec) {
+ int offset_hms, offset_day;
+ long time_jd;
+ int time_year, time_month, time_day;
+ /* split offset into days and day seconds */
+ offset_day = offset_sec / SECS_PER_DAY;
+ /* Avoid sign issues with % operator */
+ offset_hms = offset_sec - (offset_day * SECS_PER_DAY);
+ offset_day += off_day;
+ /* Add current time seconds to offset */
+ offset_hms += tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec;
+ /* Adjust day seconds if overflow */
+ if (offset_hms >= SECS_PER_DAY) {
+ offset_day++;
+ offset_hms -= SECS_PER_DAY;
+ } else if (offset_hms < 0) {
+ offset_day--;
+ offset_hms += SECS_PER_DAY;
+ }
+
+ /* Convert date of time structure into a Julian day number. */
+
+ time_year = tm->tm_year + 1900;
+ time_month = tm->tm_mon + 1;
+ time_day = tm->tm_mday;
+
+ time_jd = date_to_julian(time_year, time_month, time_day);
+
+ /* Work out Julian day of new date */
+ time_jd += offset_day;
+
+ if (time_jd < 0)
+ return 0;
+
+ *pday = time_jd;
+ *psec = offset_hms;
+ return 1;
+}
+
+int OPENSSL_gmtime_adj(struct tm *tm, int off_day, long offset_sec) {
+ int time_sec, time_year, time_month, time_day;
+ long time_jd;
+
+ /* Convert time and offset into julian day and seconds */
+ if (!julian_adj(tm, off_day, offset_sec, &time_jd, &time_sec))
+ return 0;
+
+ /* Convert Julian day back to date */
+
+ julian_to_date(time_jd, &time_year, &time_month, &time_day);
+
+ if (time_year < 1900 || time_year > 9999)
+ return 0;
+
+ /* Update tm structure */
+
+ tm->tm_year = time_year - 1900;
+ tm->tm_mon = time_month - 1;
+ tm->tm_mday = time_day;
+
+ tm->tm_hour = time_sec / 3600;
+ tm->tm_min = (time_sec / 60) % 60;
+ tm->tm_sec = time_sec % 60;
+
+ return 1;
+}
+
+int OPENSSL_gmtime_diff(int *pday, int *psec, const struct tm *from,
+ const struct tm *to) {
+ int from_sec, to_sec, diff_sec;
+ long from_jd, to_jd, diff_day;
+
+ if (!julian_adj(from, 0, 0, &from_jd, &from_sec)) {
+ return 0;
+ }
+ if (!julian_adj(to, 0, 0, &to_jd, &to_sec)) {
+ return 0;
+ }
+
+ diff_day = to_jd - from_jd;
+ diff_sec = to_sec - from_sec;
+ /* Adjust differences so both positive or both negative */
+ if (diff_day > 0 && diff_sec < 0) {
+ diff_day--;
+ diff_sec += SECS_PER_DAY;
+ }
+ if (diff_day < 0 && diff_sec > 0) {
+ diff_day++;
+ diff_sec -= SECS_PER_DAY;
+ }
+
+ if (pday) {
+ *pday = (int)diff_day;
+ }
+ if (psec) {
+ *psec = diff_sec;
+ }
+
+ return 1;
+}
diff --git a/crypto/time_support.h b/crypto/time_support.h
new file mode 100644
index 0000000..051c691
--- /dev/null
+++ b/crypto/time_support.h
@@ -0,0 +1,88 @@
+/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL
+ * project 2001.
+ * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2008.
+ */
+/* ====================================================================
+ * Copyright (c) 2001 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). */
+
+#ifndef OPENSSL_HEADER_TIME_H
+#define OPENSSL_HEADER_TIME_H
+
+#include <openssl/base.h>
+
+#include <time.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* OPENSSL_gmtime wraps |gmtime_r|. See the manual page for that function. */
+struct tm *OPENSSL_gmtime(const time_t *timer, struct tm *result);
+
+/* OPENSSL_gmtime_adj updates |tm| by adding |offset_day| days and |offset_sec|
+ * seconds. */
+int OPENSSL_gmtime_adj(struct tm *tm, int offset_day, long offset_sec);
+
+/* OPENSSL_gmtime_diff calculates the difference between |from| and |to| and
+ * outputs the difference as a number of days and seconds in |*out_days| and
+ * |*out_secs|. */
+int OPENSSL_gmtime_diff(int *out_days, int *out_secs, const struct tm *from,
+ const struct tm *to);
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_TIME_H */
diff --git a/crypto/type_check.h b/crypto/type_check.h
new file mode 100644
index 0000000..dd59151
--- /dev/null
+++ b/crypto/type_check.h
@@ -0,0 +1,87 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#ifndef OPENSSL_HEADER_TYPE_CHECK_H
+#define OPENSSL_HEADER_TYPE_CHECK_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* This header file contains some common macros for enforcing type checking.
+ * Several, common OpenSSL structures (i.e. stack and lhash) operate on void
+ * pointers, but we wish to have type checking when they are used with a
+ * specific type. */
+
+/* CHECKED_CAST casts |p| from type |from| to type |to|. */
+#define CHECKED_CAST(to, from, p) ((to) (1 ? (p) : (from)0))
+
+/* CHECKED_PTR_OF casts a given pointer to void* and statically checks that it
+ * was a pointer to |type|. */
+#define CHECKED_PTR_OF(type, p) CHECKED_CAST(void*, type*, (p))
+
+#define OPENSSL_COMPILE_ASSERT(cond, msg) \
+ typedef char OPENSSL_COMPILE_ASSERT_##msg[((cond) ? 1 : -1)]
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_TYPE_CHECK_H */
diff --git a/crypto/x509/CMakeLists.txt b/crypto/x509/CMakeLists.txt
new file mode 100644
index 0000000..9017d76
--- /dev/null
+++ b/crypto/x509/CMakeLists.txt
@@ -0,0 +1,57 @@
+include_directories(. .. ../../include)
+
+add_library(
+ x509
+
+ OBJECT
+
+ a_digest.c
+ a_sign.c
+ a_strex.c
+ a_verify.c
+ asn1_gen.c
+ by_dir.c
+ by_file.c
+ i2d_pr.c
+ pkcs7.c
+ t_crl.c
+ t_x509.c
+ t_x509a.c
+ x509.c
+ x509_att.c
+ x509_cmp.c
+ x509_d2.c
+ x509_def.c
+ x509_error.c
+ x509_ext.c
+ x509_lu.c
+ x509_obj.c
+ x509_r2x.c
+ x509_req.c
+ x509_set.c
+ x509_trs.c
+ x509_txt.c
+ x509_v3.c
+ x509_vfy.c
+ x509_vpm.c
+ x509cset.c
+ x509name.c
+ x509rset.c
+ x509spki.c
+ x509type.c
+ x_algor.c
+ x_all.c
+ x_attrib.c
+ x_crl.c
+ x_exten.c
+ x_info.c
+ x_name.c
+ x_pkey.c
+ x_pubkey.c
+ x_req.c
+ x_sig.c
+ x_spki.c
+ x_val.c
+ x_x509.c
+ x_x509a.c
+)
diff --git a/crypto/x509/a_digest.c b/crypto/x509/a_digest.c
new file mode 100644
index 0000000..9411dbc
--- /dev/null
+++ b/crypto/x509/a_digest.c
@@ -0,0 +1,99 @@
+/* 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/x509.h>
+
+#include <openssl/asn1.h>
+#include <openssl/digest.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+int ASN1_digest(i2d_of_void *i2d, const EVP_MD *type, char *data,
+ unsigned char *md, unsigned int *len)
+ {
+ int i;
+ unsigned char *str,*p;
+
+ i=i2d(data,NULL);
+ if ((str=(unsigned char *)OPENSSL_malloc(i)) == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, ASN1_digest, ERR_R_MALLOC_FAILURE);
+ return(0);
+ }
+ p=str;
+ i2d(data,&p);
+
+ if (!EVP_Digest(str, i, md, len, type, NULL))
+ return 0;
+ OPENSSL_free(str);
+ return(1);
+ }
+
+int ASN1_item_digest(const ASN1_ITEM *it, const EVP_MD *type, void *asn,
+ unsigned char *md, unsigned int *len)
+ {
+ int i;
+ unsigned char *str = NULL;
+
+ i=ASN1_item_i2d(asn,&str, it);
+ if (!str) return(0);
+
+ if (!EVP_Digest(str, i, md, len, type, NULL))
+ return 0;
+ OPENSSL_free(str);
+ return(1);
+ }
diff --git a/crypto/x509/a_sign.c b/crypto/x509/a_sign.c
new file mode 100644
index 0000000..d35efe1
--- /dev/null
+++ b/crypto/x509/a_sign.c
@@ -0,0 +1,272 @@
+/* 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/asn1.h>
+#include <openssl/digest.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509.h>
+
+#include "../evp/internal.h"
+
+
+/* TODO(fork): this code appears to be dead. */
+#if 0
+#ifndef NO_ASN1_OLD
+
+int ASN1_sign(i2d_of_void *i2d, X509_ALGOR *algor1, X509_ALGOR *algor2,
+ ASN1_BIT_STRING *signature, char *data, EVP_PKEY *pkey,
+ const EVP_MD *type)
+ {
+ EVP_MD_CTX ctx;
+ unsigned char *p,*buf_in=NULL,*buf_out=NULL;
+ int i,inl=0,outl=0,outll=0;
+ X509_ALGOR *a;
+
+ EVP_MD_CTX_init(&ctx);
+ for (i=0; i<2; i++)
+ {
+ if (i == 0)
+ a=algor1;
+ else
+ a=algor2;
+ if (a == NULL) continue;
+ if (type->pkey_type == NID_dsaWithSHA1)
+ {
+ /* special case: RFC 2459 tells us to omit 'parameters'
+ * with id-dsa-with-sha1 */
+ ASN1_TYPE_free(a->parameter);
+ a->parameter = NULL;
+ }
+ else if ((a->parameter == NULL) ||
+ (a->parameter->type != V_ASN1_NULL))
+ {
+ ASN1_TYPE_free(a->parameter);
+ if ((a->parameter=ASN1_TYPE_new()) == NULL) goto err;
+ a->parameter->type=V_ASN1_NULL;
+ }
+ ASN1_OBJECT_free(a->algorithm);
+ a->algorithm=OBJ_nid2obj(type->pkey_type);
+ if (a->algorithm == NULL)
+ {
+ OPENSSL_PUT_ERROR(ASN1, XXX, ASN1_R_UNKNOWN_OBJECT_TYPE);
+ goto err;
+ }
+ if (a->algorithm->length == 0)
+ {
+ OPENSSL_PUT_ERROR(ASN1, XXX, ASN1_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD);
+ goto err;
+ }
+ }
+ inl=i2d(data,NULL);
+ buf_in=(unsigned char *)OPENSSL_malloc((unsigned int)inl);
+ outll=outl=EVP_PKEY_size(pkey);
+ buf_out=(unsigned char *)OPENSSL_malloc((unsigned int)outl);
+ if ((buf_in == NULL) || (buf_out == NULL))
+ {
+ outl=0;
+ OPENSSL_PUT_ERROR(ASN1, XXX, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ p=buf_in;
+
+ i2d(data,&p);
+ if (!EVP_SignInit_ex(&ctx,type, NULL)
+ || !EVP_SignUpdate(&ctx,(unsigned char *)buf_in,inl)
+ || !EVP_SignFinal(&ctx,(unsigned char *)buf_out,
+ (unsigned int *)&outl,pkey))
+ {
+ outl=0;
+ OPENSSL_PUT_ERROR(ASN1, XXX, ERR_R_EVP_LIB);
+ goto err;
+ }
+ if (signature->data != NULL) OPENSSL_free(signature->data);
+ signature->data=buf_out;
+ buf_out=NULL;
+ signature->length=outl;
+ /* In the interests of compatibility, I'll make sure that
+ * the bit string has a 'not-used bits' value of 0
+ */
+ signature->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07);
+ signature->flags|=ASN1_STRING_FLAG_BITS_LEFT;
+err:
+ EVP_MD_CTX_cleanup(&ctx);
+ if (buf_in != NULL)
+ { OPENSSL_cleanse((char *)buf_in,(unsigned int)inl); OPENSSL_free(buf_in); }
+ if (buf_out != NULL)
+ { OPENSSL_cleanse((char *)buf_out,outll); OPENSSL_free(buf_out); }
+ return(outl);
+ }
+
+#endif
+#endif
+
+int ASN1_item_sign(const ASN1_ITEM *it, X509_ALGOR *algor1, X509_ALGOR *algor2,
+ ASN1_BIT_STRING *signature, void *asn, EVP_PKEY *pkey,
+ const EVP_MD *type)
+ {
+ EVP_MD_CTX ctx;
+ EVP_MD_CTX_init(&ctx);
+ if (!EVP_DigestSignInit(&ctx, NULL, type, NULL, pkey))
+ {
+ EVP_MD_CTX_cleanup(&ctx);
+ return 0;
+ }
+ return ASN1_item_sign_ctx(it, algor1, algor2, signature, asn, &ctx);
+ }
+
+
+int ASN1_item_sign_ctx(const ASN1_ITEM *it,
+ X509_ALGOR *algor1, X509_ALGOR *algor2,
+ ASN1_BIT_STRING *signature, void *asn, EVP_MD_CTX *ctx)
+ {
+ const EVP_MD *type;
+ EVP_PKEY *pkey;
+ unsigned char *buf_in=NULL,*buf_out=NULL;
+ size_t inl=0,outl=0,outll=0;
+ int signid, paramtype;
+ int rv;
+
+ type = EVP_MD_CTX_md(ctx);
+ pkey = EVP_PKEY_CTX_get0_pkey(ctx->pctx);
+
+ if (!type || !pkey)
+ {
+ OPENSSL_PUT_ERROR(X509, ASN1_item_sign_ctx, X509_R_CONTEXT_NOT_INITIALISED);
+ return 0;
+ }
+
+ if (pkey->ameth->item_sign)
+ {
+ rv = pkey->ameth->item_sign(ctx, it, asn, algor1, algor2,
+ signature);
+ if (rv == 1)
+ outl = signature->length;
+ /* Return value meanings:
+ * <=0: error.
+ * 1: method does everything.
+ * 2: carry on as normal.
+ * 3: ASN1 method sets algorithm identifiers: just sign.
+ */
+ if (rv <= 0)
+ OPENSSL_PUT_ERROR(X509, ASN1_item_sign_ctx, ERR_R_EVP_LIB);
+ if (rv <= 1)
+ goto err;
+ }
+ else
+ rv = 2;
+
+ if (rv == 2)
+ {
+ /* TODO(fork): EVP_MD_FLAG_PKEY_METHOD_SIGNATURE seems to mean
+ * "is SHA". */
+ if (!pkey->ameth ||
+ !OBJ_find_sigid_by_algs(&signid,
+ EVP_MD_type(type),
+ pkey->ameth->pkey_id))
+ {
+ OPENSSL_PUT_ERROR(X509, ASN1_item_sign_ctx, X509_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED);
+ return 0;
+ }
+
+ if (pkey->ameth->pkey_flags & ASN1_PKEY_SIGPARAM_NULL)
+ paramtype = V_ASN1_NULL;
+ else
+ paramtype = V_ASN1_UNDEF;
+
+ if (algor1)
+ X509_ALGOR_set0(algor1, OBJ_nid2obj(signid), paramtype, NULL);
+ if (algor2)
+ X509_ALGOR_set0(algor2, OBJ_nid2obj(signid), paramtype, NULL);
+
+ }
+
+ inl=ASN1_item_i2d(asn,&buf_in, it);
+ outll=outl=EVP_PKEY_size(pkey);
+ buf_out=OPENSSL_malloc((unsigned int)outl);
+ if ((buf_in == NULL) || (buf_out == NULL))
+ {
+ outl=0;
+ OPENSSL_PUT_ERROR(X509, ASN1_item_sign_ctx, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!EVP_DigestSignUpdate(ctx, buf_in, inl)
+ || !EVP_DigestSignFinal(ctx, buf_out, &outl))
+ {
+ outl=0;
+ OPENSSL_PUT_ERROR(X509, ASN1_item_sign_ctx, ERR_R_EVP_LIB);
+ goto err;
+ }
+ if (signature->data != NULL) OPENSSL_free(signature->data);
+ signature->data=buf_out;
+ buf_out=NULL;
+ signature->length=outl;
+ /* In the interests of compatibility, I'll make sure that
+ * the bit string has a 'not-used bits' value of 0
+ */
+ signature->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07);
+ signature->flags|=ASN1_STRING_FLAG_BITS_LEFT;
+err:
+ EVP_MD_CTX_cleanup(ctx);
+ if (buf_in != NULL)
+ { OPENSSL_cleanse((char *)buf_in,(unsigned int)inl); OPENSSL_free(buf_in); }
+ if (buf_out != NULL)
+ { OPENSSL_cleanse((char *)buf_out,outll); OPENSSL_free(buf_out); }
+ return(outl);
+ }
diff --git a/crypto/x509/a_strex.c b/crypto/x509/a_strex.c
new file mode 100644
index 0000000..92b61ac
--- /dev/null
+++ b/crypto/x509/a_strex.c
@@ -0,0 +1,561 @@
+/* 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/x509.h>
+
+#include <openssl/asn1.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+
+#include "charmap.h"
+
+
+/* ASN1_STRING_print_ex() and X509_NAME_print_ex().
+ * Enhanced string and name printing routines handling
+ * multibyte characters, RFC2253 and a host of other
+ * options.
+ */
+
+
+#define CHARTYPE_BS_ESC (ASN1_STRFLGS_ESC_2253 | CHARTYPE_FIRST_ESC_2253 | CHARTYPE_LAST_ESC_2253)
+
+#define ESC_FLAGS (ASN1_STRFLGS_ESC_2253 | \
+ ASN1_STRFLGS_ESC_QUOTE | \
+ ASN1_STRFLGS_ESC_CTRL | \
+ ASN1_STRFLGS_ESC_MSB)
+
+
+static int send_bio_chars(void *arg, const void *buf, int len)
+{
+ if(!arg) return 1;
+ if(BIO_write(arg, buf, len) != len) return 0;
+ return 1;
+}
+
+static int send_fp_chars(void *arg, const void *buf, int len)
+{
+ if(!arg) return 1;
+ if(fwrite(buf, 1, len, arg) != (unsigned int)len) return 0;
+ return 1;
+}
+
+typedef int char_io(void *arg, const void *buf, int len);
+
+/* This function handles display of
+ * strings, one character at a time.
+ * It is passed an unsigned long for each
+ * character because it could come from 2 or even
+ * 4 byte forms.
+ */
+
+#define HEX_SIZE(type) (sizeof(type)*2)
+
+static int do_esc_char(unsigned long c, unsigned char flags, char *do_quotes, char_io *io_ch, void *arg)
+{
+ unsigned char chflgs, chtmp;
+ char tmphex[HEX_SIZE(long)+3];
+
+ if(c > 0xffffffffL)
+ return -1;
+ if(c > 0xffff) {
+ BIO_snprintf(tmphex, sizeof tmphex, "\\W%08lX", c);
+ if(!io_ch(arg, tmphex, 10)) return -1;
+ return 10;
+ }
+ if(c > 0xff) {
+ BIO_snprintf(tmphex, sizeof tmphex, "\\U%04lX", c);
+ if(!io_ch(arg, tmphex, 6)) return -1;
+ return 6;
+ }
+ chtmp = (unsigned char)c;
+ if(chtmp > 0x7f) chflgs = flags & ASN1_STRFLGS_ESC_MSB;
+ else chflgs = char_type[chtmp] & flags;
+ if(chflgs & CHARTYPE_BS_ESC) {
+ /* If we don't escape with quotes, signal we need quotes */
+ if(chflgs & ASN1_STRFLGS_ESC_QUOTE) {
+ if(do_quotes) *do_quotes = 1;
+ if(!io_ch(arg, &chtmp, 1)) return -1;
+ return 1;
+ }
+ if(!io_ch(arg, "\\", 1)) return -1;
+ if(!io_ch(arg, &chtmp, 1)) return -1;
+ return 2;
+ }
+ if(chflgs & (ASN1_STRFLGS_ESC_CTRL|ASN1_STRFLGS_ESC_MSB)) {
+ BIO_snprintf(tmphex, 11, "\\%02X", chtmp);
+ if(!io_ch(arg, tmphex, 3)) return -1;
+ return 3;
+ }
+ /* If we get this far and do any escaping at all must escape
+ * the escape character itself: backslash.
+ */
+ if (chtmp == '\\' && flags & ESC_FLAGS) {
+ if(!io_ch(arg, "\\\\", 2)) return -1;
+ return 2;
+ }
+ if(!io_ch(arg, &chtmp, 1)) return -1;
+ return 1;
+}
+
+#define BUF_TYPE_WIDTH_MASK 0x7
+#define BUF_TYPE_CONVUTF8 0x8
+
+/* This function sends each character in a buffer to
+ * do_esc_char(). It interprets the content formats
+ * and converts to or from UTF8 as appropriate.
+ */
+
+static int do_buf(unsigned char *buf, int buflen,
+ int type, unsigned char flags, char *quotes, char_io *io_ch, void *arg)
+{
+ int i, outlen, len;
+ unsigned char orflags, *p, *q;
+ unsigned long c;
+ p = buf;
+ q = buf + buflen;
+ outlen = 0;
+ while(p != q) {
+ if(p == buf && flags & ASN1_STRFLGS_ESC_2253) orflags = CHARTYPE_FIRST_ESC_2253;
+ else orflags = 0;
+ switch(type & BUF_TYPE_WIDTH_MASK) {
+ case 4:
+ c = ((unsigned long)*p++) << 24;
+ c |= ((unsigned long)*p++) << 16;
+ c |= ((unsigned long)*p++) << 8;
+ c |= *p++;
+ break;
+
+ case 2:
+ c = ((unsigned long)*p++) << 8;
+ c |= *p++;
+ break;
+
+ case 1:
+ c = *p++;
+ break;
+
+ case 0:
+ i = UTF8_getc(p, buflen, &c);
+ if(i < 0) return -1; /* Invalid UTF8String */
+ p += i;
+ break;
+ default:
+ return -1; /* invalid width */
+ }
+ if (p == q && flags & ASN1_STRFLGS_ESC_2253) orflags = CHARTYPE_LAST_ESC_2253;
+ if(type & BUF_TYPE_CONVUTF8) {
+ unsigned char utfbuf[6];
+ int utflen;
+ utflen = UTF8_putc(utfbuf, sizeof utfbuf, c);
+ for(i = 0; i < utflen; i++) {
+ /* We don't need to worry about setting orflags correctly
+ * because if utflen==1 its value will be correct anyway
+ * otherwise each character will be > 0x7f and so the
+ * character will never be escaped on first and last.
+ */
+ len = do_esc_char(utfbuf[i], (unsigned char)(flags | orflags), quotes, io_ch, arg);
+ if(len < 0) return -1;
+ outlen += len;
+ }
+ } else {
+ len = do_esc_char(c, (unsigned char)(flags | orflags), quotes, io_ch, arg);
+ if(len < 0) return -1;
+ outlen += len;
+ }
+ }
+ return outlen;
+}
+
+/* This function hex dumps a buffer of characters */
+
+static int do_hex_dump(char_io *io_ch, void *arg, unsigned char *buf, int buflen)
+{
+ static const char hexdig[] = "0123456789ABCDEF";
+ unsigned char *p, *q;
+ char hextmp[2];
+ if(arg) {
+ p = buf;
+ q = buf + buflen;
+ while(p != q) {
+ hextmp[0] = hexdig[*p >> 4];
+ hextmp[1] = hexdig[*p & 0xf];
+ if(!io_ch(arg, hextmp, 2)) return -1;
+ p++;
+ }
+ }
+ return buflen << 1;
+}
+
+/* "dump" a string. This is done when the type is unknown,
+ * or the flags request it. We can either dump the content
+ * octets or the entire DER encoding. This uses the RFC2253
+ * #01234 format.
+ */
+
+static int do_dump(unsigned long lflags, char_io *io_ch, void *arg, ASN1_STRING *str)
+{
+ /* Placing the ASN1_STRING in a temp ASN1_TYPE allows
+ * the DER encoding to readily obtained
+ */
+ ASN1_TYPE t;
+ unsigned char *der_buf, *p;
+ int outlen, der_len;
+
+ if(!io_ch(arg, "#", 1)) return -1;
+ /* If we don't dump DER encoding just dump content octets */
+ if(!(lflags & ASN1_STRFLGS_DUMP_DER)) {
+ outlen = do_hex_dump(io_ch, arg, str->data, str->length);
+ if(outlen < 0) return -1;
+ return outlen + 1;
+ }
+ t.type = str->type;
+ t.value.ptr = (char *)str;
+ der_len = i2d_ASN1_TYPE(&t, NULL);
+ der_buf = OPENSSL_malloc(der_len);
+ if(!der_buf) return -1;
+ p = der_buf;
+ i2d_ASN1_TYPE(&t, &p);
+ outlen = do_hex_dump(io_ch, arg, der_buf, der_len);
+ OPENSSL_free(der_buf);
+ if(outlen < 0) return -1;
+ return outlen + 1;
+}
+
+/* Lookup table to convert tags to character widths,
+ * 0 = UTF8 encoded, -1 is used for non string types
+ * otherwise it is the number of bytes per character
+ */
+
+static const signed char tag2nbyte[] = {
+ -1, -1, -1, -1, -1, /* 0-4 */
+ -1, -1, -1, -1, -1, /* 5-9 */
+ -1, -1, 0, -1, /* 10-13 */
+ -1, -1, -1, -1, /* 15-17 */
+ -1, 1, 1, /* 18-20 */
+ -1, 1, 1, 1, /* 21-24 */
+ -1, 1, -1, /* 25-27 */
+ 4, -1, 2 /* 28-30 */
+};
+
+/* This is the main function, print out an
+ * ASN1_STRING taking note of various escape
+ * and display options. Returns number of
+ * characters written or -1 if an error
+ * occurred.
+ */
+
+static int do_print_ex(char_io *io_ch, void *arg, unsigned long lflags, ASN1_STRING *str)
+{
+ int outlen, len;
+ int type;
+ char quotes;
+ unsigned char flags;
+ quotes = 0;
+ /* Keep a copy of escape flags */
+ flags = (unsigned char)(lflags & ESC_FLAGS);
+
+ type = str->type;
+
+ outlen = 0;
+
+
+ if(lflags & ASN1_STRFLGS_SHOW_TYPE) {
+ const char *tagname;
+ tagname = ASN1_tag2str(type);
+ outlen += strlen(tagname);
+ if(!io_ch(arg, tagname, outlen) || !io_ch(arg, ":", 1)) return -1;
+ outlen++;
+ }
+
+ /* Decide what to do with type, either dump content or display it */
+
+ /* Dump everything */
+ if(lflags & ASN1_STRFLGS_DUMP_ALL) type = -1;
+ /* Ignore the string type */
+ else if(lflags & ASN1_STRFLGS_IGNORE_TYPE) type = 1;
+ else {
+ /* Else determine width based on type */
+ if((type > 0) && (type < 31)) type = tag2nbyte[type];
+ else type = -1;
+ if((type == -1) && !(lflags & ASN1_STRFLGS_DUMP_UNKNOWN)) type = 1;
+ }
+
+ if(type == -1) {
+ len = do_dump(lflags, io_ch, arg, str);
+ if(len < 0) return -1;
+ outlen += len;
+ return outlen;
+ }
+
+ if(lflags & ASN1_STRFLGS_UTF8_CONVERT) {
+ /* Note: if string is UTF8 and we want
+ * to convert to UTF8 then we just interpret
+ * it as 1 byte per character to avoid converting
+ * twice.
+ */
+ if(!type) type = 1;
+ else type |= BUF_TYPE_CONVUTF8;
+ }
+
+ len = do_buf(str->data, str->length, type, flags, "es, io_ch, NULL);
+ if(len < 0) return -1;
+ outlen += len;
+ if(quotes) outlen += 2;
+ if(!arg) return outlen;
+ if(quotes && !io_ch(arg, "\"", 1)) return -1;
+ if(do_buf(str->data, str->length, type, flags, NULL, io_ch, arg) < 0)
+ return -1;
+ if(quotes && !io_ch(arg, "\"", 1)) return -1;
+ return outlen;
+}
+
+/* Used for line indenting: print 'indent' spaces */
+
+static int do_indent(char_io *io_ch, void *arg, int indent)
+{
+ int i;
+ for(i = 0; i < indent; i++)
+ if(!io_ch(arg, " ", 1)) return 0;
+ return 1;
+}
+
+#define FN_WIDTH_LN 25
+#define FN_WIDTH_SN 10
+
+static int do_name_ex(char_io *io_ch, void *arg, X509_NAME *n,
+ int indent, unsigned long flags)
+{
+ int i, prev = -1, orflags, cnt;
+ int fn_opt, fn_nid;
+ ASN1_OBJECT *fn;
+ ASN1_STRING *val;
+ X509_NAME_ENTRY *ent;
+ char objtmp[80];
+ const char *objbuf;
+ int outlen, len;
+ char *sep_dn, *sep_mv, *sep_eq;
+ int sep_dn_len, sep_mv_len, sep_eq_len;
+ if(indent < 0) indent = 0;
+ outlen = indent;
+ if(!do_indent(io_ch, arg, indent)) return -1;
+ switch (flags & XN_FLAG_SEP_MASK)
+ {
+ case XN_FLAG_SEP_MULTILINE:
+ sep_dn = "\n";
+ sep_dn_len = 1;
+ sep_mv = " + ";
+ sep_mv_len = 3;
+ break;
+
+ case XN_FLAG_SEP_COMMA_PLUS:
+ sep_dn = ",";
+ sep_dn_len = 1;
+ sep_mv = "+";
+ sep_mv_len = 1;
+ indent = 0;
+ break;
+
+ case XN_FLAG_SEP_CPLUS_SPC:
+ sep_dn = ", ";
+ sep_dn_len = 2;
+ sep_mv = " + ";
+ sep_mv_len = 3;
+ indent = 0;
+ break;
+
+ case XN_FLAG_SEP_SPLUS_SPC:
+ sep_dn = "; ";
+ sep_dn_len = 2;
+ sep_mv = " + ";
+ sep_mv_len = 3;
+ indent = 0;
+ break;
+
+ default:
+ return -1;
+ }
+
+ if(flags & XN_FLAG_SPC_EQ) {
+ sep_eq = " = ";
+ sep_eq_len = 3;
+ } else {
+ sep_eq = "=";
+ sep_eq_len = 1;
+ }
+
+ fn_opt = flags & XN_FLAG_FN_MASK;
+
+ cnt = X509_NAME_entry_count(n);
+ for(i = 0; i < cnt; i++) {
+ if(flags & XN_FLAG_DN_REV)
+ ent = X509_NAME_get_entry(n, cnt - i - 1);
+ else ent = X509_NAME_get_entry(n, i);
+ if(prev != -1) {
+ if(prev == ent->set) {
+ if(!io_ch(arg, sep_mv, sep_mv_len)) return -1;
+ outlen += sep_mv_len;
+ } else {
+ if(!io_ch(arg, sep_dn, sep_dn_len)) return -1;
+ outlen += sep_dn_len;
+ if(!do_indent(io_ch, arg, indent)) return -1;
+ outlen += indent;
+ }
+ }
+ prev = ent->set;
+ fn = X509_NAME_ENTRY_get_object(ent);
+ val = X509_NAME_ENTRY_get_data(ent);
+ fn_nid = OBJ_obj2nid(fn);
+ if(fn_opt != XN_FLAG_FN_NONE) {
+ int objlen, fld_len;
+ if((fn_opt == XN_FLAG_FN_OID) || (fn_nid==NID_undef) ) {
+ OBJ_obj2txt(objtmp, sizeof objtmp, fn, 1);
+ fld_len = 0; /* XXX: what should this be? */
+ objbuf = objtmp;
+ } else {
+ if(fn_opt == XN_FLAG_FN_SN) {
+ fld_len = FN_WIDTH_SN;
+ objbuf = OBJ_nid2sn(fn_nid);
+ } else if(fn_opt == XN_FLAG_FN_LN) {
+ fld_len = FN_WIDTH_LN;
+ objbuf = OBJ_nid2ln(fn_nid);
+ } else {
+ fld_len = 0; /* XXX: what should this be? */
+ objbuf = "";
+ }
+ }
+ objlen = strlen(objbuf);
+ if(!io_ch(arg, objbuf, objlen)) return -1;
+ if ((objlen < fld_len) && (flags & XN_FLAG_FN_ALIGN)) {
+ if (!do_indent(io_ch, arg, fld_len - objlen)) return -1;
+ outlen += fld_len - objlen;
+ }
+ if(!io_ch(arg, sep_eq, sep_eq_len)) return -1;
+ outlen += objlen + sep_eq_len;
+ }
+ /* If the field name is unknown then fix up the DER dump
+ * flag. We might want to limit this further so it will
+ * DER dump on anything other than a few 'standard' fields.
+ */
+ if((fn_nid == NID_undef) && (flags & XN_FLAG_DUMP_UNKNOWN_FIELDS))
+ orflags = ASN1_STRFLGS_DUMP_ALL;
+ else orflags = 0;
+
+ len = do_print_ex(io_ch, arg, flags | orflags, val);
+ if(len < 0) return -1;
+ outlen += len;
+ }
+ return outlen;
+}
+
+/* Wrappers round the main functions */
+
+int X509_NAME_print_ex(BIO *out, X509_NAME *nm, int indent, unsigned long flags)
+{
+ if(flags == XN_FLAG_COMPAT)
+ return X509_NAME_print(out, nm, indent);
+ return do_name_ex(send_bio_chars, out, nm, indent, flags);
+}
+
+#ifndef OPENSSL_NO_FP_API
+int X509_NAME_print_ex_fp(FILE *fp, X509_NAME *nm, int indent, unsigned long flags)
+{
+ if(flags == XN_FLAG_COMPAT)
+ {
+ BIO *btmp;
+ int ret;
+ btmp = BIO_new_fp(fp, BIO_NOCLOSE);
+ if(!btmp) return -1;
+ ret = X509_NAME_print(btmp, nm, indent);
+ BIO_free(btmp);
+ return ret;
+ }
+ return do_name_ex(send_fp_chars, fp, nm, indent, flags);
+}
+#endif
+
+int ASN1_STRING_print_ex(BIO *out, ASN1_STRING *str, unsigned long flags)
+{
+ return do_print_ex(send_bio_chars, out, flags, str);
+}
+
+#ifndef OPENSSL_NO_FP_API
+int ASN1_STRING_print_ex_fp(FILE *fp, ASN1_STRING *str, unsigned long flags)
+{
+ return do_print_ex(send_fp_chars, fp, flags, str);
+}
+#endif
+
+/* Utility function: convert any string type to UTF8, returns number of bytes
+ * in output string or a negative error code
+ */
+
+int ASN1_STRING_to_UTF8(unsigned char **out, ASN1_STRING *in)
+{
+ ASN1_STRING stmp, *str = &stmp;
+ int mbflag, type, ret;
+ if(!in) return -1;
+ type = in->type;
+ if((type < 0) || (type > 30)) return -1;
+ mbflag = tag2nbyte[type];
+ if(mbflag == -1) return -1;
+ mbflag |= MBSTRING_FLAG;
+ stmp.data = NULL;
+ stmp.length = 0;
+ ret = ASN1_mbstring_copy(&str, in->data, in->length, mbflag, B_ASN1_UTF8STRING);
+ if(ret < 0) return ret;
+ *out = stmp.data;
+ return stmp.length;
+}
diff --git a/crypto/x509/a_verify.c b/crypto/x509/a_verify.c
new file mode 100644
index 0000000..2bece38
--- /dev/null
+++ b/crypto/x509/a_verify.c
@@ -0,0 +1,169 @@
+/* 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/x509.h>
+
+#include <stdio.h>
+#include <time.h>
+#include <sys/types.h>
+
+#include <openssl/bn.h>
+#include <openssl/buf.h>
+#include <openssl/digest.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+
+#include "../evp/internal.h"
+
+
+int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a,
+ ASN1_BIT_STRING *signature, void *asn, EVP_PKEY *pkey)
+ {
+ EVP_MD_CTX ctx;
+ unsigned char *buf_in=NULL;
+ int ret= -1,inl;
+ const EVP_PKEY_ASN1_METHOD *ameth;
+
+ int mdnid, pknid;
+
+ EVP_MD_CTX_init(&ctx);
+
+ /* Convert signature OID into digest and public key OIDs */
+ if (!OBJ_find_sigid_algs(OBJ_obj2nid(a->algorithm), &mdnid, &pknid))
+ {
+ OPENSSL_PUT_ERROR(X509, ASN1_item_verify, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM);
+ goto err;
+ }
+ if (mdnid == NID_undef)
+ {
+ if (!pkey->ameth || !pkey->ameth->item_verify)
+ {
+ OPENSSL_PUT_ERROR(X509, ASN1_item_verify, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM);
+ goto err;
+ }
+ ret = pkey->ameth->item_verify(&ctx, it, asn, a,
+ signature, pkey);
+ /* Return value of 2 means carry on, anything else means we
+ * exit straight away: either a fatal error of the underlying
+ * verification routine handles all verification.
+ */
+ if (ret != 2)
+ goto err;
+ ret = -1;
+ }
+ else
+ {
+ const EVP_MD *type;
+ type=EVP_get_digestbynid(mdnid);
+ if (type == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, ASN1_item_verify, ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM);
+ goto err;
+ }
+
+ /* Check public key OID matches public key type */
+ ameth = EVP_PKEY_asn1_find(NULL, pknid);
+ if (ameth == NULL || ameth->pkey_id != pkey->ameth->pkey_id)
+ {
+ OPENSSL_PUT_ERROR(X509, ASN1_item_verify, ASN1_R_WRONG_PUBLIC_KEY_TYPE);
+ goto err;
+ }
+
+ if (!EVP_DigestVerifyInit(&ctx, NULL, type, NULL, pkey))
+ {
+ OPENSSL_PUT_ERROR(X509, ASN1_item_verify, ERR_R_EVP_LIB);
+ ret=0;
+ goto err;
+ }
+
+ }
+
+ inl = ASN1_item_i2d(asn, &buf_in, it);
+
+ if (buf_in == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, ASN1_item_verify, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!EVP_DigestVerifyUpdate(&ctx,buf_in,inl))
+ {
+ OPENSSL_PUT_ERROR(X509, ASN1_item_verify, ERR_R_EVP_LIB);
+ ret=0;
+ goto err;
+ }
+
+ OPENSSL_cleanse(buf_in,(unsigned int)inl);
+ OPENSSL_free(buf_in);
+
+ if (EVP_DigestVerifyFinal(&ctx,signature->data,
+ (size_t)signature->length) <= 0)
+ {
+ OPENSSL_PUT_ERROR(X509, ASN1_item_verify, ERR_R_EVP_LIB);
+ ret=0;
+ goto err;
+ }
+ /* we don't need to zero the 'ctx' because we just checked
+ * public information */
+ /* memset(&ctx,0,sizeof(ctx)); */
+ ret=1;
+err:
+ EVP_MD_CTX_cleanup(&ctx);
+ return(ret);
+ }
+
diff --git a/crypto/x509/asn1_gen.c b/crypto/x509/asn1_gen.c
new file mode 100644
index 0000000..bbdc1a3
--- /dev/null
+++ b/crypto/x509/asn1_gen.c
@@ -0,0 +1,857 @@
+/* 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/x509.h>
+
+#include <openssl/asn1.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509v3.h>
+
+
+#define ASN1_GEN_FLAG 0x10000
+#define ASN1_GEN_FLAG_IMP (ASN1_GEN_FLAG|1)
+#define ASN1_GEN_FLAG_EXP (ASN1_GEN_FLAG|2)
+#define ASN1_GEN_FLAG_TAG (ASN1_GEN_FLAG|3)
+#define ASN1_GEN_FLAG_BITWRAP (ASN1_GEN_FLAG|4)
+#define ASN1_GEN_FLAG_OCTWRAP (ASN1_GEN_FLAG|5)
+#define ASN1_GEN_FLAG_SEQWRAP (ASN1_GEN_FLAG|6)
+#define ASN1_GEN_FLAG_SETWRAP (ASN1_GEN_FLAG|7)
+#define ASN1_GEN_FLAG_FORMAT (ASN1_GEN_FLAG|8)
+
+#define ASN1_GEN_STR(str,val) {str, sizeof(str) - 1, val}
+
+#define ASN1_FLAG_EXP_MAX 20
+
+/* Input formats */
+
+/* ASCII: default */
+#define ASN1_GEN_FORMAT_ASCII 1
+/* UTF8 */
+#define ASN1_GEN_FORMAT_UTF8 2
+/* Hex */
+#define ASN1_GEN_FORMAT_HEX 3
+/* List of bits */
+#define ASN1_GEN_FORMAT_BITLIST 4
+
+
+struct tag_name_st
+ {
+ const char *strnam;
+ int len;
+ int tag;
+ };
+
+typedef struct
+ {
+ int exp_tag;
+ int exp_class;
+ int exp_constructed;
+ int exp_pad;
+ long exp_len;
+ } tag_exp_type;
+
+typedef struct
+ {
+ int imp_tag;
+ int imp_class;
+ int utype;
+ int format;
+ const char *str;
+ tag_exp_type exp_list[ASN1_FLAG_EXP_MAX];
+ int exp_count;
+ } tag_exp_arg;
+
+static int bitstr_cb(const char *elem, int len, void *bitstr);
+static int asn1_cb(const char *elem, int len, void *bitstr);
+static int append_exp(tag_exp_arg *arg, int exp_tag, int exp_class, int exp_constructed, int exp_pad, int imp_ok);
+static int parse_tagging(const char *vstart, int vlen, int *ptag, int *pclass);
+static ASN1_TYPE *asn1_multi(int utype, const char *section, X509V3_CTX *cnf);
+static ASN1_TYPE *asn1_str2type(const char *str, int format, int utype);
+static int asn1_str2tag(const char *tagstr, int len);
+
+ASN1_TYPE *ASN1_generate_nconf(char *str, CONF *nconf)
+ {
+ X509V3_CTX cnf;
+
+ if (!nconf)
+ return ASN1_generate_v3(str, NULL);
+
+ X509V3_set_nconf(&cnf, nconf);
+ return ASN1_generate_v3(str, &cnf);
+ }
+
+ASN1_TYPE *ASN1_generate_v3(char *str, X509V3_CTX *cnf)
+ {
+ ASN1_TYPE *ret;
+ tag_exp_arg asn1_tags;
+ tag_exp_type *etmp;
+
+ int i, len;
+
+ unsigned char *orig_der = NULL, *new_der = NULL;
+ const unsigned char *cpy_start;
+ unsigned char *p;
+ const unsigned char *cp;
+ int cpy_len;
+ long hdr_len;
+ int hdr_constructed = 0, hdr_tag, hdr_class;
+ int r;
+
+ asn1_tags.imp_tag = -1;
+ asn1_tags.imp_class = -1;
+ asn1_tags.format = ASN1_GEN_FORMAT_ASCII;
+ asn1_tags.exp_count = 0;
+ if (CONF_parse_list(str, ',', 1, asn1_cb, &asn1_tags) != 0)
+ return NULL;
+
+ if ((asn1_tags.utype == V_ASN1_SEQUENCE) || (asn1_tags.utype == V_ASN1_SET))
+ {
+ if (!cnf)
+ {
+ OPENSSL_PUT_ERROR(X509, ASN1_generate_v3, ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG);
+ return NULL;
+ }
+ ret = asn1_multi(asn1_tags.utype, asn1_tags.str, cnf);
+ }
+ else
+ ret = asn1_str2type(asn1_tags.str, asn1_tags.format, asn1_tags.utype);
+
+ if (!ret)
+ return NULL;
+
+ /* If no tagging return base type */
+ if ((asn1_tags.imp_tag == -1) && (asn1_tags.exp_count == 0))
+ return ret;
+
+ /* Generate the encoding */
+ cpy_len = i2d_ASN1_TYPE(ret, &orig_der);
+ ASN1_TYPE_free(ret);
+ ret = NULL;
+ /* Set point to start copying for modified encoding */
+ cpy_start = orig_der;
+
+ /* Do we need IMPLICIT tagging? */
+ if (asn1_tags.imp_tag != -1)
+ {
+ /* If IMPLICIT we will replace the underlying tag */
+ /* Skip existing tag+len */
+ r = ASN1_get_object(&cpy_start, &hdr_len, &hdr_tag, &hdr_class, cpy_len);
+ if (r & 0x80)
+ goto err;
+ /* Update copy length */
+ cpy_len -= cpy_start - orig_der;
+ /* For IMPLICIT tagging the length should match the
+ * original length and constructed flag should be
+ * consistent.
+ */
+ if (r & 0x1)
+ {
+ /* Indefinite length constructed */
+ hdr_constructed = 2;
+ hdr_len = 0;
+ }
+ else
+ /* Just retain constructed flag */
+ hdr_constructed = r & V_ASN1_CONSTRUCTED;
+ /* Work out new length with IMPLICIT tag: ignore constructed
+ * because it will mess up if indefinite length
+ */
+ len = ASN1_object_size(0, hdr_len, asn1_tags.imp_tag);
+ }
+ else
+ len = cpy_len;
+
+ /* Work out length in any EXPLICIT, starting from end */
+
+ for(i = 0, etmp = asn1_tags.exp_list + asn1_tags.exp_count - 1; i < asn1_tags.exp_count; i++, etmp--)
+ {
+ /* Content length: number of content octets + any padding */
+ len += etmp->exp_pad;
+ etmp->exp_len = len;
+ /* Total object length: length including new header */
+ len = ASN1_object_size(0, len, etmp->exp_tag);
+ }
+
+ /* Allocate buffer for new encoding */
+
+ new_der = OPENSSL_malloc(len);
+ if (!new_der)
+ goto err;
+
+ /* Generate tagged encoding */
+
+ p = new_der;
+
+ /* Output explicit tags first */
+
+ for (i = 0, etmp = asn1_tags.exp_list; i < asn1_tags.exp_count; i++, etmp++)
+ {
+ ASN1_put_object(&p, etmp->exp_constructed, etmp->exp_len,
+ etmp->exp_tag, etmp->exp_class);
+ if (etmp->exp_pad)
+ *p++ = 0;
+ }
+
+ /* If IMPLICIT, output tag */
+
+ if (asn1_tags.imp_tag != -1)
+ {
+ if (asn1_tags.imp_class == V_ASN1_UNIVERSAL
+ && (asn1_tags.imp_tag == V_ASN1_SEQUENCE
+ || asn1_tags.imp_tag == V_ASN1_SET) )
+ hdr_constructed = V_ASN1_CONSTRUCTED;
+ ASN1_put_object(&p, hdr_constructed, hdr_len,
+ asn1_tags.imp_tag, asn1_tags.imp_class);
+ }
+
+ /* Copy across original encoding */
+ memcpy(p, cpy_start, cpy_len);
+
+ cp = new_der;
+
+ /* Obtain new ASN1_TYPE structure */
+ ret = d2i_ASN1_TYPE(NULL, &cp, len);
+
+ err:
+ if (orig_der)
+ OPENSSL_free(orig_der);
+ if (new_der)
+ OPENSSL_free(new_der);
+
+ return ret;
+
+ }
+
+static int asn1_cb(const char *elem, int len, void *bitstr)
+ {
+ tag_exp_arg *arg = bitstr;
+ int i;
+ int utype;
+ int vlen = 0;
+ const char *p, *vstart = NULL;
+
+ int tmp_tag, tmp_class;
+
+ for(i = 0, p = elem; i < len; p++, i++)
+ {
+ /* Look for the ':' in name value pairs */
+ if (*p == ':')
+ {
+ vstart = p + 1;
+ vlen = len - (vstart - elem);
+ len = p - elem;
+ break;
+ }
+ }
+
+ utype = asn1_str2tag(elem, len);
+
+ if (utype == -1)
+ {
+ OPENSSL_PUT_ERROR(X509, asn1_cb, ASN1_R_UNKNOWN_TAG);
+ ERR_add_error_data(2, "tag=", elem);
+ return -1;
+ }
+
+ /* If this is not a modifier mark end of string and exit */
+ if (!(utype & ASN1_GEN_FLAG))
+ {
+ arg->utype = utype;
+ arg->str = vstart;
+ /* If no value and not end of string, error */
+ if (!vstart && elem[len])
+ {
+ OPENSSL_PUT_ERROR(X509, asn1_cb, ASN1_R_MISSING_VALUE);
+ return -1;
+ }
+ return 0;
+ }
+
+ switch(utype)
+ {
+
+ case ASN1_GEN_FLAG_IMP:
+ /* Check for illegal multiple IMPLICIT tagging */
+ if (arg->imp_tag != -1)
+ {
+ OPENSSL_PUT_ERROR(X509, asn1_cb, ASN1_R_ILLEGAL_NESTED_TAGGING);
+ return -1;
+ }
+ if (!parse_tagging(vstart, vlen, &arg->imp_tag, &arg->imp_class))
+ return -1;
+ break;
+
+ case ASN1_GEN_FLAG_EXP:
+
+ if (!parse_tagging(vstart, vlen, &tmp_tag, &tmp_class))
+ return -1;
+ if (!append_exp(arg, tmp_tag, tmp_class, 1, 0, 0))
+ return -1;
+ break;
+
+ case ASN1_GEN_FLAG_SEQWRAP:
+ if (!append_exp(arg, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL, 1, 0, 1))
+ return -1;
+ break;
+
+ case ASN1_GEN_FLAG_SETWRAP:
+ if (!append_exp(arg, V_ASN1_SET, V_ASN1_UNIVERSAL, 1, 0, 1))
+ return -1;
+ break;
+
+ case ASN1_GEN_FLAG_BITWRAP:
+ if (!append_exp(arg, V_ASN1_BIT_STRING, V_ASN1_UNIVERSAL, 0, 1, 1))
+ return -1;
+ break;
+
+ case ASN1_GEN_FLAG_OCTWRAP:
+ if (!append_exp(arg, V_ASN1_OCTET_STRING, V_ASN1_UNIVERSAL, 0, 0, 1))
+ return -1;
+ break;
+
+ case ASN1_GEN_FLAG_FORMAT:
+ if (!strncmp(vstart, "ASCII", 5))
+ arg->format = ASN1_GEN_FORMAT_ASCII;
+ else if (!strncmp(vstart, "UTF8", 4))
+ arg->format = ASN1_GEN_FORMAT_UTF8;
+ else if (!strncmp(vstart, "HEX", 3))
+ arg->format = ASN1_GEN_FORMAT_HEX;
+ else if (!strncmp(vstart, "BITLIST", 3))
+ arg->format = ASN1_GEN_FORMAT_BITLIST;
+ else
+ {
+ OPENSSL_PUT_ERROR(X509, asn1_cb, ASN1_R_UNKOWN_FORMAT);
+ return -1;
+ }
+ break;
+
+ }
+
+ return 1;
+
+ }
+
+static int parse_tagging(const char *vstart, int vlen, int *ptag, int *pclass)
+ {
+ char erch[2];
+ long tag_num;
+ char *eptr;
+ if (!vstart)
+ return 0;
+ tag_num = strtoul(vstart, &eptr, 10);
+ /* Check we haven't gone past max length: should be impossible */
+ if (eptr && *eptr && (eptr > vstart + vlen))
+ return 0;
+ if (tag_num < 0)
+ {
+ OPENSSL_PUT_ERROR(X509, parse_tagging, ASN1_R_INVALID_NUMBER);
+ return 0;
+ }
+ *ptag = tag_num;
+ /* If we have non numeric characters, parse them */
+ if (eptr)
+ vlen -= eptr - vstart;
+ else
+ vlen = 0;
+ if (vlen)
+ {
+ switch (*eptr)
+ {
+
+ case 'U':
+ *pclass = V_ASN1_UNIVERSAL;
+ break;
+
+ case 'A':
+ *pclass = V_ASN1_APPLICATION;
+ break;
+
+ case 'P':
+ *pclass = V_ASN1_PRIVATE;
+ break;
+
+ case 'C':
+ *pclass = V_ASN1_CONTEXT_SPECIFIC;
+ break;
+
+ default:
+ erch[0] = *eptr;
+ erch[1] = 0;
+ OPENSSL_PUT_ERROR(X509, parse_tagging, ASN1_R_INVALID_MODIFIER);
+ ERR_add_error_data(2, "Char=", erch);
+ return 0;
+ break;
+
+ }
+ }
+ else
+ *pclass = V_ASN1_CONTEXT_SPECIFIC;
+
+ return 1;
+
+ }
+
+/* Handle multiple types: SET and SEQUENCE */
+
+static ASN1_TYPE *asn1_multi(int utype, const char *section, X509V3_CTX *cnf)
+ {
+ ASN1_TYPE *ret = NULL;
+ STACK_OF(ASN1_TYPE) *sk = NULL;
+ STACK_OF(CONF_VALUE) *sect = NULL;
+ unsigned char *der = NULL;
+ int derlen;
+ size_t i;
+ sk = sk_ASN1_TYPE_new_null();
+ if (!sk)
+ goto bad;
+ if (section)
+ {
+ if (!cnf)
+ goto bad;
+ sect = X509V3_get_section(cnf, (char *)section);
+ if (!sect)
+ goto bad;
+ for (i = 0; i < sk_CONF_VALUE_num(sect); i++)
+ {
+ ASN1_TYPE *typ = ASN1_generate_v3(sk_CONF_VALUE_value(sect, i)->value, cnf);
+ if (!typ)
+ goto bad;
+ if (!sk_ASN1_TYPE_push(sk, typ))
+ goto bad;
+ }
+ }
+
+ /* Now we has a STACK of the components, convert to the correct form */
+
+ if (utype == V_ASN1_SET)
+ derlen = i2d_ASN1_SET_ANY(sk, &der);
+ else
+ derlen = i2d_ASN1_SEQUENCE_ANY(sk, &der);
+
+ if (derlen < 0)
+ goto bad;
+
+ if (!(ret = ASN1_TYPE_new()))
+ goto bad;
+
+ if (!(ret->value.asn1_string = ASN1_STRING_type_new(utype)))
+ goto bad;
+
+ ret->type = utype;
+
+ ret->value.asn1_string->data = der;
+ ret->value.asn1_string->length = derlen;
+
+ der = NULL;
+
+ bad:
+
+ if (der)
+ OPENSSL_free(der);
+
+ if (sk)
+ sk_ASN1_TYPE_pop_free(sk, ASN1_TYPE_free);
+ if (sect)
+ X509V3_section_free(cnf, sect);
+
+ return ret;
+ }
+
+static int append_exp(tag_exp_arg *arg, int exp_tag, int exp_class, int exp_constructed, int exp_pad, int imp_ok)
+ {
+ tag_exp_type *exp_tmp;
+ /* Can only have IMPLICIT if permitted */
+ if ((arg->imp_tag != -1) && !imp_ok)
+ {
+ OPENSSL_PUT_ERROR(X509, append_exp, ASN1_R_ILLEGAL_IMPLICIT_TAG);
+ return 0;
+ }
+
+ if (arg->exp_count == ASN1_FLAG_EXP_MAX)
+ {
+ OPENSSL_PUT_ERROR(X509, append_exp, ASN1_R_DEPTH_EXCEEDED);
+ return 0;
+ }
+
+ exp_tmp = &arg->exp_list[arg->exp_count++];
+
+ /* If IMPLICIT set tag to implicit value then
+ * reset implicit tag since it has been used.
+ */
+ if (arg->imp_tag != -1)
+ {
+ exp_tmp->exp_tag = arg->imp_tag;
+ exp_tmp->exp_class = arg->imp_class;
+ arg->imp_tag = -1;
+ arg->imp_class = -1;
+ }
+ else
+ {
+ exp_tmp->exp_tag = exp_tag;
+ exp_tmp->exp_class = exp_class;
+ }
+ exp_tmp->exp_constructed = exp_constructed;
+ exp_tmp->exp_pad = exp_pad;
+
+ return 1;
+ }
+
+
+static int asn1_str2tag(const char *tagstr, int len)
+ {
+ unsigned int i;
+ static const struct tag_name_st *tntmp, tnst [] = {
+ ASN1_GEN_STR("BOOL", V_ASN1_BOOLEAN),
+ ASN1_GEN_STR("BOOLEAN", V_ASN1_BOOLEAN),
+ ASN1_GEN_STR("NULL", V_ASN1_NULL),
+ ASN1_GEN_STR("INT", V_ASN1_INTEGER),
+ ASN1_GEN_STR("INTEGER", V_ASN1_INTEGER),
+ ASN1_GEN_STR("ENUM", V_ASN1_ENUMERATED),
+ ASN1_GEN_STR("ENUMERATED", V_ASN1_ENUMERATED),
+ ASN1_GEN_STR("OID", V_ASN1_OBJECT),
+ ASN1_GEN_STR("OBJECT", V_ASN1_OBJECT),
+ ASN1_GEN_STR("UTCTIME", V_ASN1_UTCTIME),
+ ASN1_GEN_STR("UTC", V_ASN1_UTCTIME),
+ ASN1_GEN_STR("GENERALIZEDTIME", V_ASN1_GENERALIZEDTIME),
+ ASN1_GEN_STR("GENTIME", V_ASN1_GENERALIZEDTIME),
+ ASN1_GEN_STR("OCT", V_ASN1_OCTET_STRING),
+ ASN1_GEN_STR("OCTETSTRING", V_ASN1_OCTET_STRING),
+ ASN1_GEN_STR("BITSTR", V_ASN1_BIT_STRING),
+ ASN1_GEN_STR("BITSTRING", V_ASN1_BIT_STRING),
+ ASN1_GEN_STR("UNIVERSALSTRING", V_ASN1_UNIVERSALSTRING),
+ ASN1_GEN_STR("UNIV", V_ASN1_UNIVERSALSTRING),
+ ASN1_GEN_STR("IA5", V_ASN1_IA5STRING),
+ ASN1_GEN_STR("IA5STRING", V_ASN1_IA5STRING),
+ ASN1_GEN_STR("UTF8", V_ASN1_UTF8STRING),
+ ASN1_GEN_STR("UTF8String", V_ASN1_UTF8STRING),
+ ASN1_GEN_STR("BMP", V_ASN1_BMPSTRING),
+ ASN1_GEN_STR("BMPSTRING", V_ASN1_BMPSTRING),
+ ASN1_GEN_STR("VISIBLESTRING", V_ASN1_VISIBLESTRING),
+ ASN1_GEN_STR("VISIBLE", V_ASN1_VISIBLESTRING),
+ ASN1_GEN_STR("PRINTABLESTRING", V_ASN1_PRINTABLESTRING),
+ ASN1_GEN_STR("PRINTABLE", V_ASN1_PRINTABLESTRING),
+ ASN1_GEN_STR("T61", V_ASN1_T61STRING),
+ ASN1_GEN_STR("T61STRING", V_ASN1_T61STRING),
+ ASN1_GEN_STR("TELETEXSTRING", V_ASN1_T61STRING),
+ ASN1_GEN_STR("GeneralString", V_ASN1_GENERALSTRING),
+ ASN1_GEN_STR("GENSTR", V_ASN1_GENERALSTRING),
+ ASN1_GEN_STR("NUMERIC", V_ASN1_NUMERICSTRING),
+ ASN1_GEN_STR("NUMERICSTRING", V_ASN1_NUMERICSTRING),
+
+ /* Special cases */
+ ASN1_GEN_STR("SEQUENCE", V_ASN1_SEQUENCE),
+ ASN1_GEN_STR("SEQ", V_ASN1_SEQUENCE),
+ ASN1_GEN_STR("SET", V_ASN1_SET),
+ /* type modifiers */
+ /* Explicit tag */
+ ASN1_GEN_STR("EXP", ASN1_GEN_FLAG_EXP),
+ ASN1_GEN_STR("EXPLICIT", ASN1_GEN_FLAG_EXP),
+ /* Implicit tag */
+ ASN1_GEN_STR("IMP", ASN1_GEN_FLAG_IMP),
+ ASN1_GEN_STR("IMPLICIT", ASN1_GEN_FLAG_IMP),
+ /* OCTET STRING wrapper */
+ ASN1_GEN_STR("OCTWRAP", ASN1_GEN_FLAG_OCTWRAP),
+ /* SEQUENCE wrapper */
+ ASN1_GEN_STR("SEQWRAP", ASN1_GEN_FLAG_SEQWRAP),
+ /* SET wrapper */
+ ASN1_GEN_STR("SETWRAP", ASN1_GEN_FLAG_SETWRAP),
+ /* BIT STRING wrapper */
+ ASN1_GEN_STR("BITWRAP", ASN1_GEN_FLAG_BITWRAP),
+ ASN1_GEN_STR("FORM", ASN1_GEN_FLAG_FORMAT),
+ ASN1_GEN_STR("FORMAT", ASN1_GEN_FLAG_FORMAT),
+ };
+
+ if (len == -1)
+ len = strlen(tagstr);
+
+ tntmp = tnst;
+ for (i = 0; i < sizeof(tnst) / sizeof(struct tag_name_st); i++, tntmp++)
+ {
+ if ((len == tntmp->len) && !strncmp(tntmp->strnam, tagstr, len))
+ return tntmp->tag;
+ }
+
+ return -1;
+ }
+
+static ASN1_TYPE *asn1_str2type(const char *str, int format, int utype)
+ {
+ ASN1_TYPE *atmp = NULL;
+
+ CONF_VALUE vtmp;
+
+ unsigned char *rdata;
+ long rdlen;
+
+ int no_unused = 1;
+
+ if (!(atmp = ASN1_TYPE_new()))
+ {
+ OPENSSL_PUT_ERROR(X509, asn1_str2type, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ if (!str)
+ str = "";
+
+ switch(utype)
+ {
+
+ case V_ASN1_NULL:
+ if (str && *str)
+ {
+ OPENSSL_PUT_ERROR(X509, asn1_str2type, ASN1_R_ILLEGAL_NULL_VALUE);
+ goto bad_form;
+ }
+ break;
+
+ case V_ASN1_BOOLEAN:
+ if (format != ASN1_GEN_FORMAT_ASCII)
+ {
+ OPENSSL_PUT_ERROR(X509, asn1_str2type, ASN1_R_NOT_ASCII_FORMAT);
+ goto bad_form;
+ }
+ vtmp.name = NULL;
+ vtmp.section = NULL;
+ vtmp.value = (char *)str;
+ if (!X509V3_get_value_bool(&vtmp, &atmp->value.boolean))
+ {
+ OPENSSL_PUT_ERROR(X509, asn1_str2type, ASN1_R_ILLEGAL_BOOLEAN);
+ goto bad_str;
+ }
+ break;
+
+ case V_ASN1_INTEGER:
+ case V_ASN1_ENUMERATED:
+ if (format != ASN1_GEN_FORMAT_ASCII)
+ {
+ OPENSSL_PUT_ERROR(X509, asn1_str2type, ASN1_R_INTEGER_NOT_ASCII_FORMAT);
+ goto bad_form;
+ }
+ if (!(atmp->value.integer = s2i_ASN1_INTEGER(NULL, (char *)str)))
+ {
+ OPENSSL_PUT_ERROR(X509, asn1_str2type, ASN1_R_ILLEGAL_INTEGER);
+ goto bad_str;
+ }
+ break;
+
+ case V_ASN1_OBJECT:
+ if (format != ASN1_GEN_FORMAT_ASCII)
+ {
+ OPENSSL_PUT_ERROR(X509, asn1_str2type, ASN1_R_OBJECT_NOT_ASCII_FORMAT);
+ goto bad_form;
+ }
+ if (!(atmp->value.object = OBJ_txt2obj(str, 0)))
+ {
+ OPENSSL_PUT_ERROR(X509, asn1_str2type, ASN1_R_ILLEGAL_OBJECT);
+ goto bad_str;
+ }
+ break;
+
+ case V_ASN1_UTCTIME:
+ case V_ASN1_GENERALIZEDTIME:
+ if (format != ASN1_GEN_FORMAT_ASCII)
+ {
+ OPENSSL_PUT_ERROR(X509, asn1_str2type, ASN1_R_TIME_NOT_ASCII_FORMAT);
+ goto bad_form;
+ }
+ if (!(atmp->value.asn1_string = ASN1_STRING_new()))
+ {
+ OPENSSL_PUT_ERROR(X509, asn1_str2type, ERR_R_MALLOC_FAILURE);
+ goto bad_str;
+ }
+ if (!ASN1_STRING_set(atmp->value.asn1_string, str, -1))
+ {
+ OPENSSL_PUT_ERROR(X509, asn1_str2type, ERR_R_MALLOC_FAILURE);
+ goto bad_str;
+ }
+ atmp->value.asn1_string->type = utype;
+ if (!ASN1_TIME_check(atmp->value.asn1_string))
+ {
+ OPENSSL_PUT_ERROR(X509, asn1_str2type, ASN1_R_ILLEGAL_TIME_VALUE);
+ goto bad_str;
+ }
+
+ break;
+
+ case V_ASN1_BMPSTRING:
+ case V_ASN1_PRINTABLESTRING:
+ case V_ASN1_IA5STRING:
+ case V_ASN1_T61STRING:
+ case V_ASN1_UTF8STRING:
+ case V_ASN1_VISIBLESTRING:
+ case V_ASN1_UNIVERSALSTRING:
+ case V_ASN1_GENERALSTRING:
+ case V_ASN1_NUMERICSTRING:
+
+ if (format == ASN1_GEN_FORMAT_ASCII)
+ format = MBSTRING_ASC;
+ else if (format == ASN1_GEN_FORMAT_UTF8)
+ format = MBSTRING_UTF8;
+ else
+ {
+ OPENSSL_PUT_ERROR(X509, asn1_str2type, ASN1_R_ILLEGAL_FORMAT);
+ goto bad_form;
+ }
+
+
+ if (ASN1_mbstring_copy(&atmp->value.asn1_string, (unsigned char *)str,
+ -1, format, ASN1_tag2bit(utype)) <= 0)
+ {
+ OPENSSL_PUT_ERROR(X509, asn1_str2type, ERR_R_MALLOC_FAILURE);
+ goto bad_str;
+ }
+
+
+ break;
+
+ case V_ASN1_BIT_STRING:
+
+ case V_ASN1_OCTET_STRING:
+
+ if (!(atmp->value.asn1_string = ASN1_STRING_new()))
+ {
+ OPENSSL_PUT_ERROR(X509, asn1_str2type, ERR_R_MALLOC_FAILURE);
+ goto bad_form;
+ }
+
+ if (format == ASN1_GEN_FORMAT_HEX)
+ {
+
+ if (!(rdata = string_to_hex((char *)str, &rdlen)))
+ {
+ OPENSSL_PUT_ERROR(X509, asn1_str2type, ASN1_R_ILLEGAL_HEX);
+ goto bad_str;
+ }
+
+ atmp->value.asn1_string->data = rdata;
+ atmp->value.asn1_string->length = rdlen;
+ atmp->value.asn1_string->type = utype;
+
+ }
+ else if (format == ASN1_GEN_FORMAT_ASCII)
+ ASN1_STRING_set(atmp->value.asn1_string, str, -1);
+ else if ((format == ASN1_GEN_FORMAT_BITLIST) && (utype == V_ASN1_BIT_STRING))
+ {
+ if (!CONF_parse_list(str, ',', 1, bitstr_cb, atmp->value.bit_string))
+ {
+ OPENSSL_PUT_ERROR(X509, asn1_str2type, ASN1_R_LIST_ERROR);
+ goto bad_str;
+ }
+ no_unused = 0;
+
+ }
+ else
+ {
+ OPENSSL_PUT_ERROR(X509, asn1_str2type, ASN1_R_ILLEGAL_BITSTRING_FORMAT);
+ goto bad_form;
+ }
+
+ if ((utype == V_ASN1_BIT_STRING) && no_unused)
+ {
+ atmp->value.asn1_string->flags
+ &= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07);
+ atmp->value.asn1_string->flags
+ |= ASN1_STRING_FLAG_BITS_LEFT;
+ }
+
+
+ break;
+
+ default:
+ OPENSSL_PUT_ERROR(X509, asn1_str2type, ASN1_R_UNSUPPORTED_TYPE);
+ goto bad_str;
+ break;
+ }
+
+
+ atmp->type = utype;
+ return atmp;
+
+
+ bad_str:
+ ERR_add_error_data(2, "string=", str);
+ bad_form:
+
+ ASN1_TYPE_free(atmp);
+ return NULL;
+
+ }
+
+static int bitstr_cb(const char *elem, int len, void *bitstr)
+ {
+ long bitnum;
+ char *eptr;
+ if (!elem)
+ return 0;
+ bitnum = strtoul(elem, &eptr, 10);
+ if (eptr && *eptr && (eptr != elem + len))
+ return 0;
+ if (bitnum < 0)
+ {
+ OPENSSL_PUT_ERROR(X509, bitstr_cb, ASN1_R_INVALID_NUMBER);
+ return 0;
+ }
+ if (!ASN1_BIT_STRING_set_bit(bitstr, bitnum, 1))
+ {
+ OPENSSL_PUT_ERROR(X509, bitstr_cb, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ return 1;
+ }
+
diff --git a/crypto/x509/by_dir.c b/crypto/x509/by_dir.c
new file mode 100644
index 0000000..8b8d0d4
--- /dev/null
+++ b/crypto/x509/by_dir.c
@@ -0,0 +1,472 @@
+/* crypto/x509/by_dir.c */
+/* 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 <sys/types.h>
+#include <sys/stat.h>
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/lhash.h>
+#include <openssl/mem.h>
+#include <openssl/x509.h>
+
+
+typedef struct lookup_dir_hashes_st
+ {
+ unsigned long hash;
+ int suffix;
+ } BY_DIR_HASH;
+
+typedef struct lookup_dir_entry_st
+ {
+ char *dir;
+ int dir_type;
+ STACK_OF(BY_DIR_HASH) *hashes;
+ } BY_DIR_ENTRY;
+
+typedef struct lookup_dir_st
+ {
+ BUF_MEM *buffer;
+ STACK_OF(BY_DIR_ENTRY) *dirs;
+ } BY_DIR;
+
+DECLARE_STACK_OF(BY_DIR_HASH)
+DECLARE_STACK_OF(BY_DIR_ENTRY)
+
+static int dir_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl,
+ char **ret);
+static int new_dir(X509_LOOKUP *lu);
+static void free_dir(X509_LOOKUP *lu);
+static int add_cert_dir(BY_DIR *ctx,const char *dir,int type);
+static int get_cert_by_subject(X509_LOOKUP *xl,int type,X509_NAME *name,
+ X509_OBJECT *ret);
+X509_LOOKUP_METHOD x509_dir_lookup=
+ {
+ "Load certs from files in a directory",
+ new_dir, /* new */
+ free_dir, /* free */
+ NULL, /* init */
+ NULL, /* shutdown */
+ dir_ctrl, /* ctrl */
+ get_cert_by_subject, /* get_by_subject */
+ NULL, /* get_by_issuer_serial */
+ NULL, /* get_by_fingerprint */
+ NULL, /* get_by_alias */
+ };
+
+X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void)
+ {
+ return(&x509_dir_lookup);
+ }
+
+static int dir_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl,
+ char **retp)
+ {
+ int ret=0;
+ BY_DIR *ld;
+ char *dir = NULL;
+
+ ld=(BY_DIR *)ctx->method_data;
+
+ switch (cmd)
+ {
+ case X509_L_ADD_DIR:
+ if (argl == X509_FILETYPE_DEFAULT)
+ {
+ dir=(char *)getenv(X509_get_default_cert_dir_env());
+ if (dir)
+ ret=add_cert_dir(ld,dir,X509_FILETYPE_PEM);
+ else
+ ret=add_cert_dir(ld,X509_get_default_cert_dir(),
+ X509_FILETYPE_PEM);
+ if (!ret)
+ {
+ OPENSSL_PUT_ERROR(X509, dir_ctrl, X509_R_LOADING_CERT_DIR);
+ }
+ }
+ else
+ ret=add_cert_dir(ld,argp,(int)argl);
+ break;
+ }
+ return(ret);
+ }
+
+static int new_dir(X509_LOOKUP *lu)
+ {
+ BY_DIR *a;
+
+ if ((a=(BY_DIR *)OPENSSL_malloc(sizeof(BY_DIR))) == NULL)
+ return(0);
+ if ((a->buffer=BUF_MEM_new()) == NULL)
+ {
+ OPENSSL_free(a);
+ return(0);
+ }
+ a->dirs=NULL;
+ lu->method_data=(char *)a;
+ return(1);
+ }
+
+static void by_dir_hash_free(BY_DIR_HASH *hash)
+ {
+ OPENSSL_free(hash);
+ }
+
+static int by_dir_hash_cmp(const BY_DIR_HASH **a,
+ const BY_DIR_HASH **b)
+ {
+ if ((*a)->hash > (*b)->hash)
+ return 1;
+ if ((*a)->hash < (*b)->hash)
+ return -1;
+ return 0;
+ }
+
+static void by_dir_entry_free(BY_DIR_ENTRY *ent)
+ {
+ if (ent->dir)
+ OPENSSL_free(ent->dir);
+ if (ent->hashes)
+ sk_BY_DIR_HASH_pop_free(ent->hashes, by_dir_hash_free);
+ OPENSSL_free(ent);
+ }
+
+static void free_dir(X509_LOOKUP *lu)
+ {
+ BY_DIR *a;
+
+ a=(BY_DIR *)lu->method_data;
+ if (a->dirs != NULL)
+ sk_BY_DIR_ENTRY_pop_free(a->dirs, by_dir_entry_free);
+ if (a->buffer != NULL)
+ BUF_MEM_free(a->buffer);
+ OPENSSL_free(a);
+ }
+
+static int add_cert_dir(BY_DIR *ctx, const char *dir, int type)
+ {
+ int j,len;
+ const char *s,*ss,*p;
+
+ if (dir == NULL || !*dir)
+ {
+ OPENSSL_PUT_ERROR(X509, add_cert_dir, X509_R_INVALID_DIRECTORY);
+ return 0;
+ }
+
+ s=dir;
+ p=s;
+ for (;;p++)
+ {
+ if ((*p == ':') || (*p == '\0'))
+ {
+ BY_DIR_ENTRY *ent;
+ ss=s;
+ s=p+1;
+ len=(int)(p-ss);
+ if (len == 0) continue;
+ for (j=0; j < sk_BY_DIR_ENTRY_num(ctx->dirs); j++)
+ {
+ ent = sk_BY_DIR_ENTRY_value(ctx->dirs, j);
+ if (strlen(ent->dir) == (size_t)len &&
+ strncmp(ent->dir,ss,(unsigned int)len) == 0)
+ break;
+ }
+ if (j < sk_BY_DIR_ENTRY_num(ctx->dirs))
+ continue;
+ if (ctx->dirs == NULL)
+ {
+ ctx->dirs = sk_BY_DIR_ENTRY_new_null();
+ if (!ctx->dirs)
+ {
+ OPENSSL_PUT_ERROR(X509, add_cert_dir, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ }
+ ent = OPENSSL_malloc(sizeof(BY_DIR_ENTRY));
+ if (!ent)
+ return 0;
+ ent->dir_type = type;
+ ent->hashes = sk_BY_DIR_HASH_new(by_dir_hash_cmp);
+ ent->dir = OPENSSL_malloc((unsigned int)len+1);
+ if (!ent->dir || !ent->hashes)
+ {
+ by_dir_entry_free(ent);
+ return 0;
+ }
+ strncpy(ent->dir,ss,(unsigned int)len);
+ ent->dir[len] = '\0';
+ if (!sk_BY_DIR_ENTRY_push(ctx->dirs, ent))
+ {
+ by_dir_entry_free(ent);
+ return 0;
+ }
+ }
+ if (*p == '\0')
+ break;
+ }
+ return 1;
+ }
+
+static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name,
+ X509_OBJECT *ret)
+ {
+ BY_DIR *ctx;
+ union {
+ struct {
+ X509 st_x509;
+ X509_CINF st_x509_cinf;
+ } x509;
+ struct {
+ X509_CRL st_crl;
+ X509_CRL_INFO st_crl_info;
+ } crl;
+ } data;
+ int ok=0;
+ int i,j,k;
+ unsigned long h;
+ BUF_MEM *b=NULL;
+ X509_OBJECT stmp,*tmp;
+ const char *postfix="";
+
+ if (name == NULL) return(0);
+
+ stmp.type=type;
+ if (type == X509_LU_X509)
+ {
+ data.x509.st_x509.cert_info= &data.x509.st_x509_cinf;
+ data.x509.st_x509_cinf.subject=name;
+ stmp.data.x509= &data.x509.st_x509;
+ postfix="";
+ }
+ else if (type == X509_LU_CRL)
+ {
+ data.crl.st_crl.crl= &data.crl.st_crl_info;
+ data.crl.st_crl_info.issuer=name;
+ stmp.data.crl= &data.crl.st_crl;
+ postfix="r";
+ }
+ else
+ {
+ OPENSSL_PUT_ERROR(X509, get_cert_by_subject, 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);
+ goto finish;
+ }
+
+ ctx=(BY_DIR *)xl->method_data;
+
+ h=X509_NAME_hash(name);
+ for (i=0; i < sk_BY_DIR_ENTRY_num(ctx->dirs); i++)
+ {
+ BY_DIR_ENTRY *ent;
+ size_t idx;
+ BY_DIR_HASH htmp, *hent;
+ ent = sk_BY_DIR_ENTRY_value(ctx->dirs, i);
+ 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);
+ goto finish;
+ }
+ if (type == X509_LU_CRL && ent->hashes)
+ {
+ htmp.hash = h;
+ CRYPTO_r_lock(CRYPTO_LOCK_X509_STORE);
+ if (sk_BY_DIR_HASH_find(ent->hashes, &idx, &htmp))
+ {
+ hent = sk_BY_DIR_HASH_value(ent->hashes, idx);
+ k = hent->suffix;
+ }
+ else
+ {
+ hent = NULL;
+ k=0;
+ }
+ CRYPTO_r_unlock(CRYPTO_LOCK_X509_STORE);
+ }
+ else
+ {
+ k = 0;
+ hent = NULL;
+ }
+ for (;;)
+ {
+ char c = '/';
+#ifdef OPENSSL_SYS_VMS
+ c = ent->dir[strlen(ent->dir)-1];
+ if (c != ':' && c != '>' && c != ']')
+ {
+ /* If no separator is present, we assume the
+ directory specifier is a logical name, and
+ add a colon. We really should use better
+ VMS routines for merging things like this,
+ but this will do for now...
+ -- Richard Levitte */
+ c = ':';
+ }
+ else
+ {
+ c = '\0';
+ }
+#endif
+ if (c == '\0')
+ {
+ /* This is special. When c == '\0', no
+ directory separator should be added. */
+ BIO_snprintf(b->data,b->max,
+ "%s%08lx.%s%d",ent->dir,h,
+ postfix,k);
+ }
+ else
+ {
+ BIO_snprintf(b->data,b->max,
+ "%s%c%08lx.%s%d",ent->dir,c,h,
+ postfix,k);
+ }
+#ifndef OPENSSL_NO_POSIX_IO
+#ifdef _WIN32
+#define stat _stat
+#endif
+ {
+ struct stat st;
+ if (stat(b->data,&st) < 0)
+ break;
+ }
+#endif
+ /* found one. */
+ if (type == X509_LU_X509)
+ {
+ if ((X509_load_cert_file(xl,b->data,
+ ent->dir_type)) == 0)
+ break;
+ }
+ else if (type == X509_LU_CRL)
+ {
+ if ((X509_load_crl_file(xl,b->data,
+ ent->dir_type)) == 0)
+ break;
+ }
+ /* else case will caught higher up */
+ k++;
+ }
+
+ /* we have added it to the cache so now pull
+ * it out again */
+ CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
+ tmp = NULL;
+ if (sk_X509_OBJECT_find(xl->store_ctx->objs, &idx, &stmp)) {
+ tmp=sk_X509_OBJECT_value(xl->store_ctx->objs,idx);
+ }
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
+
+
+ /* If a CRL, update the last file suffix added for this */
+
+ if (type == X509_LU_CRL)
+ {
+ CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
+ /* Look for entry again in case another thread added
+ * an entry first.
+ */
+ if (!hent)
+ {
+ htmp.hash = h;
+ if (sk_BY_DIR_HASH_find(ent->hashes, &idx, &htmp))
+ hent = sk_BY_DIR_HASH_value(ent->hashes, idx);
+ }
+ if (!hent)
+ {
+ hent = OPENSSL_malloc(sizeof(BY_DIR_HASH));
+ hent->hash = h;
+ hent->suffix = k;
+ if (!sk_BY_DIR_HASH_push(ent->hashes, hent))
+ {
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
+ OPENSSL_free(hent);
+ ok = 0;
+ goto finish;
+ }
+ }
+ else if (hent->suffix < k)
+ hent->suffix = k;
+
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
+
+ }
+
+ if (tmp != NULL)
+ {
+ ok=1;
+ ret->type=tmp->type;
+ memcpy(&ret->data,&tmp->data,sizeof(ret->data));
+ /* If we were going to up the reference count,
+ * we would need to do it on a perl 'type'
+ * basis */
+ /* CRYPTO_add(&tmp->data.x509->references,1,
+ CRYPTO_LOCK_X509);*/
+ goto finish;
+ }
+ }
+finish:
+ if (b != NULL) BUF_MEM_free(b);
+ return(ok);
+ }
diff --git a/crypto/x509/by_file.c b/crypto/x509/by_file.c
new file mode 100644
index 0000000..2649631
--- /dev/null
+++ b/crypto/x509/by_file.c
@@ -0,0 +1,292 @@
+/* crypto/x509/by_file.c */
+/* 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/buf.h>
+#include <openssl/err.h>
+#include <openssl/lhash.h>
+#include <openssl/pem.h>
+#include <openssl/x509.h>
+
+#ifndef OPENSSL_NO_STDIO
+
+static int by_file_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc,
+ long argl, char **ret);
+X509_LOOKUP_METHOD x509_file_lookup=
+ {
+ "Load file into cache",
+ NULL, /* new */
+ NULL, /* free */
+ NULL, /* init */
+ NULL, /* shutdown */
+ by_file_ctrl, /* ctrl */
+ NULL, /* get_by_subject */
+ NULL, /* get_by_issuer_serial */
+ NULL, /* get_by_fingerprint */
+ NULL, /* get_by_alias */
+ };
+
+X509_LOOKUP_METHOD *X509_LOOKUP_file(void)
+ {
+ return(&x509_file_lookup);
+ }
+
+static int by_file_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl,
+ char **ret)
+ {
+ int ok=0;
+ char *file;
+
+ switch (cmd)
+ {
+ case X509_L_FILE_LOAD:
+ if (argl == X509_FILETYPE_DEFAULT)
+ {
+ file = (char *)getenv(X509_get_default_cert_file_env());
+ if (file)
+ ok = (X509_load_cert_crl_file(ctx,file,
+ X509_FILETYPE_PEM) != 0);
+
+ else
+ ok = (X509_load_cert_crl_file(ctx,X509_get_default_cert_file(),
+ X509_FILETYPE_PEM) != 0);
+
+ if (!ok)
+ {
+ OPENSSL_PUT_ERROR(X509, by_file_ctrl, X509_R_LOADING_DEFAULTS);
+ }
+ }
+ else
+ {
+ if(argl == X509_FILETYPE_PEM)
+ ok = (X509_load_cert_crl_file(ctx,argp,
+ X509_FILETYPE_PEM) != 0);
+ else
+ ok = (X509_load_cert_file(ctx,argp,(int)argl) != 0);
+ }
+ break;
+ }
+ return(ok);
+ }
+
+int X509_load_cert_file(X509_LOOKUP *ctx, const char *file, int type)
+ {
+ int ret=0;
+ BIO *in=NULL;
+ int i,count=0;
+ X509 *x=NULL;
+
+ if (file == NULL) return(1);
+ in=BIO_new(BIO_s_file());
+
+ if ((in == NULL) || (BIO_read_filename(in,file) <= 0))
+ {
+ OPENSSL_PUT_ERROR(X509, X509_load_cert_file, ERR_R_SYS_LIB);
+ goto err;
+ }
+
+ if (type == X509_FILETYPE_PEM)
+ {
+ for (;;)
+ {
+ x=PEM_read_bio_X509_AUX(in,NULL,NULL,NULL);
+ if (x == NULL)
+ {
+ if ((ERR_GET_REASON(ERR_peek_last_error()) ==
+ PEM_R_NO_START_LINE) && (count > 0))
+ {
+ ERR_clear_error();
+ break;
+ }
+ else
+ {
+ OPENSSL_PUT_ERROR(X509, X509_load_cert_file, ERR_R_PEM_LIB);
+ goto err;
+ }
+ }
+ i=X509_STORE_add_cert(ctx->store_ctx,x);
+ if (!i) goto err;
+ count++;
+ X509_free(x);
+ x=NULL;
+ }
+ ret=count;
+ }
+ else if (type == X509_FILETYPE_ASN1)
+ {
+ x=d2i_X509_bio(in,NULL);
+ if (x == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_load_cert_file, ERR_R_ASN1_LIB);
+ goto err;
+ }
+ i=X509_STORE_add_cert(ctx->store_ctx,x);
+ if (!i) goto err;
+ ret=i;
+ }
+ else
+ {
+ OPENSSL_PUT_ERROR(X509, X509_load_cert_file, X509_R_BAD_X509_FILETYPE);
+ goto err;
+ }
+err:
+ if (x != NULL) X509_free(x);
+ if (in != NULL) BIO_free(in);
+ return(ret);
+ }
+
+int X509_load_crl_file(X509_LOOKUP *ctx, const char *file, int type)
+ {
+ int ret=0;
+ BIO *in=NULL;
+ int i,count=0;
+ X509_CRL *x=NULL;
+
+ if (file == NULL) return(1);
+ in=BIO_new(BIO_s_file());
+
+ if ((in == NULL) || (BIO_read_filename(in,file) <= 0))
+ {
+ OPENSSL_PUT_ERROR(X509, X509_load_crl_file, ERR_R_SYS_LIB);
+ goto err;
+ }
+
+ if (type == X509_FILETYPE_PEM)
+ {
+ for (;;)
+ {
+ x=PEM_read_bio_X509_CRL(in,NULL,NULL,NULL);
+ if (x == NULL)
+ {
+ if ((ERR_GET_REASON(ERR_peek_last_error()) ==
+ PEM_R_NO_START_LINE) && (count > 0))
+ {
+ ERR_clear_error();
+ break;
+ }
+ else
+ {
+ OPENSSL_PUT_ERROR(X509, X509_load_crl_file, ERR_R_PEM_LIB);
+ goto err;
+ }
+ }
+ i=X509_STORE_add_crl(ctx->store_ctx,x);
+ if (!i) goto err;
+ count++;
+ X509_CRL_free(x);
+ x=NULL;
+ }
+ ret=count;
+ }
+ else if (type == X509_FILETYPE_ASN1)
+ {
+ x=d2i_X509_CRL_bio(in,NULL);
+ if (x == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_load_crl_file, ERR_R_ASN1_LIB);
+ goto err;
+ }
+ i=X509_STORE_add_crl(ctx->store_ctx,x);
+ if (!i) goto err;
+ ret=i;
+ }
+ else
+ {
+ OPENSSL_PUT_ERROR(X509, X509_load_crl_file, X509_R_BAD_X509_FILETYPE);
+ goto err;
+ }
+err:
+ if (x != NULL) X509_CRL_free(x);
+ if (in != NULL) BIO_free(in);
+ return(ret);
+ }
+
+int X509_load_cert_crl_file(X509_LOOKUP *ctx, const char *file, int type)
+{
+ STACK_OF(X509_INFO) *inf;
+ X509_INFO *itmp;
+ BIO *in;
+ size_t i;
+ int count = 0;
+ if(type != X509_FILETYPE_PEM)
+ 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);
+ 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);
+ return 0;
+ }
+ for(i = 0; i < sk_X509_INFO_num(inf); i++) {
+ itmp = sk_X509_INFO_value(inf, i);
+ if(itmp->x509) {
+ X509_STORE_add_cert(ctx->store_ctx, itmp->x509);
+ count++;
+ }
+ if(itmp->crl) {
+ X509_STORE_add_crl(ctx->store_ctx, itmp->crl);
+ count++;
+ }
+ }
+ sk_X509_INFO_pop_free(inf, X509_INFO_free);
+ return count;
+}
+
+#endif /* OPENSSL_NO_STDIO */
diff --git a/crypto/x509/charmap.h b/crypto/x509/charmap.h
new file mode 100644
index 0000000..b55e638
--- /dev/null
+++ b/crypto/x509/charmap.h
@@ -0,0 +1,15 @@
+/* Auto generated with chartype.pl script.
+ * Mask of various character properties
+ */
+
+static const unsigned char char_type[] = {
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+120, 0, 1,40, 0, 0, 0,16,16,16, 0,25,25,16,16,16,
+16,16,16,16,16,16,16,16,16,16,16, 9, 9,16, 9,16,
+ 0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
+16,16,16,16,16,16,16,16,16,16,16, 0, 1, 0, 0, 0,
+ 0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
+16,16,16,16,16,16,16,16,16,16,16, 0, 0, 0, 0, 2
+};
+
diff --git a/crypto/x509/i2d_pr.c b/crypto/x509/i2d_pr.c
new file mode 100644
index 0000000..8896565
--- /dev/null
+++ b/crypto/x509/i2d_pr.c
@@ -0,0 +1,83 @@
+/* crypto/asn1/i2d_pr.c */
+/* 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/x509.h>
+
+#include <stdio.h>
+
+#include <openssl/err.h>
+#include <openssl/evp.h>
+
+#include "../evp/internal.h"
+
+
+int i2d_PrivateKey(const EVP_PKEY *a, unsigned char **pp)
+ {
+ if (a->ameth && a->ameth->old_priv_encode)
+ {
+ return a->ameth->old_priv_encode(a, pp);
+ }
+ if (a->ameth && a->ameth->priv_encode) {
+ PKCS8_PRIV_KEY_INFO *p8 = EVP_PKEY2PKCS8((EVP_PKEY*)a);
+ int ret = i2d_PKCS8_PRIV_KEY_INFO(p8,pp);
+ PKCS8_PRIV_KEY_INFO_free(p8);
+ return ret;
+ }
+ OPENSSL_PUT_ERROR(X509, i2d_PrivateKey, ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
+ return -1;
+ }
+
diff --git a/crypto/x509/pkcs7.c b/crypto/x509/pkcs7.c
new file mode 100644
index 0000000..8bbb393
--- /dev/null
+++ b/crypto/x509/pkcs7.c
@@ -0,0 +1,97 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/x509.h>
+
+#include <openssl/bytestring.h>
+#include <openssl/err.h>
+#include <openssl/obj.h>
+#include <openssl/stack.h>
+
+
+int PKCS7_get_certificates(STACK_OF(X509) *out_certs, CBS *cbs) {
+ /* See https://tools.ietf.org/html/rfc2315#section-9.1 */
+ CBS content_info, content_type, wrapped_signed_data, signed_data,
+ version_bytes, certificates;
+ int nid;
+ const size_t initial_certs_len = sk_X509_num(out_certs);
+
+ if (!CBS_get_asn1_ber(cbs, &content_info, CBS_ASN1_SEQUENCE) ||
+ !CBS_get_asn1(&content_info, &content_type, CBS_ASN1_OBJECT)) {
+ return 0;
+ }
+
+ nid = OBJ_cbs2nid(&content_type);
+ if (nid != NID_pkcs7_signed) {
+ OPENSSL_PUT_ERROR(X509, PKCS7_get_certificates,
+ X509_R_NOT_PKCS7_SIGNED_DATA);
+ return 0;
+ }
+
+ if (!CBS_get_asn1_ber(&content_info, &wrapped_signed_data,
+ CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
+ !CBS_get_asn1_ber(&wrapped_signed_data, &signed_data,
+ CBS_ASN1_SEQUENCE) ||
+ !CBS_get_asn1_ber(&signed_data, &version_bytes, CBS_ASN1_INTEGER) ||
+ !CBS_get_asn1_ber(&signed_data, NULL /* digests */, CBS_ASN1_SET) ||
+ !CBS_get_asn1_ber(&signed_data, NULL /* content */, CBS_ASN1_SEQUENCE)) {
+ return 0;
+ }
+
+ if (CBS_len(&version_bytes) < 1 || CBS_data(&version_bytes)[0] == 0) {
+ OPENSSL_PUT_ERROR(X509, PKCS7_get_certificates,
+ X509_R_BAD_PKCS7_VERSION);
+ return 0;
+ }
+
+ if (!CBS_get_asn1_ber(&signed_data, &certificates,
+ CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) {
+ OPENSSL_PUT_ERROR(X509, PKCS7_get_certificates,
+ X509_R_NO_CERTIFICATES_INCLUDED);
+ return 0;
+ }
+
+ while (CBS_len(&certificates) > 0) {
+ CBS cert;
+ X509 *x509;
+ const uint8_t *inp;
+
+ if (!CBS_get_asn1_element(&certificates, &cert, CBS_ASN1_SEQUENCE)) {
+ goto err;
+ }
+
+ inp = CBS_data(&cert);
+ x509 = d2i_X509(NULL, &inp, CBS_len(&cert));
+ if (!x509) {
+ goto err;
+ }
+
+ if (inp != CBS_data(&cert) + CBS_len(&cert)) {
+ /* This suggests a disconnect between the two ASN.1 parsers. */
+ goto err;
+ }
+
+ sk_X509_push(out_certs, x509);
+ }
+
+ return 1;
+
+err:
+ while (sk_X509_num(out_certs) != initial_certs_len) {
+ X509 *x509 = sk_X509_pop(out_certs);
+ X509_free(x509);
+ }
+
+ return 0;
+}
diff --git a/crypto/x509/t_crl.c b/crypto/x509/t_crl.c
new file mode 100644
index 0000000..f2b2ee2
--- /dev/null
+++ b/crypto/x509/t_crl.c
@@ -0,0 +1,130 @@
+/* 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/asn1.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+
+#ifndef OPENSSL_NO_FP_API
+int X509_CRL_print_fp(FILE *fp, X509_CRL *x)
+ {
+ BIO *b;
+ int ret;
+
+ if ((b=BIO_new(BIO_s_file())) == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_CRL_print_fp, ERR_R_BUF_LIB);
+ return(0);
+ }
+ BIO_set_fp(b,fp,BIO_NOCLOSE);
+ ret=X509_CRL_print(b, x);
+ BIO_free(b);
+ return(ret);
+ }
+#endif
+
+int X509_CRL_print(BIO *out, X509_CRL *x)
+{
+ STACK_OF(X509_REVOKED) *rev;
+ X509_REVOKED *r;
+ long l;
+ size_t i;
+ char *p;
+
+ BIO_printf(out, "Certificate Revocation List (CRL):\n");
+ l = X509_CRL_get_version(x);
+ BIO_printf(out, "%8sVersion %lu (0x%lx)\n", "", l+1, l);
+ i = OBJ_obj2nid(x->sig_alg->algorithm);
+ X509_signature_print(out, x->sig_alg, NULL);
+ p=X509_NAME_oneline(X509_CRL_get_issuer(x),NULL,0);
+ BIO_printf(out,"%8sIssuer: %s\n","",p);
+ OPENSSL_free(p);
+ BIO_printf(out,"%8sLast Update: ","");
+ ASN1_TIME_print(out,X509_CRL_get_lastUpdate(x));
+ BIO_printf(out,"\n%8sNext Update: ","");
+ if (X509_CRL_get_nextUpdate(x))
+ ASN1_TIME_print(out,X509_CRL_get_nextUpdate(x));
+ else BIO_printf(out,"NONE");
+ BIO_printf(out,"\n");
+
+ X509V3_extensions_print(out, "CRL extensions",
+ x->crl->extensions, 0, 8);
+
+ rev = X509_CRL_get_REVOKED(x);
+
+ if(sk_X509_REVOKED_num(rev) > 0)
+ BIO_printf(out, "Revoked Certificates:\n");
+ else BIO_printf(out, "No Revoked Certificates.\n");
+
+ for(i = 0; i < sk_X509_REVOKED_num(rev); i++) {
+ r = sk_X509_REVOKED_value(rev, i);
+ BIO_printf(out," Serial Number: ");
+ i2a_ASN1_INTEGER(out,r->serialNumber);
+ BIO_printf(out,"\n Revocation Date: ");
+ ASN1_TIME_print(out,r->revocationDate);
+ BIO_printf(out,"\n");
+ X509V3_extensions_print(out, "CRL entry extensions",
+ r->extensions, 0, 8);
+ }
+ X509_signature_print(out, x->sig_alg, x->signature);
+
+ return 1;
+
+}
diff --git a/crypto/x509/t_x509.c b/crypto/x509/t_x509.c
new file mode 100644
index 0000000..91d4ac7
--- /dev/null
+++ b/crypto/x509/t_x509.c
@@ -0,0 +1,516 @@
+/* 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/asn1.h>
+#include <openssl/bio.h>
+#include <openssl/digest.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#include "../evp/internal.h"
+
+#ifndef OPENSSL_NO_FP_API
+int X509_print_ex_fp(FILE *fp, X509 *x, unsigned long nmflag, unsigned long cflag)
+ {
+ BIO *b;
+ int ret;
+
+ if ((b=BIO_new(BIO_s_file())) == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_print_ex_fp, ERR_R_BUF_LIB);
+ return(0);
+ }
+ BIO_set_fp(b,fp,BIO_NOCLOSE);
+ ret=X509_print_ex(b, x, nmflag, cflag);
+ BIO_free(b);
+ return(ret);
+ }
+
+int X509_print_fp(FILE *fp, X509 *x)
+ {
+ return X509_print_ex_fp(fp, x, XN_FLAG_COMPAT, X509_FLAG_COMPAT);
+ }
+#endif
+
+int X509_print(BIO *bp, X509 *x)
+{
+ return X509_print_ex(bp, x, XN_FLAG_COMPAT, X509_FLAG_COMPAT);
+}
+
+int X509_print_ex(BIO *bp, X509 *x, unsigned long nmflags, unsigned long cflag)
+ {
+ long l;
+ int ret=0,i;
+ char *m=NULL,mlch = ' ';
+ int nmindent = 0;
+ X509_CINF *ci;
+ ASN1_INTEGER *bs;
+ EVP_PKEY *pkey=NULL;
+ const char *neg;
+
+ if((nmflags & XN_FLAG_SEP_MASK) == XN_FLAG_SEP_MULTILINE) {
+ mlch = '\n';
+ nmindent = 12;
+ }
+
+ if(nmflags == X509_FLAG_COMPAT)
+ nmindent = 16;
+
+ ci=x->cert_info;
+ if(!(cflag & X509_FLAG_NO_HEADER))
+ {
+ if (BIO_write(bp,"Certificate:\n",13) <= 0) goto err;
+ if (BIO_write(bp," Data:\n",10) <= 0) goto err;
+ }
+ if(!(cflag & X509_FLAG_NO_VERSION))
+ {
+ l=X509_get_version(x);
+ if (BIO_printf(bp,"%8sVersion: %lu (0x%lx)\n","",l+1,l) <= 0) goto err;
+ }
+ if(!(cflag & X509_FLAG_NO_SERIAL))
+ {
+
+ if (BIO_write(bp," Serial Number:",22) <= 0) goto err;
+
+ bs=X509_get_serialNumber(x);
+ if (bs->length <= (int)sizeof(long))
+ {
+ l=ASN1_INTEGER_get(bs);
+ if (bs->type == V_ASN1_NEG_INTEGER)
+ {
+ l= -l;
+ neg="-";
+ }
+ else
+ neg="";
+ if (BIO_printf(bp," %s%lu (%s0x%lx)\n",neg,l,neg,l) <= 0)
+ goto err;
+ }
+ else
+ {
+ neg=(bs->type == V_ASN1_NEG_INTEGER)?" (Negative)":"";
+ if (BIO_printf(bp,"\n%12s%s","",neg) <= 0) goto err;
+
+ for (i=0; i<bs->length; i++)
+ {
+ if (BIO_printf(bp,"%02x%c",bs->data[i],
+ ((i+1 == bs->length)?'\n':':')) <= 0)
+ goto err;
+ }
+ }
+
+ }
+
+ if(!(cflag & X509_FLAG_NO_SIGNAME))
+ {
+ if(X509_signature_print(bp, x->sig_alg, NULL) <= 0)
+ goto err;
+#if 0
+ if (BIO_printf(bp,"%8sSignature Algorithm: ","") <= 0)
+ goto err;
+ if (i2a_ASN1_OBJECT(bp, ci->signature->algorithm) <= 0)
+ goto err;
+ if (BIO_puts(bp, "\n") <= 0)
+ goto err;
+#endif
+ }
+
+ if(!(cflag & X509_FLAG_NO_ISSUER))
+ {
+ if (BIO_printf(bp," Issuer:%c",mlch) <= 0) goto err;
+ if (X509_NAME_print_ex(bp,X509_get_issuer_name(x),nmindent, nmflags) < 0) goto err;
+ if (BIO_write(bp,"\n",1) <= 0) goto err;
+ }
+ if(!(cflag & X509_FLAG_NO_VALIDITY))
+ {
+ if (BIO_write(bp," Validity\n",17) <= 0) goto err;
+ if (BIO_write(bp," Not Before: ",24) <= 0) goto err;
+ if (!ASN1_TIME_print(bp,X509_get_notBefore(x))) goto err;
+ if (BIO_write(bp,"\n Not After : ",25) <= 0) goto err;
+ if (!ASN1_TIME_print(bp,X509_get_notAfter(x))) goto err;
+ if (BIO_write(bp,"\n",1) <= 0) goto err;
+ }
+ if(!(cflag & X509_FLAG_NO_SUBJECT))
+ {
+ if (BIO_printf(bp," Subject:%c",mlch) <= 0) goto err;
+ if (X509_NAME_print_ex(bp,X509_get_subject_name(x),nmindent, nmflags) < 0) goto err;
+ if (BIO_write(bp,"\n",1) <= 0) goto err;
+ }
+ if(!(cflag & X509_FLAG_NO_PUBKEY))
+ {
+ if (BIO_write(bp," Subject Public Key Info:\n",33) <= 0)
+ goto err;
+ if (BIO_printf(bp,"%12sPublic Key Algorithm: ","") <= 0)
+ goto err;
+ if (i2a_ASN1_OBJECT(bp, ci->key->algor->algorithm) <= 0)
+ goto err;
+ if (BIO_puts(bp, "\n") <= 0)
+ goto err;
+
+ pkey=X509_get_pubkey(x);
+ if (pkey == NULL)
+ {
+ BIO_printf(bp,"%12sUnable to load Public Key\n","");
+ BIO_print_errors(bp);
+ }
+ else
+ {
+ EVP_PKEY_print_public(bp, pkey, 16, NULL);
+ EVP_PKEY_free(pkey);
+ }
+ }
+
+ if(!(cflag & X509_FLAG_NO_IDS))
+ {
+ if (ci->issuerUID)
+ {
+ if (BIO_printf(bp,"%8sIssuer Unique ID: ","") <= 0)
+ goto err;
+ if (!X509_signature_dump(bp, ci->issuerUID, 12))
+ goto err;
+ }
+ if (ci->subjectUID)
+ {
+ if (BIO_printf(bp,"%8sSubject Unique ID: ","") <= 0)
+ goto err;
+ if (!X509_signature_dump(bp, ci->subjectUID, 12))
+ goto err;
+ }
+ }
+
+ if (!(cflag & X509_FLAG_NO_EXTENSIONS))
+ X509V3_extensions_print(bp, "X509v3 extensions",
+ ci->extensions, cflag, 8);
+
+ if(!(cflag & X509_FLAG_NO_SIGDUMP))
+ {
+ if(X509_signature_print(bp, x->sig_alg, x->signature) <= 0) goto err;
+ }
+ if(!(cflag & X509_FLAG_NO_AUX))
+ {
+ if (!X509_CERT_AUX_print(bp, x->aux, 0)) goto err;
+ }
+ ret=1;
+err:
+ if (m != NULL) OPENSSL_free(m);
+ return(ret);
+ }
+
+int X509_ocspid_print (BIO *bp, X509 *x)
+ {
+ unsigned char *der=NULL ;
+ unsigned char *dertmp;
+ int derlen;
+ int i;
+ unsigned char SHA1md[SHA_DIGEST_LENGTH];
+
+ /* display the hash of the subject as it would appear
+ in OCSP requests */
+ if (BIO_printf(bp," Subject OCSP hash: ") <= 0)
+ goto err;
+ derlen = i2d_X509_NAME(x->cert_info->subject, NULL);
+ if ((der = dertmp = (unsigned char *)OPENSSL_malloc (derlen)) == NULL)
+ goto err;
+ i2d_X509_NAME(x->cert_info->subject, &dertmp);
+
+ if (!EVP_Digest(der, derlen, SHA1md, NULL, EVP_sha1(), NULL))
+ goto err;
+ for (i=0; i < SHA_DIGEST_LENGTH; i++)
+ {
+ if (BIO_printf(bp,"%02X",SHA1md[i]) <= 0) goto err;
+ }
+ OPENSSL_free (der);
+ der=NULL;
+
+ /* display the hash of the public key as it would appear
+ in OCSP requests */
+ if (BIO_printf(bp,"\n Public key OCSP hash: ") <= 0)
+ goto err;
+
+ if (!EVP_Digest(x->cert_info->key->public_key->data,
+ x->cert_info->key->public_key->length,
+ SHA1md, NULL, EVP_sha1(), NULL))
+ goto err;
+ for (i=0; i < SHA_DIGEST_LENGTH; i++)
+ {
+ if (BIO_printf(bp,"%02X",SHA1md[i]) <= 0)
+ goto err;
+ }
+ BIO_printf(bp,"\n");
+
+ return (1);
+err:
+ if (der != NULL) OPENSSL_free(der);
+ return(0);
+ }
+
+int X509_signature_print(BIO *bp, X509_ALGOR *sigalg, ASN1_STRING *sig)
+{
+ int sig_nid;
+ if (BIO_puts(bp," Signature Algorithm: ") <= 0) return 0;
+ if (i2a_ASN1_OBJECT(bp, sigalg->algorithm) <= 0) return 0;
+
+ sig_nid = OBJ_obj2nid(sigalg->algorithm);
+ if (sig_nid != NID_undef)
+ {
+ int pkey_nid, dig_nid;
+ const EVP_PKEY_ASN1_METHOD *ameth;
+ if (OBJ_find_sigid_algs(sig_nid, &dig_nid, &pkey_nid))
+ {
+ ameth = EVP_PKEY_asn1_find(NULL, pkey_nid);
+ if (ameth && ameth->sig_print)
+ return ameth->sig_print(bp, sigalg, sig, 9, 0);
+ }
+ }
+ if (sig)
+ return X509_signature_dump(bp, sig, 9);
+ else if (BIO_puts(bp, "\n") <= 0)
+ return 0;
+ return 1;
+}
+
+int ASN1_STRING_print(BIO *bp, const ASN1_STRING *v)
+ {
+ int i,n;
+ char buf[80];
+ const char *p;
+
+ if (v == NULL) return(0);
+ n=0;
+ p=(const char *)v->data;
+ for (i=0; i<v->length; i++)
+ {
+ if ((p[i] > '~') || ((p[i] < ' ') &&
+ (p[i] != '\n') && (p[i] != '\r')))
+ buf[n]='.';
+ else
+ buf[n]=p[i];
+ n++;
+ if (n >= 80)
+ {
+ if (BIO_write(bp,buf,n) <= 0)
+ return(0);
+ n=0;
+ }
+ }
+ if (n > 0)
+ if (BIO_write(bp,buf,n) <= 0)
+ return(0);
+ return(1);
+ }
+
+int ASN1_TIME_print(BIO *bp, const ASN1_TIME *tm)
+{
+ if(tm->type == V_ASN1_UTCTIME) return ASN1_UTCTIME_print(bp, tm);
+ if(tm->type == V_ASN1_GENERALIZEDTIME)
+ return ASN1_GENERALIZEDTIME_print(bp, tm);
+ BIO_write(bp,"Bad time value",14);
+ return(0);
+}
+
+static const char *mon[12]=
+ {
+ "Jan","Feb","Mar","Apr","May","Jun",
+ "Jul","Aug","Sep","Oct","Nov","Dec"
+ };
+
+int ASN1_GENERALIZEDTIME_print(BIO *bp, const ASN1_GENERALIZEDTIME *tm)
+ {
+ char *v;
+ int gmt=0;
+ int i;
+ int y=0,M=0,d=0,h=0,m=0,s=0;
+ char *f = NULL;
+ int f_len = 0;
+
+ i=tm->length;
+ v=(char *)tm->data;
+
+ if (i < 12) goto err;
+ if (v[i-1] == 'Z') gmt=1;
+ for (i=0; i<12; i++)
+ if ((v[i] > '9') || (v[i] < '0')) goto err;
+ y= (v[0]-'0')*1000+(v[1]-'0')*100 + (v[2]-'0')*10+(v[3]-'0');
+ M= (v[4]-'0')*10+(v[5]-'0');
+ if ((M > 12) || (M < 1)) goto err;
+ d= (v[6]-'0')*10+(v[7]-'0');
+ h= (v[8]-'0')*10+(v[9]-'0');
+ m= (v[10]-'0')*10+(v[11]-'0');
+ if (tm->length >= 14 &&
+ (v[12] >= '0') && (v[12] <= '9') &&
+ (v[13] >= '0') && (v[13] <= '9'))
+ {
+ s= (v[12]-'0')*10+(v[13]-'0');
+ /* Check for fractions of seconds. */
+ if (tm->length >= 15 && v[14] == '.')
+ {
+ int l = tm->length;
+ f = &v[14]; /* The decimal point. */
+ f_len = 1;
+ while (14 + f_len < l && f[f_len] >= '0' && f[f_len] <= '9')
+ ++f_len;
+ }
+ }
+
+ if (BIO_printf(bp,"%s %2d %02d:%02d:%02d%.*s %d%s",
+ mon[M-1],d,h,m,s,f_len,f,y,(gmt)?" GMT":"") <= 0)
+ return(0);
+ else
+ return(1);
+err:
+ BIO_write(bp,"Bad time value",14);
+ return(0);
+ }
+
+int ASN1_UTCTIME_print(BIO *bp, const ASN1_UTCTIME *tm)
+ {
+ const char *v;
+ int gmt=0;
+ int i;
+ int y=0,M=0,d=0,h=0,m=0,s=0;
+
+ i=tm->length;
+ v=(const char *)tm->data;
+
+ if (i < 10) goto err;
+ if (v[i-1] == 'Z') gmt=1;
+ for (i=0; i<10; i++)
+ if ((v[i] > '9') || (v[i] < '0')) goto err;
+ y= (v[0]-'0')*10+(v[1]-'0');
+ if (y < 50) y+=100;
+ M= (v[2]-'0')*10+(v[3]-'0');
+ if ((M > 12) || (M < 1)) goto err;
+ d= (v[4]-'0')*10+(v[5]-'0');
+ h= (v[6]-'0')*10+(v[7]-'0');
+ m= (v[8]-'0')*10+(v[9]-'0');
+ if (tm->length >=12 &&
+ (v[10] >= '0') && (v[10] <= '9') &&
+ (v[11] >= '0') && (v[11] <= '9'))
+ s= (v[10]-'0')*10+(v[11]-'0');
+
+ if (BIO_printf(bp,"%s %2d %02d:%02d:%02d %d%s",
+ mon[M-1],d,h,m,s,y+1900,(gmt)?" GMT":"") <= 0)
+ return(0);
+ else
+ return(1);
+err:
+ BIO_write(bp,"Bad time value",14);
+ return(0);
+ }
+
+int X509_NAME_print(BIO *bp, X509_NAME *name, int obase)
+ {
+ char *s,*c,*b;
+ int ret=0,l,i;
+
+ l=80-2-obase;
+
+ b=X509_NAME_oneline(name,NULL,0);
+ if (!*b)
+ {
+ OPENSSL_free(b);
+ return 1;
+ }
+ s=b+1; /* skip the first slash */
+
+ c=s;
+ for (;;)
+ {
+#ifndef CHARSET_EBCDIC
+ if ( ((*s == '/') &&
+ ((s[1] >= 'A') && (s[1] <= 'Z') && (
+ (s[2] == '=') ||
+ ((s[2] >= 'A') && (s[2] <= 'Z') &&
+ (s[3] == '='))
+ ))) ||
+ (*s == '\0'))
+#else
+ if ( ((*s == '/') &&
+ (isupper(s[1]) && (
+ (s[2] == '=') ||
+ (isupper(s[2]) &&
+ (s[3] == '='))
+ ))) ||
+ (*s == '\0'))
+#endif
+ {
+ i=s-c;
+ if (BIO_write(bp,c,i) != i) goto err;
+ c=s+1; /* skip following slash */
+ if (*s != '\0')
+ {
+ if (BIO_write(bp,", ",2) != 2) goto err;
+ }
+ l--;
+ }
+ if (*s == '\0') break;
+ s++;
+ l--;
+ }
+
+ ret=1;
+ if (0)
+ {
+err:
+ OPENSSL_PUT_ERROR(X509, X509_NAME_print, ERR_R_BUF_LIB);
+ }
+ OPENSSL_free(b);
+ return(ret);
+ }
diff --git a/crypto/x509/t_x509a.c b/crypto/x509/t_x509a.c
new file mode 100644
index 0000000..7667268
--- /dev/null
+++ b/crypto/x509/t_x509a.c
@@ -0,0 +1,109 @@
+/* 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/asn1.h>
+#include <openssl/bio.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509.h>
+
+
+/* X509_CERT_AUX and string set routines */
+
+int X509_CERT_AUX_print(BIO *out, X509_CERT_AUX *aux, int indent)
+{
+ char oidstr[80], first;
+ size_t i;
+ int j;
+ if(!aux) return 1;
+ if(aux->trust) {
+ first = 1;
+ BIO_printf(out, "%*sTrusted Uses:\n%*s",
+ indent, "", indent + 2, "");
+ for(i = 0; i < sk_ASN1_OBJECT_num(aux->trust); i++) {
+ if(!first) BIO_puts(out, ", ");
+ else first = 0;
+ OBJ_obj2txt(oidstr, sizeof oidstr,
+ sk_ASN1_OBJECT_value(aux->trust, i), 0);
+ BIO_puts(out, oidstr);
+ }
+ BIO_puts(out, "\n");
+ } else BIO_printf(out, "%*sNo Trusted Uses.\n", indent, "");
+ if(aux->reject) {
+ first = 1;
+ BIO_printf(out, "%*sRejected Uses:\n%*s",
+ indent, "", indent + 2, "");
+ for(i = 0; i < sk_ASN1_OBJECT_num(aux->reject); i++) {
+ if(!first) BIO_puts(out, ", ");
+ else first = 0;
+ OBJ_obj2txt(oidstr, sizeof oidstr,
+ sk_ASN1_OBJECT_value(aux->reject, i), 0);
+ BIO_puts(out, oidstr);
+ }
+ BIO_puts(out, "\n");
+ } else BIO_printf(out, "%*sNo Rejected Uses.\n", indent, "");
+ if(aux->alias) BIO_printf(out, "%*sAlias: %s\n", indent, "",
+ aux->alias->data);
+ if(aux->keyid) {
+ BIO_printf(out, "%*sKey Id: ", indent, "");
+ for(j = 0; j < aux->keyid->length; j++)
+ BIO_printf(out, "%s%02X",
+ j ? ":" : "",
+ aux->keyid->data[j]);
+ BIO_write(out,"\n",1);
+ }
+ return 1;
+}
diff --git a/crypto/x509/vpm_int.h b/crypto/x509/vpm_int.h
new file mode 100644
index 0000000..af99821
--- /dev/null
+++ b/crypto/x509/vpm_int.h
@@ -0,0 +1,69 @@
+/* vpm_int.h */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2013.
+ */
+/* ====================================================================
+ * Copyright (c) 2013 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).
+ *
+ */
+
+/* internal only structure to hold additional X509_VERIFY_PARAM data */
+
+struct X509_VERIFY_PARAM_ID_st
+ {
+ unsigned char *host; /* If not NULL hostname to match */
+ size_t hostlen;
+ unsigned char *email; /* If not NULL email address to match */
+ size_t emaillen;
+ unsigned char *ip; /* If not NULL IP address to match */
+ size_t iplen; /* Length of IP address */
+ };
diff --git a/crypto/x509/x509.c b/crypto/x509/x509.c
new file mode 100644
index 0000000..31f9e1e
--- /dev/null
+++ b/crypto/x509/x509.c
@@ -0,0 +1,152 @@
+/* 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/x509.h>
+
+#include <openssl/bio.h>
+#include <openssl/mem.h>
+
+
+int PKCS8_pkey_set0(PKCS8_PRIV_KEY_INFO *priv, ASN1_OBJECT *aobj, int version,
+ int ptype, void *pval, uint8_t *penc, int penclen) {
+ uint8_t **ppenc = NULL;
+ if (version >= 0) {
+ if (!ASN1_INTEGER_set(priv->version, version)) {
+ return 0;
+ }
+ }
+
+ if (penc) {
+ int pmtype;
+ ASN1_OCTET_STRING *oct;
+
+ oct = ASN1_OCTET_STRING_new();
+ if (!oct) {
+ return 0;
+ }
+ oct->data = penc;
+ ppenc = &oct->data;
+ oct->length = penclen;
+ if (priv->broken == PKCS8_NO_OCTET) {
+ pmtype = V_ASN1_SEQUENCE;
+ } else {
+ pmtype = V_ASN1_OCTET_STRING;
+ }
+ ASN1_TYPE_set(priv->pkey, pmtype, oct);
+ }
+
+ if (!X509_ALGOR_set0(priv->pkeyalg, aobj, ptype, pval)) {
+ /* If call fails do not swallow 'enc' */
+ if (ppenc) {
+ *ppenc = NULL;
+ }
+ return 0;
+ }
+
+ return 1;
+}
+
+int PKCS8_pkey_get0(ASN1_OBJECT **ppkalg, const uint8_t **pk, int *ppklen,
+ X509_ALGOR **pa, PKCS8_PRIV_KEY_INFO *p8) {
+ if (ppkalg) {
+ *ppkalg = p8->pkeyalg->algorithm;
+ }
+
+ if (p8->pkey->type == V_ASN1_OCTET_STRING) {
+ p8->broken = PKCS8_OK;
+ if (pk) {
+ *pk = p8->pkey->value.octet_string->data;
+ *ppklen = p8->pkey->value.octet_string->length;
+ }
+ } else if (p8->pkey->type == V_ASN1_SEQUENCE) {
+ p8->broken = PKCS8_NO_OCTET;
+ if (pk) {
+ *pk = p8->pkey->value.sequence->data;
+ *ppklen = p8->pkey->value.sequence->length;
+ }
+ } else {
+ return 0;
+ }
+
+ if (pa) {
+ *pa = p8->pkeyalg;
+ }
+ return 1;
+}
+
+int X509_signature_dump(BIO *bp, const ASN1_STRING *sig, int indent) {
+ const uint8_t *s;
+ int i, n;
+
+ n = sig->length;
+ s = sig->data;
+ for (i = 0; i < n; i++) {
+ if ((i % 18) == 0) {
+ if (BIO_write(bp, "\n", 1) <= 0 ||
+ BIO_indent(bp, indent, indent) <= 0) {
+ return 0;
+ }
+ }
+ if (BIO_printf(bp, "%02x%s", s[i], ((i + 1) == n) ? "" : ":") <= 0) {
+ return 0;
+ }
+ }
+ if (BIO_write(bp, "\n", 1) != 1) {
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/crypto/x509/x509.h b/crypto/x509/x509.h
new file mode 100644
index 0000000..c4e742e
--- /dev/null
+++ b/crypto/x509/x509.h
@@ -0,0 +1,1332 @@
+/* crypto/x509/x509.h */
+/* 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.]
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECDH support in OpenSSL originally developed by
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
+
+#ifndef HEADER_X509_H
+#define HEADER_X509_H
+
+#include <openssl/base.h>
+
+#include <time.h>
+
+#include <openssl/asn1.h>
+#include <openssl/bio.h>
+#include <openssl/cipher.h>
+#include <openssl/dh.h>
+#include <openssl/dsa.h>
+#include <openssl/ec.h>
+#include <openssl/ecdh.h>
+#include <openssl/ecdsa.h>
+#include <openssl/evp.h>
+#include <openssl/rsa.h>
+#include <openssl/sha.h>
+#include <openssl/stack.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef OPENSSL_SYS_WIN32
+/* Under Win32 these are defined in wincrypt.h */
+#undef X509_NAME
+#undef X509_CERT_PAIR
+#undef X509_EXTENSIONS
+#endif
+
+#define X509_FILETYPE_PEM 1
+#define X509_FILETYPE_ASN1 2
+#define X509_FILETYPE_DEFAULT 3
+
+#define X509v3_KU_DIGITAL_SIGNATURE 0x0080
+#define X509v3_KU_NON_REPUDIATION 0x0040
+#define X509v3_KU_KEY_ENCIPHERMENT 0x0020
+#define X509v3_KU_DATA_ENCIPHERMENT 0x0010
+#define X509v3_KU_KEY_AGREEMENT 0x0008
+#define X509v3_KU_KEY_CERT_SIGN 0x0004
+#define X509v3_KU_CRL_SIGN 0x0002
+#define X509v3_KU_ENCIPHER_ONLY 0x0001
+#define X509v3_KU_DECIPHER_ONLY 0x8000
+#define X509v3_KU_UNDEF 0xffff
+
+typedef struct X509_objects_st
+ {
+ int nid;
+ int (*a2i)(void);
+ int (*i2a)(void);
+ } X509_OBJECTS;
+
+DECLARE_ASN1_SET_OF(X509_ALGOR)
+
+typedef STACK_OF(X509_ALGOR) X509_ALGORS;
+
+typedef struct X509_val_st
+ {
+ ASN1_TIME *notBefore;
+ ASN1_TIME *notAfter;
+ } X509_VAL;
+
+struct X509_pubkey_st
+ {
+ X509_ALGOR *algor;
+ ASN1_BIT_STRING *public_key;
+ EVP_PKEY *pkey;
+ };
+
+typedef struct X509_sig_st
+ {
+ X509_ALGOR *algor;
+ ASN1_OCTET_STRING *digest;
+ } X509_SIG;
+
+typedef struct X509_name_entry_st
+ {
+ ASN1_OBJECT *object;
+ ASN1_STRING *value;
+ int set;
+ int size; /* temp variable */
+ } X509_NAME_ENTRY;
+
+DECLARE_STACK_OF(X509_NAME_ENTRY)
+DECLARE_ASN1_SET_OF(X509_NAME_ENTRY)
+
+/* we always keep X509_NAMEs in 2 forms. */
+struct X509_name_st
+ {
+ STACK_OF(X509_NAME_ENTRY) *entries;
+ int modified; /* true if 'bytes' needs to be built */
+#ifndef OPENSSL_NO_BUFFER
+ BUF_MEM *bytes;
+#else
+ char *bytes;
+#endif
+/* unsigned long hash; Keep the hash around for lookups */
+ unsigned char *canon_enc;
+ int canon_enclen;
+ } /* X509_NAME */;
+
+DECLARE_STACK_OF(X509_NAME)
+
+#define X509_EX_V_NETSCAPE_HACK 0x8000
+#define X509_EX_V_INIT 0x0001
+typedef struct X509_extension_st
+ {
+ ASN1_OBJECT *object;
+ ASN1_BOOLEAN critical;
+ ASN1_OCTET_STRING *value;
+ } X509_EXTENSION;
+
+typedef STACK_OF(X509_EXTENSION) X509_EXTENSIONS;
+
+DECLARE_STACK_OF(X509_EXTENSION)
+DECLARE_ASN1_SET_OF(X509_EXTENSION)
+
+/* a sequence of these are used */
+typedef struct x509_attributes_st
+ {
+ ASN1_OBJECT *object;
+ int single; /* 0 for a set, 1 for a single item (which is wrong) */
+ union {
+ char *ptr;
+/* 0 */ STACK_OF(ASN1_TYPE) *set;
+/* 1 */ ASN1_TYPE *single;
+ } value;
+ } X509_ATTRIBUTE;
+
+DECLARE_STACK_OF(X509_ATTRIBUTE)
+DECLARE_ASN1_SET_OF(X509_ATTRIBUTE)
+
+
+typedef struct X509_req_info_st
+ {
+ ASN1_ENCODING enc;
+ ASN1_INTEGER *version;
+ X509_NAME *subject;
+ X509_PUBKEY *pubkey;
+ /* d=2 hl=2 l= 0 cons: cont: 00 */
+ STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */
+ } X509_REQ_INFO;
+
+typedef struct X509_req_st
+ {
+ X509_REQ_INFO *req_info;
+ X509_ALGOR *sig_alg;
+ ASN1_BIT_STRING *signature;
+ int references;
+ } X509_REQ;
+
+typedef struct x509_cinf_st
+ {
+ ASN1_INTEGER *version; /* [ 0 ] default of v1 */
+ ASN1_INTEGER *serialNumber;
+ X509_ALGOR *signature;
+ X509_NAME *issuer;
+ X509_VAL *validity;
+ X509_NAME *subject;
+ X509_PUBKEY *key;
+ ASN1_BIT_STRING *issuerUID; /* [ 1 ] optional in v2 */
+ ASN1_BIT_STRING *subjectUID; /* [ 2 ] optional in v2 */
+ STACK_OF(X509_EXTENSION) *extensions; /* [ 3 ] optional in v3 */
+ ASN1_ENCODING enc;
+ } X509_CINF;
+
+/* This stuff is certificate "auxiliary info"
+ * it contains details which are useful in certificate
+ * stores and databases. When used this is tagged onto
+ * the end of the certificate itself
+ */
+
+typedef struct x509_cert_aux_st
+ {
+ STACK_OF(ASN1_OBJECT) *trust; /* trusted uses */
+ STACK_OF(ASN1_OBJECT) *reject; /* rejected uses */
+ ASN1_UTF8STRING *alias; /* "friendly name" */
+ ASN1_OCTET_STRING *keyid; /* key id of private key */
+ STACK_OF(X509_ALGOR) *other; /* other unspecified info */
+ } X509_CERT_AUX;
+
+struct x509_st
+ {
+ X509_CINF *cert_info;
+ X509_ALGOR *sig_alg;
+ ASN1_BIT_STRING *signature;
+ int valid;
+ int references;
+ char *name;
+ CRYPTO_EX_DATA ex_data;
+ /* These contain copies of various extension values */
+ long ex_pathlen;
+ long ex_pcpathlen;
+ unsigned long ex_flags;
+ unsigned long ex_kusage;
+ unsigned long ex_xkusage;
+ unsigned long ex_nscert;
+ ASN1_OCTET_STRING *skid;
+ AUTHORITY_KEYID *akid;
+ X509_POLICY_CACHE *policy_cache;
+ STACK_OF(DIST_POINT) *crldp;
+ STACK_OF(GENERAL_NAME) *altname;
+ NAME_CONSTRAINTS *nc;
+#ifndef OPENSSL_NO_SHA
+ unsigned char sha1_hash[SHA_DIGEST_LENGTH];
+#endif
+ X509_CERT_AUX *aux;
+ } /* X509 */;
+
+DECLARE_STACK_OF(X509)
+DECLARE_ASN1_SET_OF(X509)
+
+/* This is used for a table of trust checking functions */
+
+typedef struct x509_trust_st {
+ int trust;
+ int flags;
+ int (*check_trust)(struct x509_trust_st *, X509 *, int);
+ char *name;
+ int arg1;
+ void *arg2;
+} X509_TRUST;
+
+DECLARE_STACK_OF(X509_TRUST)
+
+typedef struct x509_cert_pair_st {
+ X509 *forward;
+ X509 *reverse;
+} X509_CERT_PAIR;
+
+/* standard trust ids */
+
+#define X509_TRUST_DEFAULT -1 /* Only valid in purpose settings */
+
+#define X509_TRUST_COMPAT 1
+#define X509_TRUST_SSL_CLIENT 2
+#define X509_TRUST_SSL_SERVER 3
+#define X509_TRUST_EMAIL 4
+#define X509_TRUST_OBJECT_SIGN 5
+#define X509_TRUST_OCSP_SIGN 6
+#define X509_TRUST_OCSP_REQUEST 7
+#define X509_TRUST_TSA 8
+
+/* Keep these up to date! */
+#define X509_TRUST_MIN 1
+#define X509_TRUST_MAX 8
+
+
+/* trust_flags values */
+#define X509_TRUST_DYNAMIC 1
+#define X509_TRUST_DYNAMIC_NAME 2
+
+/* check_trust return codes */
+
+#define X509_TRUST_TRUSTED 1
+#define X509_TRUST_REJECTED 2
+#define X509_TRUST_UNTRUSTED 3
+
+/* Flags for X509_print_ex() */
+
+#define X509_FLAG_COMPAT 0
+#define X509_FLAG_NO_HEADER 1L
+#define X509_FLAG_NO_VERSION (1L << 1)
+#define X509_FLAG_NO_SERIAL (1L << 2)
+#define X509_FLAG_NO_SIGNAME (1L << 3)
+#define X509_FLAG_NO_ISSUER (1L << 4)
+#define X509_FLAG_NO_VALIDITY (1L << 5)
+#define X509_FLAG_NO_SUBJECT (1L << 6)
+#define X509_FLAG_NO_PUBKEY (1L << 7)
+#define X509_FLAG_NO_EXTENSIONS (1L << 8)
+#define X509_FLAG_NO_SIGDUMP (1L << 9)
+#define X509_FLAG_NO_AUX (1L << 10)
+#define X509_FLAG_NO_ATTRIBUTES (1L << 11)
+#define X509_FLAG_NO_IDS (1L << 12)
+
+/* Flags specific to X509_NAME_print_ex() */
+
+/* The field separator information */
+
+#define XN_FLAG_SEP_MASK (0xf << 16)
+
+#define XN_FLAG_COMPAT 0 /* Traditional SSLeay: use old X509_NAME_print */
+#define XN_FLAG_SEP_COMMA_PLUS (1 << 16) /* RFC2253 ,+ */
+#define XN_FLAG_SEP_CPLUS_SPC (2 << 16) /* ,+ spaced: more readable */
+#define XN_FLAG_SEP_SPLUS_SPC (3 << 16) /* ;+ spaced */
+#define XN_FLAG_SEP_MULTILINE (4 << 16) /* One line per field */
+
+#define XN_FLAG_DN_REV (1 << 20) /* Reverse DN order */
+
+/* How the field name is shown */
+
+#define XN_FLAG_FN_MASK (0x3 << 21)
+
+#define XN_FLAG_FN_SN 0 /* Object short name */
+#define XN_FLAG_FN_LN (1 << 21) /* Object long name */
+#define XN_FLAG_FN_OID (2 << 21) /* Always use OIDs */
+#define XN_FLAG_FN_NONE (3 << 21) /* No field names */
+
+#define XN_FLAG_SPC_EQ (1 << 23) /* Put spaces round '=' */
+
+/* This determines if we dump fields we don't recognise:
+ * RFC2253 requires this.
+ */
+
+#define XN_FLAG_DUMP_UNKNOWN_FIELDS (1 << 24)
+
+#define XN_FLAG_FN_ALIGN (1 << 25) /* Align field names to 20 characters */
+
+/* Complete set of RFC2253 flags */
+
+#define XN_FLAG_RFC2253 (ASN1_STRFLGS_RFC2253 | \
+ XN_FLAG_SEP_COMMA_PLUS | \
+ XN_FLAG_DN_REV | \
+ XN_FLAG_FN_SN | \
+ XN_FLAG_DUMP_UNKNOWN_FIELDS)
+
+/* readable oneline form */
+
+#define XN_FLAG_ONELINE (ASN1_STRFLGS_RFC2253 | \
+ ASN1_STRFLGS_ESC_QUOTE | \
+ XN_FLAG_SEP_CPLUS_SPC | \
+ XN_FLAG_SPC_EQ | \
+ XN_FLAG_FN_SN)
+
+/* readable multiline form */
+
+#define XN_FLAG_MULTILINE (ASN1_STRFLGS_ESC_CTRL | \
+ ASN1_STRFLGS_ESC_MSB | \
+ XN_FLAG_SEP_MULTILINE | \
+ XN_FLAG_SPC_EQ | \
+ XN_FLAG_FN_LN | \
+ XN_FLAG_FN_ALIGN)
+
+struct x509_revoked_st
+ {
+ ASN1_INTEGER *serialNumber;
+ ASN1_TIME *revocationDate;
+ STACK_OF(X509_EXTENSION) /* optional */ *extensions;
+ /* Set up if indirect CRL */
+ STACK_OF(GENERAL_NAME) *issuer;
+ /* Revocation reason */
+ int reason;
+ int sequence; /* load sequence */
+ };
+
+DECLARE_STACK_OF(X509_REVOKED)
+DECLARE_ASN1_SET_OF(X509_REVOKED)
+
+typedef struct X509_crl_info_st
+ {
+ ASN1_INTEGER *version;
+ X509_ALGOR *sig_alg;
+ X509_NAME *issuer;
+ ASN1_TIME *lastUpdate;
+ ASN1_TIME *nextUpdate;
+ STACK_OF(X509_REVOKED) *revoked;
+ STACK_OF(X509_EXTENSION) /* [0] */ *extensions;
+ ASN1_ENCODING enc;
+ } X509_CRL_INFO;
+
+struct X509_crl_st
+ {
+ /* actual signature */
+ X509_CRL_INFO *crl;
+ X509_ALGOR *sig_alg;
+ ASN1_BIT_STRING *signature;
+ int references;
+ int flags;
+ /* Copies of various extensions */
+ AUTHORITY_KEYID *akid;
+ ISSUING_DIST_POINT *idp;
+ /* Convenient breakdown of IDP */
+ int idp_flags;
+ int idp_reasons;
+ /* CRL and base CRL numbers for delta processing */
+ ASN1_INTEGER *crl_number;
+ ASN1_INTEGER *base_crl_number;
+#ifndef OPENSSL_NO_SHA
+ unsigned char sha1_hash[SHA_DIGEST_LENGTH];
+#endif
+ STACK_OF(GENERAL_NAMES) *issuers;
+ const X509_CRL_METHOD *meth;
+ void *meth_data;
+ } /* X509_CRL */;
+
+DECLARE_STACK_OF(X509_CRL)
+DECLARE_ASN1_SET_OF(X509_CRL)
+
+typedef struct private_key_st
+ {
+ int version;
+ /* The PKCS#8 data types */
+ X509_ALGOR *enc_algor;
+ ASN1_OCTET_STRING *enc_pkey; /* encrypted pub key */
+
+ /* When decrypted, the following will not be NULL */
+ EVP_PKEY *dec_pkey;
+
+ /* used to encrypt and decrypt */
+ int key_length;
+ char *key_data;
+ int key_free; /* true if we should auto free key_data */
+
+ /* expanded version of 'enc_algor' */
+ EVP_CIPHER_INFO cipher;
+
+ int references;
+ } X509_PKEY;
+
+#ifndef OPENSSL_NO_EVP
+typedef struct X509_info_st
+ {
+ X509 *x509;
+ X509_CRL *crl;
+ X509_PKEY *x_pkey;
+
+ EVP_CIPHER_INFO enc_cipher;
+ int enc_len;
+ char *enc_data;
+
+ int references;
+ } X509_INFO;
+
+DECLARE_STACK_OF(X509_INFO)
+#endif
+
+/* The next 2 structures and their 8 routines were sent to me by
+ * Pat Richard <patr@x509.com> and are used to manipulate
+ * Netscapes spki structures - useful if you are writing a CA web page
+ */
+typedef struct Netscape_spkac_st
+ {
+ X509_PUBKEY *pubkey;
+ ASN1_IA5STRING *challenge; /* challenge sent in atlas >= PR2 */
+ } NETSCAPE_SPKAC;
+
+typedef struct Netscape_spki_st
+ {
+ NETSCAPE_SPKAC *spkac; /* signed public key and challenge */
+ X509_ALGOR *sig_algor;
+ ASN1_BIT_STRING *signature;
+ } NETSCAPE_SPKI;
+
+/* Netscape certificate sequence structure */
+typedef struct Netscape_certificate_sequence
+ {
+ ASN1_OBJECT *type;
+ STACK_OF(X509) *certs;
+ } NETSCAPE_CERT_SEQUENCE;
+
+/* Unused (and iv length is wrong)
+typedef struct CBCParameter_st
+ {
+ unsigned char iv[8];
+ } CBC_PARAM;
+*/
+
+/* Password based encryption structure */
+
+typedef struct PBEPARAM_st {
+ASN1_OCTET_STRING *salt;
+ASN1_INTEGER *iter;
+} PBEPARAM;
+
+/* Password based encryption V2 structures */
+
+typedef struct PBE2PARAM_st {
+X509_ALGOR *keyfunc;
+X509_ALGOR *encryption;
+} PBE2PARAM;
+
+typedef struct PBKDF2PARAM_st {
+ASN1_TYPE *salt; /* Usually OCTET STRING but could be anything */
+ASN1_INTEGER *iter;
+ASN1_INTEGER *keylength;
+X509_ALGOR *prf;
+} PBKDF2PARAM;
+
+
+/* PKCS#8 private key info structure */
+
+struct pkcs8_priv_key_info_st
+ {
+ int broken; /* Flag for various broken formats */
+#define PKCS8_OK 0
+#define PKCS8_NO_OCTET 1
+#define PKCS8_EMBEDDED_PARAM 2
+#define PKCS8_NS_DB 3
+#define PKCS8_NEG_PRIVKEY 4
+ ASN1_INTEGER *version;
+ X509_ALGOR *pkeyalg;
+ ASN1_TYPE *pkey; /* Should be OCTET STRING but some are broken */
+ STACK_OF(X509_ATTRIBUTE) *attributes;
+ };
+
+#ifdef __cplusplus
+}
+#endif
+
+#include <openssl/x509_vfy.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define X509_EXT_PACK_UNKNOWN 1
+#define X509_EXT_PACK_STRING 2
+
+#define X509_get_version(x) ASN1_INTEGER_get((x)->cert_info->version)
+/* #define X509_get_serialNumber(x) ((x)->cert_info->serialNumber) */
+#define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore)
+#define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter)
+#define X509_extract_key(x) X509_get_pubkey(x) /*****/
+#define X509_REQ_get_version(x) ASN1_INTEGER_get((x)->req_info->version)
+#define X509_REQ_get_subject_name(x) ((x)->req_info->subject)
+#define X509_REQ_extract_key(a) X509_REQ_get_pubkey(a)
+#define X509_name_cmp(a,b) X509_NAME_cmp((a),(b))
+#define X509_get_signature_type(x) EVP_PKEY_type(OBJ_obj2nid((x)->sig_alg->algorithm))
+
+#define X509_CRL_get_version(x) ASN1_INTEGER_get((x)->crl->version)
+#define X509_CRL_get_lastUpdate(x) ((x)->crl->lastUpdate)
+#define X509_CRL_get_nextUpdate(x) ((x)->crl->nextUpdate)
+#define X509_CRL_get_issuer(x) ((x)->crl->issuer)
+#define X509_CRL_get_REVOKED(x) ((x)->crl->revoked)
+
+void X509_CRL_set_default_method(const X509_CRL_METHOD *meth);
+X509_CRL_METHOD *X509_CRL_METHOD_new(
+ int (*crl_init)(X509_CRL *crl),
+ int (*crl_free)(X509_CRL *crl),
+ int (*crl_lookup)(X509_CRL *crl, X509_REVOKED **ret,
+ ASN1_INTEGER *ser, X509_NAME *issuer),
+ int (*crl_verify)(X509_CRL *crl, EVP_PKEY *pk));
+void X509_CRL_METHOD_free(X509_CRL_METHOD *m);
+
+void X509_CRL_set_meth_data(X509_CRL *crl, void *dat);
+void *X509_CRL_get_meth_data(X509_CRL *crl);
+
+/* This one is only used so that a binary form can output, as in
+ * i2d_X509_NAME(X509_get_X509_PUBKEY(x),&buf) */
+#define X509_get_X509_PUBKEY(x) ((x)->cert_info->key)
+
+
+const char *X509_verify_cert_error_string(long n);
+
+#ifndef OPENSSL_NO_EVP
+int X509_verify(X509 *a, EVP_PKEY *r);
+
+int X509_REQ_verify(X509_REQ *a, EVP_PKEY *r);
+int X509_CRL_verify(X509_CRL *a, EVP_PKEY *r);
+int NETSCAPE_SPKI_verify(NETSCAPE_SPKI *a, EVP_PKEY *r);
+
+NETSCAPE_SPKI * NETSCAPE_SPKI_b64_decode(const char *str, int len);
+char * NETSCAPE_SPKI_b64_encode(NETSCAPE_SPKI *x);
+EVP_PKEY *NETSCAPE_SPKI_get_pubkey(NETSCAPE_SPKI *x);
+int NETSCAPE_SPKI_set_pubkey(NETSCAPE_SPKI *x, EVP_PKEY *pkey);
+
+int NETSCAPE_SPKI_print(BIO *out, NETSCAPE_SPKI *spki);
+
+int X509_signature_dump(BIO *bp,const ASN1_STRING *sig, int indent);
+int X509_signature_print(BIO *bp,X509_ALGOR *alg, ASN1_STRING *sig);
+
+int X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md);
+int X509_sign_ctx(X509 *x, EVP_MD_CTX *ctx);
+/* int X509_http_nbio(OCSP_REQ_CTX *rctx, X509 **pcert); */
+int X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md);
+int X509_REQ_sign_ctx(X509_REQ *x, EVP_MD_CTX *ctx);
+int X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md);
+int X509_CRL_sign_ctx(X509_CRL *x, EVP_MD_CTX *ctx);
+/* int X509_CRL_http_nbio(OCSP_REQ_CTX *rctx, X509_CRL **pcrl); */
+int NETSCAPE_SPKI_sign(NETSCAPE_SPKI *x, EVP_PKEY *pkey, const EVP_MD *md);
+
+int X509_pubkey_digest(const X509 *data,const EVP_MD *type,
+ unsigned char *md, unsigned int *len);
+int X509_digest(const X509 *data,const EVP_MD *type,
+ unsigned char *md, unsigned int *len);
+int X509_CRL_digest(const X509_CRL *data,const EVP_MD *type,
+ unsigned char *md, unsigned int *len);
+int X509_REQ_digest(const X509_REQ *data,const EVP_MD *type,
+ unsigned char *md, unsigned int *len);
+int X509_NAME_digest(const X509_NAME *data,const EVP_MD *type,
+ unsigned char *md, unsigned int *len);
+#endif
+
+#ifndef OPENSSL_NO_FP_API
+X509 *d2i_X509_fp(FILE *fp, X509 **x509);
+int i2d_X509_fp(FILE *fp,X509 *x509);
+X509_CRL *d2i_X509_CRL_fp(FILE *fp,X509_CRL **crl);
+int i2d_X509_CRL_fp(FILE *fp,X509_CRL *crl);
+X509_REQ *d2i_X509_REQ_fp(FILE *fp,X509_REQ **req);
+int i2d_X509_REQ_fp(FILE *fp,X509_REQ *req);
+#ifndef OPENSSL_NO_RSA
+RSA *d2i_RSAPrivateKey_fp(FILE *fp,RSA **rsa);
+int i2d_RSAPrivateKey_fp(FILE *fp,RSA *rsa);
+RSA *d2i_RSAPublicKey_fp(FILE *fp,RSA **rsa);
+int i2d_RSAPublicKey_fp(FILE *fp,RSA *rsa);
+RSA *d2i_RSA_PUBKEY_fp(FILE *fp,RSA **rsa);
+int i2d_RSA_PUBKEY_fp(FILE *fp,RSA *rsa);
+#endif
+#ifndef OPENSSL_NO_DSA
+DSA *d2i_DSA_PUBKEY_fp(FILE *fp, DSA **dsa);
+int i2d_DSA_PUBKEY_fp(FILE *fp, DSA *dsa);
+DSA *d2i_DSAPrivateKey_fp(FILE *fp, DSA **dsa);
+int i2d_DSAPrivateKey_fp(FILE *fp, DSA *dsa);
+#endif
+#ifndef OPENSSL_NO_EC
+EC_KEY *d2i_EC_PUBKEY_fp(FILE *fp, EC_KEY **eckey);
+int i2d_EC_PUBKEY_fp(FILE *fp, EC_KEY *eckey);
+EC_KEY *d2i_ECPrivateKey_fp(FILE *fp, EC_KEY **eckey);
+int i2d_ECPrivateKey_fp(FILE *fp, EC_KEY *eckey);
+#endif
+X509_SIG *d2i_PKCS8_fp(FILE *fp,X509_SIG **p8);
+int i2d_PKCS8_fp(FILE *fp,X509_SIG *p8);
+PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_fp(FILE *fp,
+ PKCS8_PRIV_KEY_INFO **p8inf);
+int i2d_PKCS8_PRIV_KEY_INFO_fp(FILE *fp,PKCS8_PRIV_KEY_INFO *p8inf);
+int i2d_PKCS8PrivateKeyInfo_fp(FILE *fp, EVP_PKEY *key);
+int i2d_PrivateKey_fp(FILE *fp, EVP_PKEY *pkey);
+EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, EVP_PKEY **a);
+int i2d_PUBKEY_fp(FILE *fp, EVP_PKEY *pkey);
+EVP_PKEY *d2i_PUBKEY_fp(FILE *fp, EVP_PKEY **a);
+#endif
+
+#ifndef OPENSSL_NO_BIO
+X509 *d2i_X509_bio(BIO *bp,X509 **x509);
+int i2d_X509_bio(BIO *bp,X509 *x509);
+X509_CRL *d2i_X509_CRL_bio(BIO *bp,X509_CRL **crl);
+int i2d_X509_CRL_bio(BIO *bp,X509_CRL *crl);
+X509_REQ *d2i_X509_REQ_bio(BIO *bp,X509_REQ **req);
+int i2d_X509_REQ_bio(BIO *bp,X509_REQ *req);
+#ifndef OPENSSL_NO_RSA
+RSA *d2i_RSAPrivateKey_bio(BIO *bp,RSA **rsa);
+int i2d_RSAPrivateKey_bio(BIO *bp,RSA *rsa);
+RSA *d2i_RSAPublicKey_bio(BIO *bp,RSA **rsa);
+int i2d_RSAPublicKey_bio(BIO *bp,RSA *rsa);
+RSA *d2i_RSA_PUBKEY_bio(BIO *bp,RSA **rsa);
+int i2d_RSA_PUBKEY_bio(BIO *bp,RSA *rsa);
+#endif
+#ifndef OPENSSL_NO_DSA
+DSA *d2i_DSA_PUBKEY_bio(BIO *bp, DSA **dsa);
+int i2d_DSA_PUBKEY_bio(BIO *bp, DSA *dsa);
+DSA *d2i_DSAPrivateKey_bio(BIO *bp, DSA **dsa);
+int i2d_DSAPrivateKey_bio(BIO *bp, DSA *dsa);
+#endif
+#ifndef OPENSSL_NO_EC
+EC_KEY *d2i_EC_PUBKEY_bio(BIO *bp, EC_KEY **eckey);
+int i2d_EC_PUBKEY_bio(BIO *bp, EC_KEY *eckey);
+EC_KEY *d2i_ECPrivateKey_bio(BIO *bp, EC_KEY **eckey);
+int i2d_ECPrivateKey_bio(BIO *bp, EC_KEY *eckey);
+#endif
+X509_SIG *d2i_PKCS8_bio(BIO *bp,X509_SIG **p8);
+int i2d_PKCS8_bio(BIO *bp,X509_SIG *p8);
+PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_bio(BIO *bp,
+ PKCS8_PRIV_KEY_INFO **p8inf);
+int i2d_PKCS8_PRIV_KEY_INFO_bio(BIO *bp,PKCS8_PRIV_KEY_INFO *p8inf);
+int i2d_PKCS8PrivateKeyInfo_bio(BIO *bp, EVP_PKEY *key);
+int i2d_PrivateKey_bio(BIO *bp, EVP_PKEY *pkey);
+EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a);
+int i2d_PUBKEY_bio(BIO *bp, EVP_PKEY *pkey);
+EVP_PKEY *d2i_PUBKEY_bio(BIO *bp, EVP_PKEY **a);
+#endif
+
+X509 *X509_dup(X509 *x509);
+X509_ATTRIBUTE *X509_ATTRIBUTE_dup(X509_ATTRIBUTE *xa);
+X509_EXTENSION *X509_EXTENSION_dup(X509_EXTENSION *ex);
+X509_CRL *X509_CRL_dup(X509_CRL *crl);
+X509_REVOKED *X509_REVOKED_dup(X509_REVOKED *rev);
+X509_REQ *X509_REQ_dup(X509_REQ *req);
+X509_ALGOR *X509_ALGOR_dup(X509_ALGOR *xn);
+int X509_ALGOR_set0(X509_ALGOR *alg, const ASN1_OBJECT *aobj, int ptype, void *pval);
+void X509_ALGOR_get0(ASN1_OBJECT **paobj, int *pptype, void **ppval,
+ X509_ALGOR *algor);
+void X509_ALGOR_set_md(X509_ALGOR *alg, const EVP_MD *md);
+
+X509_NAME *X509_NAME_dup(X509_NAME *xn);
+X509_NAME_ENTRY *X509_NAME_ENTRY_dup(X509_NAME_ENTRY *ne);
+
+int X509_cmp_time(const ASN1_TIME *s, time_t *t);
+int X509_cmp_current_time(const ASN1_TIME *s);
+ASN1_TIME * X509_time_adj(ASN1_TIME *s, long adj, time_t *t);
+ASN1_TIME * X509_time_adj_ex(ASN1_TIME *s,
+ int offset_day, long offset_sec, time_t *t);
+ASN1_TIME * X509_gmtime_adj(ASN1_TIME *s, long adj);
+
+const char * X509_get_default_cert_area(void );
+const char * X509_get_default_cert_dir(void );
+const char * X509_get_default_cert_file(void );
+const char * X509_get_default_cert_dir_env(void );
+const char * X509_get_default_cert_file_env(void );
+const char * X509_get_default_private_dir(void );
+
+X509_REQ * X509_to_X509_REQ(X509 *x, EVP_PKEY *pkey, const EVP_MD *md);
+X509 * X509_REQ_to_X509(X509_REQ *r, int days,EVP_PKEY *pkey);
+
+DECLARE_ASN1_ENCODE_FUNCTIONS(X509_ALGORS, X509_ALGORS, X509_ALGORS)
+DECLARE_ASN1_FUNCTIONS(X509_VAL)
+
+DECLARE_ASN1_FUNCTIONS(X509_PUBKEY)
+
+int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey);
+EVP_PKEY * X509_PUBKEY_get(X509_PUBKEY *key);
+int X509_get_pubkey_parameters(EVP_PKEY *pkey,
+ STACK_OF(X509) *chain);
+int i2d_PUBKEY(const EVP_PKEY *a,unsigned char **pp);
+EVP_PKEY * d2i_PUBKEY(EVP_PKEY **a,const unsigned char **pp,
+ long length);
+#ifndef OPENSSL_NO_RSA
+int i2d_RSA_PUBKEY(const RSA *a,unsigned char **pp);
+RSA * d2i_RSA_PUBKEY(RSA **a,const unsigned char **pp,
+ long length);
+#endif
+#ifndef OPENSSL_NO_DSA
+int i2d_DSA_PUBKEY(const DSA *a,unsigned char **pp);
+DSA * d2i_DSA_PUBKEY(DSA **a,const unsigned char **pp,
+ long length);
+#endif
+#ifndef OPENSSL_NO_EC
+int i2d_EC_PUBKEY(const EC_KEY *a, unsigned char **pp);
+EC_KEY *d2i_EC_PUBKEY(EC_KEY **a, const unsigned char **pp,
+ long length);
+#endif
+
+DECLARE_ASN1_FUNCTIONS(X509_SIG)
+DECLARE_ASN1_FUNCTIONS(X509_REQ_INFO)
+DECLARE_ASN1_FUNCTIONS(X509_REQ)
+
+DECLARE_ASN1_FUNCTIONS(X509_ATTRIBUTE)
+X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int atrtype, void *value);
+
+DECLARE_ASN1_FUNCTIONS(X509_EXTENSION)
+DECLARE_ASN1_ENCODE_FUNCTIONS(X509_EXTENSIONS, X509_EXTENSIONS, X509_EXTENSIONS)
+
+DECLARE_ASN1_FUNCTIONS(X509_NAME_ENTRY)
+
+DECLARE_ASN1_FUNCTIONS(X509_NAME)
+
+int X509_NAME_set(X509_NAME **xn, X509_NAME *name);
+
+DECLARE_ASN1_FUNCTIONS(X509_CINF)
+
+DECLARE_ASN1_FUNCTIONS(X509)
+DECLARE_ASN1_FUNCTIONS(X509_CERT_AUX)
+
+DECLARE_ASN1_FUNCTIONS(X509_CERT_PAIR)
+
+int X509_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+ CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+int X509_set_ex_data(X509 *r, int idx, void *arg);
+void *X509_get_ex_data(X509 *r, int idx);
+int i2d_X509_AUX(X509 *a,unsigned char **pp);
+X509 * d2i_X509_AUX(X509 **a,const unsigned char **pp,long length);
+
+void X509_get0_signature(ASN1_BIT_STRING **psig, X509_ALGOR **palg,
+ const X509 *x);
+int X509_get_signature_nid(const X509 *x);
+
+int X509_alias_set1(X509 *x, unsigned char *name, int len);
+int X509_keyid_set1(X509 *x, unsigned char *id, int len);
+unsigned char * X509_alias_get0(X509 *x, int *len);
+unsigned char * X509_keyid_get0(X509 *x, int *len);
+int (*X509_TRUST_set_default(int (*trust)(int , X509 *, int)))(int, X509 *, int);
+int X509_TRUST_set(int *t, int trust);
+int X509_add1_trust_object(X509 *x, ASN1_OBJECT *obj);
+int X509_add1_reject_object(X509 *x, ASN1_OBJECT *obj);
+void X509_trust_clear(X509 *x);
+void X509_reject_clear(X509 *x);
+
+DECLARE_ASN1_FUNCTIONS(X509_REVOKED)
+DECLARE_ASN1_FUNCTIONS(X509_CRL_INFO)
+DECLARE_ASN1_FUNCTIONS(X509_CRL)
+
+int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev);
+int X509_CRL_get0_by_serial(X509_CRL *crl,
+ X509_REVOKED **ret, ASN1_INTEGER *serial);
+int X509_CRL_get0_by_cert(X509_CRL *crl, X509_REVOKED **ret, X509 *x);
+
+X509_PKEY * X509_PKEY_new(void );
+void X509_PKEY_free(X509_PKEY *a);
+int i2d_X509_PKEY(X509_PKEY *a,unsigned char **pp);
+X509_PKEY * d2i_X509_PKEY(X509_PKEY **a,const unsigned char **pp,long length);
+
+DECLARE_ASN1_FUNCTIONS(NETSCAPE_SPKI)
+DECLARE_ASN1_FUNCTIONS(NETSCAPE_SPKAC)
+DECLARE_ASN1_FUNCTIONS(NETSCAPE_CERT_SEQUENCE)
+
+#ifndef OPENSSL_NO_EVP
+X509_INFO * X509_INFO_new(void);
+void X509_INFO_free(X509_INFO *a);
+char * X509_NAME_oneline(X509_NAME *a,char *buf,int size);
+
+int ASN1_verify(i2d_of_void *i2d, X509_ALGOR *algor1,
+ ASN1_BIT_STRING *signature,char *data,EVP_PKEY *pkey);
+
+int ASN1_digest(i2d_of_void *i2d,const EVP_MD *type,char *data,
+ unsigned char *md,unsigned int *len);
+
+int ASN1_sign(i2d_of_void *i2d, X509_ALGOR *algor1,
+ X509_ALGOR *algor2, ASN1_BIT_STRING *signature,
+ char *data,EVP_PKEY *pkey, const EVP_MD *type);
+
+int ASN1_item_digest(const ASN1_ITEM *it,const EVP_MD *type,void *data,
+ unsigned char *md,unsigned int *len);
+
+int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *algor1,
+ ASN1_BIT_STRING *signature,void *data,EVP_PKEY *pkey);
+
+int ASN1_item_sign(const ASN1_ITEM *it, X509_ALGOR *algor1, X509_ALGOR *algor2,
+ ASN1_BIT_STRING *signature,
+ void *data, EVP_PKEY *pkey, const EVP_MD *type);
+int ASN1_item_sign_ctx(const ASN1_ITEM *it,
+ X509_ALGOR *algor1, X509_ALGOR *algor2,
+ ASN1_BIT_STRING *signature, void *asn, EVP_MD_CTX *ctx);
+#endif
+
+int X509_set_version(X509 *x,long version);
+int X509_set_serialNumber(X509 *x, ASN1_INTEGER *serial);
+ASN1_INTEGER * X509_get_serialNumber(X509 *x);
+int X509_set_issuer_name(X509 *x, X509_NAME *name);
+X509_NAME * X509_get_issuer_name(X509 *a);
+int X509_set_subject_name(X509 *x, X509_NAME *name);
+X509_NAME * X509_get_subject_name(X509 *a);
+int X509_set_notBefore(X509 *x, const ASN1_TIME *tm);
+int X509_set_notAfter(X509 *x, const ASN1_TIME *tm);
+int X509_set_pubkey(X509 *x, EVP_PKEY *pkey);
+EVP_PKEY * X509_get_pubkey(X509 *x);
+ASN1_BIT_STRING * X509_get0_pubkey_bitstr(const X509 *x);
+int X509_certificate_type(X509 *x,EVP_PKEY *pubkey /* optional */);
+
+int X509_REQ_set_version(X509_REQ *x,long version);
+int X509_REQ_set_subject_name(X509_REQ *req,X509_NAME *name);
+int X509_REQ_set_pubkey(X509_REQ *x, EVP_PKEY *pkey);
+EVP_PKEY * X509_REQ_get_pubkey(X509_REQ *req);
+int X509_REQ_extension_nid(int nid);
+int * X509_REQ_get_extension_nids(void);
+void X509_REQ_set_extension_nids(int *nids);
+STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(X509_REQ *req);
+int X509_REQ_add_extensions_nid(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts,
+ int nid);
+int X509_REQ_add_extensions(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts);
+int X509_REQ_get_attr_count(const X509_REQ *req);
+int X509_REQ_get_attr_by_NID(const X509_REQ *req, int nid,
+ int lastpos);
+int X509_REQ_get_attr_by_OBJ(const X509_REQ *req, ASN1_OBJECT *obj,
+ int lastpos);
+X509_ATTRIBUTE *X509_REQ_get_attr(const X509_REQ *req, int loc);
+X509_ATTRIBUTE *X509_REQ_delete_attr(X509_REQ *req, int loc);
+int X509_REQ_add1_attr(X509_REQ *req, X509_ATTRIBUTE *attr);
+int X509_REQ_add1_attr_by_OBJ(X509_REQ *req,
+ const ASN1_OBJECT *obj, int type,
+ const unsigned char *bytes, int len);
+int X509_REQ_add1_attr_by_NID(X509_REQ *req,
+ int nid, int type,
+ const unsigned char *bytes, int len);
+int X509_REQ_add1_attr_by_txt(X509_REQ *req,
+ const char *attrname, int type,
+ const unsigned char *bytes, int len);
+
+int X509_CRL_set_version(X509_CRL *x, long version);
+int X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name);
+int X509_CRL_set_lastUpdate(X509_CRL *x, const ASN1_TIME *tm);
+int X509_CRL_set_nextUpdate(X509_CRL *x, const ASN1_TIME *tm);
+int X509_CRL_sort(X509_CRL *crl);
+
+int X509_REVOKED_set_serialNumber(X509_REVOKED *x, ASN1_INTEGER *serial);
+int X509_REVOKED_set_revocationDate(X509_REVOKED *r, ASN1_TIME *tm);
+
+X509_CRL *X509_CRL_diff(X509_CRL *base, X509_CRL *newer,
+ EVP_PKEY *skey, const EVP_MD *md, unsigned int flags);
+
+int X509_REQ_check_private_key(X509_REQ *x509,EVP_PKEY *pkey);
+
+int X509_check_private_key(X509 *x509,EVP_PKEY *pkey);
+int X509_chain_check_suiteb(int *perror_depth,
+ X509 *x, STACK_OF(X509) *chain,
+ unsigned long flags);
+int X509_CRL_check_suiteb(X509_CRL *crl, EVP_PKEY *pk,
+ unsigned long flags);
+STACK_OF(X509) *X509_chain_up_ref(STACK_OF(X509) *chain);
+
+int X509_issuer_and_serial_cmp(const X509 *a, const X509 *b);
+unsigned long X509_issuer_and_serial_hash(X509 *a);
+
+int X509_issuer_name_cmp(const X509 *a, const X509 *b);
+unsigned long X509_issuer_name_hash(X509 *a);
+
+int X509_subject_name_cmp(const X509 *a, const X509 *b);
+unsigned long X509_subject_name_hash(X509 *x);
+
+#ifndef OPENSSL_NO_MD5
+unsigned long X509_issuer_name_hash_old(X509 *a);
+unsigned long X509_subject_name_hash_old(X509 *x);
+#endif
+
+int X509_cmp(const X509 *a, const X509 *b);
+int X509_NAME_cmp(const X509_NAME *a, const X509_NAME *b);
+unsigned long X509_NAME_hash(X509_NAME *x);
+unsigned long X509_NAME_hash_old(X509_NAME *x);
+
+int X509_CRL_cmp(const X509_CRL *a, const X509_CRL *b);
+int X509_CRL_match(const X509_CRL *a, const X509_CRL *b);
+#ifndef OPENSSL_NO_FP_API
+int X509_print_ex_fp(FILE *bp,X509 *x, unsigned long nmflag, unsigned long cflag);
+int X509_print_fp(FILE *bp,X509 *x);
+int X509_CRL_print_fp(FILE *bp,X509_CRL *x);
+int X509_REQ_print_fp(FILE *bp,X509_REQ *req);
+int X509_NAME_print_ex_fp(FILE *fp, X509_NAME *nm, int indent, unsigned long flags);
+#endif
+
+#ifndef OPENSSL_NO_BIO
+int X509_NAME_print(BIO *bp, X509_NAME *name, int obase);
+int X509_NAME_print_ex(BIO *out, X509_NAME *nm, int indent, unsigned long flags);
+int X509_print_ex(BIO *bp,X509 *x, unsigned long nmflag, unsigned long cflag);
+int X509_print(BIO *bp,X509 *x);
+int X509_ocspid_print(BIO *bp,X509 *x);
+int X509_CERT_AUX_print(BIO *bp,X509_CERT_AUX *x, int indent);
+int X509_CRL_print(BIO *bp,X509_CRL *x);
+int X509_REQ_print_ex(BIO *bp, X509_REQ *x, unsigned long nmflag, unsigned long cflag);
+int X509_REQ_print(BIO *bp,X509_REQ *req);
+#endif
+
+int X509_NAME_entry_count(X509_NAME *name);
+int X509_NAME_get_text_by_NID(X509_NAME *name, int nid,
+ char *buf,int len);
+int X509_NAME_get_text_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj,
+ char *buf,int len);
+
+/* NOTE: you should be passsing -1, not 0 as lastpos. The functions that use
+ * lastpos, search after that position on. */
+int X509_NAME_get_index_by_NID(X509_NAME *name,int nid,int lastpos);
+int X509_NAME_get_index_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj,
+ int lastpos);
+X509_NAME_ENTRY *X509_NAME_get_entry(X509_NAME *name, int loc);
+X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *name, int loc);
+int X509_NAME_add_entry(X509_NAME *name,X509_NAME_ENTRY *ne,
+ int loc, int set);
+int X509_NAME_add_entry_by_OBJ(X509_NAME *name, ASN1_OBJECT *obj, int type,
+ unsigned char *bytes, int len, int loc, int set);
+int X509_NAME_add_entry_by_NID(X509_NAME *name, int nid, int type,
+ unsigned char *bytes, int len, int loc, int set);
+X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_txt(X509_NAME_ENTRY **ne,
+ const char *field, int type, const unsigned char *bytes, int len);
+X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_NID(X509_NAME_ENTRY **ne, int nid,
+ int type,unsigned char *bytes, int len);
+int X509_NAME_add_entry_by_txt(X509_NAME *name, const char *field, int type,
+ const unsigned char *bytes, int len, int loc, int set);
+X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_OBJ(X509_NAME_ENTRY **ne,
+ const ASN1_OBJECT *obj, int type,const unsigned char *bytes,
+ int len);
+int X509_NAME_ENTRY_set_object(X509_NAME_ENTRY *ne,
+ const ASN1_OBJECT *obj);
+int X509_NAME_ENTRY_set_data(X509_NAME_ENTRY *ne, int type,
+ const unsigned char *bytes, int len);
+ASN1_OBJECT * X509_NAME_ENTRY_get_object(X509_NAME_ENTRY *ne);
+ASN1_STRING * X509_NAME_ENTRY_get_data(X509_NAME_ENTRY *ne);
+
+int X509v3_get_ext_count(const STACK_OF(X509_EXTENSION) *x);
+int X509v3_get_ext_by_NID(const STACK_OF(X509_EXTENSION) *x,
+ int nid, int lastpos);
+int X509v3_get_ext_by_OBJ(const STACK_OF(X509_EXTENSION) *x,
+ const ASN1_OBJECT *obj,int lastpos);
+int X509v3_get_ext_by_critical(const STACK_OF(X509_EXTENSION) *x,
+ int crit, int lastpos);
+X509_EXTENSION *X509v3_get_ext(const STACK_OF(X509_EXTENSION) *x, int loc);
+X509_EXTENSION *X509v3_delete_ext(STACK_OF(X509_EXTENSION) *x, int loc);
+STACK_OF(X509_EXTENSION) *X509v3_add_ext(STACK_OF(X509_EXTENSION) **x,
+ X509_EXTENSION *ex, int loc);
+
+int X509_get_ext_count(X509 *x);
+int X509_get_ext_by_NID(X509 *x, int nid, int lastpos);
+int X509_get_ext_by_OBJ(X509 *x,ASN1_OBJECT *obj,int lastpos);
+int X509_get_ext_by_critical(X509 *x, int crit, int lastpos);
+X509_EXTENSION *X509_get_ext(X509 *x, int loc);
+X509_EXTENSION *X509_delete_ext(X509 *x, int loc);
+int X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc);
+void * X509_get_ext_d2i(X509 *x, int nid, int *crit, int *idx);
+int X509_add1_ext_i2d(X509 *x, int nid, void *value, int crit,
+ unsigned long flags);
+
+int X509_CRL_get_ext_count(X509_CRL *x);
+int X509_CRL_get_ext_by_NID(X509_CRL *x, int nid, int lastpos);
+int X509_CRL_get_ext_by_OBJ(X509_CRL *x,ASN1_OBJECT *obj,int lastpos);
+int X509_CRL_get_ext_by_critical(X509_CRL *x, int crit, int lastpos);
+X509_EXTENSION *X509_CRL_get_ext(X509_CRL *x, int loc);
+X509_EXTENSION *X509_CRL_delete_ext(X509_CRL *x, int loc);
+int X509_CRL_add_ext(X509_CRL *x, X509_EXTENSION *ex, int loc);
+void * X509_CRL_get_ext_d2i(X509_CRL *x, int nid, int *crit, int *idx);
+int X509_CRL_add1_ext_i2d(X509_CRL *x, int nid, void *value, int crit,
+ unsigned long flags);
+
+int X509_REVOKED_get_ext_count(X509_REVOKED *x);
+int X509_REVOKED_get_ext_by_NID(X509_REVOKED *x, int nid, int lastpos);
+int X509_REVOKED_get_ext_by_OBJ(X509_REVOKED *x,ASN1_OBJECT *obj,int lastpos);
+int X509_REVOKED_get_ext_by_critical(X509_REVOKED *x, int crit, int lastpos);
+X509_EXTENSION *X509_REVOKED_get_ext(X509_REVOKED *x, int loc);
+X509_EXTENSION *X509_REVOKED_delete_ext(X509_REVOKED *x, int loc);
+int X509_REVOKED_add_ext(X509_REVOKED *x, X509_EXTENSION *ex, int loc);
+void * X509_REVOKED_get_ext_d2i(X509_REVOKED *x, int nid, int *crit, int *idx);
+int X509_REVOKED_add1_ext_i2d(X509_REVOKED *x, int nid, void *value, int crit,
+ unsigned long flags);
+
+X509_EXTENSION *X509_EXTENSION_create_by_NID(X509_EXTENSION **ex,
+ int nid, int crit, ASN1_OCTET_STRING *data);
+X509_EXTENSION *X509_EXTENSION_create_by_OBJ(X509_EXTENSION **ex,
+ const ASN1_OBJECT *obj,int crit,ASN1_OCTET_STRING *data);
+int X509_EXTENSION_set_object(X509_EXTENSION *ex,const ASN1_OBJECT *obj);
+int X509_EXTENSION_set_critical(X509_EXTENSION *ex, int crit);
+int X509_EXTENSION_set_data(X509_EXTENSION *ex,
+ ASN1_OCTET_STRING *data);
+ASN1_OBJECT * X509_EXTENSION_get_object(X509_EXTENSION *ex);
+ASN1_OCTET_STRING *X509_EXTENSION_get_data(X509_EXTENSION *ne);
+int X509_EXTENSION_get_critical(X509_EXTENSION *ex);
+
+int X509at_get_attr_count(const STACK_OF(X509_ATTRIBUTE) *x);
+int X509at_get_attr_by_NID(const STACK_OF(X509_ATTRIBUTE) *x, int nid,
+ int lastpos);
+int X509at_get_attr_by_OBJ(const STACK_OF(X509_ATTRIBUTE) *sk, const ASN1_OBJECT *obj,
+ int lastpos);
+X509_ATTRIBUTE *X509at_get_attr(const STACK_OF(X509_ATTRIBUTE) *x, int loc);
+X509_ATTRIBUTE *X509at_delete_attr(STACK_OF(X509_ATTRIBUTE) *x, int loc);
+STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x,
+ X509_ATTRIBUTE *attr);
+STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_OBJ(STACK_OF(X509_ATTRIBUTE) **x,
+ const ASN1_OBJECT *obj, int type,
+ const unsigned char *bytes, int len);
+STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_NID(STACK_OF(X509_ATTRIBUTE) **x,
+ int nid, int type,
+ const unsigned char *bytes, int len);
+STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_txt(STACK_OF(X509_ATTRIBUTE) **x,
+ const char *attrname, int type,
+ const unsigned char *bytes, int len);
+void *X509at_get0_data_by_OBJ(STACK_OF(X509_ATTRIBUTE) *x,
+ ASN1_OBJECT *obj, int lastpos, int type);
+X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_NID(X509_ATTRIBUTE **attr, int nid,
+ int atrtype, const void *data, int len);
+X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_OBJ(X509_ATTRIBUTE **attr,
+ const ASN1_OBJECT *obj, int atrtype, const void *data, int len);
+X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_txt(X509_ATTRIBUTE **attr,
+ const char *atrname, int type, const unsigned char *bytes, int len);
+int X509_ATTRIBUTE_set1_object(X509_ATTRIBUTE *attr, const ASN1_OBJECT *obj);
+int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype, const void *data, int len);
+void *X509_ATTRIBUTE_get0_data(X509_ATTRIBUTE *attr, int idx,
+ int atrtype, void *data);
+int X509_ATTRIBUTE_count(X509_ATTRIBUTE *attr);
+ASN1_OBJECT *X509_ATTRIBUTE_get0_object(X509_ATTRIBUTE *attr);
+ASN1_TYPE *X509_ATTRIBUTE_get0_type(X509_ATTRIBUTE *attr, int idx);
+
+int EVP_PKEY_get_attr_count(const EVP_PKEY *key);
+int EVP_PKEY_get_attr_by_NID(const EVP_PKEY *key, int nid,
+ int lastpos);
+int EVP_PKEY_get_attr_by_OBJ(const EVP_PKEY *key, ASN1_OBJECT *obj,
+ int lastpos);
+X509_ATTRIBUTE *EVP_PKEY_get_attr(const EVP_PKEY *key, int loc);
+X509_ATTRIBUTE *EVP_PKEY_delete_attr(EVP_PKEY *key, int loc);
+int EVP_PKEY_add1_attr(EVP_PKEY *key, X509_ATTRIBUTE *attr);
+int EVP_PKEY_add1_attr_by_OBJ(EVP_PKEY *key,
+ const ASN1_OBJECT *obj, int type,
+ const unsigned char *bytes, int len);
+int EVP_PKEY_add1_attr_by_NID(EVP_PKEY *key,
+ int nid, int type,
+ const unsigned char *bytes, int len);
+int EVP_PKEY_add1_attr_by_txt(EVP_PKEY *key,
+ const char *attrname, int type,
+ const unsigned char *bytes, int len);
+
+int X509_verify_cert(X509_STORE_CTX *ctx);
+
+/* lookup a cert from a X509 STACK */
+X509 *X509_find_by_issuer_and_serial(STACK_OF(X509) *sk,X509_NAME *name,
+ ASN1_INTEGER *serial);
+X509 *X509_find_by_subject(STACK_OF(X509) *sk,X509_NAME *name);
+
+DECLARE_ASN1_FUNCTIONS(PBEPARAM)
+DECLARE_ASN1_FUNCTIONS(PBE2PARAM)
+DECLARE_ASN1_FUNCTIONS(PBKDF2PARAM)
+
+int PKCS5_pbe_set0_algor(X509_ALGOR *algor, int alg, int iter,
+ const unsigned char *salt, int saltlen);
+
+X509_ALGOR *PKCS5_pbe_set(int alg, int iter,
+ const unsigned char *salt, int saltlen);
+X509_ALGOR *PKCS5_pbe2_set(const EVP_CIPHER *cipher, int iter,
+ unsigned char *salt, int saltlen);
+X509_ALGOR *PKCS5_pbe2_set_iv(const EVP_CIPHER *cipher, int iter,
+ unsigned char *salt, int saltlen,
+ unsigned char *aiv, int prf_nid);
+
+X509_ALGOR *PKCS5_pbkdf2_set(int iter, unsigned char *salt, int saltlen,
+ int prf_nid, int keylen);
+
+/* PKCS#8 utilities */
+
+DECLARE_ASN1_FUNCTIONS(PKCS8_PRIV_KEY_INFO)
+
+EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8);
+PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey);
+PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8_broken(EVP_PKEY *pkey, int broken);
+PKCS8_PRIV_KEY_INFO *PKCS8_set_broken(PKCS8_PRIV_KEY_INFO *p8, int broken);
+
+int PKCS8_pkey_set0(PKCS8_PRIV_KEY_INFO *priv, ASN1_OBJECT *aobj,
+ int version, int ptype, void *pval,
+ unsigned char *penc, int penclen);
+int PKCS8_pkey_get0(ASN1_OBJECT **ppkalg,
+ const unsigned char **pk, int *ppklen,
+ X509_ALGOR **pa,
+ PKCS8_PRIV_KEY_INFO *p8);
+
+int X509_PUBKEY_set0_param(X509_PUBKEY *pub, const ASN1_OBJECT *aobj,
+ int ptype, void *pval,
+ unsigned char *penc, int penclen);
+int X509_PUBKEY_get0_param(ASN1_OBJECT **ppkalg,
+ const unsigned char **pk, int *ppklen,
+ X509_ALGOR **pa,
+ X509_PUBKEY *pub);
+
+int X509_check_trust(X509 *x, int id, int flags);
+int X509_TRUST_get_count(void);
+X509_TRUST * X509_TRUST_get0(int idx);
+int X509_TRUST_get_by_id(int id);
+int X509_TRUST_add(int id, int flags, int (*ck)(X509_TRUST *, X509 *, int),
+ char *name, int arg1, void *arg2);
+void X509_TRUST_cleanup(void);
+int X509_TRUST_get_flags(X509_TRUST *xp);
+char *X509_TRUST_get0_name(X509_TRUST *xp);
+int X509_TRUST_get_trust(X509_TRUST *xp);
+
+/* PKCS7_get_certificates parses a PKCS#7, SignedData structure from |cbs| and
+ * appends the included certificates to |out_certs|. It returns one on success
+ * and zero on error. */
+int PKCS7_get_certificates(STACK_OF(X509) *out_certs, CBS *cbs);
+
+
+/* EVP_PK values indicate the algorithm of the public key in a certificate. */
+
+#define EVP_PK_RSA 0x0001
+#define EVP_PK_DSA 0x0002
+#define EVP_PK_DH 0x0004
+#define EVP_PK_EC 0x0008
+
+/* EVP_PKS values indicate the algorithm used to sign a certificate. */
+
+#define EVP_PKS_RSA 0x0100
+#define EVP_PKS_DSA 0x0200
+#define EVP_PKS_EC 0x0400
+
+/* EVP_PKT values are flags that define what public-key operations can be
+ * performed with the public key from a certificate. */
+
+/* EVP_PKT_SIGN indicates that the public key can be used for signing. */
+#define EVP_PKT_SIGN 0x0010
+/* EVP_PKT_ENC indicates that a session key can be encrypted to the public
+ * key. */
+#define EVP_PKT_ENC 0x0020
+/* EVP_PKT_EXCH indicates that key-agreement can be performed. */
+#define EVP_PKT_EXCH 0x0040
+/* EVP_PKT_EXP indicates that key is weak (i.e. "export"). */
+#define EVP_PKT_EXP 0x1000
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#define X509_F_x509_name_ex_new 100
+#define X509_F_X509_EXTENSION_create_by_NID 101
+#define X509_F_X509_load_crl_file 102
+#define X509_F_X509_TRUST_set 103
+#define X509_F_X509_EXTENSION_create_by_OBJ 104
+#define X509_F_by_file_ctrl 105
+#define X509_F_X509_load_cert_crl_file 106
+#define X509_F_X509_CRL_add0_revoked 107
+#define X509_F_bitstr_cb 108
+#define X509_F_X509_STORE_CTX_new 109
+#define X509_F_X509_REQ_to_X509 110
+#define X509_F_X509v3_add_ext 111
+#define X509_F_ASN1_sign 112
+#define X509_F_asn1_str2type 113
+#define X509_F_i2d_RSA_PUBKEY 114
+#define X509_F_ASN1_item_sign_ctx 115
+#define X509_F_x509_name_encode 116
+#define X509_F_d2i_X509_PKEY 117
+#define X509_F_ASN1_generate_v3 118
+#define X509_F_dir_ctrl 119
+#define X509_F_X509_print_ex_fp 120
+#define X509_F_X509_ATTRIBUTE_get0_data 121
+#define X509_F_X509_NAME_oneline 122
+#define X509_F_X509_CRL_print_fp 123
+#define X509_F_X509_STORE_CTX_get1_issuer 124
+#define X509_F_add_cert_dir 125
+#define X509_F_PKCS7_get_certificates 126
+#define X509_F_X509_ATTRIBUTE_create_by_NID 127
+#define X509_F_X509_ATTRIBUTE_set1_data 128
+#define X509_F_X509_STORE_CTX_init 129
+#define X509_F_NETSCAPE_SPKI_b64_decode 130
+#define X509_F_X509_NAME_print 131
+#define X509_F_x509_name_ex_d2i 132
+#define X509_F_X509_PKEY_new 133
+#define X509_F_X509_STORE_add_cert 134
+#define X509_F_parse_tagging 135
+#define X509_F_check_policy 136
+#define X509_F_ASN1_digest 137
+#define X509_F_X509_load_cert_file 138
+#define X509_F_X509_ATTRIBUTE_create_by_txt 139
+#define X509_F_X509_PUBKEY_set 140
+#define X509_F_X509_PUBKEY_get 141
+#define X509_F_get_cert_by_subject 142
+#define X509_F_X509_NAME_add_entry 143
+#define X509_F_X509at_add1_attr 144
+#define X509_F_X509_check_private_key 145
+#define X509_F_append_exp 146
+#define X509_F_i2d_EC_PUBKEY 147
+#define X509_F_X509_INFO_new 148
+#define X509_F_X509_STORE_CTX_purpose_inherit 149
+#define X509_F_NETSCAPE_SPKI_b64_encode 150
+#define X509_F_X509_to_X509_REQ 151
+#define X509_F_X509_NAME_ENTRY_create_by_txt 152
+#define X509_F_X509_NAME_ENTRY_set_object 153
+#define X509_F_asn1_cb 154
+#define X509_F_X509_verify_cert 155
+#define X509_F_X509_CRL_diff 156
+#define X509_F_i2d_PrivateKey 157
+#define X509_F_X509_REQ_check_private_key 158
+#define X509_F_X509_STORE_add_crl 159
+#define X509_F_X509_get_pubkey_parameters 160
+#define X509_F_ASN1_item_verify 161
+#define X509_F_X509_ATTRIBUTE_create_by_OBJ 162
+#define X509_F_i2d_DSA_PUBKEY 163
+#define X509_F_X509_TRUST_add 164
+#define X509_F_X509_NAME_ENTRY_create_by_NID 165
+#define X509_R_NO_CERT_SET_FOR_US_TO_VERIFY 100
+#define X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN 101
+#define X509_R_METHOD_NOT_SUPPORTED 102
+#define X509_R_UNSUPPORTED_ALGORITHM 103
+#define X509_R_CRL_VERIFY_FAILURE 104
+#define X509_R_BASE64_DECODE_ERROR 105
+#define X509_R_INVALID_TRUST 106
+#define X509_R_UNKNOWN_NID 107
+#define X509_R_INVALID_DIRECTORY 108
+#define X509_R_KEY_VALUES_MISMATCH 109
+#define X509_R_CERT_ALREADY_IN_HASH_TABLE 110
+#define X509_R_PUBLIC_KEY_DECODE_ERROR 111
+#define X509_R_NOT_PKCS7_SIGNED_DATA 112
+#define X509_R_PUBLIC_KEY_ENCODE_ERROR 113
+#define X509_R_LOADING_CERT_DIR 114
+#define X509_R_WRONG_TYPE 115
+#define X509_R_UNKNOWN_PURPOSE_ID 116
+#define X509_R_NEWER_CRL_NOT_NEWER 117
+#define X509_R_UNKNOWN_TRUST_ID 118
+#define X509_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED 119
+#define X509_R_KEY_TYPE_MISMATCH 120
+#define X509_R_UNKNOWN_KEY_TYPE 121
+#define X509_R_BAD_X509_FILETYPE 122
+#define X509_R_ISSUER_MISMATCH 123
+#define X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY 124
+#define X509_R_WRONG_LOOKUP_TYPE 125
+#define X509_R_CONTEXT_NOT_INITIALISED 126
+#define X509_R_CANT_CHECK_DH_KEY 127
+#define X509_R_NO_CERTIFICATES_INCLUDED 128
+#define X509_R_INVALID_FIELD_NAME 129
+#define X509_R_SHOULD_RETRY 130
+#define X509_R_NO_CRL_NUMBER 131
+#define X509_R_IDP_MISMATCH 132
+#define X509_R_LOADING_DEFAULTS 133
+#define X509_R_BAD_PKCS7_VERSION 134
+#define X509_R_CRL_ALREADY_DELTA 135
+#define X509_R_ERR_ASN1_LIB 136
+#define X509_R_AKID_MISMATCH 137
+
+#endif
diff --git a/crypto/x509/x509_att.c b/crypto/x509/x509_att.c
new file mode 100644
index 0000000..3613c35
--- /dev/null
+++ b/crypto/x509/x509_att.c
@@ -0,0 +1,353 @@
+/* crypto/x509/x509_att.c */
+/* 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/asn1.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/obj.h>
+#include <openssl/stack.h>
+#include <openssl/x509.h>
+
+
+int X509at_get_attr_count(const STACK_OF(X509_ATTRIBUTE) *x)
+{
+ return sk_X509_ATTRIBUTE_num(x);
+}
+
+int X509at_get_attr_by_NID(const STACK_OF(X509_ATTRIBUTE) *x, int nid,
+ int lastpos)
+{
+ const ASN1_OBJECT *obj;
+
+ obj=OBJ_nid2obj(nid);
+ if (obj == NULL) return(-2);
+ return(X509at_get_attr_by_OBJ(x,obj,lastpos));
+}
+
+int X509at_get_attr_by_OBJ(const STACK_OF(X509_ATTRIBUTE) *sk, const ASN1_OBJECT *obj,
+ int lastpos)
+{
+ int n;
+ X509_ATTRIBUTE *ex;
+
+ if (sk == NULL) return(-1);
+ lastpos++;
+ if (lastpos < 0)
+ lastpos=0;
+ n=sk_X509_ATTRIBUTE_num(sk);
+ for ( ; lastpos < n; lastpos++)
+ {
+ ex=sk_X509_ATTRIBUTE_value(sk,lastpos);
+ if (OBJ_cmp(ex->object,obj) == 0)
+ return(lastpos);
+ }
+ return(-1);
+}
+
+X509_ATTRIBUTE *X509at_get_attr(const STACK_OF(X509_ATTRIBUTE) *x, int loc)
+{
+ if (x == NULL || loc < 0 || sk_X509_ATTRIBUTE_num(x) <= (size_t) loc)
+ return NULL;
+ else
+ return sk_X509_ATTRIBUTE_value(x,loc);
+}
+
+X509_ATTRIBUTE *X509at_delete_attr(STACK_OF(X509_ATTRIBUTE) *x, int loc)
+{
+ X509_ATTRIBUTE *ret;
+
+ if (x == NULL || loc < 0 || sk_X509_ATTRIBUTE_num(x) <= (size_t) loc)
+ return(NULL);
+ ret=sk_X509_ATTRIBUTE_delete(x,loc);
+ return(ret);
+}
+
+STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x,
+ X509_ATTRIBUTE *attr)
+{
+ X509_ATTRIBUTE *new_attr=NULL;
+ STACK_OF(X509_ATTRIBUTE) *sk=NULL;
+
+ if (x == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, X509at_add1_attr, ERR_R_PASSED_NULL_PARAMETER);
+ goto err2;
+ }
+
+ if (*x == NULL)
+ {
+ if ((sk=sk_X509_ATTRIBUTE_new_null()) == NULL)
+ goto err;
+ }
+ else
+ sk= *x;
+
+ if ((new_attr=X509_ATTRIBUTE_dup(attr)) == NULL)
+ goto err2;
+ if (!sk_X509_ATTRIBUTE_push(sk,new_attr))
+ goto err;
+ if (*x == NULL)
+ *x=sk;
+ return(sk);
+err:
+ OPENSSL_PUT_ERROR(X509, X509at_add1_attr, ERR_R_MALLOC_FAILURE);
+err2:
+ if (new_attr != NULL) X509_ATTRIBUTE_free(new_attr);
+ if (sk != NULL) sk_X509_ATTRIBUTE_free(sk);
+ return(NULL);
+}
+
+STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_OBJ(STACK_OF(X509_ATTRIBUTE) **x,
+ const ASN1_OBJECT *obj, int type,
+ const unsigned char *bytes, int len)
+{
+ X509_ATTRIBUTE *attr;
+ STACK_OF(X509_ATTRIBUTE) *ret;
+ attr = X509_ATTRIBUTE_create_by_OBJ(NULL, obj, type, bytes, len);
+ if(!attr) return 0;
+ ret = X509at_add1_attr(x, attr);
+ X509_ATTRIBUTE_free(attr);
+ return ret;
+}
+
+STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_NID(STACK_OF(X509_ATTRIBUTE) **x,
+ int nid, int type,
+ const unsigned char *bytes, int len)
+{
+ X509_ATTRIBUTE *attr;
+ STACK_OF(X509_ATTRIBUTE) *ret;
+ attr = X509_ATTRIBUTE_create_by_NID(NULL, nid, type, bytes, len);
+ if(!attr) return 0;
+ ret = X509at_add1_attr(x, attr);
+ X509_ATTRIBUTE_free(attr);
+ return ret;
+}
+
+STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_txt(STACK_OF(X509_ATTRIBUTE) **x,
+ const char *attrname, int type,
+ const unsigned char *bytes, int len)
+{
+ X509_ATTRIBUTE *attr;
+ STACK_OF(X509_ATTRIBUTE) *ret;
+ attr = X509_ATTRIBUTE_create_by_txt(NULL, attrname, type, bytes, len);
+ if(!attr) return 0;
+ ret = X509at_add1_attr(x, attr);
+ X509_ATTRIBUTE_free(attr);
+ return ret;
+}
+
+void *X509at_get0_data_by_OBJ(STACK_OF(X509_ATTRIBUTE) *x,
+ ASN1_OBJECT *obj, int lastpos, int type)
+{
+ int i;
+ X509_ATTRIBUTE *at;
+ i = X509at_get_attr_by_OBJ(x, obj, lastpos);
+ if (i == -1)
+ return NULL;
+ if ((lastpos <= -2) && (X509at_get_attr_by_OBJ(x, obj, i) != -1))
+ return NULL;
+ at = X509at_get_attr(x, i);
+ if (lastpos <= -3 && (X509_ATTRIBUTE_count(at) != 1))
+ return NULL;
+ return X509_ATTRIBUTE_get0_data(at, 0, type, NULL);
+}
+
+X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_NID(X509_ATTRIBUTE **attr, int nid,
+ int atrtype, const void *data, int len)
+{
+ const ASN1_OBJECT *obj;
+
+ obj=OBJ_nid2obj(nid);
+ if (obj == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_ATTRIBUTE_create_by_NID, X509_R_UNKNOWN_NID);
+ return(NULL);
+ }
+ return X509_ATTRIBUTE_create_by_OBJ(attr,obj,atrtype,data,len);
+}
+
+X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_OBJ(X509_ATTRIBUTE **attr,
+ const ASN1_OBJECT *obj, int atrtype, const void *data, int len)
+{
+ X509_ATTRIBUTE *ret;
+
+ if ((attr == NULL) || (*attr == NULL))
+ {
+ if ((ret=X509_ATTRIBUTE_new()) == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_ATTRIBUTE_create_by_OBJ, ERR_R_MALLOC_FAILURE);
+ return(NULL);
+ }
+ }
+ else
+ ret= *attr;
+
+ if (!X509_ATTRIBUTE_set1_object(ret,obj))
+ goto err;
+ if (!X509_ATTRIBUTE_set1_data(ret,atrtype,data,len))
+ goto err;
+
+ if ((attr != NULL) && (*attr == NULL)) *attr=ret;
+ return(ret);
+err:
+ if ((attr == NULL) || (ret != *attr))
+ X509_ATTRIBUTE_free(ret);
+ return(NULL);
+}
+
+X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_txt(X509_ATTRIBUTE **attr,
+ const char *atrname, int type, const unsigned char *bytes, int len)
+ {
+ ASN1_OBJECT *obj;
+ X509_ATTRIBUTE *nattr;
+
+ obj=OBJ_txt2obj(atrname, 0);
+ if (obj == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_ATTRIBUTE_create_by_txt, X509_R_INVALID_FIELD_NAME);
+ ERR_add_error_data(2, "name=", atrname);
+ return(NULL);
+ }
+ nattr = X509_ATTRIBUTE_create_by_OBJ(attr,obj,type,bytes,len);
+ ASN1_OBJECT_free(obj);
+ return nattr;
+ }
+
+int X509_ATTRIBUTE_set1_object(X509_ATTRIBUTE *attr, const ASN1_OBJECT *obj)
+{
+ if ((attr == NULL) || (obj == NULL))
+ return(0);
+ ASN1_OBJECT_free(attr->object);
+ attr->object=OBJ_dup(obj);
+ return(1);
+}
+
+int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype, const void *data, int len)
+{
+ ASN1_TYPE *ttmp;
+ ASN1_STRING *stmp = NULL;
+ int atype = 0;
+ if (!attr) return 0;
+ if(attrtype & MBSTRING_FLAG) {
+ 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);
+ return 0;
+ }
+ atype = stmp->type;
+ } else if (len != -1){
+ if(!(stmp = ASN1_STRING_type_new(attrtype))) goto err;
+ if(!ASN1_STRING_set(stmp, data, len)) goto err;
+ atype = attrtype;
+ }
+ if(!(attr->value.set = sk_ASN1_TYPE_new_null())) goto err;
+ attr->single = 0;
+ /* This is a bit naughty because the attribute should really have
+ * at least one value but some types use and zero length SET and
+ * require this.
+ */
+ if (attrtype == 0)
+ return 1;
+ if(!(ttmp = ASN1_TYPE_new())) goto err;
+ if ((len == -1) && !(attrtype & MBSTRING_FLAG))
+ {
+ if (!ASN1_TYPE_set1(ttmp, attrtype, data))
+ goto err;
+ }
+ else
+ ASN1_TYPE_set(ttmp, atype, stmp);
+ 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);
+ return 0;
+}
+
+int X509_ATTRIBUTE_count(X509_ATTRIBUTE *attr)
+{
+ if(!attr->single) return sk_ASN1_TYPE_num(attr->value.set);
+ if(attr->value.single) return 1;
+ return 0;
+}
+
+ASN1_OBJECT *X509_ATTRIBUTE_get0_object(X509_ATTRIBUTE *attr)
+{
+ if (attr == NULL) return(NULL);
+ return(attr->object);
+}
+
+void *X509_ATTRIBUTE_get0_data(X509_ATTRIBUTE *attr, int idx,
+ int atrtype, void *data)
+{
+ ASN1_TYPE *ttmp;
+ 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);
+ return NULL;
+ }
+ return ttmp->value.ptr;
+}
+
+ASN1_TYPE *X509_ATTRIBUTE_get0_type(X509_ATTRIBUTE *attr, int idx)
+{
+ if (attr == NULL) return(NULL);
+ if(idx >= X509_ATTRIBUTE_count(attr)) return NULL;
+ if(!attr->single) return sk_ASN1_TYPE_value(attr->value.set, idx);
+ else return attr->value.single;
+}
diff --git a/crypto/x509/x509_cmp.c b/crypto/x509/x509_cmp.c
new file mode 100644
index 0000000..e626fcf
--- /dev/null
+++ b/crypto/x509/x509_cmp.c
@@ -0,0 +1,515 @@
+/* crypto/x509/x509_cmp.c */
+/* 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/asn1.h>
+#include <openssl/buf.h>
+#include <openssl/digest.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/stack.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+
+int X509_issuer_and_serial_cmp(const X509 *a, const X509 *b)
+ {
+ int i;
+ X509_CINF *ai,*bi;
+
+ ai=a->cert_info;
+ bi=b->cert_info;
+ i=M_ASN1_INTEGER_cmp(ai->serialNumber,bi->serialNumber);
+ if (i) return(i);
+ return(X509_NAME_cmp(ai->issuer,bi->issuer));
+ }
+
+#ifndef OPENSSL_NO_MD5
+unsigned long X509_issuer_and_serial_hash(X509 *a)
+ {
+ unsigned long ret=0;
+ EVP_MD_CTX ctx;
+ unsigned char md[16];
+ char *f;
+
+ EVP_MD_CTX_init(&ctx);
+ f=X509_NAME_oneline(a->cert_info->issuer,NULL,0);
+ if (!EVP_DigestInit_ex(&ctx, EVP_md5(), NULL))
+ goto err;
+ if (!EVP_DigestUpdate(&ctx,(unsigned char *)f,strlen(f)))
+ goto err;
+ OPENSSL_free(f);
+ if(!EVP_DigestUpdate(&ctx,(unsigned char *)a->cert_info->serialNumber->data,
+ (unsigned long)a->cert_info->serialNumber->length))
+ goto err;
+ if (!EVP_DigestFinal_ex(&ctx,&(md[0]),NULL))
+ goto err;
+ ret=( ((unsigned long)md[0] )|((unsigned long)md[1]<<8L)|
+ ((unsigned long)md[2]<<16L)|((unsigned long)md[3]<<24L)
+ )&0xffffffffL;
+ err:
+ EVP_MD_CTX_cleanup(&ctx);
+ return(ret);
+ }
+#endif
+
+int X509_issuer_name_cmp(const X509 *a, const X509 *b)
+ {
+ return(X509_NAME_cmp(a->cert_info->issuer,b->cert_info->issuer));
+ }
+
+int X509_subject_name_cmp(const X509 *a, const X509 *b)
+ {
+ return(X509_NAME_cmp(a->cert_info->subject,b->cert_info->subject));
+ }
+
+int X509_CRL_cmp(const X509_CRL *a, const X509_CRL *b)
+ {
+ return(X509_NAME_cmp(a->crl->issuer,b->crl->issuer));
+ }
+
+#ifndef OPENSSL_NO_SHA
+int X509_CRL_match(const X509_CRL *a, const X509_CRL *b)
+ {
+ return memcmp(a->sha1_hash, b->sha1_hash, 20);
+ }
+#endif
+
+X509_NAME *X509_get_issuer_name(X509 *a)
+ {
+ return(a->cert_info->issuer);
+ }
+
+unsigned long X509_issuer_name_hash(X509 *x)
+ {
+ return(X509_NAME_hash(x->cert_info->issuer));
+ }
+
+#ifndef OPENSSL_NO_MD5
+unsigned long X509_issuer_name_hash_old(X509 *x)
+ {
+ return(X509_NAME_hash_old(x->cert_info->issuer));
+ }
+#endif
+
+X509_NAME *X509_get_subject_name(X509 *a)
+ {
+ return(a->cert_info->subject);
+ }
+
+ASN1_INTEGER *X509_get_serialNumber(X509 *a)
+ {
+ return(a->cert_info->serialNumber);
+ }
+
+unsigned long X509_subject_name_hash(X509 *x)
+ {
+ return(X509_NAME_hash(x->cert_info->subject));
+ }
+
+#ifndef OPENSSL_NO_MD5
+unsigned long X509_subject_name_hash_old(X509 *x)
+ {
+ return(X509_NAME_hash_old(x->cert_info->subject));
+ }
+#endif
+
+#ifndef OPENSSL_NO_SHA
+/* Compare two certificates: they must be identical for
+ * this to work. NB: Although "cmp" operations are generally
+ * prototyped to take "const" arguments (eg. for use in
+ * STACKs), the way X509 handling is - these operations may
+ * involve ensuring the hashes are up-to-date and ensuring
+ * certain cert information is cached. So this is the point
+ * where the "depth-first" constification tree has to halt
+ * with an evil cast.
+ */
+int X509_cmp(const X509 *a, const X509 *b)
+{
+ int rv;
+ /* ensure hash is valid */
+ X509_check_purpose((X509 *)a, -1, 0);
+ X509_check_purpose((X509 *)b, -1, 0);
+
+ rv = memcmp(a->sha1_hash, b->sha1_hash, SHA_DIGEST_LENGTH);
+ if (rv)
+ return rv;
+ /* Check for match against stored encoding too */
+ if (!a->cert_info->enc.modified && !b->cert_info->enc.modified)
+ {
+ rv = (int)(a->cert_info->enc.len - b->cert_info->enc.len);
+ if (rv)
+ return rv;
+ return memcmp(a->cert_info->enc.enc, b->cert_info->enc.enc,
+ a->cert_info->enc.len);
+ }
+ return rv;
+}
+#endif
+
+
+int X509_NAME_cmp(const X509_NAME *a, const X509_NAME *b)
+ {
+ int ret;
+
+ /* Ensure canonical encoding is present and up to date */
+
+ if (!a->canon_enc || a->modified)
+ {
+ ret = i2d_X509_NAME((X509_NAME *)a, NULL);
+ if (ret < 0)
+ return -2;
+ }
+
+ if (!b->canon_enc || b->modified)
+ {
+ ret = i2d_X509_NAME((X509_NAME *)b, NULL);
+ if (ret < 0)
+ return -2;
+ }
+
+ ret = a->canon_enclen - b->canon_enclen;
+
+ if (ret)
+ return ret;
+
+ return memcmp(a->canon_enc, b->canon_enc, a->canon_enclen);
+
+ }
+
+unsigned long X509_NAME_hash(X509_NAME *x)
+ {
+ unsigned long ret=0;
+ unsigned char md[SHA_DIGEST_LENGTH];
+
+ /* Make sure X509_NAME structure contains valid cached encoding */
+ i2d_X509_NAME(x,NULL);
+ if (!EVP_Digest(x->canon_enc, x->canon_enclen, md, NULL, EVP_sha1(),
+ NULL))
+ return 0;
+
+ ret=( ((unsigned long)md[0] )|((unsigned long)md[1]<<8L)|
+ ((unsigned long)md[2]<<16L)|((unsigned long)md[3]<<24L)
+ )&0xffffffffL;
+ return(ret);
+ }
+
+
+#ifndef OPENSSL_NO_MD5
+/* I now DER encode the name and hash it. Since I cache the DER encoding,
+ * this is reasonably efficient. */
+
+unsigned long X509_NAME_hash_old(X509_NAME *x)
+ {
+ EVP_MD_CTX md_ctx;
+ unsigned long ret=0;
+ unsigned char md[16];
+
+ /* Make sure X509_NAME structure contains valid cached encoding */
+ i2d_X509_NAME(x,NULL);
+ EVP_MD_CTX_init(&md_ctx);
+ /* EVP_MD_CTX_set_flags(&md_ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); */
+ if (EVP_DigestInit_ex(&md_ctx, EVP_md5(), NULL)
+ && EVP_DigestUpdate(&md_ctx, x->bytes->data, x->bytes->length)
+ && EVP_DigestFinal_ex(&md_ctx,md,NULL))
+ ret=(((unsigned long)md[0] )|((unsigned long)md[1]<<8L)|
+ ((unsigned long)md[2]<<16L)|((unsigned long)md[3]<<24L)
+ )&0xffffffffL;
+ EVP_MD_CTX_cleanup(&md_ctx);
+
+ return(ret);
+ }
+#endif
+
+/* Search a stack of X509 for a match */
+X509 *X509_find_by_issuer_and_serial(STACK_OF(X509) *sk, X509_NAME *name,
+ ASN1_INTEGER *serial)
+ {
+ size_t i;
+ X509_CINF cinf;
+ X509 x,*x509=NULL;
+
+ if(!sk) return NULL;
+
+ x.cert_info= &cinf;
+ cinf.serialNumber=serial;
+ cinf.issuer=name;
+
+ for (i=0; i<sk_X509_num(sk); i++)
+ {
+ x509=sk_X509_value(sk,i);
+ if (X509_issuer_and_serial_cmp(x509,&x) == 0)
+ return(x509);
+ }
+ return(NULL);
+ }
+
+X509 *X509_find_by_subject(STACK_OF(X509) *sk, X509_NAME *name)
+ {
+ X509 *x509;
+ size_t i;
+
+ for (i=0; i<sk_X509_num(sk); i++)
+ {
+ x509=sk_X509_value(sk,i);
+ if (X509_NAME_cmp(X509_get_subject_name(x509),name) == 0)
+ return(x509);
+ }
+ return(NULL);
+ }
+
+EVP_PKEY *X509_get_pubkey(X509 *x)
+ {
+ if ((x == NULL) || (x->cert_info == NULL))
+ return(NULL);
+ return(X509_PUBKEY_get(x->cert_info->key));
+ }
+
+ASN1_BIT_STRING *X509_get0_pubkey_bitstr(const X509 *x)
+ {
+ if(!x) return NULL;
+ return x->cert_info->key->public_key;
+ }
+
+
+int X509_check_private_key(X509 *x, EVP_PKEY *k)
+ {
+ EVP_PKEY *xk;
+ int ret;
+
+ xk=X509_get_pubkey(x);
+
+ if (xk)
+ ret = EVP_PKEY_cmp(xk, k);
+ else
+ ret = -2;
+
+ switch (ret)
+ {
+ case 1:
+ break;
+ case 0:
+ OPENSSL_PUT_ERROR(X509, X509_check_private_key, X509_R_KEY_VALUES_MISMATCH);
+ break;
+ case -1:
+ OPENSSL_PUT_ERROR(X509, X509_check_private_key, X509_R_KEY_TYPE_MISMATCH);
+ break;
+ case -2:
+ OPENSSL_PUT_ERROR(X509, X509_check_private_key, X509_R_UNKNOWN_KEY_TYPE);
+ }
+ if (xk)
+ EVP_PKEY_free(xk);
+ if (ret > 0)
+ return 1;
+ return 0;
+ }
+
+/* Check a suite B algorithm is permitted: pass in a public key and
+ * the NID of its signature (or 0 if no signature). The pflags is
+ * a pointer to a flags field which must contain the suite B verification
+ * flags.
+ */
+
+#ifndef OPENSSL_NO_EC
+
+static int check_suite_b(EVP_PKEY *pkey, int sign_nid, unsigned long *pflags)
+ {
+ const EC_GROUP *grp = NULL;
+ int curve_nid;
+ if (pkey && pkey->type == EVP_PKEY_EC)
+ grp = EC_KEY_get0_group(pkey->pkey.ec);
+ if (!grp)
+ return X509_V_ERR_SUITE_B_INVALID_ALGORITHM;
+ curve_nid = EC_GROUP_get_curve_name(grp);
+ /* Check curve is consistent with LOS */
+ if (curve_nid == NID_secp384r1) /* P-384 */
+ {
+ /* Check signature algorithm is consistent with
+ * curve.
+ */
+ if (sign_nid != -1 && sign_nid != NID_ecdsa_with_SHA384)
+ return X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM;
+ if (!(*pflags & X509_V_FLAG_SUITEB_192_LOS))
+ return X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED;
+ /* If we encounter P-384 we cannot use P-256 later */
+ *pflags &= ~X509_V_FLAG_SUITEB_128_LOS_ONLY;
+ }
+ else if (curve_nid == NID_X9_62_prime256v1) /* P-256 */
+ {
+ if (sign_nid != -1 && sign_nid != NID_ecdsa_with_SHA256)
+ return X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM;
+ if (!(*pflags & X509_V_FLAG_SUITEB_128_LOS_ONLY))
+ return X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED;
+ }
+ else
+ return X509_V_ERR_SUITE_B_INVALID_CURVE;
+
+ return X509_V_OK;
+ }
+
+int X509_chain_check_suiteb(int *perror_depth, X509 *x, STACK_OF(X509) *chain,
+ unsigned long flags)
+ {
+ int rv, sign_nid;
+ size_t i;
+ EVP_PKEY *pk = NULL;
+ unsigned long tflags;
+ if (!(flags & X509_V_FLAG_SUITEB_128_LOS))
+ return X509_V_OK;
+ tflags = flags;
+ /* If no EE certificate passed in must be first in chain */
+ if (x == NULL)
+ {
+ x = sk_X509_value(chain, 0);
+ i = 1;
+ }
+ else
+ i = 0;
+
+ if (X509_get_version(x) != 2)
+ {
+ rv = X509_V_ERR_SUITE_B_INVALID_VERSION;
+ /* Correct error depth */
+ i = 0;
+ goto end;
+ }
+
+ pk = X509_get_pubkey(x);
+ /* Check EE key only */
+ rv = check_suite_b(pk, -1, &tflags);
+ if (rv != X509_V_OK)
+ {
+ /* Correct error depth */
+ i = 0;
+ goto end;
+ }
+ for(; i < sk_X509_num(chain); i++)
+ {
+ sign_nid = X509_get_signature_nid(x);
+ x = sk_X509_value(chain, i);
+ if (X509_get_version(x) != 2)
+ {
+ rv = X509_V_ERR_SUITE_B_INVALID_VERSION;
+ goto end;
+ }
+ EVP_PKEY_free(pk);
+ pk = X509_get_pubkey(x);
+ rv = check_suite_b(pk, sign_nid, &tflags);
+ if (rv != X509_V_OK)
+ goto end;
+ }
+
+ /* Final check: root CA signature */
+ rv = check_suite_b(pk, X509_get_signature_nid(x), &tflags);
+ end:
+ if (pk)
+ EVP_PKEY_free(pk);
+ if (rv != X509_V_OK)
+ {
+ /* Invalid signature or LOS errors are for previous cert */
+ if ((rv == X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM
+ || rv == X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED) && i)
+ i--;
+ /* If we have LOS error and flags changed then we are signing
+ * P-384 with P-256. Use more meaninggul error.
+ */
+ if (rv == X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED && flags != tflags)
+ rv = X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256;
+ if (perror_depth)
+ *perror_depth = i;
+ }
+ return rv;
+ }
+
+int X509_CRL_check_suiteb(X509_CRL *crl, EVP_PKEY *pk, unsigned long flags)
+ {
+ int sign_nid;
+ if (!(flags & X509_V_FLAG_SUITEB_128_LOS))
+ return X509_V_OK;
+ sign_nid = OBJ_obj2nid(crl->crl->sig_alg->algorithm);
+ return check_suite_b(pk, sign_nid, &flags);
+ }
+
+#else
+int X509_chain_check_suiteb(int *perror_depth, X509 *x, STACK_OF(X509) *chain,
+ unsigned long flags)
+ {
+ return 0;
+ }
+
+int X509_CRL_check_suiteb(X509_CRL *crl, EVP_PKEY *pk, unsigned long flags)
+ {
+ return 0;
+ }
+
+#endif
+/* Not strictly speaking an "up_ref" as a STACK doesn't have a reference
+ * count but it has the same effect by duping the STACK and upping the ref
+ * of each X509 structure.
+ */
+STACK_OF(X509) *X509_chain_up_ref(STACK_OF(X509) *chain)
+ {
+ STACK_OF(X509) *ret;
+ size_t i;
+ ret = sk_X509_dup(chain);
+ for (i = 0; i < sk_X509_num(ret); i++)
+ {
+ X509 *x = sk_X509_value(ret, i);
+ CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
+ }
+ return ret;
+ }
diff --git a/crypto/x509/x509_d2.c b/crypto/x509/x509_d2.c
new file mode 100644
index 0000000..2161d85
--- /dev/null
+++ b/crypto/x509/x509_d2.c
@@ -0,0 +1,105 @@
+/* crypto/x509/x509_d2.c */
+/* 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/err.h>
+#include <openssl/x509.h>
+
+
+#ifndef OPENSSL_NO_STDIO
+int X509_STORE_set_default_paths(X509_STORE *ctx)
+ {
+ X509_LOOKUP *lookup;
+
+ lookup=X509_STORE_add_lookup(ctx,X509_LOOKUP_file());
+ if (lookup == NULL) return(0);
+ X509_LOOKUP_load_file(lookup,NULL,X509_FILETYPE_DEFAULT);
+
+ lookup=X509_STORE_add_lookup(ctx,X509_LOOKUP_hash_dir());
+ if (lookup == NULL) return(0);
+ X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT);
+
+ /* clear any errors */
+ ERR_clear_error();
+
+ return(1);
+ }
+
+int X509_STORE_load_locations(X509_STORE *ctx, const char *file,
+ const char *path)
+ {
+ X509_LOOKUP *lookup;
+
+ if (file != NULL)
+ {
+ lookup=X509_STORE_add_lookup(ctx,X509_LOOKUP_file());
+ if (lookup == NULL) return(0);
+ if (X509_LOOKUP_load_file(lookup,file,X509_FILETYPE_PEM) != 1)
+ return(0);
+ }
+ if (path != NULL)
+ {
+ lookup=X509_STORE_add_lookup(ctx,X509_LOOKUP_hash_dir());
+ if (lookup == NULL) return(0);
+ if (X509_LOOKUP_add_dir(lookup,path,X509_FILETYPE_PEM) != 1)
+ return(0);
+ }
+ if ((path == NULL) && (file == NULL))
+ return(0);
+ return(1);
+ }
+
+#endif
diff --git a/crypto/x509/x509_def.c b/crypto/x509/x509_def.c
new file mode 100644
index 0000000..dbae289
--- /dev/null
+++ b/crypto/x509/x509_def.c
@@ -0,0 +1,88 @@
+/* crypto/x509/x509_def.c */
+/* 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/x509.h>
+
+
+/* TODO(fork): cleanup */
+
+#define OPENSSLDIR "/etc/ssl"
+#define X509_CERT_AREA OPENSSLDIR
+#define X509_CERT_DIR OPENSSLDIR "/certs"
+#define X509_CERT_FILE OPENSSLDIR "/cert.pem"
+#define X509_PRIVATE_DIR OPENSSLDIR "/private"
+#define X509_CERT_DIR_EVP "SSL_CERT_DIR"
+#define X509_CERT_FILE_EVP "SSL_CERT_FILE"
+
+const char *X509_get_default_private_dir(void)
+ { return(X509_PRIVATE_DIR); }
+
+const char *X509_get_default_cert_area(void)
+ { return(X509_CERT_AREA); }
+
+const char *X509_get_default_cert_dir(void)
+ { return(X509_CERT_DIR); }
+
+const char *X509_get_default_cert_file(void)
+ { return(X509_CERT_FILE); }
+
+const char *X509_get_default_cert_dir_env(void)
+ { return(X509_CERT_DIR_EVP); }
+
+const char *X509_get_default_cert_file_env(void)
+ { return(X509_CERT_FILE_EVP); }
+
diff --git a/crypto/x509/x509_error.c b/crypto/x509/x509_error.c
new file mode 100644
index 0000000..53d2faf
--- /dev/null
+++ b/crypto/x509/x509_error.c
@@ -0,0 +1,125 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/err.h>
+
+#include "x509.h"
+
+const ERR_STRING_DATA X509_error_string_data[] = {
+ {ERR_PACK(ERR_LIB_X509, X509_F_ASN1_digest, 0), "ASN1_digest"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_ASN1_generate_v3, 0), "ASN1_generate_v3"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_ASN1_item_sign_ctx, 0), "ASN1_item_sign_ctx"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_ASN1_item_verify, 0), "ASN1_item_verify"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_ASN1_sign, 0), "ASN1_sign"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_NETSCAPE_SPKI_b64_decode, 0), "NETSCAPE_SPKI_b64_decode"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_NETSCAPE_SPKI_b64_encode, 0), "NETSCAPE_SPKI_b64_encode"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_PKCS7_get_certificates, 0), "PKCS7_get_certificates"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_ATTRIBUTE_create_by_NID, 0), "X509_ATTRIBUTE_create_by_NID"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_ATTRIBUTE_create_by_OBJ, 0), "X509_ATTRIBUTE_create_by_OBJ"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_ATTRIBUTE_create_by_txt, 0), "X509_ATTRIBUTE_create_by_txt"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_ATTRIBUTE_get0_data, 0), "X509_ATTRIBUTE_get0_data"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_ATTRIBUTE_set1_data, 0), "X509_ATTRIBUTE_set1_data"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_CRL_add0_revoked, 0), "X509_CRL_add0_revoked"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_CRL_diff, 0), "X509_CRL_diff"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_CRL_print_fp, 0), "X509_CRL_print_fp"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_EXTENSION_create_by_NID, 0), "X509_EXTENSION_create_by_NID"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_EXTENSION_create_by_OBJ, 0), "X509_EXTENSION_create_by_OBJ"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_INFO_new, 0), "X509_INFO_new"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_NAME_ENTRY_create_by_NID, 0), "X509_NAME_ENTRY_create_by_NID"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_NAME_ENTRY_create_by_txt, 0), "X509_NAME_ENTRY_create_by_txt"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_NAME_ENTRY_set_object, 0), "X509_NAME_ENTRY_set_object"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_NAME_add_entry, 0), "X509_NAME_add_entry"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_NAME_oneline, 0), "X509_NAME_oneline"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_NAME_print, 0), "X509_NAME_print"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_PKEY_new, 0), "X509_PKEY_new"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_PUBKEY_get, 0), "X509_PUBKEY_get"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_PUBKEY_set, 0), "X509_PUBKEY_set"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_REQ_check_private_key, 0), "X509_REQ_check_private_key"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_REQ_to_X509, 0), "X509_REQ_to_X509"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_STORE_CTX_get1_issuer, 0), "X509_STORE_CTX_get1_issuer"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_STORE_CTX_init, 0), "X509_STORE_CTX_init"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_STORE_CTX_new, 0), "X509_STORE_CTX_new"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_STORE_CTX_purpose_inherit, 0), "X509_STORE_CTX_purpose_inherit"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_STORE_add_cert, 0), "X509_STORE_add_cert"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_STORE_add_crl, 0), "X509_STORE_add_crl"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_TRUST_add, 0), "X509_TRUST_add"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_TRUST_set, 0), "X509_TRUST_set"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_check_private_key, 0), "X509_check_private_key"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_get_pubkey_parameters, 0), "X509_get_pubkey_parameters"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_load_cert_crl_file, 0), "X509_load_cert_crl_file"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_load_cert_file, 0), "X509_load_cert_file"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_load_crl_file, 0), "X509_load_crl_file"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_print_ex_fp, 0), "X509_print_ex_fp"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_to_X509_REQ, 0), "X509_to_X509_REQ"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509_verify_cert, 0), "X509_verify_cert"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509at_add1_attr, 0), "X509at_add1_attr"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_X509v3_add_ext, 0), "X509v3_add_ext"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_add_cert_dir, 0), "add_cert_dir"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_append_exp, 0), "append_exp"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_asn1_cb, 0), "asn1_cb"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_asn1_str2type, 0), "asn1_str2type"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_bitstr_cb, 0), "bitstr_cb"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_by_file_ctrl, 0), "by_file_ctrl"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_check_policy, 0), "check_policy"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_d2i_X509_PKEY, 0), "d2i_X509_PKEY"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_dir_ctrl, 0), "dir_ctrl"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_get_cert_by_subject, 0), "get_cert_by_subject"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_i2d_DSA_PUBKEY, 0), "i2d_DSA_PUBKEY"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_i2d_EC_PUBKEY, 0), "i2d_EC_PUBKEY"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_i2d_PrivateKey, 0), "i2d_PrivateKey"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_i2d_RSA_PUBKEY, 0), "i2d_RSA_PUBKEY"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_parse_tagging, 0), "parse_tagging"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_x509_name_encode, 0), "x509_name_encode"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_x509_name_ex_d2i, 0), "x509_name_ex_d2i"},
+ {ERR_PACK(ERR_LIB_X509, X509_F_x509_name_ex_new, 0), "x509_name_ex_new"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_AKID_MISMATCH), "AKID_MISMATCH"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_BAD_PKCS7_VERSION), "BAD_PKCS7_VERSION"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_BAD_X509_FILETYPE), "BAD_X509_FILETYPE"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_BASE64_DECODE_ERROR), "BASE64_DECODE_ERROR"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_CANT_CHECK_DH_KEY), "CANT_CHECK_DH_KEY"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_CERT_ALREADY_IN_HASH_TABLE), "CERT_ALREADY_IN_HASH_TABLE"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_CONTEXT_NOT_INITIALISED), "CONTEXT_NOT_INITIALISED"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_CRL_ALREADY_DELTA), "CRL_ALREADY_DELTA"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_CRL_VERIFY_FAILURE), "CRL_VERIFY_FAILURE"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED), "DIGEST_AND_KEY_TYPE_NOT_SUPPORTED"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_ERR_ASN1_LIB), "ERR_ASN1_LIB"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_IDP_MISMATCH), "IDP_MISMATCH"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_INVALID_DIRECTORY), "INVALID_DIRECTORY"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_INVALID_FIELD_NAME), "INVALID_FIELD_NAME"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_INVALID_TRUST), "INVALID_TRUST"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_ISSUER_MISMATCH), "ISSUER_MISMATCH"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_KEY_TYPE_MISMATCH), "KEY_TYPE_MISMATCH"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_KEY_VALUES_MISMATCH), "KEY_VALUES_MISMATCH"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_LOADING_CERT_DIR), "LOADING_CERT_DIR"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_LOADING_DEFAULTS), "LOADING_DEFAULTS"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_METHOD_NOT_SUPPORTED), "METHOD_NOT_SUPPORTED"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_NEWER_CRL_NOT_NEWER), "NEWER_CRL_NOT_NEWER"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_NOT_PKCS7_SIGNED_DATA), "NOT_PKCS7_SIGNED_DATA"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_NO_CERTIFICATES_INCLUDED), "NO_CERTIFICATES_INCLUDED"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY), "NO_CERT_SET_FOR_US_TO_VERIFY"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_NO_CRL_NUMBER), "NO_CRL_NUMBER"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_PUBLIC_KEY_DECODE_ERROR), "PUBLIC_KEY_DECODE_ERROR"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_PUBLIC_KEY_ENCODE_ERROR), "PUBLIC_KEY_ENCODE_ERROR"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_SHOULD_RETRY), "SHOULD_RETRY"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN), "UNABLE_TO_FIND_PARAMETERS_IN_CHAIN"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY), "UNABLE_TO_GET_CERTS_PUBLIC_KEY"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_UNKNOWN_KEY_TYPE), "UNKNOWN_KEY_TYPE"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_UNKNOWN_NID), "UNKNOWN_NID"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_UNKNOWN_PURPOSE_ID), "UNKNOWN_PURPOSE_ID"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_UNKNOWN_TRUST_ID), "UNKNOWN_TRUST_ID"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_UNSUPPORTED_ALGORITHM), "UNSUPPORTED_ALGORITHM"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_WRONG_LOOKUP_TYPE), "WRONG_LOOKUP_TYPE"},
+ {ERR_PACK(ERR_LIB_X509, 0, X509_R_WRONG_TYPE), "WRONG_TYPE"},
+ {0, NULL},
+};
diff --git a/crypto/x509/x509_ext.c b/crypto/x509/x509_ext.c
new file mode 100644
index 0000000..2f1e0c5
--- /dev/null
+++ b/crypto/x509/x509_ext.c
@@ -0,0 +1,206 @@
+/* crypto/x509/x509_ext.c */
+/* 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/asn1.h>
+#include <openssl/evp.h>
+#include <openssl/obj.h>
+#include <openssl/stack.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+
+int X509_CRL_get_ext_count(X509_CRL *x)
+ {
+ return(X509v3_get_ext_count(x->crl->extensions));
+ }
+
+int X509_CRL_get_ext_by_NID(X509_CRL *x, int nid, int lastpos)
+ {
+ return(X509v3_get_ext_by_NID(x->crl->extensions,nid,lastpos));
+ }
+
+int X509_CRL_get_ext_by_OBJ(X509_CRL *x, ASN1_OBJECT *obj, int lastpos)
+ {
+ return(X509v3_get_ext_by_OBJ(x->crl->extensions,obj,lastpos));
+ }
+
+int X509_CRL_get_ext_by_critical(X509_CRL *x, int crit, int lastpos)
+ {
+ return(X509v3_get_ext_by_critical(x->crl->extensions,crit,lastpos));
+ }
+
+X509_EXTENSION *X509_CRL_get_ext(X509_CRL *x, int loc)
+ {
+ return(X509v3_get_ext(x->crl->extensions,loc));
+ }
+
+X509_EXTENSION *X509_CRL_delete_ext(X509_CRL *x, int loc)
+ {
+ return(X509v3_delete_ext(x->crl->extensions,loc));
+ }
+
+void *X509_CRL_get_ext_d2i(X509_CRL *x, int nid, int *crit, int *idx)
+{
+ return X509V3_get_d2i(x->crl->extensions, nid, crit, idx);
+}
+
+int X509_CRL_add1_ext_i2d(X509_CRL *x, int nid, void *value, int crit,
+ unsigned long flags)
+{
+ return X509V3_add1_i2d(&x->crl->extensions, nid, value, crit, flags);
+}
+
+int X509_CRL_add_ext(X509_CRL *x, X509_EXTENSION *ex, int loc)
+ {
+ return(X509v3_add_ext(&(x->crl->extensions),ex,loc) != NULL);
+ }
+
+int X509_get_ext_count(X509 *x)
+ {
+ return(X509v3_get_ext_count(x->cert_info->extensions));
+ }
+
+int X509_get_ext_by_NID(X509 *x, int nid, int lastpos)
+ {
+ return(X509v3_get_ext_by_NID(x->cert_info->extensions,nid,lastpos));
+ }
+
+int X509_get_ext_by_OBJ(X509 *x, ASN1_OBJECT *obj, int lastpos)
+ {
+ return(X509v3_get_ext_by_OBJ(x->cert_info->extensions,obj,lastpos));
+ }
+
+int X509_get_ext_by_critical(X509 *x, int crit, int lastpos)
+ {
+ return(X509v3_get_ext_by_critical(x->cert_info->extensions,crit,lastpos));
+ }
+
+X509_EXTENSION *X509_get_ext(X509 *x, int loc)
+ {
+ return(X509v3_get_ext(x->cert_info->extensions,loc));
+ }
+
+X509_EXTENSION *X509_delete_ext(X509 *x, int loc)
+ {
+ return(X509v3_delete_ext(x->cert_info->extensions,loc));
+ }
+
+int X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc)
+ {
+ return(X509v3_add_ext(&(x->cert_info->extensions),ex,loc) != NULL);
+ }
+
+void *X509_get_ext_d2i(X509 *x, int nid, int *crit, int *idx)
+{
+ return X509V3_get_d2i(x->cert_info->extensions, nid, crit, idx);
+}
+
+int X509_add1_ext_i2d(X509 *x, int nid, void *value, int crit,
+ unsigned long flags)
+{
+ return X509V3_add1_i2d(&x->cert_info->extensions, nid, value, crit,
+ flags);
+}
+
+int X509_REVOKED_get_ext_count(X509_REVOKED *x)
+ {
+ return(X509v3_get_ext_count(x->extensions));
+ }
+
+int X509_REVOKED_get_ext_by_NID(X509_REVOKED *x, int nid, int lastpos)
+ {
+ return(X509v3_get_ext_by_NID(x->extensions,nid,lastpos));
+ }
+
+int X509_REVOKED_get_ext_by_OBJ(X509_REVOKED *x, ASN1_OBJECT *obj,
+ int lastpos)
+ {
+ return(X509v3_get_ext_by_OBJ(x->extensions,obj,lastpos));
+ }
+
+int X509_REVOKED_get_ext_by_critical(X509_REVOKED *x, int crit, int lastpos)
+ {
+ return(X509v3_get_ext_by_critical(x->extensions,crit,lastpos));
+ }
+
+X509_EXTENSION *X509_REVOKED_get_ext(X509_REVOKED *x, int loc)
+ {
+ return(X509v3_get_ext(x->extensions,loc));
+ }
+
+X509_EXTENSION *X509_REVOKED_delete_ext(X509_REVOKED *x, int loc)
+ {
+ return(X509v3_delete_ext(x->extensions,loc));
+ }
+
+int X509_REVOKED_add_ext(X509_REVOKED *x, X509_EXTENSION *ex, int loc)
+ {
+ return(X509v3_add_ext(&(x->extensions),ex,loc) != NULL);
+ }
+
+void *X509_REVOKED_get_ext_d2i(X509_REVOKED *x, int nid, int *crit, int *idx)
+{
+ return X509V3_get_d2i(x->extensions, nid, crit, idx);
+}
+
+int X509_REVOKED_add1_ext_i2d(X509_REVOKED *x, int nid, void *value, int crit,
+ unsigned long flags)
+{
+ return X509V3_add1_i2d(&x->extensions, nid, value, crit, flags);
+}
+
+IMPLEMENT_ASN1_SET_OF(X509_EXTENSION)
diff --git a/crypto/x509/x509_lu.c b/crypto/x509/x509_lu.c
new file mode 100644
index 0000000..3cf2d81
--- /dev/null
+++ b/crypto/x509/x509_lu.c
@@ -0,0 +1,742 @@
+/* crypto/x509/x509_lu.c */
+/* 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/err.h>
+#include <openssl/lhash.h>
+#include <openssl/mem.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+
+X509_LOOKUP *X509_LOOKUP_new(X509_LOOKUP_METHOD *method)
+ {
+ X509_LOOKUP *ret;
+
+ ret=(X509_LOOKUP *)OPENSSL_malloc(sizeof(X509_LOOKUP));
+ if (ret == NULL) return NULL;
+
+ ret->init=0;
+ ret->skip=0;
+ ret->method=method;
+ ret->method_data=NULL;
+ ret->store_ctx=NULL;
+ if ((method->new_item != NULL) && !method->new_item(ret))
+ {
+ OPENSSL_free(ret);
+ return NULL;
+ }
+ return ret;
+ }
+
+void X509_LOOKUP_free(X509_LOOKUP *ctx)
+ {
+ if (ctx == NULL) return;
+ if ( (ctx->method != NULL) &&
+ (ctx->method->free != NULL))
+ (*ctx->method->free)(ctx);
+ OPENSSL_free(ctx);
+ }
+
+int X509_LOOKUP_init(X509_LOOKUP *ctx)
+ {
+ if (ctx->method == NULL) return 0;
+ if (ctx->method->init != NULL)
+ return ctx->method->init(ctx);
+ else
+ return 1;
+ }
+
+int X509_LOOKUP_shutdown(X509_LOOKUP *ctx)
+ {
+ if (ctx->method == NULL) return 0;
+ if (ctx->method->shutdown != NULL)
+ return ctx->method->shutdown(ctx);
+ else
+ return 1;
+ }
+
+int X509_LOOKUP_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc, long argl,
+ char **ret)
+ {
+ if (ctx->method == NULL) return -1;
+ if (ctx->method->ctrl != NULL)
+ return ctx->method->ctrl(ctx,cmd,argc,argl,ret);
+ else
+ return 1;
+ }
+
+int X509_LOOKUP_by_subject(X509_LOOKUP *ctx, int type, X509_NAME *name,
+ X509_OBJECT *ret)
+ {
+ if ((ctx->method == NULL) || (ctx->method->get_by_subject == NULL))
+ return X509_LU_FAIL;
+ if (ctx->skip) return 0;
+ return ctx->method->get_by_subject(ctx,type,name,ret);
+ }
+
+int X509_LOOKUP_by_issuer_serial(X509_LOOKUP *ctx, int type, X509_NAME *name,
+ ASN1_INTEGER *serial, X509_OBJECT *ret)
+ {
+ if ((ctx->method == NULL) ||
+ (ctx->method->get_by_issuer_serial == NULL))
+ return X509_LU_FAIL;
+ return ctx->method->get_by_issuer_serial(ctx,type,name,serial,ret);
+ }
+
+int X509_LOOKUP_by_fingerprint(X509_LOOKUP *ctx, int type,
+ unsigned char *bytes, int len, X509_OBJECT *ret)
+ {
+ if ((ctx->method == NULL) || (ctx->method->get_by_fingerprint == NULL))
+ return X509_LU_FAIL;
+ return ctx->method->get_by_fingerprint(ctx,type,bytes,len,ret);
+ }
+
+int X509_LOOKUP_by_alias(X509_LOOKUP *ctx, int type, char *str, int len,
+ X509_OBJECT *ret)
+ {
+ if ((ctx->method == NULL) || (ctx->method->get_by_alias == NULL))
+ return X509_LU_FAIL;
+ return ctx->method->get_by_alias(ctx,type,str,len,ret);
+ }
+
+
+static int x509_object_cmp(const X509_OBJECT **a, const X509_OBJECT **b)
+ {
+ int ret;
+
+ ret=((*a)->type - (*b)->type);
+ if (ret) return ret;
+ switch ((*a)->type)
+ {
+ case X509_LU_X509:
+ ret=X509_subject_name_cmp((*a)->data.x509,(*b)->data.x509);
+ break;
+ case X509_LU_CRL:
+ ret=X509_CRL_cmp((*a)->data.crl,(*b)->data.crl);
+ break;
+ default:
+ /* abort(); */
+ return 0;
+ }
+ return ret;
+ }
+
+X509_STORE *X509_STORE_new(void)
+ {
+ X509_STORE *ret;
+
+ if ((ret=(X509_STORE *)OPENSSL_malloc(sizeof(X509_STORE))) == NULL)
+ return NULL;
+ ret->objs = sk_X509_OBJECT_new(x509_object_cmp);
+ ret->cache=1;
+ ret->get_cert_methods=sk_X509_LOOKUP_new_null();
+ ret->verify=0;
+ ret->verify_cb=0;
+
+ if ((ret->param = X509_VERIFY_PARAM_new()) == NULL)
+ return NULL;
+
+ ret->get_issuer = 0;
+ ret->check_issued = 0;
+ ret->check_revocation = 0;
+ ret->get_crl = 0;
+ ret->check_crl = 0;
+ ret->cert_crl = 0;
+ ret->lookup_certs = 0;
+ ret->lookup_crls = 0;
+ ret->cleanup = 0;
+
+ if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_X509_STORE, ret, &ret->ex_data))
+ {
+ sk_X509_OBJECT_free(ret->objs);
+ OPENSSL_free(ret);
+ return NULL;
+ }
+
+ ret->references=1;
+ return ret;
+ }
+
+static void cleanup(X509_OBJECT *a)
+ {
+ if (a->type == X509_LU_X509)
+ {
+ X509_free(a->data.x509);
+ }
+ else if (a->type == X509_LU_CRL)
+ {
+ X509_CRL_free(a->data.crl);
+ }
+ else
+ {
+ /* abort(); */
+ }
+
+ OPENSSL_free(a);
+ }
+
+void X509_STORE_free(X509_STORE *vfy)
+ {
+ int i;
+ size_t j;
+ STACK_OF(X509_LOOKUP) *sk;
+ X509_LOOKUP *lu;
+
+ if (vfy == NULL)
+ return;
+
+ i=CRYPTO_add(&vfy->references,-1,CRYPTO_LOCK_X509_STORE);
+#ifdef REF_PRINT
+ REF_PRINT("X509_STORE",vfy);
+#endif
+ if (i > 0) return;
+#ifdef REF_CHECK
+ if (i < 0)
+ {
+ fprintf(stderr,"X509_STORE_free, bad reference count\n");
+ abort(); /* ok */
+ }
+#endif
+
+ sk=vfy->get_cert_methods;
+ for (j=0; j<sk_X509_LOOKUP_num(sk); j++)
+ {
+ lu=sk_X509_LOOKUP_value(sk,j);
+ X509_LOOKUP_shutdown(lu);
+ X509_LOOKUP_free(lu);
+ }
+ sk_X509_LOOKUP_free(sk);
+ sk_X509_OBJECT_pop_free(vfy->objs, cleanup);
+
+ CRYPTO_free_ex_data(CRYPTO_EX_INDEX_X509_STORE, vfy, &vfy->ex_data);
+ if (vfy->param)
+ X509_VERIFY_PARAM_free(vfy->param);
+ OPENSSL_free(vfy);
+ }
+
+X509_LOOKUP *X509_STORE_add_lookup(X509_STORE *v, X509_LOOKUP_METHOD *m)
+ {
+ size_t i;
+ STACK_OF(X509_LOOKUP) *sk;
+ X509_LOOKUP *lu;
+
+ sk=v->get_cert_methods;
+ for (i=0; i<sk_X509_LOOKUP_num(sk); i++)
+ {
+ lu=sk_X509_LOOKUP_value(sk,i);
+ if (m == lu->method)
+ {
+ return lu;
+ }
+ }
+ /* a new one */
+ lu=X509_LOOKUP_new(m);
+ if (lu == NULL)
+ return NULL;
+ else
+ {
+ lu->store_ctx=v;
+ if (sk_X509_LOOKUP_push(v->get_cert_methods,lu))
+ return lu;
+ else
+ {
+ X509_LOOKUP_free(lu);
+ return NULL;
+ }
+ }
+ }
+
+int X509_STORE_get_by_subject(X509_STORE_CTX *vs, int type, X509_NAME *name,
+ X509_OBJECT *ret)
+ {
+ X509_STORE *ctx=vs->ctx;
+ X509_LOOKUP *lu;
+ X509_OBJECT stmp,*tmp;
+ int i,j;
+
+ CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
+ tmp=X509_OBJECT_retrieve_by_subject(ctx->objs,type,name);
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
+
+ if (tmp == NULL || type == X509_LU_CRL)
+ {
+ for (i=vs->current_method; i<(int)sk_X509_LOOKUP_num(ctx->get_cert_methods); i++)
+ {
+ lu=sk_X509_LOOKUP_value(ctx->get_cert_methods,i);
+ j=X509_LOOKUP_by_subject(lu,type,name,&stmp);
+ if (j < 0)
+ {
+ vs->current_method=j;
+ return j;
+ }
+ else if (j)
+ {
+ tmp= &stmp;
+ break;
+ }
+ }
+ vs->current_method=0;
+ if (tmp == NULL)
+ return 0;
+ }
+
+/* if (ret->data.ptr != NULL)
+ X509_OBJECT_free_contents(ret); */
+
+ ret->type=tmp->type;
+ ret->data.ptr=tmp->data.ptr;
+
+ X509_OBJECT_up_ref_count(ret);
+
+ return 1;
+ }
+
+int X509_STORE_add_cert(X509_STORE *ctx, X509 *x)
+ {
+ X509_OBJECT *obj;
+ int ret=1;
+
+ if (x == NULL) return 0;
+ obj=(X509_OBJECT *)OPENSSL_malloc(sizeof(X509_OBJECT));
+ if (obj == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_STORE_add_cert, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ obj->type=X509_LU_X509;
+ obj->data.x509=x;
+
+ CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
+
+ X509_OBJECT_up_ref_count(obj);
+
+ if (X509_OBJECT_retrieve_match(ctx->objs, obj))
+ {
+ X509_OBJECT_free_contents(obj);
+ OPENSSL_free(obj);
+ OPENSSL_PUT_ERROR(X509, X509_STORE_add_cert, X509_R_CERT_ALREADY_IN_HASH_TABLE);
+ ret=0;
+ }
+ else sk_X509_OBJECT_push(ctx->objs, obj);
+
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
+
+ return ret;
+ }
+
+int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x)
+ {
+ X509_OBJECT *obj;
+ int ret=1;
+
+ if (x == NULL) return 0;
+ obj=(X509_OBJECT *)OPENSSL_malloc(sizeof(X509_OBJECT));
+ if (obj == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_STORE_add_crl, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ obj->type=X509_LU_CRL;
+ obj->data.crl=x;
+
+ CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
+
+ X509_OBJECT_up_ref_count(obj);
+
+ if (X509_OBJECT_retrieve_match(ctx->objs, obj))
+ {
+ X509_OBJECT_free_contents(obj);
+ OPENSSL_free(obj);
+ OPENSSL_PUT_ERROR(X509, X509_STORE_add_crl, X509_R_CERT_ALREADY_IN_HASH_TABLE);
+ ret=0;
+ }
+ else sk_X509_OBJECT_push(ctx->objs, obj);
+
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
+
+ return ret;
+ }
+
+void X509_OBJECT_up_ref_count(X509_OBJECT *a)
+ {
+ switch (a->type)
+ {
+ case X509_LU_X509:
+ CRYPTO_add(&a->data.x509->references,1,CRYPTO_LOCK_X509);
+ break;
+ case X509_LU_CRL:
+ CRYPTO_add(&a->data.crl->references,1,CRYPTO_LOCK_X509_CRL);
+ break;
+ }
+ }
+
+void X509_OBJECT_free_contents(X509_OBJECT *a)
+ {
+ switch (a->type)
+ {
+ case X509_LU_X509:
+ X509_free(a->data.x509);
+ break;
+ case X509_LU_CRL:
+ X509_CRL_free(a->data.crl);
+ break;
+ }
+ }
+
+static int x509_object_idx_cnt(STACK_OF(X509_OBJECT) *h, int type,
+ X509_NAME *name, int *pnmatch)
+ {
+ X509_OBJECT stmp;
+ X509 x509_s;
+ X509_CINF cinf_s;
+ X509_CRL crl_s;
+ X509_CRL_INFO crl_info_s;
+ size_t idx;
+
+ stmp.type=type;
+ switch (type)
+ {
+ case X509_LU_X509:
+ stmp.data.x509= &x509_s;
+ x509_s.cert_info= &cinf_s;
+ cinf_s.subject=name;
+ break;
+ case X509_LU_CRL:
+ stmp.data.crl= &crl_s;
+ crl_s.crl= &crl_info_s;
+ crl_info_s.issuer=name;
+ break;
+ default:
+ /* abort(); */
+ return -1;
+ }
+
+ idx = -1;
+ if (sk_X509_OBJECT_find(h, &idx, &stmp) && pnmatch)
+ {
+ int tidx;
+ const X509_OBJECT *tobj, *pstmp;
+ *pnmatch = 1;
+ pstmp = &stmp;
+ for (tidx = idx + 1; tidx < (int)sk_X509_OBJECT_num(h); tidx++)
+ {
+ tobj = sk_X509_OBJECT_value(h, tidx);
+ if (x509_object_cmp(&tobj, &pstmp))
+ break;
+ (*pnmatch)++;
+ }
+ }
+
+ return idx;
+ }
+
+
+int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, int type,
+ X509_NAME *name)
+ {
+ return x509_object_idx_cnt(h, type, name, NULL);
+ }
+
+X509_OBJECT *X509_OBJECT_retrieve_by_subject(STACK_OF(X509_OBJECT) *h, int type,
+ X509_NAME *name)
+ {
+ int idx;
+ idx = X509_OBJECT_idx_by_subject(h, type, name);
+ if (idx==-1) return NULL;
+ return sk_X509_OBJECT_value(h, idx);
+ }
+
+STACK_OF(X509)* X509_STORE_get1_certs(X509_STORE_CTX *ctx, X509_NAME *nm)
+ {
+ int i, idx, cnt;
+ STACK_OF(X509) *sk;
+ X509 *x;
+ X509_OBJECT *obj;
+ sk = sk_X509_new_null();
+ CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
+ idx = x509_object_idx_cnt(ctx->ctx->objs, X509_LU_X509, nm, &cnt);
+ if (idx < 0)
+ {
+ /* Nothing found in cache: do lookup to possibly add new
+ * objects to cache
+ */
+ X509_OBJECT xobj;
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
+ if (!X509_STORE_get_by_subject(ctx, X509_LU_X509, nm, &xobj))
+ {
+ sk_X509_free(sk);
+ return NULL;
+ }
+ X509_OBJECT_free_contents(&xobj);
+ CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
+ idx = x509_object_idx_cnt(ctx->ctx->objs,X509_LU_X509,nm, &cnt);
+ if (idx < 0)
+ {
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
+ sk_X509_free(sk);
+ return NULL;
+ }
+ }
+ for (i = 0; i < cnt; i++, idx++)
+ {
+ obj = sk_X509_OBJECT_value(ctx->ctx->objs, idx);
+ x = obj->data.x509;
+ CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
+ if (!sk_X509_push(sk, x))
+ {
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
+ X509_free(x);
+ sk_X509_pop_free(sk, X509_free);
+ return NULL;
+ }
+ }
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
+ return sk;
+
+ }
+
+STACK_OF(X509_CRL)* X509_STORE_get1_crls(X509_STORE_CTX *ctx, X509_NAME *nm)
+ {
+ int i, idx, cnt;
+ STACK_OF(X509_CRL) *sk;
+ X509_CRL *x;
+ X509_OBJECT *obj, xobj;
+ sk = sk_X509_CRL_new_null();
+ CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
+ /* Check cache first */
+ idx = x509_object_idx_cnt(ctx->ctx->objs, X509_LU_CRL, nm, &cnt);
+
+ /* Always do lookup to possibly add new CRLs to cache
+ */
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
+ if (!X509_STORE_get_by_subject(ctx, X509_LU_CRL, nm, &xobj))
+ {
+ sk_X509_CRL_free(sk);
+ return NULL;
+ }
+ X509_OBJECT_free_contents(&xobj);
+ CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
+ idx = x509_object_idx_cnt(ctx->ctx->objs,X509_LU_CRL, nm, &cnt);
+ if (idx < 0)
+ {
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
+ sk_X509_CRL_free(sk);
+ return NULL;
+ }
+
+ for (i = 0; i < cnt; i++, idx++)
+ {
+ obj = sk_X509_OBJECT_value(ctx->ctx->objs, idx);
+ x = obj->data.crl;
+ CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509_CRL);
+ if (!sk_X509_CRL_push(sk, x))
+ {
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
+ X509_CRL_free(x);
+ sk_X509_CRL_pop_free(sk, X509_CRL_free);
+ return NULL;
+ }
+ }
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
+ return sk;
+ }
+
+X509_OBJECT *X509_OBJECT_retrieve_match(STACK_OF(X509_OBJECT) *h, X509_OBJECT *x)
+ {
+ size_t idx, i;
+ X509_OBJECT *obj;
+
+ if (!sk_X509_OBJECT_find(h, &idx, x)) {
+ return NULL;
+ }
+ if ((x->type != X509_LU_X509) && (x->type != X509_LU_CRL))
+ return sk_X509_OBJECT_value(h, idx);
+ for (i = idx; i < sk_X509_OBJECT_num(h); i++)
+ {
+ obj = sk_X509_OBJECT_value(h, i);
+ if (x509_object_cmp((const X509_OBJECT **)&obj, (const X509_OBJECT **)&x))
+ return NULL;
+ if (x->type == X509_LU_X509)
+ {
+ if (!X509_cmp(obj->data.x509, x->data.x509))
+ return obj;
+ }
+ else if (x->type == X509_LU_CRL)
+ {
+ if (!X509_CRL_match(obj->data.crl, x->data.crl))
+ return obj;
+ }
+ else
+ return obj;
+ }
+ return NULL;
+ }
+
+
+/* Try to get issuer certificate from store. Due to limitations
+ * of the API this can only retrieve a single certificate matching
+ * a given subject name. However it will fill the cache with all
+ * matching certificates, so we can examine the cache for all
+ * matches.
+ *
+ * Return values are:
+ * 1 lookup successful.
+ * 0 certificate not found.
+ * -1 some other error.
+ */
+int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x)
+ {
+ X509_NAME *xn;
+ X509_OBJECT obj, *pobj;
+ int ok, idx, ret;
+ size_t i;
+ xn=X509_get_issuer_name(x);
+ ok=X509_STORE_get_by_subject(ctx,X509_LU_X509,xn,&obj);
+ if (ok != X509_LU_X509)
+ {
+ if (ok == X509_LU_RETRY)
+ {
+ X509_OBJECT_free_contents(&obj);
+ OPENSSL_PUT_ERROR(X509, X509_STORE_CTX_get1_issuer, X509_R_SHOULD_RETRY);
+ return -1;
+ }
+ else if (ok != X509_LU_FAIL)
+ {
+ X509_OBJECT_free_contents(&obj);
+ /* not good :-(, break anyway */
+ return -1;
+ }
+ return 0;
+ }
+ /* If certificate matches all OK */
+ if (ctx->check_issued(ctx, x, obj.data.x509))
+ {
+ *issuer = obj.data.x509;
+ return 1;
+ }
+ X509_OBJECT_free_contents(&obj);
+
+ /* Else find index of first cert accepted by 'check_issued' */
+ ret = 0;
+ CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
+ idx = X509_OBJECT_idx_by_subject(ctx->ctx->objs, X509_LU_X509, xn);
+ if (idx != -1) /* should be true as we've had at least one match */
+ {
+ /* Look through all matching certs for suitable issuer */
+ for (i = idx; i < sk_X509_OBJECT_num(ctx->ctx->objs); i++)
+ {
+ pobj = sk_X509_OBJECT_value(ctx->ctx->objs, i);
+ /* See if we've run past the matches */
+ if (pobj->type != X509_LU_X509)
+ break;
+ if (X509_NAME_cmp(xn, X509_get_subject_name(pobj->data.x509)))
+ break;
+ if (ctx->check_issued(ctx, x, pobj->data.x509))
+ {
+ *issuer = pobj->data.x509;
+ X509_OBJECT_up_ref_count(pobj);
+ ret = 1;
+ break;
+ }
+ }
+ }
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
+ return ret;
+ }
+
+int X509_STORE_set_flags(X509_STORE *ctx, unsigned long flags)
+ {
+ return X509_VERIFY_PARAM_set_flags(ctx->param, flags);
+ }
+
+int X509_STORE_set_depth(X509_STORE *ctx, int depth)
+ {
+ X509_VERIFY_PARAM_set_depth(ctx->param, depth);
+ return 1;
+ }
+
+int X509_STORE_set_purpose(X509_STORE *ctx, int purpose)
+ {
+ return X509_VERIFY_PARAM_set_purpose(ctx->param, purpose);
+ }
+
+int X509_STORE_set_trust(X509_STORE *ctx, int trust)
+ {
+ return X509_VERIFY_PARAM_set_trust(ctx->param, trust);
+ }
+
+int X509_STORE_set1_param(X509_STORE *ctx, X509_VERIFY_PARAM *param)
+ {
+ return X509_VERIFY_PARAM_set1(ctx->param, param);
+ }
+
+void X509_STORE_set_verify_cb(X509_STORE *ctx,
+ int (*verify_cb)(int, X509_STORE_CTX *))
+ {
+ ctx->verify_cb = verify_cb;
+ }
+
+void X509_STORE_set_lookup_crls_cb(X509_STORE *ctx,
+ STACK_OF(X509_CRL)* (*cb)(X509_STORE_CTX *ctx, X509_NAME *nm))
+ {
+ ctx->lookup_crls = cb;
+ }
+
+X509_STORE *X509_STORE_CTX_get0_store(X509_STORE_CTX *ctx)
+ {
+ return ctx->ctx;
+ }
diff --git a/crypto/x509/x509_obj.c b/crypto/x509/x509_obj.c
new file mode 100644
index 0000000..434108c
--- /dev/null
+++ b/crypto/x509/x509_obj.c
@@ -0,0 +1,226 @@
+/* crypto/x509/x509_obj.c */
+/* 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/buf.h>
+#include <openssl/err.h>
+#include <openssl/lhash.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509.h>
+
+
+char *X509_NAME_oneline(X509_NAME *a, char *buf, int len)
+ {
+ X509_NAME_ENTRY *ne;
+ size_t i;
+ int n,lold,l,l1,l2,num,j,type;
+ const char *s;
+ char *p;
+ unsigned char *q;
+ BUF_MEM *b=NULL;
+ static const char hex[17]="0123456789ABCDEF";
+ int gs_doit[4];
+ char tmp_buf[80];
+#ifdef CHARSET_EBCDIC
+ char ebcdic_buf[1024];
+#endif
+
+ if (buf == NULL)
+ {
+ if ((b=BUF_MEM_new()) == NULL) goto err;
+ if (!BUF_MEM_grow(b,200)) goto err;
+ b->data[0]='\0';
+ len=200;
+ }
+ if (a == NULL)
+ {
+ if(b)
+ {
+ buf=b->data;
+ OPENSSL_free(b);
+ }
+ strncpy(buf,"NO X509_NAME",len);
+ buf[len-1]='\0';
+ return buf;
+ }
+
+ len--; /* space for '\0' */
+ l=0;
+ for (i=0; i<sk_X509_NAME_ENTRY_num(a->entries); i++)
+ {
+ ne=sk_X509_NAME_ENTRY_value(a->entries,i);
+ n=OBJ_obj2nid(ne->object);
+ if ((n == NID_undef) || ((s=OBJ_nid2sn(n)) == NULL))
+ {
+ i2t_ASN1_OBJECT(tmp_buf,sizeof(tmp_buf),ne->object);
+ s=tmp_buf;
+ }
+ l1=strlen(s);
+
+ type=ne->value->type;
+ num=ne->value->length;
+ q=ne->value->data;
+#ifdef CHARSET_EBCDIC
+ if (type == V_ASN1_GENERALSTRING ||
+ type == V_ASN1_VISIBLESTRING ||
+ type == V_ASN1_PRINTABLESTRING ||
+ type == V_ASN1_TELETEXSTRING ||
+ type == V_ASN1_VISIBLESTRING ||
+ type == V_ASN1_IA5STRING) {
+ ascii2ebcdic(ebcdic_buf, q,
+ (num > sizeof ebcdic_buf)
+ ? sizeof ebcdic_buf : num);
+ q=ebcdic_buf;
+ }
+#endif
+
+ if ((type == V_ASN1_GENERALSTRING) && ((num%4) == 0))
+ {
+ gs_doit[0]=gs_doit[1]=gs_doit[2]=gs_doit[3]=0;
+ for (j=0; j<num; j++)
+ if (q[j] != 0) gs_doit[j&3]=1;
+
+ if (gs_doit[0]|gs_doit[1]|gs_doit[2])
+ gs_doit[0]=gs_doit[1]=gs_doit[2]=gs_doit[3]=1;
+ else
+ {
+ gs_doit[0]=gs_doit[1]=gs_doit[2]=0;
+ gs_doit[3]=1;
+ }
+ }
+ else
+ gs_doit[0]=gs_doit[1]=gs_doit[2]=gs_doit[3]=1;
+
+ for (l2=j=0; j<num; j++)
+ {
+ if (!gs_doit[j&3]) continue;
+ l2++;
+#ifndef CHARSET_EBCDIC
+ if ((q[j] < ' ') || (q[j] > '~')) l2+=3;
+#else
+ if ((os_toascii[q[j]] < os_toascii[' ']) ||
+ (os_toascii[q[j]] > os_toascii['~'])) l2+=3;
+#endif
+ }
+
+ lold=l;
+ l+=1+l1+1+l2;
+ if (b != NULL)
+ {
+ if (!BUF_MEM_grow(b,l+1)) goto err;
+ p= &(b->data[lold]);
+ }
+ else if (l > len)
+ {
+ break;
+ }
+ else
+ p= &(buf[lold]);
+ *(p++)='/';
+ memcpy(p,s,(unsigned int)l1); p+=l1;
+ *(p++)='=';
+
+#ifndef CHARSET_EBCDIC /* q was assigned above already. */
+ q=ne->value->data;
+#endif
+
+ for (j=0; j<num; j++)
+ {
+ if (!gs_doit[j&3]) continue;
+#ifndef CHARSET_EBCDIC
+ n=q[j];
+ if ((n < ' ') || (n > '~'))
+ {
+ *(p++)='\\';
+ *(p++)='x';
+ *(p++)=hex[(n>>4)&0x0f];
+ *(p++)=hex[n&0x0f];
+ }
+ else
+ *(p++)=n;
+#else
+ n=os_toascii[q[j]];
+ if ((n < os_toascii[' ']) ||
+ (n > os_toascii['~']))
+ {
+ *(p++)='\\';
+ *(p++)='x';
+ *(p++)=hex[(n>>4)&0x0f];
+ *(p++)=hex[n&0x0f];
+ }
+ else
+ *(p++)=q[j];
+#endif
+ }
+ *p='\0';
+ }
+ if (b != NULL)
+ {
+ p=b->data;
+ OPENSSL_free(b);
+ }
+ else
+ p=buf;
+ if (i == 0)
+ *p = '\0';
+ return(p);
+err:
+ OPENSSL_PUT_ERROR(X509, X509_NAME_oneline, ERR_R_MALLOC_FAILURE);
+ if (b != NULL) BUF_MEM_free(b);
+ return(NULL);
+ }
+
diff --git a/crypto/x509/x509_r2x.c b/crypto/x509/x509_r2x.c
new file mode 100644
index 0000000..3c8e9c0
--- /dev/null
+++ b/crypto/x509/x509_r2x.c
@@ -0,0 +1,113 @@
+/* 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/asn1.h>
+#include <openssl/bn.h>
+#include <openssl/buf.h>
+#include <openssl/digest.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/obj.h>
+#include <openssl/x509.h>
+
+
+X509 *X509_REQ_to_X509(X509_REQ *r, int days, EVP_PKEY *pkey)
+ {
+ X509 *ret=NULL;
+ X509_CINF *xi=NULL;
+ X509_NAME *xn;
+
+ if ((ret=X509_new()) == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_REQ_to_X509, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* duplicate the request */
+ xi=ret->cert_info;
+
+ if (sk_X509_ATTRIBUTE_num(r->req_info->attributes) != 0)
+ {
+ if ((xi->version=M_ASN1_INTEGER_new()) == NULL) goto err;
+ if (!ASN1_INTEGER_set(xi->version,2)) goto err;
+/* xi->extensions=ri->attributes; <- bad, should not ever be done
+ ri->attributes=NULL; */
+ }
+
+ xn=X509_REQ_get_subject_name(r);
+ if (X509_set_subject_name(ret,X509_NAME_dup(xn)) == 0)
+ goto err;
+ if (X509_set_issuer_name(ret,X509_NAME_dup(xn)) == 0)
+ goto err;
+
+ if (X509_gmtime_adj(xi->validity->notBefore,0) == NULL)
+ goto err;
+ if (X509_gmtime_adj(xi->validity->notAfter,(long)60*60*24*days) == NULL)
+ goto err;
+
+ X509_set_pubkey(ret,X509_REQ_get_pubkey(r));
+
+ if (!X509_sign(ret,pkey,EVP_md5()))
+ goto err;
+ if (0)
+ {
+err:
+ X509_free(ret);
+ ret=NULL;
+ }
+ return(ret);
+ }
+
diff --git a/crypto/x509/x509_req.c b/crypto/x509/x509_req.c
new file mode 100644
index 0000000..ccaf729
--- /dev/null
+++ b/crypto/x509/x509_req.c
@@ -0,0 +1,316 @@
+/* crypto/x509/x509_req.c */
+/* 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/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/bn.h>
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/pem.h>
+#include <openssl/x509.h>
+
+
+X509_REQ *X509_to_X509_REQ(X509 *x, EVP_PKEY *pkey, const EVP_MD *md)
+ {
+ X509_REQ *ret;
+ X509_REQ_INFO *ri;
+ int i;
+ EVP_PKEY *pktmp;
+
+ ret=X509_REQ_new();
+ if (ret == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_to_X509_REQ, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ ri=ret->req_info;
+
+ ri->version->length=1;
+ ri->version->data=(unsigned char *)OPENSSL_malloc(1);
+ if (ri->version->data == NULL) goto err;
+ ri->version->data[0]=0; /* version == 0 */
+
+ if (!X509_REQ_set_subject_name(ret,X509_get_subject_name(x)))
+ goto err;
+
+ pktmp = X509_get_pubkey(x);
+ i=X509_REQ_set_pubkey(ret,pktmp);
+ EVP_PKEY_free(pktmp);
+ if (!i) goto err;
+
+ if (pkey != NULL)
+ {
+ if (!X509_REQ_sign(ret,pkey,md))
+ goto err;
+ }
+ return(ret);
+err:
+ X509_REQ_free(ret);
+ return(NULL);
+ }
+
+EVP_PKEY *X509_REQ_get_pubkey(X509_REQ *req)
+ {
+ if ((req == NULL) || (req->req_info == NULL))
+ return(NULL);
+ return(X509_PUBKEY_get(req->req_info->pubkey));
+ }
+
+int X509_REQ_check_private_key(X509_REQ *x, EVP_PKEY *k)
+ {
+ EVP_PKEY *xk=NULL;
+ int ok=0;
+
+ xk=X509_REQ_get_pubkey(x);
+ switch (EVP_PKEY_cmp(xk, k))
+ {
+ case 1:
+ ok=1;
+ break;
+ case 0:
+ OPENSSL_PUT_ERROR(X509, X509_REQ_check_private_key, X509_R_KEY_VALUES_MISMATCH);
+ break;
+ case -1:
+ OPENSSL_PUT_ERROR(X509, X509_REQ_check_private_key, X509_R_KEY_TYPE_MISMATCH);
+ break;
+ case -2:
+#ifndef OPENSSL_NO_EC
+ if (k->type == EVP_PKEY_EC)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_REQ_check_private_key, ERR_R_EC_LIB);
+ break;
+ }
+#endif
+#ifndef OPENSSL_NO_DH
+ if (k->type == EVP_PKEY_DH)
+ {
+ /* No idea */
+ OPENSSL_PUT_ERROR(X509, X509_REQ_check_private_key, X509_R_CANT_CHECK_DH_KEY);
+ break;
+ }
+#endif
+ OPENSSL_PUT_ERROR(X509, X509_REQ_check_private_key, X509_R_UNKNOWN_KEY_TYPE);
+ }
+
+ EVP_PKEY_free(xk);
+ return(ok);
+ }
+
+/* It seems several organisations had the same idea of including a list of
+ * extensions in a certificate request. There are at least two OIDs that are
+ * used and there may be more: so the list is configurable.
+ */
+
+static int ext_nid_list[] = { NID_ext_req, NID_ms_ext_req, NID_undef};
+
+static int *ext_nids = ext_nid_list;
+
+int X509_REQ_extension_nid(int req_nid)
+{
+ int i, nid;
+ for(i = 0; ; i++) {
+ nid = ext_nids[i];
+ if(nid == NID_undef) return 0;
+ else if (req_nid == nid) return 1;
+ }
+}
+
+int *X509_REQ_get_extension_nids(void)
+{
+ return ext_nids;
+}
+
+void X509_REQ_set_extension_nids(int *nids)
+{
+ ext_nids = nids;
+}
+
+STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(X509_REQ *req)
+ {
+ X509_ATTRIBUTE *attr;
+ ASN1_TYPE *ext = NULL;
+ int idx, *pnid;
+ const unsigned char *p;
+
+ if ((req == NULL) || (req->req_info == NULL) || !ext_nids)
+ return(NULL);
+ for (pnid = ext_nids; *pnid != NID_undef; pnid++)
+ {
+ idx = X509_REQ_get_attr_by_NID(req, *pnid, -1);
+ if (idx == -1)
+ continue;
+ attr = X509_REQ_get_attr(req, idx);
+ if(attr->single) ext = attr->value.single;
+ else if(sk_ASN1_TYPE_num(attr->value.set))
+ ext = sk_ASN1_TYPE_value(attr->value.set, 0);
+ break;
+ }
+ if(!ext || (ext->type != V_ASN1_SEQUENCE))
+ return NULL;
+ p = ext->value.sequence->data;
+ return (STACK_OF(X509_EXTENSION) *)
+ ASN1_item_d2i(NULL, &p, ext->value.sequence->length,
+ ASN1_ITEM_rptr(X509_EXTENSIONS));
+}
+
+/* Add a STACK_OF extensions to a certificate request: allow alternative OIDs
+ * in case we want to create a non standard one.
+ */
+
+int X509_REQ_add_extensions_nid(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts,
+ int nid)
+{
+ ASN1_TYPE *at = NULL;
+ X509_ATTRIBUTE *attr = NULL;
+ if(!(at = ASN1_TYPE_new()) ||
+ !(at->value.sequence = ASN1_STRING_new())) goto err;
+
+ at->type = V_ASN1_SEQUENCE;
+ /* Generate encoding of extensions */
+ at->value.sequence->length =
+ ASN1_item_i2d((ASN1_VALUE *)exts,
+ &at->value.sequence->data,
+ ASN1_ITEM_rptr(X509_EXTENSIONS));
+ if(!(attr = X509_ATTRIBUTE_new())) goto err;
+ if(!(attr->value.set = sk_ASN1_TYPE_new_null())) goto err;
+ if(!sk_ASN1_TYPE_push(attr->value.set, at)) goto err;
+ at = NULL;
+ attr->single = 0;
+ attr->object = (ASN1_OBJECT*) OBJ_nid2obj(nid);
+ if (!req->req_info->attributes)
+ {
+ if (!(req->req_info->attributes = sk_X509_ATTRIBUTE_new_null()))
+ goto err;
+ }
+ if(!sk_X509_ATTRIBUTE_push(req->req_info->attributes, attr)) goto err;
+ return 1;
+ err:
+ X509_ATTRIBUTE_free(attr);
+ ASN1_TYPE_free(at);
+ return 0;
+}
+/* This is the normal usage: use the "official" OID */
+int X509_REQ_add_extensions(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts)
+{
+ return X509_REQ_add_extensions_nid(req, exts, NID_ext_req);
+}
+
+/* Request attribute functions */
+
+int X509_REQ_get_attr_count(const X509_REQ *req)
+{
+ return X509at_get_attr_count(req->req_info->attributes);
+}
+
+int X509_REQ_get_attr_by_NID(const X509_REQ *req, int nid,
+ int lastpos)
+{
+ return X509at_get_attr_by_NID(req->req_info->attributes, nid, lastpos);
+}
+
+int X509_REQ_get_attr_by_OBJ(const X509_REQ *req, ASN1_OBJECT *obj,
+ int lastpos)
+{
+ return X509at_get_attr_by_OBJ(req->req_info->attributes, obj, lastpos);
+}
+
+X509_ATTRIBUTE *X509_REQ_get_attr(const X509_REQ *req, int loc)
+{
+ return X509at_get_attr(req->req_info->attributes, loc);
+}
+
+X509_ATTRIBUTE *X509_REQ_delete_attr(X509_REQ *req, int loc)
+{
+ return X509at_delete_attr(req->req_info->attributes, loc);
+}
+
+int X509_REQ_add1_attr(X509_REQ *req, X509_ATTRIBUTE *attr)
+{
+ if(X509at_add1_attr(&req->req_info->attributes, attr)) return 1;
+ return 0;
+}
+
+int X509_REQ_add1_attr_by_OBJ(X509_REQ *req,
+ const ASN1_OBJECT *obj, int type,
+ const unsigned char *bytes, int len)
+{
+ if(X509at_add1_attr_by_OBJ(&req->req_info->attributes, obj,
+ type, bytes, len)) return 1;
+ return 0;
+}
+
+int X509_REQ_add1_attr_by_NID(X509_REQ *req,
+ int nid, int type,
+ const unsigned char *bytes, int len)
+{
+ if(X509at_add1_attr_by_NID(&req->req_info->attributes, nid,
+ type, bytes, len)) return 1;
+ return 0;
+}
+
+int X509_REQ_add1_attr_by_txt(X509_REQ *req,
+ const char *attrname, int type,
+ const unsigned char *bytes, int len)
+{
+ if(X509at_add1_attr_by_txt(&req->req_info->attributes, attrname,
+ type, bytes, len)) return 1;
+ return 0;
+}
diff --git a/crypto/x509/x509_set.c b/crypto/x509/x509_set.c
new file mode 100644
index 0000000..4288571
--- /dev/null
+++ b/crypto/x509/x509_set.c
@@ -0,0 +1,148 @@
+/* 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/asn1.h>
+#include <openssl/cipher.h>
+#include <openssl/evp.h>
+#include <openssl/obj.h>
+#include <openssl/x509.h>
+
+
+int X509_set_version(X509 *x, long version)
+ {
+ if (x == NULL) return(0);
+ if (x->cert_info->version == NULL)
+ {
+ if ((x->cert_info->version=M_ASN1_INTEGER_new()) == NULL)
+ return(0);
+ }
+ return(ASN1_INTEGER_set(x->cert_info->version,version));
+ }
+
+int X509_set_serialNumber(X509 *x, ASN1_INTEGER *serial)
+ {
+ ASN1_INTEGER *in;
+
+ if (x == NULL) return(0);
+ in=x->cert_info->serialNumber;
+ if (in != serial)
+ {
+ in=M_ASN1_INTEGER_dup(serial);
+ if (in != NULL)
+ {
+ M_ASN1_INTEGER_free(x->cert_info->serialNumber);
+ x->cert_info->serialNumber=in;
+ }
+ }
+ return(in != NULL);
+ }
+
+int X509_set_issuer_name(X509 *x, X509_NAME *name)
+ {
+ if ((x == NULL) || (x->cert_info == NULL)) return(0);
+ return(X509_NAME_set(&x->cert_info->issuer,name));
+ }
+
+int X509_set_subject_name(X509 *x, X509_NAME *name)
+ {
+ if ((x == NULL) || (x->cert_info == NULL)) return(0);
+ return(X509_NAME_set(&x->cert_info->subject,name));
+ }
+
+int X509_set_notBefore(X509 *x, const ASN1_TIME *tm)
+ {
+ ASN1_TIME *in;
+
+ if ((x == NULL) || (x->cert_info->validity == NULL)) return(0);
+ in=x->cert_info->validity->notBefore;
+ if (in != tm)
+ {
+ in=M_ASN1_TIME_dup(tm);
+ if (in != NULL)
+ {
+ M_ASN1_TIME_free(x->cert_info->validity->notBefore);
+ x->cert_info->validity->notBefore=in;
+ }
+ }
+ return(in != NULL);
+ }
+
+int X509_set_notAfter(X509 *x, const ASN1_TIME *tm)
+ {
+ ASN1_TIME *in;
+
+ if ((x == NULL) || (x->cert_info->validity == NULL)) return(0);
+ in=x->cert_info->validity->notAfter;
+ if (in != tm)
+ {
+ in=M_ASN1_TIME_dup(tm);
+ if (in != NULL)
+ {
+ M_ASN1_TIME_free(x->cert_info->validity->notAfter);
+ x->cert_info->validity->notAfter=in;
+ }
+ }
+ return(in != NULL);
+ }
+
+int X509_set_pubkey(X509 *x, EVP_PKEY *pkey)
+ {
+ if ((x == NULL) || (x->cert_info == NULL)) return(0);
+ return(X509_PUBKEY_set(&(x->cert_info->key),pkey));
+ }
+
+
+
diff --git a/crypto/x509/x509_trs.c b/crypto/x509/x509_trs.c
new file mode 100644
index 0000000..e55b75b
--- /dev/null
+++ b/crypto/x509/x509_trs.c
@@ -0,0 +1,295 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999. */
+/* ====================================================================
+ * Copyright (c) 1999 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/buf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509v3.h>
+
+
+static int tr_cmp(const X509_TRUST **a,
+ const X509_TRUST **b);
+static void trtable_free(X509_TRUST *p);
+
+static int trust_1oidany(X509_TRUST *trust, X509 *x, int flags);
+static int trust_1oid(X509_TRUST *trust, X509 *x, int flags);
+static int trust_compat(X509_TRUST *trust, X509 *x, int flags);
+
+static int obj_trust(int id, X509 *x, int flags);
+static int (*default_trust)(int id, X509 *x, int flags) = obj_trust;
+
+/* WARNING: the following table should be kept in order of trust
+ * and without any gaps so we can just subtract the minimum trust
+ * value to get an index into the table
+ */
+
+static X509_TRUST trstandard[] = {
+{X509_TRUST_COMPAT, 0, trust_compat, "compatible", 0, NULL},
+{X509_TRUST_SSL_CLIENT, 0, trust_1oidany, "SSL Client", NID_client_auth, NULL},
+{X509_TRUST_SSL_SERVER, 0, trust_1oidany, "SSL Server", NID_server_auth, NULL},
+{X509_TRUST_EMAIL, 0, trust_1oidany, "S/MIME email", NID_email_protect, NULL},
+{X509_TRUST_OBJECT_SIGN, 0, trust_1oidany, "Object Signer", NID_code_sign, NULL},
+{X509_TRUST_OCSP_SIGN, 0, trust_1oid, "OCSP responder", NID_OCSP_sign, NULL},
+{X509_TRUST_OCSP_REQUEST, 0, trust_1oid, "OCSP request", NID_ad_OCSP, NULL},
+{X509_TRUST_TSA, 0, trust_1oidany, "TSA server", NID_time_stamp, NULL}
+};
+
+#define X509_TRUST_COUNT (sizeof(trstandard)/sizeof(X509_TRUST))
+
+static STACK_OF(X509_TRUST) *trtable = NULL;
+
+static int tr_cmp(const X509_TRUST **a,
+ const X509_TRUST **b)
+{
+ return (*a)->trust - (*b)->trust;
+}
+
+int (*X509_TRUST_set_default(int (*trust)(int , X509 *, int)))(int, X509 *, int)
+{
+ int (*oldtrust)(int , X509 *, int);
+ oldtrust = default_trust;
+ default_trust = trust;
+ return oldtrust;
+}
+
+
+int X509_check_trust(X509 *x, int id, int flags)
+{
+ X509_TRUST *pt;
+ int idx;
+ if(id == -1) return 1;
+ /* We get this as a default value */
+ if (id == 0)
+ {
+ int rv;
+ rv = obj_trust(NID_anyExtendedKeyUsage, x, 0);
+ if (rv != X509_TRUST_UNTRUSTED)
+ return rv;
+ return trust_compat(NULL, x, 0);
+ }
+ idx = X509_TRUST_get_by_id(id);
+ if(idx == -1) return default_trust(id, x, flags);
+ pt = X509_TRUST_get0(idx);
+ return pt->check_trust(pt, x, flags);
+}
+
+int X509_TRUST_get_count(void)
+{
+ if(!trtable) return X509_TRUST_COUNT;
+ return sk_X509_TRUST_num(trtable) + X509_TRUST_COUNT;
+}
+
+X509_TRUST * X509_TRUST_get0(int idx)
+{
+ if(idx < 0) return NULL;
+ if(idx < (int)X509_TRUST_COUNT) return trstandard + idx;
+ return sk_X509_TRUST_value(trtable, idx - X509_TRUST_COUNT);
+}
+
+int X509_TRUST_get_by_id(int id)
+{
+ X509_TRUST tmp;
+ size_t idx;
+
+ if((id >= X509_TRUST_MIN) && (id <= X509_TRUST_MAX))
+ return id - X509_TRUST_MIN;
+ tmp.trust = id;
+ if(!trtable) return -1;
+ if (!sk_X509_TRUST_find(trtable, &idx, &tmp)) {
+ return -1;
+ }
+ return idx + X509_TRUST_COUNT;
+}
+
+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);
+ return 0;
+ }
+ *t = trust;
+ return 1;
+}
+
+int X509_TRUST_add(int id, int flags, int (*ck)(X509_TRUST *, X509 *, int),
+ char *name, int arg1, void *arg2)
+{
+ int idx;
+ X509_TRUST *trtmp;
+ /* This is set according to what we change: application can't set it */
+ flags &= ~X509_TRUST_DYNAMIC;
+ /* This will always be set for application modified trust entries */
+ flags |= X509_TRUST_DYNAMIC_NAME;
+ /* Get existing entry if any */
+ idx = X509_TRUST_get_by_id(id);
+ /* 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);
+ return 0;
+ }
+ trtmp->flags = X509_TRUST_DYNAMIC;
+ } else trtmp = X509_TRUST_get0(idx);
+
+ /* OPENSSL_free existing name if dynamic */
+ if(trtmp->flags & X509_TRUST_DYNAMIC_NAME) OPENSSL_free(trtmp->name);
+ /* dup supplied name */
+ if(!(trtmp->name = BUF_strdup(name))) {
+ OPENSSL_PUT_ERROR(X509, X509_TRUST_add, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ /* Keep the dynamic flag of existing entry */
+ trtmp->flags &= X509_TRUST_DYNAMIC;
+ /* Set all other flags */
+ trtmp->flags |= flags;
+
+ trtmp->trust = id;
+ trtmp->check_trust = ck;
+ trtmp->arg1 = arg1;
+ trtmp->arg2 = arg2;
+
+ /* 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);
+ return 0;
+ }
+ if (!sk_X509_TRUST_push(trtable, trtmp)) {
+ OPENSSL_PUT_ERROR(X509, X509_TRUST_add, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void trtable_free(X509_TRUST *p)
+ {
+ if(!p) return;
+ if (p->flags & X509_TRUST_DYNAMIC)
+ {
+ if (p->flags & X509_TRUST_DYNAMIC_NAME)
+ OPENSSL_free(p->name);
+ OPENSSL_free(p);
+ }
+ }
+
+void X509_TRUST_cleanup(void)
+{
+ unsigned int i;
+ for(i = 0; i < X509_TRUST_COUNT; i++) trtable_free(trstandard + i);
+ sk_X509_TRUST_pop_free(trtable, trtable_free);
+ trtable = NULL;
+}
+
+int X509_TRUST_get_flags(X509_TRUST *xp)
+{
+ return xp->flags;
+}
+
+char *X509_TRUST_get0_name(X509_TRUST *xp)
+{
+ return xp->name;
+}
+
+int X509_TRUST_get_trust(X509_TRUST *xp)
+{
+ return xp->trust;
+}
+
+static int trust_1oidany(X509_TRUST *trust, X509 *x, int flags)
+{
+ if(x->aux && (x->aux->trust || x->aux->reject))
+ return obj_trust(trust->arg1, x, flags);
+ /* we don't have any trust settings: for compatibility
+ * we return trusted if it is self signed
+ */
+ return trust_compat(trust, x, flags);
+}
+
+static int trust_1oid(X509_TRUST *trust, X509 *x, int flags)
+{
+ if(x->aux) return obj_trust(trust->arg1, x, flags);
+ return X509_TRUST_UNTRUSTED;
+}
+
+static int trust_compat(X509_TRUST *trust, X509 *x, int flags)
+{
+ X509_check_purpose(x, -1, 0);
+ if(x->ex_flags & EXFLAG_SS) return X509_TRUST_TRUSTED;
+ else return X509_TRUST_UNTRUSTED;
+}
+
+static int obj_trust(int id, X509 *x, int flags)
+{
+ ASN1_OBJECT *obj;
+ size_t i;
+ X509_CERT_AUX *ax;
+ ax = x->aux;
+ if(!ax) return X509_TRUST_UNTRUSTED;
+ if(ax->reject) {
+ for(i = 0; i < sk_ASN1_OBJECT_num(ax->reject); i++) {
+ obj = sk_ASN1_OBJECT_value(ax->reject, i);
+ if(OBJ_obj2nid(obj) == id) return X509_TRUST_REJECTED;
+ }
+ }
+ if(ax->trust) {
+ for(i = 0; i < sk_ASN1_OBJECT_num(ax->trust); i++) {
+ obj = sk_ASN1_OBJECT_value(ax->trust, i);
+ if(OBJ_obj2nid(obj) == id) return X509_TRUST_TRUSTED;
+ }
+ }
+ return X509_TRUST_UNTRUSTED;
+}
+
diff --git a/crypto/x509/x509_txt.c b/crypto/x509/x509_txt.c
new file mode 100644
index 0000000..c286710
--- /dev/null
+++ b/crypto/x509/x509_txt.c
@@ -0,0 +1,209 @@
+/* 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/asn1.h>
+#include <openssl/buf.h>
+#include <openssl/cipher.h>
+#include <openssl/evp.h>
+#include <openssl/lhash.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509.h>
+
+
+const char *X509_verify_cert_error_string(long n)
+ {
+ static char buf[100];
+
+ switch ((int)n)
+ {
+ case X509_V_OK:
+ return("ok");
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+ return("unable to get issuer certificate");
+ case X509_V_ERR_UNABLE_TO_GET_CRL:
+ return("unable to get certificate CRL");
+ case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
+ return("unable to decrypt certificate's signature");
+ case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
+ return("unable to decrypt CRL's signature");
+ case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
+ return("unable to decode issuer public key");
+ case X509_V_ERR_CERT_SIGNATURE_FAILURE:
+ return("certificate signature failure");
+ case X509_V_ERR_CRL_SIGNATURE_FAILURE:
+ return("CRL signature failure");
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ return("certificate is not yet valid");
+ case X509_V_ERR_CRL_NOT_YET_VALID:
+ return("CRL is not yet valid");
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ return("certificate has expired");
+ case X509_V_ERR_CRL_HAS_EXPIRED:
+ return("CRL has expired");
+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+ return("format error in certificate's notBefore field");
+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+ return("format error in certificate's notAfter field");
+ case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
+ return("format error in CRL's lastUpdate field");
+ case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
+ return("format error in CRL's nextUpdate field");
+ case X509_V_ERR_OUT_OF_MEM:
+ return("out of memory");
+ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+ return("self signed certificate");
+ case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+ return("self signed certificate in certificate chain");
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+ return("unable to get local issuer certificate");
+ case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+ return("unable to verify the first certificate");
+ case X509_V_ERR_CERT_CHAIN_TOO_LONG:
+ return("certificate chain too long");
+ case X509_V_ERR_CERT_REVOKED:
+ return("certificate revoked");
+ case X509_V_ERR_INVALID_CA:
+ return ("invalid CA certificate");
+ case X509_V_ERR_INVALID_NON_CA:
+ return ("invalid non-CA certificate (has CA markings)");
+ case X509_V_ERR_PATH_LENGTH_EXCEEDED:
+ return ("path length constraint exceeded");
+ case X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED:
+ return("proxy path length constraint exceeded");
+ case X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED:
+ return("proxy certificates not allowed, please set the appropriate flag");
+ case X509_V_ERR_INVALID_PURPOSE:
+ return ("unsupported certificate purpose");
+ case X509_V_ERR_CERT_UNTRUSTED:
+ return ("certificate not trusted");
+ case X509_V_ERR_CERT_REJECTED:
+ return ("certificate rejected");
+ case X509_V_ERR_APPLICATION_VERIFICATION:
+ return("application verification failure");
+ case X509_V_ERR_SUBJECT_ISSUER_MISMATCH:
+ return("subject issuer mismatch");
+ case X509_V_ERR_AKID_SKID_MISMATCH:
+ return("authority and subject key identifier mismatch");
+ case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH:
+ return("authority and issuer serial number mismatch");
+ case X509_V_ERR_KEYUSAGE_NO_CERTSIGN:
+ return("key usage does not include certificate signing");
+ case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
+ return("unable to get CRL issuer certificate");
+ case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION:
+ return("unhandled critical extension");
+ case X509_V_ERR_KEYUSAGE_NO_CRL_SIGN:
+ return("key usage does not include CRL signing");
+ case X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE:
+ return("key usage does not include digital signature");
+ case X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION:
+ return("unhandled critical CRL extension");
+ case X509_V_ERR_INVALID_EXTENSION:
+ return("invalid or inconsistent certificate extension");
+ case X509_V_ERR_INVALID_POLICY_EXTENSION:
+ return("invalid or inconsistent certificate policy extension");
+ case X509_V_ERR_NO_EXPLICIT_POLICY:
+ return("no explicit policy");
+ case X509_V_ERR_DIFFERENT_CRL_SCOPE:
+ return("Different CRL scope");
+ case X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE:
+ return("Unsupported extension feature");
+ case X509_V_ERR_UNNESTED_RESOURCE:
+ return("RFC 3779 resource not subset of parent's resources");
+
+ case X509_V_ERR_PERMITTED_VIOLATION:
+ return("permitted subtree violation");
+ case X509_V_ERR_EXCLUDED_VIOLATION:
+ return("excluded subtree violation");
+ case X509_V_ERR_SUBTREE_MINMAX:
+ return("name constraints minimum and maximum not supported");
+ case X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE:
+ return("unsupported name constraint type");
+ case X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX:
+ return("unsupported or invalid name constraint syntax");
+ case X509_V_ERR_UNSUPPORTED_NAME_SYNTAX:
+ return("unsupported or invalid name syntax");
+ case X509_V_ERR_CRL_PATH_VALIDATION_ERROR:
+ return("CRL path validation error");
+
+ case X509_V_ERR_SUITE_B_INVALID_VERSION:
+ return("Suite B: certificate version invalid");
+ case X509_V_ERR_SUITE_B_INVALID_ALGORITHM:
+ return("Suite B: invalid public key algorithm");
+ case X509_V_ERR_SUITE_B_INVALID_CURVE:
+ return("Suite B: invalid ECC curve");
+ case X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM:
+ return("Suite B: invalid signature algorithm");
+ case X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED:
+ return("Suite B: curve not allowed for this LOS");
+ case X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256:
+ return("Suite B: cannot sign P-384 with P-256");
+
+ case X509_V_ERR_HOSTNAME_MISMATCH:
+ return("Hostname mismatch");
+ case X509_V_ERR_EMAIL_MISMATCH:
+ return("Email address mismatch");
+ case X509_V_ERR_IP_ADDRESS_MISMATCH:
+ return("IP address mismatch");
+
+ default:
+ BIO_snprintf(buf,sizeof buf,"error number %ld",n);
+ return(buf);
+ }
+ }
+
+
diff --git a/crypto/x509/x509_v3.c b/crypto/x509/x509_v3.c
new file mode 100644
index 0000000..95fe729
--- /dev/null
+++ b/crypto/x509/x509_v3.c
@@ -0,0 +1,271 @@
+/* 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/asn1.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/obj.h>
+#include <openssl/stack.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+
+int X509v3_get_ext_count(const STACK_OF(X509_EXTENSION) *x)
+ {
+ if (x == NULL) return(0);
+ return(sk_X509_EXTENSION_num(x));
+ }
+
+int X509v3_get_ext_by_NID(const STACK_OF(X509_EXTENSION) *x, int nid,
+ int lastpos)
+ {
+ const ASN1_OBJECT *obj;
+
+ obj=OBJ_nid2obj(nid);
+ if (obj == NULL) return(-2);
+ return(X509v3_get_ext_by_OBJ(x,obj,lastpos));
+ }
+
+int X509v3_get_ext_by_OBJ(const STACK_OF(X509_EXTENSION) *sk, const ASN1_OBJECT *obj,
+ int lastpos)
+ {
+ int n;
+ X509_EXTENSION *ex;
+
+ if (sk == NULL) return(-1);
+ lastpos++;
+ if (lastpos < 0)
+ lastpos=0;
+ n=sk_X509_EXTENSION_num(sk);
+ for ( ; lastpos < n; lastpos++)
+ {
+ ex=sk_X509_EXTENSION_value(sk,lastpos);
+ if (OBJ_cmp(ex->object,obj) == 0)
+ return(lastpos);
+ }
+ return(-1);
+ }
+
+int X509v3_get_ext_by_critical(const STACK_OF(X509_EXTENSION) *sk, int crit,
+ int lastpos)
+ {
+ int n;
+ X509_EXTENSION *ex;
+
+ if (sk == NULL) return(-1);
+ lastpos++;
+ if (lastpos < 0)
+ lastpos=0;
+ n=sk_X509_EXTENSION_num(sk);
+ for ( ; lastpos < n; lastpos++)
+ {
+ ex=sk_X509_EXTENSION_value(sk,lastpos);
+ if ( ((ex->critical > 0) && crit) ||
+ ((ex->critical <= 0) && !crit))
+ return(lastpos);
+ }
+ return(-1);
+ }
+
+X509_EXTENSION *X509v3_get_ext(const STACK_OF(X509_EXTENSION) *x, int loc)
+ {
+ if (x == NULL || loc < 0 || sk_X509_EXTENSION_num(x) <= (size_t) loc)
+ return NULL;
+ else
+ return sk_X509_EXTENSION_value(x,loc);
+ }
+
+X509_EXTENSION *X509v3_delete_ext(STACK_OF(X509_EXTENSION) *x, int loc)
+ {
+ X509_EXTENSION *ret;
+
+ if (x == NULL || loc < 0 || sk_X509_EXTENSION_num(x) <= (size_t) loc)
+ return(NULL);
+ ret=sk_X509_EXTENSION_delete(x,loc);
+ return(ret);
+ }
+
+STACK_OF(X509_EXTENSION) *X509v3_add_ext(STACK_OF(X509_EXTENSION) **x,
+ X509_EXTENSION *ex, int loc)
+ {
+ X509_EXTENSION *new_ex=NULL;
+ int n;
+ STACK_OF(X509_EXTENSION) *sk=NULL;
+
+ if (x == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, X509v3_add_ext, ERR_R_PASSED_NULL_PARAMETER);
+ goto err2;
+ }
+
+ if (*x == NULL)
+ {
+ if ((sk=sk_X509_EXTENSION_new_null()) == NULL)
+ goto err;
+ }
+ else
+ sk= *x;
+
+ n=sk_X509_EXTENSION_num(sk);
+ if (loc > n) loc=n;
+ else if (loc < 0) loc=n;
+
+ if ((new_ex=X509_EXTENSION_dup(ex)) == NULL)
+ goto err2;
+ if (!sk_X509_EXTENSION_insert(sk,new_ex,loc))
+ goto err;
+ if (*x == NULL)
+ *x=sk;
+ return(sk);
+err:
+ OPENSSL_PUT_ERROR(X509, X509v3_add_ext, ERR_R_MALLOC_FAILURE);
+err2:
+ if (new_ex != NULL) X509_EXTENSION_free(new_ex);
+ if (sk != NULL) sk_X509_EXTENSION_free(sk);
+ return(NULL);
+ }
+
+X509_EXTENSION *X509_EXTENSION_create_by_NID(X509_EXTENSION **ex, int nid,
+ int crit, ASN1_OCTET_STRING *data)
+ {
+ const ASN1_OBJECT *obj;
+ X509_EXTENSION *ret;
+
+ obj=OBJ_nid2obj(nid);
+ if (obj == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_EXTENSION_create_by_NID, X509_R_UNKNOWN_NID);
+ return(NULL);
+ }
+ ret=X509_EXTENSION_create_by_OBJ(ex,obj,crit,data);
+ return(ret);
+ }
+
+X509_EXTENSION *X509_EXTENSION_create_by_OBJ(X509_EXTENSION **ex,
+ const ASN1_OBJECT *obj, int crit, ASN1_OCTET_STRING *data)
+ {
+ X509_EXTENSION *ret;
+
+ if ((ex == NULL) || (*ex == NULL))
+ {
+ if ((ret=X509_EXTENSION_new()) == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_EXTENSION_create_by_OBJ, ERR_R_MALLOC_FAILURE);
+ return(NULL);
+ }
+ }
+ else
+ ret= *ex;
+
+ if (!X509_EXTENSION_set_object(ret,obj))
+ goto err;
+ if (!X509_EXTENSION_set_critical(ret,crit))
+ goto err;
+ if (!X509_EXTENSION_set_data(ret,data))
+ goto err;
+
+ if ((ex != NULL) && (*ex == NULL)) *ex=ret;
+ return(ret);
+err:
+ if ((ex == NULL) || (ret != *ex))
+ X509_EXTENSION_free(ret);
+ return(NULL);
+ }
+
+int X509_EXTENSION_set_object(X509_EXTENSION *ex, const ASN1_OBJECT *obj)
+ {
+ if ((ex == NULL) || (obj == NULL))
+ return(0);
+ ASN1_OBJECT_free(ex->object);
+ ex->object=OBJ_dup(obj);
+ return(1);
+ }
+
+int X509_EXTENSION_set_critical(X509_EXTENSION *ex, int crit)
+ {
+ if (ex == NULL) return(0);
+ ex->critical=(crit)?0xFF:-1;
+ return(1);
+ }
+
+int X509_EXTENSION_set_data(X509_EXTENSION *ex, ASN1_OCTET_STRING *data)
+ {
+ int i;
+
+ if (ex == NULL) return(0);
+ i=M_ASN1_OCTET_STRING_set(ex->value,data->data,data->length);
+ if (!i) return(0);
+ return(1);
+ }
+
+ASN1_OBJECT *X509_EXTENSION_get_object(X509_EXTENSION *ex)
+ {
+ if (ex == NULL) return(NULL);
+ return(ex->object);
+ }
+
+ASN1_OCTET_STRING *X509_EXTENSION_get_data(X509_EXTENSION *ex)
+ {
+ if (ex == NULL) return(NULL);
+ return(ex->value);
+ }
+
+int X509_EXTENSION_get_critical(X509_EXTENSION *ex)
+ {
+ if (ex == NULL) return(0);
+ if(ex->critical > 0) return 1;
+ return 0;
+ }
diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c
new file mode 100644
index 0000000..ce2087f
--- /dev/null
+++ b/crypto/x509/x509_vfy.c
@@ -0,0 +1,2457 @@
+/* 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 <time.h>
+
+#include <openssl/asn1.h>
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/lhash.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#include "vpm_int.h"
+
+/* CRL score values */
+
+/* No unhandled critical extensions */
+
+#define CRL_SCORE_NOCRITICAL 0x100
+
+/* certificate is within CRL scope */
+
+#define CRL_SCORE_SCOPE 0x080
+
+/* CRL times valid */
+
+#define CRL_SCORE_TIME 0x040
+
+/* Issuer name matches certificate */
+
+#define CRL_SCORE_ISSUER_NAME 0x020
+
+/* If this score or above CRL is probably valid */
+
+#define CRL_SCORE_VALID (CRL_SCORE_NOCRITICAL|CRL_SCORE_TIME|CRL_SCORE_SCOPE)
+
+/* CRL issuer is certificate issuer */
+
+#define CRL_SCORE_ISSUER_CERT 0x018
+
+/* CRL issuer is on certificate path */
+
+#define CRL_SCORE_SAME_PATH 0x008
+
+/* CRL issuer matches CRL AKID */
+
+#define CRL_SCORE_AKID 0x004
+
+/* Have a delta CRL with valid times */
+
+#define CRL_SCORE_TIME_DELTA 0x002
+
+static int null_callback(int ok,X509_STORE_CTX *e);
+static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer);
+static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x);
+static int check_chain_extensions(X509_STORE_CTX *ctx);
+static int check_name_constraints(X509_STORE_CTX *ctx);
+static int check_id(X509_STORE_CTX *ctx);
+static int check_trust(X509_STORE_CTX *ctx);
+static int check_revocation(X509_STORE_CTX *ctx);
+static int check_cert(X509_STORE_CTX *ctx);
+static int check_policy(X509_STORE_CTX *ctx);
+
+static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer,
+ unsigned int *preasons,
+ X509_CRL *crl, X509 *x);
+static int get_crl_delta(X509_STORE_CTX *ctx,
+ X509_CRL **pcrl, X509_CRL **pdcrl, X509 *x);
+static void get_delta_sk(X509_STORE_CTX *ctx, X509_CRL **dcrl, int *pcrl_score,
+ X509_CRL *base, STACK_OF(X509_CRL) *crls);
+static void crl_akid_check(X509_STORE_CTX *ctx, X509_CRL *crl,
+ X509 **pissuer, int *pcrl_score);
+static int crl_crldp_check(X509 *x, X509_CRL *crl, int crl_score,
+ unsigned int *preasons);
+static int check_crl_path(X509_STORE_CTX *ctx, X509 *x);
+static int check_crl_chain(X509_STORE_CTX *ctx,
+ STACK_OF(X509) *cert_path,
+ STACK_OF(X509) *crl_path);
+
+static int internal_verify(X509_STORE_CTX *ctx);
+const char X509_version[]="X.509";
+
+
+static int null_callback(int ok, X509_STORE_CTX *e)
+ {
+ return ok;
+ }
+
+#if 0
+static int x509_subject_cmp(X509 **a, X509 **b)
+ {
+ return X509_subject_name_cmp(*a,*b);
+ }
+#endif
+
+/* Given a certificate try and find an exact match in the store */
+
+static X509 *lookup_cert_match(X509_STORE_CTX *ctx, X509 *x)
+ {
+ STACK_OF(X509) *certs;
+ X509 *xtmp = NULL;
+ size_t i;
+ /* Lookup all certs with matching subject name */
+ certs = ctx->lookup_certs(ctx, X509_get_subject_name(x));
+ if (certs == NULL)
+ return NULL;
+ /* Look for exact match */
+ for (i = 0; i < sk_X509_num(certs); i++)
+ {
+ xtmp = sk_X509_value(certs, i);
+ if (!X509_cmp(xtmp, x))
+ break;
+ }
+ if (i < sk_X509_num(certs))
+ CRYPTO_add(&xtmp->references,1,CRYPTO_LOCK_X509);
+ else
+ xtmp = NULL;
+ sk_X509_pop_free(certs, X509_free);
+ return xtmp;
+ }
+
+int X509_verify_cert(X509_STORE_CTX *ctx)
+ {
+ X509 *x,*xtmp,*chain_ss=NULL;
+ int bad_chain = 0;
+ X509_VERIFY_PARAM *param = ctx->param;
+ int depth,i,ok=0;
+ int num;
+ int (*cb)(int xok,X509_STORE_CTX *xctx);
+ 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);
+ return -1;
+ }
+
+ cb=ctx->verify_cb;
+
+ /* first we make sure the chain we are going to build is
+ * present and that the first entry is in place */
+ if (ctx->chain == NULL)
+ {
+ 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);
+ goto end;
+ }
+ CRYPTO_add(&ctx->cert->references,1,CRYPTO_LOCK_X509);
+ ctx->last_untrusted=1;
+ }
+
+ /* We use a temporary STACK so we can chop and hack at it */
+ if (ctx->untrusted != NULL
+ && (sktmp=sk_X509_dup(ctx->untrusted)) == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_verify_cert, ERR_R_MALLOC_FAILURE);
+ goto end;
+ }
+
+ num=sk_X509_num(ctx->chain);
+ x=sk_X509_value(ctx->chain,num-1);
+ depth=param->depth;
+
+
+ for (;;)
+ {
+ /* If we have enough, we break */
+ if (depth < num) break; /* FIXME: If this happens, we should take
+ * note of it and, if appropriate, use the
+ * X509_V_ERR_CERT_CHAIN_TOO_LONG error
+ * code later.
+ */
+
+ /* If we are self signed, we break */
+ if (ctx->check_issued(ctx, x,x)) break;
+
+ /* If asked see if we can find issuer in trusted store first */
+ if (ctx->param->flags & X509_V_FLAG_TRUSTED_FIRST)
+ {
+ ok = ctx->get_issuer(&xtmp, ctx, x);
+ if (ok < 0)
+ return ok;
+ /* If successful for now free up cert so it
+ * will be picked up again later.
+ */
+ if (ok > 0)
+ {
+ X509_free(xtmp);
+ break;
+ }
+ }
+
+ /* If we were passed a cert chain, use it first */
+ if (ctx->untrusted != NULL)
+ {
+ xtmp=find_issuer(ctx, sktmp,x);
+ if (xtmp != NULL)
+ {
+ if (!sk_X509_push(ctx->chain,xtmp))
+ {
+ OPENSSL_PUT_ERROR(X509, X509_verify_cert, ERR_R_MALLOC_FAILURE);
+ goto end;
+ }
+ CRYPTO_add(&xtmp->references,1,CRYPTO_LOCK_X509);
+ (void)sk_X509_delete_ptr(sktmp,xtmp);
+ ctx->last_untrusted++;
+ x=xtmp;
+ num++;
+ /* reparse the full chain for
+ * the next one */
+ continue;
+ }
+ }
+ break;
+ }
+
+ /* at this point, chain should contain a list of untrusted
+ * certificates. We now need to add at least one trusted one,
+ * if possible, otherwise we complain. */
+
+ /* Examine last certificate in chain and see if it
+ * is self signed.
+ */
+
+ i=sk_X509_num(ctx->chain);
+ x=sk_X509_value(ctx->chain,i-1);
+ if (ctx->check_issued(ctx, x, x))
+ {
+ /* we have a self signed certificate */
+ if (sk_X509_num(ctx->chain) == 1)
+ {
+ /* We have a single self signed certificate: see if
+ * we can find it in the store. We must have an exact
+ * match to avoid possible impersonation.
+ */
+ ok = ctx->get_issuer(&xtmp, ctx, x);
+ if ((ok <= 0) || X509_cmp(x, xtmp))
+ {
+ ctx->error=X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT;
+ ctx->current_cert=x;
+ ctx->error_depth=i-1;
+ if (ok == 1) X509_free(xtmp);
+ bad_chain = 1;
+ ok=cb(0,ctx);
+ if (!ok) goto end;
+ }
+ else
+ {
+ /* We have a match: replace certificate with store version
+ * so we get any trust settings.
+ */
+ X509_free(x);
+ x = xtmp;
+ (void)sk_X509_set(ctx->chain, i - 1, x);
+ ctx->last_untrusted=0;
+ }
+ }
+ else
+ {
+ /* extract and save self signed certificate for later use */
+ chain_ss=sk_X509_pop(ctx->chain);
+ ctx->last_untrusted--;
+ num--;
+ x=sk_X509_value(ctx->chain,num-1);
+ }
+ }
+
+ /* We now lookup certs from the certificate store */
+ for (;;)
+ {
+ /* If we have enough, we break */
+ if (depth < num) break;
+
+ /* If we are self signed, we break */
+ if (ctx->check_issued(ctx,x,x)) break;
+
+ ok = ctx->get_issuer(&xtmp, ctx, x);
+
+ if (ok < 0) return ok;
+ 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;
+ }
+ num++;
+ }
+
+ /* we now have our chain, lets check it... */
+
+ i = check_trust(ctx);
+
+ /* If explicitly rejected error */
+ if (i == X509_TRUST_REJECTED)
+ goto end;
+ /* If not explicitly trusted then indicate error */
+ if (i != X509_TRUST_TRUSTED)
+ {
+ if ((chain_ss == NULL) || !ctx->check_issued(ctx, x, chain_ss))
+ {
+ if (ctx->last_untrusted >= num)
+ ctx->error=X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY;
+ else
+ ctx->error=X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT;
+ ctx->current_cert=x;
+ }
+ else
+ {
+
+ sk_X509_push(ctx->chain,chain_ss);
+ num++;
+ ctx->last_untrusted=num;
+ ctx->current_cert=chain_ss;
+ ctx->error=X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
+ chain_ss=NULL;
+ }
+
+ ctx->error_depth=num-1;
+ bad_chain = 1;
+ ok=cb(0,ctx);
+ if (!ok) goto end;
+ }
+
+ /* We have the chain complete: now we need to check its purpose */
+ ok = check_chain_extensions(ctx);
+
+ if (!ok) goto end;
+
+ /* Check name constraints */
+
+ ok = check_name_constraints(ctx);
+
+ if (!ok) goto end;
+
+ ok = check_id(ctx);
+
+ if (!ok) goto end;
+
+ /* We may as well copy down any DSA parameters that are required */
+ X509_get_pubkey_parameters(NULL,ctx->chain);
+
+ /* Check revocation status: we do this after copying parameters
+ * because they may be needed for CRL signature verification.
+ */
+
+ ok = ctx->check_revocation(ctx);
+ if(!ok) goto end;
+
+ i = X509_chain_check_suiteb(&ctx->error_depth, NULL, ctx->chain,
+ ctx->param->flags);
+ if (i != X509_V_OK)
+ {
+ ctx->error = i;
+ ctx->current_cert = sk_X509_value(ctx->chain, ctx->error_depth);
+ ok = cb(0, ctx);
+ if (!ok)
+ goto end;
+ }
+
+ /* At this point, we have a chain and need to verify it */
+ if (ctx->verify != NULL)
+ ok=ctx->verify(ctx);
+ else
+ ok=internal_verify(ctx);
+ if(!ok) goto end;
+
+ /* If we get this far evaluate policies */
+ if (!bad_chain && (ctx->param->flags & X509_V_FLAG_POLICY_CHECK))
+ ok = ctx->check_policy(ctx);
+ if(!ok) goto end;
+ if (0)
+ {
+end:
+ X509_get_pubkey_parameters(NULL,ctx->chain);
+ }
+ if (sktmp != NULL) sk_X509_free(sktmp);
+ if (chain_ss != NULL) X509_free(chain_ss);
+ return ok;
+ }
+
+
+/* Given a STACK_OF(X509) find the issuer of cert (if any)
+ */
+
+static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x)
+{
+ size_t i;
+ X509 *issuer;
+ for (i = 0; i < sk_X509_num(sk); i++)
+ {
+ issuer = sk_X509_value(sk, i);
+ if (ctx->check_issued(ctx, x, issuer))
+ return issuer;
+ }
+ return NULL;
+}
+
+/* Given a possible certificate and issuer check them */
+
+static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer)
+{
+ int ret;
+ ret = X509_check_issued(issuer, x);
+ if (ret == X509_V_OK)
+ return 1;
+ /* If we haven't asked for issuer errors don't set ctx */
+ if (!(ctx->param->flags & X509_V_FLAG_CB_ISSUER_CHECK))
+ return 0;
+
+ ctx->error = ret;
+ ctx->current_cert = x;
+ ctx->current_issuer = issuer;
+ return ctx->verify_cb(0, ctx);
+ return 0;
+}
+
+/* Alternative lookup method: look from a STACK stored in other_ctx */
+
+static int get_issuer_sk(X509 **issuer, X509_STORE_CTX *ctx, X509 *x)
+{
+ *issuer = find_issuer(ctx, ctx->other_ctx, x);
+ if (*issuer)
+ {
+ CRYPTO_add(&(*issuer)->references,1,CRYPTO_LOCK_X509);
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+/* Check a certificate chains extensions for consistency
+ * with the supplied purpose
+ */
+
+static int check_chain_extensions(X509_STORE_CTX *ctx)
+{
+#ifdef OPENSSL_NO_CHAIN_VERIFY
+ return 1;
+#else
+ int i, ok=0, must_be_ca, plen = 0;
+ X509 *x;
+ int (*cb)(int xok,X509_STORE_CTX *xctx);
+ int proxy_path_length = 0;
+ int purpose;
+ int allow_proxy_certs;
+ cb=ctx->verify_cb;
+
+ /* must_be_ca can have 1 of 3 values:
+ -1: we accept both CA and non-CA certificates, to allow direct
+ use of self-signed certificates (which are marked as CA).
+ 0: we only accept non-CA certificates. This is currently not
+ used, but the possibility is present for future extensions.
+ 1: we only accept CA certificates. This is currently used for
+ all certificates in the chain except the leaf certificate.
+ */
+ must_be_ca = -1;
+
+ /* CRL path validation */
+ if (ctx->parent)
+ {
+ allow_proxy_certs = 0;
+ purpose = X509_PURPOSE_CRL_SIGN;
+ }
+ else
+ {
+ allow_proxy_certs =
+ !!(ctx->param->flags & X509_V_FLAG_ALLOW_PROXY_CERTS);
+ /* A hack to keep people who don't want to modify their
+ software happy */
+ if (getenv("OPENSSL_ALLOW_PROXY_CERTS"))
+ allow_proxy_certs = 1;
+ purpose = ctx->param->purpose;
+ }
+
+ /* Check all untrusted certificates */
+ for (i = 0; i < ctx->last_untrusted; i++)
+ {
+ int ret;
+ x = sk_X509_value(ctx->chain, i);
+ if (!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL)
+ && (x->ex_flags & EXFLAG_CRITICAL))
+ {
+ ctx->error = X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION;
+ ctx->error_depth = i;
+ ctx->current_cert = x;
+ ok=cb(0,ctx);
+ if (!ok) goto end;
+ }
+ if (!allow_proxy_certs && (x->ex_flags & EXFLAG_PROXY))
+ {
+ ctx->error = X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED;
+ ctx->error_depth = i;
+ ctx->current_cert = x;
+ ok=cb(0,ctx);
+ if (!ok) goto end;
+ }
+ ret = X509_check_ca(x);
+ switch(must_be_ca)
+ {
+ case -1:
+ if ((ctx->param->flags & X509_V_FLAG_X509_STRICT)
+ && (ret != 1) && (ret != 0))
+ {
+ ret = 0;
+ ctx->error = X509_V_ERR_INVALID_CA;
+ }
+ else
+ ret = 1;
+ break;
+ case 0:
+ if (ret != 0)
+ {
+ ret = 0;
+ ctx->error = X509_V_ERR_INVALID_NON_CA;
+ }
+ else
+ ret = 1;
+ break;
+ default:
+ if ((ret == 0)
+ || ((ctx->param->flags & X509_V_FLAG_X509_STRICT)
+ && (ret != 1)))
+ {
+ ret = 0;
+ ctx->error = X509_V_ERR_INVALID_CA;
+ }
+ else
+ ret = 1;
+ break;
+ }
+ if (ret == 0)
+ {
+ ctx->error_depth = i;
+ ctx->current_cert = x;
+ ok=cb(0,ctx);
+ if (!ok) goto end;
+ }
+ if (ctx->param->purpose > 0)
+ {
+ ret = X509_check_purpose(x, purpose, must_be_ca > 0);
+ if ((ret == 0)
+ || ((ctx->param->flags & X509_V_FLAG_X509_STRICT)
+ && (ret != 1)))
+ {
+ ctx->error = X509_V_ERR_INVALID_PURPOSE;
+ ctx->error_depth = i;
+ ctx->current_cert = x;
+ ok=cb(0,ctx);
+ if (!ok) goto end;
+ }
+ }
+ /* Check pathlen if not self issued */
+ if ((i > 1) && !(x->ex_flags & EXFLAG_SI)
+ && (x->ex_pathlen != -1)
+ && (plen > (x->ex_pathlen + proxy_path_length + 1)))
+ {
+ ctx->error = X509_V_ERR_PATH_LENGTH_EXCEEDED;
+ ctx->error_depth = i;
+ ctx->current_cert = x;
+ ok=cb(0,ctx);
+ if (!ok) goto end;
+ }
+ /* Increment path length if not self issued */
+ if (!(x->ex_flags & EXFLAG_SI))
+ plen++;
+ /* If this certificate is a proxy certificate, the next
+ certificate must be another proxy certificate or a EE
+ certificate. If not, the next certificate must be a
+ CA certificate. */
+ if (x->ex_flags & EXFLAG_PROXY)
+ {
+ if (x->ex_pcpathlen != -1 && i > x->ex_pcpathlen)
+ {
+ ctx->error =
+ X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED;
+ ctx->error_depth = i;
+ ctx->current_cert = x;
+ ok=cb(0,ctx);
+ if (!ok) goto end;
+ }
+ proxy_path_length++;
+ must_be_ca = 0;
+ }
+ else
+ must_be_ca = 1;
+ }
+ ok = 1;
+ end:
+ return ok;
+#endif
+}
+
+static int check_name_constraints(X509_STORE_CTX *ctx)
+ {
+ X509 *x;
+ int i, j, rv;
+ /* Check name constraints for all certificates */
+ for (i = sk_X509_num(ctx->chain) - 1; i >= 0; i--)
+ {
+ x = sk_X509_value(ctx->chain, i);
+ /* Ignore self issued certs unless last in chain */
+ if (i && (x->ex_flags & EXFLAG_SI))
+ continue;
+ /* Check against constraints for all certificates higher in
+ * chain including trust anchor. Trust anchor not strictly
+ * speaking needed but if it includes constraints it is to be
+ * assumed it expects them to be obeyed.
+ */
+ for (j = sk_X509_num(ctx->chain) - 1; j > i; j--)
+ {
+ NAME_CONSTRAINTS *nc = sk_X509_value(ctx->chain, j)->nc;
+ if (nc)
+ {
+ rv = NAME_CONSTRAINTS_check(x, nc);
+ if (rv != X509_V_OK)
+ {
+ ctx->error = rv;
+ ctx->error_depth = i;
+ ctx->current_cert = x;
+ if (!ctx->verify_cb(0,ctx))
+ return 0;
+ }
+ }
+ }
+ }
+ return 1;
+ }
+
+static int check_id_error(X509_STORE_CTX *ctx, int errcode)
+ {
+ ctx->error = errcode;
+ ctx->current_cert = ctx->cert;
+ ctx->error_depth = 0;
+ return ctx->verify_cb(0, ctx);
+ }
+
+static int check_id(X509_STORE_CTX *ctx)
+ {
+ X509_VERIFY_PARAM *vpm = ctx->param;
+ X509_VERIFY_PARAM_ID *id = vpm->id;
+ X509 *x = ctx->cert;
+ if (id->host && !X509_check_host(x, id->host, id->hostlen, 0))
+ {
+ if (!check_id_error(ctx, X509_V_ERR_HOSTNAME_MISMATCH))
+ return 0;
+ }
+ if (id->email && !X509_check_email(x, id->email, id->emaillen, 0))
+ {
+ if (!check_id_error(ctx, X509_V_ERR_EMAIL_MISMATCH))
+ return 0;
+ }
+ if (id->ip && !X509_check_ip(x, id->ip, id->iplen, 0))
+ {
+ if (!check_id_error(ctx, X509_V_ERR_IP_ADDRESS_MISMATCH))
+ return 0;
+ }
+ return 1;
+ }
+
+static int check_trust(X509_STORE_CTX *ctx)
+{
+ size_t i;
+ int ok;
+ X509 *x = NULL;
+ int (*cb)(int xok,X509_STORE_CTX *xctx);
+ cb=ctx->verify_cb;
+ /* Check all trusted certificates in chain */
+ for (i = ctx->last_untrusted; i < sk_X509_num(ctx->chain); i++)
+ {
+ x = sk_X509_value(ctx->chain, i);
+ ok = X509_check_trust(x, ctx->param->trust, 0);
+ /* If explicitly trusted return trusted */
+ if (ok == X509_TRUST_TRUSTED)
+ return X509_TRUST_TRUSTED;
+ /* If explicitly rejected notify callback and reject if
+ * not overridden.
+ */
+ if (ok == X509_TRUST_REJECTED)
+ {
+ ctx->error_depth = i;
+ ctx->current_cert = x;
+ ctx->error = X509_V_ERR_CERT_REJECTED;
+ ok = cb(0, ctx);
+ if (!ok)
+ return X509_TRUST_REJECTED;
+ }
+ }
+ /* If we accept partial chains and have at least one trusted
+ * certificate return success.
+ */
+ if (ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN)
+ {
+ X509 *mx;
+ if (ctx->last_untrusted < (int) sk_X509_num(ctx->chain))
+ return X509_TRUST_TRUSTED;
+ x = sk_X509_value(ctx->chain, 0);
+ mx = lookup_cert_match(ctx, x);
+ if (mx)
+ {
+ (void)sk_X509_set(ctx->chain, 0, mx);
+ X509_free(x);
+ ctx->last_untrusted = 0;
+ return X509_TRUST_TRUSTED;
+ }
+ }
+
+ /* If no trusted certs in chain at all return untrusted and
+ * allow standard (no issuer cert) etc errors to be indicated.
+ */
+ return X509_TRUST_UNTRUSTED;
+}
+
+static int check_revocation(X509_STORE_CTX *ctx)
+ {
+ int i, last, ok;
+ if (!(ctx->param->flags & X509_V_FLAG_CRL_CHECK))
+ return 1;
+ if (ctx->param->flags & X509_V_FLAG_CRL_CHECK_ALL)
+ last = sk_X509_num(ctx->chain) - 1;
+ else
+ {
+ /* If checking CRL paths this isn't the EE certificate */
+ if (ctx->parent)
+ return 1;
+ last = 0;
+ }
+ for(i = 0; i <= last; i++)
+ {
+ ctx->error_depth = i;
+ ok = check_cert(ctx);
+ if (!ok) return ok;
+ }
+ return 1;
+ }
+
+static int check_cert(X509_STORE_CTX *ctx)
+ {
+ X509_CRL *crl = NULL, *dcrl = NULL;
+ X509 *x;
+ int ok, cnum;
+ unsigned int last_reasons;
+ cnum = ctx->error_depth;
+ x = sk_X509_value(ctx->chain, cnum);
+ ctx->current_cert = x;
+ ctx->current_issuer = NULL;
+ ctx->current_crl_score = 0;
+ ctx->current_reasons = 0;
+ while (ctx->current_reasons != CRLDP_ALL_REASONS)
+ {
+ last_reasons = ctx->current_reasons;
+ /* Try to retrieve relevant CRL */
+ if (ctx->get_crl)
+ ok = ctx->get_crl(ctx, &crl, x);
+ else
+ ok = get_crl_delta(ctx, &crl, &dcrl, x);
+ /* If error looking up CRL, nothing we can do except
+ * notify callback
+ */
+ if(!ok)
+ {
+ ctx->error = X509_V_ERR_UNABLE_TO_GET_CRL;
+ ok = ctx->verify_cb(0, ctx);
+ goto err;
+ }
+ ctx->current_crl = crl;
+ ok = ctx->check_crl(ctx, crl);
+ if (!ok)
+ goto err;
+
+ if (dcrl)
+ {
+ ok = ctx->check_crl(ctx, dcrl);
+ if (!ok)
+ goto err;
+ ok = ctx->cert_crl(ctx, dcrl, x);
+ if (!ok)
+ goto err;
+ }
+ else
+ ok = 1;
+
+ /* Don't look in full CRL if delta reason is removefromCRL */
+ if (ok != 2)
+ {
+ ok = ctx->cert_crl(ctx, crl, x);
+ if (!ok)
+ goto err;
+ }
+
+ X509_CRL_free(crl);
+ X509_CRL_free(dcrl);
+ crl = NULL;
+ dcrl = NULL;
+ /* If reasons not updated we wont get anywhere by
+ * another iteration, so exit loop.
+ */
+ if (last_reasons == ctx->current_reasons)
+ {
+ ctx->error = X509_V_ERR_UNABLE_TO_GET_CRL;
+ ok = ctx->verify_cb(0, ctx);
+ goto err;
+ }
+ }
+ err:
+ X509_CRL_free(crl);
+ X509_CRL_free(dcrl);
+
+ ctx->current_crl = NULL;
+ return ok;
+
+ }
+
+/* Check CRL times against values in X509_STORE_CTX */
+
+static int check_crl_time(X509_STORE_CTX *ctx, X509_CRL *crl, int notify)
+ {
+ time_t *ptime;
+ int i;
+ if (notify)
+ ctx->current_crl = crl;
+ if (ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME)
+ ptime = &ctx->param->check_time;
+ else
+ ptime = NULL;
+
+ i=X509_cmp_time(X509_CRL_get_lastUpdate(crl), ptime);
+ if (i == 0)
+ {
+ if (!notify)
+ return 0;
+ ctx->error=X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD;
+ if (!ctx->verify_cb(0, ctx))
+ return 0;
+ }
+
+ if (i > 0)
+ {
+ if (!notify)
+ return 0;
+ ctx->error=X509_V_ERR_CRL_NOT_YET_VALID;
+ if (!ctx->verify_cb(0, ctx))
+ return 0;
+ }
+
+ if(X509_CRL_get_nextUpdate(crl))
+ {
+ i=X509_cmp_time(X509_CRL_get_nextUpdate(crl), ptime);
+
+ if (i == 0)
+ {
+ if (!notify)
+ return 0;
+ ctx->error=X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD;
+ if (!ctx->verify_cb(0, ctx))
+ return 0;
+ }
+ /* Ignore expiry of base CRL is delta is valid */
+ if ((i < 0) && !(ctx->current_crl_score & CRL_SCORE_TIME_DELTA))
+ {
+ if (!notify)
+ return 0;
+ ctx->error=X509_V_ERR_CRL_HAS_EXPIRED;
+ if (!ctx->verify_cb(0, ctx))
+ return 0;
+ }
+ }
+
+ if (notify)
+ ctx->current_crl = NULL;
+
+ return 1;
+ }
+
+static int get_crl_sk(X509_STORE_CTX *ctx, X509_CRL **pcrl, X509_CRL **pdcrl,
+ X509 **pissuer, int *pscore, unsigned int *preasons,
+ STACK_OF(X509_CRL) *crls)
+ {
+ int crl_score, best_score = *pscore;
+ size_t i;
+ unsigned int reasons, best_reasons = 0;
+ X509 *x = ctx->current_cert;
+ X509_CRL *crl, *best_crl = NULL;
+ X509 *crl_issuer = NULL, *best_crl_issuer = NULL;
+
+ for (i = 0; i < sk_X509_CRL_num(crls); i++)
+ {
+ crl = sk_X509_CRL_value(crls, i);
+ reasons = *preasons;
+ crl_score = get_crl_score(ctx, &crl_issuer, &reasons, crl, x);
+
+ if (crl_score > best_score)
+ {
+ best_crl = crl;
+ best_crl_issuer = crl_issuer;
+ best_score = crl_score;
+ best_reasons = reasons;
+ }
+ }
+
+ if (best_crl)
+ {
+ if (*pcrl)
+ X509_CRL_free(*pcrl);
+ *pcrl = best_crl;
+ *pissuer = best_crl_issuer;
+ *pscore = best_score;
+ *preasons = best_reasons;
+ CRYPTO_add(&best_crl->references, 1, CRYPTO_LOCK_X509_CRL);
+ if (*pdcrl)
+ {
+ X509_CRL_free(*pdcrl);
+ *pdcrl = NULL;
+ }
+ get_delta_sk(ctx, pdcrl, pscore, best_crl, crls);
+ }
+
+ if (best_score >= CRL_SCORE_VALID)
+ return 1;
+
+ return 0;
+ }
+
+/* Compare two CRL extensions for delta checking purposes. They should be
+ * both present or both absent. If both present all fields must be identical.
+ */
+
+static int crl_extension_match(X509_CRL *a, X509_CRL *b, int nid)
+ {
+ ASN1_OCTET_STRING *exta, *extb;
+ int i;
+ i = X509_CRL_get_ext_by_NID(a, nid, -1);
+ if (i >= 0)
+ {
+ /* Can't have multiple occurrences */
+ if (X509_CRL_get_ext_by_NID(a, nid, i) != -1)
+ return 0;
+ exta = X509_EXTENSION_get_data(X509_CRL_get_ext(a, i));
+ }
+ else
+ exta = NULL;
+
+ i = X509_CRL_get_ext_by_NID(b, nid, -1);
+
+ if (i >= 0)
+ {
+
+ if (X509_CRL_get_ext_by_NID(b, nid, i) != -1)
+ return 0;
+ extb = X509_EXTENSION_get_data(X509_CRL_get_ext(b, i));
+ }
+ else
+ extb = NULL;
+
+ if (!exta && !extb)
+ return 1;
+
+ if (!exta || !extb)
+ return 0;
+
+
+ if (ASN1_OCTET_STRING_cmp(exta, extb))
+ return 0;
+
+ return 1;
+ }
+
+/* See if a base and delta are compatible */
+
+static int check_delta_base(X509_CRL *delta, X509_CRL *base)
+ {
+ /* Delta CRL must be a delta */
+ if (!delta->base_crl_number)
+ return 0;
+ /* Base must have a CRL number */
+ if (!base->crl_number)
+ return 0;
+ /* Issuer names must match */
+ if (X509_NAME_cmp(X509_CRL_get_issuer(base),
+ X509_CRL_get_issuer(delta)))
+ return 0;
+ /* AKID and IDP must match */
+ if (!crl_extension_match(delta, base, NID_authority_key_identifier))
+ return 0;
+ if (!crl_extension_match(delta, base, NID_issuing_distribution_point))
+ return 0;
+ /* Delta CRL base number must not exceed Full CRL number. */
+ if (ASN1_INTEGER_cmp(delta->base_crl_number, base->crl_number) > 0)
+ return 0;
+ /* Delta CRL number must exceed full CRL number */
+ if (ASN1_INTEGER_cmp(delta->crl_number, base->crl_number) > 0)
+ return 1;
+ return 0;
+ }
+
+/* For a given base CRL find a delta... maybe extend to delta scoring
+ * or retrieve a chain of deltas...
+ */
+
+static void get_delta_sk(X509_STORE_CTX *ctx, X509_CRL **dcrl, int *pscore,
+ X509_CRL *base, STACK_OF(X509_CRL) *crls)
+ {
+ X509_CRL *delta;
+ size_t i;
+ if (!(ctx->param->flags & X509_V_FLAG_USE_DELTAS))
+ return;
+ if (!((ctx->current_cert->ex_flags | base->flags) & EXFLAG_FRESHEST))
+ return;
+ for (i = 0; i < sk_X509_CRL_num(crls); i++)
+ {
+ delta = sk_X509_CRL_value(crls, i);
+ if (check_delta_base(delta, base))
+ {
+ if (check_crl_time(ctx, delta, 0))
+ *pscore |= CRL_SCORE_TIME_DELTA;
+ CRYPTO_add(&delta->references, 1, CRYPTO_LOCK_X509_CRL);
+ *dcrl = delta;
+ return;
+ }
+ }
+ *dcrl = NULL;
+ }
+
+/* For a given CRL return how suitable it is for the supplied certificate 'x'.
+ * The return value is a mask of several criteria.
+ * If the issuer is not the certificate issuer this is returned in *pissuer.
+ * The reasons mask is also used to determine if the CRL is suitable: if
+ * no new reasons the CRL is rejected, otherwise reasons is updated.
+ */
+
+static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer,
+ unsigned int *preasons,
+ X509_CRL *crl, X509 *x)
+ {
+
+ int crl_score = 0;
+ unsigned int tmp_reasons = *preasons, crl_reasons;
+
+ /* First see if we can reject CRL straight away */
+
+ /* Invalid IDP cannot be processed */
+ if (crl->idp_flags & IDP_INVALID)
+ return 0;
+ /* Reason codes or indirect CRLs need extended CRL support */
+ if (!(ctx->param->flags & X509_V_FLAG_EXTENDED_CRL_SUPPORT))
+ {
+ if (crl->idp_flags & (IDP_INDIRECT | IDP_REASONS))
+ return 0;
+ }
+ else if (crl->idp_flags & IDP_REASONS)
+ {
+ /* If no new reasons reject */
+ if (!(crl->idp_reasons & ~tmp_reasons))
+ return 0;
+ }
+ /* Don't process deltas at this stage */
+ else if (crl->base_crl_number)
+ return 0;
+ /* If issuer name doesn't match certificate need indirect CRL */
+ if (X509_NAME_cmp(X509_get_issuer_name(x), X509_CRL_get_issuer(crl)))
+ {
+ if (!(crl->idp_flags & IDP_INDIRECT))
+ return 0;
+ }
+ else
+ crl_score |= CRL_SCORE_ISSUER_NAME;
+
+ if (!(crl->flags & EXFLAG_CRITICAL))
+ crl_score |= CRL_SCORE_NOCRITICAL;
+
+ /* Check expiry */
+ if (check_crl_time(ctx, crl, 0))
+ crl_score |= CRL_SCORE_TIME;
+
+ /* Check authority key ID and locate certificate issuer */
+ crl_akid_check(ctx, crl, pissuer, &crl_score);
+
+ /* If we can't locate certificate issuer at this point forget it */
+
+ if (!(crl_score & CRL_SCORE_AKID))
+ return 0;
+
+ /* Check cert for matching CRL distribution points */
+
+ if (crl_crldp_check(x, crl, crl_score, &crl_reasons))
+ {
+ /* If no new reasons reject */
+ if (!(crl_reasons & ~tmp_reasons))
+ return 0;
+ tmp_reasons |= crl_reasons;
+ crl_score |= CRL_SCORE_SCOPE;
+ }
+
+ *preasons = tmp_reasons;
+
+ return crl_score;
+
+ }
+
+static void crl_akid_check(X509_STORE_CTX *ctx, X509_CRL *crl,
+ X509 **pissuer, int *pcrl_score)
+ {
+ X509 *crl_issuer = NULL;
+ X509_NAME *cnm = X509_CRL_get_issuer(crl);
+ int cidx = ctx->error_depth;
+ size_t i;
+
+ if (cidx != sk_X509_num(ctx->chain) - 1)
+ cidx++;
+
+ crl_issuer = sk_X509_value(ctx->chain, cidx);
+
+ if (X509_check_akid(crl_issuer, crl->akid) == X509_V_OK)
+ {
+ if (*pcrl_score & CRL_SCORE_ISSUER_NAME)
+ {
+ *pcrl_score |= CRL_SCORE_AKID|CRL_SCORE_ISSUER_CERT;
+ *pissuer = crl_issuer;
+ return;
+ }
+ }
+
+ for (cidx++; cidx < (int) sk_X509_num(ctx->chain); cidx++)
+ {
+ crl_issuer = sk_X509_value(ctx->chain, cidx);
+ if (X509_NAME_cmp(X509_get_subject_name(crl_issuer), cnm))
+ continue;
+ if (X509_check_akid(crl_issuer, crl->akid) == X509_V_OK)
+ {
+ *pcrl_score |= CRL_SCORE_AKID|CRL_SCORE_SAME_PATH;
+ *pissuer = crl_issuer;
+ return;
+ }
+ }
+
+ /* Anything else needs extended CRL support */
+
+ if (!(ctx->param->flags & X509_V_FLAG_EXTENDED_CRL_SUPPORT))
+ return;
+
+ /* Otherwise the CRL issuer is not on the path. Look for it in the
+ * set of untrusted certificates.
+ */
+ for (i = 0; i < sk_X509_num(ctx->untrusted); i++)
+ {
+ crl_issuer = sk_X509_value(ctx->untrusted, i);
+ if (X509_NAME_cmp(X509_get_subject_name(crl_issuer), cnm))
+ continue;
+ if (X509_check_akid(crl_issuer, crl->akid) == X509_V_OK)
+ {
+ *pissuer = crl_issuer;
+ *pcrl_score |= CRL_SCORE_AKID;
+ return;
+ }
+ }
+ }
+
+/* Check the path of a CRL issuer certificate. This creates a new
+ * X509_STORE_CTX and populates it with most of the parameters from the
+ * parent. This could be optimised somewhat since a lot of path checking
+ * will be duplicated by the parent, but this will rarely be used in
+ * practice.
+ */
+
+static int check_crl_path(X509_STORE_CTX *ctx, X509 *x)
+ {
+ X509_STORE_CTX crl_ctx;
+ int ret;
+ /* Don't allow recursive CRL path validation */
+ if (ctx->parent)
+ return 0;
+ if (!X509_STORE_CTX_init(&crl_ctx, ctx->ctx, x, ctx->untrusted))
+ return -1;
+
+ crl_ctx.crls = ctx->crls;
+ /* Copy verify params across */
+ X509_STORE_CTX_set0_param(&crl_ctx, ctx->param);
+
+ crl_ctx.parent = ctx;
+ crl_ctx.verify_cb = ctx->verify_cb;
+
+ /* Verify CRL issuer */
+ ret = X509_verify_cert(&crl_ctx);
+
+ if (ret <= 0)
+ goto err;
+
+ /* Check chain is acceptable */
+
+ ret = check_crl_chain(ctx, ctx->chain, crl_ctx.chain);
+ err:
+ X509_STORE_CTX_cleanup(&crl_ctx);
+ return ret;
+ }
+
+/* RFC3280 says nothing about the relationship between CRL path
+ * and certificate path, which could lead to situations where a
+ * certificate could be revoked or validated by a CA not authorised
+ * to do so. RFC5280 is more strict and states that the two paths must
+ * end in the same trust anchor, though some discussions remain...
+ * until this is resolved we use the RFC5280 version
+ */
+
+static int check_crl_chain(X509_STORE_CTX *ctx,
+ STACK_OF(X509) *cert_path,
+ STACK_OF(X509) *crl_path)
+ {
+ X509 *cert_ta, *crl_ta;
+ cert_ta = sk_X509_value(cert_path, sk_X509_num(cert_path) - 1);
+ crl_ta = sk_X509_value(crl_path, sk_X509_num(crl_path) - 1);
+ if (!X509_cmp(cert_ta, crl_ta))
+ return 1;
+ return 0;
+ }
+
+/* Check for match between two dist point names: three separate cases.
+ * 1. Both are relative names and compare X509_NAME types.
+ * 2. One full, one relative. Compare X509_NAME to GENERAL_NAMES.
+ * 3. Both are full names and compare two GENERAL_NAMES.
+ * 4. One is NULL: automatic match.
+ */
+
+
+static int idp_check_dp(DIST_POINT_NAME *a, DIST_POINT_NAME *b)
+ {
+ X509_NAME *nm = NULL;
+ GENERAL_NAMES *gens = NULL;
+ GENERAL_NAME *gena, *genb;
+ size_t i, j;
+ if (!a || !b)
+ return 1;
+ if (a->type == 1)
+ {
+ if (!a->dpname)
+ return 0;
+ /* Case 1: two X509_NAME */
+ if (b->type == 1)
+ {
+ if (!b->dpname)
+ return 0;
+ if (!X509_NAME_cmp(a->dpname, b->dpname))
+ return 1;
+ else
+ return 0;
+ }
+ /* Case 2: set name and GENERAL_NAMES appropriately */
+ nm = a->dpname;
+ gens = b->name.fullname;
+ }
+ else if (b->type == 1)
+ {
+ if (!b->dpname)
+ return 0;
+ /* Case 2: set name and GENERAL_NAMES appropriately */
+ gens = a->name.fullname;
+ nm = b->dpname;
+ }
+
+ /* Handle case 2 with one GENERAL_NAMES and one X509_NAME */
+ if (nm)
+ {
+ for (i = 0; i < sk_GENERAL_NAME_num(gens); i++)
+ {
+ gena = sk_GENERAL_NAME_value(gens, i);
+ if (gena->type != GEN_DIRNAME)
+ continue;
+ if (!X509_NAME_cmp(nm, gena->d.directoryName))
+ return 1;
+ }
+ return 0;
+ }
+
+ /* Else case 3: two GENERAL_NAMES */
+
+ for (i = 0; i < sk_GENERAL_NAME_num(a->name.fullname); i++)
+ {
+ gena = sk_GENERAL_NAME_value(a->name.fullname, i);
+ for (j = 0; j < sk_GENERAL_NAME_num(b->name.fullname); j++)
+ {
+ genb = sk_GENERAL_NAME_value(b->name.fullname, j);
+ if (!GENERAL_NAME_cmp(gena, genb))
+ return 1;
+ }
+ }
+
+ return 0;
+
+ }
+
+static int crldp_check_crlissuer(DIST_POINT *dp, X509_CRL *crl, int crl_score)
+ {
+ size_t i;
+ X509_NAME *nm = X509_CRL_get_issuer(crl);
+ /* If no CRLissuer return is successful iff don't need a match */
+ if (!dp->CRLissuer)
+ return !!(crl_score & CRL_SCORE_ISSUER_NAME);
+ for (i = 0; i < sk_GENERAL_NAME_num(dp->CRLissuer); i++)
+ {
+ GENERAL_NAME *gen = sk_GENERAL_NAME_value(dp->CRLissuer, i);
+ if (gen->type != GEN_DIRNAME)
+ continue;
+ if (!X509_NAME_cmp(gen->d.directoryName, nm))
+ return 1;
+ }
+ return 0;
+ }
+
+/* Check CRLDP and IDP */
+
+static int crl_crldp_check(X509 *x, X509_CRL *crl, int crl_score,
+ unsigned int *preasons)
+ {
+ size_t i;
+ if (crl->idp_flags & IDP_ONLYATTR)
+ return 0;
+ if (x->ex_flags & EXFLAG_CA)
+ {
+ if (crl->idp_flags & IDP_ONLYUSER)
+ return 0;
+ }
+ else
+ {
+ if (crl->idp_flags & IDP_ONLYCA)
+ return 0;
+ }
+ *preasons = crl->idp_reasons;
+ for (i = 0; i < sk_DIST_POINT_num(x->crldp); i++)
+ {
+ DIST_POINT *dp = sk_DIST_POINT_value(x->crldp, i);
+ if (crldp_check_crlissuer(dp, crl, crl_score))
+ {
+ if (!crl->idp ||
+ idp_check_dp(dp->distpoint, crl->idp->distpoint))
+ {
+ *preasons &= dp->dp_reasons;
+ return 1;
+ }
+ }
+ }
+ if ((!crl->idp || !crl->idp->distpoint) && (crl_score & CRL_SCORE_ISSUER_NAME))
+ return 1;
+ return 0;
+ }
+
+/* Retrieve CRL corresponding to current certificate.
+ * If deltas enabled try to find a delta CRL too
+ */
+
+static int get_crl_delta(X509_STORE_CTX *ctx,
+ X509_CRL **pcrl, X509_CRL **pdcrl, X509 *x)
+ {
+ int ok;
+ X509 *issuer = NULL;
+ int crl_score = 0;
+ unsigned int reasons;
+ X509_CRL *crl = NULL, *dcrl = NULL;
+ STACK_OF(X509_CRL) *skcrl;
+ X509_NAME *nm = X509_get_issuer_name(x);
+ reasons = ctx->current_reasons;
+ ok = get_crl_sk(ctx, &crl, &dcrl,
+ &issuer, &crl_score, &reasons, ctx->crls);
+
+ if (ok)
+ goto done;
+
+ /* Lookup CRLs from store */
+
+ skcrl = ctx->lookup_crls(ctx, nm);
+
+ /* If no CRLs found and a near match from get_crl_sk use that */
+ if (!skcrl && crl)
+ goto done;
+
+ get_crl_sk(ctx, &crl, &dcrl, &issuer, &crl_score, &reasons, skcrl);
+
+ sk_X509_CRL_pop_free(skcrl, X509_CRL_free);
+
+ done:
+
+ /* If we got any kind of CRL use it and return success */
+ if (crl)
+ {
+ ctx->current_issuer = issuer;
+ ctx->current_crl_score = crl_score;
+ ctx->current_reasons = reasons;
+ *pcrl = crl;
+ *pdcrl = dcrl;
+ return 1;
+ }
+
+ return 0;
+ }
+
+/* Check CRL validity */
+static int check_crl(X509_STORE_CTX *ctx, X509_CRL *crl)
+ {
+ X509 *issuer = NULL;
+ EVP_PKEY *ikey = NULL;
+ int ok = 0, chnum, cnum;
+ cnum = ctx->error_depth;
+ chnum = sk_X509_num(ctx->chain) - 1;
+ /* if we have an alternative CRL issuer cert use that */
+ if (ctx->current_issuer)
+ issuer = ctx->current_issuer;
+
+ /* Else find CRL issuer: if not last certificate then issuer
+ * is next certificate in chain.
+ */
+ else if (cnum < chnum)
+ issuer = sk_X509_value(ctx->chain, cnum + 1);
+ else
+ {
+ issuer = sk_X509_value(ctx->chain, chnum);
+ /* If not self signed, can't check signature */
+ if(!ctx->check_issued(ctx, issuer, issuer))
+ {
+ ctx->error = X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER;
+ ok = ctx->verify_cb(0, ctx);
+ if(!ok) goto err;
+ }
+ }
+
+ if(issuer)
+ {
+ /* Skip most tests for deltas because they have already
+ * been done
+ */
+ if (!crl->base_crl_number)
+ {
+ /* Check for cRLSign bit if keyUsage present */
+ if ((issuer->ex_flags & EXFLAG_KUSAGE) &&
+ !(issuer->ex_kusage & KU_CRL_SIGN))
+ {
+ ctx->error = X509_V_ERR_KEYUSAGE_NO_CRL_SIGN;
+ ok = ctx->verify_cb(0, ctx);
+ if(!ok) goto err;
+ }
+
+ if (!(ctx->current_crl_score & CRL_SCORE_SCOPE))
+ {
+ ctx->error = X509_V_ERR_DIFFERENT_CRL_SCOPE;
+ ok = ctx->verify_cb(0, ctx);
+ if(!ok) goto err;
+ }
+
+ if (!(ctx->current_crl_score & CRL_SCORE_SAME_PATH))
+ {
+ if (check_crl_path(ctx, ctx->current_issuer) <= 0)
+ {
+ ctx->error = X509_V_ERR_CRL_PATH_VALIDATION_ERROR;
+ ok = ctx->verify_cb(0, ctx);
+ if(!ok) goto err;
+ }
+ }
+
+ if (crl->idp_flags & IDP_INVALID)
+ {
+ ctx->error = X509_V_ERR_INVALID_EXTENSION;
+ ok = ctx->verify_cb(0, ctx);
+ if(!ok) goto err;
+ }
+
+
+ }
+
+ if (!(ctx->current_crl_score & CRL_SCORE_TIME))
+ {
+ ok = check_crl_time(ctx, crl, 1);
+ if (!ok)
+ goto err;
+ }
+
+ /* Attempt to get issuer certificate public key */
+ ikey = X509_get_pubkey(issuer);
+
+ if(!ikey)
+ {
+ ctx->error=X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY;
+ ok = ctx->verify_cb(0, ctx);
+ if (!ok) goto err;
+ }
+ else
+ {
+ int rv;
+ rv = X509_CRL_check_suiteb(crl, ikey, ctx->param->flags);
+ if (rv != X509_V_OK)
+ {
+ ctx->error=rv;
+ ok = ctx->verify_cb(0, ctx);
+ if (!ok)
+ goto err;
+ }
+ /* Verify CRL signature */
+ if(X509_CRL_verify(crl, ikey) <= 0)
+ {
+ ctx->error=X509_V_ERR_CRL_SIGNATURE_FAILURE;
+ ok = ctx->verify_cb(0, ctx);
+ if (!ok) goto err;
+ }
+ }
+ }
+
+ ok = 1;
+
+ err:
+ EVP_PKEY_free(ikey);
+ return ok;
+ }
+
+/* Check certificate against CRL */
+static int cert_crl(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x)
+ {
+ int ok;
+ X509_REVOKED *rev;
+ /* The rules changed for this... previously if a CRL contained
+ * unhandled critical extensions it could still be used to indicate
+ * a certificate was revoked. This has since been changed since
+ * critical extension can change the meaning of CRL entries.
+ */
+ if (!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL)
+ && (crl->flags & EXFLAG_CRITICAL))
+ {
+ ctx->error = X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION;
+ ok = ctx->verify_cb(0, ctx);
+ if(!ok)
+ return 0;
+ }
+ /* Look for serial number of certificate in CRL
+ * If found make sure reason is not removeFromCRL.
+ */
+ if (X509_CRL_get0_by_cert(crl, &rev, x))
+ {
+ if (rev->reason == CRL_REASON_REMOVE_FROM_CRL)
+ return 2;
+ ctx->error = X509_V_ERR_CERT_REVOKED;
+ ok = ctx->verify_cb(0, ctx);
+ if (!ok)
+ return 0;
+ }
+
+ return 1;
+ }
+
+static int check_policy(X509_STORE_CTX *ctx)
+ {
+ int ret;
+ if (ctx->parent)
+ return 1;
+ ret = X509_policy_check(&ctx->tree, &ctx->explicit_policy, ctx->chain,
+ ctx->param->policies, ctx->param->flags);
+ if (ret == 0)
+ {
+ OPENSSL_PUT_ERROR(X509, check_policy, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ /* Invalid or inconsistent extensions */
+ if (ret == -1)
+ {
+ /* Locate certificates with bad extensions and notify
+ * callback.
+ */
+ X509 *x;
+ size_t i;
+ for (i = 1; i < sk_X509_num(ctx->chain); i++)
+ {
+ x = sk_X509_value(ctx->chain, i);
+ if (!(x->ex_flags & EXFLAG_INVALID_POLICY))
+ continue;
+ ctx->current_cert = x;
+ ctx->error = X509_V_ERR_INVALID_POLICY_EXTENSION;
+ if(!ctx->verify_cb(0, ctx))
+ return 0;
+ }
+ return 1;
+ }
+ if (ret == -2)
+ {
+ ctx->current_cert = NULL;
+ ctx->error = X509_V_ERR_NO_EXPLICIT_POLICY;
+ return ctx->verify_cb(0, ctx);
+ }
+
+ if (ctx->param->flags & X509_V_FLAG_NOTIFY_POLICY)
+ {
+ ctx->current_cert = NULL;
+ ctx->error = X509_V_OK;
+ if (!ctx->verify_cb(2, ctx))
+ return 0;
+ }
+
+ return 1;
+ }
+
+static int check_cert_time(X509_STORE_CTX *ctx, X509 *x)
+ {
+ time_t *ptime;
+ int i;
+
+ if (ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME)
+ ptime = &ctx->param->check_time;
+ else
+ ptime = NULL;
+
+ i=X509_cmp_time(X509_get_notBefore(x), ptime);
+ if (i == 0)
+ {
+ ctx->error=X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD;
+ ctx->current_cert=x;
+ if (!ctx->verify_cb(0, ctx))
+ return 0;
+ }
+
+ if (i > 0)
+ {
+ ctx->error=X509_V_ERR_CERT_NOT_YET_VALID;
+ ctx->current_cert=x;
+ if (!ctx->verify_cb(0, ctx))
+ return 0;
+ }
+
+ i=X509_cmp_time(X509_get_notAfter(x), ptime);
+ if (i == 0)
+ {
+ ctx->error=X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD;
+ ctx->current_cert=x;
+ if (!ctx->verify_cb(0, ctx))
+ return 0;
+ }
+
+ if (i < 0)
+ {
+ ctx->error=X509_V_ERR_CERT_HAS_EXPIRED;
+ ctx->current_cert=x;
+ if (!ctx->verify_cb(0, ctx))
+ return 0;
+ }
+
+ return 1;
+ }
+
+static int internal_verify(X509_STORE_CTX *ctx)
+ {
+ int ok=0,n;
+ X509 *xs,*xi;
+ EVP_PKEY *pkey=NULL;
+ int (*cb)(int xok,X509_STORE_CTX *xctx);
+
+ cb=ctx->verify_cb;
+
+ n=sk_X509_num(ctx->chain);
+ ctx->error_depth=n-1;
+ n--;
+ xi=sk_X509_value(ctx->chain,n);
+
+ if (ctx->check_issued(ctx, xi, xi))
+ xs=xi;
+ else
+ {
+ if (ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN && n == 0)
+ {
+ xs = xi;
+ goto check_cert;
+ }
+ if (n <= 0)
+ {
+ ctx->error=X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE;
+ ctx->current_cert=xi;
+ ok=cb(0,ctx);
+ goto end;
+ }
+ else
+ {
+ n--;
+ ctx->error_depth=n;
+ xs=sk_X509_value(ctx->chain,n);
+ }
+ }
+
+/* ctx->error=0; not needed */
+ while (n >= 0)
+ {
+ ctx->error_depth=n;
+
+ /* Skip signature check for self signed certificates unless
+ * explicitly asked for. It doesn't add any security and
+ * just wastes time.
+ */
+ if (!xs->valid && (xs != xi || (ctx->param->flags & X509_V_FLAG_CHECK_SS_SIGNATURE)))
+ {
+ if ((pkey=X509_get_pubkey(xi)) == NULL)
+ {
+ ctx->error=X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY;
+ ctx->current_cert=xi;
+ ok=(*cb)(0,ctx);
+ if (!ok) goto end;
+ }
+ else if (X509_verify(xs,pkey) <= 0)
+ {
+ ctx->error=X509_V_ERR_CERT_SIGNATURE_FAILURE;
+ ctx->current_cert=xs;
+ ok=(*cb)(0,ctx);
+ if (!ok)
+ {
+ EVP_PKEY_free(pkey);
+ goto end;
+ }
+ }
+ EVP_PKEY_free(pkey);
+ pkey=NULL;
+ }
+
+ xs->valid = 1;
+
+ check_cert:
+ ok = check_cert_time(ctx, xs);
+ if (!ok)
+ goto end;
+
+ /* The last error (if any) is still in the error value */
+ ctx->current_issuer=xi;
+ ctx->current_cert=xs;
+ ok=(*cb)(1,ctx);
+ if (!ok) goto end;
+
+ n--;
+ if (n >= 0)
+ {
+ xi=xs;
+ xs=sk_X509_value(ctx->chain,n);
+ }
+ }
+ ok=1;
+end:
+ return ok;
+ }
+
+int X509_cmp_current_time(const ASN1_TIME *ctm)
+{
+ return X509_cmp_time(ctm, NULL);
+}
+
+int X509_cmp_time(const ASN1_TIME *ctm, time_t *cmp_time)
+ {
+ char *str;
+ ASN1_TIME atm;
+ long offset;
+ char buff1[24],buff2[24],*p;
+ int i,j;
+
+ p=buff1;
+ i=ctm->length;
+ str=(char *)ctm->data;
+ if (ctm->type == V_ASN1_UTCTIME)
+ {
+ if ((i < 11) || (i > 17)) return 0;
+ memcpy(p,str,10);
+ p+=10;
+ str+=10;
+ }
+ else
+ {
+ if (i < 13) return 0;
+ memcpy(p,str,12);
+ p+=12;
+ str+=12;
+ }
+
+ if ((*str == 'Z') || (*str == '-') || (*str == '+'))
+ { *(p++)='0'; *(p++)='0'; }
+ else
+ {
+ *(p++)= *(str++);
+ *(p++)= *(str++);
+ /* Skip any fractional seconds... */
+ if (*str == '.')
+ {
+ str++;
+ while ((*str >= '0') && (*str <= '9')) str++;
+ }
+
+ }
+ *(p++)='Z';
+ *(p++)='\0';
+
+ if (*str == 'Z')
+ offset=0;
+ else
+ {
+ if ((*str != '+') && (*str != '-'))
+ return 0;
+ offset=((str[1]-'0')*10+(str[2]-'0'))*60;
+ offset+=(str[3]-'0')*10+(str[4]-'0');
+ if (*str == '-')
+ offset= -offset;
+ }
+ atm.type=ctm->type;
+ atm.flags = 0;
+ atm.length=sizeof(buff2);
+ atm.data=(unsigned char *)buff2;
+
+ if (X509_time_adj(&atm, offset*60, cmp_time) == NULL)
+ return 0;
+
+ if (ctm->type == V_ASN1_UTCTIME)
+ {
+ i=(buff1[0]-'0')*10+(buff1[1]-'0');
+ if (i < 50) i+=100; /* cf. RFC 2459 */
+ j=(buff2[0]-'0')*10+(buff2[1]-'0');
+ if (j < 50) j+=100;
+
+ if (i < j) return -1;
+ if (i > j) return 1;
+ }
+ i=strcmp(buff1,buff2);
+ if (i == 0) /* wait a second then return younger :-) */
+ return -1;
+ else
+ return i;
+ }
+
+ASN1_TIME *X509_gmtime_adj(ASN1_TIME *s, long adj)
+{
+ return X509_time_adj(s, adj, NULL);
+}
+
+ASN1_TIME *X509_time_adj(ASN1_TIME *s, long offset_sec, time_t *in_tm)
+ {
+ return X509_time_adj_ex(s, 0, offset_sec, in_tm);
+ }
+
+ASN1_TIME *X509_time_adj_ex(ASN1_TIME *s,
+ int offset_day, long offset_sec, time_t *in_tm)
+ {
+ time_t t;
+
+ if (in_tm) t = *in_tm;
+ else time(&t);
+
+ if (s && !(s->flags & ASN1_STRING_FLAG_MSTRING))
+ {
+ if (s->type == V_ASN1_UTCTIME)
+ return ASN1_UTCTIME_adj(s,t, offset_day, offset_sec);
+ if (s->type == V_ASN1_GENERALIZEDTIME)
+ return ASN1_GENERALIZEDTIME_adj(s, t, offset_day,
+ offset_sec);
+ }
+ return ASN1_TIME_adj(s, t, offset_day, offset_sec);
+ }
+
+int X509_get_pubkey_parameters(EVP_PKEY *pkey, STACK_OF(X509) *chain)
+ {
+ EVP_PKEY *ktmp=NULL,*ktmp2;
+ size_t i,j;
+
+ if ((pkey != NULL) && !EVP_PKEY_missing_parameters(pkey)) return 1;
+
+ for (i=0; i<sk_X509_num(chain); i++)
+ {
+ ktmp=X509_get_pubkey(sk_X509_value(chain,i));
+ if (ktmp == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_get_pubkey_parameters, X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY);
+ return 0;
+ }
+ if (!EVP_PKEY_missing_parameters(ktmp))
+ break;
+ else
+ {
+ EVP_PKEY_free(ktmp);
+ ktmp=NULL;
+ }
+ }
+ if (ktmp == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_get_pubkey_parameters, X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN);
+ return 0;
+ }
+
+ /* first, populate the other certs */
+ for (j=i-1; j < i; j--)
+ {
+ ktmp2=X509_get_pubkey(sk_X509_value(chain,j));
+ EVP_PKEY_copy_parameters(ktmp2,ktmp);
+ EVP_PKEY_free(ktmp2);
+ }
+
+ if (pkey != NULL) EVP_PKEY_copy_parameters(pkey,ktmp);
+ EVP_PKEY_free(ktmp);
+ return 1;
+ }
+
+/* Make a delta CRL as the diff between two full CRLs */
+
+X509_CRL *X509_CRL_diff(X509_CRL *base, X509_CRL *newer,
+ EVP_PKEY *skey, const EVP_MD *md, unsigned int flags)
+ {
+ X509_CRL *crl = NULL;
+ int i;
+ size_t j;
+ STACK_OF(X509_REVOKED) *revs = NULL;
+ /* 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);
+ 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);
+ 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);
+ 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);
+ return NULL;
+ }
+ if (!crl_extension_match(base, newer, NID_issuing_distribution_point))
+ {
+ OPENSSL_PUT_ERROR(X509, X509_CRL_diff, 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);
+ 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);
+ return NULL;
+ }
+ /* Create new CRL */
+ crl = X509_CRL_new();
+ if (!crl || !X509_CRL_set_version(crl, 1))
+ goto memerr;
+ /* Set issuer name */
+ if (!X509_CRL_set_issuer_name(crl, X509_CRL_get_issuer(newer)))
+ goto memerr;
+
+ if (!X509_CRL_set_lastUpdate(crl, X509_CRL_get_lastUpdate(newer)))
+ goto memerr;
+ if (!X509_CRL_set_nextUpdate(crl, X509_CRL_get_nextUpdate(newer)))
+ goto memerr;
+
+ /* Set base CRL number: must be critical */
+
+ if (!X509_CRL_add1_ext_i2d(crl, NID_delta_crl, base->crl_number, 1, 0))
+ goto memerr;
+
+ /* Copy extensions across from newest CRL to delta: this will set
+ * CRL number to correct value too.
+ */
+
+ for (i = 0; i < X509_CRL_get_ext_count(newer); i++)
+ {
+ X509_EXTENSION *ext;
+ ext = X509_CRL_get_ext(newer, i);
+ if (!X509_CRL_add_ext(crl, ext, -1))
+ goto memerr;
+ }
+
+ /* Go through revoked entries, copying as needed */
+
+ revs = X509_CRL_get_REVOKED(newer);
+
+ for (j = 0; j < sk_X509_REVOKED_num(revs); j++)
+ {
+ X509_REVOKED *rvn, *rvtmp;
+ rvn = sk_X509_REVOKED_value(revs, j);
+ /* Add only if not also in base.
+ * TODO: need something cleverer here for some more complex
+ * CRLs covering multiple CAs.
+ */
+ if (!X509_CRL_get0_by_serial(base, &rvtmp, rvn->serialNumber))
+ {
+ rvtmp = X509_REVOKED_dup(rvn);
+ if (!rvtmp)
+ goto memerr;
+ if (!X509_CRL_add0_revoked(crl, rvtmp))
+ {
+ X509_REVOKED_free(rvtmp);
+ goto memerr;
+ }
+ }
+ }
+ /* TODO: optionally prune deleted entries */
+
+ if (skey && md && !X509_CRL_sign(crl, skey, md))
+ goto memerr;
+
+ return crl;
+
+ memerr:
+ OPENSSL_PUT_ERROR(X509, X509_CRL_diff, ERR_R_MALLOC_FAILURE);
+ if (crl)
+ X509_CRL_free(crl);
+ return NULL;
+ }
+
+int X509_STORE_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+ CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func)
+ {
+ /* This function is (usually) called only once, by
+ * SSL_get_ex_data_X509_STORE_CTX_idx (ssl/ssl_cert.c). */
+ return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_X509_STORE_CTX, argl, argp,
+ new_func, dup_func, free_func);
+ }
+
+int X509_STORE_CTX_set_ex_data(X509_STORE_CTX *ctx, int idx, void *data)
+ {
+ return CRYPTO_set_ex_data(&ctx->ex_data,idx,data);
+ }
+
+void *X509_STORE_CTX_get_ex_data(X509_STORE_CTX *ctx, int idx)
+ {
+ return CRYPTO_get_ex_data(&ctx->ex_data,idx);
+ }
+
+int X509_STORE_CTX_get_error(X509_STORE_CTX *ctx)
+ {
+ return ctx->error;
+ }
+
+void X509_STORE_CTX_set_error(X509_STORE_CTX *ctx, int err)
+ {
+ ctx->error=err;
+ }
+
+int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *ctx)
+ {
+ return ctx->error_depth;
+ }
+
+X509 *X509_STORE_CTX_get_current_cert(X509_STORE_CTX *ctx)
+ {
+ return ctx->current_cert;
+ }
+
+STACK_OF(X509) *X509_STORE_CTX_get_chain(X509_STORE_CTX *ctx)
+ {
+ return ctx->chain;
+ }
+
+STACK_OF(X509) *X509_STORE_CTX_get1_chain(X509_STORE_CTX *ctx)
+ {
+ size_t i;
+ X509 *x;
+ STACK_OF(X509) *chain;
+ if (!ctx->chain || !(chain = sk_X509_dup(ctx->chain))) return NULL;
+ for (i = 0; i < sk_X509_num(chain); i++)
+ {
+ x = sk_X509_value(chain, i);
+ CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
+ }
+ return chain;
+ }
+
+X509 *X509_STORE_CTX_get0_current_issuer(X509_STORE_CTX *ctx)
+ {
+ return ctx->current_issuer;
+ }
+
+X509_CRL *X509_STORE_CTX_get0_current_crl(X509_STORE_CTX *ctx)
+ {
+ return ctx->current_crl;
+ }
+
+X509_STORE_CTX *X509_STORE_CTX_get0_parent_ctx(X509_STORE_CTX *ctx)
+ {
+ return ctx->parent;
+ }
+
+void X509_STORE_CTX_set_cert(X509_STORE_CTX *ctx, X509 *x)
+ {
+ ctx->cert=x;
+ }
+
+void X509_STORE_CTX_set_chain(X509_STORE_CTX *ctx, STACK_OF(X509) *sk)
+ {
+ ctx->untrusted=sk;
+ }
+
+void X509_STORE_CTX_set0_crls(X509_STORE_CTX *ctx, STACK_OF(X509_CRL) *sk)
+ {
+ ctx->crls=sk;
+ }
+
+int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose)
+ {
+ return X509_STORE_CTX_purpose_inherit(ctx, 0, purpose, 0);
+ }
+
+int X509_STORE_CTX_set_trust(X509_STORE_CTX *ctx, int trust)
+ {
+ return X509_STORE_CTX_purpose_inherit(ctx, 0, 0, trust);
+ }
+
+/* This function is used to set the X509_STORE_CTX purpose and trust
+ * values. This is intended to be used when another structure has its
+ * own trust and purpose values which (if set) will be inherited by
+ * the ctx. If they aren't set then we will usually have a default
+ * purpose in mind which should then be used to set the trust value.
+ * An example of this is SSL use: an SSL structure will have its own
+ * purpose and trust settings which the application can set: if they
+ * aren't set then we use the default of SSL client/server.
+ */
+
+int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose,
+ int purpose, int trust)
+{
+ int idx;
+ /* If purpose not set use default */
+ if (!purpose) purpose = def_purpose;
+ /* If we have a purpose then check it is valid */
+ if (purpose)
+ {
+ X509_PURPOSE *ptmp;
+ idx = X509_PURPOSE_get_by_id(purpose);
+ if (idx == -1)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_STORE_CTX_purpose_inherit, X509_R_UNKNOWN_PURPOSE_ID);
+ return 0;
+ }
+ ptmp = X509_PURPOSE_get0(idx);
+ if (ptmp->trust == X509_TRUST_DEFAULT)
+ {
+ 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);
+ return 0;
+ }
+ ptmp = X509_PURPOSE_get0(idx);
+ }
+ /* If trust not set then get from purpose default */
+ if (!trust) trust = ptmp->trust;
+ }
+ if (trust)
+ {
+ idx = X509_TRUST_get_by_id(trust);
+ if (idx == -1)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_STORE_CTX_purpose_inherit, X509_R_UNKNOWN_TRUST_ID);
+ return 0;
+ }
+ }
+
+ if (purpose && !ctx->param->purpose) ctx->param->purpose = purpose;
+ if (trust && !ctx->param->trust) ctx->param->trust = trust;
+ return 1;
+}
+
+X509_STORE_CTX *X509_STORE_CTX_new(void)
+{
+ X509_STORE_CTX *ctx;
+ ctx = (X509_STORE_CTX *)OPENSSL_malloc(sizeof(X509_STORE_CTX));
+ if (!ctx)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_STORE_CTX_new, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ memset(ctx, 0, sizeof(X509_STORE_CTX));
+ return ctx;
+}
+
+void X509_STORE_CTX_free(X509_STORE_CTX *ctx)
+{
+ X509_STORE_CTX_cleanup(ctx);
+ OPENSSL_free(ctx);
+}
+
+int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509,
+ STACK_OF(X509) *chain)
+ {
+ int ret = 1;
+ ctx->ctx=store;
+ ctx->current_method=0;
+ ctx->cert=x509;
+ ctx->untrusted=chain;
+ ctx->crls = NULL;
+ ctx->last_untrusted=0;
+ ctx->other_ctx=NULL;
+ ctx->valid=0;
+ ctx->chain=NULL;
+ ctx->error=0;
+ ctx->explicit_policy=0;
+ ctx->error_depth=0;
+ ctx->current_cert=NULL;
+ ctx->current_issuer=NULL;
+ ctx->current_crl=NULL;
+ ctx->current_crl_score=0;
+ ctx->current_reasons=0;
+ ctx->tree = NULL;
+ ctx->parent = NULL;
+
+ ctx->param = X509_VERIFY_PARAM_new();
+
+ if (!ctx->param)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_STORE_CTX_init, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ /* Inherit callbacks and flags from X509_STORE if not set
+ * use defaults.
+ */
+
+
+ if (store)
+ ret = X509_VERIFY_PARAM_inherit(ctx->param, store->param);
+ else
+ ctx->param->inh_flags |= X509_VP_FLAG_DEFAULT|X509_VP_FLAG_ONCE;
+
+ if (store)
+ {
+ ctx->verify_cb = store->verify_cb;
+ ctx->cleanup = store->cleanup;
+ }
+ else
+ ctx->cleanup = 0;
+
+ if (ret)
+ ret = X509_VERIFY_PARAM_inherit(ctx->param,
+ X509_VERIFY_PARAM_lookup("default"));
+
+ if (ret == 0)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_STORE_CTX_init, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ if (store && store->check_issued)
+ ctx->check_issued = store->check_issued;
+ else
+ ctx->check_issued = check_issued;
+
+ if (store && store->get_issuer)
+ ctx->get_issuer = store->get_issuer;
+ else
+ ctx->get_issuer = X509_STORE_CTX_get1_issuer;
+
+ if (store && store->verify_cb)
+ ctx->verify_cb = store->verify_cb;
+ else
+ ctx->verify_cb = null_callback;
+
+ if (store && store->verify)
+ ctx->verify = store->verify;
+ else
+ ctx->verify = internal_verify;
+
+ if (store && store->check_revocation)
+ ctx->check_revocation = store->check_revocation;
+ else
+ ctx->check_revocation = check_revocation;
+
+ if (store && store->get_crl)
+ ctx->get_crl = store->get_crl;
+ else
+ ctx->get_crl = NULL;
+
+ if (store && store->check_crl)
+ ctx->check_crl = store->check_crl;
+ else
+ ctx->check_crl = check_crl;
+
+ if (store && store->cert_crl)
+ ctx->cert_crl = store->cert_crl;
+ else
+ ctx->cert_crl = cert_crl;
+
+ if (store && store->lookup_certs)
+ ctx->lookup_certs = store->lookup_certs;
+ else
+ ctx->lookup_certs = X509_STORE_get1_certs;
+
+ if (store && store->lookup_crls)
+ ctx->lookup_crls = store->lookup_crls;
+ else
+ ctx->lookup_crls = X509_STORE_get1_crls;
+
+ ctx->check_policy = check_policy;
+
+
+ /* This memset() can't make any sense anyway, so it's removed. As
+ * X509_STORE_CTX_cleanup does a proper "free" on the ex_data, we put a
+ * corresponding "new" here and remove this bogus initialisation. */
+ /* memset(&(ctx->ex_data),0,sizeof(CRYPTO_EX_DATA)); */
+ if(!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_X509_STORE_CTX, ctx,
+ &(ctx->ex_data)))
+ {
+ OPENSSL_free(ctx);
+ OPENSSL_PUT_ERROR(X509, X509_STORE_CTX_init, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ return 1;
+ }
+
+/* Set alternative lookup method: just a STACK of trusted certificates.
+ * This avoids X509_STORE nastiness where it isn't needed.
+ */
+
+void X509_STORE_CTX_trusted_stack(X509_STORE_CTX *ctx, STACK_OF(X509) *sk)
+{
+ ctx->other_ctx = sk;
+ ctx->get_issuer = get_issuer_sk;
+}
+
+void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx)
+ {
+ if (ctx->cleanup) ctx->cleanup(ctx);
+ if (ctx->param != NULL)
+ {
+ if (ctx->parent == NULL)
+ X509_VERIFY_PARAM_free(ctx->param);
+ ctx->param=NULL;
+ }
+ if (ctx->tree != NULL)
+ {
+ X509_policy_tree_free(ctx->tree);
+ ctx->tree=NULL;
+ }
+ if (ctx->chain != NULL)
+ {
+ sk_X509_pop_free(ctx->chain,X509_free);
+ ctx->chain=NULL;
+ }
+ CRYPTO_free_ex_data(CRYPTO_EX_INDEX_X509_STORE_CTX, ctx, &(ctx->ex_data));
+ memset(&ctx->ex_data,0,sizeof(CRYPTO_EX_DATA));
+ }
+
+void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth)
+ {
+ X509_VERIFY_PARAM_set_depth(ctx->param, depth);
+ }
+
+void X509_STORE_CTX_set_flags(X509_STORE_CTX *ctx, unsigned long flags)
+ {
+ X509_VERIFY_PARAM_set_flags(ctx->param, flags);
+ }
+
+void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx, unsigned long flags, time_t t)
+ {
+ X509_VERIFY_PARAM_set_time(ctx->param, t);
+ }
+
+void X509_STORE_CTX_set_verify_cb(X509_STORE_CTX *ctx,
+ int (*verify_cb)(int, X509_STORE_CTX *))
+ {
+ ctx->verify_cb=verify_cb;
+ }
+
+X509_POLICY_TREE *X509_STORE_CTX_get0_policy_tree(X509_STORE_CTX *ctx)
+ {
+ return ctx->tree;
+ }
+
+int X509_STORE_CTX_get_explicit_policy(X509_STORE_CTX *ctx)
+ {
+ return ctx->explicit_policy;
+ }
+
+int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx, const char *name)
+ {
+ const X509_VERIFY_PARAM *param;
+ param = X509_VERIFY_PARAM_lookup(name);
+ if (!param)
+ return 0;
+ return X509_VERIFY_PARAM_inherit(ctx->param, param);
+ }
+
+X509_VERIFY_PARAM *X509_STORE_CTX_get0_param(X509_STORE_CTX *ctx)
+ {
+ return ctx->param;
+ }
+
+void X509_STORE_CTX_set0_param(X509_STORE_CTX *ctx, X509_VERIFY_PARAM *param)
+ {
+ if (ctx->param)
+ X509_VERIFY_PARAM_free(ctx->param);
+ ctx->param = param;
+ }
+
+IMPLEMENT_ASN1_SET_OF(X509)
+IMPLEMENT_ASN1_SET_OF(X509_ATTRIBUTE)
diff --git a/crypto/x509/x509_vfy.h b/crypto/x509/x509_vfy.h
new file mode 100644
index 0000000..6054250
--- /dev/null
+++ b/crypto/x509/x509_vfy.h
@@ -0,0 +1,605 @@
+/* crypto/x509/x509_vfy.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_X509_H
+#include <openssl/x509.h>
+/* openssl/x509.h ends up #include-ing this file at about the only
+ * appropriate moment. */
+#endif
+
+#ifndef HEADER_X509_VFY_H
+#define HEADER_X509_VFY_H
+
+#include <openssl/bio.h>
+#include <openssl/lhash.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if 0
+/* Outer object */
+typedef struct x509_hash_dir_st
+ {
+ int num_dirs;
+ char **dirs;
+ int *dirs_type;
+ int num_dirs_alloced;
+ } X509_HASH_DIR_CTX;
+#endif
+
+typedef struct x509_file_st
+ {
+ int num_paths; /* number of paths to files or directories */
+ int num_alloced;
+ char **paths; /* the list of paths or directories */
+ int *path_type;
+ } X509_CERT_FILE_CTX;
+
+/*******************************/
+/*
+SSL_CTX -> X509_STORE
+ -> X509_LOOKUP
+ ->X509_LOOKUP_METHOD
+ -> X509_LOOKUP
+ ->X509_LOOKUP_METHOD
+
+SSL -> X509_STORE_CTX
+ ->X509_STORE
+
+The X509_STORE holds the tables etc for verification stuff.
+A X509_STORE_CTX is used while validating a single certificate.
+The X509_STORE has X509_LOOKUPs for looking up certs.
+The X509_STORE then calls a function to actually verify the
+certificate chain.
+*/
+
+#define X509_LU_RETRY -1
+#define X509_LU_FAIL 0
+#define X509_LU_X509 1
+#define X509_LU_CRL 2
+#define X509_LU_PKEY 3
+
+typedef struct x509_object_st
+ {
+ /* one of the above types */
+ int type;
+ union {
+ char *ptr;
+ X509 *x509;
+ X509_CRL *crl;
+ EVP_PKEY *pkey;
+ } data;
+ } X509_OBJECT;
+
+typedef struct x509_lookup_st X509_LOOKUP;
+
+DECLARE_STACK_OF(X509_LOOKUP)
+DECLARE_STACK_OF(X509_OBJECT)
+
+/* This is a static that defines the function interface */
+typedef struct x509_lookup_method_st
+ {
+ const char *name;
+ int (*new_item)(X509_LOOKUP *ctx);
+ void (*free)(X509_LOOKUP *ctx);
+ int (*init)(X509_LOOKUP *ctx);
+ int (*shutdown)(X509_LOOKUP *ctx);
+ int (*ctrl)(X509_LOOKUP *ctx,int cmd,const char *argc,long argl,
+ char **ret);
+ int (*get_by_subject)(X509_LOOKUP *ctx,int type,X509_NAME *name,
+ X509_OBJECT *ret);
+ int (*get_by_issuer_serial)(X509_LOOKUP *ctx,int type,X509_NAME *name,
+ ASN1_INTEGER *serial,X509_OBJECT *ret);
+ int (*get_by_fingerprint)(X509_LOOKUP *ctx,int type,
+ unsigned char *bytes,int len,
+ X509_OBJECT *ret);
+ int (*get_by_alias)(X509_LOOKUP *ctx,int type,char *str,int len,
+ X509_OBJECT *ret);
+ } X509_LOOKUP_METHOD;
+
+typedef struct X509_VERIFY_PARAM_ID_st X509_VERIFY_PARAM_ID;
+
+/* This structure hold all parameters associated with a verify operation
+ * by including an X509_VERIFY_PARAM structure in related structures the
+ * parameters used can be customized
+ */
+
+typedef struct X509_VERIFY_PARAM_st
+ {
+ char *name;
+ time_t check_time; /* Time to use */
+ unsigned long inh_flags; /* Inheritance flags */
+ unsigned long flags; /* Various verify flags */
+ int purpose; /* purpose to check untrusted certificates */
+ int trust; /* trust setting to check */
+ int depth; /* Verify depth */
+ STACK_OF(ASN1_OBJECT) *policies; /* Permissible policies */
+ X509_VERIFY_PARAM_ID *id; /* opaque ID data */
+ } X509_VERIFY_PARAM;
+
+DECLARE_STACK_OF(X509_VERIFY_PARAM)
+
+/* This is used to hold everything. It is used for all certificate
+ * validation. Once we have a certificate chain, the 'verify'
+ * function is then called to actually check the cert chain. */
+struct x509_store_st
+ {
+ /* The following is a cache of trusted certs */
+ int cache; /* if true, stash any hits */
+ STACK_OF(X509_OBJECT) *objs; /* Cache of all objects */
+
+ /* These are external lookup methods */
+ STACK_OF(X509_LOOKUP) *get_cert_methods;
+
+ X509_VERIFY_PARAM *param;
+
+ /* Callbacks for various operations */
+ int (*verify)(X509_STORE_CTX *ctx); /* called to verify a certificate */
+ int (*verify_cb)(int ok,X509_STORE_CTX *ctx); /* error callback */
+ int (*get_issuer)(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); /* get issuers cert from ctx */
+ int (*check_issued)(X509_STORE_CTX *ctx, X509 *x, X509 *issuer); /* check issued */
+ int (*check_revocation)(X509_STORE_CTX *ctx); /* Check revocation status of chain */
+ int (*get_crl)(X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x); /* retrieve CRL */
+ int (*check_crl)(X509_STORE_CTX *ctx, X509_CRL *crl); /* Check CRL validity */
+ int (*cert_crl)(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x); /* Check certificate against CRL */
+ STACK_OF(X509) * (*lookup_certs)(X509_STORE_CTX *ctx, X509_NAME *nm);
+ STACK_OF(X509_CRL) * (*lookup_crls)(X509_STORE_CTX *ctx, X509_NAME *nm);
+ int (*cleanup)(X509_STORE_CTX *ctx);
+
+ CRYPTO_EX_DATA ex_data;
+ int references;
+ } /* X509_STORE */;
+
+int X509_STORE_set_depth(X509_STORE *store, int depth);
+
+#define X509_STORE_set_verify_cb_func(ctx,func) ((ctx)->verify_cb=(func))
+#define X509_STORE_set_verify_func(ctx,func) ((ctx)->verify=(func))
+
+/* This is the functions plus an instance of the local variables. */
+struct x509_lookup_st
+ {
+ int init; /* have we been started */
+ int skip; /* don't use us. */
+ X509_LOOKUP_METHOD *method; /* the functions */
+ char *method_data; /* method data */
+
+ X509_STORE *store_ctx; /* who owns us */
+ } /* X509_LOOKUP */;
+
+/* This is a used when verifying cert chains. Since the
+ * gathering of the cert chain can take some time (and have to be
+ * 'retried', this needs to be kept and passed around. */
+struct x509_store_ctx_st /* X509_STORE_CTX */
+ {
+ X509_STORE *ctx;
+ int current_method; /* used when looking up certs */
+
+ /* The following are set by the caller */
+ X509 *cert; /* The cert to check */
+ STACK_OF(X509) *untrusted; /* chain of X509s - untrusted - passed in */
+ STACK_OF(X509_CRL) *crls; /* set of CRLs passed in */
+
+ X509_VERIFY_PARAM *param;
+ void *other_ctx; /* Other info for use with get_issuer() */
+
+ /* Callbacks for various operations */
+ int (*verify)(X509_STORE_CTX *ctx); /* called to verify a certificate */
+ int (*verify_cb)(int ok,X509_STORE_CTX *ctx); /* error callback */
+ int (*get_issuer)(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); /* get issuers cert from ctx */
+ int (*check_issued)(X509_STORE_CTX *ctx, X509 *x, X509 *issuer); /* check issued */
+ int (*check_revocation)(X509_STORE_CTX *ctx); /* Check revocation status of chain */
+ int (*get_crl)(X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x); /* retrieve CRL */
+ int (*check_crl)(X509_STORE_CTX *ctx, X509_CRL *crl); /* Check CRL validity */
+ int (*cert_crl)(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x); /* Check certificate against CRL */
+ int (*check_policy)(X509_STORE_CTX *ctx);
+ STACK_OF(X509) * (*lookup_certs)(X509_STORE_CTX *ctx, X509_NAME *nm);
+ STACK_OF(X509_CRL) * (*lookup_crls)(X509_STORE_CTX *ctx, X509_NAME *nm);
+ int (*cleanup)(X509_STORE_CTX *ctx);
+
+ /* The following is built up */
+ int valid; /* if 0, rebuild chain */
+ int last_untrusted; /* index of last untrusted cert */
+ STACK_OF(X509) *chain; /* chain of X509s - built up and trusted */
+ X509_POLICY_TREE *tree; /* Valid policy tree */
+
+ int explicit_policy; /* Require explicit policy value */
+
+ /* When something goes wrong, this is why */
+ int error_depth;
+ int error;
+ X509 *current_cert;
+ X509 *current_issuer; /* cert currently being tested as valid issuer */
+ X509_CRL *current_crl; /* current CRL */
+
+ int current_crl_score; /* score of current CRL */
+ unsigned int current_reasons; /* Reason mask */
+
+ X509_STORE_CTX *parent; /* For CRL path validation: parent context */
+
+ CRYPTO_EX_DATA ex_data;
+ } /* X509_STORE_CTX */;
+
+void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth);
+
+#define X509_STORE_CTX_set_app_data(ctx,data) \
+ X509_STORE_CTX_set_ex_data(ctx,0,data)
+#define X509_STORE_CTX_get_app_data(ctx) \
+ X509_STORE_CTX_get_ex_data(ctx,0)
+
+#define X509_L_FILE_LOAD 1
+#define X509_L_ADD_DIR 2
+
+#define X509_LOOKUP_load_file(x,name,type) \
+ X509_LOOKUP_ctrl((x),X509_L_FILE_LOAD,(name),(long)(type),NULL)
+
+#define X509_LOOKUP_add_dir(x,name,type) \
+ X509_LOOKUP_ctrl((x),X509_L_ADD_DIR,(name),(long)(type),NULL)
+
+#define X509_V_OK 0
+/* illegal error (for uninitialized values, to avoid X509_V_OK): 1 */
+
+#define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT 2
+#define X509_V_ERR_UNABLE_TO_GET_CRL 3
+#define X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE 4
+#define X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE 5
+#define X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY 6
+#define X509_V_ERR_CERT_SIGNATURE_FAILURE 7
+#define X509_V_ERR_CRL_SIGNATURE_FAILURE 8
+#define X509_V_ERR_CERT_NOT_YET_VALID 9
+#define X509_V_ERR_CERT_HAS_EXPIRED 10
+#define X509_V_ERR_CRL_NOT_YET_VALID 11
+#define X509_V_ERR_CRL_HAS_EXPIRED 12
+#define X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD 13
+#define X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD 14
+#define X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD 15
+#define X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD 16
+#define X509_V_ERR_OUT_OF_MEM 17
+#define X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT 18
+#define X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN 19
+#define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY 20
+#define X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE 21
+#define X509_V_ERR_CERT_CHAIN_TOO_LONG 22
+#define X509_V_ERR_CERT_REVOKED 23
+#define X509_V_ERR_INVALID_CA 24
+#define X509_V_ERR_PATH_LENGTH_EXCEEDED 25
+#define X509_V_ERR_INVALID_PURPOSE 26
+#define X509_V_ERR_CERT_UNTRUSTED 27
+#define X509_V_ERR_CERT_REJECTED 28
+/* These are 'informational' when looking for issuer cert */
+#define X509_V_ERR_SUBJECT_ISSUER_MISMATCH 29
+#define X509_V_ERR_AKID_SKID_MISMATCH 30
+#define X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH 31
+#define X509_V_ERR_KEYUSAGE_NO_CERTSIGN 32
+
+#define X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER 33
+#define X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION 34
+#define X509_V_ERR_KEYUSAGE_NO_CRL_SIGN 35
+#define X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION 36
+#define X509_V_ERR_INVALID_NON_CA 37
+#define X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED 38
+#define X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE 39
+#define X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED 40
+
+#define X509_V_ERR_INVALID_EXTENSION 41
+#define X509_V_ERR_INVALID_POLICY_EXTENSION 42
+#define X509_V_ERR_NO_EXPLICIT_POLICY 43
+#define X509_V_ERR_DIFFERENT_CRL_SCOPE 44
+#define X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE 45
+
+#define X509_V_ERR_UNNESTED_RESOURCE 46
+
+#define X509_V_ERR_PERMITTED_VIOLATION 47
+#define X509_V_ERR_EXCLUDED_VIOLATION 48
+#define X509_V_ERR_SUBTREE_MINMAX 49
+#define X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE 51
+#define X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX 52
+#define X509_V_ERR_UNSUPPORTED_NAME_SYNTAX 53
+#define X509_V_ERR_CRL_PATH_VALIDATION_ERROR 54
+
+/* Suite B mode algorithm violation */
+#define X509_V_ERR_SUITE_B_INVALID_VERSION 56
+#define X509_V_ERR_SUITE_B_INVALID_ALGORITHM 57
+#define X509_V_ERR_SUITE_B_INVALID_CURVE 58
+#define X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM 59
+#define X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED 60
+#define X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 61
+
+/* Host, email and IP check errors */
+#define X509_V_ERR_HOSTNAME_MISMATCH 62
+#define X509_V_ERR_EMAIL_MISMATCH 63
+#define X509_V_ERR_IP_ADDRESS_MISMATCH 64
+
+/* The application is not happy */
+#define X509_V_ERR_APPLICATION_VERIFICATION 50
+
+/* Certificate verify flags */
+
+/* Send issuer+subject checks to verify_cb */
+#define X509_V_FLAG_CB_ISSUER_CHECK 0x1
+/* Use check time instead of current time */
+#define X509_V_FLAG_USE_CHECK_TIME 0x2
+/* Lookup CRLs */
+#define X509_V_FLAG_CRL_CHECK 0x4
+/* Lookup CRLs for whole chain */
+#define X509_V_FLAG_CRL_CHECK_ALL 0x8
+/* Ignore unhandled critical extensions */
+#define X509_V_FLAG_IGNORE_CRITICAL 0x10
+/* Disable workarounds for broken certificates */
+#define X509_V_FLAG_X509_STRICT 0x20
+/* Enable proxy certificate validation */
+#define X509_V_FLAG_ALLOW_PROXY_CERTS 0x40
+/* Enable policy checking */
+#define X509_V_FLAG_POLICY_CHECK 0x80
+/* Policy variable require-explicit-policy */
+#define X509_V_FLAG_EXPLICIT_POLICY 0x100
+/* Policy variable inhibit-any-policy */
+#define X509_V_FLAG_INHIBIT_ANY 0x200
+/* Policy variable inhibit-policy-mapping */
+#define X509_V_FLAG_INHIBIT_MAP 0x400
+/* Notify callback that policy is OK */
+#define X509_V_FLAG_NOTIFY_POLICY 0x800
+/* Extended CRL features such as indirect CRLs, alternate CRL signing keys */
+#define X509_V_FLAG_EXTENDED_CRL_SUPPORT 0x1000
+/* Delta CRL support */
+#define X509_V_FLAG_USE_DELTAS 0x2000
+/* Check selfsigned CA signature */
+#define X509_V_FLAG_CHECK_SS_SIGNATURE 0x4000
+/* Use trusted store first */
+#define X509_V_FLAG_TRUSTED_FIRST 0x8000
+/* Suite B 128 bit only mode: not normally used */
+#define X509_V_FLAG_SUITEB_128_LOS_ONLY 0x10000
+/* Suite B 192 bit only mode */
+#define X509_V_FLAG_SUITEB_192_LOS 0x20000
+/* Suite B 128 bit mode allowing 192 bit algorithms */
+#define X509_V_FLAG_SUITEB_128_LOS 0x30000
+
+/* Allow partial chains if at least one certificate is in trusted store */
+#define X509_V_FLAG_PARTIAL_CHAIN 0x80000
+
+#define X509_VP_FLAG_DEFAULT 0x1
+#define X509_VP_FLAG_OVERWRITE 0x2
+#define X509_VP_FLAG_RESET_FLAGS 0x4
+#define X509_VP_FLAG_LOCKED 0x8
+#define X509_VP_FLAG_ONCE 0x10
+
+/* Internal use: mask of policy related options */
+#define X509_V_FLAG_POLICY_MASK (X509_V_FLAG_POLICY_CHECK \
+ | X509_V_FLAG_EXPLICIT_POLICY \
+ | X509_V_FLAG_INHIBIT_ANY \
+ | X509_V_FLAG_INHIBIT_MAP)
+
+int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, int type,
+ X509_NAME *name);
+X509_OBJECT *X509_OBJECT_retrieve_by_subject(STACK_OF(X509_OBJECT) *h,int type,X509_NAME *name);
+X509_OBJECT *X509_OBJECT_retrieve_match(STACK_OF(X509_OBJECT) *h, X509_OBJECT *x);
+void X509_OBJECT_up_ref_count(X509_OBJECT *a);
+void X509_OBJECT_free_contents(X509_OBJECT *a);
+X509_STORE *X509_STORE_new(void );
+void X509_STORE_free(X509_STORE *v);
+
+STACK_OF(X509)* X509_STORE_get1_certs(X509_STORE_CTX *st, X509_NAME *nm);
+STACK_OF(X509_CRL)* X509_STORE_get1_crls(X509_STORE_CTX *st, X509_NAME *nm);
+int X509_STORE_set_flags(X509_STORE *ctx, unsigned long flags);
+int X509_STORE_set_purpose(X509_STORE *ctx, int purpose);
+int X509_STORE_set_trust(X509_STORE *ctx, int trust);
+int X509_STORE_set1_param(X509_STORE *ctx, X509_VERIFY_PARAM *pm);
+
+void X509_STORE_set_verify_cb(X509_STORE *ctx,
+ int (*verify_cb)(int, X509_STORE_CTX *));
+
+void X509_STORE_set_lookup_crls_cb(X509_STORE *ctx,
+ STACK_OF(X509_CRL)* (*cb)(X509_STORE_CTX *ctx, X509_NAME *nm));
+
+X509_STORE_CTX *X509_STORE_CTX_new(void);
+
+int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x);
+
+void X509_STORE_CTX_free(X509_STORE_CTX *ctx);
+int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store,
+ X509 *x509, STACK_OF(X509) *chain);
+void X509_STORE_CTX_trusted_stack(X509_STORE_CTX *ctx, STACK_OF(X509) *sk);
+void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx);
+
+X509_STORE *X509_STORE_CTX_get0_store(X509_STORE_CTX *ctx);
+
+X509_LOOKUP *X509_STORE_add_lookup(X509_STORE *v, X509_LOOKUP_METHOD *m);
+
+X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void);
+X509_LOOKUP_METHOD *X509_LOOKUP_file(void);
+
+int X509_STORE_add_cert(X509_STORE *ctx, X509 *x);
+int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x);
+
+int X509_STORE_get_by_subject(X509_STORE_CTX *vs,int type,X509_NAME *name,
+ X509_OBJECT *ret);
+
+int X509_LOOKUP_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc,
+ long argl, char **ret);
+
+#ifndef OPENSSL_NO_STDIO
+int X509_load_cert_file(X509_LOOKUP *ctx, const char *file, int type);
+int X509_load_crl_file(X509_LOOKUP *ctx, const char *file, int type);
+int X509_load_cert_crl_file(X509_LOOKUP *ctx, const char *file, int type);
+#endif
+
+
+X509_LOOKUP *X509_LOOKUP_new(X509_LOOKUP_METHOD *method);
+void X509_LOOKUP_free(X509_LOOKUP *ctx);
+int X509_LOOKUP_init(X509_LOOKUP *ctx);
+int X509_LOOKUP_by_subject(X509_LOOKUP *ctx, int type, X509_NAME *name,
+ X509_OBJECT *ret);
+int X509_LOOKUP_by_issuer_serial(X509_LOOKUP *ctx, int type, X509_NAME *name,
+ ASN1_INTEGER *serial, X509_OBJECT *ret);
+int X509_LOOKUP_by_fingerprint(X509_LOOKUP *ctx, int type,
+ unsigned char *bytes, int len, X509_OBJECT *ret);
+int X509_LOOKUP_by_alias(X509_LOOKUP *ctx, int type, char *str,
+ int len, X509_OBJECT *ret);
+int X509_LOOKUP_shutdown(X509_LOOKUP *ctx);
+
+#ifndef OPENSSL_NO_STDIO
+int X509_STORE_load_locations (X509_STORE *ctx,
+ const char *file, const char *dir);
+int X509_STORE_set_default_paths(X509_STORE *ctx);
+#endif
+
+int X509_STORE_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+ CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+int X509_STORE_CTX_set_ex_data(X509_STORE_CTX *ctx,int idx,void *data);
+void * X509_STORE_CTX_get_ex_data(X509_STORE_CTX *ctx,int idx);
+int X509_STORE_CTX_get_error(X509_STORE_CTX *ctx);
+void X509_STORE_CTX_set_error(X509_STORE_CTX *ctx,int s);
+int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *ctx);
+X509 * X509_STORE_CTX_get_current_cert(X509_STORE_CTX *ctx);
+X509 *X509_STORE_CTX_get0_current_issuer(X509_STORE_CTX *ctx);
+X509_CRL *X509_STORE_CTX_get0_current_crl(X509_STORE_CTX *ctx);
+X509_STORE_CTX *X509_STORE_CTX_get0_parent_ctx(X509_STORE_CTX *ctx);
+STACK_OF(X509) *X509_STORE_CTX_get_chain(X509_STORE_CTX *ctx);
+STACK_OF(X509) *X509_STORE_CTX_get1_chain(X509_STORE_CTX *ctx);
+void X509_STORE_CTX_set_cert(X509_STORE_CTX *c,X509 *x);
+void X509_STORE_CTX_set_chain(X509_STORE_CTX *c,STACK_OF(X509) *sk);
+void X509_STORE_CTX_set0_crls(X509_STORE_CTX *c,STACK_OF(X509_CRL) *sk);
+int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose);
+int X509_STORE_CTX_set_trust(X509_STORE_CTX *ctx, int trust);
+int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose,
+ int purpose, int trust);
+void X509_STORE_CTX_set_flags(X509_STORE_CTX *ctx, unsigned long flags);
+void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx, unsigned long flags,
+ time_t t);
+void X509_STORE_CTX_set_verify_cb(X509_STORE_CTX *ctx,
+ int (*verify_cb)(int, X509_STORE_CTX *));
+
+X509_POLICY_TREE *X509_STORE_CTX_get0_policy_tree(X509_STORE_CTX *ctx);
+int X509_STORE_CTX_get_explicit_policy(X509_STORE_CTX *ctx);
+
+X509_VERIFY_PARAM *X509_STORE_CTX_get0_param(X509_STORE_CTX *ctx);
+void X509_STORE_CTX_set0_param(X509_STORE_CTX *ctx, X509_VERIFY_PARAM *param);
+int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx, const char *name);
+
+/* X509_VERIFY_PARAM functions */
+
+X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void);
+void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param);
+int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *to,
+ const X509_VERIFY_PARAM *from);
+int X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to,
+ const X509_VERIFY_PARAM *from);
+int X509_VERIFY_PARAM_set1_name(X509_VERIFY_PARAM *param, const char *name);
+int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *param, unsigned long flags);
+int X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *param,
+ unsigned long flags);
+unsigned long X509_VERIFY_PARAM_get_flags(X509_VERIFY_PARAM *param);
+int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param, int purpose);
+int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param, int trust);
+void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *param, int depth);
+void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param, time_t t);
+int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param,
+ ASN1_OBJECT *policy);
+int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param,
+ STACK_OF(ASN1_OBJECT) *policies);
+
+int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param,
+ const unsigned char *name, size_t namelen);
+int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param,
+ const unsigned char *email, size_t emaillen);
+int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param,
+ const unsigned char *ip, size_t iplen);
+int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param, const char *ipasc);
+
+int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param);
+const char *X509_VERIFY_PARAM_get0_name(const X509_VERIFY_PARAM *param);
+
+int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param);
+int X509_VERIFY_PARAM_get_count(void);
+const X509_VERIFY_PARAM *X509_VERIFY_PARAM_get0(int id);
+const X509_VERIFY_PARAM *X509_VERIFY_PARAM_lookup(const char *name);
+void X509_VERIFY_PARAM_table_cleanup(void);
+
+int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy,
+ STACK_OF(X509) *certs,
+ STACK_OF(ASN1_OBJECT) *policy_oids,
+ unsigned int flags);
+
+void X509_policy_tree_free(X509_POLICY_TREE *tree);
+
+int X509_policy_tree_level_count(const X509_POLICY_TREE *tree);
+X509_POLICY_LEVEL *
+ X509_policy_tree_get0_level(const X509_POLICY_TREE *tree, int i);
+
+STACK_OF(X509_POLICY_NODE) *
+ X509_policy_tree_get0_policies(const X509_POLICY_TREE *tree);
+
+STACK_OF(X509_POLICY_NODE) *
+ X509_policy_tree_get0_user_policies(const X509_POLICY_TREE *tree);
+
+int X509_policy_level_node_count(X509_POLICY_LEVEL *level);
+
+X509_POLICY_NODE *X509_policy_level_get0_node(X509_POLICY_LEVEL *level, int i);
+
+const ASN1_OBJECT *X509_policy_node_get0_policy(const X509_POLICY_NODE *node);
+
+STACK_OF(POLICYQUALINFO) *
+ X509_policy_node_get0_qualifiers(const X509_POLICY_NODE *node);
+const X509_POLICY_NODE *
+ X509_policy_node_get0_parent(const X509_POLICY_NODE *node);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/crypto/x509/x509_vpm.c b/crypto/x509/x509_vpm.c
new file mode 100644
index 0000000..25b0987
--- /dev/null
+++ b/crypto/x509/x509_vpm.c
@@ -0,0 +1,578 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2004. */
+/* ====================================================================
+ * Copyright (c) 2004 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/buf.h>
+#include <openssl/lhash.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#include "vpm_int.h"
+
+/* X509_VERIFY_PARAM functions */
+
+static void x509_verify_param_zero(X509_VERIFY_PARAM *param)
+ {
+ X509_VERIFY_PARAM_ID *paramid;
+ if (!param)
+ return;
+ param->name = NULL;
+ param->purpose = 0;
+ param->trust = 0;
+ /*param->inh_flags = X509_VP_FLAG_DEFAULT;*/
+ param->inh_flags = 0;
+ param->flags = 0;
+ param->depth = -1;
+ if (param->policies)
+ {
+ sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free);
+ param->policies = NULL;
+ }
+ paramid = param->id;
+ if (paramid->host)
+ {
+ OPENSSL_free(paramid->host);
+ paramid->host = NULL;
+ paramid->hostlen = 0;
+ }
+ if (paramid->email)
+ {
+ OPENSSL_free(paramid->email);
+ paramid->email = NULL;
+ paramid->emaillen = 0;
+ }
+ if (paramid->ip)
+ {
+ OPENSSL_free(paramid->ip);
+ paramid->ip = NULL;
+ paramid->iplen = 0;
+ }
+
+ }
+
+X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void)
+ {
+ X509_VERIFY_PARAM *param;
+ X509_VERIFY_PARAM_ID *paramid;
+ param = OPENSSL_malloc(sizeof(X509_VERIFY_PARAM));
+ if (!param)
+ return NULL;
+ paramid = OPENSSL_malloc(sizeof(X509_VERIFY_PARAM));
+ if (!paramid)
+ {
+ OPENSSL_free(param);
+ return NULL;
+ }
+ memset(param, 0, sizeof(X509_VERIFY_PARAM));
+ memset(paramid, 0, sizeof(X509_VERIFY_PARAM_ID));
+ param->id = paramid;
+ x509_verify_param_zero(param);
+ return param;
+ }
+
+void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param)
+ {
+ x509_verify_param_zero(param);
+ OPENSSL_free(param->id);
+ OPENSSL_free(param);
+ }
+
+/* This function determines how parameters are "inherited" from one structure
+ * to another. There are several different ways this can happen.
+ *
+ * 1. If a child structure needs to have its values initialized from a parent
+ * they are simply copied across. For example SSL_CTX copied to SSL.
+ * 2. If the structure should take on values only if they are currently unset.
+ * For example the values in an SSL structure will take appropriate value
+ * for SSL servers or clients but only if the application has not set new
+ * ones.
+ *
+ * The "inh_flags" field determines how this function behaves.
+ *
+ * Normally any values which are set in the default are not copied from the
+ * destination and verify flags are ORed together.
+ *
+ * If X509_VP_FLAG_DEFAULT is set then anything set in the source is copied
+ * to the destination. Effectively the values in "to" become default values
+ * which will be used only if nothing new is set in "from".
+ *
+ * If X509_VP_FLAG_OVERWRITE is set then all value are copied across whether
+ * they are set or not. Flags is still Ored though.
+ *
+ * If X509_VP_FLAG_RESET_FLAGS is set then the flags value is copied instead
+ * of ORed.
+ *
+ * If X509_VP_FLAG_LOCKED is set then no values are copied.
+ *
+ * If X509_VP_FLAG_ONCE is set then the current inh_flags setting is zeroed
+ * after the next call.
+ */
+
+/* Macro to test if a field should be copied from src to dest */
+
+#define test_x509_verify_param_copy(field, def) \
+ (to_overwrite || \
+ ((src->field != def) && (to_default || (dest->field == def))))
+
+/* As above but for ID fields */
+
+#define test_x509_verify_param_copy_id(idf, def) \
+ test_x509_verify_param_copy(id->idf, def)
+
+/* Macro to test and copy a field if necessary */
+
+#define x509_verify_param_copy(field, def) \
+ if (test_x509_verify_param_copy(field, def)) \
+ dest->field = src->field
+
+
+int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest,
+ const X509_VERIFY_PARAM *src)
+ {
+ unsigned long inh_flags;
+ int to_default, to_overwrite;
+ X509_VERIFY_PARAM_ID *id;
+ if (!src)
+ return 1;
+ id = src->id;
+ inh_flags = dest->inh_flags | src->inh_flags;
+
+ if (inh_flags & X509_VP_FLAG_ONCE)
+ dest->inh_flags = 0;
+
+ if (inh_flags & X509_VP_FLAG_LOCKED)
+ return 1;
+
+ if (inh_flags & X509_VP_FLAG_DEFAULT)
+ to_default = 1;
+ else
+ to_default = 0;
+
+ if (inh_flags & X509_VP_FLAG_OVERWRITE)
+ to_overwrite = 1;
+ else
+ to_overwrite = 0;
+
+ x509_verify_param_copy(purpose, 0);
+ x509_verify_param_copy(trust, 0);
+ x509_verify_param_copy(depth, -1);
+
+ /* If overwrite or check time not set, copy across */
+
+ if (to_overwrite || !(dest->flags & X509_V_FLAG_USE_CHECK_TIME))
+ {
+ dest->check_time = src->check_time;
+ dest->flags &= ~X509_V_FLAG_USE_CHECK_TIME;
+ /* Don't need to copy flag: that is done below */
+ }
+
+ if (inh_flags & X509_VP_FLAG_RESET_FLAGS)
+ dest->flags = 0;
+
+ dest->flags |= src->flags;
+
+ if (test_x509_verify_param_copy(policies, NULL))
+ {
+ if (!X509_VERIFY_PARAM_set1_policies(dest, src->policies))
+ return 0;
+ }
+
+ if (test_x509_verify_param_copy_id(host, NULL))
+ {
+ if (!X509_VERIFY_PARAM_set1_host(dest, id->host, id->hostlen))
+ return 0;
+ }
+
+ if (test_x509_verify_param_copy_id(email, NULL))
+ {
+ if (!X509_VERIFY_PARAM_set1_email(dest, id->email, id->emaillen))
+ return 0;
+ }
+
+ if (test_x509_verify_param_copy_id(ip, NULL))
+ {
+ if (!X509_VERIFY_PARAM_set1_ip(dest, id->ip, id->iplen))
+ return 0;
+ }
+
+ return 1;
+ }
+
+int X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to,
+ const X509_VERIFY_PARAM *from)
+ {
+ unsigned long save_flags = to->inh_flags;
+ int ret;
+ to->inh_flags |= X509_VP_FLAG_DEFAULT;
+ ret = X509_VERIFY_PARAM_inherit(to, from);
+ to->inh_flags = save_flags;
+ return ret;
+ }
+
+static int int_x509_param_set1(unsigned char **pdest, size_t *pdestlen,
+ const unsigned char *src, size_t srclen)
+ {
+ void *tmp;
+ if (src)
+ {
+ if (srclen == 0)
+ {
+ tmp = BUF_strdup((char *)src);
+ srclen = strlen((char *)src);
+ }
+ else
+ tmp = BUF_memdup(src, srclen);
+ if (!tmp)
+ return 0;
+ }
+ else
+ {
+ tmp = NULL;
+ srclen = 0;
+ }
+ if (*pdest)
+ OPENSSL_free(*pdest);
+ *pdest = tmp;
+ if (pdestlen)
+ *pdestlen = srclen;
+ return 1;
+ }
+
+int X509_VERIFY_PARAM_set1_name(X509_VERIFY_PARAM *param, const char *name)
+ {
+ if (param->name)
+ OPENSSL_free(param->name);
+ param->name = BUF_strdup(name);
+ if (param->name)
+ return 1;
+ return 0;
+ }
+
+int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *param, unsigned long flags)
+ {
+ param->flags |= flags;
+ if (flags & X509_V_FLAG_POLICY_MASK)
+ param->flags |= X509_V_FLAG_POLICY_CHECK;
+ return 1;
+ }
+
+int X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *param, unsigned long flags)
+ {
+ param->flags &= ~flags;
+ return 1;
+ }
+
+unsigned long X509_VERIFY_PARAM_get_flags(X509_VERIFY_PARAM *param)
+ {
+ return param->flags;
+ }
+
+int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param, int purpose)
+ {
+ return X509_PURPOSE_set(¶m->purpose, purpose);
+ }
+
+int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param, int trust)
+ {
+ return X509_TRUST_set(¶m->trust, trust);
+ }
+
+void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *param, int depth)
+ {
+ param->depth = depth;
+ }
+
+void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param, time_t t)
+ {
+ param->check_time = t;
+ param->flags |= X509_V_FLAG_USE_CHECK_TIME;
+ }
+
+int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param, ASN1_OBJECT *policy)
+ {
+ if (!param->policies)
+ {
+ param->policies = sk_ASN1_OBJECT_new_null();
+ if (!param->policies)
+ return 0;
+ }
+ if (!sk_ASN1_OBJECT_push(param->policies, policy))
+ return 0;
+ return 1;
+ }
+
+int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param,
+ STACK_OF(ASN1_OBJECT) *policies)
+ {
+ size_t i;
+ ASN1_OBJECT *oid, *doid;
+ if (!param)
+ return 0;
+ if (param->policies)
+ sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free);
+
+ if (!policies)
+ {
+ param->policies = NULL;
+ return 1;
+ }
+
+ param->policies = sk_ASN1_OBJECT_new_null();
+ if (!param->policies)
+ return 0;
+
+ for (i = 0; i < sk_ASN1_OBJECT_num(policies); i++)
+ {
+ oid = sk_ASN1_OBJECT_value(policies, i);
+ doid = OBJ_dup(oid);
+ if (!doid)
+ return 0;
+ if (!sk_ASN1_OBJECT_push(param->policies, doid))
+ {
+ ASN1_OBJECT_free(doid);
+ return 0;
+ }
+ }
+ param->flags |= X509_V_FLAG_POLICY_CHECK;
+ return 1;
+ }
+
+int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param,
+ const unsigned char *name, size_t namelen)
+ {
+ return int_x509_param_set1(¶m->id->host, ¶m->id->hostlen,
+ name, namelen);
+ }
+
+int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param,
+ const unsigned char *email, size_t emaillen)
+ {
+ return int_x509_param_set1(¶m->id->email, ¶m->id->emaillen,
+ email, emaillen);
+ }
+
+int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param,
+ const unsigned char *ip, size_t iplen)
+ {
+ if (iplen != 0 && iplen != 4 && iplen != 16)
+ return 0;
+ return int_x509_param_set1(¶m->id->ip, ¶m->id->iplen, ip, iplen);
+ }
+
+int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param, const char *ipasc)
+ {
+ unsigned char ipout[16];
+ int iplen;
+ iplen = a2i_ipadd(ipout, ipasc);
+ if (iplen == 0)
+ return 0;
+ return X509_VERIFY_PARAM_set1_ip(param, ipout, (size_t)iplen);
+ }
+
+int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param)
+ {
+ return param->depth;
+ }
+
+const char *X509_VERIFY_PARAM_get0_name(const X509_VERIFY_PARAM *param)
+ {
+ return param->name;
+ }
+
+static X509_VERIFY_PARAM_ID _empty_id = {NULL, 0, NULL, 0, NULL, 0};
+
+#define vpm_empty_id (X509_VERIFY_PARAM_ID *)&_empty_id
+
+/* Default verify parameters: these are used for various
+ * applications and can be overridden by the user specified table.
+ * NB: the 'name' field *must* be in alphabetical order because it
+ * will be searched using OBJ_search.
+ */
+
+static const X509_VERIFY_PARAM default_table[] = {
+ {
+ "default", /* X509 default parameters */
+ 0, /* Check time */
+ 0, /* internal flags */
+ 0, /* flags */
+ 0, /* purpose */
+ 0, /* trust */
+ 100, /* depth */
+ NULL, /* policies */
+ vpm_empty_id
+ },
+ {
+ "pkcs7", /* S/MIME sign parameters */
+ 0, /* Check time */
+ 0, /* internal flags */
+ 0, /* flags */
+ X509_PURPOSE_SMIME_SIGN, /* purpose */
+ X509_TRUST_EMAIL, /* trust */
+ -1, /* depth */
+ NULL, /* policies */
+ vpm_empty_id
+ },
+ {
+ "smime_sign", /* S/MIME sign parameters */
+ 0, /* Check time */
+ 0, /* internal flags */
+ 0, /* flags */
+ X509_PURPOSE_SMIME_SIGN, /* purpose */
+ X509_TRUST_EMAIL, /* trust */
+ -1, /* depth */
+ NULL, /* policies */
+ vpm_empty_id
+ },
+ {
+ "ssl_client", /* SSL/TLS client parameters */
+ 0, /* Check time */
+ 0, /* internal flags */
+ 0, /* flags */
+ X509_PURPOSE_SSL_CLIENT, /* purpose */
+ X509_TRUST_SSL_CLIENT, /* trust */
+ -1, /* depth */
+ NULL, /* policies */
+ vpm_empty_id
+ },
+ {
+ "ssl_server", /* SSL/TLS server parameters */
+ 0, /* Check time */
+ 0, /* internal flags */
+ 0, /* flags */
+ X509_PURPOSE_SSL_SERVER, /* purpose */
+ X509_TRUST_SSL_SERVER, /* trust */
+ -1, /* depth */
+ NULL, /* policies */
+ vpm_empty_id
+ }};
+
+static STACK_OF(X509_VERIFY_PARAM) *param_table = NULL;
+
+static int param_cmp(const X509_VERIFY_PARAM **a,
+ const X509_VERIFY_PARAM **b)
+ {
+ return strcmp((*a)->name, (*b)->name);
+ }
+
+int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param)
+ {
+ X509_VERIFY_PARAM *ptmp;
+ if (!param_table)
+ {
+ param_table = sk_X509_VERIFY_PARAM_new(param_cmp);
+ if (!param_table)
+ return 0;
+ }
+ else
+ {
+ size_t idx;
+
+ if (sk_X509_VERIFY_PARAM_find(param_table, &idx, param))
+ {
+ ptmp = sk_X509_VERIFY_PARAM_value(param_table, idx);
+ X509_VERIFY_PARAM_free(ptmp);
+ (void)sk_X509_VERIFY_PARAM_delete(param_table, idx);
+ }
+ }
+ if (!sk_X509_VERIFY_PARAM_push(param_table, param))
+ return 0;
+ return 1;
+ }
+
+int X509_VERIFY_PARAM_get_count(void)
+ {
+ int num = sizeof(default_table)/sizeof(X509_VERIFY_PARAM);
+ if (param_table)
+ num += sk_X509_VERIFY_PARAM_num(param_table);
+ return num;
+ }
+
+const X509_VERIFY_PARAM *X509_VERIFY_PARAM_get0(int id)
+ {
+ int num = sizeof(default_table)/sizeof(X509_VERIFY_PARAM);
+ if (id < num)
+ return default_table + id;
+ return sk_X509_VERIFY_PARAM_value(param_table, id - num);
+ }
+
+const X509_VERIFY_PARAM *X509_VERIFY_PARAM_lookup(const char *name)
+ {
+ X509_VERIFY_PARAM pm;
+ unsigned i, limit;
+
+ pm.name = (char *)name;
+ if (param_table)
+ {
+ size_t idx;
+ if (sk_X509_VERIFY_PARAM_find(param_table, &idx, &pm))
+ return sk_X509_VERIFY_PARAM_value(param_table, idx);
+ }
+
+ limit = sizeof(default_table)/sizeof(X509_VERIFY_PARAM);
+ for (i = 0; i < limit; i++) {
+ if (strcmp(default_table[i].name, name) == 0) {
+ return &default_table[i];
+ }
+ }
+ return NULL;
+ }
+
+void X509_VERIFY_PARAM_table_cleanup(void)
+ {
+ if (param_table)
+ sk_X509_VERIFY_PARAM_pop_free(param_table,
+ X509_VERIFY_PARAM_free);
+ param_table = NULL;
+ }
diff --git a/crypto/x509/x509cset.c b/crypto/x509/x509cset.c
new file mode 100644
index 0000000..b526c69
--- /dev/null
+++ b/crypto/x509/x509cset.c
@@ -0,0 +1,165 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2001. */
+/* ====================================================================
+ * Copyright (c) 2001 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/asn1.h>
+#include <openssl/evp.h>
+#include <openssl/obj.h>
+#include <openssl/x509.h>
+
+
+int X509_CRL_set_version(X509_CRL *x, long version)
+ {
+ if (x == NULL) return(0);
+ if (x->crl->version == NULL)
+ {
+ if ((x->crl->version=M_ASN1_INTEGER_new()) == NULL)
+ return(0);
+ }
+ return(ASN1_INTEGER_set(x->crl->version,version));
+ }
+
+int X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name)
+ {
+ if ((x == NULL) || (x->crl == NULL)) return(0);
+ return(X509_NAME_set(&x->crl->issuer,name));
+ }
+
+
+int X509_CRL_set_lastUpdate(X509_CRL *x, const ASN1_TIME *tm)
+ {
+ ASN1_TIME *in;
+
+ if (x == NULL) return(0);
+ in=x->crl->lastUpdate;
+ if (in != tm)
+ {
+ in=M_ASN1_TIME_dup(tm);
+ if (in != NULL)
+ {
+ M_ASN1_TIME_free(x->crl->lastUpdate);
+ x->crl->lastUpdate=in;
+ }
+ }
+ return(in != NULL);
+ }
+
+int X509_CRL_set_nextUpdate(X509_CRL *x, const ASN1_TIME *tm)
+ {
+ ASN1_TIME *in;
+
+ if (x == NULL) return(0);
+ in=x->crl->nextUpdate;
+ if (in != tm)
+ {
+ in=M_ASN1_TIME_dup(tm);
+ if (in != NULL)
+ {
+ M_ASN1_TIME_free(x->crl->nextUpdate);
+ x->crl->nextUpdate=in;
+ }
+ }
+ return(in != NULL);
+ }
+
+int X509_CRL_sort(X509_CRL *c)
+ {
+ size_t i;
+ X509_REVOKED *r;
+ /* sort the data so it will be written in serial
+ * number order */
+ sk_X509_REVOKED_sort(c->crl->revoked);
+ for (i=0; i<sk_X509_REVOKED_num(c->crl->revoked); i++)
+ {
+ r=sk_X509_REVOKED_value(c->crl->revoked,i);
+ r->sequence=i;
+ }
+ c->crl->enc.modified = 1;
+ return 1;
+ }
+
+int X509_REVOKED_set_revocationDate(X509_REVOKED *x, ASN1_TIME *tm)
+ {
+ ASN1_TIME *in;
+
+ if (x == NULL) return(0);
+ in=x->revocationDate;
+ if (in != tm)
+ {
+ in=M_ASN1_TIME_dup(tm);
+ if (in != NULL)
+ {
+ M_ASN1_TIME_free(x->revocationDate);
+ x->revocationDate=in;
+ }
+ }
+ return(in != NULL);
+ }
+
+int X509_REVOKED_set_serialNumber(X509_REVOKED *x, ASN1_INTEGER *serial)
+ {
+ ASN1_INTEGER *in;
+
+ if (x == NULL) return(0);
+ in=x->serialNumber;
+ if (in != serial)
+ {
+ in=M_ASN1_INTEGER_dup(serial);
+ if (in != NULL)
+ {
+ M_ASN1_INTEGER_free(x->serialNumber);
+ x->serialNumber=in;
+ }
+ }
+ return(in != NULL);
+ }
diff --git a/crypto/x509/x509name.c b/crypto/x509/x509name.c
new file mode 100644
index 0000000..4a5ea17
--- /dev/null
+++ b/crypto/x509/x509name.c
@@ -0,0 +1,379 @@
+/* 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/asn1.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/obj.h>
+#include <openssl/stack.h>
+#include <openssl/x509.h>
+
+
+int X509_NAME_get_text_by_NID(X509_NAME *name, int nid, char *buf, int len)
+ {
+ const ASN1_OBJECT *obj;
+
+ obj=OBJ_nid2obj(nid);
+ if (obj == NULL) return(-1);
+ return(X509_NAME_get_text_by_OBJ(name,obj,buf,len));
+ }
+
+int X509_NAME_get_text_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, char *buf,
+ int len)
+ {
+ int i;
+ ASN1_STRING *data;
+
+ i=X509_NAME_get_index_by_OBJ(name,obj,-1);
+ if (i < 0) return(-1);
+ data=X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name,i));
+ i=(data->length > (len-1))?(len-1):data->length;
+ if (buf == NULL) return(data->length);
+ memcpy(buf,data->data,i);
+ buf[i]='\0';
+ return(i);
+ }
+
+int X509_NAME_entry_count(X509_NAME *name)
+ {
+ if (name == NULL) return(0);
+ return(sk_X509_NAME_ENTRY_num(name->entries));
+ }
+
+int X509_NAME_get_index_by_NID(X509_NAME *name, int nid, int lastpos)
+ {
+ const ASN1_OBJECT *obj;
+
+ obj=OBJ_nid2obj(nid);
+ if (obj == NULL) return(-2);
+ return(X509_NAME_get_index_by_OBJ(name,obj,lastpos));
+ }
+
+/* NOTE: you should be passsing -1, not 0 as lastpos */
+int X509_NAME_get_index_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj,
+ int lastpos)
+ {
+ int n;
+ X509_NAME_ENTRY *ne;
+ STACK_OF(X509_NAME_ENTRY) *sk;
+
+ if (name == NULL) return(-1);
+ if (lastpos < 0)
+ lastpos= -1;
+ sk=name->entries;
+ n=sk_X509_NAME_ENTRY_num(sk);
+ for (lastpos++; lastpos < n; lastpos++)
+ {
+ ne=sk_X509_NAME_ENTRY_value(sk,lastpos);
+ if (OBJ_cmp(ne->object,obj) == 0)
+ return(lastpos);
+ }
+ return(-1);
+ }
+
+X509_NAME_ENTRY *X509_NAME_get_entry(X509_NAME *name, int loc)
+ {
+ if(name == NULL || loc < 0 || sk_X509_NAME_ENTRY_num(name->entries) <= (size_t) loc)
+ return(NULL);
+ else
+ return(sk_X509_NAME_ENTRY_value(name->entries,loc));
+ }
+
+X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *name, int loc)
+ {
+ X509_NAME_ENTRY *ret;
+ int i,n,set_prev,set_next;
+ STACK_OF(X509_NAME_ENTRY) *sk;
+
+ if (name == NULL || loc < 0 || sk_X509_NAME_ENTRY_num(name->entries) <= (size_t) loc)
+ return(NULL);
+ sk=name->entries;
+ ret=sk_X509_NAME_ENTRY_delete(sk,loc);
+ n=sk_X509_NAME_ENTRY_num(sk);
+ name->modified=1;
+ if (loc == n) return(ret);
+
+ /* else we need to fixup the set field */
+ if (loc != 0)
+ set_prev=(sk_X509_NAME_ENTRY_value(sk,loc-1))->set;
+ else
+ set_prev=ret->set-1;
+ set_next=sk_X509_NAME_ENTRY_value(sk,loc)->set;
+
+ /* set_prev is the previous set
+ * set is the current set
+ * set_next is the following
+ * prev 1 1 1 1 1 1 1 1
+ * set 1 1 2 2
+ * next 1 1 2 2 2 2 3 2
+ * so basically only if prev and next differ by 2, then
+ * re-number down by 1 */
+ if (set_prev+1 < set_next)
+ for (i=loc; i<n; i++)
+ sk_X509_NAME_ENTRY_value(sk,i)->set--;
+ return(ret);
+ }
+
+int X509_NAME_add_entry_by_OBJ(X509_NAME *name, ASN1_OBJECT *obj, int type,
+ unsigned char *bytes, int len, int loc, int set)
+{
+ X509_NAME_ENTRY *ne;
+ int ret;
+ ne = X509_NAME_ENTRY_create_by_OBJ(NULL, obj, type, bytes, len);
+ if(!ne) return 0;
+ ret = X509_NAME_add_entry(name, ne, loc, set);
+ X509_NAME_ENTRY_free(ne);
+ return ret;
+}
+
+int X509_NAME_add_entry_by_NID(X509_NAME *name, int nid, int type,
+ unsigned char *bytes, int len, int loc, int set)
+{
+ X509_NAME_ENTRY *ne;
+ int ret;
+ ne = X509_NAME_ENTRY_create_by_NID(NULL, nid, type, bytes, len);
+ if(!ne) return 0;
+ ret = X509_NAME_add_entry(name, ne, loc, set);
+ X509_NAME_ENTRY_free(ne);
+ return ret;
+}
+
+int X509_NAME_add_entry_by_txt(X509_NAME *name, const char *field, int type,
+ const unsigned char *bytes, int len, int loc, int set)
+{
+ X509_NAME_ENTRY *ne;
+ int ret;
+ ne = X509_NAME_ENTRY_create_by_txt(NULL, field, type, bytes, len);
+ if(!ne) return 0;
+ ret = X509_NAME_add_entry(name, ne, loc, set);
+ X509_NAME_ENTRY_free(ne);
+ return ret;
+}
+
+/* if set is -1, append to previous set, 0 'a new one', and 1,
+ * prepend to the guy we are about to stomp on. */
+int X509_NAME_add_entry(X509_NAME *name, X509_NAME_ENTRY *ne, int loc,
+ int set)
+ {
+ X509_NAME_ENTRY *new_name=NULL;
+ int n,i,inc;
+ STACK_OF(X509_NAME_ENTRY) *sk;
+
+ if (name == NULL) return(0);
+ sk=name->entries;
+ n=sk_X509_NAME_ENTRY_num(sk);
+ if (loc > n) loc=n;
+ else if (loc < 0) loc=n;
+
+ name->modified=1;
+
+ if (set == -1)
+ {
+ if (loc == 0)
+ {
+ set=0;
+ inc=1;
+ }
+ else
+ {
+ set=sk_X509_NAME_ENTRY_value(sk,loc-1)->set;
+ inc=0;
+ }
+ }
+ else /* if (set >= 0) */
+ {
+ if (loc >= n)
+ {
+ if (loc != 0)
+ set=sk_X509_NAME_ENTRY_value(sk,loc-1)->set+1;
+ else
+ set=0;
+ }
+ else
+ set=sk_X509_NAME_ENTRY_value(sk,loc)->set;
+ inc=(set == 0)?1:0;
+ }
+
+ if ((new_name=X509_NAME_ENTRY_dup(ne)) == NULL)
+ goto err;
+ 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);
+ goto err;
+ }
+ if (inc)
+ {
+ n=sk_X509_NAME_ENTRY_num(sk);
+ for (i=loc+1; i<n; i++)
+ sk_X509_NAME_ENTRY_value(sk,i-1)->set+=1;
+ }
+ return(1);
+err:
+ if (new_name != NULL)
+ X509_NAME_ENTRY_free(new_name);
+ return(0);
+ }
+
+X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_txt(X509_NAME_ENTRY **ne,
+ const char *field, int type, const unsigned char *bytes, int len)
+ {
+ ASN1_OBJECT *obj;
+ X509_NAME_ENTRY *nentry;
+
+ obj=OBJ_txt2obj(field, 0);
+ if (obj == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_NAME_ENTRY_create_by_txt, X509_R_INVALID_FIELD_NAME);
+ ERR_add_error_data(2, "name=", field);
+ return(NULL);
+ }
+ nentry = X509_NAME_ENTRY_create_by_OBJ(ne,obj,type,bytes,len);
+ ASN1_OBJECT_free(obj);
+ return nentry;
+ }
+
+X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_NID(X509_NAME_ENTRY **ne, int nid,
+ int type, unsigned char *bytes, int len)
+ {
+ const ASN1_OBJECT *obj;
+ X509_NAME_ENTRY *nentry;
+
+ obj=OBJ_nid2obj(nid);
+ if (obj == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_NAME_ENTRY_create_by_NID, X509_R_UNKNOWN_NID);
+ return(NULL);
+ }
+ nentry = X509_NAME_ENTRY_create_by_OBJ(ne,obj,type,bytes,len);
+ /* TODO(fork): remove this? */
+ /* ASN1_OBJECT_free(obj); */
+ return nentry;
+ }
+
+X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_OBJ(X509_NAME_ENTRY **ne,
+ const ASN1_OBJECT *obj, int type, const unsigned char *bytes, int len)
+ {
+ X509_NAME_ENTRY *ret;
+
+ if ((ne == NULL) || (*ne == NULL))
+ {
+ if ((ret=X509_NAME_ENTRY_new()) == NULL)
+ return(NULL);
+ }
+ else
+ ret= *ne;
+
+ if (!X509_NAME_ENTRY_set_object(ret,obj))
+ goto err;
+ if (!X509_NAME_ENTRY_set_data(ret,type,bytes,len))
+ goto err;
+
+ if ((ne != NULL) && (*ne == NULL)) *ne=ret;
+ return(ret);
+err:
+ if ((ne == NULL) || (ret != *ne))
+ X509_NAME_ENTRY_free(ret);
+ return(NULL);
+ }
+
+int X509_NAME_ENTRY_set_object(X509_NAME_ENTRY *ne, const ASN1_OBJECT *obj)
+ {
+ if ((ne == NULL) || (obj == NULL))
+ {
+ OPENSSL_PUT_ERROR(X509, X509_NAME_ENTRY_set_object, ERR_R_PASSED_NULL_PARAMETER);
+ return(0);
+ }
+ ASN1_OBJECT_free(ne->object);
+ ne->object=OBJ_dup(obj);
+ return((ne->object == NULL)?0:1);
+ }
+
+int X509_NAME_ENTRY_set_data(X509_NAME_ENTRY *ne, int type,
+ const unsigned char *bytes, int len)
+ {
+ int i;
+
+ if ((ne == NULL) || ((bytes == NULL) && (len != 0))) return(0);
+ if((type > 0) && (type & MBSTRING_FLAG))
+ return ASN1_STRING_set_by_NID(&ne->value, bytes,
+ len, type,
+ OBJ_obj2nid(ne->object)) ? 1 : 0;
+ if (len < 0) len=strlen((const char *)bytes);
+ i=ASN1_STRING_set(ne->value,bytes,len);
+ if (!i) return(0);
+ if (type != V_ASN1_UNDEF)
+ {
+ if (type == V_ASN1_APP_CHOOSE)
+ ne->value->type=ASN1_PRINTABLE_type(bytes,len);
+ else
+ ne->value->type=type;
+ }
+ return(1);
+ }
+
+ASN1_OBJECT *X509_NAME_ENTRY_get_object(X509_NAME_ENTRY *ne)
+ {
+ if (ne == NULL) return(NULL);
+ return(ne->object);
+ }
+
+ASN1_STRING *X509_NAME_ENTRY_get_data(X509_NAME_ENTRY *ne)
+ {
+ if (ne == NULL) return(NULL);
+ return(ne->value);
+ }
+
diff --git a/crypto/x509/x509rset.c b/crypto/x509/x509rset.c
new file mode 100644
index 0000000..dbab555
--- /dev/null
+++ b/crypto/x509/x509rset.c
@@ -0,0 +1,80 @@
+/* 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/asn1.h>
+#include <openssl/evp.h>
+#include <openssl/obj.h>
+#include <openssl/x509.h>
+
+
+int X509_REQ_set_version(X509_REQ *x, long version)
+ {
+ if (x == NULL) return(0);
+ return(ASN1_INTEGER_set(x->req_info->version,version));
+ }
+
+int X509_REQ_set_subject_name(X509_REQ *x, X509_NAME *name)
+ {
+ if ((x == NULL) || (x->req_info == NULL)) return(0);
+ return(X509_NAME_set(&x->req_info->subject,name));
+ }
+
+int X509_REQ_set_pubkey(X509_REQ *x, EVP_PKEY *pkey)
+ {
+ if ((x == NULL) || (x->req_info == NULL)) return(0);
+ return(X509_PUBKEY_set(&x->req_info->pubkey,pkey));
+ }
+
diff --git a/crypto/x509/x509spki.c b/crypto/x509/x509spki.c
new file mode 100644
index 0000000..ffadcb4
--- /dev/null
+++ b/crypto/x509/x509spki.c
@@ -0,0 +1,118 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999. */
+/* ====================================================================
+ * Copyright (c) 1999 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/base64.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/x509.h>
+
+
+int NETSCAPE_SPKI_set_pubkey(NETSCAPE_SPKI *x, EVP_PKEY *pkey)
+{
+ if ((x == NULL) || (x->spkac == NULL)) return(0);
+ return(X509_PUBKEY_set(&(x->spkac->pubkey),pkey));
+}
+
+EVP_PKEY *NETSCAPE_SPKI_get_pubkey(NETSCAPE_SPKI *x)
+{
+ if ((x == NULL) || (x->spkac == NULL))
+ return(NULL);
+ return(X509_PUBKEY_get(x->spkac->pubkey));
+}
+
+/* Load a Netscape SPKI from a base64 encoded string */
+
+NETSCAPE_SPKI * NETSCAPE_SPKI_b64_decode(const char *str, int len)
+{
+ unsigned char *spki_der;
+ const unsigned char *p;
+ int spki_len;
+ NETSCAPE_SPKI *spki;
+ if(len <= 0) len = strlen(str);
+ if (!(spki_der = OPENSSL_malloc(len + 1))) {
+ OPENSSL_PUT_ERROR(X509, NETSCAPE_SPKI_b64_decode, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ spki_len = EVP_DecodeBlock(spki_der, (const unsigned char *)str, len);
+ if(spki_len < 0) {
+ OPENSSL_PUT_ERROR(X509, NETSCAPE_SPKI_b64_decode, X509_R_BASE64_DECODE_ERROR);
+ OPENSSL_free(spki_der);
+ return NULL;
+ }
+ p = spki_der;
+ spki = d2i_NETSCAPE_SPKI(NULL, &p, spki_len);
+ OPENSSL_free(spki_der);
+ return spki;
+}
+
+/* Generate a base64 encoded string from an SPKI */
+
+char * NETSCAPE_SPKI_b64_encode(NETSCAPE_SPKI *spki)
+{
+ unsigned char *der_spki, *p;
+ char *b64_str;
+ int der_len;
+ der_len = i2d_NETSCAPE_SPKI(spki, NULL);
+ der_spki = OPENSSL_malloc(der_len);
+ b64_str = OPENSSL_malloc(der_len * 2);
+ if(!der_spki || !b64_str) {
+ OPENSSL_PUT_ERROR(X509, NETSCAPE_SPKI_b64_encode, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ p = der_spki;
+ i2d_NETSCAPE_SPKI(spki, &p);
+ EVP_EncodeBlock((unsigned char *)b64_str, der_spki, der_len);
+ OPENSSL_free(der_spki);
+ return b64_str;
+}
diff --git a/crypto/x509/x509type.c b/crypto/x509/x509type.c
new file mode 100644
index 0000000..e7c7935
--- /dev/null
+++ b/crypto/x509/x509type.c
@@ -0,0 +1,128 @@
+/* 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/evp.h>
+#include <openssl/obj.h>
+#include <openssl/x509.h>
+
+
+int X509_certificate_type(X509 *x, EVP_PKEY *pkey)
+ {
+ EVP_PKEY *pk;
+ int ret=0,i;
+
+ if (x == NULL) return(0);
+
+ if (pkey == NULL)
+ pk=X509_get_pubkey(x);
+ else
+ pk=pkey;
+
+ if (pk == NULL) return(0);
+
+ switch (pk->type)
+ {
+ case EVP_PKEY_RSA:
+ ret=EVP_PK_RSA|EVP_PKT_SIGN;
+/* if (!sign only extension) */
+ ret|=EVP_PKT_ENC;
+ break;
+ case EVP_PKEY_DSA:
+ ret=EVP_PK_DSA|EVP_PKT_SIGN;
+ break;
+ case EVP_PKEY_EC:
+ ret=EVP_PK_EC|EVP_PKT_SIGN|EVP_PKT_EXCH;
+ break;
+ case EVP_PKEY_DH:
+ ret=EVP_PK_DH|EVP_PKT_EXCH;
+ break;
+ case NID_id_GostR3410_94:
+ case NID_id_GostR3410_2001:
+ ret=EVP_PKT_EXCH|EVP_PKT_SIGN;
+ break;
+ default:
+ break;
+ }
+
+ i=OBJ_obj2nid(x->sig_alg->algorithm);
+ if (i && OBJ_find_sigid_algs(i, NULL, &i))
+ {
+
+ switch (i)
+ {
+ case NID_rsaEncryption:
+ case NID_rsa:
+ ret|=EVP_PKS_RSA;
+ break;
+ case NID_dsa:
+ case NID_dsa_2:
+ ret|=EVP_PKS_DSA;
+ break;
+ case NID_X9_62_id_ecPublicKey:
+ ret|=EVP_PKS_EC;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (EVP_PKEY_size(pk) <= 1024/8)/* /8 because it's 1024 bits we look
+ for, not bytes */
+ ret|=EVP_PKT_EXP;
+ if(pkey==NULL) EVP_PKEY_free(pk);
+ return(ret);
+ }
+
diff --git a/crypto/x509/x_algor.c b/crypto/x509/x_algor.c
new file mode 100644
index 0000000..238b0f3
--- /dev/null
+++ b/crypto/x509/x_algor.c
@@ -0,0 +1,142 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2000. */
+/* ====================================================================
+ * Copyright (c) 2000 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/x509.h>
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/digest.h>
+#include <openssl/obj.h>
+
+
+ASN1_SEQUENCE(X509_ALGOR) = {
+ ASN1_SIMPLE(X509_ALGOR, algorithm, ASN1_OBJECT),
+ ASN1_OPT(X509_ALGOR, parameter, ASN1_ANY)
+} ASN1_SEQUENCE_END(X509_ALGOR)
+
+ASN1_ITEM_TEMPLATE(X509_ALGORS) =
+ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, algorithms, X509_ALGOR)
+ASN1_ITEM_TEMPLATE_END(X509_ALGORS)
+
+IMPLEMENT_ASN1_FUNCTIONS(X509_ALGOR)
+IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(X509_ALGORS, X509_ALGORS, X509_ALGORS)
+IMPLEMENT_ASN1_DUP_FUNCTION(X509_ALGOR)
+
+IMPLEMENT_ASN1_SET_OF(X509_ALGOR)
+
+int X509_ALGOR_set0(X509_ALGOR *alg, const ASN1_OBJECT *aobj, int ptype, void *pval)
+ {
+ if (!alg)
+ return 0;
+ if (ptype != V_ASN1_UNDEF)
+ {
+ if (alg->parameter == NULL)
+ alg->parameter = ASN1_TYPE_new();
+ if (alg->parameter == NULL)
+ return 0;
+ }
+ if (alg)
+ {
+ if (alg->algorithm)
+ ASN1_OBJECT_free(alg->algorithm);
+ alg->algorithm = (ASN1_OBJECT*) aobj;
+ }
+ if (ptype == 0)
+ return 1;
+ if (ptype == V_ASN1_UNDEF)
+ {
+ if (alg->parameter)
+ {
+ ASN1_TYPE_free(alg->parameter);
+ alg->parameter = NULL;
+ }
+ }
+ else
+ ASN1_TYPE_set(alg->parameter, ptype, pval);
+ return 1;
+ }
+
+void X509_ALGOR_get0(ASN1_OBJECT **paobj, int *pptype, void **ppval,
+ X509_ALGOR *algor)
+ {
+ if (paobj)
+ *paobj = algor->algorithm;
+ if (pptype)
+ {
+ if (algor->parameter == NULL)
+ {
+ *pptype = V_ASN1_UNDEF;
+ return;
+ }
+ else
+ *pptype = algor->parameter->type;
+ if (ppval)
+ *ppval = algor->parameter->value.ptr;
+ }
+ }
+
+/* Set up an X509_ALGOR DigestAlgorithmIdentifier from an EVP_MD */
+
+void X509_ALGOR_set_md(X509_ALGOR *alg, const EVP_MD *md)
+ {
+ int param_type;
+
+ if (EVP_MD_flags(md) & EVP_MD_FLAG_DIGALGID_ABSENT)
+ param_type = V_ASN1_UNDEF;
+ else
+ param_type = V_ASN1_NULL;
+
+ X509_ALGOR_set0(alg, OBJ_nid2obj(EVP_MD_type(md)), param_type, NULL);
+
+ }
diff --git a/crypto/x509/x_all.c b/crypto/x509/x_all.c
new file mode 100644
index 0000000..49e35e5
--- /dev/null
+++ b/crypto/x509/x_all.c
@@ -0,0 +1,547 @@
+/* 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/asn1.h>
+#include <openssl/buf.h>
+#include <openssl/digest.h>
+#include <openssl/dsa.h>
+#include <openssl/evp.h>
+#include <openssl/rsa.h>
+#include <openssl/stack.h>
+#include <openssl/x509.h>
+
+
+extern const ASN1_ITEM RSAPrivateKey_it;
+extern const ASN1_ITEM RSAPublicKey_it;
+
+int X509_verify(X509 *a, EVP_PKEY *r)
+ {
+ return(ASN1_item_verify(ASN1_ITEM_rptr(X509_CINF),a->sig_alg,
+ a->signature,a->cert_info,r));
+ }
+
+int X509_REQ_verify(X509_REQ *a, EVP_PKEY *r)
+ {
+ return( ASN1_item_verify(ASN1_ITEM_rptr(X509_REQ_INFO),
+ a->sig_alg,a->signature,a->req_info,r));
+ }
+
+int X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md)
+ {
+ x->cert_info->enc.modified = 1;
+ return(ASN1_item_sign(ASN1_ITEM_rptr(X509_CINF), x->cert_info->signature,
+ x->sig_alg, x->signature, x->cert_info,pkey,md));
+ }
+
+int X509_sign_ctx(X509 *x, EVP_MD_CTX *ctx)
+ {
+ x->cert_info->enc.modified = 1;
+ return ASN1_item_sign_ctx(ASN1_ITEM_rptr(X509_CINF),
+ x->cert_info->signature,
+ x->sig_alg, x->signature, x->cert_info, ctx);
+ }
+
+/* TODO(fork)
+int X509_http_nbio(OCSP_REQ_CTX *rctx, X509 **pcert)
+ {
+ return OCSP_REQ_CTX_nbio_d2i(rctx,
+ (ASN1_VALUE **)pcert, ASN1_ITEM_rptr(X509));
+ }
+*/
+
+int X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md)
+ {
+ return(ASN1_item_sign(ASN1_ITEM_rptr(X509_REQ_INFO),x->sig_alg, NULL,
+ x->signature, x->req_info,pkey,md));
+ }
+
+int X509_REQ_sign_ctx(X509_REQ *x, EVP_MD_CTX *ctx)
+ {
+ return ASN1_item_sign_ctx(ASN1_ITEM_rptr(X509_REQ_INFO),
+ x->sig_alg, NULL, x->signature, x->req_info, ctx);
+ }
+
+int X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md)
+ {
+ x->crl->enc.modified = 1;
+ return(ASN1_item_sign(ASN1_ITEM_rptr(X509_CRL_INFO),x->crl->sig_alg,
+ x->sig_alg, x->signature, x->crl,pkey,md));
+ }
+
+int X509_CRL_sign_ctx(X509_CRL *x, EVP_MD_CTX *ctx)
+ {
+ x->crl->enc.modified = 1;
+ return ASN1_item_sign_ctx(ASN1_ITEM_rptr(X509_CRL_INFO),
+ x->crl->sig_alg, x->sig_alg, x->signature, x->crl, ctx);
+ }
+
+/* TODO(fork)
+int X509_CRL_http_nbio(OCSP_REQ_CTX *rctx, X509_CRL **pcrl)
+ {
+ return OCSP_REQ_CTX_nbio_d2i(rctx,
+ (ASN1_VALUE **)pcrl, ASN1_ITEM_rptr(X509_CRL));
+ }
+*/
+
+int NETSCAPE_SPKI_sign(NETSCAPE_SPKI *x, EVP_PKEY *pkey, const EVP_MD *md)
+ {
+ return(ASN1_item_sign(ASN1_ITEM_rptr(NETSCAPE_SPKAC), x->sig_algor,NULL,
+ x->signature, x->spkac,pkey,md));
+ }
+
+#ifndef OPENSSL_NO_FP_API
+X509 *d2i_X509_fp(FILE *fp, X509 **x509)
+ {
+ return ASN1_item_d2i_fp(ASN1_ITEM_rptr(X509), fp, x509);
+ }
+
+int i2d_X509_fp(FILE *fp, X509 *x509)
+ {
+ return ASN1_item_i2d_fp(ASN1_ITEM_rptr(X509), fp, x509);
+ }
+#endif
+
+X509 *d2i_X509_bio(BIO *bp, X509 **x509)
+ {
+ return ASN1_item_d2i_bio(ASN1_ITEM_rptr(X509), bp, x509);
+ }
+
+int i2d_X509_bio(BIO *bp, X509 *x509)
+ {
+ return ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509), bp, x509);
+ }
+
+#ifndef OPENSSL_NO_FP_API
+X509_CRL *d2i_X509_CRL_fp(FILE *fp, X509_CRL **crl)
+ {
+ return ASN1_item_d2i_fp(ASN1_ITEM_rptr(X509_CRL), fp, crl);
+ }
+
+int i2d_X509_CRL_fp(FILE *fp, X509_CRL *crl)
+ {
+ return ASN1_item_i2d_fp(ASN1_ITEM_rptr(X509_CRL), fp, crl);
+ }
+#endif
+
+X509_CRL *d2i_X509_CRL_bio(BIO *bp, X509_CRL **crl)
+ {
+ return ASN1_item_d2i_bio(ASN1_ITEM_rptr(X509_CRL), bp, crl);
+ }
+
+int i2d_X509_CRL_bio(BIO *bp, X509_CRL *crl)
+ {
+ return ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509_CRL), bp, crl);
+ }
+
+/* TODO(fork) */
+#if 0
+#ifndef OPENSSL_NO_FP_API
+PKCS7 *d2i_PKCS7_fp(FILE *fp, PKCS7 **p7)
+ {
+ return ASN1_item_d2i_fp(ASN1_ITEM_rptr(PKCS7), fp, p7);
+ }
+
+int i2d_PKCS7_fp(FILE *fp, PKCS7 *p7)
+ {
+ return ASN1_item_i2d_fp(ASN1_ITEM_rptr(PKCS7), fp, p7);
+ }
+#endif
+
+PKCS7 *d2i_PKCS7_bio(BIO *bp, PKCS7 **p7)
+ {
+ return ASN1_item_d2i_bio(ASN1_ITEM_rptr(PKCS7), bp, p7);
+ }
+
+int i2d_PKCS7_bio(BIO *bp, PKCS7 *p7)
+ {
+ return ASN1_item_i2d_bio(ASN1_ITEM_rptr(PKCS7), bp, p7);
+ }
+#endif
+
+#ifndef OPENSSL_NO_FP_API
+X509_REQ *d2i_X509_REQ_fp(FILE *fp, X509_REQ **req)
+ {
+ return ASN1_item_d2i_fp(ASN1_ITEM_rptr(X509_REQ), fp, req);
+ }
+
+int i2d_X509_REQ_fp(FILE *fp, X509_REQ *req)
+ {
+ return ASN1_item_i2d_fp(ASN1_ITEM_rptr(X509_REQ), fp, req);
+ }
+#endif
+
+X509_REQ *d2i_X509_REQ_bio(BIO *bp, X509_REQ **req)
+ {
+ return ASN1_item_d2i_bio(ASN1_ITEM_rptr(X509_REQ), bp, req);
+ }
+
+int i2d_X509_REQ_bio(BIO *bp, X509_REQ *req)
+ {
+ return ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509_REQ), bp, req);
+ }
+
+#ifndef OPENSSL_NO_RSA
+
+#ifndef OPENSSL_NO_FP_API
+RSA *d2i_RSAPrivateKey_fp(FILE *fp, RSA **rsa)
+ {
+ return ASN1_item_d2i_fp(ASN1_ITEM_rptr(RSAPrivateKey), fp, rsa);
+ }
+
+int i2d_RSAPrivateKey_fp(FILE *fp, RSA *rsa)
+ {
+ return ASN1_item_i2d_fp(ASN1_ITEM_rptr(RSAPrivateKey), fp, rsa);
+ }
+
+RSA *d2i_RSAPublicKey_fp(FILE *fp, RSA **rsa)
+ {
+ return ASN1_item_d2i_fp(ASN1_ITEM_rptr(RSAPublicKey), fp, rsa);
+ }
+
+
+RSA *d2i_RSA_PUBKEY_fp(FILE *fp, RSA **rsa)
+ {
+ return ASN1_d2i_fp((void *(*)(void))
+ RSA_new,(D2I_OF(void))d2i_RSA_PUBKEY, fp,
+ (void **)rsa);
+ }
+
+int i2d_RSAPublicKey_fp(FILE *fp, RSA *rsa)
+ {
+ return ASN1_item_i2d_fp(ASN1_ITEM_rptr(RSAPublicKey), fp, rsa);
+ }
+
+int i2d_RSA_PUBKEY_fp(FILE *fp, RSA *rsa)
+ {
+ return ASN1_i2d_fp((I2D_OF_const(void))i2d_RSA_PUBKEY,fp,rsa);
+ }
+#endif
+
+RSA *d2i_RSAPrivateKey_bio(BIO *bp, RSA **rsa)
+ {
+ return ASN1_item_d2i_bio(ASN1_ITEM_rptr(RSAPrivateKey), bp, rsa);
+ }
+
+int i2d_RSAPrivateKey_bio(BIO *bp, RSA *rsa)
+ {
+ return ASN1_item_i2d_bio(ASN1_ITEM_rptr(RSAPrivateKey), bp, rsa);
+ }
+
+RSA *d2i_RSAPublicKey_bio(BIO *bp, RSA **rsa)
+ {
+ return ASN1_item_d2i_bio(ASN1_ITEM_rptr(RSAPublicKey), bp, rsa);
+ }
+
+
+RSA *d2i_RSA_PUBKEY_bio(BIO *bp, RSA **rsa)
+ {
+ return ASN1_d2i_bio_of(RSA,RSA_new,d2i_RSA_PUBKEY,bp,rsa);
+ }
+
+int i2d_RSAPublicKey_bio(BIO *bp, RSA *rsa)
+ {
+ return ASN1_item_i2d_bio(ASN1_ITEM_rptr(RSAPublicKey), bp, rsa);
+ }
+
+int i2d_RSA_PUBKEY_bio(BIO *bp, RSA *rsa)
+ {
+ return ASN1_i2d_bio_of_const(RSA,i2d_RSA_PUBKEY,bp,rsa);
+ }
+#endif
+
+#ifndef OPENSSL_NO_DSA
+#ifndef OPENSSL_NO_FP_API
+DSA *d2i_DSAPrivateKey_fp(FILE *fp, DSA **dsa)
+ {
+ return ASN1_d2i_fp_of(DSA,DSA_new,d2i_DSAPrivateKey,fp,dsa);
+ }
+
+int i2d_DSAPrivateKey_fp(FILE *fp, DSA *dsa)
+ {
+ return ASN1_i2d_fp_of_const(DSA,i2d_DSAPrivateKey,fp,dsa);
+ }
+
+DSA *d2i_DSA_PUBKEY_fp(FILE *fp, DSA **dsa)
+ {
+ return ASN1_d2i_fp_of(DSA,DSA_new,d2i_DSA_PUBKEY,fp,dsa);
+ }
+
+int i2d_DSA_PUBKEY_fp(FILE *fp, DSA *dsa)
+ {
+ return ASN1_i2d_fp_of_const(DSA,i2d_DSA_PUBKEY,fp,dsa);
+ }
+#endif
+
+DSA *d2i_DSAPrivateKey_bio(BIO *bp, DSA **dsa)
+ {
+ return ASN1_d2i_bio_of(DSA,DSA_new,d2i_DSAPrivateKey,bp,dsa
+);
+ }
+
+int i2d_DSAPrivateKey_bio(BIO *bp, DSA *dsa)
+ {
+ return ASN1_i2d_bio_of_const(DSA,i2d_DSAPrivateKey,bp,dsa);
+ }
+
+DSA *d2i_DSA_PUBKEY_bio(BIO *bp, DSA **dsa)
+ {
+ return ASN1_d2i_bio_of(DSA,DSA_new,d2i_DSA_PUBKEY,bp,dsa);
+ }
+
+int i2d_DSA_PUBKEY_bio(BIO *bp, DSA *dsa)
+ {
+ return ASN1_i2d_bio_of_const(DSA,i2d_DSA_PUBKEY,bp,dsa);
+ }
+
+#endif
+
+#ifndef OPENSSL_NO_EC
+#ifndef OPENSSL_NO_FP_API
+EC_KEY *d2i_EC_PUBKEY_fp(FILE *fp, EC_KEY **eckey)
+ {
+ return ASN1_d2i_fp_of(EC_KEY,EC_KEY_new,d2i_EC_PUBKEY,fp,eckey);
+ }
+
+int i2d_EC_PUBKEY_fp(FILE *fp, EC_KEY *eckey)
+ {
+ return ASN1_i2d_fp_of_const(EC_KEY,i2d_EC_PUBKEY,fp,eckey);
+ }
+
+EC_KEY *d2i_ECPrivateKey_fp(FILE *fp, EC_KEY **eckey)
+ {
+ return ASN1_d2i_fp_of(EC_KEY,EC_KEY_new,d2i_ECPrivateKey,fp,eckey);
+ }
+
+int i2d_ECPrivateKey_fp(FILE *fp, EC_KEY *eckey)
+ {
+ return ASN1_i2d_fp_of_const(EC_KEY,i2d_ECPrivateKey,fp,eckey);
+ }
+#endif
+EC_KEY *d2i_EC_PUBKEY_bio(BIO *bp, EC_KEY **eckey)
+ {
+ return ASN1_d2i_bio_of(EC_KEY,EC_KEY_new,d2i_EC_PUBKEY,bp,eckey);
+ }
+
+int i2d_EC_PUBKEY_bio(BIO *bp, EC_KEY *ecdsa)
+ {
+ return ASN1_i2d_bio_of_const(EC_KEY,i2d_EC_PUBKEY,bp,ecdsa);
+ }
+
+EC_KEY *d2i_ECPrivateKey_bio(BIO *bp, EC_KEY **eckey)
+ {
+ return ASN1_d2i_bio_of(EC_KEY,EC_KEY_new,d2i_ECPrivateKey,bp,eckey);
+ }
+
+int i2d_ECPrivateKey_bio(BIO *bp, EC_KEY *eckey)
+ {
+ return ASN1_i2d_bio_of_const(EC_KEY,i2d_ECPrivateKey,bp,eckey);
+ }
+#endif
+
+
+int X509_pubkey_digest(const X509 *data, const EVP_MD *type, unsigned char *md,
+ unsigned int *len)
+ {
+ ASN1_BIT_STRING *key;
+ key = X509_get0_pubkey_bitstr(data);
+ if(!key) return 0;
+ return EVP_Digest(key->data, key->length, md, len, type, NULL);
+ }
+
+int X509_digest(const X509 *data, const EVP_MD *type, unsigned char *md,
+ unsigned int *len)
+ {
+ return(ASN1_item_digest(ASN1_ITEM_rptr(X509),type,(char *)data,md,len));
+ }
+
+int X509_CRL_digest(const X509_CRL *data, const EVP_MD *type, unsigned char *md,
+ unsigned int *len)
+ {
+ return(ASN1_item_digest(ASN1_ITEM_rptr(X509_CRL),type,(char *)data,md,len));
+ }
+
+int X509_REQ_digest(const X509_REQ *data, const EVP_MD *type, unsigned char *md,
+ unsigned int *len)
+ {
+ return(ASN1_item_digest(ASN1_ITEM_rptr(X509_REQ),type,(char *)data,md,len));
+ }
+
+int X509_NAME_digest(const X509_NAME *data, const EVP_MD *type, unsigned char *md,
+ unsigned int *len)
+ {
+ return(ASN1_item_digest(ASN1_ITEM_rptr(X509_NAME),type,(char *)data,md,len));
+ }
+
+#if 0 /* TODO(fork): remove */
+int PKCS7_ISSUER_AND_SERIAL_digest(PKCS7_ISSUER_AND_SERIAL *data, const EVP_MD *type,
+ unsigned char *md, unsigned int *len)
+ {
+ return(ASN1_item_digest(ASN1_ITEM_rptr(PKCS7_ISSUER_AND_SERIAL),type,
+ (char *)data,md,len));
+ }
+#endif
+
+#ifndef OPENSSL_NO_FP_API
+X509_SIG *d2i_PKCS8_fp(FILE *fp, X509_SIG **p8)
+ {
+ return ASN1_d2i_fp_of(X509_SIG,X509_SIG_new,d2i_X509_SIG,fp,p8);
+ }
+
+int i2d_PKCS8_fp(FILE *fp, X509_SIG *p8)
+ {
+ return ASN1_i2d_fp_of(X509_SIG,i2d_X509_SIG,fp,p8);
+ }
+#endif
+
+X509_SIG *d2i_PKCS8_bio(BIO *bp, X509_SIG **p8)
+ {
+ return ASN1_d2i_bio_of(X509_SIG,X509_SIG_new,d2i_X509_SIG,bp,p8);
+ }
+
+int i2d_PKCS8_bio(BIO *bp, X509_SIG *p8)
+ {
+ return ASN1_i2d_bio_of(X509_SIG,i2d_X509_SIG,bp,p8);
+ }
+
+#ifndef OPENSSL_NO_FP_API
+PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_fp(FILE *fp,
+ PKCS8_PRIV_KEY_INFO **p8inf)
+ {
+ return ASN1_d2i_fp_of(PKCS8_PRIV_KEY_INFO,PKCS8_PRIV_KEY_INFO_new,
+ d2i_PKCS8_PRIV_KEY_INFO,fp,p8inf);
+ }
+
+int i2d_PKCS8_PRIV_KEY_INFO_fp(FILE *fp, PKCS8_PRIV_KEY_INFO *p8inf)
+ {
+ return ASN1_i2d_fp_of(PKCS8_PRIV_KEY_INFO,i2d_PKCS8_PRIV_KEY_INFO,fp,
+ p8inf);
+ }
+
+int i2d_PKCS8PrivateKeyInfo_fp(FILE *fp, EVP_PKEY *key)
+ {
+ PKCS8_PRIV_KEY_INFO *p8inf;
+ int ret;
+ p8inf = EVP_PKEY2PKCS8(key);
+ if(!p8inf) return 0;
+ ret = i2d_PKCS8_PRIV_KEY_INFO_fp(fp, p8inf);
+ PKCS8_PRIV_KEY_INFO_free(p8inf);
+ return ret;
+ }
+
+int i2d_PrivateKey_fp(FILE *fp, EVP_PKEY *pkey)
+ {
+ return ASN1_i2d_fp_of_const(EVP_PKEY,i2d_PrivateKey,fp,pkey);
+ }
+
+EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, EVP_PKEY **a)
+{
+ return ASN1_d2i_fp_of(EVP_PKEY,EVP_PKEY_new,d2i_AutoPrivateKey,fp,a);
+}
+
+int i2d_PUBKEY_fp(FILE *fp, EVP_PKEY *pkey)
+ {
+ return ASN1_i2d_fp_of_const(EVP_PKEY,i2d_PUBKEY,fp,pkey);
+ }
+
+EVP_PKEY *d2i_PUBKEY_fp(FILE *fp, EVP_PKEY **a)
+{
+ return ASN1_d2i_fp_of(EVP_PKEY,EVP_PKEY_new,d2i_PUBKEY,fp,a);
+}
+
+PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_bio(BIO *bp,
+ PKCS8_PRIV_KEY_INFO **p8inf)
+ {
+ return ASN1_d2i_bio_of(PKCS8_PRIV_KEY_INFO,PKCS8_PRIV_KEY_INFO_new,
+ d2i_PKCS8_PRIV_KEY_INFO,bp,p8inf);
+ }
+
+int i2d_PKCS8_PRIV_KEY_INFO_bio(BIO *bp, PKCS8_PRIV_KEY_INFO *p8inf)
+ {
+ return ASN1_i2d_bio_of(PKCS8_PRIV_KEY_INFO,i2d_PKCS8_PRIV_KEY_INFO,bp,
+ p8inf);
+ }
+
+int i2d_PKCS8PrivateKeyInfo_bio(BIO *bp, EVP_PKEY *key)
+ {
+ PKCS8_PRIV_KEY_INFO *p8inf;
+ int ret;
+ p8inf = EVP_PKEY2PKCS8(key);
+ if(!p8inf) return 0;
+ ret = i2d_PKCS8_PRIV_KEY_INFO_bio(bp, p8inf);
+ PKCS8_PRIV_KEY_INFO_free(p8inf);
+ return ret;
+ }
+#endif
+
+int i2d_PrivateKey_bio(BIO *bp, EVP_PKEY *pkey)
+ {
+ return ASN1_i2d_bio_of_const(EVP_PKEY,i2d_PrivateKey,bp,pkey);
+ }
+
+EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a)
+ {
+ return ASN1_d2i_bio_of(EVP_PKEY,EVP_PKEY_new,d2i_AutoPrivateKey,bp,a);
+ }
+
+int i2d_PUBKEY_bio(BIO *bp, EVP_PKEY *pkey)
+ {
+ return ASN1_i2d_bio_of_const(EVP_PKEY,i2d_PUBKEY,bp,pkey);
+ }
+
+EVP_PKEY *d2i_PUBKEY_bio(BIO *bp, EVP_PKEY **a)
+ {
+ return ASN1_d2i_bio_of(EVP_PKEY,EVP_PKEY_new,d2i_PUBKEY,bp,a);
+ }
diff --git a/crypto/x509/x_attrib.c b/crypto/x509/x_attrib.c
new file mode 100644
index 0000000..c460a70
--- /dev/null
+++ b/crypto/x509/x_attrib.c
@@ -0,0 +1,117 @@
+/* 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/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/x509.h>
+#include <openssl/obj.h>
+
+
+/* X509_ATTRIBUTE: this has the following form:
+ *
+ * typedef struct x509_attributes_st
+ * {
+ * ASN1_OBJECT *object;
+ * int single;
+ * union {
+ * char *ptr;
+ * STACK_OF(ASN1_TYPE) *set;
+ * ASN1_TYPE *single;
+ * } value;
+ * } X509_ATTRIBUTE;
+ *
+ * this needs some extra thought because the CHOICE type is
+ * merged with the main structure and because the value can
+ * be anything at all we *must* try the SET OF first because
+ * the ASN1_ANY type will swallow anything including the whole
+ * SET OF structure.
+ */
+
+ASN1_CHOICE(X509_ATTRIBUTE_SET) = {
+ ASN1_SET_OF(X509_ATTRIBUTE, value.set, ASN1_ANY),
+ ASN1_SIMPLE(X509_ATTRIBUTE, value.single, ASN1_ANY)
+} ASN1_CHOICE_END_selector(X509_ATTRIBUTE, X509_ATTRIBUTE_SET, single)
+
+ASN1_SEQUENCE(X509_ATTRIBUTE) = {
+ ASN1_SIMPLE(X509_ATTRIBUTE, object, ASN1_OBJECT),
+ /* CHOICE type merged with parent */
+ ASN1_EX_COMBINE(0, 0, X509_ATTRIBUTE_SET)
+} ASN1_SEQUENCE_END(X509_ATTRIBUTE)
+
+IMPLEMENT_ASN1_FUNCTIONS(X509_ATTRIBUTE)
+IMPLEMENT_ASN1_DUP_FUNCTION(X509_ATTRIBUTE)
+
+X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int atrtype, void *value)
+ {
+ X509_ATTRIBUTE *ret=NULL;
+ ASN1_TYPE *val=NULL;
+
+ if ((ret=X509_ATTRIBUTE_new()) == NULL)
+ return(NULL);
+ /* TODO(fork): const correctness. */
+ ret->object=(ASN1_OBJECT*) OBJ_nid2obj(nid);
+ ret->single=0;
+ if ((ret->value.set=sk_ASN1_TYPE_new_null()) == NULL) goto err;
+ if ((val=ASN1_TYPE_new()) == NULL) goto err;
+ if (!sk_ASN1_TYPE_push(ret->value.set,val)) goto err;
+
+ ASN1_TYPE_set(val,atrtype,value);
+ return(ret);
+err:
+ if (ret != NULL) X509_ATTRIBUTE_free(ret);
+ if (val != NULL) ASN1_TYPE_free(val);
+ return(NULL);
+ }
diff --git a/crypto/x509/x_crl.c b/crypto/x509/x_crl.c
new file mode 100644
index 0000000..2d74ff5
--- /dev/null
+++ b/crypto/x509/x_crl.c
@@ -0,0 +1,530 @@
+/* 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/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/digest.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/stack.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#include "../asn1/asn1_locl.h"
+
+
+static int X509_REVOKED_cmp(const X509_REVOKED **a,
+ const X509_REVOKED **b);
+static void setup_idp(X509_CRL *crl, ISSUING_DIST_POINT *idp);
+
+ASN1_SEQUENCE(X509_REVOKED) = {
+ ASN1_SIMPLE(X509_REVOKED,serialNumber, ASN1_INTEGER),
+ ASN1_SIMPLE(X509_REVOKED,revocationDate, ASN1_TIME),
+ ASN1_SEQUENCE_OF_OPT(X509_REVOKED,extensions, X509_EXTENSION)
+} ASN1_SEQUENCE_END(X509_REVOKED)
+
+static int def_crl_verify(X509_CRL *crl, EVP_PKEY *r);
+static int def_crl_lookup(X509_CRL *crl,
+ X509_REVOKED **ret, ASN1_INTEGER *serial, X509_NAME *issuer);
+
+static X509_CRL_METHOD int_crl_meth =
+ {
+ 0,
+ 0,0,
+ def_crl_lookup,
+ def_crl_verify
+ };
+
+static const X509_CRL_METHOD *default_crl_method = &int_crl_meth;
+
+/* The X509_CRL_INFO structure needs a bit of customisation.
+ * Since we cache the original encoding the signature wont be affected by
+ * reordering of the revoked field.
+ */
+static int crl_inf_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
+ void *exarg)
+{
+ X509_CRL_INFO *a = (X509_CRL_INFO *)*pval;
+
+ if(!a || !a->revoked) return 1;
+ switch(operation) {
+ /* Just set cmp function here. We don't sort because that
+ * would affect the output of X509_CRL_print().
+ */
+ case ASN1_OP_D2I_POST:
+ (void)sk_X509_REVOKED_set_cmp_func(a->revoked,X509_REVOKED_cmp);
+ break;
+ }
+ return 1;
+}
+
+
+ASN1_SEQUENCE_enc(X509_CRL_INFO, enc, crl_inf_cb) = {
+ ASN1_OPT(X509_CRL_INFO, version, ASN1_INTEGER),
+ ASN1_SIMPLE(X509_CRL_INFO, sig_alg, X509_ALGOR),
+ ASN1_SIMPLE(X509_CRL_INFO, issuer, X509_NAME),
+ ASN1_SIMPLE(X509_CRL_INFO, lastUpdate, ASN1_TIME),
+ ASN1_OPT(X509_CRL_INFO, nextUpdate, ASN1_TIME),
+ ASN1_SEQUENCE_OF_OPT(X509_CRL_INFO, revoked, X509_REVOKED),
+ ASN1_EXP_SEQUENCE_OF_OPT(X509_CRL_INFO, extensions, X509_EXTENSION, 0)
+} ASN1_SEQUENCE_END_enc(X509_CRL_INFO, X509_CRL_INFO)
+
+/* Set CRL entry issuer according to CRL certificate issuer extension.
+ * Check for unhandled critical CRL entry extensions.
+ */
+
+static int crl_set_issuers(X509_CRL *crl)
+ {
+
+ size_t i, k;
+ int j;
+ GENERAL_NAMES *gens, *gtmp;
+ STACK_OF(X509_REVOKED) *revoked;
+
+ revoked = X509_CRL_get_REVOKED(crl);
+
+ gens = NULL;
+ for (i = 0; i < sk_X509_REVOKED_num(revoked); i++)
+ {
+ X509_REVOKED *rev = sk_X509_REVOKED_value(revoked, i);
+ STACK_OF(X509_EXTENSION) *exts;
+ ASN1_ENUMERATED *reason;
+ X509_EXTENSION *ext;
+ gtmp = X509_REVOKED_get_ext_d2i(rev,
+ NID_certificate_issuer,
+ &j, NULL);
+ if (!gtmp && (j != -1))
+ {
+ crl->flags |= EXFLAG_INVALID;
+ return 1;
+ }
+
+ if (gtmp)
+ {
+ gens = gtmp;
+ if (!crl->issuers)
+ {
+ crl->issuers = sk_GENERAL_NAMES_new_null();
+ if (!crl->issuers)
+ return 0;
+ }
+ if (!sk_GENERAL_NAMES_push(crl->issuers, gtmp))
+ return 0;
+ }
+ rev->issuer = gens;
+
+ reason = X509_REVOKED_get_ext_d2i(rev, NID_crl_reason,
+ &j, NULL);
+ if (!reason && (j != -1))
+ {
+ crl->flags |= EXFLAG_INVALID;
+ return 1;
+ }
+
+ if (reason)
+ {
+ rev->reason = ASN1_ENUMERATED_get(reason);
+ ASN1_ENUMERATED_free(reason);
+ }
+ else
+ rev->reason = CRL_REASON_NONE;
+
+ /* Check for critical CRL entry extensions */
+
+ exts = rev->extensions;
+
+ for (k = 0; k < sk_X509_EXTENSION_num(exts); k++)
+ {
+ ext = sk_X509_EXTENSION_value(exts, k);
+ if (ext->critical > 0)
+ {
+ if (OBJ_obj2nid(ext->object) ==
+ NID_certificate_issuer)
+ continue;
+ crl->flags |= EXFLAG_CRITICAL;
+ break;
+ }
+ }
+
+
+ }
+
+ return 1;
+
+ }
+
+/* The X509_CRL structure needs a bit of customisation. Cache some extensions
+ * and hash of the whole CRL.
+ */
+static int crl_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
+ void *exarg)
+ {
+ X509_CRL *crl = (X509_CRL *)*pval;
+ STACK_OF(X509_EXTENSION) *exts;
+ X509_EXTENSION *ext;
+ size_t idx;
+
+ switch(operation)
+ {
+ case ASN1_OP_NEW_POST:
+ crl->idp = NULL;
+ crl->akid = NULL;
+ crl->flags = 0;
+ crl->idp_flags = 0;
+ crl->idp_reasons = CRLDP_ALL_REASONS;
+ crl->meth = default_crl_method;
+ crl->meth_data = NULL;
+ crl->issuers = NULL;
+ crl->crl_number = NULL;
+ crl->base_crl_number = NULL;
+ break;
+
+ case ASN1_OP_D2I_POST:
+#ifndef OPENSSL_NO_SHA
+ X509_CRL_digest(crl, EVP_sha1(), crl->sha1_hash, NULL);
+#endif
+ crl->idp = X509_CRL_get_ext_d2i(crl,
+ NID_issuing_distribution_point, NULL, NULL);
+ if (crl->idp)
+ setup_idp(crl, crl->idp);
+
+ crl->akid = X509_CRL_get_ext_d2i(crl,
+ NID_authority_key_identifier, NULL, NULL);
+
+ crl->crl_number = X509_CRL_get_ext_d2i(crl,
+ NID_crl_number, NULL, NULL);
+
+ crl->base_crl_number = X509_CRL_get_ext_d2i(crl,
+ NID_delta_crl, NULL, NULL);
+ /* Delta CRLs must have CRL number */
+ if (crl->base_crl_number && !crl->crl_number)
+ crl->flags |= EXFLAG_INVALID;
+
+ /* See if we have any unhandled critical CRL extensions and
+ * indicate this in a flag. We only currently handle IDP so
+ * anything else critical sets the flag.
+ *
+ * This code accesses the X509_CRL structure directly:
+ * applications shouldn't do this.
+ */
+
+ exts = crl->crl->extensions;
+
+ for (idx = 0; idx < sk_X509_EXTENSION_num(exts); idx++)
+ {
+ int nid;
+ ext = sk_X509_EXTENSION_value(exts, idx);
+ nid = OBJ_obj2nid(ext->object);
+ if (nid == NID_freshest_crl)
+ crl->flags |= EXFLAG_FRESHEST;
+ if (ext->critical > 0)
+ {
+ /* We handle IDP and deltas */
+ if ((nid == NID_issuing_distribution_point)
+ || (nid == NID_delta_crl))
+ break;;
+ crl->flags |= EXFLAG_CRITICAL;
+ break;
+ }
+ }
+
+
+ if (!crl_set_issuers(crl))
+ return 0;
+
+ if (crl->meth->crl_init)
+ {
+ if (crl->meth->crl_init(crl) == 0)
+ return 0;
+ }
+ break;
+
+ case ASN1_OP_FREE_POST:
+ if (crl->meth->crl_free)
+ {
+ if (!crl->meth->crl_free(crl))
+ return 0;
+ }
+ if (crl->akid)
+ AUTHORITY_KEYID_free(crl->akid);
+ if (crl->idp)
+ ISSUING_DIST_POINT_free(crl->idp);
+ ASN1_INTEGER_free(crl->crl_number);
+ ASN1_INTEGER_free(crl->base_crl_number);
+ sk_GENERAL_NAMES_pop_free(crl->issuers, GENERAL_NAMES_free);
+ break;
+ }
+ return 1;
+ }
+
+/* Convert IDP into a more convenient form */
+
+static void setup_idp(X509_CRL *crl, ISSUING_DIST_POINT *idp)
+ {
+ int idp_only = 0;
+ /* Set various flags according to IDP */
+ crl->idp_flags |= IDP_PRESENT;
+ if (idp->onlyuser > 0)
+ {
+ idp_only++;
+ crl->idp_flags |= IDP_ONLYUSER;
+ }
+ if (idp->onlyCA > 0)
+ {
+ idp_only++;
+ crl->idp_flags |= IDP_ONLYCA;
+ }
+ if (idp->onlyattr > 0)
+ {
+ idp_only++;
+ crl->idp_flags |= IDP_ONLYATTR;
+ }
+
+ if (idp_only > 1)
+ crl->idp_flags |= IDP_INVALID;
+
+ if (idp->indirectCRL > 0)
+ crl->idp_flags |= IDP_INDIRECT;
+
+ if (idp->onlysomereasons)
+ {
+ crl->idp_flags |= IDP_REASONS;
+ if (idp->onlysomereasons->length > 0)
+ crl->idp_reasons = idp->onlysomereasons->data[0];
+ if (idp->onlysomereasons->length > 1)
+ crl->idp_reasons |=
+ (idp->onlysomereasons->data[1] << 8);
+ crl->idp_reasons &= CRLDP_ALL_REASONS;
+ }
+
+ DIST_POINT_set_dpname(idp->distpoint, X509_CRL_get_issuer(crl));
+ }
+
+ASN1_SEQUENCE_ref(X509_CRL, crl_cb, CRYPTO_LOCK_X509_CRL) = {
+ ASN1_SIMPLE(X509_CRL, crl, X509_CRL_INFO),
+ ASN1_SIMPLE(X509_CRL, sig_alg, X509_ALGOR),
+ ASN1_SIMPLE(X509_CRL, signature, ASN1_BIT_STRING)
+} ASN1_SEQUENCE_END_ref(X509_CRL, X509_CRL)
+
+IMPLEMENT_ASN1_FUNCTIONS(X509_REVOKED)
+IMPLEMENT_ASN1_DUP_FUNCTION(X509_REVOKED)
+IMPLEMENT_ASN1_FUNCTIONS(X509_CRL_INFO)
+IMPLEMENT_ASN1_FUNCTIONS(X509_CRL)
+IMPLEMENT_ASN1_DUP_FUNCTION(X509_CRL)
+
+static int X509_REVOKED_cmp(const X509_REVOKED **a,
+ const X509_REVOKED **b)
+ {
+ return(ASN1_STRING_cmp(
+ (ASN1_STRING *)(*a)->serialNumber,
+ (ASN1_STRING *)(*b)->serialNumber));
+ }
+
+int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev)
+{
+ X509_CRL_INFO *inf;
+ inf = crl->crl;
+ 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);
+ return 0;
+ }
+ inf->enc.modified = 1;
+ return 1;
+}
+
+int X509_CRL_verify(X509_CRL *crl, EVP_PKEY *r)
+ {
+ if (crl->meth->crl_verify)
+ return crl->meth->crl_verify(crl, r);
+ return 0;
+ }
+
+int X509_CRL_get0_by_serial(X509_CRL *crl,
+ X509_REVOKED **ret, ASN1_INTEGER *serial)
+ {
+ if (crl->meth->crl_lookup)
+ return crl->meth->crl_lookup(crl, ret, serial, NULL);
+ return 0;
+ }
+
+int X509_CRL_get0_by_cert(X509_CRL *crl, X509_REVOKED **ret, X509 *x)
+ {
+ if (crl->meth->crl_lookup)
+ return crl->meth->crl_lookup(crl, ret,
+ X509_get_serialNumber(x),
+ X509_get_issuer_name(x));
+ return 0;
+ }
+
+static int def_crl_verify(X509_CRL *crl, EVP_PKEY *r)
+ {
+ return(ASN1_item_verify(ASN1_ITEM_rptr(X509_CRL_INFO),
+ crl->sig_alg, crl->signature,crl->crl,r));
+ }
+
+static int crl_revoked_issuer_match(X509_CRL *crl, X509_NAME *nm,
+ X509_REVOKED *rev)
+ {
+ size_t i;
+
+ if (!rev->issuer)
+ {
+ if (!nm)
+ return 1;
+ if (!X509_NAME_cmp(nm, X509_CRL_get_issuer(crl)))
+ return 1;
+ return 0;
+ }
+
+ if (!nm)
+ nm = X509_CRL_get_issuer(crl);
+
+ for (i = 0; i < sk_GENERAL_NAME_num(rev->issuer); i++)
+ {
+ GENERAL_NAME *gen = sk_GENERAL_NAME_value(rev->issuer, i);
+ if (gen->type != GEN_DIRNAME)
+ continue;
+ if (!X509_NAME_cmp(nm, gen->d.directoryName))
+ return 1;
+ }
+ return 0;
+
+ }
+
+static int def_crl_lookup(X509_CRL *crl,
+ X509_REVOKED **ret, ASN1_INTEGER *serial, X509_NAME *issuer)
+ {
+ X509_REVOKED rtmp, *rev;
+ size_t idx;
+ rtmp.serialNumber = serial;
+ /* Sort revoked into serial number order if not already sorted.
+ * Do this under a lock to avoid race condition.
+ */
+ if (!sk_X509_REVOKED_is_sorted(crl->crl->revoked))
+ {
+ CRYPTO_w_lock(CRYPTO_LOCK_X509_CRL);
+ sk_X509_REVOKED_sort(crl->crl->revoked);
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509_CRL);
+ }
+ if (!sk_X509_REVOKED_find(crl->crl->revoked, &idx, &rtmp))
+ return 0;
+ /* Need to look for matching name */
+ for(;idx < sk_X509_REVOKED_num(crl->crl->revoked); idx++)
+ {
+ rev = sk_X509_REVOKED_value(crl->crl->revoked, idx);
+ if (ASN1_INTEGER_cmp(rev->serialNumber, serial))
+ return 0;
+ if (crl_revoked_issuer_match(crl, issuer, rev))
+ {
+ if (ret)
+ *ret = rev;
+ if (rev->reason == CRL_REASON_REMOVE_FROM_CRL)
+ return 2;
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+void X509_CRL_set_default_method(const X509_CRL_METHOD *meth)
+ {
+ if (meth == NULL)
+ default_crl_method = &int_crl_meth;
+ else
+ default_crl_method = meth;
+ }
+
+X509_CRL_METHOD *X509_CRL_METHOD_new(
+ int (*crl_init)(X509_CRL *crl),
+ int (*crl_free)(X509_CRL *crl),
+ int (*crl_lookup)(X509_CRL *crl, X509_REVOKED **ret,
+ ASN1_INTEGER *ser, X509_NAME *issuer),
+ int (*crl_verify)(X509_CRL *crl, EVP_PKEY *pk))
+ {
+ X509_CRL_METHOD *m;
+ m = OPENSSL_malloc(sizeof(X509_CRL_METHOD));
+ if (!m)
+ return NULL;
+ m->crl_init = crl_init;
+ m->crl_free = crl_free;
+ m->crl_lookup = crl_lookup;
+ m->crl_verify = crl_verify;
+ m->flags = X509_CRL_METHOD_DYNAMIC;
+ return m;
+ }
+
+void X509_CRL_METHOD_free(X509_CRL_METHOD *m)
+ {
+ if (!(m->flags & X509_CRL_METHOD_DYNAMIC))
+ return;
+ OPENSSL_free(m);
+ }
+
+void X509_CRL_set_meth_data(X509_CRL *crl, void *dat)
+ {
+ crl->meth_data = dat;
+ }
+
+void *X509_CRL_get_meth_data(X509_CRL *crl)
+ {
+ return crl->meth_data;
+ }
+
+IMPLEMENT_ASN1_SET_OF(X509_REVOKED)
+IMPLEMENT_ASN1_SET_OF(X509_CRL)
diff --git a/crypto/x509/x_exten.c b/crypto/x509/x_exten.c
new file mode 100644
index 0000000..cf64c84
--- /dev/null
+++ b/crypto/x509/x_exten.c
@@ -0,0 +1,75 @@
+/* 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/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/cipher.h>
+#include <openssl/x509.h>
+
+
+ASN1_SEQUENCE(X509_EXTENSION) = {
+ ASN1_SIMPLE(X509_EXTENSION, object, ASN1_OBJECT),
+ ASN1_OPT(X509_EXTENSION, critical, ASN1_BOOLEAN),
+ ASN1_SIMPLE(X509_EXTENSION, value, ASN1_OCTET_STRING)
+} ASN1_SEQUENCE_END(X509_EXTENSION)
+
+ASN1_ITEM_TEMPLATE(X509_EXTENSIONS) =
+ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, Extension, X509_EXTENSION)
+ASN1_ITEM_TEMPLATE_END(X509_EXTENSIONS)
+
+IMPLEMENT_ASN1_FUNCTIONS(X509_EXTENSION)
+IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(X509_EXTENSIONS, X509_EXTENSIONS, X509_EXTENSIONS)
+IMPLEMENT_ASN1_DUP_FUNCTION(X509_EXTENSION)
diff --git a/crypto/x509/x_info.c b/crypto/x509/x_info.c
new file mode 100644
index 0000000..8047c71
--- /dev/null
+++ b/crypto/x509/x_info.c
@@ -0,0 +1,110 @@
+/* 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/x509.h>
+
+#include <openssl/asn1.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+
+
+X509_INFO *X509_INFO_new(void)
+ {
+ X509_INFO *ret=NULL;
+
+ ret=(X509_INFO *)OPENSSL_malloc(sizeof(X509_INFO));
+ if (ret == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_INFO_new, ERR_R_MALLOC_FAILURE);
+ return(NULL);
+ }
+
+ ret->enc_cipher.cipher=NULL;
+ ret->enc_len=0;
+ ret->enc_data=NULL;
+
+ ret->references=1;
+ ret->x509=NULL;
+ ret->crl=NULL;
+ ret->x_pkey=NULL;
+ return(ret);
+ }
+
+void X509_INFO_free(X509_INFO *x)
+ {
+ int i;
+
+ if (x == NULL) return;
+
+ i=CRYPTO_add(&x->references,-1,CRYPTO_LOCK_X509_INFO);
+#ifdef REF_PRINT
+ REF_PRINT("X509_INFO",x);
+#endif
+ if (i > 0) return;
+#ifdef REF_CHECK
+ if (i < 0)
+ {
+ fprintf(stderr,"X509_INFO_free, bad reference count\n");
+ abort();
+ }
+#endif
+
+ if (x->x509 != NULL) X509_free(x->x509);
+ if (x->crl != NULL) X509_CRL_free(x->crl);
+ if (x->x_pkey != NULL) X509_PKEY_free(x->x_pkey);
+ if (x->enc_data != NULL) OPENSSL_free(x->enc_data);
+ OPENSSL_free(x);
+ }
diff --git a/crypto/x509/x_name.c b/crypto/x509/x_name.c
new file mode 100644
index 0000000..56eeaf4
--- /dev/null
+++ b/crypto/x509/x_name.c
@@ -0,0 +1,527 @@
+/* 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 <ctype.h>
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/stack.h>
+#include <openssl/x509.h>
+
+#include "../asn1/asn1_locl.h"
+
+
+typedef STACK_OF(X509_NAME_ENTRY) STACK_OF_X509_NAME_ENTRY;
+DECLARE_STACK_OF(STACK_OF_X509_NAME_ENTRY)
+
+static int x509_name_ex_d2i(ASN1_VALUE **val,
+ const unsigned char **in, long len,
+ const ASN1_ITEM *it,
+ int tag, int aclass, char opt, ASN1_TLC *ctx);
+
+static int x509_name_ex_i2d(ASN1_VALUE **val, unsigned char **out,
+ const ASN1_ITEM *it, int tag, int aclass);
+static int x509_name_ex_new(ASN1_VALUE **val, const ASN1_ITEM *it);
+static void x509_name_ex_free(ASN1_VALUE **val, const ASN1_ITEM *it);
+
+static int x509_name_encode(X509_NAME *a);
+static int x509_name_canon(X509_NAME *a);
+static int asn1_string_canon(ASN1_STRING *out, ASN1_STRING *in);
+static int i2d_name_canon(STACK_OF(STACK_OF_X509_NAME_ENTRY) *intname,
+ unsigned char **in);
+
+
+static int x509_name_ex_print(BIO *out, ASN1_VALUE **pval,
+ int indent,
+ const char *fname,
+ const ASN1_PCTX *pctx);
+
+ASN1_SEQUENCE(X509_NAME_ENTRY) = {
+ ASN1_SIMPLE(X509_NAME_ENTRY, object, ASN1_OBJECT),
+ ASN1_SIMPLE(X509_NAME_ENTRY, value, ASN1_PRINTABLE)
+} ASN1_SEQUENCE_END(X509_NAME_ENTRY)
+
+IMPLEMENT_ASN1_FUNCTIONS(X509_NAME_ENTRY)
+IMPLEMENT_ASN1_DUP_FUNCTION(X509_NAME_ENTRY)
+
+/* For the "Name" type we need a SEQUENCE OF { SET OF X509_NAME_ENTRY }
+ * so declare two template wrappers for this
+ */
+
+ASN1_ITEM_TEMPLATE(X509_NAME_ENTRIES) =
+ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_OF, 0, RDNS, X509_NAME_ENTRY)
+ASN1_ITEM_TEMPLATE_END(X509_NAME_ENTRIES)
+
+ASN1_ITEM_TEMPLATE(X509_NAME_INTERNAL) =
+ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, Name, X509_NAME_ENTRIES)
+ASN1_ITEM_TEMPLATE_END(X509_NAME_INTERNAL)
+
+/* Normally that's where it would end: we'd have two nested STACK structures
+ * representing the ASN1. Unfortunately X509_NAME uses a completely different
+ * form and caches encodings so we have to process the internal form and convert
+ * to the external form.
+ */
+
+const ASN1_EXTERN_FUNCS x509_name_ff = {
+ NULL,
+ x509_name_ex_new,
+ x509_name_ex_free,
+ 0, /* Default clear behaviour is OK */
+ x509_name_ex_d2i,
+ x509_name_ex_i2d,
+ x509_name_ex_print
+};
+
+IMPLEMENT_EXTERN_ASN1(X509_NAME, V_ASN1_SEQUENCE, x509_name_ff)
+
+IMPLEMENT_ASN1_FUNCTIONS(X509_NAME)
+IMPLEMENT_ASN1_DUP_FUNCTION(X509_NAME)
+
+static int x509_name_ex_new(ASN1_VALUE **val, const ASN1_ITEM *it)
+{
+ X509_NAME *ret = NULL;
+ ret = OPENSSL_malloc(sizeof(X509_NAME));
+ if(!ret) goto memerr;
+ if ((ret->entries=sk_X509_NAME_ENTRY_new_null()) == NULL)
+ goto memerr;
+ if((ret->bytes = BUF_MEM_new()) == NULL) goto memerr;
+ ret->canon_enc = NULL;
+ ret->canon_enclen = 0;
+ ret->modified=1;
+ *val = (ASN1_VALUE *)ret;
+ return 1;
+
+ memerr:
+ OPENSSL_PUT_ERROR(X509, x509_name_ex_new, ERR_R_MALLOC_FAILURE);
+ if (ret)
+ {
+ if (ret->entries)
+ sk_X509_NAME_ENTRY_free(ret->entries);
+ OPENSSL_free(ret);
+ }
+ return 0;
+}
+
+static void x509_name_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
+{
+ X509_NAME *a;
+ if(!pval || !*pval)
+ return;
+ a = (X509_NAME *)*pval;
+
+ BUF_MEM_free(a->bytes);
+ sk_X509_NAME_ENTRY_pop_free(a->entries,X509_NAME_ENTRY_free);
+ if (a->canon_enc)
+ OPENSSL_free(a->canon_enc);
+ OPENSSL_free(a);
+ *pval = NULL;
+}
+
+static int x509_name_ex_d2i(ASN1_VALUE **val,
+ const unsigned char **in, long len, const ASN1_ITEM *it,
+ int tag, int aclass, char opt, ASN1_TLC *ctx)
+{
+ const unsigned char *p = *in, *q;
+ union { STACK_OF(STACK_OF_X509_NAME_ENTRY) *s;
+ ASN1_VALUE *a; } intname = {NULL};
+ union { X509_NAME *x; ASN1_VALUE *a; } nm = {NULL};
+ size_t i, j;
+ int ret;
+ STACK_OF(X509_NAME_ENTRY) *entries;
+ X509_NAME_ENTRY *entry;
+ q = p;
+
+ /* Get internal representation of Name */
+ ret = ASN1_item_ex_d2i(&intname.a,
+ &p, len, ASN1_ITEM_rptr(X509_NAME_INTERNAL),
+ tag, aclass, opt, ctx);
+
+ if(ret <= 0) return ret;
+
+ if(*val) x509_name_ex_free(val, NULL);
+ if(!x509_name_ex_new(&nm.a, NULL)) goto err;
+ /* We've decoded it: now cache encoding */
+ if(!BUF_MEM_grow(nm.x->bytes, p - q)) goto err;
+ memcpy(nm.x->bytes->data, q, p - q);
+
+ /* Convert internal representation to X509_NAME structure */
+ for(i = 0; i < sk_STACK_OF_X509_NAME_ENTRY_num(intname.s); i++) {
+ entries = sk_STACK_OF_X509_NAME_ENTRY_value(intname.s, i);
+ for(j = 0; j < sk_X509_NAME_ENTRY_num(entries); j++) {
+ entry = sk_X509_NAME_ENTRY_value(entries, j);
+ entry->set = i;
+ if(!sk_X509_NAME_ENTRY_push(nm.x->entries, entry))
+ goto err;
+ }
+ sk_X509_NAME_ENTRY_free(entries);
+ }
+ sk_STACK_OF_X509_NAME_ENTRY_free(intname.s);
+ ret = x509_name_canon(nm.x);
+ if (!ret)
+ goto err;
+ nm.x->modified = 0;
+ *val = nm.a;
+ *in = p;
+ return ret;
+err:
+ if (nm.x != NULL)
+ X509_NAME_free(nm.x);
+ OPENSSL_PUT_ERROR(X509, x509_name_ex_d2i, ERR_R_ASN1_LIB);
+ return 0;
+}
+
+static int x509_name_ex_i2d(ASN1_VALUE **val, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass)
+{
+ int ret;
+ X509_NAME *a = (X509_NAME *)*val;
+ if(a->modified) {
+ ret = x509_name_encode(a);
+ if(ret < 0)
+ return ret;
+ ret = x509_name_canon(a);
+ if(ret < 0)
+ return ret;
+ }
+ ret = a->bytes->length;
+ if(out != NULL) {
+ memcpy(*out,a->bytes->data,ret);
+ *out+=ret;
+ }
+ return ret;
+}
+
+static void local_sk_X509_NAME_ENTRY_free(STACK_OF(X509_NAME_ENTRY) *ne)
+ {
+ sk_X509_NAME_ENTRY_free(ne);
+ }
+
+static void local_sk_X509_NAME_ENTRY_pop_free(STACK_OF(X509_NAME_ENTRY) *ne)
+ {
+ sk_X509_NAME_ENTRY_pop_free(ne, X509_NAME_ENTRY_free);
+ }
+
+static int x509_name_encode(X509_NAME *a)
+{
+ union { STACK_OF(STACK_OF_X509_NAME_ENTRY) *s;
+ ASN1_VALUE *a; } intname = {NULL};
+ int len;
+ unsigned char *p;
+ STACK_OF(X509_NAME_ENTRY) *entries = NULL;
+ X509_NAME_ENTRY *entry;
+ int set = -1;
+ size_t i;
+ intname.s = sk_STACK_OF_X509_NAME_ENTRY_new_null();
+ if(!intname.s) goto memerr;
+ for(i = 0; i < sk_X509_NAME_ENTRY_num(a->entries); i++) {
+ entry = sk_X509_NAME_ENTRY_value(a->entries, i);
+ if(entry->set != set) {
+ entries = sk_X509_NAME_ENTRY_new_null();
+ if(!entries) goto memerr;
+ if(!sk_STACK_OF_X509_NAME_ENTRY_push(intname.s,
+ entries))
+ goto memerr;
+ set = entry->set;
+ }
+ if(!sk_X509_NAME_ENTRY_push(entries, entry)) goto memerr;
+ }
+ len = ASN1_item_ex_i2d(&intname.a, NULL,
+ ASN1_ITEM_rptr(X509_NAME_INTERNAL), -1, -1);
+ if (!BUF_MEM_grow(a->bytes,len)) goto memerr;
+ p=(unsigned char *)a->bytes->data;
+ ASN1_item_ex_i2d(&intname.a,
+ &p, ASN1_ITEM_rptr(X509_NAME_INTERNAL), -1, -1);
+ sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname.s,
+ local_sk_X509_NAME_ENTRY_free);
+ a->modified = 0;
+ return len;
+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);
+ return -1;
+}
+
+static int x509_name_ex_print(BIO *out, ASN1_VALUE **pval,
+ int indent,
+ const char *fname,
+ const ASN1_PCTX *pctx)
+ {
+ if (X509_NAME_print_ex(out, (X509_NAME *)*pval,
+ indent, pctx->nm_flags) <= 0)
+ return 0;
+ return 2;
+ }
+
+/* This function generates the canonical encoding of the Name structure.
+ * In it all strings are converted to UTF8, leading, trailing and
+ * multiple spaces collapsed, converted to lower case and the leading
+ * SEQUENCE header removed.
+ *
+ * In future we could also normalize the UTF8 too.
+ *
+ * By doing this comparison of Name structures can be rapidly
+ * perfomed by just using memcmp() of the canonical encoding.
+ * By omitting the leading SEQUENCE name constraints of type
+ * dirName can also be checked with a simple memcmp().
+ */
+
+static int x509_name_canon(X509_NAME *a)
+ {
+ unsigned char *p;
+ STACK_OF(STACK_OF_X509_NAME_ENTRY) *intname = NULL;
+ STACK_OF(X509_NAME_ENTRY) *entries = NULL;
+ X509_NAME_ENTRY *entry, *tmpentry = NULL;
+ int set = -1, ret = 0;
+ size_t i;
+
+ if (a->canon_enc)
+ {
+ OPENSSL_free(a->canon_enc);
+ a->canon_enc = NULL;
+ }
+ /* Special case: empty X509_NAME => null encoding */
+ if (sk_X509_NAME_ENTRY_num(a->entries) == 0)
+ {
+ a->canon_enclen = 0;
+ return 1;
+ }
+ intname = sk_STACK_OF_X509_NAME_ENTRY_new_null();
+ if(!intname)
+ goto err;
+ for(i = 0; i < sk_X509_NAME_ENTRY_num(a->entries); i++)
+ {
+ entry = sk_X509_NAME_ENTRY_value(a->entries, i);
+ if(entry->set != set)
+ {
+ entries = sk_X509_NAME_ENTRY_new_null();
+ if(!entries)
+ goto err;
+ if(!sk_STACK_OF_X509_NAME_ENTRY_push(intname, entries))
+ goto err;
+ set = entry->set;
+ }
+ tmpentry = X509_NAME_ENTRY_new();
+ tmpentry->object = OBJ_dup(entry->object);
+ if (!asn1_string_canon(tmpentry->value, entry->value))
+ goto err;
+ if(!sk_X509_NAME_ENTRY_push(entries, tmpentry))
+ goto err;
+ tmpentry = NULL;
+ }
+
+ /* Finally generate encoding */
+
+ a->canon_enclen = i2d_name_canon(intname, NULL);
+
+ p = OPENSSL_malloc(a->canon_enclen);
+
+ if (!p)
+ goto err;
+
+ a->canon_enc = p;
+
+ i2d_name_canon(intname, &p);
+
+ ret = 1;
+
+ err:
+
+ if (tmpentry)
+ X509_NAME_ENTRY_free(tmpentry);
+ if (intname)
+ sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname,
+ local_sk_X509_NAME_ENTRY_pop_free);
+ return ret;
+ }
+
+/* Bitmap of all the types of string that will be canonicalized. */
+
+#define ASN1_MASK_CANON \
+ (B_ASN1_UTF8STRING | B_ASN1_BMPSTRING | B_ASN1_UNIVERSALSTRING \
+ | B_ASN1_PRINTABLESTRING | B_ASN1_T61STRING | B_ASN1_IA5STRING \
+ | B_ASN1_VISIBLESTRING)
+
+
+static int asn1_string_canon(ASN1_STRING *out, ASN1_STRING *in)
+ {
+ unsigned char *to, *from;
+ int len, i;
+
+ /* If type not in bitmask just copy string across */
+ if (!(ASN1_tag2bit(in->type) & ASN1_MASK_CANON))
+ {
+ if (!ASN1_STRING_copy(out, in))
+ return 0;
+ return 1;
+ }
+
+ out->type = V_ASN1_UTF8STRING;
+ out->length = ASN1_STRING_to_UTF8(&out->data, in);
+ if (out->length == -1)
+ return 0;
+
+ to = out->data;
+ from = to;
+
+ len = out->length;
+
+ /* Convert string in place to canonical form.
+ * Ultimately we may need to handle a wider range of characters
+ * but for now ignore anything with MSB set and rely on the
+ * isspace() and tolower() functions.
+ */
+
+ /* Ignore leading spaces */
+ while((len > 0) && !(*from & 0x80) && isspace(*from))
+ {
+ from++;
+ len--;
+ }
+
+ to = from + len - 1;
+
+ /* Ignore trailing spaces */
+ while ((len > 0) && !(*to & 0x80) && isspace(*to))
+ {
+ to--;
+ len--;
+ }
+
+ to = out->data;
+
+ i = 0;
+ while(i < len)
+ {
+ /* If MSB set just copy across */
+ if (*from & 0x80)
+ {
+ *to++ = *from++;
+ i++;
+ }
+ /* Collapse multiple spaces */
+ else if (isspace(*from))
+ {
+ /* Copy one space across */
+ *to++ = ' ';
+ /* Ignore subsequent spaces. Note: don't need to
+ * check len here because we know the last
+ * character is a non-space so we can't overflow.
+ */
+ do
+ {
+ from++;
+ i++;
+ }
+ while(!(*from & 0x80) && isspace(*from));
+ }
+ else
+ {
+ *to++ = tolower(*from);
+ from++;
+ i++;
+ }
+ }
+
+ out->length = to - out->data;
+
+ return 1;
+
+ }
+
+static int i2d_name_canon(STACK_OF(STACK_OF_X509_NAME_ENTRY) *_intname,
+ unsigned char **in)
+ {
+ int len, ltmp;
+ size_t i;
+ ASN1_VALUE *v;
+ STACK_OF(ASN1_VALUE) *intname = (STACK_OF(ASN1_VALUE) *)_intname;
+
+ len = 0;
+ for (i = 0; i < sk_ASN1_VALUE_num(intname); i++)
+ {
+ v = sk_ASN1_VALUE_value(intname, i);
+ ltmp = ASN1_item_ex_i2d(&v, in,
+ ASN1_ITEM_rptr(X509_NAME_ENTRIES), -1, -1);
+ if (ltmp < 0)
+ return ltmp;
+ len += ltmp;
+ }
+ return len;
+ }
+
+int X509_NAME_set(X509_NAME **xn, X509_NAME *name)
+ {
+ X509_NAME *in;
+
+ if (!xn || !name) return(0);
+
+ if (*xn != name)
+ {
+ in=X509_NAME_dup(name);
+ if (in != NULL)
+ {
+ X509_NAME_free(*xn);
+ *xn=in;
+ }
+ }
+ return(*xn != NULL);
+ }
+
+IMPLEMENT_ASN1_SET_OF(X509_NAME_ENTRY)
diff --git a/crypto/x509/x_pkey.c b/crypto/x509/x_pkey.c
new file mode 100644
index 0000000..b7d29f1
--- /dev/null
+++ b/crypto/x509/x_pkey.c
@@ -0,0 +1,147 @@
+/* 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/x509.h>
+
+#include <openssl/asn1.h>
+#include <openssl/asn1_mac.h>
+#include <openssl/mem.h>
+#include <openssl/err.h>
+
+
+OPENSSL_DECLARE_ERROR_FUNCTION(X509, d2i_X509_PKEY);
+OPENSSL_DECLARE_ERROR_FUNCTION(X509, X509_PKEY_new);
+
+/* need to implement */
+int i2d_X509_PKEY(X509_PKEY *a, unsigned char **pp)
+ {
+ return(0);
+ }
+
+X509_PKEY *d2i_X509_PKEY(X509_PKEY **a, const unsigned char **pp, long length)
+ {
+ int i;
+ M_ASN1_D2I_vars(a,X509_PKEY *,X509_PKEY_new);
+
+ M_ASN1_D2I_Init();
+ M_ASN1_D2I_start_sequence();
+ M_ASN1_D2I_get_x(X509_ALGOR,ret->enc_algor,d2i_X509_ALGOR);
+ M_ASN1_D2I_get_x(ASN1_OCTET_STRING,ret->enc_pkey,d2i_ASN1_OCTET_STRING);
+
+ ret->cipher.cipher=NULL;
+
+ /* TODO(fork): fix */
+ /*ret->cipher.cipher=EVP_get_cipherbyname(
+ OBJ_nid2ln(OBJ_obj2nid(ret->enc_algor->algorithm)));*/
+
+ if (ret->cipher.cipher == NULL)
+ {
+ c.error=ASN1_R_UNSUPPORTED_CIPHER;
+ c.line=__LINE__;
+ goto err;
+ }
+ if (ret->enc_algor->parameter->type == V_ASN1_OCTET_STRING)
+ {
+ i=ret->enc_algor->parameter->value.octet_string->length;
+ if (i > EVP_MAX_IV_LENGTH)
+ {
+ c.error=ASN1_R_IV_TOO_LARGE;
+ c.line=__LINE__;
+ goto err;
+ }
+ memcpy(ret->cipher.iv,
+ ret->enc_algor->parameter->value.octet_string->data,i);
+ }
+ else
+ memset(ret->cipher.iv,0,EVP_MAX_IV_LENGTH);
+ M_ASN1_D2I_Finish(a,X509_PKEY_free,X509_F_d2i_X509_PKEY);
+ }
+
+X509_PKEY *X509_PKEY_new(void)
+ {
+ X509_PKEY *ret=NULL;
+ ASN1_CTX c;
+
+ M_ASN1_New_Malloc(ret,X509_PKEY);
+ ret->version=0;
+ M_ASN1_New(ret->enc_algor,X509_ALGOR_new);
+ M_ASN1_New(ret->enc_pkey,M_ASN1_OCTET_STRING_new);
+ ret->dec_pkey=NULL;
+ ret->key_length=0;
+ ret->key_data=NULL;
+ ret->key_free=0;
+ ret->cipher.cipher=NULL;
+ memset(ret->cipher.iv,0,EVP_MAX_IV_LENGTH);
+ ret->references=1;
+ return(ret);
+ M_ASN1_New_Error(X509_F_X509_PKEY_new);
+ }
+
+void X509_PKEY_free(X509_PKEY *x)
+ {
+ int i;
+
+ if (x == NULL) return;
+
+ i=CRYPTO_add(&x->references,-1,CRYPTO_LOCK_X509_PKEY);
+ if (i > 0) return;
+
+ if (x->enc_algor != NULL) X509_ALGOR_free(x->enc_algor);
+ if (x->enc_pkey != NULL) M_ASN1_OCTET_STRING_free(x->enc_pkey);
+ if (x->dec_pkey != NULL)EVP_PKEY_free(x->dec_pkey);
+ if ((x->key_data != NULL) && (x->key_free)) OPENSSL_free(x->key_data);
+ OPENSSL_free(x);
+ }
diff --git a/crypto/x509/x_pubkey.c b/crypto/x509/x_pubkey.c
new file mode 100644
index 0000000..df1d4af
--- /dev/null
+++ b/crypto/x509/x_pubkey.c
@@ -0,0 +1,379 @@
+/* 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/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509.h>
+
+#include "../evp/internal.h"
+
+
+/* Minor tweak to operation: free up EVP_PKEY */
+static int pubkey_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
+ void *exarg)
+ {
+ if (operation == ASN1_OP_FREE_POST)
+ {
+ X509_PUBKEY *pubkey = (X509_PUBKEY *)*pval;
+ EVP_PKEY_free(pubkey->pkey);
+ }
+ return 1;
+ }
+
+ASN1_SEQUENCE_cb(X509_PUBKEY, pubkey_cb) = {
+ ASN1_SIMPLE(X509_PUBKEY, algor, X509_ALGOR),
+ ASN1_SIMPLE(X509_PUBKEY, public_key, ASN1_BIT_STRING)
+} ASN1_SEQUENCE_END_cb(X509_PUBKEY, X509_PUBKEY)
+
+IMPLEMENT_ASN1_FUNCTIONS(X509_PUBKEY)
+
+int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey)
+ {
+ X509_PUBKEY *pk=NULL;
+
+ if (x == NULL) return(0);
+
+ if ((pk=X509_PUBKEY_new()) == NULL) goto error;
+
+ if (pkey->ameth)
+ {
+ if (pkey->ameth->pub_encode)
+ {
+ if (!pkey->ameth->pub_encode(pk, pkey))
+ {
+ OPENSSL_PUT_ERROR(X509, X509_PUBKEY_set, X509_R_PUBLIC_KEY_ENCODE_ERROR);
+ goto error;
+ }
+ }
+ else
+ {
+ OPENSSL_PUT_ERROR(X509, X509_PUBKEY_set, X509_R_METHOD_NOT_SUPPORTED);
+ goto error;
+ }
+ }
+ else
+ {
+ OPENSSL_PUT_ERROR(X509, X509_PUBKEY_set, X509_R_UNSUPPORTED_ALGORITHM);
+ goto error;
+ }
+
+ if (*x != NULL)
+ X509_PUBKEY_free(*x);
+
+ *x=pk;
+
+ return 1;
+error:
+ if (pk != NULL) X509_PUBKEY_free(pk);
+ return 0;
+ }
+
+EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key)
+ {
+ EVP_PKEY *ret=NULL;
+
+ if (key == NULL) goto error;
+
+ if (key->pkey != NULL)
+ {
+ CRYPTO_add(&key->pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
+ return key->pkey;
+ }
+
+ if (key->public_key == NULL) goto error;
+
+ if ((ret = EVP_PKEY_new()) == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, X509_PUBKEY_get, 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);
+ goto error;
+ }
+
+ if (ret->ameth->pub_decode)
+ {
+ if (!ret->ameth->pub_decode(ret, key))
+ {
+ OPENSSL_PUT_ERROR(X509, X509_PUBKEY_get, X509_R_PUBLIC_KEY_DECODE_ERROR);
+ goto error;
+ }
+ }
+ else
+ {
+ OPENSSL_PUT_ERROR(X509, X509_PUBKEY_get, X509_R_METHOD_NOT_SUPPORTED);
+ goto error;
+ }
+
+ /* Check to see if another thread set key->pkey first */
+ CRYPTO_w_lock(CRYPTO_LOCK_EVP_PKEY);
+ if (key->pkey)
+ {
+ CRYPTO_w_unlock(CRYPTO_LOCK_EVP_PKEY);
+ EVP_PKEY_free(ret);
+ ret = key->pkey;
+ }
+ else
+ {
+ key->pkey = ret;
+ CRYPTO_w_unlock(CRYPTO_LOCK_EVP_PKEY);
+ }
+ CRYPTO_add(&ret->references, 1, CRYPTO_LOCK_EVP_PKEY);
+
+ return ret;
+
+ error:
+ if (ret != NULL)
+ EVP_PKEY_free(ret);
+ return(NULL);
+ }
+
+/* Now two pseudo ASN1 routines that take an EVP_PKEY structure
+ * and encode or decode as X509_PUBKEY
+ */
+
+EVP_PKEY *d2i_PUBKEY(EVP_PKEY **a, const unsigned char **pp,
+ long length)
+ {
+ X509_PUBKEY *xpk;
+ EVP_PKEY *pktmp;
+ xpk = d2i_X509_PUBKEY(NULL, pp, length);
+ if(!xpk) return NULL;
+ pktmp = X509_PUBKEY_get(xpk);
+ X509_PUBKEY_free(xpk);
+ if(!pktmp) return NULL;
+ if(a)
+ {
+ EVP_PKEY_free(*a);
+ *a = pktmp;
+ }
+ return pktmp;
+ }
+
+int i2d_PUBKEY(const EVP_PKEY *a, unsigned char **pp)
+ {
+ X509_PUBKEY *xpk=NULL;
+ int ret;
+ if(!a) return 0;
+ if(!X509_PUBKEY_set(&xpk, (EVP_PKEY*) a)) return 0;
+ ret = i2d_X509_PUBKEY(xpk, pp);
+ X509_PUBKEY_free(xpk);
+ return ret;
+ }
+
+/* The following are equivalents but which return RSA and DSA
+ * keys
+ */
+#ifndef OPENSSL_NO_RSA
+RSA *d2i_RSA_PUBKEY(RSA **a, const unsigned char **pp,
+ long length)
+ {
+ EVP_PKEY *pkey;
+ RSA *key;
+ const unsigned char *q;
+ q = *pp;
+ pkey = d2i_PUBKEY(NULL, &q, length);
+ if (!pkey) return NULL;
+ key = EVP_PKEY_get1_RSA(pkey);
+ EVP_PKEY_free(pkey);
+ if (!key) return NULL;
+ *pp = q;
+ if (a)
+ {
+ RSA_free(*a);
+ *a = key;
+ }
+ return key;
+ }
+
+int i2d_RSA_PUBKEY(const RSA *a, unsigned char **pp)
+ {
+ EVP_PKEY *pktmp;
+ int ret;
+ if (!a) return 0;
+ pktmp = EVP_PKEY_new();
+ if (!pktmp)
+ {
+ OPENSSL_PUT_ERROR(X509, i2d_RSA_PUBKEY, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ EVP_PKEY_set1_RSA(pktmp, (RSA*) a);
+ ret = i2d_PUBKEY(pktmp, pp);
+ EVP_PKEY_free(pktmp);
+ return ret;
+ }
+#endif
+
+#ifndef OPENSSL_NO_DSA
+DSA *d2i_DSA_PUBKEY(DSA **a, const unsigned char **pp,
+ long length)
+ {
+ EVP_PKEY *pkey;
+ DSA *key;
+ const unsigned char *q;
+ q = *pp;
+ pkey = d2i_PUBKEY(NULL, &q, length);
+ if (!pkey) return NULL;
+ key = EVP_PKEY_get1_DSA(pkey);
+ EVP_PKEY_free(pkey);
+ if (!key) return NULL;
+ *pp = q;
+ if (a)
+ {
+ DSA_free(*a);
+ *a = key;
+ }
+ return key;
+ }
+
+int i2d_DSA_PUBKEY(const DSA *a, unsigned char **pp)
+ {
+ EVP_PKEY *pktmp;
+ int ret;
+ if(!a) return 0;
+ pktmp = EVP_PKEY_new();
+ if(!pktmp)
+ {
+ OPENSSL_PUT_ERROR(X509, i2d_DSA_PUBKEY, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ EVP_PKEY_set1_DSA(pktmp, (DSA*) a);
+ ret = i2d_PUBKEY(pktmp, pp);
+ EVP_PKEY_free(pktmp);
+ return ret;
+ }
+#endif
+
+#ifndef OPENSSL_NO_EC
+EC_KEY *d2i_EC_PUBKEY(EC_KEY **a, const unsigned char **pp, long length)
+ {
+ EVP_PKEY *pkey;
+ EC_KEY *key;
+ const unsigned char *q;
+ q = *pp;
+ pkey = d2i_PUBKEY(NULL, &q, length);
+ if (!pkey) return(NULL);
+ key = EVP_PKEY_get1_EC_KEY(pkey);
+ EVP_PKEY_free(pkey);
+ if (!key) return(NULL);
+ *pp = q;
+ if (a)
+ {
+ EC_KEY_free(*a);
+ *a = key;
+ }
+ return(key);
+ }
+
+int i2d_EC_PUBKEY(const EC_KEY *a, unsigned char **pp)
+ {
+ EVP_PKEY *pktmp;
+ int ret;
+ if (!a) return(0);
+ if ((pktmp = EVP_PKEY_new()) == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509, i2d_EC_PUBKEY, ERR_R_MALLOC_FAILURE);
+ return(0);
+ }
+ EVP_PKEY_set1_EC_KEY(pktmp, (EC_KEY*) a);
+ ret = i2d_PUBKEY(pktmp, pp);
+ EVP_PKEY_free(pktmp);
+ return(ret);
+ }
+#endif
+
+int X509_PUBKEY_set0_param(X509_PUBKEY *pub, const ASN1_OBJECT *aobj,
+ int ptype, void *pval,
+ unsigned char *penc, int penclen)
+ {
+ if (!X509_ALGOR_set0(pub->algor, aobj, ptype, pval))
+ return 0;
+ if (penc)
+ {
+ if (pub->public_key->data)
+ OPENSSL_free(pub->public_key->data);
+ pub->public_key->data = penc;
+ pub->public_key->length = penclen;
+ /* Set number of unused bits to zero */
+ pub->public_key->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07);
+ pub->public_key->flags|=ASN1_STRING_FLAG_BITS_LEFT;
+ }
+ return 1;
+ }
+
+int X509_PUBKEY_get0_param(ASN1_OBJECT **ppkalg,
+ const unsigned char **pk, int *ppklen,
+ X509_ALGOR **pa,
+ X509_PUBKEY *pub)
+ {
+ if (ppkalg)
+ *ppkalg = pub->algor->algorithm;
+ if (pk)
+ {
+ *pk = pub->public_key->data;
+ *ppklen = pub->public_key->length;
+ }
+ if (pa)
+ *pa = pub->algor;
+ return 1;
+ }
diff --git a/crypto/x509/x_req.c b/crypto/x509/x_req.c
new file mode 100644
index 0000000..8bf4613
--- /dev/null
+++ b/crypto/x509/x_req.c
@@ -0,0 +1,112 @@
+/* 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/asn1t.h>
+#include <openssl/thread.h>
+#include <openssl/x509.h>
+
+/* X509_REQ_INFO is handled in an unusual way to get round
+ * invalid encodings. Some broken certificate requests don't
+ * encode the attributes field if it is empty. This is in
+ * violation of PKCS#10 but we need to tolerate it. We do
+ * this by making the attributes field OPTIONAL then using
+ * the callback to initialise it to an empty STACK.
+ *
+ * This means that the field will be correctly encoded unless
+ * we NULL out the field.
+ *
+ * As a result we no longer need the req_kludge field because
+ * the information is now contained in the attributes field:
+ * 1. If it is NULL then it's the invalid omission.
+ * 2. If it is empty it is the correct encoding.
+ * 3. If it is not empty then some attributes are present.
+ *
+ */
+
+static int rinf_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
+ void *exarg)
+{
+ X509_REQ_INFO *rinf = (X509_REQ_INFO *)*pval;
+
+ if(operation == ASN1_OP_NEW_POST) {
+ rinf->attributes = sk_X509_ATTRIBUTE_new_null();
+ if(!rinf->attributes) return 0;
+ }
+ return 1;
+}
+
+ASN1_SEQUENCE_enc(X509_REQ_INFO, enc, rinf_cb) = {
+ ASN1_SIMPLE(X509_REQ_INFO, version, ASN1_INTEGER),
+ ASN1_SIMPLE(X509_REQ_INFO, subject, X509_NAME),
+ ASN1_SIMPLE(X509_REQ_INFO, pubkey, X509_PUBKEY),
+ /* This isn't really OPTIONAL but it gets round invalid
+ * encodings
+ */
+ ASN1_IMP_SET_OF_OPT(X509_REQ_INFO, attributes, X509_ATTRIBUTE, 0)
+} ASN1_SEQUENCE_END_enc(X509_REQ_INFO, X509_REQ_INFO)
+
+IMPLEMENT_ASN1_FUNCTIONS(X509_REQ_INFO)
+
+ASN1_SEQUENCE_ref(X509_REQ, 0, CRYPTO_LOCK_X509_REQ) = {
+ ASN1_SIMPLE(X509_REQ, req_info, X509_REQ_INFO),
+ ASN1_SIMPLE(X509_REQ, sig_alg, X509_ALGOR),
+ ASN1_SIMPLE(X509_REQ, signature, ASN1_BIT_STRING)
+} ASN1_SEQUENCE_END_ref(X509_REQ, X509_REQ)
+
+IMPLEMENT_ASN1_FUNCTIONS(X509_REQ)
+IMPLEMENT_ASN1_DUP_FUNCTION(X509_REQ)
diff --git a/crypto/x509/x_sig.c b/crypto/x509/x_sig.c
new file mode 100644
index 0000000..fabdb67
--- /dev/null
+++ b/crypto/x509/x_sig.c
@@ -0,0 +1,69 @@
+/* crypto/asn1/x_sig.c */
+/* 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/asn1t.h>
+#include <openssl/x509.h>
+
+
+ASN1_SEQUENCE(X509_SIG) = {
+ ASN1_SIMPLE(X509_SIG, algor, X509_ALGOR),
+ ASN1_SIMPLE(X509_SIG, digest, ASN1_OCTET_STRING)
+} ASN1_SEQUENCE_END(X509_SIG)
+
+IMPLEMENT_ASN1_FUNCTIONS(X509_SIG)
diff --git a/crypto/x509/x_spki.c b/crypto/x509/x_spki.c
new file mode 100644
index 0000000..35bf246
--- /dev/null
+++ b/crypto/x509/x_spki.c
@@ -0,0 +1,78 @@
+/* crypto/asn1/x_spki.c */
+/* 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.] */
+
+ /* This module was send to me my Pat Richards <patr@x509.com> who
+ * wrote it. It is under my Copyright with his permission. */
+
+#include <openssl/x509.h>
+#include <openssl/asn1t.h>
+
+
+ASN1_SEQUENCE(NETSCAPE_SPKAC) = {
+ ASN1_SIMPLE(NETSCAPE_SPKAC, pubkey, X509_PUBKEY),
+ ASN1_SIMPLE(NETSCAPE_SPKAC, challenge, ASN1_IA5STRING)
+} ASN1_SEQUENCE_END(NETSCAPE_SPKAC)
+
+IMPLEMENT_ASN1_FUNCTIONS(NETSCAPE_SPKAC)
+
+ASN1_SEQUENCE(NETSCAPE_SPKI) = {
+ ASN1_SIMPLE(NETSCAPE_SPKI, spkac, NETSCAPE_SPKAC),
+ ASN1_SIMPLE(NETSCAPE_SPKI, sig_algor, X509_ALGOR),
+ ASN1_SIMPLE(NETSCAPE_SPKI, signature, ASN1_BIT_STRING)
+} ASN1_SEQUENCE_END(NETSCAPE_SPKI)
+
+IMPLEMENT_ASN1_FUNCTIONS(NETSCAPE_SPKI)
diff --git a/crypto/x509/x_val.c b/crypto/x509/x_val.c
new file mode 100644
index 0000000..26200ee
--- /dev/null
+++ b/crypto/x509/x_val.c
@@ -0,0 +1,69 @@
+/* crypto/asn1/x_val.c */
+/* 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/asn1t.h>
+#include <openssl/x509.h>
+
+
+ASN1_SEQUENCE(X509_VAL) = {
+ ASN1_SIMPLE(X509_VAL, notBefore, ASN1_TIME),
+ ASN1_SIMPLE(X509_VAL, notAfter, ASN1_TIME)
+} ASN1_SEQUENCE_END(X509_VAL)
+
+IMPLEMENT_ASN1_FUNCTIONS(X509_VAL)
diff --git a/crypto/x509/x_x509.c b/crypto/x509/x_x509.c
new file mode 100644
index 0000000..712cff4
--- /dev/null
+++ b/crypto/x509/x_x509.c
@@ -0,0 +1,203 @@
+/* crypto/asn1/x_x509.c */
+/* 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/asn1t.h>
+#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/thread.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+
+ASN1_SEQUENCE_enc(X509_CINF, enc, 0) = {
+ ASN1_EXP_OPT(X509_CINF, version, ASN1_INTEGER, 0),
+ ASN1_SIMPLE(X509_CINF, serialNumber, ASN1_INTEGER),
+ ASN1_SIMPLE(X509_CINF, signature, X509_ALGOR),
+ ASN1_SIMPLE(X509_CINF, issuer, X509_NAME),
+ ASN1_SIMPLE(X509_CINF, validity, X509_VAL),
+ ASN1_SIMPLE(X509_CINF, subject, X509_NAME),
+ ASN1_SIMPLE(X509_CINF, key, X509_PUBKEY),
+ ASN1_IMP_OPT(X509_CINF, issuerUID, ASN1_BIT_STRING, 1),
+ ASN1_IMP_OPT(X509_CINF, subjectUID, ASN1_BIT_STRING, 2),
+ ASN1_EXP_SEQUENCE_OF_OPT(X509_CINF, extensions, X509_EXTENSION, 3)
+} ASN1_SEQUENCE_END_enc(X509_CINF, X509_CINF)
+
+IMPLEMENT_ASN1_FUNCTIONS(X509_CINF)
+/* X509 top level structure needs a bit of customisation */
+
+extern void policy_cache_free(X509_POLICY_CACHE *cache);
+
+static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
+ void *exarg)
+{
+ X509 *ret = (X509 *)*pval;
+
+ switch(operation) {
+
+ case ASN1_OP_NEW_POST:
+ ret->valid=0;
+ ret->name = NULL;
+ ret->ex_flags = 0;
+ ret->ex_pathlen = -1;
+ ret->skid = NULL;
+ ret->akid = NULL;
+ ret->aux = NULL;
+ ret->crldp = NULL;
+ CRYPTO_new_ex_data(CRYPTO_EX_INDEX_X509, ret, &ret->ex_data);
+ break;
+
+ case ASN1_OP_D2I_POST:
+ if (ret->name != NULL) OPENSSL_free(ret->name);
+ ret->name=X509_NAME_oneline(ret->cert_info->subject,NULL,0);
+ break;
+
+ case ASN1_OP_FREE_POST:
+ CRYPTO_free_ex_data(CRYPTO_EX_INDEX_X509, ret, &ret->ex_data);
+ X509_CERT_AUX_free(ret->aux);
+ ASN1_OCTET_STRING_free(ret->skid);
+ AUTHORITY_KEYID_free(ret->akid);
+ CRL_DIST_POINTS_free(ret->crldp);
+ policy_cache_free(ret->policy_cache);
+ GENERAL_NAMES_free(ret->altname);
+ NAME_CONSTRAINTS_free(ret->nc);
+
+ if (ret->name != NULL) OPENSSL_free(ret->name);
+ break;
+
+ }
+
+ return 1;
+
+}
+
+ASN1_SEQUENCE_ref(X509, x509_cb, CRYPTO_LOCK_X509) = {
+ ASN1_SIMPLE(X509, cert_info, X509_CINF),
+ ASN1_SIMPLE(X509, sig_alg, X509_ALGOR),
+ ASN1_SIMPLE(X509, signature, ASN1_BIT_STRING)
+} ASN1_SEQUENCE_END_ref(X509, X509)
+
+IMPLEMENT_ASN1_FUNCTIONS(X509)
+IMPLEMENT_ASN1_DUP_FUNCTION(X509)
+
+int X509_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+ CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func)
+ {
+ return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_X509, argl, argp,
+ new_func, dup_func, free_func);
+ }
+
+int X509_set_ex_data(X509 *r, int idx, void *arg)
+ {
+ return(CRYPTO_set_ex_data(&r->ex_data,idx,arg));
+ }
+
+void *X509_get_ex_data(X509 *r, int idx)
+ {
+ return(CRYPTO_get_ex_data(&r->ex_data,idx));
+ }
+
+/* X509_AUX ASN1 routines. X509_AUX is the name given to
+ * a certificate with extra info tagged on the end. Since these
+ * functions set how a certificate is trusted they should only
+ * be used when the certificate comes from a reliable source
+ * such as local storage.
+ *
+ */
+
+X509 *d2i_X509_AUX(X509 **a, const unsigned char **pp, long length)
+{
+ const unsigned char *q;
+ X509 *ret;
+ /* Save start position */
+ q = *pp;
+ ret = d2i_X509(a, pp, length);
+ /* If certificate unreadable then forget it */
+ if(!ret) return NULL;
+ /* update length */
+ length -= *pp - q;
+ if(!length) return ret;
+ if(!d2i_X509_CERT_AUX(&ret->aux, pp, length)) goto err;
+ return ret;
+ err:
+ X509_free(ret);
+ return NULL;
+}
+
+int i2d_X509_AUX(X509 *a, unsigned char **pp)
+{
+ int length;
+ length = i2d_X509(a, pp);
+ if(a) length += i2d_X509_CERT_AUX(a->aux, pp);
+ return length;
+}
+
+void X509_get0_signature(ASN1_BIT_STRING **psig, X509_ALGOR **palg,
+ const X509 *x)
+ {
+ if (psig)
+ *psig = x->signature;
+ if (palg)
+ *palg = x->sig_alg;
+ }
+
+int X509_get_signature_nid(const X509 *x)
+ {
+ return OBJ_obj2nid(x->sig_alg->algorithm);
+ }
diff --git a/crypto/x509/x_x509a.c b/crypto/x509/x_x509a.c
new file mode 100644
index 0000000..e13204b
--- /dev/null
+++ b/crypto/x509/x_x509a.c
@@ -0,0 +1,177 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999. */
+/* ====================================================================
+ * Copyright (c) 1999 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 <stdio.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/evp.h>
+#include <openssl/obj.h>
+#include <openssl/x509.h>
+
+
+/* X509_CERT_AUX routines. These are used to encode additional
+ * user modifiable data about a certificate. This data is
+ * appended to the X509 encoding when the *_X509_AUX routines
+ * are used. This means that the "traditional" X509 routines
+ * will simply ignore the extra data. */
+
+static X509_CERT_AUX *aux_get(X509 *x);
+
+ASN1_SEQUENCE(X509_CERT_AUX) = {
+ ASN1_SEQUENCE_OF_OPT(X509_CERT_AUX, trust, ASN1_OBJECT),
+ ASN1_IMP_SEQUENCE_OF_OPT(X509_CERT_AUX, reject, ASN1_OBJECT, 0),
+ ASN1_OPT(X509_CERT_AUX, alias, ASN1_UTF8STRING),
+ ASN1_OPT(X509_CERT_AUX, keyid, ASN1_OCTET_STRING),
+ ASN1_IMP_SEQUENCE_OF_OPT(X509_CERT_AUX, other, X509_ALGOR, 1)
+} ASN1_SEQUENCE_END(X509_CERT_AUX)
+
+IMPLEMENT_ASN1_FUNCTIONS(X509_CERT_AUX)
+
+static X509_CERT_AUX *aux_get(X509 *x)
+{
+ if(!x) return NULL;
+ if(!x->aux && !(x->aux = X509_CERT_AUX_new())) return NULL;
+ return x->aux;
+}
+
+int X509_alias_set1(X509 *x, unsigned char *name, int len)
+{
+ X509_CERT_AUX *aux;
+ if (!name)
+ {
+ if (!x || !x->aux || !x->aux->alias)
+ return 1;
+ ASN1_UTF8STRING_free(x->aux->alias);
+ x->aux->alias = NULL;
+ return 1;
+ }
+ if(!(aux = aux_get(x))) return 0;
+ if(!aux->alias && !(aux->alias = ASN1_UTF8STRING_new())) return 0;
+ return ASN1_STRING_set(aux->alias, name, len);
+}
+
+int X509_keyid_set1(X509 *x, unsigned char *id, int len)
+{
+ X509_CERT_AUX *aux;
+ if (!id)
+ {
+ if (!x || !x->aux || !x->aux->keyid)
+ return 1;
+ ASN1_OCTET_STRING_free(x->aux->keyid);
+ x->aux->keyid = NULL;
+ return 1;
+ }
+ if(!(aux = aux_get(x))) return 0;
+ if(!aux->keyid && !(aux->keyid = ASN1_OCTET_STRING_new())) return 0;
+ return ASN1_STRING_set(aux->keyid, id, len);
+}
+
+unsigned char *X509_alias_get0(X509 *x, int *len)
+{
+ if(!x->aux || !x->aux->alias) return NULL;
+ if(len) *len = x->aux->alias->length;
+ return x->aux->alias->data;
+}
+
+unsigned char *X509_keyid_get0(X509 *x, int *len)
+{
+ if(!x->aux || !x->aux->keyid) return NULL;
+ if(len) *len = x->aux->keyid->length;
+ return x->aux->keyid->data;
+}
+
+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);
+}
+
+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);
+}
+
+void X509_trust_clear(X509 *x)
+{
+ if(x->aux && x->aux->trust) {
+ sk_ASN1_OBJECT_pop_free(x->aux->trust, ASN1_OBJECT_free);
+ x->aux->trust = NULL;
+ }
+}
+
+void X509_reject_clear(X509 *x)
+{
+ if(x->aux && x->aux->reject) {
+ sk_ASN1_OBJECT_pop_free(x->aux->reject, ASN1_OBJECT_free);
+ x->aux->reject = NULL;
+ }
+}
+
+ASN1_SEQUENCE(X509_CERT_PAIR) = {
+ ASN1_EXP_OPT(X509_CERT_PAIR, forward, X509, 0),
+ ASN1_EXP_OPT(X509_CERT_PAIR, reverse, X509, 1)
+} ASN1_SEQUENCE_END(X509_CERT_PAIR)
+
+IMPLEMENT_ASN1_FUNCTIONS(X509_CERT_PAIR)
diff --git a/crypto/x509v3/CMakeLists.txt b/crypto/x509v3/CMakeLists.txt
new file mode 100644
index 0000000..8a76259
--- /dev/null
+++ b/crypto/x509v3/CMakeLists.txt
@@ -0,0 +1,60 @@
+include_directories(. .. ../../include)
+
+add_library(
+ x509v3
+
+ OBJECT
+
+ # v3_addr.c - disabled by upstream by default.
+ # v3_asid.c - disabled by upstream by default.
+ # v3_ocsp.c - missing OCSP for now.
+
+ pcy_cache.c
+ pcy_data.c
+ pcy_lib.c
+ pcy_map.c
+ pcy_node.c
+ pcy_tree.c
+ v3_akey.c
+ v3_akeya.c
+ v3_alt.c
+ v3_bcons.c
+ v3_bitst.c
+ v3_conf.c
+ v3_cpols.c
+ v3_crld.c
+ v3_enum.c
+ v3_extku.c
+ v3_genn.c
+ v3_ia5.c
+ v3_info.c
+ v3_int.c
+ v3_lib.c
+ v3_ncons.c
+ v3_pci.c
+ v3_pcia.c
+ v3_pcons.c
+ v3_pku.c
+ v3_pmaps.c
+ v3_prn.c
+ v3_purp.c
+ v3_skey.c
+ v3_sxnet.c
+ v3_utl.c
+ x509v3_error.c
+)
+
+add_executable(
+ v3name_test
+
+ v3nametest.c
+)
+
+add_executable(
+ tab_test
+
+ tabtest.c
+)
+
+target_link_libraries(v3name_test crypto)
+target_link_libraries(tab_test crypto)
diff --git a/crypto/x509v3/ext_dat.h b/crypto/x509v3/ext_dat.h
new file mode 100644
index 0000000..e7d0052
--- /dev/null
+++ b/crypto/x509v3/ext_dat.h
@@ -0,0 +1,129 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2004 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). */
+
+/* This file contains a table of "standard" extensions */
+
+extern X509V3_EXT_METHOD v3_bcons, v3_nscert, v3_key_usage, v3_ext_ku;
+extern X509V3_EXT_METHOD v3_pkey_usage_period, v3_sxnet, v3_info, v3_sinfo;
+extern X509V3_EXT_METHOD v3_ns_ia5_list[], v3_alt[], v3_skey_id, v3_akey_id;
+extern X509V3_EXT_METHOD v3_crl_num, v3_crl_reason, v3_crl_invdate;
+extern X509V3_EXT_METHOD v3_delta_crl, v3_cpols, v3_crld, v3_freshest_crl;
+extern X509V3_EXT_METHOD v3_ocsp_nonce, v3_ocsp_accresp, v3_ocsp_acutoff;
+extern X509V3_EXT_METHOD v3_ocsp_crlid, v3_ocsp_nocheck, v3_ocsp_serviceloc;
+extern X509V3_EXT_METHOD v3_crl_hold, v3_pci;
+extern X509V3_EXT_METHOD v3_policy_mappings, v3_policy_constraints;
+extern X509V3_EXT_METHOD v3_name_constraints, v3_inhibit_anyp, v3_idp;
+extern X509V3_EXT_METHOD v3_addr, v3_asid;
+
+/* This table will be searched using OBJ_bsearch so it *must* kept in
+ * order of the ext_nid values.
+ */
+
+/* TODO(fork): OCSP support */
+#define OPENSSL_NO_OCSP
+
+static const X509V3_EXT_METHOD *standard_exts[] = {
+&v3_nscert,
+&v3_ns_ia5_list[0],
+&v3_ns_ia5_list[1],
+&v3_ns_ia5_list[2],
+&v3_ns_ia5_list[3],
+&v3_ns_ia5_list[4],
+&v3_ns_ia5_list[5],
+&v3_ns_ia5_list[6],
+&v3_skey_id,
+&v3_key_usage,
+&v3_pkey_usage_period,
+&v3_alt[0],
+&v3_alt[1],
+&v3_bcons,
+&v3_crl_num,
+&v3_cpols,
+&v3_akey_id,
+&v3_crld,
+&v3_ext_ku,
+&v3_delta_crl,
+&v3_crl_reason,
+#ifndef OPENSSL_NO_OCSP
+&v3_crl_invdate,
+#endif
+&v3_sxnet,
+&v3_info,
+#ifndef OPENSSL_NO_OCSP
+&v3_ocsp_nonce,
+&v3_ocsp_crlid,
+&v3_ocsp_accresp,
+&v3_ocsp_nocheck,
+&v3_ocsp_acutoff,
+&v3_ocsp_serviceloc,
+#endif
+&v3_sinfo,
+&v3_policy_constraints,
+#ifndef OPENSSL_NO_OCSP
+&v3_crl_hold,
+#endif
+&v3_pci,
+&v3_name_constraints,
+&v3_policy_mappings,
+&v3_inhibit_anyp,
+&v3_idp,
+&v3_alt[2],
+&v3_freshest_crl,
+};
+
+/* Number of standard extensions */
+
+#define STANDARD_EXTENSION_COUNT (sizeof(standard_exts)/sizeof(X509V3_EXT_METHOD *))
+
diff --git a/crypto/x509v3/pcy_cache.c b/crypto/x509v3/pcy_cache.c
new file mode 100644
index 0000000..5d59c00
--- /dev/null
+++ b/crypto/x509v3/pcy_cache.c
@@ -0,0 +1,286 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2004.
+ */
+/* ====================================================================
+ * Copyright (c) 2004 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/mem.h>
+#include <openssl/obj.h>
+#include <openssl/thread.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#include "pcy_int.h"
+
+
+static int policy_data_cmp(const X509_POLICY_DATA **a,
+ const X509_POLICY_DATA **b);
+static int policy_cache_set_int(long *out, ASN1_INTEGER *value);
+
+/* Set cache entry according to CertificatePolicies extension.
+ * Note: this destroys the passed CERTIFICATEPOLICIES structure.
+ */
+
+static int policy_cache_create(X509 *x,
+ CERTIFICATEPOLICIES *policies, int crit)
+ {
+ size_t i;
+ int ret = 0;
+ X509_POLICY_CACHE *cache = x->policy_cache;
+ X509_POLICY_DATA *data = NULL;
+ POLICYINFO *policy;
+ if (sk_POLICYINFO_num(policies) == 0)
+ goto bad_policy;
+ cache->data = sk_X509_POLICY_DATA_new(policy_data_cmp);
+ if (!cache->data)
+ goto bad_policy;
+ for (i = 0; i < sk_POLICYINFO_num(policies); i++)
+ {
+ policy = sk_POLICYINFO_value(policies, i);
+ data = policy_data_new(policy, NULL, crit);
+ if (!data)
+ goto bad_policy;
+ /* Duplicate policy OIDs are illegal: reject if matches
+ * found.
+ */
+ if (OBJ_obj2nid(data->valid_policy) == NID_any_policy)
+ {
+ if (cache->anyPolicy)
+ {
+ ret = -1;
+ goto bad_policy;
+ }
+ cache->anyPolicy = data;
+ }
+ else if (sk_X509_POLICY_DATA_find(cache->data, NULL, data))
+ {
+ ret = -1;
+ goto bad_policy;
+ }
+ else if (!sk_X509_POLICY_DATA_push(cache->data, data))
+ goto bad_policy;
+ data = NULL;
+ }
+ ret = 1;
+ bad_policy:
+ if (ret == -1)
+ x->ex_flags |= EXFLAG_INVALID_POLICY;
+ if (data)
+ policy_data_free(data);
+ sk_POLICYINFO_pop_free(policies, POLICYINFO_free);
+ if (ret <= 0)
+ {
+ sk_X509_POLICY_DATA_pop_free(cache->data, policy_data_free);
+ cache->data = NULL;
+ }
+ return ret;
+ }
+
+
+static int policy_cache_new(X509 *x)
+ {
+ X509_POLICY_CACHE *cache;
+ ASN1_INTEGER *ext_any = NULL;
+ POLICY_CONSTRAINTS *ext_pcons = NULL;
+ CERTIFICATEPOLICIES *ext_cpols = NULL;
+ POLICY_MAPPINGS *ext_pmaps = NULL;
+ int i;
+ cache = OPENSSL_malloc(sizeof(X509_POLICY_CACHE));
+ if (!cache)
+ return 0;
+ cache->anyPolicy = NULL;
+ cache->data = NULL;
+ cache->any_skip = -1;
+ cache->explicit_skip = -1;
+ cache->map_skip = -1;
+
+ x->policy_cache = cache;
+
+ /* Handle requireExplicitPolicy *first*. Need to process this
+ * even if we don't have any policies.
+ */
+ ext_pcons = X509_get_ext_d2i(x, NID_policy_constraints, &i, NULL);
+
+ if (!ext_pcons)
+ {
+ if (i != -1)
+ goto bad_cache;
+ }
+ else
+ {
+ if (!ext_pcons->requireExplicitPolicy
+ && !ext_pcons->inhibitPolicyMapping)
+ goto bad_cache;
+ if (!policy_cache_set_int(&cache->explicit_skip,
+ ext_pcons->requireExplicitPolicy))
+ goto bad_cache;
+ if (!policy_cache_set_int(&cache->map_skip,
+ ext_pcons->inhibitPolicyMapping))
+ goto bad_cache;
+ }
+
+ /* Process CertificatePolicies */
+
+ ext_cpols = X509_get_ext_d2i(x, NID_certificate_policies, &i, NULL);
+ /* If no CertificatePolicies extension or problem decoding then
+ * there is no point continuing because the valid policies will be
+ * NULL.
+ */
+ if (!ext_cpols)
+ {
+ /* If not absent some problem with extension */
+ if (i != -1)
+ goto bad_cache;
+ return 1;
+ }
+
+ i = policy_cache_create(x, ext_cpols, i);
+
+ /* NB: ext_cpols freed by policy_cache_set_policies */
+
+ if (i <= 0)
+ return i;
+
+ ext_pmaps = X509_get_ext_d2i(x, NID_policy_mappings, &i, NULL);
+
+ if (!ext_pmaps)
+ {
+ /* If not absent some problem with extension */
+ if (i != -1)
+ goto bad_cache;
+ }
+ else
+ {
+ i = policy_cache_set_mapping(x, ext_pmaps);
+ if (i <= 0)
+ goto bad_cache;
+ }
+
+ ext_any = X509_get_ext_d2i(x, NID_inhibit_any_policy, &i, NULL);
+
+ if (!ext_any)
+ {
+ if (i != -1)
+ goto bad_cache;
+ }
+ else if (!policy_cache_set_int(&cache->any_skip, ext_any))
+ goto bad_cache;
+
+ if (0)
+ {
+ bad_cache:
+ x->ex_flags |= EXFLAG_INVALID_POLICY;
+ }
+
+ if(ext_pcons)
+ POLICY_CONSTRAINTS_free(ext_pcons);
+
+ if (ext_any)
+ ASN1_INTEGER_free(ext_any);
+
+ return 1;
+
+
+}
+
+void policy_cache_free(X509_POLICY_CACHE *cache)
+ {
+ if (!cache)
+ return;
+ if (cache->anyPolicy)
+ policy_data_free(cache->anyPolicy);
+ if (cache->data)
+ sk_X509_POLICY_DATA_pop_free(cache->data, policy_data_free);
+ OPENSSL_free(cache);
+ }
+
+const X509_POLICY_CACHE *policy_cache_set(X509 *x)
+ {
+
+ if (x->policy_cache == NULL)
+ {
+ CRYPTO_w_lock(CRYPTO_LOCK_X509);
+ policy_cache_new(x);
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509);
+ }
+
+ return x->policy_cache;
+
+ }
+
+X509_POLICY_DATA *policy_cache_find_data(const X509_POLICY_CACHE *cache,
+ const ASN1_OBJECT *id)
+ {
+ size_t idx;
+ X509_POLICY_DATA tmp;
+
+ tmp.valid_policy = (ASN1_OBJECT *)id;
+ if (!sk_X509_POLICY_DATA_find(cache->data, &idx, &tmp))
+ return NULL;
+ return sk_X509_POLICY_DATA_value(cache->data, idx);
+ }
+
+static int policy_data_cmp(const X509_POLICY_DATA **a,
+ const X509_POLICY_DATA **b)
+ {
+ return OBJ_cmp((*a)->valid_policy, (*b)->valid_policy);
+ }
+
+static int policy_cache_set_int(long *out, ASN1_INTEGER *value)
+ {
+ if (value == NULL)
+ return 1;
+ if (value->type == V_ASN1_NEG_INTEGER)
+ return 0;
+ *out = ASN1_INTEGER_get(value);
+ return 1;
+ }
diff --git a/crypto/x509v3/pcy_data.c b/crypto/x509v3/pcy_data.c
new file mode 100644
index 0000000..cd45dca
--- /dev/null
+++ b/crypto/x509v3/pcy_data.c
@@ -0,0 +1,137 @@
+/* pcy_data.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2004.
+ */
+/* ====================================================================
+ * Copyright (c) 2004 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/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#include "pcy_int.h"
+
+
+/* Policy Node routines */
+
+void policy_data_free(X509_POLICY_DATA *data)
+ {
+ ASN1_OBJECT_free(data->valid_policy);
+ /* Don't free qualifiers if shared */
+ if (!(data->flags & POLICY_DATA_FLAG_SHARED_QUALIFIERS))
+ sk_POLICYQUALINFO_pop_free(data->qualifier_set,
+ POLICYQUALINFO_free);
+ sk_ASN1_OBJECT_pop_free(data->expected_policy_set, ASN1_OBJECT_free);
+ OPENSSL_free(data);
+ }
+
+/* Create a data based on an existing policy. If 'id' is NULL use the
+ * oid in the policy, otherwise use 'id'. This behaviour covers the two
+ * types of data in RFC3280: data with from a CertificatePolcies extension
+ * and additional data with just the qualifiers of anyPolicy and ID from
+ * another source.
+ */
+
+X509_POLICY_DATA *policy_data_new(POLICYINFO *policy,
+ const ASN1_OBJECT *cid, int crit)
+ {
+ X509_POLICY_DATA *ret;
+ ASN1_OBJECT *id;
+ if (!policy && !cid)
+ return NULL;
+ if (cid)
+ {
+ id = OBJ_dup(cid);
+ if (!id)
+ return NULL;
+ }
+ else
+ id = NULL;
+ ret = OPENSSL_malloc(sizeof(X509_POLICY_DATA));
+ if (!ret)
+ return NULL;
+ ret->expected_policy_set = sk_ASN1_OBJECT_new_null();
+ if (!ret->expected_policy_set)
+ {
+ OPENSSL_free(ret);
+ if (id)
+ ASN1_OBJECT_free(id);
+ return NULL;
+ }
+
+ if (crit)
+ ret->flags = POLICY_DATA_FLAG_CRITICAL;
+ else
+ ret->flags = 0;
+
+ if (id)
+ ret->valid_policy = id;
+ else
+ {
+ ret->valid_policy = policy->policyid;
+ policy->policyid = NULL;
+ }
+
+ if (policy)
+ {
+ ret->qualifier_set = policy->qualifiers;
+ policy->qualifiers = NULL;
+ }
+ else
+ ret->qualifier_set = NULL;
+
+ return ret;
+ }
+
diff --git a/crypto/x509v3/pcy_int.h b/crypto/x509v3/pcy_int.h
new file mode 100644
index 0000000..ccff928
--- /dev/null
+++ b/crypto/x509v3/pcy_int.h
@@ -0,0 +1,212 @@
+/* pcy_int.h */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2004.
+ */
+/* ====================================================================
+ * Copyright (c) 2004 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).
+ *
+ */
+
+
+typedef struct X509_POLICY_DATA_st X509_POLICY_DATA;
+
+DECLARE_STACK_OF(X509_POLICY_DATA)
+
+/* Internal structures */
+
+/* This structure and the field names correspond to the Policy 'node' of
+ * RFC3280. NB this structure contains no pointers to parent or child
+ * data: X509_POLICY_NODE contains that. This means that the main policy data
+ * can be kept static and cached with the certificate.
+ */
+
+struct X509_POLICY_DATA_st
+ {
+ unsigned int flags;
+ /* Policy OID and qualifiers for this data */
+ ASN1_OBJECT *valid_policy;
+ STACK_OF(POLICYQUALINFO) *qualifier_set;
+ STACK_OF(ASN1_OBJECT) *expected_policy_set;
+ };
+
+/* X509_POLICY_DATA flags values */
+
+/* This flag indicates the structure has been mapped using a policy mapping
+ * extension. If policy mapping is not active its references get deleted.
+ */
+
+#define POLICY_DATA_FLAG_MAPPED 0x1
+
+/* This flag indicates the data doesn't correspond to a policy in Certificate
+ * Policies: it has been mapped to any policy.
+ */
+
+#define POLICY_DATA_FLAG_MAPPED_ANY 0x2
+
+/* AND with flags to see if any mapping has occurred */
+
+#define POLICY_DATA_FLAG_MAP_MASK 0x3
+
+/* qualifiers are shared and shouldn't be freed */
+
+#define POLICY_DATA_FLAG_SHARED_QUALIFIERS 0x4
+
+/* Parent node is an extra node and should be freed */
+
+#define POLICY_DATA_FLAG_EXTRA_NODE 0x8
+
+/* Corresponding CertificatePolicies is critical */
+
+#define POLICY_DATA_FLAG_CRITICAL 0x10
+
+/* This structure is cached with a certificate */
+
+struct X509_POLICY_CACHE_st {
+ /* anyPolicy data or NULL if no anyPolicy */
+ X509_POLICY_DATA *anyPolicy;
+ /* other policy data */
+ STACK_OF(X509_POLICY_DATA) *data;
+ /* If InhibitAnyPolicy present this is its value or -1 if absent. */
+ long any_skip;
+ /* If policyConstraints and requireExplicitPolicy present this is its
+ * value or -1 if absent.
+ */
+ long explicit_skip;
+ /* If policyConstraints and policyMapping present this is its
+ * value or -1 if absent.
+ */
+ long map_skip;
+ };
+
+/*#define POLICY_CACHE_FLAG_CRITICAL POLICY_DATA_FLAG_CRITICAL*/
+
+/* This structure represents the relationship between nodes */
+
+struct X509_POLICY_NODE_st
+ {
+ /* node data this refers to */
+ const X509_POLICY_DATA *data;
+ /* Parent node */
+ X509_POLICY_NODE *parent;
+ /* Number of child nodes */
+ int nchild;
+ };
+
+struct X509_POLICY_LEVEL_st
+ {
+ /* Cert for this level */
+ X509 *cert;
+ /* nodes at this level */
+ STACK_OF(X509_POLICY_NODE) *nodes;
+ /* anyPolicy node */
+ X509_POLICY_NODE *anyPolicy;
+ /* Extra data */
+ /*STACK_OF(X509_POLICY_DATA) *extra_data;*/
+ unsigned int flags;
+ };
+
+struct X509_POLICY_TREE_st
+ {
+ /* This is the tree 'level' data */
+ X509_POLICY_LEVEL *levels;
+ int nlevel;
+ /* Extra policy data when additional nodes (not from the certificate)
+ * are required.
+ */
+ STACK_OF(X509_POLICY_DATA) *extra_data;
+ /* This is the authority constained policy set */
+ STACK_OF(X509_POLICY_NODE) *auth_policies;
+ STACK_OF(X509_POLICY_NODE) *user_policies;
+ unsigned int flags;
+ };
+
+/* Set if anyPolicy present in user policies */
+#define POLICY_FLAG_ANY_POLICY 0x2
+
+/* Useful macros */
+
+#define node_data_critical(data) (data->flags & POLICY_DATA_FLAG_CRITICAL)
+#define node_critical(node) node_data_critical(node->data)
+
+/* Internal functions */
+
+X509_POLICY_DATA *policy_data_new(POLICYINFO *policy, const ASN1_OBJECT *id,
+ int crit);
+void policy_data_free(X509_POLICY_DATA *data);
+
+X509_POLICY_DATA *policy_cache_find_data(const X509_POLICY_CACHE *cache,
+ const ASN1_OBJECT *id);
+int policy_cache_set_mapping(X509 *x, POLICY_MAPPINGS *maps);
+
+
+STACK_OF(X509_POLICY_NODE) *policy_node_cmp_new(void);
+
+void policy_cache_init(void);
+
+void policy_cache_free(X509_POLICY_CACHE *cache);
+
+X509_POLICY_NODE *level_find_node(const X509_POLICY_LEVEL *level,
+ const X509_POLICY_NODE *parent,
+ const ASN1_OBJECT *id);
+
+X509_POLICY_NODE *tree_find_sk(STACK_OF(X509_POLICY_NODE) *sk,
+ const ASN1_OBJECT *id);
+
+X509_POLICY_NODE *level_add_node(X509_POLICY_LEVEL *level,
+ const X509_POLICY_DATA *data,
+ X509_POLICY_NODE *parent,
+ X509_POLICY_TREE *tree);
+void policy_node_free(X509_POLICY_NODE *node);
+int policy_node_match(const X509_POLICY_LEVEL *lvl,
+ const X509_POLICY_NODE *node, const ASN1_OBJECT *oid);
+
+const X509_POLICY_CACHE *policy_cache_set(X509 *x);
diff --git a/crypto/x509v3/pcy_lib.c b/crypto/x509v3/pcy_lib.c
new file mode 100644
index 0000000..16be2f0
--- /dev/null
+++ b/crypto/x509v3/pcy_lib.c
@@ -0,0 +1,165 @@
+/* pcy_lib.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2004.
+ */
+/* ====================================================================
+ * Copyright (c) 2004 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/x509.h>
+#include <openssl/x509v3.h>
+
+#include "pcy_int.h"
+
+
+/* accessor functions */
+
+/* X509_POLICY_TREE stuff */
+
+int X509_policy_tree_level_count(const X509_POLICY_TREE *tree)
+ {
+ if (!tree)
+ return 0;
+ return tree->nlevel;
+ }
+
+X509_POLICY_LEVEL *
+ X509_policy_tree_get0_level(const X509_POLICY_TREE *tree, int i)
+ {
+ if (!tree || (i < 0) || (i >= tree->nlevel))
+ return NULL;
+ return tree->levels + i;
+ }
+
+STACK_OF(X509_POLICY_NODE) *
+ X509_policy_tree_get0_policies(const X509_POLICY_TREE *tree)
+ {
+ if (!tree)
+ return NULL;
+ return tree->auth_policies;
+ }
+
+STACK_OF(X509_POLICY_NODE) *
+ X509_policy_tree_get0_user_policies(const X509_POLICY_TREE *tree)
+ {
+ if (!tree)
+ return NULL;
+ if (tree->flags & POLICY_FLAG_ANY_POLICY)
+ return tree->auth_policies;
+ else
+ return tree->user_policies;
+ }
+
+/* X509_POLICY_LEVEL stuff */
+
+int X509_policy_level_node_count(X509_POLICY_LEVEL *level)
+ {
+ int n;
+ if (!level)
+ return 0;
+ if (level->anyPolicy)
+ n = 1;
+ else
+ n = 0;
+ if (level->nodes)
+ n += sk_X509_POLICY_NODE_num(level->nodes);
+ return n;
+ }
+
+X509_POLICY_NODE *X509_policy_level_get0_node(X509_POLICY_LEVEL *level, int i)
+ {
+ if (!level)
+ return NULL;
+ if (level->anyPolicy)
+ {
+ if (i == 0)
+ return level->anyPolicy;
+ i--;
+ }
+ return sk_X509_POLICY_NODE_value(level->nodes, i);
+ }
+
+/* X509_POLICY_NODE stuff */
+
+const ASN1_OBJECT *X509_policy_node_get0_policy(const X509_POLICY_NODE *node)
+ {
+ if (!node)
+ return NULL;
+ return node->data->valid_policy;
+ }
+
+#if 0
+int X509_policy_node_get_critical(const X509_POLICY_NODE *node)
+ {
+ if (node_critical(node))
+ return 1;
+ return 0;
+ }
+#endif
+
+STACK_OF(POLICYQUALINFO) *
+ X509_policy_node_get0_qualifiers(const X509_POLICY_NODE *node)
+ {
+ if (!node)
+ return NULL;
+ return node->data->qualifier_set;
+ }
+
+const X509_POLICY_NODE *
+ X509_policy_node_get0_parent(const X509_POLICY_NODE *node)
+ {
+ if (!node)
+ return NULL;
+ return node->parent;
+ }
+
+
diff --git a/crypto/x509v3/pcy_map.c b/crypto/x509v3/pcy_map.c
new file mode 100644
index 0000000..2b8307b
--- /dev/null
+++ b/crypto/x509v3/pcy_map.c
@@ -0,0 +1,133 @@
+/* pcy_map.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2004.
+ */
+/* ====================================================================
+ * Copyright (c) 2004 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/obj.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#include "pcy_int.h"
+
+
+/* Set policy mapping entries in cache.
+ * Note: this modifies the passed POLICY_MAPPINGS structure
+ */
+
+int policy_cache_set_mapping(X509 *x, POLICY_MAPPINGS *maps)
+ {
+ POLICY_MAPPING *map;
+ X509_POLICY_DATA *data;
+ X509_POLICY_CACHE *cache = x->policy_cache;
+ size_t i;
+ int ret = 0;
+ if (sk_POLICY_MAPPING_num(maps) == 0)
+ {
+ ret = -1;
+ goto bad_mapping;
+ }
+ for (i = 0; i < sk_POLICY_MAPPING_num(maps); i++)
+ {
+ map = sk_POLICY_MAPPING_value(maps, i);
+ /* Reject if map to or from anyPolicy */
+ if ((OBJ_obj2nid(map->subjectDomainPolicy) == NID_any_policy)
+ || (OBJ_obj2nid(map->issuerDomainPolicy) == NID_any_policy))
+ {
+ ret = -1;
+ goto bad_mapping;
+ }
+
+ /* Attempt to find matching policy data */
+ data = policy_cache_find_data(cache, map->issuerDomainPolicy);
+ /* If we don't have anyPolicy can't map */
+ if (!data && !cache->anyPolicy)
+ continue;
+
+ /* Create a NODE from anyPolicy */
+ if (!data)
+ {
+ data = policy_data_new(NULL, map->issuerDomainPolicy,
+ cache->anyPolicy->flags
+ & POLICY_DATA_FLAG_CRITICAL);
+ if (!data)
+ goto bad_mapping;
+ data->qualifier_set = cache->anyPolicy->qualifier_set;
+ /*map->issuerDomainPolicy = NULL;*/
+ data->flags |= POLICY_DATA_FLAG_MAPPED_ANY;
+ data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS;
+ if (!sk_X509_POLICY_DATA_push(cache->data, data))
+ {
+ policy_data_free(data);
+ goto bad_mapping;
+ }
+ }
+ else
+ data->flags |= POLICY_DATA_FLAG_MAPPED;
+ if (!sk_ASN1_OBJECT_push(data->expected_policy_set,
+ map->subjectDomainPolicy))
+ goto bad_mapping;
+ map->subjectDomainPolicy = NULL;
+
+ }
+
+ ret = 1;
+ bad_mapping:
+ if (ret == -1)
+ x->ex_flags |= EXFLAG_INVALID_POLICY;
+ sk_POLICY_MAPPING_pop_free(maps, POLICY_MAPPING_free);
+ return ret;
+
+ }
diff --git a/crypto/x509v3/pcy_node.c b/crypto/x509v3/pcy_node.c
new file mode 100644
index 0000000..55cc203
--- /dev/null
+++ b/crypto/x509v3/pcy_node.c
@@ -0,0 +1,197 @@
+/* pcy_node.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2004.
+ */
+/* ====================================================================
+ * Copyright (c) 2004 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/asn1.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#include "pcy_int.h"
+
+
+static int node_cmp(const X509_POLICY_NODE **a,
+ const X509_POLICY_NODE **b)
+ {
+ return OBJ_cmp((*a)->data->valid_policy, (*b)->data->valid_policy);
+ }
+
+STACK_OF(X509_POLICY_NODE) *policy_node_cmp_new(void)
+ {
+ return sk_X509_POLICY_NODE_new(node_cmp);
+ }
+
+X509_POLICY_NODE *tree_find_sk(STACK_OF(X509_POLICY_NODE) *nodes,
+ const ASN1_OBJECT *id)
+ {
+ X509_POLICY_DATA n;
+ X509_POLICY_NODE l;
+ size_t idx;
+
+ n.valid_policy = (ASN1_OBJECT *)id;
+ l.data = &n;
+
+ if (!sk_X509_POLICY_NODE_find(nodes, &idx, &l))
+ return NULL;
+
+ return sk_X509_POLICY_NODE_value(nodes, idx);
+
+ }
+
+X509_POLICY_NODE *level_find_node(const X509_POLICY_LEVEL *level,
+ const X509_POLICY_NODE *parent,
+ const ASN1_OBJECT *id)
+ {
+ X509_POLICY_NODE *node;
+ size_t i;
+ for (i = 0; i < sk_X509_POLICY_NODE_num(level->nodes); i++)
+ {
+ node = sk_X509_POLICY_NODE_value(level->nodes, i);
+ if (node->parent == parent)
+ {
+ if (!OBJ_cmp(node->data->valid_policy, id))
+ return node;
+ }
+ }
+ return NULL;
+ }
+
+X509_POLICY_NODE *level_add_node(X509_POLICY_LEVEL *level,
+ const X509_POLICY_DATA *data,
+ X509_POLICY_NODE *parent,
+ X509_POLICY_TREE *tree)
+ {
+ X509_POLICY_NODE *node;
+ node = OPENSSL_malloc(sizeof(X509_POLICY_NODE));
+ if (!node)
+ return NULL;
+ node->data = data;
+ node->parent = parent;
+ node->nchild = 0;
+ if (level)
+ {
+ if (OBJ_obj2nid(data->valid_policy) == NID_any_policy)
+ {
+ if (level->anyPolicy)
+ goto node_error;
+ level->anyPolicy = node;
+ }
+ else
+ {
+
+ if (!level->nodes)
+ level->nodes = policy_node_cmp_new();
+ if (!level->nodes)
+ goto node_error;
+ if (!sk_X509_POLICY_NODE_push(level->nodes, node))
+ goto node_error;
+ }
+ }
+
+ if (tree)
+ {
+ if (!tree->extra_data)
+ tree->extra_data = sk_X509_POLICY_DATA_new_null();
+ if (!tree->extra_data)
+ goto node_error;
+ if (!sk_X509_POLICY_DATA_push(tree->extra_data, data))
+ goto node_error;
+ }
+
+ if (parent)
+ parent->nchild++;
+
+ return node;
+
+ node_error:
+ policy_node_free(node);
+ return 0;
+
+ }
+
+void policy_node_free(X509_POLICY_NODE *node)
+ {
+ OPENSSL_free(node);
+ }
+
+/* See if a policy node matches a policy OID. If mapping enabled look through
+ * expected policy set otherwise just valid policy.
+ */
+
+int policy_node_match(const X509_POLICY_LEVEL *lvl,
+ const X509_POLICY_NODE *node, const ASN1_OBJECT *oid)
+ {
+ size_t i;
+ ASN1_OBJECT *policy_oid;
+ const X509_POLICY_DATA *x = node->data;
+
+ if ( (lvl->flags & X509_V_FLAG_INHIBIT_MAP)
+ || !(x->flags & POLICY_DATA_FLAG_MAP_MASK))
+ {
+ if (!OBJ_cmp(x->valid_policy, oid))
+ return 1;
+ return 0;
+ }
+
+ for (i = 0; i < sk_ASN1_OBJECT_num(x->expected_policy_set); i++)
+ {
+ policy_oid = sk_ASN1_OBJECT_value(x->expected_policy_set, i);
+ if (!OBJ_cmp(policy_oid, oid))
+ return 1;
+ }
+ return 0;
+
+ }
diff --git a/crypto/x509v3/pcy_tree.c b/crypto/x509v3/pcy_tree.c
new file mode 100644
index 0000000..dbaa498
--- /dev/null
+++ b/crypto/x509v3/pcy_tree.c
@@ -0,0 +1,877 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2004.
+ */
+/* ====================================================================
+ * Copyright (c) 2004 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/mem.h>
+#include <openssl/obj.h>
+#include <openssl/stack.h>
+#include <openssl/thread.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#include "pcy_int.h"
+
+
+/* Enable this to print out the complete policy tree at various point during
+ * evaluation.
+ */
+
+/*#define OPENSSL_POLICY_DEBUG*/
+
+#ifdef OPENSSL_POLICY_DEBUG
+
+static void expected_print(BIO *err, X509_POLICY_LEVEL *lev,
+ X509_POLICY_NODE *node, int indent)
+ {
+ if ( (lev->flags & X509_V_FLAG_INHIBIT_MAP)
+ || !(node->data->flags & POLICY_DATA_FLAG_MAP_MASK))
+ BIO_puts(err, " Not Mapped\n");
+ else
+ {
+ int i;
+ STACK_OF(ASN1_OBJECT) *pset = node->data->expected_policy_set;
+ ASN1_OBJECT *oid;
+ BIO_puts(err, " Expected: ");
+ for (i = 0; i < sk_ASN1_OBJECT_num(pset); i++)
+ {
+ oid = sk_ASN1_OBJECT_value(pset, i);
+ if (i)
+ BIO_puts(err, ", ");
+ i2a_ASN1_OBJECT(err, oid);
+ }
+ BIO_puts(err, "\n");
+ }
+ }
+
+static void tree_print(char *str, X509_POLICY_TREE *tree,
+ X509_POLICY_LEVEL *curr)
+ {
+ X509_POLICY_LEVEL *plev;
+ X509_POLICY_NODE *node;
+ int i;
+ BIO *err;
+ err = BIO_new_fp(stderr, BIO_NOCLOSE);
+ if (!curr)
+ curr = tree->levels + tree->nlevel;
+ else
+ curr++;
+ BIO_printf(err, "Level print after %s\n", str);
+ BIO_printf(err, "Printing Up to Level %ld\n", curr - tree->levels);
+ for (plev = tree->levels; plev != curr; plev++)
+ {
+ BIO_printf(err, "Level %ld, flags = %x\n",
+ plev - tree->levels, plev->flags);
+ for (i = 0; i < sk_X509_POLICY_NODE_num(plev->nodes); i++)
+ {
+ node = sk_X509_POLICY_NODE_value(plev->nodes, i);
+ X509_POLICY_NODE_print(err, node, 2);
+ expected_print(err, plev, node, 2);
+ BIO_printf(err, " Flags: %x\n", node->data->flags);
+ }
+ if (plev->anyPolicy)
+ X509_POLICY_NODE_print(err, plev->anyPolicy, 2);
+ }
+
+ BIO_free(err);
+
+ }
+#else
+
+#define tree_print(a,b,c) /* */
+
+#endif
+
+/* Initialize policy tree. Return values:
+ * 0 Some internal error occured.
+ * -1 Inconsistent or invalid extensions in certificates.
+ * 1 Tree initialized OK.
+ * 2 Policy tree is empty.
+ * 5 Tree OK and requireExplicitPolicy true.
+ * 6 Tree empty and requireExplicitPolicy true.
+ */
+
+static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs,
+ unsigned int flags)
+ {
+ X509_POLICY_TREE *tree;
+ X509_POLICY_LEVEL *level;
+ const X509_POLICY_CACHE *cache;
+ X509_POLICY_DATA *data = NULL;
+ X509 *x;
+ int ret = 1;
+ int i, n;
+ int explicit_policy;
+ int any_skip;
+ int map_skip;
+ *ptree = NULL;
+ n = sk_X509_num(certs);
+
+#if 0
+ /* Disable policy mapping for now... */
+ flags |= X509_V_FLAG_INHIBIT_MAP;
+#endif
+
+ if (flags & X509_V_FLAG_EXPLICIT_POLICY)
+ explicit_policy = 0;
+ else
+ explicit_policy = n + 1;
+
+ if (flags & X509_V_FLAG_INHIBIT_ANY)
+ any_skip = 0;
+ else
+ any_skip = n + 1;
+
+ if (flags & X509_V_FLAG_INHIBIT_MAP)
+ map_skip = 0;
+ else
+ map_skip = n + 1;
+
+ /* Can't do anything with just a trust anchor */
+ if (n == 1)
+ return 1;
+ /* First setup policy cache in all certificates apart from the
+ * trust anchor. Note any bad cache results on the way. Also can
+ * calculate explicit_policy value at this point.
+ */
+ for (i = n - 2; i >= 0; i--)
+ {
+ x = sk_X509_value(certs, i);
+ X509_check_purpose(x, -1, -1);
+ cache = policy_cache_set(x);
+ /* If cache NULL something bad happened: return immediately */
+ if (cache == NULL)
+ return 0;
+ /* If inconsistent extensions keep a note of it but continue */
+ if (x->ex_flags & EXFLAG_INVALID_POLICY)
+ ret = -1;
+ /* Otherwise if we have no data (hence no CertificatePolicies)
+ * and haven't already set an inconsistent code note it.
+ */
+ else if ((ret == 1) && !cache->data)
+ ret = 2;
+ if (explicit_policy > 0)
+ {
+ if (!(x->ex_flags & EXFLAG_SI))
+ explicit_policy--;
+ if ((cache->explicit_skip != -1)
+ && (cache->explicit_skip < explicit_policy))
+ explicit_policy = cache->explicit_skip;
+ }
+ }
+
+ if (ret != 1)
+ {
+ if (ret == 2 && !explicit_policy)
+ return 6;
+ return ret;
+ }
+
+
+ /* If we get this far initialize the tree */
+
+ tree = OPENSSL_malloc(sizeof(X509_POLICY_TREE));
+
+ if (!tree)
+ return 0;
+
+ tree->flags = 0;
+ tree->levels = OPENSSL_malloc(sizeof(X509_POLICY_LEVEL) * n);
+ tree->nlevel = 0;
+ tree->extra_data = NULL;
+ tree->auth_policies = NULL;
+ tree->user_policies = NULL;
+
+ if (!tree->levels)
+ {
+ OPENSSL_free(tree);
+ return 0;
+ }
+
+ memset(tree->levels, 0, n * sizeof(X509_POLICY_LEVEL));
+
+ tree->nlevel = n;
+
+ level = tree->levels;
+
+ /* Root data: initialize to anyPolicy */
+
+ data = policy_data_new(NULL, OBJ_nid2obj(NID_any_policy), 0);
+
+ if (!data || !level_add_node(level, data, NULL, tree))
+ goto bad_tree;
+
+ for (i = n - 2; i >= 0; i--)
+ {
+ level++;
+ x = sk_X509_value(certs, i);
+ cache = policy_cache_set(x);
+ CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
+ level->cert = x;
+
+ if (!cache->anyPolicy)
+ level->flags |= X509_V_FLAG_INHIBIT_ANY;
+
+ /* Determine inhibit any and inhibit map flags */
+ if (any_skip == 0)
+ {
+ /* Any matching allowed if certificate is self
+ * issued and not the last in the chain.
+ */
+ if (!(x->ex_flags & EXFLAG_SI) || (i == 0))
+ level->flags |= X509_V_FLAG_INHIBIT_ANY;
+ }
+ else
+ {
+ if (!(x->ex_flags & EXFLAG_SI))
+ any_skip--;
+ if ((cache->any_skip >= 0)
+ && (cache->any_skip < any_skip))
+ any_skip = cache->any_skip;
+ }
+
+ if (map_skip == 0)
+ level->flags |= X509_V_FLAG_INHIBIT_MAP;
+ else
+ {
+ if (!(x->ex_flags & EXFLAG_SI))
+ map_skip--;
+ if ((cache->map_skip >= 0)
+ && (cache->map_skip < map_skip))
+ map_skip = cache->map_skip;
+ }
+
+ }
+
+ *ptree = tree;
+
+ if (explicit_policy)
+ return 1;
+ else
+ return 5;
+
+ bad_tree:
+
+ X509_policy_tree_free(tree);
+
+ return 0;
+
+ }
+
+static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr,
+ const X509_POLICY_DATA *data)
+ {
+ X509_POLICY_LEVEL *last = curr - 1;
+ X509_POLICY_NODE *node;
+ int matched = 0;
+ size_t i;
+ /* Iterate through all in nodes linking matches */
+ for (i = 0; i < sk_X509_POLICY_NODE_num(last->nodes); i++)
+ {
+ node = sk_X509_POLICY_NODE_value(last->nodes, i);
+ if (policy_node_match(last, node, data->valid_policy))
+ {
+ if (!level_add_node(curr, data, node, NULL))
+ return 0;
+ matched = 1;
+ }
+ }
+ if (!matched && last->anyPolicy)
+ {
+ if (!level_add_node(curr, data, last->anyPolicy, NULL))
+ return 0;
+ }
+ return 1;
+ }
+
+/* This corresponds to RFC3280 6.1.3(d)(1):
+ * link any data from CertificatePolicies onto matching parent
+ * or anyPolicy if no match.
+ */
+
+static int tree_link_nodes(X509_POLICY_LEVEL *curr,
+ const X509_POLICY_CACHE *cache)
+ {
+ size_t i;
+ X509_POLICY_DATA *data;
+
+ for (i = 0; i < sk_X509_POLICY_DATA_num(cache->data); i++)
+ {
+ data = sk_X509_POLICY_DATA_value(cache->data, i);
+ /* If a node is mapped any it doesn't have a corresponding
+ * CertificatePolicies entry.
+ * However such an identical node would be created
+ * if anyPolicy matching is enabled because there would be
+ * no match with the parent valid_policy_set. So we create
+ * link because then it will have the mapping flags
+ * right and we can prune it later.
+ */
+#if 0
+ if ((data->flags & POLICY_DATA_FLAG_MAPPED_ANY)
+ && !(curr->flags & X509_V_FLAG_INHIBIT_ANY))
+ continue;
+#endif
+ /* Look for matching nodes in previous level */
+ if (!tree_link_matching_nodes(curr, data))
+ return 0;
+ }
+ return 1;
+ }
+
+/* This corresponds to RFC3280 6.1.3(d)(2):
+ * Create new data for any unmatched policies in the parent and link
+ * to anyPolicy.
+ */
+
+static int tree_add_unmatched(X509_POLICY_LEVEL *curr,
+ const X509_POLICY_CACHE *cache,
+ const ASN1_OBJECT *id,
+ X509_POLICY_NODE *node,
+ X509_POLICY_TREE *tree)
+ {
+ X509_POLICY_DATA *data;
+ if (id == NULL)
+ id = node->data->valid_policy;
+ /* Create a new node with qualifiers from anyPolicy and
+ * id from unmatched node.
+ */
+ data = policy_data_new(NULL, id, node_critical(node));
+
+ if (data == NULL)
+ return 0;
+ /* Curr may not have anyPolicy */
+ data->qualifier_set = cache->anyPolicy->qualifier_set;
+ data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS;
+ if (!level_add_node(curr, data, node, tree))
+ {
+ policy_data_free(data);
+ return 0;
+ }
+
+ return 1;
+ }
+
+static int tree_link_unmatched(X509_POLICY_LEVEL *curr,
+ const X509_POLICY_CACHE *cache,
+ X509_POLICY_NODE *node,
+ X509_POLICY_TREE *tree)
+ {
+ const X509_POLICY_LEVEL *last = curr - 1;
+ size_t i;
+
+ if ( (last->flags & X509_V_FLAG_INHIBIT_MAP)
+ || !(node->data->flags & POLICY_DATA_FLAG_MAPPED))
+ {
+ /* If no policy mapping: matched if one child present */
+ if (node->nchild)
+ return 1;
+ if (!tree_add_unmatched(curr, cache, NULL, node, tree))
+ return 0;
+ /* Add it */
+ }
+ else
+ {
+ /* If mapping: matched if one child per expected policy set */
+ STACK_OF(ASN1_OBJECT) *expset = node->data->expected_policy_set;
+ if (node->nchild == sk_ASN1_OBJECT_num(expset))
+ return 1;
+ /* Locate unmatched nodes */
+ for (i = 0; i < sk_ASN1_OBJECT_num(expset); i++)
+ {
+ ASN1_OBJECT *oid = sk_ASN1_OBJECT_value(expset, i);
+ if (level_find_node(curr, node, oid))
+ continue;
+ if (!tree_add_unmatched(curr, cache, oid, node, tree))
+ return 0;
+ }
+
+ }
+
+ return 1;
+
+ }
+
+static int tree_link_any(X509_POLICY_LEVEL *curr,
+ const X509_POLICY_CACHE *cache,
+ X509_POLICY_TREE *tree)
+ {
+ size_t i;
+ /*X509_POLICY_DATA *data;*/
+ X509_POLICY_NODE *node;
+ X509_POLICY_LEVEL *last = curr - 1;
+
+ for (i = 0; i < sk_X509_POLICY_NODE_num(last->nodes); i++)
+ {
+ node = sk_X509_POLICY_NODE_value(last->nodes, i);
+
+ if (!tree_link_unmatched(curr, cache, node, tree))
+ return 0;
+
+#if 0
+
+ /* Skip any node with any children: we only want unmathced
+ * nodes.
+ *
+ * Note: need something better for policy mapping
+ * because each node may have multiple children
+ */
+ if (node->nchild)
+ continue;
+
+ /* Create a new node with qualifiers from anyPolicy and
+ * id from unmatched node.
+ */
+ data = policy_data_new(NULL, node->data->valid_policy,
+ node_critical(node));
+
+ if (data == NULL)
+ return 0;
+ /* Curr may not have anyPolicy */
+ data->qualifier_set = cache->anyPolicy->qualifier_set;
+ data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS;
+ if (!level_add_node(curr, data, node, tree))
+ {
+ policy_data_free(data);
+ return 0;
+ }
+
+#endif
+
+ }
+ /* Finally add link to anyPolicy */
+ if (last->anyPolicy)
+ {
+ if (!level_add_node(curr, cache->anyPolicy,
+ last->anyPolicy, NULL))
+ return 0;
+ }
+ return 1;
+ }
+
+/* Prune the tree: delete any child mapped child data on the current level
+ * then proceed up the tree deleting any data with no children. If we ever
+ * have no data on a level we can halt because the tree will be empty.
+ */
+
+static int tree_prune(X509_POLICY_TREE *tree, X509_POLICY_LEVEL *curr)
+ {
+ STACK_OF(X509_POLICY_NODE) *nodes;
+ X509_POLICY_NODE *node;
+ int i;
+ nodes = curr->nodes;
+ if (curr->flags & X509_V_FLAG_INHIBIT_MAP)
+ {
+ for (i = sk_X509_POLICY_NODE_num(nodes) - 1; i >= 0; i--)
+ {
+ node = sk_X509_POLICY_NODE_value(nodes, i);
+ /* Delete any mapped data: see RFC3280 XXXX */
+ if (node->data->flags & POLICY_DATA_FLAG_MAP_MASK)
+ {
+ node->parent->nchild--;
+ OPENSSL_free(node);
+ (void)sk_X509_POLICY_NODE_delete(nodes,i);
+ }
+ }
+ }
+
+ for(;;) {
+ --curr;
+ nodes = curr->nodes;
+ for (i = sk_X509_POLICY_NODE_num(nodes) - 1; i >= 0; i--)
+ {
+ node = sk_X509_POLICY_NODE_value(nodes, i);
+ if (node->nchild == 0)
+ {
+ node->parent->nchild--;
+ OPENSSL_free(node);
+ (void)sk_X509_POLICY_NODE_delete(nodes, i);
+ }
+ }
+ if (curr->anyPolicy && !curr->anyPolicy->nchild)
+ {
+ if (curr->anyPolicy->parent)
+ curr->anyPolicy->parent->nchild--;
+ OPENSSL_free(curr->anyPolicy);
+ curr->anyPolicy = NULL;
+ }
+ if (curr == tree->levels)
+ {
+ /* If we zapped anyPolicy at top then tree is empty */
+ if (!curr->anyPolicy)
+ return 2;
+ return 1;
+ }
+ }
+
+ return 1;
+
+ }
+
+static int tree_add_auth_node(STACK_OF(X509_POLICY_NODE) **pnodes,
+ X509_POLICY_NODE *pcy)
+ {
+ if (!*pnodes)
+ {
+ *pnodes = policy_node_cmp_new();
+ if (!*pnodes)
+ return 0;
+ }
+ else if (sk_X509_POLICY_NODE_find(*pnodes, NULL, pcy))
+ return 1;
+
+ if (!sk_X509_POLICY_NODE_push(*pnodes, pcy))
+ return 0;
+
+ return 1;
+
+ }
+
+/* Calculate the authority set based on policy tree.
+ * The 'pnodes' parameter is used as a store for the set of policy nodes
+ * used to calculate the user set. If the authority set is not anyPolicy
+ * then pnodes will just point to the authority set. If however the authority
+ * set is anyPolicy then the set of valid policies (other than anyPolicy)
+ * is store in pnodes. The return value of '2' is used in this case to indicate
+ * that pnodes should be freed.
+ */
+
+static int tree_calculate_authority_set(X509_POLICY_TREE *tree,
+ STACK_OF(X509_POLICY_NODE) **pnodes)
+ {
+ X509_POLICY_LEVEL *curr;
+ X509_POLICY_NODE *node, *anyptr;
+ STACK_OF(X509_POLICY_NODE) **addnodes;
+ int i;
+ size_t j;
+ curr = tree->levels + tree->nlevel - 1;
+
+ /* If last level contains anyPolicy set is anyPolicy */
+ if (curr->anyPolicy)
+ {
+ if (!tree_add_auth_node(&tree->auth_policies, curr->anyPolicy))
+ return 0;
+ addnodes = pnodes;
+ }
+ else
+ /* Add policies to authority set */
+ addnodes = &tree->auth_policies;
+
+ curr = tree->levels;
+ for (i = 1; i < tree->nlevel; i++)
+ {
+ /* If no anyPolicy node on this this level it can't
+ * appear on lower levels so end search.
+ */
+ if (!(anyptr = curr->anyPolicy))
+ break;
+ curr++;
+ for (j = 0; j < sk_X509_POLICY_NODE_num(curr->nodes); j++)
+ {
+ node = sk_X509_POLICY_NODE_value(curr->nodes, j);
+ if ((node->parent == anyptr)
+ && !tree_add_auth_node(addnodes, node))
+ return 0;
+ }
+ }
+
+ if (addnodes == pnodes)
+ return 2;
+
+ *pnodes = tree->auth_policies;
+
+ return 1;
+ }
+
+static int tree_calculate_user_set(X509_POLICY_TREE *tree,
+ STACK_OF(ASN1_OBJECT) *policy_oids,
+ STACK_OF(X509_POLICY_NODE) *auth_nodes)
+ {
+ size_t i;
+ X509_POLICY_NODE *node;
+ ASN1_OBJECT *oid;
+
+ X509_POLICY_NODE *anyPolicy;
+ X509_POLICY_DATA *extra;
+
+ /* Check if anyPolicy present in authority constrained policy set:
+ * this will happen if it is a leaf node.
+ */
+
+ if (sk_ASN1_OBJECT_num(policy_oids) <= 0)
+ return 1;
+
+ anyPolicy = tree->levels[tree->nlevel - 1].anyPolicy;
+
+ for (i = 0; i < sk_ASN1_OBJECT_num(policy_oids); i++)
+ {
+ oid = sk_ASN1_OBJECT_value(policy_oids, i);
+ if (OBJ_obj2nid(oid) == NID_any_policy)
+ {
+ tree->flags |= POLICY_FLAG_ANY_POLICY;
+ return 1;
+ }
+ }
+
+ for (i = 0; i < sk_ASN1_OBJECT_num(policy_oids); i++)
+ {
+ oid = sk_ASN1_OBJECT_value(policy_oids, i);
+ node = tree_find_sk(auth_nodes, oid);
+ if (!node)
+ {
+ if (!anyPolicy)
+ continue;
+ /* Create a new node with policy ID from user set
+ * and qualifiers from anyPolicy.
+ */
+ extra = policy_data_new(NULL, oid,
+ node_critical(anyPolicy));
+ if (!extra)
+ return 0;
+ extra->qualifier_set = anyPolicy->data->qualifier_set;
+ extra->flags = POLICY_DATA_FLAG_SHARED_QUALIFIERS
+ | POLICY_DATA_FLAG_EXTRA_NODE;
+ node = level_add_node(NULL, extra, anyPolicy->parent,
+ tree);
+ }
+ if (!tree->user_policies)
+ {
+ tree->user_policies = sk_X509_POLICY_NODE_new_null();
+ if (!tree->user_policies)
+ return 1;
+ }
+ if (!sk_X509_POLICY_NODE_push(tree->user_policies, node))
+ return 0;
+ }
+ return 1;
+
+ }
+
+static int tree_evaluate(X509_POLICY_TREE *tree)
+ {
+ int ret, i;
+ X509_POLICY_LEVEL *curr = tree->levels + 1;
+ const X509_POLICY_CACHE *cache;
+
+ for(i = 1; i < tree->nlevel; i++, curr++)
+ {
+ cache = policy_cache_set(curr->cert);
+ if (!tree_link_nodes(curr, cache))
+ return 0;
+
+ if (!(curr->flags & X509_V_FLAG_INHIBIT_ANY)
+ && !tree_link_any(curr, cache, tree))
+ return 0;
+ tree_print("before tree_prune()", tree, curr);
+ ret = tree_prune(tree, curr);
+ if (ret != 1)
+ return ret;
+ }
+
+ return 1;
+
+ }
+
+static void exnode_free(X509_POLICY_NODE *node)
+ {
+ if (node->data && (node->data->flags & POLICY_DATA_FLAG_EXTRA_NODE))
+ OPENSSL_free(node);
+ }
+
+
+void X509_policy_tree_free(X509_POLICY_TREE *tree)
+ {
+ X509_POLICY_LEVEL *curr;
+ int i;
+
+ if (!tree)
+ return;
+
+ sk_X509_POLICY_NODE_free(tree->auth_policies);
+ sk_X509_POLICY_NODE_pop_free(tree->user_policies, exnode_free);
+
+ for(i = 0, curr = tree->levels; i < tree->nlevel; i++, curr++)
+ {
+ if (curr->cert)
+ X509_free(curr->cert);
+ if (curr->nodes)
+ sk_X509_POLICY_NODE_pop_free(curr->nodes,
+ policy_node_free);
+ if (curr->anyPolicy)
+ policy_node_free(curr->anyPolicy);
+ }
+
+ if (tree->extra_data)
+ sk_X509_POLICY_DATA_pop_free(tree->extra_data,
+ policy_data_free);
+
+ OPENSSL_free(tree->levels);
+ OPENSSL_free(tree);
+
+ }
+
+/* Application policy checking function.
+ * Return codes:
+ * 0 Internal Error.
+ * 1 Successful.
+ * -1 One or more certificates contain invalid or inconsistent extensions
+ * -2 User constrained policy set empty and requireExplicit true.
+ */
+
+int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy,
+ STACK_OF(X509) *certs,
+ STACK_OF(ASN1_OBJECT) *policy_oids,
+ unsigned int flags)
+ {
+ int ret;
+ X509_POLICY_TREE *tree = NULL;
+ STACK_OF(X509_POLICY_NODE) *nodes, *auth_nodes = NULL;
+ *ptree = NULL;
+
+ *pexplicit_policy = 0;
+ ret = tree_init(&tree, certs, flags);
+
+ switch (ret)
+ {
+
+ /* Tree empty requireExplicit False: OK */
+ case 2:
+ return 1;
+
+ /* Some internal error */
+ case -1:
+ return -1;
+
+ /* Some internal error */
+ case 0:
+ return 0;
+
+ /* Tree empty requireExplicit True: Error */
+
+ case 6:
+ *pexplicit_policy = 1;
+ return -2;
+
+ /* Tree OK requireExplicit True: OK and continue */
+ case 5:
+ *pexplicit_policy = 1;
+ break;
+
+ /* Tree OK: continue */
+
+ case 1:
+ if (!tree)
+ /*
+ * tree_init() returns success and a null tree
+ * if it's just looking at a trust anchor.
+ * I'm not sure that returning success here is
+ * correct, but I'm sure that reporting this
+ * as an internal error which our caller
+ * interprets as a malloc failure is wrong.
+ */
+ return 1;
+ break;
+ }
+
+ if (!tree) goto error;
+ ret = tree_evaluate(tree);
+
+ tree_print("tree_evaluate()", tree, NULL);
+
+ if (ret <= 0)
+ goto error;
+
+ /* Return value 2 means tree empty */
+ if (ret == 2)
+ {
+ X509_policy_tree_free(tree);
+ if (*pexplicit_policy)
+ return -2;
+ else
+ return 1;
+ }
+
+ /* Tree is not empty: continue */
+
+ ret = tree_calculate_authority_set(tree, &auth_nodes);
+
+ if (!ret)
+ goto error;
+
+ if (!tree_calculate_user_set(tree, policy_oids, auth_nodes))
+ goto error;
+
+ if (ret == 2)
+ sk_X509_POLICY_NODE_free(auth_nodes);
+
+ if (tree)
+ *ptree = tree;
+
+ if (*pexplicit_policy)
+ {
+ nodes = X509_policy_tree_get0_user_policies(tree);
+ if (sk_X509_POLICY_NODE_num(nodes) <= 0)
+ return -2;
+ }
+
+ return 1;
+
+ error:
+
+ X509_policy_tree_free(tree);
+
+ return 0;
+
+ }
+
diff --git a/crypto/x509v3/tabtest.c b/crypto/x509v3/tabtest.c
new file mode 100644
index 0000000..aa27c1e
--- /dev/null
+++ b/crypto/x509v3/tabtest.c
@@ -0,0 +1,92 @@
+/* tabtest.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999 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).
+ *
+ */
+
+/* Simple program to check the ext_dat.h is correct and print out
+ * problems if it is not.
+ */
+
+#include <stdio.h>
+
+#include <openssl/x509v3.h>
+
+#include "ext_dat.h"
+
+int main()
+{
+ int i, prev = -1, bad = 0;
+ const X509V3_EXT_METHOD **tmp;
+ i = sizeof(standard_exts) / sizeof(X509V3_EXT_METHOD *);
+ if(i != STANDARD_EXTENSION_COUNT)
+ fprintf(stderr, "Extension number invalid expecting %d\n", i);
+ tmp = standard_exts;
+ for(i = 0; i < STANDARD_EXTENSION_COUNT; i++, tmp++) {
+ if((*tmp)->ext_nid < prev) bad = 1;
+ prev = (*tmp)->ext_nid;
+
+ }
+ if(bad) {
+ tmp = standard_exts;
+ fprintf(stderr, "Extensions out of order!\n");
+ for(i = 0; i < STANDARD_EXTENSION_COUNT; i++, tmp++)
+ printf("%d : %s\n", (*tmp)->ext_nid, OBJ_nid2sn((*tmp)->ext_nid));
+ return 1;
+ } else {
+ printf("PASS\n");
+ return 0;
+ }
+}
diff --git a/crypto/x509v3/v3_akey.c b/crypto/x509v3/v3_akey.c
new file mode 100644
index 0000000..67607d9
--- /dev/null
+++ b/crypto/x509v3/v3_akey.c
@@ -0,0 +1,211 @@
+/* v3_akey.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999 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 <stdio.h>
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/conf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509v3.h>
+
+
+static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_KEYID(X509V3_EXT_METHOD *method,
+ AUTHORITY_KEYID *akeyid, STACK_OF(CONF_VALUE) *extlist);
+static AUTHORITY_KEYID *v2i_AUTHORITY_KEYID(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *values);
+
+const X509V3_EXT_METHOD v3_akey_id =
+ {
+ NID_authority_key_identifier,
+ X509V3_EXT_MULTILINE, ASN1_ITEM_ref(AUTHORITY_KEYID),
+ 0,0,0,0,
+ 0,0,
+ (X509V3_EXT_I2V)i2v_AUTHORITY_KEYID,
+ (X509V3_EXT_V2I)v2i_AUTHORITY_KEYID,
+ 0,0,
+ NULL
+ };
+
+static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_KEYID(X509V3_EXT_METHOD *method,
+ AUTHORITY_KEYID *akeyid, STACK_OF(CONF_VALUE) *extlist)
+{
+ char *tmp;
+ if(akeyid->keyid) {
+ tmp = hex_to_string(akeyid->keyid->data, akeyid->keyid->length);
+ X509V3_add_value("keyid", tmp, &extlist);
+ OPENSSL_free(tmp);
+ }
+ if(akeyid->issuer)
+ extlist = i2v_GENERAL_NAMES(NULL, akeyid->issuer, extlist);
+ if(akeyid->serial) {
+ tmp = hex_to_string(akeyid->serial->data,
+ akeyid->serial->length);
+ X509V3_add_value("serial", tmp, &extlist);
+ OPENSSL_free(tmp);
+ }
+ return extlist;
+}
+
+/* Currently two options:
+ * keyid: use the issuers subject keyid, the value 'always' means its is
+ * an error if the issuer certificate doesn't have a key id.
+ * issuer: use the issuers cert issuer and serial number. The default is
+ * to only use this if keyid is not present. With the option 'always'
+ * this is always included.
+ */
+
+static AUTHORITY_KEYID *v2i_AUTHORITY_KEYID(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *values)
+ {
+ char keyid=0, issuer=0;
+ size_t i;
+ int j;
+ CONF_VALUE *cnf;
+ ASN1_OCTET_STRING *ikeyid = NULL;
+ X509_NAME *isname = NULL;
+ GENERAL_NAMES * gens = NULL;
+ GENERAL_NAME *gen = NULL;
+ ASN1_INTEGER *serial = NULL;
+ X509_EXTENSION *ext;
+ X509 *cert;
+ AUTHORITY_KEYID *akeyid;
+
+ for(i = 0; i < sk_CONF_VALUE_num(values); i++)
+ {
+ cnf = sk_CONF_VALUE_value(values, i);
+ if(!strcmp(cnf->name, "keyid"))
+ {
+ keyid = 1;
+ if(cnf->value && !strcmp(cnf->value, "always"))
+ keyid = 2;
+ }
+ else if(!strcmp(cnf->name, "issuer"))
+ {
+ issuer = 1;
+ if(cnf->value && !strcmp(cnf->value, "always"))
+ issuer = 2;
+ }
+ else
+ {
+ OPENSSL_PUT_ERROR(X509V3, v2i_AUTHORITY_KEYID, X509V3_R_UNKNOWN_OPTION);
+ ERR_add_error_data(2, "name=", cnf->name);
+ return NULL;
+ }
+ }
+
+ if(!ctx || !ctx->issuer_cert)
+ {
+ if(ctx && (ctx->flags==CTX_TEST))
+ return AUTHORITY_KEYID_new();
+ OPENSSL_PUT_ERROR(X509V3, v2i_AUTHORITY_KEYID, X509V3_R_NO_ISSUER_CERTIFICATE);
+ return NULL;
+ }
+
+ cert = ctx->issuer_cert;
+
+ if(keyid)
+ {
+ j = X509_get_ext_by_NID(cert, NID_subject_key_identifier, -1);
+ if((j >= 0) && (ext = X509_get_ext(cert, j)))
+ ikeyid = X509V3_EXT_d2i(ext);
+ if(keyid==2 && !ikeyid)
+ {
+ OPENSSL_PUT_ERROR(X509V3, v2i_AUTHORITY_KEYID, X509V3_R_UNABLE_TO_GET_ISSUER_KEYID);
+ return NULL;
+ }
+ }
+
+ if((issuer && !ikeyid) || (issuer == 2))
+ {
+ isname = X509_NAME_dup(X509_get_issuer_name(cert));
+ 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);
+ goto err;
+ }
+ }
+
+ if(!(akeyid = AUTHORITY_KEYID_new())) goto err;
+
+ if(isname)
+ {
+ if(!(gens = sk_GENERAL_NAME_new_null())
+ || !(gen = GENERAL_NAME_new())
+ || !sk_GENERAL_NAME_push(gens, gen))
+ {
+ OPENSSL_PUT_ERROR(X509V3, v2i_AUTHORITY_KEYID, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ gen->type = GEN_DIRNAME;
+ gen->d.dirn = isname;
+ }
+
+ akeyid->issuer = gens;
+ akeyid->serial = serial;
+ akeyid->keyid = ikeyid;
+
+ return akeyid;
+
+ err:
+ X509_NAME_free(isname);
+ M_ASN1_INTEGER_free(serial);
+ M_ASN1_OCTET_STRING_free(ikeyid);
+ return NULL;
+ }
diff --git a/crypto/x509v3/v3_akeya.c b/crypto/x509v3/v3_akeya.c
new file mode 100644
index 0000000..8b72cca
--- /dev/null
+++ b/crypto/x509v3/v3_akeya.c
@@ -0,0 +1,71 @@
+/* v3_akey_asn1.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999 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 <stdio.h>
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/conf.h>
+#include <openssl/x509v3.h>
+
+
+ASN1_SEQUENCE(AUTHORITY_KEYID) = {
+ ASN1_IMP_OPT(AUTHORITY_KEYID, keyid, ASN1_OCTET_STRING, 0),
+ ASN1_IMP_SEQUENCE_OF_OPT(AUTHORITY_KEYID, issuer, GENERAL_NAME, 1),
+ ASN1_IMP_OPT(AUTHORITY_KEYID, serial, ASN1_INTEGER, 2)
+} ASN1_SEQUENCE_END(AUTHORITY_KEYID)
+
+IMPLEMENT_ASN1_FUNCTIONS(AUTHORITY_KEYID)
diff --git a/crypto/x509v3/v3_alt.c b/crypto/x509v3/v3_alt.c
new file mode 100644
index 0000000..54e0f0a
--- /dev/null
+++ b/crypto/x509v3/v3_alt.c
@@ -0,0 +1,617 @@
+/* v3_alt.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2003 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 <stdio.h>
+
+#include <openssl/conf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509v3.h>
+
+
+static GENERAL_NAMES *v2i_subject_alt(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval);
+static GENERAL_NAMES *v2i_issuer_alt(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval);
+static int copy_email(X509V3_CTX *ctx, GENERAL_NAMES *gens, int move_p);
+static int copy_issuer(X509V3_CTX *ctx, GENERAL_NAMES *gens);
+static int do_othername(GENERAL_NAME *gen, char *value, X509V3_CTX *ctx);
+static int do_dirname(GENERAL_NAME *gen, char *value, X509V3_CTX *ctx);
+
+const X509V3_EXT_METHOD v3_alt[] = {
+{ NID_subject_alt_name, 0, ASN1_ITEM_ref(GENERAL_NAMES),
+0,0,0,0,
+0,0,
+(X509V3_EXT_I2V)i2v_GENERAL_NAMES,
+(X509V3_EXT_V2I)v2i_subject_alt,
+NULL, NULL, NULL},
+
+{ NID_issuer_alt_name, 0, ASN1_ITEM_ref(GENERAL_NAMES),
+0,0,0,0,
+0,0,
+(X509V3_EXT_I2V)i2v_GENERAL_NAMES,
+(X509V3_EXT_V2I)v2i_issuer_alt,
+NULL, NULL, NULL},
+
+{ NID_certificate_issuer, 0, ASN1_ITEM_ref(GENERAL_NAMES),
+0,0,0,0,
+0,0,
+(X509V3_EXT_I2V)i2v_GENERAL_NAMES,
+NULL, NULL, NULL, NULL},
+};
+
+STACK_OF(CONF_VALUE) *i2v_GENERAL_NAMES(X509V3_EXT_METHOD *method,
+ GENERAL_NAMES *gens, STACK_OF(CONF_VALUE) *ret)
+{
+ size_t i;
+ GENERAL_NAME *gen;
+ for(i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
+ gen = sk_GENERAL_NAME_value(gens, i);
+ ret = i2v_GENERAL_NAME(method, gen, ret);
+ }
+ if(!ret) return sk_CONF_VALUE_new_null();
+ return ret;
+}
+
+STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method,
+ GENERAL_NAME *gen, STACK_OF(CONF_VALUE) *ret)
+{
+ unsigned char *p;
+ char oline[256], htmp[5];
+ int i;
+ switch (gen->type)
+ {
+ case GEN_OTHERNAME:
+ X509V3_add_value("othername","<unsupported>", &ret);
+ break;
+
+ case GEN_X400:
+ X509V3_add_value("X400Name","<unsupported>", &ret);
+ break;
+
+ case GEN_EDIPARTY:
+ X509V3_add_value("EdiPartyName","<unsupported>", &ret);
+ break;
+
+ case GEN_EMAIL:
+ X509V3_add_value_uchar("email",gen->d.ia5->data, &ret);
+ break;
+
+ case GEN_DNS:
+ X509V3_add_value_uchar("DNS",gen->d.ia5->data, &ret);
+ break;
+
+ case GEN_URI:
+ X509V3_add_value_uchar("URI",gen->d.ia5->data, &ret);
+ break;
+
+ case GEN_DIRNAME:
+ X509_NAME_oneline(gen->d.dirn, oline, 256);
+ X509V3_add_value("DirName",oline, &ret);
+ break;
+
+ case GEN_IPADD:
+ p = gen->d.ip->data;
+ if(gen->d.ip->length == 4)
+ BIO_snprintf(oline, sizeof oline,
+ "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+ else if(gen->d.ip->length == 16)
+ {
+ oline[0] = 0;
+ for (i = 0; i < 8; i++)
+ {
+ BIO_snprintf(htmp, sizeof htmp,
+ "%X", p[0] << 8 | p[1]);
+ p += 2;
+ strcat(oline, htmp);
+ if (i != 7)
+ strcat(oline, ":");
+ }
+ }
+ else
+ {
+ X509V3_add_value("IP Address","<invalid>", &ret);
+ break;
+ }
+ X509V3_add_value("IP Address",oline, &ret);
+ break;
+
+ case GEN_RID:
+ i2t_ASN1_OBJECT(oline, 256, gen->d.rid);
+ X509V3_add_value("Registered ID",oline, &ret);
+ break;
+ }
+ return ret;
+}
+
+int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen)
+{
+ unsigned char *p;
+ int i;
+ switch (gen->type)
+ {
+ case GEN_OTHERNAME:
+ BIO_printf(out, "othername:<unsupported>");
+ break;
+
+ case GEN_X400:
+ BIO_printf(out, "X400Name:<unsupported>");
+ break;
+
+ case GEN_EDIPARTY:
+ /* Maybe fix this: it is supported now */
+ BIO_printf(out, "EdiPartyName:<unsupported>");
+ break;
+
+ case GEN_EMAIL:
+ BIO_printf(out, "email:%s",gen->d.ia5->data);
+ break;
+
+ case GEN_DNS:
+ BIO_printf(out, "DNS:%s",gen->d.ia5->data);
+ break;
+
+ case GEN_URI:
+ BIO_printf(out, "URI:%s",gen->d.ia5->data);
+ break;
+
+ case GEN_DIRNAME:
+ BIO_printf(out, "DirName: ");
+ X509_NAME_print_ex(out, gen->d.dirn, 0, XN_FLAG_ONELINE);
+ break;
+
+ case GEN_IPADD:
+ p = gen->d.ip->data;
+ if(gen->d.ip->length == 4)
+ BIO_printf(out, "IP Address:%d.%d.%d.%d",
+ p[0], p[1], p[2], p[3]);
+ else if(gen->d.ip->length == 16)
+ {
+ BIO_printf(out, "IP Address");
+ for (i = 0; i < 8; i++)
+ {
+ BIO_printf(out, ":%X", p[0] << 8 | p[1]);
+ p += 2;
+ }
+ BIO_puts(out, "\n");
+ }
+ else
+ {
+ BIO_printf(out,"IP Address:<invalid>");
+ break;
+ }
+ break;
+
+ case GEN_RID:
+ BIO_printf(out, "Registered ID");
+ i2a_ASN1_OBJECT(out, gen->d.rid);
+ break;
+ }
+ return 1;
+}
+
+static GENERAL_NAMES *v2i_issuer_alt(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
+{
+ GENERAL_NAMES *gens = NULL;
+ CONF_VALUE *cnf;
+ size_t i;
+ if(!(gens = sk_GENERAL_NAME_new_null())) {
+ OPENSSL_PUT_ERROR(X509V3, v2i_issuer_alt, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ for(i = 0; i < sk_CONF_VALUE_num(nval); i++) {
+ cnf = sk_CONF_VALUE_value(nval, i);
+ if(!name_cmp(cnf->name, "issuer") && cnf->value &&
+ !strcmp(cnf->value, "copy")) {
+ if(!copy_issuer(ctx, gens)) goto err;
+ } else {
+ GENERAL_NAME *gen;
+ if(!(gen = v2i_GENERAL_NAME(method, ctx, cnf)))
+ goto err;
+ sk_GENERAL_NAME_push(gens, gen);
+ }
+ }
+ return gens;
+ err:
+ sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
+ return NULL;
+}
+
+/* Append subject altname of issuer to issuer alt name of subject */
+
+static int copy_issuer(X509V3_CTX *ctx, GENERAL_NAMES *gens)
+{
+ GENERAL_NAMES *ialt;
+ GENERAL_NAME *gen;
+ X509_EXTENSION *ext;
+ int i;
+ 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);
+ 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);
+ 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);
+ goto err;
+ }
+ }
+ sk_GENERAL_NAME_free(ialt);
+
+ return 1;
+
+ err:
+ return 0;
+
+}
+
+static GENERAL_NAMES *v2i_subject_alt(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
+{
+ GENERAL_NAMES *gens = NULL;
+ CONF_VALUE *cnf;
+ size_t i;
+ if(!(gens = sk_GENERAL_NAME_new_null())) {
+ OPENSSL_PUT_ERROR(X509V3, v2i_subject_alt, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ for(i = 0; i < sk_CONF_VALUE_num(nval); i++) {
+ cnf = sk_CONF_VALUE_value(nval, i);
+ if(!name_cmp(cnf->name, "email") && cnf->value &&
+ !strcmp(cnf->value, "copy")) {
+ if(!copy_email(ctx, gens, 0)) goto err;
+ } else if(!name_cmp(cnf->name, "email") && cnf->value &&
+ !strcmp(cnf->value, "move")) {
+ if(!copy_email(ctx, gens, 1)) goto err;
+ } else {
+ GENERAL_NAME *gen;
+ if(!(gen = v2i_GENERAL_NAME(method, ctx, cnf)))
+ goto err;
+ sk_GENERAL_NAME_push(gens, gen);
+ }
+ }
+ return gens;
+ err:
+ sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
+ return NULL;
+}
+
+/* Copy any email addresses in a certificate or request to
+ * GENERAL_NAMES
+ */
+
+static int copy_email(X509V3_CTX *ctx, GENERAL_NAMES *gens, int move_p)
+{
+ X509_NAME *nm;
+ ASN1_IA5STRING *email = NULL;
+ X509_NAME_ENTRY *ne;
+ GENERAL_NAME *gen = NULL;
+ int i;
+ 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);
+ goto err;
+ }
+ /* Find the subject name */
+ if(ctx->subject_cert) nm = X509_get_subject_name(ctx->subject_cert);
+ else nm = X509_REQ_get_subject_name(ctx->subject_req);
+
+ /* Now add any email address(es) to STACK */
+ i = -1;
+ while((i = X509_NAME_get_index_by_NID(nm,
+ NID_pkcs9_emailAddress, i)) >= 0) {
+ ne = X509_NAME_get_entry(nm, i);
+ email = M_ASN1_IA5STRING_dup(X509_NAME_ENTRY_get_data(ne));
+ if (move_p)
+ {
+ X509_NAME_delete_entry(nm, i);
+ X509_NAME_ENTRY_free(ne);
+ i--;
+ }
+ if(!email || !(gen = GENERAL_NAME_new())) {
+ OPENSSL_PUT_ERROR(X509V3, copy_email, 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);
+ goto err;
+ }
+ gen = NULL;
+ }
+
+
+ return 1;
+
+ err:
+ GENERAL_NAME_free(gen);
+ M_ASN1_IA5STRING_free(email);
+ return 0;
+
+}
+
+GENERAL_NAMES *v2i_GENERAL_NAMES(const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
+{
+ GENERAL_NAME *gen;
+ GENERAL_NAMES *gens = NULL;
+ CONF_VALUE *cnf;
+ size_t i;
+ if(!(gens = sk_GENERAL_NAME_new_null())) {
+ OPENSSL_PUT_ERROR(X509V3, v2i_GENERAL_NAMES, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ for(i = 0; i < sk_CONF_VALUE_num(nval); i++) {
+ cnf = sk_CONF_VALUE_value(nval, i);
+ if(!(gen = v2i_GENERAL_NAME(method, ctx, cnf))) goto err;
+ sk_GENERAL_NAME_push(gens, gen);
+ }
+ return gens;
+ err:
+ sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
+ return NULL;
+}
+
+GENERAL_NAME *v2i_GENERAL_NAME(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
+ CONF_VALUE *cnf)
+ {
+ return v2i_GENERAL_NAME_ex(NULL, method, ctx, cnf, 0);
+ }
+
+GENERAL_NAME *a2i_GENERAL_NAME(GENERAL_NAME *out,
+ const X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
+ int gen_type, char *value, int is_nc)
+ {
+ char is_string = 0;
+ GENERAL_NAME *gen = NULL;
+
+ if(!value)
+ {
+ OPENSSL_PUT_ERROR(X509V3, a2i_GENERAL_NAME, X509V3_R_MISSING_VALUE);
+ return NULL;
+ }
+
+ if (out)
+ gen = out;
+ else
+ {
+ gen = GENERAL_NAME_new();
+ if(gen == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509V3, a2i_GENERAL_NAME, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ }
+
+ switch (gen_type)
+ {
+ case GEN_URI:
+ case GEN_EMAIL:
+ case GEN_DNS:
+ is_string = 1;
+ break;
+
+ case GEN_RID:
+ {
+ ASN1_OBJECT *obj;
+ if(!(obj = OBJ_txt2obj(value,0)))
+ {
+ OPENSSL_PUT_ERROR(X509V3, a2i_GENERAL_NAME, X509V3_R_BAD_OBJECT);
+ ERR_add_error_data(2, "value=", value);
+ goto err;
+ }
+ gen->d.rid = obj;
+ }
+ break;
+
+ case GEN_IPADD:
+ if (is_nc)
+ gen->d.ip = a2i_IPADDRESS_NC(value);
+ else
+ gen->d.ip = a2i_IPADDRESS(value);
+ if(gen->d.ip == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509V3, a2i_GENERAL_NAME, X509V3_R_BAD_IP_ADDRESS);
+ ERR_add_error_data(2, "value=", value);
+ goto err;
+ }
+ break;
+
+ case GEN_DIRNAME:
+ if (!do_dirname(gen, value, ctx))
+ {
+ OPENSSL_PUT_ERROR(X509V3, a2i_GENERAL_NAME, X509V3_R_DIRNAME_ERROR);
+ goto err;
+ }
+ break;
+
+ case GEN_OTHERNAME:
+ if (!do_othername(gen, value, ctx))
+ {
+ OPENSSL_PUT_ERROR(X509V3, a2i_GENERAL_NAME, X509V3_R_OTHERNAME_ERROR);
+ goto err;
+ }
+ break;
+ default:
+ OPENSSL_PUT_ERROR(X509V3, a2i_GENERAL_NAME, X509V3_R_UNSUPPORTED_TYPE);
+ goto err;
+ }
+
+ if(is_string)
+ {
+ if(!(gen->d.ia5 = M_ASN1_IA5STRING_new()) ||
+ !ASN1_STRING_set(gen->d.ia5, (unsigned char*)value,
+ strlen(value)))
+ {
+ OPENSSL_PUT_ERROR(X509V3, a2i_GENERAL_NAME, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+
+ gen->type = gen_type;
+
+ return gen;
+
+ err:
+ if (!out)
+ GENERAL_NAME_free(gen);
+ return NULL;
+ }
+
+GENERAL_NAME *v2i_GENERAL_NAME_ex(GENERAL_NAME *out,
+ const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, CONF_VALUE *cnf, int is_nc)
+ {
+ int type;
+
+ char *name, *value;
+
+ name = cnf->name;
+ value = cnf->value;
+
+ if(!value)
+ {
+ OPENSSL_PUT_ERROR(X509V3, v2i_GENERAL_NAME_ex, X509V3_R_MISSING_VALUE);
+ return NULL;
+ }
+
+ if(!name_cmp(name, "email"))
+ type = GEN_EMAIL;
+ else if(!name_cmp(name, "URI"))
+ type = GEN_URI;
+ else if(!name_cmp(name, "DNS"))
+ type = GEN_DNS;
+ else if(!name_cmp(name, "RID"))
+ type = GEN_RID;
+ else if(!name_cmp(name, "IP"))
+ type = GEN_IPADD;
+ else if(!name_cmp(name, "dirName"))
+ type = GEN_DIRNAME;
+ else if(!name_cmp(name, "otherName"))
+ type = GEN_OTHERNAME;
+ else
+ {
+ OPENSSL_PUT_ERROR(X509V3, v2i_GENERAL_NAME_ex, X509V3_R_UNSUPPORTED_OPTION);
+ ERR_add_error_data(2, "name=", name);
+ return NULL;
+ }
+
+ return a2i_GENERAL_NAME(out, method, ctx, type, value, is_nc);
+
+ }
+
+static int do_othername(GENERAL_NAME *gen, char *value, X509V3_CTX *ctx)
+ {
+ char *objtmp = NULL, *p;
+ int objlen;
+ if (!(p = strchr(value, ';')))
+ return 0;
+ if (!(gen->d.otherName = OTHERNAME_new()))
+ return 0;
+ /* Free this up because we will overwrite it.
+ * no need to free type_id because it is static
+ */
+ ASN1_TYPE_free(gen->d.otherName->value);
+ if (!(gen->d.otherName->value = ASN1_generate_v3(p + 1, ctx)))
+ return 0;
+ objlen = p - value;
+ objtmp = OPENSSL_malloc(objlen + 1);
+ strncpy(objtmp, value, objlen);
+ objtmp[objlen] = 0;
+ gen->d.otherName->type_id = OBJ_txt2obj(objtmp, 0);
+ OPENSSL_free(objtmp);
+ if (!gen->d.otherName->type_id)
+ return 0;
+ return 1;
+ }
+
+static int do_dirname(GENERAL_NAME *gen, char *value, X509V3_CTX *ctx)
+ {
+ int ret;
+ STACK_OF(CONF_VALUE) *sk;
+ X509_NAME *nm;
+ if (!(nm = X509_NAME_new()))
+ return 0;
+ sk = X509V3_get_section(ctx, value);
+ if (!sk)
+ {
+ OPENSSL_PUT_ERROR(X509V3, do_dirname, X509V3_R_SECTION_NOT_FOUND);
+ ERR_add_error_data(2, "section=", value);
+ X509_NAME_free(nm);
+ return 0;
+ }
+ /* FIXME: should allow other character types... */
+ ret = X509V3_NAME_from_section(nm, sk, MBSTRING_ASC);
+ if (!ret)
+ X509_NAME_free(nm);
+ gen->d.dirn = nm;
+ X509V3_section_free(ctx, sk);
+
+ return ret;
+ }
diff --git a/crypto/x509v3/v3_bcons.c b/crypto/x509v3/v3_bcons.c
new file mode 100644
index 0000000..881b922
--- /dev/null
+++ b/crypto/x509v3/v3_bcons.c
@@ -0,0 +1,125 @@
+/* v3_bcons.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999 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 <stdio.h>
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/conf.h>
+#include <openssl/err.h>
+#include <openssl/obj.h>
+#include <openssl/x509v3.h>
+
+
+static STACK_OF(CONF_VALUE) *i2v_BASIC_CONSTRAINTS(X509V3_EXT_METHOD *method, BASIC_CONSTRAINTS *bcons, STACK_OF(CONF_VALUE) *extlist);
+static BASIC_CONSTRAINTS *v2i_BASIC_CONSTRAINTS(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *values);
+
+const X509V3_EXT_METHOD v3_bcons = {
+NID_basic_constraints, 0,
+ASN1_ITEM_ref(BASIC_CONSTRAINTS),
+0,0,0,0,
+0,0,
+(X509V3_EXT_I2V)i2v_BASIC_CONSTRAINTS,
+(X509V3_EXT_V2I)v2i_BASIC_CONSTRAINTS,
+NULL,NULL,
+NULL
+};
+
+ASN1_SEQUENCE(BASIC_CONSTRAINTS) = {
+ ASN1_OPT(BASIC_CONSTRAINTS, ca, ASN1_FBOOLEAN),
+ ASN1_OPT(BASIC_CONSTRAINTS, pathlen, ASN1_INTEGER)
+} ASN1_SEQUENCE_END(BASIC_CONSTRAINTS)
+
+IMPLEMENT_ASN1_FUNCTIONS(BASIC_CONSTRAINTS)
+
+
+static STACK_OF(CONF_VALUE) *i2v_BASIC_CONSTRAINTS(X509V3_EXT_METHOD *method,
+ BASIC_CONSTRAINTS *bcons, STACK_OF(CONF_VALUE) *extlist)
+{
+ X509V3_add_value_bool("CA", bcons->ca, &extlist);
+ X509V3_add_value_int("pathlen", bcons->pathlen, &extlist);
+ return extlist;
+}
+
+static BASIC_CONSTRAINTS *v2i_BASIC_CONSTRAINTS(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *values)
+{
+ BASIC_CONSTRAINTS *bcons=NULL;
+ CONF_VALUE *val;
+ size_t i;
+ if(!(bcons = BASIC_CONSTRAINTS_new())) {
+ OPENSSL_PUT_ERROR(X509V3, v2i_BASIC_CONSTRAINTS, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ for(i = 0; i < sk_CONF_VALUE_num(values); i++) {
+ val = sk_CONF_VALUE_value(values, i);
+ if(!strcmp(val->name, "CA")) {
+ if(!X509V3_get_value_bool(val, &bcons->ca)) goto err;
+ } 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);
+ X509V3_conf_err(val);
+ goto err;
+ }
+ }
+ return bcons;
+ err:
+ BASIC_CONSTRAINTS_free(bcons);
+ return NULL;
+}
+
diff --git a/crypto/x509v3/v3_bitst.c b/crypto/x509v3/v3_bitst.c
new file mode 100644
index 0000000..dd389f0
--- /dev/null
+++ b/crypto/x509v3/v3_bitst.c
@@ -0,0 +1,140 @@
+/* v3_bitst.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999 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 <stdio.h>
+
+#include <openssl/conf.h>
+#include <openssl/err.h>
+#include <openssl/obj.h>
+#include <openssl/x509v3.h>
+
+
+static BIT_STRING_BITNAME ns_cert_type_table[] = {
+{0, "SSL Client", "client"},
+{1, "SSL Server", "server"},
+{2, "S/MIME", "email"},
+{3, "Object Signing", "objsign"},
+{4, "Unused", "reserved"},
+{5, "SSL CA", "sslCA"},
+{6, "S/MIME CA", "emailCA"},
+{7, "Object Signing CA", "objCA"},
+{-1, NULL, NULL}
+};
+
+static BIT_STRING_BITNAME key_usage_type_table[] = {
+{0, "Digital Signature", "digitalSignature"},
+{1, "Non Repudiation", "nonRepudiation"},
+{2, "Key Encipherment", "keyEncipherment"},
+{3, "Data Encipherment", "dataEncipherment"},
+{4, "Key Agreement", "keyAgreement"},
+{5, "Certificate Sign", "keyCertSign"},
+{6, "CRL Sign", "cRLSign"},
+{7, "Encipher Only", "encipherOnly"},
+{8, "Decipher Only", "decipherOnly"},
+{-1, NULL, NULL}
+};
+
+
+
+const X509V3_EXT_METHOD v3_nscert = EXT_BITSTRING(NID_netscape_cert_type, ns_cert_type_table);
+const X509V3_EXT_METHOD v3_key_usage = EXT_BITSTRING(NID_key_usage, key_usage_type_table);
+
+STACK_OF(CONF_VALUE) *i2v_ASN1_BIT_STRING(X509V3_EXT_METHOD *method,
+ ASN1_BIT_STRING *bits, STACK_OF(CONF_VALUE) *ret)
+{
+ BIT_STRING_BITNAME *bnam;
+ for(bnam =method->usr_data; bnam->lname; bnam++) {
+ if(ASN1_BIT_STRING_get_bit(bits, bnam->bitnum))
+ X509V3_add_value(bnam->lname, NULL, &ret);
+ }
+ return ret;
+}
+
+ASN1_BIT_STRING *v2i_ASN1_BIT_STRING(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
+{
+ CONF_VALUE *val;
+ ASN1_BIT_STRING *bs;
+ size_t i;
+ BIT_STRING_BITNAME *bnam;
+ if(!(bs = M_ASN1_BIT_STRING_new())) {
+ OPENSSL_PUT_ERROR(X509V3, v2i_ASN1_BIT_STRING, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ for(i = 0; i < sk_CONF_VALUE_num(nval); i++) {
+ val = sk_CONF_VALUE_value(nval, i);
+ for(bnam = method->usr_data; bnam->lname; bnam++) {
+ 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);
+ M_ASN1_BIT_STRING_free(bs);
+ return NULL;
+ }
+ break;
+ }
+ }
+ if(!bnam->lname) {
+ OPENSSL_PUT_ERROR(X509V3, v2i_ASN1_BIT_STRING, X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT);
+ X509V3_conf_err(val);
+ M_ASN1_BIT_STRING_free(bs);
+ return NULL;
+ }
+ }
+ return bs;
+}
+
+
diff --git a/crypto/x509v3/v3_conf.c b/crypto/x509v3/v3_conf.c
new file mode 100644
index 0000000..9ee4809
--- /dev/null
+++ b/crypto/x509v3/v3_conf.c
@@ -0,0 +1,528 @@
+/* v3_conf.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2002 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). */
+
+/* extension creation utilities */
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include <openssl/conf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+
+static int v3_check_critical(char **value);
+static int v3_check_generic(char **value);
+static X509_EXTENSION *do_ext_nconf(CONF *conf, X509V3_CTX *ctx, int ext_nid, int crit, char *value);
+static X509_EXTENSION *v3_generic_extension(const char *ext, char *value, int crit, int type, X509V3_CTX *ctx);
+static X509_EXTENSION *do_ext_i2d(const X509V3_EXT_METHOD *method, int ext_nid,
+ int crit, void *ext_struc);
+static unsigned char *generic_asn1(char *value, X509V3_CTX *ctx, long *ext_len);
+/* CONF *conf: Config file */
+/* char *name: Name */
+/* char *value: Value */
+X509_EXTENSION *X509V3_EXT_nconf(CONF *conf, X509V3_CTX *ctx, char *name,
+ char *value)
+ {
+ int crit;
+ int ext_type;
+ X509_EXTENSION *ret;
+ crit = v3_check_critical(&value);
+ if ((ext_type = v3_check_generic(&value)))
+ return v3_generic_extension(name, value, crit, ext_type, ctx);
+ 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);
+ ERR_add_error_data(4,"name=", name, ", value=", value);
+ }
+ return ret;
+ }
+
+/* CONF *conf: Config file */
+/* char *value: Value */
+X509_EXTENSION *X509V3_EXT_nconf_nid(CONF *conf, X509V3_CTX *ctx, int ext_nid,
+ char *value)
+ {
+ int crit;
+ int ext_type;
+ crit = v3_check_critical(&value);
+ if ((ext_type = v3_check_generic(&value)))
+ return v3_generic_extension(OBJ_nid2sn(ext_nid),
+ value, crit, ext_type, ctx);
+ return do_ext_nconf(conf, ctx, ext_nid, crit, value);
+ }
+
+/* CONF *conf: Config file */
+/* char *value: Value */
+static X509_EXTENSION *do_ext_nconf(CONF *conf, X509V3_CTX *ctx, int ext_nid,
+ int crit, char *value)
+ {
+ const X509V3_EXT_METHOD *method;
+ X509_EXTENSION *ext;
+ STACK_OF(CONF_VALUE) *nval;
+ void *ext_struc;
+ if (ext_nid == NID_undef)
+ {
+ OPENSSL_PUT_ERROR(X509V3, do_ext_nconf, 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);
+ return NULL;
+ }
+ /* Now get internal extension representation based on type */
+ if (method->v2i)
+ {
+ if(*value == '@') nval = NCONF_get_section(conf, value + 1);
+ 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);
+ ERR_add_error_data(4, "name=", OBJ_nid2sn(ext_nid), ",section=", value);
+ return NULL;
+ }
+ ext_struc = method->v2i(method, ctx, nval);
+ if(*value != '@') sk_CONF_VALUE_pop_free(nval,
+ X509V3_conf_free);
+ if(!ext_struc) return NULL;
+ }
+ else if(method->s2i)
+ {
+ if(!(ext_struc = method->s2i(method, ctx, value))) return NULL;
+ }
+ else if(method->r2i)
+ {
+ if(!ctx->db || !ctx->db_meth)
+ {
+ OPENSSL_PUT_ERROR(X509V3, do_ext_nconf, 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);
+ ERR_add_error_data(2, "name=", OBJ_nid2sn(ext_nid));
+ return NULL;
+ }
+
+ ext = do_ext_i2d(method, ext_nid, crit, ext_struc);
+ if(method->it) ASN1_item_free(ext_struc, ASN1_ITEM_ptr(method->it));
+ else method->ext_free(ext_struc);
+ return ext;
+
+ }
+
+static X509_EXTENSION *do_ext_i2d(const X509V3_EXT_METHOD *method, int ext_nid,
+ int crit, void *ext_struc)
+ {
+ unsigned char *ext_der;
+ int ext_len;
+ ASN1_OCTET_STRING *ext_oct;
+ X509_EXTENSION *ext;
+ /* Convert internal representation to DER */
+ if (method->it)
+ {
+ ext_der = NULL;
+ ext_len = ASN1_item_i2d(ext_struc, &ext_der, ASN1_ITEM_ptr(method->it));
+ if (ext_len < 0) goto merr;
+ }
+ else
+ {
+ unsigned char *p;
+ ext_len = method->i2d(ext_struc, NULL);
+ if(!(ext_der = OPENSSL_malloc(ext_len))) goto merr;
+ p = ext_der;
+ method->i2d(ext_struc, &p);
+ }
+ if (!(ext_oct = M_ASN1_OCTET_STRING_new())) goto merr;
+ ext_oct->data = ext_der;
+ ext_oct->length = ext_len;
+
+ ext = X509_EXTENSION_create_by_NID(NULL, ext_nid, crit, ext_oct);
+ if (!ext) goto merr;
+ M_ASN1_OCTET_STRING_free(ext_oct);
+
+ return ext;
+
+ merr:
+ OPENSSL_PUT_ERROR(X509V3, do_ext_i2d, ERR_R_MALLOC_FAILURE);
+ return NULL;
+
+ }
+
+/* Given an internal structure, nid and critical flag create an extension */
+
+X509_EXTENSION *X509V3_EXT_i2d(int ext_nid, int crit, void *ext_struc)
+ {
+ const X509V3_EXT_METHOD *method;
+ if (!(method = X509V3_EXT_get_nid(ext_nid))) {
+ OPENSSL_PUT_ERROR(X509V3, X509V3_EXT_i2d, X509V3_R_UNKNOWN_EXTENSION);
+ return NULL;
+ }
+ return do_ext_i2d(method, ext_nid, crit, ext_struc);
+}
+
+/* Check the extension string for critical flag */
+static int v3_check_critical(char **value)
+{
+ char *p = *value;
+ if ((strlen(p) < 9) || strncmp(p, "critical,", 9)) return 0;
+ p+=9;
+ while(isspace((unsigned char)*p)) p++;
+ *value = p;
+ return 1;
+}
+
+/* Check extension string for generic extension and return the type */
+static int v3_check_generic(char **value)
+{
+ int gen_type = 0;
+ char *p = *value;
+ if ((strlen(p) >= 4) && !strncmp(p, "DER:", 4))
+ {
+ p+=4;
+ gen_type = 1;
+ }
+ else if ((strlen(p) >= 5) && !strncmp(p, "ASN1:", 5))
+ {
+ p+=5;
+ gen_type = 2;
+ }
+ else
+ return 0;
+
+ while (isspace((unsigned char)*p)) p++;
+ *value = p;
+ return gen_type;
+}
+
+/* Create a generic extension: for now just handle DER type */
+static X509_EXTENSION *v3_generic_extension(const char *ext, char *value,
+ int crit, int gen_type,
+ X509V3_CTX *ctx)
+ {
+ unsigned char *ext_der=NULL;
+ long ext_len;
+ ASN1_OBJECT *obj=NULL;
+ ASN1_OCTET_STRING *oct=NULL;
+ X509_EXTENSION *extension=NULL;
+ if (!(obj = OBJ_txt2obj(ext, 0)))
+ {
+ OPENSSL_PUT_ERROR(X509V3, v3_generic_extension, X509V3_R_EXTENSION_NAME_ERROR);
+ ERR_add_error_data(2, "name=", ext);
+ goto err;
+ }
+
+ if (gen_type == 1)
+ ext_der = string_to_hex(value, &ext_len);
+ else if (gen_type == 2)
+ ext_der = generic_asn1(value, ctx, &ext_len);
+
+ if (ext_der == NULL)
+ {
+ OPENSSL_PUT_ERROR(X509V3, v3_generic_extension, 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);
+ goto err;
+ }
+
+ oct->data = ext_der;
+ oct->length = ext_len;
+ ext_der = NULL;
+
+ extension = X509_EXTENSION_create_by_OBJ(NULL, obj, crit, oct);
+
+ err:
+ ASN1_OBJECT_free(obj);
+ M_ASN1_OCTET_STRING_free(oct);
+ if(ext_der) OPENSSL_free(ext_der);
+ return extension;
+
+ }
+
+static unsigned char *generic_asn1(char *value, X509V3_CTX *ctx, long *ext_len)
+ {
+ ASN1_TYPE *typ;
+ unsigned char *ext_der = NULL;
+ typ = ASN1_generate_v3(value, ctx);
+ if (typ == NULL)
+ return NULL;
+ *ext_len = i2d_ASN1_TYPE(typ, &ext_der);
+ ASN1_TYPE_free(typ);
+ return ext_der;
+ }
+
+/* This is the main function: add a bunch of extensions based on a config file
+ * section to an extension STACK.
+ */
+
+
+int X509V3_EXT_add_nconf_sk(CONF *conf, X509V3_CTX *ctx, char *section,
+ STACK_OF(X509_EXTENSION) **sk)
+ {
+ X509_EXTENSION *ext;
+ STACK_OF(CONF_VALUE) *nval;
+ CONF_VALUE *val;
+ size_t i;
+ if (!(nval = NCONF_get_section(conf, section))) return 0;
+ for (i = 0; i < sk_CONF_VALUE_num(nval); i++)
+ {
+ val = sk_CONF_VALUE_value(nval, i);
+ if (!(ext = X509V3_EXT_nconf(conf, ctx, val->name, val->value)))
+ return 0;
+ if (sk) X509v3_add_ext(sk, ext, -1);
+ X509_EXTENSION_free(ext);
+ }
+ return 1;
+ }
+
+/* Convenience functions to add extensions to a certificate, CRL and request */
+
+int X509V3_EXT_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section,
+ X509 *cert)
+ {
+ STACK_OF(X509_EXTENSION) **sk = NULL;
+ if (cert)
+ sk = &cert->cert_info->extensions;
+ return X509V3_EXT_add_nconf_sk(conf, ctx, section, sk);
+ }
+
+/* Same as above but for a CRL */
+
+int X509V3_EXT_CRL_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section,
+ X509_CRL *crl)
+ {
+ STACK_OF(X509_EXTENSION) **sk = NULL;
+ if (crl)
+ sk = &crl->crl->extensions;
+ return X509V3_EXT_add_nconf_sk(conf, ctx, section, sk);
+ }
+
+/* Add extensions to certificate request */
+
+int X509V3_EXT_REQ_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section,
+ X509_REQ *req)
+ {
+ STACK_OF(X509_EXTENSION) *extlist = NULL, **sk = NULL;
+ int i;
+ if (req)
+ sk = &extlist;
+ i = X509V3_EXT_add_nconf_sk(conf, ctx, section, sk);
+ if (!i || !sk)
+ return i;
+ i = X509_REQ_add_extensions(req, extlist);
+ sk_X509_EXTENSION_pop_free(extlist, X509_EXTENSION_free);
+ return i;
+ }
+
+/* Config database functions */
+
+char * X509V3_get_string(X509V3_CTX *ctx, char *name, char *section)
+ {
+ if(!ctx->db || !ctx->db_meth || !ctx->db_meth->get_string)
+ {
+ OPENSSL_PUT_ERROR(X509V3, X509V3_get_string, X509V3_R_OPERATION_NOT_DEFINED);
+ return NULL;
+ }
+ if (ctx->db_meth->get_string)
+ return ctx->db_meth->get_string(ctx->db, name, section);
+ return NULL;
+ }
+
+STACK_OF(CONF_VALUE) * X509V3_get_section(X509V3_CTX *ctx, char *section)
+ {
+ if(!ctx->db || !ctx->db_meth || !ctx->db_meth->get_section)
+ {
+ OPENSSL_PUT_ERROR(X509V3, X509V3_get_section, X509V3_R_OPERATION_NOT_DEFINED);
+ return NULL;
+ }
+ if (ctx->db_meth->get_section)
+ return ctx->db_meth->get_section(ctx->db, section);
+ return NULL;
+ }
+
+void X509V3_string_free(X509V3_CTX *ctx, char *str)
+ {
+ if (!str) return;
+ if (ctx->db_meth->free_string)
+ ctx->db_meth->free_string(ctx->db, str);
+ }
+
+void X509V3_section_free(X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *section)
+ {
+ if (!section) return;
+ if (ctx->db_meth->free_section)
+ ctx->db_meth->free_section(ctx->db, section);
+ }
+
+static char *nconf_get_string(void *db, char *section, char *value)
+ {
+ /* TODO(fork): this should return a const value. */
+ return (char *) NCONF_get_string(db, section, value);
+ }
+
+static STACK_OF(CONF_VALUE) *nconf_get_section(void *db, char *section)
+ {
+ return NCONF_get_section(db, section);
+ }
+
+static X509V3_CONF_METHOD nconf_method = {
+nconf_get_string,
+nconf_get_section,
+NULL,
+NULL
+};
+
+void X509V3_set_nconf(X509V3_CTX *ctx, CONF *conf)
+ {
+ ctx->db_meth = &nconf_method;
+ ctx->db = conf;
+ }
+
+void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subj, X509_REQ *req,
+ X509_CRL *crl, int flags)
+ {
+ ctx->issuer_cert = issuer;
+ ctx->subject_cert = subj;
+ ctx->crl = crl;
+ ctx->subject_req = req;
+ ctx->flags = flags;
+ }
+
+/* TODO(fork): remove */
+#if 0
+/* Old conf compatibility functions */
+
+X509_EXTENSION *X509V3_EXT_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx,
+ char *name, char *value)
+ {
+ CONF ctmp;
+ CONF_set_nconf(&ctmp, conf);
+ return X509V3_EXT_nconf(&ctmp, ctx, name, value);
+ }
+
+/* LHASH *conf: Config file */
+/* char *value: Value */
+X509_EXTENSION *X509V3_EXT_conf_nid(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx,
+ int ext_nid, char *value)
+ {
+ CONF ctmp;
+ CONF_set_nconf(&ctmp, conf);
+ return X509V3_EXT_nconf_nid(&ctmp, ctx, ext_nid, value);
+ }
+
+static char *conf_lhash_get_string(void *db, char *section, char *value)
+ {
+ return CONF_get_string(db, section, value);
+ }
+
+static STACK_OF(CONF_VALUE) *conf_lhash_get_section(void *db, char *section)
+ {
+ return CONF_get_section(db, section);
+ }
+
+static X509V3_CONF_METHOD conf_lhash_method = {
+conf_lhash_get_string,
+conf_lhash_get_section,
+NULL,
+NULL
+};
+
+void X509V3_set_conf_lhash(X509V3_CTX *ctx, LHASH_OF(CONF_VALUE) *lhash)
+ {
+ ctx->db_meth = &conf_lhash_method;
+ ctx->db = lhash;
+ }
+
+int X509V3_EXT_add_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx,
+ char *section, X509 *cert)
+ {
+ CONF ctmp;
+ CONF_set_nconf(&ctmp, conf);
+ return X509V3_EXT_add_nconf(&ctmp, ctx, section, cert);
+ }
+
+/* Same as above but for a CRL */
+
+int X509V3_EXT_CRL_add_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx,
+ char *section, X509_CRL *crl)
+ {
+ CONF ctmp;
+ CONF_set_nconf(&ctmp, conf);
+ return X509V3_EXT_CRL_add_nconf(&ctmp, ctx, section, crl);
+ }
+
+/* Add extensions to certificate request */
+
+int X509V3_EXT_REQ_add_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx,
+ char *section, X509_REQ *req)
+ {
+ CONF ctmp;
+ CONF_set_nconf(&ctmp, conf);
+ return X509V3_EXT_REQ_add_nconf(&ctmp, ctx, section, req);
+ }
+#endif
diff --git a/crypto/x509v3/v3_cpols.c b/crypto/x509v3/v3_cpols.c
new file mode 100644
index 0000000..b3d6fef
--- /dev/null
+++ b/crypto/x509v3/v3_cpols.c
@@ -0,0 +1,460 @@
+/* v3_cpols.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2004 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 <stdio.h>
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/conf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/stack.h>
+#include <openssl/x509v3.h>
+
+#include "pcy_int.h"
+
+/* Certificate policies extension support: this one is a bit complex... */
+
+static int i2r_certpol(X509V3_EXT_METHOD *method, STACK_OF(POLICYINFO) *pol, BIO *out, int indent);
+static STACK_OF(POLICYINFO) *r2i_certpol(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, char *value);
+static void print_qualifiers(BIO *out, STACK_OF(POLICYQUALINFO) *quals, int indent);
+static void print_notice(BIO *out, USERNOTICE *notice, int indent);
+static POLICYINFO *policy_section(X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *polstrs, int ia5org);
+static POLICYQUALINFO *notice_section(X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *unot, int ia5org);
+static int nref_nos(STACK_OF(ASN1_INTEGER) *nnums, STACK_OF(CONF_VALUE) *nos);
+
+const X509V3_EXT_METHOD v3_cpols = {
+NID_certificate_policies, 0,ASN1_ITEM_ref(CERTIFICATEPOLICIES),
+0,0,0,0,
+0,0,
+0,0,
+(X509V3_EXT_I2R)i2r_certpol,
+(X509V3_EXT_R2I)r2i_certpol,
+NULL
+};
+
+ASN1_ITEM_TEMPLATE(CERTIFICATEPOLICIES) =
+ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, CERTIFICATEPOLICIES, POLICYINFO)
+ASN1_ITEM_TEMPLATE_END(CERTIFICATEPOLICIES)
+
+IMPLEMENT_ASN1_FUNCTIONS(CERTIFICATEPOLICIES)
+
+ASN1_SEQUENCE(POLICYINFO) = {
+ ASN1_SIMPLE(POLICYINFO, policyid, ASN1_OBJECT),
+ ASN1_SEQUENCE_OF_OPT(POLICYINFO, qualifiers, POLICYQUALINFO)
+} ASN1_SEQUENCE_END(POLICYINFO)
+
+IMPLEMENT_ASN1_FUNCTIONS(POLICYINFO)
+
+ASN1_ADB_TEMPLATE(policydefault) = ASN1_SIMPLE(POLICYQUALINFO, d.other, ASN1_ANY);
+
+ASN1_ADB(POLICYQUALINFO) = {
+ ADB_ENTRY(NID_id_qt_cps, ASN1_SIMPLE(POLICYQUALINFO, d.cpsuri, ASN1_IA5STRING)),
+ ADB_ENTRY(NID_id_qt_unotice, ASN1_SIMPLE(POLICYQUALINFO, d.usernotice, USERNOTICE))
+} ASN1_ADB_END(POLICYQUALINFO, 0, pqualid, 0, &policydefault_tt, NULL);
+
+ASN1_SEQUENCE(POLICYQUALINFO) = {
+ ASN1_SIMPLE(POLICYQUALINFO, pqualid, ASN1_OBJECT),
+ ASN1_ADB_OBJECT(POLICYQUALINFO)
+} ASN1_SEQUENCE_END(POLICYQUALINFO)
+
+IMPLEMENT_ASN1_FUNCTIONS(POLICYQUALINFO)
+
+ASN1_SEQUENCE(USERNOTICE) = {
+ ASN1_OPT(USERNOTICE, noticeref, NOTICEREF),
+ ASN1_OPT(USERNOTICE, exptext, DISPLAYTEXT)
+} ASN1_SEQUENCE_END(USERNOTICE)
+
+IMPLEMENT_ASN1_FUNCTIONS(USERNOTICE)
+
+ASN1_SEQUENCE(NOTICEREF) = {
+ ASN1_SIMPLE(NOTICEREF, organization, DISPLAYTEXT),
+ ASN1_SEQUENCE_OF(NOTICEREF, noticenos, ASN1_INTEGER)
+} ASN1_SEQUENCE_END(NOTICEREF)
+
+IMPLEMENT_ASN1_FUNCTIONS(NOTICEREF)
+
+static STACK_OF(POLICYINFO) *r2i_certpol(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, char *value)
+{
+ STACK_OF(POLICYINFO) *pols = NULL;
+ char *pstr;
+ POLICYINFO *pol;
+ ASN1_OBJECT *pobj;
+ STACK_OF(CONF_VALUE) *vals;
+ CONF_VALUE *cnf;
+ size_t i;
+ int ia5org;
+ pols = sk_POLICYINFO_new_null();
+ if (pols == NULL) {
+ OPENSSL_PUT_ERROR(X509V3, r2i_certpol, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ vals = X509V3_parse_list(value);
+ if (vals == NULL) {
+ OPENSSL_PUT_ERROR(X509V3, r2i_certpol, 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);
+ X509V3_conf_err(cnf);
+ goto err;
+ }
+ pstr = cnf->name;
+ if(!strcmp(pstr,"ia5org")) {
+ ia5org = 1;
+ continue;
+ } else if(*pstr == '@') {
+ STACK_OF(CONF_VALUE) *polsect;
+ polsect = X509V3_get_section(ctx, pstr + 1);
+ if(!polsect) {
+ OPENSSL_PUT_ERROR(X509V3, r2i_certpol, X509V3_R_INVALID_SECTION);
+
+ X509V3_conf_err(cnf);
+ goto err;
+ }
+ pol = policy_section(ctx, polsect, ia5org);
+ X509V3_section_free(ctx, polsect);
+ if(!pol) goto err;
+ } else {
+ if(!(pobj = OBJ_txt2obj(cnf->name, 0))) {
+ OPENSSL_PUT_ERROR(X509V3, r2i_certpol, X509V3_R_INVALID_OBJECT_IDENTIFIER);
+ X509V3_conf_err(cnf);
+ goto err;
+ }
+ pol = POLICYINFO_new();
+ pol->policyid = pobj;
+ }
+ if (!sk_POLICYINFO_push(pols, pol)){
+ POLICYINFO_free(pol);
+ OPENSSL_PUT_ERROR(X509V3, r2i_certpol, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+ sk_CONF_VALUE_pop_free(vals, X509V3_conf_free);
+ return pols;
+ err:
+ sk_CONF_VALUE_pop_free(vals, X509V3_conf_free);
+ sk_POLICYINFO_pop_free(pols, POLICYINFO_free);
+ return NULL;
+}
+
+static POLICYINFO *policy_section(X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *polstrs, int ia5org)
+{
+ size_t i;
+ CONF_VALUE *cnf;
+ POLICYINFO *pol;
+ POLICYQUALINFO *qual;
+ if(!(pol = POLICYINFO_new())) goto merr;
+ for(i = 0; i < sk_CONF_VALUE_num(polstrs); i++) {
+ cnf = sk_CONF_VALUE_value(polstrs, i);
+ 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);
+ X509V3_conf_err(cnf);
+ goto err;
+ }
+ pol->policyid = pobj;
+
+ } else if(!name_cmp(cnf->name, "CPS")) {
+ if(!pol->qualifiers) pol->qualifiers =
+ sk_POLICYQUALINFO_new_null();
+ if(!(qual = POLICYQUALINFO_new())) goto merr;
+ if(!sk_POLICYQUALINFO_push(pol->qualifiers, qual))
+ goto merr;
+ /* TODO(fork): const correctness */
+ qual->pqualid = (ASN1_OBJECT*) OBJ_nid2obj(NID_id_qt_cps);
+ qual->d.cpsuri = M_ASN1_IA5STRING_new();
+ if(!ASN1_STRING_set(qual->d.cpsuri, cnf->value,
+ strlen(cnf->value))) goto merr;
+ } 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);
+ 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);
+
+ X509V3_conf_err(cnf);
+ goto err;
+ }
+ qual = notice_section(ctx, unot, ia5org);
+ X509V3_section_free(ctx, unot);
+ if(!qual) goto err;
+ if(!pol->qualifiers) pol->qualifiers =
+ sk_POLICYQUALINFO_new_null();
+ if(!sk_POLICYQUALINFO_push(pol->qualifiers, qual))
+ goto merr;
+ } else {
+ OPENSSL_PUT_ERROR(X509V3, policy_section, X509V3_R_INVALID_OPTION);
+
+ X509V3_conf_err(cnf);
+ goto err;
+ }
+ }
+ if(!pol->policyid) {
+ OPENSSL_PUT_ERROR(X509V3, policy_section, X509V3_R_NO_POLICY_IDENTIFIER);
+ goto err;
+ }
+
+ return pol;
+
+ merr:
+ OPENSSL_PUT_ERROR(X509V3, policy_section, ERR_R_MALLOC_FAILURE);
+
+ err:
+ POLICYINFO_free(pol);
+ return NULL;
+
+
+}
+
+static POLICYQUALINFO *notice_section(X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *unot, int ia5org)
+{
+ size_t i;
+ int ret;
+ CONF_VALUE *cnf;
+ USERNOTICE *not;
+ POLICYQUALINFO *qual;
+ if(!(qual = POLICYQUALINFO_new())) goto merr;
+ /* TODO(fork): const correctness */
+ qual->pqualid = (ASN1_OBJECT *) OBJ_nid2obj(NID_id_qt_unotice);
+ if(!(not = USERNOTICE_new())) goto merr;
+ qual->d.usernotice = not;
+ for(i = 0; i < sk_CONF_VALUE_num(unot); i++) {
+ cnf = sk_CONF_VALUE_value(unot, i);
+ if(!strcmp(cnf->name, "explicitText")) {
+ not->exptext = M_ASN1_VISIBLESTRING_new();
+ if(!ASN1_STRING_set(not->exptext, cnf->value,
+ strlen(cnf->value))) goto merr;
+ } else if(!strcmp(cnf->name, "organization")) {
+ NOTICEREF *nref;
+ if(!not->noticeref) {
+ if(!(nref = NOTICEREF_new())) goto merr;
+ not->noticeref = nref;
+ } else nref = not->noticeref;
+ if(ia5org) nref->organization->type = V_ASN1_IA5STRING;
+ else nref->organization->type = V_ASN1_VISIBLESTRING;
+ if(!ASN1_STRING_set(nref->organization, cnf->value,
+ strlen(cnf->value))) goto merr;
+ } else if(!strcmp(cnf->name, "noticeNumbers")) {
+ NOTICEREF *nref;
+ STACK_OF(CONF_VALUE) *nos;
+ if(!not->noticeref) {
+ if(!(nref = NOTICEREF_new())) goto merr;
+ not->noticeref = nref;
+ } 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);
+ X509V3_conf_err(cnf);
+ goto err;
+ }
+ ret = nref_nos(nref->noticenos, nos);
+ sk_CONF_VALUE_pop_free(nos, X509V3_conf_free);
+ if (!ret)
+ goto err;
+ } else {
+ OPENSSL_PUT_ERROR(X509V3, notice_section, X509V3_R_INVALID_OPTION);
+ X509V3_conf_err(cnf);
+ goto err;
+ }
+ }
+
+ if(not->noticeref &&
+ (!not->noticeref->noticenos || !not->noticeref->organization)) {
+ OPENSSL_PUT_ERROR(X509V3, notice_section, X509V3_R_NEED_ORGANIZATION_AND_NUMBERS);
+ goto err;
+ }
+
+ return qual;
+
+ merr:
+ OPENSSL_PUT_ERROR(X509V3, notice_section, ERR_R_MALLOC_FAILURE);
+
+ err:
+ POLICYQUALINFO_free(qual);
+ return NULL;
+}
+
+static int nref_nos(STACK_OF(ASN1_INTEGER) *nnums, STACK_OF(CONF_VALUE) *nos)
+{
+ CONF_VALUE *cnf;
+ ASN1_INTEGER *aint;
+
+ size_t i;
+
+ 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);
+ goto err;
+ }
+ if(!sk_ASN1_INTEGER_push(nnums, aint)) goto merr;
+ }
+ return 1;
+
+ merr:
+ OPENSSL_PUT_ERROR(X509V3, nref_nos, ERR_R_MALLOC_FAILURE);
+
+ err:
+ sk_ASN1_INTEGER_pop_free(nnums, ASN1_STRING_free);
+ return 0;
+}
+
+
+static int i2r_certpol(X509V3_EXT_METHOD *method, STACK_OF(POLICYINFO) *pol,
+ BIO *out, int indent)
+{
+ size_t i;
+ POLICYINFO *pinfo;
+ /* First print out the policy OIDs */
+ for(i = 0; i < sk_POLICYINFO_num(pol); i++) {
+ pinfo = sk_POLICYINFO_value(pol, i);
+ BIO_printf(out, "%*sPolicy: ", indent, "");
+ i2a_ASN1_OBJECT(out, pinfo->policyid);
+ BIO_puts(out, "\n");
+ if(pinfo->qualifiers)
+ print_qualifiers(out, pinfo->qualifiers, indent + 2);
+ }
+ return 1;
+}
+
+static void print_qualifiers(BIO *out, STACK_OF(POLICYQUALINFO) *quals,
+ int indent)
+{
+ POLICYQUALINFO *qualinfo;
+ size_t i;
+ for(i = 0; i < sk_POLICYQUALINFO_num(quals); i++) {
+ qualinfo = sk_POLICYQUALINFO_value(quals, i);
+ switch(OBJ_obj2nid(qualinfo->pqualid))
+ {
+ case NID_id_qt_cps:
+ BIO_printf(out, "%*sCPS: %s\n", indent, "",
+ qualinfo->d.cpsuri->data);
+ break;
+
+ case NID_id_qt_unotice:
+ BIO_printf(out, "%*sUser Notice:\n", indent, "");
+ print_notice(out, qualinfo->d.usernotice, indent + 2);
+ break;
+
+ default:
+ BIO_printf(out, "%*sUnknown Qualifier: ",
+ indent + 2, "");
+
+ i2a_ASN1_OBJECT(out, qualinfo->pqualid);
+ BIO_puts(out, "\n");
+ break;
+ }
+ }
+}
+
+static void print_notice(BIO *out, USERNOTICE *notice, int indent)
+{
+ size_t i;
+ if(notice->noticeref) {
+ NOTICEREF *ref;
+ ref = notice->noticeref;
+ BIO_printf(out, "%*sOrganization: %s\n", indent, "",
+ ref->organization->data);
+ BIO_printf(out, "%*sNumber%s: ", indent, "",
+ sk_ASN1_INTEGER_num(ref->noticenos) > 1 ? "s" : "");
+ for(i = 0; i < sk_ASN1_INTEGER_num(ref->noticenos); i++) {
+ ASN1_INTEGER *num;
+ char *tmp;
+ num = sk_ASN1_INTEGER_value(ref->noticenos, i);
+ if(i) BIO_puts(out, ", ");
+ tmp = i2s_ASN1_INTEGER(NULL, num);
+ BIO_puts(out, tmp);
+ OPENSSL_free(tmp);
+ }
+ BIO_puts(out, "\n");
+ }
+ if(notice->exptext)
+ BIO_printf(out, "%*sExplicit Text: %s\n", indent, "",
+ notice->exptext->data);
+}
+
+void X509_POLICY_NODE_print(BIO *out, X509_POLICY_NODE *node, int indent)
+ {
+ const X509_POLICY_DATA *dat = node->data;
+
+ BIO_printf(out, "%*sPolicy: ", indent, "");
+
+ i2a_ASN1_OBJECT(out, dat->valid_policy);
+ BIO_puts(out, "\n");
+ BIO_printf(out, "%*s%s\n", indent + 2, "",
+ node_data_critical(dat) ? "Critical" : "Non Critical");
+ if (dat->qualifier_set)
+ print_qualifiers(out, dat->qualifier_set, indent + 2);
+ else
+ BIO_printf(out, "%*sNo Qualifiers\n", indent + 2, "");
+ }
diff --git a/crypto/x509v3/v3_crld.c b/crypto/x509v3/v3_crld.c
new file mode 100644
index 0000000..e2bd2ad
--- /dev/null
+++ b/crypto/x509v3/v3_crld.c
@@ -0,0 +1,615 @@
+/* v3_crld.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2008 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 <stdio.h>
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/conf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509v3.h>
+
+
+static void *v2i_crld(const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval);
+static int i2r_crldp(const X509V3_EXT_METHOD *method, void *pcrldp, BIO *out,
+ int indent);
+
+const X509V3_EXT_METHOD v3_crld =
+ {
+ NID_crl_distribution_points, 0, ASN1_ITEM_ref(CRL_DIST_POINTS),
+ 0,0,0,0,
+ 0,0,
+ 0,
+ v2i_crld,
+ i2r_crldp,0,
+ NULL
+ };
+
+const X509V3_EXT_METHOD v3_freshest_crl =
+ {
+ NID_freshest_crl, 0, ASN1_ITEM_ref(CRL_DIST_POINTS),
+ 0,0,0,0,
+ 0,0,
+ 0,
+ v2i_crld,
+ i2r_crldp,0,
+ NULL
+ };
+
+static STACK_OF(GENERAL_NAME) *gnames_from_sectname(X509V3_CTX *ctx, char *sect)
+ {
+ STACK_OF(CONF_VALUE) *gnsect;
+ STACK_OF(GENERAL_NAME) *gens;
+ if (*sect == '@')
+ gnsect = X509V3_get_section(ctx, sect + 1);
+ else
+ gnsect = X509V3_parse_list(sect);
+ if (!gnsect)
+ {
+ OPENSSL_PUT_ERROR(X509V3, gnames_from_sectname, X509V3_R_SECTION_NOT_FOUND);
+ return NULL;
+ }
+ gens = v2i_GENERAL_NAMES(NULL, ctx, gnsect);
+ if (*sect == '@')
+ X509V3_section_free(ctx, gnsect);
+ else
+ sk_CONF_VALUE_pop_free(gnsect, X509V3_conf_free);
+ return gens;
+ }
+
+static int set_dist_point_name(DIST_POINT_NAME **pdp, X509V3_CTX *ctx,
+ CONF_VALUE *cnf)
+ {
+ STACK_OF(GENERAL_NAME) *fnm = NULL;
+ STACK_OF(X509_NAME_ENTRY) *rnm = NULL;
+ if (!strncmp(cnf->name, "fullname", 9))
+ {
+ fnm = gnames_from_sectname(ctx, cnf->value);
+ if (!fnm)
+ goto err;
+ }
+ else if (!strcmp(cnf->name, "relativename"))
+ {
+ int ret;
+ STACK_OF(CONF_VALUE) *dnsect;
+ X509_NAME *nm;
+ nm = X509_NAME_new();
+ if (!nm)
+ return -1;
+ dnsect = X509V3_get_section(ctx, cnf->value);
+ if (!dnsect)
+ {
+ OPENSSL_PUT_ERROR(X509V3, set_dist_point_name, X509V3_R_SECTION_NOT_FOUND);
+ return -1;
+ }
+ ret = X509V3_NAME_from_section(nm, dnsect, MBSTRING_ASC);
+ X509V3_section_free(ctx, dnsect);
+ rnm = nm->entries;
+ nm->entries = NULL;
+ X509_NAME_free(nm);
+ if (!ret || sk_X509_NAME_ENTRY_num(rnm) <= 0)
+ goto err;
+ /* Since its a name fragment can't have more than one
+ * RDNSequence
+ */
+ 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);
+ goto err;
+ }
+ }
+ else
+ return 0;
+
+ if (*pdp)
+ {
+ OPENSSL_PUT_ERROR(X509V3, set_dist_point_name, X509V3_R_DISTPOINT_ALREADY_SET);
+ goto err;
+ }
+
+ *pdp = DIST_POINT_NAME_new();
+ if (!*pdp)
+ goto err;
+ if (fnm)
+ {
+ (*pdp)->type = 0;
+ (*pdp)->name.fullname = fnm;
+ }
+ else
+ {
+ (*pdp)->type = 1;
+ (*pdp)->name.relativename = rnm;
+ }
+
+ return 1;
+
+ err:
+ if (fnm)
+ sk_GENERAL_NAME_pop_free(fnm, GENERAL_NAME_free);
+ if (rnm)
+ sk_X509_NAME_ENTRY_pop_free(rnm, X509_NAME_ENTRY_free);
+ return -1;
+ }
+
+static const BIT_STRING_BITNAME reason_flags[] = {
+{0, "Unused", "unused"},
+{1, "Key Compromise", "keyCompromise"},
+{2, "CA Compromise", "CACompromise"},
+{3, "Affiliation Changed", "affiliationChanged"},
+{4, "Superseded", "superseded"},
+{5, "Cessation Of Operation", "cessationOfOperation"},
+{6, "Certificate Hold", "certificateHold"},
+{7, "Privilege Withdrawn", "privilegeWithdrawn"},
+{8, "AA Compromise", "AACompromise"},
+{-1, NULL, NULL}
+};
+
+static int set_reasons(ASN1_BIT_STRING **preas, char *value)
+ {
+ STACK_OF(CONF_VALUE) *rsk = NULL;
+ const BIT_STRING_BITNAME *pbn;
+ const char *bnam;
+ size_t i;
+ int ret = 0;
+ rsk = X509V3_parse_list(value);
+ if (!rsk)
+ return 0;
+ if (*preas)
+ return 0;
+ for (i = 0; i < sk_CONF_VALUE_num(rsk); i++)
+ {
+ bnam = sk_CONF_VALUE_value(rsk, i)->name;
+ if (!*preas)
+ {
+ *preas = ASN1_BIT_STRING_new();
+ if (!*preas)
+ goto err;
+ }
+ for (pbn = reason_flags; pbn->lname; pbn++)
+ {
+ if (!strcmp(pbn->sname, bnam))
+ {
+ if (!ASN1_BIT_STRING_set_bit(*preas,
+ pbn->bitnum, 1))
+ goto err;
+ break;
+ }
+ }
+ if (!pbn->lname)
+ goto err;
+ }
+ ret = 1;
+
+ err:
+ sk_CONF_VALUE_pop_free(rsk, X509V3_conf_free);
+ return ret;
+ }
+
+static int print_reasons(BIO *out, const char *rname,
+ ASN1_BIT_STRING *rflags, int indent)
+ {
+ int first = 1;
+ const BIT_STRING_BITNAME *pbn;
+ BIO_printf(out, "%*s%s:\n%*s", indent, "", rname, indent + 2, "");
+ for (pbn = reason_flags; pbn->lname; pbn++)
+ {
+ if (ASN1_BIT_STRING_get_bit(rflags, pbn->bitnum))
+ {
+ if (first)
+ first = 0;
+ else
+ BIO_puts(out, ", ");
+ BIO_puts(out, pbn->lname);
+ }
+ }
+ if (first)
+ BIO_puts(out, "<EMPTY>\n");
+ else
+ BIO_puts(out, "\n");
+ return 1;
+ }
+
+static DIST_POINT *crldp_from_section(X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *nval)
+ {
+ size_t i;
+ CONF_VALUE *cnf;
+ DIST_POINT *point = NULL;
+ point = DIST_POINT_new();
+ if (!point)
+ goto err;
+ for(i = 0; i < sk_CONF_VALUE_num(nval); i++)
+ {
+ int ret;
+ cnf = sk_CONF_VALUE_value(nval, i);
+ ret = set_dist_point_name(&point->distpoint, ctx, cnf);
+ if (ret > 0)
+ continue;
+ if (ret < 0)
+ goto err;
+ if (!strcmp(cnf->name, "reasons"))
+ {
+ if (!set_reasons(&point->reasons, cnf->value))
+ goto err;
+ }
+ else if (!strcmp(cnf->name, "CRLissuer"))
+ {
+ point->CRLissuer =
+ gnames_from_sectname(ctx, cnf->value);
+ if (!point->CRLissuer)
+ goto err;
+ }
+ }
+
+ return point;
+
+
+ err:
+ if (point)
+ DIST_POINT_free(point);
+ return NULL;
+ }
+
+static void *v2i_crld(const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
+ {
+ STACK_OF(DIST_POINT) *crld = NULL;
+ GENERAL_NAMES *gens = NULL;
+ GENERAL_NAME *gen = NULL;
+ CONF_VALUE *cnf;
+ size_t i;
+ if(!(crld = sk_DIST_POINT_new_null())) goto merr;
+ for(i = 0; i < sk_CONF_VALUE_num(nval); i++) {
+ DIST_POINT *point;
+ cnf = sk_CONF_VALUE_value(nval, i);
+ if (!cnf->value)
+ {
+ STACK_OF(CONF_VALUE) *dpsect;
+ dpsect = X509V3_get_section(ctx, cnf->name);
+ if (!dpsect)
+ goto err;
+ point = crldp_from_section(ctx, dpsect);
+ X509V3_section_free(ctx, dpsect);
+ if (!point)
+ goto err;
+ if(!sk_DIST_POINT_push(crld, point))
+ {
+ DIST_POINT_free(point);
+ goto merr;
+ }
+ }
+ else
+ {
+ if(!(gen = v2i_GENERAL_NAME(method, ctx, cnf)))
+ goto err;
+ if(!(gens = GENERAL_NAMES_new()))
+ goto merr;
+ if(!sk_GENERAL_NAME_push(gens, gen))
+ goto merr;
+ gen = NULL;
+ if(!(point = DIST_POINT_new()))
+ goto merr;
+ if(!sk_DIST_POINT_push(crld, point))
+ {
+ DIST_POINT_free(point);
+ goto merr;
+ }
+ if(!(point->distpoint = DIST_POINT_NAME_new()))
+ goto merr;
+ point->distpoint->name.fullname = gens;
+ point->distpoint->type = 0;
+ gens = NULL;
+ }
+ }
+ return crld;
+
+ merr:
+ OPENSSL_PUT_ERROR(X509V3, v2i_crld, ERR_R_MALLOC_FAILURE);
+ err:
+ GENERAL_NAME_free(gen);
+ GENERAL_NAMES_free(gens);
+ sk_DIST_POINT_pop_free(crld, DIST_POINT_free);
+ return NULL;
+}
+
+IMPLEMENT_ASN1_SET_OF(DIST_POINT)
+
+static int dpn_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
+ void *exarg)
+ {
+ DIST_POINT_NAME *dpn = (DIST_POINT_NAME *)*pval;
+
+ switch(operation)
+ {
+ case ASN1_OP_NEW_POST:
+ dpn->dpname = NULL;
+ break;
+
+ case ASN1_OP_FREE_POST:
+ if (dpn->dpname)
+ X509_NAME_free(dpn->dpname);
+ break;
+ }
+ return 1;
+ }
+
+
+ASN1_CHOICE_cb(DIST_POINT_NAME, dpn_cb) = {
+ ASN1_IMP_SEQUENCE_OF(DIST_POINT_NAME, name.fullname, GENERAL_NAME, 0),
+ ASN1_IMP_SET_OF(DIST_POINT_NAME, name.relativename, X509_NAME_ENTRY, 1)
+} ASN1_CHOICE_END_cb(DIST_POINT_NAME, DIST_POINT_NAME, type)
+
+
+IMPLEMENT_ASN1_FUNCTIONS(DIST_POINT_NAME)
+
+ASN1_SEQUENCE(DIST_POINT) = {
+ ASN1_EXP_OPT(DIST_POINT, distpoint, DIST_POINT_NAME, 0),
+ ASN1_IMP_OPT(DIST_POINT, reasons, ASN1_BIT_STRING, 1),
+ ASN1_IMP_SEQUENCE_OF_OPT(DIST_POINT, CRLissuer, GENERAL_NAME, 2)
+} ASN1_SEQUENCE_END(DIST_POINT)
+
+IMPLEMENT_ASN1_FUNCTIONS(DIST_POINT)
+
+ASN1_ITEM_TEMPLATE(CRL_DIST_POINTS) =
+ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, CRLDistributionPoints, DIST_POINT)
+ASN1_ITEM_TEMPLATE_END(CRL_DIST_POINTS)
+
+IMPLEMENT_ASN1_FUNCTIONS(CRL_DIST_POINTS)
+
+ASN1_SEQUENCE(ISSUING_DIST_POINT) = {
+ ASN1_EXP_OPT(ISSUING_DIST_POINT, distpoint, DIST_POINT_NAME, 0),
+ ASN1_IMP_OPT(ISSUING_DIST_POINT, onlyuser, ASN1_FBOOLEAN, 1),
+ ASN1_IMP_OPT(ISSUING_DIST_POINT, onlyCA, ASN1_FBOOLEAN, 2),
+ ASN1_IMP_OPT(ISSUING_DIST_POINT, onlysomereasons, ASN1_BIT_STRING, 3),
+ ASN1_IMP_OPT(ISSUING_DIST_POINT, indirectCRL, ASN1_FBOOLEAN, 4),
+ ASN1_IMP_OPT(ISSUING_DIST_POINT, onlyattr, ASN1_FBOOLEAN, 5)
+} ASN1_SEQUENCE_END(ISSUING_DIST_POINT)
+
+IMPLEMENT_ASN1_FUNCTIONS(ISSUING_DIST_POINT)
+
+static int i2r_idp(const X509V3_EXT_METHOD *method, void *pidp, BIO *out,
+ int indent);
+static void *v2i_idp(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *nval);
+
+const X509V3_EXT_METHOD v3_idp =
+ {
+ NID_issuing_distribution_point, X509V3_EXT_MULTILINE,
+ ASN1_ITEM_ref(ISSUING_DIST_POINT),
+ 0,0,0,0,
+ 0,0,
+ 0,
+ v2i_idp,
+ i2r_idp,0,
+ NULL
+ };
+
+static void *v2i_idp(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *nval)
+ {
+ ISSUING_DIST_POINT *idp = NULL;
+ CONF_VALUE *cnf;
+ char *name, *val;
+ size_t i;
+ int ret;
+ idp = ISSUING_DIST_POINT_new();
+ if (!idp)
+ goto merr;
+ for(i = 0; i < sk_CONF_VALUE_num(nval); i++)
+ {
+ cnf = sk_CONF_VALUE_value(nval, i);
+ name = cnf->name;
+ val = cnf->value;
+ ret = set_dist_point_name(&idp->distpoint, ctx, cnf);
+ if (ret > 0)
+ continue;
+ if (ret < 0)
+ goto err;
+ if (!strcmp(name, "onlyuser"))
+ {
+ if (!X509V3_get_value_bool(cnf, &idp->onlyuser))
+ goto err;
+ }
+ else if (!strcmp(name, "onlyCA"))
+ {
+ if (!X509V3_get_value_bool(cnf, &idp->onlyCA))
+ goto err;
+ }
+ else if (!strcmp(name, "onlyAA"))
+ {
+ if (!X509V3_get_value_bool(cnf, &idp->onlyattr))
+ goto err;
+ }
+ else if (!strcmp(name, "indirectCRL"))
+ {
+ if (!X509V3_get_value_bool(cnf, &idp->indirectCRL))
+ goto err;
+ }
+ else if (!strcmp(name, "onlysomereasons"))
+ {
+ if (!set_reasons(&idp->onlysomereasons, val))
+ goto err;
+ }
+ else
+ {
+ OPENSSL_PUT_ERROR(X509V3, v2i_idp, X509V3_R_INVALID_NAME);
+ X509V3_conf_err(cnf);
+ goto err;
+ }
+ }
+ return idp;
+
+ merr:
+ OPENSSL_PUT_ERROR(X509V3, v2i_idp, ERR_R_MALLOC_FAILURE);
+ err:
+ ISSUING_DIST_POINT_free(idp);
+ return NULL;
+ }
+
+static int print_gens(BIO *out, STACK_OF(GENERAL_NAME) *gens, int indent)
+ {
+ size_t i;
+ for (i = 0; i < sk_GENERAL_NAME_num(gens); i++)
+ {
+ BIO_printf(out, "%*s", indent + 2, "");
+ GENERAL_NAME_print(out, sk_GENERAL_NAME_value(gens, i));
+ BIO_puts(out, "\n");
+ }
+ return 1;
+ }
+
+static int print_distpoint(BIO *out, DIST_POINT_NAME *dpn, int indent)
+ {
+ if (dpn->type == 0)
+ {
+ BIO_printf(out, "%*sFull Name:\n", indent, "");
+ print_gens(out, dpn->name.fullname, indent);
+ }
+ else
+ {
+ X509_NAME ntmp;
+ ntmp.entries = dpn->name.relativename;
+ BIO_printf(out, "%*sRelative Name:\n%*s",
+ indent, "", indent + 2, "");
+ X509_NAME_print_ex(out, &ntmp, 0, XN_FLAG_ONELINE);
+ BIO_puts(out, "\n");
+ }
+ return 1;
+ }
+
+static int i2r_idp(const X509V3_EXT_METHOD *method, void *pidp, BIO *out,
+ int indent)
+ {
+ ISSUING_DIST_POINT *idp = pidp;
+ if (idp->distpoint)
+ print_distpoint(out, idp->distpoint, indent);
+ if (idp->onlyuser > 0)
+ BIO_printf(out, "%*sOnly User Certificates\n", indent, "");
+ if (idp->onlyCA > 0)
+ BIO_printf(out, "%*sOnly CA Certificates\n", indent, "");
+ if (idp->indirectCRL > 0)
+ BIO_printf(out, "%*sIndirect CRL\n", indent, "");
+ if (idp->onlysomereasons)
+ print_reasons(out, "Only Some Reasons",
+ idp->onlysomereasons, indent);
+ if (idp->onlyattr > 0)
+ BIO_printf(out, "%*sOnly Attribute Certificates\n", indent, "");
+ if (!idp->distpoint && (idp->onlyuser <= 0) && (idp->onlyCA <= 0)
+ && (idp->indirectCRL <= 0) && !idp->onlysomereasons
+ && (idp->onlyattr <= 0))
+ BIO_printf(out, "%*s<EMPTY>\n", indent, "");
+
+ return 1;
+ }
+
+static int i2r_crldp(const X509V3_EXT_METHOD *method, void *pcrldp, BIO *out,
+ int indent)
+ {
+ STACK_OF(DIST_POINT) *crld = pcrldp;
+ DIST_POINT *point;
+ size_t i;
+ for(i = 0; i < sk_DIST_POINT_num(crld); i++)
+ {
+ BIO_puts(out, "\n");
+ point = sk_DIST_POINT_value(crld, i);
+ if(point->distpoint)
+ print_distpoint(out, point->distpoint, indent);
+ if(point->reasons)
+ print_reasons(out, "Reasons", point->reasons,
+ indent);
+ if(point->CRLissuer)
+ {
+ BIO_printf(out, "%*sCRL Issuer:\n", indent, "");
+ print_gens(out, point->CRLissuer, indent);
+ }
+ }
+ return 1;
+ }
+
+int DIST_POINT_set_dpname(DIST_POINT_NAME *dpn, X509_NAME *iname)
+ {
+ size_t i;
+ STACK_OF(X509_NAME_ENTRY) *frag;
+ X509_NAME_ENTRY *ne;
+ if (!dpn || (dpn->type != 1))
+ return 1;
+ frag = dpn->name.relativename;
+ dpn->dpname = X509_NAME_dup(iname);
+ if (!dpn->dpname)
+ return 0;
+ for (i = 0; i < sk_X509_NAME_ENTRY_num(frag); i++)
+ {
+ ne = sk_X509_NAME_ENTRY_value(frag, i);
+ if (!X509_NAME_add_entry(dpn->dpname, ne, -1, i ? 0 : 1))
+ {
+ X509_NAME_free(dpn->dpname);
+ dpn->dpname = NULL;
+ return 0;
+ }
+ }
+ /* generate cached encoding of name */
+ if (i2d_X509_NAME(dpn->dpname, NULL) < 0)
+ {
+ X509_NAME_free(dpn->dpname);
+ dpn->dpname = NULL;
+ return 0;
+ }
+ return 1;
+ }
diff --git a/crypto/x509v3/v3_enum.c b/crypto/x509v3/v3_enum.c
new file mode 100644
index 0000000..d6a1b8b
--- /dev/null
+++ b/crypto/x509v3/v3_enum.c
@@ -0,0 +1,98 @@
+/* v3_enum.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999 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 <stdio.h>
+
+#include <openssl/buf.h>
+#include <openssl/obj.h>
+#include <openssl/x509v3.h>
+
+
+static ENUMERATED_NAMES crl_reasons[] = {
+{CRL_REASON_UNSPECIFIED, "Unspecified", "unspecified"},
+{CRL_REASON_KEY_COMPROMISE, "Key Compromise", "keyCompromise"},
+{CRL_REASON_CA_COMPROMISE, "CA Compromise", "CACompromise"},
+{CRL_REASON_AFFILIATION_CHANGED, "Affiliation Changed", "affiliationChanged"},
+{CRL_REASON_SUPERSEDED, "Superseded", "superseded"},
+{CRL_REASON_CESSATION_OF_OPERATION,
+ "Cessation Of Operation", "cessationOfOperation"},
+{CRL_REASON_CERTIFICATE_HOLD, "Certificate Hold", "certificateHold"},
+{CRL_REASON_REMOVE_FROM_CRL, "Remove From CRL", "removeFromCRL"},
+{CRL_REASON_PRIVILEGE_WITHDRAWN, "Privilege Withdrawn", "privilegeWithdrawn"},
+{CRL_REASON_AA_COMPROMISE, "AA Compromise", "AACompromise"},
+{-1, NULL, NULL}
+};
+
+const X509V3_EXT_METHOD v3_crl_reason = {
+NID_crl_reason, 0, ASN1_ITEM_ref(ASN1_ENUMERATED),
+0,0,0,0,
+(X509V3_EXT_I2S)i2s_ASN1_ENUMERATED_TABLE,
+0,
+0,0,0,0,
+crl_reasons};
+
+
+char *i2s_ASN1_ENUMERATED_TABLE(X509V3_EXT_METHOD *method,
+ ASN1_ENUMERATED *e)
+{
+ ENUMERATED_NAMES *enam;
+ long strval;
+ strval = ASN1_ENUMERATED_get(e);
+ for(enam = method->usr_data; enam->lname; enam++) {
+ if(strval == enam->bitnum) return BUF_strdup(enam->lname);
+ }
+ return i2s_ASN1_ENUMERATED(method, e);
+}
diff --git a/crypto/x509v3/v3_extku.c b/crypto/x509v3/v3_extku.c
new file mode 100644
index 0000000..f4b8af8
--- /dev/null
+++ b/crypto/x509v3/v3_extku.c
@@ -0,0 +1,145 @@
+/* v3_extku.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999 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 <stdio.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/conf.h>
+#include <openssl/err.h>
+#include <openssl/obj.h>
+#include <openssl/x509v3.h>
+
+
+static void *v2i_EXTENDED_KEY_USAGE(const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *nval);
+static STACK_OF(CONF_VALUE) *i2v_EXTENDED_KEY_USAGE(const X509V3_EXT_METHOD *method,
+ void *eku, STACK_OF(CONF_VALUE) *extlist);
+
+const X509V3_EXT_METHOD v3_ext_ku = {
+ NID_ext_key_usage, 0,
+ ASN1_ITEM_ref(EXTENDED_KEY_USAGE),
+ 0,0,0,0,
+ 0,0,
+ i2v_EXTENDED_KEY_USAGE,
+ v2i_EXTENDED_KEY_USAGE,
+ 0,0,
+ NULL
+};
+
+/* NB OCSP acceptable responses also is a SEQUENCE OF OBJECT */
+const X509V3_EXT_METHOD v3_ocsp_accresp = {
+ NID_id_pkix_OCSP_acceptableResponses, 0,
+ ASN1_ITEM_ref(EXTENDED_KEY_USAGE),
+ 0,0,0,0,
+ 0,0,
+ i2v_EXTENDED_KEY_USAGE,
+ v2i_EXTENDED_KEY_USAGE,
+ 0,0,
+ NULL
+};
+
+ASN1_ITEM_TEMPLATE(EXTENDED_KEY_USAGE) =
+ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, EXTENDED_KEY_USAGE, ASN1_OBJECT)
+ASN1_ITEM_TEMPLATE_END(EXTENDED_KEY_USAGE)
+
+IMPLEMENT_ASN1_FUNCTIONS(EXTENDED_KEY_USAGE)
+
+static STACK_OF(CONF_VALUE) *
+ i2v_EXTENDED_KEY_USAGE(const X509V3_EXT_METHOD *method, void *a,
+ STACK_OF(CONF_VALUE) *ext_list)
+{
+ EXTENDED_KEY_USAGE *eku = a;
+ size_t i;
+ ASN1_OBJECT *obj;
+ char obj_tmp[80];
+ for(i = 0; i < sk_ASN1_OBJECT_num(eku); i++) {
+ obj = sk_ASN1_OBJECT_value(eku, i);
+ i2t_ASN1_OBJECT(obj_tmp, 80, obj);
+ X509V3_add_value(NULL, obj_tmp, &ext_list);
+ }
+ return ext_list;
+}
+
+static void *v2i_EXTENDED_KEY_USAGE(const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
+{
+ EXTENDED_KEY_USAGE *extku;
+ char *extval;
+ ASN1_OBJECT *objtmp;
+ CONF_VALUE *val;
+ size_t i;
+
+ if(!(extku = sk_ASN1_OBJECT_new_null())) {
+ OPENSSL_PUT_ERROR(X509V3, v2i_EXTENDED_KEY_USAGE, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ for(i = 0; i < sk_CONF_VALUE_num(nval); i++) {
+ val = sk_CONF_VALUE_value(nval, i);
+ if(val->value) extval = val->value;
+ 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);
+ X509V3_conf_err(val);
+ return NULL;
+ }
+ sk_ASN1_OBJECT_push(extku, objtmp);
+ }
+ return extku;
+}
diff --git a/crypto/x509v3/v3_genn.c b/crypto/x509v3/v3_genn.c
new file mode 100644
index 0000000..8b0a68d
--- /dev/null
+++ b/crypto/x509v3/v3_genn.c
@@ -0,0 +1,252 @@
+/* v3_genn.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2008 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 <stdio.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/conf.h>
+#include <openssl/obj.h>
+#include <openssl/x509v3.h>
+
+
+ASN1_SEQUENCE(OTHERNAME) = {
+ ASN1_SIMPLE(OTHERNAME, type_id, ASN1_OBJECT),
+ /* Maybe have a true ANY DEFINED BY later */
+ ASN1_EXP(OTHERNAME, value, ASN1_ANY, 0)
+} ASN1_SEQUENCE_END(OTHERNAME)
+
+IMPLEMENT_ASN1_FUNCTIONS(OTHERNAME)
+
+ASN1_SEQUENCE(EDIPARTYNAME) = {
+ ASN1_IMP_OPT(EDIPARTYNAME, nameAssigner, DIRECTORYSTRING, 0),
+ ASN1_IMP_OPT(EDIPARTYNAME, partyName, DIRECTORYSTRING, 1)
+} ASN1_SEQUENCE_END(EDIPARTYNAME)
+
+IMPLEMENT_ASN1_FUNCTIONS(EDIPARTYNAME)
+
+ASN1_CHOICE(GENERAL_NAME) = {
+ ASN1_IMP(GENERAL_NAME, d.otherName, OTHERNAME, GEN_OTHERNAME),
+ ASN1_IMP(GENERAL_NAME, d.rfc822Name, ASN1_IA5STRING, GEN_EMAIL),
+ ASN1_IMP(GENERAL_NAME, d.dNSName, ASN1_IA5STRING, GEN_DNS),
+ /* Don't decode this */
+ ASN1_IMP(GENERAL_NAME, d.x400Address, ASN1_SEQUENCE, GEN_X400),
+ /* X509_NAME is a CHOICE type so use EXPLICIT */
+ ASN1_EXP(GENERAL_NAME, d.directoryName, X509_NAME, GEN_DIRNAME),
+ ASN1_IMP(GENERAL_NAME, d.ediPartyName, EDIPARTYNAME, GEN_EDIPARTY),
+ ASN1_IMP(GENERAL_NAME, d.uniformResourceIdentifier, ASN1_IA5STRING, GEN_URI),
+ ASN1_IMP(GENERAL_NAME, d.iPAddress, ASN1_OCTET_STRING, GEN_IPADD),
+ ASN1_IMP(GENERAL_NAME, d.registeredID, ASN1_OBJECT, GEN_RID)
+} ASN1_CHOICE_END(GENERAL_NAME)
+
+IMPLEMENT_ASN1_FUNCTIONS(GENERAL_NAME)
+
+ASN1_ITEM_TEMPLATE(GENERAL_NAMES) =
+ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, GeneralNames, GENERAL_NAME)
+ASN1_ITEM_TEMPLATE_END(GENERAL_NAMES)
+
+IMPLEMENT_ASN1_FUNCTIONS(GENERAL_NAMES)
+
+GENERAL_NAME *GENERAL_NAME_dup(GENERAL_NAME *a)
+ {
+ return (GENERAL_NAME *) ASN1_dup((i2d_of_void *) i2d_GENERAL_NAME,
+ (d2i_of_void *) d2i_GENERAL_NAME,
+ (char *) a);
+ }
+
+/* Returns 0 if they are equal, != 0 otherwise. */
+int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b)
+ {
+ int result = -1;
+
+ if (!a || !b || a->type != b->type) return -1;
+ switch(a->type)
+ {
+ case GEN_X400:
+ case GEN_EDIPARTY:
+ result = ASN1_TYPE_cmp(a->d.other, b->d.other);
+ break;
+
+ case GEN_OTHERNAME:
+ result = OTHERNAME_cmp(a->d.otherName, b->d.otherName);
+ break;
+
+ case GEN_EMAIL:
+ case GEN_DNS:
+ case GEN_URI:
+ result = ASN1_STRING_cmp(a->d.ia5, b->d.ia5);
+ break;
+
+ case GEN_DIRNAME:
+ result = X509_NAME_cmp(a->d.dirn, b->d.dirn);
+ break;
+
+ case GEN_IPADD:
+ result = ASN1_OCTET_STRING_cmp(a->d.ip, b->d.ip);
+ break;
+
+ case GEN_RID:
+ result = OBJ_cmp(a->d.rid, b->d.rid);
+ break;
+ }
+ return result;
+ }
+
+/* Returns 0 if they are equal, != 0 otherwise. */
+int OTHERNAME_cmp(OTHERNAME *a, OTHERNAME *b)
+ {
+ int result = -1;
+
+ if (!a || !b) return -1;
+ /* Check their type first. */
+ if ((result = OBJ_cmp(a->type_id, b->type_id)) != 0)
+ return result;
+ /* Check the value. */
+ result = ASN1_TYPE_cmp(a->value, b->value);
+ return result;
+ }
+
+void GENERAL_NAME_set0_value(GENERAL_NAME *a, int type, void *value)
+ {
+ switch(type)
+ {
+ case GEN_X400:
+ case GEN_EDIPARTY:
+ a->d.other = value;
+ break;
+
+ case GEN_OTHERNAME:
+ a->d.otherName = value;
+ break;
+
+ case GEN_EMAIL:
+ case GEN_DNS:
+ case GEN_URI:
+ a->d.ia5 = value;
+ break;
+
+ case GEN_DIRNAME:
+ a->d.dirn = value;
+ break;
+
+ case GEN_IPADD:
+ a->d.ip = value;
+ break;
+
+ case GEN_RID:
+ a->d.rid = value;
+ break;
+ }
+ a->type = type;
+ }
+
+void *GENERAL_NAME_get0_value(GENERAL_NAME *a, int *ptype)
+ {
+ if (ptype)
+ *ptype = a->type;
+ switch(a->type)
+ {
+ case GEN_X400:
+ case GEN_EDIPARTY:
+ return a->d.other;
+
+ case GEN_OTHERNAME:
+ return a->d.otherName;
+
+ case GEN_EMAIL:
+ case GEN_DNS:
+ case GEN_URI:
+ return a->d.ia5;
+
+ case GEN_DIRNAME:
+ return a->d.dirn;
+
+ case GEN_IPADD:
+ return a->d.ip;
+
+ case GEN_RID:
+ return a->d.rid;
+
+ default:
+ return NULL;
+ }
+ }
+
+int GENERAL_NAME_set0_othername(GENERAL_NAME *gen,
+ ASN1_OBJECT *oid, ASN1_TYPE *value)
+ {
+ OTHERNAME *oth;
+ oth = OTHERNAME_new();
+ if (!oth)
+ return 0;
+ oth->type_id = oid;
+ oth->value = value;
+ GENERAL_NAME_set0_value(gen, GEN_OTHERNAME, oth);
+ return 1;
+ }
+
+int GENERAL_NAME_get0_otherName(GENERAL_NAME *gen,
+ ASN1_OBJECT **poid, ASN1_TYPE **pvalue)
+ {
+ if (gen->type != GEN_OTHERNAME)
+ return 0;
+ if (poid)
+ *poid = gen->d.otherName->type_id;
+ if (pvalue)
+ *pvalue = gen->d.otherName->value;
+ return 1;
+ }
+
diff --git a/crypto/x509v3/v3_ia5.c b/crypto/x509v3/v3_ia5.c
new file mode 100644
index 0000000..04ef05c
--- /dev/null
+++ b/crypto/x509v3/v3_ia5.c
@@ -0,0 +1,120 @@
+/* v3_ia5.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999 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 <stdio.h>
+
+#include <openssl/asn1.h>
+#include <openssl/conf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509v3.h>
+
+
+static char *i2s_ASN1_IA5STRING(X509V3_EXT_METHOD *method, ASN1_IA5STRING *ia5);
+static ASN1_IA5STRING *s2i_ASN1_IA5STRING(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, char *str);
+const X509V3_EXT_METHOD v3_ns_ia5_list[] = {
+EXT_IA5STRING(NID_netscape_base_url),
+EXT_IA5STRING(NID_netscape_revocation_url),
+EXT_IA5STRING(NID_netscape_ca_revocation_url),
+EXT_IA5STRING(NID_netscape_renewal_url),
+EXT_IA5STRING(NID_netscape_ca_policy_url),
+EXT_IA5STRING(NID_netscape_ssl_server_name),
+EXT_IA5STRING(NID_netscape_comment),
+EXT_END
+};
+
+
+static char *i2s_ASN1_IA5STRING(X509V3_EXT_METHOD *method,
+ ASN1_IA5STRING *ia5)
+{
+ 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);
+ return NULL;
+ }
+ memcpy(tmp, ia5->data, ia5->length);
+ tmp[ia5->length] = 0;
+ return tmp;
+}
+
+static ASN1_IA5STRING *s2i_ASN1_IA5STRING(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, char *str)
+{
+ ASN1_IA5STRING *ia5;
+ if(!str) {
+ OPENSSL_PUT_ERROR(X509V3, s2i_ASN1_IA5STRING, X509V3_R_INVALID_NULL_ARGUMENT);
+ return NULL;
+ }
+ if(!(ia5 = M_ASN1_IA5STRING_new())) goto err;
+ if(!ASN1_STRING_set((ASN1_STRING *)ia5, (unsigned char*)str,
+ strlen(str))) {
+ M_ASN1_IA5STRING_free(ia5);
+ goto err;
+ }
+#ifdef CHARSET_EBCDIC
+ ebcdic2ascii(ia5->data, ia5->data, ia5->length);
+#endif /*CHARSET_EBCDIC*/
+ return ia5;
+ err:
+ OPENSSL_PUT_ERROR(X509V3, s2i_ASN1_IA5STRING, ERR_R_MALLOC_FAILURE);
+ return NULL;
+}
+
diff --git a/crypto/x509v3/v3_info.c b/crypto/x509v3/v3_info.c
new file mode 100644
index 0000000..4ef744b
--- /dev/null
+++ b/crypto/x509v3/v3_info.c
@@ -0,0 +1,199 @@
+/* v3_info.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999 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 <stdio.h>
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/buf.h>
+#include <openssl/conf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509v3.h>
+
+
+static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_INFO_ACCESS(X509V3_EXT_METHOD *method,
+ AUTHORITY_INFO_ACCESS *ainfo,
+ STACK_OF(CONF_VALUE) *ret);
+static AUTHORITY_INFO_ACCESS *v2i_AUTHORITY_INFO_ACCESS(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval);
+
+const X509V3_EXT_METHOD v3_info =
+{ NID_info_access, X509V3_EXT_MULTILINE, ASN1_ITEM_ref(AUTHORITY_INFO_ACCESS),
+0,0,0,0,
+0,0,
+(X509V3_EXT_I2V)i2v_AUTHORITY_INFO_ACCESS,
+(X509V3_EXT_V2I)v2i_AUTHORITY_INFO_ACCESS,
+0,0,
+NULL};
+
+const X509V3_EXT_METHOD v3_sinfo =
+{ NID_sinfo_access, X509V3_EXT_MULTILINE, ASN1_ITEM_ref(AUTHORITY_INFO_ACCESS),
+0,0,0,0,
+0,0,
+(X509V3_EXT_I2V)i2v_AUTHORITY_INFO_ACCESS,
+(X509V3_EXT_V2I)v2i_AUTHORITY_INFO_ACCESS,
+0,0,
+NULL};
+
+ASN1_SEQUENCE(ACCESS_DESCRIPTION) = {
+ ASN1_SIMPLE(ACCESS_DESCRIPTION, method, ASN1_OBJECT),
+ ASN1_SIMPLE(ACCESS_DESCRIPTION, location, GENERAL_NAME)
+} ASN1_SEQUENCE_END(ACCESS_DESCRIPTION)
+
+IMPLEMENT_ASN1_FUNCTIONS(ACCESS_DESCRIPTION)
+
+ASN1_ITEM_TEMPLATE(AUTHORITY_INFO_ACCESS) =
+ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, GeneralNames, ACCESS_DESCRIPTION)
+ASN1_ITEM_TEMPLATE_END(AUTHORITY_INFO_ACCESS)
+
+IMPLEMENT_ASN1_FUNCTIONS(AUTHORITY_INFO_ACCESS)
+
+static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_INFO_ACCESS(X509V3_EXT_METHOD *method,
+ AUTHORITY_INFO_ACCESS *ainfo,
+ STACK_OF(CONF_VALUE) *ret)
+{
+ ACCESS_DESCRIPTION *desc;
+ size_t i;
+ int nlen;
+ char objtmp[80], *ntmp;
+ CONF_VALUE *vtmp;
+ for(i = 0; i < sk_ACCESS_DESCRIPTION_num(ainfo); i++) {
+ desc = sk_ACCESS_DESCRIPTION_value(ainfo, i);
+ ret = i2v_GENERAL_NAME(method, desc->location, ret);
+ if(!ret) break;
+ vtmp = sk_CONF_VALUE_value(ret, i);
+ i2t_ASN1_OBJECT(objtmp, sizeof objtmp, desc->method);
+ 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);
+ return NULL;
+ }
+ BUF_strlcpy(ntmp, objtmp, nlen);
+ BUF_strlcat(ntmp, " - ", nlen);
+ BUF_strlcat(ntmp, vtmp->name, nlen);
+ OPENSSL_free(vtmp->name);
+ vtmp->name = ntmp;
+
+ }
+ if(!ret) return sk_CONF_VALUE_new_null();
+ return ret;
+}
+
+static AUTHORITY_INFO_ACCESS *v2i_AUTHORITY_INFO_ACCESS(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
+{
+ AUTHORITY_INFO_ACCESS *ainfo = NULL;
+ CONF_VALUE *cnf, ctmp;
+ ACCESS_DESCRIPTION *acc;
+ size_t i;
+ int objlen;
+ char *objtmp, *ptmp;
+ if(!(ainfo = sk_ACCESS_DESCRIPTION_new_null())) {
+ OPENSSL_PUT_ERROR(X509V3, v2i_AUTHORITY_INFO_ACCESS, 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);
+ goto err;
+ }
+ ptmp = strchr(cnf->name, ';');
+ if(!ptmp) {
+ OPENSSL_PUT_ERROR(X509V3, v2i_AUTHORITY_INFO_ACCESS, X509V3_R_INVALID_SYNTAX);
+ goto err;
+ }
+ objlen = ptmp - cnf->name;
+ ctmp.name = ptmp + 1;
+ ctmp.value = cnf->value;
+ 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);
+ 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);
+ ERR_add_error_data(2, "value=", objtmp);
+ OPENSSL_free(objtmp);
+ goto err;
+ }
+ OPENSSL_free(objtmp);
+
+ }
+ return ainfo;
+ err:
+ sk_ACCESS_DESCRIPTION_pop_free(ainfo, ACCESS_DESCRIPTION_free);
+ return NULL;
+}
+
+int i2a_ACCESS_DESCRIPTION(BIO *bp, ACCESS_DESCRIPTION* a)
+ {
+ i2a_ASN1_OBJECT(bp, a->method);
+#ifdef UNDEF
+ i2a_GENERAL_NAME(bp, a->location);
+#endif
+ return 2;
+ }
diff --git a/crypto/x509v3/v3_int.c b/crypto/x509v3/v3_int.c
new file mode 100644
index 0000000..8ca23bd
--- /dev/null
+++ b/crypto/x509v3/v3_int.c
@@ -0,0 +1,87 @@
+/* v3_int.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2004 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 <stdio.h>
+
+#include <openssl/obj.h>
+#include <openssl/x509v3.h>
+
+
+const X509V3_EXT_METHOD v3_crl_num = {
+ NID_crl_number, 0, ASN1_ITEM_ref(ASN1_INTEGER),
+ 0,0,0,0,
+ (X509V3_EXT_I2S)i2s_ASN1_INTEGER,
+ 0,
+ 0,0,0,0, NULL};
+
+const X509V3_EXT_METHOD v3_delta_crl = {
+ NID_delta_crl, 0, ASN1_ITEM_ref(ASN1_INTEGER),
+ 0,0,0,0,
+ (X509V3_EXT_I2S)i2s_ASN1_INTEGER,
+ 0,
+ 0,0,0,0, NULL};
+
+static void * s2i_asn1_int(X509V3_EXT_METHOD *meth, X509V3_CTX *ctx, char *value)
+ {
+ return s2i_ASN1_INTEGER(meth, value);
+ }
+
+const X509V3_EXT_METHOD v3_inhibit_anyp = {
+ NID_inhibit_any_policy, 0, ASN1_ITEM_ref(ASN1_INTEGER),
+ 0,0,0,0,
+ (X509V3_EXT_I2S)i2s_ASN1_INTEGER,
+ (X509V3_EXT_S2I)s2i_asn1_int,
+ 0,0,0,0, NULL};
diff --git a/crypto/x509v3/v3_lib.c b/crypto/x509v3/v3_lib.c
new file mode 100644
index 0000000..b921499
--- /dev/null
+++ b/crypto/x509v3/v3_lib.c
@@ -0,0 +1,312 @@
+/* v3_lib.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999 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).
+ *
+ */
+/* X509 v3 extension utilities */
+
+#include <stdio.h>
+
+#include <openssl/conf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509v3.h>
+
+#include "ext_dat.h"
+static STACK_OF(X509V3_EXT_METHOD) *ext_list = NULL;
+
+static void ext_list_free(X509V3_EXT_METHOD *ext);
+
+static int ext_stack_cmp(const X509V3_EXT_METHOD **a, const X509V3_EXT_METHOD **b)
+{
+ return ((*a)->ext_nid - (*b)->ext_nid);
+}
+
+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);
+ return 0;
+ }
+ if(!sk_X509V3_EXT_METHOD_push(ext_list, ext)) {
+ OPENSSL_PUT_ERROR(X509V3, X509V3_EXT_add, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ return 1;
+}
+
+static int ext_cmp(const void *void_a,
+ const void *void_b)
+{
+ const X509V3_EXT_METHOD **a = (const X509V3_EXT_METHOD**) void_a;
+ const X509V3_EXT_METHOD **b = (const X509V3_EXT_METHOD**) void_b;
+ return ext_stack_cmp(a, b);
+}
+
+const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid)
+{
+ X509V3_EXT_METHOD tmp;
+ const X509V3_EXT_METHOD *t = &tmp, * const *ret;
+ size_t idx;
+
+ if(nid < 0) return NULL;
+ tmp.ext_nid = nid;
+ ret = bsearch(&t, standard_exts, STANDARD_EXTENSION_COUNT, sizeof(X509V3_EXT_METHOD*), ext_cmp);
+ if(ret) return *ret;
+ if(!ext_list) return NULL;
+
+ if (!sk_X509V3_EXT_METHOD_find(ext_list, &idx, &tmp))
+ return NULL;
+ return sk_X509V3_EXT_METHOD_value(ext_list, idx);
+}
+
+const X509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *ext)
+{
+ int nid;
+ if((nid = OBJ_obj2nid(ext->object)) == NID_undef) return NULL;
+ return X509V3_EXT_get_nid(nid);
+}
+
+
+int X509V3_EXT_add_list(X509V3_EXT_METHOD *extlist)
+{
+ for(;extlist->ext_nid!=-1;extlist++)
+ if(!X509V3_EXT_add(extlist)) return 0;
+ return 1;
+}
+
+int X509V3_EXT_add_alias(int nid_to, int nid_from)
+{
+ const X509V3_EXT_METHOD *ext;
+ 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);
+ 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);
+ return 0;
+ }
+ *tmpext = *ext;
+ tmpext->ext_nid = nid_to;
+ tmpext->ext_flags |= X509V3_EXT_DYNAMIC;
+ return X509V3_EXT_add(tmpext);
+}
+
+void X509V3_EXT_cleanup(void)
+{
+ sk_X509V3_EXT_METHOD_pop_free(ext_list, ext_list_free);
+ ext_list = NULL;
+}
+
+static void ext_list_free(X509V3_EXT_METHOD *ext)
+{
+ if(ext->ext_flags & X509V3_EXT_DYNAMIC) OPENSSL_free(ext);
+}
+
+/* Legacy function: we don't need to add standard extensions
+ * any more because they are now kept in ext_dat.h.
+ */
+
+int X509V3_add_standard_extensions(void)
+{
+ return 1;
+}
+
+/* Return an extension internal structure */
+
+void *X509V3_EXT_d2i(X509_EXTENSION *ext)
+{
+ const X509V3_EXT_METHOD *method;
+ const unsigned char *p;
+
+ if(!(method = X509V3_EXT_get(ext))) return NULL;
+ p = ext->value->data;
+ if(method->it) return ASN1_item_d2i(NULL, &p, ext->value->length, ASN1_ITEM_ptr(method->it));
+ return method->d2i(NULL, &p, ext->value->length);
+}
+
+/* Get critical flag and decoded version of extension from a NID.
+ * The "idx" variable returns the last found extension and can
+ * be used to retrieve multiple extensions of the same NID.
+ * However multiple extensions with the same NID is usually
+ * due to a badly encoded certificate so if idx is NULL we
+ * choke if multiple extensions exist.
+ * The "crit" variable is set to the critical value.
+ * The return value is the decoded extension or NULL on
+ * error. The actual error can have several different causes,
+ * the value of *crit reflects the cause:
+ * >= 0, extension found but not decoded (reflects critical value).
+ * -1 extension not found.
+ * -2 extension occurs more than once.
+ */
+
+void *X509V3_get_d2i(STACK_OF(X509_EXTENSION) *x, int nid, int *crit, int *idx)
+{
+ int lastpos;
+ size_t i;
+ X509_EXTENSION *ex, *found_ex = NULL;
+ if(!x) {
+ if(idx) *idx = -1;
+ if(crit) *crit = -1;
+ return NULL;
+ }
+ if(idx) lastpos = *idx + 1;
+ else lastpos = 0;
+ if(lastpos < 0) lastpos = 0;
+ for(i = lastpos; i < sk_X509_EXTENSION_num(x); i++)
+ {
+ ex = sk_X509_EXTENSION_value(x, i);
+ if(OBJ_obj2nid(ex->object) == nid) {
+ if(idx) {
+ *idx = i;
+ found_ex = ex;
+ break;
+ } else if(found_ex) {
+ /* Found more than one */
+ if(crit) *crit = -2;
+ return NULL;
+ }
+ found_ex = ex;
+ }
+ }
+ if(found_ex) {
+ /* Found it */
+ if(crit) *crit = X509_EXTENSION_get_critical(found_ex);
+ return X509V3_EXT_d2i(found_ex);
+ }
+
+ /* Extension not found */
+ if(idx) *idx = -1;
+ if(crit) *crit = -1;
+ return NULL;
+}
+
+/* This function is a general extension append, replace and delete utility.
+ * The precise operation is governed by the 'flags' value. The 'crit' and
+ * 'value' arguments (if relevant) are the extensions internal structure.
+ */
+
+int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value,
+ int crit, unsigned long flags)
+{
+ int extidx = -1;
+ int errcode;
+ X509_EXTENSION *ext, *extmp;
+ unsigned long ext_op = flags & X509V3_ADD_OP_MASK;
+
+ /* If appending we don't care if it exists, otherwise
+ * look for existing extension.
+ */
+ if(ext_op != X509V3_ADD_APPEND)
+ extidx = X509v3_get_ext_by_NID(*x, nid, -1);
+
+ /* See if extension exists */
+ if(extidx >= 0) {
+ /* If keep existing, nothing to do */
+ if(ext_op == X509V3_ADD_KEEP_EXISTING)
+ return 1;
+ /* If default then its an error */
+ if(ext_op == X509V3_ADD_DEFAULT) {
+ errcode = X509V3_R_EXTENSION_EXISTS;
+ goto err;
+ }
+ /* If delete, just delete it */
+ if(ext_op == X509V3_ADD_DELETE) {
+ if(!sk_X509_EXTENSION_delete(*x, extidx)) return -1;
+ return 1;
+ }
+ } else {
+ /* If replace existing or delete, error since
+ * extension must exist
+ */
+ if((ext_op == X509V3_ADD_REPLACE_EXISTING) ||
+ (ext_op == X509V3_ADD_DELETE)) {
+ errcode = X509V3_R_EXTENSION_NOT_FOUND;
+ goto err;
+ }
+ }
+
+ /* If we get this far then we have to create an extension:
+ * could have some flags for alternative encoding schemes...
+ */
+
+ ext = X509V3_EXT_i2d(nid, crit, value);
+
+ if(!ext) {
+ OPENSSL_PUT_ERROR(X509V3, X509V3_add1_i2d, X509V3_R_ERROR_CREATING_EXTENSION);
+ return 0;
+ }
+
+ /* If extension exists replace it.. */
+ if(extidx >= 0) {
+ extmp = sk_X509_EXTENSION_value(*x, extidx);
+ X509_EXTENSION_free(extmp);
+ if(!sk_X509_EXTENSION_set(*x, extidx, ext)) return -1;
+ return 1;
+ }
+
+ if(!*x && !(*x = sk_X509_EXTENSION_new_null())) return -1;
+ if(!sk_X509_EXTENSION_push(*x, ext)) return -1;
+
+ return 1;
+
+ err:
+ if(!(flags & X509V3_ADD_SILENT))
+ OPENSSL_PUT_ERROR(X509V3, X509V3_add1_i2d, errcode);
+ return 0;
+}
diff --git a/crypto/x509v3/v3_ncons.c b/crypto/x509v3/v3_ncons.c
new file mode 100644
index 0000000..a50a725
--- /dev/null
+++ b/crypto/x509v3/v3_ncons.c
@@ -0,0 +1,514 @@
+/* v3_ncons.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project.
+ */
+/* ====================================================================
+ * Copyright (c) 2003 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 <stdio.h>
+#include <string.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/conf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509v3.h>
+
+#if !defined(OPENSSL_WINDOWS)
+#include <strings.h>
+#endif
+
+
+static void *v2i_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval);
+static int i2r_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method,
+ void *a, BIO *bp, int ind);
+static int do_i2r_name_constraints(const X509V3_EXT_METHOD *method,
+ STACK_OF(GENERAL_SUBTREE) *trees,
+ BIO *bp, int ind, char *name);
+static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip);
+
+static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc);
+static int nc_match_single(GENERAL_NAME *sub, GENERAL_NAME *gen);
+static int nc_dn(X509_NAME *sub, X509_NAME *nm);
+static int nc_dns(ASN1_IA5STRING *sub, ASN1_IA5STRING *dns);
+static int nc_email(ASN1_IA5STRING *sub, ASN1_IA5STRING *eml);
+static int nc_uri(ASN1_IA5STRING *uri, ASN1_IA5STRING *base);
+
+const X509V3_EXT_METHOD v3_name_constraints = {
+ NID_name_constraints, 0,
+ ASN1_ITEM_ref(NAME_CONSTRAINTS),
+ 0,0,0,0,
+ 0,0,
+ 0, v2i_NAME_CONSTRAINTS,
+ i2r_NAME_CONSTRAINTS,0,
+ NULL
+};
+
+ASN1_SEQUENCE(GENERAL_SUBTREE) = {
+ ASN1_SIMPLE(GENERAL_SUBTREE, base, GENERAL_NAME),
+ ASN1_IMP_OPT(GENERAL_SUBTREE, minimum, ASN1_INTEGER, 0),
+ ASN1_IMP_OPT(GENERAL_SUBTREE, maximum, ASN1_INTEGER, 1)
+} ASN1_SEQUENCE_END(GENERAL_SUBTREE)
+
+ASN1_SEQUENCE(NAME_CONSTRAINTS) = {
+ ASN1_IMP_SEQUENCE_OF_OPT(NAME_CONSTRAINTS, permittedSubtrees,
+ GENERAL_SUBTREE, 0),
+ ASN1_IMP_SEQUENCE_OF_OPT(NAME_CONSTRAINTS, excludedSubtrees,
+ GENERAL_SUBTREE, 1),
+} ASN1_SEQUENCE_END(NAME_CONSTRAINTS)
+
+
+IMPLEMENT_ASN1_ALLOC_FUNCTIONS(GENERAL_SUBTREE)
+IMPLEMENT_ASN1_ALLOC_FUNCTIONS(NAME_CONSTRAINTS)
+
+static void *v2i_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
+ {
+ size_t i;
+ CONF_VALUE tval, *val;
+ STACK_OF(GENERAL_SUBTREE) **ptree = NULL;
+ NAME_CONSTRAINTS *ncons = NULL;
+ GENERAL_SUBTREE *sub = NULL;
+ ncons = NAME_CONSTRAINTS_new();
+ if (!ncons)
+ goto memerr;
+ for(i = 0; i < sk_CONF_VALUE_num(nval); i++)
+ {
+ val = sk_CONF_VALUE_value(nval, i);
+ if (!strncmp(val->name, "permitted", 9) && val->name[9])
+ {
+ ptree = &ncons->permittedSubtrees;
+ tval.name = val->name + 10;
+ }
+ else if (!strncmp(val->name, "excluded", 8) && val->name[8])
+ {
+ ptree = &ncons->excludedSubtrees;
+ tval.name = val->name + 9;
+ }
+ else
+ {
+ OPENSSL_PUT_ERROR(X509V3, v2i_NAME_CONSTRAINTS, X509V3_R_INVALID_SYNTAX);
+ goto err;
+ }
+ tval.value = val->value;
+ sub = GENERAL_SUBTREE_new();
+ if (!v2i_GENERAL_NAME_ex(sub->base, method, ctx, &tval, 1))
+ goto err;
+ if (!*ptree)
+ *ptree = sk_GENERAL_SUBTREE_new_null();
+ if (!*ptree || !sk_GENERAL_SUBTREE_push(*ptree, sub))
+ goto memerr;
+ sub = NULL;
+ }
+
+ return ncons;
+
+ memerr:
+ OPENSSL_PUT_ERROR(X509V3, v2i_NAME_CONSTRAINTS, ERR_R_MALLOC_FAILURE);
+ err:
+ if (ncons)
+ NAME_CONSTRAINTS_free(ncons);
+ if (sub)
+ GENERAL_SUBTREE_free(sub);
+
+ return NULL;
+ }
+
+
+
+
+static int i2r_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, void *a,
+ BIO *bp, int ind)
+ {
+ NAME_CONSTRAINTS *ncons = a;
+ do_i2r_name_constraints(method, ncons->permittedSubtrees,
+ bp, ind, "Permitted");
+ do_i2r_name_constraints(method, ncons->excludedSubtrees,
+ bp, ind, "Excluded");
+ return 1;
+ }
+
+static int do_i2r_name_constraints(const X509V3_EXT_METHOD *method,
+ STACK_OF(GENERAL_SUBTREE) *trees,
+ BIO *bp, int ind, char *name)
+ {
+ GENERAL_SUBTREE *tree;
+ size_t i;
+ if (sk_GENERAL_SUBTREE_num(trees) > 0)
+ BIO_printf(bp, "%*s%s:\n", ind, "", name);
+ for(i = 0; i < sk_GENERAL_SUBTREE_num(trees); i++)
+ {
+ tree = sk_GENERAL_SUBTREE_value(trees, i);
+ BIO_printf(bp, "%*s", ind + 2, "");
+ if (tree->base->type == GEN_IPADD)
+ print_nc_ipadd(bp, tree->base->d.ip);
+ else
+ GENERAL_NAME_print(bp, tree->base);
+ BIO_puts(bp, "\n");
+ }
+ return 1;
+ }
+
+static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip)
+ {
+ int i, len;
+ unsigned char *p;
+ p = ip->data;
+ len = ip->length;
+ BIO_puts(bp, "IP:");
+ if(len == 8)
+ {
+ BIO_printf(bp, "%d.%d.%d.%d/%d.%d.%d.%d",
+ p[0], p[1], p[2], p[3],
+ p[4], p[5], p[6], p[7]);
+ }
+ else if(len == 32)
+ {
+ for (i = 0; i < 16; i++)
+ {
+ BIO_printf(bp, "%X", p[0] << 8 | p[1]);
+ p += 2;
+ if (i == 7)
+ BIO_puts(bp, "/");
+ else if (i != 15)
+ BIO_puts(bp, ":");
+ }
+ }
+ else
+ BIO_printf(bp, "IP Address:<invalid>");
+ return 1;
+ }
+
+/* Check a certificate conforms to a specified set of constraints.
+ * Return values:
+ * X509_V_OK: All constraints obeyed.
+ * X509_V_ERR_PERMITTED_VIOLATION: Permitted subtree violation.
+ * X509_V_ERR_EXCLUDED_VIOLATION: Excluded subtree violation.
+ * X509_V_ERR_SUBTREE_MINMAX: Min or max values present and matching type.
+ * X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE: Unsupported constraint type.
+ * X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: bad unsupported constraint syntax.
+ * X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: bad or unsupported syntax of name
+
+ */
+
+int NAME_CONSTRAINTS_check(X509 *x, NAME_CONSTRAINTS *nc)
+ {
+ int r, i;
+ size_t j;
+ X509_NAME *nm;
+
+ nm = X509_get_subject_name(x);
+
+ if (X509_NAME_entry_count(nm) > 0)
+ {
+ GENERAL_NAME gntmp;
+ gntmp.type = GEN_DIRNAME;
+ gntmp.d.directoryName = nm;
+
+ r = nc_match(&gntmp, nc);
+
+ if (r != X509_V_OK)
+ return r;
+
+ gntmp.type = GEN_EMAIL;
+
+
+ /* Process any email address attributes in subject name */
+
+ for (i = -1;;)
+ {
+ X509_NAME_ENTRY *ne;
+ i = X509_NAME_get_index_by_NID(nm,
+ NID_pkcs9_emailAddress,
+ i);
+ if (i == -1)
+ break;
+ ne = X509_NAME_get_entry(nm, i);
+ gntmp.d.rfc822Name = X509_NAME_ENTRY_get_data(ne);
+ if (gntmp.d.rfc822Name->type != V_ASN1_IA5STRING)
+ return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
+
+ r = nc_match(&gntmp, nc);
+
+ if (r != X509_V_OK)
+ return r;
+ }
+
+ }
+
+ for (j = 0; j < sk_GENERAL_NAME_num(x->altname); j++)
+ {
+ GENERAL_NAME *gen = sk_GENERAL_NAME_value(x->altname, j);
+ r = nc_match(gen, nc);
+ if (r != X509_V_OK)
+ return r;
+ }
+
+ return X509_V_OK;
+
+ }
+
+static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc)
+ {
+ GENERAL_SUBTREE *sub;
+ int r, match = 0;
+ size_t i;
+
+ /* Permitted subtrees: if any subtrees exist of matching the type
+ * at least one subtree must match.
+ */
+
+ for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->permittedSubtrees); i++)
+ {
+ sub = sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, i);
+ if (gen->type != sub->base->type)
+ continue;
+ if (sub->minimum || sub->maximum)
+ return X509_V_ERR_SUBTREE_MINMAX;
+ /* If we already have a match don't bother trying any more */
+ if (match == 2)
+ continue;
+ if (match == 0)
+ match = 1;
+ r = nc_match_single(gen, sub->base);
+ if (r == X509_V_OK)
+ match = 2;
+ else if (r != X509_V_ERR_PERMITTED_VIOLATION)
+ return r;
+ }
+
+ if (match == 1)
+ return X509_V_ERR_PERMITTED_VIOLATION;
+
+ /* Excluded subtrees: must not match any of these */
+
+ for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->excludedSubtrees); i++)
+ {
+ sub = sk_GENERAL_SUBTREE_value(nc->excludedSubtrees, i);
+ if (gen->type != sub->base->type)
+ continue;
+ if (sub->minimum || sub->maximum)
+ return X509_V_ERR_SUBTREE_MINMAX;
+
+ r = nc_match_single(gen, sub->base);
+ if (r == X509_V_OK)
+ return X509_V_ERR_EXCLUDED_VIOLATION;
+ else if (r != X509_V_ERR_PERMITTED_VIOLATION)
+ return r;
+
+ }
+
+ return X509_V_OK;
+
+ }
+
+static int nc_match_single(GENERAL_NAME *gen, GENERAL_NAME *base)
+ {
+ switch(base->type)
+ {
+ case GEN_DIRNAME:
+ return nc_dn(gen->d.directoryName, base->d.directoryName);
+
+ case GEN_DNS:
+ return nc_dns(gen->d.dNSName, base->d.dNSName);
+
+ case GEN_EMAIL:
+ return nc_email(gen->d.rfc822Name, base->d.rfc822Name);
+
+ case GEN_URI:
+ return nc_uri(gen->d.uniformResourceIdentifier,
+ base->d.uniformResourceIdentifier);
+
+ default:
+ return X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE;
+ }
+
+ }
+
+/* directoryName name constraint matching.
+ * The canonical encoding of X509_NAME makes this comparison easy. It is
+ * matched if the subtree is a subset of the name.
+ */
+
+static int nc_dn(X509_NAME *nm, X509_NAME *base)
+ {
+ /* Ensure canonical encodings are up to date. */
+ if (nm->modified && i2d_X509_NAME(nm, NULL) < 0)
+ return X509_V_ERR_OUT_OF_MEM;
+ if (base->modified && i2d_X509_NAME(base, NULL) < 0)
+ return X509_V_ERR_OUT_OF_MEM;
+ if (base->canon_enclen > nm->canon_enclen)
+ return X509_V_ERR_PERMITTED_VIOLATION;
+ if (memcmp(base->canon_enc, nm->canon_enc, base->canon_enclen))
+ return X509_V_ERR_PERMITTED_VIOLATION;
+ return X509_V_OK;
+ }
+
+static int nc_dns(ASN1_IA5STRING *dns, ASN1_IA5STRING *base)
+ {
+ char *baseptr = (char *)base->data;
+ char *dnsptr = (char *)dns->data;
+ /* Empty matches everything */
+ if (!*baseptr)
+ return X509_V_OK;
+ /* Otherwise can add zero or more components on the left so
+ * compare RHS and if dns is longer and expect '.' as preceding
+ * character.
+ */
+ if (dns->length > base->length)
+ {
+ dnsptr += dns->length - base->length;
+ if (dnsptr[-1] != '.')
+ return X509_V_ERR_PERMITTED_VIOLATION;
+ }
+
+ if (strcasecmp(baseptr, dnsptr))
+ return X509_V_ERR_PERMITTED_VIOLATION;
+
+ return X509_V_OK;
+
+ }
+
+static int nc_email(ASN1_IA5STRING *eml, ASN1_IA5STRING *base)
+ {
+ const char *baseptr = (char *)base->data;
+ const char *emlptr = (char *)eml->data;
+
+ const char *baseat = strchr(baseptr, '@');
+ const char *emlat = strchr(emlptr, '@');
+ if (!emlat)
+ return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
+ /* Special case: inital '.' is RHS match */
+ if (!baseat && (*baseptr == '.'))
+ {
+ if (eml->length > base->length)
+ {
+ emlptr += eml->length - base->length;
+ if (!strcasecmp(baseptr, emlptr))
+ return X509_V_OK;
+ }
+ return X509_V_ERR_PERMITTED_VIOLATION;
+ }
+
+ /* If we have anything before '@' match local part */
+
+ if (baseat)
+ {
+ if (baseat != baseptr)
+ {
+ if ((baseat - baseptr) != (emlat - emlptr))
+ return X509_V_ERR_PERMITTED_VIOLATION;
+ /* Case sensitive match of local part */
+ if (strncmp(baseptr, emlptr, emlat - emlptr))
+ return X509_V_ERR_PERMITTED_VIOLATION;
+ }
+ /* Position base after '@' */
+ baseptr = baseat + 1;
+ }
+ emlptr = emlat + 1;
+ /* Just have hostname left to match: case insensitive */
+ if (strcasecmp(baseptr, emlptr))
+ return X509_V_ERR_PERMITTED_VIOLATION;
+
+ return X509_V_OK;
+
+ }
+
+static int nc_uri(ASN1_IA5STRING *uri, ASN1_IA5STRING *base)
+ {
+ const char *baseptr = (char *)base->data;
+ const char *hostptr = (char *)uri->data;
+ const char *p = strchr(hostptr, ':');
+ int hostlen;
+ /* Check for foo:// and skip past it */
+ if (!p || (p[1] != '/') || (p[2] != '/'))
+ return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
+ hostptr = p + 3;
+
+ /* Determine length of hostname part of URI */
+
+ /* Look for a port indicator as end of hostname first */
+
+ p = strchr(hostptr, ':');
+ /* Otherwise look for trailing slash */
+ if (!p)
+ p = strchr(hostptr, '/');
+
+ if (!p)
+ hostlen = strlen(hostptr);
+ else
+ hostlen = p - hostptr;
+
+ if (hostlen == 0)
+ return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
+
+ /* Special case: inital '.' is RHS match */
+ if (*baseptr == '.')
+ {
+ if (hostlen > base->length)
+ {
+ p = hostptr + hostlen - base->length;
+ if (!strncasecmp(p, baseptr, base->length))
+ return X509_V_OK;
+ }
+ return X509_V_ERR_PERMITTED_VIOLATION;
+ }
+
+ if ((base->length != (int)hostlen) || strncasecmp(hostptr, baseptr, hostlen))
+ return X509_V_ERR_PERMITTED_VIOLATION;
+
+ return X509_V_OK;
+
+ }
diff --git a/crypto/x509v3/v3_pci.c b/crypto/x509v3/v3_pci.c
new file mode 100644
index 0000000..6f0b1c8
--- /dev/null
+++ b/crypto/x509v3/v3_pci.c
@@ -0,0 +1,333 @@
+/* v3_pci.c -*- mode:C; c-file-style: "eay" -*- */
+/* Contributed to the OpenSSL Project 2004
+ * by Richard Levitte (richard@levitte.org)
+ */
+/* Copyright (c) 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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. Neither the name of the Institute 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 THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE 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.
+ */
+
+#include <stdio.h>
+
+#include <openssl/conf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509v3.h>
+
+
+static int i2r_pci(X509V3_EXT_METHOD *method, PROXY_CERT_INFO_EXTENSION *ext,
+ BIO *out, int indent);
+static PROXY_CERT_INFO_EXTENSION *r2i_pci(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, char *str);
+
+const X509V3_EXT_METHOD v3_pci =
+ { NID_proxyCertInfo, 0, ASN1_ITEM_ref(PROXY_CERT_INFO_EXTENSION),
+ 0,0,0,0,
+ 0,0,
+ NULL, NULL,
+ (X509V3_EXT_I2R)i2r_pci,
+ (X509V3_EXT_R2I)r2i_pci,
+ NULL,
+ };
+
+static int i2r_pci(X509V3_EXT_METHOD *method, PROXY_CERT_INFO_EXTENSION *pci,
+ BIO *out, int indent)
+ {
+ BIO_printf(out, "%*sPath Length Constraint: ", indent, "");
+ if (pci->pcPathLengthConstraint)
+ i2a_ASN1_INTEGER(out, pci->pcPathLengthConstraint);
+ else
+ BIO_printf(out, "infinite");
+ BIO_puts(out, "\n");
+ BIO_printf(out, "%*sPolicy Language: ", indent, "");
+ i2a_ASN1_OBJECT(out, pci->proxyPolicy->policyLanguage);
+ BIO_puts(out, "\n");
+ if (pci->proxyPolicy->policy && pci->proxyPolicy->policy->data)
+ BIO_printf(out, "%*sPolicy Text: %s\n", indent, "",
+ pci->proxyPolicy->policy->data);
+ return 1;
+ }
+
+static int process_pci_value(CONF_VALUE *val,
+ ASN1_OBJECT **language, ASN1_INTEGER **pathlen,
+ ASN1_OCTET_STRING **policy)
+ {
+ int free_policy = 0;
+
+ if (strcmp(val->name, "language") == 0)
+ {
+ if (*language)
+ {
+ OPENSSL_PUT_ERROR(X509V3, process_pci_value, 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);
+ X509V3_conf_err(val);
+ return 0;
+ }
+ }
+ else if (strcmp(val->name, "pathlen") == 0)
+ {
+ if (*pathlen)
+ {
+ OPENSSL_PUT_ERROR(X509V3, process_pci_value, 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);
+ X509V3_conf_err(val);
+ return 0;
+ }
+ }
+ else if (strcmp(val->name, "policy") == 0)
+ {
+ unsigned char *tmp_data = NULL;
+ long val_len;
+ if (!*policy)
+ {
+ *policy = ASN1_OCTET_STRING_new();
+ if (!*policy)
+ {
+ OPENSSL_PUT_ERROR(X509V3, process_pci_value, ERR_R_MALLOC_FAILURE);
+ X509V3_conf_err(val);
+ return 0;
+ }
+ free_policy = 1;
+ }
+ if (strncmp(val->value, "hex:", 4) == 0)
+ {
+ unsigned char *tmp_data2 =
+ string_to_hex(val->value + 4, &val_len);
+
+ if (!tmp_data2)
+ {
+ OPENSSL_PUT_ERROR(X509V3, process_pci_value, X509V3_R_ILLEGAL_HEX_DIGIT);
+ X509V3_conf_err(val);
+ goto err;
+ }
+
+ tmp_data = OPENSSL_realloc((*policy)->data,
+ (*policy)->length + val_len + 1);
+ if (tmp_data)
+ {
+ (*policy)->data = tmp_data;
+ memcpy(&(*policy)->data[(*policy)->length],
+ tmp_data2, val_len);
+ (*policy)->length += val_len;
+ (*policy)->data[(*policy)->length] = '\0';
+ }
+ else
+ {
+ OPENSSL_free(tmp_data2);
+ /* 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);
+ X509V3_conf_err(val);
+ goto err;
+ }
+ OPENSSL_free(tmp_data2);
+ }
+ else if (strncmp(val->value, "file:", 5) == 0)
+ {
+ unsigned char buf[2048];
+ int n;
+ BIO *b = BIO_new_file(val->value + 5, "r");
+ if (!b)
+ {
+ OPENSSL_PUT_ERROR(X509V3, process_pci_value, ERR_R_BIO_LIB);
+ X509V3_conf_err(val);
+ goto err;
+ }
+ while((n = BIO_read(b, buf, sizeof(buf))) > 0
+ || (n == 0 && BIO_should_retry(b)))
+ {
+ if (!n) continue;
+
+ tmp_data = OPENSSL_realloc((*policy)->data,
+ (*policy)->length + n + 1);
+
+ if (!tmp_data)
+ break;
+
+ (*policy)->data = tmp_data;
+ memcpy(&(*policy)->data[(*policy)->length],
+ buf, n);
+ (*policy)->length += n;
+ (*policy)->data[(*policy)->length] = '\0';
+ }
+ BIO_free_all(b);
+
+ if (n < 0)
+ {
+ OPENSSL_PUT_ERROR(X509V3, process_pci_value, ERR_R_BIO_LIB);
+ X509V3_conf_err(val);
+ goto err;
+ }
+ }
+ else if (strncmp(val->value, "text:", 5) == 0)
+ {
+ val_len = strlen(val->value + 5);
+ tmp_data = OPENSSL_realloc((*policy)->data,
+ (*policy)->length + val_len + 1);
+ if (tmp_data)
+ {
+ (*policy)->data = tmp_data;
+ memcpy(&(*policy)->data[(*policy)->length],
+ val->value + 5, val_len);
+ (*policy)->length += val_len;
+ (*policy)->data[(*policy)->length] = '\0';
+ }
+ else
+ {
+ /* 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);
+ X509V3_conf_err(val);
+ goto err;
+ }
+ }
+ else
+ {
+ OPENSSL_PUT_ERROR(X509V3, process_pci_value, 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);
+ X509V3_conf_err(val);
+ goto err;
+ }
+ }
+ return 1;
+err:
+ if (free_policy)
+ {
+ ASN1_OCTET_STRING_free(*policy);
+ *policy = NULL;
+ }
+ return 0;
+ }
+
+static PROXY_CERT_INFO_EXTENSION *r2i_pci(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, char *value)
+ {
+ PROXY_CERT_INFO_EXTENSION *pci = NULL;
+ STACK_OF(CONF_VALUE) *vals;
+ ASN1_OBJECT *language = NULL;
+ ASN1_INTEGER *pathlen = NULL;
+ ASN1_OCTET_STRING *policy = NULL;
+ size_t i, j;
+ int nid;
+
+ vals = X509V3_parse_list(value);
+ for (i = 0; i < sk_CONF_VALUE_num(vals); i++)
+ {
+ 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);
+ X509V3_conf_err(cnf);
+ goto err;
+ }
+ if (*cnf->name == '@')
+ {
+ STACK_OF(CONF_VALUE) *sect;
+ int success_p = 1;
+
+ sect = X509V3_get_section(ctx, cnf->name + 1);
+ if (!sect)
+ {
+ OPENSSL_PUT_ERROR(X509V3, r2i_pci, X509V3_R_INVALID_SECTION);
+ X509V3_conf_err(cnf);
+ goto err;
+ }
+ for (j = 0; success_p && j < sk_CONF_VALUE_num(sect); j++)
+ {
+ success_p =
+ process_pci_value(sk_CONF_VALUE_value(sect, j),
+ &language, &pathlen, &policy);
+ }
+ X509V3_section_free(ctx, sect);
+ if (!success_p)
+ goto err;
+ }
+ else
+ {
+ if (!process_pci_value(cnf,
+ &language, &pathlen, &policy))
+ {
+ X509V3_conf_err(cnf);
+ goto err;
+ }
+ }
+ }
+
+ /* Language is mandatory */
+ if (!language)
+ {
+ OPENSSL_PUT_ERROR(X509V3, r2i_pci, 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);
+ goto err;
+ }
+
+ pci = PROXY_CERT_INFO_EXTENSION_new();
+ if (!pci)
+ {
+ OPENSSL_PUT_ERROR(X509V3, r2i_pci, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ pci->proxyPolicy->policyLanguage = language; language = NULL;
+ pci->proxyPolicy->policy = policy; policy = NULL;
+ pci->pcPathLengthConstraint = pathlen; pathlen = NULL;
+ goto end;
+err:
+ if (language) { ASN1_OBJECT_free(language); language = NULL; }
+ if (pathlen) { ASN1_INTEGER_free(pathlen); pathlen = NULL; }
+ if (policy) { ASN1_OCTET_STRING_free(policy); policy = NULL; }
+ if (pci) { PROXY_CERT_INFO_EXTENSION_free(pci); pci = NULL; }
+end:
+ sk_CONF_VALUE_pop_free(vals, X509V3_conf_free);
+ return pci;
+ }
diff --git a/crypto/x509v3/v3_pcia.c b/crypto/x509v3/v3_pcia.c
new file mode 100644
index 0000000..04842bf
--- /dev/null
+++ b/crypto/x509v3/v3_pcia.c
@@ -0,0 +1,56 @@
+/* v3_pcia.c -*- mode:C; c-file-style: "eay" -*- */
+/* Contributed to the OpenSSL Project 2004
+ * by Richard Levitte (richard@levitte.org)
+ */
+/* Copyright (c) 2004 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * 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. Neither the name of the Institute 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 THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE 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.
+ */
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/x509v3.h>
+
+
+ASN1_SEQUENCE(PROXY_POLICY) =
+ {
+ ASN1_SIMPLE(PROXY_POLICY,policyLanguage,ASN1_OBJECT),
+ ASN1_OPT(PROXY_POLICY,policy,ASN1_OCTET_STRING)
+} ASN1_SEQUENCE_END(PROXY_POLICY)
+
+IMPLEMENT_ASN1_FUNCTIONS(PROXY_POLICY)
+
+ASN1_SEQUENCE(PROXY_CERT_INFO_EXTENSION) =
+ {
+ ASN1_OPT(PROXY_CERT_INFO_EXTENSION,pcPathLengthConstraint,ASN1_INTEGER),
+ ASN1_SIMPLE(PROXY_CERT_INFO_EXTENSION,proxyPolicy,PROXY_POLICY)
+} ASN1_SEQUENCE_END(PROXY_CERT_INFO_EXTENSION)
+
+IMPLEMENT_ASN1_FUNCTIONS(PROXY_CERT_INFO_EXTENSION)
diff --git a/crypto/x509v3/v3_pcons.c b/crypto/x509v3/v3_pcons.c
new file mode 100644
index 0000000..dac732c
--- /dev/null
+++ b/crypto/x509v3/v3_pcons.c
@@ -0,0 +1,141 @@
+/* v3_pcons.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project.
+ */
+/* ====================================================================
+ * Copyright (c) 2003 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 <stdio.h>
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/conf.h>
+#include <openssl/err.h>
+#include <openssl/obj.h>
+#include <openssl/x509v3.h>
+
+
+static STACK_OF(CONF_VALUE) *
+i2v_POLICY_CONSTRAINTS(const X509V3_EXT_METHOD *method, void *bcons,
+ STACK_OF(CONF_VALUE) *extlist);
+static void *v2i_POLICY_CONSTRAINTS(const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *values);
+
+const X509V3_EXT_METHOD v3_policy_constraints = {
+NID_policy_constraints, 0,
+ASN1_ITEM_ref(POLICY_CONSTRAINTS),
+0,0,0,0,
+0,0,
+i2v_POLICY_CONSTRAINTS,
+v2i_POLICY_CONSTRAINTS,
+NULL,NULL,
+NULL
+};
+
+ASN1_SEQUENCE(POLICY_CONSTRAINTS) = {
+ ASN1_IMP_OPT(POLICY_CONSTRAINTS, requireExplicitPolicy, ASN1_INTEGER,0),
+ ASN1_IMP_OPT(POLICY_CONSTRAINTS, inhibitPolicyMapping, ASN1_INTEGER,1)
+} ASN1_SEQUENCE_END(POLICY_CONSTRAINTS)
+
+IMPLEMENT_ASN1_ALLOC_FUNCTIONS(POLICY_CONSTRAINTS)
+
+
+static STACK_OF(CONF_VALUE) *
+i2v_POLICY_CONSTRAINTS(const X509V3_EXT_METHOD *method, void *a,
+ STACK_OF(CONF_VALUE) *extlist)
+{
+ POLICY_CONSTRAINTS *pcons = a;
+ X509V3_add_value_int("Require Explicit Policy",
+ pcons->requireExplicitPolicy, &extlist);
+ X509V3_add_value_int("Inhibit Policy Mapping",
+ pcons->inhibitPolicyMapping, &extlist);
+ return extlist;
+}
+
+static void *v2i_POLICY_CONSTRAINTS(const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *values)
+{
+ POLICY_CONSTRAINTS *pcons=NULL;
+ CONF_VALUE *val;
+ size_t i;
+ if(!(pcons = POLICY_CONSTRAINTS_new())) {
+ OPENSSL_PUT_ERROR(X509V3, v2i_POLICY_CONSTRAINTS, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ for(i = 0; i < sk_CONF_VALUE_num(values); i++) {
+ val = sk_CONF_VALUE_value(values, i);
+ if(!strcmp(val->name, "requireExplicitPolicy")) {
+ if(!X509V3_get_value_int(val,
+ &pcons->requireExplicitPolicy)) goto err;
+ } else if(!strcmp(val->name, "inhibitPolicyMapping")) {
+ if(!X509V3_get_value_int(val,
+ &pcons->inhibitPolicyMapping)) goto err;
+ } else {
+ OPENSSL_PUT_ERROR(X509V3, v2i_POLICY_CONSTRAINTS, 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);
+ goto err;
+ }
+
+ return pcons;
+ err:
+ POLICY_CONSTRAINTS_free(pcons);
+ return NULL;
+}
+
diff --git a/crypto/x509v3/v3_pku.c b/crypto/x509v3/v3_pku.c
new file mode 100644
index 0000000..445eda6
--- /dev/null
+++ b/crypto/x509v3/v3_pku.c
@@ -0,0 +1,109 @@
+/* v3_pku.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999 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 <stdio.h>
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509v3.h>
+
+
+static int i2r_PKEY_USAGE_PERIOD(X509V3_EXT_METHOD *method, PKEY_USAGE_PERIOD *usage, BIO *out, int indent);
+/*
+static PKEY_USAGE_PERIOD *v2i_PKEY_USAGE_PERIOD(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *values);
+*/
+const X509V3_EXT_METHOD v3_pkey_usage_period = {
+NID_private_key_usage_period, 0, ASN1_ITEM_ref(PKEY_USAGE_PERIOD),
+0,0,0,0,
+0,0,0,0,
+(X509V3_EXT_I2R)i2r_PKEY_USAGE_PERIOD, NULL,
+NULL
+};
+
+ASN1_SEQUENCE(PKEY_USAGE_PERIOD) = {
+ ASN1_IMP_OPT(PKEY_USAGE_PERIOD, notBefore, ASN1_GENERALIZEDTIME, 0),
+ ASN1_IMP_OPT(PKEY_USAGE_PERIOD, notAfter, ASN1_GENERALIZEDTIME, 1)
+} ASN1_SEQUENCE_END(PKEY_USAGE_PERIOD)
+
+IMPLEMENT_ASN1_FUNCTIONS(PKEY_USAGE_PERIOD)
+
+static int i2r_PKEY_USAGE_PERIOD(X509V3_EXT_METHOD *method,
+ PKEY_USAGE_PERIOD *usage, BIO *out, int indent)
+{
+ BIO_printf(out, "%*s", indent, "");
+ if(usage->notBefore) {
+ BIO_write(out, "Not Before: ", 12);
+ ASN1_GENERALIZEDTIME_print(out, usage->notBefore);
+ if(usage->notAfter) BIO_write(out, ", ", 2);
+ }
+ if(usage->notAfter) {
+ BIO_write(out, "Not After: ", 11);
+ ASN1_GENERALIZEDTIME_print(out, usage->notAfter);
+ }
+ return 1;
+}
+
+/*
+static PKEY_USAGE_PERIOD *v2i_PKEY_USAGE_PERIOD(method, ctx, values)
+X509V3_EXT_METHOD *method;
+X509V3_CTX *ctx;
+STACK_OF(CONF_VALUE) *values;
+{
+return NULL;
+}
+*/
diff --git a/crypto/x509v3/v3_pmaps.c b/crypto/x509v3/v3_pmaps.c
new file mode 100644
index 0000000..fbc169d
--- /dev/null
+++ b/crypto/x509v3/v3_pmaps.c
@@ -0,0 +1,156 @@
+/* v3_pmaps.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project.
+ */
+/* ====================================================================
+ * Copyright (c) 2003 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 <stdio.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/conf.h>
+#include <openssl/err.h>
+#include <openssl/obj.h>
+#include <openssl/x509v3.h>
+
+
+static void *v2i_POLICY_MAPPINGS(const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval);
+static STACK_OF(CONF_VALUE) *
+i2v_POLICY_MAPPINGS(const X509V3_EXT_METHOD *method, void *pmps,
+ STACK_OF(CONF_VALUE) *extlist);
+
+const X509V3_EXT_METHOD v3_policy_mappings = {
+ NID_policy_mappings, 0,
+ ASN1_ITEM_ref(POLICY_MAPPINGS),
+ 0,0,0,0,
+ 0,0,
+ i2v_POLICY_MAPPINGS,
+ v2i_POLICY_MAPPINGS,
+ 0,0,
+ NULL
+};
+
+ASN1_SEQUENCE(POLICY_MAPPING) = {
+ ASN1_SIMPLE(POLICY_MAPPING, issuerDomainPolicy, ASN1_OBJECT),
+ ASN1_SIMPLE(POLICY_MAPPING, subjectDomainPolicy, ASN1_OBJECT)
+} ASN1_SEQUENCE_END(POLICY_MAPPING)
+
+ASN1_ITEM_TEMPLATE(POLICY_MAPPINGS) =
+ ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, POLICY_MAPPINGS,
+ POLICY_MAPPING)
+ASN1_ITEM_TEMPLATE_END(POLICY_MAPPINGS)
+
+IMPLEMENT_ASN1_ALLOC_FUNCTIONS(POLICY_MAPPING)
+
+
+static STACK_OF(CONF_VALUE) *
+i2v_POLICY_MAPPINGS(const X509V3_EXT_METHOD *method, void *a,
+ STACK_OF(CONF_VALUE) *ext_list)
+{
+ POLICY_MAPPINGS *pmaps = a;
+ POLICY_MAPPING *pmap;
+ size_t i;
+ char obj_tmp1[80];
+ char obj_tmp2[80];
+ for(i = 0; i < sk_POLICY_MAPPING_num(pmaps); i++) {
+ pmap = sk_POLICY_MAPPING_value(pmaps, i);
+ i2t_ASN1_OBJECT(obj_tmp1, 80, pmap->issuerDomainPolicy);
+ i2t_ASN1_OBJECT(obj_tmp2, 80, pmap->subjectDomainPolicy);
+ X509V3_add_value(obj_tmp1, obj_tmp2, &ext_list);
+ }
+ return ext_list;
+}
+
+static void *v2i_POLICY_MAPPINGS(const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
+{
+ POLICY_MAPPINGS *pmaps;
+ POLICY_MAPPING *pmap;
+ ASN1_OBJECT *obj1, *obj2;
+ CONF_VALUE *val;
+ size_t i;
+
+ if(!(pmaps = sk_POLICY_MAPPING_new_null())) {
+ OPENSSL_PUT_ERROR(X509V3, v2i_POLICY_MAPPINGS, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ for(i = 0; i < sk_CONF_VALUE_num(nval); i++) {
+ 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);
+ X509V3_conf_err(val);
+ return NULL;
+ }
+ obj1 = OBJ_txt2obj(val->name, 0);
+ 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);
+ 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);
+ return NULL;
+ }
+ pmap->issuerDomainPolicy = obj1;
+ pmap->subjectDomainPolicy = obj2;
+ sk_POLICY_MAPPING_push(pmaps, pmap);
+ }
+ return pmaps;
+}
diff --git a/crypto/x509v3/v3_prn.c b/crypto/x509v3/v3_prn.c
new file mode 100644
index 0000000..4376e0f
--- /dev/null
+++ b/crypto/x509v3/v3_prn.c
@@ -0,0 +1,237 @@
+/* v3_prn.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999 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). */
+
+/* X509 v3 extension utilities */
+
+#include <stdio.h>
+
+#include <openssl/bio.h>
+#include <openssl/conf.h>
+#include <openssl/mem.h>
+#include <openssl/x509v3.h>
+
+
+/* Extension printing routines */
+
+static int unknown_ext_print(BIO *out, X509_EXTENSION *ext, unsigned long flag, int indent, int supported);
+
+/* Print out a name+value stack */
+
+void X509V3_EXT_val_prn(BIO *out, STACK_OF(CONF_VALUE) *val, int indent, int ml)
+{
+ size_t i;
+ CONF_VALUE *nval;
+ if(!val) return;
+ if(!ml || !sk_CONF_VALUE_num(val)) {
+ BIO_printf(out, "%*s", indent, "");
+ if(!sk_CONF_VALUE_num(val)) BIO_puts(out, "<EMPTY>\n");
+ }
+ for(i = 0; i < sk_CONF_VALUE_num(val); i++) {
+ if(ml) BIO_printf(out, "%*s", indent, "");
+ else if(i > 0) BIO_printf(out, ", ");
+ nval = sk_CONF_VALUE_value(val, i);
+ if(!nval->name) BIO_puts(out, nval->value);
+ else if(!nval->value) BIO_puts(out, nval->name);
+#ifndef CHARSET_EBCDIC
+ else BIO_printf(out, "%s:%s", nval->name, nval->value);
+#else
+ else {
+ int len;
+ char *tmp;
+ len = strlen(nval->value)+1;
+ tmp = OPENSSL_malloc(len);
+ if (tmp)
+ {
+ ascii2ebcdic(tmp, nval->value, len);
+ BIO_printf(out, "%s:%s", nval->name, tmp);
+ OPENSSL_free(tmp);
+ }
+ }
+#endif
+ if(ml) BIO_puts(out, "\n");
+ }
+}
+
+/* Main routine: print out a general extension */
+
+int X509V3_EXT_print(BIO *out, X509_EXTENSION *ext, unsigned long flag, int indent)
+{
+ void *ext_str = NULL;
+ char *value = NULL;
+ const unsigned char *p;
+ const X509V3_EXT_METHOD *method;
+ STACK_OF(CONF_VALUE) *nval = NULL;
+ int ok = 1;
+
+ if(!(method = X509V3_EXT_get(ext)))
+ return unknown_ext_print(out, ext, flag, indent, 0);
+ p = ext->value->data;
+ if(method->it) ext_str = ASN1_item_d2i(NULL, &p, ext->value->length, ASN1_ITEM_ptr(method->it));
+ else ext_str = method->d2i(NULL, &p, ext->value->length);
+
+ if(!ext_str) return unknown_ext_print(out, ext, flag, indent, 1);
+
+ if(method->i2s) {
+ if(!(value = method->i2s(method, ext_str))) {
+ ok = 0;
+ goto err;
+ }
+#ifndef CHARSET_EBCDIC
+ BIO_printf(out, "%*s%s", indent, "", value);
+#else
+ {
+ int len;
+ char *tmp;
+ len = strlen(value)+1;
+ tmp = OPENSSL_malloc(len);
+ if (tmp)
+ {
+ ascii2ebcdic(tmp, value, len);
+ BIO_printf(out, "%*s%s", indent, "", tmp);
+ OPENSSL_free(tmp);
+ }
+ }
+#endif
+ } else if(method->i2v) {
+ if(!(nval = method->i2v(method, ext_str, NULL))) {
+ ok = 0;
+ goto err;
+ }
+ X509V3_EXT_val_prn(out, nval, indent,
+ method->ext_flags & X509V3_EXT_MULTILINE);
+ } else if(method->i2r) {
+ if(!method->i2r(method, ext_str, out, indent)) ok = 0;
+ } else ok = 0;
+
+ err:
+ sk_CONF_VALUE_pop_free(nval, X509V3_conf_free);
+ if(value) OPENSSL_free(value);
+ if(method->it) ASN1_item_free(ext_str, ASN1_ITEM_ptr(method->it));
+ else method->ext_free(ext_str);
+ return ok;
+}
+
+int X509V3_extensions_print(BIO *bp, char *title, STACK_OF(X509_EXTENSION) *exts, unsigned long flag, int indent)
+{
+ size_t i;
+ int j;
+
+ if(sk_X509_EXTENSION_num(exts) <= 0) return 1;
+
+ if(title)
+ {
+ BIO_printf(bp,"%*s%s:\n",indent, "", title);
+ indent += 4;
+ }
+
+ for (i=0; i<sk_X509_EXTENSION_num(exts); i++)
+ {
+ ASN1_OBJECT *obj;
+ X509_EXTENSION *ex;
+ ex=sk_X509_EXTENSION_value(exts, i);
+ if (indent && BIO_printf(bp,"%*s",indent, "") <= 0) return 0;
+ obj=X509_EXTENSION_get_object(ex);
+ i2a_ASN1_OBJECT(bp,obj);
+ j=X509_EXTENSION_get_critical(ex);
+ if (BIO_printf(bp,": %s\n",j?"critical":"") <= 0)
+ return 0;
+ if(!X509V3_EXT_print(bp, ex, flag, indent + 4))
+ {
+ BIO_printf(bp, "%*s", indent + 4, "");
+ M_ASN1_OCTET_STRING_print(bp,ex->value);
+ }
+ if (BIO_write(bp,"\n",1) <= 0) return 0;
+ }
+ return 1;
+}
+
+static int unknown_ext_print(BIO *out, X509_EXTENSION *ext, unsigned long flag, int indent, int supported)
+{
+ switch(flag & X509V3_EXT_UNKNOWN_MASK) {
+
+ case X509V3_EXT_DEFAULT:
+ return 0;
+
+ case X509V3_EXT_ERROR_UNKNOWN:
+ if(supported)
+ BIO_printf(out, "%*s<Parse Error>", indent, "");
+ else
+ BIO_printf(out, "%*s<Not Supported>", indent, "");
+ return 1;
+
+ case X509V3_EXT_PARSE_UNKNOWN:
+ return ASN1_parse_dump(out,
+ ext->value->data, ext->value->length, indent, -1);
+ case X509V3_EXT_DUMP_UNKNOWN:
+ return BIO_hexdump(out, ext->value->data, ext->value->length, indent);
+
+ default:
+ return 1;
+ }
+}
+
+
+#ifndef OPENSSL_NO_FP_API
+int X509V3_EXT_print_fp(FILE *fp, X509_EXTENSION *ext, int flag, int indent)
+{
+ BIO *bio_tmp;
+ int ret;
+ if(!(bio_tmp = BIO_new_fp(fp, BIO_NOCLOSE))) return 0;
+ ret = X509V3_EXT_print(bio_tmp, ext, flag, indent);
+ BIO_free(bio_tmp);
+ return ret;
+}
+#endif
diff --git a/crypto/x509v3/v3_purp.c b/crypto/x509v3/v3_purp.c
new file mode 100644
index 0000000..8f7279c
--- /dev/null
+++ b/crypto/x509v3/v3_purp.c
@@ -0,0 +1,767 @@
+/* v3_purp.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 2001.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2004 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 <stdio.h>
+
+#include <openssl/buf.h>
+#include <openssl/err.h>
+#include <openssl/digest.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509_vfy.h>
+#include <openssl/x509v3.h>
+
+
+static void x509v3_cache_extensions(X509 *x);
+
+static int check_ssl_ca(const X509 *x);
+static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x, int ca);
+static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca);
+static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca);
+static int purpose_smime(const X509 *x, int ca);
+static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x, int ca);
+static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x, int ca);
+static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x, int ca);
+static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x, int ca);
+static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca);
+static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca);
+
+static int xp_cmp(const X509_PURPOSE **a, const X509_PURPOSE **b);
+static void xptable_free(X509_PURPOSE *p);
+
+static X509_PURPOSE xstandard[] = {
+ {X509_PURPOSE_SSL_CLIENT, X509_TRUST_SSL_CLIENT, 0, check_purpose_ssl_client, "SSL client", "sslclient", NULL},
+ {X509_PURPOSE_SSL_SERVER, X509_TRUST_SSL_SERVER, 0, check_purpose_ssl_server, "SSL server", "sslserver", NULL},
+ {X509_PURPOSE_NS_SSL_SERVER, X509_TRUST_SSL_SERVER, 0, check_purpose_ns_ssl_server, "Netscape SSL server", "nssslserver", NULL},
+ {X509_PURPOSE_SMIME_SIGN, X509_TRUST_EMAIL, 0, check_purpose_smime_sign, "S/MIME signing", "smimesign", NULL},
+ {X509_PURPOSE_SMIME_ENCRYPT, X509_TRUST_EMAIL, 0, check_purpose_smime_encrypt, "S/MIME encryption", "smimeencrypt", NULL},
+ {X509_PURPOSE_CRL_SIGN, X509_TRUST_COMPAT, 0, check_purpose_crl_sign, "CRL signing", "crlsign", NULL},
+ {X509_PURPOSE_ANY, X509_TRUST_DEFAULT, 0, no_check, "Any Purpose", "any", NULL},
+ {X509_PURPOSE_OCSP_HELPER, X509_TRUST_COMPAT, 0, ocsp_helper, "OCSP helper", "ocsphelper", NULL},
+ {X509_PURPOSE_TIMESTAMP_SIGN, X509_TRUST_TSA, 0, check_purpose_timestamp_sign, "Time Stamp signing", "timestampsign", NULL},
+};
+
+#define X509_PURPOSE_COUNT (sizeof(xstandard)/sizeof(X509_PURPOSE))
+
+static STACK_OF(X509_PURPOSE) *xptable = NULL;
+
+static int xp_cmp(const X509_PURPOSE **a, const X509_PURPOSE **b)
+{
+ return (*a)->purpose - (*b)->purpose;
+}
+
+/* As much as I'd like to make X509_check_purpose use a "const" X509*
+ * I really can't because it does recalculate hashes and do other non-const
+ * things. */
+int X509_check_purpose(X509 *x, int id, int ca)
+{
+ int idx;
+ const X509_PURPOSE *pt;
+ if(!(x->ex_flags & EXFLAG_SET)) {
+ CRYPTO_w_lock(CRYPTO_LOCK_X509);
+ x509v3_cache_extensions(x);
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509);
+ }
+ if(id == -1) return 1;
+ idx = X509_PURPOSE_get_by_id(id);
+ if(idx == -1) return -1;
+ pt = X509_PURPOSE_get0(idx);
+ return pt->check_purpose(pt, x, ca);
+}
+
+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);
+ return 0;
+ }
+ *p = purpose;
+ return 1;
+}
+
+int X509_PURPOSE_get_count(void)
+{
+ if(!xptable) return X509_PURPOSE_COUNT;
+ return sk_X509_PURPOSE_num(xptable) + X509_PURPOSE_COUNT;
+}
+
+X509_PURPOSE * X509_PURPOSE_get0(int idx)
+{
+ if(idx < 0) return NULL;
+ if(idx < (int)X509_PURPOSE_COUNT) return xstandard + idx;
+ return sk_X509_PURPOSE_value(xptable, idx - X509_PURPOSE_COUNT);
+}
+
+int X509_PURPOSE_get_by_sname(char *sname)
+{
+ int i;
+ X509_PURPOSE *xptmp;
+ for(i = 0; i < X509_PURPOSE_get_count(); i++) {
+ xptmp = X509_PURPOSE_get0(i);
+ if(!strcmp(xptmp->sname, sname)) return i;
+ }
+ return -1;
+}
+
+int X509_PURPOSE_get_by_id(int purpose)
+{
+ X509_PURPOSE tmp;
+ size_t idx;
+
+ if((purpose >= X509_PURPOSE_MIN) && (purpose <= X509_PURPOSE_MAX))
+ return purpose - X509_PURPOSE_MIN;
+ tmp.purpose = purpose;
+ if(!xptable) return -1;
+
+ if (!sk_X509_PURPOSE_find(xptable, &idx, &tmp))
+ return -1;
+ return idx + X509_PURPOSE_COUNT;
+}
+
+int X509_PURPOSE_add(int id, int trust, int flags,
+ int (*ck)(const X509_PURPOSE *, const X509 *, int),
+ char *name, char *sname, void *arg)
+{
+ int idx;
+ X509_PURPOSE *ptmp;
+ /* This is set according to what we change: application can't set it */
+ flags &= ~X509_PURPOSE_DYNAMIC;
+ /* This will always be set for application modified trust entries */
+ flags |= X509_PURPOSE_DYNAMIC_NAME;
+ /* Get existing entry if any */
+ idx = X509_PURPOSE_get_by_id(id);
+ /* 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);
+ return 0;
+ }
+ ptmp->flags = X509_PURPOSE_DYNAMIC;
+ } else ptmp = X509_PURPOSE_get0(idx);
+
+ /* OPENSSL_free existing name if dynamic */
+ if(ptmp->flags & X509_PURPOSE_DYNAMIC_NAME) {
+ OPENSSL_free(ptmp->name);
+ OPENSSL_free(ptmp->sname);
+ }
+ /* dup supplied name */
+ ptmp->name = BUF_strdup(name);
+ ptmp->sname = BUF_strdup(sname);
+ if(!ptmp->name || !ptmp->sname) {
+ OPENSSL_PUT_ERROR(X509V3, X509_PURPOSE_add, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ /* Keep the dynamic flag of existing entry */
+ ptmp->flags &= X509_PURPOSE_DYNAMIC;
+ /* Set all other flags */
+ ptmp->flags |= flags;
+
+ ptmp->purpose = id;
+ ptmp->trust = trust;
+ ptmp->check_purpose = ck;
+ ptmp->usr_data = arg;
+
+ /* 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);
+ return 0;
+ }
+ if (!sk_X509_PURPOSE_push(xptable, ptmp)) {
+ OPENSSL_PUT_ERROR(X509V3, X509_PURPOSE_add, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void xptable_free(X509_PURPOSE *p)
+ {
+ if(!p) return;
+ if (p->flags & X509_PURPOSE_DYNAMIC)
+ {
+ if (p->flags & X509_PURPOSE_DYNAMIC_NAME) {
+ OPENSSL_free(p->name);
+ OPENSSL_free(p->sname);
+ }
+ OPENSSL_free(p);
+ }
+ }
+
+void X509_PURPOSE_cleanup(void)
+{
+ unsigned int i;
+ sk_X509_PURPOSE_pop_free(xptable, xptable_free);
+ for(i = 0; i < X509_PURPOSE_COUNT; i++) xptable_free(xstandard + i);
+ xptable = NULL;
+}
+
+int X509_PURPOSE_get_id(X509_PURPOSE *xp)
+{
+ return xp->purpose;
+}
+
+char *X509_PURPOSE_get0_name(X509_PURPOSE *xp)
+{
+ return xp->name;
+}
+
+char *X509_PURPOSE_get0_sname(X509_PURPOSE *xp)
+{
+ return xp->sname;
+}
+
+int X509_PURPOSE_get_trust(X509_PURPOSE *xp)
+{
+ return xp->trust;
+}
+
+static int nid_cmp(const void *void_a, const void *void_b)
+ {
+ const int *a = void_a, *b = void_b;
+
+ return *a - *b;
+ }
+
+int X509_supported_extension(X509_EXTENSION *ex)
+ {
+ /* This table is a list of the NIDs of supported extensions:
+ * that is those which are used by the verify process. If
+ * an extension is critical and doesn't appear in this list
+ * then the verify process will normally reject the certificate.
+ * The list must be kept in numerical order because it will be
+ * searched using bsearch.
+ */
+
+ static const int supported_nids[] = {
+ NID_netscape_cert_type, /* 71 */
+ NID_key_usage, /* 83 */
+ NID_subject_alt_name, /* 85 */
+ NID_basic_constraints, /* 87 */
+ NID_certificate_policies, /* 89 */
+ NID_ext_key_usage, /* 126 */
+ NID_policy_constraints, /* 401 */
+ NID_proxyCertInfo, /* 663 */
+ NID_name_constraints, /* 666 */
+ NID_policy_mappings, /* 747 */
+ NID_inhibit_any_policy /* 748 */
+ };
+
+ int ex_nid = OBJ_obj2nid(X509_EXTENSION_get_object(ex));
+
+ if (ex_nid == NID_undef)
+ return 0;
+
+ if (bsearch(&ex_nid, supported_nids, sizeof(supported_nids)/sizeof(int), sizeof(int), nid_cmp) != NULL)
+ return 1;
+ return 0;
+ }
+
+static void setup_dp(X509 *x, DIST_POINT *dp)
+ {
+ X509_NAME *iname = NULL;
+ size_t i;
+ if (dp->reasons)
+ {
+ if (dp->reasons->length > 0)
+ dp->dp_reasons = dp->reasons->data[0];
+ if (dp->reasons->length > 1)
+ dp->dp_reasons |= (dp->reasons->data[1] << 8);
+ dp->dp_reasons &= CRLDP_ALL_REASONS;
+ }
+ else
+ dp->dp_reasons = CRLDP_ALL_REASONS;
+ if (!dp->distpoint || (dp->distpoint->type != 1))
+ return;
+ for (i = 0; i < sk_GENERAL_NAME_num(dp->CRLissuer); i++)
+ {
+ GENERAL_NAME *gen = sk_GENERAL_NAME_value(dp->CRLissuer, i);
+ if (gen->type == GEN_DIRNAME)
+ {
+ iname = gen->d.directoryName;
+ break;
+ }
+ }
+ if (!iname)
+ iname = X509_get_issuer_name(x);
+
+ DIST_POINT_set_dpname(dp->distpoint, iname);
+
+ }
+
+static void setup_crldp(X509 *x)
+ {
+ size_t i;
+ x->crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, NULL, NULL);
+ for (i = 0; i < sk_DIST_POINT_num(x->crldp); i++)
+ setup_dp(x, sk_DIST_POINT_value(x->crldp, i));
+ }
+
+static void x509v3_cache_extensions(X509 *x)
+{
+ BASIC_CONSTRAINTS *bs;
+ PROXY_CERT_INFO_EXTENSION *pci;
+ ASN1_BIT_STRING *usage;
+ ASN1_BIT_STRING *ns;
+ EXTENDED_KEY_USAGE *extusage;
+ X509_EXTENSION *ex;
+ size_t i;
+ int j;
+ if(x->ex_flags & EXFLAG_SET) return;
+#ifndef OPENSSL_NO_SHA
+ X509_digest(x, EVP_sha1(), x->sha1_hash, NULL);
+#endif
+ /* Does subject name match issuer ? */
+ if(!X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x)))
+ x->ex_flags |= EXFLAG_SI;
+ /* V1 should mean no extensions ... */
+ if(!X509_get_version(x)) x->ex_flags |= EXFLAG_V1;
+ /* Handle basic constraints */
+ if((bs=X509_get_ext_d2i(x, NID_basic_constraints, NULL, NULL))) {
+ if(bs->ca) x->ex_flags |= EXFLAG_CA;
+ if(bs->pathlen) {
+ if((bs->pathlen->type == V_ASN1_NEG_INTEGER)
+ || !bs->ca) {
+ x->ex_flags |= EXFLAG_INVALID;
+ x->ex_pathlen = 0;
+ } else x->ex_pathlen = ASN1_INTEGER_get(bs->pathlen);
+ } else x->ex_pathlen = -1;
+ BASIC_CONSTRAINTS_free(bs);
+ x->ex_flags |= EXFLAG_BCONS;
+ }
+ /* Handle proxy certificates */
+ if((pci=X509_get_ext_d2i(x, NID_proxyCertInfo, NULL, NULL))) {
+ if (x->ex_flags & EXFLAG_CA
+ || X509_get_ext_by_NID(x, NID_subject_alt_name, 0) >= 0
+ || X509_get_ext_by_NID(x, NID_issuer_alt_name, 0) >= 0) {
+ x->ex_flags |= EXFLAG_INVALID;
+ }
+ if (pci->pcPathLengthConstraint) {
+ x->ex_pcpathlen =
+ ASN1_INTEGER_get(pci->pcPathLengthConstraint);
+ } else x->ex_pcpathlen = -1;
+ PROXY_CERT_INFO_EXTENSION_free(pci);
+ x->ex_flags |= EXFLAG_PROXY;
+ }
+ /* Handle key usage */
+ if((usage=X509_get_ext_d2i(x, NID_key_usage, NULL, NULL))) {
+ if(usage->length > 0) {
+ x->ex_kusage = usage->data[0];
+ if(usage->length > 1)
+ x->ex_kusage |= usage->data[1] << 8;
+ } else x->ex_kusage = 0;
+ x->ex_flags |= EXFLAG_KUSAGE;
+ ASN1_BIT_STRING_free(usage);
+ }
+ x->ex_xkusage = 0;
+ if((extusage=X509_get_ext_d2i(x, NID_ext_key_usage, NULL, NULL))) {
+ x->ex_flags |= EXFLAG_XKUSAGE;
+ for(i = 0; i < sk_ASN1_OBJECT_num(extusage); i++) {
+ switch(OBJ_obj2nid(sk_ASN1_OBJECT_value(extusage,i))) {
+ case NID_server_auth:
+ x->ex_xkusage |= XKU_SSL_SERVER;
+ break;
+
+ case NID_client_auth:
+ x->ex_xkusage |= XKU_SSL_CLIENT;
+ break;
+
+ case NID_email_protect:
+ x->ex_xkusage |= XKU_SMIME;
+ break;
+
+ case NID_code_sign:
+ x->ex_xkusage |= XKU_CODE_SIGN;
+ break;
+
+ case NID_ms_sgc:
+ case NID_ns_sgc:
+ x->ex_xkusage |= XKU_SGC;
+ break;
+
+ case NID_OCSP_sign:
+ x->ex_xkusage |= XKU_OCSP_SIGN;
+ break;
+
+ case NID_time_stamp:
+ x->ex_xkusage |= XKU_TIMESTAMP;
+ break;
+
+ case NID_dvcs:
+ x->ex_xkusage |= XKU_DVCS;
+ break;
+
+ case NID_anyExtendedKeyUsage:
+ x->ex_xkusage |= XKU_ANYEKU;
+ break;
+ }
+ }
+ sk_ASN1_OBJECT_pop_free(extusage, ASN1_OBJECT_free);
+ }
+
+ if((ns=X509_get_ext_d2i(x, NID_netscape_cert_type, NULL, NULL))) {
+ if(ns->length > 0) x->ex_nscert = ns->data[0];
+ else x->ex_nscert = 0;
+ x->ex_flags |= EXFLAG_NSCERT;
+ ASN1_BIT_STRING_free(ns);
+ }
+ x->skid =X509_get_ext_d2i(x, NID_subject_key_identifier, NULL, NULL);
+ x->akid =X509_get_ext_d2i(x, NID_authority_key_identifier, NULL, NULL);
+ x->altname = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL);
+ x->nc = X509_get_ext_d2i(x, NID_name_constraints, &j, NULL);
+ if (!x->nc && (j != -1))
+ x->ex_flags |= EXFLAG_INVALID;
+ setup_crldp(x);
+
+ for (j = 0; j < X509_get_ext_count(x); j++)
+ {
+ ex = X509_get_ext(x, j);
+ if (OBJ_obj2nid(X509_EXTENSION_get_object(ex))
+ == NID_freshest_crl)
+ x->ex_flags |= EXFLAG_FRESHEST;
+ if (!X509_EXTENSION_get_critical(ex))
+ continue;
+ if (!X509_supported_extension(ex))
+ {
+ x->ex_flags |= EXFLAG_CRITICAL;
+ break;
+ }
+ }
+ x->ex_flags |= EXFLAG_SET;
+}
+
+/* CA checks common to all purposes
+ * return codes:
+ * 0 not a CA
+ * 1 is a CA
+ * 2 basicConstraints absent so "maybe" a CA
+ * 3 basicConstraints absent but self signed V1.
+ * 4 basicConstraints absent but keyUsage present and keyCertSign asserted.
+ */
+
+#define V1_ROOT (EXFLAG_V1|EXFLAG_SS)
+#define ku_reject(x, usage) \
+ (((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage)))
+#define xku_reject(x, usage) \
+ (((x)->ex_flags & EXFLAG_XKUSAGE) && !((x)->ex_xkusage & (usage)))
+#define ns_reject(x, usage) \
+ (((x)->ex_flags & EXFLAG_NSCERT) && !((x)->ex_nscert & (usage)))
+
+static int check_ca(const X509 *x)
+{
+ /* keyUsage if present should allow cert signing */
+ if(ku_reject(x, KU_KEY_CERT_SIGN)) return 0;
+ if(x->ex_flags & EXFLAG_BCONS) {
+ if(x->ex_flags & EXFLAG_CA) return 1;
+ /* If basicConstraints says not a CA then say so */
+ else return 0;
+ } else {
+ /* we support V1 roots for... uh, I don't really know why. */
+ if((x->ex_flags & V1_ROOT) == V1_ROOT) return 3;
+ /* If key usage present it must have certSign so tolerate it */
+ else if (x->ex_flags & EXFLAG_KUSAGE) return 4;
+ /* Older certificates could have Netscape-specific CA types */
+ else if (x->ex_flags & EXFLAG_NSCERT
+ && x->ex_nscert & NS_ANY_CA) return 5;
+ /* can this still be regarded a CA certificate? I doubt it */
+ return 0;
+ }
+}
+
+int X509_check_ca(X509 *x)
+{
+ if(!(x->ex_flags & EXFLAG_SET)) {
+ CRYPTO_w_lock(CRYPTO_LOCK_X509);
+ x509v3_cache_extensions(x);
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509);
+ }
+
+ return check_ca(x);
+}
+
+/* Check SSL CA: common checks for SSL client and server */
+static int check_ssl_ca(const X509 *x)
+{
+ int ca_ret;
+ ca_ret = check_ca(x);
+ if(!ca_ret) return 0;
+ /* check nsCertType if present */
+ if(ca_ret != 5 || x->ex_nscert & NS_SSL_CA) return ca_ret;
+ else return 0;
+}
+
+
+static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x, int ca)
+{
+ if(xku_reject(x,XKU_SSL_CLIENT)) return 0;
+ if(ca) return check_ssl_ca(x);
+ /* We need to do digital signatures or key agreement */
+ if(ku_reject(x,KU_DIGITAL_SIGNATURE|KU_KEY_AGREEMENT)) return 0;
+ /* nsCertType if present should allow SSL client use */
+ if(ns_reject(x, NS_SSL_CLIENT)) return 0;
+ return 1;
+}
+/* Key usage needed for TLS/SSL server: digital signature, encipherment or
+ * key agreement. The ssl code can check this more thoroughly for individual
+ * key types.
+ */
+#define KU_TLS \
+ KU_DIGITAL_SIGNATURE|KU_KEY_ENCIPHERMENT|KU_KEY_AGREEMENT
+
+static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca)
+{
+ if(xku_reject(x,XKU_SSL_SERVER|XKU_SGC)) return 0;
+ if(ca) return check_ssl_ca(x);
+
+ if(ns_reject(x, NS_SSL_SERVER)) return 0;
+ if(ku_reject(x, KU_TLS)) return 0;
+
+ return 1;
+
+}
+
+static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca)
+{
+ int ret;
+ ret = check_purpose_ssl_server(xp, x, ca);
+ if(!ret || ca) return ret;
+ /* We need to encipher or Netscape complains */
+ if(ku_reject(x, KU_KEY_ENCIPHERMENT)) return 0;
+ return ret;
+}
+
+/* common S/MIME checks */
+static int purpose_smime(const X509 *x, int ca)
+{
+ if(xku_reject(x,XKU_SMIME)) return 0;
+ if(ca) {
+ int ca_ret;
+ ca_ret = check_ca(x);
+ if(!ca_ret) return 0;
+ /* check nsCertType if present */
+ if(ca_ret != 5 || x->ex_nscert & NS_SMIME_CA) return ca_ret;
+ else return 0;
+ }
+ if(x->ex_flags & EXFLAG_NSCERT) {
+ if(x->ex_nscert & NS_SMIME) return 1;
+ /* Workaround for some buggy certificates */
+ if(x->ex_nscert & NS_SSL_CLIENT) return 2;
+ return 0;
+ }
+ return 1;
+}
+
+static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x, int ca)
+{
+ int ret;
+ ret = purpose_smime(x, ca);
+ if(!ret || ca) return ret;
+ if(ku_reject(x, KU_DIGITAL_SIGNATURE|KU_NON_REPUDIATION)) return 0;
+ return ret;
+}
+
+static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x, int ca)
+{
+ int ret;
+ ret = purpose_smime(x, ca);
+ if(!ret || ca) return ret;
+ if(ku_reject(x, KU_KEY_ENCIPHERMENT)) return 0;
+ return ret;
+}
+
+static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x, int ca)
+{
+ if(ca) {
+ int ca_ret;
+ if((ca_ret = check_ca(x)) != 2) return ca_ret;
+ else return 0;
+ }
+ if(ku_reject(x, KU_CRL_SIGN)) return 0;
+ return 1;
+}
+
+/* OCSP helper: this is *not* a full OCSP check. It just checks that
+ * each CA is valid. Additional checks must be made on the chain.
+ */
+
+static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca)
+{
+ /* Must be a valid CA. Should we really support the "I don't know"
+ value (2)? */
+ if(ca) return check_ca(x);
+ /* leaf certificate is checked in OCSP_verify() */
+ return 1;
+}
+
+static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x,
+ int ca)
+{
+ int i_ext;
+
+ /* If ca is true we must return if this is a valid CA certificate. */
+ if (ca) return check_ca(x);
+
+ /*
+ * Check the optional key usage field:
+ * if Key Usage is present, it must be one of digitalSignature
+ * and/or nonRepudiation (other values are not consistent and shall
+ * be rejected).
+ */
+ if ((x->ex_flags & EXFLAG_KUSAGE)
+ && ((x->ex_kusage & ~(KU_NON_REPUDIATION | KU_DIGITAL_SIGNATURE)) ||
+ !(x->ex_kusage & (KU_NON_REPUDIATION | KU_DIGITAL_SIGNATURE))))
+ return 0;
+
+ /* Only time stamp key usage is permitted and it's required. */
+ if (!(x->ex_flags & EXFLAG_XKUSAGE) || x->ex_xkusage != XKU_TIMESTAMP)
+ return 0;
+
+ /* Extended Key Usage MUST be critical */
+ i_ext = X509_get_ext_by_NID((X509 *) x, NID_ext_key_usage, 0);
+ if (i_ext >= 0)
+ {
+ X509_EXTENSION *ext = X509_get_ext((X509 *) x, i_ext);
+ if (!X509_EXTENSION_get_critical(ext))
+ return 0;
+ }
+
+ return 1;
+}
+
+static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca)
+{
+ return 1;
+}
+
+/* Various checks to see if one certificate issued the second.
+ * This can be used to prune a set of possible issuer certificates
+ * which have been looked up using some simple method such as by
+ * subject name.
+ * These are:
+ * 1. Check issuer_name(subject) == subject_name(issuer)
+ * 2. If akid(subject) exists check it matches issuer
+ * 3. If key_usage(issuer) exists check it supports certificate signing
+ * returns 0 for OK, positive for reason for mismatch, reasons match
+ * codes for X509_verify_cert()
+ */
+
+int X509_check_issued(X509 *issuer, X509 *subject)
+{
+ if(X509_NAME_cmp(X509_get_subject_name(issuer),
+ X509_get_issuer_name(subject)))
+ return X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
+ x509v3_cache_extensions(issuer);
+ x509v3_cache_extensions(subject);
+
+ if(subject->akid)
+ {
+ int ret = X509_check_akid(issuer, subject->akid);
+ if (ret != X509_V_OK)
+ return ret;
+ }
+
+ if(subject->ex_flags & EXFLAG_PROXY)
+ {
+ if(ku_reject(issuer, KU_DIGITAL_SIGNATURE))
+ return X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE;
+ }
+ else if(ku_reject(issuer, KU_KEY_CERT_SIGN))
+ return X509_V_ERR_KEYUSAGE_NO_CERTSIGN;
+ return X509_V_OK;
+}
+
+int X509_check_akid(X509 *issuer, AUTHORITY_KEYID *akid)
+ {
+
+ if(!akid)
+ return X509_V_OK;
+
+ /* Check key ids (if present) */
+ if(akid->keyid && issuer->skid &&
+ ASN1_OCTET_STRING_cmp(akid->keyid, issuer->skid) )
+ return X509_V_ERR_AKID_SKID_MISMATCH;
+ /* Check serial number */
+ if(akid->serial &&
+ ASN1_INTEGER_cmp(X509_get_serialNumber(issuer), akid->serial))
+ return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
+ /* Check issuer name */
+ if(akid->issuer)
+ {
+ /* Ugh, for some peculiar reason AKID includes
+ * SEQUENCE OF GeneralName. So look for a DirName.
+ * There may be more than one but we only take any
+ * notice of the first.
+ */
+ GENERAL_NAMES *gens;
+ GENERAL_NAME *gen;
+ X509_NAME *nm = NULL;
+ size_t i;
+ gens = akid->issuer;
+ for(i = 0; i < sk_GENERAL_NAME_num(gens); i++)
+ {
+ gen = sk_GENERAL_NAME_value(gens, i);
+ if(gen->type == GEN_DIRNAME)
+ {
+ nm = gen->d.dirn;
+ break;
+ }
+ }
+ if(nm && X509_NAME_cmp(nm, X509_get_issuer_name(issuer)))
+ return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
+ }
+ return X509_V_OK;
+ }
+
diff --git a/crypto/x509v3/v3_skey.c b/crypto/x509v3/v3_skey.c
new file mode 100644
index 0000000..116679a
--- /dev/null
+++ b/crypto/x509v3/v3_skey.c
@@ -0,0 +1,147 @@
+/* v3_skey.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999 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 <stdio.h>
+
+#include <openssl/digest.h>
+#include <openssl/err.h>
+#include <openssl/obj.h>
+#include <openssl/x509v3.h>
+
+
+static ASN1_OCTET_STRING *s2i_skey_id(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, char *str);
+const X509V3_EXT_METHOD v3_skey_id = {
+NID_subject_key_identifier, 0, ASN1_ITEM_ref(ASN1_OCTET_STRING),
+0,0,0,0,
+(X509V3_EXT_I2S)i2s_ASN1_OCTET_STRING,
+(X509V3_EXT_S2I)s2i_skey_id,
+0,0,0,0,
+NULL};
+
+char *i2s_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method,
+ ASN1_OCTET_STRING *oct)
+{
+ return hex_to_string(oct->data, oct->length);
+}
+
+ASN1_OCTET_STRING *s2i_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, char *str)
+{
+ ASN1_OCTET_STRING *oct;
+ long length;
+
+ if(!(oct = M_ASN1_OCTET_STRING_new())) {
+ OPENSSL_PUT_ERROR(X509V3, s2i_ASN1_OCTET_STRING, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ if(!(oct->data = string_to_hex(str, &length))) {
+ M_ASN1_OCTET_STRING_free(oct);
+ return NULL;
+ }
+
+ oct->length = length;
+
+ return oct;
+
+}
+
+static ASN1_OCTET_STRING *s2i_skey_id(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, char *str)
+{
+ ASN1_OCTET_STRING *oct;
+ ASN1_BIT_STRING *pk;
+ unsigned char pkey_dig[EVP_MAX_MD_SIZE];
+ unsigned int diglen;
+
+ 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);
+ 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);
+ goto err;
+ }
+
+ if(ctx->subject_req)
+ pk = ctx->subject_req->req_info->pubkey->public_key;
+ else pk = ctx->subject_cert->cert_info->key->public_key;
+
+ if(!pk) {
+ OPENSSL_PUT_ERROR(X509V3, s2i_skey_id, X509V3_R_NO_PUBLIC_KEY);
+ goto err;
+ }
+
+ if (!EVP_Digest(pk->data, pk->length, pkey_dig, &diglen, EVP_sha1(), NULL))
+ goto err;
+
+ if(!M_ASN1_OCTET_STRING_set(oct, pkey_dig, diglen)) {
+ OPENSSL_PUT_ERROR(X509V3, s2i_skey_id, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ return oct;
+
+ err:
+ M_ASN1_OCTET_STRING_free(oct);
+ return NULL;
+}
diff --git a/crypto/x509v3/v3_sxnet.c b/crypto/x509v3/v3_sxnet.c
new file mode 100644
index 0000000..7b8e3c5
--- /dev/null
+++ b/crypto/x509v3/v3_sxnet.c
@@ -0,0 +1,265 @@
+/* v3_sxnet.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999 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 <stdio.h>
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+#include <openssl/conf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509v3.h>
+
+
+/* Support for Thawte strong extranet extension */
+
+#define SXNET_TEST
+
+static int sxnet_i2r(X509V3_EXT_METHOD *method, SXNET *sx, BIO *out, int indent);
+#ifdef SXNET_TEST
+static SXNET * sxnet_v2i(X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *nval);
+#endif
+const X509V3_EXT_METHOD v3_sxnet = {
+NID_sxnet, X509V3_EXT_MULTILINE, ASN1_ITEM_ref(SXNET),
+0,0,0,0,
+0,0,
+0,
+#ifdef SXNET_TEST
+(X509V3_EXT_V2I)sxnet_v2i,
+#else
+0,
+#endif
+(X509V3_EXT_I2R)sxnet_i2r,
+0,
+NULL
+};
+
+ASN1_SEQUENCE(SXNETID) = {
+ ASN1_SIMPLE(SXNETID, zone, ASN1_INTEGER),
+ ASN1_SIMPLE(SXNETID, user, ASN1_OCTET_STRING)
+} ASN1_SEQUENCE_END(SXNETID)
+
+IMPLEMENT_ASN1_FUNCTIONS(SXNETID)
+
+ASN1_SEQUENCE(SXNET) = {
+ ASN1_SIMPLE(SXNET, version, ASN1_INTEGER),
+ ASN1_SEQUENCE_OF(SXNET, ids, SXNETID)
+} ASN1_SEQUENCE_END(SXNET)
+
+IMPLEMENT_ASN1_FUNCTIONS(SXNET)
+
+static int sxnet_i2r(X509V3_EXT_METHOD *method, SXNET *sx, BIO *out,
+ int indent)
+{
+ long v;
+ char *tmp;
+ SXNETID *id;
+ size_t i;
+ v = ASN1_INTEGER_get(sx->version);
+ BIO_printf(out, "%*sVersion: %ld (0x%lX)", indent, "", v + 1, v);
+ for(i = 0; i < sk_SXNETID_num(sx->ids); i++) {
+ id = sk_SXNETID_value(sx->ids, i);
+ tmp = i2s_ASN1_INTEGER(NULL, id->zone);
+ BIO_printf(out, "\n%*sZone: %s, User: ", indent, "", tmp);
+ OPENSSL_free(tmp);
+ M_ASN1_OCTET_STRING_print(out, id->user);
+ }
+ return 1;
+}
+
+#ifdef SXNET_TEST
+
+/* NBB: this is used for testing only. It should *not* be used for anything
+ * else because it will just take static IDs from the configuration file and
+ * they should really be separate values for each user.
+ */
+
+
+static SXNET * sxnet_v2i(X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
+ STACK_OF(CONF_VALUE) *nval)
+{
+ CONF_VALUE *cnf;
+ SXNET *sx = NULL;
+ size_t i;
+ for(i = 0; i < sk_CONF_VALUE_num(nval); i++) {
+ cnf = sk_CONF_VALUE_value(nval, i);
+ if(!SXNET_add_id_asc(&sx, cnf->name, cnf->value, -1))
+ return NULL;
+ }
+ return sx;
+}
+
+
+#endif
+
+/* Strong Extranet utility functions */
+
+/* Add an id given the zone as an ASCII number */
+
+int SXNET_add_id_asc(SXNET **psx, char *zone, char *user,
+ int userlen)
+{
+ ASN1_INTEGER *izone = NULL;
+ if(!(izone = s2i_ASN1_INTEGER(NULL, zone))) {
+ OPENSSL_PUT_ERROR(X509V3, SXNET_add_id_asc, X509V3_R_ERROR_CONVERTING_ZONE);
+ return 0;
+ }
+ return SXNET_add_id_INTEGER(psx, izone, user, userlen);
+}
+
+/* Add an id given the zone as an unsigned long */
+
+int SXNET_add_id_ulong(SXNET **psx, unsigned long lzone, char *user,
+ int userlen)
+{
+ 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);
+ M_ASN1_INTEGER_free(izone);
+ return 0;
+ }
+ return SXNET_add_id_INTEGER(psx, izone, user, userlen);
+
+}
+
+/* Add an id given the zone as an ASN1_INTEGER.
+ * Note this version uses the passed integer and doesn't make a copy so don't
+ * free it up afterwards.
+ */
+
+int SXNET_add_id_INTEGER(SXNET **psx, ASN1_INTEGER *zone, char *user,
+ int userlen)
+{
+ SXNET *sx = NULL;
+ SXNETID *id = NULL;
+ if(!psx || !zone || !user) {
+ OPENSSL_PUT_ERROR(X509V3, SXNET_add_id_INTEGER, 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);
+ return 0;
+ }
+ if(!*psx) {
+ if(!(sx = SXNET_new())) goto err;
+ if(!ASN1_INTEGER_set(sx->version, 0)) goto err;
+ *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);
+ return 0;
+ }
+
+ if(!(id = SXNETID_new())) goto err;
+ if(userlen == -1) userlen = strlen(user);
+
+ if(!M_ASN1_OCTET_STRING_set(id->user, user, userlen)) goto err;
+ if(!sk_SXNETID_push(sx->ids, id)) goto err;
+ id->zone = zone;
+ return 1;
+
+ err:
+ OPENSSL_PUT_ERROR(X509V3, SXNET_add_id_INTEGER, ERR_R_MALLOC_FAILURE);
+ SXNETID_free(id);
+ SXNET_free(sx);
+ *psx = NULL;
+ return 0;
+}
+
+ASN1_OCTET_STRING *SXNET_get_id_asc(SXNET *sx, char *zone)
+{
+ 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);
+ return NULL;
+ }
+ oct = SXNET_get_id_INTEGER(sx, izone);
+ M_ASN1_INTEGER_free(izone);
+ return oct;
+}
+
+ASN1_OCTET_STRING *SXNET_get_id_ulong(SXNET *sx, unsigned long lzone)
+{
+ 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);
+ M_ASN1_INTEGER_free(izone);
+ return NULL;
+ }
+ oct = SXNET_get_id_INTEGER(sx, izone);
+ M_ASN1_INTEGER_free(izone);
+ return oct;
+}
+
+ASN1_OCTET_STRING *SXNET_get_id_INTEGER(SXNET *sx, ASN1_INTEGER *zone)
+{
+ SXNETID *id;
+ size_t i;
+ for(i = 0; i < sk_SXNETID_num(sx->ids); i++) {
+ id = sk_SXNETID_value(sx->ids, i);
+ if(!M_ASN1_INTEGER_cmp(id->zone, zone)) return id->user;
+ }
+ return NULL;
+}
+
+IMPLEMENT_ASN1_SET_OF(SXNETID)
diff --git a/crypto/x509v3/v3_utl.c b/crypto/x509v3/v3_utl.c
new file mode 100644
index 0000000..a4df78c
--- /dev/null
+++ b/crypto/x509v3/v3_utl.c
@@ -0,0 +1,1181 @@
+/* v3_utl.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2003 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).
+ *
+ */
+/* X509 v3 extension utilities */
+
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include <openssl/bn.h>
+#include <openssl/buf.h>
+#include <openssl/conf.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
+#include <openssl/obj.h>
+#include <openssl/x509v3.h>
+
+
+static char *strip_spaces(char *name);
+static int sk_strcmp(const OPENSSL_STRING *a, const OPENSSL_STRING *b);
+static STACK_OF(OPENSSL_STRING) *get_email(X509_NAME *name, GENERAL_NAMES *gens);
+static void str_free(OPENSSL_STRING str);
+static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, ASN1_IA5STRING *email);
+
+static int ipv4_from_asc(unsigned char *v4, const char *in);
+static int ipv6_from_asc(unsigned char *v6, const char *in);
+static int ipv6_cb(const char *elem, int len, void *usr);
+static int ipv6_hex(unsigned char *out, const char *in, int inlen);
+
+/* Add a CONF_VALUE name value pair to stack */
+
+int X509V3_add_value(const char *name, const char *value,
+ STACK_OF(CONF_VALUE) **extlist)
+{
+ CONF_VALUE *vtmp = NULL;
+ 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(!*extlist && !(*extlist = sk_CONF_VALUE_new_null())) goto err;
+ vtmp->section = NULL;
+ vtmp->name = tname;
+ vtmp->value = tvalue;
+ if(!sk_CONF_VALUE_push(*extlist, vtmp)) goto err;
+ return 1;
+ err:
+ OPENSSL_PUT_ERROR(X509V3, X509V3_add_value, ERR_R_MALLOC_FAILURE);
+ if(vtmp) OPENSSL_free(vtmp);
+ if(tname) OPENSSL_free(tname);
+ if(tvalue) OPENSSL_free(tvalue);
+ return 0;
+}
+
+int X509V3_add_value_uchar(const char *name, const unsigned char *value,
+ STACK_OF(CONF_VALUE) **extlist)
+ {
+ return X509V3_add_value(name,(const char *)value,extlist);
+ }
+
+/* Free function for STACK_OF(CONF_VALUE) */
+
+void X509V3_conf_free(CONF_VALUE *conf)
+{
+ if(!conf) return;
+ if(conf->name) OPENSSL_free(conf->name);
+ if(conf->value) OPENSSL_free(conf->value);
+ if(conf->section) OPENSSL_free(conf->section);
+ OPENSSL_free(conf);
+}
+
+int X509V3_add_value_bool(const char *name, int asn1_bool,
+ STACK_OF(CONF_VALUE) **extlist)
+{
+ if(asn1_bool) return X509V3_add_value(name, "TRUE", extlist);
+ return X509V3_add_value(name, "FALSE", extlist);
+}
+
+int X509V3_add_value_bool_nf(char *name, int asn1_bool,
+ STACK_OF(CONF_VALUE) **extlist)
+{
+ if(asn1_bool) return X509V3_add_value(name, "TRUE", extlist);
+ return 1;
+}
+
+
+char *i2s_ASN1_ENUMERATED(X509V3_EXT_METHOD *method, ASN1_ENUMERATED *a)
+{
+ BIGNUM *bntmp = NULL;
+ char *strtmp = NULL;
+ 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);
+ BN_free(bntmp);
+ return strtmp;
+}
+
+char *i2s_ASN1_INTEGER(X509V3_EXT_METHOD *method, ASN1_INTEGER *a)
+{
+ BIGNUM *bntmp = NULL;
+ char *strtmp = NULL;
+ 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);
+ BN_free(bntmp);
+ return strtmp;
+}
+
+ASN1_INTEGER *s2i_ASN1_INTEGER(X509V3_EXT_METHOD *method, char *value)
+{
+ BIGNUM *bn = NULL;
+ ASN1_INTEGER *aint;
+ int isneg, ishex;
+ int ret;
+ if (!value) {
+ OPENSSL_PUT_ERROR(X509V3, s2i_ASN1_INTEGER, X509V3_R_INVALID_NULL_VALUE);
+ return 0;
+ }
+ bn = BN_new();
+ if (value[0] == '-') {
+ value++;
+ isneg = 1;
+ } else isneg = 0;
+
+ if (value[0] == '0' && ((value[1] == 'x') || (value[1] == 'X'))) {
+ value += 2;
+ ishex = 1;
+ } else ishex = 0;
+
+ if (ishex) ret = BN_hex2bn(&bn, value);
+ else ret = BN_dec2bn(&bn, value);
+
+ if (!ret || value[ret]) {
+ BN_free(bn);
+ OPENSSL_PUT_ERROR(X509V3, s2i_ASN1_INTEGER, X509V3_R_BN_DEC2BN_ERROR);
+ return 0;
+ }
+
+ if (isneg && BN_is_zero(bn)) isneg = 0;
+
+ 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);
+ return 0;
+ }
+ if (isneg) aint->type |= V_ASN1_NEG;
+ return aint;
+}
+
+int X509V3_add_value_int(const char *name, ASN1_INTEGER *aint,
+ STACK_OF(CONF_VALUE) **extlist)
+{
+ char *strtmp;
+ int ret;
+ if(!aint) return 1;
+ if(!(strtmp = i2s_ASN1_INTEGER(NULL, aint))) return 0;
+ ret = X509V3_add_value(name, strtmp, extlist);
+ OPENSSL_free(strtmp);
+ return ret;
+}
+
+int X509V3_get_value_bool(CONF_VALUE *value, int *asn1_bool)
+{
+ char *btmp;
+ if(!(btmp = value->value)) goto err;
+ if(!strcmp(btmp, "TRUE") || !strcmp(btmp, "true")
+ || !strcmp(btmp, "Y") || !strcmp(btmp, "y")
+ || !strcmp(btmp, "YES") || !strcmp(btmp, "yes")) {
+ *asn1_bool = 0xff;
+ return 1;
+ } else if(!strcmp(btmp, "FALSE") || !strcmp(btmp, "false")
+ || !strcmp(btmp, "N") || !strcmp(btmp, "n")
+ || !strcmp(btmp, "NO") || !strcmp(btmp, "no")) {
+ *asn1_bool = 0;
+ return 1;
+ }
+ err:
+ OPENSSL_PUT_ERROR(X509V3, X509V3_get_value_bool, X509V3_R_INVALID_BOOLEAN_STRING);
+ X509V3_conf_err(value);
+ return 0;
+}
+
+int X509V3_get_value_int(CONF_VALUE *value, ASN1_INTEGER **aint)
+{
+ ASN1_INTEGER *itmp;
+ if(!(itmp = s2i_ASN1_INTEGER(NULL, value->value))) {
+ X509V3_conf_err(value);
+ return 0;
+ }
+ *aint = itmp;
+ return 1;
+}
+
+#define HDR_NAME 1
+#define HDR_VALUE 2
+
+/*#define DEBUG*/
+
+STACK_OF(CONF_VALUE) *X509V3_parse_list(const char *line)
+{
+ char *p, *q, c;
+ char *ntmp, *vtmp;
+ STACK_OF(CONF_VALUE) *values = NULL;
+ char *linebuf;
+ int state;
+ /* We are going to modify the line so copy it first */
+ linebuf = BUF_strdup(line);
+ state = HDR_NAME;
+ ntmp = NULL;
+ /* Go through all characters */
+ for(p = linebuf, q = linebuf; (c = *p) && (c!='\r') && (c!='\n'); p++) {
+
+ switch(state) {
+ case HDR_NAME:
+ if(c == ':') {
+ state = HDR_VALUE;
+ *p = 0;
+ ntmp = strip_spaces(q);
+ if(!ntmp) {
+ OPENSSL_PUT_ERROR(X509V3, X509V3_parse_list, X509V3_R_INVALID_NULL_NAME);
+ goto err;
+ }
+ q = p + 1;
+ } else if(c == ',') {
+ *p = 0;
+ ntmp = strip_spaces(q);
+ q = p + 1;
+#if 0
+ printf("%s\n", ntmp);
+#endif
+ if(!ntmp) {
+ OPENSSL_PUT_ERROR(X509V3, X509V3_parse_list, X509V3_R_INVALID_NULL_NAME);
+ goto err;
+ }
+ X509V3_add_value(ntmp, NULL, &values);
+ }
+ break ;
+
+ case HDR_VALUE:
+ if(c == ',') {
+ state = HDR_NAME;
+ *p = 0;
+ vtmp = strip_spaces(q);
+#if 0
+ printf("%s\n", ntmp);
+#endif
+ if(!vtmp) {
+ OPENSSL_PUT_ERROR(X509V3, X509V3_parse_list, X509V3_R_INVALID_NULL_VALUE);
+ goto err;
+ }
+ X509V3_add_value(ntmp, vtmp, &values);
+ ntmp = NULL;
+ q = p + 1;
+ }
+
+ }
+ }
+
+ if(state == HDR_VALUE) {
+ vtmp = strip_spaces(q);
+#if 0
+ printf("%s=%s\n", ntmp, vtmp);
+#endif
+ if(!vtmp) {
+ OPENSSL_PUT_ERROR(X509V3, X509V3_parse_list, X509V3_R_INVALID_NULL_VALUE);
+ goto err;
+ }
+ X509V3_add_value(ntmp, vtmp, &values);
+ } else {
+ ntmp = strip_spaces(q);
+#if 0
+ printf("%s\n", ntmp);
+#endif
+ if(!ntmp) {
+ OPENSSL_PUT_ERROR(X509V3, X509V3_parse_list, X509V3_R_INVALID_NULL_NAME);
+ goto err;
+ }
+ X509V3_add_value(ntmp, NULL, &values);
+ }
+OPENSSL_free(linebuf);
+return values;
+
+err:
+OPENSSL_free(linebuf);
+sk_CONF_VALUE_pop_free(values, X509V3_conf_free);
+return NULL;
+
+}
+
+/* Delete leading and trailing spaces from a string */
+static char *strip_spaces(char *name)
+{
+ char *p, *q;
+ /* Skip over leading spaces */
+ p = name;
+ while(*p && isspace((unsigned char)*p)) p++;
+ if(!*p) return NULL;
+ q = p + strlen(p) - 1;
+ while((q != p) && isspace((unsigned char)*q)) q--;
+ if(p != q) q[1] = 0;
+ if(!*p) return NULL;
+ return p;
+}
+
+/* hex string utilities */
+
+/* Given a buffer of length 'len' return a OPENSSL_malloc'ed string with its
+ * hex representation
+ * @@@ (Contents of buffer are always kept in ASCII, also on EBCDIC machines)
+ */
+
+char *hex_to_string(const unsigned char *buffer, long len)
+{
+ char *tmp, *q;
+ const unsigned char *p;
+ int i;
+ const static 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);
+ return NULL;
+ }
+ q = tmp;
+ for(i = 0, p = buffer; i < len; i++,p++) {
+ *q++ = hexdig[(*p >> 4) & 0xf];
+ *q++ = hexdig[*p & 0xf];
+ *q++ = ':';
+ }
+ q[-1] = 0;
+#ifdef CHARSET_EBCDIC
+ ebcdic2ascii(tmp, tmp, q - tmp - 1);
+#endif
+
+ return tmp;
+}
+
+/* Give a string of hex digits convert to
+ * a buffer
+ */
+
+unsigned char *string_to_hex(const char *str, long *len)
+{
+ unsigned char *hexbuf, *q;
+ unsigned char ch, cl, *p;
+ if(!str) {
+ OPENSSL_PUT_ERROR(X509V3, string_to_hex, X509V3_R_INVALID_NULL_ARGUMENT);
+ return NULL;
+ }
+ if(!(hexbuf = OPENSSL_malloc(strlen(str) >> 1))) goto err;
+ for(p = (unsigned char *)str, q = hexbuf; *p;) {
+ ch = *p++;
+#ifdef CHARSET_EBCDIC
+ ch = os_toebcdic[ch];
+#endif
+ if(ch == ':') continue;
+ cl = *p++;
+#ifdef CHARSET_EBCDIC
+ cl = os_toebcdic[cl];
+#endif
+ if(!cl) {
+ OPENSSL_PUT_ERROR(X509V3, string_to_hex, X509V3_R_ODD_NUMBER_OF_DIGITS);
+ OPENSSL_free(hexbuf);
+ return NULL;
+ }
+ if(isupper(ch)) ch = tolower(ch);
+ if(isupper(cl)) cl = tolower(cl);
+
+ if((ch >= '0') && (ch <= '9')) ch -= '0';
+ else if ((ch >= 'a') && (ch <= 'f')) ch -= 'a' - 10;
+ else goto badhex;
+
+ if((cl >= '0') && (cl <= '9')) cl -= '0';
+ else if ((cl >= 'a') && (cl <= 'f')) cl -= 'a' - 10;
+ else goto badhex;
+
+ *q++ = (ch << 4) | cl;
+ }
+
+ if(len) *len = q - hexbuf;
+
+ return hexbuf;
+
+ err:
+ if(hexbuf) OPENSSL_free(hexbuf);
+ OPENSSL_PUT_ERROR(X509V3, string_to_hex, ERR_R_MALLOC_FAILURE);
+ return NULL;
+
+ badhex:
+ OPENSSL_free(hexbuf);
+ OPENSSL_PUT_ERROR(X509V3, string_to_hex, X509V3_R_ILLEGAL_HEX_DIGIT);
+ return NULL;
+
+}
+
+/* V2I name comparison function: returns zero if 'name' matches
+ * cmp or cmp.*
+ */
+
+int name_cmp(const char *name, const char *cmp)
+{
+ int len, ret;
+ char c;
+ len = strlen(cmp);
+ if((ret = strncmp(name, cmp, len))) return ret;
+ c = name[len];
+ if(!c || (c=='.')) return 0;
+ return 1;
+}
+
+static int sk_strcmp(const OPENSSL_STRING *a, const OPENSSL_STRING *b)
+{
+ return strcmp(*a, *b);
+}
+
+STACK_OF(OPENSSL_STRING) *X509_get1_email(X509 *x)
+{
+ GENERAL_NAMES *gens;
+ STACK_OF(OPENSSL_STRING) *ret;
+
+ gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL);
+ ret = get_email(X509_get_subject_name(x), gens);
+ sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
+ return ret;
+}
+
+STACK_OF(OPENSSL_STRING) *X509_get1_ocsp(X509 *x)
+{
+ AUTHORITY_INFO_ACCESS *info;
+ STACK_OF(OPENSSL_STRING) *ret = NULL;
+ size_t i;
+
+ info = X509_get_ext_d2i(x, NID_info_access, NULL, NULL);
+ if (!info)
+ return NULL;
+ for (i = 0; i < sk_ACCESS_DESCRIPTION_num(info); i++)
+ {
+ ACCESS_DESCRIPTION *ad = sk_ACCESS_DESCRIPTION_value(info, i);
+ if (OBJ_obj2nid(ad->method) == NID_ad_OCSP)
+ {
+ if (ad->location->type == GEN_URI)
+ {
+ if (!append_ia5(&ret, ad->location->d.uniformResourceIdentifier))
+ break;
+ }
+ }
+ }
+ AUTHORITY_INFO_ACCESS_free(info);
+ return ret;
+}
+
+STACK_OF(OPENSSL_STRING) *X509_REQ_get1_email(X509_REQ *x)
+{
+ GENERAL_NAMES *gens;
+ STACK_OF(X509_EXTENSION) *exts;
+ STACK_OF(OPENSSL_STRING) *ret;
+
+ exts = X509_REQ_get_extensions(x);
+ gens = X509V3_get_d2i(exts, NID_subject_alt_name, NULL, NULL);
+ ret = get_email(X509_REQ_get_subject_name(x), gens);
+ sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
+ sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
+ return ret;
+}
+
+
+static STACK_OF(OPENSSL_STRING) *get_email(X509_NAME *name, GENERAL_NAMES *gens)
+{
+ STACK_OF(OPENSSL_STRING) *ret = NULL;
+ X509_NAME_ENTRY *ne;
+ ASN1_IA5STRING *email;
+ GENERAL_NAME *gen;
+ int i;
+ size_t j;
+ /* Now add any email address(es) to STACK */
+ i = -1;
+ /* First supplied X509_NAME */
+ while((i = X509_NAME_get_index_by_NID(name,
+ NID_pkcs9_emailAddress, i)) >= 0) {
+ ne = X509_NAME_get_entry(name, i);
+ email = X509_NAME_ENTRY_get_data(ne);
+ if(!append_ia5(&ret, email)) return NULL;
+ }
+ for(j = 0; j < sk_GENERAL_NAME_num(gens); j++)
+ {
+ gen = sk_GENERAL_NAME_value(gens, j);
+ if(gen->type != GEN_EMAIL) continue;
+ if(!append_ia5(&ret, gen->d.ia5)) return NULL;
+ }
+ return ret;
+}
+
+static void str_free(OPENSSL_STRING str)
+{
+ OPENSSL_free(str);
+}
+
+static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, ASN1_IA5STRING *email)
+{
+ char *emtmp;
+ /* First some sanity checks */
+ if(email->type != V_ASN1_IA5STRING) return 1;
+ if(!email->data || !email->length) return 1;
+ if(!*sk) *sk = sk_OPENSSL_STRING_new(sk_strcmp);
+ if(!*sk) return 0;
+ /* Don't add duplicates */
+ if(sk_OPENSSL_STRING_find(*sk, NULL, (char *)email->data)) return 1;
+ emtmp = BUF_strdup((char *)email->data);
+ if(!emtmp || !sk_OPENSSL_STRING_push(*sk, emtmp)) {
+ X509_email_free(*sk);
+ *sk = NULL;
+ return 0;
+ }
+ return 1;
+}
+
+void X509_email_free(STACK_OF(OPENSSL_STRING) *sk)
+{
+ sk_OPENSSL_STRING_pop_free(sk, str_free);
+}
+
+typedef int (*equal_fn)(const unsigned char *pattern, size_t pattern_len,
+ const unsigned char *subject, size_t subject_len);
+
+/* Compare while ASCII ignoring case. */
+static int equal_nocase(const unsigned char *pattern, size_t pattern_len,
+ const unsigned char *subject, size_t subject_len)
+ {
+ if (pattern_len != subject_len)
+ return 0;
+ while (pattern_len)
+ {
+ unsigned char l = *pattern;
+ unsigned char r = *subject;
+ /* The pattern must not contain NUL characters. */
+ if (l == 0)
+ return 0;
+ if (l != r)
+ {
+ if ('A' <= l && l <= 'Z')
+ l = (l - 'A') + 'a';
+ if ('A' <= r && r <= 'Z')
+ r = (r - 'A') + 'a';
+ if (l != r)
+ return 0;
+ }
+ ++pattern;
+ ++subject;
+ --pattern_len;
+ }
+ return 1;
+ }
+
+/* Compare using memcmp. */
+static int equal_case(const unsigned char *pattern, size_t pattern_len,
+ const unsigned char *subject, size_t subject_len)
+{
+ /* The pattern must not contain NUL characters. */
+ if (memchr(pattern, '\0', pattern_len) != NULL)
+ return 0;
+ if (pattern_len != subject_len)
+ return 0;
+ return !memcmp(pattern, subject, pattern_len);
+}
+
+/* RFC 5280, section 7.5, requires that only the domain is compared in
+ a case-insensitive manner. */
+static int equal_email(const unsigned char *a, size_t a_len,
+ const unsigned char *b, size_t b_len)
+ {
+ size_t i = a_len;
+ if (a_len != b_len)
+ return 0;
+ /* We search backwards for the '@' character, so that we do
+ not have to deal with quoted local-parts. The domain part
+ is compared in a case-insensitive manner. */
+ while (i > 0)
+ {
+ --i;
+ if (a[i] == '@' || b[i] == '@')
+ {
+ if (!equal_nocase(a + i, a_len - i,
+ b + i, a_len - i))
+ return 0;
+ break;
+ }
+ }
+ if (i == 0)
+ i = a_len;
+ return equal_case(a, i, b, i);
+ }
+
+/* Compare the prefix and suffix with the subject, and check that the
+ characters in-between are valid. */
+static int wildcard_match(const unsigned char *prefix, size_t prefix_len,
+ const unsigned char *suffix, size_t suffix_len,
+ const unsigned char *subject, size_t subject_len)
+ {
+ const unsigned char *wildcard_start;
+ const unsigned char *wildcard_end;
+ const unsigned char *p;
+ if (subject_len < prefix_len + suffix_len)
+ return 0;
+ if (!equal_nocase(prefix, prefix_len, subject, prefix_len))
+ return 0;
+ wildcard_start = subject + prefix_len;
+ wildcard_end = subject + (subject_len - suffix_len);
+ if (!equal_nocase(wildcard_end, suffix_len, suffix, suffix_len))
+ return 0;
+ /* The wildcard must match at least one character. */
+ if (wildcard_start == wildcard_end)
+ return 0;
+ /* Check that the part matched by the wildcard contains only
+ permitted characters and only matches a single label. */
+ for (p = wildcard_start; p != wildcard_end; ++p)
+ if (!(('0' <= *p && *p <= '9') ||
+ ('A' <= *p && *p <= 'Z') ||
+ ('a' <= *p && *p <= 'z') ||
+ *p == '-'))
+ return 0;
+ return 1;
+ }
+
+/* Checks if the memory region consistens of [0-9A-Za-z.-]. */
+static int valid_domain_characters(const unsigned char *p, size_t len)
+ {
+ while (len)
+ {
+ if (!(('0' <= *p && *p <= '9') ||
+ ('A' <= *p && *p <= 'Z') ||
+ ('a' <= *p && *p <= 'z') ||
+ *p == '-' || *p == '.'))
+ return 0;
+ ++p;
+ --len;
+ }
+ return 1;
+ }
+
+/* Find the '*' in a wildcard pattern. If no such character is found
+ or the pattern is otherwise invalid, returns NULL. */
+static const unsigned char *wildcard_find_star(const unsigned char *pattern,
+ size_t pattern_len)
+ {
+ const unsigned char *star = memchr(pattern, '*', pattern_len);
+ size_t dot_count = 0;
+ const unsigned char *suffix_start;
+ size_t suffix_length;
+ if (star == NULL)
+ return NULL;
+ suffix_start = star + 1;
+ suffix_length = (pattern + pattern_len) - (star + 1);
+ if (!(valid_domain_characters(pattern, star - pattern) &&
+ valid_domain_characters(suffix_start, suffix_length)))
+ return NULL;
+ /* Check that the suffix matches at least two labels. */
+ while (suffix_length)
+ {
+ if (*suffix_start == '.')
+ ++dot_count;
+ ++suffix_start;
+ --suffix_length;
+ }
+ if (dot_count < 2)
+ return NULL;
+ return star;
+ }
+
+/* Compare using wildcards. */
+static int equal_wildcard(const unsigned char *pattern, size_t pattern_len,
+ const unsigned char *subject, size_t subject_len)
+ {
+ const unsigned char *star = wildcard_find_star(pattern, pattern_len);
+ if (star == NULL)
+ return equal_nocase(pattern, pattern_len,
+ subject, subject_len);
+ return wildcard_match(pattern, star - pattern,
+ star + 1, (pattern + pattern_len) - star - 1,
+ subject, subject_len);
+ }
+
+/* Compare an ASN1_STRING to a supplied string. If they match
+ * return 1. If cmp_type > 0 only compare if string matches the
+ * type, otherwise convert it to UTF8.
+ */
+
+static int do_check_string(ASN1_STRING *a, int cmp_type, equal_fn equal,
+ const unsigned char *b, size_t blen)
+ {
+ if (!a->data || !a->length)
+ return 0;
+ if (cmp_type > 0)
+ {
+ if (cmp_type != a->type)
+ return 0;
+ if (cmp_type == V_ASN1_IA5STRING)
+ return equal(a->data, a->length, b, blen);
+ if (a->length == (int)blen && !memcmp(a->data, b, blen))
+ return 1;
+ else
+ return 0;
+ }
+ else
+ {
+ int astrlen, rv;
+ unsigned char *astr;
+ astrlen = ASN1_STRING_to_UTF8(&astr, a);
+ if (astrlen < 0)
+ return -1;
+ rv = equal(astr, astrlen, b, blen);
+ OPENSSL_free(astr);
+ return rv;
+ }
+ }
+
+static int do_x509_check(X509 *x, const unsigned char *chk, size_t chklen,
+ unsigned int flags, int check_type)
+ {
+ GENERAL_NAMES *gens = NULL;
+ X509_NAME *name = NULL;
+ size_t i;
+ int j;
+ int cnid;
+ int alt_type;
+ equal_fn equal;
+ if (check_type == GEN_EMAIL)
+ {
+ cnid = NID_pkcs9_emailAddress;
+ alt_type = V_ASN1_IA5STRING;
+ equal = equal_email;
+ }
+ else if (check_type == GEN_DNS)
+ {
+ cnid = NID_commonName;
+ alt_type = V_ASN1_IA5STRING;
+ if (flags & X509_CHECK_FLAG_NO_WILDCARDS)
+ equal = equal_nocase;
+ else
+ equal = equal_wildcard;
+ }
+ else
+ {
+ cnid = 0;
+ alt_type = V_ASN1_OCTET_STRING;
+ equal = equal_case;
+ }
+
+ if (chklen == 0)
+ chklen = strlen((const char *)chk);
+
+ gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL);
+ if (gens)
+ {
+ int rv = 0;
+ for (i = 0; i < sk_GENERAL_NAME_num(gens); i++)
+ {
+ GENERAL_NAME *gen;
+ ASN1_STRING *cstr;
+ gen = sk_GENERAL_NAME_value(gens, i);
+ if(gen->type != check_type)
+ continue;
+ if (check_type == GEN_EMAIL)
+ cstr = gen->d.rfc822Name;
+ else if (check_type == GEN_DNS)
+ cstr = gen->d.dNSName;
+ else
+ cstr = gen->d.iPAddress;
+ if (do_check_string(cstr, alt_type, equal, chk, chklen))
+ {
+ rv = 1;
+ break;
+ }
+ }
+ GENERAL_NAMES_free(gens);
+ if (rv)
+ return 1;
+ if (!(flags & X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT) || !cnid)
+ return 0;
+ }
+ j = -1;
+ name = X509_get_subject_name(x);
+ while((j = X509_NAME_get_index_by_NID(name, cnid, j)) >= 0)
+ {
+ X509_NAME_ENTRY *ne;
+ ASN1_STRING *str;
+ ne = X509_NAME_get_entry(name, j);
+ str = X509_NAME_ENTRY_get_data(ne);
+ if (do_check_string(str, -1, equal, chk, chklen))
+ return 1;
+ }
+ return 0;
+ }
+
+int X509_check_host(X509 *x, const unsigned char *chk, size_t chklen,
+ unsigned int flags)
+ {
+ return do_x509_check(x, chk, chklen, flags, GEN_DNS);
+ }
+
+int X509_check_email(X509 *x, const unsigned char *chk, size_t chklen,
+ unsigned int flags)
+ {
+ return do_x509_check(x, chk, chklen, flags, GEN_EMAIL);
+ }
+
+int X509_check_ip(X509 *x, const unsigned char *chk, size_t chklen,
+ unsigned int flags)
+ {
+ return do_x509_check(x, chk, chklen, flags, GEN_IPADD);
+ }
+
+int X509_check_ip_asc(X509 *x, const char *ipasc, unsigned int flags)
+ {
+ unsigned char ipout[16];
+ int iplen;
+ iplen = a2i_ipadd(ipout, ipasc);
+ if (iplen == 0)
+ return -2;
+ return do_x509_check(x, ipout, (size_t)iplen, flags, GEN_IPADD);
+ }
+
+/* Convert IP addresses both IPv4 and IPv6 into an
+ * OCTET STRING compatible with RFC3280.
+ */
+
+ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc)
+ {
+ unsigned char ipout[16];
+ ASN1_OCTET_STRING *ret;
+ int iplen;
+
+ /* If string contains a ':' assume IPv6 */
+
+ iplen = a2i_ipadd(ipout, ipasc);
+
+ if (!iplen)
+ return NULL;
+
+ ret = ASN1_OCTET_STRING_new();
+ if (!ret)
+ return NULL;
+ if (!ASN1_OCTET_STRING_set(ret, ipout, iplen))
+ {
+ ASN1_OCTET_STRING_free(ret);
+ return NULL;
+ }
+ return ret;
+ }
+
+ASN1_OCTET_STRING *a2i_IPADDRESS_NC(const char *ipasc)
+ {
+ ASN1_OCTET_STRING *ret = NULL;
+ unsigned char ipout[32];
+ char *iptmp = NULL, *p;
+ int iplen1, iplen2;
+ p = strchr(ipasc,'/');
+ if (!p)
+ return NULL;
+ iptmp = BUF_strdup(ipasc);
+ if (!iptmp)
+ return NULL;
+ p = iptmp + (p - ipasc);
+ *p++ = 0;
+
+ iplen1 = a2i_ipadd(ipout, iptmp);
+
+ if (!iplen1)
+ goto err;
+
+ iplen2 = a2i_ipadd(ipout + iplen1, p);
+
+ OPENSSL_free(iptmp);
+ iptmp = NULL;
+
+ if (!iplen2 || (iplen1 != iplen2))
+ goto err;
+
+ ret = ASN1_OCTET_STRING_new();
+ if (!ret)
+ goto err;
+ if (!ASN1_OCTET_STRING_set(ret, ipout, iplen1 + iplen2))
+ goto err;
+
+ return ret;
+
+ err:
+ if (iptmp)
+ OPENSSL_free(iptmp);
+ if (ret)
+ ASN1_OCTET_STRING_free(ret);
+ return NULL;
+ }
+
+
+int a2i_ipadd(unsigned char *ipout, const char *ipasc)
+ {
+ /* If string contains a ':' assume IPv6 */
+
+ if (strchr(ipasc, ':'))
+ {
+ if (!ipv6_from_asc(ipout, ipasc))
+ return 0;
+ return 16;
+ }
+ else
+ {
+ if (!ipv4_from_asc(ipout, ipasc))
+ return 0;
+ return 4;
+ }
+ }
+
+static int ipv4_from_asc(unsigned char *v4, const char *in)
+ {
+ int a0, a1, a2, a3;
+ if (sscanf(in, "%d.%d.%d.%d", &a0, &a1, &a2, &a3) != 4)
+ return 0;
+ if ((a0 < 0) || (a0 > 255) || (a1 < 0) || (a1 > 255)
+ || (a2 < 0) || (a2 > 255) || (a3 < 0) || (a3 > 255))
+ return 0;
+ v4[0] = a0;
+ v4[1] = a1;
+ v4[2] = a2;
+ v4[3] = a3;
+ return 1;
+ }
+
+typedef struct {
+ /* Temporary store for IPV6 output */
+ unsigned char tmp[16];
+ /* Total number of bytes in tmp */
+ int total;
+ /* The position of a zero (corresponding to '::') */
+ int zero_pos;
+ /* Number of zeroes */
+ int zero_cnt;
+ } IPV6_STAT;
+
+
+static int ipv6_from_asc(unsigned char *v6, const char *in)
+ {
+ IPV6_STAT v6stat;
+ v6stat.total = 0;
+ v6stat.zero_pos = -1;
+ v6stat.zero_cnt = 0;
+ /* Treat the IPv6 representation as a list of values
+ * separated by ':'. The presence of a '::' will parse
+ * as one, two or three zero length elements.
+ */
+ if (!CONF_parse_list(in, ':', 0, ipv6_cb, &v6stat))
+ return 0;
+
+ /* Now for some sanity checks */
+
+ if (v6stat.zero_pos == -1)
+ {
+ /* If no '::' must have exactly 16 bytes */
+ if (v6stat.total != 16)
+ return 0;
+ }
+ else
+ {
+ /* If '::' must have less than 16 bytes */
+ if (v6stat.total == 16)
+ return 0;
+ /* More than three zeroes is an error */
+ if (v6stat.zero_cnt > 3)
+ return 0;
+ /* Can only have three zeroes if nothing else present */
+ else if (v6stat.zero_cnt == 3)
+ {
+ if (v6stat.total > 0)
+ return 0;
+ }
+ /* Can only have two zeroes if at start or end */
+ else if (v6stat.zero_cnt == 2)
+ {
+ if ((v6stat.zero_pos != 0)
+ && (v6stat.zero_pos != v6stat.total))
+ return 0;
+ }
+ else
+ /* Can only have one zero if *not* start or end */
+ {
+ if ((v6stat.zero_pos == 0)
+ || (v6stat.zero_pos == v6stat.total))
+ return 0;
+ }
+ }
+
+ /* Format result */
+
+ if (v6stat.zero_pos >= 0)
+ {
+ /* Copy initial part */
+ memcpy(v6, v6stat.tmp, v6stat.zero_pos);
+ /* Zero middle */
+ memset(v6 + v6stat.zero_pos, 0, 16 - v6stat.total);
+ /* Copy final part */
+ if (v6stat.total != v6stat.zero_pos)
+ memcpy(v6 + v6stat.zero_pos + 16 - v6stat.total,
+ v6stat.tmp + v6stat.zero_pos,
+ v6stat.total - v6stat.zero_pos);
+ }
+ else
+ memcpy(v6, v6stat.tmp, 16);
+
+ return 1;
+ }
+
+static int ipv6_cb(const char *elem, int len, void *usr)
+ {
+ IPV6_STAT *s = usr;
+ /* Error if 16 bytes written */
+ if (s->total == 16)
+ return 0;
+ if (len == 0)
+ {
+ /* Zero length element, corresponds to '::' */
+ if (s->zero_pos == -1)
+ s->zero_pos = s->total;
+ /* If we've already got a :: its an error */
+ else if (s->zero_pos != s->total)
+ return 0;
+ s->zero_cnt++;
+ }
+ else
+ {
+ /* If more than 4 characters could be final a.b.c.d form */
+ if (len > 4)
+ {
+ /* Need at least 4 bytes left */
+ if (s->total > 12)
+ return 0;
+ /* Must be end of string */
+ if (elem[len])
+ return 0;
+ if (!ipv4_from_asc(s->tmp + s->total, elem))
+ return 0;
+ s->total += 4;
+ }
+ else
+ {
+ if (!ipv6_hex(s->tmp + s->total, elem, len))
+ return 0;
+ s->total += 2;
+ }
+ }
+ return 1;
+ }
+
+/* Convert a string of up to 4 hex digits into the corresponding
+ * IPv6 form.
+ */
+
+static int ipv6_hex(unsigned char *out, const char *in, int inlen)
+ {
+ unsigned char c;
+ unsigned int num = 0;
+ if (inlen > 4)
+ return 0;
+ while(inlen--)
+ {
+ c = *in++;
+ num <<= 4;
+ if ((c >= '0') && (c <= '9'))
+ num |= c - '0';
+ else if ((c >= 'A') && (c <= 'F'))
+ num |= c - 'A' + 10;
+ else if ((c >= 'a') && (c <= 'f'))
+ num |= c - 'a' + 10;
+ else
+ return 0;
+ }
+ out[0] = num >> 8;
+ out[1] = num & 0xff;
+ return 1;
+ }
+
+
+int X509V3_NAME_from_section(X509_NAME *nm, STACK_OF(CONF_VALUE)*dn_sk,
+ unsigned long chtype)
+ {
+ CONF_VALUE *v;
+ int mval;
+ size_t i;
+ char *p, *type;
+ if (!nm)
+ return 0;
+
+ for (i = 0; i < sk_CONF_VALUE_num(dn_sk); i++)
+ {
+ v=sk_CONF_VALUE_value(dn_sk,i);
+ type=v->name;
+ /* Skip past any leading X. X: X, etc to allow for
+ * multiple instances
+ */
+ for(p = type; *p ; p++)
+#ifndef CHARSET_EBCDIC
+ if ((*p == ':') || (*p == ',') || (*p == '.'))
+#else
+ if ((*p == os_toascii[':']) || (*p == os_toascii[',']) || (*p == os_toascii['.']))
+#endif
+ {
+ p++;
+ if(*p) type = p;
+ break;
+ }
+#ifndef CHARSET_EBCDIC
+ if (*type == '+')
+#else
+ if (*type == os_toascii['+'])
+#endif
+ {
+ mval = -1;
+ type++;
+ }
+ else
+ mval = 0;
+ if (!X509_NAME_add_entry_by_txt(nm,type, chtype,
+ (unsigned char *) v->value,-1,-1,mval))
+ return 0;
+
+ }
+ return 1;
+ }
diff --git a/crypto/x509v3/v3nametest.c b/crypto/x509v3/v3nametest.c
new file mode 100644
index 0000000..15d3e10
--- /dev/null
+++ b/crypto/x509v3/v3nametest.c
@@ -0,0 +1,418 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999. */
+/* ====================================================================
+ * Copyright (c) 1999-2004 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 <string.h>
+#include <strings.h>
+
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+
+static const char *const names[] =
+ {
+ "a", "b", ".", "*", "@",
+ ".a", "a.", ".b", "b.", ".*", "*.", "*@", "@*", "a@", "@a", "b@", "..",
+ "@@", "**",
+ "*.com", "*com", "*.*.com", "*com", "com*", "*example.com",
+ "*@example.com", "test@*.example.com",
+ "example.com", "www.example.com", "test.www.example.com",
+ "*.example.com", "*.www.example.com", "test.*.example.com", "www.*.com",
+ "example.net", "xn--rger-koa.example.com",
+ "a.example.com", "b.example.com",
+ "postmaster@example.com", "Postmaster@example.com",
+ "postmaster@EXAMPLE.COM",
+ NULL
+ };
+
+static const char *const exceptions[] =
+ {
+ "set CN: host: [*.example.com] does not match [*.example.com]",
+ "set CN: host: [*.example.com] matches [a.example.com]",
+ "set CN: host: [*.example.com] matches [b.example.com]",
+ "set CN: host: [*.example.com] matches [www.example.com]",
+ "set CN: host: [*.example.com] matches [xn--rger-koa.example.com]",
+ "set CN: host: [test.*.example.com] does not match [test.*.example.com]",
+ "set CN: host: [test.*.example.com] matches [test.www.example.com]",
+ "set CN: host: [*.www.example.com] does not match [*.www.example.com]",
+ "set CN: host: [*.www.example.com] matches [test.www.example.com]",
+ "set emailAddress: email: [postmaster@example.com] does not match [Postmaster@example.com]",
+ "set emailAddress: email: [postmaster@EXAMPLE.COM] does not match [Postmaster@example.com]",
+ "set emailAddress: email: [Postmaster@example.com] does not match [postmaster@example.com]",
+ "set emailAddress: email: [Postmaster@example.com] does not match [postmaster@EXAMPLE.COM]",
+ "set dnsName: host: [*.example.com] matches [www.example.com]",
+ "set dnsName: host: [*.example.com] does not match [*.example.com]",
+ "set dnsName: host: [*.example.com] matches [a.example.com]",
+ "set dnsName: host: [*.example.com] matches [b.example.com]",
+ "set dnsName: host: [*.example.com] matches [xn--rger-koa.example.com]",
+ "set dnsName: host: [*.www.example.com] matches [test.www.example.com]",
+ "set dnsName: host: [*.www.example.com] does not match [*.www.example.com]",
+ "set dnsName: host: [test.*.example.com] matches [test.www.example.com]",
+ "set dnsName: host: [test.*.example.com] does not match [test.*.example.com]",
+ "set rfc822Name: email: [postmaster@example.com] does not match [Postmaster@example.com]",
+ "set rfc822Name: email: [Postmaster@example.com] does not match [postmaster@example.com]",
+ "set rfc822Name: email: [Postmaster@example.com] does not match [postmaster@EXAMPLE.COM]",
+ "set rfc822Name: email: [postmaster@EXAMPLE.COM] does not match [Postmaster@example.com]",
+ NULL
+ };
+
+static int is_exception(const char *msg)
+ {
+ const char *const *p;
+ for (p = exceptions; *p; ++p)
+ if (strcmp(msg, *p) == 0)
+ return 1;
+ return 0;
+ }
+
+static int set_cn(X509 *crt, ...)
+ {
+ int ret = 0;
+ X509_NAME *n = NULL;
+ va_list ap;
+ va_start(ap, crt);
+ n = X509_NAME_new();
+ if (n == NULL)
+ goto out;
+ while (1) {
+ int nid;
+ const char *name;
+ nid = va_arg(ap, int);
+ if (nid == 0)
+ break;
+ name = va_arg(ap, const char *);
+ if (!X509_NAME_add_entry_by_NID(n, nid, MBSTRING_ASC,
+ (unsigned char *)name,
+ -1, -1, 1))
+ goto out;
+ }
+ if (!X509_set_subject_name(crt, n))
+ goto out;
+ ret = 1;
+ out:
+ X509_NAME_free(n);
+ va_end(ap);
+ return ret;
+ }
+
+/*
+int X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc);
+X509_EXTENSION *X509_EXTENSION_create_by_NID(X509_EXTENSION **ex,
+ int nid, int crit, ASN1_OCTET_STRING *data);
+int X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc);
+*/
+
+static int set_altname(X509 *crt, ...)
+ {
+ int ret = 0;
+ GENERAL_NAMES *gens = NULL;
+ GENERAL_NAME *gen = NULL;
+ ASN1_IA5STRING *ia5 = NULL;
+ va_list ap;
+ va_start(ap, crt);
+ gens = sk_GENERAL_NAME_new_null();
+ if (gens == NULL)
+ goto out;
+ while (1) {
+ int type;
+ const char *name;
+ type = va_arg(ap, int);
+ if (type == 0)
+ break;
+ name = va_arg(ap, const char *);
+
+ gen = GENERAL_NAME_new();
+ if (gen == NULL)
+ goto out;
+ ia5 = ASN1_IA5STRING_new();
+ if (ia5 == NULL)
+ goto out;
+ if (!ASN1_STRING_set(ia5, name, -1))
+ goto out;
+ switch (type)
+ {
+ case GEN_EMAIL:
+ case GEN_DNS:
+ GENERAL_NAME_set0_value(gen, type, ia5);
+ ia5 = NULL;
+ break;
+ default:
+ abort();
+ }
+ sk_GENERAL_NAME_push(gens, gen);
+ gen = NULL;
+ }
+ if (!X509_add1_ext_i2d(crt, NID_subject_alt_name, gens, 0, 0))
+ goto out;
+ ret = 1;
+ out:
+ ASN1_IA5STRING_free(ia5);
+ GENERAL_NAME_free(gen);
+ GENERAL_NAMES_free(gens);
+ va_end(ap);
+ return ret;
+ }
+
+static int set_cn1(X509 *crt, const char *name)
+ {
+ return set_cn(crt, NID_commonName, name, 0);
+ }
+
+
+static int set_cn_and_email(X509 *crt, const char *name)
+ {
+ return set_cn(crt, NID_commonName, name,
+ NID_pkcs9_emailAddress, "dummy@example.com", 0);
+ }
+
+static int set_cn2(X509 *crt, const char *name)
+ {
+ return set_cn(crt, NID_commonName, "dummy value",
+ NID_commonName, name, 0);
+ }
+
+static int set_cn3(X509 *crt, const char *name)
+ {
+ return set_cn(crt, NID_commonName, name,
+ NID_commonName, "dummy value", 0);
+ }
+
+static int set_email1(X509 *crt, const char *name)
+ {
+ return set_cn(crt, NID_pkcs9_emailAddress, name, 0);
+ }
+
+static int set_email2(X509 *crt, const char *name)
+ {
+ return set_cn(crt, NID_pkcs9_emailAddress, "dummy@example.com",
+ NID_pkcs9_emailAddress, name, 0);
+ }
+
+static int set_email3(X509 *crt, const char *name)
+ {
+ return set_cn(crt, NID_pkcs9_emailAddress, name,
+ NID_pkcs9_emailAddress, "dummy@example.com", 0);
+ }
+
+static int set_email_and_cn(X509 *crt, const char *name)
+ {
+ return set_cn(crt, NID_pkcs9_emailAddress, name,
+ NID_commonName, "www.example.org", 0);
+ }
+
+static int set_altname_dns(X509 *crt, const char *name)
+ {
+ return set_altname(crt, GEN_DNS, name, 0);
+ }
+
+static int set_altname_email(X509 *crt, const char *name)
+ {
+ return set_altname(crt, GEN_EMAIL, name, 0);
+ }
+
+struct set_name_fn
+ {
+ int (*fn)(X509 *, const char *);
+ const char *name;
+ int host;
+ int email;
+ };
+
+static const struct set_name_fn name_fns[] =
+ {
+ {set_cn1, "set CN", 1, 0},
+ {set_cn2, "set CN", 1, 0},
+ {set_cn3, "set CN", 1, 0},
+ {set_cn_and_email, "set CN", 1, 0},
+ {set_email1, "set emailAddress", 0, 1},
+ {set_email2, "set emailAddress", 0, 1},
+ {set_email3, "set emailAddress", 0, 1},
+ {set_email_and_cn, "set emailAddress", 0, 1},
+ {set_altname_dns, "set dnsName", 1, 0},
+ {set_altname_email, "set rfc822Name", 0, 1},
+ {NULL, NULL, 0}
+ };
+
+static X509 *make_cert()
+ {
+ X509 *ret = NULL;
+ X509 *crt = NULL;
+ X509_NAME *issuer = NULL;
+ crt = X509_new();
+ if (crt == NULL)
+ goto out;
+ if (!X509_set_version(crt, 3))
+ goto out;
+ ret = crt;
+ crt = NULL;
+ out:
+ X509_NAME_free(issuer);
+ return ret;
+ }
+
+static int errors;
+
+static void check_message(const struct set_name_fn *fn, const char *op,
+ const char *nameincert, int match, const char *name)
+ {
+ char msg[1024];
+ if (match < 0)
+ return;
+ BIO_snprintf(msg, sizeof(msg), "%s: %s: [%s] %s [%s]",
+ fn->name, op, nameincert,
+ match ? "matches" : "does not match", name);
+ if (is_exception(msg))
+ return;
+ puts(msg);
+ ++errors;
+ }
+
+static void run_cert(X509 *crt, const char *nameincert,
+ const struct set_name_fn *fn)
+ {
+ const char *const *pname = names;
+ while (*pname)
+ {
+ int samename = strcasecmp(nameincert, *pname) == 0;
+ size_t namelen = strlen(*pname);
+ char *name = malloc(namelen);
+ int match, ret;
+ memcpy(name, *pname, namelen);
+
+ ret = X509_check_host(crt, (const unsigned char *)name,
+ namelen, 0);
+ match = -1;
+ if (ret < 0)
+ {
+ fprintf(stderr, "internal error in X509_check_host");
+ ++errors;
+ }
+ else if (fn->host)
+ {
+ if (ret == 1 && !samename)
+ match = 1;
+ if (ret == 0 && samename)
+ match = 0;
+ }
+ else if (ret == 1)
+ match = 1;
+ check_message(fn, "host", nameincert, match, *pname);
+
+ ret = X509_check_host(crt, (const unsigned char *)name,
+ namelen, X509_CHECK_FLAG_NO_WILDCARDS);
+ match = -1;
+ if (ret < 0)
+ {
+ fprintf(stderr, "internal error in X509_check_host");
+ ++errors;
+ }
+ else if (fn->host)
+ {
+ if (ret == 1 && !samename)
+ match = 1;
+ if (ret == 0 && samename)
+ match = 0;
+ }
+ else if (ret == 1)
+ match = 1;
+ check_message(fn, "host-no-wildcards",
+ nameincert, match, *pname);
+
+ ret = X509_check_email(crt, (const unsigned char *)name,
+ namelen, 0);
+ match = -1;
+ if (fn->email)
+ {
+ if (ret && !samename)
+ match = 1;
+ if (!ret && samename && strchr(nameincert, '@') != NULL)
+ match = 0;
+ }
+ else if (ret)
+ match = 1;
+ check_message(fn, "email", nameincert, match, *pname);
+ ++pname;
+ free(name);
+ }
+ }
+
+int
+main(void)
+ {
+ const struct set_name_fn *pfn = name_fns;
+ while (pfn->name) {
+ const char *const *pname = names;
+ while (*pname)
+ {
+ X509 *crt = make_cert();
+ if (crt == NULL)
+ {
+ fprintf(stderr, "make_cert failed\n");
+ return 1;
+ }
+ if (!pfn->fn(crt, *pname))
+ {
+ fprintf(stderr, "X509 name setting failed\n");
+ return 1;
+ }
+ run_cert(crt, *pname, pfn);
+ X509_free(crt);
+ ++pname;
+ }
+ ++pfn;
+ }
+ if (errors == 0) {
+ printf("PASS\n");
+ }
+ return errors > 0 ? 1 : 0;
+ }
diff --git a/crypto/x509v3/x509v3.h b/crypto/x509v3/x509v3.h
new file mode 100644
index 0000000..8eae9ce
--- /dev/null
+++ b/crypto/x509v3/x509v3.h
@@ -0,0 +1,855 @@
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999. */
+/* ====================================================================
+ * Copyright (c) 1999-2004 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). */
+
+#ifndef HEADER_X509V3_H
+#define HEADER_X509V3_H
+
+#include <openssl/bio.h>
+#include <openssl/conf.h>
+#include <openssl/x509.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Forward reference */
+struct v3_ext_method;
+struct v3_ext_ctx;
+
+/* Useful typedefs */
+
+typedef void * (*X509V3_EXT_NEW)(void);
+typedef void (*X509V3_EXT_FREE)(void *);
+typedef void * (*X509V3_EXT_D2I)(void *, const unsigned char ** , long);
+typedef int (*X509V3_EXT_I2D)(void *, unsigned char **);
+typedef STACK_OF(CONF_VALUE) *
+ (*X509V3_EXT_I2V)(const struct v3_ext_method *method, void *ext,
+ STACK_OF(CONF_VALUE) *extlist);
+typedef void * (*X509V3_EXT_V2I)(const struct v3_ext_method *method,
+ struct v3_ext_ctx *ctx,
+ STACK_OF(CONF_VALUE) *values);
+typedef char * (*X509V3_EXT_I2S)(const struct v3_ext_method *method, void *ext);
+typedef void * (*X509V3_EXT_S2I)(const struct v3_ext_method *method,
+ struct v3_ext_ctx *ctx, const char *str);
+typedef int (*X509V3_EXT_I2R)(const struct v3_ext_method *method, void *ext,
+ BIO *out, int indent);
+typedef void * (*X509V3_EXT_R2I)(const struct v3_ext_method *method,
+ struct v3_ext_ctx *ctx, const char *str);
+
+/* V3 extension structure */
+
+struct v3_ext_method {
+int ext_nid;
+int ext_flags;
+/* If this is set the following four fields are ignored */
+ASN1_ITEM_EXP *it;
+/* Old style ASN1 calls */
+X509V3_EXT_NEW ext_new;
+X509V3_EXT_FREE ext_free;
+X509V3_EXT_D2I d2i;
+X509V3_EXT_I2D i2d;
+
+/* The following pair is used for string extensions */
+X509V3_EXT_I2S i2s;
+X509V3_EXT_S2I s2i;
+
+/* The following pair is used for multi-valued extensions */
+X509V3_EXT_I2V i2v;
+X509V3_EXT_V2I v2i;
+
+/* The following are used for raw extensions */
+X509V3_EXT_I2R i2r;
+X509V3_EXT_R2I r2i;
+
+void *usr_data; /* Any extension specific data */
+};
+
+typedef struct X509V3_CONF_METHOD_st {
+char * (*get_string)(void *db, char *section, char *value);
+STACK_OF(CONF_VALUE) * (*get_section)(void *db, char *section);
+void (*free_string)(void *db, char * string);
+void (*free_section)(void *db, STACK_OF(CONF_VALUE) *section);
+} X509V3_CONF_METHOD;
+
+/* Context specific info */
+struct v3_ext_ctx {
+#define CTX_TEST 0x1
+int flags;
+X509 *issuer_cert;
+X509 *subject_cert;
+X509_REQ *subject_req;
+X509_CRL *crl;
+X509V3_CONF_METHOD *db_meth;
+void *db;
+/* Maybe more here */
+};
+
+typedef struct v3_ext_method X509V3_EXT_METHOD;
+
+DECLARE_STACK_OF(X509V3_EXT_METHOD)
+
+/* ext_flags values */
+#define X509V3_EXT_DYNAMIC 0x1
+#define X509V3_EXT_CTX_DEP 0x2
+#define X509V3_EXT_MULTILINE 0x4
+
+typedef BIT_STRING_BITNAME ENUMERATED_NAMES;
+
+typedef struct BASIC_CONSTRAINTS_st {
+int ca;
+ASN1_INTEGER *pathlen;
+} BASIC_CONSTRAINTS;
+
+
+typedef struct PKEY_USAGE_PERIOD_st {
+ASN1_GENERALIZEDTIME *notBefore;
+ASN1_GENERALIZEDTIME *notAfter;
+} PKEY_USAGE_PERIOD;
+
+typedef struct otherName_st {
+ASN1_OBJECT *type_id;
+ASN1_TYPE *value;
+} OTHERNAME;
+
+typedef struct EDIPartyName_st {
+ ASN1_STRING *nameAssigner;
+ ASN1_STRING *partyName;
+} EDIPARTYNAME;
+
+typedef struct GENERAL_NAME_st {
+
+#define GEN_OTHERNAME 0
+#define GEN_EMAIL 1
+#define GEN_DNS 2
+#define GEN_X400 3
+#define GEN_DIRNAME 4
+#define GEN_EDIPARTY 5
+#define GEN_URI 6
+#define GEN_IPADD 7
+#define GEN_RID 8
+
+int type;
+union {
+ char *ptr;
+ OTHERNAME *otherName; /* otherName */
+ ASN1_IA5STRING *rfc822Name;
+ ASN1_IA5STRING *dNSName;
+ ASN1_TYPE *x400Address;
+ X509_NAME *directoryName;
+ EDIPARTYNAME *ediPartyName;
+ ASN1_IA5STRING *uniformResourceIdentifier;
+ ASN1_OCTET_STRING *iPAddress;
+ ASN1_OBJECT *registeredID;
+
+ /* Old names */
+ ASN1_OCTET_STRING *ip; /* iPAddress */
+ X509_NAME *dirn; /* dirn */
+ ASN1_IA5STRING *ia5;/* rfc822Name, dNSName, uniformResourceIdentifier */
+ ASN1_OBJECT *rid; /* registeredID */
+ ASN1_TYPE *other; /* x400Address */
+} d;
+} GENERAL_NAME;
+
+typedef STACK_OF(GENERAL_NAME) GENERAL_NAMES;
+
+typedef struct ACCESS_DESCRIPTION_st {
+ ASN1_OBJECT *method;
+ GENERAL_NAME *location;
+} ACCESS_DESCRIPTION;
+
+typedef STACK_OF(ACCESS_DESCRIPTION) AUTHORITY_INFO_ACCESS;
+
+typedef STACK_OF(ASN1_OBJECT) EXTENDED_KEY_USAGE;
+
+DECLARE_STACK_OF(GENERAL_NAME)
+DECLARE_ASN1_SET_OF(GENERAL_NAME)
+
+DECLARE_STACK_OF(ACCESS_DESCRIPTION)
+DECLARE_ASN1_SET_OF(ACCESS_DESCRIPTION)
+
+typedef struct DIST_POINT_NAME_st {
+int type;
+union {
+ GENERAL_NAMES *fullname;
+ STACK_OF(X509_NAME_ENTRY) *relativename;
+} name;
+/* If relativename then this contains the full distribution point name */
+X509_NAME *dpname;
+} DIST_POINT_NAME;
+/* All existing reasons */
+#define CRLDP_ALL_REASONS 0x807f
+
+#define CRL_REASON_NONE -1
+#define CRL_REASON_UNSPECIFIED 0
+#define CRL_REASON_KEY_COMPROMISE 1
+#define CRL_REASON_CA_COMPROMISE 2
+#define CRL_REASON_AFFILIATION_CHANGED 3
+#define CRL_REASON_SUPERSEDED 4
+#define CRL_REASON_CESSATION_OF_OPERATION 5
+#define CRL_REASON_CERTIFICATE_HOLD 6
+#define CRL_REASON_REMOVE_FROM_CRL 8
+#define CRL_REASON_PRIVILEGE_WITHDRAWN 9
+#define CRL_REASON_AA_COMPROMISE 10
+
+struct DIST_POINT_st {
+DIST_POINT_NAME *distpoint;
+ASN1_BIT_STRING *reasons;
+GENERAL_NAMES *CRLissuer;
+int dp_reasons;
+};
+
+typedef STACK_OF(DIST_POINT) CRL_DIST_POINTS;
+
+DECLARE_STACK_OF(DIST_POINT)
+DECLARE_ASN1_SET_OF(DIST_POINT)
+
+struct AUTHORITY_KEYID_st {
+ASN1_OCTET_STRING *keyid;
+GENERAL_NAMES *issuer;
+ASN1_INTEGER *serial;
+};
+
+/* Strong extranet structures */
+
+typedef struct SXNET_ID_st {
+ ASN1_INTEGER *zone;
+ ASN1_OCTET_STRING *user;
+} SXNETID;
+
+DECLARE_STACK_OF(SXNETID)
+DECLARE_ASN1_SET_OF(SXNETID)
+
+typedef struct SXNET_st {
+ ASN1_INTEGER *version;
+ STACK_OF(SXNETID) *ids;
+} SXNET;
+
+typedef struct NOTICEREF_st {
+ ASN1_STRING *organization;
+ STACK_OF(ASN1_INTEGER) *noticenos;
+} NOTICEREF;
+
+typedef struct USERNOTICE_st {
+ NOTICEREF *noticeref;
+ ASN1_STRING *exptext;
+} USERNOTICE;
+
+typedef struct POLICYQUALINFO_st {
+ ASN1_OBJECT *pqualid;
+ union {
+ ASN1_IA5STRING *cpsuri;
+ USERNOTICE *usernotice;
+ ASN1_TYPE *other;
+ } d;
+} POLICYQUALINFO;
+
+DECLARE_STACK_OF(POLICYQUALINFO)
+DECLARE_ASN1_SET_OF(POLICYQUALINFO)
+
+typedef struct POLICYINFO_st {
+ ASN1_OBJECT *policyid;
+ STACK_OF(POLICYQUALINFO) *qualifiers;
+} POLICYINFO;
+
+typedef STACK_OF(POLICYINFO) CERTIFICATEPOLICIES;
+
+DECLARE_STACK_OF(POLICYINFO)
+DECLARE_ASN1_SET_OF(POLICYINFO)
+
+typedef struct POLICY_MAPPING_st {
+ ASN1_OBJECT *issuerDomainPolicy;
+ ASN1_OBJECT *subjectDomainPolicy;
+} POLICY_MAPPING;
+
+DECLARE_STACK_OF(POLICY_MAPPING)
+
+typedef STACK_OF(POLICY_MAPPING) POLICY_MAPPINGS;
+
+typedef struct GENERAL_SUBTREE_st {
+ GENERAL_NAME *base;
+ ASN1_INTEGER *minimum;
+ ASN1_INTEGER *maximum;
+} GENERAL_SUBTREE;
+
+DECLARE_STACK_OF(GENERAL_SUBTREE)
+
+struct NAME_CONSTRAINTS_st {
+ STACK_OF(GENERAL_SUBTREE) *permittedSubtrees;
+ STACK_OF(GENERAL_SUBTREE) *excludedSubtrees;
+};
+
+typedef struct POLICY_CONSTRAINTS_st {
+ ASN1_INTEGER *requireExplicitPolicy;
+ ASN1_INTEGER *inhibitPolicyMapping;
+} POLICY_CONSTRAINTS;
+
+/* Proxy certificate structures, see RFC 3820 */
+typedef struct PROXY_POLICY_st
+ {
+ ASN1_OBJECT *policyLanguage;
+ ASN1_OCTET_STRING *policy;
+ } PROXY_POLICY;
+
+typedef struct PROXY_CERT_INFO_EXTENSION_st
+ {
+ ASN1_INTEGER *pcPathLengthConstraint;
+ PROXY_POLICY *proxyPolicy;
+ } PROXY_CERT_INFO_EXTENSION;
+
+DECLARE_ASN1_FUNCTIONS(PROXY_POLICY)
+DECLARE_ASN1_FUNCTIONS(PROXY_CERT_INFO_EXTENSION)
+
+struct ISSUING_DIST_POINT_st
+ {
+ DIST_POINT_NAME *distpoint;
+ int onlyuser;
+ int onlyCA;
+ ASN1_BIT_STRING *onlysomereasons;
+ int indirectCRL;
+ int onlyattr;
+ };
+
+/* Values in idp_flags field */
+/* IDP present */
+#define IDP_PRESENT 0x1
+/* IDP values inconsistent */
+#define IDP_INVALID 0x2
+/* onlyuser true */
+#define IDP_ONLYUSER 0x4
+/* onlyCA true */
+#define IDP_ONLYCA 0x8
+/* onlyattr true */
+#define IDP_ONLYATTR 0x10
+/* indirectCRL true */
+#define IDP_INDIRECT 0x20
+/* onlysomereasons present */
+#define IDP_REASONS 0x40
+
+#define X509V3_conf_err(val) ERR_add_error_data(6, "section:", val->section, \
+",name:", val->name, ",value:", val->value);
+
+#define X509V3_set_ctx_test(ctx) \
+ X509V3_set_ctx(ctx, NULL, NULL, NULL, NULL, CTX_TEST)
+#define X509V3_set_ctx_nodb(ctx) (ctx)->db = NULL;
+
+#define EXT_BITSTRING(nid, table) { nid, 0, ASN1_ITEM_ref(ASN1_BIT_STRING), \
+ 0,0,0,0, \
+ 0,0, \
+ (X509V3_EXT_I2V)i2v_ASN1_BIT_STRING, \
+ (X509V3_EXT_V2I)v2i_ASN1_BIT_STRING, \
+ NULL, NULL, \
+ table}
+
+#define EXT_IA5STRING(nid) { nid, 0, ASN1_ITEM_ref(ASN1_IA5STRING), \
+ 0,0,0,0, \
+ (X509V3_EXT_I2S)i2s_ASN1_IA5STRING, \
+ (X509V3_EXT_S2I)s2i_ASN1_IA5STRING, \
+ 0,0,0,0, \
+ NULL}
+
+#define EXT_END { -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+
+
+/* X509_PURPOSE stuff */
+
+#define EXFLAG_BCONS 0x1
+#define EXFLAG_KUSAGE 0x2
+#define EXFLAG_XKUSAGE 0x4
+#define EXFLAG_NSCERT 0x8
+
+#define EXFLAG_CA 0x10
+/* Really self issued not necessarily self signed */
+#define EXFLAG_SI 0x20
+#define EXFLAG_SS 0x20
+#define EXFLAG_V1 0x40
+#define EXFLAG_INVALID 0x80
+#define EXFLAG_SET 0x100
+#define EXFLAG_CRITICAL 0x200
+#define EXFLAG_PROXY 0x400
+
+#define EXFLAG_INVALID_POLICY 0x800
+#define EXFLAG_FRESHEST 0x1000
+
+#define KU_DIGITAL_SIGNATURE 0x0080
+#define KU_NON_REPUDIATION 0x0040
+#define KU_KEY_ENCIPHERMENT 0x0020
+#define KU_DATA_ENCIPHERMENT 0x0010
+#define KU_KEY_AGREEMENT 0x0008
+#define KU_KEY_CERT_SIGN 0x0004
+#define KU_CRL_SIGN 0x0002
+#define KU_ENCIPHER_ONLY 0x0001
+#define KU_DECIPHER_ONLY 0x8000
+
+#define NS_SSL_CLIENT 0x80
+#define NS_SSL_SERVER 0x40
+#define NS_SMIME 0x20
+#define NS_OBJSIGN 0x10
+#define NS_SSL_CA 0x04
+#define NS_SMIME_CA 0x02
+#define NS_OBJSIGN_CA 0x01
+#define NS_ANY_CA (NS_SSL_CA|NS_SMIME_CA|NS_OBJSIGN_CA)
+
+#define XKU_SSL_SERVER 0x1
+#define XKU_SSL_CLIENT 0x2
+#define XKU_SMIME 0x4
+#define XKU_CODE_SIGN 0x8
+#define XKU_SGC 0x10
+#define XKU_OCSP_SIGN 0x20
+#define XKU_TIMESTAMP 0x40
+#define XKU_DVCS 0x80
+#define XKU_ANYEKU 0x100
+
+#define X509_PURPOSE_DYNAMIC 0x1
+#define X509_PURPOSE_DYNAMIC_NAME 0x2
+
+typedef struct x509_purpose_st {
+ int purpose;
+ int trust; /* Default trust ID */
+ int flags;
+ int (*check_purpose)(const struct x509_purpose_st *,
+ const X509 *, int);
+ char *name;
+ char *sname;
+ void *usr_data;
+} X509_PURPOSE;
+
+#define X509_PURPOSE_SSL_CLIENT 1
+#define X509_PURPOSE_SSL_SERVER 2
+#define X509_PURPOSE_NS_SSL_SERVER 3
+#define X509_PURPOSE_SMIME_SIGN 4
+#define X509_PURPOSE_SMIME_ENCRYPT 5
+#define X509_PURPOSE_CRL_SIGN 6
+#define X509_PURPOSE_ANY 7
+#define X509_PURPOSE_OCSP_HELPER 8
+#define X509_PURPOSE_TIMESTAMP_SIGN 9
+
+#define X509_PURPOSE_MIN 1
+#define X509_PURPOSE_MAX 9
+
+/* Flags for X509V3_EXT_print() */
+
+#define X509V3_EXT_UNKNOWN_MASK (0xfL << 16)
+/* Return error for unknown extensions */
+#define X509V3_EXT_DEFAULT 0
+/* Print error for unknown extensions */
+#define X509V3_EXT_ERROR_UNKNOWN (1L << 16)
+/* ASN1 parse unknown extensions */
+#define X509V3_EXT_PARSE_UNKNOWN (2L << 16)
+/* BIO_dump unknown extensions */
+#define X509V3_EXT_DUMP_UNKNOWN (3L << 16)
+
+/* Flags for X509V3_add1_i2d */
+
+#define X509V3_ADD_OP_MASK 0xfL
+#define X509V3_ADD_DEFAULT 0L
+#define X509V3_ADD_APPEND 1L
+#define X509V3_ADD_REPLACE 2L
+#define X509V3_ADD_REPLACE_EXISTING 3L
+#define X509V3_ADD_KEEP_EXISTING 4L
+#define X509V3_ADD_DELETE 5L
+#define X509V3_ADD_SILENT 0x10
+
+DECLARE_STACK_OF(X509_PURPOSE)
+
+DECLARE_ASN1_FUNCTIONS(BASIC_CONSTRAINTS)
+
+DECLARE_ASN1_FUNCTIONS(SXNET)
+DECLARE_ASN1_FUNCTIONS(SXNETID)
+
+int SXNET_add_id_asc(SXNET **psx, char *zone, char *user, int userlen);
+int SXNET_add_id_ulong(SXNET **psx, unsigned long lzone, char *user, int userlen);
+int SXNET_add_id_INTEGER(SXNET **psx, ASN1_INTEGER *izone, char *user, int userlen);
+
+ASN1_OCTET_STRING *SXNET_get_id_asc(SXNET *sx, char *zone);
+ASN1_OCTET_STRING *SXNET_get_id_ulong(SXNET *sx, unsigned long lzone);
+ASN1_OCTET_STRING *SXNET_get_id_INTEGER(SXNET *sx, ASN1_INTEGER *zone);
+
+DECLARE_ASN1_FUNCTIONS(AUTHORITY_KEYID)
+
+DECLARE_ASN1_FUNCTIONS(PKEY_USAGE_PERIOD)
+
+DECLARE_ASN1_FUNCTIONS(GENERAL_NAME)
+GENERAL_NAME *GENERAL_NAME_dup(GENERAL_NAME *a);
+int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b);
+
+
+
+ASN1_BIT_STRING *v2i_ASN1_BIT_STRING(X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval);
+STACK_OF(CONF_VALUE) *i2v_ASN1_BIT_STRING(X509V3_EXT_METHOD *method,
+ ASN1_BIT_STRING *bits,
+ STACK_OF(CONF_VALUE) *extlist);
+
+STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method, GENERAL_NAME *gen, STACK_OF(CONF_VALUE) *ret);
+int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen);
+
+DECLARE_ASN1_FUNCTIONS(GENERAL_NAMES)
+
+STACK_OF(CONF_VALUE) *i2v_GENERAL_NAMES(X509V3_EXT_METHOD *method,
+ GENERAL_NAMES *gen, STACK_OF(CONF_VALUE) *extlist);
+GENERAL_NAMES *v2i_GENERAL_NAMES(const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval);
+
+DECLARE_ASN1_FUNCTIONS(OTHERNAME)
+DECLARE_ASN1_FUNCTIONS(EDIPARTYNAME)
+int OTHERNAME_cmp(OTHERNAME *a, OTHERNAME *b);
+void GENERAL_NAME_set0_value(GENERAL_NAME *a, int type, void *value);
+void *GENERAL_NAME_get0_value(GENERAL_NAME *a, int *ptype);
+int GENERAL_NAME_set0_othername(GENERAL_NAME *gen,
+ ASN1_OBJECT *oid, ASN1_TYPE *value);
+int GENERAL_NAME_get0_otherName(GENERAL_NAME *gen,
+ ASN1_OBJECT **poid, ASN1_TYPE **pvalue);
+
+char *i2s_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, ASN1_OCTET_STRING *ia5);
+ASN1_OCTET_STRING *s2i_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, char *str);
+
+DECLARE_ASN1_FUNCTIONS(EXTENDED_KEY_USAGE)
+int i2a_ACCESS_DESCRIPTION(BIO *bp, ACCESS_DESCRIPTION* a);
+
+DECLARE_ASN1_FUNCTIONS(CERTIFICATEPOLICIES)
+DECLARE_ASN1_FUNCTIONS(POLICYINFO)
+DECLARE_ASN1_FUNCTIONS(POLICYQUALINFO)
+DECLARE_ASN1_FUNCTIONS(USERNOTICE)
+DECLARE_ASN1_FUNCTIONS(NOTICEREF)
+
+DECLARE_ASN1_FUNCTIONS(CRL_DIST_POINTS)
+DECLARE_ASN1_FUNCTIONS(DIST_POINT)
+DECLARE_ASN1_FUNCTIONS(DIST_POINT_NAME)
+DECLARE_ASN1_FUNCTIONS(ISSUING_DIST_POINT)
+
+int DIST_POINT_set_dpname(DIST_POINT_NAME *dpn, X509_NAME *iname);
+
+int NAME_CONSTRAINTS_check(X509 *x, NAME_CONSTRAINTS *nc);
+
+DECLARE_ASN1_FUNCTIONS(ACCESS_DESCRIPTION)
+DECLARE_ASN1_FUNCTIONS(AUTHORITY_INFO_ACCESS)
+
+DECLARE_ASN1_ITEM(POLICY_MAPPING)
+DECLARE_ASN1_ALLOC_FUNCTIONS(POLICY_MAPPING)
+DECLARE_ASN1_ITEM(POLICY_MAPPINGS)
+
+DECLARE_ASN1_ITEM(GENERAL_SUBTREE)
+DECLARE_ASN1_ALLOC_FUNCTIONS(GENERAL_SUBTREE)
+
+DECLARE_ASN1_ITEM(NAME_CONSTRAINTS)
+DECLARE_ASN1_ALLOC_FUNCTIONS(NAME_CONSTRAINTS)
+
+DECLARE_ASN1_ALLOC_FUNCTIONS(POLICY_CONSTRAINTS)
+DECLARE_ASN1_ITEM(POLICY_CONSTRAINTS)
+
+GENERAL_NAME *a2i_GENERAL_NAME(GENERAL_NAME *out,
+ const X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
+ int gen_type, char *value, int is_nc);
+
+GENERAL_NAME *v2i_GENERAL_NAME(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
+ CONF_VALUE *cnf);
+GENERAL_NAME *v2i_GENERAL_NAME_ex(GENERAL_NAME *out,
+ const X509V3_EXT_METHOD *method,
+ X509V3_CTX *ctx, CONF_VALUE *cnf, int is_nc);
+void X509V3_conf_free(CONF_VALUE *val);
+
+X509_EXTENSION *X509V3_EXT_nconf_nid(CONF *conf, X509V3_CTX *ctx, int ext_nid, char *value);
+X509_EXTENSION *X509V3_EXT_nconf(CONF *conf, X509V3_CTX *ctx, char *name, char *value);
+int X509V3_EXT_add_nconf_sk(CONF *conf, X509V3_CTX *ctx, char *section, STACK_OF(X509_EXTENSION) **sk);
+int X509V3_EXT_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, X509 *cert);
+int X509V3_EXT_REQ_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, X509_REQ *req);
+int X509V3_EXT_CRL_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, X509_CRL *crl);
+
+X509_EXTENSION *X509V3_EXT_conf_nid(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx,
+ int ext_nid, char *value);
+X509_EXTENSION *X509V3_EXT_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx,
+ char *name, char *value);
+int X509V3_EXT_add_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx,
+ char *section, X509 *cert);
+int X509V3_EXT_REQ_add_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx,
+ char *section, X509_REQ *req);
+int X509V3_EXT_CRL_add_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx,
+ char *section, X509_CRL *crl);
+
+int X509V3_add_value_bool_nf(char *name, int asn1_bool,
+ STACK_OF(CONF_VALUE) **extlist);
+int X509V3_get_value_bool(CONF_VALUE *value, int *asn1_bool);
+int X509V3_get_value_int(CONF_VALUE *value, ASN1_INTEGER **aint);
+void X509V3_set_nconf(X509V3_CTX *ctx, CONF *conf);
+void X509V3_set_conf_lhash(X509V3_CTX *ctx, LHASH_OF(CONF_VALUE) *lhash);
+
+char * X509V3_get_string(X509V3_CTX *ctx, char *name, char *section);
+STACK_OF(CONF_VALUE) * X509V3_get_section(X509V3_CTX *ctx, char *section);
+void X509V3_string_free(X509V3_CTX *ctx, char *str);
+void X509V3_section_free( X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *section);
+void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subject,
+ X509_REQ *req, X509_CRL *crl, int flags);
+
+int X509V3_add_value(const char *name, const char *value,
+ STACK_OF(CONF_VALUE) **extlist);
+int X509V3_add_value_uchar(const char *name, const unsigned char *value,
+ STACK_OF(CONF_VALUE) **extlist);
+int X509V3_add_value_bool(const char *name, int asn1_bool,
+ STACK_OF(CONF_VALUE) **extlist);
+int X509V3_add_value_int(const char *name, ASN1_INTEGER *aint,
+ STACK_OF(CONF_VALUE) **extlist);
+char * i2s_ASN1_INTEGER(X509V3_EXT_METHOD *meth, ASN1_INTEGER *aint);
+ASN1_INTEGER * s2i_ASN1_INTEGER(X509V3_EXT_METHOD *meth, char *value);
+char * i2s_ASN1_ENUMERATED(X509V3_EXT_METHOD *meth, ASN1_ENUMERATED *aint);
+char * i2s_ASN1_ENUMERATED_TABLE(X509V3_EXT_METHOD *meth, ASN1_ENUMERATED *aint);
+int X509V3_EXT_add(X509V3_EXT_METHOD *ext);
+int X509V3_EXT_add_list(X509V3_EXT_METHOD *extlist);
+int X509V3_EXT_add_alias(int nid_to, int nid_from);
+void X509V3_EXT_cleanup(void);
+
+const X509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *ext);
+const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid);
+int X509V3_add_standard_extensions(void);
+STACK_OF(CONF_VALUE) *X509V3_parse_list(const char *line);
+void *X509V3_EXT_d2i(X509_EXTENSION *ext);
+void *X509V3_get_d2i(STACK_OF(X509_EXTENSION) *x, int nid, int *crit, int *idx);
+
+
+X509_EXTENSION *X509V3_EXT_i2d(int ext_nid, int crit, void *ext_struc);
+int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value, int crit, unsigned long flags);
+
+char *hex_to_string(const unsigned char *buffer, long len);
+unsigned char *string_to_hex(const char *str, long *len);
+int name_cmp(const char *name, const char *cmp);
+
+void X509V3_EXT_val_prn(BIO *out, STACK_OF(CONF_VALUE) *val, int indent,
+ int ml);
+int X509V3_EXT_print(BIO *out, X509_EXTENSION *ext, unsigned long flag, int indent);
+int X509V3_EXT_print_fp(FILE *out, X509_EXTENSION *ext, int flag, int indent);
+
+int X509V3_extensions_print(BIO *out, char *title, STACK_OF(X509_EXTENSION) *exts, unsigned long flag, int indent);
+
+int X509_check_ca(X509 *x);
+int X509_check_purpose(X509 *x, int id, int ca);
+int X509_supported_extension(X509_EXTENSION *ex);
+int X509_PURPOSE_set(int *p, int purpose);
+int X509_check_issued(X509 *issuer, X509 *subject);
+int X509_check_akid(X509 *issuer, AUTHORITY_KEYID *akid);
+int X509_PURPOSE_get_count(void);
+X509_PURPOSE * X509_PURPOSE_get0(int idx);
+int X509_PURPOSE_get_by_sname(char *sname);
+int X509_PURPOSE_get_by_id(int id);
+int X509_PURPOSE_add(int id, int trust, int flags,
+ int (*ck)(const X509_PURPOSE *, const X509 *, int),
+ char *name, char *sname, void *arg);
+char *X509_PURPOSE_get0_name(X509_PURPOSE *xp);
+char *X509_PURPOSE_get0_sname(X509_PURPOSE *xp);
+int X509_PURPOSE_get_trust(X509_PURPOSE *xp);
+void X509_PURPOSE_cleanup(void);
+int X509_PURPOSE_get_id(X509_PURPOSE *);
+
+STACK_OF(OPENSSL_STRING) *X509_get1_email(X509 *x);
+STACK_OF(OPENSSL_STRING) *X509_REQ_get1_email(X509_REQ *x);
+void X509_email_free(STACK_OF(OPENSSL_STRING) *sk);
+STACK_OF(OPENSSL_STRING) *X509_get1_ocsp(X509 *x);
+/* Flags for X509_check_* functions */
+
+/* Always check subject name for host match even if subject alt names present */
+#define X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT 0x1
+/* Disable wild-card matching for dnsName fields and common name. */
+#define X509_CHECK_FLAG_NO_WILDCARDS 0x2
+
+int X509_check_host(X509 *x, const unsigned char *chk, size_t chklen,
+ unsigned int flags);
+int X509_check_email(X509 *x, const unsigned char *chk, size_t chklen,
+ unsigned int flags);
+int X509_check_ip(X509 *x, const unsigned char *chk, size_t chklen,
+ unsigned int flags);
+int X509_check_ip_asc(X509 *x, const char *ipasc, unsigned int flags);
+
+ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc);
+ASN1_OCTET_STRING *a2i_IPADDRESS_NC(const char *ipasc);
+int a2i_ipadd(unsigned char *ipout, const char *ipasc);
+int X509V3_NAME_from_section(X509_NAME *nm, STACK_OF(CONF_VALUE)*dn_sk,
+ unsigned long chtype);
+
+void X509_POLICY_NODE_print(BIO *out, X509_POLICY_NODE *node, int indent);
+DECLARE_STACK_OF(X509_POLICY_NODE)
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_X509V3_strings(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+#define X509V3_F_do_ext_i2d 100
+#define X509V3_F_v2i_AUTHORITY_KEYID 101
+#define X509V3_F_X509V3_parse_list 102
+#define X509V3_F_SXNET_add_id_asc 103
+#define X509V3_F_SXNET_get_id_ulong 104
+#define X509V3_F_v2i_AUTHORITY_INFO_ACCESS 105
+#define X509V3_F_X509V3_EXT_add 106
+#define X509V3_F_i2s_ASN1_INTEGER 107
+#define X509V3_F_s2i_ASN1_OCTET_STRING 108
+#define X509V3_F_copy_issuer 109
+#define X509V3_F_v2i_subject_alt 110
+#define X509V3_F_copy_email 111
+#define X509V3_F_X509V3_EXT_i2d 112
+#define X509V3_F_v2i_crld 113
+#define X509V3_F_policy_section 114
+#define X509V3_F_a2i_GENERAL_NAME 115
+#define X509V3_F_hex_to_string 116
+#define X509V3_F_i2s_ASN1_IA5STRING 117
+#define X509V3_F_string_to_hex 118
+#define X509V3_F_v3_generic_extension 119
+#define X509V3_F_X509V3_get_section 120
+#define X509V3_F_s2i_skey_id 121
+#define X509V3_F_nref_nos 122
+#define X509V3_F_X509V3_get_value_bool 123
+#define X509V3_F_v2i_NAME_CONSTRAINTS 124
+#define X509V3_F_v2i_POLICY_MAPPINGS 125
+#define X509V3_F_v2i_GENERAL_NAMES 126
+#define X509V3_F_do_dirname 127
+#define X509V3_F_v2i_ASN1_BIT_STRING 128
+#define X509V3_F_SXNET_add_id_ulong 129
+#define X509V3_F_X509V3_EXT_add_alias 130
+#define X509V3_F_X509V3_add1_i2d 131
+#define X509V3_F_r2i_pci 132
+#define X509V3_F_X509V3_get_string 133
+#define X509V3_F_gnames_from_sectname 134
+#define X509V3_F_r2i_certpol 135
+#define X509V3_F_X509V3_add_value 136
+#define X509V3_F_s2i_ASN1_INTEGER 137
+#define X509V3_F_v2i_issuer_alt 138
+#define X509V3_F_v2i_GENERAL_NAME_ex 139
+#define X509V3_F_X509V3_EXT_nconf 140
+#define X509V3_F_v2i_BASIC_CONSTRAINTS 141
+#define X509V3_F_process_pci_value 142
+#define X509V3_F_notice_section 143
+#define X509V3_F_X509_PURPOSE_set 144
+#define X509V3_F_do_ext_nconf 145
+#define X509V3_F_i2s_ASN1_ENUMERATED 146
+#define X509V3_F_s2i_ASN1_IA5STRING 147
+#define X509V3_F_v2i_POLICY_CONSTRAINTS 148
+#define X509V3_F_v2i_EXTENDED_KEY_USAGE 149
+#define X509V3_F_SXNET_get_id_asc 150
+#define X509V3_F_set_dist_point_name 151
+#define X509V3_F_v2i_idp 152
+#define X509V3_F_X509_PURPOSE_add 153
+#define X509V3_F_SXNET_add_id_INTEGER 154
+#define X509V3_F_i2v_AUTHORITY_INFO_ACCESS 155
+#define X509V3_R_INVALID_BOOLEAN_STRING 100
+#define X509V3_R_POLICY_SYNTAX_NOT_CURRENTLY_SUPPORTED 101
+#define X509V3_R_INVALID_NAME 102
+#define X509V3_R_OPERATION_NOT_DEFINED 103
+#define X509V3_R_POLICY_PATH_LENGTH 104
+#define X509V3_R_INVALID_PROXY_POLICY_SETTING 105
+#define X509V3_R_INVALID_ASRANGE 106
+#define X509V3_R_ERROR_CREATING_EXTENSION 107
+#define X509V3_R_ISSUER_DECODE_ERROR 108
+#define X509V3_R_OTHERNAME_ERROR 109
+#define X509V3_R_ILLEGAL_HEX_DIGIT 110
+#define X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED 111
+#define X509V3_R_USER_TOO_LONG 112
+#define X509V3_R_INVALID_INHERITANCE 113
+#define X509V3_R_INVALID_SAFI 114
+#define X509V3_R_INVALID_NULL_VALUE 115
+#define X509V3_R_NO_SUBJECT_DETAILS 116
+#define X509V3_R_BAD_OBJECT 117
+#define X509V3_R_DIRNAME_ERROR 118
+#define X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT 119
+#define X509V3_R_INVALID_EXTENSION_STRING 120
+#define X509V3_R_NEED_ORGANIZATION_AND_NUMBERS 121
+#define X509V3_R_BN_TO_ASN1_INTEGER_ERROR 122
+#define X509V3_R_INVALID_OPTION 123
+#define X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS 124
+#define X509V3_R_INVALID_POLICY_IDENTIFIER 125
+#define X509V3_R_INVALID_PURPOSE 126
+#define X509V3_R_UNKNOWN_EXTENSION 127
+#define X509V3_R_NO_ISSUER_CERTIFICATE 128
+#define X509V3_R_BN_DEC2BN_ERROR 129
+#define X509V3_R_EXPECTED_A_SECTION_NAME 130
+#define X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED 131
+#define X509V3_R_MISSING_VALUE 132
+#define X509V3_R_SECTION_NOT_FOUND 133
+#define X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED 134
+#define X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED 135
+#define X509V3_R_ILLEGAL_EMPTY_EXTENSION 136
+#define X509V3_R_NO_POLICY_IDENTIFIER 137
+#define X509V3_R_NO_ISSUER_DETAILS 138
+#define X509V3_R_NO_CONFIG_DATABASE 139
+#define X509V3_R_INCORRECT_POLICY_SYNTAX_TAG 140
+#define X509V3_R_INVALID_SECTION 141
+#define X509V3_R_INVALID_IPADDRESS 142
+#define X509V3_R_EXTENSION_VALUE_ERROR 143
+#define X509V3_R_UNABLE_TO_GET_ISSUER_KEYID 144
+#define X509V3_R_INVALID_NULL_ARGUMENT 145
+#define X509V3_R_ERROR_IN_EXTENSION 146
+#define X509V3_R_INVALID_NULL_NAME 147
+#define X509V3_R_BAD_IP_ADDRESS 148
+#define X509V3_R_UNSUPPORTED_OPTION 149
+#define X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY 150
+#define X509V3_R_EXTENSION_EXISTS 151
+#define X509V3_R_UNKNOWN_OPTION 152
+#define X509V3_R_ERROR_CONVERTING_ZONE 153
+#define X509V3_R_NO_PUBLIC_KEY 154
+#define X509V3_R_INVALID_MULTIPLE_RDNS 155
+#define X509V3_R_INVALID_SYNTAX 156
+#define X509V3_R_UNKNOWN_EXTENSION_NAME 157
+#define X509V3_R_ODD_NUMBER_OF_DIGITS 158
+#define X509V3_R_DISTPOINT_ALREADY_SET 159
+#define X509V3_R_UNSUPPORTED_TYPE 160
+#define X509V3_R_EXTENSION_NAME_ERROR 161
+#define X509V3_R_INVALID_NUMBERS 162
+#define X509V3_R_INVALID_NUMBER 163
+#define X509V3_R_INVALID_OBJECT_IDENTIFIER 164
+#define X509V3_R_DUPLICATE_ZONE_ID 165
+#define X509V3_R_EXTENSION_NOT_FOUND 166
+#define X509V3_R_INVALID_ASNUMBER 167
+
+#endif
diff --git a/crypto/x509v3/x509v3_error.c b/crypto/x509v3/x509v3_error.c
new file mode 100644
index 0000000..6a8d582
--- /dev/null
+++ b/crypto/x509v3/x509v3_error.c
@@ -0,0 +1,145 @@
+/* Copyright (c) 2014, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/err.h>
+
+#include "x509v3.h"
+
+const ERR_STRING_DATA X509V3_error_string_data[] = {
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_SXNET_add_id_INTEGER, 0), "SXNET_add_id_INTEGER"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_SXNET_add_id_asc, 0), "SXNET_add_id_asc"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_SXNET_add_id_ulong, 0), "SXNET_add_id_ulong"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_SXNET_get_id_asc, 0), "SXNET_get_id_asc"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_SXNET_get_id_ulong, 0), "SXNET_get_id_ulong"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_X509V3_EXT_add, 0), "X509V3_EXT_add"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_X509V3_EXT_add_alias, 0), "X509V3_EXT_add_alias"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_X509V3_EXT_i2d, 0), "X509V3_EXT_i2d"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_X509V3_EXT_nconf, 0), "X509V3_EXT_nconf"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_X509V3_add1_i2d, 0), "X509V3_add1_i2d"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_X509V3_add_value, 0), "X509V3_add_value"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_X509V3_get_section, 0), "X509V3_get_section"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_X509V3_get_string, 0), "X509V3_get_string"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_X509V3_get_value_bool, 0), "X509V3_get_value_bool"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_X509V3_parse_list, 0), "X509V3_parse_list"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_X509_PURPOSE_add, 0), "X509_PURPOSE_add"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_X509_PURPOSE_set, 0), "X509_PURPOSE_set"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_a2i_GENERAL_NAME, 0), "a2i_GENERAL_NAME"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_copy_email, 0), "copy_email"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_copy_issuer, 0), "copy_issuer"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_do_dirname, 0), "do_dirname"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_do_ext_i2d, 0), "do_ext_i2d"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_do_ext_nconf, 0), "do_ext_nconf"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_gnames_from_sectname, 0), "gnames_from_sectname"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_hex_to_string, 0), "hex_to_string"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_i2s_ASN1_ENUMERATED, 0), "i2s_ASN1_ENUMERATED"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_i2s_ASN1_IA5STRING, 0), "i2s_ASN1_IA5STRING"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_i2s_ASN1_INTEGER, 0), "i2s_ASN1_INTEGER"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_i2v_AUTHORITY_INFO_ACCESS, 0), "i2v_AUTHORITY_INFO_ACCESS"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_notice_section, 0), "notice_section"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_nref_nos, 0), "nref_nos"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_policy_section, 0), "policy_section"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_process_pci_value, 0), "process_pci_value"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_r2i_certpol, 0), "r2i_certpol"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_r2i_pci, 0), "r2i_pci"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_s2i_ASN1_IA5STRING, 0), "s2i_ASN1_IA5STRING"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_s2i_ASN1_INTEGER, 0), "s2i_ASN1_INTEGER"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_s2i_ASN1_OCTET_STRING, 0), "s2i_ASN1_OCTET_STRING"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_s2i_skey_id, 0), "s2i_skey_id"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_set_dist_point_name, 0), "set_dist_point_name"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_string_to_hex, 0), "string_to_hex"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_v2i_ASN1_BIT_STRING, 0), "v2i_ASN1_BIT_STRING"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_v2i_AUTHORITY_INFO_ACCESS, 0), "v2i_AUTHORITY_INFO_ACCESS"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_v2i_AUTHORITY_KEYID, 0), "v2i_AUTHORITY_KEYID"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_v2i_BASIC_CONSTRAINTS, 0), "v2i_BASIC_CONSTRAINTS"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_v2i_EXTENDED_KEY_USAGE, 0), "v2i_EXTENDED_KEY_USAGE"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_v2i_GENERAL_NAMES, 0), "v2i_GENERAL_NAMES"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_v2i_GENERAL_NAME_ex, 0), "v2i_GENERAL_NAME_ex"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_v2i_NAME_CONSTRAINTS, 0), "v2i_NAME_CONSTRAINTS"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_v2i_POLICY_CONSTRAINTS, 0), "v2i_POLICY_CONSTRAINTS"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_v2i_POLICY_MAPPINGS, 0), "v2i_POLICY_MAPPINGS"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_v2i_crld, 0), "v2i_crld"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_v2i_idp, 0), "v2i_idp"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_v2i_issuer_alt, 0), "v2i_issuer_alt"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_v2i_subject_alt, 0), "v2i_subject_alt"},
+ {ERR_PACK(ERR_LIB_X509V3, X509V3_F_v3_generic_extension, 0), "v3_generic_extension"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_BAD_IP_ADDRESS), "BAD_IP_ADDRESS"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_BAD_OBJECT), "BAD_OBJECT"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_BN_DEC2BN_ERROR), "BN_DEC2BN_ERROR"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_BN_TO_ASN1_INTEGER_ERROR), "BN_TO_ASN1_INTEGER_ERROR"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_DIRNAME_ERROR), "DIRNAME_ERROR"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_DISTPOINT_ALREADY_SET), "DISTPOINT_ALREADY_SET"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_DUPLICATE_ZONE_ID), "DUPLICATE_ZONE_ID"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_ERROR_CONVERTING_ZONE), "ERROR_CONVERTING_ZONE"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_ERROR_CREATING_EXTENSION), "ERROR_CREATING_EXTENSION"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_ERROR_IN_EXTENSION), "ERROR_IN_EXTENSION"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EXPECTED_A_SECTION_NAME), "EXPECTED_A_SECTION_NAME"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EXTENSION_EXISTS), "EXTENSION_EXISTS"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EXTENSION_NAME_ERROR), "EXTENSION_NAME_ERROR"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EXTENSION_NOT_FOUND), "EXTENSION_NOT_FOUND"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED), "EXTENSION_SETTING_NOT_SUPPORTED"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EXTENSION_VALUE_ERROR), "EXTENSION_VALUE_ERROR"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_ILLEGAL_EMPTY_EXTENSION), "ILLEGAL_EMPTY_EXTENSION"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_ILLEGAL_HEX_DIGIT), "ILLEGAL_HEX_DIGIT"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INCORRECT_POLICY_SYNTAX_TAG), "INCORRECT_POLICY_SYNTAX_TAG"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_ASNUMBER), "INVALID_ASNUMBER"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_ASRANGE), "INVALID_ASRANGE"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_BOOLEAN_STRING), "INVALID_BOOLEAN_STRING"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_EXTENSION_STRING), "INVALID_EXTENSION_STRING"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_INHERITANCE), "INVALID_INHERITANCE"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_IPADDRESS), "INVALID_IPADDRESS"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_MULTIPLE_RDNS), "INVALID_MULTIPLE_RDNS"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_NAME), "INVALID_NAME"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_NULL_ARGUMENT), "INVALID_NULL_ARGUMENT"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_NULL_NAME), "INVALID_NULL_NAME"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_NULL_VALUE), "INVALID_NULL_VALUE"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_NUMBER), "INVALID_NUMBER"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_NUMBERS), "INVALID_NUMBERS"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_OBJECT_IDENTIFIER), "INVALID_OBJECT_IDENTIFIER"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_OPTION), "INVALID_OPTION"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_POLICY_IDENTIFIER), "INVALID_POLICY_IDENTIFIER"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_PROXY_POLICY_SETTING), "INVALID_PROXY_POLICY_SETTING"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_PURPOSE), "INVALID_PURPOSE"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_SAFI), "INVALID_SAFI"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_SECTION), "INVALID_SECTION"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_SYNTAX), "INVALID_SYNTAX"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_ISSUER_DECODE_ERROR), "ISSUER_DECODE_ERROR"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_MISSING_VALUE), "MISSING_VALUE"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NEED_ORGANIZATION_AND_NUMBERS), "NEED_ORGANIZATION_AND_NUMBERS"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_CONFIG_DATABASE), "NO_CONFIG_DATABASE"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_ISSUER_CERTIFICATE), "NO_ISSUER_CERTIFICATE"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_ISSUER_DETAILS), "NO_ISSUER_DETAILS"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_POLICY_IDENTIFIER), "NO_POLICY_IDENTIFIER"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED), "NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_PUBLIC_KEY), "NO_PUBLIC_KEY"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_SUBJECT_DETAILS), "NO_SUBJECT_DETAILS"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_ODD_NUMBER_OF_DIGITS), "ODD_NUMBER_OF_DIGITS"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_OPERATION_NOT_DEFINED), "OPERATION_NOT_DEFINED"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_OTHERNAME_ERROR), "OTHERNAME_ERROR"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED), "POLICY_LANGUAGE_ALREADY_DEFINED"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_POLICY_PATH_LENGTH), "POLICY_PATH_LENGTH"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED), "POLICY_PATH_LENGTH_ALREADY_DEFINED"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_POLICY_SYNTAX_NOT_CURRENTLY_SUPPORTED), "POLICY_SYNTAX_NOT_CURRENTLY_SUPPORTED"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY), "POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_SECTION_NOT_FOUND), "SECTION_NOT_FOUND"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS), "UNABLE_TO_GET_ISSUER_DETAILS"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNABLE_TO_GET_ISSUER_KEYID), "UNABLE_TO_GET_ISSUER_KEYID"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT), "UNKNOWN_BIT_STRING_ARGUMENT"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNKNOWN_EXTENSION), "UNKNOWN_EXTENSION"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNKNOWN_EXTENSION_NAME), "UNKNOWN_EXTENSION_NAME"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNKNOWN_OPTION), "UNKNOWN_OPTION"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNSUPPORTED_OPTION), "UNSUPPORTED_OPTION"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNSUPPORTED_TYPE), "UNSUPPORTED_TYPE"},
+ {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_USER_TOO_LONG), "USER_TOO_LONG"},
+ {0, NULL},
+};