Skip to content

Commit

Permalink
feat: feature probe S2N_LIBCRYPTO_SUPPORTS_ENGINE (#4878)
Browse files Browse the repository at this point in the history
  • Loading branch information
toidiu authored Dec 5, 2024
1 parent 77628b7 commit 774462f
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 78 deletions.
2 changes: 1 addition & 1 deletion crypto/s2n_libcrypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ static S2N_RESULT s2n_libcrypto_validate_expected_version_number(void)
* ABI compatible forks of OpenSSL, detecting OpenSSL is done by checking the
* absence of other known libcrypto variants.
*/
bool s2n_libcrypto_is_openssl()
bool s2n_libcrypto_is_openssl(void)
{
bool is_other_libcrypto_variant =
s2n_libcrypto_is_boringssl() || s2n_libcrypto_is_libressl() || s2n_libcrypto_is_awslc();
Expand Down
8 changes: 1 addition & 7 deletions crypto/s2n_openssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +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_openssl(void);
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
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
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(void);
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
99 changes: 58 additions & 41 deletions utils/s2n_random.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@
#endif
#include <errno.h>
#include <limits.h>
#include <openssl/engine.h>
#if S2N_LIBCRYPTO_SUPPORTS_ENGINE
#include <openssl/engine.h>
#endif
/* LibreSSL requires <openssl/rand.h> include.
* https://github.com/aws/s2n-tls/issues/153#issuecomment-129651643
*/
Expand Down Expand Up @@ -79,6 +81,8 @@
#include "utils/s2n_result.h"
#include "utils/s2n_safety.h"

const char s2n_rand_engine_id[] = "s2n_rand";

#if defined(O_CLOEXEC)
#define ENTROPY_FLAGS O_RDONLY | O_CLOEXEC
#else
Expand Down Expand Up @@ -495,10 +499,6 @@ S2N_RESULT s2n_public_random(int64_t bound, uint64_t *output)
}
}

#if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND

#define S2N_RAND_ENGINE_ID "s2n_rand"

int s2n_openssl_compat_rand(unsigned char *buf, int num)
{
struct s2n_blob out = { 0 };
Expand All @@ -515,11 +515,18 @@ int s2n_openssl_compat_status(void)
return 1;
}

#if S2N_LIBCRYPTO_SUPPORTS_ENGINE
int s2n_openssl_compat_init(ENGINE *unused)
{
return 1;
}

/* 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_openssl_rand_method = {
.seed = NULL,
.bytes = s2n_openssl_compat_rand,
Expand All @@ -545,38 +552,46 @@ static int s2n_rand_init_cb_impl(void)
return S2N_SUCCESS;
}

bool s2n_supports_custom_rand(void)
{
#if !defined(S2N_LIBCRYPTO_SUPPORTS_ENGINE)
return false;
#else
return s2n_libcrypto_is_openssl() && !s2n_is_in_fips_mode();
#endif
}

S2N_RESULT s2n_rand_init(void)
{
RESULT_ENSURE(s2n_rand_init_cb() >= S2N_SUCCESS, S2N_ERR_CANCELLED);

RESULT_GUARD(s2n_ensure_initialized_drbgs());

#if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND
if (s2n_is_in_fips_mode()) {
return S2N_RESULT_OK;
#if S2N_LIBCRYPTO_SUPPORTS_ENGINE
if (s2n_supports_custom_rand()) {
/* Unset any existing random engine */
RESULT_GUARD_OSSL(RAND_set_rand_engine(NULL), S2N_ERR_OPEN_RANDOM);

/* Create an engine */
ENGINE *e = ENGINE_new();

/* Initialize the engine */
RESULT_ENSURE(e != NULL, S2N_ERR_OPEN_RANDOM);
RESULT_GUARD_OSSL(ENGINE_set_id(e, s2n_rand_engine_id), S2N_ERR_OPEN_RANDOM);
RESULT_GUARD_OSSL(ENGINE_set_name(e, "s2n entropy generator"), S2N_ERR_OPEN_RANDOM);
RESULT_GUARD_OSSL(ENGINE_set_flags(e, ENGINE_FLAGS_NO_REGISTER_ALL), S2N_ERR_OPEN_RANDOM);
RESULT_GUARD_OSSL(ENGINE_set_init_function(e, s2n_openssl_compat_init), S2N_ERR_OPEN_RANDOM);
RESULT_GUARD_OSSL(ENGINE_set_RAND(e, &s2n_openssl_rand_method), S2N_ERR_OPEN_RANDOM);
RESULT_GUARD_OSSL(ENGINE_add(e), S2N_ERR_OPEN_RANDOM);
RESULT_GUARD_OSSL(ENGINE_free(e), S2N_ERR_OPEN_RANDOM);

/* Use that engine for rand() */
e = ENGINE_by_id(s2n_rand_engine_id);
RESULT_ENSURE(e != NULL, S2N_ERR_OPEN_RANDOM);
RESULT_GUARD_OSSL(ENGINE_init(e), S2N_ERR_OPEN_RANDOM);
RESULT_GUARD_OSSL(ENGINE_set_default(e, ENGINE_METHOD_RAND), S2N_ERR_OPEN_RANDOM);
RESULT_GUARD_OSSL(ENGINE_free(e), S2N_ERR_OPEN_RANDOM);
}

/* Unset any existing random engine */
RESULT_GUARD_OSSL(RAND_set_rand_engine(NULL), S2N_ERR_OPEN_RANDOM);

/* Create an engine */
ENGINE *e = ENGINE_new();

RESULT_ENSURE(e != NULL, S2N_ERR_OPEN_RANDOM);
RESULT_GUARD_OSSL(ENGINE_set_id(e, S2N_RAND_ENGINE_ID), S2N_ERR_OPEN_RANDOM);
RESULT_GUARD_OSSL(ENGINE_set_name(e, "s2n entropy generator"), S2N_ERR_OPEN_RANDOM);
RESULT_GUARD_OSSL(ENGINE_set_flags(e, ENGINE_FLAGS_NO_REGISTER_ALL), S2N_ERR_OPEN_RANDOM);
RESULT_GUARD_OSSL(ENGINE_set_init_function(e, s2n_openssl_compat_init), S2N_ERR_OPEN_RANDOM);
RESULT_GUARD_OSSL(ENGINE_set_RAND(e, &s2n_openssl_rand_method), S2N_ERR_OPEN_RANDOM);
RESULT_GUARD_OSSL(ENGINE_add(e), S2N_ERR_OPEN_RANDOM);
RESULT_GUARD_OSSL(ENGINE_free(e), S2N_ERR_OPEN_RANDOM);

/* Use that engine for rand() */
e = ENGINE_by_id(S2N_RAND_ENGINE_ID);
RESULT_ENSURE(e != NULL, S2N_ERR_OPEN_RANDOM);
RESULT_GUARD_OSSL(ENGINE_init(e), S2N_ERR_OPEN_RANDOM);
RESULT_GUARD_OSSL(ENGINE_set_default(e, ENGINE_METHOD_RAND), S2N_ERR_OPEN_RANDOM);
RESULT_GUARD_OSSL(ENGINE_free(e), S2N_ERR_OPEN_RANDOM);
#endif

return S2N_RESULT_OK;
Expand All @@ -598,17 +613,19 @@ S2N_RESULT s2n_rand_cleanup(void)
{
RESULT_ENSURE(s2n_rand_cleanup_cb() >= S2N_SUCCESS, S2N_ERR_CANCELLED);

#if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND
/* Cleanup our rand ENGINE in libcrypto */
ENGINE *rand_engine = ENGINE_by_id(S2N_RAND_ENGINE_ID);
if (rand_engine) {
ENGINE_remove(rand_engine);
ENGINE_finish(rand_engine);
ENGINE_unregister_RAND(rand_engine);
ENGINE_free(rand_engine);
ENGINE_cleanup();
RAND_set_rand_engine(NULL);
RAND_set_rand_method(NULL);
#if S2N_LIBCRYPTO_SUPPORTS_ENGINE
if (s2n_supports_custom_rand()) {
/* Cleanup our rand ENGINE in libcrypto */
ENGINE *rand_engine = ENGINE_by_id(s2n_rand_engine_id);
if (rand_engine) {
ENGINE_remove(rand_engine);
ENGINE_finish(rand_engine);
ENGINE_unregister_RAND(rand_engine);
ENGINE_free(rand_engine);
ENGINE_cleanup();
RAND_set_rand_engine(NULL);
RAND_set_rand_method(NULL);
}
}
#endif

Expand Down
1 change: 1 addition & 0 deletions utils/s2n_random.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ struct s2n_rand_device {
dev_t rdev;
};

bool s2n_supports_custom_rand(void);
S2N_RESULT s2n_rand_init(void);
S2N_RESULT s2n_rand_cleanup(void);
S2N_RESULT s2n_get_seed_entropy(struct s2n_blob *blob);
Expand Down

0 comments on commit 774462f

Please sign in to comment.