mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-11-28 08:16:09 +03:00
196 lines
7.0 KiB
Plaintext
196 lines
7.0 KiB
Plaintext
|
// 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
|