2 * Copyright (c) 2014-2020 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
);
39 #if TARGET_OS_OSX || TARGET_OS_MACCATALYST
40 OSStatus
SecCopySharedWebCredentialSyncUsingAuthSvcs(CFStringRef fqdn
, CFStringRef account
, CFArrayRef
*credentials
, CFErrorRef
*error
);
43 #if SHAREDWEBCREDENTIALS
45 // OSX now has SWC enabled, but cannot link SharedWebCredentials framework: rdar://59958701
46 #if TARGET_OS_OSX || TARGET_OS_MACCATALYST
48 OSStatus
SecAddSharedWebCredentialSync(CFStringRef fqdn
,
53 OSStatus status
= errSecUnimplemented
;
55 SecError(status
, error
, CFSTR("SecAddSharedWebCredentialSync not supported on this platform"));
62 OSStatus
SecAddSharedWebCredentialSync(CFStringRef fqdn
,
68 __block CFErrorRef
* outError
= error
;
69 __block CFMutableDictionaryRef args
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
70 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
72 CFDictionaryAddValue(args
, kSecAttrServer
, fqdn
);
75 CFDictionaryAddValue(args
, kSecAttrAccount
, account
);
78 CFDictionaryAddValue(args
, kSecSharedPassword
, password
);
80 status
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
81 CFTypeRef raw_result
= NULL
;
82 bool xpc_result
= false;
83 bool internal_spi
= false; // TODO: support this for SecurityDevTests
84 if(internal_spi
&& gSecurityd
&& gSecurityd
->sec_add_shared_web_credential
) {
85 xpc_result
= gSecurityd
->sec_add_shared_web_credential(args
, NULL
, NULL
, NULL
, SecAccessGroupsGetCurrent(), &raw_result
, error
);
87 xpc_result
= cftype_client_to_bool_cftype_error_request(sec_add_shared_web_credential_id
, args
, SecSecurityClientGet(), &raw_result
, error
);
92 SecError(errSecInternal
, error
, CFSTR("Internal error (XPC failure)"));
96 *outError
= (error
) ? *error
: NULL
;
97 CFRetainSafe(*outError
);
99 CFReleaseNull(*error
);
101 CFReleaseNull(raw_result
);
107 #endif /* !TARGET_OS_OSX || !TARGET_OS_MACCATALYST */
108 #endif /* SHAREDWEBCREDENTIALS */
110 void SecAddSharedWebCredential(CFStringRef fqdn
,
112 CFStringRef password
,
113 void (^completionHandler
)(CFErrorRef error
))
115 __block CFErrorRef error
= NULL
;
116 __block dispatch_queue_t dst_queue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
,0);
117 #if SHAREDWEBCREDENTIALS
119 /* sanity check input arguments */
120 CFStringRef errStr
= NULL
;
121 if (!fqdn
|| CFGetTypeID(fqdn
) != CFStringGetTypeID() || !CFStringGetLength(fqdn
) ||
122 !account
|| CFGetTypeID(account
) != CFStringGetTypeID() || !CFStringGetLength(account
) ) {
123 errStr
= CFSTR("fqdn or account was not of type CFString, or not provided");
125 else if (password
&& CFGetTypeID(password
) != CFStringGetTypeID()) {
126 errStr
= CFSTR("non-nil password was not of type CFString");
129 SecError(errSecParam
, &error
, CFSTR("%@"), errStr
);
130 dispatch_async(dst_queue
, ^{
131 if (completionHandler
) {
132 completionHandler(error
);
134 CFReleaseSafe(error
);
139 __block CFStringRef serverStr
= CFRetainSafe(fqdn
);
140 __block CFStringRef accountStr
= CFRetainSafe(account
);
141 __block CFStringRef passwordStr
= CFRetainSafe(password
);
143 dispatch_async(dst_queue
, ^{
144 OSStatus status
= SecAddSharedWebCredentialSync(serverStr
, accountStr
, passwordStr
, &error
);
145 CFReleaseSafe(serverStr
);
146 CFReleaseSafe(accountStr
);
147 CFReleaseSafe(passwordStr
);
149 if (status
&& !error
) {
150 SecError(status
, &error
, CFSTR("Error adding shared password"));
152 dispatch_async(dst_queue
, ^{
153 if (completionHandler
) {
154 completionHandler(error
);
156 CFReleaseSafe(error
);
160 SecError(errSecParam
, &error
, CFSTR("SharedWebCredentials not supported on this platform"));
161 dispatch_async(dst_queue
, ^{
162 if (completionHandler
) {
163 completionHandler(error
);
165 CFReleaseSafe(error
);
170 #if SHAREDWEBCREDENTIALS
172 #if TARGET_OS_OSX || TARGET_OS_MACCATALYST
174 OSStatus
SecCopySharedWebCredentialSync(CFStringRef fqdn
,
176 CFArrayRef
*credentials
,
179 OSStatus status
= errSecUnimplemented
;
181 SecError(status
, error
, CFSTR("SecCopySharedWebCredentialSync not supported on this platform"));
188 OSStatus
SecCopySharedWebCredentialSync(CFStringRef fqdn
,
190 CFArrayRef
*credentials
,
194 __block CFErrorRef
* outError
= error
;
195 __block CFMutableDictionaryRef args
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
196 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
198 CFDictionaryAddValue(args
, kSecAttrServer
, fqdn
);
201 CFDictionaryAddValue(args
, kSecAttrAccount
, account
);
203 status
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
204 CFTypeRef raw_result
= NULL
;
205 bool xpc_result
= false;
206 bool internal_spi
= false; // TODO: support this for SecurityDevTests
207 if(internal_spi
&& gSecurityd
&& gSecurityd
->sec_copy_shared_web_credential
) {
208 xpc_result
= gSecurityd
->sec_copy_shared_web_credential(args
, NULL
, NULL
, NULL
, SecAccessGroupsGetCurrent(), &raw_result
, error
);
210 xpc_result
= cftype_client_to_bool_cftype_error_request(sec_copy_shared_web_credential_id
, args
, SecSecurityClientGet(), &raw_result
, error
);
214 if (NULL
== *error
) {
215 SecError(errSecInternal
, error
, CFSTR("Internal error (XPC failure)"));
219 *outError
= (error
) ? *error
: NULL
;
220 CFRetainSafe(*outError
);
222 CFReleaseNull(*error
);
225 raw_result
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
227 *credentials
= raw_result
;
233 #endif /* !TARGET_OS_OSX || !TARGET_OS_MACCATALYST */
234 #endif /* SHAREDWEBCREDENTIALS */
236 void SecRequestSharedWebCredential(CFStringRef fqdn
,
238 void (^completionHandler
)(CFArrayRef credentials
, CFErrorRef error
))
240 __block CFErrorRef error
= NULL
;
241 __block dispatch_queue_t dst_queue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
,0);
242 #if SHAREDWEBCREDENTIALS
243 __block CFArrayRef result
= NULL
;
245 /* sanity check input arguments, if provided */
246 CFStringRef errStr
= NULL
;
247 if (fqdn
&& (CFGetTypeID(fqdn
) != CFStringGetTypeID() || !CFStringGetLength(fqdn
))) {
248 errStr
= CFSTR("fqdn was empty or not a CFString");
250 else if (account
&& (CFGetTypeID(account
) != CFStringGetTypeID() || !CFStringGetLength(account
))) {
251 errStr
= CFSTR("account was empty or not a CFString");
254 SecError(errSecParam
, &error
, CFSTR("%@"), errStr
);
255 dispatch_async(dst_queue
, ^{
256 if (completionHandler
) {
257 completionHandler(result
, error
);
259 CFReleaseSafe(error
);
260 CFReleaseSafe(result
);
265 __block CFStringRef serverStr
= CFRetainSafe(fqdn
);
266 __block CFStringRef accountStr
= CFRetainSafe(account
);
268 dispatch_async(dst_queue
, ^{
269 #if TARGET_OS_OSX || TARGET_OS_MACCATALYST
270 OSStatus status
= SecCopySharedWebCredentialSyncUsingAuthSvcs(serverStr
, accountStr
, &result
, &error
);
272 OSStatus status
= SecCopySharedWebCredentialSync(serverStr
, accountStr
, &result
, &error
);
274 CFReleaseSafe(serverStr
);
275 CFReleaseSafe(accountStr
);
277 if (status
&& !error
) {
278 SecError(status
, &error
, CFSTR("Error copying shared password"));
280 dispatch_async(dst_queue
, ^{
281 if (completionHandler
) {
282 completionHandler(result
, error
);
284 CFReleaseSafe(error
);
285 CFReleaseSafe(result
);
289 SecError(errSecParam
, &error
, CFSTR("SharedWebCredentials not supported on this platform"));
290 dispatch_async(dst_queue
, ^{
291 if (completionHandler
) {
292 completionHandler(NULL
, error
);
294 CFReleaseSafe(error
);
296 #endif /* SHAREDWEBCREDENTIALS */
300 CFStringRef
SecCreateSharedWebCredentialPassword(void)
303 CFStringRef password
= NULL
;
304 CFErrorRef error
= NULL
;
305 CFMutableDictionaryRef passwordRequirements
= NULL
;
307 CFStringRef allowedCharacters
= CFSTR("abcdefghkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789");
308 CFCharacterSetRef requiredCharactersLower
= CFCharacterSetCreateWithCharactersInString(NULL
, CFSTR("abcdefghkmnopqrstuvwxyz"));
309 CFCharacterSetRef requiredCharactersUppder
= CFCharacterSetCreateWithCharactersInString(NULL
, CFSTR("ABCDEFGHJKLMNPQRSTUVWXYZ"));
310 CFCharacterSetRef requiredCharactersNumbers
= CFCharacterSetCreateWithCharactersInString(NULL
, CFSTR("3456789"));
314 int totalLength
= (groupSize
* groupCount
);
315 CFNumberRef groupSizeRef
= CFNumberCreate(NULL
, kCFNumberIntType
, &groupSize
);
316 CFNumberRef groupCountRef
= CFNumberCreate(NULL
, kCFNumberIntType
, &groupCount
);
317 CFNumberRef totalLengthRef
= CFNumberCreate(NULL
, kCFNumberIntType
, &totalLength
);
318 CFStringRef separator
= CFSTR("-");
320 CFMutableArrayRef requiredCharacterSets
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
321 CFArrayAppendValue(requiredCharacterSets
, requiredCharactersLower
);
322 CFArrayAppendValue(requiredCharacterSets
, requiredCharactersUppder
);
323 CFArrayAppendValue(requiredCharacterSets
, requiredCharactersNumbers
);
325 passwordRequirements
= CFDictionaryCreateMutable(NULL
, 0, NULL
, NULL
);
326 CFDictionaryAddValue(passwordRequirements
, kSecPasswordAllowedCharactersKey
, allowedCharacters
);
327 CFDictionaryAddValue(passwordRequirements
, kSecPasswordRequiredCharactersKey
, requiredCharacterSets
);
328 CFDictionaryAddValue(passwordRequirements
, kSecPasswordGroupSize
, groupSizeRef
);
329 CFDictionaryAddValue(passwordRequirements
, kSecPasswordNumberOfGroups
, groupCountRef
);
330 CFDictionaryAddValue(passwordRequirements
, kSecPasswordSeparator
, separator
);
331 CFDictionaryAddValue(passwordRequirements
, kSecPasswordMaxLengthKey
, totalLengthRef
);
332 CFDictionaryAddValue(passwordRequirements
, kSecPasswordMinLengthKey
, totalLengthRef
);
333 CFDictionaryAddValue(passwordRequirements
, kSecPasswordDefaultForType
, CFSTR("false"));
334 CFRelease(requiredCharactersLower
);
335 CFRelease(requiredCharactersUppder
);
336 CFRelease(requiredCharactersNumbers
);
337 CFRelease(groupSizeRef
);
338 CFRelease(groupCountRef
);
339 CFRelease(totalLengthRef
);
341 password
= SecPasswordGenerate(kSecPasswordTypeSafari
, &error
, passwordRequirements
);
343 CFRelease(requiredCharacterSets
);
344 CFRelease(passwordRequirements
);
345 if ((error
&& error
!= errSecSuccess
) || !password
)
347 if (password
) CFRelease(password
);
348 secwarning("SecPasswordGenerate failed to generate a password for SecCreateSharedWebCredentialPassword.");