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 "s2n_testlib.h"
17 #include "utils/s2n_safety.h"
18 #include "tls/s2n_kem.h"
19 #include "tests/testlib/s2n_nist_kats.h"
20 #include "pq-crypto/s2n_pq.h"
21
s2n_kem_recv_ciphertext_fuzz_test_init(const char * kat_file_path,struct s2n_kem_params * kem_params)22 int s2n_kem_recv_ciphertext_fuzz_test_init(const char *kat_file_path, struct s2n_kem_params *kem_params) {
23 POSIX_ENSURE_REF(kat_file_path);
24 POSIX_ENSURE_REF(kem_params);
25 POSIX_ENSURE_REF(kem_params->kem);
26
27 POSIX_GUARD(s2n_alloc(&kem_params->private_key, kem_params->kem->private_key_length));
28 FILE *kat_file = fopen(kat_file_path, "r");
29 POSIX_ENSURE_REF(kat_file);
30 POSIX_GUARD(ReadHex(kat_file, kem_params->private_key.data, kem_params->kem->private_key_length, "sk = "));
31 fclose(kat_file);
32
33 return S2N_SUCCESS;
34 }
35
s2n_kem_recv_ciphertext_fuzz_test(const uint8_t * buf,size_t len,struct s2n_kem_params * kem_params)36 int s2n_kem_recv_ciphertext_fuzz_test(const uint8_t *buf, size_t len, struct s2n_kem_params *kem_params) {
37 POSIX_ENSURE_REF(buf);
38 POSIX_ENSURE_REF(kem_params);
39 POSIX_ENSURE_REF(kem_params->kem);
40
41 DEFER_CLEANUP(struct s2n_stuffer ciphertext = { 0 }, s2n_stuffer_free);
42 POSIX_GUARD(s2n_stuffer_alloc(&ciphertext, len));
43 POSIX_GUARD(s2n_stuffer_write_bytes(&ciphertext, buf, len));
44
45 /* Don't GUARD the call to recv_ciphertext().
46 * recv_ciphertext() parses the would-be ciphertext bytes from the
47 * handshake, then passes them to the KEM's decaps function.
48 * recv_ciphertext() may fail appropriately during parsing if the
49 * ciphertext bytes do not correspond to TLS specification (e.g.
50 * improperly length-encoded).
51 *
52 * All but one of the KEM's decaps functions are written in such
53 * a way that they should never fail, regardless of the input provided
54 * by the fuzzer. If the fuzzer-provided "ciphertext" is not a
55 * valid PQ ciphertext (and it probably won't be), the decaps function
56 * should still succeed and return 0, but the output plaintext will
57 * be garbage. Therefore, if recv_ciphertext() fails for these KEMs,
58 * it should not have been due to S2N_ERR_PQ_CRYPTO.
59 *
60 * The one exception is BIKE1L1R1, which does not guarantee this
61 * property. If provided an invalid ciphertext input, BIKE1L1R1
62 * will likely fail (return non-zero) and set S2N_ERR_PQ_CRYPTO.
63 *
64 * If PQ is not enabled, then recv_ciphertext() should always fail. */
65 int recv_ciphertext_ret = s2n_kem_recv_ciphertext(&ciphertext, kem_params);
66
67 if (s2n_pq_is_enabled() && recv_ciphertext_ret != S2N_SUCCESS && kem_params->kem != &s2n_bike1_l1_r1) {
68 POSIX_ENSURE_NE(s2n_errno, S2N_ERR_PQ_CRYPTO);
69 }
70
71 if (!s2n_pq_is_enabled()) {
72 POSIX_ENSURE_NE(recv_ciphertext_ret, S2N_SUCCESS);
73 }
74
75 /* Shared secret may have been alloc'ed in recv_ciphertext */
76 POSIX_GUARD(s2n_free(&kem_params->shared_secret));
77
78 return S2N_SUCCESS;
79 }
80
s2n_kem_recv_public_key_fuzz_test(const uint8_t * buf,size_t len,struct s2n_kem_params * kem_params)81 int s2n_kem_recv_public_key_fuzz_test(const uint8_t *buf, size_t len, struct s2n_kem_params *kem_params) {
82 POSIX_ENSURE_REF(buf);
83 POSIX_ENSURE_REF(kem_params);
84 POSIX_ENSURE_REF(kem_params->kem);
85
86 DEFER_CLEANUP(struct s2n_stuffer public_key = { 0 }, s2n_stuffer_free);
87 POSIX_GUARD(s2n_stuffer_alloc(&public_key, len));
88 POSIX_GUARD(s2n_stuffer_write_bytes(&public_key, buf, len));
89
90 /* s2n_kem_recv_public_key performs only very basic checks, like ensuring
91 * that the public key size is correct. If the received public key passes,
92 * we continue by calling s2n_kem_send_ciphertext to attempt to use the key
93 * for encryption. */
94 if (s2n_kem_recv_public_key(&public_key, kem_params) == S2N_SUCCESS) {
95 DEFER_CLEANUP(struct s2n_stuffer out = {0}, s2n_stuffer_free);
96 POSIX_GUARD(s2n_stuffer_growable_alloc(&out, 8192));
97 int send_ct_ret = s2n_kem_send_ciphertext(&out, kem_params);
98
99 /* The KEM encaps functions are written in such a way that
100 * s2n_kem_send_ciphertext() should always succeed as long
101 * as PQ is enabled, even if the previously received public
102 * key is not valid. If PQ is not enabled, send_ciphertext()
103 * should always fail because of a PQ crypto errno. */
104 if (s2n_pq_is_enabled()) {
105 POSIX_ENSURE_EQ(send_ct_ret, S2N_SUCCESS);
106 } else {
107 POSIX_ENSURE_NE(send_ct_ret, S2N_SUCCESS);
108 POSIX_ENSURE_EQ(s2n_errno, S2N_ERR_PQ_CRYPTO);
109 }
110 }
111
112 /* Clean up */
113 POSIX_GUARD(s2n_kem_free(kem_params));
114
115 return S2N_SUCCESS;
116 }
117