| // Copyright 2022 The ChromiumOS Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef LIBHWSEC_FUZZED_BASIC_OBJECTS_H_ | |
| #define LIBHWSEC_FUZZED_BASIC_OBJECTS_H_ | |
| #include <concepts> | |
| #include <map> | |
| #include <optional> | |
| #include <set> | |
| #include <string> | |
| #include <type_traits> | |
| #include <utility> | |
| #include <variant> | |
| #include <vector> | |
| #include <absl/container/flat_hash_map.h> | |
| #include <absl/container/flat_hash_set.h> | |
| #include <base/notreached.h> | |
| #include <base/time/time.h> | |
| #include <brillo/secure_blob.h> | |
| #include <crypto/scoped_openssl_types.h> | |
| #include <fuzzer/FuzzedDataProvider.h> | |
| #include <libhwsec-foundation/crypto/big_num_util.h> | |
| #include <libhwsec-foundation/crypto/elliptic_curve.h> | |
| #include <libhwsec-foundation/crypto/sha.h> | |
| #include <libhwsec-foundation/utility/concepts.h> | |
| // This file contains the fuzzed generator for basic objects. | |
| // The basic type means primitive type or everything that is belong to "std", | |
| // "absl", "base", "brillo" namespaces. | |
| namespace hwsec { | |
| // FuzzedObject would generate a fuzzed data from the input type. | |
| // | |
| // Template parameters: | |
| // |FuzzedType| - The type of the data to be generate. | |
| template <typename FuzzedType> | |
| struct FuzzedObject { | |
| // You have to have a specialization for FuzzedObject. | |
| FuzzedObject() = delete; | |
| }; | |
| // Generates fuzzed enum with the max value. | |
| template <typename T> | |
| requires(hwsec_foundation::EnumTypeWithMaxValue<T>) | |
| struct FuzzedObject<T> { | |
| T operator()(FuzzedDataProvider& provider) const { | |
| return provider.ConsumeEnum<T>(); | |
| } | |
| }; | |
| // Generates fuzzed enum without max value. | |
| template <typename T> | |
| requires(hwsec_foundation::EnumTypeWithoutMaxValue<T>) | |
| struct FuzzedObject<T> { | |
| T operator()(FuzzedDataProvider& provider) const { | |
| return static_cast<T>( | |
| provider.ConsumeIntegral<std::underlying_type_t<T>>()); | |
| } | |
| }; | |
| // Generates fuzzed integral. | |
| template <typename T> | |
| requires(std::integral<T> && !std::same_as<T, bool>) | |
| struct FuzzedObject<T> { | |
| T operator()(FuzzedDataProvider& provider) const { | |
| return provider.ConsumeIntegral<T>(); | |
| } | |
| }; | |
| // Generates fuzzed bool. | |
| template <> | |
| struct FuzzedObject<bool> { | |
| bool operator()(FuzzedDataProvider& provider) const { | |
| return provider.ConsumeBool(); | |
| } | |
| }; | |
| // Generates fuzzed brillo::SecureBlob. | |
| template <> | |
| struct FuzzedObject<brillo::SecureBlob> { | |
| brillo::SecureBlob operator()(FuzzedDataProvider& provider) const { | |
| return brillo::SecureBlob(provider.ConsumeRandomLengthString()); | |
| } | |
| }; | |
| // Generates fuzzed brillo::Blob. | |
| template <> | |
| struct FuzzedObject<brillo::Blob> { | |
| brillo::Blob operator()(FuzzedDataProvider& provider) const { | |
| return brillo::BlobFromString(provider.ConsumeRandomLengthString()); | |
| } | |
| }; | |
| // Generates fuzzed std::string. | |
| template <> | |
| struct FuzzedObject<std::string> { | |
| std::string operator()(FuzzedDataProvider& provider) const { | |
| return provider.ConsumeRandomLengthString(); | |
| } | |
| }; | |
| // Generates fuzzed std::set. | |
| template <typename T> | |
| struct FuzzedObject<std::set<T>> { | |
| std::set<T> operator()(FuzzedDataProvider& provider) const { | |
| std::set<T> result; | |
| for (auto& data : FuzzedObject<std::vector<T>>()(provider)) { | |
| result.insert(std::move(data)); | |
| } | |
| return result; | |
| } | |
| }; | |
| // Generates fuzzed std::map. | |
| template <typename T, typename U> | |
| struct FuzzedObject<std::map<T, U>> { | |
| std::map<T, U> operator()(FuzzedDataProvider& provider) const { | |
| std::map<T, U> result; | |
| while (provider.ConsumeBool()) { | |
| result.insert({FuzzedObject<T>()(provider), FuzzedObject<U>()(provider)}); | |
| } | |
| return result; | |
| } | |
| }; | |
| // Generates fuzzed absl::flat_hash_set. | |
| template <typename T> | |
| struct FuzzedObject<absl::flat_hash_set<T>> { | |
| absl::flat_hash_set<T> operator()(FuzzedDataProvider& provider) const { | |
| absl::flat_hash_set<T> result; | |
| for (auto& data : FuzzedObject<std::vector<T>>()(provider)) { | |
| result.insert(std::move(data)); | |
| } | |
| return result; | |
| } | |
| }; | |
| // Generates fuzzed absl::flat_hash_map. | |
| template <typename T, typename U> | |
| struct FuzzedObject<absl::flat_hash_map<T, U>> { | |
| absl::flat_hash_map<T, U> operator()(FuzzedDataProvider& provider) const { | |
| absl::flat_hash_map<T, U> result; | |
| for (auto& [key, value] : FuzzedObject<std::map<T, U>>()(provider)) { | |
| result.insert({key, std::move(value)}); | |
| } | |
| return result; | |
| } | |
| }; | |
| // Generates fuzzed std::vector. | |
| // Excludes the uint8_t variant, because it's covered by brillo::Blob. | |
| template <typename T> | |
| requires(!std::same_as<T, uint8_t>) | |
| struct FuzzedObject<std::vector<T>> { | |
| std::vector<T> operator()(FuzzedDataProvider& provider) const { | |
| std::vector<T> result; | |
| while (provider.ConsumeBool()) { | |
| result.push_back(FuzzedObject<T>()(provider)); | |
| } | |
| return result; | |
| } | |
| }; | |
| // Generates fuzzed std::optional. | |
| template <typename T> | |
| struct FuzzedObject<std::optional<T>> { | |
| std::optional<T> operator()(FuzzedDataProvider& provider) const { | |
| if (!provider.ConsumeBool()) { | |
| return std::nullopt; | |
| } | |
| return FuzzedObject<T>()(provider); | |
| } | |
| }; | |
| // Generates fuzzed std::monostate. | |
| template <> | |
| struct FuzzedObject<std::monostate> { | |
| std::monostate operator()(FuzzedDataProvider& provider) const { | |
| return std::monostate(); | |
| } | |
| }; | |
| // Generates fuzzed std::variant. | |
| template <typename... VariantArgs> | |
| struct FuzzedObject<std::variant<VariantArgs...>> { | |
| using Variant = std::variant<VariantArgs...>; | |
| Variant operator()(FuzzedDataProvider& provider) const { | |
| size_t idx = | |
| provider.ConsumeIntegralInRange<size_t>(0, sizeof...(VariantArgs) - 1); | |
| return (*this)(provider, idx, std::index_sequence_for<VariantArgs...>{}); | |
| } | |
| Variant operator()(FuzzedDataProvider& provider, | |
| size_t idx, | |
| std::index_sequence<> int_seq) const { | |
| NOTREACHED() << "Should not reach here."; | |
| // We should not reach here. | |
| return FuzzedObject<Variant>()(provider); | |
| } | |
| template <size_t Index, size_t... RemainingIndexes> | |
| Variant operator()( | |
| FuzzedDataProvider& provider, | |
| size_t idx, | |
| std::index_sequence<Index, RemainingIndexes...> int_seq) const { | |
| if (idx == Index) { | |
| return FuzzedObject<std::variant_alternative_t<Index, Variant>>()( | |
| provider); | |
| } | |
| return (*this)(provider, idx, std::index_sequence<RemainingIndexes...>{}); | |
| } | |
| }; | |
| template <> | |
| struct FuzzedObject<crypto::ScopedEC_POINT> { | |
| crypto::ScopedEC_POINT operator()(FuzzedDataProvider& provider) const { | |
| if (provider.ConsumeBool()) { | |
| return nullptr; | |
| } | |
| hwsec_foundation::ScopedBN_CTX context = | |
| hwsec_foundation::CreateBigNumContext(); | |
| std::optional<hwsec_foundation::EllipticCurve> ec_256 = | |
| hwsec_foundation::EllipticCurve::Create( | |
| hwsec_foundation::EllipticCurve::CurveType::kPrime256, | |
| context.get()); | |
| CHECK(ec_256.has_value()); | |
| crypto::ScopedBIGNUM private_key = hwsec_foundation::SecureBlobToBigNum( | |
| hwsec_foundation::Sha256(FuzzedObject<brillo::SecureBlob>()(provider))); | |
| return ec_256->MultiplyWithGenerator(*private_key, context.get()); | |
| } | |
| }; | |
| template <> | |
| struct FuzzedObject<base::TimeDelta> { | |
| base::TimeDelta operator()(FuzzedDataProvider& provider) const { | |
| return base::Microseconds(provider.ConsumeIntegral<int64_t>()); | |
| } | |
| }; | |
| } // namespace hwsec | |
| #endif // LIBHWSEC_FUZZED_BASIC_OBJECTS_H_ |