SOSAuthKitHelpers.m
1 // 2 // SOSAuthKitHelpers.m 3 // Security 4 // 5 // 6 7 #import <Foundation/Foundation.h> 8 #import "SOSAuthKitHelpers.h" 9 #import <utilities/debugging.h> 10 #import "keychain/SecureObjectSync/SOSAccount.h" 11 #import "keychain/SecureObjectSync/SOSAccountPriv.h" 12 #import "keychain/SecureObjectSync/SOSFullPeerInfo.h" 13 #import "keychain/SecureObjectSync/SOSPeerInfoV2.h" 14 #import "keychain/SecureObjectSync/SOSPeerInfoPriv.h" 15 16 #if !TARGET_OS_BRIDGE && !TARGET_OS_SIMULATOR && __OBJC2__ 17 #import <AppleAccount/AppleAccount_Private.h> 18 #import <AuthKit/AuthKit.h> 19 #import <AuthKit/AuthKit_Private.h> 20 #import <SoftLinking/SoftLinking.h> 21 22 #define SUPPORT_MID 1 23 24 SOFT_LINK_FRAMEWORK(PrivateFrameworks, AuthKit); 25 SOFT_LINK_FRAMEWORK(Frameworks, Accounts); 26 27 #pragma clang diagnostic push 28 #pragma clang diagnostic ignored "-Wstrict-prototypes" 29 SOFT_LINK_CLASS(AuthKit, AKAccountManager); 30 SOFT_LINK_CLASS(AuthKit, AKAnisetteProvisioningController); 31 SOFT_LINK_CLASS(AuthKit, AKAppleIDAuthenticationController); 32 SOFT_LINK_CLASS(AuthKit, AKDeviceListRequestContext); 33 SOFT_LINK_CLASS(Accounts, ACAccountStore); 34 SOFT_LINK_CONSTANT(AuthKit, AKServiceNameiCloud, const NSString *); 35 #pragma clang diagnostic pop 36 37 static void *accountsFramework = NULL; 38 static void *appleAccountFramework = NULL; 39 40 static void 41 initAccountsFramework(void) { 42 static dispatch_once_t onceToken; 43 dispatch_once(&onceToken, ^{ 44 accountsFramework = dlopen("/System/Library/Frameworks/Accounts.framework/Accounts", RTLD_LAZY); 45 appleAccountFramework = dlopen("/System/Library/PrivateFrameworks/AppleAccount.framework/AppleAccount", RTLD_LAZY); 46 }); 47 } 48 49 @implementation SOSAuthKitHelpers 50 51 @class SOSAuthKitHelpers; 52 53 + (NSString *) machineID { 54 NSError *error = nil; 55 NSString *retval = nil; 56 secnotice("sosauthkit", "Entering machineID"); 57 58 AKAnisetteProvisioningController *anisetteController = [getAKAnisetteProvisioningControllerClass() new]; 59 if(anisetteController) { 60 AKAnisetteData *anisetteData = [anisetteController anisetteDataWithError:&error]; 61 if (anisetteData) { 62 retval = [anisetteData.machineID copy]; 63 if(retval) { 64 secnotice("sosauthkit", "machineID is %@", retval); 65 } else { 66 secnotice("sosauthkit", "Failed to get machineID"); 67 } 68 } else { 69 secnotice("sosauthkit", "can't get mID: %@", error); 70 } 71 } else { 72 secnotice("sosauthkit", "can't get controller"); 73 } 74 return retval; 75 } 76 77 static ACAccount *GetPrimaryAccount(void) { 78 ACAccount *primaryAccount; 79 80 initAccountsFramework(); 81 82 ACAccountStore *store = [getACAccountStoreClass() new]; 83 84 if(!store) { 85 secnotice("sosauthkit", "can't get store"); 86 return nil; 87 } 88 89 primaryAccount = [store aa_primaryAppleAccount]; 90 91 return primaryAccount; 92 } 93 94 95 + (void)activeMIDs:(void(^_Nonnull)(NSSet <SOSTrustedDeviceAttributes *> *activeMIDs, NSError *error))complete { 96 ACAccount *primaryAccount; 97 AKDeviceListRequestContext *context; 98 99 primaryAccount = GetPrimaryAccount(); 100 101 if(!primaryAccount) { 102 secnotice("sosauthkit", "can't get account"); 103 complete(NULL, [NSError errorWithDomain:(__bridge NSString *)kSecErrorDomain code:errSecParam userInfo:@{NSLocalizedDescriptionKey : @"no primary account"}]); 104 return; 105 } 106 107 context = [getAKDeviceListRequestContextClass() new]; 108 if (context == NULL) { 109 complete(NULL, [NSError errorWithDomain:(__bridge NSString *)kSecErrorDomain code:errSecParam userInfo:@{NSLocalizedDescriptionKey : @"can't get AKDeviceListRequestContextClass"}]); 110 return; 111 } 112 context.altDSID = primaryAccount.aa_altDSID; 113 context.services = @[ getAKServiceNameiCloud() ]; 114 115 // -[AKAppleIDAuthenticationController fetchDeviceListWithContext:error:] is not exposed, use a semaphore 116 AKAppleIDAuthenticationController *authController = [getAKAppleIDAuthenticationControllerClass() new]; 117 if(!authController) { 118 complete(NULL, [NSError errorWithDomain:(__bridge NSString *)kSecErrorDomain code:errSecParam userInfo:@{NSLocalizedDescriptionKey : @"can't get authController"}]); 119 return; 120 } 121 122 [authController fetchDeviceListWithContext:context completion:^(NSArray<AKRemoteDevice *> *deviceList, NSError *error) { 123 NSMutableSet *mids = [NSMutableSet new]; 124 for(AKRemoteDevice *akdev in deviceList) { 125 SOSTrustedDeviceAttributes *newdev = [SOSTrustedDeviceAttributes new]; 126 newdev.machineID = akdev.machineId; 127 newdev.serialNumber = akdev.serialNumber; 128 [mids addObject:newdev]; 129 } 130 if([mids count] == 0) { 131 secnotice("sosauthkit", "found no devices in account"); 132 mids = nil; 133 } 134 complete(mids, error); 135 }]; 136 } 137 138 + (bool) peerinfoHasMID: (SOSAccount *) account { 139 SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(account.fullPeerInfo); 140 if(!pi) return true; // if there's no PI then just say "we don't need one" 141 return SOSPeerInfoV2DictionaryHasString(pi, sMachineIDKey); 142 } 143 144 145 146 + (bool) updateMIDInPeerInfo: (SOSAccount *) account { 147 NSString *mid = [SOSAuthKitHelpers machineID]; 148 if(!mid) return true; 149 CFErrorRef error = NULL; 150 SOSAccountSetValue(account, sMachineIDKey, (__bridge CFStringRef)mid, &error); 151 bool peerUpdated = SOSAccountUpdatePeerInfoAndPush(account, CFSTR("Add Machine ID"), &error, ^bool(SOSPeerInfoRef pi, CFErrorRef *error) { 152 if(SOSPeerInfoV2DictionaryHasString(pi, sMachineIDKey)) { 153 return false; 154 } 155 secnotice("sosauthkit", "Setting PeerInfo MID to %@", mid); 156 SOSPeerInfoV2DictionarySetValue(pi, sMachineIDKey, (__bridge CFStringRef)mid); 157 return true; 158 }); 159 if(!peerUpdated) { 160 secnotice("sosauthkit", "Failed to record MID in PeerInfo: %@", error); 161 } 162 CFReleaseNull(error); 163 return peerUpdated; 164 } 165 166 167 + (bool) accountIsHSA2 { 168 bool hsa2 = false; 169 170 ACAccount *primaryAccount = GetPrimaryAccount(); 171 AKAccountManager *manager = [getAKAccountManagerClass() new]; 172 173 if(manager && primaryAccount) { 174 ACAccount *account = [manager authKitAccountWithAltDSID:[manager altDSIDForAccount:primaryAccount]]; 175 AKAppleIDSecurityLevel securityLevel = [manager securityLevelForAccount:account]; 176 if(securityLevel == AKAppleIDSecurityLevelHSA2) { 177 hsa2 = true; 178 } else { 179 secnotice("sosauthkit", "Security level is %lu", (unsigned long)securityLevel); 180 } 181 secnotice("sosauthkit", "Account %s HSA2", (hsa2) ? "is": "isn't" ); 182 } else { 183 secnotice("sosauthkit", "Failed to get manager"); 184 } 185 return hsa2; 186 } 187 188 189 -(id) initWithActiveMIDS: (NSSet <SOSTrustedDeviceAttributes *> *) theMidList 190 { 191 if ((self = [super init])) { 192 NSMutableSet *MmachineIDs = [[NSMutableSet alloc] init]; 193 NSMutableSet *MserialNumbers = [[NSMutableSet alloc] init]; 194 _machineIDs = [[NSSet alloc] init]; 195 _serialNumbers = [[NSSet alloc] init]; 196 197 if(!theMidList) return nil; 198 _midList = theMidList; 199 200 for(SOSTrustedDeviceAttributes *dev in _midList) { 201 if(dev.machineID) { 202 [MmachineIDs addObject:dev.machineID]; 203 } 204 if(dev.serialNumber) { 205 [MserialNumbers addObject:dev.serialNumber]; 206 } 207 208 } 209 _machineIDs = MmachineIDs; 210 _serialNumbers = MserialNumbers; 211 } 212 return self; 213 } 214 215 // if the ID passed in is null, the peer doesn't have one, we'll say true - we can't tell from the list 216 - (bool) midIsValidInList: (NSString *) machineId { 217 return (machineId) ? [_machineIDs containsObject:machineId]: true; 218 } 219 220 - (bool) serialIsValidInList: (NSString *) serialNumber { 221 return (serialNumber) ? [_serialNumbers containsObject:serialNumber]: true; 222 } 223 224 - (bool) isUseful { 225 return [ _machineIDs count ] > 0; 226 } 227 228 #else 229 230 231 @implementation SOSAuthKitHelpers 232 233 @class SOSAuthKitHelpers; 234 235 + (NSString *) machineID { 236 return nil; 237 } 238 239 + (void)activeMIDs:(void(^_Nonnull)(NSSet<SOSTrustedDeviceAttributes*> *activeMIDs, NSError *error))complete { 240 complete(nil, nil); 241 } 242 243 + (bool) updateMIDInPeerInfo: (SOSAccount *) account { 244 return true; 245 } 246 247 + (bool) peerinfoHasMID: (SOSAccount *) account { 248 return true; 249 } 250 251 + (bool) accountIsHSA2 { 252 return false; 253 } 254 255 - (id _Nullable) initWithActiveMIDS: (NSSet *_Nullable) theMidList { 256 return nil; 257 } 258 259 - (bool) midIsValidInList: (NSString *_Nullable) machineId { 260 return true; 261 } 262 263 - (bool) serialIsValidInList: (NSString *_Nullable) serialNumber { 264 return true; 265 } 266 267 - (bool) isUseful { 268 return false; 269 } 270 271 #endif 272 273 @end 274