Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4d7ba4e4e5 | |||
| 9f69f139ed |
@@ -5,7 +5,6 @@ ssl/test/runner/runner
|
||||
doc/*.html
|
||||
doc/doc.css
|
||||
|
||||
util/bot/android_ndk
|
||||
util/bot/android_tools
|
||||
util/bot/cmake-linux64
|
||||
util/bot/cmake-linux64.tar.gz
|
||||
@@ -15,11 +14,8 @@ util/bot/cmake-win32
|
||||
util/bot/cmake-win32.zip
|
||||
util/bot/golang
|
||||
util/bot/gyp
|
||||
util/bot/libcxx
|
||||
util/bot/libcxxabi
|
||||
util/bot/libFuzzer
|
||||
util/bot/llvm-build
|
||||
util/bot/nasm-win32.exe
|
||||
util/bot/perl-win32
|
||||
util/bot/perl-win32.zip
|
||||
util/bot/sde-linux64
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
# How to change BoringSSL's API
|
||||
|
||||
BoringSSL has more flexibility in changing things than many other library projects because we have a reasonable idea of who our users are. Still, breaking changes require some care. We depend on tight feedback loops with our consumers so that we can learn about mistakes and fix them. For that to work, updating BoringSSL must be smooth.
|
||||
|
||||
Ultimately, the strategy for each breaking change is decided on a case-by-case basis. This document provides guidelines and techniques to help with a smooth transition.
|
||||
|
||||
## Breakage risk
|
||||
|
||||
Traditionally, breaking changes are defined in terms of API or ABI surface. Exposed symbols and type signatures cannot change, etc. But this is a poor approximation of the true impact. Removing an API may not a breaking change if no one is using it. Conversely, [Hyrum's Law](http://www.hyrumslaw.com/) applies. Fixing a bug may be a breaking change for some consumer which was depending on that bug.
|
||||
|
||||
Thus, we do not think about whether a change is formally a breaking change, but about the *risk* of it breaking someone.
|
||||
|
||||
Some changes, such as internal cleanups or bug-fixes, are low risk and do not need special measures. Any problems can be handled when the affected consumer updates BoringSSL and notices.
|
||||
|
||||
Other changes, such as removing an API, forbidding some edge case, or adjusting some behavior, are more likely to break things. To help the consumer triage any resulting failures, include some text in the commit message, prefixed by `Update-Note: `. This can include what this change may break and instructions on how to fix the issue.
|
||||
|
||||
## Code Search
|
||||
|
||||
The vast majority of BoringSSL consumers are conveniently indexed in various Code Search instances. This can predict the impact of a risky change and identify code to fix ahead of time. The document “How to Code Search” in the (Google-only) [go/boringssl-folder](https://goto.google.com/boringssl-folder) includes notes on this.
|
||||
|
||||
## Evaluate a change's cost
|
||||
|
||||
If some change has high cost (from having to fix consumers) and relatively little benefit to BoringSSL, it may not be worth the trouble. For instance, it is likely not worth removing a small compatibility function in the corner of the library that is easily dropped by the static linker.
|
||||
|
||||
Conversely, a change that leads to a major improvement to all BoringSSL consumers, at the cost of fixing one or two consumers, is typically worth it.
|
||||
|
||||
## Fixing consumers
|
||||
|
||||
If code search reveals call sites that are definitely going to break, prefer to handle these before making the change. While unexpected breakage is always possible, we generally consider it the responsibility of the developer or group making a change to handle impact of that change. Teams are generally unhappy to be surprised by new migration work but happy to have migration work done for them.
|
||||
|
||||
In most cases, this is straightforward:
|
||||
|
||||
1. Add the replacement API.
|
||||
2. As the replacement API enters each consuming repository, migrate callers to it.
|
||||
3. Remove the original API once all consumers have been migrated.
|
||||
|
||||
The removal should still include an `Update-Note` tag, in case some were missed.
|
||||
|
||||
In some cases, this kind of staged approach is not feasible: perhaps the same code cannot simultaneously work before and after the change, or perhaps there are too many different versions in play. For instance, [Conscrypt](https://github.com/google/conscrypt) feeds into three different repositories. The GitHub repository consumes BoringSSL's `master` branch directly. It is pushed into Android, where it consumes Android's `external/boringssl`. Yet another copy is pushed into the internal repository, where it consumes that copy of BoringSSL. As each of these Conscrypts are updated independently from their corresponding BoringSSLs, Conscrypt upstream cannot rely on a new BoringSSL API until it is present in all copies of BoringSSL its downstreams rely on.
|
||||
|
||||
In that case, a multi-sided change may be more appropriate:
|
||||
|
||||
1. Upload the breaking change to Gerrit, but do not submit it yet. Increment the `BORINGSSL_API_VERSION` symbol.
|
||||
2. Update the consuming repository with `#if BORINGSSL_API_VERSION < N` preprocessor logic. Leave a comment to remove this later, linking to your BoringSSL change.
|
||||
3. When the `BORINGSSL_API_VERSION` check has propagated to relevant copies of the consuming repository, submit the BoringSSL change.
|
||||
4. When the BoringSSL change has propagated to relevant copies of BoringSSL, remove the staging logic from the consumer.
|
||||
|
||||
Finally, in some cases, the consumer's change may be committed atomically with the BoringSSL update. This can only be done for code which only consumes one instance of BoringSSL (so the Conscrypt example above is not eligible). Check with that project's maintainer first or, better, be that project's maintainer.
|
||||
|
||||
If more complex changes are needed in some consumer, communicate with the relevant maintainers to plan the transition.
|
||||
|
||||
## Fail early, fail closed
|
||||
|
||||
When breaking changes do occur, they should fail as early and as detectably as possible.
|
||||
|
||||
Ideally, problematic consumers fail to compile. Prefer to remove functions completely over leaving an always failing stub function. Sometimes this is not possible due to other consumers, particularly bindings libraries. Alternatively, if a stub function can be reasonably justified as still satisfying the API constraints, consider adding one to improve compatibility. For example, BoringSSL has many no-op stubs corresponding to OpenSSL's many initialization functions.
|
||||
|
||||
If some parameter now must be `NULL`, change the type to an opaque struct pointer. Consumers passing non-`NULL` pointers will then fail to compile.
|
||||
|
||||
If breaking the compile is not feasible, break at runtime, in the hope that consumers have some amount of test coverage. When doing so, try to fail on the common case. In particular, do not rely on consumers adequately testing or even checking for failure cases. One strategy is to bring the object into a “poison” state: if an illegal operation occurs, set a flag to fail all subsequent ones.
|
||||
|
||||
In other functions, it may be appropriate to simply call `abort()`.
|
||||
|
||||
## Unexpected breakage
|
||||
|
||||
While we try to avoid breaking things, sometimes things unexpectedly break. Depending on the impact, we may fix the consumer, make a small fix to BoringSSL, or revert the change to either try again later or revise the approach.
|
||||
|
||||
If we do not ultimately fix the consumer, add a test in BoringSSL to capture the unexpected API contract, so future regressions are caught quickly.
|
||||
|
||||
## Canary changes and bake time
|
||||
|
||||
When planning a large project that depends on a breaking change, prefer to make the breaking change first—before committing larger changes. Or, when changing toolchain or language requirements, add a small instance of the dependency somewhere first then wait a couple of weeks for the change to appear in consumers. This ensures that reverting the change is still feasible if necessary.
|
||||
|
||||
While we rely on a tight feedback loop with our consumers, there are a few consumers which update less frequently. For extremely risky changes, such as introducing C++ to a target, it may be prudent to wait much longer.
|
||||
|
||||
## Third-party code
|
||||
|
||||
In many cases, we are interested in changing behavior which came from OpenSSL. OpenSSL's API surface is huge, but only a small subset is actually used. So we can and occasionally do change these behaviors. This is more complex than changing BoringSSL-only behavior due to third-party code.
|
||||
|
||||
We use BoringSSL with many third-party projects that normally use OpenSSL. Generally, we consider this our burden to make this work and do not encourage external projects to depend on BoringSSL. While we can and do maintain patches for this as necessary, it has overhead and so the cost of breaking third-party code is higher.
|
||||
|
||||
We lean fairly strongly towards making changes to BoringSSL over patching third-party code, unless the third-party change fixes a security problem.
|
||||
|
||||
Additionally, changing an OpenSSL API will not only affect third-party code we use today, but also any third-party code we use in the future. Thus Code Search is less useful as an absolute predictor, and the various other considerations in this document are more important.
|
||||
|
||||
If the patch to support a BoringSSL change can be generally useful to the third-party project, send it upstream. For instance, it may use the APIs better, clean up code, or help support newer versions of OpenSSL. In general, we try to target compatibility with “most” “well-behaved” OpenSSL consumers.
|
||||
|
||||
Finally, if some particular OpenSSL API or pattern is problematic to BoringSSL, it is likely problematic to OpenSSL too. Consider filing a bug with them to suggest a change, either in new code going forward or for the next API break. OpenSSL's release cycles and feedback loops are much longer than BoringSSL's, so this is usually not immediately useful, but it keeps the ecosystem moving in the right direction.
|
||||
+15
-15
@@ -79,15 +79,14 @@ for other variables which may be used to configure the build.
|
||||
|
||||
### Building for Android
|
||||
|
||||
It's possible to build BoringSSL with the Android NDK using CMake. Recent
|
||||
versions of the NDK include a CMake toolchain file which works with CMake 3.6.0
|
||||
or later. This has been tested with version r16b of the NDK.
|
||||
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:
|
||||
|
||||
cmake -DANDROID_ABI=armeabi-v7a \
|
||||
-DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake \
|
||||
-DCMAKE_TOOLCHAIN_FILE=../third_party/android-cmake/android.toolchain.cmake \
|
||||
-DANDROID_NATIVE_API_LEVEL=16 \
|
||||
-GNinja ..
|
||||
|
||||
@@ -95,11 +94,7 @@ 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 older NDK versions, BoringSSL ships a third-party CMake toolchain file. Use
|
||||
`../third_party/android-cmake/android.toolchain.cmake` for
|
||||
`CMAKE_TOOLCHAIN_FILE` instead.
|
||||
|
||||
For other options, see the documentation in the toolchain file.
|
||||
For other options, see [android-cmake's documentation](./third_party/android-cmake/README.md).
|
||||
|
||||
### Building for iOS
|
||||
|
||||
@@ -150,14 +145,19 @@ corresponding ARM feature.
|
||||
Note that if a feature is enabled in this way, but not actually supported at
|
||||
run-time, BoringSSL will likely crash.
|
||||
|
||||
## Binary Size
|
||||
## Assembling ARMv8 with Clang
|
||||
|
||||
The implementations of some algorithms require a trade-off between binary size
|
||||
and performance. For instance, BoringSSL's fastest P-256 implementation uses a
|
||||
148 KiB pre-computed table. To optimize instead for binary size, pass
|
||||
`-DOPENSSL_SMALL=1` to CMake or define the `OPENSSL_SMALL` preprocessor symbol.
|
||||
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.
|
||||
|
||||
# Running Tests
|
||||
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
|
||||
are built by Ninja and can be run from the top-level directory with `go run
|
||||
|
||||
+46
-156
@@ -1,13 +1,7 @@
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
|
||||
# Report AppleClang separately from Clang. Their version numbers are different.
|
||||
# https://cmake.org/cmake/help/v3.0/policy/CMP0025.html
|
||||
if(POLICY CMP0025)
|
||||
cmake_policy(SET CMP0025 NEW)
|
||||
endif()
|
||||
cmake_minimum_required (VERSION 2.8.11)
|
||||
|
||||
# Defer enabling C and CXX languages.
|
||||
project(BoringSSL NONE)
|
||||
project (BoringSSL NONE)
|
||||
|
||||
if(WIN32)
|
||||
# On Windows, prefer cl over gcc if both are available. By default most of
|
||||
@@ -34,14 +28,11 @@ else()
|
||||
find_program(GO_EXECUTABLE go)
|
||||
endif()
|
||||
|
||||
if(NOT GO_EXECUTABLE)
|
||||
if (NOT GO_EXECUTABLE)
|
||||
message(FATAL_ERROR "Could not find Go")
|
||||
endif()
|
||||
|
||||
if(USE_CUSTOM_LIBCXX)
|
||||
set(BORINGSSL_ALLOW_CXX_RUNTIME 1)
|
||||
endif()
|
||||
if(BORINGSSL_ALLOW_CXX_RUNTIME)
|
||||
if (BORINGSSL_ALLOW_CXX_RUNTIME)
|
||||
add_definitions(-DBORINGSSL_ALLOW_CXX_RUNTIME)
|
||||
endif()
|
||||
|
||||
@@ -51,18 +42,17 @@ endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CLANG)
|
||||
# Note clang-cl is odd and sets both CLANG and MSVC. We base our configuration
|
||||
# primarily on our normal Clang one.
|
||||
set(C_CXX_FLAGS "-Werror -Wformat=2 -Wsign-compare -Wmissing-field-initializers -Wwrite-strings")
|
||||
# primarily on our normal Clang one because the MSVC one is mostly
|
||||
# suppressions for an overaggressive -Wall.
|
||||
set(C_CXX_FLAGS "-Wall -Werror -Wformat=2 -Wsign-compare -Wmissing-field-initializers -Wwrite-strings")
|
||||
if(MSVC)
|
||||
# clang-cl sets different default warnings than clang. It also treats -Wall
|
||||
# as -Weverything, to match MSVC. Instead -W3 is the alias for -Wall.
|
||||
# See http://llvm.org/viewvc/llvm-project?view=revision&revision=319116
|
||||
set(C_CXX_FLAGS "${C_CXX_FLAGS} -W3 -Wno-unused-parameter -fmsc-version=1900")
|
||||
# clang-cl sets different default warnings than clang.
|
||||
set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wno-unused-parameter -fmsc-version=1900")
|
||||
# googletest suppresses warning C4996 via a pragma, but clang-cl does not
|
||||
# honor it. Suppress it here to compensate. See https://crbug.com/772117.
|
||||
set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wno-deprecated-declarations")
|
||||
else()
|
||||
set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wall -ggdb -fvisibility=hidden -fno-common")
|
||||
set(C_CXX_FLAGS "${C_CXX_FLAGS} -ggdb -fvisibility=hidden -fno-common")
|
||||
endif()
|
||||
|
||||
if(CLANG)
|
||||
@@ -82,9 +72,6 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CLANG)
|
||||
|
||||
if(NOT MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
if(APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
||||
endif()
|
||||
if(NOT BORINGSSL_ALLOW_CXX_RUNTIME)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions -fno-rtti")
|
||||
endif()
|
||||
@@ -154,8 +141,6 @@ elseif(MSVC)
|
||||
"C4820" # 'bytes' bytes padding added after construct 'member_name'
|
||||
"C5026" # move constructor was implicitly defined as deleted
|
||||
"C5027" # move assignment operator was implicitly defined as deleted
|
||||
"C5045" # Compiler will insert Spectre mitigation for memory load if
|
||||
# /Qspectre switch specified
|
||||
)
|
||||
set(MSVC_LEVEL4_WARNINGS_LIST
|
||||
# See https://connect.microsoft.com/VisualStudio/feedback/details/1217660/warning-c4265-when-using-functional-header
|
||||
@@ -165,8 +150,8 @@ elseif(MSVC)
|
||||
${MSVC_DISABLED_WARNINGS_LIST})
|
||||
string(REPLACE "C" " -w4" MSVC_LEVEL4_WARNINGS_STR
|
||||
${MSVC_LEVEL4_WARNINGS_LIST})
|
||||
set(CMAKE_C_FLAGS "-utf-8 -Wall -WX ${MSVC_DISABLED_WARNINGS_STR} ${MSVC_LEVEL4_WARNINGS_STR}")
|
||||
set(CMAKE_CXX_FLAGS "-utf-8 -Wall -WX ${MSVC_DISABLED_WARNINGS_STR} ${MSVC_LEVEL4_WARNINGS_STR}")
|
||||
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}")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
@@ -175,11 +160,8 @@ if(WIN32)
|
||||
add_definitions(-DNOMINMAX)
|
||||
# Allow use of fopen.
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
# VS 2017 and higher supports STL-only warning suppressions. Manually add to
|
||||
# C++ only to work around a CMake quoting bug when using NASM with the Visual
|
||||
# Studio generator. This will be fixed in CMake 3.13.0. See
|
||||
# https://gitlab.kitware.com/cmake/cmake/merge_requests/2179
|
||||
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-D_STL_EXTRA_DISABLED_WARNINGS=4774\ 4987>)
|
||||
# VS 2017 and higher supports STL-only warning suppressions.
|
||||
add_definitions("-D_STL_EXTRA_DISABLED_WARNINGS=4774 4987")
|
||||
endif()
|
||||
|
||||
if((CMAKE_COMPILER_IS_GNUCXX AND CMAKE_C_COMPILER_VERSION VERSION_GREATER "4.7.99") OR
|
||||
@@ -189,7 +171,7 @@ if((CMAKE_COMPILER_IS_GNUCXX AND CMAKE_C_COMPILER_VERSION VERSION_GREATER "4.7.9
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
if((CMAKE_C_COMPILER_VERSION VERSION_GREATER "4.8.99") OR CLANG)
|
||||
if ((CMAKE_C_COMPILER_VERSION VERSION_GREATER "4.8.99") OR CLANG)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11")
|
||||
else()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")
|
||||
@@ -216,25 +198,25 @@ if(FUZZ)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fsanitize-coverage=edge,indirect-calls,trace-pc-guard")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fsanitize-coverage=edge,indirect-calls,trace-pc-guard")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address")
|
||||
link_directories(.)
|
||||
endif()
|
||||
|
||||
add_definitions(-DBORINGSSL_IMPLEMENTATION)
|
||||
|
||||
if(BUILD_SHARED_LIBS)
|
||||
if (BUILD_SHARED_LIBS)
|
||||
add_definitions(-DBORINGSSL_SHARED_LIBRARY)
|
||||
# Enable position-independent code globally. This is needed because
|
||||
# some library targets are OBJECT libraries.
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
|
||||
endif()
|
||||
|
||||
if(MSAN)
|
||||
if (MSAN)
|
||||
if(NOT CLANG)
|
||||
message(FATAL_ERROR "Cannot enable MSAN unless using Clang")
|
||||
endif()
|
||||
|
||||
if(ASAN)
|
||||
if (ASAN)
|
||||
message(FATAL_ERROR "ASAN and MSAN are mutually exclusive")
|
||||
endif()
|
||||
|
||||
@@ -243,7 +225,7 @@ if(MSAN)
|
||||
set(OPENSSL_NO_ASM "1")
|
||||
endif()
|
||||
|
||||
if(ASAN)
|
||||
if (ASAN)
|
||||
if(NOT CLANG)
|
||||
message(FATAL_ERROR "Cannot enable ASAN unless using Clang")
|
||||
endif()
|
||||
@@ -253,35 +235,7 @@ if(ASAN)
|
||||
set(OPENSSL_NO_ASM "1")
|
||||
endif()
|
||||
|
||||
if(CFI)
|
||||
if(NOT CLANG)
|
||||
message(FATAL_ERROR "Cannot enable CFI unless using Clang")
|
||||
endif()
|
||||
|
||||
# TODO(crbug.com/785442): Remove -fsanitize-cfi-icall-generalize-pointers.
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=cfi -fno-sanitize-trap=cfi -fsanitize-cfi-icall-generalize-pointers -flto=thin")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=cfi -fno-sanitize-trap=cfi -fsanitize-cfi-icall-generalize-pointers -flto=thin")
|
||||
# We use Chromium's copy of clang, which requires -fuse-ld=lld if building
|
||||
# with -flto. That, in turn, can't handle -ggdb.
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=lld")
|
||||
string(REPLACE "-ggdb" "-g" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
|
||||
string(REPLACE "-ggdb" "-g" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
# -flto causes object files to contain LLVM bitcode. Mixing those with
|
||||
# assembly output in the same static library breaks the linker.
|
||||
set(OPENSSL_NO_ASM "1")
|
||||
endif()
|
||||
|
||||
if(TSAN)
|
||||
if(NOT CLANG)
|
||||
message(FATAL_ERROR "Cannot enable TSAN unless using Clang")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=thread")
|
||||
endif()
|
||||
|
||||
if(GCOV)
|
||||
if (GCOV)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
|
||||
endif()
|
||||
@@ -297,132 +251,73 @@ if(FIPS)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(OPENSSL_SMALL)
|
||||
add_definitions(-DOPENSSL_SMALL)
|
||||
endif()
|
||||
|
||||
# CMake's iOS support uses Apple's multiple-architecture toolchain. It takes an
|
||||
# architecture list from CMAKE_OSX_ARCHITECTURES, leaves CMAKE_SYSTEM_PROCESSOR
|
||||
# alone, and expects all architecture-specific logic to be conditioned within
|
||||
# the source files rather than the build. This does not work for our assembly
|
||||
# files, so we fix CMAKE_SYSTEM_PROCESSOR and only support single-architecture
|
||||
# builds.
|
||||
if(NOT OPENSSL_NO_ASM AND CMAKE_OSX_ARCHITECTURES)
|
||||
if (NOT OPENSSL_NO_ASM AND CMAKE_OSX_ARCHITECTURES)
|
||||
list(LENGTH CMAKE_OSX_ARCHITECTURES NUM_ARCHES)
|
||||
if(NOT ${NUM_ARCHES} EQUAL 1)
|
||||
if (NOT ${NUM_ARCHES} EQUAL 1)
|
||||
message(FATAL_ERROR "Universal binaries not supported.")
|
||||
endif()
|
||||
list(GET CMAKE_OSX_ARCHITECTURES 0 CMAKE_SYSTEM_PROCESSOR)
|
||||
endif()
|
||||
|
||||
if(OPENSSL_NO_ASM)
|
||||
if (OPENSSL_NO_ASM)
|
||||
add_definitions(-DOPENSSL_NO_ASM)
|
||||
set(ARCH "generic")
|
||||
elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64")
|
||||
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64")
|
||||
set(ARCH "x86_64")
|
||||
elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "amd64")
|
||||
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "amd64")
|
||||
set(ARCH "x86_64")
|
||||
elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "AMD64")
|
||||
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "AMD64")
|
||||
# cmake reports AMD64 on Windows, but we might be building for 32-bit.
|
||||
if(CMAKE_CL_64)
|
||||
if (CMAKE_CL_64)
|
||||
set(ARCH "x86_64")
|
||||
else()
|
||||
set(ARCH "x86")
|
||||
endif()
|
||||
elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86")
|
||||
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86")
|
||||
set(ARCH "x86")
|
||||
elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i386")
|
||||
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i386")
|
||||
set(ARCH "x86")
|
||||
elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i686")
|
||||
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i686")
|
||||
set(ARCH "x86")
|
||||
elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
|
||||
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
|
||||
set(ARCH "aarch64")
|
||||
elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm64")
|
||||
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm64")
|
||||
set(ARCH "aarch64")
|
||||
elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^arm*")
|
||||
elseif (${CMAKE_SYSTEM_PROCESSOR} MATCHES "^arm*")
|
||||
set(ARCH "arm")
|
||||
elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "mips")
|
||||
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "mips")
|
||||
# Just to avoid the “unknown processor” error.
|
||||
set(ARCH "generic")
|
||||
elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "ppc64le")
|
||||
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "ppc64le")
|
||||
set(ARCH "ppc64le")
|
||||
else()
|
||||
message(FATAL_ERROR "Unknown processor:" ${CMAKE_SYSTEM_PROCESSOR})
|
||||
endif()
|
||||
|
||||
if(ANDROID AND NOT ANDROID_NDK_REVISION AND ${ARCH} STREQUAL "arm")
|
||||
# The third-party Android-NDK CMake files somehow fail to set the -march flag
|
||||
# for assembly files. Without this flag, the compiler believes that it's
|
||||
if (ANDROID AND ${ARCH} STREQUAL "arm")
|
||||
# The Android-NDK CMake files somehow fail to set the -march flag for
|
||||
# assembly files. Without this flag, the compiler believes that it's
|
||||
# building for ARMv5.
|
||||
set(CMAKE_ASM_FLAGS "-march=${CMAKE_SYSTEM_PROCESSOR} ${CMAKE_ASM_FLAGS}")
|
||||
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -march=${CMAKE_SYSTEM_PROCESSOR}")
|
||||
endif()
|
||||
|
||||
if(${ARCH} STREQUAL "x86" AND APPLE AND ${CMAKE_VERSION} VERSION_LESS "3.0")
|
||||
if (${ARCH} STREQUAL "x86" AND APPLE)
|
||||
# With CMake 2.8.x, ${CMAKE_SYSTEM_PROCESSOR} evalutes to i386 on OS X,
|
||||
# but clang defaults to 64-bit builds on OS X unless otherwise told.
|
||||
# Set ARCH to x86_64 so clang and CMake agree. This is fixed in CMake 3.
|
||||
set(ARCH "x86_64")
|
||||
endif()
|
||||
|
||||
if(USE_CUSTOM_LIBCXX)
|
||||
if(NOT CLANG)
|
||||
message(FATAL_ERROR "USE_CUSTOM_LIBCXX only supported with Clang")
|
||||
endif()
|
||||
|
||||
# CMAKE_CXX_FLAGS ends up in the linker flags as well, so use
|
||||
# add_compile_options. There does not appear to be a way to set
|
||||
# language-specific compile-only flags.
|
||||
add_compile_options("-nostdinc++")
|
||||
set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -nostdlib++")
|
||||
include_directories(
|
||||
SYSTEM
|
||||
util/bot/libcxx/include
|
||||
util/bot/libcxxabi/include
|
||||
)
|
||||
|
||||
# This is patterned after buildtools/third_party/libc++/BUILD.gn and
|
||||
# buildtools/third_party/libc++abi/BUILD.gn in Chromium.
|
||||
|
||||
file(GLOB LIBCXX_SOURCES "util/bot/libcxx/src/*.cpp")
|
||||
file(GLOB LIBCXXABI_SOURCES "util/bot/libcxxabi/src/*.cpp")
|
||||
|
||||
# This file is meant for exception-less builds.
|
||||
list(REMOVE_ITEM LIBCXXABI_SOURCES "trunk/src/cxa_noexception.cpp")
|
||||
# libc++ also defines new and delete.
|
||||
list(REMOVE_ITEM LIBCXXABI_SOURCES "trunk/src/stdlib_new_delete.cpp")
|
||||
if(TSAN)
|
||||
# ThreadSanitizer tries to intercept these symbols. Skip them to avoid
|
||||
# symbol conflicts.
|
||||
list(REMOVE_ITEM LIBCXXABI_SOURCES "trunk/src/cxa_guard.cpp")
|
||||
endif()
|
||||
|
||||
add_library(libcxxabi ${LIBCXXABI_SOURCES})
|
||||
target_compile_definitions(
|
||||
libcxxabi PRIVATE
|
||||
-D_LIBCPP_ENABLE_CXX17_REMOVED_UNEXPECTED_FUNCTIONS
|
||||
)
|
||||
set_target_properties(libcxxabi PROPERTIES COMPILE_FLAGS "-Wno-missing-prototypes -Wno-implicit-fallthrough")
|
||||
|
||||
add_library(libcxx ${LIBCXX_SOURCES})
|
||||
if(ASAN OR MSAN OR TSAN)
|
||||
# Sanitizers try to intercept new and delete.
|
||||
target_compile_definitions(
|
||||
libcxx PRIVATE
|
||||
-D_LIBCPP_DISABLE_NEW_DELETE_DEFINITIONS
|
||||
)
|
||||
endif()
|
||||
target_compile_definitions(
|
||||
libcxx PRIVATE
|
||||
-D_LIBCPP_BUILDING_LIBRARY
|
||||
-DLIBCXX_BUILDING_LIBCXXABI
|
||||
)
|
||||
target_link_libraries(libcxx libcxxabi)
|
||||
endif()
|
||||
|
||||
# Add minimal googletest targets. The provided one has many side-effects, and
|
||||
# googletest has a very straightforward build.
|
||||
add_library(boringssl_gtest third_party/googletest/src/gtest-all.cc)
|
||||
target_include_directories(boringssl_gtest PRIVATE third_party/googletest)
|
||||
add_library(gtest third_party/googletest/src/gtest-all.cc)
|
||||
target_include_directories(gtest PRIVATE third_party/googletest)
|
||||
|
||||
include_directories(third_party/googletest/include)
|
||||
|
||||
@@ -440,7 +335,6 @@ add_custom_command(
|
||||
add_library(crypto_test_data OBJECT crypto_test_data.cc)
|
||||
|
||||
add_subdirectory(crypto)
|
||||
add_subdirectory(third_party/fiat)
|
||||
add_subdirectory(ssl)
|
||||
add_subdirectory(ssl/test)
|
||||
add_subdirectory(fipstools)
|
||||
@@ -459,22 +353,18 @@ if(FUZZ)
|
||||
add_subdirectory(fuzz)
|
||||
endif()
|
||||
|
||||
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.2")
|
||||
if (NOT ${CMAKE_VERSION} VERSION_LESS "3.2")
|
||||
# USES_TERMINAL is only available in CMake 3.2 or later.
|
||||
set(MAYBE_USES_TERMINAL USES_TERMINAL)
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE AND NOT ANDROID)
|
||||
set(HANDSHAKER_ARGS "-handshaker-path" $<TARGET_FILE:handshaker>)
|
||||
endif()
|
||||
|
||||
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>
|
||||
${HANDSHAKER_ARGS} ${RUNNER_ARGS}
|
||||
${RUNNER_ARGS}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
DEPENDS all_tests bssl_shim handshaker
|
||||
DEPENDS all_tests bssl_shim
|
||||
${MAYBE_USES_TERMINAL})
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ updating things more complex.
|
||||
|
||||
BoringSSL is designed to work with many different build systems. Currently,
|
||||
different projects use [GYP](https://gyp.gsrc.io/),
|
||||
[GN](https://gn.googlesource.com/gn/+/master/docs/quick_start.md),
|
||||
[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.
|
||||
|
||||
|
||||
@@ -5,9 +5,8 @@ license. This license is reproduced at the bottom of this file.
|
||||
Contributors to BoringSSL are required to follow the CLA rules for Chromium:
|
||||
https://cla.developers.google.com/clas
|
||||
|
||||
Files in third_party/ have their own licenses, as described therein. The MIT
|
||||
license, for third_party/fiat, which, unlike other third_party directories, is
|
||||
compiled into non-test libraries, is included below.
|
||||
Some files from Intel are under yet another license, which is also included
|
||||
underneath.
|
||||
|
||||
The OpenSSL toolkit stays under a dual license, i.e. both the conditions of the
|
||||
OpenSSL License and the original SSLeay license apply to the toolkit. See below
|
||||
@@ -157,95 +156,37 @@ ISC license used for completely new code in BoringSSL:
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
|
||||
The code in third_party/fiat carries the MIT license:
|
||||
Some files from Intel carry the following license:
|
||||
|
||||
Copyright (c) 2015-2016 the fiat-crypto authors (see
|
||||
https://github.com/mit-plv/fiat-crypto/blob/master/AUTHORS).
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
Licenses for support code
|
||||
-------------------------
|
||||
|
||||
Parts of the TLS test suite are under the Go license. This code is not included
|
||||
in BoringSSL (i.e. libcrypto and libssl) when compiled, however, so
|
||||
distributing code linked against BoringSSL does not trigger this license:
|
||||
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
BoringSSL uses the Chromium test infrastructure to run a continuous build,
|
||||
trybots etc. The scripts which manage this, and the script for generating build
|
||||
metadata, are under the Chromium license. Distributing code linked against
|
||||
BoringSSL does not trigger this license.
|
||||
|
||||
Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
# Copyright (c) 2012, Intel Corporation
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
#
|
||||
# * Neither the name of the Intel Corporation nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY
|
||||
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
+2
-2
@@ -123,7 +123,7 @@ feature, so BoringSSL rejects peer renegotiations by default.
|
||||
|
||||
To enable renegotiation, call `SSL_set_renegotiate_mode` and set it to
|
||||
`ssl_renegotiate_once` or `ssl_renegotiate_freely`. Renegotiation is only
|
||||
supported as a client in TLS and the HelloRequest must be received at a
|
||||
supported as a client in SSL3/TLS and the HelloRequest must be received at a
|
||||
quiet point in the application protocol. This is sufficient to support the
|
||||
common use of requesting a new client certificate between an HTTP request and
|
||||
response in (unpipelined) HTTP/1.1.
|
||||
@@ -210,7 +210,7 @@ strings and loading algorithms, etc. All of these functions still exist in
|
||||
BoringSSL for convenience, but they do nothing and are not necessary.
|
||||
|
||||
The one exception is `CRYPTO_library_init`. In `BORINGSSL_NO_STATIC_INITIALIZER`
|
||||
builds, it must be called to query CPU capabilities before the rest of the
|
||||
builds, it must be called to query CPU capabitilies before the rest of the
|
||||
library. In the default configuration, this is done with a static initializer
|
||||
and is also unnecessary.
|
||||
|
||||
|
||||
@@ -31,4 +31,3 @@ There are other files in this directory which might be helpful:
|
||||
* 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.
|
||||
* [CONTRIBUTING.md](/CONTRIBUTING.md): how to contribute to BoringSSL.
|
||||
* [BREAKING-CHANGES.md](/BREAKING-CHANGES.md): notes on potentially-breaking changes.
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
# This file is used by "git cl" 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
|
||||
|
||||
+17
-29
@@ -2,27 +2,27 @@ include_directories(../include)
|
||||
|
||||
if(NOT OPENSSL_NO_ASM)
|
||||
if(UNIX)
|
||||
if(${ARCH} STREQUAL "aarch64")
|
||||
if (${ARCH} STREQUAL "aarch64")
|
||||
# The "armx" Perl scripts look for "64" in the style argument
|
||||
# in order to decide whether to generate 32- or 64-bit asm.
|
||||
if(APPLE)
|
||||
if (APPLE)
|
||||
set(PERLASM_STYLE ios64)
|
||||
else()
|
||||
set(PERLASM_STYLE linux64)
|
||||
endif()
|
||||
elseif(${ARCH} STREQUAL "arm")
|
||||
if(APPLE)
|
||||
elseif (${ARCH} STREQUAL "arm")
|
||||
if (APPLE)
|
||||
set(PERLASM_STYLE ios32)
|
||||
else()
|
||||
set(PERLASM_STYLE linux32)
|
||||
endif()
|
||||
elseif(${ARCH} STREQUAL "ppc64le")
|
||||
elseif (${ARCH} STREQUAL "ppc64le")
|
||||
set(PERLASM_STYLE linux64le)
|
||||
else()
|
||||
if(${ARCH} STREQUAL "x86")
|
||||
if (${ARCH} STREQUAL "x86")
|
||||
set(PERLASM_FLAGS "-fPIC -DOPENSSL_IA32_SSE2")
|
||||
endif()
|
||||
if(APPLE)
|
||||
if (APPLE)
|
||||
set(PERLASM_STYLE macosx)
|
||||
else()
|
||||
set(PERLASM_STYLE elf)
|
||||
@@ -38,8 +38,8 @@ if(NOT OPENSSL_NO_ASM)
|
||||
endif()
|
||||
|
||||
# CMake does not add -isysroot and -arch flags to assembly.
|
||||
if(APPLE)
|
||||
if(CMAKE_OSX_SYSROOT)
|
||||
if (APPLE)
|
||||
if (CMAKE_OSX_SYSROOT)
|
||||
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -isysroot \"${CMAKE_OSX_SYSROOT}\"")
|
||||
endif()
|
||||
foreach(arch ${CMAKE_OSX_ARCHITECTURES})
|
||||
@@ -47,13 +47,13 @@ if(NOT OPENSSL_NO_ASM)
|
||||
endforeach()
|
||||
endif()
|
||||
else()
|
||||
if(${ARCH} STREQUAL "x86_64")
|
||||
if (${ARCH} STREQUAL "x86_64")
|
||||
set(PERLASM_STYLE nasm)
|
||||
else()
|
||||
set(PERLASM_STYLE win32n)
|
||||
set(PERLASM_FLAGS "-DOPENSSL_IA32_SSE2")
|
||||
endif()
|
||||
set(CMAKE_ASM_NASM_FLAGS "-gcv8")
|
||||
set(CMAKE_ASM_NASM_FLAGS "-g cv8")
|
||||
|
||||
# On Windows, we use the NASM output, specifically built with Yasm.
|
||||
set(ASM_EXT asm)
|
||||
@@ -109,7 +109,7 @@ add_subdirectory(dh)
|
||||
add_subdirectory(dsa)
|
||||
add_subdirectory(rsa_extra)
|
||||
add_subdirectory(ec_extra)
|
||||
add_subdirectory(ecdh_extra)
|
||||
add_subdirectory(ecdh)
|
||||
add_subdirectory(ecdsa_extra)
|
||||
|
||||
# Level 3
|
||||
@@ -134,7 +134,6 @@ add_library(
|
||||
|
||||
OBJECT
|
||||
|
||||
cpu-aarch64-fuchsia.c
|
||||
cpu-aarch64-linux.c
|
||||
cpu-arm.c
|
||||
cpu-arm-linux.c
|
||||
@@ -180,7 +179,6 @@ add_library(
|
||||
$<TARGET_OBJECTS:chacha>
|
||||
$<TARGET_OBJECTS:poly1305>
|
||||
$<TARGET_OBJECTS:curve25519>
|
||||
$<TARGET_OBJECTS:fiat>
|
||||
$<TARGET_OBJECTS:buf>
|
||||
$<TARGET_OBJECTS:bn_extra>
|
||||
$<TARGET_OBJECTS:bio>
|
||||
@@ -192,7 +190,7 @@ add_library(
|
||||
$<TARGET_OBJECTS:dsa>
|
||||
$<TARGET_OBJECTS:rsa_extra>
|
||||
$<TARGET_OBJECTS:ec_extra>
|
||||
$<TARGET_OBJECTS:ecdh_extra>
|
||||
$<TARGET_OBJECTS:ecdh>
|
||||
$<TARGET_OBJECTS:ecdsa_extra>
|
||||
$<TARGET_OBJECTS:cmac>
|
||||
$<TARGET_OBJECTS:evp>
|
||||
@@ -216,19 +214,12 @@ if(NOT MSVC AND NOT ANDROID)
|
||||
target_link_libraries(crypto pthread)
|
||||
endif()
|
||||
|
||||
# Every target depends on crypto, so we add libcxx as a dependency here to
|
||||
# simplify injecting it everywhere.
|
||||
if(USE_CUSTOM_LIBCXX)
|
||||
target_link_libraries(crypto libcxx)
|
||||
endif()
|
||||
|
||||
# TODO(davidben): Convert the remaining tests to GTest.
|
||||
add_executable(
|
||||
crypto_test
|
||||
|
||||
asn1/asn1_test.cc
|
||||
base64/base64_test.cc
|
||||
buf/buf_test.cc
|
||||
bio/bio_test.cc
|
||||
bytestring/bytestring_test.cc
|
||||
chacha/chacha_test.cc
|
||||
@@ -240,7 +231,7 @@ add_executable(
|
||||
curve25519/ed25519_test.cc
|
||||
curve25519/spake25519_test.cc
|
||||
curve25519/x25519_test.cc
|
||||
ecdh_extra/ecdh_test.cc
|
||||
ecdh/ecdh_test.cc
|
||||
dh/dh_test.cc
|
||||
digest_extra/digest_test.cc
|
||||
dsa/dsa_test.cc
|
||||
@@ -260,7 +251,6 @@ add_executable(
|
||||
hmac_extra/hmac_test.cc
|
||||
lhash/lhash_test.cc
|
||||
obj/obj_test.cc
|
||||
pem/pem_test.cc
|
||||
pkcs7/pkcs7_test.cc
|
||||
pkcs8/pkcs8_test.cc
|
||||
pkcs8/pkcs12_test.cc
|
||||
@@ -268,21 +258,19 @@ add_executable(
|
||||
pool/pool_test.cc
|
||||
refcount_test.cc
|
||||
rsa_extra/rsa_test.cc
|
||||
self_test.cc
|
||||
test/file_test_gtest.cc
|
||||
thread_test.cc
|
||||
x509/x509_test.cc
|
||||
x509/x509_time_test.cc
|
||||
x509v3/tab_test.cc
|
||||
x509v3/v3name_test.cc
|
||||
|
||||
$<TARGET_OBJECTS:crypto_test_data>
|
||||
$<TARGET_OBJECTS:boringssl_gtest_main>
|
||||
$<TARGET_OBJECTS:gtest_main>
|
||||
$<TARGET_OBJECTS:test_support>
|
||||
)
|
||||
|
||||
target_link_libraries(crypto_test crypto boringssl_gtest)
|
||||
if(WIN32)
|
||||
target_link_libraries(crypto_test crypto gtest)
|
||||
if (WIN32)
|
||||
target_link_libraries(crypto_test ws2_32)
|
||||
endif()
|
||||
add_dependencies(all_tests crypto_test)
|
||||
|
||||
+5
-18
@@ -62,30 +62,17 @@
|
||||
int i2d_ASN1_BOOLEAN(int a, unsigned char **pp)
|
||||
{
|
||||
int r;
|
||||
unsigned char *p, *allocated = NULL;
|
||||
unsigned char *p;
|
||||
|
||||
r = ASN1_object_size(0, 1, V_ASN1_BOOLEAN);
|
||||
if (pp == NULL)
|
||||
return (r);
|
||||
|
||||
if (*pp == NULL) {
|
||||
if ((p = allocated = OPENSSL_malloc(r)) == NULL) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
p = *pp;
|
||||
}
|
||||
p = *pp;
|
||||
|
||||
ASN1_put_object(&p, 0, 1, V_ASN1_BOOLEAN, V_ASN1_UNIVERSAL);
|
||||
*p = (unsigned char)a;
|
||||
|
||||
/*
|
||||
* If a new buffer was allocated, just return it back.
|
||||
* If not, return the incremented buffer pointer.
|
||||
*/
|
||||
*pp = allocated != NULL ? allocated : p + 1;
|
||||
return r;
|
||||
*(p++) = (unsigned char)a;
|
||||
*pp = p;
|
||||
return (r);
|
||||
}
|
||||
|
||||
int d2i_ASN1_BOOLEAN(int *a, const unsigned char **pp, long length)
|
||||
|
||||
+9
-20
@@ -56,7 +56,6 @@
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
@@ -111,6 +110,7 @@ int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v)
|
||||
long ASN1_ENUMERATED_get(ASN1_ENUMERATED *a)
|
||||
{
|
||||
int neg = 0, i;
|
||||
long r = 0;
|
||||
|
||||
if (a == NULL)
|
||||
return (0L);
|
||||
@@ -120,31 +120,20 @@ long ASN1_ENUMERATED_get(ASN1_ENUMERATED *a)
|
||||
else if (i != V_ASN1_ENUMERATED)
|
||||
return -1;
|
||||
|
||||
OPENSSL_COMPILE_ASSERT(sizeof(uint64_t) >= sizeof(long),
|
||||
long_larger_than_uint64_t);
|
||||
|
||||
if (a->length > (int)sizeof(uint64_t)) {
|
||||
if (a->length > (int)sizeof(long)) {
|
||||
/* hmm... a bit ugly */
|
||||
return -1;
|
||||
return (0xffffffffL);
|
||||
}
|
||||
if (a->data == NULL)
|
||||
return 0;
|
||||
|
||||
uint64_t r64 = 0;
|
||||
if (a->data != NULL) {
|
||||
for (i = 0; i < a->length; i++) {
|
||||
r64 <<= 8;
|
||||
r64 |= (unsigned char)a->data[i];
|
||||
}
|
||||
|
||||
if (r64 > LONG_MAX) {
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < a->length; i++) {
|
||||
r <<= 8;
|
||||
r |= (unsigned char)a->data[i];
|
||||
}
|
||||
|
||||
long r = (long) r64;
|
||||
if (neg)
|
||||
r = -r;
|
||||
|
||||
return r;
|
||||
return (r);
|
||||
}
|
||||
|
||||
ASN1_ENUMERATED *BN_to_ASN1_ENUMERATED(BIGNUM *bn, ASN1_ENUMERATED *ai)
|
||||
|
||||
@@ -81,9 +81,6 @@ int ASN1_i2d_bio(i2d_of_void *i2d, BIO *out, void *x)
|
||||
int i, j = 0, n, ret = 1;
|
||||
|
||||
n = i2d(x, NULL);
|
||||
if (n <= 0)
|
||||
return 0;
|
||||
|
||||
b = (char *)OPENSSL_malloc(n);
|
||||
if (b == NULL) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
|
||||
+36
-52
@@ -57,7 +57,6 @@
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
@@ -347,50 +346,46 @@ ASN1_INTEGER *d2i_ASN1_UINTEGER(ASN1_INTEGER **a, const unsigned char **pp,
|
||||
|
||||
int ASN1_INTEGER_set(ASN1_INTEGER *a, long v)
|
||||
{
|
||||
if (v >= 0) {
|
||||
return ASN1_INTEGER_set_uint64(a, (uint64_t) v);
|
||||
int j, k;
|
||||
unsigned int i;
|
||||
unsigned char buf[sizeof(long) + 1];
|
||||
long d;
|
||||
|
||||
a->type = V_ASN1_INTEGER;
|
||||
if (a->length < (int)(sizeof(long) + 1)) {
|
||||
if (a->data != NULL)
|
||||
OPENSSL_free(a->data);
|
||||
if ((a->data =
|
||||
(unsigned char *)OPENSSL_malloc(sizeof(long) + 1)) != NULL)
|
||||
OPENSSL_memset((char *)a->data, 0, sizeof(long) + 1);
|
||||
}
|
||||
|
||||
if (!ASN1_INTEGER_set_uint64(a, 0 - (uint64_t) v)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
a->type = V_ASN1_NEG_INTEGER;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ASN1_INTEGER_set_uint64(ASN1_INTEGER *out, uint64_t v)
|
||||
{
|
||||
uint8_t *const newdata = OPENSSL_malloc(sizeof(uint64_t));
|
||||
if (newdata == NULL) {
|
||||
if (a->data == NULL) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
return (0);
|
||||
}
|
||||
d = v;
|
||||
if (d < 0) {
|
||||
d = -d;
|
||||
a->type = V_ASN1_NEG_INTEGER;
|
||||
}
|
||||
|
||||
OPENSSL_free(out->data);
|
||||
out->data = newdata;
|
||||
v = CRYPTO_bswap8(v);
|
||||
memcpy(out->data, &v, sizeof(v));
|
||||
|
||||
out->type = V_ASN1_INTEGER;
|
||||
|
||||
size_t leading_zeros;
|
||||
for (leading_zeros = 0; leading_zeros < sizeof(uint64_t) - 1;
|
||||
leading_zeros++) {
|
||||
if (out->data[leading_zeros] != 0) {
|
||||
for (i = 0; i < sizeof(long); i++) {
|
||||
if (d == 0)
|
||||
break;
|
||||
}
|
||||
buf[i] = (int)d & 0xff;
|
||||
d >>= 8;
|
||||
}
|
||||
|
||||
out->length = sizeof(uint64_t) - leading_zeros;
|
||||
OPENSSL_memmove(out->data, out->data + leading_zeros, out->length);
|
||||
|
||||
return 1;
|
||||
j = 0;
|
||||
for (k = i - 1; k >= 0; k--)
|
||||
a->data[j++] = buf[k];
|
||||
a->length = j;
|
||||
return (1);
|
||||
}
|
||||
|
||||
long ASN1_INTEGER_get(const ASN1_INTEGER *a)
|
||||
{
|
||||
int neg = 0, i;
|
||||
long r = 0;
|
||||
|
||||
if (a == NULL)
|
||||
return (0L);
|
||||
@@ -400,31 +395,20 @@ long ASN1_INTEGER_get(const ASN1_INTEGER *a)
|
||||
else if (i != V_ASN1_INTEGER)
|
||||
return -1;
|
||||
|
||||
OPENSSL_COMPILE_ASSERT(sizeof(uint64_t) >= sizeof(long),
|
||||
long_larger_than_uint64_t);
|
||||
|
||||
if (a->length > (int)sizeof(uint64_t)) {
|
||||
if (a->length > (int)sizeof(long)) {
|
||||
/* hmm... a bit ugly, return all ones */
|
||||
return -1;
|
||||
}
|
||||
if (a->data == NULL)
|
||||
return 0;
|
||||
|
||||
uint64_t r64 = 0;
|
||||
if (a->data != NULL) {
|
||||
for (i = 0; i < a->length; i++) {
|
||||
r64 <<= 8;
|
||||
r64 |= (unsigned char)a->data[i];
|
||||
}
|
||||
|
||||
if (r64 > LONG_MAX) {
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < a->length; i++) {
|
||||
r <<= 8;
|
||||
r |= (unsigned char)a->data[i];
|
||||
}
|
||||
|
||||
long r = (long) r64;
|
||||
if (neg)
|
||||
r = -r;
|
||||
|
||||
return r;
|
||||
return (r);
|
||||
}
|
||||
|
||||
ASN1_INTEGER *BN_to_ASN1_INTEGER(const BIGNUM *bn, ASN1_INTEGER *ai)
|
||||
|
||||
+219
-115
@@ -56,17 +56,22 @@
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/bytestring.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "asn1_locl.h"
|
||||
#include "../bytestring/internal.h"
|
||||
|
||||
static int is_printable(uint32_t value);
|
||||
static int traverse_string(const unsigned char *p, int len, int inform,
|
||||
int (*rfunc) (unsigned long value, void *in),
|
||||
void *arg);
|
||||
static int in_utf8(unsigned long value, void *arg);
|
||||
static int out_utf8(unsigned long value, void *arg);
|
||||
static int type_str(unsigned long value, void *arg);
|
||||
static int cpy_asc(unsigned long value, void *arg);
|
||||
static int cpy_bmp(unsigned long value, void *arg);
|
||||
static int cpy_univ(unsigned long value, void *arg);
|
||||
static int cpy_utf8(unsigned long value, void *arg);
|
||||
static int is_printable(unsigned long value);
|
||||
|
||||
/*
|
||||
* These functions take a string in UTF8, ASCII or multibyte form and a mask
|
||||
@@ -83,45 +88,55 @@ int ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len,
|
||||
return ASN1_mbstring_ncopy(out, in, len, inform, mask, 0, 0);
|
||||
}
|
||||
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_BMPSTRING)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_UNIVERSALSTRING)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_UTF8STRING)
|
||||
|
||||
int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
|
||||
int inform, unsigned long mask,
|
||||
long minsize, long maxsize)
|
||||
{
|
||||
int str_type;
|
||||
int ret;
|
||||
char free_out;
|
||||
int outform, outlen = 0;
|
||||
ASN1_STRING *dest;
|
||||
size_t nchar = 0;
|
||||
unsigned char *p;
|
||||
int nchar;
|
||||
char strbuf[32];
|
||||
int (*cpyfunc) (unsigned long, void *) = NULL;
|
||||
if (len == -1)
|
||||
len = strlen((const char *)in);
|
||||
if (!mask)
|
||||
mask = DIRSTRING_TYPE;
|
||||
|
||||
int (*decode_func)(CBS *, uint32_t*);
|
||||
int error;
|
||||
/* First do a string check and work out the number of characters */
|
||||
switch (inform) {
|
||||
|
||||
case MBSTRING_BMP:
|
||||
decode_func = cbs_get_ucs2_be;
|
||||
error = ASN1_R_INVALID_BMPSTRING;
|
||||
if (len & 1) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_BMPSTRING_LENGTH);
|
||||
return -1;
|
||||
}
|
||||
nchar = len >> 1;
|
||||
break;
|
||||
|
||||
case MBSTRING_UNIV:
|
||||
decode_func = cbs_get_utf32_be;
|
||||
error = ASN1_R_INVALID_UNIVERSALSTRING;
|
||||
if (len & 3) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_UNIVERSALSTRING_LENGTH);
|
||||
return -1;
|
||||
}
|
||||
nchar = len >> 2;
|
||||
break;
|
||||
|
||||
case MBSTRING_UTF8:
|
||||
decode_func = cbs_get_utf8;
|
||||
error = ASN1_R_INVALID_UTF8STRING;
|
||||
nchar = 0;
|
||||
/* This counts the characters and does utf8 syntax checking */
|
||||
ret = traverse_string(in, len, MBSTRING_UTF8, in_utf8, &nchar);
|
||||
if (ret < 0) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_UTF8STRING);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case MBSTRING_ASC:
|
||||
decode_func = cbs_get_latin1;
|
||||
error = ERR_R_INTERNAL_ERROR; // Latin-1 inputs are never invalid.
|
||||
nchar = len;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -129,92 +144,44 @@ int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check |minsize| and |maxsize| and work out the minimal type, if any. */
|
||||
CBS cbs;
|
||||
CBS_init(&cbs, in, len);
|
||||
size_t utf8_len = 0;
|
||||
while (CBS_len(&cbs) != 0) {
|
||||
uint32_t c;
|
||||
if (!decode_func(&cbs, &c)) {
|
||||
OPENSSL_PUT_ERROR(ASN1, error);
|
||||
return -1;
|
||||
}
|
||||
if (nchar == 0 &&
|
||||
(inform == MBSTRING_BMP || inform == MBSTRING_UNIV) &&
|
||||
c == 0xfeff) {
|
||||
/* Reject byte-order mark. We could drop it but that would mean
|
||||
* adding ambiguity around whether a BOM was included or not when
|
||||
* matching strings.
|
||||
*
|
||||
* For a little-endian UCS-2 string, the BOM will appear as 0xfffe
|
||||
* and will be rejected as noncharacter, below. */
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_CHARACTERS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Update which output formats are still possible. */
|
||||
if ((mask & B_ASN1_PRINTABLESTRING) && !is_printable(c)) {
|
||||
mask &= ~B_ASN1_PRINTABLESTRING;
|
||||
}
|
||||
if ((mask & B_ASN1_IA5STRING) && (c > 127)) {
|
||||
mask &= ~B_ASN1_IA5STRING;
|
||||
}
|
||||
if ((mask & B_ASN1_T61STRING) && (c > 0xff)) {
|
||||
mask &= ~B_ASN1_T61STRING;
|
||||
}
|
||||
if ((mask & B_ASN1_BMPSTRING) && (c > 0xffff)) {
|
||||
mask &= ~B_ASN1_BMPSTRING;
|
||||
}
|
||||
if (!mask) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_CHARACTERS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
nchar++;
|
||||
utf8_len += cbb_get_utf8_len(c);
|
||||
}
|
||||
|
||||
if (minsize > 0 && nchar < (size_t)minsize) {
|
||||
if ((minsize > 0) && (nchar < minsize)) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_STRING_TOO_SHORT);
|
||||
BIO_snprintf(strbuf, sizeof strbuf, "%ld", minsize);
|
||||
ERR_add_error_data(2, "minsize=", strbuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (maxsize > 0 && nchar > (size_t)maxsize) {
|
||||
if ((maxsize > 0) && (nchar > maxsize)) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_STRING_TOO_LONG);
|
||||
BIO_snprintf(strbuf, sizeof strbuf, "%ld", maxsize);
|
||||
ERR_add_error_data(2, "maxsize=", strbuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Now work out minimal type (if any) */
|
||||
if (traverse_string(in, len, inform, type_str, &mask) < 0) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_CHARACTERS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Now work out output format and string type */
|
||||
int (*encode_func)(CBB *, uint32_t) = cbb_add_latin1;
|
||||
size_t size_estimate = nchar;
|
||||
int outform = MBSTRING_ASC;
|
||||
if (mask & B_ASN1_PRINTABLESTRING) {
|
||||
outform = MBSTRING_ASC;
|
||||
if (mask & B_ASN1_PRINTABLESTRING)
|
||||
str_type = V_ASN1_PRINTABLESTRING;
|
||||
} else if (mask & B_ASN1_IA5STRING) {
|
||||
else if (mask & B_ASN1_IA5STRING)
|
||||
str_type = V_ASN1_IA5STRING;
|
||||
} else if (mask & B_ASN1_T61STRING) {
|
||||
else if (mask & B_ASN1_T61STRING)
|
||||
str_type = V_ASN1_T61STRING;
|
||||
} else if (mask & B_ASN1_BMPSTRING) {
|
||||
else if (mask & B_ASN1_BMPSTRING) {
|
||||
str_type = V_ASN1_BMPSTRING;
|
||||
outform = MBSTRING_BMP;
|
||||
encode_func = cbb_add_ucs2_be;
|
||||
size_estimate = 2 * nchar;
|
||||
} else if (mask & B_ASN1_UNIVERSALSTRING) {
|
||||
str_type = V_ASN1_UNIVERSALSTRING;
|
||||
encode_func = cbb_add_utf32_be;
|
||||
size_estimate = 4 * nchar;
|
||||
outform = MBSTRING_UNIV;
|
||||
} else {
|
||||
str_type = V_ASN1_UTF8STRING;
|
||||
outform = MBSTRING_UTF8;
|
||||
encode_func = cbb_add_utf8;
|
||||
size_estimate = utf8_len;
|
||||
}
|
||||
|
||||
if (!out)
|
||||
return str_type;
|
||||
if (*out) {
|
||||
@@ -235,7 +202,6 @@ int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
|
||||
}
|
||||
*out = dest;
|
||||
}
|
||||
|
||||
/* If both the same type just copy across */
|
||||
if (inform == outform) {
|
||||
if (!ASN1_STRING_set(dest, in, len)) {
|
||||
@@ -245,45 +211,183 @@ int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
|
||||
return str_type;
|
||||
}
|
||||
|
||||
CBB cbb;
|
||||
if (!CBB_init(&cbb, size_estimate + 1)) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
/* Work out how much space the destination will need */
|
||||
switch (outform) {
|
||||
case MBSTRING_ASC:
|
||||
outlen = nchar;
|
||||
cpyfunc = cpy_asc;
|
||||
break;
|
||||
|
||||
case MBSTRING_BMP:
|
||||
outlen = nchar << 1;
|
||||
cpyfunc = cpy_bmp;
|
||||
break;
|
||||
|
||||
case MBSTRING_UNIV:
|
||||
outlen = nchar << 2;
|
||||
cpyfunc = cpy_univ;
|
||||
break;
|
||||
|
||||
case MBSTRING_UTF8:
|
||||
outlen = 0;
|
||||
traverse_string(in, len, inform, out_utf8, &outlen);
|
||||
cpyfunc = cpy_utf8;
|
||||
break;
|
||||
}
|
||||
CBS_init(&cbs, in, len);
|
||||
while (CBS_len(&cbs) != 0) {
|
||||
uint32_t c;
|
||||
if (!decode_func(&cbs, &c) ||
|
||||
!encode_func(&cbb, c)) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
if (!(p = OPENSSL_malloc(outlen + 1))) {
|
||||
if (free_out)
|
||||
ASN1_STRING_free(dest);
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
return -1;
|
||||
}
|
||||
dest->length = outlen;
|
||||
dest->data = p;
|
||||
p[outlen] = 0;
|
||||
traverse_string(in, len, inform, cpyfunc, &p);
|
||||
return str_type;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function traverses a string and passes the value of each character to
|
||||
* an optional function along with a void * argument.
|
||||
*/
|
||||
|
||||
static int traverse_string(const unsigned char *p, int len, int inform,
|
||||
int (*rfunc) (unsigned long value, void *in),
|
||||
void *arg)
|
||||
{
|
||||
unsigned long value;
|
||||
int ret;
|
||||
while (len) {
|
||||
if (inform == MBSTRING_ASC) {
|
||||
value = *p++;
|
||||
len--;
|
||||
} else if (inform == MBSTRING_BMP) {
|
||||
value = *p++ << 8;
|
||||
value |= *p++;
|
||||
len -= 2;
|
||||
} else if (inform == MBSTRING_UNIV) {
|
||||
value = ((unsigned long)*p++) << 24;
|
||||
value |= ((unsigned long)*p++) << 16;
|
||||
value |= *p++ << 8;
|
||||
value |= *p++;
|
||||
len -= 4;
|
||||
} else {
|
||||
ret = UTF8_getc(p, len, &value);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
len -= ret;
|
||||
p += ret;
|
||||
}
|
||||
if (rfunc) {
|
||||
ret = rfunc(value, arg);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
uint8_t *data = NULL;
|
||||
size_t data_len;
|
||||
if (/* OpenSSL historically NUL-terminated this value with a single byte,
|
||||
* even for |MBSTRING_BMP| and |MBSTRING_UNIV|. */
|
||||
!CBB_add_u8(&cbb, 0) ||
|
||||
!CBB_finish(&cbb, &data, &data_len) ||
|
||||
data_len < 1 ||
|
||||
data_len > INT_MAX) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_INTERNAL_ERROR);
|
||||
OPENSSL_free(data);
|
||||
goto err;
|
||||
}
|
||||
dest->length = (int)(data_len - 1);
|
||||
dest->data = data;
|
||||
return str_type;
|
||||
return 1;
|
||||
}
|
||||
|
||||
err:
|
||||
if (free_out)
|
||||
ASN1_STRING_free(dest);
|
||||
CBB_cleanup(&cbb);
|
||||
return -1;
|
||||
/* Various utility functions for traverse_string */
|
||||
|
||||
/* Just count number of characters */
|
||||
|
||||
static int in_utf8(unsigned long value, void *arg)
|
||||
{
|
||||
int *nchar;
|
||||
nchar = arg;
|
||||
(*nchar)++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Determine size of output as a UTF8 String */
|
||||
|
||||
static int out_utf8(unsigned long value, void *arg)
|
||||
{
|
||||
int *outlen;
|
||||
outlen = arg;
|
||||
*outlen += UTF8_putc(NULL, -1, value);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine the "type" of a string: check each character against a supplied
|
||||
* "mask".
|
||||
*/
|
||||
|
||||
static int type_str(unsigned long value, void *arg)
|
||||
{
|
||||
unsigned long types;
|
||||
types = *((unsigned long *)arg);
|
||||
if ((types & B_ASN1_PRINTABLESTRING) && !is_printable(value))
|
||||
types &= ~B_ASN1_PRINTABLESTRING;
|
||||
if ((types & B_ASN1_IA5STRING) && (value > 127))
|
||||
types &= ~B_ASN1_IA5STRING;
|
||||
if ((types & B_ASN1_T61STRING) && (value > 0xff))
|
||||
types &= ~B_ASN1_T61STRING;
|
||||
if ((types & B_ASN1_BMPSTRING) && (value > 0xffff))
|
||||
types &= ~B_ASN1_BMPSTRING;
|
||||
if (!types)
|
||||
return -1;
|
||||
*((unsigned long *)arg) = types;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Copy one byte per character ASCII like strings */
|
||||
|
||||
static int cpy_asc(unsigned long value, void *arg)
|
||||
{
|
||||
unsigned char **p, *q;
|
||||
p = arg;
|
||||
q = *p;
|
||||
*q = (unsigned char)value;
|
||||
(*p)++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Copy two byte per character BMPStrings */
|
||||
|
||||
static int cpy_bmp(unsigned long value, void *arg)
|
||||
{
|
||||
unsigned char **p, *q;
|
||||
p = arg;
|
||||
q = *p;
|
||||
*q++ = (unsigned char)((value >> 8) & 0xff);
|
||||
*q = (unsigned char)(value & 0xff);
|
||||
*p += 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Copy four byte per character UniversalStrings */
|
||||
|
||||
static int cpy_univ(unsigned long value, void *arg)
|
||||
{
|
||||
unsigned char **p, *q;
|
||||
p = arg;
|
||||
q = *p;
|
||||
*q++ = (unsigned char)((value >> 24) & 0xff);
|
||||
*q++ = (unsigned char)((value >> 16) & 0xff);
|
||||
*q++ = (unsigned char)((value >> 8) & 0xff);
|
||||
*q = (unsigned char)(value & 0xff);
|
||||
*p += 4;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Copy to a UTF8String */
|
||||
|
||||
static int cpy_utf8(unsigned long value, void *arg)
|
||||
{
|
||||
unsigned char **p;
|
||||
int ret;
|
||||
p = arg;
|
||||
/* We already know there is enough room so pass 0xff as the length */
|
||||
ret = UTF8_putc(*p, 0xff, value);
|
||||
*p += ret;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Return 1 if the character is permitted in a PrintableString */
|
||||
static int is_printable(uint32_t value)
|
||||
static int is_printable(unsigned long value)
|
||||
{
|
||||
int ch;
|
||||
if (value > 0x7f)
|
||||
|
||||
+133
-16
@@ -68,7 +68,7 @@
|
||||
|
||||
int i2d_ASN1_OBJECT(ASN1_OBJECT *a, unsigned char **pp)
|
||||
{
|
||||
unsigned char *p, *allocated = NULL;
|
||||
unsigned char *p;
|
||||
int objsize;
|
||||
|
||||
if ((a == NULL) || (a->data == NULL))
|
||||
@@ -78,24 +78,141 @@ int i2d_ASN1_OBJECT(ASN1_OBJECT *a, unsigned char **pp)
|
||||
if (pp == NULL || objsize == -1)
|
||||
return objsize;
|
||||
|
||||
if (*pp == NULL) {
|
||||
if ((p = allocated = OPENSSL_malloc(objsize)) == NULL) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
p = *pp;
|
||||
}
|
||||
|
||||
p = *pp;
|
||||
ASN1_put_object(&p, 0, a->length, V_ASN1_OBJECT, V_ASN1_UNIVERSAL);
|
||||
OPENSSL_memcpy(p, a->data, a->length);
|
||||
p += a->length;
|
||||
|
||||
/*
|
||||
* If a new buffer was allocated, just return it back.
|
||||
* If not, return the incremented buffer pointer.
|
||||
*/
|
||||
*pp = allocated != NULL ? allocated : p + a->length;
|
||||
return objsize;
|
||||
*pp = p;
|
||||
return (objsize);
|
||||
}
|
||||
|
||||
int a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num)
|
||||
{
|
||||
int i, first, len = 0, c, use_bn;
|
||||
char ftmp[24], *tmp = ftmp;
|
||||
int tmpsize = sizeof ftmp;
|
||||
const char *p;
|
||||
unsigned long l;
|
||||
BIGNUM *bl = NULL;
|
||||
|
||||
if (num == 0)
|
||||
return (0);
|
||||
else if (num == -1)
|
||||
num = strlen(buf);
|
||||
|
||||
p = buf;
|
||||
c = *(p++);
|
||||
num--;
|
||||
if ((c >= '0') && (c <= '2')) {
|
||||
first = c - '0';
|
||||
} else {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_FIRST_NUM_TOO_LARGE);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (num <= 0) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_SECOND_NUMBER);
|
||||
goto err;
|
||||
}
|
||||
c = *(p++);
|
||||
num--;
|
||||
for (;;) {
|
||||
if (num <= 0)
|
||||
break;
|
||||
if ((c != '.') && (c != ' ')) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_SEPARATOR);
|
||||
goto err;
|
||||
}
|
||||
l = 0;
|
||||
use_bn = 0;
|
||||
for (;;) {
|
||||
if (num <= 0)
|
||||
break;
|
||||
num--;
|
||||
c = *(p++);
|
||||
if ((c == ' ') || (c == '.'))
|
||||
break;
|
||||
if ((c < '0') || (c > '9')) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_DIGIT);
|
||||
goto err;
|
||||
}
|
||||
if (!use_bn && l >= ((ULONG_MAX - 80) / 10L)) {
|
||||
use_bn = 1;
|
||||
if (!bl)
|
||||
bl = BN_new();
|
||||
if (!bl || !BN_set_word(bl, l))
|
||||
goto err;
|
||||
}
|
||||
if (use_bn) {
|
||||
if (!BN_mul_word(bl, 10L)
|
||||
|| !BN_add_word(bl, c - '0'))
|
||||
goto err;
|
||||
} else
|
||||
l = l * 10L + (long)(c - '0');
|
||||
}
|
||||
if (len == 0) {
|
||||
if ((first < 2) && (l >= 40)) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_SECOND_NUMBER_TOO_LARGE);
|
||||
goto err;
|
||||
}
|
||||
if (use_bn) {
|
||||
if (!BN_add_word(bl, first * 40))
|
||||
goto err;
|
||||
} else
|
||||
l += (long)first *40;
|
||||
}
|
||||
i = 0;
|
||||
if (use_bn) {
|
||||
int blsize;
|
||||
blsize = BN_num_bits(bl);
|
||||
blsize = (blsize + 6) / 7;
|
||||
if (blsize > tmpsize) {
|
||||
if (tmp != ftmp)
|
||||
OPENSSL_free(tmp);
|
||||
tmpsize = blsize + 32;
|
||||
tmp = OPENSSL_malloc(tmpsize);
|
||||
if (!tmp)
|
||||
goto err;
|
||||
}
|
||||
while (blsize--) {
|
||||
BN_ULONG t = BN_div_word(bl, 0x80L);
|
||||
if (t == (BN_ULONG)-1)
|
||||
goto err;
|
||||
tmp[i++] = (unsigned char)t;
|
||||
}
|
||||
} else {
|
||||
|
||||
for (;;) {
|
||||
tmp[i++] = (unsigned char)l & 0x7f;
|
||||
l >>= 7L;
|
||||
if (l == 0L)
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if (out != NULL) {
|
||||
if (len + i > olen) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_BUFFER_TOO_SMALL);
|
||||
goto err;
|
||||
}
|
||||
while (--i > 0)
|
||||
out[len++] = tmp[i] | 0x80;
|
||||
out[len++] = tmp[0];
|
||||
} else
|
||||
len += i;
|
||||
}
|
||||
if (tmp != ftmp)
|
||||
OPENSSL_free(tmp);
|
||||
if (bl)
|
||||
BN_free(bl);
|
||||
return (len);
|
||||
err:
|
||||
if (tmp != ftmp)
|
||||
OPENSSL_free(tmp);
|
||||
if (bl)
|
||||
BN_free(bl);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int i2t_ASN1_OBJECT(char *buf, int buf_len, ASN1_OBJECT *a)
|
||||
|
||||
@@ -223,7 +223,6 @@ ASN1_STRING_TABLE *ASN1_STRING_TABLE_get(int nid)
|
||||
return ttmp;
|
||||
if (!stable)
|
||||
return NULL;
|
||||
sk_ASN1_STRING_TABLE_sort(stable);
|
||||
found = sk_ASN1_STRING_TABLE_find(stable, &idx, &fnd);
|
||||
if (!found)
|
||||
return NULL;
|
||||
|
||||
+11
-13
@@ -59,8 +59,6 @@
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "asn1_locl.h"
|
||||
|
||||
/* UTF8 utilities */
|
||||
|
||||
/*
|
||||
@@ -72,10 +70,10 @@
|
||||
* incorrectly (not minimal length).
|
||||
*/
|
||||
|
||||
int UTF8_getc(const unsigned char *str, int len, uint32_t *val)
|
||||
int UTF8_getc(const unsigned char *str, int len, unsigned long *val)
|
||||
{
|
||||
const unsigned char *p;
|
||||
uint32_t value;
|
||||
unsigned long value;
|
||||
int ret;
|
||||
if (len <= 0)
|
||||
return 0;
|
||||
@@ -114,7 +112,7 @@ int UTF8_getc(const unsigned char *str, int len, uint32_t *val)
|
||||
|| ((p[2] & 0xc0) != 0x80)
|
||||
|| ((p[3] & 0xc0) != 0x80))
|
||||
return -3;
|
||||
value = ((uint32_t)(*p++ & 0x7)) << 18;
|
||||
value = ((unsigned long)(*p++ & 0x7)) << 18;
|
||||
value |= (*p++ & 0x3f) << 12;
|
||||
value |= (*p++ & 0x3f) << 6;
|
||||
value |= *p++ & 0x3f;
|
||||
@@ -129,9 +127,9 @@ int UTF8_getc(const unsigned char *str, int len, uint32_t *val)
|
||||
|| ((p[3] & 0xc0) != 0x80)
|
||||
|| ((p[4] & 0xc0) != 0x80))
|
||||
return -3;
|
||||
value = ((uint32_t)(*p++ & 0x3)) << 24;
|
||||
value |= ((uint32_t)(*p++ & 0x3f)) << 18;
|
||||
value |= ((uint32_t)(*p++ & 0x3f)) << 12;
|
||||
value = ((unsigned long)(*p++ & 0x3)) << 24;
|
||||
value |= ((unsigned long)(*p++ & 0x3f)) << 18;
|
||||
value |= ((unsigned long)(*p++ & 0x3f)) << 12;
|
||||
value |= (*p++ & 0x3f) << 6;
|
||||
value |= *p++ & 0x3f;
|
||||
if (value < 0x200000)
|
||||
@@ -146,10 +144,10 @@ int UTF8_getc(const unsigned char *str, int len, uint32_t *val)
|
||||
|| ((p[4] & 0xc0) != 0x80)
|
||||
|| ((p[5] & 0xc0) != 0x80))
|
||||
return -3;
|
||||
value = ((uint32_t)(*p++ & 0x1)) << 30;
|
||||
value |= ((uint32_t)(*p++ & 0x3f)) << 24;
|
||||
value |= ((uint32_t)(*p++ & 0x3f)) << 18;
|
||||
value |= ((uint32_t)(*p++ & 0x3f)) << 12;
|
||||
value = ((unsigned long)(*p++ & 0x1)) << 30;
|
||||
value |= ((unsigned long)(*p++ & 0x3f)) << 24;
|
||||
value |= ((unsigned long)(*p++ & 0x3f)) << 18;
|
||||
value |= ((unsigned long)(*p++ & 0x3f)) << 12;
|
||||
value |= (*p++ & 0x3f) << 6;
|
||||
value |= *p++ & 0x3f;
|
||||
if (value < 0x4000000)
|
||||
@@ -169,7 +167,7 @@ int UTF8_getc(const unsigned char *str, int len, uint32_t *val)
|
||||
* most 6 characters.
|
||||
*/
|
||||
|
||||
int UTF8_putc(unsigned char *str, int len, uint32_t value)
|
||||
int UTF8_putc(unsigned char *str, int len, unsigned long value)
|
||||
{
|
||||
if (!str)
|
||||
len = 6; /* Maximum we will need */
|
||||
|
||||
@@ -90,12 +90,6 @@ int OPENSSL_gmtime_diff(int *out_days, int *out_secs, const struct tm *from,
|
||||
int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d);
|
||||
int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d);
|
||||
|
||||
void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it,
|
||||
int combine);
|
||||
|
||||
int UTF8_getc(const unsigned char *str, int len, uint32_t *val);
|
||||
int UTF8_putc(unsigned char *str, int len, uint32_t value);
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} /* extern C */
|
||||
|
||||
@@ -12,20 +12,12 @@
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/asn1t.h>
|
||||
#include <openssl/bytestring.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/obj.h>
|
||||
#include <openssl/span.h>
|
||||
|
||||
#include "../test/test_util.h"
|
||||
|
||||
@@ -68,119 +60,3 @@ TEST(ASN1Test, LargeTags) {
|
||||
EXPECT_EQ(Bytes(&kZero, 1), Bytes(obj->value.asn1_string->data,
|
||||
obj->value.asn1_string->length));
|
||||
}
|
||||
|
||||
TEST(ASN1Test, IntegerSetting) {
|
||||
bssl::UniquePtr<ASN1_INTEGER> by_bn(M_ASN1_INTEGER_new());
|
||||
bssl::UniquePtr<ASN1_INTEGER> by_long(M_ASN1_INTEGER_new());
|
||||
bssl::UniquePtr<ASN1_INTEGER> by_uint64(M_ASN1_INTEGER_new());
|
||||
bssl::UniquePtr<BIGNUM> bn(BN_new());
|
||||
|
||||
const std::vector<int64_t> kValues = {
|
||||
LONG_MIN, -2, -1, 0, 1, 2, 0xff, 0x100, 0xffff, 0x10000, LONG_MAX,
|
||||
};
|
||||
for (const auto &i : kValues) {
|
||||
SCOPED_TRACE(i);
|
||||
|
||||
ASSERT_EQ(1, ASN1_INTEGER_set(by_long.get(), i));
|
||||
const uint64_t abs = i < 0 ? (0 - (uint64_t) i) : i;
|
||||
ASSERT_TRUE(BN_set_u64(bn.get(), abs));
|
||||
BN_set_negative(bn.get(), i < 0);
|
||||
ASSERT_TRUE(BN_to_ASN1_INTEGER(bn.get(), by_bn.get()));
|
||||
|
||||
EXPECT_EQ(0, ASN1_INTEGER_cmp(by_bn.get(), by_long.get()));
|
||||
|
||||
if (i >= 0) {
|
||||
ASSERT_EQ(1, ASN1_INTEGER_set_uint64(by_uint64.get(), i));
|
||||
EXPECT_EQ(0, ASN1_INTEGER_cmp(by_bn.get(), by_uint64.get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct asn1_linked_list_st {
|
||||
struct asn1_linked_list_st *next;
|
||||
} ASN1_LINKED_LIST;
|
||||
|
||||
DECLARE_ASN1_ITEM(ASN1_LINKED_LIST)
|
||||
DECLARE_ASN1_FUNCTIONS(ASN1_LINKED_LIST)
|
||||
|
||||
ASN1_SEQUENCE(ASN1_LINKED_LIST) = {
|
||||
ASN1_OPT(ASN1_LINKED_LIST, next, ASN1_LINKED_LIST),
|
||||
} ASN1_SEQUENCE_END(ASN1_LINKED_LIST)
|
||||
|
||||
IMPLEMENT_ASN1_FUNCTIONS(ASN1_LINKED_LIST)
|
||||
|
||||
static bool MakeLinkedList(bssl::UniquePtr<uint8_t> *out, size_t *out_len,
|
||||
size_t count) {
|
||||
bssl::ScopedCBB cbb;
|
||||
std::vector<CBB> cbbs(count);
|
||||
if (!CBB_init(cbb.get(), 2 * count) ||
|
||||
!CBB_add_asn1(cbb.get(), &cbbs[0], CBS_ASN1_SEQUENCE)) {
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 1; i < count; i++) {
|
||||
if (!CBB_add_asn1(&cbbs[i - 1], &cbbs[i], CBS_ASN1_SEQUENCE)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
uint8_t *ptr;
|
||||
if (!CBB_finish(cbb.get(), &ptr, out_len)) {
|
||||
return false;
|
||||
}
|
||||
out->reset(ptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(ASN1Test, Recursive) {
|
||||
bssl::UniquePtr<uint8_t> data;
|
||||
size_t len;
|
||||
|
||||
// Sanity-check that MakeLinkedList can be parsed.
|
||||
ASSERT_TRUE(MakeLinkedList(&data, &len, 5));
|
||||
const uint8_t *ptr = data.get();
|
||||
ASN1_LINKED_LIST *list = d2i_ASN1_LINKED_LIST(nullptr, &ptr, len);
|
||||
EXPECT_TRUE(list);
|
||||
ASN1_LINKED_LIST_free(list);
|
||||
|
||||
// Excessively deep structures are rejected.
|
||||
ASSERT_TRUE(MakeLinkedList(&data, &len, 100));
|
||||
ptr = data.get();
|
||||
list = d2i_ASN1_LINKED_LIST(nullptr, &ptr, len);
|
||||
EXPECT_FALSE(list);
|
||||
// Note checking the error queue here does not work. The error "stack trace"
|
||||
// is too deep, so the |ASN1_R_NESTED_TOO_DEEP| entry drops off the queue.
|
||||
ASN1_LINKED_LIST_free(list);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void TestSerialize(T obj, int (*i2d_func)(T a, uint8_t **pp),
|
||||
bssl::Span<const uint8_t> expected) {
|
||||
int len = static_cast<int>(expected.size());
|
||||
ASSERT_EQ(i2d_func(obj, nullptr), len);
|
||||
|
||||
std::vector<uint8_t> buf(expected.size());
|
||||
uint8_t *ptr = buf.data();
|
||||
ASSERT_EQ(i2d_func(obj, &ptr), len);
|
||||
EXPECT_EQ(ptr, buf.data() + buf.size());
|
||||
EXPECT_EQ(Bytes(expected), Bytes(buf));
|
||||
|
||||
// Test the allocating version.
|
||||
ptr = nullptr;
|
||||
ASSERT_EQ(i2d_func(obj, &ptr), len);
|
||||
EXPECT_EQ(Bytes(expected), Bytes(ptr, expected.size()));
|
||||
OPENSSL_free(ptr);
|
||||
}
|
||||
|
||||
TEST(ASN1Test, SerializeObject) {
|
||||
static const uint8_t kDER[] = {0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
|
||||
0xf7, 0x0d, 0x01, 0x01, 0x01};
|
||||
const ASN1_OBJECT *obj = OBJ_nid2obj(NID_rsaEncryption);
|
||||
TestSerialize(const_cast<ASN1_OBJECT *>(obj), i2d_ASN1_OBJECT, kDER);
|
||||
}
|
||||
|
||||
TEST(ASN1Test, SerializeBoolean) {
|
||||
static const uint8_t kTrue[] = {0x01, 0x01, 0xff};
|
||||
TestSerialize(0xff, i2d_ASN1_BOOLEAN, kTrue);
|
||||
|
||||
static const uint8_t kFalse[] = {0x01, 0x01, 0x00};
|
||||
TestSerialize(0x00, i2d_ASN1_BOOLEAN, kFalse);
|
||||
}
|
||||
|
||||
+19
-40
@@ -66,14 +66,6 @@
|
||||
|
||||
#include "../internal.h"
|
||||
|
||||
/*
|
||||
* Constructed types with a recursive definition (such as can be found in PKCS7)
|
||||
* could eventually exceed the stack given malicious input with excessive
|
||||
* recursion. Therefore we limit the stack depth. This is the maximum number of
|
||||
* recursive invocations of asn1_item_embed_d2i().
|
||||
*/
|
||||
#define ASN1_MAX_CONSTRUCTED_NEST 30
|
||||
|
||||
static int asn1_check_eoc(const unsigned char **in, long len);
|
||||
static int asn1_find_end(const unsigned char **in, long len, char inf);
|
||||
|
||||
@@ -90,11 +82,11 @@ static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass,
|
||||
static int asn1_template_ex_d2i(ASN1_VALUE **pval,
|
||||
const unsigned char **in, long len,
|
||||
const ASN1_TEMPLATE *tt, char opt,
|
||||
ASN1_TLC *ctx, int depth);
|
||||
ASN1_TLC *ctx);
|
||||
static int asn1_template_noexp_d2i(ASN1_VALUE **val,
|
||||
const unsigned char **in, long len,
|
||||
const ASN1_TEMPLATE *tt, char opt,
|
||||
ASN1_TLC *ctx, int depth);
|
||||
ASN1_TLC *ctx);
|
||||
static int asn1_d2i_ex_primitive(ASN1_VALUE **pval,
|
||||
const unsigned char **in, long len,
|
||||
const ASN1_ITEM *it,
|
||||
@@ -161,9 +153,9 @@ ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **pval,
|
||||
* tag mismatch return -1 to handle OPTIONAL
|
||||
*/
|
||||
|
||||
static int asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in,
|
||||
long len, const ASN1_ITEM *it, int tag, int aclass,
|
||||
char opt, ASN1_TLC *ctx, int depth)
|
||||
int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
|
||||
const ASN1_ITEM *it,
|
||||
int tag, int aclass, char opt, ASN1_TLC *ctx)
|
||||
{
|
||||
const ASN1_TEMPLATE *tt, *errtt = NULL;
|
||||
const ASN1_COMPAT_FUNCS *cf;
|
||||
@@ -196,11 +188,6 @@ static int asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in,
|
||||
len = INT_MAX/2;
|
||||
}
|
||||
|
||||
if (++depth > ASN1_MAX_CONSTRUCTED_NEST) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_TOO_DEEP);
|
||||
goto err;
|
||||
}
|
||||
|
||||
switch (it->itype) {
|
||||
case ASN1_ITYPE_PRIMITIVE:
|
||||
if (it->templates) {
|
||||
@@ -216,7 +203,7 @@ static int asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in,
|
||||
goto err;
|
||||
}
|
||||
return asn1_template_ex_d2i(pval, in, len,
|
||||
it->templates, opt, ctx, depth);
|
||||
it->templates, opt, ctx);
|
||||
}
|
||||
return asn1_d2i_ex_primitive(pval, in, len, it,
|
||||
tag, aclass, opt, ctx);
|
||||
@@ -339,7 +326,7 @@ static int asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in,
|
||||
/*
|
||||
* We mark field as OPTIONAL so its absence can be recognised.
|
||||
*/
|
||||
ret = asn1_template_ex_d2i(pchptr, &p, len, tt, 1, ctx, depth);
|
||||
ret = asn1_template_ex_d2i(pchptr, &p, len, tt, 1, ctx);
|
||||
/* If field not present, try the next one */
|
||||
if (ret == -1)
|
||||
continue;
|
||||
@@ -457,8 +444,7 @@ static int asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in,
|
||||
* attempt to read in field, allowing each to be OPTIONAL
|
||||
*/
|
||||
|
||||
ret = asn1_template_ex_d2i(pseqval, &p, len, seqtt, isopt, ctx,
|
||||
depth);
|
||||
ret = asn1_template_ex_d2i(pseqval, &p, len, seqtt, isopt, ctx);
|
||||
if (!ret) {
|
||||
errtt = seqtt;
|
||||
goto err;
|
||||
@@ -528,13 +514,6 @@ static int asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
|
||||
const ASN1_ITEM *it,
|
||||
int tag, int aclass, char opt, ASN1_TLC *ctx)
|
||||
{
|
||||
return asn1_item_ex_d2i(pval, in, len, it, tag, aclass, opt, ctx, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Templates are handled with two separate functions. One handles any
|
||||
* EXPLICIT tag and the other handles the rest.
|
||||
@@ -543,7 +522,7 @@ int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len,
|
||||
static int asn1_template_ex_d2i(ASN1_VALUE **val,
|
||||
const unsigned char **in, long inlen,
|
||||
const ASN1_TEMPLATE *tt, char opt,
|
||||
ASN1_TLC *ctx, int depth)
|
||||
ASN1_TLC *ctx)
|
||||
{
|
||||
int flags, aclass;
|
||||
int ret;
|
||||
@@ -577,7 +556,7 @@ static int asn1_template_ex_d2i(ASN1_VALUE **val,
|
||||
return 0;
|
||||
}
|
||||
/* We've found the field so it can't be OPTIONAL now */
|
||||
ret = asn1_template_noexp_d2i(val, &p, len, tt, 0, ctx, depth);
|
||||
ret = asn1_template_noexp_d2i(val, &p, len, tt, 0, ctx);
|
||||
if (!ret) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
|
||||
return 0;
|
||||
@@ -600,7 +579,7 @@ static int asn1_template_ex_d2i(ASN1_VALUE **val,
|
||||
}
|
||||
}
|
||||
} else
|
||||
return asn1_template_noexp_d2i(val, in, inlen, tt, opt, ctx, depth);
|
||||
return asn1_template_noexp_d2i(val, in, inlen, tt, opt, ctx);
|
||||
|
||||
*in = p;
|
||||
return 1;
|
||||
@@ -613,7 +592,7 @@ static int asn1_template_ex_d2i(ASN1_VALUE **val,
|
||||
static int asn1_template_noexp_d2i(ASN1_VALUE **val,
|
||||
const unsigned char **in, long len,
|
||||
const ASN1_TEMPLATE *tt, char opt,
|
||||
ASN1_TLC *ctx, int depth)
|
||||
ASN1_TLC *ctx)
|
||||
{
|
||||
int flags, aclass;
|
||||
int ret;
|
||||
@@ -682,8 +661,8 @@ static int asn1_template_noexp_d2i(ASN1_VALUE **val,
|
||||
break;
|
||||
}
|
||||
skfield = NULL;
|
||||
if (!asn1_item_ex_d2i(&skfield, &p, len, ASN1_ITEM_ptr(tt->item),
|
||||
-1, 0, 0, ctx, depth)) {
|
||||
if (!ASN1_item_ex_d2i(&skfield, &p, len,
|
||||
ASN1_ITEM_ptr(tt->item), -1, 0, 0, ctx)) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
|
||||
goto err;
|
||||
}
|
||||
@@ -700,8 +679,9 @@ static int asn1_template_noexp_d2i(ASN1_VALUE **val,
|
||||
}
|
||||
} else if (flags & ASN1_TFLG_IMPTAG) {
|
||||
/* IMPLICIT tagging */
|
||||
ret = asn1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item), tt->tag,
|
||||
aclass, opt, ctx, depth);
|
||||
ret = ASN1_item_ex_d2i(val, &p, len,
|
||||
ASN1_ITEM_ptr(tt->item), tt->tag, aclass, opt,
|
||||
ctx);
|
||||
if (!ret) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
|
||||
goto err;
|
||||
@@ -709,9 +689,8 @@ static int asn1_template_noexp_d2i(ASN1_VALUE **val,
|
||||
return -1;
|
||||
} else {
|
||||
/* Nothing special */
|
||||
ret = asn1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item),
|
||||
-1, tt->flags & ASN1_TFLG_COMBINE, opt, ctx,
|
||||
depth);
|
||||
ret = ASN1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item),
|
||||
-1, tt->flags & ASN1_TFLG_COMBINE, opt, ctx);
|
||||
if (!ret) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR);
|
||||
goto err;
|
||||
|
||||
@@ -583,8 +583,6 @@ int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype,
|
||||
otmp = (ASN1_OBJECT *)*pval;
|
||||
cont = otmp->data;
|
||||
len = otmp->length;
|
||||
if (cont == NULL || len == 0)
|
||||
return -1;
|
||||
break;
|
||||
|
||||
case V_ASN1_NULL:
|
||||
|
||||
@@ -59,7 +59,8 @@
|
||||
#include <openssl/asn1t.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "asn1_locl.h"
|
||||
static void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it,
|
||||
int combine);
|
||||
|
||||
/* Free up an ASN1 structure */
|
||||
|
||||
@@ -73,7 +74,8 @@ void ASN1_item_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
|
||||
asn1_item_combine_free(pval, it, 0);
|
||||
}
|
||||
|
||||
void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it, int combine)
|
||||
static void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it,
|
||||
int combine)
|
||||
{
|
||||
const ASN1_TEMPLATE *tt = NULL, *seqtt;
|
||||
const ASN1_EXTERN_FUNCS *ef;
|
||||
|
||||
@@ -63,7 +63,6 @@
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/obj.h>
|
||||
|
||||
#include "asn1_locl.h"
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
@@ -202,7 +201,7 @@ static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it,
|
||||
return 1;
|
||||
|
||||
memerr2:
|
||||
asn1_item_combine_free(pval, it, combine);
|
||||
ASN1_item_ex_free(pval, it);
|
||||
memerr:
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
#ifdef CRYPTO_MDEBUG
|
||||
@@ -212,7 +211,7 @@ static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it,
|
||||
return 0;
|
||||
|
||||
auxerr2:
|
||||
asn1_item_combine_free(pval, it, combine);
|
||||
ASN1_item_ex_free(pval, it);
|
||||
auxerr:
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_AUX_ERROR);
|
||||
#ifdef CRYPTO_MDEBUG
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
|
||||
#if !defined(OPENSSL_WINDOWS)
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -56,8 +56,6 @@
|
||||
|
||||
#include <openssl/bio.h>
|
||||
|
||||
#if !defined(OPENSSL_TRUSTY)
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
@@ -542,5 +540,3 @@ int BIO_set_nbio(BIO *bio, int on) {
|
||||
int BIO_do_connect(BIO *bio) {
|
||||
return BIO_ctrl(bio, BIO_C_DO_STATE_MACHINE, 0, NULL);
|
||||
}
|
||||
|
||||
#endif // OPENSSL_TRUSTY
|
||||
|
||||
@@ -56,8 +56,6 @@
|
||||
|
||||
#include <openssl/bio.h>
|
||||
|
||||
#if !defined(OPENSSL_TRUSTY)
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -75,7 +73,6 @@ OPENSSL_MSVC_PRAGMA(warning(pop))
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
static int bio_fd_non_fatal_error(int err) {
|
||||
@@ -276,5 +273,3 @@ int BIO_set_fd(BIO *bio, int fd, int close_flag) {
|
||||
int BIO_get_fd(BIO *bio, int *out_fd) {
|
||||
return BIO_ctrl(bio, BIO_C_GET_FD, 0, (char *) out_fd);
|
||||
}
|
||||
|
||||
#endif // OPENSSL_TRUSTY
|
||||
|
||||
@@ -73,8 +73,6 @@
|
||||
|
||||
#include <openssl/bio.h>
|
||||
|
||||
#if !defined(OPENSSL_TRUSTY)
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -83,8 +81,6 @@
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
#define BIO_FP_READ 0x02
|
||||
#define BIO_FP_WRITE 0x04
|
||||
@@ -315,5 +311,3 @@ int BIO_rw_filename(BIO *bio, const char *filename) {
|
||||
return BIO_ctrl(bio, BIO_C_SET_FILENAME,
|
||||
BIO_CLOSE | BIO_FP_READ | BIO_FP_WRITE, (char *)filename);
|
||||
}
|
||||
|
||||
#endif // OPENSSL_TRUSTY
|
||||
|
||||
@@ -57,8 +57,6 @@
|
||||
|
||||
#include <openssl/bio.h>
|
||||
|
||||
#if !defined(OPENSSL_TRUSTY)
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -202,5 +200,3 @@ BIO *BIO_new_socket(int fd, int close_flag) {
|
||||
BIO_set_fd(ret, fd, close_flag);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif // OPENSSL_TRUSTY
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#if !defined(OPENSSL_TRUSTY)
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
@@ -114,5 +112,3 @@ int bio_sock_error(int sock) {
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
#endif // OPENSSL_TRUSTY
|
||||
|
||||
@@ -42,6 +42,22 @@ int BN_parse_asn1_unsigned(CBS *cbs, BIGNUM *ret) {
|
||||
return BN_bin2bn(CBS_data(&child), CBS_len(&child), ret) != NULL;
|
||||
}
|
||||
|
||||
int BN_parse_asn1_unsigned_buggy(CBS *cbs, BIGNUM *ret) {
|
||||
CBS child;
|
||||
if (!CBS_get_asn1(cbs, &child, CBS_ASN1_INTEGER) ||
|
||||
CBS_len(&child) == 0) {
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_BAD_ENCODING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This function intentionally does not reject negative numbers or non-minimal
|
||||
// encodings. Estonian IDs issued between September 2014 to September 2015 are
|
||||
// broken. See https://crbug.com/532048 and https://crbug.com/534766.
|
||||
//
|
||||
// TODO(davidben): Remove this code and callers in March 2016.
|
||||
return BN_bin2bn(CBS_data(&child), CBS_len(&child), ret) != NULL;
|
||||
}
|
||||
|
||||
int BN_marshal_asn1(CBB *cbb, const BIGNUM *bn) {
|
||||
// Negative numbers are unsupported.
|
||||
if (BN_is_negative(bn)) {
|
||||
|
||||
@@ -77,9 +77,8 @@ int BN_bn2cbb_padded(CBB *out, size_t len, const BIGNUM *in) {
|
||||
static const char hextable[] = "0123456789abcdef";
|
||||
|
||||
char *BN_bn2hex(const BIGNUM *bn) {
|
||||
int width = bn_minimal_width(bn);
|
||||
char *buf = OPENSSL_malloc(1 /* leading '-' */ + 1 /* zero is non-empty */ +
|
||||
width * BN_BYTES * 2 + 1 /* trailing NUL */);
|
||||
bn->top * BN_BYTES * 2 + 1 /* trailing NUL */);
|
||||
if (buf == NULL) {
|
||||
OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
|
||||
return NULL;
|
||||
@@ -95,7 +94,7 @@ char *BN_bn2hex(const BIGNUM *bn) {
|
||||
}
|
||||
|
||||
int z = 0;
|
||||
for (int i = width - 1; i >= 0; i--) {
|
||||
for (int i = bn->top - 1; i >= 0; i--) {
|
||||
for (int j = BN_BITS2 - 8; j >= 0; j -= 8) {
|
||||
// strip leading zeros
|
||||
int v = ((int)(bn->d[i] >> (long)j)) & 0xff;
|
||||
@@ -154,7 +153,7 @@ static int decode_hex(BIGNUM *bn, const char *in, int in_len) {
|
||||
in_len -= todo;
|
||||
}
|
||||
assert(i <= bn->dmax);
|
||||
bn->width = i;
|
||||
bn->top = i;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -223,7 +222,7 @@ static int bn_x2bn(BIGNUM **outp, const char *in, decode_func decode, char_test_
|
||||
goto err;
|
||||
}
|
||||
|
||||
bn_set_minimal_width(ret);
|
||||
bn_correct_top(ret);
|
||||
if (!BN_is_zero(ret)) {
|
||||
ret->neg = neg;
|
||||
}
|
||||
@@ -348,7 +347,7 @@ int BN_print(BIO *bp, const BIGNUM *a) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (i = bn_minimal_width(a) - 1; i >= 0; i--) {
|
||||
for (i = a->top - 1; i >= 0; i--) {
|
||||
for (j = BN_BITS2 - 4; j >= 0; j -= 4) {
|
||||
// strip leading zeros
|
||||
v = ((int)(a->d[i] >> (long)j)) & 0x0f;
|
||||
|
||||
@@ -131,20 +131,6 @@ size_t BUF_MEM_grow_clean(BUF_MEM *buf, size_t len) {
|
||||
return BUF_MEM_grow(buf, len);
|
||||
}
|
||||
|
||||
int BUF_MEM_append(BUF_MEM *buf, const void *in, size_t len) {
|
||||
size_t new_len = buf->length + len;
|
||||
if (new_len < len) {
|
||||
OPENSSL_PUT_ERROR(BUF, ERR_R_OVERFLOW);
|
||||
return 0;
|
||||
}
|
||||
if (!BUF_MEM_reserve(buf, new_len)) {
|
||||
return 0;
|
||||
}
|
||||
OPENSSL_memcpy(buf->data + buf->length, in, len);
|
||||
buf->length = new_len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *BUF_strdup(const char *str) {
|
||||
if (str == NULL) {
|
||||
return NULL;
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
/* Copyright (c) 2017, Google Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
#include <openssl/buf.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
||||
TEST(BufTest, Basic) {
|
||||
bssl::UniquePtr<BUF_MEM> buf(BUF_MEM_new());
|
||||
ASSERT_TRUE(buf);
|
||||
EXPECT_EQ(0u, buf->length);
|
||||
|
||||
// Use BUF_MEM_reserve to increase buf->max.
|
||||
ASSERT_TRUE(BUF_MEM_reserve(buf.get(), 200));
|
||||
EXPECT_GE(buf->max, 200u);
|
||||
EXPECT_EQ(0u, buf->length);
|
||||
|
||||
// BUF_MEM_reserve with a smaller cap is a no-op.
|
||||
size_t old_max = buf->max;
|
||||
ASSERT_TRUE(BUF_MEM_reserve(buf.get(), 100));
|
||||
EXPECT_EQ(old_max, buf->max);
|
||||
EXPECT_EQ(0u, buf->length);
|
||||
|
||||
// BUF_MEM_grow can increase the length without reallocating.
|
||||
ASSERT_EQ(100u, BUF_MEM_grow(buf.get(), 100));
|
||||
EXPECT_EQ(100u, buf->length);
|
||||
EXPECT_EQ(old_max, buf->max);
|
||||
memset(buf->data, 'A', buf->length);
|
||||
|
||||
// If BUF_MEM_reserve reallocates, it preserves the contents.
|
||||
ASSERT_TRUE(BUF_MEM_reserve(buf.get(), old_max + 1));
|
||||
ASSERT_GE(buf->max, old_max + 1);
|
||||
EXPECT_EQ(100u, buf->length);
|
||||
for (size_t i = 0; i < 100; i++) {
|
||||
EXPECT_EQ('A', buf->data[i]);
|
||||
}
|
||||
|
||||
// BUF_MEM_grow should zero everything beyond buf->length.
|
||||
memset(buf->data, 'B', buf->max);
|
||||
ASSERT_EQ(150u, BUF_MEM_grow(buf.get(), 150));
|
||||
EXPECT_EQ(150u, buf->length);
|
||||
for (size_t i = 0; i < 100; i++) {
|
||||
EXPECT_EQ('B', buf->data[i]);
|
||||
}
|
||||
for (size_t i = 100; i < 150; i++) {
|
||||
EXPECT_EQ(0, buf->data[i]);
|
||||
}
|
||||
|
||||
// BUF_MEM_grow can rellocate if necessary.
|
||||
size_t new_len = buf->max + 1;
|
||||
ASSERT_EQ(new_len, BUF_MEM_grow(buf.get(), new_len));
|
||||
EXPECT_GE(buf->max, new_len);
|
||||
EXPECT_EQ(new_len, buf->length);
|
||||
for (size_t i = 0; i < 100; i++) {
|
||||
EXPECT_EQ('B', buf->data[i]);
|
||||
}
|
||||
for (size_t i = 100; i < new_len; i++) {
|
||||
EXPECT_EQ(0, buf->data[i]);
|
||||
}
|
||||
|
||||
// BUF_MEM_grow can shink.
|
||||
ASSERT_EQ(50u, BUF_MEM_grow(buf.get(), 50));
|
||||
EXPECT_EQ(50u, buf->length);
|
||||
for (size_t i = 0; i < 50; i++) {
|
||||
EXPECT_EQ('B', buf->data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BufTest, Append) {
|
||||
bssl::UniquePtr<BUF_MEM> buf(BUF_MEM_new());
|
||||
ASSERT_TRUE(buf);
|
||||
|
||||
ASSERT_TRUE(BUF_MEM_append(buf.get(), nullptr, 0));
|
||||
ASSERT_TRUE(BUF_MEM_append(buf.get(), "hello ", 6));
|
||||
ASSERT_TRUE(BUF_MEM_append(buf.get(), nullptr, 0));
|
||||
ASSERT_TRUE(BUF_MEM_append(buf.get(), "world", 5));
|
||||
std::string str(128, 'A');
|
||||
ASSERT_TRUE(BUF_MEM_append(buf.get(), str.data(), str.size()));
|
||||
|
||||
EXPECT_EQ("hello world" + str, std::string(buf->data, buf->length));
|
||||
}
|
||||
@@ -9,5 +9,4 @@ add_library(
|
||||
ber.c
|
||||
cbs.c
|
||||
cbb.c
|
||||
unicode.c
|
||||
)
|
||||
|
||||
@@ -29,7 +29,10 @@ static const unsigned kMaxDepth = 2048;
|
||||
// is_string_type returns one if |tag| is a string type and zero otherwise. It
|
||||
// ignores the constructed bit.
|
||||
static int is_string_type(unsigned tag) {
|
||||
switch (tag & ~CBS_ASN1_CONSTRUCTED) {
|
||||
if ((tag & 0xc0) != 0) {
|
||||
return 0;
|
||||
}
|
||||
switch (tag & 0x1f) {
|
||||
case CBS_ASN1_BITSTRING:
|
||||
case CBS_ASN1_OCTETSTRING:
|
||||
case CBS_ASN1_UTF8STRING:
|
||||
@@ -189,7 +192,7 @@ static int cbs_convert_ber(CBS *in, CBB *out, unsigned string_tag,
|
||||
return looking_for_eoc == 0;
|
||||
}
|
||||
|
||||
int CBS_asn1_ber_to_der(CBS *in, CBS *out, uint8_t **out_storage) {
|
||||
int CBS_asn1_ber_to_der(CBS *in, uint8_t **out, size_t *out_len) {
|
||||
CBB cbb;
|
||||
|
||||
// First, do a quick walk to find any indefinite-length elements. Most of the
|
||||
@@ -200,22 +203,18 @@ int CBS_asn1_ber_to_der(CBS *in, CBS *out, uint8_t **out_storage) {
|
||||
}
|
||||
|
||||
if (!conversion_needed) {
|
||||
if (!CBS_get_any_asn1_element(in, out, NULL, NULL)) {
|
||||
return 0;
|
||||
}
|
||||
*out_storage = NULL;
|
||||
*out = NULL;
|
||||
*out_len = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t len;
|
||||
if (!CBB_init(&cbb, CBS_len(in)) ||
|
||||
!cbs_convert_ber(in, &cbb, 0, 0, 0) ||
|
||||
!CBB_finish(&cbb, out_storage, &len)) {
|
||||
!CBB_finish(&cbb, out, out_len)) {
|
||||
CBB_cleanup(&cbb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
CBS_init(out, *out_storage, len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -123,27 +123,27 @@ TEST(CBSTest, GetASN1) {
|
||||
uint64_t value;
|
||||
|
||||
CBS_init(&data, kData1, sizeof(kData1));
|
||||
EXPECT_FALSE(CBS_peek_asn1_tag(&data, CBS_ASN1_BOOLEAN));
|
||||
EXPECT_TRUE(CBS_peek_asn1_tag(&data, CBS_ASN1_SEQUENCE));
|
||||
EXPECT_FALSE(CBS_peek_asn1_tag(&data, 0x1));
|
||||
EXPECT_TRUE(CBS_peek_asn1_tag(&data, 0x30));
|
||||
|
||||
ASSERT_TRUE(CBS_get_asn1(&data, &contents, CBS_ASN1_SEQUENCE));
|
||||
ASSERT_TRUE(CBS_get_asn1(&data, &contents, 0x30));
|
||||
EXPECT_EQ(Bytes("\x01\x02"), Bytes(CBS_data(&contents), CBS_len(&contents)));
|
||||
|
||||
CBS_init(&data, kData2, sizeof(kData2));
|
||||
// data is truncated
|
||||
EXPECT_FALSE(CBS_get_asn1(&data, &contents, CBS_ASN1_SEQUENCE));
|
||||
EXPECT_FALSE(CBS_get_asn1(&data, &contents, 0x30));
|
||||
|
||||
CBS_init(&data, kData3, sizeof(kData3));
|
||||
// zero byte length of length
|
||||
EXPECT_FALSE(CBS_get_asn1(&data, &contents, CBS_ASN1_SEQUENCE));
|
||||
EXPECT_FALSE(CBS_get_asn1(&data, &contents, 0x30));
|
||||
|
||||
CBS_init(&data, kData4, sizeof(kData4));
|
||||
// long form mistakenly used.
|
||||
EXPECT_FALSE(CBS_get_asn1(&data, &contents, CBS_ASN1_SEQUENCE));
|
||||
EXPECT_FALSE(CBS_get_asn1(&data, &contents, 0x30));
|
||||
|
||||
CBS_init(&data, kData5, sizeof(kData5));
|
||||
// length takes too many bytes.
|
||||
EXPECT_FALSE(CBS_get_asn1(&data, &contents, CBS_ASN1_SEQUENCE));
|
||||
EXPECT_FALSE(CBS_get_asn1(&data, &contents, 0x30));
|
||||
|
||||
CBS_init(&data, kData1, sizeof(kData1));
|
||||
// wrong tag.
|
||||
@@ -151,72 +151,56 @@ TEST(CBSTest, GetASN1) {
|
||||
|
||||
CBS_init(&data, NULL, 0);
|
||||
// peek at empty data.
|
||||
EXPECT_FALSE(CBS_peek_asn1_tag(&data, CBS_ASN1_SEQUENCE));
|
||||
EXPECT_FALSE(CBS_peek_asn1_tag(&data, 0x30));
|
||||
|
||||
CBS_init(&data, NULL, 0);
|
||||
// optional elements at empty data.
|
||||
ASSERT_TRUE(CBS_get_optional_asn1(
|
||||
&data, &contents, &present,
|
||||
CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0));
|
||||
ASSERT_TRUE(CBS_get_optional_asn1(&data, &contents, &present, 0xa0));
|
||||
EXPECT_FALSE(present);
|
||||
ASSERT_TRUE(CBS_get_optional_asn1_octet_string(
|
||||
&data, &contents, &present,
|
||||
CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0));
|
||||
ASSERT_TRUE(
|
||||
CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa0));
|
||||
EXPECT_FALSE(present);
|
||||
EXPECT_EQ(0u, CBS_len(&contents));
|
||||
ASSERT_TRUE(CBS_get_optional_asn1_octet_string(
|
||||
&data, &contents, NULL,
|
||||
CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0));
|
||||
ASSERT_TRUE(CBS_get_optional_asn1_octet_string(&data, &contents, NULL, 0xa0));
|
||||
EXPECT_EQ(0u, CBS_len(&contents));
|
||||
ASSERT_TRUE(CBS_get_optional_asn1_uint64(
|
||||
&data, &value, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0, 42));
|
||||
ASSERT_TRUE(CBS_get_optional_asn1_uint64(&data, &value, 0xa0, 42));
|
||||
EXPECT_EQ(42u, value);
|
||||
|
||||
CBS_init(&data, kData6, sizeof(kData6));
|
||||
// optional element.
|
||||
ASSERT_TRUE(CBS_get_optional_asn1(
|
||||
&data, &contents, &present,
|
||||
CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0));
|
||||
ASSERT_TRUE(CBS_get_optional_asn1(&data, &contents, &present, 0xa0));
|
||||
EXPECT_FALSE(present);
|
||||
ASSERT_TRUE(CBS_get_optional_asn1(
|
||||
&data, &contents, &present,
|
||||
CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1));
|
||||
ASSERT_TRUE(CBS_get_optional_asn1(&data, &contents, &present, 0xa1));
|
||||
EXPECT_TRUE(present);
|
||||
EXPECT_EQ(Bytes("\x04\x01\x01"),
|
||||
Bytes(CBS_data(&contents), CBS_len(&contents)));
|
||||
|
||||
CBS_init(&data, kData6, sizeof(kData6));
|
||||
// optional octet string.
|
||||
ASSERT_TRUE(CBS_get_optional_asn1_octet_string(
|
||||
&data, &contents, &present,
|
||||
CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0));
|
||||
ASSERT_TRUE(
|
||||
CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa0));
|
||||
EXPECT_FALSE(present);
|
||||
EXPECT_EQ(0u, CBS_len(&contents));
|
||||
ASSERT_TRUE(CBS_get_optional_asn1_octet_string(
|
||||
&data, &contents, &present,
|
||||
CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1));
|
||||
ASSERT_TRUE(
|
||||
CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa1));
|
||||
EXPECT_TRUE(present);
|
||||
EXPECT_EQ(Bytes("\x01"), Bytes(CBS_data(&contents), CBS_len(&contents)));
|
||||
|
||||
CBS_init(&data, kData7, sizeof(kData7));
|
||||
// invalid optional octet string.
|
||||
EXPECT_FALSE(CBS_get_optional_asn1_octet_string(
|
||||
&data, &contents, &present,
|
||||
CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1));
|
||||
EXPECT_FALSE(
|
||||
CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa1));
|
||||
|
||||
CBS_init(&data, kData8, sizeof(kData8));
|
||||
// optional integer.
|
||||
ASSERT_TRUE(CBS_get_optional_asn1_uint64(
|
||||
&data, &value, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0, 42));
|
||||
ASSERT_TRUE(CBS_get_optional_asn1_uint64(&data, &value, 0xa0, 42));
|
||||
EXPECT_EQ(42u, value);
|
||||
ASSERT_TRUE(CBS_get_optional_asn1_uint64(
|
||||
&data, &value, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1, 42));
|
||||
ASSERT_TRUE(CBS_get_optional_asn1_uint64(&data, &value, 0xa1, 42));
|
||||
EXPECT_EQ(1u, value);
|
||||
|
||||
CBS_init(&data, kData9, sizeof(kData9));
|
||||
// invalid optional integer.
|
||||
EXPECT_FALSE(CBS_get_optional_asn1_uint64(
|
||||
&data, &value, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1, 42));
|
||||
EXPECT_FALSE(CBS_get_optional_asn1_uint64(&data, &value, 0xa1, 42));
|
||||
|
||||
unsigned tag;
|
||||
CBS_init(&data, kData1, sizeof(kData1));
|
||||
@@ -233,54 +217,6 @@ TEST(CBSTest, GetASN1) {
|
||||
Bytes(CBS_data(&contents), CBS_len(&contents)));
|
||||
}
|
||||
|
||||
TEST(CBSTest, ParseASN1Tag) {
|
||||
const struct {
|
||||
bool ok;
|
||||
unsigned tag;
|
||||
std::vector<uint8_t> in;
|
||||
} kTests[] = {
|
||||
{true, CBS_ASN1_SEQUENCE, {0x30, 0}},
|
||||
{true, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 4, {0xa4, 0}},
|
||||
{true, CBS_ASN1_APPLICATION | 30, {0x5e, 0}},
|
||||
{true, CBS_ASN1_APPLICATION | 31, {0x5f, 0x1f, 0}},
|
||||
{true, CBS_ASN1_APPLICATION | 32, {0x5f, 0x20, 0}},
|
||||
{true,
|
||||
CBS_ASN1_PRIVATE | CBS_ASN1_CONSTRUCTED | 0x1fffffff,
|
||||
{0xff, 0x81, 0xff, 0xff, 0xff, 0x7f, 0}},
|
||||
// Tag number fits in unsigned but not |CBS_ASN1_TAG_NUMBER_MASK|.
|
||||
{false, 0, {0xff, 0x82, 0xff, 0xff, 0xff, 0x7f, 0}},
|
||||
// Tag number does not fit in unsigned.
|
||||
{false, 0, {0xff, 0x90, 0x80, 0x80, 0x80, 0, 0}},
|
||||
// Tag number is not minimally-encoded
|
||||
{false, 0, {0x5f, 0x80, 0x1f, 0}},
|
||||
// Tag number should have used short form.
|
||||
{false, 0, {0x5f, 0x80, 0x1e, 0}},
|
||||
};
|
||||
for (const auto &t : kTests) {
|
||||
SCOPED_TRACE(Bytes(t.in));
|
||||
unsigned tag;
|
||||
CBS cbs, child;
|
||||
CBS_init(&cbs, t.in.data(), t.in.size());
|
||||
ASSERT_EQ(t.ok, !!CBS_get_any_asn1(&cbs, &child, &tag));
|
||||
if (t.ok) {
|
||||
EXPECT_EQ(t.tag, tag);
|
||||
EXPECT_EQ(0u, CBS_len(&child));
|
||||
EXPECT_EQ(0u, CBS_len(&cbs));
|
||||
|
||||
CBS_init(&cbs, t.in.data(), t.in.size());
|
||||
EXPECT_TRUE(CBS_peek_asn1_tag(&cbs, t.tag));
|
||||
EXPECT_FALSE(CBS_peek_asn1_tag(&cbs, t.tag + 1));
|
||||
|
||||
EXPECT_TRUE(CBS_get_asn1(&cbs, &child, t.tag));
|
||||
EXPECT_EQ(0u, CBS_len(&child));
|
||||
EXPECT_EQ(0u, CBS_len(&cbs));
|
||||
|
||||
CBS_init(&cbs, t.in.data(), t.in.size());
|
||||
EXPECT_FALSE(CBS_get_asn1(&cbs, &child, t.tag + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CBSTest, GetOptionalASN1Bool) {
|
||||
static const uint8_t kTrue[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0xff};
|
||||
static const uint8_t kFalse[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0x00};
|
||||
@@ -480,42 +416,15 @@ TEST(CBBTest, Misuse) {
|
||||
}
|
||||
|
||||
TEST(CBBTest, ASN1) {
|
||||
static const uint8_t kExpected[] = {
|
||||
// SEQUENCE { 1 2 3 }
|
||||
0x30, 3, 1, 2, 3,
|
||||
// [4 CONSTRUCTED] { 4 5 6 }
|
||||
0xa4, 3, 4, 5, 6,
|
||||
// [APPLICATION 30 PRIMITIVE] { 7 8 9 }
|
||||
0x5e, 3, 7, 8, 9,
|
||||
// [APPLICATION 31 PRIMITIVE] { 10 11 12 }
|
||||
0x5f, 0x1f, 3, 10, 11, 12,
|
||||
// [PRIVATE 2^29-1 CONSTRUCTED] { 13 14 15 }
|
||||
0xff, 0x81, 0xff, 0xff, 0xff, 0x7f, 3, 13, 14, 15,
|
||||
};
|
||||
static const uint8_t kExpected[] = {0x30, 3, 1, 2, 3};
|
||||
uint8_t *buf;
|
||||
size_t buf_len;
|
||||
bssl::ScopedCBB cbb;
|
||||
CBB contents, inner_contents;
|
||||
|
||||
ASSERT_TRUE(CBB_init(cbb.get(), 0));
|
||||
ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, CBS_ASN1_SEQUENCE));
|
||||
ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, 0x30));
|
||||
ASSERT_TRUE(CBB_add_bytes(&contents, (const uint8_t *)"\x01\x02\x03", 3));
|
||||
ASSERT_TRUE(
|
||||
CBB_add_asn1(cbb.get(), &contents,
|
||||
CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 4));
|
||||
ASSERT_TRUE(CBB_add_bytes(&contents, (const uint8_t *)"\x04\x05\x06", 3));
|
||||
ASSERT_TRUE(
|
||||
CBB_add_asn1(cbb.get(), &contents,
|
||||
CBS_ASN1_APPLICATION | 30));
|
||||
ASSERT_TRUE(CBB_add_bytes(&contents, (const uint8_t *)"\x07\x08\x09", 3));
|
||||
ASSERT_TRUE(
|
||||
CBB_add_asn1(cbb.get(), &contents,
|
||||
CBS_ASN1_APPLICATION | 31));
|
||||
ASSERT_TRUE(CBB_add_bytes(&contents, (const uint8_t *)"\x0a\x0b\x0c", 3));
|
||||
ASSERT_TRUE(
|
||||
CBB_add_asn1(cbb.get(), &contents,
|
||||
CBS_ASN1_PRIVATE | CBS_ASN1_CONSTRUCTED | 0x1fffffff));
|
||||
ASSERT_TRUE(CBB_add_bytes(&contents, (const uint8_t *)"\x0d\x0e\x0f", 3));
|
||||
ASSERT_TRUE(CBB_finish(cbb.get(), &buf, &buf_len));
|
||||
bssl::UniquePtr<uint8_t> scoper(buf);
|
||||
|
||||
@@ -523,7 +432,7 @@ TEST(CBBTest, ASN1) {
|
||||
|
||||
std::vector<uint8_t> test_data(100000, 0x42);
|
||||
ASSERT_TRUE(CBB_init(cbb.get(), 0));
|
||||
ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, CBS_ASN1_SEQUENCE));
|
||||
ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, 0x30));
|
||||
ASSERT_TRUE(CBB_add_bytes(&contents, test_data.data(), 130));
|
||||
ASSERT_TRUE(CBB_finish(cbb.get(), &buf, &buf_len));
|
||||
scoper.reset(buf);
|
||||
@@ -533,7 +442,7 @@ TEST(CBBTest, ASN1) {
|
||||
EXPECT_EQ(Bytes(test_data.data(), 130), Bytes(buf + 3, 130));
|
||||
|
||||
ASSERT_TRUE(CBB_init(cbb.get(), 0));
|
||||
ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, CBS_ASN1_SEQUENCE));
|
||||
ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, 0x30));
|
||||
ASSERT_TRUE(CBB_add_bytes(&contents, test_data.data(), 1000));
|
||||
ASSERT_TRUE(CBB_finish(cbb.get(), &buf, &buf_len));
|
||||
scoper.reset(buf);
|
||||
@@ -543,8 +452,8 @@ TEST(CBBTest, ASN1) {
|
||||
EXPECT_EQ(Bytes(test_data.data(), 1000), Bytes(buf + 4, 1000));
|
||||
|
||||
ASSERT_TRUE(CBB_init(cbb.get(), 0));
|
||||
ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, CBS_ASN1_SEQUENCE));
|
||||
ASSERT_TRUE(CBB_add_asn1(&contents, &inner_contents, CBS_ASN1_SEQUENCE));
|
||||
ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, 0x30));
|
||||
ASSERT_TRUE(CBB_add_asn1(&contents, &inner_contents, 0x30));
|
||||
ASSERT_TRUE(CBB_add_bytes(&inner_contents, test_data.data(), 100000));
|
||||
ASSERT_TRUE(CBB_finish(cbb.get(), &buf, &buf_len));
|
||||
scoper.reset(buf);
|
||||
@@ -558,18 +467,19 @@ static void ExpectBerConvert(const char *name, const uint8_t *der_expected,
|
||||
size_t der_len, const uint8_t *ber,
|
||||
size_t ber_len) {
|
||||
SCOPED_TRACE(name);
|
||||
CBS in, out;
|
||||
uint8_t *storage;
|
||||
CBS in;
|
||||
uint8_t *out;
|
||||
size_t out_len;
|
||||
|
||||
CBS_init(&in, ber, ber_len);
|
||||
ASSERT_TRUE(CBS_asn1_ber_to_der(&in, &out, &storage));
|
||||
bssl::UniquePtr<uint8_t> scoper(storage);
|
||||
ASSERT_TRUE(CBS_asn1_ber_to_der(&in, &out, &out_len));
|
||||
bssl::UniquePtr<uint8_t> scoper(out);
|
||||
|
||||
EXPECT_EQ(Bytes(der_expected, der_len), Bytes(CBS_data(&out), CBS_len(&out)));
|
||||
if (storage != nullptr) {
|
||||
EXPECT_NE(Bytes(der_expected, der_len), Bytes(ber, ber_len));
|
||||
} else {
|
||||
if (out == NULL) {
|
||||
EXPECT_EQ(Bytes(der_expected, der_len), Bytes(ber, ber_len));
|
||||
} else {
|
||||
EXPECT_NE(Bytes(der_expected, der_len), Bytes(ber, ber_len));
|
||||
EXPECT_EQ(Bytes(der_expected, der_len), Bytes(out, out_len));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -580,12 +490,6 @@ TEST(CBSTest, BerConvert) {
|
||||
static const uint8_t kIndefBER[] = {0x30, 0x80, 0x01, 0x01, 0x02, 0x00, 0x00};
|
||||
static const uint8_t kIndefDER[] = {0x30, 0x03, 0x01, 0x01, 0x02};
|
||||
|
||||
// kIndefBER2 contains a constructed [APPLICATION 31] with an indefinite
|
||||
// length.
|
||||
static const uint8_t kIndefBER2[] = {0x7f, 0x1f, 0x80, 0x01,
|
||||
0x01, 0x02, 0x00, 0x00};
|
||||
static const uint8_t kIndefDER2[] = {0x7f, 0x1f, 0x03, 0x01, 0x01, 0x02};
|
||||
|
||||
// kOctetStringBER contains an indefinite length OCTET STRING with two parts.
|
||||
// These parts need to be concatenated in DER form.
|
||||
static const uint8_t kOctetStringBER[] = {0x24, 0x80, 0x04, 0x02, 0, 1,
|
||||
@@ -630,8 +534,6 @@ TEST(CBSTest, BerConvert) {
|
||||
sizeof(kSimpleBER));
|
||||
ExpectBerConvert("kIndefBER", kIndefDER, sizeof(kIndefDER), kIndefBER,
|
||||
sizeof(kIndefBER));
|
||||
ExpectBerConvert("kIndefBER2", kIndefDER2, sizeof(kIndefDER2), kIndefBER2,
|
||||
sizeof(kIndefBER2));
|
||||
ExpectBerConvert("kOctetStringBER", kOctetStringDER, sizeof(kOctetStringDER),
|
||||
kOctetStringBER, sizeof(kOctetStringBER));
|
||||
ExpectBerConvert("kNSSBER", kNSSDER, sizeof(kNSSDER), kNSSBER,
|
||||
@@ -885,386 +787,3 @@ TEST(CBSTest, BitString) {
|
||||
CBS_asn1_bitstring_has_bit(&cbs, test.bit));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CBBTest, AddOIDFromText) {
|
||||
const struct {
|
||||
const char *text;
|
||||
std::vector<uint8_t> der;
|
||||
} kValidOIDs[] = {
|
||||
// Some valid values.
|
||||
{"0.0", {0x00}},
|
||||
{"0.2.3.4", {0x2, 0x3, 0x4}},
|
||||
{"1.2.3.4", {0x2a, 0x3, 0x4}},
|
||||
{"2.2.3.4", {0x52, 0x3, 0x4}},
|
||||
{"1.2.840.113554.4.1.72585",
|
||||
{0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, 0x01, 0x84, 0xb7, 0x09}},
|
||||
// Test edge cases around the first component.
|
||||
{"0.39", {0x27}},
|
||||
{"1.0", {0x28}},
|
||||
{"1.39", {0x4f}},
|
||||
{"2.0", {0x50}},
|
||||
{"2.1", {0x51}},
|
||||
{"2.40", {0x78}},
|
||||
// Edge cases near an overflow.
|
||||
{"1.2.18446744073709551615",
|
||||
{0x2a, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}},
|
||||
{"2.18446744073709551535",
|
||||
{0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}},
|
||||
};
|
||||
|
||||
const char *kInvalidTexts[] = {
|
||||
// Invalid second component.
|
||||
"0.40",
|
||||
"1.40",
|
||||
// Invalid first component.
|
||||
"3.1",
|
||||
// The empty string is not an OID.
|
||||
"",
|
||||
// No empty components.
|
||||
".1.2.3.4.5",
|
||||
"1..2.3.4.5",
|
||||
"1.2.3.4.5.",
|
||||
// There must be at least two components.
|
||||
"1",
|
||||
// No extra leading zeros.
|
||||
"00.1.2.3.4",
|
||||
"01.1.2.3.4",
|
||||
// Overflow for both components or 40*A + B.
|
||||
"1.2.18446744073709551616",
|
||||
"2.18446744073709551536",
|
||||
};
|
||||
|
||||
const std::vector<uint8_t> kInvalidDER[] = {
|
||||
// The empty string is not an OID.
|
||||
{},
|
||||
// Non-minimal representation.
|
||||
{0x80, 0x01},
|
||||
// Overflow. This is the DER representation of
|
||||
// 1.2.840.113554.4.1.72585.18446744073709551616. (The final value is
|
||||
// 2^64.)
|
||||
{0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, 0x01, 0x84, 0xb7, 0x09,
|
||||
0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00},
|
||||
};
|
||||
|
||||
for (const auto &t : kValidOIDs) {
|
||||
SCOPED_TRACE(t.text);
|
||||
|
||||
bssl::ScopedCBB cbb;
|
||||
ASSERT_TRUE(CBB_init(cbb.get(), 0));
|
||||
ASSERT_TRUE(CBB_add_asn1_oid_from_text(cbb.get(), t.text, strlen(t.text)));
|
||||
uint8_t *out;
|
||||
size_t len;
|
||||
ASSERT_TRUE(CBB_finish(cbb.get(), &out, &len));
|
||||
bssl::UniquePtr<uint8_t> free_out(out);
|
||||
EXPECT_EQ(Bytes(t.der), Bytes(out, len));
|
||||
|
||||
CBS cbs;
|
||||
CBS_init(&cbs, t.der.data(), t.der.size());
|
||||
bssl::UniquePtr<char> text(CBS_asn1_oid_to_text(&cbs));
|
||||
ASSERT_TRUE(text.get());
|
||||
EXPECT_STREQ(t.text, text.get());
|
||||
}
|
||||
|
||||
for (const char *t : kInvalidTexts) {
|
||||
SCOPED_TRACE(t);
|
||||
bssl::ScopedCBB cbb;
|
||||
ASSERT_TRUE(CBB_init(cbb.get(), 0));
|
||||
EXPECT_FALSE(CBB_add_asn1_oid_from_text(cbb.get(), t, strlen(t)));
|
||||
}
|
||||
|
||||
for (const auto &t : kInvalidDER) {
|
||||
SCOPED_TRACE(Bytes(t));
|
||||
CBS cbs;
|
||||
CBS_init(&cbs, t.data(), t.size());
|
||||
bssl::UniquePtr<char> text(CBS_asn1_oid_to_text(&cbs));
|
||||
EXPECT_FALSE(text);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CBBTest, FlushASN1SetOf) {
|
||||
const struct {
|
||||
std::vector<uint8_t> in, out;
|
||||
} kValidInputs[] = {
|
||||
// No elements.
|
||||
{{}, {}},
|
||||
// One element.
|
||||
{{0x30, 0x00}, {0x30, 0x00}},
|
||||
// Two identical elements.
|
||||
{{0x30, 0x00, 0x30, 0x00}, {0x30, 0x00, 0x30, 0x00}},
|
||||
// clang-format off
|
||||
{{0x30, 0x02, 0x00, 0x00,
|
||||
0x30, 0x00,
|
||||
0x01, 0x00,
|
||||
0x30, 0x02, 0x00, 0x00,
|
||||
0x30, 0x03, 0x00, 0x00, 0x00,
|
||||
0x30, 0x00,
|
||||
0x30, 0x03, 0x00, 0x00, 0x01,
|
||||
0x30, 0x01, 0x00,
|
||||
0x01, 0x01, 0x00},
|
||||
{0x01, 0x00,
|
||||
0x01, 0x01, 0x00,
|
||||
0x30, 0x00,
|
||||
0x30, 0x00,
|
||||
0x30, 0x01, 0x00,
|
||||
0x30, 0x02, 0x00, 0x00,
|
||||
0x30, 0x02, 0x00, 0x00,
|
||||
0x30, 0x03, 0x00, 0x00, 0x00,
|
||||
0x30, 0x03, 0x00, 0x00, 0x01}},
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
for (const auto &t : kValidInputs) {
|
||||
SCOPED_TRACE(Bytes(t.in));
|
||||
|
||||
bssl::ScopedCBB cbb;
|
||||
CBB child;
|
||||
ASSERT_TRUE(CBB_init(cbb.get(), 0));
|
||||
ASSERT_TRUE(CBB_add_asn1(cbb.get(), &child, CBS_ASN1_SET));
|
||||
ASSERT_TRUE(CBB_add_bytes(&child, t.in.data(), t.in.size()));
|
||||
ASSERT_TRUE(CBB_flush_asn1_set_of(&child));
|
||||
EXPECT_EQ(Bytes(t.out), Bytes(CBB_data(&child), CBB_len(&child)));
|
||||
|
||||
// Running it again should be idempotent.
|
||||
ASSERT_TRUE(CBB_flush_asn1_set_of(&child));
|
||||
EXPECT_EQ(Bytes(t.out), Bytes(CBB_data(&child), CBB_len(&child)));
|
||||
|
||||
// The ASN.1 header remain intact.
|
||||
ASSERT_TRUE(CBB_flush(cbb.get()));
|
||||
EXPECT_EQ(0x31, CBB_data(cbb.get())[0]);
|
||||
}
|
||||
|
||||
const std::vector<uint8_t> kInvalidInputs[] = {
|
||||
{0x30},
|
||||
{0x30, 0x01},
|
||||
{0x30, 0x00, 0x30, 0x00, 0x30, 0x01},
|
||||
};
|
||||
|
||||
for (const auto &t : kInvalidInputs) {
|
||||
SCOPED_TRACE(Bytes(t));
|
||||
|
||||
bssl::ScopedCBB cbb;
|
||||
CBB child;
|
||||
ASSERT_TRUE(CBB_init(cbb.get(), 0));
|
||||
ASSERT_TRUE(CBB_add_asn1(cbb.get(), &child, CBS_ASN1_SET));
|
||||
ASSERT_TRUE(CBB_add_bytes(&child, t.data(), t.size()));
|
||||
EXPECT_FALSE(CBB_flush_asn1_set_of(&child));
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static std::vector<uint8_t> LiteralToBytes(const T *str) {
|
||||
std::vector<uint8_t> ret;
|
||||
for (; *str != 0; str++) {
|
||||
for (size_t i = 0; i < sizeof(T); i++) {
|
||||
ret.push_back(static_cast<uint8_t>(*str >> (8 * (sizeof(T) - 1 - i))));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static std::vector<uint32_t> LiteralToCodePoints(const char32_t *str) {
|
||||
std::vector<uint32_t> ret;
|
||||
for (; *str != 0; str++) {
|
||||
ret.push_back(static_cast<uint32_t>(*str));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
TEST(CBBTest, Unicode) {
|
||||
struct {
|
||||
int (*decode)(CBS *, uint32_t *);
|
||||
int (*encode)(CBB *, uint32_t);
|
||||
std::vector<uint8_t> in;
|
||||
std::vector<uint32_t> out;
|
||||
bool ok;
|
||||
} kTests[] = {
|
||||
{cbs_get_utf8, cbb_add_utf8,
|
||||
// This test string captures all four cases in UTF-8.
|
||||
LiteralToBytes(u8"Hello, 世界! ¡Hola, 🌎!"),
|
||||
LiteralToCodePoints(U"Hello, 世界! ¡Hola, 🌎!"), true},
|
||||
|
||||
// Some invalid inputs adapted from
|
||||
// http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
|
||||
// 2.1 First possible sequence of a certain length. (5- and 6-bit
|
||||
// sequences no longer exist.)
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xf8, 0x88, 0x80, 0x80, 0x80}, {}, false},
|
||||
{cbs_get_utf8,
|
||||
cbb_add_utf8,
|
||||
{0xfc, 0x84, 0x80, 0x80, 0x80, 0x80},
|
||||
{},
|
||||
false},
|
||||
// 3.1 Unexpected continuation bytes.
|
||||
{cbs_get_utf8, cbb_add_utf8, {0x80}, {}, false},
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xbf}, {}, false},
|
||||
// 3.2 Lonely start characters.
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xc0, ' '}, {}, false},
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xe0, ' '}, {}, false},
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xf0, ' '}, {}, false},
|
||||
// 3.3 Sequences with last continuation byte missing
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xc0}, {}, false},
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xe0, 0x80}, {}, false},
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xf0, 0x80, 0x80}, {}, false},
|
||||
// Variation of the above with unexpected spaces.
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xe0, 0x80, ' '}, {}, false},
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xf0, 0x80, 0x80, ' '}, {}, false},
|
||||
// 4.1 Examples of an overlong ASCII character
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xc0, 0xaf}, {}, false},
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xe0, 0x80, 0xaf}, {}, false},
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xf0, 0x80, 0x80, 0xaf}, {}, false},
|
||||
// 4.2 Maximum overlong sequences
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xc1, 0xbf}, {}, false},
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xe0, 0x9f, 0xbf}, {}, false},
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xf0, 0x8f, 0xbf, 0xbf}, {}, false},
|
||||
// 4.3 Overlong representation of the NUL character
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xc0, 0x80}, {}, false},
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xe0, 0x80, 0x80}, {}, false},
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xf0, 0x80, 0x80, 0x80}, {}, false},
|
||||
// 5.1 Single UTF-16 surrogates
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xed, 0xa0, 0x80}, {}, false},
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xed, 0xad, 0xbf}, {}, false},
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xed, 0xae, 0x80}, {}, false},
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xed, 0xb0, 0x80}, {}, false},
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xed, 0xbe, 0x80}, {}, false},
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xed, 0xbf, 0xbf}, {}, false},
|
||||
// 5.2 Paired UTF-16 surrogates
|
||||
{cbs_get_utf8,
|
||||
cbb_add_utf8,
|
||||
{0xed, 0xa0, 0x80, 0xed, 0xb0, 0x80},
|
||||
{},
|
||||
false},
|
||||
{cbs_get_utf8,
|
||||
cbb_add_utf8,
|
||||
{0xed, 0xa0, 0x80, 0xed, 0xbf, 0xbf},
|
||||
{},
|
||||
false},
|
||||
{cbs_get_utf8,
|
||||
cbb_add_utf8,
|
||||
{0xed, 0xad, 0xbf, 0xed, 0xb0, 0x80},
|
||||
{},
|
||||
false},
|
||||
{cbs_get_utf8,
|
||||
cbb_add_utf8,
|
||||
{0xed, 0xad, 0xbf, 0xed, 0xbf, 0xbf},
|
||||
{},
|
||||
false},
|
||||
{cbs_get_utf8,
|
||||
cbb_add_utf8,
|
||||
{0xed, 0xae, 0x80, 0xed, 0xb0, 0x80},
|
||||
{},
|
||||
false},
|
||||
{cbs_get_utf8,
|
||||
cbb_add_utf8,
|
||||
{0xed, 0xae, 0x80, 0xed, 0xbf, 0xbf},
|
||||
{},
|
||||
false},
|
||||
{cbs_get_utf8,
|
||||
cbb_add_utf8,
|
||||
{0xed, 0xaf, 0xbf, 0xed, 0xb0, 0x80},
|
||||
{},
|
||||
false},
|
||||
{cbs_get_utf8,
|
||||
cbb_add_utf8,
|
||||
{0xed, 0xaf, 0xbf, 0xed, 0xbf, 0xbf},
|
||||
{},
|
||||
false},
|
||||
// 5.3 Noncharacter code positions
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xef, 0xbf, 0xbe}, {}, false},
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xef, 0xbf, 0xbf}, {}, false},
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xef, 0xb7, 0x90}, {}, false},
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xef, 0xb7, 0xaf}, {}, false},
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xf0, 0x9f, 0xbf, 0xbe}, {}, false},
|
||||
{cbs_get_utf8, cbb_add_utf8, {0xf0, 0x9f, 0xbf, 0xbf}, {}, false},
|
||||
|
||||
{cbs_get_latin1, cbb_add_latin1, LiteralToBytes("\xa1Hola!"),
|
||||
LiteralToCodePoints(U"¡Hola!"), true},
|
||||
|
||||
// UCS-2 matches UTF-16 on the BMP.
|
||||
{cbs_get_ucs2_be, cbb_add_ucs2_be, LiteralToBytes(u"Hello, 世界!"),
|
||||
LiteralToCodePoints(U"Hello, 世界!"), true},
|
||||
// It does not support characters beyond the BMP.
|
||||
{cbs_get_ucs2_be, cbb_add_ucs2_be,
|
||||
LiteralToBytes(u"Hello, 世界! ¡Hola, 🌎!"),
|
||||
LiteralToCodePoints(U"Hello, 世界! ¡Hola, "), false},
|
||||
// Unpaired surrogates and non-characters are also rejected.
|
||||
{cbs_get_ucs2_be, cbb_add_ucs2_be, {0xd8, 0x00}, {}, false},
|
||||
{cbs_get_ucs2_be, cbb_add_ucs2_be, {0xff, 0xfe}, {}, false},
|
||||
|
||||
{cbs_get_utf32_be, cbb_add_utf32_be,
|
||||
LiteralToBytes(U"Hello, 世界! ¡Hola, 🌎!"),
|
||||
LiteralToCodePoints(U"Hello, 世界! ¡Hola, 🌎!"), true},
|
||||
// Unpaired surrogates and non-characters are rejected.
|
||||
{cbs_get_utf32_be, cbb_add_utf32_be, {0x00, 0x00, 0xd8, 0x00}, {}, false},
|
||||
{cbs_get_utf32_be, cbb_add_utf32_be, {0x00, 0x00, 0xff, 0xfe}, {}, false},
|
||||
|
||||
// Test that the NUL character can be encoded.
|
||||
{cbs_get_latin1, cbb_add_latin1, {0}, {0}, true},
|
||||
{cbs_get_utf8, cbb_add_utf8, {0}, {0}, true},
|
||||
{cbs_get_ucs2_be, cbb_add_ucs2_be, {0, 0}, {0}, true},
|
||||
{cbs_get_utf32_be, cbb_add_utf32_be, {0, 0, 0, 0}, {0}, true},
|
||||
};
|
||||
for (const auto &t : kTests) {
|
||||
SCOPED_TRACE(Bytes(t.in));
|
||||
|
||||
// Test decoding.
|
||||
CBS cbs;
|
||||
CBS_init(&cbs, t.in.data(), t.in.size());
|
||||
std::vector<uint32_t> out;
|
||||
bool ok = true;
|
||||
while (CBS_len(&cbs) != 0) {
|
||||
uint32_t u;
|
||||
if (!t.decode(&cbs, &u)) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
out.push_back(u);
|
||||
}
|
||||
EXPECT_EQ(t.ok, ok);
|
||||
EXPECT_EQ(t.out, out);
|
||||
|
||||
// Test encoding.
|
||||
if (t.ok) {
|
||||
bssl::ScopedCBB cbb;
|
||||
ASSERT_TRUE(CBB_init(cbb.get(), 0));
|
||||
for (uint32_t u : t.out) {
|
||||
ASSERT_TRUE(t.encode(cbb.get(), u));
|
||||
}
|
||||
EXPECT_EQ(Bytes(t.in), Bytes(CBB_data(cbb.get()), CBB_len(cbb.get())));
|
||||
}
|
||||
}
|
||||
|
||||
static const uint32_t kBadCodePoints[] = {
|
||||
// Surrogate pairs.
|
||||
0xd800,
|
||||
0xdfff,
|
||||
// Non-characters.
|
||||
0xfffe,
|
||||
0xffff,
|
||||
0xfdd0,
|
||||
0x1fffe,
|
||||
0x1ffff,
|
||||
// Too big.
|
||||
0x110000,
|
||||
};
|
||||
bssl::ScopedCBB cbb;
|
||||
ASSERT_TRUE(CBB_init(cbb.get(), 0));
|
||||
for (uint32_t v : kBadCodePoints) {
|
||||
SCOPED_TRACE(v);
|
||||
EXPECT_FALSE(cbb_add_utf8(cbb.get(), v));
|
||||
EXPECT_FALSE(cbb_add_latin1(cbb.get(), v));
|
||||
EXPECT_FALSE(cbb_add_ucs2_be(cbb.get(), v));
|
||||
EXPECT_FALSE(cbb_add_utf32_be(cbb.get(), v));
|
||||
}
|
||||
|
||||
// Additional values that are out of range.
|
||||
EXPECT_FALSE(cbb_add_latin1(cbb.get(), 0x100));
|
||||
EXPECT_FALSE(cbb_add_ucs2_be(cbb.get(), 0x10000));
|
||||
|
||||
EXPECT_EQ(1u, cbb_get_utf8_len(0));
|
||||
EXPECT_EQ(1u, cbb_get_utf8_len(0x7f));
|
||||
EXPECT_EQ(2u, cbb_get_utf8_len(0x80));
|
||||
EXPECT_EQ(2u, cbb_get_utf8_len(0x7ff));
|
||||
EXPECT_EQ(3u, cbb_get_utf8_len(0x800));
|
||||
EXPECT_EQ(3u, cbb_get_utf8_len(0xffff));
|
||||
EXPECT_EQ(4u, cbb_get_utf8_len(0x10000));
|
||||
EXPECT_EQ(4u, cbb_get_utf8_len(0x10ffff));
|
||||
}
|
||||
|
||||
+8
-201
@@ -15,10 +15,8 @@
|
||||
#include <openssl/bytestring.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/buf.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "../internal.h"
|
||||
@@ -330,47 +328,18 @@ int CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents) {
|
||||
return cbb_add_length_prefixed(cbb, out_contents, 3);
|
||||
}
|
||||
|
||||
// add_base128_integer encodes |v| as a big-endian base-128 integer where the
|
||||
// high bit of each byte indicates where there is more data. This is the
|
||||
// encoding used in DER for both high tag number form and OID components.
|
||||
static int add_base128_integer(CBB *cbb, uint64_t v) {
|
||||
unsigned len_len = 0;
|
||||
uint64_t copy = v;
|
||||
while (copy > 0) {
|
||||
len_len++;
|
||||
copy >>= 7;
|
||||
}
|
||||
if (len_len == 0) {
|
||||
len_len = 1; // Zero is encoded with one byte.
|
||||
}
|
||||
for (unsigned i = len_len - 1; i < len_len; i--) {
|
||||
uint8_t byte = (v >> (7 * i)) & 0x7f;
|
||||
if (i != 0) {
|
||||
// The high bit denotes whether there is more data.
|
||||
byte |= 0x80;
|
||||
}
|
||||
if (!CBB_add_u8(cbb, byte)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CBB_add_asn1(CBB *cbb, CBB *out_contents, unsigned tag) {
|
||||
if (!CBB_flush(cbb)) {
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Split the tag into leading bits and tag number.
|
||||
uint8_t tag_bits = (tag >> CBS_ASN1_TAG_SHIFT) & 0xe0;
|
||||
unsigned tag_number = tag & CBS_ASN1_TAG_NUMBER_MASK;
|
||||
if (tag_number >= 0x1f) {
|
||||
// Set all the bits in the tag number to signal high tag number form.
|
||||
if (!CBB_add_u8(cbb, tag_bits | 0x1f) ||
|
||||
!add_base128_integer(cbb, tag_number)) {
|
||||
return 0;
|
||||
}
|
||||
} else if (!CBB_add_u8(cbb, tag_bits | tag_number)) {
|
||||
if (!CBB_flush(cbb) ||
|
||||
// |tag|'s representation matches the DER encoding.
|
||||
!CBB_add_u8(cbb, (uint8_t)tag)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -504,165 +473,3 @@ int CBB_add_asn1_uint64(CBB *cbb, uint64_t value) {
|
||||
|
||||
return CBB_flush(cbb);
|
||||
}
|
||||
|
||||
int CBB_add_asn1_octet_string(CBB *cbb, const uint8_t *data, size_t data_len) {
|
||||
CBB child;
|
||||
if (!CBB_add_asn1(cbb, &child, CBS_ASN1_OCTETSTRING) ||
|
||||
!CBB_add_bytes(&child, data, data_len) ||
|
||||
!CBB_flush(cbb)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CBB_add_asn1_bool(CBB *cbb, int value) {
|
||||
CBB child;
|
||||
if (!CBB_add_asn1(cbb, &child, CBS_ASN1_BOOLEAN) ||
|
||||
!CBB_add_u8(&child, value != 0 ? 0xff : 0) ||
|
||||
!CBB_flush(cbb)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// parse_dotted_decimal parses one decimal component from |cbs|, where |cbs| is
|
||||
// an OID literal, e.g., "1.2.840.113554.4.1.72585". It consumes both the
|
||||
// component and the dot, so |cbs| may be passed into the function again for the
|
||||
// next value.
|
||||
static int parse_dotted_decimal(CBS *cbs, uint64_t *out) {
|
||||
*out = 0;
|
||||
int seen_digit = 0;
|
||||
for (;;) {
|
||||
// Valid terminators for a component are the end of the string or a
|
||||
// non-terminal dot. If the string ends with a dot, this is not a valid OID
|
||||
// string.
|
||||
uint8_t u;
|
||||
if (!CBS_get_u8(cbs, &u) ||
|
||||
(u == '.' && CBS_len(cbs) > 0)) {
|
||||
break;
|
||||
}
|
||||
if (u < '0' || u > '9' ||
|
||||
// Forbid stray leading zeros.
|
||||
(seen_digit && *out == 0) ||
|
||||
// Check for overflow.
|
||||
*out > UINT64_MAX / 10 ||
|
||||
*out * 10 > UINT64_MAX - (u - '0')) {
|
||||
return 0;
|
||||
}
|
||||
*out = *out * 10 + (u - '0');
|
||||
seen_digit = 1;
|
||||
}
|
||||
// The empty string is not a legal OID component.
|
||||
return seen_digit;
|
||||
}
|
||||
|
||||
int CBB_add_asn1_oid_from_text(CBB *cbb, const char *text, size_t len) {
|
||||
if (!CBB_flush(cbb)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
CBS cbs;
|
||||
CBS_init(&cbs, (const uint8_t *)text, len);
|
||||
|
||||
// OIDs must have at least two components.
|
||||
uint64_t a, b;
|
||||
if (!parse_dotted_decimal(&cbs, &a) ||
|
||||
!parse_dotted_decimal(&cbs, &b)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The first component is encoded as 40 * |a| + |b|. This assumes that |a| is
|
||||
// 0, 1, or 2 and that, when it is 0 or 1, |b| is at most 39.
|
||||
if (a > 2 ||
|
||||
(a < 2 && b > 39) ||
|
||||
b > UINT64_MAX - 80 ||
|
||||
!add_base128_integer(cbb, 40u * a + b)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The remaining components are encoded unmodified.
|
||||
while (CBS_len(&cbs) > 0) {
|
||||
if (!parse_dotted_decimal(&cbs, &a) ||
|
||||
!add_base128_integer(cbb, a)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int compare_set_of_element(const void *a_ptr, const void *b_ptr) {
|
||||
// See X.690, section 11.6 for the ordering. They are sorted in ascending
|
||||
// order by their DER encoding.
|
||||
const CBS *a = a_ptr, *b = b_ptr;
|
||||
size_t a_len = CBS_len(a), b_len = CBS_len(b);
|
||||
size_t min_len = a_len < b_len ? a_len : b_len;
|
||||
int ret = OPENSSL_memcmp(CBS_data(a), CBS_data(b), min_len);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
if (a_len == b_len) {
|
||||
return 0;
|
||||
}
|
||||
// If one is a prefix of the other, the shorter one sorts first. (This is not
|
||||
// actually reachable. No DER encoding is a prefix of another DER encoding.)
|
||||
return a_len < b_len ? -1 : 1;
|
||||
}
|
||||
|
||||
int CBB_flush_asn1_set_of(CBB *cbb) {
|
||||
if (!CBB_flush(cbb)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
CBS cbs;
|
||||
size_t num_children = 0;
|
||||
CBS_init(&cbs, CBB_data(cbb), CBB_len(cbb));
|
||||
while (CBS_len(&cbs) != 0) {
|
||||
if (!CBS_get_any_asn1_element(&cbs, NULL, NULL, NULL)) {
|
||||
return 0;
|
||||
}
|
||||
num_children++;
|
||||
}
|
||||
|
||||
if (num_children < 2) {
|
||||
return 1; // Nothing to do. This is the common case for X.509.
|
||||
}
|
||||
if (num_children > ((size_t)-1) / sizeof(CBS)) {
|
||||
return 0; // Overflow.
|
||||
}
|
||||
|
||||
// Parse out the children and sort. We alias them into a copy of so they
|
||||
// remain valid as we rewrite |cbb|.
|
||||
int ret = 0;
|
||||
size_t buf_len = CBB_len(cbb);
|
||||
uint8_t *buf = BUF_memdup(CBB_data(cbb), buf_len);
|
||||
CBS *children = OPENSSL_malloc(num_children * sizeof(CBS));
|
||||
if (buf == NULL || children == NULL) {
|
||||
goto err;
|
||||
}
|
||||
CBS_init(&cbs, buf, buf_len);
|
||||
for (size_t i = 0; i < num_children; i++) {
|
||||
if (!CBS_get_any_asn1_element(&cbs, &children[i], NULL, NULL)) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
qsort(children, num_children, sizeof(CBS), compare_set_of_element);
|
||||
|
||||
// Rewind |cbb| and write the contents back in the new order.
|
||||
cbb->base->len = cbb->offset + cbb->pending_len_len;
|
||||
for (size_t i = 0; i < num_children; i++) {
|
||||
if (!CBB_add_bytes(cbb, CBS_data(&children[i]), CBS_len(&children[i]))) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
assert(CBB_len(cbb) == buf_len);
|
||||
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
OPENSSL_free(buf);
|
||||
OPENSSL_free(children);
|
||||
return ret;
|
||||
}
|
||||
|
||||
+20
-151
@@ -12,16 +12,11 @@
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
#if !defined(__STDC_FORMAT_MACROS)
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#endif
|
||||
|
||||
#include <openssl/buf.h>
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/bytestring.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "internal.h"
|
||||
@@ -180,36 +175,18 @@ int CBS_get_u24_length_prefixed(CBS *cbs, CBS *out) {
|
||||
return cbs_get_length_prefixed(cbs, out, 3);
|
||||
}
|
||||
|
||||
// parse_base128_integer reads a big-endian base-128 integer from |cbs| and sets
|
||||
// |*out| to the result. This is the encoding used in DER for both high tag
|
||||
// number form and OID components.
|
||||
static int parse_base128_integer(CBS *cbs, uint64_t *out) {
|
||||
uint64_t v = 0;
|
||||
uint8_t b;
|
||||
do {
|
||||
if (!CBS_get_u8(cbs, &b)) {
|
||||
return 0;
|
||||
}
|
||||
if ((v >> (64 - 7)) != 0) {
|
||||
// The value is too large.
|
||||
return 0;
|
||||
}
|
||||
if (v == 0 && b == 0x80) {
|
||||
// The value must be minimally encoded.
|
||||
return 0;
|
||||
}
|
||||
v = (v << 7) | (b & 0x7f);
|
||||
static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
|
||||
size_t *out_header_len, int ber_ok) {
|
||||
uint8_t tag, length_byte;
|
||||
CBS header = *cbs;
|
||||
CBS throwaway;
|
||||
|
||||
// Values end at an octet with the high bit cleared.
|
||||
} while (b & 0x80);
|
||||
if (out == NULL) {
|
||||
out = &throwaway;
|
||||
}
|
||||
|
||||
*out = v;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int parse_asn1_tag(CBS *cbs, unsigned *out) {
|
||||
uint8_t tag_byte;
|
||||
if (!CBS_get_u8(cbs, &tag_byte)) {
|
||||
if (!CBS_get_u8(&header, &tag) ||
|
||||
!CBS_get_u8(&header, &length_byte)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -220,58 +197,22 @@ static int parse_asn1_tag(CBS *cbs, unsigned *out) {
|
||||
// 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).
|
||||
unsigned tag = ((unsigned)tag_byte & 0xe0) << CBS_ASN1_TAG_SHIFT;
|
||||
unsigned tag_number = tag_byte & 0x1f;
|
||||
if (tag_number == 0x1f) {
|
||||
uint64_t v;
|
||||
if (!parse_base128_integer(cbs, &v) ||
|
||||
// Check the tag number is within our supported bounds.
|
||||
v > CBS_ASN1_TAG_NUMBER_MASK ||
|
||||
// Small tag numbers should have used low tag number form.
|
||||
v < 0x1f) {
|
||||
return 0;
|
||||
}
|
||||
tag_number = (unsigned)v;
|
||||
}
|
||||
|
||||
tag |= tag_number;
|
||||
|
||||
*out = tag;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
|
||||
size_t *out_header_len, int ber_ok) {
|
||||
CBS header = *cbs;
|
||||
CBS throwaway;
|
||||
|
||||
if (out == NULL) {
|
||||
out = &throwaway;
|
||||
}
|
||||
|
||||
unsigned tag;
|
||||
if (!parse_asn1_tag(&header, &tag)) {
|
||||
if ((tag & 0x1f) == 0x1f) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (out_tag != NULL) {
|
||||
*out_tag = tag;
|
||||
}
|
||||
|
||||
uint8_t length_byte;
|
||||
if (!CBS_get_u8(&header, &length_byte)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t header_len = CBS_len(cbs) - CBS_len(&header);
|
||||
|
||||
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) + header_len;
|
||||
len = ((size_t) length_byte) + 2;
|
||||
if (out_header_len != NULL) {
|
||||
*out_header_len = header_len;
|
||||
*out_header_len = 2;
|
||||
}
|
||||
} else {
|
||||
// The high bit indicate that this is the long form, while the next 7 bits
|
||||
@@ -283,9 +224,9 @@ static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
|
||||
if (ber_ok && (tag & CBS_ASN1_CONSTRUCTED) != 0 && num_bytes == 0) {
|
||||
// indefinite length
|
||||
if (out_header_len != NULL) {
|
||||
*out_header_len = header_len;
|
||||
*out_header_len = 2;
|
||||
}
|
||||
return CBS_get_bytes(cbs, out, header_len);
|
||||
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
|
||||
@@ -308,13 +249,13 @@ static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
|
||||
return 0;
|
||||
}
|
||||
len = len32;
|
||||
if (len + header_len + num_bytes < len) {
|
||||
if (len + 2 + num_bytes < len) {
|
||||
// Overflow.
|
||||
return 0;
|
||||
}
|
||||
len += header_len + num_bytes;
|
||||
len += 2 + num_bytes;
|
||||
if (out_header_len != NULL) {
|
||||
*out_header_len = header_len + num_bytes;
|
||||
*out_header_len = 2 + num_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,10 +323,7 @@ int CBS_peek_asn1_tag(const CBS *cbs, unsigned tag_value) {
|
||||
if (CBS_len(cbs) < 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
CBS copy = *cbs;
|
||||
unsigned actual_tag;
|
||||
return parse_asn1_tag(©, &actual_tag) && tag_value == actual_tag;
|
||||
return CBS_data(cbs)[0] == tag_value;
|
||||
}
|
||||
|
||||
int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out) {
|
||||
@@ -425,22 +363,6 @@ int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CBS_get_asn1_bool(CBS *cbs, int *out) {
|
||||
CBS bytes;
|
||||
if (!CBS_get_asn1(cbs, &bytes, CBS_ASN1_BOOLEAN) ||
|
||||
CBS_len(&bytes) != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint8_t value = *CBS_data(&bytes);
|
||||
if (value != 0 && value != 0xff) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*out = !!value;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, unsigned tag) {
|
||||
int present = 0;
|
||||
|
||||
@@ -466,7 +388,6 @@ int CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out, int *out_present,
|
||||
return 0;
|
||||
}
|
||||
if (present) {
|
||||
assert(out);
|
||||
if (!CBS_get_asn1(&child, out, CBS_ASN1_OCTETSTRING) ||
|
||||
CBS_len(&child) != 0) {
|
||||
return 0;
|
||||
@@ -564,55 +485,3 @@ int CBS_asn1_bitstring_has_bit(const CBS *cbs, unsigned bit) {
|
||||
return byte_num < CBS_len(cbs) &&
|
||||
(CBS_data(cbs)[byte_num] & (1 << bit_num)) != 0;
|
||||
}
|
||||
|
||||
static int add_decimal(CBB *out, uint64_t v) {
|
||||
char buf[DECIMAL_SIZE(uint64_t) + 1];
|
||||
BIO_snprintf(buf, sizeof(buf), "%" PRIu64, v);
|
||||
return CBB_add_bytes(out, (const uint8_t *)buf, strlen(buf));
|
||||
}
|
||||
|
||||
char *CBS_asn1_oid_to_text(const CBS *cbs) {
|
||||
CBB cbb;
|
||||
if (!CBB_init(&cbb, 32)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
CBS copy = *cbs;
|
||||
// The first component is 40 * value1 + value2, where value1 is 0, 1, or 2.
|
||||
uint64_t v;
|
||||
if (!parse_base128_integer(©, &v)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (v >= 80) {
|
||||
if (!CBB_add_bytes(&cbb, (const uint8_t *)"2.", 2) ||
|
||||
!add_decimal(&cbb, v - 80)) {
|
||||
goto err;
|
||||
}
|
||||
} else if (!add_decimal(&cbb, v / 40) ||
|
||||
!CBB_add_u8(&cbb, '.') ||
|
||||
!add_decimal(&cbb, v % 40)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
while (CBS_len(©) != 0) {
|
||||
if (!parse_base128_integer(©, &v) ||
|
||||
!CBB_add_u8(&cbb, '.') ||
|
||||
!add_decimal(&cbb, v)) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *txt;
|
||||
size_t txt_len;
|
||||
if (!CBB_add_u8(&cbb, '\0') ||
|
||||
!CBB_finish(&cbb, &txt, &txt_len)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
return (char *)txt;
|
||||
|
||||
err:
|
||||
CBB_cleanup(&cbb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -24,10 +24,12 @@ extern "C" {
|
||||
|
||||
// CBS_asn1_ber_to_der reads a BER element from |in|. If it finds
|
||||
// indefinite-length elements or constructed strings then it converts the BER
|
||||
// data to DER, sets |out| to the converted contents and |*out_storage| to a
|
||||
// buffer which the caller must release with |OPENSSL_free|. Otherwise, it sets
|
||||
// |out| to the original BER element in |in| and |*out_storage| to NULL.
|
||||
// Additionally, |*in| will be advanced over the BER element.
|
||||
// data to DER and sets |*out| and |*out_length| to describe a malloced buffer
|
||||
// containing the DER data. Additionally, |*in| will be advanced over the BER
|
||||
// element.
|
||||
//
|
||||
// If it doesn't find any indefinite-length elements or constructed strings then
|
||||
// it sets |*out| to NULL and |*in| is unmodified.
|
||||
//
|
||||
// This function should successfully process any valid BER input, however it
|
||||
// will not convert all of BER's deviations from DER. BER is ambiguous between
|
||||
@@ -37,8 +39,7 @@ extern "C" {
|
||||
// must also account for BER variations in the contents of a primitive.
|
||||
//
|
||||
// It returns one on success and zero otherwise.
|
||||
OPENSSL_EXPORT int CBS_asn1_ber_to_der(CBS *in, CBS *out,
|
||||
uint8_t **out_storage);
|
||||
OPENSSL_EXPORT int CBS_asn1_ber_to_der(CBS *in, uint8_t **out, size_t *out_len);
|
||||
|
||||
// CBS_get_asn1_implicit_string parses a BER string of primitive type
|
||||
// |inner_tag| implicitly-tagged with |outer_tag|. It sets |out| to the
|
||||
@@ -67,28 +68,6 @@ OPENSSL_EXPORT int CBS_get_asn1_implicit_string(CBS *in, CBS *out,
|
||||
int CBB_finish_i2d(CBB *cbb, uint8_t **outp);
|
||||
|
||||
|
||||
// Unicode utilities.
|
||||
|
||||
// The following functions read one Unicode code point from |cbs| with the
|
||||
// corresponding encoding and store it in |*out|. They return one on success and
|
||||
// zero on error.
|
||||
OPENSSL_EXPORT int cbs_get_utf8(CBS *cbs, uint32_t *out);
|
||||
OPENSSL_EXPORT int cbs_get_latin1(CBS *cbs, uint32_t *out);
|
||||
OPENSSL_EXPORT int cbs_get_ucs2_be(CBS *cbs, uint32_t *out);
|
||||
OPENSSL_EXPORT int cbs_get_utf32_be(CBS *cbs, uint32_t *out);
|
||||
|
||||
// cbb_get_utf8_len returns the number of bytes needed to represent |u| in
|
||||
// UTF-8.
|
||||
OPENSSL_EXPORT size_t cbb_get_utf8_len(uint32_t u);
|
||||
|
||||
// The following functions encode |u| to |cbb| with the corresponding
|
||||
// encoding. They return one on success and zero on error.
|
||||
OPENSSL_EXPORT int cbb_add_utf8(CBB *cbb, uint32_t u);
|
||||
OPENSSL_EXPORT int cbb_add_latin1(CBB *cbb, uint32_t u);
|
||||
OPENSSL_EXPORT int cbb_add_ucs2_be(CBB *cbb, uint32_t u);
|
||||
OPENSSL_EXPORT int cbb_add_utf32_be(CBB *cbb, uint32_t u);
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} // extern C
|
||||
#endif
|
||||
|
||||
@@ -1,155 +0,0 @@
|
||||
/* Copyright (c) 2018, Google Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
#include <openssl/bytestring.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
static int is_valid_code_point(uint32_t v) {
|
||||
// References in the following are to Unicode 9.0.0.
|
||||
if (// The Unicode space runs from zero to 0x10ffff (3.4 D9).
|
||||
v > 0x10ffff ||
|
||||
// Values 0x...fffe, 0x...ffff, and 0xfdd0-0xfdef are permanently reserved
|
||||
// (3.4 D14)
|
||||
(v & 0xfffe) == 0xfffe ||
|
||||
(v >= 0xfdd0 && v <= 0xfdef) ||
|
||||
// Surrogate code points are invalid (3.2 C1).
|
||||
(v >= 0xd800 && v <= 0xdfff)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// BOTTOM_BITS returns a byte with the bottom |n| bits set.
|
||||
#define BOTTOM_BITS(n) (uint8_t)((1u << (n)) - 1)
|
||||
|
||||
// TOP_BITS returns a byte with the top |n| bits set.
|
||||
#define TOP_BITS(n) ((uint8_t)~BOTTOM_BITS(8 - (n)))
|
||||
|
||||
int cbs_get_utf8(CBS *cbs, uint32_t *out) {
|
||||
uint8_t c;
|
||||
if (!CBS_get_u8(cbs, &c)) {
|
||||
return 0;
|
||||
}
|
||||
if (c <= 0x7f) {
|
||||
*out = c;
|
||||
return 1;
|
||||
}
|
||||
uint32_t v, lower_bound;
|
||||
size_t len;
|
||||
if ((c & TOP_BITS(3)) == TOP_BITS(2)) {
|
||||
v = c & BOTTOM_BITS(5);
|
||||
len = 1;
|
||||
lower_bound = 0x80;
|
||||
} else if ((c & TOP_BITS(4)) == TOP_BITS(3)) {
|
||||
v = c & BOTTOM_BITS(4);
|
||||
len = 2;
|
||||
lower_bound = 0x800;
|
||||
} else if ((c & TOP_BITS(5)) == TOP_BITS(4)) {
|
||||
v = c & BOTTOM_BITS(3);
|
||||
len = 3;
|
||||
lower_bound = 0x10000;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (!CBS_get_u8(cbs, &c) ||
|
||||
(c & TOP_BITS(2)) != TOP_BITS(1)) {
|
||||
return 0;
|
||||
}
|
||||
v <<= 6;
|
||||
v |= c & BOTTOM_BITS(6);
|
||||
}
|
||||
if (!is_valid_code_point(v) ||
|
||||
v < lower_bound) {
|
||||
return 0;
|
||||
}
|
||||
*out = v;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cbs_get_latin1(CBS *cbs, uint32_t *out) {
|
||||
uint8_t c;
|
||||
if (!CBS_get_u8(cbs, &c)) {
|
||||
return 0;
|
||||
}
|
||||
*out = c;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cbs_get_ucs2_be(CBS *cbs, uint32_t *out) {
|
||||
// Note UCS-2 (used by BMPString) does not support surrogates.
|
||||
uint16_t c;
|
||||
if (!CBS_get_u16(cbs, &c) ||
|
||||
!is_valid_code_point(c)) {
|
||||
return 0;
|
||||
}
|
||||
*out = c;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cbs_get_utf32_be(CBS *cbs, uint32_t *out) {
|
||||
return CBS_get_u32(cbs, out) && is_valid_code_point(*out);
|
||||
}
|
||||
|
||||
size_t cbb_get_utf8_len(uint32_t u) {
|
||||
if (u <= 0x7f) {
|
||||
return 1;
|
||||
}
|
||||
if (u <= 0x7ff) {
|
||||
return 2;
|
||||
}
|
||||
if (u <= 0xffff) {
|
||||
return 3;
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
|
||||
int cbb_add_utf8(CBB *cbb, uint32_t u) {
|
||||
if (!is_valid_code_point(u)) {
|
||||
return 0;
|
||||
}
|
||||
if (u <= 0x7f) {
|
||||
return CBB_add_u8(cbb, (uint8_t)u);
|
||||
}
|
||||
if (u <= 0x7ff) {
|
||||
return CBB_add_u8(cbb, TOP_BITS(2) | (u >> 6)) &&
|
||||
CBB_add_u8(cbb, TOP_BITS(1) | (u & BOTTOM_BITS(6)));
|
||||
}
|
||||
if (u <= 0xffff) {
|
||||
return CBB_add_u8(cbb, TOP_BITS(3) | (u >> 12)) &&
|
||||
CBB_add_u8(cbb, TOP_BITS(1) | ((u >> 6) & BOTTOM_BITS(6))) &&
|
||||
CBB_add_u8(cbb, TOP_BITS(1) | (u & BOTTOM_BITS(6)));
|
||||
}
|
||||
if (u <= 0x10ffff) {
|
||||
return CBB_add_u8(cbb, TOP_BITS(4) | (u >> 18)) &&
|
||||
CBB_add_u8(cbb, TOP_BITS(1) | ((u >> 12) & BOTTOM_BITS(6))) &&
|
||||
CBB_add_u8(cbb, TOP_BITS(1) | ((u >> 6) & BOTTOM_BITS(6))) &&
|
||||
CBB_add_u8(cbb, TOP_BITS(1) | (u & BOTTOM_BITS(6)));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cbb_add_latin1(CBB *cbb, uint32_t u) {
|
||||
return u <= 0xff && CBB_add_u8(cbb, (uint8_t)u);
|
||||
}
|
||||
|
||||
int cbb_add_ucs2_be(CBB *cbb, uint32_t u) {
|
||||
return u <= 0xffff && is_valid_code_point(u) && CBB_add_u16(cbb, (uint16_t)u);
|
||||
}
|
||||
|
||||
int cbb_add_utf32_be(CBB *cbb, uint32_t u) {
|
||||
return is_valid_code_point(u) && CBB_add_u32(cbb, u);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
include_directories(../../include)
|
||||
|
||||
if(${ARCH} STREQUAL "arm")
|
||||
if (${ARCH} STREQUAL "arm")
|
||||
set(
|
||||
CHACHA_ARCH_SOURCES
|
||||
|
||||
@@ -8,7 +8,7 @@ if(${ARCH} STREQUAL "arm")
|
||||
)
|
||||
endif()
|
||||
|
||||
if(${ARCH} STREQUAL "aarch64")
|
||||
if (${ARCH} STREQUAL "aarch64")
|
||||
set(
|
||||
CHACHA_ARCH_SOURCES
|
||||
|
||||
@@ -16,7 +16,7 @@ if(${ARCH} STREQUAL "aarch64")
|
||||
)
|
||||
endif()
|
||||
|
||||
if(${ARCH} STREQUAL "x86")
|
||||
if (${ARCH} STREQUAL "x86")
|
||||
set(
|
||||
CHACHA_ARCH_SOURCES
|
||||
|
||||
@@ -24,7 +24,7 @@ if(${ARCH} STREQUAL "x86")
|
||||
)
|
||||
endif()
|
||||
|
||||
if(${ARCH} STREQUAL "x86_64")
|
||||
if (${ARCH} STREQUAL "x86_64")
|
||||
set(
|
||||
CHACHA_ARCH_SOURCES
|
||||
|
||||
|
||||
@@ -171,10 +171,6 @@ my @ret;
|
||||
$code.=<<___;
|
||||
#include <openssl/arm_arch.h>
|
||||
|
||||
@ Silence ARMv8 deprecated IT instruction warnings. This file is used by both
|
||||
@ ARMv7 and ARMv8 processors and does not use ARMv8 instructions.
|
||||
.arch armv7-a
|
||||
|
||||
.text
|
||||
#if defined(__thumb2__) || defined(__clang__)
|
||||
.syntax unified
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
# Denver 4.50/+82% 2.63 2.67(*)
|
||||
# X-Gene 9.50/+46% 8.82 8.89(*)
|
||||
# Mongoose 8.00/+44% 3.64 3.25
|
||||
# Kryo 8.17/+50% 4.83 4.65
|
||||
#
|
||||
# (*) it's expected that doubling interleave factor doesn't help
|
||||
# all processors, only those with higher NEON latency and
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
#! /usr/bin/env perl
|
||||
# Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the OpenSSL license (the "License"). You may not use
|
||||
# this file except in compliance with the License. You can obtain a copy
|
||||
# in the file LICENSE in the source distribution or at
|
||||
# https://www.openssl.org/source/license.html
|
||||
|
||||
#!/usr/bin/env perl
|
||||
#
|
||||
# ====================================================================
|
||||
# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
|
||||
|
||||
+13
-36
@@ -22,48 +22,12 @@
|
||||
#include <openssl/cpu.h>
|
||||
|
||||
#include "../internal.h"
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
#define U8TO32_LITTLE(p) \
|
||||
(((uint32_t)((p)[0])) | ((uint32_t)((p)[1]) << 8) | \
|
||||
((uint32_t)((p)[2]) << 16) | ((uint32_t)((p)[3]) << 24))
|
||||
|
||||
// sigma contains the ChaCha constants, which happen to be an ASCII string.
|
||||
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))))
|
||||
|
||||
// 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);
|
||||
|
||||
void CRYPTO_hchacha20(uint8_t out[32], const uint8_t key[32],
|
||||
const uint8_t nonce[16]) {
|
||||
uint32_t x[16];
|
||||
OPENSSL_memcpy(x, sigma, sizeof(sigma));
|
||||
OPENSSL_memcpy(&x[4], key, 32);
|
||||
OPENSSL_memcpy(&x[12], nonce, 16);
|
||||
|
||||
for (size_t i = 0; i < 20; i += 2) {
|
||||
QUARTERROUND(0, 4, 8, 12)
|
||||
QUARTERROUND(1, 5, 9, 13)
|
||||
QUARTERROUND(2, 6, 10, 14)
|
||||
QUARTERROUND(3, 7, 11, 15)
|
||||
QUARTERROUND(0, 5, 10, 15)
|
||||
QUARTERROUND(1, 6, 11, 12)
|
||||
QUARTERROUND(2, 7, 8, 13)
|
||||
QUARTERROUND(3, 4, 9, 14)
|
||||
}
|
||||
|
||||
OPENSSL_memcpy(out, &x[0], sizeof(uint32_t) * 4);
|
||||
OPENSSL_memcpy(&out[16], &x[12], sizeof(uint32_t) * 4);
|
||||
}
|
||||
|
||||
#if !defined(OPENSSL_NO_ASM) && \
|
||||
(defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \
|
||||
defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64))
|
||||
@@ -105,6 +69,12 @@ void CRYPTO_chacha_20(uint8_t *out, const uint8_t *in, size_t in_len,
|
||||
|
||||
#else
|
||||
|
||||
// sigma contains the ChaCha constants, which happen to be an ASCII string.
|
||||
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 U32TO8_LITTLE(p, v) \
|
||||
{ \
|
||||
(p)[0] = (v >> 0) & 0xff; \
|
||||
@@ -113,6 +83,13 @@ void CRYPTO_chacha_20(uint8_t *out, const uint8_t *in, size_t in_len,
|
||||
(p)[3] = (v >> 24) & 0xff; \
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// chacha_core performs 20 rounds of ChaCha on the input words in
|
||||
// |input| and writes the 64 output bytes to |output|.
|
||||
static void chacha_core(uint8_t output[64], const uint32_t input[16]) {
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
/* Copyright (c) 2018, Google Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
#ifndef OPENSSL_HEADER_CHACHA_INTERNAL
|
||||
#define OPENSSL_HEADER_CHACHA_INTERNAL
|
||||
|
||||
#include <openssl/base.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
// CRYPTO_hchacha20 computes the HChaCha20 function, which should only be used
|
||||
// as part of XChaCha20.
|
||||
void CRYPTO_hchacha20(uint8_t out[32], const uint8_t key[32],
|
||||
const uint8_t nonce[16]);
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} // extern C
|
||||
#endif
|
||||
|
||||
#endif // OPENSSL_HEADER_CHACHA_INTERNAL
|
||||
@@ -1,6 +1,6 @@
|
||||
include_directories(../../include)
|
||||
|
||||
if(${ARCH} STREQUAL "x86_64")
|
||||
if (${ARCH} STREQUAL "x86_64")
|
||||
set(
|
||||
CIPHER_ARCH_SOURCES
|
||||
|
||||
@@ -22,11 +22,11 @@ add_library(
|
||||
e_rc4.c
|
||||
e_aesgcmsiv.c
|
||||
e_aesctrhmac.c
|
||||
e_aesccm.c
|
||||
e_chacha20poly1305.c
|
||||
|
||||
tls_cbc.c
|
||||
e_tls.c
|
||||
e_ssl3.c
|
||||
|
||||
${CIPHER_ARCH_SOURCES}
|
||||
)
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#include "../internal.h"
|
||||
#include "../test/file_test.h"
|
||||
#include "../test/test_util.h"
|
||||
#include "../test/wycheproof_util.h"
|
||||
|
||||
|
||||
struct KnownAEAD {
|
||||
@@ -36,8 +35,8 @@ struct KnownAEAD {
|
||||
const char *test_vectors;
|
||||
// limited_implementation indicates that tests that assume a generic AEAD
|
||||
// interface should not be performed. For example, the key-wrap AEADs only
|
||||
// handle inputs that are a multiple of eight bytes in length and the TLS CBC
|
||||
// AEADs have the concept of “direction”.
|
||||
// handle inputs that are a multiple of eight bytes in length and the
|
||||
// SSLv3/TLS AEADs have the concept of “direction”.
|
||||
bool limited_implementation;
|
||||
// truncated_tags is true if the AEAD supports truncating tags to arbitrary
|
||||
// lengths.
|
||||
@@ -63,8 +62,6 @@ static const struct KnownAEAD kAEADs[] = {
|
||||
#endif
|
||||
{"ChaCha20Poly1305", EVP_aead_chacha20_poly1305,
|
||||
"chacha20_poly1305_tests.txt", false, true, 0},
|
||||
{"XChaCha20Poly1305", EVP_aead_xchacha20_poly1305,
|
||||
"xchacha20_poly1305_tests.txt", false, true, 0},
|
||||
{"AES_128_CBC_SHA1_TLS", EVP_aead_aes_128_cbc_sha1_tls,
|
||||
"aes_128_cbc_sha1_tls_tests.txt", true, false, 11},
|
||||
{"AES_128_CBC_SHA1_TLSImplicitIV",
|
||||
@@ -86,14 +83,16 @@ static const struct KnownAEAD kAEADs[] = {
|
||||
{"DES_EDE3_CBC_SHA1_TLSImplicitIV",
|
||||
EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv,
|
||||
"des_ede3_cbc_sha1_tls_implicit_iv_tests.txt", true, false, 11},
|
||||
{"AES_128_CBC_SHA1_SSL3", EVP_aead_aes_128_cbc_sha1_ssl3,
|
||||
"aes_128_cbc_sha1_ssl3_tests.txt", true, false, 9},
|
||||
{"AES_256_CBC_SHA1_SSL3", EVP_aead_aes_256_cbc_sha1_ssl3,
|
||||
"aes_256_cbc_sha1_ssl3_tests.txt", true, false, 9},
|
||||
{"DES_EDE3_CBC_SHA1_SSL3", EVP_aead_des_ede3_cbc_sha1_ssl3,
|
||||
"des_ede3_cbc_sha1_ssl3_tests.txt", true, false, 9},
|
||||
{"AES_128_CTR_HMAC_SHA256", EVP_aead_aes_128_ctr_hmac_sha256,
|
||||
"aes_128_ctr_hmac_sha256.txt", false, true, 0},
|
||||
{"AES_256_CTR_HMAC_SHA256", EVP_aead_aes_256_ctr_hmac_sha256,
|
||||
"aes_256_ctr_hmac_sha256.txt", false, true, 0},
|
||||
{"AES_128_CCM_BLUETOOTH", EVP_aead_aes_128_ccm_bluetooth,
|
||||
"aes_128_ccm_bluetooth_tests.txt", false, false, 0},
|
||||
{"AES_128_CCM_BLUETOOTH_8", EVP_aead_aes_128_ccm_bluetooth_8,
|
||||
"aes_128_ccm_bluetooth_8_tests.txt", false, false, 0},
|
||||
};
|
||||
|
||||
class PerAEADTest : public testing::TestWithParam<KnownAEAD> {
|
||||
@@ -652,164 +651,3 @@ TEST(AEADTest, AESGCMEmptyNonce) {
|
||||
EXPECT_EQ(ERR_LIB_CIPHER, ERR_GET_LIB(err));
|
||||
EXPECT_EQ(CIPHER_R_INVALID_NONCE_SIZE, ERR_GET_REASON(err));
|
||||
}
|
||||
|
||||
TEST(AEADTest, AESCCMLargeAD) {
|
||||
static const std::vector<uint8_t> kKey(16, 'A');
|
||||
static const std::vector<uint8_t> kNonce(13, 'N');
|
||||
static const std::vector<uint8_t> kAD(65536, 'D');
|
||||
static const std::vector<uint8_t> kPlaintext = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
|
||||
static const std::vector<uint8_t> kCiphertext = {
|
||||
0xa2, 0x12, 0x3f, 0x0b, 0x07, 0xd5, 0x02, 0xff,
|
||||
0xa9, 0xcd, 0xa0, 0xf3, 0x69, 0x1c, 0x49, 0x0c};
|
||||
static const std::vector<uint8_t> kTag = {0x4a, 0x31, 0x82, 0x96};
|
||||
|
||||
// Test AES-128-CCM-Bluetooth.
|
||||
bssl::ScopedEVP_AEAD_CTX ctx;
|
||||
ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), EVP_aead_aes_128_ccm_bluetooth(),
|
||||
kKey.data(), kKey.size(),
|
||||
EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr));
|
||||
|
||||
std::vector<uint8_t> out(kCiphertext.size() + kTag.size());
|
||||
size_t out_len;
|
||||
EXPECT_TRUE(EVP_AEAD_CTX_seal(ctx.get(), out.data(), &out_len, out.size(),
|
||||
kNonce.data(), kNonce.size(), kPlaintext.data(),
|
||||
kPlaintext.size(), kAD.data(), kAD.size()));
|
||||
|
||||
ASSERT_EQ(out_len, kCiphertext.size() + kTag.size());
|
||||
EXPECT_EQ(Bytes(kCiphertext), Bytes(out.data(), kCiphertext.size()));
|
||||
EXPECT_EQ(Bytes(kTag), Bytes(out.data() + kCiphertext.size(), kTag.size()));
|
||||
|
||||
EXPECT_TRUE(EVP_AEAD_CTX_open(ctx.get(), out.data(), &out_len, out.size(),
|
||||
kNonce.data(), kNonce.size(), out.data(),
|
||||
out.size(), kAD.data(), kAD.size()));
|
||||
|
||||
ASSERT_EQ(out_len, kPlaintext.size());
|
||||
EXPECT_EQ(Bytes(kPlaintext), Bytes(out.data(), kPlaintext.size()));
|
||||
}
|
||||
|
||||
static void RunWycheproofTestCase(FileTest *t, const EVP_AEAD *aead) {
|
||||
t->IgnoreInstruction("ivSize");
|
||||
|
||||
std::vector<uint8_t> aad, ct, iv, key, msg, tag;
|
||||
ASSERT_TRUE(t->GetBytes(&aad, "aad"));
|
||||
ASSERT_TRUE(t->GetBytes(&ct, "ct"));
|
||||
ASSERT_TRUE(t->GetBytes(&iv, "iv"));
|
||||
ASSERT_TRUE(t->GetBytes(&key, "key"));
|
||||
ASSERT_TRUE(t->GetBytes(&msg, "msg"));
|
||||
ASSERT_TRUE(t->GetBytes(&tag, "tag"));
|
||||
std::string tag_size_str;
|
||||
ASSERT_TRUE(t->GetInstruction(&tag_size_str, "tagSize"));
|
||||
size_t tag_size = static_cast<size_t>(atoi(tag_size_str.c_str()));
|
||||
ASSERT_EQ(0u, tag_size % 8);
|
||||
tag_size /= 8;
|
||||
WycheproofResult result;
|
||||
ASSERT_TRUE(GetWycheproofResult(t, &result));
|
||||
|
||||
std::vector<uint8_t> ct_and_tag = ct;
|
||||
ct_and_tag.insert(ct_and_tag.end(), tag.begin(), tag.end());
|
||||
|
||||
bssl::ScopedEVP_AEAD_CTX ctx;
|
||||
ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), aead, key.data(), key.size(),
|
||||
tag_size, nullptr));
|
||||
std::vector<uint8_t> out(msg.size());
|
||||
size_t out_len;
|
||||
// Wycheproof tags small AES-GCM IVs as "acceptable" and otherwise does not
|
||||
// use it in AEADs. Any AES-GCM IV that isn't 96 bits is absurd, but our API
|
||||
// supports those, so we treat "acceptable" as "valid" here.
|
||||
if (result != WycheproofResult::kInvalid) {
|
||||
// Decryption should succeed.
|
||||
ASSERT_TRUE(EVP_AEAD_CTX_open(ctx.get(), out.data(), &out_len, out.size(),
|
||||
iv.data(), iv.size(), ct_and_tag.data(),
|
||||
ct_and_tag.size(), aad.data(), aad.size()));
|
||||
EXPECT_EQ(Bytes(msg), Bytes(out.data(), out_len));
|
||||
|
||||
// Decryption in-place should succeed.
|
||||
out = ct_and_tag;
|
||||
ASSERT_TRUE(EVP_AEAD_CTX_open(ctx.get(), out.data(), &out_len, out.size(),
|
||||
iv.data(), iv.size(), out.data(), out.size(),
|
||||
aad.data(), aad.size()));
|
||||
EXPECT_EQ(Bytes(msg), Bytes(out.data(), out_len));
|
||||
|
||||
// AEADs are deterministic, so encryption should produce the same result.
|
||||
out.resize(ct_and_tag.size());
|
||||
ASSERT_TRUE(EVP_AEAD_CTX_seal(ctx.get(), out.data(), &out_len, out.size(),
|
||||
iv.data(), iv.size(), msg.data(), msg.size(),
|
||||
aad.data(), aad.size()));
|
||||
EXPECT_EQ(Bytes(ct_and_tag), Bytes(out.data(), out_len));
|
||||
|
||||
// Encrypt in-place.
|
||||
out = msg;
|
||||
out.resize(ct_and_tag.size());
|
||||
ASSERT_TRUE(EVP_AEAD_CTX_seal(ctx.get(), out.data(), &out_len, out.size(),
|
||||
iv.data(), iv.size(), out.data(), msg.size(),
|
||||
aad.data(), aad.size()));
|
||||
EXPECT_EQ(Bytes(ct_and_tag), Bytes(out.data(), out_len));
|
||||
} else {
|
||||
// Decryption should fail.
|
||||
EXPECT_FALSE(EVP_AEAD_CTX_open(ctx.get(), out.data(), &out_len, out.size(),
|
||||
iv.data(), iv.size(), ct_and_tag.data(),
|
||||
ct_and_tag.size(), aad.data(), aad.size()));
|
||||
|
||||
// Decryption in-place should also fail.
|
||||
out = ct_and_tag;
|
||||
EXPECT_FALSE(EVP_AEAD_CTX_open(ctx.get(), out.data(), &out_len, out.size(),
|
||||
iv.data(), iv.size(), out.data(), out.size(),
|
||||
aad.data(), aad.size()));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AEADTest, WycheproofAESGCMSIV) {
|
||||
FileTestGTest("third_party/wycheproof_testvectors/aes_gcm_siv_test.txt",
|
||||
[](FileTest *t) {
|
||||
std::string key_size_str;
|
||||
ASSERT_TRUE(t->GetInstruction(&key_size_str, "keySize"));
|
||||
const EVP_AEAD *aead;
|
||||
switch (atoi(key_size_str.c_str())) {
|
||||
case 128:
|
||||
aead = EVP_aead_aes_128_gcm_siv();
|
||||
break;
|
||||
case 256:
|
||||
aead = EVP_aead_aes_256_gcm_siv();
|
||||
break;
|
||||
default:
|
||||
FAIL() << "Unknown key size: " << key_size_str;
|
||||
}
|
||||
|
||||
RunWycheproofTestCase(t, aead);
|
||||
});
|
||||
}
|
||||
|
||||
TEST(AEADTest, WycheproofAESGCM) {
|
||||
FileTestGTest("third_party/wycheproof_testvectors/aes_gcm_test.txt",
|
||||
[](FileTest *t) {
|
||||
std::string key_size_str;
|
||||
ASSERT_TRUE(t->GetInstruction(&key_size_str, "keySize"));
|
||||
const EVP_AEAD *aead;
|
||||
switch (atoi(key_size_str.c_str())) {
|
||||
case 128:
|
||||
aead = EVP_aead_aes_128_gcm();
|
||||
break;
|
||||
case 192:
|
||||
// Skip AES-192-GCM tests.
|
||||
t->SkipCurrent();
|
||||
return;
|
||||
case 256:
|
||||
aead = EVP_aead_aes_256_gcm();
|
||||
break;
|
||||
default:
|
||||
FAIL() << "Unknown key size: " << key_size_str;
|
||||
}
|
||||
|
||||
RunWycheproofTestCase(t, aead);
|
||||
});
|
||||
}
|
||||
|
||||
TEST(AEADTest, WycheproofChaCha20Poly1305) {
|
||||
FileTestGTest("third_party/wycheproof_testvectors/chacha20_poly1305_test.txt",
|
||||
[](FileTest *t) {
|
||||
t->IgnoreInstruction("keySize");
|
||||
RunWycheproofTestCase(t, EVP_aead_chacha20_poly1305());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -94,41 +94,20 @@ const EVP_CIPHER *EVP_get_cipherbyname(const char *name) {
|
||||
} else if (OPENSSL_strcasecmp(name, "des-cbc") == 0) {
|
||||
return EVP_des_cbc();
|
||||
} else if (OPENSSL_strcasecmp(name, "des-ede3-cbc") == 0 ||
|
||||
// This is not a name used by OpenSSL, but tcpdump registers it
|
||||
// with |EVP_add_cipher_alias|. Our |EVP_add_cipher_alias| is a
|
||||
// no-op, so we support the name here.
|
||||
OPENSSL_strcasecmp(name, "3des") == 0) {
|
||||
return EVP_des_ede3_cbc();
|
||||
} else if (OPENSSL_strcasecmp(name, "aes-128-cbc") == 0) {
|
||||
return EVP_aes_128_cbc();
|
||||
} else if (OPENSSL_strcasecmp(name, "aes-192-cbc") == 0) {
|
||||
return EVP_aes_192_cbc();
|
||||
} else if (OPENSSL_strcasecmp(name, "aes-256-cbc") == 0) {
|
||||
return EVP_aes_256_cbc();
|
||||
} else if (OPENSSL_strcasecmp(name, "aes-128-ctr") == 0) {
|
||||
return EVP_aes_128_ctr();
|
||||
} else if (OPENSSL_strcasecmp(name, "aes-192-ctr") == 0) {
|
||||
return EVP_aes_192_ctr();
|
||||
} else if (OPENSSL_strcasecmp(name, "aes-256-ctr") == 0) {
|
||||
return EVP_aes_256_ctr();
|
||||
} else if (OPENSSL_strcasecmp(name, "aes-128-ecb") == 0) {
|
||||
return EVP_aes_128_ecb();
|
||||
} else if (OPENSSL_strcasecmp(name, "aes-192-ecb") == 0) {
|
||||
return EVP_aes_192_ecb();
|
||||
} else if (OPENSSL_strcasecmp(name, "aes-256-ecb") == 0) {
|
||||
return EVP_aes_256_ecb();
|
||||
} else if (OPENSSL_strcasecmp(name, "aes-128-gcm") == 0) {
|
||||
return EVP_aes_128_gcm();
|
||||
} else if (OPENSSL_strcasecmp(name, "aes-192-gcm") == 0) {
|
||||
return EVP_aes_192_gcm();
|
||||
} else if (OPENSSL_strcasecmp(name, "aes-256-gcm") == 0) {
|
||||
return EVP_aes_256_gcm();
|
||||
} else if (OPENSSL_strcasecmp(name, "aes-128-ofb") == 0) {
|
||||
return EVP_aes_128_ofb();
|
||||
} else if (OPENSSL_strcasecmp(name, "aes-192-ofb") == 0) {
|
||||
return EVP_aes_192_ofb();
|
||||
} else if (OPENSSL_strcasecmp(name, "aes-256-ofb") == 0) {
|
||||
return EVP_aes_256_ofb();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -51,11 +51,9 @@
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -63,11 +61,9 @@
|
||||
|
||||
#include <openssl/cipher.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/span.h>
|
||||
|
||||
#include "../test/file_test.h"
|
||||
#include "../test/test_util.h"
|
||||
#include "../test/wycheproof_util.h"
|
||||
|
||||
|
||||
static const EVP_CIPHER *GetCipher(const std::string &name) {
|
||||
@@ -101,8 +97,6 @@ static const EVP_CIPHER *GetCipher(const std::string &name) {
|
||||
return EVP_aes_192_ctr();
|
||||
} else if (name == "AES-192-ECB") {
|
||||
return EVP_aes_192_ecb();
|
||||
} else if (name == "AES-192-OFB") {
|
||||
return EVP_aes_192_ofb();
|
||||
} else if (name == "AES-256-CBC") {
|
||||
return EVP_aes_256_cbc();
|
||||
} else if (name == "AES-128-CTR") {
|
||||
@@ -117,38 +111,6 @@ static const EVP_CIPHER *GetCipher(const std::string &name) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool DoCipher(EVP_CIPHER_CTX *ctx, std::vector<uint8_t> *out,
|
||||
bssl::Span<const uint8_t> in, size_t chunk) {
|
||||
size_t max_out = in.size();
|
||||
if ((EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_NO_PADDING) == 0 &&
|
||||
EVP_CIPHER_CTX_encrypting(ctx)) {
|
||||
unsigned block_size = EVP_CIPHER_CTX_block_size(ctx);
|
||||
max_out += block_size - (max_out % block_size);
|
||||
}
|
||||
out->resize(max_out);
|
||||
|
||||
size_t total = 0;
|
||||
int len;
|
||||
while (!in.empty()) {
|
||||
size_t todo = chunk == 0 ? in.size() : std::min(in.size(), chunk);
|
||||
EXPECT_LE(todo, static_cast<size_t>(INT_MAX));
|
||||
if (!EVP_CipherUpdate(ctx, out->data() + total, &len, in.data(),
|
||||
static_cast<int>(todo))) {
|
||||
return false;
|
||||
}
|
||||
EXPECT_GE(len, 0);
|
||||
total += static_cast<size_t>(len);
|
||||
in = in.subspan(todo);
|
||||
}
|
||||
if (!EVP_CipherFinal_ex(ctx, out->data() + total, &len)) {
|
||||
return false;
|
||||
}
|
||||
EXPECT_GE(len, 0);
|
||||
total += static_cast<size_t>(len);
|
||||
out->resize(total);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void TestOperation(FileTest *t, const EVP_CIPHER *cipher, bool encrypt,
|
||||
size_t chunk_size, const std::vector<uint8_t> &key,
|
||||
const std::vector<uint8_t> &iv,
|
||||
@@ -172,40 +134,58 @@ static void TestOperation(FileTest *t, const EVP_CIPHER *cipher, bool encrypt,
|
||||
encrypt ? 1 : 0));
|
||||
if (t->HasAttribute("IV")) {
|
||||
if (is_aead) {
|
||||
ASSERT_TRUE(EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_AEAD_SET_IVLEN,
|
||||
iv.size(), 0));
|
||||
ASSERT_TRUE(
|
||||
EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, iv.size(), 0));
|
||||
} else {
|
||||
ASSERT_EQ(iv.size(), EVP_CIPHER_CTX_iv_length(ctx.get()));
|
||||
}
|
||||
}
|
||||
if (is_aead && !encrypt) {
|
||||
ASSERT_TRUE(EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_AEAD_SET_TAG,
|
||||
tag.size(),
|
||||
ASSERT_TRUE(EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, tag.size(),
|
||||
const_cast<uint8_t *>(tag.data())));
|
||||
}
|
||||
// The ciphers are run with no padding. For each of the ciphers we test, the
|
||||
// output size matches the input size.
|
||||
std::vector<uint8_t> result(in->size());
|
||||
ASSERT_EQ(in->size(), out->size());
|
||||
int unused, result_len1 = 0, result_len2;
|
||||
ASSERT_TRUE(EVP_CIPHER_CTX_set_key_length(ctx.get(), key.size()));
|
||||
ASSERT_TRUE(EVP_CipherInit_ex(ctx.get(), nullptr, nullptr, key.data(),
|
||||
iv.data(), -1));
|
||||
// Note: the deprecated |EVP_CIPHER|-based AEAD API is sensitive to whether
|
||||
// Note: the deprecated |EVP_CIPHER|-based AES-GCM API is sensitive to whether
|
||||
// parameters are NULL, so it is important to skip the |in| and |aad|
|
||||
// |EVP_CipherUpdate| calls when empty.
|
||||
if (!aad.empty()) {
|
||||
int unused;
|
||||
ASSERT_TRUE(
|
||||
EVP_CipherUpdate(ctx.get(), nullptr, &unused, aad.data(), aad.size()));
|
||||
}
|
||||
ASSERT_TRUE(EVP_CIPHER_CTX_set_padding(ctx.get(), 0));
|
||||
std::vector<uint8_t> result;
|
||||
ASSERT_TRUE(DoCipher(ctx.get(), &result, *in, chunk_size));
|
||||
if (chunk_size != 0) {
|
||||
for (size_t i = 0; i < in->size();) {
|
||||
size_t todo = chunk_size;
|
||||
if (i + todo > in->size()) {
|
||||
todo = in->size() - i;
|
||||
}
|
||||
|
||||
int len;
|
||||
ASSERT_TRUE(EVP_CipherUpdate(ctx.get(), result.data() + result_len1, &len,
|
||||
in->data() + i, todo));
|
||||
result_len1 += len;
|
||||
i += todo;
|
||||
}
|
||||
} else if (!in->empty()) {
|
||||
ASSERT_TRUE(EVP_CipherUpdate(ctx.get(), result.data(), &result_len1,
|
||||
in->data(), in->size()));
|
||||
}
|
||||
ASSERT_TRUE(
|
||||
EVP_CipherFinal_ex(ctx.get(), result.data() + result_len1, &result_len2));
|
||||
result.resize(result_len1 + result_len2);
|
||||
EXPECT_EQ(Bytes(*out), Bytes(result));
|
||||
if (encrypt && is_aead) {
|
||||
uint8_t rtag[16];
|
||||
ASSERT_LE(tag.size(), sizeof(rtag));
|
||||
ASSERT_TRUE(EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_AEAD_GET_TAG,
|
||||
tag.size(), rtag));
|
||||
ASSERT_TRUE(
|
||||
EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, tag.size(), rtag));
|
||||
EXPECT_EQ(Bytes(tag), Bytes(rtag, tag.size()));
|
||||
}
|
||||
}
|
||||
@@ -305,61 +285,3 @@ TEST(CipherTest, CAVP_TDES_CBC) {
|
||||
TEST(CipherTest, CAVP_TDES_ECB) {
|
||||
FileTestGTest("crypto/cipher_extra/test/nist_cavp/tdes_ecb.txt", TestCipher);
|
||||
}
|
||||
|
||||
TEST(CipherTest, WycheproofAESCBC) {
|
||||
FileTestGTest("third_party/wycheproof_testvectors/aes_cbc_pkcs5_test.txt",
|
||||
[](FileTest *t) {
|
||||
t->IgnoreInstruction("type");
|
||||
t->IgnoreInstruction("ivSize");
|
||||
|
||||
std::string key_size;
|
||||
ASSERT_TRUE(t->GetInstruction(&key_size, "keySize"));
|
||||
const EVP_CIPHER *cipher;
|
||||
switch (atoi(key_size.c_str())) {
|
||||
case 128:
|
||||
cipher = EVP_aes_128_cbc();
|
||||
break;
|
||||
case 192:
|
||||
cipher = EVP_aes_192_cbc();
|
||||
break;
|
||||
case 256:
|
||||
cipher = EVP_aes_256_cbc();
|
||||
break;
|
||||
default:
|
||||
FAIL() << "Unsupported key size: " << key_size;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> key, iv, msg, ct;
|
||||
ASSERT_TRUE(t->GetBytes(&key, "key"));
|
||||
ASSERT_TRUE(t->GetBytes(&iv, "iv"));
|
||||
ASSERT_TRUE(t->GetBytes(&msg, "msg"));
|
||||
ASSERT_TRUE(t->GetBytes(&ct, "ct"));
|
||||
ASSERT_EQ(EVP_CIPHER_key_length(cipher), key.size());
|
||||
ASSERT_EQ(EVP_CIPHER_iv_length(cipher), iv.size());
|
||||
WycheproofResult result;
|
||||
ASSERT_TRUE(GetWycheproofResult(t, &result));
|
||||
|
||||
bssl::ScopedEVP_CIPHER_CTX ctx;
|
||||
std::vector<uint8_t> out;
|
||||
const std::vector<size_t> chunk_sizes = {0, 1, 2, 5, 7, 8, 9, 15, 16,
|
||||
17, 31, 32, 33, 63, 64, 65, 512};
|
||||
for (size_t chunk : chunk_sizes) {
|
||||
SCOPED_TRACE(chunk);
|
||||
if (result == WycheproofResult::kValid) {
|
||||
ASSERT_TRUE(EVP_DecryptInit_ex(ctx.get(), cipher, nullptr, key.data(),
|
||||
iv.data()));
|
||||
ASSERT_TRUE(DoCipher(ctx.get(), &out, ct, chunk));
|
||||
EXPECT_EQ(Bytes(msg), Bytes(out));
|
||||
|
||||
ASSERT_TRUE(EVP_EncryptInit_ex(ctx.get(), cipher, nullptr, key.data(),
|
||||
iv.data()));
|
||||
ASSERT_TRUE(DoCipher(ctx.get(), &out, msg, chunk));
|
||||
EXPECT_EQ(Bytes(ct), Bytes(out));
|
||||
} else {
|
||||
ASSERT_TRUE(EVP_DecryptInit_ex(ctx.get(), cipher, nullptr, key.data(),
|
||||
iv.data()));
|
||||
EXPECT_FALSE(DoCipher(ctx.get(), &out, ct, chunk));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,203 +0,0 @@
|
||||
/* Copyright (c) 2018, Google Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
#include <openssl/aead.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <openssl/cipher.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "../fipsmodule/cipher/internal.h"
|
||||
|
||||
|
||||
#define EVP_AEAD_AES_CCM_MAX_TAG_LEN 16
|
||||
|
||||
struct aead_aes_ccm_ctx {
|
||||
union {
|
||||
double align;
|
||||
AES_KEY ks;
|
||||
} ks;
|
||||
CCM128_CONTEXT ccm;
|
||||
};
|
||||
|
||||
static int aead_aes_ccm_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
|
||||
size_t key_len, size_t tag_len, unsigned M,
|
||||
unsigned L) {
|
||||
assert(M == EVP_AEAD_max_overhead(ctx->aead));
|
||||
assert(M == EVP_AEAD_max_tag_len(ctx->aead));
|
||||
assert(15 - L == EVP_AEAD_nonce_length(ctx->aead));
|
||||
|
||||
if (key_len != EVP_AEAD_key_length(ctx->aead)) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH);
|
||||
return 0; // EVP_AEAD_CTX_init should catch this.
|
||||
}
|
||||
|
||||
if (tag_len == EVP_AEAD_DEFAULT_TAG_LENGTH) {
|
||||
tag_len = M;
|
||||
}
|
||||
|
||||
if (tag_len != M) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TAG_TOO_LARGE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct aead_aes_ccm_ctx *ccm_ctx =
|
||||
OPENSSL_malloc(sizeof(struct aead_aes_ccm_ctx));
|
||||
if (ccm_ctx == NULL) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
block128_f block;
|
||||
ctr128_f ctr = aes_ctr_set_key(&ccm_ctx->ks.ks, NULL, &block, key, key_len);
|
||||
ctx->tag_len = tag_len;
|
||||
if (!CRYPTO_ccm128_init(&ccm_ctx->ccm, &ccm_ctx->ks.ks, block, ctr, M, L)) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, ERR_R_INTERNAL_ERROR);
|
||||
OPENSSL_free(ccm_ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctx->aead_state = ccm_ctx;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void aead_aes_ccm_cleanup(EVP_AEAD_CTX *ctx) {
|
||||
OPENSSL_free(ctx->aead_state);
|
||||
}
|
||||
|
||||
static int aead_aes_ccm_seal_scatter(
|
||||
const EVP_AEAD_CTX *ctx, uint8_t *out, uint8_t *out_tag,
|
||||
size_t *out_tag_len, size_t max_out_tag_len, const uint8_t *nonce,
|
||||
size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *extra_in,
|
||||
size_t extra_in_len, const uint8_t *ad, size_t ad_len) {
|
||||
const struct aead_aes_ccm_ctx *ccm_ctx = ctx->aead_state;
|
||||
|
||||
if (in_len > CRYPTO_ccm128_max_input(&ccm_ctx->ccm)) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (max_out_tag_len < ctx->tag_len) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nonce_len != EVP_AEAD_nonce_length(ctx->aead)) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_NONCE_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!CRYPTO_ccm128_encrypt(&ccm_ctx->ccm, &ccm_ctx->ks.ks, out, out_tag,
|
||||
ctx->tag_len, nonce, nonce_len, in, in_len, ad,
|
||||
ad_len)) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*out_tag_len = ctx->tag_len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int aead_aes_ccm_open_gather(const EVP_AEAD_CTX *ctx, uint8_t *out,
|
||||
const uint8_t *nonce, size_t nonce_len,
|
||||
const uint8_t *in, size_t in_len,
|
||||
const uint8_t *in_tag, size_t in_tag_len,
|
||||
const uint8_t *ad, size_t ad_len) {
|
||||
const struct aead_aes_ccm_ctx *ccm_ctx = ctx->aead_state;
|
||||
|
||||
if (in_len > CRYPTO_ccm128_max_input(&ccm_ctx->ccm)) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nonce_len != EVP_AEAD_nonce_length(ctx->aead)) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_NONCE_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (in_tag_len != ctx->tag_len) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t tag[EVP_AEAD_AES_CCM_MAX_TAG_LEN];
|
||||
assert(ctx->tag_len <= EVP_AEAD_AES_CCM_MAX_TAG_LEN);
|
||||
if (!CRYPTO_ccm128_decrypt(&ccm_ctx->ccm, &ccm_ctx->ks.ks, out, tag,
|
||||
ctx->tag_len, nonce, nonce_len, in, in_len, ad,
|
||||
ad_len)) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (CRYPTO_memcmp(tag, in_tag, ctx->tag_len) != 0) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int aead_aes_ccm_bluetooth_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
|
||||
size_t key_len, size_t tag_len) {
|
||||
return aead_aes_ccm_init(ctx, key, key_len, tag_len, 4, 2);
|
||||
}
|
||||
|
||||
static const EVP_AEAD aead_aes_128_ccm_bluetooth = {
|
||||
16, // key length (AES-128)
|
||||
13, // nonce length
|
||||
4, // overhead
|
||||
4, // max tag length
|
||||
0, // seal_scatter_supports_extra_in
|
||||
|
||||
aead_aes_ccm_bluetooth_init,
|
||||
NULL /* init_with_direction */,
|
||||
aead_aes_ccm_cleanup,
|
||||
NULL /* open */,
|
||||
aead_aes_ccm_seal_scatter,
|
||||
aead_aes_ccm_open_gather,
|
||||
NULL /* get_iv */,
|
||||
NULL /* tag_len */,
|
||||
};
|
||||
|
||||
const EVP_AEAD *EVP_aead_aes_128_ccm_bluetooth(void) {
|
||||
return &aead_aes_128_ccm_bluetooth;
|
||||
}
|
||||
|
||||
static int aead_aes_ccm_bluetooth_8_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
|
||||
size_t key_len, size_t tag_len) {
|
||||
return aead_aes_ccm_init(ctx, key, key_len, tag_len, 8, 2);
|
||||
}
|
||||
|
||||
static const EVP_AEAD aead_aes_128_ccm_bluetooth_8 = {
|
||||
16, // key length (AES-128)
|
||||
13, // nonce length
|
||||
8, // overhead
|
||||
8, // max tag length
|
||||
0, // seal_scatter_supports_extra_in
|
||||
|
||||
aead_aes_ccm_bluetooth_8_init,
|
||||
NULL /* init_with_direction */,
|
||||
aead_aes_ccm_cleanup,
|
||||
NULL /* open */,
|
||||
aead_aes_ccm_seal_scatter,
|
||||
aead_aes_ccm_open_gather,
|
||||
NULL /* get_iv */,
|
||||
NULL /* tag_len */,
|
||||
};
|
||||
|
||||
const EVP_AEAD *EVP_aead_aes_128_ccm_bluetooth_8(void) {
|
||||
return &aead_aes_128_ccm_bluetooth_8;
|
||||
}
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
#include "../fipsmodule/cipher/internal.h"
|
||||
#include "../internal.h"
|
||||
#include "../chacha/internal.h"
|
||||
|
||||
|
||||
#define POLY1305_TAG_LEN 16
|
||||
@@ -152,15 +151,16 @@ static void poly1305_update_length(poly1305_state *poly1305, size_t data_len) {
|
||||
}
|
||||
|
||||
// calc_tag fills |tag| with the authentication tag for the given inputs.
|
||||
static void calc_tag(uint8_t tag[POLY1305_TAG_LEN], const uint8_t *key,
|
||||
static void calc_tag(uint8_t tag[POLY1305_TAG_LEN],
|
||||
const struct aead_chacha20_poly1305_ctx *c20_ctx,
|
||||
const uint8_t nonce[12], const uint8_t *ad, size_t ad_len,
|
||||
const uint8_t *ciphertext, size_t ciphertext_len,
|
||||
const uint8_t *ciphertext_extra,
|
||||
size_t ciphertext_extra_len) {
|
||||
alignas(16) uint8_t poly1305_key[32];
|
||||
OPENSSL_memset(poly1305_key, 0, sizeof(poly1305_key));
|
||||
CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key), key, nonce,
|
||||
0);
|
||||
CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key),
|
||||
c20_ctx->key, nonce, 0);
|
||||
|
||||
static const uint8_t padding[16] = { 0 }; // Padding is all zeros.
|
||||
poly1305_state ctx;
|
||||
@@ -181,16 +181,18 @@ static void calc_tag(uint8_t tag[POLY1305_TAG_LEN], const uint8_t *key,
|
||||
CRYPTO_poly1305_finish(&ctx, tag);
|
||||
}
|
||||
|
||||
static int chacha20_poly1305_seal_scatter(
|
||||
const uint8_t *key, uint8_t *out, uint8_t *out_tag,
|
||||
static int aead_chacha20_poly1305_seal_scatter(
|
||||
const EVP_AEAD_CTX *ctx, uint8_t *out, uint8_t *out_tag,
|
||||
size_t *out_tag_len, size_t max_out_tag_len, const uint8_t *nonce,
|
||||
size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *extra_in,
|
||||
size_t extra_in_len, const uint8_t *ad, size_t ad_len, size_t tag_len) {
|
||||
if (extra_in_len + tag_len < tag_len) {
|
||||
size_t extra_in_len, const uint8_t *ad, size_t ad_len) {
|
||||
const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
|
||||
|
||||
if (extra_in_len + ctx->tag_len < ctx->tag_len) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
|
||||
return 0;
|
||||
}
|
||||
if (max_out_tag_len < tag_len + extra_in_len) {
|
||||
if (max_out_tag_len < ctx->tag_len + extra_in_len) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
|
||||
return 0;
|
||||
}
|
||||
@@ -211,7 +213,7 @@ static int chacha20_poly1305_seal_scatter(
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (max_out_tag_len < tag_len) {
|
||||
if (max_out_tag_len < ctx->tag_len) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
|
||||
return 0;
|
||||
}
|
||||
@@ -226,7 +228,7 @@ static int chacha20_poly1305_seal_scatter(
|
||||
|
||||
for (size_t done = 0; done < extra_in_len; block_counter++) {
|
||||
memset(block, 0, sizeof(block));
|
||||
CRYPTO_chacha_20(block, block, sizeof(block), key, nonce,
|
||||
CRYPTO_chacha_20(block, block, sizeof(block), c20_ctx->key, nonce,
|
||||
block_counter);
|
||||
for (size_t i = offset; i < sizeof(block) && done < extra_in_len;
|
||||
i++, done++) {
|
||||
@@ -238,69 +240,35 @@ static int chacha20_poly1305_seal_scatter(
|
||||
|
||||
union seal_data data;
|
||||
if (asm_capable()) {
|
||||
OPENSSL_memcpy(data.in.key, key, 32);
|
||||
OPENSSL_memcpy(data.in.key, c20_ctx->key, 32);
|
||||
data.in.counter = 0;
|
||||
OPENSSL_memcpy(data.in.nonce, nonce, 12);
|
||||
data.in.extra_ciphertext = out_tag;
|
||||
data.in.extra_ciphertext_len = extra_in_len;
|
||||
chacha20_poly1305_seal(out, in, in_len, ad, ad_len, &data);
|
||||
} else {
|
||||
CRYPTO_chacha_20(out, in, in_len, key, nonce, 1);
|
||||
calc_tag(data.out.tag, key, nonce, ad, ad_len, out, in_len, out_tag,
|
||||
CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, nonce, 1);
|
||||
calc_tag(data.out.tag, c20_ctx, nonce, ad, ad_len, out, in_len, out_tag,
|
||||
extra_in_len);
|
||||
}
|
||||
|
||||
OPENSSL_memcpy(out_tag + extra_in_len, data.out.tag, tag_len);
|
||||
*out_tag_len = extra_in_len + tag_len;
|
||||
OPENSSL_memcpy(out_tag + extra_in_len, data.out.tag, ctx->tag_len);
|
||||
*out_tag_len = extra_in_len + ctx->tag_len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int aead_chacha20_poly1305_seal_scatter(
|
||||
const EVP_AEAD_CTX *ctx, uint8_t *out, uint8_t *out_tag,
|
||||
size_t *out_tag_len, size_t max_out_tag_len, const uint8_t *nonce,
|
||||
size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *extra_in,
|
||||
size_t extra_in_len, const uint8_t *ad, size_t ad_len) {
|
||||
const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
|
||||
|
||||
return chacha20_poly1305_seal_scatter(
|
||||
c20_ctx->key, out, out_tag, out_tag_len, max_out_tag_len, nonce,
|
||||
nonce_len, in, in_len, extra_in, extra_in_len, ad, ad_len, ctx->tag_len);
|
||||
}
|
||||
|
||||
static int aead_xchacha20_poly1305_seal_scatter(
|
||||
const EVP_AEAD_CTX *ctx, uint8_t *out, uint8_t *out_tag,
|
||||
size_t *out_tag_len, size_t max_out_tag_len, const uint8_t *nonce,
|
||||
size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *extra_in,
|
||||
size_t extra_in_len, const uint8_t *ad, size_t ad_len) {
|
||||
const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
|
||||
|
||||
if (nonce_len != 24) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
alignas(4) uint8_t derived_key[32];
|
||||
alignas(4) uint8_t derived_nonce[12];
|
||||
CRYPTO_hchacha20(derived_key, c20_ctx->key, nonce);
|
||||
OPENSSL_memset(derived_nonce, 0, 4);
|
||||
OPENSSL_memcpy(&derived_nonce[4], &nonce[16], 8);
|
||||
|
||||
return chacha20_poly1305_seal_scatter(
|
||||
derived_key, out, out_tag, out_tag_len, max_out_tag_len,
|
||||
derived_nonce, sizeof(derived_nonce), in, in_len, extra_in, extra_in_len,
|
||||
ad, ad_len, ctx->tag_len);
|
||||
}
|
||||
|
||||
static int chacha20_poly1305_open_gather(
|
||||
const uint8_t *key, uint8_t *out, const uint8_t *nonce,
|
||||
static int aead_chacha20_poly1305_open_gather(
|
||||
const EVP_AEAD_CTX *ctx, uint8_t *out, const uint8_t *nonce,
|
||||
size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *in_tag,
|
||||
size_t in_tag_len, const uint8_t *ad, size_t ad_len, size_t tag_len) {
|
||||
size_t in_tag_len, const uint8_t *ad, size_t ad_len) {
|
||||
const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
|
||||
|
||||
if (nonce_len != 12) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (in_tag_len != tag_len) {
|
||||
if (in_tag_len != ctx->tag_len) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
|
||||
return 0;
|
||||
}
|
||||
@@ -319,16 +287,16 @@ static int chacha20_poly1305_open_gather(
|
||||
|
||||
union open_data data;
|
||||
if (asm_capable()) {
|
||||
OPENSSL_memcpy(data.in.key, key, 32);
|
||||
OPENSSL_memcpy(data.in.key, c20_ctx->key, 32);
|
||||
data.in.counter = 0;
|
||||
OPENSSL_memcpy(data.in.nonce, nonce, 12);
|
||||
chacha20_poly1305_open(out, in, in_len, ad, ad_len, &data);
|
||||
} else {
|
||||
calc_tag(data.out.tag, key, nonce, ad, ad_len, in, in_len, NULL, 0);
|
||||
CRYPTO_chacha_20(out, in, in_len, key, nonce, 1);
|
||||
calc_tag(data.out.tag, c20_ctx, nonce, ad, ad_len, in, in_len, NULL, 0);
|
||||
CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, nonce, 1);
|
||||
}
|
||||
|
||||
if (CRYPTO_memcmp(data.out.tag, in_tag, tag_len) != 0) {
|
||||
if (CRYPTO_memcmp(data.out.tag, in_tag, ctx->tag_len) != 0) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
|
||||
return 0;
|
||||
}
|
||||
@@ -336,39 +304,6 @@ static int chacha20_poly1305_open_gather(
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int aead_chacha20_poly1305_open_gather(
|
||||
const EVP_AEAD_CTX *ctx, uint8_t *out, const uint8_t *nonce,
|
||||
size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *in_tag,
|
||||
size_t in_tag_len, const uint8_t *ad, size_t ad_len) {
|
||||
const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
|
||||
|
||||
return chacha20_poly1305_open_gather(c20_ctx->key, out, nonce, nonce_len, in,
|
||||
in_len, in_tag, in_tag_len, ad, ad_len,
|
||||
ctx->tag_len);
|
||||
}
|
||||
|
||||
static int aead_xchacha20_poly1305_open_gather(
|
||||
const EVP_AEAD_CTX *ctx, uint8_t *out, const uint8_t *nonce,
|
||||
size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *in_tag,
|
||||
size_t in_tag_len, const uint8_t *ad, size_t ad_len) {
|
||||
const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state;
|
||||
|
||||
if (nonce_len != 24) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
alignas(4) uint8_t derived_key[32];
|
||||
alignas(4) uint8_t derived_nonce[12];
|
||||
CRYPTO_hchacha20(derived_key, c20_ctx->key, nonce);
|
||||
OPENSSL_memset(derived_nonce, 0, 4);
|
||||
OPENSSL_memcpy(&derived_nonce[4], &nonce[16], 8);
|
||||
|
||||
return chacha20_poly1305_open_gather(
|
||||
derived_key, out, derived_nonce, sizeof(derived_nonce), in, in_len,
|
||||
in_tag, in_tag_len, ad, ad_len, ctx->tag_len);
|
||||
}
|
||||
|
||||
static const EVP_AEAD aead_chacha20_poly1305 = {
|
||||
32, // key len
|
||||
12, // nonce len
|
||||
@@ -386,27 +321,6 @@ static const EVP_AEAD aead_chacha20_poly1305 = {
|
||||
NULL, // tag_len
|
||||
};
|
||||
|
||||
static const EVP_AEAD aead_xchacha20_poly1305 = {
|
||||
32, // key len
|
||||
24, // nonce len
|
||||
POLY1305_TAG_LEN, // overhead
|
||||
POLY1305_TAG_LEN, // max tag length
|
||||
1, // seal_scatter_supports_extra_in
|
||||
|
||||
aead_chacha20_poly1305_init,
|
||||
NULL, // init_with_direction
|
||||
aead_chacha20_poly1305_cleanup,
|
||||
NULL /* open */,
|
||||
aead_xchacha20_poly1305_seal_scatter,
|
||||
aead_xchacha20_poly1305_open_gather,
|
||||
NULL, // get_iv
|
||||
NULL, // tag_len
|
||||
};
|
||||
|
||||
const EVP_AEAD *EVP_aead_chacha20_poly1305(void) {
|
||||
return &aead_chacha20_poly1305;
|
||||
}
|
||||
|
||||
const EVP_AEAD *EVP_aead_xchacha20_poly1305(void) {
|
||||
return &aead_xchacha20_poly1305;
|
||||
}
|
||||
|
||||
@@ -57,8 +57,6 @@
|
||||
#include <openssl/cipher.h>
|
||||
#include <openssl/nid.h>
|
||||
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
#define c2l(c, l) \
|
||||
do { \
|
||||
|
||||
@@ -0,0 +1,460 @@
|
||||
/* Copyright (c) 2014, Google Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/aead.h>
|
||||
#include <openssl/cipher.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "../internal.h"
|
||||
#include "../fipsmodule/cipher/internal.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
EVP_CIPHER_CTX cipher_ctx;
|
||||
EVP_MD_CTX md_ctx;
|
||||
} AEAD_SSL3_CTX;
|
||||
|
||||
static int ssl3_mac(AEAD_SSL3_CTX *ssl3_ctx, uint8_t *out, unsigned *out_len,
|
||||
const uint8_t *ad, size_t ad_len, const uint8_t *in,
|
||||
size_t in_len) {
|
||||
size_t md_size = EVP_MD_CTX_size(&ssl3_ctx->md_ctx);
|
||||
size_t pad_len = (md_size == 20) ? 40 : 48;
|
||||
|
||||
// To allow for CBC mode which changes cipher length, |ad| doesn't include the
|
||||
// length for legacy ciphers.
|
||||
uint8_t ad_extra[2];
|
||||
ad_extra[0] = (uint8_t)(in_len >> 8);
|
||||
ad_extra[1] = (uint8_t)(in_len & 0xff);
|
||||
|
||||
EVP_MD_CTX md_ctx;
|
||||
EVP_MD_CTX_init(&md_ctx);
|
||||
|
||||
uint8_t pad[48];
|
||||
uint8_t tmp[EVP_MAX_MD_SIZE];
|
||||
OPENSSL_memset(pad, 0x36, pad_len);
|
||||
if (!EVP_MD_CTX_copy_ex(&md_ctx, &ssl3_ctx->md_ctx) ||
|
||||
!EVP_DigestUpdate(&md_ctx, pad, pad_len) ||
|
||||
!EVP_DigestUpdate(&md_ctx, ad, ad_len) ||
|
||||
!EVP_DigestUpdate(&md_ctx, ad_extra, sizeof(ad_extra)) ||
|
||||
!EVP_DigestUpdate(&md_ctx, in, in_len) ||
|
||||
!EVP_DigestFinal_ex(&md_ctx, tmp, NULL)) {
|
||||
EVP_MD_CTX_cleanup(&md_ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
OPENSSL_memset(pad, 0x5c, pad_len);
|
||||
if (!EVP_MD_CTX_copy_ex(&md_ctx, &ssl3_ctx->md_ctx) ||
|
||||
!EVP_DigestUpdate(&md_ctx, pad, pad_len) ||
|
||||
!EVP_DigestUpdate(&md_ctx, tmp, md_size) ||
|
||||
!EVP_DigestFinal_ex(&md_ctx, out, out_len)) {
|
||||
EVP_MD_CTX_cleanup(&md_ctx);
|
||||
return 0;
|
||||
}
|
||||
EVP_MD_CTX_cleanup(&md_ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void aead_ssl3_cleanup(EVP_AEAD_CTX *ctx) {
|
||||
AEAD_SSL3_CTX *ssl3_ctx = (AEAD_SSL3_CTX *)ctx->aead_state;
|
||||
EVP_CIPHER_CTX_cleanup(&ssl3_ctx->cipher_ctx);
|
||||
EVP_MD_CTX_cleanup(&ssl3_ctx->md_ctx);
|
||||
OPENSSL_free(ssl3_ctx);
|
||||
ctx->aead_state = NULL;
|
||||
}
|
||||
|
||||
static int aead_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len,
|
||||
size_t tag_len, enum evp_aead_direction_t dir,
|
||||
const EVP_CIPHER *cipher, const EVP_MD *md) {
|
||||
if (tag_len != EVP_AEAD_DEFAULT_TAG_LENGTH &&
|
||||
tag_len != EVP_MD_size(md)) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_TAG_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (key_len != EVP_AEAD_key_length(ctx->aead)) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t mac_key_len = EVP_MD_size(md);
|
||||
size_t enc_key_len = EVP_CIPHER_key_length(cipher);
|
||||
assert(mac_key_len + enc_key_len + EVP_CIPHER_iv_length(cipher) == key_len);
|
||||
|
||||
AEAD_SSL3_CTX *ssl3_ctx = OPENSSL_malloc(sizeof(AEAD_SSL3_CTX));
|
||||
if (ssl3_ctx == NULL) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
EVP_CIPHER_CTX_init(&ssl3_ctx->cipher_ctx);
|
||||
EVP_MD_CTX_init(&ssl3_ctx->md_ctx);
|
||||
|
||||
ctx->aead_state = ssl3_ctx;
|
||||
if (!EVP_CipherInit_ex(&ssl3_ctx->cipher_ctx, cipher, NULL, &key[mac_key_len],
|
||||
&key[mac_key_len + enc_key_len],
|
||||
dir == evp_aead_seal) ||
|
||||
!EVP_DigestInit_ex(&ssl3_ctx->md_ctx, md, NULL) ||
|
||||
!EVP_DigestUpdate(&ssl3_ctx->md_ctx, key, mac_key_len)) {
|
||||
aead_ssl3_cleanup(ctx);
|
||||
ctx->aead_state = NULL;
|
||||
return 0;
|
||||
}
|
||||
EVP_CIPHER_CTX_set_padding(&ssl3_ctx->cipher_ctx, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static size_t aead_ssl3_tag_len(const EVP_AEAD_CTX *ctx, const size_t in_len,
|
||||
const size_t extra_in_len) {
|
||||
assert(extra_in_len == 0);
|
||||
const AEAD_SSL3_CTX *ssl3_ctx = (AEAD_SSL3_CTX*)ctx->aead_state;
|
||||
|
||||
const size_t digest_len = EVP_MD_CTX_size(&ssl3_ctx->md_ctx);
|
||||
if (EVP_CIPHER_CTX_mode(&ssl3_ctx->cipher_ctx) != EVP_CIPH_CBC_MODE) {
|
||||
// The NULL cipher.
|
||||
return digest_len;
|
||||
}
|
||||
|
||||
const size_t block_size = EVP_CIPHER_CTX_block_size(&ssl3_ctx->cipher_ctx);
|
||||
// An overflow of |in_len + digest_len| doesn't affect the result mod
|
||||
// |block_size|, provided that |block_size| is a smaller power of two.
|
||||
assert(block_size != 0 && (block_size & (block_size - 1)) == 0);
|
||||
const size_t pad_len = block_size - ((in_len + digest_len) % block_size);
|
||||
return digest_len + pad_len;
|
||||
}
|
||||
|
||||
static int aead_ssl3_seal_scatter(const EVP_AEAD_CTX *ctx, uint8_t *out,
|
||||
uint8_t *out_tag, size_t *out_tag_len,
|
||||
const size_t max_out_tag_len,
|
||||
const uint8_t *nonce, const size_t nonce_len,
|
||||
const uint8_t *in, const size_t in_len,
|
||||
const uint8_t *extra_in,
|
||||
const size_t extra_in_len, const uint8_t *ad,
|
||||
const size_t ad_len) {
|
||||
AEAD_SSL3_CTX *ssl3_ctx = (AEAD_SSL3_CTX *)ctx->aead_state;
|
||||
|
||||
if (!ssl3_ctx->cipher_ctx.encrypt) {
|
||||
// Unlike a normal AEAD, an SSL3 AEAD may only be used in one direction.
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_OPERATION);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (in_len > INT_MAX) {
|
||||
// EVP_CIPHER takes int as input.
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (max_out_tag_len < aead_ssl3_tag_len(ctx, in_len, extra_in_len)) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nonce_len != 0) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_IV_TOO_LARGE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ad_len != 11 - 2 /* length bytes */) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_AD_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Compute the MAC. This must be first in case the operation is being done
|
||||
// in-place.
|
||||
uint8_t mac[EVP_MAX_MD_SIZE];
|
||||
unsigned mac_len;
|
||||
if (!ssl3_mac(ssl3_ctx, mac, &mac_len, ad, ad_len, in, in_len)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Encrypt the input.
|
||||
int len;
|
||||
if (!EVP_EncryptUpdate(&ssl3_ctx->cipher_ctx, out, &len, in,
|
||||
(int)in_len)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const size_t block_size = EVP_CIPHER_CTX_block_size(&ssl3_ctx->cipher_ctx);
|
||||
|
||||
// Feed the MAC into the cipher in two steps. First complete the final partial
|
||||
// block from encrypting the input and split the result between |out| and
|
||||
// |out_tag|. Then encrypt the remainder.
|
||||
|
||||
size_t early_mac_len = (block_size - (in_len % block_size)) % block_size;
|
||||
if (early_mac_len != 0) {
|
||||
assert(len + block_size - early_mac_len == in_len);
|
||||
uint8_t buf[EVP_MAX_BLOCK_LENGTH];
|
||||
int buf_len;
|
||||
if (!EVP_EncryptUpdate(&ssl3_ctx->cipher_ctx, buf, &buf_len, mac,
|
||||
(int)early_mac_len)) {
|
||||
return 0;
|
||||
}
|
||||
assert(buf_len == (int)block_size);
|
||||
OPENSSL_memcpy(out + len, buf, block_size - early_mac_len);
|
||||
OPENSSL_memcpy(out_tag, buf + block_size - early_mac_len, early_mac_len);
|
||||
}
|
||||
size_t tag_len = early_mac_len;
|
||||
|
||||
if (!EVP_EncryptUpdate(&ssl3_ctx->cipher_ctx, out_tag + tag_len, &len,
|
||||
mac + tag_len, mac_len - tag_len)) {
|
||||
return 0;
|
||||
}
|
||||
tag_len += len;
|
||||
|
||||
if (block_size > 1) {
|
||||
assert(block_size <= 256);
|
||||
assert(EVP_CIPHER_CTX_mode(&ssl3_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE);
|
||||
|
||||
// Compute padding and feed that into the cipher.
|
||||
uint8_t padding[256];
|
||||
size_t padding_len = block_size - ((in_len + mac_len) % block_size);
|
||||
OPENSSL_memset(padding, 0, padding_len - 1);
|
||||
padding[padding_len - 1] = padding_len - 1;
|
||||
if (!EVP_EncryptUpdate(&ssl3_ctx->cipher_ctx, out_tag + tag_len, &len, padding,
|
||||
(int)padding_len)) {
|
||||
return 0;
|
||||
}
|
||||
tag_len += len;
|
||||
}
|
||||
|
||||
if (!EVP_EncryptFinal_ex(&ssl3_ctx->cipher_ctx, out_tag + tag_len, &len)) {
|
||||
return 0;
|
||||
}
|
||||
tag_len += len;
|
||||
assert(tag_len == aead_ssl3_tag_len(ctx, in_len, extra_in_len));
|
||||
|
||||
*out_tag_len = tag_len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int aead_ssl3_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) {
|
||||
AEAD_SSL3_CTX *ssl3_ctx = (AEAD_SSL3_CTX *)ctx->aead_state;
|
||||
|
||||
if (ssl3_ctx->cipher_ctx.encrypt) {
|
||||
// Unlike a normal AEAD, an SSL3 AEAD may only be used in one direction.
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_OPERATION);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t mac_len = EVP_MD_CTX_size(&ssl3_ctx->md_ctx);
|
||||
if (in_len < mac_len) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (max_out_len < in_len) {
|
||||
// This requires that the caller provide space for the MAC, even though it
|
||||
// will always be removed on return.
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nonce_len != 0) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ad_len != 11 - 2 /* length bytes */) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_AD_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (in_len > INT_MAX) {
|
||||
// EVP_CIPHER takes int as input.
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Decrypt to get the plaintext + MAC + padding.
|
||||
size_t total = 0;
|
||||
int len;
|
||||
if (!EVP_DecryptUpdate(&ssl3_ctx->cipher_ctx, out, &len, in, (int)in_len)) {
|
||||
return 0;
|
||||
}
|
||||
total += len;
|
||||
if (!EVP_DecryptFinal_ex(&ssl3_ctx->cipher_ctx, out + total, &len)) {
|
||||
return 0;
|
||||
}
|
||||
total += len;
|
||||
assert(total == in_len);
|
||||
|
||||
// Remove CBC padding and MAC. This would normally be timing-sensitive, but
|
||||
// SSLv3 CBC ciphers are already broken. Support will be removed eventually.
|
||||
// https://www.openssl.org/~bodo/ssl-poodle.pdf
|
||||
size_t data_len;
|
||||
if (EVP_CIPHER_CTX_mode(&ssl3_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE) {
|
||||
unsigned padding_length = out[total - 1];
|
||||
if (total < padding_length + 1 + mac_len) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
|
||||
return 0;
|
||||
}
|
||||
// The padding must be minimal.
|
||||
if (padding_length + 1 > EVP_CIPHER_CTX_block_size(&ssl3_ctx->cipher_ctx)) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
|
||||
return 0;
|
||||
}
|
||||
data_len = total - padding_length - 1 - mac_len;
|
||||
} else {
|
||||
data_len = total - mac_len;
|
||||
}
|
||||
|
||||
// Compute the MAC and compare against the one in the record.
|
||||
uint8_t mac[EVP_MAX_MD_SIZE];
|
||||
if (!ssl3_mac(ssl3_ctx, mac, NULL, ad, ad_len, out, data_len)) {
|
||||
return 0;
|
||||
}
|
||||
if (CRYPTO_memcmp(&out[data_len], mac, mac_len) != 0) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*out_len = data_len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int aead_ssl3_get_iv(const EVP_AEAD_CTX *ctx, const uint8_t **out_iv,
|
||||
size_t *out_iv_len) {
|
||||
AEAD_SSL3_CTX *ssl3_ctx = (AEAD_SSL3_CTX *)ctx->aead_state;
|
||||
const size_t iv_len = EVP_CIPHER_CTX_iv_length(&ssl3_ctx->cipher_ctx);
|
||||
if (iv_len <= 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*out_iv = ssl3_ctx->cipher_ctx.iv;
|
||||
*out_iv_len = iv_len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int aead_aes_128_cbc_sha1_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
|
||||
size_t key_len, size_t tag_len,
|
||||
enum evp_aead_direction_t dir) {
|
||||
return aead_ssl3_init(ctx, key, key_len, tag_len, dir, EVP_aes_128_cbc(),
|
||||
EVP_sha1());
|
||||
}
|
||||
|
||||
static int aead_aes_256_cbc_sha1_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
|
||||
size_t key_len, size_t tag_len,
|
||||
enum evp_aead_direction_t dir) {
|
||||
return aead_ssl3_init(ctx, key, key_len, tag_len, dir, EVP_aes_256_cbc(),
|
||||
EVP_sha1());
|
||||
}
|
||||
static int aead_des_ede3_cbc_sha1_ssl3_init(EVP_AEAD_CTX *ctx,
|
||||
const uint8_t *key, size_t key_len,
|
||||
size_t tag_len,
|
||||
enum evp_aead_direction_t dir) {
|
||||
return aead_ssl3_init(ctx, key, key_len, tag_len, dir, EVP_des_ede3_cbc(),
|
||||
EVP_sha1());
|
||||
}
|
||||
|
||||
static int aead_null_sha1_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
|
||||
size_t key_len, size_t tag_len,
|
||||
enum evp_aead_direction_t dir) {
|
||||
return aead_ssl3_init(ctx, key, key_len, tag_len, dir, EVP_enc_null(),
|
||||
EVP_sha1());
|
||||
}
|
||||
|
||||
static const EVP_AEAD aead_aes_128_cbc_sha1_ssl3 = {
|
||||
SHA_DIGEST_LENGTH + 16 + 16, // key len (SHA1 + AES128 + IV)
|
||||
0, // nonce len
|
||||
16 + SHA_DIGEST_LENGTH, // overhead (padding + SHA1)
|
||||
SHA_DIGEST_LENGTH, // max tag length
|
||||
0, // seal_scatter_supports_extra_in
|
||||
|
||||
NULL, // init
|
||||
aead_aes_128_cbc_sha1_ssl3_init,
|
||||
aead_ssl3_cleanup,
|
||||
aead_ssl3_open,
|
||||
aead_ssl3_seal_scatter,
|
||||
NULL, // open_gather
|
||||
aead_ssl3_get_iv,
|
||||
aead_ssl3_tag_len,
|
||||
};
|
||||
|
||||
static const EVP_AEAD aead_aes_256_cbc_sha1_ssl3 = {
|
||||
SHA_DIGEST_LENGTH + 32 + 16, // key len (SHA1 + AES256 + IV)
|
||||
0, // nonce len
|
||||
16 + SHA_DIGEST_LENGTH, // overhead (padding + SHA1)
|
||||
SHA_DIGEST_LENGTH, // max tag length
|
||||
0, // seal_scatter_supports_extra_in
|
||||
|
||||
NULL, // init
|
||||
aead_aes_256_cbc_sha1_ssl3_init,
|
||||
aead_ssl3_cleanup,
|
||||
aead_ssl3_open,
|
||||
aead_ssl3_seal_scatter,
|
||||
NULL, // open_gather
|
||||
aead_ssl3_get_iv,
|
||||
aead_ssl3_tag_len,
|
||||
};
|
||||
|
||||
static const EVP_AEAD aead_des_ede3_cbc_sha1_ssl3 = {
|
||||
SHA_DIGEST_LENGTH + 24 + 8, // key len (SHA1 + 3DES + IV)
|
||||
0, // nonce len
|
||||
8 + SHA_DIGEST_LENGTH, // overhead (padding + SHA1)
|
||||
SHA_DIGEST_LENGTH, // max tag length
|
||||
0, // seal_scatter_supports_extra_in
|
||||
|
||||
NULL, // init
|
||||
aead_des_ede3_cbc_sha1_ssl3_init,
|
||||
aead_ssl3_cleanup,
|
||||
aead_ssl3_open,
|
||||
aead_ssl3_seal_scatter,
|
||||
NULL, // open_gather
|
||||
aead_ssl3_get_iv,
|
||||
aead_ssl3_tag_len,
|
||||
};
|
||||
|
||||
static const EVP_AEAD aead_null_sha1_ssl3 = {
|
||||
SHA_DIGEST_LENGTH, // key len
|
||||
0, // nonce len
|
||||
SHA_DIGEST_LENGTH, // overhead (SHA1)
|
||||
SHA_DIGEST_LENGTH, // max tag length
|
||||
0, // seal_scatter_supports_extra_in
|
||||
|
||||
NULL, // init
|
||||
aead_null_sha1_ssl3_init,
|
||||
aead_ssl3_cleanup,
|
||||
aead_ssl3_open,
|
||||
aead_ssl3_seal_scatter,
|
||||
NULL, // open_gather
|
||||
NULL, // get_iv
|
||||
aead_ssl3_tag_len,
|
||||
};
|
||||
|
||||
const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_ssl3(void) {
|
||||
return &aead_aes_128_cbc_sha1_ssl3;
|
||||
}
|
||||
|
||||
const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_ssl3(void) {
|
||||
return &aead_aes_256_cbc_sha1_ssl3;
|
||||
}
|
||||
|
||||
const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_ssl3(void) {
|
||||
return &aead_des_ede3_cbc_sha1_ssl3;
|
||||
}
|
||||
|
||||
const EVP_AEAD *EVP_aead_null_sha1_ssl3(void) { return &aead_null_sha1_ssl3; }
|
||||
@@ -191,7 +191,8 @@ static int aead_tls_seal_scatter(const EVP_AEAD_CTX *ctx, uint8_t *out,
|
||||
// block from encrypting the input and split the result between |out| and
|
||||
// |out_tag|. Then feed the rest.
|
||||
|
||||
const size_t early_mac_len = (block_size - (in_len % block_size)) % block_size;
|
||||
const size_t early_mac_len =
|
||||
(block_size - (in_len % block_size) % block_size);
|
||||
if (early_mac_len != 0) {
|
||||
assert(len + block_size - early_mac_len == in_len);
|
||||
uint8_t buf[EVP_MAX_BLOCK_LENGTH];
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,105 +0,0 @@
|
||||
# From the Bluetooth Mesh Profile Specification v1.0.
|
||||
#
|
||||
# The relevant AES-CCM calls are:
|
||||
#
|
||||
# KEY: EncryptionKey
|
||||
# NONCE: Network Nonce
|
||||
# IN: DST || TransportPDU
|
||||
# AD: (none)
|
||||
# CT: EncTransportPDU
|
||||
# TAG: NetMIC
|
||||
#
|
||||
# KEY: DevKey if present, otherwise AppKey
|
||||
# NONCE: Application Nonce
|
||||
# IN: Access Payload
|
||||
# AD: Label UUID, if present
|
||||
# CT: EncAccessPayload
|
||||
# TAG: TransMIC
|
||||
|
||||
# Section 8.3.1.
|
||||
KEY: 0953fa93e7caac9638f58820220a398e
|
||||
NONCE: 00800000011201000012345678
|
||||
IN: fffd034b50057e400000010000
|
||||
AD:
|
||||
CT: b5e5bfdacbaf6cb7fb6bff871f
|
||||
TAG: 035444ce83a670df
|
||||
|
||||
# Section 8.3.2
|
||||
KEY: 0953fa93e7caac9638f58820220a398e
|
||||
NONCE: 00800148202345000012345678
|
||||
IN: 120104320308ba072f
|
||||
AD:
|
||||
CT: 79d7dbc0c9b4d43eeb
|
||||
TAG: ec129d20a620d01e
|
||||
|
||||
# Section 8.3.3.
|
||||
KEY: 0953fa93e7caac9638f58820220a398e
|
||||
NONCE: 00802b38322fe3000012345678
|
||||
IN: 120104fa0205a6000a
|
||||
AD:
|
||||
CT: 53273086b8c5ee00bd
|
||||
TAG: d9cfcc62a2ddf572
|
||||
|
||||
# Section 8.3.4.
|
||||
KEY: be635105434859f484fc798e043ce40e
|
||||
NONCE: 00800000021201000012345678
|
||||
IN: 23450100
|
||||
AD:
|
||||
CT: b0e5d0ad
|
||||
TAG: 970d579a4e88051c
|
||||
|
||||
# Section 8.3.5.
|
||||
KEY: be635105434859f484fc798e043ce40e
|
||||
NONCE: 00800148342345000012345678
|
||||
IN: 120102001234567800
|
||||
AD:
|
||||
CT: 5c39da1792b1fee9ec
|
||||
TAG: 74b786c56d3a9dee
|
||||
|
||||
# Section 8.3.7.
|
||||
KEY: 0953fa93e7caac9638f58820220a398e
|
||||
NONCE: 008b0148352345000012345678
|
||||
IN: 000300a6ac00000002
|
||||
AD:
|
||||
CT: 0d0d730f94d7f3509d
|
||||
TAG: f987bb417eb7c05f
|
||||
|
||||
# Section 8.3.9.
|
||||
KEY: 0953fa93e7caac9638f58820220a398e
|
||||
NONCE: 008b0148362345000012345678
|
||||
IN: 000300a6ac00000003
|
||||
AD:
|
||||
CT: d85d806bbed248614f
|
||||
TAG: 938067b0d983bb7b
|
||||
|
||||
# Section 8.3.10.
|
||||
KEY: be635105434859f484fc798e043ce40e
|
||||
NONCE: 00800000031201000012345678
|
||||
IN: 23450101
|
||||
AD:
|
||||
CT: 7777ed35
|
||||
TAG: 5afaf66d899c1e3d
|
||||
|
||||
# Section 8.3.12.
|
||||
KEY: be635105434859f484fc798e043ce40e
|
||||
NONCE: 00800000041201000012345678
|
||||
IN: 23450101
|
||||
AD:
|
||||
CT: ae214660
|
||||
TAG: 87599c2426ce9a35
|
||||
|
||||
# Section 8.3.14.
|
||||
KEY: be635105434859f484fc798e043ce40e
|
||||
NONCE: 00800000051201000012345678
|
||||
IN: 23450100
|
||||
AD:
|
||||
CT: 7d3ae62a
|
||||
TAG: 3c75dff683dce24e
|
||||
|
||||
# Section 8.3.24.
|
||||
KEY: 63964771734fbd76e3b40519d1d94a48
|
||||
NONCE: 010007080d1234973612345677
|
||||
IN: ea0a00576f726c64
|
||||
AD: f4a002c7fb1e4ca0a469a021de0db875
|
||||
CT: de1547118463123e
|
||||
TAG: 5f6a17b99dbca387
|
||||
@@ -1,208 +0,0 @@
|
||||
KEY: 404142434445464748494a4b4c4d4e4f
|
||||
NONCE: 101112131415161718191a1b1c
|
||||
IN: 20212223
|
||||
AD: 0001020304050607
|
||||
CT: 69915dad
|
||||
TAG: 064617ca
|
||||
|
||||
KEY: 404142434445464748494a4b4c4d4e4f
|
||||
NONCE: 101112131415161718191a1b1c
|
||||
IN: 202122232425262728292a2b2c2d2e2f
|
||||
AD: 0001020304050607
|
||||
CT: 69915dad1e84c6376a68c2967e4dab61
|
||||
TAG: 99763ebb
|
||||
|
||||
KEY: 404142434445464748494a4b4c4d4e4f
|
||||
NONCE: 101112131415161718191a1b1c
|
||||
IN: 202122232425262728292a2b2c2d2e2f
|
||||
AD:
|
||||
CT: 69915dad1e84c6376a68c2967e4dab61
|
||||
TAG: c4630026
|
||||
|
||||
# From the Bluetooth Mesh Profile Specification v1.0.
|
||||
#
|
||||
# The relevant AES-CCM calls are:
|
||||
#
|
||||
# KEY: EncryptionKey
|
||||
# NONCE: Network Nonce
|
||||
# IN: DST || TransportPDU
|
||||
# AD: (none)
|
||||
# CT: EncTransportPDU
|
||||
# TAG: NetMIC
|
||||
#
|
||||
# KEY: DevKey if present, otherwise AppKey
|
||||
# NONCE: Application Nonce
|
||||
# IN: Access Payload
|
||||
# AD: Label UUID, if present
|
||||
# CT: EncAccessPayload
|
||||
# TAG: TransMIC
|
||||
|
||||
# Section 8.3.6.
|
||||
KEY: 9d6dd0e96eb25dc19a40ed9914f8f03f
|
||||
NONCE: 02003129ab0003120112345678
|
||||
IN: 0056341263964771734fbd76e3b40519d1d94a48
|
||||
AD:
|
||||
CT: ee9dddfd2169326d23f3afdfcfdc18c52fdef772
|
||||
TAG: e0e17308
|
||||
|
||||
KEY: 0953fa93e7caac9638f58820220a398e
|
||||
NONCE: 00043129ab0003000012345678
|
||||
IN: 12018026ac01ee9dddfd2169326d23f3afdf
|
||||
AD:
|
||||
CT: 0afba8c63d4e686364979deaf4fd40961145
|
||||
TAG: 939cda0e
|
||||
|
||||
KEY: 0953fa93e7caac9638f58820220a398e
|
||||
NONCE: 00043129ac0003000012345678
|
||||
IN: 12018026ac21cfdc18c52fdef772e0e17308
|
||||
AD:
|
||||
CT: 6cae0c032bf0746f44f1b8cc8ce5edc57e55
|
||||
TAG: beed49c0
|
||||
|
||||
# Section 8.3.8.
|
||||
KEY: 0953fa93e7caac9638f58820220a398e
|
||||
NONCE: 00043129ad0003000012345678
|
||||
IN: 12018026ac01ee9dddfd2169326d23f3afdf
|
||||
AD:
|
||||
CT: 0e2f91add6f06e66006844cec97f973105ae
|
||||
TAG: 2534f958
|
||||
|
||||
# Section 8.3.11.
|
||||
KEY: be635105434859f484fc798e043ce40e
|
||||
NONCE: 00033129ad0003000012345678
|
||||
IN: 1201c026ac01ee9dddfd2169326d23f3afdf
|
||||
AD:
|
||||
CT: d5e748a20ecfd98ddfd32de80befb400213d
|
||||
TAG: 113813b5
|
||||
|
||||
# Section 8.3.13's test vector is identical to 8.3.11.
|
||||
|
||||
# Section 8.3.15.
|
||||
KEY: be635105434859f484fc798e043ce40e
|
||||
NONCE: 00033129ac0003000012345678
|
||||
IN: 12018026ac21cfdc18c52fdef772e0e17308
|
||||
AD:
|
||||
CT: f1d29805664d235eacd707217dedfe78497f
|
||||
TAG: efec7391
|
||||
|
||||
# Section 8.3.16.
|
||||
KEY: 9d6dd0e96eb25dc19a40ed9914f8f03f
|
||||
NONCE: 02000000061201000312345678
|
||||
IN: 800300563412
|
||||
AD:
|
||||
CT: 89511bf1d1a8
|
||||
TAG: 1c11dcef
|
||||
|
||||
KEY: 0953fa93e7caac9638f58820220a398e
|
||||
NONCE: 000b0000061201000012345678
|
||||
IN: 00030089511bf1d1a81c11dcef
|
||||
AD:
|
||||
CT: 6b9be7f5a642f2f98680e61c3a
|
||||
TAG: 8b47f228
|
||||
|
||||
# Section 8.3.17's test vector is identical to 8.3.16.
|
||||
|
||||
# Section 8.3.18.
|
||||
KEY: 63964771734fbd76e3b40519d1d94a48
|
||||
NONCE: 01000000071201ffff12345678
|
||||
IN: 0400000000
|
||||
AD:
|
||||
CT: 5a8bde6d91
|
||||
TAG: 06ea078a
|
||||
|
||||
KEY: 0953fa93e7caac9638f58820220a398e
|
||||
NONCE: 00030000071201000012345678
|
||||
IN: ffff665a8bde6d9106ea078a
|
||||
AD:
|
||||
CT: 5673728a627fb938535508e2
|
||||
TAG: 1a6baf57
|
||||
|
||||
# Section 8.3.19.
|
||||
KEY: 63964771734fbd76e3b40519d1d94a48
|
||||
NONCE: 01000000091201ffff12345678
|
||||
IN: 04000000010703
|
||||
AD:
|
||||
CT: ca6cd88e698d12
|
||||
TAG: 65f43fc5
|
||||
|
||||
KEY: 0953fa93e7caac9638f58820220a398e
|
||||
NONCE: 00030000091201000012345678
|
||||
IN: ffff66ca6cd88e698d1265f43fc5
|
||||
AD:
|
||||
CT: 3010a05e1b23a926023da75d25ba
|
||||
TAG: 91793736
|
||||
|
||||
# Section 8.3.20.
|
||||
KEY: 63964771734fbd76e3b40519d1d94a48
|
||||
NONCE: 01000708091234ffff12345677
|
||||
IN: 04000000010703
|
||||
AD:
|
||||
CT: 9c9803e110fea9
|
||||
TAG: 29e9542d
|
||||
|
||||
KEY: 0953fa93e7caac9638f58820220a398e
|
||||
NONCE: 00030708091234000012345677
|
||||
IN: ffff669c9803e110fea929e9542d
|
||||
AD:
|
||||
CT: 8c3dc87344a16c787f6b08cc897c
|
||||
TAG: 941a5368
|
||||
|
||||
# Section 8.3.21.
|
||||
KEY: 63964771734fbd76e3b40519d1d94a48
|
||||
NONCE: 010007080a1234810512345677
|
||||
IN: d50a0048656c6c6f
|
||||
AD:
|
||||
CT: 2fa730fd98f6e4bd
|
||||
TAG: 120ea9d6
|
||||
|
||||
KEY: 0953fa93e7caac9638f58820220a398e
|
||||
NONCE: 000307080a1234000012345677
|
||||
IN: 8105662fa730fd98f6e4bd120ea9d6
|
||||
AD:
|
||||
CT: e4d611358eaf17796a6c98977f69e5
|
||||
TAG: 872c4620
|
||||
|
||||
# Section 8.3.22.
|
||||
KEY: 63964771734fbd76e3b40519d1d94a48
|
||||
NONCE: 010007080b1234b52912345677
|
||||
IN: d50a0048656c6c6f
|
||||
AD: 0073e7e4d8b9440faf8415df4c56c0e1
|
||||
CT: 3871b904d4315263
|
||||
TAG: 16ca48a0
|
||||
|
||||
KEY: 0953fa93e7caac9638f58820220a398e
|
||||
NONCE: 000307080b1234000012345677
|
||||
IN: b529663871b904d431526316ca48a0
|
||||
AD:
|
||||
CT: ed31f3fdcf88a411135fea55df730b
|
||||
TAG: 6b28e255
|
||||
|
||||
# Section 8.3.23.
|
||||
KEY: 63964771734fbd76e3b40519d1d94a48
|
||||
NONCE: 010007080c1234973612345677
|
||||
IN: d50a0048656c6c6f
|
||||
AD: f4a002c7fb1e4ca0a469a021de0db875
|
||||
CT: 2456db5e3100eef6
|
||||
TAG: 5daa7a38
|
||||
|
||||
KEY: 0953fa93e7caac9638f58820220a398e
|
||||
NONCE: 000307080c1234000012345677
|
||||
IN: 9736662456db5e3100eef65daa7a38
|
||||
AD:
|
||||
CT: 7a9d696d3dd16a75489696f0b70c71
|
||||
TAG: 1b881385
|
||||
|
||||
# Section 8.3.24.
|
||||
KEY: 0953fa93e7caac9638f58820220a398e
|
||||
NONCE: 000307080d1234000012345677
|
||||
IN: 9736e6a03401de1547118463123e5f6a17b9
|
||||
AD:
|
||||
CT: 94e998b4081f5a7308ce3edbb3b06cdecd02
|
||||
TAG: 8e307f1c
|
||||
|
||||
KEY: 0953fa93e7caac9638f58820220a398e
|
||||
NONCE: 000307080e1234000012345677
|
||||
IN: 9736e6a034219dbca387
|
||||
AD:
|
||||
CT: dc2f4dd6fb4d32870129
|
||||
TAG: 1be4aafe
|
||||
File diff suppressed because it is too large
Load Diff
@@ -520,64 +520,6 @@ Operation = DECRYPT
|
||||
Plaintext = F69F2445DF4F9B17AD2B417BE66C3710
|
||||
Ciphertext = 304C6528F659C77866A510D9C1D6AE5E
|
||||
|
||||
# OFB-AES192.Encrypt
|
||||
Cipher = AES-192-OFB
|
||||
Key = 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
|
||||
IV = 000102030405060708090A0B0C0D0E0F
|
||||
Operation = ENCRYPT
|
||||
Plaintext = 6BC1BEE22E409F96E93D7E117393172A
|
||||
Ciphertext = CDC80D6FDDF18CAB34C25909C99A4174
|
||||
|
||||
Cipher = AES-192-OFB
|
||||
Key = 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
|
||||
IV = A609B38DF3B1133DDDFF2718BA09565E
|
||||
Operation = ENCRYPT
|
||||
Plaintext = AE2D8A571E03AC9C9EB76FAC45AF8E51
|
||||
Ciphertext = FCC28B8D4C63837C09E81700C1100401
|
||||
|
||||
Cipher = AES-192-OFB
|
||||
Key = 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
|
||||
IV = 52EF01DA52602FE0975F78AC84BF8A50
|
||||
Operation = ENCRYPT
|
||||
Plaintext = 30C81C46A35CE411E5FBC1191A0A52EF
|
||||
Ciphertext = 8D9A9AEAC0F6596F559C6D4DAF59A5F2
|
||||
|
||||
Cipher = AES-192-OFB
|
||||
Key = 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
|
||||
IV = BD5286AC63AABD7EB067AC54B553F71D
|
||||
Operation = ENCRYPT
|
||||
Plaintext = F69F2445DF4F9B17AD2B417BE66C3710
|
||||
Ciphertext = 6D9F200857CA6C3E9CAC524BD9ACC92A
|
||||
|
||||
# OFB-AES192.Decrypt
|
||||
Cipher = AES-192-OFB
|
||||
Key = 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
|
||||
IV = 000102030405060708090A0B0C0D0E0F
|
||||
Operation = ENCRYPT
|
||||
Plaintext = 6BC1BEE22E409F96E93D7E117393172A
|
||||
Ciphertext = CDC80D6FDDF18CAB34C25909C99A4174
|
||||
|
||||
Cipher = AES-192-OFB
|
||||
Key = 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
|
||||
IV = A609B38DF3B1133DDDFF2718BA09565E
|
||||
Operation = ENCRYPT
|
||||
Plaintext = AE2D8A571E03AC9C9EB76FAC45AF8E51
|
||||
Ciphertext = FCC28B8D4C63837C09E81700C1100401
|
||||
|
||||
Cipher = AES-192-OFB
|
||||
Key = 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
|
||||
IV = 52EF01DA52602FE0975F78AC84BF8A50
|
||||
Operation = ENCRYPT
|
||||
Plaintext = 30C81C46A35CE411E5FBC1191A0A52EF
|
||||
Ciphertext = 8D9A9AEAC0F6596F559C6D4DAF59A5F2
|
||||
|
||||
Cipher = AES-192-OFB
|
||||
Key = 8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B
|
||||
IV = BD5286AC63AABD7EB067AC54B553F71D
|
||||
Operation = ENCRYPT
|
||||
Plaintext = F69F2445DF4F9B17AD2B417BE66C3710
|
||||
Ciphertext = 6D9F200857CA6C3E9CAC524BD9ACC92A
|
||||
|
||||
# OFB-AES256.Encrypt
|
||||
Cipher = AES-256-OFB
|
||||
Key = 603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,3 +13,7 @@ go run make_legacy_aead_tests.go -cipher aes256 -mac sha384 > aes_256_cbc_sha384
|
||||
|
||||
go run make_legacy_aead_tests.go -cipher 3des -mac sha1 > des_ede3_cbc_sha1_tls_tests.txt
|
||||
go run make_legacy_aead_tests.go -cipher 3des -mac sha1 -implicit-iv > des_ede3_cbc_sha1_tls_implicit_iv_tests.txt
|
||||
|
||||
go run make_legacy_aead_tests.go -cipher aes128 -mac sha1 -ssl3 > aes_128_cbc_sha1_ssl3_tests.txt
|
||||
go run make_legacy_aead_tests.go -cipher aes256 -mac sha1 -ssl3 > aes_256_cbc_sha1_ssl3_tests.txt
|
||||
go run make_legacy_aead_tests.go -cipher 3des -mac sha1 -ssl3 > des_ede3_cbc_sha1_ssl3_tests.txt
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
var bulkCipher *string = flag.String("cipher", "", "The bulk cipher to use")
|
||||
var mac *string = flag.String("mac", "", "The hash function to use in the MAC")
|
||||
var implicitIV *bool = flag.Bool("implicit-iv", false, "If true, generate tests for a cipher using a pre-TLS-1.0 implicit IV")
|
||||
var ssl3 *bool = flag.Bool("ssl3", false, "If true, use the SSLv3 MAC and padding rather than TLS")
|
||||
|
||||
// rc4Stream produces a deterministic stream of pseudorandom bytes. This is to
|
||||
// make this script idempotent.
|
||||
@@ -83,6 +84,30 @@ func newBlockCipher(name string, key []byte) (cipher.Block, error) {
|
||||
}
|
||||
}
|
||||
|
||||
var ssl30Pad1 = [48]byte{0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}
|
||||
|
||||
var ssl30Pad2 = [48]byte{0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c}
|
||||
|
||||
func ssl30MAC(hash crypto.Hash, key, input, ad []byte) []byte {
|
||||
padLength := 48
|
||||
if hash.Size() == 20 {
|
||||
padLength = 40
|
||||
}
|
||||
|
||||
h := hash.New()
|
||||
h.Write(key)
|
||||
h.Write(ssl30Pad1[:padLength])
|
||||
h.Write(ad)
|
||||
h.Write(input)
|
||||
digestBuf := h.Sum(nil)
|
||||
|
||||
h.Reset()
|
||||
h.Write(key)
|
||||
h.Write(ssl30Pad2[:padLength])
|
||||
h.Write(digestBuf)
|
||||
return h.Sum(digestBuf[:0])
|
||||
}
|
||||
|
||||
type testCase struct {
|
||||
digest []byte
|
||||
key []byte
|
||||
@@ -123,7 +148,12 @@ func makeTestCase(length int, options options) (*testCase, error) {
|
||||
input := make([]byte, length)
|
||||
rand.fillBytes(input)
|
||||
|
||||
adFull := make([]byte, 13)
|
||||
var adFull []byte
|
||||
if *ssl3 {
|
||||
adFull = make([]byte, 11)
|
||||
} else {
|
||||
adFull = make([]byte, 13)
|
||||
}
|
||||
ad := adFull[:len(adFull)-2]
|
||||
rand.fillBytes(ad)
|
||||
adFull[len(adFull)-2] = uint8(length >> 8)
|
||||
@@ -137,10 +167,18 @@ func makeTestCase(length int, options options) (*testCase, error) {
|
||||
macKey := make([]byte, hash.Size())
|
||||
rand.fillBytes(macKey)
|
||||
|
||||
h := hmac.New(hash.New, macKey)
|
||||
h.Write(adFull)
|
||||
h.Write(input)
|
||||
digest := h.Sum(nil)
|
||||
var digest []byte
|
||||
if *ssl3 {
|
||||
if hash != crypto.SHA1 && hash != crypto.MD5 {
|
||||
return nil, fmt.Errorf("invalid hash for SSLv3: '%s'", *mac)
|
||||
}
|
||||
digest = ssl30MAC(hash, macKey, input, adFull)
|
||||
} else {
|
||||
h := hmac.New(hash.New, macKey)
|
||||
h.Write(adFull)
|
||||
h.Write(input)
|
||||
digest = h.Sum(nil)
|
||||
}
|
||||
|
||||
size := getKeySize(*bulkCipher)
|
||||
if size == 0 {
|
||||
@@ -160,7 +198,7 @@ func makeTestCase(length int, options options) (*testCase, error) {
|
||||
|
||||
iv := make([]byte, block.BlockSize())
|
||||
rand.fillBytes(iv)
|
||||
if *implicitIV {
|
||||
if *implicitIV || *ssl3 {
|
||||
fixedIV = iv
|
||||
} else {
|
||||
nonce = iv
|
||||
@@ -194,20 +232,31 @@ func makeTestCase(length int, options options) (*testCase, error) {
|
||||
paddingLen = 256
|
||||
}
|
||||
noSeal = true
|
||||
if *ssl3 {
|
||||
// SSLv3 padding must be minimal.
|
||||
fails = true
|
||||
}
|
||||
}
|
||||
pad := make([]byte, paddingLen)
|
||||
for i := range pad {
|
||||
pad[i] = byte(paddingLen - 1)
|
||||
if *ssl3 {
|
||||
sealed = append(sealed, make([]byte, paddingLen-1)...)
|
||||
sealed = append(sealed, byte(paddingLen-1))
|
||||
} else {
|
||||
pad := make([]byte, paddingLen)
|
||||
for i := range pad {
|
||||
pad[i] = byte(paddingLen - 1)
|
||||
}
|
||||
sealed = append(sealed, pad...)
|
||||
}
|
||||
sealed = append(sealed, pad...)
|
||||
if options.wrongPadding {
|
||||
if options.wrongPaddingOffset >= paddingLen {
|
||||
return nil, fmt.Errorf("invalid wrongPaddingOffset")
|
||||
}
|
||||
sealed[len(sealed)-paddingLen+options.wrongPaddingOffset]++
|
||||
noSeal = true
|
||||
// TLS specifies the all the padding bytes.
|
||||
fails = true
|
||||
if !*ssl3 {
|
||||
// TLS specifies the all the padding bytes.
|
||||
fails = true
|
||||
}
|
||||
}
|
||||
}
|
||||
cbc.CryptBlocks(sealed, sealed)
|
||||
@@ -265,6 +314,9 @@ func main() {
|
||||
if *implicitIV {
|
||||
commandLine += " -implicit-iv"
|
||||
}
|
||||
if *ssl3 {
|
||||
commandLine += " -ssl3"
|
||||
}
|
||||
fmt.Printf("# Generated by\n")
|
||||
fmt.Printf("# %s\n", commandLine)
|
||||
fmt.Printf("#\n")
|
||||
|
||||
@@ -1,416 +0,0 @@
|
||||
# Test vectors generated from libsodium with this code:
|
||||
#
|
||||
# #include <stdio.h>
|
||||
# #include <sodium.h>
|
||||
# #include <stdlib.h>
|
||||
#
|
||||
# void hexdump(const uint8_t *in, size_t in_len) {
|
||||
# for (size_t i = 0; i < in_len; i++) {
|
||||
# printf("%02x", in[i]);
|
||||
# }
|
||||
# printf("\n");
|
||||
# }
|
||||
#
|
||||
# int main() {
|
||||
# uint8_t nonce[24];
|
||||
# uint8_t key[32];
|
||||
# uint8_t m[64], c[64];
|
||||
# uint8_t ad[16], tag[16];
|
||||
#
|
||||
# for (size_t ad_len = 0; ad_len < sizeof(ad); ad_len += 4) {
|
||||
# for (size_t m_len = 0; m_len < sizeof(m); m_len += 5) {
|
||||
# randombytes(nonce, sizeof(nonce));
|
||||
# randombytes(key, sizeof(key));
|
||||
# randombytes(m, m_len);
|
||||
# randombytes(ad, ad_len);
|
||||
#
|
||||
# unsigned long long tag_len = sizeof(tag);
|
||||
#
|
||||
# if (crypto_aead_xchacha20poly1305_ietf_encrypt_detached(
|
||||
# c, tag, &tag_len, m, m_len, ad, ad_len, NULL, nonce, key)) {
|
||||
# abort();
|
||||
# }
|
||||
#
|
||||
# printf("KEY: ");
|
||||
# hexdump(key, sizeof(key));
|
||||
# printf("NONCE: ");
|
||||
# hexdump(nonce, sizeof(nonce));
|
||||
# printf("IN: ");
|
||||
# hexdump(m, m_len);
|
||||
# printf("AD: ");
|
||||
# hexdump(ad, ad_len);
|
||||
# printf("CT: ");
|
||||
# hexdump(c, m_len);
|
||||
# printf("TAG: ");
|
||||
# hexdump(tag, sizeof(tag));
|
||||
# printf("\n");
|
||||
# }
|
||||
# }
|
||||
#
|
||||
# return 0;
|
||||
# }
|
||||
|
||||
KEY: 1f4774fbe6324700d62dd6a104e7b3ca7160cfd958413f2afdb96695475f007e
|
||||
NONCE: 029174e5102710975a8a4a936075eb3e0f470d436884d250
|
||||
IN:
|
||||
AD:
|
||||
CT:
|
||||
TAG: f55cf0949af356f977479f1f187d7291
|
||||
|
||||
KEY: eb27969c7abf9aff79348e1e77f1fcba7508ceb29a7471961b017aef9ceaf1c2
|
||||
NONCE: 990009311eab3459c1bee84b5b860bb5bdf93c7bec8767e2
|
||||
IN: e7ec3d4b9f
|
||||
AD:
|
||||
CT: 66bd484861
|
||||
TAG: 07e31b4dd0f51f0819a0641c86380f32
|
||||
|
||||
KEY: 4b6d89dbd7d019c0e1683d4c2a497305c778e2089ddb0f383f2c7fa2a5a52153
|
||||
NONCE: 97525eb02a8d347fcf38c81b1be5c3ba59406241cf251ba6
|
||||
IN: 074db54ef9fbc680b41a
|
||||
AD:
|
||||
CT: 1221898afd6f516f770f
|
||||
TAG: 75e7182e7d715f5a32ee6733fd324539
|
||||
|
||||
KEY: 766997b1dc6c3c73b1f50e8c28c0fcb90f206258e685aff320f2d4884506c8f4
|
||||
NONCE: 30e7a9454892ef304776b6dc3d2c2f767ed97041b331c173
|
||||
IN: b8250c93ac6cf28902137b4522cc67
|
||||
AD:
|
||||
CT: e2a13eeff8831a35d9336cb3b5c5d9
|
||||
TAG: 62fdf67735cad0172f9b88603b5f3c13
|
||||
|
||||
KEY: 6585031b5649fcabd9d4971d4ac5646fc7dca22f991dfa7dac39647001004e20
|
||||
NONCE: 705ee25d03fec430e24c9c6ccaa633f5b86dd43682778278
|
||||
IN: 9a4ca0633886a742e0241f132e8f90794c34dfd4
|
||||
AD:
|
||||
CT: 0a8e6fd4cd1640be77c4c87dde4ae6222c887ed7
|
||||
TAG: edc4fbc91dfa07021e74ae0d9d1c98dc
|
||||
|
||||
KEY: dfc6f7c86a10a319ebcb6362997e585f55b67f3434f47dc4039c2d67973e3077
|
||||
NONCE: 6097f30fd75229d928454c7d59a2d2c58bfddcb14c16438e
|
||||
IN: 74c946a7f0733377e852a23087506a28dccef86e101a4359c0
|
||||
AD:
|
||||
CT: 6e8ea0bb4c2f1323841d8e236816c61c3295866b75cefb5c25
|
||||
TAG: f16c0e9487ca7de5e7cb2a1b8bb370fc
|
||||
|
||||
KEY: 59b8d488773767c4804d918709cfec6c69a193371145bb94f183899851aaadac
|
||||
NONCE: ad5bdf8f190ca2d2cc02a75bb62aa22274cb3c98fe2d25f2
|
||||
IN: 066b9ed10f16d3dc132b409aae02d8cac209dd9b4fb789c4d34725ab2a1f
|
||||
AD:
|
||||
CT: 2bbd4542489006df66ad1462a932524642b139ddcbf86b6b480e9e6d976c
|
||||
TAG: ca4835419ba029bc57010a8cc8bca80c
|
||||
|
||||
KEY: 8c0cb4633cf8dc6b4b9552d1035f85517cb1ba4c36bcbc43338a8c6c7d15ce20
|
||||
NONCE: 8418b9655a0376fadefa3cdf8805815c4f7b56f467a74a95
|
||||
IN: 50c205a9c5d4088ba8e59a96fcd837f5170669854547678288199f1078ff2a81f0b19a
|
||||
AD:
|
||||
CT: 8b55a12df1a85dd3fb19c34ab047a85849d15a30225bb5360bad1f0a8f5f2bd49f5898
|
||||
TAG: bce13201df6e4a7e6d896262e45d969d
|
||||
|
||||
KEY: b45386a75a5772e34bd193e1946f69ebfb90c37ae4581d39c9669d75e4584f50
|
||||
NONCE: 9fb763d0926585b5f726af9b8e3babdb331e9aa97f8d99ed
|
||||
IN: 64df0e341145d9e4a0d090153591a74893bc36cb9dae1e9570d8fee62e907cf004f9d8a360343483
|
||||
AD:
|
||||
CT: 3146d8a5c898edd832ec9d126e93b3a433ec97dc47dce0e1985bda88c88c6aeca46fc7d9a68e30ab
|
||||
TAG: 44fdb0d69abd8068442cb2ea6df8b2f2
|
||||
|
||||
KEY: f2efbd358dd353639a162be39a957d27c0175d5ab72aeba4a266aeda434e4a58
|
||||
NONCE: 65a6f7ebe48de78beb183b518589a0afacf71b40a949fa59
|
||||
IN: f7473947996e6682a3b9c720f03cfaf26bbcdaf76c83342d2ad922435e227a5d1eacbd9bd6ea1727ec19fb0e42
|
||||
AD:
|
||||
CT: 778a0fb701b9d671ccfaf1454e8928158ede9bb4395119356a8133036840c1bcbb8fe5e19922fbbcf8b18596e7
|
||||
TAG: 9d195a89fdd29ca271405d3330f996f9
|
||||
|
||||
KEY: 9dd674fb4a30a7bb85fc78050479ab0e2c3cc9f9f5b8689a7a67413aca304b21
|
||||
NONCE: ad9e8fe15940694725f232e88f79cda7c82fe1b8aae58ba4
|
||||
IN: 7272bb6609cbd1399a0b89f6ea255165f99330aeb170ac88fccdd8e226df0952407e35718fb5edc9e987faabb271cc69f7e7
|
||||
AD:
|
||||
CT: 846901650cb38974463a18c367676e1579ebdaf3e96b57224e842f5d5f678f3270b9a15f01241795662befb3db0768800e25
|
||||
TAG: 900004db3613acbeb33d65d74dd437d7
|
||||
|
||||
KEY: 280cbe7380a0d8bb4d8dd4476012f2eeb388a37b8b71067969abb99f6a888007
|
||||
NONCE: 2e1854617c67002599e6b077a812c326deb22fe29d093cbb
|
||||
IN: d0901ec3d31ece2832685ff577f383bdff26c31341ea254acee7c5929a5df74fea2aa964524dc680b2f55fbd4fea900e956c304cc4ac3c
|
||||
AD:
|
||||
CT: 546370726cc63068d3520d67f4f57f65d03b9ecec21c2a8c7b1133089ad28b07025a7181bddeb4a49f514fac1a44f64ee3af33d778fb98
|
||||
TAG: 39084e33e42a1b05f58da65ba487d138
|
||||
|
||||
KEY: 887564f75afa78f595cdadcea7340d20f5c5a2df169d0ad14b15fe32ce337004
|
||||
NONCE: 54c11df13d1f444da80b0964caeb59474b17b23a650a33f5
|
||||
IN: f0f008eece79ecb24b715dff8a3456dfe253924b99f98f2f1b18564cced50925fca860d1c2d4785bdf4a964c76c3079efa6b37c4ba2cacc534fb590c
|
||||
AD:
|
||||
CT: 32bb077268568d569b39e8ccdeeeb447ef424eaa2ffab565209a19b16a25952f897e5405bb0d67d8c9005d1c0b32687164d17fa4d0f412b80414c025
|
||||
TAG: 0bac7c0f8dce12917fbd4ed1738ac0cc
|
||||
|
||||
KEY: 21c6aa88eb1a320d251f71a4b312ca75347040990d869a1dd2a1982c30fda2c7
|
||||
NONCE: 7dead2f1a3d9d45a9124a40efe8994300976991a4417ef4d
|
||||
IN:
|
||||
AD: e1bf7de4
|
||||
CT:
|
||||
TAG: 341e9d0687006f981bced2f985f953e6
|
||||
|
||||
KEY: 0c97b9a65ffcd80b8f7c20c3904d0d6dd8809a7f97d7f46d39a12c198a85da5d
|
||||
NONCE: 1f2c1dbc5f52fc9c8f9ca7695515d01d15904b86f703fba3
|
||||
IN: ecaf65b66d
|
||||
AD: bd8a6f18
|
||||
CT: 8d1b2b0e38
|
||||
TAG: 27a7c7ac8bda627085414f0f31206a07
|
||||
|
||||
KEY: 4ab5e3595f39c4379a924e5f8ebcf3279075c08d18daff01d9ddfa40e03faf12
|
||||
NONCE: 94e6ddc294f5f1531924ec018823343ebcc220a88ea5ee33
|
||||
IN: c91b73abe5316c3effc6
|
||||
AD: c576f6ea
|
||||
CT: abe960fbc64b339c53b1
|
||||
TAG: 7ebae48a2ff10117069324f04619ad6f
|
||||
|
||||
KEY: a1e6146c71c2ea22300e9063455f621e15bd5bf1a3762e17f845e1aba5dd5a9c
|
||||
NONCE: 82ddb6929abff8a9ad03dfb86c0bb3e7c092d45ebfa60a1b
|
||||
IN: f011f32ccc2955158c117f53cf7b12
|
||||
AD: 5d14bc05
|
||||
CT: 44592321c665f51e9ffea052df1fea
|
||||
TAG: d556798b97f9b647729801419424affc
|
||||
|
||||
KEY: 7a1af30362c27fd55b8c24b7fca324d350decee1d1f8fae56b66253a9dd127dd
|
||||
NONCE: 61201d6247992002e24e1a893180d4f0c19a3ae4cc74bf0c
|
||||
IN: 5c7150b6a4daa362e62f82f676fdc4c4b558df64
|
||||
AD: 00c49210
|
||||
CT: 27d9e2730b6809c08efbd4b0d24639c7b67486f3
|
||||
TAG: 5889fdee25379960038778e36b2cedb2
|
||||
|
||||
KEY: 0b3fd9073e545ac44a7967263ead139c9547f7a54f06228fd3c8609fa2620784
|
||||
NONCE: 6450e1097d6f9ea76eb42e8e65972d501041c3a58baf8770
|
||||
IN: d679ae442b0351e5bff9906b099d45aab4f6aea5306a7a794f
|
||||
AD: 318d292b
|
||||
CT: a3f9ee45316d7b0f948a26145ee4fd0552bc6dc25e577e777a
|
||||
TAG: 0068a401a194b8417ec0e198baa81830
|
||||
|
||||
KEY: 047c7d378fe80c02ee48df6f679a859253aed534fdcdd87023eb3d2f93fcafe3
|
||||
NONCE: ed240b0ff6f8ac585b3ea1ab2dab8080fc2f6401b010c5d0
|
||||
IN: 7288afb4e0fa5c58602090a75c10d84b5f5f1c0e03498519afe457251aa7
|
||||
AD: e4310302
|
||||
CT: 87906b14ca3e32ab01523b31ae0bb74590ce9e1df0811e743a2c7a93415a
|
||||
TAG: 3a0abeab93792b1ffe768d316da74741
|
||||
|
||||
KEY: 1ad4e42acc5dfd07eb0a2456e9103cd0e150a36c667eb2f2b73c0d1ac1089ce3
|
||||
NONCE: 48efb52387284c5d38b4940c75f0c39a3f81f60bfebb48cb
|
||||
IN: da7edb5b3193b4484f09efa85fcf85600968ecdc537d3829a469c866ee67b0df677866
|
||||
AD: 446be8e3
|
||||
CT: b76457ca99e95b6539b12f1d6bdac55a6d5c6469b1ff274459363ec05241f7e6e5d3ce
|
||||
TAG: 06880ee508ce929da5a81f8b9de0031c
|
||||
|
||||
KEY: 702a554c1b703d4dd69ad51234293ab787a01e15bdb3ce88bf89e18c01a67164
|
||||
NONCE: ea535d9c371241b9850b8b4a596b63db79eea60bd2cd9fbb
|
||||
IN: a97156e9b39d05c00b811552d22088d7ee090a117a7f08adac574820d592021f16207720d49fb5fd
|
||||
AD: ba5790e3
|
||||
CT: 8d0b2b04479c33287096f0c6276a73f6c037edc1a2b28f8d3b2b8e6d4c5f9dc5113309dd3ecb15e6
|
||||
TAG: 3cf303305e12924d29c223976699fb73
|
||||
|
||||
KEY: 1bb7303fefa4d8d344bb9a215901b2314324bf1f3aeb9df5d1c1532c3a55ebf1
|
||||
NONCE: a304551e5f0dc98995ddfee6215a9995023a3696debfd302
|
||||
IN: 6cf6819ce3e7ed9d4f85f4a5699701dbcaf3161adc210c0b7825ddfd83d6d7c685db62f68b3801ccc8a786066d
|
||||
AD: 901c5feb
|
||||
CT: bc5ef09c111f76e54f897e6fce4aee1d25b6ed934f641ed5262d0c5eed45f610a6aea3b58b7771e34256d43a16
|
||||
TAG: b83f73f7995ba1b243dbf48ddfeb8e3a
|
||||
|
||||
KEY: 24b294f6cbac10d87158d1c6aca83b337d596132afac7633f69a3b3e58823f11
|
||||
NONCE: 805772ff619cc6fcc5ec0e9965435d6f74a2290c055ec754
|
||||
IN: 65e8581286868caabcec1a9814db00b805edc660b94ee3babc6ce19a3ca868bd322105484d59b4ce02ced4071bc16642a1f2
|
||||
AD: 7ae1c561
|
||||
CT: fe1d463b1466e8e411f0b0700f90760472ee5141f3e5afef43fd729f1623dca75cd4d00576765b335f8b2b77b00527599cb3
|
||||
TAG: 111d8540fd5ec04b9ba16ed810133026
|
||||
|
||||
KEY: 38e63e8b6402ac3f6d1641a1e3b74d2074be0fe41129975a3ff62b74ca52af05
|
||||
NONCE: 228d671b036710cbdaa72e9bf1d9ed6982b0bb3428a69fd6
|
||||
IN: 20a8d18878924d09aac32853c10e73dbd741134b7050ae6999839f2dbc727cb0052b5497c4bbd2a89e716278f15c81b871953614a49693
|
||||
AD: e9e6ac73
|
||||
CT: 80e0fe8eb26e5df229c6d939c944d440a37aa3cabf76eab5b9a420095513021ea4241ab367f6f44a20817b14631549ae6c96aa963970e1
|
||||
TAG: 1e80fbafcc7168e0494fce4cd76d692c
|
||||
|
||||
KEY: 4325dd8406fdb8431a81f1b5db3603995256de36121019724cca2190c87a6e83
|
||||
NONCE: dcbf3077b36d5d678d668fd2d0c99284c780b55c4658ea75
|
||||
IN: 4f599ad04f79be9add10fdc649b8be53e1062ea5e9c2bed22265dc6fb30d5ab4fd4425b38ff14d8e68013405bec1eff8c9ef3069902e492aac73dcd9
|
||||
AD: 6fa0d757
|
||||
CT: 7decbdc7043495c59ecc64e720436bb0708b586a46f8745f74391477f5a2520905dfcebc3765a330999013d309dfaa997bf70bab6a0b8f4f2a2a3cdf
|
||||
TAG: 051ec4ecce208d9be0cd17f434e13be3
|
||||
|
||||
KEY: 2d3d9ed4bc9eb9668733bafbb73e88be2cd17021c3a23be69b981d9f0df71df1
|
||||
NONCE: 84cae69639240c82b58895997511f145e474ebe1b008f391
|
||||
IN:
|
||||
AD: 64db597c26a4c3da
|
||||
CT:
|
||||
TAG: 2a22c4a962d46a719014ab7b0ffaf6d3
|
||||
|
||||
KEY: 09ec4e79a02db53b19b54dd2d3592afc92c74ef57d1e0f51f3726a6631b1b73f
|
||||
NONCE: 2907ced16e0777fedb1e2de30df11b3fd712af41dd714a4b
|
||||
IN: b6e50cd4ea
|
||||
AD: b5488e9b7f339b7b
|
||||
CT: 0163e75330
|
||||
TAG: e29401c6d756adcc516580ae656852aa
|
||||
|
||||
KEY: 9d5ac25a417b8a57b85332979e8a7cbad23617bb27772bbccc2acb0acae7b755
|
||||
NONCE: ff152421688dd6af7fef87817b508493a32d97a06fbda4f3
|
||||
IN: 92f4b9bc809be77e6a0d
|
||||
AD: 892b793f7a6e0727
|
||||
CT: bcc594f59de8ee8c22c6
|
||||
TAG: 1a8275816c0d32a1b6cfd41fa3889558
|
||||
|
||||
KEY: eccf80c5f744d2ecc932f95ade0d9fe9327e19795023db1846d68d04720a2401
|
||||
NONCE: abc050fad8876589633b222d6a0f2e0bf709f73610aa23ee
|
||||
IN: 45a380e438405314510c166bac6840
|
||||
AD: c32c9a1ce6852046
|
||||
CT: 9fa452dc9ca04c16ff7bde9925e246
|
||||
TAG: 3d5e826162fa78de3fc043af26044a08
|
||||
|
||||
KEY: b1912d6bc3cff47f0c3beccff85d7cd915b70ab88d0d3a8a59e994e1b0da8ac8
|
||||
NONCE: d8756090a42eea14ff25be890e66bfe4949fad498776ea20
|
||||
IN: e2f85df2ebcfa6045bd521abfe8af37fc88a0be1
|
||||
AD: 4576bb59b78032c8
|
||||
CT: 5eb6324aa48e0a4f72f5cb0a4917faf93af4209c
|
||||
TAG: 774f8077f039588495045fee07950e14
|
||||
|
||||
KEY: 85162b111c9f3163f57c2cbc311a1e9aeed9dd6136b5784bc9c0b5052f8bffbd
|
||||
NONCE: 23cdb8b546bb8a5a746b24446f0ab4199f0543d915ff51f1
|
||||
IN: dc81000077d5743beef09ac91663885d984212bbccf3dbe6f3
|
||||
AD: 3084f3e9c4d0a15f
|
||||
CT: 692d17ae0b524ec6edc0cf49b69ac90c99bed44691f7ae63b7
|
||||
TAG: efe72ff84b3bccb4d83a27ddc574bc21
|
||||
|
||||
KEY: b05ca358d8ca79f51283d83e2673bfb741c379ba271a773b8dd9c6a108e758d3
|
||||
NONCE: 9a53ad79f535c6e9da011463063c896f2ec7645e6e3548fc
|
||||
IN: 44e793742c774020e7349c996418042dc0dc30ee2bfd2654008c8929a436
|
||||
AD: 71ab5948c5e0f4c6
|
||||
CT: c5eddb7aeaa175b5f3dab68cf746f2acaf56fc62b29804629e25e2d63879
|
||||
TAG: bec3b7a8b8dad22ff3d14d26273294d2
|
||||
|
||||
KEY: abb5136a01354c765a96e832df58bec3b088bd19dc4d6bd6674f2f02007ebdaa
|
||||
NONCE: 71267ac9f4fe5caa1d52cd85948a170a778f0141d54dbffe
|
||||
IN: afb526fe41c4e2a767ce77c4145b9d054268f5f3b279237dec97f8bc46f9d158868b86
|
||||
AD: 047baa2b04748b62
|
||||
CT: 0032d4c1e65da2266539464c5d3c2b1618454a6af0e7f1e3cfc87845c75f2f4ae8b03f
|
||||
TAG: b526a95a33f17ab61f2cdfc1e2dd486a
|
||||
|
||||
KEY: bb826ed38008a0d7fb34c0c1a1a1149d2cad16b691d5129cc83f5eff2b3e5748
|
||||
NONCE: 4e02fe0915d81e9d5a62e5b3551b9db882e3873c0aaa230d
|
||||
IN: 20270d291a8d9791b0f5e35a64387bb4237bad61169841d7e1667c994ad49869c7d5580ffa752a2d
|
||||
AD: db852a275081e29b
|
||||
CT: d740012efb7e1bb986ce2c535134a45f658b92163c109bdecf1ce5b836879fe9e006a56be1fac8d7
|
||||
TAG: 21e931042e7df80695262198a06286c9
|
||||
|
||||
KEY: 938d2c59f6f3e2e7316726537932372e05e8c1b5577aae0ee870bf712ff001ab
|
||||
NONCE: fb4d71cf7eb2f70df9759a64c76a36b75203f88bf64f4edb
|
||||
IN: 8910415d674a93c54c8f5e4aa88e59648d9a0a5039a66837d58ab14f0665a5f6d9af9b839f9033d0fe8bc58f19
|
||||
AD: a3fca278a63bf944
|
||||
CT: 1905c6987a702980b7f87f1ed2d3ae073abe1401b23434f3db43b5c37c979c2068ce9a92afedcdc218003848ea
|
||||
TAG: 1bd712f64777381f68be5ccc73f364a3
|
||||
|
||||
KEY: dd0521842f498d23236692a22db0eb2f0f14fef57577e5fb194503e206b0973d
|
||||
NONCE: 519e0eee8f86c75c7a364e0905a5d10d82073e11b91083a5
|
||||
IN: 61ff13acb99c5a7fd1921ec787c8de23c1a712ff002b08cecc644a78c47341eab78e7680380c93c7d53d5e56ef050d6ff192
|
||||
AD: bb5c4e5ae8f7e461
|
||||
CT: 9bfdb0fd195fa5d37da3416b3b1e8f67bd2a456eb0317c02aabf9aac9d833a19bda299e6388e7b7119be235761477a34d49e
|
||||
TAG: 0f0c03b8423583cb8305a74f622fa1f9
|
||||
|
||||
KEY: 189bd84be3fb02723539b29cf76d41507c8b85b7217777ee1fb8f84a24aa7fee
|
||||
NONCE: ef1bf39f22ba2edf86853505c24fafdf62c1a067963c63ba
|
||||
IN: d5f96e240b5dd77b9fb2bf11c154fcbff312a791c3eb0717684e4fd84bf943e788050b47e76c427f42f3e5344b2636091603ba3b1d7a91
|
||||
AD: 93368a8e0900c7b6
|
||||
CT: c55a8b7f587bee4f97514582c5115582abffd6312914d76c2568be6836f62ba098789ed897c9a7508a5dc214bf8c218664f29941ccdfd6
|
||||
TAG: 78f87352dcb1143038c95dc6e7352cfd
|
||||
|
||||
KEY: 23a2dbfcd02d265805169fa86e6927c7d49c9a24d2707884e18955e32dafc542
|
||||
NONCE: 305c7851f46f23ea8d832d5ed09d266714fd14f82ba0f69c
|
||||
IN: 224de94a938d49cad46144e657e548bd86690a1b57b81558095eace59df1c552600dea389aaa609304fbc1eadf2241f2118c8bdf04522e1898efe1d4
|
||||
AD: 0075b20502bd29b2
|
||||
CT: 8e10c59369bbb0d72958100b05788498f59588795e075b8bce21d92d320206348b04010ced9b8cd3d651e825488915ce4a6e4f1af2f4d2f77b955376
|
||||
TAG: c39f0595ae8112dea6ef96df1c12458b
|
||||
|
||||
KEY: 264e3c3f47bdf795cdde57d9a30be5a4da8b18463c0e3e05df28b7bf4e56410b
|
||||
NONCE: 3ee09b6e205c261bf48ac53a9ba0afa460a5d5c0f2d80be8
|
||||
IN:
|
||||
AD: 8eeec09d8972cb8ab0069554
|
||||
CT:
|
||||
TAG: 245a034d84edab9fa6f0decb6b984766
|
||||
|
||||
KEY: d8ba98a272b5f91797b04b114311c3b92b7f2e3bb72edb7f78ed311b9f8ea2ad
|
||||
NONCE: 481de9a06eee76a501e3c2b9d7423d90596193ad9d8a6564
|
||||
IN: 9ee1a3134d
|
||||
AD: 928653701f6d6c8429b08c0d
|
||||
CT: 459a07898f
|
||||
TAG: 9188ec8d8e3bd91dcfda48fcc76773f7
|
||||
|
||||
KEY: ac9afd627a745df682bb003517056f07876eb94d2f8c610c61b6ac0d34ec4ec0
|
||||
NONCE: eaae7b8704530db1e8c3dcc968a00604a333c7c27ba51b16
|
||||
IN: f7c3f6ee2e9c03394dc8
|
||||
AD: 796620b367d5f041821baf69
|
||||
CT: d4a69005790cc91d8d34
|
||||
TAG: e4c83def113afcf83a1ea8cb204a0eae
|
||||
|
||||
KEY: ea1a07c1fd60a5421f1fb6c43b4318090e290c97aa3bfa037e6fc5ee00fd47d4
|
||||
NONCE: 37327805cce92b38a669affbca1de92e068727fcf6fbb09a
|
||||
IN: 7002ca765b91913ee719e7521ef5ac
|
||||
AD: 64e7c48fc3041eac0734737f
|
||||
CT: 9d8857a8c52a9ab3bf44b024b191b6
|
||||
TAG: d072c31714a7d0fe1596fd443a96e715
|
||||
|
||||
KEY: b3beb34fe0229fc8f49b354e941025bde6a788f25017a60e8a49591ed5d7e7da
|
||||
NONCE: dd0e9fec76de1f6efb022b12164f7e9248b8e8c01d14ac02
|
||||
IN: acf360d7529a42be1f132f74745a940da9e823f2
|
||||
AD: 1489ca8d852f0a8547dbe8bc
|
||||
CT: 2e8718372d6e8167213cf112dc41c80377244f5a
|
||||
TAG: e4f31e8f84b9356999dc60989009e698
|
||||
|
||||
KEY: 9357cecd10bab8d2e42ed88c0386204827c3b76e9e51150d09fd4e3b4e0e1e6f
|
||||
NONCE: 81f2106a5379e0ed861cf76b3cf95afb17515478b5cbcae9
|
||||
IN: ee51a0f25d091288b5e2b91ad11d491329e48b35a18a3a8685
|
||||
AD: b80cb677f4b409cd1537363b
|
||||
CT: f681f19fa8de1fdea3538001a46f30fa6333b76d6439337e68
|
||||
TAG: afad5e6d282d9df6d8119c32237b3e60
|
||||
|
||||
KEY: 9f868600fbf81e40398b7dfb201fcae35d34bba10908860b0b2bf8b942b4e8fa
|
||||
NONCE: 2ddcc13c97185614095d437900b8c0a9170e0a4a50e46ba5
|
||||
IN: 133fa3ac176fee6df67472752e41c6834f13300c0064ff5b190f903b7ac7
|
||||
AD: 0d61321fbee8bb1f3f5cb454
|
||||
CT: b93abb311ec0bf018dc300c7d511b42ade72780373186e231820b44f22f0
|
||||
TAG: f8bd2f649a337783ff911e37966037bd
|
||||
|
||||
KEY: 05affcdfce0a28539924370db8d80a78b835254778ec41acbff52bfab092fa33
|
||||
NONCE: 3edaeb185f7273b1a7cccba54f84c5f7d6583433b49d3694
|
||||
IN: 7657581faad266cc1037962a380c8aa5306f88000427d0a05397696b503790ad2643c6
|
||||
AD: d7c213e9e6f4a40f3e5b662c
|
||||
CT: 5eb19080aadc89f2329da4f5c41dc60568651c424c1b05d827f2bfb8dbff42c5a08224
|
||||
TAG: 2da20087b5674f0b967d1baa664bbd82
|
||||
|
||||
KEY: 645ed60ec74ddfe1f02694792db4436c262d20405d8645cd9755d64876219799
|
||||
NONCE: d83665b44c1fdf567299f2b8501e9c0e7ae2dda0bb8f2c82
|
||||
IN: ceee69d32ad4667a00909964d9611bf34fd98be41ad7f0feaaaff8169060d64cf310c13bcb9394cf
|
||||
AD: 57379f8f44191ec9cf3b1a07
|
||||
CT: 4496a0666f0f895ebce224b448a04502f2ae7b354d868b7c54295bf051162e82c530c767d1ffd2cc
|
||||
TAG: 1ffc56da4fb961ffdfabe66d82ec8f29
|
||||
|
||||
KEY: 06624c9a75bb7dbe224a3f23791281f53c40b407a14161a3f82f34924623dc02
|
||||
NONCE: e647b8b4739bf542a81d72d695e1cd6ba348fa593987ac47
|
||||
IN: 2658763f8d70e8c3303582d66ba3d736ce9d407e9507f6c6627e382d0144da157d73d0aee10ef034083cdd9013
|
||||
AD: 75536443a6c2189a57d553bb
|
||||
CT: 305cab5c2f9a6edccac307d6965febe3c86f2a1e31ac8c74e88924a10c2a29106bce980c803b7886985bba8ec5
|
||||
TAG: 8c12bb58c84175b9f601b704d0f8a25c
|
||||
|
||||
KEY: 63aeb46083100bbcc430f4f09bcc34410df9cfd5883d629e4af8645ffabb89c2
|
||||
NONCE: b09830874dc549195a5d6da93b9dcc12aa1ec8af201c96bd
|
||||
IN: 1b3c9050e0a062f5a5cff7bec8706864cf8648142ec5cb1f9867ace384e9b2bba33aab8dc83e83b2d2fac70cd5189f2b5ab5
|
||||
AD: 7dcc05b0940198bd5c68cdf1
|
||||
CT: d8b22e5d381de08a50b163c00dbbca6c07d61c80199cebd52234c7bd4f7ed0a90d47ef05617cdb8e3f782875ae629c0f0ad6
|
||||
TAG: 194077f0e6d415bf7307d171e8484a9c
|
||||
|
||||
KEY: 4826c1bf8b48088fece4008922173c500ff45790f945b1027f36110da4fecc92
|
||||
NONCE: 3a78fc7397944d762303b0a75974ac92a60e250bf112600a
|
||||
IN: d26e3a2b92120ff8056bb992660cc8a2364792589c16a518b8d232b8184aed05ba8d4fd0b2ad2b928cd873e11905a21ffece5f1e63c974
|
||||
AD: 904d2cd3e50f7bfb9352f142
|
||||
CT: 21f4cf679662fad36f57945fc0c0753c3791261eb58d643278dfe1f14bfb585c5a01370ba96f18dc3f6b6945a2c6997330b24f12f5219a
|
||||
TAG: 95397c54428f9d069c511b5c82e0151c
|
||||
|
||||
KEY: ec526c03d8a08e8a63751112428a76399c399e8b83d98c9247c73164805ac8fe
|
||||
NONCE: 2cc1a6ae89c2a091415fa2964b44a0e5da629d40d77b77f1
|
||||
IN: 567377f5b6df5442e70bc9a31bc450bd4febfcf89d7ca611353c7e612d8b7e36e859f6365ec7e5e99e9e0e882532666dd7203d06f6e25439ed871237
|
||||
AD: 35575b56716868b66cd21e24
|
||||
CT: 6b738274fe974438f1f5fca8ef1ee7df664f1e72bc54ccd3fb58c4a3df67ef9a73261df41ffe9c52aeafc8be4f6524baf9efb1558d4a57defec7bee3
|
||||
TAG: 92599d4b14a795e8c375ec2a8960b4dc
|
||||
|
||||
@@ -271,7 +271,7 @@ int EVP_tls_cbc_digest_record(const EVP_MD *md, uint8_t *md_out,
|
||||
HASH_CTX md_state;
|
||||
void (*md_final_raw)(HASH_CTX *ctx, uint8_t *md_out);
|
||||
void (*md_transform)(HASH_CTX *ctx, const uint8_t *block);
|
||||
unsigned md_size, md_block_size = 64, md_block_shift = 6;
|
||||
unsigned md_size, md_block_size = 64;
|
||||
// md_length_size is the number of bytes in the length field that terminates
|
||||
// the hash.
|
||||
unsigned md_length_size = 8;
|
||||
@@ -305,7 +305,6 @@ int EVP_tls_cbc_digest_record(const EVP_MD *md, uint8_t *md_out,
|
||||
md_transform = tls1_sha512_transform;
|
||||
md_size = SHA384_DIGEST_LENGTH;
|
||||
md_block_size = 128;
|
||||
md_block_shift = 7;
|
||||
md_length_size = 16;
|
||||
break;
|
||||
|
||||
@@ -319,7 +318,6 @@ int EVP_tls_cbc_digest_record(const EVP_MD *md, uint8_t *md_out,
|
||||
|
||||
assert(md_length_size <= MAX_HASH_BIT_COUNT_BYTES);
|
||||
assert(md_block_size <= MAX_HASH_BLOCK_SIZE);
|
||||
assert(md_block_size == (1u << md_block_shift));
|
||||
assert(md_size <= EVP_MAX_MD_SIZE);
|
||||
|
||||
static const size_t kHeaderLength = 13;
|
||||
@@ -352,16 +350,18 @@ int EVP_tls_cbc_digest_record(const EVP_MD *md, uint8_t *md_out,
|
||||
// k is the starting byte offset into the conceptual header||data where
|
||||
// we start processing.
|
||||
size_t k = 0;
|
||||
// mac_end_offset is the index just past the end of the data to be MACed.
|
||||
// mac_end_offset is the index just past the end of the data to be
|
||||
// MACed.
|
||||
size_t mac_end_offset = data_plus_mac_size + kHeaderLength - md_size;
|
||||
// c is the index of the 0x80 byte in the final hash block that contains
|
||||
// application data.
|
||||
size_t c = mac_end_offset & (md_block_size - 1);
|
||||
// index_a is the hash block number that contains the 0x80 terminating value.
|
||||
size_t index_a = mac_end_offset >> md_block_shift;
|
||||
// index_b is the hash block number that contains the 64-bit hash length, in
|
||||
// bits.
|
||||
size_t index_b = (mac_end_offset + md_length_size) >> md_block_shift;
|
||||
// c is the index of the 0x80 byte in the final hash block that
|
||||
// contains application data.
|
||||
size_t c = mac_end_offset % md_block_size;
|
||||
// index_a is the hash block number that contains the 0x80 terminating
|
||||
// value.
|
||||
size_t index_a = mac_end_offset / md_block_size;
|
||||
// index_b is the hash block number that contains the 64-bit hash
|
||||
// length, in bits.
|
||||
size_t index_b = (mac_end_offset + md_length_size) / md_block_size;
|
||||
|
||||
if (num_blocks > kVarianceBlocks) {
|
||||
num_starting_blocks = num_blocks - kVarianceBlocks;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+25
-62
@@ -124,22 +124,12 @@ void CMAC_CTX_free(CMAC_CTX *ctx) {
|
||||
OPENSSL_free(ctx);
|
||||
}
|
||||
|
||||
int CMAC_CTX_copy(CMAC_CTX *out, const CMAC_CTX *in) {
|
||||
if (!EVP_CIPHER_CTX_copy(&out->cipher_ctx, &in->cipher_ctx)) {
|
||||
return 0;
|
||||
}
|
||||
OPENSSL_memcpy(out->k1, in->k1, AES_BLOCK_SIZE);
|
||||
OPENSSL_memcpy(out->k2, in->k2, AES_BLOCK_SIZE);
|
||||
OPENSSL_memcpy(out->block, in->block, AES_BLOCK_SIZE);
|
||||
out->block_used = in->block_used;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// binary_field_mul_x_128 treats the 128 bits at |in| as an element of GF(2¹²⁸)
|
||||
// with a hard-coded reduction polynomial and sets |out| as x times the input.
|
||||
// binary_field_mul_x treats the 128 bits at |in| as an element of GF(2¹²⁸)
|
||||
// with a hard-coded reduction polynomial and sets |out| as x times the
|
||||
// input.
|
||||
//
|
||||
// See https://tools.ietf.org/html/rfc4493#section-2.3
|
||||
static void binary_field_mul_x_128(uint8_t out[16], const uint8_t in[16]) {
|
||||
static void binary_field_mul_x(uint8_t out[16], const uint8_t in[16]) {
|
||||
unsigned i;
|
||||
|
||||
// Shift |in| to left, including carry.
|
||||
@@ -152,46 +142,23 @@ static void binary_field_mul_x_128(uint8_t out[16], const uint8_t in[16]) {
|
||||
out[i] = (in[i] << 1) ^ ((0 - carry) & 0x87);
|
||||
}
|
||||
|
||||
// binary_field_mul_x_64 behaves like |binary_field_mul_x_128| but acts on an
|
||||
// element of GF(2⁶⁴).
|
||||
//
|
||||
// See https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38b.pdf
|
||||
static void binary_field_mul_x_64(uint8_t out[8], const uint8_t in[8]) {
|
||||
unsigned i;
|
||||
|
||||
// Shift |in| to left, including carry.
|
||||
for (i = 0; i < 7; i++) {
|
||||
out[i] = (in[i] << 1) | (in[i+1] >> 7);
|
||||
}
|
||||
|
||||
// If MSB set fixup with R.
|
||||
const uint8_t carry = in[0] >> 7;
|
||||
out[i] = (in[i] << 1) ^ ((0 - carry) & 0x1b);
|
||||
}
|
||||
|
||||
static const uint8_t kZeroIV[AES_BLOCK_SIZE] = {0};
|
||||
|
||||
int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t key_len,
|
||||
const EVP_CIPHER *cipher, ENGINE *engine) {
|
||||
uint8_t scratch[AES_BLOCK_SIZE];
|
||||
|
||||
size_t block_size = EVP_CIPHER_block_size(cipher);
|
||||
if ((block_size != AES_BLOCK_SIZE && block_size != 8 /* 3-DES */) ||
|
||||
if (EVP_CIPHER_block_size(cipher) != AES_BLOCK_SIZE ||
|
||||
EVP_CIPHER_key_length(cipher) != key_len ||
|
||||
!EVP_EncryptInit_ex(&ctx->cipher_ctx, cipher, NULL, key, kZeroIV) ||
|
||||
!EVP_Cipher(&ctx->cipher_ctx, scratch, kZeroIV, block_size) ||
|
||||
!EVP_Cipher(&ctx->cipher_ctx, scratch, kZeroIV, AES_BLOCK_SIZE) ||
|
||||
// Reset context again ready for first data.
|
||||
!EVP_EncryptInit_ex(&ctx->cipher_ctx, NULL, NULL, NULL, kZeroIV)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (block_size == AES_BLOCK_SIZE) {
|
||||
binary_field_mul_x_128(ctx->k1, scratch);
|
||||
binary_field_mul_x_128(ctx->k2, ctx->k1);
|
||||
} else {
|
||||
binary_field_mul_x_64(ctx->k1, scratch);
|
||||
binary_field_mul_x_64(ctx->k2, ctx->k1);
|
||||
}
|
||||
binary_field_mul_x(ctx->k1, scratch);
|
||||
binary_field_mul_x(ctx->k2, ctx->k1);
|
||||
ctx->block_used = 0;
|
||||
|
||||
return 1;
|
||||
@@ -203,12 +170,10 @@ int CMAC_Reset(CMAC_CTX *ctx) {
|
||||
}
|
||||
|
||||
int CMAC_Update(CMAC_CTX *ctx, const uint8_t *in, size_t in_len) {
|
||||
size_t block_size = EVP_CIPHER_CTX_block_size(&ctx->cipher_ctx);
|
||||
assert(block_size <= AES_BLOCK_SIZE);
|
||||
uint8_t scratch[AES_BLOCK_SIZE];
|
||||
|
||||
if (ctx->block_used > 0) {
|
||||
size_t todo = block_size - ctx->block_used;
|
||||
size_t todo = AES_BLOCK_SIZE - ctx->block_used;
|
||||
if (in_len < todo) {
|
||||
todo = in_len;
|
||||
}
|
||||
@@ -219,28 +184,28 @@ int CMAC_Update(CMAC_CTX *ctx, const uint8_t *in, size_t in_len) {
|
||||
ctx->block_used += todo;
|
||||
|
||||
// If |in_len| is zero then either |ctx->block_used| is less than
|
||||
// |block_size|, in which case we can stop here, or |ctx->block_used| is
|
||||
// exactly |block_size| but there's no more data to process. In the latter
|
||||
// case we don't want to process this block now because it might be the last
|
||||
// block and that block is treated specially.
|
||||
// |AES_BLOCK_SIZE|, in which case we can stop here, or |ctx->block_used|
|
||||
// is exactly |AES_BLOCK_SIZE| but there's no more data to process. In the
|
||||
// latter case we don't want to process this block now because it might be
|
||||
// the last block and that block is treated specially.
|
||||
if (in_len == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
assert(ctx->block_used == block_size);
|
||||
assert(ctx->block_used == AES_BLOCK_SIZE);
|
||||
|
||||
if (!EVP_Cipher(&ctx->cipher_ctx, scratch, ctx->block, block_size)) {
|
||||
if (!EVP_Cipher(&ctx->cipher_ctx, scratch, ctx->block, AES_BLOCK_SIZE)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Encrypt all but one of the remaining blocks.
|
||||
while (in_len > block_size) {
|
||||
if (!EVP_Cipher(&ctx->cipher_ctx, scratch, in, block_size)) {
|
||||
while (in_len > AES_BLOCK_SIZE) {
|
||||
if (!EVP_Cipher(&ctx->cipher_ctx, scratch, in, AES_BLOCK_SIZE)) {
|
||||
return 0;
|
||||
}
|
||||
in += block_size;
|
||||
in_len -= block_size;
|
||||
in += AES_BLOCK_SIZE;
|
||||
in_len -= AES_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
OPENSSL_memcpy(ctx->block, in, in_len);
|
||||
@@ -250,29 +215,27 @@ int CMAC_Update(CMAC_CTX *ctx, const uint8_t *in, size_t in_len) {
|
||||
}
|
||||
|
||||
int CMAC_Final(CMAC_CTX *ctx, uint8_t *out, size_t *out_len) {
|
||||
size_t block_size = EVP_CIPHER_CTX_block_size(&ctx->cipher_ctx);
|
||||
assert(block_size <= AES_BLOCK_SIZE);
|
||||
|
||||
*out_len = block_size;
|
||||
*out_len = AES_BLOCK_SIZE;
|
||||
if (out == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const uint8_t *mask = ctx->k1;
|
||||
|
||||
if (ctx->block_used != block_size) {
|
||||
if (ctx->block_used != AES_BLOCK_SIZE) {
|
||||
// If the last block is incomplete, terminate it with a single 'one' bit
|
||||
// followed by zeros.
|
||||
ctx->block[ctx->block_used] = 0x80;
|
||||
OPENSSL_memset(ctx->block + ctx->block_used + 1, 0,
|
||||
block_size - (ctx->block_used + 1));
|
||||
AES_BLOCK_SIZE - (ctx->block_used + 1));
|
||||
|
||||
mask = ctx->k2;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < block_size; i++) {
|
||||
unsigned i;
|
||||
for (i = 0; i < AES_BLOCK_SIZE; i++) {
|
||||
out[i] = ctx->block[i] ^ mask[i];
|
||||
}
|
||||
|
||||
return EVP_Cipher(&ctx->cipher_ctx, out, out, block_size);
|
||||
return EVP_Cipher(&ctx->cipher_ctx, out, out, AES_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
@@ -23,9 +22,7 @@
|
||||
#include <openssl/cmac.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "../test/file_test.h"
|
||||
#include "../test/test_util.h"
|
||||
#include "../test/wycheproof_util.h"
|
||||
|
||||
|
||||
static void test(const char *name, const uint8_t *key, size_t key_len,
|
||||
@@ -57,18 +54,6 @@ static void test(const char *name, const uint8_t *key, size_t key_len,
|
||||
ASSERT_TRUE(CMAC_Final(ctx.get(), out, &out_len));
|
||||
EXPECT_EQ(Bytes(expected, sizeof(out)), Bytes(out, out_len));
|
||||
}
|
||||
|
||||
// Test that |CMAC_CTX_copy| works.
|
||||
ASSERT_TRUE(CMAC_Reset(ctx.get()));
|
||||
size_t chunk = msg_len / 2;
|
||||
ASSERT_TRUE(CMAC_Update(ctx.get(), msg, chunk));
|
||||
bssl::UniquePtr<CMAC_CTX> ctx2(CMAC_CTX_new());
|
||||
ASSERT_TRUE(ctx2);
|
||||
ASSERT_TRUE(CMAC_CTX_copy(ctx2.get(), ctx.get()));
|
||||
ASSERT_TRUE(CMAC_Update(ctx2.get(), msg + chunk, msg_len - chunk));
|
||||
size_t out_len;
|
||||
ASSERT_TRUE(CMAC_Final(ctx2.get(), out, &out_len));
|
||||
EXPECT_EQ(Bytes(expected, sizeof(out)), Bytes(out, out_len));
|
||||
}
|
||||
|
||||
TEST(CMACTest, RFC4493TestVectors) {
|
||||
@@ -119,149 +104,3 @@ TEST(CMACTest, RFC4493TestVectors) {
|
||||
test("RFC 4493 #3", kKey, sizeof(kKey), kMsg3, sizeof(kMsg3), kOut3);
|
||||
test("RFC 4493 #4", kKey, sizeof(kKey), kMsg4, sizeof(kMsg4), kOut4);
|
||||
}
|
||||
|
||||
TEST(CMACTest, Wycheproof) {
|
||||
FileTestGTest("third_party/wycheproof_testvectors/aes_cmac_test.txt",
|
||||
[](FileTest *t) {
|
||||
std::string key_size, tag_size;
|
||||
ASSERT_TRUE(t->GetInstruction(&key_size, "keySize"));
|
||||
ASSERT_TRUE(t->GetInstruction(&tag_size, "tagSize"));
|
||||
WycheproofResult result;
|
||||
ASSERT_TRUE(GetWycheproofResult(t, &result));
|
||||
std::vector<uint8_t> key, msg, tag;
|
||||
ASSERT_TRUE(t->GetBytes(&key, "key"));
|
||||
ASSERT_TRUE(t->GetBytes(&msg, "msg"));
|
||||
ASSERT_TRUE(t->GetBytes(&tag, "tag"));
|
||||
|
||||
const EVP_CIPHER *cipher;
|
||||
switch (atoi(key_size.c_str())) {
|
||||
case 128:
|
||||
cipher = EVP_aes_128_cbc();
|
||||
break;
|
||||
case 192:
|
||||
cipher = EVP_aes_192_cbc();
|
||||
break;
|
||||
case 256:
|
||||
cipher = EVP_aes_256_cbc();
|
||||
break;
|
||||
default:
|
||||
// Some test vectors intentionally give the wrong key size. Our API
|
||||
// requires the caller pick the sized CBC primitive, so these tests
|
||||
// aren't useful for us.
|
||||
EXPECT_EQ(WycheproofResult::kInvalid, result);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t tag_len = static_cast<size_t>(atoi(tag_size.c_str())) / 8;
|
||||
|
||||
uint8_t out[16];
|
||||
bssl::UniquePtr<CMAC_CTX> ctx(CMAC_CTX_new());
|
||||
ASSERT_TRUE(ctx);
|
||||
ASSERT_TRUE(CMAC_Init(ctx.get(), key.data(), key.size(), cipher, NULL));
|
||||
ASSERT_TRUE(CMAC_Update(ctx.get(), msg.data(), msg.size()));
|
||||
size_t out_len;
|
||||
ASSERT_TRUE(CMAC_Final(ctx.get(), out, &out_len));
|
||||
// Truncate the tag, if requested.
|
||||
out_len = std::min(out_len, tag_len);
|
||||
|
||||
if (result == WycheproofResult::kValid) {
|
||||
EXPECT_EQ(Bytes(tag), Bytes(out, out_len));
|
||||
|
||||
// Test the streaming API as well.
|
||||
ASSERT_TRUE(CMAC_Reset(ctx.get()));
|
||||
for (uint8_t b : msg) {
|
||||
ASSERT_TRUE(CMAC_Update(ctx.get(), &b, 1));
|
||||
}
|
||||
ASSERT_TRUE(CMAC_Final(ctx.get(), out, &out_len));
|
||||
out_len = std::min(out_len, tag_len);
|
||||
EXPECT_EQ(Bytes(tag), Bytes(out, out_len));
|
||||
} else {
|
||||
// Wycheproof's invalid tests assume the implementation internally does
|
||||
// the comparison, whereas our API only computes the tag. Check that
|
||||
// they're not equal, but these tests are mostly not useful for us.
|
||||
EXPECT_NE(Bytes(tag), Bytes(out, out_len));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void RunCAVPTest(const char *path, const EVP_CIPHER *cipher,
|
||||
bool is_3des) {
|
||||
FileTestGTest(path, [&](FileTest *t) {
|
||||
t->IgnoreAttribute("Count");
|
||||
t->IgnoreAttribute("Klen");
|
||||
std::string t_len, m_len, result;
|
||||
ASSERT_TRUE(t->GetAttribute(&t_len, "Tlen"));
|
||||
ASSERT_TRUE(t->GetAttribute(&m_len, "Mlen"));
|
||||
ASSERT_TRUE(t->GetAttribute(&result, "Result"));
|
||||
std::vector<uint8_t> key, msg, mac;
|
||||
if (is_3des) {
|
||||
std::vector<uint8_t> key2, key3;
|
||||
ASSERT_TRUE(t->GetBytes(&key, "Key1"));
|
||||
ASSERT_TRUE(t->GetBytes(&key2, "Key2"));
|
||||
ASSERT_TRUE(t->GetBytes(&key3, "Key3"));
|
||||
key.insert(key.end(), key2.begin(), key2.end());
|
||||
key.insert(key.end(), key3.begin(), key3.end());
|
||||
} else {
|
||||
ASSERT_TRUE(t->GetBytes(&key, "Key"));
|
||||
}
|
||||
ASSERT_TRUE(t->GetBytes(&msg, "Msg"));
|
||||
ASSERT_TRUE(t->GetBytes(&mac, "Mac"));
|
||||
|
||||
// CAVP's uses a non-empty Msg attribute and zero Mlen for the empty string.
|
||||
if (atoi(m_len.c_str()) == 0) {
|
||||
msg.clear();
|
||||
} else {
|
||||
EXPECT_EQ(static_cast<size_t>(atoi(m_len.c_str())), msg.size());
|
||||
}
|
||||
|
||||
size_t tag_len = static_cast<size_t>(atoi(t_len.c_str()));
|
||||
|
||||
uint8_t out[16];
|
||||
bssl::UniquePtr<CMAC_CTX> ctx(CMAC_CTX_new());
|
||||
ASSERT_TRUE(ctx);
|
||||
ASSERT_TRUE(CMAC_Init(ctx.get(), key.data(), key.size(), cipher, NULL));
|
||||
ASSERT_TRUE(CMAC_Update(ctx.get(), msg.data(), msg.size()));
|
||||
size_t out_len;
|
||||
ASSERT_TRUE(CMAC_Final(ctx.get(), out, &out_len));
|
||||
// Truncate the tag, if requested.
|
||||
out_len = std::min(out_len, tag_len);
|
||||
|
||||
ASSERT_FALSE(result.empty());
|
||||
if (result[0] == 'P') {
|
||||
EXPECT_EQ(Bytes(mac), Bytes(out, out_len));
|
||||
|
||||
// Test the streaming API as well.
|
||||
ASSERT_TRUE(CMAC_Reset(ctx.get()));
|
||||
for (uint8_t b : msg) {
|
||||
ASSERT_TRUE(CMAC_Update(ctx.get(), &b, 1));
|
||||
}
|
||||
ASSERT_TRUE(CMAC_Final(ctx.get(), out, &out_len));
|
||||
out_len = std::min(out_len, tag_len);
|
||||
EXPECT_EQ(Bytes(mac), Bytes(out, out_len));
|
||||
} else {
|
||||
// CAVP's invalid tests assume the implementation internally does the
|
||||
// comparison, whereas our API only computes the tag. Check that they're
|
||||
// not equal, but these tests are mostly not useful for us.
|
||||
EXPECT_NE(Bytes(mac), Bytes(out, out_len));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
TEST(CMACTest, CAVPAES128) {
|
||||
RunCAVPTest("crypto/cmac/cavp_aes128_cmac_tests.txt", EVP_aes_128_cbc(),
|
||||
false);
|
||||
}
|
||||
|
||||
TEST(CMACTest, CAVPAES192) {
|
||||
RunCAVPTest("crypto/cmac/cavp_aes192_cmac_tests.txt", EVP_aes_192_cbc(),
|
||||
false);
|
||||
}
|
||||
|
||||
TEST(CMACTest, CAVPAES256) {
|
||||
RunCAVPTest("crypto/cmac/cavp_aes256_cmac_tests.txt", EVP_aes_256_cbc(),
|
||||
false);
|
||||
}
|
||||
|
||||
TEST(CMACTest, CAVP3DES) {
|
||||
RunCAVPTest("crypto/cmac/cavp_3des_cmac_tests.txt", EVP_des_ede3_cbc(), true);
|
||||
}
|
||||
|
||||
+2
-2
@@ -791,13 +791,13 @@ int CONF_parse_list(const char *list, char sep, int remove_whitespace,
|
||||
}
|
||||
}
|
||||
|
||||
int CONF_modules_load_file(const char *filename, const char *appname,
|
||||
int CONF_modules_load_file(CONF_MUST_BE_NULL *filename, const char *appname,
|
||||
unsigned long flags) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CONF_modules_free(void) {}
|
||||
|
||||
void OPENSSL_config(const char *config_name) {}
|
||||
void OPENSSL_config(CONF_MUST_BE_NULL *config_name) {}
|
||||
|
||||
void OPENSSL_no_config(void) {}
|
||||
|
||||
@@ -53,9 +53,6 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
|
||||
static uint8_t FromBool8(bool b) {
|
||||
return b ? CONSTTIME_TRUE_8 : CONSTTIME_FALSE_8;
|
||||
@@ -137,19 +134,3 @@ TEST(ConstantTimeTest, Test) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ConstantTimeTest, MemCmp) {
|
||||
uint8_t buf[256], copy[256];
|
||||
RAND_bytes(buf, sizeof(buf));
|
||||
|
||||
OPENSSL_memcpy(copy, buf, sizeof(buf));
|
||||
EXPECT_EQ(0, CRYPTO_memcmp(buf, copy, sizeof(buf)));
|
||||
|
||||
for (size_t i = 0; i < sizeof(buf); i++) {
|
||||
for (uint8_t bit = 1; bit != 0; bit <<= 1) {
|
||||
OPENSSL_memcpy(copy, buf, sizeof(buf));
|
||||
copy[i] ^= bit;
|
||||
EXPECT_NE(0, CRYPTO_memcmp(buf, copy, sizeof(buf)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
/* Copyright (c) 2018, Google Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
#include <openssl/cpu.h>
|
||||
|
||||
#if defined(OPENSSL_AARCH64) && defined(OPENSSL_FUCHSIA) && \
|
||||
!defined(OPENSSL_STATIC_ARMCAP)
|
||||
|
||||
#include <zircon/features.h>
|
||||
#include <zircon/syscalls.h>
|
||||
#include <zircon/types.h>
|
||||
|
||||
#include <openssl/arm_arch.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
extern uint32_t OPENSSL_armcap_P;
|
||||
|
||||
void OPENSSL_cpuid_setup(void) {
|
||||
uint32_t hwcap;
|
||||
zx_status_t rc = zx_system_get_features(ZX_FEATURE_KIND_CPU, &hwcap);
|
||||
if (rc != ZX_OK || (hwcap & ZX_ARM64_FEATURE_ISA_ASIMD) == 0) {
|
||||
// Matching OpenSSL, if NEON/ASIMD is missing, don't report other features
|
||||
// either.
|
||||
return;
|
||||
}
|
||||
|
||||
OPENSSL_armcap_P |= ARMV7_NEON;
|
||||
|
||||
if (hwcap & ZX_ARM64_FEATURE_ISA_AES) {
|
||||
OPENSSL_armcap_P |= ARMV8_AES;
|
||||
}
|
||||
if (hwcap & ZX_ARM64_FEATURE_ISA_PMULL) {
|
||||
OPENSSL_armcap_P |= ARMV8_PMULL;
|
||||
}
|
||||
if (hwcap & ZX_ARM64_FEATURE_ISA_SHA1) {
|
||||
OPENSSL_armcap_P |= ARMV8_SHA1;
|
||||
}
|
||||
if (hwcap & ZX_ARM64_FEATURE_ISA_SHA2) {
|
||||
OPENSSL_armcap_P |= ARMV8_SHA256;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // OPENSSL_AARCH64 && !OPENSSL_STATIC_ARMCAP
|
||||
@@ -14,8 +14,7 @@
|
||||
|
||||
#include <openssl/cpu.h>
|
||||
|
||||
#if defined(OPENSSL_AARCH64) && defined(OPENSSL_LINUX) && \
|
||||
!defined(OPENSSL_STATIC_ARMCAP)
|
||||
#if defined(OPENSSL_AARCH64) && !defined(OPENSSL_STATIC_ARMCAP)
|
||||
|
||||
#include <sys/auxv.h>
|
||||
|
||||
|
||||
+22
-23
@@ -164,17 +164,16 @@ void OPENSSL_cpuid_setup(void) {
|
||||
uint32_t num_extended_ids = eax;
|
||||
if (num_extended_ids >= 0x80000001) {
|
||||
OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 0x80000001);
|
||||
if (ecx & (1u << 11)) {
|
||||
if (ecx & (1 << 11)) {
|
||||
has_amd_xop = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t extended_features[2] = {0};
|
||||
uint32_t extended_features = 0;
|
||||
if (num_ids >= 7) {
|
||||
OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 7);
|
||||
extended_features[0] = ebx;
|
||||
extended_features[1] = ecx;
|
||||
extended_features = ebx;
|
||||
}
|
||||
|
||||
// Determine the number of cores sharing an L1 data cache to adjust the
|
||||
@@ -194,74 +193,74 @@ void OPENSSL_cpuid_setup(void) {
|
||||
OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 1);
|
||||
|
||||
// Adjust the hyper-threading bit.
|
||||
if (edx & (1u << 28)) {
|
||||
if (edx & (1 << 28)) {
|
||||
uint32_t num_logical_cores = (ebx >> 16) & 0xff;
|
||||
if (cores_per_cache == 1 || num_logical_cores <= 1) {
|
||||
edx &= ~(1u << 28);
|
||||
edx &= ~(1 << 28);
|
||||
}
|
||||
}
|
||||
|
||||
// Reserved bit #20 was historically repurposed to control the in-memory
|
||||
// representation of RC4 state. Always set it to zero.
|
||||
edx &= ~(1u << 20);
|
||||
edx &= ~(1 << 20);
|
||||
|
||||
// Reserved bit #30 is repurposed to signal an Intel CPU.
|
||||
if (is_intel) {
|
||||
edx |= (1u << 30);
|
||||
edx |= (1 << 30);
|
||||
|
||||
// Clear the XSAVE bit on Knights Landing to mimic Silvermont. This enables
|
||||
// some Silvermont-specific codepaths which perform better. See OpenSSL
|
||||
// commit 64d92d74985ebb3d0be58a9718f9e080a14a8e7f.
|
||||
if ((eax & 0x0fff0ff0) == 0x00050670 /* Knights Landing */ ||
|
||||
(eax & 0x0fff0ff0) == 0x00080650 /* Knights Mill (per SDE) */) {
|
||||
ecx &= ~(1u << 26);
|
||||
ecx &= ~(1 << 26);
|
||||
}
|
||||
} else {
|
||||
edx &= ~(1u << 30);
|
||||
edx &= ~(1 << 30);
|
||||
}
|
||||
|
||||
// The SDBG bit is repurposed to denote AMD XOP support.
|
||||
if (has_amd_xop) {
|
||||
ecx |= (1u << 11);
|
||||
ecx |= (1 << 11);
|
||||
} else {
|
||||
ecx &= ~(1u << 11);
|
||||
ecx &= ~(1 << 11);
|
||||
}
|
||||
|
||||
uint64_t xcr0 = 0;
|
||||
if (ecx & (1u << 27)) {
|
||||
if (ecx & (1 << 27)) {
|
||||
// XCR0 may only be queried if the OSXSAVE bit is set.
|
||||
xcr0 = OPENSSL_xgetbv(0);
|
||||
}
|
||||
// See Intel manual, volume 1, section 14.3.
|
||||
if ((xcr0 & 6) != 6) {
|
||||
// YMM registers cannot be used.
|
||||
ecx &= ~(1u << 28); // AVX
|
||||
ecx &= ~(1u << 12); // FMA
|
||||
ecx &= ~(1u << 11); // AMD XOP
|
||||
ecx &= ~(1 << 28); // AVX
|
||||
ecx &= ~(1 << 12); // FMA
|
||||
ecx &= ~(1 << 11); // AMD XOP
|
||||
// Clear AVX2 and AVX512* bits.
|
||||
//
|
||||
// TODO(davidben): Should bits 17 and 26-28 also be cleared? Upstream
|
||||
// doesn't clear those.
|
||||
extended_features[0] &=
|
||||
~((1u << 5) | (1u << 16) | (1u << 21) | (1u << 30) | (1u << 31));
|
||||
extended_features &=
|
||||
~((1 << 5) | (1 << 16) | (1 << 21) | (1 << 30) | (1 << 31));
|
||||
}
|
||||
// See Intel manual, volume 1, section 15.2.
|
||||
if ((xcr0 & 0xe6) != 0xe6) {
|
||||
// Clear AVX512F. Note we don't touch other AVX512 extensions because they
|
||||
// can be used with YMM.
|
||||
extended_features[0] &= ~(1u << 16);
|
||||
extended_features &= ~(1 << 16);
|
||||
}
|
||||
|
||||
// Disable ADX instructions on Knights Landing. See OpenSSL commit
|
||||
// 64d92d74985ebb3d0be58a9718f9e080a14a8e7f.
|
||||
if ((ecx & (1u << 26)) == 0) {
|
||||
extended_features[0] &= ~(1u << 19);
|
||||
if ((ecx & (1 << 26)) == 0) {
|
||||
extended_features &= ~(1 << 19);
|
||||
}
|
||||
|
||||
OPENSSL_ia32cap_P[0] = edx;
|
||||
OPENSSL_ia32cap_P[1] = ecx;
|
||||
OPENSSL_ia32cap_P[2] = extended_features[0];
|
||||
OPENSSL_ia32cap_P[3] = extended_features[1];
|
||||
OPENSSL_ia32cap_P[2] = extended_features;
|
||||
OPENSSL_ia32cap_P[3] = 0;
|
||||
|
||||
const char *env1, *env2;
|
||||
env1 = getenv("OPENSSL_ia32cap");
|
||||
|
||||
+21
-53
@@ -19,19 +19,6 @@
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
#if defined(OPENSSL_MSAN) && !defined(OPENSSL_NO_ASM)
|
||||
// MSan works by instrumenting memory accesses in the compiler. Accesses from
|
||||
// uninstrumented code, such as assembly, are invisible to it. MSan will
|
||||
// incorrectly report reads from assembly-initialized memory as uninitialized.
|
||||
// If building BoringSSL with MSan, exclude assembly files from the build and
|
||||
// define OPENSSL_NO_ASM.
|
||||
//
|
||||
// This is checked here rather than in a header because the consumer might not
|
||||
// define OPENSSL_NO_ASM. It is only necessary for BoringSSL source files to be
|
||||
// built with it.
|
||||
#error "BoringSSL must be built with assembly disabled to use MSan."
|
||||
#endif
|
||||
|
||||
#if !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_STATIC_ARMCAP) && \
|
||||
(defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \
|
||||
defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) || \
|
||||
@@ -53,18 +40,6 @@
|
||||
OPENSSL_ARM || OPENSSL_AARCH64) */
|
||||
|
||||
|
||||
// Our assembly does not use the GOT to reference symbols, which means
|
||||
// references to visible symbols will often require a TEXTREL. This is
|
||||
// undesirable, so all assembly-referenced symbols should be hidden. CPU
|
||||
// capabilities are the only such symbols defined in C. Explicitly hide them,
|
||||
// rather than rely on being built with -fvisibility=hidden.
|
||||
#if defined(OPENSSL_WINDOWS)
|
||||
#define HIDDEN
|
||||
#else
|
||||
#define HIDDEN __attribute__((visibility("hidden")))
|
||||
#endif
|
||||
|
||||
|
||||
// The capability variables are defined in this file in order to work around a
|
||||
// linker bug. When linking with a .a, if no symbols in a .o are referenced
|
||||
// then the .o is discarded, even if it has constructor functions.
|
||||
@@ -82,11 +57,11 @@
|
||||
// archive, linking on OS X will fail to resolve common symbols. By
|
||||
// initialising it to zero, it becomes a "data symbol", which isn't so
|
||||
// affected.
|
||||
HIDDEN uint32_t OPENSSL_ia32cap_P[4] = {0};
|
||||
uint32_t OPENSSL_ia32cap_P[4] = {0};
|
||||
|
||||
#elif defined(OPENSSL_PPC64LE)
|
||||
|
||||
HIDDEN unsigned long OPENSSL_ppc64le_hwcap2 = 0;
|
||||
unsigned long OPENSSL_ppc64le_hwcap2 = 0;
|
||||
|
||||
#elif defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)
|
||||
|
||||
@@ -94,7 +69,7 @@ HIDDEN unsigned long OPENSSL_ppc64le_hwcap2 = 0;
|
||||
|
||||
#if defined(OPENSSL_STATIC_ARMCAP)
|
||||
|
||||
HIDDEN uint32_t OPENSSL_armcap_P =
|
||||
uint32_t OPENSSL_armcap_P =
|
||||
#if defined(OPENSSL_STATIC_ARMCAP_NEON) || defined(__ARM_NEON__)
|
||||
ARMV7_NEON |
|
||||
#endif
|
||||
@@ -113,7 +88,7 @@ HIDDEN uint32_t OPENSSL_armcap_P =
|
||||
0;
|
||||
|
||||
#else
|
||||
HIDDEN uint32_t OPENSSL_armcap_P = 0;
|
||||
uint32_t OPENSSL_armcap_P = 0;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -177,36 +152,31 @@ int CRYPTO_has_asm(void) {
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *SSLeay_version(int which) { return OpenSSL_version(which); }
|
||||
|
||||
const char *OpenSSL_version(int which) {
|
||||
switch (which) {
|
||||
case OPENSSL_VERSION:
|
||||
return "BoringSSL";
|
||||
case OPENSSL_CFLAGS:
|
||||
return "compiler: n/a";
|
||||
case OPENSSL_BUILT_ON:
|
||||
return "built on: n/a";
|
||||
case OPENSSL_PLATFORM:
|
||||
return "platform: n/a";
|
||||
case OPENSSL_DIR:
|
||||
return "OPENSSLDIR: n/a";
|
||||
default:
|
||||
return "not available";
|
||||
}
|
||||
const char *SSLeay_version(int unused) {
|
||||
return "BoringSSL";
|
||||
}
|
||||
|
||||
unsigned long SSLeay(void) { return OPENSSL_VERSION_NUMBER; }
|
||||
const char *OpenSSL_version(int unused) {
|
||||
return "BoringSSL";
|
||||
}
|
||||
|
||||
unsigned long OpenSSL_version_num(void) { return OPENSSL_VERSION_NUMBER; }
|
||||
unsigned long SSLeay(void) {
|
||||
return OPENSSL_VERSION_NUMBER;
|
||||
}
|
||||
|
||||
int CRYPTO_malloc_init(void) { return 1; }
|
||||
unsigned long OpenSSL_version_num(void) {
|
||||
return OPENSSL_VERSION_NUMBER;
|
||||
}
|
||||
|
||||
int OPENSSL_malloc_init(void) { return 1; }
|
||||
int CRYPTO_malloc_init(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ENGINE_load_builtin_engines(void) {}
|
||||
|
||||
int ENGINE_register_all_complete(void) { return 1; }
|
||||
int ENGINE_register_all_complete(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void OPENSSL_load_builtin_modules(void) {}
|
||||
|
||||
@@ -214,5 +184,3 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings) {
|
||||
CRYPTO_library_init();
|
||||
return 1;
|
||||
}
|
||||
|
||||
void OPENSSL_cleanup(void) {}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
include_directories(../../include)
|
||||
|
||||
if(${ARCH} STREQUAL "arm")
|
||||
if (${ARCH} STREQUAL "arm")
|
||||
set(
|
||||
CURVE25519_ARCH_SOURCES
|
||||
|
||||
@@ -8,12 +8,22 @@ if(${ARCH} STREQUAL "arm")
|
||||
)
|
||||
endif()
|
||||
|
||||
if (${ARCH} STREQUAL "x86_64")
|
||||
set(
|
||||
CURVE25519_ARCH_SOURCES
|
||||
|
||||
asm/x25519-asm-x86_64.S
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(
|
||||
curve25519
|
||||
|
||||
OBJECT
|
||||
|
||||
curve25519.c
|
||||
spake25519.c
|
||||
x25519-x86_64.c
|
||||
|
||||
${CURVE25519_ARCH_SOURCES}
|
||||
)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -44,28 +44,6 @@ TEST(Ed25519Test, TestVectors) {
|
||||
});
|
||||
}
|
||||
|
||||
TEST(Ed25519Test, Malleability) {
|
||||
// https://tools.ietf.org/html/rfc8032#section-5.1.7 adds an additional test
|
||||
// that s be in [0, order). This prevents someone from adding a multiple of
|
||||
// order to s and obtaining a second valid signature for the same message.
|
||||
static const uint8_t kMsg[] = {0x54, 0x65, 0x73, 0x74};
|
||||
static const uint8_t kSig[] = {
|
||||
0x7c, 0x38, 0xe0, 0x26, 0xf2, 0x9e, 0x14, 0xaa, 0xbd, 0x05, 0x9a,
|
||||
0x0f, 0x2d, 0xb8, 0xb0, 0xcd, 0x78, 0x30, 0x40, 0x60, 0x9a, 0x8b,
|
||||
0xe6, 0x84, 0xdb, 0x12, 0xf8, 0x2a, 0x27, 0x77, 0x4a, 0xb0, 0x67,
|
||||
0x65, 0x4b, 0xce, 0x38, 0x32, 0xc2, 0xd7, 0x6f, 0x8f, 0x6f, 0x5d,
|
||||
0xaf, 0xc0, 0x8d, 0x93, 0x39, 0xd4, 0xee, 0xf6, 0x76, 0x57, 0x33,
|
||||
0x36, 0xa5, 0xc5, 0x1e, 0xb6, 0xf9, 0x46, 0xb3, 0x1d,
|
||||
};
|
||||
static const uint8_t kPub[] = {
|
||||
0x7d, 0x4d, 0x0e, 0x7f, 0x61, 0x53, 0xa6, 0x9b, 0x62, 0x42, 0xb5,
|
||||
0x22, 0xab, 0xbe, 0xe6, 0x85, 0xfd, 0xa4, 0x42, 0x0f, 0x88, 0x34,
|
||||
0xb1, 0x08, 0xc3, 0xbd, 0xae, 0x36, 0x9e, 0xf5, 0x49, 0xfa,
|
||||
};
|
||||
|
||||
EXPECT_FALSE(ED25519_verify(kMsg, sizeof(kMsg), kSig, kPub));
|
||||
}
|
||||
|
||||
TEST(Ed25519Test, KeypairFromSeed) {
|
||||
uint8_t public_key1[32], private_key1[64];
|
||||
ED25519_keypair(public_key1, private_key1);
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/* Copyright (c) 2015, Google Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
#ifndef OPENSSL_HEADER_CURVE25519_INTERNAL_H
|
||||
#define OPENSSL_HEADER_CURVE25519_INTERNAL_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(OPENSSL_X86_64) && !defined(OPENSSL_SMALL) && \
|
||||
!defined(OPENSSL_WINDOWS) && !defined(OPENSSL_NO_ASM)
|
||||
#define BORINGSSL_X25519_X86_64
|
||||
|
||||
void x25519_x86_64(uint8_t out[32], const uint8_t scalar[32],
|
||||
const uint8_t point[32]);
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_APPLE)
|
||||
#define BORINGSSL_X25519_NEON
|
||||
|
||||
// x25519_NEON is defined in asm/x25519-arm.S.
|
||||
void x25519_NEON(uint8_t out[32], const uint8_t scalar[32],
|
||||
const uint8_t point[32]);
|
||||
#endif
|
||||
|
||||
// fe means field element. Here the field is \Z/(2^255-19). An element t,
|
||||
// entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
|
||||
// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on
|
||||
// context.
|
||||
typedef int32_t fe[10];
|
||||
|
||||
/* ge means group element.
|
||||
|
||||
* Here the group is the set of pairs (x,y) of field elements (see fe.h)
|
||||
* satisfying -x^2 + y^2 = 1 + d x^2y^2
|
||||
* where d = -121665/121666.
|
||||
*
|
||||
* Representations:
|
||||
* ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
|
||||
* ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
|
||||
* ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
|
||||
* ge_precomp (Duif): (y+x,y-x,2dxy) */
|
||||
|
||||
typedef struct {
|
||||
fe X;
|
||||
fe Y;
|
||||
fe Z;
|
||||
} ge_p2;
|
||||
|
||||
typedef struct {
|
||||
fe X;
|
||||
fe Y;
|
||||
fe Z;
|
||||
fe T;
|
||||
} ge_p3;
|
||||
|
||||
typedef struct {
|
||||
fe X;
|
||||
fe Y;
|
||||
fe Z;
|
||||
fe T;
|
||||
} ge_p1p1;
|
||||
|
||||
typedef struct {
|
||||
fe yplusx;
|
||||
fe yminusx;
|
||||
fe xy2d;
|
||||
} ge_precomp;
|
||||
|
||||
typedef struct {
|
||||
fe YplusX;
|
||||
fe YminusX;
|
||||
fe Z;
|
||||
fe T2d;
|
||||
} ge_cached;
|
||||
|
||||
void x25519_ge_tobytes(uint8_t *s, const ge_p2 *h);
|
||||
int x25519_ge_frombytes_vartime(ge_p3 *h, const uint8_t *s);
|
||||
void x25519_ge_p3_to_cached(ge_cached *r, const ge_p3 *p);
|
||||
void x25519_ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p);
|
||||
void x25519_ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p);
|
||||
void x25519_ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q);
|
||||
void x25519_ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q);
|
||||
void x25519_ge_scalarmult_small_precomp(
|
||||
ge_p3 *h, const uint8_t a[32], const uint8_t precomp_table[15 * 2 * 32]);
|
||||
void x25519_ge_scalarmult_base(ge_p3 *h, const uint8_t a[32]);
|
||||
void x25519_ge_scalarmult(ge_p2 *r, const uint8_t *scalar, const ge_p3 *A);
|
||||
void x25519_sc_reduce(uint8_t *s);
|
||||
|
||||
enum spake2_state_t {
|
||||
spake2_state_init = 0,
|
||||
spake2_state_msg_generated,
|
||||
spake2_state_key_generated,
|
||||
};
|
||||
|
||||
struct spake2_ctx_st {
|
||||
uint8_t private_key[32];
|
||||
uint8_t my_msg[32];
|
||||
uint8_t password_scalar[32];
|
||||
uint8_t password_hash[64];
|
||||
uint8_t *my_name;
|
||||
size_t my_name_len;
|
||||
uint8_t *their_name;
|
||||
size_t their_name_len;
|
||||
enum spake2_role_t my_role;
|
||||
enum spake2_state_t state;
|
||||
char disable_password_scalar_hack;
|
||||
};
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} // extern C
|
||||
#endif
|
||||
|
||||
#endif // OPENSSL_HEADER_CURVE25519_INTERNAL_H
|
||||
@@ -22,8 +22,8 @@
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "../internal.h"
|
||||
#include "../../third_party/fiat/internal.h"
|
||||
|
||||
|
||||
// The following precomputation tables are for the following
|
||||
@@ -44,14 +44,14 @@
|
||||
// see curve25519.c in this directory.
|
||||
//
|
||||
// Exact copies of the source code are kept in bug 27296743.
|
||||
//
|
||||
// import hashlib
|
||||
// import ed25519 as E # http://ed25519.cr.yp.to/python/ed25519.py
|
||||
//
|
||||
// SEED_N = 'edwards25519 point generation seed (N)'
|
||||
// SEED_M = 'edwards25519 point generation seed (M)'
|
||||
|
||||
/*
|
||||
import hashlib
|
||||
import ed25519 as E # http://ed25519.cr.yp.to/python/ed25519.py
|
||||
|
||||
SEED_N = 'edwards25519 point generation seed (N)'
|
||||
SEED_M = 'edwards25519 point generation seed (M)'
|
||||
|
||||
def genpoint(seed):
|
||||
v = hashlib.sha256(seed).digest()
|
||||
it = 1
|
||||
@@ -73,10 +73,10 @@ def genpoint(seed):
|
||||
def gentable(P):
|
||||
t = []
|
||||
for i in range(1,16):
|
||||
k = ((i >> 3 & 1) * (1 << 192) +
|
||||
(i >> 2 & 1) * (1 << 128) +
|
||||
(i >> 1 & 1) * (1 << 64) +
|
||||
(i & 1))
|
||||
k = (i >> 3 & 1) * (1 << 192) + \
|
||||
(i >> 2 & 1) * (1 << 128) + \
|
||||
(i >> 1 & 1) * (1 << 64) + \
|
||||
(i & 1)
|
||||
t.append(E.scalarmult(P, k))
|
||||
return ''.join(E.encodeint(x) + E.encodeint(y) for (x,y) in t)
|
||||
|
||||
@@ -481,7 +481,7 @@ int SPAKE2_process_msg(SPAKE2_CTX *ctx, uint8_t *out_key, size_t *out_key_len,
|
||||
}
|
||||
|
||||
ge_p3 Qstar;
|
||||
if (!x25519_ge_frombytes_vartime(&Qstar, their_msg)) {
|
||||
if (0 != x25519_ge_frombytes_vartime(&Qstar, their_msg)) {
|
||||
// Point received from peer was not on the curve.
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "../internal.h"
|
||||
#include "../../third_party/fiat/internal.h"
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
// TODO(agl): add tests with fixed vectors once SPAKE2 is nailed down.
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
/* Copyright (c) 2015, Google Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
// This code is mostly taken from the ref10 version of Ed25519 in SUPERCOP
|
||||
// 20141124 (http://bench.cr.yp.to/supercop.html). That code is released as
|
||||
// public domain but this file has the ISC license just to keep licencing
|
||||
// simple.
|
||||
//
|
||||
// The field functions are shared by Ed25519 and X25519 where possible.
|
||||
|
||||
#include <openssl/curve25519.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "../internal.h"
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
#if defined(BORINGSSL_X25519_X86_64)
|
||||
|
||||
typedef struct { uint64_t v[5]; } fe25519;
|
||||
|
||||
// These functions are defined in asm/x25519-x86_64.S
|
||||
void x25519_x86_64_work_cswap(fe25519 *, uint64_t);
|
||||
void x25519_x86_64_mul(fe25519 *out, const fe25519 *a, const fe25519 *b);
|
||||
void x25519_x86_64_square(fe25519 *out, const fe25519 *a);
|
||||
void x25519_x86_64_freeze(fe25519 *);
|
||||
void x25519_x86_64_ladderstep(fe25519 *work);
|
||||
|
||||
static void fe25519_setint(fe25519 *r, unsigned v) {
|
||||
r->v[0] = v;
|
||||
r->v[1] = 0;
|
||||
r->v[2] = 0;
|
||||
r->v[3] = 0;
|
||||
r->v[4] = 0;
|
||||
}
|
||||
|
||||
// Assumes input x being reduced below 2^255
|
||||
static void fe25519_pack(unsigned char r[32], const fe25519 *x) {
|
||||
fe25519 t;
|
||||
t = *x;
|
||||
x25519_x86_64_freeze(&t);
|
||||
|
||||
r[0] = (uint8_t)(t.v[0] & 0xff);
|
||||
r[1] = (uint8_t)((t.v[0] >> 8) & 0xff);
|
||||
r[2] = (uint8_t)((t.v[0] >> 16) & 0xff);
|
||||
r[3] = (uint8_t)((t.v[0] >> 24) & 0xff);
|
||||
r[4] = (uint8_t)((t.v[0] >> 32) & 0xff);
|
||||
r[5] = (uint8_t)((t.v[0] >> 40) & 0xff);
|
||||
r[6] = (uint8_t)((t.v[0] >> 48));
|
||||
|
||||
r[6] ^= (uint8_t)((t.v[1] << 3) & 0xf8);
|
||||
r[7] = (uint8_t)((t.v[1] >> 5) & 0xff);
|
||||
r[8] = (uint8_t)((t.v[1] >> 13) & 0xff);
|
||||
r[9] = (uint8_t)((t.v[1] >> 21) & 0xff);
|
||||
r[10] = (uint8_t)((t.v[1] >> 29) & 0xff);
|
||||
r[11] = (uint8_t)((t.v[1] >> 37) & 0xff);
|
||||
r[12] = (uint8_t)((t.v[1] >> 45));
|
||||
|
||||
r[12] ^= (uint8_t)((t.v[2] << 6) & 0xc0);
|
||||
r[13] = (uint8_t)((t.v[2] >> 2) & 0xff);
|
||||
r[14] = (uint8_t)((t.v[2] >> 10) & 0xff);
|
||||
r[15] = (uint8_t)((t.v[2] >> 18) & 0xff);
|
||||
r[16] = (uint8_t)((t.v[2] >> 26) & 0xff);
|
||||
r[17] = (uint8_t)((t.v[2] >> 34) & 0xff);
|
||||
r[18] = (uint8_t)((t.v[2] >> 42) & 0xff);
|
||||
r[19] = (uint8_t)((t.v[2] >> 50));
|
||||
|
||||
r[19] ^= (uint8_t)((t.v[3] << 1) & 0xfe);
|
||||
r[20] = (uint8_t)((t.v[3] >> 7) & 0xff);
|
||||
r[21] = (uint8_t)((t.v[3] >> 15) & 0xff);
|
||||
r[22] = (uint8_t)((t.v[3] >> 23) & 0xff);
|
||||
r[23] = (uint8_t)((t.v[3] >> 31) & 0xff);
|
||||
r[24] = (uint8_t)((t.v[3] >> 39) & 0xff);
|
||||
r[25] = (uint8_t)((t.v[3] >> 47));
|
||||
|
||||
r[25] ^= (uint8_t)((t.v[4] << 4) & 0xf0);
|
||||
r[26] = (uint8_t)((t.v[4] >> 4) & 0xff);
|
||||
r[27] = (uint8_t)((t.v[4] >> 12) & 0xff);
|
||||
r[28] = (uint8_t)((t.v[4] >> 20) & 0xff);
|
||||
r[29] = (uint8_t)((t.v[4] >> 28) & 0xff);
|
||||
r[30] = (uint8_t)((t.v[4] >> 36) & 0xff);
|
||||
r[31] = (uint8_t)((t.v[4] >> 44));
|
||||
}
|
||||
|
||||
static void fe25519_unpack(fe25519 *r, const uint8_t x[32]) {
|
||||
r->v[0] = x[0];
|
||||
r->v[0] += (uint64_t)x[1] << 8;
|
||||
r->v[0] += (uint64_t)x[2] << 16;
|
||||
r->v[0] += (uint64_t)x[3] << 24;
|
||||
r->v[0] += (uint64_t)x[4] << 32;
|
||||
r->v[0] += (uint64_t)x[5] << 40;
|
||||
r->v[0] += ((uint64_t)x[6] & 7) << 48;
|
||||
|
||||
r->v[1] = x[6] >> 3;
|
||||
r->v[1] += (uint64_t)x[7] << 5;
|
||||
r->v[1] += (uint64_t)x[8] << 13;
|
||||
r->v[1] += (uint64_t)x[9] << 21;
|
||||
r->v[1] += (uint64_t)x[10] << 29;
|
||||
r->v[1] += (uint64_t)x[11] << 37;
|
||||
r->v[1] += ((uint64_t)x[12] & 63) << 45;
|
||||
|
||||
r->v[2] = x[12] >> 6;
|
||||
r->v[2] += (uint64_t)x[13] << 2;
|
||||
r->v[2] += (uint64_t)x[14] << 10;
|
||||
r->v[2] += (uint64_t)x[15] << 18;
|
||||
r->v[2] += (uint64_t)x[16] << 26;
|
||||
r->v[2] += (uint64_t)x[17] << 34;
|
||||
r->v[2] += (uint64_t)x[18] << 42;
|
||||
r->v[2] += ((uint64_t)x[19] & 1) << 50;
|
||||
|
||||
r->v[3] = x[19] >> 1;
|
||||
r->v[3] += (uint64_t)x[20] << 7;
|
||||
r->v[3] += (uint64_t)x[21] << 15;
|
||||
r->v[3] += (uint64_t)x[22] << 23;
|
||||
r->v[3] += (uint64_t)x[23] << 31;
|
||||
r->v[3] += (uint64_t)x[24] << 39;
|
||||
r->v[3] += ((uint64_t)x[25] & 15) << 47;
|
||||
|
||||
r->v[4] = x[25] >> 4;
|
||||
r->v[4] += (uint64_t)x[26] << 4;
|
||||
r->v[4] += (uint64_t)x[27] << 12;
|
||||
r->v[4] += (uint64_t)x[28] << 20;
|
||||
r->v[4] += (uint64_t)x[29] << 28;
|
||||
r->v[4] += (uint64_t)x[30] << 36;
|
||||
r->v[4] += ((uint64_t)x[31] & 127) << 44;
|
||||
}
|
||||
|
||||
static void fe25519_invert(fe25519 *r, const fe25519 *x) {
|
||||
fe25519 z2;
|
||||
fe25519 z9;
|
||||
fe25519 z11;
|
||||
fe25519 z2_5_0;
|
||||
fe25519 z2_10_0;
|
||||
fe25519 z2_20_0;
|
||||
fe25519 z2_50_0;
|
||||
fe25519 z2_100_0;
|
||||
fe25519 t;
|
||||
int i;
|
||||
|
||||
/* 2 */ x25519_x86_64_square(&z2, x);
|
||||
/* 4 */ x25519_x86_64_square(&t, &z2);
|
||||
/* 8 */ x25519_x86_64_square(&t, &t);
|
||||
/* 9 */ x25519_x86_64_mul(&z9, &t, x);
|
||||
/* 11 */ x25519_x86_64_mul(&z11, &z9, &z2);
|
||||
/* 22 */ x25519_x86_64_square(&t, &z11);
|
||||
/* 2^5 - 2^0 = 31 */ x25519_x86_64_mul(&z2_5_0, &t, &z9);
|
||||
|
||||
/* 2^6 - 2^1 */ x25519_x86_64_square(&t, &z2_5_0);
|
||||
/* 2^20 - 2^10 */ for (i = 1; i < 5; i++) { x25519_x86_64_square(&t, &t); }
|
||||
/* 2^10 - 2^0 */ x25519_x86_64_mul(&z2_10_0, &t, &z2_5_0);
|
||||
|
||||
/* 2^11 - 2^1 */ x25519_x86_64_square(&t, &z2_10_0);
|
||||
/* 2^20 - 2^10 */ for (i = 1; i < 10; i++) { x25519_x86_64_square(&t, &t); }
|
||||
/* 2^20 - 2^0 */ x25519_x86_64_mul(&z2_20_0, &t, &z2_10_0);
|
||||
|
||||
/* 2^21 - 2^1 */ x25519_x86_64_square(&t, &z2_20_0);
|
||||
/* 2^40 - 2^20 */ for (i = 1; i < 20; i++) { x25519_x86_64_square(&t, &t); }
|
||||
/* 2^40 - 2^0 */ x25519_x86_64_mul(&t, &t, &z2_20_0);
|
||||
|
||||
/* 2^41 - 2^1 */ x25519_x86_64_square(&t, &t);
|
||||
/* 2^50 - 2^10 */ for (i = 1; i < 10; i++) { x25519_x86_64_square(&t, &t); }
|
||||
/* 2^50 - 2^0 */ x25519_x86_64_mul(&z2_50_0, &t, &z2_10_0);
|
||||
|
||||
/* 2^51 - 2^1 */ x25519_x86_64_square(&t, &z2_50_0);
|
||||
/* 2^100 - 2^50 */ for (i = 1; i < 50; i++) { x25519_x86_64_square(&t, &t); }
|
||||
/* 2^100 - 2^0 */ x25519_x86_64_mul(&z2_100_0, &t, &z2_50_0);
|
||||
|
||||
/* 2^101 - 2^1 */ x25519_x86_64_square(&t, &z2_100_0);
|
||||
/* 2^200 - 2^100 */ for (i = 1; i < 100; i++) {
|
||||
x25519_x86_64_square(&t, &t);
|
||||
}
|
||||
/* 2^200 - 2^0 */ x25519_x86_64_mul(&t, &t, &z2_100_0);
|
||||
|
||||
/* 2^201 - 2^1 */ x25519_x86_64_square(&t, &t);
|
||||
/* 2^250 - 2^50 */ for (i = 1; i < 50; i++) { x25519_x86_64_square(&t, &t); }
|
||||
/* 2^250 - 2^0 */ x25519_x86_64_mul(&t, &t, &z2_50_0);
|
||||
|
||||
/* 2^251 - 2^1 */ x25519_x86_64_square(&t, &t);
|
||||
/* 2^252 - 2^2 */ x25519_x86_64_square(&t, &t);
|
||||
/* 2^253 - 2^3 */ x25519_x86_64_square(&t, &t);
|
||||
|
||||
/* 2^254 - 2^4 */ x25519_x86_64_square(&t, &t);
|
||||
|
||||
/* 2^255 - 2^5 */ x25519_x86_64_square(&t, &t);
|
||||
/* 2^255 - 21 */ x25519_x86_64_mul(r, &t, &z11);
|
||||
}
|
||||
|
||||
static void mladder(fe25519 *xr, fe25519 *zr, const uint8_t s[32]) {
|
||||
fe25519 work[5];
|
||||
|
||||
work[0] = *xr;
|
||||
fe25519_setint(work + 1, 1);
|
||||
fe25519_setint(work + 2, 0);
|
||||
work[3] = *xr;
|
||||
fe25519_setint(work + 4, 1);
|
||||
|
||||
int i, j;
|
||||
uint8_t prevbit = 0;
|
||||
|
||||
j = 6;
|
||||
for (i = 31; i >= 0; i--) {
|
||||
while (j >= 0) {
|
||||
const uint8_t bit = 1 & (s[i] >> j);
|
||||
const uint64_t swap = bit ^ prevbit;
|
||||
prevbit = bit;
|
||||
x25519_x86_64_work_cswap(work + 1, swap);
|
||||
x25519_x86_64_ladderstep(work);
|
||||
j -= 1;
|
||||
}
|
||||
j = 7;
|
||||
}
|
||||
|
||||
*xr = work[1];
|
||||
*zr = work[2];
|
||||
}
|
||||
|
||||
void x25519_x86_64(uint8_t out[32], const uint8_t scalar[32],
|
||||
const uint8_t point[32]) {
|
||||
uint8_t e[32];
|
||||
OPENSSL_memcpy(e, scalar, sizeof(e));
|
||||
|
||||
e[0] &= 248;
|
||||
e[31] &= 127;
|
||||
e[31] |= 64;
|
||||
|
||||
fe25519 t;
|
||||
fe25519 z;
|
||||
fe25519_unpack(&t, point);
|
||||
mladder(&t, &z, e);
|
||||
fe25519_invert(&z, &z);
|
||||
x25519_x86_64_mul(&t, &t, &z);
|
||||
fe25519_pack(out, &t);
|
||||
}
|
||||
|
||||
#endif // BORINGSSL_X25519_X86_64
|
||||
@@ -21,7 +21,6 @@
|
||||
#include <openssl/curve25519.h>
|
||||
|
||||
#include "../internal.h"
|
||||
#include "../test/file_test.h"
|
||||
#include "../test/test_util.h"
|
||||
|
||||
|
||||
@@ -106,45 +105,3 @@ TEST(X25519Test, Iterated) {
|
||||
|
||||
EXPECT_EQ(Bytes(kExpected), Bytes(scalar));
|
||||
}
|
||||
|
||||
TEST(X25519Test, DISABLED_IteratedLarge) {
|
||||
// Taken from https://tools.ietf.org/html/rfc7748#section-5.2.
|
||||
uint8_t scalar[32] = {9}, point[32] = {9}, out[32];
|
||||
|
||||
for (unsigned i = 0; i < 1000000; i++) {
|
||||
EXPECT_TRUE(X25519(out, scalar, point));
|
||||
OPENSSL_memcpy(point, scalar, sizeof(point));
|
||||
OPENSSL_memcpy(scalar, out, sizeof(scalar));
|
||||
}
|
||||
|
||||
static const uint8_t kExpected[32] = {
|
||||
0x7c, 0x39, 0x11, 0xe0, 0xab, 0x25, 0x86, 0xfd, 0x86, 0x44, 0x97,
|
||||
0x29, 0x7e, 0x57, 0x5e, 0x6f, 0x3b, 0xc6, 0x01, 0xc0, 0x88, 0x3c,
|
||||
0x30, 0xdf, 0x5f, 0x4d, 0xd2, 0xd2, 0x4f, 0x66, 0x54, 0x24,
|
||||
};
|
||||
|
||||
EXPECT_EQ(Bytes(kExpected), Bytes(scalar));
|
||||
}
|
||||
|
||||
TEST(X25519Test, Wycheproof) {
|
||||
FileTestGTest("third_party/wycheproof_testvectors/x25519_test.txt",
|
||||
[](FileTest *t) {
|
||||
t->IgnoreInstruction("curve");
|
||||
t->IgnoreAttribute("curve");
|
||||
|
||||
// Our implementation tolerates the Wycheproof "acceptable"
|
||||
// inputs. Wycheproof's valid vs. acceptable criteria does not match our
|
||||
// X25519 return value, so we test only the overall output.
|
||||
t->IgnoreAttribute("result");
|
||||
|
||||
std::vector<uint8_t> priv, pub, shared;
|
||||
ASSERT_TRUE(t->GetBytes(&priv, "private"));
|
||||
ASSERT_TRUE(t->GetBytes(&pub, "public"));
|
||||
ASSERT_TRUE(t->GetBytes(&shared, "shared"));
|
||||
ASSERT_EQ(32u, priv.size());
|
||||
ASSERT_EQ(32u, pub.size());
|
||||
uint8_t secret[32];
|
||||
X25519(secret, priv.data(), pub.data());
|
||||
EXPECT_EQ(Bytes(secret), Bytes(shared));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -258,20 +258,3 @@ TEST(DigestTest, ASN1) {
|
||||
CBS_init(&cbs, kSHA256GarbageParam, sizeof(kSHA256GarbageParam));
|
||||
EXPECT_FALSE(EVP_parse_digest_algorithm(&cbs));
|
||||
}
|
||||
|
||||
TEST(DigestTest, TransformBlocks) {
|
||||
uint8_t blocks[SHA256_CBLOCK * 10];
|
||||
for (size_t i = 0; i < sizeof(blocks); i++) {
|
||||
blocks[i] = i*3;
|
||||
}
|
||||
|
||||
SHA256_CTX ctx1;
|
||||
SHA256_Init(&ctx1);
|
||||
SHA256_Update(&ctx1, blocks, sizeof(blocks));
|
||||
|
||||
SHA256_CTX ctx2;
|
||||
SHA256_Init(&ctx2);
|
||||
SHA256_TransformBlocks(ctx2.h, blocks, sizeof(blocks) / SHA256_CBLOCK);
|
||||
|
||||
EXPECT_TRUE(0 == OPENSSL_memcmp(ctx1.h, ctx2.h, sizeof(ctx1.h)));
|
||||
}
|
||||
|
||||
+91
-76
@@ -82,9 +82,6 @@
|
||||
// Rabin-Miller
|
||||
#define DSS_prime_checks 50
|
||||
|
||||
static int dsa_sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **out_kinv,
|
||||
BIGNUM **out_r);
|
||||
|
||||
static CRYPTO_EX_DATA_CLASS g_ex_data_class = CRYPTO_EX_DATA_CLASS_INIT;
|
||||
|
||||
DSA *DSA_new(void) {
|
||||
@@ -120,6 +117,8 @@ void DSA_free(DSA *dsa) {
|
||||
BN_clear_free(dsa->g);
|
||||
BN_clear_free(dsa->pub_key);
|
||||
BN_clear_free(dsa->priv_key);
|
||||
BN_clear_free(dsa->kinv);
|
||||
BN_clear_free(dsa->r);
|
||||
BN_MONT_CTX_free(dsa->method_mont_p);
|
||||
BN_MONT_CTX_free(dsa->method_mont_q);
|
||||
CRYPTO_MUTEX_cleanup(&dsa->method_mont_lock);
|
||||
@@ -239,6 +238,11 @@ int DSA_generate_parameters_ex(DSA *dsa, unsigned bits, const uint8_t *seed_in,
|
||||
}
|
||||
BN_CTX_start(ctx);
|
||||
|
||||
mont = BN_MONT_CTX_new();
|
||||
if (mont == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
r0 = BN_CTX_get(ctx);
|
||||
g = BN_CTX_get(ctx);
|
||||
W = BN_CTX_get(ctx);
|
||||
@@ -396,9 +400,8 @@ end:
|
||||
goto err;
|
||||
}
|
||||
|
||||
mont = BN_MONT_CTX_new_for_modulus(p, ctx);
|
||||
if (mont == NULL ||
|
||||
!BN_set_word(test, h)) {
|
||||
if (!BN_set_word(test, h) ||
|
||||
!BN_MONT_CTX_set(mont, p, ctx)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -541,29 +544,14 @@ void DSA_SIG_free(DSA_SIG *sig) {
|
||||
OPENSSL_free(sig);
|
||||
}
|
||||
|
||||
// mod_mul_consttime sets |r| to |a| * |b| modulo |mont->N|, treating |a| and
|
||||
// |b| as secret. This function internally uses Montgomery reduction, but
|
||||
// neither inputs nor outputs are in Montgomery form.
|
||||
static int mod_mul_consttime(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
|
||||
const BN_MONT_CTX *mont, BN_CTX *ctx) {
|
||||
BN_CTX_start(ctx);
|
||||
BIGNUM *tmp = BN_CTX_get(ctx);
|
||||
// |BN_mod_mul_montgomery| removes a factor of R, so we cancel it with a
|
||||
// single |BN_to_montgomery| which adds one factor of R.
|
||||
int ok = tmp != NULL &&
|
||||
BN_to_montgomery(tmp, a, mont, ctx) &&
|
||||
BN_mod_mul_montgomery(r, tmp, b, mont, ctx);
|
||||
BN_CTX_end(ctx);
|
||||
return ok;
|
||||
}
|
||||
|
||||
DSA_SIG *DSA_do_sign(const uint8_t *digest, size_t digest_len, const DSA *dsa) {
|
||||
DSA_SIG *DSA_do_sign(const uint8_t *digest, size_t digest_len, DSA *dsa) {
|
||||
BIGNUM *kinv = NULL, *r = NULL, *s = NULL;
|
||||
BIGNUM m;
|
||||
BIGNUM xr;
|
||||
BN_CTX *ctx = NULL;
|
||||
int reason = ERR_R_BN_LIB;
|
||||
DSA_SIG *ret = NULL;
|
||||
int noredo = 0;
|
||||
|
||||
BN_init(&m);
|
||||
BN_init(&xr);
|
||||
@@ -573,14 +561,6 @@ DSA_SIG *DSA_do_sign(const uint8_t *digest, size_t digest_len, const DSA *dsa) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
// We only support DSA keys that are a multiple of 8 bits. (This is a weaker
|
||||
// check than the one in |DSA_do_check_signature|, which only allows 160-,
|
||||
// 224-, and 256-bit keys.
|
||||
if (BN_num_bits(dsa->q) % 8 != 0) {
|
||||
reason = DSA_R_BAD_Q_VALUE;
|
||||
goto err;
|
||||
}
|
||||
|
||||
s = BN_new();
|
||||
if (s == NULL) {
|
||||
goto err;
|
||||
@@ -591,14 +571,22 @@ DSA_SIG *DSA_do_sign(const uint8_t *digest, size_t digest_len, const DSA *dsa) {
|
||||
}
|
||||
|
||||
redo:
|
||||
if (!dsa_sign_setup(dsa, ctx, &kinv, &r)) {
|
||||
goto err;
|
||||
if (dsa->kinv == NULL || dsa->r == NULL) {
|
||||
if (!DSA_sign_setup(dsa, ctx, &kinv, &r)) {
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
kinv = dsa->kinv;
|
||||
dsa->kinv = NULL;
|
||||
r = dsa->r;
|
||||
dsa->r = NULL;
|
||||
noredo = 1;
|
||||
}
|
||||
|
||||
if (digest_len > BN_num_bytes(dsa->q)) {
|
||||
// If the digest length is greater than the size of |dsa->q| use the
|
||||
// BN_num_bits(dsa->q) leftmost bits of the digest, see FIPS 186-3, 4.2.
|
||||
// Note the above check that |dsa->q| is a multiple of 8 bits.
|
||||
// if the digest length is greater than the size of q use the
|
||||
// BN_num_bits(dsa->q) leftmost bits of the digest, see
|
||||
// fips 186-3, 4.2
|
||||
digest_len = BN_num_bytes(dsa->q);
|
||||
}
|
||||
|
||||
@@ -606,29 +594,29 @@ redo:
|
||||
goto err;
|
||||
}
|
||||
|
||||
// |m| is bounded by 2^(num_bits(q)), which is slightly looser than q. This
|
||||
// violates |bn_mod_add_consttime| and |mod_mul_consttime|'s preconditions.
|
||||
// (The underlying algorithms could accept looser bounds, but we reduce for
|
||||
// simplicity.)
|
||||
size_t q_width = bn_minimal_width(dsa->q);
|
||||
if (!bn_resize_words(&m, q_width) ||
|
||||
!bn_resize_words(&xr, q_width)) {
|
||||
goto err;
|
||||
// Compute s = inv(k) (m + xr) mod q
|
||||
if (!BN_mod_mul(&xr, dsa->priv_key, r, dsa->q, ctx)) {
|
||||
goto err; // s = xr
|
||||
}
|
||||
bn_reduce_once_in_place(m.d, 0 /* no carry word */, dsa->q->d,
|
||||
xr.d /* scratch space */, q_width);
|
||||
|
||||
// Compute s = inv(k) (m + xr) mod q. Note |dsa->method_mont_q| is
|
||||
// initialized by |dsa_sign_setup|.
|
||||
if (!mod_mul_consttime(&xr, dsa->priv_key, r, dsa->method_mont_q, ctx) ||
|
||||
!bn_mod_add_consttime(s, &xr, &m, dsa->q, ctx) ||
|
||||
!mod_mul_consttime(s, s, kinv, dsa->method_mont_q, ctx)) {
|
||||
if (!BN_add(s, &xr, &m)) {
|
||||
goto err; // s = m + xr
|
||||
}
|
||||
if (BN_cmp(s, dsa->q) > 0) {
|
||||
if (!BN_sub(s, s, dsa->q)) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
if (!BN_mod_mul(s, s, kinv, dsa->q, ctx)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
// Redo if r or s is zero as required by FIPS 186-3: this is
|
||||
// very unlikely.
|
||||
if (BN_is_zero(r) || BN_is_zero(s)) {
|
||||
if (noredo) {
|
||||
reason = DSA_R_NEED_NEW_SETUP_VALUES;
|
||||
goto err;
|
||||
}
|
||||
goto redo;
|
||||
}
|
||||
ret = DSA_SIG_new();
|
||||
@@ -676,7 +664,7 @@ int DSA_do_check_signature(int *out_valid, const uint8_t *digest,
|
||||
}
|
||||
|
||||
i = BN_num_bits(dsa->q);
|
||||
// FIPS 186-3 allows only different sizes for q.
|
||||
// fips 186-3 allows only different sizes for q
|
||||
if (i != 160 && i != 224 && i != 256) {
|
||||
OPENSSL_PUT_ERROR(DSA, DSA_R_BAD_Q_VALUE);
|
||||
return 0;
|
||||
@@ -770,7 +758,7 @@ err:
|
||||
}
|
||||
|
||||
int DSA_sign(int type, const uint8_t *digest, size_t digest_len,
|
||||
uint8_t *out_sig, unsigned int *out_siglen, const DSA *dsa) {
|
||||
uint8_t *out_sig, unsigned int *out_siglen, DSA *dsa) {
|
||||
DSA_SIG *s;
|
||||
|
||||
s = DSA_do_sign(digest, digest_len, dsa);
|
||||
@@ -860,10 +848,10 @@ int DSA_size(const DSA *dsa) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dsa_sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **out_kinv,
|
||||
BIGNUM **out_r) {
|
||||
int DSA_sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **out_kinv,
|
||||
BIGNUM **out_r) {
|
||||
BN_CTX *ctx;
|
||||
BIGNUM k, *kinv = NULL, *r = NULL;
|
||||
BIGNUM k, kq, *kinv = NULL, *r = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if (!dsa->p || !dsa->q || !dsa->g) {
|
||||
@@ -872,6 +860,7 @@ static int dsa_sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **out_kinv,
|
||||
}
|
||||
|
||||
BN_init(&k);
|
||||
BN_init(&kq);
|
||||
|
||||
ctx = ctx_in;
|
||||
if (ctx == NULL) {
|
||||
@@ -882,29 +871,54 @@ static int dsa_sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **out_kinv,
|
||||
}
|
||||
|
||||
r = BN_new();
|
||||
kinv = BN_new();
|
||||
if (r == NULL || kinv == NULL ||
|
||||
// Get random k
|
||||
!BN_rand_range_ex(&k, 1, dsa->q) ||
|
||||
!BN_MONT_CTX_set_locked((BN_MONT_CTX **)&dsa->method_mont_p,
|
||||
if (r == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
// Get random k
|
||||
if (!BN_rand_range_ex(&k, 1, dsa->q)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!BN_MONT_CTX_set_locked((BN_MONT_CTX **)&dsa->method_mont_p,
|
||||
(CRYPTO_MUTEX *)&dsa->method_mont_lock, dsa->p,
|
||||
ctx) ||
|
||||
!BN_MONT_CTX_set_locked((BN_MONT_CTX **)&dsa->method_mont_q,
|
||||
(CRYPTO_MUTEX *)&dsa->method_mont_lock, dsa->q,
|
||||
ctx) ||
|
||||
// Compute r = (g^k mod p) mod q
|
||||
!BN_mod_exp_mont_consttime(r, dsa->g, &k, dsa->p, ctx,
|
||||
dsa->method_mont_p) ||
|
||||
// Note |BN_mod| below is not constant-time and may leak information about
|
||||
// |r|. |dsa->p| may be significantly larger than |dsa->q|, so this is not
|
||||
// easily performed in constant-time with Montgomery reduction.
|
||||
//
|
||||
// However, |r| at this point is g^k (mod p). It is almost the value of
|
||||
// |r| revealed in the signature anyway (g^k (mod p) (mod q)), going from
|
||||
// it to |k| would require computing a discrete log.
|
||||
!BN_mod(r, r, dsa->q, ctx) ||
|
||||
// Compute part of 's = inv(k) (m + xr) mod q' using Fermat's Little
|
||||
// Theorem.
|
||||
ctx)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
// Compute r = (g^k mod p) mod q
|
||||
if (!BN_copy(&kq, &k)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
// We do not want timing information to leak the length of k,
|
||||
// so we compute g^k using an equivalent exponent of fixed length.
|
||||
//
|
||||
// (This is a kludge that we need because the BN_mod_exp_mont()
|
||||
// does not let us specify the desired timing behaviour.)
|
||||
|
||||
if (!BN_add(&kq, &kq, dsa->q)) {
|
||||
goto err;
|
||||
}
|
||||
if (BN_num_bits(&kq) <= BN_num_bits(dsa->q) && !BN_add(&kq, &kq, dsa->q)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!BN_mod_exp_mont_consttime(r, dsa->g, &kq, dsa->p, ctx,
|
||||
dsa->method_mont_p)) {
|
||||
goto err;
|
||||
}
|
||||
if (!BN_mod(r, r, dsa->q, ctx)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
// Compute part of 's = inv(k) (m + xr) mod q' using Fermat's Little
|
||||
// Theorem.
|
||||
kinv = BN_new();
|
||||
if (kinv == NULL ||
|
||||
!bn_mod_inverse_prime(kinv, &k, dsa->q, ctx, dsa->method_mont_q)) {
|
||||
goto err;
|
||||
}
|
||||
@@ -928,6 +942,7 @@ err:
|
||||
BN_CTX_free(ctx);
|
||||
}
|
||||
BN_clear_free(&k);
|
||||
BN_clear_free(&kq);
|
||||
BN_clear_free(kinv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
+12
-11
@@ -67,9 +67,9 @@
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
static const unsigned kParametersTag =
|
||||
static const uint8_t kParametersTag =
|
||||
CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 0;
|
||||
static const unsigned kPublicKeyTag =
|
||||
static const uint8_t kPublicKeyTag =
|
||||
CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 1;
|
||||
|
||||
EC_KEY *EC_KEY_parse_private_key(CBS *cbs, const EC_GROUP *group) {
|
||||
@@ -86,7 +86,6 @@ EC_KEY *EC_KEY_parse_private_key(CBS *cbs, const EC_GROUP *group) {
|
||||
// Parse the optional parameters field.
|
||||
EC_GROUP *inner_group = NULL;
|
||||
EC_KEY *ret = NULL;
|
||||
BIGNUM *priv_key = NULL;
|
||||
if (CBS_peek_asn1_tag(&ec_private_key, kParametersTag)) {
|
||||
// Per SEC 1, as an alternative to omitting it, one is allowed to specify
|
||||
// this field and put in a NULL to mean inheriting this value. This was
|
||||
@@ -127,10 +126,15 @@ EC_KEY *EC_KEY_parse_private_key(CBS *cbs, const EC_GROUP *group) {
|
||||
// Although RFC 5915 specifies the length of the key, OpenSSL historically
|
||||
// got this wrong, so accept any length. See upstream's
|
||||
// 30cd4ff294252c4b6a4b69cbef6a5b4117705d22.
|
||||
priv_key = BN_bin2bn(CBS_data(&private_key), CBS_len(&private_key), NULL);
|
||||
ret->priv_key =
|
||||
BN_bin2bn(CBS_data(&private_key), CBS_len(&private_key), NULL);
|
||||
ret->pub_key = EC_POINT_new(group);
|
||||
if (priv_key == NULL || ret->pub_key == NULL ||
|
||||
!EC_KEY_set_private_key(ret, priv_key)) {
|
||||
if (ret->priv_key == NULL || ret->pub_key == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (BN_cmp(ret->priv_key, EC_GROUP_get0_order(group)) >= 0) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_WRONG_ORDER);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -159,8 +163,7 @@ EC_KEY *EC_KEY_parse_private_key(CBS *cbs, const EC_GROUP *group) {
|
||||
(point_conversion_form_t)(CBS_data(&public_key)[0] & ~0x01);
|
||||
} else {
|
||||
// Compute the public key instead.
|
||||
if (!ec_point_mul_scalar(group, ret->pub_key, &ret->priv_key->scalar, NULL,
|
||||
NULL, NULL)) {
|
||||
if (!EC_POINT_mul(group, ret->pub_key, ret->priv_key, NULL, NULL, NULL)) {
|
||||
goto err;
|
||||
}
|
||||
// Remember the original private-key-only encoding.
|
||||
@@ -178,13 +181,11 @@ EC_KEY *EC_KEY_parse_private_key(CBS *cbs, const EC_GROUP *group) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
BN_free(priv_key);
|
||||
EC_GROUP_free(inner_group);
|
||||
return ret;
|
||||
|
||||
err:
|
||||
EC_KEY_free(ret);
|
||||
BN_free(priv_key);
|
||||
EC_GROUP_free(inner_group);
|
||||
return NULL;
|
||||
}
|
||||
@@ -202,7 +203,7 @@ int EC_KEY_marshal_private_key(CBB *cbb, const EC_KEY *key,
|
||||
!CBB_add_asn1(&ec_private_key, &private_key, CBS_ASN1_OCTETSTRING) ||
|
||||
!BN_bn2cbb_padded(&private_key,
|
||||
BN_num_bytes(EC_GROUP_get0_order(key->group)),
|
||||
EC_KEY_get0_private_key(key))) {
|
||||
key->priv_key)) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_ENCODE_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
include_directories(../../include)
|
||||
|
||||
add_library(
|
||||
ecdh
|
||||
|
||||
OBJECT
|
||||
|
||||
ecdh.c
|
||||
)
|
||||
@@ -70,41 +70,41 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/ec_key.h>
|
||||
#include <openssl/digest.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include "../ec/internal.h"
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
int ECDH_compute_key_fips(uint8_t *out, size_t out_len, const EC_POINT *pub_key,
|
||||
const EC_KEY *priv_key) {
|
||||
if (priv_key->priv_key == NULL) {
|
||||
int ECDH_compute_key(void *out, size_t outlen, const EC_POINT *pub_key,
|
||||
const EC_KEY *priv_key,
|
||||
void *(*kdf)(const void *in, size_t inlen, void *out,
|
||||
size_t *outlen)) {
|
||||
const BIGNUM *const priv = EC_KEY_get0_private_key(priv_key);
|
||||
if (priv == NULL) {
|
||||
OPENSSL_PUT_ERROR(ECDH, ECDH_R_NO_PRIVATE_VALUE);
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
const EC_SCALAR *const priv = &priv_key->priv_key->scalar;
|
||||
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
if (ctx == NULL) {
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
BN_CTX_start(ctx);
|
||||
|
||||
int ret = 0;
|
||||
int ret = -1;
|
||||
size_t buflen = 0;
|
||||
uint8_t *buf = NULL;
|
||||
|
||||
const EC_GROUP *const group = EC_KEY_get0_group(priv_key);
|
||||
EC_POINT *shared_point = EC_POINT_new(group);
|
||||
if (shared_point == NULL) {
|
||||
EC_POINT *tmp = EC_POINT_new(group);
|
||||
if (tmp == NULL) {
|
||||
OPENSSL_PUT_ERROR(ECDH, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!ec_point_mul_scalar(group, shared_point, NULL, pub_key, priv, ctx)) {
|
||||
if (!EC_POINT_mul(group, tmp, NULL, pub_key, priv, ctx)) {
|
||||
OPENSSL_PUT_ERROR(ECDH, ECDH_R_POINT_ARITHMETIC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
@@ -115,7 +115,7 @@ int ECDH_compute_key_fips(uint8_t *out, size_t out_len, const EC_POINT *pub_key,
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!EC_POINT_get_affine_coordinates_GFp(group, shared_point, x, NULL, ctx)) {
|
||||
if (!EC_POINT_get_affine_coordinates_GFp(group, tmp, x, NULL, ctx)) {
|
||||
OPENSSL_PUT_ERROR(ECDH, ECDH_R_POINT_ARITHMETIC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
@@ -132,29 +132,29 @@ int ECDH_compute_key_fips(uint8_t *out, size_t out_len, const EC_POINT *pub_key,
|
||||
goto err;
|
||||
}
|
||||
|
||||
switch (out_len) {
|
||||
case SHA224_DIGEST_LENGTH:
|
||||
SHA224(buf, buflen, out);
|
||||
break;
|
||||
case SHA256_DIGEST_LENGTH:
|
||||
SHA256(buf, buflen, out);
|
||||
break;
|
||||
case SHA384_DIGEST_LENGTH:
|
||||
SHA384(buf, buflen, out);
|
||||
break;
|
||||
case SHA512_DIGEST_LENGTH:
|
||||
SHA512(buf, buflen, out);
|
||||
break;
|
||||
default:
|
||||
OPENSSL_PUT_ERROR(ECDH, ECDH_R_UNKNOWN_DIGEST_LENGTH);
|
||||
if (kdf != NULL) {
|
||||
if (kdf(buf, buflen, out, &outlen) == NULL) {
|
||||
OPENSSL_PUT_ERROR(ECDH, ECDH_R_KDF_FAILED);
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
// no KDF, just copy as much as we can
|
||||
if (buflen < outlen) {
|
||||
outlen = buflen;
|
||||
}
|
||||
OPENSSL_memcpy(out, buf, outlen);
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
if (outlen > INT_MAX) {
|
||||
OPENSSL_PUT_ERROR(ECDH, ERR_R_OVERFLOW);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = (int)outlen;
|
||||
|
||||
err:
|
||||
OPENSSL_free(buf);
|
||||
EC_POINT_free(shared_point);
|
||||
EC_POINT_free(tmp);
|
||||
BN_CTX_end(ctx);
|
||||
BN_CTX_free(ctx);
|
||||
return ret;
|
||||
@@ -0,0 +1,114 @@
|
||||
/* 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. */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/ec_key.h>
|
||||
#include <openssl/ecdh.h>
|
||||
#include <openssl/nid.h>
|
||||
|
||||
#include "../test/file_test.h"
|
||||
#include "../test/test_util.h"
|
||||
|
||||
|
||||
static bssl::UniquePtr<EC_GROUP> GetCurve(FileTest *t, const char *key) {
|
||||
std::string curve_name;
|
||||
if (!t->GetAttribute(&curve_name, key)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (curve_name == "P-224") {
|
||||
return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp224r1));
|
||||
}
|
||||
if (curve_name == "P-256") {
|
||||
return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(
|
||||
NID_X9_62_prime256v1));
|
||||
}
|
||||
if (curve_name == "P-384") {
|
||||
return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp384r1));
|
||||
}
|
||||
if (curve_name == "P-521") {
|
||||
return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp521r1));
|
||||
}
|
||||
|
||||
t->PrintLine("Unknown curve '%s'", curve_name.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bssl::UniquePtr<BIGNUM> GetBIGNUM(FileTest *t, const char *key) {
|
||||
std::vector<uint8_t> bytes;
|
||||
if (!t->GetBytes(&bytes, key)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return bssl::UniquePtr<BIGNUM>(BN_bin2bn(bytes.data(), bytes.size(), nullptr));
|
||||
}
|
||||
|
||||
TEST(ECDHTest, TestVectors) {
|
||||
FileTestGTest("crypto/ecdh/ecdh_tests.txt", [](FileTest *t) {
|
||||
bssl::UniquePtr<EC_GROUP> group = GetCurve(t, "Curve");
|
||||
ASSERT_TRUE(group);
|
||||
bssl::UniquePtr<BIGNUM> priv_key = GetBIGNUM(t, "Private");
|
||||
ASSERT_TRUE(priv_key);
|
||||
bssl::UniquePtr<BIGNUM> x = GetBIGNUM(t, "X");
|
||||
ASSERT_TRUE(x);
|
||||
bssl::UniquePtr<BIGNUM> y = GetBIGNUM(t, "Y");
|
||||
ASSERT_TRUE(y);
|
||||
bssl::UniquePtr<BIGNUM> peer_x = GetBIGNUM(t, "PeerX");
|
||||
ASSERT_TRUE(peer_x);
|
||||
bssl::UniquePtr<BIGNUM> peer_y = GetBIGNUM(t, "PeerY");
|
||||
ASSERT_TRUE(peer_y);
|
||||
std::vector<uint8_t> z;
|
||||
ASSERT_TRUE(t->GetBytes(&z, "Z"));
|
||||
|
||||
bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
|
||||
ASSERT_TRUE(key);
|
||||
bssl::UniquePtr<EC_POINT> pub_key(EC_POINT_new(group.get()));
|
||||
ASSERT_TRUE(pub_key);
|
||||
bssl::UniquePtr<EC_POINT> peer_pub_key(EC_POINT_new(group.get()));
|
||||
ASSERT_TRUE(peer_pub_key);
|
||||
ASSERT_TRUE(EC_KEY_set_group(key.get(), group.get()));
|
||||
ASSERT_TRUE(EC_KEY_set_private_key(key.get(), priv_key.get()));
|
||||
ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(group.get(), pub_key.get(),
|
||||
x.get(), y.get(), nullptr));
|
||||
ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
|
||||
group.get(), peer_pub_key.get(), peer_x.get(), peer_y.get(), nullptr));
|
||||
ASSERT_TRUE(EC_KEY_set_public_key(key.get(), pub_key.get()));
|
||||
ASSERT_TRUE(EC_KEY_check_key(key.get()));
|
||||
|
||||
std::vector<uint8_t> actual_z;
|
||||
// Make |actual_z| larger than expected to ensure |ECDH_compute_key| returns
|
||||
// the right amount of data.
|
||||
actual_z.resize(z.size() + 1);
|
||||
int ret = ECDH_compute_key(actual_z.data(), actual_z.size(),
|
||||
peer_pub_key.get(), key.get(), nullptr);
|
||||
ASSERT_GE(ret, 0);
|
||||
EXPECT_EQ(Bytes(z), Bytes(actual_z.data(), static_cast<size_t>(ret)));
|
||||
|
||||
// Test |ECDH_compute_key| truncates.
|
||||
actual_z.resize(z.size() - 1);
|
||||
ret = ECDH_compute_key(actual_z.data(), actual_z.size(), peer_pub_key.get(),
|
||||
key.get(), nullptr);
|
||||
ASSERT_GE(ret, 0);
|
||||
EXPECT_EQ(Bytes(z.data(), z.size() - 1),
|
||||
Bytes(actual_z.data(), static_cast<size_t>(ret)));
|
||||
});
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
include_directories(../../include)
|
||||
|
||||
add_library(
|
||||
ecdh_extra
|
||||
|
||||
OBJECT
|
||||
|
||||
ecdh_extra.c
|
||||
)
|
||||
@@ -1,162 +0,0 @@
|
||||
/* ====================================================================
|
||||
* Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
|
||||
*
|
||||
* The Elliptic Curve Public-Key Crypto Library (ECC Code) included
|
||||
* herein is developed by SUN MICROSYSTEMS, INC., and is contributed
|
||||
* to the OpenSSL project.
|
||||
*
|
||||
* The ECC Code is licensed pursuant to the OpenSSL open source
|
||||
* license provided below.
|
||||
*
|
||||
* The ECDH software is originally written by Douglas Stebila of
|
||||
* Sun Microsystems Laboratories.
|
||||
*
|
||||
*/
|
||||
/* ====================================================================
|
||||
* Copyright (c) 2000-2002 The OpenSSL Project. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this
|
||||
* software must display the following acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
|
||||
*
|
||||
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* prior written permission. For written permission, please contact
|
||||
* licensing@OpenSSL.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "OpenSSL"
|
||||
* nor may "OpenSSL" appear in their names without prior written
|
||||
* permission of the OpenSSL Project.
|
||||
*
|
||||
* 6. Redistributions of any form whatsoever must retain the following
|
||||
* acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
||||
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
* This product includes cryptographic software written by Eric Young
|
||||
* (eay@cryptsoft.com). This product includes software written by Tim
|
||||
* Hudson (tjh@cryptsoft.com). */
|
||||
|
||||
#include <openssl/ecdh.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/digest.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "../fipsmodule/ec/internal.h"
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
int ECDH_compute_key(void *out, size_t outlen, const EC_POINT *pub_key,
|
||||
const EC_KEY *priv_key,
|
||||
void *(*kdf)(const void *in, size_t inlen, void *out,
|
||||
size_t *outlen)) {
|
||||
if (priv_key->priv_key == NULL) {
|
||||
OPENSSL_PUT_ERROR(ECDH, ECDH_R_NO_PRIVATE_VALUE);
|
||||
return -1;
|
||||
}
|
||||
const EC_SCALAR *const priv = &priv_key->priv_key->scalar;
|
||||
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
BN_CTX_start(ctx);
|
||||
|
||||
int ret = -1;
|
||||
size_t buflen = 0;
|
||||
uint8_t *buf = NULL;
|
||||
|
||||
const EC_GROUP *const group = EC_KEY_get0_group(priv_key);
|
||||
EC_POINT *tmp = EC_POINT_new(group);
|
||||
if (tmp == NULL) {
|
||||
OPENSSL_PUT_ERROR(ECDH, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!ec_point_mul_scalar(group, tmp, NULL, pub_key, priv, ctx)) {
|
||||
OPENSSL_PUT_ERROR(ECDH, ECDH_R_POINT_ARITHMETIC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
|
||||
BIGNUM *x = BN_CTX_get(ctx);
|
||||
if (!x) {
|
||||
OPENSSL_PUT_ERROR(ECDH, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!EC_POINT_get_affine_coordinates_GFp(group, tmp, x, NULL, ctx)) {
|
||||
OPENSSL_PUT_ERROR(ECDH, ECDH_R_POINT_ARITHMETIC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
|
||||
buflen = (EC_GROUP_get_degree(group) + 7) / 8;
|
||||
buf = OPENSSL_malloc(buflen);
|
||||
if (buf == NULL) {
|
||||
OPENSSL_PUT_ERROR(ECDH, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!BN_bn2bin_padded(buf, buflen, x)) {
|
||||
OPENSSL_PUT_ERROR(ECDH, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (kdf != NULL) {
|
||||
if (kdf(buf, buflen, out, &outlen) == NULL) {
|
||||
OPENSSL_PUT_ERROR(ECDH, ECDH_R_KDF_FAILED);
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
// no KDF, just copy as much as we can
|
||||
if (buflen < outlen) {
|
||||
outlen = buflen;
|
||||
}
|
||||
OPENSSL_memcpy(out, buf, outlen);
|
||||
}
|
||||
|
||||
if (outlen > INT_MAX) {
|
||||
OPENSSL_PUT_ERROR(ECDH, ERR_R_OVERFLOW);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = (int)outlen;
|
||||
|
||||
err:
|
||||
OPENSSL_free(buf);
|
||||
EC_POINT_free(tmp);
|
||||
BN_CTX_end(ctx);
|
||||
BN_CTX_free(ctx);
|
||||
return ret;
|
||||
}
|
||||
@@ -1,294 +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. */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/bytestring.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/ec_key.h>
|
||||
#include <openssl/ecdh.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/nid.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include "../test/file_test.h"
|
||||
#include "../test/test_util.h"
|
||||
#include "../test/wycheproof_util.h"
|
||||
|
||||
|
||||
static bssl::UniquePtr<EC_GROUP> GetCurve(FileTest *t, const char *key) {
|
||||
std::string curve_name;
|
||||
if (!t->GetAttribute(&curve_name, key)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (curve_name == "P-224") {
|
||||
return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp224r1));
|
||||
}
|
||||
if (curve_name == "P-256") {
|
||||
return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(
|
||||
NID_X9_62_prime256v1));
|
||||
}
|
||||
if (curve_name == "P-384") {
|
||||
return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp384r1));
|
||||
}
|
||||
if (curve_name == "P-521") {
|
||||
return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp521r1));
|
||||
}
|
||||
|
||||
t->PrintLine("Unknown curve '%s'", curve_name.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bssl::UniquePtr<BIGNUM> GetBIGNUM(FileTest *t, const char *key) {
|
||||
std::vector<uint8_t> bytes;
|
||||
if (!t->GetBytes(&bytes, key)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return bssl::UniquePtr<BIGNUM>(BN_bin2bn(bytes.data(), bytes.size(), nullptr));
|
||||
}
|
||||
|
||||
TEST(ECDHTest, TestVectors) {
|
||||
FileTestGTest("crypto/ecdh_extra/ecdh_tests.txt", [](FileTest *t) {
|
||||
bssl::UniquePtr<EC_GROUP> group = GetCurve(t, "Curve");
|
||||
ASSERT_TRUE(group);
|
||||
bssl::UniquePtr<BIGNUM> priv_key = GetBIGNUM(t, "Private");
|
||||
ASSERT_TRUE(priv_key);
|
||||
bssl::UniquePtr<BIGNUM> x = GetBIGNUM(t, "X");
|
||||
ASSERT_TRUE(x);
|
||||
bssl::UniquePtr<BIGNUM> y = GetBIGNUM(t, "Y");
|
||||
ASSERT_TRUE(y);
|
||||
bssl::UniquePtr<BIGNUM> peer_x = GetBIGNUM(t, "PeerX");
|
||||
ASSERT_TRUE(peer_x);
|
||||
bssl::UniquePtr<BIGNUM> peer_y = GetBIGNUM(t, "PeerY");
|
||||
ASSERT_TRUE(peer_y);
|
||||
std::vector<uint8_t> z;
|
||||
ASSERT_TRUE(t->GetBytes(&z, "Z"));
|
||||
|
||||
bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
|
||||
ASSERT_TRUE(key);
|
||||
bssl::UniquePtr<EC_POINT> pub_key(EC_POINT_new(group.get()));
|
||||
ASSERT_TRUE(pub_key);
|
||||
bssl::UniquePtr<EC_POINT> peer_pub_key(EC_POINT_new(group.get()));
|
||||
ASSERT_TRUE(peer_pub_key);
|
||||
ASSERT_TRUE(EC_KEY_set_group(key.get(), group.get()));
|
||||
ASSERT_TRUE(EC_KEY_set_private_key(key.get(), priv_key.get()));
|
||||
ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(group.get(), pub_key.get(),
|
||||
x.get(), y.get(), nullptr));
|
||||
ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
|
||||
group.get(), peer_pub_key.get(), peer_x.get(), peer_y.get(), nullptr));
|
||||
ASSERT_TRUE(EC_KEY_set_public_key(key.get(), pub_key.get()));
|
||||
ASSERT_TRUE(EC_KEY_check_key(key.get()));
|
||||
|
||||
std::vector<uint8_t> actual_z;
|
||||
// Make |actual_z| larger than expected to ensure |ECDH_compute_key| returns
|
||||
// the right amount of data.
|
||||
actual_z.resize(z.size() + 1);
|
||||
int ret = ECDH_compute_key(actual_z.data(), actual_z.size(),
|
||||
peer_pub_key.get(), key.get(), nullptr);
|
||||
ASSERT_GE(ret, 0);
|
||||
EXPECT_EQ(Bytes(z), Bytes(actual_z.data(), static_cast<size_t>(ret)));
|
||||
|
||||
// Test |ECDH_compute_key| truncates.
|
||||
actual_z.resize(z.size() - 1);
|
||||
ret = ECDH_compute_key(actual_z.data(), actual_z.size(), peer_pub_key.get(),
|
||||
key.get(), nullptr);
|
||||
ASSERT_GE(ret, 0);
|
||||
EXPECT_EQ(Bytes(z.data(), z.size() - 1),
|
||||
Bytes(actual_z.data(), static_cast<size_t>(ret)));
|
||||
|
||||
// Test that |ECDH_compute_key_fips| hashes as expected.
|
||||
uint8_t digest[SHA256_DIGEST_LENGTH], expected_digest[SHA256_DIGEST_LENGTH];
|
||||
ASSERT_TRUE(ECDH_compute_key_fips(digest, sizeof(digest),
|
||||
peer_pub_key.get(), key.get()));
|
||||
SHA256(z.data(), z.size(), expected_digest);
|
||||
EXPECT_EQ(Bytes(digest), Bytes(expected_digest));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
static void RunWycheproofTest(FileTest *t) {
|
||||
t->IgnoreInstruction("encoding");
|
||||
|
||||
bssl::UniquePtr<EC_GROUP> group = GetWycheproofCurve(t, "curve", true);
|
||||
ASSERT_TRUE(group);
|
||||
bssl::UniquePtr<BIGNUM> priv_key = GetWycheproofBIGNUM(t, "private", false);
|
||||
ASSERT_TRUE(priv_key);
|
||||
std::vector<uint8_t> peer_spki;
|
||||
ASSERT_TRUE(t->GetBytes(&peer_spki, "public"));
|
||||
WycheproofResult result;
|
||||
ASSERT_TRUE(GetWycheproofResult(t, &result));
|
||||
std::vector<uint8_t> shared;
|
||||
ASSERT_TRUE(t->GetBytes(&shared, "shared"));
|
||||
|
||||
// Wycheproof stores the peer key in an SPKI to mimic a Java API mistake.
|
||||
// This is non-standard and error-prone.
|
||||
CBS cbs;
|
||||
CBS_init(&cbs, peer_spki.data(), peer_spki.size());
|
||||
bssl::UniquePtr<EVP_PKEY> peer_evp(EVP_parse_public_key(&cbs));
|
||||
if (!peer_evp) {
|
||||
// Note some of Wycheproof's "acceptable" entries are unsupported by
|
||||
// BoringSSL because they test explicit curves (forbidden by RFC 5480),
|
||||
// while others are supported because they used compressed coordinates. If
|
||||
// the peer key fails to parse, we consider it to match "acceptable", but if
|
||||
// the resulting shared secret matches below, it too matches "acceptable".
|
||||
//
|
||||
// TODO(davidben): Use the flags field to disambiguate these. Possibly
|
||||
// first get the Wycheproof folks to use flags more consistently.
|
||||
EXPECT_NE(WycheproofResult::kValid, result);
|
||||
return;
|
||||
}
|
||||
EC_KEY *peer_ec = EVP_PKEY_get0_EC_KEY(peer_evp.get());
|
||||
ASSERT_TRUE(peer_ec);
|
||||
|
||||
bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
|
||||
ASSERT_TRUE(key);
|
||||
ASSERT_TRUE(EC_KEY_set_group(key.get(), group.get()));
|
||||
ASSERT_TRUE(EC_KEY_set_private_key(key.get(), priv_key.get()));
|
||||
|
||||
std::vector<uint8_t> actual((EC_GROUP_get_degree(group.get()) + 7) / 8);
|
||||
int ret =
|
||||
ECDH_compute_key(actual.data(), actual.size(),
|
||||
EC_KEY_get0_public_key(peer_ec), key.get(), nullptr);
|
||||
if (result == WycheproofResult::kInvalid) {
|
||||
EXPECT_EQ(-1, ret);
|
||||
} else {
|
||||
EXPECT_EQ(static_cast<int>(actual.size()), ret);
|
||||
EXPECT_EQ(Bytes(shared), Bytes(actual.data(), static_cast<size_t>(ret)));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ECDHTest, WycheproofP224) {
|
||||
FileTestGTest("third_party/wycheproof_testvectors/ecdh_secp224r1_test.txt",
|
||||
RunWycheproofTest);
|
||||
}
|
||||
|
||||
TEST(ECDHTest, WycheproofP256) {
|
||||
FileTestGTest("third_party/wycheproof_testvectors/ecdh_secp256r1_test.txt",
|
||||
RunWycheproofTest);
|
||||
}
|
||||
|
||||
TEST(ECDHTest, WycheproofP384) {
|
||||
FileTestGTest("third_party/wycheproof_testvectors/ecdh_secp384r1_test.txt",
|
||||
RunWycheproofTest);
|
||||
}
|
||||
|
||||
TEST(ECDHTest, WycheproofP512) {
|
||||
FileTestGTest("third_party/wycheproof_testvectors/ecdh_secp521r1_test.txt",
|
||||
RunWycheproofTest);
|
||||
}
|
||||
|
||||
// MakeCustomGroup returns an |EC_GROUP| containing a non-standard group. (P-256
|
||||
// with the wrong generator.)
|
||||
static bssl::UniquePtr<EC_GROUP> MakeCustomGroup() {
|
||||
static const uint8_t kP[] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
};
|
||||
static const uint8_t kA[] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc,
|
||||
};
|
||||
static const uint8_t kB[] = {
|
||||
0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7, 0xb3, 0xeb, 0xbd,
|
||||
0x55, 0x76, 0x98, 0x86, 0xbc, 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53,
|
||||
0xb0, 0xf6, 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b,
|
||||
};
|
||||
static const uint8_t kX[] = {
|
||||
0xe6, 0x2b, 0x69, 0xe2, 0xbf, 0x65, 0x9f, 0x97, 0xbe, 0x2f, 0x1e,
|
||||
0x0d, 0x94, 0x8a, 0x4c, 0xd5, 0x97, 0x6b, 0xb7, 0xa9, 0x1e, 0x0d,
|
||||
0x46, 0xfb, 0xdd, 0xa9, 0xa9, 0x1e, 0x9d, 0xdc, 0xba, 0x5a,
|
||||
};
|
||||
static const uint8_t kY[] = {
|
||||
0x01, 0xe7, 0xd6, 0x97, 0xa8, 0x0a, 0x18, 0xf9, 0xc3, 0xc4, 0xa3,
|
||||
0x1e, 0x56, 0xe2, 0x7c, 0x83, 0x48, 0xdb, 0x16, 0x1a, 0x1c, 0xf5,
|
||||
0x1d, 0x7e, 0xf1, 0x94, 0x2d, 0x4b, 0xcf, 0x72, 0x22, 0xc1,
|
||||
};
|
||||
static const uint8_t kOrder[] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17,
|
||||
0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51,
|
||||
};
|
||||
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
|
||||
bssl::UniquePtr<BIGNUM> p(BN_bin2bn(kP, sizeof(kP), nullptr));
|
||||
bssl::UniquePtr<BIGNUM> a(BN_bin2bn(kA, sizeof(kA), nullptr));
|
||||
bssl::UniquePtr<BIGNUM> b(BN_bin2bn(kB, sizeof(kB), nullptr));
|
||||
bssl::UniquePtr<BIGNUM> x(BN_bin2bn(kX, sizeof(kX), nullptr));
|
||||
bssl::UniquePtr<BIGNUM> y(BN_bin2bn(kY, sizeof(kY), nullptr));
|
||||
bssl::UniquePtr<BIGNUM> order(BN_bin2bn(kOrder, sizeof(kOrder), nullptr));
|
||||
if (!ctx || !p || !a || !b || !x || !y || !order) {
|
||||
return nullptr;
|
||||
}
|
||||
bssl::UniquePtr<EC_GROUP> group(
|
||||
EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
|
||||
if (!group) {
|
||||
return nullptr;
|
||||
}
|
||||
bssl::UniquePtr<EC_POINT> generator(EC_POINT_new(group.get()));
|
||||
if (!generator ||
|
||||
!EC_POINT_set_affine_coordinates_GFp(group.get(), generator.get(),
|
||||
x.get(), y.get(), ctx.get()) ||
|
||||
!EC_GROUP_set_generator(group.get(), generator.get(), order.get(),
|
||||
BN_value_one())) {
|
||||
return nullptr;
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
TEST(ECDHTest, GroupMismatch) {
|
||||
const size_t num_curves = EC_get_builtin_curves(nullptr, 0);
|
||||
std::vector<EC_builtin_curve> curves(num_curves);
|
||||
EC_get_builtin_curves(curves.data(), num_curves);
|
||||
|
||||
// Instantiate all the built-in curves.
|
||||
std::vector<bssl::UniquePtr<EC_GROUP>> groups;
|
||||
for (const auto &curve : curves) {
|
||||
groups.emplace_back(EC_GROUP_new_by_curve_name(curve.nid));
|
||||
ASSERT_TRUE(groups.back());
|
||||
}
|
||||
|
||||
// Also create some arbitrary group. (This is P-256 with the wrong generator.)
|
||||
groups.push_back(MakeCustomGroup());
|
||||
ASSERT_TRUE(groups.back());
|
||||
|
||||
for (const auto &a : groups) {
|
||||
for (const auto &b : groups) {
|
||||
if (a.get() == b.get()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
|
||||
ASSERT_TRUE(EC_KEY_set_group(key.get(), a.get()));
|
||||
ASSERT_TRUE(EC_KEY_generate_key(key.get()));
|
||||
|
||||
// ECDH across the groups should not work.
|
||||
char out[64];
|
||||
const EC_POINT *peer = EC_GROUP_get0_generator(b.get());
|
||||
EXPECT_EQ(-1,
|
||||
ECDH_compute_key(out, sizeof(out), peer, key.get(), nullptr));
|
||||
ERR_clear_error();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,6 +73,13 @@ int ECDSA_sign(int type, const uint8_t *digest, size_t digest_len, uint8_t *sig,
|
||||
(EC_KEY*) eckey /* cast away const */);
|
||||
}
|
||||
|
||||
return ECDSA_sign_ex(type, digest, digest_len, sig, sig_len, NULL, NULL,
|
||||
eckey);
|
||||
}
|
||||
|
||||
int ECDSA_sign_ex(int type, const uint8_t *digest, size_t digest_len,
|
||||
uint8_t *sig, unsigned int *sig_len, const BIGNUM *kinv,
|
||||
const BIGNUM *r, const EC_KEY *eckey) {
|
||||
int ret = 0;
|
||||
ECDSA_SIG *s = NULL;
|
||||
|
||||
@@ -82,7 +89,7 @@ int ECDSA_sign(int type, const uint8_t *digest, size_t digest_len, uint8_t *sig,
|
||||
goto err;
|
||||
}
|
||||
|
||||
s = ECDSA_do_sign(digest, digest_len, eckey);
|
||||
s = ECDSA_do_sign_ex(digest, digest_len, kinv, r, eckey);
|
||||
if (s == NULL) {
|
||||
*sig_len = 0;
|
||||
goto err;
|
||||
|
||||
@@ -40,14 +40,14 @@ ASN1,138,ILLEGAL_TIME_VALUE
|
||||
ASN1,139,INTEGER_NOT_ASCII_FORMAT
|
||||
ASN1,140,INTEGER_TOO_LARGE_FOR_LONG
|
||||
ASN1,141,INVALID_BIT_STRING_BITS_LEFT
|
||||
ASN1,142,INVALID_BMPSTRING
|
||||
ASN1,142,INVALID_BMPSTRING_LENGTH
|
||||
ASN1,143,INVALID_DIGIT
|
||||
ASN1,144,INVALID_MODIFIER
|
||||
ASN1,145,INVALID_NUMBER
|
||||
ASN1,146,INVALID_OBJECT_ENCODING
|
||||
ASN1,147,INVALID_SEPARATOR
|
||||
ASN1,148,INVALID_TIME_FORMAT
|
||||
ASN1,149,INVALID_UNIVERSALSTRING
|
||||
ASN1,149,INVALID_UNIVERSALSTRING_LENGTH
|
||||
ASN1,150,INVALID_UTF8STRING
|
||||
ASN1,151,LIST_ERROR
|
||||
ASN1,152,MISSING_ASN1_EOS
|
||||
@@ -58,7 +58,6 @@ ASN1,156,MSTRING_NOT_UNIVERSAL
|
||||
ASN1,157,MSTRING_WRONG_TAG
|
||||
ASN1,158,NESTED_ASN1_ERROR
|
||||
ASN1,159,NESTED_ASN1_STRING
|
||||
ASN1,192,NESTED_TOO_DEEP
|
||||
ASN1,160,NON_HEX_CHARACTERS
|
||||
ASN1,161,NOT_ASCII_FORMAT
|
||||
ASN1,162,NOT_ENOUGH_DATA
|
||||
|
||||
@@ -17,7 +17,6 @@ EC,110,INVALID_FIELD
|
||||
EC,111,INVALID_FORM
|
||||
EC,112,INVALID_GROUP_ORDER
|
||||
EC,113,INVALID_PRIVATE_KEY
|
||||
EC,133,INVALID_SCALAR
|
||||
EC,114,MISSING_PARAMETERS
|
||||
EC,115,MISSING_PRIVATE_KEY
|
||||
EC,116,NON_NAMED_CURVE
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user