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 #include "crypto/apple_keychain.h" | |
6 | |
7 #import <Foundation/Foundation.h> | |
8 | |
9 #include "base/mac/foundation_util.h" | |
10 #include "base/mac/scoped_cftyperef.h" | |
11 #include "base/memory/scoped_nsobject.h" | |
12 | |
13 namespace { | |
14 | |
15 enum KeychainAction { | |
16 kKeychainActionCreate, | |
17 kKeychainActionUpdate | |
Ryan Sleevi
2012/08/23 22:22:58
nit: indent two spaces.
msarda
2012/08/27 14:24:07
Done.
| |
18 }; | |
19 | |
20 // Creates a dictionary that can be used to query the keystore. | |
21 // Ownership follows the Create rule. | |
22 CFDictionaryRef CreateGenericPasswordQuery(UInt32 serviceNameLength, | |
23 const char* serviceName, | |
24 UInt32 accountNameLength, | |
25 const char* accountName) { | |
26 CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 5, | |
27 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
Ryan Sleevi
2012/08/23 22:22:58
super minor tiny nit:
Because of the second param
msarda
2012/08/27 14:24:07
It does not fit (line has 81 characters). I have r
| |
28 // Type of element is generic password. | |
29 CFDictionarySetValue(query, kSecClass, kSecClassGenericPassword); | |
30 | |
31 // Set the service name. | |
32 scoped_nsobject<NSString> service_name_ns( | |
33 [[NSString alloc] initWithBytes:serviceName | |
34 length:serviceNameLength | |
35 encoding:NSUTF8StringEncoding]); | |
36 CFDictionarySetValue(query, kSecAttrService, service_name_ns); | |
37 | |
38 // Set the account name. | |
39 scoped_nsobject<NSString> account_name_ns( | |
40 [[NSString alloc] initWithBytes:accountName | |
41 length:accountNameLength | |
42 encoding:NSUTF8StringEncoding]); | |
43 CFDictionarySetValue(query, kSecAttrAccount, account_name_ns); | |
44 | |
45 // Use the proper search constants, return only the data of the first match. | |
46 CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitOne); | |
47 CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue); | |
48 return query; | |
49 } | |
50 | |
51 // Creates a dictionary conatining the data to save into the keychain. | |
52 // Ownership follows the Create rule. | |
53 CFDictionaryRef CreateKeychainData(UInt32 serviceNameLength, | |
54 const char* serviceName, | |
55 UInt32 accountNameLength, | |
56 const char* accountName, | |
57 UInt32 passwordLength, | |
58 const void* passwordData, | |
59 KeychainAction action) { | |
60 CFMutableDictionaryRef keychain_data = CFDictionaryCreateMutable(NULL, 0, | |
61 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
62 | |
63 // Set the password. | |
64 NSData* password = [NSData dataWithBytes:passwordData length:passwordLength]; | |
65 CFDictionarySetValue(keychain_data, kSecValueData, password); | |
66 | |
67 // If this is a creation, the structural information must be defined. | |
68 if (action == kKeychainActionCreate) { | |
69 // Set the type of the data. | |
70 CFDictionarySetValue(keychain_data, kSecClass, kSecClassGenericPassword); | |
71 | |
72 // Only allow access when the device has been unlocked. | |
73 CFDictionarySetValue(keychain_data, | |
74 kSecAttrAccessible, | |
75 kSecAttrAccessibleWhenUnlocked); | |
76 | |
77 // Set the service name. | |
78 scoped_nsobject<NSString> service_name_ns( | |
79 [[NSString alloc] initWithBytes:serviceName | |
80 length:serviceNameLength | |
81 encoding:NSUTF8StringEncoding]); | |
82 CFDictionarySetValue(keychain_data, kSecAttrService, service_name_ns); | |
83 | |
84 // Set the account name. | |
85 scoped_nsobject<NSString> account_name_ns( | |
86 [[NSString alloc] initWithBytes:accountName | |
87 length:accountNameLength | |
88 encoding:NSUTF8StringEncoding]); | |
89 CFDictionarySetValue(keychain_data, kSecAttrAccount, account_name_ns); | |
90 } | |
91 | |
92 return keychain_data; | |
93 } | |
94 | |
95 } // namespace | |
96 | |
97 namespace crypto { | |
98 | |
99 AppleKeychain::AppleKeychain() {} | |
100 | |
101 AppleKeychain::~AppleKeychain() {} | |
102 | |
103 OSStatus AppleKeychain::ItemFreeContent(SecKeychainAttributeList* attrList, | |
104 void* data) const { | |
105 free(data); | |
Ryan Sleevi
2012/08/23 22:22:58
nit?
if (data)
free(data)
stuartmorgan
2012/08/24 06:56:03
free is NULL-safe.
msarda
2012/08/27 14:24:07
Kept as is following on Stuart's comment.
On 2012
| |
106 return noErr; | |
107 } | |
108 | |
109 OSStatus AppleKeychain::AddGenericPassword(SecKeychainRef keychain, | |
110 UInt32 serviceNameLength, | |
111 const char* serviceName, | |
112 UInt32 accountNameLength, | |
113 const char* accountName, | |
114 UInt32 passwordLength, | |
115 const void* passwordData, | |
116 SecKeychainItemRef* itemRef) const { | |
117 base::mac::ScopedCFTypeRef<CFDictionaryRef> query( | |
118 CreateGenericPasswordQuery(serviceNameLength, | |
119 serviceName, | |
120 accountNameLength, | |
121 accountName)); | |
122 // Check that there is not already a password. | |
123 OSStatus status = SecItemCopyMatching((CFDictionaryRef)query, NULL); | |
124 if (status == errSecItemNotFound) { | |
125 // A new entry must be created. | |
126 base::mac::ScopedCFTypeRef<CFDictionaryRef> keychain_data( | |
127 CreateKeychainData(serviceNameLength, | |
128 serviceName, | |
129 accountNameLength, | |
130 accountName, | |
131 passwordLength, | |
132 passwordData, | |
133 kKeychainActionCreate)); | |
134 status = SecItemAdd(keychain_data, NULL); | |
135 } else if (status == noErr) { | |
136 // The entry must be updated. | |
137 base::mac::ScopedCFTypeRef<CFDictionaryRef> keychain_data( | |
138 CreateKeychainData(serviceNameLength, | |
139 serviceName, | |
140 accountNameLength, | |
141 accountName, | |
142 passwordLength, | |
143 passwordData, | |
144 kKeychainActionUpdate)); | |
145 status = SecItemUpdate(query, keychain_data); | |
146 } | |
147 | |
148 return status; | |
149 } | |
150 | |
151 OSStatus AppleKeychain::FindGenericPassword(CFTypeRef keychainOrArray, | |
152 UInt32 serviceNameLength, | |
153 const char* serviceName, | |
154 UInt32 accountNameLength, | |
155 const char* accountName, | |
156 UInt32* passwordLength, | |
157 void** passwordData, | |
158 SecKeychainItemRef* itemRef) const { | |
159 base::mac::ScopedCFTypeRef<CFDictionaryRef> query( | |
160 CreateGenericPasswordQuery(serviceNameLength, | |
161 serviceName, | |
162 accountNameLength, | |
163 accountName)); | |
164 | |
165 CFTypeRef result = NULL; | |
166 OSStatus status = SecItemCopyMatching(query, &result); | |
167 if (status == noErr) { | |
168 NSData* data = base::mac::CFToNSCast(base::mac::CFCast<CFDataRef>(result)); | |
169 NSUInteger length = [data length]; | |
170 *passwordData = malloc(length); | |
Ryan Sleevi
2012/08/23 22:22:58
nit: Should you make sure to set *passwordData = N
stuartmorgan
2012/08/24 06:56:03
The docs for the function this mimics doesn't say,
msarda
2012/08/27 14:24:07
Done.
| |
171 [data getBytes:*passwordData length:length]; | |
172 *passwordLength = length; | |
173 CFRelease(result); | |
174 } | |
175 return status; | |
176 } | |
177 | |
178 } // namespace crypto | |
OLD | NEW |