FIPS validation requires showing that the continuous and start-up tests are effective by breaking them. Traditionally BoringSSL used #defines that tweaked the expected values. However, 140-3 now requires that the inputs be changed, not the expected outputs. Also, the number of tests is going to increase. Since slower platforms already took too long to compile BoringSSL n times (once for each test to break) we want something faster too. Therefore all the known-answer tests (KATs) are changed such that a Go program can find and replace the input value in order to break them. Thus we only need to recompile once to disable the integrity test. The runtime tests still need a #define to break, but that #define is now put in a header file so that only the module need be recompiled, not everything as in the previous system. Change-Id: Ib621198e6ad02253e29af0ccd978e3c3830ad54c Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/51329 Reviewed-by: David Benjamin <davidben@google.com> Commit-Queue: Adam Langley <agl@google.com>fips-20220613
parent
f8235e4993
commit
d04c32a3d8
11 changed files with 555 additions and 499 deletions
@ -0,0 +1,38 @@ |
|||||||
|
/* 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. */ |
||||||
|
|
||||||
|
#ifndef OPENSSL_HEADER_CRYPTO_FIPSMODULE_FIPS_BREAK_TEST_H |
||||||
|
#define OPENSSL_HEADER_CRYPTO_FIPSMODULE_FIPS_BREAK_TEST_H |
||||||
|
|
||||||
|
#include <openssl/base.h> |
||||||
|
|
||||||
|
#include <stdlib.h> |
||||||
|
#include <string.h> |
||||||
|
|
||||||
|
#if defined(BORINGSSL_FIPS_BREAK_TESTS) |
||||||
|
|
||||||
|
OPENSSL_INLINE int boringssl_fips_break_test(const char *test) { |
||||||
|
const char *const value = getenv("BORINGSSL_FIPS_BREAK_TEST"); |
||||||
|
return value != NULL && strcmp(value, test) == 0; |
||||||
|
} |
||||||
|
|
||||||
|
#else |
||||||
|
|
||||||
|
OPENSSL_INLINE int boringssl_fips_break_test(const char *test) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
#endif // BORINGSSL_FIPS_BREAK_TESTS
|
||||||
|
|
||||||
|
#endif // OPENSSL_HEADER_CRYPTO_FIPSMODULE_FIPS_BREAK_TEST_H
|
@ -0,0 +1,89 @@ |
|||||||
|
// break-kat corrupts a known-answer-test input in a binary and writes the
|
||||||
|
// corrupted binary to stdout. This is used to demonstrate that the KATs in the
|
||||||
|
// binary notice the error.
|
||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"bytes" |
||||||
|
"encoding/hex" |
||||||
|
"flag" |
||||||
|
"fmt" |
||||||
|
"io/ioutil" |
||||||
|
"os" |
||||||
|
"sort" |
||||||
|
) |
||||||
|
|
||||||
|
var ( |
||||||
|
kats = map[string]string{ |
||||||
|
"HMAC-SHA-256": "dad91293dfcf2a7c8ecd13fe353fa75b", |
||||||
|
"AES-CBC-encrypt": "078609a6c5ac2544699adf682fa377f9be8ab6aef563e8c56a36b84f557fadd3", |
||||||
|
"AES-CBC-decrypt": "347aa5a024b28257b36510be583d4f47adb7bbeedc6005bbbd0d0a9f06bb7b10", |
||||||
|
"AES-GCM-encrypt": "8fcc4099808e75caaff582898848a88d808b55ab4e9370797d940be8cc1d7884", |
||||||
|
"AES-GCM-decrypt": "35f3058f875760ff09d3120f70c4bc9ed7a86872e13452202176f7371ae04faae1dd391920f5d13953d896785994823c", |
||||||
|
"DRBG": "c4da0740d505f1ee280b95e58c4931ac6de846a0152fbb4a3f174cf4787a4f1a40c2b50babe14aae530be5886d910a27", |
||||||
|
"DRBG-reseed": "c7161ca36c2309b716e9859bb96c6d49bdc8352103a18cd24ef42ec97ef46bf446eb1a4576c186e9351803763a7912fe", |
||||||
|
"SHA-1": "132fd9bad5c1826263bafbb699f707a5", |
||||||
|
"SHA-256": "ff3b857da7236a2baa0f396b51522217", |
||||||
|
"SHA-512": "212512f8d2ad8322781c6c4d69a9daa1", |
||||||
|
"TLS-KDF": "abc3657b094c7628a0b282996fe75a75f4984fd94d4ecc2fcf53a2c469a3f731", |
||||||
|
"RSA-sign": "d2b56e53306f720d7929d8708bf46f1c22300305582b115bedcac722d8aa5ab2", |
||||||
|
"RSA-verify": "abe2cbc13d6bd39d48db5334ddbf8d070a93bdcb104e2cc5d0ee486ee295f6b31bda126c41890b98b73e70e6b65d82f95c663121755a90744c8d1c21148a1960be0eca446e9ff497f1345c537ef8119b9a4398e95c5c6de2b1c955905c5299d8ce7a3b6ab76380d9babdd15f610237e1f3f2aa1c1f1e770b62fbb596381b2ebdd77ecef9c90d4c92f7b6b05fed2936285fa94826e62055322a33b6f04c74ce69e5d8d737fb838b79d2d48e3daf71387531882531a95ac964d02ea413bf85952982bbc089527daff5b845c9a0f4d14ef1956d9c3acae882d12da66da0f35794f5ee32232333517db9315232a183b991654dbea41615345c885325926744a53915", |
||||||
|
"ECDSA-sign": "1e35930be860d0942ca7bbd6f6ded87f157e4de24f81ed4b875c0e018e89a81f", |
||||||
|
"ECDSA-verify": "6780c5fc70275e2c7061a0e7877bb174deadeb9887027f3fa83654158ba7f50c2d36e5799790bfbe2183d33e96f3c51f6a232f2a24488c8e5f64c37ea2cf0529", |
||||||
|
"Z-computation": "e7604491269afb5b102d6ea52cb59feb70aede6ce3bfb3e0105485abd861d77b", |
||||||
|
"FFDH": "a14f8ad36be37b18b8f35864392f150ab7ee22c47e1870052a3f17918274af18aaeaf4cf6aacfde96c9d586eb7ebaff6b03fe3b79a8e2ff9dd6df34caaf2ac70fd3771d026b41a561ee90e4337d0575f8a0bd160c868e7e3cef88aa1d88448b1e4742ba11480a9f8a8b737347c408d74a7d57598c48875629df0c85327a124ddec1ad50cd597a985588434ce19c6f044a1696b5f244b899b7e77d4f6f20213ae8eb15d37eb8e67e6c8bdbc4fd6e17426283da96f23a897b210058c7c70fb126a5bf606dbeb1a6d5cca04184c4e95c2e8a70f50f5c1eabd066bd79c180456316ac02d366eb3b0e7ba82fb70dcbd737ca55734579dd250fffa8e0584be99d32b35", |
||||||
|
} |
||||||
|
|
||||||
|
listTests = flag.Bool("list-tests", false, "List known test values and exit") |
||||||
|
) |
||||||
|
|
||||||
|
func main() { |
||||||
|
flag.Parse() |
||||||
|
|
||||||
|
if *listTests { |
||||||
|
for _, kat := range sortedKATs() { |
||||||
|
fmt.Println(kat) |
||||||
|
} |
||||||
|
os.Exit(0) |
||||||
|
} |
||||||
|
|
||||||
|
if flag.NArg() != 2 || kats[flag.Arg(1)] == "" { |
||||||
|
fmt.Fprintln(os.Stderr, "Usage: break-kat <binary path> <test to break> > output") |
||||||
|
fmt.Fprintln(os.Stderr, "Possible values for <test to break>:") |
||||||
|
for _, kat := range sortedKATs() { |
||||||
|
fmt.Fprintln(os.Stderr, " ", kat) |
||||||
|
} |
||||||
|
os.Exit(1) |
||||||
|
} |
||||||
|
|
||||||
|
inPath := flag.Arg(0) |
||||||
|
test := flag.Arg(1) |
||||||
|
testInputValue, err := hex.DecodeString(kats[test]) |
||||||
|
if err != nil { |
||||||
|
panic("invalid kat data: " + err.Error()) |
||||||
|
} |
||||||
|
|
||||||
|
binaryContents, err := ioutil.ReadFile(inPath) |
||||||
|
if err != nil { |
||||||
|
fmt.Fprintln(os.Stderr, err) |
||||||
|
os.Exit(2) |
||||||
|
} |
||||||
|
|
||||||
|
i := bytes.Index(binaryContents, testInputValue) |
||||||
|
if i < 0 { |
||||||
|
fmt.Fprintln(os.Stderr, "Expected test input value was not found in binary.") |
||||||
|
os.Exit(3) |
||||||
|
} |
||||||
|
|
||||||
|
binaryContents[i] ^= 1 |
||||||
|
os.Stdout.Write(binaryContents) |
||||||
|
} |
||||||
|
|
||||||
|
func sortedKATs() []string { |
||||||
|
var ret []string |
||||||
|
for kat := range kats { |
||||||
|
ret = append(ret, kat) |
||||||
|
} |
||||||
|
sort.Strings(ret) |
||||||
|
return ret |
||||||
|
} |
@ -1,117 +0,0 @@ |
|||||||
# Copyright (c) 2019, 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 exists to exercise breaking each of the FIPS tests on an Android |
|
||||||
# device. Since, on Android, BoringCrypto exists in both 32- and 64-bit |
|
||||||
# versions, the first argument must be either "32" or "64" to select which is |
|
||||||
# being tested. The Android source tree must have been setup (with "lunch") for |
|
||||||
# a matching build configuration before using this script to build the |
|
||||||
# binaries. (Although it'll fail non-silently if there's a mismatch.) |
|
||||||
# |
|
||||||
# Since each test needs the FIPS module to be compiled differently, and that |
|
||||||
# can take a long time, this script is run twice: once with "build" as the |
|
||||||
# second argument to run the builds, and then with "run" as the second argument |
|
||||||
# to run each test. |
|
||||||
# |
|
||||||
# Run it with /bin/bash, not /bin/sh, otherwise "read" may fail. |
|
||||||
# |
|
||||||
# In order to reconfigure the build for each test, it needs to set a define. It |
|
||||||
# does so by rewriting a template in external/boringssl/Android.bp and you must |
|
||||||
# add the template value before doing the builds. To do so, insert |
|
||||||
# -DBORINGSSL_FIPS_BREAK_XXX=1 in the cflags list for the module, probably by |
|
||||||
# putting it in the "boringssl_flags" stanza. |
|
||||||
|
|
||||||
set -x |
|
||||||
set -e |
|
||||||
|
|
||||||
if [ ! -f external/boringssl/Android.bp ]; then |
|
||||||
echo "Must be run from the top-level of an Android source tree." |
|
||||||
exit 1 |
|
||||||
fi |
|
||||||
|
|
||||||
. build/envsetup.sh |
|
||||||
|
|
||||||
TESTS="NONE ECDSA_PWCT CRNG RSA_PWCT AES_CBC AES_GCM DES SHA_1 SHA_256 SHA_512 RSA_SIG DRBG ECDSA_SIG Z_COMPUTATION TLS_KDF FFC_DH" |
|
||||||
|
|
||||||
if [ "x$1" = "x32" ]; then |
|
||||||
lib="lib" |
|
||||||
bits="32" |
|
||||||
elif [ "x$1" = "x64" ] ; then |
|
||||||
lib="lib64" |
|
||||||
bits="64" |
|
||||||
else |
|
||||||
echo "First argument must be 32 or 64" |
|
||||||
exit 1 |
|
||||||
fi |
|
||||||
|
|
||||||
if [ "x$2" = "xbuild" ]; then |
|
||||||
if ! grep -q DBORINGSSL_FIPS_BREAK_XXX=1 external/boringssl/Android.bp; then |
|
||||||
echo "Missing DBORINGSSL_FIPS_BREAK_XXX in external/boringssl/Android.bp. Edit the file and insert -DBORINGSSL_FIPS_BREAK_XXX=1 in the cflags for the FIPS module" |
|
||||||
exit 1 |
|
||||||
fi |
|
||||||
|
|
||||||
printf "\\x1b[1mBuilding modules\\x1b[0m\n" |
|
||||||
for test in $TESTS; do |
|
||||||
printf "\\x1b[1mBuilding for ${test}\\x1b[0m\n" |
|
||||||
cp external/boringssl/Android.bp external/boringssl/Android.bp.orig |
|
||||||
sed -i -e "s/DBORINGSSL_FIPS_BREAK_XXX/DBORINGSSL_FIPS_BREAK_${test}/" external/boringssl/Android.bp |
|
||||||
m test_fips |
|
||||||
dir=test-${bits}-${test} |
|
||||||
rm -Rf $dir |
|
||||||
mkdir $dir |
|
||||||
cp ${ANDROID_PRODUCT_OUT}/system/${lib}/libcrypto.so $dir |
|
||||||
cp ${ANDROID_PRODUCT_OUT}/system/bin/test_fips $dir |
|
||||||
if [ $bits = "32" ] ; then |
|
||||||
if ! file ${dir}/test_fips | grep -q "32-bit" ; then |
|
||||||
echo "32-bit build requested but binaries don't appear to be 32-bit:" |
|
||||||
file ${dir}/test_fips |
|
||||||
exit 1 |
|
||||||
fi |
|
||||||
else |
|
||||||
if ! file ${dir}/test_fips | grep -q "64-bit" ; then |
|
||||||
echo "64-bit build requested but binaries don't appear to be 64-bit:" |
|
||||||
file ${dir}/test_fips |
|
||||||
exit 1 |
|
||||||
fi |
|
||||||
fi |
|
||||||
cp external/boringssl/Android.bp.orig external/boringssl/Android.bp |
|
||||||
done |
|
||||||
elif [ "x$2" = "xrun" ]; then |
|
||||||
printf "\\x1b[1mTesting\\x1b[0m\n" |
|
||||||
for test in $TESTS; do |
|
||||||
dir=test-${bits}-${test} |
|
||||||
if [ ! '(' -d ${dir} -a -f ${dir}/test_fips -a -f ${dir}/libcrypto.so ')' ] ; then |
|
||||||
echo "Build directory ${dir} is missing or is missing files" |
|
||||||
exit 1 |
|
||||||
fi |
|
||||||
adb push ${dir}/* /data/local/tmp |
|
||||||
printf "\\x1b[1mTesting ${test}\\x1b[0m\n" |
|
||||||
adb shell -n -t -x LD_LIBRARY_PATH=/data/local/tmp /data/local/tmp/test_fips |
|
||||||
read |
|
||||||
done |
|
||||||
|
|
||||||
printf "\\x1b[1mTesting integrity}\\x1b[0m\n" |
|
||||||
src=test-${bits}-NONE |
|
||||||
dir=test-${bits}-INT |
|
||||||
rm -Rf $dir |
|
||||||
mkdir $dir |
|
||||||
go run external/boringssl/src/util/fipstools/break-hash.go ${src}/libcrypto.so ${dir}/libcrypto.so |
|
||||||
cp ${src}/test_fips $dir |
|
||||||
adb push ${dir}/* /data/local/tmp |
|
||||||
adb shell -n -t -x LD_LIBRARY_PATH=/data/local/tmp /data/local/tmp/test_fips |
|
||||||
read |
|
||||||
else |
|
||||||
echo "Second argument must be build or run" |
|
||||||
exit 1 |
|
||||||
fi |
|
@ -1,53 +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. */ |
|
||||||
|
|
||||||
# This script exists to exercise breaking each of the FIPS tests. It builds |
|
||||||
# BoringSSL differently for each test and that can take a long time. Thus it's |
|
||||||
# run twice: once, from a BoringSSL source tree, with "build" as the sole |
|
||||||
# argument to run the builds, and then (from the same location) with no |
|
||||||
# arguments to run each script. |
|
||||||
# |
|
||||||
# Run it with /bin/bash, not /bin/sh, otherwise "read" may fail. |
|
||||||
|
|
||||||
set -x |
|
||||||
|
|
||||||
TESTS="NONE ECDSA_PWCT CRNG RSA_PWCT AES_CBC AES_GCM DES SHA_1 SHA_256 SHA_512 HMAC_SHA_256 RSA_SIG DRBG ECDSA_SIG Z_COMPUTATION TLS_KDF FFC_DH" |
|
||||||
|
|
||||||
if [ "x$1" = "xbuild" ]; then |
|
||||||
for test in $TESTS; do |
|
||||||
rm -Rf build-$test |
|
||||||
mkdir build-$test |
|
||||||
pushd build-$test |
|
||||||
cmake -GNinja -DCMAKE_TOOLCHAIN_FILE=${HOME}/toolchain -DFIPS=1 -DFIPS_BREAK_TEST=${test} -DCMAKE_BUILD_TYPE=Release .. |
|
||||||
ninja test_fips |
|
||||||
popd |
|
||||||
done |
|
||||||
|
|
||||||
exit 0 |
|
||||||
fi |
|
||||||
|
|
||||||
for test in $TESTS; do |
|
||||||
pushd build-$test |
|
||||||
printf "\n\n\\x1b[1m$test\\x1b[0m\n" |
|
||||||
./util/fipstools/cavp/test_fips |
|
||||||
echo "Waiting for keypress..." |
|
||||||
read |
|
||||||
popd |
|
||||||
done |
|
||||||
|
|
||||||
pushd build-NONE |
|
||||||
printf "\\x1b[1mIntegrity\\x1b[0m\n" |
|
||||||
go run ../util/fipstools/break-hash.go ./util/fipstools/cavp/test_fips ./util/fipstools/cavp/test_fips_broken |
|
||||||
./util/fipstools/cavp/test_fips_broken |
|
||||||
popd |
|
@ -0,0 +1,40 @@ |
|||||||
|
# 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 attempts to break each of the known KATs and checks that doing so |
||||||
|
# seems to work and at least mentions the correct KAT in the output. |
||||||
|
|
||||||
|
set -x |
||||||
|
set -e |
||||||
|
|
||||||
|
TEST_FIPS_BIN="build/util/fipstools/cavp/test_fips" |
||||||
|
|
||||||
|
if [ ! -f $TEST_FIPS_BIN ]; then |
||||||
|
echo "$TEST_FIPS_BIN is missing. Run this script from the top level of a" |
||||||
|
echo "BoringSSL checkout and ensure that ./build-fips-break-test-binaries.sh" |
||||||
|
echo "has been run first." |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
|
||||||
|
KATS=$(go run util/fipstools/break-kat.go --list-tests) |
||||||
|
|
||||||
|
for kat in $KATS; do |
||||||
|
go run util/fipstools/break-kat.go $TEST_FIPS_BIN $kat > break-kat-bin |
||||||
|
chmod u+x ./break-kat-bin |
||||||
|
if ! (./break-kat-bin 2>&1 || true) | egrep -q "^$kat[^a-zA-Z0-9]"; then |
||||||
|
echo "Failure for $kat did not mention that name in the output" |
||||||
|
exit 1 |
||||||
|
fi |
||||||
|
rm ./break-kat-bin |
||||||
|
done |
Loading…
Reference in new issue