1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef CRYPTO_MOCK_KEYCHAIN_MAC_H_
6 #define CRYPTO_MOCK_KEYCHAIN_MAC_H_
15 #include "base/compiler_specific.h"
16 #include "crypto/apple_keychain.h"
20 // Mock Keychain wrapper for testing code that interacts with the OS X
21 // Keychain. Implemented by storing SecKeychainAttributeList and
22 // KeychainPasswordData values in separate mutable containers and
23 // mapping them to integer keys.
25 // Note that "const" is pretty much meaningless for this class; the const-ness
26 // of AppleKeychain doesn't apply to the actual keychain data, so all of the
27 // Mock data is mutable; don't assume that it won't change over the life of
29 class CRYPTO_EXPORT MockAppleKeychain
: public AppleKeychain
{
32 ~MockAppleKeychain() override
;
34 // AppleKeychain implementation.
35 OSStatus
FindGenericPassword(CFTypeRef keychainOrArray
,
36 UInt32 serviceNameLength
,
37 const char* serviceName
,
38 UInt32 accountNameLength
,
39 const char* accountName
,
40 UInt32
* passwordLength
,
42 SecKeychainItemRef
* itemRef
) const override
;
43 OSStatus
ItemFreeContent(SecKeychainAttributeList
* attrList
,
44 void* data
) const override
;
45 OSStatus
AddGenericPassword(SecKeychainRef keychain
,
46 UInt32 serviceNameLength
,
47 const char* serviceName
,
48 UInt32 accountNameLength
,
49 const char* accountName
,
50 UInt32 passwordLength
,
51 const void* passwordData
,
52 SecKeychainItemRef
* itemRef
) const override
;
54 // Returns the password that OSCrypt uses to generate its encryption key.
55 std::string
GetEncryptionPassword() const;
58 OSStatus
ItemCopyAttributesAndData(SecKeychainItemRef itemRef
,
59 SecKeychainAttributeInfo
* info
,
60 SecItemClass
* itemClass
,
61 SecKeychainAttributeList
** attrList
,
63 void** outData
) const override
;
64 // Pass "fail_me" as the data to get errSecAuthFailed.
65 OSStatus
ItemModifyAttributesAndData(SecKeychainItemRef itemRef
,
66 const SecKeychainAttributeList
* attrList
,
68 const void* data
) const override
;
69 OSStatus
ItemFreeAttributesAndData(SecKeychainAttributeList
* attrList
,
70 void* data
) const override
;
71 OSStatus
ItemDelete(SecKeychainItemRef itemRef
) const override
;
72 OSStatus
SearchCreateFromAttributes(
73 CFTypeRef keychainOrArray
,
74 SecItemClass itemClass
,
75 const SecKeychainAttributeList
* attrList
,
76 SecKeychainSearchRef
* searchRef
) const override
;
77 OSStatus
SearchCopyNext(SecKeychainSearchRef searchRef
,
78 SecKeychainItemRef
* itemRef
) const override
;
79 // Pass "some.domain.com" as the serverName to get errSecDuplicateItem.
80 OSStatus
AddInternetPassword(SecKeychainRef keychain
,
81 UInt32 serverNameLength
,
82 const char* serverName
,
83 UInt32 securityDomainLength
,
84 const char* securityDomain
,
85 UInt32 accountNameLength
,
86 const char* accountName
,
90 SecProtocolType protocol
,
91 SecAuthenticationType authenticationType
,
92 UInt32 passwordLength
,
93 const void* passwordData
,
94 SecKeychainItemRef
* itemRef
) const override
;
95 void Free(CFTypeRef ref
) const override
;
97 // Return the counts of objects returned by Create/Copy functions but never
98 // Free'd as they should have been.
99 int UnfreedSearchCount() const;
100 int UnfreedKeychainItemCount() const;
101 int UnfreedAttributeDataCount() const;
103 // Returns true if all items added with AddInternetPassword have a creator
105 bool CreatorCodesSetForAddedItems() const;
107 struct KeychainTestData
{
108 const SecAuthenticationType auth_type
;
110 const SecProtocolType protocol
;
113 const char* security_domain
;
114 const char* creation_date
;
115 const char* username
;
116 const char* password
;
117 const bool negative_item
;
119 // Adds a keychain item with the given info to the test set.
120 void AddTestItem(const KeychainTestData
& item_data
);
122 void set_locked(bool locked
) { locked_
= locked
; }
123 #endif // !defined(OS_IOS)
125 // |FindGenericPassword()| can return different results depending on user
126 // interaction with the system Keychain. For mocking purposes we allow the
127 // user of this class to specify the result code of the
128 // |FindGenericPassword()| call so we can simulate the result of different
129 // user interactions.
130 void set_find_generic_result(OSStatus result
) {
131 find_generic_result_
= result
;
134 // Returns the true if |AddGenericPassword()| was called.
135 bool called_add_generic() const { return called_add_generic_
; }
137 // Returns the value of the password set when |AddGenericPassword()| was
139 std::string
add_generic_password() const { return add_generic_password_
; }
141 // Returns the number of allocations - deallocations for password data.
142 int password_data_count() const { return password_data_count_
; }
145 // Type used for the keys in the std::map(s) and MockAppleKeychain items.
146 typedef uintptr_t MockKeychainItemType
;
148 // Type of the map holding the mock keychain attributes.
149 typedef std::map
<MockKeychainItemType
, SecKeychainAttributeList
>
150 MockKeychainAttributesMap
;
153 // Returns true if the keychain already contains a password that matches the
154 // attributes provided.
155 bool AlreadyContainsInternetPassword(
156 UInt32 serverNameLength
,
157 const char* serverName
,
158 UInt32 securityDomainLength
,
159 const char* securityDomain
,
160 UInt32 accountNameLength
,
161 const char* accountName
,
165 SecProtocolType protocol
,
166 SecAuthenticationType authenticationType
) const;
167 // Initializes storage for keychain data at |key|.
168 void InitializeKeychainData(MockKeychainItemType key
) const;
169 // Sets the data and length of |tag| in the item-th test item.
170 void SetTestDataBytes(
171 MockKeychainItemType item
,
175 // Sets the data and length of |tag| in the item-th test item based on
176 // |value|. The null-terminator will not be included; the Keychain Services
177 // docs don't indicate whether it is or not, so clients should not assume
179 void SetTestDataString(MockKeychainItemType item
,
182 // Sets the data of the corresponding attribute of the item-th test item to
183 // |value|. Assumes that the space has alread been allocated, and the length
185 void SetTestDataPort(MockKeychainItemType item
, UInt32 value
);
186 void SetTestDataProtocol(MockKeychainItemType item
, SecProtocolType value
);
187 void SetTestDataAuthType(MockKeychainItemType item
,
188 SecAuthenticationType value
);
189 void SetTestDataNegativeItem(MockKeychainItemType item
, Boolean value
);
190 void SetTestDataCreator(MockKeychainItemType item
, OSType value
);
191 // Sets the password data and length for the item-th test item.
192 void SetTestDataPasswordBytes(MockKeychainItemType item
,
195 // Sets the password for the item-th test item. As with SetTestDataString,
196 // the data will not be null-terminated.
197 void SetTestDataPasswordString(MockKeychainItemType item
, const char* value
);
199 // Returns the address of the attribute in attribute_list with tag |tag|.
200 static SecKeychainAttribute
* AttributeWithTag(
201 const SecKeychainAttributeList
& attribute_list
,
204 static const SecKeychainSearchRef kDummySearchRef
;
206 // Simulates the state when the user refuses to unclock the Keychain.
207 // If true, reading and modifying a password value result in errSecAuthFailed.
210 typedef struct KeychainPasswordData
{
211 KeychainPasswordData() : data(NULL
), length(0) {}
214 } KeychainPasswordData
;
216 // Mutable because the MockAppleKeychain API requires its internal keychain
217 // storage to be modifiable by users of this class.
218 mutable MockKeychainAttributesMap keychain_attr_list_
;
219 mutable std::map
<MockKeychainItemType
,
220 KeychainPasswordData
> keychain_data_
;
221 mutable MockKeychainItemType next_item_key_
;
223 // Tracks the items that should be returned in subsequent calls to
224 // SearchCopyNext, based on the last call to SearchCreateFromAttributes.
225 // We can't handle multiple active searches, since we don't track the search
226 // ref we return, but we don't need to for our mocking.
227 mutable std::vector
<MockKeychainItemType
> remaining_search_results_
;
229 // Track copies and releases to make sure they balance. Really these should
230 // be maps to track per item, but this should be good enough to catch
232 mutable int search_copy_count_
;
233 mutable int keychain_item_copy_count_
;
234 mutable int attribute_data_copy_count_
;
236 // Tracks which items (by key) were added with AddInternetPassword.
237 mutable std::set
<MockKeychainItemType
> added_via_api_
;
238 #endif // !defined(OS_IOS)
240 // Result code for the |FindGenericPassword()| method.
241 OSStatus find_generic_result_
;
243 // Records whether |AddGenericPassword()| gets called.
244 mutable bool called_add_generic_
;
246 // Tracks the allocations and frees of password data in |FindGenericPassword|
247 // and |ItemFreeContent|.
248 mutable int password_data_count_
;
250 // Records the password being set when |AddGenericPassword()| gets called.
251 mutable std::string add_generic_password_
;
254 } // namespace crypto
256 #endif // CRYPTO_MOCK_KEYCHAIN_MAC_H_