Skip to content

Add build option for exposing self-test failure messages #433

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

Merged
merged 48 commits into from
Mar 7, 2025
Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
71882bc
Break self tests by modifying AWS-LC
amirhosv Mar 31, 2023
d1a075a
Provide isFipsStatusOk to check if FIPS tests have passed or not
amirhosv Apr 14, 2023
d16e616
Updating fips-experimentation branch with main (#294)
amirhosv May 8, 2023
f274433
Revert "Only register LibCryptoRng by default in non-FIPS mode"
WillChilds-Klein May 19, 2023
e006dee
Use FIPS approved APIs to generate RSA key pairs (#301)
amirhosv May 24, 2023
355b0dd
Merge branch 'main' into fips-experimentation
WillChilds-Klein Feb 3, 2025
893b388
Fix spotless
WillChilds-Klein Feb 3, 2025
6c7d677
Remove obsolete MacOS CI jobs
WillChilds-Klein Feb 3, 2025
7c3672a
Merge branch 'fips-experimentation'
WillChilds-Klein Feb 17, 2025
9bb0c6d
Clean up merge
WillChilds-Klein Feb 17, 2025
9a05c8e
Merge remote-tracking branch 'aws/main' into self-test-failure
WillChilds-Klein Feb 17, 2025
9be07aa
Add getFipsStatusError method + JNI helpers
WillChilds-Klein Feb 17, 2025
72a0568
Cross-thread access caused JVM heap issues, use native error queue
WillChilds-Klein Feb 17, 2025
427ee31
Duct tape for the temp AWS-LC dep hack
WillChilds-Klein Feb 17, 2025
0323a8d
Execute FipsStatusTest on main test thread
WillChilds-Klein Feb 18, 2025
0c5e4b5
Add explanatory note for ibid.
WillChilds-Klein Feb 18, 2025
0cdac70
Update AWS-LC version
WillChilds-Klein Mar 2, 2025
50c61fe
Merge remote-tracking branch 'aws/main' into self-test-failure
WillChilds-Klein Mar 2, 2025
d536459
Temporarily skip ML-DSA tests
WillChilds-Klein Mar 2, 2025
599d1ae
Appease spotless
WillChilds-Klein Mar 2, 2025
10187b1
Remove break-tests example
WillChilds-Klein Mar 2, 2025
5183a70
Update README and CHANGELOG
WillChilds-Klein Mar 2, 2025
f1e2e62
Put callback stuff behind ACCP build flag
WillChilds-Klein Mar 2, 2025
2a40997
Appease spotless, check isFipsSelfTestFailureNoAbort in getInstance
WillChilds-Klein Mar 2, 2025
d2b5953
Update relevant test scripts tests/ci/run_accp_* t handle new flag
WillChilds-Klein Mar 2, 2025
ea7c873
Specify ALLOW_FIPS_TEST_BREAK in CI test scripts
WillChilds-Klein Mar 3, 2025
62ef27f
Fix AWS-LC callback build flag plumbing, test PWCT breakage
WillChilds-Klein Mar 4, 2025
b5b19a8
Rename NoAbort to SkipAbort
WillChilds-Klein Mar 4, 2025
78a3b44
Small TODO cleanups
WillChilds-Klein Mar 4, 2025
ce894e3
Merge remote-tracking branch 'aws/main' into self-test-failure
WillChilds-Klein Mar 4, 2025
13c9f3c
Rewrite string vec with pthread rwlock
WillChilds-Klein Mar 5, 2025
946b4e2
Call abort() in default AWS_LC_fips_failure_callback
WillChilds-Klein Mar 5, 2025
923ae48
Guard ML-DSA PWCT test with exp fips
WillChilds-Klein Mar 5, 2025
b7801e7
Appease spotless
WillChilds-Klein Mar 5, 2025
1971c8b
Iterate the old fashioned way, GCC 4.1 doesnt like range
WillChilds-Klein Mar 5, 2025
9a85112
Comment and documentation fix-ups
WillChilds-Klein Mar 5, 2025
10503bd
PR feedback
WillChilds-Klein Mar 6, 2025
1129dc3
Include vector header in fips_status.cpp
WillChilds-Klein Mar 6, 2025
4caf24b
Fix vector ctor call
WillChilds-Klein Mar 6, 2025
f3c1fd5
Disable EdDSA PWCT, block until self-tests finish
WillChilds-Klein Mar 7, 2025
b34faca
Remove self test status check from isFipsStatusOk()
WillChilds-Klein Mar 7, 2025
25eac43
Fix non-FIPS
WillChilds-Klein Mar 7, 2025
ef0ed12
Appease spotless
WillChilds-Klein Mar 7, 2025
6d9a71a
Busy poll self test status in isFipsStatusOk
WillChilds-Klein Mar 7, 2025
aedf5be
Fix conflict
WillChilds-Klein Mar 7, 2025
ad531ff
Appease spotless
WillChilds-Klein Mar 7, 2025
ffd6bc7
Add back Ed25519 PWCT tests with temporary guards
WillChilds-Klein Mar 7, 2025
4ce2164
Throw RuntimeCryptoException on self-test timeout
WillChilds-Klein Mar 7, 2025
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## 2.6.0

### Minor
* [PR 433:](https://github.com/corretto/amazon-corretto-crypto-provider/pull/433) Add build option for exposing self-test failure messages

## 2.5.0

### Minor
Expand Down
25 changes: 22 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ set(TEST_DATA_DIR ${PROJECT_SOURCE_DIR}/test-data/ CACHE STRING "Path to directo
set(ORIG_SRCROOT ${PROJECT_SOURCE_DIR} CACHE STRING "Path to root of original package")
set(PROVIDER_VERSION_STRING "" CACHE STRING "X.Y.Z formatted version of the provider")
set(EXPERIMENTAL_FIPS NO CACHE BOOL "Determines if this build is for FIPS mode with extra features from a non-FIPS branch of AWS-LC.")
set(FIPS_SELF_TEST_SKIP_ABORT NO CACHE BOOL "Determines whether ACCP throws exceptions on self-test failure, or AWS-LC aborts. If NO, AWS-LC aborts. If YES, ACCP will provide error messages.")
set(FIPS NO CACHE BOOL "Determine if this build is for FIPS mode")
set(ALWAYS_ALLOW_EXTERNAL_LIB NO CACHE BOOL "Always permit tests to load ACCP shared objects from the library path")
set(AWS_LC_VERSION_STRING "" CACHE STRING "Git version of AWS-LC used in this build")
Expand All @@ -51,6 +52,10 @@ if (EXPERIMENTAL_FIPS)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEXPERIMENTAL_FIPS_BUILD")
endif()

if (FIPS_SELF_TEST_SKIP_ABORT)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DFIPS_SELF_TEST_SKIP_ABORT")
endif()

if (USE_CLANG_TIDY)
# https://releases.llvm.org/9.0.0/tools/clang/tools/extra/docs/clang-tidy/checks/list.html
# https://clang.llvm.org/extra/clang-tidy/#suppressing-undesired-diagnostics
Expand Down Expand Up @@ -294,6 +299,7 @@ set(C_SRC
csrc/util.cpp
csrc/util_class.cpp
csrc/fips_kat_self_test.cpp
csrc/fips_status.cpp
${JNI_HEADER_DIR}/generated-headers.h)

if(FIPS)
Expand Down Expand Up @@ -504,7 +510,7 @@ if(NOT ENABLE_NATIVE_TEST_HOOKS)
CHECK_LINKER_FLAG_SUPPORT(USE_VERSION_SCRIPT "-Wl,--version-script -Wl,${CMAKE_CURRENT_SOURCE_DIR}/final-link.version")

# This does the same thing as the version script, but works on Darwin platforms
CHECK_LINKER_FLAG_SUPPORT(USE_EXPORTED_SYMBOL "-Wl,-exported_symbol '-Wl,_Java_*' -Wl,-exported_symbol '-Wl,_JNI_*'")
CHECK_LINKER_FLAG_SUPPORT(USE_EXPORTED_SYMBOL "-Wl,-exported_symbol '-Wl,_Java_*' '-Wl,_AWS_LC_fips_failure_callback' -Wl,-exported_symbol '-Wl,_JNI_*'")
endif()

# Attempt to drop unused sections; the idea here is to exclude unreferenced
Expand Down Expand Up @@ -681,6 +687,7 @@ add_custom_target(check-junit
--select-package=com.amazon.corretto.crypto.provider.test
--exclude-package=com.amazon.corretto.crypto.provider.test.integration
--exclude-classname=com.amazon.corretto.crypto.provider.test.SecurityManagerTest
--exclude-classname=com.amazon.corretto.crypto.provider.test.FipsStatusTest

DEPENDS accp-jar tests-jar)

Expand All @@ -702,6 +709,15 @@ add_custom_target(check-junit-SecurityManager

DEPENDS accp-jar tests-jar)

add_custom_target(check-junit-FipsStatus
COMMAND ${TEST_JAVA_EXECUTABLE}
${TEST_RUNNER_ARGUMENTS}
--select-class=com.amazon.corretto.crypto.provider.test.AesTest # Force loading ciphers
--select-class=com.amazon.corretto.crypto.provider.test.SHA1Test # Force loading digests
--select-class=com.amazon.corretto.crypto.provider.test.FipsStatusTest

DEPENDS accp-jar tests-jar)

add_custom_target(check-with-jni-flag
COMMAND ${TEST_JAVA_EXECUTABLE}
-Xcheck:jni
Expand Down Expand Up @@ -749,6 +765,7 @@ add_custom_target(check-junit-extra-checks
${TEST_RUNNER_ARGUMENTS}
--select-package=com.amazon.corretto.crypto.provider.test
--exclude-package=com.amazon.corretto.crypto.provider.test.integration
--exclude-classname=com.amazon.corretto.crypto.provider.test.FipsStatusTest
--exclude-classname=com.amazon.corretto.crypto.provider.test.SecurityManagerTest

DEPENDS accp-jar tests-jar)
Expand Down Expand Up @@ -845,7 +862,8 @@ add_custom_target(check-junit-edKeyFactory

DEPENDS accp-jar tests-jar)

set(check_targets check-recursive-init
set(check_targets
check-recursive-init
check-install-via-properties
check-install-via-properties-with-debug
check-junit
Expand All @@ -854,7 +872,8 @@ set(check_targets check-recursive-init
check-junit-AesLazy
check-junit-AesEager
check-junit-DifferentTempDir
check-junit-edKeyFactory)
check-junit-edKeyFactory
check-junit-FipsStatus)

if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(check_targets ${check_targets} check-with-jni-flag)
Expand Down
26 changes: 24 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ if (System.properties["AWSLC_GITVERSION"]) {
}

ext.isLegacyBuild = Boolean.getBoolean('LEGACY_BUILD')
ext.allowFipsTestBreak = Boolean.getBoolean('ALLOW_FIPS_TEST_BREAK')
ext.isFipsSelfTestFailureSkipAbort = Boolean.getBoolean('FIPS_SELF_TEST_SKIP_ABORT')

if (allowFipsTestBreak && !isFips) {
throw new GradleException("ALLOW_FIPS_TEST_BREAK can only be set if FIPS is also set to true")
}

if (isFipsSelfTestFailureSkipAbort && !isFips) {
throw new GradleException("FIPS_SELF_TEST_SKIP_ABORT can only be set if FIPS is also set to true")
}

ext.lcovIgnore = System.properties['LCOV_IGNORE']
if (ext.lcovIgnore == null) {
Expand Down Expand Up @@ -253,9 +263,20 @@ task buildAwsLc {


if (isFips) {
println "Building AWS-LC in FIPS mode"
args '-DFIPS=1'
}

if (allowFipsTestBreak) {
println "Building AWS-LC with hooks to break FIPS tests"
args '-DFIPS_BREAK_TEST='
}

if (isFipsSelfTestFailureSkipAbort) {
println "Building AWS-LC to call callback instead of aborting on self-test failure"
args '-DCMAKE_C_FLAGS="-DAWSLC_FIPS_FAILURE_CALLBACK"'
}

args '.'
}
}
Expand Down Expand Up @@ -342,6 +363,9 @@ task executeCmake(type: Exec) {
if (isExperimentalFips) {
args '-DEXPERIMENTAL_FIPS=ON'
}
if (isFipsSelfTestFailureSkipAbort) {
args '-DFIPS_SELF_TEST_SKIP_ABORT=ON'
}

if (prebuiltJar != null) {
args '-DSIGNED_JAR=' + prebuiltJar
Expand Down Expand Up @@ -555,11 +579,9 @@ task coverage_cmake(type: Exec) {
if (isExperimentalFips) {
args '-DEXPERIMENTAL_FIPS=ON'
}

if (System.properties['JAVA_HOME'] != null) {
args '-DJAVA_HOME=' + System.properties['JAVA_HOME']
}

if (System.properties['SINGLE_TEST'] != null) {
args '-DSINGLE_TEST=' + System.properties['SINGLE_TEST']

Expand Down
86 changes: 86 additions & 0 deletions csrc/fips_status.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
#include <cstdio>
#include <functional>
#include <jni.h>
#include <vector>

#include "string_vector.h"

static AmazonCorrettoCryptoProvider::ConcurrentStringVector fipsStatusErrors(1024);

// To have this symbol exported, one needs to modify the final-link.version and the CMakeLists.txt
extern "C" void AWS_LC_fips_failure_callback(char const* message);

#if defined(FIPS_SELF_TEST_SKIP_ABORT)
void AWS_LC_fips_failure_callback(char const* message)
{
const size_t char_limit = 128;
if (strnlen(message, char_limit + 1) > char_limit) {
fprintf(stderr, "AWS_LC_fips_failure_callback invoked with message message exceeding %lu chars\n", char_limit);
return;
}
fprintf(stderr, "AWS_LC_fips_failure_callback invoked with message: '%s'\n", message);
fipsStatusErrors.push_back(message);
}
#else
void AWS_LC_fips_failure_callback(char const* message)
{
fprintf(stderr, "AWS_LC_fips_failure_callback invoked with message: '%s'\n", message);
abort();
}
#endif

extern "C" JNIEXPORT jobject JNICALL
Java_com_amazon_corretto_crypto_provider_AmazonCorrettoCryptoProvider_getFipsSelfTestFailuresInternal(
JNIEnv* env, jobject thisObj)
{
std::vector<std::string> errors = fipsStatusErrors.to_std();

// Construct a Java ArrayList, get a handle for the |add| method
jclass arrayListClass = env->FindClass("java/util/ArrayList");
if (arrayListClass == NULL) {
abort();
}
jmethodID constructor = env->GetMethodID(arrayListClass, "<init>", "()V");
if (constructor == NULL) {
abort();
}
jobject arrayList = env->NewObject(arrayListClass, constructor);
if (arrayList == NULL) {
abort();
}
jmethodID addMethod = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
if (addMethod == NULL) {
abort();
}

// Copy the errors over to |arrayList| and clean up temporary local reference
for (size_t i = 0; i < errors.size(); i++) {
jstring javaString = env->NewStringUTF(errors[i].c_str());
env->CallVoidMethod(arrayList, addMethod, javaString);
env->DeleteLocalRef(javaString);
}

return arrayList;
}

extern "C" JNIEXPORT int JNICALL
Java_com_amazon_corretto_crypto_provider_AmazonCorrettoCryptoProvider_fipsStatusErrorCount(JNIEnv* env, jobject thisObj)
{
return fipsStatusErrors.size();
}

// TEST methods below

extern "C" JNIEXPORT void JNICALL Java_com_amazon_corretto_crypto_provider_test_NativeTestHooks_resetFipsStatus(
JNIEnv*, jclass)
{
fipsStatusErrors.clear();
}

extern "C" JNIEXPORT void JNICALL
Java_com_amazon_corretto_crypto_provider_test_NativeTestHooks_callAwsLcFipsFailureCallback(JNIEnv*, jclass)
{
AWS_LC_fips_failure_callback("called by a test");
}
10 changes: 10 additions & 0 deletions csrc/loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ JNIEXPORT jboolean JNICALL Java_com_amazon_corretto_crypto_provider_Loader_isExp
#endif
}

JNIEXPORT jboolean JNICALL Java_com_amazon_corretto_crypto_provider_Loader_isFipsSelfTestFailureSkipAbort(
JNIEnv*, jclass)
{
#ifdef FIPS_SELF_TEST_SKIP_ABORT
return JNI_TRUE;
#else
return JNI_FALSE;
#endif
}

JNIEXPORT jstring JNICALL Java_com_amazon_corretto_crypto_provider_Loader_getNativeLibraryVersion(JNIEnv* pEnv, jclass)
{
try {
Expand Down
71 changes: 71 additions & 0 deletions csrc/string_vector.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
#ifndef STRING_VECTOR_H
#define STRING_VECTOR_H

#include "compiler.h"

#include <cstdio>
#include <cstdlib>
#include <deque>
#include <pthread.h>
#include <string>

namespace AmazonCorrettoCryptoProvider {

class ConcurrentStringVector {
private:
std::deque<std::string> vec;
const size_t limit;
mutable pthread_rwlock_t lock;

public:
ConcurrentStringVector(size_t limit)
: limit(limit)
{
pthread_rwlock_init(&lock, nullptr);
}

~ConcurrentStringVector() { pthread_rwlock_destroy(&lock); }

// Disable copy constructors
ConcurrentStringVector(const ConcurrentStringVector&);
ConcurrentStringVector& operator=(const ConcurrentStringVector&);

void push_back(const std::string& value)
{
pthread_rwlock_wrlock(&lock);
if (vec.size() >= limit) { // If we're at the limit, pop FIFO
vec.pop_front();
}
vec.push_back(std::string(value));
pthread_rwlock_unlock(&lock);
}

void clear()
{
pthread_rwlock_wrlock(&lock);
vec.clear();
pthread_rwlock_unlock(&lock);
}

size_t size() const
{
pthread_rwlock_rdlock(&lock);
size_t vec_size = vec.size();
pthread_rwlock_unlock(&lock);
return vec_size;
}

std::vector<std::string> to_std() const
{
pthread_rwlock_rdlock(&lock);
std::vector<std::string> out(vec.begin(), vec.end()); // Use copy constructor, no references
pthread_rwlock_unlock(&lock);
return out;
}
};

} // namespace AmazonCorrettoCryptoProvider

#endif // STRING_VECTOR_H
28 changes: 28 additions & 0 deletions csrc/test_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,32 @@ extern "C" JNIEXPORT jbyteArray JNICALL Java_com_amazon_corretto_crypto_provider
}
}

/*
* Class: com_amazon_corretto_crypto_provider_test_TestUtil
* Method: setEnv
* Signature: (Ljava/lang/String;Ljava/lang/String;)V
*/
extern "C" JNIEXPORT void JNICALL Java_com_amazon_corretto_crypto_provider_test_TestUtil_setEnv(
JNIEnv* pEnv, jclass, jstring nameJava, jstring valueJava)
{
int ret;
try {
raii_env env(pEnv);
const char* name = env->GetStringUTFChars(nameJava, 0);
if (valueJava == nullptr) {
ret = unsetenv(name);
} else {
const char* value = env->GetStringUTFChars(valueJava, 0);
ret = setenv(name, value, /*overwrite*/ 1);
env->ReleaseStringUTFChars(valueJava, value);
}
env->ReleaseStringUTFChars(nameJava, name);
if (ret != 0) { // non-zero indicates failure https://man7.org/linux/man-pages/man3/setenv.3.html
throw_java_ex(EX_RUNTIME_CRYPTO, "Error calling POSIX setenv or unsetenv");
}
} catch (java_ex& ex) {
ex.throw_to_java(pEnv);
}
}

} // namespace
1 change: 1 addition & 0 deletions final-link.version
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
global:
Java_*;
AWS_LC_fips_failure_callback;
JNI_*;
hook_*;
local:
Expand Down
1 change: 0 additions & 1 deletion src/com/amazon/corretto/crypto/provider/AesGcmSpi.java
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,6 @@ protected void engineInit(
final AlgorithmParameterSpec algorithmParameterSpec,
final SecureRandom secureRandom)
throws InvalidKeyException, InvalidAlgorithmParameterException {

final int opMode = checkOperation(jceOpMode);

final GCMParameterSpec spec = checkSpecAndTag(algorithmParameterSpec);
Expand Down
Loading