blob: 155285ea340de3d1197310c03d8544261a12abe5 [file] [log] [blame]
// 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 <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>
// 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.
// |Enable| - The enable_if_t helper field.
template <typename FuzzedType, typename Enable = void>
struct FuzzedObject {
// You have to have a specialization for FuzzedObject.
FuzzedObject() = delete;
};
// Generates fuzzed enum.
// If the enum has kMaxValue, the generate value will not exceed it.
template <typename T>
struct FuzzedObject<T, std::enable_if_t<std::is_enum_v<T>>> {
// A helper to check an enum has kMaxValue or not.
template <typename E, typename Enable = void>
struct EnumHasMaxValue {
static constexpr inline bool value = false;
};
template <typename E>
struct EnumHasMaxValue<E, std::void_t<decltype(E::kMaxValue)>> {
static constexpr inline bool value = true;
};
T operator()(FuzzedDataProvider& provider) const {
if constexpr (EnumHasMaxValue<T>::value) {
return provider.ConsumeEnum<T>();
} else {
return static_cast<T>(
provider.ConsumeIntegral<std::underlying_type_t<T>>());
}
}
};
// Generates fuzzed integral.
template <typename T>
struct FuzzedObject<
T,
std::enable_if_t<std::is_integral_v<T> && !std::is_same_v<bool, 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>
struct FuzzedObject<std::vector<T>,
std::enable_if_t<!std::is_same_v<T, uint8_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_