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 "tls/s2n_kem.h"
17 #include "tests/testlib/s2n_nist_kats.h"
18 #include "utils/s2n_mem.h"
19 #include "utils/s2n_random.h"
20 #include "utils/s2n_safety.h"
21 #include "crypto/s2n_drbg.h"
22 #include "crypto/s2n_openssl.h"
23 #include "pq-crypto/s2n_pq.h"
24 #include "stuffer/s2n_stuffer.h"
25 #include "tests/testlib/s2n_testlib.h"
26 #include "tls/s2n_kex.h"
27 #include "tls/s2n_tls.h"
28 #include "tls/s2n_cipher_suites.h"
29 #include "tls/s2n_cipher_preferences.h"
30 #include "tls/s2n_security_policies.h"
31 
32 #define SEED_LENGTH 48
33 uint8_t hybrid_kat_entropy_buff[SEED_LENGTH] = {0};
34 struct s2n_blob hybrid_kat_entropy_blob = {.size = SEED_LENGTH, .data = hybrid_kat_entropy_buff};
35 struct s2n_drbg drbg_for_hybrid_kats;
36 
s2n_hybrid_pq_rand_init(void)37 int s2n_hybrid_pq_rand_init(void) {
38     POSIX_ENSURE(s2n_in_unit_test(), S2N_ERR_NOT_IN_UNIT_TEST);
39     return S2N_SUCCESS;
40 }
41 
s2n_hybrid_pq_rand_cleanup(void)42 int s2n_hybrid_pq_rand_cleanup(void) {
43     return S2N_SUCCESS;
44 }
45 
46 /* We use "seed" from the KAT file for both the seed entropy and mix entropy for DRBG */
s2n_hybrid_pq_entropy(void * ptr,uint32_t size)47 int s2n_hybrid_pq_entropy(void *ptr, uint32_t size) {
48     POSIX_ENSURE(s2n_in_unit_test(), S2N_ERR_NOT_IN_UNIT_TEST);
49     POSIX_ENSURE_REF(ptr);
50     POSIX_ENSURE_LTE(size, hybrid_kat_entropy_blob.size);
51     POSIX_CHECKED_MEMCPY(ptr, hybrid_kat_entropy_buff, size);
52 
53     return S2N_SUCCESS;
54 }
55 
setup_connection(struct s2n_connection * conn,const struct s2n_kem * kem,struct s2n_cipher_suite * cipher_suite,const char * cipher_pref_version)56 static int setup_connection(struct s2n_connection *conn, const struct s2n_kem *kem, struct s2n_cipher_suite *cipher_suite,
57         const char *cipher_pref_version) {
58     conn->actual_protocol_version = S2N_TLS12;
59 
60     const struct s2n_ecc_preferences *ecc_preferences = NULL;
61     POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_preferences));
62     POSIX_GUARD_PTR(ecc_preferences);
63 
64     conn->kex_params.server_ecc_evp_params.negotiated_curve = ecc_preferences->ecc_curves[0];
65     conn->kex_params.kem_params.kem = kem;
66     conn->secure.cipher_suite = cipher_suite;
67     conn->handshake_params.conn_sig_scheme = s2n_rsa_pkcs1_sha384;
68     POSIX_GUARD(s2n_connection_set_cipher_preferences(conn, cipher_pref_version));
69     return S2N_SUCCESS;
70 }
71 
s2n_test_hybrid_ecdhe_kem_with_kat(const struct s2n_kem * kem,struct s2n_cipher_suite * cipher_suite,const char * cipher_pref_version,const char * kat_file_name,uint32_t server_key_message_length,uint32_t client_key_message_length)72 int s2n_test_hybrid_ecdhe_kem_with_kat(const struct s2n_kem *kem, struct s2n_cipher_suite *cipher_suite,
73         const char *cipher_pref_version, const char * kat_file_name, uint32_t server_key_message_length,
74         uint32_t client_key_message_length) {
75     POSIX_ENSURE(s2n_pq_is_enabled(), S2N_ERR_PQ_DISABLED);
76 
77     /* Part 1 setup a client and server connection with everything they need for a key exchange */
78     struct s2n_connection *client_conn = NULL, *server_conn = NULL;
79     POSIX_GUARD_PTR(client_conn = s2n_connection_new(S2N_CLIENT));
80     POSIX_GUARD_PTR(server_conn = s2n_connection_new(S2N_SERVER));
81 
82     struct s2n_config *server_config = NULL, *client_config = NULL;
83 
84     POSIX_GUARD_PTR(client_config = s2n_config_new());
85     POSIX_GUARD(s2n_config_set_unsafe_for_testing(client_config));
86     POSIX_GUARD(s2n_connection_set_config(client_conn, client_config));
87 
88     /* Part 1.1 setup server's keypair and the give the client the certificate */
89     char *cert_chain = NULL;
90     char *private_key = NULL;
91     char *client_chain = NULL;
92     POSIX_GUARD_PTR(cert_chain = malloc(S2N_MAX_TEST_PEM_SIZE));
93     POSIX_GUARD_PTR(private_key = malloc(S2N_MAX_TEST_PEM_SIZE));
94     POSIX_GUARD_PTR(client_chain = malloc(S2N_MAX_TEST_PEM_SIZE));
95     POSIX_GUARD_PTR(server_config = s2n_config_new());
96     POSIX_GUARD(s2n_read_test_pem(S2N_RSA_2048_PKCS1_CERT_CHAIN, cert_chain, S2N_MAX_TEST_PEM_SIZE));
97     POSIX_GUARD(s2n_read_test_pem(S2N_RSA_2048_PKCS1_KEY, private_key, S2N_MAX_TEST_PEM_SIZE));
98     POSIX_GUARD(s2n_read_test_pem(S2N_RSA_2048_PKCS1_LEAF_CERT, client_chain, S2N_MAX_TEST_PEM_SIZE));
99 
100     struct s2n_cert_chain_and_key *chain_and_key = NULL;
101     POSIX_GUARD_PTR(chain_and_key = s2n_cert_chain_and_key_new());
102     POSIX_GUARD(s2n_cert_chain_and_key_load_pem(chain_and_key, cert_chain, private_key));
103     POSIX_GUARD(s2n_config_add_cert_chain_and_key_to_store(server_config, chain_and_key));
104     POSIX_GUARD(s2n_connection_set_config(server_conn, server_config));
105 
106     POSIX_GUARD(s2n_choose_sig_scheme_from_peer_preference_list(server_conn, &server_conn->handshake_params.client_sig_hash_algs,
107             &server_conn->handshake_params.conn_sig_scheme));
108 
109     DEFER_CLEANUP(struct s2n_stuffer certificate_in = {0}, s2n_stuffer_free);
110     POSIX_GUARD(s2n_stuffer_alloc(&certificate_in, S2N_MAX_TEST_PEM_SIZE));
111     DEFER_CLEANUP(struct s2n_stuffer certificate_out = {0}, s2n_stuffer_free);
112     POSIX_GUARD(s2n_stuffer_alloc(&certificate_out, S2N_MAX_TEST_PEM_SIZE));
113 
114     struct s2n_blob temp_blob = {0};
115     POSIX_GUARD(s2n_blob_init(&temp_blob, (uint8_t *) client_chain, strlen(client_chain) + 1));
116     POSIX_GUARD(s2n_stuffer_write(&certificate_in, &temp_blob));
117     POSIX_GUARD(s2n_stuffer_certificate_from_pem(&certificate_in, &certificate_out));
118 
119     temp_blob.size = s2n_stuffer_data_available(&certificate_out);
120     temp_blob.data = s2n_stuffer_raw_read(&certificate_out, temp_blob.size);
121     s2n_pkey_type pkey_type = {0};
122     POSIX_GUARD(s2n_asn1der_to_public_key_and_type(&client_conn->handshake_params.server_public_key, &pkey_type, &temp_blob));
123 
124     server_conn->handshake_params.our_chain_and_key = chain_and_key;
125 
126     POSIX_GUARD(setup_connection(server_conn, kem, cipher_suite, cipher_pref_version));
127     POSIX_GUARD(setup_connection(client_conn, kem, cipher_suite, cipher_pref_version));
128 
129 #if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND
130     /* Set the DRBG to the state that was used to generate this test vector. */
131     FILE *kat_file = fopen(kat_file_name, "r");
132     POSIX_GUARD_PTR(kat_file);
133     POSIX_GUARD(ReadHex(kat_file, hybrid_kat_entropy_blob.data, SEED_LENGTH, "seed = "));
134 
135     s2n_stack_blob(personalization_string, SEED_LENGTH, SEED_LENGTH);
136     POSIX_GUARD(s2n_rand_set_callbacks(s2n_hybrid_pq_rand_init, s2n_hybrid_pq_rand_cleanup, s2n_hybrid_pq_entropy,
137             s2n_hybrid_pq_entropy));
138     POSIX_GUARD(s2n_drbg_instantiate(&drbg_for_hybrid_kats, &personalization_string, S2N_AES_256_CTR_NO_DF_PR));
139     POSIX_GUARD_RESULT(s2n_set_private_drbg_for_test(drbg_for_hybrid_kats));
140 #endif
141 
142     /* Part 2 server sends key first */
143     POSIX_GUARD(s2n_server_key_send(server_conn));
144 
145     /* Part 2.1 verify the results as best we can */
146     POSIX_ENSURE_EQ(server_conn->handshake.io.write_cursor, server_key_message_length);
147     struct s2n_blob server_key_message = {.size = server_key_message_length, .data = s2n_stuffer_raw_read(&server_conn->handshake.io, server_key_message_length)};
148 
149 #if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND
150     /* Part 2.1.1 if we're running in known answer mode check the server's key exchange message matches the expected value */
151     uint8_t *expected_server_key_message = NULL;
152     POSIX_GUARD_PTR(expected_server_key_message = malloc(server_key_message_length));
153     POSIX_GUARD(ReadHex(kat_file, expected_server_key_message, server_key_message_length, "expected_server_key_exchange = "));
154 
155     /* Compare byte arrays for equality */
156     POSIX_ENSURE_EQ(memcmp(expected_server_key_message, server_key_message.data, server_key_message_length), 0);
157 #endif
158 
159     /* Part 2.2 copy server's message to the client's stuffer */
160     s2n_stuffer_write(&client_conn->handshake.io, &server_key_message);
161 
162     /* Part 3 client recvs the server's key and sends the client key exchange message */
163     POSIX_GUARD(s2n_server_key_recv(client_conn));
164     POSIX_GUARD(s2n_client_key_send(client_conn));
165 
166     /* Part 3.1 verify the results as best we can */
167     POSIX_ENSURE_EQ(client_conn->handshake.io.write_cursor - client_conn->handshake.io.read_cursor, client_key_message_length);
168     struct s2n_blob client_key_message = {.size = client_key_message_length, .data = s2n_stuffer_raw_read(&client_conn->handshake.io, client_key_message_length)};
169 
170 #if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND
171     /* Part 3.1.1 if we're running in known answer mode check the client's key exchange message matches the expected value */
172     uint8_t *expected_client_key_message = NULL;
173     POSIX_GUARD_PTR(expected_client_key_message = malloc(client_key_message_length));
174     POSIX_GUARD(ReadHex(kat_file, expected_client_key_message, client_key_message_length, "expected_client_key_exchange = "));
175 
176     /* Compare byte arrays for equality */
177     POSIX_ENSURE_EQ(memcmp(expected_client_key_message, client_key_message.data, client_key_message_length), 0);
178 #endif
179 
180     /* Part 3.2 copy the client's message back to the server's stuffer */
181     s2n_stuffer_write(&server_conn->handshake.io, &client_key_message);
182 
183     /* Part 4 server receives the client's message */
184     POSIX_GUARD(s2n_client_key_recv(server_conn));
185 
186     /* Part 4.1 verify results as best we can, the client and server should at least have the same master secret */
187     /* Compare byte arrays for equality */
188     POSIX_ENSURE_EQ(memcmp(server_conn->secrets.master_secret, client_conn->secrets.master_secret, S2N_TLS_SECRET_LEN), 0);
189 
190 #if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND
191     /* Part 4.1.1 if we're running in known answer mode check that both the client and server got the expected master secret
192      * from the RSP_FILE */
193     uint8_t expected_master_secret[S2N_TLS_SECRET_LEN];
194     POSIX_GUARD(ReadHex(kat_file, expected_master_secret, S2N_TLS_SECRET_LEN, "expected_master_secret = "));
195     /* Compare byte arrays for equality */
196     POSIX_ENSURE_EQ(memcmp(expected_master_secret, client_conn->secrets.master_secret, S2N_TLS_SECRET_LEN), 0);
197     POSIX_ENSURE_EQ(memcmp(expected_master_secret, server_conn->secrets.master_secret, S2N_TLS_SECRET_LEN), 0);
198 #endif
199 
200     POSIX_GUARD(s2n_cert_chain_and_key_free(chain_and_key));
201     POSIX_GUARD(s2n_connection_free(client_conn));
202     POSIX_GUARD(s2n_connection_free(server_conn));
203     POSIX_GUARD(s2n_config_free(server_config));
204     POSIX_GUARD(s2n_config_free(client_config));
205     free(cert_chain);
206     free(client_chain);
207     free(private_key);
208 
209 #if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND
210     /* Extra cleanup needed for the known answer test */
211     fclose(kat_file);
212     free(expected_server_key_message);
213     free(expected_client_key_message);
214 #endif
215 
216     return 0;
217 }
218