Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1b5bcb59f4 | |||
| b69307a1c4 |
@@ -2,10 +2,3 @@ BasedOnStyle: Google
|
||||
MaxEmptyLinesToKeep: 3
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Right
|
||||
# TODO(davidben): The default for Google style is now Regroup, but the default
|
||||
# IncludeCategories does not recognize <openssl/header.h>. We should
|
||||
# reconfigure IncludeCategories to match. For now, keep it at Preserve.
|
||||
IncludeBlocks: Preserve
|
||||
|
||||
|
||||
-26
@@ -1,32 +1,6 @@
|
||||
build/
|
||||
build32/
|
||||
build64/
|
||||
ssl/test/runner/runner
|
||||
*.pyc
|
||||
*.swp
|
||||
*.swo
|
||||
doc/*.html
|
||||
doc/doc.css
|
||||
|
||||
util/bot/android_ndk
|
||||
util/bot/android_sdk/public
|
||||
util/bot/cmake-linux64
|
||||
util/bot/cmake-linux64.tar.gz
|
||||
util/bot/cmake-mac
|
||||
util/bot/cmake-mac.tar.gz
|
||||
util/bot/cmake-win32
|
||||
util/bot/cmake-win32.zip
|
||||
util/bot/golang
|
||||
util/bot/gyp
|
||||
util/bot/libcxx
|
||||
util/bot/libcxxabi
|
||||
util/bot/llvm-build
|
||||
util/bot/nasm-win32.exe
|
||||
util/bot/perl-win32
|
||||
util/bot/perl-win32.zip
|
||||
util/bot/sde-linux64
|
||||
util/bot/sde-linux64.tar.bz2
|
||||
util/bot/sde-win32
|
||||
util/bot/sde-win32.tar.bz2
|
||||
util/bot/win_toolchain.json
|
||||
util/bot/yasm-win32.exe
|
||||
|
||||
@@ -1,248 +0,0 @@
|
||||
# BoringSSL API Conventions
|
||||
|
||||
This document describes conventions for BoringSSL APIs. The [style
|
||||
guide](/STYLE.md) also includes guidelines, but this document is targeted at
|
||||
both API consumers and developers.
|
||||
|
||||
|
||||
## Documentation
|
||||
|
||||
All supported public APIs are documented in the public header files, found in
|
||||
`include/openssl`. The API documentation is also available
|
||||
[online](https://commondatastorage.googleapis.com/chromium-boringssl-docs/headers.html).
|
||||
|
||||
Some headers lack documention comments. These are functions and structures from
|
||||
OpenSSL's legacy ASN.1, X.509, and PEM implementation. If possible, avoid using
|
||||
them. These are left largely unmodified from upstream and are retained only for
|
||||
compatibility with existing OpenSSL consumers.
|
||||
|
||||
|
||||
## Forward declarations
|
||||
|
||||
Do not write `typedef struct foo_st FOO` or try otherwise to define BoringSSL's
|
||||
types. Including `openssl/base.h` (or `openssl/ossl_typ.h` for consumers who
|
||||
wish to be OpenSSL-compatible) will forward-declare each type without importing
|
||||
the rest of the library or invasive macros.
|
||||
|
||||
|
||||
## Error-handling
|
||||
|
||||
Most functions in BoringSSL may fail, either due to allocation failures or input
|
||||
errors. Functions which return an `int` typically return one on success and zero
|
||||
on failure. Functions which return a pointer typically return `NULL` on failure.
|
||||
However, due to legacy constraints, some functions are more complex. Consult the
|
||||
API documentation before using a function.
|
||||
|
||||
On error, most functions also push errors on the error queue, an `errno`-like
|
||||
mechanism. See the documentation for
|
||||
[err.h](https://commondatastorage.googleapis.com/chromium-boringssl-docs/err.h.html)
|
||||
for more details.
|
||||
|
||||
As with `errno`, callers must test the function's return value, not the error
|
||||
queue to determine whether an operation failed. Some codepaths may not interact
|
||||
with the error queue, and the error queue may have state from a previous failed
|
||||
operation.
|
||||
|
||||
When ignoring a failed operation, it is recommended to call `ERR_clear_error` to
|
||||
avoid the state interacting with future operations. Failing to do so should not
|
||||
affect the actual behavior of any functions, but may result in errors from both
|
||||
operations being mixed in error logging. We hope to
|
||||
[improve](https://bugs.chromium.org/p/boringssl/issues/detail?id=38) this
|
||||
situation in the future.
|
||||
|
||||
Where possible, avoid conditioning on specific reason codes and limit usage to
|
||||
logging. The reason codes are very specific and may change over time.
|
||||
|
||||
|
||||
## Memory allocation
|
||||
|
||||
BoringSSL allocates memory via `OPENSSL_malloc`, found in `mem.h`. Use
|
||||
`OPENSSL_free`, found in the same header file, to release it. BoringSSL
|
||||
functions will fail gracefully on allocation error, but it is recommended to use
|
||||
a `malloc` implementation that `abort`s on failure.
|
||||
|
||||
|
||||
## Object initialization and cleanup
|
||||
|
||||
BoringSSL defines a number of structs for use in its APIs. It is a C library,
|
||||
so the caller is responsible for ensuring these structs are properly
|
||||
initialized and released. Consult the documentation for a module for the
|
||||
proper use of its types. Some general conventions are listed below.
|
||||
|
||||
|
||||
### Heap-allocated types
|
||||
|
||||
Some types, such as `RSA`, are heap-allocated. All instances will be allocated
|
||||
and returned from BoringSSL's APIs. It is an error to instantiate a heap-
|
||||
allocated type on the stack or embedded within another object.
|
||||
|
||||
Heap-allocated types may have functioned named like `RSA_new` which allocates a
|
||||
fresh blank `RSA`. Other functions may also return newly-allocated instances.
|
||||
For example, `RSA_parse_public_key` is documented to return a newly-allocated
|
||||
`RSA` object.
|
||||
|
||||
Heap-allocated objects must be released by the corresponding free function,
|
||||
named like `RSA_free`. Like C's `free` and C++'s `delete`, all free functions
|
||||
internally check for `NULL`. Consumers are not required to check for `NULL`
|
||||
before calling.
|
||||
|
||||
A heap-allocated type may be reference-counted. In this case, a function named
|
||||
like `RSA_up_ref` will be available to take an additional reference count. The
|
||||
free function must be called to decrement the reference count. It will only
|
||||
release resources when the final reference is released. For OpenSSL
|
||||
compatibility, these functions return `int`, but callers may assume they always
|
||||
successfully return one because reference counts use saturating arithmetic.
|
||||
|
||||
C++ consumers are recommended to use `bssl::UniquePtr` to manage heap-allocated
|
||||
objects. `bssl::UniquePtr<T>`, like other types, is forward-declared in
|
||||
`openssl/base.h`. Code that needs access to the free functions, such as code
|
||||
which destroys a `bssl::UniquePtr`, must include the corresponding module's
|
||||
header. (This matches `std::unique_ptr`'s relationship with forward
|
||||
declarations.) Note, despite the name, `bssl::UniquePtr` is also used with
|
||||
reference-counted types. It owns a single reference to the object. To take an
|
||||
additional reference, use the `bssl::UpRef` function, which will return a
|
||||
separate `bssl::UniquePtr`.
|
||||
|
||||
|
||||
### Stack-allocated types
|
||||
|
||||
Other types in BoringSSL are stack-allocated, such as `EVP_MD_CTX`. These
|
||||
types may be allocated on the stack or embedded within another object.
|
||||
However, they must still be initialized before use.
|
||||
|
||||
Every stack-allocated object in BoringSSL has a *zero state*, analogous to
|
||||
initializing a pointer to `NULL`. In this state, the object may not be
|
||||
completely initialized, but it is safe to call cleanup functions. Entering the
|
||||
zero state cannot fail. (It is usually `memset(0)`.)
|
||||
|
||||
The function to enter the zero state is named like `EVP_MD_CTX_init` or
|
||||
`CBB_zero` and will always return `void`. To release resources associated with
|
||||
the type, call the cleanup function, named like `EVP_MD_CTX_cleanup`. The
|
||||
cleanup function must be called on all codepaths, regardless of success or
|
||||
failure. For example:
|
||||
|
||||
uint8_t md[EVP_MAX_MD_SIZE];
|
||||
unsigned md_len;
|
||||
EVP_MD_CTX ctx;
|
||||
EVP_MD_CTX_init(&ctx); /* Enter the zero state. */
|
||||
int ok = EVP_DigestInit_ex(&ctx, EVP_sha256(), NULL) &&
|
||||
EVP_DigestUpdate(&ctx, "hello ", 6) &&
|
||||
EVP_DigestUpdate(&ctx, "world", 5) &&
|
||||
EVP_DigestFinal_ex(&ctx, md, &md_len);
|
||||
EVP_MD_CTX_cleanup(&ctx); /* Release |ctx|. */
|
||||
|
||||
Note that `EVP_MD_CTX_cleanup` is called whether or not the `EVP_Digest*`
|
||||
operations succeeded. More complex C functions may use the `goto err` pattern:
|
||||
|
||||
int ret = 0;
|
||||
EVP_MD_CTX ctx;
|
||||
EVP_MD_CTX_init(&ctx);
|
||||
|
||||
if (!some_other_operation()) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
uint8_t md[EVP_MAX_MD_SIZE];
|
||||
unsigned md_len;
|
||||
if (!EVP_DigestInit_ex(&ctx, EVP_sha256(), NULL) ||
|
||||
!EVP_DigestUpdate(&ctx, "hello ", 6) ||
|
||||
!EVP_DigestUpdate(&ctx, "world", 5) ||
|
||||
!EVP_DigestFinal_ex(&ctx, md, &md_len) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
EVP_MD_CTX_cleanup(&ctx);
|
||||
return ret;
|
||||
|
||||
Note that, because `ctx` is set to the zero state before any failures,
|
||||
`EVP_MD_CTX_cleanup` is safe to call even if the first operation fails before
|
||||
`EVP_DigestInit_ex`. However, it would be illegal to move the `EVP_MD_CTX_init`
|
||||
below the `some_other_operation` call.
|
||||
|
||||
As a rule of thumb, enter the zero state of stack-allocated structs in the
|
||||
same place they are declared.
|
||||
|
||||
C++ consumers are recommended to use the wrappers named like
|
||||
`bssl::ScopedEVP_MD_CTX`, defined in the corresponding module's header. These
|
||||
wrappers are automatically initialized to the zero state and are automatically
|
||||
cleaned up.
|
||||
|
||||
|
||||
### Data-only types
|
||||
|
||||
A few types, such as `SHA_CTX`, are data-only types and do not require cleanup.
|
||||
These are usually for low-level cryptographic operations. These types may be
|
||||
used freely without special cleanup conventions.
|
||||
|
||||
|
||||
### Ownership and lifetime
|
||||
|
||||
When working with allocated objects, it is important to think about *ownership*
|
||||
of each object, or what code is responsible for releasing it. This matches the
|
||||
corresponding notion in higher-level languages like C++ and Rust.
|
||||
|
||||
Ownership applies to both uniquely-owned types and reference-counted types. For
|
||||
the latter, ownership means the code is responsible for releasing one
|
||||
reference. Note a *reference* in BoringSSL refers to an increment (and eventual
|
||||
decrement) of an object's reference count, not `T&` in C++. Thus, to "take a
|
||||
reference" means to increment the reference count and take ownership of
|
||||
decrementing it.
|
||||
|
||||
As BoringSSL's APIs are primarily in C, ownership and lifetime obligations are
|
||||
not rigorously annotated in the type signatures or checked at compile-time.
|
||||
Instead, they are described in
|
||||
[API documentation](https://commondatastorage.googleapis.com/chromium-boringssl-docs/headers.html).
|
||||
This section describes some conventions.
|
||||
|
||||
Unless otherwise documented, functions do not take ownership of pointer
|
||||
arguments. The pointer typically must remain valid for the duration of the
|
||||
function call. The function may internally copy information from the argument or
|
||||
take a reference, but the caller is free to release its copy or reference at any
|
||||
point after the call completes.
|
||||
|
||||
A function may instead be documented to *take* or *transfer* ownership of a
|
||||
pointer. The caller must own the object before the function call and, after
|
||||
transfer, no longer owns it. As a corollary, the caller may no longer reference
|
||||
the object without a separate guarantee on the lifetime. The function may even
|
||||
release the object before returning. Callers that wish to independently retain a
|
||||
transfered object must therefore take a reference or make a copy before
|
||||
transferring. Callers should also take note of whether the function is
|
||||
documented to transfer pointers unconditionally or only on success. Unlike C++
|
||||
and Rust, functions in BoringSSL typically only transfer on success.
|
||||
|
||||
Likewise, output pointers may be owning or non-owning. Unless otherwise
|
||||
documented, functions output non-owning pointers. The caller is not responsible
|
||||
for releasing the output pointer, but it must not use the pointer beyond its
|
||||
lifetime. The pointer may be released when the parent object is released or even
|
||||
sooner on state change in the parent object.
|
||||
|
||||
If documented to output a *newly-allocated* object or a *reference* or *copy* of
|
||||
one, the caller is responsible for releasing the object when it is done.
|
||||
|
||||
By convention, functions named `get0` return non-owning pointers. Functions
|
||||
named `new` or `get1` return owning pointers. Functions named `set0` take
|
||||
ownership of arguments. Functions named `set1` do not. They typically take a
|
||||
reference or make a copy internally. These names originally referred to the
|
||||
effect on a reference count, but the convention applies equally to
|
||||
non-reference-counted types.
|
||||
|
||||
API documentation may also describe more complex obligations. For instance, an
|
||||
object may borrow a pointer for longer than the duration of a single function
|
||||
call, in which case the caller must ensure the lifetime extends accordingly.
|
||||
|
||||
Memory errors are one of the most common and dangerous bugs in C and C++, so
|
||||
callers are encouraged to make use of tools such as
|
||||
[AddressSanitizer](https://clang.llvm.org/docs/AddressSanitizer.html) and
|
||||
higher-level languages.
|
||||
|
||||
|
||||
## Thread safety
|
||||
|
||||
BoringSSL is internally aware of the platform threading library and calls into
|
||||
it as needed. Consult the API documentation for the threading guarantees of
|
||||
particular objects. In general, stateless reference-counted objects like `RSA`
|
||||
or `EVP_PKEY` which represent keys may typically be used from multiple threads
|
||||
simultaneously, provided no thread mutates the key.
|
||||
@@ -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.
|
||||
+33
-105
@@ -2,17 +2,9 @@
|
||||
|
||||
## Build Prerequisites
|
||||
|
||||
The standalone CMake build is primarily intended for developers. If embedding
|
||||
BoringSSL into another project with a pre-existing build system, see
|
||||
[INCORPORATING.md](/INCORPORATING.md).
|
||||
* [CMake](https://cmake.org/download/) 2.8.8 or later is required.
|
||||
|
||||
Unless otherwise noted, build tools must at most five years old, matching
|
||||
[Abseil guidelines](https://abseil.io/about/compatibility). If in doubt, use the
|
||||
most recent stable version of each tool.
|
||||
|
||||
* [CMake](https://cmake.org/download/) 3.0 or later is required.
|
||||
|
||||
* A recent version of Perl is required. On Windows,
|
||||
* Perl 5.6.1 or later is required. On Windows,
|
||||
[Active State Perl](http://www.activestate.com/activeperl/) has been
|
||||
reported to work, as has MSYS Perl.
|
||||
[Strawberry Perl](http://strawberryperl.com/) also works but it adds GCC
|
||||
@@ -21,27 +13,23 @@ most recent stable version of each tool.
|
||||
If Perl is not found by CMake, it may be configured explicitly by setting
|
||||
`PERL_EXECUTABLE`.
|
||||
|
||||
* Building with [Ninja](https://ninja-build.org/) instead of Make is
|
||||
recommended, because it makes builds faster. On Windows, CMake's Visual
|
||||
Studio generator may also work, but it not tested regularly and requires
|
||||
recent versions of CMake for assembly support.
|
||||
* On Windows you currently must use [Ninja](https://ninja-build.org/)
|
||||
to build; on other platforms, it is not required, but recommended, because
|
||||
it makes builds faster.
|
||||
|
||||
* On Windows only, [NASM](https://www.nasm.us/) is required. If not found
|
||||
* If you need to build Ninja from source, then a recent version of
|
||||
[Python](https://www.python.org/downloads/) is required (Python 2.7.5 works).
|
||||
|
||||
* On Windows only, [Yasm](http://yasm.tortall.net/) is required. If not found
|
||||
by CMake, it may be configured explicitly by setting
|
||||
`CMAKE_ASM_NASM_COMPILER`.
|
||||
|
||||
* C and C++ compilers with C++11 support are required. On Windows, MSVC 14
|
||||
(Visual Studio 2015) or later with Platform SDK 8.1 or later are supported.
|
||||
Recent versions of GCC (4.8+) and Clang should work on non-Windows
|
||||
platforms, and maybe on Windows too.
|
||||
* A C compiler is required. On Windows, MSVC 12 (Visual Studio 2013) or later
|
||||
with Platform SDK 8.1 or later are supported. Recent versions of GCC (4.8+)
|
||||
and Clang should work on non-Windows platforms, and maybe on Windows too.
|
||||
|
||||
* The most recent stable version of [Go](https://golang.org/dl/) is required.
|
||||
Note Go is exempt from the five year support window. If not found by CMake,
|
||||
the go executable may be configured explicitly by setting `GO_EXECUTABLE`.
|
||||
|
||||
* On x86_64 Linux, the tests have an optional
|
||||
[libunwind](https://www.nongnu.org/libunwind/) dependency to test the
|
||||
assembly more thoroughly.
|
||||
* [Go](https://golang.org/dl/) is required. If not found by CMake, the go
|
||||
executable may be configured explicitly by setting `GO_EXECUTABLE`.
|
||||
|
||||
## Building
|
||||
|
||||
@@ -87,73 +75,22 @@ 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:
|
||||
directory. Clone https://github.com/taka-no-me/android-cmake into `util/`. Then
|
||||
make a build directory as above and run CMake *twice* like this:
|
||||
|
||||
cmake -DANDROID_ABI=armeabi-v7a \
|
||||
-DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake \
|
||||
cmake -DANDROID_NATIVE_API_LEVEL=android-9 \
|
||||
-DANDROID_ABI=armeabi-v7a \
|
||||
-DCMAKE_TOOLCHAIN_FILE=../util/android-cmake/android.toolchain.cmake \
|
||||
-DANDROID_NATIVE_API_LEVEL=16 \
|
||||
-GNinja ..
|
||||
|
||||
Once you've run that, Ninja should produce Android-compatible binaries. You
|
||||
can replace `armeabi-v7a` in the above with `arm64-v8a` and use API level 21 or
|
||||
higher to build aarch64 binaries.
|
||||
|
||||
For other options, see the documentation in the toolchain file.
|
||||
|
||||
To debug the resulting binaries on an Android device with `gdb`, run the
|
||||
commands below. Replace `ARCH` with the architecture of the target device, e.g.
|
||||
`arm` or `arm64`.
|
||||
|
||||
adb push ${ANDROID_NDK}/prebuilt/android-ARCH/gdbserver/gdbserver \
|
||||
/data/local/tmp
|
||||
adb forward tcp:5039 tcp:5039
|
||||
adb shell /data/local/tmp/gdbserver :5039 /path/on/device/to/binary
|
||||
|
||||
Then run the following in a separate shell. Replace `HOST` with the OS and
|
||||
architecture of the host machine, e.g. `linux-x86_64`.
|
||||
|
||||
${ANDROID_NDK}/prebuilt/HOST/bin/gdb
|
||||
target remote :5039 # in gdb
|
||||
|
||||
### Building for iOS
|
||||
|
||||
To build for iOS, pass `-DCMAKE_OSX_SYSROOT=iphoneos` and
|
||||
`-DCMAKE_OSX_ARCHITECTURES=ARCH` to CMake, where `ARCH` is the desired
|
||||
architecture, matching values used in the `-arch` flag in Apple's toolchain.
|
||||
|
||||
Passing multiple architectures for a multiple-architecture build is not
|
||||
supported.
|
||||
|
||||
### Building with Prefixed Symbols
|
||||
|
||||
BoringSSL's build system has experimental support for adding a custom prefix to
|
||||
all symbols. This can be useful when linking multiple versions of BoringSSL in
|
||||
the same project to avoid symbol conflicts.
|
||||
|
||||
In order to build with prefixed symbols, the `BORINGSSL_PREFIX` CMake variable
|
||||
should specify the prefix to add to all symbols, and the
|
||||
`BORINGSSL_PREFIX_SYMBOLS` CMake variable should specify the path to a file
|
||||
which contains a list of symbols which should be prefixed (one per line;
|
||||
comments are supported with `#`). In other words, `cmake ..
|
||||
-DBORINGSSL_PREFIX=MY_CUSTOM_PREFIX
|
||||
-DBORINGSSL_PREFIX_SYMBOLS=/path/to/symbols.txt` will configure the build to add
|
||||
the prefix `MY_CUSTOM_PREFIX` to all of the symbols listed in
|
||||
`/path/to/symbols.txt`.
|
||||
|
||||
It is currently the caller's responsibility to create and maintain the list of
|
||||
symbols to be prefixed. Alternatively, `util/read_symbols.go` reads the list of
|
||||
exported symbols from a `.a` file, and can be used in a build script to generate
|
||||
the symbol list on the fly (by building without prefixing, using
|
||||
`read_symbols.go` to construct a symbol list, and then building again with
|
||||
prefixing).
|
||||
|
||||
This mechanism is under development and may change over time. Please contact the
|
||||
BoringSSL maintainers if making use of it.
|
||||
Once you've run that twice, Ninja should produce Android-compatible binaries.
|
||||
You can replace `armeabi-v7a` in the above with `arm64-v8a` to build aarch64
|
||||
binaries.
|
||||
|
||||
## Known Limitations on Windows
|
||||
|
||||
@@ -175,18 +112,16 @@ ARM, unlike Intel, does not have an instruction that allows applications to
|
||||
discover the capabilities of the processor. Instead, the capability information
|
||||
has to be provided by the operating system somehow.
|
||||
|
||||
By default, on Linux-based systems, BoringSSL will try to use `getauxval` and
|
||||
`/proc` to discover the capabilities. But some environments don't support that
|
||||
sort of thing and, for them, it's possible to configure the CPU capabilities at
|
||||
compile time.
|
||||
BoringSSL will try to use `getauxval` to discover the capabilities and, failing
|
||||
that, will probe for NEON support by executing a NEON instruction and handling
|
||||
any illegal-instruction signal. But some environments don't support that sort
|
||||
of thing and, for them, it's possible to configure the CPU capabilities
|
||||
at compile time.
|
||||
|
||||
On iOS or builds which define `OPENSSL_STATIC_ARMCAP`, features will be
|
||||
determined based on the `__ARM_NEON__` and `__ARM_FEATURE_CRYPTO` preprocessor
|
||||
symbols reported by the compiler. These values are usually controlled by the
|
||||
`-march` flag. You can also define any of the following to enable the
|
||||
corresponding ARM feature.
|
||||
If you define `OPENSSL_STATIC_ARMCAP` then you can define any of the following
|
||||
to enabling the corresponding ARM feature.
|
||||
|
||||
* `OPENSSL_STATIC_ARMCAP_NEON`
|
||||
* `OPENSSL_STATIC_ARMCAP_NEON` or `__ARM_NEON__` (note that the latter is set by compilers when NEON support is enabled).
|
||||
* `OPENSSL_STATIC_ARMCAP_AES`
|
||||
* `OPENSSL_STATIC_ARMCAP_SHA1`
|
||||
* `OPENSSL_STATIC_ARMCAP_SHA256`
|
||||
@@ -195,14 +130,7 @@ 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
|
||||
|
||||
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.
|
||||
|
||||
# Running Tests
|
||||
# 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
|
||||
|
||||
+79
-500
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.3)
|
||||
cmake_minimum_required (VERSION 2.8.10)
|
||||
|
||||
# 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
|
||||
@@ -9,190 +9,39 @@ if(WIN32)
|
||||
set(CMAKE_GENERATOR_CC cl)
|
||||
endif()
|
||||
|
||||
include(sources.cmake)
|
||||
|
||||
enable_language(C)
|
||||
enable_language(CXX)
|
||||
|
||||
# This is a dummy target which all other targets depend on (manually - see other
|
||||
# CMakeLists.txt files). This gives us a hook to add any targets which need to
|
||||
# run before all other targets.
|
||||
add_custom_target(global_target)
|
||||
|
||||
if(ANDROID)
|
||||
# Android-NDK CMake files reconfigure the path and so Go and Perl won't be
|
||||
# found. However, ninja will still find them in $PATH if we just name them.
|
||||
if(NOT PERL_EXECUTABLE)
|
||||
set(PERL_EXECUTABLE "perl")
|
||||
endif()
|
||||
if(NOT GO_EXECUTABLE)
|
||||
set(GO_EXECUTABLE "go")
|
||||
endif()
|
||||
set(PERL_EXECUTABLE "perl")
|
||||
set(GO_EXECUTABLE "go")
|
||||
else()
|
||||
find_package(Perl REQUIRED)
|
||||
find_program(GO_EXECUTABLE go)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND NOT CMAKE_CROSSCOMPILING)
|
||||
find_package(PkgConfig QUIET)
|
||||
if (PkgConfig_FOUND)
|
||||
pkg_check_modules(LIBUNWIND libunwind-generic)
|
||||
if(LIBUNWIND_FOUND)
|
||||
add_definitions(-DBORINGSSL_HAVE_LIBUNWIND)
|
||||
else()
|
||||
message("libunwind not found. Disabling unwind tests.")
|
||||
endif()
|
||||
else()
|
||||
message("pkgconfig not found. Disabling unwind tests.")
|
||||
endif()
|
||||
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)
|
||||
add_definitions(-DBORINGSSL_ALLOW_CXX_RUNTIME)
|
||||
endif()
|
||||
|
||||
string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LOWER)
|
||||
if(NOT FIPS)
|
||||
if(CMAKE_BUILD_TYPE_LOWER STREQUAL "relwithassert" OR
|
||||
NOT CMAKE_BUILD_TYPE_LOWER MATCHES "rel")
|
||||
add_definitions(-DBORINGSSL_DISPATCH_TEST)
|
||||
# CMake automatically connects include_directories to the NASM
|
||||
# command-line, but not add_definitions.
|
||||
set(CMAKE_ASM_NASM_FLAGS "${CMAKE_ASM_NASM_FLAGS} -DBORINGSSL_DISPATCH_TEST")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Add a RelWithAsserts build configuration. It is the same as Release, except it
|
||||
# does not define NDEBUG, so asserts run.
|
||||
foreach(VAR CMAKE_C_FLAGS CMAKE_CXX_FLAGS CMAKE_ASM_FLAGS)
|
||||
string(REGEX REPLACE "(^| )[/-]DNDEBUG( |$)" " " "${VAR}_RELWITHASSERTS"
|
||||
"${${VAR}_RELEASE}")
|
||||
endforeach()
|
||||
|
||||
if(BORINGSSL_PREFIX AND BORINGSSL_PREFIX_SYMBOLS)
|
||||
add_definitions(-DBORINGSSL_PREFIX=${BORINGSSL_PREFIX})
|
||||
# CMake automatically connects include_directories to the NASM command-line,
|
||||
# but not add_definitions.
|
||||
set(CMAKE_ASM_NASM_FLAGS "${CMAKE_ASM_NASM_FLAGS} -DBORINGSSL_PREFIX=${BORINGSSL_PREFIX}")
|
||||
|
||||
# Use "symbol_prefix_include" to store generated header files
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR}/symbol_prefix_include)
|
||||
add_custom_command(
|
||||
OUTPUT symbol_prefix_include/boringssl_prefix_symbols.h
|
||||
symbol_prefix_include/boringssl_prefix_symbols_asm.h
|
||||
symbol_prefix_include/boringssl_prefix_symbols_nasm.inc
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/symbol_prefix_include
|
||||
COMMAND ${GO_EXECUTABLE} run ${CMAKE_CURRENT_SOURCE_DIR}/util/make_prefix_headers.go -out ${CMAKE_CURRENT_BINARY_DIR}/symbol_prefix_include ${BORINGSSL_PREFIX_SYMBOLS}
|
||||
DEPENDS util/make_prefix_headers.go
|
||||
${CMAKE_BINARY_DIR}/${BORINGSSL_PREFIX_SYMBOLS})
|
||||
|
||||
# add_dependencies needs a target, not a file, so we add an intermediate
|
||||
# target.
|
||||
add_custom_target(
|
||||
boringssl_prefix_symbols
|
||||
DEPENDS symbol_prefix_include/boringssl_prefix_symbols.h
|
||||
symbol_prefix_include/boringssl_prefix_symbols_asm.h
|
||||
symbol_prefix_include/boringssl_prefix_symbols_nasm.inc)
|
||||
add_dependencies(global_target boringssl_prefix_symbols)
|
||||
elseif(BORINGSSL_PREFIX OR BORINGSSL_PREFIX_SYMBOLS)
|
||||
message(FATAL_ERROR "Must specify both or neither of BORINGSSL_PREFIX and BORINGSSL_PREFIX_SYMBOLS")
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CLANG 1)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
|
||||
set(EMSCRIPTEN 1)
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CLANG)
|
||||
# Note clang-cl is odd and sets both CLANG and MSVC. We base our configuration
|
||||
# primarily on our normal Clang one.
|
||||
set(C_CXX_FLAGS "-Werror -Wformat=2 -Wsign-compare -Wmissing-field-initializers -Wwrite-strings -Wvla")
|
||||
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")
|
||||
# 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()
|
||||
if(EMSCRIPTEN)
|
||||
# emscripten's emcc/clang does not accept the "-ggdb" flag.
|
||||
set(C_CXX_FLAGS "${C_CXX_FLAGS} -g")
|
||||
else()
|
||||
set(C_CXX_FLAGS "${C_CXX_FLAGS} -ggdb")
|
||||
endif()
|
||||
|
||||
set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wall -fvisibility=hidden -fno-common")
|
||||
endif()
|
||||
|
||||
if(CLANG)
|
||||
set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wnewline-eof -fcolor-diagnostics")
|
||||
else()
|
||||
# GCC (at least 4.8.4) has a bug where it'll find unreachable free() calls
|
||||
# and declare that the code is trying to free a stack pointer.
|
||||
set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wno-free-nonheap-object")
|
||||
endif()
|
||||
|
||||
if(CLANG OR NOT "7.0.0" VERSION_GREATER CMAKE_C_COMPILER_VERSION)
|
||||
set(C_CXX_FLAGS "${C_CXX_FLAGS} -Wimplicit-fallthrough")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${C_CXX_FLAGS} -Wmissing-prototypes -Wold-style-definition -Wstrict-prototypes")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${C_CXX_FLAGS} -Wmissing-declarations")
|
||||
|
||||
if(NOT MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
if(APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
||||
endif()
|
||||
if(NOT BORINGSSL_ALLOW_CXX_RUNTIME)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions -fno-rtti")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# In GCC, -Wmissing-declarations is the C++ spelling of -Wmissing-prototypes
|
||||
# and using the wrong one is an error. In Clang, -Wmissing-prototypes is the
|
||||
# spelling for both and -Wmissing-declarations is some other warning.
|
||||
#
|
||||
# https://gcc.gnu.org/onlinedocs/gcc-7.1.0/gcc/Warning-Options.html#Warning-Options
|
||||
# https://clang.llvm.org/docs/DiagnosticsReference.html#wmissing-prototypes
|
||||
# https://clang.llvm.org/docs/DiagnosticsReference.html#wmissing-declarations
|
||||
if(CLANG)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wmissing-prototypes")
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX AND "4.8" VERSION_GREATER CMAKE_C_COMPILER_VERSION)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-array-bounds")
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(C_CXX_FLAGS "-Wall -Werror -Wformat=2 -Wsign-compare -Wmissing-field-initializers -ggdb -fvisibility=hidden")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${C_CXX_FLAGS} -Wmissing-prototypes")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x ${C_CXX_FLAGS} -Wmissing-declarations")
|
||||
elseif(MSVC)
|
||||
set(MSVC_DISABLED_WARNINGS_LIST
|
||||
"C4061" # enumerator 'identifier' in switch of enum 'enumeration' is not
|
||||
# explicitly handled by a case label
|
||||
# Disable this because it flags even when there is a default.
|
||||
"C4100" # 'exarg' : unreferenced formal parameter
|
||||
"C4127" # conditional expression is constant
|
||||
"C4200" # nonstandard extension used : zero-sized array in
|
||||
# struct/union.
|
||||
"C4204" # nonstandard extension used: non-constant aggregate initializer
|
||||
"C4221" # nonstandard extension used : 'identifier' : cannot be
|
||||
# initialized using address of automatic variable
|
||||
"C4242" # 'function' : conversion from 'int' to 'uint8_t',
|
||||
# possible loss of data
|
||||
"C4244" # 'function' : conversion from 'int' to 'uint8_t',
|
||||
# possible loss of data
|
||||
"C4245" # 'initializing' : conversion from 'long' to
|
||||
# 'unsigned long', signed/unsigned mismatch
|
||||
"C4267" # conversion from 'size_t' to 'int', possible loss of data
|
||||
"C4371" # layout of class may have changed from a previous version of the
|
||||
# compiler due to better packing of member '...'
|
||||
@@ -202,7 +51,6 @@ elseif(MSVC)
|
||||
"C4365" # '=' : conversion from 'size_t' to 'int',
|
||||
# signed/unsigned mismatch
|
||||
"C4389" # '!=' : signed/unsigned mismatch
|
||||
"C4464" # relative include path contains '..'
|
||||
"C4510" # 'argument' : default constructor could not be generated
|
||||
"C4512" # 'argument' : assignment operator could not be generated
|
||||
"C4514" # 'function': unreferenced inline function has been removed
|
||||
@@ -210,420 +58,151 @@ elseif(MSVC)
|
||||
# side-effect" caused by FD_* macros.
|
||||
"C4610" # struct 'argument' can never be instantiated - user defined
|
||||
# constructor required.
|
||||
"C4623" # default constructor was implicitly defined as deleted
|
||||
"C4625" # copy constructor could not be generated because a base class
|
||||
# copy constructor is inaccessible or deleted
|
||||
"C4626" # assignment operator could not be generated because a base class
|
||||
# assignment operator is inaccessible or deleted
|
||||
"C4628" # digraphs not supported with -Ze
|
||||
"C4668" # 'symbol' is not defined as a preprocessor macro, replacing with
|
||||
# '0' for 'directives'
|
||||
# Disable this because GTest uses it everywhere.
|
||||
"C4706" # assignment within conditional expression
|
||||
"C4710" # 'function': function not inlined
|
||||
"C4711" # function 'function' selected for inline expansion
|
||||
"C4800" # 'int' : forcing value to bool 'true' or 'false'
|
||||
# (performance warning)
|
||||
"C4820" # 'bytes' bytes padding added after construct 'member_name'
|
||||
"C5026" # move constructor was implicitly defined as deleted
|
||||
"C5027" # move assignment operator was implicitly defined as deleted
|
||||
"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
|
||||
"C4265" # class has virtual functions, but destructor is not virtual
|
||||
)
|
||||
"C4996" # 'read': The POSIX name for this item is deprecated. Instead,
|
||||
# use the ISO C++ conformant name: _read.
|
||||
)
|
||||
if(NOT(CMAKE_C_COMPILER_VERSION VERSION_LESS "19.0.23506"))
|
||||
# MSVC 2015 Update 1.
|
||||
set(MSVC_DISABLED_WARNINGS_LIST
|
||||
${MSVC_DISABLED_WARNINGS_LIST}
|
||||
"C4464" # relative include path contains '..'
|
||||
"C4623" # default constructor was implicitly defined as deleted
|
||||
"C5027" # move assignment operator was implicitly defined as deleted
|
||||
)
|
||||
set(MSVC_LEVEL4_WARNINGS_LIST
|
||||
# See https://connect.microsoft.com/VisualStudio/feedback/details/1217660/warning-c4265-when-using-functional-header
|
||||
"C4265" # class has virtual functions, but destructor is not virtual
|
||||
)
|
||||
string(REPLACE "C" " -w4" MSVC_LEVEL4_WARNINGS_STR
|
||||
${MSVC_LEVEL4_WARNINGS_LIST})
|
||||
endif()
|
||||
string(REPLACE "C" " -wd" MSVC_DISABLED_WARNINGS_STR
|
||||
${MSVC_DISABLED_WARNINGS_LIST})
|
||||
string(REPLACE "C" " -w4" MSVC_LEVEL4_WARNINGS_STR
|
||||
${MSVC_LEVEL4_WARNINGS_LIST})
|
||||
set(CMAKE_C_FLAGS "-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}")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
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}")
|
||||
add_definitions(-D_HAS_EXCEPTIONS=0)
|
||||
add_definitions(-DWIN32_LEAN_AND_MEAN)
|
||||
add_definitions(-DNOMINMAX)
|
||||
# Allow use of fopen.
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
# VS 2017 and higher supports STL-only warning suppressions.
|
||||
# A bug in CMake < 3.13.0 may cause the space in this value to
|
||||
# cause issues when building with NASM. In that case, update CMake.
|
||||
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
|
||||
CLANG)
|
||||
CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshadow")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wshadow")
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
if((CMAKE_C_COMPILER_VERSION VERSION_GREATER "4.8.99") OR CLANG)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11")
|
||||
else()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# pthread_rwlock_t requires a feature flag.
|
||||
if(NOT WIN32)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_XOPEN_SOURCE=700")
|
||||
if((CMAKE_COMPILER_IS_GNUCXX AND CMAKE_C_COMPILER_VERSION VERSION_GREATER "4.8.99") OR
|
||||
CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_XOPEN_SOURCE=700")
|
||||
endif()
|
||||
|
||||
if(FUZZ)
|
||||
if(NOT CLANG)
|
||||
message(FATAL_ERROR "You need to build with Clang for fuzzing to work")
|
||||
if(!CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
message("You need to build with Clang for fuzzing to work")
|
||||
endif()
|
||||
|
||||
if(CMAKE_C_COMPILER_VERSION VERSION_LESS "6.0.0")
|
||||
message(FATAL_ERROR "You need Clang ≥ 6.0.0")
|
||||
endif()
|
||||
add_definitions(-DBORINGSSL_UNSAFE_FUZZER_MODE)
|
||||
set(RUNNER_ARGS "-fuzzer")
|
||||
|
||||
add_definitions(-DBORINGSSL_UNSAFE_DETERMINISTIC_MODE)
|
||||
set(RUNNER_ARGS "-deterministic")
|
||||
|
||||
if(NOT NO_FUZZER_MODE)
|
||||
add_definitions(-DBORINGSSL_UNSAFE_FUZZER_MODE)
|
||||
set(RUNNER_ARGS ${RUNNER_ARGS} "-fuzzer" "-shim-config" "fuzzer_mode.json")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address,fuzzer-no-link -fsanitize-coverage=edge,indirect-calls")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address,fuzzer-no-link -fsanitize-coverage=edge,indirect-calls")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fsanitize-coverage=edge,indirect-calls,8bit-counters")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fsanitize-coverage=edge,indirect-calls,8bit-counters")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address")
|
||||
link_directories(.)
|
||||
endif()
|
||||
|
||||
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(NOT CLANG)
|
||||
message(FATAL_ERROR "Cannot enable MSAN unless using Clang")
|
||||
endif()
|
||||
|
||||
if(ASAN)
|
||||
message(FATAL_ERROR "ASAN and MSAN are mutually exclusive")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer")
|
||||
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer")
|
||||
endif()
|
||||
|
||||
if(ASAN)
|
||||
if(NOT CLANG)
|
||||
message(FATAL_ERROR "Cannot enable ASAN unless using Clang")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fsanitize-address-use-after-scope -fno-omit-frame-pointer")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fsanitize-address-use-after-scope -fno-omit-frame-pointer")
|
||||
endif()
|
||||
|
||||
if(CFI)
|
||||
if(NOT CLANG)
|
||||
message(FATAL_ERROR "Cannot enable CFI unless using Clang")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=cfi -fno-sanitize-trap=cfi -flto=thin")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=cfi -fno-sanitize-trap=cfi -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(UBSAN)
|
||||
if(NOT CLANG)
|
||||
message(FATAL_ERROR "Cannot enable UBSAN unless using Clang")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=undefined")
|
||||
|
||||
if(NOT UBSAN_RECOVER)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-sanitize-recover=undefined")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-sanitize-recover=undefined")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fno-sanitize-recover=undefined")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(GCOV)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
|
||||
endif()
|
||||
|
||||
if(FIPS)
|
||||
add_definitions(-DBORINGSSL_FIPS)
|
||||
if(FIPS_BREAK_TEST)
|
||||
add_definitions("-DBORINGSSL_FIPS_BREAK_${FIPS_BREAK_TEST}=1")
|
||||
endif()
|
||||
# The FIPS integrity check does not work for ASan and MSan builds.
|
||||
if(NOT ASAN AND NOT MSAN)
|
||||
if(BUILD_SHARED_LIBS)
|
||||
set(FIPS_SHARED "1")
|
||||
else()
|
||||
set(FIPS_DELOCATE "1")
|
||||
endif()
|
||||
endif()
|
||||
if(FIPS_SHARED)
|
||||
# The Android CMake files set -ffunction-sections and -fdata-sections,
|
||||
# which is incompatible with FIPS_SHARED.
|
||||
set(CMAKE_C_FLAGS
|
||||
"${CMAKE_C_FLAGS} -fno-function-sections -fno-data-sections")
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} -fno-function-sections -fno-data-sections")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(OPENSSL_SMALL)
|
||||
add_definitions(-DOPENSSL_SMALL)
|
||||
endif()
|
||||
|
||||
if(CONSTANT_TIME_VALIDATION)
|
||||
add_definitions(-DBORINGSSL_CONSTANT_TIME_VALIDATION)
|
||||
# Asserts will often test secret data.
|
||||
add_definitions(-DNDEBUG)
|
||||
endif()
|
||||
|
||||
function(go_executable dest package)
|
||||
set(godeps "${CMAKE_SOURCE_DIR}/util/godeps.go")
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.7" OR
|
||||
NOT ${CMAKE_GENERATOR} STREQUAL "Ninja")
|
||||
# The DEPFILE parameter to add_custom_command is new as of CMake 3.7 and
|
||||
# only works with Ninja. Query the sources at configure time. Additionally,
|
||||
# everything depends on go.mod. That affects what external packages to use.
|
||||
execute_process(COMMAND ${GO_EXECUTABLE} run ${godeps} -format cmake
|
||||
-pkg ${package}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE sources
|
||||
RESULT_VARIABLE godeps_result)
|
||||
add_custom_command(OUTPUT ${dest}
|
||||
COMMAND ${GO_EXECUTABLE} build
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/${dest} ${package}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
DEPENDS ${sources} ${CMAKE_SOURCE_DIR}/go.mod)
|
||||
else()
|
||||
# Ninja expects the target in the depfile to match the output. This is a
|
||||
# relative path from the build directory.
|
||||
string(LENGTH "${CMAKE_BINARY_DIR}" root_dir_length)
|
||||
math(EXPR root_dir_length "${root_dir_length} + 1")
|
||||
string(SUBSTRING "${CMAKE_CURRENT_BINARY_DIR}" ${root_dir_length} -1 target)
|
||||
set(target "${target}/${dest}")
|
||||
|
||||
set(depfile "${CMAKE_CURRENT_BINARY_DIR}/${dest}.d")
|
||||
add_custom_command(OUTPUT ${dest}
|
||||
COMMAND ${GO_EXECUTABLE} build
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/${dest} ${package}
|
||||
COMMAND ${GO_EXECUTABLE} run ${godeps} -format depfile
|
||||
-target ${target} -pkg ${package} -out ${depfile}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
DEPENDS ${godeps} ${CMAKE_SOURCE_DIR}/go.mod
|
||||
DEPFILE ${depfile})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# CMake's iOS support uses Apple's multiple-architecture toolchain. It takes an
|
||||
# architecture list from CMAKE_OSX_ARCHITECTURES, leaves CMAKE_SYSTEM_PROCESSOR
|
||||
# alone, and expects all architecture-specific logic to be conditioned within
|
||||
# the source files rather than the build. This does not work for our assembly
|
||||
# files, so we fix CMAKE_SYSTEM_PROCESSOR and only support single-architecture
|
||||
# builds.
|
||||
if(NOT OPENSSL_NO_ASM AND CMAKE_OSX_ARCHITECTURES)
|
||||
list(LENGTH CMAKE_OSX_ARCHITECTURES NUM_ARCHES)
|
||||
if(NOT ${NUM_ARCHES} EQUAL 1)
|
||||
message(FATAL_ERROR "Universal binaries not supported.")
|
||||
endif()
|
||||
list(GET CMAKE_OSX_ARCHITECTURES 0 CMAKE_SYSTEM_PROCESSOR)
|
||||
endif()
|
||||
|
||||
if(OPENSSL_NO_SSE2_FOR_TESTING)
|
||||
add_definitions(-DOPENSSL_NO_SSE2_FOR_TESTING)
|
||||
endif()
|
||||
|
||||
if(OPENSSL_NO_ASM)
|
||||
add_definitions(-DOPENSSL_NO_ASM)
|
||||
set(ARCH "generic")
|
||||
elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64")
|
||||
if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64")
|
||||
set(ARCH "x86_64")
|
||||
elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "amd64")
|
||||
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_SIZEOF_VOID_P EQUAL 8)
|
||||
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")
|
||||
set(ARCH "aarch64")
|
||||
elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm64")
|
||||
set(ARCH "aarch64")
|
||||
# Apple A12 Bionic chipset which is added in iPhone XS/XS Max/XR uses arm64e architecture.
|
||||
elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm64e")
|
||||
set(ARCH "aarch64")
|
||||
elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^arm*")
|
||||
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm")
|
||||
set(ARCH "arm")
|
||||
elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "mips")
|
||||
# Just to avoid the “unknown processor” error.
|
||||
set(ARCH "generic")
|
||||
elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "ppc64le")
|
||||
set(ARCH "ppc64le")
|
||||
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv6")
|
||||
set(ARCH "arm")
|
||||
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv7-a")
|
||||
set(ARCH "arm")
|
||||
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
|
||||
set(ARCH "aarch64")
|
||||
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(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)
|
||||
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()
|
||||
|
||||
# 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)
|
||||
|
||||
include_directories(third_party/googletest/include)
|
||||
if (OPENSSL_NO_ASM)
|
||||
add_definitions(-DOPENSSL_NO_ASM)
|
||||
set(ARCH "generic")
|
||||
endif()
|
||||
|
||||
# Declare a dummy target to build all unit tests. Test targets should inject
|
||||
# themselves as dependencies next to the target definition.
|
||||
add_custom_target(all_tests)
|
||||
|
||||
# On Windows, CRYPTO_TEST_DATA is too long to fit in command-line limits.
|
||||
# TODO(davidben): CMake 3.12 has a list(JOIN) command. Use that when we've
|
||||
# updated the minimum version.
|
||||
set(EMBED_TEST_DATA_ARGS "")
|
||||
foreach(arg ${CRYPTO_TEST_DATA})
|
||||
set(EMBED_TEST_DATA_ARGS "${EMBED_TEST_DATA_ARGS}${arg}\n")
|
||||
endforeach()
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/embed_test_data_args.txt"
|
||||
"${EMBED_TEST_DATA_ARGS}")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT crypto_test_data.cc
|
||||
COMMAND ${GO_EXECUTABLE} run util/embed_test_data.go -file-list
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/embed_test_data_args.txt" >
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/crypto_test_data.cc"
|
||||
DEPENDS util/embed_test_data.go ${CRYPTO_TEST_DATA}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
add_library(crypto_test_data OBJECT crypto_test_data.cc)
|
||||
|
||||
add_subdirectory(crypto)
|
||||
add_subdirectory(ssl)
|
||||
add_subdirectory(ssl/test)
|
||||
add_subdirectory(tool)
|
||||
add_subdirectory(util/fipstools/cavp)
|
||||
add_subdirectory(util/fipstools/acvp/modulewrapper)
|
||||
add_subdirectory(decrepit)
|
||||
|
||||
if(FUZZ)
|
||||
if(LIBFUZZER_FROM_DEPS)
|
||||
file(GLOB LIBFUZZER_SOURCES "util/bot/libFuzzer/*.cpp")
|
||||
add_library(Fuzzer STATIC ${LIBFUZZER_SOURCES})
|
||||
# libFuzzer does not pass our aggressive warnings. It also must be built
|
||||
# without -fsanitize-coverage options or clang crashes.
|
||||
set_target_properties(Fuzzer PROPERTIES COMPILE_FLAGS "-Wno-shadow -Wno-format-nonliteral -Wno-missing-prototypes -fsanitize-coverage=0")
|
||||
endif()
|
||||
|
||||
add_subdirectory(fuzz)
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE AND NOT ANDROID)
|
||||
set(HANDSHAKER_ARGS "-handshaker-path" $<TARGET_FILE:handshaker>)
|
||||
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()
|
||||
|
||||
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}
|
||||
COMMAND cd ssl/test/runner
|
||||
COMMAND ${GO_EXECUTABLE} test -shim-path $<TARGET_FILE:bssl_shim>
|
||||
${RUNNER_ARGS}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
DEPENDS all_tests bssl_shim handshaker
|
||||
USES_TERMINAL)
|
||||
DEPENDS all_tests bssl_shim
|
||||
${MAYBE_USES_TERMINAL})
|
||||
|
||||
+14
-45
@@ -2,43 +2,33 @@
|
||||
|
||||
Modern fuzz testers are very effective and we wish to use them to ensure that no silly bugs creep into BoringSSL.
|
||||
|
||||
We use Clang's [libFuzzer](http://llvm.org/docs/LibFuzzer.html) for fuzz testing and there are a number of fuzz testing functions in `fuzz/`. They are not built by default because they require that the rest of BoringSSL be built with some changes that make fuzzing much more effective, but are completely unsafe for real use.
|
||||
We primarily use Clang's [libFuzzer](http://llvm.org/docs/LibFuzzer.html) for fuzz testing and there are a number of fuzz testing functions in `fuzz/`. They are not built by default because they require libFuzzer at build time.
|
||||
|
||||
In order to build the fuzz tests you will need at least Clang 6.0. Pass `-DFUZZ=1` on the CMake command line to enable building BoringSSL with coverage and AddressSanitizer, and to build the fuzz test binaries. You'll probably need to set the `CC` and `CXX` environment variables too, like this:
|
||||
In order to build the fuzz tests you will need at least Clang 3.7. Pass `-DFUZZ=1` on the CMake command line to enable building BoringSSL with coverage and AddressSanitizer, and to build the fuzz test binaries. You'll probably need to set the `CC` and `CXX` environment variables too, like this:
|
||||
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
CC=clang CXX=clang++ cmake -GNinja -DFUZZ=1 ..
|
||||
ninja
|
||||
```
|
||||
|
||||
In order for the fuzz tests to link, the linker needs to find libFuzzer. This is not commonly provided and you may need to download the [Clang source code](http://llvm.org/releases/download.html) and do the following:
|
||||
|
||||
```
|
||||
svn co http://llvm.org/svn/llvm-project/llvm/trunk/lib/Fuzzer
|
||||
clang++ -c -g -O2 -std=c++11 Fuzzer/*.cpp -IFuzzer
|
||||
ar ruv libFuzzer.a Fuzzer*.o
|
||||
```
|
||||
|
||||
Then copy `libFuzzer.a` to the top-level of your BoringSSL source directory.
|
||||
|
||||
From the `build/` directory, you can then run the fuzzers. For example:
|
||||
|
||||
```
|
||||
./fuzz/cert -max_len=10000 -jobs=32 -workers=32 ../fuzz/cert_corpus/
|
||||
./fuzz/cert -max_len=3072 -jobs=32 -workers=32 ../fuzz/cert_corpus/
|
||||
```
|
||||
|
||||
The arguments to `jobs` and `workers` should be the number of cores that you wish to dedicate to fuzzing. By default, libFuzzer uses the largest test in the corpus (or 64 if empty) as the maximum test case length. The `max_len` argument overrides this.
|
||||
|
||||
The recommended values of `max_len` for each test are:
|
||||
|
||||
| Test | `max_len` value |
|
||||
|---------------|-----------------|
|
||||
| `bn_div` | 384 |
|
||||
| `bn_mod_exp` | 4096 |
|
||||
| `cert` | 10000 |
|
||||
| `client` | 20000 |
|
||||
| `pkcs8` | 2048 |
|
||||
| `privkey` | 2048 |
|
||||
| `server` | 4096 |
|
||||
| `session` | 8192 |
|
||||
| `spki` | 1024 |
|
||||
| `read_pem` | 512 |
|
||||
| `ssl_ctx_api` | 256 |
|
||||
|
||||
These were determined by rounding up the length of the largest case in the corpus.
|
||||
The recommended values of `max_len` for each test may be found in `.options` files alongside the test source. These were determined by rounding up the length of the largest case in the corpus. When writing a new fuzzer, configure `max_len` in a similar file.
|
||||
|
||||
There are directories in `fuzz/` for each of the fuzzing tests which contain seed files for fuzzing. Some of the seed files were generated manually but many of them are “interesting” results generated by the fuzzing itself. (Where “interesting” means that it triggered a previously unknown path in the code.)
|
||||
|
||||
@@ -50,33 +40,12 @@ In order to minimise all the corpuses, build for fuzzing and run `./fuzz/minimis
|
||||
|
||||
## Fuzzer mode
|
||||
|
||||
When `-DFUZZ=1` is passed into CMake, BoringSSL builds with `BORINGSSL_UNSAFE_FUZZER_MODE` and `BORINGSSL_UNSAFE_DETERMINISTIC_MODE` defined. This modifies the library to be more friendly to fuzzers. If `BORINGSSL_UNSAFE_DETERMINISTIC_MODE` is set, BoringSSL will:
|
||||
When `-DFUZZ=1` is passed into CMake, BoringSSL builds with `BORINGSSL_UNSAFE_FUZZER_MODE` defined. This modifies the library, particularly the TLS stack, to be more friendly to fuzzers. It will:
|
||||
|
||||
* Replace `RAND_bytes` with a deterministic PRNG. Call `RAND_reset_for_fuzzing()` at the start of fuzzers which use `RAND_bytes` to reset the PRNG state.
|
||||
|
||||
* Use a hard-coded time instead of the actual time.
|
||||
|
||||
Additionally, if `BORINGSSL_UNSAFE_FUZZER_MODE` is set, BoringSSL will:
|
||||
|
||||
* Modify the TLS stack to perform all signature checks (CertificateVerify and ServerKeyExchange) and the Finished check, but always act as if the check succeeded.
|
||||
|
||||
* Treat every cipher as the NULL cipher.
|
||||
|
||||
* Tickets are unencrypted and the MAC check is performed but ignored.
|
||||
|
||||
* renegotiation\_info checks are ignored.
|
||||
|
||||
This is to prevent the fuzzer from getting stuck at a cryptographic invariant in the protocol.
|
||||
|
||||
## TLS transcripts
|
||||
|
||||
The `client` and `server` corpora are seeded from the test suite. The test suite has a `-fuzzer` flag which mirrors the fuzzer mode changes above and a `-deterministic` flag which removes all non-determinism on the Go side. Not all tests pass, so `ssl/test/runner/fuzzer_mode.json` contains the necessary suppressions. The `run_tests` target will pass appropriate command-line flags.
|
||||
|
||||
There are separate corpora, `client_corpus_no_fuzzer_mode` and `server_corpus_no_fuzzer_mode`. These are transcripts for fuzzers with only `BORINGSSL_UNSAFE_DETERMINISTIC_MODE` defined. To build in this mode, pass `-DNO_FUZZER_MODE=1` into CMake. This configuration is run in the same way but without `-fuzzer` and `-shim-config` flags.
|
||||
|
||||
If both sets of tests pass, refresh the fuzzer corpora with `refresh_ssl_corpora.sh`:
|
||||
|
||||
```
|
||||
cd fuzz
|
||||
./refresh_ssl_corpora.sh /path/to/fuzzer/mode/build /path/to/non/fuzzer/mode/build
|
||||
```
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
# Incorporating BoringSSL into a project
|
||||
|
||||
**Note**: if your target project is not a Google project then first read the
|
||||
[main README](/README.md) about the purpose of BoringSSL.
|
||||
|
||||
## Bazel
|
||||
|
||||
If you are using [Bazel](https://bazel.build) then you can incorporate
|
||||
BoringSSL as an external repository by using a commit from the
|
||||
`master-with-bazel` branch. That branch is maintained by a bot from `master`
|
||||
and includes the needed generated files and a top-level BUILD file.
|
||||
|
||||
For example:
|
||||
|
||||
git_repository(
|
||||
name = "boringssl",
|
||||
commit = "_some commit_",
|
||||
remote = "https://boringssl.googlesource.com/boringssl",
|
||||
)
|
||||
|
||||
You would still need to keep the referenced commit up to date if a specific
|
||||
commit is referred to.
|
||||
|
||||
## Directory layout
|
||||
|
||||
Typically projects create a `third_party/boringssl` directory to put
|
||||
BoringSSL-specific files into. The source code of BoringSSL itself goes into
|
||||
`third_party/boringssl/src`, either by copying or as a
|
||||
[submodule](https://git-scm.com/docs/git-submodule).
|
||||
|
||||
It's generally a mistake to put BoringSSL's source code into
|
||||
`third_party/boringssl` directly because pre-built files and custom build files
|
||||
need to go somewhere and merging these with the BoringSSL source code makes
|
||||
updating things more complex.
|
||||
|
||||
## Build support
|
||||
|
||||
BoringSSL is designed to work with many different build systems. Currently,
|
||||
different projects use [GYP](https://gyp.gsrc.io/),
|
||||
[GN](https://gn.googlesource.com/gn/+/master/docs/quick_start.md),
|
||||
[Bazel](https://bazel.build/) and [Make](https://www.gnu.org/software/make/) to
|
||||
build BoringSSL, without too much pain.
|
||||
|
||||
The development build system is CMake and the CMake build knows how to
|
||||
automatically generate the intermediate files that BoringSSL needs. However,
|
||||
outside of the CMake environment, these intermediates are generated once and
|
||||
checked into the incorporating project's source repository. This avoids
|
||||
incorporating projects needing to support Perl and Go in their build systems.
|
||||
|
||||
The script [`util/generate_build_files.py`](/util/generate_build_files.py)
|
||||
expects to be run from the `third_party/boringssl` directory and to find the
|
||||
BoringSSL source code in `src/`. You should pass it a single argument: the name
|
||||
of the build system that you're using. If you don't use any of the supported
|
||||
build systems then you should augment `generate_build_files.py` with support
|
||||
for it.
|
||||
|
||||
The script will pregenerate the intermediate files (see
|
||||
[BUILDING.md](/BUILDING.md) for details about which tools will need to be
|
||||
installed) and output helper files for that build system. It doesn't generate a
|
||||
complete build script, just file and test lists, which change often. For
|
||||
example, see the
|
||||
[file](https://code.google.com/p/chromium/codesearch#chromium/src/third_party/boringssl/BUILD.generated.gni)
|
||||
and
|
||||
[test](https://code.google.com/p/chromium/codesearch#chromium/src/third_party/boringssl/BUILD.generated_tests.gni)
|
||||
lists generated for GN in Chromium.
|
||||
|
||||
Generally one checks in these generated files alongside the hand-written build
|
||||
files. Periodically an engineer updates the BoringSSL revision, regenerates
|
||||
these files and checks in the updated result. As an example, see how this is
|
||||
done [in Chromium](https://code.google.com/p/chromium/codesearch#chromium/src/third_party/boringssl/).
|
||||
|
||||
## Defines
|
||||
|
||||
BoringSSL does not present a lot of configurability in order to reduce the
|
||||
number of configurations that need to be tested. But there are a couple of
|
||||
\#defines that you may wish to set:
|
||||
|
||||
`OPENSSL_NO_ASM` prevents the use of assembly code (although it's up to you to
|
||||
ensure that the build system doesn't link it in if you wish to reduce binary
|
||||
size). This will have a significant performance impact but can be useful if you
|
||||
wish to use tools like
|
||||
[AddressSanitizer](http://clang.llvm.org/docs/AddressSanitizer.html) that
|
||||
interact poorly with assembly code.
|
||||
|
||||
`OPENSSL_SMALL` removes some code that is especially large at some performance
|
||||
cost.
|
||||
|
||||
## Symbols
|
||||
|
||||
You cannot link multiple versions of BoringSSL or OpenSSL into a single binary
|
||||
without dealing with symbol conflicts. If you are statically linking multiple
|
||||
versions together, there's not a lot that can be done because C doesn't have a
|
||||
module system.
|
||||
|
||||
If you are using multiple versions in a single binary, in different shared
|
||||
objects, ensure you build BoringSSL with `-fvisibility=hidden` and do not
|
||||
export any of BoringSSL's symbols. This will prevent any collisions with other
|
||||
verisons that may be included in other shared objects. Note that this requires
|
||||
that all callers of BoringSSL APIs live in the same shared object as BoringSSL.
|
||||
|
||||
If you require that BoringSSL APIs be used across shared object boundaries,
|
||||
continue to build with `-fvisibility=hidden` but define
|
||||
`BORINGSSL_SHARED_LIBRARY` in both BoringSSL and consumers. BoringSSL's own
|
||||
source files (but *not* consumers' source files) must also build with
|
||||
`BORINGSSL_IMPLEMENTATION` defined. This will export BoringSSL's public symbols
|
||||
in the resulting shared object while hiding private symbols. However note that,
|
||||
as with a static link, this precludes dynamically linking with another version
|
||||
of BoringSSL or OpenSSL.
|
||||
@@ -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.
|
||||
|
||||
+17
-141
@@ -6,27 +6,14 @@ BoringSSL support, provided they do not use removed APIs. In general, see if the
|
||||
library compiles and, on failure, consult the documentation in the header files
|
||||
and see if problematic features can be removed.
|
||||
|
||||
BoringSSL's `OPENSSL_VERSION_NUMBER` matches the OpenSSL version it targets.
|
||||
Version checks for OpenSSL should ideally work as-is in BoringSSL. BoringSSL
|
||||
also defines upstream's `OPENSSL_NO_*` feature macros corresponding to removed
|
||||
features. If the preprocessor is needed, use these version checks or feature
|
||||
macros where possible, especially when patching third-party projects. Such
|
||||
patches are more generally useful to OpenSSL consumers and thus more
|
||||
appropriate to send upstream.
|
||||
In some cases, BoringSSL-specific code may be necessary. In that case, the
|
||||
`OPENSSL_IS_BORINGSSL` preprocessor macro may be used in `#ifdef`s. This macro
|
||||
should also be used in lieu of the presence of any particular function to detect
|
||||
OpenSSL vs BoringSSL in configure scripts, etc., where those are necessary.
|
||||
|
||||
In some cases, BoringSSL-specific code may be necessary. Use the
|
||||
`OPENSSL_IS_BORINGSSL` preprocessor macro in `#ifdef`s. However, first contact
|
||||
the BoringSSL maintainers about the missing APIs. We will typically add
|
||||
compatibility functions for convenience. In particular, *contact BoringSSL
|
||||
maintainers before working around missing OpenSSL 1.1.0 accessors*. BoringSSL
|
||||
was originally derived from OpenSSL 1.0.2 but now targets OpenSSL 1.1.0. Some
|
||||
newer APIs may be missing but can be added on request. (Not all projects have
|
||||
been ported to OpenSSL 1.1.0, so BoringSSL also remains largely compatible with
|
||||
OpenSSL 1.0.2.)
|
||||
|
||||
The `OPENSSL_IS_BORINGSSL` macro may also be used to distinguish OpenSSL from
|
||||
BoringSSL in configure scripts. Do not use the presence or absence of particular
|
||||
symbols to detect BoringSSL.
|
||||
For convenience, BoringSSL defines upstream's `OPENSSL_NO_*` feature macros
|
||||
corresponding to removed features. These may also be used to disable code which
|
||||
uses a removed feature.
|
||||
|
||||
Note: BoringSSL does *not* have a stable API or ABI. It must be updated with its
|
||||
consumers. It is not suitable for, say, a system library in a traditional Linux
|
||||
@@ -49,19 +36,15 @@ code, particularly to avoid compiler warnings.
|
||||
Most notably, the `STACK_OF(T)` types have all been converted to use `size_t`
|
||||
instead of `int` for indices and lengths.
|
||||
|
||||
### Reference counts and opaque types
|
||||
### Reference counts
|
||||
|
||||
Some external consumers increment reference counts directly by calling
|
||||
`CRYPTO_add` with the corresponding `CRYPTO_LOCK_*` value. These APIs no longer
|
||||
exist in BoringSSL. Instead, code which increments reference counts should call
|
||||
the corresponding `FOO_up_ref` function, such as `EVP_PKEY_up_ref`.
|
||||
`CRYPTO_add` with the corresponding `CRYPTO_LOCK_*` value.
|
||||
|
||||
BoringSSL also hides some structs which were previously exposed in OpenSSL
|
||||
1.0.2, particularly in libssl. Use the relevant accessors instead.
|
||||
|
||||
Note that some of these APIs were added in OpenSSL 1.1.0, so projects which do
|
||||
not yet support 1.1.0 may need additional `#ifdef`s. Projects supporting OpenSSL
|
||||
1.1.0 should not require modification.
|
||||
These APIs no longer exist in BoringSSL. Instead, code which increments
|
||||
reference counts should call the corresponding `FOO_up_ref` function, such as
|
||||
`EVP_PKEY_up_ref`. Note that not all of these APIs are present in OpenSSL and
|
||||
may require `#ifdef`s.
|
||||
|
||||
### Error codes
|
||||
|
||||
@@ -96,8 +79,7 @@ will continue to function. However, the macros themselves will not work.
|
||||
|
||||
Switch any `*_ctrl` callers to the macro/function versions. This works in both
|
||||
OpenSSL and BoringSSL. Note that BoringSSL's function versions will be
|
||||
type-checked and may require more care with types. See the end of this
|
||||
document for a table of functions to use.
|
||||
type-checked and may require more care with types.
|
||||
|
||||
### HMAC `EVP_PKEY`s
|
||||
|
||||
@@ -123,16 +105,14 @@ 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.
|
||||
|
||||
Things which do not work:
|
||||
|
||||
* There is no support for renegotiation as a server. (Attempts by clients will
|
||||
result in a fatal alert so that ClientHello messages cannot be used to flood
|
||||
a server and escape higher-level limits.)
|
||||
* There is no support for renegotiation as a server.
|
||||
|
||||
* There is no support for renegotiation in DTLS.
|
||||
|
||||
@@ -144,17 +124,6 @@ Things which do not work:
|
||||
* If a HelloRequest is received while `SSL_write` has unsent application data,
|
||||
the renegotiation is rejected.
|
||||
|
||||
* Renegotiation does not participate in session resumption. The client will
|
||||
not offer a session on renegotiation or resume any session established by a
|
||||
renegotiation handshake.
|
||||
|
||||
* The server may not change its certificate in the renegotiation. This mitigates
|
||||
the [triple handshake attack](https://mitls.org/pages/attacks/3SHAKE). Any new
|
||||
stapled OCSP response and SCT list will be ignored. As no authentication state
|
||||
may change, BoringSSL will not re-verify the certificate on a renegotiation.
|
||||
Callbacks such as `SSL_CTX_set_custom_verify` will only run on the initial
|
||||
handshake.
|
||||
|
||||
### Lowercase hexadecimal
|
||||
|
||||
BoringSSL's `BN_bn2hex` function uses lowercase hexadecimal digits instead of
|
||||
@@ -179,17 +148,6 @@ recommended to avoid the `out` parameter completely and always pass in `NULL`.
|
||||
Note that less error-prone APIs are available for BoringSSL-specific code (see
|
||||
below).
|
||||
|
||||
### Memory allocation
|
||||
|
||||
OpenSSL provides wrappers `OPENSSL_malloc` and `OPENSSL_free` over the standard
|
||||
`malloc` and `free`. Memory allocated by OpenSSL should be released with
|
||||
`OPENSSL_free`, not the standard `free`. However, by default, they are
|
||||
implemented directly using `malloc` and `free`, so code which mixes them up
|
||||
usually works.
|
||||
|
||||
In BoringSSL, these functions maintain additional book-keeping to zero memory
|
||||
on `OPENSSL_free`, so any mixups must be fixed.
|
||||
|
||||
## Optional BoringSSL-specific simplifications
|
||||
|
||||
BoringSSL makes some changes to OpenSSL which simplify the API but remain
|
||||
@@ -210,7 +168,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.
|
||||
|
||||
@@ -227,85 +185,3 @@ guarantees it.
|
||||
BoringSSL is in the process of deprecating OpenSSL's `d2i` and `i2d` in favor of
|
||||
new functions using the much less error-prone `CBS` and `CBB` types.
|
||||
BoringSSL-only code should use those functions where available.
|
||||
|
||||
|
||||
## Replacements for `CTRL` values
|
||||
|
||||
When porting code which uses `SSL_CTX_ctrl` or `SSL_ctrl`, use the replacement
|
||||
functions below. If a function has both `SSL_CTX` and `SSL` variants, only the
|
||||
`SSL_CTX` version is listed.
|
||||
|
||||
Note some values correspond to multiple functions depending on the `larg`
|
||||
parameter.
|
||||
|
||||
`CTRL` value | Replacement function(s)
|
||||
-------------|-------------------------
|
||||
`DTLS_CTRL_GET_TIMEOUT` | `DTLSv1_get_timeout`
|
||||
`DTLS_CTRL_HANDLE_TIMEOUT` | `DTLSv1_handle_timeout`
|
||||
`SSL_CTRL_CHAIN` | `SSL_CTX_set0_chain` or `SSL_CTX_set1_chain`
|
||||
`SSL_CTRL_CHAIN_CERT` | `SSL_add0_chain_cert` or `SSL_add1_chain_cert`
|
||||
`SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS` | `SSL_CTX_clear_extra_chain_certs`
|
||||
`SSL_CTRL_CLEAR_MODE` | `SSL_CTX_clear_mode`
|
||||
`SSL_CTRL_CLEAR_OPTIONS` | `SSL_CTX_clear_options`
|
||||
`SSL_CTRL_EXTRA_CHAIN_CERT` | `SSL_CTX_add_extra_chain_cert`
|
||||
`SSL_CTRL_GET_CHAIN_CERTS` | `SSL_CTX_get0_chain_certs`
|
||||
`SSL_CTRL_GET_CLIENT_CERT_TYPES` | `SSL_get0_certificate_types`
|
||||
`SSL_CTRL_GET_EXTRA_CHAIN_CERTS` | `SSL_CTX_get_extra_chain_certs` or `SSL_CTX_get_extra_chain_certs_only`
|
||||
`SSL_CTRL_GET_MAX_CERT_LIST` | `SSL_CTX_get_max_cert_list`
|
||||
`SSL_CTRL_GET_NUM_RENEGOTIATIONS` | `SSL_num_renegotiations`
|
||||
`SSL_CTRL_GET_READ_AHEAD` | `SSL_CTX_get_read_ahead`
|
||||
`SSL_CTRL_GET_RI_SUPPORT` | `SSL_get_secure_renegotiation_support`
|
||||
`SSL_CTRL_GET_SESSION_REUSED` | `SSL_session_reused`
|
||||
`SSL_CTRL_GET_SESS_CACHE_MODE` | `SSL_CTX_get_session_cache_mode`
|
||||
`SSL_CTRL_GET_SESS_CACHE_SIZE` | `SSL_CTX_sess_get_cache_size`
|
||||
`SSL_CTRL_GET_TLSEXT_TICKET_KEYS` | `SSL_CTX_get_tlsext_ticket_keys`
|
||||
`SSL_CTRL_GET_TOTAL_RENEGOTIATIONS` | `SSL_total_renegotiations`
|
||||
`SSL_CTRL_MODE` | `SSL_CTX_get_mode` or `SSL_CTX_set_mode`
|
||||
`SSL_CTRL_NEED_TMP_RSA` | `SSL_CTX_need_tmp_RSA` is equivalent, but [*do not use this function*](https://freakattack.com/). (It is a no-op in BoringSSL.)
|
||||
`SSL_CTRL_OPTIONS` | `SSL_CTX_get_options` or `SSL_CTX_set_options`
|
||||
`SSL_CTRL_SESS_NUMBER` | `SSL_CTX_sess_number`
|
||||
`SSL_CTRL_SET_CURVES` | `SSL_CTX_set1_curves`
|
||||
`SSL_CTRL_SET_ECDH_AUTO` | `SSL_CTX_set_ecdh_auto`
|
||||
`SSL_CTRL_SET_MAX_CERT_LIST` | `SSL_CTX_set_max_cert_list`
|
||||
`SSL_CTRL_SET_MAX_SEND_FRAGMENT` | `SSL_CTX_set_max_send_fragment`
|
||||
`SSL_CTRL_SET_MSG_CALLBACK` | `SSL_set_msg_callback`
|
||||
`SSL_CTRL_SET_MSG_CALLBACK_ARG` | `SSL_set_msg_callback_arg`
|
||||
`SSL_CTRL_SET_MTU` | `SSL_set_mtu`
|
||||
`SSL_CTRL_SET_READ_AHEAD` | `SSL_CTX_set_read_ahead`
|
||||
`SSL_CTRL_SET_SESS_CACHE_MODE` | `SSL_CTX_set_session_cache_mode`
|
||||
`SSL_CTRL_SET_SESS_CACHE_SIZE` | `SSL_CTX_sess_set_cache_size`
|
||||
`SSL_CTRL_SET_TLSEXT_HOSTNAME` | `SSL_set_tlsext_host_name`
|
||||
`SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG` | `SSL_CTX_set_tlsext_servername_arg`
|
||||
`SSL_CTRL_SET_TLSEXT_SERVERNAME_CB` | `SSL_CTX_set_tlsext_servername_callback`
|
||||
`SSL_CTRL_SET_TLSEXT_TICKET_KEYS` | `SSL_CTX_set_tlsext_ticket_keys`
|
||||
`SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB` | `SSL_CTX_set_tlsext_ticket_key_cb`
|
||||
`SSL_CTRL_SET_TMP_DH` | `SSL_CTX_set_tmp_dh`
|
||||
`SSL_CTRL_SET_TMP_DH_CB` | `SSL_CTX_set_tmp_dh_callback`
|
||||
`SSL_CTRL_SET_TMP_ECDH` | `SSL_CTX_set_tmp_ecdh`
|
||||
`SSL_CTRL_SET_TMP_ECDH_CB` | `SSL_CTX_set_tmp_ecdh_callback`
|
||||
`SSL_CTRL_SET_TMP_RSA` | `SSL_CTX_set_tmp_rsa` is equivalent, but [*do not use this function*](https://freakattack.com/). (It is a no-op in BoringSSL.)
|
||||
`SSL_CTRL_SET_TMP_RSA_CB` | `SSL_CTX_set_tmp_rsa_callback` is equivalent, but [*do not use this function*](https://freakattack.com/). (It is a no-op in BoringSSL.)
|
||||
|
||||
## Significant API additions
|
||||
|
||||
In some places, BoringSSL has added significant APIs. Use of these APIs goes beyound “porting” and means giving up on OpenSSL compatibility.
|
||||
|
||||
One example of this has already been mentioned: the [CBS and CBB](https://commondatastorage.googleapis.com/chromium-boringssl-docs/bytestring.h.html) functions should be used whenever parsing or serialising data.
|
||||
|
||||
### CRYPTO\_BUFFER
|
||||
|
||||
With the standard OpenSSL APIs, when making many TLS connections, the certificate data for each connection is retained in memory in an expensive `X509` structure. Additionally, common certificates often appear in the chains for multiple connections and are needlessly duplicated in memory.
|
||||
|
||||
A [`CRYPTO_BUFFER`](https://commondatastorage.googleapis.com/chromium-boringssl-docs/pool.h.html) is just an opaque byte string. A `CRYPTO_BUFFER_POOL` is an intern table for these buffers, i.e. it ensures that only a single copy of any given byte string is kept for each pool.
|
||||
|
||||
The function `TLS_with_buffers_method` returns an `SSL_METHOD` that avoids creating `X509` objects for certificates. Additionally, `SSL_CTX_set0_buffer_pool` can be used to install a pool on an `SSL_CTX` so that certificates can be deduplicated across connections and across `SSL_CTX`s.
|
||||
|
||||
When using these functions, the application also needs to ensure that it doesn't call other functions that deal with `X509` or `X509_NAME` objects. For example, `SSL_get_peer_certificate` or `SSL_get_peer_cert_chain`. Doing so will trigger an assert in debug mode and will result in NULLs in release mode. Instead, call the buffer-based alternatives such as `SSL_get0_peer_certificates`. (See [ssl.h](https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html) for functions taking or returning `CRYPTO_BUFFER`.) The buffer-based alternative functions will work even when not using `TLS_with_buffers_method`, thus application code can transition gradually.
|
||||
|
||||
In order to use buffers, the application code also needs to implement its own certificate verification using `SSL_[CTX_]set_custom_verify`. Otherwise all connections will fail with a verification error. Auto-chaining is also disabled when using buffers.
|
||||
|
||||
Once those changes have been completed, the whole of the OpenSSL X.509 and ASN.1 code should be eliminated by the linker if BoringSSL is linked statically.
|
||||
|
||||
### Asynchronous and opaque private keys
|
||||
|
||||
OpenSSL offers the ENGINE API for implementing opaque private keys (i.e. private keys where software only has oracle access because the secrets are held in special hardware or on another machine). While the ENGINE API has been mostly removed from BoringSSL, it is still possible to support opaque keys in this way. However, when using such keys with TLS and BoringSSL, you should strongly prefer using `SSL_PRIVATE_KEY_METHOD` via `SSL[_CTX]_set_private_key_method`. This allows a handshake to be suspended while the private operation is in progress. It also supports more forms of opaque key as it exposes higher-level information about the operation to be performed.
|
||||
|
||||
@@ -21,22 +21,11 @@ these patches in multiple places was growing steadily.
|
||||
Currently BoringSSL is the SSL library in Chrome/Chromium, Android (but it's
|
||||
not part of the NDK) and a number of other apps/programs.
|
||||
|
||||
Project links:
|
||||
|
||||
* [API documentation](https://commondatastorage.googleapis.com/chromium-boringssl-docs/headers.html)
|
||||
* [Bug tracker](https://bugs.chromium.org/p/boringssl/issues/list)
|
||||
* [CI](https://ci.chromium.org/p/boringssl/g/main/console)
|
||||
* [Code review](https://boringssl-review.googlesource.com)
|
||||
|
||||
There are other files in this directory which might be helpful:
|
||||
|
||||
* [PORTING.md](/PORTING.md): how to port OpenSSL-using code to BoringSSL.
|
||||
* [BUILDING.md](/BUILDING.md): how to build BoringSSL
|
||||
* [INCORPORATING.md](/INCORPORATING.md): how to incorporate BoringSSL into a project.
|
||||
* [API-CONVENTIONS.md](/API-CONVENTIONS.md): general API conventions for BoringSSL consumers and developers.
|
||||
* [STYLE.md](/STYLE.md): rules and guidelines for coding style.
|
||||
* include/openssl: public headers with API documentation in comments. Also [available online](https://commondatastorage.googleapis.com/chromium-boringssl-docs/headers.html).
|
||||
* [FUZZING.md](/FUZZING.md): information about fuzzing BoringSSL.
|
||||
* [CONTRIBUTING.md](/CONTRIBUTING.md): how to contribute to BoringSSL.
|
||||
* [BREAKING-CHANGES.md](/BREAKING-CHANGES.md): notes on potentially-breaking changes.
|
||||
* [SANDBOXING.md](/SANDBOXING.md): notes on using BoringSSL in a sandboxed environment.
|
||||
|
||||
-138
@@ -1,138 +0,0 @@
|
||||
# Using BoringSSL in a Sandbox
|
||||
|
||||
Sandboxes are a valuable tool for securing applications, so BoringSSL aims to
|
||||
support them. However, it is difficult to make concrete API guarantees with
|
||||
sandboxes. Sandboxes remove low-level OS resources and system calls, which
|
||||
breaks platform abstractions. A syscall-filtering sandbox may, for instance, be
|
||||
sensitive to otherwise non-breaking changes to use newer syscalls
|
||||
in either BoringSSL or the C library.
|
||||
|
||||
Some functions in BoringSSL, such as `BIO_new_file`, inherently need OS
|
||||
resources like the filesystem. We assume that sandboxed consumers either avoid
|
||||
those functions or make necessary resources available. Other functions like
|
||||
`RSA_sign` are purely computational, but still have some baseline OS
|
||||
dependencies.
|
||||
|
||||
Sandboxes which drop privileges partway through a process's lifetime are
|
||||
additionally sensitive to OS resources retained across the transitions. For
|
||||
instance, if a library function internally opened and retained a handle to the
|
||||
user's home directory, and then the application called `chroot`, that handle
|
||||
would be a sandbox escape.
|
||||
|
||||
This document attempts to describe these baseline OS dependencies and long-lived
|
||||
internal resources. These dependencies may change over time, but we aim to
|
||||
[work with sandboxed consumers](/BREAKING-CHANGES.md) when they do. However,
|
||||
each sandbox imposes different constraints, so, above all, sandboxed consumers
|
||||
must have ample test coverage to detect issues as they arise.
|
||||
|
||||
## Baseline dependencies
|
||||
|
||||
Callers must assume that any BoringSSL function may perform one of the following
|
||||
operations:
|
||||
|
||||
### Memory allocation
|
||||
|
||||
Any BoringSSL function may allocate memory via `malloc` and related functions.
|
||||
|
||||
### Thread synchronization
|
||||
|
||||
Any BoringSSL function may call into the platform's thread synchronization
|
||||
primitives, including read/write locks and the equivalent of `pthread_once`.
|
||||
These must succeed, or BoringSSL will abort the process. Callers, however, can
|
||||
assume that BoringSSL functions will not spawn internal threads, unless
|
||||
otherwise documented.
|
||||
|
||||
Syscall-filtering sandboxes should note that BoringSSL uses `pthread_rwlock_t`
|
||||
on POSIX systems, which is less common and may not be part of other libraries'
|
||||
syscall surface. Additionally, thread synchronization primitives usually have an
|
||||
atomics-based fast path. If a sandbox blocks a necessary pthreads syscall, it
|
||||
may not show up in testing without lock contention.
|
||||
|
||||
### Standard error
|
||||
|
||||
Any BoringSSL function may write to `stderr` or file descriptor
|
||||
`STDERR_FILENO` (2), either via `FILE` APIs or low-level functions like `write`.
|
||||
Writes to `stderr` may fail, but there must some file at `STDERR_FILENO` which
|
||||
will tolerate error messages from BoringSSL. (The file descriptor must be
|
||||
allocated so calls to `open` do not accidentally open something else there.)
|
||||
|
||||
Note some C standard library implementations also log to `stderr`, so callers
|
||||
should ensure this regardless.
|
||||
|
||||
### Entropy
|
||||
|
||||
Any BoringSSL function may draw entropy from the OS. On Windows, this uses
|
||||
`RtlGenRandom` and, on POSIX systems, this uses `getrandom`, `getentropy`, or a
|
||||
`read` from a file descriptor to `/dev/urandom`. These operations must succeed
|
||||
or BoringSSL will abort the process. BoringSSL only probes for `getrandom`
|
||||
support once and assumes support is consistent for the lifetime of the address
|
||||
space (and any copies made via `fork`). If a syscall-filtering sandbox is
|
||||
enabled partway through this lifetime and changes whether `getrandom` works,
|
||||
BoringSSL may abort the process. Sandboxes are recommended to allow
|
||||
`getrandom`.
|
||||
|
||||
Note even deterministic algorithms may require OS entropy. For example,
|
||||
RSASSA-PKCS1-v1_5 is deterministic, but BoringSSL draws entropy to implement
|
||||
RSA blinding.
|
||||
|
||||
Entropy gathering additionally has some initialization dependencies described in
|
||||
the following section.
|
||||
|
||||
## Initialization
|
||||
|
||||
BoringSSL has some uncommon OS dependencies which are only used once to
|
||||
initialize some state. Sandboxes which drop privileges after some setup work may
|
||||
use `CRYPTO_pre_sandbox_init` to initialize this state ahead of time. Otherwise,
|
||||
callers must assume any BoringSSL function may depend on these resources, in
|
||||
addition to the operations above.
|
||||
|
||||
### CPU capabilities
|
||||
|
||||
On Linux ARM platforms, BoringSSL depends on OS APIs to query CPU capabilities.
|
||||
32-bit and 64-bit ARM both depend on the `getauxval` function. 32-bit ARM, to
|
||||
work around bugs in older Android devices, may additionally read `/proc/cpuinfo`
|
||||
and `/proc/self/auxv`.
|
||||
|
||||
If querying CPU capabilities fails, BoringSSL will still function, but may not
|
||||
perform as well.
|
||||
|
||||
### Entropy
|
||||
|
||||
On Linux systems without a working `getrandom`, drawing entropy from the OS
|
||||
additionally requires opening `/dev/urandom`. If this fails, BoringSSL will
|
||||
abort the process. BoringSSL retains the resulting file descriptor, even across
|
||||
privilege transitions.
|
||||
|
||||
### Fork protection
|
||||
|
||||
On Linux, BoringSSL allocates a page and calls `madvise` with `MADV_WIPEONFORK`
|
||||
to protect single-use state from `fork`. This operation must not crash, but if
|
||||
it fails, BoringSSL will use alternate fork-safety strategies, potentially at a
|
||||
performance cost. If it succeeds, BoringSSL assumes `MADV_WIPEONFORK` is
|
||||
functional and relies on it for fork-safety. Sandboxes must not report success
|
||||
if they ignore the `MADV_WIPEONFORK` flag. As of writing, QEMU will ignore
|
||||
`madvise` calls and report success, so BoringSSL detects this by calling
|
||||
`madvise` with -1. Sandboxes must cleanly report an error instead of crashing.
|
||||
|
||||
Once initialized, this mechanism does not require system calls in the steady
|
||||
state, though note the configured page will be inherited across privilege
|
||||
transitions.
|
||||
|
||||
## C and C++ standard library
|
||||
|
||||
BoringSSL depends on the C and C++ standard libraries which, themselves, do not
|
||||
make any guarantees about sandboxes. If it produces the correct answer and has
|
||||
no observable invalid side effects, it is possible, though unreasonable, for
|
||||
`memcmp` to create and close a socket.
|
||||
|
||||
BoringSSL assumes that functions in the C and C++ library only have the platform
|
||||
dependencies which would be "reasonable". For instance, a function in BoringSSL
|
||||
which aims not to open files will still freely call any libc memory and
|
||||
string functions.
|
||||
|
||||
Note some C functions, such as `strerror`, may read files relating to the user's
|
||||
locale. BoringSSL may trigger these paths and assumes the sandbox environment
|
||||
will tolerate this. BoringSSL additionally cannot make guarantees about which
|
||||
system calls are used by standard library's syscall wrappers. In some cases, the
|
||||
compiler may add dependencies. (Some C++ language features emit locking code.)
|
||||
Syscall-filtering sandboxes may need updates as these dependencies change.
|
||||
@@ -14,10 +14,10 @@ concerned, balance consistency within a module with the benefits of a
|
||||
given rule. Module-wide deviations on naming should be respected while
|
||||
integer and return value conventions take precedence over consistency.
|
||||
|
||||
Modules from OpenSSL's legacy ASN.1 and X.509 stack are retained for
|
||||
compatibility and left largely unmodified. To ease importing patches from
|
||||
upstream, they match OpenSSL's new indentation style. For Emacs,
|
||||
`doc/openssl-c-indent.el` from OpenSSL may be helpful in this.
|
||||
Some modules have seen few changes, so they still retain the original
|
||||
indentation style for now. When editing these, try to retain the
|
||||
original style. For Emacs, `doc/c-indentation.el` from OpenSSL may be
|
||||
helpful in this.
|
||||
|
||||
|
||||
## Language
|
||||
@@ -27,14 +27,12 @@ Google style guide do not apply. Support for C99 features depends on
|
||||
our target platforms. Typically, Chromium's target MSVC is the most
|
||||
restrictive.
|
||||
|
||||
Variable declarations in the middle of a function or inside a `for` loop are
|
||||
allowed and preferred where possible. Note that the common `goto err` cleanup
|
||||
pattern requires lifting some variable declarations.
|
||||
Variable declarations in the middle of a function are allowed.
|
||||
|
||||
Comments should be `// C99-style` for consistency with C++.
|
||||
Comments should be `/* C-style */` for consistency.
|
||||
|
||||
When declaring pointer types, `*` should be placed next to the variable name,
|
||||
not the type. So
|
||||
When declaration pointer types, `*` should be placed next to the variable
|
||||
name, not the type. So
|
||||
|
||||
uint8_t *ptr;
|
||||
|
||||
@@ -45,34 +43,11 @@ not
|
||||
Rather than `malloc()` and `free()`, use the wrappers `OPENSSL_malloc()`
|
||||
and `OPENSSL_free()`. Use the standard C `assert()` function freely.
|
||||
|
||||
Use the following wrappers, found in `crypto/internal.h` instead of the
|
||||
corresponding C standard library functions. They behave the same but avoid
|
||||
confusing undefined behavior.
|
||||
|
||||
* `OPENSSL_memchr`
|
||||
* `OPENSSL_memcmp`
|
||||
* `OPENSSL_memcpy`
|
||||
* `OPENSSL_memmove`
|
||||
* `OPENSSL_memset`
|
||||
|
||||
For new constants, prefer enums when the values are sequential and typed
|
||||
constants for flags. If adding values to an existing set of `#define`s,
|
||||
continue with `#define`.
|
||||
|
||||
|
||||
## libssl
|
||||
|
||||
libssl was originally written in C but is being incrementally rewritten in
|
||||
C++11. As of writing, much of the style matches our C conventions rather than
|
||||
Google C++. Additionally, libssl on Linux currently may not depend on the C++
|
||||
runtime. See the C++ utilities in `ssl/internal.h` for replacements for
|
||||
problematic C++ constructs. The `util/check_imported_libraries.go` script may be
|
||||
used with a shared library build to check if a new construct is okay.
|
||||
|
||||
If unsure, match surrounding code. Discrepancies between it and Google C++ style
|
||||
will be fixed over time.
|
||||
|
||||
|
||||
## Formatting
|
||||
|
||||
Single-statement blocks are not allowed. All conditions and loops must
|
||||
@@ -182,7 +157,7 @@ For example,
|
||||
/* CBB_add_asn sets |*out_contents| to a |CBB| into which the contents of an
|
||||
* ASN.1 object can be written. The |tag| argument will be used as the tag for
|
||||
* the object. It returns one on success or zero on error. */
|
||||
OPENSSL_EXPORT int CBB_add_asn1(CBB *cbb, CBB *out_contents, unsigned tag);
|
||||
OPENSSL_EXPORT int CBB_add_asn1(CBB *cbb, CBB *out_contents, uint8_t tag);
|
||||
|
||||
|
||||
## Documentation
|
||||
@@ -198,36 +173,25 @@ behavior of the function. Pay special note to success/failure behaviors
|
||||
and caller obligations on object lifetimes. If this sacrifices
|
||||
conciseness, consider simplifying the function's behavior.
|
||||
|
||||
// EVP_DigestVerifyUpdate appends |len| bytes from |data| to the data which
|
||||
// will be verified by |EVP_DigestVerifyFinal|. It returns one on success and
|
||||
// zero otherwise.
|
||||
/* EVP_DigestVerifyUpdate appends |len| bytes from |data| to the data which
|
||||
* will be verified by |EVP_DigestVerifyFinal|. It returns one on success and
|
||||
* zero otherwise. */
|
||||
OPENSSL_EXPORT int EVP_DigestVerifyUpdate(EVP_MD_CTX *ctx, const void *data,
|
||||
size_t len);
|
||||
|
||||
Explicitly mention any surprising edge cases or deviations from common
|
||||
return value patterns in legacy functions.
|
||||
|
||||
// RSA_private_encrypt encrypts |flen| bytes from |from| with the private key in
|
||||
// |rsa| and writes the encrypted data to |to|. The |to| buffer must have at
|
||||
// least |RSA_size| bytes of space. It returns the number of bytes written, or
|
||||
// -1 on error. The |padding| argument must be one of the |RSA_*_PADDING|
|
||||
// values. If in doubt, |RSA_PKCS1_PADDING| is the most common.
|
||||
//
|
||||
// WARNING: this function is dangerous because it breaks the usual return value
|
||||
// convention. Use |RSA_sign_raw| instead.
|
||||
/* RSA_private_encrypt encrypts |flen| bytes from |from| with the private key in
|
||||
* |rsa| and writes the encrypted data to |to|. The |to| buffer must have at
|
||||
* least |RSA_size| bytes of space. It returns the number of bytes written, or
|
||||
* -1 on error. The |padding| argument must be one of the |RSA_*_PADDING|
|
||||
* values. If in doubt, |RSA_PKCS1_PADDING| is the most common.
|
||||
*
|
||||
* WARNING: this function is dangerous because it breaks the usual return value
|
||||
* convention. Use |RSA_sign_raw| instead. */
|
||||
OPENSSL_EXPORT int RSA_private_encrypt(int flen, const uint8_t *from,
|
||||
uint8_t *to, RSA *rsa, int padding);
|
||||
|
||||
Document private functions in their `internal.h` header or, if static,
|
||||
where defined.
|
||||
|
||||
|
||||
## Build logic
|
||||
|
||||
BoringSSL is used by many projects with many different build tools.
|
||||
Reimplementing and maintaining build logic in each downstream build is
|
||||
cumbersome, so build logic should be avoided where possible. Platform-specific
|
||||
files should be excluded by wrapping the contents in `#ifdef`s, rather than
|
||||
computing platform-specific file lists. Generated source files such as perlasm
|
||||
and `err_data.c` may be used in the standalone CMake build but, for downstream
|
||||
builds, they should be pre-generated in `generate_build_files.py`.
|
||||
|
||||
+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
|
||||
|
||||
+151
-505
@@ -1,80 +1,50 @@
|
||||
include_directories(../include)
|
||||
|
||||
if(NOT OPENSSL_NO_ASM)
|
||||
if(UNIX)
|
||||
if(${ARCH} STREQUAL "aarch64")
|
||||
# The "armx" Perl scripts look for "64" in the style argument
|
||||
# in order to decide whether to generate 32- or 64-bit asm.
|
||||
if(APPLE)
|
||||
set(PERLASM_STYLE ios64)
|
||||
else()
|
||||
set(PERLASM_STYLE linux64)
|
||||
endif()
|
||||
elseif(${ARCH} STREQUAL "arm")
|
||||
if(APPLE)
|
||||
set(PERLASM_STYLE ios32)
|
||||
else()
|
||||
set(PERLASM_STYLE linux32)
|
||||
endif()
|
||||
elseif(${ARCH} STREQUAL "ppc64le")
|
||||
set(PERLASM_STYLE linux64le)
|
||||
else()
|
||||
if(${ARCH} STREQUAL "x86")
|
||||
set(PERLASM_FLAGS "-fPIC -DOPENSSL_IA32_SSE2")
|
||||
endif()
|
||||
if(APPLE)
|
||||
set(PERLASM_STYLE macosx)
|
||||
else()
|
||||
set(PERLASM_STYLE elf)
|
||||
endif()
|
||||
endif()
|
||||
set(ASM_EXT S)
|
||||
enable_language(ASM)
|
||||
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -Wa,--noexecstack")
|
||||
|
||||
# Clang's integerated assembler does not support debug symbols.
|
||||
if(NOT CMAKE_ASM_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -Wa,-g")
|
||||
endif()
|
||||
|
||||
# CMake does not add -isysroot and -arch flags to assembly.
|
||||
if(APPLE)
|
||||
if(CMAKE_OSX_SYSROOT)
|
||||
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -isysroot \"${CMAKE_OSX_SYSROOT}\"")
|
||||
endif()
|
||||
foreach(arch ${CMAKE_OSX_ARCHITECTURES})
|
||||
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -arch ${arch}")
|
||||
endforeach()
|
||||
endif()
|
||||
else()
|
||||
if(${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 "${CMAKE_ASM_NASM_FLAGS} -gcv8")
|
||||
|
||||
# On Windows, we use the NASM output, specifically built with Yasm.
|
||||
set(ASM_EXT asm)
|
||||
enable_language(ASM_NASM)
|
||||
if(APPLE)
|
||||
if (${ARCH} STREQUAL "x86")
|
||||
set(PERLASM_FLAGS "-fPIC -DOPENSSL_IA32_SSE2")
|
||||
endif()
|
||||
set(PERLASM_STYLE macosx)
|
||||
set(ASM_EXT S)
|
||||
enable_language(ASM)
|
||||
elseif(UNIX)
|
||||
if (${ARCH} STREQUAL "aarch64")
|
||||
# The "armx" Perl scripts look for "64" in the style argument
|
||||
# in order to decide whether to generate 32- or 64-bit asm.
|
||||
set(PERLASM_STYLE linux64)
|
||||
elseif (${ARCH} STREQUAL "arm")
|
||||
set(PERLASM_STYLE linux32)
|
||||
elseif (${ARCH} STREQUAL "x86")
|
||||
set(PERLASM_FLAGS "-fPIC -DOPENSSL_IA32_SSE2")
|
||||
set(PERLASM_STYLE elf)
|
||||
else()
|
||||
set(PERLASM_STYLE elf)
|
||||
endif()
|
||||
set(ASM_EXT S)
|
||||
enable_language(ASM)
|
||||
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -Wa,--noexecstack")
|
||||
else()
|
||||
if (CMAKE_CL_64)
|
||||
message("Using nasm")
|
||||
set(PERLASM_STYLE nasm)
|
||||
else()
|
||||
message("Using win32n")
|
||||
set(PERLASM_STYLE win32n)
|
||||
set(PERLASM_FLAGS "-DOPENSSL_IA32_SSE2")
|
||||
endif()
|
||||
|
||||
# On Windows, we use the NASM output, specifically built with Yasm.
|
||||
set(ASM_EXT asm)
|
||||
enable_language(ASM_NASM)
|
||||
endif()
|
||||
|
||||
function(perlasm dest src)
|
||||
get_filename_component(dir ${dest} DIRECTORY)
|
||||
if ("${dir}" STREQUAL "")
|
||||
set(dir ".")
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${dest}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${dir}
|
||||
COMMAND ${PERL_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/${src} ${PERLASM_STYLE} ${PERLASM_FLAGS} ${ARGN} ${dest}
|
||||
COMMAND ${PERL_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/${src} ${PERLASM_STYLE} ${PERLASM_FLAGS} ${ARGN} > ${dest}
|
||||
DEPENDS
|
||||
${src}
|
||||
${PROJECT_SOURCE_DIR}/crypto/perlasm/arm-xlate.pl
|
||||
${PROJECT_SOURCE_DIR}/crypto/perlasm/ppc-xlate.pl
|
||||
${PROJECT_SOURCE_DIR}/crypto/perlasm/x86_64-xlate.pl
|
||||
${PROJECT_SOURCE_DIR}/crypto/perlasm/x86asm.pl
|
||||
${PROJECT_SOURCE_DIR}/crypto/perlasm/x86gas.pl
|
||||
@@ -84,476 +54,152 @@ function(perlasm dest src)
|
||||
)
|
||||
endfunction()
|
||||
|
||||
add_subdirectory(fipsmodule)
|
||||
# Level 0.1 - depends on nothing outside this set.
|
||||
add_subdirectory(stack)
|
||||
add_subdirectory(lhash)
|
||||
add_subdirectory(err)
|
||||
add_subdirectory(buf)
|
||||
add_subdirectory(base64)
|
||||
add_subdirectory(bytestring)
|
||||
|
||||
# Level 0.2 - depends on nothing but itself
|
||||
add_subdirectory(sha)
|
||||
add_subdirectory(md4)
|
||||
add_subdirectory(md5)
|
||||
add_subdirectory(modes)
|
||||
add_subdirectory(aes)
|
||||
add_subdirectory(des)
|
||||
add_subdirectory(rc4)
|
||||
add_subdirectory(conf)
|
||||
add_subdirectory(chacha)
|
||||
add_subdirectory(poly1305)
|
||||
add_subdirectory(curve25519)
|
||||
|
||||
# Level 1, depends only on 0.*
|
||||
add_subdirectory(digest)
|
||||
add_subdirectory(cipher)
|
||||
add_subdirectory(rand)
|
||||
add_subdirectory(bio)
|
||||
add_subdirectory(bn)
|
||||
add_subdirectory(obj)
|
||||
add_subdirectory(asn1)
|
||||
|
||||
# Level 2
|
||||
add_subdirectory(engine)
|
||||
add_subdirectory(dh)
|
||||
add_subdirectory(dsa)
|
||||
add_subdirectory(rsa)
|
||||
add_subdirectory(ec)
|
||||
add_subdirectory(ecdh)
|
||||
add_subdirectory(ecdsa)
|
||||
add_subdirectory(hmac)
|
||||
|
||||
# Level 3
|
||||
add_subdirectory(cmac)
|
||||
add_subdirectory(evp)
|
||||
add_subdirectory(hkdf)
|
||||
add_subdirectory(pem)
|
||||
add_subdirectory(x509)
|
||||
add_subdirectory(x509v3)
|
||||
|
||||
# Level 4
|
||||
add_subdirectory(pkcs8)
|
||||
|
||||
# Test support code
|
||||
add_subdirectory(test)
|
||||
|
||||
if(FIPS_DELOCATE OR FIPS_SHARED)
|
||||
SET_SOURCE_FILES_PROPERTIES(fipsmodule/bcm.o PROPERTIES EXTERNAL_OBJECT true)
|
||||
SET_SOURCE_FILES_PROPERTIES(fipsmodule/bcm.o PROPERTIES GENERATED true)
|
||||
|
||||
set(
|
||||
CRYPTO_FIPS_OBJECTS
|
||||
|
||||
fipsmodule/bcm.o
|
||||
)
|
||||
endif()
|
||||
|
||||
if(${ARCH} STREQUAL "arm")
|
||||
set(
|
||||
CRYPTO_ARCH_SOURCES
|
||||
|
||||
chacha/chacha-armv4.${ASM_EXT}
|
||||
curve25519/asm/x25519-asm-arm.S
|
||||
poly1305/poly1305_arm_asm.S
|
||||
test/trampoline-armv4.${ASM_EXT}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(${ARCH} STREQUAL "aarch64")
|
||||
set(
|
||||
CRYPTO_ARCH_SOURCES
|
||||
|
||||
chacha/chacha-armv8.${ASM_EXT}
|
||||
test/trampoline-armv8.${ASM_EXT}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(${ARCH} STREQUAL "ppc64le")
|
||||
set(
|
||||
CRYPTO_ARCH_SOURCES
|
||||
|
||||
test/trampoline-ppc.${ASM_EXT}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(${ARCH} STREQUAL "x86")
|
||||
set(
|
||||
CRYPTO_ARCH_SOURCES
|
||||
|
||||
chacha/chacha-x86.${ASM_EXT}
|
||||
test/trampoline-x86.${ASM_EXT}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(${ARCH} STREQUAL "x86_64")
|
||||
set(
|
||||
CRYPTO_ARCH_SOURCES
|
||||
|
||||
chacha/chacha-x86_64.${ASM_EXT}
|
||||
cipher_extra/aes128gcmsiv-x86_64.${ASM_EXT}
|
||||
cipher_extra/chacha20_poly1305_x86_64.${ASM_EXT}
|
||||
hrss/asm/poly_rq_mul.S
|
||||
test/trampoline-x86_64.${ASM_EXT}
|
||||
)
|
||||
endif()
|
||||
|
||||
perlasm(chacha/chacha-armv4.${ASM_EXT} chacha/asm/chacha-armv4.pl)
|
||||
perlasm(chacha/chacha-armv8.${ASM_EXT} chacha/asm/chacha-armv8.pl)
|
||||
perlasm(chacha/chacha-x86.${ASM_EXT} chacha/asm/chacha-x86.pl)
|
||||
perlasm(chacha/chacha-x86_64.${ASM_EXT} chacha/asm/chacha-x86_64.pl)
|
||||
perlasm(cipher_extra/aes128gcmsiv-x86_64.${ASM_EXT} cipher_extra/asm/aes128gcmsiv-x86_64.pl)
|
||||
perlasm(cipher_extra/chacha20_poly1305_x86_64.${ASM_EXT} cipher_extra/asm/chacha20_poly1305_x86_64.pl)
|
||||
perlasm(test/trampoline-armv4.${ASM_EXT} test/asm/trampoline-armv4.pl)
|
||||
perlasm(test/trampoline-armv8.${ASM_EXT} test/asm/trampoline-armv8.pl)
|
||||
perlasm(test/trampoline-ppc.${ASM_EXT} test/asm/trampoline-ppc.pl)
|
||||
perlasm(test/trampoline-x86.${ASM_EXT} test/asm/trampoline-x86.pl)
|
||||
perlasm(test/trampoline-x86_64.${ASM_EXT} test/asm/trampoline-x86_64.pl)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT err_data.c
|
||||
COMMAND ${GO_EXECUTABLE} run err_data_generate.go > ${CMAKE_CURRENT_BINARY_DIR}/err_data.c
|
||||
DEPENDS
|
||||
err/err_data_generate.go
|
||||
err/asn1.errordata
|
||||
err/bio.errordata
|
||||
err/bn.errordata
|
||||
err/cipher.errordata
|
||||
err/conf.errordata
|
||||
err/dh.errordata
|
||||
err/digest.errordata
|
||||
err/dsa.errordata
|
||||
err/ecdh.errordata
|
||||
err/ecdsa.errordata
|
||||
err/ec.errordata
|
||||
err/engine.errordata
|
||||
err/evp.errordata
|
||||
err/hkdf.errordata
|
||||
err/obj.errordata
|
||||
err/pem.errordata
|
||||
err/pkcs7.errordata
|
||||
err/pkcs8.errordata
|
||||
err/rsa.errordata
|
||||
err/ssl.errordata
|
||||
err/trust_token.errordata
|
||||
err/x509.errordata
|
||||
err/x509v3.errordata
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/err
|
||||
)
|
||||
|
||||
add_library(
|
||||
crypto
|
||||
|
||||
asn1/a_bitstr.c
|
||||
asn1/a_bool.c
|
||||
asn1/a_d2i_fp.c
|
||||
asn1/a_dup.c
|
||||
asn1/a_enum.c
|
||||
asn1/a_gentm.c
|
||||
asn1/a_i2d_fp.c
|
||||
asn1/a_int.c
|
||||
asn1/a_mbstr.c
|
||||
asn1/a_object.c
|
||||
asn1/a_octet.c
|
||||
asn1/a_print.c
|
||||
asn1/a_strnid.c
|
||||
asn1/a_time.c
|
||||
asn1/a_type.c
|
||||
asn1/a_utctm.c
|
||||
asn1/a_utf8.c
|
||||
asn1/asn1_lib.c
|
||||
asn1/asn1_par.c
|
||||
asn1/asn_pack.c
|
||||
asn1/f_enum.c
|
||||
asn1/f_int.c
|
||||
asn1/f_string.c
|
||||
asn1/tasn_dec.c
|
||||
asn1/tasn_enc.c
|
||||
asn1/tasn_fre.c
|
||||
asn1/tasn_new.c
|
||||
asn1/tasn_typ.c
|
||||
asn1/tasn_utl.c
|
||||
asn1/time_support.c
|
||||
base64/base64.c
|
||||
bio/bio.c
|
||||
bio/bio_mem.c
|
||||
bio/connect.c
|
||||
bio/fd.c
|
||||
bio/file.c
|
||||
bio/hexdump.c
|
||||
bio/pair.c
|
||||
bio/printf.c
|
||||
bio/socket.c
|
||||
bio/socket_helper.c
|
||||
bn_extra/bn_asn1.c
|
||||
bn_extra/convert.c
|
||||
buf/buf.c
|
||||
bytestring/asn1_compat.c
|
||||
bytestring/ber.c
|
||||
bytestring/cbb.c
|
||||
bytestring/cbs.c
|
||||
bytestring/unicode.c
|
||||
chacha/chacha.c
|
||||
cipher_extra/cipher_extra.c
|
||||
cipher_extra/derive_key.c
|
||||
cipher_extra/e_aesccm.c
|
||||
cipher_extra/e_aesctrhmac.c
|
||||
cipher_extra/e_aesgcmsiv.c
|
||||
cipher_extra/e_chacha20poly1305.c
|
||||
cipher_extra/e_null.c
|
||||
cipher_extra/e_rc2.c
|
||||
cipher_extra/e_rc4.c
|
||||
cipher_extra/e_tls.c
|
||||
cipher_extra/tls_cbc.c
|
||||
cmac/cmac.c
|
||||
conf/conf.c
|
||||
cpu-aarch64-fuchsia.c
|
||||
cpu-aarch64-linux.c
|
||||
cpu-arm-linux.c
|
||||
cpu-arm.c
|
||||
cpu-arm-linux.c
|
||||
cpu-intel.c
|
||||
cpu-ppc64le.c
|
||||
crypto.c
|
||||
curve25519/curve25519.c
|
||||
curve25519/spake25519.c
|
||||
dh/dh.c
|
||||
dh/params.c
|
||||
dh/check.c
|
||||
dh/dh_asn1.c
|
||||
digest_extra/digest_extra.c
|
||||
dsa/dsa.c
|
||||
dsa/dsa_asn1.c
|
||||
ecdh_extra/ecdh_extra.c
|
||||
ecdsa_extra/ecdsa_asn1.c
|
||||
ec_extra/ec_asn1.c
|
||||
ec_extra/ec_derive.c
|
||||
ec_extra/hash_to_curve.c
|
||||
err/err.c
|
||||
err_data.c
|
||||
engine/engine.c
|
||||
evp/digestsign.c
|
||||
evp/evp.c
|
||||
evp/evp_asn1.c
|
||||
evp/evp_ctx.c
|
||||
evp/p_dsa_asn1.c
|
||||
evp/p_ec.c
|
||||
evp/p_ec_asn1.c
|
||||
evp/p_ed25519.c
|
||||
evp/p_ed25519_asn1.c
|
||||
evp/p_rsa.c
|
||||
evp/p_rsa_asn1.c
|
||||
evp/p_x25519.c
|
||||
evp/p_x25519_asn1.c
|
||||
evp/pbkdf.c
|
||||
evp/print.c
|
||||
evp/scrypt.c
|
||||
evp/sign.c
|
||||
directory_posix.c
|
||||
directory_win.c
|
||||
ex_data.c
|
||||
hkdf/hkdf.c
|
||||
hpke/hpke.c
|
||||
hrss/hrss.c
|
||||
lhash/lhash.c
|
||||
mem.c
|
||||
obj/obj.c
|
||||
obj/obj_xref.c
|
||||
pem/pem_all.c
|
||||
pem/pem_info.c
|
||||
pem/pem_lib.c
|
||||
pem/pem_oth.c
|
||||
pem/pem_pk8.c
|
||||
pem/pem_pkey.c
|
||||
pem/pem_x509.c
|
||||
pem/pem_xaux.c
|
||||
pkcs7/pkcs7.c
|
||||
pkcs7/pkcs7_x509.c
|
||||
pkcs8/pkcs8.c
|
||||
pkcs8/pkcs8_x509.c
|
||||
pkcs8/p5_pbev2.c
|
||||
poly1305/poly1305.c
|
||||
poly1305/poly1305_arm.c
|
||||
poly1305/poly1305_vec.c
|
||||
pool/pool.c
|
||||
rand_extra/deterministic.c
|
||||
rand_extra/forkunsafe.c
|
||||
rand_extra/fuchsia.c
|
||||
rand_extra/rand_extra.c
|
||||
rand_extra/windows.c
|
||||
rc4/rc4.c
|
||||
refcount_c11.c
|
||||
refcount_lock.c
|
||||
rsa_extra/rsa_asn1.c
|
||||
rsa_extra/rsa_print.c
|
||||
stack/stack.c
|
||||
siphash/siphash.c
|
||||
thread.c
|
||||
thread_none.c
|
||||
thread_pthread.c
|
||||
thread_win.c
|
||||
trust_token/pmbtoken.c
|
||||
trust_token/trust_token.c
|
||||
x509/a_digest.c
|
||||
x509/a_sign.c
|
||||
x509/a_strex.c
|
||||
x509/a_verify.c
|
||||
x509/algorithm.c
|
||||
x509/asn1_gen.c
|
||||
x509/by_dir.c
|
||||
x509/by_file.c
|
||||
x509/i2d_pr.c
|
||||
x509/rsa_pss.c
|
||||
x509/t_crl.c
|
||||
x509/t_req.c
|
||||
x509/t_x509.c
|
||||
x509/t_x509a.c
|
||||
x509/x509.c
|
||||
x509/x509_att.c
|
||||
x509/x509_cmp.c
|
||||
x509/x509_d2.c
|
||||
x509/x509_def.c
|
||||
x509/x509_ext.c
|
||||
x509/x509_lu.c
|
||||
x509/x509_obj.c
|
||||
x509/x509_r2x.c
|
||||
x509/x509_req.c
|
||||
x509/x509_set.c
|
||||
x509/x509_trs.c
|
||||
x509/x509_txt.c
|
||||
x509/x509_v3.c
|
||||
x509/x509_vfy.c
|
||||
x509/x509_vpm.c
|
||||
x509/x509cset.c
|
||||
x509/x509name.c
|
||||
x509/x509rset.c
|
||||
x509/x509spki.c
|
||||
x509/x_algor.c
|
||||
x509/x_all.c
|
||||
x509/x_attrib.c
|
||||
x509/x_crl.c
|
||||
x509/x_exten.c
|
||||
x509/x_info.c
|
||||
x509/x_name.c
|
||||
x509/x_pkey.c
|
||||
x509/x_pubkey.c
|
||||
x509/x_req.c
|
||||
x509/x_sig.c
|
||||
x509/x_spki.c
|
||||
x509/x_val.c
|
||||
x509/x_x509.c
|
||||
x509/x_x509a.c
|
||||
x509v3/pcy_cache.c
|
||||
x509v3/pcy_data.c
|
||||
x509v3/pcy_lib.c
|
||||
x509v3/pcy_map.c
|
||||
x509v3/pcy_node.c
|
||||
x509v3/pcy_tree.c
|
||||
x509v3/v3_akey.c
|
||||
x509v3/v3_akeya.c
|
||||
x509v3/v3_alt.c
|
||||
x509v3/v3_bcons.c
|
||||
x509v3/v3_bitst.c
|
||||
x509v3/v3_conf.c
|
||||
x509v3/v3_cpols.c
|
||||
x509v3/v3_crld.c
|
||||
x509v3/v3_enum.c
|
||||
x509v3/v3_extku.c
|
||||
x509v3/v3_genn.c
|
||||
x509v3/v3_ia5.c
|
||||
x509v3/v3_info.c
|
||||
x509v3/v3_int.c
|
||||
x509v3/v3_lib.c
|
||||
x509v3/v3_ncons.c
|
||||
x509v3/v3_ocsp.c
|
||||
x509v3/v3_pci.c
|
||||
x509v3/v3_pcia.c
|
||||
x509v3/v3_pcons.c
|
||||
x509v3/v3_pku.c
|
||||
x509v3/v3_pmaps.c
|
||||
x509v3/v3_prn.c
|
||||
x509v3/v3_purp.c
|
||||
x509v3/v3_skey.c
|
||||
x509v3/v3_sxnet.c
|
||||
x509v3/v3_utl.c
|
||||
time_support.c
|
||||
|
||||
$<TARGET_OBJECTS:fipsmodule>
|
||||
|
||||
${CRYPTO_ARCH_SOURCES}
|
||||
${CRYPTO_FIPS_OBJECTS}
|
||||
$<TARGET_OBJECTS:stack>
|
||||
$<TARGET_OBJECTS:lhash>
|
||||
$<TARGET_OBJECTS:err>
|
||||
$<TARGET_OBJECTS:base64>
|
||||
$<TARGET_OBJECTS:bytestring>
|
||||
$<TARGET_OBJECTS:sha>
|
||||
$<TARGET_OBJECTS:md4>
|
||||
$<TARGET_OBJECTS:md5>
|
||||
$<TARGET_OBJECTS:digest>
|
||||
$<TARGET_OBJECTS:cipher>
|
||||
$<TARGET_OBJECTS:modes>
|
||||
$<TARGET_OBJECTS:aes>
|
||||
$<TARGET_OBJECTS:des>
|
||||
$<TARGET_OBJECTS:rc4>
|
||||
$<TARGET_OBJECTS:conf>
|
||||
$<TARGET_OBJECTS:chacha>
|
||||
$<TARGET_OBJECTS:poly1305>
|
||||
$<TARGET_OBJECTS:curve25519>
|
||||
$<TARGET_OBJECTS:buf>
|
||||
$<TARGET_OBJECTS:bn>
|
||||
$<TARGET_OBJECTS:bio>
|
||||
$<TARGET_OBJECTS:rand>
|
||||
$<TARGET_OBJECTS:obj>
|
||||
$<TARGET_OBJECTS:asn1>
|
||||
$<TARGET_OBJECTS:engine>
|
||||
$<TARGET_OBJECTS:dh>
|
||||
$<TARGET_OBJECTS:dsa>
|
||||
$<TARGET_OBJECTS:rsa>
|
||||
$<TARGET_OBJECTS:ec>
|
||||
$<TARGET_OBJECTS:ecdh>
|
||||
$<TARGET_OBJECTS:ecdsa>
|
||||
$<TARGET_OBJECTS:hmac>
|
||||
$<TARGET_OBJECTS:cmac>
|
||||
$<TARGET_OBJECTS:evp>
|
||||
$<TARGET_OBJECTS:hkdf>
|
||||
$<TARGET_OBJECTS:pem>
|
||||
$<TARGET_OBJECTS:x509>
|
||||
$<TARGET_OBJECTS:x509v3>
|
||||
$<TARGET_OBJECTS:pkcs8>
|
||||
)
|
||||
|
||||
if(FIPS_SHARED)
|
||||
set(EXTRA_INJECT_HASH_ARGS)
|
||||
if(ANDROID)
|
||||
set(EXTRA_INJECT_HASH_ARGS "-sha256")
|
||||
endif()
|
||||
# Rewrite libcrypto.so to inject the correct module hash value. This assumes
|
||||
# UNIX-style library naming, but we only support FIPS mode on Linux anyway.
|
||||
add_custom_command(
|
||||
TARGET crypto POST_BUILD
|
||||
COMMAND ${GO_EXECUTABLE} run
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../util/fipstools/inject_hash/inject_hash.go
|
||||
-o libcrypto.so -in-object libcrypto.so ${EXTRA_INJECT_HASH_ARGS}
|
||||
# The DEPENDS argument to a POST_BUILD rule appears to be ignored. Thus
|
||||
# go_executable isn't used (as it doesn't get built), but we list this
|
||||
# dependency anyway in case it starts working in some CMake version.
|
||||
DEPENDS ../util/fipstools/inject_hash/inject_hash.go
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
add_dependencies(crypto global_target)
|
||||
|
||||
if(FIPS_DELOCATE OR FIPS_SHARED)
|
||||
add_dependencies(crypto bcm_o_target)
|
||||
endif()
|
||||
|
||||
SET_TARGET_PROPERTIES(crypto PROPERTIES LINKER_LANGUAGE C)
|
||||
|
||||
if(NOT WIN32 AND NOT ANDROID)
|
||||
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()
|
||||
|
||||
# urandom_test is a separate binary because it needs to be able to observe the
|
||||
# PRNG initialisation, which means that it can't have other tests running before
|
||||
# it does.
|
||||
add_executable(
|
||||
urandom_test
|
||||
constant_time_test
|
||||
|
||||
fipsmodule/rand/urandom_test.cc
|
||||
constant_time_test.c
|
||||
|
||||
$<TARGET_OBJECTS:test_support>
|
||||
)
|
||||
|
||||
target_link_libraries(urandom_test test_support_lib boringssl_gtest crypto)
|
||||
|
||||
add_dependencies(urandom_test global_target)
|
||||
add_dependencies(all_tests urandom_test)
|
||||
target_link_libraries(constant_time_test crypto)
|
||||
add_dependencies(all_tests constant_time_test)
|
||||
|
||||
add_executable(
|
||||
crypto_test
|
||||
thread_test
|
||||
|
||||
abi_self_test.cc
|
||||
asn1/asn1_test.cc
|
||||
base64/base64_test.cc
|
||||
buf/buf_test.cc
|
||||
bio/bio_test.cc
|
||||
bytestring/bytestring_test.cc
|
||||
chacha/chacha_test.cc
|
||||
cipher_extra/aead_test.cc
|
||||
cipher_extra/cipher_test.cc
|
||||
cmac/cmac_test.cc
|
||||
compiler_test.cc
|
||||
constant_time_test.cc
|
||||
cpu-arm-linux_test.cc
|
||||
curve25519/ed25519_test.cc
|
||||
curve25519/spake25519_test.cc
|
||||
curve25519/x25519_test.cc
|
||||
ecdh_extra/ecdh_test.cc
|
||||
dh/dh_test.cc
|
||||
digest_extra/digest_test.cc
|
||||
dsa/dsa_test.cc
|
||||
err/err_test.cc
|
||||
evp/evp_extra_test.cc
|
||||
evp/evp_test.cc
|
||||
evp/pbkdf_test.cc
|
||||
evp/scrypt_test.cc
|
||||
fipsmodule/aes/aes_test.cc
|
||||
fipsmodule/bn/bn_test.cc
|
||||
fipsmodule/ec/ec_test.cc
|
||||
fipsmodule/ec/p256-x86_64_test.cc
|
||||
fipsmodule/ecdsa/ecdsa_test.cc
|
||||
fipsmodule/md5/md5_test.cc
|
||||
fipsmodule/modes/gcm_test.cc
|
||||
fipsmodule/rand/ctrdrbg_test.cc
|
||||
fipsmodule/rand/fork_detect_test.cc
|
||||
fipsmodule/sha/sha_test.cc
|
||||
hkdf/hkdf_test.cc
|
||||
hpke/hpke_test.cc
|
||||
hmac_extra/hmac_test.cc
|
||||
hrss/hrss_test.cc
|
||||
impl_dispatch_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
|
||||
poly1305/poly1305_test.cc
|
||||
pool/pool_test.cc
|
||||
rand_extra/rand_test.cc
|
||||
refcount_test.cc
|
||||
rsa_extra/rsa_test.cc
|
||||
self_test.cc
|
||||
stack/stack_test.cc
|
||||
siphash/siphash_test.cc
|
||||
test/file_test_gtest.cc
|
||||
thread_test.cc
|
||||
trust_token/trust_token_test.cc
|
||||
x509/x509_test.cc
|
||||
x509/x509_time_test.cc
|
||||
x509v3/tab_test.cc
|
||||
x509v3/v3name_test.cc
|
||||
thread_test.c
|
||||
|
||||
$<TARGET_OBJECTS:crypto_test_data>
|
||||
$<TARGET_OBJECTS:boringssl_gtest_main>
|
||||
$<TARGET_OBJECTS:test_support>
|
||||
)
|
||||
|
||||
add_dependencies(crypto_test global_target)
|
||||
target_link_libraries(thread_test crypto)
|
||||
add_dependencies(all_tests thread_test)
|
||||
|
||||
target_link_libraries(crypto_test test_support_lib boringssl_gtest crypto)
|
||||
if(WIN32)
|
||||
target_link_libraries(crypto_test ws2_32)
|
||||
endif()
|
||||
add_dependencies(all_tests crypto_test)
|
||||
add_executable(
|
||||
refcount_test
|
||||
|
||||
refcount_test.c
|
||||
)
|
||||
|
||||
target_link_libraries(refcount_test crypto)
|
||||
add_dependencies(all_tests refcount_test)
|
||||
|
||||
@@ -1,808 +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 <gtest/gtest.h>
|
||||
#include <gtest/gtest-spi.h>
|
||||
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "test/abi_test.h"
|
||||
|
||||
|
||||
static bool test_function_ok;
|
||||
static int TestFunction(int a1, int a2, int a3, int a4, int a5, int a6, int a7,
|
||||
int a8) {
|
||||
test_function_ok = a1 == 1 || a2 == 2 || a3 == 3 || a4 == 4 || a5 == 5 ||
|
||||
a6 == 6 || a7 == 7 || a8 == 8;
|
||||
return 42;
|
||||
}
|
||||
|
||||
TEST(ABITest, SanityCheck) {
|
||||
EXPECT_NE(0, CHECK_ABI_NO_UNWIND(strcmp, "hello", "world"));
|
||||
|
||||
test_function_ok = false;
|
||||
EXPECT_EQ(42, CHECK_ABI_SEH(TestFunction, 1, 2, 3, 4, 5, 6, 7, 8));
|
||||
EXPECT_TRUE(test_function_ok);
|
||||
|
||||
#if defined(SUPPORTS_ABI_TEST)
|
||||
abi_test::internal::CallerState state;
|
||||
RAND_bytes(reinterpret_cast<uint8_t *>(&state), sizeof(state));
|
||||
crypto_word_t argv[] = {
|
||||
1, 2, 3, 4, 5, 6, 7, 8,
|
||||
};
|
||||
CHECK_ABI_SEH(abi_test_trampoline,
|
||||
reinterpret_cast<crypto_word_t>(TestFunction), &state, argv, 8,
|
||||
0 /* no breakpoint */);
|
||||
|
||||
#if defined(OPENSSL_X86_64)
|
||||
if (abi_test::UnwindTestsEnabled()) {
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_SEH(abi_test_bad_unwind_wrong_register),
|
||||
"was not recovered");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_SEH(abi_test_bad_unwind_temporary),
|
||||
"was not recovered");
|
||||
|
||||
CHECK_ABI_NO_UNWIND(abi_test_bad_unwind_wrong_register);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_bad_unwind_temporary);
|
||||
|
||||
#if defined(OPENSSL_WINDOWS)
|
||||
// The invalid epilog makes Windows believe the epilog starts later than it
|
||||
// actually does. As a result, immediately after the popq, it does not
|
||||
// realize the stack has been unwound and repeats the work.
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_SEH(abi_test_bad_unwind_epilog),
|
||||
"unwound past starting frame");
|
||||
CHECK_ABI_NO_UNWIND(abi_test_bad_unwind_epilog);
|
||||
#endif // OPENSSL_WINDOWS
|
||||
}
|
||||
#endif // OPENSSL_X86_64
|
||||
#endif // SUPPORTS_ABI_TEST
|
||||
}
|
||||
|
||||
#if defined(OPENSSL_X86_64) && defined(SUPPORTS_ABI_TEST)
|
||||
extern "C" {
|
||||
void abi_test_clobber_rax(void);
|
||||
void abi_test_clobber_rbx(void);
|
||||
void abi_test_clobber_rcx(void);
|
||||
void abi_test_clobber_rdx(void);
|
||||
void abi_test_clobber_rsi(void);
|
||||
void abi_test_clobber_rdi(void);
|
||||
void abi_test_clobber_rbp(void);
|
||||
void abi_test_clobber_r8(void);
|
||||
void abi_test_clobber_r9(void);
|
||||
void abi_test_clobber_r10(void);
|
||||
void abi_test_clobber_r11(void);
|
||||
void abi_test_clobber_r12(void);
|
||||
void abi_test_clobber_r13(void);
|
||||
void abi_test_clobber_r14(void);
|
||||
void abi_test_clobber_r15(void);
|
||||
void abi_test_clobber_xmm0(void);
|
||||
void abi_test_clobber_xmm1(void);
|
||||
void abi_test_clobber_xmm2(void);
|
||||
void abi_test_clobber_xmm3(void);
|
||||
void abi_test_clobber_xmm4(void);
|
||||
void abi_test_clobber_xmm5(void);
|
||||
void abi_test_clobber_xmm6(void);
|
||||
void abi_test_clobber_xmm7(void);
|
||||
void abi_test_clobber_xmm8(void);
|
||||
void abi_test_clobber_xmm9(void);
|
||||
void abi_test_clobber_xmm10(void);
|
||||
void abi_test_clobber_xmm11(void);
|
||||
void abi_test_clobber_xmm12(void);
|
||||
void abi_test_clobber_xmm13(void);
|
||||
void abi_test_clobber_xmm14(void);
|
||||
void abi_test_clobber_xmm15(void);
|
||||
} // extern "C"
|
||||
|
||||
TEST(ABITest, X86_64) {
|
||||
// abi_test_trampoline hides unsaved registers from the caller, so we can
|
||||
// safely call the abi_test_clobber_* functions below.
|
||||
abi_test::internal::CallerState state;
|
||||
RAND_bytes(reinterpret_cast<uint8_t *>(&state), sizeof(state));
|
||||
CHECK_ABI_NO_UNWIND(abi_test_trampoline,
|
||||
reinterpret_cast<crypto_word_t>(abi_test_clobber_rbx),
|
||||
&state, nullptr, 0, 0 /* no breakpoint */);
|
||||
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_rax);
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_rbx),
|
||||
"rbx was not restored after return");
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_rcx);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_rdx);
|
||||
#if defined(OPENSSL_WINDOWS)
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_rdi),
|
||||
"rdi was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_rsi),
|
||||
"rsi was not restored after return");
|
||||
#else
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_rdi);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_rsi);
|
||||
#endif
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_rbp),
|
||||
"rbp was not restored after return");
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_r8);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_r9);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_r10);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_r11);
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r12),
|
||||
"r12 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r13),
|
||||
"r13 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r14),
|
||||
"r14 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r15),
|
||||
"r15 was not restored after return");
|
||||
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm0);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm1);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm2);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm3);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm4);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm5);
|
||||
#if defined(OPENSSL_WINDOWS)
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm6),
|
||||
"xmm6 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm7),
|
||||
"xmm7 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm8),
|
||||
"xmm8 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm9),
|
||||
"xmm9 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm10),
|
||||
"xmm10 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm11),
|
||||
"xmm11 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm12),
|
||||
"xmm12 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm13),
|
||||
"xmm13 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm14),
|
||||
"xmm14 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm15),
|
||||
"xmm15 was not restored after return");
|
||||
#else
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm6);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm7);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm8);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm9);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm10);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm11);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm12);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm13);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm14);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm15);
|
||||
#endif
|
||||
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_set_direction_flag),
|
||||
"Direction flag set after return");
|
||||
EXPECT_EQ(0, abi_test_get_and_clear_direction_flag())
|
||||
<< "CHECK_ABI did not insulate the caller from direction flag errors";
|
||||
}
|
||||
#endif // OPENSSL_X86_64 && SUPPORTS_ABI_TEST
|
||||
|
||||
#if defined(OPENSSL_X86) && defined(SUPPORTS_ABI_TEST)
|
||||
extern "C" {
|
||||
void abi_test_clobber_eax(void);
|
||||
void abi_test_clobber_ebx(void);
|
||||
void abi_test_clobber_ecx(void);
|
||||
void abi_test_clobber_edx(void);
|
||||
void abi_test_clobber_esi(void);
|
||||
void abi_test_clobber_edi(void);
|
||||
void abi_test_clobber_ebp(void);
|
||||
void abi_test_clobber_xmm0(void);
|
||||
void abi_test_clobber_xmm1(void);
|
||||
void abi_test_clobber_xmm2(void);
|
||||
void abi_test_clobber_xmm3(void);
|
||||
void abi_test_clobber_xmm4(void);
|
||||
void abi_test_clobber_xmm5(void);
|
||||
void abi_test_clobber_xmm6(void);
|
||||
void abi_test_clobber_xmm7(void);
|
||||
} // extern "C"
|
||||
|
||||
TEST(ABITest, X86) {
|
||||
// abi_test_trampoline hides unsaved registers from the caller, so we can
|
||||
// safely call the abi_test_clobber_* functions below.
|
||||
abi_test::internal::CallerState state;
|
||||
RAND_bytes(reinterpret_cast<uint8_t *>(&state), sizeof(state));
|
||||
CHECK_ABI_NO_UNWIND(abi_test_trampoline,
|
||||
reinterpret_cast<crypto_word_t>(abi_test_clobber_ebx),
|
||||
&state, nullptr, 0, 0 /* no breakpoint */);
|
||||
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_eax);
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_ebx),
|
||||
"ebx was not restored after return");
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_ecx);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_edx);
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_edi),
|
||||
"edi was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_esi),
|
||||
"esi was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_ebp),
|
||||
"ebp was not restored after return");
|
||||
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm0);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm1);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm2);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm3);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm4);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm5);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm6);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm7);
|
||||
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_set_direction_flag),
|
||||
"Direction flag set after return");
|
||||
EXPECT_EQ(0, abi_test_get_and_clear_direction_flag())
|
||||
<< "CHECK_ABI did not insulate the caller from direction flag errors";
|
||||
}
|
||||
#endif // OPENSSL_X86 && SUPPORTS_ABI_TEST
|
||||
|
||||
#if defined(OPENSSL_ARM) && defined(SUPPORTS_ABI_TEST)
|
||||
extern "C" {
|
||||
void abi_test_clobber_r0(void);
|
||||
void abi_test_clobber_r1(void);
|
||||
void abi_test_clobber_r2(void);
|
||||
void abi_test_clobber_r3(void);
|
||||
void abi_test_clobber_r4(void);
|
||||
void abi_test_clobber_r5(void);
|
||||
void abi_test_clobber_r6(void);
|
||||
void abi_test_clobber_r7(void);
|
||||
void abi_test_clobber_r8(void);
|
||||
void abi_test_clobber_r9(void);
|
||||
void abi_test_clobber_r10(void);
|
||||
void abi_test_clobber_r11(void);
|
||||
void abi_test_clobber_r12(void);
|
||||
// r13, r14, and r15, are sp, lr, and pc, respectively.
|
||||
|
||||
void abi_test_clobber_d0(void);
|
||||
void abi_test_clobber_d1(void);
|
||||
void abi_test_clobber_d2(void);
|
||||
void abi_test_clobber_d3(void);
|
||||
void abi_test_clobber_d4(void);
|
||||
void abi_test_clobber_d5(void);
|
||||
void abi_test_clobber_d6(void);
|
||||
void abi_test_clobber_d7(void);
|
||||
void abi_test_clobber_d8(void);
|
||||
void abi_test_clobber_d9(void);
|
||||
void abi_test_clobber_d10(void);
|
||||
void abi_test_clobber_d11(void);
|
||||
void abi_test_clobber_d12(void);
|
||||
void abi_test_clobber_d13(void);
|
||||
void abi_test_clobber_d14(void);
|
||||
void abi_test_clobber_d15(void);
|
||||
} // extern "C"
|
||||
|
||||
TEST(ABITest, ARM) {
|
||||
// abi_test_trampoline hides unsaved registers from the caller, so we can
|
||||
// safely call the abi_test_clobber_* functions below.
|
||||
abi_test::internal::CallerState state;
|
||||
RAND_bytes(reinterpret_cast<uint8_t *>(&state), sizeof(state));
|
||||
CHECK_ABI_NO_UNWIND(abi_test_trampoline,
|
||||
reinterpret_cast<crypto_word_t>(abi_test_clobber_r4),
|
||||
&state, nullptr, 0, 0 /* no breakpoint */);
|
||||
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_r0);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_r1);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_r2);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_r3);
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r4),
|
||||
"r4 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r5),
|
||||
"r5 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r6),
|
||||
"r6 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r7),
|
||||
"r7 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r8),
|
||||
"r8 was not restored after return");
|
||||
#if defined(OPENSSL_APPLE)
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_r9);
|
||||
#else
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r9),
|
||||
"r9 was not restored after return");
|
||||
#endif
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r10),
|
||||
"r10 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r11),
|
||||
"r11 was not restored after return");
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_r12);
|
||||
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d0);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d1);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d2);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d3);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d4);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d5);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d6);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d7);
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_d8),
|
||||
"d8 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_d9),
|
||||
"d9 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_d10),
|
||||
"d10 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_d11),
|
||||
"d11 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_d12),
|
||||
"d12 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_d13),
|
||||
"d13 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_d14),
|
||||
"d14 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_d15),
|
||||
"d15 was not restored after return");
|
||||
}
|
||||
#endif // OPENSSL_ARM && SUPPORTS_ABI_TEST
|
||||
|
||||
#if defined(OPENSSL_AARCH64) && defined(SUPPORTS_ABI_TEST)
|
||||
extern "C" {
|
||||
void abi_test_clobber_x0(void);
|
||||
void abi_test_clobber_x1(void);
|
||||
void abi_test_clobber_x2(void);
|
||||
void abi_test_clobber_x3(void);
|
||||
void abi_test_clobber_x4(void);
|
||||
void abi_test_clobber_x5(void);
|
||||
void abi_test_clobber_x6(void);
|
||||
void abi_test_clobber_x7(void);
|
||||
void abi_test_clobber_x8(void);
|
||||
void abi_test_clobber_x9(void);
|
||||
void abi_test_clobber_x10(void);
|
||||
void abi_test_clobber_x11(void);
|
||||
void abi_test_clobber_x12(void);
|
||||
void abi_test_clobber_x13(void);
|
||||
void abi_test_clobber_x14(void);
|
||||
void abi_test_clobber_x15(void);
|
||||
void abi_test_clobber_x16(void);
|
||||
void abi_test_clobber_x17(void);
|
||||
// x18 is the platform register and off limits.
|
||||
void abi_test_clobber_x19(void);
|
||||
void abi_test_clobber_x20(void);
|
||||
void abi_test_clobber_x21(void);
|
||||
void abi_test_clobber_x22(void);
|
||||
void abi_test_clobber_x23(void);
|
||||
void abi_test_clobber_x24(void);
|
||||
void abi_test_clobber_x25(void);
|
||||
void abi_test_clobber_x26(void);
|
||||
void abi_test_clobber_x27(void);
|
||||
void abi_test_clobber_x28(void);
|
||||
void abi_test_clobber_x29(void);
|
||||
|
||||
void abi_test_clobber_d0(void);
|
||||
void abi_test_clobber_d1(void);
|
||||
void abi_test_clobber_d2(void);
|
||||
void abi_test_clobber_d3(void);
|
||||
void abi_test_clobber_d4(void);
|
||||
void abi_test_clobber_d5(void);
|
||||
void abi_test_clobber_d6(void);
|
||||
void abi_test_clobber_d7(void);
|
||||
void abi_test_clobber_d8(void);
|
||||
void abi_test_clobber_d9(void);
|
||||
void abi_test_clobber_d10(void);
|
||||
void abi_test_clobber_d11(void);
|
||||
void abi_test_clobber_d12(void);
|
||||
void abi_test_clobber_d13(void);
|
||||
void abi_test_clobber_d14(void);
|
||||
void abi_test_clobber_d15(void);
|
||||
void abi_test_clobber_d16(void);
|
||||
void abi_test_clobber_d17(void);
|
||||
void abi_test_clobber_d18(void);
|
||||
void abi_test_clobber_d19(void);
|
||||
void abi_test_clobber_d20(void);
|
||||
void abi_test_clobber_d21(void);
|
||||
void abi_test_clobber_d22(void);
|
||||
void abi_test_clobber_d23(void);
|
||||
void abi_test_clobber_d24(void);
|
||||
void abi_test_clobber_d25(void);
|
||||
void abi_test_clobber_d26(void);
|
||||
void abi_test_clobber_d27(void);
|
||||
void abi_test_clobber_d28(void);
|
||||
void abi_test_clobber_d29(void);
|
||||
void abi_test_clobber_d30(void);
|
||||
void abi_test_clobber_d31(void);
|
||||
|
||||
void abi_test_clobber_v8_upper(void);
|
||||
void abi_test_clobber_v9_upper(void);
|
||||
void abi_test_clobber_v10_upper(void);
|
||||
void abi_test_clobber_v11_upper(void);
|
||||
void abi_test_clobber_v12_upper(void);
|
||||
void abi_test_clobber_v13_upper(void);
|
||||
void abi_test_clobber_v14_upper(void);
|
||||
void abi_test_clobber_v15_upper(void);
|
||||
} // extern "C"
|
||||
|
||||
TEST(ABITest, AArch64) {
|
||||
// abi_test_trampoline hides unsaved registers from the caller, so we can
|
||||
// safely call the abi_test_clobber_* functions below.
|
||||
abi_test::internal::CallerState state;
|
||||
RAND_bytes(reinterpret_cast<uint8_t *>(&state), sizeof(state));
|
||||
CHECK_ABI_NO_UNWIND(abi_test_trampoline,
|
||||
reinterpret_cast<crypto_word_t>(abi_test_clobber_x19),
|
||||
&state, nullptr, 0, 0 /* no breakpoint */);
|
||||
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_x0);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_x1);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_x2);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_x3);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_x4);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_x5);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_x6);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_x7);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_x8);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_x9);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_x10);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_x11);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_x12);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_x13);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_x14);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_x15);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_x16);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_x17);
|
||||
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_x19),
|
||||
"x19 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_x20),
|
||||
"x20 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_x21),
|
||||
"x21 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_x22),
|
||||
"x22 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_x23),
|
||||
"x23 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_x24),
|
||||
"x24 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_x25),
|
||||
"x25 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_x26),
|
||||
"x26 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_x27),
|
||||
"x27 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_x28),
|
||||
"x28 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_x29),
|
||||
"x29 was not restored after return");
|
||||
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d0);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d1);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d2);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d3);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d4);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d5);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d6);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d7);
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_d8),
|
||||
"d8 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_d9),
|
||||
"d9 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_d10),
|
||||
"d10 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_d11),
|
||||
"d11 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_d12),
|
||||
"d12 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_d13),
|
||||
"d13 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_d14),
|
||||
"d14 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_d15),
|
||||
"d15 was not restored after return");
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d16);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d18);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d19);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d20);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d21);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d22);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d23);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d24);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d25);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d26);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d27);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d28);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d29);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d30);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_d31);
|
||||
|
||||
// The lower halves of v8-v15 (accessed as d8-d15) must be preserved, but not
|
||||
// the upper halves.
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v8_upper);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v9_upper);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v10_upper);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v11_upper);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v12_upper);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v13_upper);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v14_upper);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v15_upper);
|
||||
}
|
||||
#endif // OPENSSL_AARCH64 && SUPPORTS_ABI_TEST
|
||||
|
||||
#if defined(OPENSSL_PPC64LE) && defined(SUPPORTS_ABI_TEST)
|
||||
extern "C" {
|
||||
void abi_test_clobber_r0(void);
|
||||
// r1 is the stack pointer.
|
||||
void abi_test_clobber_r2(void);
|
||||
void abi_test_clobber_r3(void);
|
||||
void abi_test_clobber_r4(void);
|
||||
void abi_test_clobber_r5(void);
|
||||
void abi_test_clobber_r6(void);
|
||||
void abi_test_clobber_r7(void);
|
||||
void abi_test_clobber_r8(void);
|
||||
void abi_test_clobber_r9(void);
|
||||
void abi_test_clobber_r10(void);
|
||||
void abi_test_clobber_r11(void);
|
||||
void abi_test_clobber_r12(void);
|
||||
// r13 is the thread pointer.
|
||||
void abi_test_clobber_r14(void);
|
||||
void abi_test_clobber_r15(void);
|
||||
void abi_test_clobber_r16(void);
|
||||
void abi_test_clobber_r17(void);
|
||||
void abi_test_clobber_r18(void);
|
||||
void abi_test_clobber_r19(void);
|
||||
void abi_test_clobber_r20(void);
|
||||
void abi_test_clobber_r21(void);
|
||||
void abi_test_clobber_r22(void);
|
||||
void abi_test_clobber_r23(void);
|
||||
void abi_test_clobber_r24(void);
|
||||
void abi_test_clobber_r25(void);
|
||||
void abi_test_clobber_r26(void);
|
||||
void abi_test_clobber_r27(void);
|
||||
void abi_test_clobber_r28(void);
|
||||
void abi_test_clobber_r29(void);
|
||||
void abi_test_clobber_r30(void);
|
||||
void abi_test_clobber_r31(void);
|
||||
|
||||
void abi_test_clobber_f0(void);
|
||||
void abi_test_clobber_f1(void);
|
||||
void abi_test_clobber_f2(void);
|
||||
void abi_test_clobber_f3(void);
|
||||
void abi_test_clobber_f4(void);
|
||||
void abi_test_clobber_f5(void);
|
||||
void abi_test_clobber_f6(void);
|
||||
void abi_test_clobber_f7(void);
|
||||
void abi_test_clobber_f8(void);
|
||||
void abi_test_clobber_f9(void);
|
||||
void abi_test_clobber_f10(void);
|
||||
void abi_test_clobber_f11(void);
|
||||
void abi_test_clobber_f12(void);
|
||||
void abi_test_clobber_f13(void);
|
||||
void abi_test_clobber_f14(void);
|
||||
void abi_test_clobber_f15(void);
|
||||
void abi_test_clobber_f16(void);
|
||||
void abi_test_clobber_f17(void);
|
||||
void abi_test_clobber_f18(void);
|
||||
void abi_test_clobber_f19(void);
|
||||
void abi_test_clobber_f20(void);
|
||||
void abi_test_clobber_f21(void);
|
||||
void abi_test_clobber_f22(void);
|
||||
void abi_test_clobber_f23(void);
|
||||
void abi_test_clobber_f24(void);
|
||||
void abi_test_clobber_f25(void);
|
||||
void abi_test_clobber_f26(void);
|
||||
void abi_test_clobber_f27(void);
|
||||
void abi_test_clobber_f28(void);
|
||||
void abi_test_clobber_f29(void);
|
||||
void abi_test_clobber_f30(void);
|
||||
void abi_test_clobber_f31(void);
|
||||
|
||||
void abi_test_clobber_v0(void);
|
||||
void abi_test_clobber_v1(void);
|
||||
void abi_test_clobber_v2(void);
|
||||
void abi_test_clobber_v3(void);
|
||||
void abi_test_clobber_v4(void);
|
||||
void abi_test_clobber_v5(void);
|
||||
void abi_test_clobber_v6(void);
|
||||
void abi_test_clobber_v7(void);
|
||||
void abi_test_clobber_v8(void);
|
||||
void abi_test_clobber_v9(void);
|
||||
void abi_test_clobber_v10(void);
|
||||
void abi_test_clobber_v11(void);
|
||||
void abi_test_clobber_v12(void);
|
||||
void abi_test_clobber_v13(void);
|
||||
void abi_test_clobber_v14(void);
|
||||
void abi_test_clobber_v15(void);
|
||||
void abi_test_clobber_v16(void);
|
||||
void abi_test_clobber_v17(void);
|
||||
void abi_test_clobber_v18(void);
|
||||
void abi_test_clobber_v19(void);
|
||||
void abi_test_clobber_v20(void);
|
||||
void abi_test_clobber_v21(void);
|
||||
void abi_test_clobber_v22(void);
|
||||
void abi_test_clobber_v23(void);
|
||||
void abi_test_clobber_v24(void);
|
||||
void abi_test_clobber_v25(void);
|
||||
void abi_test_clobber_v26(void);
|
||||
void abi_test_clobber_v27(void);
|
||||
void abi_test_clobber_v28(void);
|
||||
void abi_test_clobber_v29(void);
|
||||
void abi_test_clobber_v30(void);
|
||||
void abi_test_clobber_v31(void);
|
||||
|
||||
void abi_test_clobber_cr0(void);
|
||||
void abi_test_clobber_cr1(void);
|
||||
void abi_test_clobber_cr2(void);
|
||||
void abi_test_clobber_cr3(void);
|
||||
void abi_test_clobber_cr4(void);
|
||||
void abi_test_clobber_cr5(void);
|
||||
void abi_test_clobber_cr6(void);
|
||||
void abi_test_clobber_cr7(void);
|
||||
|
||||
void abi_test_clobber_ctr(void);
|
||||
void abi_test_clobber_lr(void);
|
||||
|
||||
} // extern "C"
|
||||
|
||||
TEST(ABITest, PPC64LE) {
|
||||
// abi_test_trampoline hides unsaved registers from the caller, so we can
|
||||
// safely call the abi_test_clobber_* functions below.
|
||||
abi_test::internal::CallerState state;
|
||||
RAND_bytes(reinterpret_cast<uint8_t *>(&state), sizeof(state));
|
||||
CHECK_ABI_NO_UNWIND(abi_test_trampoline,
|
||||
reinterpret_cast<crypto_word_t>(abi_test_clobber_r14),
|
||||
&state, nullptr, 0, 0 /* no breakpoint */);
|
||||
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_r0);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_r2);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_r3);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_r4);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_r5);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_r6);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_r7);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_r8);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_r9);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_r10);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_r11);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_r12);
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r14),
|
||||
"r14 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r15),
|
||||
"r15 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r16),
|
||||
"r16 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r17),
|
||||
"r17 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r18),
|
||||
"r18 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r19),
|
||||
"r19 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r20),
|
||||
"r20 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r21),
|
||||
"r21 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r22),
|
||||
"r22 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r23),
|
||||
"r23 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r24),
|
||||
"r24 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r25),
|
||||
"r25 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r26),
|
||||
"r26 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r27),
|
||||
"r27 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r28),
|
||||
"r28 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r29),
|
||||
"r29 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r30),
|
||||
"r30 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r31),
|
||||
"r31 was not restored after return");
|
||||
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_f0);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_f1);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_f2);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_f3);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_f4);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_f5);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_f6);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_f7);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_f8);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_f9);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_f10);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_f11);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_f12);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_f13);
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_f14),
|
||||
"f14 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_f15),
|
||||
"f15 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_f16),
|
||||
"f16 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_f17),
|
||||
"f17 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_f18),
|
||||
"f18 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_f19),
|
||||
"f19 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_f20),
|
||||
"f20 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_f21),
|
||||
"f21 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_f22),
|
||||
"f22 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_f23),
|
||||
"f23 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_f24),
|
||||
"f24 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_f25),
|
||||
"f25 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_f26),
|
||||
"f26 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_f27),
|
||||
"f27 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_f28),
|
||||
"f28 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_f29),
|
||||
"f29 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_f30),
|
||||
"f30 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_f31),
|
||||
"f31 was not restored after return");
|
||||
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v0);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v1);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v2);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v3);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v4);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v5);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v6);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v7);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v8);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v9);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v10);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v11);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v12);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v13);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v14);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v15);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v16);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v17);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v18);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_v19);
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_v20),
|
||||
"v20 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_v21),
|
||||
"v21 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_v22),
|
||||
"v22 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_v23),
|
||||
"v23 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_v24),
|
||||
"v24 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_v25),
|
||||
"v25 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_v26),
|
||||
"v26 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_v27),
|
||||
"v27 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_v28),
|
||||
"v28 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_v29),
|
||||
"v29 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_v30),
|
||||
"v30 was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_v31),
|
||||
"v31 was not restored after return");
|
||||
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_cr0);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_cr1);
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_cr2),
|
||||
"cr was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_cr3),
|
||||
"cr was not restored after return");
|
||||
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_cr4),
|
||||
"cr was not restored after return");
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_cr5);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_cr6);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_cr7);
|
||||
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_ctr);
|
||||
CHECK_ABI_NO_UNWIND(abi_test_clobber_lr);
|
||||
}
|
||||
#endif // OPENSSL_PPC64LE && SUPPORTS_ABI_TEST
|
||||
@@ -0,0 +1,72 @@
|
||||
include_directories(../../include)
|
||||
|
||||
if (${ARCH} STREQUAL "x86_64")
|
||||
set(
|
||||
AES_ARCH_SOURCES
|
||||
|
||||
aes-x86_64.${ASM_EXT}
|
||||
aesni-x86_64.${ASM_EXT}
|
||||
bsaes-x86_64.${ASM_EXT}
|
||||
vpaes-x86_64.${ASM_EXT}
|
||||
)
|
||||
endif()
|
||||
|
||||
if (${ARCH} STREQUAL "x86")
|
||||
set(
|
||||
AES_ARCH_SOURCES
|
||||
|
||||
aes-586.${ASM_EXT}
|
||||
vpaes-x86.${ASM_EXT}
|
||||
aesni-x86.${ASM_EXT}
|
||||
)
|
||||
endif()
|
||||
|
||||
if (${ARCH} STREQUAL "arm")
|
||||
set(
|
||||
AES_ARCH_SOURCES
|
||||
|
||||
aes-armv4.${ASM_EXT}
|
||||
bsaes-armv7.${ASM_EXT}
|
||||
aesv8-armx.${ASM_EXT}
|
||||
)
|
||||
endif()
|
||||
|
||||
if (${ARCH} STREQUAL "aarch64")
|
||||
set(
|
||||
AES_ARCH_SOURCES
|
||||
|
||||
aesv8-armx.${ASM_EXT}
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(
|
||||
aes
|
||||
|
||||
OBJECT
|
||||
|
||||
aes.c
|
||||
mode_wrappers.c
|
||||
|
||||
${AES_ARCH_SOURCES}
|
||||
)
|
||||
|
||||
perlasm(aes-x86_64.${ASM_EXT} asm/aes-x86_64.pl)
|
||||
perlasm(aesni-x86_64.${ASM_EXT} asm/aesni-x86_64.pl)
|
||||
perlasm(bsaes-x86_64.${ASM_EXT} asm/bsaes-x86_64.pl)
|
||||
perlasm(vpaes-x86_64.${ASM_EXT} asm/vpaes-x86_64.pl)
|
||||
perlasm(aes-586.${ASM_EXT} asm/aes-586.pl)
|
||||
perlasm(vpaes-x86.${ASM_EXT} asm/vpaes-x86.pl)
|
||||
perlasm(aesni-x86.${ASM_EXT} asm/aesni-x86.pl)
|
||||
perlasm(aes-armv4.${ASM_EXT} asm/aes-armv4.pl)
|
||||
perlasm(bsaes-armv7.${ASM_EXT} asm/bsaes-armv7.pl)
|
||||
perlasm(aesv8-armx.${ASM_EXT} asm/aesv8-armx.pl)
|
||||
|
||||
add_executable(
|
||||
aes_test
|
||||
|
||||
aes_test.cc
|
||||
$<TARGET_OBJECTS:test_support>
|
||||
)
|
||||
|
||||
target_link_libraries(aes_test crypto)
|
||||
add_dependencies(all_tests aes_test)
|
||||
+1142
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,102 @@
|
||||
/* Copyright (c) 2015, Google Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
|
||||
static bool TestAES(const uint8_t *key, size_t key_len,
|
||||
const uint8_t plaintext[AES_BLOCK_SIZE],
|
||||
const uint8_t ciphertext[AES_BLOCK_SIZE]) {
|
||||
AES_KEY aes_key;
|
||||
if (AES_set_encrypt_key(key, key_len * 8, &aes_key) != 0) {
|
||||
fprintf(stderr, "AES_set_encrypt_key failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test encryption.
|
||||
uint8_t block[AES_BLOCK_SIZE];
|
||||
AES_encrypt(plaintext, block, &aes_key);
|
||||
if (memcmp(block, ciphertext, AES_BLOCK_SIZE) != 0) {
|
||||
fprintf(stderr, "AES_encrypt gave the wrong output\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test in-place encryption.
|
||||
memcpy(block, plaintext, AES_BLOCK_SIZE);
|
||||
AES_encrypt(block, block, &aes_key);
|
||||
if (memcmp(block, ciphertext, AES_BLOCK_SIZE) != 0) {
|
||||
fprintf(stderr, "AES_encrypt gave the wrong output\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (AES_set_decrypt_key(key, key_len * 8, &aes_key) != 0) {
|
||||
fprintf(stderr, "AES_set_decrypt_key failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test decryption.
|
||||
AES_decrypt(ciphertext, block, &aes_key);
|
||||
if (memcmp(block, plaintext, AES_BLOCK_SIZE) != 0) {
|
||||
fprintf(stderr, "AES_decrypt gave the wrong output\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test in-place decryption.
|
||||
memcpy(block, ciphertext, AES_BLOCK_SIZE);
|
||||
AES_decrypt(block, block, &aes_key);
|
||||
if (memcmp(block, plaintext, AES_BLOCK_SIZE) != 0) {
|
||||
fprintf(stderr, "AES_decrypt gave the wrong output\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
CRYPTO_library_init();
|
||||
|
||||
// Test vectors from FIPS-197, Appendix C.
|
||||
if (!TestAES((const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07"
|
||||
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
|
||||
128 / 8,
|
||||
(const uint8_t *)"\x00\x11\x22\x33\x44\x55\x66\x77"
|
||||
"\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
|
||||
(const uint8_t *)"\x69\xc4\xe0\xd8\x6a\x7b\x04\x30"
|
||||
"\xd8\xcd\xb7\x80\x70\xb4\xc5\x5a") ||
|
||||
!TestAES((const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07"
|
||||
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
|
||||
"\x10\x11\x12\x13\x14\x15\x16\x17",
|
||||
192 / 8,
|
||||
(const uint8_t *)"\x00\x11\x22\x33\x44\x55\x66\x77"
|
||||
"\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
|
||||
(const uint8_t *)"\xdd\xa9\x7c\xa4\x86\x4c\xdf\xe0"
|
||||
"\x6e\xaf\x70\xa0\xec\x0d\x71\x91") ||
|
||||
!TestAES((const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07"
|
||||
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
|
||||
"\x10\x11\x12\x13\x14\x15\x16\x17"
|
||||
"\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
|
||||
256 / 8,
|
||||
(const uint8_t *)"\x00\x11\x22\x33\x44\x55\x66\x77"
|
||||
"\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
|
||||
(const uint8_t *)"\x8e\xa2\xb7\xca\x51\x67\x45\xbf"
|
||||
"\xea\xfc\x49\x90\x4b\x49\x60\x89")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("PASS\n");
|
||||
return 0;
|
||||
}
|
||||
Executable
+2987
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
@@ -1,11 +1,4 @@
|
||||
#! /usr/bin/env perl
|
||||
# Copyright 2009-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
|
||||
@@ -50,46 +43,32 @@
|
||||
# Add aesni_xts_[en|de]crypt. Westmere spends 1.50 cycles processing
|
||||
# one byte out of 8KB with 128-bit key, Sandy Bridge - 1.09.
|
||||
|
||||
# November 2015
|
||||
#
|
||||
# Add aesni_ocb_[en|de]crypt. [Removed in BoringSSL]
|
||||
|
||||
######################################################################
|
||||
# Current large-block performance in cycles per byte processed with
|
||||
# 128-bit key (less is better).
|
||||
#
|
||||
# CBC en-/decrypt CTR XTS ECB OCB
|
||||
# CBC en-/decrypt CTR XTS ECB
|
||||
# Westmere 3.77/1.37 1.37 1.52 1.27
|
||||
# * Bridge 5.07/0.98 0.99 1.09 0.91 1.10
|
||||
# Haswell 4.44/0.80 0.97 1.03 0.72 0.76
|
||||
# Skylake 2.68/0.65 0.65 0.66 0.64 0.66
|
||||
# Silvermont 5.77/3.56 3.67 4.03 3.46 4.03
|
||||
# Goldmont 3.84/1.39 1.39 1.63 1.31 1.70
|
||||
# Bulldozer 5.80/0.98 1.05 1.24 0.93 1.23
|
||||
# * Bridge 5.07/0.98 0.99 1.09 0.91
|
||||
# Haswell 4.44/0.80 0.97 1.03 0.72
|
||||
# Silvermont 5.77/3.56 3.67 4.03 3.46
|
||||
# Bulldozer 5.80/0.98 1.05 1.24 0.93
|
||||
|
||||
$PREFIX="aes_hw"; # if $PREFIX is set to "AES", the script
|
||||
$PREFIX="aesni"; # if $PREFIX is set to "AES", the script
|
||||
# generates drop-in replacement for
|
||||
# crypto/aes/asm/aes-586.pl:-)
|
||||
$AESNI_PREFIX="aes_hw";
|
||||
$inline=1; # inline _aesni_[en|de]crypt
|
||||
|
||||
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
push(@INC,"${dir}","${dir}../../../perlasm");
|
||||
push(@INC,"${dir}","${dir}../../perlasm");
|
||||
require "x86asm.pl";
|
||||
|
||||
$output = pop;
|
||||
open OUT,">$output";
|
||||
*STDOUT=*OUT;
|
||||
|
||||
&asm_init($ARGV[0]);
|
||||
&asm_init($ARGV[0],$0);
|
||||
|
||||
&external_label("OPENSSL_ia32cap_P");
|
||||
&preprocessor_ifdef("BORINGSSL_DISPATCH_TEST")
|
||||
&external_label("BORINGSSL_function_hit");
|
||||
&preprocessor_endif();
|
||||
&static_label("key_const");
|
||||
|
||||
if ($PREFIX eq $AESNI_PREFIX) { $movekey=\&movups; }
|
||||
if ($PREFIX eq "aesni") { $movekey=\&movups; }
|
||||
else { $movekey=\&movups; }
|
||||
|
||||
$len="eax";
|
||||
@@ -196,8 +175,6 @@ sub aesni_generate1 # fully unrolled loop
|
||||
# void $PREFIX_encrypt (const void *inp,void *out,const AES_KEY *key);
|
||||
&aesni_generate1("enc") if (!$inline);
|
||||
&function_begin_B("${PREFIX}_encrypt");
|
||||
&record_function_hit(1);
|
||||
|
||||
&mov ("eax",&wparam(0));
|
||||
&mov ($key,&wparam(2));
|
||||
&movups ($inout0,&QWP(0,"eax"));
|
||||
@@ -245,7 +222,7 @@ sub aesni_generate1 # fully unrolled loop
|
||||
# can schedule aes[enc|dec] every cycle optimal interleave factor
|
||||
# equals to corresponding instructions latency. 8x is optimal for
|
||||
# * Bridge, but it's unfeasible to accommodate such implementation
|
||||
# in XMM registers addressable in 32-bit mode and therefore maximum
|
||||
# in XMM registers addreassable in 32-bit mode and therefore maximum
|
||||
# of 6x is used instead...
|
||||
|
||||
sub aesni_generate2
|
||||
@@ -420,21 +397,21 @@ sub aesni_generate6
|
||||
&ret();
|
||||
&function_end_B("_aesni_${p}rypt6");
|
||||
}
|
||||
&aesni_generate2("enc") if ($PREFIX eq $AESNI_PREFIX);
|
||||
&aesni_generate2("enc") if ($PREFIX eq "aesni");
|
||||
&aesni_generate2("dec");
|
||||
&aesni_generate3("enc") if ($PREFIX eq $AESNI_PREFIX);
|
||||
&aesni_generate3("enc") if ($PREFIX eq "aesni");
|
||||
&aesni_generate3("dec");
|
||||
&aesni_generate4("enc") if ($PREFIX eq $AESNI_PREFIX);
|
||||
&aesni_generate4("enc") if ($PREFIX eq "aesni");
|
||||
&aesni_generate4("dec");
|
||||
&aesni_generate6("enc") if ($PREFIX eq $AESNI_PREFIX);
|
||||
&aesni_generate6("enc") if ($PREFIX eq "aesni");
|
||||
&aesni_generate6("dec");
|
||||
|
||||
if ($PREFIX eq $AESNI_PREFIX) {
|
||||
if ($PREFIX eq "aesni") {
|
||||
######################################################################
|
||||
# void aes_hw_ecb_encrypt (const void *in, void *out,
|
||||
# void aesni_ecb_encrypt (const void *in, void *out,
|
||||
# size_t length, const AES_KEY *key,
|
||||
# int enc);
|
||||
&function_begin("${PREFIX}_ecb_encrypt");
|
||||
&function_begin("aesni_ecb_encrypt");
|
||||
&mov ($inp,&wparam(0));
|
||||
&mov ($out,&wparam(1));
|
||||
&mov ($len,&wparam(2));
|
||||
@@ -653,10 +630,10 @@ if ($PREFIX eq $AESNI_PREFIX) {
|
||||
&pxor ("xmm5","xmm5");
|
||||
&pxor ("xmm6","xmm6");
|
||||
&pxor ("xmm7","xmm7");
|
||||
&function_end("${PREFIX}_ecb_encrypt");
|
||||
&function_end("aesni_ecb_encrypt");
|
||||
|
||||
######################################################################
|
||||
# void aes_hw_ccm64_[en|de]crypt_blocks (const void *in, void *out,
|
||||
# void aesni_ccm64_[en|de]crypt_blocks (const void *in, void *out,
|
||||
# size_t blocks, const AES_KEY *key,
|
||||
# const char *ivec,char *cmac);
|
||||
#
|
||||
@@ -665,7 +642,7 @@ if ($PREFIX eq $AESNI_PREFIX) {
|
||||
# (see engine/eng_aesni.c for details)
|
||||
#
|
||||
{ my $cmac=$inout1;
|
||||
&function_begin("${PREFIX}_ccm64_encrypt_blocks");
|
||||
&function_begin("aesni_ccm64_encrypt_blocks");
|
||||
&mov ($inp,&wparam(0));
|
||||
&mov ($out,&wparam(1));
|
||||
&mov ($len,&wparam(2));
|
||||
@@ -751,9 +728,9 @@ if ($PREFIX eq $AESNI_PREFIX) {
|
||||
&pxor ("xmm5","xmm5");
|
||||
&pxor ("xmm6","xmm6");
|
||||
&pxor ("xmm7","xmm7");
|
||||
&function_end("${PREFIX}_ccm64_encrypt_blocks");
|
||||
&function_end("aesni_ccm64_encrypt_blocks");
|
||||
|
||||
&function_begin("${PREFIX}_ccm64_decrypt_blocks");
|
||||
&function_begin("aesni_ccm64_decrypt_blocks");
|
||||
&mov ($inp,&wparam(0));
|
||||
&mov ($out,&wparam(1));
|
||||
&mov ($len,&wparam(2));
|
||||
@@ -860,11 +837,11 @@ if ($PREFIX eq $AESNI_PREFIX) {
|
||||
&pxor ("xmm5","xmm5");
|
||||
&pxor ("xmm6","xmm6");
|
||||
&pxor ("xmm7","xmm7");
|
||||
&function_end("${PREFIX}_ccm64_decrypt_blocks");
|
||||
&function_end("aesni_ccm64_decrypt_blocks");
|
||||
}
|
||||
|
||||
######################################################################
|
||||
# void aes_hw_ctr32_encrypt_blocks (const void *in, void *out,
|
||||
# void aesni_ctr32_encrypt_blocks (const void *in, void *out,
|
||||
# size_t blocks, const AES_KEY *key,
|
||||
# const char *ivec);
|
||||
#
|
||||
@@ -879,9 +856,7 @@ if ($PREFIX eq $AESNI_PREFIX) {
|
||||
# 64 2nd triplet of counter vector
|
||||
# 80 saved %esp
|
||||
|
||||
&function_begin("${PREFIX}_ctr32_encrypt_blocks");
|
||||
&record_function_hit(0);
|
||||
|
||||
&function_begin("aesni_ctr32_encrypt_blocks");
|
||||
&mov ($inp,&wparam(0));
|
||||
&mov ($out,&wparam(1));
|
||||
&mov ($len,&wparam(2));
|
||||
@@ -1061,7 +1036,7 @@ if ($PREFIX eq $AESNI_PREFIX) {
|
||||
&set_label("ctr32_one_shortcut",16);
|
||||
&movups ($inout0,&QWP(0,$rounds_)); # load ivec
|
||||
&mov ($rounds,&DWP(240,$key));
|
||||
|
||||
|
||||
&set_label("ctr32_one");
|
||||
if ($inline)
|
||||
{ &aesni_inline_generate1("enc"); }
|
||||
@@ -1123,16 +1098,16 @@ if ($PREFIX eq $AESNI_PREFIX) {
|
||||
&movdqa (&QWP(64,"esp"),"xmm0");
|
||||
&pxor ("xmm7","xmm7");
|
||||
&mov ("esp",&DWP(80,"esp"));
|
||||
&function_end("${PREFIX}_ctr32_encrypt_blocks");
|
||||
&function_end("aesni_ctr32_encrypt_blocks");
|
||||
|
||||
######################################################################
|
||||
# void aes_hw_xts_[en|de]crypt(const char *inp,char *out,size_t len,
|
||||
# void aesni_xts_[en|de]crypt(const char *inp,char *out,size_t len,
|
||||
# const AES_KEY *key1, const AES_KEY *key2
|
||||
# const unsigned char iv[16]);
|
||||
#
|
||||
{ my ($tweak,$twtmp,$twres,$twmask)=($rndkey1,$rndkey0,$inout0,$inout1);
|
||||
|
||||
&function_begin("${PREFIX}_xts_encrypt");
|
||||
&function_begin("aesni_xts_encrypt");
|
||||
&mov ($key,&wparam(4)); # key2
|
||||
&mov ($inp,&wparam(5)); # clear-text tweak
|
||||
|
||||
@@ -1478,9 +1453,9 @@ if ($PREFIX eq $AESNI_PREFIX) {
|
||||
&pxor ("xmm7","xmm7");
|
||||
&movdqa (&QWP(16*5,"esp"),"xmm0");
|
||||
&mov ("esp",&DWP(16*7+4,"esp")); # restore %esp
|
||||
&function_end("${PREFIX}_xts_encrypt");
|
||||
&function_end("aesni_xts_encrypt");
|
||||
|
||||
&function_begin("${PREFIX}_xts_decrypt");
|
||||
&function_begin("aesni_xts_decrypt");
|
||||
&mov ($key,&wparam(4)); # key2
|
||||
&mov ($inp,&wparam(5)); # clear-text tweak
|
||||
|
||||
@@ -1854,7 +1829,7 @@ if ($PREFIX eq $AESNI_PREFIX) {
|
||||
&pxor ("xmm7","xmm7");
|
||||
&movdqa (&QWP(16*5,"esp"),"xmm0");
|
||||
&mov ("esp",&DWP(16*7+4,"esp")); # restore %esp
|
||||
&function_end("${PREFIX}_xts_decrypt");
|
||||
&function_end("aesni_xts_decrypt");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2444,7 +2419,7 @@ if ($PREFIX eq $AESNI_PREFIX) {
|
||||
&pxor ("xmm3","xmm3");
|
||||
&aesenclast ("xmm2","xmm3");
|
||||
|
||||
&movdqa ("xmm3","xmm1");
|
||||
&movdqa ("xmm3","xmm1")
|
||||
&pslldq ("xmm1",4);
|
||||
&pxor ("xmm3","xmm1");
|
||||
&pslldq ("xmm1",4);
|
||||
@@ -2490,8 +2465,6 @@ if ($PREFIX eq $AESNI_PREFIX) {
|
||||
# int $PREFIX_set_encrypt_key (const unsigned char *userKey, int bits,
|
||||
# AES_KEY *key)
|
||||
&function_begin_B("${PREFIX}_set_encrypt_key");
|
||||
&record_function_hit(3);
|
||||
|
||||
&mov ("eax",&wparam(0));
|
||||
&mov ($rounds,&wparam(1));
|
||||
&mov ($key,&wparam(2));
|
||||
@@ -2550,5 +2523,3 @@ if ($PREFIX eq $AESNI_PREFIX) {
|
||||
&asciz("AES for Intel AES-NI, CRYPTOGAMS by <appro\@openssl.org>");
|
||||
|
||||
&asm_finish();
|
||||
|
||||
close STDOUT or die "error closing STDOUT";
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,4 @@
|
||||
#! /usr/bin/env perl
|
||||
# Copyright 2014-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
|
||||
@@ -34,7 +27,6 @@
|
||||
# Cortex-A53 1.32 1.29 1.46
|
||||
# Cortex-A57(*) 1.95 0.85 0.93
|
||||
# Denver 1.96 0.86 0.80
|
||||
# Mongoose 1.33 1.20 1.20
|
||||
#
|
||||
# (*) original 3.64/1.34/1.32 results were for r0p0 revision
|
||||
# and are still same even for updated module;
|
||||
@@ -44,13 +36,13 @@ $output = shift;
|
||||
|
||||
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
|
||||
( $xlate="${dir}../../../perlasm/arm-xlate.pl" and -f $xlate) or
|
||||
( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
|
||||
die "can't locate arm-xlate.pl";
|
||||
|
||||
open OUT,"| \"$^X\" $xlate $flavour $output";
|
||||
*STDOUT=*OUT;
|
||||
|
||||
$prefix="aes_hw";
|
||||
$prefix="aes_v8";
|
||||
|
||||
$code=<<___;
|
||||
#include <openssl/arm_arch.h>
|
||||
@@ -58,13 +50,14 @@ $code=<<___;
|
||||
#if __ARM_MAX_ARCH__>=7
|
||||
.text
|
||||
___
|
||||
$code.=".arch armv8-a+crypto\n" if ($flavour =~ /64/);
|
||||
$code.=<<___ if ($flavour !~ /64/);
|
||||
.arch armv7-a // don't confuse not-so-latest binutils with argv8 :-)
|
||||
.fpu neon
|
||||
.code 32
|
||||
#undef __thumb2__
|
||||
$code.=<<___ if ($flavour =~ /64/);
|
||||
#if !defined(__clang__)
|
||||
.arch armv8-a+crypto
|
||||
#endif
|
||||
___
|
||||
$code.=".arch armv7-a\n.fpu neon\n.code 32\n" if ($flavour !~ /64/);
|
||||
#^^^^^^ this is done to simplify adoption by not depending
|
||||
# on latest binutils.
|
||||
|
||||
# Assembler mnemonics are an eclectic mix of 32- and 64-bit syntax,
|
||||
# NEON is mostly 32-bit mnemonics, integer - mostly 64. Goal is to
|
||||
@@ -77,9 +70,6 @@ my ($zero,$rcon,$mask,$in0,$in1,$tmp,$key)=
|
||||
$flavour=~/64/? map("q$_",(0..6)) : map("q$_",(0..3,8..10));
|
||||
|
||||
|
||||
# On AArch64, put the data .rodata and use adrp + add for compatibility with
|
||||
# execute-only memory. On AArch32, put it in .text and use adr.
|
||||
$code.= ".section .rodata\n" if ($flavour =~ /64/);
|
||||
$code.=<<___;
|
||||
.align 5
|
||||
.Lrcon:
|
||||
@@ -87,8 +77,6 @@ $code.=<<___;
|
||||
.long 0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d // rotate-n-splat
|
||||
.long 0x1b,0x1b,0x1b,0x1b
|
||||
|
||||
.text
|
||||
|
||||
.globl ${prefix}_set_encrypt_key
|
||||
.type ${prefix}_set_encrypt_key,%function
|
||||
.align 5
|
||||
@@ -113,15 +101,7 @@ $code.=<<___;
|
||||
tst $bits,#0x3f
|
||||
b.ne .Lenc_key_abort
|
||||
|
||||
___
|
||||
$code.=<<___ if ($flavour =~ /64/);
|
||||
adrp $ptr,:pg_hi21:.Lrcon
|
||||
add $ptr,$ptr,:lo12:.Lrcon
|
||||
___
|
||||
$code.=<<___ if ($flavour !~ /64/);
|
||||
adr $ptr,.Lrcon
|
||||
___
|
||||
$code.=<<___;
|
||||
cmp $bits,#192
|
||||
|
||||
veor $zero,$zero,$zero
|
||||
@@ -942,7 +922,7 @@ if ($flavour =~ /64/) { ######## 64-bit code
|
||||
s/^(\s+)v/$1/o or # strip off v prefix
|
||||
s/\bbx\s+lr\b/ret/o;
|
||||
|
||||
# fix up remaining legacy suffixes
|
||||
# fix up remainig legacy suffixes
|
||||
s/\.[ui]?8//o;
|
||||
m/\],#8/o and s/\.16b/\.8b/go;
|
||||
s/\.[ui]?32//o and s/\.16b/\.4s/go;
|
||||
@@ -977,21 +957,21 @@ if ($flavour =~ /64/) { ######## 64-bit code
|
||||
|
||||
$arg =~ m/q([0-9]+),\s*\{q([0-9]+)\},\s*q([0-9]+)/o &&
|
||||
sprintf "vtbl.8 d%d,{q%d},d%d\n\t".
|
||||
"vtbl.8 d%d,{q%d},d%d", 2*$1,$2,2*$3, 2*$1+1,$2,2*$3+1;
|
||||
"vtbl.8 d%d,{q%d},d%d", 2*$1,$2,2*$3, 2*$1+1,$2,2*$3+1;
|
||||
}
|
||||
|
||||
sub unvdup32 {
|
||||
my $arg=shift;
|
||||
|
||||
$arg =~ m/q([0-9]+),\s*q([0-9]+)\[([0-3])\]/o &&
|
||||
sprintf "vdup.32 q%d,d%d[%d]",$1,2*$2+($3>>1),$3&1;
|
||||
sprintf "vdup.32 q%d,d%d[%d]",$1,2*$2+($3>>1),$3&1;
|
||||
}
|
||||
|
||||
sub unvmov32 {
|
||||
my $arg=shift;
|
||||
|
||||
$arg =~ m/q([0-9]+)\[([0-3])\],(.*)/o &&
|
||||
sprintf "vmov.32 d%d[%d],%s",2*$1+($2>>1),$2&1,$3;
|
||||
sprintf "vmov.32 d%d[%d],%s",2*$1+($2>>1),$2&1,$3;
|
||||
}
|
||||
|
||||
foreach(split("\n",$code)) {
|
||||
@@ -1001,7 +981,7 @@ if ($flavour =~ /64/) { ######## 64-bit code
|
||||
s/\bv([0-9])\.[12468]+[bsd]\b/q$1/go; # new->old registers
|
||||
s/\/\/\s?/@ /o; # new->old style commentary
|
||||
|
||||
# fix up remaining new-style suffixes
|
||||
# fix up remainig new-style suffixes
|
||||
s/\{q([0-9]+)\},\s*\[(.+)\],#8/sprintf "{d%d},[$2]!",2*$1/eo or
|
||||
s/\],#[0-9]+/]!/o;
|
||||
|
||||
@@ -1018,4 +998,4 @@ if ($flavour =~ /64/) { ######## 64-bit code
|
||||
}
|
||||
}
|
||||
|
||||
close STDOUT or die "error closing STDOUT";
|
||||
close STDOUT;
|
||||
@@ -1,11 +1,4 @@
|
||||
#! /usr/bin/env perl
|
||||
# Copyright 2012-2016 The OpenSSL Project Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the OpenSSL license (the "License"). You may not use
|
||||
# this file except in compliance with the License. You can obtain a copy
|
||||
# in the file LICENSE in the source distribution or at
|
||||
# https://www.openssl.org/source/license.html
|
||||
|
||||
#!/usr/bin/env perl
|
||||
|
||||
# ====================================================================
|
||||
# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
|
||||
@@ -14,7 +7,8 @@
|
||||
# details see http://www.openssl.org/~appro/cryptogams/.
|
||||
#
|
||||
# Specific modes and adaptation for Linux kernel by Ard Biesheuvel
|
||||
# of Linaro. Permission to use under GPL terms is granted.
|
||||
# <ard.biesheuvel@linaro.org>. Permission to use under GPL terms is
|
||||
# granted.
|
||||
# ====================================================================
|
||||
|
||||
# Bit-sliced AES for ARM NEON
|
||||
@@ -48,23 +42,24 @@
|
||||
# <appro@openssl.org>
|
||||
|
||||
# April-August 2013
|
||||
# Add CBC, CTR and XTS subroutines and adapt for kernel use; courtesy of Ard.
|
||||
#
|
||||
# Add CBC, CTR and XTS subroutines, adapt for kernel use.
|
||||
#
|
||||
# <ard.biesheuvel@linaro.org>
|
||||
|
||||
$flavour = shift;
|
||||
if ($flavour=~/\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
|
||||
else { while (($output=shift) && ($output!~/\w[\w\-]*\.\w+$/)) {} }
|
||||
if ($flavour=~/^\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
|
||||
else { while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {} }
|
||||
|
||||
if ($flavour && $flavour ne "void") {
|
||||
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
|
||||
( $xlate="${dir}../../../perlasm/arm-xlate.pl" and -f $xlate) or
|
||||
( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
|
||||
die "can't locate arm-xlate.pl";
|
||||
|
||||
open OUT,"| \"$^X\" $xlate $flavour $output";
|
||||
*STDOUT=*OUT;
|
||||
open STDOUT,"| \"$^X\" $xlate $flavour $output";
|
||||
} else {
|
||||
open OUT,">$output";
|
||||
*STDOUT=*OUT;
|
||||
open STDOUT,">$output";
|
||||
}
|
||||
|
||||
my ($inp,$out,$len,$key)=("r0","r1","r2","r3");
|
||||
@@ -89,7 +84,7 @@ my @s=@_[12..15];
|
||||
|
||||
sub InBasisChange {
|
||||
# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb
|
||||
# output in lsb > [b6, b5, b0, b3, b7, b1, b4, b2] < msb
|
||||
# output in lsb > [b6, b5, b0, b3, b7, b1, b4, b2] < msb
|
||||
my @b=@_[0..7];
|
||||
$code.=<<___;
|
||||
veor @b[2], @b[2], @b[1]
|
||||
@@ -736,15 +731,14 @@ $code.=<<___;
|
||||
.thumb
|
||||
#else
|
||||
.code 32
|
||||
# undef __thumb2__
|
||||
#endif
|
||||
|
||||
.type _bsaes_decrypt8,%function
|
||||
.align 4
|
||||
_bsaes_decrypt8:
|
||||
adr $const,.
|
||||
adr $const,_bsaes_decrypt8
|
||||
vldmia $key!, {@XMM[9]} @ round 0 key
|
||||
#if defined(__thumb2__) || defined(__APPLE__)
|
||||
#ifdef __APPLE__
|
||||
adr $const,.LM0ISR
|
||||
#else
|
||||
add $const,$const,#.LM0ISR-_bsaes_decrypt8
|
||||
@@ -841,9 +835,9 @@ _bsaes_const:
|
||||
.type _bsaes_encrypt8,%function
|
||||
.align 4
|
||||
_bsaes_encrypt8:
|
||||
adr $const,.
|
||||
adr $const,_bsaes_encrypt8
|
||||
vldmia $key!, {@XMM[9]} @ round 0 key
|
||||
#if defined(__thumb2__) || defined(__APPLE__)
|
||||
#ifdef __APPLE__
|
||||
adr $const,.LM0SR
|
||||
#else
|
||||
sub $const,$const,#_bsaes_encrypt8-.LM0SR
|
||||
@@ -949,9 +943,9 @@ $code.=<<___;
|
||||
.type _bsaes_key_convert,%function
|
||||
.align 4
|
||||
_bsaes_key_convert:
|
||||
adr $const,.
|
||||
adr $const,_bsaes_key_convert
|
||||
vld1.8 {@XMM[7]}, [$inp]! @ load round 0 key
|
||||
#if defined(__thumb2__) || defined(__APPLE__)
|
||||
#ifdef __APPLE__
|
||||
adr $const,.LM0
|
||||
#else
|
||||
sub $const,$const,#_bsaes_key_convert-.LM0
|
||||
@@ -1115,12 +1109,23 @@ my ($inp,$out,$len,$key, $ivp,$fp,$rounds)=map("r$_",(0..3,8..10));
|
||||
my ($keysched)=("sp");
|
||||
|
||||
$code.=<<___;
|
||||
.extern AES_cbc_encrypt
|
||||
.extern AES_decrypt
|
||||
|
||||
.global bsaes_cbc_encrypt
|
||||
.type bsaes_cbc_encrypt,%function
|
||||
.align 5
|
||||
bsaes_cbc_encrypt:
|
||||
@ In OpenSSL, this function had a fallback to aes_nohw_cbc_encrypt for
|
||||
@ short inputs. We patch this out, using bsaes for all input sizes.
|
||||
#ifndef __KERNEL__
|
||||
cmp $len, #128
|
||||
#ifndef __thumb__
|
||||
blo AES_cbc_encrypt
|
||||
#else
|
||||
bhs 1f
|
||||
b AES_cbc_encrypt
|
||||
1:
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ it is up to the caller to make sure we are called with enc == 0
|
||||
|
||||
@@ -1218,7 +1223,10 @@ bsaes_cbc_encrypt:
|
||||
adds $len, $len, #8
|
||||
beq .Lcbc_dec_done
|
||||
|
||||
@ Set up most parameters for the _bsaes_decrypt8 call.
|
||||
vld1.8 {@XMM[0]}, [$inp]! @ load input
|
||||
cmp $len, #2
|
||||
blo .Lcbc_dec_one
|
||||
vld1.8 {@XMM[1]}, [$inp]!
|
||||
#ifndef BSAES_ASM_EXTENDED_KEY
|
||||
mov r4, $keysched @ pass the key
|
||||
#else
|
||||
@@ -1226,11 +1234,6 @@ bsaes_cbc_encrypt:
|
||||
#endif
|
||||
mov r5, $rounds
|
||||
vstmia $fp, {@XMM[15]} @ put aside IV
|
||||
|
||||
vld1.8 {@XMM[0]}, [$inp]! @ load input
|
||||
cmp $len, #2
|
||||
blo .Lcbc_dec_one
|
||||
vld1.8 {@XMM[1]}, [$inp]!
|
||||
beq .Lcbc_dec_two
|
||||
vld1.8 {@XMM[2]}, [$inp]!
|
||||
cmp $len, #4
|
||||
@@ -1348,11 +1351,16 @@ bsaes_cbc_encrypt:
|
||||
.align 4
|
||||
.Lcbc_dec_one:
|
||||
sub $inp, $inp, #0x10
|
||||
bl _bsaes_decrypt8
|
||||
vldmia $fp, {@XMM[14]} @ reload IV
|
||||
vld1.8 {@XMM[15]}, [$inp]! @ reload input
|
||||
veor @XMM[0], @XMM[0], @XMM[14] @ ^= IV
|
||||
vst1.8 {@XMM[0]}, [$out]! @ write output
|
||||
mov $rounds, $out @ save original out pointer
|
||||
mov $out, $fp @ use the iv scratch space as out buffer
|
||||
mov r2, $key
|
||||
vmov @XMM[4],@XMM[15] @ just in case ensure that IV
|
||||
vmov @XMM[5],@XMM[0] @ and input are preserved
|
||||
bl AES_decrypt
|
||||
vld1.8 {@XMM[0]}, [$fp,:64] @ load result
|
||||
veor @XMM[0], @XMM[0], @XMM[4] @ ^= IV
|
||||
vmov @XMM[15], @XMM[5] @ @XMM[5] holds input
|
||||
vst1.8 {@XMM[0]}, [$rounds] @ write output
|
||||
|
||||
.Lcbc_dec_done:
|
||||
#ifndef BSAES_ASM_EXTENDED_KEY
|
||||
@@ -1378,12 +1386,14 @@ my $const = "r6"; # shared with _bsaes_encrypt8_alt
|
||||
my $keysched = "sp";
|
||||
|
||||
$code.=<<___;
|
||||
.extern AES_encrypt
|
||||
.global bsaes_ctr32_encrypt_blocks
|
||||
.type bsaes_ctr32_encrypt_blocks,%function
|
||||
.align 5
|
||||
bsaes_ctr32_encrypt_blocks:
|
||||
@ In OpenSSL, short inputs fall back to aes_nohw_* here. We patch this
|
||||
@ out to retain a constant-time implementation.
|
||||
cmp $len, #8 @ use plain AES for
|
||||
blo .Lctr_enc_short @ small sizes
|
||||
|
||||
mov ip, sp
|
||||
stmdb sp!, {r4-r10, lr}
|
||||
VFP_ABI_PUSH
|
||||
@@ -1559,13 +1569,54 @@ bsaes_ctr32_encrypt_blocks:
|
||||
VFP_ABI_POP
|
||||
ldmia sp!, {r4-r10, pc} @ return
|
||||
|
||||
@ OpenSSL contains aes_nohw_* fallback code here. We patch this
|
||||
@ out to retain a constant-time implementation.
|
||||
.align 4
|
||||
.Lctr_enc_short:
|
||||
ldr ip, [sp] @ ctr pointer is passed on stack
|
||||
stmdb sp!, {r4-r8, lr}
|
||||
|
||||
mov r4, $inp @ copy arguments
|
||||
mov r5, $out
|
||||
mov r6, $len
|
||||
mov r7, $key
|
||||
ldr r8, [ip, #12] @ load counter LSW
|
||||
vld1.8 {@XMM[1]}, [ip] @ load whole counter value
|
||||
#ifdef __ARMEL__
|
||||
rev r8, r8
|
||||
#endif
|
||||
sub sp, sp, #0x10
|
||||
vst1.8 {@XMM[1]}, [sp] @ copy counter value
|
||||
sub sp, sp, #0x10
|
||||
|
||||
.Lctr_enc_short_loop:
|
||||
add r0, sp, #0x10 @ input counter value
|
||||
mov r1, sp @ output on the stack
|
||||
mov r2, r7 @ key
|
||||
|
||||
bl AES_encrypt
|
||||
|
||||
vld1.8 {@XMM[0]}, [r4]! @ load input
|
||||
vld1.8 {@XMM[1]}, [sp] @ load encrypted counter
|
||||
add r8, r8, #1
|
||||
#ifdef __ARMEL__
|
||||
rev r0, r8
|
||||
str r0, [sp, #0x1c] @ next counter value
|
||||
#else
|
||||
str r8, [sp, #0x1c] @ next counter value
|
||||
#endif
|
||||
veor @XMM[0],@XMM[0],@XMM[1]
|
||||
vst1.8 {@XMM[0]}, [r5]! @ store output
|
||||
subs r6, r6, #1
|
||||
bne .Lctr_enc_short_loop
|
||||
|
||||
vmov.i32 q0, #0
|
||||
vmov.i32 q1, #0
|
||||
vstmia sp!, {q0-q1}
|
||||
|
||||
ldmia sp!, {r4-r8, pc}
|
||||
.size bsaes_ctr32_encrypt_blocks,.-bsaes_ctr32_encrypt_blocks
|
||||
___
|
||||
}
|
||||
# In BorinSSL, we patch XTS support out.
|
||||
if (0) {
|
||||
{
|
||||
######################################################################
|
||||
# void bsaes_xts_[en|de]crypt(const char *inp,char *out,size_t len,
|
||||
# const AES_KEY *key1, const AES_KEY *key2,
|
||||
@@ -1602,7 +1653,7 @@ bsaes_xts_encrypt:
|
||||
ldr r0, [ip, #4] @ iv[]
|
||||
mov r1, sp
|
||||
ldr r2, [ip, #0] @ key2
|
||||
bl aes_nohw_encrypt
|
||||
bl AES_encrypt
|
||||
mov r0,sp @ pointer to initial tweak
|
||||
#endif
|
||||
|
||||
@@ -1780,6 +1831,8 @@ $code.=<<___;
|
||||
b .Lxts_enc_done
|
||||
.align 4
|
||||
.Lxts_enc_6:
|
||||
vst1.64 {@XMM[14]}, [r0,:128] @ next round tweak
|
||||
|
||||
veor @XMM[4], @XMM[4], @XMM[12]
|
||||
#ifndef BSAES_ASM_EXTENDED_KEY
|
||||
add r4, sp, #0x90 @ pass key schedule
|
||||
@@ -1815,6 +1868,8 @@ $code.=<<___;
|
||||
|
||||
.align 5
|
||||
.Lxts_enc_5:
|
||||
vst1.64 {@XMM[13]}, [r0,:128] @ next round tweak
|
||||
|
||||
veor @XMM[3], @XMM[3], @XMM[11]
|
||||
#ifndef BSAES_ASM_EXTENDED_KEY
|
||||
add r4, sp, #0x90 @ pass key schedule
|
||||
@@ -1843,6 +1898,8 @@ $code.=<<___;
|
||||
b .Lxts_enc_done
|
||||
.align 4
|
||||
.Lxts_enc_4:
|
||||
vst1.64 {@XMM[12]}, [r0,:128] @ next round tweak
|
||||
|
||||
veor @XMM[2], @XMM[2], @XMM[10]
|
||||
#ifndef BSAES_ASM_EXTENDED_KEY
|
||||
add r4, sp, #0x90 @ pass key schedule
|
||||
@@ -1868,6 +1925,8 @@ $code.=<<___;
|
||||
b .Lxts_enc_done
|
||||
.align 4
|
||||
.Lxts_enc_3:
|
||||
vst1.64 {@XMM[11]}, [r0,:128] @ next round tweak
|
||||
|
||||
veor @XMM[1], @XMM[1], @XMM[9]
|
||||
#ifndef BSAES_ASM_EXTENDED_KEY
|
||||
add r4, sp, #0x90 @ pass key schedule
|
||||
@@ -1892,6 +1951,8 @@ $code.=<<___;
|
||||
b .Lxts_enc_done
|
||||
.align 4
|
||||
.Lxts_enc_2:
|
||||
vst1.64 {@XMM[10]}, [r0,:128] @ next round tweak
|
||||
|
||||
veor @XMM[0], @XMM[0], @XMM[8]
|
||||
#ifndef BSAES_ASM_EXTENDED_KEY
|
||||
add r4, sp, #0x90 @ pass key schedule
|
||||
@@ -1914,13 +1975,13 @@ $code.=<<___;
|
||||
.align 4
|
||||
.Lxts_enc_1:
|
||||
mov r0, sp
|
||||
veor @XMM[0], @XMM[0], @XMM[8]
|
||||
veor @XMM[0], @XMM[8]
|
||||
mov r1, sp
|
||||
vst1.8 {@XMM[0]}, [sp,:128]
|
||||
mov r2, $key
|
||||
mov r4, $fp @ preserve fp
|
||||
|
||||
bl aes_nohw_encrypt
|
||||
bl AES_encrypt
|
||||
|
||||
vld1.8 {@XMM[0]}, [sp,:128]
|
||||
veor @XMM[0], @XMM[0], @XMM[8]
|
||||
@@ -1952,7 +2013,7 @@ $code.=<<___;
|
||||
mov r2, $key
|
||||
mov r4, $fp @ preserve fp
|
||||
|
||||
bl aes_nohw_encrypt
|
||||
bl AES_encrypt
|
||||
|
||||
vld1.8 {@XMM[0]}, [sp,:128]
|
||||
veor @XMM[0], @XMM[0], @XMM[8]
|
||||
@@ -2006,7 +2067,7 @@ bsaes_xts_decrypt:
|
||||
ldr r0, [ip, #4] @ iv[]
|
||||
mov r1, sp
|
||||
ldr r2, [ip, #0] @ key2
|
||||
bl aes_nohw_encrypt
|
||||
bl AES_encrypt
|
||||
mov r0, sp @ pointer to initial tweak
|
||||
#endif
|
||||
|
||||
@@ -2226,6 +2287,8 @@ $code.=<<___;
|
||||
b .Lxts_dec_done
|
||||
.align 4
|
||||
.Lxts_dec_5:
|
||||
vst1.64 {@XMM[13]}, [r0,:128] @ next round tweak
|
||||
|
||||
veor @XMM[3], @XMM[3], @XMM[11]
|
||||
#ifndef BSAES_ASM_EXTENDED_KEY
|
||||
add r4, sp, #0x90 @ pass key schedule
|
||||
@@ -2254,6 +2317,8 @@ $code.=<<___;
|
||||
b .Lxts_dec_done
|
||||
.align 4
|
||||
.Lxts_dec_4:
|
||||
vst1.64 {@XMM[12]}, [r0,:128] @ next round tweak
|
||||
|
||||
veor @XMM[2], @XMM[2], @XMM[10]
|
||||
#ifndef BSAES_ASM_EXTENDED_KEY
|
||||
add r4, sp, #0x90 @ pass key schedule
|
||||
@@ -2279,6 +2344,8 @@ $code.=<<___;
|
||||
b .Lxts_dec_done
|
||||
.align 4
|
||||
.Lxts_dec_3:
|
||||
vst1.64 {@XMM[11]}, [r0,:128] @ next round tweak
|
||||
|
||||
veor @XMM[1], @XMM[1], @XMM[9]
|
||||
#ifndef BSAES_ASM_EXTENDED_KEY
|
||||
add r4, sp, #0x90 @ pass key schedule
|
||||
@@ -2303,6 +2370,8 @@ $code.=<<___;
|
||||
b .Lxts_dec_done
|
||||
.align 4
|
||||
.Lxts_dec_2:
|
||||
vst1.64 {@XMM[10]}, [r0,:128] @ next round tweak
|
||||
|
||||
veor @XMM[0], @XMM[0], @XMM[8]
|
||||
#ifndef BSAES_ASM_EXTENDED_KEY
|
||||
add r4, sp, #0x90 @ pass key schedule
|
||||
@@ -2325,14 +2394,14 @@ $code.=<<___;
|
||||
.align 4
|
||||
.Lxts_dec_1:
|
||||
mov r0, sp
|
||||
veor @XMM[0], @XMM[0], @XMM[8]
|
||||
veor @XMM[0], @XMM[8]
|
||||
mov r1, sp
|
||||
vst1.8 {@XMM[0]}, [sp,:128]
|
||||
mov r5, $magic @ preserve magic
|
||||
mov r2, $key
|
||||
mov r4, $fp @ preserve fp
|
||||
mov r5, $magic @ preserve magic
|
||||
|
||||
bl aes_nohw_decrypt
|
||||
bl AES_decrypt
|
||||
|
||||
vld1.8 {@XMM[0]}, [sp,:128]
|
||||
veor @XMM[0], @XMM[0], @XMM[8]
|
||||
@@ -2364,7 +2433,7 @@ $code.=<<___;
|
||||
mov r2, $key
|
||||
mov r4, $fp @ preserve fp
|
||||
|
||||
bl aes_nohw_decrypt
|
||||
bl AES_decrypt
|
||||
|
||||
vld1.8 {@XMM[0]}, [sp,:128]
|
||||
veor @XMM[0], @XMM[0], @XMM[9]
|
||||
@@ -2387,7 +2456,7 @@ $code.=<<___;
|
||||
vst1.8 {@XMM[0]}, [sp,:128]
|
||||
mov r2, $key
|
||||
|
||||
bl aes_nohw_decrypt
|
||||
bl AES_decrypt
|
||||
|
||||
vld1.8 {@XMM[0]}, [sp,:128]
|
||||
veor @XMM[0], @XMM[0], @XMM[8]
|
||||
@@ -2433,4 +2502,4 @@ close SELF;
|
||||
|
||||
print $code;
|
||||
|
||||
close STDOUT or die "error closing STDOUT";
|
||||
close STDOUT;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,4 @@
|
||||
#! /usr/bin/env perl
|
||||
# Copyright 2011-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
|
||||
|
||||
######################################################################
|
||||
## Constant-time SSSE3 AES core implementation.
|
||||
@@ -55,23 +48,16 @@
|
||||
# <appro@openssl.org>
|
||||
|
||||
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
push(@INC,"${dir}","${dir}../../../perlasm");
|
||||
push(@INC,"${dir}","${dir}../../perlasm");
|
||||
require "x86asm.pl";
|
||||
|
||||
$output = pop;
|
||||
open OUT,">$output";
|
||||
*STDOUT=*OUT;
|
||||
|
||||
&asm_init($ARGV[0],$x86only = $ARGV[$#ARGV] eq "386");
|
||||
&asm_init($ARGV[0],"vpaes-x86.pl",$x86only = $ARGV[$#ARGV] eq "386");
|
||||
|
||||
$PREFIX="vpaes";
|
||||
|
||||
my ($round, $base, $magic, $key, $const, $inp, $out)=
|
||||
("eax", "ebx", "ecx", "edx","ebp", "esi","edi");
|
||||
|
||||
&preprocessor_ifdef("BORINGSSL_DISPATCH_TEST")
|
||||
&external_label("BORINGSSL_function_hit");
|
||||
&preprocessor_endif();
|
||||
&static_label("_vpaes_consts");
|
||||
&static_label("_vpaes_schedule_low_round");
|
||||
|
||||
@@ -448,7 +434,7 @@ $k_dsbo=0x2c0; # decryption sbox final output
|
||||
##
|
||||
&set_label("schedule_192",16);
|
||||
&movdqu ("xmm0",&QWP(8,$inp)); # load key part 2 (very unaligned)
|
||||
&call ("_vpaes_schedule_transform"); # input transform
|
||||
&call ("_vpaes_schedule_transform"); # input transform
|
||||
&movdqa ("xmm6","xmm0"); # save short part
|
||||
&pxor ("xmm4","xmm4"); # clear 4
|
||||
&movhlps("xmm6","xmm4"); # clobber low side with zeros
|
||||
@@ -479,7 +465,7 @@ $k_dsbo=0x2c0; # decryption sbox final output
|
||||
##
|
||||
&set_label("schedule_256",16);
|
||||
&movdqu ("xmm0",&QWP(16,$inp)); # load key part 2 (unaligned)
|
||||
&call ("_vpaes_schedule_transform"); # input transform
|
||||
&call ("_vpaes_schedule_transform"); # input transform
|
||||
&mov ($round,7);
|
||||
|
||||
&set_label("loop_schedule_256");
|
||||
@@ -490,7 +476,7 @@ $k_dsbo=0x2c0; # decryption sbox final output
|
||||
&call ("_vpaes_schedule_round");
|
||||
&dec ($round);
|
||||
&jz (&label("schedule_mangle_last"));
|
||||
&call ("_vpaes_schedule_mangle");
|
||||
&call ("_vpaes_schedule_mangle");
|
||||
|
||||
# low round. swap xmm7 and xmm6
|
||||
&pshufd ("xmm0","xmm0",0xFF);
|
||||
@@ -613,7 +599,7 @@ $k_dsbo=0x2c0; # decryption sbox final output
|
||||
# subbyte
|
||||
&movdqa ("xmm4",&QWP($k_s0F,$const));
|
||||
&movdqa ("xmm5",&QWP($k_inv,$const)); # 4 : 1/j
|
||||
&movdqa ("xmm1","xmm4");
|
||||
&movdqa ("xmm1","xmm4");
|
||||
&pandn ("xmm1","xmm0");
|
||||
&psrld ("xmm1",4); # 1 = i
|
||||
&pand ("xmm0","xmm4"); # 0 = k
|
||||
@@ -761,8 +747,6 @@ $k_dsbo=0x2c0; # decryption sbox final output
|
||||
# Interface to OpenSSL
|
||||
#
|
||||
&function_begin("${PREFIX}_set_encrypt_key");
|
||||
record_function_hit(5);
|
||||
|
||||
&mov ($inp,&wparam(0)); # inp
|
||||
&lea ($base,&DWP(-56,"esp"));
|
||||
&mov ($round,&wparam(1)); # bits
|
||||
@@ -817,8 +801,6 @@ $k_dsbo=0x2c0; # decryption sbox final output
|
||||
&function_end("${PREFIX}_set_decrypt_key");
|
||||
|
||||
&function_begin("${PREFIX}_encrypt");
|
||||
record_function_hit(4);
|
||||
|
||||
&lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point")));
|
||||
&call ("_vpaes_preheat");
|
||||
&set_label("pic_point");
|
||||
@@ -919,5 +901,3 @@ $k_dsbo=0x2c0; # decryption sbox final output
|
||||
&function_end("${PREFIX}_cbc_encrypt");
|
||||
|
||||
&asm_finish();
|
||||
|
||||
close STDOUT or die "error closing STDOUT";
|
||||
@@ -1,11 +1,4 @@
|
||||
#! /usr/bin/env perl
|
||||
# Copyright 2011-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
|
||||
|
||||
######################################################################
|
||||
## Constant-time SSSE3 AES core implementation.
|
||||
@@ -38,7 +31,6 @@
|
||||
# Nehalem 29.6/40.3/14.6 10.0/11.8
|
||||
# Atom 57.3/74.2/32.1 60.9/77.2(***)
|
||||
# Silvermont 52.7/64.0/19.5 48.8/60.8(***)
|
||||
# Goldmont 38.9/49.0/17.8 10.6/12.6
|
||||
#
|
||||
# (*) "Hyper-threading" in the context refers rather to cache shared
|
||||
# among multiple cores, than to specifically Intel HTT. As vast
|
||||
@@ -62,10 +54,10 @@ $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
|
||||
|
||||
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
|
||||
( $xlate="${dir}../../../perlasm/x86_64-xlate.pl" and -f $xlate) or
|
||||
( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
|
||||
die "can't locate x86_64-xlate.pl";
|
||||
|
||||
open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
|
||||
open OUT,"| \"$^X\" $xlate $flavour $output";
|
||||
*STDOUT=*OUT;
|
||||
|
||||
$PREFIX="vpaes";
|
||||
@@ -91,7 +83,6 @@ $code.=<<___;
|
||||
.type _vpaes_encrypt_core,\@abi-omnipotent
|
||||
.align 16
|
||||
_vpaes_encrypt_core:
|
||||
.cfi_startproc
|
||||
mov %rdx, %r9
|
||||
mov \$16, %r11
|
||||
mov 240(%rdx),%eax
|
||||
@@ -172,184 +163,8 @@ _vpaes_encrypt_core:
|
||||
pxor %xmm4, %xmm0 # 0 = A
|
||||
pshufb %xmm1, %xmm0
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size _vpaes_encrypt_core,.-_vpaes_encrypt_core
|
||||
|
||||
##
|
||||
## _aes_encrypt_core_2x
|
||||
##
|
||||
## AES-encrypt %xmm0 and %xmm6 in parallel.
|
||||
##
|
||||
## Inputs:
|
||||
## %xmm0 and %xmm6 = input
|
||||
## %xmm9 and %xmm10 as in _vpaes_preheat
|
||||
## (%rdx) = scheduled keys
|
||||
##
|
||||
## Output in %xmm0 and %xmm6
|
||||
## Clobbers %xmm1-%xmm5, %xmm7, %xmm8, %xmm11-%xmm13, %r9, %r10, %r11, %rax
|
||||
## Preserves %xmm14 and %xmm15
|
||||
##
|
||||
## This function stitches two parallel instances of _vpaes_encrypt_core. x86_64
|
||||
## provides 16 XMM registers. _vpaes_encrypt_core computes over six registers
|
||||
## (%xmm0-%xmm5) and additionally uses seven registers with preloaded constants
|
||||
## from _vpaes_preheat (%xmm9-%xmm15). This does not quite fit two instances,
|
||||
## so we spill some of %xmm9 through %xmm15 back to memory. We keep %xmm9 and
|
||||
## %xmm10 in registers as these values are used several times in a row. The
|
||||
## remainder are read once per round and are spilled to memory. This leaves two
|
||||
## registers preserved for the caller.
|
||||
##
|
||||
## Thus, of the two _vpaes_encrypt_core instances, the first uses (%xmm0-%xmm5)
|
||||
## as before. The second uses %xmm6-%xmm8,%xmm11-%xmm13. (Add 6 to %xmm2 and
|
||||
## below. Add 8 to %xmm3 and up.) Instructions in the second instance are
|
||||
## indented by one space.
|
||||
##
|
||||
##
|
||||
.type _vpaes_encrypt_core_2x,\@abi-omnipotent
|
||||
.align 16
|
||||
_vpaes_encrypt_core_2x:
|
||||
.cfi_startproc
|
||||
mov %rdx, %r9
|
||||
mov \$16, %r11
|
||||
mov 240(%rdx),%eax
|
||||
movdqa %xmm9, %xmm1
|
||||
movdqa %xmm9, %xmm7
|
||||
movdqa .Lk_ipt(%rip), %xmm2 # iptlo
|
||||
movdqa %xmm2, %xmm8
|
||||
pandn %xmm0, %xmm1
|
||||
pandn %xmm6, %xmm7
|
||||
movdqu (%r9), %xmm5 # round0 key
|
||||
# Also use %xmm5 in the second instance.
|
||||
psrld \$4, %xmm1
|
||||
psrld \$4, %xmm7
|
||||
pand %xmm9, %xmm0
|
||||
pand %xmm9, %xmm6
|
||||
pshufb %xmm0, %xmm2
|
||||
pshufb %xmm6, %xmm8
|
||||
movdqa .Lk_ipt+16(%rip), %xmm0 # ipthi
|
||||
movdqa %xmm0, %xmm6
|
||||
pshufb %xmm1, %xmm0
|
||||
pshufb %xmm7, %xmm6
|
||||
pxor %xmm5, %xmm2
|
||||
pxor %xmm5, %xmm8
|
||||
add \$16, %r9
|
||||
pxor %xmm2, %xmm0
|
||||
pxor %xmm8, %xmm6
|
||||
lea .Lk_mc_backward(%rip),%r10
|
||||
jmp .Lenc2x_entry
|
||||
|
||||
.align 16
|
||||
.Lenc2x_loop:
|
||||
# middle of middle round
|
||||
movdqa .Lk_sb1(%rip), %xmm4 # 4 : sb1u
|
||||
movdqa .Lk_sb1+16(%rip),%xmm0 # 0 : sb1t
|
||||
movdqa %xmm4, %xmm12
|
||||
movdqa %xmm0, %xmm6
|
||||
pshufb %xmm2, %xmm4 # 4 = sb1u
|
||||
pshufb %xmm8, %xmm12
|
||||
pshufb %xmm3, %xmm0 # 0 = sb1t
|
||||
pshufb %xmm11, %xmm6
|
||||
pxor %xmm5, %xmm4 # 4 = sb1u + k
|
||||
pxor %xmm5, %xmm12
|
||||
movdqa .Lk_sb2(%rip), %xmm5 # 4 : sb2u
|
||||
movdqa %xmm5, %xmm13
|
||||
pxor %xmm4, %xmm0 # 0 = A
|
||||
pxor %xmm12, %xmm6
|
||||
movdqa -0x40(%r11,%r10), %xmm1 # .Lk_mc_forward[]
|
||||
# Also use %xmm1 in the second instance.
|
||||
pshufb %xmm2, %xmm5 # 4 = sb2u
|
||||
pshufb %xmm8, %xmm13
|
||||
movdqa (%r11,%r10), %xmm4 # .Lk_mc_backward[]
|
||||
# Also use %xmm4 in the second instance.
|
||||
movdqa .Lk_sb2+16(%rip), %xmm2 # 2 : sb2t
|
||||
movdqa %xmm2, %xmm8
|
||||
pshufb %xmm3, %xmm2 # 2 = sb2t
|
||||
pshufb %xmm11, %xmm8
|
||||
movdqa %xmm0, %xmm3 # 3 = A
|
||||
movdqa %xmm6, %xmm11
|
||||
pxor %xmm5, %xmm2 # 2 = 2A
|
||||
pxor %xmm13, %xmm8
|
||||
pshufb %xmm1, %xmm0 # 0 = B
|
||||
pshufb %xmm1, %xmm6
|
||||
add \$16, %r9 # next key
|
||||
pxor %xmm2, %xmm0 # 0 = 2A+B
|
||||
pxor %xmm8, %xmm6
|
||||
pshufb %xmm4, %xmm3 # 3 = D
|
||||
pshufb %xmm4, %xmm11
|
||||
add \$16, %r11 # next mc
|
||||
pxor %xmm0, %xmm3 # 3 = 2A+B+D
|
||||
pxor %xmm6, %xmm11
|
||||
pshufb %xmm1, %xmm0 # 0 = 2B+C
|
||||
pshufb %xmm1, %xmm6
|
||||
and \$0x30, %r11 # ... mod 4
|
||||
sub \$1,%rax # nr--
|
||||
pxor %xmm3, %xmm0 # 0 = 2A+3B+C+D
|
||||
pxor %xmm11, %xmm6
|
||||
|
||||
.Lenc2x_entry:
|
||||
# top of round
|
||||
movdqa %xmm9, %xmm1 # 1 : i
|
||||
movdqa %xmm9, %xmm7
|
||||
movdqa .Lk_inv+16(%rip), %xmm5 # 2 : a/k
|
||||
movdqa %xmm5, %xmm13
|
||||
pandn %xmm0, %xmm1 # 1 = i<<4
|
||||
pandn %xmm6, %xmm7
|
||||
psrld \$4, %xmm1 # 1 = i
|
||||
psrld \$4, %xmm7
|
||||
pand %xmm9, %xmm0 # 0 = k
|
||||
pand %xmm9, %xmm6
|
||||
pshufb %xmm0, %xmm5 # 2 = a/k
|
||||
pshufb %xmm6, %xmm13
|
||||
movdqa %xmm10, %xmm3 # 3 : 1/i
|
||||
movdqa %xmm10, %xmm11
|
||||
pxor %xmm1, %xmm0 # 0 = j
|
||||
pxor %xmm7, %xmm6
|
||||
pshufb %xmm1, %xmm3 # 3 = 1/i
|
||||
pshufb %xmm7, %xmm11
|
||||
movdqa %xmm10, %xmm4 # 4 : 1/j
|
||||
movdqa %xmm10, %xmm12
|
||||
pxor %xmm5, %xmm3 # 3 = iak = 1/i + a/k
|
||||
pxor %xmm13, %xmm11
|
||||
pshufb %xmm0, %xmm4 # 4 = 1/j
|
||||
pshufb %xmm6, %xmm12
|
||||
movdqa %xmm10, %xmm2 # 2 : 1/iak
|
||||
movdqa %xmm10, %xmm8
|
||||
pxor %xmm5, %xmm4 # 4 = jak = 1/j + a/k
|
||||
pxor %xmm13, %xmm12
|
||||
pshufb %xmm3, %xmm2 # 2 = 1/iak
|
||||
pshufb %xmm11, %xmm8
|
||||
movdqa %xmm10, %xmm3 # 3 : 1/jak
|
||||
movdqa %xmm10, %xmm11
|
||||
pxor %xmm0, %xmm2 # 2 = io
|
||||
pxor %xmm6, %xmm8
|
||||
pshufb %xmm4, %xmm3 # 3 = 1/jak
|
||||
pshufb %xmm12, %xmm11
|
||||
movdqu (%r9), %xmm5
|
||||
# Also use %xmm5 in the second instance.
|
||||
pxor %xmm1, %xmm3 # 3 = jo
|
||||
pxor %xmm7, %xmm11
|
||||
jnz .Lenc2x_loop
|
||||
|
||||
# middle of last round
|
||||
movdqa -0x60(%r10), %xmm4 # 3 : sbou .Lk_sbo
|
||||
movdqa -0x50(%r10), %xmm0 # 0 : sbot .Lk_sbo+16
|
||||
movdqa %xmm4, %xmm12
|
||||
movdqa %xmm0, %xmm6
|
||||
pshufb %xmm2, %xmm4 # 4 = sbou
|
||||
pshufb %xmm8, %xmm12
|
||||
pxor %xmm5, %xmm4 # 4 = sb1u + k
|
||||
pxor %xmm5, %xmm12
|
||||
pshufb %xmm3, %xmm0 # 0 = sb1t
|
||||
pshufb %xmm11, %xmm6
|
||||
movdqa 0x40(%r11,%r10), %xmm1 # .Lk_sr[]
|
||||
# Also use %xmm1 in the second instance.
|
||||
pxor %xmm4, %xmm0 # 0 = A
|
||||
pxor %xmm12, %xmm6
|
||||
pshufb %xmm1, %xmm0
|
||||
pshufb %xmm1, %xmm6
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size _vpaes_encrypt_core_2x,.-_vpaes_encrypt_core_2x
|
||||
|
||||
|
||||
##
|
||||
## Decryption core
|
||||
##
|
||||
@@ -358,7 +173,6 @@ _vpaes_encrypt_core_2x:
|
||||
.type _vpaes_decrypt_core,\@abi-omnipotent
|
||||
.align 16
|
||||
_vpaes_decrypt_core:
|
||||
.cfi_startproc
|
||||
mov %rdx, %r9 # load key
|
||||
mov 240(%rdx),%eax
|
||||
movdqa %xmm9, %xmm1
|
||||
@@ -455,7 +269,6 @@ _vpaes_decrypt_core:
|
||||
pxor %xmm4, %xmm0 # 0 = A
|
||||
pshufb %xmm2, %xmm0
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size _vpaes_decrypt_core,.-_vpaes_decrypt_core
|
||||
|
||||
########################################################
|
||||
@@ -466,7 +279,6 @@ _vpaes_decrypt_core:
|
||||
.type _vpaes_schedule_core,\@abi-omnipotent
|
||||
.align 16
|
||||
_vpaes_schedule_core:
|
||||
.cfi_startproc
|
||||
# rdi = key
|
||||
# rsi = size in bits
|
||||
# rdx = buffer
|
||||
@@ -513,7 +325,7 @@ _vpaes_schedule_core:
|
||||
##
|
||||
.Lschedule_128:
|
||||
mov \$10, %esi
|
||||
|
||||
|
||||
.Loop_schedule_128:
|
||||
call _vpaes_schedule_round
|
||||
dec %rsi
|
||||
@@ -547,7 +359,7 @@ _vpaes_schedule_core:
|
||||
|
||||
.Loop_schedule_192:
|
||||
call _vpaes_schedule_round
|
||||
palignr \$8,%xmm6,%xmm0
|
||||
palignr \$8,%xmm6,%xmm0
|
||||
call _vpaes_schedule_mangle # save key n
|
||||
call _vpaes_schedule_192_smear
|
||||
call _vpaes_schedule_mangle # save key n+1
|
||||
@@ -573,7 +385,7 @@ _vpaes_schedule_core:
|
||||
movdqu 16(%rdi),%xmm0 # load key part 2 (unaligned)
|
||||
call _vpaes_schedule_transform # input transform
|
||||
mov \$7, %esi
|
||||
|
||||
|
||||
.Loop_schedule_256:
|
||||
call _vpaes_schedule_mangle # output low result
|
||||
movdqa %xmm0, %xmm6 # save cur_lo in xmm6
|
||||
@@ -582,7 +394,7 @@ _vpaes_schedule_core:
|
||||
call _vpaes_schedule_round
|
||||
dec %rsi
|
||||
jz .Lschedule_mangle_last
|
||||
call _vpaes_schedule_mangle
|
||||
call _vpaes_schedule_mangle
|
||||
|
||||
# low round. swap xmm7 and xmm6
|
||||
pshufd \$0xFF, %xmm0, %xmm0
|
||||
@@ -590,10 +402,10 @@ _vpaes_schedule_core:
|
||||
movdqa %xmm6, %xmm7
|
||||
call _vpaes_schedule_low_round
|
||||
movdqa %xmm5, %xmm7
|
||||
|
||||
|
||||
jmp .Loop_schedule_256
|
||||
|
||||
|
||||
|
||||
##
|
||||
## .aes_schedule_mangle_last
|
||||
##
|
||||
@@ -633,7 +445,6 @@ _vpaes_schedule_core:
|
||||
pxor %xmm6, %xmm6
|
||||
pxor %xmm7, %xmm7
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size _vpaes_schedule_core,.-_vpaes_schedule_core
|
||||
|
||||
##
|
||||
@@ -653,7 +464,6 @@ _vpaes_schedule_core:
|
||||
.type _vpaes_schedule_192_smear,\@abi-omnipotent
|
||||
.align 16
|
||||
_vpaes_schedule_192_smear:
|
||||
.cfi_startproc
|
||||
pshufd \$0x80, %xmm6, %xmm1 # d c 0 0 -> c 0 0 0
|
||||
pshufd \$0xFE, %xmm7, %xmm0 # b a _ _ -> b b b a
|
||||
pxor %xmm1, %xmm6 # -> c+d c 0 0
|
||||
@@ -662,7 +472,6 @@ _vpaes_schedule_192_smear:
|
||||
movdqa %xmm6, %xmm0
|
||||
movhlps %xmm1, %xmm6 # clobber low side with zeros
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size _vpaes_schedule_192_smear,.-_vpaes_schedule_192_smear
|
||||
|
||||
##
|
||||
@@ -686,7 +495,6 @@ _vpaes_schedule_192_smear:
|
||||
.type _vpaes_schedule_round,\@abi-omnipotent
|
||||
.align 16
|
||||
_vpaes_schedule_round:
|
||||
.cfi_startproc
|
||||
# extract rcon from xmm8
|
||||
pxor %xmm1, %xmm1
|
||||
palignr \$15, %xmm8, %xmm1
|
||||
@@ -696,9 +504,9 @@ _vpaes_schedule_round:
|
||||
# rotate
|
||||
pshufd \$0xFF, %xmm0, %xmm0
|
||||
palignr \$1, %xmm0, %xmm0
|
||||
|
||||
|
||||
# fall through...
|
||||
|
||||
|
||||
# low round: same as high round, but no rotation and no rcon.
|
||||
_vpaes_schedule_low_round:
|
||||
# smear xmm7
|
||||
@@ -737,10 +545,9 @@ _vpaes_schedule_low_round:
|
||||
pxor %xmm4, %xmm0 # 0 = sbox output
|
||||
|
||||
# add in smeared stuff
|
||||
pxor %xmm7, %xmm0
|
||||
pxor %xmm7, %xmm0
|
||||
movdqa %xmm0, %xmm7
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size _vpaes_schedule_round,.-_vpaes_schedule_round
|
||||
|
||||
##
|
||||
@@ -755,7 +562,6 @@ _vpaes_schedule_low_round:
|
||||
.type _vpaes_schedule_transform,\@abi-omnipotent
|
||||
.align 16
|
||||
_vpaes_schedule_transform:
|
||||
.cfi_startproc
|
||||
movdqa %xmm9, %xmm1
|
||||
pandn %xmm0, %xmm1
|
||||
psrld \$4, %xmm1
|
||||
@@ -766,7 +572,6 @@ _vpaes_schedule_transform:
|
||||
pshufb %xmm1, %xmm0
|
||||
pxor %xmm2, %xmm0
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size _vpaes_schedule_transform,.-_vpaes_schedule_transform
|
||||
|
||||
##
|
||||
@@ -795,7 +600,6 @@ _vpaes_schedule_transform:
|
||||
.type _vpaes_schedule_mangle,\@abi-omnipotent
|
||||
.align 16
|
||||
_vpaes_schedule_mangle:
|
||||
.cfi_startproc
|
||||
movdqa %xmm0, %xmm4 # save xmm0 for later
|
||||
movdqa .Lk_mc_forward(%rip),%xmm5
|
||||
test %rcx, %rcx
|
||||
@@ -860,7 +664,6 @@ _vpaes_schedule_mangle:
|
||||
and \$0x30, %r8
|
||||
movdqu %xmm3, (%rdx)
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size _vpaes_schedule_mangle,.-_vpaes_schedule_mangle
|
||||
|
||||
#
|
||||
@@ -870,12 +673,6 @@ _vpaes_schedule_mangle:
|
||||
.type ${PREFIX}_set_encrypt_key,\@function,3
|
||||
.align 16
|
||||
${PREFIX}_set_encrypt_key:
|
||||
.cfi_startproc
|
||||
#ifdef BORINGSSL_DISPATCH_TEST
|
||||
.extern BORINGSSL_function_hit
|
||||
movb \$1, BORINGSSL_function_hit+5(%rip)
|
||||
#endif
|
||||
|
||||
___
|
||||
$code.=<<___ if ($win64);
|
||||
lea -0xb8(%rsp),%rsp
|
||||
@@ -918,14 +715,12 @@ ___
|
||||
$code.=<<___;
|
||||
xor %eax,%eax
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size ${PREFIX}_set_encrypt_key,.-${PREFIX}_set_encrypt_key
|
||||
|
||||
.globl ${PREFIX}_set_decrypt_key
|
||||
.type ${PREFIX}_set_decrypt_key,\@function,3
|
||||
.align 16
|
||||
${PREFIX}_set_decrypt_key:
|
||||
.cfi_startproc
|
||||
___
|
||||
$code.=<<___ if ($win64);
|
||||
lea -0xb8(%rsp),%rsp
|
||||
@@ -973,18 +768,12 @@ ___
|
||||
$code.=<<___;
|
||||
xor %eax,%eax
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size ${PREFIX}_set_decrypt_key,.-${PREFIX}_set_decrypt_key
|
||||
|
||||
.globl ${PREFIX}_encrypt
|
||||
.type ${PREFIX}_encrypt,\@function,3
|
||||
.align 16
|
||||
${PREFIX}_encrypt:
|
||||
.cfi_startproc
|
||||
#ifdef BORINGSSL_DISPATCH_TEST
|
||||
.extern BORINGSSL_function_hit
|
||||
movb \$1, BORINGSSL_function_hit+4(%rip)
|
||||
#endif
|
||||
___
|
||||
$code.=<<___ if ($win64);
|
||||
lea -0xb8(%rsp),%rsp
|
||||
@@ -1022,14 +811,12 @@ $code.=<<___ if ($win64);
|
||||
___
|
||||
$code.=<<___;
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size ${PREFIX}_encrypt,.-${PREFIX}_encrypt
|
||||
|
||||
.globl ${PREFIX}_decrypt
|
||||
.type ${PREFIX}_decrypt,\@function,3
|
||||
.align 16
|
||||
${PREFIX}_decrypt:
|
||||
.cfi_startproc
|
||||
___
|
||||
$code.=<<___ if ($win64);
|
||||
lea -0xb8(%rsp),%rsp
|
||||
@@ -1067,7 +854,6 @@ $code.=<<___ if ($win64);
|
||||
___
|
||||
$code.=<<___;
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size ${PREFIX}_decrypt,.-${PREFIX}_decrypt
|
||||
___
|
||||
{
|
||||
@@ -1080,7 +866,6 @@ $code.=<<___;
|
||||
.type ${PREFIX}_cbc_encrypt,\@function,6
|
||||
.align 16
|
||||
${PREFIX}_cbc_encrypt:
|
||||
.cfi_startproc
|
||||
xchg $key,$len
|
||||
___
|
||||
($len,$key)=($key,$len);
|
||||
@@ -1151,115 +936,9 @@ ___
|
||||
$code.=<<___;
|
||||
.Lcbc_abort:
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size ${PREFIX}_cbc_encrypt,.-${PREFIX}_cbc_encrypt
|
||||
___
|
||||
}
|
||||
{
|
||||
my ($inp,$out,$blocks,$key,$ivp)=("%rdi","%rsi","%rdx","%rcx","%r8");
|
||||
# void vpaes_ctr32_encrypt_blocks(const uint8_t *inp, uint8_t *out,
|
||||
# size_t blocks, const AES_KEY *key,
|
||||
# const uint8_t ivp[16]);
|
||||
$code.=<<___;
|
||||
.globl ${PREFIX}_ctr32_encrypt_blocks
|
||||
.type ${PREFIX}_ctr32_encrypt_blocks,\@function,5
|
||||
.align 16
|
||||
${PREFIX}_ctr32_encrypt_blocks:
|
||||
.cfi_startproc
|
||||
# _vpaes_encrypt_core and _vpaes_encrypt_core_2x expect the key in %rdx.
|
||||
xchg $key, $blocks
|
||||
___
|
||||
($blocks,$key)=($key,$blocks);
|
||||
$code.=<<___;
|
||||
test $blocks, $blocks
|
||||
jz .Lctr32_abort
|
||||
___
|
||||
$code.=<<___ if ($win64);
|
||||
lea -0xb8(%rsp),%rsp
|
||||
movaps %xmm6,0x10(%rsp)
|
||||
movaps %xmm7,0x20(%rsp)
|
||||
movaps %xmm8,0x30(%rsp)
|
||||
movaps %xmm9,0x40(%rsp)
|
||||
movaps %xmm10,0x50(%rsp)
|
||||
movaps %xmm11,0x60(%rsp)
|
||||
movaps %xmm12,0x70(%rsp)
|
||||
movaps %xmm13,0x80(%rsp)
|
||||
movaps %xmm14,0x90(%rsp)
|
||||
movaps %xmm15,0xa0(%rsp)
|
||||
.Lctr32_body:
|
||||
___
|
||||
$code.=<<___;
|
||||
movdqu ($ivp), %xmm0 # Load IV.
|
||||
movdqa .Lctr_add_one(%rip), %xmm8
|
||||
sub $inp, $out # This allows only incrementing $inp.
|
||||
call _vpaes_preheat
|
||||
movdqa %xmm0, %xmm6
|
||||
pshufb .Lrev_ctr(%rip), %xmm6
|
||||
|
||||
test \$1, $blocks
|
||||
jz .Lctr32_prep_loop
|
||||
|
||||
# Handle one block so the remaining block count is even for
|
||||
# _vpaes_encrypt_core_2x.
|
||||
movdqu ($inp), %xmm7 # Load input.
|
||||
call _vpaes_encrypt_core
|
||||
pxor %xmm7, %xmm0
|
||||
paddd %xmm8, %xmm6
|
||||
movdqu %xmm0, ($out,$inp)
|
||||
sub \$1, $blocks
|
||||
lea 16($inp), $inp
|
||||
jz .Lctr32_done
|
||||
|
||||
.Lctr32_prep_loop:
|
||||
# _vpaes_encrypt_core_2x leaves only %xmm14 and %xmm15 as spare
|
||||
# registers. We maintain two byte-swapped counters in them.
|
||||
movdqa %xmm6, %xmm14
|
||||
movdqa %xmm6, %xmm15
|
||||
paddd %xmm8, %xmm15
|
||||
|
||||
.Lctr32_loop:
|
||||
movdqa .Lrev_ctr(%rip), %xmm1 # Set up counters.
|
||||
movdqa %xmm14, %xmm0
|
||||
movdqa %xmm15, %xmm6
|
||||
pshufb %xmm1, %xmm0
|
||||
pshufb %xmm1, %xmm6
|
||||
call _vpaes_encrypt_core_2x
|
||||
movdqu ($inp), %xmm1 # Load input.
|
||||
movdqu 16($inp), %xmm2
|
||||
movdqa .Lctr_add_two(%rip), %xmm3
|
||||
pxor %xmm1, %xmm0 # XOR input.
|
||||
pxor %xmm2, %xmm6
|
||||
paddd %xmm3, %xmm14 # Increment counters.
|
||||
paddd %xmm3, %xmm15
|
||||
movdqu %xmm0, ($out,$inp) # Write output.
|
||||
movdqu %xmm6, 16($out,$inp)
|
||||
sub \$2, $blocks # Advance loop.
|
||||
lea 32($inp), $inp
|
||||
jnz .Lctr32_loop
|
||||
|
||||
.Lctr32_done:
|
||||
___
|
||||
$code.=<<___ if ($win64);
|
||||
movaps 0x10(%rsp),%xmm6
|
||||
movaps 0x20(%rsp),%xmm7
|
||||
movaps 0x30(%rsp),%xmm8
|
||||
movaps 0x40(%rsp),%xmm9
|
||||
movaps 0x50(%rsp),%xmm10
|
||||
movaps 0x60(%rsp),%xmm11
|
||||
movaps 0x70(%rsp),%xmm12
|
||||
movaps 0x80(%rsp),%xmm13
|
||||
movaps 0x90(%rsp),%xmm14
|
||||
movaps 0xa0(%rsp),%xmm15
|
||||
lea 0xb8(%rsp),%rsp
|
||||
.Lctr32_epilogue:
|
||||
___
|
||||
$code.=<<___;
|
||||
.Lctr32_abort:
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size ${PREFIX}_ctr32_encrypt_blocks,.-${PREFIX}_ctr32_encrypt_blocks
|
||||
___
|
||||
}
|
||||
$code.=<<___;
|
||||
##
|
||||
## _aes_preheat
|
||||
@@ -1270,7 +949,6 @@ $code.=<<___;
|
||||
.type _vpaes_preheat,\@abi-omnipotent
|
||||
.align 16
|
||||
_vpaes_preheat:
|
||||
.cfi_startproc
|
||||
lea .Lk_s0F(%rip), %r10
|
||||
movdqa -0x20(%r10), %xmm10 # .Lk_inv
|
||||
movdqa -0x10(%r10), %xmm11 # .Lk_inv+16
|
||||
@@ -1280,7 +958,6 @@ _vpaes_preheat:
|
||||
movdqa 0x50(%r10), %xmm15 # .Lk_sb2
|
||||
movdqa 0x60(%r10), %xmm14 # .Lk_sb2+16
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size _vpaes_preheat,.-_vpaes_preheat
|
||||
########################################################
|
||||
## ##
|
||||
@@ -1383,17 +1060,6 @@ _vpaes_consts:
|
||||
.Lk_dsbo: # decryption sbox final output
|
||||
.quad 0x1387EA537EF94000, 0xC7AA6DB9D4943E2D
|
||||
.quad 0x12D7560F93441D00, 0xCA4B8159D8C58E9C
|
||||
|
||||
# .Lrev_ctr is a permutation which byte-swaps the counter portion of the IV.
|
||||
.Lrev_ctr:
|
||||
.quad 0x0706050403020100, 0x0c0d0e0f0b0a0908
|
||||
# .Lctr_add_* may be added to a byte-swapped xmm register to increment the
|
||||
# counter. The register must be byte-swapped again to form the actual input.
|
||||
.Lctr_add_one:
|
||||
.quad 0x0000000000000000, 0x0000000100000000
|
||||
.Lctr_add_two:
|
||||
.quad 0x0000000000000000, 0x0000000200000000
|
||||
|
||||
.asciz "Vector Permutation AES for x86_64/SSSE3, Mike Hamburg (Stanford University)"
|
||||
.align 64
|
||||
.size _vpaes_consts,.-_vpaes_consts
|
||||
@@ -1509,10 +1175,6 @@ se_handler:
|
||||
.rva .LSEH_end_${PREFIX}_cbc_encrypt
|
||||
.rva .LSEH_info_${PREFIX}_cbc_encrypt
|
||||
|
||||
.rva .LSEH_begin_${PREFIX}_ctr32_encrypt_blocks
|
||||
.rva .LSEH_end_${PREFIX}_ctr32_encrypt_blocks
|
||||
.rva .LSEH_info_${PREFIX}_ctr32_encrypt_blocks
|
||||
|
||||
.section .xdata
|
||||
.align 8
|
||||
.LSEH_info_${PREFIX}_set_encrypt_key:
|
||||
@@ -1535,10 +1197,6 @@ se_handler:
|
||||
.byte 9,0,0,0
|
||||
.rva se_handler
|
||||
.rva .Lcbc_body,.Lcbc_epilogue # HandlerData[]
|
||||
.LSEH_info_${PREFIX}_ctr32_encrypt_blocks:
|
||||
.byte 9,0,0,0
|
||||
.rva se_handler
|
||||
.rva .Lctr32_body,.Lctr32_epilogue # HandlerData[]
|
||||
___
|
||||
}
|
||||
|
||||
@@ -1546,4 +1204,4 @@ $code =~ s/\`([^\`]*)\`/eval($1)/gem;
|
||||
|
||||
print $code;
|
||||
|
||||
close STDOUT or die "error closing STDOUT";
|
||||
close STDOUT;
|
||||
@@ -0,0 +1,87 @@
|
||||
/* ====================================================================
|
||||
* Copyright (c) 2002-2006 The OpenSSL Project. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this
|
||||
* software must display the following acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
||||
*
|
||||
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* prior written permission. For written permission, please contact
|
||||
* openssl-core@openssl.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "OpenSSL"
|
||||
* nor may "OpenSSL" appear in their names without prior written
|
||||
* permission of the OpenSSL Project.
|
||||
*
|
||||
* 6. Redistributions of any form whatsoever must retain the following
|
||||
* acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
||||
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ==================================================================== */
|
||||
|
||||
#ifndef OPENSSL_HEADER_AES_INTERNAL_H
|
||||
#define OPENSSL_HEADER_AES_INTERNAL_H
|
||||
|
||||
#include <openssl/base.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(_MSC_VER) && \
|
||||
(defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64))
|
||||
#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
|
||||
#define GETU32(p) SWAP(*((uint32_t *)(p)))
|
||||
#define PUTU32(ct, st) \
|
||||
{ *((uint32_t *)(ct)) = SWAP((st)); }
|
||||
#else
|
||||
#define GETU32(pt) \
|
||||
(((uint32_t)(pt)[0] << 24) ^ ((uint32_t)(pt)[1] << 16) ^ \
|
||||
((uint32_t)(pt)[2] << 8) ^ ((uint32_t)(pt)[3]))
|
||||
#define PUTU32(ct, st) \
|
||||
{ \
|
||||
(ct)[0] = (uint8_t)((st) >> 24); \
|
||||
(ct)[1] = (uint8_t)((st) >> 16); \
|
||||
(ct)[2] = (uint8_t)((st) >> 8); \
|
||||
(ct)[3] = (uint8_t)(st); \
|
||||
}
|
||||
#endif
|
||||
|
||||
#define MAXKC (256 / 32)
|
||||
#define MAXKB (256 / 8)
|
||||
#define MAXNR 14
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} /* extern C */
|
||||
#endif
|
||||
|
||||
#endif /* OPENSSL_HEADER_AES_INTERNAL_H */
|
||||
@@ -0,0 +1,108 @@
|
||||
/* ====================================================================
|
||||
* Copyright (c) 2002-2006 The OpenSSL Project. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this
|
||||
* software must display the following acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
||||
*
|
||||
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* prior written permission. For written permission, please contact
|
||||
* openssl-core@openssl.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "OpenSSL"
|
||||
* nor may "OpenSSL" appear in their names without prior written
|
||||
* permission of the OpenSSL Project.
|
||||
*
|
||||
* 6. Redistributions of any form whatsoever must retain the following
|
||||
* acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
||||
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ==================================================================== */
|
||||
|
||||
#include <openssl/aes.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "../modes/internal.h"
|
||||
|
||||
|
||||
void AES_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
|
||||
const AES_KEY *key, uint8_t ivec[AES_BLOCK_SIZE],
|
||||
uint8_t ecount_buf[AES_BLOCK_SIZE], unsigned int *num) {
|
||||
CRYPTO_ctr128_encrypt(in, out, len, key, ivec, ecount_buf, num,
|
||||
(block128_f)AES_encrypt);
|
||||
}
|
||||
|
||||
void AES_ecb_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key,
|
||||
const int enc) {
|
||||
assert(in && out && key);
|
||||
assert((AES_ENCRYPT == enc) || (AES_DECRYPT == enc));
|
||||
|
||||
if (AES_ENCRYPT == enc) {
|
||||
AES_encrypt(in, out, key);
|
||||
} else {
|
||||
AES_decrypt(in, out, key);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(OPENSSL_NO_ASM) || \
|
||||
(!defined(OPENSSL_X86_64) && !defined(OPENSSL_X86))
|
||||
void AES_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len,
|
||||
const AES_KEY *key, uint8_t *ivec, const int enc) {
|
||||
|
||||
if (enc) {
|
||||
CRYPTO_cbc128_encrypt(in, out, len, key, ivec, (block128_f)AES_encrypt);
|
||||
} else {
|
||||
CRYPTO_cbc128_decrypt(in, out, len, key, ivec, (block128_f)AES_decrypt);
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
void asm_AES_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len,
|
||||
const AES_KEY *key, uint8_t *ivec, const int enc);
|
||||
void AES_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len,
|
||||
const AES_KEY *key, uint8_t *ivec, const int enc) {
|
||||
asm_AES_cbc_encrypt(in, out, len, key, ivec, enc);
|
||||
}
|
||||
|
||||
#endif /* OPENSSL_NO_ASM || (!OPENSSL_X86_64 && !OPENSSL_X86) */
|
||||
|
||||
void AES_ofb128_encrypt(const uint8_t *in, uint8_t *out, size_t length,
|
||||
const AES_KEY *key, uint8_t *ivec, int *num) {
|
||||
CRYPTO_ofb128_encrypt(in, out, length, key, ivec, num,
|
||||
(block128_f)AES_encrypt);
|
||||
}
|
||||
|
||||
void AES_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t length,
|
||||
const AES_KEY *key, uint8_t *ivec, int *num,
|
||||
int enc) {
|
||||
CRYPTO_cfb128_encrypt(in, out, length, key, ivec, num, enc,
|
||||
(block128_f)AES_encrypt);
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
include_directories(../../include)
|
||||
|
||||
add_library(
|
||||
asn1
|
||||
|
||||
OBJECT
|
||||
|
||||
a_bitstr.c
|
||||
a_bool.c
|
||||
a_bytes.c
|
||||
a_d2i_fp.c
|
||||
a_dup.c
|
||||
a_enum.c
|
||||
a_gentm.c
|
||||
a_i2d_fp.c
|
||||
a_int.c
|
||||
a_mbstr.c
|
||||
a_object.c
|
||||
a_octet.c
|
||||
a_print.c
|
||||
a_strnid.c
|
||||
a_time.c
|
||||
a_type.c
|
||||
a_utctm.c
|
||||
a_utf8.c
|
||||
asn1_lib.c
|
||||
asn1_par.c
|
||||
asn_pack.c
|
||||
bio_asn1.c
|
||||
bio_ndef.c
|
||||
f_enum.c
|
||||
f_int.c
|
||||
f_string.c
|
||||
t_bitst.c
|
||||
tasn_dec.c
|
||||
tasn_enc.c
|
||||
tasn_fre.c
|
||||
tasn_new.c
|
||||
tasn_prn.c
|
||||
tasn_typ.c
|
||||
tasn_utl.c
|
||||
x_bignum.c
|
||||
x_long.c
|
||||
)
|
||||
|
||||
add_executable(
|
||||
asn1_test
|
||||
|
||||
asn1_test.cc
|
||||
|
||||
$<TARGET_OBJECTS:test_support>
|
||||
)
|
||||
|
||||
target_link_libraries(asn1_test crypto)
|
||||
add_dependencies(all_tests asn1_test)
|
||||
+8
-16
@@ -56,21 +56,17 @@
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
int ASN1_BIT_STRING_set(ASN1_BIT_STRING *x, unsigned char *d, int len)
|
||||
{
|
||||
return M_ASN1_BIT_STRING_set(x, d, len);
|
||||
}
|
||||
|
||||
int i2c_ASN1_BIT_STRING(const ASN1_BIT_STRING *a, unsigned char **pp)
|
||||
int i2c_ASN1_BIT_STRING(ASN1_BIT_STRING *a, unsigned char **pp)
|
||||
{
|
||||
int ret, j, bits, len;
|
||||
unsigned char *p, *d;
|
||||
@@ -119,7 +115,7 @@ int i2c_ASN1_BIT_STRING(const ASN1_BIT_STRING *a, unsigned char **pp)
|
||||
|
||||
*(p++) = (unsigned char)bits;
|
||||
d = a->data;
|
||||
OPENSSL_memcpy(p, d, len);
|
||||
memcpy(p, d, len);
|
||||
p += len;
|
||||
if (len > 0)
|
||||
p[-1] &= (0xff << bits);
|
||||
@@ -140,11 +136,6 @@ ASN1_BIT_STRING *c2i_ASN1_BIT_STRING(ASN1_BIT_STRING **a,
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (len > INT_MAX) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_STRING_TOO_LONG);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if ((a == NULL) || ((*a) == NULL)) {
|
||||
if ((ret = M_ASN1_BIT_STRING_new()) == NULL)
|
||||
return (NULL);
|
||||
@@ -171,7 +162,7 @@ ASN1_BIT_STRING *c2i_ASN1_BIT_STRING(ASN1_BIT_STRING **a,
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
OPENSSL_memcpy(s, p, (int)len);
|
||||
memcpy(s, p, (int)len);
|
||||
s[len - 1] &= (0xff << padding);
|
||||
p += len;
|
||||
} else
|
||||
@@ -217,13 +208,14 @@ int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value)
|
||||
if (a->data == NULL)
|
||||
c = (unsigned char *)OPENSSL_malloc(w + 1);
|
||||
else
|
||||
c = (unsigned char *)OPENSSL_realloc(a->data, w + 1);
|
||||
c = (unsigned char *)OPENSSL_realloc_clean(a->data,
|
||||
a->length, w + 1);
|
||||
if (c == NULL) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
if (w + 1 - a->length > 0)
|
||||
OPENSSL_memset(c + a->length, 0, w + 1 - a->length);
|
||||
memset(c + a->length, 0, w + 1 - a->length);
|
||||
a->data = c;
|
||||
a->length = w + 1;
|
||||
}
|
||||
@@ -233,7 +225,7 @@ int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value)
|
||||
return (1);
|
||||
}
|
||||
|
||||
int ASN1_BIT_STRING_get_bit(const ASN1_BIT_STRING *a, int n)
|
||||
int ASN1_BIT_STRING_get_bit(ASN1_BIT_STRING *a, int n)
|
||||
{
|
||||
int w, v;
|
||||
|
||||
@@ -250,7 +242,7 @@ int ASN1_BIT_STRING_get_bit(const ASN1_BIT_STRING *a, int n)
|
||||
* which is not specified in 'flags', 1 otherwise.
|
||||
* 'len' is the length of 'flags'.
|
||||
*/
|
||||
int ASN1_BIT_STRING_check(const ASN1_BIT_STRING *a,
|
||||
int ASN1_BIT_STRING_check(ASN1_BIT_STRING *a,
|
||||
unsigned char *flags, int flags_len)
|
||||
{
|
||||
int i, ok;
|
||||
|
||||
+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)
|
||||
|
||||
@@ -0,0 +1,308 @@
|
||||
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* This package is an SSL implementation written
|
||||
* by Eric Young (eay@cryptsoft.com).
|
||||
* The implementation was written so as to conform with Netscapes SSL.
|
||||
*
|
||||
* This library is free for commercial and non-commercial use as long as
|
||||
* the following conditions are aheared to. The following conditions
|
||||
* apply to all code found in this distribution, be it the RC4, RSA,
|
||||
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
|
||||
* included with this distribution is covered by the same copyright terms
|
||||
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||
*
|
||||
* Copyright remains Eric Young's, and as such any Copyright notices in
|
||||
* the code are not to be removed.
|
||||
* If this package is used in a product, Eric Young should be given attribution
|
||||
* as the author of the parts of the library used.
|
||||
* This can be in the form of a textual message at program startup or
|
||||
* in documentation (online or textual) provided with the package.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* "This product includes cryptographic software written by
|
||||
* Eric Young (eay@cryptsoft.com)"
|
||||
* The word 'cryptographic' can be left out if the rouines from the library
|
||||
* being used are not cryptographic related :-).
|
||||
* 4. If you include any Windows specific code (or a derivative thereof) from
|
||||
* the apps directory (application code) you must include an acknowledgement:
|
||||
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* The licence and distribution terms for any publically available version or
|
||||
* derivative of this code cannot be changed. i.e. this code cannot simply be
|
||||
* copied and put under another distribution licence
|
||||
* [including the GNU Public Licence.] */
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/buf.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
static int asn1_collate_primitive(ASN1_STRING *a, ASN1_const_CTX *c);
|
||||
/*
|
||||
* type is a 'bitmap' of acceptable string types.
|
||||
*/
|
||||
ASN1_STRING *d2i_ASN1_type_bytes(ASN1_STRING **a, const unsigned char **pp,
|
||||
long length, int type)
|
||||
{
|
||||
ASN1_STRING *ret = NULL;
|
||||
const unsigned char *p;
|
||||
unsigned char *s;
|
||||
long len;
|
||||
int inf, tag, xclass;
|
||||
int i = 0;
|
||||
|
||||
p = *pp;
|
||||
inf = ASN1_get_object(&p, &len, &tag, &xclass, length);
|
||||
if (inf & 0x80)
|
||||
goto err;
|
||||
|
||||
if (tag >= 32) {
|
||||
i = ASN1_R_TAG_VALUE_TOO_HIGH;
|
||||
goto err;
|
||||
}
|
||||
if (!(ASN1_tag2bit(tag) & type)) {
|
||||
i = ASN1_R_WRONG_TYPE;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* If a bit-string, exit early */
|
||||
if (tag == V_ASN1_BIT_STRING)
|
||||
return (d2i_ASN1_BIT_STRING(a, pp, length));
|
||||
|
||||
if ((a == NULL) || ((*a) == NULL)) {
|
||||
if ((ret = ASN1_STRING_new()) == NULL)
|
||||
return (NULL);
|
||||
} else
|
||||
ret = (*a);
|
||||
|
||||
if (len != 0) {
|
||||
s = (unsigned char *)OPENSSL_malloc((int)len + 1);
|
||||
if (s == NULL) {
|
||||
i = ERR_R_MALLOC_FAILURE;
|
||||
goto err;
|
||||
}
|
||||
memcpy(s, p, (int)len);
|
||||
s[len] = '\0';
|
||||
p += len;
|
||||
} else
|
||||
s = NULL;
|
||||
|
||||
if (ret->data != NULL)
|
||||
OPENSSL_free(ret->data);
|
||||
ret->length = (int)len;
|
||||
ret->data = s;
|
||||
ret->type = tag;
|
||||
if (a != NULL)
|
||||
(*a) = ret;
|
||||
*pp = p;
|
||||
return (ret);
|
||||
err:
|
||||
OPENSSL_PUT_ERROR(ASN1, i);
|
||||
if ((ret != NULL) && ((a == NULL) || (*a != ret)))
|
||||
ASN1_STRING_free(ret);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
int i2d_ASN1_bytes(ASN1_STRING *a, unsigned char **pp, int tag, int xclass)
|
||||
{
|
||||
int ret, r, constructed;
|
||||
unsigned char *p;
|
||||
|
||||
if (a == NULL)
|
||||
return (0);
|
||||
|
||||
if (tag == V_ASN1_BIT_STRING)
|
||||
return (i2d_ASN1_BIT_STRING(a, pp));
|
||||
|
||||
ret = a->length;
|
||||
r = ASN1_object_size(0, ret, tag);
|
||||
if (pp == NULL)
|
||||
return (r);
|
||||
p = *pp;
|
||||
|
||||
if ((tag == V_ASN1_SEQUENCE) || (tag == V_ASN1_SET))
|
||||
constructed = 1;
|
||||
else
|
||||
constructed = 0;
|
||||
ASN1_put_object(&p, constructed, ret, tag, xclass);
|
||||
memcpy(p, a->data, a->length);
|
||||
p += a->length;
|
||||
*pp = p;
|
||||
return (r);
|
||||
}
|
||||
|
||||
ASN1_STRING *d2i_ASN1_bytes(ASN1_STRING **a, const unsigned char **pp,
|
||||
long length, int Ptag, int Pclass)
|
||||
{
|
||||
ASN1_STRING *ret = NULL;
|
||||
const unsigned char *p;
|
||||
unsigned char *s;
|
||||
long len;
|
||||
int inf, tag, xclass;
|
||||
int i = 0;
|
||||
|
||||
if ((a == NULL) || ((*a) == NULL)) {
|
||||
if ((ret = ASN1_STRING_new()) == NULL)
|
||||
return (NULL);
|
||||
} else
|
||||
ret = (*a);
|
||||
|
||||
p = *pp;
|
||||
inf = ASN1_get_object(&p, &len, &tag, &xclass, length);
|
||||
if (inf & 0x80) {
|
||||
i = ASN1_R_BAD_OBJECT_HEADER;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (tag != Ptag) {
|
||||
i = ASN1_R_WRONG_TAG;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (inf & V_ASN1_CONSTRUCTED) {
|
||||
ASN1_const_CTX c;
|
||||
|
||||
c.pp = pp;
|
||||
c.p = p;
|
||||
c.inf = inf;
|
||||
c.slen = len;
|
||||
c.tag = Ptag;
|
||||
c.xclass = Pclass;
|
||||
c.max = (length == 0) ? 0 : (p + length);
|
||||
if (!asn1_collate_primitive(ret, &c))
|
||||
goto err;
|
||||
else {
|
||||
p = c.p;
|
||||
}
|
||||
} else {
|
||||
if (len != 0) {
|
||||
if ((ret->length < len) || (ret->data == NULL)) {
|
||||
if (ret->data != NULL)
|
||||
OPENSSL_free(ret->data);
|
||||
s = (unsigned char *)OPENSSL_malloc((int)len + 1);
|
||||
if (s == NULL) {
|
||||
i = ERR_R_MALLOC_FAILURE;
|
||||
goto err;
|
||||
}
|
||||
} else
|
||||
s = ret->data;
|
||||
memcpy(s, p, (int)len);
|
||||
s[len] = '\0';
|
||||
p += len;
|
||||
} else {
|
||||
s = NULL;
|
||||
if (ret->data != NULL)
|
||||
OPENSSL_free(ret->data);
|
||||
}
|
||||
|
||||
ret->length = (int)len;
|
||||
ret->data = s;
|
||||
ret->type = Ptag;
|
||||
}
|
||||
|
||||
if (a != NULL)
|
||||
(*a) = ret;
|
||||
*pp = p;
|
||||
return (ret);
|
||||
err:
|
||||
if ((ret != NULL) && ((a == NULL) || (*a != ret)))
|
||||
ASN1_STRING_free(ret);
|
||||
OPENSSL_PUT_ERROR(ASN1, i);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* We are about to parse 0..n d2i_ASN1_bytes objects, we are to collapse them
|
||||
* into the one structure that is then returned
|
||||
*/
|
||||
/*
|
||||
* There have been a few bug fixes for this function from Paul Keogh
|
||||
* <paul.keogh@sse.ie>, many thanks to him
|
||||
*/
|
||||
static int asn1_collate_primitive(ASN1_STRING *a, ASN1_const_CTX *c)
|
||||
{
|
||||
ASN1_STRING *os = NULL;
|
||||
BUF_MEM b;
|
||||
int num;
|
||||
|
||||
b.length = 0;
|
||||
b.max = 0;
|
||||
b.data = NULL;
|
||||
|
||||
if (a == NULL) {
|
||||
c->error = ERR_R_PASSED_NULL_PARAMETER;
|
||||
goto err;
|
||||
}
|
||||
|
||||
num = 0;
|
||||
for (;;) {
|
||||
if (c->inf & 1) {
|
||||
c->eos = ASN1_const_check_infinite_end(&c->p,
|
||||
(long)(c->max - c->p));
|
||||
if (c->eos)
|
||||
break;
|
||||
} else {
|
||||
if (c->slen <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
c->q = c->p;
|
||||
if (d2i_ASN1_bytes(&os, &c->p, c->max - c->p, c->tag, c->xclass)
|
||||
== NULL) {
|
||||
c->error = ERR_R_ASN1_LIB;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!BUF_MEM_grow_clean(&b, num + os->length)) {
|
||||
c->error = ERR_R_BUF_LIB;
|
||||
goto err;
|
||||
}
|
||||
memcpy(&(b.data[num]), os->data, os->length);
|
||||
if (!(c->inf & 1))
|
||||
c->slen -= (c->p - c->q);
|
||||
num += os->length;
|
||||
}
|
||||
|
||||
if (!asn1_const_Finish(c))
|
||||
goto err;
|
||||
|
||||
a->length = num;
|
||||
if (a->data != NULL)
|
||||
OPENSSL_free(a->data);
|
||||
a->data = (unsigned char *)b.data;
|
||||
if (os != NULL)
|
||||
ASN1_STRING_free(os);
|
||||
return (1);
|
||||
err:
|
||||
OPENSSL_PUT_ERROR(ASN1, c->error);
|
||||
if (os != NULL)
|
||||
ASN1_STRING_free(os);
|
||||
if (b.data != NULL)
|
||||
OPENSSL_free(b.data);
|
||||
return (0);
|
||||
}
|
||||
+191
-17
@@ -58,36 +58,210 @@
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/buf.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb);
|
||||
|
||||
#ifndef NO_OLD_ASN1
|
||||
# ifndef OPENSSL_NO_FP_API
|
||||
|
||||
void *ASN1_d2i_fp(void *(*xnew) (void), d2i_of_void *d2i, FILE *in, void **x)
|
||||
{
|
||||
BIO *b;
|
||||
void *ret;
|
||||
|
||||
if ((b = BIO_new(BIO_s_file())) == NULL) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_BUF_LIB);
|
||||
return (NULL);
|
||||
}
|
||||
BIO_set_fp(b, in, BIO_NOCLOSE);
|
||||
ret = ASN1_d2i_bio(xnew, d2i, b, x);
|
||||
BIO_free(b);
|
||||
return (ret);
|
||||
}
|
||||
# endif
|
||||
|
||||
void *ASN1_d2i_bio(void *(*xnew) (void), d2i_of_void *d2i, BIO *in, void **x)
|
||||
{
|
||||
BUF_MEM *b = NULL;
|
||||
const unsigned char *p;
|
||||
void *ret = NULL;
|
||||
int len;
|
||||
|
||||
len = asn1_d2i_read_bio(in, &b);
|
||||
if (len < 0)
|
||||
goto err;
|
||||
|
||||
p = (unsigned char *)b->data;
|
||||
ret = d2i(x, &p, len);
|
||||
err:
|
||||
if (b != NULL)
|
||||
BUF_MEM_free(b);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x)
|
||||
{
|
||||
uint8_t *data;
|
||||
size_t len;
|
||||
// Historically, this function did not impose a limit in OpenSSL and is used
|
||||
// to read CRLs, so we leave this without an external bound.
|
||||
if (!BIO_read_asn1(in, &data, &len, INT_MAX)) {
|
||||
return NULL;
|
||||
}
|
||||
const uint8_t *ptr = data;
|
||||
void *ret = ASN1_item_d2i(x, &ptr, len, it);
|
||||
OPENSSL_free(data);
|
||||
return ret;
|
||||
BUF_MEM *b = NULL;
|
||||
const unsigned char *p;
|
||||
void *ret = NULL;
|
||||
int len;
|
||||
|
||||
len = asn1_d2i_read_bio(in, &b);
|
||||
if (len < 0)
|
||||
goto err;
|
||||
|
||||
p = (const unsigned char *)b->data;
|
||||
ret = ASN1_item_d2i(x, &p, len, it);
|
||||
err:
|
||||
if (b != NULL)
|
||||
BUF_MEM_free(b);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_FP_API
|
||||
void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x)
|
||||
{
|
||||
BIO *b = BIO_new_fp(in, BIO_NOCLOSE);
|
||||
if (b == NULL) {
|
||||
BIO *b;
|
||||
char *ret;
|
||||
|
||||
if ((b = BIO_new(BIO_s_file())) == NULL) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_BUF_LIB);
|
||||
return NULL;
|
||||
return (NULL);
|
||||
}
|
||||
void *ret = ASN1_item_d2i_bio(it, b, x);
|
||||
BIO_set_fp(b, in, BIO_NOCLOSE);
|
||||
ret = ASN1_item_d2i_bio(it, b, x);
|
||||
BIO_free(b);
|
||||
return ret;
|
||||
return (ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define HEADER_SIZE 8
|
||||
static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
|
||||
{
|
||||
BUF_MEM *b;
|
||||
unsigned char *p;
|
||||
int i;
|
||||
ASN1_const_CTX c;
|
||||
size_t want = HEADER_SIZE;
|
||||
int eos = 0;
|
||||
size_t off = 0;
|
||||
size_t len = 0;
|
||||
|
||||
b = BUF_MEM_new();
|
||||
if (b == NULL) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ERR_clear_error();
|
||||
for (;;) {
|
||||
if (want >= (len - off)) {
|
||||
want -= (len - off);
|
||||
|
||||
if (len + want < len || !BUF_MEM_grow_clean(b, len + want)) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
i = BIO_read(in, &(b->data[len]), want);
|
||||
if ((i < 0) && ((len - off) == 0)) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ENOUGH_DATA);
|
||||
goto err;
|
||||
}
|
||||
if (i > 0) {
|
||||
if (len + i < len) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG);
|
||||
goto err;
|
||||
}
|
||||
len += i;
|
||||
}
|
||||
}
|
||||
/* else data already loaded */
|
||||
|
||||
p = (unsigned char *)&(b->data[off]);
|
||||
c.p = p;
|
||||
c.inf = ASN1_get_object(&(c.p), &(c.slen), &(c.tag), &(c.xclass),
|
||||
len - off);
|
||||
if (c.inf & 0x80) {
|
||||
uint32_t e;
|
||||
|
||||
e = ERR_GET_REASON(ERR_peek_error());
|
||||
if (e != ASN1_R_TOO_LONG)
|
||||
goto err;
|
||||
else
|
||||
ERR_clear_error(); /* clear error */
|
||||
}
|
||||
i = c.p - p; /* header length */
|
||||
off += i; /* end of data */
|
||||
|
||||
if (c.inf & 1) {
|
||||
/* no data body so go round again */
|
||||
eos++;
|
||||
if (eos < 0) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_HEADER_TOO_LONG);
|
||||
goto err;
|
||||
}
|
||||
want = HEADER_SIZE;
|
||||
} else if (eos && (c.slen == 0) && (c.tag == V_ASN1_EOC)) {
|
||||
/* eos value, so go back and read another header */
|
||||
eos--;
|
||||
if (eos <= 0)
|
||||
break;
|
||||
else
|
||||
want = HEADER_SIZE;
|
||||
} else {
|
||||
/* suck in c.slen bytes of data */
|
||||
want = c.slen;
|
||||
if (want > (len - off)) {
|
||||
want -= (len - off);
|
||||
if (want > INT_MAX /* BIO_read takes an int length */ ||
|
||||
len + want < len) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG);
|
||||
goto err;
|
||||
}
|
||||
if (!BUF_MEM_grow_clean(b, len + want)) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
while (want > 0) {
|
||||
i = BIO_read(in, &(b->data[len]), want);
|
||||
if (i <= 0) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ENOUGH_DATA);
|
||||
goto err;
|
||||
}
|
||||
/*
|
||||
* This can't overflow because |len+want| didn't
|
||||
* overflow.
|
||||
*/
|
||||
len += i;
|
||||
want -= i;
|
||||
}
|
||||
}
|
||||
if (off + c.slen < off) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG);
|
||||
goto err;
|
||||
}
|
||||
off += c.slen;
|
||||
if (eos <= 0) {
|
||||
break;
|
||||
} else
|
||||
want = HEADER_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
if (off > INT_MAX) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG);
|
||||
goto err;
|
||||
}
|
||||
|
||||
*pb = b;
|
||||
return off;
|
||||
err:
|
||||
if (b != NULL)
|
||||
BUF_MEM_free(b);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -59,6 +59,30 @@
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
void *ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, void *x)
|
||||
{
|
||||
unsigned char *b, *p;
|
||||
const unsigned char *p2;
|
||||
int i;
|
||||
char *ret;
|
||||
|
||||
if (x == NULL)
|
||||
return (NULL);
|
||||
|
||||
i = i2d(x, NULL);
|
||||
b = OPENSSL_malloc(i + 10);
|
||||
if (b == NULL) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
return (NULL);
|
||||
}
|
||||
p = b;
|
||||
i = i2d(x, &p);
|
||||
p2 = b;
|
||||
ret = d2i(NULL, &p2, i);
|
||||
OPENSSL_free(b);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* ASN1_ITEM version of dup: this follows the model above except we don't
|
||||
* need to allocate the buffer. At some point this could be rewritten to
|
||||
|
||||
+13
-27
@@ -56,15 +56,11 @@
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
/*
|
||||
* Code for ENUMERATED type: identical to INTEGER apart from a different tag.
|
||||
* for comments on encoding see a_int.c
|
||||
@@ -83,7 +79,7 @@ int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v)
|
||||
OPENSSL_free(a->data);
|
||||
if ((a->data =
|
||||
(unsigned char *)OPENSSL_malloc(sizeof(long) + 1)) != NULL)
|
||||
OPENSSL_memset((char *)a->data, 0, sizeof(long) + 1);
|
||||
memset((char *)a->data, 0, sizeof(long) + 1);
|
||||
}
|
||||
if (a->data == NULL) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
@@ -108,9 +104,10 @@ int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v)
|
||||
return (1);
|
||||
}
|
||||
|
||||
long ASN1_ENUMERATED_get(const ASN1_ENUMERATED *a)
|
||||
long ASN1_ENUMERATED_get(ASN1_ENUMERATED *a)
|
||||
{
|
||||
int neg = 0, i;
|
||||
long r = 0;
|
||||
|
||||
if (a == NULL)
|
||||
return (0L);
|
||||
@@ -120,34 +117,23 @@ long ASN1_ENUMERATED_get(const ASN1_ENUMERATED *a)
|
||||
else if (i != V_ASN1_ENUMERATED)
|
||||
return -1;
|
||||
|
||||
OPENSSL_STATIC_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(const BIGNUM *bn, ASN1_ENUMERATED *ai)
|
||||
ASN1_ENUMERATED *BN_to_ASN1_ENUMERATED(BIGNUM *bn, ASN1_ENUMERATED *ai)
|
||||
{
|
||||
ASN1_ENUMERATED *ret;
|
||||
int len, j;
|
||||
@@ -183,7 +169,7 @@ ASN1_ENUMERATED *BN_to_ASN1_ENUMERATED(const BIGNUM *bn, ASN1_ENUMERATED *ai)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
BIGNUM *ASN1_ENUMERATED_to_BN(const ASN1_ENUMERATED *ai, BIGNUM *bn)
|
||||
BIGNUM *ASN1_ENUMERATED_to_BN(ASN1_ENUMERATED *ai, BIGNUM *bn)
|
||||
{
|
||||
BIGNUM *ret;
|
||||
|
||||
|
||||
+16
-21
@@ -61,6 +61,7 @@
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/time_support.h>
|
||||
|
||||
#include "asn1_locl.h"
|
||||
|
||||
@@ -148,7 +149,7 @@ int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d)
|
||||
if (a[o] == 'Z')
|
||||
o++;
|
||||
else if ((a[o] == '+') || (a[o] == '-')) {
|
||||
int offsign = a[o] == '-' ? 1 : -1, offset = 0;
|
||||
int offsign = a[o] == '-' ? -1 : 1, offset = 0;
|
||||
o++;
|
||||
if (o + 4 > l)
|
||||
goto err;
|
||||
@@ -219,43 +220,37 @@ ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s,
|
||||
struct tm *ts;
|
||||
struct tm data;
|
||||
size_t len = 20;
|
||||
ASN1_GENERALIZEDTIME *tmps = NULL;
|
||||
|
||||
if (s == NULL)
|
||||
tmps = ASN1_GENERALIZEDTIME_new();
|
||||
else
|
||||
tmps = s;
|
||||
if (tmps == NULL)
|
||||
return NULL;
|
||||
s = M_ASN1_GENERALIZEDTIME_new();
|
||||
if (s == NULL)
|
||||
return (NULL);
|
||||
|
||||
ts = OPENSSL_gmtime(&t, &data);
|
||||
if (ts == NULL)
|
||||
goto err;
|
||||
return (NULL);
|
||||
|
||||
if (offset_day || offset_sec) {
|
||||
if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec))
|
||||
goto err;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = (char *)tmps->data;
|
||||
if ((p == NULL) || ((size_t)tmps->length < len)) {
|
||||
p = (char *)s->data;
|
||||
if ((p == NULL) || ((size_t)s->length < len)) {
|
||||
p = OPENSSL_malloc(len);
|
||||
if (p == NULL) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
return (NULL);
|
||||
}
|
||||
OPENSSL_free(tmps->data);
|
||||
tmps->data = (unsigned char *)p;
|
||||
if (s->data != NULL)
|
||||
OPENSSL_free(s->data);
|
||||
s->data = (unsigned char *)p;
|
||||
}
|
||||
|
||||
BIO_snprintf(p, len, "%04d%02d%02d%02d%02d%02dZ", ts->tm_year + 1900,
|
||||
ts->tm_mon + 1, ts->tm_mday, ts->tm_hour, ts->tm_min,
|
||||
ts->tm_sec);
|
||||
tmps->length = strlen(p);
|
||||
tmps->type = V_ASN1_GENERALIZEDTIME;
|
||||
return tmps;
|
||||
err:
|
||||
if (s == NULL)
|
||||
ASN1_GENERALIZEDTIME_free(tmps);
|
||||
return NULL;
|
||||
s->length = strlen(p);
|
||||
s->type = V_ASN1_GENERALIZEDTIME;
|
||||
return (s);
|
||||
}
|
||||
|
||||
+69
-10
@@ -56,33 +56,92 @@
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
int ASN1_i2d_fp(i2d_of_void *i2d, FILE *out, void *x)
|
||||
{
|
||||
BIO *b;
|
||||
int ret;
|
||||
|
||||
if ((b = BIO_new(BIO_s_file())) == NULL) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_BUF_LIB);
|
||||
return (0);
|
||||
}
|
||||
BIO_set_fp(b, out, BIO_NOCLOSE);
|
||||
ret = ASN1_i2d_bio(i2d, b, x);
|
||||
BIO_free(b);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int ASN1_i2d_bio(i2d_of_void *i2d, BIO *out, void *x)
|
||||
{
|
||||
char *b;
|
||||
unsigned char *p;
|
||||
int i, j = 0, n, ret = 1;
|
||||
|
||||
n = i2d(x, NULL);
|
||||
b = (char *)OPENSSL_malloc(n);
|
||||
if (b == NULL) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
return (0);
|
||||
}
|
||||
|
||||
p = (unsigned char *)b;
|
||||
i2d(x, &p);
|
||||
|
||||
for (;;) {
|
||||
i = BIO_write(out, &(b[j]), n);
|
||||
if (i == n)
|
||||
break;
|
||||
if (i <= 0) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
j += i;
|
||||
n -= i;
|
||||
}
|
||||
OPENSSL_free(b);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int ASN1_item_i2d_fp(const ASN1_ITEM *it, FILE *out, void *x)
|
||||
{
|
||||
BIO *b = BIO_new_fp(out, BIO_NOCLOSE);
|
||||
if (b == NULL) {
|
||||
BIO *b;
|
||||
int ret;
|
||||
|
||||
if ((b = BIO_new(BIO_s_file())) == NULL) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_BUF_LIB);
|
||||
return 0;
|
||||
return (0);
|
||||
}
|
||||
int ret = ASN1_item_i2d_bio(it, b, x);
|
||||
BIO_set_fp(b, out, BIO_NOCLOSE);
|
||||
ret = ASN1_item_i2d_bio(it, b, x);
|
||||
BIO_free(b);
|
||||
return ret;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int ASN1_item_i2d_bio(const ASN1_ITEM *it, BIO *out, void *x)
|
||||
{
|
||||
unsigned char *b = NULL;
|
||||
int n = ASN1_item_i2d(x, &b, it);
|
||||
int i, j = 0, n, ret = 1;
|
||||
|
||||
n = ASN1_item_i2d(x, &b, it);
|
||||
if (b == NULL) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int ret = BIO_write_all(out, b, n);
|
||||
for (;;) {
|
||||
i = BIO_write(out, &(b[j]), n);
|
||||
if (i == n)
|
||||
break;
|
||||
if (i <= 0) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
j += i;
|
||||
n -= i;
|
||||
}
|
||||
OPENSSL_free(b);
|
||||
return ret;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
+103
-63
@@ -57,14 +57,10 @@
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
ASN1_INTEGER *ASN1_INTEGER_dup(const ASN1_INTEGER *x)
|
||||
{
|
||||
return M_ASN1_INTEGER_dup(x);
|
||||
@@ -115,7 +111,7 @@ int ASN1_INTEGER_cmp(const ASN1_INTEGER *x, const ASN1_INTEGER *y)
|
||||
* followed by optional zeros isn't padded.
|
||||
*/
|
||||
|
||||
int i2c_ASN1_INTEGER(const ASN1_INTEGER *a, unsigned char **pp)
|
||||
int i2c_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **pp)
|
||||
{
|
||||
int pad = 0, ret, i, neg;
|
||||
unsigned char *p, *n, pb = 0;
|
||||
@@ -161,7 +157,7 @@ int i2c_ASN1_INTEGER(const ASN1_INTEGER *a, unsigned char **pp)
|
||||
if (a->length == 0)
|
||||
*(p++) = 0;
|
||||
else if (!neg)
|
||||
OPENSSL_memcpy(p, a->data, (unsigned int)a->length);
|
||||
memcpy(p, a->data, (unsigned int)a->length);
|
||||
else {
|
||||
/* Begin at the end of the encoding */
|
||||
n = a->data + a->length - 1;
|
||||
@@ -195,16 +191,6 @@ ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a, const unsigned char **pp,
|
||||
unsigned char *to, *s;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* This function can handle lengths up to INT_MAX - 1, but the rest of the
|
||||
* legacy ASN.1 code mixes integer types, so avoid exposing it to
|
||||
* ASN1_INTEGERS with larger lengths.
|
||||
*/
|
||||
if (len < 0 || len > INT_MAX / 2) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((a == NULL) || ((*a) == NULL)) {
|
||||
if ((ret = M_ASN1_INTEGER_new()) == NULL)
|
||||
return (NULL);
|
||||
@@ -268,7 +254,7 @@ ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a, const unsigned char **pp,
|
||||
p++;
|
||||
len--;
|
||||
}
|
||||
OPENSSL_memcpy(s, p, (int)len);
|
||||
memcpy(s, p, (int)len);
|
||||
}
|
||||
|
||||
if (ret->data != NULL)
|
||||
@@ -286,52 +272,117 @@ ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a, const unsigned char **pp,
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
int ASN1_INTEGER_set(ASN1_INTEGER *a, long v)
|
||||
/*
|
||||
* This is a version of d2i_ASN1_INTEGER that ignores the sign bit of ASN1
|
||||
* integers: some broken software can encode a positive INTEGER with its MSB
|
||||
* set as negative (it doesn't add a padding zero).
|
||||
*/
|
||||
|
||||
ASN1_INTEGER *d2i_ASN1_UINTEGER(ASN1_INTEGER **a, const unsigned char **pp,
|
||||
long length)
|
||||
{
|
||||
if (v >= 0) {
|
||||
return ASN1_INTEGER_set_uint64(a, (uint64_t) v);
|
||||
ASN1_INTEGER *ret = NULL;
|
||||
const unsigned char *p;
|
||||
unsigned char *s;
|
||||
long len;
|
||||
int inf, tag, xclass;
|
||||
int i;
|
||||
|
||||
if ((a == NULL) || ((*a) == NULL)) {
|
||||
if ((ret = M_ASN1_INTEGER_new()) == NULL)
|
||||
return (NULL);
|
||||
ret->type = V_ASN1_INTEGER;
|
||||
} else
|
||||
ret = (*a);
|
||||
|
||||
p = *pp;
|
||||
inf = ASN1_get_object(&p, &len, &tag, &xclass, length);
|
||||
if (inf & 0x80) {
|
||||
i = ASN1_R_BAD_OBJECT_HEADER;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!ASN1_INTEGER_set_uint64(a, 0 - (uint64_t) v)) {
|
||||
return 0;
|
||||
if (tag != V_ASN1_INTEGER) {
|
||||
i = ASN1_R_EXPECTING_AN_INTEGER;
|
||||
goto err;
|
||||
}
|
||||
|
||||
a->type = V_ASN1_NEG_INTEGER;
|
||||
return 1;
|
||||
/*
|
||||
* We must OPENSSL_malloc stuff, even for 0 bytes otherwise it signifies
|
||||
* a missing NULL parameter.
|
||||
*/
|
||||
s = (unsigned char *)OPENSSL_malloc((int)len + 1);
|
||||
if (s == NULL) {
|
||||
i = ERR_R_MALLOC_FAILURE;
|
||||
goto err;
|
||||
}
|
||||
ret->type = V_ASN1_INTEGER;
|
||||
if (len) {
|
||||
if ((*p == 0) && (len != 1)) {
|
||||
p++;
|
||||
len--;
|
||||
}
|
||||
memcpy(s, p, (int)len);
|
||||
p += len;
|
||||
}
|
||||
|
||||
if (ret->data != NULL)
|
||||
OPENSSL_free(ret->data);
|
||||
ret->data = s;
|
||||
ret->length = (int)len;
|
||||
if (a != NULL)
|
||||
(*a) = ret;
|
||||
*pp = p;
|
||||
return (ret);
|
||||
err:
|
||||
OPENSSL_PUT_ERROR(ASN1, i);
|
||||
if ((ret != NULL) && ((a == NULL) || (*a != ret)))
|
||||
M_ASN1_INTEGER_free(ret);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
int ASN1_INTEGER_set_uint64(ASN1_INTEGER *out, uint64_t v)
|
||||
int ASN1_INTEGER_set(ASN1_INTEGER *a, long v)
|
||||
{
|
||||
uint8_t *const newdata = OPENSSL_malloc(sizeof(uint64_t));
|
||||
if (newdata == NULL) {
|
||||
int j, k;
|
||||
unsigned int i;
|
||||
unsigned char buf[sizeof(long) + 1];
|
||||
long d;
|
||||
|
||||
a->type = V_ASN1_INTEGER;
|
||||
if (a->length < (int)(sizeof(long) + 1)) {
|
||||
if (a->data != NULL)
|
||||
OPENSSL_free(a->data);
|
||||
if ((a->data =
|
||||
(unsigned char *)OPENSSL_malloc(sizeof(long) + 1)) != NULL)
|
||||
memset((char *)a->data, 0, sizeof(long) + 1);
|
||||
}
|
||||
if (a->data == NULL) {
|
||||
OPENSSL_PUT_ERROR(ASN1, 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);
|
||||
@@ -341,31 +392,20 @@ long ASN1_INTEGER_get(const ASN1_INTEGER *a)
|
||||
else if (i != V_ASN1_INTEGER)
|
||||
return -1;
|
||||
|
||||
OPENSSL_STATIC_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)
|
||||
|
||||
+135
-25
@@ -63,47 +63,157 @@
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/obj.h>
|
||||
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
int i2d_ASN1_OBJECT(const ASN1_OBJECT *a, unsigned char **pp)
|
||||
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))
|
||||
return (0);
|
||||
|
||||
objsize = ASN1_object_size(0, a->length, V_ASN1_OBJECT);
|
||||
if (pp == NULL || objsize == -1)
|
||||
if (pp == NULL)
|
||||
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);
|
||||
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 i2t_ASN1_OBJECT(char *buf, int buf_len, const ASN1_OBJECT *a)
|
||||
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--)
|
||||
tmp[i++] = (unsigned char)BN_div_word(bl, 0x80L);
|
||||
} else {
|
||||
|
||||
for (;;) {
|
||||
tmp[i++] = (unsigned char)l & 0x7f;
|
||||
l >>= 7L;
|
||||
if (l == 0L)
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if (out != NULL) {
|
||||
if (len + i > olen) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_BUFFER_TOO_SMALL);
|
||||
goto err;
|
||||
}
|
||||
while (--i > 0)
|
||||
out[len++] = tmp[i] | 0x80;
|
||||
out[len++] = tmp[0];
|
||||
} else
|
||||
len += i;
|
||||
}
|
||||
if (tmp != ftmp)
|
||||
OPENSSL_free(tmp);
|
||||
if (bl)
|
||||
BN_free(bl);
|
||||
return (len);
|
||||
err:
|
||||
if (tmp != ftmp)
|
||||
OPENSSL_free(tmp);
|
||||
if (bl)
|
||||
BN_free(bl);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int i2t_ASN1_OBJECT(char *buf, int buf_len, ASN1_OBJECT *a)
|
||||
{
|
||||
return OBJ_obj2txt(buf, buf_len, a, 0);
|
||||
}
|
||||
|
||||
int i2a_ASN1_OBJECT(BIO *bp, const ASN1_OBJECT *a)
|
||||
int i2a_ASN1_OBJECT(BIO *bp, ASN1_OBJECT *a)
|
||||
{
|
||||
char buf[80], *p = buf;
|
||||
int i;
|
||||
@@ -207,7 +317,7 @@ ASN1_OBJECT *c2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp,
|
||||
}
|
||||
ret->flags |= ASN1_OBJECT_FLAG_DYNAMIC_DATA;
|
||||
}
|
||||
OPENSSL_memcpy(data, p, length);
|
||||
memcpy(data, p, length);
|
||||
/* reattach data to object, after which it remains const */
|
||||
ret->data = data;
|
||||
ret->length = length;
|
||||
|
||||
@@ -91,3 +91,31 @@ int ASN1_PRINTABLE_type(const unsigned char *s, int len)
|
||||
return (V_ASN1_IA5STRING);
|
||||
return (V_ASN1_PRINTABLESTRING);
|
||||
}
|
||||
|
||||
int ASN1_UNIVERSALSTRING_to_string(ASN1_UNIVERSALSTRING *s)
|
||||
{
|
||||
int i;
|
||||
unsigned char *p;
|
||||
|
||||
if (s->type != V_ASN1_UNIVERSALSTRING)
|
||||
return (0);
|
||||
if ((s->length % 4) != 0)
|
||||
return (0);
|
||||
p = s->data;
|
||||
for (i = 0; i < s->length; i += 4) {
|
||||
if ((p[0] != '\0') || (p[1] != '\0') || (p[2] != '\0'))
|
||||
break;
|
||||
else
|
||||
p += 4;
|
||||
}
|
||||
if (i < s->length)
|
||||
return (0);
|
||||
p = s->data;
|
||||
for (i = 3; i < s->length; i += 4) {
|
||||
*(p++) = s->data[i];
|
||||
}
|
||||
*(p) = '\0';
|
||||
s->length /= 4;
|
||||
s->type = ASN1_PRINTABLE_type(s->data, s->length);
|
||||
return (1);
|
||||
}
|
||||
|
||||
@@ -62,9 +62,6 @@
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/obj.h>
|
||||
#include <openssl/stack.h>
|
||||
|
||||
DEFINE_STACK_OF(ASN1_STRING_TABLE)
|
||||
|
||||
static STACK_OF(ASN1_STRING_TABLE) *stable = NULL;
|
||||
static void st_free(ASN1_STRING_TABLE *tbl);
|
||||
@@ -223,7 +220,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;
|
||||
@@ -251,7 +247,6 @@ int ASN1_STRING_TABLE_add(int nid,
|
||||
}
|
||||
tmp->flags = flags | STABLE_FLAGS_MALLOC;
|
||||
tmp->nid = nid;
|
||||
tmp->minsize = tmp->maxsize = -1;
|
||||
new_nid = 1;
|
||||
} else
|
||||
tmp->flags = (tmp->flags & STABLE_FLAGS_MALLOC) | flags;
|
||||
|
||||
+27
-22
@@ -60,8 +60,10 @@
|
||||
#include <time.h>
|
||||
|
||||
#include <openssl/asn1t.h>
|
||||
#include <openssl/buf.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/time_support.h>
|
||||
|
||||
#include "asn1_locl.h"
|
||||
|
||||
@@ -75,6 +77,17 @@ IMPLEMENT_ASN1_MSTRING(ASN1_TIME, B_ASN1_TIME)
|
||||
|
||||
IMPLEMENT_ASN1_FUNCTIONS(ASN1_TIME)
|
||||
|
||||
#if 0
|
||||
int i2d_ASN1_TIME(ASN1_TIME *a, unsigned char **pp)
|
||||
{
|
||||
if (a->type == V_ASN1_UTCTIME || a->type == V_ASN1_GENERALIZEDTIME)
|
||||
return (i2d_ASN1_bytes((ASN1_STRING *)a, pp,
|
||||
a->type, V_ASN1_UNIVERSAL));
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_EXPECTING_A_TIME);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s, time_t t)
|
||||
{
|
||||
return ASN1_TIME_adj(s, t, 0, 0);
|
||||
@@ -100,7 +113,7 @@ ASN1_TIME *ASN1_TIME_adj(ASN1_TIME *s, time_t t,
|
||||
return ASN1_GENERALIZEDTIME_adj(s, t, offset_day, offset_sec);
|
||||
}
|
||||
|
||||
int ASN1_TIME_check(const ASN1_TIME *t)
|
||||
int ASN1_TIME_check(ASN1_TIME *t)
|
||||
{
|
||||
if (t->type == V_ASN1_GENERALIZEDTIME)
|
||||
return ASN1_GENERALIZEDTIME_check(t);
|
||||
@@ -110,10 +123,10 @@ int ASN1_TIME_check(const ASN1_TIME *t)
|
||||
}
|
||||
|
||||
/* Convert an ASN1_TIME structure to GeneralizedTime */
|
||||
ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(const ASN1_TIME *t,
|
||||
ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *t,
|
||||
ASN1_GENERALIZEDTIME **out)
|
||||
{
|
||||
ASN1_GENERALIZEDTIME *ret = NULL;
|
||||
ASN1_GENERALIZEDTIME *ret;
|
||||
char *str;
|
||||
int newlen;
|
||||
|
||||
@@ -122,44 +135,36 @@ ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(const ASN1_TIME *t,
|
||||
|
||||
if (!out || !*out) {
|
||||
if (!(ret = ASN1_GENERALIZEDTIME_new()))
|
||||
goto err;
|
||||
} else {
|
||||
return NULL;
|
||||
if (out)
|
||||
*out = ret;
|
||||
} else
|
||||
ret = *out;
|
||||
}
|
||||
|
||||
/* If already GeneralizedTime just copy across */
|
||||
if (t->type == V_ASN1_GENERALIZEDTIME) {
|
||||
if (!ASN1_STRING_set(ret, t->data, t->length))
|
||||
goto err;
|
||||
goto done;
|
||||
return NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* grow the string */
|
||||
if (!ASN1_STRING_set(ret, NULL, t->length + 2))
|
||||
goto err;
|
||||
return NULL;
|
||||
/* ASN1_STRING_set() allocated 'len + 1' bytes. */
|
||||
newlen = t->length + 2 + 1;
|
||||
str = (char *)ret->data;
|
||||
/* Work out the century and prepend */
|
||||
if (t->data[0] >= '5')
|
||||
OPENSSL_strlcpy(str, "19", newlen);
|
||||
BUF_strlcpy(str, "19", newlen);
|
||||
else
|
||||
OPENSSL_strlcpy(str, "20", newlen);
|
||||
BUF_strlcpy(str, "20", newlen);
|
||||
|
||||
OPENSSL_strlcat(str, (char *)t->data, newlen);
|
||||
BUF_strlcat(str, (char *)t->data, newlen);
|
||||
|
||||
done:
|
||||
if (out != NULL && *out == NULL)
|
||||
*out = ret;
|
||||
return ret;
|
||||
|
||||
err:
|
||||
if (out == NULL || *out != ret)
|
||||
ASN1_GENERALIZEDTIME_free(ret);
|
||||
return NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int ASN1_TIME_set_string(ASN1_TIME *s, const char *str)
|
||||
{
|
||||
ASN1_TIME t;
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/obj.h>
|
||||
|
||||
int ASN1_TYPE_get(const ASN1_TYPE *a)
|
||||
int ASN1_TYPE_get(ASN1_TYPE *a)
|
||||
{
|
||||
if ((a->value.ptr != NULL) || (a->type == V_ASN1_NULL))
|
||||
return (a->type);
|
||||
@@ -122,7 +122,9 @@ int ASN1_TYPE_cmp(const ASN1_TYPE *a, const ASN1_TYPE *b)
|
||||
result = a->value.boolean - b->value.boolean;
|
||||
break;
|
||||
case V_ASN1_INTEGER:
|
||||
case V_ASN1_NEG_INTEGER:
|
||||
case V_ASN1_ENUMERATED:
|
||||
case V_ASN1_NEG_ENUMERATED:
|
||||
case V_ASN1_BIT_STRING:
|
||||
case V_ASN1_OCTET_STRING:
|
||||
case V_ASN1_SEQUENCE:
|
||||
|
||||
+34
-2
@@ -61,9 +61,41 @@
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/time_support.h>
|
||||
|
||||
#include "asn1_locl.h"
|
||||
|
||||
#if 0
|
||||
int i2d_ASN1_UTCTIME(ASN1_UTCTIME *a, unsigned char **pp)
|
||||
{
|
||||
return (i2d_ASN1_bytes((ASN1_STRING *)a, pp,
|
||||
V_ASN1_UTCTIME, V_ASN1_UNIVERSAL));
|
||||
}
|
||||
|
||||
ASN1_UTCTIME *d2i_ASN1_UTCTIME(ASN1_UTCTIME **a, unsigned char **pp,
|
||||
long length)
|
||||
{
|
||||
ASN1_UTCTIME *ret = NULL;
|
||||
|
||||
ret = (ASN1_UTCTIME *)d2i_ASN1_bytes((ASN1_STRING **)a, pp, length,
|
||||
V_ASN1_UTCTIME, V_ASN1_UNIVERSAL);
|
||||
if (ret == NULL) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_NESTED_ASN1_ERROR);
|
||||
return (NULL);
|
||||
}
|
||||
if (!ASN1_UTCTIME_check(ret)) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_TIME_FORMAT);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
err:
|
||||
if ((ret != NULL) && ((a == NULL) || (*a != ret)))
|
||||
M_ASN1_UTCTIME_free(ret);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d)
|
||||
{
|
||||
@@ -127,7 +159,7 @@ int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d)
|
||||
if (a[o] == 'Z')
|
||||
o++;
|
||||
else if ((a[o] == '+') || (a[o] == '-')) {
|
||||
int offsign = a[o] == '-' ? 1 : -1, offset = 0;
|
||||
int offsign = a[o] == '-' ? -1 : 1, offset = 0;
|
||||
o++;
|
||||
if (o + 4 > l)
|
||||
goto err;
|
||||
@@ -269,7 +301,7 @@ time_t ASN1_UTCTIME_get(const ASN1_UTCTIME *s)
|
||||
struct tm tm;
|
||||
int offset;
|
||||
|
||||
OPENSSL_memset(&tm, '\0', sizeof tm);
|
||||
memset(&tm, '\0', sizeof tm);
|
||||
|
||||
# define g2(p) (((p)[0]-'0')*10+(p)[1]-'0')
|
||||
tm.tm_year = g2(s->data);
|
||||
|
||||
+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 */
|
||||
|
||||
+132
-69
@@ -63,50 +63,71 @@
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
/* Cross-module errors from crypto/x509/i2d_pr.c. */
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNSUPPORTED_PUBLIC_KEY_TYPE)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNSUPPORTED_PUBLIC_KEY_TYPE);
|
||||
|
||||
/* Cross-module errors from crypto/x509/algorithm.c. */
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, CONTEXT_NOT_INITIALISED)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, DIGEST_AND_KEY_TYPE_NOT_SUPPORTED)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_MESSAGE_DIGEST_ALGORITHM)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_SIGNATURE_ALGORITHM)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, WRONG_PUBLIC_KEY_TYPE)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, CONTEXT_NOT_INITIALISED);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, DIGEST_AND_KEY_TYPE_NOT_SUPPORTED);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_MESSAGE_DIGEST_ALGORITHM);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_SIGNATURE_ALGORITHM);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, WRONG_PUBLIC_KEY_TYPE);
|
||||
/*
|
||||
* Cross-module errors from crypto/x509/asn1_gen.c. TODO(davidben): Remove
|
||||
* these once asn1_gen.c is gone.
|
||||
*/
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, DEPTH_EXCEEDED)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_BITSTRING_FORMAT)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_BOOLEAN)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_FORMAT)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_HEX)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_IMPLICIT_TAG)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_INTEGER)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_NESTED_TAGGING)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_NULL_VALUE)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_OBJECT)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_TIME_VALUE)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, INTEGER_NOT_ASCII_FORMAT)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_MODIFIER)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_NUMBER)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, LIST_ERROR)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, MISSING_VALUE)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, NOT_ASCII_FORMAT)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, OBJECT_NOT_ASCII_FORMAT)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, SEQUENCE_OR_SET_NEEDS_CONFIG)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, TIME_NOT_ASCII_FORMAT)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_FORMAT)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_TAG)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNSUPPORTED_TYPE)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, DEPTH_EXCEEDED);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_BITSTRING_FORMAT);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_BOOLEAN);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_FORMAT);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_HEX);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_IMPLICIT_TAG);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_INTEGER);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_NESTED_TAGGING);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_NULL_VALUE);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_OBJECT);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_TIME_VALUE);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, INTEGER_NOT_ASCII_FORMAT);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_MODIFIER);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_NUMBER);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, LIST_ERROR);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, MISSING_VALUE);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, NOT_ASCII_FORMAT);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, OBJECT_NOT_ASCII_FORMAT);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, SEQUENCE_OR_SET_NEEDS_CONFIG);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, TIME_NOT_ASCII_FORMAT);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_FORMAT);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_TAG);
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, UNSUPPORTED_TYPE);
|
||||
|
||||
static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
|
||||
long max);
|
||||
int max);
|
||||
static void asn1_put_length(unsigned char **pp, int length);
|
||||
|
||||
static int _asn1_check_infinite_end(const unsigned char **p, long len)
|
||||
{
|
||||
/*
|
||||
* If there is 0 or 1 byte left, the length check should pick things up
|
||||
*/
|
||||
if (len <= 0)
|
||||
return (1);
|
||||
else if ((len >= 2) && ((*p)[0] == 0) && ((*p)[1] == 0)) {
|
||||
(*p) += 2;
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int ASN1_check_infinite_end(unsigned char **p, long len)
|
||||
{
|
||||
return _asn1_check_infinite_end((const unsigned char **)p, len);
|
||||
}
|
||||
|
||||
int ASN1_const_check_infinite_end(const unsigned char **p, long len)
|
||||
{
|
||||
return _asn1_check_infinite_end(p, len);
|
||||
}
|
||||
|
||||
int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag,
|
||||
int *pclass, long omax)
|
||||
{
|
||||
@@ -152,7 +173,7 @@ int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag,
|
||||
|
||||
*ptag = tag;
|
||||
*pclass = xclass;
|
||||
if (!asn1_get_length(&p, &inf, plength, max))
|
||||
if (!asn1_get_length(&p, &inf, plength, (int)max))
|
||||
goto err;
|
||||
|
||||
if (inf && !(ret & V_ASN1_CONSTRUCTED))
|
||||
@@ -180,14 +201,14 @@ int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag,
|
||||
}
|
||||
|
||||
static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
|
||||
long max)
|
||||
int max)
|
||||
{
|
||||
const unsigned char *p = *pp;
|
||||
unsigned long ret = 0;
|
||||
unsigned long i;
|
||||
unsigned int i;
|
||||
|
||||
if (max-- < 1)
|
||||
return 0;
|
||||
return (0);
|
||||
if (*p == 0x80) {
|
||||
*inf = 1;
|
||||
ret = 0;
|
||||
@@ -196,24 +217,24 @@ static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
|
||||
*inf = 0;
|
||||
i = *p & 0x7f;
|
||||
if (*(p++) & 0x80) {
|
||||
if (i > sizeof(ret) || max < (long)i)
|
||||
if (i > sizeof(long))
|
||||
return 0;
|
||||
if (max-- == 0)
|
||||
return (0);
|
||||
while (i-- > 0) {
|
||||
ret <<= 8L;
|
||||
ret |= *(p++);
|
||||
if (max-- == 0)
|
||||
return (0);
|
||||
}
|
||||
} else
|
||||
ret = i;
|
||||
}
|
||||
/*
|
||||
* Bound the length to comfortably fit in an int. Lengths in this module
|
||||
* often switch between int and long without overflow checks.
|
||||
*/
|
||||
if (ret > INT_MAX / 2)
|
||||
if (ret > LONG_MAX)
|
||||
return 0;
|
||||
*pp = p;
|
||||
*rl = (long)ret;
|
||||
return 1;
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -281,30 +302,77 @@ static void asn1_put_length(unsigned char **pp, int length)
|
||||
|
||||
int ASN1_object_size(int constructed, int length, int tag)
|
||||
{
|
||||
int ret = 1;
|
||||
if (length < 0)
|
||||
return -1;
|
||||
int ret;
|
||||
|
||||
ret = length;
|
||||
ret++;
|
||||
if (tag >= 31) {
|
||||
while (tag > 0) {
|
||||
tag >>= 7;
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
if (constructed == 2) {
|
||||
ret += 3;
|
||||
} else {
|
||||
ret++;
|
||||
if (length > 127) {
|
||||
int tmplen = length;
|
||||
while (tmplen > 0) {
|
||||
tmplen >>= 8;
|
||||
ret++;
|
||||
}
|
||||
if (constructed == 2)
|
||||
return ret + 3;
|
||||
ret++;
|
||||
if (length > 127) {
|
||||
while (length > 0) {
|
||||
length >>= 8;
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
if (ret >= INT_MAX - length)
|
||||
return -1;
|
||||
return ret + length;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int _asn1_Finish(ASN1_const_CTX *c)
|
||||
{
|
||||
if ((c->inf == (1 | V_ASN1_CONSTRUCTED)) && (!c->eos)) {
|
||||
if (!ASN1_const_check_infinite_end(&c->p, c->slen)) {
|
||||
c->error = ASN1_R_MISSING_ASN1_EOS;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
if (((c->slen != 0) && !(c->inf & 1)) || ((c->slen < 0) && (c->inf & 1))) {
|
||||
c->error = ASN1_R_ASN1_LENGTH_MISMATCH;
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
int asn1_Finish(ASN1_CTX *c)
|
||||
{
|
||||
return _asn1_Finish((ASN1_const_CTX *)c);
|
||||
}
|
||||
|
||||
int asn1_const_Finish(ASN1_const_CTX *c)
|
||||
{
|
||||
return _asn1_Finish(c);
|
||||
}
|
||||
|
||||
int asn1_GetSequence(ASN1_const_CTX *c, long *length)
|
||||
{
|
||||
const unsigned char *q;
|
||||
|
||||
q = c->p;
|
||||
c->inf = ASN1_get_object(&(c->p), &(c->slen), &(c->tag), &(c->xclass),
|
||||
*length);
|
||||
if (c->inf & 0x80) {
|
||||
c->error = ASN1_R_BAD_GET_ASN1_OBJECT_CALL;
|
||||
return (0);
|
||||
}
|
||||
if (c->tag != V_ASN1_SEQUENCE) {
|
||||
c->error = ASN1_R_EXPECTING_AN_ASN1_SEQUENCE;
|
||||
return (0);
|
||||
}
|
||||
(*length) -= (c->p - q);
|
||||
if (c->max && (*length < 0)) {
|
||||
c->error = ASN1_R_ASN1_LENGTH_MISMATCH;
|
||||
return (0);
|
||||
}
|
||||
if (c->inf == (1 | V_ASN1_CONSTRUCTED))
|
||||
c->slen = *length + *(c->pp) - c->p;
|
||||
c->eos = 0;
|
||||
return (1);
|
||||
}
|
||||
|
||||
int ASN1_STRING_copy(ASN1_STRING *dst, const ASN1_STRING *str)
|
||||
@@ -344,7 +412,7 @@ int ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len)
|
||||
else
|
||||
len = strlen(data);
|
||||
}
|
||||
if ((str->length <= len) || (str->data == NULL)) {
|
||||
if ((str->length < len) || (str->data == NULL)) {
|
||||
c = str->data;
|
||||
if (c == NULL)
|
||||
str->data = OPENSSL_malloc(len + 1);
|
||||
@@ -359,7 +427,7 @@ int ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len)
|
||||
}
|
||||
str->length = len;
|
||||
if (data != NULL) {
|
||||
OPENSSL_memcpy(str->data, data, len);
|
||||
memcpy(str->data, data, len);
|
||||
/* an allowance for strings :-) */
|
||||
str->data[len] = '\0';
|
||||
}
|
||||
@@ -410,7 +478,7 @@ int ASN1_STRING_cmp(const ASN1_STRING *a, const ASN1_STRING *b)
|
||||
|
||||
i = (a->length - b->length);
|
||||
if (i == 0) {
|
||||
i = OPENSSL_memcmp(a->data, b->data, a->length);
|
||||
i = memcmp(a->data, b->data, a->length);
|
||||
if (i == 0)
|
||||
return (a->type - b->type);
|
||||
else
|
||||
@@ -430,7 +498,7 @@ void ASN1_STRING_length_set(ASN1_STRING *x, int len)
|
||||
return;
|
||||
}
|
||||
|
||||
int ASN1_STRING_type(const ASN1_STRING *x)
|
||||
int ASN1_STRING_type(ASN1_STRING *x)
|
||||
{
|
||||
return M_ASN1_STRING_type(x);
|
||||
}
|
||||
@@ -439,8 +507,3 @@ unsigned char *ASN1_STRING_data(ASN1_STRING *x)
|
||||
{
|
||||
return M_ASN1_STRING_data(x);
|
||||
}
|
||||
|
||||
const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *x)
|
||||
{
|
||||
return x->data;
|
||||
}
|
||||
|
||||
+8
-39
@@ -57,48 +57,17 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef OPENSSL_HEADER_ASN1_ASN1_LOCL_H
|
||||
#define OPENSSL_HEADER_ASN1_ASN1_LOCL_H
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* Wrapper functions for time functions. */
|
||||
|
||||
/* OPENSSL_gmtime wraps |gmtime_r|. See the manual page for that function. */
|
||||
struct tm *OPENSSL_gmtime(const time_t *time, struct tm *result);
|
||||
|
||||
/* OPENSSL_gmtime_adj updates |tm| by adding |offset_day| days and |offset_sec|
|
||||
* seconds. */
|
||||
int OPENSSL_gmtime_adj(struct tm *tm, int offset_day, long offset_sec);
|
||||
|
||||
/* OPENSSL_gmtime_diff calculates the difference between |from| and |to| and
|
||||
* outputs the difference as a number of days and seconds in |*out_days| and
|
||||
* |*out_secs|. */
|
||||
int OPENSSL_gmtime_diff(int *out_days, int *out_secs, const struct tm *from,
|
||||
const struct tm *to);
|
||||
|
||||
|
||||
/* Internal ASN1 structures and functions: not for application use */
|
||||
|
||||
int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d);
|
||||
int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d);
|
||||
|
||||
void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it,
|
||||
int combine);
|
||||
/* ASN1 print context structure */
|
||||
|
||||
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 */
|
||||
#endif
|
||||
|
||||
#endif /* OPENSSL_HEADER_ASN1_ASN1_LOCL_H */
|
||||
struct asn1_pctx_st {
|
||||
unsigned long flags;
|
||||
unsigned long nm_flags;
|
||||
unsigned long cert_flags;
|
||||
unsigned long oid_flags;
|
||||
unsigned long str_flags;
|
||||
} /* ASN1_PCTX */ ;
|
||||
|
||||
@@ -56,6 +56,328 @@
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#define ASN1_PARSE_MAXDEPTH 128
|
||||
|
||||
static int asn1_print_info(BIO *bp, int tag, int xclass, int constructed,
|
||||
int indent);
|
||||
static int asn1_parse2(BIO *bp, const unsigned char **pp, long length,
|
||||
int offset, int depth, int indent, int dump);
|
||||
static int asn1_print_info(BIO *bp, int tag, int xclass, int constructed,
|
||||
int indent)
|
||||
{
|
||||
static const char fmt[] = "%-18s";
|
||||
char str[128];
|
||||
const char *p;
|
||||
|
||||
if (constructed & V_ASN1_CONSTRUCTED)
|
||||
p = "cons: ";
|
||||
else
|
||||
p = "prim: ";
|
||||
if (BIO_write(bp, p, 6) < 6)
|
||||
goto err;
|
||||
BIO_indent(bp, indent, 128);
|
||||
|
||||
p = str;
|
||||
if ((xclass & V_ASN1_PRIVATE) == V_ASN1_PRIVATE)
|
||||
BIO_snprintf(str, sizeof str, "priv [ %d ] ", tag);
|
||||
else if ((xclass & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC)
|
||||
BIO_snprintf(str, sizeof str, "cont [ %d ]", tag);
|
||||
else if ((xclass & V_ASN1_APPLICATION) == V_ASN1_APPLICATION)
|
||||
BIO_snprintf(str, sizeof str, "appl [ %d ]", tag);
|
||||
else if (tag > 30)
|
||||
BIO_snprintf(str, sizeof str, "<ASN1 %d>", tag);
|
||||
else
|
||||
p = ASN1_tag2str(tag);
|
||||
|
||||
if (BIO_printf(bp, fmt, p) <= 0)
|
||||
goto err;
|
||||
return (1);
|
||||
err:
|
||||
return (0);
|
||||
}
|
||||
|
||||
int ASN1_parse(BIO *bp, const unsigned char *pp, long len, int indent)
|
||||
{
|
||||
return (asn1_parse2(bp, &pp, len, 0, 0, indent, 0));
|
||||
}
|
||||
|
||||
int ASN1_parse_dump(BIO *bp, const unsigned char *pp, long len, int indent,
|
||||
int dump)
|
||||
{
|
||||
return (asn1_parse2(bp, &pp, len, 0, 0, indent, dump));
|
||||
}
|
||||
|
||||
static int asn1_parse2(BIO *bp, const unsigned char **pp, long length,
|
||||
int offset, int depth, int indent, int dump)
|
||||
{
|
||||
const unsigned char *p, *ep, *tot, *op, *opp;
|
||||
long len;
|
||||
int tag, xclass, ret = 0;
|
||||
int nl, hl, j, r;
|
||||
ASN1_OBJECT *o = NULL;
|
||||
ASN1_OCTET_STRING *os = NULL;
|
||||
/* ASN1_BMPSTRING *bmp=NULL; */
|
||||
int dump_indent;
|
||||
|
||||
#if 0
|
||||
dump_indent = indent;
|
||||
#else
|
||||
dump_indent = 6; /* Because we know BIO_dump_indent() */
|
||||
#endif
|
||||
|
||||
if (depth > ASN1_PARSE_MAXDEPTH) {
|
||||
BIO_puts(bp, "BAD RECURSION DEPTH\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = *pp;
|
||||
tot = p + length;
|
||||
op = p - 1;
|
||||
while ((p < tot) && (op < p)) {
|
||||
op = p;
|
||||
j = ASN1_get_object(&p, &len, &tag, &xclass, length);
|
||||
#ifdef LINT
|
||||
j = j;
|
||||
#endif
|
||||
if (j & 0x80) {
|
||||
if (BIO_puts(bp, "Error in encoding\n") <= 0)
|
||||
goto end;
|
||||
ret = 0;
|
||||
goto end;
|
||||
}
|
||||
hl = (p - op);
|
||||
length -= hl;
|
||||
/*
|
||||
* if j == 0x21 it is a constructed indefinite length object
|
||||
*/
|
||||
if (BIO_printf(bp, "%5ld:", (long)offset + (long)(op - *pp))
|
||||
<= 0)
|
||||
goto end;
|
||||
|
||||
if (j != (V_ASN1_CONSTRUCTED | 1)) {
|
||||
if (BIO_printf(bp, "d=%-2d hl=%ld l=%4ld ",
|
||||
depth, (long)hl, len) <= 0)
|
||||
goto end;
|
||||
} else {
|
||||
if (BIO_printf(bp, "d=%-2d hl=%ld l=inf ", depth, (long)hl) <= 0)
|
||||
goto end;
|
||||
}
|
||||
if (!asn1_print_info(bp, tag, xclass, j, (indent) ? depth : 0))
|
||||
goto end;
|
||||
if (j & V_ASN1_CONSTRUCTED) {
|
||||
ep = p + len;
|
||||
if (BIO_puts(bp, "\n") <= 0)
|
||||
goto end;
|
||||
if (len > length) {
|
||||
BIO_printf(bp, "length is greater than %ld\n", length);
|
||||
ret = 0;
|
||||
goto end;
|
||||
}
|
||||
if ((j == 0x21) && (len == 0)) {
|
||||
for (;;) {
|
||||
r = asn1_parse2(bp, &p, (long)(tot - p),
|
||||
offset + (p - *pp), depth + 1,
|
||||
indent, dump);
|
||||
if (r == 0) {
|
||||
ret = 0;
|
||||
goto end;
|
||||
}
|
||||
if ((r == 2) || (p >= tot))
|
||||
break;
|
||||
}
|
||||
} else
|
||||
while (p < ep) {
|
||||
r = asn1_parse2(bp, &p, (long)len,
|
||||
offset + (p - *pp), depth + 1,
|
||||
indent, dump);
|
||||
if (r == 0) {
|
||||
ret = 0;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
} else if (xclass != 0) {
|
||||
p += len;
|
||||
if (BIO_puts(bp, "\n") <= 0)
|
||||
goto end;
|
||||
} else {
|
||||
nl = 0;
|
||||
if ((tag == V_ASN1_PRINTABLESTRING) ||
|
||||
(tag == V_ASN1_T61STRING) ||
|
||||
(tag == V_ASN1_IA5STRING) ||
|
||||
(tag == V_ASN1_VISIBLESTRING) ||
|
||||
(tag == V_ASN1_NUMERICSTRING) ||
|
||||
(tag == V_ASN1_UTF8STRING) ||
|
||||
(tag == V_ASN1_UTCTIME) || (tag == V_ASN1_GENERALIZEDTIME)) {
|
||||
if (BIO_puts(bp, ":") <= 0)
|
||||
goto end;
|
||||
if ((len > 0) && BIO_write(bp, (const char *)p, (int)len)
|
||||
!= (int)len)
|
||||
goto end;
|
||||
} else if (tag == V_ASN1_OBJECT) {
|
||||
opp = op;
|
||||
if (d2i_ASN1_OBJECT(&o, &opp, len + hl) != NULL) {
|
||||
if (BIO_puts(bp, ":") <= 0)
|
||||
goto end;
|
||||
i2a_ASN1_OBJECT(bp, o);
|
||||
} else {
|
||||
if (BIO_puts(bp, ":BAD OBJECT") <= 0)
|
||||
goto end;
|
||||
}
|
||||
} else if (tag == V_ASN1_BOOLEAN) {
|
||||
int ii;
|
||||
|
||||
opp = op;
|
||||
ii = d2i_ASN1_BOOLEAN(NULL, &opp, len + hl);
|
||||
if (ii < 0) {
|
||||
if (BIO_puts(bp, "Bad boolean\n") <= 0)
|
||||
goto end;
|
||||
}
|
||||
BIO_printf(bp, ":%d", ii);
|
||||
} else if (tag == V_ASN1_BMPSTRING) {
|
||||
/* do the BMP thang */
|
||||
} else if (tag == V_ASN1_OCTET_STRING) {
|
||||
int i, printable = 1;
|
||||
|
||||
opp = op;
|
||||
os = d2i_ASN1_OCTET_STRING(NULL, &opp, len + hl);
|
||||
if (os != NULL && os->length > 0) {
|
||||
opp = os->data;
|
||||
/*
|
||||
* testing whether the octet string is printable
|
||||
*/
|
||||
for (i = 0; i < os->length; i++) {
|
||||
if (((opp[i] < ' ') &&
|
||||
(opp[i] != '\n') &&
|
||||
(opp[i] != '\r') &&
|
||||
(opp[i] != '\t')) || (opp[i] > '~')) {
|
||||
printable = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (printable)
|
||||
/* printable string */
|
||||
{
|
||||
if (BIO_puts(bp, ":") <= 0)
|
||||
goto end;
|
||||
if (BIO_write(bp, (const char *)opp, os->length) <= 0)
|
||||
goto end;
|
||||
} else if (!dump)
|
||||
/*
|
||||
* not printable => print octet string as hex dump
|
||||
*/
|
||||
{
|
||||
if (BIO_puts(bp, "[HEX DUMP]:") <= 0)
|
||||
goto end;
|
||||
for (i = 0; i < os->length; i++) {
|
||||
if (BIO_printf(bp, "%02X", opp[i]) <= 0)
|
||||
goto end;
|
||||
}
|
||||
} else
|
||||
/* print the normal dump */
|
||||
{
|
||||
if (!nl) {
|
||||
if (BIO_puts(bp, "\n") <= 0)
|
||||
goto end;
|
||||
}
|
||||
if (!BIO_hexdump(bp, opp,
|
||||
((dump == -1 || dump >
|
||||
os->length) ? os->length : dump),
|
||||
dump_indent))
|
||||
goto end;
|
||||
nl = 1;
|
||||
}
|
||||
}
|
||||
if (os != NULL) {
|
||||
M_ASN1_OCTET_STRING_free(os);
|
||||
os = NULL;
|
||||
}
|
||||
} else if (tag == V_ASN1_INTEGER) {
|
||||
ASN1_INTEGER *bs;
|
||||
int i;
|
||||
|
||||
opp = op;
|
||||
bs = d2i_ASN1_INTEGER(NULL, &opp, len + hl);
|
||||
if (bs != NULL) {
|
||||
if (BIO_puts(bp, ":") <= 0)
|
||||
goto end;
|
||||
if (bs->type == V_ASN1_NEG_INTEGER)
|
||||
if (BIO_puts(bp, "-") <= 0)
|
||||
goto end;
|
||||
for (i = 0; i < bs->length; i++) {
|
||||
if (BIO_printf(bp, "%02X", bs->data[i]) <= 0)
|
||||
goto end;
|
||||
}
|
||||
if (bs->length == 0) {
|
||||
if (BIO_puts(bp, "00") <= 0)
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
if (BIO_puts(bp, "BAD INTEGER") <= 0)
|
||||
goto end;
|
||||
}
|
||||
M_ASN1_INTEGER_free(bs);
|
||||
} else if (tag == V_ASN1_ENUMERATED) {
|
||||
ASN1_ENUMERATED *bs;
|
||||
int i;
|
||||
|
||||
opp = op;
|
||||
bs = d2i_ASN1_ENUMERATED(NULL, &opp, len + hl);
|
||||
if (bs != NULL) {
|
||||
if (BIO_puts(bp, ":") <= 0)
|
||||
goto end;
|
||||
if (bs->type == V_ASN1_NEG_ENUMERATED)
|
||||
if (BIO_puts(bp, "-") <= 0)
|
||||
goto end;
|
||||
for (i = 0; i < bs->length; i++) {
|
||||
if (BIO_printf(bp, "%02X", bs->data[i]) <= 0)
|
||||
goto end;
|
||||
}
|
||||
if (bs->length == 0) {
|
||||
if (BIO_puts(bp, "00") <= 0)
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
if (BIO_puts(bp, "BAD ENUMERATED") <= 0)
|
||||
goto end;
|
||||
}
|
||||
M_ASN1_ENUMERATED_free(bs);
|
||||
} else if (len > 0 && dump) {
|
||||
if (!nl) {
|
||||
if (BIO_puts(bp, "\n") <= 0)
|
||||
goto end;
|
||||
}
|
||||
if (!BIO_hexdump(bp, p,
|
||||
((dump == -1 || dump > len) ? len : dump),
|
||||
dump_indent))
|
||||
goto end;
|
||||
nl = 1;
|
||||
}
|
||||
|
||||
if (!nl) {
|
||||
if (BIO_puts(bp, "\n") <= 0)
|
||||
goto end;
|
||||
}
|
||||
p += len;
|
||||
if ((tag == V_ASN1_EOC) && (xclass == 0)) {
|
||||
ret = 2; /* End of sequence */
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
length -= len;
|
||||
}
|
||||
ret = 1;
|
||||
end:
|
||||
if (o != NULL)
|
||||
ASN1_OBJECT_free(o);
|
||||
if (os != NULL)
|
||||
M_ASN1_OCTET_STRING_free(os);
|
||||
*pp = p;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
const char *ASN1_tag2str(int tag)
|
||||
{
|
||||
|
||||
+24
-129
@@ -12,22 +12,13 @@
|
||||
* 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/crypto.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/obj.h>
|
||||
#include <openssl/span.h>
|
||||
|
||||
#include "../test/test_util.h"
|
||||
#include "../test/scoped_types.h"
|
||||
|
||||
|
||||
// kTag128 is an ASN.1 structure with a universal tag with number 128.
|
||||
@@ -49,138 +40,42 @@ static const uint8_t kTagOverflow[] = {
|
||||
0x1f, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x01, 0x00,
|
||||
};
|
||||
|
||||
TEST(ASN1Test, LargeTags) {
|
||||
static bool TestLargeTags() {
|
||||
const uint8_t *p = kTag258;
|
||||
bssl::UniquePtr<ASN1_TYPE> obj(d2i_ASN1_TYPE(NULL, &p, sizeof(kTag258)));
|
||||
EXPECT_FALSE(obj) << "Parsed value with illegal tag" << obj->type;
|
||||
ScopedASN1_TYPE obj(d2i_ASN1_TYPE(NULL, &p, sizeof(kTag258)));
|
||||
if (obj) {
|
||||
fprintf(stderr, "Parsed value with illegal tag (type = %d).\n", obj->type);
|
||||
return false;
|
||||
}
|
||||
ERR_clear_error();
|
||||
|
||||
p = kTagOverflow;
|
||||
obj.reset(d2i_ASN1_TYPE(NULL, &p, sizeof(kTagOverflow)));
|
||||
EXPECT_FALSE(obj) << "Parsed value with tag overflow" << obj->type;
|
||||
if (obj) {
|
||||
fprintf(stderr, "Parsed value with tag overflow (type = %d).\n", obj->type);
|
||||
return false;
|
||||
}
|
||||
ERR_clear_error();
|
||||
|
||||
p = kTag128;
|
||||
obj.reset(d2i_ASN1_TYPE(NULL, &p, sizeof(kTag128)));
|
||||
ASSERT_TRUE(obj);
|
||||
EXPECT_EQ(128, obj->type);
|
||||
const uint8_t kZero = 0;
|
||||
EXPECT_EQ(Bytes(&kZero, 1), Bytes(obj->value.asn1_string->data,
|
||||
obj->value.asn1_string->length));
|
||||
}
|
||||
|
||||
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)) {
|
||||
if (!obj || obj->type != 128 || obj->value.asn1_string->length != 1 ||
|
||||
obj->value.asn1_string->data[0] != 0) {
|
||||
fprintf(stderr, "Failed to parse value with tag 128.\n");
|
||||
ERR_print_errors_fp(stderr);
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
int main() {
|
||||
CRYPTO_library_init();
|
||||
|
||||
// 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);
|
||||
if (!TestLargeTags()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 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(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);
|
||||
printf("PASS\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ ASN1_STRING *ASN1_item_pack(void *obj, const ASN1_ITEM *it, ASN1_STRING **oct)
|
||||
|
||||
/* Extract an ASN1 object from an ASN1_STRING */
|
||||
|
||||
void *ASN1_item_unpack(const ASN1_STRING *oct, const ASN1_ITEM *it)
|
||||
void *ASN1_item_unpack(ASN1_STRING *oct, const ASN1_ITEM *it)
|
||||
{
|
||||
const unsigned char *p;
|
||||
void *ret;
|
||||
|
||||
@@ -0,0 +1,477 @@
|
||||
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* This package is an SSL implementation written
|
||||
* by Eric Young (eay@cryptsoft.com).
|
||||
* The implementation was written so as to conform with Netscapes SSL.
|
||||
*
|
||||
* This library is free for commercial and non-commercial use as long as
|
||||
* the following conditions are aheared to. The following conditions
|
||||
* apply to all code found in this distribution, be it the RC4, RSA,
|
||||
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
|
||||
* included with this distribution is covered by the same copyright terms
|
||||
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||
*
|
||||
* Copyright remains Eric Young's, and as such any Copyright notices in
|
||||
* the code are not to be removed.
|
||||
* If this package is used in a product, Eric Young should be given attribution
|
||||
* as the author of the parts of the library used.
|
||||
* This can be in the form of a textual message at program startup or
|
||||
* in documentation (online or textual) provided with the package.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* "This product includes cryptographic software written by
|
||||
* Eric Young (eay@cryptsoft.com)"
|
||||
* The word 'cryptographic' can be left out if the rouines from the library
|
||||
* being used are not cryptographic related :-).
|
||||
* 4. If you include any Windows specific code (or a derivative thereof) from
|
||||
* the apps directory (application code) you must include an acknowledgement:
|
||||
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* The licence and distribution terms for any publically available version or
|
||||
* derivative of this code cannot be changed. i.e. this code cannot simply be
|
||||
* copied and put under another distribution licence
|
||||
* [including the GNU Public Licence.] */
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
/* Must be large enough for biggest tag+length */
|
||||
#define DEFAULT_ASN1_BUF_SIZE 20
|
||||
|
||||
typedef enum {
|
||||
ASN1_STATE_START,
|
||||
ASN1_STATE_PRE_COPY,
|
||||
ASN1_STATE_HEADER,
|
||||
ASN1_STATE_HEADER_COPY,
|
||||
ASN1_STATE_DATA_COPY,
|
||||
ASN1_STATE_POST_COPY,
|
||||
ASN1_STATE_DONE
|
||||
} asn1_bio_state_t;
|
||||
|
||||
typedef struct BIO_ASN1_EX_FUNCS_st {
|
||||
asn1_ps_func *ex_func;
|
||||
asn1_ps_func *ex_free_func;
|
||||
} BIO_ASN1_EX_FUNCS;
|
||||
|
||||
typedef struct BIO_ASN1_BUF_CTX_t {
|
||||
/* Internal state */
|
||||
asn1_bio_state_t state;
|
||||
/* Internal buffer */
|
||||
unsigned char *buf;
|
||||
/* Size of buffer */
|
||||
int bufsize;
|
||||
/* Current position in buffer */
|
||||
int bufpos;
|
||||
/* Current buffer length */
|
||||
int buflen;
|
||||
/* Amount of data to copy */
|
||||
int copylen;
|
||||
/* Class and tag to use */
|
||||
int asn1_class, asn1_tag;
|
||||
asn1_ps_func *prefix, *prefix_free, *suffix, *suffix_free;
|
||||
/* Extra buffer for prefix and suffix data */
|
||||
unsigned char *ex_buf;
|
||||
int ex_len;
|
||||
int ex_pos;
|
||||
void *ex_arg;
|
||||
} BIO_ASN1_BUF_CTX;
|
||||
|
||||
static int asn1_bio_write(BIO *h, const char *buf, int num);
|
||||
static int asn1_bio_read(BIO *h, char *buf, int size);
|
||||
static int asn1_bio_puts(BIO *h, const char *str);
|
||||
static int asn1_bio_gets(BIO *h, char *str, int size);
|
||||
static long asn1_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2);
|
||||
static int asn1_bio_new(BIO *h);
|
||||
static int asn1_bio_free(BIO *data);
|
||||
static long asn1_bio_callback_ctrl(BIO *h, int cmd, bio_info_cb fp);
|
||||
|
||||
static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size);
|
||||
static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
|
||||
asn1_ps_func *cleanup, asn1_bio_state_t next);
|
||||
static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
|
||||
asn1_ps_func *setup,
|
||||
asn1_bio_state_t ex_state,
|
||||
asn1_bio_state_t other_state);
|
||||
|
||||
static const BIO_METHOD methods_asn1 = {
|
||||
BIO_TYPE_ASN1,
|
||||
"asn1",
|
||||
asn1_bio_write,
|
||||
asn1_bio_read,
|
||||
asn1_bio_puts,
|
||||
asn1_bio_gets,
|
||||
asn1_bio_ctrl,
|
||||
asn1_bio_new,
|
||||
asn1_bio_free,
|
||||
asn1_bio_callback_ctrl,
|
||||
};
|
||||
|
||||
const BIO_METHOD *BIO_f_asn1(void)
|
||||
{
|
||||
return (&methods_asn1);
|
||||
}
|
||||
|
||||
static int asn1_bio_new(BIO *b)
|
||||
{
|
||||
BIO_ASN1_BUF_CTX *ctx;
|
||||
ctx = OPENSSL_malloc(sizeof(BIO_ASN1_BUF_CTX));
|
||||
if (!ctx)
|
||||
return 0;
|
||||
if (!asn1_bio_init(ctx, DEFAULT_ASN1_BUF_SIZE)) {
|
||||
OPENSSL_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
b->init = 1;
|
||||
b->ptr = (char *)ctx;
|
||||
b->flags = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size)
|
||||
{
|
||||
ctx->buf = OPENSSL_malloc(size);
|
||||
if (!ctx->buf)
|
||||
return 0;
|
||||
ctx->bufsize = size;
|
||||
ctx->bufpos = 0;
|
||||
ctx->buflen = 0;
|
||||
ctx->copylen = 0;
|
||||
ctx->asn1_class = V_ASN1_UNIVERSAL;
|
||||
ctx->asn1_tag = V_ASN1_OCTET_STRING;
|
||||
ctx->ex_buf = 0;
|
||||
ctx->ex_pos = 0;
|
||||
ctx->ex_len = 0;
|
||||
ctx->state = ASN1_STATE_START;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int asn1_bio_free(BIO *b)
|
||||
{
|
||||
BIO_ASN1_BUF_CTX *ctx;
|
||||
ctx = (BIO_ASN1_BUF_CTX *)b->ptr;
|
||||
if (ctx == NULL)
|
||||
return 0;
|
||||
if (ctx->buf)
|
||||
OPENSSL_free(ctx->buf);
|
||||
OPENSSL_free(ctx);
|
||||
b->init = 0;
|
||||
b->ptr = NULL;
|
||||
b->flags = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int asn1_bio_write(BIO *b, const char *in, int inl)
|
||||
{
|
||||
BIO_ASN1_BUF_CTX *ctx;
|
||||
int wrmax, wrlen, ret;
|
||||
unsigned char *p;
|
||||
if (!in || (inl < 0) || (b->next_bio == NULL))
|
||||
return 0;
|
||||
ctx = (BIO_ASN1_BUF_CTX *)b->ptr;
|
||||
if (ctx == NULL)
|
||||
return 0;
|
||||
|
||||
wrlen = 0;
|
||||
ret = -1;
|
||||
|
||||
for (;;) {
|
||||
switch (ctx->state) {
|
||||
|
||||
/* Setup prefix data, call it */
|
||||
case ASN1_STATE_START:
|
||||
if (!asn1_bio_setup_ex(b, ctx, ctx->prefix,
|
||||
ASN1_STATE_PRE_COPY, ASN1_STATE_HEADER))
|
||||
return 0;
|
||||
break;
|
||||
|
||||
/* Copy any pre data first */
|
||||
case ASN1_STATE_PRE_COPY:
|
||||
|
||||
ret = asn1_bio_flush_ex(b, ctx, ctx->prefix_free,
|
||||
ASN1_STATE_HEADER);
|
||||
|
||||
if (ret <= 0)
|
||||
goto done;
|
||||
|
||||
break;
|
||||
|
||||
case ASN1_STATE_HEADER:
|
||||
ctx->buflen = ASN1_object_size(0, inl, ctx->asn1_tag) - inl;
|
||||
assert(ctx->buflen <= ctx->bufsize);
|
||||
p = ctx->buf;
|
||||
ASN1_put_object(&p, 0, inl, ctx->asn1_tag, ctx->asn1_class);
|
||||
ctx->copylen = inl;
|
||||
ctx->state = ASN1_STATE_HEADER_COPY;
|
||||
|
||||
break;
|
||||
|
||||
case ASN1_STATE_HEADER_COPY:
|
||||
ret = BIO_write(b->next_bio, ctx->buf + ctx->bufpos, ctx->buflen);
|
||||
if (ret <= 0)
|
||||
goto done;
|
||||
|
||||
ctx->buflen -= ret;
|
||||
if (ctx->buflen)
|
||||
ctx->bufpos += ret;
|
||||
else {
|
||||
ctx->bufpos = 0;
|
||||
ctx->state = ASN1_STATE_DATA_COPY;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ASN1_STATE_DATA_COPY:
|
||||
|
||||
if (inl > ctx->copylen)
|
||||
wrmax = ctx->copylen;
|
||||
else
|
||||
wrmax = inl;
|
||||
ret = BIO_write(b->next_bio, in, wrmax);
|
||||
if (ret <= 0)
|
||||
break;
|
||||
wrlen += ret;
|
||||
ctx->copylen -= ret;
|
||||
in += ret;
|
||||
inl -= ret;
|
||||
|
||||
if (ctx->copylen == 0)
|
||||
ctx->state = ASN1_STATE_HEADER;
|
||||
|
||||
if (inl == 0)
|
||||
goto done;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
BIO_clear_retry_flags(b);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
done:
|
||||
BIO_clear_retry_flags(b);
|
||||
BIO_copy_next_retry(b);
|
||||
|
||||
return (wrlen > 0) ? wrlen : ret;
|
||||
|
||||
}
|
||||
|
||||
static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
|
||||
asn1_ps_func *cleanup, asn1_bio_state_t next)
|
||||
{
|
||||
int ret;
|
||||
if (ctx->ex_len <= 0)
|
||||
return 1;
|
||||
for (;;) {
|
||||
ret = BIO_write(b->next_bio, ctx->ex_buf + ctx->ex_pos, ctx->ex_len);
|
||||
if (ret <= 0)
|
||||
break;
|
||||
ctx->ex_len -= ret;
|
||||
if (ctx->ex_len > 0)
|
||||
ctx->ex_pos += ret;
|
||||
else {
|
||||
if (cleanup)
|
||||
cleanup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg);
|
||||
ctx->state = next;
|
||||
ctx->ex_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
|
||||
asn1_ps_func *setup,
|
||||
asn1_bio_state_t ex_state,
|
||||
asn1_bio_state_t other_state)
|
||||
{
|
||||
if (setup && !setup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg)) {
|
||||
BIO_clear_retry_flags(b);
|
||||
return 0;
|
||||
}
|
||||
if (ctx->ex_len > 0)
|
||||
ctx->state = ex_state;
|
||||
else
|
||||
ctx->state = other_state;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int asn1_bio_read(BIO *b, char *in, int inl)
|
||||
{
|
||||
if (!b->next_bio)
|
||||
return 0;
|
||||
return BIO_read(b->next_bio, in, inl);
|
||||
}
|
||||
|
||||
static int asn1_bio_puts(BIO *b, const char *str)
|
||||
{
|
||||
return asn1_bio_write(b, str, strlen(str));
|
||||
}
|
||||
|
||||
static int asn1_bio_gets(BIO *b, char *str, int size)
|
||||
{
|
||||
if (!b->next_bio)
|
||||
return 0;
|
||||
return BIO_gets(b->next_bio, str, size);
|
||||
}
|
||||
|
||||
static long asn1_bio_callback_ctrl(BIO *b, int cmd, bio_info_cb fp)
|
||||
{
|
||||
if (b->next_bio == NULL)
|
||||
return (0);
|
||||
return BIO_callback_ctrl(b->next_bio, cmd, fp);
|
||||
}
|
||||
|
||||
static long asn1_bio_ctrl(BIO *b, int cmd, long arg1, void *arg2)
|
||||
{
|
||||
BIO_ASN1_BUF_CTX *ctx;
|
||||
BIO_ASN1_EX_FUNCS *ex_func;
|
||||
long ret = 1;
|
||||
ctx = (BIO_ASN1_BUF_CTX *)b->ptr;
|
||||
if (ctx == NULL)
|
||||
return 0;
|
||||
switch (cmd) {
|
||||
|
||||
case BIO_C_SET_PREFIX:
|
||||
ex_func = arg2;
|
||||
ctx->prefix = ex_func->ex_func;
|
||||
ctx->prefix_free = ex_func->ex_free_func;
|
||||
break;
|
||||
|
||||
case BIO_C_GET_PREFIX:
|
||||
ex_func = arg2;
|
||||
ex_func->ex_func = ctx->prefix;
|
||||
ex_func->ex_free_func = ctx->prefix_free;
|
||||
break;
|
||||
|
||||
case BIO_C_SET_SUFFIX:
|
||||
ex_func = arg2;
|
||||
ctx->suffix = ex_func->ex_func;
|
||||
ctx->suffix_free = ex_func->ex_free_func;
|
||||
break;
|
||||
|
||||
case BIO_C_GET_SUFFIX:
|
||||
ex_func = arg2;
|
||||
ex_func->ex_func = ctx->suffix;
|
||||
ex_func->ex_free_func = ctx->suffix_free;
|
||||
break;
|
||||
|
||||
case BIO_C_SET_EX_ARG:
|
||||
ctx->ex_arg = arg2;
|
||||
break;
|
||||
|
||||
case BIO_C_GET_EX_ARG:
|
||||
*(void **)arg2 = ctx->ex_arg;
|
||||
break;
|
||||
|
||||
case BIO_CTRL_FLUSH:
|
||||
if (!b->next_bio)
|
||||
return 0;
|
||||
|
||||
/* Call post function if possible */
|
||||
if (ctx->state == ASN1_STATE_HEADER) {
|
||||
if (!asn1_bio_setup_ex(b, ctx, ctx->suffix,
|
||||
ASN1_STATE_POST_COPY, ASN1_STATE_DONE))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ctx->state == ASN1_STATE_POST_COPY) {
|
||||
ret = asn1_bio_flush_ex(b, ctx, ctx->suffix_free,
|
||||
ASN1_STATE_DONE);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ctx->state == ASN1_STATE_DONE)
|
||||
return BIO_ctrl(b->next_bio, cmd, arg1, arg2);
|
||||
else {
|
||||
BIO_clear_retry_flags(b);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!b->next_bio)
|
||||
return 0;
|
||||
return BIO_ctrl(b->next_bio, cmd, arg1, arg2);
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int asn1_bio_set_ex(BIO *b, int cmd,
|
||||
asn1_ps_func *ex_func, asn1_ps_func *ex_free_func)
|
||||
{
|
||||
BIO_ASN1_EX_FUNCS extmp;
|
||||
extmp.ex_func = ex_func;
|
||||
extmp.ex_free_func = ex_free_func;
|
||||
return BIO_ctrl(b, cmd, 0, &extmp);
|
||||
}
|
||||
|
||||
static int asn1_bio_get_ex(BIO *b, int cmd,
|
||||
asn1_ps_func **ex_func,
|
||||
asn1_ps_func **ex_free_func)
|
||||
{
|
||||
BIO_ASN1_EX_FUNCS extmp;
|
||||
int ret;
|
||||
ret = BIO_ctrl(b, cmd, 0, &extmp);
|
||||
if (ret > 0) {
|
||||
*ex_func = extmp.ex_func;
|
||||
*ex_free_func = extmp.ex_free_func;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix,
|
||||
asn1_ps_func *prefix_free)
|
||||
{
|
||||
return asn1_bio_set_ex(b, BIO_C_SET_PREFIX, prefix, prefix_free);
|
||||
}
|
||||
|
||||
int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix,
|
||||
asn1_ps_func **pprefix_free)
|
||||
{
|
||||
return asn1_bio_get_ex(b, BIO_C_GET_PREFIX, pprefix, pprefix_free);
|
||||
}
|
||||
|
||||
int BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix,
|
||||
asn1_ps_func *suffix_free)
|
||||
{
|
||||
return asn1_bio_set_ex(b, BIO_C_SET_SUFFIX, suffix, suffix_free);
|
||||
}
|
||||
|
||||
int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix,
|
||||
asn1_ps_func **psuffix_free)
|
||||
{
|
||||
return asn1_bio_get_ex(b, BIO_C_GET_SUFFIX, psuffix, psuffix_free);
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* This package is an SSL implementation written
|
||||
* by Eric Young (eay@cryptsoft.com).
|
||||
* The implementation was written so as to conform with Netscapes SSL.
|
||||
*
|
||||
* This library is free for commercial and non-commercial use as long as
|
||||
* the following conditions are aheared to. The following conditions
|
||||
* apply to all code found in this distribution, be it the RC4, RSA,
|
||||
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
|
||||
* included with this distribution is covered by the same copyright terms
|
||||
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||
*
|
||||
* Copyright remains Eric Young's, and as such any Copyright notices in
|
||||
* the code are not to be removed.
|
||||
* If this package is used in a product, Eric Young should be given attribution
|
||||
* as the author of the parts of the library used.
|
||||
* This can be in the form of a textual message at program startup or
|
||||
* in documentation (online or textual) provided with the package.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* "This product includes cryptographic software written by
|
||||
* Eric Young (eay@cryptsoft.com)"
|
||||
* The word 'cryptographic' can be left out if the rouines from the library
|
||||
* being used are not cryptographic related :-).
|
||||
* 4. If you include any Windows specific code (or a derivative thereof) from
|
||||
* the apps directory (application code) you must include an acknowledgement:
|
||||
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* The licence and distribution terms for any publically available version or
|
||||
* derivative of this code cannot be changed. i.e. this code cannot simply be
|
||||
* copied and put under another distribution licence
|
||||
* [including the GNU Public Licence.] */
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <openssl/asn1t.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
/* Experimental NDEF ASN1 BIO support routines */
|
||||
|
||||
/*
|
||||
* The usage is quite simple, initialize an ASN1 structure, get a BIO from it
|
||||
* then any data written through the BIO will end up translated to
|
||||
* approptiate format on the fly. The data is streamed out and does *not*
|
||||
* need to be all held in memory at once. When the BIO is flushed the output
|
||||
* is finalized and any signatures etc written out. The BIO is a 'proper'
|
||||
* BIO and can handle non blocking I/O correctly. The usage is simple. The
|
||||
* implementation is *not*...
|
||||
*/
|
||||
|
||||
/* BIO support data stored in the ASN1 BIO ex_arg */
|
||||
|
||||
typedef struct ndef_aux_st {
|
||||
/* ASN1 structure this BIO refers to */
|
||||
ASN1_VALUE *val;
|
||||
const ASN1_ITEM *it;
|
||||
/* Top of the BIO chain */
|
||||
BIO *ndef_bio;
|
||||
/* Output BIO */
|
||||
BIO *out;
|
||||
/* Boundary where content is inserted */
|
||||
unsigned char **boundary;
|
||||
/* DER buffer start */
|
||||
unsigned char *derbuf;
|
||||
} NDEF_SUPPORT;
|
||||
|
||||
static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg);
|
||||
static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen,
|
||||
void *parg);
|
||||
static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg);
|
||||
static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen,
|
||||
void *parg);
|
||||
|
||||
BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it)
|
||||
{
|
||||
NDEF_SUPPORT *ndef_aux = NULL;
|
||||
BIO *asn_bio = NULL;
|
||||
const ASN1_AUX *aux = it->funcs;
|
||||
ASN1_STREAM_ARG sarg;
|
||||
|
||||
if (!aux || !aux->asn1_cb) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_STREAMING_NOT_SUPPORTED);
|
||||
return NULL;
|
||||
}
|
||||
ndef_aux = OPENSSL_malloc(sizeof(NDEF_SUPPORT));
|
||||
asn_bio = BIO_new(BIO_f_asn1());
|
||||
|
||||
/* ASN1 bio needs to be next to output BIO */
|
||||
|
||||
out = BIO_push(asn_bio, out);
|
||||
|
||||
if (!ndef_aux || !asn_bio || !out)
|
||||
goto err;
|
||||
|
||||
BIO_asn1_set_prefix(asn_bio, ndef_prefix, ndef_prefix_free);
|
||||
BIO_asn1_set_suffix(asn_bio, ndef_suffix, ndef_suffix_free);
|
||||
|
||||
/*
|
||||
* Now let callback prepend any digest, cipher etc BIOs ASN1 structure
|
||||
* needs.
|
||||
*/
|
||||
|
||||
sarg.out = out;
|
||||
sarg.ndef_bio = NULL;
|
||||
sarg.boundary = NULL;
|
||||
|
||||
if (aux->asn1_cb(ASN1_OP_STREAM_PRE, &val, it, &sarg) <= 0)
|
||||
goto err;
|
||||
|
||||
ndef_aux->val = val;
|
||||
ndef_aux->it = it;
|
||||
ndef_aux->ndef_bio = sarg.ndef_bio;
|
||||
ndef_aux->boundary = sarg.boundary;
|
||||
ndef_aux->out = out;
|
||||
|
||||
BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux);
|
||||
|
||||
return sarg.ndef_bio;
|
||||
|
||||
err:
|
||||
if (asn_bio)
|
||||
BIO_free(asn_bio);
|
||||
if (ndef_aux)
|
||||
OPENSSL_free(ndef_aux);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg)
|
||||
{
|
||||
NDEF_SUPPORT *ndef_aux;
|
||||
unsigned char *p;
|
||||
int derlen;
|
||||
|
||||
if (!parg)
|
||||
return 0;
|
||||
|
||||
ndef_aux = *(NDEF_SUPPORT **)parg;
|
||||
|
||||
derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it);
|
||||
p = OPENSSL_malloc(derlen);
|
||||
if (p == NULL)
|
||||
return 0;
|
||||
|
||||
ndef_aux->derbuf = p;
|
||||
*pbuf = p;
|
||||
derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
|
||||
|
||||
if (!*ndef_aux->boundary)
|
||||
return 0;
|
||||
|
||||
*plen = *ndef_aux->boundary - *pbuf;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen,
|
||||
void *parg)
|
||||
{
|
||||
NDEF_SUPPORT *ndef_aux;
|
||||
|
||||
if (!parg)
|
||||
return 0;
|
||||
|
||||
ndef_aux = *(NDEF_SUPPORT **)parg;
|
||||
|
||||
if (ndef_aux->derbuf)
|
||||
OPENSSL_free(ndef_aux->derbuf);
|
||||
|
||||
ndef_aux->derbuf = NULL;
|
||||
*pbuf = NULL;
|
||||
*plen = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen,
|
||||
void *parg)
|
||||
{
|
||||
NDEF_SUPPORT **pndef_aux = (NDEF_SUPPORT **)parg;
|
||||
if (!ndef_prefix_free(b, pbuf, plen, parg))
|
||||
return 0;
|
||||
OPENSSL_free(*pndef_aux);
|
||||
*pndef_aux = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg)
|
||||
{
|
||||
NDEF_SUPPORT *ndef_aux;
|
||||
unsigned char *p;
|
||||
int derlen;
|
||||
const ASN1_AUX *aux;
|
||||
ASN1_STREAM_ARG sarg;
|
||||
|
||||
if (!parg)
|
||||
return 0;
|
||||
|
||||
ndef_aux = *(NDEF_SUPPORT **)parg;
|
||||
|
||||
aux = ndef_aux->it->funcs;
|
||||
|
||||
/* Finalize structures */
|
||||
sarg.ndef_bio = ndef_aux->ndef_bio;
|
||||
sarg.out = ndef_aux->out;
|
||||
sarg.boundary = ndef_aux->boundary;
|
||||
if (aux->asn1_cb(ASN1_OP_STREAM_POST,
|
||||
&ndef_aux->val, ndef_aux->it, &sarg) <= 0)
|
||||
return 0;
|
||||
|
||||
derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it);
|
||||
p = OPENSSL_malloc(derlen);
|
||||
if (p == NULL)
|
||||
return 0;
|
||||
|
||||
ndef_aux->derbuf = p;
|
||||
*pbuf = p;
|
||||
derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
|
||||
|
||||
if (!*ndef_aux->boundary)
|
||||
return 0;
|
||||
*pbuf = *ndef_aux->boundary;
|
||||
*plen = derlen - (*ndef_aux->boundary - ndef_aux->derbuf);
|
||||
|
||||
return 1;
|
||||
}
|
||||
+109
-2
@@ -56,11 +56,12 @@
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
/* Based on a_int.c: equivalent ENUMERATED functions */
|
||||
|
||||
int i2a_ASN1_ENUMERATED(BIO *bp, const ASN1_ENUMERATED *a)
|
||||
int i2a_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *a)
|
||||
{
|
||||
int i, n = 0;
|
||||
static const char *h = "0123456789ABCDEF";
|
||||
@@ -91,3 +92,109 @@ int i2a_ASN1_ENUMERATED(BIO *bp, const ASN1_ENUMERATED *a)
|
||||
err:
|
||||
return (-1);
|
||||
}
|
||||
|
||||
int a2i_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *bs, char *buf, int size)
|
||||
{
|
||||
int ret = 0;
|
||||
int i, j, k, m, n, again, bufsize;
|
||||
unsigned char *s = NULL, *sp;
|
||||
unsigned char *bufp;
|
||||
int num = 0, slen = 0, first = 1;
|
||||
|
||||
bs->type = V_ASN1_ENUMERATED;
|
||||
|
||||
bufsize = BIO_gets(bp, buf, size);
|
||||
for (;;) {
|
||||
if (bufsize < 1)
|
||||
goto err_sl;
|
||||
i = bufsize;
|
||||
if (buf[i - 1] == '\n')
|
||||
buf[--i] = '\0';
|
||||
if (i == 0)
|
||||
goto err_sl;
|
||||
if (buf[i - 1] == '\r')
|
||||
buf[--i] = '\0';
|
||||
if (i == 0)
|
||||
goto err_sl;
|
||||
again = (buf[i - 1] == '\\');
|
||||
|
||||
for (j = 0; j < i; j++) {
|
||||
if (!(((buf[j] >= '0') && (buf[j] <= '9')) ||
|
||||
((buf[j] >= 'a') && (buf[j] <= 'f')) ||
|
||||
((buf[j] >= 'A') && (buf[j] <= 'F')))) {
|
||||
i = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
buf[i] = '\0';
|
||||
/*
|
||||
* We have now cleared all the crap off the end of the line
|
||||
*/
|
||||
if (i < 2)
|
||||
goto err_sl;
|
||||
|
||||
bufp = (unsigned char *)buf;
|
||||
if (first) {
|
||||
first = 0;
|
||||
if ((bufp[0] == '0') && (buf[1] == '0')) {
|
||||
bufp += 2;
|
||||
i -= 2;
|
||||
}
|
||||
}
|
||||
k = 0;
|
||||
i -= again;
|
||||
if (i % 2 != 0) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_ODD_NUMBER_OF_CHARS);
|
||||
goto err;
|
||||
}
|
||||
i /= 2;
|
||||
if (num + i > slen) {
|
||||
if (s == NULL)
|
||||
sp = (unsigned char *)OPENSSL_malloc((unsigned int)num +
|
||||
i * 2);
|
||||
else
|
||||
sp = (unsigned char *)OPENSSL_realloc(s,
|
||||
(unsigned int)num +
|
||||
i * 2);
|
||||
if (sp == NULL) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
s = sp;
|
||||
slen = num + i * 2;
|
||||
}
|
||||
for (j = 0; j < i; j++, k += 2) {
|
||||
for (n = 0; n < 2; n++) {
|
||||
m = bufp[k + n];
|
||||
if ((m >= '0') && (m <= '9'))
|
||||
m -= '0';
|
||||
else if ((m >= 'a') && (m <= 'f'))
|
||||
m = m - 'a' + 10;
|
||||
else if ((m >= 'A') && (m <= 'F'))
|
||||
m = m - 'A' + 10;
|
||||
else {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NON_HEX_CHARACTERS);
|
||||
goto err;
|
||||
}
|
||||
s[num + j] <<= 4;
|
||||
s[num + j] |= m;
|
||||
}
|
||||
}
|
||||
num += i;
|
||||
if (again)
|
||||
bufsize = BIO_gets(bp, buf, size);
|
||||
else
|
||||
break;
|
||||
}
|
||||
bs->length = num;
|
||||
bs->data = s;
|
||||
ret = 1;
|
||||
err:
|
||||
if (0) {
|
||||
err_sl:
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_SHORT_LINE);
|
||||
}
|
||||
if (s != NULL)
|
||||
OPENSSL_free(s);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
+107
-2
@@ -56,9 +56,10 @@
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
int i2a_ASN1_INTEGER(BIO *bp, const ASN1_INTEGER *a)
|
||||
int i2a_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *a)
|
||||
{
|
||||
int i, n = 0;
|
||||
static const char *h = "0123456789ABCDEF";
|
||||
@@ -95,3 +96,107 @@ int i2a_ASN1_INTEGER(BIO *bp, const ASN1_INTEGER *a)
|
||||
err:
|
||||
return (-1);
|
||||
}
|
||||
|
||||
int a2i_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *bs, char *buf, int size)
|
||||
{
|
||||
int ret = 0;
|
||||
int i, j, k, m, n, again, bufsize;
|
||||
unsigned char *s = NULL, *sp;
|
||||
unsigned char *bufp;
|
||||
int num = 0, slen = 0, first = 1;
|
||||
|
||||
bs->type = V_ASN1_INTEGER;
|
||||
|
||||
bufsize = BIO_gets(bp, buf, size);
|
||||
for (;;) {
|
||||
if (bufsize < 1)
|
||||
goto err_sl;
|
||||
i = bufsize;
|
||||
if (buf[i - 1] == '\n')
|
||||
buf[--i] = '\0';
|
||||
if (i == 0)
|
||||
goto err_sl;
|
||||
if (buf[i - 1] == '\r')
|
||||
buf[--i] = '\0';
|
||||
if (i == 0)
|
||||
goto err_sl;
|
||||
again = (buf[i - 1] == '\\');
|
||||
|
||||
for (j = 0; j < i; j++) {
|
||||
if (!(((buf[j] >= '0') && (buf[j] <= '9')) ||
|
||||
((buf[j] >= 'a') && (buf[j] <= 'f')) ||
|
||||
((buf[j] >= 'A') && (buf[j] <= 'F')))) {
|
||||
i = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
buf[i] = '\0';
|
||||
/*
|
||||
* We have now cleared all the crap off the end of the line
|
||||
*/
|
||||
if (i < 2)
|
||||
goto err_sl;
|
||||
|
||||
bufp = (unsigned char *)buf;
|
||||
if (first) {
|
||||
first = 0;
|
||||
if ((bufp[0] == '0') && (buf[1] == '0')) {
|
||||
bufp += 2;
|
||||
i -= 2;
|
||||
}
|
||||
}
|
||||
k = 0;
|
||||
i -= again;
|
||||
if (i % 2 != 0) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_ODD_NUMBER_OF_CHARS);
|
||||
goto err;
|
||||
}
|
||||
i /= 2;
|
||||
if (num + i > slen) {
|
||||
if (s == NULL)
|
||||
sp = (unsigned char *)OPENSSL_malloc((unsigned int)num +
|
||||
i * 2);
|
||||
else
|
||||
sp = OPENSSL_realloc_clean(s, slen, num + i * 2);
|
||||
if (sp == NULL) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
s = sp;
|
||||
slen = num + i * 2;
|
||||
}
|
||||
for (j = 0; j < i; j++, k += 2) {
|
||||
for (n = 0; n < 2; n++) {
|
||||
m = bufp[k + n];
|
||||
if ((m >= '0') && (m <= '9'))
|
||||
m -= '0';
|
||||
else if ((m >= 'a') && (m <= 'f'))
|
||||
m = m - 'a' + 10;
|
||||
else if ((m >= 'A') && (m <= 'F'))
|
||||
m = m - 'A' + 10;
|
||||
else {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NON_HEX_CHARACTERS);
|
||||
goto err;
|
||||
}
|
||||
s[num + j] <<= 4;
|
||||
s[num + j] |= m;
|
||||
}
|
||||
}
|
||||
num += i;
|
||||
if (again)
|
||||
bufsize = BIO_gets(bp, buf, size);
|
||||
else
|
||||
break;
|
||||
}
|
||||
bs->length = num;
|
||||
bs->data = s;
|
||||
ret = 1;
|
||||
err:
|
||||
if (0) {
|
||||
err_sl:
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_SHORT_LINE);
|
||||
}
|
||||
if (s != NULL)
|
||||
OPENSSL_free(s);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
+107
-2
@@ -56,9 +56,10 @@
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
int i2a_ASN1_STRING(BIO *bp, const ASN1_STRING *a, int type)
|
||||
int i2a_ASN1_STRING(BIO *bp, ASN1_STRING *a, int type)
|
||||
{
|
||||
int i, n = 0;
|
||||
static const char *h = "0123456789ABCDEF";
|
||||
@@ -89,3 +90,107 @@ int i2a_ASN1_STRING(BIO *bp, const ASN1_STRING *a, int type)
|
||||
err:
|
||||
return (-1);
|
||||
}
|
||||
|
||||
int a2i_ASN1_STRING(BIO *bp, ASN1_STRING *bs, char *buf, int size)
|
||||
{
|
||||
int ret = 0;
|
||||
int i, j, k, m, n, again, bufsize;
|
||||
unsigned char *s = NULL, *sp;
|
||||
unsigned char *bufp;
|
||||
int num = 0, slen = 0, first = 1;
|
||||
|
||||
bufsize = BIO_gets(bp, buf, size);
|
||||
for (;;) {
|
||||
if (bufsize < 1) {
|
||||
if (first)
|
||||
break;
|
||||
else
|
||||
goto err_sl;
|
||||
}
|
||||
first = 0;
|
||||
|
||||
i = bufsize;
|
||||
if (buf[i - 1] == '\n')
|
||||
buf[--i] = '\0';
|
||||
if (i == 0)
|
||||
goto err_sl;
|
||||
if (buf[i - 1] == '\r')
|
||||
buf[--i] = '\0';
|
||||
if (i == 0)
|
||||
goto err_sl;
|
||||
again = (buf[i - 1] == '\\');
|
||||
|
||||
for (j = i - 1; j > 0; j--) {
|
||||
if (!(((buf[j] >= '0') && (buf[j] <= '9')) ||
|
||||
((buf[j] >= 'a') && (buf[j] <= 'f')) ||
|
||||
((buf[j] >= 'A') && (buf[j] <= 'F')))) {
|
||||
i = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
buf[i] = '\0';
|
||||
/*
|
||||
* We have now cleared all the crap off the end of the line
|
||||
*/
|
||||
if (i < 2)
|
||||
goto err_sl;
|
||||
|
||||
bufp = (unsigned char *)buf;
|
||||
|
||||
k = 0;
|
||||
i -= again;
|
||||
if (i % 2 != 0) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_ODD_NUMBER_OF_CHARS);
|
||||
goto err;
|
||||
}
|
||||
i /= 2;
|
||||
if (num + i > slen) {
|
||||
if (s == NULL)
|
||||
sp = (unsigned char *)OPENSSL_malloc((unsigned int)num +
|
||||
i * 2);
|
||||
else
|
||||
sp = (unsigned char *)OPENSSL_realloc(s,
|
||||
(unsigned int)num +
|
||||
i * 2);
|
||||
if (sp == NULL) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
s = sp;
|
||||
slen = num + i * 2;
|
||||
}
|
||||
for (j = 0; j < i; j++, k += 2) {
|
||||
for (n = 0; n < 2; n++) {
|
||||
m = bufp[k + n];
|
||||
if ((m >= '0') && (m <= '9'))
|
||||
m -= '0';
|
||||
else if ((m >= 'a') && (m <= 'f'))
|
||||
m = m - 'a' + 10;
|
||||
else if ((m >= 'A') && (m <= 'F'))
|
||||
m = m - 'A' + 10;
|
||||
else {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NON_HEX_CHARACTERS);
|
||||
goto err;
|
||||
}
|
||||
s[num + j] <<= 4;
|
||||
s[num + j] |= m;
|
||||
}
|
||||
}
|
||||
num += i;
|
||||
if (again)
|
||||
bufsize = BIO_gets(bp, buf, size);
|
||||
else
|
||||
break;
|
||||
}
|
||||
bs->length = num;
|
||||
bs->data = s;
|
||||
ret = 1;
|
||||
err:
|
||||
if (0) {
|
||||
err_sl:
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_SHORT_LINE);
|
||||
}
|
||||
if (s != NULL)
|
||||
OPENSSL_free(s);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* This package is an SSL implementation written
|
||||
* by Eric Young (eay@cryptsoft.com).
|
||||
* The implementation was written so as to conform with Netscapes SSL.
|
||||
*
|
||||
* This library is free for commercial and non-commercial use as long as
|
||||
* the following conditions are aheared to. The following conditions
|
||||
* apply to all code found in this distribution, be it the RC4, RSA,
|
||||
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
|
||||
* included with this distribution is covered by the same copyright terms
|
||||
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||
*
|
||||
* Copyright remains Eric Young's, and as such any Copyright notices in
|
||||
* the code are not to be removed.
|
||||
* If this package is used in a product, Eric Young should be given attribution
|
||||
* as the author of the parts of the library used.
|
||||
* This can be in the form of a textual message at program startup or
|
||||
* in documentation (online or textual) provided with the package.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* "This product includes cryptographic software written by
|
||||
* Eric Young (eay@cryptsoft.com)"
|
||||
* The word 'cryptographic' can be left out if the rouines from the library
|
||||
* being used are not cryptographic related :-).
|
||||
* 4. If you include any Windows specific code (or a derivative thereof) from
|
||||
* the apps directory (application code) you must include an acknowledgement:
|
||||
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* The licence and distribution terms for any publically available version or
|
||||
* derivative of this code cannot be changed. i.e. this code cannot simply be
|
||||
* copied and put under another distribution licence
|
||||
* [including the GNU Public Licence.] */
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/mem.h>
|
||||
|
||||
int ASN1_BIT_STRING_name_print(BIO *out, ASN1_BIT_STRING *bs,
|
||||
BIT_STRING_BITNAME *tbl, int indent)
|
||||
{
|
||||
BIT_STRING_BITNAME *bnam;
|
||||
char first = 1;
|
||||
BIO_printf(out, "%*s", indent, "");
|
||||
for (bnam = tbl; bnam->lname; bnam++) {
|
||||
if (ASN1_BIT_STRING_get_bit(bs, bnam->bitnum)) {
|
||||
if (!first)
|
||||
BIO_puts(out, ", ");
|
||||
BIO_puts(out, bnam->lname);
|
||||
first = 0;
|
||||
}
|
||||
}
|
||||
BIO_puts(out, "\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ASN1_BIT_STRING_set_asc(ASN1_BIT_STRING *bs, char *name, int value,
|
||||
BIT_STRING_BITNAME *tbl)
|
||||
{
|
||||
int bitnum;
|
||||
bitnum = ASN1_BIT_STRING_num_asc(name, tbl);
|
||||
if (bitnum < 0)
|
||||
return 0;
|
||||
if (bs) {
|
||||
if (!ASN1_BIT_STRING_set_bit(bs, bitnum, value))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ASN1_BIT_STRING_num_asc(char *name, BIT_STRING_BITNAME *tbl)
|
||||
{
|
||||
BIT_STRING_BITNAME *bnam;
|
||||
for (bnam = tbl; bnam->lname; bnam++) {
|
||||
if (!strcmp(bnam->sname, name) || !strcmp(bnam->lname, name))
|
||||
return bnam->bitnum;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
+34
-57
@@ -56,7 +56,6 @@
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/asn1t.h>
|
||||
@@ -66,14 +65,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 +81,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,
|
||||
@@ -156,14 +147,23 @@ ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **pval,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ASN1_template_d2i(ASN1_VALUE **pval,
|
||||
const unsigned char **in, long len,
|
||||
const ASN1_TEMPLATE *tt)
|
||||
{
|
||||
ASN1_TLC c;
|
||||
asn1_tlc_clear_nc(&c);
|
||||
return asn1_template_ex_d2i(pval, in, len, tt, 0, &c);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode an item, taking care of IMPLICIT tagging, if any. If 'opt' set and
|
||||
* tag mismatch return -1 to handle OPTIONAL
|
||||
*/
|
||||
|
||||
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;
|
||||
@@ -180,7 +180,6 @@ static int asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in,
|
||||
int ret = 0;
|
||||
ASN1_VALUE **pchptr, *ptmpval;
|
||||
int combine = aclass & ASN1_TFLG_COMBINE;
|
||||
aclass &= ~ASN1_TFLG_COMBINE;
|
||||
if (!pval)
|
||||
return 0;
|
||||
if (aux && aux->asn1_cb)
|
||||
@@ -188,19 +187,6 @@ static int asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in,
|
||||
else
|
||||
asn1_cb = 0;
|
||||
|
||||
/*
|
||||
* Bound |len| to comfortably fit in an int. Lengths in this module often
|
||||
* switch between int and long without overflow checks.
|
||||
*/
|
||||
if (len > INT_MAX/2) {
|
||||
len = INT_MAX/2;
|
||||
}
|
||||
|
||||
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 +202,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 +325,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;
|
||||
@@ -413,9 +399,7 @@ static int asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in,
|
||||
if (tt->flags & ASN1_TFLG_ADB_MASK) {
|
||||
const ASN1_TEMPLATE *seqtt;
|
||||
ASN1_VALUE **pseqval;
|
||||
seqtt = asn1_do_adb(pval, tt, 0);
|
||||
if (seqtt == NULL)
|
||||
continue;
|
||||
seqtt = asn1_do_adb(pval, tt, 1);
|
||||
pseqval = asn1_get_field_ptr(pval, seqtt);
|
||||
ASN1_template_free(pseqval, seqtt);
|
||||
}
|
||||
@@ -426,7 +410,7 @@ static int asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in,
|
||||
const ASN1_TEMPLATE *seqtt;
|
||||
ASN1_VALUE **pseqval;
|
||||
seqtt = asn1_do_adb(pval, tt, 1);
|
||||
if (seqtt == NULL)
|
||||
if (!seqtt)
|
||||
goto err;
|
||||
pseqval = asn1_get_field_ptr(pval, seqtt);
|
||||
/* Have we ran out of data? */
|
||||
@@ -457,8 +441,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;
|
||||
@@ -492,7 +475,7 @@ static int asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in,
|
||||
for (; i < it->tcount; tt++, i++) {
|
||||
const ASN1_TEMPLATE *seqtt;
|
||||
seqtt = asn1_do_adb(pval, tt, 1);
|
||||
if (seqtt == NULL)
|
||||
if (!seqtt)
|
||||
goto err;
|
||||
if (seqtt->flags & ASN1_TFLG_OPTIONAL) {
|
||||
ASN1_VALUE **pseqval;
|
||||
@@ -528,13 +511,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 +519,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 +553,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 +576,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 +589,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,14 +658,13 @@ 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;
|
||||
}
|
||||
len -= p - q;
|
||||
if (!sk_ASN1_VALUE_push((STACK_OF(ASN1_VALUE) *)*val, skfield)) {
|
||||
ASN1_item_ex_free(&skfield, ASN1_ITEM_ptr(tt->item));
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
@@ -700,8 +675,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 +685,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;
|
||||
@@ -919,7 +894,9 @@ int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
|
||||
break;
|
||||
|
||||
case V_ASN1_INTEGER:
|
||||
case V_ASN1_NEG_INTEGER:
|
||||
case V_ASN1_ENUMERATED:
|
||||
case V_ASN1_NEG_ENUMERATED:
|
||||
tint = (ASN1_INTEGER **)pval;
|
||||
if (!c2i_ASN1_INTEGER(tint, &cont, len))
|
||||
goto err;
|
||||
@@ -1131,7 +1108,7 @@ static int collect_data(BUF_MEM *buf, const unsigned char **p, long plen)
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
OPENSSL_memcpy(buf->data + len, *p, plen);
|
||||
memcpy(buf->data + len, *p, plen);
|
||||
}
|
||||
*p += plen;
|
||||
return 1;
|
||||
|
||||
+21
-26
@@ -56,15 +56,11 @@
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/asn1t.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out,
|
||||
const ASN1_ITEM *it, int tag, int aclass);
|
||||
static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out,
|
||||
@@ -192,7 +188,7 @@ int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
|
||||
/* Use indefinite length constructed if requested */
|
||||
if (aclass & ASN1_TFLG_NDEF)
|
||||
ndef = 2;
|
||||
OPENSSL_FALLTHROUGH;
|
||||
/* fall through */
|
||||
|
||||
case ASN1_ITYPE_SEQUENCE:
|
||||
i = asn1_enc_restore(&seqcontlen, out, pval, it);
|
||||
@@ -217,19 +213,17 @@ int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
|
||||
for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) {
|
||||
const ASN1_TEMPLATE *seqtt;
|
||||
ASN1_VALUE **pseqval;
|
||||
int tmplen;
|
||||
seqtt = asn1_do_adb(pval, tt, 1);
|
||||
if (!seqtt)
|
||||
return 0;
|
||||
pseqval = asn1_get_field_ptr(pval, seqtt);
|
||||
tmplen = asn1_template_ex_i2d(pseqval, NULL, seqtt, -1, aclass);
|
||||
if (tmplen == -1 || (tmplen > INT_MAX - seqcontlen))
|
||||
return -1;
|
||||
seqcontlen += tmplen;
|
||||
/* FIXME: check for errors in enhanced version */
|
||||
seqcontlen += asn1_template_ex_i2d(pseqval, NULL, seqtt,
|
||||
-1, aclass);
|
||||
}
|
||||
|
||||
seqlen = ASN1_object_size(ndef, seqcontlen, tag);
|
||||
if (!out || seqlen == -1)
|
||||
if (!out)
|
||||
return seqlen;
|
||||
/* Output SEQUENCE header */
|
||||
ASN1_put_object(out, ndef, seqcontlen, tag, aclass);
|
||||
@@ -256,6 +250,12 @@ int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ASN1_template_i2d(ASN1_VALUE **pval, unsigned char **out,
|
||||
const ASN1_TEMPLATE *tt)
|
||||
{
|
||||
return asn1_template_ex_i2d(pval, out, tt, -1, 0);
|
||||
}
|
||||
|
||||
static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
|
||||
const ASN1_TEMPLATE *tt, int tag, int iclass)
|
||||
{
|
||||
@@ -337,24 +337,19 @@ static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
|
||||
/* Determine total length of items */
|
||||
skcontlen = 0;
|
||||
for (j = 0; j < sk_ASN1_VALUE_num(sk); j++) {
|
||||
int tmplen;
|
||||
skitem = sk_ASN1_VALUE_value(sk, j);
|
||||
tmplen = ASN1_item_ex_i2d(&skitem, NULL, ASN1_ITEM_ptr(tt->item),
|
||||
-1, iclass);
|
||||
if (tmplen == -1 || (skcontlen > INT_MAX - tmplen))
|
||||
return -1;
|
||||
skcontlen += tmplen;
|
||||
skcontlen += ASN1_item_ex_i2d(&skitem, NULL,
|
||||
ASN1_ITEM_ptr(tt->item),
|
||||
-1, iclass);
|
||||
}
|
||||
sklen = ASN1_object_size(ndef, skcontlen, sktag);
|
||||
if (sklen == -1)
|
||||
return -1;
|
||||
/* If EXPLICIT need length of surrounding tag */
|
||||
if (flags & ASN1_TFLG_EXPTAG)
|
||||
ret = ASN1_object_size(ndef, sklen, ttag);
|
||||
else
|
||||
ret = sklen;
|
||||
|
||||
if (!out || ret == -1)
|
||||
if (!out)
|
||||
return ret;
|
||||
|
||||
/* Now encode this lot... */
|
||||
@@ -383,7 +378,7 @@ static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
|
||||
return 0;
|
||||
/* Find length of EXPLICIT tag */
|
||||
ret = ASN1_object_size(ndef, i, ttag);
|
||||
if (out && ret != -1) {
|
||||
if (out) {
|
||||
/* Output tag and item */
|
||||
ASN1_put_object(out, ndef, i, ttag, tclass);
|
||||
ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), -1, iclass);
|
||||
@@ -412,7 +407,7 @@ static int der_cmp(const void *a, const void *b)
|
||||
const DER_ENC *d1 = a, *d2 = b;
|
||||
int cmplen, i;
|
||||
cmplen = (d1->length < d2->length) ? d1->length : d2->length;
|
||||
i = OPENSSL_memcmp(d1->data, d2->data, cmplen);
|
||||
i = memcmp(d1->data, d2->data, cmplen);
|
||||
if (i)
|
||||
return i;
|
||||
return d1->length - d2->length;
|
||||
@@ -467,7 +462,7 @@ static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out,
|
||||
/* Output sorted DER encoding */
|
||||
p = *out;
|
||||
for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) {
|
||||
OPENSSL_memcpy(p, tder->data, tder->length);
|
||||
memcpy(p, tder->data, tder->length);
|
||||
p += tder->length;
|
||||
}
|
||||
*out = p;
|
||||
@@ -583,8 +578,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:
|
||||
@@ -616,7 +609,9 @@ int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype,
|
||||
break;
|
||||
|
||||
case V_ASN1_INTEGER:
|
||||
case V_ASN1_NEG_INTEGER:
|
||||
case V_ASN1_ENUMERATED:
|
||||
case V_ASN1_NEG_ENUMERATED:
|
||||
/*
|
||||
* These are all have the same content format as ASN1_INTEGER
|
||||
*/
|
||||
@@ -659,6 +654,6 @@ int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype,
|
||||
|
||||
}
|
||||
if (cout && len)
|
||||
OPENSSL_memcpy(cout, cont, len);
|
||||
memcpy(cout, cont, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
+7
-13
@@ -63,10 +63,6 @@
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/obj.h>
|
||||
|
||||
#include "asn1_locl.h"
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it,
|
||||
int combine);
|
||||
static void asn1_item_clear(ASN1_VALUE **pval, const ASN1_ITEM *it);
|
||||
@@ -157,11 +153,11 @@ static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it,
|
||||
*pval = OPENSSL_malloc(it->size);
|
||||
if (!*pval)
|
||||
goto memerr;
|
||||
OPENSSL_memset(*pval, 0, it->size);
|
||||
memset(*pval, 0, it->size);
|
||||
}
|
||||
asn1_set_choice_selector(pval, -1, it);
|
||||
if (asn1_cb && !asn1_cb(ASN1_OP_NEW_POST, pval, it, NULL))
|
||||
goto auxerr2;
|
||||
goto auxerr;
|
||||
break;
|
||||
|
||||
case ASN1_ITYPE_NDEF_SEQUENCE:
|
||||
@@ -182,17 +178,17 @@ static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it,
|
||||
*pval = OPENSSL_malloc(it->size);
|
||||
if (!*pval)
|
||||
goto memerr;
|
||||
OPENSSL_memset(*pval, 0, it->size);
|
||||
memset(*pval, 0, it->size);
|
||||
asn1_refcount_set_one(pval, it);
|
||||
asn1_enc_init(pval, it);
|
||||
}
|
||||
for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) {
|
||||
pseqval = asn1_get_field_ptr(pval, tt);
|
||||
if (!ASN1_template_new(pseqval, tt))
|
||||
goto memerr2;
|
||||
goto memerr;
|
||||
}
|
||||
if (asn1_cb && !asn1_cb(ASN1_OP_NEW_POST, pval, it, NULL))
|
||||
goto auxerr2;
|
||||
goto auxerr;
|
||||
break;
|
||||
}
|
||||
#ifdef CRYPTO_MDEBUG
|
||||
@@ -201,20 +197,18 @@ static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it,
|
||||
#endif
|
||||
return 1;
|
||||
|
||||
memerr2:
|
||||
asn1_item_combine_free(pval, it, combine);
|
||||
memerr:
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
ASN1_item_ex_free(pval, it);
|
||||
#ifdef CRYPTO_MDEBUG
|
||||
if (it->sname)
|
||||
CRYPTO_pop_info();
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
auxerr2:
|
||||
asn1_item_combine_free(pval, it, combine);
|
||||
auxerr:
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_AUX_ERROR);
|
||||
ASN1_item_ex_free(pval, it);
|
||||
#ifdef CRYPTO_MDEBUG
|
||||
if (it->sname)
|
||||
CRYPTO_pop_info();
|
||||
|
||||
@@ -0,0 +1,596 @@
|
||||
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* This package is an SSL implementation written
|
||||
* by Eric Young (eay@cryptsoft.com).
|
||||
* The implementation was written so as to conform with Netscapes SSL.
|
||||
*
|
||||
* This library is free for commercial and non-commercial use as long as
|
||||
* the following conditions are aheared to. The following conditions
|
||||
* apply to all code found in this distribution, be it the RC4, RSA,
|
||||
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
|
||||
* included with this distribution is covered by the same copyright terms
|
||||
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||
*
|
||||
* Copyright remains Eric Young's, and as such any Copyright notices in
|
||||
* the code are not to be removed.
|
||||
* If this package is used in a product, Eric Young should be given attribution
|
||||
* as the author of the parts of the library used.
|
||||
* This can be in the form of a textual message at program startup or
|
||||
* in documentation (online or textual) provided with the package.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* "This product includes cryptographic software written by
|
||||
* Eric Young (eay@cryptsoft.com)"
|
||||
* The word 'cryptographic' can be left out if the rouines from the library
|
||||
* being used are not cryptographic related :-).
|
||||
* 4. If you include any Windows specific code (or a derivative thereof) from
|
||||
* the apps directory (application code) you must include an acknowledgement:
|
||||
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* The licence and distribution terms for any publically available version or
|
||||
* derivative of this code cannot be changed. i.e. this code cannot simply be
|
||||
* copied and put under another distribution licence
|
||||
* [including the GNU Public Licence.] */
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include <openssl/asn1t.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/obj.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "asn1_locl.h"
|
||||
|
||||
/*
|
||||
* Print routines.
|
||||
*/
|
||||
|
||||
/* ASN1_PCTX routines */
|
||||
|
||||
static ASN1_PCTX default_pctx = {
|
||||
ASN1_PCTX_FLAGS_SHOW_ABSENT, /* flags */
|
||||
0, /* nm_flags */
|
||||
0, /* cert_flags */
|
||||
0, /* oid_flags */
|
||||
0 /* str_flags */
|
||||
};
|
||||
|
||||
ASN1_PCTX *ASN1_PCTX_new(void)
|
||||
{
|
||||
ASN1_PCTX *ret;
|
||||
ret = OPENSSL_malloc(sizeof(ASN1_PCTX));
|
||||
if (ret == NULL) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
return NULL;
|
||||
}
|
||||
ret->flags = 0;
|
||||
ret->nm_flags = 0;
|
||||
ret->cert_flags = 0;
|
||||
ret->oid_flags = 0;
|
||||
ret->str_flags = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ASN1_PCTX_free(ASN1_PCTX *p)
|
||||
{
|
||||
OPENSSL_free(p);
|
||||
}
|
||||
|
||||
unsigned long ASN1_PCTX_get_flags(ASN1_PCTX *p)
|
||||
{
|
||||
return p->flags;
|
||||
}
|
||||
|
||||
void ASN1_PCTX_set_flags(ASN1_PCTX *p, unsigned long flags)
|
||||
{
|
||||
p->flags = flags;
|
||||
}
|
||||
|
||||
unsigned long ASN1_PCTX_get_nm_flags(ASN1_PCTX *p)
|
||||
{
|
||||
return p->nm_flags;
|
||||
}
|
||||
|
||||
void ASN1_PCTX_set_nm_flags(ASN1_PCTX *p, unsigned long flags)
|
||||
{
|
||||
p->nm_flags = flags;
|
||||
}
|
||||
|
||||
unsigned long ASN1_PCTX_get_cert_flags(ASN1_PCTX *p)
|
||||
{
|
||||
return p->cert_flags;
|
||||
}
|
||||
|
||||
void ASN1_PCTX_set_cert_flags(ASN1_PCTX *p, unsigned long flags)
|
||||
{
|
||||
p->cert_flags = flags;
|
||||
}
|
||||
|
||||
unsigned long ASN1_PCTX_get_oid_flags(ASN1_PCTX *p)
|
||||
{
|
||||
return p->oid_flags;
|
||||
}
|
||||
|
||||
void ASN1_PCTX_set_oid_flags(ASN1_PCTX *p, unsigned long flags)
|
||||
{
|
||||
p->oid_flags = flags;
|
||||
}
|
||||
|
||||
unsigned long ASN1_PCTX_get_str_flags(ASN1_PCTX *p)
|
||||
{
|
||||
return p->str_flags;
|
||||
}
|
||||
|
||||
void ASN1_PCTX_set_str_flags(ASN1_PCTX *p, unsigned long flags)
|
||||
{
|
||||
p->str_flags = flags;
|
||||
}
|
||||
|
||||
/* Main print routines */
|
||||
|
||||
static int asn1_item_print_ctx(BIO *out, ASN1_VALUE **fld, int indent,
|
||||
const ASN1_ITEM *it,
|
||||
const char *fname, const char *sname,
|
||||
int nohdr, const ASN1_PCTX *pctx);
|
||||
|
||||
int asn1_template_print_ctx(BIO *out, ASN1_VALUE **fld, int indent,
|
||||
const ASN1_TEMPLATE *tt, const ASN1_PCTX *pctx);
|
||||
|
||||
static int asn1_primitive_print(BIO *out, ASN1_VALUE **fld,
|
||||
const ASN1_ITEM *it, int indent,
|
||||
const char *fname, const char *sname,
|
||||
const ASN1_PCTX *pctx);
|
||||
|
||||
static int asn1_print_fsname(BIO *out, int indent,
|
||||
const char *fname, const char *sname,
|
||||
const ASN1_PCTX *pctx);
|
||||
|
||||
int ASN1_item_print(BIO *out, ASN1_VALUE *ifld, int indent,
|
||||
const ASN1_ITEM *it, const ASN1_PCTX *pctx)
|
||||
{
|
||||
const char *sname;
|
||||
if (pctx == NULL)
|
||||
pctx = &default_pctx;
|
||||
if (pctx->flags & ASN1_PCTX_FLAGS_NO_STRUCT_NAME)
|
||||
sname = NULL;
|
||||
else
|
||||
sname = it->sname;
|
||||
return asn1_item_print_ctx(out, &ifld, indent, it, NULL, sname, 0, pctx);
|
||||
}
|
||||
|
||||
static int asn1_item_print_ctx(BIO *out, ASN1_VALUE **fld, int indent,
|
||||
const ASN1_ITEM *it,
|
||||
const char *fname, const char *sname,
|
||||
int nohdr, const ASN1_PCTX *pctx)
|
||||
{
|
||||
const ASN1_TEMPLATE *tt;
|
||||
const ASN1_EXTERN_FUNCS *ef;
|
||||
ASN1_VALUE **tmpfld;
|
||||
const ASN1_AUX *aux = it->funcs;
|
||||
ASN1_aux_cb *asn1_cb;
|
||||
ASN1_PRINT_ARG parg;
|
||||
int i;
|
||||
if (aux && aux->asn1_cb) {
|
||||
parg.out = out;
|
||||
parg.indent = indent;
|
||||
parg.pctx = pctx;
|
||||
asn1_cb = aux->asn1_cb;
|
||||
} else
|
||||
asn1_cb = 0;
|
||||
|
||||
if (*fld == NULL) {
|
||||
if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_ABSENT) {
|
||||
if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx))
|
||||
return 0;
|
||||
if (BIO_puts(out, "<ABSENT>\n") <= 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (it->itype) {
|
||||
case ASN1_ITYPE_PRIMITIVE:
|
||||
if (it->templates) {
|
||||
if (!asn1_template_print_ctx(out, fld, indent,
|
||||
it->templates, pctx))
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
/* fall thru */
|
||||
case ASN1_ITYPE_MSTRING:
|
||||
if (!asn1_primitive_print(out, fld, it, indent, fname, sname, pctx))
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case ASN1_ITYPE_EXTERN:
|
||||
if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx))
|
||||
return 0;
|
||||
/* Use new style print routine if possible */
|
||||
ef = it->funcs;
|
||||
if (ef && ef->asn1_ex_print) {
|
||||
i = ef->asn1_ex_print(out, fld, indent, "", pctx);
|
||||
if (!i)
|
||||
return 0;
|
||||
if ((i == 2) && (BIO_puts(out, "\n") <= 0))
|
||||
return 0;
|
||||
return 1;
|
||||
} else if (sname &&
|
||||
BIO_printf(out, ":EXTERNAL TYPE %s\n", sname) <= 0)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case ASN1_ITYPE_CHOICE:
|
||||
#if 0
|
||||
if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx))
|
||||
return 0;
|
||||
#endif
|
||||
/* CHOICE type, get selector */
|
||||
i = asn1_get_choice_selector(fld, it);
|
||||
/* This should never happen... */
|
||||
if ((i < 0) || (i >= it->tcount)) {
|
||||
if (BIO_printf(out, "ERROR: selector [%d] invalid\n", i) <= 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
tt = it->templates + i;
|
||||
tmpfld = asn1_get_field_ptr(fld, tt);
|
||||
if (!asn1_template_print_ctx(out, tmpfld, indent, tt, pctx))
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case ASN1_ITYPE_SEQUENCE:
|
||||
case ASN1_ITYPE_NDEF_SEQUENCE:
|
||||
if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx))
|
||||
return 0;
|
||||
if (fname || sname) {
|
||||
if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE) {
|
||||
if (BIO_puts(out, " {\n") <= 0)
|
||||
return 0;
|
||||
} else {
|
||||
if (BIO_puts(out, "\n") <= 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (asn1_cb) {
|
||||
i = asn1_cb(ASN1_OP_PRINT_PRE, fld, it, &parg);
|
||||
if (i == 0)
|
||||
return 0;
|
||||
if (i == 2)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Print each field entry */
|
||||
for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) {
|
||||
const ASN1_TEMPLATE *seqtt;
|
||||
seqtt = asn1_do_adb(fld, tt, 1);
|
||||
if (!seqtt)
|
||||
return 0;
|
||||
tmpfld = asn1_get_field_ptr(fld, seqtt);
|
||||
if (!asn1_template_print_ctx(out, tmpfld,
|
||||
indent + 2, seqtt, pctx))
|
||||
return 0;
|
||||
}
|
||||
if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE) {
|
||||
if (BIO_printf(out, "%*s}\n", indent, "") < 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (asn1_cb) {
|
||||
i = asn1_cb(ASN1_OP_PRINT_POST, fld, it, &parg);
|
||||
if (i == 0)
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
BIO_printf(out, "Unprocessed type %d\n", it->itype);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int asn1_template_print_ctx(BIO *out, ASN1_VALUE **fld, int indent,
|
||||
const ASN1_TEMPLATE *tt, const ASN1_PCTX *pctx)
|
||||
{
|
||||
int flags;
|
||||
size_t i;
|
||||
const char *sname, *fname;
|
||||
flags = tt->flags;
|
||||
if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_FIELD_STRUCT_NAME)
|
||||
sname = ASN1_ITEM_ptr(tt->item)->sname;
|
||||
else
|
||||
sname = NULL;
|
||||
if (pctx->flags & ASN1_PCTX_FLAGS_NO_FIELD_NAME)
|
||||
fname = NULL;
|
||||
else
|
||||
fname = tt->field_name;
|
||||
if (flags & ASN1_TFLG_SK_MASK) {
|
||||
const char *tname;
|
||||
ASN1_VALUE *skitem;
|
||||
STACK_OF(ASN1_VALUE) *stack;
|
||||
|
||||
/* SET OF, SEQUENCE OF */
|
||||
if (fname) {
|
||||
if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SSOF) {
|
||||
if (flags & ASN1_TFLG_SET_OF)
|
||||
tname = "SET";
|
||||
else
|
||||
tname = "SEQUENCE";
|
||||
if (BIO_printf(out, "%*s%s OF %s {\n",
|
||||
indent, "", tname, tt->field_name) <= 0)
|
||||
return 0;
|
||||
} else if (BIO_printf(out, "%*s%s:\n", indent, "", fname) <= 0)
|
||||
return 0;
|
||||
}
|
||||
stack = (STACK_OF(ASN1_VALUE) *)*fld;
|
||||
for (i = 0; i < sk_ASN1_VALUE_num(stack); i++) {
|
||||
if ((i > 0) && (BIO_puts(out, "\n") <= 0))
|
||||
return 0;
|
||||
|
||||
skitem = sk_ASN1_VALUE_value(stack, i);
|
||||
if (!asn1_item_print_ctx(out, &skitem, indent + 2,
|
||||
ASN1_ITEM_ptr(tt->item), NULL, NULL, 1,
|
||||
pctx))
|
||||
return 0;
|
||||
}
|
||||
if (!i && BIO_printf(out, "%*s<EMPTY>\n", indent + 2, "") <= 0)
|
||||
return 0;
|
||||
if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE) {
|
||||
if (BIO_printf(out, "%*s}\n", indent, "") <= 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return asn1_item_print_ctx(out, fld, indent, ASN1_ITEM_ptr(tt->item),
|
||||
fname, sname, 0, pctx);
|
||||
}
|
||||
|
||||
static int asn1_print_fsname(BIO *out, int indent,
|
||||
const char *fname, const char *sname,
|
||||
const ASN1_PCTX *pctx)
|
||||
{
|
||||
static char spaces[] = " ";
|
||||
const int nspaces = sizeof(spaces) - 1;
|
||||
|
||||
#if 0
|
||||
if (!sname && !fname)
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
while (indent > nspaces) {
|
||||
if (BIO_write(out, spaces, nspaces) != nspaces)
|
||||
return 0;
|
||||
indent -= nspaces;
|
||||
}
|
||||
if (BIO_write(out, spaces, indent) != indent)
|
||||
return 0;
|
||||
if (pctx->flags & ASN1_PCTX_FLAGS_NO_STRUCT_NAME)
|
||||
sname = NULL;
|
||||
if (pctx->flags & ASN1_PCTX_FLAGS_NO_FIELD_NAME)
|
||||
fname = NULL;
|
||||
if (!sname && !fname)
|
||||
return 1;
|
||||
if (fname) {
|
||||
if (BIO_puts(out, fname) <= 0)
|
||||
return 0;
|
||||
}
|
||||
if (sname) {
|
||||
if (fname) {
|
||||
if (BIO_printf(out, " (%s)", sname) <= 0)
|
||||
return 0;
|
||||
} else {
|
||||
if (BIO_puts(out, sname) <= 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (BIO_write(out, ": ", 2) != 2)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int asn1_print_boolean_ctx(BIO *out, int boolval,
|
||||
const ASN1_PCTX *pctx)
|
||||
{
|
||||
const char *str;
|
||||
switch (boolval) {
|
||||
case -1:
|
||||
str = "BOOL ABSENT";
|
||||
break;
|
||||
|
||||
case 0:
|
||||
str = "FALSE";
|
||||
break;
|
||||
|
||||
default:
|
||||
str = "TRUE";
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (BIO_puts(out, str) <= 0)
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
static int asn1_print_integer_ctx(BIO *out, ASN1_INTEGER *str,
|
||||
const ASN1_PCTX *pctx)
|
||||
{
|
||||
BIGNUM *bn = NULL;
|
||||
char *s = NULL;
|
||||
int ret = 1;
|
||||
|
||||
bn = ASN1_INTEGER_to_BN(str, NULL);
|
||||
if (bn == NULL) {
|
||||
return 0;
|
||||
}
|
||||
s = BN_bn2dec(bn);
|
||||
BN_free(bn);
|
||||
if (s == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (BIO_puts(out, s) <= 0) {
|
||||
ret = 0;
|
||||
}
|
||||
OPENSSL_free(s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int asn1_print_oid_ctx(BIO *out, const ASN1_OBJECT *oid,
|
||||
const ASN1_PCTX *pctx)
|
||||
{
|
||||
char objbuf[80];
|
||||
const char *ln;
|
||||
ln = OBJ_nid2ln(OBJ_obj2nid(oid));
|
||||
if (!ln)
|
||||
ln = "";
|
||||
OBJ_obj2txt(objbuf, sizeof objbuf, oid, 1);
|
||||
if (BIO_printf(out, "%s (%s)", ln, objbuf) <= 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int asn1_print_obstring_ctx(BIO *out, ASN1_STRING *str, int indent,
|
||||
const ASN1_PCTX *pctx)
|
||||
{
|
||||
if (str->type == V_ASN1_BIT_STRING) {
|
||||
if (BIO_printf(out, " (%ld unused bits)\n", str->flags & 0x7) <= 0)
|
||||
return 0;
|
||||
} else if (BIO_puts(out, "\n") <= 0)
|
||||
return 0;
|
||||
if (str->length > 0
|
||||
&& !BIO_hexdump(out, str->data, str->length, indent + 2)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int asn1_primitive_print(BIO *out, ASN1_VALUE **fld,
|
||||
const ASN1_ITEM *it, int indent,
|
||||
const char *fname, const char *sname,
|
||||
const ASN1_PCTX *pctx)
|
||||
{
|
||||
long utype;
|
||||
ASN1_STRING *str;
|
||||
int ret = 1, needlf = 1;
|
||||
const char *pname;
|
||||
const ASN1_PRIMITIVE_FUNCS *pf;
|
||||
pf = it->funcs;
|
||||
if (!asn1_print_fsname(out, indent, fname, sname, pctx))
|
||||
return 0;
|
||||
if (pf && pf->prim_print)
|
||||
return pf->prim_print(out, fld, it, indent, pctx);
|
||||
str = (ASN1_STRING *)*fld;
|
||||
if (it->itype == ASN1_ITYPE_MSTRING)
|
||||
utype = str->type & ~V_ASN1_NEG;
|
||||
else
|
||||
utype = it->utype;
|
||||
if (utype == V_ASN1_ANY) {
|
||||
ASN1_TYPE *atype = (ASN1_TYPE *)*fld;
|
||||
utype = atype->type;
|
||||
fld = &atype->value.asn1_value;
|
||||
str = (ASN1_STRING *)*fld;
|
||||
if (pctx->flags & ASN1_PCTX_FLAGS_NO_ANY_TYPE)
|
||||
pname = NULL;
|
||||
else
|
||||
pname = ASN1_tag2str(utype);
|
||||
} else {
|
||||
if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_TYPE)
|
||||
pname = ASN1_tag2str(utype);
|
||||
else
|
||||
pname = NULL;
|
||||
}
|
||||
|
||||
if (utype == V_ASN1_NULL) {
|
||||
if (BIO_puts(out, "NULL\n") <= 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (pname) {
|
||||
if (BIO_puts(out, pname) <= 0)
|
||||
return 0;
|
||||
if (BIO_puts(out, ":") <= 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (utype) {
|
||||
case V_ASN1_BOOLEAN:
|
||||
{
|
||||
int boolval = *(int *)fld;
|
||||
if (boolval == -1)
|
||||
boolval = it->size;
|
||||
ret = asn1_print_boolean_ctx(out, boolval, pctx);
|
||||
}
|
||||
break;
|
||||
|
||||
case V_ASN1_INTEGER:
|
||||
case V_ASN1_ENUMERATED:
|
||||
ret = asn1_print_integer_ctx(out, str, pctx);
|
||||
break;
|
||||
|
||||
case V_ASN1_UTCTIME:
|
||||
ret = ASN1_UTCTIME_print(out, str);
|
||||
break;
|
||||
|
||||
case V_ASN1_GENERALIZEDTIME:
|
||||
ret = ASN1_GENERALIZEDTIME_print(out, str);
|
||||
break;
|
||||
|
||||
case V_ASN1_OBJECT:
|
||||
ret = asn1_print_oid_ctx(out, (const ASN1_OBJECT *)*fld, pctx);
|
||||
break;
|
||||
|
||||
case V_ASN1_OCTET_STRING:
|
||||
case V_ASN1_BIT_STRING:
|
||||
ret = asn1_print_obstring_ctx(out, str, indent, pctx);
|
||||
needlf = 0;
|
||||
break;
|
||||
|
||||
case V_ASN1_SEQUENCE:
|
||||
case V_ASN1_SET:
|
||||
case V_ASN1_OTHER:
|
||||
if (BIO_puts(out, "\n") <= 0)
|
||||
return 0;
|
||||
if (ASN1_parse_dump(out, str->data, str->length, indent, 0) <= 0)
|
||||
ret = 0;
|
||||
needlf = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = ASN1_STRING_print_ex(out, str, pctx->str_flags);
|
||||
|
||||
}
|
||||
if (!ret)
|
||||
return 0;
|
||||
if (needlf && BIO_puts(out, "\n") <= 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
+40
-27
@@ -87,45 +87,58 @@ IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_VISIBLESTRING)
|
||||
IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_UNIVERSALSTRING)
|
||||
IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_BMPSTRING)
|
||||
|
||||
IMPLEMENT_ASN1_TYPE(ASN1_NULL)
|
||||
IMPLEMENT_ASN1_FUNCTIONS(ASN1_NULL)
|
||||
IMPLEMENT_ASN1_TYPE(ASN1_NULL);
|
||||
IMPLEMENT_ASN1_FUNCTIONS(ASN1_NULL);
|
||||
|
||||
IMPLEMENT_ASN1_TYPE(ASN1_OBJECT)
|
||||
IMPLEMENT_ASN1_TYPE(ASN1_OBJECT);
|
||||
|
||||
IMPLEMENT_ASN1_TYPE(ASN1_ANY)
|
||||
IMPLEMENT_ASN1_TYPE(ASN1_ANY);
|
||||
|
||||
/* Just swallow an ASN1_SEQUENCE in an ASN1_STRING */
|
||||
IMPLEMENT_ASN1_TYPE(ASN1_SEQUENCE)
|
||||
/*
|
||||
* Just swallow an ASN1_SEQUENCE in an ASN1_STRING
|
||||
*/ ;
|
||||
IMPLEMENT_ASN1_TYPE(ASN1_SEQUENCE);
|
||||
|
||||
IMPLEMENT_ASN1_FUNCTIONS_fname(ASN1_TYPE, ASN1_ANY, ASN1_TYPE)
|
||||
IMPLEMENT_ASN1_FUNCTIONS_fname(ASN1_TYPE, ASN1_ANY, ASN1_TYPE);
|
||||
|
||||
/* Multistring types */
|
||||
/*
|
||||
* Multistring types
|
||||
*/ ;
|
||||
|
||||
IMPLEMENT_ASN1_MSTRING(ASN1_PRINTABLE, B_ASN1_PRINTABLE)
|
||||
IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, ASN1_PRINTABLE)
|
||||
IMPLEMENT_ASN1_MSTRING(ASN1_PRINTABLE, B_ASN1_PRINTABLE);
|
||||
IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, ASN1_PRINTABLE);
|
||||
|
||||
IMPLEMENT_ASN1_MSTRING(DISPLAYTEXT, B_ASN1_DISPLAYTEXT)
|
||||
IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, DISPLAYTEXT)
|
||||
IMPLEMENT_ASN1_MSTRING(DISPLAYTEXT, B_ASN1_DISPLAYTEXT);
|
||||
IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, DISPLAYTEXT);
|
||||
|
||||
IMPLEMENT_ASN1_MSTRING(DIRECTORYSTRING, B_ASN1_DIRECTORYSTRING)
|
||||
IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, DIRECTORYSTRING)
|
||||
IMPLEMENT_ASN1_MSTRING(DIRECTORYSTRING, B_ASN1_DIRECTORYSTRING);
|
||||
IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, DIRECTORYSTRING);
|
||||
|
||||
/* Three separate BOOLEAN type: normal, DEFAULT TRUE and DEFAULT FALSE */
|
||||
IMPLEMENT_ASN1_TYPE_ex(ASN1_BOOLEAN, ASN1_BOOLEAN, -1)
|
||||
IMPLEMENT_ASN1_TYPE_ex(ASN1_TBOOLEAN, ASN1_BOOLEAN, 1)
|
||||
IMPLEMENT_ASN1_TYPE_ex(ASN1_FBOOLEAN, ASN1_BOOLEAN, 0)
|
||||
/*
|
||||
* Three separate BOOLEAN type: normal, DEFAULT TRUE and DEFAULT FALSE
|
||||
*/ ;
|
||||
IMPLEMENT_ASN1_TYPE_ex(ASN1_BOOLEAN, ASN1_BOOLEAN, -1);
|
||||
IMPLEMENT_ASN1_TYPE_ex(ASN1_TBOOLEAN, ASN1_BOOLEAN, 1);
|
||||
IMPLEMENT_ASN1_TYPE_ex(ASN1_FBOOLEAN, ASN1_BOOLEAN, 0);
|
||||
|
||||
/* Special, OCTET STRING with indefinite length constructed support */
|
||||
/*
|
||||
* Special, OCTET STRING with indefinite length constructed support
|
||||
*/ ;
|
||||
|
||||
IMPLEMENT_ASN1_TYPE_ex(ASN1_OCTET_STRING_NDEF, ASN1_OCTET_STRING, ASN1_TFLG_NDEF)
|
||||
IMPLEMENT_ASN1_TYPE_ex(ASN1_OCTET_STRING_NDEF, ASN1_OCTET_STRING,
|
||||
ASN1_TFLG_NDEF);
|
||||
|
||||
ASN1_ITEM_TEMPLATE(ASN1_SEQUENCE_ANY) =
|
||||
ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, ASN1_SEQUENCE_ANY, ASN1_ANY)
|
||||
ASN1_ITEM_TEMPLATE_END(ASN1_SEQUENCE_ANY)
|
||||
ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, ASN1_SEQUENCE_ANY,
|
||||
ASN1_ANY);
|
||||
ASN1_ITEM_TEMPLATE_END(ASN1_SEQUENCE_ANY);
|
||||
|
||||
ASN1_ITEM_TEMPLATE(ASN1_SET_ANY) =
|
||||
ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_OF, 0, ASN1_SET_ANY, ASN1_ANY)
|
||||
ASN1_ITEM_TEMPLATE_END(ASN1_SET_ANY)
|
||||
ASN1_ITEM_TEMPLATE(ASN1_SET_ANY) = ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_OF, 0,
|
||||
ASN1_SET_ANY,
|
||||
ASN1_ANY);
|
||||
ASN1_ITEM_TEMPLATE_END(ASN1_SET_ANY);
|
||||
|
||||
IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(ASN1_SEQUENCE_ANY, ASN1_SEQUENCE_ANY, ASN1_SEQUENCE_ANY)
|
||||
IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(ASN1_SEQUENCE_ANY, ASN1_SET_ANY, ASN1_SET_ANY)
|
||||
IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(ASN1_SEQUENCE_ANY,
|
||||
ASN1_SEQUENCE_ANY, ASN1_SEQUENCE_ANY);
|
||||
IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(ASN1_SEQUENCE_ANY, ASN1_SET_ANY,
|
||||
ASN1_SET_ANY);
|
||||
|
||||
+9
-23
@@ -56,7 +56,6 @@
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/asn1t.h>
|
||||
@@ -71,7 +70,7 @@
|
||||
/* Utility functions for manipulating fields and offsets */
|
||||
|
||||
/* Add 'offset' to 'addr' */
|
||||
#define offset2ptr(addr, offset) (void *)(((char *)(addr)) + (offset))
|
||||
#define offset2ptr(addr, offset) (void *)(((char *) addr) + offset)
|
||||
|
||||
/* Given an ASN1_ITEM CHOICE type return the selector value */
|
||||
int asn1_get_choice_selector(ASN1_VALUE **pval, const ASN1_ITEM *it) {
|
||||
@@ -135,8 +134,6 @@ void asn1_enc_init(ASN1_VALUE **pval, const ASN1_ITEM *it) {
|
||||
if (enc) {
|
||||
enc->enc = NULL;
|
||||
enc->len = 0;
|
||||
enc->alias_only = 0;
|
||||
enc->alias_only_on_next_parse = 0;
|
||||
enc->modified = 1;
|
||||
}
|
||||
}
|
||||
@@ -145,13 +142,11 @@ void asn1_enc_free(ASN1_VALUE **pval, const ASN1_ITEM *it) {
|
||||
ASN1_ENCODING *enc;
|
||||
enc = asn1_get_enc_ptr(pval, it);
|
||||
if (enc) {
|
||||
if (enc->enc && !enc->alias_only) {
|
||||
if (enc->enc) {
|
||||
OPENSSL_free(enc->enc);
|
||||
}
|
||||
enc->enc = NULL;
|
||||
enc->len = 0;
|
||||
enc->alias_only = 0;
|
||||
enc->alias_only_on_next_parse = 0;
|
||||
enc->modified = 1;
|
||||
}
|
||||
}
|
||||
@@ -164,23 +159,14 @@ int asn1_enc_save(ASN1_VALUE **pval, const unsigned char *in, int inlen,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!enc->alias_only) {
|
||||
if (enc->enc) {
|
||||
OPENSSL_free(enc->enc);
|
||||
}
|
||||
|
||||
enc->alias_only = enc->alias_only_on_next_parse;
|
||||
enc->alias_only_on_next_parse = 0;
|
||||
|
||||
if (enc->alias_only) {
|
||||
enc->enc = (uint8_t *) in;
|
||||
} else {
|
||||
enc->enc = OPENSSL_malloc(inlen);
|
||||
if (!enc->enc) {
|
||||
return 0;
|
||||
}
|
||||
OPENSSL_memcpy(enc->enc, in, inlen);
|
||||
enc->enc = OPENSSL_malloc(inlen);
|
||||
if (!enc->enc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(enc->enc, in, inlen);
|
||||
enc->len = inlen;
|
||||
enc->modified = 0;
|
||||
|
||||
@@ -195,7 +181,7 @@ int asn1_enc_restore(int *len, unsigned char **out, ASN1_VALUE **pval,
|
||||
return 0;
|
||||
}
|
||||
if (out) {
|
||||
OPENSSL_memcpy(*out, enc->enc, enc->len);
|
||||
memcpy(*out, enc->enc, enc->len);
|
||||
*out += enc->len;
|
||||
}
|
||||
if (len) {
|
||||
@@ -236,7 +222,7 @@ const ASN1_TEMPLATE *asn1_do_adb(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt,
|
||||
sfld = offset2ptr(*pval, adb->offset);
|
||||
|
||||
/* Check if NULL */
|
||||
if (*sfld == NULL) {
|
||||
if (!sfld) {
|
||||
if (!adb->null_tt) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* This package is an SSL implementation written
|
||||
* by Eric Young (eay@cryptsoft.com).
|
||||
* The implementation was written so as to conform with Netscapes SSL.
|
||||
*
|
||||
* This library is free for commercial and non-commercial use as long as
|
||||
* the following conditions are aheared to. The following conditions
|
||||
* apply to all code found in this distribution, be it the RC4, RSA,
|
||||
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
|
||||
* included with this distribution is covered by the same copyright terms
|
||||
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||
*
|
||||
* Copyright remains Eric Young's, and as such any Copyright notices in
|
||||
* the code are not to be removed.
|
||||
* If this package is used in a product, Eric Young should be given attribution
|
||||
* as the author of the parts of the library used.
|
||||
* This can be in the form of a textual message at program startup or
|
||||
* in documentation (online or textual) provided with the package.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* "This product includes cryptographic software written by
|
||||
* Eric Young (eay@cryptsoft.com)"
|
||||
* The word 'cryptographic' can be left out if the rouines from the library
|
||||
* being used are not cryptographic related :-).
|
||||
* 4. If you include any Windows specific code (or a derivative thereof) from
|
||||
* the apps directory (application code) you must include an acknowledgement:
|
||||
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* The licence and distribution terms for any publically available version or
|
||||
* derivative of this code cannot be changed. i.e. this code cannot simply be
|
||||
* copied and put under another distribution licence
|
||||
* [including the GNU Public Licence.] */
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <openssl/asn1t.h>
|
||||
#include <openssl/bn.h>
|
||||
|
||||
/*
|
||||
* Custom primitive type for BIGNUM handling. This reads in an ASN1_INTEGER
|
||||
* as a BIGNUM directly. Currently it ignores the sign which isn't a problem
|
||||
* since all BIGNUMs used are non negative and anything that looks negative
|
||||
* is normally due to an encoding error.
|
||||
*/
|
||||
|
||||
#define BN_SENSITIVE 1
|
||||
|
||||
static int bn_new(ASN1_VALUE **pval, const ASN1_ITEM *it);
|
||||
static void bn_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
|
||||
|
||||
static int bn_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype,
|
||||
const ASN1_ITEM *it);
|
||||
static int bn_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
|
||||
int utype, char *free_cont, const ASN1_ITEM *it);
|
||||
|
||||
static const ASN1_PRIMITIVE_FUNCS bignum_pf = {
|
||||
NULL, 0,
|
||||
bn_new,
|
||||
bn_free,
|
||||
0,
|
||||
bn_c2i,
|
||||
bn_i2c,
|
||||
NULL /* prim_print */ ,
|
||||
};
|
||||
|
||||
ASN1_ITEM_start(BIGNUM)
|
||||
ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &bignum_pf, 0, "BIGNUM"
|
||||
ASN1_ITEM_end(BIGNUM)
|
||||
|
||||
ASN1_ITEM_start(CBIGNUM)
|
||||
ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &bignum_pf, BN_SENSITIVE, "BIGNUM"
|
||||
ASN1_ITEM_end(CBIGNUM)
|
||||
|
||||
static int bn_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
|
||||
{
|
||||
*pval = (ASN1_VALUE *)BN_new();
|
||||
if (*pval)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bn_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
|
||||
{
|
||||
if (!*pval)
|
||||
return;
|
||||
if (it->size & BN_SENSITIVE)
|
||||
BN_clear_free((BIGNUM *)*pval);
|
||||
else
|
||||
BN_free((BIGNUM *)*pval);
|
||||
*pval = NULL;
|
||||
}
|
||||
|
||||
static int bn_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype,
|
||||
const ASN1_ITEM *it)
|
||||
{
|
||||
BIGNUM *bn;
|
||||
int pad;
|
||||
if (!*pval)
|
||||
return -1;
|
||||
bn = (BIGNUM *)*pval;
|
||||
/* If MSB set in an octet we need a padding byte */
|
||||
if (BN_num_bits(bn) & 0x7)
|
||||
pad = 0;
|
||||
else
|
||||
pad = 1;
|
||||
if (cont) {
|
||||
if (pad)
|
||||
*cont++ = 0;
|
||||
BN_bn2bin(bn, cont);
|
||||
}
|
||||
return pad + BN_num_bytes(bn);
|
||||
}
|
||||
|
||||
static int bn_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
|
||||
int utype, char *free_cont, const ASN1_ITEM *it)
|
||||
{
|
||||
BIGNUM *bn;
|
||||
if (!*pval) {
|
||||
if (!bn_new(pval, it)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
bn = (BIGNUM *)*pval;
|
||||
if (!BN_bin2bn(cont, len, bn)) {
|
||||
bn_free(pval, it);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* This package is an SSL implementation written
|
||||
* by Eric Young (eay@cryptsoft.com).
|
||||
* The implementation was written so as to conform with Netscapes SSL.
|
||||
*
|
||||
* This library is free for commercial and non-commercial use as long as
|
||||
* the following conditions are aheared to. The following conditions
|
||||
* apply to all code found in this distribution, be it the RC4, RSA,
|
||||
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
|
||||
* included with this distribution is covered by the same copyright terms
|
||||
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||
*
|
||||
* Copyright remains Eric Young's, and as such any Copyright notices in
|
||||
* the code are not to be removed.
|
||||
* If this package is used in a product, Eric Young should be given attribution
|
||||
* as the author of the parts of the library used.
|
||||
* This can be in the form of a textual message at program startup or
|
||||
* in documentation (online or textual) provided with the package.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* "This product includes cryptographic software written by
|
||||
* Eric Young (eay@cryptsoft.com)"
|
||||
* The word 'cryptographic' can be left out if the rouines from the library
|
||||
* being used are not cryptographic related :-).
|
||||
* 4. If you include any Windows specific code (or a derivative thereof) from
|
||||
* the apps directory (application code) you must include an acknowledgement:
|
||||
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* The licence and distribution terms for any publically available version or
|
||||
* derivative of this code cannot be changed. i.e. this code cannot simply be
|
||||
* copied and put under another distribution licence
|
||||
* [including the GNU Public Licence.] */
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/asn1t.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
/*
|
||||
* Custom primitive type for long handling. This converts between an
|
||||
* ASN1_INTEGER and a long directly.
|
||||
*/
|
||||
|
||||
static int long_new(ASN1_VALUE **pval, const ASN1_ITEM *it);
|
||||
static void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
|
||||
|
||||
static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype,
|
||||
const ASN1_ITEM *it);
|
||||
static int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
|
||||
int utype, char *free_cont, const ASN1_ITEM *it);
|
||||
static int long_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it,
|
||||
int indent, const ASN1_PCTX *pctx);
|
||||
|
||||
static const ASN1_PRIMITIVE_FUNCS long_pf = {
|
||||
NULL, 0,
|
||||
long_new,
|
||||
long_free,
|
||||
long_free, /* Clear should set to initial value */
|
||||
long_c2i,
|
||||
long_i2c,
|
||||
long_print
|
||||
};
|
||||
|
||||
ASN1_ITEM_start(LONG)
|
||||
ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &long_pf, ASN1_LONG_UNDEF, "LONG"
|
||||
ASN1_ITEM_end(LONG)
|
||||
|
||||
ASN1_ITEM_start(ZLONG)
|
||||
ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &long_pf, 0, "ZLONG"
|
||||
ASN1_ITEM_end(ZLONG)
|
||||
|
||||
static int long_new(ASN1_VALUE **pval, const ASN1_ITEM *it)
|
||||
{
|
||||
*(long *)pval = it->size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
|
||||
{
|
||||
*(long *)pval = it->size;
|
||||
}
|
||||
|
||||
static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype,
|
||||
const ASN1_ITEM *it)
|
||||
{
|
||||
long ltmp;
|
||||
unsigned long utmp;
|
||||
int clen, pad, i;
|
||||
/* this exists to bypass broken gcc optimization */
|
||||
char *cp = (char *)pval;
|
||||
|
||||
/* use memcpy, because we may not be long aligned */
|
||||
memcpy(<mp, cp, sizeof(long));
|
||||
|
||||
if (ltmp == it->size)
|
||||
return -1;
|
||||
/*
|
||||
* Convert the long to positive: we subtract one if negative so we can
|
||||
* cleanly handle the padding if only the MSB of the leading octet is
|
||||
* set.
|
||||
*/
|
||||
if (ltmp < 0)
|
||||
utmp = -ltmp - 1;
|
||||
else
|
||||
utmp = ltmp;
|
||||
clen = BN_num_bits_word(utmp);
|
||||
/* If MSB of leading octet set we need to pad */
|
||||
if (!(clen & 0x7))
|
||||
pad = 1;
|
||||
else
|
||||
pad = 0;
|
||||
|
||||
/* Convert number of bits to number of octets */
|
||||
clen = (clen + 7) >> 3;
|
||||
|
||||
if (cont) {
|
||||
if (pad)
|
||||
*cont++ = (ltmp < 0) ? 0xff : 0;
|
||||
for (i = clen - 1; i >= 0; i--) {
|
||||
cont[i] = (unsigned char)(utmp & 0xff);
|
||||
if (ltmp < 0)
|
||||
cont[i] ^= 0xff;
|
||||
utmp >>= 8;
|
||||
}
|
||||
}
|
||||
return clen + pad;
|
||||
}
|
||||
|
||||
static int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
|
||||
int utype, char *free_cont, const ASN1_ITEM *it)
|
||||
{
|
||||
int neg, i;
|
||||
long ltmp;
|
||||
unsigned long utmp = 0;
|
||||
char *cp = (char *)pval;
|
||||
if (len > (int)sizeof(long)) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG);
|
||||
return 0;
|
||||
}
|
||||
/* Is it negative? */
|
||||
if (len && (cont[0] & 0x80))
|
||||
neg = 1;
|
||||
else
|
||||
neg = 0;
|
||||
utmp = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
utmp <<= 8;
|
||||
if (neg)
|
||||
utmp |= cont[i] ^ 0xff;
|
||||
else
|
||||
utmp |= cont[i];
|
||||
}
|
||||
ltmp = (long)utmp;
|
||||
if (neg) {
|
||||
ltmp++;
|
||||
ltmp = -ltmp;
|
||||
}
|
||||
if (ltmp == it->size) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG);
|
||||
return 0;
|
||||
}
|
||||
memcpy(cp, <mp, sizeof(long));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int long_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it,
|
||||
int indent, const ASN1_PCTX *pctx)
|
||||
{
|
||||
return BIO_printf(out, "%ld\n", *(long *)pval);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
include_directories(../../include)
|
||||
|
||||
add_library(
|
||||
base64
|
||||
|
||||
OBJECT
|
||||
|
||||
base64.c
|
||||
)
|
||||
|
||||
add_executable(
|
||||
base64_test
|
||||
|
||||
base64_test.cc
|
||||
|
||||
$<TARGET_OBJECTS:test_support>
|
||||
)
|
||||
|
||||
target_link_libraries(base64_test crypto)
|
||||
add_dependencies(all_tests base64_test)
|
||||
+307
-295
@@ -60,151 +60,118 @@
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/type_check.h>
|
||||
|
||||
#include "../internal.h"
|
||||
static const unsigned char data_bin2ascii[65] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
#define conv_bin2ascii(a) (data_bin2ascii[(a) & 0x3f])
|
||||
|
||||
// constant_time_lt_args_8 behaves like |constant_time_lt_8| but takes |uint8_t|
|
||||
// arguments for a slightly simpler implementation.
|
||||
static inline uint8_t constant_time_lt_args_8(uint8_t a, uint8_t b) {
|
||||
crypto_word_t aw = a;
|
||||
crypto_word_t bw = b;
|
||||
// |crypto_word_t| is larger than |uint8_t|, so |aw| and |bw| have the same
|
||||
// MSB. |aw| < |bw| iff MSB(|aw| - |bw|) is 1.
|
||||
return constant_time_msb_w(aw - bw);
|
||||
}
|
||||
/* 64 char lines
|
||||
* pad input with 0
|
||||
* left over chars are set to =
|
||||
* 1 byte => xx==
|
||||
* 2 bytes => xxx=
|
||||
* 3 bytes => xxxx
|
||||
*/
|
||||
#define BIN_PER_LINE (64/4*3)
|
||||
#define CHUNKS_PER_LINE (64/4)
|
||||
#define CHAR_PER_LINE (64+1)
|
||||
|
||||
// constant_time_in_range_8 returns |CONSTTIME_TRUE_8| if |min| <= |a| <= |max|
|
||||
// and |CONSTTIME_FALSE_8| otherwise.
|
||||
static inline uint8_t constant_time_in_range_8(uint8_t a, uint8_t min,
|
||||
uint8_t max) {
|
||||
a -= min;
|
||||
return constant_time_lt_args_8(a, max - min + 1);
|
||||
}
|
||||
/* 0xF0 is a EOLN
|
||||
* 0xF1 is ignore but next needs to be 0xF0 (for \r\n processing).
|
||||
* 0xF2 is EOF
|
||||
* 0xE0 is ignore at start of line.
|
||||
* 0xFF is error */
|
||||
|
||||
// Encoding.
|
||||
#define B64_EOLN 0xF0
|
||||
#define B64_CR 0xF1
|
||||
#define B64_EOF 0xF2
|
||||
#define B64_WS 0xE0
|
||||
#define B64_ERROR 0xFF
|
||||
#define B64_NOT_BASE64(a) (((a) | 0x13) == 0xF3)
|
||||
|
||||
static uint8_t conv_bin2ascii(uint8_t a) {
|
||||
// Since PEM is sometimes used to carry private keys, we encode base64 data
|
||||
// itself in constant-time.
|
||||
a &= 0x3f;
|
||||
uint8_t ret = constant_time_select_8(constant_time_eq_8(a, 62), '+', '/');
|
||||
ret =
|
||||
constant_time_select_8(constant_time_lt_args_8(a, 62), a - 52 + '0', ret);
|
||||
ret =
|
||||
constant_time_select_8(constant_time_lt_args_8(a, 52), a - 26 + 'a', ret);
|
||||
ret = constant_time_select_8(constant_time_lt_args_8(a, 26), a + 'A', ret);
|
||||
return ret;
|
||||
}
|
||||
static const uint8_t data_ascii2bin[128] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xF0, 0xFF,
|
||||
0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xF2, 0xFF, 0x3F,
|
||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
||||
0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12,
|
||||
0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
|
||||
0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
|
||||
0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
};
|
||||
|
||||
OPENSSL_STATIC_ASSERT(sizeof(((EVP_ENCODE_CTX *)(NULL))->data) % 3 == 0,
|
||||
"data length must be a multiple of base64 chunk size");
|
||||
|
||||
int EVP_EncodedLength(size_t *out_len, size_t len) {
|
||||
if (len + 2 < len) {
|
||||
return 0;
|
||||
static uint8_t conv_ascii2bin(uint8_t a) {
|
||||
if (a >= 128) {
|
||||
return 0xFF;
|
||||
}
|
||||
len += 2;
|
||||
len /= 3;
|
||||
|
||||
if (((len << 2) >> 2) != len) {
|
||||
return 0;
|
||||
}
|
||||
len <<= 2;
|
||||
|
||||
if (len + 1 < len) {
|
||||
return 0;
|
||||
}
|
||||
len++;
|
||||
|
||||
*out_len = len;
|
||||
return 1;
|
||||
return data_ascii2bin[a];
|
||||
}
|
||||
|
||||
void EVP_EncodeInit(EVP_ENCODE_CTX *ctx) {
|
||||
OPENSSL_memset(ctx, 0, sizeof(EVP_ENCODE_CTX));
|
||||
ctx->length = 48;
|
||||
ctx->num = 0;
|
||||
ctx->line_num = 0;
|
||||
}
|
||||
|
||||
void EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len,
|
||||
const uint8_t *in, size_t in_len) {
|
||||
size_t total = 0;
|
||||
unsigned i, j;
|
||||
unsigned total = 0;
|
||||
|
||||
*out_len = 0;
|
||||
if (in_len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(ctx->data_used < sizeof(ctx->data));
|
||||
assert(ctx->length <= sizeof(ctx->enc_data));
|
||||
|
||||
if (sizeof(ctx->data) - ctx->data_used > in_len) {
|
||||
OPENSSL_memcpy(&ctx->data[ctx->data_used], in, in_len);
|
||||
ctx->data_used += (unsigned)in_len;
|
||||
if (ctx->num + in_len < ctx->length) {
|
||||
memcpy(&ctx->enc_data[ctx->num], in, in_len);
|
||||
ctx->num += in_len;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx->data_used != 0) {
|
||||
const size_t todo = sizeof(ctx->data) - ctx->data_used;
|
||||
OPENSSL_memcpy(&ctx->data[ctx->data_used], in, todo);
|
||||
in += todo;
|
||||
in_len -= todo;
|
||||
|
||||
size_t encoded = EVP_EncodeBlock(out, ctx->data, sizeof(ctx->data));
|
||||
ctx->data_used = 0;
|
||||
|
||||
out += encoded;
|
||||
if (ctx->num != 0) {
|
||||
i = ctx->length - ctx->num;
|
||||
memcpy(&ctx->enc_data[ctx->num], in, i);
|
||||
in += i;
|
||||
in_len -= i;
|
||||
j = EVP_EncodeBlock(out, ctx->enc_data, ctx->length);
|
||||
ctx->num = 0;
|
||||
out += j;
|
||||
*(out++) = '\n';
|
||||
*out = '\0';
|
||||
|
||||
total = encoded + 1;
|
||||
total = j + 1;
|
||||
}
|
||||
|
||||
while (in_len >= sizeof(ctx->data)) {
|
||||
size_t encoded = EVP_EncodeBlock(out, in, sizeof(ctx->data));
|
||||
in += sizeof(ctx->data);
|
||||
in_len -= sizeof(ctx->data);
|
||||
|
||||
out += encoded;
|
||||
while (in_len >= ctx->length) {
|
||||
j = EVP_EncodeBlock(out, in, ctx->length);
|
||||
in += ctx->length;
|
||||
in_len -= ctx->length;
|
||||
out += j;
|
||||
*(out++) = '\n';
|
||||
*out = '\0';
|
||||
|
||||
if (total + encoded + 1 < total) {
|
||||
*out_len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
total += encoded + 1;
|
||||
total += j + 1;
|
||||
}
|
||||
|
||||
if (in_len != 0) {
|
||||
OPENSSL_memcpy(ctx->data, in, in_len);
|
||||
memcpy(&ctx->enc_data[0], in, in_len);
|
||||
}
|
||||
|
||||
ctx->data_used = (unsigned)in_len;
|
||||
|
||||
if (total > INT_MAX) {
|
||||
// We cannot signal an error, but we can at least avoid making *out_len
|
||||
// negative.
|
||||
total = 0;
|
||||
}
|
||||
*out_len = (int)total;
|
||||
ctx->num = in_len;
|
||||
*out_len = total;
|
||||
}
|
||||
|
||||
void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len) {
|
||||
if (ctx->data_used == 0) {
|
||||
*out_len = 0;
|
||||
return;
|
||||
unsigned ret = 0;
|
||||
|
||||
if (ctx->num != 0) {
|
||||
ret = EVP_EncodeBlock(out, ctx->enc_data, ctx->num);
|
||||
out[ret++] = '\n';
|
||||
out[ret] = '\0';
|
||||
ctx->num = 0;
|
||||
}
|
||||
|
||||
size_t encoded = EVP_EncodeBlock(out, ctx->data, ctx->data_used);
|
||||
out[encoded++] = '\n';
|
||||
out[encoded] = '\0';
|
||||
ctx->data_used = 0;
|
||||
|
||||
// ctx->data_used is bounded by sizeof(ctx->data), so this does not
|
||||
// overflow.
|
||||
assert(encoded <= INT_MAX);
|
||||
*out_len = (int)encoded;
|
||||
*out_len = ret;
|
||||
}
|
||||
|
||||
size_t EVP_EncodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) {
|
||||
@@ -239,228 +206,273 @@ size_t EVP_EncodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// Decoding.
|
||||
|
||||
int EVP_DecodedLength(size_t *out_len, size_t len) {
|
||||
if (len % 4 != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*out_len = (len / 4) * 3;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void EVP_DecodeInit(EVP_ENCODE_CTX *ctx) {
|
||||
OPENSSL_memset(ctx, 0, sizeof(EVP_ENCODE_CTX));
|
||||
}
|
||||
|
||||
static uint8_t base64_ascii_to_bin(uint8_t a) {
|
||||
// Since PEM is sometimes used to carry private keys, we decode base64 data
|
||||
// itself in constant-time.
|
||||
const uint8_t is_upper = constant_time_in_range_8(a, 'A', 'Z');
|
||||
const uint8_t is_lower = constant_time_in_range_8(a, 'a', 'z');
|
||||
const uint8_t is_digit = constant_time_in_range_8(a, '0', '9');
|
||||
const uint8_t is_plus = constant_time_eq_8(a, '+');
|
||||
const uint8_t is_slash = constant_time_eq_8(a, '/');
|
||||
const uint8_t is_equals = constant_time_eq_8(a, '=');
|
||||
|
||||
uint8_t ret = 0xff; // 0xff signals invalid.
|
||||
ret = constant_time_select_8(is_upper, a - 'A', ret); // [0,26)
|
||||
ret = constant_time_select_8(is_lower, a - 'a' + 26, ret); // [26,52)
|
||||
ret = constant_time_select_8(is_digit, a - '0' + 52, ret); // [52,62)
|
||||
ret = constant_time_select_8(is_plus, 62, ret);
|
||||
ret = constant_time_select_8(is_slash, 63, ret);
|
||||
// Padding maps to zero, to be further handled by the caller.
|
||||
ret = constant_time_select_8(is_equals, 0, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// base64_decode_quad decodes a single “quad” (i.e. four characters) of base64
|
||||
// data and writes up to three bytes to |out|. It sets |*out_num_bytes| to the
|
||||
// number of bytes written, which will be less than three if the quad ended
|
||||
// with padding. It returns one on success or zero on error.
|
||||
static int base64_decode_quad(uint8_t *out, size_t *out_num_bytes,
|
||||
const uint8_t *in) {
|
||||
const uint8_t a = base64_ascii_to_bin(in[0]);
|
||||
const uint8_t b = base64_ascii_to_bin(in[1]);
|
||||
const uint8_t c = base64_ascii_to_bin(in[2]);
|
||||
const uint8_t d = base64_ascii_to_bin(in[3]);
|
||||
if (a == 0xff || b == 0xff || c == 0xff || d == 0xff) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint32_t v = ((uint32_t)a) << 18 | ((uint32_t)b) << 12 |
|
||||
((uint32_t)c) << 6 | (uint32_t)d;
|
||||
|
||||
const unsigned padding_pattern = (in[0] == '=') << 3 |
|
||||
(in[1] == '=') << 2 |
|
||||
(in[2] == '=') << 1 |
|
||||
(in[3] == '=');
|
||||
|
||||
switch (padding_pattern) {
|
||||
case 0:
|
||||
// The common case of no padding.
|
||||
*out_num_bytes = 3;
|
||||
out[0] = v >> 16;
|
||||
out[1] = v >> 8;
|
||||
out[2] = v;
|
||||
break;
|
||||
|
||||
case 1: // xxx=
|
||||
*out_num_bytes = 2;
|
||||
out[0] = v >> 16;
|
||||
out[1] = v >> 8;
|
||||
break;
|
||||
|
||||
case 3: // xx==
|
||||
*out_num_bytes = 1;
|
||||
out[0] = v >> 16;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len,
|
||||
const uint8_t *in, size_t in_len) {
|
||||
*out_len = 0;
|
||||
|
||||
if (ctx->error_encountered) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t bytes_out = 0, i;
|
||||
for (i = 0; i < in_len; i++) {
|
||||
const char c = in[i];
|
||||
switch (c) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ctx->eof_seen) {
|
||||
ctx->error_encountered = 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->data[ctx->data_used++] = c;
|
||||
if (ctx->data_used == 4) {
|
||||
size_t num_bytes_resulting;
|
||||
if (!base64_decode_quad(out, &num_bytes_resulting, ctx->data)) {
|
||||
ctx->error_encountered = 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->data_used = 0;
|
||||
bytes_out += num_bytes_resulting;
|
||||
out += num_bytes_resulting;
|
||||
|
||||
if (num_bytes_resulting < 3) {
|
||||
ctx->eof_seen = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes_out > INT_MAX) {
|
||||
ctx->error_encountered = 1;
|
||||
*out_len = 0;
|
||||
return -1;
|
||||
}
|
||||
*out_len = (int)bytes_out;
|
||||
|
||||
if (ctx->eof_seen) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len) {
|
||||
*out_len = 0;
|
||||
if (ctx->error_encountered || ctx->data_used != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_DecodeBase64(uint8_t *out, size_t *out_len, size_t max_out,
|
||||
const uint8_t *in, size_t in_len) {
|
||||
*out_len = 0;
|
||||
uint8_t a, b, c, d;
|
||||
size_t pad_len = 0, len = 0, max_len, i;
|
||||
uint32_t l;
|
||||
|
||||
if (in_len % 4 != 0) {
|
||||
if (!EVP_DecodedLength(&max_len, in_len) || max_out < max_len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t max_len;
|
||||
if (!EVP_DecodedLength(&max_len, in_len) ||
|
||||
max_out < max_len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t i, bytes_out = 0;
|
||||
for (i = 0; i < in_len; i += 4) {
|
||||
size_t num_bytes_resulting;
|
||||
|
||||
if (!base64_decode_quad(out, &num_bytes_resulting, &in[i])) {
|
||||
a = conv_ascii2bin(*(in++));
|
||||
b = conv_ascii2bin(*(in++));
|
||||
if (i + 4 == in_len && in[1] == '=') {
|
||||
if (in[0] == '=') {
|
||||
pad_len = 2;
|
||||
} else {
|
||||
pad_len = 1;
|
||||
}
|
||||
}
|
||||
if (pad_len < 2) {
|
||||
c = conv_ascii2bin(*(in++));
|
||||
} else {
|
||||
c = 0;
|
||||
}
|
||||
if (pad_len < 1) {
|
||||
d = conv_ascii2bin(*(in++));
|
||||
} else {
|
||||
d = 0;
|
||||
}
|
||||
if ((a & 0x80) || (b & 0x80) || (c & 0x80) || (d & 0x80)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bytes_out += num_bytes_resulting;
|
||||
out += num_bytes_resulting;
|
||||
if (num_bytes_resulting != 3 && i != in_len - 4) {
|
||||
return 0;
|
||||
l = ((((uint32_t)a) << 18L) | (((uint32_t)b) << 12L) |
|
||||
(((uint32_t)c) << 6L) | (((uint32_t)d)));
|
||||
*(out++) = (uint8_t)(l >> 16L) & 0xff;
|
||||
if (pad_len < 2) {
|
||||
*(out++) = (uint8_t)(l >> 8L) & 0xff;
|
||||
}
|
||||
if (pad_len < 1) {
|
||||
*(out++) = (uint8_t)(l) & 0xff;
|
||||
}
|
||||
len += 3 - pad_len;
|
||||
}
|
||||
|
||||
*out_len = bytes_out;
|
||||
*out_len = len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_DecodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) {
|
||||
// Trim spaces and tabs from the beginning of the input.
|
||||
while (src_len > 0) {
|
||||
if (src[0] != ' ' && src[0] != '\t') {
|
||||
break;
|
||||
void EVP_DecodeInit(EVP_ENCODE_CTX *ctx) {
|
||||
ctx->length = 30;
|
||||
ctx->num = 0;
|
||||
ctx->line_num = 0;
|
||||
ctx->expect_nl = 0;
|
||||
}
|
||||
|
||||
int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len,
|
||||
const uint8_t *in, size_t in_len) {
|
||||
int seof = -1, eof = 0, rv = -1, v, tmp, exp_nl;
|
||||
uint8_t *d;
|
||||
unsigned i, n, ln, ret = 0;
|
||||
|
||||
n = ctx->num;
|
||||
d = ctx->enc_data;
|
||||
ln = ctx->line_num;
|
||||
exp_nl = ctx->expect_nl;
|
||||
|
||||
/* last line of input. */
|
||||
if (in_len == 0 || (n == 0 && conv_ascii2bin(in[0]) == B64_EOF)) {
|
||||
rv = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* We parse the input data */
|
||||
for (i = 0; i < in_len; i++) {
|
||||
/* If the current line is > 80 characters, scream alot */
|
||||
if (ln >= 80) {
|
||||
rv = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Get char and put it into the buffer */
|
||||
tmp = *(in++);
|
||||
v = conv_ascii2bin(tmp);
|
||||
/* only save the good data :-) */
|
||||
if (!B64_NOT_BASE64(v)) {
|
||||
assert(n < sizeof(ctx->enc_data));
|
||||
d[n++] = tmp;
|
||||
ln++;
|
||||
} else if (v == B64_ERROR) {
|
||||
rv = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* have we seen a '=' which is 'definitly' the last
|
||||
* input line. seof will point to the character that
|
||||
* holds it. and eof will hold how many characters to
|
||||
* chop off. */
|
||||
if (tmp == '=') {
|
||||
if (seof == -1) {
|
||||
seof = n;
|
||||
}
|
||||
eof++;
|
||||
if (eof > 2) {
|
||||
/* There are, at most, two equals signs at the end of base64 data. */
|
||||
rv = -1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (v == B64_CR) {
|
||||
ln = 0;
|
||||
if (exp_nl) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* eoln */
|
||||
if (v == B64_EOLN) {
|
||||
ln = 0;
|
||||
if (exp_nl) {
|
||||
exp_nl = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
exp_nl = 0;
|
||||
|
||||
/* If we are at the end of input and it looks like a
|
||||
* line, process it. */
|
||||
if ((i + 1) == in_len && (((n & 3) == 0) || eof)) {
|
||||
v = B64_EOF;
|
||||
/* In case things were given us in really small
|
||||
records (so two '=' were given in separate
|
||||
updates), eof may contain the incorrect number
|
||||
of ending bytes to skip, so let's redo the count */
|
||||
eof = 0;
|
||||
if (d[n - 1] == '=') {
|
||||
eof++;
|
||||
}
|
||||
if (d[n - 2] == '=') {
|
||||
eof++;
|
||||
}
|
||||
/* There will never be more than two '=' */
|
||||
}
|
||||
|
||||
if ((v == B64_EOF && (n & 3) == 0) || n >= 64) {
|
||||
/* This is needed to work correctly on 64 byte input
|
||||
* lines. We process the line and then need to
|
||||
* accept the '\n' */
|
||||
if (v != B64_EOF && n >= 64) {
|
||||
exp_nl = 1;
|
||||
}
|
||||
if (n > 0) {
|
||||
/* TODO(davidben): Switch this to EVP_DecodeBase64. */
|
||||
v = EVP_DecodeBlock(out, d, n);
|
||||
n = 0;
|
||||
if (v < 0) {
|
||||
rv = 0;
|
||||
goto end;
|
||||
}
|
||||
if (eof > v) {
|
||||
rv = -1;
|
||||
goto end;
|
||||
}
|
||||
ret += (v - eof);
|
||||
} else {
|
||||
eof = 1;
|
||||
v = 0;
|
||||
}
|
||||
|
||||
/* This is the case where we have had a short
|
||||
* but valid input line */
|
||||
if (v < (int)ctx->length && eof) {
|
||||
rv = 0;
|
||||
goto end;
|
||||
} else {
|
||||
ctx->length = v;
|
||||
}
|
||||
|
||||
if (seof >= 0) {
|
||||
rv = 0;
|
||||
goto end;
|
||||
}
|
||||
out += v;
|
||||
}
|
||||
}
|
||||
rv = 1;
|
||||
|
||||
end:
|
||||
*out_len = ret;
|
||||
ctx->num = n;
|
||||
ctx->line_num = ln;
|
||||
ctx->expect_nl = exp_nl;
|
||||
return rv;
|
||||
}
|
||||
|
||||
int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, int *outl) {
|
||||
int i;
|
||||
|
||||
*outl = 0;
|
||||
if (ctx->num != 0) {
|
||||
/* TODO(davidben): Switch this to EVP_DecodeBase64. */
|
||||
i = EVP_DecodeBlock(out, ctx->enc_data, ctx->num);
|
||||
if (i < 0) {
|
||||
return -1;
|
||||
}
|
||||
ctx->num = 0;
|
||||
*outl = i;
|
||||
return 1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int EVP_DecodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) {
|
||||
size_t dst_len;
|
||||
|
||||
/* trim white space from the start of the line. */
|
||||
while (conv_ascii2bin(*src) == B64_WS && src_len > 0) {
|
||||
src++;
|
||||
src_len--;
|
||||
}
|
||||
|
||||
// Trim newlines, spaces and tabs from the end of the line.
|
||||
while (src_len > 0) {
|
||||
switch (src[src_len-1]) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
src_len--;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
/* strip off stuff at the end of the line
|
||||
* ascii2bin values B64_WS, B64_EOLN, B64_EOLN and B64_EOF */
|
||||
while (src_len > 3 && B64_NOT_BASE64(conv_ascii2bin(src[src_len - 1]))) {
|
||||
src_len--;
|
||||
}
|
||||
|
||||
size_t dst_len;
|
||||
if (!EVP_DecodedLength(&dst_len, src_len) ||
|
||||
dst_len > INT_MAX ||
|
||||
!EVP_DecodeBase64(dst, &dst_len, dst_len, src, src_len)) {
|
||||
if (!EVP_DecodedLength(&dst_len, src_len) || dst_len > INT_MAX) {
|
||||
return -1;
|
||||
}
|
||||
if (!EVP_DecodeBase64(dst, &dst_len, dst_len, src, src_len)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// EVP_DecodeBlock does not take padding into account, so put the
|
||||
// NULs back in... so the caller can strip them back out.
|
||||
/* EVP_DecodeBlock does not take padding into account, so put the
|
||||
* NULs back in... so the caller can strip them back out. */
|
||||
while (dst_len % 3 != 0) {
|
||||
dst[dst_len++] = '\0';
|
||||
}
|
||||
assert(dst_len <= INT_MAX);
|
||||
|
||||
return (int)dst_len;
|
||||
return dst_len;
|
||||
}
|
||||
|
||||
int EVP_EncodedLength(size_t *out_len, size_t len) {
|
||||
if (len + 2 < len) {
|
||||
return 0;
|
||||
}
|
||||
len += 2;
|
||||
len /= 3;
|
||||
if (((len << 2) >> 2) != len) {
|
||||
return 0;
|
||||
}
|
||||
len <<= 2;
|
||||
if (len + 1 < len) {
|
||||
return 0;
|
||||
}
|
||||
len++;
|
||||
*out_len = len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
+87
-267
@@ -15,293 +15,113 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <openssl/base64.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "../internal.h"
|
||||
#include "../test/test_util.h"
|
||||
|
||||
|
||||
enum encoding_relation {
|
||||
// canonical indicates that the encoding is the expected encoding of the
|
||||
// input.
|
||||
canonical,
|
||||
// valid indicates that the encoding is /a/ valid encoding of the input, but
|
||||
// need not be the canonical one.
|
||||
valid,
|
||||
// invalid indicates that the encoded data is valid.
|
||||
invalid,
|
||||
};
|
||||
|
||||
struct Base64TestVector {
|
||||
enum encoding_relation relation;
|
||||
struct TestVector {
|
||||
const char *decoded;
|
||||
const char *encoded;
|
||||
};
|
||||
|
||||
// Test vectors from RFC 4648.
|
||||
static const Base64TestVector kTestVectors[] = {
|
||||
{canonical, "", ""},
|
||||
{canonical, "f", "Zg==\n"},
|
||||
{canonical, "fo", "Zm8=\n"},
|
||||
{canonical, "foo", "Zm9v\n"},
|
||||
{canonical, "foob", "Zm9vYg==\n"},
|
||||
{canonical, "fooba", "Zm9vYmE=\n"},
|
||||
{canonical, "foobar", "Zm9vYmFy\n"},
|
||||
{valid, "foobar", "Zm9vYmFy\n\n"},
|
||||
{valid, "foobar", " Zm9vYmFy\n\n"},
|
||||
{valid, "foobar", " Z m 9 v Y m F y\n\n"},
|
||||
{invalid, "", "Zm9vYmFy=\n"},
|
||||
{invalid, "", "Zm9vYmFy==\n"},
|
||||
{invalid, "", "Zm9vYmFy===\n"},
|
||||
{invalid, "", "Z"},
|
||||
{invalid, "", "Z\n"},
|
||||
{invalid, "", "ab!c"},
|
||||
{invalid, "", "ab=c"},
|
||||
{invalid, "", "abc"},
|
||||
|
||||
{canonical, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
"eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA==\n"},
|
||||
{valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
"eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA\n==\n"},
|
||||
{valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
"eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA=\n=\n"},
|
||||
{invalid, "",
|
||||
"eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA=\n==\n"},
|
||||
{canonical, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
"eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4\neHh4eHh"
|
||||
"4eHh4eHh4\n"},
|
||||
{canonical,
|
||||
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
"eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4\neHh4eHh"
|
||||
"4eHh4eHh4eHh4eA==\n"},
|
||||
{valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
"eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh\n4eHh4eHh"
|
||||
"4eHh4eHh4eHh4eA==\n"},
|
||||
{valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
"eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4e"
|
||||
"Hh4eHh4eHh4eA==\n"},
|
||||
{invalid, "",
|
||||
"eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA=="
|
||||
"\neHh4eHh4eHh4eHh4eHh4eHh4\n"},
|
||||
|
||||
// A '-' has traditionally been treated as the end of the data by OpenSSL
|
||||
// and anything following would be ignored. BoringSSL does not accept this
|
||||
// non-standard extension.
|
||||
{invalid, "", "Zm9vYmFy-anythinggoes"},
|
||||
{invalid, "", "Zm9vYmFy\n-anythinggoes"},
|
||||
|
||||
// CVE-2015-0292
|
||||
{invalid, "",
|
||||
"ZW5jb2RlIG1lCg==========================================================="
|
||||
"=======\n"},
|
||||
static const TestVector kTestVectors[] = {
|
||||
{ "", "" },
|
||||
{ "f" , "Zg==" },
|
||||
{ "fo", "Zm8=" },
|
||||
{ "foo", "Zm9v" },
|
||||
{ "foob", "Zm9vYg==" },
|
||||
{ "fooba", "Zm9vYmE=" },
|
||||
{ "foobar", "Zm9vYmFy" },
|
||||
};
|
||||
|
||||
class Base64Test : public testing::TestWithParam<Base64TestVector> {};
|
||||
static const size_t kNumTests = sizeof(kTestVectors) / sizeof(kTestVectors[0]);
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(All, Base64Test, testing::ValuesIn(kTestVectors));
|
||||
|
||||
// RemoveNewlines returns a copy of |in| with all '\n' characters removed.
|
||||
static std::string RemoveNewlines(const char *in) {
|
||||
std::string ret;
|
||||
const size_t in_len = strlen(in);
|
||||
|
||||
for (size_t i = 0; i < in_len; i++) {
|
||||
if (in[i] != '\n') {
|
||||
ret.push_back(in[i]);
|
||||
static bool TestEncode() {
|
||||
for (size_t i = 0; i < kNumTests; i++) {
|
||||
const TestVector *t = &kTestVectors[i];
|
||||
uint8_t out[9];
|
||||
size_t len = EVP_EncodeBlock(out, (const uint8_t*)t->decoded,
|
||||
strlen(t->decoded));
|
||||
if (len != strlen(t->encoded) ||
|
||||
memcmp(out, t->encoded, len) != 0) {
|
||||
fprintf(stderr, "encode(\"%s\") = \"%.*s\", want \"%s\"\n",
|
||||
t->decoded, (int)len, (const char*)out, t->encoded);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST_P(Base64Test, EncodeBlock) {
|
||||
const Base64TestVector &t = GetParam();
|
||||
if (t.relation != canonical) {
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t decoded_len = strlen(t.decoded);
|
||||
size_t max_encoded_len;
|
||||
ASSERT_TRUE(EVP_EncodedLength(&max_encoded_len, decoded_len));
|
||||
|
||||
std::vector<uint8_t> out_vec(max_encoded_len);
|
||||
uint8_t *out = out_vec.data();
|
||||
size_t len = EVP_EncodeBlock(out, (const uint8_t *)t.decoded, decoded_len);
|
||||
|
||||
std::string encoded(RemoveNewlines(t.encoded));
|
||||
EXPECT_EQ(Bytes(encoded), Bytes(out, len));
|
||||
}
|
||||
|
||||
TEST_P(Base64Test, DecodeBase64) {
|
||||
const Base64TestVector &t = GetParam();
|
||||
if (t.relation == valid) {
|
||||
// The non-canonical encodings will generally have odd whitespace etc
|
||||
// that |EVP_DecodeBase64| will reject.
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string encoded(RemoveNewlines(t.encoded));
|
||||
std::vector<uint8_t> out_vec(encoded.size());
|
||||
uint8_t *out = out_vec.data();
|
||||
|
||||
static bool TestDecode() {
|
||||
uint8_t out[6];
|
||||
size_t len;
|
||||
int ok = EVP_DecodeBase64(out, &len, out_vec.size(),
|
||||
(const uint8_t *)encoded.data(), encoded.size());
|
||||
|
||||
if (t.relation == invalid) {
|
||||
EXPECT_FALSE(ok);
|
||||
} else if (t.relation == canonical) {
|
||||
ASSERT_TRUE(ok);
|
||||
EXPECT_EQ(Bytes(t.decoded), Bytes(out, len));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(Base64Test, DecodeBlock) {
|
||||
const Base64TestVector &t = GetParam();
|
||||
if (t.relation != canonical) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string encoded(RemoveNewlines(t.encoded));
|
||||
|
||||
std::vector<uint8_t> out_vec(encoded.size());
|
||||
uint8_t *out = out_vec.data();
|
||||
|
||||
// Test that the padding behavior of the deprecated API is preserved.
|
||||
int ret =
|
||||
EVP_DecodeBlock(out, (const uint8_t *)encoded.data(), encoded.size());
|
||||
ASSERT_GE(ret, 0);
|
||||
// EVP_DecodeBlock should ignore padding.
|
||||
ASSERT_EQ(0, ret % 3);
|
||||
size_t expected_len = strlen(t.decoded);
|
||||
if (expected_len % 3 != 0) {
|
||||
ret -= 3 - (expected_len % 3);
|
||||
}
|
||||
EXPECT_EQ(Bytes(t.decoded), Bytes(out, static_cast<size_t>(ret)));
|
||||
}
|
||||
|
||||
TEST_P(Base64Test, EncodeDecode) {
|
||||
const Base64TestVector &t = GetParam();
|
||||
|
||||
EVP_ENCODE_CTX ctx;
|
||||
const size_t decoded_len = strlen(t.decoded);
|
||||
|
||||
if (t.relation == canonical) {
|
||||
size_t max_encoded_len;
|
||||
ASSERT_TRUE(EVP_EncodedLength(&max_encoded_len, decoded_len));
|
||||
|
||||
// EVP_EncodeUpdate will output new lines every 64 bytes of output so we
|
||||
// need slightly more than |EVP_EncodedLength| returns. */
|
||||
max_encoded_len += (max_encoded_len + 63) >> 6;
|
||||
std::vector<uint8_t> out_vec(max_encoded_len);
|
||||
uint8_t *out = out_vec.data();
|
||||
|
||||
EVP_EncodeInit(&ctx);
|
||||
|
||||
int out_len;
|
||||
EVP_EncodeUpdate(&ctx, out, &out_len,
|
||||
reinterpret_cast<const uint8_t *>(t.decoded),
|
||||
decoded_len);
|
||||
size_t total = out_len;
|
||||
|
||||
EVP_EncodeFinal(&ctx, out + total, &out_len);
|
||||
total += out_len;
|
||||
|
||||
EXPECT_EQ(Bytes(t.encoded), Bytes(out, total));
|
||||
}
|
||||
|
||||
std::vector<uint8_t> out_vec(strlen(t.encoded));
|
||||
uint8_t *out = out_vec.data();
|
||||
|
||||
EVP_DecodeInit(&ctx);
|
||||
int out_len;
|
||||
size_t total = 0;
|
||||
int ret = EVP_DecodeUpdate(&ctx, out, &out_len,
|
||||
reinterpret_cast<const uint8_t *>(t.encoded),
|
||||
strlen(t.encoded));
|
||||
if (ret != -1) {
|
||||
total = out_len;
|
||||
ret = EVP_DecodeFinal(&ctx, out + total, &out_len);
|
||||
total += out_len;
|
||||
}
|
||||
|
||||
switch (t.relation) {
|
||||
case canonical:
|
||||
case valid:
|
||||
ASSERT_NE(-1, ret);
|
||||
EXPECT_EQ(Bytes(t.decoded), Bytes(out, total));
|
||||
break;
|
||||
|
||||
case invalid:
|
||||
EXPECT_EQ(-1, ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(Base64Test, DecodeUpdateStreaming) {
|
||||
const Base64TestVector &t = GetParam();
|
||||
if (t.relation == invalid) {
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t encoded_len = strlen(t.encoded);
|
||||
|
||||
std::vector<uint8_t> out(encoded_len);
|
||||
|
||||
for (size_t chunk_size = 1; chunk_size <= encoded_len; chunk_size++) {
|
||||
SCOPED_TRACE(chunk_size);
|
||||
size_t out_len = 0;
|
||||
EVP_ENCODE_CTX ctx;
|
||||
EVP_DecodeInit(&ctx);
|
||||
|
||||
for (size_t i = 0; i < encoded_len;) {
|
||||
size_t todo = encoded_len - i;
|
||||
if (todo > chunk_size) {
|
||||
todo = chunk_size;
|
||||
}
|
||||
|
||||
int bytes_written;
|
||||
int ret = EVP_DecodeUpdate(
|
||||
&ctx, out.data() + out_len, &bytes_written,
|
||||
reinterpret_cast<const uint8_t *>(t.encoded + i), todo);
|
||||
i += todo;
|
||||
|
||||
switch (ret) {
|
||||
case -1:
|
||||
FAIL() << "EVP_DecodeUpdate failed";
|
||||
case 0:
|
||||
out_len += bytes_written;
|
||||
if (i == encoded_len ||
|
||||
(i + 1 == encoded_len && t.encoded[i] == '\n') ||
|
||||
// If there was an '-' in the input (which means “EOF”) then
|
||||
// this loop will continue to test that |EVP_DecodeUpdate| will
|
||||
// ignore the remainder of the input.
|
||||
strchr(t.encoded, '-') != nullptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
FAIL()
|
||||
<< "EVP_DecodeUpdate returned zero before end of encoded data.";
|
||||
case 1:
|
||||
out_len += bytes_written;
|
||||
break;
|
||||
default:
|
||||
FAIL() << "Invalid return value " << ret;
|
||||
}
|
||||
for (size_t i = 0; i < kNumTests; i++) {
|
||||
// Test the normal API.
|
||||
const TestVector *t = &kTestVectors[i];
|
||||
size_t expected_len = strlen(t->decoded);
|
||||
if (!EVP_DecodeBase64(out, &len, sizeof(out),
|
||||
(const uint8_t*)t->encoded, strlen(t->encoded))) {
|
||||
fprintf(stderr, "decode(\"%s\") failed\n", t->encoded);
|
||||
return false;
|
||||
}
|
||||
if (len != strlen(t->decoded) ||
|
||||
memcmp(out, t->decoded, len) != 0) {
|
||||
fprintf(stderr, "decode(\"%s\") = \"%.*s\", want \"%s\"\n",
|
||||
t->encoded, (int)len, (const char*)out, t->decoded);
|
||||
return false;
|
||||
}
|
||||
|
||||
int bytes_written;
|
||||
int ret = EVP_DecodeFinal(&ctx, out.data() + out_len, &bytes_written);
|
||||
ASSERT_NE(ret, -1);
|
||||
out_len += bytes_written;
|
||||
|
||||
EXPECT_EQ(Bytes(t.decoded), Bytes(out.data(), out_len));
|
||||
// Test that the padding behavior of the deprecated API is preserved.
|
||||
int ret = EVP_DecodeBlock(out, (const uint8_t*)t->encoded,
|
||||
strlen(t->encoded));
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "decode(\"%s\") failed\n", t->encoded);
|
||||
return false;
|
||||
}
|
||||
if (ret % 3 != 0) {
|
||||
fprintf(stderr, "EVP_DecodeBlock did not ignore padding\n");
|
||||
return false;
|
||||
}
|
||||
if (expected_len % 3 != 0) {
|
||||
ret -= 3 - (expected_len % 3);
|
||||
}
|
||||
if (static_cast<size_t>(ret) != strlen(t->decoded) ||
|
||||
memcmp(out, t->decoded, ret) != 0) {
|
||||
fprintf(stderr, "decode(\"%s\") = \"%.*s\", want \"%s\"\n",
|
||||
t->encoded, ret, (const char*)out, t->decoded);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (EVP_DecodeBase64(out, &len, sizeof(out), (const uint8_t*)"a!bc", 4)) {
|
||||
fprintf(stderr, "Failed to reject invalid characters in the middle.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (EVP_DecodeBase64(out, &len, sizeof(out), (const uint8_t*)"a=bc", 4)) {
|
||||
fprintf(stderr, "Failed to reject invalid characters in the middle.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (EVP_DecodeBase64(out, &len, sizeof(out), (const uint8_t*)"abc", 4)) {
|
||||
fprintf(stderr, "Failed to reject invalid input length.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
CRYPTO_library_init();
|
||||
|
||||
if (!TestEncode() ||
|
||||
!TestDecode()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("PASS\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
include_directories(../../include)
|
||||
|
||||
add_library(
|
||||
bio
|
||||
|
||||
OBJECT
|
||||
|
||||
bio.c
|
||||
bio_mem.c
|
||||
buffer.c
|
||||
connect.c
|
||||
fd.c
|
||||
file.c
|
||||
hexdump.c
|
||||
pair.c
|
||||
printf.c
|
||||
socket.c
|
||||
socket_helper.c
|
||||
)
|
||||
|
||||
add_executable(
|
||||
bio_test
|
||||
|
||||
bio_test.cc
|
||||
|
||||
$<TARGET_OBJECTS:test_support>
|
||||
)
|
||||
|
||||
target_link_libraries(bio_test crypto)
|
||||
if (WIN32)
|
||||
target_link_libraries(bio_test ws2_32)
|
||||
endif()
|
||||
add_dependencies(all_tests bio_test)
|
||||
+151
-243
@@ -61,7 +61,6 @@
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/thread.h>
|
||||
@@ -69,6 +68,25 @@
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
/* BIO_set initialises a BIO structure to have the given type and sets the
|
||||
* reference count to one. It returns one on success or zero on error. */
|
||||
static int bio_set(BIO *bio, const BIO_METHOD *method) {
|
||||
/* This function can be called with a stack allocated |BIO| so we have to
|
||||
* assume that the contents of |BIO| are arbitary. This also means that it'll
|
||||
* leak memory if you call |BIO_set| twice on the same BIO. */
|
||||
memset(bio, 0, sizeof(BIO));
|
||||
|
||||
bio->method = method;
|
||||
bio->shutdown = 1;
|
||||
bio->references = 1;
|
||||
|
||||
if (method->create != NULL && !method->create(bio)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
BIO *BIO_new(const BIO_METHOD *method) {
|
||||
BIO *ret = OPENSSL_malloc(sizeof(BIO));
|
||||
if (ret == NULL) {
|
||||
@@ -76,14 +94,9 @@ BIO *BIO_new(const BIO_METHOD *method) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
OPENSSL_memset(ret, 0, sizeof(BIO));
|
||||
ret->method = method;
|
||||
ret->shutdown = 1;
|
||||
ret->references = 1;
|
||||
|
||||
if (method->create != NULL && !method->create(ret)) {
|
||||
if (!bio_set(ret, method)) {
|
||||
OPENSSL_free(ret);
|
||||
return NULL;
|
||||
ret = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -97,6 +110,13 @@ int BIO_free(BIO *bio) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bio->callback != NULL) {
|
||||
int i = (int)bio->callback(bio, BIO_CB_FREE, NULL, 0, 0, 1);
|
||||
if (i <= 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
next_bio = BIO_pop(bio);
|
||||
|
||||
if (bio->method != NULL && bio->method->destroy != NULL) {
|
||||
@@ -108,9 +128,9 @@ int BIO_free(BIO *bio) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BIO_up_ref(BIO *bio) {
|
||||
BIO *BIO_up_ref(BIO *bio) {
|
||||
CRYPTO_refcount_inc(&bio->references);
|
||||
return 1;
|
||||
return bio;
|
||||
}
|
||||
|
||||
void BIO_vfree(BIO *bio) {
|
||||
@@ -121,74 +141,64 @@ void BIO_free_all(BIO *bio) {
|
||||
BIO_free(bio);
|
||||
}
|
||||
|
||||
int BIO_read(BIO *bio, void *buf, int len) {
|
||||
if (bio == NULL || bio->method == NULL || bio->method->bread == NULL) {
|
||||
static int bio_io(BIO *bio, void *buf, int len, size_t method_offset,
|
||||
int callback_flags, size_t *num) {
|
||||
int i;
|
||||
typedef int (*io_func_t)(BIO *, char *, int);
|
||||
io_func_t io_func = NULL;
|
||||
|
||||
if (bio != NULL && bio->method != NULL) {
|
||||
io_func =
|
||||
*((const io_func_t *)(((const uint8_t *)bio->method) + method_offset));
|
||||
}
|
||||
|
||||
if (io_func == NULL) {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (bio->callback != NULL) {
|
||||
i = (int) bio->callback(bio, callback_flags, buf, len, 0L, 1L);
|
||||
if (i <= 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bio->init) {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED);
|
||||
return -2;
|
||||
}
|
||||
if (len <= 0) {
|
||||
return 0;
|
||||
|
||||
i = 0;
|
||||
if (buf != NULL && len > 0) {
|
||||
i = io_func(bio, buf, len);
|
||||
}
|
||||
int ret = bio->method->bread(bio, buf, len);
|
||||
if (ret > 0) {
|
||||
bio->num_read += ret;
|
||||
|
||||
if (i > 0) {
|
||||
*num += i;
|
||||
}
|
||||
return ret;
|
||||
|
||||
if (bio->callback != NULL) {
|
||||
i = (int)(bio->callback(bio, callback_flags | BIO_CB_RETURN, buf, len, 0L,
|
||||
(long)i));
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int BIO_read(BIO *bio, void *buf, int len) {
|
||||
return bio_io(bio, buf, len, offsetof(BIO_METHOD, bread), BIO_CB_READ,
|
||||
&bio->num_read);
|
||||
}
|
||||
|
||||
int BIO_gets(BIO *bio, char *buf, int len) {
|
||||
if (bio == NULL || bio->method == NULL || bio->method->bgets == NULL) {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
|
||||
return -2;
|
||||
}
|
||||
if (!bio->init) {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED);
|
||||
return -2;
|
||||
}
|
||||
if (len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
int ret = bio->method->bgets(bio, buf, len);
|
||||
if (ret > 0) {
|
||||
bio->num_read += ret;
|
||||
}
|
||||
return ret;
|
||||
return bio_io(bio, buf, len, offsetof(BIO_METHOD, bgets), BIO_CB_GETS,
|
||||
&bio->num_read);
|
||||
}
|
||||
|
||||
int BIO_write(BIO *bio, const void *in, int inl) {
|
||||
if (bio == NULL || bio->method == NULL || bio->method->bwrite == NULL) {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
|
||||
return -2;
|
||||
}
|
||||
if (!bio->init) {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED);
|
||||
return -2;
|
||||
}
|
||||
if (inl <= 0) {
|
||||
return 0;
|
||||
}
|
||||
int ret = bio->method->bwrite(bio, in, inl);
|
||||
if (ret > 0) {
|
||||
bio->num_write += ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int BIO_write_all(BIO *bio, const void *data, size_t len) {
|
||||
const uint8_t *data_u8 = data;
|
||||
while (len > 0) {
|
||||
int ret = BIO_write(bio, data_u8, len > INT_MAX ? INT_MAX : (int)len);
|
||||
if (ret <= 0) {
|
||||
return 0;
|
||||
}
|
||||
data_u8 += ret;
|
||||
len -= ret;
|
||||
}
|
||||
return 1;
|
||||
return bio_io(bio, (char *)in, inl, offsetof(BIO_METHOD, bwrite),
|
||||
BIO_CB_WRITE, &bio->num_write);
|
||||
}
|
||||
|
||||
int BIO_puts(BIO *bio, const char *in) {
|
||||
@@ -200,6 +210,8 @@ int BIO_flush(BIO *bio) {
|
||||
}
|
||||
|
||||
long BIO_ctrl(BIO *bio, int cmd, long larg, void *parg) {
|
||||
long ret;
|
||||
|
||||
if (bio == NULL) {
|
||||
return 0;
|
||||
}
|
||||
@@ -209,7 +221,20 @@ long BIO_ctrl(BIO *bio, int cmd, long larg, void *parg) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
return bio->method->ctrl(bio, cmd, larg, parg);
|
||||
if (bio->callback != NULL) {
|
||||
ret = bio->callback(bio, BIO_CB_CTRL, parg, cmd, larg, 1);
|
||||
if (ret <= 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = bio->method->ctrl(bio, cmd, larg, parg);
|
||||
|
||||
if (bio->callback != NULL) {
|
||||
ret = bio->callback(bio, BIO_CB_CTRL | BIO_CB_RETURN, parg, cmd, larg, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *BIO_ptr_ctrl(BIO *b, int cmd, long larg) {
|
||||
@@ -232,10 +257,6 @@ int BIO_reset(BIO *bio) {
|
||||
return BIO_ctrl(bio, BIO_CTRL_RESET, 0, NULL);
|
||||
}
|
||||
|
||||
int BIO_eof(BIO *bio) {
|
||||
return BIO_ctrl(bio, BIO_CTRL_EOF, 0, NULL);
|
||||
}
|
||||
|
||||
void BIO_set_flags(BIO *bio, int flags) {
|
||||
bio->flags |= flags;
|
||||
}
|
||||
@@ -294,6 +315,9 @@ void BIO_copy_next_retry(BIO *bio) {
|
||||
}
|
||||
|
||||
long BIO_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) {
|
||||
long ret;
|
||||
bio_info_cb cb;
|
||||
|
||||
if (bio == NULL) {
|
||||
return 0;
|
||||
}
|
||||
@@ -303,17 +327,26 @@ long BIO_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return bio->method->callback_ctrl(bio, cmd, fp);
|
||||
cb = bio->callback;
|
||||
|
||||
if (cb != NULL) {
|
||||
ret = cb(bio, BIO_CB_CTRL, (void *)&fp, cmd, 0, 1L);
|
||||
if (ret <= 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = bio->method->callback_ctrl(bio, cmd, fp);
|
||||
|
||||
if (cb != NULL) {
|
||||
ret = cb(bio, BIO_CB_CTRL | BIO_CB_RETURN, (void *)&fp, cmd, 0, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t BIO_pending(const BIO *bio) {
|
||||
const long r = BIO_ctrl((BIO *) bio, BIO_CTRL_PENDING, 0, NULL);
|
||||
assert(r >= 0);
|
||||
|
||||
if (r < 0) {
|
||||
return 0;
|
||||
}
|
||||
return r;
|
||||
return BIO_ctrl((BIO *) bio, BIO_CTRL_PENDING, 0, NULL);
|
||||
}
|
||||
|
||||
size_t BIO_ctrl_pending(const BIO *bio) {
|
||||
@@ -321,19 +354,25 @@ size_t BIO_ctrl_pending(const BIO *bio) {
|
||||
}
|
||||
|
||||
size_t BIO_wpending(const BIO *bio) {
|
||||
const long r = BIO_ctrl((BIO *) bio, BIO_CTRL_WPENDING, 0, NULL);
|
||||
assert(r >= 0);
|
||||
|
||||
if (r < 0) {
|
||||
return 0;
|
||||
}
|
||||
return r;
|
||||
return BIO_ctrl((BIO *) bio, BIO_CTRL_WPENDING, 0, NULL);
|
||||
}
|
||||
|
||||
int BIO_set_close(BIO *bio, int close_flag) {
|
||||
return BIO_ctrl(bio, BIO_CTRL_SET_CLOSE, close_flag, NULL);
|
||||
}
|
||||
|
||||
void BIO_set_callback(BIO *bio, bio_info_cb callback_func) {
|
||||
bio->callback = callback_func;
|
||||
}
|
||||
|
||||
void BIO_set_callback_arg(BIO *bio, char *arg) {
|
||||
bio->cb_arg = arg;
|
||||
}
|
||||
|
||||
char *BIO_get_callback_arg(const BIO *bio) {
|
||||
return bio->cb_arg;
|
||||
}
|
||||
|
||||
OPENSSL_EXPORT size_t BIO_number_read(const BIO *bio) {
|
||||
return bio->num_read;
|
||||
}
|
||||
@@ -419,18 +458,22 @@ static int print_bio(const char *str, size_t len, void *bio) {
|
||||
return BIO_write((BIO *)bio, str, len);
|
||||
}
|
||||
|
||||
void ERR_print_errors(BIO *bio) {
|
||||
void BIO_print_errors(BIO *bio) {
|
||||
ERR_print_errors_cb(print_bio, bio);
|
||||
}
|
||||
|
||||
// bio_read_all reads everything from |bio| and prepends |prefix| to it. On
|
||||
// success, |*out| is set to an allocated buffer (which should be freed with
|
||||
// |OPENSSL_free|), |*out_len| is set to its length and one is returned. The
|
||||
// buffer will contain |prefix| followed by the contents of |bio|. On failure,
|
||||
// zero is returned.
|
||||
//
|
||||
// The function will fail if the size of the output would equal or exceed
|
||||
// |max_len|.
|
||||
void ERR_print_errors(BIO *bio) {
|
||||
BIO_print_errors(bio);
|
||||
}
|
||||
|
||||
/* bio_read_all reads everything from |bio| and prepends |prefix| to it. On
|
||||
* success, |*out| is set to an allocated buffer (which should be freed with
|
||||
* |OPENSSL_free|), |*out_len| is set to its length and one is returned. The
|
||||
* buffer will contain |prefix| followed by the contents of |bio|. On failure,
|
||||
* zero is returned.
|
||||
*
|
||||
* The function will fail if the size of the output would equal or exceed
|
||||
* |max_len|. */
|
||||
static int bio_read_all(BIO *bio, uint8_t **out, size_t *out_len,
|
||||
const uint8_t *prefix, size_t prefix_len,
|
||||
size_t max_len) {
|
||||
@@ -447,7 +490,7 @@ static int bio_read_all(BIO *bio, uint8_t **out, size_t *out_len,
|
||||
if (*out == NULL) {
|
||||
return 0;
|
||||
}
|
||||
OPENSSL_memcpy(*out, prefix, prefix_len);
|
||||
memcpy(*out, prefix, prefix_len);
|
||||
size_t done = prefix_len;
|
||||
|
||||
for (;;) {
|
||||
@@ -482,52 +525,11 @@ static int bio_read_all(BIO *bio, uint8_t **out, size_t *out_len,
|
||||
}
|
||||
}
|
||||
|
||||
// bio_read_full reads |len| bytes |bio| and writes them into |out|. It
|
||||
// tolerates partial reads from |bio| and returns one on success or zero if a
|
||||
// read fails before |len| bytes are read. On failure, it additionally sets
|
||||
// |*out_eof_on_first_read| to whether the error was due to |bio| returning zero
|
||||
// on the first read. |out_eof_on_first_read| may be NULL to discard the value.
|
||||
static int bio_read_full(BIO *bio, uint8_t *out, int *out_eof_on_first_read,
|
||||
size_t len) {
|
||||
int first_read = 1;
|
||||
while (len > 0) {
|
||||
int todo = len <= INT_MAX ? (int)len : INT_MAX;
|
||||
int ret = BIO_read(bio, out, todo);
|
||||
if (ret <= 0) {
|
||||
if (out_eof_on_first_read != NULL) {
|
||||
*out_eof_on_first_read = first_read && ret == 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
out += ret;
|
||||
len -= (size_t)ret;
|
||||
first_read = 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// For compatibility with existing |d2i_*_bio| callers, |BIO_read_asn1| uses
|
||||
// |ERR_LIB_ASN1| errors.
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, ASN1_R_DECODE_ERROR)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, ASN1_R_HEADER_TOO_LONG)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, ASN1_R_NOT_ENOUGH_DATA)
|
||||
OPENSSL_DECLARE_ERROR_REASON(ASN1, ASN1_R_TOO_LONG)
|
||||
|
||||
int BIO_read_asn1(BIO *bio, uint8_t **out, size_t *out_len, size_t max_len) {
|
||||
uint8_t header[6];
|
||||
|
||||
static const size_t kInitialHeaderLen = 2;
|
||||
int eof_on_first_read;
|
||||
if (!bio_read_full(bio, header, &eof_on_first_read, kInitialHeaderLen)) {
|
||||
if (eof_on_first_read) {
|
||||
// Historically, OpenSSL returned |ASN1_R_HEADER_TOO_LONG| when
|
||||
// |d2i_*_bio| could not read anything. CPython conditions on this to
|
||||
// determine if |bio| was empty.
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_HEADER_TOO_LONG);
|
||||
} else {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ENOUGH_DATA);
|
||||
}
|
||||
if (BIO_read(bio, header, kInitialHeaderLen) != (int) kInitialHeaderLen) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -535,55 +537,48 @@ int BIO_read_asn1(BIO *bio, uint8_t **out, size_t *out_len, size_t max_len) {
|
||||
const uint8_t length_byte = header[1];
|
||||
|
||||
if ((tag & 0x1f) == 0x1f) {
|
||||
// Long form tags are not supported.
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
|
||||
/* Long form tags are not supported. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t len, header_len;
|
||||
if ((length_byte & 0x80) == 0) {
|
||||
// Short form length.
|
||||
/* Short form length. */
|
||||
len = length_byte;
|
||||
header_len = kInitialHeaderLen;
|
||||
} else {
|
||||
const size_t num_bytes = length_byte & 0x7f;
|
||||
|
||||
if ((tag & 0x20 /* constructed */) != 0 && num_bytes == 0) {
|
||||
// indefinite length.
|
||||
if (!bio_read_all(bio, out, out_len, header, kInitialHeaderLen,
|
||||
max_len)) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ENOUGH_DATA);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
/* indefinite length. */
|
||||
return bio_read_all(bio, out, out_len, header, kInitialHeaderLen,
|
||||
max_len);
|
||||
}
|
||||
|
||||
if (num_bytes == 0 || num_bytes > 4) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!bio_read_full(bio, header + kInitialHeaderLen, NULL, num_bytes)) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ENOUGH_DATA);
|
||||
if (BIO_read(bio, header + kInitialHeaderLen, num_bytes) !=
|
||||
(int)num_bytes) {
|
||||
return 0;
|
||||
}
|
||||
header_len = kInitialHeaderLen + num_bytes;
|
||||
|
||||
uint32_t len32 = 0;
|
||||
for (unsigned i = 0; i < num_bytes; i++) {
|
||||
unsigned i;
|
||||
for (i = 0; i < num_bytes; i++) {
|
||||
len32 <<= 8;
|
||||
len32 |= header[kInitialHeaderLen + i];
|
||||
}
|
||||
|
||||
if (len32 < 128) {
|
||||
// Length should have used short-form encoding.
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
|
||||
/* Length should have used short-form encoding. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((len32 >> ((num_bytes-1)*8)) == 0) {
|
||||
// Length should have been at least one byte shorter.
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
|
||||
/* Length should have been at least one byte shorter. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -593,7 +588,6 @@ int BIO_read_asn1(BIO *bio, uint8_t **out, size_t *out_len, size_t max_len) {
|
||||
if (len + header_len < len ||
|
||||
len + header_len > max_len ||
|
||||
len > INT_MAX) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG);
|
||||
return 0;
|
||||
}
|
||||
len += header_len;
|
||||
@@ -601,100 +595,14 @@ int BIO_read_asn1(BIO *bio, uint8_t **out, size_t *out_len, size_t max_len) {
|
||||
|
||||
*out = OPENSSL_malloc(len);
|
||||
if (*out == NULL) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
OPENSSL_memcpy(*out, header, header_len);
|
||||
if (!bio_read_full(bio, (*out) + header_len, NULL, len - header_len)) {
|
||||
OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ENOUGH_DATA);
|
||||
memcpy(*out, header, header_len);
|
||||
if (BIO_read(bio, (*out) + header_len, len - header_len) !=
|
||||
(int) (len - header_len)) {
|
||||
OPENSSL_free(*out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void BIO_set_retry_special(BIO *bio) {
|
||||
bio->flags |= BIO_FLAGS_READ | BIO_FLAGS_IO_SPECIAL;
|
||||
}
|
||||
|
||||
int BIO_set_write_buffer_size(BIO *bio, int buffer_size) { return 0; }
|
||||
|
||||
static struct CRYPTO_STATIC_MUTEX g_index_lock = CRYPTO_STATIC_MUTEX_INIT;
|
||||
static int g_index = BIO_TYPE_START;
|
||||
|
||||
int BIO_get_new_index(void) {
|
||||
CRYPTO_STATIC_MUTEX_lock_write(&g_index_lock);
|
||||
// If |g_index| exceeds 255, it will collide with the flags bits.
|
||||
int ret = g_index > 255 ? -1 : g_index++;
|
||||
CRYPTO_STATIC_MUTEX_unlock_write(&g_index_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
BIO_METHOD *BIO_meth_new(int type, const char *name) {
|
||||
BIO_METHOD *method = OPENSSL_malloc(sizeof(BIO_METHOD));
|
||||
if (method == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
OPENSSL_memset(method, 0, sizeof(BIO_METHOD));
|
||||
method->type = type;
|
||||
method->name = name;
|
||||
return method;
|
||||
}
|
||||
|
||||
void BIO_meth_free(BIO_METHOD *method) {
|
||||
OPENSSL_free(method);
|
||||
}
|
||||
|
||||
int BIO_meth_set_create(BIO_METHOD *method,
|
||||
int (*create)(BIO *)) {
|
||||
method->create = create;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BIO_meth_set_destroy(BIO_METHOD *method,
|
||||
int (*destroy)(BIO *)) {
|
||||
method->destroy = destroy;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BIO_meth_set_write(BIO_METHOD *method,
|
||||
int (*write)(BIO *, const char *, int)) {
|
||||
method->bwrite = write;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BIO_meth_set_read(BIO_METHOD *method,
|
||||
int (*read)(BIO *, char *, int)) {
|
||||
method->bread = read;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BIO_meth_set_gets(BIO_METHOD *method,
|
||||
int (*gets)(BIO *, char *, int)) {
|
||||
method->bgets = gets;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BIO_meth_set_ctrl(BIO_METHOD *method,
|
||||
long (*ctrl)(BIO *, int, long, void *)) {
|
||||
method->ctrl = ctrl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void BIO_set_data(BIO *bio, void *ptr) { bio->ptr = ptr; }
|
||||
|
||||
void *BIO_get_data(BIO *bio) { return bio->ptr; }
|
||||
|
||||
void BIO_set_init(BIO *bio, int init) { bio->init = init; }
|
||||
|
||||
int BIO_get_init(BIO *bio) { return bio->init; }
|
||||
|
||||
void BIO_set_shutdown(BIO *bio, int shutdown) { bio->shutdown = shutdown; }
|
||||
|
||||
int BIO_get_shutdown(BIO *bio) { return bio->shutdown; }
|
||||
|
||||
int BIO_meth_set_puts(BIO_METHOD *method, int (*puts)(BIO *, const char *)) {
|
||||
// Ignore the parameter. We implement |BIO_puts| using |BIO_write|.
|
||||
return 1;
|
||||
}
|
||||
|
||||
+19
-21
@@ -63,8 +63,6 @@
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
BIO *BIO_new_mem_buf(const void *buf, int len) {
|
||||
BIO *ret;
|
||||
@@ -82,16 +80,16 @@ BIO *BIO_new_mem_buf(const void *buf, int len) {
|
||||
}
|
||||
|
||||
b = (BUF_MEM *)ret->ptr;
|
||||
// BIO_FLAGS_MEM_RDONLY ensures |b->data| is not written to.
|
||||
/* BIO_FLAGS_MEM_RDONLY ensures |b->data| is not written to. */
|
||||
b->data = (void *)buf;
|
||||
b->length = size;
|
||||
b->max = size;
|
||||
|
||||
ret->flags |= BIO_FLAGS_MEM_RDONLY;
|
||||
|
||||
// |num| is used to store the value that this BIO will return when it runs
|
||||
// out of data. If it's negative then the retry flags will also be set. Since
|
||||
// this is static data, retrying wont help
|
||||
/* |num| is used to store the value that this BIO will return when it runs
|
||||
* out of data. If it's negative then the retry flags will also be set. Since
|
||||
* this is static data, retrying wont help */
|
||||
ret->num = 0;
|
||||
|
||||
return ret;
|
||||
@@ -105,8 +103,8 @@ static int mem_new(BIO *bio) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// |shutdown| is used to store the close flag: whether the BIO has ownership
|
||||
// of the BUF_MEM.
|
||||
/* |shutdown| is used to store the close flag: whether the BIO has ownership
|
||||
* of the BUF_MEM. */
|
||||
bio->shutdown = 1;
|
||||
bio->init = 1;
|
||||
bio->num = -1;
|
||||
@@ -146,12 +144,12 @@ static int mem_read(BIO *bio, char *out, int outl) {
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
OPENSSL_memcpy(out, b->data, ret);
|
||||
memcpy(out, b->data, ret);
|
||||
b->length -= ret;
|
||||
if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
|
||||
b->data += ret;
|
||||
} else {
|
||||
OPENSSL_memmove(b->data, &b->data[ret], b->length);
|
||||
memmove(b->data, &b->data[ret], b->length);
|
||||
}
|
||||
} else if (b->length == 0) {
|
||||
ret = bio->num;
|
||||
@@ -182,13 +180,17 @@ static int mem_write(BIO *bio, const char *in, int inl) {
|
||||
if (BUF_MEM_grow_clean(b, blen + inl) != ((size_t) blen) + inl) {
|
||||
goto err;
|
||||
}
|
||||
OPENSSL_memcpy(&b->data[blen], in, inl);
|
||||
memcpy(&b->data[blen], in, inl);
|
||||
ret = inl;
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mem_puts(BIO *bp, const char *str) {
|
||||
return mem_write(bp, str, strlen(str));
|
||||
}
|
||||
|
||||
static int mem_gets(BIO *bio, char *buf, int size) {
|
||||
int i, j;
|
||||
char *p;
|
||||
@@ -214,8 +216,8 @@ static int mem_gets(BIO *bio, char *buf, int size) {
|
||||
}
|
||||
}
|
||||
|
||||
// i is now the max num of bytes to copy, either j or up to and including the
|
||||
// first newline
|
||||
/* i is now the max num of bytes to copy, either j or up to and including the
|
||||
* first newline */
|
||||
|
||||
i = mem_read(bio, buf, i);
|
||||
if (i > 0) {
|
||||
@@ -233,12 +235,12 @@ static long mem_ctrl(BIO *bio, int cmd, long num, void *ptr) {
|
||||
switch (cmd) {
|
||||
case BIO_CTRL_RESET:
|
||||
if (b->data != NULL) {
|
||||
// For read only case reset to the start again
|
||||
/* For read only case reset to the start again */
|
||||
if (bio->flags & BIO_FLAGS_MEM_RDONLY) {
|
||||
b->data -= b->max - b->length;
|
||||
b->length = b->max;
|
||||
} else {
|
||||
OPENSSL_memset(b->data, 0, b->max);
|
||||
memset(b->data, 0, b->max);
|
||||
b->length = 0;
|
||||
}
|
||||
}
|
||||
@@ -291,12 +293,8 @@ static long mem_ctrl(BIO *bio, int cmd, long num, void *ptr) {
|
||||
}
|
||||
|
||||
static const BIO_METHOD mem_method = {
|
||||
BIO_TYPE_MEM, "memory buffer",
|
||||
mem_write, mem_read,
|
||||
NULL /* puts */, mem_gets,
|
||||
mem_ctrl, mem_new,
|
||||
mem_free, NULL /* callback_ctrl */,
|
||||
};
|
||||
BIO_TYPE_MEM, "memory buffer", mem_write, mem_read, mem_puts,
|
||||
mem_gets, mem_ctrl, mem_new, mem_free, NULL, };
|
||||
|
||||
const BIO_METHOD *BIO_s_mem(void) { return &mem_method; }
|
||||
|
||||
|
||||
+359
-244
@@ -12,22 +12,14 @@
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#if !defined(_POSIX_C_SOURCE)
|
||||
#define _POSIX_C_SOURCE 201410L
|
||||
#endif
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "../internal.h"
|
||||
#include "../test/test_util.h"
|
||||
#include <openssl/base.h>
|
||||
|
||||
#if !defined(OPENSSL_WINDOWS)
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
@@ -35,27 +27,39 @@
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include <io.h>
|
||||
OPENSSL_MSVC_PRAGMA(warning(push, 3))
|
||||
#pragma warning(push, 3)
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
OPENSSL_MSVC_PRAGMA(warning(pop))
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "../test/scoped_types.h"
|
||||
|
||||
|
||||
#if !defined(OPENSSL_WINDOWS)
|
||||
static int closesocket(int sock) { return close(sock); }
|
||||
static std::string LastSocketError() { return strerror(errno); }
|
||||
static int closesocket(int sock) {
|
||||
return close(sock);
|
||||
}
|
||||
|
||||
static void PrintSocketError(const char *func) {
|
||||
perror(func);
|
||||
}
|
||||
#else
|
||||
static std::string LastSocketError() {
|
||||
char buf[DECIMAL_SIZE(int) + 1];
|
||||
BIO_snprintf(buf, sizeof(buf), "%d", WSAGetLastError());
|
||||
return buf;
|
||||
static void PrintSocketError(const char *func) {
|
||||
fprintf(stderr, "%s: %d\n", func, WSAGetLastError());
|
||||
}
|
||||
#endif
|
||||
|
||||
class ScopedSocket {
|
||||
public:
|
||||
explicit ScopedSocket(int sock) : sock_(sock) {}
|
||||
ScopedSocket(int sock) : sock_(sock) {}
|
||||
~ScopedSocket() {
|
||||
closesocket(sock_);
|
||||
}
|
||||
@@ -64,262 +68,373 @@ class ScopedSocket {
|
||||
const int sock_;
|
||||
};
|
||||
|
||||
TEST(BIOTest, SocketConnect) {
|
||||
static bool TestSocketConnect() {
|
||||
static const char kTestMessage[] = "test";
|
||||
int listening_sock = -1;
|
||||
socklen_t len = 0;
|
||||
sockaddr_storage ss;
|
||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &ss;
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *) &ss;
|
||||
OPENSSL_memset(&ss, 0, sizeof(ss));
|
||||
|
||||
ss.ss_family = AF_INET6;
|
||||
listening_sock = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
ASSERT_NE(-1, listening_sock) << LastSocketError();
|
||||
len = sizeof(*sin6);
|
||||
ASSERT_EQ(1, inet_pton(AF_INET6, "::1", &sin6->sin6_addr))
|
||||
<< LastSocketError();
|
||||
if (bind(listening_sock, (struct sockaddr *)sin6, sizeof(*sin6)) == -1) {
|
||||
closesocket(listening_sock);
|
||||
|
||||
ss.ss_family = AF_INET;
|
||||
listening_sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
ASSERT_NE(-1, listening_sock) << LastSocketError();
|
||||
len = sizeof(*sin);
|
||||
ASSERT_EQ(1, inet_pton(AF_INET, "127.0.0.1", &sin->sin_addr))
|
||||
<< LastSocketError();
|
||||
ASSERT_EQ(0, bind(listening_sock, (struct sockaddr *)sin, sizeof(*sin)))
|
||||
<< LastSocketError();
|
||||
int listening_sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (listening_sock == -1) {
|
||||
PrintSocketError("socket");
|
||||
return false;
|
||||
}
|
||||
|
||||
ScopedSocket listening_sock_closer(listening_sock);
|
||||
ASSERT_EQ(0, listen(listening_sock, 1)) << LastSocketError();
|
||||
ASSERT_EQ(0, getsockname(listening_sock, (struct sockaddr *)&ss, &len))
|
||||
<< LastSocketError();
|
||||
|
||||
struct sockaddr_in sin;
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
if (!inet_pton(AF_INET, "127.0.0.1", &sin.sin_addr)) {
|
||||
PrintSocketError("inet_pton");
|
||||
return false;
|
||||
}
|
||||
if (bind(listening_sock, (struct sockaddr *)&sin, sizeof(sin)) != 0) {
|
||||
PrintSocketError("bind");
|
||||
return false;
|
||||
}
|
||||
if (listen(listening_sock, 1)) {
|
||||
PrintSocketError("listen");
|
||||
return false;
|
||||
}
|
||||
socklen_t sockaddr_len = sizeof(sin);
|
||||
if (getsockname(listening_sock, (struct sockaddr *)&sin, &sockaddr_len) ||
|
||||
sockaddr_len != sizeof(sin)) {
|
||||
PrintSocketError("getsockname");
|
||||
return false;
|
||||
}
|
||||
|
||||
char hostname[80];
|
||||
if (ss.ss_family == AF_INET6) {
|
||||
BIO_snprintf(hostname, sizeof(hostname), "[::1]:%d",
|
||||
ntohs(sin6->sin6_port));
|
||||
} else if (ss.ss_family == AF_INET) {
|
||||
BIO_snprintf(hostname, sizeof(hostname), "127.0.0.1:%d",
|
||||
ntohs(sin->sin_port));
|
||||
BIO_snprintf(hostname, sizeof(hostname), "%s:%d", "127.0.0.1",
|
||||
ntohs(sin.sin_port));
|
||||
ScopedBIO bio(BIO_new_connect(hostname));
|
||||
if (!bio) {
|
||||
fprintf(stderr, "BIO_new_connect failed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Connect to it with a connect BIO.
|
||||
bssl::UniquePtr<BIO> bio(BIO_new_connect(hostname));
|
||||
ASSERT_TRUE(bio);
|
||||
if (BIO_write(bio.get(), kTestMessage, sizeof(kTestMessage)) !=
|
||||
sizeof(kTestMessage)) {
|
||||
fprintf(stderr, "BIO_write failed.\n");
|
||||
ERR_print_errors_fp(stderr);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write a test message to the BIO.
|
||||
ASSERT_EQ(static_cast<int>(sizeof(kTestMessage)),
|
||||
BIO_write(bio.get(), kTestMessage, sizeof(kTestMessage)));
|
||||
|
||||
// Accept the socket.
|
||||
int sock = accept(listening_sock, (struct sockaddr *) &ss, &len);
|
||||
ASSERT_NE(-1, sock) << LastSocketError();
|
||||
int sock = accept(listening_sock, (struct sockaddr *) &sin, &sockaddr_len);
|
||||
if (sock == -1) {
|
||||
PrintSocketError("accept");
|
||||
return false;
|
||||
}
|
||||
ScopedSocket sock_closer(sock);
|
||||
|
||||
// Check the same message is read back out.
|
||||
char buf[sizeof(kTestMessage)];
|
||||
ASSERT_EQ(static_cast<int>(sizeof(kTestMessage)),
|
||||
recv(sock, buf, sizeof(buf), 0))
|
||||
<< LastSocketError();
|
||||
EXPECT_EQ(Bytes(kTestMessage, sizeof(kTestMessage)), Bytes(buf, sizeof(buf)));
|
||||
char buf[5];
|
||||
if (recv(sock, buf, sizeof(buf), 0) != sizeof(kTestMessage)) {
|
||||
PrintSocketError("read");
|
||||
return false;
|
||||
}
|
||||
if (memcmp(buf, kTestMessage, sizeof(kTestMessage))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(BIOTest, Printf) {
|
||||
|
||||
// BioReadZeroCopyWrapper is a wrapper around the zero-copy APIs to make
|
||||
// testing easier.
|
||||
static size_t BioReadZeroCopyWrapper(BIO *bio, uint8_t *data, size_t len) {
|
||||
uint8_t *read_buf;
|
||||
size_t read_buf_offset;
|
||||
size_t available_bytes;
|
||||
size_t len_read = 0;
|
||||
|
||||
do {
|
||||
if (!BIO_zero_copy_get_read_buf(bio, &read_buf, &read_buf_offset,
|
||||
&available_bytes)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
available_bytes = std::min(available_bytes, len - len_read);
|
||||
memmove(data + len_read, read_buf + read_buf_offset, available_bytes);
|
||||
|
||||
BIO_zero_copy_get_read_buf_done(bio, available_bytes);
|
||||
|
||||
len_read += available_bytes;
|
||||
} while (len - len_read > 0 && available_bytes > 0);
|
||||
|
||||
return len_read;
|
||||
}
|
||||
|
||||
// BioWriteZeroCopyWrapper is a wrapper around the zero-copy APIs to make
|
||||
// testing easier.
|
||||
static size_t BioWriteZeroCopyWrapper(BIO *bio, const uint8_t *data,
|
||||
size_t len) {
|
||||
uint8_t *write_buf;
|
||||
size_t write_buf_offset;
|
||||
size_t available_bytes;
|
||||
size_t len_written = 0;
|
||||
|
||||
do {
|
||||
if (!BIO_zero_copy_get_write_buf(bio, &write_buf, &write_buf_offset,
|
||||
&available_bytes)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
available_bytes = std::min(available_bytes, len - len_written);
|
||||
memmove(write_buf + write_buf_offset, data + len_written, available_bytes);
|
||||
|
||||
BIO_zero_copy_get_write_buf_done(bio, available_bytes);
|
||||
|
||||
len_written += available_bytes;
|
||||
} while (len - len_written > 0 && available_bytes > 0);
|
||||
|
||||
return len_written;
|
||||
}
|
||||
|
||||
static bool TestZeroCopyBioPairs() {
|
||||
// Test read and write, especially triggering the ring buffer wrap-around.
|
||||
uint8_t bio1_application_send_buffer[1024];
|
||||
uint8_t bio2_application_recv_buffer[1024];
|
||||
|
||||
const size_t kLengths[] = {254, 255, 256, 257, 510, 511, 512, 513};
|
||||
|
||||
// These trigger ring buffer wrap around.
|
||||
const size_t kPartialLengths[] = {0, 1, 2, 3, 128, 255, 256, 257, 511, 512};
|
||||
|
||||
static const size_t kBufferSize = 512;
|
||||
|
||||
srand(1);
|
||||
for (size_t i = 0; i < sizeof(bio1_application_send_buffer); i++) {
|
||||
bio1_application_send_buffer[i] = rand() & 255;
|
||||
}
|
||||
|
||||
// Transfer bytes from bio1_application_send_buffer to
|
||||
// bio2_application_recv_buffer in various ways.
|
||||
for (size_t i = 0; i < sizeof(kLengths) / sizeof(kLengths[0]); i++) {
|
||||
for (size_t j = 0; j < sizeof(kPartialLengths) / sizeof(kPartialLengths[0]);
|
||||
j++) {
|
||||
size_t total_write = 0;
|
||||
size_t total_read = 0;
|
||||
|
||||
BIO *bio1, *bio2;
|
||||
if (!BIO_new_bio_pair(&bio1, kBufferSize, &bio2, kBufferSize)) {
|
||||
return false;
|
||||
}
|
||||
ScopedBIO bio1_scoper(bio1);
|
||||
ScopedBIO bio2_scoper(bio2);
|
||||
|
||||
total_write += BioWriteZeroCopyWrapper(
|
||||
bio1, bio1_application_send_buffer, kLengths[i]);
|
||||
|
||||
// This tests interleaved read/write calls. Do a read between zero copy
|
||||
// write calls.
|
||||
uint8_t *write_buf;
|
||||
size_t write_buf_offset;
|
||||
size_t available_bytes;
|
||||
if (!BIO_zero_copy_get_write_buf(bio1, &write_buf, &write_buf_offset,
|
||||
&available_bytes)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Free kPartialLengths[j] bytes in the beginning of bio1 write buffer.
|
||||
// This enables ring buffer wrap around for the next write.
|
||||
total_read += BIO_read(bio2, bio2_application_recv_buffer + total_read,
|
||||
kPartialLengths[j]);
|
||||
|
||||
size_t interleaved_write_len = std::min(kPartialLengths[j],
|
||||
available_bytes);
|
||||
|
||||
// Write the data for the interleaved write call. If the buffer becomes
|
||||
// empty after a read, the write offset is normally set to 0. Check that
|
||||
// this does not happen for interleaved read/write and that
|
||||
// |write_buf_offset| is still valid.
|
||||
memcpy(write_buf + write_buf_offset,
|
||||
bio1_application_send_buffer + total_write, interleaved_write_len);
|
||||
if (BIO_zero_copy_get_write_buf_done(bio1, interleaved_write_len)) {
|
||||
total_write += interleaved_write_len;
|
||||
}
|
||||
|
||||
// Do another write in case |write_buf_offset| was wrapped.
|
||||
total_write += BioWriteZeroCopyWrapper(
|
||||
bio1, bio1_application_send_buffer + total_write,
|
||||
kPartialLengths[j] - interleaved_write_len);
|
||||
|
||||
// Drain the rest.
|
||||
size_t bytes_left = BIO_pending(bio2);
|
||||
total_read += BioReadZeroCopyWrapper(
|
||||
bio2, bio2_application_recv_buffer + total_read, bytes_left);
|
||||
|
||||
if (total_read != total_write) {
|
||||
fprintf(stderr, "Lengths not equal in round (%u, %u)\n", (unsigned)i,
|
||||
(unsigned)j);
|
||||
return false;
|
||||
}
|
||||
if (total_read > kLengths[i] + kPartialLengths[j]) {
|
||||
fprintf(stderr, "Bad lengths in round (%u, %u)\n", (unsigned)i,
|
||||
(unsigned)j);
|
||||
return false;
|
||||
}
|
||||
if (memcmp(bio1_application_send_buffer, bio2_application_recv_buffer,
|
||||
total_read) != 0) {
|
||||
fprintf(stderr, "Buffers not equal in round (%u, %u)\n", (unsigned)i,
|
||||
(unsigned)j);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool TestPrintf() {
|
||||
// Test a short output, a very long one, and various sizes around
|
||||
// 256 (the size of the buffer) to ensure edge cases are correct.
|
||||
static const size_t kLengths[] = {5, 250, 251, 252, 253, 254, 1023};
|
||||
static const size_t kLengths[] = { 5, 250, 251, 252, 253, 254, 1023 };
|
||||
|
||||
bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
|
||||
ASSERT_TRUE(bio);
|
||||
ScopedBIO bio(BIO_new(BIO_s_mem()));
|
||||
if (!bio) {
|
||||
fprintf(stderr, "BIO_new failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t length : kLengths) {
|
||||
SCOPED_TRACE(length);
|
||||
|
||||
std::string in(length, 'a');
|
||||
|
||||
int ret = BIO_printf(bio.get(), "test %s", in.c_str());
|
||||
ASSERT_GE(ret, 0);
|
||||
EXPECT_EQ(5 + length, static_cast<size_t>(ret));
|
||||
for (size_t i = 0; i < sizeof(kLengths) / sizeof(kLengths[0]); i++) {
|
||||
char string[1024];
|
||||
if (kLengths[i] >= sizeof(string)) {
|
||||
fprintf(stderr, "Bad test string length\n");
|
||||
return false;
|
||||
}
|
||||
memset(string, 'a', sizeof(string));
|
||||
string[kLengths[i]] = '\0';
|
||||
|
||||
int ret = BIO_printf(bio.get(), "test %s", string);
|
||||
if (ret < 0 || static_cast<size_t>(ret) != 5 + kLengths[i]) {
|
||||
fprintf(stderr, "BIO_printf failed: %d\n", ret);
|
||||
return false;
|
||||
}
|
||||
const uint8_t *contents;
|
||||
size_t len;
|
||||
ASSERT_TRUE(BIO_mem_contents(bio.get(), &contents, &len));
|
||||
EXPECT_EQ("test " + in,
|
||||
std::string(reinterpret_cast<const char *>(contents), len));
|
||||
if (!BIO_mem_contents(bio.get(), &contents, &len)) {
|
||||
fprintf(stderr, "BIO_mem_contents failed\n");
|
||||
return false;
|
||||
}
|
||||
if (len != 5 + kLengths[i] ||
|
||||
strncmp((const char *)contents, "test ", 5) != 0 ||
|
||||
strncmp((const char *)contents + 5, string, kLengths[i]) != 0) {
|
||||
fprintf(stderr, "Contents did not match: %.*s\n", (int)len, contents);
|
||||
return false;
|
||||
}
|
||||
|
||||
ASSERT_TRUE(BIO_reset(bio.get()));
|
||||
if (!BIO_reset(bio.get())) {
|
||||
fprintf(stderr, "BIO_reset failed\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static const size_t kLargeASN1PayloadLen = 8000;
|
||||
|
||||
struct ASN1TestParam {
|
||||
bool should_succeed;
|
||||
std::vector<uint8_t> input;
|
||||
// suffix_len is the number of zeros to append to |input|.
|
||||
size_t suffix_len;
|
||||
// expected_len, if |should_succeed| is true, is the expected length of the
|
||||
// ASN.1 element.
|
||||
size_t expected_len;
|
||||
size_t max_len;
|
||||
} kASN1TestParams[] = {
|
||||
{true, {0x30, 2, 1, 2, 0, 0}, 0, 4, 100},
|
||||
{false /* truncated */, {0x30, 3, 1, 2}, 0, 0, 100},
|
||||
{false /* should be short len */, {0x30, 0x81, 1, 1}, 0, 0, 100},
|
||||
{false /* zero padded */, {0x30, 0x82, 0, 1, 1}, 0, 0, 100},
|
||||
|
||||
// Test a large payload.
|
||||
{true,
|
||||
{0x30, 0x82, kLargeASN1PayloadLen >> 8, kLargeASN1PayloadLen & 0xff},
|
||||
kLargeASN1PayloadLen,
|
||||
4 + kLargeASN1PayloadLen,
|
||||
kLargeASN1PayloadLen * 2},
|
||||
{false /* max_len too short */,
|
||||
{0x30, 0x82, kLargeASN1PayloadLen >> 8, kLargeASN1PayloadLen & 0xff},
|
||||
kLargeASN1PayloadLen,
|
||||
4 + kLargeASN1PayloadLen,
|
||||
3 + kLargeASN1PayloadLen},
|
||||
|
||||
// Test an indefinite-length input.
|
||||
{true,
|
||||
{0x30, 0x80},
|
||||
kLargeASN1PayloadLen + 2,
|
||||
2 + kLargeASN1PayloadLen + 2,
|
||||
kLargeASN1PayloadLen * 2},
|
||||
{false /* max_len too short */,
|
||||
{0x30, 0x80},
|
||||
kLargeASN1PayloadLen + 2,
|
||||
2 + kLargeASN1PayloadLen + 2,
|
||||
2 + kLargeASN1PayloadLen + 1},
|
||||
};
|
||||
|
||||
class BIOASN1Test : public testing::TestWithParam<ASN1TestParam> {};
|
||||
|
||||
TEST_P(BIOASN1Test, ReadASN1) {
|
||||
const ASN1TestParam& param = GetParam();
|
||||
std::vector<uint8_t> input = param.input;
|
||||
input.resize(input.size() + param.suffix_len, 0);
|
||||
|
||||
bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(input.data(), input.size()));
|
||||
ASSERT_TRUE(bio);
|
||||
static bool ReadASN1(bool should_succeed, const uint8_t *data, size_t data_len,
|
||||
size_t expected_len, size_t max_len) {
|
||||
ScopedBIO bio(BIO_new_mem_buf(data, data_len));
|
||||
|
||||
uint8_t *out;
|
||||
size_t out_len;
|
||||
int ok = BIO_read_asn1(bio.get(), &out, &out_len, param.max_len);
|
||||
int ok = BIO_read_asn1(bio.get(), &out, &out_len, max_len);
|
||||
if (!ok) {
|
||||
out = nullptr;
|
||||
}
|
||||
bssl::UniquePtr<uint8_t> out_storage(out);
|
||||
ScopedOpenSSLBytes out_storage(out);
|
||||
|
||||
ASSERT_EQ(param.should_succeed, (ok == 1));
|
||||
if (param.should_succeed) {
|
||||
EXPECT_EQ(Bytes(input.data(), param.expected_len), Bytes(out, out_len));
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(All, BIOASN1Test, testing::ValuesIn(kASN1TestParams));
|
||||
|
||||
// Run through the tests twice, swapping |bio1| and |bio2|, for symmetry.
|
||||
class BIOPairTest : public testing::TestWithParam<bool> {};
|
||||
|
||||
TEST_P(BIOPairTest, TestPair) {
|
||||
BIO *bio1, *bio2;
|
||||
ASSERT_TRUE(BIO_new_bio_pair(&bio1, 10, &bio2, 10));
|
||||
bssl::UniquePtr<BIO> free_bio1(bio1), free_bio2(bio2);
|
||||
|
||||
if (GetParam()) {
|
||||
std::swap(bio1, bio2);
|
||||
if (should_succeed != (ok == 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check initial states.
|
||||
EXPECT_EQ(10u, BIO_ctrl_get_write_guarantee(bio1));
|
||||
EXPECT_EQ(0u, BIO_ctrl_get_read_request(bio1));
|
||||
if (should_succeed &&
|
||||
(out_len != expected_len || memcmp(data, out, expected_len) != 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Data written in one end may be read out the other.
|
||||
uint8_t buf[20];
|
||||
EXPECT_EQ(5, BIO_write(bio1, "12345", 5));
|
||||
EXPECT_EQ(5u, BIO_ctrl_get_write_guarantee(bio1));
|
||||
ASSERT_EQ(5, BIO_read(bio2, buf, sizeof(buf)));
|
||||
EXPECT_EQ(Bytes("12345"), Bytes(buf, 5));
|
||||
EXPECT_EQ(10u, BIO_ctrl_get_write_guarantee(bio1));
|
||||
|
||||
// Attempting to write more than 10 bytes will write partially.
|
||||
EXPECT_EQ(10, BIO_write(bio1, "1234567890___", 13));
|
||||
EXPECT_EQ(0u, BIO_ctrl_get_write_guarantee(bio1));
|
||||
EXPECT_EQ(-1, BIO_write(bio1, "z", 1));
|
||||
EXPECT_TRUE(BIO_should_write(bio1));
|
||||
ASSERT_EQ(10, BIO_read(bio2, buf, sizeof(buf)));
|
||||
EXPECT_EQ(Bytes("1234567890"), Bytes(buf, 10));
|
||||
EXPECT_EQ(10u, BIO_ctrl_get_write_guarantee(bio1));
|
||||
|
||||
// Unsuccessful reads update the read request.
|
||||
EXPECT_EQ(-1, BIO_read(bio2, buf, 5));
|
||||
EXPECT_TRUE(BIO_should_read(bio2));
|
||||
EXPECT_EQ(5u, BIO_ctrl_get_read_request(bio1));
|
||||
|
||||
// The read request is clamped to the size of the buffer.
|
||||
EXPECT_EQ(-1, BIO_read(bio2, buf, 20));
|
||||
EXPECT_TRUE(BIO_should_read(bio2));
|
||||
EXPECT_EQ(10u, BIO_ctrl_get_read_request(bio1));
|
||||
|
||||
// Data may be written and read in chunks.
|
||||
EXPECT_EQ(5, BIO_write(bio1, "12345", 5));
|
||||
EXPECT_EQ(5u, BIO_ctrl_get_write_guarantee(bio1));
|
||||
EXPECT_EQ(5, BIO_write(bio1, "67890___", 8));
|
||||
EXPECT_EQ(0u, BIO_ctrl_get_write_guarantee(bio1));
|
||||
ASSERT_EQ(3, BIO_read(bio2, buf, 3));
|
||||
EXPECT_EQ(Bytes("123"), Bytes(buf, 3));
|
||||
EXPECT_EQ(3u, BIO_ctrl_get_write_guarantee(bio1));
|
||||
ASSERT_EQ(7, BIO_read(bio2, buf, sizeof(buf)));
|
||||
EXPECT_EQ(Bytes("4567890"), Bytes(buf, 7));
|
||||
EXPECT_EQ(10u, BIO_ctrl_get_write_guarantee(bio1));
|
||||
|
||||
// Successful reads reset the read request.
|
||||
EXPECT_EQ(0u, BIO_ctrl_get_read_request(bio1));
|
||||
|
||||
// Test writes and reads starting in the middle of the ring buffer and
|
||||
// wrapping to front.
|
||||
EXPECT_EQ(8, BIO_write(bio1, "abcdefgh", 8));
|
||||
EXPECT_EQ(2u, BIO_ctrl_get_write_guarantee(bio1));
|
||||
ASSERT_EQ(3, BIO_read(bio2, buf, 3));
|
||||
EXPECT_EQ(Bytes("abc"), Bytes(buf, 3));
|
||||
EXPECT_EQ(5u, BIO_ctrl_get_write_guarantee(bio1));
|
||||
EXPECT_EQ(5, BIO_write(bio1, "ijklm___", 8));
|
||||
EXPECT_EQ(0u, BIO_ctrl_get_write_guarantee(bio1));
|
||||
ASSERT_EQ(10, BIO_read(bio2, buf, sizeof(buf)));
|
||||
EXPECT_EQ(Bytes("defghijklm"), Bytes(buf, 10));
|
||||
EXPECT_EQ(10u, BIO_ctrl_get_write_guarantee(bio1));
|
||||
|
||||
// Data may flow from both ends in parallel.
|
||||
EXPECT_EQ(5, BIO_write(bio1, "12345", 5));
|
||||
EXPECT_EQ(5, BIO_write(bio2, "67890", 5));
|
||||
ASSERT_EQ(5, BIO_read(bio2, buf, sizeof(buf)));
|
||||
EXPECT_EQ(Bytes("12345"), Bytes(buf, 5));
|
||||
ASSERT_EQ(5, BIO_read(bio1, buf, sizeof(buf)));
|
||||
EXPECT_EQ(Bytes("67890"), Bytes(buf, 5));
|
||||
|
||||
// Closing the write end causes an EOF on the read half, after draining.
|
||||
EXPECT_EQ(5, BIO_write(bio1, "12345", 5));
|
||||
EXPECT_TRUE(BIO_shutdown_wr(bio1));
|
||||
ASSERT_EQ(5, BIO_read(bio2, buf, sizeof(buf)));
|
||||
EXPECT_EQ(Bytes("12345"), Bytes(buf, 5));
|
||||
EXPECT_EQ(0, BIO_read(bio2, buf, sizeof(buf)));
|
||||
|
||||
// A closed write end may not be written to.
|
||||
EXPECT_EQ(0u, BIO_ctrl_get_write_guarantee(bio1));
|
||||
EXPECT_EQ(-1, BIO_write(bio1, "_____", 5));
|
||||
|
||||
uint32_t err = ERR_get_error();
|
||||
EXPECT_EQ(ERR_LIB_BIO, ERR_GET_LIB(err));
|
||||
EXPECT_EQ(BIO_R_BROKEN_PIPE, ERR_GET_REASON(err));
|
||||
|
||||
// The other end is still functional.
|
||||
EXPECT_EQ(5, BIO_write(bio2, "12345", 5));
|
||||
ASSERT_EQ(5, BIO_read(bio1, buf, sizeof(buf)));
|
||||
EXPECT_EQ(Bytes("12345"), Bytes(buf, 5));
|
||||
return true;
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(All, BIOPairTest, testing::Values(false, true));
|
||||
static bool TestASN1() {
|
||||
static const uint8_t kData1[] = {0x30, 2, 1, 2, 0, 0};
|
||||
static const uint8_t kData2[] = {0x30, 3, 1, 2}; /* truncated */
|
||||
static const uint8_t kData3[] = {0x30, 0x81, 1, 1}; /* should be short len */
|
||||
static const uint8_t kData4[] = {0x30, 0x82, 0, 1, 1}; /* zero padded. */
|
||||
|
||||
if (!ReadASN1(true, kData1, sizeof(kData1), 4, 100) ||
|
||||
!ReadASN1(false, kData2, sizeof(kData2), 0, 100) ||
|
||||
!ReadASN1(false, kData3, sizeof(kData3), 0, 100) ||
|
||||
!ReadASN1(false, kData4, sizeof(kData4), 0, 100)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static const size_t kLargePayloadLen = 8000;
|
||||
static const uint8_t kLargePrefix[] = {0x30, 0x82, kLargePayloadLen >> 8,
|
||||
kLargePayloadLen & 0xff};
|
||||
ScopedOpenSSLBytes large(reinterpret_cast<uint8_t *>(
|
||||
OPENSSL_malloc(sizeof(kLargePrefix) + kLargePayloadLen)));
|
||||
if (!large) {
|
||||
return false;
|
||||
}
|
||||
memset(large.get() + sizeof(kLargePrefix), 0, kLargePayloadLen);
|
||||
memcpy(large.get(), kLargePrefix, sizeof(kLargePrefix));
|
||||
|
||||
if (!ReadASN1(true, large.get(), sizeof(kLargePrefix) + kLargePayloadLen,
|
||||
sizeof(kLargePrefix) + kLargePayloadLen,
|
||||
kLargePayloadLen * 2)) {
|
||||
fprintf(stderr, "Large payload test failed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ReadASN1(false, large.get(), sizeof(kLargePrefix) + kLargePayloadLen,
|
||||
sizeof(kLargePrefix) + kLargePayloadLen,
|
||||
kLargePayloadLen - 1)) {
|
||||
fprintf(stderr, "max_len test failed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
static const uint8_t kIndefPrefix[] = {0x30, 0x80};
|
||||
memcpy(large.get(), kIndefPrefix, sizeof(kIndefPrefix));
|
||||
if (!ReadASN1(true, large.get(), sizeof(kLargePrefix) + kLargePayloadLen,
|
||||
sizeof(kLargePrefix) + kLargePayloadLen,
|
||||
kLargePayloadLen*2)) {
|
||||
fprintf(stderr, "indefinite length test failed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ReadASN1(false, large.get(), sizeof(kLargePrefix) + kLargePayloadLen,
|
||||
sizeof(kLargePrefix) + kLargePayloadLen,
|
||||
kLargePayloadLen-1)) {
|
||||
fprintf(stderr, "indefinite length, max_len test failed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
CRYPTO_library_init();
|
||||
|
||||
#if defined(OPENSSL_WINDOWS)
|
||||
// Initialize Winsock.
|
||||
WORD wsa_version = MAKEWORD(2, 2);
|
||||
WSADATA wsa_data;
|
||||
int wsa_err = WSAStartup(wsa_version, &wsa_data);
|
||||
if (wsa_err != 0) {
|
||||
fprintf(stderr, "WSAStartup failed: %d\n", wsa_err);
|
||||
return 1;
|
||||
}
|
||||
if (wsa_data.wVersion != wsa_version) {
|
||||
fprintf(stderr, "Didn't get expected version: %x\n", wsa_data.wVersion);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!TestSocketConnect() ||
|
||||
!TestPrintf() ||
|
||||
!TestZeroCopyBioPairs() ||
|
||||
!TestASN1()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("PASS\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,496 @@
|
||||
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* This package is an SSL implementation written
|
||||
* by Eric Young (eay@cryptsoft.com).
|
||||
* The implementation was written so as to conform with Netscapes SSL.
|
||||
*
|
||||
* This library is free for commercial and non-commercial use as long as
|
||||
* the following conditions are aheared to. The following conditions
|
||||
* apply to all code found in this distribution, be it the RC4, RSA,
|
||||
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
|
||||
* included with this distribution is covered by the same copyright terms
|
||||
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||
*
|
||||
* Copyright remains Eric Young's, and as such any Copyright notices in
|
||||
* the code are not to be removed.
|
||||
* If this package is used in a product, Eric Young should be given attribution
|
||||
* as the author of the parts of the library used.
|
||||
* This can be in the form of a textual message at program startup or
|
||||
* in documentation (online or textual) provided with the package.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* "This product includes cryptographic software written by
|
||||
* Eric Young (eay@cryptsoft.com)"
|
||||
* The word 'cryptographic' can be left out if the rouines from the library
|
||||
* being used are not cryptographic related :-).
|
||||
* 4. If you include any Windows specific code (or a derivative thereof) from
|
||||
* the apps directory (application code) you must include an acknowledgement:
|
||||
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* The licence and distribution terms for any publically available version or
|
||||
* derivative of this code cannot be changed. i.e. this code cannot simply be
|
||||
* copied and put under another distribution licence
|
||||
* [including the GNU Public Licence.] */
|
||||
|
||||
#include <openssl/bio.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/buf.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
|
||||
#define DEFAULT_BUFFER_SIZE 4096
|
||||
|
||||
typedef struct bio_f_buffer_ctx_struct {
|
||||
/* Buffers are setup like this:
|
||||
*
|
||||
* <---------------------- size ----------------------->
|
||||
* +---------------------------------------------------+
|
||||
* | consumed | remaining | free space |
|
||||
* +---------------------------------------------------+
|
||||
* <-- off --><------- len ------->
|
||||
*/
|
||||
|
||||
int ibuf_size; /* how big is the input buffer */
|
||||
int obuf_size; /* how big is the output buffer */
|
||||
|
||||
char *ibuf; /* the char array */
|
||||
int ibuf_len; /* how many bytes are in it */
|
||||
int ibuf_off; /* write/read offset */
|
||||
|
||||
char *obuf; /* the char array */
|
||||
int obuf_len; /* how many bytes are in it */
|
||||
int obuf_off; /* write/read offset */
|
||||
} BIO_F_BUFFER_CTX;
|
||||
|
||||
static int buffer_new(BIO *bio) {
|
||||
BIO_F_BUFFER_CTX *ctx;
|
||||
|
||||
ctx = OPENSSL_malloc(sizeof(BIO_F_BUFFER_CTX));
|
||||
if (ctx == NULL) {
|
||||
return 0;
|
||||
}
|
||||
memset(ctx, 0, sizeof(BIO_F_BUFFER_CTX));
|
||||
|
||||
ctx->ibuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE);
|
||||
if (ctx->ibuf == NULL) {
|
||||
goto err1;
|
||||
}
|
||||
ctx->obuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE);
|
||||
if (ctx->obuf == NULL) {
|
||||
goto err2;
|
||||
}
|
||||
ctx->ibuf_size = DEFAULT_BUFFER_SIZE;
|
||||
ctx->obuf_size = DEFAULT_BUFFER_SIZE;
|
||||
|
||||
bio->init = 1;
|
||||
bio->ptr = (char *)ctx;
|
||||
return 1;
|
||||
|
||||
err2:
|
||||
OPENSSL_free(ctx->ibuf);
|
||||
|
||||
err1:
|
||||
OPENSSL_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int buffer_free(BIO *bio) {
|
||||
BIO_F_BUFFER_CTX *ctx;
|
||||
|
||||
if (bio == NULL || bio->ptr == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctx = (BIO_F_BUFFER_CTX *)bio->ptr;
|
||||
OPENSSL_free(ctx->ibuf);
|
||||
OPENSSL_free(ctx->obuf);
|
||||
OPENSSL_free(bio->ptr);
|
||||
|
||||
bio->ptr = NULL;
|
||||
bio->init = 0;
|
||||
bio->flags = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int buffer_read(BIO *bio, char *out, int outl) {
|
||||
int i, num = 0;
|
||||
BIO_F_BUFFER_CTX *ctx;
|
||||
|
||||
ctx = (BIO_F_BUFFER_CTX *)bio->ptr;
|
||||
|
||||
if (ctx == NULL || bio->next_bio == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
num = 0;
|
||||
BIO_clear_retry_flags(bio);
|
||||
|
||||
for (;;) {
|
||||
i = ctx->ibuf_len;
|
||||
/* If there is stuff left over, grab it */
|
||||
if (i != 0) {
|
||||
if (i > outl) {
|
||||
i = outl;
|
||||
}
|
||||
memcpy(out, &ctx->ibuf[ctx->ibuf_off], i);
|
||||
ctx->ibuf_off += i;
|
||||
ctx->ibuf_len -= i;
|
||||
num += i;
|
||||
if (outl == i) {
|
||||
return num;
|
||||
}
|
||||
outl -= i;
|
||||
out += i;
|
||||
}
|
||||
|
||||
/* We may have done a partial read. Try to do more. We have nothing in the
|
||||
* buffer. If we get an error and have read some data, just return it and
|
||||
* let them retry to get the error again. Copy direct to parent address
|
||||
* space */
|
||||
if (outl > ctx->ibuf_size) {
|
||||
for (;;) {
|
||||
i = BIO_read(bio->next_bio, out, outl);
|
||||
if (i <= 0) {
|
||||
BIO_copy_next_retry(bio);
|
||||
if (i < 0) {
|
||||
return (num > 0) ? num : i;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
num += i;
|
||||
if (outl == i) {
|
||||
return num;
|
||||
}
|
||||
out += i;
|
||||
outl -= i;
|
||||
}
|
||||
}
|
||||
/* else */
|
||||
|
||||
/* we are going to be doing some buffering */
|
||||
i = BIO_read(bio->next_bio, ctx->ibuf, ctx->ibuf_size);
|
||||
if (i <= 0) {
|
||||
BIO_copy_next_retry(bio);
|
||||
if (i < 0) {
|
||||
return (num > 0) ? num : i;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
ctx->ibuf_off = 0;
|
||||
ctx->ibuf_len = i;
|
||||
}
|
||||
}
|
||||
|
||||
static int buffer_write(BIO *b, const char *in, int inl) {
|
||||
int i, num = 0;
|
||||
BIO_F_BUFFER_CTX *ctx;
|
||||
|
||||
ctx = (BIO_F_BUFFER_CTX *)b->ptr;
|
||||
if (ctx == NULL || b->next_bio == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
BIO_clear_retry_flags(b);
|
||||
|
||||
for (;;) {
|
||||
i = ctx->obuf_size - (ctx->obuf_off + ctx->obuf_len);
|
||||
/* add to buffer and return */
|
||||
if (i >= inl) {
|
||||
memcpy(&ctx->obuf[ctx->obuf_off + ctx->obuf_len], in, inl);
|
||||
ctx->obuf_len += inl;
|
||||
return num + inl;
|
||||
}
|
||||
/* else */
|
||||
/* stuff already in buffer, so add to it first, then flush */
|
||||
if (ctx->obuf_len != 0) {
|
||||
if (i > 0) {
|
||||
memcpy(&ctx->obuf[ctx->obuf_off + ctx->obuf_len], in, i);
|
||||
in += i;
|
||||
inl -= i;
|
||||
num += i;
|
||||
ctx->obuf_len += i;
|
||||
}
|
||||
|
||||
/* we now have a full buffer needing flushing */
|
||||
for (;;) {
|
||||
i = BIO_write(b->next_bio, &ctx->obuf[ctx->obuf_off], ctx->obuf_len);
|
||||
if (i <= 0) {
|
||||
BIO_copy_next_retry(b);
|
||||
|
||||
if (i < 0) {
|
||||
return (num > 0) ? num : i;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
ctx->obuf_off += i;
|
||||
ctx->obuf_len -= i;
|
||||
if (ctx->obuf_len == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* we only get here if the buffer has been flushed and we
|
||||
* still have stuff to write */
|
||||
ctx->obuf_off = 0;
|
||||
|
||||
/* we now have inl bytes to write */
|
||||
while (inl >= ctx->obuf_size) {
|
||||
i = BIO_write(b->next_bio, in, inl);
|
||||
if (i <= 0) {
|
||||
BIO_copy_next_retry(b);
|
||||
if (i < 0) {
|
||||
return (num > 0) ? num : i;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
num += i;
|
||||
in += i;
|
||||
inl -= i;
|
||||
if (inl == 0) {
|
||||
return num;
|
||||
}
|
||||
}
|
||||
|
||||
/* copy the rest into the buffer since we have only a small
|
||||
* amount left */
|
||||
}
|
||||
}
|
||||
|
||||
static long buffer_ctrl(BIO *b, int cmd, long num, void *ptr) {
|
||||
BIO_F_BUFFER_CTX *ctx;
|
||||
long ret = 1;
|
||||
char *p1, *p2;
|
||||
int r, *ip;
|
||||
int ibs, obs;
|
||||
|
||||
ctx = (BIO_F_BUFFER_CTX *)b->ptr;
|
||||
|
||||
switch (cmd) {
|
||||
case BIO_CTRL_RESET:
|
||||
ctx->ibuf_off = 0;
|
||||
ctx->ibuf_len = 0;
|
||||
ctx->obuf_off = 0;
|
||||
ctx->obuf_len = 0;
|
||||
if (b->next_bio == NULL) {
|
||||
return 0;
|
||||
}
|
||||
ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
|
||||
break;
|
||||
|
||||
case BIO_CTRL_INFO:
|
||||
ret = ctx->obuf_len;
|
||||
break;
|
||||
|
||||
case BIO_CTRL_WPENDING:
|
||||
ret = (long)ctx->obuf_len;
|
||||
if (ret == 0) {
|
||||
if (b->next_bio == NULL) {
|
||||
return 0;
|
||||
}
|
||||
ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
|
||||
}
|
||||
break;
|
||||
|
||||
case BIO_CTRL_PENDING:
|
||||
ret = (long)ctx->ibuf_len;
|
||||
if (ret == 0) {
|
||||
if (b->next_bio == NULL) {
|
||||
return 0;
|
||||
}
|
||||
ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
|
||||
}
|
||||
break;
|
||||
|
||||
case BIO_C_SET_BUFF_SIZE:
|
||||
ip = (int *)ptr;
|
||||
if (*ip == 0) {
|
||||
ibs = (int)num;
|
||||
obs = ctx->obuf_size;
|
||||
} else /* if (*ip == 1) */ {
|
||||
ibs = ctx->ibuf_size;
|
||||
obs = (int)num;
|
||||
}
|
||||
p1 = ctx->ibuf;
|
||||
p2 = ctx->obuf;
|
||||
if (ibs > DEFAULT_BUFFER_SIZE && ibs != ctx->ibuf_size) {
|
||||
p1 = OPENSSL_malloc(ibs);
|
||||
if (p1 == NULL) {
|
||||
goto malloc_error;
|
||||
}
|
||||
}
|
||||
if (obs > DEFAULT_BUFFER_SIZE && obs != ctx->obuf_size) {
|
||||
p2 = OPENSSL_malloc(obs);
|
||||
if (p2 == NULL) {
|
||||
if (p1 != ctx->ibuf) {
|
||||
OPENSSL_free(p1);
|
||||
}
|
||||
goto malloc_error;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->ibuf != p1) {
|
||||
OPENSSL_free(ctx->ibuf);
|
||||
ctx->ibuf = p1;
|
||||
ctx->ibuf_size = ibs;
|
||||
}
|
||||
ctx->ibuf_off = 0;
|
||||
ctx->ibuf_len = 0;
|
||||
|
||||
if (ctx->obuf != p2) {
|
||||
OPENSSL_free(ctx->obuf);
|
||||
ctx->obuf = p2;
|
||||
ctx->obuf_size = obs;
|
||||
}
|
||||
ctx->obuf_off = 0;
|
||||
ctx->obuf_len = 0;
|
||||
break;
|
||||
|
||||
case BIO_CTRL_FLUSH:
|
||||
if (b->next_bio == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (ctx->obuf_len > 0) {
|
||||
BIO_clear_retry_flags(b);
|
||||
r = BIO_write(b->next_bio, &(ctx->obuf[ctx->obuf_off]),
|
||||
ctx->obuf_len);
|
||||
BIO_copy_next_retry(b);
|
||||
if (r <= 0) {
|
||||
return r;
|
||||
}
|
||||
ctx->obuf_off += r;
|
||||
ctx->obuf_len -= r;
|
||||
}
|
||||
|
||||
ctx->obuf_len = 0;
|
||||
ctx->obuf_off = 0;
|
||||
ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (b->next_bio == NULL) {
|
||||
return 0;
|
||||
}
|
||||
BIO_clear_retry_flags(b);
|
||||
ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
|
||||
BIO_copy_next_retry(b);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
|
||||
malloc_error:
|
||||
OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long buffer_callback_ctrl(BIO *b, int cmd, bio_info_cb fp) {
|
||||
long ret = 1;
|
||||
|
||||
if (b->next_bio == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
default:
|
||||
ret = BIO_callback_ctrl(b->next_bio, cmd, fp);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int buffer_gets(BIO *b, char *buf, int size) {
|
||||
BIO_F_BUFFER_CTX *ctx;
|
||||
int num = 0, i, flag;
|
||||
char *p;
|
||||
|
||||
ctx = (BIO_F_BUFFER_CTX *)b->ptr;
|
||||
if (buf == NULL || size <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size--; /* reserve space for a '\0' */
|
||||
BIO_clear_retry_flags(b);
|
||||
|
||||
for (;;) {
|
||||
if (ctx->ibuf_len > 0) {
|
||||
p = &ctx->ibuf[ctx->ibuf_off];
|
||||
flag = 0;
|
||||
for (i = 0; (i < ctx->ibuf_len) && (i < size); i++) {
|
||||
*(buf++) = p[i];
|
||||
if (p[i] == '\n') {
|
||||
flag = 1;
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
num += i;
|
||||
size -= i;
|
||||
ctx->ibuf_len -= i;
|
||||
ctx->ibuf_off += i;
|
||||
if (flag || size == 0) {
|
||||
*buf = '\0';
|
||||
return num;
|
||||
}
|
||||
} else /* read another chunk */
|
||||
{
|
||||
i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size);
|
||||
if (i <= 0) {
|
||||
BIO_copy_next_retry(b);
|
||||
*buf = '\0';
|
||||
if (i < 0) {
|
||||
return (num > 0) ? num : i;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
ctx->ibuf_len = i;
|
||||
ctx->ibuf_off = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int buffer_puts(BIO *b, const char *str) {
|
||||
return buffer_write(b, str, strlen(str));
|
||||
}
|
||||
|
||||
static const BIO_METHOD methods_buffer = {
|
||||
BIO_TYPE_BUFFER, "buffer", buffer_write, buffer_read,
|
||||
buffer_puts, buffer_gets, buffer_ctrl, buffer_new,
|
||||
buffer_free, buffer_callback_ctrl,
|
||||
};
|
||||
|
||||
const BIO_METHOD *BIO_f_buffer(void) { return &methods_buffer; }
|
||||
|
||||
int BIO_set_read_buffer_size(BIO *bio, int buffer_size) {
|
||||
return BIO_int_ctrl(bio, BIO_C_SET_BUFF_SIZE, buffer_size, 0);
|
||||
}
|
||||
|
||||
int BIO_set_write_buffer_size(BIO *bio, int buffer_size) {
|
||||
return BIO_int_ctrl(bio, BIO_C_SET_BUFF_SIZE, buffer_size, 1);
|
||||
}
|
||||
+41
-39
@@ -56,8 +56,6 @@
|
||||
|
||||
#include <openssl/bio.h>
|
||||
|
||||
#if !defined(OPENSSL_TRUSTY)
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
@@ -68,17 +66,17 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#else
|
||||
OPENSSL_MSVC_PRAGMA(warning(push, 3))
|
||||
#pragma warning(push, 3)
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
OPENSSL_MSVC_PRAGMA(warning(pop))
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include <openssl/buf.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
enum {
|
||||
@@ -99,12 +97,12 @@ typedef struct bio_connect_st {
|
||||
struct sockaddr_storage them;
|
||||
socklen_t them_length;
|
||||
|
||||
// the file descriptor is kept in bio->num in order to match the socket
|
||||
// BIO.
|
||||
/* the file descriptor is kept in bio->num in order to match the socket
|
||||
* BIO. */
|
||||
|
||||
// info_callback is called when the connection is initially made
|
||||
// callback(BIO,state,ret); The callback should return 'ret', state is for
|
||||
// compatibility with the SSL info_callback.
|
||||
/* info_callback is called when the connection is initially made
|
||||
* callback(BIO,state,ret); The callback should return 'ret', state is for
|
||||
* compatibility with the SSL info_callback. */
|
||||
int (*info_callback)(const BIO *bio, int state, int ret);
|
||||
} BIO_CONNECT;
|
||||
|
||||
@@ -114,9 +112,9 @@ static int closesocket(int sock) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// split_host_and_port sets |*out_host| and |*out_port| to the host and port
|
||||
// parsed from |name|. It returns one on success or zero on error. Even when
|
||||
// successful, |*out_port| may be NULL on return if no port was specified.
|
||||
/* split_host_and_port sets |*out_host| and |*out_port| to the host and port
|
||||
* parsed from |name|. It returns one on success or zero on error. Even when
|
||||
* successful, |*out_port| may be NULL on return if no port was specified. */
|
||||
static int split_host_and_port(char **out_host, char **out_port, const char *name) {
|
||||
const char *host, *port = NULL;
|
||||
size_t host_len = 0;
|
||||
@@ -124,31 +122,31 @@ static int split_host_and_port(char **out_host, char **out_port, const char *nam
|
||||
*out_host = NULL;
|
||||
*out_port = NULL;
|
||||
|
||||
if (name[0] == '[') { // bracketed IPv6 address
|
||||
if (name[0] == '[') { /* bracketed IPv6 address */
|
||||
const char *close = strchr(name, ']');
|
||||
if (close == NULL) {
|
||||
return 0;
|
||||
}
|
||||
host = name + 1;
|
||||
host_len = close - host;
|
||||
if (close[1] == ':') { // [IP]:port
|
||||
if (close[1] == ':') { /* [IP]:port */
|
||||
port = close + 2;
|
||||
} else if (close[1] != 0) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
const char *colon = strchr(name, ':');
|
||||
if (colon == NULL || strchr(colon + 1, ':') != NULL) { // IPv6 address
|
||||
if (colon == NULL || strchr(colon + 1, ':') != NULL) { /* IPv6 address */
|
||||
host = name;
|
||||
host_len = strlen(name);
|
||||
} else { // host:port
|
||||
} else { /* host:port */
|
||||
host = name;
|
||||
host_len = colon - name;
|
||||
port = colon + 1;
|
||||
}
|
||||
}
|
||||
|
||||
*out_host = OPENSSL_strndup(host, host_len);
|
||||
*out_host = BUF_strndup(host, host_len);
|
||||
if (*out_host == NULL) {
|
||||
return 0;
|
||||
}
|
||||
@@ -176,9 +174,9 @@ static int conn_state(BIO *bio, BIO_CONNECT *c) {
|
||||
for (;;) {
|
||||
switch (c->state) {
|
||||
case BIO_CONN_S_BEFORE:
|
||||
// If there's a hostname and a port, assume that both are
|
||||
// exactly what they say. If there is only a hostname, try
|
||||
// (just once) to split it into a hostname and port.
|
||||
/* If there's a hostname and a port, assume that both are
|
||||
* exactly what they say. If there is only a hostname, try
|
||||
* (just once) to split it into a hostname and port. */
|
||||
|
||||
if (c->param_hostname == NULL) {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_NO_HOSTNAME_SPECIFIED);
|
||||
@@ -300,7 +298,7 @@ static BIO_CONNECT *BIO_CONNECT_new(void) {
|
||||
if (ret == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
OPENSSL_memset(ret, 0, sizeof(BIO_CONNECT));
|
||||
memset(ret, 0, sizeof(BIO_CONNECT));
|
||||
|
||||
ret->state = BIO_CONN_S_BEFORE;
|
||||
return ret;
|
||||
@@ -331,7 +329,7 @@ static void conn_close_socket(BIO *bio) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only do a shutdown if things were established
|
||||
/* Only do a shutdown if things were established */
|
||||
if (c->state == BIO_CONN_S_OK) {
|
||||
shutdown(bio->num, 2);
|
||||
}
|
||||
@@ -416,7 +414,7 @@ static long conn_ctrl(BIO *bio, int cmd, long num, void *ptr) {
|
||||
bio->flags = 0;
|
||||
break;
|
||||
case BIO_C_DO_STATE_MACHINE:
|
||||
// use this one to start the connection
|
||||
/* use this one to start the connection */
|
||||
if (data->state != BIO_CONN_S_OK) {
|
||||
ret = (long)conn_state(bio, data);
|
||||
} else {
|
||||
@@ -428,13 +426,13 @@ static long conn_ctrl(BIO *bio, int cmd, long num, void *ptr) {
|
||||
bio->init = 1;
|
||||
if (num == 0) {
|
||||
OPENSSL_free(data->param_hostname);
|
||||
data->param_hostname = OPENSSL_strdup(ptr);
|
||||
data->param_hostname = BUF_strdup(ptr);
|
||||
if (data->param_hostname == NULL) {
|
||||
ret = 0;
|
||||
}
|
||||
} else if (num == 1) {
|
||||
OPENSSL_free(data->param_port);
|
||||
data->param_port = OPENSSL_strdup(ptr);
|
||||
data->param_port = BUF_strdup(ptr);
|
||||
if (data->param_port == NULL) {
|
||||
ret = 0;
|
||||
}
|
||||
@@ -469,6 +467,14 @@ static long conn_ctrl(BIO *bio, int cmd, long num, void *ptr) {
|
||||
break;
|
||||
case BIO_CTRL_FLUSH:
|
||||
break;
|
||||
case BIO_CTRL_SET_CALLBACK: {
|
||||
#if 0 /* FIXME: Should this be used? -- Richard Levitte */
|
||||
OPENSSL_PUT_ERROR(BIO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
|
||||
ret = -1;
|
||||
#else
|
||||
ret = 0;
|
||||
#endif
|
||||
} break;
|
||||
case BIO_CTRL_GET_CALLBACK: {
|
||||
int (**fptr)(const BIO *bio, int state, int xret);
|
||||
fptr = (int (**)(const BIO *bio, int state, int xret))ptr;
|
||||
@@ -478,7 +484,7 @@ static long conn_ctrl(BIO *bio, int cmd, long num, void *ptr) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static long conn_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) {
|
||||
@@ -488,9 +494,9 @@ static long conn_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) {
|
||||
data = (BIO_CONNECT *)bio->ptr;
|
||||
|
||||
switch (cmd) {
|
||||
case BIO_CTRL_SET_CALLBACK:
|
||||
case BIO_CTRL_SET_CALLBACK: {
|
||||
data->info_callback = (int (*)(const struct bio_st *, int, int))fp;
|
||||
break;
|
||||
} break;
|
||||
default:
|
||||
ret = 0;
|
||||
break;
|
||||
@@ -498,6 +504,10 @@ static long conn_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int conn_puts(BIO *bp, const char *str) {
|
||||
return conn_write(bp, str, strlen(str));
|
||||
}
|
||||
|
||||
BIO *BIO_new_connect(const char *hostname) {
|
||||
BIO *ret;
|
||||
|
||||
@@ -513,8 +523,8 @@ BIO *BIO_new_connect(const char *hostname) {
|
||||
}
|
||||
|
||||
static const BIO_METHOD methods_connectp = {
|
||||
BIO_TYPE_CONNECT, "socket connect", conn_write, conn_read,
|
||||
NULL /* puts */, NULL /* gets */, conn_ctrl, conn_new,
|
||||
BIO_TYPE_CONNECT, "socket connect", conn_write, conn_read,
|
||||
conn_puts, NULL /* connect_gets, */, conn_ctrl, conn_new,
|
||||
conn_free, conn_callback_ctrl,
|
||||
};
|
||||
|
||||
@@ -528,12 +538,6 @@ int BIO_set_conn_port(BIO *bio, const char *port_str) {
|
||||
return BIO_ctrl(bio, BIO_C_SET_CONNECT, 1, (void*) port_str);
|
||||
}
|
||||
|
||||
int BIO_set_conn_int_port(BIO *bio, const int *port) {
|
||||
char buf[DECIMAL_SIZE(int) + 1];
|
||||
BIO_snprintf(buf, sizeof(buf), "%d", *port);
|
||||
return BIO_set_conn_port(bio, buf);
|
||||
}
|
||||
|
||||
int BIO_set_nbio(BIO *bio, int on) {
|
||||
return BIO_ctrl(bio, BIO_C_SET_NBIO, on, NULL);
|
||||
}
|
||||
@@ -541,5 +545,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
|
||||
|
||||
+24
-31
@@ -56,8 +56,6 @@
|
||||
|
||||
#include <openssl/bio.h>
|
||||
|
||||
#if !defined(OPENSSL_TRUSTY)
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -65,16 +63,16 @@
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include <io.h>
|
||||
OPENSSL_MSVC_PRAGMA(warning(push, 3))
|
||||
#pragma warning(push, 3)
|
||||
#include <windows.h>
|
||||
OPENSSL_MSVC_PRAGMA(warning(pop))
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include <openssl/buf.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
static int bio_fd_non_fatal_error(int err) {
|
||||
@@ -110,25 +108,20 @@ static int bio_fd_non_fatal_error(int err) {
|
||||
}
|
||||
|
||||
#if defined(OPENSSL_WINDOWS)
|
||||
#define BORINGSSL_ERRNO (int)GetLastError()
|
||||
#define BORINGSSL_CLOSE _close
|
||||
#define BORINGSSL_LSEEK _lseek
|
||||
#define BORINGSSL_READ _read
|
||||
#define BORINGSSL_WRITE _write
|
||||
#else
|
||||
#define BORINGSSL_ERRNO errno
|
||||
#define BORINGSSL_CLOSE close
|
||||
#define BORINGSSL_LSEEK lseek
|
||||
#define BORINGSSL_READ read
|
||||
#define BORINGSSL_WRITE write
|
||||
#endif
|
||||
|
||||
int bio_fd_should_retry(int i) {
|
||||
if (i == -1) {
|
||||
return bio_fd_non_fatal_error(BORINGSSL_ERRNO);
|
||||
return bio_fd_non_fatal_error((int)GetLastError());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int bio_fd_should_retry(int i) {
|
||||
if (i == -1) {
|
||||
return bio_fd_non_fatal_error(errno);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
BIO *BIO_new_fd(int fd, int close_flag) {
|
||||
BIO *ret = BIO_new(BIO_s_fd());
|
||||
@@ -140,7 +133,7 @@ BIO *BIO_new_fd(int fd, int close_flag) {
|
||||
}
|
||||
|
||||
static int fd_new(BIO *bio) {
|
||||
// num is used to store the file descriptor.
|
||||
/* num is used to store the file descriptor. */
|
||||
bio->num = -1;
|
||||
return 1;
|
||||
}
|
||||
@@ -152,7 +145,7 @@ static int fd_free(BIO *bio) {
|
||||
|
||||
if (bio->shutdown) {
|
||||
if (bio->init) {
|
||||
BORINGSSL_CLOSE(bio->num);
|
||||
close(bio->num);
|
||||
}
|
||||
bio->init = 0;
|
||||
}
|
||||
@@ -162,7 +155,7 @@ static int fd_free(BIO *bio) {
|
||||
static int fd_read(BIO *b, char *out, int outl) {
|
||||
int ret = 0;
|
||||
|
||||
ret = BORINGSSL_READ(b->num, out, outl);
|
||||
ret = read(b->num, out, outl);
|
||||
BIO_clear_retry_flags(b);
|
||||
if (ret <= 0) {
|
||||
if (bio_fd_should_retry(ret)) {
|
||||
@@ -174,7 +167,7 @@ static int fd_read(BIO *b, char *out, int outl) {
|
||||
}
|
||||
|
||||
static int fd_write(BIO *b, const char *in, int inl) {
|
||||
int ret = BORINGSSL_WRITE(b->num, in, inl);
|
||||
int ret = write(b->num, in, inl);
|
||||
BIO_clear_retry_flags(b);
|
||||
if (ret <= 0) {
|
||||
if (bio_fd_should_retry(ret)) {
|
||||
@@ -192,18 +185,17 @@ static long fd_ctrl(BIO *b, int cmd, long num, void *ptr) {
|
||||
switch (cmd) {
|
||||
case BIO_CTRL_RESET:
|
||||
num = 0;
|
||||
OPENSSL_FALLTHROUGH;
|
||||
case BIO_C_FILE_SEEK:
|
||||
ret = 0;
|
||||
if (b->init) {
|
||||
ret = (long)BORINGSSL_LSEEK(b->num, num, SEEK_SET);
|
||||
ret = (long)lseek(b->num, num, SEEK_SET);
|
||||
}
|
||||
break;
|
||||
case BIO_C_FILE_TELL:
|
||||
case BIO_CTRL_INFO:
|
||||
ret = 0;
|
||||
if (b->init) {
|
||||
ret = (long)BORINGSSL_LSEEK(b->num, 0, SEEK_CUR);
|
||||
ret = (long)lseek(b->num, 0, SEEK_CUR);
|
||||
}
|
||||
break;
|
||||
case BIO_C_SET_FD:
|
||||
@@ -244,6 +236,10 @@ static long fd_ctrl(BIO *b, int cmd, long num, void *ptr) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fd_puts(BIO *bp, const char *str) {
|
||||
return fd_write(bp, str, strlen(str));
|
||||
}
|
||||
|
||||
static int fd_gets(BIO *bp, char *buf, int size) {
|
||||
char *ptr = buf;
|
||||
char *end = buf + size - 1;
|
||||
@@ -262,9 +258,8 @@ static int fd_gets(BIO *bp, char *buf, int size) {
|
||||
}
|
||||
|
||||
static const BIO_METHOD methods_fdp = {
|
||||
BIO_TYPE_FD, "file descriptor", fd_write, fd_read, NULL /* puts */,
|
||||
fd_gets, fd_ctrl, fd_new, fd_free, NULL /* callback_ctrl */,
|
||||
};
|
||||
BIO_TYPE_FD, "file descriptor", fd_write, fd_read, fd_puts,
|
||||
fd_gets, fd_ctrl, fd_new, fd_free, NULL, };
|
||||
|
||||
const BIO_METHOD *BIO_s_fd(void) { return &methods_fdp; }
|
||||
|
||||
@@ -275,5 +270,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
|
||||
|
||||
+28
-32
@@ -55,17 +55,18 @@
|
||||
* [including the GNU Public Licence.] */
|
||||
|
||||
#if defined(__linux) || defined(__sun) || defined(__hpux)
|
||||
// Following definition aliases fopen to fopen64 on above mentioned
|
||||
// platforms. This makes it possible to open and sequentially access
|
||||
// files larger than 2GB from 32-bit application. It does not allow to
|
||||
// traverse them beyond 2GB with fseek/ftell, but on the other hand *no*
|
||||
// 32-bit platform permits that, not with fseek/ftell. Not to mention
|
||||
// that breaking 2GB limit for seeking would require surgery to *our*
|
||||
// API. But sequential access suffices for practical cases when you
|
||||
// can run into large files, such as fingerprinting, so we can let API
|
||||
// alone. For reference, the list of 32-bit platforms which allow for
|
||||
// sequential access of large files without extra "magic" comprise *BSD,
|
||||
// Darwin, IRIX...
|
||||
/* Following definition aliases fopen to fopen64 on above mentioned
|
||||
* platforms. This makes it possible to open and sequentially access
|
||||
* files larger than 2GB from 32-bit application. It does not allow to
|
||||
* traverse them beyond 2GB with fseek/ftell, but on the other hand *no*
|
||||
* 32-bit platform permits that, not with fseek/ftell. Not to mention
|
||||
* that breaking 2GB limit for seeking would require surgery to *our*
|
||||
* API. But sequential access suffices for practical cases when you
|
||||
* can run into large files, such as fingerprinting, so we can let API
|
||||
* alone. For reference, the list of 32-bit platforms which allow for
|
||||
* sequential access of large files without extra "magic" comprise *BSD,
|
||||
* Darwin, IRIX...
|
||||
*/
|
||||
#ifndef _FILE_OFFSET_BITS
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
@@ -73,17 +74,14 @@
|
||||
|
||||
#include <openssl/bio.h>
|
||||
|
||||
#if !defined(OPENSSL_TRUSTY)
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/buf.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
#define BIO_FP_READ 0x02
|
||||
#define BIO_FP_WRITE 0x04
|
||||
@@ -106,12 +104,13 @@ BIO *BIO_new_file(const char *filename, const char *mode) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = BIO_new_fp(file, BIO_CLOSE);
|
||||
ret = BIO_new(BIO_s_file());
|
||||
if (ret == NULL) {
|
||||
fclose(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BIO_set_fp(ret, file, BIO_CLOSE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -158,7 +157,7 @@ static int file_read(BIO *b, char *out, int outl) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// fread reads at most |outl| bytes, so |ret| fits in an int.
|
||||
/* fread reads at most |outl| bytes, so |ret| fits in an int. */
|
||||
return (int)ret;
|
||||
}
|
||||
|
||||
@@ -185,7 +184,6 @@ static long file_ctrl(BIO *b, int cmd, long num, void *ptr) {
|
||||
switch (cmd) {
|
||||
case BIO_CTRL_RESET:
|
||||
num = 0;
|
||||
OPENSSL_FALLTHROUGH;
|
||||
case BIO_C_FILE_SEEK:
|
||||
ret = (long)fseek(fp, num, 0);
|
||||
break;
|
||||
@@ -207,16 +205,16 @@ static long file_ctrl(BIO *b, int cmd, long num, void *ptr) {
|
||||
b->shutdown = (int)num & BIO_CLOSE;
|
||||
if (num & BIO_FP_APPEND) {
|
||||
if (num & BIO_FP_READ) {
|
||||
OPENSSL_strlcpy(p, "a+", sizeof(p));
|
||||
BUF_strlcpy(p, "a+", sizeof(p));
|
||||
} else {
|
||||
OPENSSL_strlcpy(p, "a", sizeof(p));
|
||||
BUF_strlcpy(p, "a", sizeof(p));
|
||||
}
|
||||
} else if ((num & BIO_FP_READ) && (num & BIO_FP_WRITE)) {
|
||||
OPENSSL_strlcpy(p, "r+", sizeof(p));
|
||||
BUF_strlcpy(p, "r+", sizeof(p));
|
||||
} else if (num & BIO_FP_WRITE) {
|
||||
OPENSSL_strlcpy(p, "w", sizeof(p));
|
||||
BUF_strlcpy(p, "w", sizeof(p));
|
||||
} else if (num & BIO_FP_READ) {
|
||||
OPENSSL_strlcpy(p, "r", sizeof(p));
|
||||
BUF_strlcpy(p, "r", sizeof(p));
|
||||
} else {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_BAD_FOPEN_MODE);
|
||||
ret = 0;
|
||||
@@ -234,7 +232,7 @@ static long file_ctrl(BIO *b, int cmd, long num, void *ptr) {
|
||||
b->init = 1;
|
||||
break;
|
||||
case BIO_C_GET_FILE_PTR:
|
||||
// the ptr parameter is actually a FILE ** in this case.
|
||||
/* the ptr parameter is actually a FILE ** in this case. */
|
||||
if (ptr != NULL) {
|
||||
fpp = (FILE **)ptr;
|
||||
*fpp = (FILE *)b->ptr;
|
||||
@@ -275,13 +273,13 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int file_puts(BIO *bp, const char *str) {
|
||||
return file_write(bp, str, strlen(str));
|
||||
}
|
||||
|
||||
static const BIO_METHOD methods_filep = {
|
||||
BIO_TYPE_FILE, "FILE pointer",
|
||||
file_write, file_read,
|
||||
NULL /* puts */, file_gets,
|
||||
file_ctrl, file_new,
|
||||
file_free, NULL /* callback_ctrl */,
|
||||
};
|
||||
BIO_TYPE_FILE, "FILE pointer", file_write, file_read, file_puts,
|
||||
file_gets, file_ctrl, file_new, file_free, NULL, };
|
||||
|
||||
const BIO_METHOD *BIO_s_file(void) { return &methods_filep; }
|
||||
|
||||
@@ -313,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
|
||||
|
||||
+20
-20
@@ -59,15 +59,13 @@
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
// hexdump_ctx contains the state of a hexdump.
|
||||
/* hexdump_ctx contains the state of a hexdump. */
|
||||
struct hexdump_ctx {
|
||||
BIO *bio;
|
||||
char right_chars[18]; // the contents of the right-hand side, ASCII dump.
|
||||
unsigned used; // number of bytes in the current line.
|
||||
size_t n; // number of bytes total.
|
||||
char right_chars[18]; /* the contents of the right-hand side, ASCII dump. */
|
||||
unsigned used; /* number of bytes in the current line. */
|
||||
size_t n; /* number of bytes total. */
|
||||
unsigned indent;
|
||||
};
|
||||
|
||||
@@ -84,20 +82,22 @@ static char to_char(uint8_t b) {
|
||||
return b;
|
||||
}
|
||||
|
||||
// hexdump_write adds |len| bytes of |data| to the current hex dump described by
|
||||
// |ctx|.
|
||||
/* hexdump_write adds |len| bytes of |data| to the current hex dump described by
|
||||
* |ctx|. */
|
||||
static int hexdump_write(struct hexdump_ctx *ctx, const uint8_t *data,
|
||||
size_t len) {
|
||||
size_t i;
|
||||
char buf[10];
|
||||
unsigned l;
|
||||
|
||||
// Output lines look like:
|
||||
// 00000010 2e 2f 30 31 32 33 34 35 36 37 38 ... 3c 3d // |./0123456789:;<=|
|
||||
// ^ offset ^ extra space ^ ASCII of line
|
||||
/* Output lines look like:
|
||||
* 00000010 2e 2f 30 31 32 33 34 35 36 37 38 ... 3c 3d // |./0123456789:;<=|
|
||||
* ^ offset ^ extra space ^ ASCII of line
|
||||
*/
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
for (i = 0; i < len; i++) {
|
||||
if (ctx->used == 0) {
|
||||
// The beginning of a line.
|
||||
/* The beginning of a line. */
|
||||
BIO_indent(ctx->bio, ctx->indent, UINT_MAX);
|
||||
|
||||
hexbyte(&buf[0], ctx->n >> 24);
|
||||
@@ -114,12 +114,12 @@ static int hexdump_write(struct hexdump_ctx *ctx, const uint8_t *data,
|
||||
buf[2] = ' ';
|
||||
l = 3;
|
||||
if (ctx->used == 7) {
|
||||
// There's an additional space after the 8th byte.
|
||||
/* There's an additional space after the 8th byte. */
|
||||
buf[3] = ' ';
|
||||
l = 4;
|
||||
} else if (ctx->used == 15) {
|
||||
// At the end of the line there's an extra space and the bar for the
|
||||
// right column.
|
||||
/* At the end of the line there's an extra space and the bar for the
|
||||
* right column. */
|
||||
buf[3] = ' ';
|
||||
buf[4] = '|';
|
||||
l = 5;
|
||||
@@ -144,9 +144,9 @@ static int hexdump_write(struct hexdump_ctx *ctx, const uint8_t *data,
|
||||
return 1;
|
||||
}
|
||||
|
||||
// finish flushes any buffered data in |ctx|.
|
||||
/* finish flushes any buffered data in |ctx|. */
|
||||
static int finish(struct hexdump_ctx *ctx) {
|
||||
// See the comments in |hexdump| for the details of this format.
|
||||
/* See the comments in |hexdump| for the details of this format. */
|
||||
const unsigned n_bytes = ctx->used;
|
||||
unsigned l;
|
||||
char buf[5];
|
||||
@@ -155,7 +155,7 @@ static int finish(struct hexdump_ctx *ctx) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
OPENSSL_memset(buf, ' ', 4);
|
||||
memset(buf, ' ', 4);
|
||||
buf[4] = '|';
|
||||
|
||||
for (; ctx->used < 16; ctx->used++) {
|
||||
@@ -180,7 +180,7 @@ static int finish(struct hexdump_ctx *ctx) {
|
||||
|
||||
int BIO_hexdump(BIO *bio, const uint8_t *data, size_t len, unsigned indent) {
|
||||
struct hexdump_ctx ctx;
|
||||
OPENSSL_memset(&ctx, 0, sizeof(ctx));
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
ctx.bio = bio;
|
||||
ctx.indent = indent;
|
||||
|
||||
|
||||
+16
-16
@@ -61,15 +61,15 @@
|
||||
|
||||
#if !defined(OPENSSL_WINDOWS)
|
||||
#if defined(OPENSSL_PNACL)
|
||||
// newlib uses u_short in socket.h without defining it.
|
||||
/* newlib uses u_short in socket.h without defining it. */
|
||||
typedef unsigned short u_short;
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#else
|
||||
OPENSSL_MSVC_PRAGMA(warning(push, 3))
|
||||
#pragma warning(push, 3)
|
||||
#include <winsock2.h>
|
||||
OPENSSL_MSVC_PRAGMA(warning(pop))
|
||||
#pragma warning(pop)
|
||||
typedef int socklen_t;
|
||||
#endif
|
||||
|
||||
@@ -78,34 +78,34 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
// BIO_ip_and_port_to_socket_and_addr creates a socket and fills in |*out_addr|
|
||||
// and |*out_addr_length| with the correct values for connecting to |hostname|
|
||||
// on |port_str|. It returns one on success or zero on error.
|
||||
/* BIO_ip_and_port_to_socket_and_addr creates a socket and fills in |*out_addr|
|
||||
* and |*out_addr_length| with the correct values for connecting to |hostname|
|
||||
* on |port_str|. It returns one on success or zero on error. */
|
||||
int bio_ip_and_port_to_socket_and_addr(int *out_sock,
|
||||
struct sockaddr_storage *out_addr,
|
||||
socklen_t *out_addr_length,
|
||||
const char *hostname,
|
||||
const char *port_str);
|
||||
|
||||
// BIO_socket_nbio sets whether |sock| is non-blocking. It returns one on
|
||||
// success and zero otherwise.
|
||||
/* BIO_socket_nbio sets whether |sock| is non-blocking. It returns one on
|
||||
* success and zero otherwise. */
|
||||
int bio_socket_nbio(int sock, int on);
|
||||
|
||||
// BIO_clear_socket_error clears the last system socket error.
|
||||
//
|
||||
// TODO(fork): remove all callers of this.
|
||||
/* BIO_clear_socket_error clears the last system socket error.
|
||||
*
|
||||
* TODO(fork): remove all callers of this. */
|
||||
void bio_clear_socket_error(void);
|
||||
|
||||
// BIO_sock_error returns the last socket error on |sock|.
|
||||
/* BIO_sock_error returns the last socket error on |sock|. */
|
||||
int bio_sock_error(int sock);
|
||||
|
||||
// BIO_fd_should_retry returns non-zero if |return_value| indicates an error
|
||||
// and |errno| indicates that it's non-fatal.
|
||||
/* BIO_fd_should_retry returns non-zero if |return_value| indicates an error
|
||||
* and |errno| indicates that it's non-fatal. */
|
||||
int bio_fd_should_retry(int return_value);
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} // extern C
|
||||
} /* extern C */
|
||||
#endif
|
||||
|
||||
#endif // OPENSSL_HEADER_BIO_INTERNAL_H
|
||||
#endif /* OPENSSL_HEADER_BIO_INTERNAL_H */
|
||||
|
||||
+388
-73
@@ -55,29 +55,34 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/buf.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
struct bio_bio_st {
|
||||
BIO *peer; // NULL if buf == NULL.
|
||||
// If peer != NULL, then peer->ptr is also a bio_bio_st,
|
||||
// and its "peer" member points back to us.
|
||||
// peer != NULL iff init != 0 in the BIO.
|
||||
BIO *peer; /* NULL if buf == NULL.
|
||||
* If peer != NULL, then peer->ptr is also a bio_bio_st,
|
||||
* and its "peer" member points back to us.
|
||||
* peer != NULL iff init != 0 in the BIO. */
|
||||
|
||||
// This is for what we write (i.e. reading uses peer's struct):
|
||||
int closed; // valid iff peer != NULL
|
||||
size_t len; // valid iff buf != NULL; 0 if peer == NULL
|
||||
size_t offset; // valid iff buf != NULL; 0 if len == 0
|
||||
/* This is for what we write (i.e. reading uses peer's struct): */
|
||||
int closed; /* valid iff peer != NULL */
|
||||
size_t len; /* valid iff buf != NULL; 0 if peer == NULL */
|
||||
size_t offset; /* valid iff buf != NULL; 0 if len == 0 */
|
||||
size_t size;
|
||||
uint8_t *buf; // "size" elements (if != NULL)
|
||||
uint8_t *buf; /* "size" elements (if != NULL) */
|
||||
char buf_externally_allocated; /* true iff buf was externally allocated. */
|
||||
|
||||
size_t request; // valid iff peer != NULL; 0 if len != 0,
|
||||
// otherwise set by peer to number of bytes
|
||||
// it (unsuccessfully) tried to read,
|
||||
// never more than buffer space (size-len) warrants.
|
||||
char zero_copy_read_lock; /* true iff a zero copy read operation
|
||||
* is in progress. */
|
||||
char zero_copy_write_lock; /* true iff a zero copy write operation
|
||||
* is in progress. */
|
||||
|
||||
size_t request; /* valid iff peer != NULL; 0 if len != 0,
|
||||
* otherwise set by peer to number of bytes
|
||||
* it (unsuccessfully) tried to read,
|
||||
* never more than buffer space (size-len) warrants. */
|
||||
};
|
||||
|
||||
static int bio_new(BIO *bio) {
|
||||
@@ -87,9 +92,9 @@ static int bio_new(BIO *bio) {
|
||||
if (b == NULL) {
|
||||
return 0;
|
||||
}
|
||||
OPENSSL_memset(b, 0, sizeof(struct bio_bio_st));
|
||||
memset(b, 0, sizeof(struct bio_bio_st));
|
||||
|
||||
b->size = 17 * 1024; // enough for one TLS record (just a default)
|
||||
b->size = 17 * 1024; /* enough for one TLS record (just a default) */
|
||||
bio->ptr = b;
|
||||
return 1;
|
||||
}
|
||||
@@ -140,12 +145,263 @@ static int bio_free(BIO *bio) {
|
||||
bio_destroy_pair(bio);
|
||||
}
|
||||
|
||||
OPENSSL_free(b->buf);
|
||||
if (!b->buf_externally_allocated) {
|
||||
OPENSSL_free(b->buf);
|
||||
}
|
||||
|
||||
OPENSSL_free(b);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static size_t bio_zero_copy_get_read_buf(struct bio_bio_st* peer_b,
|
||||
uint8_t** out_read_buf,
|
||||
size_t* out_buf_offset) {
|
||||
size_t max_available;
|
||||
if (peer_b->len > peer_b->size - peer_b->offset) {
|
||||
/* Only the first half of the ring buffer can be read. */
|
||||
max_available = peer_b->size - peer_b->offset;
|
||||
} else {
|
||||
max_available = peer_b->len;
|
||||
}
|
||||
|
||||
*out_read_buf = peer_b->buf;
|
||||
*out_buf_offset = peer_b->offset;
|
||||
return max_available;
|
||||
}
|
||||
|
||||
int BIO_zero_copy_get_read_buf(BIO* bio, uint8_t** out_read_buf,
|
||||
size_t* out_buf_offset,
|
||||
size_t* out_available_bytes) {
|
||||
struct bio_bio_st* b;
|
||||
struct bio_bio_st* peer_b;
|
||||
size_t max_available;
|
||||
*out_available_bytes = 0;
|
||||
|
||||
BIO_clear_retry_flags(bio);
|
||||
|
||||
if (!bio->init) {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
b = bio->ptr;
|
||||
|
||||
if (!b || !b->peer) {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
peer_b = b->peer->ptr;
|
||||
if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (peer_b->zero_copy_read_lock) {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
peer_b->request = 0; /* Is not used by zero-copy API. */
|
||||
|
||||
max_available =
|
||||
bio_zero_copy_get_read_buf(peer_b, out_read_buf, out_buf_offset);
|
||||
|
||||
assert(peer_b->buf != NULL);
|
||||
if (max_available > 0) {
|
||||
peer_b->zero_copy_read_lock = 1;
|
||||
}
|
||||
|
||||
*out_available_bytes = max_available;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BIO_zero_copy_get_read_buf_done(BIO* bio, size_t bytes_read) {
|
||||
struct bio_bio_st* b;
|
||||
struct bio_bio_st* peer_b;
|
||||
size_t max_available;
|
||||
size_t dummy_read_offset;
|
||||
uint8_t* dummy_read_buf;
|
||||
|
||||
assert(BIO_get_retry_flags(bio) == 0);
|
||||
|
||||
if (!bio->init) {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
b = bio->ptr;
|
||||
|
||||
if (!b || !b->peer) {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
peer_b = b->peer->ptr;
|
||||
if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!peer_b->zero_copy_read_lock) {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
max_available =
|
||||
bio_zero_copy_get_read_buf(peer_b, &dummy_read_buf, &dummy_read_offset);
|
||||
if (bytes_read > max_available) {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(peer_b->len >= bytes_read);
|
||||
peer_b->len -= bytes_read;
|
||||
assert(peer_b->offset + bytes_read <= peer_b->size);
|
||||
|
||||
/* Move read offset. If zero_copy_write_lock == 1 we must advance the
|
||||
* offset even if buffer becomes empty, to make sure
|
||||
* write_offset = (offset + len) mod size does not change. */
|
||||
if (peer_b->offset + bytes_read == peer_b->size ||
|
||||
(!peer_b->zero_copy_write_lock && peer_b->len == 0)) {
|
||||
peer_b->offset = 0;
|
||||
} else {
|
||||
peer_b->offset += bytes_read;
|
||||
}
|
||||
|
||||
bio->num_read += bytes_read;
|
||||
peer_b->zero_copy_read_lock = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static size_t bio_zero_copy_get_write_buf(struct bio_bio_st* b,
|
||||
uint8_t** out_write_buf,
|
||||
size_t* out_buf_offset) {
|
||||
size_t write_offset;
|
||||
size_t max_available;
|
||||
|
||||
assert(b->len <= b->size);
|
||||
|
||||
write_offset = b->offset + b->len;
|
||||
|
||||
if (write_offset >= b->size) {
|
||||
/* Only the first half of the ring buffer can be written to. */
|
||||
write_offset -= b->size;
|
||||
/* write up to the start of the ring buffer. */
|
||||
max_available = b->offset - write_offset;
|
||||
} else {
|
||||
/* write up to the end the buffer. */
|
||||
max_available = b->size - write_offset;
|
||||
}
|
||||
|
||||
*out_write_buf = b->buf;
|
||||
*out_buf_offset = write_offset;
|
||||
return max_available;
|
||||
}
|
||||
|
||||
int BIO_zero_copy_get_write_buf(BIO* bio, uint8_t** out_write_buf,
|
||||
size_t* out_buf_offset,
|
||||
size_t* out_available_bytes) {
|
||||
struct bio_bio_st* b;
|
||||
struct bio_bio_st* peer_b;
|
||||
size_t max_available;
|
||||
|
||||
*out_available_bytes = 0;
|
||||
BIO_clear_retry_flags(bio);
|
||||
|
||||
if (!bio->init) {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
b = bio->ptr;
|
||||
|
||||
if (!b || !b->buf || !b->peer) {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
|
||||
return 0;
|
||||
}
|
||||
peer_b = b->peer->ptr;
|
||||
if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(b->buf != NULL);
|
||||
|
||||
if (b->zero_copy_write_lock) {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
b->request = 0;
|
||||
if (b->closed) {
|
||||
/* Bio is already closed. */
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_BROKEN_PIPE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
max_available = bio_zero_copy_get_write_buf(b, out_write_buf, out_buf_offset);
|
||||
|
||||
if (max_available > 0) {
|
||||
b->zero_copy_write_lock = 1;
|
||||
}
|
||||
|
||||
*out_available_bytes = max_available;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BIO_zero_copy_get_write_buf_done(BIO* bio, size_t bytes_written) {
|
||||
struct bio_bio_st* b;
|
||||
struct bio_bio_st* peer_b;
|
||||
|
||||
size_t rest;
|
||||
size_t dummy_write_offset;
|
||||
uint8_t* dummy_write_buf;
|
||||
|
||||
if (!bio->init) {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
b = bio->ptr;
|
||||
|
||||
if (!b || !b->buf || !b->peer) {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
|
||||
return 0;
|
||||
}
|
||||
peer_b = b->peer->ptr;
|
||||
if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
b->request = 0;
|
||||
if (b->closed) {
|
||||
/* BIO is already closed. */
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_BROKEN_PIPE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!b->zero_copy_write_lock) {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rest = bio_zero_copy_get_write_buf(b, &dummy_write_buf, &dummy_write_offset);
|
||||
|
||||
if (bytes_written > rest) {
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bio->num_write += bytes_written;
|
||||
/* Move write offset. */
|
||||
b->len += bytes_written;
|
||||
b->zero_copy_write_lock = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int bio_read(BIO *bio, char *buf, int size_) {
|
||||
size_t size = size_;
|
||||
size_t rest;
|
||||
@@ -164,38 +420,38 @@ static int bio_read(BIO *bio, char *buf, int size_) {
|
||||
assert(peer_b != NULL);
|
||||
assert(peer_b->buf != NULL);
|
||||
|
||||
peer_b->request = 0; // will be set in "retry_read" situation
|
||||
peer_b->request = 0; /* will be set in "retry_read" situation */
|
||||
|
||||
if (buf == NULL || size == 0) {
|
||||
if (buf == NULL || size == 0 || peer_b->zero_copy_read_lock) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (peer_b->len == 0) {
|
||||
if (peer_b->closed) {
|
||||
return 0; // writer has closed, and no data is left
|
||||
return 0; /* writer has closed, and no data is left */
|
||||
} else {
|
||||
BIO_set_retry_read(bio); // buffer is empty
|
||||
BIO_set_retry_read(bio); /* buffer is empty */
|
||||
if (size <= peer_b->size) {
|
||||
peer_b->request = size;
|
||||
} else {
|
||||
// don't ask for more than the peer can
|
||||
// deliver in one write
|
||||
/* don't ask for more than the peer can
|
||||
* deliver in one write */
|
||||
peer_b->request = peer_b->size;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// we can read
|
||||
/* we can read */
|
||||
if (peer_b->len < size) {
|
||||
size = peer_b->len;
|
||||
}
|
||||
|
||||
// now read "size" bytes
|
||||
/* now read "size" bytes */
|
||||
rest = size;
|
||||
|
||||
assert(rest > 0);
|
||||
// one or two iterations
|
||||
/* one or two iterations */
|
||||
do {
|
||||
size_t chunk;
|
||||
|
||||
@@ -203,15 +459,18 @@ static int bio_read(BIO *bio, char *buf, int size_) {
|
||||
if (peer_b->offset + rest <= peer_b->size) {
|
||||
chunk = rest;
|
||||
} else {
|
||||
// wrap around ring buffer
|
||||
/* wrap around ring buffer */
|
||||
chunk = peer_b->size - peer_b->offset;
|
||||
}
|
||||
assert(peer_b->offset + chunk <= peer_b->size);
|
||||
|
||||
OPENSSL_memcpy(buf, peer_b->buf + peer_b->offset, chunk);
|
||||
memcpy(buf, peer_b->buf + peer_b->offset, chunk);
|
||||
|
||||
peer_b->len -= chunk;
|
||||
if (peer_b->len) {
|
||||
/* If zero_copy_write_lock == 1 we must advance the offset even if buffer
|
||||
* becomes empty, to make sure write_offset = (offset + len) % size
|
||||
* does not change. */
|
||||
if (peer_b->len || peer_b->zero_copy_write_lock) {
|
||||
peer_b->offset += chunk;
|
||||
assert(peer_b->offset <= peer_b->size);
|
||||
if (peer_b->offset == peer_b->size) {
|
||||
@@ -219,7 +478,7 @@ static int bio_read(BIO *bio, char *buf, int size_) {
|
||||
}
|
||||
buf += chunk;
|
||||
} else {
|
||||
// buffer now empty, no need to advance "buf"
|
||||
/* buffer now empty, no need to advance "buf" */
|
||||
assert(chunk == rest);
|
||||
peer_b->offset = 0;
|
||||
}
|
||||
@@ -245,9 +504,13 @@ static int bio_write(BIO *bio, const char *buf, int num_) {
|
||||
assert(b->peer != NULL);
|
||||
assert(b->buf != NULL);
|
||||
|
||||
if (b->zero_copy_write_lock) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
b->request = 0;
|
||||
if (b->closed) {
|
||||
// we already closed
|
||||
/* we already closed */
|
||||
OPENSSL_PUT_ERROR(BIO, BIO_R_BROKEN_PIPE);
|
||||
return -1;
|
||||
}
|
||||
@@ -255,20 +518,20 @@ static int bio_write(BIO *bio, const char *buf, int num_) {
|
||||
assert(b->len <= b->size);
|
||||
|
||||
if (b->len == b->size) {
|
||||
BIO_set_retry_write(bio); // buffer is full
|
||||
BIO_set_retry_write(bio); /* buffer is full */
|
||||
return -1;
|
||||
}
|
||||
|
||||
// we can write
|
||||
/* we can write */
|
||||
if (num > b->size - b->len) {
|
||||
num = b->size - b->len;
|
||||
}
|
||||
|
||||
// now write "num" bytes
|
||||
/* now write "num" bytes */
|
||||
rest = num;
|
||||
|
||||
assert(rest > 0);
|
||||
// one or two iterations
|
||||
/* one or two iterations */
|
||||
do {
|
||||
size_t write_offset;
|
||||
size_t chunk;
|
||||
@@ -279,16 +542,16 @@ static int bio_write(BIO *bio, const char *buf, int num_) {
|
||||
if (write_offset >= b->size) {
|
||||
write_offset -= b->size;
|
||||
}
|
||||
// b->buf[write_offset] is the first byte we can write to.
|
||||
/* b->buf[write_offset] is the first byte we can write to. */
|
||||
|
||||
if (write_offset + rest <= b->size) {
|
||||
chunk = rest;
|
||||
} else {
|
||||
// wrap around ring buffer
|
||||
/* wrap around ring buffer */
|
||||
chunk = b->size - write_offset;
|
||||
}
|
||||
|
||||
OPENSSL_memcpy(b->buf + write_offset, buf, chunk);
|
||||
memcpy(b->buf + write_offset, buf, chunk);
|
||||
|
||||
b->len += chunk;
|
||||
|
||||
@@ -301,8 +564,9 @@ static int bio_write(BIO *bio, const char *buf, int num_) {
|
||||
return num;
|
||||
}
|
||||
|
||||
static int bio_make_pair(BIO *bio1, BIO *bio2, size_t writebuf1_len,
|
||||
size_t writebuf2_len) {
|
||||
static int bio_make_pair(BIO* bio1, BIO* bio2,
|
||||
size_t writebuf1_len, uint8_t* ext_writebuf1,
|
||||
size_t writebuf2_len, uint8_t* ext_writebuf2) {
|
||||
struct bio_bio_st *b1, *b2;
|
||||
|
||||
assert(bio1 != NULL);
|
||||
@@ -316,14 +580,23 @@ static int bio_make_pair(BIO *bio1, BIO *bio2, size_t writebuf1_len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(b1->buf_externally_allocated == 0);
|
||||
assert(b2->buf_externally_allocated == 0);
|
||||
|
||||
if (b1->buf == NULL) {
|
||||
if (writebuf1_len) {
|
||||
b1->size = writebuf1_len;
|
||||
}
|
||||
b1->buf = OPENSSL_malloc(b1->size);
|
||||
if (b1->buf == NULL) {
|
||||
OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
if (!ext_writebuf1) {
|
||||
b1->buf_externally_allocated = 0;
|
||||
b1->buf = OPENSSL_malloc(b1->size);
|
||||
if (b1->buf == NULL) {
|
||||
OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
b1->buf = ext_writebuf1;
|
||||
b1->buf_externally_allocated = 1;
|
||||
}
|
||||
b1->len = 0;
|
||||
b1->offset = 0;
|
||||
@@ -333,10 +606,16 @@ static int bio_make_pair(BIO *bio1, BIO *bio2, size_t writebuf1_len,
|
||||
if (writebuf2_len) {
|
||||
b2->size = writebuf2_len;
|
||||
}
|
||||
b2->buf = OPENSSL_malloc(b2->size);
|
||||
if (b2->buf == NULL) {
|
||||
OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
if (!ext_writebuf2) {
|
||||
b2->buf_externally_allocated = 0;
|
||||
b2->buf = OPENSSL_malloc(b2->size);
|
||||
if (b2->buf == NULL) {
|
||||
OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
b2->buf = ext_writebuf2;
|
||||
b2->buf_externally_allocated = 1;
|
||||
}
|
||||
b2->len = 0;
|
||||
b2->offset = 0;
|
||||
@@ -345,9 +624,13 @@ static int bio_make_pair(BIO *bio1, BIO *bio2, size_t writebuf1_len,
|
||||
b1->peer = bio2;
|
||||
b1->closed = 0;
|
||||
b1->request = 0;
|
||||
b1->zero_copy_read_lock = 0;
|
||||
b1->zero_copy_write_lock = 0;
|
||||
b2->peer = bio1;
|
||||
b2->closed = 0;
|
||||
b2->request = 0;
|
||||
b2->zero_copy_read_lock = 0;
|
||||
b2->zero_copy_write_lock = 0;
|
||||
|
||||
bio1->init = 1;
|
||||
bio2->init = 1;
|
||||
@@ -362,15 +645,15 @@ static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr) {
|
||||
assert(b != NULL);
|
||||
|
||||
switch (cmd) {
|
||||
// specific CTRL codes
|
||||
/* specific CTRL codes */
|
||||
|
||||
case BIO_C_GET_WRITE_BUF_SIZE:
|
||||
ret = (long)b->size;
|
||||
break;
|
||||
|
||||
case BIO_C_GET_WRITE_GUARANTEE:
|
||||
// How many bytes can the caller feed to the next write
|
||||
// without having to keep any?
|
||||
/* How many bytes can the caller feed to the next write
|
||||
* without having to keep any? */
|
||||
if (b->peer == NULL || b->closed) {
|
||||
ret = 0;
|
||||
} else {
|
||||
@@ -379,28 +662,28 @@ static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr) {
|
||||
break;
|
||||
|
||||
case BIO_C_GET_READ_REQUEST:
|
||||
// If the peer unsuccessfully tried to read, how many bytes
|
||||
// were requested? (As with BIO_CTRL_PENDING, that number
|
||||
// can usually be treated as boolean.)
|
||||
/* If the peer unsuccessfully tried to read, how many bytes
|
||||
* were requested? (As with BIO_CTRL_PENDING, that number
|
||||
* can usually be treated as boolean.) */
|
||||
ret = (long)b->request;
|
||||
break;
|
||||
|
||||
case BIO_C_RESET_READ_REQUEST:
|
||||
// Reset request. (Can be useful after read attempts
|
||||
// at the other side that are meant to be non-blocking,
|
||||
// e.g. when probing SSL_read to see if any data is
|
||||
// available.)
|
||||
/* Reset request. (Can be useful after read attempts
|
||||
* at the other side that are meant to be non-blocking,
|
||||
* e.g. when probing SSL_read to see if any data is
|
||||
* available.) */
|
||||
b->request = 0;
|
||||
ret = 1;
|
||||
break;
|
||||
|
||||
case BIO_C_SHUTDOWN_WR:
|
||||
// similar to shutdown(..., SHUT_WR)
|
||||
/* similar to shutdown(..., SHUT_WR) */
|
||||
b->closed = 1;
|
||||
ret = 1;
|
||||
break;
|
||||
|
||||
// standard CTRL codes follow
|
||||
/* standard CTRL codes follow */
|
||||
|
||||
case BIO_CTRL_GET_CLOSE:
|
||||
ret = bio->shutdown;
|
||||
@@ -449,30 +732,62 @@ static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bio_puts(BIO *bio, const char *str) {
|
||||
return bio_write(bio, str, strlen(str));
|
||||
}
|
||||
|
||||
static const BIO_METHOD methods_biop = {
|
||||
BIO_TYPE_BIO, "BIO pair", bio_write, bio_read, NULL /* puts */,
|
||||
NULL /* gets */, bio_ctrl, bio_new, bio_free, NULL /* callback_ctrl */,
|
||||
BIO_TYPE_BIO, "BIO pair", bio_write, bio_read,
|
||||
bio_puts, NULL /* no bio_gets */, bio_ctrl, bio_new,
|
||||
bio_free, NULL /* no bio_callback_ctrl */
|
||||
};
|
||||
|
||||
static const BIO_METHOD *bio_s_bio(void) { return &methods_biop; }
|
||||
|
||||
int BIO_new_bio_pair(BIO** bio1_p, size_t writebuf1_len,
|
||||
BIO** bio2_p, size_t writebuf2_len) {
|
||||
BIO *bio1 = BIO_new(bio_s_bio());
|
||||
BIO *bio2 = BIO_new(bio_s_bio());
|
||||
if (bio1 == NULL || bio2 == NULL ||
|
||||
!bio_make_pair(bio1, bio2, writebuf1_len, writebuf2_len)) {
|
||||
int BIO_new_bio_pair(BIO** bio1_p, size_t writebuf1,
|
||||
BIO** bio2_p, size_t writebuf2) {
|
||||
return BIO_new_bio_pair_external_buf(bio1_p, writebuf1, NULL, bio2_p,
|
||||
writebuf2, NULL);
|
||||
}
|
||||
|
||||
int BIO_new_bio_pair_external_buf(BIO** bio1_p, size_t writebuf1_len,
|
||||
uint8_t* ext_writebuf1,
|
||||
BIO** bio2_p, size_t writebuf2_len,
|
||||
uint8_t* ext_writebuf2) {
|
||||
BIO *bio1 = NULL, *bio2 = NULL;
|
||||
int ret = 0;
|
||||
|
||||
/* External buffers must have sizes greater than 0. */
|
||||
if ((ext_writebuf1 && !writebuf1_len) || (ext_writebuf2 && !writebuf2_len)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
bio1 = BIO_new(bio_s_bio());
|
||||
if (bio1 == NULL) {
|
||||
goto err;
|
||||
}
|
||||
bio2 = BIO_new(bio_s_bio());
|
||||
if (bio2 == NULL) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!bio_make_pair(bio1, bio2, writebuf1_len, ext_writebuf1, writebuf2_len,
|
||||
ext_writebuf2)) {
|
||||
goto err;
|
||||
}
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
if (ret == 0) {
|
||||
BIO_free(bio1);
|
||||
bio1 = NULL;
|
||||
BIO_free(bio2);
|
||||
*bio1_p = NULL;
|
||||
*bio2_p = NULL;
|
||||
return 0;
|
||||
bio2 = NULL;
|
||||
}
|
||||
|
||||
*bio1_p = bio1;
|
||||
*bio2_p = bio2;
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t BIO_ctrl_get_read_request(BIO *bio) {
|
||||
|
||||
+10
-6
@@ -54,6 +54,10 @@
|
||||
* copied and put under another distribution licence
|
||||
* [including the GNU Public Licence.] */
|
||||
|
||||
#if !defined(_POSIX_C_SOURCE)
|
||||
#define _POSIX_C_SOURCE 201410L /* for snprintf, vprintf etc */
|
||||
#endif
|
||||
|
||||
#include <openssl/bio.h>
|
||||
|
||||
#include <assert.h>
|
||||
@@ -73,13 +77,13 @@ int BIO_printf(BIO *bio, const char *format, ...) {
|
||||
va_end(args);
|
||||
|
||||
#if defined(OPENSSL_WINDOWS)
|
||||
// On Windows, vsnprintf returns -1 rather than the requested length on
|
||||
// truncation
|
||||
/* On Windows, vsnprintf returns -1 rather than the requested length on
|
||||
* truncation */
|
||||
if (out_len < 0) {
|
||||
va_start(args, format);
|
||||
out_len = _vscprintf(format, args);
|
||||
va_end(args);
|
||||
assert(out_len >= (int)sizeof(buf));
|
||||
assert(out_len >= sizeof(buf));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -89,9 +93,9 @@ int BIO_printf(BIO *bio, const char *format, ...) {
|
||||
|
||||
if ((size_t) out_len >= sizeof(buf)) {
|
||||
const int requested_len = out_len;
|
||||
// The output was truncated. Note that vsnprintf's return value
|
||||
// does not include a trailing NUL, but the buffer must be sized
|
||||
// for it.
|
||||
/* The output was truncated. Note that vsnprintf's return value
|
||||
* does not include a trailing NUL, but the buffer must be sized
|
||||
* for it. */
|
||||
out = OPENSSL_malloc(requested_len + 1);
|
||||
out_malloced = 1;
|
||||
if (out == NULL) {
|
||||
|
||||
+9
-20
@@ -57,19 +57,17 @@
|
||||
|
||||
#include <openssl/bio.h>
|
||||
|
||||
#if !defined(OPENSSL_TRUSTY)
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
#if !defined(OPENSSL_WINDOWS)
|
||||
#include <unistd.h>
|
||||
#else
|
||||
OPENSSL_MSVC_PRAGMA(warning(push, 3))
|
||||
#pragma warning(push, 3)
|
||||
#include <winsock2.h>
|
||||
OPENSSL_MSVC_PRAGMA(warning(pop))
|
||||
#pragma warning(pop)
|
||||
|
||||
OPENSSL_MSVC_PRAGMA(comment(lib, "Ws2_32.lib"))
|
||||
#pragma comment(lib, "Ws2_32.lib")
|
||||
#endif
|
||||
|
||||
#include "internal.h"
|
||||
@@ -112,11 +110,7 @@ static int sock_read(BIO *b, char *out, int outl) {
|
||||
}
|
||||
|
||||
bio_clear_socket_error();
|
||||
#if defined(OPENSSL_WINDOWS)
|
||||
ret = recv(b->num, out, outl, 0);
|
||||
#else
|
||||
ret = read(b->num, out, outl);
|
||||
#endif
|
||||
BIO_clear_retry_flags(b);
|
||||
if (ret <= 0) {
|
||||
if (bio_fd_should_retry(ret)) {
|
||||
@@ -130,11 +124,7 @@ static int sock_write(BIO *b, const char *in, int inl) {
|
||||
int ret;
|
||||
|
||||
bio_clear_socket_error();
|
||||
#if defined(OPENSSL_WINDOWS)
|
||||
ret = send(b->num, in, inl, 0);
|
||||
#else
|
||||
ret = write(b->num, in, inl);
|
||||
#endif
|
||||
BIO_clear_retry_flags(b);
|
||||
if (ret <= 0) {
|
||||
if (bio_fd_should_retry(ret)) {
|
||||
@@ -144,6 +134,10 @@ static int sock_write(BIO *b, const char *in, int inl) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sock_puts(BIO *bp, const char *str) {
|
||||
return sock_write(bp, str, strlen(str));
|
||||
}
|
||||
|
||||
static long sock_ctrl(BIO *b, int cmd, long num, void *ptr) {
|
||||
long ret = 1;
|
||||
int *ip;
|
||||
@@ -183,11 +177,8 @@ static long sock_ctrl(BIO *b, int cmd, long num, void *ptr) {
|
||||
}
|
||||
|
||||
static const BIO_METHOD methods_sockp = {
|
||||
BIO_TYPE_SOCKET, "socket",
|
||||
sock_write, sock_read,
|
||||
NULL /* puts */, NULL /* gets, */,
|
||||
sock_ctrl, sock_new,
|
||||
sock_free, NULL /* callback_ctrl */,
|
||||
BIO_TYPE_SOCKET, "socket", sock_write, sock_read, sock_puts,
|
||||
NULL /* gets, */, sock_ctrl, sock_new, sock_free, NULL,
|
||||
};
|
||||
|
||||
const BIO_METHOD *BIO_s_socket(void) { return &methods_sockp; }
|
||||
@@ -202,5 +193,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>
|
||||
@@ -28,14 +26,13 @@
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#else
|
||||
OPENSSL_MSVC_PRAGMA(warning(push, 3))
|
||||
#pragma warning(push, 3)
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
OPENSSL_MSVC_PRAGMA(warning(pop))
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include "internal.h"
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
int bio_ip_and_port_to_socket_and_addr(int *out_sock,
|
||||
@@ -48,7 +45,7 @@ int bio_ip_and_port_to_socket_and_addr(int *out_sock,
|
||||
|
||||
*out_sock = -1;
|
||||
|
||||
OPENSSL_memset(&hint, 0, sizeof(hint));
|
||||
memset(&hint, 0, sizeof(hint));
|
||||
hint.ai_family = AF_UNSPEC;
|
||||
hint.ai_socktype = SOCK_STREAM;
|
||||
|
||||
@@ -65,8 +62,8 @@ int bio_ip_and_port_to_socket_and_addr(int *out_sock,
|
||||
if ((size_t) cur->ai_addrlen > sizeof(struct sockaddr_storage)) {
|
||||
continue;
|
||||
}
|
||||
OPENSSL_memset(out_addr, 0, sizeof(struct sockaddr_storage));
|
||||
OPENSSL_memcpy(out_addr, cur->ai_addr, cur->ai_addrlen);
|
||||
memset(out_addr, 0, sizeof(struct sockaddr_storage));
|
||||
memcpy(out_addr, cur->ai_addr, cur->ai_addrlen);
|
||||
*out_addr_length = cur->ai_addrlen;
|
||||
|
||||
*out_sock = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol);
|
||||
@@ -114,5 +111,3 @@ int bio_sock_error(int sock) {
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
#endif // OPENSSL_TRUSTY
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
include_directories(../../include)
|
||||
|
||||
if (${ARCH} STREQUAL "x86_64")
|
||||
set(
|
||||
BN_ARCH_SOURCES
|
||||
|
||||
x86_64-mont.${ASM_EXT}
|
||||
x86_64-mont5.${ASM_EXT}
|
||||
rsaz-x86_64.${ASM_EXT}
|
||||
rsaz-avx2.${ASM_EXT}
|
||||
|
||||
rsaz_exp.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if (${ARCH} STREQUAL "x86")
|
||||
set(
|
||||
BN_ARCH_SOURCES
|
||||
|
||||
bn-586.${ASM_EXT}
|
||||
co-586.${ASM_EXT}
|
||||
x86-mont.${ASM_EXT}
|
||||
)
|
||||
endif()
|
||||
|
||||
if (${ARCH} STREQUAL "arm")
|
||||
set(
|
||||
BN_ARCH_SOURCES
|
||||
|
||||
armv4-mont.${ASM_EXT}
|
||||
)
|
||||
endif()
|
||||
|
||||
if (${ARCH} STREQUAL "aarch64")
|
||||
set(
|
||||
BN_ARCH_SOURCES
|
||||
|
||||
armv8-mont.${ASM_EXT}
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(
|
||||
bn
|
||||
|
||||
OBJECT
|
||||
|
||||
add.c
|
||||
asm/x86_64-gcc.c
|
||||
bn.c
|
||||
bn_asn1.c
|
||||
cmp.c
|
||||
convert.c
|
||||
ctx.c
|
||||
div.c
|
||||
exponentiation.c
|
||||
generic.c
|
||||
gcd.c
|
||||
kronecker.c
|
||||
montgomery.c
|
||||
mul.c
|
||||
prime.c
|
||||
random.c
|
||||
shift.c
|
||||
sqrt.c
|
||||
|
||||
${BN_ARCH_SOURCES}
|
||||
)
|
||||
|
||||
perlasm(x86_64-mont.${ASM_EXT} asm/x86_64-mont.pl)
|
||||
perlasm(x86_64-mont5.${ASM_EXT} asm/x86_64-mont5.pl)
|
||||
perlasm(rsaz-x86_64.${ASM_EXT} asm/rsaz-x86_64.pl)
|
||||
perlasm(rsaz-avx2.${ASM_EXT} asm/rsaz-avx2.pl)
|
||||
perlasm(bn-586.${ASM_EXT} asm/bn-586.pl)
|
||||
perlasm(co-586.${ASM_EXT} asm/co-586.pl)
|
||||
perlasm(x86-mont.${ASM_EXT} asm/x86-mont.pl)
|
||||
perlasm(armv4-mont.${ASM_EXT} asm/armv4-mont.pl)
|
||||
perlasm(armv8-mont.${ASM_EXT} asm/armv8-mont.pl)
|
||||
|
||||
add_executable(
|
||||
bn_test
|
||||
|
||||
bn_test.cc
|
||||
|
||||
$<TARGET_OBJECTS:test_support>
|
||||
)
|
||||
|
||||
target_link_libraries(bn_test crypto)
|
||||
add_dependencies(all_tests bn_test)
|
||||
+377
@@ -0,0 +1,377 @@
|
||||
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* This package is an SSL implementation written
|
||||
* by Eric Young (eay@cryptsoft.com).
|
||||
* The implementation was written so as to conform with Netscapes SSL.
|
||||
*
|
||||
* This library is free for commercial and non-commercial use as long as
|
||||
* the following conditions are aheared to. The following conditions
|
||||
* apply to all code found in this distribution, be it the RC4, RSA,
|
||||
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
|
||||
* included with this distribution is covered by the same copyright terms
|
||||
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||
*
|
||||
* Copyright remains Eric Young's, and as such any Copyright notices in
|
||||
* the code are not to be removed.
|
||||
* If this package is used in a product, Eric Young should be given attribution
|
||||
* as the author of the parts of the library used.
|
||||
* This can be in the form of a textual message at program startup or
|
||||
* in documentation (online or textual) provided with the package.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* "This product includes cryptographic software written by
|
||||
* Eric Young (eay@cryptsoft.com)"
|
||||
* The word 'cryptographic' can be left out if the rouines from the library
|
||||
* being used are not cryptographic related :-).
|
||||
* 4. If you include any Windows specific code (or a derivative thereof) from
|
||||
* the apps directory (application code) you must include an acknowledgement:
|
||||
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* The licence and distribution terms for any publically available version or
|
||||
* derivative of this code cannot be changed. i.e. this code cannot simply be
|
||||
* copied and put under another distribution licence
|
||||
* [including the GNU Public Licence.] */
|
||||
|
||||
#include <openssl/bn.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
|
||||
const BIGNUM *tmp;
|
||||
int a_neg = a->neg, ret;
|
||||
|
||||
/* a + b a+b
|
||||
* a + -b a-b
|
||||
* -a + b b-a
|
||||
* -a + -b -(a+b)
|
||||
*/
|
||||
if (a_neg ^ b->neg) {
|
||||
/* only one is negative */
|
||||
if (a_neg) {
|
||||
tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
|
||||
/* we are now a - b */
|
||||
if (BN_ucmp(a, b) < 0) {
|
||||
if (!BN_usub(r, b, a)) {
|
||||
return 0;
|
||||
}
|
||||
r->neg = 1;
|
||||
} else {
|
||||
if (!BN_usub(r, a, b)) {
|
||||
return 0;
|
||||
}
|
||||
r->neg = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = BN_uadd(r, a, b);
|
||||
r->neg = a_neg;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
|
||||
int max, min, dif;
|
||||
BN_ULONG *ap, *bp, *rp, carry, t1, t2;
|
||||
const BIGNUM *tmp;
|
||||
|
||||
if (a->top < b->top) {
|
||||
tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
max = a->top;
|
||||
min = b->top;
|
||||
dif = max - min;
|
||||
|
||||
if (bn_wexpand(r, max + 1) == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
r->top = max;
|
||||
|
||||
ap = a->d;
|
||||
bp = b->d;
|
||||
rp = r->d;
|
||||
|
||||
carry = bn_add_words(rp, ap, bp, min);
|
||||
rp += min;
|
||||
ap += min;
|
||||
bp += min;
|
||||
|
||||
if (carry) {
|
||||
while (dif) {
|
||||
dif--;
|
||||
t1 = *(ap++);
|
||||
t2 = (t1 + 1) & BN_MASK2;
|
||||
*(rp++) = t2;
|
||||
if (t2) {
|
||||
carry = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (carry) {
|
||||
/* carry != 0 => dif == 0 */
|
||||
*rp = 1;
|
||||
r->top++;
|
||||
}
|
||||
}
|
||||
|
||||
if (dif && rp != ap) {
|
||||
while (dif--) {
|
||||
/* copy remaining words if ap != rp */
|
||||
*(rp++) = *(ap++);
|
||||
}
|
||||
}
|
||||
|
||||
r->neg = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BN_add_word(BIGNUM *a, BN_ULONG w) {
|
||||
BN_ULONG l;
|
||||
int i;
|
||||
|
||||
w &= BN_MASK2;
|
||||
|
||||
/* degenerate case: w is zero */
|
||||
if (!w) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* degenerate case: a is zero */
|
||||
if (BN_is_zero(a)) {
|
||||
return BN_set_word(a, w);
|
||||
}
|
||||
|
||||
/* handle 'a' when negative */
|
||||
if (a->neg) {
|
||||
a->neg = 0;
|
||||
i = BN_sub_word(a, w);
|
||||
if (!BN_is_zero(a)) {
|
||||
a->neg = !(a->neg);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
for (i = 0; w != 0 && i < a->top; i++) {
|
||||
a->d[i] = l = (a->d[i] + w) & BN_MASK2;
|
||||
w = (w > l) ? 1 : 0;
|
||||
}
|
||||
|
||||
if (w && i == a->top) {
|
||||
if (bn_wexpand(a, a->top + 1) == NULL) {
|
||||
return 0;
|
||||
}
|
||||
a->top++;
|
||||
a->d[i] = w;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
|
||||
int max;
|
||||
int add = 0, neg = 0;
|
||||
const BIGNUM *tmp;
|
||||
|
||||
/* a - b a-b
|
||||
* a - -b a+b
|
||||
* -a - b -(a+b)
|
||||
* -a - -b b-a
|
||||
*/
|
||||
if (a->neg) {
|
||||
if (b->neg) {
|
||||
tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
} else {
|
||||
add = 1;
|
||||
neg = 1;
|
||||
}
|
||||
} else {
|
||||
if (b->neg) {
|
||||
add = 1;
|
||||
neg = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (add) {
|
||||
if (!BN_uadd(r, a, b)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
r->neg = neg;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* We are actually doing a - b :-) */
|
||||
|
||||
max = (a->top > b->top) ? a->top : b->top;
|
||||
if (bn_wexpand(r, max) == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (BN_ucmp(a, b) < 0) {
|
||||
if (!BN_usub(r, b, a)) {
|
||||
return 0;
|
||||
}
|
||||
r->neg = 1;
|
||||
} else {
|
||||
if (!BN_usub(r, a, b)) {
|
||||
return 0;
|
||||
}
|
||||
r->neg = 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) {
|
||||
int max, min, dif;
|
||||
register BN_ULONG t1, t2, *ap, *bp, *rp;
|
||||
int i, carry;
|
||||
|
||||
max = a->top;
|
||||
min = b->top;
|
||||
dif = max - min;
|
||||
|
||||
if (dif < 0) /* hmm... should not be happening */
|
||||
{
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_ARG2_LT_ARG3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bn_wexpand(r, max) == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ap = a->d;
|
||||
bp = b->d;
|
||||
rp = r->d;
|
||||
|
||||
carry = 0;
|
||||
for (i = min; i != 0; i--) {
|
||||
t1 = *(ap++);
|
||||
t2 = *(bp++);
|
||||
if (carry) {
|
||||
carry = (t1 <= t2);
|
||||
t1 = (t1 - t2 - 1) & BN_MASK2;
|
||||
} else {
|
||||
carry = (t1 < t2);
|
||||
t1 = (t1 - t2) & BN_MASK2;
|
||||
}
|
||||
*(rp++) = t1 & BN_MASK2;
|
||||
}
|
||||
|
||||
if (carry) /* subtracted */
|
||||
{
|
||||
if (!dif) {
|
||||
/* error: a < b */
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (dif) {
|
||||
dif--;
|
||||
t1 = *(ap++);
|
||||
t2 = (t1 - 1) & BN_MASK2;
|
||||
*(rp++) = t2;
|
||||
if (t1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dif > 0 && rp != ap) {
|
||||
memcpy(rp, ap, sizeof(*rp) * dif);
|
||||
}
|
||||
|
||||
r->top = max;
|
||||
r->neg = 0;
|
||||
bn_correct_top(r);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BN_sub_word(BIGNUM *a, BN_ULONG w) {
|
||||
int i;
|
||||
|
||||
w &= BN_MASK2;
|
||||
|
||||
/* degenerate case: w is zero */
|
||||
if (!w) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* degenerate case: a is zero */
|
||||
if (BN_is_zero(a)) {
|
||||
i = BN_set_word(a, w);
|
||||
if (i != 0) {
|
||||
BN_set_negative(a, 1);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/* handle 'a' when negative */
|
||||
if (a->neg) {
|
||||
a->neg = 0;
|
||||
i = BN_add_word(a, w);
|
||||
a->neg = 1;
|
||||
return i;
|
||||
}
|
||||
|
||||
if ((a->top == 1) && (a->d[0] < w)) {
|
||||
a->d[0] = w - a->d[0];
|
||||
a->neg = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (;;) {
|
||||
if (a->d[i] >= w) {
|
||||
a->d[i] -= w;
|
||||
break;
|
||||
} else {
|
||||
a->d[i] = (a->d[i] - w) & BN_MASK2;
|
||||
i++;
|
||||
w = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((a->d[i] == 0) && (i == (a->top - 1))) {
|
||||
a->top--;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,693 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
# ====================================================================
|
||||
# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
|
||||
# project. The module is, however, dual licensed under OpenSSL and
|
||||
# CRYPTOGAMS licenses depending on where you obtain it. For further
|
||||
# details see http://www.openssl.org/~appro/cryptogams/.
|
||||
# ====================================================================
|
||||
|
||||
# January 2007.
|
||||
|
||||
# Montgomery multiplication for ARMv4.
|
||||
#
|
||||
# Performance improvement naturally varies among CPU implementations
|
||||
# and compilers. The code was observed to provide +65-35% improvement
|
||||
# [depending on key length, less for longer keys] on ARM920T, and
|
||||
# +115-80% on Intel IXP425. This is compared to pre-bn_mul_mont code
|
||||
# base and compiler generated code with in-lined umull and even umlal
|
||||
# instructions. The latter means that this code didn't really have an
|
||||
# "advantage" of utilizing some "secret" instruction.
|
||||
#
|
||||
# The code is interoperable with Thumb ISA and is rather compact, less
|
||||
# than 1/2KB. Windows CE port would be trivial, as it's exclusively
|
||||
# about decorations, ABI and instruction syntax are identical.
|
||||
|
||||
# November 2013
|
||||
#
|
||||
# Add NEON code path, which handles lengths divisible by 8. RSA/DSA
|
||||
# performance improvement on Cortex-A8 is ~45-100% depending on key
|
||||
# length, more for longer keys. On Cortex-A15 the span is ~10-105%.
|
||||
# On Snapdragon S4 improvement was measured to vary from ~70% to
|
||||
# incredible ~380%, yes, 4.8x faster, for RSA4096 sign. But this is
|
||||
# rather because original integer-only code seems to perform
|
||||
# suboptimally on S4. Situation on Cortex-A9 is unfortunately
|
||||
# different. It's being looked into, but the trouble is that
|
||||
# performance for vectors longer than 256 bits is actually couple
|
||||
# of percent worse than for integer-only code. The code is chosen
|
||||
# for execution on all NEON-capable processors, because gain on
|
||||
# others outweighs the marginal loss on Cortex-A9.
|
||||
|
||||
$flavour = shift;
|
||||
if ($flavour=~/^\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; }
|
||||
else { while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {} }
|
||||
|
||||
if ($flavour && $flavour ne "void") {
|
||||
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
|
||||
( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
|
||||
die "can't locate arm-xlate.pl";
|
||||
|
||||
open STDOUT,"| \"$^X\" $xlate $flavour $output";
|
||||
} else {
|
||||
open STDOUT,">$output";
|
||||
}
|
||||
|
||||
$num="r0"; # starts as num argument, but holds &tp[num-1]
|
||||
$ap="r1";
|
||||
$bp="r2"; $bi="r2"; $rp="r2";
|
||||
$np="r3";
|
||||
$tp="r4";
|
||||
$aj="r5";
|
||||
$nj="r6";
|
||||
$tj="r7";
|
||||
$n0="r8";
|
||||
########### # r9 is reserved by ELF as platform specific, e.g. TLS pointer
|
||||
$alo="r10"; # sl, gcc uses it to keep @GOT
|
||||
$ahi="r11"; # fp
|
||||
$nlo="r12"; # ip
|
||||
########### # r13 is stack pointer
|
||||
$nhi="r14"; # lr
|
||||
########### # r15 is program counter
|
||||
|
||||
#### argument block layout relative to &tp[num-1], a.k.a. $num
|
||||
$_rp="$num,#12*4";
|
||||
# ap permanently resides in r1
|
||||
$_bp="$num,#13*4";
|
||||
# np permanently resides in r3
|
||||
$_n0="$num,#14*4";
|
||||
$_num="$num,#15*4"; $_bpend=$_num;
|
||||
|
||||
$code=<<___;
|
||||
#include <openssl/arm_arch.h>
|
||||
|
||||
.text
|
||||
.code 32
|
||||
|
||||
#if __ARM_MAX_ARCH__>=7
|
||||
.align 5
|
||||
.LOPENSSL_armcap:
|
||||
.word OPENSSL_armcap_P-.Lbn_mul_mont
|
||||
#endif
|
||||
|
||||
.global bn_mul_mont
|
||||
.type bn_mul_mont,%function
|
||||
|
||||
.align 5
|
||||
bn_mul_mont:
|
||||
.Lbn_mul_mont:
|
||||
ldr ip,[sp,#4] @ load num
|
||||
stmdb sp!,{r0,r2} @ sp points at argument block
|
||||
#if __ARM_MAX_ARCH__>=7
|
||||
tst ip,#7
|
||||
bne .Lialu
|
||||
adr r0,bn_mul_mont
|
||||
ldr r2,.LOPENSSL_armcap
|
||||
ldr r0,[r0,r2]
|
||||
#ifdef __APPLE__
|
||||
ldr r0,[r0]
|
||||
#endif
|
||||
tst r0,#ARMV7_NEON @ NEON available?
|
||||
ldmia sp, {r0,r2}
|
||||
beq .Lialu
|
||||
add sp,sp,#8
|
||||
b bn_mul8x_mont_neon
|
||||
.align 4
|
||||
.Lialu:
|
||||
#endif
|
||||
cmp ip,#2
|
||||
mov $num,ip @ load num
|
||||
movlt r0,#0
|
||||
addlt sp,sp,#2*4
|
||||
blt .Labrt
|
||||
|
||||
stmdb sp!,{r4-r12,lr} @ save 10 registers
|
||||
|
||||
mov $num,$num,lsl#2 @ rescale $num for byte count
|
||||
sub sp,sp,$num @ alloca(4*num)
|
||||
sub sp,sp,#4 @ +extra dword
|
||||
sub $num,$num,#4 @ "num=num-1"
|
||||
add $tp,$bp,$num @ &bp[num-1]
|
||||
|
||||
add $num,sp,$num @ $num to point at &tp[num-1]
|
||||
ldr $n0,[$_n0] @ &n0
|
||||
ldr $bi,[$bp] @ bp[0]
|
||||
ldr $aj,[$ap],#4 @ ap[0],ap++
|
||||
ldr $nj,[$np],#4 @ np[0],np++
|
||||
ldr $n0,[$n0] @ *n0
|
||||
str $tp,[$_bpend] @ save &bp[num]
|
||||
|
||||
umull $alo,$ahi,$aj,$bi @ ap[0]*bp[0]
|
||||
str $n0,[$_n0] @ save n0 value
|
||||
mul $n0,$alo,$n0 @ "tp[0]"*n0
|
||||
mov $nlo,#0
|
||||
umlal $alo,$nlo,$nj,$n0 @ np[0]*n0+"t[0]"
|
||||
mov $tp,sp
|
||||
|
||||
.L1st:
|
||||
ldr $aj,[$ap],#4 @ ap[j],ap++
|
||||
mov $alo,$ahi
|
||||
ldr $nj,[$np],#4 @ np[j],np++
|
||||
mov $ahi,#0
|
||||
umlal $alo,$ahi,$aj,$bi @ ap[j]*bp[0]
|
||||
mov $nhi,#0
|
||||
umlal $nlo,$nhi,$nj,$n0 @ np[j]*n0
|
||||
adds $nlo,$nlo,$alo
|
||||
str $nlo,[$tp],#4 @ tp[j-1]=,tp++
|
||||
adc $nlo,$nhi,#0
|
||||
cmp $tp,$num
|
||||
bne .L1st
|
||||
|
||||
adds $nlo,$nlo,$ahi
|
||||
ldr $tp,[$_bp] @ restore bp
|
||||
mov $nhi,#0
|
||||
ldr $n0,[$_n0] @ restore n0
|
||||
adc $nhi,$nhi,#0
|
||||
str $nlo,[$num] @ tp[num-1]=
|
||||
str $nhi,[$num,#4] @ tp[num]=
|
||||
|
||||
.Louter:
|
||||
sub $tj,$num,sp @ "original" $num-1 value
|
||||
sub $ap,$ap,$tj @ "rewind" ap to &ap[1]
|
||||
ldr $bi,[$tp,#4]! @ *(++bp)
|
||||
sub $np,$np,$tj @ "rewind" np to &np[1]
|
||||
ldr $aj,[$ap,#-4] @ ap[0]
|
||||
ldr $alo,[sp] @ tp[0]
|
||||
ldr $nj,[$np,#-4] @ np[0]
|
||||
ldr $tj,[sp,#4] @ tp[1]
|
||||
|
||||
mov $ahi,#0
|
||||
umlal $alo,$ahi,$aj,$bi @ ap[0]*bp[i]+tp[0]
|
||||
str $tp,[$_bp] @ save bp
|
||||
mul $n0,$alo,$n0
|
||||
mov $nlo,#0
|
||||
umlal $alo,$nlo,$nj,$n0 @ np[0]*n0+"tp[0]"
|
||||
mov $tp,sp
|
||||
|
||||
.Linner:
|
||||
ldr $aj,[$ap],#4 @ ap[j],ap++
|
||||
adds $alo,$ahi,$tj @ +=tp[j]
|
||||
ldr $nj,[$np],#4 @ np[j],np++
|
||||
mov $ahi,#0
|
||||
umlal $alo,$ahi,$aj,$bi @ ap[j]*bp[i]
|
||||
mov $nhi,#0
|
||||
umlal $nlo,$nhi,$nj,$n0 @ np[j]*n0
|
||||
adc $ahi,$ahi,#0
|
||||
ldr $tj,[$tp,#8] @ tp[j+1]
|
||||
adds $nlo,$nlo,$alo
|
||||
str $nlo,[$tp],#4 @ tp[j-1]=,tp++
|
||||
adc $nlo,$nhi,#0
|
||||
cmp $tp,$num
|
||||
bne .Linner
|
||||
|
||||
adds $nlo,$nlo,$ahi
|
||||
mov $nhi,#0
|
||||
ldr $tp,[$_bp] @ restore bp
|
||||
adc $nhi,$nhi,#0
|
||||
ldr $n0,[$_n0] @ restore n0
|
||||
adds $nlo,$nlo,$tj
|
||||
ldr $tj,[$_bpend] @ restore &bp[num]
|
||||
adc $nhi,$nhi,#0
|
||||
str $nlo,[$num] @ tp[num-1]=
|
||||
str $nhi,[$num,#4] @ tp[num]=
|
||||
|
||||
cmp $tp,$tj
|
||||
bne .Louter
|
||||
|
||||
ldr $rp,[$_rp] @ pull rp
|
||||
add $num,$num,#4 @ $num to point at &tp[num]
|
||||
sub $aj,$num,sp @ "original" num value
|
||||
mov $tp,sp @ "rewind" $tp
|
||||
mov $ap,$tp @ "borrow" $ap
|
||||
sub $np,$np,$aj @ "rewind" $np to &np[0]
|
||||
|
||||
subs $tj,$tj,$tj @ "clear" carry flag
|
||||
.Lsub: ldr $tj,[$tp],#4
|
||||
ldr $nj,[$np],#4
|
||||
sbcs $tj,$tj,$nj @ tp[j]-np[j]
|
||||
str $tj,[$rp],#4 @ rp[j]=
|
||||
teq $tp,$num @ preserve carry
|
||||
bne .Lsub
|
||||
sbcs $nhi,$nhi,#0 @ upmost carry
|
||||
mov $tp,sp @ "rewind" $tp
|
||||
sub $rp,$rp,$aj @ "rewind" $rp
|
||||
|
||||
and $ap,$tp,$nhi
|
||||
bic $np,$rp,$nhi
|
||||
orr $ap,$ap,$np @ ap=borrow?tp:rp
|
||||
|
||||
.Lcopy: ldr $tj,[$ap],#4 @ copy or in-place refresh
|
||||
str sp,[$tp],#4 @ zap tp
|
||||
str $tj,[$rp],#4
|
||||
cmp $tp,$num
|
||||
bne .Lcopy
|
||||
|
||||
add sp,$num,#4 @ skip over tp[num+1]
|
||||
ldmia sp!,{r4-r12,lr} @ restore registers
|
||||
add sp,sp,#2*4 @ skip over {r0,r2}
|
||||
mov r0,#1
|
||||
.Labrt:
|
||||
#if __ARM_ARCH__>=5
|
||||
ret @ bx lr
|
||||
#else
|
||||
tst lr,#1
|
||||
moveq pc,lr @ be binary compatible with V4, yet
|
||||
bx lr @ interoperable with Thumb ISA:-)
|
||||
#endif
|
||||
.size bn_mul_mont,.-bn_mul_mont
|
||||
___
|
||||
{
|
||||
sub Dlo() { shift=~m|q([1]?[0-9])|?"d".($1*2):""; }
|
||||
sub Dhi() { shift=~m|q([1]?[0-9])|?"d".($1*2+1):""; }
|
||||
|
||||
my ($A0,$A1,$A2,$A3)=map("d$_",(0..3));
|
||||
my ($N0,$N1,$N2,$N3)=map("d$_",(4..7));
|
||||
my ($Z,$Temp)=("q4","q5");
|
||||
my ($A0xB,$A1xB,$A2xB,$A3xB,$A4xB,$A5xB,$A6xB,$A7xB)=map("q$_",(6..13));
|
||||
my ($Bi,$Ni,$M0)=map("d$_",(28..31));
|
||||
my $zero=&Dlo($Z);
|
||||
my $temp=&Dlo($Temp);
|
||||
|
||||
my ($rptr,$aptr,$bptr,$nptr,$n0,$num)=map("r$_",(0..5));
|
||||
my ($tinptr,$toutptr,$inner,$outer)=map("r$_",(6..9));
|
||||
|
||||
$code.=<<___;
|
||||
#if __ARM_MAX_ARCH__>=7
|
||||
.arch armv7-a
|
||||
.fpu neon
|
||||
|
||||
.type bn_mul8x_mont_neon,%function
|
||||
.align 5
|
||||
bn_mul8x_mont_neon:
|
||||
mov ip,sp
|
||||
stmdb sp!,{r4-r11}
|
||||
vstmdb sp!,{d8-d15} @ ABI specification says so
|
||||
ldmia ip,{r4-r5} @ load rest of parameter block
|
||||
|
||||
sub $toutptr,sp,#16
|
||||
vld1.32 {${Bi}[0]}, [$bptr,:32]!
|
||||
sub $toutptr,$toutptr,$num,lsl#4
|
||||
vld1.32 {$A0-$A3}, [$aptr]! @ can't specify :32 :-(
|
||||
and $toutptr,$toutptr,#-64
|
||||
vld1.32 {${M0}[0]}, [$n0,:32]
|
||||
mov sp,$toutptr @ alloca
|
||||
veor $zero,$zero,$zero
|
||||
subs $inner,$num,#8
|
||||
vzip.16 $Bi,$zero
|
||||
|
||||
vmull.u32 $A0xB,$Bi,${A0}[0]
|
||||
vmull.u32 $A1xB,$Bi,${A0}[1]
|
||||
vmull.u32 $A2xB,$Bi,${A1}[0]
|
||||
vshl.i64 $temp,`&Dhi("$A0xB")`,#16
|
||||
vmull.u32 $A3xB,$Bi,${A1}[1]
|
||||
|
||||
vadd.u64 $temp,$temp,`&Dlo("$A0xB")`
|
||||
veor $zero,$zero,$zero
|
||||
vmul.u32 $Ni,$temp,$M0
|
||||
|
||||
vmull.u32 $A4xB,$Bi,${A2}[0]
|
||||
vld1.32 {$N0-$N3}, [$nptr]!
|
||||
vmull.u32 $A5xB,$Bi,${A2}[1]
|
||||
vmull.u32 $A6xB,$Bi,${A3}[0]
|
||||
vzip.16 $Ni,$zero
|
||||
vmull.u32 $A7xB,$Bi,${A3}[1]
|
||||
|
||||
bne .LNEON_1st
|
||||
|
||||
@ special case for num=8, everything is in register bank...
|
||||
|
||||
vmlal.u32 $A0xB,$Ni,${N0}[0]
|
||||
sub $outer,$num,#1
|
||||
vmlal.u32 $A1xB,$Ni,${N0}[1]
|
||||
vmlal.u32 $A2xB,$Ni,${N1}[0]
|
||||
vmlal.u32 $A3xB,$Ni,${N1}[1]
|
||||
|
||||
vmlal.u32 $A4xB,$Ni,${N2}[0]
|
||||
vmov $Temp,$A0xB
|
||||
vmlal.u32 $A5xB,$Ni,${N2}[1]
|
||||
vmov $A0xB,$A1xB
|
||||
vmlal.u32 $A6xB,$Ni,${N3}[0]
|
||||
vmov $A1xB,$A2xB
|
||||
vmlal.u32 $A7xB,$Ni,${N3}[1]
|
||||
vmov $A2xB,$A3xB
|
||||
vmov $A3xB,$A4xB
|
||||
vshr.u64 $temp,$temp,#16
|
||||
vmov $A4xB,$A5xB
|
||||
vmov $A5xB,$A6xB
|
||||
vadd.u64 $temp,$temp,`&Dhi("$Temp")`
|
||||
vmov $A6xB,$A7xB
|
||||
veor $A7xB,$A7xB
|
||||
vshr.u64 $temp,$temp,#16
|
||||
|
||||
b .LNEON_outer8
|
||||
|
||||
.align 4
|
||||
.LNEON_outer8:
|
||||
vld1.32 {${Bi}[0]}, [$bptr,:32]!
|
||||
veor $zero,$zero,$zero
|
||||
vzip.16 $Bi,$zero
|
||||
vadd.u64 `&Dlo("$A0xB")`,`&Dlo("$A0xB")`,$temp
|
||||
|
||||
vmlal.u32 $A0xB,$Bi,${A0}[0]
|
||||
vmlal.u32 $A1xB,$Bi,${A0}[1]
|
||||
vmlal.u32 $A2xB,$Bi,${A1}[0]
|
||||
vshl.i64 $temp,`&Dhi("$A0xB")`,#16
|
||||
vmlal.u32 $A3xB,$Bi,${A1}[1]
|
||||
|
||||
vadd.u64 $temp,$temp,`&Dlo("$A0xB")`
|
||||
veor $zero,$zero,$zero
|
||||
subs $outer,$outer,#1
|
||||
vmul.u32 $Ni,$temp,$M0
|
||||
|
||||
vmlal.u32 $A4xB,$Bi,${A2}[0]
|
||||
vmlal.u32 $A5xB,$Bi,${A2}[1]
|
||||
vmlal.u32 $A6xB,$Bi,${A3}[0]
|
||||
vzip.16 $Ni,$zero
|
||||
vmlal.u32 $A7xB,$Bi,${A3}[1]
|
||||
|
||||
vmlal.u32 $A0xB,$Ni,${N0}[0]
|
||||
vmlal.u32 $A1xB,$Ni,${N0}[1]
|
||||
vmlal.u32 $A2xB,$Ni,${N1}[0]
|
||||
vmlal.u32 $A3xB,$Ni,${N1}[1]
|
||||
|
||||
vmlal.u32 $A4xB,$Ni,${N2}[0]
|
||||
vmov $Temp,$A0xB
|
||||
vmlal.u32 $A5xB,$Ni,${N2}[1]
|
||||
vmov $A0xB,$A1xB
|
||||
vmlal.u32 $A6xB,$Ni,${N3}[0]
|
||||
vmov $A1xB,$A2xB
|
||||
vmlal.u32 $A7xB,$Ni,${N3}[1]
|
||||
vmov $A2xB,$A3xB
|
||||
vmov $A3xB,$A4xB
|
||||
vshr.u64 $temp,$temp,#16
|
||||
vmov $A4xB,$A5xB
|
||||
vmov $A5xB,$A6xB
|
||||
vadd.u64 $temp,$temp,`&Dhi("$Temp")`
|
||||
vmov $A6xB,$A7xB
|
||||
veor $A7xB,$A7xB
|
||||
vshr.u64 $temp,$temp,#16
|
||||
|
||||
bne .LNEON_outer8
|
||||
|
||||
vadd.u64 `&Dlo("$A0xB")`,`&Dlo("$A0xB")`,$temp
|
||||
mov $toutptr,sp
|
||||
vshr.u64 $temp,`&Dlo("$A0xB")`,#16
|
||||
mov $inner,$num
|
||||
vadd.u64 `&Dhi("$A0xB")`,`&Dhi("$A0xB")`,$temp
|
||||
add $tinptr,sp,#16
|
||||
vshr.u64 $temp,`&Dhi("$A0xB")`,#16
|
||||
vzip.16 `&Dlo("$A0xB")`,`&Dhi("$A0xB")`
|
||||
|
||||
b .LNEON_tail2
|
||||
|
||||
.align 4
|
||||
.LNEON_1st:
|
||||
vmlal.u32 $A0xB,$Ni,${N0}[0]
|
||||
vld1.32 {$A0-$A3}, [$aptr]!
|
||||
vmlal.u32 $A1xB,$Ni,${N0}[1]
|
||||
subs $inner,$inner,#8
|
||||
vmlal.u32 $A2xB,$Ni,${N1}[0]
|
||||
vmlal.u32 $A3xB,$Ni,${N1}[1]
|
||||
|
||||
vmlal.u32 $A4xB,$Ni,${N2}[0]
|
||||
vld1.32 {$N0-$N1}, [$nptr]!
|
||||
vmlal.u32 $A5xB,$Ni,${N2}[1]
|
||||
vst1.64 {$A0xB-$A1xB}, [$toutptr,:256]!
|
||||
vmlal.u32 $A6xB,$Ni,${N3}[0]
|
||||
vmlal.u32 $A7xB,$Ni,${N3}[1]
|
||||
vst1.64 {$A2xB-$A3xB}, [$toutptr,:256]!
|
||||
|
||||
vmull.u32 $A0xB,$Bi,${A0}[0]
|
||||
vld1.32 {$N2-$N3}, [$nptr]!
|
||||
vmull.u32 $A1xB,$Bi,${A0}[1]
|
||||
vst1.64 {$A4xB-$A5xB}, [$toutptr,:256]!
|
||||
vmull.u32 $A2xB,$Bi,${A1}[0]
|
||||
vmull.u32 $A3xB,$Bi,${A1}[1]
|
||||
vst1.64 {$A6xB-$A7xB}, [$toutptr,:256]!
|
||||
|
||||
vmull.u32 $A4xB,$Bi,${A2}[0]
|
||||
vmull.u32 $A5xB,$Bi,${A2}[1]
|
||||
vmull.u32 $A6xB,$Bi,${A3}[0]
|
||||
vmull.u32 $A7xB,$Bi,${A3}[1]
|
||||
|
||||
bne .LNEON_1st
|
||||
|
||||
vmlal.u32 $A0xB,$Ni,${N0}[0]
|
||||
add $tinptr,sp,#16
|
||||
vmlal.u32 $A1xB,$Ni,${N0}[1]
|
||||
sub $aptr,$aptr,$num,lsl#2 @ rewind $aptr
|
||||
vmlal.u32 $A2xB,$Ni,${N1}[0]
|
||||
vld1.64 {$Temp}, [sp,:128]
|
||||
vmlal.u32 $A3xB,$Ni,${N1}[1]
|
||||
sub $outer,$num,#1
|
||||
|
||||
vmlal.u32 $A4xB,$Ni,${N2}[0]
|
||||
vst1.64 {$A0xB-$A1xB}, [$toutptr,:256]!
|
||||
vmlal.u32 $A5xB,$Ni,${N2}[1]
|
||||
vshr.u64 $temp,$temp,#16
|
||||
vld1.64 {$A0xB}, [$tinptr, :128]!
|
||||
vmlal.u32 $A6xB,$Ni,${N3}[0]
|
||||
vst1.64 {$A2xB-$A3xB}, [$toutptr,:256]!
|
||||
vmlal.u32 $A7xB,$Ni,${N3}[1]
|
||||
|
||||
vst1.64 {$A4xB-$A5xB}, [$toutptr,:256]!
|
||||
vadd.u64 $temp,$temp,`&Dhi("$Temp")`
|
||||
veor $Z,$Z,$Z
|
||||
vst1.64 {$A6xB-$A7xB}, [$toutptr,:256]!
|
||||
vld1.64 {$A1xB-$A2xB}, [$tinptr, :256]!
|
||||
vst1.64 {$Z}, [$toutptr,:128]
|
||||
vshr.u64 $temp,$temp,#16
|
||||
|
||||
b .LNEON_outer
|
||||
|
||||
.align 4
|
||||
.LNEON_outer:
|
||||
vld1.32 {${Bi}[0]}, [$bptr,:32]!
|
||||
sub $nptr,$nptr,$num,lsl#2 @ rewind $nptr
|
||||
vld1.32 {$A0-$A3}, [$aptr]!
|
||||
veor $zero,$zero,$zero
|
||||
mov $toutptr,sp
|
||||
vzip.16 $Bi,$zero
|
||||
sub $inner,$num,#8
|
||||
vadd.u64 `&Dlo("$A0xB")`,`&Dlo("$A0xB")`,$temp
|
||||
|
||||
vmlal.u32 $A0xB,$Bi,${A0}[0]
|
||||
vld1.64 {$A3xB-$A4xB},[$tinptr,:256]!
|
||||
vmlal.u32 $A1xB,$Bi,${A0}[1]
|
||||
vmlal.u32 $A2xB,$Bi,${A1}[0]
|
||||
vld1.64 {$A5xB-$A6xB},[$tinptr,:256]!
|
||||
vmlal.u32 $A3xB,$Bi,${A1}[1]
|
||||
|
||||
vshl.i64 $temp,`&Dhi("$A0xB")`,#16
|
||||
veor $zero,$zero,$zero
|
||||
vadd.u64 $temp,$temp,`&Dlo("$A0xB")`
|
||||
vld1.64 {$A7xB},[$tinptr,:128]!
|
||||
vmul.u32 $Ni,$temp,$M0
|
||||
|
||||
vmlal.u32 $A4xB,$Bi,${A2}[0]
|
||||
vld1.32 {$N0-$N3}, [$nptr]!
|
||||
vmlal.u32 $A5xB,$Bi,${A2}[1]
|
||||
vmlal.u32 $A6xB,$Bi,${A3}[0]
|
||||
vzip.16 $Ni,$zero
|
||||
vmlal.u32 $A7xB,$Bi,${A3}[1]
|
||||
|
||||
.LNEON_inner:
|
||||
vmlal.u32 $A0xB,$Ni,${N0}[0]
|
||||
vld1.32 {$A0-$A3}, [$aptr]!
|
||||
vmlal.u32 $A1xB,$Ni,${N0}[1]
|
||||
subs $inner,$inner,#8
|
||||
vmlal.u32 $A2xB,$Ni,${N1}[0]
|
||||
vmlal.u32 $A3xB,$Ni,${N1}[1]
|
||||
vst1.64 {$A0xB-$A1xB}, [$toutptr,:256]!
|
||||
|
||||
vmlal.u32 $A4xB,$Ni,${N2}[0]
|
||||
vld1.64 {$A0xB}, [$tinptr, :128]!
|
||||
vmlal.u32 $A5xB,$Ni,${N2}[1]
|
||||
vst1.64 {$A2xB-$A3xB}, [$toutptr,:256]!
|
||||
vmlal.u32 $A6xB,$Ni,${N3}[0]
|
||||
vld1.64 {$A1xB-$A2xB}, [$tinptr, :256]!
|
||||
vmlal.u32 $A7xB,$Ni,${N3}[1]
|
||||
vst1.64 {$A4xB-$A5xB}, [$toutptr,:256]!
|
||||
|
||||
vmlal.u32 $A0xB,$Bi,${A0}[0]
|
||||
vld1.64 {$A3xB-$A4xB}, [$tinptr, :256]!
|
||||
vmlal.u32 $A1xB,$Bi,${A0}[1]
|
||||
vst1.64 {$A6xB-$A7xB}, [$toutptr,:256]!
|
||||
vmlal.u32 $A2xB,$Bi,${A1}[0]
|
||||
vld1.64 {$A5xB-$A6xB}, [$tinptr, :256]!
|
||||
vmlal.u32 $A3xB,$Bi,${A1}[1]
|
||||
vld1.32 {$N0-$N3}, [$nptr]!
|
||||
|
||||
vmlal.u32 $A4xB,$Bi,${A2}[0]
|
||||
vld1.64 {$A7xB}, [$tinptr, :128]!
|
||||
vmlal.u32 $A5xB,$Bi,${A2}[1]
|
||||
vmlal.u32 $A6xB,$Bi,${A3}[0]
|
||||
vmlal.u32 $A7xB,$Bi,${A3}[1]
|
||||
|
||||
bne .LNEON_inner
|
||||
|
||||
vmlal.u32 $A0xB,$Ni,${N0}[0]
|
||||
add $tinptr,sp,#16
|
||||
vmlal.u32 $A1xB,$Ni,${N0}[1]
|
||||
sub $aptr,$aptr,$num,lsl#2 @ rewind $aptr
|
||||
vmlal.u32 $A2xB,$Ni,${N1}[0]
|
||||
vld1.64 {$Temp}, [sp,:128]
|
||||
vmlal.u32 $A3xB,$Ni,${N1}[1]
|
||||
subs $outer,$outer,#1
|
||||
|
||||
vmlal.u32 $A4xB,$Ni,${N2}[0]
|
||||
vst1.64 {$A0xB-$A1xB}, [$toutptr,:256]!
|
||||
vmlal.u32 $A5xB,$Ni,${N2}[1]
|
||||
vld1.64 {$A0xB}, [$tinptr, :128]!
|
||||
vshr.u64 $temp,$temp,#16
|
||||
vst1.64 {$A2xB-$A3xB}, [$toutptr,:256]!
|
||||
vmlal.u32 $A6xB,$Ni,${N3}[0]
|
||||
vld1.64 {$A1xB-$A2xB}, [$tinptr, :256]!
|
||||
vmlal.u32 $A7xB,$Ni,${N3}[1]
|
||||
|
||||
vst1.64 {$A4xB-$A5xB}, [$toutptr,:256]!
|
||||
vadd.u64 $temp,$temp,`&Dhi("$Temp")`
|
||||
vst1.64 {$A6xB-$A7xB}, [$toutptr,:256]!
|
||||
vshr.u64 $temp,$temp,#16
|
||||
|
||||
bne .LNEON_outer
|
||||
|
||||
mov $toutptr,sp
|
||||
mov $inner,$num
|
||||
|
||||
.LNEON_tail:
|
||||
vadd.u64 `&Dlo("$A0xB")`,`&Dlo("$A0xB")`,$temp
|
||||
vld1.64 {$A3xB-$A4xB}, [$tinptr, :256]!
|
||||
vshr.u64 $temp,`&Dlo("$A0xB")`,#16
|
||||
vadd.u64 `&Dhi("$A0xB")`,`&Dhi("$A0xB")`,$temp
|
||||
vld1.64 {$A5xB-$A6xB}, [$tinptr, :256]!
|
||||
vshr.u64 $temp,`&Dhi("$A0xB")`,#16
|
||||
vld1.64 {$A7xB}, [$tinptr, :128]!
|
||||
vzip.16 `&Dlo("$A0xB")`,`&Dhi("$A0xB")`
|
||||
|
||||
.LNEON_tail2:
|
||||
vadd.u64 `&Dlo("$A1xB")`,`&Dlo("$A1xB")`,$temp
|
||||
vst1.32 {`&Dlo("$A0xB")`[0]}, [$toutptr, :32]!
|
||||
vshr.u64 $temp,`&Dlo("$A1xB")`,#16
|
||||
vadd.u64 `&Dhi("$A1xB")`,`&Dhi("$A1xB")`,$temp
|
||||
vshr.u64 $temp,`&Dhi("$A1xB")`,#16
|
||||
vzip.16 `&Dlo("$A1xB")`,`&Dhi("$A1xB")`
|
||||
|
||||
vadd.u64 `&Dlo("$A2xB")`,`&Dlo("$A2xB")`,$temp
|
||||
vst1.32 {`&Dlo("$A1xB")`[0]}, [$toutptr, :32]!
|
||||
vshr.u64 $temp,`&Dlo("$A2xB")`,#16
|
||||
vadd.u64 `&Dhi("$A2xB")`,`&Dhi("$A2xB")`,$temp
|
||||
vshr.u64 $temp,`&Dhi("$A2xB")`,#16
|
||||
vzip.16 `&Dlo("$A2xB")`,`&Dhi("$A2xB")`
|
||||
|
||||
vadd.u64 `&Dlo("$A3xB")`,`&Dlo("$A3xB")`,$temp
|
||||
vst1.32 {`&Dlo("$A2xB")`[0]}, [$toutptr, :32]!
|
||||
vshr.u64 $temp,`&Dlo("$A3xB")`,#16
|
||||
vadd.u64 `&Dhi("$A3xB")`,`&Dhi("$A3xB")`,$temp
|
||||
vshr.u64 $temp,`&Dhi("$A3xB")`,#16
|
||||
vzip.16 `&Dlo("$A3xB")`,`&Dhi("$A3xB")`
|
||||
|
||||
vadd.u64 `&Dlo("$A4xB")`,`&Dlo("$A4xB")`,$temp
|
||||
vst1.32 {`&Dlo("$A3xB")`[0]}, [$toutptr, :32]!
|
||||
vshr.u64 $temp,`&Dlo("$A4xB")`,#16
|
||||
vadd.u64 `&Dhi("$A4xB")`,`&Dhi("$A4xB")`,$temp
|
||||
vshr.u64 $temp,`&Dhi("$A4xB")`,#16
|
||||
vzip.16 `&Dlo("$A4xB")`,`&Dhi("$A4xB")`
|
||||
|
||||
vadd.u64 `&Dlo("$A5xB")`,`&Dlo("$A5xB")`,$temp
|
||||
vst1.32 {`&Dlo("$A4xB")`[0]}, [$toutptr, :32]!
|
||||
vshr.u64 $temp,`&Dlo("$A5xB")`,#16
|
||||
vadd.u64 `&Dhi("$A5xB")`,`&Dhi("$A5xB")`,$temp
|
||||
vshr.u64 $temp,`&Dhi("$A5xB")`,#16
|
||||
vzip.16 `&Dlo("$A5xB")`,`&Dhi("$A5xB")`
|
||||
|
||||
vadd.u64 `&Dlo("$A6xB")`,`&Dlo("$A6xB")`,$temp
|
||||
vst1.32 {`&Dlo("$A5xB")`[0]}, [$toutptr, :32]!
|
||||
vshr.u64 $temp,`&Dlo("$A6xB")`,#16
|
||||
vadd.u64 `&Dhi("$A6xB")`,`&Dhi("$A6xB")`,$temp
|
||||
vld1.64 {$A0xB}, [$tinptr, :128]!
|
||||
vshr.u64 $temp,`&Dhi("$A6xB")`,#16
|
||||
vzip.16 `&Dlo("$A6xB")`,`&Dhi("$A6xB")`
|
||||
|
||||
vadd.u64 `&Dlo("$A7xB")`,`&Dlo("$A7xB")`,$temp
|
||||
vst1.32 {`&Dlo("$A6xB")`[0]}, [$toutptr, :32]!
|
||||
vshr.u64 $temp,`&Dlo("$A7xB")`,#16
|
||||
vadd.u64 `&Dhi("$A7xB")`,`&Dhi("$A7xB")`,$temp
|
||||
vld1.64 {$A1xB-$A2xB}, [$tinptr, :256]!
|
||||
vshr.u64 $temp,`&Dhi("$A7xB")`,#16
|
||||
vzip.16 `&Dlo("$A7xB")`,`&Dhi("$A7xB")`
|
||||
subs $inner,$inner,#8
|
||||
vst1.32 {`&Dlo("$A7xB")`[0]}, [$toutptr, :32]!
|
||||
|
||||
bne .LNEON_tail
|
||||
|
||||
vst1.32 {${temp}[0]}, [$toutptr, :32] @ top-most bit
|
||||
sub $nptr,$nptr,$num,lsl#2 @ rewind $nptr
|
||||
subs $aptr,sp,#0 @ clear carry flag
|
||||
add $bptr,sp,$num,lsl#2
|
||||
|
||||
.LNEON_sub:
|
||||
ldmia $aptr!, {r4-r7}
|
||||
ldmia $nptr!, {r8-r11}
|
||||
sbcs r8, r4,r8
|
||||
sbcs r9, r5,r9
|
||||
sbcs r10,r6,r10
|
||||
sbcs r11,r7,r11
|
||||
teq $aptr,$bptr @ preserves carry
|
||||
stmia $rptr!, {r8-r11}
|
||||
bne .LNEON_sub
|
||||
|
||||
ldr r10, [$aptr] @ load top-most bit
|
||||
veor q0,q0,q0
|
||||
sub r11,$bptr,sp @ this is num*4
|
||||
veor q1,q1,q1
|
||||
mov $aptr,sp
|
||||
sub $rptr,$rptr,r11 @ rewind $rptr
|
||||
mov $nptr,$bptr @ second 3/4th of frame
|
||||
sbcs r10,r10,#0 @ result is carry flag
|
||||
|
||||
.LNEON_copy_n_zap:
|
||||
ldmia $aptr!, {r4-r7}
|
||||
ldmia $rptr, {r8-r11}
|
||||
movcc r8, r4
|
||||
vst1.64 {q0-q1}, [$nptr,:256]! @ wipe
|
||||
movcc r9, r5
|
||||
movcc r10,r6
|
||||
vst1.64 {q0-q1}, [$nptr,:256]! @ wipe
|
||||
movcc r11,r7
|
||||
ldmia $aptr, {r4-r7}
|
||||
stmia $rptr!, {r8-r11}
|
||||
sub $aptr,$aptr,#16
|
||||
ldmia $rptr, {r8-r11}
|
||||
movcc r8, r4
|
||||
vst1.64 {q0-q1}, [$aptr,:256]! @ wipe
|
||||
movcc r9, r5
|
||||
movcc r10,r6
|
||||
vst1.64 {q0-q1}, [$nptr,:256]! @ wipe
|
||||
movcc r11,r7
|
||||
teq $aptr,$bptr @ preserves carry
|
||||
stmia $rptr!, {r8-r11}
|
||||
bne .LNEON_copy_n_zap
|
||||
|
||||
sub sp,ip,#96
|
||||
vldmia sp!,{d8-d15}
|
||||
ldmia sp!,{r4-r11}
|
||||
ret @ bx lr
|
||||
.size bn_mul8x_mont_neon,.-bn_mul8x_mont_neon
|
||||
#endif
|
||||
___
|
||||
}
|
||||
$code.=<<___;
|
||||
.asciz "Montgomery multiplication for ARMv4/NEON, CRYPTOGAMS by <appro\@openssl.org>"
|
||||
.align 2
|
||||
#if __ARM_MAX_ARCH__>=7
|
||||
.comm OPENSSL_armcap_P,4,4
|
||||
.hidden OPENSSL_armcap_P
|
||||
#endif
|
||||
___
|
||||
|
||||
$code =~ s/\`([^\`]*)\`/eval $1/gem;
|
||||
$code =~ s/\bbx\s+lr\b/.word\t0xe12fff1e/gm; # make it possible to compile with -march=armv4
|
||||
$code =~ s/\bret\b/bx lr/gm;
|
||||
print $code;
|
||||
close STDOUT;
|
||||
@@ -1,11 +1,4 @@
|
||||
#! /usr/bin/env perl
|
||||
# Copyright 2015-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
|
||||
@@ -45,7 +38,7 @@ $output = shift;
|
||||
|
||||
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
|
||||
( $xlate="${dir}../../../perlasm/arm-xlate.pl" and -f $xlate) or
|
||||
( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
|
||||
die "can't locate arm-xlate.pl";
|
||||
|
||||
open OUT,"| \"$^X\" $xlate $flavour $output";
|
||||
@@ -61,7 +54,7 @@ $ap="x1"; # const BN_ULONG *ap,
|
||||
$bp="x2"; # const BN_ULONG *bp,
|
||||
$np="x3"; # const BN_ULONG *np,
|
||||
$n0="x4"; # const BN_ULONG *n0,
|
||||
$num="x5"; # size_t num);
|
||||
$num="x5"; # int num);
|
||||
|
||||
$code.=<<___;
|
||||
.text
|
||||
@@ -1507,4 +1500,4 @@ ___
|
||||
|
||||
print $code;
|
||||
|
||||
close STDOUT or die "error closing STDOUT";
|
||||
close STDOUT;
|
||||
@@ -0,0 +1,774 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
push(@INC,"${dir}","${dir}../../perlasm");
|
||||
require "x86asm.pl";
|
||||
|
||||
&asm_init($ARGV[0],$0);
|
||||
|
||||
$sse2=0;
|
||||
for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); }
|
||||
|
||||
&external_label("OPENSSL_ia32cap_P") if ($sse2);
|
||||
|
||||
&bn_mul_add_words("bn_mul_add_words");
|
||||
&bn_mul_words("bn_mul_words");
|
||||
&bn_sqr_words("bn_sqr_words");
|
||||
&bn_div_words("bn_div_words");
|
||||
&bn_add_words("bn_add_words");
|
||||
&bn_sub_words("bn_sub_words");
|
||||
&bn_sub_part_words("bn_sub_part_words");
|
||||
|
||||
&asm_finish();
|
||||
|
||||
sub bn_mul_add_words
|
||||
{
|
||||
local($name)=@_;
|
||||
|
||||
&function_begin_B($name,$sse2?"EXTRN\t_OPENSSL_ia32cap_P:DWORD":"");
|
||||
|
||||
$r="eax";
|
||||
$a="edx";
|
||||
$c="ecx";
|
||||
|
||||
if ($sse2) {
|
||||
&picmeup("eax","OPENSSL_ia32cap_P");
|
||||
&bt(&DWP(0,"eax"),26);
|
||||
&jnc(&label("maw_non_sse2"));
|
||||
|
||||
&mov($r,&wparam(0));
|
||||
&mov($a,&wparam(1));
|
||||
&mov($c,&wparam(2));
|
||||
&movd("mm0",&wparam(3)); # mm0 = w
|
||||
&pxor("mm1","mm1"); # mm1 = carry_in
|
||||
&jmp(&label("maw_sse2_entry"));
|
||||
|
||||
&set_label("maw_sse2_unrolled",16);
|
||||
&movd("mm3",&DWP(0,$r,"",0)); # mm3 = r[0]
|
||||
&paddq("mm1","mm3"); # mm1 = carry_in + r[0]
|
||||
&movd("mm2",&DWP(0,$a,"",0)); # mm2 = a[0]
|
||||
&pmuludq("mm2","mm0"); # mm2 = w*a[0]
|
||||
&movd("mm4",&DWP(4,$a,"",0)); # mm4 = a[1]
|
||||
&pmuludq("mm4","mm0"); # mm4 = w*a[1]
|
||||
&movd("mm6",&DWP(8,$a,"",0)); # mm6 = a[2]
|
||||
&pmuludq("mm6","mm0"); # mm6 = w*a[2]
|
||||
&movd("mm7",&DWP(12,$a,"",0)); # mm7 = a[3]
|
||||
&pmuludq("mm7","mm0"); # mm7 = w*a[3]
|
||||
&paddq("mm1","mm2"); # mm1 = carry_in + r[0] + w*a[0]
|
||||
&movd("mm3",&DWP(4,$r,"",0)); # mm3 = r[1]
|
||||
&paddq("mm3","mm4"); # mm3 = r[1] + w*a[1]
|
||||
&movd("mm5",&DWP(8,$r,"",0)); # mm5 = r[2]
|
||||
&paddq("mm5","mm6"); # mm5 = r[2] + w*a[2]
|
||||
&movd("mm4",&DWP(12,$r,"",0)); # mm4 = r[3]
|
||||
&paddq("mm7","mm4"); # mm7 = r[3] + w*a[3]
|
||||
&movd(&DWP(0,$r,"",0),"mm1");
|
||||
&movd("mm2",&DWP(16,$a,"",0)); # mm2 = a[4]
|
||||
&pmuludq("mm2","mm0"); # mm2 = w*a[4]
|
||||
&psrlq("mm1",32); # mm1 = carry0
|
||||
&movd("mm4",&DWP(20,$a,"",0)); # mm4 = a[5]
|
||||
&pmuludq("mm4","mm0"); # mm4 = w*a[5]
|
||||
&paddq("mm1","mm3"); # mm1 = carry0 + r[1] + w*a[1]
|
||||
&movd("mm6",&DWP(24,$a,"",0)); # mm6 = a[6]
|
||||
&pmuludq("mm6","mm0"); # mm6 = w*a[6]
|
||||
&movd(&DWP(4,$r,"",0),"mm1");
|
||||
&psrlq("mm1",32); # mm1 = carry1
|
||||
&movd("mm3",&DWP(28,$a,"",0)); # mm3 = a[7]
|
||||
&add($a,32);
|
||||
&pmuludq("mm3","mm0"); # mm3 = w*a[7]
|
||||
&paddq("mm1","mm5"); # mm1 = carry1 + r[2] + w*a[2]
|
||||
&movd("mm5",&DWP(16,$r,"",0)); # mm5 = r[4]
|
||||
&paddq("mm2","mm5"); # mm2 = r[4] + w*a[4]
|
||||
&movd(&DWP(8,$r,"",0),"mm1");
|
||||
&psrlq("mm1",32); # mm1 = carry2
|
||||
&paddq("mm1","mm7"); # mm1 = carry2 + r[3] + w*a[3]
|
||||
&movd("mm5",&DWP(20,$r,"",0)); # mm5 = r[5]
|
||||
&paddq("mm4","mm5"); # mm4 = r[5] + w*a[5]
|
||||
&movd(&DWP(12,$r,"",0),"mm1");
|
||||
&psrlq("mm1",32); # mm1 = carry3
|
||||
&paddq("mm1","mm2"); # mm1 = carry3 + r[4] + w*a[4]
|
||||
&movd("mm5",&DWP(24,$r,"",0)); # mm5 = r[6]
|
||||
&paddq("mm6","mm5"); # mm6 = r[6] + w*a[6]
|
||||
&movd(&DWP(16,$r,"",0),"mm1");
|
||||
&psrlq("mm1",32); # mm1 = carry4
|
||||
&paddq("mm1","mm4"); # mm1 = carry4 + r[5] + w*a[5]
|
||||
&movd("mm5",&DWP(28,$r,"",0)); # mm5 = r[7]
|
||||
&paddq("mm3","mm5"); # mm3 = r[7] + w*a[7]
|
||||
&movd(&DWP(20,$r,"",0),"mm1");
|
||||
&psrlq("mm1",32); # mm1 = carry5
|
||||
&paddq("mm1","mm6"); # mm1 = carry5 + r[6] + w*a[6]
|
||||
&movd(&DWP(24,$r,"",0),"mm1");
|
||||
&psrlq("mm1",32); # mm1 = carry6
|
||||
&paddq("mm1","mm3"); # mm1 = carry6 + r[7] + w*a[7]
|
||||
&movd(&DWP(28,$r,"",0),"mm1");
|
||||
&lea($r,&DWP(32,$r));
|
||||
&psrlq("mm1",32); # mm1 = carry_out
|
||||
|
||||
&sub($c,8);
|
||||
&jz(&label("maw_sse2_exit"));
|
||||
&set_label("maw_sse2_entry");
|
||||
&test($c,0xfffffff8);
|
||||
&jnz(&label("maw_sse2_unrolled"));
|
||||
|
||||
&set_label("maw_sse2_loop",4);
|
||||
&movd("mm2",&DWP(0,$a)); # mm2 = a[i]
|
||||
&movd("mm3",&DWP(0,$r)); # mm3 = r[i]
|
||||
&pmuludq("mm2","mm0"); # a[i] *= w
|
||||
&lea($a,&DWP(4,$a));
|
||||
&paddq("mm1","mm3"); # carry += r[i]
|
||||
&paddq("mm1","mm2"); # carry += a[i]*w
|
||||
&movd(&DWP(0,$r),"mm1"); # r[i] = carry_low
|
||||
&sub($c,1);
|
||||
&psrlq("mm1",32); # carry = carry_high
|
||||
&lea($r,&DWP(4,$r));
|
||||
&jnz(&label("maw_sse2_loop"));
|
||||
&set_label("maw_sse2_exit");
|
||||
&movd("eax","mm1"); # c = carry_out
|
||||
&emms();
|
||||
&ret();
|
||||
|
||||
&set_label("maw_non_sse2",16);
|
||||
}
|
||||
|
||||
# function_begin prologue
|
||||
&push("ebp");
|
||||
&push("ebx");
|
||||
&push("esi");
|
||||
&push("edi");
|
||||
|
||||
&comment("");
|
||||
$Low="eax";
|
||||
$High="edx";
|
||||
$a="ebx";
|
||||
$w="ebp";
|
||||
$r="edi";
|
||||
$c="esi";
|
||||
|
||||
&xor($c,$c); # clear carry
|
||||
&mov($r,&wparam(0)); #
|
||||
|
||||
&mov("ecx",&wparam(2)); #
|
||||
&mov($a,&wparam(1)); #
|
||||
|
||||
&and("ecx",0xfffffff8); # num / 8
|
||||
&mov($w,&wparam(3)); #
|
||||
|
||||
&push("ecx"); # Up the stack for a tmp variable
|
||||
|
||||
&jz(&label("maw_finish"));
|
||||
|
||||
&set_label("maw_loop",16);
|
||||
|
||||
for ($i=0; $i<32; $i+=4)
|
||||
{
|
||||
&comment("Round $i");
|
||||
|
||||
&mov("eax",&DWP($i,$a)); # *a
|
||||
&mul($w); # *a * w
|
||||
&add("eax",$c); # L(t)+= c
|
||||
&adc("edx",0); # H(t)+=carry
|
||||
&add("eax",&DWP($i,$r)); # L(t)+= *r
|
||||
&adc("edx",0); # H(t)+=carry
|
||||
&mov(&DWP($i,$r),"eax"); # *r= L(t);
|
||||
&mov($c,"edx"); # c= H(t);
|
||||
}
|
||||
|
||||
&comment("");
|
||||
&sub("ecx",8);
|
||||
&lea($a,&DWP(32,$a));
|
||||
&lea($r,&DWP(32,$r));
|
||||
&jnz(&label("maw_loop"));
|
||||
|
||||
&set_label("maw_finish",0);
|
||||
&mov("ecx",&wparam(2)); # get num
|
||||
&and("ecx",7);
|
||||
&jnz(&label("maw_finish2")); # helps branch prediction
|
||||
&jmp(&label("maw_end"));
|
||||
|
||||
&set_label("maw_finish2",1);
|
||||
for ($i=0; $i<7; $i++)
|
||||
{
|
||||
&comment("Tail Round $i");
|
||||
&mov("eax",&DWP($i*4,$a)); # *a
|
||||
&mul($w); # *a * w
|
||||
&add("eax",$c); # L(t)+=c
|
||||
&adc("edx",0); # H(t)+=carry
|
||||
&add("eax",&DWP($i*4,$r)); # L(t)+= *r
|
||||
&adc("edx",0); # H(t)+=carry
|
||||
&dec("ecx") if ($i != 7-1);
|
||||
&mov(&DWP($i*4,$r),"eax"); # *r= L(t);
|
||||
&mov($c,"edx"); # c= H(t);
|
||||
&jz(&label("maw_end")) if ($i != 7-1);
|
||||
}
|
||||
&set_label("maw_end",0);
|
||||
&mov("eax",$c);
|
||||
|
||||
&pop("ecx"); # clear variable from
|
||||
|
||||
&function_end($name);
|
||||
}
|
||||
|
||||
sub bn_mul_words
|
||||
{
|
||||
local($name)=@_;
|
||||
|
||||
&function_begin_B($name,$sse2?"EXTRN\t_OPENSSL_ia32cap_P:DWORD":"");
|
||||
|
||||
$r="eax";
|
||||
$a="edx";
|
||||
$c="ecx";
|
||||
|
||||
if ($sse2) {
|
||||
&picmeup("eax","OPENSSL_ia32cap_P");
|
||||
&bt(&DWP(0,"eax"),26);
|
||||
&jnc(&label("mw_non_sse2"));
|
||||
|
||||
&mov($r,&wparam(0));
|
||||
&mov($a,&wparam(1));
|
||||
&mov($c,&wparam(2));
|
||||
&movd("mm0",&wparam(3)); # mm0 = w
|
||||
&pxor("mm1","mm1"); # mm1 = carry = 0
|
||||
|
||||
&set_label("mw_sse2_loop",16);
|
||||
&movd("mm2",&DWP(0,$a)); # mm2 = a[i]
|
||||
&pmuludq("mm2","mm0"); # a[i] *= w
|
||||
&lea($a,&DWP(4,$a));
|
||||
&paddq("mm1","mm2"); # carry += a[i]*w
|
||||
&movd(&DWP(0,$r),"mm1"); # r[i] = carry_low
|
||||
&sub($c,1);
|
||||
&psrlq("mm1",32); # carry = carry_high
|
||||
&lea($r,&DWP(4,$r));
|
||||
&jnz(&label("mw_sse2_loop"));
|
||||
|
||||
&movd("eax","mm1"); # return carry
|
||||
&emms();
|
||||
&ret();
|
||||
&set_label("mw_non_sse2",16);
|
||||
}
|
||||
|
||||
# function_begin prologue
|
||||
&push("ebp");
|
||||
&push("ebx");
|
||||
&push("esi");
|
||||
&push("edi");
|
||||
|
||||
&comment("");
|
||||
$Low="eax";
|
||||
$High="edx";
|
||||
$a="ebx";
|
||||
$w="ecx";
|
||||
$r="edi";
|
||||
$c="esi";
|
||||
$num="ebp";
|
||||
|
||||
&xor($c,$c); # clear carry
|
||||
&mov($r,&wparam(0)); #
|
||||
&mov($a,&wparam(1)); #
|
||||
&mov($num,&wparam(2)); #
|
||||
&mov($w,&wparam(3)); #
|
||||
|
||||
&and($num,0xfffffff8); # num / 8
|
||||
&jz(&label("mw_finish"));
|
||||
|
||||
&set_label("mw_loop",0);
|
||||
for ($i=0; $i<32; $i+=4)
|
||||
{
|
||||
&comment("Round $i");
|
||||
|
||||
&mov("eax",&DWP($i,$a,"",0)); # *a
|
||||
&mul($w); # *a * w
|
||||
&add("eax",$c); # L(t)+=c
|
||||
# XXX
|
||||
|
||||
&adc("edx",0); # H(t)+=carry
|
||||
&mov(&DWP($i,$r,"",0),"eax"); # *r= L(t);
|
||||
|
||||
&mov($c,"edx"); # c= H(t);
|
||||
}
|
||||
|
||||
&comment("");
|
||||
&add($a,32);
|
||||
&add($r,32);
|
||||
&sub($num,8);
|
||||
&jz(&label("mw_finish"));
|
||||
&jmp(&label("mw_loop"));
|
||||
|
||||
&set_label("mw_finish",0);
|
||||
&mov($num,&wparam(2)); # get num
|
||||
&and($num,7);
|
||||
&jnz(&label("mw_finish2"));
|
||||
&jmp(&label("mw_end"));
|
||||
|
||||
&set_label("mw_finish2",1);
|
||||
for ($i=0; $i<7; $i++)
|
||||
{
|
||||
&comment("Tail Round $i");
|
||||
&mov("eax",&DWP($i*4,$a,"",0));# *a
|
||||
&mul($w); # *a * w
|
||||
&add("eax",$c); # L(t)+=c
|
||||
# XXX
|
||||
&adc("edx",0); # H(t)+=carry
|
||||
&mov(&DWP($i*4,$r,"",0),"eax");# *r= L(t);
|
||||
&mov($c,"edx"); # c= H(t);
|
||||
&dec($num) if ($i != 7-1);
|
||||
&jz(&label("mw_end")) if ($i != 7-1);
|
||||
}
|
||||
&set_label("mw_end",0);
|
||||
&mov("eax",$c);
|
||||
|
||||
&function_end($name);
|
||||
}
|
||||
|
||||
sub bn_sqr_words
|
||||
{
|
||||
local($name)=@_;
|
||||
|
||||
&function_begin_B($name,$sse2?"EXTRN\t_OPENSSL_ia32cap_P:DWORD":"");
|
||||
|
||||
$r="eax";
|
||||
$a="edx";
|
||||
$c="ecx";
|
||||
|
||||
if ($sse2) {
|
||||
&picmeup("eax","OPENSSL_ia32cap_P");
|
||||
&bt(&DWP(0,"eax"),26);
|
||||
&jnc(&label("sqr_non_sse2"));
|
||||
|
||||
&mov($r,&wparam(0));
|
||||
&mov($a,&wparam(1));
|
||||
&mov($c,&wparam(2));
|
||||
|
||||
&set_label("sqr_sse2_loop",16);
|
||||
&movd("mm0",&DWP(0,$a)); # mm0 = a[i]
|
||||
&pmuludq("mm0","mm0"); # a[i] *= a[i]
|
||||
&lea($a,&DWP(4,$a)); # a++
|
||||
&movq(&QWP(0,$r),"mm0"); # r[i] = a[i]*a[i]
|
||||
&sub($c,1);
|
||||
&lea($r,&DWP(8,$r)); # r += 2
|
||||
&jnz(&label("sqr_sse2_loop"));
|
||||
|
||||
&emms();
|
||||
&ret();
|
||||
&set_label("sqr_non_sse2",16);
|
||||
}
|
||||
|
||||
# function_begin prologue
|
||||
&push("ebp");
|
||||
&push("ebx");
|
||||
&push("esi");
|
||||
&push("edi");
|
||||
|
||||
&comment("");
|
||||
$r="esi";
|
||||
$a="edi";
|
||||
$num="ebx";
|
||||
|
||||
&mov($r,&wparam(0)); #
|
||||
&mov($a,&wparam(1)); #
|
||||
&mov($num,&wparam(2)); #
|
||||
|
||||
&and($num,0xfffffff8); # num / 8
|
||||
&jz(&label("sw_finish"));
|
||||
|
||||
&set_label("sw_loop",0);
|
||||
for ($i=0; $i<32; $i+=4)
|
||||
{
|
||||
&comment("Round $i");
|
||||
&mov("eax",&DWP($i,$a,"",0)); # *a
|
||||
# XXX
|
||||
&mul("eax"); # *a * *a
|
||||
&mov(&DWP($i*2,$r,"",0),"eax"); #
|
||||
&mov(&DWP($i*2+4,$r,"",0),"edx");#
|
||||
}
|
||||
|
||||
&comment("");
|
||||
&add($a,32);
|
||||
&add($r,64);
|
||||
&sub($num,8);
|
||||
&jnz(&label("sw_loop"));
|
||||
|
||||
&set_label("sw_finish",0);
|
||||
&mov($num,&wparam(2)); # get num
|
||||
&and($num,7);
|
||||
&jz(&label("sw_end"));
|
||||
|
||||
for ($i=0; $i<7; $i++)
|
||||
{
|
||||
&comment("Tail Round $i");
|
||||
&mov("eax",&DWP($i*4,$a,"",0)); # *a
|
||||
# XXX
|
||||
&mul("eax"); # *a * *a
|
||||
&mov(&DWP($i*8,$r,"",0),"eax"); #
|
||||
&dec($num) if ($i != 7-1);
|
||||
&mov(&DWP($i*8+4,$r,"",0),"edx");
|
||||
&jz(&label("sw_end")) if ($i != 7-1);
|
||||
}
|
||||
&set_label("sw_end",0);
|
||||
|
||||
&function_end($name);
|
||||
}
|
||||
|
||||
sub bn_div_words
|
||||
{
|
||||
local($name)=@_;
|
||||
|
||||
&function_begin_B($name,"");
|
||||
&mov("edx",&wparam(0)); #
|
||||
&mov("eax",&wparam(1)); #
|
||||
&mov("ecx",&wparam(2)); #
|
||||
&div("ecx");
|
||||
&ret();
|
||||
&function_end_B($name);
|
||||
}
|
||||
|
||||
sub bn_add_words
|
||||
{
|
||||
local($name)=@_;
|
||||
|
||||
&function_begin($name,"");
|
||||
|
||||
&comment("");
|
||||
$a="esi";
|
||||
$b="edi";
|
||||
$c="eax";
|
||||
$r="ebx";
|
||||
$tmp1="ecx";
|
||||
$tmp2="edx";
|
||||
$num="ebp";
|
||||
|
||||
&mov($r,&wparam(0)); # get r
|
||||
&mov($a,&wparam(1)); # get a
|
||||
&mov($b,&wparam(2)); # get b
|
||||
&mov($num,&wparam(3)); # get num
|
||||
&xor($c,$c); # clear carry
|
||||
&and($num,0xfffffff8); # num / 8
|
||||
|
||||
&jz(&label("aw_finish"));
|
||||
|
||||
&set_label("aw_loop",0);
|
||||
for ($i=0; $i<8; $i++)
|
||||
{
|
||||
&comment("Round $i");
|
||||
|
||||
&mov($tmp1,&DWP($i*4,$a,"",0)); # *a
|
||||
&mov($tmp2,&DWP($i*4,$b,"",0)); # *b
|
||||
&add($tmp1,$c);
|
||||
&mov($c,0);
|
||||
&adc($c,$c);
|
||||
&add($tmp1,$tmp2);
|
||||
&adc($c,0);
|
||||
&mov(&DWP($i*4,$r,"",0),$tmp1); # *r
|
||||
}
|
||||
|
||||
&comment("");
|
||||
&add($a,32);
|
||||
&add($b,32);
|
||||
&add($r,32);
|
||||
&sub($num,8);
|
||||
&jnz(&label("aw_loop"));
|
||||
|
||||
&set_label("aw_finish",0);
|
||||
&mov($num,&wparam(3)); # get num
|
||||
&and($num,7);
|
||||
&jz(&label("aw_end"));
|
||||
|
||||
for ($i=0; $i<7; $i++)
|
||||
{
|
||||
&comment("Tail Round $i");
|
||||
&mov($tmp1,&DWP($i*4,$a,"",0)); # *a
|
||||
&mov($tmp2,&DWP($i*4,$b,"",0));# *b
|
||||
&add($tmp1,$c);
|
||||
&mov($c,0);
|
||||
&adc($c,$c);
|
||||
&add($tmp1,$tmp2);
|
||||
&adc($c,0);
|
||||
&dec($num) if ($i != 6);
|
||||
&mov(&DWP($i*4,$r,"",0),$tmp1); # *r
|
||||
&jz(&label("aw_end")) if ($i != 6);
|
||||
}
|
||||
&set_label("aw_end",0);
|
||||
|
||||
# &mov("eax",$c); # $c is "eax"
|
||||
|
||||
&function_end($name);
|
||||
}
|
||||
|
||||
sub bn_sub_words
|
||||
{
|
||||
local($name)=@_;
|
||||
|
||||
&function_begin($name,"");
|
||||
|
||||
&comment("");
|
||||
$a="esi";
|
||||
$b="edi";
|
||||
$c="eax";
|
||||
$r="ebx";
|
||||
$tmp1="ecx";
|
||||
$tmp2="edx";
|
||||
$num="ebp";
|
||||
|
||||
&mov($r,&wparam(0)); # get r
|
||||
&mov($a,&wparam(1)); # get a
|
||||
&mov($b,&wparam(2)); # get b
|
||||
&mov($num,&wparam(3)); # get num
|
||||
&xor($c,$c); # clear carry
|
||||
&and($num,0xfffffff8); # num / 8
|
||||
|
||||
&jz(&label("aw_finish"));
|
||||
|
||||
&set_label("aw_loop",0);
|
||||
for ($i=0; $i<8; $i++)
|
||||
{
|
||||
&comment("Round $i");
|
||||
|
||||
&mov($tmp1,&DWP($i*4,$a,"",0)); # *a
|
||||
&mov($tmp2,&DWP($i*4,$b,"",0)); # *b
|
||||
&sub($tmp1,$c);
|
||||
&mov($c,0);
|
||||
&adc($c,$c);
|
||||
&sub($tmp1,$tmp2);
|
||||
&adc($c,0);
|
||||
&mov(&DWP($i*4,$r,"",0),$tmp1); # *r
|
||||
}
|
||||
|
||||
&comment("");
|
||||
&add($a,32);
|
||||
&add($b,32);
|
||||
&add($r,32);
|
||||
&sub($num,8);
|
||||
&jnz(&label("aw_loop"));
|
||||
|
||||
&set_label("aw_finish",0);
|
||||
&mov($num,&wparam(3)); # get num
|
||||
&and($num,7);
|
||||
&jz(&label("aw_end"));
|
||||
|
||||
for ($i=0; $i<7; $i++)
|
||||
{
|
||||
&comment("Tail Round $i");
|
||||
&mov($tmp1,&DWP($i*4,$a,"",0)); # *a
|
||||
&mov($tmp2,&DWP($i*4,$b,"",0));# *b
|
||||
&sub($tmp1,$c);
|
||||
&mov($c,0);
|
||||
&adc($c,$c);
|
||||
&sub($tmp1,$tmp2);
|
||||
&adc($c,0);
|
||||
&dec($num) if ($i != 6);
|
||||
&mov(&DWP($i*4,$r,"",0),$tmp1); # *r
|
||||
&jz(&label("aw_end")) if ($i != 6);
|
||||
}
|
||||
&set_label("aw_end",0);
|
||||
|
||||
# &mov("eax",$c); # $c is "eax"
|
||||
|
||||
&function_end($name);
|
||||
}
|
||||
|
||||
sub bn_sub_part_words
|
||||
{
|
||||
local($name)=@_;
|
||||
|
||||
&function_begin($name,"");
|
||||
|
||||
&comment("");
|
||||
$a="esi";
|
||||
$b="edi";
|
||||
$c="eax";
|
||||
$r="ebx";
|
||||
$tmp1="ecx";
|
||||
$tmp2="edx";
|
||||
$num="ebp";
|
||||
|
||||
&mov($r,&wparam(0)); # get r
|
||||
&mov($a,&wparam(1)); # get a
|
||||
&mov($b,&wparam(2)); # get b
|
||||
&mov($num,&wparam(3)); # get num
|
||||
&xor($c,$c); # clear carry
|
||||
&and($num,0xfffffff8); # num / 8
|
||||
|
||||
&jz(&label("aw_finish"));
|
||||
|
||||
&set_label("aw_loop",0);
|
||||
for ($i=0; $i<8; $i++)
|
||||
{
|
||||
&comment("Round $i");
|
||||
|
||||
&mov($tmp1,&DWP($i*4,$a,"",0)); # *a
|
||||
&mov($tmp2,&DWP($i*4,$b,"",0)); # *b
|
||||
&sub($tmp1,$c);
|
||||
&mov($c,0);
|
||||
&adc($c,$c);
|
||||
&sub($tmp1,$tmp2);
|
||||
&adc($c,0);
|
||||
&mov(&DWP($i*4,$r,"",0),$tmp1); # *r
|
||||
}
|
||||
|
||||
&comment("");
|
||||
&add($a,32);
|
||||
&add($b,32);
|
||||
&add($r,32);
|
||||
&sub($num,8);
|
||||
&jnz(&label("aw_loop"));
|
||||
|
||||
&set_label("aw_finish",0);
|
||||
&mov($num,&wparam(3)); # get num
|
||||
&and($num,7);
|
||||
&jz(&label("aw_end"));
|
||||
|
||||
for ($i=0; $i<7; $i++)
|
||||
{
|
||||
&comment("Tail Round $i");
|
||||
&mov($tmp1,&DWP(0,$a,"",0)); # *a
|
||||
&mov($tmp2,&DWP(0,$b,"",0));# *b
|
||||
&sub($tmp1,$c);
|
||||
&mov($c,0);
|
||||
&adc($c,$c);
|
||||
&sub($tmp1,$tmp2);
|
||||
&adc($c,0);
|
||||
&mov(&DWP(0,$r,"",0),$tmp1); # *r
|
||||
&add($a, 4);
|
||||
&add($b, 4);
|
||||
&add($r, 4);
|
||||
&dec($num) if ($i != 6);
|
||||
&jz(&label("aw_end")) if ($i != 6);
|
||||
}
|
||||
&set_label("aw_end",0);
|
||||
|
||||
&cmp(&wparam(4),0);
|
||||
&je(&label("pw_end"));
|
||||
|
||||
&mov($num,&wparam(4)); # get dl
|
||||
&cmp($num,0);
|
||||
&je(&label("pw_end"));
|
||||
&jge(&label("pw_pos"));
|
||||
|
||||
&comment("pw_neg");
|
||||
&mov($tmp2,0);
|
||||
&sub($tmp2,$num);
|
||||
&mov($num,$tmp2);
|
||||
&and($num,0xfffffff8); # num / 8
|
||||
&jz(&label("pw_neg_finish"));
|
||||
|
||||
&set_label("pw_neg_loop",0);
|
||||
for ($i=0; $i<8; $i++)
|
||||
{
|
||||
&comment("dl<0 Round $i");
|
||||
|
||||
&mov($tmp1,0);
|
||||
&mov($tmp2,&DWP($i*4,$b,"",0)); # *b
|
||||
&sub($tmp1,$c);
|
||||
&mov($c,0);
|
||||
&adc($c,$c);
|
||||
&sub($tmp1,$tmp2);
|
||||
&adc($c,0);
|
||||
&mov(&DWP($i*4,$r,"",0),$tmp1); # *r
|
||||
}
|
||||
|
||||
&comment("");
|
||||
&add($b,32);
|
||||
&add($r,32);
|
||||
&sub($num,8);
|
||||
&jnz(&label("pw_neg_loop"));
|
||||
|
||||
&set_label("pw_neg_finish",0);
|
||||
&mov($tmp2,&wparam(4)); # get dl
|
||||
&mov($num,0);
|
||||
&sub($num,$tmp2);
|
||||
&and($num,7);
|
||||
&jz(&label("pw_end"));
|
||||
|
||||
for ($i=0; $i<7; $i++)
|
||||
{
|
||||
&comment("dl<0 Tail Round $i");
|
||||
&mov($tmp1,0);
|
||||
&mov($tmp2,&DWP($i*4,$b,"",0));# *b
|
||||
&sub($tmp1,$c);
|
||||
&mov($c,0);
|
||||
&adc($c,$c);
|
||||
&sub($tmp1,$tmp2);
|
||||
&adc($c,0);
|
||||
&dec($num) if ($i != 6);
|
||||
&mov(&DWP($i*4,$r,"",0),$tmp1); # *r
|
||||
&jz(&label("pw_end")) if ($i != 6);
|
||||
}
|
||||
|
||||
&jmp(&label("pw_end"));
|
||||
|
||||
&set_label("pw_pos",0);
|
||||
|
||||
&and($num,0xfffffff8); # num / 8
|
||||
&jz(&label("pw_pos_finish"));
|
||||
|
||||
&set_label("pw_pos_loop",0);
|
||||
|
||||
for ($i=0; $i<8; $i++)
|
||||
{
|
||||
&comment("dl>0 Round $i");
|
||||
|
||||
&mov($tmp1,&DWP($i*4,$a,"",0)); # *a
|
||||
&sub($tmp1,$c);
|
||||
&mov(&DWP($i*4,$r,"",0),$tmp1); # *r
|
||||
&jnc(&label("pw_nc".$i));
|
||||
}
|
||||
|
||||
&comment("");
|
||||
&add($a,32);
|
||||
&add($r,32);
|
||||
&sub($num,8);
|
||||
&jnz(&label("pw_pos_loop"));
|
||||
|
||||
&set_label("pw_pos_finish",0);
|
||||
&mov($num,&wparam(4)); # get dl
|
||||
&and($num,7);
|
||||
&jz(&label("pw_end"));
|
||||
|
||||
for ($i=0; $i<7; $i++)
|
||||
{
|
||||
&comment("dl>0 Tail Round $i");
|
||||
&mov($tmp1,&DWP($i*4,$a,"",0)); # *a
|
||||
&sub($tmp1,$c);
|
||||
&mov(&DWP($i*4,$r,"",0),$tmp1); # *r
|
||||
&jnc(&label("pw_tail_nc".$i));
|
||||
&dec($num) if ($i != 6);
|
||||
&jz(&label("pw_end")) if ($i != 6);
|
||||
}
|
||||
&mov($c,1);
|
||||
&jmp(&label("pw_end"));
|
||||
|
||||
&set_label("pw_nc_loop",0);
|
||||
for ($i=0; $i<8; $i++)
|
||||
{
|
||||
&mov($tmp1,&DWP($i*4,$a,"",0)); # *a
|
||||
&mov(&DWP($i*4,$r,"",0),$tmp1); # *r
|
||||
&set_label("pw_nc".$i,0);
|
||||
}
|
||||
|
||||
&comment("");
|
||||
&add($a,32);
|
||||
&add($r,32);
|
||||
&sub($num,8);
|
||||
&jnz(&label("pw_nc_loop"));
|
||||
|
||||
&mov($num,&wparam(4)); # get dl
|
||||
&and($num,7);
|
||||
&jz(&label("pw_nc_end"));
|
||||
|
||||
for ($i=0; $i<7; $i++)
|
||||
{
|
||||
&mov($tmp1,&DWP($i*4,$a,"",0)); # *a
|
||||
&mov(&DWP($i*4,$r,"",0),$tmp1); # *r
|
||||
&set_label("pw_tail_nc".$i,0);
|
||||
&dec($num) if ($i != 6);
|
||||
&jz(&label("pw_nc_end")) if ($i != 6);
|
||||
}
|
||||
|
||||
&set_label("pw_nc_end",0);
|
||||
&mov($c,0);
|
||||
|
||||
&set_label("pw_end",0);
|
||||
|
||||
# &mov("eax",$c); # $c is "eax"
|
||||
|
||||
&function_end($name);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,10 @@
|
||||
#! /usr/bin/env perl
|
||||
# Copyright 1995-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/local/bin/perl
|
||||
|
||||
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
push(@INC,"${dir}","${dir}../../../perlasm");
|
||||
push(@INC,"${dir}","${dir}../../perlasm");
|
||||
require "x86asm.pl";
|
||||
|
||||
$output = pop;
|
||||
open STDOUT,">$output";
|
||||
|
||||
&asm_init($ARGV[0]);
|
||||
&asm_init($ARGV[0],$0);
|
||||
|
||||
&bn_mul_comba("bn_mul_comba8",8);
|
||||
&bn_mul_comba("bn_mul_comba4",4);
|
||||
@@ -22,8 +13,6 @@ open STDOUT,">$output";
|
||||
|
||||
&asm_finish();
|
||||
|
||||
close STDOUT or die "error closing STDOUT";
|
||||
|
||||
sub mul_add_c
|
||||
{
|
||||
local($a,$ai,$b,$bi,$c0,$c1,$c2,$pos,$i,$na,$nb)=@_;
|
||||
@@ -47,7 +36,7 @@ sub mul_add_c
|
||||
&mov("edx",&DWP(($nb)*4,$b,"",0)) if $pos == 1; # laod next b
|
||||
###
|
||||
&adc($c2,0);
|
||||
# is pos > 1, it means it is the last loop
|
||||
# is pos > 1, it means it is the last loop
|
||||
&mov(&DWP($i*4,"eax","",0),$c0) if $pos > 0; # save r[];
|
||||
&mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 1; # laod next a
|
||||
}
|
||||
@@ -76,7 +65,7 @@ sub sqr_add_c
|
||||
&mov("edx",&DWP(($nb)*4,$a,"",0)) if ($pos == 1) && ($na != $nb);
|
||||
###
|
||||
&adc($c2,0);
|
||||
# is pos > 1, it means it is the last loop
|
||||
# is pos > 1, it means it is the last loop
|
||||
&mov(&DWP($i*4,$r,"",0),$c0) if $pos > 0; # save r[];
|
||||
&mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 1; # load next b
|
||||
}
|
||||
@@ -127,7 +116,7 @@ sub bn_mul_comba
|
||||
$c2="ebp";
|
||||
$a="esi";
|
||||
$b="edi";
|
||||
|
||||
|
||||
$as=0;
|
||||
$ae=0;
|
||||
$bs=0;
|
||||
@@ -142,9 +131,9 @@ sub bn_mul_comba
|
||||
&push("ebx");
|
||||
|
||||
&xor($c0,$c0);
|
||||
&mov("eax",&DWP(0,$a,"",0)); # load the first word
|
||||
&mov("eax",&DWP(0,$a,"",0)); # load the first word
|
||||
&xor($c1,$c1);
|
||||
&mov("edx",&DWP(0,$b,"",0)); # load the first second
|
||||
&mov("edx",&DWP(0,$b,"",0)); # load the first second
|
||||
|
||||
for ($i=0; $i<$tot; $i++)
|
||||
{
|
||||
@@ -152,7 +141,7 @@ sub bn_mul_comba
|
||||
$bi=$bs;
|
||||
$end=$be+1;
|
||||
|
||||
&comment("################## Calculate word $i");
|
||||
&comment("################## Calculate word $i");
|
||||
|
||||
for ($j=$bs; $j<$end; $j++)
|
||||
{
|
||||
@@ -1,30 +1,61 @@
|
||||
#! /usr/bin/env perl
|
||||
# Copyright 2013-2016 The OpenSSL Project Authors. All Rights Reserved.
|
||||
# Copyright (c) 2012, Intel Corporation. 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
|
||||
#
|
||||
# Originally written by Shay Gueron (1, 2), and Vlad Krasnov (1)
|
||||
# (1) Intel Corporation, Israel Development Center, Haifa, Israel
|
||||
# (2) University of Haifa, Israel
|
||||
#
|
||||
# References:
|
||||
# [1] S. Gueron, V. Krasnov: "Software Implementation of Modular
|
||||
# Exponentiation, Using Advanced Vector Instructions Architectures",
|
||||
# F. Ozbudak and F. Rodriguez-Henriquez (Eds.): WAIFI 2012, LNCS 7369,
|
||||
# pp. 119?135, 2012. Springer-Verlag Berlin Heidelberg 2012
|
||||
# [2] S. Gueron: "Efficient Software Implementations of Modular
|
||||
# Exponentiation", Journal of Cryptographic Engineering 2:31-43 (2012).
|
||||
# [3] S. Gueron, V. Krasnov: "Speeding up Big-numbers Squaring",IEEE
|
||||
# Proceedings of 9th International Conference on Information Technology:
|
||||
# New Generations (ITNG 2012), pp.821-823 (2012)
|
||||
# [4] S. Gueron, V. Krasnov: "[PATCH] Efficient and side channel analysis
|
||||
# resistant 1024-bit modular exponentiation, for optimizing RSA2048
|
||||
# on AVX2 capable x86_64 platforms",
|
||||
# http://rt.openssl.org/Ticket/Display.html?id=2850&user=guest&pass=guest
|
||||
#!/usr/bin/env perl
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
# Copyright (c) 2012, Intel Corporation #
|
||||
# #
|
||||
# All rights reserved. #
|
||||
# #
|
||||
# Redistribution and use in source and binary forms, with or without #
|
||||
# modification, are permitted provided that the following conditions are #
|
||||
# met: #
|
||||
# #
|
||||
# * Redistributions of source code must retain the above copyright #
|
||||
# notice, this list of conditions and the following disclaimer. #
|
||||
# #
|
||||
# * Redistributions in binary form must reproduce the above copyright #
|
||||
# notice, this list of conditions and the following disclaimer in the #
|
||||
# documentation and/or other materials provided with the #
|
||||
# distribution. #
|
||||
# #
|
||||
# * Neither the name of the Intel Corporation nor the names of its #
|
||||
# contributors may be used to endorse or promote products derived from #
|
||||
# this software without specific prior written permission. #
|
||||
# #
|
||||
# #
|
||||
# THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY #
|
||||
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE #
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR #
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR #
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, #
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, #
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR #
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF #
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING #
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS #
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #
|
||||
# #
|
||||
##############################################################################
|
||||
# Developers and authors: #
|
||||
# Shay Gueron (1, 2), and Vlad Krasnov (1) #
|
||||
# (1) Intel Corporation, Israel Development Center, Haifa, Israel #
|
||||
# (2) University of Haifa, Israel #
|
||||
##############################################################################
|
||||
# Reference: #
|
||||
# [1] S. Gueron, V. Krasnov: "Software Implementation of Modular #
|
||||
# Exponentiation, Using Advanced Vector Instructions Architectures", #
|
||||
# F. Ozbudak and F. Rodriguez-Henriquez (Eds.): WAIFI 2012, LNCS 7369, #
|
||||
# pp. 119?135, 2012. Springer-Verlag Berlin Heidelberg 2012 #
|
||||
# [2] S. Gueron: "Efficient Software Implementations of Modular #
|
||||
# Exponentiation", Journal of Cryptographic Engineering 2:31-43 (2012). #
|
||||
# [3] S. Gueron, V. Krasnov: "Speeding up Big-numbers Squaring",IEEE #
|
||||
# Proceedings of 9th International Conference on Information Technology: #
|
||||
# New Generations (ITNG 2012), pp.821-823 (2012) #
|
||||
# [4] S. Gueron, V. Krasnov: "[PATCH] Efficient and side channel analysis #
|
||||
# resistant 1024-bit modular exponentiation, for optimizing RSA2048 #
|
||||
# on AVX2 capable x86_64 platforms", #
|
||||
# http://rt.openssl.org/Ticket/Display.html?id=2850&user=guest&pass=guest#
|
||||
##############################################################################
|
||||
#
|
||||
# +13% improvement over original submission by <appro@openssl.org>
|
||||
#
|
||||
@@ -45,15 +76,18 @@ $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
|
||||
|
||||
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
|
||||
( $xlate="${dir}../../../perlasm/x86_64-xlate.pl" and -f $xlate) or
|
||||
( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
|
||||
die "can't locate x86_64-xlate.pl";
|
||||
|
||||
# In upstream, this is controlled by shelling out to the compiler to check
|
||||
# versions, but BoringSSL is intended to be used with pre-generated perlasm
|
||||
# output, so this isn't useful anyway.
|
||||
$avx = 2;
|
||||
#
|
||||
# TODO(davidben): Enable these after testing. $avx goes up to 2 and $addx to 1.
|
||||
$avx = 0;
|
||||
$addx = 0;
|
||||
|
||||
open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
|
||||
open OUT,"| \"$^X\" $xlate $flavour $output";
|
||||
*STDOUT = *OUT;
|
||||
|
||||
if ($avx>1) {{{
|
||||
@@ -111,21 +145,13 @@ $code.=<<___;
|
||||
.type rsaz_1024_sqr_avx2,\@function,5
|
||||
.align 64
|
||||
rsaz_1024_sqr_avx2: # 702 cycles, 14% faster than rsaz_1024_mul_avx2
|
||||
.cfi_startproc
|
||||
lea (%rsp), %rax
|
||||
.cfi_def_cfa_register %rax
|
||||
push %rbx
|
||||
.cfi_push %rbx
|
||||
push %rbp
|
||||
.cfi_push %rbp
|
||||
push %r12
|
||||
.cfi_push %r12
|
||||
push %r13
|
||||
.cfi_push %r13
|
||||
push %r14
|
||||
.cfi_push %r14
|
||||
push %r15
|
||||
.cfi_push %r15
|
||||
vzeroupper
|
||||
___
|
||||
$code.=<<___ if ($win64);
|
||||
@@ -144,7 +170,6 @@ $code.=<<___ if ($win64);
|
||||
___
|
||||
$code.=<<___;
|
||||
mov %rax,%rbp
|
||||
.cfi_def_cfa_register %rbp
|
||||
mov %rdx, $np # reassigned argument
|
||||
sub \$$FrameSize, %rsp
|
||||
mov $np, $tmp
|
||||
@@ -198,7 +223,7 @@ $code.=<<___;
|
||||
vmovdqu 32*8-128($ap), $ACC8
|
||||
|
||||
lea 192(%rsp), $tp0 # 64+128=192
|
||||
vmovdqu .Land_mask(%rip), $AND_MASK
|
||||
vpbroadcastq .Land_mask(%rip), $AND_MASK
|
||||
jmp .LOOP_GRANDE_SQR_1024
|
||||
|
||||
.align 32
|
||||
@@ -334,7 +359,7 @@ $code.=<<___;
|
||||
vpaddq $TEMP1, $ACC1, $ACC1
|
||||
vpmuludq 32*7-128($aap), $B2, $ACC2
|
||||
vpbroadcastq 32*5-128($tpa), $B2
|
||||
vpaddq 32*11-448($tp1), $ACC2, $ACC2
|
||||
vpaddq 32*11-448($tp1), $ACC2, $ACC2
|
||||
|
||||
vmovdqu $ACC6, 32*6-192($tp0)
|
||||
vmovdqu $ACC7, 32*7-192($tp0)
|
||||
@@ -393,7 +418,7 @@ $code.=<<___;
|
||||
vmovdqu $ACC7, 32*16-448($tp1)
|
||||
lea 8($tp1), $tp1
|
||||
|
||||
dec $i
|
||||
dec $i
|
||||
jnz .LOOP_SQR_1024
|
||||
___
|
||||
$ZERO = $ACC9;
|
||||
@@ -738,7 +763,7 @@ $code.=<<___;
|
||||
vpblendd \$3, $TEMP4, $TEMP5, $TEMP4
|
||||
vpaddq $TEMP3, $ACC7, $ACC7
|
||||
vpaddq $TEMP4, $ACC8, $ACC8
|
||||
|
||||
|
||||
vpsrlq \$29, $ACC4, $TEMP1
|
||||
vpand $AND_MASK, $ACC4, $ACC4
|
||||
vpsrlq \$29, $ACC5, $TEMP2
|
||||
@@ -777,10 +802,8 @@ $code.=<<___;
|
||||
|
||||
vzeroall
|
||||
mov %rbp, %rax
|
||||
.cfi_def_cfa_register %rax
|
||||
___
|
||||
$code.=<<___ if ($win64);
|
||||
.Lsqr_1024_in_tail:
|
||||
movaps -0xd8(%rax),%xmm6
|
||||
movaps -0xc8(%rax),%xmm7
|
||||
movaps -0xb8(%rax),%xmm8
|
||||
@@ -794,22 +817,14 @@ $code.=<<___ if ($win64);
|
||||
___
|
||||
$code.=<<___;
|
||||
mov -48(%rax),%r15
|
||||
.cfi_restore %r15
|
||||
mov -40(%rax),%r14
|
||||
.cfi_restore %r14
|
||||
mov -32(%rax),%r13
|
||||
.cfi_restore %r13
|
||||
mov -24(%rax),%r12
|
||||
.cfi_restore %r12
|
||||
mov -16(%rax),%rbp
|
||||
.cfi_restore %rbp
|
||||
mov -8(%rax),%rbx
|
||||
.cfi_restore %rbx
|
||||
lea (%rax),%rsp # restore %rsp
|
||||
.cfi_def_cfa_register %rsp
|
||||
.Lsqr_1024_epilogue:
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size rsaz_1024_sqr_avx2,.-rsaz_1024_sqr_avx2
|
||||
___
|
||||
}
|
||||
@@ -862,21 +877,13 @@ $code.=<<___;
|
||||
.type rsaz_1024_mul_avx2,\@function,5
|
||||
.align 64
|
||||
rsaz_1024_mul_avx2:
|
||||
.cfi_startproc
|
||||
lea (%rsp), %rax
|
||||
.cfi_def_cfa_register %rax
|
||||
push %rbx
|
||||
.cfi_push %rbx
|
||||
push %rbp
|
||||
.cfi_push %rbp
|
||||
push %r12
|
||||
.cfi_push %r12
|
||||
push %r13
|
||||
.cfi_push %r13
|
||||
push %r14
|
||||
.cfi_push %r14
|
||||
push %r15
|
||||
.cfi_push %r15
|
||||
___
|
||||
$code.=<<___ if ($win64);
|
||||
vzeroupper
|
||||
@@ -895,7 +902,6 @@ $code.=<<___ if ($win64);
|
||||
___
|
||||
$code.=<<___;
|
||||
mov %rax,%rbp
|
||||
.cfi_def_cfa_register %rbp
|
||||
vzeroall
|
||||
mov %rdx, $bp # reassigned argument
|
||||
sub \$64,%rsp
|
||||
@@ -1048,10 +1054,10 @@ $code.=<<___;
|
||||
vpmuludq 32*6-128($np),$Yi,$TEMP1
|
||||
vpaddq $TEMP1,$ACC6,$ACC6
|
||||
vpmuludq 32*7-128($np),$Yi,$TEMP2
|
||||
vpblendd \$3, $ZERO, $ACC9, $TEMP1 # correct $ACC3
|
||||
vpblendd \$3, $ZERO, $ACC9, $ACC9 # correct $ACC3
|
||||
vpaddq $TEMP2,$ACC7,$ACC7
|
||||
vpmuludq 32*8-128($np),$Yi,$TEMP0
|
||||
vpaddq $TEMP1, $ACC3, $ACC3 # correct $ACC3
|
||||
vpaddq $ACC9, $ACC3, $ACC3 # correct $ACC3
|
||||
vpaddq $TEMP0,$ACC8,$ACC8
|
||||
|
||||
mov %rbx, %rax
|
||||
@@ -1064,9 +1070,7 @@ $code.=<<___;
|
||||
vmovdqu -8+32*2-128($ap),$TEMP2
|
||||
|
||||
mov $r1, %rax
|
||||
vpblendd \$0xfc, $ZERO, $ACC9, $ACC9 # correct $ACC3
|
||||
imull $n0, %eax
|
||||
vpaddq $ACC9,$ACC4,$ACC4 # correct $ACC3
|
||||
and \$0x1fffffff, %eax
|
||||
|
||||
imulq 16-128($ap),%rbx
|
||||
@@ -1302,12 +1306,15 @@ ___
|
||||
# But as we underutilize resources, it's possible to correct in
|
||||
# each iteration with marginal performance loss. But then, as
|
||||
# we do it in each iteration, we can correct less digits, and
|
||||
# avoid performance penalties completely.
|
||||
# avoid performance penalties completely. Also note that we
|
||||
# correct only three digits out of four. This works because
|
||||
# most significant digit is subjected to less additions.
|
||||
|
||||
$TEMP0 = $ACC9;
|
||||
$TEMP3 = $Bi;
|
||||
$TEMP4 = $Yi;
|
||||
$code.=<<___;
|
||||
vpermq \$0, $AND_MASK, $AND_MASK
|
||||
vpaddq (%rsp), $TEMP1, $ACC0
|
||||
|
||||
vpsrlq \$29, $ACC0, $TEMP1
|
||||
@@ -1421,17 +1428,15 @@ $code.=<<___;
|
||||
vpaddq $TEMP4, $ACC8, $ACC8
|
||||
|
||||
vmovdqu $ACC4, 128-128($rp)
|
||||
vmovdqu $ACC5, 160-128($rp)
|
||||
vmovdqu $ACC5, 160-128($rp)
|
||||
vmovdqu $ACC6, 192-128($rp)
|
||||
vmovdqu $ACC7, 224-128($rp)
|
||||
vmovdqu $ACC8, 256-128($rp)
|
||||
vzeroupper
|
||||
|
||||
mov %rbp, %rax
|
||||
.cfi_def_cfa_register %rax
|
||||
___
|
||||
$code.=<<___ if ($win64);
|
||||
.Lmul_1024_in_tail:
|
||||
movaps -0xd8(%rax),%xmm6
|
||||
movaps -0xc8(%rax),%xmm7
|
||||
movaps -0xb8(%rax),%xmm8
|
||||
@@ -1445,22 +1450,14 @@ $code.=<<___ if ($win64);
|
||||
___
|
||||
$code.=<<___;
|
||||
mov -48(%rax),%r15
|
||||
.cfi_restore %r15
|
||||
mov -40(%rax),%r14
|
||||
.cfi_restore %r14
|
||||
mov -32(%rax),%r13
|
||||
.cfi_restore %r13
|
||||
mov -24(%rax),%r12
|
||||
.cfi_restore %r12
|
||||
mov -16(%rax),%rbp
|
||||
.cfi_restore %rbp
|
||||
mov -8(%rax),%rbx
|
||||
.cfi_restore %rbx
|
||||
lea (%rax),%rsp # restore %rsp
|
||||
.cfi_def_cfa_register %rsp
|
||||
.Lmul_1024_epilogue:
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size rsaz_1024_mul_avx2,.-rsaz_1024_mul_avx2
|
||||
___
|
||||
}
|
||||
@@ -1473,7 +1470,6 @@ $code.=<<___;
|
||||
.type rsaz_1024_red2norm_avx2,\@abi-omnipotent
|
||||
.align 32
|
||||
rsaz_1024_red2norm_avx2:
|
||||
.cfi_startproc
|
||||
sub \$-128,$inp # size optimization
|
||||
xor %rax,%rax
|
||||
___
|
||||
@@ -1507,14 +1503,12 @@ ___
|
||||
}
|
||||
$code.=<<___;
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size rsaz_1024_red2norm_avx2,.-rsaz_1024_red2norm_avx2
|
||||
|
||||
.globl rsaz_1024_norm2red_avx2
|
||||
.type rsaz_1024_norm2red_avx2,\@abi-omnipotent
|
||||
.align 32
|
||||
rsaz_1024_norm2red_avx2:
|
||||
.cfi_startproc
|
||||
sub \$-128,$out # size optimization
|
||||
mov ($inp),@T[0]
|
||||
mov \$0x1fffffff,%eax
|
||||
@@ -1546,7 +1540,6 @@ $code.=<<___;
|
||||
mov @T[0],`8*($j+2)-128`($out)
|
||||
mov @T[0],`8*($j+3)-128`($out)
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size rsaz_1024_norm2red_avx2,.-rsaz_1024_norm2red_avx2
|
||||
___
|
||||
}
|
||||
@@ -1558,7 +1551,6 @@ $code.=<<___;
|
||||
.type rsaz_1024_scatter5_avx2,\@abi-omnipotent
|
||||
.align 32
|
||||
rsaz_1024_scatter5_avx2:
|
||||
.cfi_startproc
|
||||
vzeroupper
|
||||
vmovdqu .Lscatter_permd(%rip),%ymm5
|
||||
shl \$4,$power
|
||||
@@ -1578,17 +1570,14 @@ rsaz_1024_scatter5_avx2:
|
||||
|
||||
vzeroupper
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size rsaz_1024_scatter5_avx2,.-rsaz_1024_scatter5_avx2
|
||||
|
||||
.globl rsaz_1024_gather5_avx2
|
||||
.type rsaz_1024_gather5_avx2,\@abi-omnipotent
|
||||
.align 32
|
||||
rsaz_1024_gather5_avx2:
|
||||
.cfi_startproc
|
||||
vzeroupper
|
||||
mov %rsp,%r11
|
||||
.cfi_def_cfa_register %r11
|
||||
___
|
||||
$code.=<<___ if ($win64);
|
||||
lea -0x88(%rsp),%rax
|
||||
@@ -1726,21 +1715,39 @@ $code.=<<___ if ($win64);
|
||||
movaps -0x38(%r11),%xmm13
|
||||
movaps -0x28(%r11),%xmm14
|
||||
movaps -0x18(%r11),%xmm15
|
||||
.LSEH_end_rsaz_1024_gather5:
|
||||
___
|
||||
$code.=<<___;
|
||||
lea (%r11),%rsp
|
||||
.cfi_def_cfa_register %rsp
|
||||
ret
|
||||
.cfi_endproc
|
||||
.LSEH_end_rsaz_1024_gather5:
|
||||
.size rsaz_1024_gather5_avx2,.-rsaz_1024_gather5_avx2
|
||||
___
|
||||
}
|
||||
|
||||
$code.=<<___;
|
||||
.extern OPENSSL_ia32cap_P
|
||||
.globl rsaz_avx2_eligible
|
||||
.type rsaz_avx2_eligible,\@abi-omnipotent
|
||||
.align 32
|
||||
rsaz_avx2_eligible:
|
||||
mov OPENSSL_ia32cap_P+8(%rip),%eax
|
||||
___
|
||||
$code.=<<___ if ($addx);
|
||||
mov \$`1<<8|1<<19`,%ecx
|
||||
mov \$0,%edx
|
||||
and %eax,%ecx
|
||||
cmp \$`1<<8|1<<19`,%ecx # check for BMI2+AD*X
|
||||
cmove %edx,%eax
|
||||
___
|
||||
$code.=<<___;
|
||||
and \$`1<<5`,%eax
|
||||
shr \$5,%eax
|
||||
ret
|
||||
.size rsaz_avx2_eligible,.-rsaz_avx2_eligible
|
||||
|
||||
.align 64
|
||||
.Land_mask:
|
||||
.quad 0x1fffffff,0x1fffffff,0x1fffffff,0x1fffffff
|
||||
.quad 0x1fffffff,0x1fffffff,0x1fffffff,-1
|
||||
.Lscatter_permd:
|
||||
.long 0,2,4,6,7,7,7,7
|
||||
.Lgather_permd:
|
||||
@@ -1785,17 +1792,14 @@ rsaz_se_handler:
|
||||
cmp %r10,%rbx # context->Rip<prologue label
|
||||
jb .Lcommon_seh_tail
|
||||
|
||||
mov 152($context),%rax # pull context->Rsp
|
||||
|
||||
mov 4(%r11),%r10d # HandlerData[1]
|
||||
lea (%rsi,%r10),%r10 # epilogue label
|
||||
cmp %r10,%rbx # context->Rip>=epilogue label
|
||||
jae .Lcommon_seh_tail
|
||||
|
||||
mov 160($context),%rbp # pull context->Rbp
|
||||
|
||||
mov 8(%r11),%r10d # HandlerData[2]
|
||||
lea (%rsi,%r10),%r10 # "in tail" label
|
||||
cmp %r10,%rbx # context->Rip>="in tail" label
|
||||
cmovc %rbp,%rax
|
||||
mov 160($context),%rax # pull context->Rbp
|
||||
|
||||
mov -48(%rax),%r15
|
||||
mov -40(%rax),%r14
|
||||
@@ -1873,13 +1877,11 @@ rsaz_se_handler:
|
||||
.LSEH_info_rsaz_1024_sqr_avx2:
|
||||
.byte 9,0,0,0
|
||||
.rva rsaz_se_handler
|
||||
.rva .Lsqr_1024_body,.Lsqr_1024_epilogue,.Lsqr_1024_in_tail
|
||||
.long 0
|
||||
.rva .Lsqr_1024_body,.Lsqr_1024_epilogue
|
||||
.LSEH_info_rsaz_1024_mul_avx2:
|
||||
.byte 9,0,0,0
|
||||
.rva rsaz_se_handler
|
||||
.rva .Lmul_1024_body,.Lmul_1024_epilogue,.Lmul_1024_in_tail
|
||||
.long 0
|
||||
.rva .Lmul_1024_body,.Lmul_1024_epilogue
|
||||
.LSEH_info_rsaz_1024_gather5:
|
||||
.byte 0x01,0x36,0x17,0x0b
|
||||
.byte 0x36,0xf8,0x09,0x00 # vmovaps 0x90(rsp),xmm15
|
||||
@@ -1940,4 +1942,4 @@ rsaz_1024_gather5_avx2:
|
||||
___
|
||||
}}}
|
||||
|
||||
close STDOUT or die "error closing STDOUT";
|
||||
close STDOUT;
|
||||
Executable
+2338
File diff suppressed because it is too large
Load Diff
Executable → Regular
+23
-62
@@ -1,14 +1,7 @@
|
||||
#! /usr/bin/env perl
|
||||
# Copyright 2005-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
|
||||
# Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
|
||||
# project. The module is, however, dual licensed under OpenSSL and
|
||||
# CRYPTOGAMS licenses depending on where you obtain it. For further
|
||||
# details see http://www.openssl.org/~appro/cryptogams/.
|
||||
@@ -34,13 +27,10 @@
|
||||
# gives ~40% on rsa512 sign benchmark...
|
||||
|
||||
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
push(@INC,"${dir}","${dir}../../../perlasm");
|
||||
push(@INC,"${dir}","${dir}../../perlasm");
|
||||
require "x86asm.pl";
|
||||
|
||||
$output = pop;
|
||||
open STDOUT,">$output";
|
||||
|
||||
&asm_init($ARGV[0]);
|
||||
&asm_init($ARGV[0],$0);
|
||||
|
||||
$sse2=0;
|
||||
for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); }
|
||||
@@ -73,57 +63,33 @@ $frame=32; # size of above frame rounded up to 16n
|
||||
|
||||
&lea ("esi",&wparam(0)); # put aside pointer to argument block
|
||||
&lea ("edx",&wparam(1)); # load ap
|
||||
&mov ("ebp","esp"); # saved stack pointer!
|
||||
&add ("edi",2); # extra two words on top of tp
|
||||
&neg ("edi");
|
||||
&lea ("ebp",&DWP(-$frame,"esp","edi",4)); # future alloca($frame+4*(num+2))
|
||||
&lea ("esp",&DWP(-$frame,"esp","edi",4)); # alloca($frame+4*(num+2))
|
||||
&neg ("edi");
|
||||
|
||||
# minimize cache contention by arranging 2K window between stack
|
||||
# minimize cache contention by arraning 2K window between stack
|
||||
# pointer and ap argument [np is also position sensitive vector,
|
||||
# but it's assumed to be near ap, as it's allocated at ~same
|
||||
# time].
|
||||
&mov ("eax","ebp");
|
||||
&mov ("eax","esp");
|
||||
&sub ("eax","edx");
|
||||
&and ("eax",2047);
|
||||
&sub ("ebp","eax"); # this aligns sp and ap modulo 2048
|
||||
&sub ("esp","eax"); # this aligns sp and ap modulo 2048
|
||||
|
||||
&xor ("edx","ebp");
|
||||
&xor ("edx","esp");
|
||||
&and ("edx",2048);
|
||||
&xor ("edx",2048);
|
||||
&sub ("ebp","edx"); # this splits them apart modulo 4096
|
||||
&sub ("esp","edx"); # this splits them apart modulo 4096
|
||||
|
||||
&and ("ebp",-64); # align to cache line
|
||||
|
||||
# An OS-agnostic version of __chkstk.
|
||||
#
|
||||
# Some OSes (Windows) insist on stack being "wired" to
|
||||
# physical memory in strictly sequential manner, i.e. if stack
|
||||
# allocation spans two pages, then reference to farmost one can
|
||||
# be punishable by SEGV. But page walking can do good even on
|
||||
# other OSes, because it guarantees that villain thread hits
|
||||
# the guard page before it can make damage to innocent one...
|
||||
&mov ("eax","esp");
|
||||
&sub ("eax","ebp");
|
||||
&and ("eax",-4096);
|
||||
&mov ("edx","esp"); # saved stack pointer!
|
||||
&lea ("esp",&DWP(0,"ebp","eax"));
|
||||
&mov ("eax",&DWP(0,"esp"));
|
||||
&cmp ("esp","ebp");
|
||||
&ja (&label("page_walk"));
|
||||
&jmp (&label("page_walk_done"));
|
||||
|
||||
&set_label("page_walk",16);
|
||||
&lea ("esp",&DWP(-4096,"esp"));
|
||||
&mov ("eax",&DWP(0,"esp"));
|
||||
&cmp ("esp","ebp");
|
||||
&ja (&label("page_walk"));
|
||||
&set_label("page_walk_done");
|
||||
&and ("esp",-64); # align to cache line
|
||||
|
||||
################################# load argument block...
|
||||
&mov ("eax",&DWP(0*4,"esi"));# BN_ULONG *rp
|
||||
&mov ("ebx",&DWP(1*4,"esi"));# const BN_ULONG *ap
|
||||
&mov ("ecx",&DWP(2*4,"esi"));# const BN_ULONG *bp
|
||||
&mov ("ebp",&DWP(3*4,"esi"));# const BN_ULONG *np
|
||||
&mov ("edx",&DWP(3*4,"esi"));# const BN_ULONG *np
|
||||
&mov ("esi",&DWP(4*4,"esi"));# const BN_ULONG *n0
|
||||
#&mov ("edi",&DWP(5*4,"esi"));# int num
|
||||
|
||||
@@ -131,11 +97,11 @@ $frame=32; # size of above frame rounded up to 16n
|
||||
&mov ($_rp,"eax"); # ... save a copy of argument block
|
||||
&mov ($_ap,"ebx");
|
||||
&mov ($_bp,"ecx");
|
||||
&mov ($_np,"ebp");
|
||||
&mov ($_np,"edx");
|
||||
&mov ($_n0,"esi");
|
||||
&lea ($num,&DWP(-3,"edi")); # num=num-1 to assist modulo-scheduling
|
||||
#&mov ($_num,$num); # redundant as $num is not reused
|
||||
&mov ($_sp,"edx"); # saved stack pointer!
|
||||
&mov ($_sp,"ebp"); # saved stack pointer!
|
||||
|
||||
if($sse2) {
|
||||
$acc0="mm0"; # mmx register bank layout
|
||||
@@ -301,7 +267,7 @@ if (0) {
|
||||
&xor ("eax","eax"); # signal "not fast enough [yet]"
|
||||
&jmp (&label("just_leave"));
|
||||
# While the below code provides competitive performance for
|
||||
# all key lengths on modern Intel cores, it's still more
|
||||
# all key lengthes on modern Intel cores, it's still more
|
||||
# than 10% slower for 4096-bit key elsewhere:-( "Competitive"
|
||||
# means compared to the original integer-only assembler.
|
||||
# 512-bit RSA sign is better by ~40%, but that's about all
|
||||
@@ -604,18 +570,15 @@ $sbit=$num;
|
||||
&jge (&label("sub"));
|
||||
|
||||
&sbb ("eax",0); # handle upmost overflow bit
|
||||
&mov ("edx",-1);
|
||||
&xor ("edx","eax");
|
||||
&jmp (&label("copy"));
|
||||
|
||||
&set_label("copy",16); # conditional copy
|
||||
&mov ($tp,&DWP($frame,"esp",$num,4));
|
||||
&set_label("copy",16); # copy or in-place refresh
|
||||
&mov ("edx",&DWP(0,$tp,$num,4));
|
||||
&mov ($np,&DWP(0,$rp,$num,4));
|
||||
&mov (&DWP($frame,"esp",$num,4),$j); # zap temporary vector
|
||||
&and ($tp,"eax");
|
||||
&and ($np,"edx");
|
||||
&or ($np,$tp);
|
||||
&mov (&DWP(0,$rp,$num,4),$np);
|
||||
&xor ("edx",$np); # conditional select
|
||||
&and ("edx","eax");
|
||||
&xor ("edx",$np);
|
||||
&mov (&DWP(0,$tp,$num,4),$j) # zap temporary vector
|
||||
&mov (&DWP(0,$rp,$num,4),"edx"); # rp[i]=tp[i]
|
||||
&dec ($num);
|
||||
&jge (&label("copy"));
|
||||
|
||||
@@ -627,5 +590,3 @@ $sbit=$num;
|
||||
&asciz("Montgomery Multiplication for x86, CRYPTOGAMS by <appro\@openssl.org>");
|
||||
|
||||
&asm_finish();
|
||||
|
||||
close STDOUT or die "error closing STDOUT";
|
||||
@@ -0,0 +1,531 @@
|
||||
/* x86_64 BIGNUM accelerator version 0.1, December 2002.
|
||||
*
|
||||
* Implemented by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
|
||||
* project.
|
||||
*
|
||||
* Rights for redistribution and usage in source and binary forms are
|
||||
* granted according to the OpenSSL license. Warranty of any kind is
|
||||
* disclaimed.
|
||||
*
|
||||
* Q. Version 0.1? It doesn't sound like Andy, he used to assign real
|
||||
* versions, like 1.0...
|
||||
* A. Well, that's because this code is basically a quick-n-dirty
|
||||
* proof-of-concept hack. As you can see it's implemented with
|
||||
* inline assembler, which means that you're bound to GCC and that
|
||||
* there might be enough room for further improvement.
|
||||
*
|
||||
* Q. Why inline assembler?
|
||||
* A. x86_64 features own ABI which I'm not familiar with. This is
|
||||
* why I decided to let the compiler take care of subroutine
|
||||
* prologue/epilogue as well as register allocation. For reference.
|
||||
* Win64 implements different ABI for AMD64, different from Linux.
|
||||
*
|
||||
* Q. How much faster does it get?
|
||||
* A. 'apps/openssl speed rsa dsa' output with no-asm:
|
||||
*
|
||||
* sign verify sign/s verify/s
|
||||
* rsa 512 bits 0.0006s 0.0001s 1683.8 18456.2
|
||||
* rsa 1024 bits 0.0028s 0.0002s 356.0 6407.0
|
||||
* rsa 2048 bits 0.0172s 0.0005s 58.0 1957.8
|
||||
* rsa 4096 bits 0.1155s 0.0018s 8.7 555.6
|
||||
* sign verify sign/s verify/s
|
||||
* dsa 512 bits 0.0005s 0.0006s 2100.8 1768.3
|
||||
* dsa 1024 bits 0.0014s 0.0018s 692.3 559.2
|
||||
* dsa 2048 bits 0.0049s 0.0061s 204.7 165.0
|
||||
*
|
||||
* 'apps/openssl speed rsa dsa' output with this module:
|
||||
*
|
||||
* sign verify sign/s verify/s
|
||||
* rsa 512 bits 0.0004s 0.0000s 2767.1 33297.9
|
||||
* rsa 1024 bits 0.0012s 0.0001s 867.4 14674.7
|
||||
* rsa 2048 bits 0.0061s 0.0002s 164.0 5270.0
|
||||
* rsa 4096 bits 0.0384s 0.0006s 26.1 1650.8
|
||||
* sign verify sign/s verify/s
|
||||
* dsa 512 bits 0.0002s 0.0003s 4442.2 3786.3
|
||||
* dsa 1024 bits 0.0005s 0.0007s 1835.1 1497.4
|
||||
* dsa 2048 bits 0.0016s 0.0020s 620.4 504.6
|
||||
*
|
||||
* For the reference. IA-32 assembler implementation performs
|
||||
* very much like 64-bit code compiled with no-asm on the same
|
||||
* machine.
|
||||
*/
|
||||
|
||||
#include <openssl/bn.h>
|
||||
|
||||
/* TODO(davidben): Get this file working on Windows x64. */
|
||||
#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && defined(__GNUC__)
|
||||
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
#undef mul
|
||||
#undef mul_add
|
||||
|
||||
#define asm __asm__
|
||||
|
||||
/*
|
||||
* "m"(a), "+m"(r) is the way to favor DirectPath µ-code;
|
||||
* "g"(0) let the compiler to decide where does it
|
||||
* want to keep the value of zero;
|
||||
*/
|
||||
#define mul_add(r, a, word, carry) \
|
||||
do { \
|
||||
register BN_ULONG high, low; \
|
||||
asm("mulq %3" : "=a"(low), "=d"(high) : "a"(word), "m"(a) : "cc"); \
|
||||
asm("addq %2,%0; adcq %3,%1" \
|
||||
: "+r"(carry), "+d"(high) \
|
||||
: "a"(low), "g"(0) \
|
||||
: "cc"); \
|
||||
asm("addq %2,%0; adcq %3,%1" \
|
||||
: "+m"(r), "+d"(high) \
|
||||
: "r"(carry), "g"(0) \
|
||||
: "cc"); \
|
||||
carry = high; \
|
||||
} while (0)
|
||||
|
||||
#define mul(r, a, word, carry) \
|
||||
do { \
|
||||
register BN_ULONG high, low; \
|
||||
asm("mulq %3" : "=a"(low), "=d"(high) : "a"(word), "g"(a) : "cc"); \
|
||||
asm("addq %2,%0; adcq %3,%1" \
|
||||
: "+r"(carry), "+d"(high) \
|
||||
: "a"(low), "g"(0) \
|
||||
: "cc"); \
|
||||
(r) = carry, carry = high; \
|
||||
} while (0)
|
||||
#undef sqr
|
||||
#define sqr(r0, r1, a) asm("mulq %2" : "=a"(r0), "=d"(r1) : "a"(a) : "cc");
|
||||
|
||||
BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num,
|
||||
BN_ULONG w) {
|
||||
BN_ULONG c1 = 0;
|
||||
|
||||
if (num <= 0) {
|
||||
return (c1);
|
||||
}
|
||||
|
||||
while (num & ~3) {
|
||||
mul_add(rp[0], ap[0], w, c1);
|
||||
mul_add(rp[1], ap[1], w, c1);
|
||||
mul_add(rp[2], ap[2], w, c1);
|
||||
mul_add(rp[3], ap[3], w, c1);
|
||||
ap += 4;
|
||||
rp += 4;
|
||||
num -= 4;
|
||||
}
|
||||
if (num) {
|
||||
mul_add(rp[0], ap[0], w, c1);
|
||||
if (--num == 0) {
|
||||
return c1;
|
||||
}
|
||||
mul_add(rp[1], ap[1], w, c1);
|
||||
if (--num == 0) {
|
||||
return c1;
|
||||
}
|
||||
mul_add(rp[2], ap[2], w, c1);
|
||||
return c1;
|
||||
}
|
||||
|
||||
return c1;
|
||||
}
|
||||
|
||||
BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w) {
|
||||
BN_ULONG c1 = 0;
|
||||
|
||||
if (num <= 0) {
|
||||
return c1;
|
||||
}
|
||||
|
||||
while (num & ~3) {
|
||||
mul(rp[0], ap[0], w, c1);
|
||||
mul(rp[1], ap[1], w, c1);
|
||||
mul(rp[2], ap[2], w, c1);
|
||||
mul(rp[3], ap[3], w, c1);
|
||||
ap += 4;
|
||||
rp += 4;
|
||||
num -= 4;
|
||||
}
|
||||
if (num) {
|
||||
mul(rp[0], ap[0], w, c1);
|
||||
if (--num == 0) {
|
||||
return c1;
|
||||
}
|
||||
mul(rp[1], ap[1], w, c1);
|
||||
if (--num == 0) {
|
||||
return c1;
|
||||
}
|
||||
mul(rp[2], ap[2], w, c1);
|
||||
}
|
||||
return c1;
|
||||
}
|
||||
|
||||
void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, int n) {
|
||||
if (n <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (n & ~3) {
|
||||
sqr(r[0], r[1], a[0]);
|
||||
sqr(r[2], r[3], a[1]);
|
||||
sqr(r[4], r[5], a[2]);
|
||||
sqr(r[6], r[7], a[3]);
|
||||
a += 4;
|
||||
r += 8;
|
||||
n -= 4;
|
||||
}
|
||||
if (n) {
|
||||
sqr(r[0], r[1], a[0]);
|
||||
if (--n == 0) {
|
||||
return;
|
||||
}
|
||||
sqr(r[2], r[3], a[1]);
|
||||
if (--n == 0) {
|
||||
return;
|
||||
}
|
||||
sqr(r[4], r[5], a[2]);
|
||||
}
|
||||
}
|
||||
|
||||
BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
|
||||
int n) {
|
||||
BN_ULONG ret;
|
||||
size_t i = 0;
|
||||
|
||||
if (n <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
asm volatile (
|
||||
" subq %0,%0 \n" /* clear carry */
|
||||
" jmp 1f \n"
|
||||
".p2align 4 \n"
|
||||
"1: movq (%4,%2,8),%0 \n"
|
||||
" adcq (%5,%2,8),%0 \n"
|
||||
" movq %0,(%3,%2,8) \n"
|
||||
" lea 1(%2),%2 \n"
|
||||
" loop 1b \n"
|
||||
" sbbq %0,%0 \n"
|
||||
: "=&r"(ret), "+c"(n), "+r"(i)
|
||||
: "r"(rp), "r"(ap), "r"(bp)
|
||||
: "cc", "memory");
|
||||
|
||||
return ret & 1;
|
||||
}
|
||||
|
||||
BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,
|
||||
int n) {
|
||||
BN_ULONG ret;
|
||||
size_t i = 0;
|
||||
|
||||
if (n <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
asm volatile (
|
||||
" subq %0,%0 \n" /* clear borrow */
|
||||
" jmp 1f \n"
|
||||
".p2align 4 \n"
|
||||
"1: movq (%4,%2,8),%0 \n"
|
||||
" sbbq (%5,%2,8),%0 \n"
|
||||
" movq %0,(%3,%2,8) \n"
|
||||
" lea 1(%2),%2 \n"
|
||||
" loop 1b \n"
|
||||
" sbbq %0,%0 \n"
|
||||
: "=&r"(ret), "+c"(n), "+r"(i)
|
||||
: "r"(rp), "r"(ap), "r"(bp)
|
||||
: "cc", "memory");
|
||||
|
||||
return ret & 1;
|
||||
}
|
||||
|
||||
/* mul_add_c(a,b,c0,c1,c2) -- c+=a*b for three word number c=(c2,c1,c0) */
|
||||
/* mul_add_c2(a,b,c0,c1,c2) -- c+=2*a*b for three word number c=(c2,c1,c0) */
|
||||
/* sqr_add_c(a,i,c0,c1,c2) -- c+=a[i]^2 for three word number c=(c2,c1,c0) */
|
||||
/* sqr_add_c2(a,i,c0,c1,c2) -- c+=2*a[i]*a[j] for three word number c=(c2,c1,c0)
|
||||
*/
|
||||
|
||||
/* Keep in mind that carrying into high part of multiplication result can not
|
||||
* overflow, because it cannot be all-ones. */
|
||||
#define mul_add_c(a, b, c0, c1, c2) \
|
||||
do { \
|
||||
BN_ULONG t1, t2; \
|
||||
asm("mulq %3" : "=a"(t1), "=d"(t2) : "a"(a), "m"(b) : "cc"); \
|
||||
asm("addq %3,%0; adcq %4,%1; adcq %5,%2" \
|
||||
: "+r"(c0), "+r"(c1), "+r"(c2) \
|
||||
: "r"(t1), "r"(t2), "g"(0) \
|
||||
: "cc"); \
|
||||
} while (0)
|
||||
|
||||
#define sqr_add_c(a, i, c0, c1, c2) \
|
||||
do { \
|
||||
BN_ULONG t1, t2; \
|
||||
asm("mulq %2" : "=a"(t1), "=d"(t2) : "a"(a[i]) : "cc"); \
|
||||
asm("addq %3,%0; adcq %4,%1; adcq %5,%2" \
|
||||
: "+r"(c0), "+r"(c1), "+r"(c2) \
|
||||
: "r"(t1), "r"(t2), "g"(0) \
|
||||
: "cc"); \
|
||||
} while (0)
|
||||
|
||||
#define mul_add_c2(a, b, c0, c1, c2) \
|
||||
do { \
|
||||
BN_ULONG t1, t2; \
|
||||
asm("mulq %3" : "=a"(t1), "=d"(t2) : "a"(a), "m"(b) : "cc"); \
|
||||
asm("addq %3,%0; adcq %4,%1; adcq %5,%2" \
|
||||
: "+r"(c0), "+r"(c1), "+r"(c2) \
|
||||
: "r"(t1), "r"(t2), "g"(0) \
|
||||
: "cc"); \
|
||||
asm("addq %3,%0; adcq %4,%1; adcq %5,%2" \
|
||||
: "+r"(c0), "+r"(c1), "+r"(c2) \
|
||||
: "r"(t1), "r"(t2), "g"(0) \
|
||||
: "cc"); \
|
||||
} while (0)
|
||||
|
||||
#define sqr_add_c2(a, i, j, c0, c1, c2) mul_add_c2((a)[i], (a)[j], c0, c1, c2)
|
||||
|
||||
void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) {
|
||||
BN_ULONG c1, c2, c3;
|
||||
|
||||
c1 = 0;
|
||||
c2 = 0;
|
||||
c3 = 0;
|
||||
mul_add_c(a[0], b[0], c1, c2, c3);
|
||||
r[0] = c1;
|
||||
c1 = 0;
|
||||
mul_add_c(a[0], b[1], c2, c3, c1);
|
||||
mul_add_c(a[1], b[0], c2, c3, c1);
|
||||
r[1] = c2;
|
||||
c2 = 0;
|
||||
mul_add_c(a[2], b[0], c3, c1, c2);
|
||||
mul_add_c(a[1], b[1], c3, c1, c2);
|
||||
mul_add_c(a[0], b[2], c3, c1, c2);
|
||||
r[2] = c3;
|
||||
c3 = 0;
|
||||
mul_add_c(a[0], b[3], c1, c2, c3);
|
||||
mul_add_c(a[1], b[2], c1, c2, c3);
|
||||
mul_add_c(a[2], b[1], c1, c2, c3);
|
||||
mul_add_c(a[3], b[0], c1, c2, c3);
|
||||
r[3] = c1;
|
||||
c1 = 0;
|
||||
mul_add_c(a[4], b[0], c2, c3, c1);
|
||||
mul_add_c(a[3], b[1], c2, c3, c1);
|
||||
mul_add_c(a[2], b[2], c2, c3, c1);
|
||||
mul_add_c(a[1], b[3], c2, c3, c1);
|
||||
mul_add_c(a[0], b[4], c2, c3, c1);
|
||||
r[4] = c2;
|
||||
c2 = 0;
|
||||
mul_add_c(a[0], b[5], c3, c1, c2);
|
||||
mul_add_c(a[1], b[4], c3, c1, c2);
|
||||
mul_add_c(a[2], b[3], c3, c1, c2);
|
||||
mul_add_c(a[3], b[2], c3, c1, c2);
|
||||
mul_add_c(a[4], b[1], c3, c1, c2);
|
||||
mul_add_c(a[5], b[0], c3, c1, c2);
|
||||
r[5] = c3;
|
||||
c3 = 0;
|
||||
mul_add_c(a[6], b[0], c1, c2, c3);
|
||||
mul_add_c(a[5], b[1], c1, c2, c3);
|
||||
mul_add_c(a[4], b[2], c1, c2, c3);
|
||||
mul_add_c(a[3], b[3], c1, c2, c3);
|
||||
mul_add_c(a[2], b[4], c1, c2, c3);
|
||||
mul_add_c(a[1], b[5], c1, c2, c3);
|
||||
mul_add_c(a[0], b[6], c1, c2, c3);
|
||||
r[6] = c1;
|
||||
c1 = 0;
|
||||
mul_add_c(a[0], b[7], c2, c3, c1);
|
||||
mul_add_c(a[1], b[6], c2, c3, c1);
|
||||
mul_add_c(a[2], b[5], c2, c3, c1);
|
||||
mul_add_c(a[3], b[4], c2, c3, c1);
|
||||
mul_add_c(a[4], b[3], c2, c3, c1);
|
||||
mul_add_c(a[5], b[2], c2, c3, c1);
|
||||
mul_add_c(a[6], b[1], c2, c3, c1);
|
||||
mul_add_c(a[7], b[0], c2, c3, c1);
|
||||
r[7] = c2;
|
||||
c2 = 0;
|
||||
mul_add_c(a[7], b[1], c3, c1, c2);
|
||||
mul_add_c(a[6], b[2], c3, c1, c2);
|
||||
mul_add_c(a[5], b[3], c3, c1, c2);
|
||||
mul_add_c(a[4], b[4], c3, c1, c2);
|
||||
mul_add_c(a[3], b[5], c3, c1, c2);
|
||||
mul_add_c(a[2], b[6], c3, c1, c2);
|
||||
mul_add_c(a[1], b[7], c3, c1, c2);
|
||||
r[8] = c3;
|
||||
c3 = 0;
|
||||
mul_add_c(a[2], b[7], c1, c2, c3);
|
||||
mul_add_c(a[3], b[6], c1, c2, c3);
|
||||
mul_add_c(a[4], b[5], c1, c2, c3);
|
||||
mul_add_c(a[5], b[4], c1, c2, c3);
|
||||
mul_add_c(a[6], b[3], c1, c2, c3);
|
||||
mul_add_c(a[7], b[2], c1, c2, c3);
|
||||
r[9] = c1;
|
||||
c1 = 0;
|
||||
mul_add_c(a[7], b[3], c2, c3, c1);
|
||||
mul_add_c(a[6], b[4], c2, c3, c1);
|
||||
mul_add_c(a[5], b[5], c2, c3, c1);
|
||||
mul_add_c(a[4], b[6], c2, c3, c1);
|
||||
mul_add_c(a[3], b[7], c2, c3, c1);
|
||||
r[10] = c2;
|
||||
c2 = 0;
|
||||
mul_add_c(a[4], b[7], c3, c1, c2);
|
||||
mul_add_c(a[5], b[6], c3, c1, c2);
|
||||
mul_add_c(a[6], b[5], c3, c1, c2);
|
||||
mul_add_c(a[7], b[4], c3, c1, c2);
|
||||
r[11] = c3;
|
||||
c3 = 0;
|
||||
mul_add_c(a[7], b[5], c1, c2, c3);
|
||||
mul_add_c(a[6], b[6], c1, c2, c3);
|
||||
mul_add_c(a[5], b[7], c1, c2, c3);
|
||||
r[12] = c1;
|
||||
c1 = 0;
|
||||
mul_add_c(a[6], b[7], c2, c3, c1);
|
||||
mul_add_c(a[7], b[6], c2, c3, c1);
|
||||
r[13] = c2;
|
||||
c2 = 0;
|
||||
mul_add_c(a[7], b[7], c3, c1, c2);
|
||||
r[14] = c3;
|
||||
r[15] = c1;
|
||||
}
|
||||
|
||||
void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) {
|
||||
BN_ULONG c1, c2, c3;
|
||||
|
||||
c1 = 0;
|
||||
c2 = 0;
|
||||
c3 = 0;
|
||||
mul_add_c(a[0], b[0], c1, c2, c3);
|
||||
r[0] = c1;
|
||||
c1 = 0;
|
||||
mul_add_c(a[0], b[1], c2, c3, c1);
|
||||
mul_add_c(a[1], b[0], c2, c3, c1);
|
||||
r[1] = c2;
|
||||
c2 = 0;
|
||||
mul_add_c(a[2], b[0], c3, c1, c2);
|
||||
mul_add_c(a[1], b[1], c3, c1, c2);
|
||||
mul_add_c(a[0], b[2], c3, c1, c2);
|
||||
r[2] = c3;
|
||||
c3 = 0;
|
||||
mul_add_c(a[0], b[3], c1, c2, c3);
|
||||
mul_add_c(a[1], b[2], c1, c2, c3);
|
||||
mul_add_c(a[2], b[1], c1, c2, c3);
|
||||
mul_add_c(a[3], b[0], c1, c2, c3);
|
||||
r[3] = c1;
|
||||
c1 = 0;
|
||||
mul_add_c(a[3], b[1], c2, c3, c1);
|
||||
mul_add_c(a[2], b[2], c2, c3, c1);
|
||||
mul_add_c(a[1], b[3], c2, c3, c1);
|
||||
r[4] = c2;
|
||||
c2 = 0;
|
||||
mul_add_c(a[2], b[3], c3, c1, c2);
|
||||
mul_add_c(a[3], b[2], c3, c1, c2);
|
||||
r[5] = c3;
|
||||
c3 = 0;
|
||||
mul_add_c(a[3], b[3], c1, c2, c3);
|
||||
r[6] = c1;
|
||||
r[7] = c2;
|
||||
}
|
||||
|
||||
void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a) {
|
||||
BN_ULONG c1, c2, c3;
|
||||
|
||||
c1 = 0;
|
||||
c2 = 0;
|
||||
c3 = 0;
|
||||
sqr_add_c(a, 0, c1, c2, c3);
|
||||
r[0] = c1;
|
||||
c1 = 0;
|
||||
sqr_add_c2(a, 1, 0, c2, c3, c1);
|
||||
r[1] = c2;
|
||||
c2 = 0;
|
||||
sqr_add_c(a, 1, c3, c1, c2);
|
||||
sqr_add_c2(a, 2, 0, c3, c1, c2);
|
||||
r[2] = c3;
|
||||
c3 = 0;
|
||||
sqr_add_c2(a, 3, 0, c1, c2, c3);
|
||||
sqr_add_c2(a, 2, 1, c1, c2, c3);
|
||||
r[3] = c1;
|
||||
c1 = 0;
|
||||
sqr_add_c(a, 2, c2, c3, c1);
|
||||
sqr_add_c2(a, 3, 1, c2, c3, c1);
|
||||
sqr_add_c2(a, 4, 0, c2, c3, c1);
|
||||
r[4] = c2;
|
||||
c2 = 0;
|
||||
sqr_add_c2(a, 5, 0, c3, c1, c2);
|
||||
sqr_add_c2(a, 4, 1, c3, c1, c2);
|
||||
sqr_add_c2(a, 3, 2, c3, c1, c2);
|
||||
r[5] = c3;
|
||||
c3 = 0;
|
||||
sqr_add_c(a, 3, c1, c2, c3);
|
||||
sqr_add_c2(a, 4, 2, c1, c2, c3);
|
||||
sqr_add_c2(a, 5, 1, c1, c2, c3);
|
||||
sqr_add_c2(a, 6, 0, c1, c2, c3);
|
||||
r[6] = c1;
|
||||
c1 = 0;
|
||||
sqr_add_c2(a, 7, 0, c2, c3, c1);
|
||||
sqr_add_c2(a, 6, 1, c2, c3, c1);
|
||||
sqr_add_c2(a, 5, 2, c2, c3, c1);
|
||||
sqr_add_c2(a, 4, 3, c2, c3, c1);
|
||||
r[7] = c2;
|
||||
c2 = 0;
|
||||
sqr_add_c(a, 4, c3, c1, c2);
|
||||
sqr_add_c2(a, 5, 3, c3, c1, c2);
|
||||
sqr_add_c2(a, 6, 2, c3, c1, c2);
|
||||
sqr_add_c2(a, 7, 1, c3, c1, c2);
|
||||
r[8] = c3;
|
||||
c3 = 0;
|
||||
sqr_add_c2(a, 7, 2, c1, c2, c3);
|
||||
sqr_add_c2(a, 6, 3, c1, c2, c3);
|
||||
sqr_add_c2(a, 5, 4, c1, c2, c3);
|
||||
r[9] = c1;
|
||||
c1 = 0;
|
||||
sqr_add_c(a, 5, c2, c3, c1);
|
||||
sqr_add_c2(a, 6, 4, c2, c3, c1);
|
||||
sqr_add_c2(a, 7, 3, c2, c3, c1);
|
||||
r[10] = c2;
|
||||
c2 = 0;
|
||||
sqr_add_c2(a, 7, 4, c3, c1, c2);
|
||||
sqr_add_c2(a, 6, 5, c3, c1, c2);
|
||||
r[11] = c3;
|
||||
c3 = 0;
|
||||
sqr_add_c(a, 6, c1, c2, c3);
|
||||
sqr_add_c2(a, 7, 5, c1, c2, c3);
|
||||
r[12] = c1;
|
||||
c1 = 0;
|
||||
sqr_add_c2(a, 7, 6, c2, c3, c1);
|
||||
r[13] = c2;
|
||||
c2 = 0;
|
||||
sqr_add_c(a, 7, c3, c1, c2);
|
||||
r[14] = c3;
|
||||
r[15] = c1;
|
||||
}
|
||||
|
||||
void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a) {
|
||||
BN_ULONG c1, c2, c3;
|
||||
|
||||
c1 = 0;
|
||||
c2 = 0;
|
||||
c3 = 0;
|
||||
sqr_add_c(a, 0, c1, c2, c3);
|
||||
r[0] = c1;
|
||||
c1 = 0;
|
||||
sqr_add_c2(a, 1, 0, c2, c3, c1);
|
||||
r[1] = c2;
|
||||
c2 = 0;
|
||||
sqr_add_c(a, 1, c3, c1, c2);
|
||||
sqr_add_c2(a, 2, 0, c3, c1, c2);
|
||||
r[2] = c3;
|
||||
c3 = 0;
|
||||
sqr_add_c2(a, 3, 0, c1, c2, c3);
|
||||
sqr_add_c2(a, 2, 1, c1, c2, c3);
|
||||
r[3] = c1;
|
||||
c1 = 0;
|
||||
sqr_add_c(a, 2, c2, c3, c1);
|
||||
sqr_add_c2(a, 3, 1, c2, c3, c1);
|
||||
r[4] = c2;
|
||||
c2 = 0;
|
||||
sqr_add_c2(a, 3, 2, c3, c1, c2);
|
||||
r[5] = c3;
|
||||
c3 = 0;
|
||||
sqr_add_c(a, 3, c1, c2, c3);
|
||||
r[6] = c1;
|
||||
r[7] = c2;
|
||||
}
|
||||
|
||||
#endif /* !NO_ASM && X86_64 && __GNUC__ */
|
||||
@@ -1,11 +1,4 @@
|
||||
#! /usr/bin/env perl
|
||||
# Copyright 2005-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
|
||||
@@ -54,16 +47,18 @@ $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
|
||||
|
||||
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
|
||||
( $xlate="${dir}../../../perlasm/x86_64-xlate.pl" and -f $xlate) or
|
||||
( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
|
||||
die "can't locate x86_64-xlate.pl";
|
||||
|
||||
open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
|
||||
open OUT,"| \"$^X\" $xlate $flavour $output";
|
||||
*STDOUT=*OUT;
|
||||
|
||||
# In upstream, this is controlled by shelling out to the compiler to check
|
||||
# versions, but BoringSSL is intended to be used with pre-generated perlasm
|
||||
# output, so this isn't useful anyway.
|
||||
$addx = 1;
|
||||
#
|
||||
# TODO(davidben): Enable this option after testing. $addx goes up to 1.
|
||||
$addx = 0;
|
||||
|
||||
# int bn_mul_mont(
|
||||
$rp="%rdi"; # BN_ULONG *rp,
|
||||
@@ -71,9 +66,7 @@ $ap="%rsi"; # const BN_ULONG *ap,
|
||||
$bp="%rdx"; # const BN_ULONG *bp,
|
||||
$np="%rcx"; # const BN_ULONG *np,
|
||||
$n0="%r8"; # const BN_ULONG *n0,
|
||||
# TODO(davidben): The code below treats $num as an int, but C passes in a
|
||||
# size_t.
|
||||
$num="%r9"; # size_t num);
|
||||
$num="%r9"; # int num);
|
||||
$lo0="%r10";
|
||||
$hi0="%r11";
|
||||
$hi1="%r13";
|
||||
@@ -91,18 +84,13 @@ $code=<<___;
|
||||
.type bn_mul_mont,\@function,6
|
||||
.align 16
|
||||
bn_mul_mont:
|
||||
.cfi_startproc
|
||||
mov ${num}d,${num}d
|
||||
mov %rsp,%rax
|
||||
.cfi_def_cfa_register %rax
|
||||
test \$3,${num}d
|
||||
jnz .Lmul_enter
|
||||
cmp \$8,${num}d
|
||||
jb .Lmul_enter
|
||||
___
|
||||
$code.=<<___ if ($addx);
|
||||
leaq OPENSSL_ia32cap_P(%rip),%r11
|
||||
mov 8(%r11),%r11d
|
||||
mov OPENSSL_ia32cap_P+8(%rip),%r11d
|
||||
___
|
||||
$code.=<<___;
|
||||
cmp $ap,$bp
|
||||
@@ -114,50 +102,20 @@ $code.=<<___;
|
||||
.align 16
|
||||
.Lmul_enter:
|
||||
push %rbx
|
||||
.cfi_push %rbx
|
||||
push %rbp
|
||||
.cfi_push %rbp
|
||||
push %r12
|
||||
.cfi_push %r12
|
||||
push %r13
|
||||
.cfi_push %r13
|
||||
push %r14
|
||||
.cfi_push %r14
|
||||
push %r15
|
||||
.cfi_push %r15
|
||||
|
||||
neg $num
|
||||
mov ${num}d,${num}d
|
||||
lea 2($num),%r10
|
||||
mov %rsp,%r11
|
||||
lea -16(%rsp,$num,8),%r10 # future alloca(8*(num+2))
|
||||
neg $num # restore $num
|
||||
and \$-1024,%r10 # minimize TLB usage
|
||||
neg %r10
|
||||
lea (%rsp,%r10,8),%rsp # tp=alloca(8*(num+2))
|
||||
and \$-1024,%rsp # minimize TLB usage
|
||||
|
||||
# An OS-agnostic version of __chkstk.
|
||||
#
|
||||
# Some OSes (Windows) insist on stack being "wired" to
|
||||
# physical memory in strictly sequential manner, i.e. if stack
|
||||
# allocation spans two pages, then reference to farmost one can
|
||||
# be punishable by SEGV. But page walking can do good even on
|
||||
# other OSes, because it guarantees that villain thread hits
|
||||
# the guard page before it can make damage to innocent one...
|
||||
sub %r10,%r11
|
||||
and \$-4096,%r11
|
||||
lea (%r10,%r11),%rsp
|
||||
mov (%rsp),%r11
|
||||
cmp %r10,%rsp
|
||||
ja .Lmul_page_walk
|
||||
jmp .Lmul_page_walk_done
|
||||
|
||||
.align 16
|
||||
.Lmul_page_walk:
|
||||
lea -4096(%rsp),%rsp
|
||||
mov (%rsp),%r11
|
||||
cmp %r10,%rsp
|
||||
ja .Lmul_page_walk
|
||||
.Lmul_page_walk_done:
|
||||
|
||||
mov %rax,8(%rsp,$num,8) # tp[num+1]=%rsp
|
||||
.cfi_cfa_expression %rsp+8,$num,8,mul,plus,deref,+8
|
||||
mov %r11,8(%rsp,$num,8) # tp[num+1]=%rsp
|
||||
.Lmul_body:
|
||||
mov $bp,%r12 # reassign $bp
|
||||
___
|
||||
@@ -299,54 +257,44 @@ $code.=<<___;
|
||||
|
||||
xor $i,$i # i=0 and clear CF!
|
||||
mov (%rsp),%rax # tp[0]
|
||||
lea (%rsp),$ap # borrow ap for tp
|
||||
mov $num,$j # j=num
|
||||
|
||||
jmp .Lsub
|
||||
.align 16
|
||||
.Lsub: sbb ($np,$i,8),%rax
|
||||
mov %rax,($rp,$i,8) # rp[i]=tp[i]-np[i]
|
||||
mov 8(%rsp,$i,8),%rax # tp[i+1]
|
||||
mov 8($ap,$i,8),%rax # tp[i+1]
|
||||
lea 1($i),$i # i++
|
||||
dec $j # doesn't affect CF!
|
||||
jnz .Lsub
|
||||
|
||||
sbb \$0,%rax # handle upmost overflow bit
|
||||
mov \$-1,%rbx
|
||||
xor %rax,%rbx # not %rax
|
||||
xor $i,$i
|
||||
mov $num,$j # j=num
|
||||
|
||||
.Lcopy: # conditional copy
|
||||
mov ($rp,$i,8),%rcx
|
||||
mov (%rsp,$i,8),%rdx
|
||||
and %rbx,%rcx
|
||||
and %rax,%rdx
|
||||
mov $num,(%rsp,$i,8) # zap temporary vector
|
||||
or %rcx,%rdx
|
||||
mov %rdx,($rp,$i,8) # rp[i]=tp[i]
|
||||
.align 16
|
||||
.Lcopy: # copy or in-place refresh
|
||||
mov (%rsp,$i,8),$ap
|
||||
mov ($rp,$i,8),$np
|
||||
xor $np,$ap # conditional select:
|
||||
and %rax,$ap # ((ap ^ np) & %rax) ^ np
|
||||
xor $np,$ap # ap = borrow?tp:rp
|
||||
mov $i,(%rsp,$i,8) # zap temporary vector
|
||||
mov $ap,($rp,$i,8) # rp[i]=tp[i]
|
||||
lea 1($i),$i
|
||||
sub \$1,$j
|
||||
jnz .Lcopy
|
||||
|
||||
mov 8(%rsp,$num,8),%rsi # restore %rsp
|
||||
.cfi_def_cfa %rsi,8
|
||||
mov \$1,%rax
|
||||
mov -48(%rsi),%r15
|
||||
.cfi_restore %r15
|
||||
mov -40(%rsi),%r14
|
||||
.cfi_restore %r14
|
||||
mov -32(%rsi),%r13
|
||||
.cfi_restore %r13
|
||||
mov -24(%rsi),%r12
|
||||
.cfi_restore %r12
|
||||
mov -16(%rsi),%rbp
|
||||
.cfi_restore %rbp
|
||||
mov -8(%rsi),%rbx
|
||||
.cfi_restore %rbx
|
||||
lea (%rsi),%rsp
|
||||
.cfi_def_cfa_register %rsp
|
||||
mov (%rsi),%r15
|
||||
mov 8(%rsi),%r14
|
||||
mov 16(%rsi),%r13
|
||||
mov 24(%rsi),%r12
|
||||
mov 32(%rsi),%rbp
|
||||
mov 40(%rsi),%rbx
|
||||
lea 48(%rsi),%rsp
|
||||
.Lmul_epilogue:
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size bn_mul_mont,.-bn_mul_mont
|
||||
___
|
||||
{{{
|
||||
@@ -356,10 +304,6 @@ $code.=<<___;
|
||||
.type bn_mul4x_mont,\@function,6
|
||||
.align 16
|
||||
bn_mul4x_mont:
|
||||
.cfi_startproc
|
||||
mov ${num}d,${num}d
|
||||
mov %rsp,%rax
|
||||
.cfi_def_cfa_register %rax
|
||||
.Lmul4x_enter:
|
||||
___
|
||||
$code.=<<___ if ($addx);
|
||||
@@ -369,41 +313,20 @@ $code.=<<___ if ($addx);
|
||||
___
|
||||
$code.=<<___;
|
||||
push %rbx
|
||||
.cfi_push %rbx
|
||||
push %rbp
|
||||
.cfi_push %rbp
|
||||
push %r12
|
||||
.cfi_push %r12
|
||||
push %r13
|
||||
.cfi_push %r13
|
||||
push %r14
|
||||
.cfi_push %r14
|
||||
push %r15
|
||||
.cfi_push %r15
|
||||
|
||||
neg $num
|
||||
mov ${num}d,${num}d
|
||||
lea 4($num),%r10
|
||||
mov %rsp,%r11
|
||||
lea -32(%rsp,$num,8),%r10 # future alloca(8*(num+4))
|
||||
neg $num # restore
|
||||
and \$-1024,%r10 # minimize TLB usage
|
||||
neg %r10
|
||||
lea (%rsp,%r10,8),%rsp # tp=alloca(8*(num+4))
|
||||
and \$-1024,%rsp # minimize TLB usage
|
||||
|
||||
sub %r10,%r11
|
||||
and \$-4096,%r11
|
||||
lea (%r10,%r11),%rsp
|
||||
mov (%rsp),%r11
|
||||
cmp %r10,%rsp
|
||||
ja .Lmul4x_page_walk
|
||||
jmp .Lmul4x_page_walk_done
|
||||
|
||||
.Lmul4x_page_walk:
|
||||
lea -4096(%rsp),%rsp
|
||||
mov (%rsp),%r11
|
||||
cmp %r10,%rsp
|
||||
ja .Lmul4x_page_walk
|
||||
.Lmul4x_page_walk_done:
|
||||
|
||||
mov %rax,8(%rsp,$num,8) # tp[num+1]=%rsp
|
||||
.cfi_cfa_expression %rsp+8,$num,8,mul,plus,deref,+8
|
||||
mov %r11,8(%rsp,$num,8) # tp[num+1]=%rsp
|
||||
.Lmul4x_body:
|
||||
mov $rp,16(%rsp,$num,8) # tp[num+2]=$rp
|
||||
mov %rdx,%r12 # reassign $bp
|
||||
@@ -710,10 +633,9 @@ ___
|
||||
my @ri=("%rax","%rdx",$m0,$m1);
|
||||
$code.=<<___;
|
||||
mov 16(%rsp,$num,8),$rp # restore $rp
|
||||
lea -4($num),$j
|
||||
mov 0(%rsp),@ri[0] # tp[0]
|
||||
mov 8(%rsp),@ri[1] # tp[1]
|
||||
shr \$2,$j # j=num/4-1
|
||||
shr \$2,$num # num/=4
|
||||
lea (%rsp),$ap # borrow ap for tp
|
||||
xor $i,$i # i=0 and clear CF!
|
||||
|
||||
@@ -721,7 +643,9 @@ $code.=<<___;
|
||||
mov 16($ap),@ri[2] # tp[2]
|
||||
mov 24($ap),@ri[3] # tp[3]
|
||||
sbb 8($np),@ri[1]
|
||||
|
||||
lea -1($num),$j # j=num/4-1
|
||||
jmp .Lsub4x
|
||||
.align 16
|
||||
.Lsub4x:
|
||||
mov @ri[0],0($rp,$i,8) # rp[i]=tp[i]-np[i]
|
||||
mov @ri[1],8($rp,$i,8) # rp[i]=tp[i]-np[i]
|
||||
@@ -736,7 +660,7 @@ $code.=<<___;
|
||||
mov 56($ap,$i,8),@ri[3]
|
||||
sbb 40($np,$i,8),@ri[1]
|
||||
lea 4($i),$i # i++
|
||||
dec $j # doesn't affect CF!
|
||||
dec $j # doesnn't affect CF!
|
||||
jnz .Lsub4x
|
||||
|
||||
mov @ri[0],0($rp,$i,8) # rp[i]=tp[i]-np[i]
|
||||
@@ -747,59 +671,50 @@ $code.=<<___;
|
||||
mov @ri[2],16($rp,$i,8) # rp[i]=tp[i]-np[i]
|
||||
|
||||
sbb \$0,@ri[0] # handle upmost overflow bit
|
||||
mov @ri[0],%xmm0
|
||||
punpcklqdq %xmm0,%xmm0 # extend mask to 128 bits
|
||||
mov @ri[3],24($rp,$i,8) # rp[i]=tp[i]-np[i]
|
||||
pxor %xmm0,%xmm0
|
||||
movq @ri[0],%xmm4
|
||||
pcmpeqd %xmm5,%xmm5
|
||||
pshufd \$0,%xmm4,%xmm4
|
||||
mov $num,$j
|
||||
pxor %xmm4,%xmm5
|
||||
shr \$2,$j # j=num/4
|
||||
xor %eax,%eax # i=0
|
||||
xor $i,$i # i=0
|
||||
|
||||
mov $num,$j
|
||||
pxor %xmm5,%xmm5
|
||||
jmp .Lcopy4x
|
||||
.align 16
|
||||
.Lcopy4x: # conditional copy
|
||||
movdqa (%rsp,%rax),%xmm1
|
||||
movdqu ($rp,%rax),%xmm2
|
||||
pand %xmm4,%xmm1
|
||||
pand %xmm5,%xmm2
|
||||
movdqa 16(%rsp,%rax),%xmm3
|
||||
movdqa %xmm0,(%rsp,%rax)
|
||||
por %xmm2,%xmm1
|
||||
movdqu 16($rp,%rax),%xmm2
|
||||
movdqu %xmm1,($rp,%rax)
|
||||
pand %xmm4,%xmm3
|
||||
pand %xmm5,%xmm2
|
||||
movdqa %xmm0,16(%rsp,%rax)
|
||||
por %xmm2,%xmm3
|
||||
movdqu %xmm3,16($rp,%rax)
|
||||
lea 32(%rax),%rax
|
||||
.Lcopy4x: # copy or in-place refresh
|
||||
movdqu (%rsp,$i),%xmm2
|
||||
movdqu 16(%rsp,$i),%xmm4
|
||||
movdqu ($rp,$i),%xmm1
|
||||
movdqu 16($rp,$i),%xmm3
|
||||
pxor %xmm1,%xmm2 # conditional select
|
||||
pxor %xmm3,%xmm4
|
||||
pand %xmm0,%xmm2
|
||||
pand %xmm0,%xmm4
|
||||
pxor %xmm1,%xmm2
|
||||
pxor %xmm3,%xmm4
|
||||
movdqu %xmm2,($rp,$i)
|
||||
movdqu %xmm4,16($rp,$i)
|
||||
movdqa %xmm5,(%rsp,$i) # zap temporary vectors
|
||||
movdqa %xmm5,16(%rsp,$i)
|
||||
|
||||
lea 32($i),$i
|
||||
dec $j
|
||||
jnz .Lcopy4x
|
||||
|
||||
shl \$2,$num
|
||||
___
|
||||
}
|
||||
$code.=<<___;
|
||||
mov 8(%rsp,$num,8),%rsi # restore %rsp
|
||||
.cfi_def_cfa %rsi, 8
|
||||
mov \$1,%rax
|
||||
mov -48(%rsi),%r15
|
||||
.cfi_restore %r15
|
||||
mov -40(%rsi),%r14
|
||||
.cfi_restore %r14
|
||||
mov -32(%rsi),%r13
|
||||
.cfi_restore %r13
|
||||
mov -24(%rsi),%r12
|
||||
.cfi_restore %r12
|
||||
mov -16(%rsi),%rbp
|
||||
.cfi_restore %rbp
|
||||
mov -8(%rsi),%rbx
|
||||
.cfi_restore %rbx
|
||||
lea (%rsi),%rsp
|
||||
.cfi_def_cfa_register %rsp
|
||||
mov (%rsi),%r15
|
||||
mov 8(%rsi),%r14
|
||||
mov 16(%rsi),%r13
|
||||
mov 24(%rsi),%r12
|
||||
mov 32(%rsi),%rbp
|
||||
mov 40(%rsi),%rbx
|
||||
lea 48(%rsi),%rsp
|
||||
.Lmul4x_epilogue:
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size bn_mul4x_mont,.-bn_mul4x_mont
|
||||
___
|
||||
}}}
|
||||
@@ -827,23 +742,14 @@ $code.=<<___;
|
||||
.type bn_sqr8x_mont,\@function,6
|
||||
.align 32
|
||||
bn_sqr8x_mont:
|
||||
.cfi_startproc
|
||||
mov %rsp,%rax
|
||||
.cfi_def_cfa_register %rax
|
||||
.Lsqr8x_enter:
|
||||
mov %rsp,%rax
|
||||
push %rbx
|
||||
.cfi_push %rbx
|
||||
push %rbp
|
||||
.cfi_push %rbp
|
||||
push %r12
|
||||
.cfi_push %r12
|
||||
push %r13
|
||||
.cfi_push %r13
|
||||
push %r14
|
||||
.cfi_push %r14
|
||||
push %r15
|
||||
.cfi_push %r15
|
||||
.Lsqr8x_prologue:
|
||||
|
||||
mov ${num}d,%r10d
|
||||
shl \$3,${num}d # convert $num to bytes
|
||||
@@ -856,49 +762,30 @@ bn_sqr8x_mont:
|
||||
# do its job.
|
||||
#
|
||||
lea -64(%rsp,$num,2),%r11
|
||||
mov %rsp,%rbp
|
||||
mov ($n0),$n0 # *n0
|
||||
sub $aptr,%r11
|
||||
and \$4095,%r11
|
||||
cmp %r11,%r10
|
||||
jb .Lsqr8x_sp_alt
|
||||
sub %r11,%rbp # align with $aptr
|
||||
lea -64(%rbp,$num,2),%rbp # future alloca(frame+2*$num)
|
||||
sub %r11,%rsp # align with $aptr
|
||||
lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num)
|
||||
jmp .Lsqr8x_sp_done
|
||||
|
||||
.align 32
|
||||
.Lsqr8x_sp_alt:
|
||||
lea 4096-64(,$num,2),%r10 # 4096-frame-2*$num
|
||||
lea -64(%rbp,$num,2),%rbp # future alloca(frame+2*$num)
|
||||
lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num)
|
||||
sub %r10,%r11
|
||||
mov \$0,%r10
|
||||
cmovc %r10,%r11
|
||||
sub %r11,%rbp
|
||||
sub %r11,%rsp
|
||||
.Lsqr8x_sp_done:
|
||||
and \$-64,%rbp
|
||||
mov %rsp,%r11
|
||||
sub %rbp,%r11
|
||||
and \$-4096,%r11
|
||||
lea (%rbp,%r11),%rsp
|
||||
mov (%rsp),%r10
|
||||
cmp %rbp,%rsp
|
||||
ja .Lsqr8x_page_walk
|
||||
jmp .Lsqr8x_page_walk_done
|
||||
|
||||
.align 16
|
||||
.Lsqr8x_page_walk:
|
||||
lea -4096(%rsp),%rsp
|
||||
mov (%rsp),%r10
|
||||
cmp %rbp,%rsp
|
||||
ja .Lsqr8x_page_walk
|
||||
.Lsqr8x_page_walk_done:
|
||||
|
||||
and \$-64,%rsp
|
||||
mov $num,%r10
|
||||
neg $num
|
||||
|
||||
mov $n0, 32(%rsp)
|
||||
mov %rax, 40(%rsp) # save original %rsp
|
||||
.cfi_cfa_expression %rsp+40,deref,+8
|
||||
.Lsqr8x_body:
|
||||
|
||||
movq $nptr, %xmm2 # save pointer to modulus
|
||||
@@ -907,8 +794,7 @@ bn_sqr8x_mont:
|
||||
movq %r10, %xmm3 # -$num
|
||||
___
|
||||
$code.=<<___ if ($addx);
|
||||
leaq OPENSSL_ia32cap_P(%rip),%rax
|
||||
mov 8(%rax),%eax
|
||||
mov OPENSSL_ia32cap_P+8(%rip),%eax
|
||||
and \$0x80100,%eax
|
||||
cmp \$0x80100,%eax
|
||||
jne .Lsqr8x_nox
|
||||
@@ -969,7 +855,6 @@ $code.=<<___;
|
||||
pxor %xmm0,%xmm0
|
||||
pshufd \$0,%xmm1,%xmm1
|
||||
mov 40(%rsp),%rsi # restore %rsp
|
||||
.cfi_def_cfa %rsi,8
|
||||
jmp .Lsqr8x_cond_copy
|
||||
|
||||
.align 32
|
||||
@@ -999,22 +884,14 @@ $code.=<<___;
|
||||
|
||||
mov \$1,%rax
|
||||
mov -48(%rsi),%r15
|
||||
.cfi_restore %r15
|
||||
mov -40(%rsi),%r14
|
||||
.cfi_restore %r14
|
||||
mov -32(%rsi),%r13
|
||||
.cfi_restore %r13
|
||||
mov -24(%rsi),%r12
|
||||
.cfi_restore %r12
|
||||
mov -16(%rsi),%rbp
|
||||
.cfi_restore %rbp
|
||||
mov -8(%rsi),%rbx
|
||||
.cfi_restore %rbx
|
||||
lea (%rsi),%rsp
|
||||
.cfi_def_cfa_register %rsp
|
||||
.Lsqr8x_epilogue:
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size bn_sqr8x_mont,.-bn_sqr8x_mont
|
||||
___
|
||||
}}}
|
||||
@@ -1026,48 +903,23 @@ $code.=<<___;
|
||||
.type bn_mulx4x_mont,\@function,6
|
||||
.align 32
|
||||
bn_mulx4x_mont:
|
||||
.cfi_startproc
|
||||
mov %rsp,%rax
|
||||
.cfi_def_cfa_register %rax
|
||||
.Lmulx4x_enter:
|
||||
mov %rsp,%rax
|
||||
push %rbx
|
||||
.cfi_push %rbx
|
||||
push %rbp
|
||||
.cfi_push %rbp
|
||||
push %r12
|
||||
.cfi_push %r12
|
||||
push %r13
|
||||
.cfi_push %r13
|
||||
push %r14
|
||||
.cfi_push %r14
|
||||
push %r15
|
||||
.cfi_push %r15
|
||||
.Lmulx4x_prologue:
|
||||
|
||||
shl \$3,${num}d # convert $num to bytes
|
||||
.byte 0x67
|
||||
xor %r10,%r10
|
||||
sub $num,%r10 # -$num
|
||||
mov ($n0),$n0 # *n0
|
||||
lea -72(%rsp,%r10),%rbp # future alloca(frame+$num+8)
|
||||
and \$-128,%rbp
|
||||
mov %rsp,%r11
|
||||
sub %rbp,%r11
|
||||
and \$-4096,%r11
|
||||
lea (%rbp,%r11),%rsp
|
||||
mov (%rsp),%r10
|
||||
cmp %rbp,%rsp
|
||||
ja .Lmulx4x_page_walk
|
||||
jmp .Lmulx4x_page_walk_done
|
||||
|
||||
.align 16
|
||||
.Lmulx4x_page_walk:
|
||||
lea -4096(%rsp),%rsp
|
||||
mov (%rsp),%r10
|
||||
cmp %rbp,%rsp
|
||||
ja .Lmulx4x_page_walk
|
||||
.Lmulx4x_page_walk_done:
|
||||
|
||||
lea -72(%rsp,%r10),%rsp # alloca(frame+$num+8)
|
||||
lea ($bp,$num),%r10
|
||||
and \$-128,%rsp
|
||||
##############################################################
|
||||
# Stack layout
|
||||
# +0 num
|
||||
@@ -1087,7 +939,6 @@ bn_mulx4x_mont:
|
||||
mov $n0, 24(%rsp) # save *n0
|
||||
mov $rp, 32(%rsp) # save $rp
|
||||
mov %rax,40(%rsp) # save original %rsp
|
||||
.cfi_cfa_expression %rsp+40,deref,+8
|
||||
mov $num,48(%rsp) # inner counter
|
||||
jmp .Lmulx4x_body
|
||||
|
||||
@@ -1208,17 +1059,18 @@ $code.=<<___;
|
||||
mulx 2*8($aptr),%r15,%r13 # ...
|
||||
adox -3*8($tptr),%r11
|
||||
adcx %r15,%r12
|
||||
adox -2*8($tptr),%r12
|
||||
adox $zero,%r12
|
||||
adcx $zero,%r13
|
||||
adox $zero,%r13
|
||||
|
||||
mov $bptr,8(%rsp) # off-load &b[i]
|
||||
.byte 0x67
|
||||
mov $mi,%r15
|
||||
imulq 24(%rsp),$mi # "t[0]"*n0
|
||||
xor %ebp,%ebp # xor $zero,$zero # cf=0, of=0
|
||||
|
||||
mulx 3*8($aptr),%rax,%r14
|
||||
mov $mi,%rdx
|
||||
adox -2*8($tptr),%r12
|
||||
adcx %rax,%r13
|
||||
adox -1*8($tptr),%r13
|
||||
adcx $zero,%r14
|
||||
@@ -1337,7 +1189,6 @@ $code.=<<___;
|
||||
pxor %xmm0,%xmm0
|
||||
pshufd \$0,%xmm1,%xmm1
|
||||
mov 40(%rsp),%rsi # restore %rsp
|
||||
.cfi_def_cfa %rsi,8
|
||||
jmp .Lmulx4x_cond_copy
|
||||
|
||||
.align 32
|
||||
@@ -1367,22 +1218,14 @@ $code.=<<___;
|
||||
|
||||
mov \$1,%rax
|
||||
mov -48(%rsi),%r15
|
||||
.cfi_restore %r15
|
||||
mov -40(%rsi),%r14
|
||||
.cfi_restore %r14
|
||||
mov -32(%rsi),%r13
|
||||
.cfi_restore %r13
|
||||
mov -24(%rsi),%r12
|
||||
.cfi_restore %r12
|
||||
mov -16(%rsi),%rbp
|
||||
.cfi_restore %rbp
|
||||
mov -8(%rsi),%rbx
|
||||
.cfi_restore %rbx
|
||||
lea (%rsi),%rsp
|
||||
.cfi_def_cfa_register %rsp
|
||||
.Lmulx4x_epilogue:
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size bn_mulx4x_mont,.-bn_mulx4x_mont
|
||||
___
|
||||
}}}
|
||||
@@ -1435,8 +1278,22 @@ mul_handler:
|
||||
|
||||
mov 192($context),%r10 # pull $num
|
||||
mov 8(%rax,%r10,8),%rax # pull saved stack pointer
|
||||
lea 48(%rax),%rax
|
||||
|
||||
jmp .Lcommon_pop_regs
|
||||
mov -8(%rax),%rbx
|
||||
mov -16(%rax),%rbp
|
||||
mov -24(%rax),%r12
|
||||
mov -32(%rax),%r13
|
||||
mov -40(%rax),%r14
|
||||
mov -48(%rax),%r15
|
||||
mov %rbx,144($context) # restore context->Rbx
|
||||
mov %rbp,160($context) # restore context->Rbp
|
||||
mov %r12,216($context) # restore context->R12
|
||||
mov %r13,224($context) # restore context->R13
|
||||
mov %r14,232($context) # restore context->R14
|
||||
mov %r15,240($context) # restore context->R15
|
||||
|
||||
jmp .Lcommon_seh_tail
|
||||
.size mul_handler,.-mul_handler
|
||||
|
||||
.type sqr_handler,\@abi-omnipotent
|
||||
@@ -1461,24 +1318,18 @@ sqr_handler:
|
||||
|
||||
mov 0(%r11),%r10d # HandlerData[0]
|
||||
lea (%rsi,%r10),%r10 # end of prologue label
|
||||
cmp %r10,%rbx # context->Rip<.Lsqr_prologue
|
||||
jb .Lcommon_seh_tail
|
||||
|
||||
mov 4(%r11),%r10d # HandlerData[1]
|
||||
lea (%rsi,%r10),%r10 # body label
|
||||
cmp %r10,%rbx # context->Rip<.Lsqr_body
|
||||
jb .Lcommon_pop_regs
|
||||
jb .Lcommon_seh_tail
|
||||
|
||||
mov 152($context),%rax # pull context->Rsp
|
||||
|
||||
mov 8(%r11),%r10d # HandlerData[2]
|
||||
mov 4(%r11),%r10d # HandlerData[1]
|
||||
lea (%rsi,%r10),%r10 # epilogue label
|
||||
cmp %r10,%rbx # context->Rip>=.Lsqr_epilogue
|
||||
jae .Lcommon_seh_tail
|
||||
|
||||
mov 40(%rax),%rax # pull saved stack pointer
|
||||
|
||||
.Lcommon_pop_regs:
|
||||
mov -8(%rax),%rbx
|
||||
mov -16(%rax),%rbp
|
||||
mov -24(%rax),%r12
|
||||
@@ -1565,17 +1416,15 @@ $code.=<<___;
|
||||
.LSEH_info_bn_sqr8x_mont:
|
||||
.byte 9,0,0,0
|
||||
.rva sqr_handler
|
||||
.rva .Lsqr8x_prologue,.Lsqr8x_body,.Lsqr8x_epilogue # HandlerData[]
|
||||
.align 8
|
||||
.rva .Lsqr8x_body,.Lsqr8x_epilogue # HandlerData[]
|
||||
___
|
||||
$code.=<<___ if ($addx);
|
||||
.LSEH_info_bn_mulx4x_mont:
|
||||
.byte 9,0,0,0
|
||||
.rva sqr_handler
|
||||
.rva .Lmulx4x_prologue,.Lmulx4x_body,.Lmulx4x_epilogue # HandlerData[]
|
||||
.align 8
|
||||
.rva .Lmulx4x_body,.Lmulx4x_epilogue # HandlerData[]
|
||||
___
|
||||
}
|
||||
|
||||
print $code;
|
||||
close STDOUT or die "error closing STDOUT";
|
||||
close STDOUT;
|
||||
File diff suppressed because it is too large
Load Diff
+353
@@ -0,0 +1,353 @@
|
||||
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* This package is an SSL implementation written
|
||||
* by Eric Young (eay@cryptsoft.com).
|
||||
* The implementation was written so as to conform with Netscapes SSL.
|
||||
*
|
||||
* This library is free for commercial and non-commercial use as long as
|
||||
* the following conditions are aheared to. The following conditions
|
||||
* apply to all code found in this distribution, be it the RC4, RSA,
|
||||
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
|
||||
* included with this distribution is covered by the same copyright terms
|
||||
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||
*
|
||||
* Copyright remains Eric Young's, and as such any Copyright notices in
|
||||
* the code are not to be removed.
|
||||
* If this package is used in a product, Eric Young should be given attribution
|
||||
* as the author of the parts of the library used.
|
||||
* This can be in the form of a textual message at program startup or
|
||||
* in documentation (online or textual) provided with the package.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* "This product includes cryptographic software written by
|
||||
* Eric Young (eay@cryptsoft.com)"
|
||||
* The word 'cryptographic' can be left out if the rouines from the library
|
||||
* being used are not cryptographic related :-).
|
||||
* 4. If you include any Windows specific code (or a derivative thereof) from
|
||||
* the apps directory (application code) you must include an acknowledgement:
|
||||
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* The licence and distribution terms for any publically available version or
|
||||
* derivative of this code cannot be changed. i.e. this code cannot simply be
|
||||
* copied and put under another distribution licence
|
||||
* [including the GNU Public Licence.] */
|
||||
|
||||
#include <openssl/bn.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/mem.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
BIGNUM *BN_new(void) {
|
||||
BIGNUM *bn = OPENSSL_malloc(sizeof(BIGNUM));
|
||||
|
||||
if (bn == NULL) {
|
||||
OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(bn, 0, sizeof(BIGNUM));
|
||||
bn->flags = BN_FLG_MALLOCED;
|
||||
|
||||
return bn;
|
||||
}
|
||||
|
||||
void BN_init(BIGNUM *bn) {
|
||||
memset(bn, 0, sizeof(BIGNUM));
|
||||
}
|
||||
|
||||
void BN_free(BIGNUM *bn) {
|
||||
if (bn == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((bn->flags & BN_FLG_STATIC_DATA) == 0) {
|
||||
OPENSSL_free(bn->d);
|
||||
}
|
||||
|
||||
if (bn->flags & BN_FLG_MALLOCED) {
|
||||
OPENSSL_free(bn);
|
||||
} else {
|
||||
bn->d = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void BN_clear_free(BIGNUM *bn) {
|
||||
char should_free;
|
||||
|
||||
if (bn == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bn->d != NULL) {
|
||||
OPENSSL_cleanse(bn->d, bn->dmax * sizeof(bn->d[0]));
|
||||
if ((bn->flags & BN_FLG_STATIC_DATA) == 0) {
|
||||
OPENSSL_free(bn->d);
|
||||
}
|
||||
}
|
||||
|
||||
should_free = (bn->flags & BN_FLG_MALLOCED) != 0;
|
||||
OPENSSL_cleanse(bn, sizeof(BIGNUM));
|
||||
if (should_free) {
|
||||
OPENSSL_free(bn);
|
||||
}
|
||||
}
|
||||
|
||||
BIGNUM *BN_dup(const BIGNUM *src) {
|
||||
BIGNUM *copy;
|
||||
|
||||
if (src == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
copy = BN_new();
|
||||
if (copy == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!BN_copy(copy, src)) {
|
||||
BN_free(copy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
BIGNUM *BN_copy(BIGNUM *dest, const BIGNUM *src) {
|
||||
if (src == dest) {
|
||||
return dest;
|
||||
}
|
||||
|
||||
if (bn_wexpand(dest, src->top) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(dest->d, src->d, sizeof(src->d[0]) * src->top);
|
||||
|
||||
dest->top = src->top;
|
||||
dest->neg = src->neg;
|
||||
return dest;
|
||||
}
|
||||
|
||||
void BN_clear(BIGNUM *bn) {
|
||||
if (bn->d != NULL) {
|
||||
memset(bn->d, 0, bn->dmax * sizeof(bn->d[0]));
|
||||
}
|
||||
|
||||
bn->top = 0;
|
||||
bn->neg = 0;
|
||||
}
|
||||
|
||||
const BIGNUM *BN_value_one(void) {
|
||||
static const BN_ULONG kOneLimbs[1] = { 1 };
|
||||
static const BIGNUM kOne = STATIC_BIGNUM(kOneLimbs);
|
||||
|
||||
return &kOne;
|
||||
}
|
||||
|
||||
void BN_with_flags(BIGNUM *out, const BIGNUM *in, int flags) {
|
||||
memcpy(out, in, sizeof(BIGNUM));
|
||||
out->flags &= ~BN_FLG_MALLOCED;
|
||||
out->flags |= BN_FLG_STATIC_DATA | flags;
|
||||
}
|
||||
|
||||
/* BN_num_bits_word returns the minimum number of bits needed to represent the
|
||||
* value in |l|. */
|
||||
unsigned BN_num_bits_word(BN_ULONG l) {
|
||||
static const unsigned char bits[256] = {
|
||||
0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8};
|
||||
|
||||
#if defined(OPENSSL_64_BIT)
|
||||
if (l & 0xffffffff00000000L) {
|
||||
if (l & 0xffff000000000000L) {
|
||||
if (l & 0xff00000000000000L) {
|
||||
return (bits[(int)(l >> 56)] + 56);
|
||||
} else {
|
||||
return (bits[(int)(l >> 48)] + 48);
|
||||
}
|
||||
} else {
|
||||
if (l & 0x0000ff0000000000L) {
|
||||
return (bits[(int)(l >> 40)] + 40);
|
||||
} else {
|
||||
return (bits[(int)(l >> 32)] + 32);
|
||||
}
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (l & 0xffff0000L) {
|
||||
if (l & 0xff000000L) {
|
||||
return (bits[(int)(l >> 24L)] + 24);
|
||||
} else {
|
||||
return (bits[(int)(l >> 16L)] + 16);
|
||||
}
|
||||
} else {
|
||||
if (l & 0xff00L) {
|
||||
return (bits[(int)(l >> 8)] + 8);
|
||||
} else {
|
||||
return (bits[(int)(l)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned BN_num_bits(const BIGNUM *bn) {
|
||||
const int max = bn->top - 1;
|
||||
|
||||
if (BN_is_zero(bn)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return max*BN_BITS2 + BN_num_bits_word(bn->d[max]);
|
||||
}
|
||||
|
||||
unsigned BN_num_bytes(const BIGNUM *bn) {
|
||||
return (BN_num_bits(bn) + 7) / 8;
|
||||
}
|
||||
|
||||
void BN_zero(BIGNUM *bn) {
|
||||
bn->top = bn->neg = 0;
|
||||
}
|
||||
|
||||
int BN_one(BIGNUM *bn) {
|
||||
return BN_set_word(bn, 1);
|
||||
}
|
||||
|
||||
int BN_set_word(BIGNUM *bn, BN_ULONG value) {
|
||||
if (value == 0) {
|
||||
BN_zero(bn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (bn_wexpand(bn, 1) == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bn->neg = 0;
|
||||
bn->d[0] = value;
|
||||
bn->top = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int bn_set_words(BIGNUM *bn, const BN_ULONG *words, size_t num) {
|
||||
if (bn_wexpand(bn, num) == NULL) {
|
||||
return 0;
|
||||
}
|
||||
memmove(bn->d, words, num * sizeof(BN_ULONG));
|
||||
/* |bn_wexpand| verified that |num| isn't too large. */
|
||||
bn->top = (int)num;
|
||||
bn_correct_top(bn);
|
||||
bn->neg = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BN_is_negative(const BIGNUM *bn) {
|
||||
return bn->neg != 0;
|
||||
}
|
||||
|
||||
void BN_set_negative(BIGNUM *bn, int sign) {
|
||||
if (sign && !BN_is_zero(bn)) {
|
||||
bn->neg = 1;
|
||||
} else {
|
||||
bn->neg = 0;
|
||||
}
|
||||
}
|
||||
|
||||
BIGNUM *bn_wexpand(BIGNUM *bn, size_t words) {
|
||||
BN_ULONG *a;
|
||||
|
||||
if (words <= (size_t)bn->dmax) {
|
||||
return bn;
|
||||
}
|
||||
|
||||
if (words > (INT_MAX / (4 * BN_BITS2))) {
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_BIGNUM_TOO_LONG);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bn->flags & BN_FLG_STATIC_DATA) {
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_EXPAND_ON_STATIC_BIGNUM_DATA);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
a = OPENSSL_malloc(sizeof(BN_ULONG) * words);
|
||||
if (a == NULL) {
|
||||
OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(a, bn->d, sizeof(BN_ULONG) * bn->top);
|
||||
|
||||
OPENSSL_free(bn->d);
|
||||
bn->d = a;
|
||||
bn->dmax = (int)words;
|
||||
|
||||
return bn;
|
||||
}
|
||||
|
||||
BIGNUM *bn_expand(BIGNUM *bn, size_t bits) {
|
||||
if (bits + BN_BITS2 - 1 < bits) {
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_BIGNUM_TOO_LONG);
|
||||
return NULL;
|
||||
}
|
||||
return bn_wexpand(bn, (bits+BN_BITS2-1)/BN_BITS2);
|
||||
}
|
||||
|
||||
void bn_correct_top(BIGNUM *bn) {
|
||||
BN_ULONG *ftl;
|
||||
int tmp_top = bn->top;
|
||||
|
||||
if (tmp_top > 0) {
|
||||
for (ftl = &(bn->d[tmp_top - 1]); tmp_top > 0; tmp_top--) {
|
||||
if (*(ftl--)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
bn->top = tmp_top;
|
||||
}
|
||||
}
|
||||
|
||||
int BN_get_flags(const BIGNUM *bn, int flags) {
|
||||
return bn->flags & flags;
|
||||
}
|
||||
|
||||
void BN_set_flags(BIGNUM *bn, int flags) {
|
||||
bn->flags |= flags;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/* Copyright (c) 2015, Google Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
#include <openssl/bn.h>
|
||||
|
||||
#include <openssl/bytestring.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
|
||||
int BN_parse_asn1_unsigned(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;
|
||||
}
|
||||
|
||||
if (CBS_data(&child)[0] & 0x80) {
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* INTEGERs must be minimal. */
|
||||
if (CBS_data(&child)[0] == 0x00 &&
|
||||
CBS_len(&child) > 1 &&
|
||||
!(CBS_data(&child)[1] & 0x80)) {
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_BAD_ENCODING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)) {
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
CBB child;
|
||||
if (!CBB_add_asn1(cbb, &child, CBS_ASN1_INTEGER) ||
|
||||
/* The number must be padded with a leading zero if the high bit would
|
||||
* otherwise be set or if |bn| is zero. */
|
||||
(BN_num_bits(bn) % 8 == 0 && !CBB_add_u8(&child, 0x00)) ||
|
||||
!BN_bn2cbb_padded(&child, BN_num_bytes(bn), bn) ||
|
||||
!CBB_flush(cbb)) {
|
||||
OPENSSL_PUT_ERROR(BN, BN_R_ENCODE_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user