| /* |
| * Copyright (C) 2016 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/objects.h> |
| #include <openssl/pem.h> |
| #include <openssl/rsa.h> |
| #include <openssl/sha.h> |
| |
| #include <libavb_atx/libavb_atx.h> |
| |
| #include "avb_unittest_util.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 char kPRKPrivateKeyPath[] = "test/data/testkey_atx_prk.pem"; |
| const char kPIKPrivateKeyPath[] = "test/data/testkey_atx_pik.pem"; |
| const char kPSKPrivateKeyPath[] = "test/data/testkey_atx_psk.pem"; |
| const char kPUKPrivateKeyPath[] = "test/data/testkey_atx_puk.pem"; |
| const char kUnlockChallengePath[] = "test/data/atx_unlock_challenge.bin"; |
| const char kUnlockCredentialPath[] = "test/data/atx_unlock_credential.bin"; |
| |
| class ScopedRSA { |
| public: |
| ScopedRSA(const char* pem_key_path) { |
| FILE* file = fopen(pem_key_path, "r"); |
| rsa_ = PEM_read_RSAPrivateKey(file, nullptr, nullptr, nullptr); |
| fclose(file); |
| } |
| |
| ~ScopedRSA() { |
| if (rsa_) { |
| RSA_free(rsa_); |
| } |
| } |
| |
| // PKCS #1 v1.5 signature using SHA512. Returns true on success. |
| bool Sign(const void* data_to_sign, size_t length, uint8_t signature[]) { |
| uint8_t digest[AVB_SHA512_DIGEST_SIZE]; |
| const unsigned char* data_to_sign_buf = |
| reinterpret_cast<const unsigned char*>(data_to_sign); |
| SHA512(data_to_sign_buf, length, digest); |
| unsigned int signature_length = 0; |
| return (1 == RSA_sign(NID_sha512, |
| digest, |
| AVB_SHA512_DIGEST_SIZE, |
| signature, |
| &signature_length, |
| rsa_)); |
| } |
| |
| private: |
| RSA* rsa_; |
| }; |
| |
| } /* namespace */ |
| |
| namespace avb { |
| |
| class AvbAtxValidateTest : public ::testing::Test, |
| public FakeAvbOpsDelegateWithDefaults { |
| public: |
| ~AvbAtxValidateTest() override {} |
| |
| void SetUp() override { |
| ReadDefaultData(); |
| ops_.set_delegate(this); |
| ops_.set_permanent_attributes(attributes_); |
| ops_.set_stored_rollback_indexes( |
| {{AVB_ATX_PIK_VERSION_LOCATION, 0}, {AVB_ATX_PSK_VERSION_LOCATION, 0}}); |
| } |
| |
| // FakeAvbOpsDelegate methods. |
| AvbIOResult read_from_partition(const char* partition, |
| int64_t offset, |
| size_t num_bytes, |
| void* buffer, |
| size_t* out_num_read) override { |
| // Expect method not used. |
| return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; |
| } |
| |
| AvbIOResult get_preloaded_partition( |
| const char* partition, |
| size_t num_bytes, |
| uint8_t** out_pointer, |
| size_t* out_num_bytes_preloaded) override { |
| // Expect method not used. |
| return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; |
| } |
| |
| AvbIOResult write_to_partition(const char* partition, |
| int64_t offset, |
| size_t num_bytes, |
| const void* buffer) override { |
| // Expect method not used. |
| return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; |
| } |
| |
| 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 { |
| // Expect method not used. |
| return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; |
| } |
| |
| AvbIOResult read_rollback_index(AvbOps* ops, |
| size_t rollback_index_slot, |
| uint64_t* out_rollback_index) override { |
| if ((fail_read_pik_rollback_index_ && |
| rollback_index_slot == AVB_ATX_PIK_VERSION_LOCATION) || |
| (fail_read_psk_rollback_index_ && |
| rollback_index_slot == AVB_ATX_PSK_VERSION_LOCATION)) { |
| return AVB_IO_RESULT_ERROR_IO; |
| } |
| return ops_.read_rollback_index( |
| ops, rollback_index_slot, out_rollback_index); |
| } |
| |
| AvbIOResult write_rollback_index(AvbOps* ops, |
| size_t rollback_index_slot, |
| uint64_t rollback_index) override { |
| // Expect method not used. |
| return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; |
| } |
| |
| AvbIOResult read_is_device_unlocked(AvbOps* ops, |
| bool* out_is_device_unlocked) override { |
| // Expect method not used. |
| return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; |
| } |
| |
| AvbIOResult get_unique_guid_for_partition(AvbOps* ops, |
| const char* partition, |
| char* guid_buf, |
| size_t guid_buf_size) override { |
| // Expect method not used. |
| return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; |
| } |
| |
| AvbIOResult get_size_of_partition(AvbOps* ops, |
| const char* partition, |
| uint64_t* out_size) override { |
| // Expect method not used. |
| return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; |
| } |
| |
| AvbIOResult read_persistent_value(const char* name, |
| size_t buffer_size, |
| uint8_t* out_buffer, |
| size_t* out_num_bytes_read) override { |
| // Expect method not used. |
| return AVB_IO_RESULT_ERROR_NO_SUCH_VALUE; |
| } |
| |
| AvbIOResult write_persistent_value(const char* name, |
| size_t value_size, |
| const uint8_t* value) override { |
| // Expect method not used. |
| return AVB_IO_RESULT_ERROR_NO_SUCH_VALUE; |
| } |
| |
| AvbIOResult read_permanent_attributes( |
| AvbAtxPermanentAttributes* attributes) override { |
| if (fail_read_permanent_attributes_) { |
| return AVB_IO_RESULT_ERROR_IO; |
| } |
| return ops_.read_permanent_attributes(attributes); |
| } |
| |
| AvbIOResult read_permanent_attributes_hash( |
| uint8_t hash[AVB_SHA256_DIGEST_SIZE]) override { |
| if (fail_read_permanent_attributes_hash_) { |
| return AVB_IO_RESULT_ERROR_IO; |
| } |
| return ops_.read_permanent_attributes_hash(hash); |
| } |
| |
| void set_key_version(size_t rollback_index_location, |
| uint64_t key_version) override { |
| ops_.set_key_version(rollback_index_location, key_version); |
| } |
| |
| AvbIOResult get_random(size_t num_bytes, uint8_t* output) override { |
| if (fail_get_random_) { |
| return AVB_IO_RESULT_ERROR_IO; |
| } |
| if (fake_random_.size() >= num_bytes) { |
| memcpy(output, fake_random_.data(), num_bytes); |
| return AVB_IO_RESULT_OK; |
| } |
| return ops_.get_random(num_bytes, output); |
| } |
| |
| protected: |
| virtual AvbIOResult Validate(bool* is_trusted) { |
| return avb_atx_validate_vbmeta_public_key( |
| ops_.avb_ops(), |
| metadata_.product_signing_key_certificate.signed_data.public_key, |
| AVB_ATX_PUBLIC_KEY_SIZE, |
| reinterpret_cast<const uint8_t*>(&metadata_), |
| sizeof(metadata_), |
| is_trusted); |
| } |
| |
| AvbIOResult ValidateUnlock(bool* is_trusted) { |
| return avb_atx_validate_unlock_credential( |
| ops_.avb_atx_ops(), &unlock_credential_, is_trusted); |
| } |
| |
| void SignPIKCertificate() { |
| memset(metadata_.product_intermediate_key_certificate.signature, |
| 0, |
| AVB_RSA4096_NUM_BYTES); |
| ScopedRSA key(kPRKPrivateKeyPath); |
| ASSERT_TRUE( |
| key.Sign(&metadata_.product_intermediate_key_certificate.signed_data, |
| sizeof(AvbAtxCertificateSignedData), |
| metadata_.product_intermediate_key_certificate.signature)); |
| } |
| |
| void SignPSKCertificate() { |
| memset(metadata_.product_signing_key_certificate.signature, |
| 0, |
| AVB_RSA4096_NUM_BYTES); |
| ScopedRSA key(kPIKPrivateKeyPath); |
| ASSERT_TRUE(key.Sign(&metadata_.product_signing_key_certificate.signed_data, |
| sizeof(AvbAtxCertificateSignedData), |
| metadata_.product_signing_key_certificate.signature)); |
| } |
| |
| void SignUnlockCredentialPIKCertificate() { |
| memset(unlock_credential_.product_intermediate_key_certificate.signature, |
| 0, |
| AVB_RSA4096_NUM_BYTES); |
| ScopedRSA key(kPRKPrivateKeyPath); |
| ASSERT_TRUE(key.Sign( |
| &unlock_credential_.product_intermediate_key_certificate.signed_data, |
| sizeof(AvbAtxCertificateSignedData), |
| unlock_credential_.product_intermediate_key_certificate.signature)); |
| } |
| |
| void SignUnlockCredentialPUKCertificate() { |
| memset(unlock_credential_.product_unlock_key_certificate.signature, |
| 0, |
| AVB_RSA4096_NUM_BYTES); |
| ScopedRSA key(kPIKPrivateKeyPath); |
| ASSERT_TRUE( |
| key.Sign(&unlock_credential_.product_unlock_key_certificate.signed_data, |
| sizeof(AvbAtxCertificateSignedData), |
| unlock_credential_.product_unlock_key_certificate.signature)); |
| } |
| |
| void SignUnlockCredentialChallenge(const char* key_path) { |
| memset(unlock_credential_.challenge_signature, 0, AVB_RSA4096_NUM_BYTES); |
| ScopedRSA key(key_path); |
| ASSERT_TRUE(key.Sign(unlock_challenge_.data(), |
| unlock_challenge_.size(), |
| unlock_credential_.challenge_signature)); |
| } |
| |
| bool PrepareUnlockCredential() { |
| // Stage a challenge to be remembered as the 'most recent challenge'. Then |
| // the next call to unlock with |unlock_credential_| is expected to succeed. |
| fake_random_ = unlock_challenge_; |
| AvbAtxUnlockChallenge challenge; |
| return (AVB_IO_RESULT_OK == |
| avb_atx_generate_unlock_challenge(ops_.avb_atx_ops(), &challenge)); |
| } |
| |
| AvbAtxPermanentAttributes attributes_; |
| AvbAtxPublicKeyMetadata metadata_; |
| bool fail_read_permanent_attributes_{false}; |
| bool fail_read_permanent_attributes_hash_{false}; |
| bool fail_read_pik_rollback_index_{false}; |
| bool fail_read_psk_rollback_index_{false}; |
| bool fail_get_random_{false}; |
| std::string fake_random_; |
| AvbAtxUnlockCredential unlock_credential_; |
| std::string unlock_challenge_; |
| |
| private: |
| void ReadDefaultData() { |
| std::string tmp; |
| ASSERT_TRUE(base::ReadFileToString(base::FilePath(kMetadataPath), &tmp)); |
| ASSERT_EQ(tmp.size(), sizeof(AvbAtxPublicKeyMetadata)); |
| memcpy(&metadata_, tmp.data(), tmp.size()); |
| ASSERT_TRUE( |
| base::ReadFileToString(base::FilePath(kPermanentAttributesPath), &tmp)); |
| ASSERT_EQ(tmp.size(), sizeof(AvbAtxPermanentAttributes)); |
| memcpy(&attributes_, tmp.data(), tmp.size()); |
| ASSERT_TRUE(base::ReadFileToString(base::FilePath(kUnlockChallengePath), |
| &unlock_challenge_)); |
| ASSERT_EQ(size_t(AVB_ATX_UNLOCK_CHALLENGE_SIZE), unlock_challenge_.size()); |
| ASSERT_TRUE( |
| base::ReadFileToString(base::FilePath(kUnlockCredentialPath), &tmp)); |
| ASSERT_EQ(tmp.size(), sizeof(AvbAtxUnlockCredential)); |
| memcpy(&unlock_credential_, tmp.data(), tmp.size()); |
| } |
| }; |
| |
| TEST_F(AvbAtxValidateTest, Success) { |
| bool is_trusted = false; |
| EXPECT_EQ(AVB_IO_RESULT_OK, Validate(&is_trusted)); |
| EXPECT_TRUE(is_trusted); |
| |
| // Check that the key versions were reported correctly. |
| EXPECT_EQ( |
| ops_.get_verified_rollback_indexes()[AVB_ATX_PIK_VERSION_LOCATION], |
| metadata_.product_intermediate_key_certificate.signed_data.key_version); |
| EXPECT_EQ(ops_.get_verified_rollback_indexes()[AVB_ATX_PSK_VERSION_LOCATION], |
| metadata_.product_signing_key_certificate.signed_data.key_version); |
| EXPECT_EQ(2UL, ops_.get_verified_rollback_indexes().size()); |
| } |
| |
| TEST_F(AvbAtxValidateTest, SuccessAfterNewSign) { |
| std::string old_pik_sig( |
| reinterpret_cast<char*>( |
| metadata_.product_intermediate_key_certificate.signature), |
| AVB_RSA4096_NUM_BYTES); |
| std::string old_psk_sig( |
| reinterpret_cast<char*>( |
| metadata_.product_signing_key_certificate.signature), |
| AVB_RSA4096_NUM_BYTES); |
| SignPIKCertificate(); |
| SignPSKCertificate(); |
| std::string new_pik_sig( |
| reinterpret_cast<char*>( |
| metadata_.product_intermediate_key_certificate.signature), |
| AVB_RSA4096_NUM_BYTES); |
| std::string new_psk_sig( |
| reinterpret_cast<char*>( |
| metadata_.product_signing_key_certificate.signature), |
| AVB_RSA4096_NUM_BYTES); |
| EXPECT_EQ(old_pik_sig, new_pik_sig); |
| EXPECT_EQ(old_psk_sig, new_psk_sig); |
| bool is_trusted = false; |
| EXPECT_EQ(AVB_IO_RESULT_OK, Validate(&is_trusted)); |
| EXPECT_TRUE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, FailReadPermamentAttributes) { |
| fail_read_permanent_attributes_ = true; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_ERROR_IO, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, FailReadPermamentAttributesHash) { |
| fail_read_permanent_attributes_hash_ = true; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_ERROR_IO, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, UnsupportedPermanentAttributesVersion) { |
| attributes_.version = 25; |
| ops_.set_permanent_attributes(attributes_); |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, PermanentAttributesHashMismatch) { |
| ops_.set_permanent_attributes_hash("bad_hash"); |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| // A fixture with parameterized metadata length. |
| class AvbAtxValidateTestWithMetadataLength |
| : public AvbAtxValidateTest, |
| public ::testing::WithParamInterface<size_t> { |
| protected: |
| AvbIOResult Validate(bool* is_trusted) override { |
| return avb_atx_validate_vbmeta_public_key( |
| ops_.avb_ops(), |
| metadata_.product_signing_key_certificate.signed_data.public_key, |
| AVB_ATX_PUBLIC_KEY_SIZE, |
| reinterpret_cast<const uint8_t*>(&metadata_), |
| GetParam(), |
| is_trusted); |
| } |
| }; |
| |
| TEST_P(AvbAtxValidateTestWithMetadataLength, InvalidMetadataLength) { |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| // Test a bunch of invalid metadata length values. |
| INSTANTIATE_TEST_CASE_P(P, |
| AvbAtxValidateTestWithMetadataLength, |
| ::testing::Values(0, |
| 1, |
| sizeof(AvbAtxPublicKeyMetadata) - 1, |
| sizeof(AvbAtxPublicKeyMetadata) + 1, |
| -1)); |
| |
| TEST_F(AvbAtxValidateTest, UnsupportedMetadataVersion) { |
| metadata_.version = 25; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, FailReadPIKRollbackIndex) { |
| fail_read_pik_rollback_index_ = true; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_ERROR_IO, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, UnsupportedPIKCertificateVersion) { |
| metadata_.product_intermediate_key_certificate.signed_data.version = 25; |
| SignPIKCertificate(); |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, BadPIKCert_ModifiedSubjectPublicKey) { |
| metadata_.product_intermediate_key_certificate.signed_data.public_key[0] ^= 1; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, BadPIKCert_ModifiedSubject) { |
| metadata_.product_intermediate_key_certificate.signed_data.subject[0] ^= 1; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, BadPIKCert_ModifiedUsage) { |
| metadata_.product_intermediate_key_certificate.signed_data.usage[0] ^= 1; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, BadPIKCert_ModifiedKeyVersion) { |
| metadata_.product_intermediate_key_certificate.signed_data.key_version ^= 1; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, BadPIKCert_BadSignature) { |
| metadata_.product_intermediate_key_certificate.signature[0] ^= 1; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, PIKCertSubjectIgnored) { |
| metadata_.product_intermediate_key_certificate.signed_data.subject[0] ^= 1; |
| SignPIKCertificate(); |
| bool is_trusted = false; |
| EXPECT_EQ(AVB_IO_RESULT_OK, Validate(&is_trusted)); |
| EXPECT_TRUE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, PIKCertUnexpectedUsage) { |
| metadata_.product_intermediate_key_certificate.signed_data.usage[0] ^= 1; |
| SignPIKCertificate(); |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, PIKRollback) { |
| ops_.set_stored_rollback_indexes( |
| {{AVB_ATX_PIK_VERSION_LOCATION, |
| metadata_.product_intermediate_key_certificate.signed_data.key_version + |
| 1}, |
| {AVB_ATX_PSK_VERSION_LOCATION, 0}}); |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, FailReadPSKRollbackIndex) { |
| fail_read_psk_rollback_index_ = true; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_ERROR_IO, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, UnsupportedPSKCertificateVersion) { |
| metadata_.product_signing_key_certificate.signed_data.version = 25; |
| SignPSKCertificate(); |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, BadPSKCert_ModifiedSubjectPublicKey) { |
| metadata_.product_signing_key_certificate.signed_data.public_key[0] ^= 1; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, BadPSKCert_ModifiedSubject) { |
| metadata_.product_signing_key_certificate.signed_data.subject[0] ^= 1; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, BadPSKCert_ModifiedUsage) { |
| metadata_.product_signing_key_certificate.signed_data.usage[0] ^= 1; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, BadPSKCert_ModifiedKeyVersion) { |
| metadata_.product_signing_key_certificate.signed_data.key_version ^= 1; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, BadPSKCert_BadSignature) { |
| metadata_.product_signing_key_certificate.signature[0] ^= 1; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, PSKCertUnexpectedSubject) { |
| metadata_.product_signing_key_certificate.signed_data.subject[0] ^= 1; |
| SignPSKCertificate(); |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, PSKCertUnexpectedUsage) { |
| metadata_.product_signing_key_certificate.signed_data.usage[0] ^= 1; |
| SignPSKCertificate(); |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, PSKRollback) { |
| ops_.set_stored_rollback_indexes( |
| {{AVB_ATX_PIK_VERSION_LOCATION, 0}, |
| {AVB_ATX_PSK_VERSION_LOCATION, |
| metadata_.product_signing_key_certificate.signed_data.key_version + |
| 1}}); |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| // A fixture with parameterized public key length. |
| class AvbAtxValidateTestWithPublicKeyLength |
| : public AvbAtxValidateTest, |
| public ::testing::WithParamInterface<size_t> { |
| protected: |
| AvbIOResult Validate(bool* is_trusted) override { |
| return avb_atx_validate_vbmeta_public_key( |
| ops_.avb_ops(), |
| metadata_.product_signing_key_certificate.signed_data.public_key, |
| GetParam(), |
| reinterpret_cast<const uint8_t*>(&metadata_), |
| sizeof(metadata_), |
| is_trusted); |
| } |
| }; |
| |
| TEST_P(AvbAtxValidateTestWithPublicKeyLength, InvalidPublicKeyLength) { |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, Validate(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| // Test a bunch of invalid public key length values. |
| INSTANTIATE_TEST_CASE_P(P, |
| AvbAtxValidateTestWithPublicKeyLength, |
| ::testing::Values(0, |
| 1, |
| AVB_ATX_PUBLIC_KEY_SIZE - 1, |
| AVB_ATX_PUBLIC_KEY_SIZE + 1, |
| AVB_ATX_PUBLIC_KEY_SIZE - 512, |
| -1)); |
| |
| TEST_F(AvbAtxValidateTest, PSKMismatch) { |
| uint8_t bad_key[AVB_ATX_PUBLIC_KEY_SIZE] = {}; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, |
| avb_atx_validate_vbmeta_public_key( |
| ops_.avb_ops(), |
| bad_key, |
| AVB_ATX_PUBLIC_KEY_SIZE, |
| reinterpret_cast<const uint8_t*>(&metadata_), |
| sizeof(metadata_), |
| &is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, GenerateUnlockChallenge) { |
| fake_random_ = std::string(AVB_ATX_UNLOCK_CHALLENGE_SIZE, 'C'); |
| AvbAtxUnlockChallenge challenge; |
| EXPECT_EQ(AVB_IO_RESULT_OK, |
| avb_atx_generate_unlock_challenge(ops_.avb_atx_ops(), &challenge)); |
| EXPECT_EQ(1UL, challenge.version); |
| EXPECT_EQ(0, |
| memcmp(fake_random_.data(), |
| challenge.challenge, |
| AVB_ATX_UNLOCK_CHALLENGE_SIZE)); |
| uint8_t expected_pid_hash[AVB_SHA256_DIGEST_SIZE]; |
| SHA256(attributes_.product_id, AVB_ATX_PRODUCT_ID_SIZE, expected_pid_hash); |
| EXPECT_EQ(0, |
| memcmp(expected_pid_hash, |
| challenge.product_id_hash, |
| AVB_SHA256_DIGEST_SIZE)); |
| } |
| |
| TEST_F(AvbAtxValidateTest, GenerateUnlockChallenge_NoAttributes) { |
| fail_read_permanent_attributes_ = true; |
| AvbAtxUnlockChallenge challenge; |
| EXPECT_NE(AVB_IO_RESULT_OK, |
| avb_atx_generate_unlock_challenge(ops_.avb_atx_ops(), &challenge)); |
| } |
| |
| TEST_F(AvbAtxValidateTest, GenerateUnlockChallenge_NoRNG) { |
| fail_get_random_ = true; |
| AvbAtxUnlockChallenge challenge; |
| EXPECT_NE(AVB_IO_RESULT_OK, |
| avb_atx_generate_unlock_challenge(ops_.avb_atx_ops(), &challenge)); |
| } |
| |
| TEST_F(AvbAtxValidateTest, ValidateUnlockCredential) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_TRUE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, ValidateUnlockCredential_UnsupportedVersion) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| unlock_credential_.version++; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, ValidateUnlockCredential_NoAttributes) { |
| PrepareUnlockCredential(); |
| fail_read_permanent_attributes_ = true; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_ERROR_IO, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, ValidateUnlockCredential_NoAttributesHash) { |
| PrepareUnlockCredential(); |
| fail_read_permanent_attributes_hash_ = true; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_ERROR_IO, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, |
| ValidateUnlockCredential_UnsupportedAttributesVersion) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| attributes_.version = 25; |
| ops_.set_permanent_attributes(attributes_); |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, ValidateUnlockCredential_AttributesHashMismatch) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| ops_.set_permanent_attributes_hash("bad_hash"); |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, ValidateUnlockCredential_FailReadPIKRollbackIndex) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| fail_read_pik_rollback_index_ = true; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_ERROR_IO, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, |
| ValidateUnlockCredential_UnsupportedPIKCertificateVersion) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| unlock_credential_.product_intermediate_key_certificate.signed_data.version = |
| 25; |
| SignUnlockCredentialPIKCertificate(); |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, |
| ValidateUnlockCredential_BadPIKCert_ModifiedSubjectPublicKey) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| unlock_credential_.product_intermediate_key_certificate.signed_data |
| .public_key[0] ^= 1; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, |
| ValidateUnlockCredential_BadPIKCert_ModifiedSubject) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| unlock_credential_.product_intermediate_key_certificate.signed_data |
| .subject[0] ^= 1; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, ValidateUnlockCredential_BadPIKCert_ModifiedUsage) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| unlock_credential_.product_intermediate_key_certificate.signed_data |
| .usage[0] ^= 1; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, |
| ValidateUnlockCredential_BadPIKCert_ModifiedKeyVersion) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| unlock_credential_.product_intermediate_key_certificate.signed_data |
| .key_version ^= 1; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, ValidateUnlockCredential_BadPIKCert_BadSignature) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| unlock_credential_.product_intermediate_key_certificate.signature[0] ^= 1; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, ValidateUnlockCredential_PIKCertSubjectIgnored) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| unlock_credential_.product_intermediate_key_certificate.signed_data |
| .subject[0] ^= 1; |
| SignUnlockCredentialPIKCertificate(); |
| bool is_trusted = false; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_TRUE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, ValidateUnlockCredential_PIKCertUnexpectedUsage) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| unlock_credential_.product_intermediate_key_certificate.signed_data |
| .usage[0] ^= 1; |
| SignUnlockCredentialPIKCertificate(); |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, ValidateUnlockCredential_PIKRollback) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| ops_.set_stored_rollback_indexes( |
| {{AVB_ATX_PIK_VERSION_LOCATION, |
| unlock_credential_.product_intermediate_key_certificate.signed_data |
| .key_version + |
| 1}, |
| {AVB_ATX_PSK_VERSION_LOCATION, 0}}); |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, ValidateUnlockCredential_FailReadPSKRollbackIndex) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| fail_read_psk_rollback_index_ = true; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_ERROR_IO, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, |
| ValidateUnlockCredential_UnsupportedPUKCertificateVersion) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| unlock_credential_.product_unlock_key_certificate.signed_data.version = 25; |
| SignUnlockCredentialPUKCertificate(); |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, |
| ValidateUnlockCredential_BadPUKCert_ModifiedSubjectPublicKey) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| unlock_credential_.product_unlock_key_certificate.signed_data.public_key[0] ^= |
| 1; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, |
| ValidateUnlockCredential_BadPUKCert_ModifiedSubject) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| unlock_credential_.product_unlock_key_certificate.signed_data.subject[0] ^= 1; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, ValidateUnlockCredential_BadPUKCert_ModifiedUsage) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| unlock_credential_.product_unlock_key_certificate.signed_data.usage[0] ^= 1; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, |
| ValidateUnlockCredential_BadPUKCert_ModifiedKeyVersion) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| unlock_credential_.product_unlock_key_certificate.signed_data.key_version ^= |
| 1; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, ValidateUnlockCredential_BadPUKCert_BadSignature) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| unlock_credential_.product_unlock_key_certificate.signature[0] ^= 1; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, ValidateUnlockCredential_PUKCertUnexpectedSubject) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| unlock_credential_.product_unlock_key_certificate.signed_data.subject[0] ^= 1; |
| SignUnlockCredentialPUKCertificate(); |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, ValidateUnlockCredential_PUKCertUnexpectedUsage) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| unlock_credential_.product_unlock_key_certificate.signed_data.usage[0] ^= 1; |
| SignUnlockCredentialPUKCertificate(); |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, ValidateUnlockCredential_PUKRollback) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| ops_.set_stored_rollback_indexes( |
| {{AVB_ATX_PIK_VERSION_LOCATION, 0}, |
| {AVB_ATX_PSK_VERSION_LOCATION, |
| unlock_credential_.product_unlock_key_certificate.signed_data |
| .key_version + |
| 1}}); |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, ValidateUnlockCredential_BadChallengeSignature) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| unlock_credential_.challenge_signature[10] ^= 1; |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, ValidateUnlockCredential_ChallengeMismatch) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| unlock_challenge_ = "bad"; |
| SignUnlockCredentialChallenge(kPUKPrivateKeyPath); |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, ValidateUnlockCredential_UnlockWithPSK) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| // Copy the PSK cert as the PUK cert. |
| memcpy(&unlock_credential_.product_unlock_key_certificate, |
| &metadata_.product_signing_key_certificate, |
| sizeof(AvbAtxCertificate)); |
| // Sign the challenge with the PSK instead of the PUK. |
| SignUnlockCredentialChallenge(kPSKPrivateKeyPath); |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, ValidateUnlockCredential_ReplayChallenge) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_TRUE(is_trusted); |
| // A second attempt with the same challenge should fail. |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_FALSE(is_trusted); |
| } |
| |
| TEST_F(AvbAtxValidateTest, ValidateUnlockCredential_MultipleUnlock) { |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| bool is_trusted = true; |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_TRUE(is_trusted); |
| // A second attempt with a newly staged challenge should succeed. |
| ASSERT_TRUE(PrepareUnlockCredential()); |
| EXPECT_EQ(AVB_IO_RESULT_OK, ValidateUnlock(&is_trusted)); |
| EXPECT_TRUE(is_trusted); |
| } |
| |
| // A fixture for testing avb_slot_verify() with ATX. |
| class AvbAtxSlotVerifyTest : public BaseAvbToolTest, |
| public FakeAvbOpsDelegateWithDefaults { |
| public: |
| ~AvbAtxSlotVerifyTest() 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_rollback_indexes({{0, 0}, |
| {1, 0}, |
| {2, 0}, |
| {3, 0}, |
| {AVB_ATX_PIK_VERSION_LOCATION, 0}, |
| {AVB_ATX_PSK_VERSION_LOCATION, 0}}); |
| ops_.set_stored_is_device_unlocked(false); |
| } |
| |
| // FakeAvbOpsDelegate override. |
| 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_.avb_ops(), |
| public_key_data, |
| public_key_length, |
| public_key_metadata, |
| public_key_metadata_length, |
| out_key_is_trusted); |
| } |
| |
| protected: |
| AvbAtxPermanentAttributes attributes_; |
| int num_atx_calls_ = 0; |
| |
| 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_F(AvbAtxSlotVerifyTest, SlotVerifyWithAtx) { |
| std::string metadata_option = "--public_key_metadata="; |
| metadata_option += kMetadataPath; |
| GenerateVBMetaImage("vbmeta_a.img", |
| "SHA512_RSA4096", |
| 0, |
| base::FilePath("test/data/testkey_atx_psk.pem"), |
| metadata_option); |
| |
| ops_.set_expected_public_key( |
| PublicKeyAVB(base::FilePath("test/data/testkey_atx_psk.pem"))); |
| |
| AvbSlotVerifyData* slot_data = NULL; |
| const char* requested_partitions[] = {"boot", NULL}; |
| EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_OK, |
| avb_slot_verify(ops_.avb_ops(), |
| requested_partitions, |
| "_a", |
| AVB_SLOT_VERIFY_FLAGS_NONE, |
| AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, |
| &slot_data)); |
| EXPECT_NE(nullptr, slot_data); |
| avb_slot_verify_data_free(slot_data); |
| EXPECT_EQ(1, num_atx_calls_); |
| } |
| |
| } // namespace avb |