Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding a runtime dis/enabler of DIT Capability on AArch64. #1783

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 25 additions & 15 deletions BUILDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@ See "Snapshot Safety Prerequisites" here: https://lkml.org/lkml/2021/3/8/677

# Data Independent Timing on AArch64

The functions described in this section are still experimental.

The Data Independent Timing (DIT) flag on Arm64 processors, when
enabled, ensures the following as per [Arm A-profile Architecture
Registers
Expand All @@ -255,19 +257,27 @@ It is also expected to disable the Data Memory-dependent Prefetcher
article](https://appleinsider.com/articles/24/03/21/apple-silicon-vulnerability-leaks-encryption-keys-and-cant-be-patched-easily).

Building with the option `-DENABLE_DATA_INDEPENDENT_TIMING_AARCH64=ON`
will enable the macro `SET_DIT_AUTO_DISABLE`. This macro is present at
the entry of functions that process/load/store secret data to enable
the DIT flag and then set it to its original value on entry. With
this build option, there is an effect on performance that varies by
will enable the macro `SET_DIT_AUTO_RESET`. This macro is present at
the entry of functions that process/load/store secret data to set the
DIT flag and then reset it to its original value on entry. With this
build option, there is an effect on performance that varies by
function and by processor architecture. The effect is mostly due to
enabling and disabling the DIT flag. If it remains enabled over many
calls, the effect can be largely mitigated. Hence, the macro can be
inserted in the caller's application at the beginning of the code
scope that makes repeated calls to AWS-LC cryptographic
functions. Alternatively, the functions `armv8_enable_dit` and
`armv8_restore_dit` can be placed at the beginning and the end of
the code section, respectively.
An example of that usage is present in the benchmarking function
`Speed()` in `tool/speed.cc` when the `-dit` option is used

./tool/bssl speed -dit
setting and resetting the DIT flag. If it remains set over many calls,
the effect can be largely mitigated. Hence, the macro can be inserted
in the caller's application at the beginning of the code scope that
makes repeated calls to AWS-LC cryptographic functions.

Alternatively, the functions that are invoked in the macro,
`armv8_set_dit` and `armv8_restore_dit`, can be placed at the
beginning and the end of the code section, respectively. These
functions are available regardless whether the build flag is used or
not. An example of that usage is present in the benchmarking function
`Speed()` in `tool/speed.cc` when the `-dit` option is used.

./tool/bssl speed -dit

The DIT capability, which is checked in `OPENSSL_cpuid_setup` can be
masked out at runtime by calling `armv8_disable_dit`. This would
result in having the functions `armv8_set_dit` and `armv8_restore_dit`
being a noop. It can be made available again at runtime by calling
`armv8_enable_dit`.
5 changes: 3 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ option(ENABLE_DILITHIUM "Enable Dilithium signatures in the EVP API" OFF)
option(DISABLE_PERL "Disable Perl for AWS-LC" OFF)
option(DISABLE_GO "Disable Go for AWS-LC" OFF)
option(ENABLE_FIPS_ENTROPY_CPU_JITTER "Enable FIPS entropy source: CPU Jitter" OFF)
option(ENABLE_DATA_INDEPENDENT_TIMING_AARCH64 "Enable Data-Independent Timing (DIT) flag on Arm64" OFF)
option(ENABLE_DATA_INDEPENDENT_TIMING_AARCH64 "Enable automatic setting/resetting Data-Independent Timing
justsmth marked this conversation as resolved.
Show resolved Hide resolved
(DIT) flag in cryptographic functions on Arm64" OFF)
include(cmake/go.cmake)

enable_language(C)
Expand Down Expand Up @@ -835,7 +836,7 @@ if(ARCH STREQUAL "x86" AND NOT OPENSSL_NO_SSE2_FOR_TESTING)
endif()

if(ENABLE_DATA_INDEPENDENT_TIMING_AARCH64)
add_definitions(-DMAKE_DIT_AVAILABLE)
add_definitions(-DENABLE_AUTO_SET_RESET_DIT)
endif()

if(USE_CUSTOM_LIBCXX)
Expand Down
1 change: 1 addition & 0 deletions crypto/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,7 @@ if(BUILD_TESTING)
fipsmodule/sha/sha_test.cc
fipsmodule/sha/sha3_test.cc
fipsmodule/cpucap/cpu_arm_linux_test.cc
fipsmodule/cpucap/cpu_aarch64_dit_test.cc
fipsmodule/hkdf/hkdf_test.cc
fipsmodule/sshkdf/sshkdf_test.cc
hpke/hpke_test.cc
Expand Down
8 changes: 4 additions & 4 deletions crypto/evp_extra/p_dh_asn1.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ const EVP_PKEY_ASN1_METHOD dh_asn1_meth = {
};

int EVP_PKEY_set1_DH(EVP_PKEY *pkey, DH *key) {
SET_DIT_AUTO_DISABLE
SET_DIT_AUTO_RESET
if (EVP_PKEY_assign_DH(pkey, key)) {
DH_up_ref(key);
return 1;
Expand All @@ -98,14 +98,14 @@ int EVP_PKEY_set1_DH(EVP_PKEY *pkey, DH *key) {
}

int EVP_PKEY_assign_DH(EVP_PKEY *pkey, DH *key) {
SET_DIT_AUTO_DISABLE
SET_DIT_AUTO_RESET
evp_pkey_set_method(pkey, &dh_asn1_meth);
pkey->pkey.dh = key;
return key != NULL;
}

DH *EVP_PKEY_get0_DH(const EVP_PKEY *pkey) {
SET_DIT_AUTO_DISABLE
SET_DIT_AUTO_RESET
if (pkey->type != EVP_PKEY_DH) {
OPENSSL_PUT_ERROR(EVP, EVP_R_EXPECTING_A_DH_KEY);
return NULL;
Expand All @@ -114,7 +114,7 @@ DH *EVP_PKEY_get0_DH(const EVP_PKEY *pkey) {
}

DH *EVP_PKEY_get1_DH(const EVP_PKEY *pkey) {
SET_DIT_AUTO_DISABLE
SET_DIT_AUTO_RESET
DH *dh = EVP_PKEY_get0_DH(pkey);
if (dh != NULL) {
DH_up_ref(dh);
Expand Down
8 changes: 4 additions & 4 deletions crypto/fipsmodule/aes/aes.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
// code, above, is incompatible with the |aes_hw_*| functions.

void AES_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
SET_DIT_AUTO_DISABLE;
SET_DIT_AUTO_RESET;
if (hwaes_capable()) {
aes_hw_encrypt(in, out, key);
} else if (vpaes_capable()) {
Expand All @@ -71,7 +71,7 @@ void AES_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
}

void AES_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
SET_DIT_AUTO_DISABLE;
SET_DIT_AUTO_RESET;
if (hwaes_capable()) {
aes_hw_decrypt(in, out, key);
} else if (vpaes_capable()) {
Expand All @@ -82,7 +82,7 @@ void AES_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
}

int AES_set_encrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey) {
SET_DIT_AUTO_DISABLE;
SET_DIT_AUTO_RESET;
if (bits != 128 && bits != 192 && bits != 256) {
return -2;
}
Expand All @@ -96,7 +96,7 @@ int AES_set_encrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey) {
}

int AES_set_decrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey) {
SET_DIT_AUTO_DISABLE;
SET_DIT_AUTO_RESET;
if (bits != 128 && bits != 192 && bits != 256) {
return -2;
}
Expand Down
10 changes: 5 additions & 5 deletions crypto/fipsmodule/cipher/aead.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ int EVP_AEAD_CTX_init_with_direction(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead,
const uint8_t *key, size_t key_len,
size_t tag_len,
enum evp_aead_direction_t dir) {
SET_DIT_AUTO_DISABLE;
SET_DIT_AUTO_RESET;
if (key_len != aead->key_len) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_KEY_SIZE);
ctx->aead = NULL;
Expand Down Expand Up @@ -125,7 +125,7 @@ int EVP_AEAD_CTX_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len,
size_t max_out_len, const uint8_t *nonce,
size_t nonce_len, const uint8_t *in, size_t in_len,
const uint8_t *ad, size_t ad_len) {
SET_DIT_AUTO_DISABLE;
SET_DIT_AUTO_RESET;
if (in_len + ctx->aead->overhead < in_len /* overflow */) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
goto error;
Expand Down Expand Up @@ -164,7 +164,7 @@ int EVP_AEAD_CTX_seal_scatter(const EVP_AEAD_CTX *ctx, uint8_t *out,
size_t in_len, const uint8_t *extra_in,
size_t extra_in_len, const uint8_t *ad,
size_t ad_len) {
SET_DIT_AUTO_DISABLE; //check that it was preserved
SET_DIT_AUTO_RESET; //check that it was preserved
// |in| and |out| may alias exactly, |out_tag| may not alias.
if (!check_alias(in, in_len, out, in_len) ||
buffers_alias(out, in_len, out_tag, max_out_tag_len) ||
Expand Down Expand Up @@ -197,7 +197,7 @@ int EVP_AEAD_CTX_open(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len,
size_t max_out_len, const uint8_t *nonce,
size_t nonce_len, const uint8_t *in, size_t in_len,
const uint8_t *ad, size_t ad_len) {
SET_DIT_AUTO_DISABLE;
SET_DIT_AUTO_RESET;
if (!check_alias(in, in_len, out, max_out_len)) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT);
goto error;
Expand Down Expand Up @@ -245,7 +245,7 @@ int EVP_AEAD_CTX_open_gather(const EVP_AEAD_CTX *ctx, uint8_t *out,
const uint8_t *in, size_t in_len,
const uint8_t *in_tag, size_t in_tag_len,
const uint8_t *ad, size_t ad_len) {
SET_DIT_AUTO_DISABLE;
SET_DIT_AUTO_RESET;
if (!check_alias(in, in_len, out, in_len)) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT);
goto error;
Expand Down
14 changes: 7 additions & 7 deletions crypto/fipsmodule/cipher/cipher.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx) {
}

int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in) {
SET_DIT_AUTO_DISABLE;
SET_DIT_AUTO_RESET;
if (in == NULL || in->cipher == NULL) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INPUT_NOT_INITIALIZED);
return 0;
Expand Down Expand Up @@ -146,7 +146,7 @@ int EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *ctx) {
int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
ENGINE *engine, const uint8_t *key, const uint8_t *iv,
int enc) {
SET_DIT_AUTO_DISABLE;
SET_DIT_AUTO_RESET;
GUARD_PTR(ctx);
if (enc == -1) {
enc = ctx->encrypt;
Expand Down Expand Up @@ -264,7 +264,7 @@ static int block_remainder(const EVP_CIPHER_CTX *ctx, int len) {

int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
const uint8_t *in, int in_len) {
SET_DIT_AUTO_DISABLE;
SET_DIT_AUTO_RESET;
GUARD_PTR(ctx);
if (ctx->poisoned) {
OPENSSL_PUT_ERROR(CIPHER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
Expand Down Expand Up @@ -357,7 +357,7 @@ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
}

int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len) {
SET_DIT_AUTO_DISABLE;
SET_DIT_AUTO_RESET;
int n;
unsigned int i, b, bl;
GUARD_PTR(ctx);
Expand Down Expand Up @@ -412,7 +412,7 @@ int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len) {

int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
const uint8_t *in, int in_len) {
SET_DIT_AUTO_DISABLE;
SET_DIT_AUTO_RESET;
GUARD_PTR(ctx);
if (ctx->poisoned) {
OPENSSL_PUT_ERROR(CIPHER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
Expand Down Expand Up @@ -479,7 +479,7 @@ int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
}

int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) {
SET_DIT_AUTO_DISABLE;
SET_DIT_AUTO_RESET;
int i, n;
unsigned int b;
*out_len = 0;
Expand Down Expand Up @@ -552,7 +552,7 @@ int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) {

int EVP_Cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in,
size_t in_len) {
SET_DIT_AUTO_DISABLE;
SET_DIT_AUTO_RESET;
GUARD_PTR(ctx);
GUARD_PTR(ctx->cipher);
const int ret = ctx->cipher->cipher(ctx, out, in, in_len);
Expand Down
38 changes: 30 additions & 8 deletions crypto/fipsmodule/cpucap/cpu_aarch64.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,21 @@ void handle_cpu_env(uint32_t *out, const char *in) {
}
}

#if defined(MAKE_DIT_AVAILABLE) && !defined(OPENSSL_WINDOWS)
#if !defined(OPENSSL_WINDOWS)
// "DIT" is not recognised as a register name by clang-10 (at least)
// Register's encoded name is from e.g.
// https://github.com/ashwio/arm64-sysreg-lib/blob/d421e249a026f6f14653cb6f9c4edd8c5d898595/include/sysreg/dit.h#L286
#define DIT_REGISTER s3_3_c4_c2_5
DEFINE_STATIC_MUTEX(OPENSSL_armcap_P_lock)

static uint64_t armv8_get_dit(void) {
uint64_t val = 0;
__asm__ volatile("mrs %0, s3_3_c4_c2_5" : "=r" (val));
return (val >> 24) & 1;
uint64_t armv8_get_dit(void) {
if (CRYPTO_is_ARMv8_DIT_capable()) {
uint64_t val = 0;
__asm__ volatile("mrs %0, s3_3_c4_c2_5" : "=r" (val));
return (val >> 24) & 1;
} else {
return 0;
}
}

// See https://github.com/torvalds/linux/blob/53eaeb7fbe2702520125ae7d72742362c071a1f2/arch/arm64/include/asm/sysreg.h#L82
Expand All @@ -70,7 +75,7 @@ static uint64_t armv8_get_dit(void) {
// Op1 (3 for DIT) , Op2 (5 for DIT) encodes the PSTATE field modified and defines the constraints.
// CRm = Imm4 (#0 or #1 below)
// Rt = 0x1f
uint64_t armv8_enable_dit(void) {
uint64_t armv8_set_dit(void) {
if (CRYPTO_is_ARMv8_DIT_capable()) {
uint64_t original_dit = armv8_get_dit();
// Encoding of "msr dit, #1"
Expand All @@ -82,11 +87,28 @@ uint64_t armv8_enable_dit(void) {
}

void armv8_restore_dit(volatile uint64_t *original_dit) {
if (CRYPTO_is_ARMv8_DIT_capable() && *original_dit != 1) {
if (*original_dit != 1 && CRYPTO_is_ARMv8_DIT_capable()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (*original_dit != 1 && CRYPTO_is_ARMv8_DIT_capable()) {
if (original_dit != NULL && *original_dit != 1 && CRYPTO_is_ARMv8_DIT_capable()) {

// Encoding of "msr dit, #0"
__asm__ volatile(".long 0xd503405f");
}
}
#endif // MAKE_DIT_AVAILABLE && !OPENSSL_WINDOWS

void armv8_disable_dit(void) {
CRYPTO_STATIC_MUTEX_lock_write(OPENSSL_armcap_P_lock_bss_get());
OPENSSL_armcap_P &= ~ARMV8_DIT_ALLOWED;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here and for armv8_enable_dit, is this operation thread-safe? not sure what the HIDDEN macro expands to, but it's not clear that OPENSSL_armcap_P is thread-local.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OPENSSL_armcap_P is a global variable of type uint32_t which is shared a cross the entire address space.

Firstly, since the memory is shared it doesn't allow a thread to control whether it wants to enable DIT mode or not; its choice can be overwritten by any other thread.

Secondly, multiple writes/reads can now occur concurrently on OPENSSL_armcap_P since it's mostly just referenced directly and there therefore aren't any synchonisation. This was fine because it was only really readable after the initial construction of the memory content (the initialisation of the arm capability vector). This PR breaks that assumption.

Finally, is this a "threading issue". Well, yes and no. One thread can read the value while another writes to it. The writing operation only mutate a single byte of the 32-bit value. So, the value when read is either the bit set or not. It won't be a bogus value. So, no. On the other hand, from the first point I made above, any thread can mutate the value. So one thread can enable, while another immediately afterwards can disable the DIT. But that might just be what we can build - DIT is a process global CPU control no?

I think we weakly considered OPENSSL_armcap_P nominally const after the initial initialisation. It might not be the ideal memory to store this information.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from the first point I made above, any thread can mutate the value. So one thread can enable, while another immediately afterwards can disable the DIT.

yes, this is my concern.

But that might just be what we can build - DIT is a process global CPU control no?

My understanding from nevine's description is that it can be configured per-thread. I suppose we could leave it up to the caller to not call these functions from >1 thread, and document this limitation very clearly. I don't think this would be an issue for ACCP, as we'd just set or unset DIT once on initialization, but it could be a concern for other consumers.

CRYPTO_STATIC_MUTEX_unlock_write(OPENSSL_armcap_P_lock_bss_get());
}

void armv8_enable_dit(void) {
CRYPTO_STATIC_MUTEX_lock_write(OPENSSL_armcap_P_lock_bss_get());
OPENSSL_armcap_P |= ARMV8_DIT_ALLOWED;
CRYPTO_STATIC_MUTEX_unlock_write(OPENSSL_armcap_P_lock_bss_get());
}

int CRYPTO_is_ARMv8_DIT_capable_for_testing(void) {
return CRYPTO_is_ARMv8_DIT_capable();
}

#endif // !OPENSSL_WINDOWS

#endif // OPENSSL_AARCH64 && !OPENSSL_STATIC_ARMCAP
4 changes: 1 addition & 3 deletions crypto/fipsmodule/cpucap/cpu_aarch64_apple.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,9 @@ void OPENSSL_cpuid_setup(void) {
OPENSSL_armcap_P |= ARMV8_APPLE_M1;
}

#if defined(MAKE_DIT_AVAILABLE)
if (has_hw_feature("hw.optional.arm.FEAT_DIT")) {
OPENSSL_armcap_P |= ARMV8_DIT;
OPENSSL_armcap_P |= (ARMV8_DIT | ARMV8_DIT_ALLOWED);
}
#endif // MAKE_DIT_AVAILABLE

justsmth marked this conversation as resolved.
Show resolved Hide resolved
// OPENSSL_armcap is a 32-bit, unsigned value which may start with "0x" to
// indicate a hex value. Prior to the 32-bit value, a '~' or '|' may be given.
Expand Down
55 changes: 55 additions & 0 deletions crypto/fipsmodule/cpucap/cpu_aarch64_dit_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC

#include <openssl/crypto.h>
#include <gtest/gtest.h>

#include "internal.h"

#if defined(OPENSSL_AARCH64) && !defined(OPENSSL_STATIC_ARMCAP) && \
!defined(OPENSSL_WINDOWS)

#if defined(ENABLE_AUTO_SET_RESET_DIT)
static void NestedMacroInvocation(uint64_t one) {
SET_DIT_AUTO_RESET;
uint64_t current_dit = armv8_get_dit();
EXPECT_EQ(current_dit, one);
}
#endif // ENABLE_AUTO_SET_RESET_DIT

TEST(DITTest, SetReset) {
uint64_t one = CRYPTO_is_ARMv8_DIT_capable_for_testing()? (uint64_t)1 : (uint64_t)0;

uint64_t original_dit = 0, original_dit_2 = 0,
current_dit = 0;
original_dit = armv8_set_dit();
EXPECT_EQ(original_dit, (uint64_t)0);

// the case of a nested call of setting DIT
original_dit_2 = armv8_set_dit();
EXPECT_EQ(original_dit_2, one);

current_dit = armv8_get_dit();
EXPECT_EQ(current_dit, one);

armv8_restore_dit(&original_dit);
current_dit = armv8_get_dit();
EXPECT_EQ(current_dit, (uint64_t)0);

#if defined(ENABLE_AUTO_SET_RESET_DIT)
{ // invoke the macro within a scope
// to test that it restores the CPU DIT flag at the end
SET_DIT_AUTO_RESET;
current_dit = armv8_get_dit();
EXPECT_EQ(current_dit, one);
// Nested macro invocation will exit the scope leaving DIT = 1
NestedMacroInvocation(one);
current_dit = armv8_get_dit();
EXPECT_EQ(current_dit, one);
}
current_dit = armv8_get_dit();
EXPECT_EQ(current_dit, (uint64_t)0);
#endif // ENABLE_AUTO_SET_RESET_DIT
}

#endif // OPENSSL_AARCH64 && !OPENSSL_STATIC_ARMCAP && !OPENSSL_WINDOWS
Loading
Loading