Remove depprecated methods in AppleKeychain.
BUG=595468 Review-Url: https://codereview.chromium.org/2932473004 Cr-Commit-Position: refs/heads/master@{#478050}
This commit is contained in:
@ -54,50 +54,7 @@ class CRYPTO_EXPORT AppleKeychain {
|
||||
SecKeychainItemRef* itemRef) const;
|
||||
|
||||
#if !defined(OS_IOS)
|
||||
virtual OSStatus ItemCopyAttributesAndData(
|
||||
SecKeychainItemRef itemRef,
|
||||
SecKeychainAttributeInfo* info,
|
||||
SecItemClass* itemClass,
|
||||
SecKeychainAttributeList** attrList,
|
||||
UInt32* length,
|
||||
void** outData) const;
|
||||
|
||||
virtual OSStatus ItemModifyAttributesAndData(
|
||||
SecKeychainItemRef itemRef,
|
||||
const SecKeychainAttributeList* attrList,
|
||||
UInt32 length,
|
||||
const void* data) const;
|
||||
|
||||
virtual OSStatus ItemFreeAttributesAndData(SecKeychainAttributeList* attrList,
|
||||
void* data) const;
|
||||
|
||||
virtual OSStatus ItemDelete(SecKeychainItemRef itemRef) const;
|
||||
|
||||
virtual OSStatus SearchCreateFromAttributes(
|
||||
CFTypeRef keychainOrArray,
|
||||
SecItemClass itemClass,
|
||||
const SecKeychainAttributeList* attrList,
|
||||
SecKeychainSearchRef* searchRef) const;
|
||||
|
||||
virtual OSStatus SearchCopyNext(SecKeychainSearchRef searchRef,
|
||||
SecKeychainItemRef* itemRef) const;
|
||||
|
||||
virtual OSStatus AddInternetPassword(SecKeychainRef keychain,
|
||||
UInt32 serverNameLength,
|
||||
const char* serverName,
|
||||
UInt32 securityDomainLength,
|
||||
const char* securityDomain,
|
||||
UInt32 accountNameLength,
|
||||
const char* accountName,
|
||||
UInt32 pathLength, const char* path,
|
||||
UInt16 port, SecProtocolType protocol,
|
||||
SecAuthenticationType authenticationType,
|
||||
UInt32 passwordLength,
|
||||
const void* passwordData,
|
||||
SecKeychainItemRef* itemRef) const;
|
||||
|
||||
// Calls CFRelease on the given ref, after checking that |ref| is non-NULL.
|
||||
virtual void Free(CFTypeRef ref) const;
|
||||
#endif // !defined(OS_IOS)
|
||||
|
||||
private:
|
||||
|
@ -15,93 +15,11 @@ AppleKeychain::AppleKeychain() {}
|
||||
|
||||
AppleKeychain::~AppleKeychain() {}
|
||||
|
||||
OSStatus AppleKeychain::ItemCopyAttributesAndData(
|
||||
SecKeychainItemRef itemRef,
|
||||
SecKeychainAttributeInfo* info,
|
||||
SecItemClass* itemClass,
|
||||
SecKeychainAttributeList** attrList,
|
||||
UInt32* length,
|
||||
void** outData) const {
|
||||
base::AutoLock lock(GetMacSecurityServicesLock());
|
||||
return SecKeychainItemCopyAttributesAndData(itemRef, info, itemClass,
|
||||
attrList, length, outData);
|
||||
}
|
||||
|
||||
OSStatus AppleKeychain::ItemModifyAttributesAndData(
|
||||
SecKeychainItemRef itemRef,
|
||||
const SecKeychainAttributeList* attrList,
|
||||
UInt32 length,
|
||||
const void* data) const {
|
||||
base::AutoLock lock(GetMacSecurityServicesLock());
|
||||
return SecKeychainItemModifyAttributesAndData(itemRef, attrList, length,
|
||||
data);
|
||||
}
|
||||
|
||||
OSStatus AppleKeychain::ItemFreeAttributesAndData(
|
||||
SecKeychainAttributeList* attrList,
|
||||
void* data) const {
|
||||
base::AutoLock lock(GetMacSecurityServicesLock());
|
||||
return SecKeychainItemFreeAttributesAndData(attrList, data);
|
||||
}
|
||||
|
||||
OSStatus AppleKeychain::ItemDelete(SecKeychainItemRef itemRef) const {
|
||||
base::AutoLock lock(GetMacSecurityServicesLock());
|
||||
return SecKeychainItemDelete(itemRef);
|
||||
}
|
||||
|
||||
OSStatus AppleKeychain::SearchCreateFromAttributes(
|
||||
CFTypeRef keychainOrArray,
|
||||
SecItemClass itemClass,
|
||||
const SecKeychainAttributeList* attrList,
|
||||
SecKeychainSearchRef* searchRef) const {
|
||||
base::AutoLock lock(GetMacSecurityServicesLock());
|
||||
// Eventually, this deprecated method should be removed entirely.
|
||||
// https://crbug.com/595468
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
return SecKeychainSearchCreateFromAttributes(keychainOrArray, itemClass,
|
||||
attrList, searchRef);
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
OSStatus AppleKeychain::SearchCopyNext(SecKeychainSearchRef searchRef,
|
||||
SecKeychainItemRef* itemRef) const {
|
||||
base::AutoLock lock(GetMacSecurityServicesLock());
|
||||
// Eventually, this deprecated method should be removed entirely.
|
||||
// https://crbug.com/595468
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
return SecKeychainSearchCopyNext(searchRef, itemRef);
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
OSStatus AppleKeychain::AddInternetPassword(
|
||||
SecKeychainRef keychain,
|
||||
UInt32 serverNameLength,
|
||||
const char* serverName,
|
||||
UInt32 securityDomainLength,
|
||||
const char* securityDomain,
|
||||
UInt32 accountNameLength,
|
||||
const char* accountName,
|
||||
UInt32 pathLength,
|
||||
const char* path,
|
||||
UInt16 port,
|
||||
SecProtocolType protocol,
|
||||
SecAuthenticationType authenticationType,
|
||||
UInt32 passwordLength,
|
||||
const void* passwordData,
|
||||
SecKeychainItemRef* itemRef) const {
|
||||
base::AutoLock lock(GetMacSecurityServicesLock());
|
||||
return SecKeychainAddInternetPassword(keychain,
|
||||
serverNameLength, serverName,
|
||||
securityDomainLength, securityDomain,
|
||||
accountNameLength, accountName,
|
||||
pathLength, path,
|
||||
port, protocol, authenticationType,
|
||||
passwordLength, passwordData,
|
||||
itemRef);
|
||||
}
|
||||
|
||||
OSStatus AppleKeychain::FindGenericPassword(CFTypeRef keychainOrArray,
|
||||
UInt32 serviceNameLength,
|
||||
const char* serviceName,
|
||||
@ -146,9 +64,4 @@ OSStatus AppleKeychain::AddGenericPassword(SecKeychainRef keychain,
|
||||
itemRef);
|
||||
}
|
||||
|
||||
void AppleKeychain::Free(CFTypeRef ref) const {
|
||||
if (ref)
|
||||
CFRelease(ref);
|
||||
}
|
||||
|
||||
} // namespace crypto
|
||||
|
@ -72,9 +72,6 @@ OSStatus MockAppleKeychain::AddGenericPassword(
|
||||
|
||||
DCHECK_GT(passwordLength, 0U);
|
||||
DCHECK(passwordData);
|
||||
add_generic_password_ =
|
||||
std::string(const_cast<char*>(static_cast<const char*>(passwordData)),
|
||||
passwordLength);
|
||||
return noErr;
|
||||
}
|
||||
|
||||
|
@ -19,9 +19,7 @@
|
||||
namespace crypto {
|
||||
|
||||
// Mock Keychain wrapper for testing code that interacts with the OS X
|
||||
// Keychain. Implemented by storing SecKeychainAttributeList and
|
||||
// KeychainPasswordData values in separate mutable containers and
|
||||
// mapping them to integer keys.
|
||||
// Keychain.
|
||||
//
|
||||
// Note that "const" is pretty much meaningless for this class; the const-ness
|
||||
// of AppleKeychain doesn't apply to the actual keychain data, so all of the
|
||||
@ -56,71 +54,7 @@ class CRYPTO_EXPORT MockAppleKeychain : public AppleKeychain {
|
||||
std::string GetEncryptionPassword() const;
|
||||
|
||||
#if !defined(OS_IOS)
|
||||
OSStatus ItemCopyAttributesAndData(SecKeychainItemRef itemRef,
|
||||
SecKeychainAttributeInfo* info,
|
||||
SecItemClass* itemClass,
|
||||
SecKeychainAttributeList** attrList,
|
||||
UInt32* length,
|
||||
void** outData) const override;
|
||||
// Pass "fail_me" as the data to get errSecAuthFailed.
|
||||
OSStatus ItemModifyAttributesAndData(SecKeychainItemRef itemRef,
|
||||
const SecKeychainAttributeList* attrList,
|
||||
UInt32 length,
|
||||
const void* data) const override;
|
||||
OSStatus ItemFreeAttributesAndData(SecKeychainAttributeList* attrList,
|
||||
void* data) const override;
|
||||
OSStatus ItemDelete(SecKeychainItemRef itemRef) const override;
|
||||
OSStatus SearchCreateFromAttributes(
|
||||
CFTypeRef keychainOrArray,
|
||||
SecItemClass itemClass,
|
||||
const SecKeychainAttributeList* attrList,
|
||||
SecKeychainSearchRef* searchRef) const override;
|
||||
OSStatus SearchCopyNext(SecKeychainSearchRef searchRef,
|
||||
SecKeychainItemRef* itemRef) const override;
|
||||
// Pass "some.domain.com" as the serverName to get errSecDuplicateItem.
|
||||
OSStatus AddInternetPassword(SecKeychainRef keychain,
|
||||
UInt32 serverNameLength,
|
||||
const char* serverName,
|
||||
UInt32 securityDomainLength,
|
||||
const char* securityDomain,
|
||||
UInt32 accountNameLength,
|
||||
const char* accountName,
|
||||
UInt32 pathLength,
|
||||
const char* path,
|
||||
UInt16 port,
|
||||
SecProtocolType protocol,
|
||||
SecAuthenticationType authenticationType,
|
||||
UInt32 passwordLength,
|
||||
const void* passwordData,
|
||||
SecKeychainItemRef* itemRef) const override;
|
||||
void Free(CFTypeRef ref) const override;
|
||||
|
||||
// Return the counts of objects returned by Create/Copy functions but never
|
||||
// Free'd as they should have been.
|
||||
int UnfreedSearchCount() const;
|
||||
int UnfreedKeychainItemCount() const;
|
||||
int UnfreedAttributeDataCount() const;
|
||||
|
||||
// Returns true if all items added with AddInternetPassword have a creator
|
||||
// code set.
|
||||
bool CreatorCodesSetForAddedItems() const;
|
||||
|
||||
struct KeychainTestData {
|
||||
const SecAuthenticationType auth_type;
|
||||
const char* server;
|
||||
const SecProtocolType protocol;
|
||||
const char* path;
|
||||
const UInt32 port;
|
||||
const char* security_domain;
|
||||
const char* creation_date;
|
||||
const char* username;
|
||||
const char* password;
|
||||
const bool negative_item;
|
||||
};
|
||||
// Adds a keychain item with the given info to the test set.
|
||||
void AddTestItem(const KeychainTestData& item_data);
|
||||
|
||||
void set_locked(bool locked) { locked_ = locked; }
|
||||
#endif // !defined(OS_IOS)
|
||||
|
||||
// |FindGenericPassword()| can return different results depending on user
|
||||
@ -135,109 +69,10 @@ class CRYPTO_EXPORT MockAppleKeychain : public AppleKeychain {
|
||||
// Returns the true if |AddGenericPassword()| was called.
|
||||
bool called_add_generic() const { return called_add_generic_; }
|
||||
|
||||
// Returns the value of the password set when |AddGenericPassword()| was
|
||||
// called.
|
||||
std::string add_generic_password() const { return add_generic_password_; }
|
||||
|
||||
// Returns the number of allocations - deallocations for password data.
|
||||
int password_data_count() const { return password_data_count_; }
|
||||
|
||||
private:
|
||||
// Type used for the keys in the std::map(s) and MockAppleKeychain items.
|
||||
typedef uintptr_t MockKeychainItemType;
|
||||
|
||||
// Type of the map holding the mock keychain attributes.
|
||||
typedef std::map<MockKeychainItemType, SecKeychainAttributeList>
|
||||
MockKeychainAttributesMap;
|
||||
|
||||
#if !defined(OS_IOS)
|
||||
// Returns true if the keychain already contains a password that matches the
|
||||
// attributes provided.
|
||||
bool AlreadyContainsInternetPassword(
|
||||
UInt32 serverNameLength,
|
||||
const char* serverName,
|
||||
UInt32 securityDomainLength,
|
||||
const char* securityDomain,
|
||||
UInt32 accountNameLength,
|
||||
const char* accountName,
|
||||
UInt32 pathLength,
|
||||
const char* path,
|
||||
UInt16 port,
|
||||
SecProtocolType protocol,
|
||||
SecAuthenticationType authenticationType) const;
|
||||
// Initializes storage for keychain data at |key|.
|
||||
void InitializeKeychainData(MockKeychainItemType key) const;
|
||||
// Sets the data and length of |tag| in the item-th test item.
|
||||
void SetTestDataBytes(
|
||||
MockKeychainItemType item,
|
||||
UInt32 tag,
|
||||
const void* data,
|
||||
size_t length);
|
||||
// Sets the data and length of |tag| in the item-th test item based on
|
||||
// |value|. The null-terminator will not be included; the Keychain Services
|
||||
// docs don't indicate whether it is or not, so clients should not assume
|
||||
// that it will be.
|
||||
void SetTestDataString(MockKeychainItemType item,
|
||||
UInt32 tag,
|
||||
const char* value);
|
||||
// Sets the data of the corresponding attribute of the item-th test item to
|
||||
// |value|. Assumes that the space has alread been allocated, and the length
|
||||
// set.
|
||||
void SetTestDataPort(MockKeychainItemType item, UInt32 value);
|
||||
void SetTestDataProtocol(MockKeychainItemType item, SecProtocolType value);
|
||||
void SetTestDataAuthType(MockKeychainItemType item,
|
||||
SecAuthenticationType value);
|
||||
void SetTestDataNegativeItem(MockKeychainItemType item, Boolean value);
|
||||
void SetTestDataCreator(MockKeychainItemType item, OSType value);
|
||||
// Sets the password data and length for the item-th test item.
|
||||
void SetTestDataPasswordBytes(MockKeychainItemType item,
|
||||
const void* data,
|
||||
size_t length);
|
||||
// Sets the password for the item-th test item. As with SetTestDataString,
|
||||
// the data will not be null-terminated.
|
||||
void SetTestDataPasswordString(MockKeychainItemType item, const char* value);
|
||||
|
||||
// Returns the address of the attribute in attribute_list with tag |tag|.
|
||||
static SecKeychainAttribute* AttributeWithTag(
|
||||
const SecKeychainAttributeList& attribute_list,
|
||||
UInt32 tag);
|
||||
|
||||
static const SecKeychainSearchRef kDummySearchRef;
|
||||
|
||||
// Simulates the state when the user refuses to unclock the Keychain.
|
||||
// If true, reading and modifying a password value result in errSecAuthFailed.
|
||||
bool locked_;
|
||||
|
||||
typedef struct KeychainPasswordData {
|
||||
KeychainPasswordData() : data(nullptr), length(0) {}
|
||||
void* data;
|
||||
UInt32 length;
|
||||
} KeychainPasswordData;
|
||||
|
||||
// Mutable because the MockAppleKeychain API requires its internal keychain
|
||||
// storage to be modifiable by users of this class.
|
||||
mutable MockKeychainAttributesMap keychain_attr_list_;
|
||||
mutable std::map<MockKeychainItemType,
|
||||
KeychainPasswordData> keychain_data_;
|
||||
mutable MockKeychainItemType next_item_key_;
|
||||
|
||||
// Tracks the items that should be returned in subsequent calls to
|
||||
// SearchCopyNext, based on the last call to SearchCreateFromAttributes.
|
||||
// We can't handle multiple active searches, since we don't track the search
|
||||
// ref we return, but we don't need to for our mocking.
|
||||
mutable std::vector<MockKeychainItemType> remaining_search_results_;
|
||||
|
||||
// Track copies and releases to make sure they balance. Really these should
|
||||
// be maps to track per item, but this should be good enough to catch
|
||||
// real mistakes.
|
||||
mutable int search_copy_count_;
|
||||
mutable int keychain_item_copy_count_;
|
||||
mutable int attribute_data_copy_count_;
|
||||
|
||||
// Tracks which items (by key) were added with AddInternetPassword.
|
||||
mutable std::set<MockKeychainItemType> added_via_api_;
|
||||
#endif // !defined(OS_IOS)
|
||||
|
||||
// Result code for the |FindGenericPassword()| method.
|
||||
OSStatus find_generic_result_;
|
||||
|
||||
@ -248,8 +83,7 @@ class CRYPTO_EXPORT MockAppleKeychain : public AppleKeychain {
|
||||
// and |ItemFreeContent|.
|
||||
mutable int password_data_count_;
|
||||
|
||||
// Records the password being set when |AddGenericPassword()| gets called.
|
||||
mutable std::string add_generic_password_;
|
||||
DISALLOW_COPY_AND_ASSIGN(MockAppleKeychain);
|
||||
};
|
||||
|
||||
} // namespace crypto
|
||||
|
@ -11,512 +11,15 @@
|
||||
|
||||
namespace crypto {
|
||||
|
||||
// static
|
||||
const SecKeychainSearchRef MockAppleKeychain::kDummySearchRef =
|
||||
reinterpret_cast<SecKeychainSearchRef>(1000);
|
||||
|
||||
MockAppleKeychain::MockAppleKeychain()
|
||||
: locked_(false),
|
||||
next_item_key_(0),
|
||||
search_copy_count_(0),
|
||||
keychain_item_copy_count_(0),
|
||||
attribute_data_copy_count_(0),
|
||||
find_generic_result_(noErr),
|
||||
: find_generic_result_(noErr),
|
||||
called_add_generic_(false),
|
||||
password_data_count_(0) {}
|
||||
|
||||
void MockAppleKeychain::InitializeKeychainData(MockKeychainItemType key) const {
|
||||
UInt32 tags[] = { kSecAccountItemAttr,
|
||||
kSecServerItemAttr,
|
||||
kSecPortItemAttr,
|
||||
kSecPathItemAttr,
|
||||
kSecProtocolItemAttr,
|
||||
kSecAuthenticationTypeItemAttr,
|
||||
kSecSecurityDomainItemAttr,
|
||||
kSecCreationDateItemAttr,
|
||||
kSecNegativeItemAttr,
|
||||
kSecCreatorItemAttr };
|
||||
keychain_attr_list_[key] = SecKeychainAttributeList();
|
||||
keychain_data_[key] = KeychainPasswordData();
|
||||
keychain_attr_list_[key].count = arraysize(tags);
|
||||
keychain_attr_list_[key].attr = static_cast<SecKeychainAttribute*>(
|
||||
calloc(keychain_attr_list_[key].count, sizeof(SecKeychainAttribute)));
|
||||
for (unsigned int i = 0; i < keychain_attr_list_[key].count; ++i) {
|
||||
keychain_attr_list_[key].attr[i].tag = tags[i];
|
||||
size_t data_size = 0;
|
||||
switch (tags[i]) {
|
||||
case kSecPortItemAttr:
|
||||
data_size = sizeof(UInt32);
|
||||
break;
|
||||
case kSecProtocolItemAttr:
|
||||
data_size = sizeof(SecProtocolType);
|
||||
break;
|
||||
case kSecAuthenticationTypeItemAttr:
|
||||
data_size = sizeof(SecAuthenticationType);
|
||||
break;
|
||||
case kSecNegativeItemAttr:
|
||||
data_size = sizeof(Boolean);
|
||||
break;
|
||||
case kSecCreatorItemAttr:
|
||||
data_size = sizeof(OSType);
|
||||
break;
|
||||
}
|
||||
if (data_size > 0) {
|
||||
keychain_attr_list_[key].attr[i].length = data_size;
|
||||
keychain_attr_list_[key].attr[i].data = calloc(1, data_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MockAppleKeychain::~MockAppleKeychain() {
|
||||
for (MockKeychainAttributesMap::iterator it = keychain_attr_list_.begin();
|
||||
it != keychain_attr_list_.end();
|
||||
++it) {
|
||||
for (unsigned int i = 0; i < it->second.count; ++i) {
|
||||
if (it->second.attr[i].data)
|
||||
free(it->second.attr[i].data);
|
||||
}
|
||||
free(it->second.attr);
|
||||
if (keychain_data_[it->first].data)
|
||||
free(keychain_data_[it->first].data);
|
||||
}
|
||||
keychain_attr_list_.clear();
|
||||
keychain_data_.clear();
|
||||
}
|
||||
|
||||
SecKeychainAttribute* MockAppleKeychain::AttributeWithTag(
|
||||
const SecKeychainAttributeList& attribute_list,
|
||||
UInt32 tag) {
|
||||
int attribute_index = -1;
|
||||
for (unsigned int i = 0; i < attribute_list.count; ++i) {
|
||||
if (attribute_list.attr[i].tag == tag) {
|
||||
attribute_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (attribute_index == -1) {
|
||||
NOTREACHED() << "Unsupported attribute: " << tag;
|
||||
return NULL;
|
||||
}
|
||||
return &(attribute_list.attr[attribute_index]);
|
||||
}
|
||||
|
||||
void MockAppleKeychain::SetTestDataBytes(MockKeychainItemType item,
|
||||
UInt32 tag,
|
||||
const void* data,
|
||||
size_t length) {
|
||||
SecKeychainAttribute* attribute = AttributeWithTag(keychain_attr_list_[item],
|
||||
tag);
|
||||
attribute->length = length;
|
||||
if (length > 0) {
|
||||
if (attribute->data)
|
||||
free(attribute->data);
|
||||
attribute->data = malloc(length);
|
||||
CHECK(attribute->data);
|
||||
memcpy(attribute->data, data, length);
|
||||
} else {
|
||||
attribute->data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void MockAppleKeychain::SetTestDataString(MockKeychainItemType item,
|
||||
UInt32 tag,
|
||||
const char* value) {
|
||||
SetTestDataBytes(item, tag, value, value ? strlen(value) : 0);
|
||||
}
|
||||
|
||||
void MockAppleKeychain::SetTestDataPort(MockKeychainItemType item,
|
||||
UInt32 value) {
|
||||
SecKeychainAttribute* attribute = AttributeWithTag(keychain_attr_list_[item],
|
||||
kSecPortItemAttr);
|
||||
UInt32* data = static_cast<UInt32*>(attribute->data);
|
||||
*data = value;
|
||||
}
|
||||
|
||||
void MockAppleKeychain::SetTestDataProtocol(MockKeychainItemType item,
|
||||
SecProtocolType value) {
|
||||
SecKeychainAttribute* attribute = AttributeWithTag(keychain_attr_list_[item],
|
||||
kSecProtocolItemAttr);
|
||||
SecProtocolType* data = static_cast<SecProtocolType*>(attribute->data);
|
||||
*data = value;
|
||||
}
|
||||
|
||||
void MockAppleKeychain::SetTestDataAuthType(MockKeychainItemType item,
|
||||
SecAuthenticationType value) {
|
||||
SecKeychainAttribute* attribute = AttributeWithTag(
|
||||
keychain_attr_list_[item], kSecAuthenticationTypeItemAttr);
|
||||
SecAuthenticationType* data = static_cast<SecAuthenticationType*>(
|
||||
attribute->data);
|
||||
*data = value;
|
||||
}
|
||||
|
||||
void MockAppleKeychain::SetTestDataNegativeItem(MockKeychainItemType item,
|
||||
Boolean value) {
|
||||
SecKeychainAttribute* attribute = AttributeWithTag(keychain_attr_list_[item],
|
||||
kSecNegativeItemAttr);
|
||||
Boolean* data = static_cast<Boolean*>(attribute->data);
|
||||
*data = value;
|
||||
}
|
||||
|
||||
void MockAppleKeychain::SetTestDataCreator(MockKeychainItemType item,
|
||||
OSType value) {
|
||||
SecKeychainAttribute* attribute = AttributeWithTag(keychain_attr_list_[item],
|
||||
kSecCreatorItemAttr);
|
||||
OSType* data = static_cast<OSType*>(attribute->data);
|
||||
*data = value;
|
||||
}
|
||||
|
||||
void MockAppleKeychain::SetTestDataPasswordBytes(MockKeychainItemType item,
|
||||
const void* data,
|
||||
size_t length) {
|
||||
keychain_data_[item].length = length;
|
||||
if (length > 0) {
|
||||
if (keychain_data_[item].data)
|
||||
free(keychain_data_[item].data);
|
||||
keychain_data_[item].data = malloc(length);
|
||||
memcpy(keychain_data_[item].data, data, length);
|
||||
} else {
|
||||
keychain_data_[item].data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void MockAppleKeychain::SetTestDataPasswordString(MockKeychainItemType item,
|
||||
const char* value) {
|
||||
SetTestDataPasswordBytes(item, value, value ? strlen(value) : 0);
|
||||
}
|
||||
|
||||
OSStatus MockAppleKeychain::ItemCopyAttributesAndData(
|
||||
SecKeychainItemRef itemRef,
|
||||
SecKeychainAttributeInfo* info,
|
||||
SecItemClass* itemClass,
|
||||
SecKeychainAttributeList** attrList,
|
||||
UInt32* length,
|
||||
void** outData) const {
|
||||
DCHECK(itemRef);
|
||||
MockKeychainItemType key =
|
||||
reinterpret_cast<MockKeychainItemType>(itemRef) - 1;
|
||||
if (keychain_attr_list_.find(key) == keychain_attr_list_.end())
|
||||
return errSecInvalidItemRef;
|
||||
|
||||
DCHECK(!itemClass); // itemClass not implemented in the Mock.
|
||||
if (locked_ && outData)
|
||||
return errSecAuthFailed;
|
||||
|
||||
if (attrList)
|
||||
*attrList = &(keychain_attr_list_[key]);
|
||||
if (outData) {
|
||||
*outData = keychain_data_[key].data;
|
||||
DCHECK(length);
|
||||
*length = keychain_data_[key].length;
|
||||
}
|
||||
|
||||
++attribute_data_copy_count_;
|
||||
return noErr;
|
||||
}
|
||||
|
||||
OSStatus MockAppleKeychain::ItemModifyAttributesAndData(
|
||||
SecKeychainItemRef itemRef,
|
||||
const SecKeychainAttributeList* attrList,
|
||||
UInt32 length,
|
||||
const void* data) const {
|
||||
DCHECK(itemRef);
|
||||
if (locked_)
|
||||
return errSecAuthFailed;
|
||||
const char* fail_trigger = "fail_me";
|
||||
if (length == strlen(fail_trigger) &&
|
||||
memcmp(data, fail_trigger, length) == 0) {
|
||||
return errSecAuthFailed;
|
||||
}
|
||||
|
||||
MockKeychainItemType key =
|
||||
reinterpret_cast<MockKeychainItemType>(itemRef) - 1;
|
||||
if (keychain_attr_list_.find(key) == keychain_attr_list_.end())
|
||||
return errSecInvalidItemRef;
|
||||
|
||||
MockAppleKeychain* mutable_this = const_cast<MockAppleKeychain*>(this);
|
||||
if (attrList) {
|
||||
for (UInt32 change_attr = 0; change_attr < attrList->count; ++change_attr) {
|
||||
if (attrList->attr[change_attr].tag == kSecCreatorItemAttr) {
|
||||
void* data = attrList->attr[change_attr].data;
|
||||
mutable_this->SetTestDataCreator(key, *(static_cast<OSType*>(data)));
|
||||
} else {
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data)
|
||||
mutable_this->SetTestDataPasswordBytes(key, data, length);
|
||||
return noErr;
|
||||
}
|
||||
|
||||
OSStatus MockAppleKeychain::ItemFreeAttributesAndData(
|
||||
SecKeychainAttributeList* attrList,
|
||||
void* data) const {
|
||||
--attribute_data_copy_count_;
|
||||
return noErr;
|
||||
}
|
||||
MockAppleKeychain::~MockAppleKeychain() {}
|
||||
|
||||
OSStatus MockAppleKeychain::ItemDelete(SecKeychainItemRef itemRef) const {
|
||||
if (locked_)
|
||||
return errSecAuthFailed;
|
||||
MockKeychainItemType key =
|
||||
reinterpret_cast<MockKeychainItemType>(itemRef) - 1;
|
||||
|
||||
for (unsigned int i = 0; i < keychain_attr_list_[key].count; ++i) {
|
||||
if (keychain_attr_list_[key].attr[i].data)
|
||||
free(keychain_attr_list_[key].attr[i].data);
|
||||
}
|
||||
free(keychain_attr_list_[key].attr);
|
||||
if (keychain_data_[key].data)
|
||||
free(keychain_data_[key].data);
|
||||
|
||||
keychain_attr_list_.erase(key);
|
||||
keychain_data_.erase(key);
|
||||
added_via_api_.erase(key);
|
||||
return noErr;
|
||||
}
|
||||
|
||||
OSStatus MockAppleKeychain::SearchCreateFromAttributes(
|
||||
CFTypeRef keychainOrArray,
|
||||
SecItemClass itemClass,
|
||||
const SecKeychainAttributeList* attrList,
|
||||
SecKeychainSearchRef* searchRef) const {
|
||||
// Figure out which of our mock items matches, and set up the array we'll use
|
||||
// to generate results out of SearchCopyNext.
|
||||
remaining_search_results_.clear();
|
||||
for (MockKeychainAttributesMap::const_iterator it =
|
||||
keychain_attr_list_.begin();
|
||||
it != keychain_attr_list_.end();
|
||||
++it) {
|
||||
bool mock_item_matches = true;
|
||||
for (UInt32 search_attr = 0; search_attr < attrList->count; ++search_attr) {
|
||||
SecKeychainAttribute* mock_attribute =
|
||||
AttributeWithTag(it->second, attrList->attr[search_attr].tag);
|
||||
if (mock_attribute->length != attrList->attr[search_attr].length ||
|
||||
memcmp(mock_attribute->data, attrList->attr[search_attr].data,
|
||||
attrList->attr[search_attr].length) != 0) {
|
||||
mock_item_matches = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mock_item_matches)
|
||||
remaining_search_results_.push_back(it->first);
|
||||
}
|
||||
|
||||
DCHECK(searchRef);
|
||||
*searchRef = kDummySearchRef;
|
||||
++search_copy_count_;
|
||||
return noErr;
|
||||
}
|
||||
|
||||
bool MockAppleKeychain::AlreadyContainsInternetPassword(
|
||||
UInt32 serverNameLength,
|
||||
const char* serverName,
|
||||
UInt32 securityDomainLength,
|
||||
const char* securityDomain,
|
||||
UInt32 accountNameLength,
|
||||
const char* accountName,
|
||||
UInt32 pathLength,
|
||||
const char* path,
|
||||
UInt16 port,
|
||||
SecProtocolType protocol,
|
||||
SecAuthenticationType authenticationType) const {
|
||||
for (MockKeychainAttributesMap::const_iterator it =
|
||||
keychain_attr_list_.begin();
|
||||
it != keychain_attr_list_.end();
|
||||
++it) {
|
||||
SecKeychainAttribute* attribute;
|
||||
attribute = AttributeWithTag(it->second, kSecServerItemAttr);
|
||||
if ((attribute->length != serverNameLength) ||
|
||||
(attribute->data == NULL && *serverName != '\0') ||
|
||||
(attribute->data != NULL && *serverName == '\0') ||
|
||||
strncmp(serverName,
|
||||
(const char*) attribute->data,
|
||||
serverNameLength) != 0) {
|
||||
continue;
|
||||
}
|
||||
attribute = AttributeWithTag(it->second, kSecSecurityDomainItemAttr);
|
||||
if ((attribute->length != securityDomainLength) ||
|
||||
(attribute->data == NULL && *securityDomain != '\0') ||
|
||||
(attribute->data != NULL && *securityDomain == '\0') ||
|
||||
strncmp(securityDomain,
|
||||
(const char*) attribute->data,
|
||||
securityDomainLength) != 0) {
|
||||
continue;
|
||||
}
|
||||
attribute = AttributeWithTag(it->second, kSecAccountItemAttr);
|
||||
if ((attribute->length != accountNameLength) ||
|
||||
(attribute->data == NULL && *accountName != '\0') ||
|
||||
(attribute->data != NULL && *accountName == '\0') ||
|
||||
strncmp(accountName,
|
||||
(const char*) attribute->data,
|
||||
accountNameLength) != 0) {
|
||||
continue;
|
||||
}
|
||||
attribute = AttributeWithTag(it->second, kSecPathItemAttr);
|
||||
if ((attribute->length != pathLength) ||
|
||||
(attribute->data == NULL && *path != '\0') ||
|
||||
(attribute->data != NULL && *path == '\0') ||
|
||||
strncmp(path,
|
||||
(const char*) attribute->data,
|
||||
pathLength) != 0) {
|
||||
continue;
|
||||
}
|
||||
attribute = AttributeWithTag(it->second, kSecPortItemAttr);
|
||||
if ((attribute->data == NULL) ||
|
||||
(port != *(static_cast<UInt32*>(attribute->data)))) {
|
||||
continue;
|
||||
}
|
||||
attribute = AttributeWithTag(it->second, kSecProtocolItemAttr);
|
||||
if ((attribute->data == NULL) ||
|
||||
(protocol != *(static_cast<SecProtocolType*>(attribute->data)))) {
|
||||
continue;
|
||||
}
|
||||
attribute = AttributeWithTag(it->second, kSecAuthenticationTypeItemAttr);
|
||||
if ((attribute->data == NULL) ||
|
||||
(authenticationType !=
|
||||
*(static_cast<SecAuthenticationType*>(attribute->data)))) {
|
||||
continue;
|
||||
}
|
||||
// The keychain already has this item, since all fields other than the
|
||||
// password match.
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
OSStatus MockAppleKeychain::AddInternetPassword(
|
||||
SecKeychainRef keychain,
|
||||
UInt32 serverNameLength,
|
||||
const char* serverName,
|
||||
UInt32 securityDomainLength,
|
||||
const char* securityDomain,
|
||||
UInt32 accountNameLength,
|
||||
const char* accountName,
|
||||
UInt32 pathLength,
|
||||
const char* path,
|
||||
UInt16 port,
|
||||
SecProtocolType protocol,
|
||||
SecAuthenticationType authenticationType,
|
||||
UInt32 passwordLength,
|
||||
const void* passwordData,
|
||||
SecKeychainItemRef* itemRef) const {
|
||||
if (locked_)
|
||||
return errSecAuthFailed;
|
||||
|
||||
// Check for the magic duplicate item trigger.
|
||||
if (strcmp(serverName, "some.domain.com") == 0)
|
||||
return errSecDuplicateItem;
|
||||
|
||||
// If the account already exists in the keychain, we don't add it.
|
||||
if (AlreadyContainsInternetPassword(serverNameLength, serverName,
|
||||
securityDomainLength, securityDomain,
|
||||
accountNameLength, accountName,
|
||||
pathLength, path,
|
||||
port, protocol,
|
||||
authenticationType)) {
|
||||
return errSecDuplicateItem;
|
||||
}
|
||||
|
||||
// Pick the next unused slot.
|
||||
MockKeychainItemType key = next_item_key_++;
|
||||
|
||||
// Initialize keychain data storage at the target location.
|
||||
InitializeKeychainData(key);
|
||||
|
||||
MockAppleKeychain* mutable_this = const_cast<MockAppleKeychain*>(this);
|
||||
mutable_this->SetTestDataBytes(key, kSecServerItemAttr, serverName,
|
||||
serverNameLength);
|
||||
mutable_this->SetTestDataBytes(key, kSecSecurityDomainItemAttr,
|
||||
securityDomain, securityDomainLength);
|
||||
mutable_this->SetTestDataBytes(key, kSecAccountItemAttr, accountName,
|
||||
accountNameLength);
|
||||
mutable_this->SetTestDataBytes(key, kSecPathItemAttr, path, pathLength);
|
||||
mutable_this->SetTestDataPort(key, port);
|
||||
mutable_this->SetTestDataProtocol(key, protocol);
|
||||
mutable_this->SetTestDataAuthType(key, authenticationType);
|
||||
mutable_this->SetTestDataPasswordBytes(key, passwordData,
|
||||
passwordLength);
|
||||
base::Time::Exploded exploded_time;
|
||||
base::Time::Now().UTCExplode(&exploded_time);
|
||||
char time_string[128];
|
||||
snprintf(time_string, sizeof(time_string), "%04d%02d%02d%02d%02d%02dZ",
|
||||
exploded_time.year, exploded_time.month, exploded_time.day_of_month,
|
||||
exploded_time.hour, exploded_time.minute, exploded_time.second);
|
||||
mutable_this->SetTestDataString(key, kSecCreationDateItemAttr, time_string);
|
||||
|
||||
added_via_api_.insert(key);
|
||||
|
||||
if (itemRef) {
|
||||
*itemRef = reinterpret_cast<SecKeychainItemRef>(key + 1);
|
||||
++keychain_item_copy_count_;
|
||||
}
|
||||
return noErr;
|
||||
}
|
||||
|
||||
OSStatus MockAppleKeychain::SearchCopyNext(SecKeychainSearchRef searchRef,
|
||||
SecKeychainItemRef* itemRef) const {
|
||||
if (remaining_search_results_.empty())
|
||||
return errSecItemNotFound;
|
||||
MockKeychainItemType key = remaining_search_results_.front();
|
||||
remaining_search_results_.erase(remaining_search_results_.begin());
|
||||
*itemRef = reinterpret_cast<SecKeychainItemRef>(key + 1);
|
||||
++keychain_item_copy_count_;
|
||||
return noErr;
|
||||
}
|
||||
|
||||
void MockAppleKeychain::Free(CFTypeRef ref) const {
|
||||
if (!ref)
|
||||
return;
|
||||
|
||||
if (ref == kDummySearchRef) {
|
||||
--search_copy_count_;
|
||||
} else {
|
||||
--keychain_item_copy_count_;
|
||||
}
|
||||
}
|
||||
|
||||
int MockAppleKeychain::UnfreedSearchCount() const {
|
||||
return search_copy_count_;
|
||||
}
|
||||
|
||||
int MockAppleKeychain::UnfreedKeychainItemCount() const {
|
||||
return keychain_item_copy_count_;
|
||||
}
|
||||
|
||||
int MockAppleKeychain::UnfreedAttributeDataCount() const {
|
||||
return attribute_data_copy_count_;
|
||||
}
|
||||
|
||||
bool MockAppleKeychain::CreatorCodesSetForAddedItems() const {
|
||||
for (std::set<MockKeychainItemType>::const_iterator
|
||||
i = added_via_api_.begin();
|
||||
i != added_via_api_.end();
|
||||
++i) {
|
||||
SecKeychainAttribute* attribute = AttributeWithTag(keychain_attr_list_[*i],
|
||||
kSecCreatorItemAttr);
|
||||
OSType* data = static_cast<OSType*>(attribute->data);
|
||||
if (*data == 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MockAppleKeychain::AddTestItem(const KeychainTestData& item_data) {
|
||||
MockKeychainItemType key = next_item_key_++;
|
||||
|
||||
InitializeKeychainData(key);
|
||||
SetTestDataAuthType(key, item_data.auth_type);
|
||||
SetTestDataString(key, kSecServerItemAttr, item_data.server);
|
||||
SetTestDataProtocol(key, item_data.protocol);
|
||||
SetTestDataString(key, kSecPathItemAttr, item_data.path);
|
||||
SetTestDataPort(key, item_data.port);
|
||||
SetTestDataString(key, kSecSecurityDomainItemAttr,
|
||||
item_data.security_domain);
|
||||
SetTestDataString(key, kSecCreationDateItemAttr, item_data.creation_date);
|
||||
SetTestDataString(key, kSecAccountItemAttr, item_data.username);
|
||||
SetTestDataPasswordString(key, item_data.password);
|
||||
SetTestDataNegativeItem(key, item_data.negative_item);
|
||||
}
|
||||
|
||||
} // namespace crypto
|
||||
|
Reference in New Issue
Block a user