Skip to content
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

feat: Add FIPS mode getter API #4450

Merged
merged 6 commits into from
Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
21 changes: 21 additions & 0 deletions api/s2n.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,27 @@ 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 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
* 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 the FIPS mode of s2n-tls.
* @returns S2N_SUCCESS on success. S2N_FAILURE on failure.
*/
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
* objects.
Expand Down
31 changes: 21 additions & 10 deletions crypto/s2n_fips.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@

#include <openssl/crypto.h>

#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

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.
*
Expand All @@ -46,17 +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)
bool s2n_is_in_fips_mode(void)
{
return s2n_fips_mode_enabled;
}

int s2n_get_fips_mode(s2n_fips_mode *fips_mode)
{
return s2n_fips_mode;
POSIX_ENSURE_REF(fips_mode);
*fips_mode = S2N_FIPS_MODE_DISABLED;
POSIX_ENSURE(s2n_is_initialized(), S2N_ERR_NOT_INITIALIZED);

if (s2n_is_in_fips_mode()) {
*fips_mode = S2N_FIPS_MODE_ENABLED;
}

return S2N_SUCCESS;
}
2 changes: 1 addition & 1 deletion crypto/s2n_fips.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
12 changes: 6 additions & 6 deletions tests/cbmc/stubs/s2n_is_in_fips_mode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
12 changes: 12 additions & 0 deletions tests/unit/s2n_build_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
s2n_fips_mode fips_mode = S2N_FIPS_MODE_DISABLED;
EXPECT_SUCCESS(s2n_get_fips_mode(&fips_mode));

if (strstr(s2n_libcrypto, "fips") != NULL) {
EXPECT_EQUAL(fips_mode, S2N_FIPS_MODE_ENABLED);
} else {
EXPECT_EQUAL(fips_mode, S2N_FIPS_MODE_DISABLED);
}
}

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)));
Expand Down
53 changes: 53 additions & 0 deletions tests/unit/s2n_fips_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* 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 "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_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_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() */
{
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);
}
}
}

END_TEST();
}
Loading