Skip to content

Commit 2beb468

Browse files
authored
Merge branch 'main' into dependabot/cargo/bindings/rust/extended/tokio-macros-eq-2.5.0
2 parents 6d9bb2e + 2c0f038 commit 2beb468

File tree

6 files changed

+451
-179
lines changed

6 files changed

+451
-179
lines changed

codebuild/spec/buildspec_openssl3fips.yml

+1
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,4 @@ phases:
3838
- make -C build test -- ARGS="-R 's2n_build_test|s2n_fips_test'"
3939
- make -C build test -- ARGS="-R 's2n_hash_test|s2n_hash_all_algs_test|s2n_openssl_test|s2n_init_test'"
4040
- make -C build test -- ARGS="-R 's2n_evp_signing_test'"
41+
- make -C build test -- ARGS="-R 's2n_tls_prf_test|s2n_tls_hybrid_prf_test'"

crypto/s2n_prf_libcrypto.c

+193
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
#include "crypto/s2n_prf_libcrypto.h"
17+
18+
#include "crypto/s2n_hash.h"
19+
#include "error/s2n_errno.h"
20+
#include "tls/s2n_connection.h"
21+
#include "utils/s2n_safety.h"
22+
23+
#if defined(OPENSSL_IS_AWSLC)
24+
25+
/* The AWSLC TLS PRF API is exported in all AWSLC versions. However, in the AWSLC FIPS branch, this
26+
* API is defined in a private header:
27+
* https://github.com/aws/aws-lc/blob/d251b365b73a6e6acff6ee634aa8f077f23cdea4/crypto/fipsmodule/tls/internal.h#L27
28+
*
29+
* AWSLC has committed to this API definition, and the API has been added to a public header in the
30+
* main branch: https://github.com/aws/aws-lc/pull/1033. As such, this API is forward-declared in
31+
* order to make it accessible to s2n-tls when linked to AWSLC-FIPS.
32+
*/
33+
int CRYPTO_tls1_prf(const EVP_MD *digest,
34+
uint8_t *out, size_t out_len,
35+
const uint8_t *secret, size_t secret_len,
36+
const char *label, size_t label_len,
37+
const uint8_t *seed1, size_t seed1_len,
38+
const uint8_t *seed2, size_t seed2_len);
39+
40+
S2N_RESULT s2n_prf_libcrypto(struct s2n_connection *conn,
41+
struct s2n_blob *secret, struct s2n_blob *label,
42+
struct s2n_blob *seed_a, struct s2n_blob *seed_b, struct s2n_blob *seed_c,
43+
struct s2n_blob *out)
44+
{
45+
const EVP_MD *digest = NULL;
46+
if (conn->actual_protocol_version < S2N_TLS12) {
47+
/* md5_sha1 is a digest that indicates both MD5 and SHA1 should be used in the PRF calculation.
48+
* This is needed for pre-TLS12 PRFs.
49+
*/
50+
digest = EVP_md5_sha1();
51+
} else {
52+
RESULT_GUARD(s2n_hmac_md_from_alg(conn->secure->cipher_suite->prf_alg, &digest));
53+
}
54+
RESULT_ENSURE_REF(digest);
55+
56+
DEFER_CLEANUP(struct s2n_stuffer seed_b_stuffer = { 0 }, s2n_stuffer_free);
57+
size_t seed_b_len = 0;
58+
uint8_t *seed_b_data = NULL;
59+
60+
if (seed_b != NULL) {
61+
struct s2n_blob seed_b_blob = { 0 };
62+
RESULT_GUARD_POSIX(s2n_blob_init(&seed_b_blob, seed_b->data, seed_b->size));
63+
RESULT_GUARD_POSIX(s2n_stuffer_init_written(&seed_b_stuffer, &seed_b_blob));
64+
65+
if (seed_c != NULL) {
66+
/* The AWSLC TLS PRF implementation only provides two seed arguments. If three seeds
67+
* were provided, pass in the third seed by concatenating it with the second seed.
68+
*/
69+
RESULT_GUARD_POSIX(s2n_stuffer_alloc(&seed_b_stuffer, seed_b->size + seed_c->size));
70+
RESULT_GUARD_POSIX(s2n_stuffer_write_bytes(&seed_b_stuffer, seed_b->data, seed_b->size));
71+
RESULT_GUARD_POSIX(s2n_stuffer_write_bytes(&seed_b_stuffer, seed_c->data, seed_c->size));
72+
}
73+
74+
seed_b_len = s2n_stuffer_data_available(&seed_b_stuffer);
75+
seed_b_data = s2n_stuffer_raw_read(&seed_b_stuffer, seed_b_len);
76+
RESULT_ENSURE_REF(seed_b_data);
77+
}
78+
79+
RESULT_GUARD_OSSL(CRYPTO_tls1_prf(digest,
80+
out->data, out->size,
81+
secret->data, secret->size,
82+
(const char *) label->data, label->size,
83+
seed_a->data, seed_a->size,
84+
seed_b_data, seed_b_len),
85+
S2N_ERR_PRF_DERIVE);
86+
87+
return S2N_RESULT_OK;
88+
}
89+
90+
#elif S2N_OPENSSL_VERSION_AT_LEAST(3, 0, 0)
91+
92+
#include <openssl/core_names.h>
93+
#include <openssl/kdf.h>
94+
95+
#define S2N_OSSL_PARAM_BLOB(id, blob) \
96+
OSSL_PARAM_octet_string(id, blob->data, blob->size)
97+
#define S2N_OSSL_PARAM_STR(id, cstr) \
98+
OSSL_PARAM_utf8_string(id, cstr, strlen(cstr))
99+
100+
DEFINE_POINTER_CLEANUP_FUNC(EVP_KDF_CTX *, EVP_KDF_CTX_free);
101+
DEFINE_POINTER_CLEANUP_FUNC(EVP_KDF *, EVP_KDF_free);
102+
103+
S2N_RESULT s2n_prf_libcrypto(struct s2n_connection *conn,
104+
struct s2n_blob *secret, struct s2n_blob *label,
105+
struct s2n_blob *seed_a, struct s2n_blob *seed_b, struct s2n_blob *seed_c,
106+
struct s2n_blob *out)
107+
{
108+
RESULT_ENSURE_REF(conn);
109+
RESULT_ENSURE_REF(secret);
110+
RESULT_ENSURE_REF(label);
111+
RESULT_ENSURE_REF(seed_a);
112+
RESULT_ENSURE_REF(out);
113+
114+
struct s2n_blob empty_seed = { 0 };
115+
if (!seed_b) {
116+
seed_b = &empty_seed;
117+
}
118+
if (!seed_c) {
119+
seed_c = &empty_seed;
120+
}
121+
122+
/* Openssl limits the size of the seed to 1024 bytes, including the label.
123+
* This would be an issue for TLS1.2 PQ, which uses full keyshares as seeds.
124+
* However, s2n-tls doesn't support PQ with Openssl, so this limitation will
125+
* never affect customers.
126+
*
127+
* As of this commit, EVP_KDF_derive will fail silently (without logging any
128+
* error) if the seed is too large. This check adds visibility.
129+
*/
130+
uint64_t seed_total_size = label->size + seed_a->size + seed_b->size + seed_c->size;
131+
RESULT_ENSURE(seed_total_size <= 1024, S2N_ERR_PRF_INVALID_SEED);
132+
133+
const char *digest_name = "MD5-SHA1";
134+
const char *fetch_properties = "-fips";
135+
136+
if (conn->actual_protocol_version == S2N_TLS12) {
137+
fetch_properties = "";
138+
139+
RESULT_ENSURE_REF(conn->secure);
140+
RESULT_ENSURE_REF(conn->secure->cipher_suite);
141+
s2n_hmac_algorithm prf_alg = conn->secure->cipher_suite->prf_alg;
142+
143+
const EVP_MD *digest = NULL;
144+
RESULT_GUARD(s2n_hmac_md_from_alg(prf_alg, &digest));
145+
RESULT_ENSURE_REF(digest);
146+
digest_name = EVP_MD_get0_name(digest);
147+
RESULT_ENSURE_REF(digest_name);
148+
}
149+
150+
/* As an optimization, we should be able to fetch and cache this EVP_KDF*
151+
* once when s2n_init is called.
152+
*/
153+
DEFER_CLEANUP(EVP_KDF *prf_impl = EVP_KDF_fetch(NULL, "TLS1-PRF", fetch_properties),
154+
EVP_KDF_free_pointer);
155+
RESULT_ENSURE(prf_impl, S2N_ERR_PRF_INVALID_ALGORITHM);
156+
157+
DEFER_CLEANUP(EVP_KDF_CTX *prf_ctx = EVP_KDF_CTX_new(prf_impl),
158+
EVP_KDF_CTX_free_pointer);
159+
RESULT_ENSURE_REF(prf_ctx);
160+
161+
OSSL_PARAM params[] = {
162+
/* Casting away the const is safe because providers are forbidden from
163+
* modifying any OSSL_PARAM value other than return_size.
164+
* Even the examples in the Openssl documentation cast const strings to
165+
* non-const void pointers when setting up OSSL_PARAMs.
166+
*/
167+
S2N_OSSL_PARAM_STR(OSSL_KDF_PARAM_PROPERTIES, (void *) (uintptr_t) fetch_properties),
168+
S2N_OSSL_PARAM_STR(OSSL_KDF_PARAM_DIGEST, (void *) (uintptr_t) digest_name),
169+
S2N_OSSL_PARAM_BLOB(OSSL_KDF_PARAM_SECRET, secret),
170+
/* "TLS1-PRF" handles the label like just another seed */
171+
S2N_OSSL_PARAM_BLOB(OSSL_KDF_PARAM_SEED, label),
172+
S2N_OSSL_PARAM_BLOB(OSSL_KDF_PARAM_SEED, seed_a),
173+
S2N_OSSL_PARAM_BLOB(OSSL_KDF_PARAM_SEED, seed_b),
174+
S2N_OSSL_PARAM_BLOB(OSSL_KDF_PARAM_SEED, seed_c),
175+
OSSL_PARAM_END,
176+
};
177+
178+
RESULT_GUARD_OSSL(EVP_KDF_derive(prf_ctx, out->data, out->size, params),
179+
S2N_ERR_PRF_DERIVE);
180+
return S2N_RESULT_OK;
181+
}
182+
183+
#else
184+
185+
S2N_RESULT s2n_prf_libcrypto(struct s2n_connection *conn,
186+
struct s2n_blob *secret, struct s2n_blob *label,
187+
struct s2n_blob *seed_a, struct s2n_blob *seed_b, struct s2n_blob *seed_c,
188+
struct s2n_blob *out)
189+
{
190+
RESULT_BAIL(S2N_ERR_FIPS_MODE_UNSUPPORTED);
191+
}
192+
193+
#endif

crypto/s2n_prf_libcrypto.h

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
#pragma once
17+
18+
#include "utils/s2n_blob.h"
19+
#include "utils/s2n_result.h"
20+
21+
S2N_RESULT s2n_prf_libcrypto(struct s2n_connection *conn,
22+
struct s2n_blob *secret, struct s2n_blob *label,
23+
struct s2n_blob *seed_a, struct s2n_blob *seed_b, struct s2n_blob *seed_c,
24+
struct s2n_blob *out);

tests/unit/s2n_tls_hybrid_prf_test.c

+10
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <string.h>
1818

1919
#include "api/s2n.h"
20+
#include "crypto/s2n_pq.h"
2021
#include "s2n_test.h"
2122
#include "stuffer/s2n_stuffer.h"
2223
#include "tests/testlib/s2n_nist_kats.h"
@@ -40,6 +41,15 @@ int main(int argc, char **argv)
4041
BEGIN_TEST();
4142
EXPECT_SUCCESS(s2n_disable_tls13_in_test());
4243

44+
if (!s2n_pq_is_enabled()) {
45+
/* The hybrid PRF sets a seed too large for the openssl PRF,
46+
* but s2n-tls doesn't support PQ with openssl anyway.
47+
*
48+
* Only run this test in environments where PQ is possible.
49+
*/
50+
END_TEST();
51+
}
52+
4353
FILE *kat_file = fopen(KAT_FILE_NAME, "r");
4454
EXPECT_NOT_NULL(kat_file);
4555

0 commit comments

Comments
 (0)