OLD | NEW |
| (Empty) |
1 // Copyright 2017 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 #if !defined(__has_feature) || !__has_feature(objc_arc) | |
6 #error "This file requires ARC support." | |
7 #endif | |
8 | |
9 #import "remoting/client/ios/keychain_wrapper.h" | |
10 | |
11 #import "remoting/client/ios/domain/host_info.h" | |
12 | |
13 static const UInt8 kKeychainItemIdentifier[] = "org.chromium.RemoteDesktop\0"; | |
14 | |
15 @interface KeychainWrapper () { | |
16 NSMutableDictionary* _keychainData; | |
17 NSMutableDictionary* _userInfoQuery; | |
18 } | |
19 @end | |
20 | |
21 @implementation KeychainWrapper | |
22 | |
23 - (id)init { | |
24 if ((self = [super init])) { | |
25 OSStatus keychainErr = noErr; | |
26 _userInfoQuery = [[NSMutableDictionary alloc] init]; | |
27 [_userInfoQuery setObject:(__bridge id)kSecClassGenericPassword | |
28 forKey:(__bridge id)kSecClass]; | |
29 NSData* keychainItemID = | |
30 [NSData dataWithBytes:kKeychainItemIdentifier | |
31 length:strlen((const char*)kKeychainItemIdentifier)]; | |
32 [_userInfoQuery setObject:keychainItemID | |
33 forKey:(__bridge id)kSecAttrGeneric]; | |
34 [_userInfoQuery setObject:(__bridge id)kSecMatchLimitOne | |
35 forKey:(__bridge id)kSecMatchLimit]; | |
36 [_userInfoQuery setObject:(__bridge id)kCFBooleanTrue | |
37 forKey:(__bridge id)kSecReturnAttributes]; | |
38 | |
39 CFMutableDictionaryRef outDictionary = nil; | |
40 keychainErr = SecItemCopyMatching((__bridge CFDictionaryRef)_userInfoQuery, | |
41 (CFTypeRef*)&outDictionary); | |
42 if (keychainErr == noErr) { | |
43 _keychainData = [self | |
44 secItemFormatToDictionary:(__bridge_transfer NSMutableDictionary*) | |
45 outDictionary]; | |
46 } else if (keychainErr == errSecItemNotFound) { | |
47 [self resetKeychainItem]; | |
48 | |
49 if (outDictionary) { | |
50 CFRelease(outDictionary); | |
51 _keychainData = nil; | |
52 } | |
53 } else { | |
54 NSLog(@"Serious error."); | |
55 if (outDictionary) { | |
56 CFRelease(outDictionary); | |
57 _keychainData = nil; | |
58 } | |
59 } | |
60 } | |
61 return self; | |
62 } | |
63 | |
64 - (void)setRefreshToken:(NSString*)refreshToken { | |
65 [self setObject:refreshToken forKey:(__bridge id)kSecValueData]; | |
66 } | |
67 | |
68 - (NSString*)refreshToken { | |
69 return [self objectForKey:(__bridge id)kSecValueData]; | |
70 } | |
71 | |
72 // Implement the mySetObject:forKey method, which writes attributes to the | |
73 // keychain: | |
74 - (void)setObject:(id)inObject forKey:(id)key { | |
75 if (inObject == nil) | |
76 return; | |
77 id currentObject = [_keychainData objectForKey:key]; | |
78 if (![currentObject isEqual:inObject]) { | |
79 [_keychainData setObject:inObject forKey:key]; | |
80 [self writeToKeychain]; | |
81 } | |
82 } | |
83 | |
84 // Implement the myObjectForKey: method, which reads an attribute value from a | |
85 // dictionary: | |
86 - (id)objectForKey:(id)key { | |
87 return [_keychainData objectForKey:key]; | |
88 } | |
89 | |
90 - (void)resetKeychainItem { | |
91 if (!_keychainData) { | |
92 _keychainData = [[NSMutableDictionary alloc] init]; | |
93 } else if (_keychainData) { | |
94 NSMutableDictionary* tmpDictionary = | |
95 [self dictionaryToSecItemFormat:_keychainData]; | |
96 OSStatus errorcode = SecItemDelete((__bridge CFDictionaryRef)tmpDictionary); | |
97 if (errorcode == errSecItemNotFound) { | |
98 // this is ok. | |
99 } else if (errorcode != noErr) { | |
100 NSLog(@"Problem deleting current keychain item."); | |
101 } | |
102 } | |
103 | |
104 [_keychainData setObject:@"gaia_refresh_token" | |
105 forKey:(__bridge id)kSecAttrLabel]; | |
106 [_keychainData setObject:@"Gaia fresh token" | |
107 forKey:(__bridge id)kSecAttrDescription]; | |
108 [_keychainData setObject:@"" forKey:(__bridge id)kSecValueData]; | |
109 } | |
110 | |
111 - (NSMutableDictionary*)dictionaryToSecItemFormat: | |
112 (NSDictionary*)dictionaryToConvert { | |
113 NSMutableDictionary* returnDictionary = | |
114 [NSMutableDictionary dictionaryWithDictionary:dictionaryToConvert]; | |
115 | |
116 NSData* keychainItemID = | |
117 [NSData dataWithBytes:kKeychainItemIdentifier | |
118 length:strlen((const char*)kKeychainItemIdentifier)]; | |
119 [returnDictionary setObject:keychainItemID | |
120 forKey:(__bridge id)kSecAttrGeneric]; | |
121 [returnDictionary setObject:(__bridge id)kSecClassGenericPassword | |
122 forKey:(__bridge id)kSecClass]; | |
123 | |
124 NSString* passwordString = | |
125 [dictionaryToConvert objectForKey:(__bridge id)kSecValueData]; | |
126 [returnDictionary | |
127 setObject:[passwordString dataUsingEncoding:NSUTF8StringEncoding] | |
128 forKey:(__bridge id)kSecValueData]; | |
129 return returnDictionary; | |
130 } | |
131 | |
132 - (NSMutableDictionary*)secItemFormatToDictionary: | |
133 (NSDictionary*)dictionaryToConvert { | |
134 NSMutableDictionary* returnDictionary = | |
135 [NSMutableDictionary dictionaryWithDictionary:dictionaryToConvert]; | |
136 | |
137 [returnDictionary setObject:(__bridge id)kCFBooleanTrue | |
138 forKey:(__bridge id)kSecReturnData]; | |
139 [returnDictionary setObject:(__bridge id)kSecClassGenericPassword | |
140 forKey:(__bridge id)kSecClass]; | |
141 | |
142 CFDataRef passwordData = NULL; | |
143 OSStatus keychainError = noErr; | |
144 keychainError = SecItemCopyMatching( | |
145 (__bridge CFDictionaryRef)returnDictionary, (CFTypeRef*)&passwordData); | |
146 if (keychainError == noErr) { | |
147 [returnDictionary removeObjectForKey:(__bridge id)kSecReturnData]; | |
148 | |
149 NSString* password = [[NSString alloc] | |
150 initWithBytes:[(__bridge_transfer NSData*)passwordData bytes] | |
151 length:[(__bridge NSData*)passwordData length] | |
152 encoding:NSUTF8StringEncoding]; | |
153 [returnDictionary setObject:password forKey:(__bridge id)kSecValueData]; | |
154 } else if (keychainError == errSecItemNotFound) { | |
155 NSLog(@"Nothing was found in the keychain."); | |
156 if (passwordData) { | |
157 CFRelease(passwordData); | |
158 passwordData = nil; | |
159 } | |
160 } else { | |
161 NSLog(@"Serious error.\n"); | |
162 if (passwordData) { | |
163 CFRelease(passwordData); | |
164 passwordData = nil; | |
165 } | |
166 } | |
167 return returnDictionary; | |
168 } | |
169 | |
170 - (void)writeToKeychain { | |
171 CFDictionaryRef attributes = nil; | |
172 NSMutableDictionary* updateItem = nil; | |
173 | |
174 if (SecItemCopyMatching((__bridge CFDictionaryRef)_userInfoQuery, | |
175 (CFTypeRef*)&attributes) == noErr) { | |
176 updateItem = [NSMutableDictionary | |
177 dictionaryWithDictionary:(__bridge_transfer NSDictionary*)attributes]; | |
178 | |
179 [updateItem setObject:[_userInfoQuery objectForKey:(__bridge id)kSecClass] | |
180 forKey:(__bridge id)kSecClass]; | |
181 | |
182 NSMutableDictionary* tempCheck = | |
183 [self dictionaryToSecItemFormat:_keychainData]; | |
184 [tempCheck removeObjectForKey:(__bridge id)kSecClass]; | |
185 | |
186 OSStatus errorcode = SecItemUpdate((__bridge CFDictionaryRef)updateItem, | |
187 (__bridge CFDictionaryRef)tempCheck); | |
188 if (errorcode != noErr) { | |
189 NSLog(@"Couldn't update the Keychain Item. %d", (int)errorcode); | |
190 } | |
191 } else { | |
192 OSStatus errorcode = | |
193 SecItemAdd((__bridge CFDictionaryRef) | |
194 [self dictionaryToSecItemFormat:_keychainData], | |
195 NULL); | |
196 if (errorcode != noErr) { | |
197 NSLog(@"Couldn't add the Keychain Item. %d", (int)errorcode); | |
198 } | |
199 if (attributes) { | |
200 CFRelease(attributes); | |
201 attributes = nil; | |
202 } | |
203 } | |
204 } | |
205 | |
206 @end | |
OLD | NEW |