//
// Copyright (C) 2014 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#include <base/stl_util.h>
#include <base/strings/string_number_conversions.h>
#include <crypto/sha2.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <openssl/aes.h>

#include "trunks/error_codes.h"
#include "trunks/hmac_authorization_delegate.h"
#include "trunks/mock_authorization_delegate.h"
#include "trunks/mock_blob_parser.h"
#include "trunks/mock_command_transceiver.h"
#include "trunks/mock_hmac_session.h"
#include "trunks/mock_policy_session.h"
#include "trunks/mock_tpm.h"
#include "trunks/mock_tpm_state.h"
#include "trunks/tpm_constants.h"
#include "trunks/tpm_utility_impl.h"
#include "trunks/trunks_factory_for_test.h"

using testing::_;
using testing::DoAll;
using testing::NiceMock;
using testing::Return;
using testing::SaveArg;
using testing::SetArgPointee;

namespace {

// Cr50 Vendor ID ("CROS").
const uint32_t kVendorIdCr50 = 0x43524f53;

// Returns the total number of bits set in the first |size| elements from
// |array|.
int CountSetBits(const uint8_t* array, size_t size) {
  int res = 0;
  for (size_t i = 0; i < size; ++i) {
    for (int bit_position = 0; bit_position < 8; ++bit_position) {
      if ((array[i] & (1 << bit_position)) != 0) {
        ++res;
      }
    }
  }
  return res;
}

}  // namespace

namespace trunks {

// A test fixture for TpmUtility tests.
class TpmUtilityTest : public testing::Test {
 public:
  TpmUtilityTest() : mock_tpm_(&mock_transceiver_), utility_(factory_) {}
  ~TpmUtilityTest() override {}
  void SetUp() override {
    factory_.set_blob_parser(&mock_blob_parser_);
    factory_.set_tpm_state(&mock_tpm_state_);
    factory_.set_tpm(&mock_tpm_);
    factory_.set_hmac_session(&mock_hmac_session_);
    factory_.set_trial_session(&mock_trial_session_);
    ON_CALL(mock_tpm_, NV_ReadPublicSync(_, _, _, _, _))
        .WillByDefault(Return(TPM_RC_FAILURE));
  }

  TPM_RC ComputeKeyName(const TPMT_PUBLIC& public_area,
                        std::string* object_name) {
    return utility_.ComputeKeyName(public_area, object_name);
  }

  TPM_RC SetKnownOwnerPassword(const std::string& owner_password) {
    return utility_.SetKnownOwnerPassword(owner_password);
  }

  TPM_RC CreateStorageRootKeys(const std::string& owner_password) {
    return utility_.CreateStorageRootKeys(owner_password);
  }

  TPM_RC CreateSaltingKey(const std::string& owner_password) {
    return utility_.CreateSaltingKey(owner_password);
  }

  void SetExistingKeyHandleExpectation(TPM_HANDLE handle) {
    TPMS_CAPABILITY_DATA capability_data = {};
    TPML_HANDLE& handles = capability_data.data.handles;
    handles.count = 1;
    handles.handle[0] = handle;
    EXPECT_CALL(mock_tpm_,
                GetCapabilitySync(TPM_CAP_HANDLES, handle, _, _, _, _))
        .WillRepeatedly(
            DoAll(SetArgPointee<4>(capability_data), Return(TPM_RC_SUCCESS)));
  }

  void PopulatePCRSelection(bool has_sha1_pcrs,
                            bool make_sha1_bank_empty,
                            bool has_sha256_pcrs,
                            TPML_PCR_SELECTION* pcrs) {
    memset(pcrs, 0, sizeof(TPML_PCR_SELECTION));
    // By convention fill SHA-256 first. This is a bit brittle because order is
    // not important but it simplifies comparison to memcmp.
    if (has_sha256_pcrs) {
      pcrs->pcr_selections[pcrs->count].hash = TPM_ALG_SHA256;
      pcrs->pcr_selections[pcrs->count].sizeof_select = PCR_SELECT_MIN;
      for (int i = 0; i < PCR_SELECT_MIN; ++i) {
        pcrs->pcr_selections[pcrs->count].pcr_select[i] = 0xff;
      }
      ++pcrs->count;
    }
    if (has_sha1_pcrs) {
      pcrs->pcr_selections[pcrs->count].hash = TPM_ALG_SHA1;
      if (make_sha1_bank_empty) {
        pcrs->pcr_selections[pcrs->count].sizeof_select = PCR_SELECT_MAX;
      } else {
        pcrs->pcr_selections[pcrs->count].sizeof_select = PCR_SELECT_MIN;
        for (int i = 0; i < PCR_SELECT_MIN; ++i) {
          pcrs->pcr_selections[pcrs->count].pcr_select[i] = 0xff;
        }
      }
      ++pcrs->count;
    }
  }

  void SetExistingPCRSExpectation(bool has_sha1_pcrs, bool has_sha256_pcrs) {
    TPMS_CAPABILITY_DATA capability_data = {};
    TPML_PCR_SELECTION& pcrs = capability_data.data.assigned_pcr;
    PopulatePCRSelection(has_sha1_pcrs, false, has_sha256_pcrs, &pcrs);
    EXPECT_CALL(mock_tpm_, GetCapabilitySync(TPM_CAP_PCRS, _, _, _, _, _))
        .WillRepeatedly(
            DoAll(SetArgPointee<4>(capability_data), Return(TPM_RC_SUCCESS)));
  }

  void SetCr50(bool is_cr50) {
    EXPECT_CALL(mock_tpm_state_, Initialize())
        .WillOnce(Return(TPM_RC_SUCCESS));
    uint32_t vendor_id = is_cr50 ? kVendorIdCr50 : 1;
    EXPECT_CALL(mock_tpm_state_, GetTpmProperty(TPM_PT_MANUFACTURER, _))
        .WillOnce(DoAll(SetArgPointee<1>(vendor_id), Return(true)));
  }

 protected:
  TrunksFactoryForTest factory_;
  NiceMock<MockCommandTransceiver> mock_transceiver_;
  NiceMock<MockBlobParser> mock_blob_parser_;
  NiceMock<MockTpmState> mock_tpm_state_;
  NiceMock<MockTpm> mock_tpm_;
  NiceMock<MockAuthorizationDelegate> mock_authorization_delegate_;
  NiceMock<MockHmacSession> mock_hmac_session_;
  NiceMock<MockPolicySession> mock_trial_session_;
  TpmUtilityImpl utility_;
};

class NVTpmUtilityTest : public TpmUtilityTest {
 protected:
  // Constants with some valid NVRAM data.
  const uint32_t kNvIndex = 53;
  const uint32_t kNvTpmIndex = NV_INDEX_FIRST + kNvIndex;
  const TPMI_ALG_HASH kNvNameAlg = TPM_ALG_SHA256;
  const TPMA_NV kNvAttributes = TPMA_NV_WRITEDEFINE;
  const uint16_t kNvDataSize = 256;
  const std::string kNvData = std::string(kNvDataSize, 'z');
  const TPM2B_NV_PUBLIC kTpm2bNvPublic = MakeTpm2bNvPublic();
  const TPM2B_NV_PUBLIC kEmptyTpm2bNvPublic = MakeEmptyTpm2bNvPublic();
  const TPM2B_MAX_NV_BUFFER kTpm2bMaxNvBuffer = MakeTpm2bMaxNvBuffer();
  // Constants with invalid NVRAM data, for use in negative tests.
  const uint32_t kNvBadIndex = 1 << 29;

  NVTpmUtilityTest() = default;
  ~NVTpmUtilityTest() = default;

  void SetNVRAMMap(uint32_t index, const TPMS_NV_PUBLIC& public_area) {
    utility_.nvram_public_area_map_[index] = public_area;
  }

  TPM_RC GetNVRAMMap(uint32_t index, TPMS_NV_PUBLIC* public_area) const {
    auto it = utility_.nvram_public_area_map_.find(index);
    if (it == utility_.nvram_public_area_map_.end())
      return TPM_RC_FAILURE;
    *public_area = it->second;
    return TPM_RC_SUCCESS;
  }

 private:
  TPM2B_NV_PUBLIC MakeTpm2bNvPublic() const {
    TPM2B_NV_PUBLIC tpm2b_nv_public;
    tpm2b_nv_public.size = sizeof(TPMS_NV_PUBLIC);
    TPMS_NV_PUBLIC& tpms_nv_public = tpm2b_nv_public.nv_public;
    memset(&tpms_nv_public, 0, sizeof(TPMS_NV_PUBLIC));
    tpms_nv_public.nv_index = kNvTpmIndex;
    tpms_nv_public.name_alg = kNvNameAlg;
    tpms_nv_public.attributes = kNvAttributes;
    tpms_nv_public.data_size = kNvDataSize;
    return tpm2b_nv_public;
  }

  TPM2B_NV_PUBLIC MakeEmptyTpm2bNvPublic() const {
    TPM2B_NV_PUBLIC tpm2b_nv_public;
    tpm2b_nv_public.size = 0;
    // Intentionally not zeroing the TPMS_NV_PUBLIC sub-structure - it should
    // not be read by the tested code.
    return tpm2b_nv_public;
  }

  TPM2B_MAX_NV_BUFFER MakeTpm2bMaxNvBuffer() const {
    CHECK_LE(kNvDataSize, MAX_NV_BUFFER_SIZE);
    TPM2B_MAX_NV_BUFFER tpm2b_max_nv_buffer;
    tpm2b_max_nv_buffer.size = kNvDataSize;
    memcpy(tpm2b_max_nv_buffer.buffer, kNvData.data(), kNvDataSize);
    return tpm2b_max_nv_buffer;
  }
};

TEST_F(TpmUtilityTest, StartupSuccess) {
  EXPECT_EQ(TPM_RC_SUCCESS, utility_.Startup());
}

TEST_F(TpmUtilityTest, StartupAlreadyStarted) {
  EXPECT_CALL(mock_tpm_, StartupSync(_, _))
      .WillRepeatedly(Return(TPM_RC_INITIALIZE));
  EXPECT_EQ(TPM_RC_SUCCESS, utility_.Startup());
}

TEST_F(TpmUtilityTest, StartupFailure) {
  EXPECT_CALL(mock_tpm_, StartupSync(_, _))
      .WillRepeatedly(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE, utility_.Startup());
}

TEST_F(TpmUtilityTest, StartupSelfTestFailure) {
  EXPECT_CALL(mock_tpm_, SelfTestSync(_, _))
      .WillRepeatedly(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE, utility_.Startup());
}

TEST_F(TpmUtilityTest, ClearSuccess) {
  EXPECT_EQ(TPM_RC_SUCCESS, utility_.Clear());
}

TEST_F(TpmUtilityTest, ClearAfterBadInit) {
  EXPECT_CALL(mock_tpm_, ClearSync(_, _, _))
      .WillOnce(Return(TPM_RC_AUTH_MISSING))
      .WillOnce(Return(TPM_RC_SUCCESS));
  EXPECT_EQ(TPM_RC_SUCCESS, utility_.Clear());
}

TEST_F(TpmUtilityTest, ClearFail) {
  EXPECT_CALL(mock_tpm_, ClearSync(_, _, _)).WillOnce(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE, utility_.Clear());
}

TEST_F(TpmUtilityTest, ShutdownTest) {
  EXPECT_CALL(mock_tpm_, ShutdownSync(TPM_SU_CLEAR, _));
  utility_.Shutdown();
}

TEST_F(TpmUtilityTest, InitializeTpmAlreadyInit) {
  SetExistingPCRSExpectation(false, true);
  EXPECT_EQ(TPM_RC_SUCCESS, utility_.InitializeTpm());
  EXPECT_EQ(TPM_RC_SUCCESS, utility_.InitializeTpm());
}

TEST_F(TpmUtilityTest, InitializeTpmSuccess) {
  SetExistingPCRSExpectation(false, true);
  EXPECT_EQ(TPM_RC_SUCCESS, utility_.InitializeTpm());
}

TEST_F(TpmUtilityTest, InitializeTpmBadAuth) {
  SetExistingPCRSExpectation(false, true);
  // Reject attempts to set platform auth.
  EXPECT_CALL(mock_tpm_, HierarchyChangeAuthSync(TPM_RH_PLATFORM, _, _, _))
      .WillRepeatedly(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE, utility_.InitializeTpm());
}

TEST_F(TpmUtilityTest, InitializeTpmDisablePHFails) {
  SetExistingPCRSExpectation(false, true);
  // Reject attempts to disable the platform hierarchy.
  EXPECT_CALL(mock_tpm_, HierarchyControlSync(_, _, TPM_RH_PLATFORM, _, _))
      .WillRepeatedly(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE, utility_.InitializeTpm());
}

TEST_F(TpmUtilityTest, AllocatePCRFromNone) {
  SetExistingPCRSExpectation(false, false);
  TPML_PCR_SELECTION new_pcr_allocation;
  EXPECT_CALL(mock_tpm_, PCR_AllocateSync(TPM_RH_PLATFORM, _, _, _, _, _, _, _))
      .WillOnce(DoAll(SaveArg<2>(&new_pcr_allocation), SetArgPointee<3>(YES),
                      Return(TPM_RC_SUCCESS)));
  ASSERT_EQ(TPM_RC_SUCCESS, utility_.AllocatePCR(""));
  ASSERT_EQ(1u, new_pcr_allocation.count);
  TPML_PCR_SELECTION expected_pcr_allocation;
  PopulatePCRSelection(false, false, true, &expected_pcr_allocation);
  ASSERT_EQ(0, memcmp(&expected_pcr_allocation, &new_pcr_allocation,
                      sizeof(TPML_PCR_SELECTION)));
}

TEST_F(TpmUtilityTest, AllocatePCRFromSHA1Only) {
  SetExistingPCRSExpectation(true, false);
  TPML_PCR_SELECTION new_pcr_allocation;
  EXPECT_CALL(mock_tpm_, PCR_AllocateSync(TPM_RH_PLATFORM, _, _, _, _, _, _, _))
      .WillOnce(DoAll(SaveArg<2>(&new_pcr_allocation), SetArgPointee<3>(YES),
                      Return(TPM_RC_SUCCESS)));
  ASSERT_EQ(TPM_RC_SUCCESS, utility_.AllocatePCR(""));
  ASSERT_EQ(2u, new_pcr_allocation.count);
  TPML_PCR_SELECTION expected_pcr_allocation;
  PopulatePCRSelection(true, true, true, &expected_pcr_allocation);
  ASSERT_EQ(0, memcmp(&expected_pcr_allocation, &new_pcr_allocation,
                      sizeof(TPML_PCR_SELECTION)));
}

TEST_F(TpmUtilityTest, AllocatePCRFromSHA1AndSHA256) {
  SetExistingPCRSExpectation(true, true);
  TPML_PCR_SELECTION new_pcr_allocation;
  EXPECT_CALL(mock_tpm_, PCR_AllocateSync(TPM_RH_PLATFORM, _, _, _, _, _, _, _))
      .WillOnce(DoAll(SaveArg<2>(&new_pcr_allocation), SetArgPointee<3>(YES),
                      Return(TPM_RC_SUCCESS)));
  ASSERT_EQ(TPM_RC_SUCCESS, utility_.AllocatePCR(""));
  ASSERT_EQ(1u, new_pcr_allocation.count);
  TPML_PCR_SELECTION expected_pcr_allocation;
  PopulatePCRSelection(true, true, false, &expected_pcr_allocation);
  ASSERT_EQ(0, memcmp(&expected_pcr_allocation, &new_pcr_allocation,
                      sizeof(TPML_PCR_SELECTION)));
}

TEST_F(TpmUtilityTest, AllocatePCRFromSHA256Only) {
  SetExistingPCRSExpectation(false, true);
  EXPECT_CALL(mock_tpm_, PCR_AllocateSync(TPM_RH_PLATFORM, _, _, _, _, _, _, _))
      .Times(0);
  ASSERT_EQ(TPM_RC_SUCCESS, utility_.AllocatePCR(""));
}

TEST_F(TpmUtilityTest, AllocatePCRCommandFailure) {
  SetExistingPCRSExpectation(false, false);
  EXPECT_CALL(mock_tpm_, PCR_AllocateSync(_, _, _, _, _, _, _, _))
      .WillOnce(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE, utility_.AllocatePCR(""));
}

TEST_F(TpmUtilityTest, AllocatePCRTpmFailure) {
  SetExistingPCRSExpectation(false, false);
  EXPECT_CALL(mock_tpm_, PCR_AllocateSync(_, _, _, _, _, _, _, _))
      .WillOnce(DoAll(SetArgPointee<3>(NO), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_FAILURE, utility_.AllocatePCR(""));
}

TEST_F(TpmUtilityTest, PrepareForOwnershipSuccess) {
  EXPECT_CALL(mock_tpm_state_, IsOwnerPasswordSet())
      .WillRepeatedly(Return(false));
  EXPECT_CALL(mock_tpm_, HierarchyChangeAuthSync(TPM_RH_OWNER, _, _, _))
      .WillOnce(Return(TPM_RC_SUCCESS));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.PrepareForOwnership());
}

TEST_F(TpmUtilityTest, PrepareForOwnershipFailure) {
  EXPECT_CALL(mock_tpm_state_, IsOwnerPasswordSet())
      .WillRepeatedly(Return(false));
  EXPECT_CALL(mock_tpm_, HierarchyChangeAuthSync(TPM_RH_OWNER, _, _, _))
      .WillOnce(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.PrepareForOwnership());
}

TEST_F(TpmUtilityTest, PrepareForOwnershipAlreadyOwned) {
  EXPECT_CALL(mock_tpm_state_, IsOwnerPasswordSet())
      .WillOnce(Return(true));
  EXPECT_CALL(mock_tpm_, HierarchyChangeAuthSync(_, _, _, _))
      .Times(0);
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.PrepareForOwnership());
}

TEST_F(TpmUtilityTest, TakeOwnershipSuccess) {
  EXPECT_CALL(mock_tpm_state_, IsOwnerPasswordSet())
      .WillRepeatedly(Return(false));
  EXPECT_CALL(mock_tpm_state_, IsEndorsementPasswordSet())
      .WillRepeatedly(Return(false));
  EXPECT_CALL(mock_tpm_state_, IsLockoutPasswordSet())
      .WillRepeatedly(Return(false));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.TakeOwnership("owner", "endorsement", "lockout"));
}

TEST_F(TpmUtilityTest, TakeOwnershipOwnershipDone) {
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.TakeOwnership("owner", "endorsement", "lockout"));
}

TEST_F(TpmUtilityTest, TakeOwnershipBadSession) {
  EXPECT_CALL(mock_hmac_session_, StartUnboundSession(true, true))
      .WillRepeatedly(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.TakeOwnership("owner", "endorsement", "lockout"));
}

TEST_F(TpmUtilityTest, TakeOwnershipFailure) {
  EXPECT_CALL(mock_tpm_, HierarchyChangeAuthSync(TPM_RH_OWNER, _, _, _))
      .WillRepeatedly(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.TakeOwnership("owner", "endorsement", "lockout"));
}

TEST_F(TpmUtilityTest, ChangeOwnerPasswordEndorsementDone) {
  EXPECT_CALL(mock_tpm_state_, IsOwnerPasswordSet())
      .WillRepeatedly(Return(false));
  EXPECT_CALL(mock_tpm_state_, IsLockoutPasswordSet())
      .WillRepeatedly(Return(false));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.TakeOwnership("owner", "endorsement", "lockout"));
}

TEST_F(TpmUtilityTest, ChangeOwnerPasswordLockoutDone) {
  EXPECT_CALL(mock_tpm_state_, IsOwnerPasswordSet())
      .WillRepeatedly(Return(false));
  EXPECT_CALL(mock_tpm_state_, IsEndorsementPasswordSet())
      .WillRepeatedly(Return(false));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.TakeOwnership("owner", "endorsement", "lockout"));
}

TEST_F(TpmUtilityTest, ChangeOwnerPasswordEndorsementLockoutDone) {
  EXPECT_CALL(mock_tpm_state_, IsOwnerPasswordSet())
      .WillRepeatedly(Return(false));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.TakeOwnership("owner", "endorsement", "lockout"));
}

TEST_F(TpmUtilityTest, ChangeOwnerPasswordEndorsementFail) {
  EXPECT_CALL(mock_tpm_state_, IsOwnerPasswordSet())
      .WillRepeatedly(Return(false));
  EXPECT_CALL(mock_tpm_state_, IsEndorsementPasswordSet())
      .WillRepeatedly(Return(false));
  EXPECT_CALL(mock_tpm_, HierarchyChangeAuthSync(_, _, _, _))
      .WillRepeatedly(Return(TPM_RC_SUCCESS));
  EXPECT_CALL(mock_tpm_, HierarchyChangeAuthSync(TPM_RH_ENDORSEMENT, _, _, _))
      .WillRepeatedly(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.TakeOwnership("owner", "endorsement", "lockout"));
}

TEST_F(TpmUtilityTest, ChangeOwnerPasswordLockoutFailure) {
  EXPECT_CALL(mock_tpm_state_, IsOwnerPasswordSet())
      .WillRepeatedly(Return(false));
  EXPECT_CALL(mock_tpm_state_, IsEndorsementPasswordSet())
      .WillRepeatedly(Return(false));
  EXPECT_CALL(mock_tpm_state_, IsLockoutPasswordSet())
      .WillRepeatedly(Return(false));
  EXPECT_CALL(mock_tpm_, HierarchyChangeAuthSync(_, _, _, _))
      .WillRepeatedly(Return(TPM_RC_SUCCESS));
  EXPECT_CALL(mock_tpm_, HierarchyChangeAuthSync(TPM_RH_LOCKOUT, _, _, _))
      .WillRepeatedly(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.TakeOwnership("owner", "endorsement", "lockout"));
}

TEST_F(TpmUtilityTest, StirRandomSuccess) {
  std::string entropy_data(
      "large test data large test data large test data is that enough?");
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.StirRandom(entropy_data, &mock_authorization_delegate_));
}

TEST_F(TpmUtilityTest, StirRandomFails) {
  std::string entropy_data("test data");
  EXPECT_CALL(mock_tpm_, StirRandomSync(_, nullptr))
      .WillOnce(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE, utility_.StirRandom(entropy_data, nullptr));
}

TEST_F(TpmUtilityTest, GenerateRandomSuccess) {
  // This number is larger than the max bytes the GetRandom call can return.
  // Therefore we expect software to make multiple calls to fill this many
  // bytes.
  size_t num_bytes = 72;
  std::string random_data;
  TPM2B_DIGEST large_random;
  large_random.size = 32;
  TPM2B_DIGEST small_random;
  small_random.size = 8;
  EXPECT_CALL(mock_tpm_, GetRandomSync(_, _, &mock_authorization_delegate_))
      .Times(2)
      .WillRepeatedly(
          DoAll(SetArgPointee<1>(large_random), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, GetRandomSync(8, _, &mock_authorization_delegate_))
      .WillOnce(DoAll(SetArgPointee<1>(small_random), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.GenerateRandom(num_bytes, &mock_authorization_delegate_,
                                    &random_data));
  EXPECT_EQ(num_bytes, random_data.size());
}

TEST_F(TpmUtilityTest, GenerateRandomFails) {
  size_t num_bytes = 5;
  std::string random_data;
  EXPECT_CALL(mock_tpm_, GetRandomSync(_, _, nullptr))
      .WillOnce(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.GenerateRandom(num_bytes, nullptr, &random_data));
}

TEST_F(TpmUtilityTest, ExtendPCRSuccess) {
  TPM_HANDLE pcr_handle = HR_PCR + 1;
  TPML_DIGEST_VALUES digests;
  EXPECT_CALL(mock_tpm_,
              PCR_ExtendSync(pcr_handle, _, _, &mock_authorization_delegate_))
      .WillOnce(DoAll(SaveArg<2>(&digests), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS, utility_.ExtendPCR(1, "test digest",
                                               &mock_authorization_delegate_));
  EXPECT_EQ(1u, digests.count);
  EXPECT_EQ(TPM_ALG_SHA256, digests.digests[0].hash_alg);
  std::string hash_string = crypto::SHA256HashString("test digest");
  EXPECT_EQ(0, memcmp(hash_string.data(), digests.digests[0].digest.sha256,
                      crypto::kSHA256Length));
}

TEST_F(TpmUtilityTest, ExtendPCRFail) {
  int pcr_index = 0;
  TPM_HANDLE pcr_handle = HR_PCR + pcr_index;
  EXPECT_CALL(mock_tpm_, PCR_ExtendSync(pcr_handle, _, _, _))
      .WillOnce(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.ExtendPCR(pcr_index, "test digest", nullptr));
}

TEST_F(TpmUtilityTest, ExtendPCRBadParam) {
  EXPECT_EQ(TPM_RC_FAILURE, utility_.ExtendPCR(-1, "test digest", nullptr));
}

TEST_F(TpmUtilityTest, ReadPCRSuccess) {
  // The |pcr_index| is chosen to match the structure for |pcr_select|.
  // If you change |pcr_index|, remember to change |pcr_select|.
  int pcr_index = 1;
  std::string pcr_value;
  TPML_PCR_SELECTION pcr_select;
  pcr_select.count = 1;
  pcr_select.pcr_selections[0].hash = TPM_ALG_SHA256;
  pcr_select.pcr_selections[0].sizeof_select = 1;
  pcr_select.pcr_selections[0].pcr_select[0] = 2;
  TPML_DIGEST pcr_values;
  pcr_values.count = 1;
  pcr_values.digests[0].size = 5;
  EXPECT_CALL(mock_tpm_, PCR_ReadSync(_, _, _, _, _))
      .WillOnce(DoAll(SetArgPointee<2>(pcr_select),
                      SetArgPointee<3>(pcr_values), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS, utility_.ReadPCR(pcr_index, &pcr_value));
}

TEST_F(TpmUtilityTest, ReadPCRFail) {
  std::string pcr_value;
  EXPECT_CALL(mock_tpm_, PCR_ReadSync(_, _, _, _, _))
      .WillOnce(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE, utility_.ReadPCR(1, &pcr_value));
}

TEST_F(TpmUtilityTest, ReadPCRBadReturn) {
  std::string pcr_value;
  EXPECT_EQ(TPM_RC_FAILURE, utility_.ReadPCR(1, &pcr_value));
}

TEST_F(TpmUtilityTest, AsymmetricEncryptSuccess) {
  TPM_HANDLE key_handle;
  std::string plaintext;
  std::string output_ciphertext("ciphertext");
  std::string ciphertext;
  TPM2B_PUBLIC_KEY_RSA out_message =
      Make_TPM2B_PUBLIC_KEY_RSA(output_ciphertext);
  TPM2B_PUBLIC public_area;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kDecrypt;
  public_area.public_area.auth_policy.size = 0;
  public_area.public_area.unique.rsa.size = 0;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, RSA_EncryptSync(key_handle, _, _, _, _, _,
                                         &mock_authorization_delegate_))
      .WillOnce(DoAll(SetArgPointee<5>(out_message), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.AsymmetricEncrypt(key_handle, TPM_ALG_NULL, TPM_ALG_NULL,
                                       plaintext, &mock_authorization_delegate_,
                                       &ciphertext));
  EXPECT_EQ(0, ciphertext.compare(output_ciphertext));
}

TEST_F(TpmUtilityTest, AsymmetricEncryptFail) {
  TPM_HANDLE key_handle;
  std::string plaintext;
  std::string ciphertext;
  TPM2B_PUBLIC public_area;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kDecrypt;
  public_area.public_area.auth_policy.size = 0;
  public_area.public_area.unique.rsa.size = 0;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, RSA_EncryptSync(key_handle, _, _, _, _, _, nullptr))
      .WillOnce(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.AsymmetricEncrypt(key_handle, TPM_ALG_NULL, TPM_ALG_NULL,
                                       plaintext, nullptr, &ciphertext));
}

TEST_F(TpmUtilityTest, AsymmetricEncryptBadParams) {
  TPM_HANDLE key_handle = TPM_RH_FIRST;
  std::string plaintext;
  std::string ciphertext;
  TPM2B_PUBLIC public_area;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kDecrypt | kRestricted;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, nullptr))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(SAPI_RC_BAD_PARAMETER,
            utility_.AsymmetricEncrypt(key_handle, TPM_ALG_RSAES, TPM_ALG_NULL,
                                       plaintext, nullptr, &ciphertext));
}

TEST_F(TpmUtilityTest, AsymmetricEncryptNullSchemeForward) {
  TPM_HANDLE key_handle;
  std::string plaintext;
  std::string output_ciphertext("ciphertext");
  std::string ciphertext;
  TPM2B_PUBLIC_KEY_RSA out_message =
      Make_TPM2B_PUBLIC_KEY_RSA(output_ciphertext);
  TPM2B_PUBLIC public_area;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kDecrypt;
  public_area.public_area.auth_policy.size = 0;
  public_area.public_area.unique.rsa.size = 0;
  TPMT_RSA_DECRYPT scheme;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, RSA_EncryptSync(key_handle, _, _, _, _, _, nullptr))
      .WillOnce(DoAll(SetArgPointee<5>(out_message), SaveArg<3>(&scheme),
                      Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.AsymmetricEncrypt(key_handle, TPM_ALG_NULL, TPM_ALG_NULL,
                                       plaintext, nullptr, &ciphertext));
  EXPECT_EQ(scheme.scheme, TPM_ALG_OAEP);
  EXPECT_EQ(scheme.details.oaep.hash_alg, TPM_ALG_SHA256);
}

TEST_F(TpmUtilityTest, AsymmetricEncryptSchemeForward) {
  TPM_HANDLE key_handle;
  std::string plaintext;
  std::string output_ciphertext("ciphertext");
  std::string ciphertext;
  TPM2B_PUBLIC_KEY_RSA out_message =
      Make_TPM2B_PUBLIC_KEY_RSA(output_ciphertext);
  TPM2B_PUBLIC public_area;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kDecrypt;
  public_area.public_area.auth_policy.size = 0;
  public_area.public_area.unique.rsa.size = 0;
  TPMT_RSA_DECRYPT scheme;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, RSA_EncryptSync(key_handle, _, _, _, _, _, nullptr))
      .WillOnce(DoAll(SetArgPointee<5>(out_message), SaveArg<3>(&scheme),
                      Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.AsymmetricEncrypt(key_handle, TPM_ALG_RSAES, TPM_ALG_NULL,
                                       plaintext, nullptr, &ciphertext));
  EXPECT_EQ(scheme.scheme, TPM_ALG_RSAES);
}

TEST_F(TpmUtilityTest, AsymmetricDecryptSuccess) {
  TPM_HANDLE key_handle;
  std::string plaintext;
  std::string output_plaintext("plaintext");
  std::string ciphertext;
  std::string password("password");
  TPM2B_PUBLIC_KEY_RSA out_message =
      Make_TPM2B_PUBLIC_KEY_RSA(output_plaintext);
  TPM2B_PUBLIC public_area;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kDecrypt;
  public_area.public_area.auth_policy.size = 0;
  public_area.public_area.unique.rsa.size = 0;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, RSA_DecryptSync(key_handle, _, _, _, _, _,
                                         &mock_authorization_delegate_))
      .WillOnce(DoAll(SetArgPointee<5>(out_message), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.AsymmetricDecrypt(
                key_handle, TPM_ALG_NULL, TPM_ALG_NULL, ciphertext,
                &mock_authorization_delegate_, &plaintext));
  EXPECT_EQ(0, plaintext.compare(output_plaintext));
}

TEST_F(TpmUtilityTest, AsymmetricDecryptFail) {
  TPM_HANDLE key_handle;
  std::string key_name;
  std::string plaintext;
  std::string ciphertext;
  std::string password;
  TPM2B_PUBLIC public_area;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kDecrypt;
  public_area.public_area.auth_policy.size = 0;
  public_area.public_area.unique.rsa.size = 0;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, RSA_DecryptSync(key_handle, _, _, _, _, _, _))
      .WillOnce(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.AsymmetricDecrypt(
                key_handle, TPM_ALG_NULL, TPM_ALG_NULL, ciphertext,
                &mock_authorization_delegate_, &plaintext));
}

TEST_F(TpmUtilityTest, AsymmetricDecryptBadParams) {
  TPM_HANDLE key_handle = TPM_RH_FIRST;
  std::string plaintext;
  std::string ciphertext;
  TPM2B_PUBLIC public_area;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kDecrypt | kRestricted;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(SAPI_RC_BAD_PARAMETER,
            utility_.AsymmetricDecrypt(
                key_handle, TPM_ALG_RSAES, TPM_ALG_NULL, ciphertext,
                &mock_authorization_delegate_, &plaintext));
}

TEST_F(TpmUtilityTest, AsymmetricDecryptBadSession) {
  TPM_HANDLE key_handle = TPM_RH_FIRST;
  std::string key_name;
  std::string plaintext;
  std::string ciphertext;
  std::string password;
  EXPECT_EQ(SAPI_RC_INVALID_SESSIONS,
            utility_.AsymmetricDecrypt(key_handle, TPM_ALG_RSAES, TPM_ALG_NULL,
                                       ciphertext, nullptr, &plaintext));
}

TEST_F(TpmUtilityTest, AsymmetricDecryptNullHashAlgorithmForward) {
  TPM_HANDLE key_handle;
  std::string plaintext;
  std::string output_plaintext("plaintext");
  std::string ciphertext;
  std::string password;
  TPM2B_PUBLIC_KEY_RSA out_message =
      Make_TPM2B_PUBLIC_KEY_RSA(output_plaintext);
  TPM2B_PUBLIC public_area;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kDecrypt;
  public_area.public_area.auth_policy.size = 0;
  public_area.public_area.unique.rsa.size = 0;
  TPMT_RSA_DECRYPT scheme;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, RSA_DecryptSync(key_handle, _, _, _, _, _, _))
      .WillOnce(DoAll(SetArgPointee<5>(out_message), SaveArg<3>(&scheme),
                      Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.AsymmetricDecrypt(
                key_handle, TPM_ALG_OAEP, TPM_ALG_NULL, ciphertext,
                &mock_authorization_delegate_, &plaintext));
  EXPECT_EQ(scheme.scheme, TPM_ALG_OAEP);
  EXPECT_EQ(scheme.details.oaep.hash_alg, TPM_ALG_SHA256);
}

TEST_F(TpmUtilityTest, AsymmetricDecryptSchemeForward) {
  TPM_HANDLE key_handle;
  std::string plaintext;
  std::string output_plaintext("plaintext");
  std::string ciphertext;
  std::string password;
  TPM2B_PUBLIC_KEY_RSA out_message =
      Make_TPM2B_PUBLIC_KEY_RSA(output_plaintext);
  TPM2B_PUBLIC public_area;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kDecrypt;
  public_area.public_area.auth_policy.size = 0;
  public_area.public_area.unique.rsa.size = 0;
  TPMT_RSA_DECRYPT scheme;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, RSA_DecryptSync(key_handle, _, _, _, _, _, _))
      .WillOnce(DoAll(SetArgPointee<5>(out_message), SaveArg<3>(&scheme),
                      Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.AsymmetricDecrypt(
                key_handle, TPM_ALG_RSAES, TPM_ALG_NULL, ciphertext,
                &mock_authorization_delegate_, &plaintext));
  EXPECT_EQ(scheme.scheme, TPM_ALG_RSAES);
}

TEST_F(TpmUtilityTest, SignSuccess) {
  TPM_HANDLE key_handle;
  std::string password("password");
  std::string digest(32, 'a');
  TPMT_SIGNATURE signature_out;
  signature_out.signature.rsassa.sig.size = 2;
  signature_out.signature.rsassa.sig.buffer[0] = 'h';
  signature_out.signature.rsassa.sig.buffer[1] = 'i';
  std::string signature;
  TPM2B_PUBLIC public_area;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kSign;
  public_area.public_area.auth_policy.size = 0;
  public_area.public_area.unique.rsa.size = 0;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, SignSync(key_handle, _, _, _, _, _,
                                  &mock_authorization_delegate_))
      .WillOnce(DoAll(SetArgPointee<5>(signature_out), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.Sign(key_handle, TPM_ALG_RSASSA, TPM_ALG_SHA256, digest,
                          true /* generate_hash */,
                          &mock_authorization_delegate_, &signature));
  EXPECT_EQ(0, signature.compare("hi"));
}

TEST_F(TpmUtilityTest, SignFail) {
  TPM_HANDLE key_handle;
  std::string password;
  std::string digest(32, 'a');
  std::string signature;
  TPM2B_PUBLIC public_area;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kSign;
  public_area.public_area.auth_policy.size = 0;
  public_area.public_area.unique.rsa.size = 0;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, SignSync(key_handle, _, _, _, _, _, _))
      .WillOnce(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.Sign(key_handle, TPM_ALG_RSASSA, TPM_ALG_SHA256, digest,
                          true /* generate_hash */,
                          &mock_authorization_delegate_, &signature));
}

TEST_F(TpmUtilityTest, SignBadParams1) {
  TPM_HANDLE key_handle;
  std::string password;
  std::string digest(32, 'a');
  std::string signature;
  TPM2B_PUBLIC public_area;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kSign | kRestricted;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(SAPI_RC_BAD_PARAMETER,
            utility_.Sign(key_handle, TPM_ALG_RSAPSS, TPM_ALG_NULL, digest,
                          true /* generate_hash */,
                          &mock_authorization_delegate_, &signature));
}

TEST_F(TpmUtilityTest, SignBadAuthorizationSession) {
  TPM_HANDLE key_handle = TPM_RH_FIRST;
  std::string password;
  std::string digest(32, 'a');
  std::string signature;
  EXPECT_EQ(SAPI_RC_INVALID_SESSIONS,
            utility_.Sign(key_handle, TPM_ALG_RSAPSS, TPM_ALG_NULL, digest,
                          true /* generate_hash */,
                          nullptr, &signature));
}

TEST_F(TpmUtilityTest, SignBadParams2) {
  TPM_HANDLE key_handle;
  std::string password;
  std::string digest(32, 'a');
  std::string signature;
  TPM2B_PUBLIC public_area;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kDecrypt;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(SAPI_RC_BAD_PARAMETER,
            utility_.Sign(key_handle, TPM_ALG_RSAPSS, TPM_ALG_NULL, digest,
                          true /* generate_hash */,
                          &mock_authorization_delegate_, &signature));
}

TEST_F(TpmUtilityTest, SignBadParams3) {
  TPM_HANDLE key_handle;
  std::string password;
  std::string digest(32, 'a');
  std::string signature;
  TPM2B_PUBLIC public_area;
  public_area.public_area.type = TPM_ALG_ECC;
  public_area.public_area.object_attributes = kSign;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(SAPI_RC_BAD_PARAMETER,
            utility_.Sign(key_handle, TPM_ALG_RSAPSS, TPM_ALG_NULL, digest,
                          true /* generate_hash */,
                          &mock_authorization_delegate_, &signature));
}

TEST_F(TpmUtilityTest, SignBadParams4) {
  TPM_HANDLE key_handle;
  std::string password;
  std::string digest(32, 'a');
  std::string signature;
  TPM2B_PUBLIC public_area;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kSign;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_FAILURE)));
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.Sign(key_handle, TPM_ALG_RSAPSS, TPM_ALG_NULL, digest,
                          true /* generate_hash */,
                          &mock_authorization_delegate_, &signature));
}

TEST_F(TpmUtilityTest, SignBadParams5) {
  TPM_HANDLE key_handle = 0;
  std::string password;
  std::string digest(32, 'a');
  std::string signature;
  EXPECT_EQ(SAPI_RC_BAD_PARAMETER,
            utility_.Sign(key_handle, TPM_ALG_AES, TPM_ALG_NULL, digest,
                          true /* generate_hash */,
                          &mock_authorization_delegate_, &signature));
}

TEST_F(TpmUtilityTest, SignNullSchemeForward) {
  TPM_HANDLE key_handle;
  std::string password;
  std::string digest(32, 'a');
  TPMT_SIGNATURE signature_out;
  signature_out.signature.rsassa.sig.size = 0;
  std::string signature;
  TPM2B_PUBLIC public_area;
  TPMT_SIG_SCHEME scheme;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kSign;
  public_area.public_area.auth_policy.size = 0;
  public_area.public_area.unique.rsa.size = 0;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, SignSync(key_handle, _, _, _, _, _, _))
      .WillOnce(DoAll(SetArgPointee<5>(signature_out), SaveArg<3>(&scheme),
                      Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.Sign(key_handle, TPM_ALG_NULL, TPM_ALG_SHA256, digest,
                          true /* generate_hash */,
                          &mock_authorization_delegate_, &signature));
  EXPECT_EQ(scheme.scheme, TPM_ALG_RSASSA);
  EXPECT_EQ(scheme.details.rsassa.hash_alg, TPM_ALG_SHA256);
}

TEST_F(TpmUtilityTest, SignRSASSAWithNullAlgorithm) {
  TPM_HANDLE key_handle;
  std::string password;
  std::string digest(32, 'a');
  TPMT_SIGNATURE signature_out;
  signature_out.signature.rsassa.sig.size = 0;
  std::string signature;
  TPM2B_PUBLIC public_area;
  TPMT_SIG_SCHEME scheme;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kSign;
  public_area.public_area.auth_policy.size = 0;
  public_area.public_area.unique.rsa.size = 0;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, SignSync(key_handle, _, _, _, _, _, _))
      .WillOnce(DoAll(SetArgPointee<5>(signature_out), SaveArg<3>(&scheme),
                      Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.Sign(key_handle, TPM_ALG_NULL, TPM_ALG_NULL, digest,
                          false /* generate_hash */,
                          &mock_authorization_delegate_, &signature));
  EXPECT_EQ(scheme.scheme, TPM_ALG_RSASSA);
  EXPECT_EQ(scheme.details.rsassa.hash_alg, TPM_ALG_NULL);
}

TEST_F(TpmUtilityTest, SignSchemeForward) {
  TPM_HANDLE key_handle;
  std::string password;
  std::string digest(64, 'a');
  TPMT_SIGNATURE signature_out;
  signature_out.signature.rsassa.sig.size = 0;
  std::string signature;
  TPM2B_PUBLIC public_area;
  TPMT_SIG_SCHEME scheme;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kSign;
  public_area.public_area.auth_policy.size = 0;
  public_area.public_area.unique.rsa.size = 0;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, SignSync(key_handle, _, _, _, _, _, _))
      .WillOnce(DoAll(SetArgPointee<5>(signature_out), SaveArg<3>(&scheme),
                      Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.Sign(key_handle, TPM_ALG_RSAPSS, TPM_ALG_SHA1, digest,
                          true /* generate_hash */,
                          &mock_authorization_delegate_, &signature));
  EXPECT_EQ(scheme.scheme, TPM_ALG_RSAPSS);
  EXPECT_EQ(scheme.details.rsapss.hash_alg, TPM_ALG_SHA1);
}

TEST_F(TpmUtilityTest, VerifySuccess) {
  TPM_HANDLE key_handle;
  std::string digest(32, 'a');
  std::string signature;
  TPM2B_PUBLIC public_area;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kSign;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, VerifySignatureSync(key_handle, _, _, _, _, _))
      .WillOnce(Return(TPM_RC_SUCCESS));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.Verify(key_handle, TPM_ALG_NULL, TPM_ALG_NULL, digest,
                            true /* generate_hash */, signature, nullptr));
}

TEST_F(TpmUtilityTest, VerifyFail) {
  TPM_HANDLE key_handle;
  std::string digest(32, 'a');
  std::string signature;
  TPM2B_PUBLIC public_area;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kSign;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, VerifySignatureSync(key_handle, _, _, _, _, _))
      .WillOnce(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.Verify(key_handle, TPM_ALG_NULL, TPM_ALG_NULL, digest,
                            true /* generate_hash */, signature, nullptr));
}

TEST_F(TpmUtilityTest, VerifyBadParams1) {
  TPM_HANDLE key_handle;
  std::string digest(32, 'a');
  std::string signature;
  TPM2B_PUBLIC public_area;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kSign | kRestricted;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(SAPI_RC_BAD_PARAMETER,
            utility_.Verify(key_handle, TPM_ALG_NULL, TPM_ALG_NULL, digest,
                            true /* generate_hash */, signature, nullptr));
}

TEST_F(TpmUtilityTest, VerifyBadParams2) {
  TPM_HANDLE key_handle;
  std::string digest(32, 'a');
  std::string signature;
  TPM2B_PUBLIC public_area;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kDecrypt;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(SAPI_RC_BAD_PARAMETER,
            utility_.Verify(key_handle, TPM_ALG_NULL, TPM_ALG_NULL, digest,
                            true /* generate_hash */, signature, nullptr));
}

TEST_F(TpmUtilityTest, VerifyBadParams3) {
  TPM_HANDLE key_handle;
  std::string digest(32, 'a');
  std::string signature;
  TPM2B_PUBLIC public_area;
  public_area.public_area.type = TPM_ALG_ECC;
  public_area.public_area.object_attributes = kSign;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(SAPI_RC_BAD_PARAMETER,
            utility_.Verify(key_handle, TPM_ALG_NULL, TPM_ALG_NULL, digest,
                            true /* generate_hash */, signature, nullptr));
}

TEST_F(TpmUtilityTest, VerifyBadParams4) {
  TPM_HANDLE key_handle;
  std::string digest(32, 'a');
  std::string signature;
  TPM2B_PUBLIC public_area;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kSign;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_FAILURE)));
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.Verify(key_handle, TPM_ALG_NULL, TPM_ALG_NULL, digest,
                            true /* generate_hash */, signature, nullptr));
}

TEST_F(TpmUtilityTest, VerifyBadParams5) {
  TPM_HANDLE key_handle;
  std::string digest(32, 'a');
  std::string signature;
  TPM2B_PUBLIC public_area;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kSign;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(SAPI_RC_BAD_PARAMETER,
            utility_.Verify(key_handle, TPM_ALG_AES, TPM_ALG_NULL, digest,
                            true /* generate_hash */, signature, nullptr));
}

TEST_F(TpmUtilityTest, VerifyNullSchemeForward) {
  TPM_HANDLE key_handle;
  std::string digest(32, 'a');
  std::string signature;
  TPM2B_PUBLIC public_area;
  TPMT_SIGNATURE signature_in;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kSign;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, VerifySignatureSync(key_handle, _, _, _, _, _))
      .WillOnce(DoAll(SaveArg<3>(&signature_in), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.Verify(key_handle, TPM_ALG_NULL, TPM_ALG_NULL, digest,
                            true /* generate_hash */, signature, nullptr));
  EXPECT_EQ(signature_in.sig_alg, TPM_ALG_RSASSA);
  EXPECT_EQ(signature_in.signature.rsassa.hash, TPM_ALG_SHA256);
}

TEST_F(TpmUtilityTest, VerifySchemeForward) {
  TPM_HANDLE key_handle;
  std::string digest(64, 'a');
  std::string signature;
  TPM2B_PUBLIC public_area;
  TPMT_SIGNATURE signature_in;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.object_attributes = kSign;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, VerifySignatureSync(key_handle, _, _, _, _, _))
      .WillOnce(DoAll(SaveArg<3>(&signature_in), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.Verify(key_handle, TPM_ALG_RSAPSS, TPM_ALG_SHA1, digest,
                            true /* generate_hash */, signature, nullptr));
  EXPECT_EQ(signature_in.sig_alg, TPM_ALG_RSAPSS);
  EXPECT_EQ(signature_in.signature.rsassa.hash, TPM_ALG_SHA1);
}

TEST_F(TpmUtilityTest, CertifyCreationSuccess) {
  TPM_HANDLE key_handle = 42;
  std::string creation_blob;
  EXPECT_CALL(mock_tpm_, CertifyCreationSyncShort(TPM_RH_NULL, key_handle, _, _,
                                                  _, _, _, _, _))
      .WillOnce(Return(TPM_RC_SUCCESS));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.CertifyCreation(key_handle, creation_blob));
}

TEST_F(TpmUtilityTest, CertifyCreationParserError) {
  TPM_HANDLE key_handle = 42;
  std::string creation_blob;
  EXPECT_CALL(mock_blob_parser_, ParseCreationBlob(creation_blob, _, _, _))
      .WillOnce(Return(false));
  EXPECT_EQ(SAPI_RC_BAD_PARAMETER,
            utility_.CertifyCreation(key_handle, creation_blob));
}

TEST_F(TpmUtilityTest, CertifyCreationFailure) {
  TPM_HANDLE key_handle = 42;
  std::string creation_blob;
  EXPECT_CALL(mock_tpm_, CertifyCreationSyncShort(TPM_RH_NULL, key_handle, _, _,
                                                  _, _, _, _, _))
      .WillOnce(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.CertifyCreation(key_handle, creation_blob));
}

TEST_F(TpmUtilityTest, ChangeAuthDataSuccess) {
  TPM_HANDLE key_handle = 1;
  std::string new_password;
  std::string key_blob;
  TPM2B_PUBLIC public_area;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.auth_policy.size = 0;
  public_area.public_area.unique.rsa.size = 0;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(_, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS, utility_.ChangeKeyAuthorizationData(
                                key_handle, new_password,
                                &mock_authorization_delegate_, &key_blob));
}

TEST_F(TpmUtilityTest, ChangeAuthDataKeyNameFail) {
  TPM_HANDLE key_handle = 1;
  std::string old_password;
  std::string new_password;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(key_handle, _, _, _, _, _))
      .WillOnce(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE, utility_.ChangeKeyAuthorizationData(
                                key_handle, new_password,
                                &mock_authorization_delegate_, nullptr));
}

TEST_F(TpmUtilityTest, ChangeAuthDataFailure) {
  TPM_HANDLE key_handle = 1;
  std::string new_password;
  EXPECT_CALL(mock_tpm_, ObjectChangeAuthSync(key_handle, _, _, _, _, _, _))
      .WillOnce(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE, utility_.ChangeKeyAuthorizationData(
                                key_handle, new_password,
                                &mock_authorization_delegate_, nullptr));
}

TEST_F(TpmUtilityTest, ChangeAuthDataParserFail) {
  TPM_HANDLE key_handle = 1;
  std::string new_password;
  std::string key_blob;
  TPM2B_PUBLIC public_area;
  public_area.public_area.type = TPM_ALG_RSA;
  public_area.public_area.auth_policy.size = 0;
  public_area.public_area.unique.rsa.size = 0;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(_, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_blob_parser_, SerializeKeyBlob(_, _, &key_blob))
      .WillOnce(Return(false));
  EXPECT_EQ(
      SAPI_RC_BAD_TCTI_STRUCTURE,
      utility_.ChangeKeyAuthorizationData(
          key_handle, new_password, &mock_authorization_delegate_, &key_blob));
}

TEST_F(TpmUtilityTest, ImportRSAKeySuccess) {
  uint32_t public_exponent = 0x10001;
  std::string modulus(256, 'a');
  std::string prime_factor(128, 'b');
  std::string password("password");
  std::string key_blob;
  TPM2B_DATA encryption_key;
  TPM2B_PUBLIC public_data;
  TPM2B_PRIVATE private_data;
  EXPECT_CALL(mock_tpm_, ImportSync(_, _, _, _, _, _, _, _, _))
      .WillOnce(DoAll(SaveArg<2>(&encryption_key), SaveArg<3>(&public_data),
                      SaveArg<4>(&private_data), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(
      TPM_RC_SUCCESS,
      utility_.ImportRSAKey(TpmUtility::AsymmetricKeyUsage::kDecryptKey,
                            modulus, public_exponent, prime_factor, password,
                            &mock_authorization_delegate_, &key_blob));
  // Validate that the public area was properly constructed.
  EXPECT_EQ(public_data.public_area.parameters.rsa_detail.key_bits,
            modulus.size() * 8);
  EXPECT_EQ(public_data.public_area.parameters.rsa_detail.exponent,
            public_exponent);
  EXPECT_EQ(public_data.public_area.unique.rsa.size, modulus.size());
  EXPECT_EQ(0, memcmp(public_data.public_area.unique.rsa.buffer, modulus.data(),
                      modulus.size()));
  // Validate the private struct construction.
  EXPECT_EQ(kAesKeySize, encryption_key.size);
  AES_KEY key;
  AES_set_encrypt_key(encryption_key.buffer, kAesKeySize * 8, &key);
  unsigned char iv[MAX_AES_BLOCK_SIZE_BYTES] = {0};
  int iv_in = 0;
  std::string unencrypted_private(private_data.size, 0);
  AES_cfb128_encrypt(
      reinterpret_cast<const unsigned char*>(private_data.buffer),
      reinterpret_cast<unsigned char*>(
          base::string_as_array(&unencrypted_private)),
      private_data.size, &key, iv, &iv_in, AES_DECRYPT);
  TPM2B_DIGEST inner_integrity;
  EXPECT_EQ(TPM_RC_SUCCESS, Parse_TPM2B_DIGEST(&unencrypted_private,
                                               &inner_integrity, nullptr));
  std::string object_name;
  EXPECT_EQ(TPM_RC_SUCCESS,
            ComputeKeyName(public_data.public_area, &object_name));
  std::string integrity_value =
      crypto::SHA256HashString(unencrypted_private + object_name);
  EXPECT_EQ(integrity_value.size(), inner_integrity.size);
  EXPECT_EQ(0, memcmp(inner_integrity.buffer, integrity_value.data(),
                      inner_integrity.size));
  TPM2B_SENSITIVE sensitive_data;
  EXPECT_EQ(TPM_RC_SUCCESS, Parse_TPM2B_SENSITIVE(&unencrypted_private,
                                                  &sensitive_data, nullptr));
  EXPECT_TRUE(unencrypted_private.empty());
  EXPECT_EQ(sensitive_data.sensitive_area.auth_value.size, password.size());
  EXPECT_EQ(0, memcmp(sensitive_data.sensitive_area.auth_value.buffer,
                      password.data(), password.size()));
  EXPECT_EQ(sensitive_data.sensitive_area.sensitive.rsa.size,
            prime_factor.size());
  EXPECT_EQ(0, memcmp(sensitive_data.sensitive_area.sensitive.rsa.buffer,
                      prime_factor.data(), prime_factor.size()));
}

TEST_F(TpmUtilityTest, ImportRSAKeySuccessWithNoBlob) {
  uint32_t public_exponent = 0x10001;
  std::string modulus(256, 'a');
  std::string prime_factor(128, 'b');
  std::string password;
  EXPECT_EQ(
      TPM_RC_SUCCESS,
      utility_.ImportRSAKey(TpmUtility::AsymmetricKeyUsage::kDecryptKey,
                            modulus, public_exponent, prime_factor, password,
                            &mock_authorization_delegate_, nullptr));
}

TEST_F(TpmUtilityTest, ImportRSAKeyParentNameFail) {
  uint32_t public_exponent = 0x10001;
  std::string modulus(256, 'a');
  std::string prime_factor(128, 'b');
  std::string password;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(_, _, _, _, _, _))
      .WillOnce(Return(TPM_RC_FAILURE));
  EXPECT_EQ(
      TPM_RC_FAILURE,
      utility_.ImportRSAKey(TpmUtility::AsymmetricKeyUsage::kDecryptKey,
                            modulus, public_exponent, prime_factor, password,
                            &mock_authorization_delegate_, nullptr));
}

TEST_F(TpmUtilityTest, ImportRSAKeyFail) {
  std::string modulus;
  std::string prime_factor;
  std::string password;
  EXPECT_CALL(mock_tpm_, ImportSync(_, _, _, _, _, _, _, _, _))
      .WillOnce(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.ImportRSAKey(TpmUtility::AsymmetricKeyUsage::kDecryptKey,
                                  modulus, 0x10001, prime_factor, password,
                                  &mock_authorization_delegate_, nullptr));
}

TEST_F(TpmUtilityTest, ImportRSAKeyParserFail) {
  std::string modulus;
  std::string prime_factor;
  std::string password;
  std::string key_blob;
  EXPECT_CALL(mock_blob_parser_, SerializeKeyBlob(_, _, &key_blob))
      .WillOnce(Return(false));
  EXPECT_EQ(SAPI_RC_BAD_TCTI_STRUCTURE,
            utility_.ImportRSAKey(TpmUtility::AsymmetricKeyUsage::kDecryptKey,
                                  modulus, 0x10001, prime_factor, password,
                                  &mock_authorization_delegate_, &key_blob));
}

TEST_F(TpmUtilityTest, CreateRSAKeyPairSuccess) {
  TPM2B_PUBLIC public_area;
  TPML_PCR_SELECTION creation_pcrs;
  EXPECT_CALL(mock_tpm_, CreateSyncShort(kRSAStorageRootKey, _, _, _, _, _, _,
                                         _, _, &mock_authorization_delegate_))
      .WillOnce(DoAll(SaveArg<2>(&public_area), SaveArg<3>(&creation_pcrs),
                      Return(TPM_RC_SUCCESS)));
  std::string key_blob;
  std::string creation_blob;
  uint32_t creation_pcr = 12;
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.CreateRSAKeyPair(
                TpmUtility::AsymmetricKeyUsage::kDecryptAndSignKey, 2048,
                0x10001, "password", "", false,
                std::vector<uint32_t>({creation_pcr}),
                &mock_authorization_delegate_, &key_blob, &creation_blob));
  EXPECT_EQ(public_area.public_area.object_attributes & kDecrypt, kDecrypt);
  EXPECT_EQ(public_area.public_area.object_attributes & kSign, kSign);
  EXPECT_EQ(public_area.public_area.object_attributes & kUserWithAuth,
            kUserWithAuth);
  EXPECT_EQ(public_area.public_area.object_attributes & kAdminWithPolicy, 0u);
  EXPECT_EQ(public_area.public_area.parameters.rsa_detail.scheme.scheme,
            TPM_ALG_NULL);
  EXPECT_EQ(1u, creation_pcrs.count);
  EXPECT_EQ(TPM_ALG_SHA256, creation_pcrs.pcr_selections[0].hash);
  EXPECT_EQ(PCR_SELECT_MIN, creation_pcrs.pcr_selections[0].sizeof_select);
  EXPECT_EQ(1u << (creation_pcr % 8),
            creation_pcrs.pcr_selections[0].pcr_select[creation_pcr / 8]);
}

TEST_F(TpmUtilityTest, CreateRSAKeyPairMultiplePCRSuccess) {
  TPM2B_PUBLIC public_area;
  TPML_PCR_SELECTION creation_pcrs;
  EXPECT_CALL(mock_tpm_, CreateSyncShort(kRSAStorageRootKey, _, _, _, _, _, _,
                                         _, _, &mock_authorization_delegate_))
      .WillOnce(DoAll(SaveArg<2>(&public_area), SaveArg<3>(&creation_pcrs),
                      Return(TPM_RC_SUCCESS)));
  std::string key_blob;
  std::string creation_blob;
  std::vector<uint32_t> creation_pcr_indexes({0, 2});
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.CreateRSAKeyPair(
                TpmUtility::AsymmetricKeyUsage::kDecryptAndSignKey, 2048,
                0x10001, "password", "", false, creation_pcr_indexes,
                &mock_authorization_delegate_, &key_blob, &creation_blob));
  EXPECT_EQ(public_area.public_area.object_attributes & kDecrypt, kDecrypt);
  EXPECT_EQ(public_area.public_area.object_attributes & kSign, kSign);
  EXPECT_EQ(public_area.public_area.object_attributes & kUserWithAuth,
            kUserWithAuth);
  EXPECT_EQ(public_area.public_area.object_attributes & kAdminWithPolicy, 0u);
  EXPECT_EQ(public_area.public_area.parameters.rsa_detail.scheme.scheme,
            TPM_ALG_NULL);
  EXPECT_EQ(1u, creation_pcrs.count);
  TPMS_PCR_SELECTION pcr_selection = creation_pcrs.pcr_selections[0];
  EXPECT_EQ(TPM_ALG_SHA256, pcr_selection.hash);
  EXPECT_EQ(PCR_SELECT_MIN, pcr_selection.sizeof_select);
  EXPECT_EQ(creation_pcr_indexes.size(),
            CountSetBits(pcr_selection.pcr_select, PCR_SELECT_MIN));
  for (uint32_t pcr_index : creation_pcr_indexes) {
    uint8_t creation_pcr_index = pcr_index / 8;
    uint8_t creation_pcr_mask = 1u << (pcr_index % 8);
    EXPECT_EQ(creation_pcr_mask,
              creation_pcr_mask & pcr_selection.pcr_select[creation_pcr_index]);
  }
}

TEST_F(TpmUtilityTest, CreateRSAKeyPairDecryptKeySuccess) {
  TPM2B_PUBLIC public_area;
  EXPECT_CALL(mock_tpm_, CreateSyncShort(kRSAStorageRootKey, _, _, _, _, _, _,
                                         _, _, &mock_authorization_delegate_))
      .WillOnce(DoAll(SaveArg<2>(&public_area), Return(TPM_RC_SUCCESS)));
  std::string key_blob;
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.CreateRSAKeyPair(
                TpmUtility::AsymmetricKeyUsage::kDecryptKey, 2048, 0x10001,
                "password", "", false, std::vector<uint32_t>(),
                &mock_authorization_delegate_, &key_blob, nullptr));
  EXPECT_EQ(public_area.public_area.object_attributes & kDecrypt, kDecrypt);
  EXPECT_EQ(public_area.public_area.object_attributes & kSign, 0u);
  EXPECT_EQ(public_area.public_area.parameters.rsa_detail.scheme.scheme,
            TPM_ALG_NULL);
}

TEST_F(TpmUtilityTest, CreateRSAKeyPairSignKeySuccess) {
  TPM2B_PUBLIC public_area;
  TPM2B_SENSITIVE_CREATE sensitive_create;
  EXPECT_CALL(mock_tpm_state_, Initialize())
      .WillOnce(Return(TPM_RC_SUCCESS));
  EXPECT_CALL(mock_tpm_state_, GetTpmProperty(TPM_PT_MANUFACTURER, _))
      .WillOnce(DoAll(SetArgPointee<1>(kVendorIdCr50), Return(true)));
  EXPECT_CALL(mock_tpm_, CreateSyncShort(kRSAStorageRootKey, _, _, _, _, _, _,
                                         _, _, &mock_authorization_delegate_))
      .WillOnce(DoAll(SaveArg<1>(&sensitive_create), SaveArg<2>(&public_area),
                      Return(TPM_RC_SUCCESS)));
  std::string key_blob;
  std::string policy_digest(32, 'a');
  std::string key_auth("password");
  EXPECT_EQ(
      TPM_RC_SUCCESS,
      utility_.CreateRSAKeyPair(
          TpmUtility::AsymmetricKeyUsage::kSignKey, 2048, 0x10001, key_auth,
          policy_digest, true /* use_only_policy_authorization */,
          std::vector<uint32_t>(), &mock_authorization_delegate_, &key_blob,
          nullptr));
  EXPECT_EQ(public_area.public_area.object_attributes & kDecrypt, 0u);
  EXPECT_EQ(public_area.public_area.object_attributes & kSign, kSign);
  EXPECT_EQ(public_area.public_area.object_attributes & kUserWithAuth, 0u);
  EXPECT_EQ(public_area.public_area.object_attributes & kAdminWithPolicy,
            kAdminWithPolicy);
  EXPECT_EQ(public_area.public_area.parameters.rsa_detail.scheme.scheme,
            TPM_ALG_NULL);
  EXPECT_EQ(public_area.public_area.parameters.rsa_detail.key_bits, 2048);
  EXPECT_EQ(public_area.public_area.parameters.rsa_detail.exponent, 0x10001u);
  EXPECT_EQ(public_area.public_area.auth_policy.size, policy_digest.size());
  EXPECT_EQ(0, memcmp(public_area.public_area.auth_policy.buffer,
                      policy_digest.data(), policy_digest.size()));
  EXPECT_EQ(sensitive_create.sensitive.user_auth.size, key_auth.size());
  EXPECT_EQ(0, memcmp(sensitive_create.sensitive.user_auth.buffer,
                      key_auth.data(), key_auth.size()));
}

TEST_F(TpmUtilityTest, CreateRSAKeyPairSignKeySuccessNoPaddingOnlyAlg) {
  // Unknown vendor - no padding-only alg support expected for TPM.
  uint32_t vendor_id = 0xaabbccdd;
  TPM2B_PUBLIC public_area;
  EXPECT_CALL(mock_tpm_state_, Initialize())
      .WillOnce(Return(TPM_RC_SUCCESS));
  EXPECT_CALL(mock_tpm_state_, GetTpmProperty(TPM_PT_MANUFACTURER, _))
      .WillOnce(DoAll(SetArgPointee<1>(vendor_id), Return(true)));
  EXPECT_CALL(mock_tpm_, CreateSyncShort(_, _, _, _, _, _, _, _, _, _))
      .WillOnce(DoAll(SaveArg<2>(&public_area), Return(TPM_RC_SUCCESS)));
  std::string key_blob;
  std::string policy_digest(32, 'a');
  std::string key_auth("password");
  EXPECT_EQ(
      TPM_RC_SUCCESS,
      utility_.CreateRSAKeyPair(
          TpmUtility::AsymmetricKeyUsage::kSignKey, 2048, 0x10001, key_auth,
          policy_digest, true /* use_only_policy_authorization */,
          std::vector<uint32_t>(), &mock_authorization_delegate_, &key_blob,
          nullptr));
  EXPECT_EQ(public_area.public_area.object_attributes & kDecrypt, kDecrypt);
  EXPECT_EQ(public_area.public_area.object_attributes & kSign, kSign);
}

TEST_F(TpmUtilityTest, CreateRSAKeyPairBadDelegate) {
  std::string key_blob;
  EXPECT_EQ(
      SAPI_RC_INVALID_SESSIONS,
      utility_.CreateRSAKeyPair(TpmUtility::AsymmetricKeyUsage::kDecryptKey,
                                2048, 0x10001, "password", "", false,
                                std::vector<uint32_t>(), nullptr, &key_blob,
                                nullptr));
}

TEST_F(TpmUtilityTest, CreateRSAKeyPairFailure) {
  EXPECT_CALL(mock_tpm_state_, Initialize())
      .WillOnce(Return(TPM_RC_SUCCESS));
  EXPECT_CALL(mock_tpm_state_, GetTpmProperty(TPM_PT_MANUFACTURER, _))
      .WillOnce(DoAll(SetArgPointee<1>(kVendorIdCr50), Return(true)));
  EXPECT_CALL(mock_tpm_, CreateSyncShort(kRSAStorageRootKey, _, _, _, _, _, _,
                                         _, _, &mock_authorization_delegate_))
      .WillOnce(Return(TPM_RC_FAILURE));
  std::string key_blob;
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.CreateRSAKeyPair(
                TpmUtility::AsymmetricKeyUsage::kSignKey, 2048, 0x10001,
                "password", "", false, std::vector<uint32_t>(),
                &mock_authorization_delegate_, &key_blob, nullptr));
}

TEST_F(TpmUtilityTest, CreateRSAKeyPairKeyParserFail) {
  std::string key_blob;
  EXPECT_CALL(mock_tpm_state_, Initialize())
      .WillOnce(Return(TPM_RC_SUCCESS));
  EXPECT_CALL(mock_tpm_state_, GetTpmProperty(TPM_PT_MANUFACTURER, _))
      .WillOnce(DoAll(SetArgPointee<1>(kVendorIdCr50), Return(true)));
  EXPECT_CALL(mock_blob_parser_, SerializeKeyBlob(_, _, &key_blob))
      .WillOnce(Return(false));
  EXPECT_EQ(SAPI_RC_BAD_TCTI_STRUCTURE,
            utility_.CreateRSAKeyPair(
                TpmUtility::AsymmetricKeyUsage::kSignKey, 2048, 0x10001,
                "password", "", false, std::vector<uint32_t>(),
                &mock_authorization_delegate_, &key_blob, nullptr));
}

TEST_F(TpmUtilityTest, CreateRSAKeyPairCreationParserFail) {
  std::string creation_blob;
  std::string key_blob;
  EXPECT_CALL(mock_tpm_state_, Initialize())
      .WillOnce(Return(TPM_RC_SUCCESS));
  EXPECT_CALL(mock_tpm_state_, GetTpmProperty(TPM_PT_MANUFACTURER, _))
      .WillOnce(DoAll(SetArgPointee<1>(kVendorIdCr50), Return(true)));
  EXPECT_CALL(mock_blob_parser_, SerializeCreationBlob(_, _, _, &creation_blob))
      .WillOnce(Return(false));
  EXPECT_EQ(SAPI_RC_BAD_TCTI_STRUCTURE,
            utility_.CreateRSAKeyPair(
                TpmUtility::AsymmetricKeyUsage::kSignKey, 2048, 0x10001,
                "password", "", false, std::vector<uint32_t>(),
                &mock_authorization_delegate_, &key_blob, &creation_blob));
}

TEST_F(TpmUtilityTest, LoadKeySuccess) {
  TPM_HANDLE key_handle = TPM_RH_FIRST;
  TPM_HANDLE loaded_handle;
  EXPECT_CALL(mock_tpm_, LoadSync(kRSAStorageRootKey, _, _, _, _, _,
                                  &mock_authorization_delegate_))
      .WillOnce(DoAll(SetArgPointee<4>(key_handle), Return(TPM_RC_SUCCESS)));
  std::string key_blob;
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.LoadKey(key_blob, &mock_authorization_delegate_,
                             &loaded_handle));
  EXPECT_EQ(loaded_handle, key_handle);
}

TEST_F(TpmUtilityTest, LoadKeyFailure) {
  TPM_HANDLE key_handle;
  EXPECT_CALL(mock_tpm_, LoadSync(_, _, _, _, _, _, _))
      .WillOnce(Return(TPM_RC_FAILURE));
  std::string key_blob;
  EXPECT_EQ(
      TPM_RC_FAILURE,
      utility_.LoadKey(key_blob, &mock_authorization_delegate_, &key_handle));
}

TEST_F(TpmUtilityTest, LoadKeyBadDelegate) {
  TPM_HANDLE key_handle;
  std::string key_blob;
  EXPECT_EQ(SAPI_RC_INVALID_SESSIONS,
            utility_.LoadKey(key_blob, nullptr, &key_handle));
}

TEST_F(TpmUtilityTest, LoadKeyParserFail) {
  TPM_HANDLE key_handle;
  std::string key_blob;
  EXPECT_CALL(mock_blob_parser_, ParseKeyBlob(key_blob, _, _))
      .WillOnce(Return(false));
  EXPECT_EQ(
      SAPI_RC_BAD_TCTI_STRUCTURE,
      utility_.LoadKey(key_blob, &mock_authorization_delegate_, &key_handle));
}

TEST_F(TpmUtilityTest, LoadRSAPublicKey) {
  const TPM_HANDLE kKeyHandle = TPM_RH_FIRST;
  const std::string kModulus(128, '\1');
  const int kModulusSizeBits = 1024;
  const uint32_t kPublicExponent = 3;

  TPM2B_SENSITIVE in_private_arg;
  memset(&in_private_arg, 0, sizeof(TPM2B_SENSITIVE));
  TPM2B_PUBLIC in_public_arg;
  memset(&in_public_arg, 0, sizeof(TPM2B_PUBLIC));
  TPMI_RH_HIERARCHY hierarchy_arg = 0;
  TPM_HANDLE loaded_handle = 0;

  // Test a signing RSASSA SHA-256 key.
  EXPECT_CALL(mock_tpm_,
              LoadExternalSync(_, _, _, _, _, &mock_authorization_delegate_))
      .WillOnce(DoAll(SaveArg<0>(&in_private_arg), SaveArg<1>(&in_public_arg),
                      SaveArg<2>(&hierarchy_arg), SetArgPointee<3>(kKeyHandle),
                      Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.LoadRSAPublicKey(
                TpmUtility::AsymmetricKeyUsage::kSignKey, TPM_ALG_RSASSA,
                TPM_ALG_SHA256, kModulus, kPublicExponent,
                &mock_authorization_delegate_, &loaded_handle));
  testing::Mock::VerifyAndClearExpectations(&mock_tpm_);
  EXPECT_EQ(0, in_private_arg.size);
  EXPECT_EQ(kSign | kFixedTPM | kFixedParent,
            in_public_arg.public_area.object_attributes);
  EXPECT_EQ(TPM_ALG_RSASSA,
            in_public_arg.public_area.parameters.rsa_detail.scheme.scheme);
  EXPECT_EQ(TPM_ALG_SHA256, in_public_arg.public_area.parameters.rsa_detail
                                .scheme.details.rsassa.hash_alg);
  EXPECT_EQ(kModulusSizeBits,
            in_public_arg.public_area.parameters.rsa_detail.key_bits);
  EXPECT_EQ(kPublicExponent,
            in_public_arg.public_area.parameters.rsa_detail.exponent);
  EXPECT_EQ(kModulus, StringFrom_TPM2B_PUBLIC_KEY_RSA(
                          in_public_arg.public_area.unique.rsa));
  EXPECT_EQ(TPM_RH_NULL, hierarchy_arg);
  EXPECT_EQ(kKeyHandle, loaded_handle);

  // Test a signing SHA-256 key with the default (RSASSA) scheme.
  memset(&in_public_arg, 0, sizeof(TPM2B_PUBLIC));
  EXPECT_CALL(mock_tpm_,
              LoadExternalSync(_, _, _, _, _, &mock_authorization_delegate_))
      .WillOnce(DoAll(SaveArg<1>(&in_public_arg), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.LoadRSAPublicKey(
                TpmUtility::AsymmetricKeyUsage::kSignKey, TPM_ALG_NULL,
                TPM_ALG_SHA256, kModulus, kPublicExponent,
                &mock_authorization_delegate_, &loaded_handle));
  testing::Mock::VerifyAndClearExpectations(&mock_tpm_);
  EXPECT_EQ(kSign | kFixedTPM | kFixedParent,
            in_public_arg.public_area.object_attributes);
  EXPECT_EQ(TPM_ALG_RSASSA,
            in_public_arg.public_area.parameters.rsa_detail.scheme.scheme);
  EXPECT_EQ(TPM_ALG_SHA256, in_public_arg.public_area.parameters.rsa_detail
                                .scheme.details.rsassa.hash_alg);

  // Test a signing RSAPSS SHA-512 key.
  memset(&in_public_arg, 0, sizeof(TPM2B_PUBLIC));
  EXPECT_CALL(mock_tpm_,
              LoadExternalSync(_, _, _, _, _, &mock_authorization_delegate_))
      .WillOnce(DoAll(SaveArg<1>(&in_public_arg), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.LoadRSAPublicKey(
                TpmUtility::AsymmetricKeyUsage::kSignKey, TPM_ALG_RSAPSS,
                TPM_ALG_SHA512, kModulus, kPublicExponent,
                &mock_authorization_delegate_, &loaded_handle));
  testing::Mock::VerifyAndClearExpectations(&mock_tpm_);
  EXPECT_EQ(kSign | kFixedTPM | kFixedParent,
            in_public_arg.public_area.object_attributes);
  EXPECT_EQ(TPM_ALG_RSAPSS,
            in_public_arg.public_area.parameters.rsa_detail.scheme.scheme);
  EXPECT_EQ(TPM_ALG_SHA512, in_public_arg.public_area.parameters.rsa_detail
                                .scheme.details.rsapss.hash_alg);

  // Test a decrypting OAEP SHA-256 key.
  memset(&in_public_arg, 0, sizeof(TPM2B_PUBLIC));
  EXPECT_CALL(mock_tpm_,
              LoadExternalSync(_, _, _, _, _, &mock_authorization_delegate_))
      .WillOnce(DoAll(SaveArg<1>(&in_public_arg), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.LoadRSAPublicKey(
                TpmUtility::AsymmetricKeyUsage::kDecryptKey, TPM_ALG_OAEP,
                TPM_ALG_SHA256, kModulus, kPublicExponent,
                &mock_authorization_delegate_, &loaded_handle));
  testing::Mock::VerifyAndClearExpectations(&mock_tpm_);
  EXPECT_EQ(kDecrypt | kFixedTPM | kFixedParent,
            in_public_arg.public_area.object_attributes);
  EXPECT_EQ(TPM_ALG_OAEP,
            in_public_arg.public_area.parameters.rsa_detail.scheme.scheme);
  EXPECT_EQ(TPM_ALG_SHA256, in_public_arg.public_area.parameters.rsa_detail
                                .scheme.details.oaep.hash_alg);

  // Test a decrypting SHA-256 key with the default (OAEP) scheme.
  memset(&in_public_arg, 0, sizeof(TPM2B_PUBLIC));
  EXPECT_CALL(mock_tpm_,
              LoadExternalSync(_, _, _, _, _, &mock_authorization_delegate_))
      .WillOnce(DoAll(SaveArg<1>(&in_public_arg), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.LoadRSAPublicKey(
                TpmUtility::AsymmetricKeyUsage::kDecryptKey, TPM_ALG_NULL,
                TPM_ALG_SHA256, kModulus, kPublicExponent,
                &mock_authorization_delegate_, &loaded_handle));
  testing::Mock::VerifyAndClearExpectations(&mock_tpm_);
  EXPECT_EQ(kDecrypt | kFixedTPM | kFixedParent,
            in_public_arg.public_area.object_attributes);
  EXPECT_EQ(TPM_ALG_OAEP,
            in_public_arg.public_area.parameters.rsa_detail.scheme.scheme);
  EXPECT_EQ(TPM_ALG_SHA256, in_public_arg.public_area.parameters.rsa_detail
                                .scheme.details.oaep.hash_alg);

  // Test a decrypting RSAES key.
  memset(&in_public_arg, 0, sizeof(TPM2B_PUBLIC));
  EXPECT_CALL(mock_tpm_,
              LoadExternalSync(_, _, _, _, _, &mock_authorization_delegate_))
      .WillOnce(DoAll(SaveArg<1>(&in_public_arg), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.LoadRSAPublicKey(
                TpmUtility::AsymmetricKeyUsage::kDecryptKey, TPM_ALG_RSAES,
                TPM_ALG_NULL, kModulus, kPublicExponent,
                &mock_authorization_delegate_, &loaded_handle));
  testing::Mock::VerifyAndClearExpectations(&mock_tpm_);
  EXPECT_EQ(kDecrypt | kFixedTPM | kFixedParent,
            in_public_arg.public_area.object_attributes);
  EXPECT_EQ(TPM_ALG_RSAES,
            in_public_arg.public_area.parameters.rsa_detail.scheme.scheme);

  // Test a key that is both for decrypting and signing.
  memset(&in_public_arg, 0, sizeof(TPM2B_PUBLIC));
  EXPECT_CALL(mock_tpm_,
              LoadExternalSync(_, _, _, _, _, &mock_authorization_delegate_))
      .WillOnce(DoAll(SaveArg<1>(&in_public_arg), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.LoadRSAPublicKey(
                TpmUtility::AsymmetricKeyUsage::kDecryptAndSignKey,
                TPM_ALG_NULL, TPM_ALG_NULL, kModulus, kPublicExponent,
                &mock_authorization_delegate_, &loaded_handle));
  testing::Mock::VerifyAndClearExpectations(&mock_tpm_);
  EXPECT_EQ(kDecrypt | kSign | kFixedTPM | kFixedParent,
            in_public_arg.public_area.object_attributes);
  EXPECT_EQ(TPM_ALG_NULL,
            in_public_arg.public_area.parameters.rsa_detail.scheme.scheme);
}

TEST_F(TpmUtilityTest, SealedDataSuccess) {
  std::string data_to_seal("seal_data");
  std::string sealed_data;
  TPM2B_SENSITIVE_CREATE sensitive_create;
  TPM2B_PUBLIC in_public;
  EXPECT_CALL(mock_tpm_,
              CreateSyncShort(kRSAStorageRootKey, _, _, _, _, _, _, _, _, _))
      .WillOnce(DoAll(SaveArg<1>(&sensitive_create), SaveArg<2>(&in_public),
                      Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.SealData(data_to_seal, "", &mock_authorization_delegate_,
                              &sealed_data));
  EXPECT_EQ(sensitive_create.sensitive.data.size, data_to_seal.size());
  EXPECT_EQ(0, memcmp(sensitive_create.sensitive.data.buffer,
                      data_to_seal.data(), data_to_seal.size()));
  EXPECT_EQ(in_public.public_area.type, TPM_ALG_KEYEDHASH);
  EXPECT_EQ(in_public.public_area.name_alg, TPM_ALG_SHA256);
}

TEST_F(TpmUtilityTest, SealDataBadDelegate) {
  std::string data_to_seal("seal_data");
  std::string sealed_data;
  EXPECT_EQ(SAPI_RC_INVALID_SESSIONS,
            utility_.SealData(data_to_seal, "", nullptr, &sealed_data));
}

TEST_F(TpmUtilityTest, SealDataFailure) {
  std::string data_to_seal("seal_data");
  std::string sealed_data;
  EXPECT_CALL(mock_tpm_,
              CreateSyncShort(kRSAStorageRootKey, _, _, _, _, _, _, _, _, _))
      .WillOnce(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.SealData(data_to_seal, "", &mock_authorization_delegate_,
                              &sealed_data));
}

TEST_F(TpmUtilityTest, SealDataParserFail) {
  std::string data_to_seal("seal_data");
  std::string sealed_data;
  EXPECT_CALL(mock_blob_parser_, SerializeKeyBlob(_, _, &sealed_data))
      .WillOnce(Return(false));
  EXPECT_EQ(SAPI_RC_BAD_TCTI_STRUCTURE,
            utility_.SealData(data_to_seal, "", &mock_authorization_delegate_,
                              &sealed_data));
}

TEST_F(TpmUtilityTest, UnsealDataSuccess) {
  std::string sealed_data;
  std::string tpm_unsealed_data("password");
  std::string unsealed_data;
  TPM_HANDLE object_handle = 42;
  TPM2B_PUBLIC public_data;
  public_data.public_area.auth_policy.size = 0;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(_, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_data), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, ReadPublicSync(object_handle, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<2>(public_data), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, LoadSync(_, _, _, _, _, _, _))
      .WillOnce(DoAll(SetArgPointee<4>(object_handle), Return(TPM_RC_SUCCESS)));
  TPM2B_SENSITIVE_DATA out_data = Make_TPM2B_SENSITIVE_DATA(tpm_unsealed_data);
  EXPECT_CALL(mock_tpm_, UnsealSync(object_handle, _, _, _))
      .WillOnce(DoAll(SetArgPointee<2>(out_data), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.UnsealData(sealed_data, &mock_authorization_delegate_,
                                &unsealed_data));
  EXPECT_EQ(unsealed_data, tpm_unsealed_data);
}

TEST_F(TpmUtilityTest, UnsealDataBadDelegate) {
  std::string sealed_data;
  std::string unsealed_data;
  EXPECT_EQ(SAPI_RC_INVALID_SESSIONS,
            utility_.UnsealData(sealed_data, nullptr, &unsealed_data));
}

TEST_F(TpmUtilityTest, UnsealDataLoadFail) {
  std::string sealed_data;
  std::string unsealed_data;
  EXPECT_CALL(mock_tpm_, LoadSync(_, _, _, _, _, _, _))
      .WillOnce(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.UnsealData(sealed_data, &mock_authorization_delegate_,
                                &unsealed_data));
}

TEST_F(TpmUtilityTest, UnsealDataBadKeyName) {
  std::string sealed_data;
  std::string unsealed_data;
  EXPECT_CALL(mock_tpm_, ReadPublicSync(_, _, _, _, _, _))
      .WillOnce(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.UnsealData(sealed_data, &mock_authorization_delegate_,
                                &unsealed_data));
}

TEST_F(TpmUtilityTest, UnsealObjectFailure) {
  std::string sealed_data;
  std::string unsealed_data;
  EXPECT_CALL(mock_tpm_, UnsealSync(_, _, _, _))
      .WillOnce(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.UnsealData(sealed_data, &mock_authorization_delegate_,
                                &unsealed_data));
}

TEST_F(TpmUtilityTest, StartSessionSuccess) {
  EXPECT_CALL(mock_hmac_session_, StartUnboundSession(true, true))
      .WillOnce(Return(TPM_RC_SUCCESS));
  EXPECT_EQ(TPM_RC_SUCCESS, utility_.StartSession(&mock_hmac_session_));
}

TEST_F(TpmUtilityTest, StartSessionFailure) {
  EXPECT_CALL(mock_hmac_session_, StartUnboundSession(true, true))
      .WillOnce(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE, utility_.StartSession(&mock_hmac_session_));
}

TEST_F(TpmUtilityTest, GetPolicyDigestForPcrValuesSuccess) {
  uint32_t index = 5;
  std::string pcr_value("pcr_value");
  std::string policy_digest;
  TPML_PCR_SELECTION pcr_select;
  pcr_select.count = 1;
  pcr_select.pcr_selections[0].hash = TPM_ALG_SHA256;
  pcr_select.pcr_selections[0].sizeof_select = 1;
  pcr_select.pcr_selections[0].pcr_select[index / 8] = 1 << (index % 8);
  TPML_DIGEST pcr_values;
  pcr_values.count = 1;
  pcr_values.digests[0] = Make_TPM2B_DIGEST(pcr_value);
  EXPECT_CALL(mock_tpm_, PCR_ReadSync(_, _, _, _, _))
      .WillOnce(DoAll(SetArgPointee<2>(pcr_select),
                      SetArgPointee<3>(pcr_values), Return(TPM_RC_SUCCESS)));
  std::map<uint32_t, std::string> pcr_map;
  EXPECT_CALL(mock_trial_session_, PolicyPCR(_))
      .WillOnce(DoAll(SaveArg<0>(&pcr_map),
                      Return(TPM_RC_SUCCESS)));
  std::string tpm_policy_digest("digest");
  EXPECT_CALL(mock_trial_session_, GetDigest(_))
      .WillOnce(
          DoAll(SetArgPointee<0>(tpm_policy_digest), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.GetPolicyDigestForPcrValues(
                std::map<uint32_t, std::string>({{index, ""}}),
                &policy_digest));
  EXPECT_EQ(policy_digest, tpm_policy_digest);
  EXPECT_EQ(pcr_value, pcr_map[index]);
}

TEST_F(TpmUtilityTest, GetPolicyDigestForPcrValuesSuccessWithPcrValue) {
  uint32_t index = 5;
  std::string pcr_value("pcr_value");
  std::string policy_digest;
  std::map<uint32_t, std::string> pcr_map;
  EXPECT_CALL(mock_trial_session_,
              PolicyPCR(_))
      .WillOnce(DoAll(SaveArg<0>(&pcr_map),
                      Return(TPM_RC_SUCCESS)));
  std::string tpm_policy_digest("digest");
  EXPECT_CALL(mock_trial_session_, GetDigest(_))
      .WillOnce(
          DoAll(SetArgPointee<0>(tpm_policy_digest), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.GetPolicyDigestForPcrValues(
                std::map<uint32_t, std::string>({{index, pcr_value}}),
                &policy_digest));
  EXPECT_EQ(policy_digest, tpm_policy_digest);
  EXPECT_EQ(pcr_value, pcr_map[index]);
}

TEST_F(TpmUtilityTest, GetPolicyDigestForPcrValuesSuccessMultiplePcrs) {
  uint32_t index1 = 5;
  std::string pcr_value1("pcr_value1");
  uint32_t index2 = 6;
  std::string pcr_value2("pcr_value2");
  uint32_t index3 = 13;
  std::string pcr_value3("");
  std::string policy_digest;
  TPML_PCR_SELECTION pcr_select;
  pcr_select.count = 1;
  pcr_select.pcr_selections[0].hash = TPM_ALG_SHA256;
  pcr_select.pcr_selections[0].sizeof_select = 2;
  pcr_select.pcr_selections[0].pcr_select[index3 / 8] = 1 << (index3 % 8);
  TPML_DIGEST pcr_values;
  pcr_values.count = 1;
  pcr_values.digests[0] = Make_TPM2B_DIGEST(pcr_value3);
  std::map<uint32_t, std::string> pcr_map;
  EXPECT_CALL(mock_trial_session_,
              PolicyPCR(_))
      .WillOnce(DoAll(SaveArg<0>(&pcr_map),
                      Return(TPM_RC_SUCCESS)));
  std::string tpm_policy_digest("digest");
  EXPECT_CALL(mock_trial_session_, GetDigest(_))
      .WillOnce(
          DoAll(SetArgPointee<0>(tpm_policy_digest), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, PCR_ReadSync(_, _, _, _, _))
      .WillOnce(DoAll(SetArgPointee<2>(pcr_select),
                      SetArgPointee<3>(pcr_values), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.GetPolicyDigestForPcrValues(
                std::map<uint32_t, std::string>(
                    {{index1, pcr_value1},
                     {index2, pcr_value2},
                     {index3, pcr_value3}}),
                &policy_digest));
  EXPECT_EQ(policy_digest, tpm_policy_digest);
  EXPECT_EQ(pcr_value1, pcr_map[index1]);
  EXPECT_EQ(pcr_value2, pcr_map[index2]);
  EXPECT_EQ(pcr_value3, pcr_map[index3]);
}

TEST_F(TpmUtilityTest, GetPolicyDigestForPcrValuesBadSession) {
  int index = 5;
  std::string pcr_value("value");
  std::string policy_digest;
  EXPECT_CALL(mock_trial_session_, StartUnboundSession(true, false))
      .WillOnce(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.GetPolicyDigestForPcrValues(
                std::map<uint32_t, std::string>({{index, pcr_value}}),
                &policy_digest));
}

TEST_F(TpmUtilityTest, GetPolicyDigestForPcrValuesPcrReadFail) {
  int index = 5;
  std::string policy_digest;
  EXPECT_CALL(mock_tpm_, PCR_ReadSync(_, _, _, _, _))
      .WillOnce(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.GetPolicyDigestForPcrValues(
                std::map<uint32_t, std::string>({{index, ""}}),
                &policy_digest));
}

TEST_F(TpmUtilityTest, GetPolicyDigestForPcrValuesBadPcr) {
  int index = 5;
  std::string pcr_value("value");
  std::string policy_digest;
  EXPECT_CALL(mock_trial_session_,
              PolicyPCR(_))
      .WillOnce(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.GetPolicyDigestForPcrValues(
                std::map<uint32_t, std::string>({{index, pcr_value}}),
                &policy_digest));
}

TEST_F(TpmUtilityTest, GetPolicyDigestForPcrValuesBadDigest) {
  int index = 5;
  std::string pcr_value("value");
  std::string policy_digest;
  EXPECT_CALL(mock_trial_session_, GetDigest(&policy_digest))
      .WillOnce(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.GetPolicyDigestForPcrValues(
                std::map<uint32_t, std::string>({{index, pcr_value}}),
                &policy_digest));
}

TEST_F(NVTpmUtilityTest, DefineNVSpaceSuccess) {
  TPM2B_NV_PUBLIC public_data;
  EXPECT_CALL(mock_tpm_, NV_DefineSpaceSync(TPM_RH_OWNER, _, _, _, _))
      .WillOnce(DoAll(SaveArg<3>(&public_data), Return(TPM_RC_SUCCESS)));

  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.DefineNVSpace(kNvIndex, kNvDataSize, kNvAttributes, "", "",
                                   &mock_authorization_delegate_));
  EXPECT_TRUE(public_data.size);
  EXPECT_EQ(public_data.nv_public.nv_index, kNvTpmIndex);
  EXPECT_EQ(public_data.nv_public.name_alg, kNvNameAlg);
  EXPECT_EQ(public_data.nv_public.attributes, kNvAttributes);
  EXPECT_EQ(public_data.nv_public.data_size, kNvDataSize);
}

TEST_F(NVTpmUtilityTest, DefineNVSpaceBadLength) {
  size_t bad_length = MAX_NV_INDEX_SIZE + 1;
  EXPECT_CALL(mock_tpm_, NV_DefineSpaceSync(_, _, _, _, _)).Times(0);

  EXPECT_EQ(SAPI_RC_BAD_SIZE,
            utility_.DefineNVSpace(kNvIndex, bad_length, kNvAttributes, "", "",
                                   &mock_authorization_delegate_));
}

TEST_F(NVTpmUtilityTest, DefineNVSpaceBadIndex) {
  EXPECT_CALL(mock_tpm_, NV_DefineSpaceSync(_, _, _, _, _)).Times(0);

  EXPECT_EQ(SAPI_RC_BAD_PARAMETER,
            utility_.DefineNVSpace(kNvBadIndex, kNvDataSize, kNvAttributes, "",
                                   "", &mock_authorization_delegate_));
}

TEST_F(NVTpmUtilityTest, DefineNVSpaceBadSession) {
  EXPECT_CALL(mock_tpm_, NV_DefineSpaceSync(_, _, _, _, _)).Times(0);

  EXPECT_EQ(SAPI_RC_INVALID_SESSIONS,
            utility_.DefineNVSpace(kNvIndex, kNvDataSize, kNvAttributes, "", "",
                                   nullptr));
}

TEST_F(NVTpmUtilityTest, DefineNVSpaceFail) {
  EXPECT_CALL(mock_tpm_, NV_DefineSpaceSync(TPM_RH_OWNER, _, _, _, _))
      .WillOnce(Return(TPM_RC_FAILURE));

  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.DefineNVSpace(kNvIndex, kNvDataSize, kNvAttributes, "", "",
                                   &mock_authorization_delegate_));
}

TEST_F(NVTpmUtilityTest, DestroyNVSpaceSuccess) {
  EXPECT_CALL(mock_tpm_, NV_ReadPublicSync(kNvTpmIndex, _, _, _, _))
      .WillOnce(
          DoAll(SetArgPointee<2>(kTpm2bNvPublic), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_,
              NV_UndefineSpaceSync(TPM_RH_OWNER, _, kNvTpmIndex, _, _));

  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.DestroyNVSpace(kNvIndex, &mock_authorization_delegate_));
}

TEST_F(NVTpmUtilityTest, DestroyNVSpaceBadIndex) {
  EXPECT_CALL(mock_tpm_, NV_UndefineSpaceSync(_, _, _, _, _)).Times(0);

  EXPECT_EQ(
      SAPI_RC_BAD_PARAMETER,
      utility_.DestroyNVSpace(kNvBadIndex, &mock_authorization_delegate_));
}

TEST_F(NVTpmUtilityTest, DestroyNVSpaceBadSession) {
  EXPECT_CALL(mock_tpm_, NV_UndefineSpaceSync(_, _, _, _, _)).Times(0);

  EXPECT_EQ(SAPI_RC_INVALID_SESSIONS,
            utility_.DestroyNVSpace(kNvIndex, nullptr));
}

TEST_F(NVTpmUtilityTest, DestroyNVSpaceFailure) {
  EXPECT_CALL(mock_tpm_, NV_ReadPublicSync(kNvTpmIndex, _, _, _, _))
      .WillOnce(
          DoAll(SetArgPointee<2>(kTpm2bNvPublic), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_,
              NV_UndefineSpaceSync(TPM_RH_OWNER, _, kNvTpmIndex, _, _))
      .WillOnce(Return(TPM_RC_FAILURE));

  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.DestroyNVSpace(kNvIndex, &mock_authorization_delegate_));
}

TEST_F(NVTpmUtilityTest, LockNVSpaceWriteSuccess) {
  EXPECT_FALSE(kNvAttributes & TPMA_NV_WRITELOCKED);

  EXPECT_CALL(mock_tpm_, NV_ReadPublicSync(kNvTpmIndex, _, _, _, _))
      .WillOnce(
          DoAll(SetArgPointee<2>(kTpm2bNvPublic), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, NV_WriteLockSync(TPM_RH_OWNER, _, kNvTpmIndex, _, _))
      .WillOnce(Return(TPM_RC_SUCCESS));
  EXPECT_CALL(mock_tpm_, NV_ReadLockSync(TPM_RH_OWNER, _, kNvTpmIndex, _, _))
      .Times(0);

  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.LockNVSpace(kNvIndex, false, true, true,
                                 &mock_authorization_delegate_));
  TPMS_NV_PUBLIC public_area;
  EXPECT_EQ(TPM_RC_SUCCESS, GetNVRAMMap(kNvIndex, &public_area));
  EXPECT_EQ(kNvAttributes | TPMA_NV_WRITELOCKED, public_area.attributes);
}

TEST_F(NVTpmUtilityTest, LockNVSpaceReadSuccess) {
  EXPECT_FALSE(kNvAttributes & TPMA_NV_READLOCKED);

  EXPECT_CALL(mock_tpm_, NV_ReadPublicSync(kNvTpmIndex, _, _, _, _))
      .WillOnce(
          DoAll(SetArgPointee<2>(kTpm2bNvPublic), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, NV_WriteLockSync(TPM_RH_OWNER, _, kNvTpmIndex, _, _))
      .Times(0);
  EXPECT_CALL(mock_tpm_, NV_ReadLockSync(TPM_RH_OWNER, _, kNvTpmIndex, _, _))
      .WillOnce(Return(TPM_RC_SUCCESS));

  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.LockNVSpace(kNvIndex, true, false, true,
                                 &mock_authorization_delegate_));
  TPMS_NV_PUBLIC public_area;
  EXPECT_EQ(TPM_RC_SUCCESS, GetNVRAMMap(kNvIndex, &public_area));
  EXPECT_EQ(kNvAttributes | TPMA_NV_READLOCKED, public_area.attributes);
}

TEST_F(NVTpmUtilityTest, LockNVSpaceBothSuccess) {
  EXPECT_FALSE(kNvAttributes & (TPMA_NV_READLOCKED | TPMA_NV_WRITELOCKED));

  EXPECT_CALL(mock_tpm_, NV_ReadPublicSync(kNvTpmIndex, _, _, _, _))
      .WillOnce(
          DoAll(SetArgPointee<2>(kTpm2bNvPublic), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, NV_WriteLockSync(TPM_RH_OWNER, _, kNvTpmIndex, _, _))
      .WillOnce(Return(TPM_RC_SUCCESS));
  EXPECT_CALL(mock_tpm_, NV_ReadLockSync(TPM_RH_OWNER, _, kNvTpmIndex, _, _))
      .WillOnce(Return(TPM_RC_SUCCESS));

  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.LockNVSpace(kNvIndex, true, true, true,
                                 &mock_authorization_delegate_));
  TPMS_NV_PUBLIC public_area;
  EXPECT_EQ(TPM_RC_SUCCESS, GetNVRAMMap(kNvIndex, &public_area));
  EXPECT_EQ(kNvAttributes | TPMA_NV_READLOCKED | TPMA_NV_WRITELOCKED,
            public_area.attributes);
}

TEST_F(NVTpmUtilityTest, LockNVSpaceBothNotOwner) {
  EXPECT_CALL(mock_tpm_, NV_ReadPublicSync(kNvTpmIndex, _, _, _, _))
      .WillOnce(
          DoAll(SetArgPointee<2>(kTpm2bNvPublic), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, NV_WriteLockSync(kNvTpmIndex, _, kNvTpmIndex, _, _))
      .WillOnce(Return(TPM_RC_SUCCESS));
  EXPECT_CALL(mock_tpm_, NV_ReadLockSync(kNvTpmIndex, _, kNvTpmIndex, _, _))
      .WillOnce(Return(TPM_RC_SUCCESS));

  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.LockNVSpace(kNvIndex, true, true, false,
                                 &mock_authorization_delegate_));
}

TEST_F(NVTpmUtilityTest, LockNVSpaceBadIndex) {
  EXPECT_CALL(mock_tpm_, NV_WriteLockSync(_, _, _, _, _)).Times(0);
  EXPECT_CALL(mock_tpm_, NV_ReadLockSync(_, _, _, _, _)).Times(0);

  EXPECT_EQ(SAPI_RC_BAD_PARAMETER,
            utility_.LockNVSpace(kNvBadIndex, true, true, true,
                                 &mock_authorization_delegate_));
}

TEST_F(NVTpmUtilityTest, LockNVSpaceFailure) {
  EXPECT_CALL(mock_tpm_, NV_ReadPublicSync(kNvTpmIndex, _, _, _, _))
      .WillOnce(
          DoAll(SetArgPointee<2>(kTpm2bNvPublic), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, NV_WriteLockSync(TPM_RH_OWNER, _, kNvTpmIndex, _, _))
      .WillOnce(Return(TPM_RC_FAILURE));

  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.LockNVSpace(kNvIndex, true, true, true,
                                 &mock_authorization_delegate_));
}

TEST_F(NVTpmUtilityTest, WriteNVSpaceSuccess) {
  EXPECT_FALSE(kNvAttributes & TPMA_NV_WRITTEN);

  uint32_t offset = 5;
  EXPECT_CALL(mock_tpm_, NV_ReadPublicSync(kNvTpmIndex, _, _, _, _))
      .WillOnce(
          DoAll(SetArgPointee<2>(kTpm2bNvPublic), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_,
              NV_WriteSync(TPM_RH_OWNER, _, kNvTpmIndex, _, _, offset, _))
      .WillOnce(Return(TPM_RC_SUCCESS));

  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.WriteNVSpace(kNvIndex, offset, "", true, false,
                                  &mock_authorization_delegate_));
  TPMS_NV_PUBLIC public_area;
  EXPECT_EQ(TPM_RC_SUCCESS, GetNVRAMMap(kNvIndex, &public_area));
  EXPECT_EQ(kNvAttributes | TPMA_NV_WRITTEN, public_area.attributes);
}

TEST_F(NVTpmUtilityTest, WriteNVSpaceNotOwner) {
  uint32_t offset = 5;
  EXPECT_CALL(mock_tpm_, NV_ReadPublicSync(kNvTpmIndex, _, _, _, _))
      .WillOnce(
          DoAll(SetArgPointee<2>(kTpm2bNvPublic), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_,
              NV_WriteSync(kNvTpmIndex, _, kNvTpmIndex, _, _, offset, _))
      .WillOnce(Return(TPM_RC_SUCCESS));

  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.WriteNVSpace(kNvIndex, offset, "", false, false,
                                  &mock_authorization_delegate_));
}

TEST_F(NVTpmUtilityTest, ExtendNVSpace) {
  uint32_t offset = 5;
  EXPECT_CALL(mock_tpm_, NV_ReadPublicSync(kNvTpmIndex, _, _, _, _))
      .WillOnce(
          DoAll(SetArgPointee<2>(kTpm2bNvPublic), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, NV_ExtendSync(TPM_RH_OWNER, _, kNvTpmIndex, _, _, _))
      .WillOnce(Return(TPM_RC_SUCCESS));

  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.WriteNVSpace(kNvIndex, offset, "", true, true,
                                  &mock_authorization_delegate_));
}

TEST_F(NVTpmUtilityTest, WriteNVSpaceBadSize) {
  std::string nvram_data(MAX_NV_INDEX_SIZE + 1, 0);
  EXPECT_CALL(mock_tpm_, NV_ExtendSync(_, _, _, _, _, _)).Times(0);

  EXPECT_EQ(SAPI_RC_BAD_SIZE,
            utility_.WriteNVSpace(kNvIndex, 0, nvram_data, true, false,
                                  &mock_authorization_delegate_));
}

TEST_F(NVTpmUtilityTest, WriteNVSpaceBadIndex) {
  EXPECT_CALL(mock_tpm_, NV_WriteSync(_, _, _, _, _, _, _)).Times(0);

  EXPECT_EQ(SAPI_RC_BAD_PARAMETER,
            utility_.WriteNVSpace(kNvBadIndex, 0, "", true, false,
                                  &mock_authorization_delegate_));
}

TEST_F(NVTpmUtilityTest, WriteNVSpaceFailure) {
  uint32_t offset = 5;
  EXPECT_CALL(mock_tpm_, NV_ReadPublicSync(kNvTpmIndex, _, _, _, _))
      .WillOnce(
          DoAll(SetArgPointee<2>(kTpm2bNvPublic), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_,
              NV_WriteSync(TPM_RH_OWNER, _, kNvTpmIndex, _, _, offset, _))
      .WillOnce(Return(TPM_RC_FAILURE));

  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.WriteNVSpace(kNvIndex, offset, "", true, false,
                                  &mock_authorization_delegate_));
}

TEST_F(NVTpmUtilityTest, ReadNVSpaceSuccess) {
  uint32_t offset = 5;
  EXPECT_CALL(mock_tpm_, NV_ReadPublicSync(kNvTpmIndex, _, _, _, _))
      .WillOnce(
          DoAll(SetArgPointee<2>(kTpm2bNvPublic), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, NV_ReadSync(kNvTpmIndex, _, kNvTpmIndex, _,
                                     kNvDataSize, offset, _, _))
      .WillOnce(
          DoAll(SetArgPointee<6>(kTpm2bMaxNvBuffer), Return(TPM_RC_SUCCESS)));

  std::string nvram_data;
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.ReadNVSpace(kNvIndex, offset, kNvDataSize, false,
                                 &nvram_data, &mock_authorization_delegate_));
  EXPECT_EQ(nvram_data, kNvData);
}

TEST_F(NVTpmUtilityTest, ReadNVSpaceOwner) {
  uint32_t offset = 5;
  EXPECT_CALL(mock_tpm_, NV_ReadPublicSync(kNvTpmIndex, _, _, _, _))
      .WillOnce(
          DoAll(SetArgPointee<2>(kTpm2bNvPublic), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, NV_ReadSync(TPM_RH_OWNER, _, kNvTpmIndex, _,
                                     kNvDataSize, offset, _, _))
      .WillOnce(
          DoAll(SetArgPointee<6>(kTpm2bMaxNvBuffer), Return(TPM_RC_SUCCESS)));

  std::string nvram_data;
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.ReadNVSpace(kNvIndex, offset, kNvDataSize, true,
                                 &nvram_data, &mock_authorization_delegate_));
  EXPECT_EQ(nvram_data, kNvData);
}

TEST_F(NVTpmUtilityTest, ReadNVSpaceBadReadLength) {
  size_t length = MAX_NV_BUFFER_SIZE + 1;
  EXPECT_CALL(mock_tpm_, NV_ReadSync(_, _, _, _, _, _, _, _)).Times(0);

  std::string nvram_data;
  EXPECT_EQ(SAPI_RC_BAD_SIZE,
            utility_.ReadNVSpace(kNvIndex, 0, length, true, &nvram_data,
                                 &mock_authorization_delegate_));
}

TEST_F(NVTpmUtilityTest, ReadNVSpaceBadIndex) {
  EXPECT_CALL(mock_tpm_, NV_ReadSync(_, _, _, _, _, _, _, _)).Times(0);

  std::string nvram_data;
  EXPECT_EQ(SAPI_RC_BAD_PARAMETER,
            utility_.ReadNVSpace(kNvBadIndex, 0, 5, true, &nvram_data,
                                 &mock_authorization_delegate_));
}

TEST_F(NVTpmUtilityTest, ReadNVSpaceFailure) {
  uint32_t offset = 5;
  EXPECT_CALL(mock_tpm_, NV_ReadPublicSync(kNvTpmIndex, _, _, _, _))
      .WillOnce(
          DoAll(SetArgPointee<2>(kTpm2bNvPublic), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, NV_ReadSync(kNvTpmIndex, _, kNvTpmIndex, _,
                                     kNvDataSize, offset, _, _))
      .WillOnce(Return(TPM_RC_FAILURE));
  std::string nvram_data;
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.ReadNVSpace(kNvIndex, offset, kNvDataSize, false,
                                 &nvram_data, &mock_authorization_delegate_));
}

TEST_F(NVTpmUtilityTest, GetNVSpaceNameSuccess) {
  EXPECT_CALL(mock_tpm_, NV_ReadPublicSync(kNvTpmIndex, _, _, _, _))
      .WillOnce(
          DoAll(SetArgPointee<2>(kTpm2bNvPublic), Return(TPM_RC_SUCCESS)));

  std::string name;
  EXPECT_EQ(TPM_RC_SUCCESS, utility_.GetNVSpaceName(kNvIndex, &name));
  EXPECT_TRUE(name.length());
}

TEST_F(NVTpmUtilityTest, GetNVSpaceNameFailure) {
  EXPECT_CALL(mock_tpm_, NV_ReadPublicSync(_, _, _, _, _))
      .WillOnce(Return(TPM_RC_FAILURE));

  std::string name;
  EXPECT_EQ(TPM_RC_FAILURE, utility_.GetNVSpaceName(kNvIndex, &name));
}

TEST_F(NVTpmUtilityTest, GetNVSpaceNameFailureEmptyData) {
  EXPECT_CALL(mock_tpm_, NV_ReadPublicSync(_, _, _, _, _))
      .WillOnce(
          DoAll(SetArgPointee<2>(kEmptyTpm2bNvPublic), Return(TPM_RC_SUCCESS)));

  std::string name;
  EXPECT_EQ(TPM_RC_FAILURE, utility_.GetNVSpaceName(kNvIndex, &name));
}

TEST_F(NVTpmUtilityTest, GetNVSpacePublicAreaCachedSuccess) {
  SetNVRAMMap(kNvIndex, kTpm2bNvPublic.nv_public);
  EXPECT_CALL(mock_tpm_, NV_ReadPublicSync(_, _, _, _, _)).Times(0);

  TPMS_NV_PUBLIC public_area;
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.GetNVSpacePublicArea(kNvIndex, &public_area));
  EXPECT_EQ(kNvTpmIndex, public_area.nv_index);
  EXPECT_EQ(kNvNameAlg, public_area.name_alg);
  EXPECT_EQ(kNvAttributes, public_area.attributes);
  EXPECT_EQ(kNvDataSize, public_area.data_size);
}

TEST_F(NVTpmUtilityTest, GetNVSpacePublicAreaSuccess) {
  EXPECT_CALL(mock_tpm_, NV_ReadPublicSync(kNvTpmIndex, _, _, _, _))
      .WillOnce(
          DoAll(SetArgPointee<2>(kTpm2bNvPublic), Return(TPM_RC_SUCCESS)));

  TPMS_NV_PUBLIC public_area;
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.GetNVSpacePublicArea(kNvIndex, &public_area));
  EXPECT_EQ(kNvTpmIndex, public_area.nv_index);
  EXPECT_EQ(kNvNameAlg, public_area.name_alg);
  EXPECT_EQ(kNvAttributes, public_area.attributes);
  EXPECT_EQ(kNvDataSize, public_area.data_size);
}

TEST_F(NVTpmUtilityTest, GetNVSpacePublicAreaFailure) {
  EXPECT_CALL(mock_tpm_, NV_ReadPublicSync(_, _, _, _, _))
      .WillOnce(Return(TPM_RC_FAILURE));

  TPMS_NV_PUBLIC public_area;
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.GetNVSpacePublicArea(kNvIndex, &public_area));
}

TEST_F(NVTpmUtilityTest, GetNVSpacePublicAreaFailureEmptyData) {
  EXPECT_CALL(mock_tpm_, NV_ReadPublicSync(_, _, _, _, _))
      .WillOnce(
          DoAll(SetArgPointee<2>(kEmptyTpm2bNvPublic), Return(TPM_RC_SUCCESS)));

  TPMS_NV_PUBLIC public_area;
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.GetNVSpacePublicArea(kNvIndex, &public_area));
}

TEST_F(TpmUtilityTest, SetKnownPasswordSuccess) {
  EXPECT_CALL(mock_tpm_state_, IsOwnerPasswordSet()).WillOnce(Return(false));
  EXPECT_CALL(mock_tpm_, HierarchyChangeAuthSync(TPM_RH_OWNER, _, _, _))
      .WillOnce(Return(TPM_RC_SUCCESS));
  EXPECT_EQ(TPM_RC_SUCCESS, SetKnownOwnerPassword("password"));
}

TEST_F(TpmUtilityTest, SetKnownPasswordOwnershipDone) {
  EXPECT_EQ(TPM_RC_SUCCESS, SetKnownOwnerPassword("password"));
}

TEST_F(TpmUtilityTest, SetKnownPasswordFailure) {
  EXPECT_CALL(mock_tpm_state_, IsOwnerPasswordSet()).WillOnce(Return(false));
  EXPECT_CALL(mock_tpm_, HierarchyChangeAuthSync(TPM_RH_OWNER, _, _, _))
      .WillRepeatedly(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE, SetKnownOwnerPassword("password"));
}

TEST_F(TpmUtilityTest, RootKeysSuccess) {
  EXPECT_EQ(TPM_RC_SUCCESS, CreateStorageRootKeys("password"));
}

TEST_F(TpmUtilityTest, RootKeysHandleConsistency) {
  TPM_HANDLE test_handle = 42;
  EXPECT_CALL(mock_tpm_, CreatePrimarySyncShort(_, _, _, _, _, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<3>(test_handle), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, EvictControlSync(_, _, test_handle, _, _, _))
      .WillRepeatedly(Return(TPM_RC_SUCCESS));
  EXPECT_EQ(TPM_RC_SUCCESS, CreateStorageRootKeys("password"));
}

TEST_F(TpmUtilityTest, RootKeysCreateFailure) {
  EXPECT_CALL(mock_tpm_, CreatePrimarySyncShort(_, _, _, _, _, _, _, _, _, _))
      .WillRepeatedly(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE, CreateStorageRootKeys("password"));
}

TEST_F(TpmUtilityTest, RootKeysPersistFailure) {
  EXPECT_CALL(mock_tpm_, EvictControlSync(_, _, _, _, _, _))
      .WillRepeatedly(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE, CreateStorageRootKeys("password"));
}

TEST_F(TpmUtilityTest, RootKeysAlreadyExist) {
  SetExistingKeyHandleExpectation(kRSAStorageRootKey);
  SetExistingKeyHandleExpectation(kECCStorageRootKey);
  EXPECT_EQ(TPM_RC_SUCCESS, CreateStorageRootKeys("password"));
}

TEST_F(TpmUtilityTest, SaltingKeySuccess) {
  TPM2B_PUBLIC public_area;
  EXPECT_CALL(mock_tpm_, CreateSyncShort(_, _, _, _, _, _, _, _, _, _))
      .WillOnce(DoAll(SaveArg<2>(&public_area), Return(TPM_RC_SUCCESS)));
  EXPECT_EQ(TPM_RC_SUCCESS, CreateSaltingKey("password"));
  EXPECT_EQ(TPM_ALG_SHA256, public_area.public_area.name_alg);
}

TEST_F(TpmUtilityTest, SaltingKeyConsistency) {
  TPM_HANDLE test_handle = 42;
  EXPECT_CALL(mock_tpm_, LoadSync(_, _, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<4>(test_handle), Return(TPM_RC_SUCCESS)));
  EXPECT_CALL(mock_tpm_, EvictControlSync(_, _, test_handle, _, _, _))
      .WillRepeatedly(Return(TPM_RC_SUCCESS));
  EXPECT_EQ(TPM_RC_SUCCESS, CreateSaltingKey("password"));
}

TEST_F(TpmUtilityTest, SaltingKeyCreateFailure) {
  EXPECT_CALL(mock_tpm_, CreateSyncShort(_, _, _, _, _, _, _, _, _, _))
      .WillRepeatedly(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE, CreateSaltingKey("password"));
}

TEST_F(TpmUtilityTest, SaltingKeyLoadFailure) {
  EXPECT_CALL(mock_tpm_, LoadSync(_, _, _, _, _, _, _))
      .WillRepeatedly(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE, CreateSaltingKey("password"));
}

TEST_F(TpmUtilityTest, SaltingKeyPersistFailure) {
  EXPECT_CALL(mock_tpm_, EvictControlSync(_, _, _, _, _, _))
      .WillRepeatedly(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE, CreateSaltingKey("password"));
}

TEST_F(TpmUtilityTest, SaltingKeyAlreadyExists) {
  SetExistingKeyHandleExpectation(kSaltingKey);
  EXPECT_EQ(TPM_RC_SUCCESS, CreateSaltingKey("password"));
}

TEST_F(TpmUtilityTest, SetDictionaryAttackParametersSuccess) {
  EXPECT_CALL(mock_tpm_, DictionaryAttackParametersSync(TPM_RH_LOCKOUT, _, 1, 2,
                                                        3, nullptr))
      .WillRepeatedly(Return(TPM_RC_SUCCESS));
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.SetDictionaryAttackParameters(1, 2, 3, nullptr));
}

TEST_F(TpmUtilityTest, SetDictionaryAttackParametersFailure) {
  EXPECT_CALL(mock_tpm_, DictionaryAttackParametersSync(TPM_RH_LOCKOUT, _, 1, 2,
                                                        3, nullptr))
      .WillRepeatedly(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.SetDictionaryAttackParameters(1, 2, 3, nullptr));
}

TEST_F(TpmUtilityTest, ResetDictionaryAttackLockSuccess) {
  EXPECT_CALL(mock_tpm_,
              DictionaryAttackLockResetSync(TPM_RH_LOCKOUT, _, nullptr))
      .WillRepeatedly(Return(TPM_RC_SUCCESS));
  EXPECT_EQ(TPM_RC_SUCCESS, utility_.ResetDictionaryAttackLock(nullptr));
}

TEST_F(TpmUtilityTest, ResetDictionaryAttackLockFailure) {
  EXPECT_CALL(mock_tpm_,
              DictionaryAttackLockResetSync(TPM_RH_LOCKOUT, _, nullptr))
      .WillRepeatedly(Return(TPM_RC_FAILURE));
  EXPECT_EQ(TPM_RC_FAILURE, utility_.ResetDictionaryAttackLock(nullptr));
}

TEST_F(TpmUtilityTest, GetEndorsementKey) {
  EXPECT_CALL(mock_tpm_, CreatePrimarySyncShort(TPM_RH_ENDORSEMENT, _, _, _, _,
                                                _, _, _, _, _))
      .WillRepeatedly(Return(TPM_RC_SUCCESS));
  TPM_HANDLE key_handle;
  EXPECT_EQ(TPM_RC_SUCCESS, utility_.GetEndorsementKey(TPM_ALG_RSA, nullptr,
                                                       nullptr, &key_handle));
}

TEST_F(TpmUtilityTest, GetEndorsementKeyFail) {
  EXPECT_CALL(mock_tpm_, CreatePrimarySyncShort(TPM_RH_ENDORSEMENT, _, _, _, _,
                                                _, _, _, _, _))
      .WillRepeatedly(Return(TPM_RC_FAILURE));
  TPM_HANDLE key_handle;
  EXPECT_EQ(TPM_RC_FAILURE, utility_.GetEndorsementKey(TPM_ALG_RSA, nullptr,
                                                       nullptr, &key_handle));
}

TEST_F(TpmUtilityTest, CreateIdentityKey) {
  EXPECT_CALL(mock_tpm_, CreateSyncShort(_, _, _, _, _, _, _, _, _, _))
      .WillRepeatedly(Return(TPM_RC_SUCCESS));
  std::string key_blob;
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.CreateIdentityKey(TPM_ALG_RSA, nullptr, &key_blob));
}

TEST_F(TpmUtilityTest, CreateIdentityKeyFail) {
  EXPECT_CALL(mock_tpm_, CreateSyncShort(_, _, _, _, _, _, _, _, _, _))
      .WillRepeatedly(Return(TPM_RC_FAILURE));
  std::string key_blob;
  EXPECT_EQ(TPM_RC_FAILURE,
            utility_.CreateIdentityKey(TPM_ALG_RSA, nullptr, &key_blob));
}

TEST_F(TpmUtilityTest, DeclareTpmFirmwareStableNonCr50) {
  SetCr50(false);
  EXPECT_CALL(mock_transceiver_, SendCommandAndWait(_))
      .Times(0);
  EXPECT_EQ(TPM_RC_SUCCESS, utility_.DeclareTpmFirmwareStable());
}

TEST_F(TpmUtilityTest, DeclareTpmFirmwareStableCr50Success) {
  // A hand-coded kCr50SubcmdInvalidateInactiveRW command and response.
  std::string expected_command(
      "\x80\x01"          // tag=TPM_ST_NO_SESSIONS
      "\x00\x00\x00\x0C"  // size=12
      "\x20\x00\x00\x00"  // code=kCr50VendorCC
      "\x00\x14",         // subcommand=kCr50SubcmdInvalidateInactiveRW
      12);
  std::string command_response(
      "\x80\x01"           // tag=TPM_ST_NO_SESSIONS
      "\x00\x00\x00\x0C"   // size=12
      "\x00\x00\x00\x00"   // code=TPM_RC_SUCCESS
      "\x00\x14",          // subcommand=kCr50SubcmdInvalidateInactiveRW
      12);
  SetCr50(true);
  EXPECT_CALL(mock_transceiver_, SendCommandAndWait(expected_command))
      .WillOnce(Return(command_response));
  EXPECT_EQ(TPM_RC_SUCCESS, utility_.DeclareTpmFirmwareStable());
}

TEST_F(TpmUtilityTest, DeclareTpmFirmwareStableCr50Failure) {
  // A hand-coded kCr50SubcmdInvalidateInactiveRW command and response.
  std::string expected_command(
      "\x80\x01"          // tag=TPM_ST_NO_SESSIONS
      "\x00\x00\x00\x0C"  // size=12
      "\x20\x00\x00\x00"  // code=kCr50VendorCC
      "\x00\x14",         // subcommand=kCr50SubcmdInvalidateInactiveRW
      12);
  std::string command_response(
      "\x80\x01"           // tag=TPM_ST_NO_SESSIONS
      "\x00\x00\x00\x0C"   // size=10
      "\x00\x00\x01\x01"   // code=TPM_RC_FAILURE
      "\x00\x14",          // subcommand=kCr50SubcmdInvalidateInactiveRW
      12);
  SetCr50(true);
  EXPECT_CALL(mock_transceiver_, SendCommandAndWait(expected_command))
      .WillOnce(Return(command_response));
  EXPECT_EQ(TPM_RC_FAILURE, utility_.DeclareTpmFirmwareStable());
}

TEST_F(TpmUtilityTest, GetPublicRSAEndorsementKeyModulus_NoDataInNvram) {
  EXPECT_CALL(mock_tpm_, NV_ReadPublicSync(_, _, _, _, _))
      .WillOnce(Return(TPM_RC_FAILURE));

  std::string ekm;
  EXPECT_NE(TPM_RC_SUCCESS, utility_.GetPublicRSAEndorsementKeyModulus(&ekm));
}

TEST_F(TpmUtilityTest, GetPublicRSAEndorsementKeyModulus_EmptyNvram) {
  uint32_t nv_index = 29360128;
  TPM2B_MAX_NV_BUFFER nvram_data_buffer;
  nvram_data_buffer.size = 0;

  TPM2B_NV_PUBLIC public_area;
  public_area.size = sizeof(TPMS_NV_PUBLIC);
  // Note that, in particular, this implies that the size of the NVRAM data,
  // which is read from the |data_size| field of TPMS_NV_PUBLIC, is zero.
  memset(&public_area.nv_public, 0, sizeof(TPMS_NV_PUBLIC));

  EXPECT_CALL(mock_tpm_, NV_ReadPublicSync(nv_index, _, _, _, _))
      .WillOnce(DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));

  EXPECT_CALL(mock_tpm_, NV_ReadSync(_, _, _, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<6>(nvram_data_buffer), Return(TPM_RC_SUCCESS)));

  std::string ekm;
  EXPECT_EQ(SAPI_RC_CORRUPTED_DATA,
            utility_.GetPublicRSAEndorsementKeyModulus(&ekm));
}

TEST_F(TpmUtilityTest, GetPublicRSAEndorsementKeyModulus_InvalidDataInNvram) {
  uint32_t nv_index = 29360128;
  std::vector<unsigned char> cert = {1, 2, 3, 4};
  TPM2B_MAX_NV_BUFFER nvram_data_buffer;
  nvram_data_buffer.size = cert.size();
  memcpy(nvram_data_buffer.buffer, cert.data(), cert.size());

  TPM2B_NV_PUBLIC public_area;
  public_area.size = sizeof(TPMS_NV_PUBLIC);
  memset(&public_area.nv_public, 0, sizeof(TPMS_NV_PUBLIC));
  public_area.nv_public.data_size = 4;

  EXPECT_CALL(mock_tpm_, NV_ReadPublicSync(nv_index, _, _, _, _))
      .WillOnce(DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));

  EXPECT_CALL(mock_tpm_, NV_ReadSync(_, _, _, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<6>(nvram_data_buffer), Return(TPM_RC_SUCCESS)));

  std::string ekm;
  EXPECT_EQ(SAPI_RC_CORRUPTED_DATA,
            utility_.GetPublicRSAEndorsementKeyModulus(&ekm));
}

TEST_F(TpmUtilityTest,
       GetPublicRSAEndorsementKeyModulus_ValidCertificateInNvram) {
  std::string hex_encoded_cert =
      "308203EB308202D3A00302010202105A12528603AC1ABE3FE8EB925C951823300D06092A"
      "864886F70D01010B0500308180310B30090603550406130255533113301106035504080C"
      "0A43616C69666F726E696131143012060355040A0C0B476F6F676C6520496E632E312430"
      "22060355040B0C1B456E67696E656572696E6720616E6420446576656C6F706D656E7431"
      "20301E06035504030C1743524F532054504D2050524420454B20524F4F54204341301E17"
      "0D3137303232313030303030325A170D3237303232313030303030325A30003082012230"
      "0D06092A864886F70D01010105000382010F003082010A0282010100AC5869BD60F30463"
      "612BB0C472AA19E5400E524A213290EBFB728D1AAC956F74B7CF6A8D57F17C94D4BE2B3D"
      "07FD882CF708C30C476DCB1FF32695A8BAC77BDD5C04E89E2AB228D6EDFF2EFAA54BE9C3"
      "0F9D211E2E42DE7E50CF424EEE6C310D677D8870522E8C953711BE42C9B94579D56D4815"
      "60926606C60D74EFEEB013869C0424BB7D8585F79159BE7F476625B9BD2701D1C5ABA6D4"
      "07A4724C2165C176C45CD2188576ADC20303C3368D11603CFEEE4CFD81EB9C9EACF0029C"
      "4F41B2E4033AB68453884D5BB3E0DD9F680E150CB604428546CFA32B05743B073BAE9796"
      "4A847756BB79D132EAEFF44EE1B25315C6B45CE74087A777CFD142769B5CF4E502030100"
      "01A381DF3081DC300E0603551D0F0101FF04040302002030510603551D110101FF044730"
      "45A443304131163014060567810502010C0B69643A3437344634463437310F300D060567"
      "810502020C044831423231163014060567810502030C0B69643A3030313330303337300C"
      "0603551D130101FF0402300030130603551D20040C300A3008060667810C010202301F06"
      "03551D23041830168014153934FC5919CD2982F1F47FAD85D64469A1A17B30100603551D"
      "25040930070605678105080130210603551D09041A3018301606056781050210310D300B"
      "0C03322E30020100020110300D06092A864886F70D01010B05000382010100AE963A2EC0"
      "72B8DC7C673389B62112CFDEAD6A7C2A1D5142E74D628B9FCA1599C9705A23C2FCB3A529"
      "6B5CE3C2CB78A82B99D03D3B2E892C779EC46A2476CE70B68BE3FC87F1FC0B15A551F392"
      "33AAB7A0E0B425C709790C05298F101AC0CF95FE5C2502D4E5D78233041EBB66CFC0AA59"
      "983E20C915D7A35AE025FBE8ABBC898FD475288512C8BA2B70F4185E00A28A53D241188C"
      "C9216D6AA8FA0F15DE4BD8EF11A78F55B89C1C330A6C39EC6647954C816FB74BEFA02CAB"
      "C2B036B3E88DF7AE13F99449A2CADD70F322F64EFC437BA0A74BAE8354EAE44A5B0D5D66"
      "A3A6F14630157CD7BABDC6B0FD45EC71D208DD7BF1EA014540E46865E34947B87A2668";
  std::vector<uint8_t> cert;
  base::HexStringToBytes(hex_encoded_cert, &cert);

  ASSERT_TRUE(cert.size() <= MAX_NV_BUFFER_SIZE);

  uint32_t nv_index = 29360128;
  TPM2B_MAX_NV_BUFFER nvram_data_buffer;
  nvram_data_buffer.size = cert.size();
  memcpy(nvram_data_buffer.buffer, cert.data(), cert.size());

  TPM2B_NV_PUBLIC public_area;
  public_area.size = sizeof(TPMS_NV_PUBLIC);
  memset(&public_area.nv_public, 0, sizeof(TPMS_NV_PUBLIC));
  public_area.nv_public.data_size = cert.size();

  EXPECT_CALL(mock_tpm_, NV_ReadPublicSync(nv_index, _, _, _, _))
      .WillOnce(DoAll(SetArgPointee<2>(public_area), Return(TPM_RC_SUCCESS)));

  EXPECT_CALL(mock_tpm_, NV_ReadSync(_, _, _, _, _, _, _, _))
      .WillRepeatedly(
          DoAll(SetArgPointee<6>(nvram_data_buffer), Return(TPM_RC_SUCCESS)));

  std::string ekm;
  EXPECT_EQ(TPM_RC_SUCCESS,
            utility_.GetPublicRSAEndorsementKeyModulus(&ekm));
  std::string hex_encoded_ekm =
      "AC5869BD60F30463612BB0C472AA19E5400E524A213290EBFB728D1AAC956F74B7CF6A8D"
      "57F17C94D4BE2B3D07FD882CF708C30C476DCB1FF32695A8BAC77BDD5C04E89E2AB228D6"
      "EDFF2EFAA54BE9C30F9D211E2E42DE7E50CF424EEE6C310D677D8870522E8C953711BE42"
      "C9B94579D56D481560926606C60D74EFEEB013869C0424BB7D8585F79159BE7F476625B9"
      "BD2701D1C5ABA6D407A4724C2165C176C45CD2188576ADC20303C3368D11603CFEEE4CFD"
      "81EB9C9EACF0029C4F41B2E4033AB68453884D5BB3E0DD9F680E150CB604428546CFA32B"
      "05743B073BAE97964A847756BB79D132EAEFF44EE1B25315C6B45CE74087A777CFD14276"
      "9B5CF4E5";
  EXPECT_EQ(hex_encoded_ekm,
            base::HexEncode(ekm.data(), ekm.size()));
}

TEST_F(TpmUtilityTest, ManageCCDPwdNonCr50) {
  SetCr50(false);
  EXPECT_CALL(mock_transceiver_, SendCommandAndWait(_))
      .Times(0);
  EXPECT_EQ(TPM_RC_SUCCESS, utility_.ManageCCDPwd(true));
}

TEST_F(TpmUtilityTest, ManageCCDPwdCr50Success) {
  // A hand-coded kCr50SubcmdManageCCDPwd command (two variants: true and false)
  // and response.
  std::string expected_command_true(
      "\x80\x01"          // tag=TPM_ST_NO_SESSIONS
      "\x00\x00\x00\x0D"  // size=13
      "\x20\x00\x00\x00"  // code=kCr50VendorCC
      "\x00\x21"          // subcommand=kCr50SubcmdManageCCDPwd
      "\x01",             // value=true
      13);
  std::string expected_command_false(
      "\x80\x01"          // tag=TPM_ST_NO_SESSIONS
      "\x00\x00\x00\x0D"  // size=13
      "\x20\x00\x00\x00"  // code=kCr50VendorCC
      "\x00\x21"          // subcommand=kCr50SubcmdManageCCDPwd
      "\x00",             // value=false
      13);
  std::string command_response(
      "\x80\x01"           // tag=TPM_ST_NO_SESSIONS
      "\x00\x00\x00\x0C"   // size=12
      "\x00\x00\x00\x00"   // code=TPM_RC_SUCCESS
      "\x00\x21",          // subcommand=kCr50SubcmdManageCCDPwd
      12);
  SetCr50(true);
  EXPECT_CALL(mock_transceiver_, SendCommandAndWait(expected_command_true))
      .WillOnce(Return(command_response));
  EXPECT_EQ(TPM_RC_SUCCESS, utility_.ManageCCDPwd(true));
  testing::Mock::VerifyAndClearExpectations(&mock_transceiver_);
  EXPECT_CALL(mock_transceiver_, SendCommandAndWait(expected_command_false))
      .WillOnce(Return(command_response));
  EXPECT_EQ(TPM_RC_SUCCESS, utility_.ManageCCDPwd(false));
}

TEST_F(TpmUtilityTest, ManageCCDPwdFailure) {
  // A hand-coded kCr50SubcmdManageCCDPwd command and response.
  std::string expected_command(
      "\x80\x01"          // tag=TPM_ST_NO_SESSIONS
      "\x00\x00\x00\x0D"  // size=13
      "\x20\x00\x00\x00"  // code=kCr50VendorCC
      "\x00\x21"          // subcommand=kCr50SubcmdManageCCDPwd
      "\x01",             // value=true
      13);
  std::string command_response(
      "\x80\x01"           // tag=TPM_ST_NO_SESSIONS
      "\x00\x00\x00\x0C"   // size=12
      "\x00\x00\x01\x01"   // code=TPM_RC_FAILURE
      "\x00\x21",          // subcommand=kCr50SubcmdManageCCDPwd
      12);
  SetCr50(true);
  EXPECT_CALL(mock_transceiver_, SendCommandAndWait(expected_command))
      .WillOnce(Return(command_response));
  EXPECT_EQ(TPM_RC_FAILURE, utility_.ManageCCDPwd(true));
}

}  // namespace trunks
