Skip to content

Commit

Permalink
refactor: cleanup prf header (#5144)
Browse files Browse the repository at this point in the history
  • Loading branch information
lrstewart authored Feb 26, 2025
1 parent 711ee0d commit 43d05f5
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 63 deletions.
5 changes: 3 additions & 2 deletions tests/unit/s2n_ssl_prf_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@
#include "testlib/s2n_testlib.h"
#include "tls/s2n_prf.h"

/*
int s2n_prf_tls_master_secret(struct s2n_connection *conn, struct s2n_blob *premaster_secret);

/*
* Grabbed from gnutls-cli --insecure -d 9 www.example.com --ciphers AES --macs SHA --protocols SSLv3
*
* |<9>| INT: PREMASTER SECRET[48]: 03009e8e006a7f1451d32164088a8cba5077d1b819160662a97e90a765cec244b5f8f98fd50cfe8e4fba97994a7a4843
Expand Down Expand Up @@ -86,7 +87,7 @@ int main(int argc, char **argv)
conn->actual_protocol_version = S2N_SSLv3;
pms.data = conn->secrets.version.tls12.rsa_premaster_secret;
pms.size = sizeof(conn->secrets.version.tls12.rsa_premaster_secret);
EXPECT_SUCCESS(s2n_tls_prf_master_secret(conn, &pms));
EXPECT_SUCCESS(s2n_prf_tls_master_secret(conn, &pms));

/* Convert the master secret to hex */
for (int i = 0; i < 48; i++) {
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/s2n_tls_hybrid_prf_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ int main(int argc, char **argv)

EXPECT_MEMCPY_SUCCESS(conn->kex_params.client_key_exchange_message.data, client_key_exchange_message, client_key_exchange_message_length);

EXPECT_SUCCESS(s2n_hybrid_prf_master_secret(conn, &combined_pms));
EXPECT_SUCCESS(s2n_prf_hybrid_master_secret(conn, &combined_pms));
EXPECT_BYTEARRAY_EQUAL(expected_master_secret, conn->secrets.version.tls12.master_secret, S2N_TLS_SECRET_LEN);
EXPECT_SUCCESS(s2n_free(&conn->kex_params.client_key_exchange_message));
EXPECT_SUCCESS(s2n_connection_free(conn));
Expand Down
20 changes: 15 additions & 5 deletions tests/unit/s2n_tls_prf_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@

#define TEST_BLOB_SIZE 64

bool s2n_libcrypto_supports_tls_prf();
int s2n_prf(struct s2n_connection *conn, struct s2n_blob *secret,
struct s2n_blob *label, struct s2n_blob *seed_a,
struct s2n_blob *seed_b, struct s2n_blob *seed_c, struct s2n_blob *out);
S2N_RESULT s2n_prf_get_digest_for_ems(struct s2n_connection *conn,
struct s2n_blob *message, s2n_hash_algorithm hash_alg, struct s2n_blob *output);
S2N_RESULT s2n_prf_tls_extended_master_secret(struct s2n_connection *conn,
struct s2n_blob *premaster_secret, struct s2n_blob *session_hash, struct s2n_blob *sha1_hash);
int s2n_prf_tls_master_secret(struct s2n_connection *conn, struct s2n_blob *premaster_secret);

/*
* Grabbed from gnutls-cli --insecure -d 9 www.example.com --ciphers AES --macs SHA --protocols TLS1.0
*
Expand Down Expand Up @@ -63,7 +73,7 @@ int main(int argc, char **argv)

struct s2n_blob pms = { 0 };
EXPECT_SUCCESS(s2n_blob_init(&pms, conn->secrets.version.tls12.rsa_premaster_secret, sizeof(conn->secrets.version.tls12.rsa_premaster_secret)));
EXPECT_SUCCESS(s2n_tls_prf_master_secret(conn, &pms));
EXPECT_SUCCESS(s2n_prf_tls_master_secret(conn, &pms));
EXPECT_EQUAL(memcmp(conn->secrets.version.tls12.master_secret, master_secret_in.data, master_secret_in.size), 0);

EXPECT_SUCCESS(s2n_connection_free(conn));
Expand Down Expand Up @@ -100,7 +110,7 @@ int main(int argc, char **argv)
*# session_hash)
*# [0..47];
*/
EXPECT_OK(s2n_tls_prf_extended_master_secret(conn, &premaster_secret, &hash_digest, NULL));
EXPECT_OK(s2n_prf_tls_extended_master_secret(conn, &premaster_secret, &hash_digest, NULL));
EXPECT_BYTEARRAY_EQUAL(extended_master_secret.data, conn->secrets.version.tls12.master_secret, S2N_TLS_SECRET_LEN);

EXPECT_SUCCESS(s2n_connection_free(conn));
Expand Down Expand Up @@ -293,20 +303,20 @@ int main(int argc, char **argv)
EXPECT_MEMCPY_SUCCESS(conn->secrets.version.tls12.rsa_premaster_secret, premaster_secret_in.data, premaster_secret_in.size);
EXPECT_MEMCPY_SUCCESS(conn->handshake_params.client_random, client_random_in.data, client_random_in.size);
EXPECT_MEMCPY_SUCCESS(conn->handshake_params.server_random, server_random_in.data, server_random_in.size);
EXPECT_SUCCESS(s2n_tls_prf_master_secret(conn, &pms));
EXPECT_SUCCESS(s2n_prf_tls_master_secret(conn, &pms));
EXPECT_EQUAL(memcmp(conn->secrets.version.tls12.master_secret, master_secret_in.data, master_secret_in.size), 0);

EXPECT_SUCCESS(s2n_connection_free_handshake(conn));
EXPECT_MEMCPY_SUCCESS(conn->secrets.version.tls12.rsa_premaster_secret, premaster_secret_in.data, premaster_secret_in.size);
EXPECT_MEMCPY_SUCCESS(conn->handshake_params.client_random, client_random_in.data, client_random_in.size);
EXPECT_MEMCPY_SUCCESS(conn->handshake_params.server_random, server_random_in.data, server_random_in.size);
EXPECT_FAILURE_WITH_ERRNO(s2n_tls_prf_master_secret(conn, &pms), S2N_ERR_NULL);
EXPECT_FAILURE_WITH_ERRNO(s2n_prf_tls_master_secret(conn, &pms), S2N_ERR_NULL);

EXPECT_SUCCESS(s2n_connection_wipe(conn));
EXPECT_MEMCPY_SUCCESS(conn->secrets.version.tls12.rsa_premaster_secret, premaster_secret_in.data, premaster_secret_in.size);
EXPECT_MEMCPY_SUCCESS(conn->handshake_params.client_random, client_random_in.data, client_random_in.size);
EXPECT_MEMCPY_SUCCESS(conn->handshake_params.server_random, server_random_in.data, server_random_in.size);
EXPECT_SUCCESS(s2n_tls_prf_master_secret(conn, &pms));
EXPECT_SUCCESS(s2n_prf_tls_master_secret(conn, &pms));
EXPECT_EQUAL(memcmp(conn->secrets.version.tls12.master_secret, master_secret_in.data, master_secret_in.size), 0);

EXPECT_SUCCESS(s2n_connection_free(conn));
Expand Down
2 changes: 1 addition & 1 deletion tls/s2n_kex.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ const struct s2n_kex s2n_hybrid_ecdhe_kem = {
.server_key_send = &s2n_hybrid_server_key_send,
.client_key_recv = &s2n_hybrid_client_key_recv,
.client_key_send = &s2n_hybrid_client_key_send,
.prf = &s2n_hybrid_prf_master_secret,
.prf = &s2n_prf_hybrid_master_secret,
};

/* TLS1.3 key exchange is implemented differently from previous versions and does
Expand Down
63 changes: 43 additions & 20 deletions tls/s2n_prf.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,29 @@
#include "utils/s2n_mem.h"
#include "utils/s2n_safety.h"

#if defined(OPENSSL_IS_AWSLC)
#define S2N_LIBCRYPTO_SUPPORTS_TLS_PRF 1
#else
#define S2N_LIBCRYPTO_SUPPORTS_TLS_PRF 0
#endif

/* The s2n p_hash implementation is abstracted to allow for separate implementations, using
* either s2n's formally verified HMAC or OpenSSL's EVP HMAC, for use by the TLS PRF. */
struct s2n_p_hash_hmac {
int (*alloc)(struct s2n_prf_working_space *ws);
int (*init)(struct s2n_prf_working_space *ws, s2n_hmac_algorithm alg, struct s2n_blob *secret);
int (*update)(struct s2n_prf_working_space *ws, const void *data, uint32_t size);
int (*final)(struct s2n_prf_working_space *ws, void *digest, uint32_t size);
int (*reset)(struct s2n_prf_working_space *ws);
int (*cleanup)(struct s2n_prf_working_space *ws);
int (*free)(struct s2n_prf_working_space *ws);
};

S2N_RESULT s2n_prf_get_digest_for_ems(struct s2n_connection *conn, struct s2n_blob *message,
s2n_hash_algorithm hash_alg, struct s2n_blob *output);
S2N_RESULT s2n_prf_tls_extended_master_secret(struct s2n_connection *conn,
struct s2n_blob *premaster_secret, struct s2n_blob *session_hash, struct s2n_blob *sha1_hash);

S2N_RESULT s2n_key_material_init(struct s2n_key_material *key_material, struct s2n_connection *conn)
{
RESULT_ENSURE_REF(key_material);
Expand Down Expand Up @@ -114,7 +137,7 @@ S2N_RESULT s2n_key_material_init(struct s2n_key_material *key_material, struct s
return S2N_RESULT_OK;
}

static int s2n_sslv3_prf(struct s2n_connection *conn, struct s2n_blob *secret, struct s2n_blob *seed_a,
static int s2n_prf_sslv3(struct s2n_connection *conn, struct s2n_blob *secret, struct s2n_blob *seed_a,
struct s2n_blob *seed_b, struct s2n_blob *seed_c, struct s2n_blob *out)
{
POSIX_ENSURE_REF(conn);
Expand Down Expand Up @@ -509,7 +532,7 @@ bool s2n_libcrypto_supports_tls_prf()
#endif
}

S2N_RESULT s2n_custom_prf(struct s2n_connection *conn, struct s2n_blob *secret, struct s2n_blob *label,
S2N_RESULT s2n_prf_custom(struct s2n_connection *conn, struct s2n_blob *secret, struct s2n_blob *label,
struct s2n_blob *seed_a, struct s2n_blob *seed_b, struct s2n_blob *seed_c, struct s2n_blob *out)
{
/* We zero the out blob because p_hash works by XOR'ing with the existing
Expand Down Expand Up @@ -553,7 +576,7 @@ int CRYPTO_tls1_prf(const EVP_MD *digest,
const uint8_t *seed1, size_t seed1_len,
const uint8_t *seed2, size_t seed2_len);

S2N_RESULT s2n_libcrypto_prf(struct s2n_connection *conn, struct s2n_blob *secret, struct s2n_blob *label,
S2N_RESULT s2n_prf_libcrypto(struct s2n_connection *conn, struct s2n_blob *secret, struct s2n_blob *label,
struct s2n_blob *seed_a, struct s2n_blob *seed_b, struct s2n_blob *seed_c, struct s2n_blob *out)
{
const EVP_MD *digest = NULL;
Expand Down Expand Up @@ -601,7 +624,7 @@ S2N_RESULT s2n_libcrypto_prf(struct s2n_connection *conn, struct s2n_blob *secre
return S2N_RESULT_OK;
}
#else
S2N_RESULT s2n_libcrypto_prf(struct s2n_connection *conn, struct s2n_blob *secret, struct s2n_blob *label,
S2N_RESULT s2n_prf_libcrypto(struct s2n_connection *conn, struct s2n_blob *secret, struct s2n_blob *label,
struct s2n_blob *seed_a, struct s2n_blob *seed_b, struct s2n_blob *seed_c, struct s2n_blob *out)
{
RESULT_BAIL(S2N_ERR_UNIMPLEMENTED);
Expand All @@ -624,24 +647,24 @@ int s2n_prf(struct s2n_connection *conn, struct s2n_blob *secret, struct s2n_blo
POSIX_ENSURE(S2N_IMPLIES(seed_c != NULL, seed_b != NULL), S2N_ERR_PRF_INVALID_SEED);

if (conn->actual_protocol_version == S2N_SSLv3) {
POSIX_GUARD(s2n_sslv3_prf(conn, secret, seed_a, seed_b, seed_c, out));
POSIX_GUARD(s2n_prf_sslv3(conn, secret, seed_a, seed_b, seed_c, out));
return S2N_SUCCESS;
}

/* By default, s2n-tls uses a custom PRF implementation. When operating in FIPS mode, the
* FIPS-validated libcrypto implementation is used instead, if an implementation is provided.
*/
if (s2n_is_in_fips_mode() && s2n_libcrypto_supports_tls_prf()) {
POSIX_GUARD_RESULT(s2n_libcrypto_prf(conn, secret, label, seed_a, seed_b, seed_c, out));
POSIX_GUARD_RESULT(s2n_prf_libcrypto(conn, secret, label, seed_a, seed_b, seed_c, out));
return S2N_SUCCESS;
}

POSIX_GUARD_RESULT(s2n_custom_prf(conn, secret, label, seed_a, seed_b, seed_c, out));
POSIX_GUARD_RESULT(s2n_prf_custom(conn, secret, label, seed_a, seed_b, seed_c, out));

return S2N_SUCCESS;
}

int s2n_tls_prf_master_secret(struct s2n_connection *conn, struct s2n_blob *premaster_secret)
int s2n_prf_tls_master_secret(struct s2n_connection *conn, struct s2n_blob *premaster_secret)
{
POSIX_ENSURE_REF(conn);

Expand All @@ -659,7 +682,7 @@ int s2n_tls_prf_master_secret(struct s2n_connection *conn, struct s2n_blob *prem
return s2n_prf(conn, premaster_secret, &label, &client_random, &server_random, NULL, &master_secret);
}

int s2n_hybrid_prf_master_secret(struct s2n_connection *conn, struct s2n_blob *premaster_secret)
int s2n_prf_hybrid_master_secret(struct s2n_connection *conn, struct s2n_blob *premaster_secret)
{
POSIX_ENSURE_REF(conn);

Expand All @@ -685,7 +708,7 @@ int s2n_prf_calculate_master_secret(struct s2n_connection *conn, struct s2n_blob
POSIX_ENSURE_EQ(s2n_conn_get_current_message_type(conn), CLIENT_KEY);

if (!conn->ems_negotiated) {
POSIX_GUARD(s2n_tls_prf_master_secret(conn, premaster_secret));
POSIX_GUARD(s2n_prf_tls_master_secret(conn, premaster_secret));
return S2N_SUCCESS;
}

Expand All @@ -708,13 +731,13 @@ int s2n_prf_calculate_master_secret(struct s2n_connection *conn, struct s2n_blob
POSIX_GUARD(s2n_blob_init(&sha1_digest, sha1_data, sizeof(sha1_data)));
POSIX_GUARD_RESULT(s2n_prf_get_digest_for_ems(conn, &client_key_blob, S2N_HASH_MD5, &digest));
POSIX_GUARD_RESULT(s2n_prf_get_digest_for_ems(conn, &client_key_blob, S2N_HASH_SHA1, &sha1_digest));
POSIX_GUARD_RESULT(s2n_tls_prf_extended_master_secret(conn, premaster_secret, &digest, &sha1_digest));
POSIX_GUARD_RESULT(s2n_prf_tls_extended_master_secret(conn, premaster_secret, &digest, &sha1_digest));
} else {
s2n_hmac_algorithm prf_alg = conn->secure->cipher_suite->prf_alg;
s2n_hash_algorithm hash_alg = 0;
POSIX_GUARD(s2n_hmac_hash_alg(prf_alg, &hash_alg));
POSIX_GUARD_RESULT(s2n_prf_get_digest_for_ems(conn, &client_key_blob, hash_alg, &digest));
POSIX_GUARD_RESULT(s2n_tls_prf_extended_master_secret(conn, premaster_secret, &digest, NULL));
POSIX_GUARD_RESULT(s2n_prf_tls_extended_master_secret(conn, premaster_secret, &digest, NULL));
}
return S2N_SUCCESS;
}
Expand All @@ -728,7 +751,7 @@ int s2n_prf_calculate_master_secret(struct s2n_connection *conn, struct s2n_blob
*# session_hash)
*# [0..47];
*/
S2N_RESULT s2n_tls_prf_extended_master_secret(struct s2n_connection *conn, struct s2n_blob *premaster_secret, struct s2n_blob *session_hash, struct s2n_blob *sha1_hash)
S2N_RESULT s2n_prf_tls_extended_master_secret(struct s2n_connection *conn, struct s2n_blob *premaster_secret, struct s2n_blob *session_hash, struct s2n_blob *sha1_hash)
{
RESULT_ENSURE_REF(conn);

Expand Down Expand Up @@ -765,7 +788,7 @@ S2N_RESULT s2n_prf_get_digest_for_ems(struct s2n_connection *conn, struct s2n_bl
return S2N_RESULT_OK;
}

static int s2n_sslv3_finished(struct s2n_connection *conn, uint8_t prefix[4], struct s2n_hash_state *hash_workspace, uint8_t *out)
static int s2n_prf_sslv3_finished(struct s2n_connection *conn, uint8_t prefix[4], struct s2n_hash_state *hash_workspace, uint8_t *out)
{
POSIX_ENSURE_REF(conn);
POSIX_ENSURE_REF(conn->handshake.hashes);
Expand Down Expand Up @@ -808,24 +831,24 @@ static int s2n_sslv3_finished(struct s2n_connection *conn, uint8_t prefix[4], st
return 0;
}

static int s2n_sslv3_client_finished(struct s2n_connection *conn)
static int s2n_prf_sslv3_client_finished(struct s2n_connection *conn)
{
POSIX_ENSURE_REF(conn);
POSIX_ENSURE_REF(conn->handshake.hashes);

uint8_t prefix[4] = { 0x43, 0x4c, 0x4e, 0x54 };

return s2n_sslv3_finished(conn, prefix, &conn->handshake.hashes->hash_workspace, conn->handshake.client_finished);
return s2n_prf_sslv3_finished(conn, prefix, &conn->handshake.hashes->hash_workspace, conn->handshake.client_finished);
}

static int s2n_sslv3_server_finished(struct s2n_connection *conn)
static int s2n_prf_sslv3_server_finished(struct s2n_connection *conn)
{
POSIX_ENSURE_REF(conn);
POSIX_ENSURE_REF(conn->handshake.hashes);

uint8_t prefix[4] = { 0x53, 0x52, 0x56, 0x52 };

return s2n_sslv3_finished(conn, prefix, &conn->handshake.hashes->hash_workspace, conn->handshake.server_finished);
return s2n_prf_sslv3_finished(conn, prefix, &conn->handshake.hashes->hash_workspace, conn->handshake.server_finished);
}

int s2n_prf_client_finished(struct s2n_connection *conn)
Expand All @@ -842,7 +865,7 @@ int s2n_prf_client_finished(struct s2n_connection *conn)
struct s2n_blob label = { 0 };

if (conn->actual_protocol_version == S2N_SSLv3) {
return s2n_sslv3_client_finished(conn);
return s2n_prf_sslv3_client_finished(conn);
}

client_finished.data = conn->handshake.client_finished;
Expand Down Expand Up @@ -900,7 +923,7 @@ int s2n_prf_server_finished(struct s2n_connection *conn)
struct s2n_blob label = { 0 };

if (conn->actual_protocol_version == S2N_SSLv3) {
return s2n_sslv3_server_finished(conn);
return s2n_prf_sslv3_server_finished(conn);
}

server_finished.data = conn->handshake.server_finished;
Expand Down
36 changes: 2 additions & 34 deletions tls/s2n_prf.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,13 @@

#include <stdint.h>

#include "crypto/s2n_hash.h"
#include "crypto/s2n_hmac.h"
#include "tls/s2n_connection.h"
#include "utils/s2n_blob.h"

/* Enough to support TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, 2*SHA384_DIGEST_LEN + 2*AES256_KEY_SIZE */
#define S2N_MAX_KEY_BLOCK_LEN 160

#if defined(OPENSSL_IS_AWSLC)
#define S2N_LIBCRYPTO_SUPPORTS_TLS_PRF 1
#else
#define S2N_LIBCRYPTO_SUPPORTS_TLS_PRF 0
#endif

union p_hash_state {
struct s2n_hmac_state s2n_hmac;
struct s2n_evp_hmac_state evp_hmac;
Expand All @@ -41,18 +35,6 @@ struct s2n_prf_working_space {
uint8_t digest1[S2N_MAX_DIGEST_LEN];
};

/* The s2n p_hash implementation is abstracted to allow for separate implementations, using
* either s2n's formally verified HMAC or OpenSSL's EVP HMAC, for use by the TLS PRF. */
struct s2n_p_hash_hmac {
int (*alloc)(struct s2n_prf_working_space *ws);
int (*init)(struct s2n_prf_working_space *ws, s2n_hmac_algorithm alg, struct s2n_blob *secret);
int (*update)(struct s2n_prf_working_space *ws, const void *data, uint32_t size);
int (*final)(struct s2n_prf_working_space *ws, void *digest, uint32_t size);
int (*reset)(struct s2n_prf_working_space *ws);
int (*cleanup)(struct s2n_prf_working_space *ws);
int (*free)(struct s2n_prf_working_space *ws);
};

/* TLS key expansion results in an array of contiguous data which is then
* interpreted as the MAC, KEY and IV for the client and server.
*
Expand All @@ -75,27 +57,13 @@ struct s2n_key_material {

S2N_RESULT s2n_key_material_init(struct s2n_key_material *key_material, struct s2n_connection *conn);

#include "tls/s2n_connection.h"

S2N_RESULT s2n_prf_new(struct s2n_connection *conn);
S2N_RESULT s2n_prf_wipe(struct s2n_connection *conn);
S2N_RESULT s2n_prf_free(struct s2n_connection *conn);

int s2n_prf(struct s2n_connection *conn, struct s2n_blob *secret, struct s2n_blob *label, struct s2n_blob *seed_a,
struct s2n_blob *seed_b, struct s2n_blob *seed_c, struct s2n_blob *out);
int s2n_prf_calculate_master_secret(struct s2n_connection *conn, struct s2n_blob *premaster_secret);
int s2n_tls_prf_master_secret(struct s2n_connection *conn, struct s2n_blob *premaster_secret);
int s2n_hybrid_prf_master_secret(struct s2n_connection *conn, struct s2n_blob *premaster_secret);
S2N_RESULT s2n_tls_prf_extended_master_secret(struct s2n_connection *conn, struct s2n_blob *premaster_secret, struct s2n_blob *session_hash, struct s2n_blob *sha1_hash);
S2N_RESULT s2n_prf_get_digest_for_ems(struct s2n_connection *conn, struct s2n_blob *message, s2n_hash_algorithm hash_alg, struct s2n_blob *output);
int s2n_prf_hybrid_master_secret(struct s2n_connection *conn, struct s2n_blob *premaster_secret);
S2N_RESULT s2n_prf_generate_key_material(struct s2n_connection *conn, struct s2n_key_material *key_material);
int s2n_prf_key_expansion(struct s2n_connection *conn);
int s2n_prf_server_finished(struct s2n_connection *conn);
int s2n_prf_client_finished(struct s2n_connection *conn);

bool s2n_libcrypto_supports_tls_prf();

S2N_RESULT s2n_custom_prf(struct s2n_connection *conn, struct s2n_blob *secret, struct s2n_blob *label,
struct s2n_blob *seed_a, struct s2n_blob *seed_b, struct s2n_blob *seed_c, struct s2n_blob *out);
S2N_RESULT s2n_libcrypto_prf(struct s2n_connection *conn, struct s2n_blob *secret, struct s2n_blob *label,
struct s2n_blob *seed_a, struct s2n_blob *seed_b, struct s2n_blob *seed_c, struct s2n_blob *out);

0 comments on commit 43d05f5

Please sign in to comment.