blob: 6d723cf28b2e4239f8c686c6d97320030c8591eb [file] [log] [blame]
#include <cstddef>
#include <cstdint>
#include <pw_fuzzer/fuzztest.h>
#include <pw_unit_test/framework.h>
#include "credentials/CHIPCert.h"
namespace {
using namespace chip;
using namespace chip::Credentials;
using namespace fuzztest;
/*----------------------------------- Helper Functions: Seed Providers -----------------------------------*/
/******************************************************************************************************************* */
const std::string OpCertsDir = "credentials/test/operational-certificates-error-cases/";
auto isChipFile = [](std::string_view name) { return absl::EndsWith(name, ".chip"); };
auto isDerFile = [](std::string_view name) { return absl::EndsWith(name, ".der"); };
auto isChipRCACFile = [](std::string_view name) { return absl::StrContains(name, "RCAC") && absl::EndsWith(name, ".chip"); };
// Lambda that reads certificates from a directory and returns them as a vector of strings, to be used as seeds
auto seedProvider = [](auto filterFunction) -> std::vector<std::string> {
// fuzztest::ReadFilesFromDirectory returns a vector of tuples, each tuple contains a file
// We need to unpack the tuples and then extract file content into a vector of strings.
std::vector<std::tuple<std::string>> tupleVector = ReadFilesFromDirectory(OpCertsDir, filterFunction);
std::vector<std::string> seeds;
if (tupleVector.size() == 0)
{
std::cout << "No Matching Seed files found in the chosen directory" << std::endl;
}
// DEBUG TIP: print tupleVector.size() here to check that we have the correct number of files as seeds.
for (auto & [fileContents] : tupleVector)
{
seeds.push_back(fileContents);
}
return seeds;
};
void ChipCertFuzzer(const std::string & fuzzChipCerts)
{
ByteSpan span(reinterpret_cast<const uint8_t *>(fuzzChipCerts.data()), fuzzChipCerts.size());
{
NodeId nodeId;
FabricId fabricId;
RETURN_SAFELY_IGNORED ExtractFabricIdFromCert(span, &fabricId);
RETURN_SAFELY_IGNORED ExtractNodeIdFabricIdFromOpCert(span, &nodeId, &fabricId);
}
{
CATValues cats;
RETURN_SAFELY_IGNORED ExtractCATsFromOpCert(span, cats);
}
}
FUZZ_TEST(FuzzChipCert, ChipCertFuzzer).WithDomains(Arbitrary<std::string>().WithSeeds(seedProvider(isChipFile)));
/*----------------------------------- Chip Cert FuzzTests -----------------------------------*/
/******************************************************************************************************************* */
// The Property function for DecodeChipCertFuzzer, The FUZZ_TEST Macro will call this function.
void DecodeChipCertFuzzer(const std::string & fuzzChipCerts, BitFlags<CertDecodeFlags> aDecodeFlag)
{
// TODO: #34352 To Move this to a Fixture once Errors related to FuzzTest Fixtures are resolved
ASSERT_EQ(chip::Platform::MemoryInit(), CHIP_NO_ERROR);
{
ByteSpan span(reinterpret_cast<const uint8_t *>(fuzzChipCerts.data()), fuzzChipCerts.size());
ChipCertificateData certData;
RETURN_SAFELY_IGNORED DecodeChipCert(span, certData, aDecodeFlag);
}
chip::Platform::MemoryShutdown();
}
// This function allows us to fuzz using one of three CertDecodeFlags flags; by using FuzzTests's `ElementOf` API, we define an
// input domain by explicitly enumerating the set of values in it More Info:
// https://github.com/google/fuzztest/blob/main/doc/domains-reference.md#elementof-domains-element-of
auto AnyCertDecodeFlag()
{
constexpr BitFlags<CertDecodeFlags> NullDecodeFlag;
constexpr BitFlags<CertDecodeFlags> GenTBSHashFlag(CertDecodeFlags::kGenerateTBSHash);
constexpr BitFlags<CertDecodeFlags> TrustAnchorFlag(CertDecodeFlags::kIsTrustAnchor);
return ElementOf<CertDecodeFlags>({ NullDecodeFlag, GenTBSHashFlag, TrustAnchorFlag });
}
FUZZ_TEST(FuzzChipCert, DecodeChipCertFuzzer)
.WithDomains(Arbitrary<std::string>().WithSeeds(seedProvider(isChipFile)), AnyCertDecodeFlag());
/*************************************** */
void ConvertChipCertToX509CertFuzz(const std::string & fuzzChipCerts)
{
ByteSpan span(reinterpret_cast<const uint8_t *>(fuzzChipCerts.data()), fuzzChipCerts.size());
uint8_t outCertBuf[kMaxDERCertLength];
MutableByteSpan outCert(outCertBuf);
RETURN_SAFELY_IGNORED ConvertChipCertToX509Cert(span, outCert);
}
FUZZ_TEST(FuzzChipCert, ConvertChipCertToX509CertFuzz).WithDomains(Arbitrary<std::string>().WithSeeds(seedProvider(isChipFile)));
/******************************************************************************** */
/******************************************************************************** */
void ValidateChipRCACFuzz(const std::string & fuzzRcacCerts)
{
// TODO: #35369 Move this to a Fixture once Errors related to FuzzTest Fixtures are resolved
ASSERT_EQ(chip::Platform::MemoryInit(), CHIP_NO_ERROR);
{
ByteSpan span(reinterpret_cast<const uint8_t *>(fuzzRcacCerts.data()), fuzzRcacCerts.size());
RETURN_SAFELY_IGNORED ValidateChipRCAC(span);
}
chip::Platform::MemoryShutdown();
}
FUZZ_TEST(FuzzChipCert, ValidateChipRCACFuzz).WithDomains(Arbitrary<std::string>().WithSeeds(seedProvider(isChipRCACFile)));
/*----------------------------------- DER Cert FuzzTests -----------------------------------*/
/******************************************************************************** */
void ConvertX509CertToChipCertFuzz(const std::string & fuzzDerCerts)
{
ByteSpan span(reinterpret_cast<const uint8_t *>(fuzzDerCerts.data()), fuzzDerCerts.size());
uint8_t outCertBuf[kMaxDERCertLength];
MutableByteSpan outCert(outCertBuf);
RETURN_SAFELY_IGNORED ConvertX509CertToChipCert(span, outCert);
}
FUZZ_TEST(FuzzChipCert, ConvertX509CertToChipCertFuzz).WithDomains(Arbitrary<std::string>().WithSeeds(seedProvider(isDerFile)));
/******************************************************************************** */
/******************************************************************************** */
void ExtractSubjectDNFromX509CertFuzz(const std::string & fuzzDerCerts)
{
ByteSpan span(reinterpret_cast<const uint8_t *>(fuzzDerCerts.data()), fuzzDerCerts.size());
ChipDN subjectDN;
RETURN_SAFELY_IGNORED ExtractSubjectDNFromX509Cert(span, subjectDN);
}
FUZZ_TEST(FuzzChipCert, ExtractSubjectDNFromX509CertFuzz).WithDomains(Arbitrary<std::string>().WithSeeds(seedProvider(isDerFile)));
} // namespace