diff options
-rw-r--r-- | Android.bp | 159 | ||||
-rw-r--r-- | CryptoNativeTests.xml (renamed from NativeTests.xml) | 9 | ||||
-rw-r--r-- | SslNativeTests.xml | 33 | ||||
-rwxr-xr-x | UPDATING | 20 | ||||
-rw-r--r-- | rules.mk | 19 | ||||
-rw-r--r-- | src/crypto/fipsmodule/hmac/hmac.c | 1 | ||||
-rw-r--r-- | src/crypto/x509/x509_test.cc | 106 | ||||
-rw-r--r-- | src/crypto/x509/x509_vfy.c | 6 | ||||
-rw-r--r-- | src/include/openssl/x509.h | 4 | ||||
-rw-r--r-- | src/ssl/ssl_test.cc | 2 | ||||
-rwxr-xr-x | src/util/fipstools/break-tests.sh | 200 |
11 files changed, 515 insertions, 44 deletions
@@ -60,15 +60,9 @@ cc_defaults { "-Werror", ], - c_std: "gnu11", - // Build BoringSSL and its tests against the same STL. sdk_version: "9", - target: { - android: { - stl: "libc++_static", - }, - }, + stl: "libc++_static", } // Used by libcrypto + libssl @@ -109,8 +103,11 @@ cc_defaults { }, local_include_dirs: ["src/crypto"], + stl: "none", } +// Boring Crypto Module object file. +// Any changes here must also be reflected in bcm_object_for_testing below. cc_object { name: "bcm_object", device_supported: true, @@ -125,6 +122,7 @@ cc_object { sanitize: { address: false, hwaddress: false, + memtag_stack: false, fuzzer: false, }, target: { @@ -158,7 +156,7 @@ cc_object { "com.android.art", "com.android.art.debug", "com.android.art.testing", - "com.android.bluetooth", + "com.android.btservices", "com.android.compos", "com.android.conscrypt", "com.android.resolv", @@ -167,6 +165,55 @@ cc_object { min_sdk_version: "29", } +// Version of bcm_object built with BORINGSSL_FIPS_BREAK_TESTS defined. +// Only for use with the FIPS break-tests.sh script. +// Must be kept in sync with bcm_object. +cc_object { + name: "bcm_object_for_testing", + visibility: [ + "//external/boringssl", + ], + device_supported: true, + defaults: [ + "libcrypto_bcm_sources", + "libcrypto_defaults", + "boringssl_defaults", + "boringssl_flags", + ], + sanitize: { + address: false, + hwaddress: false, + fuzzer: false, + }, + target: { + android: { + cflags: [ + "-DBORINGSSL_FIPS", + "-DBORINGSSL_FIPS_BREAK_TESTS", + "-fPIC", + // -fno[data|text]-sections required to ensure a + // single text and data section for FIPS integrity check + "-fno-data-sections", + "-fno-function-sections", + ], + linker_script: "src/crypto/fipsmodule/fips_shared.lds", + }, + // Temporary hack to let BoringSSL build with a new compiler. + // This doesn't enable HWASAN unconditionally, it just causes + // BoringSSL's asm code to unconditionally use a HWASAN-compatible + // global variable reference so that the non-HWASANified (because of + // sanitize: { hwaddress: false } above) code in the BCM can + // successfully link against the HWASANified code in the rest of + // BoringSSL in HWASAN builds. + android_arm64: { + asflags: [ + "-fsanitize=hwaddress", + ], + }, + }, + min_sdk_version: "29", +} + bootstrap_go_package { name: "bssl_ar", pkgPath: "boringssl.googlesource.com/boringssl/util/ar", @@ -197,7 +244,8 @@ blueprint_go_binary { ], } -// Target and host library +// Target and host library. +// Any changes here must also be reflected in libcrypto_for_test below. cc_library { name: "libcrypto", visibility: ["//visibility:public"], @@ -246,7 +294,7 @@ cc_library { "com.android.art", "com.android.art.debug", "com.android.art.testing", - "com.android.bluetooth", + "com.android.btservices", "com.android.compos", "com.android.conscrypt", "com.android.resolv", @@ -255,6 +303,49 @@ cc_library { min_sdk_version: "29", } +// Version of libcrypto build with BORINGSSL_FIPS_BREAK_TESTS defined +// Only for use with the FIPS break-tests.sh script. +// Must be kept in sync with libcrypto. +cc_library { + name: "libcrypto_for_testing", + visibility: [ + "//external/boringssl", + ], + defaults: [ + "libcrypto_sources", + "libcrypto_defaults", + "boringssl_defaults", + "boringssl_flags", + ], + unique_host_soname: true, + srcs: [ + ":bcm_object_for_testing", + ], + target: { + android: { + cflags: [ + "-DBORINGSSL_FIPS", + "-DBORINGSSL_FIPS_BREAK_TESTS", + ], + sanitize: { + // Disable address sanitizing otherwise libcrypto will not report + // itself as being in FIPS mode, which causes boringssl_self_test + // to fail. + address: false, + }, + inject_bssl_hash: true, + static: { + // Disable the static version of libcrypto, as it causes + // problems for FIPS certification. Use libcrypto_static for + // modules that need static libcrypto but do not need FIPS self + // testing, or use dynamic libcrypto. + enabled: false, + }, + }, + }, + min_sdk_version: "29", +} + // Static library // This version of libcrypto will not have FIPS self tests enabled, so its // usage is protected through visibility to ensure it doesn't end up used @@ -278,6 +369,7 @@ cc_library_static { "//hardware/interfaces/keymaster/4.0/vts/functional", "//hardware/interfaces/keymaster/4.1/vts/functional", "//packages/modules/adb", + "//packages/modules/Bluetooth:__subpackages__", "//packages/modules/DnsResolver/tests:__subpackages__", "//packages/modules/NeuralNetworks:__subpackages__", "//system/core/init", @@ -288,6 +380,7 @@ cc_library_static { "//system/security/keystore/tests", "//test/vts-testcase/security/avb", ], + min_sdk_version: "29", apex_available: [ "//apex_available:platform", "com.android.neuralnetworks", @@ -301,6 +394,25 @@ cc_library_static { ], } +// Static library for use in bare-metal environments +cc_library_static { + name: "libcrypto_baremetal", + defaults: [ + "libcrypto_bcm_sources", + "libcrypto_sources", + "libcrypto_defaults", + "boringssl_defaults", + "boringssl_flags", + ], + cflags: [ + "-DOPENSSL_NO_THREADS_CORRUPT_MEMORY_AND_LEAK_SECRETS_IF_THREADED", + "-DOPENSSL_SMALL", + "-DOPENSSL_NO_ASM", + ], + visibility: ["//packages/modules/Virtualization:__subpackages__"], + apex_available: ["com.android.virt"], +} + // Common defaults for lib*_fuzz_unsafe. These are unsafe and deterministic // libraries for testing and fuzzing only. See src/FUZZING.md. cc_defaults { @@ -363,10 +475,11 @@ cc_library { apex_available: [ "//apex_available:platform", - "com.android.bluetooth", + "com.android.btservices", "com.android.adbd", "com.android.conscrypt", "com.android.resolv", + "com.android.virt", ], min_sdk_version: "29", } @@ -486,14 +599,13 @@ cc_library_static { shared_libs: [ "libcrypto", - "libssl", ], } // Tests cc_test { name: "boringssl_crypto_test", - test_config: "NativeTests.xml", + test_config: "CryptoNativeTests.xml", host_supported: false, per_testcase_directory: true, compile_multilib: "both", @@ -522,7 +634,7 @@ cc_test { cc_test { name: "boringssl_ssl_test", - test_config: "NativeTests.xml", + test_config: "SslNativeTests.xml", host_supported: false, per_testcase_directory: true, compile_multilib: "both", @@ -565,6 +677,10 @@ cc_binary { srcs: [ "src/util/fipstools/test_fips.c", ], + required: [ + "adb", + "libcrypto_for_testing", + ], } // Rust bindings @@ -603,6 +719,10 @@ rust_bindgen { "libcrypto", "libssl", ], + apex_available: [ + "//apex_available:platform", + "com.android.virt", + ], } // Encapsulate the bindgen-generated layout tests as a test target. @@ -629,6 +749,10 @@ cc_library_static { "libcrypto", "libssl", ], + apex_available: [ + "//apex_available:platform", + "com.android.virt", + ], } // Replace the upstream CMake placeholder with a re-export of all of the local bindgen output. @@ -653,7 +777,12 @@ rust_library { // Since libbssl_sys_raw is not publically visible, we can't // accidentally force a double-link by linking statically, so do so. rlibs: ["libbssl_sys_raw"], - static_libs: [ + whole_static_libs: [ "libbssl_rust_support", ], + apex_available: [ + "//apex_available:platform", + "com.android.virt", + ], } + diff --git a/NativeTests.xml b/CryptoNativeTests.xml index d3eb9444..0adc18f2 100644 --- a/NativeTests.xml +++ b/CryptoNativeTests.xml @@ -14,26 +14,19 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. ~ - ~ Re-runs a subset of MtsConscryptTestCases using Conscrypt's file-descriptor based - ~ implementation to ensure there are no regressions in this implementation before - ~ it is fully deprecated. - ~ - ~ Apart from the include filters and SSLSocket implementation this test suite is - ~ identical to MtsConscryptTestCases. + ~ Native test configuration for boringssl_crypto_test. --> <configuration description="Configuration for BoringSSL native tests"> <option name="test-suite-tag" value="mts-conscrypt" /> <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher"> <option name="cleanup" value="true" /> <option name="push" value="boringssl_crypto_test->/data/local/tmp/boringssl_crypto_test" /> - <option name="push" value="boringssl_ssl_test->/data/local/tmp/boringssl_ssl_test" /> <option name="append-bitness" value="true" /> </target_preparer> <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/> <test class="com.android.tradefed.testtype.GTest" > <option name="native-test-device-path" value="/data/local/tmp" /> <option name="module-name" value="boringssl_crypto_test" /> - <option name="module-name" value="boringssl_ssl_test" /> <option name="runtime-hint" value="10m" /> <option name="native-test-timeout" value="600000" /> </test> diff --git a/SslNativeTests.xml b/SslNativeTests.xml new file mode 100644 index 00000000..9257111d --- /dev/null +++ b/SslNativeTests.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2022 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + ~ + ~ Native test configuration for boringssl_ssl_test. + --> +<configuration description="Configuration for BoringSSL native tests"> + <option name="test-suite-tag" value="mts-conscrypt" /> + <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher"> + <option name="cleanup" value="true" /> + <option name="push" value="boringssl_ssl_test->/data/local/tmp/boringssl_ssl_test" /> + <option name="append-bitness" value="true" /> + </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/> + <test class="com.android.tradefed.testtype.GTest" > + <option name="native-test-device-path" value="/data/local/tmp" /> + <option name="module-name" value="boringssl_ssl_test" /> + <option name="runtime-hint" value="10m" /> + <option name="native-test-timeout" value="600000" /> + </test> +</configuration> @@ -2,14 +2,26 @@ set -xe +# If a branch name is passed on the command line then sync +# to that instead of HEAD. +branch="$1" + old_revision=$(cat BORINGSSL_REVISION) rm -Rf src git clone https://boringssl.googlesource.com/boringssl src cd src +if [ "$branch" ]; then + git checkout "$branch" +fi new_revision=$(git show -s --pretty=%H) +if [ "$branch" ]; then + target="branch $branch" +else + target="$new_revision" +fi msgfile=$(mktemp) -echo "external/boringssl: Sync to ${new_revision}. +echo "external/boringssl: Sync to ${target}. This includes the following changes: @@ -24,8 +36,10 @@ git log --format='format:* %s%n%n%b' ${old_revision}..${new_revision} \ cd .. echo " -Test: atest CtsLibcoreTestCases CtsLibcoreOkHttpTestCases" >> $msgfile -echo ${new_revision} > BORINGSSL_REVISION +Test: atest CtsLibcoreTestCases CtsLibcoreOkHttpTestCases boringssl_crypto_test boringssl_ssl_test" >> $msgfile +if [ ! "$branch" ]; then + echo ${new_revision} > BORINGSSL_REVISION +fi rm -Rf src/.git rm -Rf src/fuzz @@ -37,22 +37,6 @@ LOCAL_ADDITIONAL_DEPENDENCIES := MODULE_SRCDEPS += $(LOCAL_DIR)/crypto-sources.mk include $(LOCAL_DIR)/crypto-sources.mk -# Some files in BoringSSL use OS functions that aren't supported by Trusty. The -# easiest way to deal with them is not to include them. As long as no path to -# the functions defined in these files exists, the linker will be happy. If -# such a path is created, it'll be a link-time error and something more complex -# may need to be considered. -LOCAL_SRC_FILES := $(filter-out src/crypto/bio/connect.c,$(LOCAL_SRC_FILES)) -LOCAL_SRC_FILES := $(filter-out src/crypto/bio/fd.c,$(LOCAL_SRC_FILES)) -LOCAL_SRC_FILES := $(filter-out src/crypto/bio/file.c,$(LOCAL_SRC_FILES)) -LOCAL_SRC_FILES := $(filter-out src/crypto/bio/socket.c,$(LOCAL_SRC_FILES)) -LOCAL_SRC_FILES := $(filter-out src/crypto/bio/socket_helper.c,$(LOCAL_SRC_FILES)) -LOCAL_SRC_FILES := $(filter-out src/crypto/x509/by_dir.c,$(LOCAL_SRC_FILES)) - -# BoringSSL detects Trusty based on this define and does things like switch to -# no-op threading functions. -MODULE_CFLAGS += -DTRUSTY - # The AOSP stdatomic.h clang header does not build against musl. Disable C11 # atomics. MODULE_CFLAGS += -D__STDC_NO_ATOMICS__ @@ -88,7 +72,6 @@ MODULE_INCLUDES += $(LOCAL_DIR)/src/crypto MODULE_EXPORT_INCLUDES += $(LOCAL_DIR)/src/include -MODULE_LIBRARY_DEPS += \ - trusty/user/base/lib/openssl-stubs \ +include trusty/user/base/lib/openssl-stubs/openssl-stubs-inc.mk include make/library.mk diff --git a/src/crypto/fipsmodule/hmac/hmac.c b/src/crypto/fipsmodule/hmac/hmac.c index 454d0c0d..56e21b04 100644 --- a/src/crypto/fipsmodule/hmac/hmac.c +++ b/src/crypto/fipsmodule/hmac/hmac.c @@ -63,6 +63,7 @@ #include <openssl/mem.h> #include "../../internal.h" +#include "../service_indicator/internal.h" uint8_t *HMAC(const EVP_MD *evp_md, const void *key, size_t key_len, diff --git a/src/crypto/x509/x509_test.cc b/src/crypto/x509/x509_test.cc index ce70ae3b..379f26bc 100644 --- a/src/crypto/x509/x509_test.cc +++ b/src/crypto/x509/x509_test.cc @@ -1470,6 +1470,23 @@ TEST(X509Test, TestCRL) { Verify(leaf.get(), {root.get()}, {root.get()}, {algorithm_mismatch_crl2.get()}, X509_V_FLAG_CRL_CHECK)); + // The CRL is valid for a month. + EXPECT_EQ(X509_V_ERR_CRL_HAS_EXPIRED, + Verify(leaf.get(), {root.get()}, {root.get()}, {basic_crl.get()}, + X509_V_FLAG_CRL_CHECK, [](X509_VERIFY_PARAM *param) { + X509_VERIFY_PARAM_set_time( + param, kReferenceTime + 2 * 30 * 24 * 3600); + })); + + // X509_V_FLAG_NO_CHECK_TIME suppresses the validity check. + EXPECT_EQ(X509_V_OK, + Verify(leaf.get(), {root.get()}, {root.get()}, {basic_crl.get()}, + X509_V_FLAG_CRL_CHECK | X509_V_FLAG_NO_CHECK_TIME, + [](X509_VERIFY_PARAM *param) { + X509_VERIFY_PARAM_set_time( + param, kReferenceTime + 2 * 30 * 24 * 3600); + })); + // Parsing kBadExtensionCRL should fail. EXPECT_FALSE(CRLFromPEM(kBadExtensionCRL)); } @@ -3551,6 +3568,95 @@ TEST(X509Test, TrustedFirst) { })); } +// Test that notBefore and notAfter checks work correctly. +TEST(X509Test, Expiry) { + bssl::UniquePtr<EVP_PKEY> key = PrivateKeyFromPEM(kP256Key); + ASSERT_TRUE(key); + + // The following are measured in seconds relative to kReferenceTime. The + // validity periods are staggered so we can independently test both leaf and + // root time checks. + const time_t kSecondsInDay = 24 * 3600; + const time_t kRootStart = -30 * kSecondsInDay; + const time_t kIntermediateStart = -20 * kSecondsInDay; + const time_t kLeafStart = -10 * kSecondsInDay; + const time_t kIntermediateEnd = 10 * kSecondsInDay; + const time_t kLeafEnd = 20 * kSecondsInDay; + const time_t kRootEnd = 30 * kSecondsInDay; + + bssl::UniquePtr<X509> root = + MakeTestCert("Root", "Root", key.get(), /*is_ca=*/true); + ASSERT_TRUE(root); + ASSERT_TRUE(ASN1_TIME_adj(X509_getm_notBefore(root.get()), kReferenceTime, + /*offset_day=*/0, + /*offset_sec=*/kRootStart)); + ASSERT_TRUE(ASN1_TIME_adj(X509_getm_notAfter(root.get()), kReferenceTime, + /*offset_day=*/0, + /*offset_sec=*/kRootEnd)); + ASSERT_TRUE(X509_sign(root.get(), key.get(), EVP_sha256())); + + bssl::UniquePtr<X509> intermediate = + MakeTestCert("Root", "Intermediate", key.get(), /*is_ca=*/true); + ASSERT_TRUE(intermediate); + ASSERT_TRUE(ASN1_TIME_adj(X509_getm_notBefore(intermediate.get()), + kReferenceTime, + /*offset_day=*/0, + /*offset_sec=*/kIntermediateStart)); + ASSERT_TRUE(ASN1_TIME_adj(X509_getm_notAfter(intermediate.get()), + kReferenceTime, + /*offset_day=*/0, + /*offset_sec=*/kIntermediateEnd)); + ASSERT_TRUE(X509_sign(intermediate.get(), key.get(), EVP_sha256())); + + bssl::UniquePtr<X509> leaf = + MakeTestCert("Intermediate", "Leaf", key.get(), /*is_ca=*/false); + ASSERT_TRUE(leaf); + ASSERT_TRUE(ASN1_TIME_adj(X509_getm_notBefore(leaf.get()), kReferenceTime, + /*offset_day=*/0, + /*offset_sec=*/kLeafStart)); + ASSERT_TRUE(ASN1_TIME_adj(X509_getm_notAfter(leaf.get()), kReferenceTime, + /*offset_day=*/0, + /*offset_sec=*/kLeafEnd)); + ASSERT_TRUE(X509_sign(leaf.get(), key.get(), EVP_sha256())); + + struct VerifyAt { + time_t time; + void operator()(X509_VERIFY_PARAM *param) const { + X509_VERIFY_PARAM_set_time(param, time); + } + }; + + for (bool check_time : {true, false}) { + SCOPED_TRACE(check_time); + unsigned long flags = check_time ? 0 : X509_V_FLAG_NO_CHECK_TIME; + int not_yet_valid = check_time ? X509_V_ERR_CERT_NOT_YET_VALID : X509_V_OK; + int has_expired = check_time ? X509_V_ERR_CERT_HAS_EXPIRED : X509_V_OK; + + EXPECT_EQ(not_yet_valid, + Verify(leaf.get(), {root.get()}, {intermediate.get()}, {}, flags, + VerifyAt{kReferenceTime + kRootStart - 1})); + EXPECT_EQ(not_yet_valid, + Verify(leaf.get(), {root.get()}, {intermediate.get()}, {}, flags, + VerifyAt{kReferenceTime + kIntermediateStart - 1})); + EXPECT_EQ(not_yet_valid, + Verify(leaf.get(), {root.get()}, {intermediate.get()}, {}, flags, + VerifyAt{kReferenceTime + kLeafStart - 1})); + + EXPECT_EQ(X509_V_OK, Verify(leaf.get(), {root.get()}, {intermediate.get()}, + {}, flags, VerifyAt{kReferenceTime})); + + EXPECT_EQ(has_expired, + Verify(leaf.get(), {root.get()}, {intermediate.get()}, {}, flags, + VerifyAt{kReferenceTime + kRootEnd + 1})); + EXPECT_EQ(has_expired, + Verify(leaf.get(), {root.get()}, {intermediate.get()}, {}, flags, + VerifyAt{kReferenceTime + kIntermediateEnd + 1})); + EXPECT_EQ(has_expired, + Verify(leaf.get(), {root.get()}, {intermediate.get()}, {}, flags, + VerifyAt{kReferenceTime + kLeafEnd + 1})); + } +} + // kConstructedBitString is an X.509 certificate where the signature is encoded // as a BER constructed BIT STRING. Note that, while OpenSSL's parser accepts // this input, it interprets the value incorrectly. diff --git a/src/crypto/x509/x509_vfy.c b/src/crypto/x509/x509_vfy.c index f41ae6e1..7dcac260 100644 --- a/src/crypto/x509/x509_vfy.c +++ b/src/crypto/x509/x509_vfy.c @@ -1000,6 +1000,9 @@ static int check_crl_time(X509_STORE_CTX *ctx, X509_CRL *crl, int notify) { time_t *ptime; int i; + if (ctx->param->flags & X509_V_FLAG_NO_CHECK_TIME) { + return 1; + } if (notify) ctx->current_crl = crl; if (ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME) @@ -1743,6 +1746,9 @@ static int check_cert_time(X509_STORE_CTX *ctx, X509 *x) time_t *ptime; int i; + if (ctx->param->flags & X509_V_FLAG_NO_CHECK_TIME) { + return 1; + } if (ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME) ptime = &ctx->param->check_time; else diff --git a/src/include/openssl/x509.h b/src/include/openssl/x509.h index 4d312c7e..608c6700 100644 --- a/src/include/openssl/x509.h +++ b/src/include/openssl/x509.h @@ -2071,6 +2071,10 @@ OPENSSL_EXPORT void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth); // will force the behaviour to match that of previous versions. #define X509_V_FLAG_NO_ALT_CHAINS 0x100000 +// X509_V_FLAG_NO_CHECK_TIME disables all time checks in certificate +// verification. +#define X509_V_FLAG_NO_CHECK_TIME 0x200000 + #define X509_VP_FLAG_DEFAULT 0x1 #define X509_VP_FLAG_OVERWRITE 0x2 #define X509_VP_FLAG_RESET_FLAGS 0x4 diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc index e2db5a4d..f07196cf 100644 --- a/src/ssl/ssl_test.cc +++ b/src/ssl/ssl_test.cc @@ -8064,6 +8064,8 @@ RVHWbCvFvNZAoWiIJ2z34RLGInyZvCZ8xLAvsuaWULDDaoeDl1M0t4Hm SSL_CTX_set_verify(client_ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr); + X509_VERIFY_PARAM_set_flags(SSL_CTX_get0_param(client_ctx.get()), + X509_V_FLAG_NO_CHECK_TIME); struct TestCase { X509 *cert; diff --git a/src/util/fipstools/break-tests.sh b/src/util/fipstools/break-tests.sh new file mode 100755 index 00000000..f33c4c6f --- /dev/null +++ b/src/util/fipstools/break-tests.sh @@ -0,0 +1,200 @@ +# Copyright (c) 2022, Google Inc. +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +# This script runs test_fips repeatedly with different FIPS tests broken. It is +# intended to be observed to demonstrate that the various tests are working and +# thus pauses for a keystroke between tests. +# +# Runs in either device mode (on an attached Android device) or in a locally built +# BoringSSL checkout. +# +# On Android static binaries are not built using FIPS mode, so in device mode each +# test makes changes to libcrypto.so rather than the test binary, test_fips. + +set -e + +die () { + echo "ERROR: $@" + exit 1 +} + +usage() { + echo "USAGE: $0 [local|device]" + exit 1 +} + +inferred_mode() { + # Try and infer local or device mode based on makefiles and artifacts. + if [ -f Android.bp -o -f external/boringssl/Android.bp ]; then + echo device + elif [ -f CMakeLists.txt -a -d build/crypto -a -d build/ssl ]; then + echo local + else + echo "Unable to infer mode, please specify on the command line." + usage + fi +} + +# Prefer mode from command line if present. +case "$1" in + local|device) + MODE=$1 + ;; + + "") + MODE=`inferred_mode` + ;; + + *) + usage + ;; +esac + +check_directory() { + test -d $1 || die "Directory $1 not found." +} + +check_file() { + test -f $1 || die "File $1 not found." +} + +run_test_locally() { + eval "$1" || true +} + +run_test_on_device() { + EXECFILE="$1" + LIBRARY="$2" + adb shell rm -rf $DEVICE_TMP + adb shell mkdir -p $DEVICE_TMP + adb push $EXECFILE $DEVICE_TMP > /dev/null + EXECPATH=$(basename $EXECFILE) + adb push $LIBRARY $DEVICE_TMP > /dev/null + CMD="LD_LIBRARY_PATH=$DEVICE_TMP $DEVICE_TMP/$EXECPATH" + if [ "$BORINGSSL_FIPS_BREAK_TEST" ]; then + CMD="BORINGSSL_FIPS_BREAK_TEST=$BORINGSSL_FIPS_BREAK_TEST $CMD" + fi + adb shell "$CMD" || true +} + +device_integrity_break_test() { + go run $BORINGSSL/util/fipstools/break-hash.go $LIBCRYPTO_BIN ./libcrypto.so + $RUN $TEST_FIPS_BIN ./libcrypto.so + rm ./libcrypto.so +} + +local_integrity_break_test() { + go run $BORINGSSL/util/fipstools/break-hash.go $TEST_FIPS_BIN ./break-bin + chmod u+x ./break-bin + $RUN ./break-bin + rm ./break-bin +} + +local_runtime_break_test() { + BORINGSSL_FIPS_BREAK_TEST=$1 $RUN $TEST_FIPS_BREAK_BIN +} + +device_runtime_break_test() { + cp $LIBCRYPTO_BREAK_BIN ./libcrypto.so + BORINGSSL_FIPS_BREAK_TEST=$1 $RUN $TEST_FIPS_BIN ./libcrypto.so + rm ./libcrypto.so +} + +# TODO(prb): make break-hash and break-kat take similar arguments to save having +# separate functions for each. +device_kat_break_test() { + KAT="$1" + go run $BORINGSSL/util/fipstools/break-kat.go $LIBCRYPTO_BREAK_BIN $KAT > ./libcrypto.so + $RUN $TEST_FIPS_BIN ./libcrypto.so + rm ./libcrypto.so +} + +local_kat_break_test() { + KAT="$1" + go run $BORINGSSL/util/fipstools/break-kat.go $TEST_FIPS_BREAK_BIN $KAT > ./break-bin + chmod u+x ./break-bin + $RUN ./break-bin + rm ./break-bin +} + +pause () { + echo -n "Press <Enter> " + read +} + +if [ "$MODE" = "local" ]; then + TEST_FIPS_BIN=${TEST_FIPS_BIN:-build/util/fipstools/test_fips} + check_file $TEST_FIPS_BIN + + TEST_FIPS_BREAK_BIN=${TEST_FIPS_BREAK_BIN:-./test_fips_break} + if [ ! -f $TEST_FIPS_BREAK_BIN ]; then + echo "$TEST_FIPS_BREAK_BIN is missing. Build BoringSSL with " + echo "-DFIPS_BREAK_TEST=TESTS passed to CMake and copy the resulting" + echo "test_fips binary to $TEST_FIPS_BREAK_BIN." + exit 1 + fi + + BORINGSSL=. + RUN=run_test_locally + BREAK_TEST=local_break_test + INTEGRITY_BREAK_TEST=local_integrity_break_test + KAT_BREAK_TEST=local_kat_break_test + RUNTIME_BREAK_TEST=local_runtime_break_test +else # Device mode + test "$ANDROID_BUILD_TOP" || die "'lunch aosp_arm64-eng' first" + check_directory "$ANDROID_PRODUCT_OUT" + test "$TARGET_PRODUCT" = "aosp_arm64" || die "Lunch target is $TARGET_PRODUCT not aosp_arm64" + + TEST_FIPS_BIN="$ANDROID_PRODUCT_OUT/system/bin/test_fips" + check_file "$TEST_FIPS_BIN" + LIBCRYPTO_BIN="$ANDROID_PRODUCT_OUT/system/lib64/libcrypto.so" + LIBCRYPTO_BREAK_BIN="$ANDROID_PRODUCT_OUT/system/lib64/libcrypto_for_testing.so" + check_file "$LIBCRYPTO_BIN" + check_file "$LIBCRYPTO_BREAK_BIN" + + test "$ANDROID_SERIAL" || die "ANDROID_SERIAL not set" + DEVICE_TMP=/data/local/tmp + + BORINGSSL="$ANDROID_BUILD_TOP/external/boringssl/src" + RUN=run_test_on_device + INTEGRITY_BREAK_TEST=device_integrity_break_test + KAT_BREAK_TEST=device_kat_break_test + RUNTIME_BREAK_TEST=device_runtime_break_test +fi + + +KATS=$(go run $BORINGSSL/util/fipstools/break-kat.go --list-tests) + +echo -e '\033[1mNormal output\033[0m' +$RUN $TEST_FIPS_BIN $LIBCRYPTO_BIN +pause + +echo +echo -e '\033[1mIntegrity test failure\033[0m' +$INTEGRITY_BREAK_TEST +pause + +for kat in $KATS; do + echo + echo -e "\033[1mKAT failure ${kat}\033[0m" + $KAT_BREAK_TEST $kat + pause +done + +for runtime_test in ECDSA_PWCT RSA_PWCT CRNG; do + echo + echo -e "\033[1m${runtime_test} failure\033[0m" + $RUNTIME_BREAK_TEST ${runtime_test} + pause +done |