diff --git a/api/s2n.h b/api/s2n.h index 6bce51c0342..f96008fb4ed 100644 --- a/api/s2n.h +++ b/api/s2n.h @@ -241,6 +241,22 @@ S2N_API extern int s2n_init(void); */ S2N_API extern int s2n_cleanup(void); +/** + * Determines whether s2n-tls is in FIPS mode. + * + * s2n-tls enters FIPS mode on initialization when the linked libcrypto has FIPS mode enabled. Some + * libcryptos, such as AWS-LC-FIPS, have FIPS mode enabled by default. With other libcryptos, such + * as OpenSSL, FIPS mode must be enabled before initialization by calling `FIPS_mode_set()`. + * + * s2n-tls MUST be linked to a FIPS libcrypto and MUST be in FIPS mode in order to comply with FIPS + * requirements. Applications desiring FIPS compliance should use this API to ensure that s2n-tls + * has been properly linked with a FIPS libcrypto and has successfully entered FIPS mode. + * + * @param fips_mode Set to true if s2n-tls is in FIPS mode, set to false otherwise. + * @returns S2N_SUCCESS on success. S2N_FAILURE on failure. + */ +S2N_API extern int s2n_get_fips_mode(bool *fips_mode); + /** * Creates a new s2n_config object. This object can (and should) be associated with many connection * objects. diff --git a/crypto/s2n_fips.c b/crypto/s2n_fips.c index 29229dd607d..53ce8b80f77 100644 --- a/crypto/s2n_fips.c +++ b/crypto/s2n_fips.c @@ -17,6 +17,9 @@ #include +#include "utils/s2n_init.h" +#include "utils/s2n_safety.h" + #if defined(S2N_INTERN_LIBCRYPTO) && defined(OPENSSL_FIPS) #error "Interning with OpenSSL fips-validated libcrypto is not currently supported. See https://github.com/aws/s2n-tls/issues/2741" #endif @@ -60,3 +63,16 @@ int s2n_is_in_fips_mode(void) { return s2n_fips_mode; } + +int s2n_get_fips_mode(bool *fips_mode) +{ + POSIX_ENSURE_REF(fips_mode); + *fips_mode = false; + POSIX_ENSURE(s2n_is_initialized(), S2N_ERR_NOT_INITIALIZED); + + if (s2n_is_in_fips_mode()) { + *fips_mode = true; + } + + return S2N_SUCCESS; +} diff --git a/tests/unit/s2n_build_test.c b/tests/unit/s2n_build_test.c index 75195fe0d2a..42d4745383e 100644 --- a/tests/unit/s2n_build_test.c +++ b/tests/unit/s2n_build_test.c @@ -84,6 +84,18 @@ int main() END_TEST(); } + /* Ensure that FIPS mode is enabled when linked to AWS-LC-FIPS, and disabled when linked to AWS-LC */ + if (strstr(s2n_libcrypto, "awslc") != NULL) { + bool fips_mode = false; + EXPECT_SUCCESS(s2n_get_fips_mode(&fips_mode)); + + if (strstr(s2n_libcrypto, "fips") != NULL) { + EXPECT_TRUE(fips_mode); + } else { + EXPECT_FALSE(fips_mode); + } + } + char s2n_libcrypto_copy[MAX_LIBCRYPTO_NAME_LEN] = { 0 }; EXPECT_TRUE(strlen(s2n_libcrypto) < MAX_LIBCRYPTO_NAME_LEN); EXPECT_OK(s2n_test_lowercase_copy(s2n_libcrypto, &s2n_libcrypto_copy[0], s2n_array_len(s2n_libcrypto_copy))); diff --git a/tests/unit/s2n_fips_mode_test.c b/tests/unit/s2n_fips_mode_test.c new file mode 100644 index 00000000000..da958ef9849 --- /dev/null +++ b/tests/unit/s2n_fips_mode_test.c @@ -0,0 +1,47 @@ +/* +* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"). +* You may not use this file except in compliance with the License. +* A copy of the License is located at +* +* http://aws.amazon.com/apache2.0 +* +* or in the "license" file accompanying this file. This file 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. +*/ + +#include "api/s2n.h" +#include "crypto/s2n_fips.h" +#include "s2n_test.h" + +int main() +{ + BEGIN_TEST_NO_INIT(); + + /* s2n_get_fips_mode() fails before initialization */ + { + bool fips_mode = true; + EXPECT_FAILURE_WITH_ERRNO(s2n_get_fips_mode(&fips_mode), S2N_ERR_NOT_INITIALIZED); + EXPECT_FALSE(fips_mode); + } + + EXPECT_SUCCESS(s2n_init()); + + /* Test s2n_get_fips_mode() after init */ + { + /* Safety */ + EXPECT_FAILURE_WITH_ERRNO(s2n_get_fips_mode(NULL), S2N_ERR_NULL); + + /* FIPS mode matches s2n_is_in_fips_mode() */ + { + bool fips_mode = false; + EXPECT_SUCCESS(s2n_get_fips_mode(&fips_mode)); + EXPECT_EQUAL(fips_mode, s2n_is_in_fips_mode()); + } + } + + END_TEST(); +}