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: feature probe S2N_LIBCRYPTO_SUPPORTS_ENGINE #4878

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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: 14 additions & 7 deletions crypto/s2n_fips.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,24 @@

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.
/* FIPS mode can be checked if OpenSSL was configured and built for FIPS which
* then defines OPENSSL_FIPS.
*
* AWS-LC always defines FIPS_mode() that you can call and check what the library was built with. It does not define
* a public OPENSSL_FIPS/AWSLC_FIPS macro that we can (or need to) check here
* AWS-LC always defines FIPS_mode() that you can call and check what the
* library was built with. It does not define a public OPENSSL_FIPS/AWSLC_FIPS
* macro that we can (or need to) check here
*
* Safeguard with macro's, for example because Libressl dosn't define
* Safeguard with macro's, for example because Libressl doesn't define
* FIPS_mode() by default.
*
* Note: FIPS_mode() does not change the FIPS state of libcrypto. This only returns the current state. Applications
* using s2n must call FIPS_mode_set(1) prior to s2n_init.
* */
* Note: FIPS_mode() does not change the FIPS state of libcrypto. This only
* returns the current state. Applications using s2n must call FIPS_mode_set(1)
* prior to s2n_init.
*
* Note: Developers should use `s2n_is_in_fips_mode()` instead of calling this
* directly. `s2n_is_in_fips_mode()` returns libcrypto FIPS status at library
* initialization, ie. s2n_init().
*/
bool s2n_libcrypto_is_fips(void)
{
#if defined(OPENSSL_FIPS) || defined(OPENSSL_IS_AWSLC)
Expand Down
1 change: 0 additions & 1 deletion crypto/s2n_fips.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@

int s2n_fips_init(void);
bool s2n_is_in_fips_mode(void);
bool s2n_libcrypto_is_fips(void);

struct s2n_cipher_suite;
S2N_RESULT s2n_fips_validate_cipher_suite(const struct s2n_cipher_suite *cipher_suite, bool *valid);
Expand Down
25 changes: 21 additions & 4 deletions crypto/s2n_libcrypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,33 @@ static S2N_RESULT s2n_libcrypto_validate_expected_version_number(void)
}

/* s2n_libcrypto_is_*() encodes the libcrypto version used at build-time.
* Currently only captures AWS-LC and BoringSSL. When a libcrypto-dependent
* branch is required, we prefer these functions where possible to reduce
# #ifs and avoid potential bugs where the header containing the #define is not
* included.
*
* When a libcrypto-dependent branch is required, we prefer these functions
* where possible to reduce #ifs and avoid potential bugs where the header
* containing the #define is not included.
*/

#if defined(OPENSSL_IS_AWSLC) && defined(OPENSSL_IS_BORINGSSL)
#error "Both OPENSSL_IS_AWSLC and OPENSSL_IS_BORINGSSL are defined at the same time!"
#endif

/* Attempt to detect if the libcrypto is OpenSSL.
*
* Since, quite a few libcrypto (BoringSSL, AWSLC) implementations are ABI
* compatible forks of OpenSSL, detecting OpenSSL is done by checking the
* absence of other libcrypto variants.
*
* Note: This check needs to be updated if s2n-tls adds support for a new
* libcrypto.
*/
bool s2n_libcrypto_is_openssl()
{
bool is_other_libcrypto_variant =
s2n_libcrypto_is_boringssl() || s2n_libcrypto_is_libressl() || s2n_libcrypto_is_awslc();

return !is_other_libcrypto_variant;
}

bool s2n_libcrypto_is_awslc()
{
#if defined(OPENSSL_IS_AWSLC)
Expand Down
7 changes: 1 addition & 6 deletions crypto/s2n_openssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,7 @@
#define RESULT_EVP_CTX_INIT(ctx) EVP_CIPHER_CTX_init(ctx)
#endif

#if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_FIPS) && !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_AWSLC) && !defined(OPENSSL_NO_ENGINE)
#define S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND 1
#else
#define S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND 0
#endif

bool s2n_libcrypto_is_openssl();
bool s2n_libcrypto_is_awslc();
bool s2n_libcrypto_is_boringssl();
bool s2n_libcrypto_is_libressl();
79 changes: 79 additions & 0 deletions tests/features/S2N_LIBCRYPTO_SUPPORTS_ENGINE.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* 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.
*/

/*
* This feature probe checks if the linked libcrypto has ENGINE support.
* https://docs.openssl.org/1.0.2/man3/engine/
*/

/*
* We would always expect the `openssl/engine.h` header to be available.
* However, some platforms (CentOS 10, Fedora 41, and RHEL 10) have reportedly
* been removing the `openssl/engine.h` header.
*
* See the related issues:
* - https://github.com/aws/s2n-tls/pull/4705
* - https://github.com/aws/s2n-tls/pull/4873
*/
#include <openssl/engine.h>
/* LibreSSL requires <openssl/rand.h> include.
* https://github.com/aws/s2n-tls/issues/153#issuecomment-129651643
*/
#include <openssl/rand.h>

int s2n_noop_rand(unsigned char *buf, int num)
{
return 1;
}

int main()
{
/* Init usage in utils/s2n_random.c */
ENGINE *e = ENGINE_new();
ENGINE_set_id(e, "id");
ENGINE_set_name(e, "name");
ENGINE_set_flags(e, ENGINE_FLAGS_NO_REGISTER_ALL);
ENGINE_set_init_function(e, NULL);
ENGINE_set_RAND(e, NULL);
ENGINE_add(e);
ENGINE_init(e);
ENGINE_set_default(e, ENGINE_METHOD_RAND);

/* Cleanup usage in utils/s2n_random.c */
ENGINE_remove(e);
ENGINE_finish(e);
ENGINE_unregister_RAND(e);
ENGINE_free(e);
ENGINE_cleanup();
RAND_set_rand_engine(NULL);
RAND_set_rand_method(NULL);

/* RAND_METHOD is gated behind S2N_LIBCRYPTO_SUPPORTS_ENGINE because AWS-LC has
* a different signature for RAND_METHOD and fails to compile.
*
* - AWS-LC: https://github.com/aws/aws-lc/blob/main/include/openssl/rand.h#L124
* - OpenSSL: https://github.com/openssl/openssl/blob/master/include/openssl/rand.h#L42
*/
RAND_METHOD s2n_noop_rand_method = {
.seed = NULL,
.bytes = s2n_noop_rand,
.cleanup = NULL,
.add = NULL,
.pseudorand = s2n_noop_rand,
.status = NULL
};

return 0;
}
1 change: 1 addition & 0 deletions tests/features/S2N_LIBCRYPTO_SUPPORTS_ENGINE.flags
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-Wincompatible-pointer-types
39 changes: 25 additions & 14 deletions tests/unit/s2n_openssl_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,32 @@ int main(int argc, char** argv)
{
BEGIN_TEST();

const char* env_libcrypto = getenv("S2N_LIBCRYPTO");
if (env_libcrypto == NULL) {
END_TEST();
}
{
const char* env_libcrypto = getenv("S2N_LIBCRYPTO");
if (env_libcrypto == NULL) {
END_TEST();
}

if (strcmp(env_libcrypto, "boringssl") == 0) {
EXPECT_FALSE(s2n_libcrypto_is_awslc());
EXPECT_TRUE(s2n_libcrypto_is_boringssl());
} else if (strstr(env_libcrypto, "awslc") != NULL) {
EXPECT_TRUE(s2n_libcrypto_is_awslc());
EXPECT_FALSE(s2n_libcrypto_is_boringssl());
} else {
EXPECT_FALSE(s2n_libcrypto_is_awslc());
EXPECT_FALSE(s2n_libcrypto_is_boringssl());
}
if (strcmp(env_libcrypto, "boringssl") == 0) {
EXPECT_FALSE(s2n_libcrypto_is_awslc());
EXPECT_TRUE(s2n_libcrypto_is_boringssl());
} else if (strstr(env_libcrypto, "awslc") != NULL) {
EXPECT_TRUE(s2n_libcrypto_is_awslc());
EXPECT_FALSE(s2n_libcrypto_is_boringssl());
} else {
EXPECT_FALSE(s2n_libcrypto_is_awslc());
EXPECT_FALSE(s2n_libcrypto_is_boringssl());
}
};

/* Check if libcrypto is OpenSSL. */
{
if (s2n_libcrypto_is_openssl()) {
EXPECT_FALSE(s2n_libcrypto_is_awslc());
EXPECT_FALSE(s2n_libcrypto_is_boringssl());
EXPECT_FALSE(s2n_libcrypto_is_libressl());
}
};

END_TEST();
}
19 changes: 6 additions & 13 deletions tests/unit/s2n_override_openssl_random_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
*/

#include <openssl/dh.h>
#include <openssl/engine.h>

#include "api/s2n.h"
#include "crypto/s2n_dhe.h"
Expand All @@ -26,7 +25,6 @@
#include "utils/s2n_random.h"
#include "utils/s2n_safety.h"

#if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND
const char reference_entropy_hex[] = "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
Expand Down Expand Up @@ -70,6 +68,12 @@ int main(int argc, char **argv)
uint64_t bytes_used = 0;

BEGIN_TEST();

if (!s2n_supports_custom_rand()) {
/* Skip when custom rand is not supported */
END_TEST();
}

EXPECT_SUCCESS(s2n_disable_tls13_in_test());

EXPECT_NOT_NULL(dhparams_pem = malloc(S2N_MAX_TEST_PEM_SIZE));
Expand Down Expand Up @@ -137,14 +141,3 @@ int main(int argc, char **argv)

END_TEST();
}

#else

int main(int argc, char **argv)
{
BEGIN_TEST();

END_TEST();
}

#endif
2 changes: 1 addition & 1 deletion tests/unit/s2n_pq_kem_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ int main()

#if defined(OPENSSL_IS_AWSLC) && defined(AWSLC_API_VERSION)
/* If using non-FIPS AWS-LC >= v1.6 (API vers. 21), expect Kyber512 KEM from AWS-LC */
if (!s2n_libcrypto_is_fips() && AWSLC_API_VERSION >= 21) {
if (!s2n_is_in_fips_mode() && AWSLC_API_VERSION >= 21) {
EXPECT_TRUE(s2n_libcrypto_supports_evp_kem());
}
#endif
Expand Down
57 changes: 41 additions & 16 deletions tests/unit/s2n_random_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
#define NUMBER_OF_RANGE_FUNCTION_CALLS 200
#define MAX_REPEATED_OUTPUT 4

bool s2n_libcrypto_is_fips(void);
bool s2n_libcrypto_is_openssl();
S2N_RESULT s2n_rand_device_validate(struct s2n_rand_device *device);
S2N_RESULT s2n_rand_get_urandom_for_test(struct s2n_rand_device **device);
S2N_RESULT s2n_rand_set_urandom_for_test();
Expand Down Expand Up @@ -793,25 +795,25 @@ static int s2n_random_rand_bytes_after_cleanup_cb(struct random_test_case *test_

static int s2n_random_rand_bytes_before_init(struct random_test_case *test_case)
{
#if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND
/* Calling RAND_bytes will set a global random method */
unsigned char rndbytes[16] = { 0 };
EXPECT_EQUAL(RAND_bytes(rndbytes, sizeof(rndbytes)), 1);
const RAND_METHOD *rand_method = RAND_get_rand_method();
EXPECT_NOT_NULL(rand_method);
EXPECT_NOT_EQUAL(rand_method->bytes, s2n_openssl_compat_rand);

EXPECT_SUCCESS(s2n_init());
/* s2n_libcrypto_is_fips() is used since we are testing `s2n_init()` */
if (s2n_supports_custom_rand() && !s2n_libcrypto_is_fips()) {
/* Calling RAND_bytes will set a global random method */
unsigned char rndbytes[16] = { 0 };
EXPECT_EQUAL(RAND_bytes(rndbytes, sizeof(rndbytes)), 1);
const RAND_METHOD *rand_method = RAND_get_rand_method();
EXPECT_NOT_NULL(rand_method);
EXPECT_NOT_EQUAL((void (*)(void)) rand_method->bytes, (void (*)(void)) s2n_openssl_compat_rand);

/* The global random method is overridden after calling s2n_init() */
const RAND_METHOD *custom_rand_method = RAND_get_rand_method();
EXPECT_NOT_NULL(custom_rand_method);
EXPECT_EQUAL(custom_rand_method->bytes, s2n_openssl_compat_rand);
EXPECT_SUCCESS(s2n_init());

/* RAND_bytes is still successful */
EXPECT_EQUAL(RAND_bytes(rndbytes, sizeof(rndbytes)), 1);
/* The global random method is overridden after calling s2n_init() */
const RAND_METHOD *custom_rand_method = RAND_get_rand_method();
EXPECT_NOT_NULL(custom_rand_method);
EXPECT_EQUAL((void (*)(void)) custom_rand_method->bytes, (void (*)(void)) s2n_openssl_compat_rand);

#endif
/* RAND_bytes is still successful */
EXPECT_EQUAL(RAND_bytes(rndbytes, sizeof(rndbytes)), 1);
}
return S2N_SUCCESS;
}

Expand Down Expand Up @@ -894,6 +896,29 @@ int main(int argc, char **argv)
{
BEGIN_TEST_NO_INIT();

/* Feature probe: Negative test */
{
if (s2n_libcrypto_is_awslc()) {
#if defined(S2N_LIBCRYPTO_SUPPORTS_ENGINE)
FAIL_MSG("Expected ENGINE feature probe to be disabled with AWS-LC");
#endif
}
};

/* Feature probe: Positive test
*
* TODO: Test missing due to unrelated feature probe failure on AL2.
* https://github.com/aws/s2n-tls/issues/4900
*/

/* s2n_supports_custom_rand */
{
if (s2n_supports_custom_rand()) {
EXPECT_TRUE(s2n_libcrypto_is_openssl());
EXPECT_FALSE(s2n_is_in_fips_mode());
}
};

/* For each test case, creates a child process that runs the test case.
*
* Fork detection is lazily initialised on first invocation of
Expand Down
Loading
Loading