2 * Copyright (c) 2014-2016 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 * SecSharedCredential.c - CoreFoundation-based functions to store and retrieve shared credentials.
28 #include <Security/SecSharedCredential.h>
29 #include <Security/SecBasePriv.h>
30 #include <utilities/SecCFError.h>
31 #include <utilities/SecCFWrappers.h>
32 #include "SecItemInternal.h"
33 #include <ipc/securityd_client.h>
34 #include "SecPasswordGenerate.h"
36 /* forward declarations */
37 OSStatus
SecAddSharedWebCredentialSync(CFStringRef fqdn
, CFStringRef account
, CFStringRef password
, CFErrorRef
*error
);
38 OSStatus
SecCopySharedWebCredentialSync(CFStringRef fqdn
, CFStringRef account
, CFArrayRef
*credentials
, CFErrorRef
*error
);
42 OSStatus
SecAddSharedWebCredentialSync(CFStringRef fqdn
,
48 __block CFErrorRef
* outError
= error
;
49 __block CFMutableDictionaryRef args
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
50 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
52 CFDictionaryAddValue(args
, kSecAttrServer
, fqdn
);
55 CFDictionaryAddValue(args
, kSecAttrAccount
, account
);
58 CFDictionaryAddValue(args
, kSecSharedPassword
, password
);
60 status
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
61 CFTypeRef raw_result
= NULL
;
63 bool internal_spi
= false; // TODO: support this for SecurityDevTests
64 if(internal_spi
&& gSecurityd
&& gSecurityd
->sec_add_shared_web_credential
) {
65 xpc_result
= gSecurityd
->sec_add_shared_web_credential(args
, NULL
, NULL
, NULL
, SecAccessGroupsGetCurrent(), &raw_result
, error
);
67 xpc_result
= cftype_client_to_bool_cftype_error_request(sec_add_shared_web_credential_id
, args
, SecSecurityClientGet(), &raw_result
, error
);
72 SecError(errSecInternal
, error
, CFSTR("Internal error (XPC failure)"));
76 *outError
= (error
) ? *error
: NULL
;
77 CFRetainSafe(*outError
);
79 CFReleaseNull(*error
);
81 CFReleaseNull(raw_result
);
87 #endif /* TARGET_OS_IOS */
89 void SecAddSharedWebCredential(CFStringRef fqdn
,
92 void (^completionHandler
)(CFErrorRef error
))
94 __block CFErrorRef error
= NULL
;
95 __block dispatch_queue_t dst_queue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
,0);
98 /* sanity check input arguments */
99 CFStringRef errStr
= NULL
;
100 if (!fqdn
|| CFGetTypeID(fqdn
) != CFStringGetTypeID() || !CFStringGetLength(fqdn
) ||
101 !account
|| CFGetTypeID(account
) != CFStringGetTypeID() || !CFStringGetLength(account
) ) {
102 errStr
= CFSTR("fqdn or account was not of type CFString, or not provided");
104 else if (password
&& CFGetTypeID(password
) != CFStringGetTypeID()) {
105 errStr
= CFSTR("non-nil password was not of type CFString");
108 SecError(errSecParam
, &error
, CFSTR("%@"), errStr
);
109 dispatch_async(dst_queue
, ^{
110 if (completionHandler
) {
111 completionHandler(error
);
113 CFReleaseSafe(error
);
118 __block CFStringRef serverStr
= CFRetainSafe(fqdn
);
119 __block CFStringRef accountStr
= CFRetainSafe(account
);
120 __block CFStringRef passwordStr
= CFRetainSafe(password
);
122 dispatch_async(dst_queue
, ^{
123 OSStatus status
= SecAddSharedWebCredentialSync(serverStr
, accountStr
, passwordStr
, &error
);
124 CFReleaseSafe(serverStr
);
125 CFReleaseSafe(accountStr
);
126 CFReleaseSafe(passwordStr
);
128 if (status
&& !error
) {
129 SecError(status
, &error
, CFSTR("Error adding shared password"));
131 dispatch_async(dst_queue
, ^{
132 if (completionHandler
) {
133 completionHandler(error
);
135 CFReleaseSafe(error
);
139 SecError(errSecParam
, &error
, CFSTR("SharedWebCredentials not supported on this platform"));
140 dispatch_async(dst_queue
, ^{
141 if (completionHandler
) {
142 completionHandler(error
);
144 CFReleaseSafe(error
);
150 OSStatus
SecCopySharedWebCredentialSync(CFStringRef fqdn
,
152 CFArrayRef
*credentials
,
156 __block CFErrorRef
* outError
= error
;
157 __block CFMutableDictionaryRef args
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
158 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
160 CFDictionaryAddValue(args
, kSecAttrServer
, fqdn
);
163 CFDictionaryAddValue(args
, kSecAttrAccount
, account
);
165 status
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
166 CFTypeRef raw_result
= NULL
;
168 bool internal_spi
= false; // TODO: support this for SecurityDevTests
169 if(internal_spi
&& gSecurityd
&& gSecurityd
->sec_copy_shared_web_credential
) {
170 xpc_result
= gSecurityd
->sec_copy_shared_web_credential(args
, NULL
, NULL
, NULL
, SecAccessGroupsGetCurrent(), &raw_result
, error
);
172 xpc_result
= cftype_client_to_bool_cftype_error_request(sec_copy_shared_web_credential_id
, args
, SecSecurityClientGet(), &raw_result
, error
);
176 if (NULL
== *error
) {
177 SecError(errSecInternal
, error
, CFSTR("Internal error (XPC failure)"));
181 *outError
= (error
) ? *error
: NULL
;
182 CFRetainSafe(*outError
);
184 CFReleaseNull(*error
);
187 raw_result
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
189 *credentials
= raw_result
;
195 #endif /* TARGET_OS_IOS */
197 void SecRequestSharedWebCredential(CFStringRef fqdn
,
199 void (^completionHandler
)(CFArrayRef credentials
, CFErrorRef error
))
201 __block CFErrorRef error
= NULL
;
202 __block dispatch_queue_t dst_queue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
,0);
204 __block CFArrayRef result
= NULL
;
206 /* sanity check input arguments, if provided */
207 CFStringRef errStr
= NULL
;
208 if (fqdn
&& (CFGetTypeID(fqdn
) != CFStringGetTypeID() || !CFStringGetLength(fqdn
))) {
209 errStr
= CFSTR("fqdn was empty or not a CFString");
211 else if (account
&& (CFGetTypeID(account
) != CFStringGetTypeID() || !CFStringGetLength(account
))) {
212 errStr
= CFSTR("account was empty or not a CFString");
215 SecError(errSecParam
, &error
, CFSTR("%@"), errStr
);
216 dispatch_async(dst_queue
, ^{
217 if (completionHandler
) {
218 completionHandler(result
, error
);
220 CFReleaseSafe(error
);
221 CFReleaseSafe(result
);
226 __block CFStringRef serverStr
= CFRetainSafe(fqdn
);
227 __block CFStringRef accountStr
= CFRetainSafe(account
);
229 dispatch_async(dst_queue
, ^{
230 OSStatus status
= SecCopySharedWebCredentialSync(serverStr
, accountStr
, &result
, &error
);
231 CFReleaseSafe(serverStr
);
232 CFReleaseSafe(accountStr
);
234 if (status
&& !error
) {
235 SecError(status
, &error
, CFSTR("Error copying shared password"));
237 dispatch_async(dst_queue
, ^{
238 if (completionHandler
) {
239 completionHandler(result
, error
);
241 CFReleaseSafe(error
);
242 CFReleaseSafe(result
);
246 SecError(errSecParam
, &error
, CFSTR("SharedWebCredentials not supported on this platform"));
247 dispatch_async(dst_queue
, ^{
248 if (completionHandler
) {
249 completionHandler(NULL
, error
);
251 CFReleaseSafe(error
);
257 CFStringRef
SecCreateSharedWebCredentialPassword(void)
260 CFStringRef password
= NULL
;
261 CFErrorRef error
= NULL
;
262 CFMutableDictionaryRef passwordRequirements
= NULL
;
264 CFStringRef allowedCharacters
= CFSTR("abcdefghkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789");
265 CFCharacterSetRef requiredCharactersLower
= CFCharacterSetCreateWithCharactersInString(NULL
, CFSTR("abcdefghkmnopqrstuvwxyz"));
266 CFCharacterSetRef requiredCharactersUppder
= CFCharacterSetCreateWithCharactersInString(NULL
, CFSTR("ABCDEFGHJKLMNPQRSTUVWXYZ"));
267 CFCharacterSetRef requiredCharactersNumbers
= CFCharacterSetCreateWithCharactersInString(NULL
, CFSTR("3456789"));
271 int totalLength
= (groupSize
* groupCount
);
272 CFNumberRef groupSizeRef
= CFNumberCreate(NULL
, kCFNumberIntType
, &groupSize
);
273 CFNumberRef groupCountRef
= CFNumberCreate(NULL
, kCFNumberIntType
, &groupCount
);
274 CFNumberRef totalLengthRef
= CFNumberCreate(NULL
, kCFNumberIntType
, &totalLength
);
275 CFStringRef separator
= CFSTR("-");
277 CFMutableArrayRef requiredCharacterSets
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
278 CFArrayAppendValue(requiredCharacterSets
, requiredCharactersLower
);
279 CFArrayAppendValue(requiredCharacterSets
, requiredCharactersUppder
);
280 CFArrayAppendValue(requiredCharacterSets
, requiredCharactersNumbers
);
282 passwordRequirements
= CFDictionaryCreateMutable(NULL
, 0, NULL
, NULL
);
283 CFDictionaryAddValue(passwordRequirements
, kSecPasswordAllowedCharactersKey
, allowedCharacters
);
284 CFDictionaryAddValue(passwordRequirements
, kSecPasswordRequiredCharactersKey
, requiredCharacterSets
);
285 CFDictionaryAddValue(passwordRequirements
, kSecPasswordGroupSize
, groupSizeRef
);
286 CFDictionaryAddValue(passwordRequirements
, kSecPasswordNumberOfGroups
, groupCountRef
);
287 CFDictionaryAddValue(passwordRequirements
, kSecPasswordSeparator
, separator
);
288 CFDictionaryAddValue(passwordRequirements
, kSecPasswordMaxLengthKey
, totalLengthRef
);
289 CFDictionaryAddValue(passwordRequirements
, kSecPasswordMinLengthKey
, totalLengthRef
);
290 CFDictionaryAddValue(passwordRequirements
, kSecPasswordDefaultForType
, CFSTR("false"));
291 CFRelease(requiredCharactersLower
);
292 CFRelease(requiredCharactersUppder
);
293 CFRelease(requiredCharactersNumbers
);
294 CFRelease(groupSizeRef
);
295 CFRelease(groupCountRef
);
296 CFRelease(totalLengthRef
);
298 password
= SecPasswordGenerate(kSecPasswordTypeSafari
, &error
, passwordRequirements
);
300 CFRelease(requiredCharacterSets
);
301 CFRelease(passwordRequirements
);
302 if ((error
&& error
!= errSecSuccess
) || !password
)
304 if (password
) CFRelease(password
);
305 secwarning("SecPasswordGenerate failed to generate a password for SecCreateSharedWebCredentialPassword.");