2 * Copyright (c) 2014 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
);
41 OSStatus
SecAddSharedWebCredentialSync(CFStringRef fqdn
,
47 __block CFErrorRef
* outError
= error
;
48 __block CFMutableDictionaryRef args
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
49 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
51 CFDictionaryAddValue(args
, kSecAttrServer
, fqdn
);
54 CFDictionaryAddValue(args
, kSecAttrAccount
, account
);
57 #if TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR && !TARGET_OS_WATCH
58 CFDictionaryAddValue(args
, kSecSharedPassword
, password
);
60 CFDictionaryAddValue(args
, CFSTR("spwd"), password
);
63 status
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
64 CFTypeRef raw_result
= NULL
;
66 bool internal_spi
= false; // TODO: support this for SecurityDevTests
67 if(internal_spi
&& gSecurityd
&& gSecurityd
->sec_add_shared_web_credential
) {
68 xpc_result
= gSecurityd
->sec_add_shared_web_credential(args
, NULL
, NULL
, NULL
, SecAccessGroupsGetCurrent(), &raw_result
, error
);
70 xpc_result
= cftype_client_to_bool_cftype_error_request(sec_add_shared_web_credential_id
, args
, SecSecurityClientGet(), &raw_result
, error
);
75 SecError(errSecInternal
, error
, CFSTR("Internal error (XPC failure)"));
79 *outError
= (error
) ? *error
: NULL
;
80 CFRetainSafe(*outError
);
82 CFReleaseNull(*error
);
84 CFReleaseNull(raw_result
);
91 void SecAddSharedWebCredential(CFStringRef fqdn
,
94 void (^completionHandler
)(CFErrorRef error
))
96 __block CFErrorRef error
= NULL
;
97 __block dispatch_queue_t dst_queue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
,0);
98 dispatch_retain(dst_queue
);
100 /* sanity check input arguments */
101 CFStringRef errStr
= NULL
;
102 if (!fqdn
|| CFGetTypeID(fqdn
) != CFStringGetTypeID() || !CFStringGetLength(fqdn
) ||
103 !account
|| CFGetTypeID(account
) != CFStringGetTypeID() || !CFStringGetLength(account
) ) {
104 errStr
= CFSTR("fqdn or account was not of type CFString, or not provided");
106 else if (password
&& CFGetTypeID(password
) != CFStringGetTypeID()) {
107 errStr
= CFSTR("non-nil password was not of type CFString");
110 SecError(errSecParam
, &error
, errStr
);
111 dispatch_async(dst_queue
, ^{
112 if (completionHandler
) {
113 completionHandler(error
);
115 CFReleaseSafe(error
);
116 dispatch_release(dst_queue
);
121 __block CFStringRef serverStr
= CFRetainSafe(fqdn
);
122 __block CFStringRef accountStr
= CFRetainSafe(account
);
123 __block CFStringRef passwordStr
= CFRetainSafe(password
);
125 dispatch_async(dst_queue
, ^{
126 OSStatus status
= SecAddSharedWebCredentialSync(serverStr
, accountStr
, passwordStr
, &error
);
127 CFReleaseSafe(serverStr
);
128 CFReleaseSafe(accountStr
);
129 CFReleaseSafe(passwordStr
);
131 if (status
&& !error
) {
132 SecError(status
, &error
, CFSTR("Error adding shared password"));
134 dispatch_async(dst_queue
, ^{
135 if (completionHandler
) {
136 completionHandler(error
);
138 CFReleaseSafe(error
);
139 dispatch_release(dst_queue
);
145 OSStatus
SecCopySharedWebCredentialSync(CFStringRef fqdn
,
147 CFArrayRef
*credentials
,
151 __block CFErrorRef
* outError
= error
;
152 __block CFMutableDictionaryRef args
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
153 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
155 CFDictionaryAddValue(args
, kSecAttrServer
, fqdn
);
158 CFDictionaryAddValue(args
, kSecAttrAccount
, account
);
160 status
= SecOSStatusWith(^bool (CFErrorRef
*error
) {
161 CFTypeRef raw_result
= NULL
;
163 bool internal_spi
= false; // TODO: support this for SecurityDevTests
164 if(internal_spi
&& gSecurityd
&& gSecurityd
->sec_copy_shared_web_credential
) {
165 xpc_result
= gSecurityd
->sec_copy_shared_web_credential(args
, NULL
, NULL
, NULL
, SecAccessGroupsGetCurrent(), &raw_result
, error
);
167 xpc_result
= cftype_client_to_bool_cftype_error_request(sec_copy_shared_web_credential_id
, args
, SecSecurityClientGet(), &raw_result
, error
);
171 if (NULL
== *error
) {
172 SecError(errSecInternal
, error
, CFSTR("Internal error (XPC failure)"));
176 *outError
= (error
) ? *error
: NULL
;
177 CFRetainSafe(*outError
);
179 CFReleaseNull(*error
);
182 raw_result
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
184 *credentials
= raw_result
;
192 void SecRequestSharedWebCredential(CFStringRef fqdn
,
194 void (^completionHandler
)(CFArrayRef credentials
, CFErrorRef error
))
196 __block CFArrayRef result
= NULL
;
197 __block CFErrorRef error
= NULL
;
198 __block dispatch_queue_t dst_queue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
,0);
199 dispatch_retain(dst_queue
);
201 /* sanity check input arguments, if provided */
202 CFStringRef errStr
= NULL
;
203 if (fqdn
&& (CFGetTypeID(fqdn
) != CFStringGetTypeID() || !CFStringGetLength(fqdn
))) {
204 errStr
= CFSTR("fqdn was empty or not a CFString");
206 else if (account
&& (CFGetTypeID(account
) != CFStringGetTypeID() || !CFStringGetLength(account
))) {
207 errStr
= CFSTR("account was empty or not a CFString");
210 SecError(errSecParam
, &error
, errStr
);
211 dispatch_async(dst_queue
, ^{
212 if (completionHandler
) {
213 completionHandler(result
, error
);
215 CFReleaseSafe(error
);
216 CFReleaseSafe(result
);
217 dispatch_release(dst_queue
);
222 __block CFStringRef serverStr
= CFRetainSafe(fqdn
);
223 __block CFStringRef accountStr
= CFRetainSafe(account
);
225 dispatch_async(dst_queue
, ^{
226 OSStatus status
= SecCopySharedWebCredentialSync(serverStr
, accountStr
, &result
, &error
);
227 CFReleaseSafe(serverStr
);
228 CFReleaseSafe(accountStr
);
230 if (status
&& !error
) {
231 SecError(status
, &error
, CFSTR("Error copying shared password"));
233 dispatch_async(dst_queue
, ^{
234 if (completionHandler
) {
235 completionHandler(result
, error
);
237 CFReleaseSafe(error
);
238 CFReleaseSafe(result
);
239 dispatch_release(dst_queue
);
245 CFStringRef
SecCreateSharedWebCredentialPassword(void)
248 CFStringRef password
= NULL
;
249 CFErrorRef error
= NULL
;
250 CFMutableDictionaryRef passwordRequirements
= NULL
;
252 CFStringRef allowedCharacters
= CFSTR("abcdefghkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789");
253 CFCharacterSetRef requiredCharactersLower
= CFCharacterSetCreateWithCharactersInString(NULL
, CFSTR("abcdefghkmnopqrstuvwxyz"));
254 CFCharacterSetRef requiredCharactersUppder
= CFCharacterSetCreateWithCharactersInString(NULL
, CFSTR("ABCDEFGHJKLMNPQRSTUVWXYZ"));
255 CFCharacterSetRef requiredCharactersNumbers
= CFCharacterSetCreateWithCharactersInString(NULL
, CFSTR("3456789"));
259 int totalLength
= (groupSize
* groupCount
);
260 CFNumberRef groupSizeRef
= CFNumberCreate(NULL
, kCFNumberIntType
, &groupSize
);
261 CFNumberRef groupCountRef
= CFNumberCreate(NULL
, kCFNumberIntType
, &groupCount
);
262 CFNumberRef totalLengthRef
= CFNumberCreate(NULL
, kCFNumberIntType
, &totalLength
);
263 CFStringRef separator
= CFSTR("-");
265 CFMutableArrayRef requiredCharacterSets
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
266 CFArrayAppendValue(requiredCharacterSets
, requiredCharactersLower
);
267 CFArrayAppendValue(requiredCharacterSets
, requiredCharactersUppder
);
268 CFArrayAppendValue(requiredCharacterSets
, requiredCharactersNumbers
);
270 passwordRequirements
= CFDictionaryCreateMutable(NULL
, 0, NULL
, NULL
);
271 CFDictionaryAddValue(passwordRequirements
, kSecPasswordAllowedCharactersKey
, allowedCharacters
);
272 CFDictionaryAddValue(passwordRequirements
, kSecPasswordRequiredCharactersKey
, requiredCharacterSets
);
273 CFDictionaryAddValue(passwordRequirements
, kSecPasswordGroupSize
, groupSizeRef
);
274 CFDictionaryAddValue(passwordRequirements
, kSecPasswordNumberOfGroups
, groupCountRef
);
275 CFDictionaryAddValue(passwordRequirements
, kSecPasswordSeparator
, separator
);
276 CFDictionaryAddValue(passwordRequirements
, kSecPasswordMaxLengthKey
, totalLengthRef
);
277 CFDictionaryAddValue(passwordRequirements
, kSecPasswordMinLengthKey
, totalLengthRef
);
278 CFDictionaryAddValue(passwordRequirements
, kSecPasswordDefaultForType
, CFSTR("false"));
279 CFRelease(requiredCharactersLower
);
280 CFRelease(requiredCharactersUppder
);
281 CFRelease(requiredCharactersNumbers
);
282 CFRelease(groupSizeRef
);
283 CFRelease(groupCountRef
);
284 CFRelease(totalLengthRef
);
286 password
= SecPasswordGenerate(kSecPasswordTypeSafari
, &error
, passwordRequirements
);
288 CFRelease(requiredCharacterSets
);
289 CFRelease(passwordRequirements
);
290 if ((error
&& error
!= errSecSuccess
) || !password
)
292 if (password
) CFRelease(password
);
293 secwarning("SecPasswordGenerate failed to generate a password for SecCreateSharedWebCredentialPassword.");