/* * Copyright (C) 2017 The Android Open Source Project * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include <stdio.h> #include <string.h> #include <base/files/file_util.h> #include <gtest/gtest.h> #include <openssl/sha.h> #include "avb_unittest_util.h" #include "examples/things/avb_atx_slot_verify.h" #include "fake_avb_ops.h" namespace { const char kMetadataPath[] = "test/data/atx_metadata.bin"; const char kPermanentAttributesPath[] = "test/data/atx_permanent_attributes.bin"; const uint64_t kNewRollbackValue = 42; } /* namespace */ namespace avb { // A fixture for testing avb_atx_slot_verify() with ATX. This test is // parameterized on the initial stored rollback index (same value used in all // relevant locations). class AvbAtxSlotVerifyExampleTest : public BaseAvbToolTest, public FakeAvbOpsDelegateWithDefaults, public ::testing::WithParamInterface<uint64_t> { public: ~AvbAtxSlotVerifyExampleTest() override = default; void SetUp() override { BaseAvbToolTest::SetUp(); ReadAtxDefaultData(); ops_.set_partition_dir(testdir_); ops_.set_delegate(this); ops_.set_permanent_attributes(attributes_); ops_.set_stored_is_device_unlocked(false); } // FakeAvbOpsDelegate overrides. AvbIOResult validate_vbmeta_public_key(AvbOps* ops, const uint8_t* public_key_data, size_t public_key_length, const uint8_t* public_key_metadata, size_t public_key_metadata_length, bool* out_key_is_trusted) override { // Send to ATX implementation. ++num_atx_calls_; return avb_atx_validate_vbmeta_public_key(ops, public_key_data, public_key_length, public_key_metadata, public_key_metadata_length, out_key_is_trusted); } AvbIOResult write_rollback_index(AvbOps* ops, size_t rollback_index_slot, uint64_t rollback_index) override { num_write_rollback_calls_++; return ops_.write_rollback_index(ops, rollback_index_slot, rollback_index); } void set_key_version(size_t rollback_index_location, uint64_t key_version) override { num_key_version_calls_++; return ops_.set_key_version(rollback_index_location, key_version); } AvbIOResult get_random(size_t num_bytes, uint8_t* output) override { return ops_.get_random(num_bytes, output); } void RunSlotVerify() { ops_.set_stored_rollback_indexes( {{0, initial_rollback_value_}, {AVB_ATX_PIK_VERSION_LOCATION, initial_rollback_value_}, {AVB_ATX_PSK_VERSION_LOCATION, initial_rollback_value_}}); std::string metadata_option = "--public_key_metadata="; metadata_option += kMetadataPath; GenerateVBMetaImage("vbmeta_a.img", "SHA512_RSA4096", kNewRollbackValue, base::FilePath("test/data/testkey_atx_psk.pem"), metadata_option); SHA256(vbmeta_image_.data(), vbmeta_image_.size(), expected_vbh_extension_); ops_.set_expected_public_key( PublicKeyAVB(base::FilePath("test/data/testkey_atx_psk.pem"))); AvbSlotVerifyData* slot_data = NULL; EXPECT_EQ(expected_result_, avb_atx_slot_verify(ops_.avb_atx_ops(), "_a", lock_state_, slot_state_, oem_data_state_, &slot_data, actual_vbh_extension_)); if (expected_result_ == AVB_SLOT_VERIFY_RESULT_OK) { EXPECT_NE(nullptr, slot_data); avb_slot_verify_data_free(slot_data); // Make sure ATX is being run. EXPECT_EQ(1, num_atx_calls_); // Make sure we're hooking set_key_version. EXPECT_EQ(0, num_key_version_calls_); } } void CheckVBH() { if (expected_result_ != AVB_SLOT_VERIFY_RESULT_OK || lock_state_ == AVB_ATX_UNLOCKED) { memset(&expected_vbh_extension_, 0, AVB_SHA256_DIGEST_SIZE); } // Check that the VBH was correctly calculated. EXPECT_EQ(0, memcmp(actual_vbh_extension_, expected_vbh_extension_, AVB_SHA256_DIGEST_SIZE)); } void CheckNewRollbackState() { uint64_t expected_rollback_value = kNewRollbackValue; if (expected_result_ != AVB_SLOT_VERIFY_RESULT_OK || lock_state_ == AVB_ATX_UNLOCKED || slot_state_ != AVB_ATX_SLOT_MARKED_SUCCESSFUL) { // Check that rollback indexes were unmodified. expected_rollback_value = initial_rollback_value_; } // Check that all rollback indexes have the expected value. std::map<size_t, uint64_t> stored_rollback_indexes = ops_.get_stored_rollback_indexes(); EXPECT_EQ(expected_rollback_value, stored_rollback_indexes[0]); EXPECT_EQ(expected_rollback_value, stored_rollback_indexes[AVB_ATX_PIK_VERSION_LOCATION]); EXPECT_EQ(expected_rollback_value, stored_rollback_indexes[AVB_ATX_PSK_VERSION_LOCATION]); // Check that if the rollback did not need to change, there were no writes. if (initial_rollback_value_ == kNewRollbackValue || initial_rollback_value_ == expected_rollback_value) { EXPECT_EQ(0, num_write_rollback_calls_); } else { EXPECT_NE(0, num_write_rollback_calls_); } } protected: AvbAtxPermanentAttributes attributes_; int num_atx_calls_ = 0; int num_key_version_calls_ = 0; int num_write_rollback_calls_ = 0; AvbSlotVerifyResult expected_result_ = AVB_SLOT_VERIFY_RESULT_OK; uint64_t initial_rollback_value_ = 0; AvbAtxLockState lock_state_ = AVB_ATX_LOCKED; AvbAtxSlotState slot_state_ = AVB_ATX_SLOT_MARKED_SUCCESSFUL; AvbAtxOemDataState oem_data_state_ = AVB_ATX_OEM_DATA_NOT_USED; uint8_t expected_vbh_extension_[AVB_SHA256_DIGEST_SIZE] = {}; uint8_t actual_vbh_extension_[AVB_SHA256_DIGEST_SIZE] = {}; private: void ReadAtxDefaultData() { std::string tmp; ASSERT_TRUE( base::ReadFileToString(base::FilePath(kPermanentAttributesPath), &tmp)); ASSERT_EQ(tmp.size(), sizeof(AvbAtxPermanentAttributes)); memcpy(&attributes_, tmp.data(), tmp.size()); } }; TEST_P(AvbAtxSlotVerifyExampleTest, RunWithStartingIndex) { initial_rollback_value_ = GetParam(); RunSlotVerify(); CheckVBH(); CheckNewRollbackState(); } INSTANTIATE_TEST_CASE_P(P, AvbAtxSlotVerifyExampleTest, ::testing::Values(0, 1, kNewRollbackValue / 2, kNewRollbackValue - 1, kNewRollbackValue)); TEST_F(AvbAtxSlotVerifyExampleTest, RunUnlocked) { lock_state_ = AVB_ATX_UNLOCKED; RunSlotVerify(); CheckVBH(); CheckNewRollbackState(); } TEST_F(AvbAtxSlotVerifyExampleTest, RunWithSlotNotMarkedSuccessful) { slot_state_ = AVB_ATX_SLOT_NOT_MARKED_SUCCESSFUL; RunSlotVerify(); CheckVBH(); CheckNewRollbackState(); } TEST_F(AvbAtxSlotVerifyExampleTest, RunWithOemData) { oem_data_state_ = AVB_ATX_OEM_DATA_USED; RunSlotVerify(); CheckVBH(); CheckNewRollbackState(); } } // namespace avb