Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1b5bcb59f4 | |||
| b69307a1c4 |
@@ -2,6 +2,3 @@ BasedOnStyle: Google
|
||||
MaxEmptyLinesToKeep: 3
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Right
|
||||
|
||||
|
||||
@@ -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
|
||||
compatibilty 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.
|
||||
+9
-25
@@ -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. If using GNU binutils, you must have 2.22 or later.
|
||||
|
||||
## Building
|
||||
|
||||
Using Ninja (note the 'N' is capitalized in the cmake invocation):
|
||||
@@ -83,18 +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).
|
||||
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
|
||||
|
||||
@@ -134,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
|
||||
|
||||
+38
-58
@@ -15,12 +15,8 @@ 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)
|
||||
@@ -31,25 +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")
|
||||
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")
|
||||
# Clang's integerated assembler does not support debug symbols.
|
||||
if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -Wa,-g")
|
||||
endif()
|
||||
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
|
||||
"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',
|
||||
@@ -65,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
|
||||
@@ -73,7 +58,6 @@ 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
|
||||
@@ -84,23 +68,31 @@ elseif(MSVC)
|
||||
"C4800" # 'int' : forcing value to bool 'true' or 'false'
|
||||
# (performance warning)
|
||||
"C4820" # 'bytes' bytes padding added after construct 'member_name'
|
||||
"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
|
||||
@@ -109,32 +101,18 @@ 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")
|
||||
|
||||
if(NOT NO_FUZZER_MODE)
|
||||
add_definitions(-DBORINGSSL_UNSAFE_FUZZER_MODE)
|
||||
set(RUNNER_ARGS ${RUNNER_ARGS} "-fuzzer" "-shim-config" "fuzzer_mode.json")
|
||||
endif()
|
||||
add_definitions(-DBORINGSSL_UNSAFE_FUZZER_MODE)
|
||||
set(RUNNER_ARGS "-fuzzer")
|
||||
|
||||
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")
|
||||
@@ -168,12 +146,14 @@ elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i386")
|
||||
set(ARCH "x86")
|
||||
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i686")
|
||||
set(ARCH "x86")
|
||||
elseif (${CMAKE_SYSTEM_PROCESSOR} MATCHES "^arm*")
|
||||
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 "mips")
|
||||
# Just to avoid the “unknown processor” error.
|
||||
else()
|
||||
message(FATAL_ERROR "Unknown processor:" ${CMAKE_SYSTEM_PROCESSOR})
|
||||
endif()
|
||||
@@ -220,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})
|
||||
|
||||
+2
-34
@@ -28,20 +28,7 @@ From the `build/` directory, you can then run the fuzzers. For example:
|
||||
|
||||
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` | 3072 |
|
||||
| `client` | 20000 |
|
||||
| `pkcs8` | 2048 |
|
||||
| `privkey` | 2048 |
|
||||
| `server` | 4096 |
|
||||
| `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.)
|
||||
|
||||
@@ -53,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_fuzzer_corpora.sh /path/to/fuzzer/mode/build /path/to/non/fuzzer/mode/build
|
||||
```
|
||||
|
||||
@@ -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
-62
@@ -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,60 +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_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.)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -159,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
@@ -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
|
||||
|
||||
+4
-10
@@ -17,8 +17,6 @@ elseif(UNIX)
|
||||
elseif (${ARCH} STREQUAL "x86")
|
||||
set(PERLASM_FLAGS "-fPIC -DOPENSSL_IA32_SSE2")
|
||||
set(PERLASM_STYLE elf)
|
||||
elseif (${ARCH} STREQUAL "ppc64le")
|
||||
set(PERLASM_STYLE ppc64le)
|
||||
else()
|
||||
set(PERLASM_STYLE elf)
|
||||
endif()
|
||||
@@ -43,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
|
||||
@@ -64,7 +61,6 @@ 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)
|
||||
@@ -78,7 +74,6 @@ add_subdirectory(conf)
|
||||
add_subdirectory(chacha)
|
||||
add_subdirectory(poly1305)
|
||||
add_subdirectory(curve25519)
|
||||
add_subdirectory(newhope)
|
||||
|
||||
# Level 1, depends only on 0.*
|
||||
add_subdirectory(digest)
|
||||
@@ -120,8 +115,9 @@ add_library(
|
||||
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
|
||||
@@ -137,7 +133,6 @@ add_library(
|
||||
$<TARGET_OBJECTS:err>
|
||||
$<TARGET_OBJECTS:base64>
|
||||
$<TARGET_OBJECTS:bytestring>
|
||||
$<TARGET_OBJECTS:pool>
|
||||
$<TARGET_OBJECTS:sha>
|
||||
$<TARGET_OBJECTS:md4>
|
||||
$<TARGET_OBJECTS:md5>
|
||||
@@ -171,8 +166,7 @@ add_library(
|
||||
$<TARGET_OBJECTS:pem>
|
||||
$<TARGET_OBJECTS:x509>
|
||||
$<TARGET_OBJECTS:x509v3>
|
||||
$<TARGET_OBJECTS:pkcs8_lib>
|
||||
$<TARGET_OBJECTS:newhope>
|
||||
$<TARGET_OBJECTS:pkcs8>
|
||||
)
|
||||
|
||||
if(NOT MSVC AND NOT ANDROID)
|
||||
|
||||
@@ -39,21 +39,12 @@ if (${ARCH} STREQUAL "aarch64")
|
||||
)
|
||||
endif()
|
||||
|
||||
if (${ARCH} STREQUAL "ppc64le")
|
||||
set(
|
||||
AES_ARCH_SOURCES
|
||||
|
||||
aesp8-ppc.${ASM_EXT}
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(
|
||||
aes
|
||||
|
||||
OBJECT
|
||||
|
||||
aes.c
|
||||
key_wrap.c
|
||||
mode_wrappers.c
|
||||
|
||||
${AES_ARCH_SOURCES}
|
||||
@@ -69,7 +60,6 @@ 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)
|
||||
perlasm(aesp8-ppc.${ASM_EXT} asm/aesp8-ppc.pl)
|
||||
|
||||
add_executable(
|
||||
aes_test
|
||||
|
||||
+12
-12
@@ -1066,12 +1066,12 @@ static int hwaes_capable(void) {
|
||||
return CRYPTO_is_ARMv8_AES_capable();
|
||||
}
|
||||
|
||||
int aes_hw_set_encrypt_key(const uint8_t *user_key, const int bits,
|
||||
int aes_v8_set_encrypt_key(const uint8_t *user_key, const int bits,
|
||||
AES_KEY *key);
|
||||
int aes_hw_set_decrypt_key(const uint8_t *user_key, const int bits,
|
||||
int aes_v8_set_decrypt_key(const uint8_t *user_key, const int bits,
|
||||
AES_KEY *key);
|
||||
void aes_hw_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key);
|
||||
void aes_hw_decrypt(const uint8_t *in, uint8_t *out, const 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
|
||||
|
||||
@@ -1079,19 +1079,19 @@ static int hwaes_capable(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aes_hw_set_encrypt_key(const uint8_t *user_key, int bits, AES_KEY *key) {
|
||||
static int aes_v8_set_encrypt_key(const uint8_t *user_key, int bits, AES_KEY *key) {
|
||||
abort();
|
||||
}
|
||||
|
||||
static int aes_hw_set_decrypt_key(const uint8_t *user_key, int bits, AES_KEY *key) {
|
||||
static int aes_v8_set_decrypt_key(const uint8_t *user_key, int bits, AES_KEY *key) {
|
||||
abort();
|
||||
}
|
||||
|
||||
static void aes_hw_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
|
||||
static void aes_v8_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
|
||||
abort();
|
||||
}
|
||||
|
||||
static void aes_hw_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
|
||||
static void aes_v8_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
|
||||
abort();
|
||||
}
|
||||
|
||||
@@ -1106,7 +1106,7 @@ static void aes_hw_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);
|
||||
}
|
||||
@@ -1115,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);
|
||||
}
|
||||
@@ -1124,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);
|
||||
}
|
||||
@@ -1133,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);
|
||||
}
|
||||
|
||||
+48
-128
@@ -15,168 +15,88 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
#include "../test/file_test.h"
|
||||
|
||||
|
||||
static bool TestRaw(FileTest *t) {
|
||||
std::vector<uint8_t> key, plaintext, ciphertext;
|
||||
if (!t->GetBytes(&key, "Key") ||
|
||||
!t->GetBytes(&plaintext, "Plaintext") ||
|
||||
!t->GetBytes(&ciphertext, "Ciphertext")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (plaintext.size() != AES_BLOCK_SIZE ||
|
||||
ciphertext.size() != AES_BLOCK_SIZE) {
|
||||
t->PrintLine("Plaintext or Ciphertext not a block size.");
|
||||
return false;
|
||||
}
|
||||
|
||||
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.data(), 8 * key.size(), &aes_key) != 0) {
|
||||
t->PrintLine("AES_set_encrypt_key failed.");
|
||||
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.data(), block, &aes_key);
|
||||
if (!t->ExpectBytesEqual(block, AES_BLOCK_SIZE, ciphertext.data(),
|
||||
ciphertext.size())) {
|
||||
t->PrintLine("AES_encrypt gave the wrong output.");
|
||||
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.data(), AES_BLOCK_SIZE);
|
||||
memcpy(block, plaintext, AES_BLOCK_SIZE);
|
||||
AES_encrypt(block, block, &aes_key);
|
||||
if (!t->ExpectBytesEqual(block, AES_BLOCK_SIZE, ciphertext.data(),
|
||||
ciphertext.size())) {
|
||||
t->PrintLine("In-place AES_encrypt gave the wrong output.");
|
||||
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.data(), 8 * key.size(), &aes_key) != 0) {
|
||||
t->PrintLine("AES_set_decrypt_key failed.");
|
||||
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.data(), block, &aes_key);
|
||||
if (!t->ExpectBytesEqual(block, AES_BLOCK_SIZE, plaintext.data(),
|
||||
plaintext.size())) {
|
||||
t->PrintLine("AES_decrypt gave the wrong output.");
|
||||
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.data(), AES_BLOCK_SIZE);
|
||||
memcpy(block, ciphertext, AES_BLOCK_SIZE);
|
||||
AES_decrypt(block, block, &aes_key);
|
||||
if (!t->ExpectBytesEqual(block, AES_BLOCK_SIZE, plaintext.data(),
|
||||
plaintext.size())) {
|
||||
t->PrintLine("In-place AES_decrypt gave the wrong output.");
|
||||
if (memcmp(block, plaintext, AES_BLOCK_SIZE) != 0) {
|
||||
fprintf(stderr, "AES_decrypt gave the wrong output\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool TestKeyWrap(FileTest *t) {
|
||||
// All test vectors use the default IV, so test both with implicit and
|
||||
// explicit IV.
|
||||
//
|
||||
// TODO(davidben): Find test vectors that use a different IV.
|
||||
static const uint8_t kDefaultIV[] = {
|
||||
0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
|
||||
};
|
||||
|
||||
std::vector<uint8_t> key, plaintext, ciphertext;
|
||||
if (!t->GetBytes(&key, "Key") ||
|
||||
!t->GetBytes(&plaintext, "Plaintext") ||
|
||||
!t->GetBytes(&ciphertext, "Ciphertext")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (plaintext.size() + 8 != ciphertext.size()) {
|
||||
t->PrintLine("Invalid Plaintext and Ciphertext lengths.");
|
||||
return false;
|
||||
}
|
||||
|
||||
AES_KEY aes_key;
|
||||
if (AES_set_encrypt_key(key.data(), 8 * key.size(), &aes_key) != 0) {
|
||||
t->PrintLine("AES_set_encrypt_key failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<uint8_t[]> buf(new uint8_t[ciphertext.size()]);
|
||||
if (AES_wrap_key(&aes_key, nullptr /* iv */, buf.get(), plaintext.data(),
|
||||
plaintext.size()) != static_cast<int>(ciphertext.size()) ||
|
||||
!t->ExpectBytesEqual(buf.get(), ciphertext.size(), ciphertext.data(),
|
||||
ciphertext.size())) {
|
||||
t->PrintLine("AES_wrap_key with implicit IV failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(buf.get(), 0, ciphertext.size());
|
||||
if (AES_wrap_key(&aes_key, kDefaultIV, buf.get(), plaintext.data(),
|
||||
plaintext.size()) != static_cast<int>(ciphertext.size()) ||
|
||||
!t->ExpectBytesEqual(buf.get(), ciphertext.size(), ciphertext.data(),
|
||||
ciphertext.size())) {
|
||||
t->PrintLine("AES_wrap_key with explicit IV failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (AES_set_decrypt_key(key.data(), 8 * key.size(), &aes_key) != 0) {
|
||||
t->PrintLine("AES_set_decrypt_key failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
buf.reset(new uint8_t[plaintext.size()]);
|
||||
if (AES_unwrap_key(&aes_key, nullptr /* iv */, buf.get(), ciphertext.data(),
|
||||
ciphertext.size()) != static_cast<int>(plaintext.size()) ||
|
||||
!t->ExpectBytesEqual(buf.get(), plaintext.size(), plaintext.data(),
|
||||
plaintext.size())) {
|
||||
t->PrintLine("AES_unwrap_key with implicit IV failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(buf.get(), 0, plaintext.size());
|
||||
if (AES_unwrap_key(&aes_key, kDefaultIV, buf.get(), ciphertext.data(),
|
||||
ciphertext.size()) != static_cast<int>(plaintext.size()) ||
|
||||
!t->ExpectBytesEqual(buf.get(), plaintext.size(), plaintext.data(),
|
||||
plaintext.size())) {
|
||||
t->PrintLine("AES_unwrap_key with explicit IV failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool TestAES(FileTest *t, void *arg) {
|
||||
if (t->GetParameter() == "Raw") {
|
||||
return TestRaw(t);
|
||||
}
|
||||
if (t->GetParameter() == "KeyWrap") {
|
||||
return TestKeyWrap(t);
|
||||
}
|
||||
|
||||
t->PrintLine("Unknown mode '%s'.", t->GetParameter().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int main() {
|
||||
CRYPTO_library_init();
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "%s <test file.txt>\n", argv[0]);
|
||||
return 1;
|
||||
// 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;
|
||||
}
|
||||
|
||||
return FileTestMain(TestAES, nullptr, argv[1]);
|
||||
printf("PASS\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
# Test vectors from FIPS-197, Appendix C.
|
||||
|
||||
Mode = Raw
|
||||
Key = 000102030405060708090a0b0c0d0e0f
|
||||
Plaintext = 00112233445566778899aabbccddeeff
|
||||
Ciphertext = 69c4e0d86a7b0430d8cdb78070b4c55a
|
||||
|
||||
Mode = Raw
|
||||
Key = 000102030405060708090a0b0c0d0e0f1011121314151617
|
||||
Plaintext = 00112233445566778899aabbccddeeff
|
||||
Ciphertext = dda97ca4864cdfe06eaf70a0ec0d7191
|
||||
|
||||
Mode = Raw
|
||||
Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
|
||||
Plaintext = 00112233445566778899aabbccddeeff
|
||||
Ciphertext = 8ea2b7ca516745bfeafc49904b496089
|
||||
|
||||
|
||||
# Test vectors from
|
||||
# http://csrc.nist.gov/groups/ST/toolkit/documents/kms/key-wrap.pdf
|
||||
|
||||
Mode = KeyWrap
|
||||
Key = 000102030405060708090a0b0c0d0e0f
|
||||
Plaintext = 00112233445566778899aabbccddeeff
|
||||
Ciphertext = 1fa68b0a8112b447aef34bd8fb5a7b829d3e862371d2cfe5
|
||||
|
||||
Mode = KeyWrap
|
||||
Key = 000102030405060708090a0b0c0d0e0f1011121314151617
|
||||
Plaintext = 00112233445566778899aabbccddeeff
|
||||
Ciphertext = 96778b25ae6ca435f92b5b97c050aed2468ab8a17ad84e5d
|
||||
|
||||
Mode = KeyWrap
|
||||
Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
|
||||
Plaintext = 00112233445566778899aabbccddeeff
|
||||
Ciphertext = 64e8c3f9ce0f5ba263e9777905818a2a93c8191e7d6e8ae7
|
||||
|
||||
Mode = KeyWrap
|
||||
Key = 000102030405060708090a0b0c0d0e0f1011121314151617
|
||||
Plaintext = 00112233445566778899aabbccddeeff0001020304050607
|
||||
Ciphertext = 031d33264e15d33268f24ec260743edce1c6c7ddee725a936ba814915c6762d2
|
||||
|
||||
Mode = KeyWrap
|
||||
Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
|
||||
Plaintext = 00112233445566778899aabbccddeeff0001020304050607
|
||||
Ciphertext = a8f9bc1612c68b3ff6e6f4fbe30e71e4769c8b80a32cb8958cd5d17d6b254da1
|
||||
|
||||
Mode = KeyWrap
|
||||
Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
|
||||
Plaintext = 00112233445566778899aabbccddeeff000102030405060708090a0b0c0d0e0f
|
||||
Ciphertext = 28c9f404c4b810f4cbccb35cfb87f8263f5786e2d80ed326cbc7f0e71a99f43bfb988b9b7a02dd21
|
||||
@@ -191,10 +191,6 @@ $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
push(@INC,"${dir}","${dir}../../perlasm");
|
||||
require "x86asm.pl";
|
||||
|
||||
$output = pop;
|
||||
open OUT,">$output";
|
||||
*STDOUT=*OUT;
|
||||
|
||||
&asm_init($ARGV[0],"aes-586.pl",$x86only = $ARGV[$#ARGV] eq "386");
|
||||
&static_label("AES_Te");
|
||||
&static_label("AES_Td");
|
||||
@@ -2989,5 +2985,3 @@ sub deckey()
|
||||
&asciz("AES for x86, CRYPTOGAMS by <appro\@openssl.org>");
|
||||
|
||||
&asm_finish();
|
||||
|
||||
close STDOUT;
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
# 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;
|
||||
|
||||
@@ -37,7 +37,7 @@ $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
( $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
|
||||
|
||||
@@ -63,10 +63,6 @@ $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
push(@INC,"${dir}","${dir}../../perlasm");
|
||||
require "x86asm.pl";
|
||||
|
||||
$output = pop;
|
||||
open OUT,">$output";
|
||||
*STDOUT=*OUT;
|
||||
|
||||
&asm_init($ARGV[0],$0);
|
||||
|
||||
&external_label("OPENSSL_ia32cap_P");
|
||||
@@ -2527,5 +2523,3 @@ if ($PREFIX eq "aesni") {
|
||||
&asciz("AES for Intel AES-NI, CRYPTOGAMS by <appro\@openssl.org>");
|
||||
|
||||
&asm_finish();
|
||||
|
||||
close STDOUT;
|
||||
|
||||
@@ -187,7 +187,7 @@ $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
( $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;
|
||||
|
||||
$movkey = $PREFIX eq "aesni" ? "movups" : "movups";
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -42,7 +42,7 @@ 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
|
||||
___
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
# <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;
|
||||
@@ -1831,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
|
||||
@@ -1866,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
|
||||
@@ -1894,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
|
||||
@@ -1919,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
|
||||
@@ -1943,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
|
||||
@@ -1965,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
|
||||
@@ -2277,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
|
||||
@@ -2305,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
|
||||
@@ -2330,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
|
||||
@@ -2354,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
|
||||
@@ -2376,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
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
( $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");
|
||||
|
||||
@@ -51,10 +51,6 @@ $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
push(@INC,"${dir}","${dir}../../perlasm");
|
||||
require "x86asm.pl";
|
||||
|
||||
$output = pop;
|
||||
open OUT,">$output";
|
||||
*STDOUT=*OUT;
|
||||
|
||||
&asm_init($ARGV[0],"vpaes-x86.pl",$x86only = $ARGV[$#ARGV] eq "386");
|
||||
|
||||
$PREFIX="vpaes";
|
||||
@@ -905,5 +901,3 @@ $k_dsbo=0x2c0; # decryption sbox final output
|
||||
&function_end("${PREFIX}_cbc_encrypt");
|
||||
|
||||
&asm_finish();
|
||||
|
||||
close STDOUT;
|
||||
|
||||
@@ -57,7 +57,7 @@ $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
( $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";
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
/* ====================================================================
|
||||
* Copyright (c) 2001-2011 The OpenSSL Project. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this
|
||||
* software must display the following acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
||||
*
|
||||
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* prior written permission. For written permission, please contact
|
||||
* openssl-core@openssl.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "OpenSSL"
|
||||
* nor may "OpenSSL" appear in their names without prior written
|
||||
* permission of the OpenSSL Project.
|
||||
*
|
||||
* 6. Redistributions of any form whatsoever must retain the following
|
||||
* acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
||||
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ==================================================================== */
|
||||
|
||||
#include <openssl/aes.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/mem.h>
|
||||
|
||||
|
||||
/* kDefaultIV is the default IV value given in RFC 3394, 2.2.3.1. */
|
||||
static const uint8_t kDefaultIV[] = {
|
||||
0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
|
||||
};
|
||||
|
||||
static const unsigned kBound = 6;
|
||||
|
||||
int AES_wrap_key(const AES_KEY *key, const uint8_t *iv, uint8_t *out,
|
||||
const uint8_t *in, size_t in_len) {
|
||||
/* See RFC 3394, section 2.2.1. */
|
||||
|
||||
if (in_len > INT_MAX - 8 || in_len < 8 || in_len % 8 != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (iv == NULL) {
|
||||
iv = kDefaultIV;
|
||||
}
|
||||
|
||||
memmove(out + 8, in, in_len);
|
||||
uint8_t A[AES_BLOCK_SIZE];
|
||||
memcpy(A, iv, 8);
|
||||
|
||||
size_t n = in_len / 8;
|
||||
|
||||
for (unsigned j = 0; j < kBound; j++) {
|
||||
for (size_t i = 1; i <= n; i++) {
|
||||
memcpy(A + 8, out + 8 * i, 8);
|
||||
AES_encrypt(A, A, key);
|
||||
|
||||
uint32_t t = (uint32_t)(n * j + i);
|
||||
A[7] ^= t & 0xff;
|
||||
A[6] ^= (t >> 8) & 0xff;
|
||||
A[5] ^= (t >> 16) & 0xff;
|
||||
A[4] ^= (t >> 24) & 0xff;
|
||||
memcpy(out + 8 * i, A + 8, 8);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(out, A, 8);
|
||||
return (int)in_len + 8;
|
||||
}
|
||||
|
||||
int AES_unwrap_key(const AES_KEY *key, const uint8_t *iv, uint8_t *out,
|
||||
const uint8_t *in, size_t in_len) {
|
||||
/* See RFC 3394, section 2.2.2. */
|
||||
|
||||
if (in_len > INT_MAX || in_len < 16 || in_len % 8 != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (iv == NULL) {
|
||||
iv = kDefaultIV;
|
||||
}
|
||||
|
||||
uint8_t A[AES_BLOCK_SIZE];
|
||||
memcpy(A, in, 8);
|
||||
memmove(out, in + 8, in_len - 8);
|
||||
|
||||
size_t n = (in_len / 8) - 1;
|
||||
|
||||
for (unsigned j = kBound - 1; j < kBound; j--) {
|
||||
for (size_t i = n; i > 0; i--) {
|
||||
uint32_t t = (uint32_t)(n * j + i);
|
||||
A[7] ^= t & 0xff;
|
||||
A[6] ^= (t >> 8) & 0xff;
|
||||
A[5] ^= (t >> 16) & 0xff;
|
||||
A[4] ^= (t >> 24) & 0xff;
|
||||
memcpy(A + 8, out + 8 * (i - 1), 8);
|
||||
AES_decrypt(A, A, key);
|
||||
memcpy(out + 8 * (i - 1), A + 8, 8);
|
||||
}
|
||||
}
|
||||
|
||||
if (CRYPTO_memcmp(A, iv, 8) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int)in_len - 8;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,6 +36,7 @@ add_library(
|
||||
tasn_enc.c
|
||||
tasn_fre.c
|
||||
tasn_new.c
|
||||
tasn_prn.c
|
||||
tasn_typ.c
|
||||
tasn_utl.c
|
||||
x_bignum.c
|
||||
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
+14
-20
@@ -220,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);
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ 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;
|
||||
@@ -172,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 (;;) {
|
||||
|
||||
@@ -247,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;
|
||||
|
||||
@@ -77,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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -65,6 +65,37 @@
|
||||
|
||||
#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)
|
||||
{
|
||||
|
||||
+79
-53
@@ -64,44 +64,44 @@
|
||||
#include <openssl/mem.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)
|
||||
@@ -173,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))
|
||||
@@ -201,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;
|
||||
@@ -217,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;
|
||||
@@ -230,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);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -298,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)
|
||||
@@ -349,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)
|
||||
@@ -386,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);
|
||||
|
||||
@@ -61,3 +61,13 @@
|
||||
|
||||
int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d);
|
||||
int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d);
|
||||
|
||||
/* ASN1 print context structure */
|
||||
|
||||
struct asn1_pctx_st {
|
||||
unsigned long flags;
|
||||
unsigned long nm_flags;
|
||||
unsigned long cert_flags;
|
||||
unsigned long oid_flags;
|
||||
unsigned long str_flags;
|
||||
} /* ASN1_PCTX */ ;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "../test/scoped_types.h"
|
||||
|
||||
|
||||
// kTag128 is an ASN.1 structure with a universal tag with number 128.
|
||||
static const uint8_t kTag128[] = {
|
||||
@@ -40,7 +42,7 @@ static const uint8_t kTagOverflow[] = {
|
||||
|
||||
static bool TestLargeTags() {
|
||||
const uint8_t *p = kTag258;
|
||||
bssl::UniquePtr<ASN1_TYPE> obj(d2i_ASN1_TYPE(NULL, &p, sizeof(kTag258)));
|
||||
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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -399,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);
|
||||
}
|
||||
@@ -412,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? */
|
||||
@@ -477,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;
|
||||
@@ -896,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;
|
||||
|
||||
+11
-17
@@ -56,7 +56,6 @@
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/asn1t.h>
|
||||
@@ -214,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);
|
||||
@@ -340,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... */
|
||||
@@ -386,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);
|
||||
@@ -617,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
|
||||
*/
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
+8
-22
@@ -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;
|
||||
}
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+305
-269
@@ -60,123 +60,118 @@
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/type_check.h>
|
||||
|
||||
|
||||
/* Encoding. */
|
||||
|
||||
static const unsigned char data_bin2ascii[65] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
#define conv_bin2ascii(a) (data_bin2ascii[(a) & 0x3f])
|
||||
|
||||
OPENSSL_COMPILE_ASSERT(sizeof(((EVP_ENCODE_CTX *)(NULL))->data) % 3 == 0,
|
||||
data_length_must_be_multiple_of_base64_chunk_size);
|
||||
/* 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)
|
||||
|
||||
int EVP_EncodedLength(size_t *out_len, size_t len) {
|
||||
if (len + 2 < len) {
|
||||
return 0;
|
||||
/* 0xF0 is a EOLN
|
||||
* 0xF1 is ignore but next needs to be 0xF0 (for \r\n processing).
|
||||
* 0xF2 is EOF
|
||||
* 0xE0 is ignore at start of line.
|
||||
* 0xFF is error */
|
||||
|
||||
#define B64_EOLN 0xF0
|
||||
#define B64_CR 0xF1
|
||||
#define B64_EOF 0xF2
|
||||
#define B64_WS 0xE0
|
||||
#define B64_ERROR 0xFF
|
||||
#define B64_NOT_BASE64(a) (((a) | 0x13) == 0xF3)
|
||||
|
||||
static const 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,
|
||||
};
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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;
|
||||
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) {
|
||||
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) {
|
||||
@@ -211,223 +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) {
|
||||
memset(ctx, 0, sizeof(EVP_ENCODE_CTX));
|
||||
}
|
||||
|
||||
/* kBase64ASCIIToBinData maps characters (c < 128) to their base64 value, or
|
||||
* else 0xff if they are invalid. As a special case, the padding character
|
||||
* ('=') is mapped to zero. */
|
||||
static const uint8_t kBase64ASCIIToBinData[128] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff,
|
||||
0xff, 0xff, 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, 0xff, 0xff, 0x3f,
|
||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
||||
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
|
||||
0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
|
||||
0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
|
||||
0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
};
|
||||
|
||||
static uint8_t base64_ascii_to_bin(uint8_t a) {
|
||||
if (a >= 128) {
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
return kBase64ASCIIToBinData[a];
|
||||
}
|
||||
|
||||
/* 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 (base64_ascii_to_bin(c) == 0xff || 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;
|
||||
}
|
||||
|
||||
@@ -438,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;
|
||||
}
|
||||
|
||||
+45
-312
@@ -15,204 +15,76 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/base64.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "../internal.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" },
|
||||
};
|
||||
|
||||
static const size_t kNumTests = OPENSSL_ARRAY_SIZE(kTestVectors);
|
||||
static const size_t kNumTests = sizeof(kTestVectors) / sizeof(kTestVectors[0]);
|
||||
|
||||
// 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]);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool TestEncodeBlock() {
|
||||
for (unsigned i = 0; i < kNumTests; i++) {
|
||||
static bool TestEncode() {
|
||||
for (size_t i = 0; i < kNumTests; i++) {
|
||||
const TestVector *t = &kTestVectors[i];
|
||||
if (t->relation != canonical) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const size_t decoded_len = strlen(t->decoded);
|
||||
size_t max_encoded_len;
|
||||
if (!EVP_EncodedLength(&max_encoded_len, decoded_len)) {
|
||||
fprintf(stderr, "#%u: EVP_EncodedLength failed\n", i);
|
||||
return false;
|
||||
}
|
||||
|
||||
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));
|
||||
if (len != encoded.size() ||
|
||||
memcmp(out, encoded.data(), len) != 0) {
|
||||
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, encoded.c_str());
|
||||
t->decoded, (int)len, (const char*)out, t->encoded);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool TestDecodeBase64() {
|
||||
static bool TestDecode() {
|
||||
uint8_t out[6];
|
||||
size_t len;
|
||||
|
||||
for (unsigned i = 0; i < kNumTests; i++) {
|
||||
for (size_t i = 0; i < kNumTests; i++) {
|
||||
// Test the normal API.
|
||||
const TestVector *t = &kTestVectors[i];
|
||||
|
||||
if (t->relation == valid) {
|
||||
// The non-canonical encodings will generally have odd whitespace etc
|
||||
// that |EVP_DecodeBase64| will reject.
|
||||
continue;
|
||||
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;
|
||||
}
|
||||
|
||||
const std::string encoded(RemoveNewlines(t->encoded));
|
||||
std::vector<uint8_t> out_vec(encoded.size());
|
||||
uint8_t *out = out_vec.data();
|
||||
|
||||
int ok = EVP_DecodeBase64(out, &len, out_vec.size(),
|
||||
(const uint8_t *)encoded.data(), encoded.size());
|
||||
|
||||
if (t->relation == invalid) {
|
||||
if (ok) {
|
||||
fprintf(stderr, "decode(\"%s\") didn't fail but should have\n",
|
||||
encoded.c_str());
|
||||
return false;
|
||||
}
|
||||
} else if (t->relation == canonical) {
|
||||
if (!ok) {
|
||||
fprintf(stderr, "decode(\"%s\") failed\n", encoded.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (len != strlen(t->decoded) ||
|
||||
memcmp(out, t->decoded, len) != 0) {
|
||||
fprintf(stderr, "decode(\"%s\") = \"%.*s\", want \"%s\"\n",
|
||||
encoded.c_str(), (int)len, (const char*)out, t->decoded);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool TestDecodeBlock() {
|
||||
for (unsigned i = 0; i < kNumTests; i++) {
|
||||
const TestVector *t = &kTestVectors[i];
|
||||
if (t->relation != canonical) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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());
|
||||
int ret = EVP_DecodeBlock(out, (const uint8_t*)t->encoded,
|
||||
strlen(t->encoded));
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "EVP_DecodeBlock(\"%s\") failed\n", t->encoded);
|
||||
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;
|
||||
}
|
||||
size_t expected_len = strlen(t->decoded);
|
||||
if (expected_len % 3 != 0) {
|
||||
ret -= 3 - (expected_len % 3);
|
||||
}
|
||||
@@ -224,155 +96,19 @@ static bool TestDecodeBlock() {
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool TestEncodeDecode() {
|
||||
for (unsigned test_num = 0; test_num < kNumTests; test_num++) {
|
||||
const TestVector *t = &kTestVectors[test_num];
|
||||
|
||||
EVP_ENCODE_CTX ctx;
|
||||
const size_t decoded_len = strlen(t->decoded);
|
||||
|
||||
if (t->relation == canonical) {
|
||||
size_t max_encoded_len;
|
||||
if (!EVP_EncodedLength(&max_encoded_len, decoded_len)) {
|
||||
fprintf(stderr, "#%u: EVP_EncodedLength failed\n", test_num);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
if (total != strlen(t->encoded) || memcmp(out, t->encoded, total) != 0) {
|
||||
fprintf(stderr, "#%u: EVP_EncodeUpdate produced different output: '%s' (%u)\n",
|
||||
test_num, out, static_cast<unsigned>(total));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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:
|
||||
if (ret == -1) {
|
||||
fprintf(stderr, "#%u: EVP_DecodeUpdate failed\n", test_num);
|
||||
return false;
|
||||
}
|
||||
if (total != decoded_len || memcmp(out, t->decoded, decoded_len)) {
|
||||
fprintf(stderr, "#%u: EVP_DecodeUpdate produced incorrect output\n",
|
||||
test_num);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case invalid:
|
||||
if (ret != -1) {
|
||||
fprintf(stderr, "#%u: EVP_DecodeUpdate was successful but shouldn't have been\n", test_num);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
static bool TestDecodeUpdateStreaming() {
|
||||
for (unsigned test_num = 0; test_num < kNumTests; test_num++) {
|
||||
const TestVector *t = &kTestVectors[test_num];
|
||||
if (t->relation == invalid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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++) {
|
||||
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:
|
||||
fprintf(stderr, "#%u: EVP_DecodeUpdate returned error\n", test_num);
|
||||
return 0;
|
||||
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;
|
||||
}
|
||||
|
||||
fprintf(stderr,
|
||||
"#%u: EVP_DecodeUpdate returned zero before end of "
|
||||
"encoded data\n",
|
||||
test_num);
|
||||
return 0;
|
||||
default:
|
||||
out_len += bytes_written;
|
||||
}
|
||||
}
|
||||
|
||||
int bytes_written;
|
||||
int ret = EVP_DecodeFinal(&ctx, out.data() + out_len, &bytes_written);
|
||||
if (ret == -1) {
|
||||
fprintf(stderr, "#%u: EVP_DecodeFinal returned error\n", test_num);
|
||||
return 0;
|
||||
}
|
||||
out_len += bytes_written;
|
||||
|
||||
if (out_len != strlen(t->decoded) ||
|
||||
memcmp(out.data(), t->decoded, out_len) != 0) {
|
||||
fprintf(stderr, "#%u: incorrect output\n", test_num);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
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;
|
||||
@@ -381,11 +117,8 @@ static bool TestDecodeUpdateStreaming() {
|
||||
int main(void) {
|
||||
CRYPTO_library_init();
|
||||
|
||||
if (!TestEncodeBlock() ||
|
||||
!TestDecodeBase64() ||
|
||||
!TestDecodeBlock() ||
|
||||
!TestDecodeUpdateStreaming() ||
|
||||
!TestEncodeDecode()) {
|
||||
if (!TestEncode() ||
|
||||
!TestDecode()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
+30
-28
@@ -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;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
+15
-14
@@ -27,10 +27,10 @@
|
||||
#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>
|
||||
@@ -40,7 +40,7 @@ OPENSSL_MSVC_PRAGMA(warning(pop))
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "../internal.h"
|
||||
#include "../test/scoped_types.h"
|
||||
|
||||
|
||||
#if !defined(OPENSSL_WINDOWS)
|
||||
@@ -59,7 +59,7 @@ static void PrintSocketError(const char *func) {
|
||||
|
||||
class ScopedSocket {
|
||||
public:
|
||||
explicit ScopedSocket(int sock) : sock_(sock) {}
|
||||
ScopedSocket(int sock) : sock_(sock) {}
|
||||
~ScopedSocket() {
|
||||
closesocket(sock_);
|
||||
}
|
||||
@@ -103,7 +103,7 @@ static bool TestSocketConnect() {
|
||||
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));
|
||||
ScopedBIO bio(BIO_new_connect(hostname));
|
||||
if (!bio) {
|
||||
fprintf(stderr, "BIO_new_connect failed.\n");
|
||||
return false;
|
||||
@@ -206,8 +206,9 @@ static bool TestZeroCopyBioPairs() {
|
||||
|
||||
// Transfer bytes from bio1_application_send_buffer to
|
||||
// bio2_application_recv_buffer in various ways.
|
||||
for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kLengths); i++) {
|
||||
for (size_t j = 0; j < OPENSSL_ARRAY_SIZE(kPartialLengths); j++) {
|
||||
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;
|
||||
|
||||
@@ -215,8 +216,8 @@ static bool TestZeroCopyBioPairs() {
|
||||
if (!BIO_new_bio_pair(&bio1, kBufferSize, &bio2, kBufferSize)) {
|
||||
return false;
|
||||
}
|
||||
bssl::UniquePtr<BIO> bio1_scoper(bio1);
|
||||
bssl::UniquePtr<BIO> bio2_scoper(bio2);
|
||||
ScopedBIO bio1_scoper(bio1);
|
||||
ScopedBIO bio2_scoper(bio2);
|
||||
|
||||
total_write += BioWriteZeroCopyWrapper(
|
||||
bio1, bio1_application_send_buffer, kLengths[i]);
|
||||
@@ -286,13 +287,13 @@ static bool TestPrintf() {
|
||||
// 256 (the size of the buffer) to ensure edge cases are correct.
|
||||
static const size_t kLengths[] = { 5, 250, 251, 252, 253, 254, 1023 };
|
||||
|
||||
bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
|
||||
ScopedBIO bio(BIO_new(BIO_s_mem()));
|
||||
if (!bio) {
|
||||
fprintf(stderr, "BIO_new failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kLengths); i++) {
|
||||
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");
|
||||
@@ -330,7 +331,7 @@ static bool TestPrintf() {
|
||||
|
||||
static bool ReadASN1(bool should_succeed, const uint8_t *data, size_t data_len,
|
||||
size_t expected_len, size_t max_len) {
|
||||
bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(data, data_len));
|
||||
ScopedBIO bio(BIO_new_mem_buf(data, data_len));
|
||||
|
||||
uint8_t *out;
|
||||
size_t out_len;
|
||||
@@ -338,7 +339,7 @@ static bool ReadASN1(bool should_succeed, const uint8_t *data, size_t data_len,
|
||||
if (!ok) {
|
||||
out = nullptr;
|
||||
}
|
||||
bssl::UniquePtr<uint8_t> out_storage(out);
|
||||
ScopedOpenSSLBytes out_storage(out);
|
||||
|
||||
if (should_succeed != (ok == 1)) {
|
||||
return false;
|
||||
@@ -368,7 +369,7 @@ static bool TestASN1() {
|
||||
static const size_t kLargePayloadLen = 8000;
|
||||
static const uint8_t kLargePrefix[] = {0x30, 0x82, kLargePayloadLen >> 8,
|
||||
kLargePayloadLen & 0xff};
|
||||
bssl::UniquePtr<uint8_t> large(reinterpret_cast<uint8_t *>(
|
||||
ScopedOpenSSLBytes large(reinterpret_cast<uint8_t *>(
|
||||
OPENSSL_malloc(sizeof(kLargePrefix) + kLargePayloadLen)));
|
||||
if (!large) {
|
||||
return false;
|
||||
|
||||
@@ -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>
|
||||
@@ -538,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);
|
||||
}
|
||||
|
||||
+16
-21
@@ -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:
|
||||
|
||||
@@ -86,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;
|
||||
|
||||
@@ -94,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);
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
+3
-11
@@ -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)) {
|
||||
|
||||
@@ -26,10 +26,10 @@
|
||||
#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"
|
||||
|
||||
@@ -57,7 +57,6 @@ add_library(
|
||||
gcd.c
|
||||
kronecker.c
|
||||
montgomery.c
|
||||
montgomery_inv.c
|
||||
mul.c
|
||||
prime.c
|
||||
random.c
|
||||
|
||||
@@ -39,8 +39,8 @@
|
||||
# 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;
|
||||
|
||||
@@ -4,9 +4,6 @@ $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
push(@INC,"${dir}","${dir}../../perlasm");
|
||||
require "x86asm.pl";
|
||||
|
||||
$output = pop;
|
||||
open STDOUT,">$output";
|
||||
|
||||
&asm_init($ARGV[0],$0);
|
||||
|
||||
$sse2=0;
|
||||
@@ -24,8 +21,6 @@ for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); }
|
||||
|
||||
&asm_finish();
|
||||
|
||||
close STDOUT;
|
||||
|
||||
sub bn_mul_add_words
|
||||
{
|
||||
local($name)=@_;
|
||||
@@ -776,3 +771,4 @@ sub bn_sub_part_words
|
||||
|
||||
&function_end($name);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,6 @@ $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
push(@INC,"${dir}","${dir}../../perlasm");
|
||||
require "x86asm.pl";
|
||||
|
||||
$output = pop;
|
||||
open STDOUT,">$output";
|
||||
|
||||
&asm_init($ARGV[0],$0);
|
||||
|
||||
&bn_mul_comba("bn_mul_comba8",8);
|
||||
@@ -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)=@_;
|
||||
|
||||
@@ -87,7 +87,7 @@ die "can't locate x86_64-xlate.pl";
|
||||
$avx = 0;
|
||||
$addx = 0;
|
||||
|
||||
open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
|
||||
open OUT,"| \"$^X\" $xlate $flavour $output";
|
||||
*STDOUT = *OUT;
|
||||
|
||||
if ($avx>1) {{{
|
||||
|
||||
@@ -95,7 +95,7 @@ $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
( $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
|
||||
|
||||
@@ -30,9 +30,6 @@ $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
push(@INC,"${dir}","${dir}../../perlasm");
|
||||
require "x86asm.pl";
|
||||
|
||||
$output = pop;
|
||||
open STDOUT,">$output";
|
||||
|
||||
&asm_init($ARGV[0],$0);
|
||||
|
||||
$sse2=0;
|
||||
@@ -593,5 +590,3 @@ $sbit=$num;
|
||||
&asciz("Montgomery Multiplication for x86, CRYPTOGAMS by <appro\@openssl.org>");
|
||||
|
||||
&asm_finish();
|
||||
|
||||
close STDOUT;
|
||||
|
||||
+10
-11
@@ -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");
|
||||
@@ -257,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) \
|
||||
|
||||
@@ -50,7 +50,7 @@ $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
( $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
|
||||
@@ -1059,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
|
||||
|
||||
@@ -35,7 +35,7 @@ $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
( $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
|
||||
|
||||
@@ -266,28 +266,6 @@ 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) == NULL) {
|
||||
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) == NULL) {
|
||||
return 0;
|
||||
@@ -364,10 +342,6 @@ 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) {
|
||||
|
||||
+1346
-911
File diff suppressed because it is too large
Load Diff
-10754
File diff suppressed because it is too large
Load Diff
@@ -1,262 +0,0 @@
|
||||
// Copyright (c) 2016, Google Inc.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type test struct {
|
||||
LineNumber int
|
||||
Type string
|
||||
Values map[string]*big.Int
|
||||
}
|
||||
|
||||
type testScanner struct {
|
||||
scanner *bufio.Scanner
|
||||
lineNo int
|
||||
err error
|
||||
test test
|
||||
}
|
||||
|
||||
func newTestScanner(r io.Reader) *testScanner {
|
||||
return &testScanner{scanner: bufio.NewScanner(r)}
|
||||
}
|
||||
|
||||
func (s *testScanner) scanLine() bool {
|
||||
if !s.scanner.Scan() {
|
||||
return false
|
||||
}
|
||||
s.lineNo++
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *testScanner) addAttribute(line string) (key string, ok bool) {
|
||||
fields := strings.SplitN(line, "=", 2)
|
||||
if len(fields) != 2 {
|
||||
s.setError(errors.New("invalid syntax"))
|
||||
return "", false
|
||||
}
|
||||
|
||||
key = strings.TrimSpace(fields[0])
|
||||
value := strings.TrimSpace(fields[1])
|
||||
|
||||
valueInt, ok := new(big.Int).SetString(value, 16)
|
||||
if !ok {
|
||||
s.setError(fmt.Errorf("could not parse %q", value))
|
||||
return "", false
|
||||
}
|
||||
if _, dup := s.test.Values[key]; dup {
|
||||
s.setError(fmt.Errorf("duplicate key %q", key))
|
||||
return "", false
|
||||
}
|
||||
s.test.Values[key] = valueInt
|
||||
return key, true
|
||||
}
|
||||
|
||||
func (s *testScanner) Scan() bool {
|
||||
s.test = test{
|
||||
Values: make(map[string]*big.Int),
|
||||
}
|
||||
|
||||
// Scan until the first attribute.
|
||||
for {
|
||||
if !s.scanLine() {
|
||||
return false
|
||||
}
|
||||
if len(s.scanner.Text()) != 0 && s.scanner.Text()[0] != '#' {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var ok bool
|
||||
s.test.Type, ok = s.addAttribute(s.scanner.Text())
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
s.test.LineNumber = s.lineNo
|
||||
|
||||
for s.scanLine() {
|
||||
if len(s.scanner.Text()) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if s.scanner.Text()[0] == '#' {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := s.addAttribute(s.scanner.Text()); !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return s.scanner.Err() == nil
|
||||
}
|
||||
|
||||
func (s *testScanner) Test() test {
|
||||
return s.test
|
||||
}
|
||||
|
||||
func (s *testScanner) Err() error {
|
||||
if s.err != nil {
|
||||
return s.err
|
||||
}
|
||||
return s.scanner.Err()
|
||||
}
|
||||
|
||||
func (s *testScanner) setError(err error) {
|
||||
s.err = fmt.Errorf("line %d: %s", s.lineNo, err)
|
||||
}
|
||||
|
||||
func checkKeys(t test, keys ...string) bool {
|
||||
var foundErrors bool
|
||||
|
||||
for _, k := range keys {
|
||||
if _, ok := t.Values[k]; !ok {
|
||||
fmt.Fprintf(os.Stderr, "Line %d: missing key %q.\n", t.LineNumber, k)
|
||||
foundErrors = true
|
||||
}
|
||||
}
|
||||
|
||||
for k, _ := range t.Values {
|
||||
var found bool
|
||||
for _, k2 := range keys {
|
||||
if k == k2 {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
fmt.Fprintf(os.Stderr, "Line %d: unexpected key %q.\n", t.LineNumber, k)
|
||||
foundErrors = true
|
||||
}
|
||||
}
|
||||
|
||||
return !foundErrors
|
||||
}
|
||||
|
||||
func checkResult(t test, expr, key string, r *big.Int) {
|
||||
if t.Values[key].Cmp(r) != 0 {
|
||||
fmt.Fprintf(os.Stderr, "Line %d: %s did not match %s.\n\tGot %s\n", t.LineNumber, expr, key, r.Text(16))
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) != 2 {
|
||||
fmt.Fprintf(os.Stderr, "Usage: %s bn_tests.txt\n", os.Args[0])
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
in, err := os.Open(os.Args[1])
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error opening %s: %s.\n", os.Args[0], err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer in.Close()
|
||||
|
||||
scanner := newTestScanner(in)
|
||||
for scanner.Scan() {
|
||||
test := scanner.Test()
|
||||
switch test.Type {
|
||||
case "Sum":
|
||||
if checkKeys(test, "A", "B", "Sum") {
|
||||
r := new(big.Int).Add(test.Values["A"], test.Values["B"])
|
||||
checkResult(test, "A + B", "Sum", r)
|
||||
}
|
||||
case "LShift1":
|
||||
if checkKeys(test, "A", "LShift1") {
|
||||
r := new(big.Int).Add(test.Values["A"], test.Values["A"])
|
||||
checkResult(test, "A + A", "LShift1", r)
|
||||
}
|
||||
case "LShift":
|
||||
if checkKeys(test, "A", "N", "LShift") {
|
||||
r := new(big.Int).Lsh(test.Values["A"], uint(test.Values["N"].Uint64()))
|
||||
checkResult(test, "A << N", "LShift", r)
|
||||
}
|
||||
case "RShift":
|
||||
if checkKeys(test, "A", "N", "RShift") {
|
||||
r := new(big.Int).Rsh(test.Values["A"], uint(test.Values["N"].Uint64()))
|
||||
checkResult(test, "A >> N", "RShift", r)
|
||||
}
|
||||
case "Square":
|
||||
if checkKeys(test, "A", "Square") {
|
||||
r := new(big.Int).Mul(test.Values["A"], test.Values["A"])
|
||||
checkResult(test, "A * A", "Square", r)
|
||||
}
|
||||
case "Product":
|
||||
if checkKeys(test, "A", "B", "Product") {
|
||||
r := new(big.Int).Mul(test.Values["A"], test.Values["B"])
|
||||
checkResult(test, "A * B", "Product", r)
|
||||
}
|
||||
case "Quotient":
|
||||
if checkKeys(test, "A", "B", "Quotient", "Remainder") {
|
||||
q, r := new(big.Int).QuoRem(test.Values["A"], test.Values["B"], new(big.Int))
|
||||
checkResult(test, "A / B", "Quotient", q)
|
||||
checkResult(test, "A % B", "Remainder", r)
|
||||
}
|
||||
case "ModMul":
|
||||
if checkKeys(test, "A", "B", "M", "ModMul") {
|
||||
r := new(big.Int).Mul(test.Values["A"], test.Values["B"])
|
||||
r = r.Mod(r, test.Values["M"])
|
||||
checkResult(test, "A * B (mod M)", "ModMul", r)
|
||||
}
|
||||
case "ModExp":
|
||||
if checkKeys(test, "A", "E", "M", "ModExp") {
|
||||
r := new(big.Int).Exp(test.Values["A"], test.Values["E"], test.Values["M"])
|
||||
checkResult(test, "A ^ E (mod M)", "ModExp", r)
|
||||
}
|
||||
case "Exp":
|
||||
if checkKeys(test, "A", "E", "Exp") {
|
||||
r := new(big.Int).Exp(test.Values["A"], test.Values["E"], nil)
|
||||
checkResult(test, "A ^ E", "Exp", r)
|
||||
}
|
||||
case "ModSqrt":
|
||||
bigOne := new(big.Int).SetInt64(1)
|
||||
bigTwo := new(big.Int).SetInt64(2)
|
||||
|
||||
if checkKeys(test, "A", "P", "ModSqrt") {
|
||||
test.Values["A"].Mod(test.Values["A"], test.Values["P"])
|
||||
|
||||
r := new(big.Int).Mul(test.Values["ModSqrt"], test.Values["ModSqrt"])
|
||||
r = r.Mod(r, test.Values["P"])
|
||||
checkResult(test, "ModSqrt ^ 2 (mod P)", "A", r)
|
||||
|
||||
if test.Values["P"].Cmp(bigTwo) > 0 {
|
||||
pMinus1Over2 := new(big.Int).Sub(test.Values["P"], bigOne)
|
||||
pMinus1Over2.Rsh(pMinus1Over2, 1)
|
||||
|
||||
if test.Values["ModSqrt"].Cmp(pMinus1Over2) > 0 {
|
||||
fmt.Fprintf(os.Stderr, "Line %d: ModSqrt should be minimal.\n", test.LineNumber)
|
||||
}
|
||||
}
|
||||
}
|
||||
case "ModInv":
|
||||
if checkKeys(test, "A", "M", "ModInv") {
|
||||
r := new(big.Int).ModInverse(test.Values["A"], test.Values["M"])
|
||||
checkResult(test, "A ^ -1 (mod M)", "ModInv", r)
|
||||
}
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "Line %d: unknown test type %q.\n", test.LineNumber, test.Type)
|
||||
}
|
||||
}
|
||||
if scanner.Err() != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error reading tests: %s.\n", scanner.Err())
|
||||
}
|
||||
}
|
||||
@@ -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,15 +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_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);
|
||||
}
|
||||
|
||||
+75
-72
@@ -160,6 +160,9 @@ static BN_ULONG read_word_padded(const BIGNUM *in, size_t i) {
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -172,7 +175,7 @@ int BN_bn2bin_padded(uint8_t *out, size_t len, const BIGNUM *in) {
|
||||
return 0;
|
||||
}
|
||||
if ((len % BN_BYTES) != 0) {
|
||||
BN_ULONG l = read_word_padded(in, len / BN_BYTES);
|
||||
l = read_word_padded(in, len / BN_BYTES);
|
||||
if (l >> (8 * (len % BN_BYTES)) != 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -185,9 +188,9 @@ int BN_bn2bin_padded(uint8_t *out, size_t len, const BIGNUM *in) {
|
||||
* leading zero octets is low.
|
||||
*
|
||||
* See Falko Stenzke, "Manger's Attack revisited", ICICS 2010. */
|
||||
size_t i = len;
|
||||
i = len;
|
||||
while (i--) {
|
||||
BN_ULONG l = read_word_padded(in, i / BN_BYTES);
|
||||
l = read_word_padded(in, i / BN_BYTES);
|
||||
*(out++) = (uint8_t)(l >> (8 * (i % BN_BYTES))) & 0xff;
|
||||
}
|
||||
return 1;
|
||||
@@ -201,14 +204,17 @@ int BN_bn2cbb_padded(CBB *out, size_t len, const BIGNUM *in) {
|
||||
static const char hextable[] = "0123456789abcdef";
|
||||
|
||||
char *BN_bn2hex(const BIGNUM *bn) {
|
||||
char *buf = OPENSSL_malloc(1 /* leading '-' */ + 1 /* zero is non-empty */ +
|
||||
bn->top * BN_BYTES * 2 + 1 /* trailing NUL */);
|
||||
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;
|
||||
}
|
||||
|
||||
char *p = buf;
|
||||
p = buf;
|
||||
if (bn->neg) {
|
||||
*(p++) = '-';
|
||||
}
|
||||
@@ -217,11 +223,10 @@ char *BN_bn2hex(const BIGNUM *bn) {
|
||||
*(p++) = '0';
|
||||
}
|
||||
|
||||
int z = 0;
|
||||
for (int i = bn->top - 1; i >= 0; i--) {
|
||||
for (int j = BN_BITS2 - 8; j >= 0; j -= 8) {
|
||||
for (i = bn->top - 1; i >= 0; i--) {
|
||||
for (j = BN_BITS2 - 8; j >= 0; j -= 8) {
|
||||
/* strip leading zeros */
|
||||
int v = ((int)(bn->d[i] >> (long)j)) & 0xff;
|
||||
v = ((int)(bn->d[i] >> (long)j)) & 0xff;
|
||||
if (z || v != 0) {
|
||||
*(p++) = hextable[v >> 4];
|
||||
*(p++) = hextable[v & 0x0f];
|
||||
@@ -367,69 +372,72 @@ int BN_hex2bn(BIGNUM **outp, const char *in) {
|
||||
}
|
||||
|
||||
char *BN_bn2dec(const BIGNUM *a) {
|
||||
/* It is easier to print strings little-endian, so we assemble it in reverse
|
||||
* and fix at the end. */
|
||||
BIGNUM *copy = NULL;
|
||||
CBB cbb;
|
||||
if (!CBB_init(&cbb, 16) ||
|
||||
!CBB_add_u8(&cbb, 0 /* trailing NUL */)) {
|
||||
goto cbb_err;
|
||||
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;
|
||||
}
|
||||
|
||||
if (BN_is_zero(a)) {
|
||||
if (!CBB_add_u8(&cbb, '0')) {
|
||||
goto cbb_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 {
|
||||
copy = BN_dup(a);
|
||||
if (copy == NULL) {
|
||||
goto err;
|
||||
if (BN_is_negative(t)) {
|
||||
*p++ = '-';
|
||||
}
|
||||
|
||||
while (!BN_is_zero(copy)) {
|
||||
BN_ULONG word = BN_div_word(copy, BN_DEC_CONV);
|
||||
if (word == (BN_ULONG)-1) {
|
||||
goto err;
|
||||
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++;
|
||||
}
|
||||
|
||||
const int add_leading_zeros = !BN_is_zero(copy);
|
||||
for (int i = 0; i < BN_DEC_NUM && (add_leading_zeros || word != 0); i++) {
|
||||
if (!CBB_add_u8(&cbb, '0' + word % 10)) {
|
||||
goto cbb_err;
|
||||
}
|
||||
word /= 10;
|
||||
}
|
||||
assert(word == 0);
|
||||
}
|
||||
}
|
||||
ok = 1;
|
||||
|
||||
if (BN_is_negative(a) &&
|
||||
!CBB_add_u8(&cbb, '-')) {
|
||||
goto cbb_err;
|
||||
}
|
||||
|
||||
uint8_t *data;
|
||||
size_t len;
|
||||
if (!CBB_finish(&cbb, &data, &len)) {
|
||||
goto cbb_err;
|
||||
}
|
||||
|
||||
/* Reverse the buffer. */
|
||||
for (size_t i = 0; i < len/2; i++) {
|
||||
uint8_t tmp = data[i];
|
||||
data[i] = data[len - 1 - i];
|
||||
data[len - 1 - i] = tmp;
|
||||
}
|
||||
|
||||
BN_free(copy);
|
||||
return (char *)data;
|
||||
|
||||
cbb_err:
|
||||
OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
|
||||
err:
|
||||
BN_free(copy);
|
||||
CBB_cleanup(&cbb);
|
||||
return NULL;
|
||||
OPENSSL_free(bn_data);
|
||||
BN_free(t);
|
||||
if (!ok) {
|
||||
OPENSSL_free(buf);
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
int BN_dec2bn(BIGNUM **outp, const char *in) {
|
||||
@@ -569,14 +577,12 @@ BIGNUM *BN_mpi2bn(const uint8_t *in, size_t len, BIGNUM *out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int out_is_alloced = 0;
|
||||
if (out == NULL) {
|
||||
out = BN_new();
|
||||
if (out == NULL) {
|
||||
OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
|
||||
return NULL;
|
||||
}
|
||||
out_is_alloced = 1;
|
||||
}
|
||||
if (out == NULL) {
|
||||
OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (in_len == 0) {
|
||||
@@ -586,9 +592,6 @@ BIGNUM *BN_mpi2bn(const uint8_t *in, size_t len, BIGNUM *out) {
|
||||
|
||||
in += 4;
|
||||
if (BN_bin2bn(in, in_len, out) == NULL) {
|
||||
if (out_is_alloced) {
|
||||
BN_free(out);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
out->neg = ((*in) & 0x80) != 0;
|
||||
|
||||
+2
-16
@@ -158,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)
|
||||
@@ -644,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
|
||||
|
||||
+357
-33
@@ -576,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);
|
||||
}
|
||||
|
||||
@@ -992,7 +1026,7 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
|
||||
|
||||
/* prepare a^1 in Montgomery domain */
|
||||
if (a->neg || BN_ucmp(a, m) >= 0) {
|
||||
if (!BN_nnmod(&am, a, m, ctx) ||
|
||||
if (!BN_mod(&am, a, m, ctx) ||
|
||||
!BN_to_montgomery(&am, &am, mont, ctx)) {
|
||||
goto err;
|
||||
}
|
||||
@@ -1200,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) {
|
||||
@@ -1238,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;
|
||||
}
|
||||
|
||||
+298
-215
@@ -108,8 +108,6 @@
|
||||
|
||||
#include <openssl/bn.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "internal.h"
|
||||
@@ -225,44 +223,54 @@ err:
|
||||
}
|
||||
|
||||
/* solves ax == 1 (mod n) */
|
||||
static int bn_mod_inverse_general(BIGNUM *out, int *out_no_inverse,
|
||||
const BIGNUM *a, const BIGNUM *n,
|
||||
BN_CTX *ctx);
|
||||
static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, int *out_no_inverse,
|
||||
const BIGNUM *a, const BIGNUM *n,
|
||||
BN_CTX *ctx);
|
||||
|
||||
int BN_mod_inverse_odd(BIGNUM *out, int *out_no_inverse, const BIGNUM *a,
|
||||
const BIGNUM *n, BN_CTX *ctx) {
|
||||
*out_no_inverse = 0;
|
||||
|
||||
if (!BN_is_odd(n)) {
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (BN_is_negative(a) || BN_cmp(a, n) >= 0) {
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_INPUT_NOT_REDUCED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
BIGNUM *A, *B, *X, *Y;
|
||||
int ret = 0;
|
||||
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);
|
||||
if (Y == NULL) {
|
||||
T = BN_CTX_get(ctx);
|
||||
if (T == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
BIGNUM *R = out;
|
||||
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
|
||||
*
|
||||
@@ -271,99 +279,225 @@ int BN_mod_inverse_odd(BIGNUM *out, int *out_no_inverse, const BIGNUM *a,
|
||||
* sign*Y*a == A (mod |n|).
|
||||
*/
|
||||
|
||||
/* 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 systems, but much more on 64-bit systems) */
|
||||
int shift;
|
||||
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|) */
|
||||
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++;
|
||||
/* 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)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
/* 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)) {
|
||||
if (shift > 0) {
|
||||
if (!BN_rshift(B, B, shift)) {
|
||||
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;
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
/* 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;
|
||||
if (shift > 0) {
|
||||
if (!BN_rshift(A, A, shift)) {
|
||||
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;
|
||||
|
||||
/* 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 */
|
||||
|
||||
if (!BN_is_one(A)) {
|
||||
*out_no_inverse = 1;
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_NO_INVERSE);
|
||||
goto err;
|
||||
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
|
||||
@@ -379,20 +513,28 @@ int BN_mod_inverse_odd(BIGNUM *out, int *out_no_inverse, const BIGNUM *a,
|
||||
}
|
||||
/* Now Y*a == A (mod |n|). */
|
||||
|
||||
/* Y*a == 1 (mod |n|) */
|
||||
if (!Y->neg && BN_ucmp(Y, n) < 0) {
|
||||
if (!BN_copy(R, Y)) {
|
||||
goto err;
|
||||
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 {
|
||||
if (!BN_nnmod(R, Y, n, ctx)) {
|
||||
goto err;
|
||||
}
|
||||
*out_no_inverse = 1;
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_NO_INVERSE);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
ret = R;
|
||||
|
||||
err:
|
||||
if (ret == NULL && out == NULL) {
|
||||
BN_free(R);
|
||||
}
|
||||
BN_CTX_end(ctx);
|
||||
return ret;
|
||||
}
|
||||
@@ -400,97 +542,18 @@ err:
|
||||
BIGNUM *BN_mod_inverse(BIGNUM *out, const BIGNUM *a, const BIGNUM *n,
|
||||
BN_CTX *ctx) {
|
||||
int no_inverse;
|
||||
|
||||
BIGNUM *a_reduced = NULL;
|
||||
|
||||
BIGNUM *new_out = NULL;
|
||||
if (out == NULL) {
|
||||
new_out = BN_new();
|
||||
if (new_out == NULL) {
|
||||
OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
|
||||
return NULL;
|
||||
}
|
||||
out = new_out;
|
||||
}
|
||||
|
||||
int ok = 0;
|
||||
|
||||
int no_branch =
|
||||
(a->flags & BN_FLG_CONSTTIME) != 0 || (n->flags & BN_FLG_CONSTTIME) != 0;
|
||||
|
||||
if (a->neg || BN_ucmp(a, n) >= 0) {
|
||||
a_reduced = BN_dup(a);
|
||||
if (a_reduced == NULL) {
|
||||
goto err;
|
||||
}
|
||||
if (no_branch) {
|
||||
BN_set_flags(a_reduced, BN_FLG_CONSTTIME);
|
||||
}
|
||||
if (!BN_nnmod(a_reduced, a_reduced, n, ctx)) {
|
||||
goto err;
|
||||
}
|
||||
a = a_reduced;
|
||||
}
|
||||
|
||||
if (no_branch || !BN_is_odd(n)) {
|
||||
if (!bn_mod_inverse_general(out, &no_inverse, a, n, ctx)) {
|
||||
goto err;
|
||||
}
|
||||
} else if (!BN_mod_inverse_odd(out, &no_inverse, a, n, ctx)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
ok = 1;
|
||||
|
||||
err:
|
||||
if (!ok) {
|
||||
BN_free(new_out);
|
||||
out = NULL;
|
||||
}
|
||||
BN_free(a_reduced);
|
||||
return out;
|
||||
return BN_mod_inverse_ex(out, &no_inverse, a, n, ctx);
|
||||
}
|
||||
|
||||
int BN_mod_inverse_blinded(BIGNUM *out, int *out_no_inverse, const BIGNUM *a,
|
||||
const BN_MONT_CTX *mont, BN_CTX *ctx) {
|
||||
*out_no_inverse = 0;
|
||||
|
||||
if (BN_is_negative(a) || BN_cmp(a, &mont->N) >= 0) {
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_INPUT_NOT_REDUCED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
BIGNUM blinding_factor;
|
||||
BN_init(&blinding_factor);
|
||||
|
||||
if (!BN_rand_range_ex(&blinding_factor, 1, &mont->N) ||
|
||||
!BN_mod_mul_montgomery(out, &blinding_factor, a, mont, ctx) ||
|
||||
!BN_mod_inverse_odd(out, out_no_inverse, out, &mont->N, ctx) ||
|
||||
!BN_mod_mul_montgomery(out, &blinding_factor, out, mont, ctx)) {
|
||||
OPENSSL_PUT_ERROR(BN, ERR_R_BN_LIB);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
BN_free(&blinding_factor);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* bn_mod_inverse_general is the general inversion algorithm that works for
|
||||
* both even and odd |n|. It 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. */
|
||||
static int bn_mod_inverse_general(BIGNUM *out, int *out_no_inverse,
|
||||
const BIGNUM *a, const BIGNUM *n,
|
||||
BN_CTX *ctx) {
|
||||
BIGNUM *A, *B, *X, *Y, *M, *D, *T;
|
||||
BIGNUM local_A;
|
||||
BIGNUM *pA;
|
||||
int ret = 0;
|
||||
/* 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;
|
||||
@@ -507,7 +570,14 @@ static int bn_mod_inverse_general(BIGNUM *out, int *out_no_inverse,
|
||||
goto err;
|
||||
}
|
||||
|
||||
BIGNUM *R = out;
|
||||
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) {
|
||||
@@ -515,6 +585,16 @@ static int bn_mod_inverse_general(BIGNUM *out, int *out_no_inverse,
|
||||
}
|
||||
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
|
||||
*
|
||||
@@ -588,12 +668,6 @@ static int bn_mod_inverse_general(BIGNUM *out, int *out_no_inverse,
|
||||
sign = -sign;
|
||||
}
|
||||
|
||||
if (!BN_is_one(A)) {
|
||||
*out_no_inverse = 1;
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_NO_INVERSE);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* The while loop (Euclid's algorithm) ends when
|
||||
* A == gcd(a,n);
|
||||
@@ -609,20 +683,29 @@ static int bn_mod_inverse_general(BIGNUM *out, int *out_no_inverse,
|
||||
}
|
||||
/* Now Y*a == A (mod |n|). */
|
||||
|
||||
/* Y*a == 1 (mod |n|) */
|
||||
if (!Y->neg && BN_ucmp(Y, n) < 0) {
|
||||
if (!BN_copy(R, Y)) {
|
||||
goto err;
|
||||
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 {
|
||||
if (!BN_nnmod(R, Y, n, ctx)) {
|
||||
goto err;
|
||||
}
|
||||
*out_no_inverse = 1;
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_NO_INVERSE);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
ret = R;
|
||||
|
||||
err:
|
||||
if (ret == NULL && out == NULL) {
|
||||
BN_free(R);
|
||||
}
|
||||
|
||||
BN_CTX_end(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
+67
-71
@@ -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)
|
||||
|
||||
+9
-17
@@ -126,9 +126,9 @@
|
||||
#include <openssl/base.h>
|
||||
|
||||
#if defined(OPENSSL_X86_64) && defined(_MSC_VER)
|
||||
OPENSSL_MSVC_PRAGMA(warning(push, 3))
|
||||
#pragma warning(push, 3)
|
||||
#include <intrin.h>
|
||||
OPENSSL_MSVC_PRAGMA(warning(pop))
|
||||
#pragma warning(pop)
|
||||
#pragma intrinsic(__umulh, _umul128)
|
||||
#endif
|
||||
|
||||
@@ -156,11 +156,10 @@ BIGNUM *bn_expand(BIGNUM *bn, size_t bits);
|
||||
#define BN_MASK2l (0xffffffffUL)
|
||||
#define BN_MASK2h (0xffffffff00000000UL)
|
||||
#define BN_MASK2h1 (0xffffffff80000000UL)
|
||||
#define BN_MONT_CTX_N0_LIMBS 1
|
||||
#define BN_TBIT (0x8000000000000000UL)
|
||||
#define BN_DEC_CONV (10000000000000000000UL)
|
||||
#define BN_DEC_NUM 19
|
||||
#define TOBN(hi, lo) ((BN_ULONG)(hi) << 32 | (lo))
|
||||
#define TOBN(hi, lo) ((BN_ULONG)hi << 32 | lo)
|
||||
|
||||
#elif defined(OPENSSL_32_BIT)
|
||||
|
||||
@@ -172,26 +171,20 @@ BIGNUM *bn_expand(BIGNUM *bn, size_t bits);
|
||||
#define BN_MASK2l (0xffffUL)
|
||||
#define BN_MASK2h1 (0xffff8000UL)
|
||||
#define BN_MASK2h (0xffff0000UL)
|
||||
/* On some 32-bit platforms, Montgomery multiplication is done using 64-bit
|
||||
* arithmetic with SIMD instructions. On such platforms, |BN_MONT_CTX::n0|
|
||||
* needs to be two words long. Only certain 32-bit platforms actually make use
|
||||
* of n0[1] and shorter R value would suffice for the others. However,
|
||||
* currently only the assembly files know which is which. */
|
||||
#define BN_MONT_CTX_N0_LIMBS 2
|
||||
#define BN_TBIT (0x80000000UL)
|
||||
#define BN_DEC_CONV (1000000000UL)
|
||||
#define BN_DEC_NUM 9
|
||||
#define TOBN(hi, lo) (lo), (hi)
|
||||
#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 \
|
||||
#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)
|
||||
@@ -199,6 +192,7 @@ BIGNUM *bn_expand(BIGNUM *bn, size_t bits);
|
||||
#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);
|
||||
@@ -227,8 +221,6 @@ 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);
|
||||
|
||||
uint64_t bn_mont_n0(const BIGNUM *n);
|
||||
|
||||
#if defined(OPENSSL_X86_64) && defined(_MSC_VER)
|
||||
#define BN_UMULT_LOHI(low, high, a, b) ((low) = _umul128((a), (b), &(high)))
|
||||
#endif
|
||||
|
||||
+115
-45
@@ -162,71 +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 */
|
||||
}
|
||||
if (BN_get_flags(mod, BN_FLG_CONSTTIME)) {
|
||||
BN_set_flags(&mont->N, BN_FLG_CONSTTIME);
|
||||
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 because R^2 will still be a multiple of the
|
||||
* latter as |BN_MONT_CTX_N0_LIMBS| is either one or two. */
|
||||
unsigned lgBigR = (BN_num_bits(mod) + (BN_BITS2 - 1)) / BN_BITS2 * BN_BITS2;
|
||||
BN_zero(&mont->RR);
|
||||
if (!BN_set_bit(&mont->RR, lgBigR * 2) ||
|
||||
!BN_mod(&mont->RR, &mont->RR, &mont->N, ctx)) {
|
||||
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);
|
||||
@@ -247,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,
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
/* Copyright 2016 Brian Smith.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
#include <openssl/bn.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
static uint64_t bn_neg_inv_mod_r_u64(uint64_t n);
|
||||
|
||||
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(uint64_t) ==
|
||||
BN_MONT_CTX_N0_LIMBS * sizeof(BN_ULONG),
|
||||
BN_MONT_CTX_N0_LIMBS_DOES_NOT_MATCH_UINT64_T);
|
||||
|
||||
/* LG_LITTLE_R is log_2(r). */
|
||||
#define LG_LITTLE_R (BN_MONT_CTX_N0_LIMBS * BN_BITS2)
|
||||
|
||||
uint64_t bn_mont_n0(const BIGNUM *n) {
|
||||
/* These conditions are checked by the caller, |BN_MONT_CTX_set|. */
|
||||
assert(!BN_is_zero(n));
|
||||
assert(!BN_is_negative(n));
|
||||
assert(BN_is_odd(n));
|
||||
|
||||
/* r == 2**(BN_MONT_CTX_N0_LIMBS * BN_BITS2) and LG_LITTLE_R == lg(r). This
|
||||
* ensures that we can do integer division by |r| by simply ignoring
|
||||
* |BN_MONT_CTX_N0_LIMBS| limbs. Similarly, we can calculate values modulo
|
||||
* |r| by just looking at the lowest |BN_MONT_CTX_N0_LIMBS| limbs. This is
|
||||
* what makes Montgomery multiplication efficient.
|
||||
*
|
||||
* As shown in Algorithm 1 of "Fast Prime Field Elliptic Curve Cryptography
|
||||
* with 256 Bit Primes" by Shay Gueron and Vlad Krasnov, in the loop of a
|
||||
* multi-limb Montgomery multiplication of |a * b (mod n)|, given the
|
||||
* unreduced product |t == a * b|, we repeatedly calculate:
|
||||
*
|
||||
* t1 := t % r |t1| is |t|'s lowest limb (see previous paragraph).
|
||||
* t2 := t1*n0*n
|
||||
* t3 := t + t2
|
||||
* t := t3 / r copy all limbs of |t3| except the lowest to |t|.
|
||||
*
|
||||
* In the last step, it would only make sense to ignore the lowest limb of
|
||||
* |t3| if it were zero. The middle steps ensure that this is the case:
|
||||
*
|
||||
* t3 == 0 (mod r)
|
||||
* t + t2 == 0 (mod r)
|
||||
* t + t1*n0*n == 0 (mod r)
|
||||
* t1*n0*n == -t (mod r)
|
||||
* t*n0*n == -t (mod r)
|
||||
* n0*n == -1 (mod r)
|
||||
* n0 == -1/n (mod r)
|
||||
*
|
||||
* Thus, in each iteration of the loop, we multiply by the constant factor
|
||||
* |n0|, the negative inverse of n (mod r). */
|
||||
|
||||
/* n_mod_r = n % r. As explained above, this is done by taking the lowest
|
||||
* |BN_MONT_CTX_N0_LIMBS| limbs of |n|. */
|
||||
uint64_t n_mod_r = n->d[0];
|
||||
#if BN_MONT_CTX_N0_LIMBS == 2
|
||||
if (n->top > 1) {
|
||||
n_mod_r |= (uint64_t)n->d[1] << BN_BITS2;
|
||||
}
|
||||
#endif
|
||||
|
||||
return bn_neg_inv_mod_r_u64(n_mod_r);
|
||||
}
|
||||
|
||||
/* bn_neg_inv_r_mod_n_u64 calculates the -1/n mod r; i.e. it calculates |v|
|
||||
* such that u*r - v*n == 1. |r| is the constant defined in |bn_mont_n0|. |n|
|
||||
* must be odd.
|
||||
*
|
||||
* This is derived from |xbinGCD| in Henry S. Warren, Jr.'s "Montgomery
|
||||
* Multiplication" (http://www.hackersdelight.org/MontgomeryMultiplication.pdf).
|
||||
* It is very similar to the MODULAR-INVERSE function in Stephen R. Dussé's and
|
||||
* Burton S. Kaliski Jr.'s "A Cryptographic Library for the Motorola DSP56000"
|
||||
* (http://link.springer.com/chapter/10.1007%2F3-540-46877-3_21).
|
||||
*
|
||||
* This is inspired by Joppe W. Bos's "Constant Time Modular Inversion"
|
||||
* (http://www.joppebos.com/files/CTInversion.pdf) so that the inversion is
|
||||
* constant-time with respect to |n|. We assume uint64_t additions,
|
||||
* subtractions, shifts, and bitwise operations are all constant time, which
|
||||
* may be a large leap of faith on 32-bit targets. We avoid division and
|
||||
* multiplication, which tend to be the most problematic in terms of timing
|
||||
* leaks.
|
||||
*
|
||||
* Most GCD implementations return values such that |u*r + v*n == 1|, so the
|
||||
* caller would have to negate the resultant |v| for the purpose of Montgomery
|
||||
* multiplication. This implementation does the negation implicitly by doing
|
||||
* the computations as a difference instead of a sum. */
|
||||
static uint64_t bn_neg_inv_mod_r_u64(uint64_t n) {
|
||||
assert(n % 2 == 1);
|
||||
|
||||
/* alpha == 2**(lg r - 1) == r / 2. */
|
||||
static const uint64_t alpha = UINT64_C(1) << (LG_LITTLE_R - 1);
|
||||
|
||||
const uint64_t beta = n;
|
||||
|
||||
uint64_t u = 1;
|
||||
uint64_t v = 0;
|
||||
|
||||
/* The invariant maintained from here on is:
|
||||
* 2**(lg r - i) == u*2*alpha - v*beta. */
|
||||
for (size_t i = 0; i < LG_LITTLE_R; ++i) {
|
||||
#if BN_BITS2 == 64 && defined(BN_ULLONG)
|
||||
assert((BN_ULLONG)(1) << (LG_LITTLE_R - i) ==
|
||||
((BN_ULLONG)u * 2 * alpha) - ((BN_ULLONG)v * beta));
|
||||
#endif
|
||||
|
||||
/* Delete a common factor of 2 in u and v if |u| is even. Otherwise, set
|
||||
* |u = (u + beta) / 2| and |v = (v / 2) + alpha|. */
|
||||
|
||||
uint64_t u_is_odd = UINT64_C(0) - (u & 1); /* Either 0xff..ff or 0. */
|
||||
|
||||
/* The addition can overflow, so use Dietz's method for it.
|
||||
*
|
||||
* Dietz calculates (x+y)/2 by (x⊕y)>>1 + x&y. This is valid for all
|
||||
* (unsigned) x and y, even when x+y overflows. Evidence for 32-bit values
|
||||
* (embedded in 64 bits to so that overflow can be ignored):
|
||||
*
|
||||
* (declare-fun x () (_ BitVec 64))
|
||||
* (declare-fun y () (_ BitVec 64))
|
||||
* (assert (let (
|
||||
* (one (_ bv1 64))
|
||||
* (thirtyTwo (_ bv32 64)))
|
||||
* (and
|
||||
* (bvult x (bvshl one thirtyTwo))
|
||||
* (bvult y (bvshl one thirtyTwo))
|
||||
* (not (=
|
||||
* (bvadd (bvlshr (bvxor x y) one) (bvand x y))
|
||||
* (bvlshr (bvadd x y) one)))
|
||||
* )))
|
||||
* (check-sat) */
|
||||
uint64_t beta_if_u_is_odd = beta & u_is_odd; /* Either |beta| or 0. */
|
||||
u = ((u ^ beta_if_u_is_odd) >> 1) + (u & beta_if_u_is_odd);
|
||||
|
||||
uint64_t alpha_if_u_is_odd = alpha & u_is_odd; /* Either |alpha| or 0. */
|
||||
v = (v >> 1) + alpha_if_u_is_odd;
|
||||
}
|
||||
|
||||
/* The invariant now shows that u*r - v*n == 1 since r == 2 * alpha. */
|
||||
#if BN_BITS2 == 64 && defined(BN_ULLONG)
|
||||
assert(1 == ((BN_ULLONG)u * 2 * alpha) - ((BN_ULLONG)v * beta));
|
||||
#endif
|
||||
|
||||
return v;
|
||||
}
|
||||
+8
-24
@@ -496,11 +496,7 @@ int BN_is_prime_fasttest_ex(const BIGNUM *a, int checks, BN_CTX *ctx_passed,
|
||||
|
||||
if (do_trial_division) {
|
||||
for (i = 1; i < NUMPRIMES; i++) {
|
||||
BN_ULONG mod = BN_mod_word(a, primes[i]);
|
||||
if (mod == (BN_ULONG)-1) {
|
||||
goto err;
|
||||
}
|
||||
if (mod == 0) {
|
||||
if (BN_mod_word(a, primes[i]) == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -651,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. */
|
||||
@@ -735,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;
|
||||
}
|
||||
|
||||
@@ -761,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;
|
||||
}
|
||||
@@ -798,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;
|
||||
}
|
||||
|
||||
@@ -837,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;
|
||||
}
|
||||
|
||||
+34
-48
@@ -123,17 +123,6 @@ int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (top != BN_RAND_TOP_ANY && top != BN_RAND_TOP_ONE &&
|
||||
top != BN_RAND_TOP_TWO) {
|
||||
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bottom != BN_RAND_BOTTOM_ANY && bottom != BN_RAND_BOTTOM_ODD) {
|
||||
OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bits == 0) {
|
||||
BN_zero(rnd);
|
||||
return 1;
|
||||
@@ -154,8 +143,8 @@ int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (top != BN_RAND_TOP_ANY) {
|
||||
if (top == BN_RAND_TOP_TWO && bits > 1) {
|
||||
if (top != -1) {
|
||||
if (top && bits > 1) {
|
||||
if (bit == 0) {
|
||||
buf[0] = 1;
|
||||
buf[1] |= 0x80;
|
||||
@@ -169,8 +158,8 @@ int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) {
|
||||
|
||||
buf[0] &= ~mask;
|
||||
|
||||
/* Set the bottom bit if requested, */
|
||||
if (bottom == BN_RAND_BOTTOM_ODD) {
|
||||
/* set bottom bit if requested */
|
||||
if (bottom) {
|
||||
buf[bytes - 1] |= 1;
|
||||
}
|
||||
|
||||
@@ -192,68 +181,65 @@ int BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom) {
|
||||
return BN_rand(rnd, bits, top, bottom);
|
||||
}
|
||||
|
||||
int BN_rand_range_ex(BIGNUM *r, BN_ULONG min_inclusive,
|
||||
const BIGNUM *max_exclusive) {
|
||||
int BN_rand_range(BIGNUM *r, const BIGNUM *range) {
|
||||
unsigned n;
|
||||
unsigned count = 100;
|
||||
|
||||
if (BN_cmp_word(max_exclusive, min_inclusive) <= 0) {
|
||||
if (range->neg || BN_is_zero(range)) {
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_INVALID_RANGE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n = BN_num_bits(max_exclusive); /* n > 0 */
|
||||
n = BN_num_bits(range); /* n > 0 */
|
||||
|
||||
/* BN_is_bit_set(range, n - 1) always holds */
|
||||
if (n == 1) {
|
||||
BN_zero(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
do {
|
||||
if (!--count) {
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_ITERATIONS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!BN_is_bit_set(max_exclusive, n - 2) &&
|
||||
!BN_is_bit_set(max_exclusive, n - 3)) {
|
||||
/* range = 100..._2, so 3*range (= 11..._2) is exactly one bit longer
|
||||
* than range. This is a common scenario when generating a random value
|
||||
* modulo an RSA public modulus, e.g. for RSA base blinding. */
|
||||
if (!BN_rand(r, n + 1, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY)) {
|
||||
} 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, max_exclusive) >= 0) {
|
||||
if (!BN_sub(r, r, max_exclusive)) {
|
||||
if (BN_cmp(r, range) >= 0) {
|
||||
if (!BN_sub(r, r, range)) {
|
||||
return 0;
|
||||
}
|
||||
if (BN_cmp(r, max_exclusive) >= 0) {
|
||||
if (!BN_sub(r, r, max_exclusive)) {
|
||||
if (BN_cmp(r, range) >= 0) {
|
||||
if (!BN_sub(r, r, range)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* range = 11..._2 or range = 101..._2 */
|
||||
if (!BN_rand(r, n, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY)) {
|
||||
|
||||
if (!--count) {
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_ITERATIONS);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} while (BN_cmp_word(r, min_inclusive) < 0 ||
|
||||
BN_cmp(r, max_exclusive) >= 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_rand_range(BIGNUM *r, const BIGNUM *range) {
|
||||
return BN_rand_range_ex(r, 0, range);
|
||||
}
|
||||
|
||||
int BN_pseudo_rand_range(BIGNUM *r, const BIGNUM *range) {
|
||||
return BN_rand_range(r, range);
|
||||
}
|
||||
|
||||
+5
-4
@@ -57,11 +57,12 @@
|
||||
#include <openssl/err.h>
|
||||
|
||||
|
||||
/* Returns 'ret' such that
|
||||
* ret^2 == a (mod p),
|
||||
* using the Tonelli/Shanks algorithm (cf. Henri Cohen, "A Course
|
||||
* in Algebraic Computational Number Theory", algorithm 1.5.1).
|
||||
* 'p' must be prime! */
|
||||
BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx) {
|
||||
/* Compute a square root of |a| mod |p| using the Tonelli/Shanks algorithm
|
||||
* (cf. Henri Cohen, "A Course in Algebraic Computational Number Theory",
|
||||
* algorithm 1.5.1). |p| is assumed to be a prime. */
|
||||
|
||||
BIGNUM *ret = in;
|
||||
int err = 1;
|
||||
int r;
|
||||
|
||||
+21
-25
@@ -88,26 +88,34 @@ void BUF_MEM_free(BUF_MEM *buf) {
|
||||
OPENSSL_free(buf);
|
||||
}
|
||||
|
||||
static int buf_mem_reserve(BUF_MEM *buf, size_t cap, int clean) {
|
||||
if (buf->max >= cap) {
|
||||
return 1;
|
||||
static size_t buf_mem_grow(BUF_MEM *buf, size_t len, char clean) {
|
||||
char *new_buf;
|
||||
size_t n, alloc_size;
|
||||
|
||||
if (buf->length >= len) {
|
||||
buf->length = len;
|
||||
return len;
|
||||
}
|
||||
if (buf->max >= len) {
|
||||
memset(&buf->data[buf->length], 0, len - buf->length);
|
||||
buf->length = len;
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t n = cap + 3;
|
||||
if (n < cap) {
|
||||
n = len + 3;
|
||||
if (n < len) {
|
||||
/* overflow */
|
||||
OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
n = n / 3;
|
||||
size_t alloc_size = n * 4;
|
||||
alloc_size = n * 4;
|
||||
if (alloc_size / 4 != n) {
|
||||
/* overflow */
|
||||
OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *new_buf;
|
||||
if (buf->data == NULL) {
|
||||
new_buf = OPENSSL_malloc(alloc_size);
|
||||
} else {
|
||||
@@ -120,26 +128,14 @@ static int buf_mem_reserve(BUF_MEM *buf, size_t cap, int clean) {
|
||||
|
||||
if (new_buf == NULL) {
|
||||
OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
buf->data = new_buf;
|
||||
buf->max = alloc_size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BUF_MEM_reserve(BUF_MEM *buf, size_t cap) {
|
||||
return buf_mem_reserve(buf, cap, 0 /* don't clear old buffer contents. */);
|
||||
}
|
||||
|
||||
static size_t buf_mem_grow(BUF_MEM *buf, size_t len, int clean) {
|
||||
if (!buf_mem_reserve(buf, len, clean)) {
|
||||
return 0;
|
||||
}
|
||||
if (buf->length < len) {
|
||||
len = 0;
|
||||
} else {
|
||||
buf->data = new_buf;
|
||||
buf->max = alloc_size;
|
||||
memset(&buf->data[buf->length], 0, len - buf->length);
|
||||
buf->length = len;
|
||||
}
|
||||
buf->length = len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,13 +22,12 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/bytestring.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/bytestring.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "../internal.h"
|
||||
#include "../test/scoped_types.h"
|
||||
|
||||
namespace bssl {
|
||||
|
||||
static bool TestSkip() {
|
||||
static const uint8_t kData[] = {1, 2, 3};
|
||||
@@ -44,7 +43,7 @@ static bool TestSkip() {
|
||||
}
|
||||
|
||||
static bool TestGetUint() {
|
||||
static const uint8_t kData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
|
||||
static const uint8_t kData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
uint8_t u8;
|
||||
uint16_t u16;
|
||||
uint32_t u32;
|
||||
@@ -59,10 +58,7 @@ static bool TestGetUint() {
|
||||
u32 == 0x40506 &&
|
||||
CBS_get_u32(&data, &u32) &&
|
||||
u32 == 0x708090a &&
|
||||
CBS_get_last_u8(&data, &u8) &&
|
||||
u8 == 0xb &&
|
||||
!CBS_get_u8(&data, &u8) &&
|
||||
!CBS_get_last_u8(&data, &u8);
|
||||
!CBS_get_u8(&data, &u8);
|
||||
}
|
||||
|
||||
static bool TestGetPrefixed() {
|
||||
@@ -231,25 +227,6 @@ static bool TestGetASN1() {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned tag;
|
||||
CBS_init(&data, kData1, sizeof(kData1));
|
||||
if (!CBS_get_any_asn1(&data, &contents, &tag) ||
|
||||
tag != CBS_ASN1_SEQUENCE ||
|
||||
CBS_len(&contents) != 2 ||
|
||||
memcmp(CBS_data(&contents), "\x01\x02", 2) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t header_len;
|
||||
CBS_init(&data, kData1, sizeof(kData1));
|
||||
if (!CBS_get_any_asn1_element(&data, &contents, &tag, &header_len) ||
|
||||
tag != CBS_ASN1_SEQUENCE ||
|
||||
header_len != 2 ||
|
||||
CBS_len(&contents) != 4 ||
|
||||
memcmp(CBS_data(&contents), "\x30\x02\x01\x02", 2) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -289,7 +266,7 @@ static bool TestGetOptionalASN1Bool() {
|
||||
}
|
||||
|
||||
static bool TestCBBBasic() {
|
||||
static const uint8_t kExpected[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc};
|
||||
static const uint8_t kExpected[] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
uint8_t *buf;
|
||||
size_t buf_len;
|
||||
CBB cbb;
|
||||
@@ -305,47 +282,40 @@ static bool TestCBBBasic() {
|
||||
if (!CBB_add_u8(&cbb, 1) ||
|
||||
!CBB_add_u16(&cbb, 0x203) ||
|
||||
!CBB_add_u24(&cbb, 0x40506) ||
|
||||
!CBB_add_u32(&cbb, 0x708090a) ||
|
||||
!CBB_add_bytes(&cbb, (const uint8_t*) "\x0b\x0c", 2) ||
|
||||
!CBB_add_bytes(&cbb, (const uint8_t*) "\x07\x08", 2) ||
|
||||
!CBB_finish(&cbb, &buf, &buf_len)) {
|
||||
CBB_cleanup(&cbb);
|
||||
return false;
|
||||
}
|
||||
|
||||
bssl::UniquePtr<uint8_t> scoper(buf);
|
||||
ScopedOpenSSLBytes scoper(buf);
|
||||
return buf_len == sizeof(kExpected) && memcmp(buf, kExpected, buf_len) == 0;
|
||||
}
|
||||
|
||||
static bool TestCBBFixed() {
|
||||
ScopedCBB cbb;
|
||||
CBB cbb;
|
||||
uint8_t buf[1];
|
||||
uint8_t *out_buf;
|
||||
size_t out_size;
|
||||
|
||||
if (!CBB_init_fixed(cbb.get(), NULL, 0) ||
|
||||
!CBB_finish(cbb.get(), &out_buf, &out_size) ||
|
||||
if (!CBB_init_fixed(&cbb, NULL, 0) ||
|
||||
CBB_add_u8(&cbb, 1) ||
|
||||
!CBB_finish(&cbb, &out_buf, &out_size) ||
|
||||
out_buf != NULL ||
|
||||
out_size != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cbb.Reset();
|
||||
if (!CBB_init_fixed(cbb.get(), buf, 1) ||
|
||||
!CBB_add_u8(cbb.get(), 1) ||
|
||||
!CBB_finish(cbb.get(), &out_buf, &out_size) ||
|
||||
if (!CBB_init_fixed(&cbb, buf, 1) ||
|
||||
!CBB_add_u8(&cbb, 1) ||
|
||||
CBB_add_u8(&cbb, 2) ||
|
||||
!CBB_finish(&cbb, &out_buf, &out_size) ||
|
||||
out_buf != buf ||
|
||||
out_size != 1 ||
|
||||
buf[0] != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cbb.Reset();
|
||||
if (!CBB_init_fixed(cbb.get(), buf, 1) ||
|
||||
!CBB_add_u8(cbb.get(), 1) ||
|
||||
CBB_add_u8(cbb.get(), 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -363,7 +333,7 @@ static bool TestCBBFinishChild() {
|
||||
CBB_cleanup(&cbb);
|
||||
return false;
|
||||
}
|
||||
bssl::UniquePtr<uint8_t> scoper(out_buf);
|
||||
ScopedOpenSSLBytes scoper(out_buf);
|
||||
return out_size == 1 && out_buf[0] == 0;
|
||||
}
|
||||
|
||||
@@ -396,7 +366,7 @@ static bool TestCBBPrefixed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bssl::UniquePtr<uint8_t> scoper(buf);
|
||||
ScopedOpenSSLBytes scoper(buf);
|
||||
return buf_len == sizeof(kExpected) && memcmp(buf, kExpected, buf_len) == 0;
|
||||
}
|
||||
|
||||
@@ -436,7 +406,7 @@ static bool TestCBBDiscardChild() {
|
||||
if (!CBB_finish(cbb.get(), &buf, &buf_len)) {
|
||||
return false;
|
||||
}
|
||||
bssl::UniquePtr<uint8_t> scoper(buf);
|
||||
ScopedOpenSSLBytes scoper(buf);
|
||||
|
||||
static const uint8_t kExpected[] = {
|
||||
0xaa,
|
||||
@@ -482,7 +452,7 @@ static bool TestCBBMisuse() {
|
||||
CBB_cleanup(&cbb);
|
||||
return false;
|
||||
}
|
||||
bssl::UniquePtr<uint8_t> scoper(buf);
|
||||
ScopedOpenSSLBytes scoper(buf);
|
||||
|
||||
if (buf_len != 3 ||
|
||||
memcmp(buf, "\x01\x01\x02", 3) != 0) {
|
||||
@@ -506,7 +476,7 @@ static bool TestCBBASN1() {
|
||||
CBB_cleanup(&cbb);
|
||||
return false;
|
||||
}
|
||||
bssl::UniquePtr<uint8_t> scoper(buf);
|
||||
ScopedOpenSSLBytes scoper(buf);
|
||||
|
||||
if (buf_len != sizeof(kExpected) || memcmp(buf, kExpected, buf_len) != 0) {
|
||||
return false;
|
||||
@@ -581,7 +551,7 @@ static bool DoBerConvert(const char *name,
|
||||
fprintf(stderr, "%s: CBS_asn1_ber_to_der failed.\n", name);
|
||||
return false;
|
||||
}
|
||||
bssl::UniquePtr<uint8_t> scoper(out);
|
||||
ScopedOpenSSLBytes scoper(out);
|
||||
|
||||
if (out == NULL) {
|
||||
if (ber_len != der_len ||
|
||||
@@ -694,7 +664,7 @@ static bool TestImplicitString() {
|
||||
int ok = CBS_get_asn1_implicit_string(&in, &out, &storage,
|
||||
CBS_ASN1_CONTEXT_SPECIFIC | 0,
|
||||
CBS_ASN1_OCTETSTRING);
|
||||
bssl::UniquePtr<uint8_t> scoper(storage);
|
||||
ScopedOpenSSLBytes scoper(storage);
|
||||
|
||||
if (static_cast<bool>(ok) != test.ok) {
|
||||
fprintf(stderr, "CBS_get_asn1_implicit_string unexpectedly %s\n",
|
||||
@@ -749,7 +719,8 @@ static const ASN1InvalidUint64Test kASN1InvalidUint64Tests[] = {
|
||||
};
|
||||
|
||||
static bool TestASN1Uint64() {
|
||||
for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kASN1Uint64Tests); i++) {
|
||||
for (size_t i = 0; i < sizeof(kASN1Uint64Tests) / sizeof(kASN1Uint64Tests[0]);
|
||||
i++) {
|
||||
const ASN1Uint64Test *test = &kASN1Uint64Tests[i];
|
||||
CBS cbs;
|
||||
uint64_t value;
|
||||
@@ -772,13 +743,15 @@ static bool TestASN1Uint64() {
|
||||
CBB_cleanup(&cbb);
|
||||
return false;
|
||||
}
|
||||
bssl::UniquePtr<uint8_t> scoper(out);
|
||||
ScopedOpenSSLBytes scoper(out);
|
||||
if (len != test->encoding_len || memcmp(out, test->encoding, len) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kASN1InvalidUint64Tests); i++) {
|
||||
for (size_t i = 0;
|
||||
i < sizeof(kASN1InvalidUint64Tests) / sizeof(kASN1InvalidUint64Tests[0]);
|
||||
i++) {
|
||||
const ASN1InvalidUint64Test *test = &kASN1InvalidUint64Tests[i];
|
||||
CBS cbs;
|
||||
uint64_t value;
|
||||
@@ -807,12 +780,7 @@ static bool TestCBBReserve() {
|
||||
ScopedCBB cbb;
|
||||
if (!CBB_init_fixed(cbb.get(), buf, sizeof(buf)) ||
|
||||
// Too large.
|
||||
CBB_reserve(cbb.get(), &ptr, 11)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cbb.Reset();
|
||||
if (!CBB_init_fixed(cbb.get(), buf, sizeof(buf)) ||
|
||||
CBB_reserve(cbb.get(), &ptr, 11) ||
|
||||
// Successfully reserve the entire space.
|
||||
!CBB_reserve(cbb.get(), &ptr, 10) ||
|
||||
ptr != buf ||
|
||||
@@ -825,72 +793,7 @@ static bool TestCBBReserve() {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool TestStickyError() {
|
||||
// Write an input that exceeds the limit for its length prefix.
|
||||
ScopedCBB cbb;
|
||||
CBB child;
|
||||
static const uint8_t kZeros[256] = {0};
|
||||
if (!CBB_init(cbb.get(), 0) ||
|
||||
!CBB_add_u8_length_prefixed(cbb.get(), &child) ||
|
||||
!CBB_add_bytes(&child, kZeros, sizeof(kZeros))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CBB_flush(cbb.get())) {
|
||||
fprintf(stderr, "CBB_flush unexpectedly succeeded.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// All future operations should fail.
|
||||
uint8_t *ptr;
|
||||
size_t len;
|
||||
if (CBB_add_u8(cbb.get(), 0) ||
|
||||
CBB_finish(cbb.get(), &ptr, &len)) {
|
||||
fprintf(stderr, "Future operations unexpectedly succeeded.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write an input that cannot fit in a fixed CBB.
|
||||
cbb.Reset();
|
||||
uint8_t buf;
|
||||
if (!CBB_init_fixed(cbb.get(), &buf, 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CBB_add_bytes(cbb.get(), kZeros, sizeof(kZeros))) {
|
||||
fprintf(stderr, "CBB_add_bytes unexpectedly succeeded.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// All future operations should fail.
|
||||
if (CBB_add_u8(cbb.get(), 0) ||
|
||||
CBB_finish(cbb.get(), &ptr, &len)) {
|
||||
fprintf(stderr, "Future operations unexpectedly succeeded.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write a u32 that cannot fit in a u24.
|
||||
cbb.Reset();
|
||||
if (!CBB_init(cbb.get(), 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CBB_add_u24(cbb.get(), 1u << 24)) {
|
||||
fprintf(stderr, "CBB_add_u24 unexpectedly succeeded.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// All future operations should fail.
|
||||
if (CBB_add_u8(cbb.get(), 0) ||
|
||||
CBB_finish(cbb.get(), &ptr, &len)) {
|
||||
fprintf(stderr, "Future operations unexpectedly succeeded.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int Main() {
|
||||
int main(void) {
|
||||
CRYPTO_library_init();
|
||||
|
||||
if (!TestSkip() ||
|
||||
@@ -910,17 +813,10 @@ static int Main() {
|
||||
!TestASN1Uint64() ||
|
||||
!TestGetOptionalASN1Bool() ||
|
||||
!TestZero() ||
|
||||
!TestCBBReserve() ||
|
||||
!TestStickyError()) {
|
||||
!TestCBBReserve()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("PASS\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace bssl
|
||||
|
||||
int main() {
|
||||
return bssl::Main();
|
||||
}
|
||||
|
||||
+22
-50
@@ -37,7 +37,6 @@ static int cbb_init(CBB *cbb, uint8_t *buf, size_t cap) {
|
||||
base->len = 0;
|
||||
base->cap = cap;
|
||||
base->can_resize = 1;
|
||||
base->error = 0;
|
||||
|
||||
cbb->base = base;
|
||||
cbb->is_top_level = 1;
|
||||
@@ -96,7 +95,7 @@ static int cbb_buffer_reserve(struct cbb_buffer_st *base, uint8_t **out,
|
||||
newlen = base->len + len;
|
||||
if (newlen < base->len) {
|
||||
/* Overflow */
|
||||
goto err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (newlen > base->cap) {
|
||||
@@ -104,7 +103,7 @@ static int cbb_buffer_reserve(struct cbb_buffer_st *base, uint8_t **out,
|
||||
uint8_t *newbuf;
|
||||
|
||||
if (!base->can_resize) {
|
||||
goto err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (newcap < base->cap || newcap < newlen) {
|
||||
@@ -112,7 +111,7 @@ static int cbb_buffer_reserve(struct cbb_buffer_st *base, uint8_t **out,
|
||||
}
|
||||
newbuf = OPENSSL_realloc(base->buf, newcap);
|
||||
if (newbuf == NULL) {
|
||||
goto err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
base->buf = newbuf;
|
||||
@@ -124,10 +123,6 @@ static int cbb_buffer_reserve(struct cbb_buffer_st *base, uint8_t **out,
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
err:
|
||||
base->error = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cbb_buffer_add(struct cbb_buffer_st *base, uint8_t **out,
|
||||
@@ -142,25 +137,20 @@ static int cbb_buffer_add(struct cbb_buffer_st *base, uint8_t **out,
|
||||
|
||||
static int cbb_buffer_add_u(struct cbb_buffer_st *base, uint32_t v,
|
||||
size_t len_len) {
|
||||
uint8_t *buf;
|
||||
size_t i;
|
||||
|
||||
if (len_len == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t *buf;
|
||||
if (!cbb_buffer_add(base, &buf, len_len)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (size_t i = len_len - 1; i < len_len; i--) {
|
||||
for (i = len_len - 1; i < len_len; i--) {
|
||||
buf[i] = v;
|
||||
v >>= 8;
|
||||
}
|
||||
|
||||
if (v != 0) {
|
||||
base->error = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -195,10 +185,7 @@ int CBB_finish(CBB *cbb, uint8_t **out_data, size_t *out_len) {
|
||||
int CBB_flush(CBB *cbb) {
|
||||
size_t child_start, i, len;
|
||||
|
||||
/* If |cbb->base| has hit an error, the buffer is in an undefined state, so
|
||||
* fail all following calls. In particular, |cbb->child| may point to invalid
|
||||
* memory. */
|
||||
if (cbb->base == NULL || cbb->base->error) {
|
||||
if (cbb->base == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -211,7 +198,7 @@ int CBB_flush(CBB *cbb) {
|
||||
if (!CBB_flush(cbb->child) ||
|
||||
child_start < cbb->child->offset ||
|
||||
cbb->base->len < child_start) {
|
||||
goto err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = cbb->base->len - child_start;
|
||||
@@ -220,14 +207,14 @@ int CBB_flush(CBB *cbb) {
|
||||
/* For ASN.1 we assume that we'll only need a single byte for the length.
|
||||
* If that turned out to be incorrect, we have to move the contents along
|
||||
* in order to make space. */
|
||||
uint8_t len_len;
|
||||
size_t len_len;
|
||||
uint8_t initial_length_byte;
|
||||
|
||||
assert (cbb->child->pending_len_len == 1);
|
||||
|
||||
if (len > 0xfffffffe) {
|
||||
/* Too large. */
|
||||
goto err;
|
||||
return 0;
|
||||
} else if (len > 0xffffff) {
|
||||
len_len = 5;
|
||||
initial_length_byte = 0x80 | 4;
|
||||
@@ -242,7 +229,7 @@ int CBB_flush(CBB *cbb) {
|
||||
initial_length_byte = 0x80 | 1;
|
||||
} else {
|
||||
len_len = 1;
|
||||
initial_length_byte = (uint8_t)len;
|
||||
initial_length_byte = len;
|
||||
len = 0;
|
||||
}
|
||||
|
||||
@@ -250,7 +237,7 @@ int CBB_flush(CBB *cbb) {
|
||||
/* We need to move the contents along in order to make space. */
|
||||
size_t extra_bytes = len_len - 1;
|
||||
if (!cbb_buffer_add(cbb->base, NULL, extra_bytes)) {
|
||||
goto err;
|
||||
return 0;
|
||||
}
|
||||
memmove(cbb->base->buf + child_start + extra_bytes,
|
||||
cbb->base->buf + child_start, len);
|
||||
@@ -261,21 +248,17 @@ int CBB_flush(CBB *cbb) {
|
||||
|
||||
for (i = cbb->child->pending_len_len - 1; i < cbb->child->pending_len_len;
|
||||
i--) {
|
||||
cbb->base->buf[cbb->child->offset + i] = (uint8_t)len;
|
||||
cbb->base->buf[cbb->child->offset + i] = len;
|
||||
len >>= 8;
|
||||
}
|
||||
if (len != 0) {
|
||||
goto err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
cbb->child->base = NULL;
|
||||
cbb->child = NULL;
|
||||
|
||||
return 1;
|
||||
|
||||
err:
|
||||
cbb->base->error = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint8_t *CBB_data(const CBB *cbb) {
|
||||
@@ -291,7 +274,7 @@ size_t CBB_len(const CBB *cbb) {
|
||||
}
|
||||
|
||||
static int cbb_add_length_prefixed(CBB *cbb, CBB *out_contents,
|
||||
uint8_t len_len) {
|
||||
size_t len_len) {
|
||||
uint8_t *prefix_bytes;
|
||||
|
||||
if (!CBB_flush(cbb)) {
|
||||
@@ -326,18 +309,14 @@ int CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents) {
|
||||
return cbb_add_length_prefixed(cbb, out_contents, 3);
|
||||
}
|
||||
|
||||
int CBB_add_asn1(CBB *cbb, CBB *out_contents, unsigned tag) {
|
||||
if (tag > 0xff ||
|
||||
(tag & 0x1f) == 0x1f) {
|
||||
/* Long form identifier octets are not supported. Further, all current valid
|
||||
* tag serializations are 8 bits. */
|
||||
cbb->base->error = 1;
|
||||
int CBB_add_asn1(CBB *cbb, CBB *out_contents, uint8_t tag) {
|
||||
if ((tag & 0x1f) == 0x1f) {
|
||||
/* Long form identifier octets are not supported. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!CBB_flush(cbb) ||
|
||||
/* |tag|'s representation matches the DER encoding. */
|
||||
!CBB_add_u8(cbb, (uint8_t)tag)) {
|
||||
!CBB_add_u8(cbb, tag)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -418,14 +397,6 @@ int CBB_add_u24(CBB *cbb, uint32_t value) {
|
||||
return cbb_buffer_add_u(cbb->base, value, 3);
|
||||
}
|
||||
|
||||
int CBB_add_u32(CBB *cbb, uint32_t value) {
|
||||
if (!CBB_flush(cbb)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return cbb_buffer_add_u(cbb->base, value, 4);
|
||||
}
|
||||
|
||||
void CBB_discard_child(CBB *cbb) {
|
||||
if (cbb->child == NULL) {
|
||||
return;
|
||||
@@ -439,13 +410,14 @@ void CBB_discard_child(CBB *cbb) {
|
||||
|
||||
int CBB_add_asn1_uint64(CBB *cbb, uint64_t value) {
|
||||
CBB child;
|
||||
size_t i;
|
||||
int started = 0;
|
||||
|
||||
if (!CBB_add_asn1(cbb, &child, CBS_ASN1_INTEGER)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
for (i = 0; i < 8; i++) {
|
||||
uint8_t byte = (value >> 8*(7-i)) & 0xff;
|
||||
if (!started) {
|
||||
if (byte == 0) {
|
||||
|
||||
+4
-42
@@ -88,12 +88,13 @@ int CBS_mem_equal(const CBS *cbs, const uint8_t *data, size_t len) {
|
||||
|
||||
static int cbs_get_u(CBS *cbs, uint32_t *out, size_t len) {
|
||||
uint32_t result = 0;
|
||||
size_t i;
|
||||
const uint8_t *data;
|
||||
|
||||
if (!cbs_get(cbs, &data, len)) {
|
||||
return 0;
|
||||
}
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
for (i = 0; i < len; i++) {
|
||||
result <<= 8;
|
||||
result |= data[i];
|
||||
}
|
||||
@@ -127,15 +128,6 @@ int CBS_get_u32(CBS *cbs, uint32_t *out) {
|
||||
return cbs_get_u(cbs, out, 4);
|
||||
}
|
||||
|
||||
int CBS_get_last_u8(CBS *cbs, uint8_t *out) {
|
||||
if (cbs->len == 0) {
|
||||
return 0;
|
||||
}
|
||||
*out = cbs->data[cbs->len - 1];
|
||||
cbs->len--;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CBS_get_bytes(CBS *cbs, CBS *out, size_t len) {
|
||||
const uint8_t *v;
|
||||
if (!cbs_get(cbs, &v, len)) {
|
||||
@@ -189,14 +181,8 @@ static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ITU-T X.690 section 8.1.2.3 specifies the format for identifiers with a tag
|
||||
* number no greater than 30.
|
||||
*
|
||||
* If the number portion is 31 (0x1f, the largest value that fits in the
|
||||
* allotted bits), then the tag is more than one byte long and the
|
||||
* continuation bytes contain the tag number. This parser only supports tag
|
||||
* numbers less than 31 (and thus single-byte tags). */
|
||||
if ((tag & 0x1f) == 0x1f) {
|
||||
/* Long form tags are not supported. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -205,8 +191,6 @@ static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
|
||||
}
|
||||
|
||||
size_t len;
|
||||
/* The format for the length encoding is specified in ITU-T X.690 section
|
||||
* 8.1.3. */
|
||||
if ((length_byte & 0x80) == 0) {
|
||||
/* Short form length. */
|
||||
len = ((size_t) length_byte) + 2;
|
||||
@@ -214,9 +198,7 @@ static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
|
||||
*out_header_len = 2;
|
||||
}
|
||||
} else {
|
||||
/* The high bit indicate that this is the long form, while the next 7 bits
|
||||
* encode the number of subsequent octets used to encode the length (ITU-T
|
||||
* X.690 clause 8.1.3.5.b). */
|
||||
/* Long form length. */
|
||||
const size_t num_bytes = length_byte & 0x7f;
|
||||
uint32_t len32;
|
||||
|
||||
@@ -228,18 +210,12 @@ static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
|
||||
return CBS_get_bytes(cbs, out, 2);
|
||||
}
|
||||
|
||||
/* ITU-T X.690 clause 8.1.3.5.c specifies that the value 0xff shall not be
|
||||
* used as the first byte of the length. If this parser encounters that
|
||||
* value, num_bytes will be parsed as 127, which will fail the check below.
|
||||
*/
|
||||
if (num_bytes == 0 || num_bytes > 4) {
|
||||
return 0;
|
||||
}
|
||||
if (!cbs_get_u(&header, &len32, num_bytes)) {
|
||||
return 0;
|
||||
}
|
||||
/* ITU-T X.690 section 10.1 (DER length forms) requires encoding the length
|
||||
* with the minimum number of octets. */
|
||||
if (len32 < 128) {
|
||||
/* Length should have used short-form encoding. */
|
||||
return 0;
|
||||
@@ -262,20 +238,6 @@ static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
|
||||
return CBS_get_bytes(cbs, out, len);
|
||||
}
|
||||
|
||||
int CBS_get_any_asn1(CBS *cbs, CBS *out, unsigned *out_tag) {
|
||||
size_t header_len;
|
||||
if (!CBS_get_any_asn1_element(cbs, out, out_tag, &header_len)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!CBS_skip(out, header_len)) {
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CBS_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
|
||||
size_t *out_header_len) {
|
||||
return cbs_get_any_asn1_element(cbs, out, out_tag, out_header_len,
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
# 20-25% worse;
|
||||
|
||||
$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;
|
||||
|
||||
@@ -1124,4 +1124,3 @@ foreach (split("\n",$code)) {
|
||||
|
||||
print $_,"\n";
|
||||
}
|
||||
close STDOUT; # flush
|
||||
|
||||
@@ -19,13 +19,13 @@
|
||||
# P4 18.6/+84%
|
||||
# Core2 9.56/+89% 4.83
|
||||
# Westmere 9.50/+45% 3.35
|
||||
# Sandy Bridge 10.5/+47% 3.20
|
||||
# Haswell 8.15/+50% 2.83
|
||||
# Silvermont 17.4/+36% 8.35
|
||||
# Sandy Bridge 10.7/+47% 3.24
|
||||
# Haswell 8.22/+50% 2.89
|
||||
# Silvermont 17.8/+36% 8.53
|
||||
# Sledgehammer 10.2/+54%
|
||||
# Bulldozer 13.4/+50% 4.38(*)
|
||||
# Bulldozer 13.5/+50% 4.39(*)
|
||||
#
|
||||
# (*) Bulldozer actually executes 4xXOP code path that delivers 3.55;
|
||||
# (*) Bulldozer actually executes 4xXOP code path that delivers 3.50;
|
||||
#
|
||||
# Modified from upstream OpenSSL to remove the XOP code.
|
||||
|
||||
@@ -33,9 +33,6 @@ $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
push(@INC,"${dir}","${dir}../../perlasm");
|
||||
require "x86asm.pl";
|
||||
|
||||
$output=pop;
|
||||
open STDOUT,">$output";
|
||||
|
||||
&asm_init($ARGV[0],"chacha-x86.pl",$ARGV[$#ARGV] eq "386");
|
||||
|
||||
$xmm=$ymm=0;
|
||||
@@ -227,18 +224,20 @@ if ($xmm) {
|
||||
|
||||
&xor ($a, &DWP(4*0,$b)); # xor with input
|
||||
&xor ($b_,&DWP(4*4,$b));
|
||||
&mov (&DWP(4*0,"esp"),$a);
|
||||
&mov (&DWP(4*0,"esp"),$a); # off-load for later write
|
||||
&mov ($a,&wparam(0)); # load output pointer
|
||||
&xor ($c, &DWP(4*8,$b));
|
||||
&xor ($c_,&DWP(4*9,$b));
|
||||
&xor ($d, &DWP(4*12,$b));
|
||||
&xor ($d_,&DWP(4*14,$b));
|
||||
&mov (&DWP(4*4,$a),$b_); # write output
|
||||
&mov (&DWP(4*8,$a),$c);
|
||||
&mov (&DWP(4*9,$a),$c_);
|
||||
&mov (&DWP(4*12,$a),$d);
|
||||
&mov (&DWP(4*14,$a),$d_);
|
||||
&mov (&DWP(4*4,"esp"),$b_);
|
||||
&mov ($b_,&DWP(4*0,"esp"));
|
||||
&mov (&DWP(4*8,"esp"),$c);
|
||||
&mov (&DWP(4*9,"esp"),$c_);
|
||||
&mov (&DWP(4*12,"esp"),$d);
|
||||
&mov (&DWP(4*14,"esp"),$d_);
|
||||
|
||||
&mov (&DWP(4*0,$a),$b_); # write output in order
|
||||
&mov ($b_,&DWP(4*1,"esp"));
|
||||
&mov ($c, &DWP(4*2,"esp"));
|
||||
&mov ($c_,&DWP(4*3,"esp"));
|
||||
@@ -255,35 +254,45 @@ if ($xmm) {
|
||||
&xor ($d, &DWP(4*5,$b));
|
||||
&xor ($d_,&DWP(4*6,$b));
|
||||
&mov (&DWP(4*1,$a),$b_);
|
||||
&mov ($b_,&DWP(4*4,"esp"));
|
||||
&mov (&DWP(4*2,$a),$c);
|
||||
&mov (&DWP(4*3,$a),$c_);
|
||||
&mov (&DWP(4*4,$a),$b_);
|
||||
&mov (&DWP(4*5,$a),$d);
|
||||
&mov (&DWP(4*6,$a),$d_);
|
||||
|
||||
&mov ($b_,&DWP(4*7,"esp"));
|
||||
&mov ($c, &DWP(4*10,"esp"));
|
||||
&mov ($c,&DWP(4*7,"esp"));
|
||||
&mov ($d,&DWP(4*8,"esp"));
|
||||
&mov ($d_,&DWP(4*9,"esp"));
|
||||
&add ($c,&DWP(64+4*7,"esp"));
|
||||
&mov ($b_, &DWP(4*10,"esp"));
|
||||
&xor ($c,&DWP(4*7,$b));
|
||||
&mov ($c_,&DWP(4*11,"esp"));
|
||||
&mov (&DWP(4*7,$a),$c);
|
||||
&mov (&DWP(4*8,$a),$d);
|
||||
&mov (&DWP(4*9,$a),$d_);
|
||||
|
||||
&add ($b_, &DWP(64+4*10,"esp"));
|
||||
&add ($c_,&DWP(64+4*11,"esp"));
|
||||
&xor ($b_, &DWP(4*10,$b));
|
||||
&xor ($c_,&DWP(4*11,$b));
|
||||
&mov (&DWP(4*10,$a),$b_);
|
||||
&mov (&DWP(4*11,$a),$c_);
|
||||
|
||||
&mov ($c,&DWP(4*12,"esp"));
|
||||
&mov ($c_,&DWP(4*14,"esp"));
|
||||
&mov ($d, &DWP(4*13,"esp"));
|
||||
&mov ($d_,&DWP(4*15,"esp"));
|
||||
&add ($b_,&DWP(64+4*7,"esp"));
|
||||
&add ($c, &DWP(64+4*10,"esp"));
|
||||
&add ($c_,&DWP(64+4*11,"esp"));
|
||||
&add ($d, &DWP(64+4*13,"esp"));
|
||||
&add ($d_,&DWP(64+4*15,"esp"));
|
||||
&xor ($b_,&DWP(4*7,$b));
|
||||
&xor ($c, &DWP(4*10,$b));
|
||||
&xor ($c_,&DWP(4*11,$b));
|
||||
&xor ($d, &DWP(4*13,$b));
|
||||
&xor ($d_,&DWP(4*15,$b));
|
||||
&lea ($b,&DWP(4*16,$b));
|
||||
&mov (&DWP(4*7,$a),$b_);
|
||||
&mov ($b_,&DWP(4*0,"esp"));
|
||||
&mov (&DWP(4*10,$a),$c);
|
||||
&mov (&DWP(4*12,$a),$c);
|
||||
&mov ($c,&wparam(2)); # len
|
||||
&mov (&DWP(4*11,$a),$c_);
|
||||
&mov (&DWP(4*13,$a),$d);
|
||||
&mov (&DWP(4*14,$a),$c_);
|
||||
&mov (&DWP(4*15,$a),$d_);
|
||||
&mov (&DWP(4*0,$a),$b_);
|
||||
&lea ($a,&DWP(4*16,$a));
|
||||
&sub ($c,64);
|
||||
&jnz (&label("outer_loop"));
|
||||
@@ -558,12 +567,12 @@ my ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_-1)&3),($ai,$bi,$ci,$di)); # previous
|
||||
|
||||
my ($xa0,$xa1,$xa2,$xa3,$xt0,$xt1,$xt2,$xt3)=map("xmm$_",(0..7));
|
||||
|
||||
#&movdqa ($xa0,&QWP(16*0-128,"ebx")); # it's there
|
||||
&movdqa ($xa1,&QWP(16*1-128,"ebx"));
|
||||
&movdqa ($xa2,&QWP(16*2-128,"ebx"));
|
||||
&movdqa ($xa3,&QWP(16*3-128,"ebx"));
|
||||
|
||||
for($i=0;$i<256;$i+=64) {
|
||||
#&movdqa ($xa0,&QWP($i+16*0-128,"ebx")); # it's there
|
||||
&movdqa ($xa1,&QWP($i+16*1-128,"ebx"));
|
||||
&movdqa ($xa2,&QWP($i+16*2-128,"ebx"));
|
||||
&movdqa ($xa3,&QWP($i+16*3-128,"ebx"));
|
||||
|
||||
&paddd ($xa0,&QWP($i+16*0-128,"ebp")); # accumulate key material
|
||||
&paddd ($xa1,&QWP($i+16*1-128,"ebp"));
|
||||
&paddd ($xa2,&QWP($i+16*2-128,"ebp"));
|
||||
@@ -584,25 +593,29 @@ my ($ap,$bp,$cp,$dp)=map(($_&~3)+(($_-1)&3),($ai,$bi,$ci,$di)); # previous
|
||||
|
||||
#($xa2,$xt2)=($xt2,$xa2);
|
||||
|
||||
&movdqu ($xt0,&QWP(64*0-128,$inp)); # load input
|
||||
&movdqu ($xt1,&QWP(64*1-128,$inp));
|
||||
&movdqu ($xa2,&QWP(64*2-128,$inp));
|
||||
&movdqu ($xt3,&QWP(64*3-128,$inp));
|
||||
&lea ($inp,&QWP($i<192?16:(64*4-16*3),$inp));
|
||||
&pxor ($xt0,$xa0);
|
||||
&movdqa (&QWP($i+16*0-128,"ebx"),$xa0);
|
||||
&movdqa ($xa0,&QWP($i+16*4-128,"ebx")) if ($i<192);
|
||||
&pxor ($xt1,$xa1);
|
||||
&movdqa ($xa1,&QWP($i+16*5-128,"ebx")) if ($i<192);
|
||||
&pxor ($xt2,$xa2);
|
||||
&movdqa ($xa2,&QWP($i+16*6-128,"ebx")) if ($i<192);
|
||||
&pxor ($xt3,$xa3);
|
||||
&movdqa ($xa3,&QWP($i+16*7-128,"ebx")) if ($i<192);
|
||||
&movdqu (&QWP(64*0-128,$out),$xt0); # store output
|
||||
&movdqu (&QWP(64*1-128,$out),$xt1);
|
||||
&movdqu (&QWP(64*2-128,$out),$xt2);
|
||||
&movdqu (&QWP(64*3-128,$out),$xt3);
|
||||
&lea ($out,&QWP($i<192?16:(64*4-16*3),$out));
|
||||
&movdqa (&QWP($i+16*1-128,"ebx"),$xa1);
|
||||
&movdqa (&QWP($i+16*2-128,"ebx"),$xt2);
|
||||
&movdqa (&QWP($i+16*3-128,"ebx"),$xa3);
|
||||
}
|
||||
for($i=0;$i<256;$i+=64) {
|
||||
my $j = 16*($i/64);
|
||||
&movdqu ($xa0,&QWP($i+16*0-128,$inp)); # load input
|
||||
&movdqu ($xa1,&QWP($i+16*1-128,$inp));
|
||||
&movdqu ($xa2,&QWP($i+16*2-128,$inp));
|
||||
&movdqu ($xa3,&QWP($i+16*3-128,$inp));
|
||||
&pxor ($xa0,&QWP($j+64*0-128,"ebx"));
|
||||
&pxor ($xa1,&QWP($j+64*1-128,"ebx"));
|
||||
&pxor ($xa2,&QWP($j+64*2-128,"ebx"));
|
||||
&pxor ($xa3,&QWP($j+64*3-128,"ebx"));
|
||||
&movdqu (&QWP($i+16*0-128,$out),$xa0); # write output
|
||||
&movdqu (&QWP($i+16*1-128,$out),$xa1);
|
||||
&movdqu (&QWP($i+16*2-128,$out),$xa2);
|
||||
&movdqu (&QWP($i+16*3-128,$out),$xa3);
|
||||
}
|
||||
&lea ($inp,&DWP(256,$inp));
|
||||
&lea ($out,&DWP(256,$out));
|
||||
&sub ($len,64*4);
|
||||
&jnc (&label("outer_loop"));
|
||||
|
||||
@@ -754,5 +767,3 @@ sub SSSE3ROUND { # critical path is 20 "SIMD ticks" per round
|
||||
&asciz ("ChaCha20 for x86, CRYPTOGAMS by <appro\@openssl.org>");
|
||||
|
||||
&asm_finish();
|
||||
|
||||
close STDOUT;
|
||||
|
||||
+11
-14
@@ -16,13 +16,10 @@
|
||||
|
||||
#include <openssl/chacha.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/cpu.h>
|
||||
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
#define U8TO32_LITTLE(p) \
|
||||
(((uint32_t)((p)[0])) | ((uint32_t)((p)[1]) << 8) | \
|
||||
@@ -39,9 +36,8 @@ void ChaCha20_ctr32(uint8_t *out, const uint8_t *in, size_t in_len,
|
||||
void CRYPTO_chacha_20(uint8_t *out, const uint8_t *in, size_t in_len,
|
||||
const uint8_t key[32], const uint8_t nonce[12],
|
||||
uint32_t counter) {
|
||||
assert(!buffers_alias(out, in_len, in, in_len) || in == out);
|
||||
|
||||
uint32_t counter_nonce[4]; counter_nonce[0] = counter;
|
||||
uint32_t counter_nonce[4];
|
||||
counter_nonce[0] = counter;
|
||||
counter_nonce[1] = U8TO32_LITTLE(nonce + 0);
|
||||
counter_nonce[2] = U8TO32_LITTLE(nonce + 4);
|
||||
counter_nonce[3] = U8TO32_LITTLE(nonce + 8);
|
||||
@@ -74,6 +70,9 @@ static const uint8_t sigma[16] = { 'e', 'x', 'p', 'a', 'n', 'd', ' ', '3',
|
||||
'2', '-', 'b', 'y', 't', 'e', ' ', 'k' };
|
||||
|
||||
#define ROTATE(v, n) (((v) << (n)) | ((v) >> (32 - (n))))
|
||||
#define XOR(v, w) ((v) ^ (w))
|
||||
#define PLUS(x, y) ((x) + (y))
|
||||
#define PLUSONE(v) (PLUS((v), 1))
|
||||
|
||||
#define U32TO8_LITTLE(p, v) \
|
||||
{ \
|
||||
@@ -84,11 +83,11 @@ static const uint8_t sigma[16] = { 'e', 'x', 'p', 'a', 'n', 'd', ' ', '3',
|
||||
}
|
||||
|
||||
/* QUARTERROUND updates a, b, c, d with a ChaCha "quarter" round. */
|
||||
#define QUARTERROUND(a, b, c, d) \
|
||||
x[a] += x[b]; x[d] = ROTATE(x[d] ^ x[a], 16); \
|
||||
x[c] += x[d]; x[b] = ROTATE(x[b] ^ x[c], 12); \
|
||||
x[a] += x[b]; x[d] = ROTATE(x[d] ^ x[a], 8); \
|
||||
x[c] += x[d]; x[b] = ROTATE(x[b] ^ x[c], 7);
|
||||
#define QUARTERROUND(a,b,c,d) \
|
||||
x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]),16); \
|
||||
x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]),12); \
|
||||
x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]), 8); \
|
||||
x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]), 7);
|
||||
|
||||
/* chacha_core performs 20 rounds of ChaCha on the input words in
|
||||
* |input| and writes the 64 output bytes to |output|. */
|
||||
@@ -109,7 +108,7 @@ static void chacha_core(uint8_t output[64], const uint32_t input[16]) {
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; ++i) {
|
||||
x[i] += input[i];
|
||||
x[i] = PLUS(x[i], input[i]);
|
||||
}
|
||||
for (i = 0; i < 16; ++i) {
|
||||
U32TO8_LITTLE(output + 4 * i, x[i]);
|
||||
@@ -119,8 +118,6 @@ static void chacha_core(uint8_t output[64], const uint32_t input[16]) {
|
||||
void CRYPTO_chacha_20(uint8_t *out, const uint8_t *in, size_t in_len,
|
||||
const uint8_t key[32], const uint8_t nonce[12],
|
||||
uint32_t counter) {
|
||||
assert(!buffers_alias(out, in_len, in, in_len) || in == out);
|
||||
|
||||
uint32_t input[16];
|
||||
uint8_t buf[64];
|
||||
size_t todo, i;
|
||||
|
||||
@@ -218,16 +218,25 @@ static bool TestChaCha20(size_t len) {
|
||||
std::unique_ptr<uint8_t[]> buf(new uint8_t[len]);
|
||||
CRYPTO_chacha_20(buf.get(), kInput, len, kKey, kNonce, kCounter);
|
||||
if (memcmp(buf.get(), kOutput, len) != 0) {
|
||||
fprintf(stderr, "Mismatch at length %zu.\n", len);
|
||||
fprintf(stderr, "Mismatch at length %u.\n", static_cast<unsigned>(len));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test in-place.
|
||||
memcpy(buf.get(), kInput, len);
|
||||
CRYPTO_chacha_20(buf.get(), buf.get(), len, kKey, kNonce, kCounter);
|
||||
if (memcmp(buf.get(), kOutput, len) != 0) {
|
||||
fprintf(stderr, "Mismatch at length %zu, in-place.\n", len);
|
||||
return false;
|
||||
// Test in-place at various offsets.
|
||||
static const size_t kOffsets[] = {
|
||||
0, 1, 2, 8, 15, 16, 17, 31, 32, 33, 63,
|
||||
64, 65, 95, 96, 97, 127, 128, 129, 255, 256, 257,
|
||||
};
|
||||
for (size_t offset : kOffsets) {
|
||||
buf.reset(new uint8_t[len + offset]);
|
||||
memcpy(buf.get() + offset, kInput, len);
|
||||
CRYPTO_chacha_20(buf.get(), buf.get() + offset, len, kKey, kNonce,
|
||||
kCounter);
|
||||
if (memcmp(buf.get(), kOutput, len) != 0) {
|
||||
fprintf(stderr, "Mismatch at length %u with in-place offset %u.\n",
|
||||
static_cast<unsigned>(len), static_cast<unsigned>(offset));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
+22
-11
@@ -20,7 +20,6 @@
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
size_t EVP_AEAD_key_length(const EVP_AEAD *aead) { return aead->key_len; }
|
||||
@@ -81,15 +80,21 @@ void EVP_AEAD_CTX_cleanup(EVP_AEAD_CTX *ctx) {
|
||||
ctx->aead = NULL;
|
||||
}
|
||||
|
||||
/* check_alias returns 1 if |out| is compatible with |in| and 0 otherwise. If
|
||||
* |in| and |out| alias, we require that |in| == |out|. */
|
||||
static int check_alias(const uint8_t *in, size_t in_len, const uint8_t *out,
|
||||
size_t out_len) {
|
||||
if (!buffers_alias(in, in_len, out, out_len)) {
|
||||
/* check_alias returns 0 if |out| points within the buffer determined by |in|
|
||||
* and |in_len| and 1 otherwise.
|
||||
*
|
||||
* When processing, there's only an issue if |out| points within in[:in_len]
|
||||
* and isn't equal to |in|. If that's the case then writing the output will
|
||||
* stomp input that hasn't been read yet.
|
||||
*
|
||||
* This function checks for that case. */
|
||||
static int check_alias(const uint8_t *in, size_t in_len, const uint8_t *out) {
|
||||
if (out <= in) {
|
||||
return 1;
|
||||
} else if (in + in_len <= out) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return in == out;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int EVP_AEAD_CTX_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len,
|
||||
@@ -103,7 +108,7 @@ int EVP_AEAD_CTX_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len,
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!check_alias(in, in_len, out, max_out_len)) {
|
||||
if (!check_alias(in, in_len, out)) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT);
|
||||
goto error;
|
||||
}
|
||||
@@ -125,7 +130,7 @@ int EVP_AEAD_CTX_open(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len,
|
||||
size_t max_out_len, const uint8_t *nonce,
|
||||
size_t nonce_len, const uint8_t *in, size_t in_len,
|
||||
const uint8_t *ad, size_t ad_len) {
|
||||
if (!check_alias(in, in_len, out, max_out_len)) {
|
||||
if (!check_alias(in, in_len, out)) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT);
|
||||
goto error;
|
||||
}
|
||||
@@ -144,7 +149,13 @@ error:
|
||||
return 0;
|
||||
}
|
||||
|
||||
const EVP_AEAD *EVP_AEAD_CTX_aead(const EVP_AEAD_CTX *ctx) { return ctx->aead; }
|
||||
int EVP_AEAD_CTX_get_rc4_state(const EVP_AEAD_CTX *ctx, const RC4_KEY **out_key) {
|
||||
if (ctx->aead->get_rc4_state == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ctx->aead->get_rc4_state(ctx, out_key);
|
||||
}
|
||||
|
||||
int EVP_AEAD_CTX_get_iv(const EVP_AEAD_CTX *ctx, const uint8_t **out_iv,
|
||||
size_t *out_len) {
|
||||
|
||||
+79
-60
@@ -22,8 +22,8 @@
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "../test/file_test.h"
|
||||
#include "../test/scoped_types.h"
|
||||
|
||||
namespace bssl {
|
||||
|
||||
// This program tests an AEAD against a series of test vectors from a file,
|
||||
// using the FileTest format. As an example, here's a valid test case:
|
||||
@@ -225,65 +225,84 @@ static bool TestWithAliasedBuffers(const EVP_AEAD *aead) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test with out != in which we expect to fail.
|
||||
std::vector<uint8_t> buffer(2 + valid_encryption_len);
|
||||
uint8_t *in = buffer.data() + 1;
|
||||
uint8_t *out1 = buffer.data();
|
||||
uint8_t *out2 = buffer.data() + 2;
|
||||
// First test with out > in, which we expect to fail.
|
||||
for (auto offset : offsets) {
|
||||
if (offset == 0) {
|
||||
// Will be tested in the next loop.
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(in, kPlaintext, sizeof(kPlaintext));
|
||||
size_t out_len;
|
||||
if (EVP_AEAD_CTX_seal(ctx.get(), out1, &out_len,
|
||||
sizeof(kPlaintext) + max_overhead, nonce.data(),
|
||||
nonce_len, in, sizeof(kPlaintext), nullptr, 0) ||
|
||||
EVP_AEAD_CTX_seal(ctx.get(), out2, &out_len,
|
||||
sizeof(kPlaintext) + max_overhead, nonce.data(),
|
||||
nonce_len, in, sizeof(kPlaintext), nullptr, 0)) {
|
||||
fprintf(stderr, "EVP_AEAD_CTX_seal unexpectedly succeeded.\n");
|
||||
return false;
|
||||
}
|
||||
ERR_clear_error();
|
||||
std::vector<uint8_t> buffer(offset + valid_encryption_len);
|
||||
memcpy(buffer.data(), kPlaintext, sizeof(kPlaintext));
|
||||
uint8_t *out = buffer.data() + offset;
|
||||
|
||||
memcpy(in, valid_encryption.data(), valid_encryption_len);
|
||||
if (EVP_AEAD_CTX_open(ctx.get(), out1, &out_len, valid_encryption_len,
|
||||
nonce.data(), nonce_len, in, valid_encryption_len,
|
||||
nullptr, 0) ||
|
||||
EVP_AEAD_CTX_open(ctx.get(), out2, &out_len, valid_encryption_len,
|
||||
nonce.data(), nonce_len, in, valid_encryption_len,
|
||||
nullptr, 0)) {
|
||||
fprintf(stderr, "EVP_AEAD_CTX_open unexpectedly succeeded.\n");
|
||||
return false;
|
||||
}
|
||||
ERR_clear_error();
|
||||
size_t out_len;
|
||||
if (!EVP_AEAD_CTX_seal(ctx.get(), out, &out_len,
|
||||
sizeof(kPlaintext) + max_overhead, nonce.data(),
|
||||
nonce_len, buffer.data(), sizeof(kPlaintext),
|
||||
nullptr, 0)) {
|
||||
// We expect offsets where the output is greater than the input to fail.
|
||||
ERR_clear_error();
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"EVP_AEAD_CTX_seal unexpectedly succeeded for offset %u.\n",
|
||||
static_cast<unsigned>(offset));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test with out == in, which we expect to work.
|
||||
memcpy(in, kPlaintext, sizeof(kPlaintext));
|
||||
|
||||
if (!EVP_AEAD_CTX_seal(ctx.get(), in, &out_len,
|
||||
sizeof(kPlaintext) + max_overhead, nonce.data(),
|
||||
nonce_len, in, sizeof(kPlaintext), nullptr, 0)) {
|
||||
fprintf(stderr, "EVP_AEAD_CTX_seal failed in-place.\n");
|
||||
return false;
|
||||
memcpy(buffer.data(), valid_encryption.data(), valid_encryption_len);
|
||||
if (!EVP_AEAD_CTX_open(ctx.get(), out, &out_len, valid_encryption_len,
|
||||
nonce.data(), nonce_len, buffer.data(),
|
||||
valid_encryption_len, nullptr, 0)) {
|
||||
// We expect offsets where the output is greater than the input to fail.
|
||||
ERR_clear_error();
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"EVP_AEAD_CTX_open unexpectedly succeeded for offset %u.\n",
|
||||
static_cast<unsigned>(offset));
|
||||
ERR_print_errors_fp(stderr);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (out_len != valid_encryption_len ||
|
||||
memcmp(in, valid_encryption.data(), out_len) != 0) {
|
||||
fprintf(stderr, "EVP_AEAD_CTX_seal produced bad output in-place.\n");
|
||||
return false;
|
||||
}
|
||||
// Test with out <= in, which we expect to work.
|
||||
for (auto offset : offsets) {
|
||||
std::vector<uint8_t> buffer(offset + valid_encryption_len);
|
||||
uint8_t *const out = buffer.data();
|
||||
uint8_t *const in = buffer.data() + offset;
|
||||
memcpy(in, kPlaintext, sizeof(kPlaintext));
|
||||
|
||||
memcpy(in, valid_encryption.data(), valid_encryption_len);
|
||||
if (!EVP_AEAD_CTX_open(ctx.get(), in, &out_len, valid_encryption_len,
|
||||
nonce.data(), nonce_len, in, valid_encryption_len,
|
||||
nullptr, 0)) {
|
||||
fprintf(stderr, "EVP_AEAD_CTX_open failed in-place.\n");
|
||||
return false;
|
||||
}
|
||||
size_t out_len;
|
||||
if (!EVP_AEAD_CTX_seal(ctx.get(), out, &out_len,
|
||||
sizeof(kPlaintext) + max_overhead, nonce.data(),
|
||||
nonce_len, in, sizeof(kPlaintext), nullptr, 0)) {
|
||||
fprintf(stderr, "EVP_AEAD_CTX_seal failed for offset -%u.\n",
|
||||
static_cast<unsigned>(offset));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (out_len != sizeof(kPlaintext) ||
|
||||
memcmp(in, kPlaintext, out_len) != 0) {
|
||||
fprintf(stderr, "EVP_AEAD_CTX_open produced bad output in-place.\n");
|
||||
return false;
|
||||
if (out_len != valid_encryption_len ||
|
||||
memcmp(out, valid_encryption.data(), out_len) != 0) {
|
||||
fprintf(stderr, "EVP_AEAD_CTX_seal produced bad output for offset -%u.\n",
|
||||
static_cast<unsigned>(offset));
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(in, valid_encryption.data(), valid_encryption_len);
|
||||
if (!EVP_AEAD_CTX_open(ctx.get(), out, &out_len,
|
||||
offset + valid_encryption_len, nonce.data(),
|
||||
nonce_len, in, valid_encryption_len, nullptr, 0)) {
|
||||
fprintf(stderr, "EVP_AEAD_CTX_open failed for offset -%u.\n",
|
||||
static_cast<unsigned>(offset));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (out_len != sizeof(kPlaintext) ||
|
||||
memcmp(out, kPlaintext, out_len) != 0) {
|
||||
fprintf(stderr, "EVP_AEAD_CTX_open produced bad output for offset -%u.\n",
|
||||
static_cast<unsigned>(offset));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -304,6 +323,8 @@ static const struct KnownAEAD kAEADs[] = {
|
||||
{ "aes-256-gcm", EVP_aead_aes_256_gcm, false },
|
||||
{ "chacha20-poly1305", EVP_aead_chacha20_poly1305, false },
|
||||
{ "chacha20-poly1305-old", EVP_aead_chacha20_poly1305_old, false },
|
||||
{ "rc4-md5-tls", EVP_aead_rc4_md5_tls, true },
|
||||
{ "rc4-sha1-tls", EVP_aead_rc4_sha1_tls, true },
|
||||
{ "aes-128-cbc-sha1-tls", EVP_aead_aes_128_cbc_sha1_tls, true },
|
||||
{ "aes-128-cbc-sha1-tls-implicit-iv", EVP_aead_aes_128_cbc_sha1_tls_implicit_iv, true },
|
||||
{ "aes-128-cbc-sha256-tls", EVP_aead_aes_128_cbc_sha256_tls, true },
|
||||
@@ -313,15 +334,19 @@ static const struct KnownAEAD kAEADs[] = {
|
||||
{ "aes-256-cbc-sha384-tls", EVP_aead_aes_256_cbc_sha384_tls, true },
|
||||
{ "des-ede3-cbc-sha1-tls", EVP_aead_des_ede3_cbc_sha1_tls, true },
|
||||
{ "des-ede3-cbc-sha1-tls-implicit-iv", EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv, true },
|
||||
{ "rc4-md5-ssl3", EVP_aead_rc4_md5_ssl3, true },
|
||||
{ "rc4-sha1-ssl3", EVP_aead_rc4_sha1_ssl3, true },
|
||||
{ "aes-128-cbc-sha1-ssl3", EVP_aead_aes_128_cbc_sha1_ssl3, true },
|
||||
{ "aes-256-cbc-sha1-ssl3", EVP_aead_aes_256_cbc_sha1_ssl3, true },
|
||||
{ "des-ede3-cbc-sha1-ssl3", EVP_aead_des_ede3_cbc_sha1_ssl3, true },
|
||||
{ "aes-128-key-wrap", EVP_aead_aes_128_key_wrap, true },
|
||||
{ "aes-256-key-wrap", EVP_aead_aes_256_key_wrap, true },
|
||||
{ "aes-128-ctr-hmac-sha256", EVP_aead_aes_128_ctr_hmac_sha256, false },
|
||||
{ "aes-256-ctr-hmac-sha256", EVP_aead_aes_256_ctr_hmac_sha256, false },
|
||||
{ "", NULL, false },
|
||||
};
|
||||
|
||||
static int Main(int argc, char **argv) {
|
||||
int main(int argc, char **argv) {
|
||||
CRYPTO_library_init();
|
||||
|
||||
if (argc != 3) {
|
||||
@@ -354,9 +379,3 @@ static int Main(int argc, char **argv) {
|
||||
|
||||
return FileTestMain(TestAEAD, const_cast<EVP_AEAD*>(aead), argv[2]);
|
||||
}
|
||||
|
||||
} // namespace bssl
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
return bssl::Main(argc, argv);
|
||||
}
|
||||
|
||||
@@ -284,7 +284,7 @@ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
|
||||
bl = ctx->cipher->block_size;
|
||||
assert(bl <= (int)sizeof(ctx->buf));
|
||||
if (i != 0) {
|
||||
if (bl - i > in_len) {
|
||||
if (i + in_len < bl) {
|
||||
memcpy(&ctx->buf[i], in, in_len);
|
||||
ctx->buf_len += in_len;
|
||||
*out_len = 0;
|
||||
|
||||
@@ -62,8 +62,8 @@
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "../test/file_test.h"
|
||||
#include "../test/scoped_types.h"
|
||||
|
||||
namespace bssl {
|
||||
|
||||
static const EVP_CIPHER *GetCipher(const std::string &name) {
|
||||
if (name == "DES-CBC") {
|
||||
@@ -284,7 +284,7 @@ static bool TestCipher(FileTest *t, void *arg) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static int Main(int argc, char **argv) {
|
||||
int main(int argc, char **argv) {
|
||||
CRYPTO_library_init();
|
||||
|
||||
if (argc != 2) {
|
||||
@@ -294,9 +294,3 @@ static int Main(int argc, char **argv) {
|
||||
|
||||
return FileTestMain(TestCipher, nullptr, argv[1]);
|
||||
}
|
||||
|
||||
} // namespace bssl
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
return bssl::Main(argc, argv);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user