1 // Copyright (c) 2009 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 CHROME_BROWSER_KEYCHAIN_MOCK_MAC_H_ 6 #define CHROME_BROWSER_KEYCHAIN_MOCK_MAC_H_ 7 #pragma once 8 9 #include <set> 10 #include <string> 11 #include <vector> 12 13 #include "chrome/browser/keychain_mac.h" 14 15 // Mock Keychain wrapper for testing code that interacts with the OS Keychain. 16 // The basic idea of this mock is that it has a static array of data, and 17 // SecKeychainItemRef values are just indexes into that array (offset by 1 to 18 // prevent problems with clients that null-check refs), cast to pointers. 19 // 20 // Note that "const" is pretty much meaningless for this class; the const-ness 21 // of MacKeychain doesn't apply to the actual keychain data, so all of the Mock 22 // data is mutable; don't assume that it won't change over the life of tests. 23 class MockKeychain : public MacKeychain { 24 public: 25 // Create a Mock Keychain capable of holding item_capacity keychain items. 26 explicit MockKeychain(unsigned int item_capacity); 27 virtual ~MockKeychain(); 28 virtual OSStatus ItemCopyAttributesAndData( 29 SecKeychainItemRef itemRef, SecKeychainAttributeInfo *info, 30 SecItemClass *itemClass, SecKeychainAttributeList **attrList, 31 UInt32 *length, void **outData) const; 32 // Pass "fail_me" as the data to get errSecAuthFailed. 33 virtual OSStatus ItemModifyAttributesAndData( 34 SecKeychainItemRef itemRef, const SecKeychainAttributeList *attrList, 35 UInt32 length, const void *data) const; 36 virtual OSStatus ItemFreeAttributesAndData(SecKeychainAttributeList *attrList, 37 void *data) const; 38 virtual OSStatus ItemDelete(SecKeychainItemRef itemRef) const; 39 virtual OSStatus SearchCreateFromAttributes( 40 CFTypeRef keychainOrArray, SecItemClass itemClass, 41 const SecKeychainAttributeList *attrList, 42 SecKeychainSearchRef *searchRef) const; 43 virtual OSStatus SearchCopyNext(SecKeychainSearchRef searchRef, 44 SecKeychainItemRef *itemRef) const; 45 // If there are unused slots in the Mock Keychain's capacity, the new item 46 // will use the first free one, otherwise it will stomp the last item. 47 // Pass "some.domain.com" as the serverName to get errSecDuplicateItem. 48 virtual OSStatus AddInternetPassword(SecKeychainRef keychain, 49 UInt32 serverNameLength, 50 const char *serverName, 51 UInt32 securityDomainLength, 52 const char *securityDomain, 53 UInt32 accountNameLength, 54 const char *accountName, 55 UInt32 pathLength, const char *path, 56 UInt16 port, SecProtocolType protocol, 57 SecAuthenticationType authenticationType, 58 UInt32 passwordLength, 59 const void *passwordData, 60 SecKeychainItemRef *itemRef) const; 61 virtual OSStatus FindGenericPassword(CFTypeRef keychainOrArray, 62 UInt32 serviceNameLength, 63 const char *serviceName, 64 UInt32 accountNameLength, 65 const char *accountName, 66 UInt32 *passwordLength, 67 void **passwordData, 68 SecKeychainItemRef *itemRef) const; 69 virtual OSStatus ItemFreeContent(SecKeychainAttributeList *attrList, 70 void *data) const; 71 virtual OSStatus AddGenericPassword(SecKeychainRef keychain, 72 UInt32 serviceNameLength, 73 const char *serviceName, 74 UInt32 accountNameLength, 75 const char *accountName, 76 UInt32 passwordLength, 77 const void *passwordData, 78 SecKeychainItemRef *itemRef) const; 79 virtual void Free(CFTypeRef ref) const; 80 81 // Return the counts of objects returned by Create/Copy functions but never 82 // Free'd as they should have been. 83 int UnfreedSearchCount() const; 84 int UnfreedKeychainItemCount() const; 85 int UnfreedAttributeDataCount() const; 86 87 // Returns true if all items added with AddInternetPassword have a creator 88 // code set. 89 bool CreatorCodesSetForAddedItems() const; 90 91 struct KeychainTestData { 92 const SecAuthenticationType auth_type; 93 const char* server; 94 const SecProtocolType protocol; 95 const char* path; 96 const UInt32 port; 97 const char* security_domain; 98 const char* creation_date; 99 const char* username; 100 const char* password; 101 const bool negative_item; 102 }; 103 // Adds a keychain item with the given info to the test set. 104 void AddTestItem(const KeychainTestData& item_data); 105 106 // |FindGenericPassword()| can return different results depending on user 107 // interaction with the system Keychain. For mocking purposes we allow the 108 // user of this class to specify the result code of the 109 // |FindGenericPassword()| call so we can simulate the result of different 110 // user interactions. 111 void set_find_generic_result(OSStatus result) { 112 find_generic_result_ = result; 113 } 114 115 // Returns the true if |AddGenericPassword()| was called. 116 bool called_add_generic() const { return called_add_generic_; } 117 118 // Returns the value of the password set when |AddGenericPassword()| was 119 // called. 120 std::string add_generic_password() const { return add_generic_password_; } 121 122 // Returns the number of allocations - deallocations for password data. 123 int password_data_count() const { return password_data_count_; } 124 125 private: 126 // Sets the data and length of |tag| in the item-th test item. 127 void SetTestDataBytes(int item, UInt32 tag, const void* data, size_t length); 128 // Sets the data and length of |tag| in the item-th test item based on 129 // |value|. The null-terminator will not be included; the Keychain Services 130 // docs don't indicate whether it is or not, so clients should not assume 131 // that it will be. 132 void SetTestDataString(int item, UInt32 tag, const char* value); 133 // Sets the data of the corresponding attribute of the item-th test item to 134 // |value|. Assumes that the space has alread been allocated, and the length 135 // set. 136 void SetTestDataPort(int item, UInt32 value); 137 void SetTestDataProtocol(int item, SecProtocolType value); 138 void SetTestDataAuthType(int item, SecAuthenticationType value); 139 void SetTestDataNegativeItem(int item, Boolean value); 140 void SetTestDataCreator(int item, OSType value); 141 // Sets the password data and length for the item-th test item. 142 void SetTestDataPasswordBytes(int item, const void* data, size_t length); 143 // Sets the password for the item-th test item. As with SetTestDataString, 144 // the data will not be null-terminated. 145 void SetTestDataPasswordString(int item, const char* value); 146 147 // Returns the address of the attribute in attribute_list with tag |tag|. 148 static SecKeychainAttribute* AttributeWithTag( 149 const SecKeychainAttributeList& attribute_list, UInt32 tag); 150 151 static const int kDummySearchRef = 1000; 152 153 typedef struct { 154 void* data; 155 UInt32 length; 156 } KeychainPasswordData; 157 158 SecKeychainAttributeList* keychain_attr_list_; 159 KeychainPasswordData* keychain_data_; 160 unsigned int item_capacity_; 161 mutable unsigned int item_count_; 162 163 // Tracks the items that should be returned in subsequent calls to 164 // SearchCopyNext, based on the last call to SearchCreateFromAttributes. 165 // We can't handle multiple active searches, since we don't track the search 166 // ref we return, but we don't need to for our mocking. 167 mutable std::vector<unsigned int> remaining_search_results_; 168 169 // Track copies and releases to make sure they balance. Really these should 170 // be maps to track per item, but this should be good enough to catch 171 // real mistakes. 172 mutable int search_copy_count_; 173 mutable int keychain_item_copy_count_; 174 mutable int attribute_data_copy_count_; 175 176 // Tracks which items (by index) were added with AddInternetPassword. 177 mutable std::set<unsigned int> added_via_api_; 178 179 // Result code for the |FindGenericPassword()| method. 180 OSStatus find_generic_result_; 181 182 // Records whether |AddGenericPassword()| gets called. 183 mutable bool called_add_generic_; 184 185 // Tracks the allocations and frees of password data in |FindGenericPassword| 186 // and |ItemFreeContent|. 187 mutable unsigned int password_data_count_; 188 189 // Records the password being set when |AddGenericPassword()| gets called. 190 mutable std::string add_generic_password_; 191 }; 192 193 #endif // CHROME_BROWSER_KEYCHAIN_MOCK_MAC_H_ 194