[go: nahoru, domu]

blob: e114aae5fbcfcfcf3070d96219de2b3e65bf5730 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_client.h"
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
#include <memory>
#include "base/apple/bridging.h"
#include "base/apple/foundation_util.h"
#include "base/apple/scoped_cftyperef.h"
#include "base/containers/span.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/metrics_util.h"
#include "chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/mock_secure_enclave_helper.h"
#include "chrome/browser/enterprise/connectors/device_trust/key_management/core/mac/secure_enclave_helper.h"
#include "chrome/browser/enterprise/connectors/device_trust/key_management/core/shared_command_constants.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
namespace enterprise_connectors {
namespace {
constexpr char kPermanentStatusHistogramName[] =
"Enterprise.DeviceTrust.Mac.SecureEnclaveOperation.Permanent";
constexpr char kTemporaryStatusHistogramName[] =
"Enterprise.DeviceTrust.Mac.SecureEnclaveOperation.Temporary";
constexpr char kOSStatusHistogramPrefix[] =
"Enterprise.DeviceTrust.Mac.KeychainOSStatus.";
constexpr char kKeychainOSStatusHistogramFormat[] =
"Enterprise.DeviceTrust.Mac.KeychainOSStatus.%s.%s";
std::string GetOSStatusHistogramName(bool permanent_key,
const std::string& operation) {
return base::StringPrintf(kKeychainOSStatusHistogramFormat,
permanent_key ? "Permanent" : "Temporary",
operation.c_str());
}
} // namespace
using test::MockSecureEnclaveHelper;
class SecureEnclaveClientTest : public testing::Test {
protected:
void SetUp() override {
auto mock_secure_enclave_helper =
std::make_unique<MockSecureEnclaveHelper>();
mock_secure_enclave_helper_ = mock_secure_enclave_helper.get();
SecureEnclaveHelper::SetInstanceForTesting(
std::move(mock_secure_enclave_helper));
secure_enclave_client_ = SecureEnclaveClient::Create();
CreateAndSetTestKey();
}
// Creates a test key.
void CreateAndSetTestKey() {
base::ScopedCFTypeRef<CFMutableDictionaryRef> test_attributes(
CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks));
CFDictionarySetValue(test_attributes, kSecAttrLabel,
base::SysUTF8ToCFStringRef("fake-label"));
CFDictionarySetValue(test_attributes, kSecAttrKeyType,
kSecAttrKeyTypeECSECPrimeRandom);
CFDictionarySetValue(test_attributes, kSecAttrKeySizeInBits,
base::apple::NSToCFPtrCast(@256));
base::ScopedCFTypeRef<CFMutableDictionaryRef> private_key_params(
CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks));
CFDictionarySetValue(private_key_params, kSecAttrIsPermanent,
kCFBooleanFalse);
CFDictionarySetValue(test_attributes, kSecPrivateKeyAttrs,
private_key_params);
test_key_ = base::ScopedCFTypeRef<SecKeyRef>(
SecKeyCreateRandomKey(test_attributes, nullptr));
}
void VerifyQuery(CFDictionaryRef query, CFStringRef label) {
EXPECT_TRUE(CFEqual(label, base::apple::GetValueFromDictionary<CFStringRef>(
query, kSecAttrLabel)));
EXPECT_TRUE(CFEqual(kSecAttrKeyTypeECSECPrimeRandom,
base::apple::GetValueFromDictionary<CFStringRef>(
query, kSecAttrKeyType)));
}
base::HistogramTester histogram_tester_;
raw_ptr<MockSecureEnclaveHelper, DanglingUntriaged>
mock_secure_enclave_helper_ = nullptr;
std::unique_ptr<SecureEnclaveClient> secure_enclave_client_;
base::ScopedCFTypeRef<SecKeyRef> test_key_;
};
// Tests that the CreatePermanentKey method invokes both the SE helper's
// Delete and CreateSecureKey method and that the key attributes are set
// correctly.
TEST_F(SecureEnclaveClientTest, CreateKey_Success) {
EXPECT_CALL(*mock_secure_enclave_helper_, Delete(_))
.Times(1)
.WillOnce([this](CFDictionaryRef query) {
VerifyQuery(query, base::SysUTF8ToCFStringRef(
constants::kDeviceTrustSigningKeyLabel));
return errSecSuccess;
});
EXPECT_CALL(*mock_secure_enclave_helper_, CreateSecureKey(_, _))
.Times(1)
.WillOnce([this](CFDictionaryRef attributes, OSStatus* status) {
EXPECT_TRUE(CFEqual(
base::SysUTF8ToCFStringRef(constants::kDeviceTrustSigningKeyLabel),
base::apple::GetValueFromDictionary<CFStringRef>(attributes,
kSecAttrLabel)));
EXPECT_TRUE(CFEqual(kSecAttrKeyTypeECSECPrimeRandom,
base::apple::GetValueFromDictionary<CFStringRef>(
attributes, kSecAttrKeyType)));
EXPECT_TRUE(CFEqual(kSecAttrTokenIDSecureEnclave,
base::apple::GetValueFromDictionary<CFStringRef>(
attributes, kSecAttrTokenID)));
EXPECT_TRUE(CFEqual(base::apple::NSToCFPtrCast(@256),
base::apple::GetValueFromDictionary<CFNumberRef>(
attributes, kSecAttrKeySizeInBits)));
auto* private_key_attributes =
base::apple::GetValueFromDictionary<CFDictionaryRef>(
attributes, kSecPrivateKeyAttrs);
EXPECT_TRUE(CFEqual(kCFBooleanTrue,
base::apple::GetValueFromDictionary<CFBooleanRef>(
private_key_attributes, kSecAttrIsPermanent)));
*status = errSecSuccess;
return test_key_;
});
EXPECT_EQ(secure_enclave_client_->CreatePermanentKey(), test_key_);
// Should expect no create key failure metrics.
histogram_tester_.ExpectTotalCount(kPermanentStatusHistogramName, 0);
histogram_tester_.ExpectTotalCount(kTemporaryStatusHistogramName, 0);
EXPECT_TRUE(
histogram_tester_.GetTotalCountsForPrefix(kOSStatusHistogramPrefix)
.empty());
}
// Tests that a create key failure metric is logged when the CreatePermanentKey
// method fails to create the permanent key.
TEST_F(SecureEnclaveClientTest, CreateKey_Failure) {
EXPECT_CALL(*mock_secure_enclave_helper_, Delete(_))
.Times(1)
.WillOnce([this](CFDictionaryRef query) {
VerifyQuery(query, base::SysUTF8ToCFStringRef(
constants::kDeviceTrustSigningKeyLabel));
return errSecSuccess;
});
EXPECT_CALL(*mock_secure_enclave_helper_, CreateSecureKey(_, _))
.Times(1)
.WillOnce([](CFDictionaryRef attributes, OSStatus* status) {
*status = errSecItemNotFound;
return base::ScopedCFTypeRef<SecKeyRef>();
});
EXPECT_FALSE(secure_enclave_client_->CreatePermanentKey());
// Should expect one create key failure metric for the permanent key.
histogram_tester_.ExpectUniqueSample(
kPermanentStatusHistogramName,
SecureEnclaveOperationStatus::kCreateSecureKeyFailed, 1);
histogram_tester_.ExpectUniqueSample(GetOSStatusHistogramName(true, "Create"),
errSecItemNotFound, 1);
EXPECT_EQ(histogram_tester_.GetTotalCountsForPrefix(kOSStatusHistogramPrefix)
.size(),
1U);
// Should expect no create key failure metric for the temporary key.
histogram_tester_.ExpectTotalCount(kTemporaryStatusHistogramName, 0);
}
// Tests when the CopyStoredKey method invokes the SE helper's CopyKey method
// and a key is found using both a permanent and a temporary key type.
TEST_F(SecureEnclaveClientTest, CopyStoredKey_KeyFound) {
EXPECT_CALL(*mock_secure_enclave_helper_, CopyKey(_, _))
.Times(2)
.WillRepeatedly([this](CFDictionaryRef query, OSStatus* status) {
*status = errSecSuccess;
return test_key_;
});
EXPECT_EQ(secure_enclave_client_->CopyStoredKey(
SecureEnclaveClient::KeyType::kPermanent),
test_key_);
EXPECT_EQ(secure_enclave_client_->CopyStoredKey(
SecureEnclaveClient::KeyType::kTemporary),
test_key_);
// Should expect no copy key failure metrics.
histogram_tester_.ExpectTotalCount(kPermanentStatusHistogramName, 0);
histogram_tester_.ExpectTotalCount(kTemporaryStatusHistogramName, 0);
EXPECT_TRUE(
histogram_tester_.GetTotalCountsForPrefix(kOSStatusHistogramPrefix)
.empty());
}
// Tests when the CopyStoredKey method invokes the SE helper's CopyKey method
// and a key is not found using both a permanent and a temporary key type.
TEST_F(SecureEnclaveClientTest, CopyStoredKey_KeyNotFound) {
EXPECT_CALL(*mock_secure_enclave_helper_, CopyKey(_, _))
.Times(2)
.WillRepeatedly([](CFDictionaryRef query, OSStatus* status) {
*status = errSecItemNotFound;
return base::ScopedCFTypeRef<SecKeyRef>();
});
EXPECT_FALSE(secure_enclave_client_->CopyStoredKey(
SecureEnclaveClient::KeyType::kPermanent));
EXPECT_FALSE(secure_enclave_client_->CopyStoredKey(
SecureEnclaveClient::KeyType::kTemporary));
auto status = SecureEnclaveOperationStatus::
kCopySecureKeyRefDataProtectionKeychainFailed;
// Should expect one copy key reference failure metric for the permanent key.
histogram_tester_.ExpectUniqueSample(kPermanentStatusHistogramName, status,
1);
// Should expect one copy key reference failure metric for the temporary key.
histogram_tester_.ExpectUniqueSample(kTemporaryStatusHistogramName, status,
1);
histogram_tester_.ExpectUniqueSample(GetOSStatusHistogramName(true, "Copy"),
errSecItemNotFound, 1);
histogram_tester_.ExpectUniqueSample(GetOSStatusHistogramName(false, "Copy"),
errSecItemNotFound, 1);
EXPECT_EQ(histogram_tester_.GetTotalCountsForPrefix(kOSStatusHistogramPrefix)
.size(),
2U);
}
// Tests that the UpdateStoredKeyLabel method invokes the SE helper's
// Update method and that the key attributes and query are set correctly for
// the permanent key label being updated to the temporary key label.
TEST_F(SecureEnclaveClientTest,
UpdateStoredKeyLabel_PermanentToTemporary_Success) {
EXPECT_CALL(*mock_secure_enclave_helper_, Delete(_))
.Times(1)
.WillOnce([](CFDictionaryRef query) { return errSecSuccess; });
EXPECT_CALL(*mock_secure_enclave_helper_, Update(_, _))
.Times(1)
.WillOnce(
[this](CFDictionaryRef query, CFDictionaryRef attribute_to_update) {
EXPECT_TRUE(
CFEqual(base::SysUTF8ToCFStringRef(
constants::kTemporaryDeviceTrustSigningKeyLabel),
base::apple::GetValueFromDictionary<CFStringRef>(
attribute_to_update, kSecAttrLabel)));
VerifyQuery(query, base::SysUTF8ToCFStringRef(
constants::kDeviceTrustSigningKeyLabel));
return errSecSuccess;
});
EXPECT_TRUE(secure_enclave_client_->UpdateStoredKeyLabel(
SecureEnclaveClient::KeyType::kPermanent,
SecureEnclaveClient::KeyType::kTemporary));
// Should expect no update key failure metrics.
histogram_tester_.ExpectTotalCount(kPermanentStatusHistogramName, 0);
histogram_tester_.ExpectTotalCount(kTemporaryStatusHistogramName, 0);
EXPECT_TRUE(
histogram_tester_.GetTotalCountsForPrefix(kOSStatusHistogramPrefix)
.empty());
}
// Tests that an update key failure metric is logged when the
// UpdateStoredKeyLabel method fails to update the permanent key to temporary
// key storage.
TEST_F(SecureEnclaveClientTest,
UpdateStoredKeyLabel_PermanentToTemporary_Failure) {
EXPECT_CALL(*mock_secure_enclave_helper_, Delete(_))
.Times(1)
.WillOnce([](CFDictionaryRef query) { return errSecSuccess; });
EXPECT_CALL(*mock_secure_enclave_helper_, Update(_, _))
.Times(1)
.WillOnce([](CFDictionaryRef query, CFDictionaryRef attribute_to_update) {
return errSecItemNotFound;
});
EXPECT_FALSE(secure_enclave_client_->UpdateStoredKeyLabel(
SecureEnclaveClient::KeyType::kPermanent,
SecureEnclaveClient::KeyType::kTemporary));
auto status = SecureEnclaveOperationStatus::
kUpdateSecureKeyLabelDataProtectionKeychainFailed;
// Should expect an update failure metric for the permanent key.
histogram_tester_.ExpectUniqueSample(kPermanentStatusHistogramName, status,
1);
histogram_tester_.ExpectUniqueSample(GetOSStatusHistogramName(true, "Update"),
errSecItemNotFound, 1);
EXPECT_EQ(histogram_tester_.GetTotalCountsForPrefix(kOSStatusHistogramPrefix)
.size(),
1U);
// Should expect no update key failure metric for the temporary key.
histogram_tester_.ExpectTotalCount(kTemporaryStatusHistogramName, 0);
}
// Tests that the UpdateStoredKeyLabel method invokes the SE helper's
// Update method and that the key attributes and query are set correctly for
// the temporary key label being updated to the permanent key label.
TEST_F(SecureEnclaveClientTest,
UpdateStoredKeyLabel_TemporaryToPermanent_Success) {
EXPECT_CALL(*mock_secure_enclave_helper_, Delete(_))
.Times(1)
.WillOnce([](CFDictionaryRef query) { return errSecSuccess; });
EXPECT_CALL(*mock_secure_enclave_helper_, Update(_, _))
.Times(1)
.WillOnce([this](CFDictionaryRef query,
CFDictionaryRef attribute_to_update) {
EXPECT_TRUE(CFEqual(
base::SysUTF8ToCFStringRef(constants::kDeviceTrustSigningKeyLabel),
base::apple::GetValueFromDictionary<CFStringRef>(
attribute_to_update, kSecAttrLabel)));
VerifyQuery(query,
base::SysUTF8ToCFStringRef(
constants::kTemporaryDeviceTrustSigningKeyLabel));
return errSecSuccess;
});
EXPECT_TRUE(secure_enclave_client_->UpdateStoredKeyLabel(
SecureEnclaveClient::KeyType::kTemporary,
SecureEnclaveClient::KeyType::kPermanent));
// Should expect no update key failure metrics.
histogram_tester_.ExpectTotalCount(kPermanentStatusHistogramName, 0);
histogram_tester_.ExpectTotalCount(kTemporaryStatusHistogramName, 0);
EXPECT_TRUE(
histogram_tester_.GetTotalCountsForPrefix(kOSStatusHistogramPrefix)
.empty());
}
// Tests that an update key failure metric is logged when the
// UpdateStoredKeyLabel method fails to update the temporary key to permanent
// key storage.
TEST_F(SecureEnclaveClientTest,
UpdateStoredKeyLabel_TemporaryToPermanent_Failure) {
EXPECT_CALL(*mock_secure_enclave_helper_, Delete(_))
.Times(1)
.WillOnce([](CFDictionaryRef query) { return errSecSuccess; });
EXPECT_CALL(*mock_secure_enclave_helper_, Update(_, _))
.Times(1)
.WillOnce([](CFDictionaryRef query, CFDictionaryRef attribute_to_update) {
return errSecItemNotFound;
});
EXPECT_FALSE(secure_enclave_client_->UpdateStoredKeyLabel(
SecureEnclaveClient::KeyType::kTemporary,
SecureEnclaveClient::KeyType::kPermanent));
auto status = SecureEnclaveOperationStatus::
kUpdateSecureKeyLabelDataProtectionKeychainFailed;
// Should expect an update failure metric for the temporary key.
histogram_tester_.ExpectUniqueSample(kTemporaryStatusHistogramName, status,
1);
histogram_tester_.ExpectUniqueSample(
GetOSStatusHistogramName(false, "Update"), errSecItemNotFound, 1);
EXPECT_EQ(histogram_tester_.GetTotalCountsForPrefix(kOSStatusHistogramPrefix)
.size(),
1U);
// Should expect no update key failure metric for the permanent key.
histogram_tester_.ExpectTotalCount(kPermanentStatusHistogramName, 0);
}
// Tests that the DeleteKey method invokes the SE helper's Delete method
// and that the key query is set correctly with the temporary key label.
TEST_F(SecureEnclaveClientTest, DeleteKey_TempKeyLabel_Success) {
EXPECT_CALL(*mock_secure_enclave_helper_, Delete(_))
.Times(1)
.WillOnce([this](CFDictionaryRef query) {
VerifyQuery(query,
base::SysUTF8ToCFStringRef(
constants::kTemporaryDeviceTrustSigningKeyLabel));
return errSecSuccess;
});
EXPECT_TRUE(secure_enclave_client_->DeleteKey(
SecureEnclaveClient::KeyType::kTemporary));
// Should expect no delete key failure metrics.
histogram_tester_.ExpectTotalCount(kPermanentStatusHistogramName, 0);
histogram_tester_.ExpectTotalCount(kTemporaryStatusHistogramName, 0);
EXPECT_TRUE(
histogram_tester_.GetTotalCountsForPrefix(kOSStatusHistogramPrefix)
.empty());
}
// Tests that a delete key failure metric is logged when the DeleteKey method
// fails to delete the temporary key.
TEST_F(SecureEnclaveClientTest, DeleteKey_TempKeyLabel_Failure) {
EXPECT_CALL(*mock_secure_enclave_helper_, Delete(_))
.Times(1)
.WillOnce([](CFDictionaryRef query) { return errSecItemNotFound; });
EXPECT_FALSE(secure_enclave_client_->DeleteKey(
SecureEnclaveClient::KeyType::kTemporary));
auto status = SecureEnclaveOperationStatus::
kDeleteSecureKeyDataProtectionKeychainFailed;
// Should expect one delete key failure metric for the temporary key.
histogram_tester_.ExpectUniqueSample(kTemporaryStatusHistogramName, status,
1);
histogram_tester_.ExpectUniqueSample(
GetOSStatusHistogramName(false, "Delete"), errSecItemNotFound, 1);
EXPECT_EQ(histogram_tester_.GetTotalCountsForPrefix(kOSStatusHistogramPrefix)
.size(),
1U);
// Should expect no delete key failure metric for the permanent key.
histogram_tester_.ExpectTotalCount(kPermanentStatusHistogramName, 0);
}
// Tests that the DeleteKey method invokes the SE helper's Delete method
// and that the key query is set correctly with the permanent key label.
TEST_F(SecureEnclaveClientTest, DeleteKey_PermanentKeyLabel_Success) {
EXPECT_CALL(*mock_secure_enclave_helper_, Delete(_))
.Times(1)
.WillOnce([this](CFDictionaryRef query) {
VerifyQuery(query, base::SysUTF8ToCFStringRef(
constants::kDeviceTrustSigningKeyLabel));
return errSecSuccess;
});
EXPECT_TRUE(secure_enclave_client_->DeleteKey(
SecureEnclaveClient::KeyType::kPermanent));
// Should expect no delete key failure metrics.
histogram_tester_.ExpectTotalCount(kPermanentStatusHistogramName, 0);
histogram_tester_.ExpectTotalCount(kTemporaryStatusHistogramName, 0);
EXPECT_TRUE(
histogram_tester_.GetTotalCountsForPrefix(kOSStatusHistogramPrefix)
.empty());
}
// Tests that a delete key failure metric is logged when the DeleteKey method
// fails to delete the permanent key.
TEST_F(SecureEnclaveClientTest, DeleteKey_PermanentKeyLabel_Failure) {
EXPECT_CALL(*mock_secure_enclave_helper_, Delete(_))
.Times(1)
.WillOnce([](CFDictionaryRef query) { return errSecItemNotFound; });
EXPECT_FALSE(secure_enclave_client_->DeleteKey(
SecureEnclaveClient::KeyType::kPermanent));
auto status = SecureEnclaveOperationStatus::
kDeleteSecureKeyDataProtectionKeychainFailed;
// Should expect one delete key failure metric for the permanent key.
histogram_tester_.ExpectUniqueSample(kPermanentStatusHistogramName, status,
1);
histogram_tester_.ExpectUniqueSample(GetOSStatusHistogramName(true, "Delete"),
errSecItemNotFound, 1);
EXPECT_EQ(histogram_tester_.GetTotalCountsForPrefix(kOSStatusHistogramPrefix)
.size(),
1U);
// Should expect no delete key failure metric for the temporary key.
histogram_tester_.ExpectTotalCount(kTemporaryStatusHistogramName, 0);
}
// Tests that the GetStoredKeyLabel method invokes the SE helper's CopyKey
// method, and that the query and output is correct for a temporary key.
TEST_F(SecureEnclaveClientTest, GetStoredKeyLabel_TempKeyLabelFound) {
std::vector<uint8_t> output;
std::string temp_label = constants::kTemporaryDeviceTrustSigningKeyLabel;
EXPECT_CALL(*mock_secure_enclave_helper_, CopyKey(_, _))
.Times(1)
.WillOnce([this, &temp_label](CFDictionaryRef query, OSStatus* status) {
VerifyQuery(query, base::SysUTF8ToCFStringRef(temp_label));
*status = errSecSuccess;
return test_key_;
});
EXPECT_TRUE(secure_enclave_client_->GetStoredKeyLabel(
SecureEnclaveClient::KeyType::kTemporary, output));
std::vector<uint8_t> expected_output;
expected_output.assign(temp_label.begin(), temp_label.end());
EXPECT_EQ(expected_output, output);
// Should expect no copy key failure metrics.
histogram_tester_.ExpectTotalCount(kPermanentStatusHistogramName, 0);
histogram_tester_.ExpectTotalCount(kTemporaryStatusHistogramName, 0);
EXPECT_TRUE(
histogram_tester_.GetTotalCountsForPrefix(kOSStatusHistogramPrefix)
.empty());
}
// Tests that the GetStoredKeyLabel method invokes the SE helper's CopyKey
// method and that the query search returns false. Also tests that a copy key
// failure metric is logged.
TEST_F(SecureEnclaveClientTest, GetStoredKeyLabel_TemporaryKeyNotFound) {
std::vector<uint8_t> output;
EXPECT_CALL(*mock_secure_enclave_helper_, CopyKey(_, _))
.Times(1)
.WillOnce([](CFDictionaryRef query, OSStatus* status) {
*status = errSecItemNotFound;
return base::ScopedCFTypeRef<SecKeyRef>();
});
EXPECT_FALSE(secure_enclave_client_->GetStoredKeyLabel(
SecureEnclaveClient::KeyType::kTemporary, output));
std::vector<uint8_t> expected_output;
EXPECT_EQ(expected_output, output);
auto status = SecureEnclaveOperationStatus::
kCopySecureKeyRefDataProtectionKeychainFailed;
// Should expect one copy key failure metric for the temporary key.
histogram_tester_.ExpectUniqueSample(kTemporaryStatusHistogramName, status,
1);
histogram_tester_.ExpectUniqueSample(GetOSStatusHistogramName(false, "Copy"),
errSecItemNotFound, 1);
EXPECT_EQ(histogram_tester_.GetTotalCountsForPrefix(kOSStatusHistogramPrefix)
.size(),
1U);
// Should expect no copy key failure metric for the permanent key.
histogram_tester_.ExpectTotalCount(kPermanentStatusHistogramName, 0);
}
// Tests that the GetStoredKeyLabel method invokes the SE helper's CopyKey
// method and that the query and output is correct for a permanent key.
TEST_F(SecureEnclaveClientTest, GetStoredKeyLabel_PermanentKeyLabelFound) {
std::vector<uint8_t> output;
std::string permanent_label = constants::kDeviceTrustSigningKeyLabel;
EXPECT_CALL(*mock_secure_enclave_helper_, CopyKey(_, _))
.Times(1)
.WillOnce(
[this, &permanent_label](CFDictionaryRef query, OSStatus* status) {
VerifyQuery(query, base::SysUTF8ToCFStringRef(permanent_label));
*status = errSecSuccess;
return test_key_;
});
EXPECT_TRUE(secure_enclave_client_->GetStoredKeyLabel(
SecureEnclaveClient::KeyType::kPermanent, output));
std::vector<uint8_t> expected_output;
expected_output.assign(permanent_label.begin(), permanent_label.end());
EXPECT_EQ(expected_output, output);
// Should expect no copy key failure metrics.
histogram_tester_.ExpectTotalCount(kPermanentStatusHistogramName, 0);
histogram_tester_.ExpectTotalCount(kTemporaryStatusHistogramName, 0);
EXPECT_TRUE(
histogram_tester_.GetTotalCountsForPrefix(kOSStatusHistogramPrefix)
.empty());
}
// Tests that the GetStoredKeyLabel method invokes the SE helper's CopyKey
// method and that the query search returns false. Also tests that a copy key
// failure metric is logged.
TEST_F(SecureEnclaveClientTest, GetStoredKeyLabel_PermanentKeyNotFound) {
std::vector<uint8_t> output;
EXPECT_CALL(*mock_secure_enclave_helper_, CopyKey(_, _))
.Times(1)
.WillOnce([](CFDictionaryRef query, OSStatus* status) {
*status = errSecItemNotFound;
return base::ScopedCFTypeRef<SecKeyRef>();
});
EXPECT_FALSE(secure_enclave_client_->GetStoredKeyLabel(
SecureEnclaveClient::KeyType::kPermanent, output));
std::vector<uint8_t> expected_output;
EXPECT_EQ(expected_output, output);
auto status = SecureEnclaveOperationStatus::
kCopySecureKeyRefDataProtectionKeychainFailed;
// Should expect one copy key failure metric for the permanent key.
histogram_tester_.ExpectUniqueSample(kPermanentStatusHistogramName, status,
1);
histogram_tester_.ExpectUniqueSample(GetOSStatusHistogramName(true, "Copy"),
errSecItemNotFound, 1);
EXPECT_EQ(histogram_tester_.GetTotalCountsForPrefix(kOSStatusHistogramPrefix)
.size(),
1U);
// Should expect no copy key failure metric for the temporary key.
histogram_tester_.ExpectTotalCount(kTemporaryStatusHistogramName, 0);
}
// Tests that the ExportPublicKey method successfully creates the public key
// data and stores it in output.
TEST_F(SecureEnclaveClientTest, ExportPublicKey) {
std::vector<uint8_t> output;
EXPECT_TRUE(secure_enclave_client_->ExportPublicKey(test_key_, output));
EXPECT_TRUE(output.size() > 0);
}
// Tests that the SignDataWithKey method successfully creates a signature
// and stores it in output.
TEST_F(SecureEnclaveClientTest, SignDataWithKey) {
std::vector<uint8_t> output;
std::string data = "test_string";
EXPECT_TRUE(secure_enclave_client_->SignDataWithKey(
test_key_, base::as_bytes(base::make_span(data)), output));
EXPECT_TRUE(output.size() > 0);
}
// Tests that the VerifySecureEnclaveSupported method invokes the SE helper's
// IsSecureEnclaveSupported method.
TEST_F(SecureEnclaveClientTest, VerifySecureEnclaveSupported) {
EXPECT_CALL(*mock_secure_enclave_helper_, IsSecureEnclaveSupported())
.Times(1)
.WillOnce([]() { return true; });
EXPECT_TRUE(secure_enclave_client_->VerifySecureEnclaveSupported());
}
} // namespace enterprise_connectors