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.");