/ SOSCCAuthPlugin / SOSCCAuthPlugin.m
SOSCCAuthPlugin.m
1 // 2 // SOSCCAuthPlugin.m 3 // Security 4 // 5 // Created by Christian Schmidt on 7/8/15. 6 // Copyright 2015 Apple, Inc. All rights reserved. 7 // 8 9 #import "SOSCCAuthPlugin.h" 10 #import <Foundation/Foundation.h> 11 #import <Accounts/Accounts.h> 12 #import <Accounts/Accounts_Private.h> 13 #import <AccountsDaemon/ACDAccountStore.h> 14 #import <AppleAccount/ACAccount+AppleAccount.h> 15 #import <AppleAccount/ACAccountStore+AppleAccount.h> 16 #import <AuthKit/AuthKit.h> 17 #import <AuthKit/AuthKit_Private.h> 18 #import <SoftLinking/SoftLinking.h> 19 #import <Security/SecureObjectSync/SOSCloudCircle.h> 20 #import "utilities/SecCFRelease.h" 21 #import "utilities/debugging.h" 22 23 24 #if !TARGET_OS_SIMULATOR 25 SOFT_LINK_FRAMEWORK(PrivateFrameworks, AuthKit); 26 27 #pragma clang diagnostic push 28 #pragma clang diagnostic ignored "-Wstrict-prototypes" 29 SOFT_LINK_CLASS(AuthKit, AKAccountManager); 30 #pragma clang diagnostic pop 31 #endif 32 33 @implementation SOSCCAuthPlugin 34 35 static bool accountIsHSA2(ACAccount *account) { 36 bool hsa2 = false; 37 38 #if !TARGET_OS_SIMULATOR 39 AKAccountManager *manager = [getAKAccountManagerClass() sharedInstance]; 40 if(manager != nil) { 41 ACAccount *aka = [manager authKitAccountWithAltDSID:account.aa_altDSID]; 42 if (aka) { 43 AKAppleIDSecurityLevel securityLevel = [manager securityLevelForAccount: aka]; 44 if(securityLevel == AKAppleIDSecurityLevelHSA2) { 45 hsa2 = true; 46 } 47 } 48 } 49 #endif 50 secnotice("accounts", "Account %s HSA2", (hsa2) ? "is": "isn't" ); 51 return hsa2; 52 } 53 54 - (void) didReceiveAuthenticationResponseParameters: (NSDictionary *) parameters 55 accountStore: (ACDAccountStore *) store 56 account: (ACAccount *) account 57 completion: (dispatch_block_t) completion 58 { 59 BOOL do_auth = NO; 60 NSString* accountIdentifier = account.identifier; // strong reference 61 secinfo("accounts", "parameters %@", parameters); 62 secinfo("accounts", "account %@", account); 63 64 if ([account.accountType.identifier isEqualToString:ACAccountTypeIdentifierIdentityServices]) { 65 ACAccount *icloud = [store aa_primaryAppleAccount]; 66 NSString *dsid = [parameters[@"com.apple.private.ids"][@"service-data"][@"profile-id"] substringFromIndex:2]; // remove "D:" prefix 67 secinfo("accounts", "IDS account: iCloud %@ (personID %@)", icloud, icloud.aa_personID); 68 do_auth = icloud && icloud.aa_personID && [icloud.aa_personID isEqualToString:dsid]; 69 } else if ([account.accountType.identifier isEqualToString:ACAccountTypeIdentifierAppleAccount]) { 70 do_auth = [account aa_isAccountClass:AAAccountClassPrimary]; 71 secinfo("accounts", "AppleID account: primary %@", @(do_auth)); 72 } 73 74 if(do_auth && !accountIsHSA2(account)) { 75 NSString *rawPassword = [account _aa_rawPassword]; 76 77 if (rawPassword != NULL) { 78 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 79 CFErrorRef asyncError = NULL; 80 NSString *dsid = [account aa_personID]; 81 const char *password = [rawPassword cStringUsingEncoding:NSUTF8StringEncoding]; 82 CFDataRef passwordData = CFDataCreate(kCFAllocatorDefault, (const uint8_t *) password, strlen(password)); 83 84 if (passwordData) { 85 secinfo("accounts", "Performing async SOS circle credential set for account %@: %@", accountIdentifier, account.username); 86 87 if (!SOSCCSetUserCredentialsAndDSID((__bridge CFStringRef) account.username, passwordData, (__bridge CFStringRef) dsid, &asyncError)) { 88 secerror("Unable to set SOS circle credentials for account %@: %@", accountIdentifier, asyncError); 89 secinfo("accounts", "Returning from failed async call to SOSCCSetUserCredentialsAndDSID"); 90 CFReleaseNull(asyncError); 91 } else { 92 secinfo("accounts", "Returning from successful async call to SOSCCSetUserCredentialsAndDSID"); 93 } 94 CFRelease(passwordData); 95 } else { 96 secinfo("accounts", "Failed to create string for call to SOSCCSetUserCredentialsAndDSID"); 97 } 98 }); 99 } else { 100 CFErrorRef authError = NULL; 101 if (!SOSCCCanAuthenticate(&authError)) { 102 secerror("Account %@ did not present a password and we could not authenticate the SOS circle: %@", accountIdentifier, authError); 103 CFReleaseNull(authError); 104 } 105 } 106 } else { 107 secinfo("accounts", "NOT performing SOS circle credential set for account %@: %@", accountIdentifier, account.username); 108 } 109 110 completion(); 111 } 112 113 @end