123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- // 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(void* data) const {
- free(data);
- return noErr;
- }
- OSStatus AppleKeychain::AddGenericPassword(
- UInt32 serviceNameLength,
- const char* serviceName,
- UInt32 accountNameLength,
- const char* accountName,
- UInt32 passwordLength,
- const void* passwordData,
- AppleSecKeychainItemRef* 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(
- UInt32 serviceNameLength,
- const char* serviceName,
- UInt32 accountNameLength,
- const char* accountName,
- UInt32* passwordLength,
- void** passwordData,
- AppleSecKeychainItemRef* 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
|