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 |