OLD | NEW |
(Empty) | |
| 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. |
| 4 |
| 5 #ifndef CRYPTO_MOCK_KEYCHAIN_MAC_H_ |
| 6 #define CRYPTO_MOCK_KEYCHAIN_MAC_H_ |
| 7 |
| 8 #include <stdint.h> |
| 9 |
| 10 #include <map> |
| 11 #include <set> |
| 12 #include <string> |
| 13 #include <vector> |
| 14 |
| 15 #include "base/compiler_specific.h" |
| 16 #include "crypto/apple_keychain.h" |
| 17 |
| 18 namespace crypto { |
| 19 |
| 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. |
| 24 // |
| 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 |
| 28 // tests. |
| 29 class CRYPTO_EXPORT MockAppleKeychain : public AppleKeychain { |
| 30 public: |
| 31 MockAppleKeychain(); |
| 32 ~MockAppleKeychain() override; |
| 33 |
| 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, |
| 41 void** passwordData, |
| 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; |
| 53 |
| 54 // Returns the password that OSCrypt uses to generate its encryption key. |
| 55 std::string GetEncryptionPassword() const; |
| 56 |
| 57 #if !defined(OS_IOS) |
| 58 OSStatus ItemCopyAttributesAndData(SecKeychainItemRef itemRef, |
| 59 SecKeychainAttributeInfo* info, |
| 60 SecItemClass* itemClass, |
| 61 SecKeychainAttributeList** attrList, |
| 62 UInt32* length, |
| 63 void** outData) const override; |
| 64 // Pass "fail_me" as the data to get errSecAuthFailed. |
| 65 OSStatus ItemModifyAttributesAndData(SecKeychainItemRef itemRef, |
| 66 const SecKeychainAttributeList* attrList, |
| 67 UInt32 length, |
| 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, |
| 87 UInt32 pathLength, |
| 88 const char* path, |
| 89 UInt16 port, |
| 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; |
| 96 |
| 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; |
| 102 |
| 103 // Returns true if all items added with AddInternetPassword have a creator |
| 104 // code set. |
| 105 bool CreatorCodesSetForAddedItems() const; |
| 106 |
| 107 struct KeychainTestData { |
| 108 const SecAuthenticationType auth_type; |
| 109 const char* server; |
| 110 const SecProtocolType protocol; |
| 111 const char* path; |
| 112 const UInt32 port; |
| 113 const char* security_domain; |
| 114 const char* creation_date; |
| 115 const char* username; |
| 116 const char* password; |
| 117 const bool negative_item; |
| 118 }; |
| 119 // Adds a keychain item with the given info to the test set. |
| 120 void AddTestItem(const KeychainTestData& item_data); |
| 121 |
| 122 void set_locked(bool locked) { locked_ = locked; } |
| 123 #endif // !defined(OS_IOS) |
| 124 |
| 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; |
| 132 } |
| 133 |
| 134 // Returns the true if |AddGenericPassword()| was called. |
| 135 bool called_add_generic() const { return called_add_generic_; } |
| 136 |
| 137 // Returns the value of the password set when |AddGenericPassword()| was |
| 138 // called. |
| 139 std::string add_generic_password() const { return add_generic_password_; } |
| 140 |
| 141 // Returns the number of allocations - deallocations for password data. |
| 142 int password_data_count() const { return password_data_count_; } |
| 143 |
| 144 private: |
| 145 // Type used for the keys in the std::map(s) and MockAppleKeychain items. |
| 146 typedef uintptr_t MockKeychainItemType; |
| 147 |
| 148 // Type of the map holding the mock keychain attributes. |
| 149 typedef std::map<MockKeychainItemType, SecKeychainAttributeList> |
| 150 MockKeychainAttributesMap; |
| 151 |
| 152 #if !defined(OS_IOS) |
| 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, |
| 162 UInt32 pathLength, |
| 163 const char* path, |
| 164 UInt16 port, |
| 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, |
| 172 UInt32 tag, |
| 173 const void* data, |
| 174 size_t length); |
| 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 |
| 178 // that it will be. |
| 179 void SetTestDataString(MockKeychainItemType item, |
| 180 UInt32 tag, |
| 181 const char* value); |
| 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 |
| 184 // set. |
| 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, |
| 193 const void* data, |
| 194 size_t length); |
| 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); |
| 198 |
| 199 // Returns the address of the attribute in attribute_list with tag |tag|. |
| 200 static SecKeychainAttribute* AttributeWithTag( |
| 201 const SecKeychainAttributeList& attribute_list, |
| 202 UInt32 tag); |
| 203 |
| 204 static const SecKeychainSearchRef kDummySearchRef; |
| 205 |
| 206 // Simulates the state when the user refuses to unclock the Keychain. |
| 207 // If true, reading and modifying a password value result in errSecAuthFailed. |
| 208 bool locked_; |
| 209 |
| 210 typedef struct KeychainPasswordData { |
| 211 KeychainPasswordData() : data(NULL), length(0) {} |
| 212 void* data; |
| 213 UInt32 length; |
| 214 } KeychainPasswordData; |
| 215 |
| 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_; |
| 222 |
| 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_; |
| 228 |
| 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 |
| 231 // real mistakes. |
| 232 mutable int search_copy_count_; |
| 233 mutable int keychain_item_copy_count_; |
| 234 mutable int attribute_data_copy_count_; |
| 235 |
| 236 // Tracks which items (by key) were added with AddInternetPassword. |
| 237 mutable std::set<MockKeychainItemType> added_via_api_; |
| 238 #endif // !defined(OS_IOS) |
| 239 |
| 240 // Result code for the |FindGenericPassword()| method. |
| 241 OSStatus find_generic_result_; |
| 242 |
| 243 // Records whether |AddGenericPassword()| gets called. |
| 244 mutable bool called_add_generic_; |
| 245 |
| 246 // Tracks the allocations and frees of password data in |FindGenericPassword| |
| 247 // and |ItemFreeContent|. |
| 248 mutable int password_data_count_; |
| 249 |
| 250 // Records the password being set when |AddGenericPassword()| gets called. |
| 251 mutable std::string add_generic_password_; |
| 252 }; |
| 253 |
| 254 } // namespace crypto |
| 255 |
| 256 #endif // CRYPTO_MOCK_KEYCHAIN_MAC_H_ |
OLD | NEW |