Compare commits

..

2 Commits

Author SHA1 Message Date
David Benjamin 1b5bcb59f4 Make CRYPTO_is_NEON_capable aware of the buggy CPU.
If we're to allow the buggy CPU workaround to fire when __ARM_NEON__ is set,
CRYPTO_is_NEON_capable also needs to be aware of it. Also add an API to export
this value out of BoringSSL, so we can get some metrics on how prevalent this
chip is.

BUG=chromium:606629

Change-Id: I97d65a47a6130689098b32ce45a8c57c468aa405
Reviewed-on: https://boringssl-review.googlesource.com/7796
Reviewed-by: Adam Langley <agl@google.com>
2016-04-29 14:24:33 -04:00
David Benjamin b69307a1c4 Don't set a default armcap state in dynamic armcap modes.
The getauxval (and friends) code would be filling that in anyway. The default
only serves to enable NEON even if the OS is old enough to be missing getauxval
(and everything else).

Notably, this unbreaks the has_buggy_neon code when __ARM_NEON__ is set, as is
the case in Chrome for Android, as of M50.  Before, the default
OPENSSL_armcap_P value was getting in the way.

Arguably, this doesn't make a whole lot of sense. We're saying we'll let the
CPU run compiler-generated NEON code, but not our hand-crafted stuff. But, so
far, we only have evidence of the hand-written NEON tickling the bug and not
the compiler-generated stuff, so avoid the unintentional regression. (Naively,
I would expect the hand-crafted NEON is better at making full use of the
pipeline and is thus more likely to tickle the CPU bug.)

This is not the fix for M50, as in the associated Chromium bug, but it will fix
master and M51. M50 will instead want to revert
https://codereview.chromium.org/1730823002.

BUG=chromium:606629

Change-Id: I394f97fea2f09891dd8fa30e0ec6fc6b1adfab7a
Reviewed-on: https://boringssl-review.googlesource.com/7794
Reviewed-by: Adam Langley <agl@google.com>
2016-04-29 14:24:26 -04:00
3435 changed files with 98876 additions and 542143 deletions
-3
View File
@@ -2,6 +2,3 @@ BasedOnStyle: Google
MaxEmptyLinesToKeep: 3
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
DerivePointerAlignment: false
PointerAlignment: Right
-18
View File
@@ -4,21 +4,3 @@ ssl/test/runner/runner
*.swo
doc/*.html
doc/doc.css
util/bot/android_tools
util/bot/cmake-linux64
util/bot/cmake-linux64.tar.gz
util/bot/cmake-mac
util/bot/cmake-mac.tar.gz
util/bot/cmake-win32
util/bot/cmake-win32.zip
util/bot/golang
util/bot/gyp
util/bot/libFuzzer
util/bot/llvm-build
util/bot/perl-win32
util/bot/perl-win32.zip
util/bot/sde-linux64
util/bot/sde-linux64.tar.bz2
util/bot/win_toolchain.json
util/bot/yasm-win32.exe
-184
View File
@@ -1,184 +0,0 @@
# BoringSSL API Conventions
This document describes conventions for BoringSSL APIs. The [style
guide](/STYLE.md) also includes guidelines, but this document is targeted at
both API consumers and developers.
## Documentation
All supported public APIs are documented in the public header files, found in
`include/openssl`. The API documentation is also available
[online](https://commondatastorage.googleapis.com/chromium-boringssl-docs/headers.html).
Some headers lack documention comments. These are functions and structures from
OpenSSL's legacy ASN.1, X.509, and PEM implementation. If possible, avoid using
them. These are left largely unmodified from upstream and are retained only for
compatibility with existing OpenSSL consumers.
## Forward declarations
Do not write `typedef struct foo_st FOO` or try otherwise to define BoringSSL's
types. Including `openssl/base.h` (or `openssl/ossl_typ.h` for consumers who
wish to be OpenSSL-compatible) will forward-declare each type without importing
the rest of the library or invasive macros.
## Error-handling
Most functions in BoringSSL may fail, either due to allocation failures or input
errors. Functions which return an `int` typically return one on success and zero
on failure. Functions which return a pointer typically return `NULL` on failure.
However, due to legacy constraints, some functions are more complex. Consult the
API documentation before using a function.
On error, most functions also push errors on the error queue, an `errno`-like
mechanism. See the documentation for
[err.h](https://commondatastorage.googleapis.com/chromium-boringssl-docs/err.h.html)
for more details.
As with `errno`, callers must test the function's return value, not the error
queue to determine whether an operation failed. Some codepaths may not interact
with the error queue, and the error queue may have state from a previous failed
operation.
When ignoring a failed operation, it is recommended to call `ERR_clear_error` to
avoid the state interacting with future operations. Failing to do so should not
affect the actual behavior of any functions, but may result in errors from both
operations being mixed in error logging. We hope to
[improve](https://bugs.chromium.org/p/boringssl/issues/detail?id=38) this
situation in the future.
Where possible, avoid conditioning on specific reason codes and limit usage to
logging. The reason codes are very specific and may change over time.
## Memory allocation
BoringSSL allocates memory via `OPENSSL_malloc`, found in `mem.h`. Use
`OPENSSL_free`, found in the same header file, to release it. BoringSSL
functions will fail gracefully on allocation error, but it is recommended to use
a `malloc` implementation that `abort`s on failure.
## Object initialization and cleanup
BoringSSL defines a number of structs for use in its APIs. It is a C library,
so the caller is responsible for ensuring these structs are properly
initialized and released. Consult the documentation for a module for the
proper use of its types. Some general conventions are listed below.
### Heap-allocated types
Some types, such as `RSA`, are heap-allocated. All instances will be allocated
and returned from BoringSSL's APIs. It is an error to instantiate a heap-
allocated type on the stack or embedded within another object.
Heap-allocated types may have functioned named like `RSA_new` which allocates a
fresh blank `RSA`. Other functions may also return newly-allocated instances.
For example, `RSA_parse_public_key` is documented to return a newly-allocated
`RSA` object.
Heap-allocated objects must be released by the corresponding free function,
named like `RSA_free`. Like C's `free` and C++'s `delete`, all free functions
internally check for `NULL`. Consumers are not required to check for `NULL`
before calling.
A heap-allocated type may be reference-counted. In this case, a function named
like `RSA_up_ref` will be available to take an additional reference count. The
free function must be called to decrement the reference count. It will only
release resources when the final reference is released. For OpenSSL
compatibility, these functions return `int`, but callers may assume they always
successfully return one because reference counts use saturating arithmetic.
C++ consumers are recommended to use `bssl::UniquePtr` to manage heap-allocated
objects. `bssl::UniquePtr<T>`, like other types, is forward-declared in
`openssl/base.h`. Code that needs access to the free functions, such as code
which destroys a `bssl::UniquePtr`, must include the corresponding module's
header. (This matches `std::unique_ptr`'s relationship with forward
declarations.)
### Stack-allocated types
Other types in BoringSSL are stack-allocated, such as `EVP_MD_CTX`. These
types may be allocated on the stack or embedded within another object.
However, they must still be initialized before use.
Every stack-allocated object in BoringSSL has a *zero state*, analogous to
initializing a pointer to `NULL`. In this state, the object may not be
completely initialized, but it is safe to call cleanup functions. Entering the
zero state cannot fail. (It is usually `memset(0)`.)
The function to enter the zero state is named like `EVP_MD_CTX_init` or
`CBB_zero` and will always return `void`. To release resources associated with
the type, call the cleanup function, named like `EVP_MD_CTX_cleanup`. The
cleanup function must be called on all codepaths, regardless of success or
failure. For example:
uint8_t md[EVP_MAX_MD_SIZE];
unsigned md_len;
EVP_MD_CTX ctx;
EVP_MD_CTX_init(&ctx); /* Enter the zero state. */
int ok = EVP_DigestInit_ex(&ctx, EVP_sha256(), NULL) &&
EVP_DigestUpdate(&ctx, "hello ", 6) &&
EVP_DigestUpdate(&ctx, "world", 5) &&
EVP_DigestFinal_ex(&ctx, md, &md_len);
EVP_MD_CTX_cleanup(&ctx); /* Release |ctx|. */
Note that `EVP_MD_CTX_cleanup` is called whether or not the `EVP_Digest*`
operations succeeded. More complex C functions may use the `goto err` pattern:
int ret = 0;
EVP_MD_CTX ctx;
EVP_MD_CTX_init(&ctx);
if (!some_other_operation()) {
goto err;
}
uint8_t md[EVP_MAX_MD_SIZE];
unsigned md_len;
if (!EVP_DigestInit_ex(&ctx, EVP_sha256(), NULL) ||
!EVP_DigestUpdate(&ctx, "hello ", 6) ||
!EVP_DigestUpdate(&ctx, "world", 5) ||
!EVP_DigestFinal_ex(&ctx, md, &md_len) {
goto err;
}
ret = 1;
err:
EVP_MD_CTX_cleanup(&ctx);
return ret;
Note that, because `ctx` is set to the zero state before any failures,
`EVP_MD_CTX_cleanup` is safe to call even if the first operation fails before
`EVP_DigestInit_ex`. However, it would be illegal to move the `EVP_MD_CTX_init`
below the `some_other_operation` call.
As a rule of thumb, enter the zero state of stack-allocated structs in the
same place they are declared.
C++ consumers are recommended to use the wrappers named like
`bssl::ScopedEVP_MD_CTX`, defined in the corresponding module's header. These
wrappers are automatically initialized to the zero state and are automatically
cleaned up.
### Data-only types
A few types, such as `SHA_CTX`, are data-only types and do not require cleanup.
These are usually for low-level cryptographic operations. These types may be
used freely without special cleanup conventions.
## Thread safety
BoringSSL is internally aware of the platform threading library and calls into
it as needed. Consult the API documentation for the threading guarantees of
particular objects. In general, stateless reference-counted objects like `RSA`
or `EVP_PKEY` which represent keys may typically be used from multiple threads
simultaneously, provided no thread mutates the key.
+10 -35
View File
@@ -2,7 +2,7 @@
## Build Prerequisites
* [CMake](https://cmake.org/download/) 2.8.11 or later is required.
* [CMake](https://cmake.org/download/) 2.8.8 or later is required.
* Perl 5.6.1 or later is required. On Windows,
[Active State Perl](http://www.activestate.com/activeperl/) has been
@@ -24,17 +24,13 @@
by CMake, it may be configured explicitly by setting
`CMAKE_ASM_NASM_COMPILER`.
* A C compiler is required. On Windows, MSVC 14 (Visual Studio 2015) or later
* A C compiler is required. On Windows, MSVC 12 (Visual Studio 2013) or later
with Platform SDK 8.1 or later are supported. Recent versions of GCC (4.8+)
and Clang should work on non-Windows platforms, and maybe on Windows too.
To build the tests, you also need a C++ compiler with C++11 support.
* [Go](https://golang.org/dl/) is required. If not found by CMake, the go
executable may be configured explicitly by setting `GO_EXECUTABLE`.
* To build the x86 and x86\_64 assembly, your assembler must support AVX2
instructions and MOVBE. If using GNU binutils, you must have 2.22 or later.
## Building
Using Ninja (note the 'N' is capitalized in the cmake invocation):
@@ -83,27 +79,18 @@ It's possible to build BoringSSL with the Android NDK using CMake. This has
been tested with version 10d of the NDK.
Unpack the Android NDK somewhere and export `ANDROID_NDK` to point to the
directory. Then make a build directory as above and run CMake like this:
directory. Clone https://github.com/taka-no-me/android-cmake into `util/`. Then
make a build directory as above and run CMake *twice* like this:
cmake -DANDROID_ABI=armeabi-v7a \
-DCMAKE_TOOLCHAIN_FILE=../third_party/android-cmake/android.toolchain.cmake \
cmake -DANDROID_NATIVE_API_LEVEL=android-9 \
-DANDROID_ABI=armeabi-v7a \
-DCMAKE_TOOLCHAIN_FILE=../util/android-cmake/android.toolchain.cmake \
-DANDROID_NATIVE_API_LEVEL=16 \
-GNinja ..
Once you've run that, Ninja should produce Android-compatible binaries. You
can replace `armeabi-v7a` in the above with `arm64-v8a` and use API level 21 or
higher to build aarch64 binaries.
For other options, see [android-cmake's documentation](./third_party/android-cmake/README.md).
### Building for iOS
To build for iOS, pass `-DCMAKE_OSX_SYSROOT=iphoneos` and
`-DCMAKE_OSX_ARCHITECTURES=ARCH` to CMake, where `ARCH` is the desired
architecture, matching values used in the `-arch` flag in Apple's toolchain.
Passing multiple architectures for a multiple-architecture build is not
supported.
Once you've run that twice, Ninja should produce Android-compatible binaries.
You can replace `armeabi-v7a` in the above with `arm64-v8a` to build aarch64
binaries.
## Known Limitations on Windows
@@ -143,18 +130,6 @@ to enabling the corresponding ARM feature.
Note that if a feature is enabled in this way, but not actually supported at
run-time, BoringSSL will likely crash.
## Assembling ARMv8 with Clang
In order to support the ARMv8 crypto instructions, Clang requires that the
architecture be `armv8-a+crypto`. However, setting that as a general build flag
would allow the compiler to assume that crypto instructions are *always*
supported, even without testing for them.
It's possible to set the architecture in an assembly file using the `.arch`
directive, but only very recent versions of Clang support this. If
`BORINGSSL_CLANG_SUPPORTS_DOT_ARCH` is defined then `.arch` directives will be
used with Clang, otherwise you may need to craft acceptable assembler flags.
# Running tests
There are two sets of tests: the C/C++ tests and the blackbox tests. For former
+47 -151
View File
@@ -1,4 +1,4 @@
cmake_minimum_required (VERSION 2.8.11)
cmake_minimum_required (VERSION 2.8.10)
# Defer enabling C and CXX languages.
project (BoringSSL NONE)
@@ -9,20 +9,14 @@ if(WIN32)
set(CMAKE_GENERATOR_CC cl)
endif()
include(sources.cmake)
enable_language(C)
enable_language(CXX)
if(ANDROID)
# Android-NDK CMake files reconfigure the path and so Go and Perl won't be
# found. However, ninja will still find them in $PATH if we just name them.
if(NOT PERL_EXECUTABLE)
set(PERL_EXECUTABLE "perl")
endif()
if(NOT GO_EXECUTABLE)
set(GO_EXECUTABLE "go")
endif()
set(PERL_EXECUTABLE "perl")
set(GO_EXECUTABLE "go")
else()
find_package(Perl REQUIRED)
find_program(GO_EXECUTABLE go)
@@ -33,28 +27,15 @@ if (NOT GO_EXECUTABLE)
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")
set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wnewline-eof")
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")
set(C_CXX_FLAGS "-Wall -Werror -Wformat=2 -Wsign-compare -Wmissing-field-initializers -ggdb -fvisibility=hidden")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${C_CXX_FLAGS} -Wmissing-prototypes")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x ${C_CXX_FLAGS} -Wmissing-declarations")
elseif(MSVC)
set(MSVC_DISABLED_WARNINGS_LIST
"C4061" # enumerator 'identifier' in switch of enum 'enumeration' is not
# explicitly handled by a case label
# Disable this because it flags even when there is a default.
"C4100" # 'exarg' : unreferenced formal parameter
"C4127" # conditional expression is constant
"C4200" # nonstandard extension used : zero-sized array in
# struct/union.
"C4204" # nonstandard extension used: non-constant aggregate initializer
"C4221" # nonstandard extension used : 'identifier' : cannot be
# initialized using address of automatic variable
"C4242" # 'function' : conversion from 'int' to 'uint8_t',
# possible loss of data
"C4244" # 'function' : conversion from 'int' to 'uint8_t',
@@ -70,7 +51,6 @@ elseif(MSVC)
"C4365" # '=' : conversion from 'size_t' to 'int',
# signed/unsigned mismatch
"C4389" # '!=' : signed/unsigned mismatch
"C4464" # relative include path contains '..'
"C4510" # 'argument' : default constructor could not be generated
"C4512" # 'argument' : assignment operator could not be generated
"C4514" # 'function': unreferenced inline function has been removed
@@ -78,38 +58,41 @@ elseif(MSVC)
# side-effect" caused by FD_* macros.
"C4610" # struct 'argument' can never be instantiated - user defined
# constructor required.
"C4623" # default constructor was implicitly defined as deleted
"C4625" # copy constructor could not be generated because a base class
# copy constructor is inaccessible or deleted
"C4626" # assignment operator could not be generated because a base class
# assignment operator is inaccessible or deleted
"C4668" # 'symbol' is not defined as a preprocessor macro, replacing with
# '0' for 'directives'
# Disable this because GTest uses it everywhere.
"C4706" # assignment within conditional expression
"C4710" # 'function': function not inlined
"C4711" # function 'function' selected for inline expansion
"C4800" # 'int' : forcing value to bool 'true' or 'false'
# (performance warning)
"C4820" # 'bytes' bytes padding added after construct 'member_name'
"C5026" # move constructor was implicitly defined as deleted
"C5027" # move assignment operator was implicitly defined as deleted
)
set(MSVC_LEVEL4_WARNINGS_LIST
# See https://connect.microsoft.com/VisualStudio/feedback/details/1217660/warning-c4265-when-using-functional-header
"C4265" # class has virtual functions, but destructor is not virtual
)
"C4996" # 'read': The POSIX name for this item is deprecated. Instead,
# use the ISO C++ conformant name: _read.
)
if(NOT(CMAKE_C_COMPILER_VERSION VERSION_LESS "19.0.23506"))
# MSVC 2015 Update 1.
set(MSVC_DISABLED_WARNINGS_LIST
${MSVC_DISABLED_WARNINGS_LIST}
"C4464" # relative include path contains '..'
"C4623" # default constructor was implicitly defined as deleted
"C5027" # move assignment operator was implicitly defined as deleted
)
set(MSVC_LEVEL4_WARNINGS_LIST
# See https://connect.microsoft.com/VisualStudio/feedback/details/1217660/warning-c4265-when-using-functional-header
"C4265" # class has virtual functions, but destructor is not virtual
)
string(REPLACE "C" " -w4" MSVC_LEVEL4_WARNINGS_STR
${MSVC_LEVEL4_WARNINGS_LIST})
endif()
string(REPLACE "C" " -wd" MSVC_DISABLED_WARNINGS_STR
${MSVC_DISABLED_WARNINGS_LIST})
string(REPLACE "C" " -w4" MSVC_LEVEL4_WARNINGS_STR
${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")
add_definitions(-D_HAS_EXCEPTIONS=0)
add_definitions(-DWIN32_LEAN_AND_MEAN)
add_definitions(-DNOMINMAX)
add_definitions(-D_CRT_SECURE_NO_WARNINGS) # Allow use of fopen
endif()
if((CMAKE_COMPILER_IS_GNUCXX AND CMAKE_C_COMPILER_VERSION VERSION_GREATER "4.7.99") OR
@@ -118,35 +101,21 @@ if((CMAKE_COMPILER_IS_GNUCXX AND CMAKE_C_COMPILER_VERSION VERSION_GREATER "4.7.9
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")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11")
else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")
endif()
endif()
# pthread_rwlock_t requires a feature flag.
if(NOT WIN32)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_XOPEN_SOURCE=700")
if((CMAKE_COMPILER_IS_GNUCXX AND CMAKE_C_COMPILER_VERSION VERSION_GREATER "4.8.99") OR
CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_XOPEN_SOURCE=700")
endif()
if(FUZZ)
if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
message(FATAL_ERROR "You need to build with Clang for fuzzing to work")
if(!CMAKE_CXX_COMPILER_ID MATCHES "Clang")
message("You need to build with Clang for fuzzing to work")
endif()
add_definitions(-DBORINGSSL_UNSAFE_DETERMINISTIC_MODE)
set(RUNNER_ARGS "-deterministic")
add_definitions(-DBORINGSSL_UNSAFE_FUZZER_MODE)
set(RUNNER_ARGS "-fuzzer")
if(NOT NO_FUZZER_MODE)
add_definitions(-DBORINGSSL_UNSAFE_FUZZER_MODE)
set(RUNNER_ARGS ${RUNNER_ARGS} "-fuzzer" "-shim-config" "fuzzer_mode.json")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fsanitize-coverage=edge,indirect-calls,trace-pc-guard")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fsanitize-coverage=edge,indirect-calls,trace-pc-guard")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fsanitize-coverage=edge,indirect-calls,8bit-counters")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fsanitize-coverage=edge,indirect-calls,8bit-counters")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address")
link_directories(.)
endif()
@@ -160,57 +129,7 @@ if (BUILD_SHARED_LIBS)
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
endif()
if (MSAN)
if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
message(FATAL_ERROR "Cannot enable MSAN unless using Clang")
endif()
if (ASAN)
message(FATAL_ERROR "ASAN and MSAN are mutually exclusive")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer")
set(OPENSSL_NO_ASM "1")
endif()
if (ASAN)
if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
message(FATAL_ERROR "Cannot enable ASAN unless using Clang")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fsanitize-address-use-after-scope -fno-omit-frame-pointer")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fsanitize-address-use-after-scope -fno-omit-frame-pointer")
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")
endif()
if(FIPS)
add_definitions(-DBORINGSSL_FIPS)
endif()
# CMake's iOS support uses Apple's multiple-architecture toolchain. It takes an
# architecture list from CMAKE_OSX_ARCHITECTURES, leaves CMAKE_SYSTEM_PROCESSOR
# alone, and expects all architecture-specific logic to be conditioned within
# the source files rather than the build. This does not work for our assembly
# files, so we fix CMAKE_SYSTEM_PROCESSOR and only support single-architecture
# builds.
if (NOT OPENSSL_NO_ASM AND CMAKE_OSX_ARCHITECTURES)
list(LENGTH CMAKE_OSX_ARCHITECTURES NUM_ARCHES)
if (NOT ${NUM_ARCHES} EQUAL 1)
message(FATAL_ERROR "Universal binaries not supported.")
endif()
list(GET CMAKE_OSX_ARCHITECTURES 0 CMAKE_SYSTEM_PROCESSOR)
endif()
if (OPENSSL_NO_ASM)
add_definitions(-DOPENSSL_NO_ASM)
set(ARCH "generic")
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64")
if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64")
set(ARCH "x86_64")
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "amd64")
set(ARCH "x86_64")
@@ -227,17 +146,14 @@ elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i386")
set(ARCH "x86")
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i686")
set(ARCH "x86")
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm")
set(ARCH "arm")
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv6")
set(ARCH "arm")
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv7-a")
set(ARCH "arm")
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
set(ARCH "aarch64")
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm64")
set(ARCH "aarch64")
elseif (${CMAKE_SYSTEM_PROCESSOR} MATCHES "^arm*")
set(ARCH "arm")
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "mips")
# Just to avoid the “unknown processor” error.
set(ARCH "generic")
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "ppc64le")
set(ARCH "ppc64le")
else()
message(FATAL_ERROR "Unknown processor:" ${CMAKE_SYSTEM_PROCESSOR})
endif()
@@ -256,42 +172,22 @@ if (${ARCH} STREQUAL "x86" AND APPLE)
set(ARCH "x86_64")
endif()
# Add minimal googletest targets. The provided one has many side-effects, and
# googletest has a very straightforward build.
add_library(gtest third_party/googletest/src/gtest-all.cc)
target_include_directories(gtest PRIVATE third_party/googletest)
include_directories(third_party/googletest/include)
if (OPENSSL_NO_ASM)
add_definitions(-DOPENSSL_NO_ASM)
set(ARCH "generic")
endif()
# Declare a dummy target to build all unit tests. Test targets should inject
# themselves as dependencies next to the target definition.
add_custom_target(all_tests)
add_custom_command(
OUTPUT crypto_test_data.cc
COMMAND ${GO_EXECUTABLE} run util/embed_test_data.go ${CRYPTO_TEST_DATA} >
${CMAKE_CURRENT_BINARY_DIR}/crypto_test_data.cc
DEPENDS util/embed_test_data.go ${CRYPTO_TEST_DATA}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
add_library(crypto_test_data OBJECT crypto_test_data.cc)
add_subdirectory(crypto)
add_subdirectory(ssl)
add_subdirectory(ssl/test)
add_subdirectory(fipstools)
add_subdirectory(tool)
add_subdirectory(decrepit)
if(FUZZ)
if(LIBFUZZER_FROM_DEPS)
file(GLOB LIBFUZZER_SOURCES "util/bot/libFuzzer/*.cpp")
add_library(Fuzzer STATIC ${LIBFUZZER_SOURCES})
# libFuzzer does not pass our aggressive warnings. It also must be built
# without -fsanitize-coverage options or clang crashes.
set_target_properties(Fuzzer PROPERTIES COMPILE_FLAGS "-Wno-shadow -Wno-format-nonliteral -fsanitize-coverage=0")
endif()
add_subdirectory(fuzz)
endif()
@@ -304,9 +200,9 @@ add_custom_target(
run_tests
COMMAND ${GO_EXECUTABLE} run util/all_tests.go -build-dir
${CMAKE_BINARY_DIR}
COMMAND cd ssl/test/runner &&
${GO_EXECUTABLE} test -shim-path $<TARGET_FILE:bssl_shim>
${RUNNER_ARGS}
COMMAND cd ssl/test/runner
COMMAND ${GO_EXECUTABLE} test -shim-path $<TARGET_FILE:bssl_shim>
${RUNNER_ARGS}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
DEPENDS all_tests bssl_shim
${MAYBE_USES_TERMINAL})
+3 -36
View File
@@ -23,26 +23,12 @@ Then copy `libFuzzer.a` to the top-level of your BoringSSL source directory.
From the `build/` directory, you can then run the fuzzers. For example:
```
./fuzz/cert -max_len=10000 -jobs=32 -workers=32 ../fuzz/cert_corpus/
./fuzz/cert -max_len=3072 -jobs=32 -workers=32 ../fuzz/cert_corpus/
```
The arguments to `jobs` and `workers` should be the number of cores that you wish to dedicate to fuzzing. By default, libFuzzer uses the largest test in the corpus (or 64 if empty) as the maximum test case length. The `max_len` argument overrides this.
The recommended values of `max_len` for each test are:
| Test | `max_len` value |
|---------------|-----------------|
| `cert` | 10000 |
| `client` | 20000 |
| `pkcs8` | 2048 |
| `privkey` | 2048 |
| `server` | 4096 |
| `session` | 8192 |
| `spki` | 1024 |
| `read_pem` | 512 |
| `ssl_ctx_api` | 256 |
These were determined by rounding up the length of the largest case in the corpus.
The recommended values of `max_len` for each test may be found in `.options` files alongside the test source. These were determined by rounding up the length of the largest case in the corpus. When writing a new fuzzer, configure `max_len` in a similar file.
There are directories in `fuzz/` for each of the fuzzing tests which contain seed files for fuzzing. Some of the seed files were generated manually but many of them are “interesting” results generated by the fuzzing itself. (Where “interesting” means that it triggered a previously unknown path in the code.)
@@ -54,31 +40,12 @@ In order to minimise all the corpuses, build for fuzzing and run `./fuzz/minimis
## Fuzzer mode
When `-DFUZZ=1` is passed into CMake, BoringSSL builds with `BORINGSSL_UNSAFE_FUZZER_MODE` and `BORINGSSL_UNSAFE_DETERMINISTIC_MODE` defined. This modifies the library to be more friendly to fuzzers. If `BORINGSSL_UNSAFE_DETERMINISTIC_MODE` is set, BoringSSL will:
When `-DFUZZ=1` is passed into CMake, BoringSSL builds with `BORINGSSL_UNSAFE_FUZZER_MODE` defined. This modifies the library, particularly the TLS stack, to be more friendly to fuzzers. It will:
* Replace `RAND_bytes` with a deterministic PRNG. Call `RAND_reset_for_fuzzing()` at the start of fuzzers which use `RAND_bytes` to reset the PRNG state.
* Use a hard-coded time instead of the actual time.
Additionally, if `BORINGSSL_UNSAFE_FUZZER_MODE` is set, BoringSSL will:
* Modify the TLS stack to perform all signature checks (CertificateVerify and ServerKeyExchange) and the Finished check, but always act as if the check succeeded.
* Treat every cipher as the NULL cipher.
* Tickets are unencrypted and the MAC check is performed but ignored.
This is to prevent the fuzzer from getting stuck at a cryptographic invariant in the protocol.
## TLS transcripts
The `client` and `server` corpora are seeded from the test suite. The test suite has a `-fuzzer` flag which mirrors the fuzzer mode changes above and a `-deterministic` flag which removes all non-determinism on the Go side. Not all tests pass, so `ssl/test/runner/fuzzer_mode.json` contains the necessary suppressions. The `run_tests` target will pass appropriate command-line flags.
There are separate corpora, `client_corpus_no_fuzzer_mode` and `server_corpus_no_fuzzer_mode`. These are transcripts for fuzzers with only `BORINGSSL_UNSAFE_DETERMINISTIC_MODE` defined. To build in this mode, pass `-DNO_FUZZER_MODE=1` into CMake. This configuration is run in the same way but without `-fuzzer` and `-shim-path` flags.
If both sets of tests pass, refresh the fuzzer corpora with `refresh_ssl_corpora.sh`:
```
cd fuzz
./refresh_ssl_corpora.sh /path/to/fuzzer/mode/build /path/to/non/fuzzer/mode/build
```
-108
View File
@@ -1,108 +0,0 @@
# Incorporating BoringSSL into a project
**Note**: if your target project is not a Google project then first read the
[main README](/README.md) about the purpose of BoringSSL.
## Bazel
If you are using [Bazel](https://bazel.build) then you can incorporate
BoringSSL as an external repository by using a commit from the
`master-with-bazel` branch. That branch is maintained by a bot from `master`
and includes the needed generated files and a top-level BUILD file.
For example:
git_repository(
name = "boringssl",
commit = "_some commit_",
remote = "https://boringssl.googlesource.com/boringssl",
)
You would still need to keep the referenced commit up to date if a specific
commit is referred to.
## Directory layout
Typically projects create a `third_party/boringssl` directory to put
BoringSSL-specific files into. The source code of BoringSSL itself goes into
`third_party/boringssl/src`, either by copying or as a
[submodule](https://git-scm.com/docs/git-submodule).
It's generally a mistake to put BoringSSL's source code into
`third_party/boringssl` directly because pre-built files and custom build files
need to go somewhere and merging these with the BoringSSL source code makes
updating things more complex.
## Build support
BoringSSL is designed to work with many different build systems. Currently,
different projects use [GYP](https://gyp.gsrc.io/),
[GN](https://chromium.googlesource.com/chromium/src/+/master/tools/gn/docs/quick_start.md),
[Bazel](https://bazel.build/) and [Make](https://www.gnu.org/software/make/) to
build BoringSSL, without too much pain.
The development build system is CMake and the CMake build knows how to
automatically generate the intermediate files that BoringSSL needs. However,
outside of the CMake environment, these intermediates are generated once and
checked into the incorporating project's source repository. This avoids
incorporating projects needing to support Perl and Go in their build systems.
The script [`util/generate_build_files.py`](/util/generate_build_files.py)
expects to be run from the `third_party/boringssl` directory and to find the
BoringSSL source code in `src/`. You should pass it a single argument: the name
of the build system that you're using. If you don't use any of the supported
build systems then you should augment `generate_build_files.py` with support
for it.
The script will pregenerate the intermediate files (see
[BUILDING.md](/BUILDING.md) for details about which tools will need to be
installed) and output helper files for that build system. It doesn't generate a
complete build script, just file and test lists, which change often. For
example, see the
[file](https://code.google.com/p/chromium/codesearch#chromium/src/third_party/boringssl/BUILD.generated.gni)
and
[test](https://code.google.com/p/chromium/codesearch#chromium/src/third_party/boringssl/BUILD.generated_tests.gni)
lists generated for GN in Chromium.
Generally one checks in these generated files alongside the hand-written build
files. Periodically an engineer updates the BoringSSL revision, regenerates
these files and checks in the updated result. As an example, see how this is
done [in Chromium](https://code.google.com/p/chromium/codesearch#chromium/src/third_party/boringssl/).
## Defines
BoringSSL does not present a lot of configurability in order to reduce the
number of configurations that need to be tested. But there are a couple of
\#defines that you may wish to set:
`OPENSSL_NO_ASM` prevents the use of assembly code (although it's up to you to
ensure that the build system doesn't link it in if you wish to reduce binary
size). This will have a significant performance impact but can be useful if you
wish to use tools like
[AddressSanitizer](http://clang.llvm.org/docs/AddressSanitizer.html) that
interact poorly with assembly code.
`OPENSSL_SMALL` removes some code that is especially large at some performance
cost.
## Symbols
You cannot link multiple versions of BoringSSL or OpenSSL into a single binary
without dealing with symbol conflicts. If you are statically linking multiple
versions together, there's not a lot that can be done because C doesn't have a
module system.
If you are using multiple versions in a single binary, in different shared
objects, ensure you build BoringSSL with `-fvisibility=hidden` and do not
export any of BoringSSL's symbols. This will prevent any collisions with other
verisons that may be included in other shared objects. Note that this requires
that all callers of BoringSSL APIs live in the same shared object as BoringSSL.
If you require that BoringSSL APIs be used across shared object boundaries,
continue to build with `-fvisibility=hidden` but define
`BORINGSSL_SHARED_LIBRARY` in both BoringSSL and consumers. BoringSSL's own
source files (but *not* consumers' source files) must also build with
`BORINGSSL_IMPLEMENTATION` defined. This will export BoringSSL's public symbols
in the resulting shared object while hiding private symbols. However note that,
as with a static link, this precludes dynamically linking with another version
of BoringSSL or OpenSSL.
+1 -63
View File
@@ -10,9 +10,6 @@ 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.
For convenience, BoringSSL defines upstream's `OPENSSL_NO_*` feature macros
corresponding to removed features. These may also be used to disable code which
@@ -82,8 +79,7 @@ will continue to function. However, the macros themselves will not work.
Switch any `*_ctrl` callers to the macro/function versions. This works in both
OpenSSL and BoringSSL. Note that BoringSSL's function versions will be
type-checked and may require more care with types. See the end of this
document for a table of functions to use.
type-checked and may require more care with types.
### HMAC `EVP_PKEY`s
@@ -189,61 +185,3 @@ guarantees it.
BoringSSL is in the process of deprecating OpenSSL's `d2i` and `i2d` in favor of
new functions using the much less error-prone `CBS` and `CBB` types.
BoringSSL-only code should use those functions where available.
## Replacements for `CTRL` values
When porting code which uses `SSL_CTX_ctrl` or `SSL_ctrl`, use the replacement
functions below. If a function has both `SSL_CTX` and `SSL` variants, only the
`SSL_CTX` version is listed.
Note some values correspond to multiple functions depending on the `larg`
parameter.
`CTRL` value | Replacement function(s)
-------------|-------------------------
`DTLS_CTRL_GET_TIMEOUT` | `DTLSv1_get_timeout`
`DTLS_CTRL_HANDLE_TIMEOUT` | `DTLSv1_handle_timeout`
`SSL_CTRL_CHAIN` | `SSL_CTX_set0_chain` or `SSL_CTX_set1_chain`
`SSL_CTRL_CHAIN_CERT` | `SSL_add0_chain_cert` or `SSL_add1_chain_cert`
`SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS` | `SSL_CTX_clear_extra_chain_certs`
`SSL_CTRL_CLEAR_MODE` | `SSL_CTX_clear_mode`
`SSL_CTRL_CLEAR_OPTIONS` | `SSL_CTX_clear_options`
`SSL_CTRL_EXTRA_CHAIN_CERT` | `SSL_CTX_add_extra_chain_cert`
`SSL_CTRL_GET_CHAIN_CERTS` | `SSL_CTX_get0_chain_certs`
`SSL_CTRL_GET_CLIENT_CERT_TYPES` | `SSL_get0_certificate_types`
`SSL_CTRL_GET_EXTRA_CHAIN_CERTS` | `SSL_CTX_get_extra_chain_certs` or `SSL_CTX_get_extra_chain_certs_only`
`SSL_CTRL_GET_MAX_CERT_LIST` | `SSL_CTX_get_max_cert_list`
`SSL_CTRL_GET_NUM_RENEGOTIATIONS` | `SSL_num_renegotiations`
`SSL_CTRL_GET_READ_AHEAD` | `SSL_CTX_get_read_ahead`
`SSL_CTRL_GET_RI_SUPPORT` | `SSL_get_secure_renegotiation_support`
`SSL_CTRL_GET_SESSION_REUSED` | `SSL_session_reused`
`SSL_CTRL_GET_SESS_CACHE_MODE` | `SSL_CTX_get_session_cache_mode`
`SSL_CTRL_GET_SESS_CACHE_SIZE` | `SSL_CTX_sess_get_cache_size`
`SSL_CTRL_GET_TLSEXT_TICKET_KEYS` | `SSL_CTX_get_tlsext_ticket_keys`
`SSL_CTRL_GET_TOTAL_RENEGOTIATIONS` | `SSL_total_renegotiations`
`SSL_CTRL_MODE` | `SSL_CTX_get_mode` or `SSL_CTX_set_mode`
`SSL_CTRL_NEED_TMP_RSA` | `SSL_CTX_need_tmp_RSA` is equivalent, but [*do not use this function*](https://freakattack.com/). (It is a no-op in BoringSSL.)
`SSL_CTRL_OPTIONS` | `SSL_CTX_get_options` or `SSL_CTX_set_options`
`SSL_CTRL_SESS_NUMBER` | `SSL_CTX_sess_number`
`SSL_CTRL_SET_CURVES` | `SSL_CTX_set1_curves`
`SSL_CTRL_SET_ECDH_AUTO` | `SSL_CTX_set_ecdh_auto`
`SSL_CTRL_SET_MAX_CERT_LIST` | `SSL_CTX_set_max_cert_list`
`SSL_CTRL_SET_MAX_SEND_FRAGMENT` | `SSL_CTX_set_max_send_fragment`
`SSL_CTRL_SET_MSG_CALLBACK` | `SSL_set_msg_callback`
`SSL_CTRL_SET_MSG_CALLBACK_ARG` | `SSL_set_msg_callback_arg`
`SSL_CTRL_SET_MTU` | `SSL_set_mtu`
`SSL_CTRL_SET_READ_AHEAD` | `SSL_CTX_set_read_ahead`
`SSL_CTRL_SET_SESS_CACHE_MODE` | `SSL_CTX_set_session_cache_mode`
`SSL_CTRL_SET_SESS_CACHE_SIZE` | `SSL_CTX_sess_set_cache_size`
`SSL_CTRL_SET_TLSEXT_HOSTNAME` | `SSL_set_tlsext_host_name`
`SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG` | `SSL_CTX_set_tlsext_servername_arg`
`SSL_CTRL_SET_TLSEXT_SERVERNAME_CB` | `SSL_CTX_set_tlsext_servername_callback`
`SSL_CTRL_SET_TLSEXT_TICKET_KEYS` | `SSL_CTX_set_tlsext_ticket_keys`
`SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB` | `SSL_CTX_set_tlsext_ticket_key_cb`
`SSL_CTRL_SET_TMP_DH` | `SSL_CTX_set_tmp_dh`
`SSL_CTRL_SET_TMP_DH_CB` | `SSL_CTX_set_tmp_dh_callback`
`SSL_CTRL_SET_TMP_ECDH` | `SSL_CTX_set_tmp_ecdh`
`SSL_CTRL_SET_TMP_ECDH_CB` | `SSL_CTX_set_tmp_ecdh_callback`
`SSL_CTRL_SET_TMP_RSA` | `SSL_CTX_set_tmp_rsa` is equivalent, but [*do not use this function*](https://freakattack.com/). (It is a no-op in BoringSSL.)
`SSL_CTRL_SET_TMP_RSA_CB` | `SSL_CTX_set_tmp_rsa_callback` is equivalent, but [*do not use this function*](https://freakattack.com/). (It is a no-op in BoringSSL.)
-2
View File
@@ -25,8 +25,6 @@ There are other files in this directory which might be helpful:
* [PORTING.md](/PORTING.md): how to port OpenSSL-using code to BoringSSL.
* [BUILDING.md](/BUILDING.md): how to build BoringSSL
* [INCORPORATING.md](/INCORPORATING.md): how to incorporate BoringSSL into a project.
* [API-CONVENTIONS.md](/API-CONVENTIONS.md): general API conventions for BoringSSL consumers and developers.
* [STYLE.md](/STYLE.md): rules and guidelines for coding style.
* include/openssl: public headers with API documentation in comments. Also [available online](https://commondatastorage.googleapis.com/chromium-boringssl-docs/headers.html).
* [FUZZING.md](/FUZZING.md): information about fuzzing BoringSSL.
+6 -18
View File
@@ -14,10 +14,10 @@ concerned, balance consistency within a module with the benefits of a
given rule. Module-wide deviations on naming should be respected while
integer and return value conventions take precedence over consistency.
Modules from OpenSSL's legacy ASN.1 and X.509 stack are retained for
compatibility and left largely unmodified. To ease importing patches from
upstream, they match OpenSSL's new indentation style. For Emacs,
`doc/openssl-c-indent.el` from OpenSSL may be helpful in this.
Some modules have seen few changes, so they still retain the original
indentation style for now. When editing these, try to retain the
original style. For Emacs, `doc/c-indentation.el` from OpenSSL may be
helpful in this.
## Language
@@ -27,9 +27,7 @@ Google style guide do not apply. Support for C99 features depends on
our target platforms. Typically, Chromium's target MSVC is the most
restrictive.
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.
Variable declarations in the middle of a function are allowed.
Comments should be `/* C-style */` for consistency.
@@ -45,16 +43,6 @@ not
Rather than `malloc()` and `free()`, use the wrappers `OPENSSL_malloc()`
and `OPENSSL_free()`. Use the standard C `assert()` function freely.
Use the following wrappers, found in `crypto/internal.h` instead of the
corresponding C standard library functions. They behave the same but avoid
confusing undefined behavior.
* `OPENSSL_memchr`
* `OPENSSL_memcmp`
* `OPENSSL_memcpy`
* `OPENSSL_memmove`
* `OPENSSL_memset`
For new constants, prefer enums when the values are sequential and typed
constants for flags. If adding values to an existing set of `#define`s,
continue with `#define`.
@@ -169,7 +157,7 @@ For example,
/* CBB_add_asn sets |*out_contents| to a |CBB| into which the contents of an
* ASN.1 object can be written. The |tag| argument will be used as the tag for
* the object. It returns one on success or zero on error. */
OPENSSL_EXPORT int CBB_add_asn1(CBB *cbb, CBB *out_contents, unsigned tag);
OPENSSL_EXPORT int CBB_add_asn1(CBB *cbb, CBB *out_contents, uint8_t tag);
## Documentation
+1 -1
View File
@@ -1,4 +1,4 @@
# This file is used by gcl to get repository specific information.
# This file is used by gcl to get repository specific information.
GERRIT_HOST: True
GERRIT_PORT: True
CODE_REVIEW_SERVER: https://boringssl-review.googlesource.com
+65 -127
View File
@@ -1,54 +1,34 @@
include_directories(../include)
if(UNIX)
if(APPLE)
if (${ARCH} STREQUAL "x86")
set(PERLASM_FLAGS "-fPIC -DOPENSSL_IA32_SSE2")
endif()
set(PERLASM_STYLE macosx)
set(ASM_EXT S)
enable_language(ASM)
elseif(UNIX)
if (${ARCH} STREQUAL "aarch64")
# The "armx" Perl scripts look for "64" in the style argument
# in order to decide whether to generate 32- or 64-bit asm.
if (APPLE)
set(PERLASM_STYLE ios64)
else()
set(PERLASM_STYLE linux64)
endif()
set(PERLASM_STYLE linux64)
elseif (${ARCH} STREQUAL "arm")
if (APPLE)
set(PERLASM_STYLE ios32)
else()
set(PERLASM_STYLE linux32)
endif()
elseif (${ARCH} STREQUAL "ppc64le")
set(PERLASM_STYLE ppc64le)
set(PERLASM_STYLE linux32)
elseif (${ARCH} STREQUAL "x86")
set(PERLASM_FLAGS "-fPIC -DOPENSSL_IA32_SSE2")
set(PERLASM_STYLE elf)
else()
if (${ARCH} STREQUAL "x86")
set(PERLASM_FLAGS "-fPIC -DOPENSSL_IA32_SSE2")
endif()
if (APPLE)
set(PERLASM_STYLE macosx)
else()
set(PERLASM_STYLE elf)
endif()
set(PERLASM_STYLE elf)
endif()
set(ASM_EXT S)
enable_language(ASM)
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -Wa,--noexecstack")
# Clang's integerated assembler does not support debug symbols.
if(NOT CMAKE_ASM_COMPILER_ID MATCHES "Clang")
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -Wa,-g")
endif()
# 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}")
endif()
foreach(arch ${CMAKE_OSX_ARCHITECTURES})
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -arch ${arch}")
endforeach()
endif()
else()
if (CMAKE_CL_64)
message("Using nasm")
set(PERLASM_STYLE nasm)
else()
message("Using win32n")
set(PERLASM_STYLE win32n)
set(PERLASM_FLAGS "-DOPENSSL_IA32_SSE2")
endif()
@@ -61,11 +41,10 @@ endif()
function(perlasm dest src)
add_custom_command(
OUTPUT ${dest}
COMMAND ${PERL_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/${src} ${PERLASM_STYLE} ${PERLASM_FLAGS} ${ARGN} ${dest}
COMMAND ${PERL_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/${src} ${PERLASM_STYLE} ${PERLASM_FLAGS} ${ARGN} > ${dest}
DEPENDS
${src}
${PROJECT_SOURCE_DIR}/crypto/perlasm/arm-xlate.pl
${PROJECT_SOURCE_DIR}/crypto/perlasm/ppc-xlate.pl
${PROJECT_SOURCE_DIR}/crypto/perlasm/x86_64-xlate.pl
${PROJECT_SOURCE_DIR}/crypto/perlasm/x86asm.pl
${PROJECT_SOURCE_DIR}/crypto/perlasm/x86gas.pl
@@ -82,9 +61,14 @@ add_subdirectory(err)
add_subdirectory(buf)
add_subdirectory(base64)
add_subdirectory(bytestring)
add_subdirectory(pool)
# Level 0.2 - depends on nothing but itself
add_subdirectory(sha)
add_subdirectory(md4)
add_subdirectory(md5)
add_subdirectory(modes)
add_subdirectory(aes)
add_subdirectory(des)
add_subdirectory(rc4)
add_subdirectory(conf)
add_subdirectory(chacha)
@@ -92,11 +76,11 @@ add_subdirectory(poly1305)
add_subdirectory(curve25519)
# Level 1, depends only on 0.*
add_subdirectory(digest_extra)
add_subdirectory(cipher_extra)
add_subdirectory(rand_extra)
add_subdirectory(digest)
add_subdirectory(cipher)
add_subdirectory(rand)
add_subdirectory(bio)
add_subdirectory(bn_extra)
add_subdirectory(bn)
add_subdirectory(obj)
add_subdirectory(asn1)
@@ -104,11 +88,11 @@ add_subdirectory(asn1)
add_subdirectory(engine)
add_subdirectory(dh)
add_subdirectory(dsa)
add_subdirectory(rsa_extra)
add_subdirectory(ec_extra)
add_subdirectory(rsa)
add_subdirectory(ec)
add_subdirectory(ecdh)
add_subdirectory(ecdsa_extra)
add_subdirectory(hmac_extra)
add_subdirectory(ecdsa)
add_subdirectory(hmac)
# Level 3
add_subdirectory(cmac)
@@ -119,25 +103,21 @@ add_subdirectory(x509)
add_subdirectory(x509v3)
# Level 4
add_subdirectory(pkcs7)
add_subdirectory(pkcs8)
# Test support code
add_subdirectory(test)
add_subdirectory(fipsmodule)
add_library(
crypto_base
OBJECT
crypto
cpu-aarch64-linux.c
cpu-arm.c
cpu-arm-linux.c
cpu-intel.c
cpu-ppc64le.c
crypto.c
directory_posix.c
directory_win.c
ex_data.c
mem.c
refcount_c11.c
@@ -146,72 +126,64 @@ add_library(
thread_none.c
thread_pthread.c
thread_win.c
)
time_support.c
if(FIPS)
SET_SOURCE_FILES_PROPERTIES(fipsmodule/bcm.o PROPERTIES EXTERNAL_OBJECT true)
SET_SOURCE_FILES_PROPERTIES(fipsmodule/bcm.o PROPERTIES GENERATED true)
set(
CRYPTO_FIPS_OBJECTS
fipsmodule/bcm.o
)
endif()
add_library(
crypto
$<TARGET_OBJECTS:crypto_base>
$<TARGET_OBJECTS:stack>
$<TARGET_OBJECTS:lhash>
$<TARGET_OBJECTS:err>
$<TARGET_OBJECTS:base64>
$<TARGET_OBJECTS:bytestring>
$<TARGET_OBJECTS:pool>
$<TARGET_OBJECTS:fipsmodule>
$<TARGET_OBJECTS:digest_extra>
$<TARGET_OBJECTS:cipher_extra>
$<TARGET_OBJECTS:sha>
$<TARGET_OBJECTS:md4>
$<TARGET_OBJECTS:md5>
$<TARGET_OBJECTS:digest>
$<TARGET_OBJECTS:cipher>
$<TARGET_OBJECTS:modes>
$<TARGET_OBJECTS:aes>
$<TARGET_OBJECTS:des>
$<TARGET_OBJECTS:rc4>
$<TARGET_OBJECTS:conf>
$<TARGET_OBJECTS:chacha>
$<TARGET_OBJECTS:poly1305>
$<TARGET_OBJECTS:curve25519>
$<TARGET_OBJECTS:buf>
$<TARGET_OBJECTS:bn_extra>
$<TARGET_OBJECTS:bn>
$<TARGET_OBJECTS:bio>
$<TARGET_OBJECTS:rand_extra>
$<TARGET_OBJECTS:rand>
$<TARGET_OBJECTS:obj>
$<TARGET_OBJECTS:asn1>
$<TARGET_OBJECTS:engine>
$<TARGET_OBJECTS:dh>
$<TARGET_OBJECTS:dsa>
$<TARGET_OBJECTS:rsa_extra>
$<TARGET_OBJECTS:ec_extra>
$<TARGET_OBJECTS:rsa>
$<TARGET_OBJECTS:ec>
$<TARGET_OBJECTS:ecdh>
$<TARGET_OBJECTS:ecdsa_extra>
$<TARGET_OBJECTS:ecdsa>
$<TARGET_OBJECTS:hmac>
$<TARGET_OBJECTS:cmac>
$<TARGET_OBJECTS:evp>
$<TARGET_OBJECTS:hkdf>
$<TARGET_OBJECTS:pem>
$<TARGET_OBJECTS:x509>
$<TARGET_OBJECTS:x509v3>
$<TARGET_OBJECTS:pkcs7>
$<TARGET_OBJECTS:pkcs8_lib>
${CRYPTO_FIPS_OBJECTS}
$<TARGET_OBJECTS:pkcs8>
)
if(FIPS)
add_dependencies(crypto bcm_o_target)
endif()
SET_TARGET_PROPERTIES(crypto PROPERTIES LINKER_LANGUAGE C)
if(NOT MSVC AND NOT ANDROID)
target_link_libraries(crypto pthread)
endif()
add_executable(
constant_time_test
constant_time_test.c
$<TARGET_OBJECTS:test_support>
)
target_link_libraries(constant_time_test crypto)
add_dependencies(all_tests constant_time_test)
add_executable(
thread_test
@@ -223,45 +195,11 @@ add_executable(
target_link_libraries(thread_test crypto)
add_dependencies(all_tests thread_test)
# TODO(davidben): Convert the remaining tests to GTest.
add_executable(
crypto_test
refcount_test
asn1/asn1_test.cc
base64/base64_test.cc
bio/bio_test.cc
bytestring/bytestring_test.cc
chacha/chacha_test.cc
cipher_extra/aead_extra_test.cc
cmac/cmac_test.cc
compiler_test.cc
constant_time_test.cc
curve25519/ed25519_test.cc
curve25519/spake25519_test.cc
curve25519/x25519_test.cc
dh/dh_test.cc
digest_extra/digest_test.cc
dsa/dsa_test.cc
err/err_test.cc
evp/evp_extra_test.cc
evp/pbkdf_test.cc
fipsmodule/aes/aes_test.cc
fipsmodule/ec/ec_test.cc
fipsmodule/rand/ctrdrbg_test.cc
hkdf/hkdf_test.cc
lhash/lhash_test.cc
pool/pool_test.cc
refcount_test.cc
rsa_extra/rsa_test.cc
test/file_test_gtest.cc
$<TARGET_OBJECTS:crypto_test_data>
$<TARGET_OBJECTS:gtest_main>
$<TARGET_OBJECTS:test_support>
refcount_test.c
)
target_link_libraries(crypto_test crypto gtest)
if (WIN32)
target_link_libraries(crypto_test ws2_32)
endif()
add_dependencies(all_tests crypto_test)
target_link_libraries(refcount_test crypto)
add_dependencies(all_tests refcount_test)
+72
View File
@@ -0,0 +1,72 @@
include_directories(../../include)
if (${ARCH} STREQUAL "x86_64")
set(
AES_ARCH_SOURCES
aes-x86_64.${ASM_EXT}
aesni-x86_64.${ASM_EXT}
bsaes-x86_64.${ASM_EXT}
vpaes-x86_64.${ASM_EXT}
)
endif()
if (${ARCH} STREQUAL "x86")
set(
AES_ARCH_SOURCES
aes-586.${ASM_EXT}
vpaes-x86.${ASM_EXT}
aesni-x86.${ASM_EXT}
)
endif()
if (${ARCH} STREQUAL "arm")
set(
AES_ARCH_SOURCES
aes-armv4.${ASM_EXT}
bsaes-armv7.${ASM_EXT}
aesv8-armx.${ASM_EXT}
)
endif()
if (${ARCH} STREQUAL "aarch64")
set(
AES_ARCH_SOURCES
aesv8-armx.${ASM_EXT}
)
endif()
add_library(
aes
OBJECT
aes.c
mode_wrappers.c
${AES_ARCH_SOURCES}
)
perlasm(aes-x86_64.${ASM_EXT} asm/aes-x86_64.pl)
perlasm(aesni-x86_64.${ASM_EXT} asm/aesni-x86_64.pl)
perlasm(bsaes-x86_64.${ASM_EXT} asm/bsaes-x86_64.pl)
perlasm(vpaes-x86_64.${ASM_EXT} asm/vpaes-x86_64.pl)
perlasm(aes-586.${ASM_EXT} asm/aes-586.pl)
perlasm(vpaes-x86.${ASM_EXT} asm/vpaes-x86.pl)
perlasm(aesni-x86.${ASM_EXT} asm/aesni-x86.pl)
perlasm(aes-armv4.${ASM_EXT} asm/aes-armv4.pl)
perlasm(bsaes-armv7.${ASM_EXT} asm/bsaes-armv7.pl)
perlasm(aesv8-armx.${ASM_EXT} asm/aesv8-armx.pl)
add_executable(
aes_test
aes_test.cc
$<TARGET_OBJECTS:test_support>
)
target_link_libraries(aes_test crypto)
add_dependencies(all_tests aes_test)
@@ -49,11 +49,11 @@
#include <openssl/aes.h>
#include <assert.h>
#include <stdlib.h>
#include <openssl/cpu.h>
#include "internal.h"
#include "../modes/internal.h"
#if defined(OPENSSL_NO_ASM) || \
@@ -1060,6 +1060,44 @@ void AES_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
#else
#if defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)
static int hwaes_capable(void) {
return CRYPTO_is_ARMv8_AES_capable();
}
int aes_v8_set_encrypt_key(const uint8_t *user_key, const int bits,
AES_KEY *key);
int aes_v8_set_decrypt_key(const uint8_t *user_key, const int bits,
AES_KEY *key);
void aes_v8_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key);
void aes_v8_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key);
#else
static int hwaes_capable(void) {
return 0;
}
static int aes_v8_set_encrypt_key(const uint8_t *user_key, int bits, AES_KEY *key) {
abort();
}
static int aes_v8_set_decrypt_key(const uint8_t *user_key, int bits, AES_KEY *key) {
abort();
}
static void aes_v8_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
abort();
}
static void aes_v8_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
abort();
}
#endif
/* In this case several functions are provided by asm code. However, one cannot
* control asm symbol visibility with command line flags and such so they are
* always hidden and wrapped by these C functions, which can be so
@@ -1068,7 +1106,7 @@ void AES_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
void asm_AES_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key);
void AES_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
if (hwaes_capable()) {
aes_hw_encrypt(in, out, key);
aes_v8_encrypt(in, out, key);
} else {
asm_AES_encrypt(in, out, key);
}
@@ -1077,7 +1115,7 @@ void AES_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
void asm_AES_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key);
void AES_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
if (hwaes_capable()) {
aes_hw_decrypt(in, out, key);
aes_v8_decrypt(in, out, key);
} else {
asm_AES_decrypt(in, out, key);
}
@@ -1086,7 +1124,7 @@ void AES_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
int asm_AES_set_encrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey);
int AES_set_encrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey) {
if (hwaes_capable()) {
return aes_hw_set_encrypt_key(key, bits, aeskey);
return aes_v8_set_encrypt_key(key, bits, aeskey);
} else {
return asm_AES_set_encrypt_key(key, bits, aeskey);
}
@@ -1095,7 +1133,7 @@ int AES_set_encrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey) {
int asm_AES_set_decrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey);
int AES_set_decrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey) {
if (hwaes_capable()) {
return aes_hw_set_decrypt_key(key, bits, aeskey);
return aes_v8_set_decrypt_key(key, bits, aeskey);
} else {
return asm_AES_set_decrypt_key(key, bits, aeskey);
}
+102
View File
@@ -0,0 +1,102 @@
/* Copyright (c) 2015, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#include <stdio.h>
#include <string.h>
#include <openssl/aes.h>
#include <openssl/crypto.h>
static bool TestAES(const uint8_t *key, size_t key_len,
const uint8_t plaintext[AES_BLOCK_SIZE],
const uint8_t ciphertext[AES_BLOCK_SIZE]) {
AES_KEY aes_key;
if (AES_set_encrypt_key(key, key_len * 8, &aes_key) != 0) {
fprintf(stderr, "AES_set_encrypt_key failed\n");
return false;
}
// Test encryption.
uint8_t block[AES_BLOCK_SIZE];
AES_encrypt(plaintext, block, &aes_key);
if (memcmp(block, ciphertext, AES_BLOCK_SIZE) != 0) {
fprintf(stderr, "AES_encrypt gave the wrong output\n");
return false;
}
// Test in-place encryption.
memcpy(block, plaintext, AES_BLOCK_SIZE);
AES_encrypt(block, block, &aes_key);
if (memcmp(block, ciphertext, AES_BLOCK_SIZE) != 0) {
fprintf(stderr, "AES_encrypt gave the wrong output\n");
return false;
}
if (AES_set_decrypt_key(key, key_len * 8, &aes_key) != 0) {
fprintf(stderr, "AES_set_decrypt_key failed\n");
return false;
}
// Test decryption.
AES_decrypt(ciphertext, block, &aes_key);
if (memcmp(block, plaintext, AES_BLOCK_SIZE) != 0) {
fprintf(stderr, "AES_decrypt gave the wrong output\n");
return false;
}
// Test in-place decryption.
memcpy(block, ciphertext, AES_BLOCK_SIZE);
AES_decrypt(block, block, &aes_key);
if (memcmp(block, plaintext, AES_BLOCK_SIZE) != 0) {
fprintf(stderr, "AES_decrypt gave the wrong output\n");
return false;
}
return true;
}
int main() {
CRYPTO_library_init();
// Test vectors from FIPS-197, Appendix C.
if (!TestAES((const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07"
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
128 / 8,
(const uint8_t *)"\x00\x11\x22\x33\x44\x55\x66\x77"
"\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
(const uint8_t *)"\x69\xc4\xe0\xd8\x6a\x7b\x04\x30"
"\xd8\xcd\xb7\x80\x70\xb4\xc5\x5a") ||
!TestAES((const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07"
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
"\x10\x11\x12\x13\x14\x15\x16\x17",
192 / 8,
(const uint8_t *)"\x00\x11\x22\x33\x44\x55\x66\x77"
"\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
(const uint8_t *)"\xdd\xa9\x7c\xa4\x86\x4c\xdf\xe0"
"\x6e\xaf\x70\xa0\xec\x0d\x71\x91") ||
!TestAES((const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07"
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
"\x10\x11\x12\x13\x14\x15\x16\x17"
"\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
256 / 8,
(const uint8_t *)"\x00\x11\x22\x33\x44\x55\x66\x77"
"\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
(const uint8_t *)"\x8e\xa2\xb7\xca\x51\x67\x45\xbf"
"\xea\xfc\x49\x90\x4b\x49\x60\x89")) {
return false;
}
printf("PASS\n");
return 0;
}
@@ -116,7 +116,7 @@
# words every cache-line is *guaranteed* to be accessed within ~50
# cycles window. Why just SSE? Because it's needed on hyper-threading
# CPU! Which is also why it's prefetched with 64 byte stride. Best
# part is that it has no negative effect on performance:-)
# part is that it has no negative effect on performance:-)
#
# Version 4.3 implements switch between compact and non-compact block
# functions in AES_cbc_encrypt depending on how much data was asked
@@ -188,14 +188,10 @@
# window, which is actually *less* than RDTSC latency on Intel P4!
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
push(@INC,"${dir}","${dir}../../../perlasm");
push(@INC,"${dir}","${dir}../../perlasm");
require "x86asm.pl";
$output = pop;
open OUT,">$output";
*STDOUT=*OUT;
&asm_init($ARGV[0],$x86only = $ARGV[$#ARGV] eq "386");
&asm_init($ARGV[0],"aes-586.pl",$x86only = $ARGV[$#ARGV] eq "386");
&static_label("AES_Te");
&static_label("AES_Td");
@@ -578,7 +574,7 @@ sub enctransform()
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# | mm4 | mm0 |
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# | s3 | s2 | s1 | s0 |
# | s3 | s2 | s1 | s0 |
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
# |15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0|
# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
@@ -798,7 +794,7 @@ sub encstep()
if ($i==3) { $tmp=$s[3]; &mov ($s[2],$__s1); }##%ecx
elsif($i==2){ &movz ($tmp,&HB($s[3])); }#%ebx[2]
else { &mov ($tmp,$s[3]);
else { &mov ($tmp,$s[3]);
&shr ($tmp,24) }
&xor ($out,&DWP(1,$te,$tmp,8));
if ($i<2) { &mov (&DWP(4+4*$i,"esp"),$out); }
@@ -1551,7 +1547,7 @@ sub sse_deccompact()
&pxor ("mm1","mm3"); &pxor ("mm5","mm7"); # tp4
&pshufw ("mm3","mm1",0xb1); &pshufw ("mm7","mm5",0xb1);
&pxor ("mm0","mm1"); &pxor ("mm4","mm5"); # ^= tp4
&pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= ROTATE(tp4,16)
&pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= ROTATE(tp4,16)
&pxor ("mm3","mm3"); &pxor ("mm7","mm7");
&pcmpgtb("mm3","mm1"); &pcmpgtb("mm7","mm5");
@@ -2021,7 +2017,7 @@ sub declast()
{
# stack frame layout
# -4(%esp) # return address 0(%esp)
# 0(%esp) # s0 backing store 4(%esp)
# 0(%esp) # s0 backing store 4(%esp)
# 4(%esp) # s1 backing store 8(%esp)
# 8(%esp) # s2 backing store 12(%esp)
# 12(%esp) # s3 backing store 16(%esp)
@@ -2731,7 +2727,7 @@ sub enckey()
&mov (&DWP(80,"edi"),10); # setup number of rounds
&xor ("eax","eax");
&jmp (&label("exit"));
&set_label("12rounds");
&mov ("eax",&DWP(0,"esi")); # copy first 6 dwords
&mov ("ebx",&DWP(4,"esi"));
@@ -2989,5 +2985,3 @@ sub deckey()
&asciz("AES for x86, CRYPTOGAMS by <appro\@openssl.org>");
&asm_finish();
close STDOUT;
@@ -33,13 +33,13 @@
# improvement on Cortex A8 core and ~21.5 cycles per byte.
$flavour = shift;
if ($flavour=~/\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
else { while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {} }
if ($flavour=~/^\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
else { while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {} }
if ($flavour && $flavour ne "void") {
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
( $xlate="${dir}../../../perlasm/arm-xlate.pl" and -f $xlate) or
( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
die "can't locate arm-xlate.pl";
open STDOUT,"| \"$^X\" $xlate $flavour $output";
+27 -26
View File
@@ -34,10 +34,10 @@ $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
( $xlate="${dir}../../../perlasm/x86_64-xlate.pl" and -f $xlate) or
( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
die "can't locate x86_64-xlate.pl";
open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
open OUT,"| \"$^X\" $xlate $flavour $output";
*STDOUT=*OUT;
$verticalspin=1; # unlike 32-bit version $verticalspin performs
@@ -590,7 +590,6 @@ $code.=<<___;
.type asm_AES_encrypt,\@function,3
.hidden asm_AES_encrypt
asm_AES_encrypt:
mov %rsp,%rax
push %rbx
push %rbp
push %r12
@@ -599,6 +598,7 @@ asm_AES_encrypt:
push %r15
# allocate frame "above" key schedule
mov %rsp,%r10
lea -63(%rdx),%rcx # %rdx is key argument
and \$-64,%rsp
sub %rsp,%rcx
@@ -608,7 +608,7 @@ asm_AES_encrypt:
sub \$32,%rsp
mov %rsi,16(%rsp) # save out
mov %rax,24(%rsp) # save original stack pointer
mov %r10,24(%rsp) # save real stack pointer
.Lenc_prologue:
mov %rdx,$key
@@ -640,13 +640,13 @@ asm_AES_encrypt:
mov $s2,8($out)
mov $s3,12($out)
mov -48(%rsi),%r15
mov -40(%rsi),%r14
mov -32(%rsi),%r13
mov -24(%rsi),%r12
mov -16(%rsi),%rbp
mov -8(%rsi),%rbx
lea (%rsi),%rsp
mov (%rsi),%r15
mov 8(%rsi),%r14
mov 16(%rsi),%r13
mov 24(%rsi),%r12
mov 32(%rsi),%rbp
mov 40(%rsi),%rbx
lea 48(%rsi),%rsp
.Lenc_epilogue:
ret
.size asm_AES_encrypt,.-asm_AES_encrypt
@@ -1186,7 +1186,6 @@ $code.=<<___;
.type asm_AES_decrypt,\@function,3
.hidden asm_AES_decrypt
asm_AES_decrypt:
mov %rsp,%rax
push %rbx
push %rbp
push %r12
@@ -1195,6 +1194,7 @@ asm_AES_decrypt:
push %r15
# allocate frame "above" key schedule
mov %rsp,%r10
lea -63(%rdx),%rcx # %rdx is key argument
and \$-64,%rsp
sub %rsp,%rcx
@@ -1204,7 +1204,7 @@ asm_AES_decrypt:
sub \$32,%rsp
mov %rsi,16(%rsp) # save out
mov %rax,24(%rsp) # save original stack pointer
mov %r10,24(%rsp) # save real stack pointer
.Ldec_prologue:
mov %rdx,$key
@@ -1238,13 +1238,13 @@ asm_AES_decrypt:
mov $s2,8($out)
mov $s3,12($out)
mov -48(%rsi),%r15
mov -40(%rsi),%r14
mov -32(%rsi),%r13
mov -24(%rsi),%r12
mov -16(%rsi),%rbp
mov -8(%rsi),%rbx
lea (%rsi),%rsp
mov (%rsi),%r15
mov 8(%rsi),%r14
mov 16(%rsi),%r13
mov 24(%rsi),%r12
mov 32(%rsi),%rbp
mov 40(%rsi),%rbx
lea 48(%rsi),%rsp
.Ldec_epilogue:
ret
.size asm_AES_decrypt,.-asm_AES_decrypt
@@ -1286,7 +1286,7 @@ $code.=<<___;
asm_AES_set_encrypt_key:
push %rbx
push %rbp
push %r12 # redundant, but allows to share
push %r12 # redundant, but allows to share
push %r13 # exception handler...
push %r14
push %r15
@@ -1412,7 +1412,7 @@ $code.=<<___;
xor %rax,%rax
jmp .Lexit
.L14rounds:
.L14rounds:
mov 0(%rsi),%rax # copy first 8 dwords
mov 8(%rsi),%rbx
mov 16(%rsi),%rcx
@@ -1660,12 +1660,12 @@ asm_AES_cbc_encrypt:
mov %r9d,%r9d # clear upper half of enc
lea .LAES_Te(%rip),$sbox
lea .LAES_Td(%rip),%r10
cmp \$0,%r9
cmoveq %r10,$sbox
jne .Lcbc_picked_te
lea .LAES_Td(%rip),$sbox
.Lcbc_picked_te:
leaq OPENSSL_ia32cap_P(%rip),%r10
mov (%r10), %r10d
mov OPENSSL_ia32cap_P(%rip),%r10d
cmp \$$speed_limit,%rdx
jb .Lcbc_slow_prologue
test \$15,%rdx
@@ -2565,6 +2565,7 @@ block_se_handler:
jae .Lin_block_prologue
mov 24(%rax),%rax # pull saved real stack pointer
lea 48(%rax),%rax # adjust...
mov -8(%rax),%rbx
mov -16(%rax),%rbp
@@ -51,9 +51,7 @@
# Westmere 3.77/1.37 1.37 1.52 1.27
# * Bridge 5.07/0.98 0.99 1.09 0.91
# Haswell 4.44/0.80 0.97 1.03 0.72
# Skylake 2.68/0.65 0.65 0.66 0.64
# Silvermont 5.77/3.56 3.67 4.03 3.46
# Goldmont 3.84/1.39 1.39 1.63 1.31
# Bulldozer 5.80/0.98 1.05 1.24 0.93
$PREFIX="aesni"; # if $PREFIX is set to "AES", the script
@@ -62,14 +60,10 @@ $PREFIX="aesni"; # if $PREFIX is set to "AES", the script
$inline=1; # inline _aesni_[en|de]crypt
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
push(@INC,"${dir}","${dir}../../../perlasm");
push(@INC,"${dir}","${dir}../../perlasm");
require "x86asm.pl";
$output = pop;
open OUT,">$output";
*STDOUT=*OUT;
&asm_init($ARGV[0]);
&asm_init($ARGV[0],$0);
&external_label("OPENSSL_ia32cap_P");
&static_label("key_const");
@@ -1042,7 +1036,7 @@ if ($PREFIX eq "aesni") {
&set_label("ctr32_one_shortcut",16);
&movups ($inout0,&QWP(0,$rounds_)); # load ivec
&mov ($rounds,&DWP(240,$key));
&set_label("ctr32_one");
if ($inline)
{ &aesni_inline_generate1("enc"); }
@@ -2529,5 +2523,3 @@ if ($PREFIX eq "aesni") {
&asciz("AES for Intel AES-NI, CRYPTOGAMS by <appro\@openssl.org>");
&asm_finish();
close STDOUT;
File diff suppressed because it is too large Load Diff
@@ -36,13 +36,13 @@ $output = shift;
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
( $xlate="${dir}../../../perlasm/arm-xlate.pl" and -f $xlate) or
( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
die "can't locate arm-xlate.pl";
open OUT,"| \"$^X\" $xlate $flavour $output";
*STDOUT=*OUT;
$prefix="aes_hw";
$prefix="aes_v8";
$code=<<___;
#include <openssl/arm_arch.h>
@@ -51,7 +51,7 @@ $code=<<___;
.text
___
$code.=<<___ if ($flavour =~ /64/);
#if !defined(__clang__) || defined(BORINGSSL_CLANG_SUPPORTS_DOT_ARCH)
#if !defined(__clang__)
.arch armv8-a+crypto
#endif
___
@@ -957,21 +957,21 @@ if ($flavour =~ /64/) { ######## 64-bit code
$arg =~ m/q([0-9]+),\s*\{q([0-9]+)\},\s*q([0-9]+)/o &&
sprintf "vtbl.8 d%d,{q%d},d%d\n\t".
"vtbl.8 d%d,{q%d},d%d", 2*$1,$2,2*$3, 2*$1+1,$2,2*$3+1;
"vtbl.8 d%d,{q%d},d%d", 2*$1,$2,2*$3, 2*$1+1,$2,2*$3+1;
}
sub unvdup32 {
my $arg=shift;
$arg =~ m/q([0-9]+),\s*q([0-9]+)\[([0-3])\]/o &&
sprintf "vdup.32 q%d,d%d[%d]",$1,2*$2+($3>>1),$3&1;
sprintf "vdup.32 q%d,d%d[%d]",$1,2*$2+($3>>1),$3&1;
}
sub unvmov32 {
my $arg=shift;
$arg =~ m/q([0-9]+)\[([0-3])\],(.*)/o &&
sprintf "vmov.32 d%d[%d],%s",2*$1+($2>>1),$2&1,$3;
sprintf "vmov.32 d%d[%d],%s",2*$1+($2>>1),$2&1,$3;
}
foreach(split("\n",$code)) {
@@ -1,11 +1,4 @@
#! /usr/bin/env perl
# Copyright 2012-2016 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the OpenSSL license (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
#!/usr/bin/env perl
# ====================================================================
# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
@@ -55,13 +48,13 @@
# <ard.biesheuvel@linaro.org>
$flavour = shift;
if ($flavour=~/\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
else { while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {} }
if ($flavour=~/^\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
else { while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {} }
if ($flavour && $flavour ne "void") {
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
( $xlate="${dir}../../../perlasm/arm-xlate.pl" and -f $xlate) or
( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
die "can't locate arm-xlate.pl";
open STDOUT,"| \"$^X\" $xlate $flavour $output";
@@ -91,7 +84,7 @@ my @s=@_[12..15];
sub InBasisChange {
# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb
# output in lsb > [b6, b5, b0, b3, b7, b1, b4, b2] < msb
# output in lsb > [b6, b5, b0, b3, b7, b1, b4, b2] < msb
my @b=@_[0..7];
$code.=<<___;
veor @b[2], @b[2], @b[1]
@@ -738,7 +731,6 @@ $code.=<<___;
.thumb
#else
.code 32
# undef __thumb2__
#endif
.type _bsaes_decrypt8,%function
@@ -1365,7 +1357,7 @@ bsaes_cbc_encrypt:
vmov @XMM[4],@XMM[15] @ just in case ensure that IV
vmov @XMM[5],@XMM[0] @ and input are preserved
bl AES_decrypt
vld1.8 {@XMM[0]}, [$fp] @ load result
vld1.8 {@XMM[0]}, [$fp,:64] @ load result
veor @XMM[0], @XMM[0], @XMM[4] @ ^= IV
vmov @XMM[15], @XMM[5] @ @XMM[5] holds input
vst1.8 {@XMM[0]}, [$rounds] @ write output
@@ -1839,6 +1831,8 @@ $code.=<<___;
b .Lxts_enc_done
.align 4
.Lxts_enc_6:
vst1.64 {@XMM[14]}, [r0,:128] @ next round tweak
veor @XMM[4], @XMM[4], @XMM[12]
#ifndef BSAES_ASM_EXTENDED_KEY
add r4, sp, #0x90 @ pass key schedule
@@ -1874,6 +1868,8 @@ $code.=<<___;
.align 5
.Lxts_enc_5:
vst1.64 {@XMM[13]}, [r0,:128] @ next round tweak
veor @XMM[3], @XMM[3], @XMM[11]
#ifndef BSAES_ASM_EXTENDED_KEY
add r4, sp, #0x90 @ pass key schedule
@@ -1902,6 +1898,8 @@ $code.=<<___;
b .Lxts_enc_done
.align 4
.Lxts_enc_4:
vst1.64 {@XMM[12]}, [r0,:128] @ next round tweak
veor @XMM[2], @XMM[2], @XMM[10]
#ifndef BSAES_ASM_EXTENDED_KEY
add r4, sp, #0x90 @ pass key schedule
@@ -1927,6 +1925,8 @@ $code.=<<___;
b .Lxts_enc_done
.align 4
.Lxts_enc_3:
vst1.64 {@XMM[11]}, [r0,:128] @ next round tweak
veor @XMM[1], @XMM[1], @XMM[9]
#ifndef BSAES_ASM_EXTENDED_KEY
add r4, sp, #0x90 @ pass key schedule
@@ -1951,6 +1951,8 @@ $code.=<<___;
b .Lxts_enc_done
.align 4
.Lxts_enc_2:
vst1.64 {@XMM[10]}, [r0,:128] @ next round tweak
veor @XMM[0], @XMM[0], @XMM[8]
#ifndef BSAES_ASM_EXTENDED_KEY
add r4, sp, #0x90 @ pass key schedule
@@ -1973,7 +1975,7 @@ $code.=<<___;
.align 4
.Lxts_enc_1:
mov r0, sp
veor @XMM[0], @XMM[0], @XMM[8]
veor @XMM[0], @XMM[8]
mov r1, sp
vst1.8 {@XMM[0]}, [sp,:128]
mov r2, $key
@@ -2285,6 +2287,8 @@ $code.=<<___;
b .Lxts_dec_done
.align 4
.Lxts_dec_5:
vst1.64 {@XMM[13]}, [r0,:128] @ next round tweak
veor @XMM[3], @XMM[3], @XMM[11]
#ifndef BSAES_ASM_EXTENDED_KEY
add r4, sp, #0x90 @ pass key schedule
@@ -2313,6 +2317,8 @@ $code.=<<___;
b .Lxts_dec_done
.align 4
.Lxts_dec_4:
vst1.64 {@XMM[12]}, [r0,:128] @ next round tweak
veor @XMM[2], @XMM[2], @XMM[10]
#ifndef BSAES_ASM_EXTENDED_KEY
add r4, sp, #0x90 @ pass key schedule
@@ -2338,6 +2344,8 @@ $code.=<<___;
b .Lxts_dec_done
.align 4
.Lxts_dec_3:
vst1.64 {@XMM[11]}, [r0,:128] @ next round tweak
veor @XMM[1], @XMM[1], @XMM[9]
#ifndef BSAES_ASM_EXTENDED_KEY
add r4, sp, #0x90 @ pass key schedule
@@ -2362,6 +2370,8 @@ $code.=<<___;
b .Lxts_dec_done
.align 4
.Lxts_dec_2:
vst1.64 {@XMM[10]}, [r0,:128] @ next round tweak
veor @XMM[0], @XMM[0], @XMM[8]
#ifndef BSAES_ASM_EXTENDED_KEY
add r4, sp, #0x90 @ pass key schedule
@@ -2384,12 +2394,12 @@ $code.=<<___;
.align 4
.Lxts_dec_1:
mov r0, sp
veor @XMM[0], @XMM[0], @XMM[8]
veor @XMM[0], @XMM[8]
mov r1, sp
vst1.8 {@XMM[0]}, [sp,:128]
mov r5, $magic @ preserve magic
mov r2, $key
mov r4, $fp @ preserve fp
mov r5, $magic @ preserve magic
bl AES_decrypt
@@ -41,7 +41,6 @@
# Nehalem(**) 7.63 6.88 +11%
# Atom 17.1 16.4 +4%
# Silvermont - 12.9
# Goldmont - 8.85
#
# (*) Comparison is not completely fair, because "this" is ECB,
# i.e. no extra processing such as counter values calculation
@@ -81,7 +80,6 @@
# Nehalem 7.80
# Atom 17.9
# Silvermont 14.0
# Goldmont 10.2
#
# November 2011.
#
@@ -98,10 +96,10 @@ $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
( $xlate="${dir}../../../perlasm/x86_64-xlate.pl" and -f $xlate) or
( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
die "can't locate x86_64-xlate.pl";
open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
open OUT,"| \"$^X\" $xlate $flavour $output";
*STDOUT=*OUT;
my ($inp,$out,$len,$key,$ivp)=("%rdi","%rsi","%rdx","%rcx");
@@ -124,7 +122,7 @@ my @s=@_[12..15];
sub InBasisChange {
# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb
# output in lsb > [b6, b5, b0, b3, b7, b1, b4, b2] < msb
# output in lsb > [b6, b5, b0, b3, b7, b1, b4, b2] < msb
my @b=@_[0..7];
$code.=<<___;
pxor @b[6], @b[5]
@@ -374,7 +372,7 @@ $code.=<<___;
pxor @s[0], @t[3]
pxor @s[1], @t[2]
pxor @s[2], @t[1]
pxor @s[3], @t[0]
pxor @s[3], @t[0]
#Inv_GF16 \t0, \t1, \t2, \t3, \s0, \s1, \s2, \s3
@@ -1327,7 +1325,7 @@ $code.=<<___;
cmp %rax, %rbp
jb .Lecb_enc_bzero
lea 0x78(%rbp),%rax
lea (%rbp),%rsp # restore %rsp
___
$code.=<<___ if ($win64);
movaps 0x40(%rbp), %xmm6
@@ -1340,17 +1338,17 @@ $code.=<<___ if ($win64);
movaps 0xb0(%rbp), %xmm13
movaps 0xc0(%rbp), %xmm14
movaps 0xd0(%rbp), %xmm15
lea 0xa0(%rax), %rax
.Lecb_enc_tail:
lea 0xa0(%rbp), %rsp
___
$code.=<<___;
mov -48(%rax), %r15
mov -40(%rax), %r14
mov -32(%rax), %r13
mov -24(%rax), %r12
mov -16(%rax), %rbx
mov -8(%rax), %rbp
lea (%rax), %rsp # restore %rsp
mov 0x48(%rsp), %r15
mov 0x50(%rsp), %r14
mov 0x58(%rsp), %r13
mov 0x60(%rsp), %r12
mov 0x68(%rsp), %rbx
mov 0x70(%rsp), %rax
lea 0x78(%rsp), %rsp
mov %rax, %rbp
.Lecb_enc_epilogue:
ret
.size bsaes_ecb_encrypt_blocks,.-bsaes_ecb_encrypt_blocks
@@ -1529,7 +1527,7 @@ $code.=<<___;
cmp %rax, %rbp
jb .Lecb_dec_bzero
lea 0x78(%rbp),%rax
lea (%rbp),%rsp # restore %rsp
___
$code.=<<___ if ($win64);
movaps 0x40(%rbp), %xmm6
@@ -1542,17 +1540,17 @@ $code.=<<___ if ($win64);
movaps 0xb0(%rbp), %xmm13
movaps 0xc0(%rbp), %xmm14
movaps 0xd0(%rbp), %xmm15
lea 0xa0(%rax), %rax
.Lecb_dec_tail:
lea 0xa0(%rbp), %rsp
___
$code.=<<___;
mov -48(%rax), %r15
mov -40(%rax), %r14
mov -32(%rax), %r13
mov -24(%rax), %r12
mov -16(%rax), %rbx
mov -8(%rax), %rbp
lea (%rax), %rsp # restore %rsp
mov 0x48(%rsp), %r15
mov 0x50(%rsp), %r14
mov 0x58(%rsp), %r13
mov 0x60(%rsp), %r12
mov 0x68(%rsp), %rbx
mov 0x70(%rsp), %rax
lea 0x78(%rsp), %rsp
mov %rax, %rbp
.Lecb_dec_epilogue:
ret
.size bsaes_ecb_decrypt_blocks,.-bsaes_ecb_decrypt_blocks
@@ -1819,7 +1817,7 @@ $code.=<<___;
cmp %rax, %rbp
ja .Lcbc_dec_bzero
lea 0x78(%rbp),%rax
lea (%rbp),%rsp # restore %rsp
___
$code.=<<___ if ($win64);
movaps 0x40(%rbp), %xmm6
@@ -1832,17 +1830,17 @@ $code.=<<___ if ($win64);
movaps 0xb0(%rbp), %xmm13
movaps 0xc0(%rbp), %xmm14
movaps 0xd0(%rbp), %xmm15
lea 0xa0(%rax), %rax
.Lcbc_dec_tail:
lea 0xa0(%rbp), %rsp
___
$code.=<<___;
mov -48(%rax), %r15
mov -40(%rax), %r14
mov -32(%rax), %r13
mov -24(%rax), %r12
mov -16(%rax), %rbx
mov -8(%rax), %rbp
lea (%rax), %rsp # restore %rsp
mov 0x48(%rsp), %r15
mov 0x50(%rsp), %r14
mov 0x58(%rsp), %r13
mov 0x60(%rsp), %r12
mov 0x68(%rsp), %rbx
mov 0x70(%rsp), %rax
lea 0x78(%rsp), %rsp
mov %rax, %rbp
.Lcbc_dec_epilogue:
ret
.size bsaes_cbc_encrypt,.-bsaes_cbc_encrypt
@@ -2051,7 +2049,7 @@ $code.=<<___;
cmp %rax, %rbp
ja .Lctr_enc_bzero
lea 0x78(%rbp),%rax
lea (%rbp),%rsp # restore %rsp
___
$code.=<<___ if ($win64);
movaps 0x40(%rbp), %xmm6
@@ -2064,17 +2062,17 @@ $code.=<<___ if ($win64);
movaps 0xb0(%rbp), %xmm13
movaps 0xc0(%rbp), %xmm14
movaps 0xd0(%rbp), %xmm15
lea 0xa0(%rax), %rax
.Lctr_enc_tail:
lea 0xa0(%rbp), %rsp
___
$code.=<<___;
mov -48(%rax), %r15
mov -40(%rax), %r14
mov -32(%rax), %r13
mov -24(%rax), %r12
mov -16(%rax), %rbx
mov -8(%rax), %rbp
lea (%rax), %rsp # restore %rsp
mov 0x48(%rsp), %r15
mov 0x50(%rsp), %r14
mov 0x58(%rsp), %r13
mov 0x60(%rsp), %r12
mov 0x68(%rsp), %rbx
mov 0x70(%rsp), %rax
lea 0x78(%rsp), %rsp
mov %rax, %rbp
.Lctr_enc_epilogue:
ret
.size bsaes_ctr32_encrypt_blocks,.-bsaes_ctr32_encrypt_blocks
@@ -2441,7 +2439,7 @@ $code.=<<___;
cmp %rax, %rbp
ja .Lxts_enc_bzero
lea 0x78(%rbp),%rax
lea (%rbp),%rsp # restore %rsp
___
$code.=<<___ if ($win64);
movaps 0x40(%rbp), %xmm6
@@ -2454,17 +2452,17 @@ $code.=<<___ if ($win64);
movaps 0xb0(%rbp), %xmm13
movaps 0xc0(%rbp), %xmm14
movaps 0xd0(%rbp), %xmm15
lea 0xa0(%rax), %rax
.Lxts_enc_tail:
lea 0xa0(%rbp), %rsp
___
$code.=<<___;
mov -48(%rax), %r15
mov -40(%rax), %r14
mov -32(%rax), %r13
mov -24(%rax), %r12
mov -16(%rax), %rbx
mov -8(%rax), %rbp
lea (%rax), %rsp # restore %rsp
mov 0x48(%rsp), %r15
mov 0x50(%rsp), %r14
mov 0x58(%rsp), %r13
mov 0x60(%rsp), %r12
mov 0x68(%rsp), %rbx
mov 0x70(%rsp), %rax
lea 0x78(%rsp), %rsp
mov %rax, %rbp
.Lxts_enc_epilogue:
ret
.size bsaes_xts_encrypt,.-bsaes_xts_encrypt
@@ -2848,7 +2846,7 @@ $code.=<<___;
cmp %rax, %rbp
ja .Lxts_dec_bzero
lea 0x78(%rbp),%rax
lea (%rbp),%rsp # restore %rsp
___
$code.=<<___ if ($win64);
movaps 0x40(%rbp), %xmm6
@@ -2861,17 +2859,17 @@ $code.=<<___ if ($win64);
movaps 0xb0(%rbp), %xmm13
movaps 0xc0(%rbp), %xmm14
movaps 0xd0(%rbp), %xmm15
lea 0xa0(%rax), %rax
.Lxts_dec_tail:
lea 0xa0(%rbp), %rsp
___
$code.=<<___;
mov -48(%rax), %r15
mov -40(%rax), %r14
mov -32(%rax), %r13
mov -24(%rax), %r12
mov -16(%rax), %rbx
mov -8(%rax), %rbp
lea (%rax), %rsp # restore %rsp
mov 0x48(%rsp), %r15
mov 0x50(%rsp), %r14
mov 0x58(%rsp), %r13
mov 0x60(%rsp), %r12
mov 0x68(%rsp), %rbx
mov 0x70(%rsp), %rax
lea 0x78(%rsp), %rsp
mov %rax, %rbp
.Lxts_dec_epilogue:
ret
.size bsaes_xts_decrypt,.-bsaes_xts_decrypt
@@ -2967,34 +2965,31 @@ se_handler:
mov 0(%r11),%r10d # HandlerData[0]
lea (%rsi,%r10),%r10 # prologue label
cmp %r10,%rbx # context->Rip<=prologue label
jbe .Lin_prologue
cmp %r10,%rbx # context->Rip<prologue label
jb .Lin_prologue
mov 152($context),%rax # pull context->Rsp
mov 4(%r11),%r10d # HandlerData[1]
lea (%rsi,%r10),%r10 # epilogue label
cmp %r10,%rbx # context->Rip>=epilogue label
jae .Lin_prologue
mov 8(%r11),%r10d # HandlerData[2]
lea (%rsi,%r10),%r10 # epilogue label
cmp %r10,%rbx # context->Rip>=tail label
jae .Lin_tail
mov 160($context),%rax # pull context->Rbp
lea 0x40(%rax),%rsi # %xmm save area
lea 512($context),%rdi # &context.Xmm6
mov \$20,%ecx # 10*sizeof(%xmm0)/sizeof(%rax)
.long 0xa548f3fc # cld; rep movsq
lea 0xa0+0x78(%rax),%rax # adjust stack pointer
lea 0xa0(%rax),%rax # adjust stack pointer
.Lin_tail:
mov -48(%rax),%rbp
mov -40(%rax),%rbx
mov -32(%rax),%r12
mov -24(%rax),%r13
mov -16(%rax),%r14
mov -8(%rax),%r15
mov 0x70(%rax),%rbp
mov 0x68(%rax),%rbx
mov 0x60(%rax),%r12
mov 0x58(%rax),%r13
mov 0x50(%rax),%r14
mov 0x48(%rax),%r15
lea 0x78(%rax),%rax # adjust stack pointer
mov %rbx,144($context) # restore context->Rbx
mov %rbp,160($context) # restore context->Rbp
mov %r12,216($context) # restore context->R12
@@ -3075,40 +3070,28 @@ $code.=<<___ if ($ecb);
.byte 9,0,0,0
.rva se_handler
.rva .Lecb_enc_body,.Lecb_enc_epilogue # HandlerData[]
.rva .Lecb_enc_tail
.long 0
.Lecb_dec_info:
.byte 9,0,0,0
.rva se_handler
.rva .Lecb_dec_body,.Lecb_dec_epilogue # HandlerData[]
.rva .Lecb_dec_tail
.long 0
___
$code.=<<___;
.Lcbc_dec_info:
.byte 9,0,0,0
.rva se_handler
.rva .Lcbc_dec_body,.Lcbc_dec_epilogue # HandlerData[]
.rva .Lcbc_dec_tail
.long 0
.Lctr_enc_info:
.byte 9,0,0,0
.rva se_handler
.rva .Lctr_enc_body,.Lctr_enc_epilogue # HandlerData[]
.rva .Lctr_enc_tail
.long 0
.Lxts_enc_info:
.byte 9,0,0,0
.rva se_handler
.rva .Lxts_enc_body,.Lxts_enc_epilogue # HandlerData[]
.rva .Lxts_enc_tail
.long 0
.Lxts_dec_info:
.byte 9,0,0,0
.rva se_handler
.rva .Lxts_dec_body,.Lxts_dec_epilogue # HandlerData[]
.rva .Lxts_dec_tail
.long 0
___
}
@@ -48,14 +48,10 @@
# <appro@openssl.org>
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
push(@INC,"${dir}","${dir}../../../perlasm");
push(@INC,"${dir}","${dir}../../perlasm");
require "x86asm.pl";
$output = pop;
open OUT,">$output";
*STDOUT=*OUT;
&asm_init($ARGV[0],$x86only = $ARGV[$#ARGV] eq "386");
&asm_init($ARGV[0],"vpaes-x86.pl",$x86only = $ARGV[$#ARGV] eq "386");
$PREFIX="vpaes";
@@ -438,7 +434,7 @@ $k_dsbo=0x2c0; # decryption sbox final output
##
&set_label("schedule_192",16);
&movdqu ("xmm0",&QWP(8,$inp)); # load key part 2 (very unaligned)
&call ("_vpaes_schedule_transform"); # input transform
&call ("_vpaes_schedule_transform"); # input transform
&movdqa ("xmm6","xmm0"); # save short part
&pxor ("xmm4","xmm4"); # clear 4
&movhlps("xmm6","xmm4"); # clobber low side with zeros
@@ -469,7 +465,7 @@ $k_dsbo=0x2c0; # decryption sbox final output
##
&set_label("schedule_256",16);
&movdqu ("xmm0",&QWP(16,$inp)); # load key part 2 (unaligned)
&call ("_vpaes_schedule_transform"); # input transform
&call ("_vpaes_schedule_transform"); # input transform
&mov ($round,7);
&set_label("loop_schedule_256");
@@ -480,7 +476,7 @@ $k_dsbo=0x2c0; # decryption sbox final output
&call ("_vpaes_schedule_round");
&dec ($round);
&jz (&label("schedule_mangle_last"));
&call ("_vpaes_schedule_mangle");
&call ("_vpaes_schedule_mangle");
# low round. swap xmm7 and xmm6
&pshufd ("xmm0","xmm0",0xFF);
@@ -603,7 +599,7 @@ $k_dsbo=0x2c0; # decryption sbox final output
# subbyte
&movdqa ("xmm4",&QWP($k_s0F,$const));
&movdqa ("xmm5",&QWP($k_inv,$const)); # 4 : 1/j
&movdqa ("xmm1","xmm4");
&movdqa ("xmm1","xmm4");
&pandn ("xmm1","xmm0");
&psrld ("xmm1",4); # 1 = i
&pand ("xmm0","xmm4"); # 0 = k
@@ -905,5 +901,3 @@ $k_dsbo=0x2c0; # decryption sbox final output
&function_end("${PREFIX}_cbc_encrypt");
&asm_finish();
close STDOUT;
@@ -31,7 +31,6 @@
# Nehalem 29.6/40.3/14.6 10.0/11.8
# Atom 57.3/74.2/32.1 60.9/77.2(***)
# Silvermont 52.7/64.0/19.5 48.8/60.8(***)
# Goldmont 38.9/49.0/17.8 10.6/12.6
#
# (*) "Hyper-threading" in the context refers rather to cache shared
# among multiple cores, than to specifically Intel HTT. As vast
@@ -55,10 +54,10 @@ $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
( $xlate="${dir}../../../perlasm/x86_64-xlate.pl" and -f $xlate) or
( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
die "can't locate x86_64-xlate.pl";
open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
open OUT,"| \"$^X\" $xlate $flavour $output";
*STDOUT=*OUT;
$PREFIX="vpaes";
@@ -165,7 +164,7 @@ _vpaes_encrypt_core:
pshufb %xmm1, %xmm0
ret
.size _vpaes_encrypt_core,.-_vpaes_encrypt_core
##
## Decryption core
##
@@ -326,7 +325,7 @@ _vpaes_schedule_core:
##
.Lschedule_128:
mov \$10, %esi
.Loop_schedule_128:
call _vpaes_schedule_round
dec %rsi
@@ -360,7 +359,7 @@ _vpaes_schedule_core:
.Loop_schedule_192:
call _vpaes_schedule_round
palignr \$8,%xmm6,%xmm0
palignr \$8,%xmm6,%xmm0
call _vpaes_schedule_mangle # save key n
call _vpaes_schedule_192_smear
call _vpaes_schedule_mangle # save key n+1
@@ -386,7 +385,7 @@ _vpaes_schedule_core:
movdqu 16(%rdi),%xmm0 # load key part 2 (unaligned)
call _vpaes_schedule_transform # input transform
mov \$7, %esi
.Loop_schedule_256:
call _vpaes_schedule_mangle # output low result
movdqa %xmm0, %xmm6 # save cur_lo in xmm6
@@ -395,7 +394,7 @@ _vpaes_schedule_core:
call _vpaes_schedule_round
dec %rsi
jz .Lschedule_mangle_last
call _vpaes_schedule_mangle
call _vpaes_schedule_mangle
# low round. swap xmm7 and xmm6
pshufd \$0xFF, %xmm0, %xmm0
@@ -403,10 +402,10 @@ _vpaes_schedule_core:
movdqa %xmm6, %xmm7
call _vpaes_schedule_low_round
movdqa %xmm5, %xmm7
jmp .Loop_schedule_256
##
## .aes_schedule_mangle_last
##
@@ -505,9 +504,9 @@ _vpaes_schedule_round:
# rotate
pshufd \$0xFF, %xmm0, %xmm0
palignr \$1, %xmm0, %xmm0
# fall through...
# low round: same as high round, but no rotation and no rcon.
_vpaes_schedule_low_round:
# smear xmm7
@@ -546,7 +545,7 @@ _vpaes_schedule_low_round:
pxor %xmm4, %xmm0 # 0 = sbox output
# add in smeared stuff
pxor %xmm7, %xmm0
pxor %xmm7, %xmm0
movdqa %xmm0, %xmm7
ret
.size _vpaes_schedule_round,.-_vpaes_schedule_round
+87
View File
@@ -0,0 +1,87 @@
/* ====================================================================
* Copyright (c) 2002-2006 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ==================================================================== */
#ifndef OPENSSL_HEADER_AES_INTERNAL_H
#define OPENSSL_HEADER_AES_INTERNAL_H
#include <openssl/base.h>
#if defined(__cplusplus)
extern "C" {
#endif
#if defined(_MSC_VER) && \
(defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64))
#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
#define GETU32(p) SWAP(*((uint32_t *)(p)))
#define PUTU32(ct, st) \
{ *((uint32_t *)(ct)) = SWAP((st)); }
#else
#define GETU32(pt) \
(((uint32_t)(pt)[0] << 24) ^ ((uint32_t)(pt)[1] << 16) ^ \
((uint32_t)(pt)[2] << 8) ^ ((uint32_t)(pt)[3]))
#define PUTU32(ct, st) \
{ \
(ct)[0] = (uint8_t)((st) >> 24); \
(ct)[1] = (uint8_t)((st) >> 16); \
(ct)[2] = (uint8_t)((st) >> 8); \
(ct)[3] = (uint8_t)(st); \
}
#endif
#define MAXKC (256 / 32)
#define MAXKB (256 / 8)
#define MAXNR 14
#if defined(__cplusplus)
} /* extern C */
#endif
#endif /* OPENSSL_HEADER_AES_INTERNAL_H */
@@ -96,17 +96,13 @@ void AES_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len,
void AES_ofb128_encrypt(const uint8_t *in, uint8_t *out, size_t length,
const AES_KEY *key, uint8_t *ivec, int *num) {
unsigned num_u = (unsigned)(*num);
CRYPTO_ofb128_encrypt(in, out, length, key, ivec, &num_u,
CRYPTO_ofb128_encrypt(in, out, length, key, ivec, num,
(block128_f)AES_encrypt);
*num = (int)num_u;
}
void AES_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t length,
const AES_KEY *key, uint8_t *ivec, int *num,
int enc) {
unsigned num_u = (unsigned)(*num);
CRYPTO_cfb128_encrypt(in, out, length, key, ivec, &num_u, enc,
CRYPTO_cfb128_encrypt(in, out, length, key, ivec, num, enc,
(block128_f)AES_encrypt);
*num = (int)num_u;
}
+17 -1
View File
@@ -7,6 +7,7 @@ add_library(
a_bitstr.c
a_bool.c
a_bytes.c
a_d2i_fp.c
a_dup.c
a_enum.c
@@ -25,6 +26,8 @@ add_library(
asn1_lib.c
asn1_par.c
asn_pack.c
bio_asn1.c
bio_ndef.c
f_enum.c
f_int.c
f_string.c
@@ -33,7 +36,20 @@ add_library(
tasn_enc.c
tasn_fre.c
tasn_new.c
tasn_prn.c
tasn_typ.c
tasn_utl.c
time_support.c
x_bignum.c
x_long.c
)
add_executable(
asn1_test
asn1_test.cc
$<TARGET_OBJECTS:test_support>
)
target_link_libraries(asn1_test crypto)
add_dependencies(all_tests asn1_test)
+3 -6
View File
@@ -61,9 +61,6 @@
#include <openssl/err.h>
#include <openssl/mem.h>
#include "../internal.h"
int ASN1_BIT_STRING_set(ASN1_BIT_STRING *x, unsigned char *d, int len)
{
return M_ASN1_BIT_STRING_set(x, d, len);
@@ -118,7 +115,7 @@ int i2c_ASN1_BIT_STRING(ASN1_BIT_STRING *a, unsigned char **pp)
*(p++) = (unsigned char)bits;
d = a->data;
OPENSSL_memcpy(p, d, len);
memcpy(p, d, len);
p += len;
if (len > 0)
p[-1] &= (0xff << bits);
@@ -165,7 +162,7 @@ ASN1_BIT_STRING *c2i_ASN1_BIT_STRING(ASN1_BIT_STRING **a,
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
goto err;
}
OPENSSL_memcpy(s, p, (int)len);
memcpy(s, p, (int)len);
s[len - 1] &= (0xff << padding);
p += len;
} else
@@ -218,7 +215,7 @@ int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value)
return 0;
}
if (w + 1 - a->length > 0)
OPENSSL_memset(c + a->length, 0, w + 1 - a->length);
memset(c + a->length, 0, w + 1 - a->length);
a->data = c;
a->length = w + 1;
}
+308
View File
@@ -0,0 +1,308 @@
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.] */
#include <openssl/asn1.h>
#include <string.h>
#include <openssl/buf.h>
#include <openssl/err.h>
#include <openssl/mem.h>
static int asn1_collate_primitive(ASN1_STRING *a, ASN1_const_CTX *c);
/*
* type is a 'bitmap' of acceptable string types.
*/
ASN1_STRING *d2i_ASN1_type_bytes(ASN1_STRING **a, const unsigned char **pp,
long length, int type)
{
ASN1_STRING *ret = NULL;
const unsigned char *p;
unsigned char *s;
long len;
int inf, tag, xclass;
int i = 0;
p = *pp;
inf = ASN1_get_object(&p, &len, &tag, &xclass, length);
if (inf & 0x80)
goto err;
if (tag >= 32) {
i = ASN1_R_TAG_VALUE_TOO_HIGH;
goto err;
}
if (!(ASN1_tag2bit(tag) & type)) {
i = ASN1_R_WRONG_TYPE;
goto err;
}
/* If a bit-string, exit early */
if (tag == V_ASN1_BIT_STRING)
return (d2i_ASN1_BIT_STRING(a, pp, length));
if ((a == NULL) || ((*a) == NULL)) {
if ((ret = ASN1_STRING_new()) == NULL)
return (NULL);
} else
ret = (*a);
if (len != 0) {
s = (unsigned char *)OPENSSL_malloc((int)len + 1);
if (s == NULL) {
i = ERR_R_MALLOC_FAILURE;
goto err;
}
memcpy(s, p, (int)len);
s[len] = '\0';
p += len;
} else
s = NULL;
if (ret->data != NULL)
OPENSSL_free(ret->data);
ret->length = (int)len;
ret->data = s;
ret->type = tag;
if (a != NULL)
(*a) = ret;
*pp = p;
return (ret);
err:
OPENSSL_PUT_ERROR(ASN1, i);
if ((ret != NULL) && ((a == NULL) || (*a != ret)))
ASN1_STRING_free(ret);
return (NULL);
}
int i2d_ASN1_bytes(ASN1_STRING *a, unsigned char **pp, int tag, int xclass)
{
int ret, r, constructed;
unsigned char *p;
if (a == NULL)
return (0);
if (tag == V_ASN1_BIT_STRING)
return (i2d_ASN1_BIT_STRING(a, pp));
ret = a->length;
r = ASN1_object_size(0, ret, tag);
if (pp == NULL)
return (r);
p = *pp;
if ((tag == V_ASN1_SEQUENCE) || (tag == V_ASN1_SET))
constructed = 1;
else
constructed = 0;
ASN1_put_object(&p, constructed, ret, tag, xclass);
memcpy(p, a->data, a->length);
p += a->length;
*pp = p;
return (r);
}
ASN1_STRING *d2i_ASN1_bytes(ASN1_STRING **a, const unsigned char **pp,
long length, int Ptag, int Pclass)
{
ASN1_STRING *ret = NULL;
const unsigned char *p;
unsigned char *s;
long len;
int inf, tag, xclass;
int i = 0;
if ((a == NULL) || ((*a) == NULL)) {
if ((ret = ASN1_STRING_new()) == NULL)
return (NULL);
} else
ret = (*a);
p = *pp;
inf = ASN1_get_object(&p, &len, &tag, &xclass, length);
if (inf & 0x80) {
i = ASN1_R_BAD_OBJECT_HEADER;
goto err;
}
if (tag != Ptag) {
i = ASN1_R_WRONG_TAG;
goto err;
}
if (inf & V_ASN1_CONSTRUCTED) {
ASN1_const_CTX c;
c.pp = pp;
c.p = p;
c.inf = inf;
c.slen = len;
c.tag = Ptag;
c.xclass = Pclass;
c.max = (length == 0) ? 0 : (p + length);
if (!asn1_collate_primitive(ret, &c))
goto err;
else {
p = c.p;
}
} else {
if (len != 0) {
if ((ret->length < len) || (ret->data == NULL)) {
if (ret->data != NULL)
OPENSSL_free(ret->data);
s = (unsigned char *)OPENSSL_malloc((int)len + 1);
if (s == NULL) {
i = ERR_R_MALLOC_FAILURE;
goto err;
}
} else
s = ret->data;
memcpy(s, p, (int)len);
s[len] = '\0';
p += len;
} else {
s = NULL;
if (ret->data != NULL)
OPENSSL_free(ret->data);
}
ret->length = (int)len;
ret->data = s;
ret->type = Ptag;
}
if (a != NULL)
(*a) = ret;
*pp = p;
return (ret);
err:
if ((ret != NULL) && ((a == NULL) || (*a != ret)))
ASN1_STRING_free(ret);
OPENSSL_PUT_ERROR(ASN1, i);
return (NULL);
}
/*
* We are about to parse 0..n d2i_ASN1_bytes objects, we are to collapse them
* into the one structure that is then returned
*/
/*
* There have been a few bug fixes for this function from Paul Keogh
* <paul.keogh@sse.ie>, many thanks to him
*/
static int asn1_collate_primitive(ASN1_STRING *a, ASN1_const_CTX *c)
{
ASN1_STRING *os = NULL;
BUF_MEM b;
int num;
b.length = 0;
b.max = 0;
b.data = NULL;
if (a == NULL) {
c->error = ERR_R_PASSED_NULL_PARAMETER;
goto err;
}
num = 0;
for (;;) {
if (c->inf & 1) {
c->eos = ASN1_const_check_infinite_end(&c->p,
(long)(c->max - c->p));
if (c->eos)
break;
} else {
if (c->slen <= 0)
break;
}
c->q = c->p;
if (d2i_ASN1_bytes(&os, &c->p, c->max - c->p, c->tag, c->xclass)
== NULL) {
c->error = ERR_R_ASN1_LIB;
goto err;
}
if (!BUF_MEM_grow_clean(&b, num + os->length)) {
c->error = ERR_R_BUF_LIB;
goto err;
}
memcpy(&(b.data[num]), os->data, os->length);
if (!(c->inf & 1))
c->slen -= (c->p - c->q);
num += os->length;
}
if (!asn1_const_Finish(c))
goto err;
a->length = num;
if (a->data != NULL)
OPENSSL_free(a->data);
a->data = (unsigned char *)b.data;
if (os != NULL)
ASN1_STRING_free(os);
return (1);
err:
OPENSSL_PUT_ERROR(ASN1, c->error);
if (os != NULL)
ASN1_STRING_free(os);
if (b.data != NULL)
OPENSSL_free(b.data);
return (0);
}
+13 -28
View File
@@ -141,7 +141,6 @@ void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x)
#endif
#define HEADER_SIZE 8
#define ASN1_CHUNK_INITIAL_SIZE (16 * 1024)
static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
{
BUF_MEM *b;
@@ -218,42 +217,28 @@ static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
/* suck in c.slen bytes of data */
want = c.slen;
if (want > (len - off)) {
size_t chunk_max = ASN1_CHUNK_INITIAL_SIZE;
want -= (len - off);
if (want > INT_MAX /* BIO_read takes an int length */ ||
len + want < len) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG);
goto err;
}
if (!BUF_MEM_grow_clean(b, len + want)) {
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
goto err;
}
while (want > 0) {
/*
* Read content in chunks of increasing size
* so we can return an error for EOF without
* having to allocate the entire content length
* in one go.
*/
size_t chunk = want > chunk_max ? chunk_max : want;
if (!BUF_MEM_grow_clean(b, len + chunk)) {
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
i = BIO_read(in, &(b->data[len]), want);
if (i <= 0) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ENOUGH_DATA);
goto err;
}
want -= chunk;
while (chunk > 0) {
i = BIO_read(in, &(b->data[len]), chunk);
if (i <= 0) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ENOUGH_DATA);
goto err;
}
/*
* This can't overflow because |len+want| didn't
* overflow.
*/
len += i;
chunk -= i;
}
if (chunk_max < INT_MAX/2)
chunk_max *= 2;
/*
* This can't overflow because |len+want| didn't
* overflow.
*/
len += i;
want -= i;
}
}
if (off + c.slen < off) {
+1 -4
View File
@@ -61,9 +61,6 @@
#include <openssl/err.h>
#include <openssl/mem.h>
#include "../internal.h"
/*
* Code for ENUMERATED type: identical to INTEGER apart from a different tag.
* for comments on encoding see a_int.c
@@ -82,7 +79,7 @@ int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v)
OPENSSL_free(a->data);
if ((a->data =
(unsigned char *)OPENSSL_malloc(sizeof(long) + 1)) != NULL)
OPENSSL_memset((char *)a->data, 0, sizeof(long) + 1);
memset((char *)a->data, 0, sizeof(long) + 1);
}
if (a->data == NULL) {
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
+16 -21
View File
@@ -61,6 +61,7 @@
#include <openssl/err.h>
#include <openssl/mem.h>
#include <openssl/time_support.h>
#include "asn1_locl.h"
@@ -148,7 +149,7 @@ int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d)
if (a[o] == 'Z')
o++;
else if ((a[o] == '+') || (a[o] == '-')) {
int offsign = a[o] == '-' ? 1 : -1, offset = 0;
int offsign = a[o] == '-' ? -1 : 1, offset = 0;
o++;
if (o + 4 > l)
goto err;
@@ -219,43 +220,37 @@ ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s,
struct tm *ts;
struct tm data;
size_t len = 20;
ASN1_GENERALIZEDTIME *tmps = NULL;
if (s == NULL)
tmps = ASN1_GENERALIZEDTIME_new();
else
tmps = s;
if (tmps == NULL)
return NULL;
s = M_ASN1_GENERALIZEDTIME_new();
if (s == NULL)
return (NULL);
ts = OPENSSL_gmtime(&t, &data);
if (ts == NULL)
goto err;
return (NULL);
if (offset_day || offset_sec) {
if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec))
goto err;
return NULL;
}
p = (char *)tmps->data;
if ((p == NULL) || ((size_t)tmps->length < len)) {
p = (char *)s->data;
if ((p == NULL) || ((size_t)s->length < len)) {
p = OPENSSL_malloc(len);
if (p == NULL) {
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
goto err;
return (NULL);
}
OPENSSL_free(tmps->data);
tmps->data = (unsigned char *)p;
if (s->data != NULL)
OPENSSL_free(s->data);
s->data = (unsigned char *)p;
}
BIO_snprintf(p, len, "%04d%02d%02d%02d%02d%02dZ", ts->tm_year + 1900,
ts->tm_mon + 1, ts->tm_mday, ts->tm_hour, ts->tm_min,
ts->tm_sec);
tmps->length = strlen(p);
tmps->type = V_ASN1_GENERALIZEDTIME;
return tmps;
err:
if (s == NULL)
ASN1_GENERALIZEDTIME_free(tmps);
return NULL;
s->length = strlen(p);
s->type = V_ASN1_GENERALIZEDTIME;
return (s);
}
+4 -7
View File
@@ -61,9 +61,6 @@
#include <openssl/err.h>
#include <openssl/mem.h>
#include "../internal.h"
ASN1_INTEGER *ASN1_INTEGER_dup(const ASN1_INTEGER *x)
{
return M_ASN1_INTEGER_dup(x);
@@ -160,7 +157,7 @@ int i2c_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **pp)
if (a->length == 0)
*(p++) = 0;
else if (!neg)
OPENSSL_memcpy(p, a->data, (unsigned int)a->length);
memcpy(p, a->data, (unsigned int)a->length);
else {
/* Begin at the end of the encoding */
n = a->data + a->length - 1;
@@ -257,7 +254,7 @@ ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a, const unsigned char **pp,
p++;
len--;
}
OPENSSL_memcpy(s, p, (int)len);
memcpy(s, p, (int)len);
}
if (ret->data != NULL)
@@ -325,7 +322,7 @@ ASN1_INTEGER *d2i_ASN1_UINTEGER(ASN1_INTEGER **a, const unsigned char **pp,
p++;
len--;
}
OPENSSL_memcpy(s, p, (int)len);
memcpy(s, p, (int)len);
p += len;
}
@@ -357,7 +354,7 @@ int ASN1_INTEGER_set(ASN1_INTEGER *a, long v)
OPENSSL_free(a->data);
if ((a->data =
(unsigned char *)OPENSSL_malloc(sizeof(long) + 1)) != NULL)
OPENSSL_memset((char *)a->data, 0, sizeof(long) + 1);
memset((char *)a->data, 0, sizeof(long) + 1);
}
if (a->data == NULL) {
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
+5 -12
View File
@@ -63,9 +63,6 @@
#include <openssl/mem.h>
#include <openssl/obj.h>
#include "../internal.h"
int i2d_ASN1_OBJECT(ASN1_OBJECT *a, unsigned char **pp)
{
unsigned char *p;
@@ -75,12 +72,12 @@ int i2d_ASN1_OBJECT(ASN1_OBJECT *a, unsigned char **pp)
return (0);
objsize = ASN1_object_size(0, a->length, V_ASN1_OBJECT);
if (pp == NULL || objsize == -1)
if (pp == NULL)
return objsize;
p = *pp;
ASN1_put_object(&p, 0, a->length, V_ASN1_OBJECT, V_ASN1_UNIVERSAL);
OPENSSL_memcpy(p, a->data, a->length);
memcpy(p, a->data, a->length);
p += a->length;
*pp = p;
@@ -175,12 +172,8 @@ int a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num)
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;
}
while (blsize--)
tmp[i++] = (unsigned char)BN_div_word(bl, 0x80L);
} else {
for (;;) {
@@ -324,7 +317,7 @@ ASN1_OBJECT *c2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp,
}
ret->flags |= ASN1_OBJECT_FLAG_DYNAMIC_DATA;
}
OPENSSL_memcpy(data, p, length);
memcpy(data, p, length);
/* reattach data to object, after which it remains const */
ret->data = data;
ret->length = length;
-4
View File
@@ -62,9 +62,6 @@
#include <openssl/err.h>
#include <openssl/mem.h>
#include <openssl/obj.h>
#include <openssl/stack.h>
DEFINE_STACK_OF(ASN1_STRING_TABLE)
static STACK_OF(ASN1_STRING_TABLE) *stable = NULL;
static void st_free(ASN1_STRING_TABLE *tbl);
@@ -250,7 +247,6 @@ int ASN1_STRING_TABLE_add(int nid,
}
tmp->flags = flags | STABLE_FLAGS_MALLOC;
tmp->nid = nid;
tmp->minsize = tmp->maxsize = -1;
new_nid = 1;
} else
tmp->flags = (tmp->flags & STABLE_FLAGS_MALLOC) | flags;
+21 -17
View File
@@ -63,6 +63,7 @@
#include <openssl/buf.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include <openssl/time_support.h>
#include "asn1_locl.h"
@@ -76,6 +77,17 @@ IMPLEMENT_ASN1_MSTRING(ASN1_TIME, B_ASN1_TIME)
IMPLEMENT_ASN1_FUNCTIONS(ASN1_TIME)
#if 0
int i2d_ASN1_TIME(ASN1_TIME *a, unsigned char **pp)
{
if (a->type == V_ASN1_UTCTIME || a->type == V_ASN1_GENERALIZEDTIME)
return (i2d_ASN1_bytes((ASN1_STRING *)a, pp,
a->type, V_ASN1_UNIVERSAL));
OPENSSL_PUT_ERROR(ASN1, ASN1_R_EXPECTING_A_TIME);
return -1;
}
#endif
ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s, time_t t)
{
return ASN1_TIME_adj(s, t, 0, 0);
@@ -114,7 +126,7 @@ int ASN1_TIME_check(ASN1_TIME *t)
ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *t,
ASN1_GENERALIZEDTIME **out)
{
ASN1_GENERALIZEDTIME *ret = NULL;
ASN1_GENERALIZEDTIME *ret;
char *str;
int newlen;
@@ -123,21 +135,22 @@ ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *t,
if (!out || !*out) {
if (!(ret = ASN1_GENERALIZEDTIME_new()))
goto err;
} else {
return NULL;
if (out)
*out = ret;
} else
ret = *out;
}
/* If already GeneralizedTime just copy across */
if (t->type == V_ASN1_GENERALIZEDTIME) {
if (!ASN1_STRING_set(ret, t->data, t->length))
goto err;
goto done;
return NULL;
return ret;
}
/* grow the string */
if (!ASN1_STRING_set(ret, NULL, t->length + 2))
goto err;
return NULL;
/* ASN1_STRING_set() allocated 'len + 1' bytes. */
newlen = t->length + 2 + 1;
str = (char *)ret->data;
@@ -149,18 +162,9 @@ ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *t,
BUF_strlcat(str, (char *)t->data, newlen);
done:
if (out != NULL && *out == NULL)
*out = ret;
return ret;
err:
if (out == NULL || *out != ret)
ASN1_GENERALIZEDTIME_free(ret);
return NULL;
return ret;
}
int ASN1_TIME_set_string(ASN1_TIME *s, const char *str)
{
ASN1_TIME t;
+2
View File
@@ -122,7 +122,9 @@ int ASN1_TYPE_cmp(const ASN1_TYPE *a, const ASN1_TYPE *b)
result = a->value.boolean - b->value.boolean;
break;
case V_ASN1_INTEGER:
case V_ASN1_NEG_INTEGER:
case V_ASN1_ENUMERATED:
case V_ASN1_NEG_ENUMERATED:
case V_ASN1_BIT_STRING:
case V_ASN1_OCTET_STRING:
case V_ASN1_SEQUENCE:
+34 -2
View File
@@ -61,9 +61,41 @@
#include <openssl/err.h>
#include <openssl/mem.h>
#include <openssl/time_support.h>
#include "asn1_locl.h"
#if 0
int i2d_ASN1_UTCTIME(ASN1_UTCTIME *a, unsigned char **pp)
{
return (i2d_ASN1_bytes((ASN1_STRING *)a, pp,
V_ASN1_UTCTIME, V_ASN1_UNIVERSAL));
}
ASN1_UTCTIME *d2i_ASN1_UTCTIME(ASN1_UTCTIME **a, unsigned char **pp,
long length)
{
ASN1_UTCTIME *ret = NULL;
ret = (ASN1_UTCTIME *)d2i_ASN1_bytes((ASN1_STRING **)a, pp, length,
V_ASN1_UTCTIME, V_ASN1_UNIVERSAL);
if (ret == NULL) {
OPENSSL_PUT_ERROR(ASN1, ERR_R_NESTED_ASN1_ERROR);
return (NULL);
}
if (!ASN1_UTCTIME_check(ret)) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_TIME_FORMAT);
goto err;
}
return (ret);
err:
if ((ret != NULL) && ((a == NULL) || (*a != ret)))
M_ASN1_UTCTIME_free(ret);
return (NULL);
}
#endif
int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d)
{
@@ -127,7 +159,7 @@ int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d)
if (a[o] == 'Z')
o++;
else if ((a[o] == '+') || (a[o] == '-')) {
int offsign = a[o] == '-' ? 1 : -1, offset = 0;
int offsign = a[o] == '-' ? -1 : 1, offset = 0;
o++;
if (o + 4 > l)
goto err;
@@ -269,7 +301,7 @@ time_t ASN1_UTCTIME_get(const ASN1_UTCTIME *s)
struct tm tm;
int offset;
OPENSSL_memset(&tm, '\0', sizeof tm);
memset(&tm, '\0', sizeof tm);
# define g2(p) (((p)[0]-'0')*10+(p)[1]-'0')
tm.tm_year = g2(s->data);
+81 -58
View File
@@ -63,48 +63,45 @@
#include <openssl/err.h>
#include <openssl/mem.h>
#include "../internal.h"
/* Cross-module errors from crypto/x509/i2d_pr.c. */
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNSUPPORTED_PUBLIC_KEY_TYPE)
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNSUPPORTED_PUBLIC_KEY_TYPE);
/* Cross-module errors from crypto/x509/algorithm.c. */
OPENSSL_DECLARE_ERROR_REASON(ASN1, CONTEXT_NOT_INITIALISED)
OPENSSL_DECLARE_ERROR_REASON(ASN1, DIGEST_AND_KEY_TYPE_NOT_SUPPORTED)
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_MESSAGE_DIGEST_ALGORITHM)
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_SIGNATURE_ALGORITHM)
OPENSSL_DECLARE_ERROR_REASON(ASN1, WRONG_PUBLIC_KEY_TYPE)
OPENSSL_DECLARE_ERROR_REASON(ASN1, CONTEXT_NOT_INITIALISED);
OPENSSL_DECLARE_ERROR_REASON(ASN1, DIGEST_AND_KEY_TYPE_NOT_SUPPORTED);
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_MESSAGE_DIGEST_ALGORITHM);
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_SIGNATURE_ALGORITHM);
OPENSSL_DECLARE_ERROR_REASON(ASN1, WRONG_PUBLIC_KEY_TYPE);
/*
* Cross-module errors from crypto/x509/asn1_gen.c. TODO(davidben): Remove
* these once asn1_gen.c is gone.
*/
OPENSSL_DECLARE_ERROR_REASON(ASN1, DEPTH_EXCEEDED)
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_BITSTRING_FORMAT)
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_BOOLEAN)
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_FORMAT)
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_HEX)
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_IMPLICIT_TAG)
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_INTEGER)
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_NESTED_TAGGING)
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_NULL_VALUE)
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_OBJECT)
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_TIME_VALUE)
OPENSSL_DECLARE_ERROR_REASON(ASN1, INTEGER_NOT_ASCII_FORMAT)
OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_MODIFIER)
OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_NUMBER)
OPENSSL_DECLARE_ERROR_REASON(ASN1, LIST_ERROR)
OPENSSL_DECLARE_ERROR_REASON(ASN1, MISSING_VALUE)
OPENSSL_DECLARE_ERROR_REASON(ASN1, NOT_ASCII_FORMAT)
OPENSSL_DECLARE_ERROR_REASON(ASN1, OBJECT_NOT_ASCII_FORMAT)
OPENSSL_DECLARE_ERROR_REASON(ASN1, SEQUENCE_OR_SET_NEEDS_CONFIG)
OPENSSL_DECLARE_ERROR_REASON(ASN1, TIME_NOT_ASCII_FORMAT)
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_FORMAT)
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_TAG)
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNSUPPORTED_TYPE)
OPENSSL_DECLARE_ERROR_REASON(ASN1, DEPTH_EXCEEDED);
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_BITSTRING_FORMAT);
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_BOOLEAN);
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_FORMAT);
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_HEX);
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_IMPLICIT_TAG);
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_INTEGER);
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_NESTED_TAGGING);
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_NULL_VALUE);
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_OBJECT);
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_TIME_VALUE);
OPENSSL_DECLARE_ERROR_REASON(ASN1, INTEGER_NOT_ASCII_FORMAT);
OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_MODIFIER);
OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_NUMBER);
OPENSSL_DECLARE_ERROR_REASON(ASN1, LIST_ERROR);
OPENSSL_DECLARE_ERROR_REASON(ASN1, MISSING_VALUE);
OPENSSL_DECLARE_ERROR_REASON(ASN1, NOT_ASCII_FORMAT);
OPENSSL_DECLARE_ERROR_REASON(ASN1, OBJECT_NOT_ASCII_FORMAT);
OPENSSL_DECLARE_ERROR_REASON(ASN1, SEQUENCE_OR_SET_NEEDS_CONFIG);
OPENSSL_DECLARE_ERROR_REASON(ASN1, TIME_NOT_ASCII_FORMAT);
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_FORMAT);
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_TAG);
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNSUPPORTED_TYPE);
static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
long max);
int max);
static void asn1_put_length(unsigned char **pp, int length);
static int _asn1_check_infinite_end(const unsigned char **p, long len)
@@ -176,7 +173,7 @@ int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag,
*ptag = tag;
*pclass = xclass;
if (!asn1_get_length(&p, &inf, plength, max))
if (!asn1_get_length(&p, &inf, plength, (int)max))
goto err;
if (inf && !(ret & V_ASN1_CONSTRUCTED))
@@ -204,14 +201,14 @@ int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag,
}
static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
long max)
int max)
{
const unsigned char *p = *pp;
unsigned long ret = 0;
unsigned long i;
unsigned int i;
if (max-- < 1)
return 0;
return (0);
if (*p == 0x80) {
*inf = 1;
ret = 0;
@@ -220,11 +217,15 @@ static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
*inf = 0;
i = *p & 0x7f;
if (*(p++) & 0x80) {
if (i > sizeof(ret) || max < (long)i)
if (i > sizeof(long))
return 0;
if (max-- == 0)
return (0);
while (i-- > 0) {
ret <<= 8L;
ret |= *(p++);
if (max-- == 0)
return (0);
}
} else
ret = i;
@@ -233,7 +234,7 @@ static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
return 0;
*pp = p;
*rl = (long)ret;
return 1;
return (1);
}
/*
@@ -301,30 +302,26 @@ static void asn1_put_length(unsigned char **pp, int length)
int ASN1_object_size(int constructed, int length, int tag)
{
int ret = 1;
if (length < 0)
return -1;
int ret;
ret = length;
ret++;
if (tag >= 31) {
while (tag > 0) {
tag >>= 7;
ret++;
}
}
if (constructed == 2) {
ret += 3;
} else {
ret++;
if (length > 127) {
int tmplen = length;
while (tmplen > 0) {
tmplen >>= 8;
ret++;
}
if (constructed == 2)
return ret + 3;
ret++;
if (length > 127) {
while (length > 0) {
length >>= 8;
ret++;
}
}
if (ret >= INT_MAX - length)
return -1;
return ret + length;
return (ret);
}
static int _asn1_Finish(ASN1_const_CTX *c)
@@ -352,6 +349,32 @@ int asn1_const_Finish(ASN1_const_CTX *c)
return _asn1_Finish(c);
}
int asn1_GetSequence(ASN1_const_CTX *c, long *length)
{
const unsigned char *q;
q = c->p;
c->inf = ASN1_get_object(&(c->p), &(c->slen), &(c->tag), &(c->xclass),
*length);
if (c->inf & 0x80) {
c->error = ASN1_R_BAD_GET_ASN1_OBJECT_CALL;
return (0);
}
if (c->tag != V_ASN1_SEQUENCE) {
c->error = ASN1_R_EXPECTING_AN_ASN1_SEQUENCE;
return (0);
}
(*length) -= (c->p - q);
if (c->max && (*length < 0)) {
c->error = ASN1_R_ASN1_LENGTH_MISMATCH;
return (0);
}
if (c->inf == (1 | V_ASN1_CONSTRUCTED))
c->slen = *length + *(c->pp) - c->p;
c->eos = 0;
return (1);
}
int ASN1_STRING_copy(ASN1_STRING *dst, const ASN1_STRING *str)
{
if (str == NULL)
@@ -389,7 +412,7 @@ int ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len)
else
len = strlen(data);
}
if ((str->length <= len) || (str->data == NULL)) {
if ((str->length < len) || (str->data == NULL)) {
c = str->data;
if (c == NULL)
str->data = OPENSSL_malloc(len + 1);
@@ -404,7 +427,7 @@ int ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len)
}
str->length = len;
if (data != NULL) {
OPENSSL_memcpy(str->data, data, len);
memcpy(str->data, data, len);
/* an allowance for strings :-) */
str->data[len] = '\0';
}
@@ -455,7 +478,7 @@ int ASN1_STRING_cmp(const ASN1_STRING *a, const ASN1_STRING *b)
i = (a->length - b->length);
if (i == 0) {
i = OPENSSL_memcmp(a->data, b->data, a->length);
i = memcmp(a->data, b->data, a->length);
if (i == 0)
return (a->type - b->type);
else
+8 -33
View File
@@ -57,42 +57,17 @@
*
*/
#ifndef OPENSSL_HEADER_ASN1_ASN1_LOCL_H
#define OPENSSL_HEADER_ASN1_ASN1_LOCL_H
#include <time.h>
#include <openssl/asn1.h>
#if defined(__cplusplus)
extern "C" {
#endif
/* Wrapper functions for time functions. */
/* OPENSSL_gmtime wraps |gmtime_r|. See the manual page for that function. */
struct tm *OPENSSL_gmtime(const time_t *timer, struct tm *result);
/* OPENSSL_gmtime_adj updates |tm| by adding |offset_day| days and |offset_sec|
* seconds. */
int OPENSSL_gmtime_adj(struct tm *tm, int offset_day, long offset_sec);
/* OPENSSL_gmtime_diff calculates the difference between |from| and |to| and
* outputs the difference as a number of days and seconds in |*out_days| and
* |*out_secs|. */
int OPENSSL_gmtime_diff(int *out_days, int *out_secs, const struct tm *from,
const struct tm *to);
/* Internal ASN1 structures and functions: not for application use */
int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d);
int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d);
/* ASN1 print context structure */
#if defined(__cplusplus)
} /* extern C */
#endif
#endif /* OPENSSL_HEADER_ASN1_ASN1_LOCL_H */
struct asn1_pctx_st {
unsigned long flags;
unsigned long nm_flags;
unsigned long cert_flags;
unsigned long oid_flags;
unsigned long str_flags;
} /* ASN1_PCTX */ ;
+322
View File
@@ -56,6 +56,328 @@
#include <openssl/asn1.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#define ASN1_PARSE_MAXDEPTH 128
static int asn1_print_info(BIO *bp, int tag, int xclass, int constructed,
int indent);
static int asn1_parse2(BIO *bp, const unsigned char **pp, long length,
int offset, int depth, int indent, int dump);
static int asn1_print_info(BIO *bp, int tag, int xclass, int constructed,
int indent)
{
static const char fmt[] = "%-18s";
char str[128];
const char *p;
if (constructed & V_ASN1_CONSTRUCTED)
p = "cons: ";
else
p = "prim: ";
if (BIO_write(bp, p, 6) < 6)
goto err;
BIO_indent(bp, indent, 128);
p = str;
if ((xclass & V_ASN1_PRIVATE) == V_ASN1_PRIVATE)
BIO_snprintf(str, sizeof str, "priv [ %d ] ", tag);
else if ((xclass & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC)
BIO_snprintf(str, sizeof str, "cont [ %d ]", tag);
else if ((xclass & V_ASN1_APPLICATION) == V_ASN1_APPLICATION)
BIO_snprintf(str, sizeof str, "appl [ %d ]", tag);
else if (tag > 30)
BIO_snprintf(str, sizeof str, "<ASN1 %d>", tag);
else
p = ASN1_tag2str(tag);
if (BIO_printf(bp, fmt, p) <= 0)
goto err;
return (1);
err:
return (0);
}
int ASN1_parse(BIO *bp, const unsigned char *pp, long len, int indent)
{
return (asn1_parse2(bp, &pp, len, 0, 0, indent, 0));
}
int ASN1_parse_dump(BIO *bp, const unsigned char *pp, long len, int indent,
int dump)
{
return (asn1_parse2(bp, &pp, len, 0, 0, indent, dump));
}
static int asn1_parse2(BIO *bp, const unsigned char **pp, long length,
int offset, int depth, int indent, int dump)
{
const unsigned char *p, *ep, *tot, *op, *opp;
long len;
int tag, xclass, ret = 0;
int nl, hl, j, r;
ASN1_OBJECT *o = NULL;
ASN1_OCTET_STRING *os = NULL;
/* ASN1_BMPSTRING *bmp=NULL; */
int dump_indent;
#if 0
dump_indent = indent;
#else
dump_indent = 6; /* Because we know BIO_dump_indent() */
#endif
if (depth > ASN1_PARSE_MAXDEPTH) {
BIO_puts(bp, "BAD RECURSION DEPTH\n");
return 0;
}
p = *pp;
tot = p + length;
op = p - 1;
while ((p < tot) && (op < p)) {
op = p;
j = ASN1_get_object(&p, &len, &tag, &xclass, length);
#ifdef LINT
j = j;
#endif
if (j & 0x80) {
if (BIO_puts(bp, "Error in encoding\n") <= 0)
goto end;
ret = 0;
goto end;
}
hl = (p - op);
length -= hl;
/*
* if j == 0x21 it is a constructed indefinite length object
*/
if (BIO_printf(bp, "%5ld:", (long)offset + (long)(op - *pp))
<= 0)
goto end;
if (j != (V_ASN1_CONSTRUCTED | 1)) {
if (BIO_printf(bp, "d=%-2d hl=%ld l=%4ld ",
depth, (long)hl, len) <= 0)
goto end;
} else {
if (BIO_printf(bp, "d=%-2d hl=%ld l=inf ", depth, (long)hl) <= 0)
goto end;
}
if (!asn1_print_info(bp, tag, xclass, j, (indent) ? depth : 0))
goto end;
if (j & V_ASN1_CONSTRUCTED) {
ep = p + len;
if (BIO_puts(bp, "\n") <= 0)
goto end;
if (len > length) {
BIO_printf(bp, "length is greater than %ld\n", length);
ret = 0;
goto end;
}
if ((j == 0x21) && (len == 0)) {
for (;;) {
r = asn1_parse2(bp, &p, (long)(tot - p),
offset + (p - *pp), depth + 1,
indent, dump);
if (r == 0) {
ret = 0;
goto end;
}
if ((r == 2) || (p >= tot))
break;
}
} else
while (p < ep) {
r = asn1_parse2(bp, &p, (long)len,
offset + (p - *pp), depth + 1,
indent, dump);
if (r == 0) {
ret = 0;
goto end;
}
}
} else if (xclass != 0) {
p += len;
if (BIO_puts(bp, "\n") <= 0)
goto end;
} else {
nl = 0;
if ((tag == V_ASN1_PRINTABLESTRING) ||
(tag == V_ASN1_T61STRING) ||
(tag == V_ASN1_IA5STRING) ||
(tag == V_ASN1_VISIBLESTRING) ||
(tag == V_ASN1_NUMERICSTRING) ||
(tag == V_ASN1_UTF8STRING) ||
(tag == V_ASN1_UTCTIME) || (tag == V_ASN1_GENERALIZEDTIME)) {
if (BIO_puts(bp, ":") <= 0)
goto end;
if ((len > 0) && BIO_write(bp, (const char *)p, (int)len)
!= (int)len)
goto end;
} else if (tag == V_ASN1_OBJECT) {
opp = op;
if (d2i_ASN1_OBJECT(&o, &opp, len + hl) != NULL) {
if (BIO_puts(bp, ":") <= 0)
goto end;
i2a_ASN1_OBJECT(bp, o);
} else {
if (BIO_puts(bp, ":BAD OBJECT") <= 0)
goto end;
}
} else if (tag == V_ASN1_BOOLEAN) {
int ii;
opp = op;
ii = d2i_ASN1_BOOLEAN(NULL, &opp, len + hl);
if (ii < 0) {
if (BIO_puts(bp, "Bad boolean\n") <= 0)
goto end;
}
BIO_printf(bp, ":%d", ii);
} else if (tag == V_ASN1_BMPSTRING) {
/* do the BMP thang */
} else if (tag == V_ASN1_OCTET_STRING) {
int i, printable = 1;
opp = op;
os = d2i_ASN1_OCTET_STRING(NULL, &opp, len + hl);
if (os != NULL && os->length > 0) {
opp = os->data;
/*
* testing whether the octet string is printable
*/
for (i = 0; i < os->length; i++) {
if (((opp[i] < ' ') &&
(opp[i] != '\n') &&
(opp[i] != '\r') &&
(opp[i] != '\t')) || (opp[i] > '~')) {
printable = 0;
break;
}
}
if (printable)
/* printable string */
{
if (BIO_puts(bp, ":") <= 0)
goto end;
if (BIO_write(bp, (const char *)opp, os->length) <= 0)
goto end;
} else if (!dump)
/*
* not printable => print octet string as hex dump
*/
{
if (BIO_puts(bp, "[HEX DUMP]:") <= 0)
goto end;
for (i = 0; i < os->length; i++) {
if (BIO_printf(bp, "%02X", opp[i]) <= 0)
goto end;
}
} else
/* print the normal dump */
{
if (!nl) {
if (BIO_puts(bp, "\n") <= 0)
goto end;
}
if (!BIO_hexdump(bp, opp,
((dump == -1 || dump >
os->length) ? os->length : dump),
dump_indent))
goto end;
nl = 1;
}
}
if (os != NULL) {
M_ASN1_OCTET_STRING_free(os);
os = NULL;
}
} else if (tag == V_ASN1_INTEGER) {
ASN1_INTEGER *bs;
int i;
opp = op;
bs = d2i_ASN1_INTEGER(NULL, &opp, len + hl);
if (bs != NULL) {
if (BIO_puts(bp, ":") <= 0)
goto end;
if (bs->type == V_ASN1_NEG_INTEGER)
if (BIO_puts(bp, "-") <= 0)
goto end;
for (i = 0; i < bs->length; i++) {
if (BIO_printf(bp, "%02X", bs->data[i]) <= 0)
goto end;
}
if (bs->length == 0) {
if (BIO_puts(bp, "00") <= 0)
goto end;
}
} else {
if (BIO_puts(bp, "BAD INTEGER") <= 0)
goto end;
}
M_ASN1_INTEGER_free(bs);
} else if (tag == V_ASN1_ENUMERATED) {
ASN1_ENUMERATED *bs;
int i;
opp = op;
bs = d2i_ASN1_ENUMERATED(NULL, &opp, len + hl);
if (bs != NULL) {
if (BIO_puts(bp, ":") <= 0)
goto end;
if (bs->type == V_ASN1_NEG_ENUMERATED)
if (BIO_puts(bp, "-") <= 0)
goto end;
for (i = 0; i < bs->length; i++) {
if (BIO_printf(bp, "%02X", bs->data[i]) <= 0)
goto end;
}
if (bs->length == 0) {
if (BIO_puts(bp, "00") <= 0)
goto end;
}
} else {
if (BIO_puts(bp, "BAD ENUMERATED") <= 0)
goto end;
}
M_ASN1_ENUMERATED_free(bs);
} else if (len > 0 && dump) {
if (!nl) {
if (BIO_puts(bp, "\n") <= 0)
goto end;
}
if (!BIO_hexdump(bp, p,
((dump == -1 || dump > len) ? len : dump),
dump_indent))
goto end;
nl = 1;
}
if (!nl) {
if (BIO_puts(bp, "\n") <= 0)
goto end;
}
p += len;
if ((tag == V_ASN1_EOC) && (xclass == 0)) {
ret = 2; /* End of sequence */
goto end;
}
}
length -= len;
}
ret = 1;
end:
if (o != NULL)
ASN1_OBJECT_free(o);
if (os != NULL)
M_ASN1_OCTET_STRING_free(os);
*pp = p;
return (ret);
}
const char *ASN1_tag2str(int tag)
{
+31 -12
View File
@@ -14,12 +14,11 @@
#include <stdio.h>
#include <gtest/gtest.h>
#include <openssl/asn1.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include "../test/test_util.h"
#include "../test/scoped_types.h"
// kTag128 is an ASN.1 structure with a universal tag with number 128.
@@ -41,22 +40,42 @@ static const uint8_t kTagOverflow[] = {
0x1f, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x01, 0x00,
};
TEST(ASN1Test, LargeTags) {
static bool TestLargeTags() {
const uint8_t *p = kTag258;
bssl::UniquePtr<ASN1_TYPE> obj(d2i_ASN1_TYPE(NULL, &p, sizeof(kTag258)));
EXPECT_FALSE(obj) << "Parsed value with illegal tag" << obj->type;
ScopedASN1_TYPE obj(d2i_ASN1_TYPE(NULL, &p, sizeof(kTag258)));
if (obj) {
fprintf(stderr, "Parsed value with illegal tag (type = %d).\n", obj->type);
return false;
}
ERR_clear_error();
p = kTagOverflow;
obj.reset(d2i_ASN1_TYPE(NULL, &p, sizeof(kTagOverflow)));
EXPECT_FALSE(obj) << "Parsed value with tag overflow" << obj->type;
if (obj) {
fprintf(stderr, "Parsed value with tag overflow (type = %d).\n", obj->type);
return false;
}
ERR_clear_error();
p = kTag128;
obj.reset(d2i_ASN1_TYPE(NULL, &p, sizeof(kTag128)));
ASSERT_TRUE(obj);
EXPECT_EQ(128, obj->type);
const uint8_t kZero = 0;
EXPECT_EQ(Bytes(&kZero, 1), Bytes(obj->value.asn1_string->data,
obj->value.asn1_string->length));
if (!obj || obj->type != 128 || obj->value.asn1_string->length != 1 ||
obj->value.asn1_string->data[0] != 0) {
fprintf(stderr, "Failed to parse value with tag 128.\n");
ERR_print_errors_fp(stderr);
return false;
}
return true;
}
int main() {
CRYPTO_library_init();
if (!TestLargeTags()) {
return 1;
}
printf("PASS\n");
return 0;
}
+477
View File
@@ -0,0 +1,477 @@
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.] */
#include <openssl/asn1.h>
#include <assert.h>
#include <string.h>
#include <openssl/bio.h>
#include <openssl/mem.h>
/* Must be large enough for biggest tag+length */
#define DEFAULT_ASN1_BUF_SIZE 20
typedef enum {
ASN1_STATE_START,
ASN1_STATE_PRE_COPY,
ASN1_STATE_HEADER,
ASN1_STATE_HEADER_COPY,
ASN1_STATE_DATA_COPY,
ASN1_STATE_POST_COPY,
ASN1_STATE_DONE
} asn1_bio_state_t;
typedef struct BIO_ASN1_EX_FUNCS_st {
asn1_ps_func *ex_func;
asn1_ps_func *ex_free_func;
} BIO_ASN1_EX_FUNCS;
typedef struct BIO_ASN1_BUF_CTX_t {
/* Internal state */
asn1_bio_state_t state;
/* Internal buffer */
unsigned char *buf;
/* Size of buffer */
int bufsize;
/* Current position in buffer */
int bufpos;
/* Current buffer length */
int buflen;
/* Amount of data to copy */
int copylen;
/* Class and tag to use */
int asn1_class, asn1_tag;
asn1_ps_func *prefix, *prefix_free, *suffix, *suffix_free;
/* Extra buffer for prefix and suffix data */
unsigned char *ex_buf;
int ex_len;
int ex_pos;
void *ex_arg;
} BIO_ASN1_BUF_CTX;
static int asn1_bio_write(BIO *h, const char *buf, int num);
static int asn1_bio_read(BIO *h, char *buf, int size);
static int asn1_bio_puts(BIO *h, const char *str);
static int asn1_bio_gets(BIO *h, char *str, int size);
static long asn1_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2);
static int asn1_bio_new(BIO *h);
static int asn1_bio_free(BIO *data);
static long asn1_bio_callback_ctrl(BIO *h, int cmd, bio_info_cb fp);
static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size);
static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
asn1_ps_func *cleanup, asn1_bio_state_t next);
static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
asn1_ps_func *setup,
asn1_bio_state_t ex_state,
asn1_bio_state_t other_state);
static const BIO_METHOD methods_asn1 = {
BIO_TYPE_ASN1,
"asn1",
asn1_bio_write,
asn1_bio_read,
asn1_bio_puts,
asn1_bio_gets,
asn1_bio_ctrl,
asn1_bio_new,
asn1_bio_free,
asn1_bio_callback_ctrl,
};
const BIO_METHOD *BIO_f_asn1(void)
{
return (&methods_asn1);
}
static int asn1_bio_new(BIO *b)
{
BIO_ASN1_BUF_CTX *ctx;
ctx = OPENSSL_malloc(sizeof(BIO_ASN1_BUF_CTX));
if (!ctx)
return 0;
if (!asn1_bio_init(ctx, DEFAULT_ASN1_BUF_SIZE)) {
OPENSSL_free(ctx);
return 0;
}
b->init = 1;
b->ptr = (char *)ctx;
b->flags = 0;
return 1;
}
static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size)
{
ctx->buf = OPENSSL_malloc(size);
if (!ctx->buf)
return 0;
ctx->bufsize = size;
ctx->bufpos = 0;
ctx->buflen = 0;
ctx->copylen = 0;
ctx->asn1_class = V_ASN1_UNIVERSAL;
ctx->asn1_tag = V_ASN1_OCTET_STRING;
ctx->ex_buf = 0;
ctx->ex_pos = 0;
ctx->ex_len = 0;
ctx->state = ASN1_STATE_START;
return 1;
}
static int asn1_bio_free(BIO *b)
{
BIO_ASN1_BUF_CTX *ctx;
ctx = (BIO_ASN1_BUF_CTX *)b->ptr;
if (ctx == NULL)
return 0;
if (ctx->buf)
OPENSSL_free(ctx->buf);
OPENSSL_free(ctx);
b->init = 0;
b->ptr = NULL;
b->flags = 0;
return 1;
}
static int asn1_bio_write(BIO *b, const char *in, int inl)
{
BIO_ASN1_BUF_CTX *ctx;
int wrmax, wrlen, ret;
unsigned char *p;
if (!in || (inl < 0) || (b->next_bio == NULL))
return 0;
ctx = (BIO_ASN1_BUF_CTX *)b->ptr;
if (ctx == NULL)
return 0;
wrlen = 0;
ret = -1;
for (;;) {
switch (ctx->state) {
/* Setup prefix data, call it */
case ASN1_STATE_START:
if (!asn1_bio_setup_ex(b, ctx, ctx->prefix,
ASN1_STATE_PRE_COPY, ASN1_STATE_HEADER))
return 0;
break;
/* Copy any pre data first */
case ASN1_STATE_PRE_COPY:
ret = asn1_bio_flush_ex(b, ctx, ctx->prefix_free,
ASN1_STATE_HEADER);
if (ret <= 0)
goto done;
break;
case ASN1_STATE_HEADER:
ctx->buflen = ASN1_object_size(0, inl, ctx->asn1_tag) - inl;
assert(ctx->buflen <= ctx->bufsize);
p = ctx->buf;
ASN1_put_object(&p, 0, inl, ctx->asn1_tag, ctx->asn1_class);
ctx->copylen = inl;
ctx->state = ASN1_STATE_HEADER_COPY;
break;
case ASN1_STATE_HEADER_COPY:
ret = BIO_write(b->next_bio, ctx->buf + ctx->bufpos, ctx->buflen);
if (ret <= 0)
goto done;
ctx->buflen -= ret;
if (ctx->buflen)
ctx->bufpos += ret;
else {
ctx->bufpos = 0;
ctx->state = ASN1_STATE_DATA_COPY;
}
break;
case ASN1_STATE_DATA_COPY:
if (inl > ctx->copylen)
wrmax = ctx->copylen;
else
wrmax = inl;
ret = BIO_write(b->next_bio, in, wrmax);
if (ret <= 0)
break;
wrlen += ret;
ctx->copylen -= ret;
in += ret;
inl -= ret;
if (ctx->copylen == 0)
ctx->state = ASN1_STATE_HEADER;
if (inl == 0)
goto done;
break;
default:
BIO_clear_retry_flags(b);
return 0;
}
}
done:
BIO_clear_retry_flags(b);
BIO_copy_next_retry(b);
return (wrlen > 0) ? wrlen : ret;
}
static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
asn1_ps_func *cleanup, asn1_bio_state_t next)
{
int ret;
if (ctx->ex_len <= 0)
return 1;
for (;;) {
ret = BIO_write(b->next_bio, ctx->ex_buf + ctx->ex_pos, ctx->ex_len);
if (ret <= 0)
break;
ctx->ex_len -= ret;
if (ctx->ex_len > 0)
ctx->ex_pos += ret;
else {
if (cleanup)
cleanup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg);
ctx->state = next;
ctx->ex_pos = 0;
break;
}
}
return ret;
}
static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
asn1_ps_func *setup,
asn1_bio_state_t ex_state,
asn1_bio_state_t other_state)
{
if (setup && !setup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg)) {
BIO_clear_retry_flags(b);
return 0;
}
if (ctx->ex_len > 0)
ctx->state = ex_state;
else
ctx->state = other_state;
return 1;
}
static int asn1_bio_read(BIO *b, char *in, int inl)
{
if (!b->next_bio)
return 0;
return BIO_read(b->next_bio, in, inl);
}
static int asn1_bio_puts(BIO *b, const char *str)
{
return asn1_bio_write(b, str, strlen(str));
}
static int asn1_bio_gets(BIO *b, char *str, int size)
{
if (!b->next_bio)
return 0;
return BIO_gets(b->next_bio, str, size);
}
static long asn1_bio_callback_ctrl(BIO *b, int cmd, bio_info_cb fp)
{
if (b->next_bio == NULL)
return (0);
return BIO_callback_ctrl(b->next_bio, cmd, fp);
}
static long asn1_bio_ctrl(BIO *b, int cmd, long arg1, void *arg2)
{
BIO_ASN1_BUF_CTX *ctx;
BIO_ASN1_EX_FUNCS *ex_func;
long ret = 1;
ctx = (BIO_ASN1_BUF_CTX *)b->ptr;
if (ctx == NULL)
return 0;
switch (cmd) {
case BIO_C_SET_PREFIX:
ex_func = arg2;
ctx->prefix = ex_func->ex_func;
ctx->prefix_free = ex_func->ex_free_func;
break;
case BIO_C_GET_PREFIX:
ex_func = arg2;
ex_func->ex_func = ctx->prefix;
ex_func->ex_free_func = ctx->prefix_free;
break;
case BIO_C_SET_SUFFIX:
ex_func = arg2;
ctx->suffix = ex_func->ex_func;
ctx->suffix_free = ex_func->ex_free_func;
break;
case BIO_C_GET_SUFFIX:
ex_func = arg2;
ex_func->ex_func = ctx->suffix;
ex_func->ex_free_func = ctx->suffix_free;
break;
case BIO_C_SET_EX_ARG:
ctx->ex_arg = arg2;
break;
case BIO_C_GET_EX_ARG:
*(void **)arg2 = ctx->ex_arg;
break;
case BIO_CTRL_FLUSH:
if (!b->next_bio)
return 0;
/* Call post function if possible */
if (ctx->state == ASN1_STATE_HEADER) {
if (!asn1_bio_setup_ex(b, ctx, ctx->suffix,
ASN1_STATE_POST_COPY, ASN1_STATE_DONE))
return 0;
}
if (ctx->state == ASN1_STATE_POST_COPY) {
ret = asn1_bio_flush_ex(b, ctx, ctx->suffix_free,
ASN1_STATE_DONE);
if (ret <= 0)
return ret;
}
if (ctx->state == ASN1_STATE_DONE)
return BIO_ctrl(b->next_bio, cmd, arg1, arg2);
else {
BIO_clear_retry_flags(b);
return 0;
}
break;
default:
if (!b->next_bio)
return 0;
return BIO_ctrl(b->next_bio, cmd, arg1, arg2);
}
return ret;
}
static int asn1_bio_set_ex(BIO *b, int cmd,
asn1_ps_func *ex_func, asn1_ps_func *ex_free_func)
{
BIO_ASN1_EX_FUNCS extmp;
extmp.ex_func = ex_func;
extmp.ex_free_func = ex_free_func;
return BIO_ctrl(b, cmd, 0, &extmp);
}
static int asn1_bio_get_ex(BIO *b, int cmd,
asn1_ps_func **ex_func,
asn1_ps_func **ex_free_func)
{
BIO_ASN1_EX_FUNCS extmp;
int ret;
ret = BIO_ctrl(b, cmd, 0, &extmp);
if (ret > 0) {
*ex_func = extmp.ex_func;
*ex_free_func = extmp.ex_free_func;
}
return ret;
}
int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix,
asn1_ps_func *prefix_free)
{
return asn1_bio_set_ex(b, BIO_C_SET_PREFIX, prefix, prefix_free);
}
int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix,
asn1_ps_func **pprefix_free)
{
return asn1_bio_get_ex(b, BIO_C_GET_PREFIX, pprefix, pprefix_free);
}
int BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix,
asn1_ps_func *suffix_free)
{
return asn1_bio_set_ex(b, BIO_C_SET_SUFFIX, suffix, suffix_free);
}
int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix,
asn1_ps_func **psuffix_free)
{
return asn1_bio_get_ex(b, BIO_C_GET_SUFFIX, psuffix, psuffix_free);
}
+251
View File
@@ -0,0 +1,251 @@
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.] */
#include <openssl/asn1.h>
#include <assert.h>
#include <openssl/asn1t.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/mem.h>
/* Experimental NDEF ASN1 BIO support routines */
/*
* The usage is quite simple, initialize an ASN1 structure, get a BIO from it
* then any data written through the BIO will end up translated to
* approptiate format on the fly. The data is streamed out and does *not*
* need to be all held in memory at once. When the BIO is flushed the output
* is finalized and any signatures etc written out. The BIO is a 'proper'
* BIO and can handle non blocking I/O correctly. The usage is simple. The
* implementation is *not*...
*/
/* BIO support data stored in the ASN1 BIO ex_arg */
typedef struct ndef_aux_st {
/* ASN1 structure this BIO refers to */
ASN1_VALUE *val;
const ASN1_ITEM *it;
/* Top of the BIO chain */
BIO *ndef_bio;
/* Output BIO */
BIO *out;
/* Boundary where content is inserted */
unsigned char **boundary;
/* DER buffer start */
unsigned char *derbuf;
} NDEF_SUPPORT;
static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg);
static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen,
void *parg);
static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg);
static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen,
void *parg);
BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it)
{
NDEF_SUPPORT *ndef_aux = NULL;
BIO *asn_bio = NULL;
const ASN1_AUX *aux = it->funcs;
ASN1_STREAM_ARG sarg;
if (!aux || !aux->asn1_cb) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_STREAMING_NOT_SUPPORTED);
return NULL;
}
ndef_aux = OPENSSL_malloc(sizeof(NDEF_SUPPORT));
asn_bio = BIO_new(BIO_f_asn1());
/* ASN1 bio needs to be next to output BIO */
out = BIO_push(asn_bio, out);
if (!ndef_aux || !asn_bio || !out)
goto err;
BIO_asn1_set_prefix(asn_bio, ndef_prefix, ndef_prefix_free);
BIO_asn1_set_suffix(asn_bio, ndef_suffix, ndef_suffix_free);
/*
* Now let callback prepend any digest, cipher etc BIOs ASN1 structure
* needs.
*/
sarg.out = out;
sarg.ndef_bio = NULL;
sarg.boundary = NULL;
if (aux->asn1_cb(ASN1_OP_STREAM_PRE, &val, it, &sarg) <= 0)
goto err;
ndef_aux->val = val;
ndef_aux->it = it;
ndef_aux->ndef_bio = sarg.ndef_bio;
ndef_aux->boundary = sarg.boundary;
ndef_aux->out = out;
BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux);
return sarg.ndef_bio;
err:
if (asn_bio)
BIO_free(asn_bio);
if (ndef_aux)
OPENSSL_free(ndef_aux);
return NULL;
}
static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg)
{
NDEF_SUPPORT *ndef_aux;
unsigned char *p;
int derlen;
if (!parg)
return 0;
ndef_aux = *(NDEF_SUPPORT **)parg;
derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it);
p = OPENSSL_malloc(derlen);
if (p == NULL)
return 0;
ndef_aux->derbuf = p;
*pbuf = p;
derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
if (!*ndef_aux->boundary)
return 0;
*plen = *ndef_aux->boundary - *pbuf;
return 1;
}
static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen,
void *parg)
{
NDEF_SUPPORT *ndef_aux;
if (!parg)
return 0;
ndef_aux = *(NDEF_SUPPORT **)parg;
if (ndef_aux->derbuf)
OPENSSL_free(ndef_aux->derbuf);
ndef_aux->derbuf = NULL;
*pbuf = NULL;
*plen = 0;
return 1;
}
static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen,
void *parg)
{
NDEF_SUPPORT **pndef_aux = (NDEF_SUPPORT **)parg;
if (!ndef_prefix_free(b, pbuf, plen, parg))
return 0;
OPENSSL_free(*pndef_aux);
*pndef_aux = NULL;
return 1;
}
static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg)
{
NDEF_SUPPORT *ndef_aux;
unsigned char *p;
int derlen;
const ASN1_AUX *aux;
ASN1_STREAM_ARG sarg;
if (!parg)
return 0;
ndef_aux = *(NDEF_SUPPORT **)parg;
aux = ndef_aux->it->funcs;
/* Finalize structures */
sarg.ndef_bio = ndef_aux->ndef_bio;
sarg.out = ndef_aux->out;
sarg.boundary = ndef_aux->boundary;
if (aux->asn1_cb(ASN1_OP_STREAM_POST,
&ndef_aux->val, ndef_aux->it, &sarg) <= 0)
return 0;
derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it);
p = OPENSSL_malloc(derlen);
if (p == NULL)
return 0;
ndef_aux->derbuf = p;
*pbuf = p;
derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
if (!*ndef_aux->boundary)
return 0;
*pbuf = *ndef_aux->boundary;
*plen = derlen - (*ndef_aux->boundary - ndef_aux->derbuf);
return 1;
}
+108 -1
View File
@@ -56,7 +56,8 @@
#include <openssl/asn1.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/mem.h>
/* Based on a_int.c: equivalent ENUMERATED functions */
@@ -91,3 +92,109 @@ int i2a_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *a)
err:
return (-1);
}
int a2i_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *bs, char *buf, int size)
{
int ret = 0;
int i, j, k, m, n, again, bufsize;
unsigned char *s = NULL, *sp;
unsigned char *bufp;
int num = 0, slen = 0, first = 1;
bs->type = V_ASN1_ENUMERATED;
bufsize = BIO_gets(bp, buf, size);
for (;;) {
if (bufsize < 1)
goto err_sl;
i = bufsize;
if (buf[i - 1] == '\n')
buf[--i] = '\0';
if (i == 0)
goto err_sl;
if (buf[i - 1] == '\r')
buf[--i] = '\0';
if (i == 0)
goto err_sl;
again = (buf[i - 1] == '\\');
for (j = 0; j < i; j++) {
if (!(((buf[j] >= '0') && (buf[j] <= '9')) ||
((buf[j] >= 'a') && (buf[j] <= 'f')) ||
((buf[j] >= 'A') && (buf[j] <= 'F')))) {
i = j;
break;
}
}
buf[i] = '\0';
/*
* We have now cleared all the crap off the end of the line
*/
if (i < 2)
goto err_sl;
bufp = (unsigned char *)buf;
if (first) {
first = 0;
if ((bufp[0] == '0') && (buf[1] == '0')) {
bufp += 2;
i -= 2;
}
}
k = 0;
i -= again;
if (i % 2 != 0) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_ODD_NUMBER_OF_CHARS);
goto err;
}
i /= 2;
if (num + i > slen) {
if (s == NULL)
sp = (unsigned char *)OPENSSL_malloc((unsigned int)num +
i * 2);
else
sp = (unsigned char *)OPENSSL_realloc(s,
(unsigned int)num +
i * 2);
if (sp == NULL) {
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
goto err;
}
s = sp;
slen = num + i * 2;
}
for (j = 0; j < i; j++, k += 2) {
for (n = 0; n < 2; n++) {
m = bufp[k + n];
if ((m >= '0') && (m <= '9'))
m -= '0';
else if ((m >= 'a') && (m <= 'f'))
m = m - 'a' + 10;
else if ((m >= 'A') && (m <= 'F'))
m = m - 'A' + 10;
else {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NON_HEX_CHARACTERS);
goto err;
}
s[num + j] <<= 4;
s[num + j] |= m;
}
}
num += i;
if (again)
bufsize = BIO_gets(bp, buf, size);
else
break;
}
bs->length = num;
bs->data = s;
ret = 1;
err:
if (0) {
err_sl:
OPENSSL_PUT_ERROR(ASN1, ASN1_R_SHORT_LINE);
}
if (s != NULL)
OPENSSL_free(s);
return (ret);
}
+106 -1
View File
@@ -56,7 +56,8 @@
#include <openssl/asn1.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/mem.h>
int i2a_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *a)
{
@@ -95,3 +96,107 @@ int i2a_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *a)
err:
return (-1);
}
int a2i_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *bs, char *buf, int size)
{
int ret = 0;
int i, j, k, m, n, again, bufsize;
unsigned char *s = NULL, *sp;
unsigned char *bufp;
int num = 0, slen = 0, first = 1;
bs->type = V_ASN1_INTEGER;
bufsize = BIO_gets(bp, buf, size);
for (;;) {
if (bufsize < 1)
goto err_sl;
i = bufsize;
if (buf[i - 1] == '\n')
buf[--i] = '\0';
if (i == 0)
goto err_sl;
if (buf[i - 1] == '\r')
buf[--i] = '\0';
if (i == 0)
goto err_sl;
again = (buf[i - 1] == '\\');
for (j = 0; j < i; j++) {
if (!(((buf[j] >= '0') && (buf[j] <= '9')) ||
((buf[j] >= 'a') && (buf[j] <= 'f')) ||
((buf[j] >= 'A') && (buf[j] <= 'F')))) {
i = j;
break;
}
}
buf[i] = '\0';
/*
* We have now cleared all the crap off the end of the line
*/
if (i < 2)
goto err_sl;
bufp = (unsigned char *)buf;
if (first) {
first = 0;
if ((bufp[0] == '0') && (buf[1] == '0')) {
bufp += 2;
i -= 2;
}
}
k = 0;
i -= again;
if (i % 2 != 0) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_ODD_NUMBER_OF_CHARS);
goto err;
}
i /= 2;
if (num + i > slen) {
if (s == NULL)
sp = (unsigned char *)OPENSSL_malloc((unsigned int)num +
i * 2);
else
sp = OPENSSL_realloc_clean(s, slen, num + i * 2);
if (sp == NULL) {
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
goto err;
}
s = sp;
slen = num + i * 2;
}
for (j = 0; j < i; j++, k += 2) {
for (n = 0; n < 2; n++) {
m = bufp[k + n];
if ((m >= '0') && (m <= '9'))
m -= '0';
else if ((m >= 'a') && (m <= 'f'))
m = m - 'a' + 10;
else if ((m >= 'A') && (m <= 'F'))
m = m - 'A' + 10;
else {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NON_HEX_CHARACTERS);
goto err;
}
s[num + j] <<= 4;
s[num + j] |= m;
}
}
num += i;
if (again)
bufsize = BIO_gets(bp, buf, size);
else
break;
}
bs->length = num;
bs->data = s;
ret = 1;
err:
if (0) {
err_sl:
OPENSSL_PUT_ERROR(ASN1, ASN1_R_SHORT_LINE);
}
if (s != NULL)
OPENSSL_free(s);
return (ret);
}
+106 -1
View File
@@ -56,7 +56,8 @@
#include <openssl/asn1.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/mem.h>
int i2a_ASN1_STRING(BIO *bp, ASN1_STRING *a, int type)
{
@@ -89,3 +90,107 @@ int i2a_ASN1_STRING(BIO *bp, ASN1_STRING *a, int type)
err:
return (-1);
}
int a2i_ASN1_STRING(BIO *bp, ASN1_STRING *bs, char *buf, int size)
{
int ret = 0;
int i, j, k, m, n, again, bufsize;
unsigned char *s = NULL, *sp;
unsigned char *bufp;
int num = 0, slen = 0, first = 1;
bufsize = BIO_gets(bp, buf, size);
for (;;) {
if (bufsize < 1) {
if (first)
break;
else
goto err_sl;
}
first = 0;
i = bufsize;
if (buf[i - 1] == '\n')
buf[--i] = '\0';
if (i == 0)
goto err_sl;
if (buf[i - 1] == '\r')
buf[--i] = '\0';
if (i == 0)
goto err_sl;
again = (buf[i - 1] == '\\');
for (j = i - 1; j > 0; j--) {
if (!(((buf[j] >= '0') && (buf[j] <= '9')) ||
((buf[j] >= 'a') && (buf[j] <= 'f')) ||
((buf[j] >= 'A') && (buf[j] <= 'F')))) {
i = j;
break;
}
}
buf[i] = '\0';
/*
* We have now cleared all the crap off the end of the line
*/
if (i < 2)
goto err_sl;
bufp = (unsigned char *)buf;
k = 0;
i -= again;
if (i % 2 != 0) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_ODD_NUMBER_OF_CHARS);
goto err;
}
i /= 2;
if (num + i > slen) {
if (s == NULL)
sp = (unsigned char *)OPENSSL_malloc((unsigned int)num +
i * 2);
else
sp = (unsigned char *)OPENSSL_realloc(s,
(unsigned int)num +
i * 2);
if (sp == NULL) {
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
goto err;
}
s = sp;
slen = num + i * 2;
}
for (j = 0; j < i; j++, k += 2) {
for (n = 0; n < 2; n++) {
m = bufp[k + n];
if ((m >= '0') && (m <= '9'))
m -= '0';
else if ((m >= 'a') && (m <= 'f'))
m = m - 'a' + 10;
else if ((m >= 'A') && (m <= 'F'))
m = m - 'A' + 10;
else {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NON_HEX_CHARACTERS);
goto err;
}
s[num + j] <<= 4;
s[num + j] |= m;
}
}
num += i;
if (again)
bufsize = BIO_gets(bp, buf, size);
else
break;
}
bs->length = num;
bs->data = s;
ret = 1;
err:
if (0) {
err_sl:
OPENSSL_PUT_ERROR(ASN1, ASN1_R_SHORT_LINE);
}
if (s != NULL)
OPENSSL_free(s);
return (ret);
}
+6 -8
View File
@@ -180,7 +180,6 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
int ret = 0;
ASN1_VALUE **pchptr, *ptmpval;
int combine = aclass & ASN1_TFLG_COMBINE;
aclass &= ~ASN1_TFLG_COMBINE;
if (!pval)
return 0;
if (aux && aux->asn1_cb)
@@ -400,9 +399,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
if (tt->flags & ASN1_TFLG_ADB_MASK) {
const ASN1_TEMPLATE *seqtt;
ASN1_VALUE **pseqval;
seqtt = asn1_do_adb(pval, tt, 0);
if (seqtt == NULL)
continue;
seqtt = asn1_do_adb(pval, tt, 1);
pseqval = asn1_get_field_ptr(pval, seqtt);
ASN1_template_free(pseqval, seqtt);
}
@@ -413,7 +410,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
const ASN1_TEMPLATE *seqtt;
ASN1_VALUE **pseqval;
seqtt = asn1_do_adb(pval, tt, 1);
if (seqtt == NULL)
if (!seqtt)
goto err;
pseqval = asn1_get_field_ptr(pval, seqtt);
/* Have we ran out of data? */
@@ -478,7 +475,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
for (; i < it->tcount; tt++, i++) {
const ASN1_TEMPLATE *seqtt;
seqtt = asn1_do_adb(pval, tt, 1);
if (seqtt == NULL)
if (!seqtt)
goto err;
if (seqtt->flags & ASN1_TFLG_OPTIONAL) {
ASN1_VALUE **pseqval;
@@ -668,7 +665,6 @@ static int asn1_template_noexp_d2i(ASN1_VALUE **val,
}
len -= p - q;
if (!sk_ASN1_VALUE_push((STACK_OF(ASN1_VALUE) *)*val, skfield)) {
ASN1_item_ex_free(&skfield, ASN1_ITEM_ptr(tt->item));
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
goto err;
}
@@ -898,7 +894,9 @@ int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
break;
case V_ASN1_INTEGER:
case V_ASN1_NEG_INTEGER:
case V_ASN1_ENUMERATED:
case V_ASN1_NEG_ENUMERATED:
tint = (ASN1_INTEGER **)pval;
if (!c2i_ASN1_INTEGER(tint, &cont, len))
goto err;
@@ -1110,7 +1108,7 @@ static int collect_data(BUF_MEM *buf, const unsigned char **p, long plen)
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
return 0;
}
OPENSSL_memcpy(buf->data + len, *p, plen);
memcpy(buf->data + len, *p, plen);
}
*p += plen;
return 1;
+14 -23
View File
@@ -56,15 +56,11 @@
#include <openssl/asn1.h>
#include <limits.h>
#include <string.h>
#include <openssl/asn1t.h>
#include <openssl/mem.h>
#include "../internal.h"
static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out,
const ASN1_ITEM *it, int tag, int aclass);
static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out,
@@ -217,19 +213,17 @@ int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) {
const ASN1_TEMPLATE *seqtt;
ASN1_VALUE **pseqval;
int tmplen;
seqtt = asn1_do_adb(pval, tt, 1);
if (!seqtt)
return 0;
pseqval = asn1_get_field_ptr(pval, seqtt);
tmplen = asn1_template_ex_i2d(pseqval, NULL, seqtt, -1, aclass);
if (tmplen == -1 || (tmplen > INT_MAX - seqcontlen))
return -1;
seqcontlen += tmplen;
/* FIXME: check for errors in enhanced version */
seqcontlen += asn1_template_ex_i2d(pseqval, NULL, seqtt,
-1, aclass);
}
seqlen = ASN1_object_size(ndef, seqcontlen, tag);
if (!out || seqlen == -1)
if (!out)
return seqlen;
/* Output SEQUENCE header */
ASN1_put_object(out, ndef, seqcontlen, tag, aclass);
@@ -343,24 +337,19 @@ static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
/* Determine total length of items */
skcontlen = 0;
for (j = 0; j < sk_ASN1_VALUE_num(sk); j++) {
int tmplen;
skitem = sk_ASN1_VALUE_value(sk, j);
tmplen = ASN1_item_ex_i2d(&skitem, NULL, ASN1_ITEM_ptr(tt->item),
-1, iclass);
if (tmplen == -1 || (skcontlen > INT_MAX - tmplen))
return -1;
skcontlen += tmplen;
skcontlen += ASN1_item_ex_i2d(&skitem, NULL,
ASN1_ITEM_ptr(tt->item),
-1, iclass);
}
sklen = ASN1_object_size(ndef, skcontlen, sktag);
if (sklen == -1)
return -1;
/* If EXPLICIT need length of surrounding tag */
if (flags & ASN1_TFLG_EXPTAG)
ret = ASN1_object_size(ndef, sklen, ttag);
else
ret = sklen;
if (!out || ret == -1)
if (!out)
return ret;
/* Now encode this lot... */
@@ -389,7 +378,7 @@ static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
return 0;
/* Find length of EXPLICIT tag */
ret = ASN1_object_size(ndef, i, ttag);
if (out && ret != -1) {
if (out) {
/* Output tag and item */
ASN1_put_object(out, ndef, i, ttag, tclass);
ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), -1, iclass);
@@ -418,7 +407,7 @@ static int der_cmp(const void *a, const void *b)
const DER_ENC *d1 = a, *d2 = b;
int cmplen, i;
cmplen = (d1->length < d2->length) ? d1->length : d2->length;
i = OPENSSL_memcmp(d1->data, d2->data, cmplen);
i = memcmp(d1->data, d2->data, cmplen);
if (i)
return i;
return d1->length - d2->length;
@@ -473,7 +462,7 @@ static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out,
/* Output sorted DER encoding */
p = *out;
for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) {
OPENSSL_memcpy(p, tder->data, tder->length);
memcpy(p, tder->data, tder->length);
p += tder->length;
}
*out = p;
@@ -620,7 +609,9 @@ int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype,
break;
case V_ASN1_INTEGER:
case V_ASN1_NEG_INTEGER:
case V_ASN1_ENUMERATED:
case V_ASN1_NEG_ENUMERATED:
/*
* These are all have the same content format as ASN1_INTEGER
*/
@@ -663,6 +654,6 @@ int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype,
}
if (cout && len)
OPENSSL_memcpy(cout, cont, len);
memcpy(cout, cont, len);
return len;
}
+7 -12
View File
@@ -63,9 +63,6 @@
#include <openssl/mem.h>
#include <openssl/obj.h>
#include "../internal.h"
static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it,
int combine);
static void asn1_item_clear(ASN1_VALUE **pval, const ASN1_ITEM *it);
@@ -156,11 +153,11 @@ static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it,
*pval = OPENSSL_malloc(it->size);
if (!*pval)
goto memerr;
OPENSSL_memset(*pval, 0, it->size);
memset(*pval, 0, it->size);
}
asn1_set_choice_selector(pval, -1, it);
if (asn1_cb && !asn1_cb(ASN1_OP_NEW_POST, pval, it, NULL))
goto auxerr2;
goto auxerr;
break;
case ASN1_ITYPE_NDEF_SEQUENCE:
@@ -181,17 +178,17 @@ static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it,
*pval = OPENSSL_malloc(it->size);
if (!*pval)
goto memerr;
OPENSSL_memset(*pval, 0, it->size);
memset(*pval, 0, it->size);
asn1_refcount_set_one(pval, it);
asn1_enc_init(pval, it);
}
for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) {
pseqval = asn1_get_field_ptr(pval, tt);
if (!ASN1_template_new(pseqval, tt))
goto memerr2;
goto memerr;
}
if (asn1_cb && !asn1_cb(ASN1_OP_NEW_POST, pval, it, NULL))
goto auxerr2;
goto auxerr;
break;
}
#ifdef CRYPTO_MDEBUG
@@ -200,20 +197,18 @@ static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it,
#endif
return 1;
memerr2:
ASN1_item_ex_free(pval, it);
memerr:
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
ASN1_item_ex_free(pval, it);
#ifdef CRYPTO_MDEBUG
if (it->sname)
CRYPTO_pop_info();
#endif
return 0;
auxerr2:
ASN1_item_ex_free(pval, it);
auxerr:
OPENSSL_PUT_ERROR(ASN1, ASN1_R_AUX_ERROR);
ASN1_item_ex_free(pval, it);
#ifdef CRYPTO_MDEBUG
if (it->sname)
CRYPTO_pop_info();
+596
View File
@@ -0,0 +1,596 @@
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.] */
#include <openssl/asn1.h>
#include <time.h>
#include <openssl/asn1t.h>
#include <openssl/err.h>
#include <openssl/obj.h>
#include <openssl/mem.h>
#include "asn1_locl.h"
/*
* Print routines.
*/
/* ASN1_PCTX routines */
static ASN1_PCTX default_pctx = {
ASN1_PCTX_FLAGS_SHOW_ABSENT, /* flags */
0, /* nm_flags */
0, /* cert_flags */
0, /* oid_flags */
0 /* str_flags */
};
ASN1_PCTX *ASN1_PCTX_new(void)
{
ASN1_PCTX *ret;
ret = OPENSSL_malloc(sizeof(ASN1_PCTX));
if (ret == NULL) {
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
return NULL;
}
ret->flags = 0;
ret->nm_flags = 0;
ret->cert_flags = 0;
ret->oid_flags = 0;
ret->str_flags = 0;
return ret;
}
void ASN1_PCTX_free(ASN1_PCTX *p)
{
OPENSSL_free(p);
}
unsigned long ASN1_PCTX_get_flags(ASN1_PCTX *p)
{
return p->flags;
}
void ASN1_PCTX_set_flags(ASN1_PCTX *p, unsigned long flags)
{
p->flags = flags;
}
unsigned long ASN1_PCTX_get_nm_flags(ASN1_PCTX *p)
{
return p->nm_flags;
}
void ASN1_PCTX_set_nm_flags(ASN1_PCTX *p, unsigned long flags)
{
p->nm_flags = flags;
}
unsigned long ASN1_PCTX_get_cert_flags(ASN1_PCTX *p)
{
return p->cert_flags;
}
void ASN1_PCTX_set_cert_flags(ASN1_PCTX *p, unsigned long flags)
{
p->cert_flags = flags;
}
unsigned long ASN1_PCTX_get_oid_flags(ASN1_PCTX *p)
{
return p->oid_flags;
}
void ASN1_PCTX_set_oid_flags(ASN1_PCTX *p, unsigned long flags)
{
p->oid_flags = flags;
}
unsigned long ASN1_PCTX_get_str_flags(ASN1_PCTX *p)
{
return p->str_flags;
}
void ASN1_PCTX_set_str_flags(ASN1_PCTX *p, unsigned long flags)
{
p->str_flags = flags;
}
/* Main print routines */
static int asn1_item_print_ctx(BIO *out, ASN1_VALUE **fld, int indent,
const ASN1_ITEM *it,
const char *fname, const char *sname,
int nohdr, const ASN1_PCTX *pctx);
int asn1_template_print_ctx(BIO *out, ASN1_VALUE **fld, int indent,
const ASN1_TEMPLATE *tt, const ASN1_PCTX *pctx);
static int asn1_primitive_print(BIO *out, ASN1_VALUE **fld,
const ASN1_ITEM *it, int indent,
const char *fname, const char *sname,
const ASN1_PCTX *pctx);
static int asn1_print_fsname(BIO *out, int indent,
const char *fname, const char *sname,
const ASN1_PCTX *pctx);
int ASN1_item_print(BIO *out, ASN1_VALUE *ifld, int indent,
const ASN1_ITEM *it, const ASN1_PCTX *pctx)
{
const char *sname;
if (pctx == NULL)
pctx = &default_pctx;
if (pctx->flags & ASN1_PCTX_FLAGS_NO_STRUCT_NAME)
sname = NULL;
else
sname = it->sname;
return asn1_item_print_ctx(out, &ifld, indent, it, NULL, sname, 0, pctx);
}
static int asn1_item_print_ctx(BIO *out, ASN1_VALUE **fld, int indent,
const ASN1_ITEM *it,
const char *fname, const char *sname,
int nohdr, const ASN1_PCTX *pctx)
{
const ASN1_TEMPLATE *tt;
const ASN1_EXTERN_FUNCS *ef;
ASN1_VALUE **tmpfld;
const ASN1_AUX *aux = it->funcs;
ASN1_aux_cb *asn1_cb;
ASN1_PRINT_ARG parg;
int i;
if (aux && aux->asn1_cb) {
parg.out = out;
parg.indent = indent;
parg.pctx = pctx;
asn1_cb = aux->asn1_cb;
} else
asn1_cb = 0;
if (*fld == NULL) {
if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_ABSENT) {
if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx))
return 0;
if (BIO_puts(out, "<ABSENT>\n") <= 0)
return 0;
}
return 1;
}
switch (it->itype) {
case ASN1_ITYPE_PRIMITIVE:
if (it->templates) {
if (!asn1_template_print_ctx(out, fld, indent,
it->templates, pctx))
return 0;
break;
}
/* fall thru */
case ASN1_ITYPE_MSTRING:
if (!asn1_primitive_print(out, fld, it, indent, fname, sname, pctx))
return 0;
break;
case ASN1_ITYPE_EXTERN:
if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx))
return 0;
/* Use new style print routine if possible */
ef = it->funcs;
if (ef && ef->asn1_ex_print) {
i = ef->asn1_ex_print(out, fld, indent, "", pctx);
if (!i)
return 0;
if ((i == 2) && (BIO_puts(out, "\n") <= 0))
return 0;
return 1;
} else if (sname &&
BIO_printf(out, ":EXTERNAL TYPE %s\n", sname) <= 0)
return 0;
break;
case ASN1_ITYPE_CHOICE:
#if 0
if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx))
return 0;
#endif
/* CHOICE type, get selector */
i = asn1_get_choice_selector(fld, it);
/* This should never happen... */
if ((i < 0) || (i >= it->tcount)) {
if (BIO_printf(out, "ERROR: selector [%d] invalid\n", i) <= 0)
return 0;
return 1;
}
tt = it->templates + i;
tmpfld = asn1_get_field_ptr(fld, tt);
if (!asn1_template_print_ctx(out, tmpfld, indent, tt, pctx))
return 0;
break;
case ASN1_ITYPE_SEQUENCE:
case ASN1_ITYPE_NDEF_SEQUENCE:
if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx))
return 0;
if (fname || sname) {
if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE) {
if (BIO_puts(out, " {\n") <= 0)
return 0;
} else {
if (BIO_puts(out, "\n") <= 0)
return 0;
}
}
if (asn1_cb) {
i = asn1_cb(ASN1_OP_PRINT_PRE, fld, it, &parg);
if (i == 0)
return 0;
if (i == 2)
return 1;
}
/* Print each field entry */
for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) {
const ASN1_TEMPLATE *seqtt;
seqtt = asn1_do_adb(fld, tt, 1);
if (!seqtt)
return 0;
tmpfld = asn1_get_field_ptr(fld, seqtt);
if (!asn1_template_print_ctx(out, tmpfld,
indent + 2, seqtt, pctx))
return 0;
}
if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE) {
if (BIO_printf(out, "%*s}\n", indent, "") < 0)
return 0;
}
if (asn1_cb) {
i = asn1_cb(ASN1_OP_PRINT_POST, fld, it, &parg);
if (i == 0)
return 0;
}
break;
default:
BIO_printf(out, "Unprocessed type %d\n", it->itype);
return 0;
}
return 1;
}
int asn1_template_print_ctx(BIO *out, ASN1_VALUE **fld, int indent,
const ASN1_TEMPLATE *tt, const ASN1_PCTX *pctx)
{
int flags;
size_t i;
const char *sname, *fname;
flags = tt->flags;
if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_FIELD_STRUCT_NAME)
sname = ASN1_ITEM_ptr(tt->item)->sname;
else
sname = NULL;
if (pctx->flags & ASN1_PCTX_FLAGS_NO_FIELD_NAME)
fname = NULL;
else
fname = tt->field_name;
if (flags & ASN1_TFLG_SK_MASK) {
const char *tname;
ASN1_VALUE *skitem;
STACK_OF(ASN1_VALUE) *stack;
/* SET OF, SEQUENCE OF */
if (fname) {
if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SSOF) {
if (flags & ASN1_TFLG_SET_OF)
tname = "SET";
else
tname = "SEQUENCE";
if (BIO_printf(out, "%*s%s OF %s {\n",
indent, "", tname, tt->field_name) <= 0)
return 0;
} else if (BIO_printf(out, "%*s%s:\n", indent, "", fname) <= 0)
return 0;
}
stack = (STACK_OF(ASN1_VALUE) *)*fld;
for (i = 0; i < sk_ASN1_VALUE_num(stack); i++) {
if ((i > 0) && (BIO_puts(out, "\n") <= 0))
return 0;
skitem = sk_ASN1_VALUE_value(stack, i);
if (!asn1_item_print_ctx(out, &skitem, indent + 2,
ASN1_ITEM_ptr(tt->item), NULL, NULL, 1,
pctx))
return 0;
}
if (!i && BIO_printf(out, "%*s<EMPTY>\n", indent + 2, "") <= 0)
return 0;
if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE) {
if (BIO_printf(out, "%*s}\n", indent, "") <= 0)
return 0;
}
return 1;
}
return asn1_item_print_ctx(out, fld, indent, ASN1_ITEM_ptr(tt->item),
fname, sname, 0, pctx);
}
static int asn1_print_fsname(BIO *out, int indent,
const char *fname, const char *sname,
const ASN1_PCTX *pctx)
{
static char spaces[] = " ";
const int nspaces = sizeof(spaces) - 1;
#if 0
if (!sname && !fname)
return 1;
#endif
while (indent > nspaces) {
if (BIO_write(out, spaces, nspaces) != nspaces)
return 0;
indent -= nspaces;
}
if (BIO_write(out, spaces, indent) != indent)
return 0;
if (pctx->flags & ASN1_PCTX_FLAGS_NO_STRUCT_NAME)
sname = NULL;
if (pctx->flags & ASN1_PCTX_FLAGS_NO_FIELD_NAME)
fname = NULL;
if (!sname && !fname)
return 1;
if (fname) {
if (BIO_puts(out, fname) <= 0)
return 0;
}
if (sname) {
if (fname) {
if (BIO_printf(out, " (%s)", sname) <= 0)
return 0;
} else {
if (BIO_puts(out, sname) <= 0)
return 0;
}
}
if (BIO_write(out, ": ", 2) != 2)
return 0;
return 1;
}
static int asn1_print_boolean_ctx(BIO *out, int boolval,
const ASN1_PCTX *pctx)
{
const char *str;
switch (boolval) {
case -1:
str = "BOOL ABSENT";
break;
case 0:
str = "FALSE";
break;
default:
str = "TRUE";
break;
}
if (BIO_puts(out, str) <= 0)
return 0;
return 1;
}
static int asn1_print_integer_ctx(BIO *out, ASN1_INTEGER *str,
const ASN1_PCTX *pctx)
{
BIGNUM *bn = NULL;
char *s = NULL;
int ret = 1;
bn = ASN1_INTEGER_to_BN(str, NULL);
if (bn == NULL) {
return 0;
}
s = BN_bn2dec(bn);
BN_free(bn);
if (s == NULL) {
return 0;
}
if (BIO_puts(out, s) <= 0) {
ret = 0;
}
OPENSSL_free(s);
return ret;
}
static int asn1_print_oid_ctx(BIO *out, const ASN1_OBJECT *oid,
const ASN1_PCTX *pctx)
{
char objbuf[80];
const char *ln;
ln = OBJ_nid2ln(OBJ_obj2nid(oid));
if (!ln)
ln = "";
OBJ_obj2txt(objbuf, sizeof objbuf, oid, 1);
if (BIO_printf(out, "%s (%s)", ln, objbuf) <= 0)
return 0;
return 1;
}
static int asn1_print_obstring_ctx(BIO *out, ASN1_STRING *str, int indent,
const ASN1_PCTX *pctx)
{
if (str->type == V_ASN1_BIT_STRING) {
if (BIO_printf(out, " (%ld unused bits)\n", str->flags & 0x7) <= 0)
return 0;
} else if (BIO_puts(out, "\n") <= 0)
return 0;
if (str->length > 0
&& !BIO_hexdump(out, str->data, str->length, indent + 2)) {
return 0;
}
return 1;
}
static int asn1_primitive_print(BIO *out, ASN1_VALUE **fld,
const ASN1_ITEM *it, int indent,
const char *fname, const char *sname,
const ASN1_PCTX *pctx)
{
long utype;
ASN1_STRING *str;
int ret = 1, needlf = 1;
const char *pname;
const ASN1_PRIMITIVE_FUNCS *pf;
pf = it->funcs;
if (!asn1_print_fsname(out, indent, fname, sname, pctx))
return 0;
if (pf && pf->prim_print)
return pf->prim_print(out, fld, it, indent, pctx);
str = (ASN1_STRING *)*fld;
if (it->itype == ASN1_ITYPE_MSTRING)
utype = str->type & ~V_ASN1_NEG;
else
utype = it->utype;
if (utype == V_ASN1_ANY) {
ASN1_TYPE *atype = (ASN1_TYPE *)*fld;
utype = atype->type;
fld = &atype->value.asn1_value;
str = (ASN1_STRING *)*fld;
if (pctx->flags & ASN1_PCTX_FLAGS_NO_ANY_TYPE)
pname = NULL;
else
pname = ASN1_tag2str(utype);
} else {
if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_TYPE)
pname = ASN1_tag2str(utype);
else
pname = NULL;
}
if (utype == V_ASN1_NULL) {
if (BIO_puts(out, "NULL\n") <= 0)
return 0;
return 1;
}
if (pname) {
if (BIO_puts(out, pname) <= 0)
return 0;
if (BIO_puts(out, ":") <= 0)
return 0;
}
switch (utype) {
case V_ASN1_BOOLEAN:
{
int boolval = *(int *)fld;
if (boolval == -1)
boolval = it->size;
ret = asn1_print_boolean_ctx(out, boolval, pctx);
}
break;
case V_ASN1_INTEGER:
case V_ASN1_ENUMERATED:
ret = asn1_print_integer_ctx(out, str, pctx);
break;
case V_ASN1_UTCTIME:
ret = ASN1_UTCTIME_print(out, str);
break;
case V_ASN1_GENERALIZEDTIME:
ret = ASN1_GENERALIZEDTIME_print(out, str);
break;
case V_ASN1_OBJECT:
ret = asn1_print_oid_ctx(out, (const ASN1_OBJECT *)*fld, pctx);
break;
case V_ASN1_OCTET_STRING:
case V_ASN1_BIT_STRING:
ret = asn1_print_obstring_ctx(out, str, indent, pctx);
needlf = 0;
break;
case V_ASN1_SEQUENCE:
case V_ASN1_SET:
case V_ASN1_OTHER:
if (BIO_puts(out, "\n") <= 0)
return 0;
if (ASN1_parse_dump(out, str->data, str->length, indent, 0) <= 0)
ret = 0;
needlf = 0;
break;
default:
ret = ASN1_STRING_print_ex(out, str, pctx->str_flags);
}
if (!ret)
return 0;
if (needlf && BIO_puts(out, "\n") <= 0)
return 0;
return 1;
}
+40 -27
View File
@@ -87,45 +87,58 @@ IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_VISIBLESTRING)
IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_UNIVERSALSTRING)
IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_BMPSTRING)
IMPLEMENT_ASN1_TYPE(ASN1_NULL)
IMPLEMENT_ASN1_FUNCTIONS(ASN1_NULL)
IMPLEMENT_ASN1_TYPE(ASN1_NULL);
IMPLEMENT_ASN1_FUNCTIONS(ASN1_NULL);
IMPLEMENT_ASN1_TYPE(ASN1_OBJECT)
IMPLEMENT_ASN1_TYPE(ASN1_OBJECT);
IMPLEMENT_ASN1_TYPE(ASN1_ANY)
IMPLEMENT_ASN1_TYPE(ASN1_ANY);
/* Just swallow an ASN1_SEQUENCE in an ASN1_STRING */
IMPLEMENT_ASN1_TYPE(ASN1_SEQUENCE)
/*
* Just swallow an ASN1_SEQUENCE in an ASN1_STRING
*/ ;
IMPLEMENT_ASN1_TYPE(ASN1_SEQUENCE);
IMPLEMENT_ASN1_FUNCTIONS_fname(ASN1_TYPE, ASN1_ANY, ASN1_TYPE)
IMPLEMENT_ASN1_FUNCTIONS_fname(ASN1_TYPE, ASN1_ANY, ASN1_TYPE);
/* Multistring types */
/*
* Multistring types
*/ ;
IMPLEMENT_ASN1_MSTRING(ASN1_PRINTABLE, B_ASN1_PRINTABLE)
IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, ASN1_PRINTABLE)
IMPLEMENT_ASN1_MSTRING(ASN1_PRINTABLE, B_ASN1_PRINTABLE);
IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, ASN1_PRINTABLE);
IMPLEMENT_ASN1_MSTRING(DISPLAYTEXT, B_ASN1_DISPLAYTEXT)
IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, DISPLAYTEXT)
IMPLEMENT_ASN1_MSTRING(DISPLAYTEXT, B_ASN1_DISPLAYTEXT);
IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, DISPLAYTEXT);
IMPLEMENT_ASN1_MSTRING(DIRECTORYSTRING, B_ASN1_DIRECTORYSTRING)
IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, DIRECTORYSTRING)
IMPLEMENT_ASN1_MSTRING(DIRECTORYSTRING, B_ASN1_DIRECTORYSTRING);
IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, DIRECTORYSTRING);
/* Three separate BOOLEAN type: normal, DEFAULT TRUE and DEFAULT FALSE */
IMPLEMENT_ASN1_TYPE_ex(ASN1_BOOLEAN, ASN1_BOOLEAN, -1)
IMPLEMENT_ASN1_TYPE_ex(ASN1_TBOOLEAN, ASN1_BOOLEAN, 1)
IMPLEMENT_ASN1_TYPE_ex(ASN1_FBOOLEAN, ASN1_BOOLEAN, 0)
/*
* Three separate BOOLEAN type: normal, DEFAULT TRUE and DEFAULT FALSE
*/ ;
IMPLEMENT_ASN1_TYPE_ex(ASN1_BOOLEAN, ASN1_BOOLEAN, -1);
IMPLEMENT_ASN1_TYPE_ex(ASN1_TBOOLEAN, ASN1_BOOLEAN, 1);
IMPLEMENT_ASN1_TYPE_ex(ASN1_FBOOLEAN, ASN1_BOOLEAN, 0);
/* Special, OCTET STRING with indefinite length constructed support */
/*
* Special, OCTET STRING with indefinite length constructed support
*/ ;
IMPLEMENT_ASN1_TYPE_ex(ASN1_OCTET_STRING_NDEF, ASN1_OCTET_STRING, ASN1_TFLG_NDEF)
IMPLEMENT_ASN1_TYPE_ex(ASN1_OCTET_STRING_NDEF, ASN1_OCTET_STRING,
ASN1_TFLG_NDEF);
ASN1_ITEM_TEMPLATE(ASN1_SEQUENCE_ANY) =
ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, ASN1_SEQUENCE_ANY, ASN1_ANY)
ASN1_ITEM_TEMPLATE_END(ASN1_SEQUENCE_ANY)
ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, ASN1_SEQUENCE_ANY,
ASN1_ANY);
ASN1_ITEM_TEMPLATE_END(ASN1_SEQUENCE_ANY);
ASN1_ITEM_TEMPLATE(ASN1_SET_ANY) =
ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_OF, 0, ASN1_SET_ANY, ASN1_ANY)
ASN1_ITEM_TEMPLATE_END(ASN1_SET_ANY)
ASN1_ITEM_TEMPLATE(ASN1_SET_ANY) = ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_OF, 0,
ASN1_SET_ANY,
ASN1_ANY);
ASN1_ITEM_TEMPLATE_END(ASN1_SET_ANY);
IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(ASN1_SEQUENCE_ANY, ASN1_SEQUENCE_ANY, ASN1_SEQUENCE_ANY)
IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(ASN1_SEQUENCE_ANY, ASN1_SET_ANY, ASN1_SET_ANY)
IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(ASN1_SEQUENCE_ANY,
ASN1_SEQUENCE_ANY, ASN1_SEQUENCE_ANY);
IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(ASN1_SEQUENCE_ANY, ASN1_SET_ANY,
ASN1_SET_ANY);
+9 -23
View File
@@ -56,7 +56,6 @@
#include <openssl/asn1.h>
#include <assert.h>
#include <string.h>
#include <openssl/asn1t.h>
@@ -71,7 +70,7 @@
/* Utility functions for manipulating fields and offsets */
/* Add 'offset' to 'addr' */
#define offset2ptr(addr, offset) (void *)(((char *)(addr)) + (offset))
#define offset2ptr(addr, offset) (void *)(((char *) addr) + offset)
/* Given an ASN1_ITEM CHOICE type return the selector value */
int asn1_get_choice_selector(ASN1_VALUE **pval, const ASN1_ITEM *it) {
@@ -135,8 +134,6 @@ void asn1_enc_init(ASN1_VALUE **pval, const ASN1_ITEM *it) {
if (enc) {
enc->enc = NULL;
enc->len = 0;
enc->alias_only = 0;
enc->alias_only_on_next_parse = 0;
enc->modified = 1;
}
}
@@ -145,13 +142,11 @@ void asn1_enc_free(ASN1_VALUE **pval, const ASN1_ITEM *it) {
ASN1_ENCODING *enc;
enc = asn1_get_enc_ptr(pval, it);
if (enc) {
if (enc->enc && !enc->alias_only) {
if (enc->enc) {
OPENSSL_free(enc->enc);
}
enc->enc = NULL;
enc->len = 0;
enc->alias_only = 0;
enc->alias_only_on_next_parse = 0;
enc->modified = 1;
}
}
@@ -164,23 +159,14 @@ int asn1_enc_save(ASN1_VALUE **pval, const unsigned char *in, int inlen,
return 1;
}
if (!enc->alias_only) {
if (enc->enc) {
OPENSSL_free(enc->enc);
}
enc->alias_only = enc->alias_only_on_next_parse;
enc->alias_only_on_next_parse = 0;
if (enc->alias_only) {
enc->enc = (uint8_t *) in;
} else {
enc->enc = OPENSSL_malloc(inlen);
if (!enc->enc) {
return 0;
}
OPENSSL_memcpy(enc->enc, in, inlen);
enc->enc = OPENSSL_malloc(inlen);
if (!enc->enc) {
return 0;
}
memcpy(enc->enc, in, inlen);
enc->len = inlen;
enc->modified = 0;
@@ -195,7 +181,7 @@ int asn1_enc_restore(int *len, unsigned char **out, ASN1_VALUE **pval,
return 0;
}
if (out) {
OPENSSL_memcpy(*out, enc->enc, enc->len);
memcpy(*out, enc->enc, enc->len);
*out += enc->len;
}
if (len) {
@@ -236,7 +222,7 @@ const ASN1_TEMPLATE *asn1_do_adb(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt,
sfld = offset2ptr(*pval, adb->offset);
/* Check if NULL */
if (*sfld == NULL) {
if (!sfld) {
if (!adb->null_tt) {
goto err;
}
+153
View File
@@ -0,0 +1,153 @@
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.] */
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include <openssl/bn.h>
/*
* Custom primitive type for BIGNUM handling. This reads in an ASN1_INTEGER
* as a BIGNUM directly. Currently it ignores the sign which isn't a problem
* since all BIGNUMs used are non negative and anything that looks negative
* is normally due to an encoding error.
*/
#define BN_SENSITIVE 1
static int bn_new(ASN1_VALUE **pval, const ASN1_ITEM *it);
static void bn_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
static int bn_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype,
const ASN1_ITEM *it);
static int bn_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
int utype, char *free_cont, const ASN1_ITEM *it);
static const ASN1_PRIMITIVE_FUNCS bignum_pf = {
NULL, 0,
bn_new,
bn_free,
0,
bn_c2i,
bn_i2c,
NULL /* prim_print */ ,
};
ASN1_ITEM_start(BIGNUM)
ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &bignum_pf, 0, "BIGNUM"
ASN1_ITEM_end(BIGNUM)
ASN1_ITEM_start(CBIGNUM)
ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &bignum_pf, BN_SENSITIVE, "BIGNUM"
ASN1_ITEM_end(CBIGNUM)
static int bn_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
{
*pval = (ASN1_VALUE *)BN_new();
if (*pval)
return 1;
else
return 0;
}
static void bn_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
{
if (!*pval)
return;
if (it->size & BN_SENSITIVE)
BN_clear_free((BIGNUM *)*pval);
else
BN_free((BIGNUM *)*pval);
*pval = NULL;
}
static int bn_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype,
const ASN1_ITEM *it)
{
BIGNUM *bn;
int pad;
if (!*pval)
return -1;
bn = (BIGNUM *)*pval;
/* If MSB set in an octet we need a padding byte */
if (BN_num_bits(bn) & 0x7)
pad = 0;
else
pad = 1;
if (cont) {
if (pad)
*cont++ = 0;
BN_bn2bin(bn, cont);
}
return pad + BN_num_bytes(bn);
}
static int bn_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
int utype, char *free_cont, const ASN1_ITEM *it)
{
BIGNUM *bn;
if (!*pval) {
if (!bn_new(pval, it)) {
return 0;
}
}
bn = (BIGNUM *)*pval;
if (!BN_bin2bn(cont, len, bn)) {
bn_free(pval, it);
return 0;
}
return 1;
}
+197
View File
@@ -0,0 +1,197 @@
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.] */
#include <openssl/asn1.h>
#include <string.h>
#include <openssl/asn1t.h>
#include <openssl/bn.h>
#include <openssl/err.h>
#include <openssl/mem.h>
/*
* Custom primitive type for long handling. This converts between an
* ASN1_INTEGER and a long directly.
*/
static int long_new(ASN1_VALUE **pval, const ASN1_ITEM *it);
static void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype,
const ASN1_ITEM *it);
static int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
int utype, char *free_cont, const ASN1_ITEM *it);
static int long_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it,
int indent, const ASN1_PCTX *pctx);
static const ASN1_PRIMITIVE_FUNCS long_pf = {
NULL, 0,
long_new,
long_free,
long_free, /* Clear should set to initial value */
long_c2i,
long_i2c,
long_print
};
ASN1_ITEM_start(LONG)
ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &long_pf, ASN1_LONG_UNDEF, "LONG"
ASN1_ITEM_end(LONG)
ASN1_ITEM_start(ZLONG)
ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &long_pf, 0, "ZLONG"
ASN1_ITEM_end(ZLONG)
static int long_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
{
*(long *)pval = it->size;
return 1;
}
static void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
{
*(long *)pval = it->size;
}
static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype,
const ASN1_ITEM *it)
{
long ltmp;
unsigned long utmp;
int clen, pad, i;
/* this exists to bypass broken gcc optimization */
char *cp = (char *)pval;
/* use memcpy, because we may not be long aligned */
memcpy(&ltmp, cp, sizeof(long));
if (ltmp == it->size)
return -1;
/*
* Convert the long to positive: we subtract one if negative so we can
* cleanly handle the padding if only the MSB of the leading octet is
* set.
*/
if (ltmp < 0)
utmp = -ltmp - 1;
else
utmp = ltmp;
clen = BN_num_bits_word(utmp);
/* If MSB of leading octet set we need to pad */
if (!(clen & 0x7))
pad = 1;
else
pad = 0;
/* Convert number of bits to number of octets */
clen = (clen + 7) >> 3;
if (cont) {
if (pad)
*cont++ = (ltmp < 0) ? 0xff : 0;
for (i = clen - 1; i >= 0; i--) {
cont[i] = (unsigned char)(utmp & 0xff);
if (ltmp < 0)
cont[i] ^= 0xff;
utmp >>= 8;
}
}
return clen + pad;
}
static int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
int utype, char *free_cont, const ASN1_ITEM *it)
{
int neg, i;
long ltmp;
unsigned long utmp = 0;
char *cp = (char *)pval;
if (len > (int)sizeof(long)) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG);
return 0;
}
/* Is it negative? */
if (len && (cont[0] & 0x80))
neg = 1;
else
neg = 0;
utmp = 0;
for (i = 0; i < len; i++) {
utmp <<= 8;
if (neg)
utmp |= cont[i] ^ 0xff;
else
utmp |= cont[i];
}
ltmp = (long)utmp;
if (neg) {
ltmp++;
ltmp = -ltmp;
}
if (ltmp == it->size) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG);
return 0;
}
memcpy(cp, &ltmp, sizeof(long));
return 1;
}
static int long_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it,
int indent, const ASN1_PCTX *pctx)
{
return BIO_printf(out, "%ld\n", *(long *)pval);
}
+11
View File
@@ -7,3 +7,14 @@ add_library(
base64.c
)
add_executable(
base64_test
base64_test.cc
$<TARGET_OBJECTS:test_support>
)
target_link_libraries(base64_test crypto)
add_dependencies(all_tests base64_test)
+305 -293
View File
@@ -60,151 +60,118 @@
#include <limits.h>
#include <string.h>
#include <openssl/type_check.h>
#include "../internal.h"
static const unsigned char data_bin2ascii[65] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
#define conv_bin2ascii(a) (data_bin2ascii[(a) & 0x3f])
/* constant_time_lt_args_8 behaves like |constant_time_lt_8| but takes |uint8_t|
* arguments for a slightly simpler implementation. */
static inline uint8_t constant_time_lt_args_8(uint8_t a, uint8_t b) {
crypto_word_t aw = a;
crypto_word_t bw = b;
/* |crypto_word_t| is larger than |uint8_t|, so |aw| and |bw| have the same
* MSB. |aw| < |bw| iff MSB(|aw| - |bw|) is 1. */
return constant_time_msb_w(aw - bw);
}
/* 64 char lines
* pad input with 0
* left over chars are set to =
* 1 byte => xx==
* 2 bytes => xxx=
* 3 bytes => xxxx
*/
#define BIN_PER_LINE (64/4*3)
#define CHUNKS_PER_LINE (64/4)
#define CHAR_PER_LINE (64+1)
/* constant_time_in_range_8 returns |CONSTTIME_TRUE_8| if |min| <= |a| <= |max|
* and |CONSTTIME_FALSE_8| otherwise. */
static inline uint8_t constant_time_in_range_8(uint8_t a, uint8_t min,
uint8_t max) {
a -= min;
return constant_time_lt_args_8(a, max - min + 1);
}
/* 0xF0 is a EOLN
* 0xF1 is ignore but next needs to be 0xF0 (for \r\n processing).
* 0xF2 is EOF
* 0xE0 is ignore at start of line.
* 0xFF is error */
/* Encoding. */
#define B64_EOLN 0xF0
#define B64_CR 0xF1
#define B64_EOF 0xF2
#define B64_WS 0xE0
#define B64_ERROR 0xFF
#define B64_NOT_BASE64(a) (((a) | 0x13) == 0xF3)
static uint8_t conv_bin2ascii(uint8_t a) {
/* Since PEM is sometimes used to carry private keys, we encode base64 data
* itself in constant-time. */
a &= 0x3f;
uint8_t ret = constant_time_select_8(constant_time_eq_8(a, 62), '+', '/');
ret =
constant_time_select_8(constant_time_lt_args_8(a, 62), a - 52 + '0', ret);
ret =
constant_time_select_8(constant_time_lt_args_8(a, 52), a - 26 + 'a', ret);
ret = constant_time_select_8(constant_time_lt_args_8(a, 26), a + 'A', ret);
return ret;
}
static const uint8_t data_ascii2bin[128] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xF0, 0xFF,
0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xF2, 0xFF, 0x3F,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12,
0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
};
OPENSSL_COMPILE_ASSERT(sizeof(((EVP_ENCODE_CTX *)(NULL))->data) % 3 == 0,
data_length_must_be_multiple_of_base64_chunk_size);
int EVP_EncodedLength(size_t *out_len, size_t len) {
if (len + 2 < len) {
return 0;
static uint8_t conv_ascii2bin(uint8_t a) {
if (a >= 128) {
return 0xFF;
}
len += 2;
len /= 3;
if (((len << 2) >> 2) != len) {
return 0;
}
len <<= 2;
if (len + 1 < len) {
return 0;
}
len++;
*out_len = len;
return 1;
return data_ascii2bin[a];
}
void EVP_EncodeInit(EVP_ENCODE_CTX *ctx) {
OPENSSL_memset(ctx, 0, sizeof(EVP_ENCODE_CTX));
ctx->length = 48;
ctx->num = 0;
ctx->line_num = 0;
}
void EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len,
const uint8_t *in, size_t in_len) {
size_t total = 0;
unsigned i, j;
unsigned total = 0;
*out_len = 0;
if (in_len == 0) {
return;
}
assert(ctx->data_used < sizeof(ctx->data));
assert(ctx->length <= sizeof(ctx->enc_data));
if (sizeof(ctx->data) - ctx->data_used > in_len) {
OPENSSL_memcpy(&ctx->data[ctx->data_used], in, in_len);
ctx->data_used += (unsigned)in_len;
if (ctx->num + in_len < ctx->length) {
memcpy(&ctx->enc_data[ctx->num], in, in_len);
ctx->num += in_len;
return;
}
if (ctx->data_used != 0) {
const size_t todo = sizeof(ctx->data) - ctx->data_used;
OPENSSL_memcpy(&ctx->data[ctx->data_used], in, todo);
in += todo;
in_len -= todo;
size_t encoded = EVP_EncodeBlock(out, ctx->data, sizeof(ctx->data));
ctx->data_used = 0;
out += encoded;
if (ctx->num != 0) {
i = ctx->length - ctx->num;
memcpy(&ctx->enc_data[ctx->num], in, i);
in += i;
in_len -= i;
j = EVP_EncodeBlock(out, ctx->enc_data, ctx->length);
ctx->num = 0;
out += j;
*(out++) = '\n';
*out = '\0';
total = encoded + 1;
total = j + 1;
}
while (in_len >= sizeof(ctx->data)) {
size_t encoded = EVP_EncodeBlock(out, in, sizeof(ctx->data));
in += sizeof(ctx->data);
in_len -= sizeof(ctx->data);
out += encoded;
while (in_len >= ctx->length) {
j = EVP_EncodeBlock(out, in, ctx->length);
in += ctx->length;
in_len -= ctx->length;
out += j;
*(out++) = '\n';
*out = '\0';
if (total + encoded + 1 < total) {
*out_len = 0;
return;
}
total += encoded + 1;
total += j + 1;
}
if (in_len != 0) {
OPENSSL_memcpy(ctx->data, in, in_len);
memcpy(&ctx->enc_data[0], in, in_len);
}
ctx->data_used = (unsigned)in_len;
if (total > INT_MAX) {
/* We cannot signal an error, but we can at least avoid making *out_len
* negative. */
total = 0;
}
*out_len = (int)total;
ctx->num = in_len;
*out_len = total;
}
void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len) {
if (ctx->data_used == 0) {
*out_len = 0;
return;
unsigned ret = 0;
if (ctx->num != 0) {
ret = EVP_EncodeBlock(out, ctx->enc_data, ctx->num);
out[ret++] = '\n';
out[ret] = '\0';
ctx->num = 0;
}
size_t encoded = EVP_EncodeBlock(out, ctx->data, ctx->data_used);
out[encoded++] = '\n';
out[encoded] = '\0';
ctx->data_used = 0;
/* ctx->data_used is bounded by sizeof(ctx->data), so this does not
* overflow. */
assert(encoded <= INT_MAX);
*out_len = (int)encoded;
*out_len = ret;
}
size_t EVP_EncodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) {
@@ -239,219 +206,246 @@ size_t EVP_EncodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) {
return ret;
}
/* Decoding. */
int EVP_DecodedLength(size_t *out_len, size_t len) {
if (len % 4 != 0) {
return 0;
}
*out_len = (len / 4) * 3;
return 1;
}
void EVP_DecodeInit(EVP_ENCODE_CTX *ctx) {
OPENSSL_memset(ctx, 0, sizeof(EVP_ENCODE_CTX));
}
static uint8_t base64_ascii_to_bin(uint8_t a) {
/* Since PEM is sometimes used to carry private keys, we decode base64 data
* itself in constant-time. */
const uint8_t is_upper = constant_time_in_range_8(a, 'A', 'Z');
const uint8_t is_lower = constant_time_in_range_8(a, 'a', 'z');
const uint8_t is_digit = constant_time_in_range_8(a, '0', '9');
const uint8_t is_plus = constant_time_eq_8(a, '+');
const uint8_t is_slash = constant_time_eq_8(a, '/');
const uint8_t is_equals = constant_time_eq_8(a, '=');
uint8_t ret = 0xff; /* 0xff signals invalid. */
ret = constant_time_select_8(is_upper, a - 'A', ret); /* [0,26) */
ret = constant_time_select_8(is_lower, a - 'a' + 26, ret); /* [26,52) */
ret = constant_time_select_8(is_digit, a - '0' + 52, ret); /* [52,62) */
ret = constant_time_select_8(is_plus, 62, ret);
ret = constant_time_select_8(is_slash, 63, ret);
/* Padding maps to zero, to be further handled by the caller. */
ret = constant_time_select_8(is_equals, 0, ret);
return ret;
}
/* base64_decode_quad decodes a single “quad” (i.e. four characters) of base64
* data and writes up to three bytes to |out|. It sets |*out_num_bytes| to the
* number of bytes written, which will be less than three if the quad ended
* with padding. It returns one on success or zero on error. */
static int base64_decode_quad(uint8_t *out, size_t *out_num_bytes,
const uint8_t *in) {
const uint8_t a = base64_ascii_to_bin(in[0]);
const uint8_t b = base64_ascii_to_bin(in[1]);
const uint8_t c = base64_ascii_to_bin(in[2]);
const uint8_t d = base64_ascii_to_bin(in[3]);
if (a == 0xff || b == 0xff || c == 0xff || d == 0xff) {
return 0;
}
const uint32_t v = ((uint32_t)a) << 18 | ((uint32_t)b) << 12 |
((uint32_t)c) << 6 | (uint32_t)d;
const unsigned padding_pattern = (in[0] == '=') << 3 |
(in[1] == '=') << 2 |
(in[2] == '=') << 1 |
(in[3] == '=');
switch (padding_pattern) {
case 0:
/* The common case of no padding. */
*out_num_bytes = 3;
out[0] = v >> 16;
out[1] = v >> 8;
out[2] = v;
break;
case 1: /* xxx= */
*out_num_bytes = 2;
out[0] = v >> 16;
out[1] = v >> 8;
break;
case 3: /* xx== */
*out_num_bytes = 1;
out[0] = v >> 16;
break;
default:
return 0;
}
return 1;
}
int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len,
const uint8_t *in, size_t in_len) {
*out_len = 0;
if (ctx->error_encountered) {
return -1;
}
size_t bytes_out = 0, i;
for (i = 0; i < in_len; i++) {
const char c = in[i];
switch (c) {
case ' ':
case '\t':
case '\r':
case '\n':
continue;
}
if (ctx->eof_seen) {
ctx->error_encountered = 1;
return -1;
}
ctx->data[ctx->data_used++] = c;
if (ctx->data_used == 4) {
size_t num_bytes_resulting;
if (!base64_decode_quad(out, &num_bytes_resulting, ctx->data)) {
ctx->error_encountered = 1;
return -1;
}
ctx->data_used = 0;
bytes_out += num_bytes_resulting;
out += num_bytes_resulting;
if (num_bytes_resulting < 3) {
ctx->eof_seen = 1;
}
}
}
if (bytes_out > INT_MAX) {
ctx->error_encountered = 1;
*out_len = 0;
return -1;
}
*out_len = (int)bytes_out;
if (ctx->eof_seen) {
return 0;
}
return 1;
}
int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len) {
*out_len = 0;
if (ctx->error_encountered || ctx->data_used != 0) {
return -1;
}
return 1;
}
int EVP_DecodeBase64(uint8_t *out, size_t *out_len, size_t max_out,
const uint8_t *in, size_t in_len) {
*out_len = 0;
uint8_t a, b, c, d;
size_t pad_len = 0, len = 0, max_len, i;
uint32_t l;
if (in_len % 4 != 0) {
if (!EVP_DecodedLength(&max_len, in_len) || max_out < max_len) {
return 0;
}
size_t max_len;
if (!EVP_DecodedLength(&max_len, in_len) ||
max_out < max_len) {
return 0;
}
size_t i, bytes_out = 0;
for (i = 0; i < in_len; i += 4) {
size_t num_bytes_resulting;
if (!base64_decode_quad(out, &num_bytes_resulting, &in[i])) {
a = conv_ascii2bin(*(in++));
b = conv_ascii2bin(*(in++));
if (i + 4 == in_len && in[1] == '=') {
if (in[0] == '=') {
pad_len = 2;
} else {
pad_len = 1;
}
}
if (pad_len < 2) {
c = conv_ascii2bin(*(in++));
} else {
c = 0;
}
if (pad_len < 1) {
d = conv_ascii2bin(*(in++));
} else {
d = 0;
}
if ((a & 0x80) || (b & 0x80) || (c & 0x80) || (d & 0x80)) {
return 0;
}
bytes_out += num_bytes_resulting;
out += num_bytes_resulting;
if (num_bytes_resulting != 3 && i != in_len - 4) {
return 0;
l = ((((uint32_t)a) << 18L) | (((uint32_t)b) << 12L) |
(((uint32_t)c) << 6L) | (((uint32_t)d)));
*(out++) = (uint8_t)(l >> 16L) & 0xff;
if (pad_len < 2) {
*(out++) = (uint8_t)(l >> 8L) & 0xff;
}
if (pad_len < 1) {
*(out++) = (uint8_t)(l) & 0xff;
}
len += 3 - pad_len;
}
*out_len = bytes_out;
*out_len = len;
return 1;
}
int EVP_DecodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) {
/* Trim spaces and tabs from the beginning of the input. */
while (src_len > 0) {
if (src[0] != ' ' && src[0] != '\t') {
break;
void EVP_DecodeInit(EVP_ENCODE_CTX *ctx) {
ctx->length = 30;
ctx->num = 0;
ctx->line_num = 0;
ctx->expect_nl = 0;
}
int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len,
const uint8_t *in, size_t in_len) {
int seof = -1, eof = 0, rv = -1, v, tmp, exp_nl;
uint8_t *d;
unsigned i, n, ln, ret = 0;
n = ctx->num;
d = ctx->enc_data;
ln = ctx->line_num;
exp_nl = ctx->expect_nl;
/* last line of input. */
if (in_len == 0 || (n == 0 && conv_ascii2bin(in[0]) == B64_EOF)) {
rv = 0;
goto end;
}
/* We parse the input data */
for (i = 0; i < in_len; i++) {
/* If the current line is > 80 characters, scream alot */
if (ln >= 80) {
rv = -1;
goto end;
}
/* Get char and put it into the buffer */
tmp = *(in++);
v = conv_ascii2bin(tmp);
/* only save the good data :-) */
if (!B64_NOT_BASE64(v)) {
assert(n < sizeof(ctx->enc_data));
d[n++] = tmp;
ln++;
} else if (v == B64_ERROR) {
rv = -1;
goto end;
}
/* have we seen a '=' which is 'definitly' the last
* input line. seof will point to the character that
* holds it. and eof will hold how many characters to
* chop off. */
if (tmp == '=') {
if (seof == -1) {
seof = n;
}
eof++;
if (eof > 2) {
/* There are, at most, two equals signs at the end of base64 data. */
rv = -1;
goto end;
}
}
if (v == B64_CR) {
ln = 0;
if (exp_nl) {
continue;
}
}
/* eoln */
if (v == B64_EOLN) {
ln = 0;
if (exp_nl) {
exp_nl = 0;
continue;
}
}
exp_nl = 0;
/* If we are at the end of input and it looks like a
* line, process it. */
if ((i + 1) == in_len && (((n & 3) == 0) || eof)) {
v = B64_EOF;
/* In case things were given us in really small
records (so two '=' were given in separate
updates), eof may contain the incorrect number
of ending bytes to skip, so let's redo the count */
eof = 0;
if (d[n - 1] == '=') {
eof++;
}
if (d[n - 2] == '=') {
eof++;
}
/* There will never be more than two '=' */
}
if ((v == B64_EOF && (n & 3) == 0) || n >= 64) {
/* This is needed to work correctly on 64 byte input
* lines. We process the line and then need to
* accept the '\n' */
if (v != B64_EOF && n >= 64) {
exp_nl = 1;
}
if (n > 0) {
/* TODO(davidben): Switch this to EVP_DecodeBase64. */
v = EVP_DecodeBlock(out, d, n);
n = 0;
if (v < 0) {
rv = 0;
goto end;
}
if (eof > v) {
rv = -1;
goto end;
}
ret += (v - eof);
} else {
eof = 1;
v = 0;
}
/* This is the case where we have had a short
* but valid input line */
if (v < (int)ctx->length && eof) {
rv = 0;
goto end;
} else {
ctx->length = v;
}
if (seof >= 0) {
rv = 0;
goto end;
}
out += v;
}
}
rv = 1;
end:
*out_len = ret;
ctx->num = n;
ctx->line_num = ln;
ctx->expect_nl = exp_nl;
return rv;
}
int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, int *outl) {
int i;
*outl = 0;
if (ctx->num != 0) {
/* TODO(davidben): Switch this to EVP_DecodeBase64. */
i = EVP_DecodeBlock(out, ctx->enc_data, ctx->num);
if (i < 0) {
return -1;
}
ctx->num = 0;
*outl = i;
return 1;
} else {
return 1;
}
}
int EVP_DecodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) {
size_t dst_len;
/* trim white space from the start of the line. */
while (conv_ascii2bin(*src) == B64_WS && src_len > 0) {
src++;
src_len--;
}
/* Trim newlines, spaces and tabs from the end of the line. */
while (src_len > 0) {
switch (src[src_len-1]) {
case ' ':
case '\t':
case '\r':
case '\n':
src_len--;
continue;
}
break;
/* strip off stuff at the end of the line
* ascii2bin values B64_WS, B64_EOLN, B64_EOLN and B64_EOF */
while (src_len > 3 && B64_NOT_BASE64(conv_ascii2bin(src[src_len - 1]))) {
src_len--;
}
size_t dst_len;
if (!EVP_DecodedLength(&dst_len, src_len) ||
dst_len > INT_MAX ||
!EVP_DecodeBase64(dst, &dst_len, dst_len, src, src_len)) {
if (!EVP_DecodedLength(&dst_len, src_len) || dst_len > INT_MAX) {
return -1;
}
if (!EVP_DecodeBase64(dst, &dst_len, dst_len, src, src_len)) {
return -1;
}
@@ -462,5 +456,23 @@ int EVP_DecodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) {
}
assert(dst_len <= INT_MAX);
return (int)dst_len;
return dst_len;
}
int EVP_EncodedLength(size_t *out_len, size_t len) {
if (len + 2 < len) {
return 0;
}
len += 2;
len /= 3;
if (((len << 2) >> 2) != len) {
return 0;
}
len <<= 2;
if (len + 1 < len) {
return 0;
}
len++;
*out_len = len;
return 1;
}
+85 -265
View File
@@ -15,293 +15,113 @@
#include <stdio.h>
#include <string.h>
#include <string>
#include <vector>
#include <gtest/gtest.h>
#include <openssl/base64.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include "../internal.h"
#include "../test/test_util.h"
enum encoding_relation {
// canonical indicates that the encoding is the expected encoding of the
// input.
canonical,
// valid indicates that the encoding is /a/ valid encoding of the input, but
// need not be the canonical one.
valid,
// invalid indicates that the encoded data is valid.
invalid,
};
struct TestVector {
enum encoding_relation relation;
const char *decoded;
const char *encoded;
};
// Test vectors from RFC 4648.
static const TestVector kTestVectors[] = {
{canonical, "", ""},
{canonical, "f", "Zg==\n"},
{canonical, "fo", "Zm8=\n"},
{canonical, "foo", "Zm9v\n"},
{canonical, "foob", "Zm9vYg==\n"},
{canonical, "fooba", "Zm9vYmE=\n"},
{canonical, "foobar", "Zm9vYmFy\n"},
{valid, "foobar", "Zm9vYmFy\n\n"},
{valid, "foobar", " Zm9vYmFy\n\n"},
{valid, "foobar", " Z m 9 v Y m F y\n\n"},
{invalid, "", "Zm9vYmFy=\n"},
{invalid, "", "Zm9vYmFy==\n"},
{invalid, "", "Zm9vYmFy===\n"},
{invalid, "", "Z"},
{invalid, "", "Z\n"},
{invalid, "", "ab!c"},
{invalid, "", "ab=c"},
{invalid, "", "abc"},
{canonical, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA==\n"},
{valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA\n==\n"},
{valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA=\n=\n"},
{invalid, "",
"eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA=\n==\n"},
{canonical, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4\neHh4eHh"
"4eHh4eHh4\n"},
{canonical,
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4\neHh4eHh"
"4eHh4eHh4eHh4eA==\n"},
{valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh\n4eHh4eHh"
"4eHh4eHh4eHh4eA==\n"},
{valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4e"
"Hh4eHh4eHh4eA==\n"},
{invalid, "",
"eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA=="
"\neHh4eHh4eHh4eHh4eHh4eHh4\n"},
// A '-' has traditionally been treated as the end of the data by OpenSSL
// and anything following would be ignored. BoringSSL does not accept this
// non-standard extension.
{invalid, "", "Zm9vYmFy-anythinggoes"},
{invalid, "", "Zm9vYmFy\n-anythinggoes"},
// CVE-2015-0292
{invalid, "",
"ZW5jb2RlIG1lCg==========================================================="
"=======\n"},
{ "", "" },
{ "f" , "Zg==" },
{ "fo", "Zm8=" },
{ "foo", "Zm9v" },
{ "foob", "Zm9vYg==" },
{ "fooba", "Zm9vYmE=" },
{ "foobar", "Zm9vYmFy" },
};
class Base64Test : public testing::TestWithParam<TestVector> {};
static const size_t kNumTests = sizeof(kTestVectors) / sizeof(kTestVectors[0]);
INSTANTIATE_TEST_CASE_P(, Base64Test, testing::ValuesIn(kTestVectors));
// RemoveNewlines returns a copy of |in| with all '\n' characters removed.
static std::string RemoveNewlines(const char *in) {
std::string ret;
const size_t in_len = strlen(in);
for (size_t i = 0; i < in_len; i++) {
if (in[i] != '\n') {
ret.push_back(in[i]);
static bool TestEncode() {
for (size_t i = 0; i < kNumTests; i++) {
const TestVector *t = &kTestVectors[i];
uint8_t out[9];
size_t len = EVP_EncodeBlock(out, (const uint8_t*)t->decoded,
strlen(t->decoded));
if (len != strlen(t->encoded) ||
memcmp(out, t->encoded, len) != 0) {
fprintf(stderr, "encode(\"%s\") = \"%.*s\", want \"%s\"\n",
t->decoded, (int)len, (const char*)out, t->encoded);
return false;
}
}
return ret;
return true;
}
TEST_P(Base64Test, EncodeBlock) {
const TestVector &t = GetParam();
if (t.relation != canonical) {
return;
}
const size_t decoded_len = strlen(t.decoded);
size_t max_encoded_len;
ASSERT_TRUE(EVP_EncodedLength(&max_encoded_len, decoded_len));
std::vector<uint8_t> out_vec(max_encoded_len);
uint8_t *out = out_vec.data();
size_t len = EVP_EncodeBlock(out, (const uint8_t *)t.decoded, decoded_len);
std::string encoded(RemoveNewlines(t.encoded));
EXPECT_EQ(Bytes(encoded), Bytes(out, len));
}
TEST_P(Base64Test, DecodeBase64) {
const TestVector &t = GetParam();
if (t.relation == valid) {
// The non-canonical encodings will generally have odd whitespace etc
// that |EVP_DecodeBase64| will reject.
return;
}
const std::string encoded(RemoveNewlines(t.encoded));
std::vector<uint8_t> out_vec(encoded.size());
uint8_t *out = out_vec.data();
static bool TestDecode() {
uint8_t out[6];
size_t len;
int ok = EVP_DecodeBase64(out, &len, out_vec.size(),
(const uint8_t *)encoded.data(), encoded.size());
if (t.relation == invalid) {
EXPECT_FALSE(ok);
} else if (t.relation == canonical) {
ASSERT_TRUE(ok);
EXPECT_EQ(Bytes(t.decoded), Bytes(out, len));
}
}
TEST_P(Base64Test, DecodeBlock) {
const TestVector &t = GetParam();
if (t.relation != canonical) {
return;
}
std::string encoded(RemoveNewlines(t.encoded));
std::vector<uint8_t> out_vec(encoded.size());
uint8_t *out = out_vec.data();
// Test that the padding behavior of the deprecated API is preserved.
int ret =
EVP_DecodeBlock(out, (const uint8_t *)encoded.data(), encoded.size());
ASSERT_GE(ret, 0);
// EVP_DecodeBlock should ignore padding.
ASSERT_EQ(0, ret % 3);
size_t expected_len = strlen(t.decoded);
if (expected_len % 3 != 0) {
ret -= 3 - (expected_len % 3);
}
EXPECT_EQ(Bytes(t.decoded), Bytes(out, static_cast<size_t>(ret)));
}
TEST_P(Base64Test, EncodeDecode) {
const TestVector &t = GetParam();
EVP_ENCODE_CTX ctx;
const size_t decoded_len = strlen(t.decoded);
if (t.relation == canonical) {
size_t max_encoded_len;
ASSERT_TRUE(EVP_EncodedLength(&max_encoded_len, decoded_len));
// EVP_EncodeUpdate will output new lines every 64 bytes of output so we
// need slightly more than |EVP_EncodedLength| returns. */
max_encoded_len += (max_encoded_len + 63) >> 6;
std::vector<uint8_t> out_vec(max_encoded_len);
uint8_t *out = out_vec.data();
EVP_EncodeInit(&ctx);
int out_len;
EVP_EncodeUpdate(&ctx, out, &out_len,
reinterpret_cast<const uint8_t *>(t.decoded),
decoded_len);
size_t total = out_len;
EVP_EncodeFinal(&ctx, out + total, &out_len);
total += out_len;
EXPECT_EQ(Bytes(t.encoded), Bytes(out, total));
}
std::vector<uint8_t> out_vec(strlen(t.encoded));
uint8_t *out = out_vec.data();
EVP_DecodeInit(&ctx);
int out_len;
size_t total = 0;
int ret = EVP_DecodeUpdate(&ctx, out, &out_len,
reinterpret_cast<const uint8_t *>(t.encoded),
strlen(t.encoded));
if (ret != -1) {
total = out_len;
ret = EVP_DecodeFinal(&ctx, out + total, &out_len);
total += out_len;
}
switch (t.relation) {
case canonical:
case valid:
ASSERT_NE(-1, ret);
EXPECT_EQ(Bytes(t.decoded), Bytes(out, total));
break;
case invalid:
EXPECT_EQ(-1, ret);
break;
}
}
TEST_P(Base64Test, DecodeUpdateStreaming) {
const TestVector &t = GetParam();
if (t.relation == invalid) {
return;
}
const size_t encoded_len = strlen(t.encoded);
std::vector<uint8_t> out(encoded_len);
for (size_t chunk_size = 1; chunk_size <= encoded_len; chunk_size++) {
SCOPED_TRACE(chunk_size);
size_t out_len = 0;
EVP_ENCODE_CTX ctx;
EVP_DecodeInit(&ctx);
for (size_t i = 0; i < encoded_len;) {
size_t todo = encoded_len - i;
if (todo > chunk_size) {
todo = chunk_size;
}
int bytes_written;
int ret = EVP_DecodeUpdate(
&ctx, out.data() + out_len, &bytes_written,
reinterpret_cast<const uint8_t *>(t.encoded + i), todo);
i += todo;
switch (ret) {
case -1:
FAIL() << "EVP_DecodeUpdate failed";
case 0:
out_len += bytes_written;
if (i == encoded_len ||
(i + 1 == encoded_len && t.encoded[i] == '\n') ||
/* If there was an '-' in the input (which means “EOF”) then
* this loop will continue to test that |EVP_DecodeUpdate| will
* ignore the remainder of the input. */
strchr(t.encoded, '-') != nullptr) {
break;
}
FAIL()
<< "EVP_DecodeUpdate returned zero before end of encoded data.";
case 1:
out_len += bytes_written;
break;
default:
FAIL() << "Invalid return value " << ret;
}
for (size_t i = 0; i < kNumTests; i++) {
// Test the normal API.
const TestVector *t = &kTestVectors[i];
size_t expected_len = strlen(t->decoded);
if (!EVP_DecodeBase64(out, &len, sizeof(out),
(const uint8_t*)t->encoded, strlen(t->encoded))) {
fprintf(stderr, "decode(\"%s\") failed\n", t->encoded);
return false;
}
if (len != strlen(t->decoded) ||
memcmp(out, t->decoded, len) != 0) {
fprintf(stderr, "decode(\"%s\") = \"%.*s\", want \"%s\"\n",
t->encoded, (int)len, (const char*)out, t->decoded);
return false;
}
int bytes_written;
int ret = EVP_DecodeFinal(&ctx, out.data() + out_len, &bytes_written);
ASSERT_NE(ret, -1);
out_len += bytes_written;
EXPECT_EQ(Bytes(t.decoded), Bytes(out.data(), out_len));
// Test that the padding behavior of the deprecated API is preserved.
int ret = EVP_DecodeBlock(out, (const uint8_t*)t->encoded,
strlen(t->encoded));
if (ret < 0) {
fprintf(stderr, "decode(\"%s\") failed\n", t->encoded);
return false;
}
if (ret % 3 != 0) {
fprintf(stderr, "EVP_DecodeBlock did not ignore padding\n");
return false;
}
if (expected_len % 3 != 0) {
ret -= 3 - (expected_len % 3);
}
if (static_cast<size_t>(ret) != strlen(t->decoded) ||
memcmp(out, t->decoded, ret) != 0) {
fprintf(stderr, "decode(\"%s\") = \"%.*s\", want \"%s\"\n",
t->encoded, ret, (const char*)out, t->decoded);
return false;
}
}
if (EVP_DecodeBase64(out, &len, sizeof(out), (const uint8_t*)"a!bc", 4)) {
fprintf(stderr, "Failed to reject invalid characters in the middle.\n");
return false;
}
if (EVP_DecodeBase64(out, &len, sizeof(out), (const uint8_t*)"a=bc", 4)) {
fprintf(stderr, "Failed to reject invalid characters in the middle.\n");
return false;
}
if (EVP_DecodeBase64(out, &len, sizeof(out), (const uint8_t*)"abc", 4)) {
fprintf(stderr, "Failed to reject invalid input length.\n");
return false;
}
return true;
}
int main(void) {
CRYPTO_library_init();
if (!TestEncode() ||
!TestDecode()) {
return 1;
}
printf("PASS\n");
return 0;
}
+15
View File
@@ -7,6 +7,7 @@ add_library(
bio.c
bio_mem.c
buffer.c
connect.c
fd.c
file.c
@@ -16,3 +17,17 @@ add_library(
socket.c
socket_helper.c
)
add_executable(
bio_test
bio_test.cc
$<TARGET_OBJECTS:test_support>
)
target_link_libraries(bio_test crypto)
if (WIN32)
target_link_libraries(bio_test ws2_32)
endif()
add_dependencies(all_tests bio_test)
+32 -36
View File
@@ -68,6 +68,25 @@
#include "../internal.h"
/* BIO_set initialises a BIO structure to have the given type and sets the
* reference count to one. It returns one on success or zero on error. */
static int bio_set(BIO *bio, const BIO_METHOD *method) {
/* This function can be called with a stack allocated |BIO| so we have to
* assume that the contents of |BIO| are arbitary. This also means that it'll
* leak memory if you call |BIO_set| twice on the same BIO. */
memset(bio, 0, sizeof(BIO));
bio->method = method;
bio->shutdown = 1;
bio->references = 1;
if (method->create != NULL && !method->create(bio)) {
return 0;
}
return 1;
}
BIO *BIO_new(const BIO_METHOD *method) {
BIO *ret = OPENSSL_malloc(sizeof(BIO));
if (ret == NULL) {
@@ -75,14 +94,9 @@ BIO *BIO_new(const BIO_METHOD *method) {
return NULL;
}
OPENSSL_memset(ret, 0, sizeof(BIO));
ret->method = method;
ret->shutdown = 1;
ret->references = 1;
if (method->create != NULL && !method->create(ret)) {
if (!bio_set(ret, method)) {
OPENSSL_free(ret);
return NULL;
ret = NULL;
}
return ret;
@@ -114,9 +128,9 @@ int BIO_free(BIO *bio) {
return 1;
}
int BIO_up_ref(BIO *bio) {
BIO *BIO_up_ref(BIO *bio) {
CRYPTO_refcount_inc(&bio->references);
return 1;
return bio;
}
void BIO_vfree(BIO *bio) {
@@ -243,10 +257,6 @@ int BIO_reset(BIO *bio) {
return BIO_ctrl(bio, BIO_CTRL_RESET, 0, NULL);
}
int BIO_eof(BIO *bio) {
return BIO_ctrl(bio, BIO_CTRL_EOF, 0, NULL);
}
void BIO_set_flags(BIO *bio, int flags) {
bio->flags |= flags;
}
@@ -336,13 +346,7 @@ long BIO_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) {
}
size_t BIO_pending(const BIO *bio) {
const long r = BIO_ctrl((BIO *) bio, BIO_CTRL_PENDING, 0, NULL);
assert(r >= 0);
if (r < 0) {
return 0;
}
return r;
return BIO_ctrl((BIO *) bio, BIO_CTRL_PENDING, 0, NULL);
}
size_t BIO_ctrl_pending(const BIO *bio) {
@@ -350,13 +354,7 @@ size_t BIO_ctrl_pending(const BIO *bio) {
}
size_t BIO_wpending(const BIO *bio) {
const long r = BIO_ctrl((BIO *) bio, BIO_CTRL_WPENDING, 0, NULL);
assert(r >= 0);
if (r < 0) {
return 0;
}
return r;
return BIO_ctrl((BIO *) bio, BIO_CTRL_WPENDING, 0, NULL);
}
int BIO_set_close(BIO *bio, int close_flag) {
@@ -460,10 +458,14 @@ static int print_bio(const char *str, size_t len, void *bio) {
return BIO_write((BIO *)bio, str, len);
}
void ERR_print_errors(BIO *bio) {
void BIO_print_errors(BIO *bio) {
ERR_print_errors_cb(print_bio, bio);
}
void ERR_print_errors(BIO *bio) {
BIO_print_errors(bio);
}
/* bio_read_all reads everything from |bio| and prepends |prefix| to it. On
* success, |*out| is set to an allocated buffer (which should be freed with
* |OPENSSL_free|), |*out_len| is set to its length and one is returned. The
@@ -488,7 +490,7 @@ static int bio_read_all(BIO *bio, uint8_t **out, size_t *out_len,
if (*out == NULL) {
return 0;
}
OPENSSL_memcpy(*out, prefix, prefix_len);
memcpy(*out, prefix, prefix_len);
size_t done = prefix_len;
for (;;) {
@@ -595,7 +597,7 @@ int BIO_read_asn1(BIO *bio, uint8_t **out, size_t *out_len, size_t max_len) {
if (*out == NULL) {
return 0;
}
OPENSSL_memcpy(*out, header, header_len);
memcpy(*out, header, header_len);
if (BIO_read(bio, (*out) + header_len, len - header_len) !=
(int) (len - header_len)) {
OPENSSL_free(*out);
@@ -604,9 +606,3 @@ int BIO_read_asn1(BIO *bio, uint8_t **out, size_t *out_len, size_t max_len) {
return 1;
}
void BIO_set_retry_special(BIO *bio) {
bio->flags |= BIO_FLAGS_READ | BIO_FLAGS_IO_SPECIAL;
}
int BIO_set_write_buffer_size(BIO *bio, int buffer_size) { return 0; }
+10 -12
View File
@@ -63,8 +63,6 @@
#include <openssl/err.h>
#include <openssl/mem.h>
#include "../internal.h"
BIO *BIO_new_mem_buf(const void *buf, int len) {
BIO *ret;
@@ -146,12 +144,12 @@ static int mem_read(BIO *bio, char *out, int outl) {
}
if (ret > 0) {
OPENSSL_memcpy(out, b->data, ret);
memcpy(out, b->data, ret);
b->length -= ret;
if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
b->data += ret;
} else {
OPENSSL_memmove(b->data, &b->data[ret], b->length);
memmove(b->data, &b->data[ret], b->length);
}
} else if (b->length == 0) {
ret = bio->num;
@@ -182,13 +180,17 @@ static int mem_write(BIO *bio, const char *in, int inl) {
if (BUF_MEM_grow_clean(b, blen + inl) != ((size_t) blen) + inl) {
goto err;
}
OPENSSL_memcpy(&b->data[blen], in, inl);
memcpy(&b->data[blen], in, inl);
ret = inl;
err:
return ret;
}
static int mem_puts(BIO *bp, const char *str) {
return mem_write(bp, str, strlen(str));
}
static int mem_gets(BIO *bio, char *buf, int size) {
int i, j;
char *p;
@@ -238,7 +240,7 @@ static long mem_ctrl(BIO *bio, int cmd, long num, void *ptr) {
b->data -= b->max - b->length;
b->length = b->max;
} else {
OPENSSL_memset(b->data, 0, b->max);
memset(b->data, 0, b->max);
b->length = 0;
}
}
@@ -291,12 +293,8 @@ static long mem_ctrl(BIO *bio, int cmd, long num, void *ptr) {
}
static const BIO_METHOD mem_method = {
BIO_TYPE_MEM, "memory buffer",
mem_write, mem_read,
NULL /* puts */, mem_gets,
mem_ctrl, mem_new,
mem_free, NULL /* callback_ctrl */,
};
BIO_TYPE_MEM, "memory buffer", mem_write, mem_read, mem_puts,
mem_gets, mem_ctrl, mem_new, mem_free, NULL, };
const BIO_METHOD *BIO_s_mem(void) { return &mem_method; }
+350 -222
View File
@@ -16,18 +16,7 @@
#define _POSIX_C_SOURCE 201410L
#endif
#include <algorithm>
#include <string>
#include <gtest/gtest.h>
#include <openssl/bio.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include "../internal.h"
#include "../test/test_util.h"
#include <openssl/base.h>
#if !defined(OPENSSL_WINDOWS)
#include <arpa/inet.h>
@@ -38,27 +27,39 @@
#include <unistd.h>
#else
#include <io.h>
OPENSSL_MSVC_PRAGMA(warning(push, 3))
#pragma warning(push, 3)
#include <winsock2.h>
#include <ws2tcpip.h>
OPENSSL_MSVC_PRAGMA(warning(pop))
#pragma warning(pop)
#endif
#include <openssl/bio.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include <algorithm>
#include "../test/scoped_types.h"
#if !defined(OPENSSL_WINDOWS)
static int closesocket(int sock) { return close(sock); }
static std::string LastSocketError() { return strerror(errno); }
static int closesocket(int sock) {
return close(sock);
}
static void PrintSocketError(const char *func) {
perror(func);
}
#else
static std::string LastSocketError() {
char buf[DECIMAL_SIZE(int) + 1];
BIO_snprintf(buf, sizeof(buf), "%d", WSAGetLastError());
return buf;
static void PrintSocketError(const char *func) {
fprintf(stderr, "%s: %d\n", func, WSAGetLastError());
}
#endif
class ScopedSocket {
public:
explicit ScopedSocket(int sock) : sock_(sock) {}
ScopedSocket(int sock) : sock_(sock) {}
~ScopedSocket() {
closesocket(sock_);
}
@@ -67,246 +68,373 @@ class ScopedSocket {
const int sock_;
};
TEST(BIOTest, SocketConnect) {
static bool TestSocketConnect() {
static const char kTestMessage[] = "test";
// Set up a listening socket on localhost.
int listening_sock = socket(AF_INET, SOCK_STREAM, 0);
ASSERT_NE(-1, listening_sock) << LastSocketError();
if (listening_sock == -1) {
PrintSocketError("socket");
return false;
}
ScopedSocket listening_sock_closer(listening_sock);
struct sockaddr_in sin;
OPENSSL_memset(&sin, 0, sizeof(sin));
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
ASSERT_EQ(1, inet_pton(AF_INET, "127.0.0.1", &sin.sin_addr))
<< LastSocketError();
ASSERT_EQ(0, bind(listening_sock, (struct sockaddr *)&sin, sizeof(sin)))
<< LastSocketError();
ASSERT_EQ(0, listen(listening_sock, 1)) << LastSocketError();
if (!inet_pton(AF_INET, "127.0.0.1", &sin.sin_addr)) {
PrintSocketError("inet_pton");
return false;
}
if (bind(listening_sock, (struct sockaddr *)&sin, sizeof(sin)) != 0) {
PrintSocketError("bind");
return false;
}
if (listen(listening_sock, 1)) {
PrintSocketError("listen");
return false;
}
socklen_t sockaddr_len = sizeof(sin);
ASSERT_EQ(0,
getsockname(listening_sock, (struct sockaddr *)&sin, &sockaddr_len))
<< LastSocketError();
// The Android NDK, contrary to POSIX, makes |socklen_t| signed.
ASSERT_EQ(sizeof(sin), static_cast<size_t>(sockaddr_len));
if (getsockname(listening_sock, (struct sockaddr *)&sin, &sockaddr_len) ||
sockaddr_len != sizeof(sin)) {
PrintSocketError("getsockname");
return false;
}
// Connect to it with a connect BIO.
char hostname[80];
BIO_snprintf(hostname, sizeof(hostname), "%s:%d", "127.0.0.1",
ntohs(sin.sin_port));
bssl::UniquePtr<BIO> bio(BIO_new_connect(hostname));
ASSERT_TRUE(bio);
ScopedBIO bio(BIO_new_connect(hostname));
if (!bio) {
fprintf(stderr, "BIO_new_connect failed.\n");
return false;
}
// Write a test message to the BIO.
ASSERT_EQ(static_cast<int>(sizeof(kTestMessage)),
BIO_write(bio.get(), kTestMessage, sizeof(kTestMessage)));
if (BIO_write(bio.get(), kTestMessage, sizeof(kTestMessage)) !=
sizeof(kTestMessage)) {
fprintf(stderr, "BIO_write failed.\n");
ERR_print_errors_fp(stderr);
return false;
}
// Accept the socket.
int sock = accept(listening_sock, (struct sockaddr *) &sin, &sockaddr_len);
ASSERT_NE(-1, sock) << LastSocketError();
if (sock == -1) {
PrintSocketError("accept");
return false;
}
ScopedSocket sock_closer(sock);
// Check the same message is read back out.
char buf[sizeof(kTestMessage)];
ASSERT_EQ(static_cast<int>(sizeof(kTestMessage)),
recv(sock, buf, sizeof(buf), 0))
<< LastSocketError();
EXPECT_EQ(Bytes(kTestMessage, sizeof(kTestMessage)), Bytes(buf, sizeof(buf)));
char buf[5];
if (recv(sock, buf, sizeof(buf), 0) != sizeof(kTestMessage)) {
PrintSocketError("read");
return false;
}
if (memcmp(buf, kTestMessage, sizeof(kTestMessage))) {
return false;
}
return true;
}
TEST(BIOTest, Printf) {
// BioReadZeroCopyWrapper is a wrapper around the zero-copy APIs to make
// testing easier.
static size_t BioReadZeroCopyWrapper(BIO *bio, uint8_t *data, size_t len) {
uint8_t *read_buf;
size_t read_buf_offset;
size_t available_bytes;
size_t len_read = 0;
do {
if (!BIO_zero_copy_get_read_buf(bio, &read_buf, &read_buf_offset,
&available_bytes)) {
return 0;
}
available_bytes = std::min(available_bytes, len - len_read);
memmove(data + len_read, read_buf + read_buf_offset, available_bytes);
BIO_zero_copy_get_read_buf_done(bio, available_bytes);
len_read += available_bytes;
} while (len - len_read > 0 && available_bytes > 0);
return len_read;
}
// BioWriteZeroCopyWrapper is a wrapper around the zero-copy APIs to make
// testing easier.
static size_t BioWriteZeroCopyWrapper(BIO *bio, const uint8_t *data,
size_t len) {
uint8_t *write_buf;
size_t write_buf_offset;
size_t available_bytes;
size_t len_written = 0;
do {
if (!BIO_zero_copy_get_write_buf(bio, &write_buf, &write_buf_offset,
&available_bytes)) {
return 0;
}
available_bytes = std::min(available_bytes, len - len_written);
memmove(write_buf + write_buf_offset, data + len_written, available_bytes);
BIO_zero_copy_get_write_buf_done(bio, available_bytes);
len_written += available_bytes;
} while (len - len_written > 0 && available_bytes > 0);
return len_written;
}
static bool TestZeroCopyBioPairs() {
// Test read and write, especially triggering the ring buffer wrap-around.
uint8_t bio1_application_send_buffer[1024];
uint8_t bio2_application_recv_buffer[1024];
const size_t kLengths[] = {254, 255, 256, 257, 510, 511, 512, 513};
// These trigger ring buffer wrap around.
const size_t kPartialLengths[] = {0, 1, 2, 3, 128, 255, 256, 257, 511, 512};
static const size_t kBufferSize = 512;
srand(1);
for (size_t i = 0; i < sizeof(bio1_application_send_buffer); i++) {
bio1_application_send_buffer[i] = rand() & 255;
}
// Transfer bytes from bio1_application_send_buffer to
// bio2_application_recv_buffer in various ways.
for (size_t i = 0; i < sizeof(kLengths) / sizeof(kLengths[0]); i++) {
for (size_t j = 0; j < sizeof(kPartialLengths) / sizeof(kPartialLengths[0]);
j++) {
size_t total_write = 0;
size_t total_read = 0;
BIO *bio1, *bio2;
if (!BIO_new_bio_pair(&bio1, kBufferSize, &bio2, kBufferSize)) {
return false;
}
ScopedBIO bio1_scoper(bio1);
ScopedBIO bio2_scoper(bio2);
total_write += BioWriteZeroCopyWrapper(
bio1, bio1_application_send_buffer, kLengths[i]);
// This tests interleaved read/write calls. Do a read between zero copy
// write calls.
uint8_t *write_buf;
size_t write_buf_offset;
size_t available_bytes;
if (!BIO_zero_copy_get_write_buf(bio1, &write_buf, &write_buf_offset,
&available_bytes)) {
return false;
}
// Free kPartialLengths[j] bytes in the beginning of bio1 write buffer.
// This enables ring buffer wrap around for the next write.
total_read += BIO_read(bio2, bio2_application_recv_buffer + total_read,
kPartialLengths[j]);
size_t interleaved_write_len = std::min(kPartialLengths[j],
available_bytes);
// Write the data for the interleaved write call. If the buffer becomes
// empty after a read, the write offset is normally set to 0. Check that
// this does not happen for interleaved read/write and that
// |write_buf_offset| is still valid.
memcpy(write_buf + write_buf_offset,
bio1_application_send_buffer + total_write, interleaved_write_len);
if (BIO_zero_copy_get_write_buf_done(bio1, interleaved_write_len)) {
total_write += interleaved_write_len;
}
// Do another write in case |write_buf_offset| was wrapped.
total_write += BioWriteZeroCopyWrapper(
bio1, bio1_application_send_buffer + total_write,
kPartialLengths[j] - interleaved_write_len);
// Drain the rest.
size_t bytes_left = BIO_pending(bio2);
total_read += BioReadZeroCopyWrapper(
bio2, bio2_application_recv_buffer + total_read, bytes_left);
if (total_read != total_write) {
fprintf(stderr, "Lengths not equal in round (%u, %u)\n", (unsigned)i,
(unsigned)j);
return false;
}
if (total_read > kLengths[i] + kPartialLengths[j]) {
fprintf(stderr, "Bad lengths in round (%u, %u)\n", (unsigned)i,
(unsigned)j);
return false;
}
if (memcmp(bio1_application_send_buffer, bio2_application_recv_buffer,
total_read) != 0) {
fprintf(stderr, "Buffers not equal in round (%u, %u)\n", (unsigned)i,
(unsigned)j);
return false;
}
}
}
return true;
}
static bool TestPrintf() {
// Test a short output, a very long one, and various sizes around
// 256 (the size of the buffer) to ensure edge cases are correct.
static const size_t kLengths[] = {5, 250, 251, 252, 253, 254, 1023};
static const size_t kLengths[] = { 5, 250, 251, 252, 253, 254, 1023 };
bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
ASSERT_TRUE(bio);
ScopedBIO bio(BIO_new(BIO_s_mem()));
if (!bio) {
fprintf(stderr, "BIO_new failed\n");
return false;
}
for (size_t length : kLengths) {
SCOPED_TRACE(length);
std::string in(length, 'a');
int ret = BIO_printf(bio.get(), "test %s", in.c_str());
ASSERT_GE(ret, 0);
EXPECT_EQ(5 + length, static_cast<size_t>(ret));
for (size_t i = 0; i < sizeof(kLengths) / sizeof(kLengths[0]); i++) {
char string[1024];
if (kLengths[i] >= sizeof(string)) {
fprintf(stderr, "Bad test string length\n");
return false;
}
memset(string, 'a', sizeof(string));
string[kLengths[i]] = '\0';
int ret = BIO_printf(bio.get(), "test %s", string);
if (ret < 0 || static_cast<size_t>(ret) != 5 + kLengths[i]) {
fprintf(stderr, "BIO_printf failed: %d\n", ret);
return false;
}
const uint8_t *contents;
size_t len;
ASSERT_TRUE(BIO_mem_contents(bio.get(), &contents, &len));
EXPECT_EQ("test " + in,
std::string(reinterpret_cast<const char *>(contents), len));
if (!BIO_mem_contents(bio.get(), &contents, &len)) {
fprintf(stderr, "BIO_mem_contents failed\n");
return false;
}
if (len != 5 + kLengths[i] ||
strncmp((const char *)contents, "test ", 5) != 0 ||
strncmp((const char *)contents + 5, string, kLengths[i]) != 0) {
fprintf(stderr, "Contents did not match: %.*s\n", (int)len, contents);
return false;
}
ASSERT_TRUE(BIO_reset(bio.get()));
if (!BIO_reset(bio.get())) {
fprintf(stderr, "BIO_reset failed\n");
return false;
}
}
return true;
}
static const size_t kLargeASN1PayloadLen = 8000;
struct ASN1TestParam {
bool should_succeed;
std::vector<uint8_t> input;
// suffix_len is the number of zeros to append to |input|.
size_t suffix_len;
// expected_len, if |should_succeed| is true, is the expected length of the
// ASN.1 element.
size_t expected_len;
size_t max_len;
} kASN1TestParams[] = {
{true, {0x30, 2, 1, 2, 0, 0}, 0, 4, 100},
{false /* truncated */, {0x30, 3, 1, 2}, 0, 0, 100},
{false /* should be short len */, {0x30, 0x81, 1, 1}, 0, 0, 100},
{false /* zero padded */, {0x30, 0x82, 0, 1, 1}, 0, 0, 100},
// Test a large payload.
{true,
{0x30, 0x82, kLargeASN1PayloadLen >> 8, kLargeASN1PayloadLen & 0xff},
kLargeASN1PayloadLen,
4 + kLargeASN1PayloadLen,
kLargeASN1PayloadLen * 2},
{false /* max_len too short */,
{0x30, 0x82, kLargeASN1PayloadLen >> 8, kLargeASN1PayloadLen & 0xff},
kLargeASN1PayloadLen,
4 + kLargeASN1PayloadLen,
3 + kLargeASN1PayloadLen},
// Test an indefinite-length input.
{true,
{0x30, 0x80},
kLargeASN1PayloadLen + 2,
2 + kLargeASN1PayloadLen + 2,
kLargeASN1PayloadLen * 2},
{false /* max_len too short */,
{0x30, 0x80},
kLargeASN1PayloadLen + 2,
2 + kLargeASN1PayloadLen + 2,
2 + kLargeASN1PayloadLen + 1},
};
class BIOASN1Test : public testing::TestWithParam<ASN1TestParam> {};
TEST_P(BIOASN1Test, ReadASN1) {
const ASN1TestParam& param = GetParam();
std::vector<uint8_t> input = param.input;
input.resize(input.size() + param.suffix_len, 0);
bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(input.data(), input.size()));
ASSERT_TRUE(bio);
static bool ReadASN1(bool should_succeed, const uint8_t *data, size_t data_len,
size_t expected_len, size_t max_len) {
ScopedBIO bio(BIO_new_mem_buf(data, data_len));
uint8_t *out;
size_t out_len;
int ok = BIO_read_asn1(bio.get(), &out, &out_len, param.max_len);
int ok = BIO_read_asn1(bio.get(), &out, &out_len, max_len);
if (!ok) {
out = nullptr;
}
bssl::UniquePtr<uint8_t> out_storage(out);
ScopedOpenSSLBytes out_storage(out);
ASSERT_EQ(param.should_succeed, (ok == 1));
if (param.should_succeed) {
EXPECT_EQ(Bytes(input.data(), param.expected_len), Bytes(out, out_len));
}
}
INSTANTIATE_TEST_CASE_P(, BIOASN1Test, testing::ValuesIn(kASN1TestParams));
// Run through the tests twice, swapping |bio1| and |bio2|, for symmetry.
class BIOPairTest : public testing::TestWithParam<bool> {};
TEST_P(BIOPairTest, TestPair) {
BIO *bio1, *bio2;
ASSERT_TRUE(BIO_new_bio_pair(&bio1, 10, &bio2, 10));
bssl::UniquePtr<BIO> free_bio1(bio1), free_bio2(bio2);
if (GetParam()) {
std::swap(bio1, bio2);
if (should_succeed != (ok == 1)) {
return false;
}
// Check initial states.
EXPECT_EQ(10u, BIO_ctrl_get_write_guarantee(bio1));
EXPECT_EQ(0u, BIO_ctrl_get_read_request(bio1));
if (should_succeed &&
(out_len != expected_len || memcmp(data, out, expected_len) != 0)) {
return false;
}
// Data written in one end may be read out the other.
uint8_t buf[20];
EXPECT_EQ(5, BIO_write(bio1, "12345", 5));
EXPECT_EQ(5u, BIO_ctrl_get_write_guarantee(bio1));
ASSERT_EQ(5, BIO_read(bio2, buf, sizeof(buf)));
EXPECT_EQ(Bytes("12345"), Bytes(buf, 5));
EXPECT_EQ(10u, BIO_ctrl_get_write_guarantee(bio1));
// Attempting to write more than 10 bytes will write partially.
EXPECT_EQ(10, BIO_write(bio1, "1234567890___", 13));
EXPECT_EQ(0u, BIO_ctrl_get_write_guarantee(bio1));
EXPECT_EQ(-1, BIO_write(bio1, "z", 1));
EXPECT_TRUE(BIO_should_write(bio1));
ASSERT_EQ(10, BIO_read(bio2, buf, sizeof(buf)));
EXPECT_EQ(Bytes("1234567890"), Bytes(buf, 10));
EXPECT_EQ(10u, BIO_ctrl_get_write_guarantee(bio1));
// Unsuccessful reads update the read request.
EXPECT_EQ(-1, BIO_read(bio2, buf, 5));
EXPECT_TRUE(BIO_should_read(bio2));
EXPECT_EQ(5u, BIO_ctrl_get_read_request(bio1));
// The read request is clamped to the size of the buffer.
EXPECT_EQ(-1, BIO_read(bio2, buf, 20));
EXPECT_TRUE(BIO_should_read(bio2));
EXPECT_EQ(10u, BIO_ctrl_get_read_request(bio1));
// Data may be written and read in chunks.
EXPECT_EQ(5, BIO_write(bio1, "12345", 5));
EXPECT_EQ(5u, BIO_ctrl_get_write_guarantee(bio1));
EXPECT_EQ(5, BIO_write(bio1, "67890___", 8));
EXPECT_EQ(0u, BIO_ctrl_get_write_guarantee(bio1));
ASSERT_EQ(3, BIO_read(bio2, buf, 3));
EXPECT_EQ(Bytes("123"), Bytes(buf, 3));
EXPECT_EQ(3u, BIO_ctrl_get_write_guarantee(bio1));
ASSERT_EQ(7, BIO_read(bio2, buf, sizeof(buf)));
EXPECT_EQ(Bytes("4567890"), Bytes(buf, 7));
EXPECT_EQ(10u, BIO_ctrl_get_write_guarantee(bio1));
// Successful reads reset the read request.
EXPECT_EQ(0u, BIO_ctrl_get_read_request(bio1));
// Test writes and reads starting in the middle of the ring buffer and
// wrapping to front.
EXPECT_EQ(8, BIO_write(bio1, "abcdefgh", 8));
EXPECT_EQ(2u, BIO_ctrl_get_write_guarantee(bio1));
ASSERT_EQ(3, BIO_read(bio2, buf, 3));
EXPECT_EQ(Bytes("abc"), Bytes(buf, 3));
EXPECT_EQ(5u, BIO_ctrl_get_write_guarantee(bio1));
EXPECT_EQ(5, BIO_write(bio1, "ijklm___", 8));
EXPECT_EQ(0u, BIO_ctrl_get_write_guarantee(bio1));
ASSERT_EQ(10, BIO_read(bio2, buf, sizeof(buf)));
EXPECT_EQ(Bytes("defghijklm"), Bytes(buf, 10));
EXPECT_EQ(10u, BIO_ctrl_get_write_guarantee(bio1));
// Data may flow from both ends in parallel.
EXPECT_EQ(5, BIO_write(bio1, "12345", 5));
EXPECT_EQ(5, BIO_write(bio2, "67890", 5));
ASSERT_EQ(5, BIO_read(bio2, buf, sizeof(buf)));
EXPECT_EQ(Bytes("12345"), Bytes(buf, 5));
ASSERT_EQ(5, BIO_read(bio1, buf, sizeof(buf)));
EXPECT_EQ(Bytes("67890"), Bytes(buf, 5));
// Closing the write end causes an EOF on the read half, after draining.
EXPECT_EQ(5, BIO_write(bio1, "12345", 5));
EXPECT_TRUE(BIO_shutdown_wr(bio1));
ASSERT_EQ(5, BIO_read(bio2, buf, sizeof(buf)));
EXPECT_EQ(Bytes("12345"), Bytes(buf, 5));
EXPECT_EQ(0, BIO_read(bio2, buf, sizeof(buf)));
// A closed write end may not be written to.
EXPECT_EQ(0u, BIO_ctrl_get_write_guarantee(bio1));
EXPECT_EQ(-1, BIO_write(bio1, "_____", 5));
uint32_t err = ERR_get_error();
EXPECT_EQ(ERR_LIB_BIO, ERR_GET_LIB(err));
EXPECT_EQ(BIO_R_BROKEN_PIPE, ERR_GET_REASON(err));
// The other end is still functional.
EXPECT_EQ(5, BIO_write(bio2, "12345", 5));
ASSERT_EQ(5, BIO_read(bio1, buf, sizeof(buf)));
EXPECT_EQ(Bytes("12345"), Bytes(buf, 5));
return true;
}
INSTANTIATE_TEST_CASE_P(, BIOPairTest, testing::Values(false, true));
static bool TestASN1() {
static const uint8_t kData1[] = {0x30, 2, 1, 2, 0, 0};
static const uint8_t kData2[] = {0x30, 3, 1, 2}; /* truncated */
static const uint8_t kData3[] = {0x30, 0x81, 1, 1}; /* should be short len */
static const uint8_t kData4[] = {0x30, 0x82, 0, 1, 1}; /* zero padded. */
if (!ReadASN1(true, kData1, sizeof(kData1), 4, 100) ||
!ReadASN1(false, kData2, sizeof(kData2), 0, 100) ||
!ReadASN1(false, kData3, sizeof(kData3), 0, 100) ||
!ReadASN1(false, kData4, sizeof(kData4), 0, 100)) {
return false;
}
static const size_t kLargePayloadLen = 8000;
static const uint8_t kLargePrefix[] = {0x30, 0x82, kLargePayloadLen >> 8,
kLargePayloadLen & 0xff};
ScopedOpenSSLBytes large(reinterpret_cast<uint8_t *>(
OPENSSL_malloc(sizeof(kLargePrefix) + kLargePayloadLen)));
if (!large) {
return false;
}
memset(large.get() + sizeof(kLargePrefix), 0, kLargePayloadLen);
memcpy(large.get(), kLargePrefix, sizeof(kLargePrefix));
if (!ReadASN1(true, large.get(), sizeof(kLargePrefix) + kLargePayloadLen,
sizeof(kLargePrefix) + kLargePayloadLen,
kLargePayloadLen * 2)) {
fprintf(stderr, "Large payload test failed.\n");
return false;
}
if (!ReadASN1(false, large.get(), sizeof(kLargePrefix) + kLargePayloadLen,
sizeof(kLargePrefix) + kLargePayloadLen,
kLargePayloadLen - 1)) {
fprintf(stderr, "max_len test failed.\n");
return false;
}
static const uint8_t kIndefPrefix[] = {0x30, 0x80};
memcpy(large.get(), kIndefPrefix, sizeof(kIndefPrefix));
if (!ReadASN1(true, large.get(), sizeof(kLargePrefix) + kLargePayloadLen,
sizeof(kLargePrefix) + kLargePayloadLen,
kLargePayloadLen*2)) {
fprintf(stderr, "indefinite length test failed.\n");
return false;
}
if (!ReadASN1(false, large.get(), sizeof(kLargePrefix) + kLargePayloadLen,
sizeof(kLargePrefix) + kLargePayloadLen,
kLargePayloadLen-1)) {
fprintf(stderr, "indefinite length, max_len test failed.\n");
return false;
}
return true;
}
int main(void) {
CRYPTO_library_init();
#if defined(OPENSSL_WINDOWS)
// Initialize Winsock.
WORD wsa_version = MAKEWORD(2, 2);
WSADATA wsa_data;
int wsa_err = WSAStartup(wsa_version, &wsa_data);
if (wsa_err != 0) {
fprintf(stderr, "WSAStartup failed: %d\n", wsa_err);
return 1;
}
if (wsa_data.wVersion != wsa_version) {
fprintf(stderr, "Didn't get expected version: %x\n", wsa_data.wVersion);
return 1;
}
#endif
if (!TestSocketConnect() ||
!TestPrintf() ||
!TestZeroCopyBioPairs() ||
!TestASN1()) {
return 1;
}
printf("PASS\n");
return 0;
}
+496
View File
@@ -0,0 +1,496 @@
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.] */
#include <openssl/bio.h>
#include <string.h>
#include <openssl/buf.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#define DEFAULT_BUFFER_SIZE 4096
typedef struct bio_f_buffer_ctx_struct {
/* Buffers are setup like this:
*
* <---------------------- size ----------------------->
* +---------------------------------------------------+
* | consumed | remaining | free space |
* +---------------------------------------------------+
* <-- off --><------- len ------->
*/
int ibuf_size; /* how big is the input buffer */
int obuf_size; /* how big is the output buffer */
char *ibuf; /* the char array */
int ibuf_len; /* how many bytes are in it */
int ibuf_off; /* write/read offset */
char *obuf; /* the char array */
int obuf_len; /* how many bytes are in it */
int obuf_off; /* write/read offset */
} BIO_F_BUFFER_CTX;
static int buffer_new(BIO *bio) {
BIO_F_BUFFER_CTX *ctx;
ctx = OPENSSL_malloc(sizeof(BIO_F_BUFFER_CTX));
if (ctx == NULL) {
return 0;
}
memset(ctx, 0, sizeof(BIO_F_BUFFER_CTX));
ctx->ibuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE);
if (ctx->ibuf == NULL) {
goto err1;
}
ctx->obuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE);
if (ctx->obuf == NULL) {
goto err2;
}
ctx->ibuf_size = DEFAULT_BUFFER_SIZE;
ctx->obuf_size = DEFAULT_BUFFER_SIZE;
bio->init = 1;
bio->ptr = (char *)ctx;
return 1;
err2:
OPENSSL_free(ctx->ibuf);
err1:
OPENSSL_free(ctx);
return 0;
}
static int buffer_free(BIO *bio) {
BIO_F_BUFFER_CTX *ctx;
if (bio == NULL || bio->ptr == NULL) {
return 0;
}
ctx = (BIO_F_BUFFER_CTX *)bio->ptr;
OPENSSL_free(ctx->ibuf);
OPENSSL_free(ctx->obuf);
OPENSSL_free(bio->ptr);
bio->ptr = NULL;
bio->init = 0;
bio->flags = 0;
return 1;
}
static int buffer_read(BIO *bio, char *out, int outl) {
int i, num = 0;
BIO_F_BUFFER_CTX *ctx;
ctx = (BIO_F_BUFFER_CTX *)bio->ptr;
if (ctx == NULL || bio->next_bio == NULL) {
return 0;
}
num = 0;
BIO_clear_retry_flags(bio);
for (;;) {
i = ctx->ibuf_len;
/* If there is stuff left over, grab it */
if (i != 0) {
if (i > outl) {
i = outl;
}
memcpy(out, &ctx->ibuf[ctx->ibuf_off], i);
ctx->ibuf_off += i;
ctx->ibuf_len -= i;
num += i;
if (outl == i) {
return num;
}
outl -= i;
out += i;
}
/* We may have done a partial read. Try to do more. We have nothing in the
* buffer. If we get an error and have read some data, just return it and
* let them retry to get the error again. Copy direct to parent address
* space */
if (outl > ctx->ibuf_size) {
for (;;) {
i = BIO_read(bio->next_bio, out, outl);
if (i <= 0) {
BIO_copy_next_retry(bio);
if (i < 0) {
return (num > 0) ? num : i;
}
return num;
}
num += i;
if (outl == i) {
return num;
}
out += i;
outl -= i;
}
}
/* else */
/* we are going to be doing some buffering */
i = BIO_read(bio->next_bio, ctx->ibuf, ctx->ibuf_size);
if (i <= 0) {
BIO_copy_next_retry(bio);
if (i < 0) {
return (num > 0) ? num : i;
}
return num;
}
ctx->ibuf_off = 0;
ctx->ibuf_len = i;
}
}
static int buffer_write(BIO *b, const char *in, int inl) {
int i, num = 0;
BIO_F_BUFFER_CTX *ctx;
ctx = (BIO_F_BUFFER_CTX *)b->ptr;
if (ctx == NULL || b->next_bio == NULL) {
return 0;
}
BIO_clear_retry_flags(b);
for (;;) {
i = ctx->obuf_size - (ctx->obuf_off + ctx->obuf_len);
/* add to buffer and return */
if (i >= inl) {
memcpy(&ctx->obuf[ctx->obuf_off + ctx->obuf_len], in, inl);
ctx->obuf_len += inl;
return num + inl;
}
/* else */
/* stuff already in buffer, so add to it first, then flush */
if (ctx->obuf_len != 0) {
if (i > 0) {
memcpy(&ctx->obuf[ctx->obuf_off + ctx->obuf_len], in, i);
in += i;
inl -= i;
num += i;
ctx->obuf_len += i;
}
/* we now have a full buffer needing flushing */
for (;;) {
i = BIO_write(b->next_bio, &ctx->obuf[ctx->obuf_off], ctx->obuf_len);
if (i <= 0) {
BIO_copy_next_retry(b);
if (i < 0) {
return (num > 0) ? num : i;
}
return num;
}
ctx->obuf_off += i;
ctx->obuf_len -= i;
if (ctx->obuf_len == 0) {
break;
}
}
}
/* we only get here if the buffer has been flushed and we
* still have stuff to write */
ctx->obuf_off = 0;
/* we now have inl bytes to write */
while (inl >= ctx->obuf_size) {
i = BIO_write(b->next_bio, in, inl);
if (i <= 0) {
BIO_copy_next_retry(b);
if (i < 0) {
return (num > 0) ? num : i;
}
return num;
}
num += i;
in += i;
inl -= i;
if (inl == 0) {
return num;
}
}
/* copy the rest into the buffer since we have only a small
* amount left */
}
}
static long buffer_ctrl(BIO *b, int cmd, long num, void *ptr) {
BIO_F_BUFFER_CTX *ctx;
long ret = 1;
char *p1, *p2;
int r, *ip;
int ibs, obs;
ctx = (BIO_F_BUFFER_CTX *)b->ptr;
switch (cmd) {
case BIO_CTRL_RESET:
ctx->ibuf_off = 0;
ctx->ibuf_len = 0;
ctx->obuf_off = 0;
ctx->obuf_len = 0;
if (b->next_bio == NULL) {
return 0;
}
ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
break;
case BIO_CTRL_INFO:
ret = ctx->obuf_len;
break;
case BIO_CTRL_WPENDING:
ret = (long)ctx->obuf_len;
if (ret == 0) {
if (b->next_bio == NULL) {
return 0;
}
ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
}
break;
case BIO_CTRL_PENDING:
ret = (long)ctx->ibuf_len;
if (ret == 0) {
if (b->next_bio == NULL) {
return 0;
}
ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
}
break;
case BIO_C_SET_BUFF_SIZE:
ip = (int *)ptr;
if (*ip == 0) {
ibs = (int)num;
obs = ctx->obuf_size;
} else /* if (*ip == 1) */ {
ibs = ctx->ibuf_size;
obs = (int)num;
}
p1 = ctx->ibuf;
p2 = ctx->obuf;
if (ibs > DEFAULT_BUFFER_SIZE && ibs != ctx->ibuf_size) {
p1 = OPENSSL_malloc(ibs);
if (p1 == NULL) {
goto malloc_error;
}
}
if (obs > DEFAULT_BUFFER_SIZE && obs != ctx->obuf_size) {
p2 = OPENSSL_malloc(obs);
if (p2 == NULL) {
if (p1 != ctx->ibuf) {
OPENSSL_free(p1);
}
goto malloc_error;
}
}
if (ctx->ibuf != p1) {
OPENSSL_free(ctx->ibuf);
ctx->ibuf = p1;
ctx->ibuf_size = ibs;
}
ctx->ibuf_off = 0;
ctx->ibuf_len = 0;
if (ctx->obuf != p2) {
OPENSSL_free(ctx->obuf);
ctx->obuf = p2;
ctx->obuf_size = obs;
}
ctx->obuf_off = 0;
ctx->obuf_len = 0;
break;
case BIO_CTRL_FLUSH:
if (b->next_bio == NULL) {
return 0;
}
while (ctx->obuf_len > 0) {
BIO_clear_retry_flags(b);
r = BIO_write(b->next_bio, &(ctx->obuf[ctx->obuf_off]),
ctx->obuf_len);
BIO_copy_next_retry(b);
if (r <= 0) {
return r;
}
ctx->obuf_off += r;
ctx->obuf_len -= r;
}
ctx->obuf_len = 0;
ctx->obuf_off = 0;
ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
break;
default:
if (b->next_bio == NULL) {
return 0;
}
BIO_clear_retry_flags(b);
ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
BIO_copy_next_retry(b);
break;
}
return ret;
malloc_error:
OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE);
return 0;
}
static long buffer_callback_ctrl(BIO *b, int cmd, bio_info_cb fp) {
long ret = 1;
if (b->next_bio == NULL) {
return 0;
}
switch (cmd) {
default:
ret = BIO_callback_ctrl(b->next_bio, cmd, fp);
break;
}
return ret;
}
static int buffer_gets(BIO *b, char *buf, int size) {
BIO_F_BUFFER_CTX *ctx;
int num = 0, i, flag;
char *p;
ctx = (BIO_F_BUFFER_CTX *)b->ptr;
if (buf == NULL || size <= 0) {
return 0;
}
size--; /* reserve space for a '\0' */
BIO_clear_retry_flags(b);
for (;;) {
if (ctx->ibuf_len > 0) {
p = &ctx->ibuf[ctx->ibuf_off];
flag = 0;
for (i = 0; (i < ctx->ibuf_len) && (i < size); i++) {
*(buf++) = p[i];
if (p[i] == '\n') {
flag = 1;
i++;
break;
}
}
num += i;
size -= i;
ctx->ibuf_len -= i;
ctx->ibuf_off += i;
if (flag || size == 0) {
*buf = '\0';
return num;
}
} else /* read another chunk */
{
i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size);
if (i <= 0) {
BIO_copy_next_retry(b);
*buf = '\0';
if (i < 0) {
return (num > 0) ? num : i;
}
return num;
}
ctx->ibuf_len = i;
ctx->ibuf_off = 0;
}
}
}
static int buffer_puts(BIO *b, const char *str) {
return buffer_write(b, str, strlen(str));
}
static const BIO_METHOD methods_buffer = {
BIO_TYPE_BUFFER, "buffer", buffer_write, buffer_read,
buffer_puts, buffer_gets, buffer_ctrl, buffer_new,
buffer_free, buffer_callback_ctrl,
};
const BIO_METHOD *BIO_f_buffer(void) { return &methods_buffer; }
int BIO_set_read_buffer_size(BIO *bio, int buffer_size) {
return BIO_int_ctrl(bio, BIO_C_SET_BUFF_SIZE, buffer_size, 0);
}
int BIO_set_write_buffer_size(BIO *bio, int buffer_size) {
return BIO_int_ctrl(bio, BIO_C_SET_BUFF_SIZE, buffer_size, 1);
}
+20 -15
View File
@@ -66,10 +66,10 @@
#include <arpa/inet.h>
#include <unistd.h>
#else
OPENSSL_MSVC_PRAGMA(warning(push, 3))
#pragma warning(push, 3)
#include <winsock2.h>
#include <ws2tcpip.h>
OPENSSL_MSVC_PRAGMA(warning(pop))
#pragma warning(pop)
#endif
#include <openssl/buf.h>
@@ -77,7 +77,6 @@ OPENSSL_MSVC_PRAGMA(warning(pop))
#include <openssl/mem.h>
#include "internal.h"
#include "../internal.h"
enum {
@@ -299,7 +298,7 @@ static BIO_CONNECT *BIO_CONNECT_new(void) {
if (ret == NULL) {
return NULL;
}
OPENSSL_memset(ret, 0, sizeof(BIO_CONNECT));
memset(ret, 0, sizeof(BIO_CONNECT));
ret->state = BIO_CONN_S_BEFORE;
return ret;
@@ -468,6 +467,14 @@ static long conn_ctrl(BIO *bio, int cmd, long num, void *ptr) {
break;
case BIO_CTRL_FLUSH:
break;
case BIO_CTRL_SET_CALLBACK: {
#if 0 /* FIXME: Should this be used? -- Richard Levitte */
OPENSSL_PUT_ERROR(BIO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
ret = -1;
#else
ret = 0;
#endif
} break;
case BIO_CTRL_GET_CALLBACK: {
int (**fptr)(const BIO *bio, int state, int xret);
fptr = (int (**)(const BIO *bio, int state, int xret))ptr;
@@ -477,7 +484,7 @@ static long conn_ctrl(BIO *bio, int cmd, long num, void *ptr) {
ret = 0;
break;
}
return ret;
return (ret);
}
static long conn_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) {
@@ -487,9 +494,9 @@ static long conn_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) {
data = (BIO_CONNECT *)bio->ptr;
switch (cmd) {
case BIO_CTRL_SET_CALLBACK:
case BIO_CTRL_SET_CALLBACK: {
data->info_callback = (int (*)(const struct bio_st *, int, int))fp;
break;
} break;
default:
ret = 0;
break;
@@ -497,6 +504,10 @@ static long conn_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) {
return ret;
}
static int conn_puts(BIO *bp, const char *str) {
return conn_write(bp, str, strlen(str));
}
BIO *BIO_new_connect(const char *hostname) {
BIO *ret;
@@ -512,8 +523,8 @@ BIO *BIO_new_connect(const char *hostname) {
}
static const BIO_METHOD methods_connectp = {
BIO_TYPE_CONNECT, "socket connect", conn_write, conn_read,
NULL /* puts */, NULL /* gets */, conn_ctrl, conn_new,
BIO_TYPE_CONNECT, "socket connect", conn_write, conn_read,
conn_puts, NULL /* connect_gets, */, conn_ctrl, conn_new,
conn_free, conn_callback_ctrl,
};
@@ -527,12 +538,6 @@ int BIO_set_conn_port(BIO *bio, const char *port_str) {
return BIO_ctrl(bio, BIO_C_SET_CONNECT, 1, (void*) port_str);
}
int BIO_set_conn_int_port(BIO *bio, const int *port) {
char buf[DECIMAL_SIZE(int) + 1];
BIO_snprintf(buf, sizeof(buf), "%d", *port);
return BIO_set_conn_port(bio, buf);
}
int BIO_set_nbio(BIO *bio, int on) {
return BIO_ctrl(bio, BIO_C_SET_NBIO, on, NULL);
}
+22 -24
View File
@@ -63,9 +63,9 @@
#include <unistd.h>
#else
#include <io.h>
OPENSSL_MSVC_PRAGMA(warning(push, 3))
#pragma warning(push, 3)
#include <windows.h>
OPENSSL_MSVC_PRAGMA(warning(pop))
#pragma warning(pop)
#endif
#include <openssl/buf.h>
@@ -108,25 +108,20 @@ static int bio_fd_non_fatal_error(int err) {
}
#if defined(OPENSSL_WINDOWS)
#define BORINGSSL_ERRNO (int)GetLastError()
#define BORINGSSL_CLOSE _close
#define BORINGSSL_LSEEK _lseek
#define BORINGSSL_READ _read
#define BORINGSSL_WRITE _write
#else
#define BORINGSSL_ERRNO errno
#define BORINGSSL_CLOSE close
#define BORINGSSL_LSEEK lseek
#define BORINGSSL_READ read
#define BORINGSSL_WRITE write
#endif
int bio_fd_should_retry(int i) {
if (i == -1) {
return bio_fd_non_fatal_error(BORINGSSL_ERRNO);
return bio_fd_non_fatal_error((int)GetLastError());
}
return 0;
}
#else
int bio_fd_should_retry(int i) {
if (i == -1) {
return bio_fd_non_fatal_error(errno);
}
return 0;
}
#endif
BIO *BIO_new_fd(int fd, int close_flag) {
BIO *ret = BIO_new(BIO_s_fd());
@@ -150,7 +145,7 @@ static int fd_free(BIO *bio) {
if (bio->shutdown) {
if (bio->init) {
BORINGSSL_CLOSE(bio->num);
close(bio->num);
}
bio->init = 0;
}
@@ -160,7 +155,7 @@ static int fd_free(BIO *bio) {
static int fd_read(BIO *b, char *out, int outl) {
int ret = 0;
ret = BORINGSSL_READ(b->num, out, outl);
ret = read(b->num, out, outl);
BIO_clear_retry_flags(b);
if (ret <= 0) {
if (bio_fd_should_retry(ret)) {
@@ -172,7 +167,7 @@ static int fd_read(BIO *b, char *out, int outl) {
}
static int fd_write(BIO *b, const char *in, int inl) {
int ret = BORINGSSL_WRITE(b->num, in, inl);
int ret = write(b->num, in, inl);
BIO_clear_retry_flags(b);
if (ret <= 0) {
if (bio_fd_should_retry(ret)) {
@@ -193,14 +188,14 @@ static long fd_ctrl(BIO *b, int cmd, long num, void *ptr) {
case BIO_C_FILE_SEEK:
ret = 0;
if (b->init) {
ret = (long)BORINGSSL_LSEEK(b->num, num, SEEK_SET);
ret = (long)lseek(b->num, num, SEEK_SET);
}
break;
case BIO_C_FILE_TELL:
case BIO_CTRL_INFO:
ret = 0;
if (b->init) {
ret = (long)BORINGSSL_LSEEK(b->num, 0, SEEK_CUR);
ret = (long)lseek(b->num, 0, SEEK_CUR);
}
break;
case BIO_C_SET_FD:
@@ -241,6 +236,10 @@ static long fd_ctrl(BIO *b, int cmd, long num, void *ptr) {
return ret;
}
static int fd_puts(BIO *bp, const char *str) {
return fd_write(bp, str, strlen(str));
}
static int fd_gets(BIO *bp, char *buf, int size) {
char *ptr = buf;
char *end = buf + size - 1;
@@ -259,9 +258,8 @@ static int fd_gets(BIO *bp, char *buf, int size) {
}
static const BIO_METHOD methods_fdp = {
BIO_TYPE_FD, "file descriptor", fd_write, fd_read, NULL /* puts */,
fd_gets, fd_ctrl, fd_new, fd_free, NULL /* callback_ctrl */,
};
BIO_TYPE_FD, "file descriptor", fd_write, fd_read, fd_puts,
fd_gets, fd_ctrl, fd_new, fd_free, NULL, };
const BIO_METHOD *BIO_s_fd(void) { return &methods_fdp; }
+6 -6
View File
@@ -273,13 +273,13 @@ err:
return ret;
}
static int file_puts(BIO *bp, const char *str) {
return file_write(bp, str, strlen(str));
}
static const BIO_METHOD methods_filep = {
BIO_TYPE_FILE, "FILE pointer",
file_write, file_read,
NULL /* puts */, file_gets,
file_ctrl, file_new,
file_free, NULL /* callback_ctrl */,
};
BIO_TYPE_FILE, "FILE pointer", file_write, file_read, file_puts,
file_gets, file_ctrl, file_new, file_free, NULL, };
const BIO_METHOD *BIO_s_file(void) { return &methods_filep; }
+4 -5
View File
@@ -59,8 +59,6 @@
#include <limits.h>
#include <string.h>
#include "../internal.h"
/* hexdump_ctx contains the state of a hexdump. */
struct hexdump_ctx {
@@ -88,6 +86,7 @@ static char to_char(uint8_t b) {
* |ctx|. */
static int hexdump_write(struct hexdump_ctx *ctx, const uint8_t *data,
size_t len) {
size_t i;
char buf[10];
unsigned l;
@@ -96,7 +95,7 @@ static int hexdump_write(struct hexdump_ctx *ctx, const uint8_t *data,
* ^ offset ^ extra space ^ ASCII of line
*/
for (size_t i = 0; i < len; i++) {
for (i = 0; i < len; i++) {
if (ctx->used == 0) {
/* The beginning of a line. */
BIO_indent(ctx->bio, ctx->indent, UINT_MAX);
@@ -156,7 +155,7 @@ static int finish(struct hexdump_ctx *ctx) {
return 1;
}
OPENSSL_memset(buf, ' ', 4);
memset(buf, ' ', 4);
buf[4] = '|';
for (; ctx->used < 16; ctx->used++) {
@@ -181,7 +180,7 @@ static int finish(struct hexdump_ctx *ctx) {
int BIO_hexdump(BIO *bio, const uint8_t *data, size_t len, unsigned indent) {
struct hexdump_ctx ctx;
OPENSSL_memset(&ctx, 0, sizeof(ctx));
memset(&ctx, 0, sizeof(ctx));
ctx.bio = bio;
ctx.indent = indent;
+2 -2
View File
@@ -67,9 +67,9 @@ typedef unsigned short u_short;
#include <sys/types.h>
#include <sys/socket.h>
#else
OPENSSL_MSVC_PRAGMA(warning(push, 3))
#pragma warning(push, 3)
#include <winsock2.h>
OPENSSL_MSVC_PRAGMA(warning(pop))
#pragma warning(pop)
typedef int socklen_t;
#endif
+344 -30
View File
@@ -59,8 +59,6 @@
#include <openssl/err.h>
#include <openssl/mem.h>
#include "../internal.h"
struct bio_bio_st {
BIO *peer; /* NULL if buf == NULL.
@@ -74,6 +72,12 @@ struct bio_bio_st {
size_t offset; /* valid iff buf != NULL; 0 if len == 0 */
size_t size;
uint8_t *buf; /* "size" elements (if != NULL) */
char buf_externally_allocated; /* true iff buf was externally allocated. */
char zero_copy_read_lock; /* true iff a zero copy read operation
* is in progress. */
char zero_copy_write_lock; /* true iff a zero copy write operation
* is in progress. */
size_t request; /* valid iff peer != NULL; 0 if len != 0,
* otherwise set by peer to number of bytes
@@ -88,7 +92,7 @@ static int bio_new(BIO *bio) {
if (b == NULL) {
return 0;
}
OPENSSL_memset(b, 0, sizeof(struct bio_bio_st));
memset(b, 0, sizeof(struct bio_bio_st));
b->size = 17 * 1024; /* enough for one TLS record (just a default) */
bio->ptr = b;
@@ -141,12 +145,263 @@ static int bio_free(BIO *bio) {
bio_destroy_pair(bio);
}
OPENSSL_free(b->buf);
if (!b->buf_externally_allocated) {
OPENSSL_free(b->buf);
}
OPENSSL_free(b);
return 1;
}
static size_t bio_zero_copy_get_read_buf(struct bio_bio_st* peer_b,
uint8_t** out_read_buf,
size_t* out_buf_offset) {
size_t max_available;
if (peer_b->len > peer_b->size - peer_b->offset) {
/* Only the first half of the ring buffer can be read. */
max_available = peer_b->size - peer_b->offset;
} else {
max_available = peer_b->len;
}
*out_read_buf = peer_b->buf;
*out_buf_offset = peer_b->offset;
return max_available;
}
int BIO_zero_copy_get_read_buf(BIO* bio, uint8_t** out_read_buf,
size_t* out_buf_offset,
size_t* out_available_bytes) {
struct bio_bio_st* b;
struct bio_bio_st* peer_b;
size_t max_available;
*out_available_bytes = 0;
BIO_clear_retry_flags(bio);
if (!bio->init) {
OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED);
return 0;
}
b = bio->ptr;
if (!b || !b->peer) {
OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
return 0;
}
peer_b = b->peer->ptr;
if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) {
OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
return 0;
}
if (peer_b->zero_copy_read_lock) {
OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT);
return 0;
}
peer_b->request = 0; /* Is not used by zero-copy API. */
max_available =
bio_zero_copy_get_read_buf(peer_b, out_read_buf, out_buf_offset);
assert(peer_b->buf != NULL);
if (max_available > 0) {
peer_b->zero_copy_read_lock = 1;
}
*out_available_bytes = max_available;
return 1;
}
int BIO_zero_copy_get_read_buf_done(BIO* bio, size_t bytes_read) {
struct bio_bio_st* b;
struct bio_bio_st* peer_b;
size_t max_available;
size_t dummy_read_offset;
uint8_t* dummy_read_buf;
assert(BIO_get_retry_flags(bio) == 0);
if (!bio->init) {
OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED);
return 0;
}
b = bio->ptr;
if (!b || !b->peer) {
OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
return 0;
}
peer_b = b->peer->ptr;
if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) {
OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
return 0;
}
if (!peer_b->zero_copy_read_lock) {
OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT);
return 0;
}
max_available =
bio_zero_copy_get_read_buf(peer_b, &dummy_read_buf, &dummy_read_offset);
if (bytes_read > max_available) {
OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT);
return 0;
}
assert(peer_b->len >= bytes_read);
peer_b->len -= bytes_read;
assert(peer_b->offset + bytes_read <= peer_b->size);
/* Move read offset. If zero_copy_write_lock == 1 we must advance the
* offset even if buffer becomes empty, to make sure
* write_offset = (offset + len) mod size does not change. */
if (peer_b->offset + bytes_read == peer_b->size ||
(!peer_b->zero_copy_write_lock && peer_b->len == 0)) {
peer_b->offset = 0;
} else {
peer_b->offset += bytes_read;
}
bio->num_read += bytes_read;
peer_b->zero_copy_read_lock = 0;
return 1;
}
static size_t bio_zero_copy_get_write_buf(struct bio_bio_st* b,
uint8_t** out_write_buf,
size_t* out_buf_offset) {
size_t write_offset;
size_t max_available;
assert(b->len <= b->size);
write_offset = b->offset + b->len;
if (write_offset >= b->size) {
/* Only the first half of the ring buffer can be written to. */
write_offset -= b->size;
/* write up to the start of the ring buffer. */
max_available = b->offset - write_offset;
} else {
/* write up to the end the buffer. */
max_available = b->size - write_offset;
}
*out_write_buf = b->buf;
*out_buf_offset = write_offset;
return max_available;
}
int BIO_zero_copy_get_write_buf(BIO* bio, uint8_t** out_write_buf,
size_t* out_buf_offset,
size_t* out_available_bytes) {
struct bio_bio_st* b;
struct bio_bio_st* peer_b;
size_t max_available;
*out_available_bytes = 0;
BIO_clear_retry_flags(bio);
if (!bio->init) {
OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED);
return 0;
}
b = bio->ptr;
if (!b || !b->buf || !b->peer) {
OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
return 0;
}
peer_b = b->peer->ptr;
if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) {
OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
return 0;
}
assert(b->buf != NULL);
if (b->zero_copy_write_lock) {
OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT);
return 0;
}
b->request = 0;
if (b->closed) {
/* Bio is already closed. */
OPENSSL_PUT_ERROR(BIO, BIO_R_BROKEN_PIPE);
return 0;
}
max_available = bio_zero_copy_get_write_buf(b, out_write_buf, out_buf_offset);
if (max_available > 0) {
b->zero_copy_write_lock = 1;
}
*out_available_bytes = max_available;
return 1;
}
int BIO_zero_copy_get_write_buf_done(BIO* bio, size_t bytes_written) {
struct bio_bio_st* b;
struct bio_bio_st* peer_b;
size_t rest;
size_t dummy_write_offset;
uint8_t* dummy_write_buf;
if (!bio->init) {
OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED);
return 0;
}
b = bio->ptr;
if (!b || !b->buf || !b->peer) {
OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
return 0;
}
peer_b = b->peer->ptr;
if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) {
OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
return 0;
}
b->request = 0;
if (b->closed) {
/* BIO is already closed. */
OPENSSL_PUT_ERROR(BIO, BIO_R_BROKEN_PIPE);
return 0;
}
if (!b->zero_copy_write_lock) {
OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT);
return 0;
}
rest = bio_zero_copy_get_write_buf(b, &dummy_write_buf, &dummy_write_offset);
if (bytes_written > rest) {
OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT);
return 0;
}
bio->num_write += bytes_written;
/* Move write offset. */
b->len += bytes_written;
b->zero_copy_write_lock = 0;
return 1;
}
static int bio_read(BIO *bio, char *buf, int size_) {
size_t size = size_;
size_t rest;
@@ -167,7 +422,7 @@ static int bio_read(BIO *bio, char *buf, int size_) {
peer_b->request = 0; /* will be set in "retry_read" situation */
if (buf == NULL || size == 0) {
if (buf == NULL || size == 0 || peer_b->zero_copy_read_lock) {
return 0;
}
@@ -209,10 +464,13 @@ static int bio_read(BIO *bio, char *buf, int size_) {
}
assert(peer_b->offset + chunk <= peer_b->size);
OPENSSL_memcpy(buf, peer_b->buf + peer_b->offset, chunk);
memcpy(buf, peer_b->buf + peer_b->offset, chunk);
peer_b->len -= chunk;
if (peer_b->len) {
/* If zero_copy_write_lock == 1 we must advance the offset even if buffer
* becomes empty, to make sure write_offset = (offset + len) % size
* does not change. */
if (peer_b->len || peer_b->zero_copy_write_lock) {
peer_b->offset += chunk;
assert(peer_b->offset <= peer_b->size);
if (peer_b->offset == peer_b->size) {
@@ -246,6 +504,10 @@ static int bio_write(BIO *bio, const char *buf, int num_) {
assert(b->peer != NULL);
assert(b->buf != NULL);
if (b->zero_copy_write_lock) {
return 0;
}
b->request = 0;
if (b->closed) {
/* we already closed */
@@ -289,7 +551,7 @@ static int bio_write(BIO *bio, const char *buf, int num_) {
chunk = b->size - write_offset;
}
OPENSSL_memcpy(b->buf + write_offset, buf, chunk);
memcpy(b->buf + write_offset, buf, chunk);
b->len += chunk;
@@ -302,8 +564,9 @@ static int bio_write(BIO *bio, const char *buf, int num_) {
return num;
}
static int bio_make_pair(BIO *bio1, BIO *bio2, size_t writebuf1_len,
size_t writebuf2_len) {
static int bio_make_pair(BIO* bio1, BIO* bio2,
size_t writebuf1_len, uint8_t* ext_writebuf1,
size_t writebuf2_len, uint8_t* ext_writebuf2) {
struct bio_bio_st *b1, *b2;
assert(bio1 != NULL);
@@ -317,14 +580,23 @@ static int bio_make_pair(BIO *bio1, BIO *bio2, size_t writebuf1_len,
return 0;
}
assert(b1->buf_externally_allocated == 0);
assert(b2->buf_externally_allocated == 0);
if (b1->buf == NULL) {
if (writebuf1_len) {
b1->size = writebuf1_len;
}
b1->buf = OPENSSL_malloc(b1->size);
if (b1->buf == NULL) {
OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE);
return 0;
if (!ext_writebuf1) {
b1->buf_externally_allocated = 0;
b1->buf = OPENSSL_malloc(b1->size);
if (b1->buf == NULL) {
OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE);
return 0;
}
} else {
b1->buf = ext_writebuf1;
b1->buf_externally_allocated = 1;
}
b1->len = 0;
b1->offset = 0;
@@ -334,10 +606,16 @@ static int bio_make_pair(BIO *bio1, BIO *bio2, size_t writebuf1_len,
if (writebuf2_len) {
b2->size = writebuf2_len;
}
b2->buf = OPENSSL_malloc(b2->size);
if (b2->buf == NULL) {
OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE);
return 0;
if (!ext_writebuf2) {
b2->buf_externally_allocated = 0;
b2->buf = OPENSSL_malloc(b2->size);
if (b2->buf == NULL) {
OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE);
return 0;
}
} else {
b2->buf = ext_writebuf2;
b2->buf_externally_allocated = 1;
}
b2->len = 0;
b2->offset = 0;
@@ -346,9 +624,13 @@ static int bio_make_pair(BIO *bio1, BIO *bio2, size_t writebuf1_len,
b1->peer = bio2;
b1->closed = 0;
b1->request = 0;
b1->zero_copy_read_lock = 0;
b1->zero_copy_write_lock = 0;
b2->peer = bio1;
b2->closed = 0;
b2->request = 0;
b2->zero_copy_read_lock = 0;
b2->zero_copy_write_lock = 0;
bio1->init = 1;
bio2->init = 1;
@@ -450,30 +732,62 @@ static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr) {
return ret;
}
static int bio_puts(BIO *bio, const char *str) {
return bio_write(bio, str, strlen(str));
}
static const BIO_METHOD methods_biop = {
BIO_TYPE_BIO, "BIO pair", bio_write, bio_read, NULL /* puts */,
NULL /* gets */, bio_ctrl, bio_new, bio_free, NULL /* callback_ctrl */
BIO_TYPE_BIO, "BIO pair", bio_write, bio_read,
bio_puts, NULL /* no bio_gets */, bio_ctrl, bio_new,
bio_free, NULL /* no bio_callback_ctrl */
};
static const BIO_METHOD *bio_s_bio(void) { return &methods_biop; }
int BIO_new_bio_pair(BIO** bio1_p, size_t writebuf1_len,
BIO** bio2_p, size_t writebuf2_len) {
BIO *bio1 = BIO_new(bio_s_bio());
BIO *bio2 = BIO_new(bio_s_bio());
if (bio1 == NULL || bio2 == NULL ||
!bio_make_pair(bio1, bio2, writebuf1_len, writebuf2_len)) {
int BIO_new_bio_pair(BIO** bio1_p, size_t writebuf1,
BIO** bio2_p, size_t writebuf2) {
return BIO_new_bio_pair_external_buf(bio1_p, writebuf1, NULL, bio2_p,
writebuf2, NULL);
}
int BIO_new_bio_pair_external_buf(BIO** bio1_p, size_t writebuf1_len,
uint8_t* ext_writebuf1,
BIO** bio2_p, size_t writebuf2_len,
uint8_t* ext_writebuf2) {
BIO *bio1 = NULL, *bio2 = NULL;
int ret = 0;
/* External buffers must have sizes greater than 0. */
if ((ext_writebuf1 && !writebuf1_len) || (ext_writebuf2 && !writebuf2_len)) {
goto err;
}
bio1 = BIO_new(bio_s_bio());
if (bio1 == NULL) {
goto err;
}
bio2 = BIO_new(bio_s_bio());
if (bio2 == NULL) {
goto err;
}
if (!bio_make_pair(bio1, bio2, writebuf1_len, ext_writebuf1, writebuf2_len,
ext_writebuf2)) {
goto err;
}
ret = 1;
err:
if (ret == 0) {
BIO_free(bio1);
bio1 = NULL;
BIO_free(bio2);
*bio1_p = NULL;
*bio2_p = NULL;
return 0;
bio2 = NULL;
}
*bio1_p = bio1;
*bio2_p = bio2;
return 1;
return ret;
}
size_t BIO_ctrl_get_read_request(BIO *bio) {
+9 -16
View File
@@ -63,11 +63,11 @@
#if !defined(OPENSSL_WINDOWS)
#include <unistd.h>
#else
OPENSSL_MSVC_PRAGMA(warning(push, 3))
#pragma warning(push, 3)
#include <winsock2.h>
OPENSSL_MSVC_PRAGMA(warning(pop))
#pragma warning(pop)
OPENSSL_MSVC_PRAGMA(comment(lib, "Ws2_32.lib"))
#pragma comment(lib, "Ws2_32.lib")
#endif
#include "internal.h"
@@ -110,11 +110,7 @@ static int sock_read(BIO *b, char *out, int outl) {
}
bio_clear_socket_error();
#if defined(OPENSSL_WINDOWS)
ret = recv(b->num, out, outl, 0);
#else
ret = read(b->num, out, outl);
#endif
BIO_clear_retry_flags(b);
if (ret <= 0) {
if (bio_fd_should_retry(ret)) {
@@ -128,11 +124,7 @@ static int sock_write(BIO *b, const char *in, int inl) {
int ret;
bio_clear_socket_error();
#if defined(OPENSSL_WINDOWS)
ret = send(b->num, in, inl, 0);
#else
ret = write(b->num, in, inl);
#endif
BIO_clear_retry_flags(b);
if (ret <= 0) {
if (bio_fd_should_retry(ret)) {
@@ -142,6 +134,10 @@ static int sock_write(BIO *b, const char *in, int inl) {
return ret;
}
static int sock_puts(BIO *bp, const char *str) {
return sock_write(bp, str, strlen(str));
}
static long sock_ctrl(BIO *b, int cmd, long num, void *ptr) {
long ret = 1;
int *ip;
@@ -181,11 +177,8 @@ static long sock_ctrl(BIO *b, int cmd, long num, void *ptr) {
}
static const BIO_METHOD methods_sockp = {
BIO_TYPE_SOCKET, "socket",
sock_write, sock_read,
NULL /* puts */, NULL /* gets, */,
sock_ctrl, sock_new,
sock_free, NULL /* callback_ctrl */,
BIO_TYPE_SOCKET, "socket", sock_write, sock_read, sock_puts,
NULL /* gets, */, sock_ctrl, sock_new, sock_free, NULL,
};
const BIO_METHOD *BIO_s_socket(void) { return &methods_sockp; }
+5 -6
View File
@@ -26,14 +26,13 @@
#include <netdb.h>
#include <unistd.h>
#else
OPENSSL_MSVC_PRAGMA(warning(push, 3))
#pragma warning(push, 3)
#include <winsock2.h>
#include <ws2tcpip.h>
OPENSSL_MSVC_PRAGMA(warning(pop))
#pragma warning(pop)
#endif
#include "internal.h"
#include "../internal.h"
int bio_ip_and_port_to_socket_and_addr(int *out_sock,
@@ -46,7 +45,7 @@ int bio_ip_and_port_to_socket_and_addr(int *out_sock,
*out_sock = -1;
OPENSSL_memset(&hint, 0, sizeof(hint));
memset(&hint, 0, sizeof(hint));
hint.ai_family = AF_UNSPEC;
hint.ai_socktype = SOCK_STREAM;
@@ -63,8 +62,8 @@ int bio_ip_and_port_to_socket_and_addr(int *out_sock,
if ((size_t) cur->ai_addrlen > sizeof(struct sockaddr_storage)) {
continue;
}
OPENSSL_memset(out_addr, 0, sizeof(struct sockaddr_storage));
OPENSSL_memcpy(out_addr, cur->ai_addr, cur->ai_addrlen);
memset(out_addr, 0, sizeof(struct sockaddr_storage));
memcpy(out_addr, cur->ai_addr, cur->ai_addrlen);
*out_addr_length = cur->ai_addrlen;
*out_sock = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol);
+88
View File
@@ -0,0 +1,88 @@
include_directories(../../include)
if (${ARCH} STREQUAL "x86_64")
set(
BN_ARCH_SOURCES
x86_64-mont.${ASM_EXT}
x86_64-mont5.${ASM_EXT}
rsaz-x86_64.${ASM_EXT}
rsaz-avx2.${ASM_EXT}
rsaz_exp.c
)
endif()
if (${ARCH} STREQUAL "x86")
set(
BN_ARCH_SOURCES
bn-586.${ASM_EXT}
co-586.${ASM_EXT}
x86-mont.${ASM_EXT}
)
endif()
if (${ARCH} STREQUAL "arm")
set(
BN_ARCH_SOURCES
armv4-mont.${ASM_EXT}
)
endif()
if (${ARCH} STREQUAL "aarch64")
set(
BN_ARCH_SOURCES
armv8-mont.${ASM_EXT}
)
endif()
add_library(
bn
OBJECT
add.c
asm/x86_64-gcc.c
bn.c
bn_asn1.c
cmp.c
convert.c
ctx.c
div.c
exponentiation.c
generic.c
gcd.c
kronecker.c
montgomery.c
mul.c
prime.c
random.c
shift.c
sqrt.c
${BN_ARCH_SOURCES}
)
perlasm(x86_64-mont.${ASM_EXT} asm/x86_64-mont.pl)
perlasm(x86_64-mont5.${ASM_EXT} asm/x86_64-mont5.pl)
perlasm(rsaz-x86_64.${ASM_EXT} asm/rsaz-x86_64.pl)
perlasm(rsaz-avx2.${ASM_EXT} asm/rsaz-avx2.pl)
perlasm(bn-586.${ASM_EXT} asm/bn-586.pl)
perlasm(co-586.${ASM_EXT} asm/co-586.pl)
perlasm(x86-mont.${ASM_EXT} asm/x86-mont.pl)
perlasm(armv4-mont.${ASM_EXT} asm/armv4-mont.pl)
perlasm(armv8-mont.${ASM_EXT} asm/armv8-mont.pl)
add_executable(
bn_test
bn_test.cc
$<TARGET_OBJECTS:test_support>
)
target_link_libraries(bn_test crypto)
add_dependencies(all_tests bn_test)
@@ -115,7 +115,7 @@ int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
min = b->top;
dif = max - min;
if (!bn_wexpand(r, max + 1)) {
if (bn_wexpand(r, max + 1) == NULL) {
return 0;
}
@@ -191,7 +191,7 @@ int BN_add_word(BIGNUM *a, BN_ULONG w) {
}
if (w && i == a->top) {
if (!bn_wexpand(a, a->top + 1)) {
if (bn_wexpand(a, a->top + 1) == NULL) {
return 0;
}
a->top++;
@@ -239,7 +239,7 @@ int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
/* We are actually doing a - b :-) */
max = (a->top > b->top) ? a->top : b->top;
if (!bn_wexpand(r, max)) {
if (bn_wexpand(r, max) == NULL) {
return 0;
}
@@ -273,7 +273,7 @@ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
return 0;
}
if (!bn_wexpand(r, max)) {
if (bn_wexpand(r, max) == NULL) {
return 0;
}
@@ -314,7 +314,7 @@ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
}
if (dif > 0 && rp != ap) {
OPENSSL_memcpy(rp, ap, sizeof(*rp) * dif);
memcpy(rp, ap, sizeof(*rp) * dif);
}
r->top = max;
@@ -16,7 +16,7 @@
# [depending on key length, less for longer keys] on ARM920T, and
# +115-80% on Intel IXP425. This is compared to pre-bn_mul_mont code
# base and compiler generated code with in-lined umull and even umlal
# instructions. The latter means that this code didn't really have an
# instructions. The latter means that this code didn't really have an
# "advantage" of utilizing some "secret" instruction.
#
# The code is interoperable with Thumb ISA and is rather compact, less
@@ -39,13 +39,13 @@
# others outweighs the marginal loss on Cortex-A9.
$flavour = shift;
if ($flavour=~/\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
else { while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {} }
if ($flavour=~/^\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
else { while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {} }
if ($flavour && $flavour ne "void") {
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
( $xlate="${dir}../../../perlasm/arm-xlate.pl" and -f $xlate) or
( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
die "can't locate arm-xlate.pl";
open STDOUT,"| \"$^X\" $xlate $flavour $output";
@@ -38,7 +38,7 @@ $output = shift;
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
( $xlate="${dir}../../../perlasm/arm-xlate.pl" and -f $xlate) or
( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
die "can't locate arm-xlate.pl";
open OUT,"| \"$^X\" $xlate $flavour $output";
@@ -1,13 +1,10 @@
#!/usr/bin/env perl
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
push(@INC,"${dir}","${dir}../../../perlasm");
push(@INC,"${dir}","${dir}../../perlasm");
require "x86asm.pl";
$output = pop;
open STDOUT,">$output";
&asm_init($ARGV[0]);
&asm_init($ARGV[0],$0);
$sse2=0;
for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); }
@@ -24,8 +21,6 @@ for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); }
&asm_finish();
close STDOUT;
sub bn_mul_add_words
{
local($name)=@_;
@@ -47,7 +42,7 @@ sub bn_mul_add_words
&movd("mm0",&wparam(3)); # mm0 = w
&pxor("mm1","mm1"); # mm1 = carry_in
&jmp(&label("maw_sse2_entry"));
&set_label("maw_sse2_unrolled",16);
&movd("mm3",&DWP(0,$r,"",0)); # mm3 = r[0]
&paddq("mm1","mm3"); # mm1 = carry_in + r[0]
@@ -668,20 +663,20 @@ sub bn_sub_part_words
&adc($c,0);
&mov(&DWP($i*4,$r,"",0),$tmp1); # *r
}
&comment("");
&add($b,32);
&add($r,32);
&sub($num,8);
&jnz(&label("pw_neg_loop"));
&set_label("pw_neg_finish",0);
&mov($tmp2,&wparam(4)); # get dl
&mov($num,0);
&sub($num,$tmp2);
&and($num,7);
&jz(&label("pw_end"));
for ($i=0; $i<7; $i++)
{
&comment("dl<0 Tail Round $i");
@@ -698,9 +693,9 @@ sub bn_sub_part_words
}
&jmp(&label("pw_end"));
&set_label("pw_pos",0);
&and($num,0xfffffff8); # num / 8
&jz(&label("pw_pos_finish"));
@@ -715,18 +710,18 @@ sub bn_sub_part_words
&mov(&DWP($i*4,$r,"",0),$tmp1); # *r
&jnc(&label("pw_nc".$i));
}
&comment("");
&add($a,32);
&add($r,32);
&sub($num,8);
&jnz(&label("pw_pos_loop"));
&set_label("pw_pos_finish",0);
&mov($num,&wparam(4)); # get dl
&and($num,7);
&jz(&label("pw_end"));
for ($i=0; $i<7; $i++)
{
&comment("dl>0 Tail Round $i");
@@ -747,17 +742,17 @@ sub bn_sub_part_words
&mov(&DWP($i*4,$r,"",0),$tmp1); # *r
&set_label("pw_nc".$i,0);
}
&comment("");
&add($a,32);
&add($r,32);
&sub($num,8);
&jnz(&label("pw_nc_loop"));
&mov($num,&wparam(4)); # get dl
&and($num,7);
&jz(&label("pw_nc_end"));
for ($i=0; $i<7; $i++)
{
&mov($tmp1,&DWP($i*4,$a,"",0)); # *a
@@ -776,3 +771,4 @@ sub bn_sub_part_words
&function_end($name);
}
@@ -1,13 +1,10 @@
#!/usr/local/bin/perl
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
push(@INC,"${dir}","${dir}../../../perlasm");
push(@INC,"${dir}","${dir}../../perlasm");
require "x86asm.pl";
$output = pop;
open STDOUT,">$output";
&asm_init($ARGV[0]);
&asm_init($ARGV[0],$0);
&bn_mul_comba("bn_mul_comba8",8);
&bn_mul_comba("bn_mul_comba4",4);
@@ -16,8 +13,6 @@ open STDOUT,">$output";
&asm_finish();
close STDOUT;
sub mul_add_c
{
local($a,$ai,$b,$bi,$c0,$c1,$c2,$pos,$i,$na,$nb)=@_;
@@ -41,7 +36,7 @@ sub mul_add_c
&mov("edx",&DWP(($nb)*4,$b,"",0)) if $pos == 1; # laod next b
###
&adc($c2,0);
# is pos > 1, it means it is the last loop
# is pos > 1, it means it is the last loop
&mov(&DWP($i*4,"eax","",0),$c0) if $pos > 0; # save r[];
&mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 1; # laod next a
}
@@ -70,7 +65,7 @@ sub sqr_add_c
&mov("edx",&DWP(($nb)*4,$a,"",0)) if ($pos == 1) && ($na != $nb);
###
&adc($c2,0);
# is pos > 1, it means it is the last loop
# is pos > 1, it means it is the last loop
&mov(&DWP($i*4,$r,"",0),$c0) if $pos > 0; # save r[];
&mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 1; # load next b
}
@@ -121,7 +116,7 @@ sub bn_mul_comba
$c2="ebp";
$a="esi";
$b="edi";
$as=0;
$ae=0;
$bs=0;
@@ -136,9 +131,9 @@ sub bn_mul_comba
&push("ebx");
&xor($c0,$c0);
&mov("eax",&DWP(0,$a,"",0)); # load the first word
&mov("eax",&DWP(0,$a,"",0)); # load the first word
&xor($c1,$c1);
&mov("edx",&DWP(0,$b,"",0)); # load the first second
&mov("edx",&DWP(0,$b,"",0)); # load the first second
for ($i=0; $i<$tot; $i++)
{
@@ -146,7 +141,7 @@ sub bn_mul_comba
$bi=$bs;
$end=$be+1;
&comment("################## Calculate word $i");
&comment("################## Calculate word $i");
for ($j=$bs; $j<$end; $j++)
{
@@ -76,7 +76,7 @@ $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
( $xlate="${dir}../../../perlasm/x86_64-xlate.pl" and -f $xlate) or
( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
die "can't locate x86_64-xlate.pl";
# In upstream, this is controlled by shelling out to the compiler to check
@@ -84,10 +84,10 @@ die "can't locate x86_64-xlate.pl";
# output, so this isn't useful anyway.
#
# TODO(davidben): Enable these after testing. $avx goes up to 2 and $addx to 1.
$avx = 2;
$addx = 1;
$avx = 0;
$addx = 0;
open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
open OUT,"| \"$^X\" $xlate $flavour $output";
*STDOUT = *OUT;
if ($avx>1) {{{
@@ -145,21 +145,13 @@ $code.=<<___;
.type rsaz_1024_sqr_avx2,\@function,5
.align 64
rsaz_1024_sqr_avx2: # 702 cycles, 14% faster than rsaz_1024_mul_avx2
.cfi_startproc
lea (%rsp), %rax
.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
vzeroupper
___
$code.=<<___ if ($win64);
@@ -178,7 +170,6 @@ $code.=<<___ if ($win64);
___
$code.=<<___;
mov %rax,%rbp
.cfi_def_cfa_register %rbp
mov %rdx, $np # reassigned argument
sub \$$FrameSize, %rsp
mov $np, $tmp
@@ -368,7 +359,7 @@ $code.=<<___;
vpaddq $TEMP1, $ACC1, $ACC1
vpmuludq 32*7-128($aap), $B2, $ACC2
vpbroadcastq 32*5-128($tpa), $B2
vpaddq 32*11-448($tp1), $ACC2, $ACC2
vpaddq 32*11-448($tp1), $ACC2, $ACC2
vmovdqu $ACC6, 32*6-192($tp0)
vmovdqu $ACC7, 32*7-192($tp0)
@@ -427,7 +418,7 @@ $code.=<<___;
vmovdqu $ACC7, 32*16-448($tp1)
lea 8($tp1), $tp1
dec $i
dec $i
jnz .LOOP_SQR_1024
___
$ZERO = $ACC9;
@@ -772,7 +763,7 @@ $code.=<<___;
vpblendd \$3, $TEMP4, $TEMP5, $TEMP4
vpaddq $TEMP3, $ACC7, $ACC7
vpaddq $TEMP4, $ACC8, $ACC8
vpsrlq \$29, $ACC4, $TEMP1
vpand $AND_MASK, $ACC4, $ACC4
vpsrlq \$29, $ACC5, $TEMP2
@@ -811,10 +802,8 @@ $code.=<<___;
vzeroall
mov %rbp, %rax
.cfi_def_cfa_register %rax
___
$code.=<<___ if ($win64);
.Lsqr_1024_in_tail:
movaps -0xd8(%rax),%xmm6
movaps -0xc8(%rax),%xmm7
movaps -0xb8(%rax),%xmm8
@@ -828,22 +817,14 @@ $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
.Lsqr_1024_epilogue:
ret
.cfi_endproc
.size rsaz_1024_sqr_avx2,.-rsaz_1024_sqr_avx2
___
}
@@ -896,21 +877,13 @@ $code.=<<___;
.type rsaz_1024_mul_avx2,\@function,5
.align 64
rsaz_1024_mul_avx2:
.cfi_startproc
lea (%rsp), %rax
.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);
vzeroupper
@@ -929,7 +902,6 @@ $code.=<<___ if ($win64);
___
$code.=<<___;
mov %rax,%rbp
.cfi_def_cfa_register %rbp
vzeroall
mov %rdx, $bp # reassigned argument
sub \$64,%rsp
@@ -1456,17 +1428,15 @@ $code.=<<___;
vpaddq $TEMP4, $ACC8, $ACC8
vmovdqu $ACC4, 128-128($rp)
vmovdqu $ACC5, 160-128($rp)
vmovdqu $ACC5, 160-128($rp)
vmovdqu $ACC6, 192-128($rp)
vmovdqu $ACC7, 224-128($rp)
vmovdqu $ACC8, 256-128($rp)
vzeroupper
mov %rbp, %rax
.cfi_def_cfa_register %rax
___
$code.=<<___ if ($win64);
.Lmul_1024_in_tail:
movaps -0xd8(%rax),%xmm6
movaps -0xc8(%rax),%xmm7
movaps -0xb8(%rax),%xmm8
@@ -1480,22 +1450,14 @@ $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
.Lmul_1024_epilogue:
ret
.cfi_endproc
.size rsaz_1024_mul_avx2,.-rsaz_1024_mul_avx2
___
}
@@ -1614,10 +1576,8 @@ rsaz_1024_scatter5_avx2:
.type rsaz_1024_gather5_avx2,\@abi-omnipotent
.align 32
rsaz_1024_gather5_avx2:
.cfi_startproc
vzeroupper
mov %rsp,%r11
.cfi_def_cfa_register %r11
___
$code.=<<___ if ($win64);
lea -0x88(%rsp),%rax
@@ -1755,13 +1715,11 @@ $code.=<<___ if ($win64);
movaps -0x38(%r11),%xmm13
movaps -0x28(%r11),%xmm14
movaps -0x18(%r11),%xmm15
.LSEH_end_rsaz_1024_gather5:
___
$code.=<<___;
lea (%r11),%rsp
.cfi_def_cfa_register %rsp
ret
.cfi_endproc
.LSEH_end_rsaz_1024_gather5:
.size rsaz_1024_gather5_avx2,.-rsaz_1024_gather5_avx2
___
}
@@ -1772,8 +1730,7 @@ $code.=<<___;
.type rsaz_avx2_eligible,\@abi-omnipotent
.align 32
rsaz_avx2_eligible:
leaq OPENSSL_ia32cap_P(%rip),%rax
mov 8(%rax),%eax
mov OPENSSL_ia32cap_P+8(%rip),%eax
___
$code.=<<___ if ($addx);
mov \$`1<<8|1<<19`,%ecx
@@ -1835,17 +1792,14 @@ rsaz_se_handler:
cmp %r10,%rbx # context->Rip<prologue label
jb .Lcommon_seh_tail
mov 152($context),%rax # pull context->Rsp
mov 4(%r11),%r10d # HandlerData[1]
lea (%rsi,%r10),%r10 # epilogue label
cmp %r10,%rbx # context->Rip>=epilogue label
jae .Lcommon_seh_tail
mov 160($context),%rbp # pull context->Rbp
mov 8(%r11),%r10d # HandlerData[2]
lea (%rsi,%r10),%r10 # "in tail" label
cmp %r10,%rbx # context->Rip>="in tail" label
cmovc %rbp,%rax
mov 160($context),%rax # pull context->Rbp
mov -48(%rax),%r15
mov -40(%rax),%r14
@@ -1923,13 +1877,11 @@ rsaz_se_handler:
.LSEH_info_rsaz_1024_sqr_avx2:
.byte 9,0,0,0
.rva rsaz_se_handler
.rva .Lsqr_1024_body,.Lsqr_1024_epilogue,.Lsqr_1024_in_tail
.long 0
.rva .Lsqr_1024_body,.Lsqr_1024_epilogue
.LSEH_info_rsaz_1024_mul_avx2:
.byte 9,0,0,0
.rva rsaz_se_handler
.rva .Lmul_1024_body,.Lmul_1024_epilogue,.Lmul_1024_in_tail
.long 0
.rva .Lmul_1024_body,.Lmul_1024_epilogue
.LSEH_info_rsaz_1024_gather5:
.byte 0x01,0x36,0x17,0x0b
.byte 0x36,0xf8,0x09,0x00 # vmovaps 0x90(rsp),xmm15
+2338
View File
File diff suppressed because it is too large Load Diff
+20 -50
View File
@@ -27,13 +27,10 @@
# gives ~40% on rsa512 sign benchmark...
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
push(@INC,"${dir}","${dir}../../../perlasm");
push(@INC,"${dir}","${dir}../../perlasm");
require "x86asm.pl";
$output = pop;
open STDOUT,">$output";
&asm_init($ARGV[0]);
&asm_init($ARGV[0],$0);
$sse2=0;
for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); }
@@ -66,57 +63,33 @@ $frame=32; # size of above frame rounded up to 16n
&lea ("esi",&wparam(0)); # put aside pointer to argument block
&lea ("edx",&wparam(1)); # load ap
&mov ("ebp","esp"); # saved stack pointer!
&add ("edi",2); # extra two words on top of tp
&neg ("edi");
&lea ("ebp",&DWP(-$frame,"esp","edi",4)); # future alloca($frame+4*(num+2))
&lea ("esp",&DWP(-$frame,"esp","edi",4)); # alloca($frame+4*(num+2))
&neg ("edi");
# minimize cache contention by arraning 2K window between stack
# pointer and ap argument [np is also position sensitive vector,
# but it's assumed to be near ap, as it's allocated at ~same
# time].
&mov ("eax","ebp");
&mov ("eax","esp");
&sub ("eax","edx");
&and ("eax",2047);
&sub ("ebp","eax"); # this aligns sp and ap modulo 2048
&sub ("esp","eax"); # this aligns sp and ap modulo 2048
&xor ("edx","ebp");
&xor ("edx","esp");
&and ("edx",2048);
&xor ("edx",2048);
&sub ("ebp","edx"); # this splits them apart modulo 4096
&sub ("esp","edx"); # this splits them apart modulo 4096
&and ("ebp",-64); # align to cache line
# An OS-agnostic version of __chkstk.
#
# Some OSes (Windows) insist on stack being "wired" to
# physical memory in strictly sequential manner, i.e. if stack
# allocation spans two pages, then reference to farmost one can
# be punishable by SEGV. But page walking can do good even on
# other OSes, because it guarantees that villain thread hits
# the guard page before it can make damage to innocent one...
&mov ("eax","esp");
&sub ("eax","ebp");
&and ("eax",-4096);
&mov ("edx","esp"); # saved stack pointer!
&lea ("esp",&DWP(0,"ebp","eax"));
&mov ("eax",&DWP(0,"esp"));
&cmp ("esp","ebp");
&ja (&label("page_walk"));
&jmp (&label("page_walk_done"));
&set_label("page_walk",16);
&lea ("esp",&DWP(-4096,"esp"));
&mov ("eax",&DWP(0,"esp"));
&cmp ("esp","ebp");
&ja (&label("page_walk"));
&set_label("page_walk_done");
&and ("esp",-64); # align to cache line
################################# load argument block...
&mov ("eax",&DWP(0*4,"esi"));# BN_ULONG *rp
&mov ("ebx",&DWP(1*4,"esi"));# const BN_ULONG *ap
&mov ("ecx",&DWP(2*4,"esi"));# const BN_ULONG *bp
&mov ("ebp",&DWP(3*4,"esi"));# const BN_ULONG *np
&mov ("edx",&DWP(3*4,"esi"));# const BN_ULONG *np
&mov ("esi",&DWP(4*4,"esi"));# const BN_ULONG *n0
#&mov ("edi",&DWP(5*4,"esi"));# int num
@@ -124,11 +97,11 @@ $frame=32; # size of above frame rounded up to 16n
&mov ($_rp,"eax"); # ... save a copy of argument block
&mov ($_ap,"ebx");
&mov ($_bp,"ecx");
&mov ($_np,"ebp");
&mov ($_np,"edx");
&mov ($_n0,"esi");
&lea ($num,&DWP(-3,"edi")); # num=num-1 to assist modulo-scheduling
#&mov ($_num,$num); # redundant as $num is not reused
&mov ($_sp,"edx"); # saved stack pointer!
&mov ($_sp,"ebp"); # saved stack pointer!
if($sse2) {
$acc0="mm0"; # mmx register bank layout
@@ -294,7 +267,7 @@ if (0) {
&xor ("eax","eax"); # signal "not fast enough [yet]"
&jmp (&label("just_leave"));
# While the below code provides competitive performance for
# all key lengths on modern Intel cores, it's still more
# all key lengthes on modern Intel cores, it's still more
# than 10% slower for 4096-bit key elsewhere:-( "Competitive"
# means compared to the original integer-only assembler.
# 512-bit RSA sign is better by ~40%, but that's about all
@@ -597,16 +570,15 @@ $sbit=$num;
&jge (&label("sub"));
&sbb ("eax",0); # handle upmost overflow bit
&and ($tp,"eax");
&not ("eax");
&mov ($np,$rp);
&and ($np,"eax");
&or ($tp,$np); # tp=carry?tp:rp
&set_label("copy",16); # copy or in-place refresh
&mov ("eax",&DWP(0,$tp,$num,4));
&mov (&DWP(0,$rp,$num,4),"eax"); # rp[i]=tp[i]
&mov (&DWP($frame,"esp",$num,4),$j); # zap temporary vector
&mov ("edx",&DWP(0,$tp,$num,4));
&mov ($np,&DWP(0,$rp,$num,4));
&xor ("edx",$np); # conditional select
&and ("edx","eax");
&xor ("edx",$np);
&mov (&DWP(0,$tp,$num,4),$j) # zap temporary vector
&mov (&DWP(0,$rp,$num,4),"edx"); # rp[i]=tp[i]
&dec ($num);
&jge (&label("copy"));
@@ -618,5 +590,3 @@ $sbit=$num;
&asciz("Montgomery Multiplication for x86, CRYPTOGAMS by <appro\@openssl.org>");
&asm_finish();
close STDOUT;
@@ -80,7 +80,7 @@
: "+m"(r), "+d"(high) \
: "r"(carry), "g"(0) \
: "cc"); \
(carry) = high; \
carry = high; \
} while (0)
#define mul(r, a, word, carry) \
@@ -91,8 +91,7 @@
: "+r"(carry), "+d"(high) \
: "a"(low), "g"(0) \
: "cc"); \
(r) = (carry); \
(carry) = high; \
(r) = carry, carry = high; \
} while (0)
#undef sqr
#define sqr(r0, r1, a) asm("mulq %2" : "=a"(r0), "=d"(r1) : "a"(a) : "cc");
@@ -200,8 +199,7 @@ BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
" subq %0,%0 \n" /* clear carry */
" jmp 1f \n"
".p2align 4 \n"
"1:"
" movq (%4,%2,8),%0 \n"
"1: movq (%4,%2,8),%0 \n"
" adcq (%5,%2,8),%0 \n"
" movq %0,(%3,%2,8) \n"
" lea 1(%2),%2 \n"
@@ -227,8 +225,7 @@ BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
" subq %0,%0 \n" /* clear borrow */
" jmp 1f \n"
".p2align 4 \n"
"1:"
" movq (%4,%2,8),%0 \n"
"1: movq (%4,%2,8),%0 \n"
" sbbq (%5,%2,8),%0 \n"
" movq %0,(%3,%2,8) \n"
" lea 1(%2),%2 \n"
@@ -259,14 +256,14 @@ BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
: "cc"); \
} while (0)
#define sqr_add_c(a, i, c0, c1, c2) \
do { \
BN_ULONG t1, t2; \
asm("mulq %2" : "=a"(t1), "=d"(t2) : "a"((a)[i]) : "cc"); \
asm("addq %3,%0; adcq %4,%1; adcq %5,%2" \
: "+r"(c0), "+r"(c1), "+r"(c2) \
: "r"(t1), "r"(t2), "g"(0) \
: "cc"); \
#define sqr_add_c(a, i, c0, c1, c2) \
do { \
BN_ULONG t1, t2; \
asm("mulq %2" : "=a"(t1), "=d"(t2) : "a"(a[i]) : "cc"); \
asm("addq %3,%0; adcq %4,%1; adcq %5,%2" \
: "+r"(c0), "+r"(c1), "+r"(c2) \
: "r"(t1), "r"(t2), "g"(0) \
: "cc"); \
} while (0)
#define mul_add_c2(a, b, c0, c1, c2) \
@@ -531,12 +528,4 @@ void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a) {
r[7] = c2;
}
#undef mul_add
#undef mul
#undef sqr
#undef mul_add_c
#undef sqr_add_c
#undef mul_add_c2
#undef sqr_add_c2
#endif /* !NO_ASM && X86_64 && __GNUC__ */
@@ -47,10 +47,10 @@ $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
( $xlate="${dir}../../../perlasm/x86_64-xlate.pl" and -f $xlate) or
( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
die "can't locate x86_64-xlate.pl";
open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
open OUT,"| \"$^X\" $xlate $flavour $output";
*STDOUT=*OUT;
# In upstream, this is controlled by shelling out to the compiler to check
@@ -84,18 +84,13 @@ $code=<<___;
.type bn_mul_mont,\@function,6
.align 16
bn_mul_mont:
.cfi_startproc
mov ${num}d,${num}d
mov %rsp,%rax
.cfi_def_cfa_register %rax
test \$3,${num}d
jnz .Lmul_enter
cmp \$8,${num}d
jb .Lmul_enter
___
$code.=<<___ if ($addx);
leaq OPENSSL_ia32cap_P(%rip),%r11
mov 8(%r11),%r11d
mov OPENSSL_ia32cap_P+8(%rip),%r11d
___
$code.=<<___;
cmp $ap,$bp
@@ -107,50 +102,20 @@ $code.=<<___;
.align 16
.Lmul_enter:
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
neg $num
mov ${num}d,${num}d
lea 2($num),%r10
mov %rsp,%r11
lea -16(%rsp,$num,8),%r10 # future alloca(8*(num+2))
neg $num # restore $num
and \$-1024,%r10 # minimize TLB usage
neg %r10
lea (%rsp,%r10,8),%rsp # tp=alloca(8*(num+2))
and \$-1024,%rsp # minimize TLB usage
# An OS-agnostic version of __chkstk.
#
# Some OSes (Windows) insist on stack being "wired" to
# physical memory in strictly sequential manner, i.e. if stack
# allocation spans two pages, then reference to farmost one can
# be punishable by SEGV. But page walking can do good even on
# other OSes, because it guarantees that villain thread hits
# the guard page before it can make damage to innocent one...
sub %r10,%r11
and \$-4096,%r11
lea (%r10,%r11),%rsp
mov (%rsp),%r11
cmp %r10,%rsp
ja .Lmul_page_walk
jmp .Lmul_page_walk_done
.align 16
.Lmul_page_walk:
lea -4096(%rsp),%rsp
mov (%rsp),%r11
cmp %r10,%rsp
ja .Lmul_page_walk
.Lmul_page_walk_done:
mov %rax,8(%rsp,$num,8) # tp[num+1]=%rsp
.cfi_cfa_expression %rsp+8,$num,8,mul,plus,deref,+8
mov %r11,8(%rsp,$num,8) # tp[num+1]=%rsp
.Lmul_body:
mov $bp,%r12 # reassign $bp
___
@@ -296,51 +261,40 @@ $code.=<<___;
mov $num,$j # j=num
jmp .Lsub
.align 16
.Lsub:
sbb ($np,$i,8),%rax
.Lsub: sbb ($np,$i,8),%rax
mov %rax,($rp,$i,8) # rp[i]=tp[i]-np[i]
mov 8($ap,$i,8),%rax # tp[i+1]
lea 1($i),$i # i++
dec $j # doesnn't affect CF!
dec $j # doesn't affect CF!
jnz .Lsub
sbb \$0,%rax # handle upmost overflow bit
xor $i,$i
and %rax,$ap
not %rax
mov $rp,$np
and %rax,$np
mov $num,$j # j=num
or $np,$ap # ap=borrow?tp:rp
.align 16
.Lcopy: # copy or in-place refresh
mov ($ap,$i,8),%rax
mov (%rsp,$i,8),$ap
mov ($rp,$i,8),$np
xor $np,$ap # conditional select:
and %rax,$ap # ((ap ^ np) & %rax) ^ np
xor $np,$ap # ap = borrow?tp:rp
mov $i,(%rsp,$i,8) # zap temporary vector
mov %rax,($rp,$i,8) # rp[i]=tp[i]
mov $ap,($rp,$i,8) # rp[i]=tp[i]
lea 1($i),$i
sub \$1,$j
jnz .Lcopy
mov 8(%rsp,$num,8),%rsi # restore %rsp
.cfi_def_cfa %rsi,8
mov \$1,%rax
mov -48(%rsi),%r15
.cfi_restore %r15
mov -40(%rsi),%r14
.cfi_restore %r14
mov -32(%rsi),%r13
.cfi_restore %r13
mov -24(%rsi),%r12
.cfi_restore %r12
mov -16(%rsi),%rbp
.cfi_restore %rbp
mov -8(%rsi),%rbx
.cfi_restore %rbx
lea (%rsi),%rsp
.cfi_def_cfa_register %rsp
mov (%rsi),%r15
mov 8(%rsi),%r14
mov 16(%rsi),%r13
mov 24(%rsi),%r12
mov 32(%rsi),%rbp
mov 40(%rsi),%rbx
lea 48(%rsi),%rsp
.Lmul_epilogue:
ret
.cfi_endproc
.size bn_mul_mont,.-bn_mul_mont
___
{{{
@@ -350,10 +304,6 @@ $code.=<<___;
.type bn_mul4x_mont,\@function,6
.align 16
bn_mul4x_mont:
.cfi_startproc
mov ${num}d,${num}d
mov %rsp,%rax
.cfi_def_cfa_register %rax
.Lmul4x_enter:
___
$code.=<<___ if ($addx);
@@ -363,41 +313,20 @@ $code.=<<___ if ($addx);
___
$code.=<<___;
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
neg $num
mov ${num}d,${num}d
lea 4($num),%r10
mov %rsp,%r11
lea -32(%rsp,$num,8),%r10 # future alloca(8*(num+4))
neg $num # restore
and \$-1024,%r10 # minimize TLB usage
neg %r10
lea (%rsp,%r10,8),%rsp # tp=alloca(8*(num+4))
and \$-1024,%rsp # minimize TLB usage
sub %r10,%r11
and \$-4096,%r11
lea (%r10,%r11),%rsp
mov (%rsp),%r11
cmp %r10,%rsp
ja .Lmul4x_page_walk
jmp .Lmul4x_page_walk_done
.Lmul4x_page_walk:
lea -4096(%rsp),%rsp
mov (%rsp),%r11
cmp %r10,%rsp
ja .Lmul4x_page_walk
.Lmul4x_page_walk_done:
mov %rax,8(%rsp,$num,8) # tp[num+1]=%rsp
.cfi_cfa_expression %rsp+8,$num,8,mul,plus,deref,+8
mov %r11,8(%rsp,$num,8) # tp[num+1]=%rsp
.Lmul4x_body:
mov $rp,16(%rsp,$num,8) # tp[num+2]=$rp
mov %rdx,%r12 # reassign $bp
@@ -704,11 +633,9 @@ ___
my @ri=("%rax","%rdx",$m0,$m1);
$code.=<<___;
mov 16(%rsp,$num,8),$rp # restore $rp
lea -4($num),$j
mov 0(%rsp),@ri[0] # tp[0]
pxor %xmm0,%xmm0
mov 8(%rsp),@ri[1] # tp[1]
shr \$2,$j # j=num/4-1
shr \$2,$num # num/=4
lea (%rsp),$ap # borrow ap for tp
xor $i,$i # i=0 and clear CF!
@@ -716,6 +643,7 @@ $code.=<<___;
mov 16($ap),@ri[2] # tp[2]
mov 24($ap),@ri[3] # tp[3]
sbb 8($np),@ri[1]
lea -1($num),$j # j=num/4-1
jmp .Lsub4x
.align 16
.Lsub4x:
@@ -743,58 +671,50 @@ $code.=<<___;
mov @ri[2],16($rp,$i,8) # rp[i]=tp[i]-np[i]
sbb \$0,@ri[0] # handle upmost overflow bit
mov @ri[0],%xmm0
punpcklqdq %xmm0,%xmm0 # extend mask to 128 bits
mov @ri[3],24($rp,$i,8) # rp[i]=tp[i]-np[i]
xor $i,$i # i=0
and @ri[0],$ap
not @ri[0]
mov $rp,$np
and @ri[0],$np
lea -4($num),$j
or $np,$ap # ap=borrow?tp:rp
shr \$2,$j # j=num/4-1
movdqu ($ap),%xmm1
movdqa %xmm0,(%rsp)
movdqu %xmm1,($rp)
mov $num,$j
pxor %xmm5,%xmm5
jmp .Lcopy4x
.align 16
.Lcopy4x: # copy or in-place refresh
movdqu 16($ap,$i),%xmm2
movdqu 32($ap,$i),%xmm1
movdqa %xmm0,16(%rsp,$i)
movdqu %xmm2,16($rp,$i)
movdqa %xmm0,32(%rsp,$i)
movdqu %xmm1,32($rp,$i)
.Lcopy4x: # copy or in-place refresh
movdqu (%rsp,$i),%xmm2
movdqu 16(%rsp,$i),%xmm4
movdqu ($rp,$i),%xmm1
movdqu 16($rp,$i),%xmm3
pxor %xmm1,%xmm2 # conditional select
pxor %xmm3,%xmm4
pand %xmm0,%xmm2
pand %xmm0,%xmm4
pxor %xmm1,%xmm2
pxor %xmm3,%xmm4
movdqu %xmm2,($rp,$i)
movdqu %xmm4,16($rp,$i)
movdqa %xmm5,(%rsp,$i) # zap temporary vectors
movdqa %xmm5,16(%rsp,$i)
lea 32($i),$i
dec $j
jnz .Lcopy4x
movdqu 16($ap,$i),%xmm2
movdqa %xmm0,16(%rsp,$i)
movdqu %xmm2,16($rp,$i)
shl \$2,$num
___
}
$code.=<<___;
mov 8(%rsp,$num,8),%rsi # restore %rsp
.cfi_def_cfa %rsi, 8
mov \$1,%rax
mov -48(%rsi),%r15
.cfi_restore %r15
mov -40(%rsi),%r14
.cfi_restore %r14
mov -32(%rsi),%r13
.cfi_restore %r13
mov -24(%rsi),%r12
.cfi_restore %r12
mov -16(%rsi),%rbp
.cfi_restore %rbp
mov -8(%rsi),%rbx
.cfi_restore %rbx
lea (%rsi),%rsp
.cfi_def_cfa_register %rsp
mov (%rsi),%r15
mov 8(%rsi),%r14
mov 16(%rsi),%r13
mov 24(%rsi),%r12
mov 32(%rsi),%rbp
mov 40(%rsi),%rbx
lea 48(%rsi),%rsp
.Lmul4x_epilogue:
ret
.cfi_endproc
.size bn_mul4x_mont,.-bn_mul4x_mont
___
}}}
@@ -822,23 +742,14 @@ $code.=<<___;
.type bn_sqr8x_mont,\@function,6
.align 32
bn_sqr8x_mont:
.cfi_startproc
mov %rsp,%rax
.cfi_def_cfa_register %rax
.Lsqr8x_enter:
mov %rsp,%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
.Lsqr8x_prologue:
mov ${num}d,%r10d
shl \$3,${num}d # convert $num to bytes
@@ -851,49 +762,30 @@ bn_sqr8x_mont:
# do its job.
#
lea -64(%rsp,$num,2),%r11
mov %rsp,%rbp
mov ($n0),$n0 # *n0
sub $aptr,%r11
and \$4095,%r11
cmp %r11,%r10
jb .Lsqr8x_sp_alt
sub %r11,%rbp # align with $aptr
lea -64(%rbp,$num,2),%rbp # future alloca(frame+2*$num)
sub %r11,%rsp # align with $aptr
lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num)
jmp .Lsqr8x_sp_done
.align 32
.Lsqr8x_sp_alt:
lea 4096-64(,$num,2),%r10 # 4096-frame-2*$num
lea -64(%rbp,$num,2),%rbp # future alloca(frame+2*$num)
lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num)
sub %r10,%r11
mov \$0,%r10
cmovc %r10,%r11
sub %r11,%rbp
sub %r11,%rsp
.Lsqr8x_sp_done:
and \$-64,%rbp
mov %rsp,%r11
sub %rbp,%r11
and \$-4096,%r11
lea (%rbp,%r11),%rsp
mov (%rsp),%r10
cmp %rbp,%rsp
ja .Lsqr8x_page_walk
jmp .Lsqr8x_page_walk_done
.align 16
.Lsqr8x_page_walk:
lea -4096(%rsp),%rsp
mov (%rsp),%r10
cmp %rbp,%rsp
ja .Lsqr8x_page_walk
.Lsqr8x_page_walk_done:
and \$-64,%rsp
mov $num,%r10
neg $num
mov $n0, 32(%rsp)
mov %rax, 40(%rsp) # save original %rsp
.cfi_cfa_expression %rsp+40,deref,+8
.Lsqr8x_body:
movq $nptr, %xmm2 # save pointer to modulus
@@ -902,8 +794,7 @@ bn_sqr8x_mont:
movq %r10, %xmm3 # -$num
___
$code.=<<___ if ($addx);
leaq OPENSSL_ia32cap_P(%rip),%rax
mov 8(%rax),%eax
mov OPENSSL_ia32cap_P+8(%rip),%eax
and \$0x80100,%eax
cmp \$0x80100,%eax
jne .Lsqr8x_nox
@@ -964,7 +855,6 @@ $code.=<<___;
pxor %xmm0,%xmm0
pshufd \$0,%xmm1,%xmm1
mov 40(%rsp),%rsi # restore %rsp
.cfi_def_cfa %rsi,8
jmp .Lsqr8x_cond_copy
.align 32
@@ -994,22 +884,14 @@ $code.=<<___;
mov \$1,%rax
mov -48(%rsi),%r15
.cfi_restore %r15
mov -40(%rsi),%r14
.cfi_restore %r14
mov -32(%rsi),%r13
.cfi_restore %r13
mov -24(%rsi),%r12
.cfi_restore %r12
mov -16(%rsi),%rbp
.cfi_restore %rbp
mov -8(%rsi),%rbx
.cfi_restore %rbx
lea (%rsi),%rsp
.cfi_def_cfa_register %rsp
.Lsqr8x_epilogue:
ret
.cfi_endproc
.size bn_sqr8x_mont,.-bn_sqr8x_mont
___
}}}
@@ -1021,48 +903,23 @@ $code.=<<___;
.type bn_mulx4x_mont,\@function,6
.align 32
bn_mulx4x_mont:
.cfi_startproc
mov %rsp,%rax
.cfi_def_cfa_register %rax
.Lmulx4x_enter:
mov %rsp,%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
.Lmulx4x_prologue:
shl \$3,${num}d # convert $num to bytes
.byte 0x67
xor %r10,%r10
sub $num,%r10 # -$num
mov ($n0),$n0 # *n0
lea -72(%rsp,%r10),%rbp # future alloca(frame+$num+8)
and \$-128,%rbp
mov %rsp,%r11
sub %rbp,%r11
and \$-4096,%r11
lea (%rbp,%r11),%rsp
mov (%rsp),%r10
cmp %rbp,%rsp
ja .Lmulx4x_page_walk
jmp .Lmulx4x_page_walk_done
.align 16
.Lmulx4x_page_walk:
lea -4096(%rsp),%rsp
mov (%rsp),%r10
cmp %rbp,%rsp
ja .Lmulx4x_page_walk
.Lmulx4x_page_walk_done:
lea -72(%rsp,%r10),%rsp # alloca(frame+$num+8)
lea ($bp,$num),%r10
and \$-128,%rsp
##############################################################
# Stack layout
# +0 num
@@ -1082,7 +939,6 @@ bn_mulx4x_mont:
mov $n0, 24(%rsp) # save *n0
mov $rp, 32(%rsp) # save $rp
mov %rax,40(%rsp) # save original %rsp
.cfi_cfa_expression %rsp+40,deref,+8
mov $num,48(%rsp) # inner counter
jmp .Lmulx4x_body
@@ -1203,17 +1059,18 @@ $code.=<<___;
mulx 2*8($aptr),%r15,%r13 # ...
adox -3*8($tptr),%r11
adcx %r15,%r12
adox -2*8($tptr),%r12
adox $zero,%r12
adcx $zero,%r13
adox $zero,%r13
mov $bptr,8(%rsp) # off-load &b[i]
.byte 0x67
mov $mi,%r15
imulq 24(%rsp),$mi # "t[0]"*n0
xor %ebp,%ebp # xor $zero,$zero # cf=0, of=0
mulx 3*8($aptr),%rax,%r14
mov $mi,%rdx
adox -2*8($tptr),%r12
adcx %rax,%r13
adox -1*8($tptr),%r13
adcx $zero,%r14
@@ -1332,7 +1189,6 @@ $code.=<<___;
pxor %xmm0,%xmm0
pshufd \$0,%xmm1,%xmm1
mov 40(%rsp),%rsi # restore %rsp
.cfi_def_cfa %rsi,8
jmp .Lmulx4x_cond_copy
.align 32
@@ -1362,22 +1218,14 @@ $code.=<<___;
mov \$1,%rax
mov -48(%rsi),%r15
.cfi_restore %r15
mov -40(%rsi),%r14
.cfi_restore %r14
mov -32(%rsi),%r13
.cfi_restore %r13
mov -24(%rsi),%r12
.cfi_restore %r12
mov -16(%rsi),%rbp
.cfi_restore %rbp
mov -8(%rsi),%rbx
.cfi_restore %rbx
lea (%rsi),%rsp
.cfi_def_cfa_register %rsp
.Lmulx4x_epilogue:
ret
.cfi_endproc
.size bn_mulx4x_mont,.-bn_mulx4x_mont
___
}}}
@@ -1430,8 +1278,22 @@ mul_handler:
mov 192($context),%r10 # pull $num
mov 8(%rax,%r10,8),%rax # pull saved stack pointer
lea 48(%rax),%rax
jmp .Lcommon_pop_regs
mov -8(%rax),%rbx
mov -16(%rax),%rbp
mov -24(%rax),%r12
mov -32(%rax),%r13
mov -40(%rax),%r14
mov -48(%rax),%r15
mov %rbx,144($context) # restore context->Rbx
mov %rbp,160($context) # restore context->Rbp
mov %r12,216($context) # restore context->R12
mov %r13,224($context) # restore context->R13
mov %r14,232($context) # restore context->R14
mov %r15,240($context) # restore context->R15
jmp .Lcommon_seh_tail
.size mul_handler,.-mul_handler
.type sqr_handler,\@abi-omnipotent
@@ -1456,24 +1318,18 @@ sqr_handler:
mov 0(%r11),%r10d # HandlerData[0]
lea (%rsi,%r10),%r10 # end of prologue label
cmp %r10,%rbx # context->Rip<.Lsqr_prologue
jb .Lcommon_seh_tail
mov 4(%r11),%r10d # HandlerData[1]
lea (%rsi,%r10),%r10 # body label
cmp %r10,%rbx # context->Rip<.Lsqr_body
jb .Lcommon_pop_regs
jb .Lcommon_seh_tail
mov 152($context),%rax # pull context->Rsp
mov 8(%r11),%r10d # HandlerData[2]
mov 4(%r11),%r10d # HandlerData[1]
lea (%rsi,%r10),%r10 # epilogue label
cmp %r10,%rbx # context->Rip>=.Lsqr_epilogue
jae .Lcommon_seh_tail
mov 40(%rax),%rax # pull saved stack pointer
.Lcommon_pop_regs:
mov -8(%rax),%rbx
mov -16(%rax),%rbp
mov -24(%rax),%r12
@@ -1560,15 +1416,13 @@ $code.=<<___;
.LSEH_info_bn_sqr8x_mont:
.byte 9,0,0,0
.rva sqr_handler
.rva .Lsqr8x_prologue,.Lsqr8x_body,.Lsqr8x_epilogue # HandlerData[]
.align 8
.rva .Lsqr8x_body,.Lsqr8x_epilogue # HandlerData[]
___
$code.=<<___ if ($addx);
.LSEH_info_bn_mulx4x_mont:
.byte 9,0,0,0
.rva sqr_handler
.rva .Lmulx4x_prologue,.Lmulx4x_body,.Lmulx4x_epilogue # HandlerData[]
.align 8
.rva .Lmulx4x_body,.Lmulx4x_epilogue # HandlerData[]
___
}
@@ -32,10 +32,10 @@ $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
( $xlate="${dir}../../../perlasm/x86_64-xlate.pl" and -f $xlate) or
( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
die "can't locate x86_64-xlate.pl";
open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
open OUT,"| \"$^X\" $xlate $flavour $output";
*STDOUT=*OUT;
# In upstream, this is controlled by shelling out to the compiler to check
@@ -73,70 +73,35 @@ $code=<<___;
.type bn_mul_mont_gather5,\@function,6
.align 64
bn_mul_mont_gather5:
.cfi_startproc
mov ${num}d,${num}d
mov %rsp,%rax
.cfi_def_cfa_register %rax
test \$7,${num}d
jnz .Lmul_enter
___
$code.=<<___ if ($addx);
leaq OPENSSL_ia32cap_P(%rip),%r11
mov 8(%r11),%r11d
mov OPENSSL_ia32cap_P+8(%rip),%r11d
___
$code.=<<___;
jmp .Lmul4x_enter
.align 16
.Lmul_enter:
mov ${num}d,${num}d
mov %rsp,%rax
movd `($win64?56:8)`(%rsp),%xmm5 # load 7th argument
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
neg $num
mov %rsp,%r11
lea -280(%rsp,$num,8),%r10 # future alloca(8*(num+2)+256+8)
neg $num # restore $num
and \$-1024,%r10 # minimize TLB usage
# An OS-agnostic version of __chkstk.
#
# Some OSes (Windows) insist on stack being "wired" to
# physical memory in strictly sequential manner, i.e. if stack
# allocation spans two pages, then reference to farmost one can
# be punishable by SEGV. But page walking can do good even on
# other OSes, because it guarantees that villain thread hits
# the guard page before it can make damage to innocent one...
sub %r10,%r11
and \$-4096,%r11
lea (%r10,%r11),%rsp
mov (%rsp),%r11
cmp %r10,%rsp
ja .Lmul_page_walk
jmp .Lmul_page_walk_done
.Lmul_page_walk:
lea -4096(%rsp),%rsp
mov (%rsp),%r11
cmp %r10,%rsp
ja .Lmul_page_walk
.Lmul_page_walk_done:
lea .Linc(%rip),%r10
mov %rax,8(%rsp,$num,8) # tp[num+1]=%rsp
.cfi_cfa_expression %rsp+8,$num,8,mul,plus,deref,+8
.Lmul_body:
push %rbx
push %rbp
push %r12
push %r13
push %r14
push %r15
lea 2($num),%r11
neg %r11
lea -264(%rsp,%r11,8),%rsp # tp=alloca(8*(num+2)+256+8)
and \$-1024,%rsp # minimize TLB usage
mov %rax,8(%rsp,$num,8) # tp[num+1]=%rsp
.Lmul_body:
lea 128($bp),%r12 # reassign $bp (+size optimization)
___
$bp="%r12";
@@ -396,8 +361,7 @@ $code.=<<___;
mov $num,$j # j=num
jmp .Lsub
.align 16
.Lsub:
sbb ($np,$i,8),%rax
.Lsub: sbb ($np,$i,8),%rax
mov %rax,($rp,$i,8) # rp[i]=tp[i]-np[i]
mov 8($ap,$i,8),%rax # tp[i+1]
lea 1($i),$i # i++
@@ -406,42 +370,32 @@ $code.=<<___;
sbb \$0,%rax # handle upmost overflow bit
xor $i,$i
and %rax,$ap
not %rax
mov $rp,$np
and %rax,$np
mov $num,$j # j=num
or $np,$ap # ap=borrow?tp:rp
.align 16
.Lcopy: # copy or in-place refresh
mov ($ap,$i,8),%rax
mov (%rsp,$i,8),$ap
mov ($rp,$i,8),$np
xor $np,$ap # conditional select:
and %rax,$ap # ((ap ^ np) & %rax) ^ np
xor $np,$ap # ap = borrow?tp:rp
mov $i,(%rsp,$i,8) # zap temporary vector
mov %rax,($rp,$i,8) # rp[i]=tp[i]
mov $ap,($rp,$i,8) # rp[i]=tp[i]
lea 1($i),$i
sub \$1,$j
jnz .Lcopy
mov 8(%rsp,$num,8),%rsi # restore %rsp
.cfi_def_cfa %rsi,8
mov \$1,%rax
mov -48(%rsi),%r15
.cfi_restore %r15
mov -40(%rsi),%r14
.cfi_restore %r14
mov -32(%rsi),%r13
.cfi_restore %r13
mov -24(%rsi),%r12
.cfi_restore %r12
mov -16(%rsi),%rbp
.cfi_restore %rbp
mov -8(%rsi),%rbx
.cfi_restore %rbx
lea (%rsi),%rsp
.cfi_def_cfa_register %rsp
.Lmul_epilogue:
ret
.cfi_endproc
.size bn_mul_mont_gather5,.-bn_mul_mont_gather5
___
{{{
@@ -451,10 +405,6 @@ $code.=<<___;
.type bn_mul4x_mont_gather5,\@function,6
.align 32
bn_mul4x_mont_gather5:
.cfi_startproc
.byte 0x67
mov %rsp,%rax
.cfi_def_cfa_register %rax
.Lmul4x_enter:
___
$code.=<<___ if ($addx);
@@ -463,19 +413,14 @@ $code.=<<___ if ($addx);
je .Lmulx4x_enter
___
$code.=<<___;
.byte 0x67
mov %rsp,%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
.Lmul4x_prologue:
.byte 0x67
shl \$3,${num}d # convert $num to bytes
@@ -492,70 +437,43 @@ $code.=<<___;
# calculated from 7th argument, the index.]
#
lea -320(%rsp,$num,2),%r11
mov %rsp,%rbp
sub $rp,%r11
and \$4095,%r11
cmp %r11,%r10
jb .Lmul4xsp_alt
sub %r11,%rbp # align with $rp
lea -320(%rbp,$num,2),%rbp # future alloca(frame+2*num*8+256)
sub %r11,%rsp # align with $rp
lea -320(%rsp,$num,2),%rsp # alloca(frame+2*num*8+256)
jmp .Lmul4xsp_done
.align 32
.Lmul4xsp_alt:
lea 4096-320(,$num,2),%r10
lea -320(%rbp,$num,2),%rbp # future alloca(frame+2*num*8+256)
lea -320(%rsp,$num,2),%rsp # alloca(frame+2*num*8+256)
sub %r10,%r11
mov \$0,%r10
cmovc %r10,%r11
sub %r11,%rbp
sub %r11,%rsp
.Lmul4xsp_done:
and \$-64,%rbp
mov %rsp,%r11
sub %rbp,%r11
and \$-4096,%r11
lea (%rbp,%r11),%rsp
mov (%rsp),%r10
cmp %rbp,%rsp
ja .Lmul4x_page_walk
jmp .Lmul4x_page_walk_done
.Lmul4x_page_walk:
lea -4096(%rsp),%rsp
mov (%rsp),%r10
cmp %rbp,%rsp
ja .Lmul4x_page_walk
.Lmul4x_page_walk_done:
and \$-64,%rsp
neg $num
mov %rax,40(%rsp)
.cfi_cfa_expression %rsp+40,deref,+8
.Lmul4x_body:
call mul4x_internal
mov 40(%rsp),%rsi # restore %rsp
.cfi_def_cfa %rsi,8
mov \$1,%rax
mov -48(%rsi),%r15
.cfi_restore %r15
mov -40(%rsi),%r14
.cfi_restore %r14
mov -32(%rsi),%r13
.cfi_restore %r13
mov -24(%rsi),%r12
.cfi_restore %r12
mov -16(%rsi),%rbp
.cfi_restore %rbp
mov -8(%rsi),%rbx
.cfi_restore %rbx
lea (%rsi),%rsp
.cfi_def_cfa_register %rsp
.Lmul4x_epilogue:
ret
.cfi_endproc
.size bn_mul4x_mont_gather5,.-bn_mul4x_mont_gather5
.type mul4x_internal,\@abi-omnipotent
@@ -1067,7 +985,7 @@ my $bptr="%rdx"; # const void *table,
my $nptr="%rcx"; # const BN_ULONG *nptr,
my $n0 ="%r8"; # const BN_ULONG *n0);
my $num ="%r9"; # int num, has to be divisible by 8
# int pwr
# int pwr
my ($i,$j,$tptr)=("%rbp","%rcx",$rptr);
my @A0=("%r10","%r11");
@@ -1079,31 +997,21 @@ $code.=<<___;
.type bn_power5,\@function,6
.align 32
bn_power5:
.cfi_startproc
mov %rsp,%rax
.cfi_def_cfa_register %rax
___
$code.=<<___ if ($addx);
leaq OPENSSL_ia32cap_P(%rip),%r11
mov 8(%r11),%r11d
mov OPENSSL_ia32cap_P+8(%rip),%r11d
and \$0x80108,%r11d
cmp \$0x80108,%r11d # check for AD*X+BMI2+BMI1
je .Lpowerx5_enter
___
$code.=<<___;
mov %rsp,%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
.Lpower5_prologue:
shl \$3,${num}d # convert $num to bytes
lea ($num,$num,2),%r10d # 3*$num
@@ -1118,42 +1026,25 @@ $code.=<<___;
# calculated from 7th argument, the index.]
#
lea -320(%rsp,$num,2),%r11
mov %rsp,%rbp
sub $rptr,%r11
and \$4095,%r11
cmp %r11,%r10
jb .Lpwr_sp_alt
sub %r11,%rbp # align with $aptr
lea -320(%rbp,$num,2),%rbp # future alloca(frame+2*num*8+256)
sub %r11,%rsp # align with $aptr
lea -320(%rsp,$num,2),%rsp # alloca(frame+2*num*8+256)
jmp .Lpwr_sp_done
.align 32
.Lpwr_sp_alt:
lea 4096-320(,$num,2),%r10
lea -320(%rbp,$num,2),%rbp # future alloca(frame+2*num*8+256)
lea -320(%rsp,$num,2),%rsp # alloca(frame+2*num*8+256)
sub %r10,%r11
mov \$0,%r10
cmovc %r10,%r11
sub %r11,%rbp
sub %r11,%rsp
.Lpwr_sp_done:
and \$-64,%rbp
mov %rsp,%r11
sub %rbp,%r11
and \$-4096,%r11
lea (%rbp,%r11),%rsp
mov (%rsp),%r10
cmp %rbp,%rsp
ja .Lpwr_page_walk
jmp .Lpwr_page_walk_done
.Lpwr_page_walk:
lea -4096(%rsp),%rsp
mov (%rsp),%r10
cmp %rbp,%rsp
ja .Lpwr_page_walk
.Lpwr_page_walk_done:
mov $num,%r10
and \$-64,%rsp
mov $num,%r10
neg $num
##############################################################
@@ -1167,7 +1058,6 @@ $code.=<<___;
#
mov $n0, 32(%rsp)
mov %rax, 40(%rsp) # save original %rsp
.cfi_cfa_expression %rsp+40,deref,+8
.Lpower5_body:
movq $rptr,%xmm1 # save $rptr, used in sqr8x
movq $nptr,%xmm2 # save $nptr
@@ -1194,25 +1084,16 @@ $code.=<<___;
call mul4x_internal
mov 40(%rsp),%rsi # restore %rsp
.cfi_def_cfa %rsi,8
mov \$1,%rax
mov -48(%rsi),%r15
.cfi_restore %r15
mov -40(%rsi),%r14
.cfi_restore %r14
mov -32(%rsi),%r13
.cfi_restore %r13
mov -24(%rsi),%r12
.cfi_restore %r12
mov -16(%rsi),%rbp
.cfi_restore %rbp
mov -8(%rsi),%rbx
.cfi_restore %rbx
lea (%rsi),%rsp
.cfi_def_cfa_register %rsp
.Lpower5_epilogue:
ret
.cfi_endproc
.size bn_power5,.-bn_power5
.globl bn_sqr8x_internal
@@ -1971,7 +1852,6 @@ __bn_sqr8x_reduction:
.align 32
.L8x_tail_done:
xor %rax,%rax
add (%rdx),%r8 # can this overflow?
adc \$0,%r9
adc \$0,%r10
@@ -1979,8 +1859,10 @@ __bn_sqr8x_reduction:
adc \$0,%r12
adc \$0,%r13
adc \$0,%r14
adc \$0,%r15
adc \$0,%rax
adc \$0,%r15 # can't overflow, because we
# started with "overhung" part
# of multiplication
xor %rax,%rax
neg $carry
.L8x_no_tail:
@@ -2072,7 +1954,7 @@ __bn_post4x_internal:
jnz .Lsqr4x_sub
mov $num,%r10 # prepare for back-to-back call
neg $num # restore $num
neg $num # restore $num
ret
.size __bn_post4x_internal,.-__bn_post4x_internal
___
@@ -2092,23 +1974,14 @@ bn_from_montgomery:
.type bn_from_mont8x,\@function,6
.align 32
bn_from_mont8x:
.cfi_startproc
.byte 0x67
mov %rsp,%rax
.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
.Lfrom_prologue:
shl \$3,${num}d # convert $num to bytes
lea ($num,$num,2),%r10 # 3*$num in bytes
@@ -2123,42 +1996,25 @@ bn_from_mont8x:
# last operation, we use the opportunity to cleanse it.
#
lea -320(%rsp,$num,2),%r11
mov %rsp,%rbp
sub $rptr,%r11
and \$4095,%r11
cmp %r11,%r10
jb .Lfrom_sp_alt
sub %r11,%rbp # align with $aptr
lea -320(%rbp,$num,2),%rbp # future alloca(frame+2*$num*8+256)
sub %r11,%rsp # align with $aptr
lea -320(%rsp,$num,2),%rsp # alloca(frame+2*$num*8+256)
jmp .Lfrom_sp_done
.align 32
.Lfrom_sp_alt:
lea 4096-320(,$num,2),%r10
lea -320(%rbp,$num,2),%rbp # future alloca(frame+2*$num*8+256)
lea -320(%rsp,$num,2),%rsp # alloca(frame+2*$num*8+256)
sub %r10,%r11
mov \$0,%r10
cmovc %r10,%r11
sub %r11,%rbp
sub %r11,%rsp
.Lfrom_sp_done:
and \$-64,%rbp
mov %rsp,%r11
sub %rbp,%r11
and \$-4096,%r11
lea (%rbp,%r11),%rsp
mov (%rsp),%r10
cmp %rbp,%rsp
ja .Lfrom_page_walk
jmp .Lfrom_page_walk_done
.Lfrom_page_walk:
lea -4096(%rsp),%rsp
mov (%rsp),%r10
cmp %rbp,%rsp
ja .Lfrom_page_walk
.Lfrom_page_walk_done:
mov $num,%r10
and \$-64,%rsp
mov $num,%r10
neg $num
##############################################################
@@ -2172,7 +2028,6 @@ bn_from_mont8x:
#
mov $n0, 32(%rsp)
mov %rax, 40(%rsp) # save original %rsp
.cfi_cfa_expression %rsp+40,deref,+8
.Lfrom_body:
mov $num,%r11
lea 48(%rsp),%rax
@@ -2205,8 +2060,7 @@ bn_from_mont8x:
movq %r10, %xmm3 # -num
___
$code.=<<___ if ($addx);
leaq OPENSSL_ia32cap_P(%rip),%r11
mov 8(%r11),%r11d
mov OPENSSL_ia32cap_P+8(%rip),%r11d
and \$0x80108,%r11d
cmp \$0x80108,%r11d # check for AD*X+BMI2+BMI1
jne .Lfrom_mont_nox
@@ -2217,6 +2071,7 @@ $code.=<<___ if ($addx);
pxor %xmm0,%xmm0
lea 48(%rsp),%rax
mov 40(%rsp),%rsi # restore %rsp
jmp .Lfrom_mont_zero
.align 32
@@ -2228,12 +2083,11 @@ $code.=<<___;
pxor %xmm0,%xmm0
lea 48(%rsp),%rax
mov 40(%rsp),%rsi # restore %rsp
jmp .Lfrom_mont_zero
.align 32
.Lfrom_mont_zero:
mov 40(%rsp),%rsi # restore %rsp
.cfi_def_cfa %rsi,8
movdqa %xmm0,16*0(%rax)
movdqa %xmm0,16*1(%rax)
movdqa %xmm0,16*2(%rax)
@@ -2244,22 +2098,14 @@ $code.=<<___;
mov \$1,%rax
mov -48(%rsi),%r15
.cfi_restore %r15
mov -40(%rsi),%r14
.cfi_restore %r14
mov -32(%rsi),%r13
.cfi_restore %r13
mov -24(%rsi),%r12
.cfi_restore %r12
mov -16(%rsi),%rbp
.cfi_restore %rbp
mov -8(%rsi),%rbx
.cfi_restore %rbx
lea (%rsi),%rsp
.cfi_def_cfa_register %rsp
.Lfrom_epilogue:
ret
.cfi_endproc
.size bn_from_mont8x,.-bn_from_mont8x
___
}
@@ -2272,23 +2118,14 @@ $code.=<<___;
.type bn_mulx4x_mont_gather5,\@function,6
.align 32
bn_mulx4x_mont_gather5:
.cfi_startproc
mov %rsp,%rax
.cfi_def_cfa_register %rax
.Lmulx4x_enter:
mov %rsp,%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
.Lmulx4x_prologue:
shl \$3,${num}d # convert $num to bytes
lea ($num,$num,2),%r10 # 3*$num in bytes
@@ -2305,40 +2142,23 @@ bn_mulx4x_mont_gather5:
# calculated from 7th argument, the index.]
#
lea -320(%rsp,$num,2),%r11
mov %rsp,%rbp
sub $rp,%r11
and \$4095,%r11
cmp %r11,%r10
jb .Lmulx4xsp_alt
sub %r11,%rbp # align with $aptr
lea -320(%rbp,$num,2),%rbp # future alloca(frame+2*$num*8+256)
sub %r11,%rsp # align with $aptr
lea -320(%rsp,$num,2),%rsp # alloca(frame+2*$num*8+256)
jmp .Lmulx4xsp_done
.Lmulx4xsp_alt:
lea 4096-320(,$num,2),%r10
lea -320(%rbp,$num,2),%rbp # future alloca(frame+2*$num*8+256)
lea -320(%rsp,$num,2),%rsp # alloca(frame+2*$num*8+256)
sub %r10,%r11
mov \$0,%r10
cmovc %r10,%r11
sub %r11,%rbp
.Lmulx4xsp_done:
and \$-64,%rbp # ensure alignment
mov %rsp,%r11
sub %rbp,%r11
and \$-4096,%r11
lea (%rbp,%r11),%rsp
mov (%rsp),%r10
cmp %rbp,%rsp
ja .Lmulx4x_page_walk
jmp .Lmulx4x_page_walk_done
.Lmulx4x_page_walk:
lea -4096(%rsp),%rsp
mov (%rsp),%r10
cmp %rbp,%rsp
ja .Lmulx4x_page_walk
.Lmulx4x_page_walk_done:
sub %r11,%rsp
.Lmulx4xsp_done:
and \$-64,%rsp # ensure alignment
##############################################################
# Stack layout
# +0 -num
@@ -2353,31 +2173,21 @@ bn_mulx4x_mont_gather5:
#
mov $n0, 32(%rsp) # save *n0
mov %rax,40(%rsp) # save original %rsp
.cfi_cfa_expression %rsp+40,deref,+8
.Lmulx4x_body:
call mulx4x_internal
mov 40(%rsp),%rsi # restore %rsp
.cfi_def_cfa %rsi,8
mov \$1,%rax
mov -48(%rsi),%r15
.cfi_restore %r15
mov -40(%rsi),%r14
.cfi_restore %r14
mov -32(%rsi),%r13
.cfi_restore %r13
mov -24(%rsi),%r12
.cfi_restore %r12
mov -16(%rsi),%rbp
.cfi_restore %rbp
mov -8(%rsi),%rbx
.cfi_restore %rbx
lea (%rsi),%rsp
.cfi_def_cfa_register %rsp
.Lmulx4x_epilogue:
ret
.cfi_endproc
.size bn_mulx4x_mont_gather5,.-bn_mulx4x_mont_gather5
.type mulx4x_internal,\@abi-omnipotent
@@ -2755,23 +2565,14 @@ $code.=<<___;
.type bn_powerx5,\@function,6
.align 32
bn_powerx5:
.cfi_startproc
mov %rsp,%rax
.cfi_def_cfa_register %rax
.Lpowerx5_enter:
mov %rsp,%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
.Lpowerx5_prologue:
shl \$3,${num}d # convert $num to bytes
lea ($num,$num,2),%r10 # 3*$num in bytes
@@ -2786,42 +2587,25 @@ bn_powerx5:
# calculated from 7th argument, the index.]
#
lea -320(%rsp,$num,2),%r11
mov %rsp,%rbp
sub $rptr,%r11
and \$4095,%r11
cmp %r11,%r10
jb .Lpwrx_sp_alt
sub %r11,%rbp # align with $aptr
lea -320(%rbp,$num,2),%rbp # future alloca(frame+2*$num*8+256)
sub %r11,%rsp # align with $aptr
lea -320(%rsp,$num,2),%rsp # alloca(frame+2*$num*8+256)
jmp .Lpwrx_sp_done
.align 32
.Lpwrx_sp_alt:
lea 4096-320(,$num,2),%r10
lea -320(%rbp,$num,2),%rbp # alloca(frame+2*$num*8+256)
lea -320(%rsp,$num,2),%rsp # alloca(frame+2*$num*8+256)
sub %r10,%r11
mov \$0,%r10
cmovc %r10,%r11
sub %r11,%rbp
sub %r11,%rsp
.Lpwrx_sp_done:
and \$-64,%rbp
mov %rsp,%r11
sub %rbp,%r11
and \$-4096,%r11
lea (%rbp,%r11),%rsp
mov (%rsp),%r10
cmp %rbp,%rsp
ja .Lpwrx_page_walk
jmp .Lpwrx_page_walk_done
.Lpwrx_page_walk:
lea -4096(%rsp),%rsp
mov (%rsp),%r10
cmp %rbp,%rsp
ja .Lpwrx_page_walk
.Lpwrx_page_walk_done:
mov $num,%r10
and \$-64,%rsp
mov $num,%r10
neg $num
##############################################################
@@ -2842,7 +2626,6 @@ bn_powerx5:
movq $bptr,%xmm4
mov $n0, 32(%rsp)
mov %rax, 40(%rsp) # save original %rsp
.cfi_cfa_expression %rsp+40,deref,+8
.Lpowerx5_body:
call __bn_sqrx8x_internal
@@ -2865,26 +2648,17 @@ bn_powerx5:
call mulx4x_internal
mov 40(%rsp),%rsi # restore %rsp
.cfi_def_cfa %rsi,8
mov \$1,%rax
mov -48(%rsi),%r15
.cfi_restore %r15
mov -40(%rsi),%r14
.cfi_restore %r14
mov -32(%rsi),%r13
.cfi_restore %r13
mov -24(%rsi),%r12
.cfi_restore %r12
mov -16(%rsi),%rbp
.cfi_restore %rbp
mov -8(%rsi),%rbx
.cfi_restore %rbx
lea (%rsi),%rsp
.cfi_def_cfa_register %rsp
.Lpowerx5_epilogue:
ret
.cfi_endproc
.size bn_powerx5,.-bn_powerx5
.globl bn_sqrx8x_internal
@@ -3474,7 +3248,6 @@ __bn_sqrx8x_reduction:
.align 32
.Lsqrx8x_tail_done:
xor %rax,%rax
add 24+8(%rsp),%r8 # can this overflow?
adc \$0,%r9
adc \$0,%r10
@@ -3482,8 +3255,10 @@ __bn_sqrx8x_reduction:
adc \$0,%r12
adc \$0,%r13
adc \$0,%r14
adc \$0,%r15
adc \$0,%rax
adc \$0,%r15 # can't overflow, because we
# started with "overhung" part
# of multiplication
mov $carry,%rax # xor %rax,%rax
sub 16+8(%rsp),$carry # mov 16(%rsp),%cf
.Lsqrx8x_no_tail: # %cf is 0 if jumped here
@@ -3498,7 +3273,7 @@ __bn_sqrx8x_reduction:
adc 8*5($tptr),%r13
adc 8*6($tptr),%r14
adc 8*7($tptr),%r15
adc \$0,%rax # top-most carry
adc %rax,%rax # top-most carry
mov 32+8(%rsp),%rbx # n0
mov 8*8($tptr,%rcx),%rdx # modulo-scheduled "%r8"
@@ -3740,14 +3515,9 @@ mul_handler:
cmp %r10,%rbx # context->Rip<end of prologue label
jb .Lcommon_seh_tail
mov 4(%r11),%r10d # HandlerData[1]
lea (%rsi,%r10),%r10 # beginning of body label
cmp %r10,%rbx # context->Rip<body label
jb .Lcommon_pop_regs
mov 152($context),%rax # pull context->Rsp
mov 8(%r11),%r10d # HandlerData[2]
mov 4(%r11),%r10d # HandlerData[1]
lea (%rsi,%r10),%r10 # epilogue label
cmp %r10,%rbx # context->Rip>=epilogue label
jae .Lcommon_seh_tail
@@ -3759,11 +3529,11 @@ mul_handler:
mov 192($context),%r10 # pull $num
mov 8(%rax,%r10,8),%rax # pull saved stack pointer
jmp .Lcommon_pop_regs
jmp .Lbody_proceed
.Lbody_40:
mov 40(%rax),%rax # pull saved stack pointer
.Lcommon_pop_regs:
.Lbody_proceed:
mov -8(%rax),%rbx
mov -16(%rax),%rbp
mov -24(%rax),%r12
@@ -3854,34 +3624,34 @@ $code.=<<___;
.LSEH_info_bn_mul_mont_gather5:
.byte 9,0,0,0
.rva mul_handler
.rva .Lmul_body,.Lmul_body,.Lmul_epilogue # HandlerData[]
.rva .Lmul_body,.Lmul_epilogue # HandlerData[]
.align 8
.LSEH_info_bn_mul4x_mont_gather5:
.byte 9,0,0,0
.rva mul_handler
.rva .Lmul4x_prologue,.Lmul4x_body,.Lmul4x_epilogue # HandlerData[]
.rva .Lmul4x_body,.Lmul4x_epilogue # HandlerData[]
.align 8
.LSEH_info_bn_power5:
.byte 9,0,0,0
.rva mul_handler
.rva .Lpower5_prologue,.Lpower5_body,.Lpower5_epilogue # HandlerData[]
.rva .Lpower5_body,.Lpower5_epilogue # HandlerData[]
.align 8
.LSEH_info_bn_from_mont8x:
.byte 9,0,0,0
.rva mul_handler
.rva .Lfrom_prologue,.Lfrom_body,.Lfrom_epilogue # HandlerData[]
.rva .Lfrom_body,.Lfrom_epilogue # HandlerData[]
___
$code.=<<___ if ($addx);
.align 8
.LSEH_info_bn_mulx4x_mont_gather5:
.byte 9,0,0,0
.rva mul_handler
.rva .Lmulx4x_prologue,.Lmulx4x_body,.Lmulx4x_epilogue # HandlerData[]
.rva .Lmulx4x_body,.Lmulx4x_epilogue # HandlerData[]
.align 8
.LSEH_info_bn_powerx5:
.byte 9,0,0,0
.rva mul_handler
.rva .Lpowerx5_prologue,.Lpowerx5_body,.Lpowerx5_epilogue # HandlerData[]
.rva .Lpowerx5_body,.Lpowerx5_epilogue # HandlerData[]
___
$code.=<<___;
.align 8
+35 -50
View File
@@ -63,7 +63,6 @@
#include <openssl/mem.h>
#include "internal.h"
#include "../delocate.h"
BIGNUM *BN_new(void) {
@@ -74,14 +73,14 @@ BIGNUM *BN_new(void) {
return NULL;
}
OPENSSL_memset(bn, 0, sizeof(BIGNUM));
memset(bn, 0, sizeof(BIGNUM));
bn->flags = BN_FLG_MALLOCED;
return bn;
}
void BN_init(BIGNUM *bn) {
OPENSSL_memset(bn, 0, sizeof(BIGNUM));
memset(bn, 0, sizeof(BIGNUM));
}
void BN_free(BIGNUM *bn) {
@@ -146,11 +145,11 @@ BIGNUM *BN_copy(BIGNUM *dest, const BIGNUM *src) {
return dest;
}
if (!bn_wexpand(dest, src->top)) {
if (bn_wexpand(dest, src->top) == NULL) {
return NULL;
}
OPENSSL_memcpy(dest->d, src->d, sizeof(src->d[0]) * src->top);
memcpy(dest->d, src->d, sizeof(src->d[0]) * src->top);
dest->top = src->top;
dest->neg = src->neg;
@@ -159,20 +158,24 @@ BIGNUM *BN_copy(BIGNUM *dest, const BIGNUM *src) {
void BN_clear(BIGNUM *bn) {
if (bn->d != NULL) {
OPENSSL_memset(bn->d, 0, bn->dmax * sizeof(bn->d[0]));
memset(bn->d, 0, bn->dmax * sizeof(bn->d[0]));
}
bn->top = 0;
bn->neg = 0;
}
DEFINE_METHOD_FUNCTION(BIGNUM, BN_value_one) {
const BIGNUM *BN_value_one(void) {
static const BN_ULONG kOneLimbs[1] = { 1 };
out->d = (BN_ULONG*) kOneLimbs;
out->top = 1;
out->dmax = 1;
out->neg = 0;
out->flags = BN_FLG_STATIC_DATA;
static const BIGNUM kOne = STATIC_BIGNUM(kOneLimbs);
return &kOne;
}
void BN_with_flags(BIGNUM *out, const BIGNUM *in, int flags) {
memcpy(out, in, sizeof(BIGNUM));
out->flags &= ~BN_FLG_MALLOCED;
out->flags |= BN_FLG_STATIC_DATA | flags;
}
/* BN_num_bits_word returns the minimum number of bits needed to represent the
@@ -253,7 +256,7 @@ int BN_set_word(BIGNUM *bn, BN_ULONG value) {
return 1;
}
if (!bn_wexpand(bn, 1)) {
if (bn_wexpand(bn, 1) == NULL) {
return 0;
}
@@ -263,33 +266,11 @@ int BN_set_word(BIGNUM *bn, BN_ULONG value) {
return 1;
}
int BN_set_u64(BIGNUM *bn, uint64_t value) {
#if BN_BITS2 == 64
return BN_set_word(bn, value);
#elif BN_BITS2 == 32
if (value <= BN_MASK2) {
return BN_set_word(bn, (BN_ULONG)value);
}
if (!bn_wexpand(bn, 2)) {
return 0;
}
bn->neg = 0;
bn->d[0] = (BN_ULONG)value;
bn->d[1] = (BN_ULONG)(value >> 32);
bn->top = 2;
return 1;
#else
#error "BN_BITS2 must be 32 or 64."
#endif
}
int bn_set_words(BIGNUM *bn, const BN_ULONG *words, size_t num) {
if (!bn_wexpand(bn, num)) {
if (bn_wexpand(bn, num) == NULL) {
return 0;
}
OPENSSL_memmove(bn->d, words, num * sizeof(BN_ULONG));
memmove(bn->d, words, num * sizeof(BN_ULONG));
/* |bn_wexpand| verified that |num| isn't too large. */
bn->top = (int)num;
bn_correct_top(bn);
@@ -309,42 +290,42 @@ void BN_set_negative(BIGNUM *bn, int sign) {
}
}
int bn_wexpand(BIGNUM *bn, size_t words) {
BIGNUM *bn_wexpand(BIGNUM *bn, size_t words) {
BN_ULONG *a;
if (words <= (size_t)bn->dmax) {
return 1;
return bn;
}
if (words > (INT_MAX / (4 * BN_BITS2))) {
OPENSSL_PUT_ERROR(BN, BN_R_BIGNUM_TOO_LONG);
return 0;
return NULL;
}
if (bn->flags & BN_FLG_STATIC_DATA) {
OPENSSL_PUT_ERROR(BN, BN_R_EXPAND_ON_STATIC_BIGNUM_DATA);
return 0;
return NULL;
}
a = OPENSSL_malloc(sizeof(BN_ULONG) * words);
if (a == NULL) {
OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
return 0;
return NULL;
}
OPENSSL_memcpy(a, bn->d, sizeof(BN_ULONG) * bn->top);
memcpy(a, bn->d, sizeof(BN_ULONG) * bn->top);
OPENSSL_free(bn->d);
bn->d = a;
bn->dmax = (int)words;
return 1;
return bn;
}
int bn_expand(BIGNUM *bn, size_t bits) {
BIGNUM *bn_expand(BIGNUM *bn, size_t bits) {
if (bits + BN_BITS2 - 1 < bits) {
OPENSSL_PUT_ERROR(BN, BN_R_BIGNUM_TOO_LONG);
return 0;
return NULL;
}
return bn_wexpand(bn, (bits+BN_BITS2-1)/BN_BITS2);
}
@@ -361,8 +342,12 @@ void bn_correct_top(BIGNUM *bn) {
}
bn->top = tmp_top;
}
if (bn->top == 0) {
bn->neg = 0;
}
}
int BN_get_flags(const BIGNUM *bn, int flags) {
return bn->flags & flags;
}
void BN_set_flags(BIGNUM *bn, int flags) {
bn->flags |= flags;
}
+1937
View File
File diff suppressed because it is too large Load Diff
@@ -56,8 +56,6 @@
#include <openssl/bn.h>
#include <openssl/mem.h>
#include "internal.h"
@@ -185,17 +183,6 @@ int BN_abs_is_word(const BIGNUM *bn, BN_ULONG w) {
}
}
int BN_cmp_word(const BIGNUM *a, BN_ULONG b) {
BIGNUM b_bn;
BN_init(&b_bn);
b_bn.d = &b;
b_bn.top = b > 0;
b_bn.dmax = 1;
b_bn.flags = BN_FLG_STATIC_DATA;
return BN_cmp(a, &b_bn);
}
int BN_is_zero(const BIGNUM *bn) {
return bn->top == 0;
}
@@ -211,29 +198,3 @@ int BN_is_word(const BIGNUM *bn, BN_ULONG w) {
int BN_is_odd(const BIGNUM *bn) {
return bn->top > 0 && (bn->d[0] & 1) == 1;
}
int BN_is_pow2(const BIGNUM *bn) {
if (bn->top == 0 || bn->neg) {
return 0;
}
for (int i = 0; i < bn->top - 1; i++) {
if (bn->d[i] != 0) {
return 0;
}
}
return 0 == (bn->d[bn->top-1] & (bn->d[bn->top-1] - 1));
}
int BN_equal_consttime(const BIGNUM *a, const BIGNUM *b) {
if (a->top != b->top) {
return 0;
}
int limbs_are_equal =
CRYPTO_memcmp(a->d, b->d, (size_t)a->top * sizeof(a->d[0])) == 0;
return constant_time_select_int(constant_time_eq_int(a->neg, b->neg),
limbs_are_equal, 0);
}
+602
View File
@@ -0,0 +1,602 @@
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.] */
#include <openssl/bn.h>
#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <openssl/bio.h>
#include <openssl/bytestring.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include "internal.h"
BIGNUM *BN_bin2bn(const uint8_t *in, size_t len, BIGNUM *ret) {
size_t num_words;
unsigned m;
BN_ULONG word = 0;
BIGNUM *bn = NULL;
if (ret == NULL) {
ret = bn = BN_new();
}
if (ret == NULL) {
return NULL;
}
if (len == 0) {
ret->top = 0;
return ret;
}
num_words = ((len - 1) / BN_BYTES) + 1;
m = (len - 1) % BN_BYTES;
if (bn_wexpand(ret, num_words) == NULL) {
if (bn) {
BN_free(bn);
}
return NULL;
}
/* |bn_wexpand| must check bounds on |num_words| to write it into
* |ret->dmax|. */
assert(num_words <= INT_MAX);
ret->top = (int)num_words;
ret->neg = 0;
while (len--) {
word = (word << 8) | *(in++);
if (m-- == 0) {
ret->d[--num_words] = word;
word = 0;
m = BN_BYTES - 1;
}
}
/* need to call this due to clear byte at top if avoiding having the top bit
* set (-ve number) */
bn_correct_top(ret);
return ret;
}
size_t BN_bn2bin(const BIGNUM *in, uint8_t *out) {
size_t n, i;
BN_ULONG l;
n = i = BN_num_bytes(in);
while (i--) {
l = in->d[i / BN_BYTES];
*(out++) = (unsigned char)(l >> (8 * (i % BN_BYTES))) & 0xff;
}
return n;
}
/* constant_time_select_ulong returns |x| if |v| is 1 and |y| if |v| is 0. Its
* behavior is undefined if |v| takes any other value. */
static BN_ULONG constant_time_select_ulong(int v, BN_ULONG x, BN_ULONG y) {
BN_ULONG mask = v;
mask--;
return (~mask & x) | (mask & y);
}
/* constant_time_le_size_t returns 1 if |x| <= |y| and 0 otherwise. |x| and |y|
* must not have their MSBs set. */
static int constant_time_le_size_t(size_t x, size_t y) {
return ((x - y - 1) >> (sizeof(size_t) * 8 - 1)) & 1;
}
/* read_word_padded returns the |i|'th word of |in|, if it is not out of
* bounds. Otherwise, it returns 0. It does so without branches on the size of
* |in|, however it necessarily does not have the same memory access pattern. If
* the access would be out of bounds, it reads the last word of |in|. |in| must
* not be zero. */
static BN_ULONG read_word_padded(const BIGNUM *in, size_t i) {
/* Read |in->d[i]| if valid. Otherwise, read the last word. */
BN_ULONG l = in->d[constant_time_select_ulong(
constant_time_le_size_t(in->dmax, i), in->dmax - 1, i)];
/* Clamp to zero if above |d->top|. */
return constant_time_select_ulong(constant_time_le_size_t(in->top, i), 0, l);
}
int BN_bn2bin_padded(uint8_t *out, size_t len, const BIGNUM *in) {
size_t i;
BN_ULONG l;
/* Special case for |in| = 0. Just branch as the probability is negligible. */
if (BN_is_zero(in)) {
memset(out, 0, len);
return 1;
}
/* Check if the integer is too big. This case can exit early in non-constant
* time. */
if ((size_t)in->top > (len + (BN_BYTES - 1)) / BN_BYTES) {
return 0;
}
if ((len % BN_BYTES) != 0) {
l = read_word_padded(in, len / BN_BYTES);
if (l >> (8 * (len % BN_BYTES)) != 0) {
return 0;
}
}
/* Write the bytes out one by one. Serialization is done without branching on
* the bits of |in| or on |in->top|, but if the routine would otherwise read
* out of bounds, the memory access pattern can't be fixed. However, for an
* RSA key of size a multiple of the word size, the probability of BN_BYTES
* leading zero octets is low.
*
* See Falko Stenzke, "Manger's Attack revisited", ICICS 2010. */
i = len;
while (i--) {
l = read_word_padded(in, i / BN_BYTES);
*(out++) = (uint8_t)(l >> (8 * (i % BN_BYTES))) & 0xff;
}
return 1;
}
int BN_bn2cbb_padded(CBB *out, size_t len, const BIGNUM *in) {
uint8_t *ptr;
return CBB_add_space(out, &ptr, len) && BN_bn2bin_padded(ptr, len, in);
}
static const char hextable[] = "0123456789abcdef";
char *BN_bn2hex(const BIGNUM *bn) {
int i, j, v, z = 0;
char *buf;
char *p;
buf = OPENSSL_malloc(bn->top * BN_BYTES * 2 + 2);
if (buf == NULL) {
OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
return NULL;
}
p = buf;
if (bn->neg) {
*(p++) = '-';
}
if (BN_is_zero(bn)) {
*(p++) = '0';
}
for (i = bn->top - 1; i >= 0; i--) {
for (j = BN_BITS2 - 8; j >= 0; j -= 8) {
/* strip leading zeros */
v = ((int)(bn->d[i] >> (long)j)) & 0xff;
if (z || v != 0) {
*(p++) = hextable[v >> 4];
*(p++) = hextable[v & 0x0f];
z = 1;
}
}
}
*p = '\0';
return buf;
}
/* decode_hex decodes |in_len| bytes of hex data from |in| and updates |bn|. */
static int decode_hex(BIGNUM *bn, const char *in, int in_len) {
if (in_len > INT_MAX/4) {
OPENSSL_PUT_ERROR(BN, BN_R_BIGNUM_TOO_LONG);
return 0;
}
/* |in_len| is the number of hex digits. */
if (bn_expand(bn, in_len * 4) == NULL) {
return 0;
}
int i = 0;
while (in_len > 0) {
/* Decode one |BN_ULONG| at a time. */
int todo = BN_BYTES * 2;
if (todo > in_len) {
todo = in_len;
}
BN_ULONG word = 0;
int j;
for (j = todo; j > 0; j--) {
char c = in[in_len - j];
BN_ULONG hex;
if (c >= '0' && c <= '9') {
hex = c - '0';
} else if (c >= 'a' && c <= 'f') {
hex = c - 'a' + 10;
} else if (c >= 'A' && c <= 'F') {
hex = c - 'A' + 10;
} else {
hex = 0;
/* This shouldn't happen. The caller checks |isxdigit|. */
assert(0);
}
word = (word << 4) | hex;
}
bn->d[i++] = word;
in_len -= todo;
}
assert(i <= bn->dmax);
bn->top = i;
return 1;
}
/* decode_dec decodes |in_len| bytes of decimal data from |in| and updates |bn|. */
static int decode_dec(BIGNUM *bn, const char *in, int in_len) {
int i, j;
BN_ULONG l = 0;
/* Decode |BN_DEC_NUM| digits at a time. */
j = BN_DEC_NUM - (in_len % BN_DEC_NUM);
if (j == BN_DEC_NUM) {
j = 0;
}
l = 0;
for (i = 0; i < in_len; i++) {
l *= 10;
l += in[i] - '0';
if (++j == BN_DEC_NUM) {
if (!BN_mul_word(bn, BN_DEC_CONV) ||
!BN_add_word(bn, l)) {
return 0;
}
l = 0;
j = 0;
}
}
return 1;
}
typedef int (*decode_func) (BIGNUM *bn, const char *in, int in_len);
typedef int (*char_test_func) (int c);
static int bn_x2bn(BIGNUM **outp, const char *in, decode_func decode, char_test_func want_char) {
BIGNUM *ret = NULL;
int neg = 0, i;
int num;
if (in == NULL || *in == 0) {
return 0;
}
if (*in == '-') {
neg = 1;
in++;
}
for (i = 0; want_char((unsigned char)in[i]) && i + neg < INT_MAX; i++) {}
num = i + neg;
if (outp == NULL) {
return num;
}
/* in is the start of the hex digits, and it is 'i' long */
if (*outp == NULL) {
ret = BN_new();
if (ret == NULL) {
return 0;
}
} else {
ret = *outp;
BN_zero(ret);
}
if (!decode(ret, in, i)) {
goto err;
}
bn_correct_top(ret);
if (!BN_is_zero(ret)) {
ret->neg = neg;
}
*outp = ret;
return num;
err:
if (*outp == NULL) {
BN_free(ret);
}
return 0;
}
int BN_hex2bn(BIGNUM **outp, const char *in) {
return bn_x2bn(outp, in, decode_hex, isxdigit);
}
char *BN_bn2dec(const BIGNUM *a) {
int i = 0, num, ok = 0;
char *buf = NULL;
char *p;
BIGNUM *t = NULL;
BN_ULONG *bn_data = NULL, *lp;
/* get an upper bound for the length of the decimal integer
* num <= (BN_num_bits(a) + 1) * log(2)
* <= 3 * BN_num_bits(a) * 0.1001 + log(2) + 1 (rounding error)
* <= BN_num_bits(a)/10 + BN_num_bits/1000 + 1 + 1
*/
i = BN_num_bits(a) * 3;
num = i / 10 + i / 1000 + 1 + 1;
bn_data = OPENSSL_malloc((num / BN_DEC_NUM + 1) * sizeof(BN_ULONG));
buf = OPENSSL_malloc(num + 3);
if ((buf == NULL) || (bn_data == NULL)) {
OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
goto err;
}
t = BN_dup(a);
if (t == NULL) {
goto err;
}
#define BUF_REMAIN (num + 3 - (size_t)(p - buf))
p = buf;
lp = bn_data;
if (BN_is_zero(t)) {
*(p++) = '0';
*(p++) = '\0';
} else {
if (BN_is_negative(t)) {
*p++ = '-';
}
while (!BN_is_zero(t)) {
*lp = BN_div_word(t, BN_DEC_CONV);
lp++;
}
lp--;
/* We now have a series of blocks, BN_DEC_NUM chars
* in length, where the last one needs truncation.
* The blocks need to be reversed in order. */
BIO_snprintf(p, BUF_REMAIN, BN_DEC_FMT1, *lp);
while (*p) {
p++;
}
while (lp != bn_data) {
lp--;
BIO_snprintf(p, BUF_REMAIN, BN_DEC_FMT2, *lp);
while (*p) {
p++;
}
}
}
ok = 1;
err:
OPENSSL_free(bn_data);
BN_free(t);
if (!ok) {
OPENSSL_free(buf);
buf = NULL;
}
return buf;
}
int BN_dec2bn(BIGNUM **outp, const char *in) {
return bn_x2bn(outp, in, decode_dec, isdigit);
}
int BN_asc2bn(BIGNUM **outp, const char *in) {
const char *const orig_in = in;
if (*in == '-') {
in++;
}
if (in[0] == '0' && (in[1] == 'X' || in[1] == 'x')) {
if (!BN_hex2bn(outp, in+2)) {
return 0;
}
} else {
if (!BN_dec2bn(outp, in)) {
return 0;
}
}
if (*orig_in == '-' && !BN_is_zero(*outp)) {
(*outp)->neg = 1;
}
return 1;
}
int BN_print(BIO *bp, const BIGNUM *a) {
int i, j, v, z = 0;
int ret = 0;
if (a->neg && BIO_write(bp, "-", 1) != 1) {
goto end;
}
if (BN_is_zero(a) && BIO_write(bp, "0", 1) != 1) {
goto end;
}
for (i = a->top - 1; i >= 0; i--) {
for (j = BN_BITS2 - 4; j >= 0; j -= 4) {
/* strip leading zeros */
v = ((int)(a->d[i] >> (long)j)) & 0x0f;
if (z || v != 0) {
if (BIO_write(bp, &hextable[v], 1) != 1) {
goto end;
}
z = 1;
}
}
}
ret = 1;
end:
return ret;
}
int BN_print_fp(FILE *fp, const BIGNUM *a) {
BIO *b;
int ret;
b = BIO_new(BIO_s_file());
if (b == NULL) {
return 0;
}
BIO_set_fp(b, fp, BIO_NOCLOSE);
ret = BN_print(b, a);
BIO_free(b);
return ret;
}
BN_ULONG BN_get_word(const BIGNUM *bn) {
switch (bn->top) {
case 0:
return 0;
case 1:
return bn->d[0];
default:
return BN_MASK2;
}
}
size_t BN_bn2mpi(const BIGNUM *in, uint8_t *out) {
const size_t bits = BN_num_bits(in);
const size_t bytes = (bits + 7) / 8;
/* If the number of bits is a multiple of 8, i.e. if the MSB is set,
* prefix with a zero byte. */
int extend = 0;
if (bytes != 0 && (bits & 0x07) == 0) {
extend = 1;
}
const size_t len = bytes + extend;
if (len < bytes ||
4 + len < len ||
(len & 0xffffffff) != len) {
/* If we cannot represent the number then we emit zero as the interface
* doesn't allow an error to be signalled. */
if (out) {
memset(out, 0, 4);
}
return 4;
}
if (out == NULL) {
return 4 + len;
}
out[0] = len >> 24;
out[1] = len >> 16;
out[2] = len >> 8;
out[3] = len;
if (extend) {
out[4] = 0;
}
BN_bn2bin(in, out + 4 + extend);
if (in->neg && len > 0) {
out[4] |= 0x80;
}
return len + 4;
}
BIGNUM *BN_mpi2bn(const uint8_t *in, size_t len, BIGNUM *out) {
if (len < 4) {
OPENSSL_PUT_ERROR(BN, BN_R_BAD_ENCODING);
return NULL;
}
const size_t in_len = ((size_t)in[0] << 24) |
((size_t)in[1] << 16) |
((size_t)in[2] << 8) |
((size_t)in[3]);
if (in_len != len - 4) {
OPENSSL_PUT_ERROR(BN, BN_R_BAD_ENCODING);
return NULL;
}
if (out == NULL) {
out = BN_new();
}
if (out == NULL) {
OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
return NULL;
}
if (in_len == 0) {
BN_zero(out);
return out;
}
in += 4;
if (BN_bin2bn(in, in_len, out) == NULL) {
return NULL;
}
out->neg = ((*in) & 0x80) != 0;
if (out->neg) {
BN_clear_bit(out, BN_num_bits(out) - 1);
}
return out;
}
+13 -7
View File
@@ -59,8 +59,6 @@
#include <openssl/err.h>
#include <openssl/mem.h>
#include "../../internal.h"
/* How many bignums are in each "pool item"; */
#define BN_CTX_POOL_SIZE 16
@@ -220,7 +218,7 @@ static int BN_STACK_push(BN_STACK *st, unsigned int idx) {
return 0;
}
if (st->depth) {
OPENSSL_memcpy(newitems, st->indexes, st->depth * sizeof(unsigned int));
memcpy(newitems, st->indexes, st->depth * sizeof(unsigned int));
}
OPENSSL_free(st->indexes);
st->indexes = newitems;
@@ -242,8 +240,13 @@ static void BN_POOL_init(BN_POOL *p) {
static void BN_POOL_finish(BN_POOL *p) {
while (p->head) {
for (size_t i = 0; i < BN_CTX_POOL_SIZE; i++) {
BN_clear_free(&p->head->vals[i]);
unsigned int loop = 0;
BIGNUM *bn = p->head->vals;
while (loop++ < BN_CTX_POOL_SIZE) {
if (bn->d) {
BN_clear_free(bn);
}
bn++;
}
p->current = p->head->next;
@@ -254,14 +257,17 @@ static void BN_POOL_finish(BN_POOL *p) {
static BIGNUM *BN_POOL_get(BN_POOL *p) {
if (p->used == p->size) {
BIGNUM *bn;
unsigned int loop = 0;
BN_POOL_ITEM *item = OPENSSL_malloc(sizeof(BN_POOL_ITEM));
if (!item) {
return NULL;
}
/* Initialise the structure */
for (size_t i = 0; i < BN_CTX_POOL_SIZE; i++) {
BN_init(&item->vals[i]);
bn = item->vals;
while (loop++ < BN_CTX_POOL_SIZE) {
BN_init(bn++);
}
item->prev = p->tail;
+53 -124
View File
@@ -58,7 +58,6 @@
#include <assert.h>
#include <limits.h>
#include <openssl/err.h>
#include "internal.h"
@@ -159,13 +158,13 @@ static inline void bn_div_rem_words(BN_ULONG *quotient_out, BN_ULONG *rem_out,
__asm__ volatile (
"divl %4"
: "=a"(*quotient_out), "=d"(*rem_out)
: "a"(n1), "d"(n0), "rm"(d0)
: "a"(n1), "d"(n0), "g"(d0)
: "cc" );
#elif !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && defined(__GNUC__)
__asm__ volatile (
"divq %4"
: "=a"(*quotient_out), "=d"(*rem_out)
: "a"(n1), "d"(n0), "rm"(d0)
: "a"(n1), "d"(n0), "g"(d0)
: "cc" );
#else
#if defined(BN_ULLONG)
@@ -183,12 +182,7 @@ static inline void bn_div_rem_words(BN_ULONG *quotient_out, BN_ULONG *rem_out,
* 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.
*
* 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. */
* If 'dv' or 'rm' is NULL, the respective value is not returned. */
int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
BN_CTX *ctx) {
int norm_shift, i, loop;
@@ -196,6 +190,7 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
BN_ULONG *resp, *wnump;
BN_ULONG d0, d1;
int num_n, div_n;
int no_branch = 0;
/* Invalid zero-padding would have particularly bad consequences
* so don't just rely on bn_check_top() here */
@@ -205,11 +200,28 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
return 0;
}
if ((num->flags & BN_FLG_CONSTTIME) != 0 ||
(divisor->flags & BN_FLG_CONSTTIME) != 0) {
no_branch = 1;
}
if (BN_is_zero(divisor)) {
OPENSSL_PUT_ERROR(BN, BN_R_DIV_BY_ZERO);
return 0;
}
if (!no_branch && BN_ucmp(num, divisor) < 0) {
if (rm != NULL) {
if (BN_copy(rm, num) == NULL) {
return 0;
}
}
if (dv != NULL) {
BN_zero(dv);
}
return 1;
}
BN_CTX_start(ctx);
tmp = BN_CTX_get(ctx);
snum = BN_CTX_get(ctx);
@@ -235,23 +247,26 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
}
snum->neg = 0;
/* Since we don't want to have special-case logic for the case where snum is
* larger than sdiv, we pad snum with enough zeroes without changing its
* value. */
if (snum->top <= sdiv->top + 1) {
if (!bn_wexpand(snum, sdiv->top + 2)) {
goto err;
if (no_branch) {
/* Since we don't know whether snum is larger than sdiv,
* we pad snum with enough zeroes without changing its
* value.
*/
if (snum->top <= sdiv->top + 1) {
if (bn_wexpand(snum, sdiv->top + 2) == NULL) {
goto err;
}
for (i = snum->top; i < sdiv->top + 2; i++) {
snum->d[i] = 0;
}
snum->top = sdiv->top + 2;
} else {
if (bn_wexpand(snum, snum->top + 1) == NULL) {
goto err;
}
snum->d[snum->top] = 0;
snum->top++;
}
for (i = snum->top; i < sdiv->top + 2; i++) {
snum->d[i] = 0;
}
snum->top = sdiv->top + 2;
} else {
if (!bn_wexpand(snum, snum->top + 1)) {
goto err;
}
snum->d[snum->top] = 0;
snum->top++;
}
div_n = sdiv->top;
@@ -279,7 +294,7 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
if (!bn_wexpand(res, (loop + 1))) {
goto err;
}
res->top = loop - 1;
res->top = loop - no_branch;
resp = &(res->d[loop - 1]);
/* space for temp */
@@ -287,6 +302,15 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
goto err;
}
if (!no_branch) {
if (BN_ucmp(&wnum, sdiv) >= 0) {
bn_sub_words(wnum.d, wnum.d, sdiv->d, div_n);
*resp = 1;
} else {
res->top--;
}
}
/* if res->top == 0 then clear the neg value otherwise decrease
* the resp pointer */
if (res->top == 0) {
@@ -377,7 +401,9 @@ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
rm->neg = neg;
}
}
bn_correct_top(res);
if (no_branch) {
bn_correct_top(res);
}
BN_CTX_end(ctx);
return 1;
@@ -602,10 +628,6 @@ BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w) {
a->top--;
}
if (a->top == 0) {
a->neg = 0;
}
ret >>= j;
return ret;
}
@@ -622,20 +644,6 @@ BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w) {
return (BN_ULONG) -1;
}
#ifndef BN_ULLONG
/* If |w| is too long and we don't have |BN_ULLONG| then we need to fall back
* to using |BN_div_word|. */
if (w > ((BN_ULONG)1 << BN_BITS4)) {
BIGNUM *tmp = BN_dup(a);
if (tmp == NULL) {
return (BN_ULONG)-1;
}
ret = BN_div_word(tmp, w);
BN_free(tmp);
return ret;
}
#endif
w &= BN_MASK2;
for (i = a->top - 1; i >= 0; i--) {
#ifndef BN_ULLONG
@@ -647,82 +655,3 @@ BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w) {
}
return (BN_ULONG)ret;
}
int BN_mod_pow2(BIGNUM *r, const BIGNUM *a, size_t e) {
if (e == 0 || a->top == 0) {
BN_zero(r);
return 1;
}
size_t num_words = 1 + ((e - 1) / BN_BITS2);
/* If |a| definitely has less than |e| bits, just BN_copy. */
if ((size_t) a->top < num_words) {
return BN_copy(r, a) != NULL;
}
/* Otherwise, first make sure we have enough space in |r|.
* Note that this will fail if num_words > INT_MAX. */
if (!bn_wexpand(r, num_words)) {
return 0;
}
/* Copy the content of |a| into |r|. */
OPENSSL_memcpy(r->d, a->d, num_words * sizeof(BN_ULONG));
/* If |e| isn't word-aligned, we have to mask off some of our bits. */
size_t top_word_exponent = e % (sizeof(BN_ULONG) * 8);
if (top_word_exponent != 0) {
r->d[num_words - 1] &= (((BN_ULONG) 1) << top_word_exponent) - 1;
}
/* Fill in the remaining fields of |r|. */
r->neg = a->neg;
r->top = (int) num_words;
bn_correct_top(r);
return 1;
}
int BN_nnmod_pow2(BIGNUM *r, const BIGNUM *a, size_t e) {
if (!BN_mod_pow2(r, a, e)) {
return 0;
}
/* If the returned value was non-negative, we're done. */
if (BN_is_zero(r) || !r->neg) {
return 1;
}
size_t num_words = 1 + (e - 1) / BN_BITS2;
/* Expand |r| to the size of our modulus. */
if (!bn_wexpand(r, num_words)) {
return 0;
}
/* Clear the upper words of |r|. */
OPENSSL_memset(&r->d[r->top], 0, (num_words - r->top) * BN_BYTES);
/* Set parameters of |r|. */
r->neg = 0;
r->top = (int) num_words;
/* Now, invert every word. The idea here is that we want to compute 2^e-|x|,
* which is actually equivalent to the twos-complement representation of |x|
* in |e| bits, which is -x = ~x + 1. */
for (int i = 0; i < r->top; i++) {
r->d[i] = ~r->d[i];
}
/* If our exponent doesn't span the top word, we have to mask the rest. */
size_t top_word_exponent = e % BN_BITS2;
if (top_word_exponent != 0) {
r->d[r->top - 1] &= (((BN_ULONG) 1) << top_word_exponent) - 1;
}
/* Keep the correct_top invariant for BN_add. */
bn_correct_top(r);
/* Finally, add one, for the reason described above. */
return BN_add(r, r, BN_value_one());
}
@@ -140,6 +140,12 @@ int BN_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx) {
int i, bits, ret = 0;
BIGNUM *v, *rr;
if ((p->flags & BN_FLG_CONSTTIME) != 0) {
/* BN_FLG_CONSTTIME only supported by BN_mod_exp_mont() */
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
BN_CTX_start(ctx);
if (r == a || r == p) {
rr = BN_CTX_get(ctx);
@@ -431,6 +437,12 @@ static int mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
BIGNUM *val[TABLE_SIZE];
BN_RECP_CTX recp;
if (BN_get_flags(p, BN_FLG_CONSTTIME) != 0) {
/* BN_FLG_CONSTTIME only supported by BN_mod_exp_mont() */
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
bits = BN_num_bits(p);
if (bits == 0) {
@@ -564,7 +576,41 @@ err:
int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m,
BN_CTX *ctx) {
/* For even modulus m = 2^k*m_odd, it might make sense to compute
* a^p mod m_odd and a^p mod 2^k separately (with Montgomery
* exponentiation for the odd part), using appropriate exponent
* reductions, and combine the results using the CRT.
*
* For now, we use Montgomery only if the modulus is odd; otherwise,
* exponentiation using the reciprocal-based quick remaindering
* algorithm is used.
*
* (Timing obtained with expspeed.c [computations a^p mod m
* where a, p, m are of the same length: 256, 512, 1024, 2048,
* 4096, 8192 bits], compared to the running time of the
* standard algorithm:
*
* BN_mod_exp_mont 33 .. 40 % [AMD K6-2, Linux, debug configuration]
* 55 .. 77 % [UltraSparc processor, but
* debug-solaris-sparcv8-gcc conf.]
*
* BN_mod_exp_recp 50 .. 70 % [AMD K6-2, Linux, debug configuration]
* 62 .. 118 % [UltraSparc, debug-solaris-sparcv8-gcc]
*
* On the Sparc, BN_mod_exp_recp was faster than BN_mod_exp_mont
* at 2048 and more bits, but at 512 and 1024 bits, it was
* slower even than the standard algorithm!
*
* "Real" timings [linux-elf, solaris-sparcv9-gcc configurations]
* should be obtained when the new Montgomery reduction code
* has been integrated into OpenSSL.) */
if (BN_is_odd(m)) {
if (a->top == 1 && !a->neg && BN_get_flags(p, BN_FLG_CONSTTIME) == 0) {
BN_ULONG A = a->d[0];
return BN_mod_exp_mont_word(r, A, p, m, ctx, NULL);
}
return BN_mod_exp_mont(r, a, p, m, ctx, NULL);
}
@@ -581,6 +627,10 @@ int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
BIGNUM *val[TABLE_SIZE];
BN_MONT_CTX *new_mont = NULL;
if (BN_get_flags(p, BN_FLG_CONSTTIME) != 0) {
return BN_mod_exp_mont_consttime(rr, a, p, m, ctx, mont);
}
if (!BN_is_odd(m)) {
OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS);
return 0;
@@ -651,7 +701,7 @@ int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
j = m->top; /* borrow j */
if (m->d[j - 1] & (((BN_ULONG)1) << (BN_BITS2 - 1))) {
if (!bn_wexpand(r, j)) {
if (bn_wexpand(r, j) == NULL) {
goto err;
}
/* 2^(top*BN_BITS2) - m */
@@ -760,7 +810,7 @@ static int copy_from_prebuf(BIGNUM *b, int top, unsigned char *buf, int idx,
const int width = 1 << window;
volatile BN_ULONG *table = (volatile BN_ULONG *)buf;
if (!bn_wexpand(b, top)) {
if (bn_wexpand(b, top) == NULL) {
return 0;
}
@@ -860,7 +910,6 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
int powerbufLen = 0;
unsigned char *powerbuf = NULL;
BIGNUM tmp, am;
BIGNUM *new_a = NULL;
if (!BN_is_odd(m)) {
OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS);
@@ -888,22 +937,13 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
mont = new_mont;
}
if (a->neg || BN_ucmp(a, m) >= 0) {
new_a = BN_new();
if (new_a == NULL ||
!BN_nnmod(new_a, a, m, ctx)) {
goto err;
}
a = new_a;
}
#ifdef RSAZ_ENABLED
/* If the size of the operands allow it, perform the optimized
* RSAZ exponentiation. For further information see
* crypto/bn/rsaz_exp.c and accompanying assembly modules. */
if ((16 == a->top) && (16 == p->top) && (BN_num_bits(m) == 1024) &&
rsaz_avx2_eligible()) {
if (!bn_wexpand(rr, 16)) {
if (NULL == bn_wexpand(rr, 16)) {
goto err;
}
RSAZ_1024_mod_exp_avx2(rr->d, a->d, p->d, m->d, mont->RR.d, mont->n0[0]);
@@ -912,6 +952,16 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
bn_correct_top(rr);
ret = 1;
goto err;
} else if ((8 == a->top) && (8 == p->top) && (BN_num_bits(m) == 512)) {
if (NULL == bn_wexpand(rr, 8)) {
goto err;
}
RSAZ_512_mod_exp(rr->d, a->d, p->d, m->d, mont->n0[0], mont->RR.d);
rr->top = 8;
rr->neg = 0;
bn_correct_top(rr);
ret = 1;
goto err;
}
#endif
@@ -945,7 +995,7 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
}
powerbuf = MOD_EXP_CTIME_ALIGN(powerbufFree);
OPENSSL_memset(powerbuf, 0, powerbufLen);
memset(powerbuf, 0, powerbufLen);
#ifdef alloca
if (powerbufLen < 3072) {
@@ -975,9 +1025,12 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
}
/* prepare a^1 in Montgomery domain */
assert(!a->neg);
assert(BN_ucmp(a, m) < 0);
if (!BN_to_montgomery(&am, a, mont, ctx)) {
if (a->neg || BN_ucmp(a, m) >= 0) {
if (!BN_mod(&am, a, m, ctx) ||
!BN_to_montgomery(&am, &am, mont, ctx)) {
goto err;
}
} else if (!BN_to_montgomery(&am, a, mont, ctx)) {
goto err;
}
@@ -1171,7 +1224,6 @@ 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);
@@ -1182,34 +1234,60 @@ err:
int BN_mod_exp_mont_word(BIGNUM *rr, BN_ULONG a, const BIGNUM *p,
const BIGNUM *m, BN_CTX *ctx,
const BN_MONT_CTX *mont) {
BIGNUM a_bignum;
BN_init(&a_bignum);
BN_MONT_CTX *new_mont = NULL;
int b, bits, ret = 0;
int r_is_one;
BN_ULONG w, next_w;
BIGNUM *d, *r, *t;
BIGNUM *swap_tmp;
#define BN_MOD_MUL_WORD(r, w, m) \
(BN_mul_word(r, (w)) && \
(/* BN_ucmp(r, (m)) < 0 ? 1 :*/ \
(BN_mod(t, r, m, ctx) && (swap_tmp = r, r = t, t = swap_tmp, 1))))
/* BN_MOD_MUL_WORD is only used with 'w' large, so the BN_ucmp test is
* probably more overhead than always using BN_mod (which uses BN_copy if a
* similar test returns true). We can use BN_mod and do not need BN_nnmod
* because our accumulator is never negative (the result of BN_mod does not
* depend on the sign of the modulus). */
#define BN_TO_MONTGOMERY_WORD(r, w, mont) \
(BN_set_word(r, (w)) && BN_to_montgomery(r, r, (mont), ctx))
int ret = 0;
if (!BN_set_word(&a_bignum, a)) {
OPENSSL_PUT_ERROR(BN, ERR_R_INTERNAL_ERROR);
goto err;
if (BN_get_flags(p, BN_FLG_CONSTTIME) != 0) {
/* BN_FLG_CONSTTIME only supported by BN_mod_exp_mont() */
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
ret = BN_mod_exp_mont(rr, &a_bignum, p, m, ctx, mont);
if (!BN_is_odd(m)) {
OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS);
return 0;
}
err:
BN_free(&a_bignum);
if (m->top == 1) {
a %= m->d[0]; /* make sure that 'a' is reduced */
}
return ret;
}
bits = BN_num_bits(p);
if (bits == 0) {
/* x**0 mod 1 is still zero. */
if (BN_is_one(m)) {
BN_zero(rr);
return 1;
}
return BN_one(rr);
}
if (a == 0) {
BN_zero(rr);
return 1;
}
#define TABLE_SIZE 32
int BN_mod_exp2_mont(BIGNUM *rr, const BIGNUM *a1, const BIGNUM *p1,
const BIGNUM *a2, const BIGNUM *p2, const BIGNUM *m,
BN_CTX *ctx, const BN_MONT_CTX *mont) {
BIGNUM tmp;
BN_init(&tmp);
int ret = 0;
BN_MONT_CTX *new_mont = NULL;
BN_CTX_start(ctx);
d = BN_CTX_get(ctx);
r = BN_CTX_get(ctx);
t = BN_CTX_get(ctx);
if (d == NULL || r == NULL || t == NULL) {
goto err;
}
/* Allocate a montgomery context if it was not supplied by the caller. */
if (mont == NULL) {
@@ -1220,21 +1298,285 @@ int BN_mod_exp2_mont(BIGNUM *rr, const BIGNUM *a1, const BIGNUM *p1,
mont = new_mont;
}
/* BN_mod_mul_montgomery removes one Montgomery factor, so passing one
* Montgomery-encoded and one non-Montgomery-encoded value gives a
* non-Montgomery-encoded result. */
if (!BN_mod_exp_mont(rr, a1, p1, m, ctx, mont) ||
!BN_mod_exp_mont(&tmp, a2, p2, m, ctx, mont) ||
!BN_to_montgomery(rr, rr, mont, ctx) ||
!BN_mod_mul_montgomery(rr, rr, &tmp, mont, ctx)) {
goto err;
r_is_one = 1; /* except for Montgomery factor */
/* bits-1 >= 0 */
/* The result is accumulated in the product r*w. */
w = a; /* bit 'bits-1' of 'p' is always set */
for (b = bits - 2; b >= 0; b--) {
/* First, square r*w. */
next_w = w * w;
if ((next_w / w) != w) {
/* overflow */
if (r_is_one) {
if (!BN_TO_MONTGOMERY_WORD(r, w, mont)) {
goto err;
}
r_is_one = 0;
} else {
if (!BN_MOD_MUL_WORD(r, w, m)) {
goto err;
}
}
next_w = 1;
}
w = next_w;
if (!r_is_one) {
if (!BN_mod_mul_montgomery(r, r, r, mont, ctx)) {
goto err;
}
}
/* Second, multiply r*w by 'a' if exponent bit is set. */
if (BN_is_bit_set(p, b)) {
next_w = w * a;
if ((next_w / a) != w) {
/* overflow */
if (r_is_one) {
if (!BN_TO_MONTGOMERY_WORD(r, w, mont)) {
goto err;
}
r_is_one = 0;
} else {
if (!BN_MOD_MUL_WORD(r, w, m)) {
goto err;
}
}
next_w = a;
}
w = next_w;
}
}
/* Finally, set r:=r*w. */
if (w != 1) {
if (r_is_one) {
if (!BN_TO_MONTGOMERY_WORD(r, w, mont)) {
goto err;
}
r_is_one = 0;
} else {
if (!BN_MOD_MUL_WORD(r, w, m)) {
goto err;
}
}
}
if (r_is_one) {
/* can happen only if a == 1*/
if (!BN_one(rr)) {
goto err;
}
} else {
if (!BN_from_montgomery(rr, r, mont, ctx)) {
goto err;
}
}
ret = 1;
err:
BN_MONT_CTX_free(new_mont);
BN_free(&tmp);
BN_CTX_end(ctx);
return ret;
}
#define TABLE_SIZE 32
int BN_mod_exp2_mont(BIGNUM *rr, const BIGNUM *a1, const BIGNUM *p1,
const BIGNUM *a2, const BIGNUM *p2, const BIGNUM *m,
BN_CTX *ctx, const BN_MONT_CTX *mont) {
int i, j, bits, b, bits1, bits2, ret = 0, wpos1, wpos2, window1, window2,
wvalue1, wvalue2;
int r_is_one = 1;
BIGNUM *d, *r;
const BIGNUM *a_mod_m;
/* Tables of variables obtained from 'ctx' */
BIGNUM *val1[TABLE_SIZE], *val2[TABLE_SIZE];
BN_MONT_CTX *new_mont = NULL;
if (!(m->d[0] & 1)) {
OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS);
return 0;
}
bits1 = BN_num_bits(p1);
bits2 = BN_num_bits(p2);
if (bits1 == 0 && bits2 == 0) {
ret = BN_one(rr);
return ret;
}
bits = (bits1 > bits2) ? bits1 : bits2;
BN_CTX_start(ctx);
d = BN_CTX_get(ctx);
r = BN_CTX_get(ctx);
val1[0] = BN_CTX_get(ctx);
val2[0] = BN_CTX_get(ctx);
if (!d || !r || !val1[0] || !val2[0]) {
goto err;
}
/* Allocate a montgomery context if it was not supplied by the caller. */
if (mont == NULL) {
new_mont = BN_MONT_CTX_new();
if (new_mont == NULL || !BN_MONT_CTX_set(new_mont, m, ctx)) {
goto err;
}
mont = new_mont;
}
window1 = BN_window_bits_for_exponent_size(bits1);
window2 = BN_window_bits_for_exponent_size(bits2);
/* Build table for a1: val1[i] := a1^(2*i + 1) mod m for i = 0 ..
* 2^(window1-1) */
if (a1->neg || BN_ucmp(a1, m) >= 0) {
if (!BN_mod(val1[0], a1, m, ctx)) {
goto err;
}
a_mod_m = val1[0];
} else {
a_mod_m = a1;
}
if (BN_is_zero(a_mod_m)) {
BN_zero(rr);
ret = 1;
goto err;
}
if (!BN_to_montgomery(val1[0], a_mod_m, mont, ctx)) {
goto err;
}
if (window1 > 1) {
if (!BN_mod_mul_montgomery(d, val1[0], val1[0], mont, ctx)) {
goto err;
}
j = 1 << (window1 - 1);
for (i = 1; i < j; i++) {
if (((val1[i] = BN_CTX_get(ctx)) == NULL) ||
!BN_mod_mul_montgomery(val1[i], val1[i - 1], d, mont, ctx)) {
goto err;
}
}
}
/* Build table for a2: val2[i] := a2^(2*i + 1) mod m for i = 0 ..
* 2^(window2-1) */
if (a2->neg || BN_ucmp(a2, m) >= 0) {
if (!BN_mod(val2[0], a2, m, ctx)) {
goto err;
}
a_mod_m = val2[0];
} else {
a_mod_m = a2;
}
if (BN_is_zero(a_mod_m)) {
BN_zero(rr);
ret = 1;
goto err;
}
if (!BN_to_montgomery(val2[0], a_mod_m, mont, ctx)) {
goto err;
}
if (window2 > 1) {
if (!BN_mod_mul_montgomery(d, val2[0], val2[0], mont, ctx)) {
goto err;
}
j = 1 << (window2 - 1);
for (i = 1; i < j; i++) {
if (((val2[i] = BN_CTX_get(ctx)) == NULL) ||
!BN_mod_mul_montgomery(val2[i], val2[i - 1], d, mont, ctx)) {
goto err;
}
}
}
/* Now compute the power product, using independent windows. */
r_is_one = 1;
wvalue1 = 0; /* The 'value' of the first window */
wvalue2 = 0; /* The 'value' of the second window */
wpos1 = 0; /* If wvalue1 > 0, the bottom bit of the first window */
wpos2 = 0; /* If wvalue2 > 0, the bottom bit of the second window */
if (!BN_to_montgomery(r, BN_value_one(), mont, ctx)) {
goto err;
}
for (b = bits - 1; b >= 0; b--) {
if (!r_is_one) {
if (!BN_mod_mul_montgomery(r, r, r, mont, ctx)) {
goto err;
}
}
if (!wvalue1 && BN_is_bit_set(p1, b)) {
/* consider bits b-window1+1 .. b for this window */
i = b - window1 + 1;
/* works for i<0 */
while (!BN_is_bit_set(p1, i)) {
i++;
}
wpos1 = i;
wvalue1 = 1;
for (i = b - 1; i >= wpos1; i--) {
wvalue1 <<= 1;
if (BN_is_bit_set(p1, i)) {
wvalue1++;
}
}
}
if (!wvalue2 && BN_is_bit_set(p2, b)) {
/* consider bits b-window2+1 .. b for this window */
i = b - window2 + 1;
while (!BN_is_bit_set(p2, i)) {
i++;
}
wpos2 = i;
wvalue2 = 1;
for (i = b - 1; i >= wpos2; i--) {
wvalue2 <<= 1;
if (BN_is_bit_set(p2, i)) {
wvalue2++;
}
}
}
if (wvalue1 && b == wpos1) {
/* wvalue1 is odd and < 2^window1 */
if (!BN_mod_mul_montgomery(r, r, val1[wvalue1 >> 1], mont, ctx)) {
goto err;
}
wvalue1 = 0;
r_is_one = 0;
}
if (wvalue2 && b == wpos2) {
/* wvalue2 is odd and < 2^window2 */
if (!BN_mod_mul_montgomery(r, r, val2[wvalue2 >> 1], mont, ctx)) {
goto err;
}
wvalue2 = 0;
r_is_one = 0;
}
}
if (!BN_from_montgomery(rr, r, mont, ctx)) {
goto err;
}
ret = 1;
err:
BN_MONT_CTX_free(new_mont);
BN_CTX_end(ctx);
return ret;
}
+711
View File
@@ -0,0 +1,711 @@
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.]
*/
/* ====================================================================
* Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com). */
#include <openssl/bn.h>
#include <openssl/err.h>
#include "internal.h"
static BIGNUM *euclid(BIGNUM *a, BIGNUM *b) {
BIGNUM *t;
int shifts = 0;
/* 0 <= b <= a */
while (!BN_is_zero(b)) {
/* 0 < b <= a */
if (BN_is_odd(a)) {
if (BN_is_odd(b)) {
if (!BN_sub(a, a, b)) {
goto err;
}
if (!BN_rshift1(a, a)) {
goto err;
}
if (BN_cmp(a, b) < 0) {
t = a;
a = b;
b = t;
}
} else {
/* a odd - b even */
if (!BN_rshift1(b, b)) {
goto err;
}
if (BN_cmp(a, b) < 0) {
t = a;
a = b;
b = t;
}
}
} else {
/* a is even */
if (BN_is_odd(b)) {
if (!BN_rshift1(a, a)) {
goto err;
}
if (BN_cmp(a, b) < 0) {
t = a;
a = b;
b = t;
}
} else {
/* a even - b even */
if (!BN_rshift1(a, a)) {
goto err;
}
if (!BN_rshift1(b, b)) {
goto err;
}
shifts++;
}
}
/* 0 <= b <= a */
}
if (shifts) {
if (!BN_lshift(a, a, shifts)) {
goto err;
}
}
return a;
err:
return NULL;
}
int BN_gcd(BIGNUM *r, const BIGNUM *in_a, const BIGNUM *in_b, BN_CTX *ctx) {
BIGNUM *a, *b, *t;
int ret = 0;
BN_CTX_start(ctx);
a = BN_CTX_get(ctx);
b = BN_CTX_get(ctx);
if (a == NULL || b == NULL) {
goto err;
}
if (BN_copy(a, in_a) == NULL) {
goto err;
}
if (BN_copy(b, in_b) == NULL) {
goto err;
}
a->neg = 0;
b->neg = 0;
if (BN_cmp(a, b) < 0) {
t = a;
a = b;
b = t;
}
t = euclid(a, b);
if (t == NULL) {
goto err;
}
if (BN_copy(r, t) == NULL) {
goto err;
}
ret = 1;
err:
BN_CTX_end(ctx);
return ret;
}
/* solves ax == 1 (mod n) */
static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, int *out_no_inverse,
const BIGNUM *a, const BIGNUM *n,
BN_CTX *ctx);
BIGNUM *BN_mod_inverse_ex(BIGNUM *out, int *out_no_inverse, const BIGNUM *a,
const BIGNUM *n, BN_CTX *ctx) {
BIGNUM *A, *B, *X, *Y, *M, *D, *T, *R = NULL;
BIGNUM *ret = NULL;
int sign;
if ((a->flags & BN_FLG_CONSTTIME) != 0 ||
(n->flags & BN_FLG_CONSTTIME) != 0) {
return BN_mod_inverse_no_branch(out, out_no_inverse, a, n, ctx);
}
*out_no_inverse = 0;
BN_CTX_start(ctx);
A = BN_CTX_get(ctx);
B = BN_CTX_get(ctx);
X = BN_CTX_get(ctx);
D = BN_CTX_get(ctx);
M = BN_CTX_get(ctx);
Y = BN_CTX_get(ctx);
T = BN_CTX_get(ctx);
if (T == NULL) {
goto err;
}
if (out == NULL) {
R = BN_new();
} else {
R = out;
}
if (R == NULL) {
goto err;
}
BN_zero(Y);
if (!BN_one(X) || BN_copy(B, a) == NULL || BN_copy(A, n) == NULL) {
goto err;
}
A->neg = 0;
if (B->neg || (BN_ucmp(B, A) >= 0)) {
if (!BN_nnmod(B, B, A, ctx)) {
goto err;
}
}
sign = -1;
/* From B = a mod |n|, A = |n| it follows that
*
* 0 <= B < A,
* -sign*X*a == B (mod |n|),
* sign*Y*a == A (mod |n|).
*/
if (BN_is_odd(n) && (BN_num_bits(n) <= (BN_BITS2 <= 32 ? 450 : 2048))) {
/* Binary inversion algorithm; requires odd modulus.
* This is faster than the general algorithm if the modulus
* is sufficiently small (about 400 .. 500 bits on 32-bit
* sytems, but much more on 64-bit systems) */
int shift;
while (!BN_is_zero(B)) {
/* 0 < B < |n|,
* 0 < A <= |n|,
* (1) -sign*X*a == B (mod |n|),
* (2) sign*Y*a == A (mod |n|) */
/* Now divide B by the maximum possible power of two in the integers,
* and divide X by the same value mod |n|.
* When we're done, (1) still holds. */
shift = 0;
while (!BN_is_bit_set(B, shift)) {
/* note that 0 < B */
shift++;
if (BN_is_odd(X)) {
if (!BN_uadd(X, X, n)) {
goto err;
}
}
/* now X is even, so we can easily divide it by two */
if (!BN_rshift1(X, X)) {
goto err;
}
}
if (shift > 0) {
if (!BN_rshift(B, B, shift)) {
goto err;
}
}
/* Same for A and Y. Afterwards, (2) still holds. */
shift = 0;
while (!BN_is_bit_set(A, shift)) {
/* note that 0 < A */
shift++;
if (BN_is_odd(Y)) {
if (!BN_uadd(Y, Y, n)) {
goto err;
}
}
/* now Y is even */
if (!BN_rshift1(Y, Y)) {
goto err;
}
}
if (shift > 0) {
if (!BN_rshift(A, A, shift)) {
goto err;
}
}
/* We still have (1) and (2).
* Both A and B are odd.
* The following computations ensure that
*
* 0 <= B < |n|,
* 0 < A < |n|,
* (1) -sign*X*a == B (mod |n|),
* (2) sign*Y*a == A (mod |n|),
*
* and that either A or B is even in the next iteration. */
if (BN_ucmp(B, A) >= 0) {
/* -sign*(X + Y)*a == B - A (mod |n|) */
if (!BN_uadd(X, X, Y)) {
goto err;
}
/* NB: we could use BN_mod_add_quick(X, X, Y, n), but that
* actually makes the algorithm slower */
if (!BN_usub(B, B, A)) {
goto err;
}
} else {
/* sign*(X + Y)*a == A - B (mod |n|) */
if (!BN_uadd(Y, Y, X)) {
goto err;
}
/* as above, BN_mod_add_quick(Y, Y, X, n) would slow things down */
if (!BN_usub(A, A, B)) {
goto err;
}
}
}
} else {
/* general inversion algorithm */
while (!BN_is_zero(B)) {
BIGNUM *tmp;
/*
* 0 < B < A,
* (*) -sign*X*a == B (mod |n|),
* sign*Y*a == A (mod |n|) */
/* (D, M) := (A/B, A%B) ... */
if (BN_num_bits(A) == BN_num_bits(B)) {
if (!BN_one(D)) {
goto err;
}
if (!BN_sub(M, A, B)) {
goto err;
}
} else if (BN_num_bits(A) == BN_num_bits(B) + 1) {
/* A/B is 1, 2, or 3 */
if (!BN_lshift1(T, B)) {
goto err;
}
if (BN_ucmp(A, T) < 0) {
/* A < 2*B, so D=1 */
if (!BN_one(D)) {
goto err;
}
if (!BN_sub(M, A, B)) {
goto err;
}
} else {
/* A >= 2*B, so D=2 or D=3 */
if (!BN_sub(M, A, T)) {
goto err;
}
if (!BN_add(D, T, B)) {
goto err; /* use D (:= 3*B) as temp */
}
if (BN_ucmp(A, D) < 0) {
/* A < 3*B, so D=2 */
if (!BN_set_word(D, 2)) {
goto err;
}
/* M (= A - 2*B) already has the correct value */
} else {
/* only D=3 remains */
if (!BN_set_word(D, 3)) {
goto err;
}
/* currently M = A - 2*B, but we need M = A - 3*B */
if (!BN_sub(M, M, B)) {
goto err;
}
}
}
} else {
if (!BN_div(D, M, A, B, ctx)) {
goto err;
}
}
/* Now
* A = D*B + M;
* thus we have
* (**) sign*Y*a == D*B + M (mod |n|). */
tmp = A; /* keep the BIGNUM object, the value does not matter */
/* (A, B) := (B, A mod B) ... */
A = B;
B = M;
/* ... so we have 0 <= B < A again */
/* Since the former M is now B and the former B is now A,
* (**) translates into
* sign*Y*a == D*A + B (mod |n|),
* i.e.
* sign*Y*a - D*A == B (mod |n|).
* Similarly, (*) translates into
* -sign*X*a == A (mod |n|).
*
* Thus,
* sign*Y*a + D*sign*X*a == B (mod |n|),
* i.e.
* sign*(Y + D*X)*a == B (mod |n|).
*
* So if we set (X, Y, sign) := (Y + D*X, X, -sign), we arrive back at
* -sign*X*a == B (mod |n|),
* sign*Y*a == A (mod |n|).
* Note that X and Y stay non-negative all the time. */
/* most of the time D is very small, so we can optimize tmp := D*X+Y */
if (BN_is_one(D)) {
if (!BN_add(tmp, X, Y)) {
goto err;
}
} else {
if (BN_is_word(D, 2)) {
if (!BN_lshift1(tmp, X)) {
goto err;
}
} else if (BN_is_word(D, 4)) {
if (!BN_lshift(tmp, X, 2)) {
goto err;
}
} else if (D->top == 1) {
if (!BN_copy(tmp, X)) {
goto err;
}
if (!BN_mul_word(tmp, D->d[0])) {
goto err;
}
} else {
if (!BN_mul(tmp, D, X, ctx)) {
goto err;
}
}
if (!BN_add(tmp, tmp, Y)) {
goto err;
}
}
M = Y; /* keep the BIGNUM object, the value does not matter */
Y = X;
X = tmp;
sign = -sign;
}
}
/* The while loop (Euclid's algorithm) ends when
* A == gcd(a,n);
* we have
* sign*Y*a == A (mod |n|),
* where Y is non-negative. */
if (sign < 0) {
if (!BN_sub(Y, n, Y)) {
goto err;
}
}
/* Now Y*a == A (mod |n|). */
if (BN_is_one(A)) {
/* Y*a == 1 (mod |n|) */
if (!Y->neg && BN_ucmp(Y, n) < 0) {
if (!BN_copy(R, Y)) {
goto err;
}
} else {
if (!BN_nnmod(R, Y, n, ctx)) {
goto err;
}
}
} else {
*out_no_inverse = 1;
OPENSSL_PUT_ERROR(BN, BN_R_NO_INVERSE);
goto err;
}
ret = R;
err:
if (ret == NULL && out == NULL) {
BN_free(R);
}
BN_CTX_end(ctx);
return ret;
}
BIGNUM *BN_mod_inverse(BIGNUM *out, const BIGNUM *a, const BIGNUM *n,
BN_CTX *ctx) {
int no_inverse;
return BN_mod_inverse_ex(out, &no_inverse, a, n, ctx);
}
/* BN_mod_inverse_no_branch is a special version of BN_mod_inverse.
* It does not contain branches that may leak sensitive information. */
static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, int *out_no_inverse,
const BIGNUM *a, const BIGNUM *n,
BN_CTX *ctx) {
BIGNUM *A, *B, *X, *Y, *M, *D, *T, *R = NULL;
BIGNUM local_A, local_B;
BIGNUM *pA, *pB;
BIGNUM *ret = NULL;
int sign;
*out_no_inverse = 0;
BN_CTX_start(ctx);
A = BN_CTX_get(ctx);
B = BN_CTX_get(ctx);
X = BN_CTX_get(ctx);
D = BN_CTX_get(ctx);
M = BN_CTX_get(ctx);
Y = BN_CTX_get(ctx);
T = BN_CTX_get(ctx);
if (T == NULL) {
goto err;
}
if (out == NULL) {
R = BN_new();
} else {
R = out;
}
if (R == NULL) {
goto err;
}
BN_zero(Y);
if (!BN_one(X) || BN_copy(B, a) == NULL || BN_copy(A, n) == NULL) {
goto err;
}
A->neg = 0;
if (B->neg || (BN_ucmp(B, A) >= 0)) {
/* Turn BN_FLG_CONSTTIME flag on, so that when BN_div is invoked,
* BN_div_no_branch will be called eventually.
*/
pB = &local_B;
BN_with_flags(pB, B, BN_FLG_CONSTTIME);
if (!BN_nnmod(B, pB, A, ctx)) {
goto err;
}
}
sign = -1;
/* From B = a mod |n|, A = |n| it follows that
*
* 0 <= B < A,
* -sign*X*a == B (mod |n|),
* sign*Y*a == A (mod |n|).
*/
while (!BN_is_zero(B)) {
BIGNUM *tmp;
/*
* 0 < B < A,
* (*) -sign*X*a == B (mod |n|),
* sign*Y*a == A (mod |n|)
*/
/* Turn BN_FLG_CONSTTIME flag on, so that when BN_div is invoked,
* BN_div_no_branch will be called eventually.
*/
pA = &local_A;
BN_with_flags(pA, A, BN_FLG_CONSTTIME);
/* (D, M) := (A/B, A%B) ... */
if (!BN_div(D, M, pA, B, ctx)) {
goto err;
}
/* Now
* A = D*B + M;
* thus we have
* (**) sign*Y*a == D*B + M (mod |n|).
*/
tmp = A; /* keep the BIGNUM object, the value does not matter */
/* (A, B) := (B, A mod B) ... */
A = B;
B = M;
/* ... so we have 0 <= B < A again */
/* Since the former M is now B and the former B is now A,
* (**) translates into
* sign*Y*a == D*A + B (mod |n|),
* i.e.
* sign*Y*a - D*A == B (mod |n|).
* Similarly, (*) translates into
* -sign*X*a == A (mod |n|).
*
* Thus,
* sign*Y*a + D*sign*X*a == B (mod |n|),
* i.e.
* sign*(Y + D*X)*a == B (mod |n|).
*
* So if we set (X, Y, sign) := (Y + D*X, X, -sign), we arrive back at
* -sign*X*a == B (mod |n|),
* sign*Y*a == A (mod |n|).
* Note that X and Y stay non-negative all the time.
*/
if (!BN_mul(tmp, D, X, ctx)) {
goto err;
}
if (!BN_add(tmp, tmp, Y)) {
goto err;
}
M = Y; /* keep the BIGNUM object, the value does not matter */
Y = X;
X = tmp;
sign = -sign;
}
/*
* The while loop (Euclid's algorithm) ends when
* A == gcd(a,n);
* we have
* sign*Y*a == A (mod |n|),
* where Y is non-negative.
*/
if (sign < 0) {
if (!BN_sub(Y, n, Y)) {
goto err;
}
}
/* Now Y*a == A (mod |n|). */
if (BN_is_one(A)) {
/* Y*a == 1 (mod |n|) */
if (!Y->neg && BN_ucmp(Y, n) < 0) {
if (!BN_copy(R, Y)) {
goto err;
}
} else {
if (!BN_nnmod(R, Y, n, ctx)) {
goto err;
}
}
} else {
*out_no_inverse = 1;
OPENSSL_PUT_ERROR(BN, BN_R_NO_INVERSE);
goto err;
}
ret = R;
err:
if (ret == NULL && out == NULL) {
BN_free(R);
}
BN_CTX_end(ctx);
return ret;
}
@@ -67,34 +67,34 @@
!(defined(OPENSSL_X86) || (defined(OPENSSL_X86_64) && defined(__GNUC__)))
#ifdef BN_ULLONG
#define mul_add(r, a, w, c) \
do { \
BN_ULLONG t; \
t = (BN_ULLONG)(w) * (a) + (r) + (c); \
(r) = Lw(t); \
(c) = Hw(t); \
} while (0)
#define mul_add(r, a, w, c) \
{ \
BN_ULLONG t; \
t = (BN_ULLONG)w * (a) + (r) + (c); \
(r) = Lw(t); \
(c) = Hw(t); \
}
#define mul(r, a, w, c) \
do { \
BN_ULLONG t; \
t = (BN_ULLONG)(w) * (a) + (c); \
(r) = Lw(t); \
(c) = Hw(t); \
} while (0)
#define mul(r, a, w, c) \
{ \
BN_ULLONG t; \
t = (BN_ULLONG)w * (a) + (c); \
(r) = Lw(t); \
(c) = Hw(t); \
}
#define sqr(r0, r1, a) \
do { \
{ \
BN_ULLONG t; \
t = (BN_ULLONG)(a) * (a); \
(r0) = Lw(t); \
(r1) = Hw(t); \
} while (0)
}
#else
#define mul_add(r, a, w, c) \
do { \
{ \
BN_ULONG high, low, ret, tmp = (a); \
ret = (r); \
BN_UMULT_LOHI(low, high, w, tmp); \
@@ -104,23 +104,23 @@
ret += low; \
(c) += (ret < low) ? 1 : 0; \
(r) = ret; \
} while (0)
}
#define mul(r, a, w, c) \
do { \
{ \
BN_ULONG high, low, ret, ta = (a); \
BN_UMULT_LOHI(low, high, w, ta); \
ret = low + (c); \
(c) = high; \
(c) += (ret < low) ? 1 : 0; \
(r) = ret; \
} while (0)
}
#define sqr(r0, r1, a) \
do { \
{ \
BN_ULONG tmp = (a); \
BN_UMULT_LOHI(r0, r1, tmp, tmp); \
} while (0)
}
#endif /* !BN_ULLONG */
@@ -369,46 +369,42 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
do { \
BN_ULONG hi; \
BN_ULLONG t = (BN_ULLONG)(a) * (b); \
t += (c0); /* no carry */ \
(c0) = (BN_ULONG)Lw(t); \
t += c0; /* no carry */ \
c0 = (BN_ULONG)Lw(t); \
hi = (BN_ULONG)Hw(t); \
(c1) = ((c1) + (hi)) & BN_MASK2; \
if ((c1) < hi) { \
(c2)++; \
} \
c1 = (c1 + hi) & BN_MASK2; \
if (c1 < hi) \
c2++; \
} while (0)
#define mul_add_c2(a, b, c0, c1, c2) \
do { \
BN_ULONG hi; \
BN_ULLONG t = (BN_ULLONG)(a) * (b); \
BN_ULLONG tt = t + (c0); /* no carry */ \
(c0) = (BN_ULONG)Lw(tt); \
hi = (BN_ULONG)Hw(tt); \
(c1) = ((c1) + hi) & BN_MASK2; \
if ((c1) < hi) { \
(c2)++; \
} \
t += (c0); /* no carry */ \
(c0) = (BN_ULONG)Lw(t); \
hi = (BN_ULONG)Hw(t); \
(c1) = ((c1) + hi) & BN_MASK2; \
if ((c1) < hi) { \
(c2)++; \
} \
#define mul_add_c2(a, b, c0, c1, c2) \
do { \
BN_ULONG hi; \
BN_ULLONG t = (BN_ULLONG)(a) * (b); \
BN_ULLONG tt = t + c0; /* no carry */ \
c0 = (BN_ULONG)Lw(tt); \
hi = (BN_ULONG)Hw(tt); \
c1 = (c1 + hi) & BN_MASK2; \
if (c1 < hi) \
c2++; \
t += c0; /* no carry */ \
c0 = (BN_ULONG)Lw(t); \
hi = (BN_ULONG)Hw(t); \
c1 = (c1 + hi) & BN_MASK2; \
if (c1 < hi) \
c2++; \
} while (0)
#define sqr_add_c(a, i, c0, c1, c2) \
do { \
BN_ULONG hi; \
BN_ULLONG t = (BN_ULLONG)(a)[i] * (a)[i]; \
t += (c0); /* no carry */ \
(c0) = (BN_ULONG)Lw(t); \
hi = (BN_ULONG)Hw(t); \
(c1) = ((c1) + hi) & BN_MASK2; \
if ((c1) < hi) { \
(c2)++; \
} \
#define sqr_add_c(a, i, c0, c1, c2) \
do { \
BN_ULONG hi; \
BN_ULLONG t = (BN_ULLONG)a[i] * a[i]; \
t += c0; /* no carry */ \
c0 = (BN_ULONG)Lw(t); \
hi = (BN_ULONG)Hw(t); \
c1 = (c1 + hi) & BN_MASK2; \
if (c1 < hi) \
c2++; \
} while (0)
#define sqr_add_c2(a, i, j, c0, c1, c2) mul_add_c2((a)[i], (a)[j], c0, c1, c2)
@@ -422,10 +418,10 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
BN_ULONG ta = (a), tb = (b); \
BN_ULONG lo, hi; \
BN_UMULT_LOHI(lo, hi, ta, tb); \
(c0) += lo; \
hi += ((c0) < lo) ? 1 : 0; \
(c1) += hi; \
(c2) += ((c1) < hi) ? 1 : 0; \
c0 += lo; \
hi += (c0 < lo) ? 1 : 0; \
c1 += hi; \
c2 += (c1 < hi) ? 1 : 0; \
} while (0)
#define mul_add_c2(a, b, c0, c1, c2) \
@@ -433,14 +429,14 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
BN_ULONG ta = (a), tb = (b); \
BN_ULONG lo, hi, tt; \
BN_UMULT_LOHI(lo, hi, ta, tb); \
(c0) += lo; \
tt = hi + (((c0) < lo) ? 1 : 0); \
(c1) += tt; \
(c2) += ((c1) < tt) ? 1 : 0; \
(c0) += lo; \
c0 += lo; \
tt = hi + ((c0 < lo) ? 1 : 0); \
c1 += tt; \
c2 += (c1 < tt) ? 1 : 0; \
c0 += lo; \
hi += (c0 < lo) ? 1 : 0; \
(c1) += hi; \
(c2) += ((c1) < hi) ? 1 : 0; \
c1 += hi; \
c2 += (c1 < hi) ? 1 : 0; \
} while (0)
#define sqr_add_c(a, i, c0, c1, c2) \
@@ -448,10 +444,10 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b,
BN_ULONG ta = (a)[i]; \
BN_ULONG lo, hi; \
BN_UMULT_LOHI(lo, hi, ta, ta); \
(c0) += lo; \
c0 += lo; \
hi += (c0 < lo) ? 1 : 0; \
(c1) += hi; \
(c2) += ((c1) < hi) ? 1 : 0; \
c1 += hi; \
c2 += (c1 < hi) ? 1 : 0; \
} while (0)
#define sqr_add_c2(a, i, j, c0, c1, c2) mul_add_c2((a)[i], (a)[j], c0, c1, c2)
@@ -704,12 +700,4 @@ void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a) {
r[7] = c2;
}
#undef mul_add
#undef mul
#undef sqr
#undef mul_add_c
#undef mul_add_c2
#undef sqr_add_c
#undef sqr_add_c2
#endif
+237
View File
@@ -0,0 +1,237 @@
/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.]
*/
/* ====================================================================
* Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com).
*
*/
/* ====================================================================
* Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
*
* Portions of the attached software ("Contribution") are developed by
* SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
*
* The Contribution is licensed pursuant to the Eric Young open source
* license provided above.
*
* The binary polynomial arithmetic software is originally written by
* Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems
* Laboratories. */
#ifndef OPENSSL_HEADER_BN_INTERNAL_H
#define OPENSSL_HEADER_BN_INTERNAL_H
#include <openssl/base.h>
#if defined(OPENSSL_X86_64) && defined(_MSC_VER)
#pragma warning(push, 3)
#include <intrin.h>
#pragma warning(pop)
#pragma intrinsic(__umulh, _umul128)
#endif
#include "../internal.h"
#if defined(__cplusplus)
extern "C" {
#endif
/* bn_expand acts the same as |bn_wexpand|, but takes a number of bits rather
* than a number of words. */
BIGNUM *bn_expand(BIGNUM *bn, size_t bits);
#if defined(OPENSSL_64_BIT)
#if !defined(_MSC_VER)
/* MSVC doesn't support two-word integers on 64-bit. */
#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_TBIT (0x8000000000000000UL)
#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_TBIT (0x80000000UL)
#define BN_DEC_CONV (1000000000UL)
#define BN_DEC_NUM 9
#define TOBN(hi, lo) lo, hi
#else
#error "Must define either OPENSSL_32_BIT or OPENSSL_64_BIT"
#endif
#define STATIC_BIGNUM(x) \
{ \
(BN_ULONG *)x, sizeof(x) / sizeof(BN_ULONG), \
sizeof(x) / sizeof(BN_ULONG), 0, BN_FLG_STATIC_DATA \
}
#if defined(BN_ULLONG)
#define Lw(t) (((BN_ULONG)(t))&BN_MASK2)
#define Hw(t) (((BN_ULONG)((t)>>BN_BITS2))&BN_MASK2)
#endif
/* bn_set_words sets |bn| to the value encoded in the |num| words in |words|,
* 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);
void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b);
void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b);
void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a);
void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a);
/* bn_cmp_words returns a value less than, equal to or greater than zero if
* the, length |n|, array |a| is less than, equal to or greater than |b|. */
int bn_cmp_words(const BN_ULONG *a, const BN_ULONG *b, int n);
/* bn_cmp_words returns a value less than, equal to or greater than zero if the
* array |a| is less than, equal to or greater than |b|. The arrays can be of
* different lengths: |cl| gives the minimum of the two lengths and |dl| gives
* the length of |a| minus the length of |b|. */
int bn_cmp_part_words(const BN_ULONG *a, const BN_ULONG *b, int cl, int dl);
int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
const BN_ULONG *np, const BN_ULONG *n0, int num);
#if defined(OPENSSL_X86_64) && defined(_MSC_VER)
#define BN_UMULT_LOHI(low, high, a, b) ((low) = _umul128((a), (b), &(high)))
#endif
#if !defined(BN_ULLONG) && !defined(BN_UMULT_LOHI)
#error "Either BN_ULLONG or BN_UMULT_LOHI must be defined on every platform."
#endif
#if defined(__cplusplus)
} /* extern C */
#endif
#endif /* OPENSSL_HEADER_BN_INTERNAL_H */
+175
View File
@@ -0,0 +1,175 @@
/* ====================================================================
* Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com). */
#include <openssl/bn.h>
#include "internal.h"
/* least significant word */
#define BN_lsw(n) (((n)->top == 0) ? (BN_ULONG) 0 : (n)->d[0])
/* Returns -2 for errors because both -1 and 0 are valid results. */
int BN_kronecker(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
int i;
int ret = -2;
BIGNUM *A, *B, *tmp;
/* In 'tab', only odd-indexed entries are relevant:
* For any odd BIGNUM n,
* tab[BN_lsw(n) & 7]
* is $(-1)^{(n^2-1)/8}$ (using TeX notation).
* Note that the sign of n does not matter. */
static const int tab[8] = {0, 1, 0, -1, 0, -1, 0, 1};
BN_CTX_start(ctx);
A = BN_CTX_get(ctx);
B = BN_CTX_get(ctx);
if (B == NULL) {
goto end;
}
if (!BN_copy(A, a) ||
!BN_copy(B, b)) {
goto end;
}
/* Kronecker symbol, imlemented according to Henri Cohen,
* "A Course in Computational Algebraic Number Theory"
* (algorithm 1.4.10). */
/* Cohen's step 1: */
if (BN_is_zero(B)) {
ret = BN_abs_is_word(A, 1);
goto end;
}
/* Cohen's step 2: */
if (!BN_is_odd(A) && !BN_is_odd(B)) {
ret = 0;
goto end;
}
/* now B is non-zero */
i = 0;
while (!BN_is_bit_set(B, i)) {
i++;
}
if (!BN_rshift(B, B, i)) {
goto end;
}
if (i & 1) {
/* i is odd */
/* (thus B was even, thus A must be odd!) */
/* set 'ret' to $(-1)^{(A^2-1)/8}$ */
ret = tab[BN_lsw(A) & 7];
} else {
/* i is even */
ret = 1;
}
if (B->neg) {
B->neg = 0;
if (A->neg) {
ret = -ret;
}
}
/* now B is positive and odd, so what remains to be done is to compute the
* Jacobi symbol (A/B) and multiply it by 'ret' */
while (1) {
/* Cohen's step 3: */
/* B is positive and odd */
if (BN_is_zero(A)) {
ret = BN_is_one(B) ? ret : 0;
goto end;
}
/* now A is non-zero */
i = 0;
while (!BN_is_bit_set(A, i)) {
i++;
}
if (!BN_rshift(A, A, i)) {
goto end;
}
if (i & 1) {
/* i is odd */
/* multiply 'ret' by $(-1)^{(B^2-1)/8}$ */
ret = ret * tab[BN_lsw(B) & 7];
}
/* Cohen's step 4: */
/* multiply 'ret' by $(-1)^{(A-1)(B-1)/4}$ */
if ((A->neg ? ~BN_lsw(A) : BN_lsw(A)) & BN_lsw(B) & 2) {
ret = -ret;
}
/* (A, B) := (B mod |A|, |A|) */
if (!BN_nnmod(B, B, A, ctx)) {
ret = -2;
goto end;
}
tmp = A;
A = B;
B = tmp;
tmp->neg = 0;
}
end:
BN_CTX_end(ctx);
return ret;
}
@@ -108,7 +108,6 @@
#include <openssl/bn.h>
#include <assert.h>
#include <string.h>
#include <openssl/err.h>
@@ -116,7 +115,7 @@
#include <openssl/thread.h>
#include "internal.h"
#include "../../internal.h"
#include "../internal.h"
#if !defined(OPENSSL_NO_ASM) && \
@@ -125,11 +124,6 @@
#define OPENSSL_BN_ASM_MONT
#endif
static int bn_mod_mul_montgomery_fallback(BIGNUM *r, const BIGNUM *a,
const BIGNUM *b,
const BN_MONT_CTX *mont, BN_CTX *ctx);
BN_MONT_CTX *BN_MONT_CTX_new(void) {
BN_MONT_CTX *ret = OPENSSL_malloc(sizeof(BN_MONT_CTX));
@@ -137,7 +131,7 @@ BN_MONT_CTX *BN_MONT_CTX_new(void) {
return NULL;
}
OPENSSL_memset(ret, 0, sizeof(BN_MONT_CTX));
memset(ret, 0, sizeof(BN_MONT_CTX));
BN_init(&ret->RR);
BN_init(&ret->N);
@@ -168,69 +162,141 @@ BN_MONT_CTX *BN_MONT_CTX_copy(BN_MONT_CTX *to, const BN_MONT_CTX *from) {
return to;
}
OPENSSL_COMPILE_ASSERT(BN_MONT_CTX_N0_LIMBS == 1 || BN_MONT_CTX_N0_LIMBS == 2,
BN_MONT_CTX_N0_LIMBS_VALUE_INVALID);
OPENSSL_COMPILE_ASSERT(sizeof(BN_ULONG) * BN_MONT_CTX_N0_LIMBS ==
sizeof(uint64_t), BN_MONT_CTX_set_64_bit_mismatch);
int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx) {
int ret = 0;
BIGNUM *Ri, *R;
BIGNUM tmod;
BN_ULONG buf[2];
if (BN_is_zero(mod)) {
OPENSSL_PUT_ERROR(BN, BN_R_DIV_BY_ZERO);
return 0;
}
if (!BN_is_odd(mod)) {
OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS);
return 0;
}
if (BN_is_negative(mod)) {
OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER);
return 0;
}
/* Save the modulus. */
BN_CTX_start(ctx);
Ri = BN_CTX_get(ctx);
if (Ri == NULL) {
goto err;
}
R = &mont->RR; /* grab RR as a temp */
if (!BN_copy(&mont->N, mod)) {
OPENSSL_PUT_ERROR(BN, ERR_R_INTERNAL_ERROR);
return 0;
goto err; /* Set N */
}
mont->N.neg = 0;
BN_init(&tmod);
tmod.d = buf;
tmod.dmax = 2;
tmod.neg = 0;
#if defined(OPENSSL_BN_ASM_MONT) && (BN_BITS2 <= 32)
/* Only certain BN_BITS2<=32 platforms actually make use of
* n0[1], and we could use the #else case (with a shorter R
* value) for the others. However, currently only the assembler
* files do know which is which. */
BN_zero(R);
if (!BN_set_bit(R, 2 * BN_BITS2)) {
goto err;
}
/* Find n0 such that n0 * N == -1 (mod r).
*
* Only certain BN_BITS2<=32 platforms actually make use of n0[1]. For the
* others, we could use a shorter R value and use faster |BN_ULONG|-based
* math instead of |uint64_t|-based math, which would be double-precision.
* However, currently only the assembler files know which is which. */
uint64_t n0 = bn_mont_n0(mod);
mont->n0[0] = (BN_ULONG)n0;
#if BN_MONT_CTX_N0_LIMBS == 2
mont->n0[1] = (BN_ULONG)(n0 >> BN_BITS2);
tmod.top = 0;
if ((buf[0] = mod->d[0])) {
tmod.top = 1;
}
if ((buf[1] = mod->top > 1 ? mod->d[1] : 0)) {
tmod.top = 2;
}
if (BN_mod_inverse(Ri, R, &tmod, ctx) == NULL) {
goto err;
}
if (!BN_lshift(Ri, Ri, 2 * BN_BITS2)) {
goto err; /* R*Ri */
}
if (!BN_is_zero(Ri)) {
if (!BN_sub_word(Ri, 1)) {
goto err;
}
} else {
/* if N mod word size == 1 */
if (bn_expand(Ri, (int)sizeof(BN_ULONG) * 2) == NULL) {
goto err;
}
/* Ri-- (mod double word size) */
Ri->neg = 0;
Ri->d[0] = BN_MASK2;
Ri->d[1] = BN_MASK2;
Ri->top = 2;
}
if (!BN_div(Ri, NULL, Ri, &tmod, ctx)) {
goto err;
}
/* Ni = (R*Ri-1)/N,
* keep only couple of least significant words: */
mont->n0[0] = (Ri->top > 0) ? Ri->d[0] : 0;
mont->n0[1] = (Ri->top > 1) ? Ri->d[1] : 0;
#else
BN_zero(R);
if (!BN_set_bit(R, BN_BITS2)) {
goto err; /* R */
}
buf[0] = mod->d[0]; /* tmod = N mod word size */
buf[1] = 0;
tmod.top = buf[0] != 0 ? 1 : 0;
/* Ri = R^-1 mod N*/
if (BN_mod_inverse(Ri, R, &tmod, ctx) == NULL) {
goto err;
}
if (!BN_lshift(Ri, Ri, BN_BITS2)) {
goto err; /* R*Ri */
}
if (!BN_is_zero(Ri)) {
if (!BN_sub_word(Ri, 1)) {
goto err;
}
} else {
/* if N mod word size == 1 */
if (!BN_set_word(Ri, BN_MASK2)) {
goto err; /* Ri-- (mod word size) */
}
}
if (!BN_div(Ri, NULL, Ri, &tmod, ctx)) {
goto err;
}
/* Ni = (R*Ri-1)/N,
* keep only least significant word: */
mont->n0[0] = (Ri->top > 0) ? Ri->d[0] : 0;
mont->n0[1] = 0;
#endif
/* Save RR = R**2 (mod N). R is the smallest power of 2**BN_BITS 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. */
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;
/* RR = (2^ri)^2 == 2^(ri*2) == 1 << (ri*2), which has its (ri*2)th bit set. */
int ri = (BN_num_bits(mod) + (BN_BITS2 - 1)) / BN_BITS2 * BN_BITS2;
BN_zero(&(mont->RR));
if (!BN_set_bit(&(mont->RR), ri * 2)) {
goto err;
}
if (!BN_mod(&(mont->RR), &(mont->RR), &(mont->N), ctx)) {
goto err;
}
return 1;
ret = 1;
err:
BN_CTX_end(ctx);
return ret;
}
int BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, CRYPTO_MUTEX *lock,
const BIGNUM *mod, BN_CTX *bn_ctx) {
BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, CRYPTO_MUTEX *lock,
const BIGNUM *mod, BN_CTX *bn_ctx) {
CRYPTO_MUTEX_lock_read(lock);
BN_MONT_CTX *ctx = *pmont;
CRYPTO_MUTEX_unlock_read(lock);
CRYPTO_MUTEX_unlock(lock);
if (ctx) {
return 1;
return ctx;
}
CRYPTO_MUTEX_lock_write(lock);
@@ -251,8 +317,8 @@ int BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, CRYPTO_MUTEX *lock,
*pmont = ctx;
out:
CRYPTO_MUTEX_unlock_write(lock);
return ctx != NULL;
CRYPTO_MUTEX_unlock(lock);
return ctx;
}
int BN_to_montgomery(BIGNUM *ret, const BIGNUM *a, const BN_MONT_CTX *mont,
@@ -273,7 +339,7 @@ static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r,
}
max = (2 * nl); /* carry is stored separately */
if (!bn_wexpand(r, max)) {
if (bn_wexpand(r, max) == NULL) {
return 0;
}
@@ -283,7 +349,7 @@ static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r,
/* clear the top words of T */
if (max > r->top) {
OPENSSL_memset(&rp[r->top], 0, (max - r->top) * sizeof(BN_ULONG));
memset(&rp[r->top], 0, (max - r->top) * sizeof(BN_ULONG));
}
r->top = max;
@@ -297,7 +363,7 @@ static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r,
rp[nl] = v;
}
if (!bn_wexpand(ret, nl)) {
if (bn_wexpand(ret, nl) == NULL) {
return 0;
}
ret->top = nl;
@@ -366,43 +432,27 @@ err:
int BN_mod_mul_montgomery(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
const BN_MONT_CTX *mont, BN_CTX *ctx) {
#if !defined(OPENSSL_BN_ASM_MONT)
return bn_mod_mul_montgomery_fallback(r, a, b, mont, ctx);
#else
int num = mont->N.top;
/* |bn_mul_mont| requires at least 128 bits of limbs, at least for x86. */
if (num < (128 / BN_BITS2) ||
a->top != num ||
b->top != num) {
return bn_mod_mul_montgomery_fallback(r, a, b, mont, ctx);
}
if (!bn_wexpand(r, num)) {
return 0;
}
if (!bn_mul_mont(r->d, a->d, b->d, mont->N.d, mont->n0, num)) {
/* The check above ensures this won't happen. */
assert(0);
OPENSSL_PUT_ERROR(BN, ERR_R_INTERNAL_ERROR);
return 0;
}
r->neg = a->neg ^ b->neg;
r->top = num;
bn_correct_top(r);
return 1;
#endif
}
static int bn_mod_mul_montgomery_fallback(BIGNUM *r, const BIGNUM *a,
const BIGNUM *b,
const BN_MONT_CTX *mont,
BN_CTX *ctx) {
BIGNUM *tmp;
int ret = 0;
#if defined(OPENSSL_BN_ASM_MONT)
int num = mont->N.top;
if (num > 1 && a->top == num && b->top == num) {
if (bn_wexpand(r, num) == NULL) {
return 0;
}
if (bn_mul_mont(r->d, a->d, b->d, mont->N.d, mont->n0, num)) {
r->neg = a->neg ^ b->neg;
r->top = num;
bn_correct_top(r);
return 1;
}
}
#endif
BN_CTX_start(ctx);
BIGNUM *tmp = BN_CTX_get(ctx);
tmp = BN_CTX_get(ctx);
if (tmp == NULL) {
goto err;
}
+19 -21
View File
@@ -312,8 +312,7 @@ static void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2,
if (n2 < BN_MUL_RECURSIVE_SIZE_NORMAL) {
bn_mul_normal(r, a, n2 + dna, b, n2 + dnb);
if ((dna + dnb) < 0) {
OPENSSL_memset(&r[2 * n2 + dna + dnb], 0,
sizeof(BN_ULONG) * -(dna + dnb));
memset(&r[2 * n2 + dna + dnb], 0, sizeof(BN_ULONG) * -(dna + dnb));
}
return;
}
@@ -359,7 +358,7 @@ static void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2,
if (!zero) {
bn_mul_comba4(&(t[n2]), t, &(t[n]));
} else {
OPENSSL_memset(&(t[n2]), 0, 8 * sizeof(BN_ULONG));
memset(&(t[n2]), 0, 8 * sizeof(BN_ULONG));
}
bn_mul_comba4(r, a, b);
@@ -369,7 +368,7 @@ static void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2,
if (!zero) {
bn_mul_comba8(&(t[n2]), t, &(t[n]));
} else {
OPENSSL_memset(&(t[n2]), 0, 16 * sizeof(BN_ULONG));
memset(&(t[n2]), 0, 16 * sizeof(BN_ULONG));
}
bn_mul_comba8(r, a, b);
@@ -379,7 +378,7 @@ static void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2,
if (!zero) {
bn_mul_recursive(&(t[n2]), t, &(t[n]), n, 0, 0, p);
} else {
OPENSSL_memset(&(t[n2]), 0, n2 * sizeof(BN_ULONG));
memset(&(t[n2]), 0, n2 * sizeof(BN_ULONG));
}
bn_mul_recursive(r, a, b, n, 0, 0, p);
bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]), n, dna, dnb, p);
@@ -474,7 +473,7 @@ static void bn_mul_part_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n,
bn_mul_comba8(&(t[n2]), t, &(t[n]));
bn_mul_comba8(r, a, b);
bn_mul_normal(&(r[n2]), &(a[n]), tna, &(b[n]), tnb);
OPENSSL_memset(&(r[n2 + tna + tnb]), 0, sizeof(BN_ULONG) * (n2 - tna - tnb));
memset(&(r[n2 + tna + tnb]), 0, sizeof(BN_ULONG) * (n2 - tna - tnb));
} else {
p = &(t[n2 * 2]);
bn_mul_recursive(&(t[n2]), t, &(t[n]), n, 0, 0, p);
@@ -490,15 +489,14 @@ static void bn_mul_part_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n,
if (j == 0) {
bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]), i, tna - i, tnb - i, p);
OPENSSL_memset(&(r[n2 + i * 2]), 0, sizeof(BN_ULONG) * (n2 - i * 2));
memset(&(r[n2 + i * 2]), 0, sizeof(BN_ULONG) * (n2 - i * 2));
} else if (j > 0) {
/* eg, n == 16, i == 8 and tn == 11 */
bn_mul_part_recursive(&(r[n2]), &(a[n]), &(b[n]), i, tna - i, tnb - i, p);
OPENSSL_memset(&(r[n2 + tna + tnb]), 0,
sizeof(BN_ULONG) * (n2 - tna - tnb));
memset(&(r[n2 + tna + tnb]), 0, sizeof(BN_ULONG) * (n2 - tna - tnb));
} else {
/* (j < 0) eg, n == 16, i == 8 and tn == 5 */
OPENSSL_memset(&(r[n2]), 0, sizeof(BN_ULONG) * n2);
memset(&(r[n2]), 0, sizeof(BN_ULONG) * n2);
if (tna < BN_MUL_RECURSIVE_SIZE_NORMAL &&
tnb < BN_MUL_RECURSIVE_SIZE_NORMAL) {
bn_mul_normal(&(r[n2]), &(a[n]), tna, &(b[n]), tnb);
@@ -591,7 +589,7 @@ int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
i = al - bl;
if (i == 0) {
if (al == 8) {
if (!bn_wexpand(rr, 16)) {
if (bn_wexpand(rr, 16) == NULL) {
goto err;
}
rr->top = 16;
@@ -619,19 +617,19 @@ int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
goto err;
}
if (al > j || bl > j) {
if (!bn_wexpand(t, k * 4)) {
if (bn_wexpand(t, k * 4) == NULL) {
goto err;
}
if (!bn_wexpand(rr, k * 4)) {
if (bn_wexpand(rr, k * 4) == NULL) {
goto err;
}
bn_mul_part_recursive(rr->d, a->d, b->d, j, al - j, bl - j, t->d);
} else {
/* al <= j || bl <= j */
if (!bn_wexpand(t, k * 2)) {
if (bn_wexpand(t, k * 2) == NULL) {
goto err;
}
if (!bn_wexpand(rr, k * 2)) {
if (bn_wexpand(rr, k * 2) == NULL) {
goto err;
}
bn_mul_recursive(rr->d, a->d, b->d, j, al - j, bl - j, t->d);
@@ -641,7 +639,7 @@ int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
}
}
if (!bn_wexpand(rr, top)) {
if (bn_wexpand(rr, top) == NULL) {
goto err;
}
rr->top = top;
@@ -737,7 +735,7 @@ static void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2, BN_ULONG *t
if (!zero) {
bn_sqr_recursive(&(t[n2]), t, n, p);
} else {
OPENSSL_memset(&(t[n2]), 0, n2 * sizeof(BN_ULONG));
memset(&(t[n2]), 0, n2 * sizeof(BN_ULONG));
}
bn_sqr_recursive(r, a, n, p);
bn_sqr_recursive(&(r[n2]), &(a[n]), n, p);
@@ -790,7 +788,7 @@ int BN_mul_word(BIGNUM *bn, BN_ULONG w) {
ll = bn_mul_words(bn->d, bn->d, bn->top, w);
if (ll) {
if (!bn_wexpand(bn, bn->top + 1)) {
if (bn_wexpand(bn, bn->top + 1) == NULL) {
return 0;
}
bn->d[bn->top++] = ll;
@@ -819,7 +817,7 @@ int BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) {
}
max = 2 * al; /* Non-zero (from above) */
if (!bn_wexpand(rr, max)) {
if (bn_wexpand(rr, max) == NULL) {
goto err;
}
@@ -838,12 +836,12 @@ int BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) {
j = 1 << (j - 1);
k = j + j;
if (al == j) {
if (!bn_wexpand(tmp, k * 2)) {
if (bn_wexpand(tmp, k * 2) == NULL) {
goto err;
}
bn_sqr_recursive(rr->d, a->d, al, tmp->d);
} else {
if (!bn_wexpand(tmp, max)) {
if (bn_wexpand(tmp, max) == NULL) {
goto err;
}
bn_sqr_normal(rr->d, a->d, al, tmp->d);
+142 -191
View File
@@ -113,10 +113,29 @@
#include "internal.h"
/* number of Miller-Rabin iterations for an error rate of less than 2^-80
* for random 'b'-bit input, b >= 100 (taken from table 4.4 in the Handbook
* of Applied Cryptography [Menezes, van Oorschot, Vanstone; CRC Press 1996];
* original paper: Damgaard, Landrock, Pomerance: Average case error estimates
* for the strong probable prime test. -- Math. Comp. 61 (1993) 177-194) */
#define BN_prime_checks_for_size(b) ((b) >= 1300 ? 2 : \
(b) >= 850 ? 3 : \
(b) >= 650 ? 4 : \
(b) >= 550 ? 5 : \
(b) >= 450 ? 6 : \
(b) >= 400 ? 7 : \
(b) >= 350 ? 8 : \
(b) >= 300 ? 9 : \
(b) >= 250 ? 12 : \
(b) >= 200 ? 15 : \
(b) >= 150 ? 18 : \
/* b >= 100 */ 27)
/* The quick sieve algorithm approach to weeding out primes is Philip
* Zimmermann's, as implemented in PGP. I have had a read of his comments and
* implemented my own version. */
/* NUMPRIMES is the number of primes that fit into a uint16_t. */
#define NUMPRIMES 2048
/* primes contains all the primes that fit into a uint16_t. */
@@ -310,37 +329,8 @@ static const uint16_t primes[NUMPRIMES] = {
17851, 17863,
};
/* BN_prime_checks_for_size returns the number of Miller-Rabin iterations
* necessary for a 'bits'-bit prime, in order to maintain an error rate greater
* than the security level for an RSA prime of that many bits (calculated using
* the FIPS SP 800-57 security level and 186-4 Section F.1; original paper:
* Damgaard, Landrock, Pomerance: Average case error estimates for the strong
* probable prime test. -- Math. Comp. 61 (1993) 177-194) */
static int BN_prime_checks_for_size(int bits) {
if (bits >= 3747) {
return 3;
}
if (bits >= 1345) {
return 4;
}
if (bits >= 476) {
return 5;
}
if (bits >= 400) {
return 6;
}
if (bits >= 308) {
return 8;
}
if (bits >= 205) {
return 13;
}
if (bits >= 155) {
return 19;
}
return 28;
}
static int witness(BIGNUM *w, const BIGNUM *a, const BIGNUM *a1,
const BIGNUM *a1_odd, int k, BN_CTX *ctx, BN_MONT_CTX *mont);
static int probable_prime(BIGNUM *rnd, int bits);
static int probable_prime_dh(BIGNUM *rnd, int bits, const BIGNUM *add,
const BIGNUM *rem, BN_CTX *ctx);
@@ -481,201 +471,174 @@ int BN_is_prime_ex(const BIGNUM *candidate, int checks, BN_CTX *ctx, BN_GENCB *c
return BN_is_prime_fasttest_ex(candidate, checks, ctx, 0, cb);
}
int BN_is_prime_fasttest_ex(const BIGNUM *a, int checks, BN_CTX *ctx,
int BN_is_prime_fasttest_ex(const BIGNUM *a, int checks, BN_CTX *ctx_passed,
int do_trial_division, BN_GENCB *cb) {
int i, j, ret = -1;
int k;
BN_CTX *ctx = NULL;
BIGNUM *A1, *A1_odd, *check; /* taken from ctx */
BN_MONT_CTX *mont = NULL;
const BIGNUM *A = NULL;
if (BN_cmp(a, BN_value_one()) <= 0) {
return 0;
}
if (checks == BN_prime_checks) {
checks = BN_prime_checks_for_size(BN_num_bits(a));
}
/* first look for small factors */
if (!BN_is_odd(a)) {
/* a is even => a is prime if and only if a == 2 */
return BN_is_word(a, 2);
}
/* Enhanced Miller-Rabin does not work for three. */
if (BN_is_word(a, 3)) {
return 1;
}
if (do_trial_division) {
for (int i = 1; i < NUMPRIMES; i++) {
BN_ULONG mod = BN_mod_word(a, primes[i]);
if (mod == (BN_ULONG)-1) {
return -1;
}
if (mod == 0) {
return BN_is_word(a, primes[i]);
for (i = 1; i < NUMPRIMES; i++) {
if (BN_mod_word(a, primes[i]) == 0) {
return 0;
}
}
if (!BN_GENCB_call(cb, 1, -1)) {
return -1;
goto err;
}
}
int ret = -1;
BN_CTX *ctx_allocated = NULL;
if (ctx == NULL) {
ctx_allocated = BN_CTX_new();
if (ctx_allocated == NULL) {
return -1;
}
ctx = ctx_allocated;
}
enum bn_primality_result_t result;
if (!BN_enhanced_miller_rabin_primality_test(&result, a, checks, ctx, cb)) {
if (ctx_passed != NULL) {
ctx = ctx_passed;
} else if ((ctx = BN_CTX_new()) == NULL) {
goto err;
}
ret = (result == bn_probably_prime);
err:
BN_CTX_free(ctx_allocated);
return ret;
}
int BN_enhanced_miller_rabin_primality_test(
enum bn_primality_result_t *out_result, const BIGNUM *w, int iterations,
BN_CTX *ctx, BN_GENCB *cb) {
/* Enhanced Miller-Rabin is only valid on odd integers greater than 3. */
if (!BN_is_odd(w) || BN_cmp_word(w, 3) <= 0) {
OPENSSL_PUT_ERROR(BN, BN_R_INVALID_INPUT);
return 0;
}
if (iterations == BN_prime_checks) {
iterations = BN_prime_checks_for_size(BN_num_bits(w));
}
int ret = 0;
BN_MONT_CTX *mont = NULL;
BN_CTX_start(ctx);
BIGNUM *w1 = BN_CTX_get(ctx);
if (w1 == NULL ||
!BN_copy(w1, w) ||
!BN_sub_word(w1, 1)) {
/* A := abs(a) */
if (a->neg) {
BIGNUM *t = BN_CTX_get(ctx);
if (t == NULL || !BN_copy(t, a)) {
goto err;
}
t->neg = 0;
A = t;
} else {
A = a;
}
A1 = BN_CTX_get(ctx);
A1_odd = BN_CTX_get(ctx);
check = BN_CTX_get(ctx);
if (check == NULL) {
goto err;
}
/* Write w1 as m*2^a (Steps 1 and 2). */
int a = 0;
while (!BN_is_bit_set(w1, a)) {
a++;
/* compute A1 := A - 1 */
if (!BN_copy(A1, A)) {
goto err;
}
BIGNUM *m = BN_CTX_get(ctx);
if (m == NULL ||
!BN_rshift(m, w1, a)) {
if (!BN_sub_word(A1, 1)) {
goto err;
}
if (BN_is_zero(A1)) {
ret = 0;
goto err;
}
BIGNUM *b = BN_CTX_get(ctx);
BIGNUM *g = BN_CTX_get(ctx);
BIGNUM *z = BN_CTX_get(ctx);
BIGNUM *x = BN_CTX_get(ctx);
BIGNUM *x1 = BN_CTX_get(ctx);
if (b == NULL ||
g == NULL ||
z == NULL ||
x == NULL ||
x1 == NULL) {
/* write A1 as A1_odd * 2^k */
k = 1;
while (!BN_is_bit_set(A1, k)) {
k++;
}
if (!BN_rshift(A1_odd, A1, k)) {
goto err;
}
/* Montgomery setup for computations mod A */
mont = BN_MONT_CTX_new();
if (mont == NULL ||
!BN_MONT_CTX_set(mont, w, ctx)) {
if (mont == NULL) {
goto err;
}
if (!BN_MONT_CTX_set(mont, A, ctx)) {
goto err;
}
/* The following loop performs in inner iteration of the Enhanced Miller-Rabin
* Primality test (Step 4). */
for (int i = 1; i <= iterations; i++) {
/* Step 4.1-4.2 */
if (!BN_rand_range_ex(b, 2, w1)) {
for (i = 0; i < checks; i++) {
if (!BN_pseudo_rand_range(check, A1)) {
goto err;
}
/* Step 4.3-4.4 */
if (!BN_gcd(g, b, w, ctx)) {
if (!BN_add_word(check, 1)) {
goto err;
}
if (BN_cmp_word(g, 1) > 0) {
*out_result = bn_composite;
ret = 1;
/* now 1 <= check < A */
j = witness(check, A, A1, A1_odd, k, ctx, mont);
if (j == -1) {
goto err;
}
/* Step 4.5 */
if (!BN_mod_exp_mont(z, b, m, w, ctx, mont)) {
if (j) {
ret = 0;
goto err;
}
/* Step 4.6 */
if (BN_is_one(z) || BN_cmp(z, w1) == 0) {
goto loop;
}
/* Step 4.7 */
for (int j = 1; j < a; j++) {
if (!BN_copy(x, z) || !BN_mod_mul(z, x, x, w, ctx)) {
goto err;
}
if (BN_cmp(z, w1) == 0) {
goto loop;
}
if (BN_is_one(z)) {
goto composite;
}
}
/* Step 4.8-4.9 */
if (!BN_copy(x, z) || !BN_mod_mul(z, x, x, w, ctx)) {
goto err;
}
/* Step 4.10-4.11 */
if (!BN_is_one(z) && !BN_copy(x, z)) {
goto err;
}
composite:
/* Step 4.12-4.14 */
if (!BN_copy(x1, x) ||
!BN_sub_word(x1, 1) ||
!BN_gcd(g, x1, w, ctx)) {
goto err;
}
if (BN_cmp_word(g, 1) > 0) {
*out_result = bn_composite;
} else {
*out_result = bn_non_prime_power_composite;
}
ret = 1;
goto err;
loop:
/* Step 4.15 */
if (!BN_GENCB_call(cb, 1, i)) {
goto err;
}
}
*out_result = bn_probably_prime;
ret = 1;
err:
BN_MONT_CTX_free(mont);
BN_CTX_end(ctx);
if (ctx != NULL) {
BN_CTX_end(ctx);
if (ctx_passed == NULL) {
BN_CTX_free(ctx);
}
}
if (mont != NULL) {
BN_MONT_CTX_free(mont);
}
return ret;
}
static int witness(BIGNUM *w, const BIGNUM *a, const BIGNUM *a1,
const BIGNUM *a1_odd, int k, BN_CTX *ctx,
BN_MONT_CTX *mont) {
if (!BN_mod_exp_mont(w, w, a1_odd, a, ctx, mont)) { /* w := w^a1_odd mod a */
return -1;
}
if (BN_is_one(w)) {
return 0; /* probably prime */
}
if (BN_cmp(w, a1) == 0) {
return 0; /* w == -1 (mod a), 'a' is probably prime */
}
while (--k) {
if (!BN_mod_mul(w, w, w, a, ctx)) { /* w := w^2 mod a */
return -1;
}
if (BN_is_one(w)) {
return 1; /* 'a' is composite, otherwise a previous 'w' would
* have been == -1 (mod 'a') */
}
if (BN_cmp(w, a1) == 0) {
return 0; /* w == -1 (mod a), 'a' is probably prime */
}
}
/* If we get here, 'w' is the (a-1)/2-th power of the original 'w',
* and it is neither -1 nor +1 -- so 'a' cannot be prime */
return 1;
}
static BN_ULONG get_word(const BIGNUM *bn) {
if (bn->top == 1) {
return bn->d[0];
}
return 0;
}
static int probable_prime(BIGNUM *rnd, int bits) {
int i;
uint16_t mods[NUMPRIMES];
@@ -684,17 +647,13 @@ static int probable_prime(BIGNUM *rnd, int bits) {
char is_single_word = bits <= BN_BITS2;
again:
if (!BN_rand(rnd, bits, BN_RAND_TOP_TWO, BN_RAND_BOTTOM_ODD)) {
if (!BN_rand(rnd, bits, 1, 1)) {
return 0;
}
/* we now have a random number 'rnd' to test. */
for (i = 1; i < NUMPRIMES; i++) {
BN_ULONG mod = BN_mod_word(rnd, (BN_ULONG)primes[i]);
if (mod == (BN_ULONG)-1) {
return 0;
}
mods[i] = (uint16_t)mod;
mods[i] = (uint16_t)BN_mod_word(rnd, (BN_ULONG)primes[i]);
}
/* If bits is so small that it fits into a single word then we
* additionally don't want to exceed that many bits. */
@@ -702,9 +661,9 @@ again:
BN_ULONG size_limit;
if (bits == BN_BITS2) {
/* Avoid undefined behavior. */
size_limit = ~((BN_ULONG)0) - BN_get_word(rnd);
size_limit = ~((BN_ULONG)0) - get_word(rnd);
} else {
size_limit = (((BN_ULONG)1) << bits) - BN_get_word(rnd) - 1;
size_limit = (((BN_ULONG)1) << bits) - get_word(rnd) - 1;
}
if (size_limit < maxdelta) {
maxdelta = size_limit;
@@ -714,7 +673,7 @@ again:
loop:
if (is_single_word) {
BN_ULONG rnd_word = BN_get_word(rnd);
BN_ULONG rnd_word = get_word(rnd);
/* In the case that the candidate prime is a single word then
* we check that:
@@ -768,7 +727,7 @@ static int probable_prime_dh(BIGNUM *rnd, int bits, const BIGNUM *add,
goto err;
}
if (!BN_rand(rnd, bits, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ODD)) {
if (!BN_rand(rnd, bits, 0, 1)) {
goto err;
}
@@ -794,11 +753,7 @@ static int probable_prime_dh(BIGNUM *rnd, int bits, const BIGNUM *add,
loop:
for (i = 1; i < NUMPRIMES; i++) {
/* check that rnd is a prime */
BN_ULONG mod = BN_mod_word(rnd, (BN_ULONG)primes[i]);
if (mod == (BN_ULONG)-1) {
goto err;
}
if (mod <= 1) {
if (BN_mod_word(rnd, (BN_ULONG)primes[i]) <= 1) {
if (!BN_add(rnd, rnd, add)) {
goto err;
}
@@ -831,7 +786,7 @@ static int probable_prime_dh_safe(BIGNUM *p, int bits, const BIGNUM *padd,
goto err;
}
if (!BN_rand(q, bits, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ODD)) {
if (!BN_rand(q, bits, 0, 1)) {
goto err;
}
@@ -870,12 +825,8 @@ loop:
/* check that p and q are prime */
/* check that for p and q
* gcd(p-1,primes) == 1 (except for 2) */
BN_ULONG pmod = BN_mod_word(p, (BN_ULONG)primes[i]);
BN_ULONG qmod = BN_mod_word(q, (BN_ULONG)primes[i]);
if (pmod == (BN_ULONG)-1 || qmod == (BN_ULONG)-1) {
goto err;
}
if (pmod == 0 || qmod == 0) {
if ((BN_mod_word(p, (BN_ULONG)primes[i]) == 0) ||
(BN_mod_word(q, (BN_ULONG)primes[i]) == 0)) {
if (!BN_add(p, p, padd)) {
goto err;
}
+326
View File
@@ -0,0 +1,326 @@
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.]
*/
/* ====================================================================
* Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com). */
#include <openssl/bn.h>
#include <string.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) {
uint8_t *buf = NULL;
int ret = 0, bit, bytes, mask;
if (rnd == NULL) {
return 0;
}
if (bits == 0) {
BN_zero(rnd);
return 1;
}
bytes = (bits + 7) / 8;
bit = (bits - 1) % 8;
mask = 0xff << (bit + 1);
buf = OPENSSL_malloc(bytes);
if (buf == NULL) {
OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
goto err;
}
/* Make a random number and set the top and bottom bits. */
if (!RAND_bytes(buf, bytes)) {
goto err;
}
if (top != -1) {
if (top && bits > 1) {
if (bit == 0) {
buf[0] = 1;
buf[1] |= 0x80;
} else {
buf[0] |= (3 << (bit - 1));
}
} else {
buf[0] |= (1 << bit);
}
}
buf[0] &= ~mask;
/* set bottom bit if requested */
if (bottom) {
buf[bytes - 1] |= 1;
}
if (!BN_bin2bn(buf, bytes, rnd)) {
goto err;
}
ret = 1;
err:
if (buf != NULL) {
OPENSSL_cleanse(buf, bytes);
OPENSSL_free(buf);
}
return (ret);
}
int BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom) {
return BN_rand(rnd, bits, top, bottom);
}
int BN_rand_range(BIGNUM *r, const BIGNUM *range) {
unsigned n;
unsigned count = 100;
if (range->neg || BN_is_zero(range)) {
OPENSSL_PUT_ERROR(BN, BN_R_INVALID_RANGE);
return 0;
}
n = BN_num_bits(range); /* n > 0 */
/* BN_is_bit_set(range, n - 1) always holds */
if (n == 1) {
BN_zero(r);
} else if (!BN_is_bit_set(range, n - 2) && !BN_is_bit_set(range, n - 3)) {
/* range = 100..._2,
* so 3*range (= 11..._2) is exactly one bit longer than range */
do {
if (!BN_rand(r, n + 1, -1 /* don't set most significant bits */,
0 /* don't set least significant bits */)) {
return 0;
}
/* If r < 3*range, use r := r MOD range (which is either r, r - range, or
* r - 2*range). Otherwise, iterate again. Since 3*range = 11..._2, each
* iteration succeeds with probability >= .75. */
if (BN_cmp(r, range) >= 0) {
if (!BN_sub(r, r, range)) {
return 0;
}
if (BN_cmp(r, range) >= 0) {
if (!BN_sub(r, r, range)) {
return 0;
}
}
}
if (!--count) {
OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_ITERATIONS);
return 0;
}
} while (BN_cmp(r, range) >= 0);
} else {
do {
/* range = 11..._2 or range = 101..._2 */
if (!BN_rand(r, n, -1, 0)) {
return 0;
}
if (!--count) {
OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_ITERATIONS);
return 0;
}
} while (BN_cmp(r, range) >= 0);
}
return 1;
}
int BN_pseudo_rand_range(BIGNUM *r, const BIGNUM *range) {
return BN_rand_range(r, range);
}
int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range, const BIGNUM *priv,
const uint8_t *message, size_t message_len,
BN_CTX *ctx) {
SHA512_CTX sha;
/* We use 512 bits of random data per iteration to
* ensure that we have at least |range| bits of randomness. */
uint8_t random_bytes[64];
uint8_t digest[SHA512_DIGEST_LENGTH];
size_t done, todo, attempt;
const unsigned num_k_bytes = BN_num_bytes(range);
const unsigned bits_to_mask = (8 - (BN_num_bits(range) % 8)) % 8;
uint8_t private_bytes[96];
uint8_t *k_bytes = NULL;
int ret = 0;
if (out == NULL) {
return 0;
}
if (BN_is_zero(range)) {
OPENSSL_PUT_ERROR(BN, BN_R_DIV_BY_ZERO);
goto err;
}
k_bytes = OPENSSL_malloc(num_k_bytes);
if (!k_bytes) {
OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
goto err;
}
/* We copy |priv| into a local buffer to avoid furthur exposing its
* length. */
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);
goto err;
}
memcpy(private_bytes, priv->d, todo);
memset(private_bytes + todo, 0, sizeof(private_bytes) - todo);
for (attempt = 0;; attempt++) {
for (done = 0; done < num_k_bytes;) {
if (!RAND_bytes(random_bytes, sizeof(random_bytes))) {
goto err;
}
SHA512_Init(&sha);
SHA512_Update(&sha, &attempt, sizeof(attempt));
SHA512_Update(&sha, &done, sizeof(done));
SHA512_Update(&sha, private_bytes, sizeof(private_bytes));
SHA512_Update(&sha, message, message_len);
SHA512_Update(&sha, random_bytes, sizeof(random_bytes));
SHA512_Final(digest, &sha);
todo = num_k_bytes - done;
if (todo > SHA512_DIGEST_LENGTH) {
todo = SHA512_DIGEST_LENGTH;
}
memcpy(k_bytes + done, digest, todo);
done += todo;
}
k_bytes[0] &= 0xff >> bits_to_mask;
if (!BN_bin2bn(k_bytes, num_k_bytes, out)) {
goto err;
}
if (BN_cmp(out, range) < 0) {
break;
}
}
ret = 1;
err:
OPENSSL_free(k_bytes);
return ret;
}

Some files were not shown because too many files have changed in this diff Show More