Compare commits
287 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a20bb7ff8b | |||
| b04ea033a3 | |||
| fc9c67599d | |||
| a7673facf8 | |||
| 28b267b357 | |||
| bd911af514 | |||
| 7ce2378750 | |||
| 47b8f00fdc | |||
| be8c8b4b1d | |||
| 8c9ceadc58 | |||
| 56aaf164ac | |||
| 27bc0f26c8 | |||
| 2fce1beda0 | |||
| e3b2a5d30d | |||
| 61e9245543 | |||
| 86c2b854b0 | |||
| a838f9dc7e | |||
| 66801feb17 | |||
| 02514002fd | |||
| 2056d7290a | |||
| 42a8cbe37c | |||
| 8dc226ca8f | |||
| 855d5046c7 | |||
| 67623735e0 | |||
| c367ee5439 | |||
| 8c565fa86c | |||
| 8793942c5c | |||
| 6d218d6d7a | |||
| 0a5f006736 | |||
| e7c95d91f8 | |||
| 3bba5ccf35 | |||
| ac4d5346ad | |||
| b8d677bfd0 | |||
| 66f8235510 | |||
| a08bba51a5 | |||
| 40e4ecb793 | |||
| a01aa9aa9f | |||
| 6bc18a3bd4 | |||
| 64619deaa3 | |||
| bd275702d2 | |||
| 73df153be8 | |||
| b25140c7b6 | |||
| 8db94be1d6 | |||
| 74b828f263 | |||
| e6f30e4ce1 | |||
| 13761f2833 | |||
| ba8f1864c1 | |||
| 4ddbc7bd0d | |||
| ca8c2c7eab | |||
| 964b2377d0 | |||
| 3bcbb37552 | |||
| a00fd08c2c | |||
| d66bbf3413 | |||
| 607f9807e5 | |||
| bf3f6caaf3 | |||
| 0a9222b824 | |||
| 238c274054 | |||
| 6aedfc137b | |||
| 896332581e | |||
| 929f842810 | |||
| 0967853d68 | |||
| ee2c1f3e68 | |||
| fa60369d6d | |||
| b8e2d6327a | |||
| 40e8c921ca | |||
| aa4c3f218e | |||
| d5dda9b803 | |||
| b1cbe19790 | |||
| 5b90eb98f6 | |||
| fdd5fed036 | |||
| b2c312d670 | |||
| 5b280a80df | |||
| 55761e6802 | |||
| 431e767c23 | |||
| 6cc352e216 | |||
| 2eb2889702 | |||
| 6dda166d21 | |||
| a02ed04d52 | |||
| f7412cb072 | |||
| 2d07d30c44 | |||
| cd8470f7fa | |||
| cfc120eb22 | |||
| 3b903f252a | |||
| 5be3a74c49 | |||
| dca1afb326 | |||
| f1db1a398d | |||
| 2637f3c431 | |||
| 696c13bd6a | |||
| 08e817d3e9 | |||
| ba94746eb2 | |||
| 4281bcd5d2 | |||
| 8f06074a91 | |||
| 4f94a8381a | |||
| a67b101594 | |||
| 98ca81daae | |||
| cb16f17b36 | |||
| 2a768d04c6 | |||
| f5beb883c2 | |||
| af92418b8b | |||
| 51073ce055 | |||
| d24fd47ff4 | |||
| ed84291188 | |||
| b26ab5c7bf | |||
| 3f5d13812a | |||
| fed560ff2a | |||
| cba7987978 | |||
| f6942f0d22 | |||
| acf2f34df5 | |||
| 6675cfddef | |||
| 4455e59980 | |||
| 883b5461d5 | |||
| 75d43b5785 | |||
| dd6c2e880f | |||
| 800046fecf | |||
| fadc975bf9 | |||
| 049fdfc7e0 | |||
| 71ea6b127d | |||
| 32ce0ac0d8 | |||
| 8e7bbbab15 | |||
| 941725789b | |||
| a37f286f4e | |||
| ea712e317f | |||
| 38636aba74 | |||
| 3b358b25b0 | |||
| 7f8c553d7f | |||
| f6632dae5f | |||
| a031b61230 | |||
| e8d0746b88 | |||
| d9229f9802 | |||
| 33febf6048 | |||
| 97250f4d64 | |||
| 31aad2dc2c | |||
| f8de2af7e3 | |||
| a05d427b41 | |||
| 3b777adb61 | |||
| 40e94701dc | |||
| f66e88228a | |||
| 2eb4bc5e89 | |||
| 619c8cec83 | |||
| e1068b76bd | |||
| 168fb2e98c | |||
| 11ac519d79 | |||
| fdb7a3580f | |||
| 24f5b18f93 | |||
| 75a1f23684 | |||
| dbf12fc2ce | |||
| 5dde62364e | |||
| 00f48c8273 | |||
| d1e3ce1fb0 | |||
| 64950cb07f | |||
| 4e840357fd | |||
| b15aa0aaef | |||
| 01f26f3f32 | |||
| 771df4416a | |||
| 1f1ac63bff | |||
| 666d16e262 | |||
| 31640931e6 | |||
| 7e58c5ef20 | |||
| 664e99a648 | |||
| be165a2e70 | |||
| e05b72c257 | |||
| 2450027e59 | |||
| 03a4b96c12 | |||
| 23c25d5b3a | |||
| a84b6f26a9 | |||
| c64d123933 | |||
| 751d1a1c22 | |||
| e52f4c4642 | |||
| b25a8999be | |||
| 89bd372a02 | |||
| 73ffb74b9e | |||
| e091af4f37 | |||
| 10154320fd | |||
| 2e9bb4eb96 | |||
| 861f28a624 | |||
| 4519a5a063 | |||
| 3b5b87f579 | |||
| 75d36eacf8 | |||
| 02afbd338e | |||
| 392cedd0a2 | |||
| 12fdd08a40 | |||
| 1de690b992 | |||
| 6c1f2b77de | |||
| a65c252f78 | |||
| 1c58471cc9 | |||
| e7136a978f | |||
| a4bafd33b3 | |||
| 4c7f5fa023 | |||
| 51776b0aeb | |||
| e1c3dad959 | |||
| f496249405 | |||
| ed9aed1ac6 | |||
| 63a0797ff2 | |||
| b949355132 | |||
| 312e1e4f66 | |||
| 575334657f | |||
| 81f030b106 | |||
| ced6e76661 | |||
| 737d2dffdf | |||
| e9c7b1c8ae | |||
| 21fa684236 | |||
| 9eaa3bd55d | |||
| 73d42e614c | |||
| b1cf48ea41 | |||
| 879efc3f3b | |||
| 08f5c76898 | |||
| 6b3ab72602 | |||
| cf0ce676d6 | |||
| 499742c60f | |||
| 6666886a9c | |||
| 15868b3bba | |||
| 42e93b6cf5 | |||
| 3a18bf0474 | |||
| e58f8a6b9a | |||
| 38570b26b8 | |||
| b7e5b08a20 | |||
| b1b76aee3c | |||
| cecf1a72ba | |||
| c03c218190 | |||
| 4015000e19 | |||
| 60931e2d8a | |||
| 6b35262272 | |||
| 40b24c8154 | |||
| 5663b634f4 | |||
| 1d6e36525d | |||
| 2186fbc22c | |||
| 246e27d807 | |||
| f231d6bfa6 | |||
| 6dc892fcdf | |||
| c5cc88d800 | |||
| e314e1c000 | |||
| 32c5b8dee3 | |||
| e64ef27cbe | |||
| 9a127b43b8 | |||
| 82dfea8d9e | |||
| 288ca7dcb4 | |||
| 9a4876e193 | |||
| f51f273ee8 | |||
| 36d59479a5 | |||
| 5a79ff5efd | |||
| 33fc2ba4e2 | |||
| 368cc3b7e7 | |||
| 683ffbbe57 | |||
| 9c2b36adbd | |||
| a16e86ced5 | |||
| c7d4d21413 | |||
| aba057a4e0 | |||
| 1682126fd8 | |||
| 54c259dec3 | |||
| a9c96bae8a | |||
| 6881ec0465 | |||
| 2978d055f6 | |||
| 2ff44b183a | |||
| a196ea15af | |||
| e51fb0fa71 | |||
| 769b386e97 | |||
| b86be3617d | |||
| 3c995f30e7 | |||
| d0beda01f9 | |||
| 3d8f0808e4 | |||
| a861460c89 | |||
| c0e15d1d9d | |||
| a23b68f564 | |||
| be90bf764a | |||
| 28d6979b7e | |||
| 24e36099ce | |||
| 8459d06599 | |||
| ce3773f9fe | |||
| 74795b32c6 | |||
| 046bc1fbe8 | |||
| 4cbb93195f | |||
| fd45ee7da8 | |||
| d816874c52 | |||
| 1ab133a9da | |||
| 6abaa316f0 | |||
| 0a471910b4 | |||
| 2762b3542d | |||
| 3536809644 | |||
| c11ea942b7 | |||
| 66d49b4952 | |||
| c79ae7aa8b | |||
| 3969fdf860 | |||
| 398085ba04 | |||
| e2ec654c9a | |||
| 617b818b49 | |||
| 4d71a9a2ca | |||
| 8997b2aa57 |
+67
-19
@@ -36,20 +36,48 @@ if (BORINGSSL_ALLOW_CXX_RUNTIME)
|
||||
add_definitions(-DBORINGSSL_ALLOW_CXX_RUNTIME)
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(C_CXX_FLAGS "-Wall -Werror -Wformat=2 -Wsign-compare -Wmissing-field-initializers -Wwrite-strings -ggdb -fvisibility=hidden -fno-common")
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CLANG 1)
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CLANG)
|
||||
# Note clang-cl is odd and sets both CLANG and MSVC. We base our configuration
|
||||
# primarily on our normal Clang one because the MSVC one is mostly
|
||||
# suppressions for an overaggressive -Wall.
|
||||
set(C_CXX_FLAGS "-Wall -Werror -Wformat=2 -Wsign-compare -Wmissing-field-initializers -Wwrite-strings")
|
||||
if(MSVC)
|
||||
# clang-cl sets different default warnings than clang.
|
||||
set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wno-unused-parameter -fmsc-version=1900")
|
||||
# googletest suppresses warning C4996 via a pragma, but clang-cl does not
|
||||
# honor it. Suppress it here to compensate. See https://crbug.com/772117.
|
||||
set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wno-deprecated-declarations")
|
||||
else()
|
||||
set(C_CXX_FLAGS "${C_CXX_FLAGS} -ggdb -fvisibility=hidden -fno-common")
|
||||
endif()
|
||||
|
||||
if(CLANG)
|
||||
set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wnewline-eof -fcolor-diagnostics")
|
||||
else()
|
||||
# GCC (at least 4.8.4) has a bug where it'll find unreachable free() calls
|
||||
# and declare that the code is trying to free a stack pointer.
|
||||
set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wno-free-nonheap-object")
|
||||
endif()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${C_CXX_FLAGS} -Wmissing-prototypes -Wold-style-definition -Wstrict-prototypes")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ${C_CXX_FLAGS} -Wmissing-declarations")
|
||||
|
||||
if(NOT BORINGSSL_ALLOW_CXX_RUNTIME)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions -fno-rtti")
|
||||
if(CLANG OR NOT "7.0.0" VERSION_GREATER CMAKE_C_COMPILER_VERSION)
|
||||
set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wimplicit-fallthrough")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${C_CXX_FLAGS} -Wmissing-prototypes -Wold-style-definition -Wstrict-prototypes")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${C_CXX_FLAGS} -Wmissing-declarations")
|
||||
|
||||
if(NOT MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
if(APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
||||
endif()
|
||||
if(NOT BORINGSSL_ALLOW_CXX_RUNTIME)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions -fno-rtti")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# In GCC, -Wmissing-declarations is the C++ spelling of -Wmissing-prototypes
|
||||
@@ -59,9 +87,14 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
# https://gcc.gnu.org/onlinedocs/gcc-7.1.0/gcc/Warning-Options.html#Warning-Options
|
||||
# https://clang.llvm.org/docs/DiagnosticsReference.html#wmissing-prototypes
|
||||
# https://clang.llvm.org/docs/DiagnosticsReference.html#wmissing-declarations
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wmissing-prototypes -Wimplicit-fallthrough")
|
||||
if(CLANG)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wmissing-prototypes")
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX AND "4.8" VERSION_GREATER CMAKE_C_COMPILER_VERSION)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-array-bounds")
|
||||
endif()
|
||||
|
||||
elseif(MSVC)
|
||||
set(MSVC_DISABLED_WARNINGS_LIST
|
||||
"C4061" # enumerator 'identifier' in switch of enum 'enumeration' is not
|
||||
@@ -78,8 +111,6 @@ elseif(MSVC)
|
||||
# possible loss of data
|
||||
"C4244" # 'function' : conversion from 'int' to 'uint8_t',
|
||||
# possible loss of data
|
||||
"C4245" # 'initializing' : conversion from 'long' to
|
||||
# 'unsigned long', signed/unsigned mismatch
|
||||
"C4267" # conversion from 'size_t' to 'int', possible loss of data
|
||||
"C4371" # layout of class may have changed from a previous version of the
|
||||
# compiler due to better packing of member '...'
|
||||
@@ -124,7 +155,6 @@ elseif(MSVC)
|
||||
${MSVC_LEVEL4_WARNINGS_LIST})
|
||||
set(CMAKE_C_FLAGS "-Wall -WX ${MSVC_DISABLED_WARNINGS_STR} ${MSVC_LEVEL4_WARNINGS_STR}")
|
||||
set(CMAKE_CXX_FLAGS "-Wall -WX ${MSVC_DISABLED_WARNINGS_STR} ${MSVC_LEVEL4_WARNINGS_STR}")
|
||||
set(CMAKE_ASM_NASM_FLAGS "-g cv8")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
@@ -138,14 +168,13 @@ if(WIN32)
|
||||
endif()
|
||||
|
||||
if((CMAKE_COMPILER_IS_GNUCXX AND CMAKE_C_COMPILER_VERSION VERSION_GREATER "4.7.99") OR
|
||||
CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
CLANG)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshadow")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wshadow")
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
if ((CMAKE_C_COMPILER_VERSION VERSION_GREATER "4.8.99") OR
|
||||
CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
if ((CMAKE_C_COMPILER_VERSION VERSION_GREATER "4.8.99") OR CLANG)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11")
|
||||
else()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")
|
||||
@@ -158,7 +187,7 @@ if(NOT WIN32)
|
||||
endif()
|
||||
|
||||
if(FUZZ)
|
||||
if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
if(NOT CLANG)
|
||||
message(FATAL_ERROR "You need to build with Clang for fuzzing to work")
|
||||
endif()
|
||||
|
||||
@@ -186,7 +215,7 @@ if (BUILD_SHARED_LIBS)
|
||||
endif()
|
||||
|
||||
if (MSAN)
|
||||
if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
if(NOT CLANG)
|
||||
message(FATAL_ERROR "Cannot enable MSAN unless using Clang")
|
||||
endif()
|
||||
|
||||
@@ -200,7 +229,7 @@ if (MSAN)
|
||||
endif()
|
||||
|
||||
if (ASAN)
|
||||
if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
if(NOT CLANG)
|
||||
message(FATAL_ERROR "Cannot enable ASAN unless using Clang")
|
||||
endif()
|
||||
|
||||
@@ -209,6 +238,24 @@ if (ASAN)
|
||||
set(OPENSSL_NO_ASM "1")
|
||||
endif()
|
||||
|
||||
if(CFI)
|
||||
if(NOT CLANG)
|
||||
message(FATAL_ERROR "Cannot enable CFI unless using Clang")
|
||||
endif()
|
||||
|
||||
# TODO(crbug.com/785442): Remove -fsanitize-cfi-icall-generalize-pointers.
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=cfi -fno-sanitize-trap=cfi -fsanitize-cfi-icall-generalize-pointers -flto")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=cfi -fno-sanitize-trap=cfi -fsanitize-cfi-icall-generalize-pointers -flto")
|
||||
# We use Chromium's copy of clang, which requires -fuse-ld=lld if building
|
||||
# with -flto. That, in turn, can't handle -ggdb.
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=lld")
|
||||
string(REPLACE "-ggdb" "-g" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
|
||||
string(REPLACE "-ggdb" "-g" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
# -flto causes object files to contain LLVM bitcode. Mixing those with
|
||||
# assembly output in the same static library breaks the linker.
|
||||
set(OPENSSL_NO_ASM "1")
|
||||
endif()
|
||||
|
||||
if (GCOV)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
|
||||
@@ -281,7 +328,7 @@ if (ANDROID AND ${ARCH} STREQUAL "arm")
|
||||
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -march=${CMAKE_SYSTEM_PROCESSOR}")
|
||||
endif()
|
||||
|
||||
if (${ARCH} STREQUAL "x86" AND APPLE)
|
||||
if (${ARCH} STREQUAL "x86" AND APPLE AND ${CMAKE_VERSION} VERSION_LESS "3.0")
|
||||
# With CMake 2.8.x, ${CMAKE_SYSTEM_PROCESSOR} evalutes to i386 on OS X,
|
||||
# but clang defaults to 64-bit builds on OS X unless otherwise told.
|
||||
# Set ARCH to x86_64 so clang and CMake agree. This is fixed in CMake 3.
|
||||
@@ -309,6 +356,7 @@ add_custom_command(
|
||||
add_library(crypto_test_data OBJECT crypto_test_data.cc)
|
||||
|
||||
add_subdirectory(crypto)
|
||||
add_subdirectory(third_party/fiat)
|
||||
add_subdirectory(ssl)
|
||||
add_subdirectory(ssl/test)
|
||||
add_subdirectory(fipstools)
|
||||
|
||||
@@ -6,7 +6,9 @@ Contributors to BoringSSL are required to follow the CLA rules for Chromium:
|
||||
https://cla.developers.google.com/clas
|
||||
|
||||
Some files from Intel are under yet another license, which is also included
|
||||
underneath.
|
||||
underneath. Files in third_party/ have their own licenses, as described
|
||||
therein. The MIT license, for third_party/fiat, which, unlike other third_party
|
||||
directories, is compiled into non-test libraries, is included below.
|
||||
|
||||
The OpenSSL toolkit stays under a dual license, i.e. both the conditions of the
|
||||
OpenSSL License and the original SSLeay license apply to the toolkit. See below
|
||||
@@ -190,3 +192,27 @@ Some files from Intel carry the following license:
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 code in third_party/fiat carries the MIT license:
|
||||
|
||||
Copyright (c) 2015-2016 the fiat-crypto authors (see
|
||||
https://github.com/mit-plv/fiat-crypto/blob/master/AUTHORS).
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
+41
-16
@@ -6,17 +6,27 @@ BoringSSL support, provided they do not use removed APIs. In general, see if the
|
||||
library compiles and, on failure, consult the documentation in the header files
|
||||
and see if problematic features can be removed.
|
||||
|
||||
In some cases, BoringSSL-specific code may be necessary. In that case, the
|
||||
`OPENSSL_IS_BORINGSSL` preprocessor macro may be used in `#ifdef`s. This macro
|
||||
should also be used in lieu of the presence of any particular function to detect
|
||||
OpenSSL vs BoringSSL in configure scripts, etc., where those are necessary.
|
||||
Before using the preprocessor, however, contact the BoringSSL maintainers about
|
||||
the missing APIs. If not an intentionally removed feature, BoringSSL will
|
||||
typically add compatibility functions for convenience.
|
||||
BoringSSL's `OPENSSL_VERSION_NUMBER` matches the OpenSSL version it targets.
|
||||
Version checks for OpenSSL should ideally work as-is in BoringSSL. BoringSSL
|
||||
also defines upstream's `OPENSSL_NO_*` feature macros corresponding to removed
|
||||
features. If the preprocessor is needed, use these version checks or feature
|
||||
macros where possible, especially when patching third-party projects. Such
|
||||
patches are more generally useful to OpenSSL consumers and thus more
|
||||
appropriate to send upstream.
|
||||
|
||||
For convenience, BoringSSL defines upstream's `OPENSSL_NO_*` feature macros
|
||||
corresponding to removed features. These may also be used to disable code which
|
||||
uses a removed feature.
|
||||
In some cases, BoringSSL-specific code may be necessary. Use the
|
||||
`OPENSSL_IS_BORINGSSL` preprocessor macro in `#ifdef`s. However, first contact
|
||||
the BoringSSL maintainers about the missing APIs. We will typically add
|
||||
compatibility functions for convenience. In particular, *contact BoringSSL
|
||||
maintainers before working around missing OpenSSL 1.1.0 accessors*. BoringSSL
|
||||
was originally derived from OpenSSL 1.0.2 but now targets OpenSSL 1.1.0. Some
|
||||
newer APIs may be missing but can be added on request. (Not all projects have
|
||||
been ported to OpenSSL 1.1.0, so BoringSSL also remains largely compatible with
|
||||
OpenSSL 1.0.2.)
|
||||
|
||||
The `OPENSSL_IS_BORINGSSL` macro may also be used to distinguish OpenSSL from
|
||||
BoringSSL in configure scripts. Do not use the presence or absence of particular
|
||||
symbols to detect BoringSSL.
|
||||
|
||||
Note: BoringSSL does *not* have a stable API or ABI. It must be updated with its
|
||||
consumers. It is not suitable for, say, a system library in a traditional Linux
|
||||
@@ -39,15 +49,19 @@ code, particularly to avoid compiler warnings.
|
||||
Most notably, the `STACK_OF(T)` types have all been converted to use `size_t`
|
||||
instead of `int` for indices and lengths.
|
||||
|
||||
### Reference counts
|
||||
### Reference counts and opaque types
|
||||
|
||||
Some external consumers increment reference counts directly by calling
|
||||
`CRYPTO_add` with the corresponding `CRYPTO_LOCK_*` value.
|
||||
`CRYPTO_add` with the corresponding `CRYPTO_LOCK_*` value. These APIs no longer
|
||||
exist in BoringSSL. Instead, code which increments reference counts should call
|
||||
the corresponding `FOO_up_ref` function, such as `EVP_PKEY_up_ref`.
|
||||
|
||||
These APIs no longer exist in BoringSSL. Instead, code which increments
|
||||
reference counts should call the corresponding `FOO_up_ref` function, such as
|
||||
`EVP_PKEY_up_ref`. Note that not all of these APIs are present in OpenSSL and
|
||||
may require `#ifdef`s.
|
||||
BoringSSL also hides some structs which were previously exposed in OpenSSL
|
||||
1.0.2, particularly in libssl. Use the relevant accessors instead.
|
||||
|
||||
Note that some of these APIs were added in OpenSSL 1.1.0, so projects which do
|
||||
not yet support 1.1.0 may need additional `#ifdef`s. Projects supporting OpenSSL
|
||||
1.1.0 should not require modification.
|
||||
|
||||
### Error codes
|
||||
|
||||
@@ -165,6 +179,17 @@ recommended to avoid the `out` parameter completely and always pass in `NULL`.
|
||||
Note that less error-prone APIs are available for BoringSSL-specific code (see
|
||||
below).
|
||||
|
||||
### Memory allocation
|
||||
|
||||
OpenSSL provides wrappers `OPENSSL_malloc` and `OPENSSL_free` over the standard
|
||||
`malloc` and `free`. Memory allocated by OpenSSL should be released with
|
||||
`OPENSSL_free`, not the standard `free`. However, by default, they are
|
||||
implemented directly using `malloc` and `free`, so code which mixes them up
|
||||
usually works.
|
||||
|
||||
In BoringSSL, these functions maintain additional book-keeping to zero memory
|
||||
on `OPENSSL_free`, so any mixups must be fixed.
|
||||
|
||||
## Optional BoringSSL-specific simplifications
|
||||
|
||||
BoringSSL makes some changes to OpenSSL which simplify the API but remain
|
||||
|
||||
@@ -31,10 +31,10 @@ Variable declarations in the middle of a function or inside a `for` loop are
|
||||
allowed and preferred where possible. Note that the common `goto err` cleanup
|
||||
pattern requires lifting some variable declarations.
|
||||
|
||||
Comments should be `/* C-style */` for consistency.
|
||||
Comments should be `// C99-style` for consistency with C++.
|
||||
|
||||
When declaration pointer types, `*` should be placed next to the variable
|
||||
name, not the type. So
|
||||
When declaring pointer types, `*` should be placed next to the variable name,
|
||||
not the type. So
|
||||
|
||||
uint8_t *ptr;
|
||||
|
||||
@@ -60,6 +60,19 @@ constants for flags. If adding values to an existing set of `#define`s,
|
||||
continue with `#define`.
|
||||
|
||||
|
||||
## libssl
|
||||
|
||||
libssl was originally written in C but is being incrementally rewritten in
|
||||
C++11. As of writing, much of the style matches our C conventions rather than
|
||||
Google C++. Additionally, libssl on Linux currently may not depend on the C++
|
||||
runtime. See the C++ utilities in `ssl/internal.h` for replacements for
|
||||
problematic C++ constructs. The `util/check_imported_libraries.go` script may be
|
||||
used with a shared library build to check if a new construct is okay.
|
||||
|
||||
If unsure, match surrounding code. Discrepancies between it and Google C++ style
|
||||
will be fixed over time.
|
||||
|
||||
|
||||
## Formatting
|
||||
|
||||
Single-statement blocks are not allowed. All conditions and loops must
|
||||
@@ -185,23 +198,23 @@ behavior of the function. Pay special note to success/failure behaviors
|
||||
and caller obligations on object lifetimes. If this sacrifices
|
||||
conciseness, consider simplifying the function's behavior.
|
||||
|
||||
/* 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. */
|
||||
// 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.
|
||||
OPENSSL_EXPORT int EVP_DigestVerifyUpdate(EVP_MD_CTX *ctx, const void *data,
|
||||
size_t len);
|
||||
|
||||
Explicitly mention any surprising edge cases or deviations from common
|
||||
return value patterns in legacy functions.
|
||||
|
||||
/* 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. */
|
||||
// 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.
|
||||
OPENSSL_EXPORT int RSA_private_encrypt(int flen, const uint8_t *from,
|
||||
uint8_t *to, RSA *rsa, int padding);
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ if(NOT OPENSSL_NO_ASM)
|
||||
# CMake does not add -isysroot and -arch flags to assembly.
|
||||
if (APPLE)
|
||||
if (CMAKE_OSX_SYSROOT)
|
||||
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -isysroot ${CMAKE_OSX_SYSROOT}")
|
||||
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -isysroot \"${CMAKE_OSX_SYSROOT}\"")
|
||||
endif()
|
||||
foreach(arch ${CMAKE_OSX_ARCHITECTURES})
|
||||
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -arch ${arch}")
|
||||
@@ -53,6 +53,7 @@ if(NOT OPENSSL_NO_ASM)
|
||||
set(PERLASM_STYLE win32n)
|
||||
set(PERLASM_FLAGS "-DOPENSSL_IA32_SSE2")
|
||||
endif()
|
||||
set(CMAKE_ASM_NASM_FLAGS "-g cv8")
|
||||
|
||||
# On Windows, we use the NASM output, specifically built with Yasm.
|
||||
set(ASM_EXT asm)
|
||||
@@ -178,6 +179,7 @@ add_library(
|
||||
$<TARGET_OBJECTS:chacha>
|
||||
$<TARGET_OBJECTS:poly1305>
|
||||
$<TARGET_OBJECTS:curve25519>
|
||||
$<TARGET_OBJECTS:fiat>
|
||||
$<TARGET_OBJECTS:buf>
|
||||
$<TARGET_OBJECTS:bn_extra>
|
||||
$<TARGET_OBJECTS:bio>
|
||||
@@ -219,6 +221,7 @@ add_executable(
|
||||
|
||||
asn1/asn1_test.cc
|
||||
base64/base64_test.cc
|
||||
buf/buf_test.cc
|
||||
bio/bio_test.cc
|
||||
bytestring/bytestring_test.cc
|
||||
chacha/chacha_test.cc
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
@@ -139,6 +140,11 @@ ASN1_BIT_STRING *c2i_ASN1_BIT_STRING(ASN1_BIT_STRING **a,
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (len > INT_MAX) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_STRING_TOO_LONG);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if ((a == NULL) || ((*a) == NULL)) {
|
||||
if ((ret = M_ASN1_BIT_STRING_new()) == NULL)
|
||||
return (NULL);
|
||||
@@ -211,8 +217,7 @@ int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value)
|
||||
if (a->data == NULL)
|
||||
c = (unsigned char *)OPENSSL_malloc(w + 1);
|
||||
else
|
||||
c = (unsigned char *)OPENSSL_realloc_clean(a->data,
|
||||
a->length, w + 1);
|
||||
c = (unsigned char *)OPENSSL_realloc(a->data, w + 1);
|
||||
if (c == NULL) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
|
||||
+22
-11
@@ -56,6 +56,7 @@
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
@@ -110,7 +111,6 @@ int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v)
|
||||
long ASN1_ENUMERATED_get(ASN1_ENUMERATED *a)
|
||||
{
|
||||
int neg = 0, i;
|
||||
long r = 0;
|
||||
|
||||
if (a == NULL)
|
||||
return (0L);
|
||||
@@ -120,20 +120,31 @@ long ASN1_ENUMERATED_get(ASN1_ENUMERATED *a)
|
||||
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;
|
||||
OPENSSL_COMPILE_ASSERT(sizeof(uint64_t) >= sizeof(long),
|
||||
long_larger_than_uint64_t);
|
||||
|
||||
for (i = 0; i < a->length; i++) {
|
||||
r <<= 8;
|
||||
r |= (unsigned char)a->data[i];
|
||||
if (a->length > (int)sizeof(uint64_t)) {
|
||||
/* hmm... a bit ugly */
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint64_t r64 = 0;
|
||||
if (a->data != NULL) {
|
||||
for (i = 0; i < a->length; i++) {
|
||||
r64 <<= 8;
|
||||
r64 |= (unsigned char)a->data[i];
|
||||
}
|
||||
|
||||
if (r64 > LONG_MAX) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
long r = (long) r64;
|
||||
if (neg)
|
||||
r = -r;
|
||||
return (r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
ASN1_ENUMERATED *BN_to_ASN1_ENUMERATED(BIGNUM *bn, ASN1_ENUMERATED *ai)
|
||||
|
||||
@@ -81,6 +81,9 @@ int ASN1_i2d_bio(i2d_of_void *i2d, BIO *out, void *x)
|
||||
int i, j = 0, n, ret = 1;
|
||||
|
||||
n = i2d(x, NULL);
|
||||
if (n <= 0)
|
||||
return 0;
|
||||
|
||||
b = (char *)OPENSSL_malloc(n);
|
||||
if (b == NULL) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
|
||||
+19
-8
@@ -57,6 +57,7 @@
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
@@ -385,7 +386,6 @@ int ASN1_INTEGER_set(ASN1_INTEGER *a, long v)
|
||||
long ASN1_INTEGER_get(const ASN1_INTEGER *a)
|
||||
{
|
||||
int neg = 0, i;
|
||||
long r = 0;
|
||||
|
||||
if (a == NULL)
|
||||
return (0L);
|
||||
@@ -395,20 +395,31 @@ long ASN1_INTEGER_get(const ASN1_INTEGER *a)
|
||||
else if (i != V_ASN1_INTEGER)
|
||||
return -1;
|
||||
|
||||
if (a->length > (int)sizeof(long)) {
|
||||
OPENSSL_COMPILE_ASSERT(sizeof(uint64_t) >= sizeof(long),
|
||||
long_larger_than_uint64_t);
|
||||
|
||||
if (a->length > (int)sizeof(uint64_t)) {
|
||||
/* 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];
|
||||
uint64_t r64 = 0;
|
||||
if (a->data != NULL) {
|
||||
for (i = 0; i < a->length; i++) {
|
||||
r64 <<= 8;
|
||||
r64 |= (unsigned char)a->data[i];
|
||||
}
|
||||
|
||||
if (r64 > LONG_MAX) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
long r = (long) r64;
|
||||
if (neg)
|
||||
r = -r;
|
||||
return (r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
ASN1_INTEGER *BN_to_ASN1_INTEGER(const BIGNUM *bn, ASN1_INTEGER *ai)
|
||||
|
||||
@@ -87,134 +87,6 @@ int i2d_ASN1_OBJECT(ASN1_OBJECT *a, unsigned char **pp)
|
||||
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, ASN1_R_FIRST_NUM_TOO_LARGE);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (num <= 0) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_SECOND_NUMBER);
|
||||
goto err;
|
||||
}
|
||||
c = *(p++);
|
||||
num--;
|
||||
for (;;) {
|
||||
if (num <= 0)
|
||||
break;
|
||||
if ((c != '.') && (c != ' ')) {
|
||||
OPENSSL_PUT_ERROR(ASN1, 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, 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, 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--) {
|
||||
BN_ULONG t = BN_div_word(bl, 0x80L);
|
||||
if (t == (BN_ULONG)-1)
|
||||
goto err;
|
||||
tmp[i++] = (unsigned char)t;
|
||||
}
|
||||
} 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, 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);
|
||||
|
||||
@@ -435,3 +435,8 @@ unsigned char *ASN1_STRING_data(ASN1_STRING *x)
|
||||
{
|
||||
return M_ASN1_STRING_data(x);
|
||||
}
|
||||
|
||||
const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *x)
|
||||
{
|
||||
return x->data;
|
||||
}
|
||||
|
||||
@@ -90,6 +90,9 @@ int OPENSSL_gmtime_diff(int *out_days, int *out_secs, const struct tm *from,
|
||||
int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d);
|
||||
int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d);
|
||||
|
||||
void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it,
|
||||
int combine);
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} /* extern C */
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/asn1t.h>
|
||||
@@ -147,15 +148,6 @@ ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **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
|
||||
@@ -188,6 +180,14 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
|
||||
else
|
||||
asn1_cb = 0;
|
||||
|
||||
/*
|
||||
* Bound |len| to comfortably fit in an int. Lengths in this module often
|
||||
* switch between int and long without overflow checks.
|
||||
*/
|
||||
if (len > INT_MAX/2) {
|
||||
len = INT_MAX/2;
|
||||
}
|
||||
|
||||
switch (it->itype) {
|
||||
case ASN1_ITYPE_PRIMITIVE:
|
||||
if (it->templates) {
|
||||
|
||||
@@ -256,12 +256,6 @@ int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -59,8 +59,7 @@
|
||||
#include <openssl/asn1t.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
static void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it,
|
||||
int combine);
|
||||
#include "asn1_locl.h"
|
||||
|
||||
/* Free up an ASN1 structure */
|
||||
|
||||
@@ -74,8 +73,7 @@ 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)
|
||||
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;
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/obj.h>
|
||||
|
||||
#include "asn1_locl.h"
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
@@ -201,7 +202,7 @@ static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it,
|
||||
return 1;
|
||||
|
||||
memerr2:
|
||||
ASN1_item_ex_free(pval, it);
|
||||
asn1_item_combine_free(pval, it, combine);
|
||||
memerr:
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
#ifdef CRYPTO_MDEBUG
|
||||
@@ -211,7 +212,7 @@ static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it,
|
||||
return 0;
|
||||
|
||||
auxerr2:
|
||||
ASN1_item_ex_free(pval, it);
|
||||
asn1_item_combine_free(pval, it, combine);
|
||||
auxerr:
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_AUX_ERROR);
|
||||
#ifdef CRYPTO_MDEBUG
|
||||
|
||||
@@ -555,3 +555,82 @@ void BIO_set_retry_special(BIO *bio) {
|
||||
}
|
||||
|
||||
int BIO_set_write_buffer_size(BIO *bio, int buffer_size) { return 0; }
|
||||
|
||||
static struct CRYPTO_STATIC_MUTEX g_index_lock = CRYPTO_STATIC_MUTEX_INIT;
|
||||
static int g_index = BIO_TYPE_START;
|
||||
|
||||
int BIO_get_new_index(void) {
|
||||
CRYPTO_STATIC_MUTEX_lock_write(&g_index_lock);
|
||||
// If |g_index| exceeds 255, it will collide with the flags bits.
|
||||
int ret = g_index > 255 ? -1 : g_index++;
|
||||
CRYPTO_STATIC_MUTEX_unlock_write(&g_index_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
BIO_METHOD *BIO_meth_new(int type, const char *name) {
|
||||
BIO_METHOD *method = OPENSSL_malloc(sizeof(BIO_METHOD));
|
||||
if (method == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
OPENSSL_memset(method, 0, sizeof(BIO_METHOD));
|
||||
method->type = type;
|
||||
method->name = name;
|
||||
return method;
|
||||
}
|
||||
|
||||
void BIO_meth_free(BIO_METHOD *method) {
|
||||
OPENSSL_free(method);
|
||||
}
|
||||
|
||||
int BIO_meth_set_create(BIO_METHOD *method,
|
||||
int (*create)(BIO *)) {
|
||||
method->create = create;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BIO_meth_set_destroy(BIO_METHOD *method,
|
||||
int (*destroy)(BIO *)) {
|
||||
method->destroy = destroy;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BIO_meth_set_write(BIO_METHOD *method,
|
||||
int (*write)(BIO *, const char *, int)) {
|
||||
method->bwrite = write;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BIO_meth_set_read(BIO_METHOD *method,
|
||||
int (*read)(BIO *, char *, int)) {
|
||||
method->bread = read;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BIO_meth_set_gets(BIO_METHOD *method,
|
||||
int (*gets)(BIO *, char *, int)) {
|
||||
method->bgets = gets;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BIO_meth_set_ctrl(BIO_METHOD *method,
|
||||
long (*ctrl)(BIO *, int, long, void *)) {
|
||||
method->ctrl = ctrl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void BIO_set_data(BIO *bio, void *ptr) { bio->ptr = ptr; }
|
||||
|
||||
void *BIO_get_data(BIO *bio) { return bio->ptr; }
|
||||
|
||||
void BIO_set_init(BIO *bio, int init) { bio->init = init; }
|
||||
|
||||
int BIO_get_init(BIO *bio) { return bio->init; }
|
||||
|
||||
void BIO_set_shutdown(BIO *bio, int shutdown) { bio->shutdown = shutdown; }
|
||||
|
||||
int BIO_get_shutdown(BIO *bio) { return bio->shutdown; }
|
||||
|
||||
int BIO_meth_set_puts(BIO_METHOD *method, int (*puts)(BIO *, const char *)) {
|
||||
// Ignore the parameter. We implement |BIO_puts| using |BIO_write|.
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -12,10 +12,6 @@
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
#if !defined(_POSIX_C_SOURCE)
|
||||
#define _POSIX_C_SOURCE 201410L
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
|
||||
@@ -190,6 +190,7 @@ static long fd_ctrl(BIO *b, int cmd, long num, void *ptr) {
|
||||
switch (cmd) {
|
||||
case BIO_CTRL_RESET:
|
||||
num = 0;
|
||||
OPENSSL_FALLTHROUGH;
|
||||
case BIO_C_FILE_SEEK:
|
||||
ret = 0;
|
||||
if (b->init) {
|
||||
|
||||
@@ -183,6 +183,7 @@ static long file_ctrl(BIO *b, int cmd, long num, void *ptr) {
|
||||
switch (cmd) {
|
||||
case BIO_CTRL_RESET:
|
||||
num = 0;
|
||||
OPENSSL_FALLTHROUGH;
|
||||
case BIO_C_FILE_SEEK:
|
||||
ret = (long)fseek(fp, num, 0);
|
||||
break;
|
||||
|
||||
@@ -54,10 +54,6 @@
|
||||
* copied and put under another distribution licence
|
||||
* [including the GNU Public Licence.] */
|
||||
|
||||
#if !defined(_POSIX_C_SOURCE)
|
||||
#define _POSIX_C_SOURCE 201410L // for snprintf, vprintf etc
|
||||
#endif
|
||||
|
||||
#include <openssl/bio.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
@@ -42,22 +42,6 @@ int BN_parse_asn1_unsigned(CBS *cbs, BIGNUM *ret) {
|
||||
return BN_bin2bn(CBS_data(&child), CBS_len(&child), ret) != NULL;
|
||||
}
|
||||
|
||||
int BN_parse_asn1_unsigned_buggy(CBS *cbs, BIGNUM *ret) {
|
||||
CBS child;
|
||||
if (!CBS_get_asn1(cbs, &child, CBS_ASN1_INTEGER) ||
|
||||
CBS_len(&child) == 0) {
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_BAD_ENCODING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This function intentionally does not reject negative numbers or non-minimal
|
||||
// encodings. Estonian IDs issued between September 2014 to September 2015 are
|
||||
// broken. See https://crbug.com/532048 and https://crbug.com/534766.
|
||||
//
|
||||
// TODO(davidben): Remove this code and callers in March 2016.
|
||||
return BN_bin2bn(CBS_data(&child), CBS_len(&child), ret) != NULL;
|
||||
}
|
||||
|
||||
int BN_marshal_asn1(CBB *cbb, const BIGNUM *bn) {
|
||||
// Negative numbers are unsupported.
|
||||
if (BN_is_negative(bn)) {
|
||||
|
||||
+19
-27
@@ -82,15 +82,11 @@ void BUF_MEM_free(BUF_MEM *buf) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (buf->data != NULL) {
|
||||
OPENSSL_cleanse(buf->data, buf->max);
|
||||
OPENSSL_free(buf->data);
|
||||
}
|
||||
|
||||
OPENSSL_free(buf->data);
|
||||
OPENSSL_free(buf);
|
||||
}
|
||||
|
||||
static int buf_mem_reserve(BUF_MEM *buf, size_t cap, int clean) {
|
||||
int BUF_MEM_reserve(BUF_MEM *buf, size_t cap) {
|
||||
if (buf->max >= cap) {
|
||||
return 1;
|
||||
}
|
||||
@@ -109,17 +105,7 @@ static int buf_mem_reserve(BUF_MEM *buf, size_t cap, int clean) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *new_buf;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
char *new_buf = OPENSSL_realloc(buf->data, alloc_size);
|
||||
if (new_buf == NULL) {
|
||||
OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
@@ -130,12 +116,8 @@ static int buf_mem_reserve(BUF_MEM *buf, size_t cap, int clean) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BUF_MEM_reserve(BUF_MEM *buf, size_t cap) {
|
||||
return buf_mem_reserve(buf, cap, 0 /* don't clear old buffer contents. */);
|
||||
}
|
||||
|
||||
static size_t buf_mem_grow(BUF_MEM *buf, size_t len, int clean) {
|
||||
if (!buf_mem_reserve(buf, len, clean)) {
|
||||
size_t BUF_MEM_grow(BUF_MEM *buf, size_t len) {
|
||||
if (!BUF_MEM_reserve(buf, len)) {
|
||||
return 0;
|
||||
}
|
||||
if (buf->length < len) {
|
||||
@@ -145,12 +127,22 @@ static size_t buf_mem_grow(BUF_MEM *buf, size_t len, int clean) {
|
||||
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);
|
||||
}
|
||||
|
||||
size_t BUF_MEM_grow_clean(BUF_MEM *buf, size_t len) {
|
||||
return buf_mem_grow(buf, len, 1 /* clear old buffer contents. */);
|
||||
int BUF_MEM_append(BUF_MEM *buf, const void *in, size_t len) {
|
||||
size_t new_len = buf->length + len;
|
||||
if (new_len < len) {
|
||||
OPENSSL_PUT_ERROR(BUF, ERR_R_OVERFLOW);
|
||||
return 0;
|
||||
}
|
||||
if (!BUF_MEM_reserve(buf, new_len)) {
|
||||
return 0;
|
||||
}
|
||||
OPENSSL_memcpy(buf->data + buf->length, in, len);
|
||||
buf->length = new_len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *BUF_strdup(const char *str) {
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/* Copyright (c) 2017, 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/buf.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
||||
TEST(BufTest, Basic) {
|
||||
bssl::UniquePtr<BUF_MEM> buf(BUF_MEM_new());
|
||||
ASSERT_TRUE(buf);
|
||||
EXPECT_EQ(0u, buf->length);
|
||||
|
||||
// Use BUF_MEM_reserve to increase buf->max.
|
||||
ASSERT_TRUE(BUF_MEM_reserve(buf.get(), 200));
|
||||
EXPECT_GE(buf->max, 200u);
|
||||
EXPECT_EQ(0u, buf->length);
|
||||
|
||||
// BUF_MEM_reserve with a smaller cap is a no-op.
|
||||
size_t old_max = buf->max;
|
||||
ASSERT_TRUE(BUF_MEM_reserve(buf.get(), 100));
|
||||
EXPECT_EQ(old_max, buf->max);
|
||||
EXPECT_EQ(0u, buf->length);
|
||||
|
||||
// BUF_MEM_grow can increase the length without reallocating.
|
||||
ASSERT_EQ(100u, BUF_MEM_grow(buf.get(), 100));
|
||||
EXPECT_EQ(100u, buf->length);
|
||||
EXPECT_EQ(old_max, buf->max);
|
||||
memset(buf->data, 'A', buf->length);
|
||||
|
||||
// If BUF_MEM_reserve reallocates, it preserves the contents.
|
||||
ASSERT_TRUE(BUF_MEM_reserve(buf.get(), old_max + 1));
|
||||
ASSERT_GE(buf->max, old_max + 1);
|
||||
EXPECT_EQ(100u, buf->length);
|
||||
for (size_t i = 0; i < 100; i++) {
|
||||
EXPECT_EQ('A', buf->data[i]);
|
||||
}
|
||||
|
||||
// BUF_MEM_grow should zero everything beyond buf->length.
|
||||
memset(buf->data, 'B', buf->max);
|
||||
ASSERT_EQ(150u, BUF_MEM_grow(buf.get(), 150));
|
||||
EXPECT_EQ(150u, buf->length);
|
||||
for (size_t i = 0; i < 100; i++) {
|
||||
EXPECT_EQ('B', buf->data[i]);
|
||||
}
|
||||
for (size_t i = 100; i < 150; i++) {
|
||||
EXPECT_EQ(0, buf->data[i]);
|
||||
}
|
||||
|
||||
// BUF_MEM_grow can rellocate if necessary.
|
||||
size_t new_len = buf->max + 1;
|
||||
ASSERT_EQ(new_len, BUF_MEM_grow(buf.get(), new_len));
|
||||
EXPECT_GE(buf->max, new_len);
|
||||
EXPECT_EQ(new_len, buf->length);
|
||||
for (size_t i = 0; i < 100; i++) {
|
||||
EXPECT_EQ('B', buf->data[i]);
|
||||
}
|
||||
for (size_t i = 100; i < new_len; i++) {
|
||||
EXPECT_EQ(0, buf->data[i]);
|
||||
}
|
||||
|
||||
// BUF_MEM_grow can shink.
|
||||
ASSERT_EQ(50u, BUF_MEM_grow(buf.get(), 50));
|
||||
EXPECT_EQ(50u, buf->length);
|
||||
for (size_t i = 0; i < 50; i++) {
|
||||
EXPECT_EQ('B', buf->data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BufTest, Append) {
|
||||
bssl::UniquePtr<BUF_MEM> buf(BUF_MEM_new());
|
||||
ASSERT_TRUE(buf);
|
||||
|
||||
ASSERT_TRUE(BUF_MEM_append(buf.get(), nullptr, 0));
|
||||
ASSERT_TRUE(BUF_MEM_append(buf.get(), "hello ", 6));
|
||||
ASSERT_TRUE(BUF_MEM_append(buf.get(), nullptr, 0));
|
||||
ASSERT_TRUE(BUF_MEM_append(buf.get(), "world", 5));
|
||||
std::string str(128, 'A');
|
||||
ASSERT_TRUE(BUF_MEM_append(buf.get(), str.data(), str.size()));
|
||||
|
||||
EXPECT_EQ("hello world" + str, std::string(buf->data, buf->length));
|
||||
}
|
||||
@@ -787,3 +787,57 @@ TEST(CBSTest, BitString) {
|
||||
CBS_asn1_bitstring_has_bit(&cbs, test.bit));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CBBTest, AddOIDFromText) {
|
||||
const struct {
|
||||
const char *in;
|
||||
bool ok;
|
||||
std::vector<uint8_t> out;
|
||||
} kTests[] = {
|
||||
// Some valid values.
|
||||
{"1.2.3.4", true, {0x2a, 0x3, 0x4}},
|
||||
{"1.2.840.113554.4.1.72585",
|
||||
true,
|
||||
{0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, 0x01, 0x84, 0xb7, 0x09}},
|
||||
// Test edge cases around the first component.
|
||||
{"0.39", true, {0x27}},
|
||||
{"0.40", false, {}},
|
||||
{"1.0", true, {0x28}},
|
||||
{"1.39", true, {0x4f}},
|
||||
{"1.40", false, {}},
|
||||
{"2.0", true, {0x50}},
|
||||
{"2.1", true, {0x51}},
|
||||
{"2.40", true, {0x78}},
|
||||
// The empty string is not an OID.
|
||||
{"", false, {}},
|
||||
// No empty components.
|
||||
{".1.2.3.4.5", false, {}},
|
||||
{"1..2.3.4.5", false, {}},
|
||||
{"1.2.3.4.5.", false, {}},
|
||||
// There must be at least two components.
|
||||
{"1", false, {}},
|
||||
// No extra leading zeros.
|
||||
{"00.1.2.3.4", false, {}},
|
||||
{"01.1.2.3.4", false, {}},
|
||||
// Check for overflow.
|
||||
{"1.2.4294967295", true, {0x2a, 0x8f, 0xff, 0xff, 0xff, 0x7f}},
|
||||
{"1.2.4294967296", false, {}},
|
||||
// 40*A + B overflows.
|
||||
{"2.4294967215", true, {0x8f, 0xff, 0xff, 0xff, 0x7f}},
|
||||
{"2.4294967216", false, {}},
|
||||
};
|
||||
for (const auto &t : kTests) {
|
||||
SCOPED_TRACE(t.in);
|
||||
bssl::ScopedCBB cbb;
|
||||
ASSERT_TRUE(CBB_init(cbb.get(), 0));
|
||||
int ok = CBB_add_asn1_oid_from_text(cbb.get(), t.in, strlen(t.in));
|
||||
EXPECT_EQ(t.ok, static_cast<bool>(ok));
|
||||
if (ok) {
|
||||
uint8_t *out;
|
||||
size_t len;
|
||||
ASSERT_TRUE(CBB_finish(cbb.get(), &out, &len));
|
||||
bssl::UniquePtr<uint8_t> free_out(out);
|
||||
EXPECT_EQ(Bytes(t.out), Bytes(out, len));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <openssl/bytestring.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/mem.h>
|
||||
@@ -328,6 +329,32 @@ int CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents) {
|
||||
return cbb_add_length_prefixed(cbb, out_contents, 3);
|
||||
}
|
||||
|
||||
// add_base128_integer encodes |v| as a big-endian base-128 integer where the
|
||||
// high bit of each byte indicates where there is more data. This is the
|
||||
// encoding used in DER for both high tag number form and OID components.
|
||||
static int add_base128_integer(CBB *cbb, uint32_t v) {
|
||||
unsigned len_len = 0;
|
||||
unsigned copy = v;
|
||||
while (copy > 0) {
|
||||
len_len++;
|
||||
copy >>= 7;
|
||||
}
|
||||
if (len_len == 0) {
|
||||
len_len = 1; // Zero is encoded with one byte.
|
||||
}
|
||||
for (unsigned i = len_len - 1; i < len_len; i--) {
|
||||
uint8_t byte = (v >> (7 * i)) & 0x7f;
|
||||
if (i != 0) {
|
||||
// The high bit denotes whether there is more data.
|
||||
byte |= 0x80;
|
||||
}
|
||||
if (!CBB_add_u8(cbb, byte)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CBB_add_asn1(CBB *cbb, CBB *out_contents, unsigned tag) {
|
||||
if (tag > 0xff ||
|
||||
(tag & 0x1f) == 0x1f) {
|
||||
@@ -473,3 +500,69 @@ int CBB_add_asn1_uint64(CBB *cbb, uint64_t value) {
|
||||
|
||||
return CBB_flush(cbb);
|
||||
}
|
||||
|
||||
// parse_dotted_decimal parses one decimal component from |cbs|, where |cbs| is
|
||||
// an OID literal, e.g., "1.2.840.113554.4.1.72585". It consumes both the
|
||||
// component and the dot, so |cbs| may be passed into the function again for the
|
||||
// next value.
|
||||
static int parse_dotted_decimal(CBS *cbs, uint32_t *out) {
|
||||
*out = 0;
|
||||
int seen_digit = 0;
|
||||
for (;;) {
|
||||
// Valid terminators for a component are the end of the string or a
|
||||
// non-terminal dot. If the string ends with a dot, this is not a valid OID
|
||||
// string.
|
||||
uint8_t u;
|
||||
if (!CBS_get_u8(cbs, &u) ||
|
||||
(u == '.' && CBS_len(cbs) > 0)) {
|
||||
break;
|
||||
}
|
||||
if (u < '0' || u > '9' ||
|
||||
// Forbid stray leading zeros.
|
||||
(seen_digit && *out == 0) ||
|
||||
// Check for overflow.
|
||||
*out > UINT32_MAX / 10 ||
|
||||
*out * 10 > UINT32_MAX - (u - '0')) {
|
||||
return 0;
|
||||
}
|
||||
*out = *out * 10 + (u - '0');
|
||||
seen_digit = 1;
|
||||
}
|
||||
// The empty string is not a legal OID component.
|
||||
return seen_digit;
|
||||
}
|
||||
|
||||
int CBB_add_asn1_oid_from_text(CBB *cbb, const char *text, size_t len) {
|
||||
if (!CBB_flush(cbb)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
CBS cbs;
|
||||
CBS_init(&cbs, (const uint8_t *)text, len);
|
||||
|
||||
// OIDs must have at least two components.
|
||||
uint32_t a, b;
|
||||
if (!parse_dotted_decimal(&cbs, &a) ||
|
||||
!parse_dotted_decimal(&cbs, &b)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The first component is encoded as 40 * |a| + |b|. This assumes that |a| is
|
||||
// 0, 1, or 2 and that, when it is 0 or 1, |b| is at most 39.
|
||||
if (a > 2 ||
|
||||
(a < 2 && b > 39) ||
|
||||
b > UINT32_MAX - 80 ||
|
||||
!add_base128_integer(cbb, 40 * a + b)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The remaining components are encoded unmodified.
|
||||
while (CBS_len(&cbs) > 0) {
|
||||
if (!parse_dotted_decimal(&cbs, &a) ||
|
||||
!add_base128_integer(cbb, a)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -102,9 +102,7 @@ static int aead_aes_ctr_hmac_sha256_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
|
||||
}
|
||||
|
||||
static void aead_aes_ctr_hmac_sha256_cleanup(EVP_AEAD_CTX *ctx) {
|
||||
struct aead_aes_ctr_hmac_sha256_ctx *aes_ctx = ctx->aead_state;
|
||||
OPENSSL_cleanse(aes_ctx, sizeof(struct aead_aes_ctr_hmac_sha256_ctx));
|
||||
OPENSSL_free(aes_ctx);
|
||||
OPENSSL_free(ctx->aead_state);
|
||||
}
|
||||
|
||||
static void hmac_update_uint64(SHA256_CTX *sha256, uint64_t value) {
|
||||
|
||||
@@ -34,6 +34,10 @@
|
||||
struct aead_aes_gcm_siv_asm_ctx {
|
||||
alignas(16) uint8_t key[16*15];
|
||||
int is_128_bit;
|
||||
// ptr contains the original pointer from |OPENSSL_malloc|, which may only be
|
||||
// 8-byte aligned. When freeing this structure, actually call |OPENSSL_free|
|
||||
// on this pointer.
|
||||
void *ptr;
|
||||
};
|
||||
|
||||
// aes128gcmsiv_aes_ks writes an AES-128 key schedule for |key| to
|
||||
@@ -64,14 +68,18 @@ static int aead_aes_gcm_siv_asm_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct aead_aes_gcm_siv_asm_ctx *gcm_siv_ctx =
|
||||
OPENSSL_malloc(sizeof(struct aead_aes_gcm_siv_asm_ctx));
|
||||
if (gcm_siv_ctx == NULL) {
|
||||
char *ptr = OPENSSL_malloc(sizeof(struct aead_aes_gcm_siv_asm_ctx) + 8);
|
||||
if (ptr == NULL) {
|
||||
return 0;
|
||||
}
|
||||
assert((((uintptr_t)ptr) & 7) == 0);
|
||||
|
||||
// gcm_siv_ctx needs to be 16-byte aligned in a cross-platform way.
|
||||
struct aead_aes_gcm_siv_asm_ctx *gcm_siv_ctx =
|
||||
(struct aead_aes_gcm_siv_asm_ctx *)(ptr + (((uintptr_t)ptr) & 8));
|
||||
|
||||
// malloc should return a 16-byte-aligned address.
|
||||
assert((((uintptr_t)gcm_siv_ctx) & 15) == 0);
|
||||
gcm_siv_ctx->ptr = ptr;
|
||||
|
||||
if (key_bits == 128) {
|
||||
aes128gcmsiv_aes_ks(key, &gcm_siv_ctx->key[0]);
|
||||
@@ -87,9 +95,8 @@ static int aead_aes_gcm_siv_asm_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
|
||||
}
|
||||
|
||||
static void aead_aes_gcm_siv_asm_cleanup(EVP_AEAD_CTX *ctx) {
|
||||
struct aead_aes_gcm_siv_asm_ctx *gcm_siv_asm_ctx = ctx->aead_state;
|
||||
OPENSSL_cleanse(gcm_siv_asm_ctx, sizeof(struct aead_aes_gcm_siv_asm_ctx));
|
||||
OPENSSL_free(gcm_siv_asm_ctx);
|
||||
const struct aead_aes_gcm_siv_asm_ctx *gcm_siv_ctx = ctx->aead_state;
|
||||
OPENSSL_free(gcm_siv_ctx->ptr);
|
||||
}
|
||||
|
||||
// aesgcmsiv_polyval_horner updates the POLYVAL value in |in_out_poly| to
|
||||
@@ -585,9 +592,7 @@ static int aead_aes_gcm_siv_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
|
||||
}
|
||||
|
||||
static void aead_aes_gcm_siv_cleanup(EVP_AEAD_CTX *ctx) {
|
||||
struct aead_aes_gcm_siv_ctx *gcm_siv_ctx = ctx->aead_state;
|
||||
OPENSSL_cleanse(gcm_siv_ctx, sizeof(struct aead_aes_gcm_siv_ctx));
|
||||
OPENSSL_free(gcm_siv_ctx);
|
||||
OPENSSL_free(ctx->aead_state);
|
||||
}
|
||||
|
||||
// gcm_siv_crypt encrypts (or decrypts—it's the same thing) |in_len| bytes from
|
||||
|
||||
@@ -136,9 +136,7 @@ static int aead_chacha20_poly1305_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
|
||||
}
|
||||
|
||||
static void aead_chacha20_poly1305_cleanup(EVP_AEAD_CTX *ctx) {
|
||||
struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
|
||||
OPENSSL_cleanse(c20_ctx->key, sizeof(c20_ctx->key));
|
||||
OPENSSL_free(c20_ctx);
|
||||
OPENSSL_free(ctx->aead_state);
|
||||
}
|
||||
|
||||
static void poly1305_update_length(poly1305_state *poly1305, size_t data_len) {
|
||||
|
||||
@@ -73,18 +73,25 @@
|
||||
switch (n) { \
|
||||
case 8: \
|
||||
(l2) = ((uint32_t)(*(--(c)))) << 24L; \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 7: \
|
||||
(l2) |= ((uint32_t)(*(--(c)))) << 16L; \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 6: \
|
||||
(l2) |= ((uint32_t)(*(--(c)))) << 8L; \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 5: \
|
||||
(l2) |= ((uint32_t)(*(--(c)))); \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 4: \
|
||||
(l1) = ((uint32_t)(*(--(c)))) << 24L; \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 3: \
|
||||
(l1) |= ((uint32_t)(*(--(c)))) << 16L; \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 2: \
|
||||
(l1) |= ((uint32_t)(*(--(c)))) << 8L; \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 1: \
|
||||
(l1) |= ((uint32_t)(*(--(c)))); \
|
||||
} \
|
||||
@@ -104,18 +111,25 @@
|
||||
switch (n) { \
|
||||
case 8: \
|
||||
*(--(c)) = (uint8_t)(((l2) >> 24L) & 0xff); \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 7: \
|
||||
*(--(c)) = (uint8_t)(((l2) >> 16L) & 0xff); \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 6: \
|
||||
*(--(c)) = (uint8_t)(((l2) >> 8L) & 0xff); \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 5: \
|
||||
*(--(c)) = (uint8_t)(((l2)) & 0xff); \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 4: \
|
||||
*(--(c)) = (uint8_t)(((l1) >> 24L) & 0xff); \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 3: \
|
||||
*(--(c)) = (uint8_t)(((l1) >> 16L) & 0xff); \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 2: \
|
||||
*(--(c)) = (uint8_t)(((l1) >> 8L) & 0xff); \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 1: \
|
||||
*(--(c)) = (uint8_t)(((l1)) & 0xff); \
|
||||
} \
|
||||
|
||||
@@ -48,7 +48,6 @@ static void aead_tls_cleanup(EVP_AEAD_CTX *ctx) {
|
||||
AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX *)ctx->aead_state;
|
||||
EVP_CIPHER_CTX_cleanup(&tls_ctx->cipher_ctx);
|
||||
HMAC_CTX_cleanup(&tls_ctx->hmac_ctx);
|
||||
OPENSSL_cleanse(&tls_ctx->mac_key, sizeof(tls_ctx->mac_key));
|
||||
OPENSSL_free(tls_ctx);
|
||||
ctx->aead_state = NULL;
|
||||
}
|
||||
|
||||
+2
-2
@@ -791,13 +791,13 @@ int CONF_parse_list(const char *list, char sep, int remove_whitespace,
|
||||
}
|
||||
}
|
||||
|
||||
int CONF_modules_load_file(CONF_MUST_BE_NULL *filename, const char *appname,
|
||||
int CONF_modules_load_file(const char *filename, const char *appname,
|
||||
unsigned long flags) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CONF_modules_free(void) {}
|
||||
|
||||
void OPENSSL_config(CONF_MUST_BE_NULL *config_name) {}
|
||||
void OPENSSL_config(const char *config_name) {}
|
||||
|
||||
void OPENSSL_no_config(void) {}
|
||||
|
||||
@@ -288,7 +288,7 @@ static int has_broken_neon(const STRING_PIECE *cpuinfo) {
|
||||
|
||||
extern uint32_t OPENSSL_armcap_P;
|
||||
|
||||
static int g_has_broken_neon;
|
||||
static int g_has_broken_neon, g_needs_hwcap2_workaround;
|
||||
|
||||
void OPENSSL_cpuid_setup(void) {
|
||||
char *cpuinfo_data;
|
||||
@@ -336,6 +336,7 @@ void OPENSSL_cpuid_setup(void) {
|
||||
}
|
||||
if (hwcap2 == 0) {
|
||||
hwcap2 = get_hwcap2_cpuinfo(&cpuinfo);
|
||||
g_needs_hwcap2_workaround = hwcap2 != 0;
|
||||
}
|
||||
|
||||
if (hwcap2 & HWCAP2_AES) {
|
||||
@@ -357,4 +358,6 @@ void OPENSSL_cpuid_setup(void) {
|
||||
|
||||
int CRYPTO_has_broken_NEON(void) { return g_has_broken_neon; }
|
||||
|
||||
int CRYPTO_needs_hwcap2_workaround(void) { return g_needs_hwcap2_workaround; }
|
||||
|
||||
#endif // OPENSSL_ARM && !OPENSSL_STATIC_ARMCAP
|
||||
|
||||
+17
-17
@@ -164,7 +164,7 @@ void OPENSSL_cpuid_setup(void) {
|
||||
uint32_t num_extended_ids = eax;
|
||||
if (num_extended_ids >= 0x80000001) {
|
||||
OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 0x80000001);
|
||||
if (ecx & (1 << 11)) {
|
||||
if (ecx & (1u << 11)) {
|
||||
has_amd_xop = 1;
|
||||
}
|
||||
}
|
||||
@@ -193,68 +193,68 @@ void OPENSSL_cpuid_setup(void) {
|
||||
OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 1);
|
||||
|
||||
// Adjust the hyper-threading bit.
|
||||
if (edx & (1 << 28)) {
|
||||
if (edx & (1u << 28)) {
|
||||
uint32_t num_logical_cores = (ebx >> 16) & 0xff;
|
||||
if (cores_per_cache == 1 || num_logical_cores <= 1) {
|
||||
edx &= ~(1 << 28);
|
||||
edx &= ~(1u << 28);
|
||||
}
|
||||
}
|
||||
|
||||
// Reserved bit #20 was historically repurposed to control the in-memory
|
||||
// representation of RC4 state. Always set it to zero.
|
||||
edx &= ~(1 << 20);
|
||||
edx &= ~(1u << 20);
|
||||
|
||||
// Reserved bit #30 is repurposed to signal an Intel CPU.
|
||||
if (is_intel) {
|
||||
edx |= (1 << 30);
|
||||
edx |= (1u << 30);
|
||||
|
||||
// Clear the XSAVE bit on Knights Landing to mimic Silvermont. This enables
|
||||
// some Silvermont-specific codepaths which perform better. See OpenSSL
|
||||
// commit 64d92d74985ebb3d0be58a9718f9e080a14a8e7f.
|
||||
if ((eax & 0x0fff0ff0) == 0x00050670 /* Knights Landing */ ||
|
||||
(eax & 0x0fff0ff0) == 0x00080650 /* Knights Mill (per SDE) */) {
|
||||
ecx &= ~(1 << 26);
|
||||
ecx &= ~(1u << 26);
|
||||
}
|
||||
} else {
|
||||
edx &= ~(1 << 30);
|
||||
edx &= ~(1u << 30);
|
||||
}
|
||||
|
||||
// The SDBG bit is repurposed to denote AMD XOP support.
|
||||
if (has_amd_xop) {
|
||||
ecx |= (1 << 11);
|
||||
ecx |= (1u << 11);
|
||||
} else {
|
||||
ecx &= ~(1 << 11);
|
||||
ecx &= ~(1u << 11);
|
||||
}
|
||||
|
||||
uint64_t xcr0 = 0;
|
||||
if (ecx & (1 << 27)) {
|
||||
if (ecx & (1u << 27)) {
|
||||
// XCR0 may only be queried if the OSXSAVE bit is set.
|
||||
xcr0 = OPENSSL_xgetbv(0);
|
||||
}
|
||||
// See Intel manual, volume 1, section 14.3.
|
||||
if ((xcr0 & 6) != 6) {
|
||||
// YMM registers cannot be used.
|
||||
ecx &= ~(1 << 28); // AVX
|
||||
ecx &= ~(1 << 12); // FMA
|
||||
ecx &= ~(1 << 11); // AMD XOP
|
||||
ecx &= ~(1u << 28); // AVX
|
||||
ecx &= ~(1u << 12); // FMA
|
||||
ecx &= ~(1u << 11); // AMD XOP
|
||||
// Clear AVX2 and AVX512* bits.
|
||||
//
|
||||
// TODO(davidben): Should bits 17 and 26-28 also be cleared? Upstream
|
||||
// doesn't clear those.
|
||||
extended_features &=
|
||||
~((1 << 5) | (1 << 16) | (1 << 21) | (1 << 30) | (1 << 31));
|
||||
~((1u << 5) | (1u << 16) | (1u << 21) | (1u << 30) | (1u << 31));
|
||||
}
|
||||
// See Intel manual, volume 1, section 15.2.
|
||||
if ((xcr0 & 0xe6) != 0xe6) {
|
||||
// Clear AVX512F. Note we don't touch other AVX512 extensions because they
|
||||
// can be used with YMM.
|
||||
extended_features &= ~(1 << 16);
|
||||
extended_features &= ~(1u << 16);
|
||||
}
|
||||
|
||||
// Disable ADX instructions on Knights Landing. See OpenSSL commit
|
||||
// 64d92d74985ebb3d0be58a9718f9e080a14a8e7f.
|
||||
if ((ecx & (1 << 26)) == 0) {
|
||||
extended_features &= ~(1 << 19);
|
||||
if ((ecx & (1u << 26)) == 0) {
|
||||
extended_features &= ~(1u << 19);
|
||||
}
|
||||
|
||||
OPENSSL_ia32cap_P[0] = edx;
|
||||
|
||||
+29
-4
@@ -40,6 +40,18 @@
|
||||
OPENSSL_ARM || OPENSSL_AARCH64) */
|
||||
|
||||
|
||||
// Our assembly does not use the GOT to reference symbols, which means
|
||||
// references to visible symbols will often require a TEXTREL. This is
|
||||
// undesirable, so all assembly-referenced symbols should be hidden. CPU
|
||||
// capabilities are the only such symbols defined in C. Explicitly hide them,
|
||||
// rather than rely on being built with -fvisibility=hidden.
|
||||
#if defined(OPENSSL_WINDOWS)
|
||||
#define HIDDEN
|
||||
#else
|
||||
#define HIDDEN __attribute__((visibility("hidden")))
|
||||
#endif
|
||||
|
||||
|
||||
// The capability variables are defined in this file in order to work around a
|
||||
// linker bug. When linking with a .a, if no symbols in a .o are referenced
|
||||
// then the .o is discarded, even if it has constructor functions.
|
||||
@@ -57,11 +69,11 @@
|
||||
// archive, linking on OS X will fail to resolve common symbols. By
|
||||
// initialising it to zero, it becomes a "data symbol", which isn't so
|
||||
// affected.
|
||||
uint32_t OPENSSL_ia32cap_P[4] = {0};
|
||||
HIDDEN uint32_t OPENSSL_ia32cap_P[4] = {0};
|
||||
|
||||
#elif defined(OPENSSL_PPC64LE)
|
||||
|
||||
unsigned long OPENSSL_ppc64le_hwcap2 = 0;
|
||||
HIDDEN unsigned long OPENSSL_ppc64le_hwcap2 = 0;
|
||||
|
||||
#elif defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)
|
||||
|
||||
@@ -69,7 +81,7 @@ unsigned long OPENSSL_ppc64le_hwcap2 = 0;
|
||||
|
||||
#if defined(OPENSSL_STATIC_ARMCAP)
|
||||
|
||||
uint32_t OPENSSL_armcap_P =
|
||||
HIDDEN uint32_t OPENSSL_armcap_P =
|
||||
#if defined(OPENSSL_STATIC_ARMCAP_NEON) || defined(__ARM_NEON__)
|
||||
ARMV7_NEON |
|
||||
#endif
|
||||
@@ -88,7 +100,7 @@ uint32_t OPENSSL_armcap_P =
|
||||
0;
|
||||
|
||||
#else
|
||||
uint32_t OPENSSL_armcap_P = 0;
|
||||
HIDDEN uint32_t OPENSSL_armcap_P = 0;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -156,10 +168,18 @@ const char *SSLeay_version(int unused) {
|
||||
return "BoringSSL";
|
||||
}
|
||||
|
||||
const char *OpenSSL_version(int unused) {
|
||||
return "BoringSSL";
|
||||
}
|
||||
|
||||
unsigned long SSLeay(void) {
|
||||
return OPENSSL_VERSION_NUMBER;
|
||||
}
|
||||
|
||||
unsigned long OpenSSL_version_num(void) {
|
||||
return OPENSSL_VERSION_NUMBER;
|
||||
}
|
||||
|
||||
int CRYPTO_malloc_init(void) {
|
||||
return 1;
|
||||
}
|
||||
@@ -171,3 +191,8 @@ int ENGINE_register_all_complete(void) {
|
||||
}
|
||||
|
||||
void OPENSSL_load_builtin_modules(void) {}
|
||||
|
||||
int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings) {
|
||||
CRYPTO_library_init();
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ add_library(
|
||||
|
||||
OBJECT
|
||||
|
||||
curve25519.c
|
||||
spake25519.c
|
||||
x25519-x86_64.c
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+106
-34
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <openssl/curve25519.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/bytestring.h>
|
||||
@@ -21,8 +22,8 @@
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "../internal.h"
|
||||
#include "../../third_party/fiat/internal.h"
|
||||
|
||||
|
||||
// The following precomputation tables are for the following
|
||||
@@ -43,14 +44,14 @@
|
||||
// see curve25519.c in this directory.
|
||||
//
|
||||
// Exact copies of the source code are kept in bug 27296743.
|
||||
//
|
||||
// import hashlib
|
||||
// import ed25519 as E # http://ed25519.cr.yp.to/python/ed25519.py
|
||||
//
|
||||
// SEED_N = 'edwards25519 point generation seed (N)'
|
||||
// SEED_M = 'edwards25519 point generation seed (M)'
|
||||
|
||||
/*
|
||||
import hashlib
|
||||
import ed25519 as E # http://ed25519.cr.yp.to/python/ed25519.py
|
||||
|
||||
SEED_N = 'edwards25519 point generation seed (N)'
|
||||
SEED_M = 'edwards25519 point generation seed (M)'
|
||||
|
||||
def genpoint(seed):
|
||||
v = hashlib.sha256(seed).digest()
|
||||
it = 1
|
||||
@@ -72,10 +73,10 @@ def genpoint(seed):
|
||||
def gentable(P):
|
||||
t = []
|
||||
for i in range(1,16):
|
||||
k = (i >> 3 & 1) * (1 << 192) + \
|
||||
(i >> 2 & 1) * (1 << 128) + \
|
||||
(i >> 1 & 1) * (1 << 64) + \
|
||||
(i & 1)
|
||||
k = ((i >> 3 & 1) * (1 << 192) +
|
||||
(i >> 2 & 1) * (1 << 128) +
|
||||
(i >> 1 & 1) * (1 << 64) +
|
||||
(i & 1))
|
||||
t.append(E.scalarmult(P, k))
|
||||
return ''.join(E.encodeint(x) + E.encodeint(y) for (x,y) in t)
|
||||
|
||||
@@ -267,25 +268,6 @@ static const uint8_t kSpakeMSmallPrecomp[15 * 2 * 32] = {
|
||||
0xa6, 0x76, 0x81, 0x28, 0xb2, 0x65, 0xe8, 0x47, 0x14, 0xc6, 0x39, 0x06,
|
||||
};
|
||||
|
||||
enum spake2_state_t {
|
||||
spake2_state_init = 0,
|
||||
spake2_state_msg_generated,
|
||||
spake2_state_key_generated,
|
||||
};
|
||||
|
||||
struct spake2_ctx_st {
|
||||
uint8_t private_key[32];
|
||||
uint8_t my_msg[32];
|
||||
uint8_t password_scalar[32];
|
||||
uint8_t password_hash[SHA512_DIGEST_LENGTH];
|
||||
uint8_t *my_name;
|
||||
size_t my_name_len;
|
||||
uint8_t *their_name;
|
||||
size_t their_name_len;
|
||||
enum spake2_role_t my_role;
|
||||
enum spake2_state_t state;
|
||||
};
|
||||
|
||||
SPAKE2_CTX *SPAKE2_CTX_new(enum spake2_role_t my_role,
|
||||
const uint8_t *my_name, size_t my_name_len,
|
||||
const uint8_t *their_name, size_t their_name_len) {
|
||||
@@ -332,6 +314,48 @@ static void left_shift_3(uint8_t n[32]) {
|
||||
}
|
||||
}
|
||||
|
||||
typedef union {
|
||||
uint8_t bytes[32];
|
||||
uint32_t words[8];
|
||||
} scalar;
|
||||
|
||||
// kOrder is the order of the prime-order subgroup of curve25519 in
|
||||
// little-endian order.
|
||||
static const scalar kOrder = {{0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
|
||||
0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}};
|
||||
|
||||
// scalar_cmov copies |src| to |dest| if |mask| is all ones.
|
||||
static void scalar_cmov(scalar *dest, const scalar *src, crypto_word_t mask) {
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
dest->words[i] =
|
||||
constant_time_select_w(mask, src->words[i], dest->words[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// scalar_double sets |s| to |2×s|.
|
||||
static void scalar_double(scalar *s) {
|
||||
uint32_t carry = 0;
|
||||
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
const uint32_t carry_out = s->words[i] >> 31;
|
||||
s->words[i] = (s->words[i] << 1) | carry;
|
||||
carry = carry_out;
|
||||
}
|
||||
}
|
||||
|
||||
// scalar_add sets |dest| to |dest| plus |src|.
|
||||
static void scalar_add(scalar *dest, const scalar *src) {
|
||||
uint32_t carry = 0;
|
||||
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
uint64_t tmp = ((uint64_t)dest->words[i] + src->words[i]) + carry;
|
||||
dest->words[i] = (uint32_t)tmp;
|
||||
carry = (uint32_t)(tmp >> 32);
|
||||
}
|
||||
}
|
||||
|
||||
int SPAKE2_generate_msg(SPAKE2_CTX *ctx, uint8_t *out, size_t *out_len,
|
||||
size_t max_out_len, const uint8_t *password,
|
||||
size_t password_len) {
|
||||
@@ -359,13 +383,61 @@ int SPAKE2_generate_msg(SPAKE2_CTX *ctx, uint8_t *out, size_t *out_len,
|
||||
SHA512(password, password_len, password_tmp);
|
||||
OPENSSL_memcpy(ctx->password_hash, password_tmp, sizeof(ctx->password_hash));
|
||||
x25519_sc_reduce(password_tmp);
|
||||
OPENSSL_memcpy(ctx->password_scalar, password_tmp, sizeof(ctx->password_scalar));
|
||||
|
||||
// Due to a copy-paste error, the call to |left_shift_3| was omitted after
|
||||
// the |x25519_sc_reduce|, just above. This meant that |ctx->password_scalar|
|
||||
// was not a multiple of eight to clear the cofactor and thus three bits of
|
||||
// the password hash would leak. In order to fix this in a unilateral way,
|
||||
// points of small order are added to the mask point such that it is in the
|
||||
// prime-order subgroup. Since the ephemeral scalar is a multiple of eight,
|
||||
// these points will cancel out when calculating the shared secret.
|
||||
//
|
||||
// Adding points of small order is the same as adding multiples of the prime
|
||||
// order to the password scalar. Since that's faster, that is what is done
|
||||
// below. The prime order (kOrder) is a large prime, thus odd, thus the LSB
|
||||
// is one. So adding it will flip the LSB. Adding twice it will flip the next
|
||||
// bit and so one for all the bottom three bits.
|
||||
|
||||
scalar password_scalar;
|
||||
OPENSSL_memcpy(&password_scalar, password_tmp, sizeof(password_scalar));
|
||||
|
||||
// |password_scalar| is the result of |x25519_sc_reduce| and thus is, at
|
||||
// most, $l-1$ (where $l$ is |kOrder|, the order of the prime-order subgroup
|
||||
// of Ed25519). In the following, we may add $l + 2×l + 4×l$ for a max value
|
||||
// of $8×l-1$. That is < 2**256, as required.
|
||||
|
||||
if (!ctx->disable_password_scalar_hack) {
|
||||
scalar order = kOrder;
|
||||
scalar tmp;
|
||||
|
||||
OPENSSL_memset(&tmp, 0, sizeof(tmp));
|
||||
scalar_cmov(&tmp, &order,
|
||||
constant_time_eq_w(password_scalar.bytes[0] & 1, 1));
|
||||
scalar_add(&password_scalar, &tmp);
|
||||
|
||||
scalar_double(&order);
|
||||
OPENSSL_memset(&tmp, 0, sizeof(tmp));
|
||||
scalar_cmov(&tmp, &order,
|
||||
constant_time_eq_w(password_scalar.bytes[0] & 2, 2));
|
||||
scalar_add(&password_scalar, &tmp);
|
||||
|
||||
scalar_double(&order);
|
||||
OPENSSL_memset(&tmp, 0, sizeof(tmp));
|
||||
scalar_cmov(&tmp, &order,
|
||||
constant_time_eq_w(password_scalar.bytes[0] & 4, 4));
|
||||
scalar_add(&password_scalar, &tmp);
|
||||
|
||||
assert((password_scalar.bytes[0] & 7) == 0);
|
||||
}
|
||||
|
||||
OPENSSL_memcpy(ctx->password_scalar, password_scalar.bytes,
|
||||
sizeof(ctx->password_scalar));
|
||||
|
||||
ge_p3 mask;
|
||||
x25519_ge_scalarmult_small_precomp(&mask, ctx->password_scalar,
|
||||
ctx->my_role == spake2_role_alice
|
||||
? kSpakeMSmallPrecomp
|
||||
: kSpakeNSmallPrecomp);
|
||||
ctx->my_role == spake2_role_alice
|
||||
? kSpakeMSmallPrecomp
|
||||
: kSpakeNSmallPrecomp);
|
||||
|
||||
// P* = P + mask.
|
||||
ge_cached mask_cached;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "../internal.h"
|
||||
#include "../../third_party/fiat/internal.h"
|
||||
|
||||
|
||||
// TODO(agl): add tests with fixed vectors once SPAKE2 is nailed down.
|
||||
@@ -46,6 +47,13 @@ struct SPAKE2Run {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (alice_disable_password_scalar_hack) {
|
||||
alice->disable_password_scalar_hack = 1;
|
||||
}
|
||||
if (bob_disable_password_scalar_hack) {
|
||||
bob->disable_password_scalar_hack = 1;
|
||||
}
|
||||
|
||||
uint8_t alice_msg[SPAKE2_MAX_MSG_SIZE];
|
||||
uint8_t bob_msg[SPAKE2_MAX_MSG_SIZE];
|
||||
size_t alice_msg_len, bob_msg_len;
|
||||
@@ -90,6 +98,8 @@ struct SPAKE2Run {
|
||||
std::string bob_password = "password";
|
||||
std::pair<std::string, std::string> alice_names = {"alice", "bob"};
|
||||
std::pair<std::string, std::string> bob_names = {"bob", "alice"};
|
||||
bool alice_disable_password_scalar_hack = false;
|
||||
bool bob_disable_password_scalar_hack = false;
|
||||
int alice_corrupt_msg_bit = -1;
|
||||
|
||||
private:
|
||||
@@ -104,6 +114,24 @@ TEST(SPAKE25519Test, SPAKE2) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SPAKE25519Test, OldAlice) {
|
||||
for (unsigned i = 0; i < 20; i++) {
|
||||
SPAKE2Run spake2;
|
||||
spake2.alice_disable_password_scalar_hack = true;
|
||||
ASSERT_TRUE(spake2.Run());
|
||||
EXPECT_TRUE(spake2.key_matches());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SPAKE25519Test, OldBob) {
|
||||
for (unsigned i = 0; i < 20; i++) {
|
||||
SPAKE2Run spake2;
|
||||
spake2.bob_disable_password_scalar_hack = true;
|
||||
ASSERT_TRUE(spake2.Run());
|
||||
EXPECT_TRUE(spake2.key_matches());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SPAKE25519Test, WrongPassword) {
|
||||
SPAKE2Run spake2;
|
||||
spake2.bob_password = "wrong password";
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "../internal.h"
|
||||
#include "internal.h"
|
||||
#include "../../third_party/fiat/internal.h"
|
||||
|
||||
|
||||
#if defined(BORINGSSL_X25519_X86_64)
|
||||
|
||||
@@ -105,3 +105,22 @@ TEST(X25519Test, Iterated) {
|
||||
|
||||
EXPECT_EQ(Bytes(kExpected), Bytes(scalar));
|
||||
}
|
||||
|
||||
TEST(X25519Test, DISABLED_IteratedLarge) {
|
||||
// Taken from https://tools.ietf.org/html/rfc7748#section-5.2.
|
||||
uint8_t scalar[32] = {9}, point[32] = {9}, out[32];
|
||||
|
||||
for (unsigned i = 0; i < 1000000; i++) {
|
||||
EXPECT_TRUE(X25519(out, scalar, point));
|
||||
OPENSSL_memcpy(point, scalar, sizeof(point));
|
||||
OPENSSL_memcpy(scalar, out, sizeof(scalar));
|
||||
}
|
||||
|
||||
static const uint8_t kExpected[32] = {
|
||||
0x7c, 0x39, 0x11, 0xe0, 0xab, 0x25, 0x86, 0xfd, 0x86, 0x44, 0x97,
|
||||
0x29, 0x7e, 0x57, 0x5e, 0x6f, 0x3b, 0xc6, 0x01, 0xc0, 0x88, 0x3c,
|
||||
0x30, 0xdf, 0x5f, 0x4d, 0xd2, 0xd2, 0x4f, 0x66, 0x54, 0x24,
|
||||
};
|
||||
|
||||
EXPECT_EQ(Bytes(kExpected), Bytes(scalar));
|
||||
}
|
||||
|
||||
@@ -124,6 +124,20 @@ void DH_get0_key(const DH *dh, const BIGNUM **out_pub_key,
|
||||
}
|
||||
}
|
||||
|
||||
int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) {
|
||||
if (pub_key != NULL) {
|
||||
BN_free(dh->pub_key);
|
||||
dh->pub_key = pub_key;
|
||||
}
|
||||
|
||||
if (priv_key != NULL) {
|
||||
BN_free(dh->priv_key);
|
||||
dh->priv_key = priv_key;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void DH_get0_pqg(const DH *dh, const BIGNUM **out_p, const BIGNUM **out_q,
|
||||
const BIGNUM **out_g) {
|
||||
if (out_p != NULL) {
|
||||
@@ -137,6 +151,30 @@ void DH_get0_pqg(const DH *dh, const BIGNUM **out_p, const BIGNUM **out_q,
|
||||
}
|
||||
}
|
||||
|
||||
int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) {
|
||||
if ((dh->p == NULL && p == NULL) ||
|
||||
(dh->g == NULL && g == NULL)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (p != NULL) {
|
||||
BN_free(dh->p);
|
||||
dh->p = p;
|
||||
}
|
||||
|
||||
if (q != NULL) {
|
||||
BN_free(dh->q);
|
||||
dh->q = q;
|
||||
}
|
||||
|
||||
if (g != NULL) {
|
||||
BN_free(dh->g);
|
||||
dh->g = g;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int DH_generate_parameters_ex(DH *dh, 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.
|
||||
|
||||
@@ -62,7 +62,6 @@
|
||||
#include <openssl/bytestring.h>
|
||||
#include <openssl/nid.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
@@ -120,22 +119,22 @@ const EVP_MD* EVP_get_digestbynid(int nid) {
|
||||
static const struct {
|
||||
uint8_t oid[9];
|
||||
uint8_t oid_len;
|
||||
const EVP_MD *(*md_func) (void);
|
||||
int nid;
|
||||
} kMDOIDs[] = {
|
||||
// 1.2.840.113549.2.4
|
||||
{ {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x04}, 8, EVP_md4 },
|
||||
{ {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x04}, 8, NID_md4 },
|
||||
// 1.2.840.113549.2.5
|
||||
{ {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05}, 8, EVP_md5 },
|
||||
{ {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05}, 8, NID_md5 },
|
||||
// 1.3.14.3.2.26
|
||||
{ {0x2b, 0x0e, 0x03, 0x02, 0x1a}, 5, EVP_sha1 },
|
||||
{ {0x2b, 0x0e, 0x03, 0x02, 0x1a}, 5, NID_sha1 },
|
||||
// 2.16.840.1.101.3.4.2.1
|
||||
{ {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}, 9, EVP_sha256 },
|
||||
{ {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}, 9, NID_sha256 },
|
||||
// 2.16.840.1.101.3.4.2.2
|
||||
{ {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02}, 9, EVP_sha384 },
|
||||
{ {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02}, 9, NID_sha384 },
|
||||
// 2.16.840.1.101.3.4.2.3
|
||||
{ {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}, 9, EVP_sha512 },
|
||||
{ {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}, 9, NID_sha512 },
|
||||
// 2.16.840.1.101.3.4.2.4
|
||||
{ {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04}, 9, EVP_sha224 },
|
||||
{ {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04}, 9, NID_sha224 },
|
||||
};
|
||||
|
||||
static const EVP_MD *cbs_to_md(const CBS *cbs) {
|
||||
@@ -143,7 +142,7 @@ static const EVP_MD *cbs_to_md(const CBS *cbs) {
|
||||
if (CBS_len(cbs) == kMDOIDs[i].oid_len &&
|
||||
OPENSSL_memcmp(CBS_data(cbs), kMDOIDs[i].oid, kMDOIDs[i].oid_len) ==
|
||||
0) {
|
||||
return kMDOIDs[i].md_func();
|
||||
return EVP_get_digestbynid(kMDOIDs[i].nid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,6 +191,41 @@ const EVP_MD *EVP_parse_digest_algorithm(CBS *cbs) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
int EVP_marshal_digest_algorithm(CBB *cbb, const EVP_MD *md) {
|
||||
CBB algorithm, oid, null;
|
||||
if (!CBB_add_asn1(cbb, &algorithm, CBS_ASN1_SEQUENCE) ||
|
||||
!CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT)) {
|
||||
OPENSSL_PUT_ERROR(DIGEST, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int found = 0;
|
||||
int nid = EVP_MD_type(md);
|
||||
for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMDOIDs); i++) {
|
||||
if (nid == kMDOIDs[i].nid) {
|
||||
if (!CBB_add_bytes(&oid, kMDOIDs[i].oid, kMDOIDs[i].oid_len)) {
|
||||
OPENSSL_PUT_ERROR(DIGEST, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
OPENSSL_PUT_ERROR(DIGEST, DIGEST_R_UNKNOWN_HASH);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!CBB_add_asn1(&algorithm, &null, CBS_ASN1_NULL) ||
|
||||
!CBB_flush(cbb)) {
|
||||
OPENSSL_PUT_ERROR(DIGEST, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
const EVP_MD *EVP_get_digestbyname(const char *name) {
|
||||
for (unsigned i = 0; i < OPENSSL_ARRAY_SIZE(nid_to_digest_mapping); i++) {
|
||||
const char *short_name = nid_to_digest_mapping[i].short_name;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/bytestring.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/digest.h>
|
||||
#include <openssl/err.h>
|
||||
@@ -31,6 +32,7 @@
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include "../internal.h"
|
||||
#include "../test/test_util.h"
|
||||
|
||||
|
||||
struct MD {
|
||||
@@ -215,3 +217,44 @@ TEST(DigestTest, Getters) {
|
||||
EXPECT_EQ(EVP_md5_sha1(), EVP_get_digestbyobj(OBJ_nid2obj(NID_md5_sha1)));
|
||||
EXPECT_EQ(EVP_sha1(), EVP_get_digestbyobj(OBJ_nid2obj(NID_sha1)));
|
||||
}
|
||||
|
||||
TEST(DigestTest, ASN1) {
|
||||
bssl::ScopedCBB cbb;
|
||||
ASSERT_TRUE(CBB_init(cbb.get(), 0));
|
||||
EXPECT_FALSE(EVP_marshal_digest_algorithm(cbb.get(), EVP_md5_sha1()));
|
||||
|
||||
static const uint8_t kSHA256[] = {0x30, 0x0d, 0x06, 0x09, 0x60,
|
||||
0x86, 0x48, 0x01, 0x65, 0x03,
|
||||
0x04, 0x02, 0x01, 0x05, 0x00};
|
||||
static const uint8_t kSHA256NoParam[] = {0x30, 0x0b, 0x06, 0x09, 0x60,
|
||||
0x86, 0x48, 0x01, 0x65, 0x03,
|
||||
0x04, 0x02, 0x01};
|
||||
static const uint8_t kSHA256GarbageParam[] = {
|
||||
0x30, 0x0e, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
|
||||
0x65, 0x03, 0x04, 0x02, 0x01, 0x02, 0x01, 0x2a};
|
||||
|
||||
// Serialize SHA-256.
|
||||
cbb.Reset();
|
||||
ASSERT_TRUE(CBB_init(cbb.get(), 0));
|
||||
ASSERT_TRUE(EVP_marshal_digest_algorithm(cbb.get(), EVP_sha256()));
|
||||
uint8_t *der;
|
||||
size_t der_len;
|
||||
ASSERT_TRUE(CBB_finish(cbb.get(), &der, &der_len));
|
||||
bssl::UniquePtr<uint8_t> free_der(der);
|
||||
EXPECT_EQ(Bytes(kSHA256), Bytes(der, der_len));
|
||||
|
||||
// Parse SHA-256.
|
||||
CBS cbs;
|
||||
CBS_init(&cbs, kSHA256, sizeof(kSHA256));
|
||||
EXPECT_EQ(EVP_sha256(), EVP_parse_digest_algorithm(&cbs));
|
||||
EXPECT_EQ(0u, CBS_len(&cbs));
|
||||
|
||||
// Missing parameters are tolerated for compatibility.
|
||||
CBS_init(&cbs, kSHA256NoParam, sizeof(kSHA256NoParam));
|
||||
EXPECT_EQ(EVP_sha256(), EVP_parse_digest_algorithm(&cbs));
|
||||
EXPECT_EQ(0u, CBS_len(&cbs));
|
||||
|
||||
// Garbage parameters are not.
|
||||
CBS_init(&cbs, kSHA256GarbageParam, sizeof(kSHA256GarbageParam));
|
||||
EXPECT_FALSE(EVP_parse_digest_algorithm(&cbs));
|
||||
}
|
||||
|
||||
+49
-21
@@ -82,6 +82,9 @@
|
||||
// Rabin-Miller
|
||||
#define DSS_prime_checks 50
|
||||
|
||||
static int dsa_sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **out_kinv,
|
||||
BIGNUM **out_r);
|
||||
|
||||
static CRYPTO_EX_DATA_CLASS g_ex_data_class = CRYPTO_EX_DATA_CLASS_INIT;
|
||||
|
||||
DSA *DSA_new(void) {
|
||||
@@ -117,8 +120,6 @@ void DSA_free(DSA *dsa) {
|
||||
BN_clear_free(dsa->g);
|
||||
BN_clear_free(dsa->pub_key);
|
||||
BN_clear_free(dsa->priv_key);
|
||||
BN_clear_free(dsa->kinv);
|
||||
BN_clear_free(dsa->r);
|
||||
BN_MONT_CTX_free(dsa->method_mont_p);
|
||||
BN_MONT_CTX_free(dsa->method_mont_q);
|
||||
CRYPTO_MUTEX_cleanup(&dsa->method_mont_lock);
|
||||
@@ -153,6 +154,46 @@ void DSA_get0_pqg(const DSA *dsa, const BIGNUM **out_p, const BIGNUM **out_q,
|
||||
}
|
||||
}
|
||||
|
||||
int DSA_set0_key(DSA *dsa, BIGNUM *pub_key, BIGNUM *priv_key) {
|
||||
if (dsa->pub_key == NULL && pub_key == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pub_key != NULL) {
|
||||
BN_free(dsa->pub_key);
|
||||
dsa->pub_key = pub_key;
|
||||
}
|
||||
if (priv_key != NULL) {
|
||||
BN_free(dsa->priv_key);
|
||||
dsa->priv_key = priv_key;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int DSA_set0_pqg(DSA *dsa, BIGNUM *p, BIGNUM *q, BIGNUM *g) {
|
||||
if ((dsa->p == NULL && p == NULL) ||
|
||||
(dsa->q == NULL && q == NULL) ||
|
||||
(dsa->g == NULL && g == NULL)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (p != NULL) {
|
||||
BN_free(dsa->p);
|
||||
dsa->p = p;
|
||||
}
|
||||
if (q != NULL) {
|
||||
BN_free(dsa->q);
|
||||
dsa->q = q;
|
||||
}
|
||||
if (g != NULL) {
|
||||
BN_free(dsa->g);
|
||||
dsa->g = g;
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -504,14 +545,13 @@ void DSA_SIG_free(DSA_SIG *sig) {
|
||||
OPENSSL_free(sig);
|
||||
}
|
||||
|
||||
DSA_SIG *DSA_do_sign(const uint8_t *digest, size_t digest_len, DSA *dsa) {
|
||||
DSA_SIG *DSA_do_sign(const uint8_t *digest, size_t digest_len, const 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);
|
||||
@@ -531,16 +571,8 @@ DSA_SIG *DSA_do_sign(const uint8_t *digest, size_t digest_len, DSA *dsa) {
|
||||
}
|
||||
|
||||
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 (!dsa_sign_setup(dsa, ctx, &kinv, &r)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (digest_len > BN_num_bytes(dsa->q)) {
|
||||
@@ -573,10 +605,6 @@ redo:
|
||||
// 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 = DSA_SIG_new();
|
||||
@@ -718,7 +746,7 @@ err:
|
||||
}
|
||||
|
||||
int DSA_sign(int type, const uint8_t *digest, size_t digest_len,
|
||||
uint8_t *out_sig, unsigned int *out_siglen, DSA *dsa) {
|
||||
uint8_t *out_sig, unsigned int *out_siglen, const DSA *dsa) {
|
||||
DSA_SIG *s;
|
||||
|
||||
s = DSA_do_sign(digest, digest_len, dsa);
|
||||
@@ -808,8 +836,8 @@ int DSA_size(const DSA *dsa) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
int DSA_sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **out_kinv,
|
||||
BIGNUM **out_r) {
|
||||
static int dsa_sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **out_kinv,
|
||||
BIGNUM **out_r) {
|
||||
BN_CTX *ctx;
|
||||
BIGNUM k, kq, *kinv = NULL, *r = NULL;
|
||||
int ret = 0;
|
||||
|
||||
@@ -67,9 +67,9 @@
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
static const uint8_t kParametersTag =
|
||||
static const unsigned kParametersTag =
|
||||
CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 0;
|
||||
static const uint8_t kPublicKeyTag =
|
||||
static const unsigned kPublicKeyTag =
|
||||
CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 1;
|
||||
|
||||
EC_KEY *EC_KEY_parse_private_key(CBS *cbs, const EC_GROUP *group) {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
@@ -23,6 +24,7 @@
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/ec_key.h>
|
||||
#include <openssl/ecdh.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/nid.h>
|
||||
|
||||
#include "../test/file_test.h"
|
||||
@@ -112,3 +114,98 @@ TEST(ECDHTest, TestVectors) {
|
||||
Bytes(actual_z.data(), static_cast<size_t>(ret)));
|
||||
});
|
||||
}
|
||||
|
||||
// MakeCustomGroup returns an |EC_GROUP| containing a non-standard group. (P-256
|
||||
// with the wrong generator.)
|
||||
static bssl::UniquePtr<EC_GROUP> MakeCustomGroup() {
|
||||
static const uint8_t kP[] = {
|
||||
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,
|
||||
};
|
||||
static const uint8_t kA[] = {
|
||||
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,
|
||||
};
|
||||
static const uint8_t kB[] = {
|
||||
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,
|
||||
};
|
||||
static const uint8_t kX[] = {
|
||||
0xe6, 0x2b, 0x69, 0xe2, 0xbf, 0x65, 0x9f, 0x97, 0xbe, 0x2f, 0x1e,
|
||||
0x0d, 0x94, 0x8a, 0x4c, 0xd5, 0x97, 0x6b, 0xb7, 0xa9, 0x1e, 0x0d,
|
||||
0x46, 0xfb, 0xdd, 0xa9, 0xa9, 0x1e, 0x9d, 0xdc, 0xba, 0x5a,
|
||||
};
|
||||
static const uint8_t kY[] = {
|
||||
0x01, 0xe7, 0xd6, 0x97, 0xa8, 0x0a, 0x18, 0xf9, 0xc3, 0xc4, 0xa3,
|
||||
0x1e, 0x56, 0xe2, 0x7c, 0x83, 0x48, 0xdb, 0x16, 0x1a, 0x1c, 0xf5,
|
||||
0x1d, 0x7e, 0xf1, 0x94, 0x2d, 0x4b, 0xcf, 0x72, 0x22, 0xc1,
|
||||
};
|
||||
static const uint8_t kOrder[] = {
|
||||
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,
|
||||
};
|
||||
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
|
||||
bssl::UniquePtr<BIGNUM> p(BN_bin2bn(kP, sizeof(kP), nullptr));
|
||||
bssl::UniquePtr<BIGNUM> a(BN_bin2bn(kA, sizeof(kA), nullptr));
|
||||
bssl::UniquePtr<BIGNUM> b(BN_bin2bn(kB, sizeof(kB), nullptr));
|
||||
bssl::UniquePtr<BIGNUM> x(BN_bin2bn(kX, sizeof(kX), nullptr));
|
||||
bssl::UniquePtr<BIGNUM> y(BN_bin2bn(kY, sizeof(kY), nullptr));
|
||||
bssl::UniquePtr<BIGNUM> order(BN_bin2bn(kOrder, sizeof(kOrder), nullptr));
|
||||
if (!ctx || !p || !a || !b || !x || !y || !order) {
|
||||
return nullptr;
|
||||
}
|
||||
bssl::UniquePtr<EC_GROUP> group(
|
||||
EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
|
||||
if (!group) {
|
||||
return nullptr;
|
||||
}
|
||||
bssl::UniquePtr<EC_POINT> generator(EC_POINT_new(group.get()));
|
||||
if (!generator ||
|
||||
!EC_POINT_set_affine_coordinates_GFp(group.get(), generator.get(),
|
||||
x.get(), y.get(), ctx.get()) ||
|
||||
!EC_GROUP_set_generator(group.get(), generator.get(), order.get(),
|
||||
BN_value_one())) {
|
||||
return nullptr;
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
TEST(ECDHTest, GroupMismatch) {
|
||||
const size_t num_curves = EC_get_builtin_curves(nullptr, 0);
|
||||
std::vector<EC_builtin_curve> curves(num_curves);
|
||||
EC_get_builtin_curves(curves.data(), num_curves);
|
||||
|
||||
// Instantiate all the built-in curves.
|
||||
std::vector<bssl::UniquePtr<EC_GROUP>> groups;
|
||||
for (const auto &curve : curves) {
|
||||
groups.emplace_back(EC_GROUP_new_by_curve_name(curve.nid));
|
||||
ASSERT_TRUE(groups.back());
|
||||
}
|
||||
|
||||
// Also create some arbitrary group. (This is P-256 with the wrong generator.)
|
||||
groups.push_back(MakeCustomGroup());
|
||||
ASSERT_TRUE(groups.back());
|
||||
|
||||
for (const auto &a : groups) {
|
||||
for (const auto &b : groups) {
|
||||
if (a.get() == b.get()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
|
||||
ASSERT_TRUE(EC_KEY_set_group(key.get(), a.get()));
|
||||
ASSERT_TRUE(EC_KEY_generate_key(key.get()));
|
||||
|
||||
// ECDH across the groups should not work.
|
||||
char out[64];
|
||||
const EC_POINT *peer = EC_GROUP_get0_generator(b.get());
|
||||
EXPECT_EQ(-1,
|
||||
ECDH_compute_key(out, sizeof(out), peer, key.get(), nullptr));
|
||||
ERR_clear_error();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,13 +73,6 @@ int ECDSA_sign(int type, const uint8_t *digest, size_t digest_len, uint8_t *sig,
|
||||
(EC_KEY*) eckey /* cast away const */);
|
||||
}
|
||||
|
||||
return ECDSA_sign_ex(type, digest, digest_len, sig, sig_len, NULL, NULL,
|
||||
eckey);
|
||||
}
|
||||
|
||||
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, const EC_KEY *eckey) {
|
||||
int ret = 0;
|
||||
ECDSA_SIG *s = NULL;
|
||||
|
||||
@@ -89,7 +82,7 @@ int ECDSA_sign_ex(int type, const uint8_t *digest, size_t digest_len,
|
||||
goto err;
|
||||
}
|
||||
|
||||
s = ECDSA_do_sign_ex(digest, digest_len, kinv, r, eckey);
|
||||
s = ECDSA_do_sign(digest, digest_len, eckey);
|
||||
if (s == NULL) {
|
||||
*sig_len = 0;
|
||||
goto err;
|
||||
|
||||
@@ -17,6 +17,7 @@ EC,110,INVALID_FIELD
|
||||
EC,111,INVALID_FORM
|
||||
EC,112,INVALID_GROUP_ORDER
|
||||
EC,113,INVALID_PRIVATE_KEY
|
||||
EC,133,INVALID_SCALAR
|
||||
EC,114,MISSING_PARAMETERS
|
||||
EC,115,MISSING_PRIVATE_KEY
|
||||
EC,116,NON_NAMED_CURVE
|
||||
|
||||
+119
-28
@@ -123,27 +123,59 @@ OPENSSL_MSVC_PRAGMA(warning(pop))
|
||||
#include <openssl/thread.h>
|
||||
|
||||
#include "../internal.h"
|
||||
#include "./internal.h"
|
||||
|
||||
|
||||
struct err_error_st {
|
||||
// file contains the filename where the error occurred.
|
||||
const char *file;
|
||||
// data contains a NUL-terminated string with optional data. It must be freed
|
||||
// with |OPENSSL_free|.
|
||||
char *data;
|
||||
// packed contains the error library and reason, as packed by ERR_PACK.
|
||||
uint32_t packed;
|
||||
// line contains the line number where the error occurred.
|
||||
uint16_t line;
|
||||
// mark indicates a reversion point in the queue. See |ERR_pop_to_mark|.
|
||||
unsigned mark : 1;
|
||||
};
|
||||
|
||||
// ERR_STATE contains the per-thread, error queue.
|
||||
typedef struct err_state_st {
|
||||
// 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;
|
||||
|
||||
// to_free, if not NULL, contains a pointer owned by this structure that was
|
||||
// previously a |data| pointer of one of the elements of |errors|.
|
||||
void *to_free;
|
||||
} ERR_STATE;
|
||||
|
||||
extern const uint32_t kOpenSSLReasonValues[];
|
||||
extern const size_t kOpenSSLReasonValuesLen;
|
||||
extern const char kOpenSSLReasonStringData[];
|
||||
|
||||
// err_clear_data frees the optional |data| member of the given error.
|
||||
static void err_clear_data(struct err_error_st *error) {
|
||||
if ((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);
|
||||
OPENSSL_free(error->data);
|
||||
OPENSSL_memset(error, 0, sizeof(struct err_error_st));
|
||||
}
|
||||
|
||||
static void err_copy(struct err_error_st *dst, const struct err_error_st *src) {
|
||||
err_clear(dst);
|
||||
dst->file = src->file;
|
||||
if (src->data != NULL) {
|
||||
dst->data = OPENSSL_strdup(src->data);
|
||||
}
|
||||
dst->packed = src->packed;
|
||||
dst->line = src->line;
|
||||
}
|
||||
|
||||
// global_next_library contains the next custom library value to return.
|
||||
static int global_next_library = ERR_NUM_LIBS;
|
||||
|
||||
@@ -159,8 +191,7 @@ static void err_state_free(void *statep) {
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < ERR_NUM_ERRORS; i++) {
|
||||
for (unsigned i = 0; i < ERR_NUM_ERRORS; i++) {
|
||||
err_clear(&state->errors[i]);
|
||||
}
|
||||
OPENSSL_free(state->to_free);
|
||||
@@ -227,7 +258,7 @@ static uint32_t get_error_values(int inc, int top, const char **file, int *line,
|
||||
} else {
|
||||
*data = error->data;
|
||||
if (flags != NULL) {
|
||||
*flags = error->flags & ERR_FLAG_PUBLIC_MASK;
|
||||
*flags = ERR_FLAG_STRING;
|
||||
}
|
||||
// If this error is being removed, take ownership of data from
|
||||
// the error. The semantics are such that the caller doesn't
|
||||
@@ -235,12 +266,11 @@ static uint32_t get_error_values(int inc, int top, const char **file, int *line,
|
||||
// ownership and retains it until the next call that affects the
|
||||
// error queue.
|
||||
if (inc) {
|
||||
if (error->flags & ERR_FLAG_MALLOCED) {
|
||||
if (error->data != NULL) {
|
||||
OPENSSL_free(state->to_free);
|
||||
state->to_free = error->data;
|
||||
}
|
||||
error->data = NULL;
|
||||
error->flags = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -585,24 +615,20 @@ void ERR_print_errors_fp(FILE *file) {
|
||||
ERR_print_errors_cb(print_errors_to_file, file);
|
||||
}
|
||||
|
||||
// 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_set_error_data sets the data on the most recent error.
|
||||
static void err_set_error_data(char *data) {
|
||||
ERR_STATE *const state = err_get_state();
|
||||
struct err_error_st *error;
|
||||
|
||||
if (state == NULL || state->top == state->bottom) {
|
||||
if (flags & ERR_FLAG_MALLOCED) {
|
||||
OPENSSL_free(data);
|
||||
}
|
||||
OPENSSL_free(data);
|
||||
return;
|
||||
}
|
||||
|
||||
error = &state->errors[state->top];
|
||||
|
||||
err_clear_data(error);
|
||||
OPENSSL_free(error->data);
|
||||
error->data = data;
|
||||
error->flags = flags;
|
||||
}
|
||||
|
||||
void ERR_put_error(int library, int unused, int reason, const char *file,
|
||||
@@ -680,7 +706,7 @@ static void err_add_error_vdata(unsigned num, va_list args) {
|
||||
}
|
||||
|
||||
buf[len] = 0;
|
||||
err_set_error_data(buf, ERR_FLAG_MALLOCED | ERR_FLAG_STRING);
|
||||
err_set_error_data(buf);
|
||||
}
|
||||
|
||||
void ERR_add_error_data(unsigned count, ...) {
|
||||
@@ -708,7 +734,7 @@ void ERR_add_error_dataf(const char *format, ...) {
|
||||
buf[buf_len] = 0;
|
||||
va_end(ap);
|
||||
|
||||
err_set_error_data(buf, ERR_FLAG_MALLOCED | ERR_FLAG_STRING);
|
||||
err_set_error_data(buf);
|
||||
}
|
||||
|
||||
int ERR_set_mark(void) {
|
||||
@@ -717,7 +743,7 @@ int ERR_set_mark(void) {
|
||||
if (state == NULL || state->bottom == state->top) {
|
||||
return 0;
|
||||
}
|
||||
state->errors[state->top].flags |= ERR_FLAG_MARK;
|
||||
state->errors[state->top].mark = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -731,8 +757,8 @@ int ERR_pop_to_mark(void) {
|
||||
while (state->bottom != state->top) {
|
||||
struct err_error_st *error = &state->errors[state->top];
|
||||
|
||||
if ((error->flags & ERR_FLAG_MARK) != 0) {
|
||||
error->flags &= ~ERR_FLAG_MARK;
|
||||
if (error->mark) {
|
||||
error->mark = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -754,3 +780,68 @@ void ERR_free_strings(void) {}
|
||||
void ERR_load_BIO_strings(void) {}
|
||||
|
||||
void ERR_load_ERR_strings(void) {}
|
||||
|
||||
struct err_save_state_st {
|
||||
struct err_error_st *errors;
|
||||
size_t num_errors;
|
||||
};
|
||||
|
||||
void ERR_SAVE_STATE_free(ERR_SAVE_STATE *state) {
|
||||
if (state == NULL) {
|
||||
return;
|
||||
}
|
||||
for (size_t i = 0; i < state->num_errors; i++) {
|
||||
err_clear(&state->errors[i]);
|
||||
}
|
||||
OPENSSL_free(state->errors);
|
||||
OPENSSL_free(state);
|
||||
}
|
||||
|
||||
ERR_SAVE_STATE *ERR_save_state(void) {
|
||||
ERR_STATE *const state = err_get_state();
|
||||
if (state == NULL || state->top == state->bottom) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ERR_SAVE_STATE *ret = OPENSSL_malloc(sizeof(ERR_SAVE_STATE));
|
||||
if (ret == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Errors are stored in the range (bottom, top].
|
||||
size_t num_errors = state->top >= state->bottom
|
||||
? state->top - state->bottom
|
||||
: ERR_NUM_ERRORS + state->top - state->bottom;
|
||||
assert(num_errors < ERR_NUM_ERRORS);
|
||||
ret->errors = OPENSSL_malloc(num_errors * sizeof(struct err_error_st));
|
||||
if (ret->errors == NULL) {
|
||||
OPENSSL_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
OPENSSL_memset(ret->errors, 0, num_errors * sizeof(struct err_error_st));
|
||||
ret->num_errors = num_errors;
|
||||
|
||||
for (size_t i = 0; i < num_errors; i++) {
|
||||
size_t j = (state->bottom + i + 1) % ERR_NUM_ERRORS;
|
||||
err_copy(&ret->errors[i], &state->errors[j]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ERR_restore_state(const ERR_SAVE_STATE *state) {
|
||||
if (state == NULL || state->num_errors == 0) {
|
||||
ERR_clear_error();
|
||||
return;
|
||||
}
|
||||
|
||||
ERR_STATE *const dst = err_get_state();
|
||||
if (dst == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < state->num_errors; i++) {
|
||||
err_copy(&dst->errors[i], &state->errors[i]);
|
||||
}
|
||||
dst->top = state->num_errors - 1;
|
||||
dst->bottom = ERR_NUM_ERRORS - 1;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "./internal.h"
|
||||
|
||||
|
||||
TEST(ErrTest, Overflow) {
|
||||
for (unsigned i = 0; i < ERR_NUM_ERRORS*2; i++) {
|
||||
@@ -119,3 +121,94 @@ TEST(ErrTest, PutMacro) {
|
||||
EXPECT_EQ(ERR_LIB_USER, ERR_GET_LIB(error));
|
||||
EXPECT_EQ(ERR_R_INTERNAL_ERROR, ERR_GET_REASON(error));
|
||||
}
|
||||
|
||||
TEST(ErrTest, SaveAndRestore) {
|
||||
// Restoring no state clears the error queue, including error data.
|
||||
ERR_put_error(1, 0 /* unused */, 1, "test1.c", 1);
|
||||
ERR_put_error(2, 0 /* unused */, 2, "test2.c", 2);
|
||||
ERR_add_error_data(1, "data1");
|
||||
ERR_restore_state(nullptr);
|
||||
EXPECT_EQ(0u, ERR_get_error());
|
||||
|
||||
// Add some entries to the error queue and save it.
|
||||
ERR_put_error(1, 0 /* unused */, 1, "test1.c", 1);
|
||||
ERR_add_error_data(1, "data1");
|
||||
ERR_put_error(2, 0 /* unused */, 2, "test2.c", 2);
|
||||
ERR_put_error(3, 0 /* unused */, 3, "test3.c", 3);
|
||||
ERR_add_error_data(1, "data3");
|
||||
bssl::UniquePtr<ERR_SAVE_STATE> saved(ERR_save_state());
|
||||
ASSERT_TRUE(saved);
|
||||
|
||||
// The existing error queue entries still exist.
|
||||
int line, flags;
|
||||
const char *file, *data;
|
||||
uint32_t packed_error = ERR_get_error_line_data(&file, &line, &data, &flags);
|
||||
EXPECT_EQ(ERR_GET_LIB(packed_error), 1);
|
||||
EXPECT_EQ(ERR_GET_REASON(packed_error), 1);
|
||||
EXPECT_STREQ("test1.c", file);
|
||||
EXPECT_EQ(line, 1);
|
||||
EXPECT_STREQ(data, "data1");
|
||||
EXPECT_EQ(flags, ERR_FLAG_STRING);
|
||||
|
||||
// The state may be restored, both over an empty and non-empty state.
|
||||
for (unsigned i = 0; i < 2; i++) {
|
||||
SCOPED_TRACE(i);
|
||||
ERR_restore_state(saved.get());
|
||||
|
||||
packed_error = ERR_get_error_line_data(&file, &line, &data, &flags);
|
||||
EXPECT_EQ(ERR_GET_LIB(packed_error), 1);
|
||||
EXPECT_EQ(ERR_GET_REASON(packed_error), 1);
|
||||
EXPECT_STREQ("test1.c", file);
|
||||
EXPECT_EQ(line, 1);
|
||||
EXPECT_STREQ(data, "data1");
|
||||
EXPECT_EQ(flags, ERR_FLAG_STRING);
|
||||
|
||||
packed_error = ERR_get_error_line_data(&file, &line, &data, &flags);
|
||||
EXPECT_EQ(ERR_GET_LIB(packed_error), 2);
|
||||
EXPECT_EQ(ERR_GET_REASON(packed_error), 2);
|
||||
EXPECT_STREQ("test2.c", file);
|
||||
EXPECT_EQ(line, 2);
|
||||
EXPECT_STREQ(data, ""); // No error data is reported as the empty string.
|
||||
EXPECT_EQ(flags, 0);
|
||||
|
||||
packed_error = ERR_get_error_line_data(&file, &line, &data, &flags);
|
||||
EXPECT_EQ(ERR_GET_LIB(packed_error), 3);
|
||||
EXPECT_EQ(ERR_GET_REASON(packed_error), 3);
|
||||
EXPECT_STREQ("test3.c", file);
|
||||
EXPECT_EQ(line, 3);
|
||||
EXPECT_STREQ(data, "data3");
|
||||
EXPECT_EQ(flags, ERR_FLAG_STRING);
|
||||
|
||||
// The error queue is now empty for the next iteration.
|
||||
EXPECT_EQ(0u, ERR_get_error());
|
||||
}
|
||||
|
||||
// Test a case where the error queue wraps around. The first set of errors
|
||||
// will all be discarded, but result in wrapping the list around.
|
||||
ERR_clear_error();
|
||||
for (unsigned i = 0; i < ERR_NUM_ERRORS / 2; i++) {
|
||||
ERR_put_error(0, 0 /* unused */, 0, "invalid", 0);
|
||||
}
|
||||
for (unsigned i = 1; i < ERR_NUM_ERRORS; i++) {
|
||||
ERR_put_error(i, 0 /* unused */, i, "test", i);
|
||||
}
|
||||
saved.reset(ERR_save_state());
|
||||
|
||||
// The state may be restored, both over an empty and non-empty state. Pop one
|
||||
// error off so the first iteration is tested to not be a no-op.
|
||||
ERR_get_error();
|
||||
for (int i = 0; i < 2; i++) {
|
||||
SCOPED_TRACE(i);
|
||||
ERR_restore_state(saved.get());
|
||||
for (int j = 1; j < ERR_NUM_ERRORS; j++) {
|
||||
SCOPED_TRACE(j);
|
||||
packed_error = ERR_get_error_line_data(&file, &line, &data, &flags);
|
||||
EXPECT_EQ(ERR_GET_LIB(packed_error), j);
|
||||
EXPECT_EQ(ERR_GET_REASON(packed_error), j);
|
||||
EXPECT_STREQ("test", file);
|
||||
EXPECT_EQ(line, j);
|
||||
}
|
||||
// The error queue is now empty for the next iteration.
|
||||
EXPECT_EQ(0u, ERR_get_error());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/* Copyright (c) 2017, Google Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
#ifndef OPENSSL_HEADER_CRYPTO_ERR_INTERNAL_H
|
||||
#define OPENSSL_HEADER_CRYPTO_ERR_INTERNAL_H
|
||||
|
||||
#include <openssl/err.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
// Private error queue functions.
|
||||
|
||||
// ERR_SAVE_STATE contains a saved representation of the error queue. It is
|
||||
// slightly more compact than |ERR_STATE| as the error queue will typically not
|
||||
// contain |ERR_NUM_ERRORS| entries.
|
||||
typedef struct err_save_state_st ERR_SAVE_STATE;
|
||||
|
||||
// ERR_SAVE_STATE_free releases all memory associated with |state|.
|
||||
OPENSSL_EXPORT void ERR_SAVE_STATE_free(ERR_SAVE_STATE *state);
|
||||
|
||||
// ERR_save_state returns a newly-allocated |ERR_SAVE_STATE| structure
|
||||
// containing the current state of the error queue or NULL on allocation
|
||||
// error. It should be released with |ERR_SAVE_STATE_free|.
|
||||
OPENSSL_EXPORT ERR_SAVE_STATE *ERR_save_state(void);
|
||||
|
||||
// ERR_restore_state clears the error queue and replaces it with |state|.
|
||||
OPENSSL_EXPORT void ERR_restore_state(const ERR_SAVE_STATE *state);
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} // extern C
|
||||
|
||||
extern "C++" {
|
||||
|
||||
namespace bssl {
|
||||
|
||||
BORINGSSL_MAKE_DELETER(ERR_SAVE_STATE, ERR_SAVE_STATE_free)
|
||||
|
||||
} // namespace bssl
|
||||
|
||||
} // extern C++
|
||||
#endif
|
||||
|
||||
#endif // OPENSSL_HEADER_CRYPTO_ERR_INTERNAL_H
|
||||
@@ -1 +1,2 @@
|
||||
OBJ,101,INVALID_OID_STRING
|
||||
OBJ,100,UNKNOWN_NID
|
||||
|
||||
@@ -53,6 +53,7 @@ SSL,143,DTLS_MESSAGE_TOO_BIG
|
||||
SSL,257,DUPLICATE_EXTENSION
|
||||
SSL,264,DUPLICATE_KEY_SHARE
|
||||
SSL,144,ECC_CERT_NOT_FOR_SIGNING
|
||||
SSL,282,EMPTY_HELLO_RETRY_REQUEST
|
||||
SSL,145,EMS_STATE_INCONSISTENT
|
||||
SSL,146,ENCRYPTED_LENGTH_TOO_LONG
|
||||
SSL,147,ERROR_ADDING_EXTENSION
|
||||
|
||||
+77
-3
@@ -70,6 +70,7 @@ OPENSSL_MSVC_PRAGMA(warning(pop))
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <openssl/buf.h>
|
||||
#include <openssl/bytestring.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/digest.h>
|
||||
@@ -206,6 +207,27 @@ static bool SetupContext(FileTest *t, EVP_PKEY_CTX *ctx) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (t->HasAttribute("OAEPDigest")) {
|
||||
const EVP_MD *digest = GetDigest(t, t->GetAttributeOrDie("OAEPDigest"));
|
||||
if (digest == nullptr || !EVP_PKEY_CTX_set_rsa_oaep_md(ctx, digest)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (t->HasAttribute("OAEPLabel")) {
|
||||
std::vector<uint8_t> label;
|
||||
if (!t->GetBytes(&label, "OAEPLabel")) {
|
||||
return false;
|
||||
}
|
||||
// For historical reasons, |EVP_PKEY_CTX_set0_rsa_oaep_label| expects to be
|
||||
// take ownership of the input.
|
||||
bssl::UniquePtr<uint8_t> buf(
|
||||
reinterpret_cast<uint8_t *>(BUF_memdup(label.data(), label.size())));
|
||||
if (!buf ||
|
||||
!EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, buf.get(), label.size())) {
|
||||
return false;
|
||||
}
|
||||
buf.release();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -239,6 +261,9 @@ static bool TestEVP(FileTest *t, KeyMap *key_map) {
|
||||
} else if (t->GetType() == "VerifyMessage") {
|
||||
md_op_init = EVP_DigestVerifyInit;
|
||||
is_verify = true;
|
||||
} else if (t->GetType() == "Encrypt") {
|
||||
key_op_init = EVP_PKEY_encrypt_init;
|
||||
key_op = EVP_PKEY_encrypt;
|
||||
} else {
|
||||
ADD_FAILURE() << "Unknown test " << t->GetType();
|
||||
return false;
|
||||
@@ -316,8 +341,58 @@ static bool TestEVP(FileTest *t, KeyMap *key_map) {
|
||||
return false;
|
||||
}
|
||||
actual.resize(len);
|
||||
if (!key_op(ctx.get(), actual.data(), &len, input.data(), input.size()) ||
|
||||
!t->GetBytes(&output, "Output")) {
|
||||
if (!key_op(ctx.get(), actual.data(), &len, input.data(), input.size())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Encryption is non-deterministic, so we check by decrypting.
|
||||
if (t->HasAttribute("CheckDecrypt")) {
|
||||
size_t plaintext_len;
|
||||
ctx.reset(EVP_PKEY_CTX_new(key, nullptr));
|
||||
if (!ctx ||
|
||||
!EVP_PKEY_decrypt_init(ctx.get()) ||
|
||||
(digest != nullptr &&
|
||||
!EVP_PKEY_CTX_set_signature_md(ctx.get(), digest)) ||
|
||||
!SetupContext(t, ctx.get()) ||
|
||||
!EVP_PKEY_decrypt(ctx.get(), nullptr, &plaintext_len, actual.data(),
|
||||
actual.size())) {
|
||||
return false;
|
||||
}
|
||||
output.resize(plaintext_len);
|
||||
if (!EVP_PKEY_decrypt(ctx.get(), output.data(), &plaintext_len,
|
||||
actual.data(), actual.size())) {
|
||||
ADD_FAILURE() << "Could not decrypt result.";
|
||||
return false;
|
||||
}
|
||||
output.resize(plaintext_len);
|
||||
EXPECT_EQ(Bytes(input), Bytes(output)) << "Decrypted result mismatch.";
|
||||
return true;
|
||||
}
|
||||
|
||||
// Some signature schemes are non-deterministic, so we check by verifying.
|
||||
if (t->HasAttribute("CheckVerify")) {
|
||||
ctx.reset(EVP_PKEY_CTX_new(key, nullptr));
|
||||
if (!ctx ||
|
||||
!EVP_PKEY_verify_init(ctx.get()) ||
|
||||
(digest != nullptr &&
|
||||
!EVP_PKEY_CTX_set_signature_md(ctx.get(), digest)) ||
|
||||
!SetupContext(t, ctx.get())) {
|
||||
return false;
|
||||
}
|
||||
if (t->HasAttribute("VerifyPSSSaltLength") &&
|
||||
!EVP_PKEY_CTX_set_rsa_pss_saltlen(
|
||||
ctx.get(),
|
||||
atoi(t->GetAttributeOrDie("VerifyPSSSaltLength").c_str()))) {
|
||||
return false;
|
||||
}
|
||||
EXPECT_TRUE(EVP_PKEY_verify(ctx.get(), actual.data(), actual.size(),
|
||||
input.data(), input.size()))
|
||||
<< "Could not verify result.";
|
||||
return true;
|
||||
}
|
||||
|
||||
// By default, check by comparing the result against Output.
|
||||
if (!t->GetBytes(&output, "Output")) {
|
||||
return false;
|
||||
}
|
||||
actual.resize(len);
|
||||
@@ -335,7 +410,6 @@ TEST(EVPTest, TestVectors) {
|
||||
EXPECT_EQ(t->GetAttributeOrDie("Error"), ERR_reason_error_string(err));
|
||||
} else if (!result) {
|
||||
ADD_FAILURE() << "Operation unexpectedly failed.";
|
||||
ERR_print_errors_fp(stdout);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -12,6 +12,11 @@ PublicKey = RSA-2048-SPKI
|
||||
Type = RSA
|
||||
Input = 30820122300d06092a864886f70d01010105000382010f003082010a0282010100cd0081ea7b2ae1ea06d59f7c73d9ffb94a09615c2e4ba7c636cef08dd3533ec3185525b015c769b99a77d6725bf9c3532a9b6e5f6627d5fb85160768d3dda9cbd35974511717dc3d309d2fc47ee41f97e32adb7f9dd864a1c4767a666ecd71bc1aacf5e7517f4b38594fea9b05e42d5ada9912008013e45316a4d9bb8ed086b88d28758bacaf922d46a868b485d239c9baeb0e2b64592710f42b2d1ea0a4b4802c0becab328f8a68b0073bdb546feea9809d2849912b390c1532bc7e29c7658f8175fae46f34332ff87bcab3e40649b98577869da0ea718353f0722754886913648760d122be676e0fc483dd20ffc31bda96a31966c9aa2e75ad03de47e1c44f0203010001
|
||||
|
||||
# The same key but with a negative RSA modulus.
|
||||
PublicKey = RSA-2048-SPKI-Negative
|
||||
Input = 30820121300d06092a864886f70d01010105000382010e003082010902820100cd0081ea7b2ae1ea06d59f7c73d9ffb94a09615c2e4ba7c636cef08dd3533ec3185525b015c769b99a77d6725bf9c3532a9b6e5f6627d5fb85160768d3dda9cbd35974511717dc3d309d2fc47ee41f97e32adb7f9dd864a1c4767a666ecd71bc1aacf5e7517f4b38594fea9b05e42d5ada9912008013e45316a4d9bb8ed086b88d28758bacaf922d46a868b485d239c9baeb0e2b64592710f42b2d1ea0a4b4802c0becab328f8a68b0073bdb546feea9809d2849912b390c1532bc7e29c7658f8175fae46f34332ff87bcab3e40649b98577869da0ea718353f0722754886913648760d122be676e0fc483dd20ffc31bda96a31966c9aa2e75ad03de47e1c44f0203010001
|
||||
Error = NEGATIVE_NUMBER
|
||||
|
||||
# The same key but with missing parameters rather than a NULL.
|
||||
PublicKey = RSA-2048-SPKI-Invalid
|
||||
Input = 30820120300b06092a864886f70d0101010382010f003082010a0282010100cd0081ea7b2ae1ea06d59f7c73d9ffb94a09615c2e4ba7c636cef08dd3533ec3185525b015c769b99a77d6725bf9c3532a9b6e5f6627d5fb85160768d3dda9cbd35974511717dc3d309d2fc47ee41f97e32adb7f9dd864a1c4767a666ecd71bc1aacf5e7517f4b38594fea9b05e42d5ada9912008013e45316a4d9bb8ed086b88d28758bacaf922d46a868b485d239c9baeb0e2b64592710f42b2d1ea0a4b4802c0becab328f8a68b0073bdb546feea9809d2849912b390c1532bc7e29c7658f8175fae46f34332ff87bcab3e40649b98577869da0ea718353f0722754886913648760d122be676e0fc483dd20ffc31bda96a31966c9aa2e75ad03de47e1c44f0203010001
|
||||
@@ -261,6 +266,14 @@ Digest = SHA256
|
||||
Input = "0123456789ABCDEF0123456789ABCDEF"
|
||||
Output = 4de433d5844043ef08d354da03cb29068780d52706d7d1e4d50efb7d58c9d547d83a747ddd0635a96b28f854e50145518482cb49e963054621b53c60c498d07c16e9c2789c893cf38d4d86900de71bde463bd2761d1271e358c7480a1ac0bab930ddf39602ad1bc165b5d7436b516b7a7858e8eb7ab1c420eeb482f4d207f0e462b1724959320a084e13848d11d10fb593e66bf680bf6d3f345fc3e9c3de60abbac37e1c6ec80a268c8d9fc49626c679097aa690bc1aa662b95eb8db70390861aa0898229f9349b4b5fdd030d4928c47084708a933144be23bd3c6e661b85b2c0ef9ed36d498d5b7320e8194d363d4ad478c059bae804181965e0b81b663158a
|
||||
|
||||
# A non-zero salt length must be checked by round-tripping.
|
||||
Sign = RSA-2048
|
||||
RSAPadding = PSS
|
||||
PSSSaltLength = 32
|
||||
Digest = SHA256
|
||||
Input = "0123456789ABCDEF0123456789ABCDEF"
|
||||
CheckVerify
|
||||
|
||||
# Auto-detected salt length
|
||||
Verify = RSA-2048-SPKI
|
||||
RSAPadding = PSS
|
||||
@@ -269,6 +282,24 @@ Digest = SHA256
|
||||
Input = "0123456789ABCDEF0123456789ABCDEF"
|
||||
Output = 4de433d5844043ef08d354da03cb29068780d52706d7d1e4d50efb7d58c9d547d83a747ddd0635a96b28f854e50145518482cb49e963054621b53c60c498d07c16e9c2789c893cf38d4d86900de71bde463bd2761d1271e358c7480a1ac0bab930ddf39602ad1bc165b5d7436b516b7a7858e8eb7ab1c420eeb482f4d207f0e462b1724959320a084e13848d11d10fb593e66bf680bf6d3f345fc3e9c3de60abbac37e1c6ec80a268c8d9fc49626c679097aa690bc1aa662b95eb8db70390861aa0898229f9349b4b5fdd030d4928c47084708a933144be23bd3c6e661b85b2c0ef9ed36d498d5b7320e8194d363d4ad478c059bae804181965e0b81b663158a
|
||||
|
||||
# Signing with salt length -1 means to match the digest length.
|
||||
Sign = RSA-2048
|
||||
RSAPadding = PSS
|
||||
PSSSaltLength = -1
|
||||
VerifyPSSSaltLength = 32
|
||||
Digest = SHA256
|
||||
Input = "0123456789ABCDEF0123456789ABCDEF"
|
||||
CheckVerify
|
||||
|
||||
# Signing with salt length -2 means to maximize the salt length.
|
||||
Sign = RSA-2048
|
||||
RSAPadding = PSS
|
||||
PSSSaltLength = -2
|
||||
VerifyPSSSaltLength = 222 # 256 - 32 - 2
|
||||
Digest = SHA256
|
||||
Input = "0123456789ABCDEF0123456789ABCDEF"
|
||||
CheckVerify
|
||||
|
||||
# Wrong digest
|
||||
Verify = RSA-2048-SPKI
|
||||
RSAPadding = PSS
|
||||
@@ -482,12 +513,38 @@ RSAPadding = OAEP
|
||||
Input = 458708dfbd42a1297ce7a9c86c7087ab80b1754810929b89c5107ca55368587686986fce94d86cc1595b3fb736223a656ec0f34d18ba1cc5665593610f56c58e26b272d584f3d983a5c91085700755aebd921fb280bba3eda7046ec07b43e7298e52d59edc92be4639a8ce08b2f85976ecf6d98cc469eeb9d5d8e2a32ea8a6626edafe1038b3df455668a9f3c77cad8b92fb872e00058c3d2a7ede1a1f03fc5622084ae04d9d24f6bf0995c58d35b93b699b9763595e123f2ab0863cc9229eb290e2ede7715c7a8f39e0b9a3e2e1b56ebb62f1cbfbb5986fb212ebd785b83d01d968b11d1756c7337f70c1f1a63bff03608e24f3a2fd44e67f832a8701c5d5af
|
||||
Output = "Hello World"
|
||||
|
||||
# OAEP padding with label and custom hash.
|
||||
Decrypt = RSA-2048
|
||||
RSAPadding = OAEP
|
||||
OAEPDigest = SHA512
|
||||
OAEPLabel = 00112233445566778899aabbccddeeff
|
||||
Input = 48b956c22b8e40cc38f0893672ddf488fc806cf1fcc6239c66dd8345eb543d6b5cac589e6c7ae86dac1c2436c4d72c48009a737b2c649e6000dbab17203e4d9c078bd70b649700a0830d4ddc396af0c48973177a229e48259d93247f04f76474c7611b530c66f020c4da2cc861c2e4104831ecc0336e0cb10d6520fdefd0b33606f5cdd736dd439583b9b6011cce99623c93caf5f76e21e9fefab414795dd5ac12cba551be74ebf266834fcffab182c5e7c9b6c064df154cb26ddfd4fe2fd87590005f4bf45e776a0082803e9f68995b8eeb4c6802c67b5ef349e5b2dc0cf7a12fc097030f2bd28f0253f17129b04c82993a12957728b35880fdd2f8d0cc469f
|
||||
Output = "Hello World"
|
||||
|
||||
# OAEP padding, corrupted ciphertext
|
||||
Decrypt = RSA-2048
|
||||
RSAPadding = OAEP
|
||||
Input = 458708dfbd42a1297ce7a9c86c7087ab80b1754810929b89c5107ca55368587686986fce94d86cc1595b3fb736223a656ec0f34d18ba1cc5665593610f56c58e26b272d584f3d983a5c91085700755aebd921fb280bba3eda7046ec07b43e7298e52d59edc92be4639a8ce08b2f85976ecf6d98cc469eeb9d5d8e2a32ea8a6626edafe1038b3df455668a9f3c77cad8b92fb872e00058c3d2a7ede1a1f03fc5622084ae04d9d24f6bf0995c58d35b93b699b9763595e123f2ab0863cc9229eb290e2ede7715c7a8f39e0b9a3e2e1b56ebb62f1cbfbb5986fb212ebd785b83d01d968b11d1756c7337f70c1f1a63bff03608e24f3a2fd44e67f832a8701c5d5ac
|
||||
Error = OAEP_DECODING_ERROR
|
||||
|
||||
# Test that RSA encryption successfully round-trips through decryption
|
||||
# with various parameters.
|
||||
Encrypt = RSA-2048
|
||||
Input = "Hello World"
|
||||
CheckDecrypt
|
||||
|
||||
Encrypt = RSA-2048
|
||||
RSAPadding = OAEP
|
||||
Input = "Hello World"
|
||||
CheckDecrypt
|
||||
|
||||
Encrypt = RSA-2048
|
||||
RSAPadding = OAEP
|
||||
OAEPDigest = SHA512
|
||||
OAEPLabel = 00112233445566778899aabbccddeeff
|
||||
Input = "Hello World"
|
||||
CheckDecrypt
|
||||
|
||||
|
||||
# EC tests
|
||||
|
||||
|
||||
@@ -151,8 +151,8 @@ static int dsa_priv_decode(EVP_PKEY *out, CBS *params, CBS *key) {
|
||||
// Calculate the public key.
|
||||
ctx = BN_CTX_new();
|
||||
if (ctx == NULL ||
|
||||
!BN_mod_exp_mont(dsa->pub_key, dsa->g, dsa->priv_key, dsa->p, ctx,
|
||||
NULL)) {
|
||||
!BN_mod_exp_mont_consttime(dsa->pub_key, dsa->g, dsa->priv_key, dsa->p,
|
||||
ctx, NULL)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,12 +24,8 @@
|
||||
|
||||
|
||||
static void ed25519_free(EVP_PKEY *pkey) {
|
||||
if (pkey->pkey.ptr != NULL) {
|
||||
ED25519_KEY *key = pkey->pkey.ptr;
|
||||
OPENSSL_cleanse(key, sizeof(ED25519_KEY));
|
||||
OPENSSL_free(key);
|
||||
pkey->pkey.ptr = NULL;
|
||||
}
|
||||
OPENSSL_free(pkey->pkey.ptr);
|
||||
pkey->pkey.ptr = NULL;
|
||||
}
|
||||
|
||||
static int set_pubkey(EVP_PKEY *pkey, const uint8_t pubkey[32]) {
|
||||
|
||||
+12
-14
@@ -92,6 +92,11 @@ typedef struct {
|
||||
size_t oaep_labellen;
|
||||
} RSA_PKEY_CTX;
|
||||
|
||||
typedef struct {
|
||||
uint8_t *data;
|
||||
size_t len;
|
||||
} RSA_OAEP_LABEL_PARAMS;
|
||||
|
||||
static int pkey_rsa_init(EVP_PKEY_CTX *ctx) {
|
||||
RSA_PKEY_CTX *rctx;
|
||||
rctx = OPENSSL_malloc(sizeof(RSA_PKEY_CTX));
|
||||
@@ -485,20 +490,17 @@ static int pkey_rsa_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) {
|
||||
}
|
||||
return 1;
|
||||
|
||||
case EVP_PKEY_CTRL_RSA_OAEP_LABEL:
|
||||
case EVP_PKEY_CTRL_RSA_OAEP_LABEL: {
|
||||
if (rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) {
|
||||
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PADDING_MODE);
|
||||
return 0;
|
||||
}
|
||||
OPENSSL_free(rctx->oaep_label);
|
||||
if (p2 && p1 > 0) {
|
||||
rctx->oaep_label = p2;
|
||||
rctx->oaep_labellen = p1;
|
||||
} else {
|
||||
rctx->oaep_label = NULL;
|
||||
rctx->oaep_labellen = 0;
|
||||
}
|
||||
RSA_OAEP_LABEL_PARAMS *params = p2;
|
||||
rctx->oaep_label = params->data;
|
||||
rctx->oaep_labellen = params->len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
case EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL:
|
||||
if (rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) {
|
||||
@@ -611,13 +613,9 @@ int EVP_PKEY_CTX_get_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md) {
|
||||
|
||||
int EVP_PKEY_CTX_set0_rsa_oaep_label(EVP_PKEY_CTX *ctx, uint8_t *label,
|
||||
size_t label_len) {
|
||||
if (label_len > INT_MAX) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
RSA_OAEP_LABEL_PARAMS params = {label, label_len};
|
||||
return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT,
|
||||
EVP_PKEY_CTRL_RSA_OAEP_LABEL, (int)label_len,
|
||||
(void *)label);
|
||||
EVP_PKEY_CTRL_RSA_OAEP_LABEL, 0, ¶ms);
|
||||
}
|
||||
|
||||
int EVP_PKEY_CTX_get0_rsa_oaep_label(EVP_PKEY_CTX *ctx,
|
||||
|
||||
+2
-23
@@ -63,19 +63,9 @@
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
#include "../fipsmodule/rsa/internal.h"
|
||||
#include "../internal.h"
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
static struct CRYPTO_STATIC_MUTEX g_buggy_lock = CRYPTO_STATIC_MUTEX_INIT;
|
||||
static int g_buggy = 1;
|
||||
|
||||
void EVP_set_buggy_rsa_parser(int buggy) {
|
||||
CRYPTO_STATIC_MUTEX_lock_write(&g_buggy_lock);
|
||||
g_buggy = buggy;
|
||||
CRYPTO_STATIC_MUTEX_unlock_write(&g_buggy_lock);
|
||||
}
|
||||
|
||||
static int rsa_pub_encode(CBB *out, const EVP_PKEY *key) {
|
||||
// See RFC 3279, section 2.3.1.
|
||||
CBB spki, algorithm, oid, null, key_bitstring;
|
||||
@@ -96,11 +86,6 @@ static int rsa_pub_encode(CBB *out, const EVP_PKEY *key) {
|
||||
}
|
||||
|
||||
static int rsa_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) {
|
||||
int buggy;
|
||||
CRYPTO_STATIC_MUTEX_lock_read(&g_buggy_lock);
|
||||
buggy = g_buggy;
|
||||
CRYPTO_STATIC_MUTEX_unlock_read(&g_buggy_lock);
|
||||
|
||||
// See RFC 3279, section 2.3.1.
|
||||
|
||||
// The parameters must be NULL.
|
||||
@@ -112,13 +97,7 @@ static int rsa_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Estonian IDs issued between September 2014 to September 2015 are
|
||||
// broken. See https://crbug.com/532048 and https://crbug.com/534766.
|
||||
//
|
||||
// TODO(davidben): Switch this to the strict version in March 2016 or when
|
||||
// Chromium can force client certificates down a different codepath, whichever
|
||||
// comes first.
|
||||
RSA *rsa = buggy ? RSA_parse_public_key_buggy(key) : RSA_parse_public_key(key);
|
||||
RSA *rsa = RSA_parse_public_key(key);
|
||||
if (rsa == NULL || CBS_len(key) != 0) {
|
||||
OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
|
||||
RSA_free(rsa);
|
||||
@@ -182,7 +161,7 @@ static int int_rsa_size(const EVP_PKEY *pkey) {
|
||||
}
|
||||
|
||||
static int rsa_bits(const EVP_PKEY *pkey) {
|
||||
return BN_num_bits(pkey->pkey.rsa->n);
|
||||
return RSA_bits(pkey->pkey.rsa);
|
||||
}
|
||||
|
||||
static void int_rsa_free(EVP_PKEY *pkey) { RSA_free(pkey->pkey.rsa); }
|
||||
|
||||
@@ -113,7 +113,6 @@
|
||||
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/lhash.h>
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/stack.h>
|
||||
#include <openssl/thread.h>
|
||||
|
||||
@@ -200,7 +200,7 @@ asm_AES_encrypt:
|
||||
#ifndef __thumb2__
|
||||
sub r3,pc,#8 @ asm_AES_encrypt
|
||||
#else
|
||||
adr r3,asm_AES_encrypt
|
||||
adr r3,.
|
||||
#endif
|
||||
stmdb sp!,{r1,r4-r12,lr}
|
||||
#ifdef __APPLE__
|
||||
@@ -450,7 +450,7 @@ _armv4_AES_set_encrypt_key:
|
||||
#ifndef __thumb2__
|
||||
sub r3,pc,#8 @ asm_AES_set_encrypt_key
|
||||
#else
|
||||
adr r3,asm_AES_set_encrypt_key
|
||||
adr r3,.
|
||||
#endif
|
||||
teq r0,#0
|
||||
#ifdef __thumb2__
|
||||
@@ -976,7 +976,7 @@ asm_AES_decrypt:
|
||||
#ifndef __thumb2__
|
||||
sub r3,pc,#8 @ asm_AES_decrypt
|
||||
#else
|
||||
adr r3,asm_AES_decrypt
|
||||
adr r3,.
|
||||
#endif
|
||||
stmdb sp!,{r1,r4-r12,lr}
|
||||
#ifdef __APPLE__
|
||||
|
||||
@@ -744,7 +744,7 @@ $code.=<<___;
|
||||
.type _bsaes_decrypt8,%function
|
||||
.align 4
|
||||
_bsaes_decrypt8:
|
||||
adr $const,_bsaes_decrypt8
|
||||
adr $const,.
|
||||
vldmia $key!, {@XMM[9]} @ round 0 key
|
||||
#ifdef __APPLE__
|
||||
adr $const,.LM0ISR
|
||||
@@ -843,7 +843,7 @@ _bsaes_const:
|
||||
.type _bsaes_encrypt8,%function
|
||||
.align 4
|
||||
_bsaes_encrypt8:
|
||||
adr $const,_bsaes_encrypt8
|
||||
adr $const,.
|
||||
vldmia $key!, {@XMM[9]} @ round 0 key
|
||||
#ifdef __APPLE__
|
||||
adr $const,.LM0SR
|
||||
@@ -951,7 +951,7 @@ $code.=<<___;
|
||||
.type _bsaes_key_convert,%function
|
||||
.align 4
|
||||
_bsaes_key_convert:
|
||||
adr $const,_bsaes_key_convert
|
||||
adr $const,.
|
||||
vld1.8 {@XMM[7]}, [$inp]! @ load round 0 key
|
||||
#ifdef __APPLE__
|
||||
adr $const,.LM0
|
||||
|
||||
@@ -133,7 +133,7 @@ int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
|
||||
while (dif) {
|
||||
dif--;
|
||||
t1 = *(ap++);
|
||||
t2 = (t1 + 1) & BN_MASK2;
|
||||
t2 = t1 + 1;
|
||||
*(rp++) = t2;
|
||||
if (t2) {
|
||||
carry = 0;
|
||||
@@ -162,8 +162,6 @@ 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;
|
||||
@@ -185,7 +183,7 @@ int BN_add_word(BIGNUM *a, BN_ULONG w) {
|
||||
}
|
||||
|
||||
for (i = 0; w != 0 && i < a->top; i++) {
|
||||
a->d[i] = l = (a->d[i] + w) & BN_MASK2;
|
||||
a->d[i] = l = a->d[i] + w;
|
||||
w = (w > l) ? 1 : 0;
|
||||
}
|
||||
|
||||
@@ -285,12 +283,12 @@ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
|
||||
t2 = *(bp++);
|
||||
if (carry) {
|
||||
carry = (t1 <= t2);
|
||||
t1 = (t1 - t2 - 1) & BN_MASK2;
|
||||
t1 -= t2 + 1;
|
||||
} else {
|
||||
carry = (t1 < t2);
|
||||
t1 = (t1 - t2) & BN_MASK2;
|
||||
t1 -= t2;
|
||||
}
|
||||
*(rp++) = t1 & BN_MASK2;
|
||||
*(rp++) = t1;
|
||||
}
|
||||
|
||||
if (carry) // subtracted
|
||||
@@ -303,7 +301,7 @@ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
|
||||
while (dif) {
|
||||
dif--;
|
||||
t1 = *(ap++);
|
||||
t2 = (t1 - 1) & BN_MASK2;
|
||||
t2 = t1 - 1;
|
||||
*(rp++) = t2;
|
||||
if (t1) {
|
||||
break;
|
||||
@@ -325,8 +323,6 @@ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
|
||||
int BN_sub_word(BIGNUM *a, BN_ULONG w) {
|
||||
int i;
|
||||
|
||||
w &= BN_MASK2;
|
||||
|
||||
// degenerate case: w is zero
|
||||
if (!w) {
|
||||
return 1;
|
||||
@@ -361,7 +357,7 @@ int BN_sub_word(BIGNUM *a, BN_ULONG w) {
|
||||
a->d[i] -= w;
|
||||
break;
|
||||
} else {
|
||||
a->d[i] = (a->d[i] - w) & BN_MASK2;
|
||||
a->d[i] -= w;
|
||||
i++;
|
||||
w = 1;
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ $code.=<<___;
|
||||
vmovdqu 32*8-128($ap), $ACC8
|
||||
|
||||
lea 192(%rsp), $tp0 # 64+128=192
|
||||
vpbroadcastq .Land_mask(%rip), $AND_MASK
|
||||
vmovdqu .Land_mask(%rip), $AND_MASK
|
||||
jmp .LOOP_GRANDE_SQR_1024
|
||||
|
||||
.align 32
|
||||
@@ -1082,10 +1082,10 @@ $code.=<<___;
|
||||
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
|
||||
vpblendd \$3, $ZERO, $ACC9, $TEMP1 # correct $ACC3
|
||||
vpaddq $TEMP2,$ACC7,$ACC7
|
||||
vpmuludq 32*8-128($np),$Yi,$TEMP0
|
||||
vpaddq $ACC9, $ACC3, $ACC3 # correct $ACC3
|
||||
vpaddq $TEMP1, $ACC3, $ACC3 # correct $ACC3
|
||||
vpaddq $TEMP0,$ACC8,$ACC8
|
||||
|
||||
mov %rbx, %rax
|
||||
@@ -1098,7 +1098,9 @@ $code.=<<___;
|
||||
vmovdqu -8+32*2-128($ap),$TEMP2
|
||||
|
||||
mov $r1, %rax
|
||||
vpblendd \$0xfc, $ZERO, $ACC9, $ACC9 # correct $ACC3
|
||||
imull $n0, %eax
|
||||
vpaddq $ACC9,$ACC4,$ACC4 # correct $ACC3
|
||||
and \$0x1fffffff, %eax
|
||||
|
||||
imulq 16-128($ap),%rbx
|
||||
@@ -1334,15 +1336,12 @@ ___
|
||||
# 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.
|
||||
# avoid performance penalties completely.
|
||||
|
||||
$TEMP0 = $ACC9;
|
||||
$TEMP3 = $Bi;
|
||||
$TEMP4 = $Yi;
|
||||
$code.=<<___;
|
||||
vpermq \$0, $AND_MASK, $AND_MASK
|
||||
vpaddq (%rsp), $TEMP1, $ACC0
|
||||
|
||||
vpsrlq \$29, $ACC0, $TEMP1
|
||||
@@ -1790,7 +1789,7 @@ $code.=<<___;
|
||||
|
||||
.align 64
|
||||
.Land_mask:
|
||||
.quad 0x1fffffff,0x1fffffff,0x1fffffff,-1
|
||||
.quad 0x1fffffff,0x1fffffff,0x1fffffff,0x1fffffff
|
||||
.Lscatter_permd:
|
||||
.long 0,2,4,6,7,7,7,7
|
||||
.Lgather_permd:
|
||||
|
||||
@@ -93,11 +93,11 @@
|
||||
#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 bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, size_t num,
|
||||
BN_ULONG w) {
|
||||
BN_ULONG c1 = 0;
|
||||
|
||||
if (num <= 0) {
|
||||
if (num == 0) {
|
||||
return (c1);
|
||||
}
|
||||
|
||||
@@ -126,10 +126,11 @@ BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num,
|
||||
return c1;
|
||||
}
|
||||
|
||||
BN_ULONG bn_mul_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, size_t num,
|
||||
BN_ULONG w) {
|
||||
BN_ULONG c1 = 0;
|
||||
|
||||
if (num <= 0) {
|
||||
if (num == 0) {
|
||||
return c1;
|
||||
}
|
||||
|
||||
@@ -156,8 +157,8 @@ BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w) {
|
||||
return c1;
|
||||
}
|
||||
|
||||
void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, int n) {
|
||||
if (n <= 0) {
|
||||
void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, size_t n) {
|
||||
if (n == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -184,11 +185,11 @@ void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, int n) {
|
||||
}
|
||||
|
||||
BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
|
||||
int n) {
|
||||
size_t n) {
|
||||
BN_ULONG ret;
|
||||
size_t i = 0;
|
||||
|
||||
if (n <= 0) {
|
||||
if (n == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -201,7 +202,8 @@ BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
|
||||
" adcq (%5,%2,8),%0 \n"
|
||||
" movq %0,(%3,%2,8) \n"
|
||||
" lea 1(%2),%2 \n"
|
||||
" loop 1b \n"
|
||||
" dec %1 \n"
|
||||
" jnz 1b \n"
|
||||
" sbbq %0,%0 \n"
|
||||
: "=&r"(ret), "+c"(n), "+r"(i)
|
||||
: "r"(rp), "r"(ap), "r"(bp)
|
||||
@@ -211,11 +213,11 @@ BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
|
||||
}
|
||||
|
||||
BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
|
||||
int n) {
|
||||
size_t n) {
|
||||
BN_ULONG ret;
|
||||
size_t i = 0;
|
||||
|
||||
if (n <= 0) {
|
||||
if (n == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -228,7 +230,8 @@ BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
|
||||
" sbbq (%5,%2,8),%0 \n"
|
||||
" movq %0,(%3,%2,8) \n"
|
||||
" lea 1(%2),%2 \n"
|
||||
" loop 1b \n"
|
||||
" dec %1 \n"
|
||||
" jnz 1b \n"
|
||||
" sbbq %0,%0 \n"
|
||||
: "=&r"(ret), "+c"(n), "+r"(i)
|
||||
: "r"(rp), "r"(ap), "r"(bp)
|
||||
@@ -280,7 +283,7 @@ BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
|
||||
|
||||
#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) {
|
||||
void bn_mul_comba8(BN_ULONG r[16], const BN_ULONG a[8], const BN_ULONG b[8]) {
|
||||
BN_ULONG c1, c2, c3;
|
||||
|
||||
c1 = 0;
|
||||
@@ -382,7 +385,7 @@ void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) {
|
||||
r[15] = c1;
|
||||
}
|
||||
|
||||
void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) {
|
||||
void bn_mul_comba4(BN_ULONG r[8], const BN_ULONG a[4], const BN_ULONG b[4]) {
|
||||
BN_ULONG c1, c2, c3;
|
||||
|
||||
c1 = 0;
|
||||
@@ -420,7 +423,7 @@ void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) {
|
||||
r[7] = c2;
|
||||
}
|
||||
|
||||
void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a) {
|
||||
void bn_sqr_comba8(BN_ULONG r[16], const BN_ULONG a[8]) {
|
||||
BN_ULONG c1, c2, c3;
|
||||
|
||||
c1 = 0;
|
||||
@@ -494,7 +497,7 @@ void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a) {
|
||||
r[15] = c1;
|
||||
}
|
||||
|
||||
void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a) {
|
||||
void bn_sqr_comba4(BN_ULONG r[8], const BN_ULONG a[4]) {
|
||||
BN_ULONG c1, c2, c3;
|
||||
|
||||
c1 = 0;
|
||||
|
||||
@@ -3190,11 +3190,19 @@ $code.=<<___;
|
||||
|
||||
.align 32
|
||||
.Lsqrx8x_break:
|
||||
sub 16+8(%rsp),%r8 # consume last carry
|
||||
xor $zero,$zero
|
||||
sub 16+8(%rsp),%rbx # mov 16(%rsp),%cf
|
||||
adcx $zero,%r8
|
||||
mov 24+8(%rsp),$carry # initial $tptr, borrow $carry
|
||||
adcx $zero,%r9
|
||||
mov 0*8($aptr),%rdx # a[8], modulo-scheduled
|
||||
xor %ebp,%ebp # xor $zero,$zero
|
||||
adc \$0,%r10
|
||||
mov %r8,0*8($tptr)
|
||||
adc \$0,%r11
|
||||
adc \$0,%r12
|
||||
adc \$0,%r13
|
||||
adc \$0,%r14
|
||||
adc \$0,%r15
|
||||
cmp $carry,$tptr # cf=0, of=0
|
||||
je .Lsqrx8x_outer_loop
|
||||
|
||||
|
||||
@@ -108,16 +108,18 @@ void BN_clear_free(BIGNUM *bn) {
|
||||
}
|
||||
|
||||
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);
|
||||
} else {
|
||||
OPENSSL_cleanse(bn->d, bn->dmax * sizeof(bn->d[0]));
|
||||
}
|
||||
}
|
||||
|
||||
should_free = (bn->flags & BN_FLG_MALLOCED) != 0;
|
||||
OPENSSL_cleanse(bn, sizeof(BIGNUM));
|
||||
if (should_free) {
|
||||
OPENSSL_free(bn);
|
||||
} else {
|
||||
OPENSSL_cleanse(bn, sizeof(BIGNUM));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+258
-68
@@ -93,6 +93,7 @@
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "./internal.h"
|
||||
#include "../../internal.h"
|
||||
#include "../../test/file_test.h"
|
||||
#include "../../test/test_util.h"
|
||||
@@ -356,9 +357,11 @@ static void TestSquare(FileTest *t, BN_CTX *ctx) {
|
||||
ASSERT_TRUE(BN_mul(ret.get(), a.get(), a.get(), ctx));
|
||||
EXPECT_BIGNUMS_EQUAL("A * A", square.get(), ret.get());
|
||||
|
||||
ASSERT_TRUE(BN_div(ret.get(), remainder.get(), square.get(), a.get(), ctx));
|
||||
EXPECT_BIGNUMS_EQUAL("Square / A", a.get(), ret.get());
|
||||
EXPECT_BIGNUMS_EQUAL("Square % A", zero.get(), remainder.get());
|
||||
if (!BN_is_zero(a.get())) {
|
||||
ASSERT_TRUE(BN_div(ret.get(), remainder.get(), square.get(), a.get(), ctx));
|
||||
EXPECT_BIGNUMS_EQUAL("Square / A", a.get(), ret.get());
|
||||
EXPECT_BIGNUMS_EQUAL("Square % A", zero.get(), remainder.get());
|
||||
}
|
||||
|
||||
BN_set_negative(a.get(), 0);
|
||||
ASSERT_TRUE(BN_sqrt(ret.get(), square.get(), ctx));
|
||||
@@ -381,6 +384,31 @@ static void TestSquare(FileTest *t, BN_CTX *ctx) {
|
||||
<< "BN_sqrt succeeded on a non-square";
|
||||
ERR_clear_error();
|
||||
}
|
||||
|
||||
#if !defined(BORINGSSL_SHARED_LIBRARY)
|
||||
if (static_cast<size_t>(a->top) <= BN_SMALL_MAX_WORDS) {
|
||||
for (size_t num_a = a->top; num_a <= BN_SMALL_MAX_WORDS; num_a++) {
|
||||
SCOPED_TRACE(num_a);
|
||||
size_t num_r = 2 * num_a;
|
||||
// Use newly-allocated buffers so ASan will catch out-of-bounds writes.
|
||||
std::unique_ptr<BN_ULONG[]> a_words(new BN_ULONG[num_a]),
|
||||
r_words(new BN_ULONG[num_r]);
|
||||
OPENSSL_memset(a_words.get(), 0, num_a * sizeof(BN_ULONG));
|
||||
OPENSSL_memcpy(a_words.get(), a->d, a->top * sizeof(BN_ULONG));
|
||||
|
||||
ASSERT_TRUE(bn_mul_small(r_words.get(), num_r, a_words.get(), num_a,
|
||||
a_words.get(), num_a));
|
||||
ASSERT_TRUE(bn_set_words(ret.get(), r_words.get(), num_r));
|
||||
EXPECT_BIGNUMS_EQUAL("A * A (words)", square.get(), ret.get());
|
||||
|
||||
OPENSSL_memset(r_words.get(), 'A', num_r * sizeof(BN_ULONG));
|
||||
ASSERT_TRUE(bn_sqr_small(r_words.get(), num_r, a_words.get(), num_a));
|
||||
|
||||
ASSERT_TRUE(bn_set_words(ret.get(), r_words.get(), num_r));
|
||||
EXPECT_BIGNUMS_EQUAL("A^2 (words)", square.get(), ret.get());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void TestProduct(FileTest *t, BN_CTX *ctx) {
|
||||
@@ -401,13 +429,46 @@ static void TestProduct(FileTest *t, BN_CTX *ctx) {
|
||||
ASSERT_TRUE(BN_mul(ret.get(), a.get(), b.get(), ctx));
|
||||
EXPECT_BIGNUMS_EQUAL("A * B", product.get(), ret.get());
|
||||
|
||||
ASSERT_TRUE(BN_div(ret.get(), remainder.get(), product.get(), a.get(), ctx));
|
||||
EXPECT_BIGNUMS_EQUAL("Product / A", b.get(), ret.get());
|
||||
EXPECT_BIGNUMS_EQUAL("Product % A", zero.get(), remainder.get());
|
||||
if (!BN_is_zero(a.get())) {
|
||||
ASSERT_TRUE(
|
||||
BN_div(ret.get(), remainder.get(), product.get(), a.get(), ctx));
|
||||
EXPECT_BIGNUMS_EQUAL("Product / A", b.get(), ret.get());
|
||||
EXPECT_BIGNUMS_EQUAL("Product % A", zero.get(), remainder.get());
|
||||
}
|
||||
|
||||
ASSERT_TRUE(BN_div(ret.get(), remainder.get(), product.get(), b.get(), ctx));
|
||||
EXPECT_BIGNUMS_EQUAL("Product / B", a.get(), ret.get());
|
||||
EXPECT_BIGNUMS_EQUAL("Product % B", zero.get(), remainder.get());
|
||||
if (!BN_is_zero(b.get())) {
|
||||
ASSERT_TRUE(
|
||||
BN_div(ret.get(), remainder.get(), product.get(), b.get(), ctx));
|
||||
EXPECT_BIGNUMS_EQUAL("Product / B", a.get(), ret.get());
|
||||
EXPECT_BIGNUMS_EQUAL("Product % B", zero.get(), remainder.get());
|
||||
}
|
||||
|
||||
#if !defined(BORINGSSL_SHARED_LIBRARY)
|
||||
if (!BN_is_negative(product.get()) &&
|
||||
static_cast<size_t>(a->top) <= BN_SMALL_MAX_WORDS &&
|
||||
static_cast<size_t>(b->top) <= BN_SMALL_MAX_WORDS) {
|
||||
for (size_t num_a = a->top; num_a <= BN_SMALL_MAX_WORDS; num_a++) {
|
||||
SCOPED_TRACE(num_a);
|
||||
for (size_t num_b = b->top; num_b <= BN_SMALL_MAX_WORDS; num_b++) {
|
||||
SCOPED_TRACE(num_b);
|
||||
size_t num_r = num_a + num_b;
|
||||
// Use newly-allocated buffers so ASan will catch out-of-bounds writes.
|
||||
std::unique_ptr<BN_ULONG[]> a_words(new BN_ULONG[num_a]),
|
||||
b_words(new BN_ULONG[num_b]), r_words(new BN_ULONG[num_r]);
|
||||
OPENSSL_memset(a_words.get(), 0, num_a * sizeof(BN_ULONG));
|
||||
OPENSSL_memcpy(a_words.get(), a->d, a->top * sizeof(BN_ULONG));
|
||||
|
||||
OPENSSL_memset(b_words.get(), 0, num_b * sizeof(BN_ULONG));
|
||||
OPENSSL_memcpy(b_words.get(), b->d, b->top * sizeof(BN_ULONG));
|
||||
|
||||
ASSERT_TRUE(bn_mul_small(r_words.get(), num_r, a_words.get(), num_a,
|
||||
b_words.get(), num_b));
|
||||
ASSERT_TRUE(bn_set_words(ret.get(), r_words.get(), num_r));
|
||||
EXPECT_BIGNUMS_EQUAL("A * B (words)", product.get(), ret.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void TestQuotient(FileTest *t, BN_CTX *ctx) {
|
||||
@@ -481,15 +542,39 @@ static void TestModMul(FileTest *t, BN_CTX *ctx) {
|
||||
ASSERT_TRUE(a_tmp);
|
||||
ASSERT_TRUE(b_tmp);
|
||||
ASSERT_TRUE(BN_MONT_CTX_set(mont.get(), m.get(), ctx));
|
||||
ASSERT_TRUE(BN_nnmod(a_tmp.get(), a.get(), m.get(), ctx));
|
||||
ASSERT_TRUE(BN_nnmod(b_tmp.get(), b.get(), m.get(), ctx));
|
||||
ASSERT_TRUE(BN_to_montgomery(a_tmp.get(), a_tmp.get(), mont.get(), ctx));
|
||||
ASSERT_TRUE(BN_to_montgomery(b_tmp.get(), b_tmp.get(), mont.get(), ctx));
|
||||
ASSERT_TRUE(BN_nnmod(a.get(), a.get(), m.get(), ctx));
|
||||
ASSERT_TRUE(BN_nnmod(b.get(), b.get(), m.get(), ctx));
|
||||
ASSERT_TRUE(BN_to_montgomery(a_tmp.get(), a.get(), mont.get(), ctx));
|
||||
ASSERT_TRUE(BN_to_montgomery(b_tmp.get(), b.get(), mont.get(), ctx));
|
||||
ASSERT_TRUE(BN_mod_mul_montgomery(ret.get(), a_tmp.get(), b_tmp.get(),
|
||||
mont.get(), ctx));
|
||||
ASSERT_TRUE(BN_from_montgomery(ret.get(), ret.get(), mont.get(), ctx));
|
||||
EXPECT_BIGNUMS_EQUAL("A * B (mod M) (Montgomery)", mod_mul.get(),
|
||||
ret.get());
|
||||
|
||||
#if !defined(BORINGSSL_SHARED_LIBRARY)
|
||||
if (m->top <= BN_SMALL_MAX_WORDS) {
|
||||
std::unique_ptr<BN_ULONG[]> a_words(new BN_ULONG[m->top]),
|
||||
b_words(new BN_ULONG[m->top]), r_words(new BN_ULONG[m->top]);
|
||||
OPENSSL_memset(a_words.get(), 0, m->top * sizeof(BN_ULONG));
|
||||
OPENSSL_memcpy(a_words.get(), a->d, a->top * sizeof(BN_ULONG));
|
||||
OPENSSL_memset(b_words.get(), 0, m->top * sizeof(BN_ULONG));
|
||||
OPENSSL_memcpy(b_words.get(), b->d, b->top * sizeof(BN_ULONG));
|
||||
ASSERT_TRUE(bn_to_montgomery_small(a_words.get(), m->top, a_words.get(),
|
||||
m->top, mont.get()));
|
||||
ASSERT_TRUE(bn_to_montgomery_small(b_words.get(), m->top, b_words.get(),
|
||||
m->top, mont.get()));
|
||||
ASSERT_TRUE(bn_mod_mul_montgomery_small(
|
||||
r_words.get(), m->top, a_words.get(), m->top, b_words.get(), m->top,
|
||||
mont.get()));
|
||||
// Use the second half of |tmp| so ASan will catch out-of-bounds writes.
|
||||
ASSERT_TRUE(bn_from_montgomery_small(r_words.get(), m->top, r_words.get(),
|
||||
m->top, mont.get()));
|
||||
ASSERT_TRUE(bn_set_words(ret.get(), r_words.get(), m->top));
|
||||
EXPECT_BIGNUMS_EQUAL("A * B (mod M) (Montgomery, words)", mod_mul.get(),
|
||||
ret.get());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -520,8 +605,8 @@ static void TestModSquare(FileTest *t, BN_CTX *ctx) {
|
||||
ASSERT_TRUE(mont);
|
||||
ASSERT_TRUE(a_tmp);
|
||||
ASSERT_TRUE(BN_MONT_CTX_set(mont.get(), m.get(), ctx));
|
||||
ASSERT_TRUE(BN_nnmod(a_tmp.get(), a.get(), m.get(), ctx));
|
||||
ASSERT_TRUE(BN_to_montgomery(a_tmp.get(), a_tmp.get(), mont.get(), ctx));
|
||||
ASSERT_TRUE(BN_nnmod(a.get(), a.get(), m.get(), ctx));
|
||||
ASSERT_TRUE(BN_to_montgomery(a_tmp.get(), a.get(), mont.get(), ctx));
|
||||
ASSERT_TRUE(BN_mod_mul_montgomery(ret.get(), a_tmp.get(), a_tmp.get(),
|
||||
mont.get(), ctx));
|
||||
ASSERT_TRUE(BN_from_montgomery(ret.get(), ret.get(), mont.get(), ctx));
|
||||
@@ -535,6 +620,38 @@ static void TestModSquare(FileTest *t, BN_CTX *ctx) {
|
||||
ASSERT_TRUE(BN_from_montgomery(ret.get(), ret.get(), mont.get(), ctx));
|
||||
EXPECT_BIGNUMS_EQUAL("A * A_copy (mod M) (Montgomery)", mod_square.get(),
|
||||
ret.get());
|
||||
|
||||
#if !defined(BORINGSSL_SHARED_LIBRARY)
|
||||
if (m->top <= BN_SMALL_MAX_WORDS) {
|
||||
std::unique_ptr<BN_ULONG[]> a_words(new BN_ULONG[m->top]),
|
||||
a_copy_words(new BN_ULONG[m->top]), r_words(new BN_ULONG[m->top]);
|
||||
OPENSSL_memset(a_words.get(), 0, m->top * sizeof(BN_ULONG));
|
||||
OPENSSL_memcpy(a_words.get(), a->d, a->top * sizeof(BN_ULONG));
|
||||
ASSERT_TRUE(bn_to_montgomery_small(a_words.get(), m->top, a_words.get(),
|
||||
m->top, mont.get()));
|
||||
ASSERT_TRUE(bn_mod_mul_montgomery_small(
|
||||
r_words.get(), m->top, a_words.get(), m->top, a_words.get(), m->top,
|
||||
mont.get()));
|
||||
ASSERT_TRUE(bn_from_montgomery_small(r_words.get(), m->top, r_words.get(),
|
||||
m->top, mont.get()));
|
||||
ASSERT_TRUE(bn_set_words(ret.get(), r_words.get(), m->top));
|
||||
EXPECT_BIGNUMS_EQUAL("A * A (mod M) (Montgomery, words)",
|
||||
mod_square.get(), ret.get());
|
||||
|
||||
// Repeat the operation with |a_copy_words|.
|
||||
OPENSSL_memcpy(a_copy_words.get(), a_words.get(),
|
||||
m->top * sizeof(BN_ULONG));
|
||||
ASSERT_TRUE(bn_mod_mul_montgomery_small(
|
||||
r_words.get(), m->top, a_words.get(), m->top, a_copy_words.get(),
|
||||
m->top, mont.get()));
|
||||
// Use the second half of |tmp| so ASan will catch out-of-bounds writes.
|
||||
ASSERT_TRUE(bn_from_montgomery_small(r_words.get(), m->top, r_words.get(),
|
||||
m->top, mont.get()));
|
||||
ASSERT_TRUE(bn_set_words(ret.get(), r_words.get(), m->top));
|
||||
EXPECT_BIGNUMS_EQUAL("A * A_copy (mod M) (Montgomery, words)",
|
||||
mod_square.get(), ret.get());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -563,6 +680,28 @@ static void TestModExp(FileTest *t, BN_CTX *ctx) {
|
||||
ctx, NULL));
|
||||
EXPECT_BIGNUMS_EQUAL("A ^ E (mod M) (constant-time)", mod_exp.get(),
|
||||
ret.get());
|
||||
|
||||
#if !defined(BORINGSSL_SHARED_LIBRARY)
|
||||
if (m->top <= BN_SMALL_MAX_WORDS) {
|
||||
bssl::UniquePtr<BN_MONT_CTX> mont(BN_MONT_CTX_new());
|
||||
ASSERT_TRUE(mont.get());
|
||||
ASSERT_TRUE(BN_MONT_CTX_set(mont.get(), m.get(), ctx));
|
||||
ASSERT_TRUE(BN_nnmod(a.get(), a.get(), m.get(), ctx));
|
||||
std::unique_ptr<BN_ULONG[]> r_words(new BN_ULONG[m->top]),
|
||||
a_words(new BN_ULONG[m->top]);
|
||||
OPENSSL_memset(a_words.get(), 0, m->top * sizeof(BN_ULONG));
|
||||
OPENSSL_memcpy(a_words.get(), a->d, a->top * sizeof(BN_ULONG));
|
||||
ASSERT_TRUE(bn_to_montgomery_small(a_words.get(), m->top, a_words.get(),
|
||||
m->top, mont.get()));
|
||||
ASSERT_TRUE(bn_mod_exp_mont_small(r_words.get(), m->top, a_words.get(),
|
||||
m->top, e->d, e->top, mont.get()));
|
||||
ASSERT_TRUE(bn_from_montgomery_small(r_words.get(), m->top, r_words.get(),
|
||||
m->top, mont.get()));
|
||||
ASSERT_TRUE(bn_set_words(ret.get(), r_words.get(), m->top));
|
||||
EXPECT_BIGNUMS_EQUAL("A ^ E (mod M) (Montgomery, words)", mod_exp.get(),
|
||||
ret.get());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -778,27 +917,27 @@ static int DecimalToBIGNUM(bssl::UniquePtr<BIGNUM> *out, const char *in) {
|
||||
TEST_F(BNTest, Dec2BN) {
|
||||
bssl::UniquePtr<BIGNUM> bn;
|
||||
int ret = DecimalToBIGNUM(&bn, "0");
|
||||
EXPECT_EQ(1, ret);
|
||||
ASSERT_EQ(1, ret);
|
||||
EXPECT_TRUE(BN_is_zero(bn.get()));
|
||||
EXPECT_FALSE(BN_is_negative(bn.get()));
|
||||
|
||||
ret = DecimalToBIGNUM(&bn, "256");
|
||||
EXPECT_EQ(3, ret);
|
||||
ASSERT_EQ(3, ret);
|
||||
EXPECT_TRUE(BN_is_word(bn.get(), 256));
|
||||
EXPECT_FALSE(BN_is_negative(bn.get()));
|
||||
|
||||
ret = DecimalToBIGNUM(&bn, "-42");
|
||||
EXPECT_EQ(3, ret);
|
||||
ASSERT_EQ(3, ret);
|
||||
EXPECT_TRUE(BN_abs_is_word(bn.get(), 42));
|
||||
EXPECT_TRUE(BN_is_negative(bn.get()));
|
||||
|
||||
ret = DecimalToBIGNUM(&bn, "-0");
|
||||
EXPECT_EQ(2, ret);
|
||||
ASSERT_EQ(2, ret);
|
||||
EXPECT_TRUE(BN_is_zero(bn.get()));
|
||||
EXPECT_FALSE(BN_is_negative(bn.get()));
|
||||
|
||||
ret = DecimalToBIGNUM(&bn, "42trailing garbage is ignored");
|
||||
EXPECT_EQ(2, ret);
|
||||
ASSERT_EQ(2, ret);
|
||||
EXPECT_TRUE(BN_abs_is_word(bn.get(), 42));
|
||||
EXPECT_FALSE(BN_is_negative(bn.get()));
|
||||
}
|
||||
@@ -806,27 +945,27 @@ TEST_F(BNTest, Dec2BN) {
|
||||
TEST_F(BNTest, Hex2BN) {
|
||||
bssl::UniquePtr<BIGNUM> bn;
|
||||
int ret = HexToBIGNUM(&bn, "0");
|
||||
EXPECT_EQ(1, ret);
|
||||
ASSERT_EQ(1, ret);
|
||||
EXPECT_TRUE(BN_is_zero(bn.get()));
|
||||
EXPECT_FALSE(BN_is_negative(bn.get()));
|
||||
|
||||
ret = HexToBIGNUM(&bn, "256");
|
||||
EXPECT_EQ(3, ret);
|
||||
ASSERT_EQ(3, ret);
|
||||
EXPECT_TRUE(BN_is_word(bn.get(), 0x256));
|
||||
EXPECT_FALSE(BN_is_negative(bn.get()));
|
||||
|
||||
ret = HexToBIGNUM(&bn, "-42");
|
||||
EXPECT_EQ(3, ret);
|
||||
ASSERT_EQ(3, ret);
|
||||
EXPECT_TRUE(BN_abs_is_word(bn.get(), 0x42));
|
||||
EXPECT_TRUE(BN_is_negative(bn.get()));
|
||||
|
||||
ret = HexToBIGNUM(&bn, "-0");
|
||||
EXPECT_EQ(2, ret);
|
||||
ASSERT_EQ(2, ret);
|
||||
EXPECT_TRUE(BN_is_zero(bn.get()));
|
||||
EXPECT_FALSE(BN_is_negative(bn.get()));
|
||||
|
||||
ret = HexToBIGNUM(&bn, "abctrailing garbage is ignored");
|
||||
EXPECT_EQ(3, ret);
|
||||
ASSERT_EQ(3, ret);
|
||||
EXPECT_TRUE(BN_is_word(bn.get(), 0xabc));
|
||||
EXPECT_FALSE(BN_is_negative(bn.get()));
|
||||
}
|
||||
@@ -1000,16 +1139,11 @@ static const ASN1InvalidTest kASN1InvalidTests[] = {
|
||||
{"\x03\x01\x00", 3},
|
||||
// Empty contents.
|
||||
{"\x02\x00", 2},
|
||||
};
|
||||
|
||||
// kASN1BuggyTests contains incorrect encodings and the corresponding, expected
|
||||
// results of |BN_parse_asn1_unsigned_buggy| given that input.
|
||||
static const ASN1Test kASN1BuggyTests[] = {
|
||||
// Negative numbers.
|
||||
{"128", "\x02\x01\x80", 3},
|
||||
{"255", "\x02\x01\xff", 3},
|
||||
{"\x02\x01\x80", 3},
|
||||
{"\x02\x01\xff", 3},
|
||||
// Unnecessary leading zeros.
|
||||
{"1", "\x02\x02\x00\x01", 4},
|
||||
{"\x02\x02\x00\x01", 4},
|
||||
};
|
||||
|
||||
TEST_F(BNTest, ASN1) {
|
||||
@@ -1036,12 +1170,6 @@ TEST_F(BNTest, ASN1) {
|
||||
ASSERT_TRUE(CBB_finish(cbb.get(), &der, &der_len));
|
||||
bssl::UniquePtr<uint8_t> delete_der(der);
|
||||
EXPECT_EQ(Bytes(test.der, test.der_len), Bytes(der, der_len));
|
||||
|
||||
// |BN_parse_asn1_unsigned_buggy| parses all valid input.
|
||||
CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len);
|
||||
ASSERT_TRUE(BN_parse_asn1_unsigned_buggy(&cbs, bn2.get()));
|
||||
EXPECT_EQ(0u, CBS_len(&cbs));
|
||||
EXPECT_BIGNUMS_EQUAL("decode ASN.1 buggy", bn.get(), bn2.get());
|
||||
}
|
||||
|
||||
for (const ASN1InvalidTest &test : kASN1InvalidTests) {
|
||||
@@ -1053,35 +1181,6 @@ TEST_F(BNTest, ASN1) {
|
||||
EXPECT_FALSE(BN_parse_asn1_unsigned(&cbs, bn.get()))
|
||||
<< "Parsed invalid input.";
|
||||
ERR_clear_error();
|
||||
|
||||
// All tests in kASN1InvalidTests are also rejected by
|
||||
// |BN_parse_asn1_unsigned_buggy|.
|
||||
CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len);
|
||||
EXPECT_FALSE(BN_parse_asn1_unsigned_buggy(&cbs, bn.get()))
|
||||
<< "Parsed invalid input.";
|
||||
ERR_clear_error();
|
||||
}
|
||||
|
||||
for (const ASN1Test &test : kASN1BuggyTests) {
|
||||
SCOPED_TRACE(Bytes(test.der, test.der_len));
|
||||
|
||||
// These broken encodings are rejected by |BN_parse_asn1_unsigned|.
|
||||
bssl::UniquePtr<BIGNUM> bn(BN_new());
|
||||
ASSERT_TRUE(bn);
|
||||
CBS cbs;
|
||||
CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len);
|
||||
EXPECT_FALSE(BN_parse_asn1_unsigned(&cbs, bn.get()))
|
||||
<< "Parsed invalid input.";
|
||||
ERR_clear_error();
|
||||
|
||||
// However |BN_parse_asn1_unsigned_buggy| accepts them.
|
||||
bssl::UniquePtr<BIGNUM> bn2 = ASCIIToBIGNUM(test.value_ascii);
|
||||
ASSERT_TRUE(bn2);
|
||||
|
||||
CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len);
|
||||
ASSERT_TRUE(BN_parse_asn1_unsigned_buggy(&cbs, bn.get()));
|
||||
EXPECT_EQ(0u, CBS_len(&cbs));
|
||||
EXPECT_BIGNUMS_EQUAL("decode ASN.1 buggy", bn2.get(), bn.get());
|
||||
}
|
||||
|
||||
// Serializing negative numbers is not supported.
|
||||
@@ -1658,3 +1757,94 @@ TEST_F(BNTest, PrimeChecking) {
|
||||
nullptr /* callback */));
|
||||
EXPECT_EQ(0, is_probably_prime_2);
|
||||
}
|
||||
|
||||
#if !defined(BORINGSSL_SHARED_LIBRARY)
|
||||
TEST_F(BNTest, LessThanWords) {
|
||||
// kTestVectors is an array of 256-bit values in sorted order.
|
||||
static const BN_ULONG kTestVectors[][256 / BN_BITS2] = {
|
||||
{TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000),
|
||||
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
|
||||
{TOBN(0x00000000, 0x00000001), TOBN(0x00000000, 0x00000000),
|
||||
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
|
||||
{TOBN(0x00000000, 0x00000002), TOBN(0x00000000, 0x00000000),
|
||||
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
|
||||
{TOBN(0x00000000, 0x0000ffff), TOBN(0x00000000, 0x00000000),
|
||||
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
|
||||
{TOBN(0x00000000, 0x83339914), TOBN(0x00000000, 0x00000000),
|
||||
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
|
||||
{TOBN(0x00000000, 0xfffffffe), TOBN(0x00000000, 0x00000000),
|
||||
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
|
||||
{TOBN(0x00000000, 0xffffffff), TOBN(0x00000000, 0x00000000),
|
||||
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
|
||||
{TOBN(0xed17ac85, 0x83339914), TOBN(0x00000000, 0x00000000),
|
||||
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
|
||||
{TOBN(0xffffffff, 0xffffffff), TOBN(0x00000000, 0x00000000),
|
||||
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
|
||||
{TOBN(0x00000000, 0x83339914), TOBN(0x00000000, 0x00000001),
|
||||
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
|
||||
{TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff),
|
||||
TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000)},
|
||||
{TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff),
|
||||
TOBN(0xffffffff, 0xffffffff), TOBN(0x00000000, 0x00000000)},
|
||||
{TOBN(0x00000000, 0x00000000), TOBN(0x1d6f60ba, 0x893ba84c),
|
||||
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
|
||||
{TOBN(0x00000000, 0x83339915), TOBN(0x1d6f60ba, 0x893ba84c),
|
||||
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
|
||||
{TOBN(0xed17ac85, 0x00000000), TOBN(0x1d6f60ba, 0x893ba84c),
|
||||
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
|
||||
{TOBN(0xed17ac85, 0x83339915), TOBN(0x1d6f60ba, 0x893ba84c),
|
||||
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
|
||||
{TOBN(0xed17ac85, 0xffffffff), TOBN(0x1d6f60ba, 0x893ba84c),
|
||||
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
|
||||
{TOBN(0xffffffff, 0x83339915), TOBN(0x1d6f60ba, 0x893ba84c),
|
||||
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
|
||||
{TOBN(0xffffffff, 0xffffffff), TOBN(0x1d6f60ba, 0x893ba84c),
|
||||
TOBN(0x597d89b3, 0x754abe9f), TOBN(0xb504f333, 0xf9de6484)},
|
||||
{TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000),
|
||||
TOBN(0x00000000, 0x00000000), TOBN(0xffffffff, 0xffffffff)},
|
||||
{TOBN(0x00000000, 0x00000000), TOBN(0x00000000, 0x00000000),
|
||||
TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff)},
|
||||
{TOBN(0x00000000, 0x00000001), TOBN(0x00000000, 0x00000000),
|
||||
TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff)},
|
||||
{TOBN(0x00000000, 0x00000000), TOBN(0xffffffff, 0xffffffff),
|
||||
TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff)},
|
||||
{TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff),
|
||||
TOBN(0xffffffff, 0xffffffff), TOBN(0xffffffff, 0xffffffff)},
|
||||
};
|
||||
|
||||
// Determine where the single-word values stop.
|
||||
size_t one_word;
|
||||
for (one_word = 0; one_word < OPENSSL_ARRAY_SIZE(kTestVectors); one_word++) {
|
||||
int is_word = 1;
|
||||
for (size_t i = 1; i < OPENSSL_ARRAY_SIZE(kTestVectors[one_word]); i++) {
|
||||
if (kTestVectors[one_word][i] != 0) {
|
||||
is_word = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!is_word) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kTestVectors); i++) {
|
||||
SCOPED_TRACE(i);
|
||||
for (size_t j = 0; j < OPENSSL_ARRAY_SIZE(kTestVectors); j++) {
|
||||
SCOPED_TRACE(j);
|
||||
EXPECT_EQ(i < j ? 1 : 0,
|
||||
bn_less_than_words(kTestVectors[i], kTestVectors[j],
|
||||
OPENSSL_ARRAY_SIZE(kTestVectors[i])));
|
||||
for (size_t k = 0; k < one_word; k++) {
|
||||
SCOPED_TRACE(k);
|
||||
EXPECT_EQ(k <= i && i < j ? 1 : 0,
|
||||
bn_in_range_words(kTestVectors[i], kTestVectors[k][0],
|
||||
kTestVectors[j],
|
||||
OPENSSL_ARRAY_SIZE(kTestVectors[i])));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(0, bn_less_than_words(NULL, NULL, 0));
|
||||
EXPECT_EQ(0, bn_in_range_words(NULL, 0, NULL, 0));
|
||||
}
|
||||
#endif // !BORINGSSL_SHARED_LIBRARY
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
// Copyright (c) 2017, 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type test struct {
|
||||
LineNumber int
|
||||
Type string
|
||||
Values map[string]*big.Int
|
||||
}
|
||||
|
||||
type testScanner struct {
|
||||
scanner *bufio.Scanner
|
||||
lineNo int
|
||||
err error
|
||||
test test
|
||||
}
|
||||
|
||||
func newTestScanner(r io.Reader) *testScanner {
|
||||
return &testScanner{scanner: bufio.NewScanner(r)}
|
||||
}
|
||||
|
||||
func (s *testScanner) scanLine() bool {
|
||||
if !s.scanner.Scan() {
|
||||
return false
|
||||
}
|
||||
s.lineNo++
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *testScanner) addAttribute(line string) (key string, ok bool) {
|
||||
fields := strings.SplitN(line, "=", 2)
|
||||
if len(fields) != 2 {
|
||||
s.setError(errors.New("invalid syntax"))
|
||||
return "", false
|
||||
}
|
||||
|
||||
key = strings.TrimSpace(fields[0])
|
||||
value := strings.TrimSpace(fields[1])
|
||||
|
||||
valueInt, ok := new(big.Int).SetString(value, 16)
|
||||
if !ok {
|
||||
s.setError(fmt.Errorf("could not parse %q", value))
|
||||
return "", false
|
||||
}
|
||||
if _, dup := s.test.Values[key]; dup {
|
||||
s.setError(fmt.Errorf("duplicate key %q", key))
|
||||
return "", false
|
||||
}
|
||||
s.test.Values[key] = valueInt
|
||||
return key, true
|
||||
}
|
||||
|
||||
func (s *testScanner) Scan() bool {
|
||||
s.test = test{
|
||||
Values: make(map[string]*big.Int),
|
||||
}
|
||||
|
||||
// Scan until the first attribute.
|
||||
for {
|
||||
if !s.scanLine() {
|
||||
return false
|
||||
}
|
||||
if len(s.scanner.Text()) != 0 && s.scanner.Text()[0] != '#' {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var ok bool
|
||||
s.test.Type, ok = s.addAttribute(s.scanner.Text())
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
s.test.LineNumber = s.lineNo
|
||||
|
||||
for s.scanLine() {
|
||||
if len(s.scanner.Text()) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if s.scanner.Text()[0] == '#' {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := s.addAttribute(s.scanner.Text()); !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return s.scanner.Err() == nil
|
||||
}
|
||||
|
||||
func (s *testScanner) Test() test {
|
||||
return s.test
|
||||
}
|
||||
|
||||
func (s *testScanner) Err() error {
|
||||
if s.err != nil {
|
||||
return s.err
|
||||
}
|
||||
return s.scanner.Err()
|
||||
}
|
||||
|
||||
func (s *testScanner) setError(err error) {
|
||||
s.err = fmt.Errorf("line %d: %s", s.lineNo, err)
|
||||
}
|
||||
|
||||
func checkKeys(t test, keys ...string) bool {
|
||||
var foundErrors bool
|
||||
|
||||
for _, k := range keys {
|
||||
if _, ok := t.Values[k]; !ok {
|
||||
fmt.Fprintf(os.Stderr, "Line %d: missing key %q.\n", t.LineNumber, k)
|
||||
foundErrors = true
|
||||
}
|
||||
}
|
||||
|
||||
for k, _ := range t.Values {
|
||||
var found bool
|
||||
for _, k2 := range keys {
|
||||
if k == k2 {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
fmt.Fprintf(os.Stderr, "Line %d: unexpected key %q.\n", t.LineNumber, k)
|
||||
foundErrors = true
|
||||
}
|
||||
}
|
||||
|
||||
return !foundErrors
|
||||
}
|
||||
|
||||
func appendLengthPrefixed(ret, b []byte) []byte {
|
||||
ret = append(ret, byte(len(b)>>8), byte(len(b)))
|
||||
ret = append(ret, b...)
|
||||
return ret
|
||||
}
|
||||
|
||||
func appendUnsigned(ret []byte, n *big.Int) []byte {
|
||||
b := n.Bytes()
|
||||
if n.Sign() == 0 {
|
||||
b = []byte{0}
|
||||
}
|
||||
return appendLengthPrefixed(ret, b)
|
||||
}
|
||||
|
||||
func appendSigned(ret []byte, n *big.Int) []byte {
|
||||
var sign byte
|
||||
if n.Sign() < 0 {
|
||||
sign = 1
|
||||
}
|
||||
b := []byte{sign}
|
||||
b = append(b, n.Bytes()...)
|
||||
if n.Sign() == 0 {
|
||||
b = append(b, 0)
|
||||
}
|
||||
return appendLengthPrefixed(ret, b)
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) != 3 {
|
||||
fmt.Fprintf(os.Stderr, "Usage: %s TESTS FUZZ_DIR\n", os.Args[0])
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
in, err := os.Open(os.Args[1])
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error opening %s: %s.\n", os.Args[0], err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer in.Close()
|
||||
|
||||
fuzzerDir := os.Args[2]
|
||||
|
||||
scanner := newTestScanner(in)
|
||||
for scanner.Scan() {
|
||||
var fuzzer string
|
||||
var b []byte
|
||||
test := scanner.Test()
|
||||
switch test.Type {
|
||||
case "Quotient":
|
||||
if checkKeys(test, "A", "B", "Quotient", "Remainder") {
|
||||
fuzzer = "bn_div"
|
||||
b = appendSigned(b, test.Values["A"])
|
||||
b = appendSigned(b, test.Values["B"])
|
||||
}
|
||||
case "ModExp":
|
||||
if checkKeys(test, "A", "E", "M", "ModExp") {
|
||||
fuzzer = "bn_mod_exp"
|
||||
b = appendSigned(b, test.Values["A"])
|
||||
b = appendUnsigned(b, test.Values["E"])
|
||||
b = appendUnsigned(b, test.Values["M"])
|
||||
}
|
||||
}
|
||||
|
||||
if len(fuzzer) != 0 {
|
||||
hash := sha1.Sum(b)
|
||||
path := filepath.Join(fuzzerDir, fuzzer + "_corpus", hex.EncodeToString(hash[:]))
|
||||
if err := ioutil.WriteFile(path, b, 0666); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error writing to %s: %s.\n", path, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
if scanner.Err() != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error reading tests: %s.\n", scanner.Err())
|
||||
}
|
||||
}
|
||||
@@ -5349,6 +5349,12 @@ A = -e53ad05c88568f09f616797f0b7f2756fb543d691ec2a5b645c1e5892a247302826419a35b1
|
||||
Square = eea8028b26e0df090504d54da714a6f5f2695202e53cff479c78aedd47a8dc676243ec586740fde53b3eca9ca02b91031ce766242184109503fbe25b1b6d318e3cd5970fabd16dfa22984dd2e9f1e0f14c189170fc69c031d66663703e6235a942d51a4545bd7b0769d01d302ce2b00b83f01568a1e378f61fd0ca6201b0490330580cd9de85719e174a71915d7efbf65cd73d8f4e66f27e0dd3144d58ec09ed0f7ed7d1238ee596922807100fb7a11127944ddcdec6a9ca3bbf6df7301e354f3f049bfb7c275b43c3d8cda5907a932fba507c9145ea3166081c1b48fcc710ee32cd931f936c796b14f8a78a592e67753a7c9e428a01719c8ba82652f3a89fae110
|
||||
A = -3dcb44be1e54c5a5d7db48055ca9afa1ebe2ae648aa6e16ac497502a7deee09ffa124720fad0ab163ce8b3ea6a90f110ea52b67dbc424d0cf1e8c9726dfd9e45bebcefaa5cd5706edeed27896525f31c6bbea3d67ee97badefabf3e2532470b66e3ae3100f66ddf50cf02fc3a8e3f44c304251d3b6a7ca3a6e4bd5d16a41bd97a4
|
||||
|
||||
Square = 0
|
||||
A = 0
|
||||
|
||||
Square = 1
|
||||
A = 1
|
||||
|
||||
|
||||
# Product tests.
|
||||
#
|
||||
@@ -5954,6 +5960,22 @@ Product = -366c125f96b38b58d01c939c27c4100af3377eabb792b5491a
|
||||
A = a57da276998c548101f514e9f
|
||||
B = -542fb814f45924aa09a16f2a6
|
||||
|
||||
Product = 0
|
||||
A = 0
|
||||
B = 542fb814f45924aa09a16f2a6
|
||||
|
||||
Product = 0
|
||||
A = 542fb814f45924aa09a16f2a6
|
||||
B = 0
|
||||
|
||||
Product = 542fb814f45924aa09a16f2a6
|
||||
A = 1
|
||||
B = 542fb814f45924aa09a16f2a6
|
||||
|
||||
Product = 542fb814f45924aa09a16f2a6
|
||||
A = 542fb814f45924aa09a16f2a6
|
||||
B = 1
|
||||
|
||||
|
||||
# Quotient tests.
|
||||
#
|
||||
@@ -9897,6 +9919,12 @@ ModSquare = fffffffdfffffd01000009000002f6fffdf403000312000402f3fff5f602fe080a00
|
||||
A = ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff00000000
|
||||
M = ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff
|
||||
|
||||
# Regression test for CVE-2017-3736.
|
||||
ModSquare = fe06fe0b06160c09
|
||||
A = fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f8f8f800000000000010000000006c000000000000000000000000000000000000000000000000000000000000000000000000000000000000fffffffffffff8f8f8f800000000000010000000006c000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffffffff00fcfdfc
|
||||
# A in Montgomery form is fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8ffeadbcfc4dae7fff908e92820306b9544d954000000006c000000000000000000000000000000000000000000000000000000000000000000ff030202fffff8ffebdbcfc4dae7fff908e92820306b9544d954000000006c000000ff0302030000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01fc00ff02ffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff00fcfdfcffffffffff000000000000000000ff0302030000000000ffffffffffffffffff00fcfdfdff030202ff00000000ffffffffffffffffff00fcfdfcffffffffff
|
||||
M = fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f8f8f800000000000010000000006c000000000000000000000000000000000000000000000000000000000000000000000000000000000000fffffffffffff8f8f8f800000000000010000000006c000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffffffff
|
||||
|
||||
|
||||
# ModExp tests.
|
||||
#
|
||||
@@ -10479,6 +10507,12 @@ A = -80000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
E = 61803d4973ae68cfb2ba6770dbed70d36760fa42c01a16d1482eacf0d01adf7a917bc86ece58a73b920295c1291b90f49167ef856ecad149330e1fd49ec71392fb62d47270b53e6d4f3c8f044b80a5736753364896932abc6d872c4c5e135d1edb200597a93ceb262ff6c99079177cd10808b9ed20c8cd7352d80ac7f6963103
|
||||
M = b5d257b2c50b050d42f0852eff5cfa2571157c500cd0bd9aa0b2ccdd89c531c9609d520eb81d928fb52b06da25dc713561aa0bd365ee56db9e62ac6787a85936990f44438363560f7af9e0c16f378e5b83f658252390d849401817624da97ec613a1b855fd901847352f434a777e4e32af0cb4033c7547fb6437d067fcd3d965
|
||||
|
||||
# Regression test for CVE-2017-3738.
|
||||
ModExp = d360792bd8210786607817c3dda64cc38c8d0f25569597cb1f363c7919a0c3587baff01a2283edaeb04fc288ac0ab3f279b2a89ffcb452d8bdf72422a9f9780f4aa702dc964cf033149d3a339883062cab8564aebdbfac0bf68985e522c6fe545b346044690c525ca85d3f4eb3e3c25cdf541545afc84a309e9b1d7807003461
|
||||
A = ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2020202020df
|
||||
E = 2020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020FF2020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020
|
||||
M = ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2020202020ff
|
||||
|
||||
|
||||
# Exp tests.
|
||||
#
|
||||
|
||||
@@ -57,8 +57,10 @@
|
||||
#include <openssl/bn.h>
|
||||
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/type_check.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "../../internal.h"
|
||||
|
||||
|
||||
int BN_ucmp(const BIGNUM *a, const BIGNUM *b) {
|
||||
@@ -174,6 +176,19 @@ int bn_cmp_part_words(const BN_ULONG *a, const BN_ULONG *b, int cl, int dl) {
|
||||
return bn_cmp_words(a, b, cl);
|
||||
}
|
||||
|
||||
int bn_less_than_words(const BN_ULONG *a, const BN_ULONG *b, size_t len) {
|
||||
OPENSSL_COMPILE_ASSERT(sizeof(BN_ULONG) <= sizeof(crypto_word_t),
|
||||
crypto_word_t_too_small);
|
||||
int ret = 0;
|
||||
// Process the words in little-endian order.
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
crypto_word_t eq = constant_time_eq_w(a[i], b[i]);
|
||||
crypto_word_t lt = constant_time_lt_w(a[i], b[i]);
|
||||
ret = constant_time_select_int(eq, ret, constant_time_select_int(lt, 1, 0));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int BN_abs_is_word(const BIGNUM *bn, BN_ULONG w) {
|
||||
switch (bn->top) {
|
||||
case 1:
|
||||
|
||||
+53
-46
@@ -128,7 +128,7 @@ static BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d) {
|
||||
}
|
||||
|
||||
ret = q << BN_BITS4;
|
||||
h = ((h << BN_BITS4) | (l >> BN_BITS4)) & BN_MASK2;
|
||||
h = (h << BN_BITS4) | (l >> BN_BITS4);
|
||||
l = (l & BN_MASK2l) << BN_BITS4;
|
||||
}
|
||||
|
||||
@@ -178,28 +178,33 @@ static inline void bn_div_rem_words(BN_ULONG *quotient_out, BN_ULONG *rem_out,
|
||||
#endif
|
||||
}
|
||||
|
||||
// BN_div computes dv := num / divisor, rounding towards
|
||||
// zero, and sets up rm such that dv*divisor + rm = num holds.
|
||||
// BN_div computes "quotient := numerator / divisor", rounding towards zero,
|
||||
// and sets up |rem| such that "quotient * divisor + rem = numerator" 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.
|
||||
//
|
||||
// quotient->neg == numerator->neg ^ divisor->neg
|
||||
// (unless the result is zero)
|
||||
// rem->neg == numerator->neg
|
||||
// (unless the remainder is zero)
|
||||
//
|
||||
// If |quotient| or |rem| is NULL, the respective value is not returned.
|
||||
//
|
||||
// This was specifically designed to contain fewer branches that may leak
|
||||
// sensitive information; see "New Branch Prediction Vulnerabilities in OpenSSL
|
||||
// and Necessary Software Countermeasures" by Onur Acıçmez, Shay Gueron, and
|
||||
// Jean-Pierre Seifert.
|
||||
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;
|
||||
int BN_div(BIGNUM *quotient, BIGNUM *rem, const BIGNUM *numerator,
|
||||
const BIGNUM *divisor, BN_CTX *ctx) {
|
||||
int norm_shift, loop;
|
||||
BIGNUM wnum;
|
||||
BN_ULONG *resp, *wnump;
|
||||
BN_ULONG d0, d1;
|
||||
int num_n, div_n;
|
||||
|
||||
// Invalid zero-padding would have particularly bad consequences
|
||||
// so don't just rely on bn_check_top() here
|
||||
if ((num->top > 0 && num->d[num->top - 1] == 0) ||
|
||||
if ((numerator->top > 0 && numerator->d[numerator->top - 1] == 0) ||
|
||||
(divisor->top > 0 && divisor->d[divisor->top - 1] == 0)) {
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_NOT_INITIALIZED);
|
||||
return 0;
|
||||
@@ -211,26 +216,27 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
|
||||
}
|
||||
|
||||
BN_CTX_start(ctx);
|
||||
tmp = BN_CTX_get(ctx);
|
||||
snum = BN_CTX_get(ctx);
|
||||
sdiv = BN_CTX_get(ctx);
|
||||
if (dv == NULL) {
|
||||
BIGNUM *tmp = BN_CTX_get(ctx);
|
||||
BIGNUM *snum = BN_CTX_get(ctx);
|
||||
BIGNUM *sdiv = BN_CTX_get(ctx);
|
||||
BIGNUM *res = NULL;
|
||||
if (quotient == NULL) {
|
||||
res = BN_CTX_get(ctx);
|
||||
} else {
|
||||
res = dv;
|
||||
res = quotient;
|
||||
}
|
||||
if (sdiv == NULL || res == NULL || tmp == NULL || snum == NULL) {
|
||||
if (sdiv == NULL || res == 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))) {
|
||||
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))) {
|
||||
if (!BN_lshift(snum, numerator, norm_shift)) {
|
||||
goto err;
|
||||
}
|
||||
snum->neg = 0;
|
||||
@@ -242,7 +248,7 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
|
||||
if (!bn_wexpand(snum, sdiv->top + 2)) {
|
||||
goto err;
|
||||
}
|
||||
for (i = snum->top; i < sdiv->top + 2; i++) {
|
||||
for (int i = snum->top; i < sdiv->top + 2; i++) {
|
||||
snum->d[i] = 0;
|
||||
}
|
||||
snum->top = sdiv->top + 2;
|
||||
@@ -275,15 +281,15 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
|
||||
wnump = &(snum->d[num_n - 1]);
|
||||
|
||||
// Setup to 'res'
|
||||
res->neg = (num->neg ^ divisor->neg);
|
||||
if (!bn_wexpand(res, (loop + 1))) {
|
||||
res->neg = (numerator->neg ^ divisor->neg);
|
||||
if (!bn_wexpand(res, loop + 1)) {
|
||||
goto err;
|
||||
}
|
||||
res->top = loop - 1;
|
||||
resp = &(res->d[loop - 1]);
|
||||
|
||||
// space for temp
|
||||
if (!bn_wexpand(tmp, (div_n + 1))) {
|
||||
if (!bn_wexpand(tmp, div_n + 1)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -295,11 +301,11 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
|
||||
resp--;
|
||||
}
|
||||
|
||||
for (i = 0; i < loop - 1; i++, wnump--, resp--) {
|
||||
for (int 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;
|
||||
BN_ULONG n0, n1, rm = 0;
|
||||
|
||||
n0 = wnump[0];
|
||||
n1 = wnump[-1];
|
||||
@@ -307,18 +313,18 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
|
||||
q = BN_MASK2;
|
||||
} else {
|
||||
// n0 < d0
|
||||
bn_div_rem_words(&q, &rem, n0, n1, d0);
|
||||
bn_div_rem_words(&q, &rm, n0, n1, d0);
|
||||
|
||||
#ifdef BN_ULLONG
|
||||
BN_ULLONG t2 = (BN_ULLONG)d1 * q;
|
||||
for (;;) {
|
||||
if (t2 <= ((((BN_ULLONG)rem) << BN_BITS2) | wnump[-2])) {
|
||||
if (t2 <= ((((BN_ULLONG)rm) << BN_BITS2) | wnump[-2])) {
|
||||
break;
|
||||
}
|
||||
q--;
|
||||
rem += d0;
|
||||
if (rem < d0) {
|
||||
break; // don't let rem overflow
|
||||
rm += d0;
|
||||
if (rm < d0) {
|
||||
break; // don't let rm overflow
|
||||
}
|
||||
t2 -= d1;
|
||||
}
|
||||
@@ -326,13 +332,14 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
|
||||
BN_ULONG t2l, t2h;
|
||||
BN_UMULT_LOHI(t2l, t2h, d1, q);
|
||||
for (;;) {
|
||||
if ((t2h < rem) || ((t2h == rem) && (t2l <= wnump[-2]))) {
|
||||
if (t2h < rm ||
|
||||
(t2h == rm && t2l <= wnump[-2])) {
|
||||
break;
|
||||
}
|
||||
q--;
|
||||
rem += d0;
|
||||
if (rem < d0) {
|
||||
break; // don't let rem overflow
|
||||
rm += d0;
|
||||
if (rm < d0) {
|
||||
break; // don't let rm overflow
|
||||
}
|
||||
if (t2l < d1) {
|
||||
t2h--;
|
||||
@@ -363,18 +370,21 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
|
||||
// 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;
|
||||
if (!BN_rshift(rm, snum, norm_shift)) {
|
||||
|
||||
if (rem != NULL) {
|
||||
// Keep a copy of the neg flag in numerator because if |rem| == |numerator|
|
||||
// |BN_rshift| will overwrite it.
|
||||
int neg = numerator->neg;
|
||||
if (!BN_rshift(rem, snum, norm_shift)) {
|
||||
goto err;
|
||||
}
|
||||
if (!BN_is_zero(rm)) {
|
||||
rm->neg = neg;
|
||||
if (!BN_is_zero(rem)) {
|
||||
rem->neg = neg;
|
||||
}
|
||||
}
|
||||
|
||||
bn_correct_top(res);
|
||||
BN_CTX_end(ctx);
|
||||
return 1;
|
||||
@@ -569,8 +579,6 @@ 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;
|
||||
@@ -592,7 +600,7 @@ BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w) {
|
||||
BN_ULONG d;
|
||||
BN_ULONG unused_rem;
|
||||
bn_div_rem_words(&d, &unused_rem, ret, l, w);
|
||||
ret = (l - ((d * w) & BN_MASK2)) & BN_MASK2;
|
||||
ret = l - (d * w);
|
||||
a->d[i] = d;
|
||||
}
|
||||
|
||||
@@ -634,7 +642,6 @@ BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w) {
|
||||
}
|
||||
#endif
|
||||
|
||||
w &= BN_MASK2;
|
||||
for (i = a->top - 1; i >= 0; i--) {
|
||||
#ifndef BN_ULLONG
|
||||
ret = ((ret << BN_BITS4) | ((a->d[i] >> BN_BITS4) & BN_MASK2l)) % w;
|
||||
|
||||
@@ -188,9 +188,6 @@ err:
|
||||
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
|
||||
@@ -393,8 +390,8 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
// BN_window_bits_for_exponent_size -- macro for sliding window mod_exp
|
||||
// functions
|
||||
// BN_window_bits_for_exponent_size returns sliding window size for mod_exp with
|
||||
// a |b| bit exponent.
|
||||
//
|
||||
// For window size 'w' (w >= 2) and a random 'b' bits exponent, the number of
|
||||
// multiplications is a constant plus on average
|
||||
@@ -416,11 +413,35 @@ err:
|
||||
//
|
||||
// (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 BN_window_bits_for_exponent_size(int b) {
|
||||
if (b > 671) {
|
||||
return 6;
|
||||
}
|
||||
if (b > 239) {
|
||||
return 5;
|
||||
}
|
||||
if (b > 79) {
|
||||
return 4;
|
||||
}
|
||||
if (b > 23) {
|
||||
return 3;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// TABLE_SIZE is the maximum precomputation table size for *variable* sliding
|
||||
// windows. This must be 2^(max_window - 1), where max_window is the largest
|
||||
// value returned from |BN_window_bits_for_exponent_size|.
|
||||
#define TABLE_SIZE 32
|
||||
|
||||
// TABLE_BITS_SMALL is the smallest value returned from
|
||||
// |BN_window_bits_for_exponent_size| when |b| is at most |BN_BITS2| *
|
||||
// |BN_SMALL_MAX_WORDS| words.
|
||||
#define TABLE_BITS_SMALL 5
|
||||
|
||||
// TABLE_SIZE_SMALL is the same as |TABLE_SIZE|, but when |b| is at most
|
||||
// |BN_BITS2| * |BN_SMALL_MAX_WORDS|.
|
||||
#define TABLE_SIZE_SMALL (1 << (TABLE_BITS_SMALL - 1))
|
||||
|
||||
static int mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
|
||||
const BIGNUM *m, BN_CTX *ctx) {
|
||||
@@ -501,7 +522,7 @@ static int mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
|
||||
int wvalue; // The 'value' of the window
|
||||
int wend; // The bottom bit of the window
|
||||
|
||||
if (BN_is_bit_set(p, wstart) == 0) {
|
||||
if (!BN_is_bit_set(p, wstart)) {
|
||||
if (!start) {
|
||||
if (!BN_mod_mul_reciprocal(r, r, r, &recp, ctx)) {
|
||||
goto err;
|
||||
@@ -573,19 +594,11 @@ int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m,
|
||||
|
||||
int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
|
||||
const BIGNUM *m, BN_CTX *ctx, const BN_MONT_CTX *mont) {
|
||||
int i, j, bits, ret = 0, wstart, window;
|
||||
int start = 1;
|
||||
BIGNUM *d, *r;
|
||||
const BIGNUM *aa;
|
||||
// Table of variables obtained from 'ctx'
|
||||
BIGNUM *val[TABLE_SIZE];
|
||||
BN_MONT_CTX *new_mont = NULL;
|
||||
|
||||
if (!BN_is_odd(m)) {
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS);
|
||||
return 0;
|
||||
}
|
||||
bits = BN_num_bits(p);
|
||||
int bits = BN_num_bits(p);
|
||||
if (bits == 0) {
|
||||
// x**0 mod 1 is still zero.
|
||||
if (BN_is_one(m)) {
|
||||
@@ -595,9 +608,13 @@ int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
|
||||
return BN_one(rr);
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
BIGNUM *val[TABLE_SIZE];
|
||||
BN_MONT_CTX *new_mont = NULL;
|
||||
|
||||
BN_CTX_start(ctx);
|
||||
d = BN_CTX_get(ctx);
|
||||
r = BN_CTX_get(ctx);
|
||||
BIGNUM *d = BN_CTX_get(ctx);
|
||||
BIGNUM *r = BN_CTX_get(ctx);
|
||||
val[0] = BN_CTX_get(ctx);
|
||||
if (!d || !r || !val[0]) {
|
||||
goto err;
|
||||
@@ -612,6 +629,7 @@ int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
|
||||
mont = new_mont;
|
||||
}
|
||||
|
||||
const BIGNUM *aa;
|
||||
if (a->neg || BN_ucmp(a, m) >= 0) {
|
||||
if (!BN_nnmod(val[0], a, m, ctx)) {
|
||||
goto err;
|
||||
@@ -626,53 +644,52 @@ int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
|
||||
ret = 1;
|
||||
goto err;
|
||||
}
|
||||
if (!BN_to_montgomery(val[0], aa, mont, ctx)) {
|
||||
goto err; // 1
|
||||
}
|
||||
|
||||
window = BN_window_bits_for_exponent_size(bits);
|
||||
// We exponentiate by looking at sliding windows of the exponent and
|
||||
// precomputing powers of |aa|. Windows may be shifted so they always end on a
|
||||
// set bit, so only precompute odd powers. We compute val[i] = aa^(2*i + 1)
|
||||
// for i = 0 to 2^(window-1), all in Montgomery form.
|
||||
int window = BN_window_bits_for_exponent_size(bits);
|
||||
if (!BN_to_montgomery(val[0], aa, mont, ctx)) {
|
||||
goto err;
|
||||
}
|
||||
if (window > 1) {
|
||||
if (!BN_mod_mul_montgomery(d, val[0], val[0], mont, ctx)) {
|
||||
goto err; // 2
|
||||
goto err;
|
||||
}
|
||||
j = 1 << (window - 1);
|
||||
for (i = 1; i < j; i++) {
|
||||
if (((val[i] = BN_CTX_get(ctx)) == NULL) ||
|
||||
for (int i = 1; i < 1 << (window - 1); i++) {
|
||||
val[i] = BN_CTX_get(ctx);
|
||||
if (val[i] == 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.
|
||||
wstart = bits - 1; // The top 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)) {
|
||||
// Set |r| to one in Montgomery form. If the high bit of |m| is set, |m| is
|
||||
// close to R and we subtract rather than perform Montgomery reduction.
|
||||
if (m->d[m->top - 1] & (((BN_ULONG)1) << (BN_BITS2 - 1))) {
|
||||
if (!bn_wexpand(r, m->top)) {
|
||||
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 = 2^(top*BN_BITS2) - m
|
||||
r->d[0] = 0 - m->d[0];
|
||||
for (int i = 1; i < m->top; i++) {
|
||||
r->d[i] = ~m->d[i];
|
||||
}
|
||||
r->top = j;
|
||||
// Upper words will be zero if the corresponding words of 'm'
|
||||
// were 0xfff[...], so decrement r->top accordingly.
|
||||
r->top = m->top;
|
||||
// The upper words will be zero if the corresponding words of |m| were
|
||||
// 0xfff[...], so call |bn_correct_top|.
|
||||
bn_correct_top(r);
|
||||
} else if (!BN_to_montgomery(r, BN_value_one(), mont, ctx)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
int r_is_one = 1;
|
||||
int wstart = bits - 1; // The top bit of the window.
|
||||
for (;;) {
|
||||
int wvalue; // The 'value' of the window
|
||||
int wend; // The bottom bit of the window
|
||||
|
||||
if (BN_is_bit_set(p, wstart) == 0) {
|
||||
if (!start && !BN_mod_mul_montgomery(r, r, r, mont, ctx)) {
|
||||
if (!BN_is_bit_set(p, wstart)) {
|
||||
if (!r_is_one && !BN_mod_mul_montgomery(r, r, r, mont, ctx)) {
|
||||
goto err;
|
||||
}
|
||||
if (wstart == 0) {
|
||||
@@ -682,44 +699,37 @@ int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
|
||||
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
|
||||
wvalue = 1;
|
||||
wend = 0;
|
||||
for (i = 1; i < window; i++) {
|
||||
if (wstart - i < 0) {
|
||||
break;
|
||||
}
|
||||
// We now have wstart on a set bit. Find the largest window we can use.
|
||||
int wvalue = 1;
|
||||
int wsize = 0;
|
||||
for (int i = 1; i < window && i <= wstart; i++) {
|
||||
if (BN_is_bit_set(p, wstart - i)) {
|
||||
wvalue <<= (i - wend);
|
||||
wvalue <<= (i - wsize);
|
||||
wvalue |= 1;
|
||||
wend = i;
|
||||
wsize = i;
|
||||
}
|
||||
}
|
||||
|
||||
// wend is the size of the current window
|
||||
j = wend + 1;
|
||||
// add the 'bytes above'
|
||||
if (!start) {
|
||||
for (i = 0; i < j; i++) {
|
||||
// Shift |r| to the end of the window.
|
||||
if (!r_is_one) {
|
||||
for (int i = 0; i < wsize + 1; i++) {
|
||||
if (!BN_mod_mul_montgomery(r, r, r, mont, ctx)) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// wvalue will be an odd number < 2^window
|
||||
assert(wvalue & 1);
|
||||
assert(wvalue < (1 << window));
|
||||
if (!BN_mod_mul_montgomery(r, r, val[wvalue >> 1], mont, ctx)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
// move the 'window' down further
|
||||
wstart -= wend + 1;
|
||||
start = 0;
|
||||
if (wstart < 0) {
|
||||
r_is_one = 0;
|
||||
if (wstart == wsize) {
|
||||
break;
|
||||
}
|
||||
wstart -= wsize + 1;
|
||||
}
|
||||
|
||||
if (!BN_from_montgomery(rr, r, mont, ctx)) {
|
||||
@@ -733,12 +743,160 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
// BN_mod_exp_mont_consttime() stores the precomputed powers in a specific
|
||||
int bn_mod_exp_mont_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
|
||||
size_t num_a, const BN_ULONG *p, size_t num_p,
|
||||
const BN_MONT_CTX *mont) {
|
||||
const BN_ULONG *n = mont->N.d;
|
||||
size_t num_n = mont->N.top;
|
||||
if (num_n != num_a || num_n != num_r || num_n > BN_SMALL_MAX_WORDS) {
|
||||
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||||
return 0;
|
||||
}
|
||||
if (!BN_is_odd(&mont->N)) {
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS);
|
||||
return 0;
|
||||
}
|
||||
unsigned bits = 0;
|
||||
if (num_p != 0) {
|
||||
bits = BN_num_bits_word(p[num_p - 1]) + (num_p - 1) * BN_BITS2;
|
||||
}
|
||||
if (bits == 0) {
|
||||
OPENSSL_memset(r, 0, num_r * sizeof(BN_ULONG));
|
||||
if (!BN_is_one(&mont->N)) {
|
||||
r[0] = 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// We exponentiate by looking at sliding windows of the exponent and
|
||||
// precomputing powers of |a|. Windows may be shifted so they always end on a
|
||||
// set bit, so only precompute odd powers. We compute val[i] = a^(2*i + 1) for
|
||||
// i = 0 to 2^(window-1), all in Montgomery form.
|
||||
unsigned window = BN_window_bits_for_exponent_size(bits);
|
||||
if (window > TABLE_BITS_SMALL) {
|
||||
window = TABLE_BITS_SMALL; // Tolerate excessively large |p|.
|
||||
}
|
||||
int ret = 0;
|
||||
BN_ULONG val[TABLE_SIZE_SMALL][BN_SMALL_MAX_WORDS];
|
||||
OPENSSL_memcpy(val[0], a, num_n * sizeof(BN_ULONG));
|
||||
if (window > 1) {
|
||||
BN_ULONG d[BN_SMALL_MAX_WORDS];
|
||||
if (!bn_mod_mul_montgomery_small(d, num_n, val[0], num_n, val[0], num_n,
|
||||
mont)) {
|
||||
goto err;
|
||||
}
|
||||
for (unsigned i = 1; i < 1u << (window - 1); i++) {
|
||||
if (!bn_mod_mul_montgomery_small(val[i], num_n, val[i - 1], num_n, d,
|
||||
num_n, mont)) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set |r| to one in Montgomery form. If the high bit of |m| is set, |m| is
|
||||
// close to R and we subtract rather than perform Montgomery reduction.
|
||||
if (n[num_n - 1] & (((BN_ULONG)1) << (BN_BITS2 - 1))) {
|
||||
// r = 2^(top*BN_BITS2) - m
|
||||
r[0] = 0 - n[0];
|
||||
for (size_t i = 1; i < num_n; i++) {
|
||||
r[i] = ~n[i];
|
||||
}
|
||||
} else if (!bn_from_montgomery_small(r, num_r, mont->RR.d, mont->RR.top,
|
||||
mont)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
int r_is_one = 1;
|
||||
unsigned wstart = bits - 1; // The top bit of the window.
|
||||
for (;;) {
|
||||
if (!bn_is_bit_set_words(p, num_p, wstart)) {
|
||||
if (!r_is_one &&
|
||||
!bn_mod_mul_montgomery_small(r, num_r, r, num_r, r, num_r, mont)) {
|
||||
goto err;
|
||||
}
|
||||
if (wstart == 0) {
|
||||
break;
|
||||
}
|
||||
wstart--;
|
||||
continue;
|
||||
}
|
||||
|
||||
// We now have wstart on a set bit. Find the largest window we can use.
|
||||
unsigned wvalue = 1;
|
||||
unsigned wsize = 0;
|
||||
for (unsigned i = 1; i < window && i <= wstart; i++) {
|
||||
if (bn_is_bit_set_words(p, num_p, wstart - i)) {
|
||||
wvalue <<= (i - wsize);
|
||||
wvalue |= 1;
|
||||
wsize = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Shift |r| to the end of the window.
|
||||
if (!r_is_one) {
|
||||
for (unsigned i = 0; i < wsize + 1; i++) {
|
||||
if (!bn_mod_mul_montgomery_small(r, num_r, r, num_r, r, num_r, mont)) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(wvalue & 1);
|
||||
assert(wvalue < (1u << window));
|
||||
if (!bn_mod_mul_montgomery_small(r, num_r, r, num_r, val[wvalue >> 1],
|
||||
num_n, mont)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
r_is_one = 0;
|
||||
if (wstart == wsize) {
|
||||
break;
|
||||
}
|
||||
wstart -= wsize + 1;
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
OPENSSL_cleanse(val, sizeof(val));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bn_mod_inverse_prime_mont_small(BN_ULONG *r, size_t num_r,
|
||||
const BN_ULONG *a, size_t num_a,
|
||||
const BN_MONT_CTX *mont) {
|
||||
const BN_ULONG *p = mont->N.d;
|
||||
size_t num_p = mont->N.top;
|
||||
if (num_p > BN_SMALL_MAX_WORDS || num_p == 0) {
|
||||
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Per Fermat's Little Theorem, a^-1 = a^(p-2) (mod p) for p prime.
|
||||
BN_ULONG p_minus_two[BN_SMALL_MAX_WORDS];
|
||||
OPENSSL_memcpy(p_minus_two, p, num_p * sizeof(BN_ULONG));
|
||||
if (p_minus_two[0] >= 2) {
|
||||
p_minus_two[0] -= 2;
|
||||
} else {
|
||||
p_minus_two[0] -= 2;
|
||||
for (size_t i = 1; i < num_p; i++) {
|
||||
if (p_minus_two[i]-- != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bn_mod_exp_mont_small(r, num_r, a, num_a, p_minus_two, num_p, mont);
|
||||
}
|
||||
|
||||
|
||||
// |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 window) {
|
||||
|
||||
static void copy_to_prebuf(const BIGNUM *b, int top, unsigned char *buf,
|
||||
int idx, int window) {
|
||||
int i, j;
|
||||
const int width = 1 << window;
|
||||
BN_ULONG *table = (BN_ULONG *) buf;
|
||||
@@ -750,8 +908,6 @@ static int copy_to_prebuf(const BIGNUM *b, int top, unsigned char *buf, int idx,
|
||||
for (i = 0, j = idx; i < top; i++, j += width) {
|
||||
table[j] = b->d[i];
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int copy_from_prebuf(BIGNUM *b, int top, unsigned char *buf, int idx,
|
||||
@@ -963,9 +1119,9 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
|
||||
// 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;
|
||||
tmp.d[0] = 0 - m->d[0];
|
||||
for (i = 1; i < top; i++) {
|
||||
tmp.d[i] = (~m->d[i]) & BN_MASK2;
|
||||
tmp.d[i] = ~m->d[i];
|
||||
}
|
||||
tmp.top = top;
|
||||
} else if (!BN_to_montgomery(&tmp, BN_value_one(), mont, ctx)) {
|
||||
@@ -1103,26 +1259,27 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (!copy_to_prebuf(&tmp, top, powerbuf, 0, window) ||
|
||||
!copy_to_prebuf(&am, top, powerbuf, 1, window)) {
|
||||
goto err;
|
||||
}
|
||||
copy_to_prebuf(&tmp, top, powerbuf, 0, window);
|
||||
copy_to_prebuf(&am, top, powerbuf, 1, window);
|
||||
|
||||
// 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) ||
|
||||
!copy_to_prebuf(&tmp, top, powerbuf, 2, window)) {
|
||||
if (!BN_mod_mul_montgomery(&tmp, &am, &am, mont, ctx)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
copy_to_prebuf(&tmp, top, powerbuf, 2, window);
|
||||
|
||||
for (i = 3; i < numPowers; i++) {
|
||||
// Calculate a^i = a^(i-1) * a
|
||||
if (!BN_mod_mul_montgomery(&tmp, &am, &tmp, mont, ctx) ||
|
||||
!copy_to_prebuf(&tmp, top, powerbuf, i, window)) {
|
||||
if (!BN_mod_mul_montgomery(&tmp, &am, &tmp, mont, ctx)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
copy_to_prebuf(&tmp, top, powerbuf, i, window);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1168,10 +1325,7 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
|
||||
err:
|
||||
BN_MONT_CTX_free(new_mont);
|
||||
BN_clear_free(new_a);
|
||||
if (powerbuf != NULL) {
|
||||
OPENSSL_cleanse(powerbuf, powerbufLen);
|
||||
OPENSSL_free(powerbufFree);
|
||||
}
|
||||
OPENSSL_free(powerbufFree);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
@@ -124,12 +124,11 @@
|
||||
|
||||
#endif // !BN_ULLONG
|
||||
|
||||
BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num,
|
||||
BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, size_t num,
|
||||
BN_ULONG w) {
|
||||
BN_ULONG c1 = 0;
|
||||
|
||||
assert(num >= 0);
|
||||
if (num <= 0) {
|
||||
if (num == 0) {
|
||||
return c1;
|
||||
}
|
||||
|
||||
@@ -153,11 +152,11 @@ BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num,
|
||||
return c1;
|
||||
}
|
||||
|
||||
BN_ULONG bn_mul_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, size_t num,
|
||||
BN_ULONG w) {
|
||||
BN_ULONG c1 = 0;
|
||||
|
||||
assert(num >= 0);
|
||||
if (num <= 0) {
|
||||
if (num == 0) {
|
||||
return c1;
|
||||
}
|
||||
|
||||
@@ -179,9 +178,8 @@ BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w) {
|
||||
return c1;
|
||||
}
|
||||
|
||||
void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, int n) {
|
||||
assert(n >= 0);
|
||||
if (n <= 0) {
|
||||
void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, size_t n) {
|
||||
if (n == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -204,26 +202,25 @@ void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, int n) {
|
||||
|
||||
#ifdef BN_ULLONG
|
||||
BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
|
||||
int n) {
|
||||
size_t n) {
|
||||
BN_ULLONG ll = 0;
|
||||
|
||||
assert(n >= 0);
|
||||
if (n <= 0) {
|
||||
return (BN_ULONG)0;
|
||||
if (n == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (n & ~3) {
|
||||
ll += (BN_ULLONG)a[0] + b[0];
|
||||
r[0] = (BN_ULONG)ll & BN_MASK2;
|
||||
r[0] = (BN_ULONG)ll;
|
||||
ll >>= BN_BITS2;
|
||||
ll += (BN_ULLONG)a[1] + b[1];
|
||||
r[1] = (BN_ULONG)ll & BN_MASK2;
|
||||
r[1] = (BN_ULONG)ll;
|
||||
ll >>= BN_BITS2;
|
||||
ll += (BN_ULLONG)a[2] + b[2];
|
||||
r[2] = (BN_ULONG)ll & BN_MASK2;
|
||||
r[2] = (BN_ULONG)ll;
|
||||
ll >>= BN_BITS2;
|
||||
ll += (BN_ULLONG)a[3] + b[3];
|
||||
r[3] = (BN_ULONG)ll & BN_MASK2;
|
||||
r[3] = (BN_ULONG)ll;
|
||||
ll >>= BN_BITS2;
|
||||
a += 4;
|
||||
b += 4;
|
||||
@@ -232,7 +229,7 @@ BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
|
||||
}
|
||||
while (n) {
|
||||
ll += (BN_ULLONG)a[0] + b[0];
|
||||
r[0] = (BN_ULONG)ll & BN_MASK2;
|
||||
r[0] = (BN_ULONG)ll;
|
||||
ll >>= BN_BITS2;
|
||||
a++;
|
||||
b++;
|
||||
@@ -245,38 +242,37 @@ BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
|
||||
#else // !BN_ULLONG
|
||||
|
||||
BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
|
||||
int n) {
|
||||
size_t n) {
|
||||
BN_ULONG c, l, t;
|
||||
|
||||
assert(n >= 0);
|
||||
if (n <= 0) {
|
||||
if (n == 0) {
|
||||
return (BN_ULONG)0;
|
||||
}
|
||||
|
||||
c = 0;
|
||||
while (n & ~3) {
|
||||
t = a[0];
|
||||
t = (t + c) & BN_MASK2;
|
||||
t += c;
|
||||
c = (t < c);
|
||||
l = (t + b[0]) & BN_MASK2;
|
||||
l = t + b[0];
|
||||
c += (l < t);
|
||||
r[0] = l;
|
||||
t = a[1];
|
||||
t = (t + c) & BN_MASK2;
|
||||
t += c;
|
||||
c = (t < c);
|
||||
l = (t + b[1]) & BN_MASK2;
|
||||
l = t + b[1];
|
||||
c += (l < t);
|
||||
r[1] = l;
|
||||
t = a[2];
|
||||
t = (t + c) & BN_MASK2;
|
||||
t += c;
|
||||
c = (t < c);
|
||||
l = (t + b[2]) & BN_MASK2;
|
||||
l = t + b[2];
|
||||
c += (l < t);
|
||||
r[2] = l;
|
||||
t = a[3];
|
||||
t = (t + c) & BN_MASK2;
|
||||
t += c;
|
||||
c = (t < c);
|
||||
l = (t + b[3]) & BN_MASK2;
|
||||
l = t + b[3];
|
||||
c += (l < t);
|
||||
r[3] = l;
|
||||
a += 4;
|
||||
@@ -286,9 +282,9 @@ BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
|
||||
}
|
||||
while (n) {
|
||||
t = a[0];
|
||||
t = (t + c) & BN_MASK2;
|
||||
t += c;
|
||||
c = (t < c);
|
||||
l = (t + b[0]) & BN_MASK2;
|
||||
l = t + b[0];
|
||||
c += (l < t);
|
||||
r[0] = l;
|
||||
a++;
|
||||
@@ -302,37 +298,36 @@ BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
|
||||
#endif // !BN_ULLONG
|
||||
|
||||
BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
|
||||
int n) {
|
||||
size_t n) {
|
||||
BN_ULONG t1, t2;
|
||||
int c = 0;
|
||||
|
||||
assert(n >= 0);
|
||||
if (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;
|
||||
r[0] = t1 - t2 - c;
|
||||
if (t1 != t2) {
|
||||
c = (t1 < t2);
|
||||
}
|
||||
t1 = a[1];
|
||||
t2 = b[1];
|
||||
r[1] = (t1 - t2 - c) & BN_MASK2;
|
||||
r[1] = t1 - t2 - c;
|
||||
if (t1 != t2) {
|
||||
c = (t1 < t2);
|
||||
}
|
||||
t1 = a[2];
|
||||
t2 = b[2];
|
||||
r[2] = (t1 - t2 - c) & BN_MASK2;
|
||||
r[2] = t1 - t2 - c;
|
||||
if (t1 != t2) {
|
||||
c = (t1 < t2);
|
||||
}
|
||||
t1 = a[3];
|
||||
t2 = b[3];
|
||||
r[3] = (t1 - t2 - c) & BN_MASK2;
|
||||
r[3] = t1 - t2 - c;
|
||||
if (t1 != t2) {
|
||||
c = (t1 < t2);
|
||||
}
|
||||
@@ -344,7 +339,7 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
|
||||
while (n) {
|
||||
t1 = a[0];
|
||||
t2 = b[0];
|
||||
r[0] = (t1 - t2 - c) & BN_MASK2;
|
||||
r[0] = t1 - t2 - c;
|
||||
if (t1 != t2) {
|
||||
c = (t1 < t2);
|
||||
}
|
||||
@@ -372,7 +367,7 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
|
||||
t += (c0); /* no carry */ \
|
||||
(c0) = (BN_ULONG)Lw(t); \
|
||||
hi = (BN_ULONG)Hw(t); \
|
||||
(c1) = ((c1) + (hi)) & BN_MASK2; \
|
||||
(c1) += (hi); \
|
||||
if ((c1) < hi) { \
|
||||
(c2)++; \
|
||||
} \
|
||||
@@ -385,14 +380,14 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
|
||||
BN_ULLONG tt = t + (c0); /* no carry */ \
|
||||
(c0) = (BN_ULONG)Lw(tt); \
|
||||
hi = (BN_ULONG)Hw(tt); \
|
||||
(c1) = ((c1) + hi) & BN_MASK2; \
|
||||
(c1) += hi; \
|
||||
if ((c1) < hi) { \
|
||||
(c2)++; \
|
||||
} \
|
||||
t += (c0); /* no carry */ \
|
||||
(c0) = (BN_ULONG)Lw(t); \
|
||||
hi = (BN_ULONG)Hw(t); \
|
||||
(c1) = ((c1) + hi) & BN_MASK2; \
|
||||
(c1) += hi; \
|
||||
if ((c1) < hi) { \
|
||||
(c2)++; \
|
||||
} \
|
||||
@@ -405,7 +400,7 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
|
||||
t += (c0); /* no carry */ \
|
||||
(c0) = (BN_ULONG)Lw(t); \
|
||||
hi = (BN_ULONG)Hw(t); \
|
||||
(c1) = ((c1) + hi) & BN_MASK2; \
|
||||
(c1) += hi; \
|
||||
if ((c1) < hi) { \
|
||||
(c2)++; \
|
||||
} \
|
||||
@@ -458,7 +453,7 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
|
||||
|
||||
#endif // !BN_ULLONG
|
||||
|
||||
void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) {
|
||||
void bn_mul_comba8(BN_ULONG r[16], const BN_ULONG a[8], const BN_ULONG b[8]) {
|
||||
BN_ULONG c1, c2, c3;
|
||||
|
||||
c1 = 0;
|
||||
@@ -560,7 +555,7 @@ void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) {
|
||||
r[15] = c1;
|
||||
}
|
||||
|
||||
void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) {
|
||||
void bn_mul_comba4(BN_ULONG r[8], const BN_ULONG a[4], const BN_ULONG b[4]) {
|
||||
BN_ULONG c1, c2, c3;
|
||||
|
||||
c1 = 0;
|
||||
@@ -598,7 +593,7 @@ void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) {
|
||||
r[7] = c2;
|
||||
}
|
||||
|
||||
void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a) {
|
||||
void bn_sqr_comba8(BN_ULONG r[16], const BN_ULONG a[8]) {
|
||||
BN_ULONG c1, c2, c3;
|
||||
|
||||
c1 = 0;
|
||||
@@ -672,7 +667,7 @@ void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a) {
|
||||
r[15] = c1;
|
||||
}
|
||||
|
||||
void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a) {
|
||||
void bn_sqr_comba4(BN_ULONG r[8], const BN_ULONG a[4]) {
|
||||
BN_ULONG c1, c2, c3;
|
||||
|
||||
c1 = 0;
|
||||
|
||||
+175
-33
@@ -142,41 +142,39 @@ extern "C" {
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
// MSVC doesn't support two-word integers on 64-bit.
|
||||
#define BN_ULLONG uint128_t
|
||||
#define BN_ULLONG uint128_t
|
||||
#endif
|
||||
|
||||
#define BN_BITS2 64
|
||||
#define BN_BYTES 8
|
||||
#define BN_BITS4 32
|
||||
#define BN_MASK2 (0xffffffffffffffffUL)
|
||||
#define BN_MASK2l (0xffffffffUL)
|
||||
#define BN_MASK2h (0xffffffff00000000UL)
|
||||
#define BN_MASK2h1 (0xffffffff80000000UL)
|
||||
#define BN_BITS2 64
|
||||
#define BN_BYTES 8
|
||||
#define BN_BITS4 32
|
||||
#define BN_MASK2 (0xffffffffffffffffUL)
|
||||
#define BN_MASK2l (0xffffffffUL)
|
||||
#define BN_MASK2h (0xffffffff00000000UL)
|
||||
#define BN_MASK2h1 (0xffffffff80000000UL)
|
||||
#define BN_MONT_CTX_N0_LIMBS 1
|
||||
#define BN_TBIT (0x8000000000000000UL)
|
||||
#define BN_DEC_CONV (10000000000000000000UL)
|
||||
#define BN_DEC_NUM 19
|
||||
#define BN_DEC_CONV (10000000000000000000UL)
|
||||
#define BN_DEC_NUM 19
|
||||
#define TOBN(hi, lo) ((BN_ULONG)(hi) << 32 | (lo))
|
||||
|
||||
#elif defined(OPENSSL_32_BIT)
|
||||
|
||||
#define BN_ULLONG uint64_t
|
||||
#define BN_BITS2 32
|
||||
#define BN_BYTES 4
|
||||
#define BN_BITS4 16
|
||||
#define BN_MASK2 (0xffffffffUL)
|
||||
#define BN_MASK2l (0xffffUL)
|
||||
#define BN_MASK2h1 (0xffff8000UL)
|
||||
#define BN_MASK2h (0xffff0000UL)
|
||||
#define BN_ULLONG uint64_t
|
||||
#define BN_BITS2 32
|
||||
#define BN_BYTES 4
|
||||
#define BN_BITS4 16
|
||||
#define BN_MASK2 (0xffffffffUL)
|
||||
#define BN_MASK2l (0xffffUL)
|
||||
#define BN_MASK2h1 (0xffff8000UL)
|
||||
#define BN_MASK2h (0xffff0000UL)
|
||||
// On some 32-bit platforms, Montgomery multiplication is done using 64-bit
|
||||
// arithmetic with SIMD instructions. On such platforms, |BN_MONT_CTX::n0|
|
||||
// needs to be two words long. Only certain 32-bit platforms actually make use
|
||||
// of n0[1] and shorter R value would suffice for the others. However,
|
||||
// currently only the assembly files know which is which.
|
||||
#define BN_MONT_CTX_N0_LIMBS 2
|
||||
#define BN_TBIT (0x80000000UL)
|
||||
#define BN_DEC_CONV (1000000000UL)
|
||||
#define BN_DEC_NUM 9
|
||||
#define BN_DEC_CONV (1000000000UL)
|
||||
#define BN_DEC_NUM 9
|
||||
#define TOBN(hi, lo) (lo), (hi)
|
||||
|
||||
#else
|
||||
@@ -191,8 +189,8 @@ extern "C" {
|
||||
}
|
||||
|
||||
#if defined(BN_ULLONG)
|
||||
#define Lw(t) (((BN_ULONG)(t))&BN_MASK2)
|
||||
#define Hw(t) (((BN_ULONG)((t)>>BN_BITS2))&BN_MASK2)
|
||||
#define Lw(t) ((BN_ULONG)(t))
|
||||
#define Hw(t) ((BN_ULONG)((t) >> BN_BITS2))
|
||||
#endif
|
||||
|
||||
// bn_correct_top decrements |bn->top| until |bn->d[top-1]| is non-zero or
|
||||
@@ -212,16 +210,50 @@ int bn_expand(BIGNUM *bn, size_t bits);
|
||||
// least significant word first.
|
||||
int bn_set_words(BIGNUM *bn, const BN_ULONG *words, size_t num);
|
||||
|
||||
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_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);
|
||||
// bn_mul_add_words multiples |ap| by |w|, adds the result to |rp|, and places
|
||||
// the result in |rp|. |ap| and |rp| must both be |num| words long. It returns
|
||||
// the carry word of the operation. |ap| and |rp| may be equal but otherwise may
|
||||
// not alias.
|
||||
BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, size_t num,
|
||||
BN_ULONG w);
|
||||
|
||||
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_mul_words multiples |ap| by |w| and places the result in |rp|. |ap| and
|
||||
// |rp| must both be |num| words long. It returns the carry word of the
|
||||
// operation. |ap| and |rp| may be equal but otherwise may not alias.
|
||||
BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, size_t num, BN_ULONG w);
|
||||
|
||||
// bn_sqr_words sets |rp[2*i]| and |rp[2*i+1]| to |ap[i]|'s square, for all |i|
|
||||
// up to |num|. |ap| is an array of |num| words and |rp| an array of |2*num|
|
||||
// words. |ap| and |rp| may not alias.
|
||||
//
|
||||
// This gives the contribution of the |ap[i]*ap[i]| terms when squaring |ap|.
|
||||
void bn_sqr_words(BN_ULONG *rp, const BN_ULONG *ap, size_t num);
|
||||
|
||||
// bn_add_words adds |ap| to |bp| and places the result in |rp|, each of which
|
||||
// are |num| words long. It returns the carry bit, which is one if the operation
|
||||
// overflowed and zero otherwise. Any pair of |ap|, |bp|, and |rp| may be equal
|
||||
// to each other but otherwise may not alias.
|
||||
BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
|
||||
size_t num);
|
||||
|
||||
// bn_sub_words subtracts |bp| from |ap| and places the result in |rp|. It
|
||||
// returns the borrow bit, which is one if the computation underflowed and zero
|
||||
// otherwise. Any pair of |ap|, |bp|, and |rp| may be equal to each other but
|
||||
// otherwise may not alias.
|
||||
BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
|
||||
size_t num);
|
||||
|
||||
// bn_mul_comba4 sets |r| to the product of |a| and |b|.
|
||||
void bn_mul_comba4(BN_ULONG r[8], const BN_ULONG a[4], const BN_ULONG b[4]);
|
||||
|
||||
// bn_mul_comba8 sets |r| to the product of |a| and |b|.
|
||||
void bn_mul_comba8(BN_ULONG r[16], const BN_ULONG a[8], const BN_ULONG b[8]);
|
||||
|
||||
// bn_sqr_comba8 sets |r| to |a|^2.
|
||||
void bn_sqr_comba8(BN_ULONG r[16], const BN_ULONG a[4]);
|
||||
|
||||
// bn_sqr_comba4 sets |r| to |a|^2.
|
||||
void bn_sqr_comba4(BN_ULONG r[8], const BN_ULONG a[4]);
|
||||
|
||||
// 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|.
|
||||
@@ -233,6 +265,29 @@ int bn_cmp_words(const BN_ULONG *a, const BN_ULONG *b, int n);
|
||||
// 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);
|
||||
|
||||
// bn_less_than_words returns one if |a| < |b| and zero otherwise, where |a|
|
||||
// and |b| both are |len| words long. It runs in constant time.
|
||||
int bn_less_than_words(const BN_ULONG *a, const BN_ULONG *b, size_t len);
|
||||
|
||||
// bn_in_range_words returns one if |min_inclusive| <= |a| < |max_exclusive|,
|
||||
// where |a| and |max_exclusive| both are |len| words long. This function leaks
|
||||
// which of [0, min_inclusive), [min_inclusive, max_exclusive), and
|
||||
// [max_exclusive, 2^(BN_BITS2*len)) contains |a|, but otherwise the value of
|
||||
// |a| is secret.
|
||||
int bn_in_range_words(const BN_ULONG *a, BN_ULONG min_inclusive,
|
||||
const BN_ULONG *max_exclusive, size_t len);
|
||||
|
||||
// bn_rand_range_words sets |out| to a uniformly distributed random number from
|
||||
// |min_inclusive| to |max_exclusive|. Both |out| and |max_exclusive| are |len|
|
||||
// words long.
|
||||
//
|
||||
// This function runs in time independent of the result, but |min_inclusive| and
|
||||
// |max_exclusive| are public data. (Information about the range is unavoidably
|
||||
// leaked by how many iterations it took to select a number.)
|
||||
int bn_rand_range_words(BN_ULONG *out, BN_ULONG min_inclusive,
|
||||
const BN_ULONG *max_exclusive, size_t len,
|
||||
const uint8_t additional_data[32]);
|
||||
|
||||
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);
|
||||
|
||||
@@ -263,6 +318,93 @@ int bn_mod_inverse_secret_prime(BIGNUM *out, const BIGNUM *a, const BIGNUM *p,
|
||||
// -2 on error.
|
||||
int bn_jacobi(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
|
||||
|
||||
// bn_is_bit_set_words returns one if bit |bit| is set in |a| and zero
|
||||
// otherwise.
|
||||
int bn_is_bit_set_words(const BN_ULONG *a, size_t num, unsigned bit);
|
||||
|
||||
|
||||
// Low-level operations for small numbers.
|
||||
//
|
||||
// The following functions implement algorithms suitable for use with scalars
|
||||
// and field elements in elliptic curves. They rely on the number being small
|
||||
// both to stack-allocate various temporaries and because they do not implement
|
||||
// optimizations useful for the larger values used in RSA.
|
||||
|
||||
// BN_SMALL_MAX_WORDS is the largest size input these functions handle. This
|
||||
// limit allows temporaries to be more easily stack-allocated. This limit is set
|
||||
// to accommodate P-521.
|
||||
#if defined(OPENSSL_32_BIT)
|
||||
#define BN_SMALL_MAX_WORDS 17
|
||||
#else
|
||||
#define BN_SMALL_MAX_WORDS 9
|
||||
#endif
|
||||
|
||||
// bn_mul_small sets |r| to |a|*|b|. |num_r| must be |num_a| + |num_b|. |r| may
|
||||
// not alias with |a| or |b|. This function returns one on success and zero if
|
||||
// lengths are inconsistent.
|
||||
int bn_mul_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a, size_t num_a,
|
||||
const BN_ULONG *b, size_t num_b);
|
||||
|
||||
// bn_sqr_small sets |r| to |a|^2. |num_a| must be at most |BN_SMALL_MAX_WORDS|.
|
||||
// |num_r| must be |num_a|*2. |r| and |a| may not alias. This function returns
|
||||
// one on success and zero on programmer error.
|
||||
int bn_sqr_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a, size_t num_a);
|
||||
|
||||
// In the following functions, the modulus must be at most |BN_SMALL_MAX_WORDS|
|
||||
// words long.
|
||||
|
||||
// bn_to_montgomery_small sets |r| to |a| translated to the Montgomery domain.
|
||||
// |num_a| and |num_r| must be the length of the modulus, which is
|
||||
// |mont->N.top|. |a| must be fully reduced. This function returns one on
|
||||
// success and zero if lengths are inconsistent. |r| and |a| may alias.
|
||||
int bn_to_montgomery_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
|
||||
size_t num_a, const BN_MONT_CTX *mont);
|
||||
|
||||
// bn_from_montgomery_small sets |r| to |a| translated out of the Montgomery
|
||||
// domain. |num_r| must be the length of the modulus, which is |mont->N.top|.
|
||||
// |a| must be at most |mont->N.top| * R and |num_a| must be at most 2 *
|
||||
// |mont->N.top|. This function returns one on success and zero if lengths are
|
||||
// inconsistent. |r| and |a| may alias.
|
||||
int bn_from_montgomery_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
|
||||
size_t num_a, const BN_MONT_CTX *mont);
|
||||
|
||||
// bn_mod_mul_montgomery_small sets |r| to |a| * |b| mod |mont->N|. Both inputs
|
||||
// and outputs are in the Montgomery domain. |num_r| must be the length of the
|
||||
// modulus, which is |mont->N.top|. This function returns one on success and
|
||||
// zero on internal error or inconsistent lengths. Any two of |r|, |a|, and |b|
|
||||
// may alias.
|
||||
//
|
||||
// This function requires |a| * |b| < N * R, where N is the modulus and R is the
|
||||
// Montgomery divisor, 2^(N.top * BN_BITS2). This should generally be satisfied
|
||||
// by ensuring |a| and |b| are fully reduced, however ECDSA has one computation
|
||||
// which requires the more general bound.
|
||||
int bn_mod_mul_montgomery_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
|
||||
size_t num_a, const BN_ULONG *b, size_t num_b,
|
||||
const BN_MONT_CTX *mont);
|
||||
|
||||
// bn_mod_exp_mont_small sets |r| to |a|^|p| mod |mont->N|. It returns one on
|
||||
// success and zero on programmer or internal error. Both inputs and outputs are
|
||||
// in the Montgomery domain. |num_r| and |num_a| must be |mont->N.top|, which
|
||||
// must be at most |BN_SMALL_MAX_WORDS|. |a| must be fully-reduced. This
|
||||
// function runs in time independent of |a|, but |p| and |mont->N| are public
|
||||
// values.
|
||||
//
|
||||
// Note this function differs from |BN_mod_exp_mont| which uses Montgomery
|
||||
// reduction but takes input and output outside the Montgomery domain. Combine
|
||||
// this function with |bn_from_montgomery_small| and |bn_to_montgomery_small|
|
||||
// if necessary.
|
||||
int bn_mod_exp_mont_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
|
||||
size_t num_a, const BN_ULONG *p, size_t num_p,
|
||||
const BN_MONT_CTX *mont);
|
||||
|
||||
// bn_mod_inverse_prime_mont_small sets |r| to |a|^-1 mod |mont->N|. |mont->N|
|
||||
// must be a prime. |num_r| and |num_a| must be |mont->N.top|, which must be at
|
||||
// most |BN_SMALL_MAX_WORDS|. |a| must be fully-reduced. This function runs in
|
||||
// time independent of |a|, but |mont->N| is a public value.
|
||||
int bn_mod_inverse_prime_mont_small(BN_ULONG *r, size_t num_r,
|
||||
const BN_ULONG *a, size_t num_a,
|
||||
const BN_MONT_CTX *mont);
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} // extern C
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/thread.h>
|
||||
#include <openssl/type_check.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "../../internal.h"
|
||||
@@ -207,14 +208,13 @@ int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx) {
|
||||
mont->n0[1] = 0;
|
||||
#endif
|
||||
|
||||
// Save RR = R**2 (mod N). R is the smallest power of 2**BN_BITS such that R
|
||||
// Save RR = R**2 (mod N). R is the smallest power of 2**BN_BITS2 such that R
|
||||
// > mod. Even though the assembly on some 32-bit platforms works with 64-bit
|
||||
// values, using |BN_BITS2| here, rather than |BN_MONT_CTX_N0_LIMBS *
|
||||
// BN_BITS2|, is correct because R**2 will still be a multiple of the latter
|
||||
// as |BN_MONT_CTX_N0_LIMBS| is either one or two.
|
||||
//
|
||||
// XXX: This is not constant time with respect to |mont->N|, but it should
|
||||
// be.
|
||||
// XXX: This is not constant time with respect to |mont->N|, but it should be.
|
||||
unsigned lgBigR = (BN_num_bits(mod) + (BN_BITS2 - 1)) / BN_BITS2 * BN_BITS2;
|
||||
if (!bn_mod_exp_base_2_vartime(&mont->RR, lgBigR * 2, &mont->N)) {
|
||||
return 0;
|
||||
@@ -260,87 +260,75 @@ int BN_to_montgomery(BIGNUM *ret, const BIGNUM *a, const BN_MONT_CTX *mont,
|
||||
return BN_mod_mul_montgomery(ret, a, &mont->RR, mont, ctx);
|
||||
}
|
||||
|
||||
static int bn_from_montgomery_in_place(BN_ULONG *r, size_t num_r, BN_ULONG *a,
|
||||
size_t num_a, const BN_MONT_CTX *mont) {
|
||||
const BN_ULONG *n = mont->N.d;
|
||||
size_t num_n = mont->N.top;
|
||||
if (num_r != num_n || num_a != 2 * num_n) {
|
||||
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Add multiples of |n| to |r| until R = 2^(nl * BN_BITS2) divides it. On
|
||||
// input, we had |r| < |n| * R, so now |r| < 2 * |n| * R. Note that |r|
|
||||
// includes |carry| which is stored separately.
|
||||
BN_ULONG n0 = mont->n0[0];
|
||||
BN_ULONG carry = 0;
|
||||
for (size_t i = 0; i < num_n; i++) {
|
||||
BN_ULONG v = bn_mul_add_words(a + i, n, num_n, a[i] * n0);
|
||||
v += carry + a[i + num_n];
|
||||
carry |= (v != a[i + num_n]);
|
||||
carry &= (v <= a[i + num_n]);
|
||||
a[i + num_n] = v;
|
||||
}
|
||||
|
||||
// Shift |num_n| words to divide by R. We have |a| < 2 * |n|. Note that |a|
|
||||
// includes |carry| which is stored separately.
|
||||
a += num_n;
|
||||
|
||||
// |a| thus requires at most one additional subtraction |n| to be reduced.
|
||||
// Subtract |n| and select the answer in constant time.
|
||||
OPENSSL_COMPILE_ASSERT(sizeof(BN_ULONG) <= sizeof(crypto_word_t),
|
||||
crypto_word_t_too_small);
|
||||
BN_ULONG v = bn_sub_words(r, a, n, num_n) - carry;
|
||||
// |v| is one if |a| - |n| underflowed or zero if it did not. Note |v| cannot
|
||||
// be -1. That would imply the subtraction did not fit in |num_n| words, and
|
||||
// we know at most one subtraction is needed.
|
||||
v = 0u - v;
|
||||
for (size_t i = 0; i < num_n; i++) {
|
||||
r[i] = constant_time_select_w(v, a[i], r[i]);
|
||||
a[i] = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r,
|
||||
const BN_MONT_CTX *mont) {
|
||||
BN_ULONG *ap, *np, *rp, n0, v, carry;
|
||||
int nl, max, i;
|
||||
|
||||
const BIGNUM *n = &mont->N;
|
||||
nl = n->top;
|
||||
if (nl == 0) {
|
||||
if (n->top == 0) {
|
||||
ret->top = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
max = (2 * nl); // carry is stored separately
|
||||
if (!bn_wexpand(r, max)) {
|
||||
int max = (2 * n->top); // carry is stored separately
|
||||
if (!bn_wexpand(r, max) ||
|
||||
!bn_wexpand(ret, n->top)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
r->neg ^= n->neg;
|
||||
np = n->d;
|
||||
rp = r->d;
|
||||
|
||||
// clear the top words of T
|
||||
// Clear the top words of |r|.
|
||||
if (max > r->top) {
|
||||
OPENSSL_memset(&rp[r->top], 0, (max - r->top) * sizeof(BN_ULONG));
|
||||
OPENSSL_memset(r->d + r->top, 0, (max - r->top) * sizeof(BN_ULONG));
|
||||
}
|
||||
|
||||
r->top = max;
|
||||
n0 = mont->n0[0];
|
||||
ret->top = n->top;
|
||||
|
||||
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)) {
|
||||
if (!bn_from_montgomery_in_place(ret->d, ret->top, r->d, r->top, mont)) {
|
||||
return 0;
|
||||
}
|
||||
ret->top = nl;
|
||||
ret->neg = r->neg;
|
||||
|
||||
rp = ret->d;
|
||||
ap = &(r->d[nl]);
|
||||
|
||||
{
|
||||
BN_ULONG *nrp;
|
||||
uintptr_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 = (0u - (uintptr_t)v);
|
||||
nrp = (BN_ULONG *)(((uintptr_t)rp & ~m) | ((uintptr_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;
|
||||
}
|
||||
|
||||
@@ -428,3 +416,68 @@ err:
|
||||
BN_CTX_end(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bn_to_montgomery_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
|
||||
size_t num_a, const BN_MONT_CTX *mont) {
|
||||
return bn_mod_mul_montgomery_small(r, num_r, a, num_a, mont->RR.d,
|
||||
mont->RR.top, mont);
|
||||
}
|
||||
|
||||
int bn_from_montgomery_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
|
||||
size_t num_a, const BN_MONT_CTX *mont) {
|
||||
size_t num_n = mont->N.top;
|
||||
if (num_a > 2 * num_n || num_r != num_n || num_n > BN_SMALL_MAX_WORDS) {
|
||||
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||||
return 0;
|
||||
}
|
||||
BN_ULONG tmp[BN_SMALL_MAX_WORDS * 2];
|
||||
size_t num_tmp = 2 * num_n;
|
||||
OPENSSL_memcpy(tmp, a, num_a * sizeof(BN_ULONG));
|
||||
OPENSSL_memset(tmp + num_a, 0, (num_tmp - num_a) * sizeof(BN_ULONG));
|
||||
int ret = bn_from_montgomery_in_place(r, num_r, tmp, num_tmp, mont);
|
||||
OPENSSL_cleanse(tmp, num_tmp * sizeof(BN_ULONG));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bn_mod_mul_montgomery_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a,
|
||||
size_t num_a, const BN_ULONG *b, size_t num_b,
|
||||
const BN_MONT_CTX *mont) {
|
||||
size_t num_n = mont->N.top;
|
||||
if (num_r != num_n || num_a + num_b > 2 * num_n ||
|
||||
num_n > BN_SMALL_MAX_WORDS) {
|
||||
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(OPENSSL_BN_ASM_MONT)
|
||||
// |bn_mul_mont| requires at least 128 bits of limbs, at least for x86.
|
||||
if (num_n >= (128 / BN_BITS2) &&
|
||||
num_a == num_n &&
|
||||
num_b == num_n) {
|
||||
if (!bn_mul_mont(r, a, b, mont->N.d, mont->n0, num_n)) {
|
||||
assert(0); // The check above ensures this won't happen.
|
||||
OPENSSL_PUT_ERROR(BN, ERR_R_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Compute the product.
|
||||
BN_ULONG tmp[2 * BN_SMALL_MAX_WORDS];
|
||||
size_t num_tmp = 2 * num_n;
|
||||
size_t num_ab = num_a + num_b;
|
||||
if (a == b && num_a == num_b) {
|
||||
if (!bn_sqr_small(tmp, num_ab, a, num_a)) {
|
||||
return 0;
|
||||
}
|
||||
} else if (!bn_mul_small(tmp, num_ab, a, num_a, b, num_b)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Zero-extend to full width and reduce.
|
||||
OPENSSL_memset(tmp + num_ab, 0, (num_tmp - num_ab) * sizeof(BN_ULONG));
|
||||
int ret = bn_from_montgomery_in_place(r, num_r, tmp, num_tmp, mont);
|
||||
OPENSSL_cleanse(tmp, num_tmp * sizeof(BN_ULONG));
|
||||
return ret;
|
||||
}
|
||||
|
||||
+96
-61
@@ -59,50 +59,48 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "../../internal.h"
|
||||
|
||||
|
||||
#define BN_MUL_RECURSIVE_SIZE_NORMAL 16
|
||||
#define BN_SQR_RECURSIVE_SIZE_NORMAL BN_MUL_RECURSIVE_SIZE_NORMAL
|
||||
|
||||
|
||||
static void bn_mul_normal(BN_ULONG *r, BN_ULONG *a, int na, BN_ULONG *b,
|
||||
int nb) {
|
||||
BN_ULONG *rr;
|
||||
|
||||
static void bn_mul_normal(BN_ULONG *r, const BN_ULONG *a, size_t na,
|
||||
const BN_ULONG *b, size_t nb) {
|
||||
if (na < nb) {
|
||||
int itmp;
|
||||
BN_ULONG *ltmp;
|
||||
|
||||
itmp = na;
|
||||
size_t itmp = na;
|
||||
na = nb;
|
||||
nb = itmp;
|
||||
ltmp = a;
|
||||
const BN_ULONG *ltmp = a;
|
||||
a = b;
|
||||
b = ltmp;
|
||||
}
|
||||
rr = &(r[na]);
|
||||
if (nb <= 0) {
|
||||
(void)bn_mul_words(r, a, na, 0);
|
||||
BN_ULONG *rr = &(r[na]);
|
||||
if (nb == 0) {
|
||||
OPENSSL_memset(r, 0, na * sizeof(BN_ULONG));
|
||||
return;
|
||||
} else {
|
||||
rr[0] = bn_mul_words(r, a, na, b[0]);
|
||||
}
|
||||
rr[0] = bn_mul_words(r, a, na, b[0]);
|
||||
|
||||
for (;;) {
|
||||
if (--nb <= 0) {
|
||||
if (--nb == 0) {
|
||||
return;
|
||||
}
|
||||
rr[1] = bn_mul_add_words(&(r[1]), a, na, b[1]);
|
||||
if (--nb <= 0) {
|
||||
if (--nb == 0) {
|
||||
return;
|
||||
}
|
||||
rr[2] = bn_mul_add_words(&(r[2]), a, na, b[2]);
|
||||
if (--nb <= 0) {
|
||||
if (--nb == 0) {
|
||||
return;
|
||||
}
|
||||
rr[3] = bn_mul_add_words(&(r[3]), a, na, b[3]);
|
||||
if (--nb <= 0) {
|
||||
if (--nb == 0) {
|
||||
return;
|
||||
}
|
||||
rr[4] = bn_mul_add_words(&(r[4]), a, na, b[4]);
|
||||
@@ -141,7 +139,7 @@ static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a,
|
||||
if (dl < 0) {
|
||||
for (;;) {
|
||||
t = b[0];
|
||||
r[0] = (0 - t - c) & BN_MASK2;
|
||||
r[0] = 0 - t - c;
|
||||
if (t != 0) {
|
||||
c = 1;
|
||||
}
|
||||
@@ -150,7 +148,7 @@ static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a,
|
||||
}
|
||||
|
||||
t = b[1];
|
||||
r[1] = (0 - t - c) & BN_MASK2;
|
||||
r[1] = 0 - t - c;
|
||||
if (t != 0) {
|
||||
c = 1;
|
||||
}
|
||||
@@ -159,7 +157,7 @@ static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a,
|
||||
}
|
||||
|
||||
t = b[2];
|
||||
r[2] = (0 - t - c) & BN_MASK2;
|
||||
r[2] = 0 - t - c;
|
||||
if (t != 0) {
|
||||
c = 1;
|
||||
}
|
||||
@@ -168,7 +166,7 @@ static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a,
|
||||
}
|
||||
|
||||
t = b[3];
|
||||
r[3] = (0 - t - c) & BN_MASK2;
|
||||
r[3] = 0 - t - c;
|
||||
if (t != 0) {
|
||||
c = 1;
|
||||
}
|
||||
@@ -183,7 +181,7 @@ static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a,
|
||||
int save_dl = dl;
|
||||
while (c) {
|
||||
t = a[0];
|
||||
r[0] = (t - c) & BN_MASK2;
|
||||
r[0] = t - c;
|
||||
if (t != 0) {
|
||||
c = 0;
|
||||
}
|
||||
@@ -192,7 +190,7 @@ static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a,
|
||||
}
|
||||
|
||||
t = a[1];
|
||||
r[1] = (t - c) & BN_MASK2;
|
||||
r[1] = t - c;
|
||||
if (t != 0) {
|
||||
c = 0;
|
||||
}
|
||||
@@ -201,7 +199,7 @@ static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a,
|
||||
}
|
||||
|
||||
t = a[2];
|
||||
r[2] = (t - c) & BN_MASK2;
|
||||
r[2] = t - c;
|
||||
if (t != 0) {
|
||||
c = 0;
|
||||
}
|
||||
@@ -210,7 +208,7 @@ static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a,
|
||||
}
|
||||
|
||||
t = a[3];
|
||||
r[3] = (t - c) & BN_MASK2;
|
||||
r[3] = t - c;
|
||||
if (t != 0) {
|
||||
c = 0;
|
||||
}
|
||||
@@ -230,11 +228,13 @@ static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a,
|
||||
if (--dl <= 0) {
|
||||
break;
|
||||
}
|
||||
OPENSSL_FALLTHROUGH;
|
||||
case 2:
|
||||
r[2] = a[2];
|
||||
if (--dl <= 0) {
|
||||
break;
|
||||
}
|
||||
OPENSSL_FALLTHROUGH;
|
||||
case 3:
|
||||
r[3] = a[3];
|
||||
if (--dl <= 0) {
|
||||
@@ -292,8 +292,8 @@ BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
|
||||
// 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) {
|
||||
static void bn_mul_recursive(BN_ULONG *r, const BN_ULONG *a, const 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;
|
||||
@@ -405,7 +405,7 @@ static void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2,
|
||||
if (c1) {
|
||||
p = &(r[n + n2]);
|
||||
lo = *p;
|
||||
ln = (lo + c1) & BN_MASK2;
|
||||
ln = lo + c1;
|
||||
*p = ln;
|
||||
|
||||
// The overflow will stop before we over write
|
||||
@@ -414,7 +414,7 @@ static void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2,
|
||||
do {
|
||||
p++;
|
||||
lo = *p;
|
||||
ln = (lo + 1) & BN_MASK2;
|
||||
ln = lo + 1;
|
||||
*p = ln;
|
||||
} while (ln == 0);
|
||||
}
|
||||
@@ -424,8 +424,9 @@ static void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2,
|
||||
// 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) {
|
||||
static void bn_mul_part_recursive(BN_ULONG *r, const BN_ULONG *a,
|
||||
const 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;
|
||||
@@ -542,7 +543,7 @@ static void bn_mul_part_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n,
|
||||
if (c1) {
|
||||
p = &(r[n + n2]);
|
||||
lo = *p;
|
||||
ln = (lo + c1) & BN_MASK2;
|
||||
ln = lo + c1;
|
||||
*p = ln;
|
||||
|
||||
// The overflow will stop before we over write
|
||||
@@ -551,7 +552,7 @@ static void bn_mul_part_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n,
|
||||
do {
|
||||
p++;
|
||||
lo = *p;
|
||||
ln = (lo + 1) & BN_MASK2;
|
||||
ln = lo + 1;
|
||||
*p = ln;
|
||||
} while (ln == 0);
|
||||
}
|
||||
@@ -656,38 +657,57 @@ err:
|
||||
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;
|
||||
int bn_mul_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a, size_t num_a,
|
||||
const BN_ULONG *b, size_t num_b) {
|
||||
if (num_r != num_a + num_b) {
|
||||
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||||
return 0;
|
||||
}
|
||||
// TODO(davidben): Should this call |bn_mul_comba4| too? |BN_mul| does not
|
||||
// hit that code.
|
||||
if (num_a == 8 && num_b == 8) {
|
||||
bn_mul_comba8(r, a, b);
|
||||
} else {
|
||||
bn_mul_normal(r, a, num_a, b, num_b);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
max = n * 2;
|
||||
ap = a;
|
||||
rp = r;
|
||||
// tmp must have 2*n words
|
||||
static void bn_sqr_normal(BN_ULONG *r, const BN_ULONG *a, size_t n,
|
||||
BN_ULONG *tmp) {
|
||||
if (n == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t max = n * 2;
|
||||
const BN_ULONG *ap = a;
|
||||
BN_ULONG *rp = r;
|
||||
rp[0] = rp[max - 1] = 0;
|
||||
rp++;
|
||||
j = n;
|
||||
|
||||
if (--j > 0) {
|
||||
// Compute the contribution of a[i] * a[j] for all i < j.
|
||||
if (n > 1) {
|
||||
ap++;
|
||||
rp[j] = bn_mul_words(rp, ap, j, ap[-1]);
|
||||
rp[n - 1] = bn_mul_words(rp, ap, n - 1, 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;
|
||||
if (n > 2) {
|
||||
for (size_t i = n - 2; i > 0; i--) {
|
||||
ap++;
|
||||
rp[i] = bn_mul_add_words(rp, ap, i, ap[-1]);
|
||||
rp += 2;
|
||||
}
|
||||
}
|
||||
|
||||
// The final result fits in |max| words, so none of the following operations
|
||||
// will overflow.
|
||||
|
||||
// Double |r|, giving the contribution of a[i] * a[j] for all i != j.
|
||||
bn_add_words(r, r, r, max);
|
||||
|
||||
// There will not be a carry
|
||||
|
||||
// Add in the contribution of a[i] * a[i] for all i.
|
||||
bn_sqr_words(tmp, a, n);
|
||||
|
||||
bn_add_words(r, r, tmp, max);
|
||||
}
|
||||
|
||||
@@ -700,7 +720,8 @@ static void bn_sqr_normal(BN_ULONG *r, const BN_ULONG *a, int n, BN_ULONG *tmp)
|
||||
// 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) {
|
||||
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;
|
||||
@@ -755,7 +776,7 @@ static void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2, BN_ULONG *t
|
||||
if (c1) {
|
||||
p = &(r[n + n2]);
|
||||
lo = *p;
|
||||
ln = (lo + c1) & BN_MASK2;
|
||||
ln = lo + c1;
|
||||
*p = ln;
|
||||
|
||||
// The overflow will stop before we over write
|
||||
@@ -764,7 +785,7 @@ static void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2, BN_ULONG *t
|
||||
do {
|
||||
p++;
|
||||
lo = *p;
|
||||
ln = (lo + 1) & BN_MASK2;
|
||||
ln = lo + 1;
|
||||
*p = ln;
|
||||
} while (ln == 0);
|
||||
}
|
||||
@@ -772,9 +793,6 @@ static void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2, BN_ULONG *t
|
||||
}
|
||||
|
||||
int BN_mul_word(BIGNUM *bn, BN_ULONG w) {
|
||||
BN_ULONG ll;
|
||||
|
||||
w &= BN_MASK2;
|
||||
if (!bn->top) {
|
||||
return 1;
|
||||
}
|
||||
@@ -784,7 +802,7 @@ int BN_mul_word(BIGNUM *bn, BN_ULONG w) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
ll = bn_mul_words(bn->d, bn->d, bn->top, w);
|
||||
BN_ULONG ll = bn_mul_words(bn->d, bn->d, bn->top, w);
|
||||
if (ll) {
|
||||
if (!bn_wexpand(bn, bn->top + 1)) {
|
||||
return 0;
|
||||
@@ -865,3 +883,20 @@ err:
|
||||
BN_CTX_end(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bn_sqr_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a, size_t num_a) {
|
||||
if (num_r != 2 * num_a || num_a > BN_SMALL_MAX_WORDS) {
|
||||
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||||
return 0;
|
||||
}
|
||||
if (num_a == 4) {
|
||||
bn_sqr_comba4(r, a);
|
||||
} else if (num_a == 8) {
|
||||
bn_sqr_comba8(r, a);
|
||||
} else {
|
||||
BN_ULONG tmp[2 * BN_SMALL_MAX_WORDS];
|
||||
bn_sqr_normal(r, a, num_a, tmp);
|
||||
OPENSSL_cleanse(tmp, 2 * num_a * sizeof(BN_ULONG));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -113,18 +113,16 @@
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/type_check.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "../../internal.h"
|
||||
#include "../rand/internal.h"
|
||||
|
||||
|
||||
static const uint8_t kDefaultAdditionalData[32] = {0};
|
||||
|
||||
static int bn_rand_with_additional_data(BIGNUM *rnd, int bits, int top,
|
||||
int bottom,
|
||||
const uint8_t additional_data[32]) {
|
||||
int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) {
|
||||
uint8_t *buf = NULL;
|
||||
int ret = 0, bit, bytes, mask;
|
||||
|
||||
@@ -159,7 +157,7 @@ static int bn_rand_with_additional_data(BIGNUM *rnd, int bits, int top,
|
||||
}
|
||||
|
||||
// Make a random number and set the top and bottom bits.
|
||||
RAND_bytes_with_additional_data(buf, bytes, additional_data);
|
||||
RAND_bytes(buf, bytes);
|
||||
|
||||
if (top != BN_RAND_TOP_ANY) {
|
||||
if (top == BN_RAND_TOP_TWO && bits > 1) {
|
||||
@@ -188,61 +186,108 @@ static int bn_rand_with_additional_data(BIGNUM *rnd, int bits, int top,
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
if (buf != NULL) {
|
||||
OPENSSL_cleanse(buf, bytes);
|
||||
OPENSSL_free(buf);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) {
|
||||
return bn_rand_with_additional_data(rnd, bits, top, bottom,
|
||||
kDefaultAdditionalData);
|
||||
OPENSSL_free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom) {
|
||||
return BN_rand(rnd, bits, top, bottom);
|
||||
}
|
||||
|
||||
static int bn_rand_range_with_additional_data(
|
||||
BIGNUM *r, BN_ULONG min_inclusive, const BIGNUM *max_exclusive,
|
||||
const uint8_t additional_data[32]) {
|
||||
if (BN_cmp_word(max_exclusive, min_inclusive) <= 0) {
|
||||
// bn_less_than_word returns one if the number represented by |len| words at |a|
|
||||
// is less than |b| and zero otherwise. It performs this computation in time
|
||||
// independent of the value of |a|. |b| is assumed public.
|
||||
static int bn_less_than_word(const BN_ULONG *a, size_t len, BN_ULONG b) {
|
||||
if (b == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (len == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// |a| < |b| iff a[1..len-1] are all zero and a[0] < b.
|
||||
OPENSSL_COMPILE_ASSERT(sizeof(BN_ULONG) <= sizeof(crypto_word_t),
|
||||
crypto_word_t_too_small);
|
||||
crypto_word_t mask = 0;
|
||||
for (size_t i = 1; i < len; i++) {
|
||||
mask |= a[i];
|
||||
}
|
||||
// |mask| is now zero iff a[1..len-1] are all zero.
|
||||
mask = constant_time_is_zero_w(mask);
|
||||
mask &= constant_time_lt_w(a[0], b);
|
||||
return constant_time_select_int(mask, 1, 0);
|
||||
}
|
||||
|
||||
int bn_in_range_words(const BN_ULONG *a, BN_ULONG min_inclusive,
|
||||
const BN_ULONG *max_exclusive, size_t len) {
|
||||
return bn_less_than_words(a, max_exclusive, len) &&
|
||||
!bn_less_than_word(a, len, min_inclusive);
|
||||
}
|
||||
|
||||
int bn_rand_range_words(BN_ULONG *out, BN_ULONG min_inclusive,
|
||||
const BN_ULONG *max_exclusive, size_t len,
|
||||
const uint8_t additional_data[32]) {
|
||||
// This function implements the equivalent of steps 4 through 7 of FIPS 186-4
|
||||
// appendices B.4.2 and B.5.2. When called in those contexts, |max_exclusive|
|
||||
// is n and |min_inclusive| is one.
|
||||
|
||||
// Compute the bit length of |max_exclusive| (step 1), in terms of a number of
|
||||
// |words| worth of entropy to fill and a mask of bits to clear in the top
|
||||
// word.
|
||||
size_t words = len;
|
||||
while (words > 0 && max_exclusive[words - 1] == 0) {
|
||||
words--;
|
||||
}
|
||||
if (words == 0 ||
|
||||
(words == 1 && max_exclusive[0] <= min_inclusive)) {
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_INVALID_RANGE);
|
||||
return 0;
|
||||
}
|
||||
BN_ULONG mask = max_exclusive[words - 1];
|
||||
// This sets all bits in |mask| below the most significant bit.
|
||||
mask |= mask >> 1;
|
||||
mask |= mask >> 2;
|
||||
mask |= mask >> 4;
|
||||
mask |= mask >> 8;
|
||||
mask |= mask >> 16;
|
||||
#if defined(OPENSSL_64_BIT)
|
||||
mask |= mask >> 32;
|
||||
#endif
|
||||
|
||||
// Fill any unused words with zero.
|
||||
OPENSSL_memset(out + words, 0, (len - words) * sizeof(BN_ULONG));
|
||||
|
||||
// This function is used to implement steps 4 through 7 of FIPS 186-4
|
||||
// appendices B.4.2 and B.5.2. When called in those contexts, |max_exclusive|
|
||||
// is n and |min_inclusive| is one.
|
||||
unsigned count = 100;
|
||||
unsigned n = BN_num_bits(max_exclusive); // n > 0
|
||||
do {
|
||||
if (!--count) {
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_ITERATIONS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (// steps 4 and 5
|
||||
!bn_rand_with_additional_data(r, n, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY,
|
||||
additional_data) ||
|
||||
// step 7
|
||||
!BN_add_word(r, min_inclusive)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Step 6. This loops if |r| >= |max_exclusive|. This is identical to
|
||||
// checking |r| > |max_exclusive| - 1 or |r| - 1 > |max_exclusive| - 2, the
|
||||
// formulation stated in FIPS 186-4.
|
||||
} while (BN_cmp(r, max_exclusive) >= 0);
|
||||
// Steps 4 and 5. Use |words| and |mask| together to obtain a string of N
|
||||
// bits, where N is the bit length of |max_exclusive|.
|
||||
RAND_bytes_with_additional_data((uint8_t *)out, words * sizeof(BN_ULONG),
|
||||
additional_data);
|
||||
out[words - 1] &= mask;
|
||||
|
||||
// If out >= max_exclusive or out < min_inclusive, retry. This implements
|
||||
// the equivalent of steps 6 and 7 without leaking the value of |out|.
|
||||
} while (!bn_in_range_words(out, min_inclusive, max_exclusive, words));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BN_rand_range_ex(BIGNUM *r, BN_ULONG min_inclusive,
|
||||
const BIGNUM *max_exclusive) {
|
||||
return bn_rand_range_with_additional_data(r, min_inclusive, max_exclusive,
|
||||
kDefaultAdditionalData);
|
||||
if (!bn_wexpand(r, max_exclusive->top) ||
|
||||
!bn_rand_range_words(r->d, min_inclusive, max_exclusive->d,
|
||||
max_exclusive->top, kDefaultAdditionalData)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
r->neg = 0;
|
||||
r->top = max_exclusive->top;
|
||||
bn_correct_top(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BN_rand_range(BIGNUM *r, const BIGNUM *range) {
|
||||
@@ -252,35 +297,3 @@ int BN_rand_range(BIGNUM *r, const BIGNUM *range) {
|
||||
int BN_pseudo_rand_range(BIGNUM *r, const BIGNUM *range) {
|
||||
return BN_rand_range(r, range);
|
||||
}
|
||||
|
||||
int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range, const BIGNUM *priv,
|
||||
const uint8_t *message, size_t message_len,
|
||||
BN_CTX *ctx) {
|
||||
// We copy |priv| into a local buffer to avoid furthur exposing its
|
||||
// length.
|
||||
uint8_t private_bytes[96];
|
||||
size_t todo = sizeof(priv->d[0]) * priv->top;
|
||||
if (todo > sizeof(private_bytes)) {
|
||||
// No reasonable DSA or ECDSA key should have a private key
|
||||
// this large and we don't handle this case in order to avoid
|
||||
// leaking the length of the private key.
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_PRIVATE_KEY_TOO_LARGE);
|
||||
return 0;
|
||||
}
|
||||
OPENSSL_memcpy(private_bytes, priv->d, todo);
|
||||
OPENSSL_memset(private_bytes + todo, 0, sizeof(private_bytes) - todo);
|
||||
|
||||
// Pass a SHA512 hash of the private key and message as additional data into
|
||||
// the RBG. This is a hardening measure against entropy failure.
|
||||
OPENSSL_COMPILE_ASSERT(SHA512_DIGEST_LENGTH >= 32,
|
||||
additional_data_is_too_large_for_sha512);
|
||||
SHA512_CTX sha;
|
||||
uint8_t digest[SHA512_DIGEST_LENGTH];
|
||||
SHA512_Init(&sha);
|
||||
SHA512_Update(&sha, private_bytes, sizeof(private_bytes));
|
||||
SHA512_Update(&sha, message, message_len);
|
||||
SHA512_Final(digest, &sha);
|
||||
|
||||
// Select a value k from [1, range-1], following FIPS 186-4 appendix B.5.2.
|
||||
return bn_rand_range_with_additional_data(out, 1, range, digest);
|
||||
}
|
||||
|
||||
@@ -90,8 +90,8 @@ int BN_lshift(BIGNUM *r, const BIGNUM *a, int n) {
|
||||
} 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;
|
||||
t[nw + i + 1] |= l >> rb;
|
||||
t[nw + i] = l << lb;
|
||||
}
|
||||
}
|
||||
OPENSSL_memset(t, 0, nw * sizeof(t[0]));
|
||||
@@ -121,8 +121,8 @@ int BN_lshift1(BIGNUM *r, const BIGNUM *a) {
|
||||
c = 0;
|
||||
for (i = 0; i < a->top; i++) {
|
||||
t = *(ap++);
|
||||
*(rp++) = ((t << 1) | c) & BN_MASK2;
|
||||
c = (t & BN_TBIT) ? 1 : 0;
|
||||
*(rp++) = (t << 1) | c;
|
||||
c = t >> (BN_BITS2 - 1);
|
||||
}
|
||||
if (c) {
|
||||
*rp = 1;
|
||||
@@ -173,11 +173,12 @@ int BN_rshift(BIGNUM *r, const BIGNUM *a, int n) {
|
||||
} else {
|
||||
l = *(f++);
|
||||
for (i = j - 1; i != 0; i--) {
|
||||
tmp = (l >> rb) & BN_MASK2;
|
||||
tmp = l >> rb;
|
||||
l = *(f++);
|
||||
*(t++) = (tmp | (l << lb)) & BN_MASK2;
|
||||
*(t++) = tmp | (l << lb);
|
||||
}
|
||||
if ((l = (l >> rb) & BN_MASK2)) {
|
||||
l >>= rb;
|
||||
if (l) {
|
||||
*(t) = l;
|
||||
}
|
||||
}
|
||||
@@ -208,14 +209,14 @@ int BN_rshift1(BIGNUM *r, const BIGNUM *a) {
|
||||
}
|
||||
rp = r->d;
|
||||
t = ap[--i];
|
||||
c = (t & 1) ? BN_TBIT : 0;
|
||||
c = t << (BN_BITS2 - 1);
|
||||
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;
|
||||
rp[i] = (t >> 1) | c;
|
||||
c = t << (BN_BITS2 - 1);
|
||||
}
|
||||
r->top = j;
|
||||
|
||||
@@ -227,19 +228,17 @@ int BN_rshift1(BIGNUM *r, const BIGNUM *a) {
|
||||
}
|
||||
|
||||
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;
|
||||
int i = n / BN_BITS2;
|
||||
int j = n % BN_BITS2;
|
||||
if (a->top <= i) {
|
||||
if (!bn_wexpand(a, i + 1)) {
|
||||
return 0;
|
||||
}
|
||||
for (k = a->top; k < i + 1; k++) {
|
||||
for (int k = a->top; k < i + 1; k++) {
|
||||
a->d[k] = 0;
|
||||
}
|
||||
a->top = i + 1;
|
||||
@@ -268,30 +267,29 @@ int BN_clear_bit(BIGNUM *a, int n) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BN_is_bit_set(const BIGNUM *a, int n) {
|
||||
int i, j;
|
||||
int bn_is_bit_set_words(const BN_ULONG *a, size_t num, unsigned bit) {
|
||||
unsigned i = bit / BN_BITS2;
|
||||
unsigned j = bit % BN_BITS2;
|
||||
if (i >= num) {
|
||||
return 0;
|
||||
}
|
||||
return (a[i] >> j) & 1;
|
||||
}
|
||||
|
||||
int BN_is_bit_set(const BIGNUM *a, int n) {
|
||||
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;
|
||||
return bn_is_bit_set_words(a->d, a->top, n);
|
||||
}
|
||||
|
||||
int BN_mask_bits(BIGNUM *a, int n) {
|
||||
int b, w;
|
||||
|
||||
if (n < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
w = n / BN_BITS2;
|
||||
b = n % BN_BITS2;
|
||||
int w = n / BN_BITS2;
|
||||
int b = n % BN_BITS2;
|
||||
if (w >= a->top) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -80,11 +80,8 @@ EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void) {
|
||||
}
|
||||
|
||||
int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *c) {
|
||||
if (c->cipher != NULL) {
|
||||
if (c->cipher->cleanup) {
|
||||
c->cipher->cleanup(c);
|
||||
}
|
||||
OPENSSL_cleanse(c->cipher_data, c->cipher->ctx_size);
|
||||
if (c->cipher != NULL && c->cipher->cleanup) {
|
||||
c->cipher->cleanup(c);
|
||||
}
|
||||
OPENSSL_free(c->cipher_data);
|
||||
|
||||
@@ -128,6 +125,11 @@ int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *ctx) {
|
||||
EVP_CIPHER_CTX_cleanup(ctx);
|
||||
EVP_CIPHER_CTX_init(ctx);
|
||||
}
|
||||
|
||||
int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
|
||||
ENGINE *engine, const uint8_t *key, const uint8_t *iv,
|
||||
int enc) {
|
||||
@@ -609,3 +611,5 @@ int EVP_DecryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
|
||||
int EVP_add_cipher_alias(const char *a, const char *b) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void EVP_CIPHER_CTX_set_flags(const EVP_CIPHER_CTX *ctx, uint32_t flags) {}
|
||||
|
||||
@@ -1197,9 +1197,7 @@ static int aead_aes_gcm_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
|
||||
}
|
||||
|
||||
static void aead_aes_gcm_cleanup(EVP_AEAD_CTX *ctx) {
|
||||
struct aead_aes_gcm_ctx *gcm_ctx = ctx->aead_state;
|
||||
OPENSSL_cleanse(gcm_ctx, sizeof(struct aead_aes_gcm_ctx));
|
||||
OPENSSL_free(gcm_ctx);
|
||||
OPENSSL_free(ctx->aead_state);
|
||||
}
|
||||
|
||||
static int aead_aes_gcm_seal_scatter(const EVP_AEAD_CTX *ctx, uint8_t *out,
|
||||
@@ -1366,9 +1364,7 @@ static int aead_aes_gcm_tls12_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
|
||||
}
|
||||
|
||||
static void aead_aes_gcm_tls12_cleanup(EVP_AEAD_CTX *ctx) {
|
||||
struct aead_aes_gcm_tls12_ctx *gcm_ctx = ctx->aead_state;
|
||||
OPENSSL_cleanse(gcm_ctx, sizeof(struct aead_aes_gcm_tls12_ctx));
|
||||
OPENSSL_free(gcm_ctx);
|
||||
OPENSSL_free(ctx->aead_state);
|
||||
}
|
||||
|
||||
static int aead_aes_gcm_tls12_seal_scatter(
|
||||
|
||||
@@ -88,18 +88,25 @@ extern "C" {
|
||||
switch (n) { \
|
||||
case 8: \
|
||||
(l2) = ((uint32_t)(*(--(c)))) << 24L; \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 7: \
|
||||
(l2) |= ((uint32_t)(*(--(c)))) << 16L; \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 6: \
|
||||
(l2) |= ((uint32_t)(*(--(c)))) << 8L; \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 5: \
|
||||
(l2) |= ((uint32_t)(*(--(c)))); \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 4: \
|
||||
(l1) = ((uint32_t)(*(--(c)))) << 24L; \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 3: \
|
||||
(l1) |= ((uint32_t)(*(--(c)))) << 16L; \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 2: \
|
||||
(l1) |= ((uint32_t)(*(--(c)))) << 8L; \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 1: \
|
||||
(l1) |= ((uint32_t)(*(--(c)))); \
|
||||
} \
|
||||
@@ -112,18 +119,25 @@ extern "C" {
|
||||
switch (n) { \
|
||||
case 8: \
|
||||
*(--(c)) = (unsigned char)(((l2) >> 24L) & 0xff); \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 7: \
|
||||
*(--(c)) = (unsigned char)(((l2) >> 16L) & 0xff); \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 6: \
|
||||
*(--(c)) = (unsigned char)(((l2) >> 8L) & 0xff); \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 5: \
|
||||
*(--(c)) = (unsigned char)(((l2)) & 0xff); \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 4: \
|
||||
*(--(c)) = (unsigned char)(((l1) >> 24L) & 0xff); \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 3: \
|
||||
*(--(c)) = (unsigned char)(((l1) >> 16L) & 0xff); \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 2: \
|
||||
*(--(c)) = (unsigned char)(((l1) >> 8L) & 0xff); \
|
||||
OPENSSL_FALLTHROUGH; \
|
||||
case 1: \
|
||||
*(--(c)) = (unsigned char)(((l1)) & 0xff); \
|
||||
} \
|
||||
|
||||
@@ -79,7 +79,7 @@ void EVP_MD_CTX_init(EVP_MD_CTX *ctx) {
|
||||
OPENSSL_memset(ctx, 0, sizeof(EVP_MD_CTX));
|
||||
}
|
||||
|
||||
EVP_MD_CTX *EVP_MD_CTX_create(void) {
|
||||
EVP_MD_CTX *EVP_MD_CTX_new(void) {
|
||||
EVP_MD_CTX *ctx = OPENSSL_malloc(sizeof(EVP_MD_CTX));
|
||||
|
||||
if (ctx) {
|
||||
@@ -89,11 +89,10 @@ EVP_MD_CTX *EVP_MD_CTX_create(void) {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
EVP_MD_CTX *EVP_MD_CTX_create(void) { return EVP_MD_CTX_new(); }
|
||||
|
||||
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);
|
||||
}
|
||||
OPENSSL_free(ctx->md_data);
|
||||
|
||||
assert(ctx->pctx == NULL || ctx->pctx_ops != NULL);
|
||||
if (ctx->pctx_ops) {
|
||||
@@ -105,7 +104,7 @@ int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx) {
|
||||
void EVP_MD_CTX_free(EVP_MD_CTX *ctx) {
|
||||
if (!ctx) {
|
||||
return;
|
||||
}
|
||||
@@ -114,18 +113,38 @@ void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx) {
|
||||
OPENSSL_free(ctx);
|
||||
}
|
||||
|
||||
int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in) {
|
||||
uint8_t *tmp_buf = NULL;
|
||||
void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx) { EVP_MD_CTX_free(ctx); }
|
||||
|
||||
int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in) {
|
||||
if (in == NULL || in->digest == NULL) {
|
||||
OPENSSL_PUT_ERROR(DIGEST, 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.
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
assert(in->pctx == NULL || in->pctx_ops != NULL);
|
||||
if (in->pctx) {
|
||||
pctx = in->pctx_ops->dup(in->pctx);
|
||||
if (!pctx) {
|
||||
OPENSSL_PUT_ERROR(DIGEST, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *tmp_buf;
|
||||
if (out->digest != in->digest) {
|
||||
assert(in->digest->ctx_size != 0);
|
||||
tmp_buf = OPENSSL_malloc(in->digest->ctx_size);
|
||||
if (tmp_buf == NULL) {
|
||||
if (pctx) {
|
||||
in->pctx_ops->free(pctx);
|
||||
}
|
||||
OPENSSL_PUT_ERROR(DIGEST, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
// |md_data| will be the correct size in this case. It's removed from |out|
|
||||
// so that |EVP_MD_CTX_cleanup| doesn't free it, and then it's reused.
|
||||
tmp_buf = out->md_data;
|
||||
out->md_data = NULL;
|
||||
}
|
||||
@@ -133,28 +152,11 @@ int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in) {
|
||||
EVP_MD_CTX_cleanup(out);
|
||||
|
||||
out->digest = in->digest;
|
||||
if (in->md_data && in->digest->ctx_size) {
|
||||
if (tmp_buf) {
|
||||
out->md_data = tmp_buf;
|
||||
} else {
|
||||
out->md_data = OPENSSL_malloc(in->digest->ctx_size);
|
||||
if (!out->md_data) {
|
||||
OPENSSL_PUT_ERROR(DIGEST, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
OPENSSL_memcpy(out->md_data, in->md_data, in->digest->ctx_size);
|
||||
}
|
||||
|
||||
assert(in->pctx == NULL || in->pctx_ops != NULL);
|
||||
out->md_data = tmp_buf;
|
||||
OPENSSL_memcpy(out->md_data, in->md_data, in->digest->ctx_size);
|
||||
out->pctx = pctx;
|
||||
out->pctx_ops = in->pctx_ops;
|
||||
if (in->pctx && in->pctx_ops) {
|
||||
out->pctx = in->pctx_ops->dup(in->pctx);
|
||||
if (!out->pctx) {
|
||||
EVP_MD_CTX_cleanup(out);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
assert(out->pctx == NULL || out->pctx_ops != NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -164,20 +166,23 @@ int EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in) {
|
||||
return EVP_MD_CTX_copy_ex(out, in);
|
||||
}
|
||||
|
||||
void EVP_MD_CTX_reset(EVP_MD_CTX *ctx) {
|
||||
EVP_MD_CTX_cleanup(ctx);
|
||||
EVP_MD_CTX_init(ctx);
|
||||
}
|
||||
|
||||
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 > 0) {
|
||||
OPENSSL_free(ctx->md_data);
|
||||
ctx->md_data = NULL;
|
||||
assert(type->ctx_size != 0);
|
||||
uint8_t *md_data = OPENSSL_malloc(type->ctx_size);
|
||||
if (md_data == NULL) {
|
||||
OPENSSL_PUT_ERROR(DIGEST, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
OPENSSL_free(ctx->md_data);
|
||||
ctx->md_data = md_data;
|
||||
ctx->digest = type;
|
||||
if (type->ctx_size > 0) {
|
||||
ctx->md_data = OPENSSL_malloc(type->ctx_size);
|
||||
if (ctx->md_data == NULL) {
|
||||
OPENSSL_PUT_ERROR(DIGEST, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(ctx->pctx == NULL || ctx->pctx_ops != NULL);
|
||||
|
||||
+262
-162
@@ -77,9 +77,12 @@
|
||||
|
||||
#include "internal.h"
|
||||
#include "../../internal.h"
|
||||
#include "../bn/internal.h"
|
||||
#include "../delocate.h"
|
||||
|
||||
|
||||
static void ec_point_free(EC_POINT *point, int free_group);
|
||||
|
||||
static const uint8_t kP224Params[6 * 28] = {
|
||||
// p
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
@@ -277,63 +280,6 @@ DEFINE_METHOD_FUNCTION(struct built_in_curves, OPENSSL_built_in_curves) {
|
||||
#endif
|
||||
}
|
||||
|
||||
// built_in_curve_scalar_field_monts contains Montgomery contexts for
|
||||
// performing inversions in the scalar fields of each of the built-in
|
||||
// curves. It's protected by |built_in_curve_scalar_field_monts_once|.
|
||||
DEFINE_LOCAL_DATA(BN_MONT_CTX **, built_in_curve_scalar_field_monts) {
|
||||
const struct built_in_curves *const curves = OPENSSL_built_in_curves();
|
||||
|
||||
BN_MONT_CTX **monts =
|
||||
OPENSSL_malloc(sizeof(BN_MONT_CTX *) * OPENSSL_NUM_BUILT_IN_CURVES);
|
||||
if (monts == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
OPENSSL_memset(monts, 0, sizeof(BN_MONT_CTX *) * OPENSSL_NUM_BUILT_IN_CURVES);
|
||||
|
||||
BIGNUM *order = BN_new();
|
||||
BN_CTX *bn_ctx = BN_CTX_new();
|
||||
BN_MONT_CTX *mont_ctx = NULL;
|
||||
|
||||
if (bn_ctx == NULL ||
|
||||
order == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < OPENSSL_NUM_BUILT_IN_CURVES; i++) {
|
||||
const struct built_in_curve *curve = &curves->curves[i];
|
||||
const unsigned param_len = curve->param_len;
|
||||
const uint8_t *params = curve->params;
|
||||
|
||||
mont_ctx = BN_MONT_CTX_new();
|
||||
if (mont_ctx == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!BN_bin2bn(params + 5 * param_len, param_len, order) ||
|
||||
!BN_MONT_CTX_set(mont_ctx, order, bn_ctx)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
monts[i] = mont_ctx;
|
||||
mont_ctx = NULL;
|
||||
}
|
||||
|
||||
*out = monts;
|
||||
goto done;
|
||||
|
||||
err:
|
||||
BN_MONT_CTX_free(mont_ctx);
|
||||
for (size_t i = 0; i < OPENSSL_NUM_BUILT_IN_CURVES; i++) {
|
||||
BN_MONT_CTX_free(monts[i]);
|
||||
}
|
||||
OPENSSL_free((BN_MONT_CTX**) monts);
|
||||
|
||||
done:
|
||||
BN_free(order);
|
||||
BN_CTX_free(bn_ctx);
|
||||
}
|
||||
|
||||
EC_GROUP *ec_group_new(const EC_METHOD *meth) {
|
||||
EC_GROUP *ret;
|
||||
|
||||
@@ -354,6 +300,7 @@ EC_GROUP *ec_group_new(const EC_METHOD *meth) {
|
||||
}
|
||||
OPENSSL_memset(ret, 0, sizeof(EC_GROUP));
|
||||
|
||||
ret->references = 1;
|
||||
ret->meth = meth;
|
||||
BN_init(&ret->order);
|
||||
|
||||
@@ -365,16 +312,35 @@ EC_GROUP *ec_group_new(const EC_METHOD *meth) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ec_group_set0_generator(EC_GROUP *group, EC_POINT *generator) {
|
||||
assert(group->generator == NULL);
|
||||
assert(group == generator->group);
|
||||
|
||||
// Avoid a reference cycle. |group->generator| does not maintain an owning
|
||||
// pointer to |group|.
|
||||
group->generator = generator;
|
||||
int is_zero = CRYPTO_refcount_dec_and_test_zero(&group->references);
|
||||
|
||||
assert(!is_zero);
|
||||
(void)is_zero;
|
||||
}
|
||||
|
||||
EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a,
|
||||
const BIGNUM *b, BN_CTX *ctx) {
|
||||
if (BN_num_bytes(p) > EC_MAX_SCALAR_BYTES) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_FIELD);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EC_GROUP *ret = ec_group_new(EC_GFp_mont_method());
|
||||
if (ret == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ret->meth->group_set_curve == 0) {
|
||||
if (ret->meth->group_set_curve == NULL) {
|
||||
OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||||
return 0;
|
||||
EC_GROUP_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
if (!ret->meth->group_set_curve(ret, p, a, b, ctx)) {
|
||||
EC_GROUP_free(ret);
|
||||
@@ -385,9 +351,19 @@ EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a,
|
||||
|
||||
int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator,
|
||||
const BIGNUM *order, const BIGNUM *cofactor) {
|
||||
if (group->curve_name != NID_undef || group->generator != NULL) {
|
||||
if (group->curve_name != NID_undef || group->generator != NULL ||
|
||||
generator->group != group) {
|
||||
// |EC_GROUP_set_generator| may only be used with |EC_GROUP|s returned by
|
||||
// |EC_GROUP_new_curve_GFp| and may only used once on each group.
|
||||
// Additionally, |generator| must been created from
|
||||
// |EC_GROUP_new_curve_GFp|, not a copy, so that
|
||||
// |generator->group->generator| is set correctly.
|
||||
OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (BN_num_bytes(order) > EC_MAX_SCALAR_BYTES) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_FIELD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -397,15 +373,44 @@ int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator,
|
||||
return 0;
|
||||
}
|
||||
|
||||
group->generator = EC_POINT_new(group);
|
||||
return group->generator != NULL &&
|
||||
EC_POINT_copy(group->generator, generator) &&
|
||||
BN_copy(&group->order, order);
|
||||
// Require that p < 2×order. This simplifies some ECDSA operations.
|
||||
//
|
||||
// Note any curve which did not satisfy this must have been invalid or use a
|
||||
// tiny prime (less than 17). See the proof in |field_element_to_scalar| in
|
||||
// the ECDSA implementation.
|
||||
BIGNUM *tmp = BN_new();
|
||||
if (tmp == NULL ||
|
||||
!BN_lshift1(tmp, order)) {
|
||||
BN_free(tmp);
|
||||
return 0;
|
||||
}
|
||||
int ok = BN_cmp(tmp, &group->field) > 0;
|
||||
BN_free(tmp);
|
||||
if (!ok) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_GROUP_ORDER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
EC_POINT *copy = EC_POINT_new(group);
|
||||
if (copy == NULL ||
|
||||
!EC_POINT_copy(copy, generator) ||
|
||||
!BN_copy(&group->order, order)) {
|
||||
EC_POINT_free(copy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
BN_MONT_CTX_free(group->order_mont);
|
||||
group->order_mont = BN_MONT_CTX_new();
|
||||
if (group->order_mont == NULL ||
|
||||
!BN_MONT_CTX_set(group->order_mont, &group->order, NULL)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ec_group_set0_generator(group, copy);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static EC_GROUP *ec_group_new_from_data(unsigned built_in_index) {
|
||||
const struct built_in_curves *const curves = OPENSSL_built_in_curves();
|
||||
const struct built_in_curve *curve = &curves->curves[built_in_index];
|
||||
static EC_GROUP *ec_group_new_from_data(const struct built_in_curve *curve) {
|
||||
EC_GROUP *group = NULL;
|
||||
EC_POINT *P = NULL;
|
||||
BIGNUM *p = NULL, *a = NULL, *b = NULL, *x = NULL, *y = NULL;
|
||||
@@ -454,12 +459,14 @@ static EC_GROUP *ec_group_new_from_data(unsigned built_in_index) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
const BN_MONT_CTX **monts = *built_in_curve_scalar_field_monts();
|
||||
if (monts != NULL) {
|
||||
group->order_mont = monts[built_in_index];
|
||||
group->order_mont = BN_MONT_CTX_new();
|
||||
if (group->order_mont == NULL ||
|
||||
!BN_MONT_CTX_set(group->order_mont, &group->order, ctx)) {
|
||||
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
|
||||
goto err;
|
||||
}
|
||||
|
||||
group->generator = P;
|
||||
ec_group_set0_generator(group, P);
|
||||
P = NULL;
|
||||
ok = 1;
|
||||
|
||||
@@ -478,87 +485,118 @@ err:
|
||||
return group;
|
||||
}
|
||||
|
||||
EC_GROUP *EC_GROUP_new_by_curve_name(int nid) {
|
||||
const struct built_in_curves *const curves = OPENSSL_built_in_curves();
|
||||
EC_GROUP *ret = NULL;
|
||||
// Built-in groups are allocated lazily and static once allocated.
|
||||
// TODO(davidben): Make these actually static. https://crbug.com/boringssl/20.
|
||||
struct built_in_groups_st {
|
||||
EC_GROUP *groups[OPENSSL_NUM_BUILT_IN_CURVES];
|
||||
};
|
||||
DEFINE_BSS_GET(struct built_in_groups_st, built_in_groups);
|
||||
DEFINE_STATIC_MUTEX(built_in_groups_lock);
|
||||
|
||||
EC_GROUP *EC_GROUP_new_by_curve_name(int nid) {
|
||||
struct built_in_groups_st *groups = built_in_groups_bss_get();
|
||||
EC_GROUP **group_ptr = NULL;
|
||||
const struct built_in_curves *const curves = OPENSSL_built_in_curves();
|
||||
const struct built_in_curve *curve = NULL;
|
||||
for (size_t i = 0; i < OPENSSL_NUM_BUILT_IN_CURVES; i++) {
|
||||
const struct built_in_curve *curve = &curves->curves[i];
|
||||
if (curve->nid == nid) {
|
||||
ret = ec_group_new_from_data(i);
|
||||
if (curves->curves[i].nid == nid) {
|
||||
curve = &curves->curves[i];
|
||||
group_ptr = &groups->groups[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == NULL) {
|
||||
if (curve == NULL) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->curve_name = nid;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void EC_GROUP_free(EC_GROUP *group) {
|
||||
if (!group) {
|
||||
return;
|
||||
CRYPTO_STATIC_MUTEX_lock_read(built_in_groups_lock_bss_get());
|
||||
EC_GROUP *ret = *group_ptr;
|
||||
CRYPTO_STATIC_MUTEX_unlock_read(built_in_groups_lock_bss_get());
|
||||
if (ret != NULL) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (group->meth->group_finish != 0) {
|
||||
group->meth->group_finish(group);
|
||||
}
|
||||
|
||||
EC_POINT_free(group->generator);
|
||||
BN_free(&group->order);
|
||||
|
||||
OPENSSL_free(group);
|
||||
}
|
||||
|
||||
const BN_MONT_CTX *ec_group_get_order_mont(const EC_GROUP *group) {
|
||||
return group->order_mont;
|
||||
}
|
||||
|
||||
EC_GROUP *EC_GROUP_dup(const EC_GROUP *a) {
|
||||
if (a == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (a->meth->group_copy == NULL) {
|
||||
OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EC_GROUP *ret = ec_group_new(a->meth);
|
||||
ret = ec_group_new_from_data(curve);
|
||||
if (ret == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->order_mont = a->order_mont;
|
||||
ret->curve_name = a->curve_name;
|
||||
|
||||
if (a->generator != NULL) {
|
||||
ret->generator = EC_POINT_dup(a->generator, ret);
|
||||
if (ret->generator == NULL) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (!BN_copy(&ret->order, &a->order) ||
|
||||
!ret->meth->group_copy(ret, a)) {
|
||||
goto err;
|
||||
EC_GROUP *to_free = NULL;
|
||||
CRYPTO_STATIC_MUTEX_lock_write(built_in_groups_lock_bss_get());
|
||||
if (*group_ptr == NULL) {
|
||||
*group_ptr = ret;
|
||||
// Filling in |ret->curve_name| makes |EC_GROUP_free| and |EC_GROUP_dup|
|
||||
// into no-ops. At this point, |ret| is considered static.
|
||||
ret->curve_name = nid;
|
||||
} else {
|
||||
to_free = ret;
|
||||
ret = *group_ptr;
|
||||
}
|
||||
CRYPTO_STATIC_MUTEX_unlock_write(built_in_groups_lock_bss_get());
|
||||
|
||||
EC_GROUP_free(to_free);
|
||||
return ret;
|
||||
}
|
||||
|
||||
err:
|
||||
EC_GROUP_free(ret);
|
||||
return NULL;
|
||||
void EC_GROUP_free(EC_GROUP *group) {
|
||||
if (group == NULL ||
|
||||
// Built-in curves are static.
|
||||
group->curve_name != NID_undef ||
|
||||
!CRYPTO_refcount_dec_and_test_zero(&group->references)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (group->meth->group_finish != NULL) {
|
||||
group->meth->group_finish(group);
|
||||
}
|
||||
|
||||
ec_point_free(group->generator, 0 /* don't free group */);
|
||||
BN_free(&group->order);
|
||||
BN_MONT_CTX_free(group->order_mont);
|
||||
|
||||
OPENSSL_free(group);
|
||||
}
|
||||
|
||||
EC_GROUP *EC_GROUP_dup(const EC_GROUP *a) {
|
||||
if (a == NULL ||
|
||||
// Built-in curves are static.
|
||||
a->curve_name != NID_undef) {
|
||||
return (EC_GROUP *)a;
|
||||
}
|
||||
|
||||
// Groups are logically immutable (but for |EC_GROUP_set_generator| which must
|
||||
// be called early on), so we simply take a reference.
|
||||
EC_GROUP *group = (EC_GROUP *)a;
|
||||
CRYPTO_refcount_inc(&group->references);
|
||||
return group;
|
||||
}
|
||||
|
||||
int EC_GROUP_cmp(const EC_GROUP *a, const EC_GROUP *b, BN_CTX *ignored) {
|
||||
return a->curve_name == NID_undef ||
|
||||
b->curve_name == NID_undef ||
|
||||
a->curve_name != b->curve_name;
|
||||
// Note this function returns 0 if equal and non-zero otherwise.
|
||||
if (a == b) {
|
||||
return 0;
|
||||
}
|
||||
if (a->curve_name != b->curve_name) {
|
||||
return 1;
|
||||
}
|
||||
if (a->curve_name != NID_undef) {
|
||||
// Built-in curves may be compared by curve name alone.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// |a| and |b| are both custom curves. We compare the entire curve
|
||||
// structure. If |a| or |b| is incomplete (due to legacy OpenSSL mistakes,
|
||||
// custom curve construction is sadly done in two parts) but otherwise not the
|
||||
// same object, we consider them always unequal.
|
||||
return a->generator == NULL ||
|
||||
b->generator == NULL ||
|
||||
BN_cmp(&a->order, &b->order) != 0 ||
|
||||
BN_cmp(&a->field, &b->field) != 0 ||
|
||||
BN_cmp(&a->a, &b->a) != 0 ||
|
||||
BN_cmp(&a->b, &b->b) != 0 ||
|
||||
ec_GFp_simple_cmp(a, a->generator, b->generator, NULL) != 0;
|
||||
}
|
||||
|
||||
const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *group) {
|
||||
@@ -608,9 +646,9 @@ EC_POINT *EC_POINT_new(const EC_GROUP *group) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->meth = group->meth;
|
||||
|
||||
if (!ec_GFp_simple_point_init(ret)) {
|
||||
ret->group = EC_GROUP_dup(group);
|
||||
if (ret->group == NULL ||
|
||||
!ec_GFp_simple_point_init(ret)) {
|
||||
OPENSSL_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
@@ -618,29 +656,25 @@ EC_POINT *EC_POINT_new(const EC_GROUP *group) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
void EC_POINT_free(EC_POINT *point) {
|
||||
static void ec_point_free(EC_POINT *point, int free_group) {
|
||||
if (!point) {
|
||||
return;
|
||||
}
|
||||
|
||||
ec_GFp_simple_point_finish(point);
|
||||
|
||||
OPENSSL_free(point);
|
||||
}
|
||||
|
||||
void EC_POINT_clear_free(EC_POINT *point) {
|
||||
if (!point) {
|
||||
return;
|
||||
if (free_group) {
|
||||
EC_GROUP_free(point->group);
|
||||
}
|
||||
|
||||
ec_GFp_simple_point_clear_finish(point);
|
||||
|
||||
OPENSSL_cleanse(point, sizeof *point);
|
||||
OPENSSL_free(point);
|
||||
}
|
||||
|
||||
void EC_POINT_free(EC_POINT *point) {
|
||||
ec_point_free(point, 1 /* free group */);
|
||||
}
|
||||
|
||||
void EC_POINT_clear_free(EC_POINT *point) { EC_POINT_free(point); }
|
||||
|
||||
int EC_POINT_copy(EC_POINT *dest, const EC_POINT *src) {
|
||||
if (dest->meth != src->meth) {
|
||||
if (EC_GROUP_cmp(dest->group, src->group, NULL) != 0) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
|
||||
return 0;
|
||||
}
|
||||
@@ -666,7 +700,7 @@ EC_POINT *EC_POINT_dup(const EC_POINT *a, const EC_GROUP *group) {
|
||||
}
|
||||
|
||||
int EC_POINT_set_to_infinity(const EC_GROUP *group, EC_POINT *point) {
|
||||
if (group->meth != point->meth) {
|
||||
if (EC_GROUP_cmp(group, point->group, NULL) != 0) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
|
||||
return 0;
|
||||
}
|
||||
@@ -674,7 +708,7 @@ int EC_POINT_set_to_infinity(const EC_GROUP *group, EC_POINT *point) {
|
||||
}
|
||||
|
||||
int EC_POINT_is_at_infinity(const EC_GROUP *group, const EC_POINT *point) {
|
||||
if (group->meth != point->meth) {
|
||||
if (EC_GROUP_cmp(group, point->group, NULL) != 0) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
|
||||
return 0;
|
||||
}
|
||||
@@ -683,7 +717,7 @@ int EC_POINT_is_at_infinity(const EC_GROUP *group, const EC_POINT *point) {
|
||||
|
||||
int EC_POINT_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
|
||||
BN_CTX *ctx) {
|
||||
if (group->meth != point->meth) {
|
||||
if (EC_GROUP_cmp(group, point->group, NULL) != 0) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
|
||||
return 0;
|
||||
}
|
||||
@@ -692,7 +726,8 @@ int EC_POINT_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
|
||||
|
||||
int EC_POINT_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b,
|
||||
BN_CTX *ctx) {
|
||||
if ((group->meth != a->meth) || (a->meth != b->meth)) {
|
||||
if (EC_GROUP_cmp(group, a->group, NULL) != 0 ||
|
||||
EC_GROUP_cmp(group, b->group, NULL) != 0) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
|
||||
return -1;
|
||||
}
|
||||
@@ -700,7 +735,7 @@ int EC_POINT_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b,
|
||||
}
|
||||
|
||||
int EC_POINT_make_affine(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) {
|
||||
if (group->meth != point->meth) {
|
||||
if (EC_GROUP_cmp(group, point->group, NULL) != 0) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
|
||||
return 0;
|
||||
}
|
||||
@@ -710,7 +745,7 @@ int EC_POINT_make_affine(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) {
|
||||
int EC_POINTs_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[],
|
||||
BN_CTX *ctx) {
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
if (group->meth != points[i]->meth) {
|
||||
if (EC_GROUP_cmp(group, points[i]->group, NULL) != 0) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
|
||||
return 0;
|
||||
}
|
||||
@@ -725,7 +760,7 @@ int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group,
|
||||
OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||||
return 0;
|
||||
}
|
||||
if (group->meth != point->meth) {
|
||||
if (EC_GROUP_cmp(group, point->group, NULL) != 0) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
|
||||
return 0;
|
||||
}
|
||||
@@ -735,7 +770,7 @@ int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group,
|
||||
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->meth) {
|
||||
if (EC_GROUP_cmp(group, point->group, NULL) != 0) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
|
||||
return 0;
|
||||
}
|
||||
@@ -753,8 +788,9 @@ int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *point,
|
||||
|
||||
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 != r->meth) || (r->meth != a->meth) ||
|
||||
(a->meth != b->meth)) {
|
||||
if (EC_GROUP_cmp(group, r->group, NULL) != 0 ||
|
||||
EC_GROUP_cmp(group, a->group, NULL) != 0 ||
|
||||
EC_GROUP_cmp(group, b->group, NULL) != 0) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
|
||||
return 0;
|
||||
}
|
||||
@@ -764,7 +800,8 @@ int EC_POINT_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
|
||||
|
||||
int EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
|
||||
BN_CTX *ctx) {
|
||||
if ((group->meth != r->meth) || (r->meth != a->meth)) {
|
||||
if (EC_GROUP_cmp(group, r->group, NULL) != 0 ||
|
||||
EC_GROUP_cmp(group, a->group, NULL) != 0) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
|
||||
return 0;
|
||||
}
|
||||
@@ -773,7 +810,7 @@ int EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
|
||||
|
||||
|
||||
int EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, BN_CTX *ctx) {
|
||||
if (group->meth != a->meth) {
|
||||
if (EC_GROUP_cmp(group, a->group, NULL) != 0) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
|
||||
return 0;
|
||||
}
|
||||
@@ -786,13 +823,59 @@ int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,
|
||||
// nothing to multiply. But, nobody should be calling this function with
|
||||
// nothing to multiply in the first place.
|
||||
if ((g_scalar == NULL && p_scalar == NULL) ||
|
||||
((p == NULL) != (p_scalar == NULL))) {
|
||||
(p == NULL) != (p_scalar == NULL)) {
|
||||
OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (group->meth != r->meth ||
|
||||
(p != NULL && group->meth != p->meth)) {
|
||||
// We cannot easily process arbitrary scalars in constant-time, and there is
|
||||
// no need to do so. Require that scalars be the same size as the order.
|
||||
//
|
||||
// One could require they be fully reduced, but some consumers try to check
|
||||
// that |order| * |pubkey| is the identity. This comes from following NIST SP
|
||||
// 800-56A section 5.6.2.3.2. (Though all our curves have cofactor one, so
|
||||
// this check isn't useful.)
|
||||
int ret = 0;
|
||||
EC_SCALAR g_scalar_storage, p_scalar_storage;
|
||||
EC_SCALAR *g_scalar_arg = NULL, *p_scalar_arg = NULL;
|
||||
unsigned order_bits = BN_num_bits(&group->order);
|
||||
if (g_scalar != NULL) {
|
||||
if (BN_is_negative(g_scalar) || BN_num_bits(g_scalar) > order_bits ||
|
||||
!ec_bignum_to_scalar(group, &g_scalar_storage, g_scalar)) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR);
|
||||
goto err;
|
||||
}
|
||||
g_scalar_arg = &g_scalar_storage;
|
||||
}
|
||||
|
||||
if (p_scalar != NULL) {
|
||||
if (BN_is_negative(p_scalar) || BN_num_bits(p_scalar) > order_bits ||
|
||||
!ec_bignum_to_scalar(group, &p_scalar_storage, p_scalar)) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR);
|
||||
goto err;
|
||||
}
|
||||
p_scalar_arg = &p_scalar_storage;
|
||||
}
|
||||
|
||||
ret = ec_point_mul_scalar(group, r, g_scalar_arg, p, p_scalar_arg, ctx);
|
||||
|
||||
err:
|
||||
OPENSSL_cleanse(&g_scalar_storage, sizeof(g_scalar_storage));
|
||||
OPENSSL_cleanse(&p_scalar_storage, sizeof(p_scalar_storage));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ec_point_mul_scalar(const EC_GROUP *group, EC_POINT *r,
|
||||
const EC_SCALAR *g_scalar, const EC_POINT *p,
|
||||
const EC_SCALAR *p_scalar, BN_CTX *ctx) {
|
||||
if ((g_scalar == NULL && p_scalar == NULL) ||
|
||||
(p == NULL) != (p_scalar == NULL)) {
|
||||
OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (EC_GROUP_cmp(group, r->group, NULL) != 0 ||
|
||||
(p != NULL && EC_GROUP_cmp(group, p->group, NULL) != 0)) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
|
||||
return 0;
|
||||
}
|
||||
@@ -804,7 +887,7 @@ 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->meth) {
|
||||
if (EC_GROUP_cmp(group, point->group, NULL) != 0) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
|
||||
return 0;
|
||||
}
|
||||
@@ -841,3 +924,20 @@ size_t EC_get_builtin_curves(EC_builtin_curve *out_curves,
|
||||
|
||||
return OPENSSL_NUM_BUILT_IN_CURVES;
|
||||
}
|
||||
|
||||
int ec_bignum_to_scalar(const EC_GROUP *group, EC_SCALAR *out,
|
||||
const BIGNUM *in) {
|
||||
if (BN_is_negative(in) || in->top > group->order.top) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR);
|
||||
return 0;
|
||||
}
|
||||
OPENSSL_memset(out->words, 0, group->order.top * sizeof(BN_ULONG));
|
||||
OPENSSL_memcpy(out->words, in->d, in->top * sizeof(BN_ULONG));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ec_random_nonzero_scalar(const EC_GROUP *group, EC_SCALAR *out,
|
||||
const uint8_t additional_data[32]) {
|
||||
return bn_rand_range_words(out->words, 1, group->order.d, group->order.top,
|
||||
additional_data);
|
||||
}
|
||||
|
||||
@@ -156,7 +156,6 @@ void EC_KEY_free(EC_KEY *r) {
|
||||
|
||||
CRYPTO_free_ex_data(g_ec_ex_data_class_bss_get(), r, &r->ex_data);
|
||||
|
||||
OPENSSL_cleanse((void *)r, sizeof(EC_KEY));
|
||||
OPENSSL_free(r);
|
||||
}
|
||||
|
||||
|
||||
@@ -90,32 +90,6 @@ void ec_GFp_mont_group_finish(EC_GROUP *group) {
|
||||
ec_GFp_simple_group_finish(group);
|
||||
}
|
||||
|
||||
int ec_GFp_mont_group_copy(EC_GROUP *dest, const EC_GROUP *src) {
|
||||
BN_MONT_CTX_free(dest->mont);
|
||||
dest->mont = NULL;
|
||||
|
||||
if (!ec_GFp_simple_group_copy(dest, src)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (src->mont != NULL) {
|
||||
dest->mont = BN_MONT_CTX_new();
|
||||
if (dest->mont == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if (!BN_MONT_CTX_copy(dest->mont, src->mont)) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
err:
|
||||
BN_MONT_CTX_free(dest->mont);
|
||||
dest->mont = 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;
|
||||
@@ -293,7 +267,6 @@ err:
|
||||
DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_mont_method) {
|
||||
out->group_init = ec_GFp_mont_group_init;
|
||||
out->group_finish = ec_GFp_mont_group_finish;
|
||||
out->group_copy = ec_GFp_mont_group_copy;
|
||||
out->group_set_curve = ec_GFp_mont_group_set_curve;
|
||||
out->point_get_affine_coordinates = ec_GFp_mont_point_get_affine_coordinates;
|
||||
out->mul = ec_wNAF_mul /* XXX: Not constant time. */;
|
||||
|
||||
@@ -276,6 +276,33 @@ TEST(ECTest, ArbitraryCurve) {
|
||||
|
||||
// The key must be valid according to the new group too.
|
||||
EXPECT_TRUE(EC_KEY_check_key(key2.get()));
|
||||
|
||||
// Make a second instance of |group|.
|
||||
bssl::UniquePtr<EC_GROUP> group2(
|
||||
EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
|
||||
ASSERT_TRUE(group2);
|
||||
bssl::UniquePtr<EC_POINT> generator2(EC_POINT_new(group2.get()));
|
||||
ASSERT_TRUE(generator2);
|
||||
ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
|
||||
group2.get(), generator2.get(), gx.get(), gy.get(), ctx.get()));
|
||||
ASSERT_TRUE(EC_GROUP_set_generator(group2.get(), generator2.get(),
|
||||
order.get(), BN_value_one()));
|
||||
|
||||
EXPECT_EQ(0, EC_GROUP_cmp(group.get(), group.get(), NULL));
|
||||
EXPECT_EQ(0, EC_GROUP_cmp(group2.get(), group.get(), NULL));
|
||||
|
||||
// group3 uses the wrong generator.
|
||||
bssl::UniquePtr<EC_GROUP> group3(
|
||||
EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
|
||||
ASSERT_TRUE(group3);
|
||||
bssl::UniquePtr<EC_POINT> generator3(EC_POINT_new(group3.get()));
|
||||
ASSERT_TRUE(generator3);
|
||||
ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
|
||||
group3.get(), generator3.get(), x.get(), y.get(), ctx.get()));
|
||||
ASSERT_TRUE(EC_GROUP_set_generator(group3.get(), generator3.get(),
|
||||
order.get(), BN_value_one()));
|
||||
|
||||
EXPECT_NE(0, EC_GROUP_cmp(group.get(), group3.get(), NULL));
|
||||
}
|
||||
|
||||
class ECCurveTest : public testing::TestWithParam<EC_builtin_curve> {};
|
||||
@@ -380,6 +407,38 @@ TEST_P(ECCurveTest, MulZero) {
|
||||
<< "p * 0 did not return point at infinity.";
|
||||
}
|
||||
|
||||
// Test that multiplying by the order produces ∞ and, moreover, that callers may
|
||||
// do so. |EC_POINT_mul| is almost exclusively used with reduced scalars, with
|
||||
// this exception. This comes from consumers following NIST SP 800-56A section
|
||||
// 5.6.2.3.2. (Though all our curves have cofactor one, so this check isn't
|
||||
// useful.)
|
||||
TEST_P(ECCurveTest, MulOrder) {
|
||||
bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid));
|
||||
ASSERT_TRUE(group);
|
||||
|
||||
// Test that g × order = ∞.
|
||||
bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group.get()));
|
||||
ASSERT_TRUE(point);
|
||||
ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(),
|
||||
EC_GROUP_get0_order(group.get()), nullptr, nullptr,
|
||||
nullptr));
|
||||
|
||||
EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), point.get()))
|
||||
<< "g * order did not return point at infinity.";
|
||||
|
||||
// Test that p × order = ∞, for some arbitrary p.
|
||||
bssl::UniquePtr<BIGNUM> forty_two(BN_new());
|
||||
ASSERT_TRUE(forty_two);
|
||||
ASSERT_TRUE(BN_set_word(forty_two.get(), 42));
|
||||
ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(), forty_two.get(), nullptr,
|
||||
nullptr, nullptr));
|
||||
ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(), nullptr, point.get(),
|
||||
EC_GROUP_get0_order(group.get()), nullptr));
|
||||
|
||||
EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), point.get()))
|
||||
<< "p * order did not return point at infinity.";
|
||||
}
|
||||
|
||||
// Test that 10×∞ + G = G.
|
||||
TEST_P(ECCurveTest, Mul) {
|
||||
bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid));
|
||||
|
||||
@@ -73,16 +73,37 @@
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/ex_data.h>
|
||||
#include <openssl/thread.h>
|
||||
#include <openssl/type_check.h>
|
||||
|
||||
#include "../bn/internal.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
// Cap the size of all field elements and scalars, including custom curves, to
|
||||
// 66 bytes, large enough to fit secp521r1 and brainpoolP512r1, which appear to
|
||||
// be the largest fields anyone plausibly uses.
|
||||
#define EC_MAX_SCALAR_BYTES 66
|
||||
#define EC_MAX_SCALAR_WORDS ((66 + BN_BYTES - 1) / BN_BYTES)
|
||||
|
||||
OPENSSL_COMPILE_ASSERT(EC_MAX_SCALAR_WORDS <= BN_SMALL_MAX_WORDS,
|
||||
bn_small_functions_applicable);
|
||||
|
||||
// An EC_SCALAR is a |BN_num_bits(order)|-bit integer. Only the first
|
||||
// |order->top| words are used. An |EC_SCALAR| is specific to an |EC_GROUP| and
|
||||
// must not be mixed between groups. Unless otherwise specified, it is fully
|
||||
// reduced modulo the |order|.
|
||||
typedef union {
|
||||
// bytes is the representation of the scalar in little-endian order.
|
||||
uint8_t bytes[EC_MAX_SCALAR_BYTES];
|
||||
BN_ULONG words[EC_MAX_SCALAR_WORDS];
|
||||
} EC_SCALAR;
|
||||
|
||||
struct ec_method_st {
|
||||
int (*group_init)(EC_GROUP *);
|
||||
void (*group_finish)(EC_GROUP *);
|
||||
int (*group_copy)(EC_GROUP *, const EC_GROUP *);
|
||||
int (*group_set_curve)(EC_GROUP *, const BIGNUM *p, const BIGNUM *a,
|
||||
const BIGNUM *b, BN_CTX *);
|
||||
int (*point_get_affine_coordinates)(const EC_GROUP *, const EC_POINT *,
|
||||
@@ -93,8 +114,8 @@ struct ec_method_st {
|
||||
// Computes |r = p_scalar*p| if g_scalar is null. At least one of |g_scalar|
|
||||
// and |p_scalar| must be non-null, and |p| must be non-null if |p_scalar| is
|
||||
// non-null.
|
||||
int (*mul)(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,
|
||||
const EC_POINT *p, const BIGNUM *p_scalar, BN_CTX *ctx);
|
||||
int (*mul)(const EC_GROUP *group, EC_POINT *r, const EC_SCALAR *g_scalar,
|
||||
const EC_POINT *p, const EC_SCALAR *p_scalar, BN_CTX *ctx);
|
||||
|
||||
// 'field_mul' and 'field_sqr' can be used by 'add' and 'dbl' so that the
|
||||
// same implementations of point operations can be used with different
|
||||
@@ -114,12 +135,14 @@ const EC_METHOD *EC_GFp_mont_method(void);
|
||||
struct ec_group_st {
|
||||
const EC_METHOD *meth;
|
||||
|
||||
// Unlike all other |EC_POINT|s, |generator| does not own |generator->group|
|
||||
// to avoid a reference cycle.
|
||||
EC_POINT *generator;
|
||||
BIGNUM order;
|
||||
|
||||
int curve_name; // optional NID for named curve
|
||||
|
||||
const BN_MONT_CTX *order_mont; // data for ECDSA inverse
|
||||
BN_MONT_CTX *order_mont; // data for ECDSA inverse
|
||||
|
||||
// The following members are handled by the method functions,
|
||||
// even if they appear generic
|
||||
@@ -130,13 +153,17 @@ struct ec_group_st {
|
||||
|
||||
int a_is_minus3; // enable optimized point arithmetics for special case
|
||||
|
||||
CRYPTO_refcount_t references;
|
||||
|
||||
BN_MONT_CTX *mont; // Montgomery structure.
|
||||
|
||||
BIGNUM one; // The value one.
|
||||
} /* EC_GROUP */;
|
||||
|
||||
struct ec_point_st {
|
||||
const EC_METHOD *meth;
|
||||
// group is an owning reference to |group|, unless this is
|
||||
// |group->generator|.
|
||||
EC_GROUP *group;
|
||||
|
||||
BIGNUM X;
|
||||
BIGNUM Y;
|
||||
@@ -145,20 +172,33 @@ struct ec_point_st {
|
||||
} /* EC_POINT */;
|
||||
|
||||
EC_GROUP *ec_group_new(const EC_METHOD *meth);
|
||||
int ec_group_copy(EC_GROUP *dest, const EC_GROUP *src);
|
||||
|
||||
// ec_group_get_order_mont returns a Montgomery context for operations modulo
|
||||
// |group|'s order. It may return NULL in the case that |group| is not a
|
||||
// built-in group.
|
||||
const BN_MONT_CTX *ec_group_get_order_mont(const EC_GROUP *group);
|
||||
// ec_bignum_to_scalar converts |in| to an |EC_SCALAR| and writes it to |*out|.
|
||||
// |in| must be non-negative and have at most |BN_num_bits(&group->order)| bits.
|
||||
// It returns one on success and zero on error. It does not ensure |in| is fully
|
||||
// reduced.
|
||||
int ec_bignum_to_scalar(const EC_GROUP *group, EC_SCALAR *out,
|
||||
const BIGNUM *in);
|
||||
|
||||
int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,
|
||||
const EC_POINT *p, const BIGNUM *p_scalar, BN_CTX *ctx);
|
||||
// ec_random_nonzero_scalar sets |out| to a uniformly selected random value from
|
||||
// 1 to |group->order| - 1. It returns one on success and zero on error.
|
||||
int ec_random_nonzero_scalar(const EC_GROUP *group, EC_SCALAR *out,
|
||||
const uint8_t additional_data[32]);
|
||||
|
||||
// ec_point_mul_scalar sets |r| to generator * |g_scalar| + |p| *
|
||||
// |p_scalar|. Unlike other functions which take |EC_SCALAR|, |g_scalar| and
|
||||
// |p_scalar| need not be fully reduced. They need only contain as many bits as
|
||||
// the order.
|
||||
int ec_point_mul_scalar(const EC_GROUP *group, EC_POINT *r,
|
||||
const EC_SCALAR *g_scalar, const EC_POINT *p,
|
||||
const EC_SCALAR *p_scalar, BN_CTX *ctx);
|
||||
|
||||
int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const EC_SCALAR *g_scalar,
|
||||
const EC_POINT *p, const EC_SCALAR *p_scalar, BN_CTX *ctx);
|
||||
|
||||
// method functions in simple.c
|
||||
int ec_GFp_simple_group_init(EC_GROUP *);
|
||||
void ec_GFp_simple_group_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,
|
||||
@@ -166,17 +206,12 @@ int ec_GFp_simple_group_get_curve(const EC_GROUP *, BIGNUM *p, BIGNUM *a,
|
||||
unsigned ec_GFp_simple_group_get_degree(const EC_GROUP *);
|
||||
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 *);
|
||||
@@ -205,7 +240,6 @@ 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 *);
|
||||
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,
|
||||
|
||||
@@ -251,7 +251,7 @@ err:
|
||||
|
||||
int EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *point,
|
||||
const uint8_t *buf, size_t len, BN_CTX *ctx) {
|
||||
if (group->meth != point->meth) {
|
||||
if (EC_GROUP_cmp(group, point->group, NULL) != 0) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
|
||||
return 0;
|
||||
}
|
||||
@@ -261,7 +261,7 @@ int EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *point,
|
||||
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 != point->meth) {
|
||||
if (EC_GROUP_cmp(group, point->group, NULL) != 0) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
|
||||
return 0;
|
||||
}
|
||||
@@ -396,7 +396,7 @@ err:
|
||||
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->meth) {
|
||||
if (EC_GROUP_cmp(group, point->group, NULL) != 0) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1038,14 +1038,13 @@ static int ec_GFp_nistp224_point_get_affine_coordinates(const EC_GROUP *group,
|
||||
}
|
||||
|
||||
static int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r,
|
||||
const BIGNUM *g_scalar, const EC_POINT *p,
|
||||
const BIGNUM *p_scalar, BN_CTX *ctx) {
|
||||
const EC_SCALAR *g_scalar,
|
||||
const EC_POINT *p,
|
||||
const EC_SCALAR *p_scalar, BN_CTX *ctx) {
|
||||
int ret = 0;
|
||||
BN_CTX *new_ctx = NULL;
|
||||
BIGNUM *x, *y, *z, *tmp_scalar;
|
||||
p224_felem_bytearray g_secret, p_secret;
|
||||
p224_felem p_pre_comp[17][3];
|
||||
p224_felem_bytearray tmp;
|
||||
p224_felem x_in, y_in, z_in, x_out, y_out, z_out;
|
||||
|
||||
if (ctx == NULL) {
|
||||
@@ -1067,23 +1066,7 @@ static int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r,
|
||||
if (p != NULL && p_scalar != NULL) {
|
||||
// We treat NULL scalars as 0, and NULL points as points at infinity, i.e.,
|
||||
// they contribute nothing to the linear combination.
|
||||
OPENSSL_memset(&p_secret, 0, sizeof(p_secret));
|
||||
OPENSSL_memset(&p_pre_comp, 0, sizeof(p_pre_comp));
|
||||
size_t num_bytes;
|
||||
// reduce g_scalar to 0 <= g_scalar < 2^224
|
||||
if (BN_num_bits(p_scalar) > 224 || BN_is_negative(p_scalar)) {
|
||||
// this is an unusual input, and we don't guarantee
|
||||
// constant-timeness
|
||||
if (!BN_nnmod(tmp_scalar, p_scalar, &group->order, ctx)) {
|
||||
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
|
||||
goto err;
|
||||
}
|
||||
num_bytes = BN_bn2bin(tmp_scalar, tmp);
|
||||
} else {
|
||||
num_bytes = BN_bn2bin(p_scalar, tmp);
|
||||
}
|
||||
|
||||
p224_flip_endian(p_secret, tmp, num_bytes);
|
||||
// precompute multiples
|
||||
if (!p224_BN_to_felem(x_out, &p->X) ||
|
||||
!p224_BN_to_felem(y_out, &p->Y) ||
|
||||
@@ -1109,26 +1092,10 @@ static int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r,
|
||||
}
|
||||
}
|
||||
|
||||
if (g_scalar != NULL) {
|
||||
OPENSSL_memset(g_secret, 0, sizeof(g_secret));
|
||||
size_t num_bytes;
|
||||
// reduce g_scalar to 0 <= g_scalar < 2^224
|
||||
if (BN_num_bits(g_scalar) > 224 || BN_is_negative(g_scalar)) {
|
||||
// this is an unusual input, and we don't guarantee constant-timeness
|
||||
if (!BN_nnmod(tmp_scalar, g_scalar, &group->order, ctx)) {
|
||||
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
|
||||
goto err;
|
||||
}
|
||||
num_bytes = BN_bn2bin(tmp_scalar, tmp);
|
||||
} else {
|
||||
num_bytes = BN_bn2bin(g_scalar, tmp);
|
||||
}
|
||||
|
||||
p224_flip_endian(g_secret, tmp, num_bytes);
|
||||
}
|
||||
p224_batch_mul(
|
||||
x_out, y_out, z_out, (p != NULL && p_scalar != NULL) ? p_secret : NULL,
|
||||
g_scalar != NULL ? g_secret : NULL, (const p224_felem(*)[3])p_pre_comp);
|
||||
p224_batch_mul(x_out, y_out, z_out,
|
||||
(p != NULL && p_scalar != NULL) ? p_scalar->bytes : NULL,
|
||||
g_scalar != NULL ? g_scalar->bytes : NULL,
|
||||
(const p224_felem(*)[3])p_pre_comp);
|
||||
|
||||
// reduce the output to its unique minimal representation
|
||||
p224_felem_contract(x_in, x_out);
|
||||
@@ -1151,7 +1118,6 @@ err:
|
||||
DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_nistp224_method) {
|
||||
out->group_init = ec_GFp_simple_group_init;
|
||||
out->group_finish = ec_GFp_simple_group_finish;
|
||||
out->group_copy = ec_GFp_simple_group_copy;
|
||||
out->group_set_curve = ec_GFp_simple_group_set_curve;
|
||||
out->point_get_affine_coordinates =
|
||||
ec_GFp_nistp224_point_get_affine_coordinates;
|
||||
|
||||
@@ -1582,14 +1582,13 @@ static int ec_GFp_nistp256_point_get_affine_coordinates(const EC_GROUP *group,
|
||||
}
|
||||
|
||||
static int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r,
|
||||
const BIGNUM *g_scalar, const EC_POINT *p,
|
||||
const BIGNUM *p_scalar, BN_CTX *ctx) {
|
||||
const EC_SCALAR *g_scalar,
|
||||
const EC_POINT *p,
|
||||
const EC_SCALAR *p_scalar, BN_CTX *ctx) {
|
||||
int ret = 0;
|
||||
BN_CTX *new_ctx = NULL;
|
||||
BIGNUM *x, *y, *z, *tmp_scalar;
|
||||
felem_bytearray g_secret, p_secret;
|
||||
smallfelem p_pre_comp[17][3];
|
||||
felem_bytearray tmp;
|
||||
smallfelem x_in, y_in, z_in;
|
||||
felem x_out, y_out, z_out;
|
||||
|
||||
@@ -1611,21 +1610,7 @@ static int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r,
|
||||
if (p != NULL && p_scalar != NULL) {
|
||||
// We treat NULL scalars as 0, and NULL points as points at infinity, i.e.,
|
||||
// they contribute nothing to the linear combination.
|
||||
OPENSSL_memset(&p_secret, 0, sizeof(p_secret));
|
||||
OPENSSL_memset(&p_pre_comp, 0, sizeof(p_pre_comp));
|
||||
size_t num_bytes;
|
||||
// Reduce g_scalar to 0 <= g_scalar < 2^256.
|
||||
if (BN_num_bits(p_scalar) > 256 || BN_is_negative(p_scalar)) {
|
||||
// This is an unusual input, and we don't guarantee constant-timeness.
|
||||
if (!BN_nnmod(tmp_scalar, p_scalar, &group->order, ctx)) {
|
||||
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
|
||||
goto err;
|
||||
}
|
||||
num_bytes = BN_bn2bin(tmp_scalar, tmp);
|
||||
} else {
|
||||
num_bytes = BN_bn2bin(p_scalar, tmp);
|
||||
}
|
||||
flip_endian(p_secret, tmp, num_bytes);
|
||||
// Precompute multiples.
|
||||
if (!BN_to_felem(x_out, &p->X) ||
|
||||
!BN_to_felem(y_out, &p->Y) ||
|
||||
@@ -1650,28 +1635,10 @@ static int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r,
|
||||
}
|
||||
}
|
||||
|
||||
if (g_scalar != NULL) {
|
||||
size_t num_bytes;
|
||||
|
||||
OPENSSL_memset(g_secret, 0, sizeof(g_secret));
|
||||
// reduce g_scalar to 0 <= g_scalar < 2^256
|
||||
if (BN_num_bits(g_scalar) > 256 || BN_is_negative(g_scalar)) {
|
||||
// this is an unusual input, and we don't guarantee
|
||||
// constant-timeness.
|
||||
if (!BN_nnmod(tmp_scalar, g_scalar, &group->order, ctx)) {
|
||||
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
|
||||
goto err;
|
||||
}
|
||||
num_bytes = BN_bn2bin(tmp_scalar, tmp);
|
||||
} else {
|
||||
num_bytes = BN_bn2bin(g_scalar, tmp);
|
||||
}
|
||||
flip_endian(g_secret, tmp, num_bytes);
|
||||
}
|
||||
batch_mul(x_out, y_out, z_out,
|
||||
(p != NULL && p_scalar != NULL) ? p_secret : NULL,
|
||||
g_scalar != NULL ? g_secret : NULL,
|
||||
(const smallfelem(*)[3]) &p_pre_comp);
|
||||
(p != NULL && p_scalar != NULL) ? p_scalar->bytes : NULL,
|
||||
g_scalar != NULL ? g_scalar->bytes : NULL,
|
||||
(const smallfelem(*)[3]) & p_pre_comp);
|
||||
|
||||
// reduce the output to its unique minimal representation
|
||||
felem_contract(x_in, x_out);
|
||||
@@ -1694,7 +1661,6 @@ err:
|
||||
DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_nistp256_method) {
|
||||
out->group_init = ec_GFp_simple_group_init;
|
||||
out->group_finish = ec_GFp_simple_group_finish;
|
||||
out->group_copy = ec_GFp_simple_group_copy;
|
||||
out->group_set_curve = ec_GFp_simple_group_set_curve;
|
||||
out->point_get_affine_coordinates =
|
||||
ec_GFp_nistp256_point_get_affine_coordinates;
|
||||
|
||||
@@ -216,8 +216,8 @@ static int ecp_nistz256_bignum_to_field_elem(BN_ULONG out[P256_LIMBS],
|
||||
|
||||
// r = p * p_scalar
|
||||
static int ecp_nistz256_windowed_mul(const EC_GROUP *group, P256_POINT *r,
|
||||
const EC_POINT *p, const BIGNUM *p_scalar,
|
||||
BN_CTX *ctx) {
|
||||
const EC_POINT *p,
|
||||
const EC_SCALAR *p_scalar) {
|
||||
assert(p != NULL);
|
||||
assert(p_scalar != NULL);
|
||||
|
||||
@@ -229,55 +229,8 @@ static int ecp_nistz256_windowed_mul(const EC_GROUP *group, P256_POINT *r,
|
||||
// ~1599 ((96 * 16) + 63) bytes of stack space.
|
||||
alignas(64) P256_POINT table[16];
|
||||
uint8_t p_str[33];
|
||||
|
||||
|
||||
int ret = 0;
|
||||
BN_CTX *new_ctx = NULL;
|
||||
int ctx_started = 0;
|
||||
|
||||
if (BN_num_bits(p_scalar) > 256 || BN_is_negative(p_scalar)) {
|
||||
if (ctx == NULL) {
|
||||
new_ctx = BN_CTX_new();
|
||||
if (new_ctx == NULL) {
|
||||
OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
ctx = new_ctx;
|
||||
}
|
||||
BN_CTX_start(ctx);
|
||||
ctx_started = 1;
|
||||
BIGNUM *mod = BN_CTX_get(ctx);
|
||||
if (mod == NULL) {
|
||||
OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
if (!BN_nnmod(mod, p_scalar, &group->order, ctx)) {
|
||||
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
|
||||
goto err;
|
||||
}
|
||||
p_scalar = mod;
|
||||
}
|
||||
|
||||
int j;
|
||||
for (j = 0; j < p_scalar->top * BN_BYTES; j += BN_BYTES) {
|
||||
BN_ULONG d = p_scalar->d[j / BN_BYTES];
|
||||
|
||||
p_str[j + 0] = d & 0xff;
|
||||
p_str[j + 1] = (d >> 8) & 0xff;
|
||||
p_str[j + 2] = (d >> 16) & 0xff;
|
||||
p_str[j + 3] = (d >>= 24) & 0xff;
|
||||
if (BN_BYTES == 8) {
|
||||
d >>= 8;
|
||||
p_str[j + 4] = d & 0xff;
|
||||
p_str[j + 5] = (d >> 8) & 0xff;
|
||||
p_str[j + 6] = (d >> 16) & 0xff;
|
||||
p_str[j + 7] = (d >> 24) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
for (; j < 33; j++) {
|
||||
p_str[j] = 0;
|
||||
}
|
||||
OPENSSL_memcpy(p_str, p_scalar->bytes, 32);
|
||||
p_str[32] = 0;
|
||||
|
||||
// table[0] is implicitly (0,0,0) (the point at infinity), therefore it is
|
||||
// not stored. All other values are actually stored with an offset of -1 in
|
||||
@@ -288,7 +241,7 @@ static int ecp_nistz256_windowed_mul(const EC_GROUP *group, P256_POINT *r,
|
||||
!ecp_nistz256_bignum_to_field_elem(row[1 - 1].Y, &p->Y) ||
|
||||
!ecp_nistz256_bignum_to_field_elem(row[1 - 1].Z, &p->Z)) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_COORDINATES_OUT_OF_RANGE);
|
||||
goto err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ecp_nistz256_point_double(&row[2 - 1], &row[1 - 1]);
|
||||
@@ -354,19 +307,13 @@ static int ecp_nistz256_windowed_mul(const EC_GROUP *group, P256_POINT *r,
|
||||
|
||||
ecp_nistz256_point_add(r, r, &h);
|
||||
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
if (ctx_started) {
|
||||
BN_CTX_end(ctx);
|
||||
}
|
||||
BN_CTX_free(new_ctx);
|
||||
return ret;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ecp_nistz256_points_mul(
|
||||
const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,
|
||||
const EC_POINT *p_, const BIGNUM *p_scalar, BN_CTX *ctx) {
|
||||
static int ecp_nistz256_points_mul(const EC_GROUP *group, EC_POINT *r,
|
||||
const EC_SCALAR *g_scalar,
|
||||
const EC_POINT *p_,
|
||||
const EC_SCALAR *p_scalar, BN_CTX *ctx) {
|
||||
assert((p_ != NULL) == (p_scalar != NULL));
|
||||
|
||||
static const unsigned kWindowSize = 7;
|
||||
@@ -377,54 +324,10 @@ static int ecp_nistz256_points_mul(
|
||||
P256_POINT_AFFINE a;
|
||||
} t, p;
|
||||
|
||||
int ret = 0;
|
||||
BN_CTX *new_ctx = NULL;
|
||||
int ctx_started = 0;
|
||||
|
||||
if (g_scalar != NULL) {
|
||||
if (BN_num_bits(g_scalar) > 256 || BN_is_negative(g_scalar)) {
|
||||
if (ctx == NULL) {
|
||||
new_ctx = BN_CTX_new();
|
||||
if (new_ctx == NULL) {
|
||||
goto err;
|
||||
}
|
||||
ctx = new_ctx;
|
||||
}
|
||||
BN_CTX_start(ctx);
|
||||
ctx_started = 1;
|
||||
BIGNUM *tmp_scalar = BN_CTX_get(ctx);
|
||||
if (tmp_scalar == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!BN_nnmod(tmp_scalar, g_scalar, &group->order, ctx)) {
|
||||
OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
|
||||
goto err;
|
||||
}
|
||||
g_scalar = tmp_scalar;
|
||||
}
|
||||
|
||||
uint8_t p_str[33] = {0};
|
||||
int i;
|
||||
for (i = 0; i < g_scalar->top * BN_BYTES; i += BN_BYTES) {
|
||||
BN_ULONG d = g_scalar->d[i / BN_BYTES];
|
||||
|
||||
p_str[i + 0] = d & 0xff;
|
||||
p_str[i + 1] = (d >> 8) & 0xff;
|
||||
p_str[i + 2] = (d >> 16) & 0xff;
|
||||
p_str[i + 3] = (d >>= 24) & 0xff;
|
||||
if (BN_BYTES == 8) {
|
||||
d >>= 8;
|
||||
p_str[i + 4] = d & 0xff;
|
||||
p_str[i + 5] = (d >> 8) & 0xff;
|
||||
p_str[i + 6] = (d >> 16) & 0xff;
|
||||
p_str[i + 7] = (d >> 24) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
for (; i < (int) sizeof(p_str); i++) {
|
||||
p_str[i] = 0;
|
||||
}
|
||||
uint8_t p_str[33];
|
||||
OPENSSL_memcpy(p_str, g_scalar->bytes, 32);
|
||||
p_str[32] = 0;
|
||||
|
||||
// First window
|
||||
unsigned wvalue = (p_str[0] << 1) & kMask;
|
||||
@@ -445,7 +348,7 @@ static int ecp_nistz256_points_mul(
|
||||
OPENSSL_memset(p.p.Z, 0, sizeof(p.p.Z));
|
||||
copy_conditional(p.p.Z, ONE, is_not_zero(wvalue >> 1));
|
||||
|
||||
for (i = 1; i < 37; i++) {
|
||||
for (int i = 1; i < 37; i++) {
|
||||
unsigned off = (index - 1) / 8;
|
||||
wvalue = p_str[off] | p_str[off + 1] << 8;
|
||||
wvalue = (wvalue >> ((index - 1) % 8)) & kMask;
|
||||
@@ -469,8 +372,8 @@ static int ecp_nistz256_points_mul(
|
||||
out = &p.p;
|
||||
}
|
||||
|
||||
if (!ecp_nistz256_windowed_mul(group, out, p_, p_scalar, ctx)) {
|
||||
goto err;
|
||||
if (!ecp_nistz256_windowed_mul(group, out, p_, p_scalar)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!p_is_infinity) {
|
||||
@@ -485,14 +388,7 @@ static int ecp_nistz256_points_mul(
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
if (ctx_started) {
|
||||
BN_CTX_end(ctx);
|
||||
}
|
||||
BN_CTX_free(new_ctx);
|
||||
return ret;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ecp_nistz256_get_affine(const EC_GROUP *group, const EC_POINT *point,
|
||||
@@ -547,7 +443,6 @@ static int ecp_nistz256_get_affine(const EC_GROUP *group, const EC_POINT *point,
|
||||
DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_nistz256_method) {
|
||||
out->group_init = ec_GFp_mont_group_init;
|
||||
out->group_finish = ec_GFp_mont_group_finish;
|
||||
out->group_copy = ec_GFp_mont_group_copy;
|
||||
out->group_set_curve = ec_GFp_mont_group_set_curve;
|
||||
out->point_get_affine_coordinates = ecp_nistz256_get_affine;
|
||||
out->mul = ecp_nistz256_points_mul;
|
||||
|
||||
@@ -104,18 +104,6 @@ void ec_GFp_simple_group_finish(EC_GROUP *group) {
|
||||
BN_free(&group->one);
|
||||
}
|
||||
|
||||
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) ||
|
||||
!BN_copy(&dest->one, &src->one)) {
|
||||
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) {
|
||||
@@ -249,12 +237,6 @@ void ec_GFp_simple_point_finish(EC_POINT *point) {
|
||||
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);
|
||||
}
|
||||
|
||||
int ec_GFp_simple_point_copy(EC_POINT *dest, const EC_POINT *src) {
|
||||
if (!BN_copy(&dest->X, &src->X) ||
|
||||
!BN_copy(&dest->Y, &src->Y) ||
|
||||
@@ -313,49 +295,6 @@ err:
|
||||
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 && !group->meth->field_decode(group, x, &point->X, ctx)) {
|
||||
goto err;
|
||||
}
|
||||
if (y != NULL && !group->meth->field_decode(group, y, &point->Y, ctx)) {
|
||||
goto err;
|
||||
}
|
||||
if (z != NULL && !group->meth->field_decode(group, z, &point->Z, ctx)) {
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
if (x != NULL && !BN_copy(x, &point->X)) {
|
||||
goto err;
|
||||
}
|
||||
if (y != NULL && !BN_copy(y, &point->Y)) {
|
||||
goto err;
|
||||
}
|
||||
if (z != NULL && !BN_copy(z, &point->Z)) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
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) {
|
||||
@@ -814,11 +753,11 @@ int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a,
|
||||
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_GFp_simple_is_at_infinity(group, a)) {
|
||||
return ec_GFp_simple_is_at_infinity(group, b) ? 0 : 1;
|
||||
}
|
||||
|
||||
if (EC_POINT_is_at_infinity(group, b)) {
|
||||
if (ec_GFp_simple_is_at_infinity(group, b)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -122,11 +122,6 @@ static int8_t *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len) {
|
||||
sign = -1;
|
||||
}
|
||||
|
||||
if (scalar->d == NULL || scalar->top == 0) {
|
||||
OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
len = BN_num_bits(scalar);
|
||||
// The modified wNAF may be one digit longer than binary representation
|
||||
// (*ret_len will be set to the actual length, i.e. at most
|
||||
@@ -236,8 +231,9 @@ static size_t window_bits_for_scalar_size(size_t b) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,
|
||||
const EC_POINT *p, const BIGNUM *p_scalar, BN_CTX *ctx) {
|
||||
int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r,
|
||||
const EC_SCALAR *g_scalar_raw, const EC_POINT *p,
|
||||
const EC_SCALAR *p_scalar_raw, BN_CTX *ctx) {
|
||||
BN_CTX *new_ctx = NULL;
|
||||
const EC_POINT *generator = NULL;
|
||||
EC_POINT *tmp = NULL;
|
||||
@@ -262,13 +258,32 @@ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
BN_CTX_start(ctx);
|
||||
|
||||
// Convert from |EC_SCALAR| to |BIGNUM|. |BIGNUM| is not constant-time, but
|
||||
// neither is the rest of this function.
|
||||
BIGNUM *g_scalar = NULL, *p_scalar = NULL;
|
||||
if (g_scalar_raw != NULL) {
|
||||
g_scalar = BN_CTX_get(ctx);
|
||||
if (g_scalar == NULL ||
|
||||
!bn_set_words(g_scalar, g_scalar_raw->words, group->order.top)) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
if (p_scalar_raw != NULL) {
|
||||
p_scalar = BN_CTX_get(ctx);
|
||||
if (p_scalar == NULL ||
|
||||
!bn_set_words(p_scalar, p_scalar_raw->words, group->order.top)) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This function used to take |points| and |scalars| as arrays of
|
||||
// |num| elements. The code below should be simplified to work in terms of |p|
|
||||
// and |p_scalar|.
|
||||
size_t num = p != NULL ? 1 : 0;
|
||||
const EC_POINT **points = p != NULL ? &p : NULL;
|
||||
const BIGNUM **scalars = p != NULL ? &p_scalar : NULL;
|
||||
BIGNUM **scalars = p != NULL ? &p_scalar : NULL;
|
||||
|
||||
total_num = num;
|
||||
|
||||
@@ -433,6 +448,9 @@ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
if (ctx != NULL) {
|
||||
BN_CTX_end(ctx);
|
||||
}
|
||||
BN_CTX_free(new_ctx);
|
||||
EC_POINT_free(tmp);
|
||||
OPENSSL_free(wsize);
|
||||
@@ -446,7 +464,7 @@ err:
|
||||
}
|
||||
if (val != NULL) {
|
||||
for (i = 0; i < num_val; i++) {
|
||||
EC_POINT_clear_free(val[i]);
|
||||
EC_POINT_free(val[i]);
|
||||
}
|
||||
|
||||
OPENSSL_free(val);
|
||||
|
||||
+204
-206
@@ -58,37 +58,72 @@
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/type_check.h>
|
||||
|
||||
#include "../bn/internal.h"
|
||||
#include "../ec/internal.h"
|
||||
#include "../../internal.h"
|
||||
|
||||
|
||||
// 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.
|
||||
// digest_to_scalar interprets |digest_len| bytes from |digest| as a scalar for
|
||||
// ECDSA. Note this value is not fully reduced modulo the order, only the
|
||||
// correct number of bits.
|
||||
static void digest_to_scalar(const EC_GROUP *group, EC_SCALAR *out,
|
||||
const uint8_t *digest, size_t digest_len) {
|
||||
const BIGNUM *order = &group->order;
|
||||
size_t 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, ERR_R_BN_LIB);
|
||||
return 0;
|
||||
OPENSSL_memset(out, 0, sizeof(EC_SCALAR));
|
||||
for (size_t i = 0; i < digest_len; i++) {
|
||||
out->bytes[i] = digest[digest_len - 1 - i];
|
||||
}
|
||||
|
||||
// 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, ERR_R_BN_LIB);
|
||||
if (8 * digest_len > num_bits) {
|
||||
size_t shift = 8 - (num_bits & 0x7);
|
||||
for (int i = 0; i < order->top - 1; i++) {
|
||||
out->words[i] =
|
||||
(out->words[i] >> shift) | (out->words[i + 1] << (BN_BITS2 - shift));
|
||||
}
|
||||
out->words[order->top - 1] >>= shift;
|
||||
}
|
||||
}
|
||||
|
||||
// field_element_to_scalar reduces |r| modulo |group->order|. |r| must
|
||||
// previously have been reduced modulo |group->field|.
|
||||
static int field_element_to_scalar(const EC_GROUP *group, BIGNUM *r) {
|
||||
// We must have p < 2×order, assuming p is not tiny (p >= 17). Thus rather we
|
||||
// can reduce by performing at most one subtraction.
|
||||
//
|
||||
// Proof: We only work with prime order curves, so the number of points on
|
||||
// the curve is the order. Thus Hasse's theorem gives:
|
||||
//
|
||||
// |order - (p + 1)| <= 2×sqrt(p)
|
||||
// p + 1 - order <= 2×sqrt(p)
|
||||
// p + 1 - 2×sqrt(p) <= order
|
||||
// p + 1 - 2×(p/4) < order (p/4 > sqrt(p) for p >= 17)
|
||||
// p/2 < p/2 + 1 < order
|
||||
// p < 2×order
|
||||
//
|
||||
// Additionally, one can manually check this property for built-in curves. It
|
||||
// is enforced for legacy custom curves in |EC_GROUP_set_generator|.
|
||||
//
|
||||
// TODO(davidben): Introduce |EC_FIELD_ELEMENT|, make this a function from
|
||||
// |EC_FIELD_ELEMENT| to |EC_SCALAR|, and cut out the |BIGNUM|. Does this need
|
||||
// to be constant-time for signing? |r| is the x-coordinate for kG, which is
|
||||
// public unless k was rerolled because |s| was zero.
|
||||
assert(!BN_is_negative(r));
|
||||
assert(BN_cmp(r, &group->field) < 0);
|
||||
if (BN_cmp(r, &group->order) >= 0 &&
|
||||
!BN_sub(r, r, &group->order)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(!BN_is_negative(r));
|
||||
assert(BN_cmp(r, &group->order) < 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -116,67 +151,87 @@ void ECDSA_SIG_free(ECDSA_SIG *sig) {
|
||||
OPENSSL_free(sig);
|
||||
}
|
||||
|
||||
ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, size_t digest_len,
|
||||
const EC_KEY *key) {
|
||||
return ECDSA_do_sign_ex(digest, digest_len, NULL, NULL, key);
|
||||
void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **out_r,
|
||||
const BIGNUM **out_s) {
|
||||
if (out_r != NULL) {
|
||||
*out_r = sig->r;
|
||||
}
|
||||
if (out_s != NULL) {
|
||||
*out_s = sig->s;
|
||||
}
|
||||
}
|
||||
|
||||
int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) {
|
||||
if (r == NULL || s == NULL) {
|
||||
return 0;
|
||||
}
|
||||
BN_free(sig->r);
|
||||
BN_free(sig->s);
|
||||
sig->r = r;
|
||||
sig->s = s;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ECDSA_do_verify(const uint8_t *digest, size_t digest_len,
|
||||
const ECDSA_SIG *sig, const EC_KEY *eckey) {
|
||||
int ret = 0;
|
||||
BN_CTX *ctx;
|
||||
BIGNUM *u1, *u2, *m, *X;
|
||||
EC_POINT *point = NULL;
|
||||
const EC_GROUP *group;
|
||||
const EC_POINT *pub_key;
|
||||
|
||||
// check input values
|
||||
if ((group = EC_KEY_get0_group(eckey)) == NULL ||
|
||||
(pub_key = EC_KEY_get0_public_key(eckey)) == NULL ||
|
||||
sig == NULL) {
|
||||
const EC_GROUP *group = EC_KEY_get0_group(eckey);
|
||||
const EC_POINT *pub_key = EC_KEY_get0_public_key(eckey);
|
||||
if (group == NULL || pub_key == NULL || sig == NULL) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_MISSING_PARAMETERS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctx = BN_CTX_new();
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
if (!ctx) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
int ret = 0;
|
||||
EC_POINT *point = NULL;
|
||||
BN_CTX_start(ctx);
|
||||
u1 = BN_CTX_get(ctx);
|
||||
u2 = BN_CTX_get(ctx);
|
||||
m = BN_CTX_get(ctx);
|
||||
X = BN_CTX_get(ctx);
|
||||
if (u1 == NULL || u2 == NULL || m == NULL || X == NULL) {
|
||||
BIGNUM *X = BN_CTX_get(ctx);
|
||||
if (X == NULL) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
|
||||
goto err;
|
||||
}
|
||||
|
||||
EC_SCALAR r, s, m, u1, u2, s_inv_mont;
|
||||
const BIGNUM *order = EC_GROUP_get0_order(group);
|
||||
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) {
|
||||
if (BN_is_zero(sig->r) ||
|
||||
BN_is_negative(sig->r) ||
|
||||
BN_ucmp(sig->r, order) >= 0 ||
|
||||
!ec_bignum_to_scalar(group, &r, sig->r) ||
|
||||
BN_is_zero(sig->s) ||
|
||||
BN_is_negative(sig->s) ||
|
||||
BN_ucmp(sig->s, order) >= 0 ||
|
||||
!ec_bignum_to_scalar(group, &s, sig->s)) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_BAD_SIGNATURE);
|
||||
goto err;
|
||||
}
|
||||
// calculate tmp1 = inv(S) mod order
|
||||
// s_inv_mont = s^-1 mod order. We convert the result to Montgomery form for
|
||||
// the products below.
|
||||
int no_inverse;
|
||||
if (!BN_mod_inverse_odd(u2, &no_inverse, sig->s, order, ctx)) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
|
||||
if (!BN_mod_inverse_odd(X, &no_inverse, sig->s, order, ctx) ||
|
||||
!ec_bignum_to_scalar(group, &s_inv_mont, X) ||
|
||||
!bn_to_montgomery_small(s_inv_mont.words, order->top, s_inv_mont.words,
|
||||
order->top, group->order_mont)) {
|
||||
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, 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, ERR_R_BN_LIB);
|
||||
// u1 = m * s_inv_mont mod order
|
||||
// u2 = r * s_inv_mont mod order
|
||||
//
|
||||
// |s_inv_mont| is in Montgomery form while |m| and |r| are not, so |u1| and
|
||||
// |u2| will be taken out of Montgomery form, as desired. Note that, although
|
||||
// |m| is not fully reduced, |bn_mod_mul_montgomery_small| only requires the
|
||||
// product not exceed R * |order|. |s_inv_mont| is fully reduced and |m| <
|
||||
// 2^BN_num_bits(order) <= R, so this holds.
|
||||
digest_to_scalar(group, &m, digest, digest_len);
|
||||
if (!bn_mod_mul_montgomery_small(u1.words, order->top, m.words, order->top,
|
||||
s_inv_mont.words, order->top,
|
||||
group->order_mont) ||
|
||||
!bn_mod_mul_montgomery_small(u2.words, order->top, r.words, order->top,
|
||||
s_inv_mont.words, order->top,
|
||||
group->order_mont)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -185,7 +240,7 @@ int ECDSA_do_verify(const uint8_t *digest, size_t digest_len,
|
||||
OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
if (!EC_POINT_mul(group, point, u1, pub_key, u2, ctx)) {
|
||||
if (!ec_point_mul_scalar(group, point, &u1, pub_key, &u2, ctx)) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB);
|
||||
goto err;
|
||||
}
|
||||
@@ -193,12 +248,12 @@ int ECDSA_do_verify(const uint8_t *digest, size_t digest_len,
|
||||
OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB);
|
||||
goto err;
|
||||
}
|
||||
if (!BN_nnmod(u1, X, order, ctx)) {
|
||||
if (!field_element_to_scalar(group, X)) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
|
||||
goto err;
|
||||
}
|
||||
// if the signature is correct u1 is equal to sig->r
|
||||
if (BN_ucmp(u1, sig->r) != 0) {
|
||||
// The signature is correct iff |X| is equal to |sig->r|.
|
||||
if (BN_ucmp(X, sig->r) != 0) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_BAD_SIGNATURE);
|
||||
goto err;
|
||||
}
|
||||
@@ -212,45 +267,26 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ecdsa_sign_setup(const EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp,
|
||||
BIGNUM **rp, const uint8_t *digest,
|
||||
size_t digest_len) {
|
||||
BN_CTX *ctx = NULL;
|
||||
BIGNUM *k = NULL, *kinv = NULL, *r = NULL, *tmp = NULL;
|
||||
static int ecdsa_sign_setup(const EC_KEY *eckey, BN_CTX *ctx,
|
||||
EC_SCALAR *out_kinv_mont, BIGNUM **rp,
|
||||
const uint8_t *digest, size_t digest_len,
|
||||
const EC_SCALAR *priv_key) {
|
||||
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, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ctx_in == NULL) {
|
||||
if ((ctx = BN_CTX_new()) == NULL) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
ctx = ctx_in;
|
||||
}
|
||||
|
||||
k = BN_new();
|
||||
kinv = BN_new(); // this value is later returned in *kinvp
|
||||
r = BN_new(); // this value is later returned in *rp
|
||||
tmp = BN_new();
|
||||
if (k == NULL || kinv == NULL || r == NULL || tmp == NULL) {
|
||||
EC_SCALAR k;
|
||||
BIGNUM *r = BN_new(); // this value is later returned in *rp
|
||||
if (r == NULL) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
const EC_GROUP *group = EC_KEY_get0_group(eckey);
|
||||
const BIGNUM *order = EC_GROUP_get0_order(group);
|
||||
tmp_point = EC_POINT_new(group);
|
||||
if (tmp_point == NULL) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB);
|
||||
goto err;
|
||||
}
|
||||
|
||||
const BIGNUM *order = EC_GROUP_get0_order(group);
|
||||
|
||||
// Check that the size of the group order is FIPS compliant (FIPS 186-4
|
||||
// B.5.2).
|
||||
if (BN_num_bits(order) < 160) {
|
||||
@@ -259,171 +295,130 @@ static int ecdsa_sign_setup(const EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp,
|
||||
}
|
||||
|
||||
do {
|
||||
// If possible, we'll include the private key and message digest in the k
|
||||
// generation. The |digest| argument is only empty if |ECDSA_sign_setup| is
|
||||
// being used.
|
||||
// Include the private key and message digest in the k generation.
|
||||
if (eckey->fixed_k != NULL) {
|
||||
if (!BN_copy(k, eckey->fixed_k)) {
|
||||
if (!ec_bignum_to_scalar(group, &k, eckey->fixed_k)) {
|
||||
goto err;
|
||||
}
|
||||
} else if (digest_len > 0) {
|
||||
do {
|
||||
if (!BN_generate_dsa_nonce(k, order, EC_KEY_get0_private_key(eckey),
|
||||
digest, digest_len, ctx)) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED);
|
||||
goto err;
|
||||
}
|
||||
} while (BN_is_zero(k));
|
||||
} else if (!BN_rand_range_ex(k, 1, order)) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED);
|
||||
goto err;
|
||||
}
|
||||
|
||||
// Compute the inverse of k. The order is a prime, so use Fermat's Little
|
||||
// Theorem. Note |ec_group_get_order_mont| may return NULL but
|
||||
// |bn_mod_inverse_prime| allows this.
|
||||
if (!bn_mod_inverse_prime(kinv, k, order, ctx,
|
||||
ec_group_get_order_mont(group))) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
|
||||
goto err;
|
||||
}
|
||||
|
||||
// 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)) {
|
||||
} else {
|
||||
// Pass a SHA512 hash of the private key and digest as additional data
|
||||
// into the RBG. This is a hardening measure against entropy failure.
|
||||
OPENSSL_COMPILE_ASSERT(SHA512_DIGEST_LENGTH >= 32,
|
||||
additional_data_is_too_large_for_sha512);
|
||||
SHA512_CTX sha;
|
||||
uint8_t additional_data[SHA512_DIGEST_LENGTH];
|
||||
SHA512_Init(&sha);
|
||||
SHA512_Update(&sha, priv_key->words, order->top * sizeof(BN_ULONG));
|
||||
SHA512_Update(&sha, digest, digest_len);
|
||||
SHA512_Final(additional_data, &sha);
|
||||
if (!ec_random_nonzero_scalar(group, &k, additional_data)) {
|
||||
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, ERR_R_EC_LIB);
|
||||
// Compute k^-1. We leave it in the Montgomery domain as an optimization for
|
||||
// later operations.
|
||||
if (!bn_to_montgomery_small(out_kinv_mont->words, order->top, k.words,
|
||||
order->top, group->order_mont) ||
|
||||
!bn_mod_inverse_prime_mont_small(out_kinv_mont->words, order->top,
|
||||
out_kinv_mont->words, order->top,
|
||||
group->order_mont)) {
|
||||
goto err;
|
||||
}
|
||||
if (!EC_POINT_get_affine_coordinates_GFp(group, tmp_point, tmp, NULL,
|
||||
|
||||
// Compute r, the x-coordinate of generator * k.
|
||||
if (!ec_point_mul_scalar(group, tmp_point, &k, NULL, NULL, ctx) ||
|
||||
!EC_POINT_get_affine_coordinates_GFp(group, tmp_point, r, NULL,
|
||||
ctx)) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!BN_nnmod(r, tmp, order, ctx)) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
|
||||
if (!field_element_to_scalar(group, r)) {
|
||||
goto err;
|
||||
}
|
||||
} while (BN_is_zero(r));
|
||||
|
||||
// clear old values if necessary
|
||||
BN_clear_free(*rp);
|
||||
BN_clear_free(*kinvp);
|
||||
|
||||
// save the pre-computed values
|
||||
*rp = r;
|
||||
*kinvp = kinv;
|
||||
r = NULL;
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
BN_clear_free(k);
|
||||
if (!ret) {
|
||||
BN_clear_free(kinv);
|
||||
BN_clear_free(r);
|
||||
}
|
||||
if (ctx_in == NULL) {
|
||||
BN_CTX_free(ctx);
|
||||
}
|
||||
OPENSSL_cleanse(&k, sizeof(k));
|
||||
BN_clear_free(r);
|
||||
EC_POINT_free(tmp_point);
|
||||
BN_clear_free(tmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ECDSA_sign_setup(const EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv,
|
||||
BIGNUM **rp) {
|
||||
return ecdsa_sign_setup(eckey, ctx, kinv, rp, NULL, 0);
|
||||
}
|
||||
|
||||
ECDSA_SIG *ECDSA_do_sign_ex(const uint8_t *digest, size_t digest_len,
|
||||
const BIGNUM *in_kinv, const BIGNUM *in_r,
|
||||
const EC_KEY *eckey) {
|
||||
int ok = 0;
|
||||
BIGNUM *kinv = NULL, *s, *m = NULL, *tmp = NULL;
|
||||
const BIGNUM *ckinv;
|
||||
BN_CTX *ctx = NULL;
|
||||
const EC_GROUP *group;
|
||||
ECDSA_SIG *ret;
|
||||
const BIGNUM *priv_key;
|
||||
|
||||
ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, size_t digest_len,
|
||||
const EC_KEY *eckey) {
|
||||
if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, 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) {
|
||||
const EC_GROUP *group = EC_KEY_get0_group(eckey);
|
||||
const BIGNUM *priv_key_bn = EC_KEY_get0_private_key(eckey);
|
||||
if (group == NULL || priv_key_bn == NULL) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return NULL;
|
||||
}
|
||||
const BIGNUM *order = EC_GROUP_get0_order(group);
|
||||
|
||||
ret = ECDSA_SIG_new();
|
||||
if (!ret) {
|
||||
int ok = 0;
|
||||
ECDSA_SIG *ret = ECDSA_SIG_new();
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
EC_SCALAR kinv_mont, priv_key, r_mont, s, tmp, m;
|
||||
if (ret == NULL || ctx == NULL) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE);
|
||||
return NULL;
|
||||
}
|
||||
s = ret->s;
|
||||
|
||||
if ((ctx = BN_CTX_new()) == NULL ||
|
||||
(tmp = BN_new()) == NULL ||
|
||||
(m = BN_new()) == NULL) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
|
||||
const BIGNUM *order = EC_GROUP_get0_order(group);
|
||||
|
||||
if (!digest_to_bn(m, digest, digest_len, order)) {
|
||||
digest_to_scalar(group, &m, digest, digest_len);
|
||||
if (!ec_bignum_to_scalar(group, &priv_key, priv_key_bn)) {
|
||||
goto err;
|
||||
}
|
||||
for (;;) {
|
||||
if (in_kinv == NULL || in_r == NULL) {
|
||||
if (!ecdsa_sign_setup(eckey, ctx, &kinv, &ret->r, digest, digest_len)) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ERR_R_ECDSA_LIB);
|
||||
goto err;
|
||||
}
|
||||
ckinv = kinv;
|
||||
} else {
|
||||
ckinv = in_kinv;
|
||||
if (BN_copy(ret->r, in_r) == NULL) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
if (!ecdsa_sign_setup(eckey, ctx, &kinv_mont, &ret->r, digest, digest_len,
|
||||
&priv_key)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!BN_mod_mul(tmp, priv_key, ret->r, order, ctx)) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
|
||||
// Compute priv_key * r (mod order). Note if only one parameter is in the
|
||||
// Montgomery domain, |bn_mod_mul_montgomery_small| will compute the answer
|
||||
// in the normal domain.
|
||||
if (!ec_bignum_to_scalar(group, &r_mont, ret->r) ||
|
||||
!bn_to_montgomery_small(r_mont.words, order->top, r_mont.words,
|
||||
order->top, group->order_mont) ||
|
||||
!bn_mod_mul_montgomery_small(s.words, order->top, priv_key.words,
|
||||
order->top, r_mont.words, order->top,
|
||||
group->order_mont)) {
|
||||
goto err;
|
||||
}
|
||||
if (!BN_mod_add_quick(s, tmp, m, order)) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
|
||||
|
||||
// Compute s += m in constant time. Reduce one copy of |order| if necessary.
|
||||
// Note this does not leave |s| fully reduced. We have
|
||||
// |m| < 2^BN_num_bits(order), so subtracting |order| leaves
|
||||
// 0 <= |s| < 2^BN_num_bits(order).
|
||||
BN_ULONG carry = bn_add_words(s.words, s.words, m.words, order->top);
|
||||
BN_ULONG v = bn_sub_words(tmp.words, s.words, order->d, order->top) - carry;
|
||||
v = 0u - v;
|
||||
for (int i = 0; i < order->top; i++) {
|
||||
s.words[i] = constant_time_select_w(v, s.words[i], tmp.words[i]);
|
||||
}
|
||||
|
||||
// Finally, multiply s by k^-1. That was retained in Montgomery form, so the
|
||||
// same technique as the previous multiplication works. Although the
|
||||
// previous step did not fully reduce |s|, |bn_mod_mul_montgomery_small|
|
||||
// only requires the product not exceed R * |order|. |kinv_mont| is fully
|
||||
// reduced and |s| < 2^BN_num_bits(order) <= R, so this holds.
|
||||
if (!bn_mod_mul_montgomery_small(s.words, order->top, s.words, order->top,
|
||||
kinv_mont.words, order->top,
|
||||
group->order_mont) ||
|
||||
!bn_set_words(ret->s, s.words, order->top)) {
|
||||
goto err;
|
||||
}
|
||||
if (!BN_mod_mul(s, s, ckinv, order, ctx)) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB);
|
||||
goto err;
|
||||
}
|
||||
if (BN_is_zero(s)) {
|
||||
// if kinv and r have been supplied by the caller
|
||||
// don't to generate new kinv and r values
|
||||
if (in_kinv != NULL && in_r != NULL) {
|
||||
OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NEED_NEW_SETUP_VALUES);
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
if (!BN_is_zero(ret->s)) {
|
||||
// s != 0 => we have a valid signature
|
||||
break;
|
||||
}
|
||||
@@ -437,8 +432,11 @@ err:
|
||||
ret = NULL;
|
||||
}
|
||||
BN_CTX_free(ctx);
|
||||
BN_clear_free(m);
|
||||
BN_clear_free(tmp);
|
||||
BN_clear_free(kinv);
|
||||
OPENSSL_cleanse(&kinv_mont, sizeof(kinv_mont));
|
||||
OPENSSL_cleanse(&priv_key, sizeof(priv_key));
|
||||
OPENSSL_cleanse(&r_mont, sizeof(r_mont));
|
||||
OPENSSL_cleanse(&s, sizeof(s));
|
||||
OPENSSL_cleanse(&tmp, sizeof(tmp));
|
||||
OPENSSL_cleanse(&m, sizeof(m));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -64,20 +64,21 @@
|
||||
#include <openssl/nid.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "../ec/internal.h"
|
||||
#include "../../test/file_test.h"
|
||||
|
||||
|
||||
enum Api {
|
||||
kEncodedApi,
|
||||
kRawApi,
|
||||
enum API {
|
||||
kEncodedAPI,
|
||||
kRawAPI,
|
||||
};
|
||||
|
||||
// VerifyECDSASig checks that verifying |ecdsa_sig| gives |expected_result|.
|
||||
static void VerifyECDSASig(Api api, const uint8_t *digest, size_t digest_len,
|
||||
static void VerifyECDSASig(API api, const uint8_t *digest, size_t digest_len,
|
||||
const ECDSA_SIG *ecdsa_sig, EC_KEY *eckey,
|
||||
int expected_result) {
|
||||
switch (api) {
|
||||
case kEncodedApi: {
|
||||
case kEncodedAPI: {
|
||||
uint8_t *der;
|
||||
size_t der_len;
|
||||
ASSERT_TRUE(ECDSA_SIG_to_bytes(&der, &der_len, ecdsa_sig));
|
||||
@@ -87,7 +88,7 @@ static void VerifyECDSASig(Api api, const uint8_t *digest, size_t digest_len,
|
||||
break;
|
||||
}
|
||||
|
||||
case kRawApi:
|
||||
case kRawAPI:
|
||||
EXPECT_EQ(expected_result,
|
||||
ECDSA_do_verify(digest, digest_len, ecdsa_sig, eckey));
|
||||
break;
|
||||
@@ -100,7 +101,7 @@ static void VerifyECDSASig(Api api, const uint8_t *digest, size_t digest_len,
|
||||
// TestTamperedSig verifies that signature verification fails when a valid
|
||||
// signature is tampered with. |ecdsa_sig| must be a valid signature, which will
|
||||
// be modified.
|
||||
static void TestTamperedSig(Api api, const uint8_t *digest,
|
||||
static void TestTamperedSig(API api, const uint8_t *digest,
|
||||
size_t digest_len, ECDSA_SIG *ecdsa_sig,
|
||||
EC_KEY *eckey, const BIGNUM *order) {
|
||||
SCOPED_TRACE(api);
|
||||
@@ -206,7 +207,7 @@ TEST(ECDSATest, BuiltinCurves) {
|
||||
bssl::UniquePtr<ECDSA_SIG> ecdsa_sig(
|
||||
ECDSA_SIG_from_bytes(signature.data(), signature.size()));
|
||||
ASSERT_TRUE(ecdsa_sig);
|
||||
TestTamperedSig(kEncodedApi, digest, 20, ecdsa_sig.get(), eckey.get(),
|
||||
TestTamperedSig(kEncodedAPI, digest, 20, ecdsa_sig.get(), eckey.get(),
|
||||
order);
|
||||
|
||||
// Test ECDSA_SIG signing and verification.
|
||||
@@ -228,7 +229,7 @@ TEST(ECDSATest, BuiltinCurves) {
|
||||
ERR_clear_error();
|
||||
|
||||
// Verify a tampered signature.
|
||||
TestTamperedSig(kRawApi, digest, 20, ecdsa_sig.get(), eckey.get(), order);
|
||||
TestTamperedSig(kRawAPI, digest, 20, ecdsa_sig.get(), eckey.get(), order);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,6 +283,32 @@ static bssl::UniquePtr<EC_GROUP> GetCurve(FileTest *t, const char *key) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bssl::UniquePtr<EC_GROUP> MakeCustomClone(const EC_GROUP *group) {
|
||||
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
|
||||
bssl::UniquePtr<BIGNUM> p(BN_new()), a(BN_new()), b(BN_new()), x(BN_new()),
|
||||
y(BN_new());
|
||||
if (!ctx || !p || !a || !b || !x || !y ||
|
||||
!EC_GROUP_get_curve_GFp(group, p.get(), a.get(), b.get(), ctx.get()) ||
|
||||
!EC_POINT_get_affine_coordinates_GFp(
|
||||
group, EC_GROUP_get0_generator(group), x.get(), y.get(), ctx.get())) {
|
||||
return nullptr;
|
||||
}
|
||||
bssl::UniquePtr<EC_GROUP> ret(
|
||||
EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
|
||||
if (!ret) {
|
||||
return nullptr;
|
||||
}
|
||||
bssl::UniquePtr<EC_POINT> g(EC_POINT_new(ret.get()));
|
||||
if (!g ||
|
||||
!EC_POINT_set_affine_coordinates_GFp(ret.get(), g.get(), x.get(), y.get(),
|
||||
ctx.get()) ||
|
||||
!EC_GROUP_set_generator(ret.get(), g.get(), EC_GROUP_get0_order(group),
|
||||
BN_value_one())) {
|
||||
return nullptr;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bssl::UniquePtr<BIGNUM> GetBIGNUM(FileTest *t, const char *key) {
|
||||
std::vector<uint8_t> bytes;
|
||||
if (!t->GetBytes(&bytes, key)) {
|
||||
@@ -294,80 +321,90 @@ static bssl::UniquePtr<BIGNUM> GetBIGNUM(FileTest *t, const char *key) {
|
||||
TEST(ECDSATest, VerifyTestVectors) {
|
||||
FileTestGTest("crypto/fipsmodule/ecdsa/ecdsa_verify_tests.txt",
|
||||
[](FileTest *t) {
|
||||
bssl::UniquePtr<EC_GROUP> group = GetCurve(t, "Curve");
|
||||
ASSERT_TRUE(group);
|
||||
bssl::UniquePtr<BIGNUM> x = GetBIGNUM(t, "X");
|
||||
ASSERT_TRUE(x);
|
||||
bssl::UniquePtr<BIGNUM> y = GetBIGNUM(t, "Y");
|
||||
ASSERT_TRUE(y);
|
||||
bssl::UniquePtr<BIGNUM> r = GetBIGNUM(t, "R");
|
||||
ASSERT_TRUE(r);
|
||||
bssl::UniquePtr<BIGNUM> s = GetBIGNUM(t, "S");
|
||||
ASSERT_TRUE(s);
|
||||
std::vector<uint8_t> digest;
|
||||
ASSERT_TRUE(t->GetBytes(&digest, "Digest"));
|
||||
for (bool custom_group : {false, true}) {
|
||||
SCOPED_TRACE(custom_group);
|
||||
bssl::UniquePtr<EC_GROUP> group = GetCurve(t, "Curve");
|
||||
ASSERT_TRUE(group);
|
||||
if (custom_group) {
|
||||
group = MakeCustomClone(group.get());
|
||||
ASSERT_TRUE(group);
|
||||
}
|
||||
bssl::UniquePtr<BIGNUM> x = GetBIGNUM(t, "X");
|
||||
ASSERT_TRUE(x);
|
||||
bssl::UniquePtr<BIGNUM> y = GetBIGNUM(t, "Y");
|
||||
ASSERT_TRUE(y);
|
||||
bssl::UniquePtr<BIGNUM> r = GetBIGNUM(t, "R");
|
||||
ASSERT_TRUE(r);
|
||||
bssl::UniquePtr<BIGNUM> s = GetBIGNUM(t, "S");
|
||||
ASSERT_TRUE(s);
|
||||
std::vector<uint8_t> digest;
|
||||
ASSERT_TRUE(t->GetBytes(&digest, "Digest"));
|
||||
|
||||
bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
|
||||
ASSERT_TRUE(key);
|
||||
bssl::UniquePtr<EC_POINT> pub_key(EC_POINT_new(group.get()));
|
||||
ASSERT_TRUE(pub_key);
|
||||
bssl::UniquePtr<ECDSA_SIG> sig(ECDSA_SIG_new());
|
||||
ASSERT_TRUE(sig);
|
||||
ASSERT_TRUE(EC_KEY_set_group(key.get(), group.get()));
|
||||
ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(group.get(), pub_key.get(),
|
||||
x.get(), y.get(), nullptr));
|
||||
ASSERT_TRUE(EC_KEY_set_public_key(key.get(), pub_key.get()));
|
||||
ASSERT_TRUE(BN_copy(sig->r, r.get()));
|
||||
ASSERT_TRUE(BN_copy(sig->s, s.get()));
|
||||
bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
|
||||
ASSERT_TRUE(key);
|
||||
bssl::UniquePtr<EC_POINT> pub_key(EC_POINT_new(group.get()));
|
||||
ASSERT_TRUE(pub_key);
|
||||
bssl::UniquePtr<ECDSA_SIG> sig(ECDSA_SIG_new());
|
||||
ASSERT_TRUE(sig);
|
||||
ASSERT_TRUE(EC_KEY_set_group(key.get(), group.get()));
|
||||
ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
|
||||
group.get(), pub_key.get(), x.get(), y.get(), nullptr));
|
||||
ASSERT_TRUE(EC_KEY_set_public_key(key.get(), pub_key.get()));
|
||||
ASSERT_TRUE(BN_copy(sig->r, r.get()));
|
||||
ASSERT_TRUE(BN_copy(sig->s, s.get()));
|
||||
|
||||
EXPECT_EQ(
|
||||
t->HasAttribute("Invalid") ? 0 : 1,
|
||||
ECDSA_do_verify(digest.data(), digest.size(), sig.get(), key.get()));
|
||||
EXPECT_EQ(
|
||||
t->HasAttribute("Invalid") ? 0 : 1,
|
||||
ECDSA_do_verify(digest.data(), digest.size(), sig.get(), key.get()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
TEST(ECDSATest, SignTestVectors) {
|
||||
FileTestGTest("crypto/fipsmodule/ecdsa/ecdsa_sign_tests.txt",
|
||||
[](FileTest *t) {
|
||||
bssl::UniquePtr<EC_GROUP> group = GetCurve(t, "Curve");
|
||||
ASSERT_TRUE(group);
|
||||
bssl::UniquePtr<BIGNUM> priv_key = GetBIGNUM(t, "Private");
|
||||
ASSERT_TRUE(priv_key);
|
||||
bssl::UniquePtr<BIGNUM> x = GetBIGNUM(t, "X");
|
||||
ASSERT_TRUE(x);
|
||||
bssl::UniquePtr<BIGNUM> y = GetBIGNUM(t, "Y");
|
||||
ASSERT_TRUE(y);
|
||||
bssl::UniquePtr<BIGNUM> k = GetBIGNUM(t, "K");
|
||||
ASSERT_TRUE(k);
|
||||
bssl::UniquePtr<BIGNUM> r = GetBIGNUM(t, "R");
|
||||
ASSERT_TRUE(r);
|
||||
bssl::UniquePtr<BIGNUM> s = GetBIGNUM(t, "S");
|
||||
ASSERT_TRUE(s);
|
||||
std::vector<uint8_t> digest;
|
||||
ASSERT_TRUE(t->GetBytes(&digest, "Digest"));
|
||||
for (bool custom_group : {false, true}) {
|
||||
SCOPED_TRACE(custom_group);
|
||||
bssl::UniquePtr<EC_GROUP> group = GetCurve(t, "Curve");
|
||||
ASSERT_TRUE(group);
|
||||
if (custom_group) {
|
||||
group = MakeCustomClone(group.get());
|
||||
ASSERT_TRUE(group);
|
||||
}
|
||||
bssl::UniquePtr<BIGNUM> priv_key = GetBIGNUM(t, "Private");
|
||||
ASSERT_TRUE(priv_key);
|
||||
bssl::UniquePtr<BIGNUM> x = GetBIGNUM(t, "X");
|
||||
ASSERT_TRUE(x);
|
||||
bssl::UniquePtr<BIGNUM> y = GetBIGNUM(t, "Y");
|
||||
ASSERT_TRUE(y);
|
||||
bssl::UniquePtr<BIGNUM> k = GetBIGNUM(t, "K");
|
||||
ASSERT_TRUE(k);
|
||||
bssl::UniquePtr<BIGNUM> r = GetBIGNUM(t, "R");
|
||||
ASSERT_TRUE(r);
|
||||
bssl::UniquePtr<BIGNUM> s = GetBIGNUM(t, "S");
|
||||
ASSERT_TRUE(s);
|
||||
std::vector<uint8_t> digest;
|
||||
ASSERT_TRUE(t->GetBytes(&digest, "Digest"));
|
||||
|
||||
bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
|
||||
ASSERT_TRUE(key);
|
||||
bssl::UniquePtr<EC_POINT> pub_key(EC_POINT_new(group.get()));
|
||||
ASSERT_TRUE(pub_key);
|
||||
ASSERT_TRUE(EC_KEY_set_group(key.get(), group.get()));
|
||||
ASSERT_TRUE(EC_KEY_set_private_key(key.get(), priv_key.get()));
|
||||
ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(group.get(), pub_key.get(),
|
||||
x.get(), y.get(), nullptr));
|
||||
ASSERT_TRUE(EC_KEY_set_public_key(key.get(), pub_key.get()));
|
||||
ASSERT_TRUE(EC_KEY_check_key(key.get()));
|
||||
bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
|
||||
ASSERT_TRUE(key);
|
||||
bssl::UniquePtr<EC_POINT> pub_key(EC_POINT_new(group.get()));
|
||||
ASSERT_TRUE(pub_key);
|
||||
ASSERT_TRUE(EC_KEY_set_group(key.get(), group.get()));
|
||||
ASSERT_TRUE(EC_KEY_set_private_key(key.get(), priv_key.get()));
|
||||
ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
|
||||
group.get(), pub_key.get(), x.get(), y.get(), nullptr));
|
||||
ASSERT_TRUE(EC_KEY_set_public_key(key.get(), pub_key.get()));
|
||||
ASSERT_TRUE(EC_KEY_check_key(key.get()));
|
||||
|
||||
// |ECDSA_do_sign_ex| expects |k| to already be inverted.
|
||||
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
|
||||
ASSERT_TRUE(ctx);
|
||||
ASSERT_TRUE(BN_mod_inverse(k.get(), k.get(),
|
||||
EC_GROUP_get0_order(group.get()), ctx.get()));
|
||||
// Set the fixed k for testing purposes.
|
||||
key->fixed_k = k.release();
|
||||
bssl::UniquePtr<ECDSA_SIG> sig(
|
||||
ECDSA_do_sign(digest.data(), digest.size(), key.get()));
|
||||
ASSERT_TRUE(sig);
|
||||
|
||||
bssl::UniquePtr<ECDSA_SIG> sig(ECDSA_do_sign_ex(
|
||||
digest.data(), digest.size(), k.get(), r.get(), key.get()));
|
||||
ASSERT_TRUE(sig);
|
||||
|
||||
EXPECT_EQ(0, BN_cmp(r.get(), sig->r));
|
||||
EXPECT_EQ(0, BN_cmp(s.get(), sig->s));
|
||||
EXPECT_EQ(0, BN_cmp(r.get(), sig->r));
|
||||
EXPECT_EQ(0, BN_cmp(s.get(), sig->s));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -87,6 +87,14 @@ void HMAC_CTX_init(HMAC_CTX *ctx) {
|
||||
EVP_MD_CTX_init(&ctx->md_ctx);
|
||||
}
|
||||
|
||||
HMAC_CTX *HMAC_CTX_new(void) {
|
||||
HMAC_CTX *ctx = OPENSSL_malloc(sizeof(HMAC_CTX));
|
||||
if (ctx != NULL) {
|
||||
HMAC_CTX_init(ctx);
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void HMAC_CTX_cleanup(HMAC_CTX *ctx) {
|
||||
EVP_MD_CTX_cleanup(&ctx->i_ctx);
|
||||
EVP_MD_CTX_cleanup(&ctx->o_ctx);
|
||||
@@ -94,6 +102,15 @@ void HMAC_CTX_cleanup(HMAC_CTX *ctx) {
|
||||
OPENSSL_cleanse(ctx, sizeof(HMAC_CTX));
|
||||
}
|
||||
|
||||
void HMAC_CTX_free(HMAC_CTX *ctx) {
|
||||
if (ctx == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
HMAC_CTX_cleanup(ctx);
|
||||
OPENSSL_free(ctx);
|
||||
}
|
||||
|
||||
int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t key_len,
|
||||
const EVP_MD *md, ENGINE *impl) {
|
||||
if (md == NULL) {
|
||||
@@ -193,6 +210,11 @@ int HMAC_CTX_copy_ex(HMAC_CTX *dest, const HMAC_CTX *src) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void HMAC_CTX_reset(HMAC_CTX *ctx) {
|
||||
HMAC_CTX_cleanup(ctx);
|
||||
HMAC_CTX_init(ctx);
|
||||
}
|
||||
|
||||
int HMAC_Init(HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md) {
|
||||
if (key && md) {
|
||||
HMAC_CTX_init(ctx);
|
||||
|
||||
@@ -86,6 +86,7 @@ $code=<<___;
|
||||
.type _aesni_ctr32_ghash_6x,\@abi-omnipotent
|
||||
.align 32
|
||||
_aesni_ctr32_ghash_6x:
|
||||
.cfi_startproc
|
||||
vmovdqu 0x20($const),$T2 # borrow $T2, .Lone_msb
|
||||
sub \$6,$len
|
||||
vpxor $Z0,$Z0,$Z0 # $Z0 = 0
|
||||
@@ -410,6 +411,7 @@ _aesni_ctr32_ghash_6x:
|
||||
vpxor $Z0,$Xi,$Xi # modulo-scheduled
|
||||
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size _aesni_ctr32_ghash_6x,.-_aesni_ctr32_ghash_6x
|
||||
___
|
||||
######################################################################
|
||||
@@ -422,6 +424,7 @@ $code.=<<___;
|
||||
.type aesni_gcm_decrypt,\@function,6
|
||||
.align 32
|
||||
aesni_gcm_decrypt:
|
||||
.cfi_startproc
|
||||
xor $ret,$ret
|
||||
|
||||
# We call |_aesni_ctr32_ghash_6x|, which requires at least 96 (0x60)
|
||||
@@ -430,12 +433,19 @@ aesni_gcm_decrypt:
|
||||
jb .Lgcm_dec_abort
|
||||
|
||||
lea (%rsp),%rax # save stack pointer
|
||||
.cfi_def_cfa_register %rax
|
||||
push %rbx
|
||||
.cfi_push %rbx
|
||||
push %rbp
|
||||
.cfi_push %rbp
|
||||
push %r12
|
||||
.cfi_push %r12
|
||||
push %r13
|
||||
.cfi_push %r13
|
||||
push %r14
|
||||
.cfi_push %r14
|
||||
push %r15
|
||||
.cfi_push %r15
|
||||
___
|
||||
$code.=<<___ if ($win64);
|
||||
lea -0xa8(%rsp),%rsp
|
||||
@@ -535,15 +545,23 @@ $code.=<<___ if ($win64);
|
||||
___
|
||||
$code.=<<___;
|
||||
mov -48(%rax),%r15
|
||||
.cfi_restore %r15
|
||||
mov -40(%rax),%r14
|
||||
.cfi_restore %r14
|
||||
mov -32(%rax),%r13
|
||||
.cfi_restore %r13
|
||||
mov -24(%rax),%r12
|
||||
.cfi_restore %r12
|
||||
mov -16(%rax),%rbp
|
||||
.cfi_restore %rbp
|
||||
mov -8(%rax),%rbx
|
||||
.cfi_restore %rbx
|
||||
lea (%rax),%rsp # restore %rsp
|
||||
.cfi_def_cfa_register %rsp
|
||||
.Lgcm_dec_abort:
|
||||
mov $ret,%rax # return value
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size aesni_gcm_decrypt,.-aesni_gcm_decrypt
|
||||
___
|
||||
|
||||
@@ -551,6 +569,7 @@ $code.=<<___;
|
||||
.type _aesni_ctr32_6x,\@abi-omnipotent
|
||||
.align 32
|
||||
_aesni_ctr32_6x:
|
||||
.cfi_startproc
|
||||
vmovdqu 0x00-0x80($key),$Z0 # borrow $Z0 for $rndkey
|
||||
vmovdqu 0x20($const),$T2 # borrow $T2, .Lone_msb
|
||||
lea -1($rounds),%r13
|
||||
@@ -637,12 +656,14 @@ _aesni_ctr32_6x:
|
||||
vpshufb $Ii,$T1,$T1 # next counter value
|
||||
vpxor $Z0,$inout5,$inout5
|
||||
jmp .Loop_ctr32
|
||||
.cfi_endproc
|
||||
.size _aesni_ctr32_6x,.-_aesni_ctr32_6x
|
||||
|
||||
.globl aesni_gcm_encrypt
|
||||
.type aesni_gcm_encrypt,\@function,6
|
||||
.align 32
|
||||
aesni_gcm_encrypt:
|
||||
.cfi_startproc
|
||||
xor $ret,$ret
|
||||
|
||||
# We call |_aesni_ctr32_6x| twice, each call consuming 96 bytes of
|
||||
@@ -652,12 +673,19 @@ aesni_gcm_encrypt:
|
||||
jb .Lgcm_enc_abort
|
||||
|
||||
lea (%rsp),%rax # save stack pointer
|
||||
.cfi_def_cfa_register %rax
|
||||
push %rbx
|
||||
.cfi_push %rbx
|
||||
push %rbp
|
||||
.cfi_push %rbp
|
||||
push %r12
|
||||
.cfi_push %r12
|
||||
push %r13
|
||||
.cfi_push %r13
|
||||
push %r14
|
||||
.cfi_push %r14
|
||||
push %r15
|
||||
.cfi_push %r15
|
||||
___
|
||||
$code.=<<___ if ($win64);
|
||||
lea -0xa8(%rsp),%rsp
|
||||
@@ -929,15 +957,23 @@ $code.=<<___ if ($win64);
|
||||
___
|
||||
$code.=<<___;
|
||||
mov -48(%rax),%r15
|
||||
.cfi_restore %r15
|
||||
mov -40(%rax),%r14
|
||||
.cfi_restore %r14
|
||||
mov -32(%rax),%r13
|
||||
.cfi_restore %r13
|
||||
mov -24(%rax),%r12
|
||||
.cfi_restore %r12
|
||||
mov -16(%rax),%rbp
|
||||
.cfi_restore %rbp
|
||||
mov -8(%rax),%rbx
|
||||
.cfi_restore %rbx
|
||||
lea (%rax),%rsp # restore %rsp
|
||||
.cfi_def_cfa_register %rsp
|
||||
.Lgcm_enc_abort:
|
||||
mov $ret,%rax # return value
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size aesni_gcm_encrypt,.-aesni_gcm_encrypt
|
||||
___
|
||||
|
||||
|
||||
@@ -62,7 +62,8 @@ void CRYPTO_cbc128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
|
||||
assert(len == 0 || (in != NULL && out != NULL));
|
||||
|
||||
if (STRICT_ALIGNMENT &&
|
||||
((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
|
||||
((uintptr_t)in | (uintptr_t)out | (uintptr_t)ivec) % sizeof(size_t) !=
|
||||
0) {
|
||||
while (len >= 16) {
|
||||
for (n = 0; n < 16; ++n) {
|
||||
out[n] = in[n] ^ iv[n];
|
||||
@@ -76,7 +77,7 @@ void CRYPTO_cbc128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
|
||||
} 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);
|
||||
store_word_le(out + n, load_word_le(in + n) ^ load_word_le(iv + n));
|
||||
}
|
||||
(*block)(out, out, key);
|
||||
iv = out;
|
||||
@@ -129,7 +130,8 @@ void CRYPTO_cbc128_decrypt(const uint8_t *in, uint8_t *out, size_t len,
|
||||
const uint8_t *iv = ivec;
|
||||
|
||||
if (STRICT_ALIGNMENT &&
|
||||
((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
|
||||
((uintptr_t)in | (uintptr_t)out | (uintptr_t)ivec) % sizeof(size_t) !=
|
||||
0) {
|
||||
while (len >= 16) {
|
||||
(*block)(in, out, key);
|
||||
for (n = 0; n < 16; ++n) {
|
||||
@@ -142,11 +144,9 @@ void CRYPTO_cbc128_decrypt(const uint8_t *in, uint8_t *out, size_t len,
|
||||
}
|
||||
} 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];
|
||||
for (n = 0; n < 16; n += sizeof(size_t)) {
|
||||
store_word_le(out + n, load_word_le(out + n) ^ load_word_le(iv + n));
|
||||
}
|
||||
iv = in;
|
||||
len -= 16;
|
||||
@@ -160,7 +160,8 @@ void CRYPTO_cbc128_decrypt(const uint8_t *in, uint8_t *out, size_t len,
|
||||
// directly to |out| would overwrite a ciphertext block before it is used as
|
||||
// the next block's IV. Decrypt to a temporary block instead.
|
||||
if (STRICT_ALIGNMENT &&
|
||||
((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
|
||||
((uintptr_t)in | (uintptr_t)out | (uintptr_t)ivec) % sizeof(size_t) !=
|
||||
0) {
|
||||
uint8_t c;
|
||||
while (len >= 16) {
|
||||
(*block)(in, tmp.c, key);
|
||||
@@ -175,14 +176,12 @@ void CRYPTO_cbc128_decrypt(const uint8_t *in, uint8_t *out, size_t len,
|
||||
}
|
||||
} 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;
|
||||
for (n = 0; n < 16; n += sizeof(size_t)) {
|
||||
size_t c = load_word_le(in + n);
|
||||
store_word_le(out + n,
|
||||
tmp.t[n / sizeof(size_t)] ^ load_word_le(ivec + n));
|
||||
store_word_le(ivec + n, c);
|
||||
}
|
||||
len -= 16;
|
||||
in += 16;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user