[M120 Migration][VD] Enable direct rendering for TVPlus
[platform/framework/web/chromium-efl.git] / crypto / apple_keychain_ios.mm
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "crypto/apple_keychain.h"
6
7 #import <Foundation/Foundation.h>
8
9 #include "base/apple/bridging.h"
10 #include "base/apple/foundation_util.h"
11 #include "base/apple/scoped_cftyperef.h"
12
13 namespace {
14
15 enum KeychainAction {
16   kKeychainActionCreate,
17   kKeychainActionUpdate
18 };
19
20 base::apple::ScopedCFTypeRef<CFStringRef> StringWithBytesAndLength(
21     const char* bytes,
22     UInt32 length) {
23   return base::apple::ScopedCFTypeRef<CFStringRef>(
24       CFStringCreateWithBytes(nullptr, reinterpret_cast<const UInt8*>(bytes),
25                               length, kCFStringEncodingUTF8,
26                               /*isExternalRepresentation=*/false));
27 }
28
29 // Creates a dictionary that can be used to query the keystore.
30 base::apple::ScopedCFTypeRef<CFDictionaryRef> MakeGenericPasswordQuery(
31     UInt32 serviceNameLength,
32     const char* serviceName,
33     UInt32 accountNameLength,
34     const char* accountName) {
35   CFMutableDictionaryRef query =
36       CFDictionaryCreateMutable(nullptr, 5, &kCFTypeDictionaryKeyCallBacks,
37                                 &kCFTypeDictionaryValueCallBacks);
38   // Type of element is generic password.
39   CFDictionarySetValue(query, kSecClass, kSecClassGenericPassword);
40
41   // Set the service name.
42   CFDictionarySetValue(
43       query, kSecAttrService,
44       StringWithBytesAndLength(serviceName, serviceNameLength));
45
46   // Set the account name.
47   CFDictionarySetValue(
48       query, kSecAttrAccount,
49       StringWithBytesAndLength(accountName, accountNameLength));
50
51   // Use the proper search constants, return only the data of the first match.
52   CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitOne);
53   CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
54
55   return base::apple::ScopedCFTypeRef<CFDictionaryRef>(query);
56 }
57
58 // Creates a dictionary containing the data to save into the keychain.
59 base::apple::ScopedCFTypeRef<CFDictionaryRef> MakeKeychainData(
60     UInt32 serviceNameLength,
61     const char* serviceName,
62     UInt32 accountNameLength,
63     const char* accountName,
64     UInt32 passwordLength,
65     const void* passwordData,
66     KeychainAction action) {
67   CFMutableDictionaryRef keychain_data =
68       CFDictionaryCreateMutable(nullptr, 0, &kCFTypeDictionaryKeyCallBacks,
69                                 &kCFTypeDictionaryValueCallBacks);
70
71   // Set the password.
72   NSData* password = [NSData dataWithBytes:passwordData length:passwordLength];
73   CFDictionarySetValue(keychain_data, kSecValueData,
74                        base::apple::NSToCFPtrCast(password));
75
76   // If this is not a creation, no structural information is needed.
77   if (action != kKeychainActionCreate) {
78     return base::apple::ScopedCFTypeRef<CFDictionaryRef>(keychain_data);
79   }
80
81   // Set the type of the data.
82   CFDictionarySetValue(keychain_data, kSecClass, kSecClassGenericPassword);
83
84   // Only allow access when the device has been unlocked.
85   CFDictionarySetValue(keychain_data,
86                        kSecAttrAccessible,
87                        kSecAttrAccessibleWhenUnlocked);
88
89   // Set the service name.
90   CFDictionarySetValue(
91       keychain_data, kSecAttrService,
92       StringWithBytesAndLength(serviceName, serviceNameLength));
93
94   // Set the account name.
95   CFDictionarySetValue(
96       keychain_data, kSecAttrAccount,
97       StringWithBytesAndLength(accountName, accountNameLength));
98
99   return base::apple::ScopedCFTypeRef<CFDictionaryRef>(keychain_data);
100 }
101
102 }  // namespace
103
104 namespace crypto {
105
106 AppleKeychain::AppleKeychain() = default;
107
108 AppleKeychain::~AppleKeychain() = default;
109
110 OSStatus AppleKeychain::ItemFreeContent(void* data) const {
111   free(data);
112   return noErr;
113 }
114
115 OSStatus AppleKeychain::AddGenericPassword(
116     UInt32 serviceNameLength,
117     const char* serviceName,
118     UInt32 accountNameLength,
119     const char* accountName,
120     UInt32 passwordLength,
121     const void* passwordData,
122     AppleSecKeychainItemRef* itemRef) const {
123   base::apple::ScopedCFTypeRef<CFDictionaryRef> query =
124       MakeGenericPasswordQuery(serviceNameLength, serviceName,
125                                accountNameLength, accountName);
126   // Check that there is not already a password.
127   OSStatus status = SecItemCopyMatching(query, /*result=*/nullptr);
128   if (status == errSecItemNotFound) {
129     // A new entry must be created.
130     base::apple::ScopedCFTypeRef<CFDictionaryRef> keychain_data =
131         MakeKeychainData(serviceNameLength, serviceName, accountNameLength,
132                          accountName, passwordLength, passwordData,
133                          kKeychainActionCreate);
134     status = SecItemAdd(keychain_data, /*result=*/nullptr);
135   } else if (status == noErr) {
136     // The entry must be updated.
137     base::apple::ScopedCFTypeRef<CFDictionaryRef> keychain_data =
138         MakeKeychainData(serviceNameLength, serviceName, accountNameLength,
139                          accountName, passwordLength, passwordData,
140                          kKeychainActionUpdate);
141     status = SecItemUpdate(query, keychain_data);
142   }
143
144   return status;
145 }
146
147 OSStatus AppleKeychain::FindGenericPassword(
148     UInt32 serviceNameLength,
149     const char* serviceName,
150     UInt32 accountNameLength,
151     const char* accountName,
152     UInt32* passwordLength,
153     void** passwordData,
154     AppleSecKeychainItemRef* itemRef) const {
155   DCHECK((passwordData && passwordLength) ||
156          (!passwordData && !passwordLength));
157   base::apple::ScopedCFTypeRef<CFDictionaryRef> query =
158       MakeGenericPasswordQuery(serviceNameLength, serviceName,
159                                accountNameLength, accountName);
160
161   // Get the keychain item containing the password.
162   base::apple::ScopedCFTypeRef<CFTypeRef> result;
163   OSStatus status = SecItemCopyMatching(query, result.InitializeInto());
164
165   if (status != noErr) {
166     if (passwordData) {
167       *passwordData = nullptr;
168       *passwordLength = 0;
169     }
170     return status;
171   }
172
173   if (passwordData) {
174     CFDataRef data = base::apple::CFCast<CFDataRef>(result);
175     NSUInteger length = CFDataGetLength(data);
176     *passwordData = malloc(length * sizeof(UInt8));
177     CFDataGetBytes(data, CFRangeMake(0, length), (UInt8*)*passwordData);
178     *passwordLength = length;
179   }
180   return status;
181 }
182
183 }  // namespace crypto