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