/* * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. This file is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing * permissions and limitations under the License. */ #include "pq-crypto/s2n_pq.h" #include "s2n_testlib.h" #include "tests/testlib/s2n_nist_kats.h" #include "tls/s2n_kem.h" #include "utils/s2n_safety.h" int s2n_kem_recv_ciphertext_fuzz_test_init(const char *kat_file_path, struct s2n_kem_params *kem_params) { POSIX_ENSURE_REF(kat_file_path); POSIX_ENSURE_REF(kem_params); POSIX_ENSURE_REF(kem_params->kem); POSIX_GUARD(s2n_alloc(&kem_params->private_key, kem_params->kem->private_key_length)); FILE *kat_file = fopen(kat_file_path, "r"); POSIX_ENSURE_REF(kat_file); POSIX_GUARD(ReadHex(kat_file, kem_params->private_key.data, kem_params->kem->private_key_length, "sk = ")); fclose(kat_file); return S2N_SUCCESS; } int s2n_kem_recv_ciphertext_fuzz_test(const uint8_t *buf, size_t len, struct s2n_kem_params *kem_params) { POSIX_ENSURE_REF(buf); POSIX_ENSURE_REF(kem_params); POSIX_ENSURE_REF(kem_params->kem); DEFER_CLEANUP(struct s2n_stuffer ciphertext = { 0 }, s2n_stuffer_free); POSIX_GUARD(s2n_stuffer_alloc(&ciphertext, len)); POSIX_GUARD(s2n_stuffer_write_bytes(&ciphertext, buf, len)); /* Don't GUARD the call to recv_ciphertext(). * recv_ciphertext() parses the would-be ciphertext bytes from the * handshake, then passes them to the KEM's decaps function. * recv_ciphertext() may fail appropriately during parsing if the * ciphertext bytes do not correspond to TLS specification (e.g. * improperly length-encoded). * * All but one of the KEM's decaps functions are written in such * a way that they should never fail, regardless of the input provided * by the fuzzer. If the fuzzer-provided "ciphertext" is not a * valid PQ ciphertext (and it probably won't be), the decaps function * should still succeed and return 0, but the output plaintext will * be garbage. Therefore, if recv_ciphertext() fails for these KEMs, * it should not have been due to S2N_ERR_PQ_CRYPTO. * * If PQ is not enabled, then recv_ciphertext() should always fail. */ int recv_ciphertext_ret = s2n_kem_recv_ciphertext(&ciphertext, kem_params); if (s2n_pq_is_enabled() && recv_ciphertext_ret != S2N_SUCCESS) { POSIX_ENSURE_NE(s2n_errno, S2N_ERR_PQ_CRYPTO); } if (!s2n_pq_is_enabled()) { POSIX_ENSURE_NE(recv_ciphertext_ret, S2N_SUCCESS); } /* Shared secret may have been alloc'ed in recv_ciphertext */ POSIX_GUARD(s2n_free(&kem_params->shared_secret)); return S2N_SUCCESS; } int s2n_kem_recv_public_key_fuzz_test(const uint8_t *buf, size_t len, struct s2n_kem_params *kem_params) { POSIX_ENSURE_REF(buf); POSIX_ENSURE_REF(kem_params); POSIX_ENSURE_REF(kem_params->kem); DEFER_CLEANUP(struct s2n_stuffer public_key = { 0 }, s2n_stuffer_free); POSIX_GUARD(s2n_stuffer_alloc(&public_key, len)); POSIX_GUARD(s2n_stuffer_write_bytes(&public_key, buf, len)); /* s2n_kem_recv_public_key performs only very basic checks, like ensuring * that the public key size is correct. If the received public key passes, * we continue by calling s2n_kem_send_ciphertext to attempt to use the key * for encryption. */ if (s2n_kem_recv_public_key(&public_key, kem_params) == S2N_SUCCESS) { DEFER_CLEANUP(struct s2n_stuffer out = { 0 }, s2n_stuffer_free); POSIX_GUARD(s2n_stuffer_growable_alloc(&out, 8192)); int send_ct_ret = s2n_kem_send_ciphertext(&out, kem_params); /* The KEM encaps functions are written in such a way that * s2n_kem_send_ciphertext() should always succeed as long * as PQ is enabled, even if the previously received public * key is not valid. If PQ is not enabled, send_ciphertext() * should always fail because of a PQ crypto errno. */ if (s2n_pq_is_enabled()) { POSIX_ENSURE_EQ(send_ct_ret, S2N_SUCCESS); } else { POSIX_ENSURE_NE(send_ct_ret, S2N_SUCCESS); POSIX_ENSURE_EQ(s2n_errno, S2N_ERR_PQ_CRYPTO); } } /* Clean up */ POSIX_GUARD(s2n_kem_free(kem_params)); return S2N_SUCCESS; }