blob: 2f0b5a0667e2d824b39a8d6e6e50bd4d9b77fa0b [file] [edit]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cryptohome/auth_blocks/revocation.h"
#include <string>
#include <brillo/secure_blob.h>
#include <gtest/gtest.h>
#include <libhwsec-foundation/error/testing_helper.h>
#include "cryptohome/mock_le_credential_manager.h"
using cryptohome::error::CryptohomeError;
using cryptohome::error::CryptohomeLECredError;
using cryptohome::error::ErrorActionSet;
using cryptohome::error::PossibleAction;
using cryptohome::error::PrimaryAction;
using hwsec_foundation::error::testing::IsOk;
using hwsec_foundation::error::testing::NotOk;
using hwsec_foundation::error::testing::ReturnError;
using testing::_;
using testing::DoAll;
using testing::NiceMock;
using testing::Return;
using testing::SaveArg;
using testing::SetArgPointee;
namespace cryptohome {
namespace revocation {
namespace {
const char kFakePerCredentialSecret[] = "fake per-credential secret";
const char kFakeHESecret[] = "fake high entropy secret";
} // namespace
TEST(RevocationTest, Create) {
brillo::SecureBlob per_credential_secret(kFakePerCredentialSecret);
NiceMock<MockLECredentialManager> le_cred_manager;
RevocationState state;
KeyBlobs key_blobs = {.vkk_key = per_credential_secret};
EXPECT_CALL(le_cred_manager, InsertCredential(_, _, _, _, _, _, _))
.WillOnce(ReturnError<CryptohomeLECredError>());
ASSERT_THAT(Create(&le_cred_manager, &state, &key_blobs), IsOk());
}
TEST(RevocationTest, Derive) {
brillo::SecureBlob he_secret(kFakeHESecret);
brillo::SecureBlob per_credential_secret(kFakePerCredentialSecret);
NiceMock<MockLECredentialManager> le_cred_manager;
RevocationState state = {.le_label = 0};
KeyBlobs key_blobs = {.vkk_key = per_credential_secret};
EXPECT_CALL(le_cred_manager, CheckCredential(_, _, _, _))
.WillOnce(DoAll(SetArgPointee<2>(he_secret),
ReturnError<CryptohomeLECredError>()));
ASSERT_THAT(Derive(&le_cred_manager, state, &key_blobs), IsOk());
}
TEST(RevocationTest, DeriveFailsWithoutLabel) {
brillo::SecureBlob per_credential_secret(kFakePerCredentialSecret);
NiceMock<MockLECredentialManager> le_cred_manager;
KeyBlobs key_blobs = {.vkk_key = per_credential_secret};
RevocationState state;
auto status = Derive(&le_cred_manager, state, &key_blobs);
ASSERT_THAT(status, NotOk());
EXPECT_EQ(status->local_crypto_error(), CryptoError::CE_OTHER_CRYPTO);
}
TEST(RevocationTest, Revoke) {
NiceMock<MockLECredentialManager> le_cred_manager;
RevocationState state = {.le_label = 0};
uint64_t label;
EXPECT_CALL(le_cred_manager, RemoveCredential(_))
.WillOnce(
DoAll(SaveArg<0>(&label), ReturnError<CryptohomeLECredError>()));
ASSERT_THAT(
Revoke(AuthBlockType::kCryptohomeRecovery, &le_cred_manager, state),
IsOk());
EXPECT_EQ(label, state.le_label.value());
}
TEST(RevocationTest, RevokeFailsWithoutLabel) {
NiceMock<MockLECredentialManager> le_cred_manager;
RevocationState state;
auto status =
Revoke(AuthBlockType::kCryptohomeRecovery, &le_cred_manager, state);
ASSERT_THAT(status, NotOk());
EXPECT_EQ(status->local_crypto_error(), CryptoError::CE_OTHER_CRYPTO);
}
TEST(RevocationTest, RevokeSucceedsWithLeCredErrorInvalidLabel) {
const CryptohomeError::ErrorLocationPair kErrorLocationForTesting1 =
CryptohomeError::ErrorLocationPair(
static_cast<::cryptohome::error::CryptohomeError::ErrorLocation>(1),
std::string("Testing1"));
NiceMock<MockLECredentialManager> le_cred_manager;
RevocationState state = {.le_label = 0};
uint64_t label;
EXPECT_CALL(le_cred_manager, RemoveCredential(_))
.WillOnce(DoAll(SaveArg<0>(&label),
ReturnError<CryptohomeLECredError>(
kErrorLocationForTesting1,
ErrorActionSet({PossibleAction::kFatal}),
LE_CRED_ERROR_INVALID_LABEL)));
// Revoke succeeds after LE_CRED_ERROR_INVALID_LABEL.
ASSERT_THAT(
Revoke(AuthBlockType::kCryptohomeRecovery, &le_cred_manager, state),
IsOk());
EXPECT_EQ(label, state.le_label.value());
}
TEST(RevocationTest, RevokeSucceedsWithLeCredErrorHashTree) {
const CryptohomeError::ErrorLocationPair kErrorLocationForTesting1 =
CryptohomeError::ErrorLocationPair(
static_cast<::cryptohome::error::CryptohomeError::ErrorLocation>(1),
std::string("Testing1"));
NiceMock<MockLECredentialManager> le_cred_manager;
RevocationState state = {.le_label = 0};
uint64_t label;
EXPECT_CALL(le_cred_manager, RemoveCredential(_))
.WillOnce(DoAll(SaveArg<0>(&label),
ReturnError<CryptohomeLECredError>(
kErrorLocationForTesting1,
ErrorActionSet({PossibleAction::kFatal}),
LE_CRED_ERROR_HASH_TREE)));
// Revoke succeeds after LE_CRED_ERROR_HASH_TREE.
ASSERT_THAT(
Revoke(AuthBlockType::kCryptohomeRecovery, &le_cred_manager, state),
IsOk());
EXPECT_EQ(label, state.le_label.value());
}
TEST(RevocationTest, RevokeFailsWithLeCredErrorUnclassified) {
const CryptohomeError::ErrorLocationPair kErrorLocationForTesting1 =
CryptohomeError::ErrorLocationPair(
static_cast<::cryptohome::error::CryptohomeError::ErrorLocation>(1),
std::string("Testing1"));
NiceMock<MockLECredentialManager> le_cred_manager;
RevocationState state = {.le_label = 0};
uint64_t label;
EXPECT_CALL(le_cred_manager, RemoveCredential(_))
.WillOnce(DoAll(SaveArg<0>(&label),
ReturnError<CryptohomeLECredError>(
kErrorLocationForTesting1,
ErrorActionSet({PossibleAction::kFatal}),
LE_CRED_ERROR_UNCLASSIFIED)));
// Revoke fails after LE_CRED_ERROR_UNCLASSIFIED.
auto status =
Revoke(AuthBlockType::kCryptohomeRecovery, &le_cred_manager, state);
ASSERT_THAT(status, NotOk());
EXPECT_EQ(status->local_crypto_error(), CryptoError::CE_OTHER_CRYPTO);
}
TEST(RevocationTest, RevokeFailsWithLeCredErrorInvalidLeSecret) {
const CryptohomeError::ErrorLocationPair kErrorLocationForTesting1 =
CryptohomeError::ErrorLocationPair(
static_cast<::cryptohome::error::CryptohomeError::ErrorLocation>(1),
std::string("Testing1"));
NiceMock<MockLECredentialManager> le_cred_manager;
RevocationState state = {.le_label = 0};
uint64_t label;
EXPECT_CALL(le_cred_manager, RemoveCredential(_))
.WillOnce(DoAll(SaveArg<0>(&label),
ReturnError<CryptohomeLECredError>(
kErrorLocationForTesting1,
ErrorActionSet({PossibleAction::kFatal}),
LE_CRED_ERROR_INVALID_LE_SECRET)));
// Revoke fails after LE_CRED_ERROR_INVALID_LE_SECRET.
auto status =
Revoke(AuthBlockType::kCryptohomeRecovery, &le_cred_manager, state);
ASSERT_THAT(status, NotOk());
EXPECT_EQ(status->local_crypto_error(), CryptoError::CE_OTHER_CRYPTO);
}
} // namespace revocation
} // namespace cryptohome