• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
set_find_generic_result(OSStatus result)111   void set_find_generic_result(OSStatus result) {
112     find_generic_result_ = result;
113   }
114 
115   // Returns the true if |AddGenericPassword()| was called.
called_add_generic()116   bool called_add_generic() const { return called_add_generic_; }
117 
118   // Returns the value of the password set when |AddGenericPassword()| was
119   // called.
add_generic_password()120   std::string add_generic_password() const { return add_generic_password_; }
121 
122   // Returns the number of allocations - deallocations for password data.
password_data_count()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