From 33b38be8cb3951a5b5a9c4fb59060271f4883c3c Mon Sep 17 00:00:00 2001 From: Sam Clark <3758302+goatgoose@users.noreply.github.com> Date: Tue, 5 Mar 2024 17:34:43 -0500 Subject: [PATCH 1/5] feat: Add FIPS mode getter API --- api/s2n.h | 16 +++++++++++ crypto/s2n_fips.c | 16 +++++++++++ tests/unit/s2n_build_test.c | 12 +++++++++ tests/unit/s2n_fips_mode_test.c | 47 +++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+) create mode 100644 tests/unit/s2n_fips_mode_test.c 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..db3e584f073 --- /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 init */ + { + 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(); +} From ed064328a2484970408c7959852e1ded33ea02e4 Mon Sep 17 00:00:00 2001 From: Sam Clark <3758302+goatgoose@users.noreply.github.com> Date: Mon, 11 Mar 2024 15:43:21 -0400 Subject: [PATCH 2/5] s2n_is_fips --- api/s2n.h | 4 ++-- crypto/s2n_fips.c | 8 +++---- tests/unit/s2n_build_test.c | 8 +++---- .../{s2n_fips_mode_test.c => s2n_fips_test.c} | 23 ++++++++++--------- 4 files changed, 22 insertions(+), 21 deletions(-) rename tests/unit/{s2n_fips_mode_test.c => s2n_fips_test.c} (59%) diff --git a/api/s2n.h b/api/s2n.h index f96008fb4ed..cf0e1ef1089 100644 --- a/api/s2n.h +++ b/api/s2n.h @@ -252,10 +252,10 @@ S2N_API extern int s2n_cleanup(void); * 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. + * @param fips 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); +S2N_API extern int s2n_is_fips(bool *fips); /** * Creates a new s2n_config object. This object can (and should) be associated with many connection diff --git a/crypto/s2n_fips.c b/crypto/s2n_fips.c index 53ce8b80f77..459e47e02a3 100644 --- a/crypto/s2n_fips.c +++ b/crypto/s2n_fips.c @@ -64,14 +64,14 @@ int s2n_is_in_fips_mode(void) return s2n_fips_mode; } -int s2n_get_fips_mode(bool *fips_mode) +int s2n_is_fips(bool *fips) { - POSIX_ENSURE_REF(fips_mode); - *fips_mode = false; + POSIX_ENSURE_REF(fips); + *fips = false; POSIX_ENSURE(s2n_is_initialized(), S2N_ERR_NOT_INITIALIZED); if (s2n_is_in_fips_mode()) { - *fips_mode = true; + *fips = true; } return S2N_SUCCESS; diff --git a/tests/unit/s2n_build_test.c b/tests/unit/s2n_build_test.c index 42d4745383e..fb5af8505d0 100644 --- a/tests/unit/s2n_build_test.c +++ b/tests/unit/s2n_build_test.c @@ -86,13 +86,13 @@ int main() /* 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)); + bool fips = false; + EXPECT_SUCCESS(s2n_is_fips(&fips)); if (strstr(s2n_libcrypto, "fips") != NULL) { - EXPECT_TRUE(fips_mode); + EXPECT_TRUE(fips); } else { - EXPECT_FALSE(fips_mode); + EXPECT_FALSE(fips); } } diff --git a/tests/unit/s2n_fips_mode_test.c b/tests/unit/s2n_fips_test.c similarity index 59% rename from tests/unit/s2n_fips_mode_test.c rename to tests/unit/s2n_fips_test.c index db3e584f073..4e964ef0cf0 100644 --- a/tests/unit/s2n_fips_mode_test.c +++ b/tests/unit/s2n_fips_test.c @@ -13,33 +13,34 @@ * permissions and limitations under the License. */ -#include "api/s2n.h" #include "crypto/s2n_fips.h" + +#include "api/s2n.h" #include "s2n_test.h" int main() { BEGIN_TEST_NO_INIT(); - /* s2n_get_fips_mode() fails before init */ + /* s2n_is_fips() fails before init */ { - bool fips_mode = true; - EXPECT_FAILURE_WITH_ERRNO(s2n_get_fips_mode(&fips_mode), S2N_ERR_NOT_INITIALIZED); - EXPECT_FALSE(fips_mode); + bool fips = true; + EXPECT_FAILURE_WITH_ERRNO(s2n_is_fips(&fips), S2N_ERR_NOT_INITIALIZED); + EXPECT_FALSE(fips); } EXPECT_SUCCESS(s2n_init()); - /* Test s2n_get_fips_mode() after init */ + /* Test s2n_is_fips() after init */ { /* Safety */ - EXPECT_FAILURE_WITH_ERRNO(s2n_get_fips_mode(NULL), S2N_ERR_NULL); + EXPECT_FAILURE_WITH_ERRNO(s2n_is_fips(NULL), S2N_ERR_NULL); - /* FIPS mode matches s2n_is_in_fips_mode() */ + /* FIPS value 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()); + bool fips = false; + EXPECT_SUCCESS(s2n_is_fips(&fips)); + EXPECT_EQUAL(fips, s2n_is_in_fips_mode()); } } From 1b3bcb89e97e6055da77f3349a8661f756bfdc6f Mon Sep 17 00:00:00 2001 From: Sam Clark <3758302+goatgoose@users.noreply.github.com> Date: Tue, 12 Mar 2024 20:28:46 -0400 Subject: [PATCH 3/5] pr feedback --- crypto/s2n_fips.c | 7 +------ tests/unit/s2n_fips_test.c | 3 +-- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/crypto/s2n_fips.c b/crypto/s2n_fips.c index 459e47e02a3..f8d09932c00 100644 --- a/crypto/s2n_fips.c +++ b/crypto/s2n_fips.c @@ -67,12 +67,7 @@ int s2n_is_in_fips_mode(void) int s2n_is_fips(bool *fips) { POSIX_ENSURE_REF(fips); - *fips = false; POSIX_ENSURE(s2n_is_initialized(), S2N_ERR_NOT_INITIALIZED); - - if (s2n_is_in_fips_mode()) { - *fips = true; - } - + *fips = s2n_is_in_fips_mode(); return S2N_SUCCESS; } diff --git a/tests/unit/s2n_fips_test.c b/tests/unit/s2n_fips_test.c index 4e964ef0cf0..d46540b25dd 100644 --- a/tests/unit/s2n_fips_test.c +++ b/tests/unit/s2n_fips_test.c @@ -24,9 +24,8 @@ int main() /* s2n_is_fips() fails before init */ { - bool fips = true; + bool fips = false; EXPECT_FAILURE_WITH_ERRNO(s2n_is_fips(&fips), S2N_ERR_NOT_INITIALIZED); - EXPECT_FALSE(fips); } EXPECT_SUCCESS(s2n_init()); From 44e721f51ebdce20c6b819a0af59431ed26f6114 Mon Sep 17 00:00:00 2001 From: Sam Clark <3758302+goatgoose@users.noreply.github.com> Date: Thu, 14 Mar 2024 10:58:28 -0400 Subject: [PATCH 4/5] enum argument --- api/s2n.h | 11 ++++++++--- crypto/s2n_fips.c | 24 ++++++++++++------------ tests/unit/s2n_build_test.c | 8 ++++---- tests/unit/s2n_fips_test.c | 24 +++++++++++++++--------- 4 files changed, 39 insertions(+), 28 deletions(-) diff --git a/api/s2n.h b/api/s2n.h index cf0e1ef1089..53257fa0659 100644 --- a/api/s2n.h +++ b/api/s2n.h @@ -241,8 +241,13 @@ S2N_API extern int s2n_init(void); */ S2N_API extern int s2n_cleanup(void); +typedef enum { + S2N_FIPS_MODE_DISABLED = 0, + S2N_FIPS_MODE_ENABLED, +} s2n_fips_mode; + /** - * Determines whether s2n-tls is in FIPS mode. + * Determines whether s2n-tls is operating 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 @@ -252,10 +257,10 @@ S2N_API extern int s2n_cleanup(void); * 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 Set to true if s2n-tls is in FIPS mode, set to false otherwise. + * @param fips_mode Set to the FIPS mode of s2n-tls. * @returns S2N_SUCCESS on success. S2N_FAILURE on failure. */ -S2N_API extern int s2n_is_fips(bool *fips); +S2N_API extern int s2n_get_fips_mode(s2n_fips_mode *fips_mode); /** * Creates a new s2n_config object. This object can (and should) be associated with many connection diff --git a/crypto/s2n_fips.c b/crypto/s2n_fips.c index f8d09932c00..2677c66434e 100644 --- a/crypto/s2n_fips.c +++ b/crypto/s2n_fips.c @@ -24,7 +24,7 @@ #error "Interning with OpenSSL fips-validated libcrypto is not currently supported. See https://github.com/aws/s2n-tls/issues/2741" #endif -static int s2n_fips_mode = 0; +static bool s2n_fips_mode_enabled = false; /* FIPS mode can be checked if OpenSSL was configured and built for FIPS which then defines OPENSSL_FIPS. * @@ -49,25 +49,25 @@ bool s2n_libcrypto_is_fips(void) int s2n_fips_init(void) { - s2n_fips_mode = 0; - - if (s2n_libcrypto_is_fips()) { - s2n_fips_mode = 1; - } - - return 0; + s2n_fips_mode_enabled = s2n_libcrypto_is_fips(); + return S2N_SUCCESS; } /* Return 1 if FIPS mode is enabled, 0 otherwise. FIPS mode must be enabled prior to calling s2n_init(). */ int s2n_is_in_fips_mode(void) { - return s2n_fips_mode; + return s2n_fips_mode_enabled; } -int s2n_is_fips(bool *fips) +int s2n_get_fips_mode(s2n_fips_mode *fips_mode) { - POSIX_ENSURE_REF(fips); + POSIX_ENSURE_REF(fips_mode); + *fips_mode = S2N_FIPS_MODE_DISABLED; POSIX_ENSURE(s2n_is_initialized(), S2N_ERR_NOT_INITIALIZED); - *fips = s2n_is_in_fips_mode(); + + if (s2n_is_in_fips_mode()) { + *fips_mode = S2N_FIPS_MODE_ENABLED; + } + return S2N_SUCCESS; } diff --git a/tests/unit/s2n_build_test.c b/tests/unit/s2n_build_test.c index fb5af8505d0..e7f40949d15 100644 --- a/tests/unit/s2n_build_test.c +++ b/tests/unit/s2n_build_test.c @@ -86,13 +86,13 @@ int main() /* 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 = false; - EXPECT_SUCCESS(s2n_is_fips(&fips)); + s2n_fips_mode fips_mode = S2N_FIPS_MODE_DISABLED; + EXPECT_SUCCESS(s2n_get_fips_mode(&fips_mode)); if (strstr(s2n_libcrypto, "fips") != NULL) { - EXPECT_TRUE(fips); + EXPECT_EQUAL(fips_mode, S2N_FIPS_MODE_ENABLED); } else { - EXPECT_FALSE(fips); + EXPECT_EQUAL(fips_mode, S2N_FIPS_MODE_DISABLED); } } diff --git a/tests/unit/s2n_fips_test.c b/tests/unit/s2n_fips_test.c index d46540b25dd..c4e5bdc134e 100644 --- a/tests/unit/s2n_fips_test.c +++ b/tests/unit/s2n_fips_test.c @@ -22,24 +22,30 @@ int main() { BEGIN_TEST_NO_INIT(); - /* s2n_is_fips() fails before init */ + /* s2n_get_fips_mode() fails before init */ { - bool fips = false; - EXPECT_FAILURE_WITH_ERRNO(s2n_is_fips(&fips), S2N_ERR_NOT_INITIALIZED); + s2n_fips_mode fips_mode = S2N_FIPS_MODE_ENABLED; + EXPECT_FAILURE_WITH_ERRNO(s2n_get_fips_mode(&fips_mode), S2N_ERR_NOT_INITIALIZED); + EXPECT_EQUAL(fips_mode, S2N_FIPS_MODE_DISABLED); } EXPECT_SUCCESS(s2n_init()); - /* Test s2n_is_fips() after init */ + /* Test s2n_get_fips_mode() after init */ { /* Safety */ - EXPECT_FAILURE_WITH_ERRNO(s2n_is_fips(NULL), S2N_ERR_NULL); + EXPECT_FAILURE_WITH_ERRNO(s2n_get_fips_mode(NULL), S2N_ERR_NULL); - /* FIPS value matches s2n_is_in_fips_mode() */ + /* FIPS mode matches s2n_is_in_fips_mode() */ { - bool fips = false; - EXPECT_SUCCESS(s2n_is_fips(&fips)); - EXPECT_EQUAL(fips, s2n_is_in_fips_mode()); + s2n_fips_mode fips_mode = S2N_FIPS_MODE_DISABLED; + EXPECT_SUCCESS(s2n_get_fips_mode(&fips_mode)); + + if (s2n_is_in_fips_mode()) { + EXPECT_EQUAL(fips_mode, S2N_FIPS_MODE_ENABLED); + } else { + EXPECT_EQUAL(fips_mode, S2N_FIPS_MODE_DISABLED); + } } } From a7e2bbc27305e9dd9f6d249ab337162e25cc40e1 Mon Sep 17 00:00:00 2001 From: Sam Clark <3758302+goatgoose@users.noreply.github.com> Date: Thu, 14 Mar 2024 11:21:37 -0400 Subject: [PATCH 5/5] fix cbmc --- crypto/s2n_fips.c | 2 +- crypto/s2n_fips.h | 2 +- tests/cbmc/stubs/s2n_is_in_fips_mode.c | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/crypto/s2n_fips.c b/crypto/s2n_fips.c index 2677c66434e..ff73433a6ce 100644 --- a/crypto/s2n_fips.c +++ b/crypto/s2n_fips.c @@ -54,7 +54,7 @@ int s2n_fips_init(void) } /* Return 1 if FIPS mode is enabled, 0 otherwise. FIPS mode must be enabled prior to calling s2n_init(). */ -int s2n_is_in_fips_mode(void) +bool s2n_is_in_fips_mode(void) { return s2n_fips_mode_enabled; } diff --git a/crypto/s2n_fips.h b/crypto/s2n_fips.h index f1047d52ae6..a353589199d 100644 --- a/crypto/s2n_fips.h +++ b/crypto/s2n_fips.h @@ -21,7 +21,7 @@ #pragma once int s2n_fips_init(void); -int s2n_is_in_fips_mode(void); +bool s2n_is_in_fips_mode(void); bool s2n_libcrypto_is_fips(void); struct s2n_cipher_suite; diff --git a/tests/cbmc/stubs/s2n_is_in_fips_mode.c b/tests/cbmc/stubs/s2n_is_in_fips_mode.c index 8a76d11bc6d..7ee61b05510 100644 --- a/tests/cbmc/stubs/s2n_is_in_fips_mode.c +++ b/tests/cbmc/stubs/s2n_is_in_fips_mode.c @@ -17,18 +17,18 @@ #include "crypto/s2n_fips.h" -static int flag = 0; -static int s2n_fips_mode = 0; +static bool flag = 0; +static bool s2n_fips_mode_enabled = 0; /** * Return 1 if FIPS mode is set, 0 otherwise, * where FIPS mode is set nondeterministically on first call. */ -int s2n_is_in_fips_mode() +bool s2n_is_in_fips_mode() { if (flag == 0) { - s2n_fips_mode = nondet_bool() ? 1 : 0; - flag = 1; + s2n_fips_mode_enabled = nondet_bool() ? 1 : 0; + flag = 1; } - return s2n_fips_mode; + return s2n_fips_mode_enabled; }