| #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; |
| (void) ExtractFabricIdFromCert(span, &fabricId); |
| (void) ExtractNodeIdFabricIdFromOpCert(span, &nodeId, &fabricId); |
| } |
| |
| { |
| CATValues cats; |
| (void) 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; |
| (void) 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); |
| (void) 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()); |
| 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); |
| |
| 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; |
| ExtractSubjectDNFromX509Cert(span, subjectDN); |
| } |
| FUZZ_TEST(FuzzChipCert, ExtractSubjectDNFromX509CertFuzz).WithDomains(Arbitrary<std::string>().WithSeeds(seedProvider(isDerFile))); |
| |
| } // namespace |