1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
|
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_KEYCHAIN_MOCK_MAC_H_
#define CHROME_BROWSER_KEYCHAIN_MOCK_MAC_H_
#pragma once
#include <set>
#include <string>
#include <vector>
#include "chrome/browser/keychain_mac.h"
// Mock Keychain wrapper for testing code that interacts with the OS Keychain.
// The basic idea of this mock is that it has a static array of data, and
// SecKeychainItemRef values are just indexes into that array (offset by 1 to
// prevent problems with clients that null-check refs), cast to pointers.
//
// Note that "const" is pretty much meaningless for this class; the const-ness
// of MacKeychain doesn't apply to the actual keychain data, so all of the Mock
// data is mutable; don't assume that it won't change over the life of tests.
class MockKeychain : public MacKeychain {
public:
// Create a Mock Keychain capable of holding item_capacity keychain items.
explicit MockKeychain(unsigned int item_capacity);
virtual ~MockKeychain();
virtual OSStatus ItemCopyAttributesAndData(
SecKeychainItemRef itemRef, SecKeychainAttributeInfo *info,
SecItemClass *itemClass, SecKeychainAttributeList **attrList,
UInt32 *length, void **outData) const;
// Pass "fail_me" as the data to get errSecAuthFailed.
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;
// If there are unused slots in the Mock Keychain's capacity, the new item
// will use the first free one, otherwise it will stomp the last item.
// Pass "some.domain.com" as the serverName to get errSecDuplicateItem.
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;
virtual OSStatus FindGenericPassword(CFTypeRef keychainOrArray,
UInt32 serviceNameLength,
const char *serviceName,
UInt32 accountNameLength,
const char *accountName,
UInt32 *passwordLength,
void **passwordData,
SecKeychainItemRef *itemRef) const;
virtual OSStatus ItemFreeContent(SecKeychainAttributeList *attrList,
void *data) const;
virtual OSStatus AddGenericPassword(SecKeychainRef keychain,
UInt32 serviceNameLength,
const char *serviceName,
UInt32 accountNameLength,
const char *accountName,
UInt32 passwordLength,
const void *passwordData,
SecKeychainItemRef *itemRef) const;
virtual void Free(CFTypeRef ref) const;
// 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);
// |FindGenericPassword()| can return different results depending on user
// interaction with the system Keychain. For mocking purposes we allow the
// user of this class to specify the result code of the
// |FindGenericPassword()| call so we can simulate the result of different
// user interactions.
void set_find_generic_result(OSStatus result) {
find_generic_result_ = result;
}
// 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:
// Sets the data and length of |tag| in the item-th test item.
void SetTestDataBytes(int 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(int 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(int item, UInt32 value);
void SetTestDataProtocol(int item, SecProtocolType value);
void SetTestDataAuthType(int item, SecAuthenticationType value);
void SetTestDataNegativeItem(int item, Boolean value);
void SetTestDataCreator(int item, OSType value);
// Sets the password data and length for the item-th test item.
void SetTestDataPasswordBytes(int 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(int 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 int kDummySearchRef = 1000;
typedef struct {
void* data;
UInt32 length;
} KeychainPasswordData;
SecKeychainAttributeList* keychain_attr_list_;
KeychainPasswordData* keychain_data_;
unsigned int item_capacity_;
mutable unsigned int item_count_;
// 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<unsigned int> 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 index) were added with AddInternetPassword.
mutable std::set<unsigned int> added_via_api_;
// Result code for the |FindGenericPassword()| method.
OSStatus find_generic_result_;
// Records whether |AddGenericPassword()| gets called.
mutable bool called_add_generic_;
// Tracks the allocations and frees of password data in |FindGenericPassword|
// and |ItemFreeContent|.
mutable unsigned int password_data_count_;
// Records the password being set when |AddGenericPassword()| gets called.
mutable std::string add_generic_password_;
};
#endif // CHROME_BROWSER_KEYCHAIN_MOCK_MAC_H_
|