diff options
author | Zeno Albisser <zeno.albisser@digia.com> | 2013-08-15 21:46:11 +0200 |
---|---|---|
committer | Zeno Albisser <zeno.albisser@digia.com> | 2013-08-15 21:46:11 +0200 |
commit | 679147eead574d186ebf3069647b4c23e8ccace6 (patch) | |
tree | fc247a0ac8ff119f7c8550879ebb6d3dd8d1ff69 /chromium/crypto/apple_keychain_ios.mm | |
download | qtwebengine-chromium-679147eead574d186ebf3069647b4c23e8ccace6.tar.gz |
Initial import.
Diffstat (limited to 'chromium/crypto/apple_keychain_ios.mm')
-rw-r--r-- | chromium/crypto/apple_keychain_ios.mm | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/chromium/crypto/apple_keychain_ios.mm b/chromium/crypto/apple_keychain_ios.mm new file mode 100644 index 00000000000..74cf129ce1f --- /dev/null +++ b/chromium/crypto/apple_keychain_ios.mm @@ -0,0 +1,196 @@ +// Copyright (c) 2012 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. + +#include "crypto/apple_keychain.h" + +#import <Foundation/Foundation.h> + +#include "base/mac/foundation_util.h" +#include "base/mac/scoped_cftyperef.h" +#include "base/mac/scoped_nsobject.h" + +namespace { + +enum KeychainAction { + kKeychainActionCreate, + kKeychainActionUpdate +}; + +// Creates a dictionary that can be used to query the keystore. +// Ownership follows the Create rule. +CFDictionaryRef CreateGenericPasswordQuery(UInt32 serviceNameLength, + const char* serviceName, + UInt32 accountNameLength, + const char* accountName) { + CFMutableDictionaryRef query = + CFDictionaryCreateMutable(NULL, + 5, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + // Type of element is generic password. + CFDictionarySetValue(query, kSecClass, kSecClassGenericPassword); + + // Set the service name. + base::scoped_nsobject<NSString> service_name_ns( + [[NSString alloc] initWithBytes:serviceName + length:serviceNameLength + encoding:NSUTF8StringEncoding]); + CFDictionarySetValue(query, kSecAttrService, + base::mac::NSToCFCast(service_name_ns)); + + // Set the account name. + base::scoped_nsobject<NSString> account_name_ns( + [[NSString alloc] initWithBytes:accountName + length:accountNameLength + encoding:NSUTF8StringEncoding]); + CFDictionarySetValue(query, kSecAttrAccount, + base::mac::NSToCFCast(account_name_ns)); + + // Use the proper search constants, return only the data of the first match. + CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitOne); + CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue); + return query; +} + +// Creates a dictionary conatining the data to save into the keychain. +// Ownership follows the Create rule. +CFDictionaryRef CreateKeychainData(UInt32 serviceNameLength, + const char* serviceName, + UInt32 accountNameLength, + const char* accountName, + UInt32 passwordLength, + const void* passwordData, + KeychainAction action) { + CFMutableDictionaryRef keychain_data = + CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + // Set the password. + NSData* password = [NSData dataWithBytes:passwordData length:passwordLength]; + CFDictionarySetValue(keychain_data, kSecValueData, + base::mac::NSToCFCast(password)); + + // If this is not a creation, no structural information is needed. + if (action != kKeychainActionCreate) + return keychain_data; + + // Set the type of the data. + CFDictionarySetValue(keychain_data, kSecClass, kSecClassGenericPassword); + + // Only allow access when the device has been unlocked. + CFDictionarySetValue(keychain_data, + kSecAttrAccessible, + kSecAttrAccessibleWhenUnlocked); + + // Set the service name. + base::scoped_nsobject<NSString> service_name_ns( + [[NSString alloc] initWithBytes:serviceName + length:serviceNameLength + encoding:NSUTF8StringEncoding]); + CFDictionarySetValue(keychain_data, kSecAttrService, + base::mac::NSToCFCast(service_name_ns)); + + // Set the account name. + base::scoped_nsobject<NSString> account_name_ns( + [[NSString alloc] initWithBytes:accountName + length:accountNameLength + encoding:NSUTF8StringEncoding]); + CFDictionarySetValue(keychain_data, kSecAttrAccount, + base::mac::NSToCFCast(account_name_ns)); + + return keychain_data; +} + +} // namespace + +namespace crypto { + +AppleKeychain::AppleKeychain() {} + +AppleKeychain::~AppleKeychain() {} + +OSStatus AppleKeychain::ItemFreeContent(SecKeychainAttributeList* attrList, + void* data) const { + free(data); + return noErr; +} + +OSStatus AppleKeychain::AddGenericPassword(SecKeychainRef keychain, + UInt32 serviceNameLength, + const char* serviceName, + UInt32 accountNameLength, + const char* accountName, + UInt32 passwordLength, + const void* passwordData, + SecKeychainItemRef* itemRef) const { + base::ScopedCFTypeRef<CFDictionaryRef> query(CreateGenericPasswordQuery( + serviceNameLength, serviceName, accountNameLength, accountName)); + // Check that there is not already a password. + OSStatus status = SecItemCopyMatching(query, NULL); + if (status == errSecItemNotFound) { + // A new entry must be created. + base::ScopedCFTypeRef<CFDictionaryRef> keychain_data( + CreateKeychainData(serviceNameLength, + serviceName, + accountNameLength, + accountName, + passwordLength, + passwordData, + kKeychainActionCreate)); + status = SecItemAdd(keychain_data, NULL); + } else if (status == noErr) { + // The entry must be updated. + base::ScopedCFTypeRef<CFDictionaryRef> keychain_data( + CreateKeychainData(serviceNameLength, + serviceName, + accountNameLength, + accountName, + passwordLength, + passwordData, + kKeychainActionUpdate)); + status = SecItemUpdate(query, keychain_data); + } + + return status; +} + +OSStatus AppleKeychain::FindGenericPassword(CFTypeRef keychainOrArray, + UInt32 serviceNameLength, + const char* serviceName, + UInt32 accountNameLength, + const char* accountName, + UInt32* passwordLength, + void** passwordData, + SecKeychainItemRef* itemRef) const { + DCHECK((passwordData && passwordLength) || + (!passwordData && !passwordLength)); + base::ScopedCFTypeRef<CFDictionaryRef> query(CreateGenericPasswordQuery( + serviceNameLength, serviceName, accountNameLength, accountName)); + + // Get the keychain item containing the password. + CFTypeRef resultRef = NULL; + OSStatus status = SecItemCopyMatching(query, &resultRef); + base::ScopedCFTypeRef<CFTypeRef> result(resultRef); + + if (status != noErr) { + if (passwordData) { + *passwordData = NULL; + *passwordLength = 0; + } + return status; + } + + if (passwordData) { + CFDataRef data = base::mac::CFCast<CFDataRef>(result); + NSUInteger length = CFDataGetLength(data); + *passwordData = malloc(length * sizeof(UInt8)); + CFDataGetBytes(data, CFRangeMake(0, length), (UInt8*)*passwordData); + *passwordLength = length; + } + return status; +} + +} // namespace crypto |