blob: f7dadb6b4951a85f66c57704b025c705dea19a12 [file] [log] [blame]
// Copyright 2022 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fuzzer/FuzzedDataProvider.h>
#include <base/logging.h>
#include <base/test/task_environment.h>
#include <chaps/proto_bindings/ck_structs.pb.h>
#include <trunks/fuzzed_command_transceiver.h>
#include <trunks/trunks_factory_impl.h>
#include <vector>
#include <base/command_line.h>
#include <base/test/test_timeouts.h>
#include "chaps/attributes.h"
#include "chaps/chaps_factory_impl.h"
#include "chaps/chaps_interface.h"
#include "chaps/chaps_service.h"
#include "chaps/fuzzers/fuzzed_tpm_manager_utility.h"
#include "chaps/isolate.h"
#include "chaps/session.h"
#include "chaps/slot_manager_impl.h"
#include "chaps/tpm2_utility_impl.h"
#include "chaps/tpm_thread_utility_impl.h"
namespace {
enum class ChapsServiceRequest {
kGetSlotList,
kGetSlotInfo,
kGetTokenInfo,
kGetMechanismList,
kGetMechanismInfo,
kInitToken,
kInitPIN,
kSetPIN,
kOpenSession,
kCloseSession,
kGetSessionInfo,
kGetOperationState,
kSetOperationState,
kLogin,
kLogout,
kCreateObject,
kCopyObject,
kDestroyObject,
kGetObjectSize,
kGetAttributeValue,
kSetAttributeValue,
kFindObjectsInit,
kFindObjects,
kFindObjectsFinal,
kEncryptInit,
kEncrypt,
kEncryptUpdate,
kEncryptFinal,
kEncryptCancel,
kDecryptInit,
kDecrypt,
kDecryptUpdate,
kDecryptFinal,
kDecryptCancel,
kDigestInit,
kDigest,
kDigestUpdate,
kDigestKey,
kDigestFinal,
kDigestCancel,
kSignInit,
kSign,
kSignUpdate,
kSignFinal,
kSignCancel,
kSignRecoverInit,
kSignRecover,
kVerifyInit,
kVerify,
kVerifyUpdate,
kVerifyFinal,
kVerifyCancel,
kVerifyRecoverInit,
kVerifyRecover,
kDigestEncryptUpdate,
kDecryptDigestUpdate,
kSignEncryptUpdate,
kDecryptVerifyUpdate,
kGenerateKey,
kGenerateKeyPair,
kWrapKey,
kUnwrapKey,
kDeriveKey,
kSeedRandom,
kGenerateRandom,
kMaxValue = kGenerateRandom,
};
enum class TokenManagerInterfaceRequest {
kOpenIsolate,
kCloseIsolate,
kLoadToken,
kUnloadToken,
kChangeTokenAuthData,
kGetTokenPath,
kMaxValue = kGetTokenPath,
};
// An arbitrary choice that provides satisfactory coverage
constexpr size_t kMaxTpmMessageLength = 2048;
constexpr int kSuccessProbability = 90;
constexpr int kChapsServiceProbability = 90;
// Provide max iterations for a single fuzz run, otherwise it might timeout.
constexpr int kMaxIterations = 100;
constexpr uint64_t kSmallLen = 10;
constexpr uint64_t kLargeLen = 100000;
constexpr uint64_t kUserTypes[4] = {CKU_SO, CKU_USER, CKU_CONTEXT_SPECIFIC,
3 /*invalid user type*/};
constexpr uint64_t kMechanismTypes[5] = {
// CKF_GENERATE_KEY_PAIR | CKF_HW
CKM_RSA_PKCS_KEY_PAIR_GEN,
// CKF_HW | CKF_ENCRYPT | CKF_DECRYPT | CKF_SIGN | CKF_VERIFY
CKM_RSA_PKCS,
// CKF_DIGEST
CKM_MD5,
// CKF_GENERATE
CKM_GENERIC_SECRET_KEY_GEN,
// Not used
CKM_RSA_9796};
bool SerializeAttributes(CK_ATTRIBUTE_PTR attributes,
CK_ULONG num_attributes,
std::vector<uint8_t>* serialized) {
chaps::Attributes tmp(attributes, num_attributes);
return tmp.Serialize(serialized);
}
class ChapsServiceFuzzer {
public:
explicit ChapsServiceFuzzer(FuzzedDataProvider* tpm_data_provider,
FuzzedDataProvider* data_provider)
: data_provider_(data_provider) {
chaps_metrics_ = std::make_unique<chaps::ChapsMetrics>();
factory_ = std::make_unique<chaps::ChapsFactoryImpl>(chaps_metrics_.get());
command_transceiver_ = std::make_unique<trunks::FuzzedCommandTransceiver>(
tpm_data_provider, kMaxTpmMessageLength);
trunks_factory_ =
std::make_unique<trunks::TrunksFactoryImpl>(command_transceiver_.get());
if (!trunks_factory_->Initialize()) {
LOG(ERROR) << "Failed to initialize TrunksFactory.";
}
tpm_manager_utility_ =
std::make_unique<chaps::FuzzedTpmManagerUtility>(tpm_data_provider);
auto tpm_utility =
std::make_unique<chaps::TPM2UtilityImpl>(trunks_factory_.get());
tpm_utility->set_tpm_manager_utility_for_testing(
tpm_manager_utility_.get());
tpm_utility_ =
std::make_unique<chaps::TPMThreadUtilityImpl>(std::move(tpm_utility));
bool auto_load_system_token = data_provider_->ConsumeBool();
slot_manager_ = std::make_unique<chaps::SlotManagerImpl>(
factory_.get(), tpm_utility_.get(), auto_load_system_token, nullptr,
chaps_metrics_.get());
chaps_service_ =
std::make_unique<chaps::ChapsServiceImpl>(slot_manager_.get());
generated_isolate_credentials_.push_back(
chaps::IsolateCredentialManager::GetDefaultIsolateCredential()
.to_string());
if (ConsumeProbability(kSuccessProbability)) {
CreateObject(GetObjectAttribute());
CreateObject(GetEncryptKeyAttribute());
CreateObject(GetDigestKeyAttribute());
CreateObject(GetSignKeyAttribute());
}
}
~ChapsServiceFuzzer() {
chaps_service_.reset();
slot_manager_.reset();
tpm_utility_.reset();
tpm_manager_utility_.reset();
trunks_factory_.reset();
factory_.reset();
chaps_metrics_.reset();
}
void Run() {
int rounds = 0;
while (data_provider_->remaining_bytes() > 0 && rounds < kMaxIterations) {
if (ConsumeProbability(kChapsServiceProbability)) {
FuzzChapsServiceRequest();
} else {
FuzzTokenManagerInterfaceRequest();
}
task_environment_.RunUntilIdle();
rounds++;
}
}
private:
void FuzzChapsServiceRequest() {
auto request = data_provider_->ConsumeEnum<ChapsServiceRequest>();
LOG(INFO) << "chaps service request: " << static_cast<int>(request);
switch (request) {
case ChapsServiceRequest::kGetSlotList: {
std::vector<uint64_t> slot_list;
chaps_service_->GetSlotList(GetIsolateCredential(),
data_provider_->ConsumeBool(), &slot_list);
break;
}
case ChapsServiceRequest::kGetSlotInfo: {
chaps::SlotInfo slot_info;
chaps_service_->GetSlotInfo(GetIsolateCredential(), GetSlotId(),
&slot_info);
break;
}
case ChapsServiceRequest::kGetTokenInfo: {
chaps::TokenInfo token_info;
chaps_service_->GetTokenInfo(GetIsolateCredential(), GetSlotId(),
&token_info);
break;
}
case ChapsServiceRequest::kGetMechanismList: {
std::vector<uint64_t> mechanism_list;
chaps_service_->GetMechanismList(GetIsolateCredential(), GetSlotId(),
&mechanism_list);
break;
}
case ChapsServiceRequest::kGetMechanismInfo: {
chaps::MechanismInfo mechanism_info;
uint64_t mechanism_type =
data_provider_->PickValueInArray(kMechanismTypes);
chaps_service_->GetMechanismInfo(GetIsolateCredential(), GetSlotId(),
mechanism_type, &mechanism_info);
break;
}
case ChapsServiceRequest::kInitToken: {
const std::vector<uint8_t> label(32);
chaps_service_->InitToken(GetIsolateCredential(), GetSlotId(),
/*so_pin=*/nullptr, label);
break;
}
case ChapsServiceRequest::kInitPIN: {
chaps_service_->InitPIN(GetIsolateCredential(), GetSessionId(),
/*pin=*/nullptr);
break;
}
case ChapsServiceRequest::kSetPIN: {
chaps_service_->SetPIN(GetIsolateCredential(), GetSessionId(),
/*old_pin=*/nullptr, /*new_pin=*/nullptr);
break;
}
case ChapsServiceRequest::kOpenSession: {
OpenSession();
break;
}
case ChapsServiceRequest::kCloseSession: {
chaps_service_->CloseSession(GetIsolateCredential(), GetSessionId());
break;
}
case ChapsServiceRequest::kGetSessionInfo: {
chaps::SessionInfo session_info;
chaps_service_->GetSessionInfo(GetIsolateCredential(), GetSessionId(),
&session_info);
break;
}
case ChapsServiceRequest::kGetOperationState: {
std::vector<uint8_t> operation_state;
chaps_service_->GetOperationState(GetIsolateCredential(),
GetSessionId(), &operation_state);
break;
}
case ChapsServiceRequest::kSetOperationState: {
const std::vector<uint8_t> operation_state;
chaps_service_->SetOperationState(
GetIsolateCredential(), GetSessionId(), operation_state,
/*encryption_key_handle=*/0, /*authentication_key_handle=*/0);
break;
}
case ChapsServiceRequest::kLogin: {
uint64_t user_type = data_provider_->PickValueInArray(kUserTypes);
std::string legacy_pin = std::string("111111");
chaps_service_->Login(
GetIsolateCredential(), GetSessionId(), user_type,
/*pin=*/data_provider_->ConsumeBool() ? nullptr : &legacy_pin);
break;
}
case ChapsServiceRequest::kLogout: {
chaps_service_->Logout(GetIsolateCredential(), GetSessionId());
break;
}
case ChapsServiceRequest::kCreateObject: {
CreateRandomObject();
break;
}
case ChapsServiceRequest::kCopyObject: {
auto attributes = data_provider_->ConsumeBytes<uint8_t>(
data_provider_->ConsumeIntegralInRange(0, 10));
uint64_t new_object_handle;
if (chaps_service_->CopyObject(GetIsolateCredential(), GetSessionId(),
GetObjectHandle(), attributes,
&new_object_handle) == CKR_OK) {
generated_object_handles_.push_back(new_object_handle);
}
break;
}
case ChapsServiceRequest::kDestroyObject: {
chaps_service_->DestroyObject(GetIsolateCredential(), GetSessionId(),
GetObjectHandle());
break;
}
case ChapsServiceRequest::kGetObjectSize: {
uint64_t object_size;
chaps_service_->GetObjectSize(GetIsolateCredential(), GetSessionId(),
GetObjectHandle(), &object_size);
break;
}
case ChapsServiceRequest::kGetAttributeValue: {
auto attributes_in = data_provider_->ConsumeBytes<uint8_t>(
data_provider_->ConsumeIntegralInRange(0, 10));
std::vector<uint8_t> attributes_out;
chaps_service_->GetAttributeValue(GetIsolateCredential(),
GetSessionId(), GetObjectHandle(),
attributes_in, &attributes_out);
break;
}
case ChapsServiceRequest::kSetAttributeValue: {
auto attributes = data_provider_->ConsumeBytes<uint8_t>(
data_provider_->ConsumeIntegralInRange(0, 10));
chaps_service_->SetAttributeValue(GetIsolateCredential(),
GetSessionId(), GetObjectHandle(),
attributes);
break;
}
case ChapsServiceRequest::kFindObjectsInit: {
auto attributes = data_provider_->ConsumeBytes<uint8_t>(
data_provider_->ConsumeIntegralInRange(0, 10));
chaps_service_->FindObjectsInit(GetIsolateCredential(), GetSessionId(),
attributes);
break;
}
case ChapsServiceRequest::kFindObjects: {
std::vector<uint64_t> object_list;
chaps_service_->FindObjects(
GetIsolateCredential(), GetSessionId(),
/*max_object_count=*/data_provider_->ConsumeIntegralInRange(0, 5),
&object_list);
break;
}
case ChapsServiceRequest::kFindObjectsFinal: {
chaps_service_->FindObjectsFinal(GetIsolateCredential(),
GetSessionId());
break;
}
case ChapsServiceRequest::kEncryptInit: {
uint64_t mechanism_type =
data_provider_->PickValueInArray(kMechanismTypes);
chaps_service_->EncryptInit(
GetIsolateCredential(), GetSessionId(),
mechanism_type, /*mechanism_parameter=*/
data_provider_->ConsumeBytes<uint8_t>(
data_provider_->ConsumeIntegralInRange(0, 10)),
GetObjectHandle());
break;
}
case ChapsServiceRequest::kEncrypt: {
std::vector<uint8_t> data_in = ConsumeLowEntropyBytes(GetMaxOutLen());
uint64_t actual_out_length;
std::vector<uint8_t> data_out;
chaps_service_->Encrypt(GetIsolateCredential(), GetSessionId(), data_in,
GetMaxOutLen(), &actual_out_length, &data_out);
break;
}
case ChapsServiceRequest::kEncryptUpdate: {
std::vector<uint8_t> data_in = ConsumeLowEntropyBytes(GetMaxOutLen());
uint64_t actual_out_length;
std::vector<uint8_t> data_out;
chaps_service_->EncryptUpdate(GetIsolateCredential(), GetSessionId(),
data_in, GetMaxOutLen(),
&actual_out_length, &data_out);
break;
}
case ChapsServiceRequest::kEncryptFinal: {
uint64_t actual_out_length;
std::vector<uint8_t> data_out;
chaps_service_->EncryptFinal(GetIsolateCredential(), GetSessionId(),
GetMaxOutLen(), &actual_out_length,
&data_out);
break;
}
case ChapsServiceRequest::kEncryptCancel: {
chaps_service_->EncryptCancel(GetIsolateCredential(), GetSessionId());
break;
}
case ChapsServiceRequest::kDecryptInit: {
uint64_t mechanism_type =
data_provider_->PickValueInArray(kMechanismTypes);
chaps_service_->DecryptInit(
GetIsolateCredential(), GetSessionId(),
mechanism_type, /*mechanism_parameter=*/
data_provider_->ConsumeBytes<uint8_t>(
data_provider_->ConsumeIntegralInRange(0, 10)),
GetObjectHandle());
break;
}
case ChapsServiceRequest::kDecrypt: {
std::vector<uint8_t> data_in = ConsumeLowEntropyBytes(GetMaxOutLen());
uint64_t actual_out_length;
std::vector<uint8_t> data_out;
chaps_service_->Decrypt(GetIsolateCredential(), GetSessionId(), data_in,
GetMaxOutLen(), &actual_out_length, &data_out);
break;
}
case ChapsServiceRequest::kDecryptUpdate: {
std::vector<uint8_t> data_in = ConsumeLowEntropyBytes(GetMaxOutLen());
uint64_t actual_out_length;
std::vector<uint8_t> data_out;
chaps_service_->DecryptUpdate(GetIsolateCredential(), GetSessionId(),
data_in, GetMaxOutLen(),
&actual_out_length, &data_out);
break;
}
case ChapsServiceRequest::kDecryptFinal: {
uint64_t actual_out_length;
std::vector<uint8_t> data_out;
chaps_service_->DecryptFinal(GetIsolateCredential(), GetSessionId(),
GetMaxOutLen(), &actual_out_length,
&data_out);
break;
}
case ChapsServiceRequest::kDecryptCancel: {
chaps_service_->DecryptCancel(GetIsolateCredential(), GetSessionId());
break;
}
case ChapsServiceRequest::kDigestInit: {
uint64_t mechanism_type =
data_provider_->PickValueInArray(kMechanismTypes);
chaps_service_->DigestInit(
GetIsolateCredential(), GetSessionId(),
mechanism_type, /*mechanism_parameter=*/
data_provider_->ConsumeBytes<uint8_t>(
data_provider_->ConsumeIntegralInRange(0, 10)));
break;
}
case ChapsServiceRequest::kDigest: {
std::vector<uint8_t> data_in = ConsumeLowEntropyBytes(GetMaxOutLen());
uint64_t actual_out_length;
std::vector<uint8_t> data_out;
chaps_service_->Digest(GetIsolateCredential(), GetSessionId(), data_in,
GetMaxOutLen(), &actual_out_length, &data_out);
break;
}
case ChapsServiceRequest::kDigestUpdate: {
// Just try a zero, a small number, and a large number.
std::vector<uint8_t> data_in = ConsumeLowEntropyBytes(GetMaxOutLen());
chaps_service_->DigestUpdate(GetIsolateCredential(), GetSessionId(),
data_in);
break;
}
case ChapsServiceRequest::kDigestKey: {
chaps_service_->DigestKey(GetIsolateCredential(), GetSessionId(),
GetObjectHandle());
break;
}
case ChapsServiceRequest::kDigestFinal: {
uint64_t actual_out_length;
std::vector<uint8_t> data_out;
chaps_service_->DigestFinal(GetIsolateCredential(), GetSessionId(),
GetMaxOutLen(), &actual_out_length,
&data_out);
break;
}
case ChapsServiceRequest::kDigestCancel: {
chaps_service_->DigestCancel(GetIsolateCredential(), GetSessionId());
break;
}
case ChapsServiceRequest::kSignInit: {
uint64_t mechanism_type =
data_provider_->PickValueInArray(kMechanismTypes);
chaps_service_->SignInit(
GetIsolateCredential(), GetSessionId(),
mechanism_type, /*mechanism_parameter=*/
data_provider_->ConsumeBytes<uint8_t>(
data_provider_->ConsumeIntegralInRange(0, 10)),
GetObjectHandle());
break;
}
case ChapsServiceRequest::kSign: {
std::vector<uint8_t> data_in = ConsumeLowEntropyBytes(GetMaxOutLen());
uint64_t actual_out_length;
std::vector<uint8_t> data_out;
chaps_service_->Sign(GetIsolateCredential(), GetSessionId(), data_in,
GetMaxOutLen(), &actual_out_length, &data_out);
break;
}
case ChapsServiceRequest::kSignUpdate: {
std::vector<uint8_t> data_in = ConsumeLowEntropyBytes(GetMaxOutLen());
chaps_service_->SignUpdate(GetIsolateCredential(), GetSessionId(),
data_in);
break;
}
case ChapsServiceRequest::kSignFinal: {
uint64_t actual_out_length;
std::vector<uint8_t> data_out;
chaps_service_->SignFinal(GetIsolateCredential(), GetSessionId(),
GetMaxOutLen(), &actual_out_length,
&data_out);
break;
}
case ChapsServiceRequest::kSignCancel: {
chaps_service_->SignCancel(GetIsolateCredential(), GetSessionId());
break;
}
case ChapsServiceRequest::kSignRecoverInit: {
uint64_t mechanism_type =
data_provider_->PickValueInArray(kMechanismTypes);
chaps_service_->SignRecoverInit(
GetIsolateCredential(), GetSessionId(),
mechanism_type, /*mechanism_parameter=*/
data_provider_->ConsumeBytes<uint8_t>(
data_provider_->ConsumeIntegralInRange(0, 10)),
GetObjectHandle());
break;
}
case ChapsServiceRequest::kSignRecover: {
std::vector<uint8_t> data_in = ConsumeLowEntropyBytes(GetMaxOutLen());
uint64_t actual_out_length;
std::vector<uint8_t> data_out;
chaps_service_->SignRecover(GetIsolateCredential(), GetSessionId(),
data_in, GetMaxOutLen(), &actual_out_length,
&data_out);
break;
}
case ChapsServiceRequest::kVerifyInit: {
uint64_t mechanism_type =
data_provider_->PickValueInArray(kMechanismTypes);
chaps_service_->VerifyInit(
GetIsolateCredential(), GetSessionId(),
mechanism_type, /*mechanism_parameter=*/
data_provider_->ConsumeBytes<uint8_t>(
data_provider_->ConsumeIntegralInRange(0, 10)),
GetObjectHandle());
break;
}
case ChapsServiceRequest::kVerify: {
std::vector<uint8_t> data = ConsumeLowEntropyRandomLengthBytes(20);
std::vector<uint8_t> signature = ConsumeLowEntropyRandomLengthBytes(20);
chaps_service_->Verify(GetIsolateCredential(), GetSessionId(), data,
signature);
break;
}
case ChapsServiceRequest::kVerifyUpdate: {
std::vector<uint8_t> data_in = ConsumeLowEntropyBytes(GetMaxOutLen());
chaps_service_->VerifyUpdate(GetIsolateCredential(), GetSessionId(),
data_in);
break;
}
case ChapsServiceRequest::kVerifyFinal: {
std::vector<uint8_t> signature = ConsumeLowEntropyRandomLengthBytes(20);
chaps_service_->VerifyFinal(GetIsolateCredential(), GetSessionId(),
signature);
break;
}
case ChapsServiceRequest::kVerifyCancel: {
chaps_service_->VerifyCancel(GetIsolateCredential(), GetSessionId());
break;
}
case ChapsServiceRequest::kVerifyRecoverInit:
case ChapsServiceRequest::kVerifyRecover:
case ChapsServiceRequest::kDigestEncryptUpdate:
case ChapsServiceRequest::kDecryptDigestUpdate:
case ChapsServiceRequest::kSignEncryptUpdate:
case ChapsServiceRequest::kDecryptVerifyUpdate:
// not supported
break;
case ChapsServiceRequest::kGenerateKey: {
// Just cover at least one mechanism that is included in the list. 0 and
// 1 are included and 2 isn't.
auto attributes = data_provider_->ConsumeBytes<uint8_t>(
data_provider_->ConsumeIntegralInRange(0, 10));
uint64_t mechanism_type = data_provider_->ConsumeIntegralInRange(0, 2);
uint64_t key_handle;
chaps_service_->GenerateKey(
GetIsolateCredential(), GetSessionId(),
mechanism_type, /*mechanism_parameter=*/
data_provider_->ConsumeBytes<uint8_t>(
data_provider_->ConsumeIntegralInRange(0, 10)),
attributes, &key_handle);
break;
}
case ChapsServiceRequest::kGenerateKeyPair: {
// Just cover at least one mechanism that is included in the list. 0 and
// 1 are included and 2 isn't.
auto public_attributes = data_provider_->ConsumeBytes<uint8_t>(
data_provider_->ConsumeIntegralInRange(0, 10));
auto private_attributes = data_provider_->ConsumeBytes<uint8_t>(
data_provider_->ConsumeIntegralInRange(0, 10));
uint64_t mechanism_type = data_provider_->ConsumeIntegralInRange(0, 2);
uint64_t public_key_handle;
uint64_t private_key_handle;
chaps_service_->GenerateKeyPair(
GetIsolateCredential(), GetSessionId(),
mechanism_type, /*mechanism_parameter=*/
data_provider_->ConsumeBytes<uint8_t>(
data_provider_->ConsumeIntegralInRange(0, 10)),
public_attributes, private_attributes, &public_key_handle,
&private_key_handle);
break;
}
case ChapsServiceRequest::kWrapKey:
case ChapsServiceRequest::kUnwrapKey:
case ChapsServiceRequest::kDeriveKey:
// not supported
break;
case ChapsServiceRequest::kSeedRandom: {
auto seed = ConsumeLowEntropyRandomLengthBytes(10);
chaps_service_->SeedRandom(GetIsolateCredential(), GetSessionId(),
seed);
break;
}
case ChapsServiceRequest::kGenerateRandom: {
std::vector<uint8_t> random_data;
chaps_service_->GenerateRandom(
GetIsolateCredential(), GetSessionId(),
/*num_bytes=*/
data_provider_->ConsumeIntegralInRange<uint64_t>(0, 1000),
&random_data);
break;
}
default:
break;
}
}
void FuzzTokenManagerInterfaceRequest() {
auto request = data_provider_->ConsumeEnum<TokenManagerInterfaceRequest>();
LOG(INFO) << "token manager request: " << static_cast<int>(request);
switch (request) {
case TokenManagerInterfaceRequest::kOpenIsolate: {
brillo::SecureBlob isolate_credential;
bool new_isolate_created;
if (slot_manager_->OpenIsolate(&isolate_credential,
&new_isolate_created) &&
new_isolate_created) {
generated_isolate_credentials_.push_back(
isolate_credential.to_string());
}
break;
}
case TokenManagerInterfaceRequest::kCloseIsolate: {
slot_manager_->CloseIsolate(GetIsolateCredential());
break;
}
case TokenManagerInterfaceRequest::kLoadToken: {
LoadToken();
break;
}
case TokenManagerInterfaceRequest::kUnloadToken: {
auto path = base::FilePath(ConsumeLowEntropyRandomLengthString(10));
slot_manager_->UnloadToken(GetIsolateCredential(), path);
break;
}
case TokenManagerInterfaceRequest::kChangeTokenAuthData: {
auto path = base::FilePath(ConsumeLowEntropyRandomLengthString(10));
auto old_auth_data =
brillo::SecureBlob(ConsumeLowEntropyRandomLengthString(10));
auto new_auth_data =
brillo::SecureBlob(ConsumeLowEntropyRandomLengthString(10));
slot_manager_->ChangeTokenAuthData(path, old_auth_data, new_auth_data);
break;
}
case TokenManagerInterfaceRequest::kGetTokenPath: {
base::FilePath path;
slot_manager_->GetTokenPath(GetIsolateCredential(), GetSlotId(), &path);
break;
}
}
}
bool ConsumeProbability(uint32_t probability) {
return data_provider_->ConsumeIntegralInRange<uint32_t>(0, 9) * 10 <
probability;
}
std::string ConsumeLowEntropyRandomLengthString(int len) {
return std::string(
data_provider_->ConsumeIntegralInRange<size_t>(0, len - 1),
'0') +
data_provider_->ConsumeBytesAsString(1);
}
std::vector<uint8_t> ConsumeLowEntropyRandomLengthBytes(int len) {
return ConsumeLowEntropyBytes(
data_provider_->ConsumeIntegralInRange<size_t>(1, len));
}
std::vector<uint8_t> ConsumeLowEntropyBytes(int len) {
if (len == 0) {
return std::vector<uint8_t>();
}
std::vector<uint8_t> bytes(len - 1, 0);
bytes.push_back(data_provider_->ConsumeIntegral<uint8_t>());
return bytes;
}
void LoadToken() {
auto path = base::FilePath(ConsumeLowEntropyRandomLengthString(10));
auto auth_data =
brillo::SecureBlob(ConsumeLowEntropyRandomLengthString(10));
std::string label = ConsumeLowEntropyRandomLengthString(10);
int slot_id;
if (slot_manager_->LoadToken(GetIsolateCredential(), path, auth_data, label,
&slot_id)) {
generated_slot_ids_.push_back(slot_id);
}
}
void OpenSession() {
uint64_t session_id;
// Only the three lowest bits are used in flags.
int flags = data_provider_->ConsumeIntegralInRange(0, 7);
if (ConsumeProbability(kSuccessProbability)) {
// For legacy reasons, the CKF_SERIAL_SESSION bit must always be set; if a
// call to C_OpenSession does not have this bit set, the call should
// return unsuccessfully with the error code CKR_PARALLEL_NOT_SUPPORTED.
// Thus setting this bit with high probability.
flags |= CKF_SERIAL_SESSION;
}
if (chaps_service_->OpenSession(GetIsolateCredential(), GetSlotId(), flags,
&session_id) == CKR_OK) {
generated_session_ids_.push_back(session_id);
}
}
void CreateObject(std::vector<uint8_t> attributes) {
uint64_t new_object_handle;
if (chaps_service_->CreateObject(GetIsolateCredential(), GetSessionId(),
attributes,
&new_object_handle) == CKR_OK) {
generated_object_handles_.push_back(new_object_handle);
}
}
void CreateRandomObject() {
CreateObject(data_provider_->ConsumeBytes<uint8_t>(
data_provider_->ConsumeIntegralInRange(0, 10)));
}
uint64_t GetMaxOutLen() {
// Just try a zero, a small number, and a large number.
switch (data_provider_->ConsumeIntegralInRange<int>(0, 2)) {
case 0:
return 0;
case 1:
return kSmallLen;
case 2:
return kLargeLen;
default:
// Not reached.
break;
}
return 0;
}
std::vector<uint8_t> GetObjectAttribute() {
CK_OBJECT_CLASS class_value = CKO_DATA;
CK_UTF8CHAR label[] = "A data object";
CK_UTF8CHAR application[] = "An application";
CK_BYTE data[] = "Sample data";
CK_BBOOL false_value = CK_FALSE;
CK_ATTRIBUTE attributes[] = {
{CKA_CLASS, &class_value, sizeof(class_value)},
{CKA_TOKEN, &false_value, sizeof(false_value)},
{CKA_LABEL, label, sizeof(label) - 1},
{CKA_APPLICATION, application, sizeof(application) - 1},
{CKA_VALUE, data, sizeof(data)}};
std::vector<uint8_t> attribute_serial;
if (!SerializeAttributes(attributes, 5, &attribute_serial)) {
LOG(FATAL) << "GetObjectAttribute failed.";
}
return attribute_serial;
}
std::vector<uint8_t> GetEncryptKeyAttribute() {
CK_OBJECT_CLASS key_class = CKO_SECRET_KEY;
CK_KEY_TYPE key_type = CKK_AES;
CK_BYTE key_value[32] = {0};
CK_BBOOL false_value = CK_FALSE;
CK_BBOOL true_value = CK_TRUE;
CK_ATTRIBUTE key_desc[] = {{CKA_CLASS, &key_class, sizeof(key_class)},
{CKA_KEY_TYPE, &key_type, sizeof(key_type)},
{CKA_TOKEN, &false_value, sizeof(false_value)},
{CKA_ENCRYPT, &true_value, sizeof(true_value)},
{CKA_DECRYPT, &true_value, sizeof(true_value)},
{CKA_VALUE, key_value, sizeof(key_value)}};
std::vector<uint8_t> key;
if (!SerializeAttributes(key_desc, 6, &key)) {
LOG(FATAL) << "GetEncryptKeyAttribute failed.";
}
return key;
}
std::vector<uint8_t> GetDigestKeyAttribute() {
CK_OBJECT_CLASS key_class = CKO_SECRET_KEY;
CK_KEY_TYPE key_type = CKK_GENERIC_SECRET;
std::vector<uint8_t> data(100, 2);
CK_BYTE key_value[100] = {0};
memcpy(key_value, data.data(), 100);
CK_BBOOL false_value = CK_FALSE;
CK_BBOOL true_value = CK_TRUE;
CK_ATTRIBUTE key_desc[] = {{CKA_CLASS, &key_class, sizeof(key_class)},
{CKA_KEY_TYPE, &key_type, sizeof(key_type)},
{CKA_TOKEN, &false_value, sizeof(false_value)},
{CKA_SIGN, &true_value, sizeof(true_value)},
{CKA_VERIFY, &true_value, sizeof(true_value)},
{CKA_VALUE, key_value, sizeof(key_value)}};
std::vector<uint8_t> key;
if (!SerializeAttributes(key_desc, 6, &key)) {
LOG(FATAL) << "GetDigestKeyAttribute failed.";
}
return key;
}
std::vector<uint8_t> GetSignKeyAttribute() {
CK_OBJECT_CLASS key_class = CKO_SECRET_KEY;
CK_KEY_TYPE key_type = CKK_GENERIC_SECRET;
CK_BYTE key_value[32] = {0};
CK_BBOOL false_value = CK_FALSE;
CK_BBOOL true_value = CK_TRUE;
CK_ATTRIBUTE key_desc[] = {{CKA_CLASS, &key_class, sizeof(key_class)},
{CKA_KEY_TYPE, &key_type, sizeof(key_type)},
{CKA_TOKEN, &false_value, sizeof(false_value)},
{CKA_SIGN, &true_value, sizeof(true_value)},
{CKA_VERIFY, &true_value, sizeof(true_value)},
{CKA_VALUE, key_value, sizeof(key_value)}};
std::vector<uint8_t> key;
if (!SerializeAttributes(key_desc, 6, &key)) {
LOG(FATAL) << "GetSignKeyAttribute failed.";
}
return key;
}
brillo::SecureBlob GetIsolateCredential() {
if (data_provider_->ConsumeBool() ||
generated_isolate_credentials_.empty()) {
return brillo::SecureBlob(ConsumeLowEntropyRandomLengthString(16));
} else {
auto idx = data_provider_->ConsumeIntegralInRange(
0ul, generated_isolate_credentials_.size() - 1);
return brillo::SecureBlob(generated_isolate_credentials_[idx]);
}
}
int GetSlotId() {
int slot_id;
// Open session if not exist yet with high probability.
if (generated_slot_ids_.empty() &&
ConsumeProbability(kSuccessProbability)) {
LoadToken();
}
if (!ConsumeProbability(kSuccessProbability) ||
generated_slot_ids_.empty()) {
slot_id = data_provider_->ConsumeIntegral<int>();
} else {
auto idx = data_provider_->ConsumeIntegralInRange(
0ul, generated_slot_ids_.size() - 1);
slot_id = generated_slot_ids_[idx];
}
return slot_id;
}
uint64_t GetSessionId() {
uint64_t session_id;
// Open session if not exist yet with high probability.
if (generated_session_ids_.empty() &&
ConsumeProbability(kSuccessProbability)) {
OpenSession();
}
if (!ConsumeProbability(kSuccessProbability) ||
generated_session_ids_.empty()) {
session_id = data_provider_->ConsumeIntegral<int>();
} else {
auto idx = data_provider_->ConsumeIntegralInRange(
0ul, generated_session_ids_.size() - 1);
session_id = generated_session_ids_[idx];
}
return session_id;
}
uint64_t GetObjectHandle() {
// Create object if not exist yet with high probability.
if (generated_object_handles_.empty() &&
ConsumeProbability(kSuccessProbability)) {
CreateRandomObject();
}
if (!ConsumeProbability(kSuccessProbability) ||
generated_object_handles_.empty()) {
return data_provider_->ConsumeIntegral<uint64_t>();
} else {
auto idx = data_provider_->ConsumeIntegralInRange(
0ul, generated_object_handles_.size() - 1);
return generated_object_handles_[idx];
}
}
FuzzedDataProvider* data_provider_;
std::unique_ptr<chaps::ChapsMetrics> chaps_metrics_;
std::unique_ptr<chaps::ChapsFactoryImpl> factory_;
std::unique_ptr<trunks::FuzzedCommandTransceiver> command_transceiver_;
std::unique_ptr<trunks::TrunksFactoryImpl> trunks_factory_;
std::unique_ptr<chaps::FuzzedTpmManagerUtility> tpm_manager_utility_;
std::unique_ptr<chaps::TPMThreadUtilityImpl> tpm_utility_;
std::unique_ptr<chaps::SlotManagerImpl> slot_manager_;
std::unique_ptr<chaps::ChapsServiceImpl> chaps_service_;
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
std::vector<std::string> generated_isolate_credentials_;
std::vector<int> generated_slot_ids_;
std::vector<uint64_t> generated_session_ids_;
std::vector<uint64_t> generated_object_handles_;
};
} // namespace
class Environment {
public:
Environment() {
logging::SetMinLogLevel(logging::LOG_FATAL);
base::CommandLine::Init(0, nullptr);
TestTimeouts::Initialize();
}
};
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
static Environment env;
if (size <= 1) {
return 0;
}
size_t tpm_data_size = size / 2;
FuzzedDataProvider tpm_data_provider(data, tpm_data_size),
data_provider(data + tpm_data_size, size - tpm_data_size);
ChapsServiceFuzzer fuzzer(&tpm_data_provider, &data_provider);
fuzzer.Run();
return 0;
}