From 805875f8be937062d519339f1e38e2c2e81d06e4 Mon Sep 17 00:00:00 2001 From: Apple Date: Thu, 2 Apr 2020 16:50:48 +0000 Subject: [PATCH] Security-59306.61.1.tar.gz --- KeychainCircle/Tests/FakeSOSControl.m | 11 +- .../KeychainSyncAccountNotification.m | 76 +- OSX/config/security_framework_macos.xcconfig | 4 +- .../authorization.dfr.prompts.strings | 6 +- .../en.lproj/authorization.prompts.strings | 6 +- .../lib/tpPolicies.cpp | 108 +-- OSX/libsecurity_asn1/lib/secport-tapi.h | 46 ++ OSX/libsecurity_codesigning/lib/SecCodePriv.h | 10 + .../lib/AppleBaselineEscrowCertificates.h | 248 ------- .../lib/SecCertificate.cpp | 3 - .../lib/SecCertificateBundle.h | 7 + OSX/libsecurity_smime/lib/cms-tapi.h | 46 ++ OSX/libsecurity_ssl/lib/sslDeprecated.h | 43 ++ .../lib/SecTransformValidator.h | 2 + .../Regressions/secitem/si-25-cms-skid.m | 23 +- .../secitem/si-26-sectrust-copyproperties.c | 5 + OSX/sec/Security/SecEC-tapi.h | 45 ++ OSX/sec/Security/SecExports.exp-in | 10 +- OSX/sec/Security/SecItem.c | 10 +- OSX/sec/Security/SecPolicy-tapi.h | 65 ++ OSX/sec/Security/SecPolicy.c | 89 +-- OSX/sec/Security/SecTrust.c | 27 - OSX/sec/Security/SecTrustInternal.h | 28 + OSX/sec/Security/Security-tapi.h | 55 ++ .../PinningPolicyTrustTest.plist | 46 -- OSX/utilities/SecABC.h | 3 + OSX/utilities/SecABC.m | 14 +- OSX/utilities/SecAppleAnchor-tapi.h | 61 ++ RegressionTests/PreprocessPlist.sh | 16 + RegressionTests/Security.plist | 32 +- RegressionTests/bats_utd_plist.h | 81 +++ SecExperiment/SecExperiment.m | 322 --------- SecExperiment/SecExperimentInternal.h | 34 - SecExperiment/SecExperimentPriv.h | 120 ---- SecExperiment/TLSAssets/Info.plist | 23 - SecExperiment/TLSAssets/Makefile | 35 - SecExperiment/TLSAssets/TLSConfig.plist | 30 - SecExperiment/test/SecExperimentTests.m | 77 -- Security.exp-in | 4 + Security.xcodeproj/project.pbxproj | 656 +++++++++--------- .../xcschemes/osx - World.xcscheme | 10 + SecurityTool/macOS/trusted_cert_ssl.m | 319 ++++----- SecurityTool/macOS/verify_cert.c | 95 ++- SecurityTool/sharedTool/sos.m | 55 +- TestPlan.xctestplan | 18 + base/Security.h | 1 + experiment/SecExperiment.m | 590 ++++++++++++++++ experiment/SecExperimentInternal.h | 141 ++++ experiment/SecExperimentPriv.h | 204 ++++++ experiment/test/SecExperimentTests.m | 358 ++++++++++ .../tool/experimentTool-Entitlements.plist | 5 + experiment/tool/experimentTool.m | 133 ++++ keychain/SecureObjectSync/SOSAccount.h | 3 + keychain/SecureObjectSync/SOSAccount.m | 431 +++++++++--- .../SOSAccountConfiguration.proto | 12 + .../SecureObjectSync/SOSAccountPersistence.m | 3 +- keychain/SecureObjectSync/SOSAccountPriv.h | 12 +- .../SecureObjectSync/SOSAccountRecovery.m | 2 + .../SecureObjectSync/SOSAccountTransaction.m | 17 +- .../SOSAccountTrustClassic+Expansion.m | 36 +- keychain/SecureObjectSync/SOSAccountUpdate.m | 2 + keychain/SecureObjectSync/SOSCircle.c | 2 +- keychain/SecureObjectSync/SOSControlHelper.m | 4 +- keychain/SecureObjectSync/SOSControlServer.m | 27 +- keychain/SecureObjectSync/SOSManifest.c | 2 +- keychain/SecureObjectSync/SOSPeer.m | 5 +- keychain/SecureObjectSync/SOSRingTypes.m | 13 +- keychain/SecureObjectSync/SOSRingUtils.c | 28 +- keychain/SecureObjectSync/SOSTypes.h | 6 +- .../SOSAccountConfiguration.h | 47 ++ .../SOSAccountConfiguration.m | 206 ++++++ keychain/SigninMetrics/OctagonSignPosts.h | 155 +++++ keychain/SigninMetrics/OctagonSignPosts.m | 60 ++ .../Resources/SFTMTests-Info.plist | 0 .../com.apple.security.signposts.plist | 27 + .../SFSignInAnalytics+Internal.h | 0 .../SFSignInAnalytics.h | 0 .../SFSignInAnalytics.m | 0 .../tests/SFSignInAnalyticsTests.m | 4 +- .../Entitlements.plist | 2 + .../OctagonTestHarnessXPCService.m | 111 +++ .../SecRemoteDevice.m | 51 -- .../SecRemoteDeviceProtocol.h | 7 - .../OctagonTestHarnessXPCServiceProtocol.h | 13 + keychain/TrustedPeersHelper/Client.swift | 38 +- keychain/TrustedPeersHelper/Container.swift | 39 ++ .../Container_MachineIDs.swift | 18 + .../TrustedPeersHelperProtocol.h | 14 + .../TrustedPeersHelperProtocol.m | 5 + .../ContainerSync.swift | 20 +- .../TrustedPeersHelperUnitTests.swift | 7 +- keychain/ckks/CKKS.h | 2 +- keychain/ckks/CKKSAnalytics.h | 7 + keychain/ckks/CKKSAnalytics.m | 7 + .../CKKSFetchAllRecordZoneChangesOperation.h | 2 + keychain/ckks/CKKSKeychainView.m | 56 +- keychain/ckks/CKKSNearFutureScheduler.h | 3 + keychain/ckks/CKKSNearFutureScheduler.m | 1 - keychain/ckks/CKKSOutgoingQueueOperation.m | 24 + keychain/ckks/CKKSPBFileStorage.h | 29 + keychain/ckks/CKKSPBFileStorage.m | 56 ++ keychain/ckks/CKKSResultOperation.h | 4 +- keychain/ckks/CKKSResultOperation.m | 1 + keychain/ckks/CKKSZoneChangeFetcher.h | 4 +- keychain/ckks/CKKSZoneChangeFetcher.m | 69 +- keychain/ckks/CKKSZoneModifier.m | 4 +- keychain/ckks/CloudKitCategories.h | 2 + keychain/ckks/CloudKitCategories.m | 16 + keychain/ckks/OctagonAPSReceiver.h | 9 +- keychain/ckks/OctagonAPSReceiver.m | 25 +- keychain/ckks/tests/CKKSAPSHandlingTests.m | 28 +- keychain/ckks/tests/CKKSPBFileStorageTests.m | 49 ++ keychain/ckks/tests/CKKSTests.m | 76 ++ keychain/ckks/tests/CloudKitMockXCTest.h | 9 + keychain/ckks/tests/CloudKitMockXCTest.m | 69 +- keychain/ckks/tests/MockCloudKit.h | 3 + keychain/ckks/tests/MockCloudKit.m | 41 ++ .../escrowrequest/EscrowRequestController.m | 7 +- keychain/ot/CuttlefishXPCWrapper.m | 45 ++ keychain/ot/OTAuthKitAdapter.h | 2 +- keychain/ot/OTAuthKitAdapter.m | 72 +- keychain/ot/OTClientStateMachine.m | 1 - keychain/ot/OTClique.m | 341 +++++++-- keychain/ot/OTConstants.h | 2 +- keychain/ot/OTConstants.m | 2 +- keychain/ot/OTCuttlefishContext.h | 4 + keychain/ot/OTCuttlefishContext.m | 97 ++- keychain/ot/OTDefines.h | 12 +- .../OTDetermineHSA2AccountStatusOperation.m | 6 +- keychain/ot/OTManager.m | 55 +- keychain/ot/OTPrepareOperation.m | 9 +- keychain/ot/OTSOSUpgradeOperation.m | 6 +- keychain/ot/OTSetRecoveryKeyOperation.m | 9 +- keychain/ot/OTStates.h | 4 +- keychain/ot/OTStates.m | 24 + keychain/ot/OTVouchWithBottleOperation.m | 6 +- keychain/ot/OTVouchWithRecoveryKeyOperation.m | 7 +- keychain/ot/ObjCImprovements.h | 2 +- keychain/ot/OctagonCKKSPeerAdapter.m | 2 +- keychain/ot/OctagonFlags.h | 7 +- keychain/ot/OctagonFlags.m | 19 + keychain/ot/OctagonStateMachine.h | 4 +- keychain/ot/OctagonStateMachine.m | 33 +- keychain/ot/OctagonStateMachineHelpers.h | 3 +- keychain/ot/OctagonStateMachineHelpers.m | 3 +- keychain/ot/OctagonStateMachineObservers.h | 4 +- keychain/ot/OctagonStateMachineObservers.m | 64 +- .../octagon/OctagonTests+DeviceList.swift | 30 +- .../octagon/OctagonTests+ErrorHandling.swift | 20 +- .../octagon/OctagonTests+RecoveryKey.swift | 3 +- .../ot/tests/octagon/OctagonTests+Reset.swift | 10 +- .../ot/tests/octagon/OctagonTests+SOS.swift | 25 +- .../octagon/OctagonTests-BridgingHeader.h | 2 + keychain/ot/tests/octagon/OctagonTests.swift | 123 +++- .../securityd/Regressions/SOSAccountTesting.h | 47 +- .../Regressions/secd-62-account-backup.m | 4 +- .../Regressions/secd-66-account-recovery.m | 6 +- keychain/securityd/SOSCloudCircleServer.h | 4 +- keychain/securityd/SOSCloudCircleServer.m | 316 +++++++-- keychain/securityd/SecDbKeychainItemV7.m | 2 +- .../securityd/SecDbKeychainMetadataKeyStore.m | 23 +- keychain/tpctl/main.swift | 26 + protocol/SecProtocol.c | 127 ++-- protocol/SecProtocolPriv.h | 73 +- protocol/SecProtocolTest.m | 95 ++- secdxctests/KeychainAPITests.m | 18 + securityd/etc/com.apple.securityd.sb | 1 + .../TestCopyProperties_ios.plist | 2 +- .../MockAKSOptionalParameters.proto | 7 + tests/secdmockaks/MockAKSRefKey.proto | 6 + .../MockAKSOptionalParameters.h | 43 ++ .../MockAKSOptionalParameters.m | 194 ++++++ .../generated_source/MockAKSRefKey.h | 39 ++ .../generated_source/MockAKSRefKey.m | 159 +++++ tests/secdmockaks/mockaks.h | 32 +- tests/secdmockaks/mockaks.m | 300 ++++++-- tests/secdmockaks/mockaksKeychain.m | 274 ++++++++ tests/secdmockaks/mockaksxcbase.m | 1 + trust/trustd/SecRevocationDb.c | 8 +- trust/trustd/SecTrustServer.c | 12 +- trust/trustd/SecTrustServer.h | 1 + trust/trustd/md.h | 23 + trust/trustd/md.m | 43 ++ xcconfig/PlatformLibraries.xcconfig | 2 +- xcconfig/Security.xcconfig | 6 +- 185 files changed, 6868 insertions(+), 2572 deletions(-) create mode 100644 OSX/libsecurity_asn1/lib/secport-tapi.h delete mode 100644 OSX/libsecurity_keychain/lib/AppleBaselineEscrowCertificates.h create mode 100644 OSX/libsecurity_smime/lib/cms-tapi.h create mode 100644 OSX/libsecurity_ssl/lib/sslDeprecated.h create mode 100644 OSX/sec/Security/SecEC-tapi.h create mode 100644 OSX/sec/Security/SecPolicy-tapi.h create mode 100644 OSX/sec/Security/Security-tapi.h create mode 100644 OSX/utilities/SecAppleAnchor-tapi.h create mode 100755 RegressionTests/PreprocessPlist.sh create mode 100644 RegressionTests/bats_utd_plist.h delete mode 100644 SecExperiment/SecExperiment.m delete mode 100644 SecExperiment/SecExperimentInternal.h delete mode 100644 SecExperiment/SecExperimentPriv.h delete mode 100644 SecExperiment/TLSAssets/Info.plist delete mode 100644 SecExperiment/TLSAssets/Makefile delete mode 100644 SecExperiment/TLSAssets/TLSConfig.plist delete mode 100644 SecExperiment/test/SecExperimentTests.m create mode 100644 TestPlan.xctestplan create mode 100644 experiment/SecExperiment.m create mode 100644 experiment/SecExperimentInternal.h create mode 100644 experiment/SecExperimentPriv.h create mode 100644 experiment/test/SecExperimentTests.m create mode 100644 experiment/tool/experimentTool-Entitlements.plist create mode 100644 experiment/tool/experimentTool.m create mode 100644 keychain/SecureObjectSync/SOSAccountConfiguration.proto create mode 100644 keychain/SecureObjectSync/generated_source/SOSAccountConfiguration.h create mode 100644 keychain/SecureObjectSync/generated_source/SOSAccountConfiguration.m create mode 100644 keychain/SigninMetrics/OctagonSignPosts.h create mode 100644 keychain/SigninMetrics/OctagonSignPosts.m rename keychain/{Signin Metrics => SigninMetrics}/Resources/SFTMTests-Info.plist (100%) create mode 100644 keychain/SigninMetrics/Resources/com.apple.security.signposts.plist rename keychain/{Signin Metrics => SigninMetrics}/SFSignInAnalytics+Internal.h (100%) rename keychain/{Signin Metrics => SigninMetrics}/SFSignInAnalytics.h (100%) rename keychain/{Signin Metrics => SigninMetrics}/SFSignInAnalytics.m (100%) rename keychain/{Signin Metrics => SigninMetrics}/tests/SFSignInAnalyticsTests.m (99%) create mode 100644 keychain/ckks/CKKSPBFileStorage.h create mode 100644 keychain/ckks/CKKSPBFileStorage.m create mode 100644 keychain/ckks/tests/CKKSPBFileStorageTests.m create mode 100644 tests/secdmockaks/MockAKSOptionalParameters.proto create mode 100644 tests/secdmockaks/MockAKSRefKey.proto create mode 100644 tests/secdmockaks/generated_source/MockAKSOptionalParameters.h create mode 100644 tests/secdmockaks/generated_source/MockAKSOptionalParameters.m create mode 100644 tests/secdmockaks/generated_source/MockAKSRefKey.h create mode 100644 tests/secdmockaks/generated_source/MockAKSRefKey.m create mode 100644 trust/trustd/md.h create mode 100644 trust/trustd/md.m diff --git a/KeychainCircle/Tests/FakeSOSControl.m b/KeychainCircle/Tests/FakeSOSControl.m index e0a2c500..b8edbae9 100644 --- a/KeychainCircle/Tests/FakeSOSControl.m +++ b/KeychainCircle/Tests/FakeSOSControl.m @@ -139,7 +139,7 @@ complete(true, NULL); } -- (void)triggerSync:(NSArray *)peers complete:(void(^)(bool success, NSError *))complete +- (void)rpcTriggerSync:(NSArray *)peers complete:(void(^)(bool success, NSError *))complete { complete(true, NULL); } @@ -328,4 +328,13 @@ complete(nil, nil); } +- (void)rpcTriggerBackup:(NSArray *)backupPeers complete:(void (^)(NSError *))complete { + complete(nil); +} + +- (void)rpcTriggerRingUpdate:(void (^)(NSError *))complete { + complete(nil); +} + + @end diff --git a/KeychainSyncAccountNotification/KeychainSyncAccountNotification.m b/KeychainSyncAccountNotification/KeychainSyncAccountNotification.m index 7120509f..030606c4 100644 --- a/KeychainSyncAccountNotification/KeychainSyncAccountNotification.m +++ b/KeychainSyncAccountNotification/KeychainSyncAccountNotification.m @@ -36,29 +36,27 @@ #if OCTAGON if(OctagonIsEnabled()){ - __block NSError* error = nil; - NSString* altDSID = [account aa_altDSID]; + secnotice("octagon-account", "Received an primary Apple account modification (altDSID %@)", altDSID); + + __block NSError* error = nil; - OTControl* otcontrol = [OTControl controlObject:&error]; + // Use asynchronous XPC here for speed and just hope it works + OTControl* otcontrol = [OTControl controlObject:false error:&error]; if (nil == otcontrol) { - secerror("octagon: Failed to get OTControl: %@", error.localizedDescription); + secerror("octagon-account: Failed to get OTControl: %@", error.localizedDescription); } else { - dispatch_semaphore_t sema = dispatch_semaphore_create(0); - [otcontrol signIn:altDSID container:nil context:OTDefaultContext reply:^(NSError * _Nullable signedInError) { + // take a retain on otcontrol so it won't invalidate the connection + (void)otcontrol; + if(signedInError) { - secerror("octagon: error signing in: %s", [[signedInError description] UTF8String]); + secerror("octagon-account: error signing in: %s", [[signedInError description] UTF8String]); } else { - secnotice("octagon", "account now signed in for octagon operation"); + secnotice("octagon-account", "account now signed in for octagon operation"); } - dispatch_semaphore_signal(sema); - }]; - if (0 != dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 60 * 5))) { - secerror("octagon: Timed out signing in"); - } } }else{ secerror("Octagon not enabled; not signing in"); @@ -70,7 +68,8 @@ #if OCTAGON if([account.accountType.identifier isEqualToString: ACAccountTypeIdentifierIDMS]) { - secnotice("octagon-authkit", "Received an IDMS account modification"); + NSString* altDSID = [account aa_altDSID];; + secnotice("octagon-authkit", "Received an IDMS account modification (altDSID: %@)", altDSID); AKAccountManager *manager = [AKAccountManager sharedInstance]; @@ -78,37 +77,35 @@ AKAppleIDSecurityLevel newSecurityLevel = [manager securityLevelForAccount:account]; if(oldSecurityLevel != newSecurityLevel) { - NSString* identifier = account.identifier; - secnotice("octagon-authkit", "IDMS security level has now moved to %ld for %@", (unsigned long)newSecurityLevel, identifier); + secnotice("octagon-authkit", "IDMS security level has now moved to %ld for altDSID %@", (unsigned long)newSecurityLevel, altDSID); __block NSError* error = nil; - OTControl* otcontrol = [OTControl controlObject:&error]; + // Use an asynchronous otcontrol for Speed But Not Necessarily Correctness + OTControl* otcontrol = [OTControl controlObject:false error:&error]; if(!otcontrol || error) { secerror("octagon-authkit: Failed to get OTControl: %@", error); } else { - dispatch_semaphore_t sema = dispatch_semaphore_create(0); - [otcontrol notifyIDMSTrustLevelChangeForContainer:nil context:OTDefaultContext reply:^(NSError * _Nullable idmsError) { - if(idmsError) { - secerror("octagon-authkit: error with idms trust level change in: %s", [[idmsError description] UTF8String]); - } else { - secnotice("octagon-authkit", "informed octagon of IDMS trust level change"); - } - dispatch_semaphore_signal(sema); + // take a retain on otcontrol so it won't invalidate the connection + (void)otcontrol; + + if(idmsError) { + secerror("octagon-authkit: error with idms trust level change in: %s", [[idmsError description] UTF8String]); + } else { + secnotice("octagon-authkit", "informed octagon of IDMS trust level change"); + } }]; - - if (0 != dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 5))) { - secerror("octagon-authkit: Timed out altering IDMS change in"); - } } } else { - secnotice("octagon-authkit", "No change to IDMS security level"); + secnotice("octagon-authkit", "No change to IDMS security level (%lu) for altDSID %@", (unsigned long)newSecurityLevel, altDSID); } } #endif if ((changeType == kACAccountChangeTypeDeleted) && [oldAccount.accountType.identifier isEqualToString:ACAccountTypeIdentifierAppleAccount]) { + NSString* altDSID = [oldAccount aa_altDSID]; + secnotice("octagon-account", "Received an Apple account deletion (altDSID %@)", altDSID); NSString *accountIdentifier = oldAccount.identifier; NSString *username = oldAccount.username; @@ -127,25 +124,22 @@ if(OctagonIsEnabled()){ __block NSError* error = nil; - OTControl* otcontrol = [OTControl controlObject:&error]; + // Use an asynchronous control for Speed + OTControl* otcontrol = [OTControl controlObject:false error:&error]; if (nil == otcontrol) { - secerror("octagon: Failed to get OTControl: %@", error.localizedDescription); + secerror("octagon-account: Failed to get OTControl: %@", error.localizedDescription); } else { - dispatch_semaphore_t sema = dispatch_semaphore_create(0); - [otcontrol signOut:nil context:OTDefaultContext reply:^(NSError * _Nullable signedInError) { + // take a retain on otcontrol so it won't invalidate the connection + (void)otcontrol; + if(signedInError) { - secerror("octagon: error signing out: %s", [[signedInError description] UTF8String]); + secerror("octagon-account: error signing out: %s", [[signedInError description] UTF8String]); } else { - secnotice("octagon", "signed out of octagon trust"); + secnotice("octagon-account", "signed out of octagon trust"); } - dispatch_semaphore_signal(sema); - }]; - if (0 != dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 60 * 5))) { - secerror("octagon: Timed out signing out"); - } } } else { secerror("Octagon not enabled; not signing out"); diff --git a/OSX/config/security_framework_macos.xcconfig b/OSX/config/security_framework_macos.xcconfig index b9708656..f341fbd7 100644 --- a/OSX/config/security_framework_macos.xcconfig +++ b/OSX/config/security_framework_macos.xcconfig @@ -19,7 +19,9 @@ INFOPLIST_FILE = OSX/lib/Info-Security.plist INSTALL_PATH = $(SYSTEM_LIBRARY_DIR)/Frameworks ASAN_EXTRA_LDFLAGS_YES = -Wl,-no_warn_inits -OTHER_LDFLAGS = -laks -lCrashReporterClient -Wl,-upward_framework,Foundation -Wl,-no_inits $(ASAN_EXTRA_LDFLAGS_$(ENABLE_ADDRESS_SANITIZER)) +ASAN_EXTRA_LDFLAGS_NO = -Wl,-no_inits +ASAN_EXTRA_LDFLAGS_ = $(ASAN_EXTRA_LDFLAGS_NO) +OTHER_LDFLAGS = -laks -lCrashReporterClient -Wl,-upward_framework,Foundation $(ASAN_EXTRA_LDFLAGS_$(ENABLE_ADDRESS_SANITIZER)) SECTORDER_FLAGS = -order_file_statistics APPLY_RULES_IN_COPY_FILES = NO diff --git a/OSX/lib/en.lproj/authorization.dfr.prompts.strings b/OSX/lib/en.lproj/authorization.dfr.prompts.strings index 2ee028fd..e54e35f7 100644 --- a/OSX/lib/en.lproj/authorization.dfr.prompts.strings +++ b/OSX/lib/en.lproj/authorization.dfr.prompts.strings @@ -56,7 +56,7 @@ "com.apple.docset.install" = "Touch ID to Update the Developer Documentation."; -"com.apple.Safari.parental-controls" = "Touch ID to Modify the Parental Controls Settings for Safari."; +"com.apple.Safari.parental-controls" = "Touch ID to Modify the Screen Time Settings for Safari."; "com.apple.Safari.allow-unsigned-app-extensions" = "Touch ID to Allow Unsigned Extensions."; @@ -86,7 +86,7 @@ "system.preferences.sharing" = "Touch ID to Unlock the Sharing Preferences."; -"system.preferences.parental-controls" = "Touch ID to Unlock Parental Controls Preferences."; +"system.preferences.parental-controls" = "Touch ID to Unlock Screen Time Preferences."; "system.preferences.security" = "Touch ID to Unlock Security & Privacy Preferences."; @@ -144,7 +144,7 @@ "com.apple.AOSNotification.FindMyMac.remove" = "Touch ID to Turn Off Find My Mac."; -"com.apple.iBooksX.ParentalControl" = "Touch ID to Unlock Your Parental Controls Preferences."; +"com.apple.iBooksX.ParentalControl" = "Touch ID to Unlock Your Screen Time Preferences."; "system.services.networkextension.vpn" = "Touch ID to Modify the VPN Configuration."; diff --git a/OSX/lib/en.lproj/authorization.prompts.strings b/OSX/lib/en.lproj/authorization.prompts.strings index 7986719b..1686dbd6 100644 --- a/OSX/lib/en.lproj/authorization.prompts.strings +++ b/OSX/lib/en.lproj/authorization.prompts.strings @@ -56,7 +56,7 @@ "com.apple.docset.install" = "__APPNAME__ is trying to update the developer documentation."; -"com.apple.Safari.parental-controls" = "__APPNAME__ is trying to modify the Parental Controls settings for Safari."; +"com.apple.Safari.parental-controls" = "__APPNAME__ is trying to modify the Screen Time settings for Safari."; "com.apple.Safari.allow-unsigned-app-extensions" = "__APPNAME__ is trying to allow unsigned extensions."; @@ -86,7 +86,7 @@ "system.preferences.sharing" = "__APPNAME__ is trying to unlock the Sharing preferences."; -"system.preferences.parental-controls" = "__APPNAME__ is trying to unlock Parental Controls preferences."; +"system.preferences.parental-controls" = "__APPNAME__ is trying to unlock Screen Time preferences."; "system.preferences.security" = "__APPNAME__ is trying to unlock Security & Privacy preferences."; @@ -144,7 +144,7 @@ "com.apple.AOSNotification.FindMyMac.remove" = "__APPNAME__ is trying to turn off Find My Mac."; -"com.apple.iBooksX.ParentalControl" = "__APPNAME__ is trying to unlock Parental Controls preferences."; +"com.apple.iBooksX.ParentalControl" = "__APPNAME__ is trying to unlock Screen Time preferences."; "system.services.networkextension.vpn" = "__APPNAME__ is trying to modify the VPN configuration."; diff --git a/OSX/libsecurity_apple_x509_tp/lib/tpPolicies.cpp b/OSX/libsecurity_apple_x509_tp/lib/tpPolicies.cpp index 786c21f1..17c152f8 100644 --- a/OSX/libsecurity_apple_x509_tp/lib/tpPolicies.cpp +++ b/OSX/libsecurity_apple_x509_tp/lib/tpPolicies.cpp @@ -2325,110 +2325,6 @@ cleanup: return crtn; } -/* - * Verify Escrow Service policy options. - * - * -- Chain length must be exactly 2. - * -- Must be issued by known escrow root. - * -- Key usage in leaf certificate must be Key Encipherment. - * -- Leaf has CSSMOID_APPLE_EXTENSION_ESCROW_SERVICE_MARKER extension - * (1.2.840.113635.100.6.23.1) - */ -static CSSM_RETURN tp_verifyEscrowServiceCommon(TPCertGroup &certGroup, - const CSSM_DATA *fieldOpts, - const iSignCertInfo *certInfo, // all certs, size certGroup.numCerts() - SecCertificateEscrowRootType rootType) -{ - unsigned numCerts = certGroup.numCerts(); - const iSignCertInfo *isCertInfo; - TPCertInfo *tpCert; - CE_KeyUsage ku; - CSSM_RETURN crtn = CSSM_OK; - - isCertInfo = &certInfo[0]; - tpCert = certGroup.certAtIndex(0); - - /* Check that KU extension is present */ - if (!isCertInfo->keyUsage.present) { - tpPolicyError("tp_verifyEscrowServiceCommon: no keyUsage in leaf"); - tpCert->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION); - crtn = CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION; - goto cleanup; - } - - /* Check that KU contains Key Encipherment usage */ - ku = isCertInfo->keyUsage.extnData->keyUsage; - if (!(ku & CE_KU_KeyEncipherment)) { - tpPolicyError("tp_verifyEscrowServiceCommon: KeyEncipherment usage not found"); - tpCert->addStatusCode(CSSMERR_APPLETP_INVALID_KEY_USAGE); - crtn = CSSMERR_APPLETP_INVALID_KEY_USAGE; - goto cleanup; - } - - /* Check that Escrow Service marker extension is present */ - if (!(isCertInfo->foundEscrowServiceMarker == CSSM_TRUE)) { - tpPolicyError("tp_verifyEscrowServiceCommon: no Escrow Service extension in leaf"); - tpCert->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION); - crtn = CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION; - goto cleanup; - } - - /* Check that cert chain length is 2 */ - if (numCerts != 2) { - tpPolicyError("tp_verifyEscrowServiceCommon: numCerts %u", numCerts); - crtn = CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH; - goto cleanup; - } - - /* Check that cert chain is anchored by a known root */ - { - tpCert = certGroup.certAtIndex(numCerts-1); - const CSSM_DATA *certData = tpCert->itemData(); - bool anchorMatch = false; - SecCertificateRef anchor = NULL; - OSStatus status = SecCertificateCreateFromData(certData, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, &anchor); - if (!status) { - CFArrayRef anchors = SecCertificateCopyEscrowRoots(rootType); - CFIndex idx, count = (anchors) ? CFArrayGetCount(anchors) : 0; - for (idx = 0; idx < count; idx++) { - SecCertificateRef cert = (SecCertificateRef) CFArrayGetValueAtIndex(anchors, idx); - if (cert && CFEqual(cert, anchor)) { - anchorMatch = true; - break; - } - } - if (anchors) - CFRelease(anchors); - } - if (anchor) - CFRelease(anchor); - - if (!anchorMatch) { - tpPolicyError("tp_verifyEscrowServiceCommon: invalid anchor for policy"); - tpCert->addStatusCode(CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH); - crtn = CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH; - goto cleanup; - } - } - -cleanup: - return crtn; -} - -static CSSM_RETURN tp_verifyEscrowServiceSigningOpts(TPCertGroup &certGroup, - const CSSM_DATA *fieldOpts, - const iSignCertInfo *certInfo) // all certs, size certGroup.numCerts() -{ - return tp_verifyEscrowServiceCommon(certGroup, fieldOpts, certInfo, kSecCertificateProductionEscrowRoot); -} - -static CSSM_RETURN tp_verifyPCSEscrowServiceSigningOpts(TPCertGroup &certGroup, - const CSSM_DATA *fieldOpts, - const iSignCertInfo *certInfo) // all certs, size certGroup.numCerts() -{ - return tp_verifyEscrowServiceCommon(certGroup, fieldOpts, certInfo, kSecCertificateProductionPCSEscrowRoot); -} - /* * Verify Provisioning Profile Signing policy options. * @@ -3169,7 +3065,7 @@ CSSM_RETURN tp_policyVerify( policyError = tp_verifyMobileStoreSigningOpts(*certGroup, policyFieldData, certInfo, true); break; case kTP_EscrowService: - policyError = tp_verifyEscrowServiceSigningOpts(*certGroup, policyFieldData, certInfo); + policyFail = CSSM_TRUE; break; case kTP_ProfileSigning: policyError = tp_verifyProfileSigningOpts(*certGroup, policyFieldData, certInfo, false); @@ -3178,7 +3074,7 @@ CSSM_RETURN tp_policyVerify( policyError = tp_verifyProfileSigningOpts(*certGroup, policyFieldData, certInfo, true); break; case kTP_PCSEscrowService: - policyError = tp_verifyPCSEscrowServiceSigningOpts(*certGroup, policyFieldData, certInfo); + policyFail = CSSM_TRUE; break; case kTP_ProvisioningProfileSigning: policyError = tp_verifyProvisioningProfileSigningOpts(*certGroup, policyFieldData, certInfo); diff --git a/OSX/libsecurity_asn1/lib/secport-tapi.h b/OSX/libsecurity_asn1/lib/secport-tapi.h new file mode 100644 index 00000000..e0054f05 --- /dev/null +++ b/OSX/libsecurity_asn1/lib/secport-tapi.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * TAPI coverage for exported functions. + */ + +#ifndef _SECPORT_TAPI_H_ +#define _SECPORT_TAPI_H_ + +#ifndef SECURITY_PROJECT_TAPI_HACKS +#error This header is not for inclusion; it's a nasty hack to get the iOS Security framework to build with TAPI. +#endif + +#if TARGET_OS_OSX + +typedef struct PLArenaPool PLArenaPool; +typedef int PRIntn; +typedef PRIntn PRBool; + +extern void PORT_FreeArena(PLArenaPool *arena, PRBool zero); +extern PLArenaPool *PORT_NewArena(unsigned long chunksize); + +#endif /* TARGET_OS_OSX */ + +#endif /* _SECPORT_TAPI_H_ */ diff --git a/OSX/libsecurity_codesigning/lib/SecCodePriv.h b/OSX/libsecurity_codesigning/lib/SecCodePriv.h index f4d8e2a7..d88239c8 100644 --- a/OSX/libsecurity_codesigning/lib/SecCodePriv.h +++ b/OSX/libsecurity_codesigning/lib/SecCodePriv.h @@ -232,6 +232,16 @@ CF_ENUM(uint32_t) { kSecCSStrictValidateStructure = 1 << 13, }; +#if TARGET_OS_OSX +/* Here just to make TAPI happy. */ +extern int GKBIS_DS_Store_Present; +extern int GKBIS_Dot_underbar_Present; +extern int GKBIS_Num_localizations; +extern int GKBIS_Num_files; +extern int GKBIS_Num_dirs; +extern int GKBIS_Num_symlinks; +#endif /* TARGET_OS_OSX */ + #ifdef __cplusplus } #endif diff --git a/OSX/libsecurity_keychain/lib/AppleBaselineEscrowCertificates.h b/OSX/libsecurity_keychain/lib/AppleBaselineEscrowCertificates.h deleted file mode 100644 index ba5e31dc..00000000 --- a/OSX/libsecurity_keychain/lib/AppleBaselineEscrowCertificates.h +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (c) 2013-2016 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - -#ifndef sec_AppleBaselineEscrowCertificates_h -#define sec_AppleBaselineEscrowCertificates_h - -struct RootRecord -{ - size_t _length; - UInt8* _bytes; -}; - -/* ========================================================================== - Production Escrow Certificates - ========================================================================== */ - - -static const UInt8 kBaseLineEscrowRootGM[] = { - 0x30,0x82,0x03,0xd0,0x30,0x82,0x02,0xb8,0xa0,0x03,0x02,0x01,0x02,0x02,0x01,0x64, - 0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0b,0x05,0x00,0x30, - 0x79,0x31,0x0c,0x30,0x0a,0x06,0x03,0x55,0x04,0x05,0x13,0x03,0x31,0x30,0x30,0x31, - 0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11, - 0x06,0x03,0x55,0x04,0x0a,0x13,0x0a,0x41,0x70,0x70,0x6c,0x65,0x20,0x49,0x6e,0x63, - 0x2e,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0b,0x13,0x1d,0x41,0x70,0x70,0x6c, - 0x65,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20, - 0x41,0x75,0x74,0x68,0x6f,0x72,0x69,0x74,0x79,0x31,0x1f,0x30,0x1d,0x06,0x03,0x55, - 0x04,0x03,0x13,0x16,0x45,0x73,0x63,0x72,0x6f,0x77,0x20,0x53,0x65,0x72,0x76,0x69, - 0x63,0x65,0x20,0x52,0x6f,0x6f,0x74,0x20,0x43,0x41,0x30,0x1e,0x17,0x0d,0x31,0x33, - 0x30,0x38,0x30,0x32,0x32,0x33,0x32,0x34,0x34,0x34,0x5a,0x17,0x0d,0x32,0x33,0x30, - 0x38,0x30,0x32,0x32,0x33,0x32,0x34,0x34,0x34,0x5a,0x30,0x79,0x31,0x0c,0x30,0x0a, - 0x06,0x03,0x55,0x04,0x05,0x13,0x03,0x31,0x30,0x30,0x31,0x0b,0x30,0x09,0x06,0x03, - 0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0a, - 0x13,0x0a,0x41,0x70,0x70,0x6c,0x65,0x20,0x49,0x6e,0x63,0x2e,0x31,0x26,0x30,0x24, - 0x06,0x03,0x55,0x04,0x0b,0x13,0x1d,0x41,0x70,0x70,0x6c,0x65,0x20,0x43,0x65,0x72, - 0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x41,0x75,0x74,0x68,0x6f, - 0x72,0x69,0x74,0x79,0x31,0x1f,0x30,0x1d,0x06,0x03,0x55,0x04,0x03,0x13,0x16,0x45, - 0x73,0x63,0x72,0x6f,0x77,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x20,0x52,0x6f, - 0x6f,0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48, - 0x86,0xf7,0x0d,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0f,0x00,0x30,0x82,0x01, - 0x0a,0x02,0x82,0x01,0x01,0x00,0xd0,0xa3,0xf4,0x56,0x7d,0x3f,0x46,0x31,0xd2,0x56, - 0xa0,0xdf,0x42,0xa0,0x29,0x83,0x1e,0xb9,0x82,0xb5,0xa5,0xff,0x3e,0xde,0xb5,0x0f, - 0x4a,0x8a,0x28,0x60,0xcf,0x75,0xb4,0xa0,0x70,0x7c,0xf5,0xe2,0x94,0xf3,0x22,0x02, - 0xc8,0x81,0xce,0x34,0xc7,0x66,0x6a,0x18,0xaa,0xb4,0xfd,0x6d,0xb0,0x0b,0xdd,0x4a, - 0xdd,0xcf,0xe0,0x08,0x1b,0x1c,0xa6,0xdb,0xba,0xb2,0xc1,0xa4,0x10,0x5f,0x35,0x4f, - 0x8b,0x8b,0x7a,0xa3,0xdb,0x3c,0xf6,0x54,0x95,0x42,0xad,0x2a,0x3b,0xfe,0x06,0x8c, - 0xe1,0x92,0xf1,0x60,0x97,0x58,0x1b,0xd9,0x8f,0xbe,0xfb,0x46,0x4c,0x29,0x5c,0x1c, - 0xf0,0x20,0xb6,0x2b,0xa5,0x12,0x09,0x9b,0x28,0x41,0x34,0x97,0x9f,0xf3,0x88,0x4b, - 0x69,0x72,0xea,0x3a,0x27,0xb0,0x50,0x1d,0x88,0x29,0x0d,0xbb,0xed,0x04,0xa2,0x11, - 0xcf,0x0c,0x5b,0x65,0x61,0x35,0xbd,0xf2,0x0d,0xfc,0xe2,0xb9,0x20,0xd3,0xb7,0x03, - 0x70,0x39,0xd5,0xe0,0x86,0x7c,0x04,0xcc,0xc9,0xa1,0x85,0xb4,0x9b,0xbc,0x88,0x4e, - 0xd7,0xad,0x5c,0xff,0x2c,0x0d,0x80,0x8e,0x51,0x39,0x20,0x8b,0xaf,0x1e,0x46,0x95, - 0xfa,0x0d,0x1b,0xd2,0xbf,0x80,0xe0,0x9f,0x6d,0x4a,0xf5,0x31,0x67,0x18,0x11,0xa5, - 0x63,0x27,0x08,0xee,0xd9,0x07,0x29,0xd0,0xd4,0x36,0x91,0x5b,0xfb,0x4a,0x0b,0x07, - 0xd1,0x0d,0x79,0x16,0x6e,0x16,0x02,0x23,0x80,0xc6,0x15,0x07,0x6d,0xa0,0x06,0xb6, - 0x45,0x90,0xb0,0xae,0xa4,0xad,0x0e,0x75,0x04,0x2b,0x2b,0x78,0xf1,0x57,0x84,0x23, - 0x87,0x24,0xec,0x58,0xc4,0xf1,0x02,0x03,0x01,0x00,0x01,0xa3,0x63,0x30,0x61,0x30, - 0x0f,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff, - 0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01,0xff,0x04,0x04,0x03,0x02,0x01,0x06, - 0x30,0x1d,0x06,0x03,0x55,0x1d,0x0e,0x04,0x16,0x04,0x14,0xfd,0x78,0x96,0x53,0x80, - 0xd6,0xf6,0xdc,0xa6,0xc3,0x59,0x06,0x38,0xed,0x79,0x3e,0x8f,0x50,0x1b,0x50,0x30, - 0x1f,0x06,0x03,0x55,0x1d,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xfd,0x78,0x96,0x53, - 0x80,0xd6,0xf6,0xdc,0xa6,0xc3,0x59,0x06,0x38,0xed,0x79,0x3e,0x8f,0x50,0x1b,0x50, - 0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0b,0x05,0x00,0x03, - 0x82,0x01,0x01,0x00,0x71,0x15,0xca,0x87,0xd0,0x2d,0xb5,0x18,0xd5,0x35,0x7a,0xcd, - 0xdf,0x62,0x28,0xf0,0x0b,0x63,0x4d,0x4e,0x02,0xba,0x3d,0xb8,0xb4,0x37,0xea,0xb0, - 0x93,0x93,0xab,0x1c,0xfd,0x9f,0xe8,0x72,0xbf,0xf3,0xdb,0xe6,0xad,0x16,0xfe,0x71, - 0x61,0xa8,0x5a,0xd0,0x58,0x0f,0x65,0x7a,0x57,0x7a,0xe0,0x34,0x80,0x8e,0xbb,0x41, - 0x01,0xe7,0xb0,0x3b,0xf7,0x2b,0x3a,0x6d,0x44,0x2a,0x3a,0x04,0x52,0xfa,0x2b,0x7b, - 0x3b,0x21,0xdd,0x0c,0x70,0x3d,0xfb,0x45,0xc6,0x79,0x68,0x62,0xe2,0x89,0xb8,0x25, - 0xee,0x63,0x76,0x02,0xb2,0x22,0xe9,0x53,0x85,0x68,0x3e,0x75,0xb6,0x0b,0x65,0xe9, - 0x1c,0xba,0x84,0x93,0xb0,0x8a,0xef,0xb5,0x1a,0x12,0xe4,0x8f,0xae,0xd5,0x5c,0xa1, - 0x05,0x4a,0x01,0xbc,0x6f,0xf9,0x58,0x5e,0xf7,0x04,0x61,0xee,0xf5,0xc6,0xa0,0x1b, - 0x44,0x2e,0x5a,0x3a,0x59,0xa1,0xb3,0xb0,0xf4,0xb6,0xcb,0xe0,0x6c,0x2b,0x59,0x8a, - 0xfb,0x6a,0xe0,0xa2,0x57,0x09,0x79,0xc1,0xdd,0xfb,0x84,0x86,0xeb,0x66,0x29,0x73, - 0xae,0xbf,0x58,0xae,0x47,0x4d,0x48,0x37,0xd6,0xb1,0x8c,0x5f,0x26,0x5f,0xb5,0x26, - 0x07,0x0b,0x85,0xb7,0x36,0x37,0x14,0xcf,0x5e,0x55,0xa5,0x3c,0xf3,0x1e,0x79,0x50, - 0xbb,0x85,0x3b,0xb2,0x94,0x68,0xb0,0x25,0x4f,0x75,0xec,0xf0,0xf9,0xc0,0x5a,0x2d, - 0xe5,0xed,0x67,0xcd,0x88,0x55,0xa0,0x42,0xde,0x78,0xbc,0xfe,0x30,0xb1,0x62,0x2d, - 0xe1,0xfd,0xec,0x75,0x03,0xa6,0x1f,0x7c,0xc4,0x3a,0x4a,0x59,0xfe,0x77,0xc3,0x99, - 0x96,0x87,0x44,0xc3, -}; - -static const UInt8 kBaseLinePCSEscrowRootGM[] = { - 0x30,0x82,0x03,0xD8,0x30,0x82,0x02,0xC0,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x64, - 0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30, - 0x7D,0x31,0x0C,0x30,0x0A,0x06,0x03,0x55,0x04,0x05,0x13,0x03,0x31,0x30,0x30,0x31, - 0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11, - 0x06,0x03,0x55,0x04,0x0A,0x13,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63, - 0x2E,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0B,0x13,0x1D,0x41,0x70,0x70,0x6C, - 0x65,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20, - 0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31,0x23,0x30,0x21,0x06,0x03,0x55, - 0x04,0x03,0x13,0x1A,0x45,0x66,0x66,0x61,0x63,0x65,0x61,0x62,0x6C,0x65,0x20,0x53, - 0x65,0x72,0x76,0x69,0x63,0x65,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x1E, - 0x17,0x0D,0x31,0x34,0x30,0x37,0x32,0x38,0x32,0x31,0x30,0x33,0x35,0x32,0x5A,0x17, - 0x0D,0x32,0x34,0x30,0x37,0x32,0x38,0x32,0x31,0x30,0x33,0x35,0x32,0x5A,0x30,0x7D, - 0x31,0x0C,0x30,0x0A,0x06,0x03,0x55,0x04,0x05,0x13,0x03,0x31,0x30,0x30,0x31,0x0B, - 0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06, - 0x03,0x55,0x04,0x0A,0x13,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E, - 0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0B,0x13,0x1D,0x41,0x70,0x70,0x6C,0x65, - 0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41, - 0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31,0x23,0x30,0x21,0x06,0x03,0x55,0x04, - 0x03,0x13,0x1A,0x45,0x66,0x66,0x61,0x63,0x65,0x61,0x62,0x6C,0x65,0x20,0x53,0x65, - 0x72,0x76,0x69,0x63,0x65,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x82,0x01, - 0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00, - 0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xC0,0x55, - 0xCC,0x74,0xCF,0x49,0xE9,0xEC,0x9A,0x76,0x17,0x30,0x12,0x40,0x7D,0xC1,0x69,0x98, - 0x97,0x2C,0xA7,0xC0,0xD6,0xF4,0x9A,0x1D,0xC2,0x46,0x75,0xB6,0xAD,0x81,0xE2,0x2F, - 0x65,0xF1,0xAF,0xF6,0xBA,0xBD,0xC1,0x44,0x37,0x93,0xB8,0x92,0x2A,0x83,0xCC,0xE3, - 0x6F,0xFD,0x95,0xAA,0x86,0xAE,0x4D,0x62,0x98,0xBC,0xE6,0x90,0x40,0x5B,0x5A,0x2E, - 0x65,0x0C,0xFF,0x07,0xB9,0x79,0xC4,0x2E,0x2E,0x72,0x80,0xE3,0xB9,0x98,0x08,0xE9, - 0x3B,0x79,0x3B,0x46,0x99,0xD7,0xB9,0xDF,0x1F,0xC4,0x0D,0x49,0xB9,0x78,0x39,0xAF, - 0x7F,0xF5,0xDC,0x9C,0xEE,0xC1,0xB0,0x90,0x70,0x97,0xD6,0xE7,0x49,0x0C,0x11,0x19, - 0xE9,0xDD,0xEA,0x38,0x30,0xB9,0x1D,0xF4,0xD7,0xFF,0xBB,0xFC,0x6B,0x49,0xFC,0x69, - 0xE8,0x05,0x8E,0x96,0x14,0x87,0x62,0xD6,0x82,0x2F,0xA2,0x97,0xB5,0x4A,0x80,0x46, - 0x43,0xF5,0xF2,0x1B,0x94,0xBF,0xFE,0x48,0x8B,0x7F,0x4D,0xD6,0x3D,0x3E,0x64,0xBE, - 0x09,0x7C,0x9E,0x24,0x80,0xDE,0xAB,0xC9,0x17,0x91,0xAC,0x60,0x06,0x98,0x9C,0xCB, - 0xAD,0x04,0x41,0x1F,0x7F,0xE5,0xC2,0x08,0xD5,0x80,0xD7,0x63,0xF1,0x5C,0x60,0xA2, - 0xE5,0xAD,0x5F,0x6E,0xBC,0x3A,0xC4,0x9F,0x4D,0xE4,0x65,0xA3,0xF2,0x18,0x0B,0x1A, - 0x2D,0xB4,0x64,0x3D,0x53,0x5A,0x14,0xF6,0x26,0x92,0x13,0x23,0x83,0x33,0xBE,0xE0, - 0xA4,0x43,0xFC,0x79,0xA0,0x91,0xFB,0x1C,0x17,0xF0,0x87,0xE5,0x8C,0x68,0xF2,0xCF, - 0xAE,0x3B,0xC5,0xD5,0xD2,0x58,0x8E,0xFB,0x29,0x53,0xFE,0x9E,0xDE,0x4F,0x02,0x03, - 0x01,0x00,0x01,0xA3,0x63,0x30,0x61,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01, - 0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01, - 0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04, - 0x16,0x04,0x14,0x64,0x0B,0xE4,0x72,0x73,0x5C,0x54,0xB2,0x58,0x59,0xAE,0x42,0xDF, - 0x2B,0xB7,0xBA,0xB9,0xEB,0x86,0xAE,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18, - 0x30,0x16,0x80,0x14,0x64,0x0B,0xE4,0x72,0x73,0x5C,0x54,0xB2,0x58,0x59,0xAE,0x42, - 0xDF,0x2B,0xB7,0xBA,0xB9,0xEB,0x86,0xAE,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86, - 0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x79,0xF4,0x22,0xC9, - 0x6C,0x25,0x64,0x2D,0x8E,0x91,0x53,0x7B,0xFB,0xA7,0xD2,0x0C,0xAD,0xDC,0xA9,0x83, - 0x90,0x75,0x16,0x98,0xC1,0x2C,0xFE,0x7C,0x16,0xCE,0x2A,0xA0,0xB8,0x8A,0xF6,0xDB, - 0x3E,0x2D,0x6C,0x5D,0x61,0x41,0x10,0xBB,0x02,0xBA,0x51,0x5B,0x42,0x62,0x18,0x9F, - 0xC4,0x25,0xF3,0x24,0xCC,0x1D,0xD2,0xFF,0x47,0xB2,0x14,0x9E,0x6A,0x31,0xA3,0xA7, - 0xB1,0x0C,0x7E,0x55,0xCE,0xC4,0x9E,0xA6,0x0A,0x06,0x9B,0x50,0x40,0x04,0x13,0xA0, - 0xC7,0x4D,0x37,0xD9,0x85,0xCF,0xB2,0xD9,0x16,0x38,0x4B,0xA3,0xA5,0x3E,0xDC,0x06, - 0x0D,0xE0,0xB1,0x13,0x7C,0x8B,0x79,0x1F,0x67,0xD8,0xBA,0xB4,0x58,0x9C,0x84,0x18, - 0xE4,0xED,0x22,0x17,0x41,0xA9,0x3B,0x88,0xD5,0x55,0x54,0x5F,0x33,0x4D,0xE2,0xBD, - 0xBE,0x66,0x46,0x59,0xC0,0x60,0xC5,0xB2,0x7A,0xF6,0xCA,0xCD,0xB9,0x2D,0xBD,0x50, - 0xB3,0xD6,0x18,0xD5,0x1F,0xFA,0x42,0x30,0x4C,0x10,0xFB,0x12,0xA9,0x9A,0x0E,0x39, - 0xFA,0x77,0xB6,0x82,0x53,0xF3,0x35,0x74,0xB5,0x10,0x5A,0x22,0xAE,0x17,0x25,0xD1, - 0x09,0xB9,0x71,0x08,0xA1,0xFA,0x2D,0xB9,0xEA,0x8C,0xC5,0xAC,0x31,0x6C,0x45,0x46, - 0x2E,0x11,0x2D,0x75,0x07,0x88,0x39,0xA3,0x14,0x08,0xA6,0xBF,0x7B,0x2C,0x26,0xAE, - 0x28,0xE9,0x1D,0x6C,0xFF,0xAC,0x99,0x53,0x44,0x91,0x26,0x2E,0x82,0x1A,0x11,0x66, - 0xB5,0x9C,0xEF,0x9E,0xC1,0x52,0x8F,0xCE,0x12,0xF3,0x88,0x86,0x06,0xF0,0xE8,0x62, - 0x69,0x12,0x04,0x6D,0x2B,0x75,0x83,0xE1,0x12,0xFC,0x3E,0xF1, -}; - -static const UInt8 kBaseLineACFEscrowRootGM[] = { - 0x30,0x82,0x03,0xD0,0x30,0x82,0x02,0xB8,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x65, - 0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30, - 0x79,0x31,0x0C,0x30,0x0A,0x06,0x03,0x55,0x04,0x05,0x13,0x03,0x31,0x30,0x31,0x31, - 0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11, - 0x06,0x03,0x55,0x04,0x0A,0x13,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63, - 0x2E,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0B,0x13,0x1D,0x41,0x70,0x70,0x6C, - 0x65,0x20,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20, - 0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55, - 0x04,0x03,0x13,0x16,0x45,0x73,0x63,0x72,0x6F,0x77,0x20,0x53,0x65,0x72,0x76,0x69, - 0x63,0x65,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x31,0x35, - 0x30,0x35,0x31,0x36,0x30,0x35,0x32,0x38,0x32,0x31,0x5A,0x17,0x0D,0x34,0x39,0x30, - 0x35,0x31,0x36,0x30,0x35,0x32,0x38,0x32,0x31,0x5A,0x30,0x79,0x31,0x0C,0x30,0x0A, - 0x06,0x03,0x55,0x04,0x05,0x13,0x03,0x31,0x30,0x31,0x31,0x0B,0x30,0x09,0x06,0x03, - 0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A, - 0x13,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x26,0x30,0x24, - 0x06,0x03,0x55,0x04,0x0B,0x13,0x1D,0x41,0x70,0x70,0x6C,0x65,0x20,0x43,0x65,0x72, - 0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F, - 0x72,0x69,0x74,0x79,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03,0x13,0x16,0x45, - 0x73,0x63,0x72,0x6F,0x77,0x20,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x20,0x52,0x6F, - 0x6F,0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48, - 0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01, - 0x0A,0x02,0x82,0x01,0x01,0x00,0xD4,0xA6,0xF0,0x01,0x97,0xDA,0x08,0x7D,0xA5,0xF9, - 0xB5,0x48,0x9D,0x4E,0x4C,0x30,0x5A,0x67,0xE4,0x12,0x6F,0x4C,0x36,0x4B,0xC6,0xE1, - 0x1F,0x6B,0x41,0xF2,0x46,0x21,0x0D,0x71,0x3D,0xCF,0xB4,0x6C,0x67,0x92,0x9B,0x37, - 0x39,0x24,0x25,0xD2,0x7B,0xFF,0x54,0xF2,0x44,0x4A,0x08,0xE2,0xE5,0xB2,0xB7,0xC9, - 0x56,0xCE,0x25,0x2E,0x41,0xBB,0xED,0xCC,0x24,0x8E,0x05,0x0F,0x28,0xDF,0xE3,0xAB, - 0xCA,0xA1,0x7C,0xCC,0xE6,0x66,0x15,0x89,0xD7,0x5C,0x68,0x35,0x48,0x9D,0xD3,0xDA, - 0x80,0x8E,0xE7,0xEE,0x15,0x73,0x67,0xD2,0xB1,0xF9,0xB3,0x09,0x4F,0xBA,0x2F,0x09, - 0x76,0xEE,0x9F,0x08,0x0D,0x8E,0x34,0x6D,0x14,0x4B,0xD7,0x57,0x17,0xE3,0xEC,0x23, - 0x6E,0xC3,0xA1,0xBD,0x2F,0xC3,0x22,0x9D,0x0E,0x8E,0x67,0x8D,0x78,0xB9,0x50,0xCB, - 0x08,0x82,0xAB,0xAC,0x90,0x91,0x45,0x86,0x18,0x7C,0x0A,0xF5,0xBA,0x22,0x67,0x4B, - 0xED,0x5F,0xC0,0x92,0xB3,0x07,0x06,0x64,0xA7,0xDA,0x11,0x13,0xF8,0xDD,0xA0,0xA8, - 0xFC,0xC9,0xF0,0xA5,0xF1,0xA5,0x90,0xF9,0x13,0xDA,0xF9,0x07,0x16,0xD6,0x38,0xCC, - 0x22,0x37,0x37,0x42,0xB3,0x6A,0x63,0xAA,0x76,0x9E,0xB3,0x87,0xA4,0x36,0x3B,0xE3, - 0x54,0x20,0x00,0x33,0x93,0x09,0x2C,0x46,0x9E,0x69,0x86,0x83,0xD8,0xE9,0xC0,0x42, - 0x5B,0x04,0x16,0x0D,0xE2,0x86,0x9F,0x57,0x0F,0xB7,0x56,0xB8,0x6E,0xE0,0x58,0xD8, - 0x78,0xDE,0xAC,0xF1,0x52,0x07,0x49,0xA5,0xC9,0x97,0x6F,0x26,0x49,0x35,0x71,0x14, - 0x38,0x11,0x3E,0x76,0x7C,0xD9,0x02,0x03,0x01,0x00,0x01,0xA3,0x63,0x30,0x61,0x30, - 0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF, - 0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06, - 0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x8C,0xC8,0x0F,0xA1,0x55, - 0xB0,0x84,0x7B,0x8D,0xC1,0x99,0x8C,0xF3,0x4F,0x18,0xB5,0x0F,0x83,0x80,0x6F,0x30, - 0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x8C,0xC8,0x0F,0xA1, - 0x55,0xB0,0x84,0x7B,0x8D,0xC1,0x99,0x8C,0xF3,0x4F,0x18,0xB5,0x0F,0x83,0x80,0x6F, - 0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03, - 0x82,0x01,0x01,0x00,0x43,0x8D,0xA8,0x86,0x77,0xB7,0xF5,0xA8,0xD8,0xE5,0x32,0xE5, - 0xE7,0xAA,0x99,0x04,0x4C,0xD2,0x86,0x81,0x4B,0x72,0x89,0xBA,0x40,0x14,0xAD,0x75, - 0xDB,0xA1,0xBF,0xC3,0x73,0x22,0xAF,0xAE,0x33,0xAC,0xB3,0x13,0x62,0xB2,0x3D,0xCA, - 0xD3,0xBC,0x45,0x7A,0xC2,0xBC,0x2C,0xCA,0xA1,0x3F,0xD9,0x52,0xA8,0x54,0xC2,0x44, - 0xB8,0x6B,0xA5,0xCA,0xF4,0x7D,0xF6,0xE3,0x0B,0x1F,0x38,0x16,0x67,0xF1,0x0B,0xA8, - 0x2A,0xDC,0x72,0xC8,0x87,0x3B,0x44,0x55,0xF7,0x0F,0x04,0x57,0x67,0xF1,0x11,0x91, - 0xA0,0xD2,0x78,0xEC,0x8C,0xBB,0x76,0x24,0x66,0x4F,0xA1,0xFE,0xBB,0xDE,0x00,0x01, - 0x9F,0x30,0x18,0x27,0x32,0xFF,0xFF,0xF6,0x9B,0xEA,0x43,0x36,0x67,0x2F,0x83,0x97, - 0x4D,0xE8,0x4E,0x9C,0xC1,0xEE,0x24,0xC8,0x21,0x72,0xFB,0x12,0xA9,0x2E,0x65,0xDE, - 0x84,0xB8,0xFF,0xC4,0xAB,0xDB,0x5D,0x3A,0xE9,0x3C,0x8F,0x1C,0x26,0x65,0x5F,0x34, - 0x50,0xB2,0x60,0x76,0x8B,0x42,0x64,0x5A,0x59,0xEA,0xD1,0x4E,0x23,0xF4,0xC8,0x28, - 0x8F,0x60,0xE5,0x75,0x36,0x3B,0x4C,0x38,0xC9,0x0F,0xCD,0x54,0x79,0x47,0x1D,0xC3, - 0x2F,0x9B,0x33,0x39,0x9F,0x50,0xD2,0x0B,0x68,0x3D,0x8A,0xCA,0x1F,0x5A,0xA5,0x5E, - 0x29,0x68,0x96,0xC2,0x1E,0x02,0xBA,0x8F,0x9C,0x55,0xB3,0x2E,0x24,0x2C,0x58,0xD8, - 0xAC,0xE4,0xF0,0x6C,0xDE,0x16,0x47,0x37,0x0D,0xA8,0x5C,0x09,0x4B,0x23,0x4D,0x21, - 0xFD,0xFF,0xCD,0x50,0xD5,0x59,0x0E,0x37,0x63,0xD0,0xA5,0xC7,0xBF,0xDD,0x88,0xF3, - 0x81,0xB1,0x3F,0x4E, -}; - - -static struct RootRecord kBaseLineEscrowRootRecord = {sizeof(kBaseLineEscrowRootGM), (UInt8*)kBaseLineEscrowRootGM}; -static struct RootRecord kBaseLineACFEscrowRootRecord = {sizeof(kBaseLineACFEscrowRootGM), (UInt8*)kBaseLineACFEscrowRootGM}; -static struct RootRecord* kBaseLineEscrowRoots[] = {&kBaseLineEscrowRootRecord, &kBaseLineACFEscrowRootRecord}; -static struct RootRecord* kBaseLineEscrowBackupRoots[] = {&kBaseLineEscrowRootRecord, &kBaseLineACFEscrowRootRecord}; -static struct RootRecord* kBaseLineEscrowEnrollmentRoots[] = {&kBaseLineACFEscrowRootRecord}; -static const int kNumberOfBaseLineEscrowRoots = (int)(sizeof(kBaseLineEscrowRoots)/sizeof(kBaseLineEscrowRoots[0])); -static const int kNumberOfBaseLineEscrowBackupRoots = (int)(sizeof(kBaseLineEscrowBackupRoots)/sizeof(kBaseLineEscrowBackupRoots[0])); -static const int kNumberOfBaseLineEscrowEnrollmentRoots = (int)(sizeof(kBaseLineEscrowEnrollmentRoots)/sizeof(kBaseLineEscrowEnrollmentRoots[0])); - -static struct RootRecord kBaseLinePCSEscrowRootRecord = {sizeof(kBaseLinePCSEscrowRootGM), (UInt8*)kBaseLinePCSEscrowRootGM}; -static struct RootRecord* kBaseLinePCSEscrowRoots[] = {&kBaseLinePCSEscrowRootRecord}; -static const int kNumberOfBaseLinePCSEscrowRoots = (int)(sizeof(kBaseLinePCSEscrowRoots)/sizeof(kBaseLinePCSEscrowRoots[0])); - -#endif diff --git a/OSX/libsecurity_keychain/lib/SecCertificate.cpp b/OSX/libsecurity_keychain/lib/SecCertificate.cpp index 7c1e40b4..ca154314 100644 --- a/OSX/libsecurity_keychain/lib/SecCertificate.cpp +++ b/OSX/libsecurity_keychain/lib/SecCertificate.cpp @@ -46,9 +46,6 @@ #include #include "CertificateValues.h" -#include "AppleBaselineEscrowCertificates.h" - - OSStatus SecCertificateGetCLHandle_legacy(SecCertificateRef certificate, CSSM_CL_HANDLE *clHandle); extern CSSM_KEYUSE ConvertArrayToKeyUsage(CFArrayRef usage); diff --git a/OSX/libsecurity_keychain/lib/SecCertificateBundle.h b/OSX/libsecurity_keychain/lib/SecCertificateBundle.h index d2bc3e10..a20f1bc1 100644 --- a/OSX/libsecurity_keychain/lib/SecCertificateBundle.h +++ b/OSX/libsecurity_keychain/lib/SecCertificateBundle.h @@ -70,6 +70,13 @@ OSStatus SecCertificateBundleExport( CSSM_CERT_BUNDLE_ENCODING encodingType, CSSM_DATA* data) DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; +/* misspelled version of above */ +OSStatus SecCertifcateBundleExport( + CFArrayRef itemList, + CSSM_CERT_BUNDLE_TYPE type, + CSSM_CERT_BUNDLE_ENCODING encodingType, + CSSM_DATA* data) DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER; + #if defined(__cplusplus) } #endif diff --git a/OSX/libsecurity_smime/lib/cms-tapi.h b/OSX/libsecurity_smime/lib/cms-tapi.h new file mode 100644 index 00000000..3866e63c --- /dev/null +++ b/OSX/libsecurity_smime/lib/cms-tapi.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * CMS coverage for exported functions. + */ + +#ifndef _CMS_TAPI_H_ +#define _CMS_TAPI_H_ + +#ifndef SECURITY_PROJECT_TAPI_HACKS +#error This header is not for inclusion; it's a nasty hack to get the iOS Security framework to build with TAPI. +#endif + +#if TARGET_OS_OSX + +typedef struct cssm_data CSSM_DATA; + +typedef OSStatus (*SecCmsTSACallback)(const void *context, void *messageImprint, uint64_t nonce, CSSM_DATA *tstoken); + +extern void +SecCmsMessageSetTSACallback(SecCmsMessageRef cmsg, SecCmsTSACallback tsaCallback); + +#endif /* TARGET_OS_OSX */ + +#endif /* _CMS_TAPI_H_ */ diff --git a/OSX/libsecurity_ssl/lib/sslDeprecated.h b/OSX/libsecurity_ssl/lib/sslDeprecated.h new file mode 100644 index 00000000..54703bf7 --- /dev/null +++ b/OSX/libsecurity_ssl/lib/sslDeprecated.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * Deprecated functions for TAPI. + */ + +#ifndef _SECURITY_SSL_DEPRECATED_H_ +#define _SECURITY_SSL_DEPRECATED_H_ + +#ifndef SECURITY_PROJECT_TAPI_HACKS +#error This header is not for inclusion; it's a nasty hack to get the iOS Security framework to build with TAPI. +#endif + +#if TARGET_OS_OSX + +OSStatus +SSLGetPeerCertificates (SSLContextRef ctx, + CFArrayRef *certs); + +#endif /* TARGET_OS_OSX */ + +#endif /* _SECURITY_SSL_DEPRECATED_H_ */ diff --git a/OSX/libsecurity_transform/lib/SecTransformValidator.h b/OSX/libsecurity_transform/lib/SecTransformValidator.h index e6c8a496..2e69f243 100644 --- a/OSX/libsecurity_transform/lib/SecTransformValidator.h +++ b/OSX/libsecurity_transform/lib/SecTransformValidator.h @@ -24,6 +24,8 @@ #ifndef _SEC_TRANSFORMVALIDATOR_H__ #define _SEC_TRANSFORMVALIDATOR_H__ +#include + CF_EXTERN_C_BEGIN diff --git a/OSX/sec/Security/Regressions/secitem/si-25-cms-skid.m b/OSX/sec/Security/Regressions/secitem/si-25-cms-skid.m index d6d53b98..7ed59fb0 100644 --- a/OSX/sec/Security/Regressions/secitem/si-25-cms-skid.m +++ b/OSX/sec/Security/Regressions/secitem/si-25-cms-skid.m @@ -28,6 +28,7 @@ #import #import +#import #include #import "si-25-cms-skid.h" @@ -39,22 +40,28 @@ static void test_cms_verification(void) SecPolicyRef policy = SecPolicyCreateBasicX509(); SecTrustRef trust = NULL; - SecTrustResultType trustResult = kSecTrustResultInvalid; + CFArrayRef certificates = NULL; ok_status(SecCMSVerify((__bridge CFDataRef)signedData, (__bridge CFDataRef)content, policy, &trust, NULL), "verify CMS message"); - //10 Sept 2016 - ok_status(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)[NSDate dateWithTimeIntervalSinceReferenceDate:495245242.0]), "set verify date"); - ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust"); - is(trustResult, kSecTrustResultUnspecified, "trust suceeded"); + /* verify that CMS stack found the certs in the CMS (using the SKID) and stuck them in the trust ref */ + ok_status(SecTrustCopyInputCertificates(trust, &certificates), "copy input certificates"); +#if TARGET_OS_OSX + // macOS implementation of CMS puts the leaf first and then adds all certs (so the signer cert is included twice) + is(CFArrayGetCount(certificates), 4, "4 certs in the cms"); +#else + // embedded implementation of CMS just orders the certs so the signer cert is first + is(CFArrayGetCount(certificates), 3, "3 certs in the cms"); +#endif - CFReleaseSafe(policy); - CFRetainSafe(trust); + CFReleaseNull(policy); + CFReleaseNull(trust); + CFReleaseNull(certificates); } int si_25_cms_skid(int argc, char *const *argv) { - plan_tests(4); + plan_tests(3); test_cms_verification(); diff --git a/OSX/sec/Security/Regressions/secitem/si-26-sectrust-copyproperties.c b/OSX/sec/Security/Regressions/secitem/si-26-sectrust-copyproperties.c index c6bfdcfa..9119beb2 100644 --- a/OSX/sec/Security/Regressions/secitem/si-26-sectrust-copyproperties.c +++ b/OSX/sec/Security/Regressions/secitem/si-26-sectrust-copyproperties.c @@ -412,7 +412,12 @@ static void tests(void) properties = SecCertificateCopyProperties(leaf); isnt(properties, NULL, "leaf properties returned"); CFReleaseNull(properties); + // Xcode doesn't have a SDK for 10.15.1 so we need to work around this. + // rdar://problem/55890533 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability" properties = SecCertificateCopyLocalizedProperties(leaf, true); +#pragma clang diagnostic pop isnt(properties, NULL, "localized leaf properties returned"); CFReleaseNull(properties); diff --git a/OSX/sec/Security/SecEC-tapi.h b/OSX/sec/Security/SecEC-tapi.h new file mode 100644 index 00000000..fe4c8e0d --- /dev/null +++ b/OSX/sec/Security/SecEC-tapi.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2019 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * TAPI coverage for exported functions. + */ + +#ifndef _SECEC_TAPI_H_ +#define _SECEC_TAPI_H_ + +#ifndef SECURITY_PROJECT_TAPI_HACKS +#error This header is not for inclusion; it's a nasty hack to get the iOS Security framework to build with TAPI. +#endif + +#include +#include + +__BEGIN_DECLS + +bool SecECDoWithFullKey(SecKeyRef key, CFErrorRef* error,void (^action)(ccec_full_ctx_t full_key)); +bool SecECDoWithPubKey(SecKeyRef key, CFErrorRef* error, void (^action)(ccec_pub_ctx_t pub_key)); + +__END_DECLS + +#endif diff --git a/OSX/sec/Security/SecExports.exp-in b/OSX/sec/Security/SecExports.exp-in index 89695818..7067b56d 100644 --- a/OSX/sec/Security/SecExports.exp-in +++ b/OSX/sec/Security/SecExports.exp-in @@ -1788,6 +1788,8 @@ _sec_protocol_options_set_tls_is_fallback_attempt _sec_protocol_options_set_verify_block _sec_protocol_options_set_tls_diffie_hellman_parameters _sec_protocol_options_set_peer_authentication_required +_sec_protocol_options_set_experiment_identifier +_sec_protocol_metadata_get_experiment_identifier _sec_protocol_options_create_config _sec_protocol_options_matches_config _sec_protocol_options_apply_config @@ -1814,6 +1816,7 @@ _sec_protocol_options_append_tls_key_exchange_group _sec_protocol_options_append_tls_key_exchange_group_set _sec_protocol_options_add_tls_key_exchange_group _sec_protocol_options_add_tls_key_exchange_group_set +_sec_protocol_options_set_connection_id _sec_protocol_metadata_get_handshake_time_ms _sec_protocol_metadata_get_handshake_byte_count _sec_protocol_metadata_get_handshake_sent_byte_count @@ -1822,6 +1825,7 @@ _sec_protocol_metadata_get_handshake_read_stall_count _sec_protocol_metadata_get_handshake_write_stall_count _sec_protocol_metadata_get_handshake_async_call_count _sec_protocol_metadata_access_pre_shared_keys +_sec_protocol_metadata_copy_connection_id _sec_protocol_options_set_pre_shared_key_selection_block _sec_protocol_helper_ciphersuite_group_to_ciphersuite_list _sec_release @@ -1832,13 +1836,15 @@ _sec_trust_create // // SecExperiment // -_kSecExperimentTLSMobileAssetConfig +_kSecExperimentTLSProbe _kSecExperimentDefaultsDomain _sec_experiment_run +_sec_experiment_run_async +_sec_experiment_run_with_sampling_disabled +_sec_experiment_run_async_with_sampling_disabled _sec_experiment_create _sec_experiment_copy_configuration _sec_experiment_set_sampling_disabled -_sec_experiment_get_identifier // // SecureTransport diff --git a/OSX/sec/Security/SecItem.c b/OSX/sec/Security/SecItem.c index 433acca7..b526d632 100644 --- a/OSX/sec/Security/SecItem.c +++ b/OSX/sec/Security/SecItem.c @@ -1188,6 +1188,8 @@ static bool SecItemAttributesPrepare(SecCFDictionaryCOW *attrs, bool forQuery, C SecAccessControlRef access_control = (SecAccessControlRef)CFDictionaryGetValue(attrs->dictionary, kSecAttrAccessControl); if (access_control != NULL) { + require_action_quiet(CFGetTypeID(access_control) == SecAccessControlGetTypeID(), out, + SecError(errSecParam, error, CFSTR("Unexpected type of kSecAttrAccessControl attribute"))); require_action_quiet(ac_data = SecAccessControlCopyData(access_control), out, SecError(errSecParam, error, CFSTR("unsupported kSecAttrAccessControl in query"))); CFDictionarySetValue(SecCFDictionaryCOWGetMutable(attrs), kSecAttrAccessControl, ac_data); @@ -1421,12 +1423,14 @@ bool SecItemAuthDoQuery(SecCFDictionaryCOW *query, SecCFDictionaryCOW *attribute bool (^perform)(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributes, CFDictionaryRef auth_params, CFErrorRef *error)) { bool ok = false; __block SecCFDictionaryCOW auth_params = { NULL }; - SecAccessControlRef access_control = NULL; __block TKTokenRef token = NULL; + CFDictionaryRef dict = attributes ? attributes->dictionary : query->dictionary; + SecAccessControlRef access_control = (SecAccessControlRef)CFDictionaryGetValue(dict, kSecAttrAccessControl); + require_action_quiet(access_control == NULL || CFGetTypeID(access_control) == SecAccessControlGetTypeID(), out, + SecError(errSecParam, error, CFSTR("Unexpected type of kSecAttrAccessControl attribute"))); + if (secItemOperation == SecItemAdd || secItemOperation == SecItemUpdate) { - CFDictionaryRef dict = attributes ? attributes->dictionary : query->dictionary; - access_control = (SecAccessControlRef)CFDictionaryGetValue(dict, kSecAttrAccessControl); if (access_control && SecAccessControlGetConstraints(access_control) && CFEqualSafe(CFDictionaryGetValue(dict, kSecAttrSynchronizable), kCFBooleanTrue)) require_quiet(SecError(errSecParam, error, CFSTR("item with kSecAttrAccessControl is not synchronizable")), out); diff --git a/OSX/sec/Security/SecPolicy-tapi.h b/OSX/sec/Security/SecPolicy-tapi.h new file mode 100644 index 00000000..cdd5846d --- /dev/null +++ b/OSX/sec/Security/SecPolicy-tapi.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2008-2017 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*! + @header SecPolicyPriv + The functions provided in SecPolicyInternal provide the interface to + trust policies used by SecTrust. +*/ + +#ifndef _SECURITY_SECPOLICYTAPI_H_ +#define _SECURITY_SECPOLICYTAPI_H_ + +#ifndef SECURITY_PROJECT_TAPI_HACKS +#error This header is not for inclusion; it's a nasty hack to get the iOS Security framework to build with TAPI. +#endif + +#include + +#include +#include +#include +#include +#include + +__BEGIN_DECLS + +#if TARGET_OS_OSX + +/******************************************************** + ****************** SecPolicy struct ******************** + ********************************************************/ +struct __SecPolicy { + CFRuntimeBase _base; + CFStringRef _oid; + CFStringRef _name; + CFDictionaryRef _options; +}; + +SecPolicyRef SecPolicyCreate(CFStringRef oid, CFStringRef name, CFDictionaryRef options); + +#endif /* TARGET_OS_OSX */ + +__END_DECLS + +#endif /* !_SECURITY_SECPOLICYTAPI_H_ */ diff --git a/OSX/sec/Security/SecPolicy.c b/OSX/sec/Security/SecPolicy.c index 2c37c6b4..98db0bf9 100644 --- a/OSX/sec/Security/SecPolicy.c +++ b/OSX/sec/Security/SecPolicy.c @@ -2608,109 +2608,50 @@ SecPolicyRef SecPolicyCreateTestMobileStoreSigner(void) CF_RETURNS_RETAINED SecPolicyRef SecPolicyCreateEscrowServiceSigner(void) { - SecPolicyRef result = NULL; + SecPolicyRef result = NULL; CFMutableDictionaryRef options = NULL; - CFArrayRef anArray = NULL; - require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut); - // X509, ignoring date validity - SecPolicyAddBasicCertOptions(options); + // X509, ignoring date validity + SecPolicyAddBasicCertOptions(options); - add_ku(options, kSecKeyUsageKeyEncipherment); + add_ku(options, kSecKeyUsageKeyEncipherment); /* Leaf has marker OID with value that can't be pre-determined */ add_element(options, kSecPolicyCheckLeafMarkerOidWithoutValueCheck, CFSTR("1.2.840.113635.100.6.23.1")); - require(SecPolicyAddChainLengthOptions(options, 2), errOut); - - Boolean anchorAdded = false; - // Get the roots by calling the SecCertificateCopyEscrowRoots - anArray = SecCertificateCopyEscrowRoots(kSecCertificateProductionEscrowRoot); - CFIndex numRoots = 0; - if (NULL == anArray || 0 == (numRoots = CFArrayGetCount(anArray))) { - goto errOut; - } - - for (CFIndex iCnt = 0; iCnt < numRoots; iCnt++) { - SecCertificateRef aCert = (SecCertificateRef)CFArrayGetValueAtIndex(anArray, iCnt); - - if (NULL != aCert) { - CFDataRef sha_data = SecCertificateGetSHA1Digest(aCert); - if (NULL != sha_data) { - const UInt8* pSHAData = CFDataGetBytePtr(sha_data); - if (NULL != pSHAData) { - SecPolicyAddAnchorSHA1Options(options, pSHAData); - anchorAdded = true; - } - } - } - } - CFReleaseNull(anArray); - - if (!anchorAdded) { - goto errOut; - } + require(SecPolicyAddChainLengthOptions(options, 2), errOut); require(result = SecPolicyCreate(kSecPolicyAppleEscrowService, kSecPolicyNameEscrowService, options), errOut); errOut: - CFReleaseSafe(anArray); - CFReleaseSafe(options); - return result; + CFReleaseSafe(options); + return result; } CF_RETURNS_RETAINED SecPolicyRef SecPolicyCreatePCSEscrowServiceSigner(void) { - SecPolicyRef result = NULL; + SecPolicyRef result = NULL; CFMutableDictionaryRef options = NULL; - CFArrayRef anArray = NULL; - require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut); - SecPolicyAddBasicX509Options(options); - add_ku(options, kSecKeyUsageKeyEncipherment); + SecPolicyAddBasicX509Options(options); + add_ku(options, kSecKeyUsageKeyEncipherment); /* Leaf has marker OID with value that can't be pre-determined */ add_element(options, kSecPolicyCheckLeafMarkerOidWithoutValueCheck, CFSTR("1.2.840.113635.100.6.23.1")); - require(SecPolicyAddChainLengthOptions(options, 2), errOut); - - Boolean anchorAdded = false; - anArray = SecCertificateCopyEscrowRoots(kSecCertificateProductionPCSEscrowRoot); - CFIndex numRoots = 0; - if (NULL == anArray || 0 == (numRoots = CFArrayGetCount(anArray))) { - goto errOut; - } - - for (CFIndex iCnt = 0; iCnt < numRoots; iCnt++) { - SecCertificateRef aCert = (SecCertificateRef)CFArrayGetValueAtIndex(anArray, iCnt); - - if (NULL != aCert) { - CFDataRef sha_data = SecCertificateGetSHA1Digest(aCert); - if (NULL != sha_data) { - const UInt8* pSHAData = CFDataGetBytePtr(sha_data); - if (NULL != pSHAData) { - SecPolicyAddAnchorSHA1Options(options, pSHAData); - anchorAdded = true; - } - } - } - } - CFReleaseNull(anArray); - - if (!anchorAdded) { - goto errOut; - } + require(SecPolicyAddChainLengthOptions(options, 2), errOut); require(result = SecPolicyCreate(kSecPolicyApplePCSEscrowService, kSecPolicyNamePCSEscrowService, options), errOut); errOut: - CFReleaseSafe(anArray); - CFReleaseSafe(options); - return result; + CFReleaseSafe(options); + return result; } static SecPolicyRef CreateConfigurationProfileSigner(bool forTest) { diff --git a/OSX/sec/Security/SecTrust.c b/OSX/sec/Security/SecTrust.c index bf3cbaab..d64de6dd 100644 --- a/OSX/sec/Security/SecTrust.c +++ b/OSX/sec/Security/SecTrust.c @@ -1039,21 +1039,6 @@ static CFStringRef SecTrustCopyChainSummary(SecTrustRef trust) { return summary; } -typedef enum { - kSecTrustErrorSubTypeBlocked, - kSecTrustErrorSubTypeRevoked, - kSecTrustErrorSubTypeKeySize, - kSecTrustErrorSubTypeWeakHash, - kSecTrustErrorSubTypeDenied, - kSecTrustErrorSubTypeCompliance, - kSecTrustErrorSubTypePinning, - kSecTrustErrorSubTypeTrust, - kSecTrustErrorSubTypeUsage, - kSecTrustErrorSubTypeName, - kSecTrustErrorSubTypeExpired, - kSecTrustErrorSubTypeInvalid, -} SecTrustErrorSubType; - #define SecCopyTrustString(KEY) SecFrameworkCopyLocalizedString(KEY, CFSTR("Trust")) struct checkmap_entry_s { @@ -1065,18 +1050,6 @@ typedef struct checkmap_entry_s checkmap_entry_t; const checkmap_entry_t checkmap[] = { #undef POLICYCHECKMACRO -#define __PC_SUBTYPE_ kSecTrustErrorSubTypeInvalid -#define __PC_SUBTYPE_N kSecTrustErrorSubTypeName -#define __PC_SUBTYPE_E kSecTrustErrorSubTypeExpired -#define __PC_SUBTYPE_S kSecTrustErrorSubTypeKeySize -#define __PC_SUBTYPE_H kSecTrustErrorSubTypeWeakHash -#define __PC_SUBTYPE_U kSecTrustErrorSubTypeUsage -#define __PC_SUBTYPE_P kSecTrustErrorSubTypePinning -#define __PC_SUBTYPE_V kSecTrustErrorSubTypeRevoked -#define __PC_SUBTYPE_T kSecTrustErrorSubTypeTrust -#define __PC_SUBTYPE_C kSecTrustErrorSubTypeCompliance -#define __PC_SUBTYPE_D kSecTrustErrorSubTypeDenied -#define __PC_SUBTYPE_B kSecTrustErrorSubTypeBlocked #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \ { __PC_SUBTYPE_##SUBTYPE , OSSTATUS, SEC_TRUST_ERROR_##NAME }, #include "SecPolicyChecks.list" diff --git a/OSX/sec/Security/SecTrustInternal.h b/OSX/sec/Security/SecTrustInternal.h index f3639401..4921bdd9 100644 --- a/OSX/sec/Security/SecTrustInternal.h +++ b/OSX/sec/Security/SecTrustInternal.h @@ -62,6 +62,34 @@ CFArrayRef SecTrustCopyProperties_ios(SecTrustRef trust); #define kSecTrustEventAttributesKey "eventAttributes" #define kSecTrustEventApplicationID "appID" +typedef enum { + kSecTrustErrorSubTypeBlocked, + kSecTrustErrorSubTypeRevoked, + kSecTrustErrorSubTypeKeySize, + kSecTrustErrorSubTypeWeakHash, + kSecTrustErrorSubTypeDenied, + kSecTrustErrorSubTypeCompliance, + kSecTrustErrorSubTypePinning, + kSecTrustErrorSubTypeTrust, + kSecTrustErrorSubTypeUsage, + kSecTrustErrorSubTypeName, + kSecTrustErrorSubTypeExpired, + kSecTrustErrorSubTypeInvalid, +} SecTrustErrorSubType; + +#define __PC_SUBTYPE_ kSecTrustErrorSubTypeInvalid +#define __PC_SUBTYPE_N kSecTrustErrorSubTypeName +#define __PC_SUBTYPE_E kSecTrustErrorSubTypeExpired +#define __PC_SUBTYPE_S kSecTrustErrorSubTypeKeySize +#define __PC_SUBTYPE_H kSecTrustErrorSubTypeWeakHash +#define __PC_SUBTYPE_U kSecTrustErrorSubTypeUsage +#define __PC_SUBTYPE_P kSecTrustErrorSubTypePinning +#define __PC_SUBTYPE_V kSecTrustErrorSubTypeRevoked +#define __PC_SUBTYPE_T kSecTrustErrorSubTypeTrust +#define __PC_SUBTYPE_C kSecTrustErrorSubTypeCompliance +#define __PC_SUBTYPE_D kSecTrustErrorSubTypeDenied +#define __PC_SUBTYPE_B kSecTrustErrorSubTypeBlocked + __END_DECLS #endif /* !_SECURITY_SECTRUSTINTERNAL_H_ */ diff --git a/OSX/sec/Security/Security-tapi.h b/OSX/sec/Security/Security-tapi.h new file mode 100644 index 00000000..e3e068f2 --- /dev/null +++ b/OSX/sec/Security/Security-tapi.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2019 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* + * TAPI coverage for exported functions. + */ + +#ifndef _SECURITY_TAPI_H_ +#define _SECURITY_TAPI_H_ + +#ifndef SECURITY_PROJECT_TAPI_HACKS +#error This header is not for inclusion; it's a nasty hack to get the iOS Security framework to build with TAPI. +#endif + +#import + +#if TARGET_OS_OSX + +//! Project version number for Security. +FOUNDATION_EXPORT double SecurityVersionNumber; + +//! Project version string for Security. +FOUNDATION_EXPORT const unsigned char SecurityVersionString[]; + +__BEGIN_DECLS + +// The following are deprecated functions. Don't use them (but they need to be here for symbol reasons). +__attribute__((visibility("default"))) void secdebug_internal(const char* scope, const char* format, ...); +__attribute__((visibility("default"))) void secdebugfunc_internal(const char* scope, const char* functionname, const char* format, ...); + +__END_DECLS + +#endif /* TARGET_OS_OSX */ + +#endif /* _SECURITY_TAPI_H_ */ diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/PinningPolicyTrustTest.plist b/OSX/shared_regressions/si-20-sectrust-policies-data/PinningPolicyTrustTest.plist index cc6821c8..2f480cf6 100644 --- a/OSX/shared_regressions/si-20-sectrust-policies-data/PinningPolicyTrustTest.plist +++ b/OSX/shared_regressions/si-20-sectrust-policies-data/PinningPolicyTrustTest.plist @@ -2889,52 +2889,6 @@ MajorTestName EscrowService MinorTestName - NegativeTest-v1 - Policies - - PolicyIdentifier - 1.2.840.113635.100.1.24 - - Leaf - escrow_service_key_B157A8D4 - Intermediates - EscrowServiceRootCA0 - Anchors - EscrowServiceRootCA0 - ExpectedResult - 5 - - - CertDirectory - si-20-sectrust-policies-data - BridgeOSDisable - - MajorTestName - EscrowService - MinorTestName - NegativeTest-v2 - Policies - - PolicyIdentifier - 1.2.840.113635.100.1.24 - - Leaf - escrow_service_key_049F9D11 - Intermediates - EscrowServiceRootCA101 - Anchors - EscrowServiceRootCA101 - ExpectedResult - 5 - - - CertDirectory - si-20-sectrust-policies-data - BridgeOSDisable - - MajorTestName - PCSEscrowService - MinorTestName PositiveTest Policies diff --git a/OSX/utilities/SecABC.h b/OSX/utilities/SecABC.h index 53c3f7b7..00022396 100644 --- a/OSX/utilities/SecABC.h +++ b/OSX/utilities/SecABC.h @@ -17,6 +17,9 @@ NS_ASSUME_NONNULL_BEGIN @interface SecABC : NSObject ++ (void)triggerAutoBugCaptureWithType:(NSString *)type + subType:(NSString *)subType; + + (void)triggerAutoBugCaptureWithType:(NSString *)type subType:(NSString *)subType subtypeContext:(NSString * _Nullable)subtypeContext diff --git a/OSX/utilities/SecABC.m b/OSX/utilities/SecABC.m index 23519a62..71e41ae3 100644 --- a/OSX/utilities/SecABC.m +++ b/OSX/utilities/SecABC.m @@ -27,6 +27,18 @@ void SecABCTrigger(CFStringRef type, @implementation SecABC ++ (void)triggerAutoBugCaptureWithType:(NSString *)type + subType:(NSString *)subType +{ + [self triggerAutoBugCaptureWithType: type + subType: subType + subtypeContext: nil + events: nil + payload: nil + detectedProcess: nil]; +} + + + (void)triggerAutoBugCaptureWithType:(NSString *)type subType:(NSString *)subType subtypeContext:(NSString *)subtypeContext @@ -56,7 +68,7 @@ void SecABCTrigger(CFStringRef type, } (void)[diagnosticReporter snapshotWithSignature:signature - duration:30.0 + duration:5.0 events:events payload:payload actions:NULL diff --git a/OSX/utilities/SecAppleAnchor-tapi.h b/OSX/utilities/SecAppleAnchor-tapi.h new file mode 100644 index 00000000..811e8e53 --- /dev/null +++ b/OSX/utilities/SecAppleAnchor-tapi.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015-2016 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +#ifndef SecAppleAnchorTapi_c +#define SecAppleAnchorTapi_c + +#ifndef SECURITY_PROJECT_TAPI_HACKS +#error This header is not for inclusion; it's a nasty hack to get the iOS Security framework to build with TAPI. +#endif + +#include +#include +#include + +__BEGIN_DECLS + +#if TARGET_OS_OSX + +typedef CF_OPTIONS(uint32_t, SecAppleTrustAnchorFlags) { + kSecAppleTrustAnchorFlagsIncludeTestAnchors = 1 << 0, + kSecAppleTrustAnchorFlagsAllowNonProduction = 1 << 1, +}; + +/* + * Return true if the certificate is an the Apple Trust anchor. + */ +bool +SecIsAppleTrustAnchor(SecCertificateRef cert, + SecAppleTrustAnchorFlags flags); + +bool +SecIsAppleTrustAnchorData(CFDataRef cert, + SecAppleTrustAnchorFlags flags); + +#endif /* TARGET_OS_OSX */ + +__END_DECLS + + +#endif /* SecAppleAnchorTapi */ diff --git a/RegressionTests/PreprocessPlist.sh b/RegressionTests/PreprocessPlist.sh new file mode 100755 index 00000000..851e4b19 --- /dev/null +++ b/RegressionTests/PreprocessPlist.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# from https://stashweb.sd.apple.com/projects/CORESERVICES/repos/rapport/browse +set -euo pipefail + +srcPath="$1" +dstPath="$2" + +mkdir -p $(dirname "$dstPath") + +xcrun -sdk ${SDK_NAME} \ + clang -x c -P -E -include ${SRCROOT}/RegressionTests/bats_utd_plist.h "$srcPath" | \ + sed -e 's/_FALSE_<\/string>//' -e 's/_TRUE_<\/string>//' > "$dstPath" +plutil -convert binary1 "$dstPath" + +[ "$(whoami)" == "root" ] || exit 0 +chown root:wheel "$dstPath" diff --git a/RegressionTests/Security.plist b/RegressionTests/Security.plist index 15cb464c..e08137ea 100644 --- a/RegressionTests/Security.plist +++ b/RegressionTests/Security.plist @@ -14,6 +14,8 @@ /usr/local/bin/keystorectl get-lock-state + Disabled + BATS_UTD_Disabled_keystorectl_get_lock_state TestName @@ -22,6 +24,8 @@ /usr/libexec/security-sysdiagnose + Disabled + BATS_UTD_Disabled_security_sysdiagnose TestName @@ -30,6 +34,8 @@ /AppleInternal/CoreOS/tests/Security/secedumodetest + Disabled + BATS_UTD_Disabled_EduModeTest TestName @@ -38,6 +44,8 @@ /AppleInternal/CoreOS/tests/Security/seckeychainnetworkextensionstest + Disabled + BATS_UTD_Disabled_keychainnetworkextensionsharing_1 TestName @@ -46,6 +54,8 @@ /AppleInternal/CoreOS/tests/Security/seckeychainnetworkextensionsystemdaemontest + Disabled + BATS_UTD_Disabled_keychainnetworkextensionsharing_2 TestName @@ -54,6 +64,8 @@ /AppleInternal/CoreOS/tests/Security/seckeychainnetworkextensionunauthorizedaccesstest + Disabled + BATS_UTD_Disabled_keychainnetworkextensionsharing_3 TestName @@ -66,6 +78,8 @@ -t KCPairingTests + Disabled + BATS_UTD_Disabled_KCPairingTest TestName @@ -74,8 +88,8 @@ /AppleInternal/CoreOS/tests/Security/authdtest - EligibleResource - type != 'CAMEmbeddedDeviceResource' + Disabled + BATS_UTD_Disabled_AuthorizationTest TestName @@ -87,6 +101,8 @@ BATS_XCTEST_CMD /AppleInternal/XCTests/com.apple.security/KeychainAnalyticsTests.xctest + Disabled + BATS_UTD_Disabled_KeychainAnalyticsTests TestName @@ -98,6 +114,8 @@ BATS_XCTEST_CMD /AppleInternal/XCTests/com.apple.security/secdmockaks.xctest + Disabled + BATS_UTD_Disabled_KeychainMockAKSTests TestName @@ -109,8 +127,8 @@ BATS_XCTEST_CMD /AppleInternal/XCTests/com.apple.security/secdxctests_mac.xctest - EligibleResource - type != 'CAMEmbeddedDeviceResource' + Disabled + BATS_UTD_Disabled_KeychainSecd_macOS TestName @@ -122,8 +140,8 @@ BATS_XCTEST_CMD /AppleInternal/XCTests/com.apple.security/secdxctests_ios.xctest - EligibleResource - type == 'CAMEmbeddedDeviceResource' + Disabled + BATS_UTD_Disabled_KeychainSecd_iOS TestName @@ -135,6 +153,8 @@ BATS_XCTEST_CMD /AppleInternal/XCTests/com.apple.security/SecurityUtilitiesTests.xctest + Disabled + BATS_UTD_Disabled_SecurityUtiltitesTests diff --git a/RegressionTests/bats_utd_plist.h b/RegressionTests/bats_utd_plist.h new file mode 100644 index 00000000..e8549e96 --- /dev/null +++ b/RegressionTests/bats_utd_plist.h @@ -0,0 +1,81 @@ +#include + +/* + * BATS Unit Test Discovery has a feature called "Disabled". This is a + * boolean: if True, the test is not run. + * + * Every test in Security.plist has a "Disabled" string: + * + * TestName + * KeychainSecd_iOS + * Disabled + * BATS_UTD_Disabled_KeychainSecd_iOS + * + * + * In Security.plist, we use a string instead of a boolean. We will convert to + * booleans during the preprocssor stage. This allows use to edit the plists + * in xcode. So, the final plist will look like: + * + * TestName + * KeychainSecd_iOS + * Disabled + * + * + * + * When you add a new test, you will need to add a define to each branch and + * specify which platform you want the test to run on. + * + * If this include becomes to ugly, we either will need to have seperate UTD + * plists per platform or have the test executable skip if on platforms it does + * not like. + */ + +#if TARGET_OS_BRIDGE +/* For BridgeOS, only two tests are currently working */ +#define BATS_UTD_Disabled_AuthorizationTest _TRUE_ +#define BATS_UTD_Disabled_EduModeTest _FALSE_ +#define BATS_UTD_Disabled_KCPairingTest _TRUE_ +#define BATS_UTD_Disabled_KeychainAnalyticsTests _TRUE_ +#define BATS_UTD_Disabled_KeychainMockAKSTests _TRUE_ +#define BATS_UTD_Disabled_KeychainSecd_iOS _TRUE_ +#define BATS_UTD_Disabled_KeychainSecd_macOS _TRUE_ +#define BATS_UTD_Disabled_SecurityUtiltitesTests _TRUE_ +#define BATS_UTD_Disabled_keychainnetworkextensionsharing_1 _TRUE_ +#define BATS_UTD_Disabled_keychainnetworkextensionsharing_2 _TRUE_ +#define BATS_UTD_Disabled_keychainnetworkextensionsharing_3 _TRUE_ +#define BATS_UTD_Disabled_keystorectl_get_lock_state _FALSE_ +#define BATS_UTD_Disabled_security_sysdiagnose _TRUE_ + +#elif TARGET_OS_OSX +/* For MacOS, we disable the iOS only tests. */ +#define BATS_UTD_Disabled_AuthorizationTest _FALSE_ +#define BATS_UTD_Disabled_EduModeTest _FALSE_ +#define BATS_UTD_Disabled_KCPairingTest _FALSE_ +#define BATS_UTD_Disabled_KeychainAnalyticsTests _FALSE_ +#define BATS_UTD_Disabled_KeychainMockAKSTests _FALSE_ +#define BATS_UTD_Disabled_KeychainSecd_iOS _TRUE_ +#define BATS_UTD_Disabled_KeychainSecd_macOS _FALSE_ +#define BATS_UTD_Disabled_SecurityUtiltitesTests _FALSE_ +#define BATS_UTD_Disabled_keychainnetworkextensionsharing_1 _FALSE_ +#define BATS_UTD_Disabled_keychainnetworkextensionsharing_2 _FALSE_ +#define BATS_UTD_Disabled_keychainnetworkextensionsharing_3 _FALSE_ +#define BATS_UTD_Disabled_keystorectl_get_lock_state _FALSE_ +#define BATS_UTD_Disabled_security_sysdiagnose _FALSE_ + +#else +/* By default, assume iOS platforms. We disable the MacOS only tests. */ +#define BATS_UTD_Disabled_AuthorizationTest _TRUE_ +#define BATS_UTD_Disabled_EduModeTest _FALSE_ +#define BATS_UTD_Disabled_KCPairingTest _FALSE_ +#define BATS_UTD_Disabled_KeychainAnalyticsTests _FALSE_ +#define BATS_UTD_Disabled_KeychainMockAKSTests _FALSE_ +#define BATS_UTD_Disabled_KeychainSecd_iOS _FALSE_ +#define BATS_UTD_Disabled_KeychainSecd_macOS _TRUE_ +#define BATS_UTD_Disabled_SecurityUtiltitesTests _FALSE_ +#define BATS_UTD_Disabled_keychainnetworkextensionsharing_1 _FALSE_ +#define BATS_UTD_Disabled_keychainnetworkextensionsharing_2 _FALSE_ +#define BATS_UTD_Disabled_keychainnetworkextensionsharing_3 _FALSE_ +#define BATS_UTD_Disabled_keystorectl_get_lock_state _FALSE_ +#define BATS_UTD_Disabled_security_sysdiagnose _FALSE_ + +#endif diff --git a/SecExperiment/SecExperiment.m b/SecExperiment/SecExperiment.m deleted file mode 100644 index fac3efd4..00000000 --- a/SecExperiment/SecExperiment.m +++ /dev/null @@ -1,322 +0,0 @@ -// -// SecExperiment.m -// Security -// - -#include -#include -#include -#include - -#define OS_OBJECT_HAVE_OBJC_SUPPORT 1 - -#define SEC_EXP_NULL_BAD_INPUT ((void *_Nonnull)NULL) -#define SEC_EXP_NULL_OUT_OF_MEMORY SEC_EXP_NULL_BAD_INPUT - -#define SEC_EXP_NIL_BAD_INPUT ((void *_Nonnull)nil) -#define SEC_EXP_NIL_OUT_OF_MEMORY SEC_EXP_NIL_BAD_INPUT - -#define SEC_EXP_CONCRETE_CLASS_NAME(external_type) SecExpConcrete_##external_type -#define SEC_EXP_CONCRETE_PREFIX_STR "SecExpConcrete_" - -#define SEC_EXP_OBJECT_DECL_INTERNAL_OBJC(external_type) \ -@class SEC_EXP_CONCRETE_CLASS_NAME(external_type); \ -typedef SEC_EXP_CONCRETE_CLASS_NAME(external_type) *external_type##_t - -#define SEC_EXP_OBJECT_IMPL_INTERNAL_OBJC_WITH_PROTOCOL_AND_VISBILITY(external_type, _protocol, visibility, ...) \ -@protocol OS_OBJECT_CLASS(external_type) <_protocol> \ -@end \ -visibility \ -@interface SEC_EXP_CONCRETE_CLASS_NAME(external_type) : NSObject \ -_Pragma("clang diagnostic push") \ -_Pragma("clang diagnostic ignored \"-Wobjc-interface-ivars\"") \ -__VA_ARGS__ \ -_Pragma("clang diagnostic pop") \ -@end \ -typedef int _useless_typedef_oio_##external_type - -#define SEC_EXP_OBJECT_IMPL_INTERNAL_OBJC_WITH_PROTOCOL(external_type, _protocol, ...) \ -SEC_EXP_OBJECT_IMPL_INTERNAL_OBJC_WITH_PROTOCOL_AND_VISBILITY(external_type, _protocol, ,__VA_ARGS__) - -#define SEC_EXP_OBJECT_IMPL_INTERNAL_OBJC(external_type, ...) \ -SEC_EXP_OBJECT_IMPL_INTERNAL_OBJC_WITH_PROTOCOL(external_type, NSObject, ##__VA_ARGS__) - -#define SEC_EXP_OBJECT_IMPL_INTERNAL_OBJC_WITH_VISIBILITY(external_type, visibility, ...) \ -SEC_EXP_OBJECT_IMPL_INTERNAL_OBJC_WITH_PROTOCOL_AND_VISBILITY(external_type, NSObject, visibility, ##__VA_ARGS__) - -SEC_EXP_OBJECT_DECL_INTERNAL_OBJC(sec_experiment); - -#define SEC_EXP_OBJECT_IMPL 1 -#import "SecExperimentPriv.h" -#import "SecExperimentInternal.h" -#import "SecCFRelease.h" -#import -#import - -#define SEC_EXPERIMENT_SAMPLING_RATE 100.0 -#define HASH_INITIAL_VALUE 0 -#define HASH_MULTIPLIER 31 - -const char *kSecExperimentDefaultsDomain = "com.apple.security.experiment"; -const char *kSecExperimentDefaultsDisableSampling = "disableSampling"; -const char *kSecExperimentTLSMobileAssetConfig = "TLSConfig"; - -const NSString *SecExperimentMAPrefix = @"com.apple.MobileAsset."; - -SEC_EXP_OBJECT_IMPL_INTERNAL_OBJC(sec_experiment, -{ - const char *identifier; - bool sampling_disabled; -}); - -@implementation SEC_EXP_CONCRETE_CLASS_NAME(sec_experiment) - -- (instancetype)initWithBundle:(const char *)bundle -{ - if (bundle == NULL) { - return SEC_EXP_NIL_BAD_INPUT; - } - - self = [super init]; - if (self == nil) { - return SEC_EXP_NIL_OUT_OF_MEMORY; - } else { - self->identifier = bundle; - } - return self; -} - -// Computes hash of input and returns a value between 1-100 -static uint32_t -_hash_multiplicative(const char *key, size_t len) -{ - if (!key) { - return 0; - } - uint32_t hash = HASH_INITIAL_VALUE; - for (uint32_t i = 0; i < len; ++i) { - hash = HASH_MULTIPLIER * hash + key[i]; - } - return hash % 101; // value between 1-100 -} - -// Computes hash of device UUID -static uint32_t -_get_host_id_hash(void) -{ - static uuid_string_t hostuuid = {}; - static uint32_t hash = 0; - static dispatch_once_t onceToken = 0; - dispatch_once(&onceToken, ^{ - struct timespec timeout = {0, 0}; - uuid_t uuid = {}; - if (gethostuuid(uuid, &timeout) == 0) { - uuid_unparse(uuid, hostuuid); - hash = _hash_multiplicative(hostuuid, strlen(hostuuid)); - } else { - onceToken = 0; - } - }); - return hash; -} - -static bool -sec_experiment_is_sampling_disabled_with_default(bool default_value) -{ - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - if (defaults != nil) { - NSMutableDictionary *experimentDefaults = [[defaults persistentDomainForName:[NSString stringWithUTF8String:kSecExperimentDefaultsDomain]] mutableCopy]; - if (experimentDefaults != nil) { - NSString *key = [NSString stringWithUTF8String:kSecExperimentDefaultsDisableSampling]; - if (experimentDefaults[key] != nil) { - return [experimentDefaults[key] boolValue]; - } - } - } - - return default_value; -} - -sec_experiment_t -sec_experiment_create(const char *bundle) -{ - return [[SEC_EXP_CONCRETE_CLASS_NAME(sec_experiment) alloc] initWithBundle:bundle]; -} - -static xpc_object_t -_copy_builtin_experiment_asset(sec_experiment_t experiment) -{ - if (strncmp(experiment->identifier, kSecExperimentTLSMobileAssetConfig, strlen(kSecExperimentTLSMobileAssetConfig)) != 0) { - return nil; - } - - static NSDictionary *defaultTLSConfig = NULL; - static dispatch_once_t onceToken = 0; - dispatch_once(&onceToken, ^{ - NSDictionary *validate = @{ - @"tcp" : @{}, - @"tls" : @{@"max_version": @0x0303, - @"false_start_enabled" : @false - } - }; - NSDictionary *transform = @{ - @"tcp" : @{}, - @"tls" : @{@"max_version": @0x0304, - @"false_start_enabled" : @true - } - }; - defaultTLSConfig = @{ - @"validate" : validate, - @"transform" : transform - }; - }); - - return _CFXPCCreateXPCObjectFromCFObject((__bridge CFDictionaryRef)defaultTLSConfig); -} - -// Default check to compute sampling in lieu of MobileAsset download -static bool -_device_is_in_experiment(sec_experiment_t experiment) -{ - if (experiment->sampling_disabled) { - return YES; - } - - uint32_t sample = arc4random(); - return (float)sample < ((float)UINT32_MAX / SEC_EXPERIMENT_SAMPLING_RATE); -} - -static NSDictionary * -_copy_experiment_asset(sec_experiment_t experiment) -{ - CFErrorRef error = NULL; - NSDictionary *config = NULL; - NSDictionary *asset = CFBridgingRelease(SecTrustOTASecExperimentCopyAsset(&error)); - if (asset) { - config = [asset valueForKey:[NSString stringWithUTF8String:experiment->identifier]]; - } - return config; -} - -static xpc_object_t -_copy_defaults_experiment_asset(sec_experiment_t experiment) -{ - xpc_object_t result = nil; - - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - if (defaults != nil) { - NSMutableDictionary *experimentDefaults = [[defaults persistentDomainForName:[NSString stringWithUTF8String:kSecExperimentDefaultsDomain]] mutableCopy]; - if (experimentDefaults != nil) { - NSString *key = [NSString stringWithUTF8String:experiment->identifier]; - if (experimentDefaults[key] != nil) { - result = _CFXPCCreateXPCObjectFromCFObject((__bridge CFDictionaryRef)experimentDefaults[key]); - } - } - } - - return result; -} - -void -sec_experiment_set_sampling_disabled(sec_experiment_t experiment, bool sampling_disabled) -{ - experiment->sampling_disabled = sampling_disabled; -} - -xpc_object_t -sec_experiment_copy_configuration(sec_experiment_t experiment) -{ - if (experiment == NULL) { - return NULL; - } - /* Check first for defaults configured */ - if (!sec_experiment_is_sampling_disabled_with_default(experiment->sampling_disabled)) { - xpc_object_t defaultAsset = _copy_defaults_experiment_asset(experiment); - if (defaultAsset != nil) { - return defaultAsset; - } - } - /* Copy assets downloaded from MA */ - NSDictionary *asset = _copy_experiment_asset(experiment); - if (asset != NULL) { - /* Get random config from array of experiments */ - NSArray *array = [asset valueForKey:@"ConfigArray"]; - if (array == NULL) { - return NULL; - } - NSDictionary *randomConfig = [array objectAtIndex:(arc4random() % [array count])]; - - /* Only if sampling is enabled for the experiment */ - if (!experiment->sampling_disabled) { - /* Check FleetSampleRate if device should be in experiment */ - uint32_t fleetSample = [[randomConfig objectForKey:@"FleetSampleRate"] intValue]; - - /* fleetSample is a percentage value configured to determine - percentage of devices in an experiment */ - uint32_t hostIdHash = _get_host_id_hash(); - if ((hostIdHash == 0) || (fleetSample < hostIdHash)) { - return nil; - } - /* Check device sampling rate if device should run experiment */ - uint32_t samplingRate = [[randomConfig objectForKey:@"DeviceSampleRate"] intValue]; - /* Only run experiment 1 out of the samplingRate value */ - uint32_t sample = arc4random(); - if ((float)sample > ((float)UINT32_MAX / samplingRate)) { - return nil; - } - } - return _CFXPCCreateXPCObjectFromCFObject((__bridge CFDictionaryRef)randomConfig); - } - - /* If asset download is not successful, fallback to built-in */ - if (_device_is_in_experiment(experiment)) { - return _copy_builtin_experiment_asset(experiment); - } - return nil; -} - -const char * -sec_experiment_get_identifier(sec_experiment_t experiment) -{ - return experiment->identifier; -} - -bool -sec_experiment_run_internal(const char *experiment_name, bool sampling_disabled, dispatch_queue_t queue, sec_experiment_run_block_t run_block) -{ - if (experiment_name == NULL || queue == nil || run_block == nil) { - return false; - } - - dispatch_async(queue, ^{ - sec_experiment_t experiment = sec_experiment_create(experiment_name); - if (experiment != nil) { - sec_experiment_set_sampling_disabled(experiment, sec_experiment_is_sampling_disabled_with_default(sampling_disabled)); - xpc_object_t config = sec_experiment_copy_configuration(experiment); - if (config != nil) { - const char *identifier = sec_experiment_get_identifier(experiment); - if (run_block(identifier, config)) { - os_log_info(OS_LOG_DEFAULT, "Configuration '%s' for experiment '%s' succeeded", identifier, experiment_name); - } else { - os_log_info(OS_LOG_DEFAULT, "Configuration '%s' for experiment '%s' failed", identifier, experiment_name); - } - } else { - os_log_debug(OS_LOG_DEFAULT, "Experiment '%s' not sampled to run", experiment_name); - } - } else { - os_log_debug(OS_LOG_DEFAULT, "Experiment '%s' not found", experiment_name); - } - }); - - return true; -} - -bool -sec_experiment_run(const char *experiment_name, dispatch_queue_t queue, sec_experiment_run_block_t run_block) -{ - // Sampling is always enabled for SecExperiment callers. Appliations may override this by setting the - // `disableSampling` key in the `com.apple.security.experiment` defaults domain. - return sec_experiment_run_internal(experiment_name, false, queue, run_block); -} - -@end diff --git a/SecExperiment/SecExperimentInternal.h b/SecExperiment/SecExperimentInternal.h deleted file mode 100644 index 6bd4fb2e..00000000 --- a/SecExperiment/SecExperimentInternal.h +++ /dev/null @@ -1,34 +0,0 @@ -// -// SecExperimentInternal.h -// Security -// - -#ifndef SecExperimentInternal_h -#define SecExperimentInternal_h - -#include - -/*! - * @function sec_experiment_run_internal - * - * @abstract - * Asynchronously run an experiment, optionally disabling sampling if desired. - * - * Note: This function MUST NOT be called outside of tests. - * - * @param experiment_name - * Name of the experiment to run. - * - * @param sampling_disabled - * Flag to disable sampling. - * - * @param queue - * Queue on which to run the experiment. - * - * @param run_block - * A `sec_experiment_run_block_t` block upon which to execute the given experiment. - */ -bool -sec_experiment_run_internal(const char *experiment_name, bool sampling_disabled, dispatch_queue_t queue, sec_experiment_run_block_t run_block); - -#endif /* SecExperimentInternal_h */ diff --git a/SecExperiment/SecExperimentPriv.h b/SecExperiment/SecExperimentPriv.h deleted file mode 100644 index 5e99758a..00000000 --- a/SecExperiment/SecExperimentPriv.h +++ /dev/null @@ -1,120 +0,0 @@ -// -// SecExperimentPriv.h -// Security -// - -#ifndef SecExperiment_h -#define SecExperiment_h - -#include - -#ifndef SEC_EXP_OBJECT_IMPL -SEC_OBJECT_DECL(sec_experiment); -#endif // !SEC_EXP_OBJECT_IMPL - -SEC_ASSUME_NONNULL_BEGIN - -extern const char *kSecExperimentTLSMobileAssetConfig; -extern const char *kSecExperimentDefaultsDomain; - -/*! - * @block sec_experiment_run_block_t - * - * @abstract A block to execute an experiment with a loggable identifier - * and configuration. `identifier` will be uniquely associated with - * `experiment_config` and should be used when measuring data. - * - * @param identifier - * Identifier for the experiment. - * - * @param experiment_config - * Configuration of this experiment. - * - * @return True if the experiment ran successfully, and false otherwise. - */ -typedef bool (^sec_experiment_run_block_t)(const char *identifier, xpc_object_t experiment_config); - -/*! - * @function sec_experiment_run - * - * @abstract - * Asynchronously run an experiment. - * - * @param experiment_name - * Name of the experiment to run. - * - * @param queue - * Queue on which to run the experiment. - * - * @param run_block - * A `sec_experiment_run_block_t` block upon which to execute the given experiment. - */ -API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)) -bool -sec_experiment_run(const char *experiment_name, dispatch_queue_t queue, sec_experiment_run_block_t run_block); - -/*! - * @function sec_experiment_create - * - * @abstract - * Create an ARC-able `sec_experiment_t` instance - * - * @param experiment_name - * Name of the experiment. - * - * @return a `sec_experiment_t` instance. - */ -API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)) -SEC_RETURNS_RETAINED _Nullable sec_experiment_t -sec_experiment_create(const char *experiment_name); - -/*! - * @function sec_experiment_set_sampling_disabled - * - * @abstract - * Set a flag to disable experiment sampling. - * This function should only be used for testing purposes. - * - * @param experiment - * A `sec_experiment_t` instance. - * - * @param sampling_disabled - * A flag indicating if sampling should be disabled. - */ -API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)) -void -sec_experiment_set_sampling_disabled(sec_experiment_t experiment, bool sampling_disabled); - -/*! - * @function sec_experiment_copy_configuration - * - * @abstract - * Returns the configuration dictionary associated with the given experiment. - * - * @param experiment - * A valid `sec_experiment_t` instance. - * - * @return xpc_object_t containing asset bundle, if client is not part of the experiment return NULL - */ -API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)) -SEC_RETURNS_RETAINED _Nullable xpc_object_t -sec_experiment_copy_configuration(sec_experiment_t experiment); - -/*! - * @function sec_experiment_get_identifier - * - * @abstract - * Returns a loggable identifier for the given experiment. - * - * @param experiment - * A valid `sec_experiment_t` instance. - * - * @return A NULL-terminated, loggable experiment identifier. - */ -API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)) -const char * _Nullable -sec_experiment_get_identifier(sec_experiment_t experiment); - -SEC_ASSUME_NONNULL_END - -#endif // SecExperiment_h diff --git a/SecExperiment/TLSAssets/Info.plist b/SecExperiment/TLSAssets/Info.plist deleted file mode 100644 index d314b507..00000000 --- a/SecExperiment/TLSAssets/Info.plist +++ /dev/null @@ -1,23 +0,0 @@ - - - - - CFBundleIdentifier - com.apple.MobileAsset.SecExperimentAssets - CFBundleName - SecExperimentAssets - CFBundleVersion - 1.0 - CFBundleShortVersionString - 1.0.0 - CFBundleInfoDictionaryVersion - 1 - MobileAssetProperties - - _ContentVersion - 1 - _CompatibilityVersion - 1 - - - diff --git a/SecExperiment/TLSAssets/Makefile b/SecExperiment/TLSAssets/Makefile deleted file mode 100644 index e3577db2..00000000 --- a/SecExperiment/TLSAssets/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -ASSET_DIR = BuiltTLSConfigAssets -ASSET_DATA = ${ASSET_DIR}/AssetData - -asset: - rm -rf ${ASSET_DIR} - mkdir -p ${ASSET_DIR} - ditto Info.plist ${ASSET_DIR} - mkdir -p ${ASSET_DATA} - ditto TLSConfig.plist ${ASSET_DIR}/AssetData - -cleanall: clean - rm -rf ${ASSET_DIR} - -clean: - rm -rf staged - -stage: asset - echo "TLSConfigs staging" - rm -rf staged - $(shell /usr/bin/xcrun --find assettool --sdk ioshostadditions) stage -p . -s staged -v 1 - $(shell /usr/bin/xcrun --find assettool --sdk ioshostadditions) sign -s staged - -installsrc: - $(DITTO) . $(SRCROOT) - -install: - $(PLUTIL) -convert binary1 $(SRCROOT)/Asset/Info.plist - $(DITTO) $(SRCROOT)/Asset $(DSTROOT)/MySampleProject/ - chown -R root:wheel $(DSTROOT) - find $(DSTROOT) -type d -exec chmod 755 {} \; - find $(DSTROOT) -type f -exec chmod 644 {} \; - $(DOTCLEAN) -m $(DSTROOT) - -installhdrs: - $(ECHO) "doing nothing" diff --git a/SecExperiment/TLSAssets/TLSConfig.plist b/SecExperiment/TLSAssets/TLSConfig.plist deleted file mode 100644 index 83b98cba..00000000 --- a/SecExperiment/TLSAssets/TLSConfig.plist +++ /dev/null @@ -1,30 +0,0 @@ - - - - - validate - - tcp - - tls - - max_version - 771 - false_start_enabled - - - - transform - - tcp - - tls - - max_version - 772 - false_start_enabled - - - - - diff --git a/SecExperiment/test/SecExperimentTests.m b/SecExperiment/test/SecExperimentTests.m deleted file mode 100644 index 4374136b..00000000 --- a/SecExperiment/test/SecExperimentTests.m +++ /dev/null @@ -1,77 +0,0 @@ -// -// SecExperimentTests.m -// -// - -#import -#import "SecExperimentInternal.h" -#import "SecExperimentPriv.h" - -@interface SecExperimentTests : XCTestCase -@end - -@implementation SecExperimentTests - -- (void)testCStyleGetTlsConfig { - sec_experiment_t experiment = sec_experiment_create(kSecExperimentTLSMobileAssetConfig); - sec_experiment_set_sampling_disabled(experiment, true); - XCTAssert(experiment, @"sec_experiment_create"); - - xpc_object_t tlsconfig = nil; - tlsconfig = sec_experiment_copy_configuration(experiment); - XCTAssertNotNil(tlsconfig); - -} - -- (void)testCStyleGetTlsConfig_SkipSampling { - sec_experiment_t experiment = sec_experiment_create(kSecExperimentTLSMobileAssetConfig); - XCTAssert(experiment, @"sec_experiment_create"); - - sec_experiment_set_sampling_disabled(experiment, true); - xpc_object_t tlsconfig = sec_experiment_copy_configuration(experiment); - XCTAssertNotNil(tlsconfig); -} - -- (void)testExperimentRun_SkipSamping { - dispatch_queue_t test_queue = dispatch_queue_create("test_queue", NULL); - - __block dispatch_semaphore_t blocker = dispatch_semaphore_create(0); - __block bool experiment_invoked = false; - sec_experiment_run_block_t run_block = ^bool(const char *identifier, xpc_object_t config) { - experiment_invoked = identifier != NULL && config != NULL; - dispatch_semaphore_signal(blocker); - return experiment_invoked; - }; - - sec_experiment_run_internal(kSecExperimentTLSMobileAssetConfig, true, test_queue, run_block); - XCTAssertTrue(dispatch_semaphore_wait(blocker, dispatch_time(DISPATCH_TIME_NOW, (uint64_t)(5 * NSEC_PER_SEC))) == 0L); - XCTAssertTrue(experiment_invoked); -} - -- (void)testDefaultsConfigCopy { - const char *test_key = "test_defaults_experiment_key"; - const char *test_value = "test_value"; - - sec_experiment_t experiment = sec_experiment_create(test_key); - XCTAssert(experiment, @"sec_experiment_create"); - - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - - NSString *test_key_string = [NSString stringWithUTF8String:test_key]; - NSString *test_value_string = [NSString stringWithUTF8String:test_value]; - NSDictionary *testConfig = @{test_key_string: test_value_string}; - [defaults setPersistentDomain:testConfig forName:[NSString stringWithUTF8String:kSecExperimentDefaultsDomain]]; - - sec_experiment_set_sampling_disabled(experiment, true); - xpc_object_t tlsconfig = sec_experiment_copy_configuration(experiment); - XCTAssertNotNil(tlsconfig); - XCTAssertTrue(xpc_get_type(tlsconfig) == XPC_TYPE_STRING); - if (xpc_get_type(tlsconfig) == XPC_TYPE_STRING) { - XCTAssertTrue(strcmp(xpc_string_get_string_ptr(tlsconfig), test_value) == 0); - } - - // Clear the persistent domain - [defaults removePersistentDomainForName:[NSString stringWithUTF8String:kSecExperimentDefaultsDomain]]; -} - -@end diff --git a/Security.exp-in b/Security.exp-in index 5da8fa4d..a027eee7 100644 --- a/Security.exp-in +++ b/Security.exp-in @@ -341,6 +341,10 @@ SEC_EXP_CLASS(OTOperationConfiguration) _kSecEntitlementPrivateOctagonEscrow #endif +__OctagonSignpostCreate +__OctagonSignpostGetNanoseconds +__OctagonSignpostLogSystem + _OTCliqueStatusToString _OTCliqueStatusFromString diff --git a/Security.xcodeproj/project.pbxproj b/Security.xcodeproj/project.pbxproj index 5d5176ea..63d915ed 100644 --- a/Security.xcodeproj/project.pbxproj +++ b/Security.xcodeproj/project.pbxproj @@ -738,7 +738,7 @@ buildConfigurationList = EB9C1DAF1BDFD4DF00F89272 /* Build configuration list for PBXAggregateTarget "SecurityBatsTests" */; buildPhases = ( EB9C1DB41BDFD4F200F89272 /* Install BATS plist */, - EBC15E801BE29A8C001C0C5B /* Chown BATS plist */, + EBC15E801BE29A8C001C0C5B /* Generate and Chown BATS plist */, EBA12514225E55C200138070 /* Check for SYSTEM_FRAMEWORK_SEARCH_PATHS */, ); dependencies = ( @@ -879,6 +879,7 @@ 0C8884012154C4E80053224D /* OTJoiningConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8FD549214AECD70098E3FB /* OTJoiningConfiguration.m */; }; 0C8884042154C4EA0053224D /* OTJoiningConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8FD549214AECD70098E3FB /* OTJoiningConfiguration.m */; }; 0C8FD52521483EF20098E3FB /* OT.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CCCC7C820261D310024405E /* OT.m */; }; + 0C97867D235A77230040A867 /* com.apple.security.signposts.plist in Copy System logging profile */ = {isa = PBXBuildFile; fileRef = 0C97867C235A76E70040A867 /* com.apple.security.signposts.plist */; }; 0C98122821ACCC9300784441 /* OTClique.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C2F336A20DD643B0031A92D /* OTClique.m */; }; 0C9AEEAF20783FBB00BF6237 /* SFSignInAnalyticsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF405F42072E2BF003D6A7F /* SFSignInAnalyticsTests.m */; }; 0C9AEEBB20783FF900BF6237 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789041D77980500B50D50 /* Security.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; @@ -938,6 +939,10 @@ 0CD5797A21498F8200C43496 /* OctagonPairingTests+Piggybacking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CD5797721498F7700C43496 /* OctagonPairingTests+Piggybacking.swift */; }; 0CD8CB051ECA50780076F37F /* SOSPeerOTRTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CD8CB041ECA50780076F37F /* SOSPeerOTRTimer.m */; }; 0CD8CB0B1ECA50920076F37F /* SOSPeerOTRTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CD8CB041ECA50780076F37F /* SOSPeerOTRTimer.m */; }; + 0CD9E34323592DD7002995DE /* OctagonSignPosts.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CD9E33E235928D1002995DE /* OctagonSignPosts.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0CD9E34423592DD7002995DE /* OctagonSignPosts.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CD9E33E235928D1002995DE /* OctagonSignPosts.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0CD9E34523592EA6002995DE /* OctagonSignPosts.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CD9E340235928E9002995DE /* OctagonSignPosts.m */; }; + 0CD9E34623592EA7002995DE /* OctagonSignPosts.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CD9E340235928E9002995DE /* OctagonSignPosts.m */; }; 0CDD6F79226E83F6009094C2 /* OTTriggerEscrowUpdateOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CDD6F76226E62AD009094C2 /* OTTriggerEscrowUpdateOperation.m */; }; 0CE079F41FEA15B20040A3F1 /* SFBehavior.m in Sources */ = {isa = PBXBuildFile; fileRef = EB82A2A51FAFF26900CA64A9 /* SFBehavior.m */; }; 0CE15E2C222DF63600B7EAA4 /* RecoveryKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CE15E2A222DF63500B7EAA4 /* RecoveryKey.swift */; }; @@ -980,6 +985,9 @@ 18F7F67914D77F4400F88A12 /* NtlmGenerator.c in Sources */ = {isa = PBXBuildFile; fileRef = 4C999BA10AB5F0BB0010451D /* NtlmGenerator.c */; }; 18F7F67A14D77F4400F88A12 /* ntlmBlobPriv.c in Sources */ = {isa = PBXBuildFile; fileRef = 4C999BA30AB5F0BB0010451D /* ntlmBlobPriv.c */; }; 1B0CDF64231C9E0E004401F0 /* ContainerMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE9F8D18206C4AD300B53D16 /* ContainerMap.swift */; }; + 1B2BD395235E050E009A8624 /* SecEC-tapi.h in Headers */ = {isa = PBXBuildFile; fileRef = 1B2BD391235E050D009A8624 /* SecEC-tapi.h */; }; + 1B2BD396235E050E009A8624 /* SecPolicy-tapi.h in Headers */ = {isa = PBXBuildFile; fileRef = 1B2BD393235E050E009A8624 /* SecPolicy-tapi.h */; }; + 1B2BD397235E050E009A8624 /* Security-tapi.h in Headers */ = {isa = PBXBuildFile; fileRef = 1B2BD394235E050E009A8624 /* Security-tapi.h */; }; 1B4AE38722400A22002188E1 /* TPDictionaryMatchingRules.m in Sources */ = {isa = PBXBuildFile; fileRef = DC8846802237431400738068 /* TPDictionaryMatchingRules.m */; }; 1B4C444B223AE65500C6F97F /* TPPBPolicyKeyViewMapping.h in Headers */ = {isa = PBXBuildFile; fileRef = 1B4C4448223AE65400C6F97F /* TPPBPolicyKeyViewMapping.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1B4C444C223AE65500C6F97F /* TPPBPolicyKeyViewMapping.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B4C444A223AE65400C6F97F /* TPPBPolicyKeyViewMapping.m */; }; @@ -987,7 +995,6 @@ 1B5EAADD2252ABCD008D27E7 /* OTFetchViewsOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B5EAADB2252ABCC008D27E7 /* OTFetchViewsOperation.m */; }; 1B8341B92239AD3A002BF18A /* TPPBPolicyKeyViewMapping.proto in Sources */ = {isa = PBXBuildFile; fileRef = 1B8341B72239AD39002BF18A /* TPPBPolicyKeyViewMapping.proto */; }; 1B8D2D96226E1FA500C94238 /* SetValueTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CE15E2A222DF63500B7EAA5 /* SetValueTransformer.swift */; }; - 1B916CCE223FFED7006657FD /* libprotobuf_source_generation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCF216D721ADD5B10029CCC1 /* libprotobuf_source_generation.a */; }; 1B916CD0223FFF25006657FD /* ProtocolBuffer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6C0B0C441E2537CC007F95E5 /* ProtocolBuffer.framework */; }; 1B995259226681FA00A2D6CD /* PolicyReporter.h in Sources */ = {isa = PBXBuildFile; fileRef = 1B995256226681ED00A2D6CD /* PolicyReporter.h */; }; 1B99525A226681FA00A2D6CD /* PolicyReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B995258226681EE00A2D6CD /* PolicyReporter.m */; }; @@ -996,6 +1003,12 @@ 1BC6F79C21C9955F005ED67A /* util.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BC6F79821C9955E005ED67A /* util.h */; }; 1BDEBEF92252DEB1009AD3D6 /* policy_dryrun.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BDEBEF72252DEB1009AD3D6 /* policy_dryrun.m */; }; 1BDEBEFD2253E6D9009AD3D6 /* policy_dryrun.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BDEBEF72252DEB1009AD3D6 /* policy_dryrun.m */; }; + 1BE85ECF235CEB620051E1D8 /* cms-tapi.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BE85ECD235CEB610051E1D8 /* cms-tapi.h */; }; + 1BE85ED0235CEB620051E1D8 /* cms-tapi.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BE85ECD235CEB610051E1D8 /* cms-tapi.h */; }; + 1BE85ED2235CEBB40051E1D8 /* secport-tapi.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BE85ED1235CEBB30051E1D8 /* secport-tapi.h */; }; + 1BE85ED3235CEBB40051E1D8 /* secport-tapi.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BE85ED1235CEBB30051E1D8 /* secport-tapi.h */; }; + 1BE85ED5235CEC250051E1D8 /* sslDeprecated.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BE85ED4235CEC250051E1D8 /* sslDeprecated.h */; }; + 1BE85ED6235CEC250051E1D8 /* sslDeprecated.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BE85ED4235CEC250051E1D8 /* sslDeprecated.h */; }; 1BF640EF222EEB6C002D0FCB /* TPPolicyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BF640EE222EEB6C002D0FCB /* TPPolicyTests.m */; }; 1F631C5422387F27005920D8 /* legacydevid.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F631C5222387F27005920D8 /* legacydevid.h */; }; 1F631C5622387FFE005920D8 /* legacydevid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1F631C5122387F27005920D8 /* legacydevid.cpp */; }; @@ -1049,11 +1062,6 @@ 22E337DA1E37FD66001D5637 /* libsecurity_codesigning_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 225394B41E3080A600D3CD9B /* libsecurity_codesigning_ios.a */; }; 24CBF8751E9D4E6100F09F0E /* kc-44-secrecoverypassword.c in Sources */ = {isa = PBXBuildFile; fileRef = 24CBF8731E9D4E4500F09F0E /* kc-44-secrecoverypassword.c */; }; 3D55EA832242F50B008E7459 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D82BD316A5EADA0078DFE5 /* Security.framework */; }; - 3D58394F21891061000ACA44 /* SecExperimentTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D7AA28E2187AD0000F1575C /* SecExperimentTests.m */; }; - 3D680BE42241BC0000C04821 /* SecExperiment.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DD852B02177FF72009E705D /* SecExperiment.m */; }; - 3D680BE72241C16E00C04821 /* SecExperiment.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DD852B02177FF72009E705D /* SecExperiment.m */; }; - 3D909E372195042C00205F8C /* SecExperimentPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DA3384421658AA8008C0CE1 /* SecExperimentPriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 3D909E382195042C00205F8C /* SecExperimentPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DA3384421658AA8008C0CE1 /* SecExperimentPriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; 3DD1FF92201FC4EA0086D049 /* SecureTransportTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DD1FE7E201AA50F0086D049 /* SecureTransportTests.m */; }; 3DD1FF93201FC4EF0086D049 /* STLegacyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DD1FE8C201AA5150086D049 /* STLegacyTests.m */; }; 3DD1FF94201FC4F40086D049 /* STLegacyTests+ciphers.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DD1FE89201AA5140086D049 /* STLegacyTests+ciphers.m */; }; @@ -1103,8 +1111,6 @@ 3DD2589F20478CF900F5DA78 /* STLegacyTests+session.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DD2589820478CCE00F5DA78 /* STLegacyTests+session.m */; }; 3DD258A020478CFA00F5DA78 /* STLegacyTests+session.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DD2589820478CCE00F5DA78 /* STLegacyTests+session.m */; }; 3DD258AC2051F10300F5DA78 /* STLegacyTests+sni.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DD1FE7F201AA50F0086D049 /* STLegacyTests+sni.m */; }; - 3DD852B12177FF72009E705D /* SecExperiment.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DD852B02177FF72009E705D /* SecExperiment.m */; }; - 3DE8F6C121829EFF006041DA /* SecExperiment.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DD852B02177FF72009E705D /* SecExperiment.m */; }; 433E519E1B66D5F600482618 /* AppSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 433E519D1B66D5F600482618 /* AppSupport.framework */; }; 4381603A1B4DCE8F00C54D58 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E71F3E3016EA69A900FAF9B4 /* SystemConfiguration.framework */; }; 4381603B1B4DCEFF00C54D58 /* AggregateDictionary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B368BD179891FC004C37CE /* AggregateDictionary.framework */; }; @@ -1165,7 +1171,6 @@ 4718AE27205B39620068EC3F /* com.apple.securityd.plist in Launchd plists */ = {isa = PBXBuildFile; fileRef = DCEE1E851D93424D00DC0EB7 /* com.apple.securityd.plist */; }; 4718AE29205B39620068EC3F /* com.apple.securityd.plist in Copy Logging Files */ = {isa = PBXBuildFile; fileRef = DCE4E80D1D7A4E3A00AFB96E /* com.apple.securityd.plist */; }; 4718AE35205B39C40068EC3F /* CKKSSQLDatabaseObject.m in Sources */ = {isa = PBXBuildFile; fileRef = DC797E131DD3F88300CC9E42 /* CKKSSQLDatabaseObject.m */; }; - 4718AE36205B39C40068EC3F /* CKKSRateLimiter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CC185981E24E87D009657D8 /* CKKSRateLimiter.m */; }; 4718AE37205B39C40068EC3F /* CKKSAccountStateTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = DCFB12C41E95A4C000510F5F /* CKKSAccountStateTracker.m */; }; 4718AE38205B39C40068EC3F /* SecCDKeychain.m in Sources */ = {isa = PBXBuildFile; fileRef = 470D96701FCDE55B0065FE90 /* SecCDKeychain.m */; }; 4718AE3A205B39C40068EC3F /* CKKSGroupOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCCD88E71E42622200F5AA71 /* CKKSGroupOperation.m */; }; @@ -1686,12 +1691,21 @@ 5A061198229ED8F3006AF14A /* NSDate+SFAnalytics.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A061190229ED60C006AF14A /* NSDate+SFAnalytics.h */; settings = {ATTRIBUTES = (Private, ); }; }; 5A061199229ED8F4006AF14A /* NSDate+SFAnalytics.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A061190229ED60C006AF14A /* NSDate+SFAnalytics.h */; settings = {ATTRIBUTES = (Private, ); }; }; 5A0F84A522AEAF5B0097AEEA /* NSDate+SFAnalyticsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A1A1C2122A71D2A00CB8D1D /* NSDate+SFAnalyticsTests.m */; }; - 5A2551F32229F41300512FAE /* SecExperimentInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A2551F12229F40800512FAE /* SecExperimentInternal.h */; }; - 5A2551F52229F41500512FAE /* SecExperimentInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A2551F12229F40800512FAE /* SecExperimentInternal.h */; }; 5A43A083225FA39C005450E4 /* SecProtocolHelperTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A43A07F225FA38D005450E4 /* SecProtocolHelperTest.m */; }; 5A43A084225FA3A5005450E4 /* SecProtocolTest.m in Sources */ = {isa = PBXBuildFile; fileRef = AA44E0B3202E3451001EA371 /* SecProtocolTest.m */; }; 5A43A085225FA3A5005450E4 /* SecProtocolHelperTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A43A07F225FA38D005450E4 /* SecProtocolHelperTest.m */; }; 5A43A08A226112DB005450E4 /* SecProtocolConfigurationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = AADD4A2B215E83140054FC6D /* SecProtocolConfigurationTest.m */; }; + 5A442F8A233C330F00918373 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D82BD316A5EADA0078DFE5 /* Security.framework */; }; + 5A442FA5233C34FE00918373 /* SecExperimentPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A442F98233C34C000918373 /* SecExperimentPriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 5A442FA6233C34FE00918373 /* SecExperimentInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A442F9B233C34C000918373 /* SecExperimentInternal.h */; }; + 5A442FA7233C34FF00918373 /* SecExperimentPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A442F98233C34C000918373 /* SecExperimentPriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 5A442FA8233C34FF00918373 /* SecExperimentInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A442F9B233C34C000918373 /* SecExperimentInternal.h */; }; + 5A442FA9233C351000918373 /* SecExperiment.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A442F9C233C34C000918373 /* SecExperiment.m */; }; + 5A442FAA233C351100918373 /* SecExperiment.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A442F9C233C34C000918373 /* SecExperiment.m */; }; + 5A442FAB233C351300918373 /* SecExperiment.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A442F9C233C34C000918373 /* SecExperiment.m */; }; + 5A442FAC233C351500918373 /* SecExperiment.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A442F9C233C34C000918373 /* SecExperiment.m */; }; + 5A442FAD233C351C00918373 /* SecExperimentTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A442F9A233C34C000918373 /* SecExperimentTests.m */; }; + 5A442FAE233C352200918373 /* experimentTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A442F9F233C34C000918373 /* experimentTool.m */; }; 5A47FFB3228F5E5500F781B8 /* KCInitialMessageData.proto in Sources */ = {isa = PBXBuildFile; fileRef = 5A47FFB1228F5DF700F781B8 /* KCInitialMessageData.proto */; }; 5A47FFB9228F5F2A00F781B8 /* KCInitialMessageData.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A47FFB5228F5E9000F781B8 /* KCInitialMessageData.m */; }; 5A47FFBA228F60DF00F781B8 /* KCInitialMessageData.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A47FFB4228F5E9000F781B8 /* KCInitialMessageData.h */; }; @@ -2064,7 +2078,6 @@ BE61F5AF1EB0060C00556CCF /* TrustedPeers.h in Headers */ = {isa = PBXBuildFile; fileRef = BEF88C641EB0005F00357577 /* TrustedPeers.h */; settings = {ATTRIBUTES = (Public, ); }; }; BE6215BE1DB6E69100961E15 /* si-84-sectrust-allowlist.m in Sources */ = {isa = PBXBuildFile; fileRef = BE6215BD1DB6E69100961E15 /* si-84-sectrust-allowlist.m */; }; BE64A7FA22AF006F001209F3 /* SecurityFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 474B5FBF1E662E21007546F8 /* SecurityFoundation.framework */; }; - BE64A7FB22AF0084001209F3 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E8141D7A4E6F00AFB96E /* CFNetwork.framework */; }; BE64A7FC22AF008D001209F3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7D848541C6C1D9C0025BB44 /* Foundation.framework */; }; BE64A80022AF010B001209F3 /* trusted_cert_ssl.m in Sources */ = {isa = PBXBuildFile; fileRef = BE64A7FE22AF010A001209F3 /* trusted_cert_ssl.m */; }; BE70899D1F9AB03E001ACC20 /* TPPBVoucher.h in Headers */ = {isa = PBXBuildFile; fileRef = BE70899A1F9AAFF7001ACC20 /* TPPBVoucher.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -2102,6 +2115,7 @@ BEC373B420D8160100DBDF5B /* TPPBAncientEpoch.h in Headers */ = {isa = PBXBuildFile; fileRef = BEC373AF20D815E200DBDF5B /* TPPBAncientEpoch.h */; settings = {ATTRIBUTES = (Private, ); }; }; BEC373CB20D822DA00DBDF5B /* TPPBDispositionEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = BEC373CA20D822CE00DBDF5B /* TPPBDispositionEntry.h */; settings = {ATTRIBUTES = (Private, ); }; }; BEC373D020D87B4D00DBDF5B /* SecFramework.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E4F1D8085FC00865A7C /* SecFramework.c */; }; + BEC6A9162331992900080069 /* Network.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BEC6A9142331992800080069 /* Network.framework */; }; BECEC11220A508F600E97255 /* TPVoucher.h in Headers */ = {isa = PBXBuildFile; fileRef = BECEC11020A508F600E97255 /* TPVoucher.h */; settings = {ATTRIBUTES = (Public, ); }; }; BECEC11320A508F600E97255 /* TPVoucher.m in Sources */ = {isa = PBXBuildFile; fileRef = BECEC11120A508F600E97255 /* TPVoucher.m */; }; BECEC11C20A634E000E97255 /* ProtocolBuffer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6C0B0C441E2537CC007F95E5 /* ProtocolBuffer.framework */; }; @@ -2221,6 +2235,8 @@ D41D36711EB14D87007FA978 /* libDiagnosticMessagesClient.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D41D36701EB14D87007FA978 /* libDiagnosticMessagesClient.tbd */; }; D425EC1D1DD3C3CF00DE5DEC /* SecInternalRelease.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCC761D8C68CF00070CB0 /* SecInternalRelease.c */; }; D425EC231DD3FFF200DE5DEC /* SecInternalRelease.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCC761D8C68CF00070CB0 /* SecInternalRelease.c */; }; + D4267BD123440F8900B54678 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF730310EF9CDE300E17471 /* CFNetwork.framework */; }; + D4267BD323440F9900B54678 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF730310EF9CDE300E17471 /* CFNetwork.framework */; }; D42C837C21158ACC008D3D83 /* cmscinfo.c in Sources */ = {isa = PBXBuildFile; fileRef = D44D1F8521158AAC00E76E1A /* cmscinfo.c */; }; D42C837D21158ACC008D3D83 /* cmsdigest.c in Sources */ = {isa = PBXBuildFile; fileRef = D44D1F8821158AAE00E76E1A /* cmsdigest.c */; }; D42C837E21158ACC008D3D83 /* cmsencode.c in Sources */ = {isa = PBXBuildFile; fileRef = D44D1F8A21158AAF00E76E1A /* cmsencode.c */; }; @@ -2425,7 +2441,17 @@ D479F6E31F981FD600388D28 /* OID.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C198F1F0ACDB4BF00AAB142 /* OID.strings */; }; D479F6E41F981FD600388D28 /* Certificate.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C198F1D0ACDB4BF00AAB142 /* Certificate.strings */; }; D479F6E51F981FD600388D28 /* Trust.strings in Resources */ = {isa = PBXBuildFile; fileRef = D479F6DF1F980F8F00388D28 /* Trust.strings */; }; + D47AB2CB2356AD72005A3801 /* Network.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D47AB2CA2356AD72005A3801 /* Network.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + D47AB2CC2356AD7C005A3801 /* Network.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D47AB2CA2356AD72005A3801 /* Network.framework */; }; + D47AB2CD2356AD8B005A3801 /* Network.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D47AB2CA2356AD72005A3801 /* Network.framework */; }; + D47AB2CE2356AD95005A3801 /* Network.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D47AB2CA2356AD72005A3801 /* Network.framework */; }; + D47AB2CF2356B2ED005A3801 /* Network.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D47AB2CA2356AD72005A3801 /* Network.framework */; }; + D47AB2D02356B2F6005A3801 /* Network.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D47AB2CA2356AD72005A3801 /* Network.framework */; }; + D47AB2D12356B2FE005A3801 /* Network.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D47AB2CA2356AD72005A3801 /* Network.framework */; }; + D47AB2D22356B325005A3801 /* Network.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D47AB2CA2356AD72005A3801 /* Network.framework */; }; + D47AB2D62357955F005A3801 /* Network.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D47AB2CA2356AD72005A3801 /* Network.framework */; }; D47CA65D1EB036450038E2BB /* libMobileGestalt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D47CA65C1EB036450038E2BB /* libMobileGestalt.dylib */; }; + D47DCCB523427C7D00B80E37 /* md.m in Sources */ = {isa = PBXBuildFile; fileRef = D47DCCB423427C7D00B80E37 /* md.m */; }; D47E69401E92F75D002C8CF6 /* si-61-pkcs12.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DD91D8085FC00865A7C /* si-61-pkcs12.c */; }; D47F514C1C3B812500A7CEFE /* SecCFAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = D47F514B1C3B812500A7CEFE /* SecCFAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; }; D487B9821DFA28DB000410A1 /* SecInternalReleasePriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BCC771D8C68CF00070CB0 /* SecInternalReleasePriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -3938,7 +3964,6 @@ DC5B391720C08B38005B09F6 /* SecFramework.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E4F1D8085FC00865A7C /* SecFramework.c */; }; DC5B391820C08B39005B09F6 /* SecFramework.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E4F1D8085FC00865A7C /* SecFramework.c */; }; DC5B391A20C08B70005B09F6 /* SecBase.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC5860220BF8A98005C7269 /* SecBase.c */; }; - DC5B391B20C08BDC005B09F6 /* SecFramework.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E4F1D8085FC00865A7C /* SecFramework.c */; }; DC5BB4FA1E0C90DE0010F836 /* CKKSIncomingQueueOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC5BB4F11E0C86800010F836 /* CKKSIncomingQueueOperation.m */; }; DC5BB4FE1E0C98320010F836 /* CKKSOutgoingQueueOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DC5BB4FC1E0C98320010F836 /* CKKSOutgoingQueueOperation.h */; }; DC5BB5001E0C98320010F836 /* CKKSOutgoingQueueOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC5BB4FD1E0C98320010F836 /* CKKSOutgoingQueueOperation.m */; }; @@ -5919,6 +5944,12 @@ EB0BC93A1C3C791500785842 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; EB0BC9671C3C798600785842 /* secedumodetest.m in Sources */ = {isa = PBXBuildFile; fileRef = EB0BC9661C3C794700785842 /* secedumodetest.m */; }; EB0DB37D1DCBC99100EAB6AE /* Keychain Circle Notification.8 in Install man8 page */ = {isa = PBXBuildFile; fileRef = EB76B75A1DCB0CDA00C43FBC /* Keychain Circle Notification.8 */; }; + EB0E1ACB2353A702002B6037 /* CKKSPBFileStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = EB973650234E8F4B00518B2B /* CKKSPBFileStorage.m */; }; + EB0E1ACD2353A704002B6037 /* CKKSRateLimiter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CC185981E24E87D009657D8 /* CKKSRateLimiter.m */; }; + EB0E1ACE2353A704002B6037 /* CKKSPBFileStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = EB973650234E8F4B00518B2B /* CKKSPBFileStorage.m */; }; + EB0E1ADA2357627F002B6037 /* CKKSPBFileStorageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB0E1AD723576273002B6037 /* CKKSPBFileStorageTests.m */; }; + EB0E1B912358FAC6002B6037 /* SOSAccountConfiguration.proto in Sources */ = {isa = PBXBuildFile; fileRef = EB0E1AC72352A81E002B6037 /* SOSAccountConfiguration.proto */; }; + EB0E1B942358FAF3002B6037 /* SOSAccountConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = EB0E1B932358FADE002B6037 /* SOSAccountConfiguration.m */; }; EB0F4A2C22F7D3DC009E855B /* OCMock.framework in Embedd OCMock */ = {isa = PBXBuildFile; fileRef = 47D1838B1FB3827700CFCD89 /* OCMock.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; EB1055791E14DF570003C309 /* SecCertificateFuzzer.c in Sources */ = {isa = PBXBuildFile; fileRef = EB10556B1E14DC0F0003C309 /* SecCertificateFuzzer.c */; }; EB1055831E14E1F90003C309 /* Digisign-Server-ID-Enrich-GTETrust-Cert.crt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 7947431C146214E500D638A3 /* Digisign-Server-ID-Enrich-GTETrust-Cert.crt */; }; @@ -6011,6 +6042,10 @@ EB59D6731E95F01600997EAC /* libcompression.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = EB59D66B1E95EF2900997EAC /* libcompression.dylib */; }; EB5E3BCC2003C67A00F1631B /* SecSignpost.h in Headers */ = {isa = PBXBuildFile; fileRef = EB5E3BC62003C66300F1631B /* SecSignpost.h */; settings = {ATTRIBUTES = (Private, ); }; }; EB5E3BCD2003C67B00F1631B /* SecSignpost.h in Headers */ = {isa = PBXBuildFile; fileRef = EB5E3BC62003C66300F1631B /* SecSignpost.h */; settings = {ATTRIBUTES = (Private, ); }; }; + EB627A73233E339200F32437 /* MockAKSOptionalParameters.proto in Sources */ = {isa = PBXBuildFile; fileRef = EB627A6F233E323600F32437 /* MockAKSOptionalParameters.proto */; }; + EB627A79233E375A00F32437 /* MockAKSOptionalParameters.proto in Sources */ = {isa = PBXBuildFile; fileRef = EB627A6F233E323600F32437 /* MockAKSOptionalParameters.proto */; }; + EB627A7E233E3C1300F32437 /* MockAKSOptionalParameters.m in Sources */ = {isa = PBXBuildFile; fileRef = EB627A77233E342B00F32437 /* MockAKSOptionalParameters.m */; }; + EB627A7F233E3C1600F32437 /* MockAKSRefKey.m in Sources */ = {isa = PBXBuildFile; fileRef = EB627A75233E342800F32437 /* MockAKSRefKey.m */; }; EB6667C7204CD69F000B404F /* testPlistDER.m in Sources */ = {isa = PBXBuildFile; fileRef = EB6667BE204CD65E000B404F /* testPlistDER.m */; }; EB6928C51D9C9C6E00062A18 /* SecRecoveryKey.h in Headers */ = {isa = PBXBuildFile; fileRef = EB6928BE1D9C9C5900062A18 /* SecRecoveryKey.h */; settings = {ATTRIBUTES = (Private, ); }; }; EB6928C61D9C9C6F00062A18 /* SecRecoveryKey.h in Headers */ = {isa = PBXBuildFile; fileRef = EB6928BE1D9C9C5900062A18 /* SecRecoveryKey.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -6096,6 +6131,7 @@ EB7E91212194849900B1FA21 /* SECC2MPMetric.m in Sources */ = {isa = PBXBuildFile; fileRef = EB7E91052193F97400B1FA21 /* SECC2MPMetric.m */; }; EB7E91222194849900B1FA21 /* SECC2MPNetworkEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = EB7E91072193F97500B1FA21 /* SECC2MPNetworkEvent.m */; }; EB7E91232194849900B1FA21 /* SECC2MPServerInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = EB7E910B2193F97700B1FA21 /* SECC2MPServerInfo.m */; }; + EB7ECF9623467FB400CE2D3C /* Cuttlefish.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE9F4F8B2072D881004A52C2 /* Cuttlefish.pb.swift */; }; EB80DE162195EDA4005B10FA /* SecC2DeviceInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = EB7E91102193FB7E00B1FA21 /* SecC2DeviceInfo.m */; }; EB80DE38219600A8005B10FA /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D4119E72202BDF2B0048587B /* libz.tbd */; }; EB80DE54219600B4005B10FA /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D4119E72202BDF2B0048587B /* libz.tbd */; }; @@ -6143,16 +6179,17 @@ EB8908B921F1953100F0DDDB /* CheckV12DevEnabled.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C4AEF83218A09210012C5DA /* CheckV12DevEnabled.m */; }; EB8908BA21F1957300F0DDDB /* SecAKSObjCWrappers.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C4AEF9D218A16F80012C5DA /* SecAKSObjCWrappers.m */; }; EB8908BE21F2181600F0DDDB /* SFKeychainControlManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 473337781FDAFBCC00E19F30 /* SFKeychainControlManager.m */; }; + EB8A9381233C900D0015A794 /* CloudServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C8A38C817B93DF10001B4C0 /* CloudServices.framework */; }; + EB973651234E8F4B00518B2B /* CKKSPBFileStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = EB97364F234E8F4A00518B2B /* CKKSPBFileStorage.h */; }; + EB973652234E8F4B00518B2B /* CKKSPBFileStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = EB973650234E8F4B00518B2B /* CKKSPBFileStorage.m */; }; EB9795B522FE9256002BDBFB /* SecItemTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB6D1D5322FE8D3000205E83 /* SecItemTests.m */; }; EB9B283321C7755700173DC2 /* OTDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C8BBE971FC9DA5A00580909 /* OTDefines.h */; settings = {ATTRIBUTES = (Private, ); }; }; EB9B283421C7755800173DC2 /* OTDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C8BBE971FC9DA5A00580909 /* OTDefines.h */; settings = {ATTRIBUTES = (Private, ); }; }; EB9B285721C77C8D00173DC2 /* OTDefines.m in Sources */ = {isa = PBXBuildFile; fileRef = EBCE06E521C6E26000FB1493 /* OTDefines.m */; }; EB9B285821C77C8D00173DC2 /* OTDefines.m in Sources */ = {isa = PBXBuildFile; fileRef = EBCE06E521C6E26000FB1493 /* OTDefines.m */; }; - EB9B285921C77E7400173DC2 /* OTDefines.m in Sources */ = {isa = PBXBuildFile; fileRef = EBCE06E521C6E26000FB1493 /* OTDefines.m */; }; EB9C02481E8A15B40040D3C6 /* secd-37-pairing-initial-sync.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9C02421E8A112A0040D3C6 /* secd-37-pairing-initial-sync.m */; }; EB9C1D7B1BDFD0E000F89272 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; EB9C1D7E1BDFD0E100F89272 /* secbackupntest.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9C1D7D1BDFD0E100F89272 /* secbackupntest.m */; }; - EB9C1DB51BDFD50100F89272 /* Security.plist in Install BATS plist */ = {isa = PBXBuildFile; fileRef = EB9C1DAD1BDFD49400F89272 /* Security.plist */; }; EBA689031E74732700FF90A7 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; EBA9AA811CE30E58004E2B68 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D82BD316A5EADA0078DFE5 /* Security.framework */; }; EBA9AA821CE30E58004E2B68 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; @@ -6173,7 +6210,6 @@ EBC1024422EBF93E0083D356 /* CKKSTests+LockStateTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = EBC1023022EBF8AC0083D356 /* CKKSTests+LockStateTracker.m */; }; EBC15B1D1DB432F800126882 /* com.apple.secd.sb in Copy Sandbox profile */ = {isa = PBXBuildFile; fileRef = EBC15B1B1DB4306C00126882 /* com.apple.secd.sb */; }; EBC73F2020993F8600AE3350 /* SFAnalyticsSQLiteStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C69518D1F75A7DB00F68F91 /* SFAnalyticsSQLiteStore.m */; }; - EBC73F2620993FA800AE3350 /* client_endpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = DC844AEC1E81F315007AAB71 /* client_endpoint.m */; }; EBC73F2720993FC900AE3350 /* SFAnalyticsMultiSampler.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CDB5FED1FA78CB400410924 /* SFAnalyticsMultiSampler.m */; }; EBC73F2820993FDA00AE3350 /* SFAnalyticsSampler.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CDF8DE61F95562B00140B54 /* SFAnalyticsSampler.m */; }; EBC73F29209966AF00AE3350 /* SFSQLite.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BC1F152EB10082882F /* SFSQLite.m */; }; @@ -6187,6 +6223,8 @@ EBD531772198AF19003A57E6 /* Accounts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF4C19C171E0EA600877419 /* Accounts.framework */; }; EBDAA7E920EC4838003EA6E5 /* SecurityLocalKeychain.plist in Install BATS plist */ = {isa = PBXBuildFile; fileRef = EBDAA7E320EC46CF003EA6E5 /* SecurityLocalKeychain.plist */; }; EBDAF15D21C75FF200EAE89F /* NSXPCConnectionMock.h in Headers */ = {isa = PBXBuildFile; fileRef = EBDAF15B21C75FF200EAE89F /* NSXPCConnectionMock.h */; }; + EBDCC001233DD3E000806566 /* MockAKSRefKey.proto in Sources */ = {isa = PBXBuildFile; fileRef = EBDCBFFE233DD31700806566 /* MockAKSRefKey.proto */; }; + EBDCC002233DD45700806566 /* MockAKSRefKey.proto in Sources */ = {isa = PBXBuildFile; fileRef = EBDCBFFE233DD31700806566 /* MockAKSRefKey.proto */; }; EBDE5E0E22BA3DE900A229C8 /* CKKSMockOctagonAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = EBDE5DFA22BA3D5D00A229C8 /* CKKSMockOctagonAdapter.m */; }; EBDE5E0F22BA3DEA00A229C8 /* CKKSMockOctagonAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = EBDE5DFA22BA3D5D00A229C8 /* CKKSMockOctagonAdapter.m */; }; EBE2026B20908C7100B48020 /* tpctl.8 in install man8 page */ = {isa = PBXBuildFile; fileRef = EBE2026420908A8A00B48020 /* tpctl.8 */; }; @@ -6319,13 +6357,6 @@ remoteGlobalIDString = DC0BCC211D8C684F00070CB0; remoteInfo = utilities; }; - 0C604F0121B8E5090036C175 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4C35DB69094F906D002917C4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DCF216D621ADD5B10029CCC1; - remoteInfo = protobuf_source_generation; - }; 0C78CCE41FCC97E7008B4B24 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -9266,13 +9297,6 @@ remoteGlobalIDString = DC52E8BE1D80C25800B0A59C; remoteInfo = SecureObjectSync; }; - DC74799F22272361001E0E8C /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4C35DB69094F906D002917C4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DCF216D621ADD5B10029CCC1; - remoteInfo = protobuf_source_generation; - }; DC7FC45121EE9208003C39B8 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -9819,27 +9843,6 @@ remoteGlobalIDString = DCDA5E4F2124B9C5009B11B2; remoteInfo = aks_support; }; - DCE0775B21ADD6A0002662FD /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4C35DB69094F906D002917C4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DCF216D621ADD5B10029CCC1; - remoteInfo = protobuf_source_generation; - }; - DCE0777D21ADEADA002662FD /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4C35DB69094F906D002917C4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DCF216D621ADD5B10029CCC1; - remoteInfo = protobuf_source_generation; - }; - DCE0778321ADEDDA002662FD /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4C35DB69094F906D002917C4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DCF216D621ADD5B10029CCC1; - remoteInfo = protobuf_source_generation; - }; DCE4E8D71D7F37F200AFB96E /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -9903,83 +9906,6 @@ remoteGlobalIDString = DCF788AB1D88CD2400E694BB; remoteInfo = security_apple_x509_tp; }; - E058E54A21626583002CA574 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = E058E53221626582002CA574 /* OctagonTrieste.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = "TriesteKit::CloudDeviceTest::Product"; - remoteInfo = CloudDeviceTest; - }; - E058E54C21626583002CA574 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = E058E53221626582002CA574 /* OctagonTrieste.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = "TriesteKit::CoreDeviceAutomation::Product"; - remoteInfo = CoreDeviceAutomation; - }; - E058E54E21626583002CA574 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = E058E53221626582002CA574 /* OctagonTrieste.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = "TriesteKit::CoreDeviceAutomationFrameworkFacade::Product"; - remoteInfo = CoreDeviceAutomationFrameworkFacade; - }; - E058E55021626583002CA574 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = E058E53221626582002CA574 /* OctagonTrieste.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = "OctagonTestHarnessXPCServiceProtocol::OctagonTestHarnessXPCServiceProtocol::Product"; - remoteInfo = OctagonTestHarnessXPCServiceProtocol; - }; - E058E55221626583002CA574 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = E058E53221626582002CA574 /* OctagonTrieste.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = "OctagonTrieste::OctagonTrieste::Product"; - remoteInfo = OctagonTrieste; - }; - E058E55421626583002CA574 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = E058E53221626582002CA574 /* OctagonTrieste.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = "OctagonTrieste::OctagonTriesteTests::Product"; - remoteInfo = OctagonTriesteTests; - }; - E058E55621626583002CA574 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = E058E53221626582002CA574 /* OctagonTrieste.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = "SwiftHTTP::OpenSSLThreadLock::Product"; - remoteInfo = OpenSSLThreadLock; - }; - E058E55A21626583002CA574 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = E058E53221626582002CA574 /* OctagonTrieste.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = "SSEClient::SSEClient::Product"; - remoteInfo = SSEClient; - }; - E058E55C21626583002CA574 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = E058E53221626582002CA574 /* OctagonTrieste.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = "SwiftHTTP::SwiftHTTP::Product"; - remoteInfo = SwiftHTTP; - }; - E058E55E21626583002CA574 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = E058E53221626582002CA574 /* OctagonTrieste.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = "SwiftLog::SwiftLog::Product"; - remoteInfo = SwiftLog; - }; - E058E56021626583002CA574 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = E058E53221626582002CA574 /* OctagonTrieste.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = "TriesteKit::os_activity::Product"; - remoteInfo = os_activity; - }; E060D1AA212478100025B833 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -10330,13 +10256,6 @@ remoteGlobalIDString = EBB851EB22F7912400424FD0; remoteInfo = SecurityUtilitiesTests; }; - EBBC11B22200D3BB00F95738 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 4C35DB69094F906D002917C4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = DCF216D621ADD5B10029CCC1; - remoteInfo = protobuf_source_generation; - }; EBCF743E1CE593A700BED7CA /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4C35DB69094F906D002917C4 /* Project object */; @@ -10455,6 +10374,17 @@ name = "Install man1 pages"; runOnlyForDeploymentPostprocessing = 1; }; + 0C97867A235A766B0040A867 /* Copy System logging profile */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /System/Library/Preferences/Logging/Subsystems; + dstSubfolderSpec = 0; + files = ( + 0C97867D235A77230040A867 /* com.apple.security.signposts.plist in Copy System logging profile */, + ); + name = "Copy System logging profile"; + runOnlyForDeploymentPostprocessing = 1; + }; 0C9AEEB320783FBB00BF6237 /* Embed OCMock */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -11579,7 +11509,6 @@ dstPath = /AppleInternal/CoreOS/BATS/unit_tests; dstSubfolderSpec = 0; files = ( - EB9C1DB51BDFD50100F89272 /* Security.plist in Install BATS plist */, EB3A8DFF1BEEC66F001A89AA /* Security_edumode.plist in Install BATS plist */, EB3D1FBA2092CB030049EF95 /* SecurityInduceLowDisk.plist in Install BATS plist */, EBDAA7E920EC4838003EA6E5 /* SecurityLocalKeychain.plist in Install BATS plist */, @@ -11740,6 +11669,7 @@ 0C8BBF101FCB486B00580909 /* OTManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTManager.h; sourceTree = ""; }; 0C8FD546214AEC650098E3FB /* OTJoiningConfiguration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTJoiningConfiguration.h; sourceTree = ""; }; 0C8FD549214AECD70098E3FB /* OTJoiningConfiguration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTJoiningConfiguration.m; sourceTree = ""; }; + 0C97867C235A76E70040A867 /* com.apple.security.signposts.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.security.signposts.plist; sourceTree = ""; }; 0C9AE289214054F4003BFDB5 /* OTSponsorToApplicantRound1M2.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTSponsorToApplicantRound1M2.h; sourceTree = ""; }; 0C9AE28A214054F5003BFDB5 /* OTSponsorToApplicantRound2M2.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTSponsorToApplicantRound2M2.h; sourceTree = ""; }; 0C9AE28B214054F5003BFDB5 /* OTApplicantToSponsorRound2M1.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTApplicantToSponsorRound2M1.h; sourceTree = ""; }; @@ -11789,6 +11719,8 @@ 0CD8CB041ECA50780076F37F /* SOSPeerOTRTimer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SOSPeerOTRTimer.m; sourceTree = ""; }; 0CD8CB0C1ECA50D10076F37F /* SOSPeerOTRTimer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSPeerOTRTimer.h; sourceTree = ""; }; 0CD8D654207D6E65005CDBE8 /* SFAnalytics+Signin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SFAnalytics+Signin.h"; sourceTree = ""; }; + 0CD9E33E235928D1002995DE /* OctagonSignPosts.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OctagonSignPosts.h; sourceTree = ""; }; + 0CD9E340235928E9002995DE /* OctagonSignPosts.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OctagonSignPosts.m; sourceTree = ""; }; 0CDBCD8620AD03FB007F8EA7 /* OTClique.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTClique.h; sourceTree = ""; }; 0CDD6F76226E62AD009094C2 /* OTTriggerEscrowUpdateOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTTriggerEscrowUpdateOperation.m; sourceTree = ""; }; 0CDD6F78226E62BC009094C2 /* OTTriggerEscrowUpdateOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTTriggerEscrowUpdateOperation.h; sourceTree = ""; }; @@ -11822,6 +11754,9 @@ 107226D10D91DB32003CF14F /* SecTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTask.h; path = sectask/SecTask.h; sourceTree = ""; }; 107227350D91FE89003CF14F /* libbsm.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbsm.dylib; path = usr/lib/libbsm.dylib; sourceTree = SDKROOT; }; 18351B8F14CB65870097860E /* SecBase64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecBase64.h; sourceTree = ""; }; + 1B2BD391235E050D009A8624 /* SecEC-tapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "SecEC-tapi.h"; path = "OSX/sec/Security/SecEC-tapi.h"; sourceTree = ""; }; + 1B2BD393235E050E009A8624 /* SecPolicy-tapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "SecPolicy-tapi.h"; path = "OSX/sec/Security/SecPolicy-tapi.h"; sourceTree = ""; }; + 1B2BD394235E050E009A8624 /* Security-tapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "Security-tapi.h"; path = "OSX/sec/Security/Security-tapi.h"; sourceTree = ""; }; 1B4C4448223AE65400C6F97F /* TPPBPolicyKeyViewMapping.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPPBPolicyKeyViewMapping.h; sourceTree = ""; }; 1B4C444A223AE65400C6F97F /* TPPBPolicyKeyViewMapping.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPPBPolicyKeyViewMapping.m; sourceTree = ""; }; 1B5EAAD92252ABCC008D27E7 /* OTFetchViewsOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTFetchViewsOperation.h; sourceTree = ""; }; @@ -11835,6 +11770,9 @@ 1BC6F79821C9955E005ED67A /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = util.h; sourceTree = ""; }; 1BDEBEF72252DEB1009AD3D6 /* policy_dryrun.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = policy_dryrun.m; sourceTree = ""; }; 1BDEBEFA2252E1DD009AD3D6 /* policy_dryrun.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = policy_dryrun.h; sourceTree = ""; }; + 1BE85ECD235CEB610051E1D8 /* cms-tapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "cms-tapi.h"; path = "OSX/libsecurity_smime/lib/cms-tapi.h"; sourceTree = ""; }; + 1BE85ED1235CEBB30051E1D8 /* secport-tapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "secport-tapi.h"; sourceTree = ""; }; + 1BE85ED4235CEC250051E1D8 /* sslDeprecated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sslDeprecated.h; path = OSX/libsecurity_ssl/lib/sslDeprecated.h; sourceTree = ""; }; 1BF640EE222EEB6C002D0FCB /* TPPolicyTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TPPolicyTests.m; sourceTree = ""; }; 1F631C5122387F27005920D8 /* legacydevid.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = legacydevid.cpp; sourceTree = ""; usesTabs = 0; }; 1F631C5222387F27005920D8 /* legacydevid.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = legacydevid.h; sourceTree = ""; }; @@ -11842,12 +11780,7 @@ 225394B41E3080A600D3CD9B /* libsecurity_codesigning_ios.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libsecurity_codesigning_ios.a; sourceTree = BUILT_PRODUCTS_DIR; }; 2281820D17B4686C0067C9C9 /* BackgroundTaskAgent.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BackgroundTaskAgent.framework; path = System/Library/PrivateFrameworks/BackgroundTaskAgent.framework; sourceTree = SDKROOT; }; 24CBF8731E9D4E4500F09F0E /* kc-44-secrecoverypassword.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "kc-44-secrecoverypassword.c"; path = "regressions/kc-44-secrecoverypassword.c"; sourceTree = ""; }; - 3D1A57412166931B009C24FD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 3D421458216C0A2400D62870 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; 3D58394D21890FFB000ACA44 /* SecExperimentTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SecExperimentTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 3D6C25BA216C00D800AB2A71 /* TLSConfig.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = TLSConfig.plist; sourceTree = ""; }; - 3D7AA28E2187AD0000F1575C /* SecExperimentTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SecExperimentTests.m; sourceTree = ""; }; - 3DA3384421658AA8008C0CE1 /* SecExperimentPriv.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecExperimentPriv.h; sourceTree = ""; }; 3DD1FE78201AA50C0086D049 /* STLegacyTests+clientauth41.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "STLegacyTests+clientauth41.m"; sourceTree = ""; }; 3DD1FE79201AA50D0086D049 /* SecureTransport_macosTests.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = SecureTransport_macosTests.plist; sourceTree = ""; }; 3DD1FE7A201AA50D0086D049 /* STLegacyTests-Entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "STLegacyTests-Entitlements.plist"; sourceTree = ""; }; @@ -11874,7 +11807,6 @@ 3DD1FFA9201FC5C30086D049 /* libcoretls_cfhelpers.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcoretls_cfhelpers.tbd; path = usr/lib/libcoretls_cfhelpers.tbd; sourceTree = SDKROOT; }; 3DD1FFD0201FDB1D0086D049 /* SecureTransport_ios_tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SecureTransport_ios_tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3DD2589820478CCE00F5DA78 /* STLegacyTests+session.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "STLegacyTests+session.m"; sourceTree = ""; }; - 3DD852B02177FF72009E705D /* SecExperiment.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SecExperiment.m; sourceTree = ""; }; 433E519D1B66D5F600482618 /* AppSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppSupport.framework; path = System/Library/PrivateFrameworks/AppSupport.framework; sourceTree = SDKROOT; }; 4381690C1B4EDCBD00C54D58 /* SOSCCAuthPlugin.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SOSCCAuthPlugin.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 4381690F1B4EDCBD00C54D58 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -12174,8 +12106,14 @@ 5A06118D229ED5EB006AF14A /* NSDate+SFAnalytics.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSDate+SFAnalytics.m"; sourceTree = ""; }; 5A061190229ED60C006AF14A /* NSDate+SFAnalytics.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSDate+SFAnalytics.h"; sourceTree = ""; }; 5A1A1C2122A71D2A00CB8D1D /* NSDate+SFAnalyticsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDate+SFAnalyticsTests.m"; sourceTree = ""; }; - 5A2551F12229F40800512FAE /* SecExperimentInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecExperimentInternal.h; sourceTree = ""; }; 5A43A07F225FA38D005450E4 /* SecProtocolHelperTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SecProtocolHelperTest.m; path = protocol/SecProtocolHelperTest.m; sourceTree = ""; }; + 5A442F90233C330F00918373 /* experimentTool */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = experimentTool; sourceTree = BUILT_PRODUCTS_DIR; }; + 5A442F98233C34C000918373 /* SecExperimentPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecExperimentPriv.h; sourceTree = ""; }; + 5A442F9A233C34C000918373 /* SecExperimentTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecExperimentTests.m; sourceTree = ""; }; + 5A442F9B233C34C000918373 /* SecExperimentInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecExperimentInternal.h; sourceTree = ""; }; + 5A442F9C233C34C000918373 /* SecExperiment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecExperiment.m; sourceTree = ""; }; + 5A442F9E233C34C000918373 /* experimentTool-Entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "experimentTool-Entitlements.plist"; sourceTree = ""; }; + 5A442F9F233C34C000918373 /* experimentTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = experimentTool.m; sourceTree = ""; }; 5A47FFB1228F5DF700F781B8 /* KCInitialMessageData.proto */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.protobuf; path = KCInitialMessageData.proto; sourceTree = ""; }; 5A47FFB4228F5E9000F781B8 /* KCInitialMessageData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KCInitialMessageData.h; path = generated_source/KCInitialMessageData.h; sourceTree = ""; }; 5A47FFB5228F5E9000F781B8 /* KCInitialMessageData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = KCInitialMessageData.m; path = generated_source/KCInitialMessageData.m; sourceTree = ""; }; @@ -12454,6 +12392,7 @@ BEC373C120D8224A00DBDF5B /* TPPBDispositionEntry.proto */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.protobuf; path = TPPBDispositionEntry.proto; sourceTree = ""; }; BEC373C920D822CD00DBDF5B /* TPPBDispositionEntry.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TPPBDispositionEntry.m; sourceTree = ""; }; BEC373CA20D822CE00DBDF5B /* TPPBDispositionEntry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TPPBDispositionEntry.h; sourceTree = ""; }; + BEC6A9142331992800080069 /* Network.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Network.framework; path = System/Library/Frameworks/Network.framework; sourceTree = SDKROOT; }; BECEC0FD20A3B94C00E97255 /* TrustedPeersHelperUnitTests-BridgingHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TrustedPeersHelperUnitTests-BridgingHeader.h"; sourceTree = ""; }; BECEC11020A508F600E97255 /* TPVoucher.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TPVoucher.h; sourceTree = ""; }; BECEC11120A508F600E97255 /* TPVoucher.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TPVoucher.m; sourceTree = ""; }; @@ -12702,10 +12641,13 @@ D4707A2B2114B31A005BCFDA /* SecCmsContentInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCmsContentInfo.h; path = CMS/SecCmsContentInfo.h; sourceTree = ""; }; D4707A2E2114C30A005BCFDA /* SecCmsDigestContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCmsDigestContext.h; path = CMS/SecCmsDigestContext.h; sourceTree = ""; }; D479F6E01F980F8F00388D28 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = en.lproj/Trust.strings; sourceTree = ""; }; + D47AB2CA2356AD72005A3801 /* Network.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Network.framework; path = System/Library/Frameworks/Network.framework; sourceTree = SDKROOT; }; D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = lib_ios_x64.xcconfig; path = xcconfig/lib_ios_x64.xcconfig; sourceTree = ""; }; D47C56AF1DCA841D00E18518 /* lib_ios_x64_shim.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = lib_ios_x64_shim.xcconfig; path = xcconfig/lib_ios_x64_shim.xcconfig; sourceTree = ""; }; D47C56FB1DCA8F4900E18518 /* all_arches.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = all_arches.xcconfig; path = xcconfig/all_arches.xcconfig; sourceTree = ""; }; D47CA65C1EB036450038E2BB /* libMobileGestalt.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libMobileGestalt.dylib; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.0.Internal.sdk/usr/lib/libMobileGestalt.dylib; sourceTree = DEVELOPER_DIR; }; + D47DCCB423427C7D00B80E37 /* md.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = md.m; sourceTree = ""; }; + D47DCCB723427C8D00B80E37 /* md.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = md.h; sourceTree = ""; }; D47F514B1C3B812500A7CEFE /* SecCFAllocator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecCFAllocator.h; sourceTree = ""; }; D48BD193206C47530075DDC9 /* si-35-cms-expiration-time.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "si-35-cms-expiration-time.m"; sourceTree = ""; }; D48BD195206C476B0075DDC9 /* si-35-cms-expiration-time.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "si-35-cms-expiration-time.h"; sourceTree = ""; }; @@ -15624,7 +15566,6 @@ DCFF82702162834C00D54B02 /* OctagonTestsXPCConnections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OctagonTestsXPCConnections.swift; sourceTree = ""; }; DCFF82722162876400D54B02 /* OTResetOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTResetOperation.h; sourceTree = ""; }; DCFF82732162876400D54B02 /* OTResetOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTResetOperation.m; sourceTree = ""; }; - E058E53221626582002CA574 /* OctagonTrieste.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = OctagonTrieste.xcodeproj; path = OctagonTriesteTests/OctagonTrieste.xcodeproj; sourceTree = ""; }; E060D19C2124780E0025B833 /* OctagonTestHarness.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OctagonTestHarness.framework; sourceTree = BUILT_PRODUCTS_DIR; }; E060D19E2124780F0025B833 /* OctagonTestHarness.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OctagonTestHarness.h; sourceTree = ""; }; E060D19F2124780F0025B833 /* OctagonTestHarnessXPCService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OctagonTestHarnessXPCService.h; sourceTree = ""; }; @@ -15726,6 +15667,10 @@ EB0BC93E1C3C791500785842 /* secedumodetest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = secedumodetest; sourceTree = BUILT_PRODUCTS_DIR; }; EB0BC9651C3C794700785842 /* secedumodetest.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = secedumodetest.entitlements; path = secedumodetest/secedumodetest.entitlements; sourceTree = ""; }; EB0BC9661C3C794700785842 /* secedumodetest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = secedumodetest.m; path = secedumodetest/secedumodetest.m; sourceTree = ""; }; + EB0E1AC72352A81E002B6037 /* SOSAccountConfiguration.proto */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.protobuf; path = SOSAccountConfiguration.proto; sourceTree = ""; }; + EB0E1AD723576273002B6037 /* CKKSPBFileStorageTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSPBFileStorageTests.m; sourceTree = ""; }; + EB0E1B922358FADE002B6037 /* SOSAccountConfiguration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSAccountConfiguration.h; sourceTree = ""; }; + EB0E1B932358FADE002B6037 /* SOSAccountConfiguration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SOSAccountConfiguration.m; sourceTree = ""; }; EB10556B1E14DC0F0003C309 /* SecCertificateFuzzer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecCertificateFuzzer.c; sourceTree = ""; }; EB1055751E14DF430003C309 /* libSecCertificateFuzzer.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libSecCertificateFuzzer.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; EB10557A1E14DF640003C309 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; }; @@ -15774,6 +15719,11 @@ EB4E0CD51FF36A1900CDCACC /* CKKSReachabilityTracker.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSReachabilityTracker.m; sourceTree = ""; }; EB59D66B1E95EF2900997EAC /* libcompression.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcompression.dylib; path = usr/lib/libcompression.dylib; sourceTree = SDKROOT; }; EB5E3BC62003C66300F1631B /* SecSignpost.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SecSignpost.h; path = base/SecSignpost.h; sourceTree = ""; }; + EB627A6F233E323600F32437 /* MockAKSOptionalParameters.proto */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.protobuf; path = MockAKSOptionalParameters.proto; sourceTree = ""; }; + EB627A75233E342800F32437 /* MockAKSRefKey.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockAKSRefKey.m; sourceTree = ""; }; + EB627A76233E342900F32437 /* MockAKSRefKey.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockAKSRefKey.h; sourceTree = ""; }; + EB627A77233E342B00F32437 /* MockAKSOptionalParameters.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockAKSOptionalParameters.m; sourceTree = ""; }; + EB627A78233E342B00F32437 /* MockAKSOptionalParameters.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockAKSOptionalParameters.h; sourceTree = ""; }; EB6667BE204CD65E000B404F /* testPlistDER.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = testPlistDER.m; sourceTree = ""; }; EB6928BE1D9C9C5900062A18 /* SecRecoveryKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecRecoveryKey.h; sourceTree = ""; }; EB6928BF1D9C9C5900062A18 /* SecRecoveryKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecRecoveryKey.m; sourceTree = ""; }; @@ -15838,6 +15788,8 @@ EB89088621F17D3C00F0DDDB /* recovery_securityd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = recovery_securityd; sourceTree = BUILT_PRODUCTS_DIR; }; EB8908BB21F20E0200F0DDDB /* com.apple.recovery_securityd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.recovery_securityd.plist; sourceTree = ""; }; EB89111020E3C15D00DE533F /* UserManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserManagement.framework; path = System/Library/PrivateFrameworks/UserManagement.framework; sourceTree = SDKROOT; }; + EB97364F234E8F4A00518B2B /* CKKSPBFileStorage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CKKSPBFileStorage.h; path = keychain/ckks/CKKSPBFileStorage.h; sourceTree = SOURCE_ROOT; }; + EB973650234E8F4B00518B2B /* CKKSPBFileStorage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = CKKSPBFileStorage.m; path = keychain/ckks/CKKSPBFileStorage.m; sourceTree = SOURCE_ROOT; }; EB9795B422FE90E6002BDBFB /* SecurityUnitTests.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SecurityUnitTests.entitlements; sourceTree = ""; }; EB9C02421E8A112A0040D3C6 /* secd-37-pairing-initial-sync.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-37-pairing-initial-sync.m"; sourceTree = ""; }; EB9C1D7A1BDFD0E000F89272 /* secbackupntest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = secbackupntest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -15869,6 +15821,7 @@ EBDAA7E320EC46CF003EA6E5 /* SecurityLocalKeychain.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = SecurityLocalKeychain.plist; sourceTree = ""; }; EBDAF15B21C75FF200EAE89F /* NSXPCConnectionMock.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NSXPCConnectionMock.h; sourceTree = ""; }; EBDAF15C21C75FF200EAE89F /* NSXPCConnectionMock.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NSXPCConnectionMock.m; sourceTree = ""; }; + EBDCBFFE233DD31700806566 /* MockAKSRefKey.proto */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.protobuf; path = MockAKSRefKey.proto; sourceTree = ""; }; EBDE5DF922BA3D5D00A229C8 /* CKKSMockOctagonAdapter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKSMockOctagonAdapter.h; sourceTree = ""; }; EBDE5DFA22BA3D5D00A229C8 /* CKKSMockOctagonAdapter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSMockOctagonAdapter.m; sourceTree = ""; }; EBE2026420908A8A00B48020 /* tpctl.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = tpctl.8; sourceTree = ""; }; @@ -15905,6 +15858,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D47AB2D22356B325005A3801 /* Network.framework in Frameworks */, DCF46572220114E400BA6EEA /* CloudServices.framework in Frameworks */, EB80DE55219600BF005B10FA /* libz.tbd in Frameworks */, DC9C066E2149E35F00C6F7B8 /* AuthKit.framework in Frameworks */, @@ -16280,6 +16234,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D47AB2D12356B2FE005A3801 /* Network.framework in Frameworks */, DC4A76AD22126A17006F2D8F /* CloudServices.framework in Frameworks */, 0C6C0FD621F14D3900CD5B9E /* CoreCDP.framework in Frameworks */, EB80DE5B219600FC005B10FA /* libz.tbd in Frameworks */, @@ -16389,6 +16344,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 5A442F89233C330F00918373 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5A442F8A233C330F00918373 /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 5E10992219A5E55800A60E2B /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -16732,7 +16695,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 1B916CCE223FFED7006657FD /* libprotobuf_source_generation.a in Frameworks */, DC730E2922401F5E0051DD48 /* ProtocolBuffer.framework in Frameworks */, DC730E2522401E310051DD48 /* TrustedPeers.framework in Frameworks */, 1B916CD0223FFF25006657FD /* ProtocolBuffer.framework in Frameworks */, @@ -16747,6 +16709,7 @@ D46246AA1F9AE6CA00D63882 /* libDER.a in Frameworks */, D41258011E94230400781F23 /* IOKit.framework in Frameworks */, D41257E01E94136000781F23 /* libz.dylib in Frameworks */, + D47AB2CB2356AD72005A3801 /* Network.framework in Frameworks */, D41257DF1E94133600781F23 /* CFNetwork.framework in Frameworks */, D41257DE1E94132900781F23 /* libsqlite3.dylib in Frameworks */, D41257DB1E9412E700781F23 /* libutilities.a in Frameworks */, @@ -16783,6 +16746,8 @@ D4428B36212262F800EB8448 /* libASN1.a in Frameworks */, D453A4B62122236D00850A26 /* libtrustd.a in Frameworks */, D4EF32172156B025000A31A5 /* Security.framework in Frameworks */, + D47AB2CE2356AD95005A3801 /* Network.framework in Frameworks */, + D4267BD323440F9900B54678 /* CFNetwork.framework in Frameworks */, D453A4B82122236D00850A26 /* CoreFoundation.framework in Frameworks */, D453A4B92122236D00850A26 /* Foundation.framework in Frameworks */, D453A4BA2122236D00850A26 /* IOKit.framework in Frameworks */, @@ -16819,6 +16784,8 @@ D4B68C5B211A7D29009FED69 /* libutilities.a in Frameworks */, D4B68C44211A3DCC009FED69 /* libtrustd.a in Frameworks */, D453A4A32122235700850A26 /* Security.framework in Frameworks */, + D4267BD123440F8900B54678 /* CFNetwork.framework in Frameworks */, + D47AB2CD2356AD8B005A3801 /* Network.framework in Frameworks */, D4B68C60211A80BC009FED69 /* CoreFoundation.framework in Frameworks */, D4B68C61211A80C4009FED69 /* Foundation.framework in Frameworks */, D4B68C63211A80DA009FED69 /* IOKit.framework in Frameworks */, @@ -17276,8 +17243,8 @@ DCD22D591D8CC200001C9B81 /* libsecurity_cdsa_client.a in Frameworks */, DCD22D5A1D8CC205001C9B81 /* libsecurity_cdsa_utilities.a in Frameworks */, DCD22D5B1D8CC20D001C9B81 /* libsecurity_cdsa_utils.a in Frameworks */, - BE64A7FB22AF0084001209F3 /* CFNetwork.framework in Frameworks */, BE64A7FC22AF008D001209F3 /* Foundation.framework in Frameworks */, + BEC6A9162331992900080069 /* Network.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -17314,6 +17281,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D47AB2D62357955F005A3801 /* Network.framework in Frameworks */, DCF46573220114F000BA6EEA /* CloudServices.framework in Frameworks */, 0C4D96A621F24E5700617E60 /* CoreCDP.framework in Frameworks */, EB80DE56219600C6005B10FA /* libz.tbd in Frameworks */, @@ -17605,6 +17573,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D47AB2D02356B2F6005A3801 /* Network.framework in Frameworks */, 09EF431B21A5A8CC0066CF20 /* libaks_acl.a in Frameworks */, D4C6C5CD1FB3B423007EA57E /* libarchive.tbd in Frameworks */, D46246B71F9AE76500D63882 /* libDER.a in Frameworks */, @@ -17699,6 +17668,7 @@ D40B6A831E2B5F5B00CD6EE5 /* libASN1.a in Frameworks */, D40B6A9D1E2B6A2700CD6EE5 /* login.framework in Frameworks */, D4ADA3311E2B43450031CEA3 /* CFNetwork.framework in Frameworks */, + D47AB2CC2356AD7C005A3801 /* Network.framework in Frameworks */, D4ADA3301E2B433B0031CEA3 /* Security.framework in Frameworks */, D4ADA32E1E2B43220031CEA3 /* CoreFoundation.framework in Frameworks */, D4ADA32F1E2B43220031CEA3 /* Foundation.framework in Frameworks */, @@ -17823,6 +17793,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + EB8A9381233C900D0015A794 /* CloudServices.framework in Frameworks */, EBFF95EF214C823F0021CD14 /* KeychainCircle.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -17831,6 +17802,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D47AB2CF2356B2ED005A3801 /* Network.framework in Frameworks */, DC4A76A62212691F006F2D8F /* CloudServices.framework in Frameworks */, 0C6C0FCF21F1457600CD5B9E /* CoreCDP.framework in Frameworks */, EB80DE5C2196010F005B10FA /* libz.tbd in Frameworks */, @@ -18174,6 +18146,8 @@ isa = PBXGroup; children = ( 0C9FB40120D8729A00864612 /* CoreCDP.framework */, + DCD067E71D8CDF7E007602F1 /* SecCodeHostLib.h */, + DCD067E81D8CDF7E007602F1 /* SecCodeHostLib.c */, ); name = "Recovered References"; sourceTree = ""; @@ -18307,16 +18281,18 @@ name = RecoveryKey; sourceTree = ""; }; - 0CF0E2DD1F8EE37C00BD18E4 /* Signin Metrics */ = { + 0CF0E2DD1F8EE37C00BD18E4 /* SigninMetrics */ = { isa = PBXGroup; children = ( 0CF405FB2072E351003D6A7F /* Resources */, + 0CD9E33E235928D1002995DE /* OctagonSignPosts.h */, + 0CD9E340235928E9002995DE /* OctagonSignPosts.m */, 0CF0E2E71F8EE40700BD18E4 /* SFSignInAnalytics.h */, 0CF0E2E31F8EE3B000BD18E4 /* SFSignInAnalytics.m */, 0C108C4B208A677100E8CF70 /* SFSignInAnalytics+Internal.h */, 0CF405F32072E295003D6A7F /* tests */, ); - path = "Signin Metrics"; + path = SigninMetrics; sourceTree = ""; }; 0CF405F32072E295003D6A7F /* tests */ = { @@ -18330,6 +18306,7 @@ 0CF405FB2072E351003D6A7F /* Resources */ = { isa = PBXGroup; children = ( + 0C97867C235A76E70040A867 /* com.apple.security.signposts.plist */, 0CF405FC2072E352003D6A7F /* SFTMTests-Info.plist */, ); path = Resources; @@ -18346,36 +18323,6 @@ path = ../../../sectask; sourceTree = ""; }; - 3D1A573E21669291009C24FD /* TLSAssets */ = { - isa = PBXGroup; - children = ( - 3D1A57412166931B009C24FD /* Info.plist */, - 3D6C25BA216C00D800AB2A71 /* TLSConfig.plist */, - 3D421458216C0A2400D62870 /* Makefile */, - ); - path = TLSAssets; - sourceTree = ""; - }; - 3D7AA28D2187ACD500F1575C /* test */ = { - isa = PBXGroup; - children = ( - 3D7AA28E2187AD0000F1575C /* SecExperimentTests.m */, - ); - path = test; - sourceTree = ""; - }; - 3DA3384121658755008C0CE1 /* SecExperiment */ = { - isa = PBXGroup; - children = ( - 3DA3384421658AA8008C0CE1 /* SecExperimentPriv.h */, - 5A2551F12229F40800512FAE /* SecExperimentInternal.h */, - 3DD852B02177FF72009E705D /* SecExperiment.m */, - 3D7AA28D2187ACD500F1575C /* test */, - 3D1A573E21669291009C24FD /* TLSAssets */, - ); - path = SecExperiment; - sourceTree = ""; - }; 3DD1FE72201AA38A0086D049 /* SecureTransportTests */ = { isa = PBXGroup; children = ( @@ -18521,7 +18468,6 @@ 47B3A90B21027D71001F4281 /* Trieste */ = { isa = PBXGroup; children = ( - E058E53221626582002CA574 /* OctagonTrieste.xcodeproj */, E060D19D2124780F0025B833 /* OctagonTestHarness */, E060D1BD212478120025B833 /* OctagonTestHarnessXPCService */, E060D23E21247C680025B833 /* OctagonTestHarnessXPCServiceProtocol */, @@ -18791,6 +18737,7 @@ EB6952B9223B75C300F02C1C /* secitemd */, DA41FE0E2241ADC000838FB3 /* otpaird */, EBB851EC22F7912400424FD0 /* SecurityUtilitiesTests.xctest */, + 5A442F90233C330F00918373 /* experimentTool */, ); name = Products; sourceTree = ""; @@ -18875,6 +18822,7 @@ 4C922CB2097F1984004CEEBD /* Security */ = { isa = PBXGroup; children = ( + 1BE85ECD235CEB610051E1D8 /* cms-tapi.h */, 5F00F95A230614A200B832E0 /* SecImportExportPriv.h */, D44D08B420AB890E0023C439 /* Security.apinotes */, D4707A1021137525005BCFDA /* CMSDecoder.h */, @@ -19000,6 +18948,35 @@ path = test; sourceTree = ""; }; + 5A442F97233C34C000918373 /* experiment */ = { + isa = PBXGroup; + children = ( + 5A442F98233C34C000918373 /* SecExperimentPriv.h */, + 5A442F9B233C34C000918373 /* SecExperimentInternal.h */, + 5A442F9C233C34C000918373 /* SecExperiment.m */, + 5A442F99233C34C000918373 /* test */, + 5A442F9D233C34C000918373 /* tool */, + ); + path = experiment; + sourceTree = ""; + }; + 5A442F99233C34C000918373 /* test */ = { + isa = PBXGroup; + children = ( + 5A442F9A233C34C000918373 /* SecExperimentTests.m */, + ); + path = test; + sourceTree = ""; + }; + 5A442F9D233C34C000918373 /* tool */ = { + isa = PBXGroup; + children = ( + 5A442F9E233C34C000918373 /* experimentTool-Entitlements.plist */, + 5A442F9F233C34C000918373 /* experimentTool.m */, + ); + path = tool; + sourceTree = ""; + }; 5A47FFAF228F5DAB00F781B8 /* Protocol Buffers */ = { isa = PBXGroup; children = ( @@ -20331,6 +20308,7 @@ DC0BC9D01D8B825900070CB0 /* ssl */ = { isa = PBXGroup; children = ( + 1BE85ED4235CEC250051E1D8 /* sslDeprecated.h */, DC1786FD1D778F5000B50D50 /* SecureTransportPriv.h */, DC1786FB1D778F3C00B50D50 /* sslTypes.h */, DC1785A31D778D0D00B50D50 /* CipherSuite.h */, @@ -21088,6 +21066,7 @@ DCF158C52064895C00B87B6D /* OctagonAPSReceiverTests.h */, DCE7F2081F21726500DDB0F7 /* OctagonAPSReceiverTests.m */, DC9C95951F748D0B000D19E5 /* CKKSServerValidationRecoveryTests.m */, + EB0E1AD723576273002B6037 /* CKKSPBFileStorageTests.m */, ); name = "Tests (Local)"; path = tests; @@ -21178,7 +21157,7 @@ DC59E9AA1D91C9BE001BDDF5 /* Security.framework (Shared) */ = { isa = PBXGroup; children = ( - 3DA3384121658755008C0CE1 /* SecExperiment */, + 5A442F97233C34C000918373 /* experiment */, 5AF593FD1FA0EE2C00A5C1EC /* Protocol */, DCC78E4F1D8085FC00865A7C /* SecFramework.c */, 4723C9B51F152E8E0082882F /* Analytics */, @@ -21836,7 +21815,7 @@ BED01530206F050F0027A2B4 /* README.txt */, DCC78D911D8085F200865A7C /* SecureObjectSync */, 47C51B851EEA657D0032D9E5 /* SecurityUnitTests */, - 0CF0E2DD1F8EE37C00BD18E4 /* Signin Metrics */, + 0CF0E2DD1F8EE37C00BD18E4 /* SigninMetrics */, DC0EF8F0208697C600AB9E95 /* tpctl */, BECFA42F20F91AFE00B11002 /* tppolicy */, 47B3A90B21027D71001F4281 /* Trieste */, @@ -21888,6 +21867,7 @@ DC8834501D8A21AA00CE0ACA /* lib */ = { isa = PBXGroup; children = ( + 1BE85ED1235CEBB30051E1D8 /* secport-tapi.h */, DC88340A1D8A21AA00CE0ACA /* SecAsn1Coder.c */, DC88340C1D8A21AA00CE0ACA /* SecAsn1Templates.c */, DC88340F1D8A21AA00CE0ACA /* certExtensionTemplates.c */, @@ -22050,6 +22030,8 @@ DC1ED8BA1DD51883002BDCFA /* CKKSItemEncrypter.m */, 6CC185971E24E87D009657D8 /* CKKSRateLimiter.h */, 6CC185981E24E87D009657D8 /* CKKSRateLimiter.m */, + EB97364F234E8F4A00518B2B /* CKKSPBFileStorage.h */, + EB973650234E8F4B00518B2B /* CKKSPBFileStorage.m */, 6CA2B9431E9F9F5700C43444 /* RateLimiter.h */, 6CC7F5B31E9F99EE0014AE63 /* RateLimiter.m */, DC9C95B21F79CFD1000D19E5 /* CKKSControl.h */, @@ -23085,6 +23067,7 @@ DCC78D911D8085F200865A7C /* SecureObjectSync */ = { isa = PBXGroup; children = ( + EB0E1B902358FA4B002B6037 /* generated_source */, CD1D64461DD386C9006D4139 /* AccountTrust */, DCC78D2D1D8085F200865A7C /* Account */, DCC78D4E1D8085F200865A7C /* Circle */, @@ -23111,6 +23094,7 @@ 48FE668F20E6E69B00FAEF17 /* SOSAuthKitHelpers.m */, 480C03D621459CD70034570E /* SOSTrustedDeviceAttributes.h */, 480C03D321459CD60034570E /* SOSTrustedDeviceAttributes.m */, + EB0E1AC72352A81E002B6037 /* SOSAccountConfiguration.proto */, ); name = SecureObjectSync; path = keychain/SecureObjectSync; @@ -24111,6 +24095,8 @@ D4BEECE61E93093A00F76D1A /* trustd.c */, D4B68C64211A8186009FED69 /* trustd_spi.h */, D4B68C65211A8186009FED69 /* trustd_spi.c */, + D47DCCB423427C7D00B80E37 /* md.m */, + D47DCCB723427C8D00B80E37 /* md.h */, D43DBED71E99D17100C04AEA /* nameconstraints.c */, D43DBED81E99D17100C04AEA /* nameconstraints.h */, D43DBED91E99D17100C04AEA /* OTATrustUtilities.m */, @@ -24934,24 +24920,6 @@ name = "dispatch Support"; sourceTree = ""; }; - E058E53321626583002CA574 /* Products */ = { - isa = PBXGroup; - children = ( - E058E54B21626583002CA574 /* CloudDeviceTest.framework */, - E058E54D21626583002CA574 /* CoreDeviceAutomation.framework */, - E058E54F21626583002CA574 /* CoreDeviceAutomationFrameworkFacade.framework */, - E058E55121626583002CA574 /* OctagonTestHarnessXPCServiceProtocol.framework */, - E058E55321626583002CA574 /* OctagonTrieste.framework */, - E058E55521626583002CA574 /* OctagonTriesteTests.xctest */, - E058E55721626583002CA574 /* OpenSSLThreadLock.framework */, - E058E55B21626583002CA574 /* SSEClient.framework */, - E058E55D21626583002CA574 /* SwiftHTTP.framework */, - E058E55F21626583002CA574 /* SwiftLog.framework */, - E058E56121626583002CA574 /* os_activity.framework */, - ); - name = Products; - sourceTree = ""; - }; E060D19D2124780F0025B833 /* OctagonTestHarness */ = { isa = PBXGroup; children = ( @@ -25052,6 +25020,9 @@ isa = PBXGroup; children = ( 4C922CB2097F1984004CEEBD /* Security */, + 1B2BD391235E050D009A8624 /* SecEC-tapi.h */, + 1B2BD393235E050E009A8624 /* SecPolicy-tapi.h */, + 1B2BD394235E050E009A8624 /* Security-tapi.h */, ); name = Headers; sourceTree = ""; @@ -25156,6 +25127,8 @@ E7FCBE401314471B000DE34E /* Frameworks */ = { isa = PBXGroup; children = ( + BEC6A9142331992800080069 /* Network.framework */, + D47AB2CA2356AD72005A3801 /* Network.framework */, 0C6C2B6C2258295D00C53C96 /* UIKitCore.framework */, 0C6C2B682258211800C53C96 /* AppleAccount.framework */, DC4A76A92212698B006F2D8F /* CloudServices.framework */, @@ -25336,6 +25309,15 @@ name = secedumodetest; sourceTree = ""; }; + EB0E1B902358FA4B002B6037 /* generated_source */ = { + isa = PBXGroup; + children = ( + EB0E1B922358FADE002B6037 /* SOSAccountConfiguration.h */, + EB0E1B932358FADE002B6037 /* SOSAccountConfiguration.m */, + ); + path = generated_source; + sourceTree = ""; + }; EB1055641E14DB370003C309 /* secfuzzer */ = { isa = PBXGroup; children = ( @@ -25414,6 +25396,7 @@ EB49B2AF202D8780003F34A0 /* secdmockaks */ = { isa = PBXGroup; children = ( + EB627A74233E33A300F32437 /* generated_source */, 72D1E5F3202FE43C003A38C5 /* secdmock_db_version_10_5.h */, EBE700FE204676E700E00A87 /* secdmock_db_version_11_1.h */, EB49B2B0202D8780003F34A0 /* mockaksKeychain.m */, @@ -25423,6 +25406,8 @@ EB6667BE204CD65E000B404F /* testPlistDER.m */, EB49B303202FB8DE003F34A0 /* mockaks.h */, EB49B2E4202DFE7F003F34A0 /* mockaks.m */, + EBDCBFFE233DD31700806566 /* MockAKSRefKey.proto */, + EB627A6F233E323600F32437 /* MockAKSOptionalParameters.proto */, EB49B2B2202D8780003F34A0 /* Info.plist */, DC311E782124B8EF002F5EAE /* aks_real_witness.h */, DC311E792124B8EF002F5EAE /* aks_real_witness.c */, @@ -25431,6 +25416,17 @@ path = tests/secdmockaks; sourceTree = ""; }; + EB627A74233E33A300F32437 /* generated_source */ = { + isa = PBXGroup; + children = ( + EB627A78233E342B00F32437 /* MockAKSOptionalParameters.h */, + EB627A77233E342B00F32437 /* MockAKSOptionalParameters.m */, + EB627A76233E342900F32437 /* MockAKSRefKey.h */, + EB627A75233E342800F32437 /* MockAKSRefKey.m */, + ); + path = generated_source; + sourceTree = ""; + }; EB74CC182207E48000F1BBAD /* KeychainSettings */ = { isa = PBXGroup; children = ( @@ -25676,10 +25672,12 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 1B2BD395235E050E009A8624 /* SecEC-tapi.h in Headers */, 4C32C1030A4976BF002891BD /* certextensions.h in Headers */, 4C32C1240A4976BF002891BD /* SecBase.h in Headers */, 4C32C1250A4976BF002891BD /* SecCertificate.h in Headers */, 4C32C1260A4976BF002891BD /* SecTrust.h in Headers */, + EB973651234E8F4B00518B2B /* CKKSPBFileStorage.h in Headers */, 4CF0484C0A5D988F00268236 /* SecItem.h in Headers */, 6CE3654F1FA100F10012F6AB /* SFAnalyticsDefines.h in Headers */, D4707A292113EF68005BCFDA /* SecCmsMessage.h in Headers */, @@ -25705,9 +25703,9 @@ D47079F321128C74005BCFDA /* SecCMS.h in Headers */, 4C12828D0BB4957D00985BB0 /* SecTrustSettingsPriv.h in Headers */, DCD45355209A5B260086CBFC /* si-cms-signing-identity-p12.h in Headers */, + 1BE85ED5235CEC250051E1D8 /* sslDeprecated.h in Headers */, CDDE9BD11729ABFA0013B0E8 /* SecPasswordGenerate.h in Headers */, 4C7072860AC9EA4F007CC205 /* SecKey.h in Headers */, - 5A2551F32229F41300512FAE /* SecExperimentInternal.h in Headers */, D4B3B1CC2115150D00A43409 /* SecCmsDigestedData.h in Headers */, 476541651F339F6300413F65 /* SecdWatchdog.h in Headers */, D47079FB211355C9005BCFDA /* CMSEncoder.h in Headers */, @@ -25729,7 +25727,6 @@ 4C4296320BB0A68200491999 /* SecTrustSettings.h in Headers */, 4CBA0E880BB33C0000E72B55 /* SecPolicy.h in Headers */, D4B3B1D52115195900A43409 /* SecCmsRecipientInfo.h in Headers */, - 3D909E372195042C00205F8C /* SecExperimentPriv.h in Headers */, 4C6416D50BB34F00001C83FD /* SecPolicyPriv.h in Headers */, 78F92F11195128D70023B54B /* SecECKeyPriv.h in Headers */, 4CD3BA621106FF4D00BE8B75 /* SecECKey.h in Headers */, @@ -25741,10 +25738,12 @@ DC3C7AB81D838C6F00F6A832 /* oidsalg.h in Headers */, B61F67561F1FCFCA00E2FDBB /* SecPaddingConfigurationsPriv.h in Headers */, 4C2F81D50BF121D2003C4F77 /* SecRandom.h in Headers */, + 0CD9E34323592DD7002995DE /* OctagonSignPosts.h in Headers */, ACBAF6EE1E941AE00007BA2F /* transform_regressions.h in Headers */, 7940D4130C3ACF9000FDB5D8 /* SecDH.h in Headers */, 478014791FBF5D2000C4043D /* SecKeyProxy.h in Headers */, 790850F70CA88AE10083CC4D /* securityd_client.h in Headers */, + 1BE85ECF235CEB620051E1D8 /* cms-tapi.h in Headers */, 795CA9CE0D38435E00BAE6A2 /* p12pbegen.h in Headers */, D4B3B1CF211516A000A43409 /* SecCmsEncryptedData.h in Headers */, 79EF5B730D3D6AFE009F5270 /* p12import.h in Headers */, @@ -25766,6 +25765,7 @@ DC2C5F4B1F0D935200FEBDA7 /* CKKSControlProtocol.h in Headers */, 107226D30D91DB32003CF14F /* SecTask.h in Headers */, 4C7CE5700DC7DC6600AE53FC /* SecEntitlements.h in Headers */, + 1BE85ED2235CEBB40051E1D8 /* secport-tapi.h in Headers */, 6CE365551FA101730012F6AB /* SFAnalyticsSQLiteStore.h in Headers */, 791766DE0DD0162C00F3B974 /* SecCertificateRequest.h in Headers */, 4C7416040F1D71A2008E0E4D /* SecSCEP.h in Headers */, @@ -25796,6 +25796,7 @@ D4707A262113EBC1005BCFDA /* SecCmsDecoder.h in Headers */, DC3C7ABA1D838C9F00F6A832 /* sslTypes.h in Headers */, 6CE3654B1FA100D00012F6AB /* SFAnalytics.h in Headers */, + 5A442FA6233C34FE00918373 /* SecExperimentInternal.h in Headers */, 4AF7000515AFB73800B9D400 /* SecOTRSession.h in Headers */, D4707A2C2114C1E5005BCFDA /* SecCmsContentInfo.h in Headers */, D487B9821DFA28DB000410A1 /* SecInternalReleasePriv.h in Headers */, @@ -25806,9 +25807,11 @@ D46CD4C72267949C00E2C4D7 /* certExtensionTemplates.h in Headers */, D46CD4C82267949C00E2C4D7 /* nameTemplates.h in Headers */, D46CD4C92267949C00E2C4D7 /* X509Templates.h in Headers */, + 5A442FA5233C34FE00918373 /* SecExperimentPriv.h in Headers */, 8E02FA6B1107BE460043545E /* pbkdf2.h in Headers */, AA7C71B62185429800EB314F /* SecProtocolTypesPriv.h in Headers */, 8ED6F6CA110904E300D2B368 /* SecPBKDF.h in Headers */, + 1B2BD396235E050E009A8624 /* SecPolicy-tapi.h in Headers */, 5F00F95B230614AC00B832E0 /* SecImportExportPriv.h in Headers */, 22A23B3A1E3AAC9800C41830 /* CodeSigning.h in Headers */, 5A6D1B9520810EAD0057CAC8 /* SecProtocolMetadata.h in Headers */, @@ -25821,6 +25824,7 @@ DC9C95BE1F79DC5F000D19E5 /* CKKSControl.h in Headers */, 0CBFEACC200FCD33009A60E9 /* SFSignInAnalytics.h in Headers */, DC3C7AB61D838C2D00F6A832 /* SecAsn1Types.h in Headers */, + 1B2BD397235E050E009A8624 /* Security-tapi.h in Headers */, D43D8B2D20AB8A54005BEEC4 /* Security.apinotes in Headers */, DC3C73551D837B2C00F6A832 /* SOSPeerInfoPriv.h in Headers */, D46246A31F9AE59E00D63882 /* oids.h in Headers */, @@ -26368,6 +26372,7 @@ DC1785241D7789AF00B50D50 /* AuthorizationTags.h in Headers */, EBF252252155E911000204D6 /* OTJoiningConfiguration.h in Headers */, EB5E3BCD2003C67B00F1631B /* SecSignpost.h in Headers */, + 0CD9E34423592DD7002995DE /* OctagonSignPosts.h in Headers */, DC1787601D7790E500B50D50 /* AuthorizationTagsPriv.h in Headers */, D47079FA211355C5005BCFDA /* CMSEncoder.h in Headers */, AA5B121C2164671000A6AB81 /* SecProtocolConfiguration.h in Headers */, @@ -26382,7 +26387,6 @@ DC17854F1D778ACD00B50D50 /* SecACL.h in Headers */, DC17854E1D778ACD00B50D50 /* SecAccess.h in Headers */, DC1785921D778BE400B50D50 /* SecAccessControl.h in Headers */, - 5A2551F52229F41500512FAE /* SecExperimentInternal.h in Headers */, DC1787751D77916000B50D50 /* SecAccessControlPriv.h in Headers */, DC1787351D77903700B50D50 /* SecAccessPriv.h in Headers */, DC1785181D77895A00B50D50 /* SecAsn1Coder.h in Headers */, @@ -26396,6 +26400,7 @@ 5F00F95C230614AD00B832E0 /* SecImportExportPriv.h in Headers */, DC1787741D77915500B50D50 /* SecBreadcrumb.h in Headers */, 6CB420AB2051FDE000FF2D44 /* LocalKeychainAnalytics.h in Headers */, + 1BE85ED0235CEB620051E1D8 /* cms-tapi.h in Headers */, DC1787761D77916600B50D50 /* SecCFAllocator.h in Headers */, DC0C343A21FA7DEB00417D04 /* SecEscrowRequest.h in Headers */, DC17859F1D778C8D00B50D50 /* SecCertificate.h in Headers */, @@ -26412,6 +26417,7 @@ DC1787521D7790A500B50D50 /* SecCodeSigner.h in Headers */, DC1785301D778A0100B50D50 /* SecCustomTransform.h in Headers */, 0CBFEACD200FCD33009A60E9 /* SFSignInAnalytics.h in Headers */, + 5A442FA8233C34FF00918373 /* SecExperimentInternal.h in Headers */, DC1787771D77916A00B50D50 /* SecDH.h in Headers */, DC1785311D778A0100B50D50 /* SecDecodeTransform.h in Headers */, 6CE365561FA101740012F6AB /* SFAnalyticsSQLiteStore.h in Headers */, @@ -26446,10 +26452,12 @@ DC1785541D778ACD00B50D50 /* SecKeychainSearch.h in Headers */, DC17873C1D77903700B50D50 /* SecKeychainSearchPriv.h in Headers */, DC1787261D778FDE00B50D50 /* SecManifest.h in Headers */, + 5A442FA7233C34FF00918373 /* SecExperimentPriv.h in Headers */, DCA9D84221FFE62A00B27421 /* EscrowRequestXPCProtocol.h in Headers */, DC1786F91D778F2500B50D50 /* SecNullTransform.h in Headers */, DC17873D1D77903700B50D50 /* SecPassword.h in Headers */, DC1787791D77917700B50D50 /* SecPasswordGenerate.h in Headers */, + 1BE85ED6235CEC250051E1D8 /* sslDeprecated.h in Headers */, F6EEF77521675EF000FB7F79 /* AuthorizationTrampolinePriv.h in Headers */, DC1785941D778BF400B50D50 /* SecPolicy.h in Headers */, D43718C921168D7D00EA350A /* SecSMIME.h in Headers */, @@ -26505,7 +26513,6 @@ D4707A272113EBC1005BCFDA /* SecCmsDecoder.h in Headers */, D4707A212113AC34005BCFDA /* SecCmsBase.h in Headers */, 6CBF65401FA1480C00A68667 /* SFAnalyticsActivityTracker.h in Headers */, - 3D909E382195042C00205F8C /* SecExperimentPriv.h in Headers */, DC17856E1D778B4A00B50D50 /* cssmapi.h in Headers */, DC1785991D778C5300B50D50 /* cssmapple.h in Headers */, DC1787431D77906C00B50D50 /* cssmapplePriv.h in Headers */, @@ -26529,6 +26536,7 @@ DC1785791D778B4A00B50D50 /* eisl.h in Headers */, DC17857A1D778B4A00B50D50 /* emmspi.h in Headers */, D4707A2A2113EF68005BCFDA /* SecCmsMessage.h in Headers */, + 1BE85ED3235CEBB40051E1D8 /* secport-tapi.h in Headers */, 6C8CE6C21FA248DB0032ADF0 /* SFAnalyticsActivityTracker+Internal.h in Headers */, D4B3B1DC21152AD300A43409 /* SecCmsSignerInfo.h in Headers */, DC17857B1D778B4A00B50D50 /* emmtype.h in Headers */, @@ -28240,12 +28248,12 @@ 4C32C0AC0A4975F6002891BD /* Sources */, 4C32C0AD0A4975F6002891BD /* Frameworks */, F3384FD12165A025004A2171 /* Install Ariadne Signposts Plist */, + 0C97867A235A766B0040A867 /* Copy System logging profile */, ); buildRules = ( E7B006FF170B56E700B27966 /* PBXBuildRule */, ); dependencies = ( - DCE0778421ADEDDA002662FD /* PBXTargetDependency */, DCDA5E5A2124BA2F009B11B2 /* PBXTargetDependency */, DCD22D7D1D8CCA18001C9B81 /* PBXTargetDependency */, D42C83A5211636A3008D3D83 /* PBXTargetDependency */, @@ -28407,6 +28415,22 @@ productReference = 5346480117331E1200FE9172 /* KeychainSyncAccountNotification.bundle */; productType = "com.apple.product-type.bundle"; }; + 5A442F81233C330F00918373 /* experimentTool */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5A442F8D233C330F00918373 /* Build configuration list for PBXNativeTarget "experimentTool" */; + buildPhases = ( + 5A442F82233C330F00918373 /* Sources */, + 5A442F89233C330F00918373 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = experimentTool; + productName = ckksctl; + productReference = 5A442F90233C330F00918373 /* experimentTool */; + productType = "com.apple.product-type.tool"; + }; 5E10992419A5E55800A60E2B /* ISACLProtectedItems */ = { isa = PBXNativeTarget; buildConfigurationList = 5E10994D19A5E55800A60E2B /* Build configuration list for PBXNativeTarget "ISACLProtectedItems" */; @@ -28739,7 +28763,6 @@ buildRules = ( ); dependencies = ( - EBBC11B32200D3BB00F95738 /* PBXTargetDependency */, BED01526206EEC710027A2B4 /* PBXTargetDependency */, ); name = TrustedPeersHelper; @@ -28816,7 +28839,6 @@ buildRules = ( ); dependencies = ( - DCE0775C21ADD6A0002662FD /* PBXTargetDependency */, D437C33121EBF8A000DD1E06 /* PBXTargetDependency */, ); name = TrustedPeers; @@ -29502,7 +29524,6 @@ buildRules = ( ); dependencies = ( - DC7479A022272361001E0E8C /* PBXTargetDependency */, ); name = tpctl; productName = tpctl; @@ -29658,7 +29679,6 @@ buildRules = ( ); dependencies = ( - DCE0777E21ADEADA002662FD /* PBXTargetDependency */, ); name = libsecurityd_ios; productName = libsecurity; @@ -30786,7 +30806,6 @@ buildRules = ( ); dependencies = ( - 0C604F0221B8E5090036C175 /* PBXTargetDependency */, DC65E7221D8CB27900152EF0 /* PBXTargetDependency */, ); name = KeychainCircle; @@ -31563,10 +31582,6 @@ productRefGroup = 4C35DC36094F9120002917C4 /* Products */; projectDirPath = ""; projectReferences = ( - { - ProductGroup = E058E53321626583002CA574 /* Products */; - ProjectRef = E058E53221626582002CA574 /* OctagonTrieste.xcodeproj */; - }, { ProductGroup = DC5AC0AE1D83533400CF422C /* Products */; ProjectRef = DC5AC0AD1D83533400CF422C /* securityd_service.xcodeproj */; @@ -31607,6 +31622,7 @@ D4F47B3822270B6E003483E9 /* Security_all_watchos */, D4F47B3C22270B89003483E9 /* Security_all_tvos */, D4F47B4022270B97003483E9 /* Security_all_bridge */, + DCF216D621ADD5B10029CCC1 /* protobuf_source_generation */, DC8E04991D7F6D9C006D80EB /* ====== Frameworks ======== */, 4C32C0AE0A4975F6002891BD /* Security_ios */, DC1789031D77980500B50D50 /* Security_osx */, @@ -31629,6 +31645,9 @@ BEAA002A202A832500E51F45 /* TrustedPeersHelper */, DA41FE0D2241ADC000838FB3 /* otpaird */, DC8E04B11D7F6EC9006D80EB /* ======= Libraries ========= */, + DCDA5E4F2124B9C5009B11B2 /* aks_support */, + DC36895D21235F42003A3735 /* aks_mock */, + DC311E6E2124B8A8002F5EAE /* aks_real_witness */, DCC78EA81D8088E200865A7C /* security */, DC52E7731D80BC8000B0A59C /* libsecurityd_ios */, 4718AE2E205B39C40068EC3F /* libsecurityd_bridge */, @@ -31655,9 +31674,6 @@ 225394AC1E3080A600D3CD9B /* security_codesigning_ios */, DC8834011D8A218F00CE0ACA /* ASN1 */, D44D1F652115893000E76E1A /* CMS */, - DCDA5E4F2124B9C5009B11B2 /* aks_support */, - DC36895D21235F42003A3735 /* aks_mock */, - DC311E6E2124B8A8002F5EAE /* aks_real_witness */, DCF782BA1D88B44300E694BB /* ==== macOS Libraries ====== */, DCF7830A1D88B4DE00E694BB /* security_apple_csp */, DCF785021D88B95500E694BB /* security_apple_cspdl */, @@ -31778,7 +31794,6 @@ DCD067561D8CDCF3007602F1 /* codesigning_DTrace */, DCD0675B1D8CDD6D007602F1 /* codesigning_SystemPolicy */, BECFA42D20F91AFE00B11002 /* tppolicy */, - DCF216D621ADD5B10029CCC1 /* protobuf_source_generation */, DC8E04AD1D7F6E76006D80EB /* ======= misc ========= */, DC7FC44721EE914C003C39B8 /* FeatureFlagsPlist */, E7B01BBD166594AB000485F1 /* SyncDevTest2 */, @@ -31809,6 +31824,7 @@ E060D1B6212478110025B833 /* OctagonTestHarnessXPCService */, EB7E90F12193F90700B1FA21 /* Build C2 Metrics */, 3D58392D21890FFB000ACA44 /* SecExperimentTests */, + 5A442F81233C330F00918373 /* experimentTool */, ); }; /* End PBXProject section */ @@ -31842,83 +31858,6 @@ remoteRef = DC5AC0BA1D83533400CF422C /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - E058E54B21626583002CA574 /* CloudDeviceTest.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = CloudDeviceTest.framework; - remoteRef = E058E54A21626583002CA574 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - E058E54D21626583002CA574 /* CoreDeviceAutomation.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = CoreDeviceAutomation.framework; - remoteRef = E058E54C21626583002CA574 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - E058E54F21626583002CA574 /* CoreDeviceAutomationFrameworkFacade.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = CoreDeviceAutomationFrameworkFacade.framework; - remoteRef = E058E54E21626583002CA574 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - E058E55121626583002CA574 /* OctagonTestHarnessXPCServiceProtocol.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = OctagonTestHarnessXPCServiceProtocol.framework; - remoteRef = E058E55021626583002CA574 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - E058E55321626583002CA574 /* OctagonTrieste.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = OctagonTrieste.framework; - remoteRef = E058E55221626583002CA574 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - E058E55521626583002CA574 /* OctagonTriesteTests.xctest */ = { - isa = PBXReferenceProxy; - fileType = file; - path = OctagonTriesteTests.xctest; - remoteRef = E058E55421626583002CA574 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - E058E55721626583002CA574 /* OpenSSLThreadLock.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = OpenSSLThreadLock.framework; - remoteRef = E058E55621626583002CA574 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - E058E55B21626583002CA574 /* SSEClient.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = SSEClient.framework; - remoteRef = E058E55A21626583002CA574 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - E058E55D21626583002CA574 /* SwiftHTTP.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = SwiftHTTP.framework; - remoteRef = E058E55C21626583002CA574 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - E058E55F21626583002CA574 /* SwiftLog.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = SwiftLog.framework; - remoteRef = E058E55E21626583002CA574 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - E058E56121626583002CA574 /* os_activity.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = os_activity.framework; - remoteRef = E058E56021626583002CA574 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; /* End PBXReferenceProxy section */ /* Begin PBXResourcesBuildPhase section */ @@ -32808,7 +32747,7 @@ ); runOnlyForDeploymentPostprocessing = 1; shellPath = /bin/sh; - shellScript = "[ \"$(whoami)\" == \"root\" ] || exit 0\n OTTESTS_DIR=${SRCROOT}/keychain/ot/tests\n \n python ${OTTESTS_DIR}/gen_test_plist.py ${OTTESTS_DIR} ${DSTROOT}/AppleInternal/CoreOS/BATS/unit_tests/Octagon.plist\n chown -f root:wheel ${DSTROOT}/AppleInternal/CoreOS/BATS/unit_tests/*.plist\n"; + shellScript = "OTTESTS_DIR=${SRCROOT}/keychain/ot/tests\npython ${OTTESTS_DIR}/gen_test_plist.py ${OTTESTS_DIR} ${DSTROOT}/AppleInternal/CoreOS/BATS/unit_tests/Octagon.plist\n\n[ \"$(whoami)\" == \"root\" ] || exit 0\nchown -f root:wheel ${DSTROOT}/AppleInternal/CoreOS/BATS/unit_tests/*.plist\n"; }; E7E0C6D11C90E87D00E69A21 /* chmod BATS Tests */ = { isa = PBXShellScriptBuildPhase; @@ -32878,19 +32817,19 @@ shellPath = /bin/sh; shellScript = "# Don't use SYSTEM_FRAMEWORK_SEARCH_PATHS, its implicit with internal SDK, if added you warnings from system headers as they where problems in our headers\ngrep -e '^\\s*SYSTEM_FRAMEWORK_SEARCH_PATHS =' ${SRCROOT}/Security.xcodeproj/project.pbxproj >/dev/null 2>&1\ntest $? != 0\n"; }; - EBC15E801BE29A8C001C0C5B /* Chown BATS plist */ = { + EBC15E801BE29A8C001C0C5B /* Generate and Chown BATS plist */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 8; files = ( ); inputPaths = ( ); - name = "Chown BATS plist"; + name = "Generate and Chown BATS plist"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 1; shellPath = /bin/sh; - shellScript = "[ \"$(whoami)\" == \"root\" ] || exit 0\nchown root:wheel ${DSTROOT}/AppleInternal/CoreOS/BATS/unit_tests/*.plist\n"; + shellScript = "${SRCROOT}/RegressionTests/PreprocessPlist.sh ${SRCROOT}/RegressionTests/Security.plist ${DSTROOT}/AppleInternal/CoreOS/BATS/unit_tests/Security.plist\n\n[ \"$(whoami)\" == \"root\" ] || exit 0\nchown root:wheel ${DSTROOT}/AppleInternal/CoreOS/BATS/unit_tests/*.plist\n"; showEnvVarsInLog = 0; }; EBC73F4B209A0C3400AE3350 /* Install OCMock framework */ = { @@ -33058,8 +32997,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 3D680BE72241C16E00C04821 /* SecExperiment.m in Sources */, - 3D58394F21891061000ACA44 /* SecExperimentTests.m in Sources */, + 5A442FAD233C351C00918373 /* SecExperimentTests.m in Sources */, + 5A442FAC233C351500918373 /* SecExperiment.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -33154,7 +33093,6 @@ buildActionMask = 2147483647; files = ( 4718AE35205B39C40068EC3F /* CKKSSQLDatabaseObject.m in Sources */, - 4718AE36205B39C40068EC3F /* CKKSRateLimiter.m in Sources */, 4718AE37205B39C40068EC3F /* CKKSAccountStateTracker.m in Sources */, 4718AE38205B39C40068EC3F /* SecCDKeychain.m in Sources */, 4718AE3A205B39C40068EC3F /* CKKSGroupOperation.m in Sources */, @@ -33174,6 +33112,7 @@ 4718AE4B205B39C40068EC3F /* CKKSHealKeyHierarchyOperation.m in Sources */, 4718AE4C205B39C40068EC3F /* CKKSCurrentItemPointer.m in Sources */, 6C4AEF97218A12810012C5DA /* SecDbKeychainMetadataKeyStore.m in Sources */, + EB0E1ACD2353A704002B6037 /* CKKSRateLimiter.m in Sources */, 4718AE4D205B39C40068EC3F /* CKKSLocalSynchronizeOperation.m in Sources */, 4718AE4E205B39C40068EC3F /* OTManager.m in Sources */, 4718AE50205B39C40068EC3F /* CKKSCurrentKeyPointer.m in Sources */, @@ -33247,6 +33186,7 @@ 4718AE92205B39C40068EC3F /* CKKSSIV.m in Sources */, 4718AE96205B39C40068EC3F /* CKKSZoneChangeFetcher.m in Sources */, 4718AE97205B39C40068EC3F /* CKKSCondition.m in Sources */, + EB0E1ACE2353A704002B6037 /* CKKSPBFileStorage.m in Sources */, 4718AE98205B39C40068EC3F /* CKKSZone.m in Sources */, 4718AE99205B39C40068EC3F /* SFKeychainServer.m in Sources */, 4718AE9B205B39C40068EC3F /* swcagent_client.c in Sources */, @@ -33345,11 +33285,12 @@ 5A06118E229ED5EB006AF14A /* NSDate+SFAnalytics.m in Sources */, 0C8884012154C4E80053224D /* OTJoiningConfiguration.m in Sources */, 0CBD55B31FE883F200A8CE21 /* SFBehavior.m in Sources */, - 3DD852B12177FF72009E705D /* SecExperiment.m in Sources */, 6C814A4D2050B4B600CB391B /* LocalKeychainAnalytics.m in Sources */, 220179E91E3BF03200EFB6F3 /* dummy.cpp in Sources */, + 5A442FA9233C351000918373 /* SecExperiment.m in Sources */, DC926F091F33FA8D0012A315 /* CKKSControlProtocol.m in Sources */, 4723C9CC1F152ED30082882F /* SFSQLiteStatement.m in Sources */, + 0CD9E34523592EA6002995DE /* OctagonSignPosts.m in Sources */, DCC5860020BF8A7E005C7269 /* SecFramework.c in Sources */, DCA85B931E8D97E400BA7241 /* client.c in Sources */, DCA9D84621FFE7CF00B27421 /* EscrowRequestXPCProtocol.m in Sources */, @@ -33374,6 +33315,7 @@ 6CE365531FA101080012F6AB /* SFAnalyticsSampler.m in Sources */, AA9FD59C2152AFD70045A07A /* SecProtocolConfiguration.m in Sources */, 6C73F48A2006B839003D5D63 /* SOSAnalytics.m in Sources */, + EB973652234E8F4B00518B2B /* CKKSPBFileStorage.m in Sources */, 5A04BAFA22976A15001848A0 /* OTClique.m in Sources */, 6CE365571FA1017D0012F6AB /* SFAnalyticsSQLiteStore.m in Sources */, EB9B285721C77C8D00173DC2 /* OTDefines.m in Sources */, @@ -33485,6 +33427,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 5A442F82233C330F00918373 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5A442FAE233C352200918373 /* experimentTool.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 5E10992119A5E55800A60E2B /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -34080,6 +34030,7 @@ D43DBF081E99D1CA00C04AEA /* SecPolicyServer.c in Sources */, D43DBF091E99D1CA00C04AEA /* SecRevocationDb.c in Sources */, D43DBF0A1E99D1CA00C04AEA /* SecRevocationServer.c in Sources */, + D47DCCB523427C7D00B80E37 /* md.m in Sources */, D43DBF0B1E99D1CA00C04AEA /* SecTrustLoggingServer.m in Sources */, D4961BC42079424200F16DA7 /* TrustURLSessionDelegate.m in Sources */, D43DBF0C1E99D1CA00C04AEA /* SecTrustServer.c in Sources */, @@ -34551,6 +34502,7 @@ DC747999222722B2001E0E8C /* CKKSConstants.m in Sources */, DC7479982227229D001E0E8C /* CKKSTLKShare.m in Sources */, DC0EF8F2208697C600AB9E95 /* main.swift in Sources */, + EB7ECF9623467FB400CE2D3C /* Cuttlefish.pb.swift in Sources */, DCD48BFE20BF3D83009A3224 /* tpctl-objc.m in Sources */, DCFFE9692277DEAF0092069C /* TrustedPeersHelperProtocol.m in Sources */, ); @@ -34582,6 +34534,7 @@ 6CAA8CFE1F83E800007B6E03 /* SFSQLite.m in Sources */, DC9C95C01F79DC89000D19E5 /* CKKSControl.m in Sources */, 5AF594001FA0EE5300A5C1EC /* SecProtocol.c in Sources */, + 5A442FAA233C351100918373 /* SecExperiment.m in Sources */, 0C8884042154C4EA0053224D /* OTJoiningConfiguration.m in Sources */, 0C0E60E020D033E400E654F2 /* OTControl.m in Sources */, 6CB420A52051FDD500FF2D44 /* LocalKeychainAnalytics.m in Sources */, @@ -34594,8 +34547,8 @@ DC1789A21D779DF400B50D50 /* SecBreadcrumb.c in Sources */, 78ADC62C1FA0FACE001EB8B6 /* SecProtocolTypes.m in Sources */, 0CE079F41FEA15B20040A3F1 /* SFBehavior.m in Sources */, - 3DE8F6C121829EFF006041DA /* SecExperiment.m in Sources */, 6CBF65411FA1481100A68667 /* SFAnalyticsActivityTracker.m in Sources */, + 0CD9E34623592EA7002995DE /* OctagonSignPosts.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -34640,6 +34593,7 @@ EBB0315822223AAF007241CB /* CKKSLaunchSequenceTests.m in Sources */, DC752F1F21C1B98000216089 /* SFObjCType.m in Sources */, DC9C98C722E264F30021E29F /* CKKSFetchTests.m in Sources */, + EB0E1ADA2357627F002B6037 /* CKKSPBFileStorageTests.m in Sources */, DC9C75161E4BCE1800F1CA0D /* CKKSOperationTests.m in Sources */, DC8D238D2064649400E163C8 /* CKKSAPSHandlingTests.m in Sources */, EBC1024422EBF93E0083D356 /* CKKSTests+LockStateTracker.m in Sources */, @@ -34662,8 +34616,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + EB627A7F233E3C1600F32437 /* MockAKSRefKey.m in Sources */, DC5999752232FA3700A9F1A3 /* SecKeybagSupport.c in Sources */, DC36896221235F99003A3735 /* mockaks.m in Sources */, + EB627A7E233E3C1300F32437 /* MockAKSOptionalParameters.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -34821,6 +34777,7 @@ DC52E7D61D80BD2800B0A59C /* SecuritydXPC.c in Sources */, 0C4F4DE221153E9E007F7E20 /* OTEpochOperation.m in Sources */, 47922D561FAA7E0D0008F7E0 /* SecDbKeychainSerializedItemV7.m in Sources */, + EB0E1ACB2353A702002B6037 /* CKKSPBFileStorage.m in Sources */, DC7A17EF1E36ABC200EF14CE /* CKKSProcessReceivedKeysOperation.m in Sources */, DC7341F51F8447AB00AB9BDF /* CKKSTLKShareRecord.m in Sources */, 0C5960811FB369C50095BA29 /* CKKSHealTLKSharesOperation.m in Sources */, @@ -34873,6 +34830,7 @@ DC2670F51F3E711400816EED /* SOSAccountCloudParameters.m in Sources */, DCDCC7E51D9B5526006487E8 /* SOSAccountSync.m in Sources */, DC2670F81F3E723B00816EED /* SOSAccountDer.m in Sources */, + EB0E1B942358FAF3002B6037 /* SOSAccountConfiguration.m in Sources */, DC59245520E470070073D284 /* SOSRingRecovery.m in Sources */, DC52E8F71D80C34000B0A59C /* SOSAccountCredentials.m in Sources */, DC59245420E46FDE0073D284 /* SOSRingBasic.m in Sources */, @@ -35777,7 +35735,7 @@ DCC78EC01D808A1C00865A7C /* SecTrust.c in Sources */, DCC78EBE1D808A0E00865A7C /* SecTrustStore.c in Sources */, DCC78EBD1D808A0400865A7C /* SecuritydXPC.c in Sources */, - 3D680BE42241BC0000C04821 /* SecExperiment.m in Sources */, + 5A442FAB233C351300918373 /* SecExperiment.m in Sources */, DCC78EBB1D8089C200865A7C /* p12import.c in Sources */, D425EC1D1DD3C3CF00DE5DEC /* SecInternalRelease.c in Sources */, DCC78EBA1D8089BD00865A7C /* p12pbegen.c in Sources */, @@ -36153,6 +36111,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + EBDCC002233DD45700806566 /* MockAKSRefKey.proto in Sources */, 0CE15E39222DF67800B7EAA4 /* OTRecovery.proto in Sources */, DCE0775621ADD665002662FD /* OTPrivateKey.proto in Sources */, DCE0775321ADD65E002662FD /* OTAuthenticatedCiphertext.proto in Sources */, @@ -36182,9 +36141,11 @@ DCE0774321ADD635002662FD /* TPPBPeerDynamicInfo.proto in Sources */, DCE0775721ADD669002662FD /* SecDbKeychainSerializedItemV7.proto in Sources */, DCE0775821ADD66B002662FD /* SecDbKeychainSerializedAKSWrappedKey.proto in Sources */, + EB627A73233E339200F32437 /* MockAKSOptionalParameters.proto in Sources */, DC90A4C721F279D4001300EB /* SecEscrowPendingRecord.proto in Sources */, DCE0775921ADD66E002662FD /* SecDbKeychainSerializedMetadata.proto in Sources */, DCE0775A21ADD671002662FD /* SecDbKeychainSerializedSecretData.proto in Sources */, + EB0E1B912358FAC6002B6037 /* SOSAccountConfiguration.proto in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -36552,7 +36513,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - EB9B285921C77E7400173DC2 /* OTDefines.m in Sources */, 6C32BB9920EAE6B00042DF59 /* LocalKeychainAnalytics.m in Sources */, EB1E069D211E16260088F0B1 /* mockaksxcbase.m in Sources */, 0CC3771320A222BC00B58D2D /* SFSignInAnalytics.m in Sources */, @@ -36561,10 +36521,10 @@ EBC73F2020993F8600AE3350 /* SFAnalyticsSQLiteStore.m in Sources */, EBC73F2720993FC900AE3350 /* SFAnalyticsMultiSampler.m in Sources */, EB49B2D8202DF1F7003F34A0 /* server_xpc.m in Sources */, - EBC73F2620993FA800AE3350 /* client_endpoint.m in Sources */, EB49B2D9202DF1F7003F34A0 /* server_security_helpers.m in Sources */, EBC73F2B2099785900AE3350 /* SFObjCType.m in Sources */, 480ADDB22155A0CE00318FC6 /* SOSAnalytics.m in Sources */, + EB627A79233E375A00F32437 /* MockAKSOptionalParameters.proto in Sources */, EB49B2E0202DF5D7003F34A0 /* server_entitlement_helpers.c in Sources */, 5A061196229ED6E8006AF14A /* NSDate+SFAnalytics.m in Sources */, EBC73F2A20996AD400AE3350 /* SFSQLiteStatement.m in Sources */, @@ -36573,11 +36533,11 @@ EB49B2D5202DF1D8003F34A0 /* SecTask.c in Sources */, EB49B2D3202DF1AC003F34A0 /* SecdWatchdog.m in Sources */, EB49B2B1202D8780003F34A0 /* mockaksKeychain.m in Sources */, - DC5B391B20C08BDC005B09F6 /* SecFramework.c in Sources */, EB1E069F211E17C00088F0B1 /* mockaksWatchDog.m in Sources */, EB49B2D1202DF15F003F34A0 /* SFAnalyticsActivityTracker.m in Sources */, EB49B2D0202DF14D003F34A0 /* SFAnalytics.m in Sources */, EBC73F2820993FDA00AE3350 /* SFAnalyticsSampler.m in Sources */, + EBDCC001233DD3E000806566 /* MockAKSRefKey.proto in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -36755,11 +36715,6 @@ target = DC0BCC211D8C684F00070CB0 /* utilities */; targetProxy = 0C5663ED20BE2E1A0035F362 /* PBXContainerItemProxy */; }; - 0C604F0221B8E5090036C175 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = DCF216D621ADD5B10029CCC1 /* protobuf_source_generation */; - targetProxy = 0C604F0121B8E5090036C175 /* PBXContainerItemProxy */; - }; 0C78CCE51FCC97E7008B4B24 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 0C8BBEFD1FCB446400580909 /* otctl */; @@ -38840,11 +38795,6 @@ target = DC52E8BE1D80C25800B0A59C /* SecureObjectSyncServer */; targetProxy = DC71DA0C1D95DD670065FB93 /* PBXContainerItemProxy */; }; - DC7479A022272361001E0E8C /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = DCF216D621ADD5B10029CCC1 /* protobuf_source_generation */; - targetProxy = DC74799F22272361001E0E8C /* PBXContainerItemProxy */; - }; DC7FC45221EE9208003C39B8 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DC7FC44721EE914C003C39B8 /* FeatureFlagsPlist */; @@ -39235,21 +39185,6 @@ target = DCDA5E4F2124B9C5009B11B2 /* aks_support */; targetProxy = DCDA5E632124BCA9009B11B2 /* PBXContainerItemProxy */; }; - DCE0775C21ADD6A0002662FD /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = DCF216D621ADD5B10029CCC1 /* protobuf_source_generation */; - targetProxy = DCE0775B21ADD6A0002662FD /* PBXContainerItemProxy */; - }; - DCE0777E21ADEADA002662FD /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = DCF216D621ADD5B10029CCC1 /* protobuf_source_generation */; - targetProxy = DCE0777D21ADEADA002662FD /* PBXContainerItemProxy */; - }; - DCE0778421ADEDDA002662FD /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = DCF216D621ADD5B10029CCC1 /* protobuf_source_generation */; - targetProxy = DCE0778321ADEDDA002662FD /* PBXContainerItemProxy */; - }; DCE4E8D81D7F37F200AFB96E /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DCE4E8931D7F34F600AFB96E /* authd */; @@ -39545,11 +39480,6 @@ target = EBB851EB22F7912400424FD0 /* SecurityUtilitiesTests */; targetProxy = EBB8521722F793EF00424FD0 /* PBXContainerItemProxy */; }; - EBBC11B32200D3BB00F95738 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = DCF216D621ADD5B10029CCC1 /* protobuf_source_generation */; - targetProxy = EBBC11B22200D3BB00F95738 /* PBXContainerItemProxy */; - }; EBCF743F1CE593A700BED7CA /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = EBCF73F31CE45F9C00BED7CA /* secitemfunctionality */; @@ -41880,6 +41810,47 @@ }; name = Release; }; + 5A442F8E233C330F00918373 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_ENTITLEMENTS = "experiment/tool/experimentTool-Entitlements.plist"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + INSTALL_PATH = /usr/sbin; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 5A442F8F233C330F00918373 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_ENTITLEMENTS = "experiment/tool/experimentTool-Entitlements.plist"; + COPY_PHASE_STRIP = NO; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + INSTALL_PATH = /usr/sbin; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; 5E10992A19A5E55800A60E2B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -52978,6 +52949,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 5A442F8D233C330F00918373 /* Build configuration list for PBXNativeTarget "experimentTool" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5A442F8E233C330F00918373 /* Debug */, + 5A442F8F233C330F00918373 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 5E10994D19A5E55800A60E2B /* Build configuration list for PBXNativeTarget "ISACLProtectedItems" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Security.xcodeproj/xcshareddata/xcschemes/osx - World.xcscheme b/Security.xcodeproj/xcshareddata/xcschemes/osx - World.xcscheme index 72291638..09059a50 100644 --- a/Security.xcodeproj/xcshareddata/xcschemes/osx - World.xcscheme +++ b/Security.xcodeproj/xcshareddata/xcschemes/osx - World.xcscheme @@ -117,6 +117,16 @@ ReferencedContainer = "container:Security.xcodeproj"> + + + + #include +#include #pragma clang diagnostic ignored "-Wdeprecated-declarations" @@ -52,53 +53,36 @@ #include #include #include +#include -#include #include -typedef CFTypeRef CFURLResponseRef; -CFDictionaryRef _CFURLResponseGetSSLCertificateContext(CFURLResponseRef); +#include -@interface NSURLResponse (URLResponseInternals) -- (CFURLResponseRef)_CFURLResponse; -@end -@interface NSHTTPURLResponse (HTTPURLResponseInternals) -- (NSArray *)_peerCertificateChain; -@end +@interface TLSConnection : NSObject -@interface NSURLResponse (CertificateUtilities) -- (SecTrustRef)peerTrust; -- (NSArray *)peerCertificates; -@end +@property NSURL *url; +@property NSError *error; +@property SecTrustRef trust; +@property BOOL finished; +@property BOOL udp; // default is NO (use tcp) +@property int verbose; +@property dispatch_queue_t queue; +@property nw_connection_t connection; -@interface CertDownloader : NSObject -{ - @private - NSURL *_url; - NSURLRequest *_urlReq; - NSURLResponse *_urlRsp; - NSURLDownload *_urlDL; - SecTrustRef _trust; - BOOL _finished; -} - -- (id)initWithURLString:(const char *)urlstr; +- (id)initWithURLString:(const char *)urlstr verbose:(int)level; - (void)dealloc; -- (BOOL)finished; -- (void)waitForDownloadToFinish; - -- (SecTrustRef)trustReference; - -- (void)downloadDidFinish:(NSURLDownload *)download; -- (void)download:(NSURLDownload *)download didFailWithError:(NSError *)error; +- (nw_connection_t)createConnection; +- (void)startConnection; +- (void)waitForConnection; +- (NSError*)error; +- (SecTrustRef)trust; + (BOOL)isNetworkURL:(const char *)urlstr; @end -static int _verbose = 0; - #define ANSI_RED "\x1b[31m" #define ANSI_GREEN "\x1b[32m" #define ANSI_YELLOW "\x1b[33m" @@ -107,130 +91,141 @@ static int _verbose = 0; #define ANSI_CYAN "\x1b[36m" #define ANSI_RESET "\x1b[0m" +#if OBJC_ARC_DISABLED +#define NW_RETAIN(obj) nw_retain(obj) +#define NW_RELEASE(obj) nw_release(obj) +#define SEC_RELEASE(obj) sec_release(obj) +#define OBJ_RELEASE(obj) [obj release] +#define SUPER_DEALLOC [super dealloc] +#else +#define NW_RETAIN(obj) +#define NW_RELEASE(obj) +#define SEC_RELEASE(obj) +#define OBJ_RELEASE(obj) +#define SUPER_DEALLOC +#endif -@implementation CertDownloader +@implementation TLSConnection -- (id)initWithURLString:(const char *)urlstr +- (id)initWithURLString:(const char *)urlstr verbose:(int)level { - _finished = NO; _url = [[NSURL alloc] initWithString:[NSString stringWithFormat:@"%s", urlstr]]; - _urlReq = [[NSURLRequest alloc] initWithURL:_url]; - _urlRsp = nil; + _udp = NO; + _finished = NO; + _verbose = level; + _error = nil; _trust = NULL; - - _urlDL = [[NSURLDownload alloc] initWithRequest:_urlReq delegate:self]; - - fprintf(stdout, "Opening connection to %s\n", urlstr); - fflush(stdout); + _queue = dispatch_get_main_queue(); + _connection = [self createConnection]; return self; } - (void)dealloc { - _urlDL = nil; - _urlReq = nil; - _urlRsp = nil; - _url = nil; - _trust = NULL; -} - -- (BOOL)finished -{ - return _finished; -} - -- (void)waitForDownloadToFinish -{ - // cycle the run loop while we're waiting for the _finished flag to be set - NSDate *cycleTime; - while (_finished == NO) { - cycleTime = [NSDate dateWithTimeIntervalSinceNow:0.1]; - [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode beforeDate:cycleTime]; + if (_connection) { + NW_RELEASE(_connection); + _connection = NULL; + } + if (_error) { + OBJ_RELEASE(_error); + _error = nil; + } + if (_url) { + OBJ_RELEASE(_url); + _url = nil; + } + if (_trust) { + CFRelease(_trust); + _trust = NULL; } + SUPER_DEALLOC; } -// NSURLDownloadDelegate delegate methods - -- (void)downloadDidFinish:(NSURLDownload *)download +- (nw_connection_t)createConnection { - if (!_urlRsp) { - fprintf(stdout, "No response received from %s\n", [[_url absoluteString] UTF8String]); - fflush(stdout); + const char *host = [[self.url host] UTF8String]; + const char *port = [[[self.url port] stringValue] UTF8String]; + if (!host) { + if (_verbose > 0) { fprintf(stderr, "Unable to continue without a hostname (is URL valid?)\n"); } + self.finished = YES; + return NULL; } - _finished = YES; + nw_endpoint_t endpoint = nw_endpoint_create_host(host, (port) ? port : "443"); + nw_parameters_configure_protocol_block_t configure_tls = ^(nw_protocol_options_t _Nonnull options) { + sec_protocol_options_t sec_options = nw_tls_copy_sec_protocol_options(options); + sec_protocol_options_set_verify_block(sec_options, ^( + sec_protocol_metadata_t _Nonnull metadata, sec_trust_t _Nonnull trust_ref, sec_protocol_verify_complete_t _Nonnull complete) { + SecTrustRef trust = sec_trust_copy_ref(trust_ref); + if (trust) { + CFRetain(trust); + if (self.trust) { CFRelease(self.trust); } + self.trust = trust; + } + CFErrorRef error = NULL; + BOOL allow = SecTrustEvaluateWithError(trust, &error); + if (error) { + if (self.error) { OBJ_RELEASE(self.error); } + self.error = (__bridge NSError *)error; + } + complete(allow); + }, self.queue); + }; + nw_parameters_t parameters = nw_parameters_create_secure_tcp(configure_tls, NW_PARAMETERS_DEFAULT_CONFIGURATION); + nw_parameters_set_indefinite(parameters, false); // so we don't enter the 'waiting' state on TLS failure + nw_connection_t connection = nw_connection_create(endpoint, parameters); + NW_RELEASE(endpoint); + NW_RELEASE(parameters); + return connection; } -- (void)download:(NSURLDownload *)download didReceiveResponse:(NSURLResponse *)response +- (void)startConnection { - fprintf(stdout, "Received response from %s\n", [[_url absoluteString] UTF8String]); - fflush(stdout); - _urlRsp = response; -} + nw_connection_set_queue(_connection, _queue); + NW_RETAIN(_connection); // Hold a reference until cancelled + + nw_connection_set_state_changed_handler(_connection, ^(nw_connection_state_t state, nw_error_t error) { + nw_endpoint_t remote = nw_connection_copy_endpoint(self.connection); + errno = error ? nw_error_get_error_code(error) : 0; + const char *protocol = self.udp ? "udp" : "tcp"; + const char *host = nw_endpoint_get_hostname(remote); + uint16_t port = nw_endpoint_get_port(remote); + // note: this code does not handle or expect nw_connection_state_waiting, + // since the connection parameters specified a definite connection. + if (state == nw_connection_state_failed) { + if (self.verbose > 0) { + fprintf(stderr, "connection to %s port %u (%s) failed\n", host, port, protocol); + } + // Cancel the connection, so we go to nw_connection_state_cancelled + nw_connection_cancel(self.connection); -- (void)download:(NSURLDownload *)download didFailWithError:(NSError *)error -{ - fprintf(stdout, "Failed connection to %s", [[_url absoluteString] UTF8String]); - if (!_verbose) { - fprintf(stdout, " (use -v option to see more information)"); - } - fprintf(stdout, "\n"); - fflush(stdout); - SecTrustRef tmp = _trust; - _trust = (SecTrustRef)CFBridgingRetain([[error userInfo] objectForKey:@"NSURLErrorFailingURLPeerTrustErrorKey"]); - if (tmp) { CFRelease(tmp); } - _finished = YES; - - if (_verbose) { - // dump the userInfo dictionary - NSLog(@"%@", [error userInfo]); - } -} + } else if (state == nw_connection_state_ready) { + if (self.verbose > 0) { + fprintf(stderr, "connection to %s port %u (%s) opened\n", host, port, protocol); + } + // Once we get the SecTrustRef, we can cancel the connection + nw_connection_cancel(self.connection); -- (SecTrustRef)trustReference -{ - // First, see if we already retained the SecTrustRef, e.g. during a failed connection. - SecTrustRef trust = _trust; - if (!trust) { - // If not, try to obtain the SecTrustRef from the response. - trust = [_urlRsp peerTrust]; - if (trust) { - if (_verbose > 1) { - fprintf(stdout, "Obtained SecTrustRef from the response\n"); + } else if (state == nw_connection_state_cancelled) { + if (self.verbose > 0) { + fprintf(stderr, "connection to %s port %u (%s) closed\n", host, port, protocol); } - CFRetain(trust); - _trust = trust; - } - } - if (!trust) { - // We don't have a SecTrustRef, so build one ourselves for this host. - NSString *host = [_url host]; - if (_verbose > 1) { - fprintf(stdout, "Building our own SecTrustRef for \"%s\"\n", host ? [host UTF8String] : ""); + nw_connection_cancel(self.connection); // cancel to be safe (should be a no-op) + NW_RELEASE(_connection); // release the reference and set flag to exit loop + self.finished = YES; } - SecPolicyRef sslPolicy = SecPolicyCreateSSL(false, (__bridge CFStringRef)host); - SecPolicyRef revPolicy = SecPolicyCreateRevocation(kSecRevocationUseAnyAvailableMethod); - NSArray *policies = [NSArray arrayWithObjects:(__bridge id)sslPolicy, (__bridge id)revPolicy, nil]; - NSArray *certs = [_urlRsp peerCertificates]; - if (certs) { - (void)SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, (__bridge CFArrayRef)policies, &trust); - _trust = trust; - } - } + NW_RELEASE(remote); + }); - // Ensure that the trust has been evaluated - SecTrustResultType result = kSecTrustResultInvalid; - OSStatus status = SecTrustGetTrustResult(trust, &result); - bool needsEvaluation = (status != errSecSuccess || result == kSecTrustResultInvalid); - if (needsEvaluation) { - status = SecTrustEvaluate(trust, &result); - if (_verbose > 1) { - fprintf(stdout, "%s trust reference (status = %d, trust result = %d)\n", - (needsEvaluation) ? "Evaluated" : "Checked", - (int)status, (int)result); - } + nw_connection_start(_connection); +} + +- (void)waitForConnection +{ + while (_finished == NO) { + NSDate *cycleTime = [NSDate dateWithTimeIntervalSinceNow:0.1]; + [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:cycleTime]; } - return trust; } + (BOOL)isNetworkURL:(const char *)urlstr @@ -247,44 +242,6 @@ static int _verbose = 0; @end -@implementation NSURLResponse (CertificateUtilities) - -- (SecTrustRef)peerTrust -{ - SecTrustRef trust = NULL; - - // Obtain the underlying SecTrustRef used by CFNetwork for the connection. - CFDictionaryRef certificateContext = _CFURLResponseGetSSLCertificateContext([self _CFURLResponse]); - if (_verbose && !certificateContext) { - fprintf(stdout, "Unable to get SSL certificate context!\n"); - fflush(stdout); - } else { - trust = (SecTrustRef) CFDictionaryGetValue(certificateContext, kCFStreamPropertySSLPeerTrust); - } - if (_verbose && !trust) { - fprintf(stdout, "Unable to get kCFStreamPropertySSLPeerTrust!\n"); - fflush(stdout); - } - return trust; -} - -- (NSArray *)peerCertificates -{ - NSArray *certificateChain = nil; - if ([self isKindOfClass:[NSHTTPURLResponse class]]) { - certificateChain = [(NSHTTPURLResponse *)self _peerCertificateChain]; - } - if (_verbose && certificateChain) { - fprintf(stdout, "Peer certificates: "); - fflush(stdout); - CFShow((__bridge CFArrayRef)certificateChain); - } - return certificateChain; -} - -@end - - static NSString *errorStringForKey(NSString *key) { NSString *errstr = nil; @@ -412,20 +369,30 @@ void printExtendedResults(SecTrustRef trust) int evaluate_ssl(const char *urlstr, int verbose, SecTrustRef * CF_RETURNS_RETAINED trustRef) { @autoreleasepool { - _verbose = verbose; if (trustRef) { *trustRef = NULL; } - if (![CertDownloader isNetworkURL:urlstr]) { + if (![TLSConnection isNetworkURL:urlstr]) { return 2; } - CertDownloader *context = [[CertDownloader alloc] initWithURLString:urlstr]; - [context waitForDownloadToFinish]; - SecTrustRef trust = [context trustReference]; + TLSConnection *tls = [[TLSConnection alloc] initWithURLString:urlstr verbose:verbose]; + [tls startConnection]; + [tls waitForConnection]; + + NSError *error = [tls error]; + if (verbose && error) { + fprintf(stderr, "NSError: { "); + CFShow((__bridge CFErrorRef)error); + fprintf(stderr,"}\n"); + } + + SecTrustRef trust = [tls trust]; if (trustRef && trust) { CFRetain(trust); *trustRef = trust; } + OBJ_RELEASE(tls); + tls = nil; } return 0; } diff --git a/SecurityTool/macOS/verify_cert.c b/SecurityTool/macOS/verify_cert.c index 58618c7b..65ffbbb0 100644 --- a/SecurityTool/macOS/verify_cert.c +++ b/SecurityTool/macOS/verify_cert.c @@ -70,6 +70,7 @@ verify_cert(int argc, char * const *argv) CFMutableArrayRef roots = NULL; CFMutableArrayRef keychains = NULL; CFMutableArrayRef policies = NULL; + CFMutableDictionaryRef properties = NULL; const CSSM_OID *policy = &CSSMOID_APPLE_X509_BASIC; SecKeychainRef kcRef = NULL; int ourRtn = 0; @@ -89,12 +90,9 @@ verify_cert(int argc, char * const *argv) const char *sslHost = NULL; const char *name = NULL; const char *url = NULL; - CSSM_APPLE_TP_SSL_OPTIONS sslOpts; - CSSM_APPLE_TP_SMIME_OPTIONS smimeOpts; CSSM_APPLE_TP_ACTION_FLAGS actionFlags = 0; bool forceActionFlags = false; CSSM_APPLE_TP_ACTION_DATA actionData; - CSSM_DATA optionData; CFDataRef cfActionData = NULL; SecTrustResultType resultType; OSStatus ocrtn; @@ -162,7 +160,7 @@ verify_cert(int argc, char * const *argv) */ char *o = argv[optind]; if (o && o[0] != '-') { - name = optarg; + name = o; ++optind; break; } @@ -256,56 +254,52 @@ verify_cert(int argc, char * const *argv) } /* cook up a SecPolicyRef */ - ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3, - policy, - NULL, // policy opts - &searchRef); - if(ortn) { - cssmPerror("SecPolicySearchCreate", ortn); - ourRtn = 1; - goto errOut; - } - ortn = SecPolicySearchCopyNext(searchRef, &policyRef); - if(ortn) { - cssmPerror("SecPolicySearchCopyNext", ortn); + properties = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (!properties) { + cssmPerror("CFDictionaryCreateMutable", errSecMemoryError); ourRtn = 1; goto errOut; - } - - /* per-policy options */ - if(compareOids(policy, &CSSMOID_APPLE_TP_SSL) || compareOids(policy, &CSSMOID_APPLE_TP_APPLEID_SHARING)) { - const char *nameStr = (name) ? name : ((sslHost) ? sslHost : NULL); - if(nameStr) { - memset(&sslOpts, 0, sizeof(sslOpts)); - sslOpts.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION; - sslOpts.ServerName = nameStr; - sslOpts.ServerNameLen = (uint32) strlen(nameStr); - sslOpts.Flags = (client) ? CSSM_APPLE_TP_SSL_CLIENT : 0; - optionData.Data = (uint8 *)&sslOpts; - optionData.Length = sizeof(sslOpts); - ortn = SecPolicySetValue(policyRef, &optionData); - if(ortn) { - cssmPerror("SecPolicySetValue", ortn); - ourRtn = 1; - goto errOut; - } + } else { + /* if a policy name was specified to match, set it in the dictionary */ + const char *nameStr = name; + if (!nameStr) { nameStr = (sslHost) ? sslHost : ((emailAddrs) ? emailAddrs : NULL); } + CFStringRef nameRef = (nameStr) ? CFStringCreateWithBytes(NULL, + (const UInt8 *)nameStr, (CFIndex)strlen(nameStr), kCFStringEncodingUTF8, false) : NULL; + if (nameRef) { + CFDictionarySetValue(properties, kSecPolicyName, nameRef); + CFRELEASE(nameRef); + } + CFStringRef policyID = NULL; + if (compareOids(policy, &CSSMOID_APPLE_TP_SSL)) { + policyID = kSecPolicyAppleSSL; + } else if (compareOids(policy, &CSSMOID_APPLE_TP_EAP)) { + policyID = kSecPolicyAppleEAP; + } else if (compareOids(policy, &CSSMOID_APPLE_TP_APPLEID_SHARING)) { + policyID = kSecPolicyAppleIDValidation; + } else if (compareOids(policy, &CSSMOID_APPLE_TP_SMIME)) { + policyID = kSecPolicyAppleSMIME; + } + if (policyID) { + policyRef = SecPolicyCreateWithProperties(policyID, properties); } } - if(compareOids(policy, &CSSMOID_APPLE_TP_SMIME)) { - const char *nameStr = (name) ? name : ((emailAddrs) ? emailAddrs : NULL); - if(nameStr) { - memset(&smimeOpts, 0, sizeof(smimeOpts)); - smimeOpts.Version = CSSM_APPLE_TP_SMIME_OPTS_VERSION; - smimeOpts.SenderEmail = nameStr; - smimeOpts.SenderEmailLen = (uint32) strlen(nameStr); - optionData.Data = (uint8 *)&smimeOpts; - optionData.Length = sizeof(smimeOpts); - ortn = SecPolicySetValue(policyRef, &optionData); - if(ortn) { - cssmPerror("SecPolicySetValue", ortn); - ourRtn = 1; - goto errOut; - } + if (!policyRef) { + /* all other policies not handled above */ + ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3, + policy, + NULL, // policy opts + &searchRef); + if(ortn) { + cssmPerror("SecPolicySearchCreate", ortn); + ourRtn = 1; + goto errOut; + } + ortn = SecPolicySearchCopyNext(searchRef, &policyRef); + if(ortn) { + cssmPerror("SecPolicySearchCopyNext", ortn); + ourRtn = 1; + goto errOut; } } @@ -439,6 +433,7 @@ errOut: CFRELEASE(certs); CFRELEASE(roots); CFRELEASE(keychains); + CFRELEASE(properties); CFRELEASE(policies); CFRELEASE(revPolicyRef); CFRELEASE(dateRef); diff --git a/SecurityTool/sharedTool/sos.m b/SecurityTool/sharedTool/sos.m index ee18108f..e52156b7 100644 --- a/SecurityTool/sharedTool/sos.m +++ b/SecurityTool/sharedTool/sos.m @@ -177,16 +177,21 @@ command_sos_control(__unused int argc, __unused char * const * argv) bool assertStashAccountKey = false; bool triggerSync = false; - NSString *syncingPeer = NULL; + NSMutableArray* syncingPeers = NULL; + bool triggerBackup = false; + NSMutableArray* backupPeers = NULL; SOSAccountGhostBustingOptions gboptions = 0; bool gbinfo = false; bool gbtriggered = false; bool circleHash = false; + bool triggerRingUpdate = false; static struct option long_options[] = { /* These options set a flag. */ {"assertStashAccountKey", no_argument, NULL, 'a'}, + {"trigger-backup", optional_argument, NULL, 'B'}, + {"trigger-ring-update", no_argument, NULL, 'R'}, {"trigger-sync", optional_argument, NULL, 's'}, {"circle-hash", optional_argument, NULL, 'H'}, {"ghostbustByMID", optional_argument, NULL, 'M'}, @@ -198,7 +203,7 @@ command_sos_control(__unused int argc, __unused char * const * argv) {0, 0, 0, 0} }; - while ((ch = getopt_long(argc, argv, "asGHAMSIT", long_options, &option_index)) != -1) { + while ((ch = getopt_long(argc, argv, "as:AB:GHIMRST", long_options, &option_index)) != -1) { switch (ch) { case 'a': { assertStashAccountKey = true; @@ -207,7 +212,10 @@ command_sos_control(__unused int argc, __unused char * const * argv) case 's': { triggerSync = true; if (optarg) { - syncingPeer = [NSString stringWithUTF8String:optarg]; + if (syncingPeers == NULL) { + syncingPeers = [NSMutableArray array]; + } + [syncingPeers addObject:[NSString stringWithUTF8String:optarg]]; } break; } @@ -215,6 +223,16 @@ command_sos_control(__unused int argc, __unused char * const * argv) gboptions |= SOSGhostBustSerialByAge; break; } + case 'B': { + triggerBackup = true; + if (optarg) { + if (backupPeers == NULL) { + backupPeers = [NSMutableArray array]; + } + [backupPeers addObject:[NSString stringWithUTF8String:optarg]]; + } + break; + } case 'G': { gbinfo = true; break; @@ -223,6 +241,9 @@ command_sos_control(__unused int argc, __unused char * const * argv) gboptions |= SOSGhostBustByMID; break; } + case 'R': + triggerRingUpdate = true; + break; case 'S': { gboptions |= SOSGhostBustBySerialNumber; break; @@ -282,20 +303,36 @@ command_sos_control(__unused int argc, __unused char * const * argv) } }]; } else if (triggerSync) { - NSMutableArray *peers = [NSMutableArray array]; - if (syncingPeer) { - [peers addObject:syncingPeer]; - } - [[control.connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *error) { printControlFailureMessage(error); - }] triggerSync:peers complete:^(bool res, NSError *error) { + }] rpcTriggerSync:syncingPeers complete:^(bool res, NSError *error) { if (res) { printf("starting to sync was successful\n"); } else { printf("%s", [[NSString stringWithFormat:@"Failed to start sync: %@\n", error] UTF8String]); } }]; + } else if (triggerBackup) { + [[control.connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *error) { + printControlFailureMessage(error); + }] rpcTriggerBackup:backupPeers complete:^(NSError *error) { + if (error == NULL) { + printf("trigger backup was successful\n"); + } else { + printf("%s", [[NSString stringWithFormat:@"Failed to start backup: %@\n", error] UTF8String]); + } + }]; + } else if (triggerRingUpdate) { + [[control.connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *error) { + printControlFailureMessage(error); + }] rpcTriggerRingUpdate:^(NSError *error) { + if (error == NULL) { + printf("trigger ring update was successful\n"); + } else { + printf("%s", [[NSString stringWithFormat:@"Failed to start ring update: %@\n", error] UTF8String]); + } + }]; + } else if (assertStashAccountKey) { [[control.connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *error) { printControlFailureMessage(error); diff --git a/TestPlan.xctestplan b/TestPlan.xctestplan new file mode 100644 index 00000000..551dd811 --- /dev/null +++ b/TestPlan.xctestplan @@ -0,0 +1,18 @@ +{ + "configurations" : [ + { + "id" : "E61600EC-4F68-414B-932D-2A0655D233A4", + "name" : "Configuration 1", + "options" : { + + } + } + ], + "defaultOptions" : { + + }, + "testTargets" : [ + + ], + "version" : 1 +} diff --git a/base/Security.h b/base/Security.h index e4e5435d..c5c4914c 100644 --- a/base/Security.h +++ b/base/Security.h @@ -85,6 +85,7 @@ /* Code Signing */ #include #include +#include #include #include diff --git a/experiment/SecExperiment.m b/experiment/SecExperiment.m new file mode 100644 index 00000000..c39ddaa5 --- /dev/null +++ b/experiment/SecExperiment.m @@ -0,0 +1,590 @@ +// +// SecExperiment.m +// Security +// + +#include +#include +#include +#include + +#define OS_OBJECT_HAVE_OBJC_SUPPORT 1 + +#define SEC_EXP_NULL_BAD_INPUT ((void *_Nonnull)NULL) +#define SEC_EXP_NULL_OUT_OF_MEMORY SEC_EXP_NULL_BAD_INPUT + +#define SEC_EXP_NIL_BAD_INPUT ((void *_Nonnull)nil) +#define SEC_EXP_NIL_OUT_OF_MEMORY SEC_EXP_NIL_BAD_INPUT + +#define SEC_EXP_CONCRETE_CLASS_NAME(external_type) SecExpConcrete_##external_type +#define SEC_EXP_CONCRETE_PREFIX_STR "SecExpConcrete_" + +#define SEC_EXP_OBJECT_DECL_INTERNAL_OBJC(external_type) \ +@class SEC_EXP_CONCRETE_CLASS_NAME(external_type); \ +typedef SEC_EXP_CONCRETE_CLASS_NAME(external_type) *external_type##_t + +#define SEC_EXP_OBJECT_IMPL_INTERNAL_OBJC_WITH_PROTOCOL_AND_VISBILITY(external_type, _protocol, visibility, ...) \ +@protocol OS_OBJECT_CLASS(external_type) <_protocol> \ +@end \ +visibility \ +@interface SEC_EXP_CONCRETE_CLASS_NAME(external_type) : NSObject \ +_Pragma("clang diagnostic push") \ +_Pragma("clang diagnostic ignored \"-Wobjc-interface-ivars\"") \ +__VA_ARGS__ \ +_Pragma("clang diagnostic pop") \ +@end \ +typedef int _useless_typedef_oio_##external_type + +#define SEC_EXP_OBJECT_IMPL_INTERNAL_OBJC_WITH_PROTOCOL(external_type, _protocol, ...) \ +SEC_EXP_OBJECT_IMPL_INTERNAL_OBJC_WITH_PROTOCOL_AND_VISBILITY(external_type, _protocol, ,__VA_ARGS__) + +#define SEC_EXP_OBJECT_IMPL_INTERNAL_OBJC(external_type, ...) \ +SEC_EXP_OBJECT_IMPL_INTERNAL_OBJC_WITH_PROTOCOL(external_type, NSObject, ##__VA_ARGS__) + +#define SEC_EXP_OBJECT_IMPL_INTERNAL_OBJC_WITH_VISIBILITY(external_type, visibility, ...) \ +SEC_EXP_OBJECT_IMPL_INTERNAL_OBJC_WITH_PROTOCOL_AND_VISBILITY(external_type, NSObject, visibility, ##__VA_ARGS__) + +SEC_EXP_OBJECT_DECL_INTERNAL_OBJC(sec_experiment); + +#define SEC_EXP_OBJECT_IMPL 1 +#import "SecExperimentPriv.h" +#import "SecExperimentInternal.h" +#import "SecCFRelease.h" +#import +#import +#import +#import + +#define SEC_EXPERIMENT_SAMPLING_RATE 100.0 +#define HASH_INITIAL_VALUE 0 +#define HASH_MULTIPLIER 31 + +const char *kSecExperimentDefaultsDomain = "com.apple.security.experiment"; +const char *kSecExperimentDefaultsDisableSampling = "disableSampling"; +const char *kSecExperimentTLSProbe = "TLSProbeExperiment"; + +const NSString *SecExperimentConfigurationKeyFleetSampleRate = @"FleetSampleRate"; +const NSString *SecExperimentConfigurationKeyDeviceSampleRate = @"DeviceSampleRate"; +const NSString *SecExperimentConfigurationKeyExperimentIdentifier = @"ExpName"; +const NSString *SecExperimentConfigurationKeyConfigurationData = @"ConfigData"; + +static os_log_t +sec_experiment_copy_log_handle(void) +{ + static dispatch_once_t onceToken = 0; + static os_log_t experiment_log = nil; + dispatch_once(&onceToken, ^{ + experiment_log = os_log_create("com.apple.security", "experiment"); + }); + return experiment_log; +} + +#define sec_experiment_log_info(fmt, ...) \ + do { \ + os_log_t _log_handle = sec_experiment_copy_log_handle(); \ + if (_log_handle) { \ + os_log_info(_log_handle, fmt, ##__VA_ARGS__); \ + } \ + } while (0); + +#define sec_experiment_log_debug(fmt, ...) \ + do { \ + os_log_t _log_handle = sec_experiment_copy_log_handle(); \ + if (_log_handle) { \ + os_log_debug(_log_handle, fmt, ##__VA_ARGS__); \ + } \ + } while (0); + +#define sec_experiment_log_error(fmt, ...) \ + do { \ + os_log_t _log_handle = sec_experiment_copy_log_handle(); \ + if (_log_handle) { \ + os_log_error(_log_handle, fmt, ##__VA_ARGS__); \ + } \ + } while (0); + +// Computes hash of input and returns a value between 1-100 +static uint32_t +sec_experiment_hash_multiplicative(const uint8_t *key, size_t len) +{ + if (!key) { + return 0; + } + + uint32_t hash = HASH_INITIAL_VALUE; + for (uint32_t i = 0; i < len; ++i) { + hash = HASH_MULTIPLIER * hash + key[i]; + } + + return hash % 101; // value between 0-100 +} + +static uint32_t +sec_experiment_host_hash(void) +{ + static uuid_string_t hostuuid = {}; + static uint32_t hash = 0; + static dispatch_once_t onceToken = 0; + dispatch_once(&onceToken, ^{ + struct timespec timeout = {0, 0}; + uuid_t uuid = {}; + if (gethostuuid(uuid, &timeout) == 0) { + uuid_unparse(uuid, hostuuid); + hash = sec_experiment_hash_multiplicative((const uint8_t *)hostuuid, strlen(hostuuid)); + } else { + onceToken = 0; + } + }); + return hash; +} + +SEC_EXP_OBJECT_IMPL_INTERNAL_OBJC(sec_experiment, +{ +@public + SecExperiment *innerExperiment; + size_t numRuns; + size_t successRuns; +}); + +@implementation SEC_EXP_CONCRETE_CLASS_NAME(sec_experiment) + +- (instancetype)initWithName:(const char *)name +{ + if (name == NULL) { + return SEC_EXP_NIL_BAD_INPUT; + } + + self = [super init]; + if (self == nil) { + return SEC_EXP_NIL_OUT_OF_MEMORY; + } else { + self->innerExperiment = [[SecExperiment alloc] initWithName:name]; + } + return self; +} + +- (instancetype)initWithInnerExperiment:(SecExperiment *)experiment +{ + if (experiment == NULL) { + return SEC_EXP_NIL_BAD_INPUT; + } + + self = [super init]; + if (self == nil) { + return SEC_EXP_NIL_OUT_OF_MEMORY; + } else { + self->innerExperiment = experiment; + } + return self; +} + +- (const char *)name +{ + return [innerExperiment.name UTF8String]; +} + +- (const char *)identifier +{ + return [innerExperiment.identifier UTF8String]; +} + +- (BOOL)experimentIsAllowedForProcess +{ + return [innerExperiment experimentIsAllowedForProcess]; +} + +- (BOOL)isSamplingDisabledWithDefault:(BOOL)defaultValue +{ + return [innerExperiment isSamplingDisabledWithDefault:defaultValue]; +} + +- (BOOL)isSamplingDisabled +{ + return [innerExperiment isSamplingDisabled]; +} + +- (SecExperimentConfig *)copyExperimentConfiguration +{ + return [innerExperiment copyExperimentConfiguration]; +} + +@end + +@interface SecExperiment() +@property NSString *name; +@property (nonatomic) BOOL samplingDisabled; +@property SecExperimentConfig *cachedConfig; +@end + +@implementation SecExperiment + +- (instancetype)initWithName:(const char *)name +{ + if (name == NULL) { + return SEC_EXP_NIL_BAD_INPUT; + } + + self = [super init]; + if (self == nil) { + return SEC_EXP_NIL_OUT_OF_MEMORY; + } else { + self.name = [NSString stringWithUTF8String:name]; + } + return self; +} + +- (BOOL)experimentIsAllowedForProcess +{ + __block NSArray *whitelistedProcesses = @[ + @"nsurlsessiond", + @"com.apple.WebKit.Networking", + @"experimentTool", + @"network_test", + ]; + + static BOOL isAllowed = NO; + static dispatch_once_t onceToken = 0; + dispatch_once(&onceToken, ^{ + uint32_t flags = 0; + int ret = csops(getpid(), CS_OPS_STATUS, &flags, sizeof(flags)); + if (ret) { + // Fail closed if we're not able to determine the type of binary. + return; + } + + if (!(flags & CS_PLATFORM_BINARY)) { + // Allow SecExperiment on all non-platform binaries, e.g., third party apps. + isAllowed = YES; + return; + } + + // Otherwise, this is a platform binary. Check against the set of whitelisted processes. + NSString *process = [NSString stringWithFormat:@"%s", getprogname()]; + [whitelistedProcesses enumerateObjectsUsingBlock:^(NSString * _Nonnull whitelistedProcess, NSUInteger idx, BOOL * _Nonnull stop) { + if ([whitelistedProcess isEqualToString:process]) { + isAllowed = YES; + *stop = YES; // Stop searching the whitelist + } + }]; + }); + + return isAllowed; +} + +- (BOOL)isSamplingDisabledWithDefault:(BOOL)defaultValue +{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + if (defaults != nil) { + NSMutableDictionary *experimentDefaults = [[defaults persistentDomainForName:[NSString stringWithUTF8String:kSecExperimentDefaultsDomain]] mutableCopy]; + if (experimentDefaults != nil) { + NSString *key = [NSString stringWithUTF8String:kSecExperimentDefaultsDisableSampling]; + if (experimentDefaults[key] != nil) { + return [experimentDefaults[key] boolValue]; + } + } + } + + return defaultValue; +} + +- (BOOL)isSamplingDisabled +{ + return [self isSamplingDisabledWithDefault:self.samplingDisabled]; +} + +- (NSDictionary *)copyExperimentConfigurationFromUserDefaults +{ + NSDictionary *result = nil; + + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + if (defaults != nil) { + NSMutableDictionary *experimentDefaults = [[defaults persistentDomainForName:[NSString stringWithUTF8String:kSecExperimentDefaultsDomain]] mutableCopy]; + if (experimentDefaults != nil) { + NSString *key = self.name; + if (experimentDefaults[key] != nil) { + result = experimentDefaults[key]; + } + } + } + + return result; +} + +- (NSDictionary *)copyRemoteExperimentAsset +{ + CFErrorRef error = NULL; + NSDictionary *config = NULL; + NSDictionary *asset = CFBridgingRelease(SecTrustOTASecExperimentCopyAsset(&error)); + if (asset) { + config = [asset valueForKey:self.name]; + } + CFReleaseNull(error); + return config; +} + +- (NSDictionary *)copyRandomExperimentConfigurationFromAsset:(NSDictionary *)asset +{ + NSArray *array = [asset valueForKey:@"ConfigArray"]; + if (array == nil) { + return nil; + } + return [array objectAtIndex:(arc4random() % [array count])]; +} + +- (SecExperimentConfig *)copyExperimentConfiguration +{ + if (self.cachedConfig) { + // If we've fetched an experiment config already, use it for the duration of this object's lifetime. + return self.cachedConfig; + } + + NSDictionary *defaultsDictionary = [self copyExperimentConfigurationFromUserDefaults]; + if (defaultsDictionary != nil) { + self.cachedConfig = [[SecExperimentConfig alloc] initWithConfiguration:defaultsDictionary]; + return self.cachedConfig; + } + + NSDictionary *remoteAsset = [self copyRemoteExperimentAsset]; + if (remoteAsset != nil) { + NSDictionary *randomConfig = [self copyRandomExperimentConfigurationFromAsset:remoteAsset]; + self.cachedConfig = [[SecExperimentConfig alloc] initWithConfiguration:randomConfig]; + return self.cachedConfig; + } + + return nil; +} + +- (NSString *)identifier +{ + if (self.cachedConfig != nil) { + return [self.cachedConfig identifier]; + } else { + return nil; + } +} + +@end + +@interface SecExperimentConfig() +@property NSString *identifier; +@property NSDictionary *config; +@property uint32_t fleetSampleRate; +@property uint32_t deviceSampleRate; +@property NSDictionary *configurationData; +@end + +@implementation SecExperimentConfig + +- (instancetype)initWithConfiguration:(NSDictionary *)configuration +{ + if (configuration == nil) { + return SEC_EXP_NIL_BAD_INPUT; + } + + self = [super init]; + if (self == nil) { + return SEC_EXP_NIL_OUT_OF_MEMORY; + } else { + // Parse out experiment information from the configuration dictionary + self.config = configuration; + self.identifier = [configuration objectForKey:SecExperimentConfigurationKeyExperimentIdentifier]; + + NSNumber *deviceSampleRate = [configuration objectForKey:SecExperimentConfigurationKeyDeviceSampleRate]; + if (deviceSampleRate != nil) { + self.deviceSampleRate = [deviceSampleRate unsignedIntValue]; + } + + NSNumber *fleetSampleRate = [configuration objectForKey:SecExperimentConfigurationKeyFleetSampleRate]; + if (fleetSampleRate != nil) { + self.fleetSampleRate = [fleetSampleRate unsignedIntValue]; + } + + self.configurationData = [configuration objectForKey:SecExperimentConfigurationKeyConfigurationData]; + } + return self; +} + +- (uint32_t)hostHash +{ + return sec_experiment_host_hash(); +} + +- (BOOL)shouldRunWithSamplingRate:(NSNumber *)sampleRate +{ + if (!sampleRate) { + return NO; + } + + uint32_t sample = arc4random(); + return ((float)sample < ((float)UINT32_MAX / [sampleRate unsignedIntegerValue])); +} + +- (BOOL)isSampled +{ + uint32_t hostIdHash = [self hostHash]; + if ((hostIdHash == 0) || (self.fleetSampleRate < hostIdHash)) { + return NO; + } + + return [self shouldRunWithSamplingRate:@(self.deviceSampleRate)]; +} + +@end + +sec_experiment_t +sec_experiment_create(const char *name) +{ + return [[SEC_EXP_CONCRETE_CLASS_NAME(sec_experiment) alloc] initWithName:name]; +} + +sec_experiment_t +sec_experiment_create_with_inner_experiment(SecExperiment *experiment) +{ + return [[SEC_EXP_CONCRETE_CLASS_NAME(sec_experiment) alloc] initWithInnerExperiment:experiment]; +} + +void +sec_experiment_set_sampling_disabled(sec_experiment_t experiment, bool sampling_disabled) +{ + experiment->innerExperiment.samplingDisabled = sampling_disabled; +} + +const char * +sec_experiment_get_identifier(sec_experiment_t experiment) +{ + return [experiment identifier]; +} + +xpc_object_t +sec_experiment_copy_configuration(sec_experiment_t experiment) +{ + if (experiment == nil) { + return nil; + } + + // Check first for defaults configured + SecExperimentConfig *experimentConfiguration = [experiment copyExperimentConfiguration]; + if (experimentConfiguration != nil) { + NSDictionary *configurationData = [experimentConfiguration configurationData]; + if (![experiment isSamplingDisabled]) { + if ([experimentConfiguration isSampled]) { + return _CFXPCCreateXPCObjectFromCFObject((__bridge CFDictionaryRef)configurationData); + } else { + sec_experiment_log_info("Configuration '%{public}s' for experiment '%{public}s' not sampled to run", + [experiment name], [[experimentConfiguration identifier] UTF8String]); + return nil; + } + } else { + return _CFXPCCreateXPCObjectFromCFObject((__bridge CFDictionaryRef)configurationData); + } + } + + return nil; +} + +bool +sec_experiment_run_internal(sec_experiment_t experiment, bool sampling_disabled, dispatch_queue_t queue, sec_experiment_run_block_t run_block, sec_experiment_skip_block_t skip_block, bool synchronous) +{ + if (experiment == NULL || run_block == nil) { + return false; + } + + if (![experiment experimentIsAllowedForProcess]) { + sec_experiment_log_info("Not running experiments for disallowed process"); + return false; + } + + dispatch_block_t experiment_block = ^{ + bool experiment_sampling_disabled = [experiment isSamplingDisabledWithDefault:sampling_disabled]; + sec_experiment_set_sampling_disabled(experiment, [experiment isSamplingDisabledWithDefault:sampling_disabled]); + xpc_object_t config = sec_experiment_copy_configuration(experiment); + const char *identifier = sec_experiment_get_identifier(experiment); + if (config != nil) { + experiment->numRuns++; + if (run_block(identifier, config)) { + experiment->successRuns++; + sec_experiment_log_info("Configuration '%s' for experiment '%s' succeeded", identifier, [experiment name]); + } else { + sec_experiment_log_info("Configuration '%s' for experiment '%s' failed", identifier, [experiment name]); + } + } else { + sec_experiment_log_info("Configuration '%s' for experiment '%s' not configured to run with sampling %s", identifier, + [experiment name], experiment_sampling_disabled ? "disabled" : "enabled"); + if (skip_block) { + skip_block(sec_experiment_get_identifier(experiment)); + } + } + }; + + if (synchronous || !queue) { + sec_experiment_log_info("Starting experiment '%s' synchronously with sampling %s", [experiment name], sampling_disabled ? "disabled" : "enabled"); + experiment_block(); + } else { + sec_experiment_log_info("Starting experiment '%s' asynchronously with sampling %s", [experiment name], sampling_disabled ? "disabled" : "enabled"); + dispatch_async(queue, experiment_block); + } + + return true; +} + +bool +sec_experiment_run(const char *experiment_name, sec_experiment_run_block_t run_block, sec_experiment_skip_block_t skip_block) +{ + // Sampling is always enabled for SecExperiment callers. Appliations may override this by setting the + // `disableSampling` key in the `com.apple.security.experiment` defaults domain. + sec_experiment_t experiment = sec_experiment_create(experiment_name); + if (experiment) { + return sec_experiment_run_internal(experiment, false, NULL, run_block, skip_block, true); + } else { + sec_experiment_log_info("Experiment '%s' not found", experiment_name); + return false; + } +} + +bool +sec_experiment_run_async(const char *experiment_name, dispatch_queue_t queue, sec_experiment_run_block_t run_block, sec_experiment_skip_block_t skip_block) +{ + sec_experiment_t experiment = sec_experiment_create(experiment_name); + if (experiment) { + return sec_experiment_run_internal(experiment, false, queue, run_block, skip_block, false); + } else { + sec_experiment_log_info("Experiment '%s' not found", experiment_name); + return false; + } +} + +bool +sec_experiment_run_with_sampling_disabled(const char *experiment_name, sec_experiment_run_block_t run_block, sec_experiment_skip_block_t skip_block, bool sampling_disabled) +{ + sec_experiment_t experiment = sec_experiment_create(experiment_name); + if (experiment) { + return sec_experiment_run_internal(experiment, sampling_disabled, NULL, run_block, skip_block, true); + } else { + sec_experiment_log_info("Experiment '%s' not found", experiment_name); + return false; + } +} + +bool +sec_experiment_run_async_with_sampling_disabled(const char *experiment_name, dispatch_queue_t queue, sec_experiment_run_block_t run_block, sec_experiment_skip_block_t skip_block, bool sampling_disabled) +{ + sec_experiment_t experiment = sec_experiment_create(experiment_name); + if (experiment) { + return sec_experiment_run_internal(experiment, sampling_disabled, queue, run_block, skip_block, false); + } else { + sec_experiment_log_info("Experiment '%s' not found", experiment_name); + return false; + } +} + +size_t +sec_experiment_get_run_count(sec_experiment_t experiment) +{ + return experiment->numRuns; +} + +size_t +sec_experiment_get_successful_run_count(sec_experiment_t experiment) +{ + return experiment->successRuns; +} diff --git a/experiment/SecExperimentInternal.h b/experiment/SecExperimentInternal.h new file mode 100644 index 00000000..e475dcdb --- /dev/null +++ b/experiment/SecExperimentInternal.h @@ -0,0 +1,141 @@ +// +// SecExperimentInternal.h +// Security +// + +#ifndef SecExperimentInternal_h +#define SecExperimentInternal_h + +#include + +SEC_ASSUME_NONNULL_BEGIN + +extern const NSString *SecExperimentConfigurationKeyFleetSampleRate; +extern const NSString *SecExperimentConfigurationKeyDeviceSampleRate; +extern const NSString *SecExperimentConfigurationKeyExperimentIdentifier; +extern const NSString *SecExperimentConfigurationKeyConfigurationData; + +@interface SecExperimentConfig : NSObject +@property (readonly) NSString *identifier; +@property (readonly) uint32_t fleetSampleRate; +@property (readonly) uint32_t deviceSampleRate; +@property (readonly) NSDictionary *configurationData; +@property (readonly) BOOL isSampled; +- (instancetype)initWithConfiguration:(NSDictionary *)configuration; + +// Note: these functions are exposed for testing purposes only. +- (uint32_t)hostHash; +- (BOOL)shouldRunWithSamplingRate:(NSNumber *)sampleRate; +@end + +@interface SecExperiment : NSObject +@property (readonly) NSString *name; +@property (readonly) NSString *identifier; +@property (readonly) BOOL samplingDisabled; +- (instancetype)initWithName:(const char *)name; +- (BOOL)experimentIsAllowedForProcess; +- (BOOL)isSamplingDisabledWithDefault:(BOOL)defaultValue; +- (BOOL)isSamplingDisabled; +- (SecExperimentConfig *)copyExperimentConfiguration; + +// Note: These functions are exposed for testing purposes only. +- (NSDictionary *)copyExperimentConfigurationFromUserDefaults; +- (NSDictionary *)copyRemoteExperimentAsset; +- (NSDictionary *)copyRandomExperimentConfigurationFromAsset:(NSDictionary *)asset; +@end + +/*! + * @function sec_experiment_create_with_inner_experiment + * + * @abstract + * Create an ARC-able `sec_experiment_t` instance wrapping an internal `SecExperiment` object. + * + * @param experiment_name + * Name of the experiment. + * + * @return a `sec_experiment_t` instance. + */ +SEC_RETURNS_RETAINED _Nullable sec_experiment_t +sec_experiment_create_with_inner_experiment(SecExperiment *experiment); + +/*! + * @function sec_experiment_run_internal + * + * @abstract + * Asynchronously run an experiment, optionally disabling sampling if desired. + * + * Note: This function MUST NOT be called outside of tests. + * + * @param experiment + * A `sec_experiment_t` to run. + * + * @param sampling_disabled + * Flag to disable sampling. + * + * @param queue + * Queue on which to run the experiment. + * + * @param run_block + * A `sec_experiment_run_block_t` block upon which to execute the given experiment. + * + * @param skip_block + * An optional `sec_experiment_skip_block_t` block that is invoked when the chosen experiment is skipped. + * + * @param synchronous + * A boolean indicating if the given experiment should be run synchronously (true) or asynchronously (false). + * + * @return True if the experiment was started, and false otherwise. + */ +bool +sec_experiment_run_internal(sec_experiment_t experiment, + bool sampling_disabled, + dispatch_queue_t _Nullable queue, + sec_experiment_run_block_t run_block, + sec_experiment_skip_block_t _Nullable skip_block, + bool synchronous); + +/*! +* @function sec_experiment_get_run_count +* +* @abstract +* Determine the number of times an experiment ran. +* +* @param experiment +* A `sec_experiment_t` instance. +* +* @return Number of times the experiment was run. +*/ +size_t +sec_experiment_get_run_count(sec_experiment_t experiment); + +/*! + * @function sec_experiment_get_successful_run_count + * + * @abstract + * Determine the number of times an experiment successfully ran. + * + * @param experiment + * A `sec_experiment_t` instance. + * + * @return Number of times the experiment was run successfully. +*/ +size_t +sec_experiment_get_successful_run_count(sec_experiment_t experiment); + +/*! + * @function sec_experiment_get_identifier + * + * @abstract + * Get the selected experiment identifier. + * + * @param experiment + * A `sec_experiment_t` instance. + * + * @return The internal experiment identifier, or NULL if one was not yet chosen. +*/ +const char * _Nullable +sec_experiment_get_identifier(sec_experiment_t experiment); + +SEC_ASSUME_NONNULL_END + +#endif /* SecExperimentInternal_h */ diff --git a/experiment/SecExperimentPriv.h b/experiment/SecExperimentPriv.h new file mode 100644 index 00000000..35f3b50e --- /dev/null +++ b/experiment/SecExperimentPriv.h @@ -0,0 +1,204 @@ +// +// SecExperimentPriv.h +// Security +// + +#ifndef SecExperiment_h +#define SecExperiment_h + +#include +#include + +#ifndef SEC_EXP_OBJECT_IMPL +SEC_OBJECT_DECL(sec_experiment); +#endif // !SEC_EXP_OBJECT_IMPL + +SEC_ASSUME_NONNULL_BEGIN + +extern const char *kSecExperimentTLSProbe; +extern const char *kSecExperimentDefaultsDomain; + +/*! + * @block sec_experiment_run_block_t + * + * @abstract A block to execute an experiment with a loggable identifier + * and configuration. `identifier` will be uniquely associated with + * `experiment_config` and should be used when measuring data. + * + * @param identifier + * Identifier for the experiment. + * + * @param experiment_config + * Configuration of this experiment. + * + * @return True if the experiment ran successfully, and false otherwise. + */ +typedef bool (^sec_experiment_run_block_t)(const char *identifier, xpc_object_t experiment_config); + +/*! + * @block sec_experiment_skip_block_t + * + * @abstract A block to execute when an experiment run is skipped. + * + * @param identifier + * Identifier for the experiment. + */ +typedef void (^sec_experiment_skip_block_t)(const char *identifier); + +/*! + * @function sec_experiment_run + * + * @abstract + * Asynchronously run an experiment. + * + * @param experiment_name + * Name of the experiment to run. + * + * @param run_block + * A `sec_experiment_run_block_t` block upon which to execute the given experiment. + * + * @param skip_block + * An optional `sec_experiment_skip_block_t` block that is invoked when the chosen experiment is skipped. + * + * @return True if the experiment was started, and false otherwise. + */ +API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)) +bool +sec_experiment_run(const char *experiment_name, + sec_experiment_run_block_t run_block, + sec_experiment_skip_block_t _Nullable skip_block); + +#define SEC_EXPERIMENT_HAS_ASYNC_WITH_SAMPLING_DISABLED 1 + +/*! + * @function sec_experiment_run_with_sampling_disabled + * + * @abstract + * Synchronously run an experiment and optionally disable sampling. Passing `true` to the `sampling_disabled` parameter + * will cause the experiment to always run. Clients typically SHOULD NOT do this unless running as part of test tools and utilities. + * + * @param experiment_name + * Name of the experiment to run. + * + * @param run_block + * A `sec_experiment_run_block_t` block upon which to execute the given experiment. + * + * @param skip_block + * An optional `sec_experiment_skip_block_t` block that is invoked when the chosen experiment is skipped. + * + * @param sampling_disabled + * A boolean indicating if sampling should be disabled for the given asynchronous experiment run. + */ +API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)) +bool +sec_experiment_run_with_sampling_disabled(const char *experiment_name, + sec_experiment_run_block_t run_block, + sec_experiment_skip_block_t _Nullable skip_block, + bool sampling_disabled); + +/*! + * @function sec_experiment_run_async + * + * @abstract + * Asynchronously run an experiment. + * + * @param experiment_name + * Name of the experiment to run. + * + * @param queue + * Queue on which to run the experiment. + * + * @param run_block + * A `sec_experiment_run_block_t` block upon which to execute the given experiment. + * + * @param skip_block + * An optional `sec_experiment_skip_block_t` block that is invoked when the chosen experiment is skipped. + */ +API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)) +bool +sec_experiment_run_async(const char *experiment_name, + dispatch_queue_t queue, + sec_experiment_run_block_t run_block, + sec_experiment_skip_block_t _Nullable skip_block); + +/*! + * @function sec_experiment_run_async + * + * @abstract + * Asynchronously run an experiment and optionally disable sampling. Passing `true` to the `sampling_disabled` parameter + * will cause the experiment to always run. Clients typically SHOULD NOT do this unless running as part of test tools and utilities. + * + * @param experiment_name + * Name of the experiment to run. + * + * @param queue + * Queue on which to run the experiment. + * + * @param run_block + * A `sec_experiment_run_block_t` block upon which to execute the given experiment. + * + * @param skip_block + * An optional `sec_experiment_skip_block_t` block that is invoked when the chosen experiment is skipped. + * + * @param sampling_disabled + * A boolean indicating if sampling should be disabled for the given asynchronous experiment run. + */ +API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)) +bool +sec_experiment_run_async_with_sampling_disabled(const char *experiment_name, + dispatch_queue_t queue, + sec_experiment_run_block_t run_block, + sec_experiment_skip_block_t _Nullable skip_block, + bool sampling_disabled); + +/*! + * @function sec_experiment_create + * + * @abstract + * Create an ARC-able `sec_experiment_t` instance + * + * @param experiment_name + * Name of the experiment. + * + * @return a `sec_experiment_t` instance. + */ +API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)) +SEC_RETURNS_RETAINED _Nullable sec_experiment_t +sec_experiment_create(const char *experiment_name); + +/*! + * @function sec_experiment_set_sampling_disabled + * + * @abstract + * Set a flag to disable experiment sampling. + * This function should only be used for testing purposes. + * + * @param experiment + * A `sec_experiment_t` instance. + * + * @param sampling_disabled + * A flag indicating if sampling should be disabled. + */ +API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)) +void +sec_experiment_set_sampling_disabled(sec_experiment_t experiment, + bool sampling_disabled); + +/*! + * @function sec_experiment_copy_configuration + * + * @abstract + * Returns the configuration dictionary associated with the given experiment. + * + * @param experiment + * A valid `sec_experiment_t` instance. + * + * @return xpc_object_t containing asset bundle, if client is not part of the experiment return NULL + */ +API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)) +SEC_RETURNS_RETAINED _Nullable xpc_object_t +sec_experiment_copy_configuration(sec_experiment_t experiment); + +SEC_ASSUME_NONNULL_END + +#endif // SecExperiment_h diff --git a/experiment/test/SecExperimentTests.m b/experiment/test/SecExperimentTests.m new file mode 100644 index 00000000..d53cd274 --- /dev/null +++ b/experiment/test/SecExperimentTests.m @@ -0,0 +1,358 @@ +// +// SecExperimentTests.m +// +// + +#import +#import +#import +#import +#import +#import "SecExperimentInternal.h" +#import "SecExperimentPriv.h" + +@interface SecExperimentTests : XCTestCase +@end + +@implementation SecExperimentTests + +- (NSDictionary *)copyRandomConfiguration +{ + const char *testKey = "test_defaults_experiment_key"; + const char *testValue = "test_value"; + NSString *testKeyString = [NSString stringWithUTF8String:testKey]; + NSString *testValueString = [NSString stringWithUTF8String:testValue]; + NSDictionary *testConfigData = @{testKeyString: testValueString}; + NSDictionary *testConfig = @{SecExperimentConfigurationKeyFleetSampleRate : @(100), + SecExperimentConfigurationKeyDeviceSampleRate : @(100), + SecExperimentConfigurationKeyExperimentIdentifier : @"identifier", + SecExperimentConfigurationKeyConfigurationData : testConfigData}; + return testConfig; +} + +- (void)testCopyFromDefaults { + const char *testKey = "test_defaults_experiment_key"; + const char *testValue = "test_value"; + NSString *testKeyString = [NSString stringWithUTF8String:testKey]; + NSString *testValueString = [NSString stringWithUTF8String:testValue]; + NSDictionary *testConfigData = @{testKeyString: testValueString}; + NSDictionary *testConfig = @{SecExperimentConfigurationKeyFleetSampleRate : @(100), + SecExperimentConfigurationKeyDeviceSampleRate : @(100), + SecExperimentConfigurationKeyExperimentIdentifier : @"identifier", + SecExperimentConfigurationKeyConfigurationData : testConfigData}; + + SecExperiment *mockExperiment = OCMPartialMock([[SecExperiment alloc] initWithName:kSecExperimentTLSProbe]); + OCMStub([mockExperiment copyExperimentConfigurationFromUserDefaults]).andReturn(testConfig); + sec_experiment_t experiment = sec_experiment_create_with_inner_experiment(mockExperiment); + + sec_experiment_set_sampling_disabled(experiment, true); + xpc_object_t actualConfig = sec_experiment_copy_configuration(experiment); + XCTAssertNotNil(actualConfig); + + xpc_type_t configType = xpc_get_type(actualConfig); + XCTAssertTrue(configType == XPC_TYPE_DICTIONARY); + + const char *actualValue = xpc_dictionary_get_string(actualConfig, testKey); + XCTAssertTrue(actualValue != NULL && strncmp(actualValue, testValue, strlen(testValue)) == 0); +} + +- (void)testInitializeWithIdentifier { + sec_experiment_t experiment = sec_experiment_create(kSecExperimentTLSProbe); + const char *identifier = sec_experiment_get_identifier(experiment); + XCTAssertTrue(identifier == NULL); +} + +- (void)testExperimentRunAsynchronously_SkipSampling { + dispatch_queue_t test_queue = dispatch_queue_create("test_queue", NULL); + + __block dispatch_semaphore_t blocker = dispatch_semaphore_create(0); + __block bool experiment_invoked = false; + sec_experiment_run_block_t run_block = ^bool(const char *identifier, xpc_object_t config) { + experiment_invoked = identifier != NULL && config != NULL; + dispatch_semaphore_signal(blocker); + return experiment_invoked; + }; + + NSDictionary *testConfig = [self copyRandomConfiguration]; + + SecExperiment *mockExperiment = OCMPartialMock([[SecExperiment alloc] initWithName:kSecExperimentTLSProbe]); + OCMStub([mockExperiment copyExperimentConfigurationFromUserDefaults]).andReturn(testConfig); + sec_experiment_t experiment = sec_experiment_create_with_inner_experiment(mockExperiment); + + sec_experiment_run_internal(experiment, true, test_queue, run_block, nil, false); + XCTAssertTrue(dispatch_semaphore_wait(blocker, dispatch_time(DISPATCH_TIME_NOW, (uint64_t)(5 * NSEC_PER_SEC))) == 0L); + XCTAssertTrue(experiment_invoked); +} + +- (void)testExperimentRun_SkipWithoutConfig { + SecExperiment *mockExperiment = OCMPartialMock([[SecExperiment alloc] initWithName:kSecExperimentTLSProbe]); + OCMStub([mockExperiment experimentIsAllowedForProcess]).andReturn(YES); + OCMStub([mockExperiment copyRemoteExperimentAsset]).andReturn(nil); + OCMStub([mockExperiment copyExperimentConfigurationFromUserDefaults]).andReturn(nil); + sec_experiment_t experiment = sec_experiment_create_with_inner_experiment(mockExperiment); + + dispatch_queue_t test_queue = dispatch_queue_create("test_queue", NULL); + __block bool run = false; + sec_experiment_run_block_t run_block = ^bool(__unused const char *identifier, __unused xpc_object_t config) { + run = true; + return true; + }; + __block BOOL skipped = false; + sec_experiment_skip_block_t skip_block = ^(__unused const char *identifier) { + skipped = true; + }; + + bool result = sec_experiment_run_internal(experiment, true, test_queue, run_block, skip_block, true); + XCTAssertTrue(result); + XCTAssertTrue(skipped); + XCTAssertFalse(run); +} + +- (void)testExperimentRunSuccess { + NSDictionary *testConfig = [self copyRandomConfiguration]; + + SecExperiment *mockExperiment = OCMPartialMock([[SecExperiment alloc] initWithName:kSecExperimentTLSProbe]); + OCMStub([mockExperiment isSamplingDisabled]).andReturn(YES); + OCMStub([mockExperiment experimentIsAllowedForProcess]).andReturn(YES); + OCMStub([mockExperiment copyRemoteExperimentAsset]).andReturn(testConfig); + OCMStub([mockExperiment copyExperimentConfigurationFromUserDefaults]).andReturn(nil); + OCMStub([mockExperiment copyRandomExperimentConfigurationFromAsset:[OCMArg any]]).andReturn(testConfig); + sec_experiment_t experiment = sec_experiment_create_with_inner_experiment(mockExperiment); + + dispatch_queue_t test_queue = dispatch_queue_create("test_queue", NULL); + __block bool run = false; + sec_experiment_run_block_t run_block = ^bool(__unused const char *identifier, __unused xpc_object_t config) { + run = true; + return true; // Signal that the experiment run was successful + }; + __block BOOL skipped = false; + sec_experiment_skip_block_t skip_block = ^(__unused const char *identifier) { + skipped = true; + }; + + bool result = sec_experiment_run_internal(experiment, true, test_queue, run_block, skip_block, true); + XCTAssertTrue(result); + XCTAssertFalse(skipped); + XCTAssertTrue(run); + XCTAssertTrue(sec_experiment_get_run_count(experiment) == 1); + XCTAssertTrue(sec_experiment_get_successful_run_count(experiment) == 1); +} + +- (void)testExperimentRunFailure { + NSDictionary *testConfig = [self copyRandomConfiguration]; + + SecExperiment *mockExperiment = OCMPartialMock([[SecExperiment alloc] initWithName:kSecExperimentTLSProbe]); + OCMStub([mockExperiment experimentIsAllowedForProcess]).andReturn(YES); + OCMStub([mockExperiment isSamplingDisabled]).andReturn(YES); + OCMStub([mockExperiment copyRemoteExperimentAsset]).andReturn(testConfig); + OCMStub([mockExperiment copyExperimentConfigurationFromUserDefaults]).andReturn(nil); + OCMStub([mockExperiment copyRandomExperimentConfigurationFromAsset:[OCMArg any]]).andReturn(testConfig); + sec_experiment_t experiment = sec_experiment_create_with_inner_experiment(mockExperiment); + + dispatch_queue_t test_queue = dispatch_queue_create("test_queue", NULL); + __block bool run = false; + sec_experiment_run_block_t run_block = ^bool(__unused const char *identifier, __unused xpc_object_t config) { + run = true; + return false; // Signal that the experiment run failed + }; + __block BOOL skipped = false; + sec_experiment_skip_block_t skip_block = ^(__unused const char *identifier) { + skipped = true; + }; + + bool result = sec_experiment_run_internal(experiment, true, test_queue, run_block, skip_block, true); + XCTAssertTrue(result); + XCTAssertFalse(skipped); + XCTAssertTrue(run); + XCTAssertTrue(sec_experiment_get_run_count(experiment) == 1); + XCTAssertTrue(sec_experiment_get_successful_run_count(experiment) == 0); +} + +- (void)testExperimentRun_SamplingEnabled_NotInFleet { + size_t fleetNumber = 10; + NSDictionary *testConfig = @{SecExperimentConfigurationKeyFleetSampleRate: @(fleetNumber), SecExperimentConfigurationKeyDeviceSampleRate : @(2)}; + + SecExperimentConfig *mockConfig = OCMPartialMock([[SecExperimentConfig alloc] initWithConfiguration:testConfig]); + OCMStub([mockConfig hostHash]).andReturn(fleetNumber + 1); // Ensure that fleetNumber < hostHash + + SecExperiment *mockExperiment = OCMPartialMock([[SecExperiment alloc] initWithName:kSecExperimentTLSProbe]); + OCMStub([mockExperiment experimentIsAllowedForProcess]).andReturn(YES); + OCMStub([mockExperiment isSamplingDisabled]).andReturn(NO); + OCMStub([mockExperiment copyExperimentConfiguration]).andReturn(mockConfig); + + sec_experiment_t experiment = sec_experiment_create_with_inner_experiment(mockExperiment); + + dispatch_queue_t test_queue = dispatch_queue_create("test_queue", NULL); + __block bool run = false; + sec_experiment_run_block_t run_block = ^bool(__unused const char *identifier, __unused xpc_object_t config) { + run = true; + return false; // Signal that the experiment run failed + }; + __block BOOL skipped = false; + sec_experiment_skip_block_t skip_block = ^(__unused const char *identifier) { + skipped = true; + }; + + bool result = sec_experiment_run_internal(experiment, true, test_queue, run_block, skip_block, true); + XCTAssertTrue(result); + XCTAssertTrue(skipped); + XCTAssertFalse(run); + XCTAssertTrue(sec_experiment_get_run_count(experiment) == 0); + XCTAssertTrue(sec_experiment_get_successful_run_count(experiment) == 0); +} + +- (void)testExperimentRun_SamplingEnabled_InFleetNotInSample { + size_t fleetNumber = 10; + NSDictionary *testConfig = @{SecExperimentConfigurationKeyFleetSampleRate: @(fleetNumber), SecExperimentConfigurationKeyDeviceSampleRate : @(2)}; + + SecExperimentConfig *mockConfig = OCMPartialMock([[SecExperimentConfig alloc] initWithConfiguration:testConfig]); + OCMStub([mockConfig hostHash]).andReturn(fleetNumber - 1); // Ensure that fleetNumber > hostHash + OCMStub([mockConfig shouldRunWithSamplingRate:[OCMArg any]]).andReturn(NO); // Determine that we're not in the fleet + + SecExperiment *mockExperiment = OCMPartialMock([[SecExperiment alloc] initWithName:kSecExperimentTLSProbe]); + OCMStub([mockExperiment experimentIsAllowedForProcess]).andReturn(YES); + OCMStub([mockExperiment isSamplingDisabled]).andReturn(NO); + OCMStub([mockExperiment copyExperimentConfiguration]).andReturn(mockConfig); + + sec_experiment_t experiment = sec_experiment_create_with_inner_experiment(mockExperiment); + + dispatch_queue_t test_queue = dispatch_queue_create("test_queue", NULL); + __block bool run = false; + sec_experiment_run_block_t run_block = ^bool(__unused const char *identifier, __unused xpc_object_t config) { + run = true; + return false; // Signal that the experiment run failed + }; + __block BOOL skipped = false; + sec_experiment_skip_block_t skip_block = ^(__unused const char *identifier) { + skipped = true; + }; + + bool result = sec_experiment_run_internal(experiment, true, test_queue, run_block, skip_block, true); + XCTAssertTrue(result); + XCTAssertTrue(skipped); + XCTAssertFalse(run); + XCTAssertTrue(sec_experiment_get_run_count(experiment) == 0); + XCTAssertTrue(sec_experiment_get_successful_run_count(experiment) == 0); +} + +- (void)testExperimentRun_DisallowedProcess { + SecExperiment *mockExperiment = OCMPartialMock([[SecExperiment alloc] initWithName:kSecExperimentTLSProbe]); + OCMStub([mockExperiment experimentIsAllowedForProcess]).andReturn(NO); + sec_experiment_t experiment = sec_experiment_create_with_inner_experiment(mockExperiment); + + dispatch_queue_t test_queue = dispatch_queue_create("test_queue", NULL); + sec_experiment_run_block_t run_block = ^bool(__unused const char *identifier, __unused xpc_object_t config) { + return true; + }; + + bool result = sec_experiment_run_internal(experiment, true, test_queue, run_block, nil, false); + XCTAssertFalse(result); +} + +- (void)testExperimentRunSynchronously_SkipSampling { + dispatch_queue_t test_queue = dispatch_queue_create("test_queue", NULL); + + __block bool experiment_invoked = false; + sec_experiment_run_block_t run_block = ^bool(const char *identifier, xpc_object_t config) { + experiment_invoked = identifier != NULL && config != NULL; + return experiment_invoked; + }; + + NSDictionary *testConfig = [self copyRandomConfiguration]; + + SecExperiment *mockExperiment = OCMPartialMock([[SecExperiment alloc] initWithName:kSecExperimentTLSProbe]); + OCMStub([mockExperiment copyExperimentConfigurationFromUserDefaults]).andReturn(testConfig); + sec_experiment_t experiment = sec_experiment_create_with_inner_experiment(mockExperiment); + + sec_experiment_run_internal(experiment, true, test_queue, run_block, nil, true); + XCTAssertTrue(experiment_invoked); +} + +- (void)testDefaultsConfigCopy { + const char *testKey = "test_defaults_experiment_key"; + const char *testValue = "test_value"; + NSString *testKeyString = [NSString stringWithUTF8String:testKey]; + NSString *testValueString = [NSString stringWithUTF8String:testValue]; + NSDictionary *testConfigData = @{testKeyString: testValueString}; + NSString *experimentName = @"TestExperiment"; + NSDictionary *testConfig = @{experimentName: @{SecExperimentConfigurationKeyFleetSampleRate : @(100), + SecExperimentConfigurationKeyDeviceSampleRate : @(100), + SecExperimentConfigurationKeyExperimentIdentifier : @"identifier", + SecExperimentConfigurationKeyConfigurationData : testConfigData}}; + + sec_experiment_t experiment = sec_experiment_create([experimentName UTF8String]); + XCTAssert(experiment, @"sec_experiment_create"); + + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + [defaults setPersistentDomain:testConfig forName:[NSString stringWithUTF8String:kSecExperimentDefaultsDomain]]; + + sec_experiment_set_sampling_disabled(experiment, true); + xpc_object_t tlsconfig = sec_experiment_copy_configuration(experiment); + XCTAssertNotNil(tlsconfig); + if (tlsconfig) { + XCTAssertTrue(xpc_get_type(tlsconfig) == XPC_TYPE_DICTIONARY); + if (xpc_get_type(tlsconfig) == XPC_TYPE_DICTIONARY) { + const char *actualValue = xpc_dictionary_get_string(tlsconfig, testKey); + XCTAssertTrue(actualValue != NULL); + if (actualValue != NULL) { + XCTAssertTrue(strcmp(actualValue, testValue) == 0); + } + } + } + + // Clear the persistent domain + [defaults removePersistentDomainForName:[NSString stringWithUTF8String:kSecExperimentDefaultsDomain]]; +} + +- (void)testRunWithIdentifier { + const char *testKey = "test_defaults_experiment_key"; + const char *testValue = "test_value"; + NSString *testKeyString = [NSString stringWithUTF8String:testKey]; + NSString *testValueString = [NSString stringWithUTF8String:testValue]; + NSDictionary *testConfigData = @{testKeyString: testValueString}; + NSString *experimentName = @"TestExperiment"; + NSString *identifierName = @"ExperimentIdentifier"; + NSDictionary *testConfig = @{experimentName: @{SecExperimentConfigurationKeyFleetSampleRate : @(100), + SecExperimentConfigurationKeyDeviceSampleRate : @(100), + SecExperimentConfigurationKeyExperimentIdentifier : identifierName, + SecExperimentConfigurationKeyConfigurationData : testConfigData}}; + + SecExperiment *mockExperiment = OCMPartialMock([[SecExperiment alloc] initWithName:[experimentName UTF8String]]); + OCMStub([mockExperiment copyExperimentConfigurationFromUserDefaults]).andReturn(testConfig); + sec_experiment_t experiment = sec_experiment_create_with_inner_experiment(mockExperiment); + + sec_experiment_run_internal(experiment, true, nil, ^bool(const char * _Nonnull identifier, xpc_object_t _Nonnull experiment_config) { + XCTAssertTrue(identifier != NULL); + if (identifier != NULL) { + XCTAssertTrue(strcmp([identifierName UTF8String], identifier) == 0); + } + }, ^(const char * _Nonnull identifier) { + XCTAssertFalse(true); + }, true); +} + +- (void)testGeneration { + nw_protocol_options_t tls_options = nw_tls_create_options(); + sec_protocol_options_t sec_options = nw_tls_copy_sec_protocol_options(tls_options); + + sec_protocol_options_set_tls_grease_enabled(sec_options, true); + xpc_object_t config = sec_protocol_options_create_config(sec_options); + + xpc_dictionary_apply(config, ^bool(const char * _Nonnull key, xpc_object_t _Nonnull value) { + if (xpc_get_type(value) == XPC_TYPE_BOOL) { + NSLog(@"%s -> %d", key, xpc_bool_get_value(value)); + } else if (xpc_get_type(value) == XPC_TYPE_UINT64) { + NSLog(@"%s -> %zu", key, (size_t)xpc_uint64_get_value(value)); + } else { + NSLog(@"%s -> %d", key, (int)xpc_get_type(value)); + } + + return true; + }); + + CFDictionaryRef config_dictionary = _CFXPCCreateCFObjectFromXPCObject(config); + XCTAssertTrue(config_dictionary != NULL); + NSLog(@"%@", (__bridge NSDictionary *)config_dictionary); +} + +@end diff --git a/experiment/tool/experimentTool-Entitlements.plist b/experiment/tool/experimentTool-Entitlements.plist new file mode 100644 index 00000000..0c67376e --- /dev/null +++ b/experiment/tool/experimentTool-Entitlements.plist @@ -0,0 +1,5 @@ + + + + + diff --git a/experiment/tool/experimentTool.m b/experiment/tool/experimentTool.m new file mode 100644 index 00000000..e08c385d --- /dev/null +++ b/experiment/tool/experimentTool.m @@ -0,0 +1,133 @@ +// +// experimentTool.m +// experimentTool +// + +#import +#import +#import +#import +#import + +static NSString *kExperimentRunResultKeySkips = @"Skips"; +static NSString *kExperimentRunResultKeyConfigurations = @"Configurations"; +static NSString *kExperimentRunResultKeyRuns = @"Runs"; + +static NSDictionary * +run_experiment(const char *experiment_name, size_t num_runs, bool sampling_disabled) +{ + __block size_t runs = 0; + __block size_t skips = 0; + __block NSMutableArray *configurations = [[NSMutableArray alloc] init]; + for (size_t i = 0; i < num_runs; i++) { + (void)sec_experiment_run_with_sampling_disabled(experiment_name, ^bool(const char *identifier, xpc_object_t experiment_config) { + runs++; + CFDictionaryRef configuration = (CFDictionaryRef)_CFXPCCreateCFObjectFromXPCObject(experiment_config); + if (configuration != NULL) { + [configurations addObject:(__bridge NSDictionary *)configuration]; + } + return true; + }, ^(const char * _Nonnull identifier) { + skips++; + }, sampling_disabled); + } + + return @{kExperimentRunResultKeyRuns: @(runs), + kExperimentRunResultKeySkips: @(skips), + kExperimentRunResultKeyConfigurations: configurations, + }; +} + +static void +usage(const char *argv[]) +{ + fprintf(stderr, "Usage: %s [-h] [-s] [-e ] [-n ]\n", argv[0]); +} + +int +main(int argc, const char *argv[]) +{ + BOOL showUsage = NO; + int arg = 0; + char * const *gargv = (char * const *)argv; + char *experiment_name = NULL; + size_t num_runs = 0; + bool sampling_disabled = true; + bool update_asset = false; + bool read_asset = false; + while ((arg = getopt(argc, gargv, "e:n:sruh")) != -1) { + switch (arg) { + case 'e': + experiment_name = strdup(optarg); + break; + case 'n': + num_runs = (size_t)atoi(optarg); + break; + case 's': + sampling_disabled = false; + break; + case 'r': + read_asset = true; + break; + case 'u': + update_asset = true; + break; + case 'h': + showUsage = YES; + break; + default: + fprintf(stderr, "%s: FAILURE: unknown option \"%c\"\n", argv[0], arg); + return -1; + } + } + + if (optind != argc) { + fprintf(stderr, "%s: FAILURE: argument missing parameter \"%c\"\n", argv[0], arg); + free(experiment_name); + return -2; + } + + if (showUsage) { + usage(argv); + free(experiment_name); + return EXIT_SUCCESS; + } + + uint64_t version = 0; + if (update_asset) { + CFErrorRef update_error = NULL; + version = SecTrustOTASecExperimentGetUpdatedAsset(&update_error); + if (update_error != NULL) { + NSLog(@"Failed to fetch latest asset: %@", (__bridge NSError *)update_error); + free(experiment_name); + return -3; + } else { + NSLog(@"Fetched asset version: %zu", (size_t)version); + } + } + + if (read_asset) { + CFErrorRef copy_error = NULL; + NSDictionary *asset = CFBridgingRelease(SecTrustOTASecExperimentCopyAsset(©_error)); + if (copy_error != NULL) { + NSLog(@"Failed to copy asset: %@", copy_error); + free(experiment_name); + return -4; + } else { + NSLog(@"Copied asset: %@", asset); + } + } + + if (num_runs > 0) { + NSLog(@"Running %zu experiments with asset verison %llu", num_runs, version); + NSDictionary *results = run_experiment(experiment_name, num_runs, sampling_disabled); + [results enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSObject * _Nonnull obj, BOOL * _Nonnull stop) { + NSLog(@"Experiment %@: %@", key, obj); + }]; + } else { + NSLog(@"Not running experiment."); + } + + free(experiment_name); + return EXIT_SUCCESS; +} diff --git a/keychain/SecureObjectSync/SOSAccount.h b/keychain/SecureObjectSync/SOSAccount.h index 9fed6f2f..a50be3ee 100644 --- a/keychain/SecureObjectSync/SOSAccount.h +++ b/keychain/SecureObjectSync/SOSAccount.h @@ -169,6 +169,9 @@ CF_RETURNS_RETAINED CFMutableSetRef SOSAccountSyncWithPeers(SOSAccountTransactio CFSetRef SOSAccountSyncWithPeersOverKVS(SOSAccountTransaction* txn, CFSetRef peers); bool SOSAccountInflateTransports(SOSAccount* account, CFStringRef circleName, CFErrorRef *error); +void +SOSAccountTriggerSyncWithBackupPeer(CFStringRef peer); + // // MARK: Outgoing/Sync functions // diff --git a/keychain/SecureObjectSync/SOSAccount.m b/keychain/SecureObjectSync/SOSAccount.m index 41035e2f..cd5951a2 100644 --- a/keychain/SecureObjectSync/SOSAccount.m +++ b/keychain/SecureObjectSync/SOSAccount.m @@ -31,7 +31,6 @@ #import "keychain/SecureObjectSync/SOSControlHelper.h" #import "keychain/SecureObjectSync/SOSAuthKitHelpers.h" - #import "keychain/SecureObjectSync/SOSAccountTrust.h" #import "keychain/SecureObjectSync/SOSAccountTrustClassic.h" #import "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h" @@ -44,19 +43,28 @@ #if OCTAGON #import "keychain/ckks/CKKSViewManager.h" #import "keychain/ckks/CKKSLockStateTracker.h" +#import "keychain/ckks/CKKSNearFutureScheduler.h" +#import "keychain/ckks/CKKSPBFileStorage.h" + #import "keychain/ot/OTManager.h" +#import "keychain/ot/ObjCImprovements.h" +#import "keychain/ot/OctagonStateMachine.h" +#import "keychain/ot/OctagonStateMachineHelpers.h" #endif #include #include -#include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h" #include "keychain/securityd/SecItemServer.h" +#include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h" +#include "keychain/SecureObjectSync/generated_source/SOSAccountConfiguration.h" + #import "SecdWatchdog.h" #include #include #include +#include #include #include @@ -67,6 +75,7 @@ #include #include + const CFStringRef kSOSAccountName = CFSTR("AccountName"); const CFStringRef kSOSEscrowRecord = CFSTR("EscrowRecord"); const CFStringRef kSOSUnsyncedViewsKey = CFSTR("unsynced"); @@ -94,62 +103,32 @@ const uint64_t max_packet_size_over_idms = 500; #define DATE_LENGTH 25 const CFStringRef kSOSAccountDebugScope = CFSTR("Scope"); -@implementation SOSAccount - -// Auto synthesis for most fields works great. -// A few CF fields need retention work when assigning. - --(id) init -{ - self = [super init]; - if(self){ - self.gestalt = [NSMutableDictionary dictionary]; - self.backup_key = nil; - self.deviceID = nil; - - self.trust = [SOSAccountTrustClassic trustClassic]; - - self.queue = NULL; - self.user_private_timer = NULL; - self.factory = NULL; - - self._password_tmp = nil; - self.isListeningForSync = false; - self.lock_notification_token = -1; - - self.circle_transport = NULL; - - self.circle_rings_retirements_need_attention = false; - self.engine_peer_state_needs_repair = false; - self.key_interests_need_updating = false; - - self.change_blocks = [NSMutableArray array]; +#if OCTAGON +static NSDictionary* SOSStateMap(void); - self.waitForInitialSync_blocks = [NSMutableDictionary dictionary]; - - self.accountKeyIsTrusted = false; - self.accountKeyDerivationParamters = nil; +@interface SOSAccount () +@property dispatch_queue_t stateMachineQueue; +@property (readwrite) OctagonStateMachine* stateMachine; - self.accountKey = NULL; - self.accountPrivateKey = NULL; - self.previousAccountKey = NULL; - - self.saveBlock = nil; +@property (readwrite) CKKSPBFileStorage* accountConfiguration; - self.notifyCircleChangeOnExit = false; - self.notifyViewChangeOnExit = false; - self.notifyBackupOnExit = false; +@property CKKSNearFutureScheduler *performBackups; +@property CKKSNearFutureScheduler *performRingUpdates; +@end +#endif - self.settings = [[NSUserDefaults alloc] initWithSuiteName:SOSAccountUserDefaultsSuite]; - } - return self; -} +@implementation SOSAccount - (void)dealloc { if(self) { CFReleaseNull(self->_accountKey); CFReleaseNull(self->_accountPrivateKey); CFReleaseNull(self->_previousAccountKey); +#if OCTAGON + [self.performBackups cancel]; + [self.performRingUpdates cancel]; + [self.stateMachine haltOperation]; +#endif } } @@ -191,16 +170,11 @@ const CFStringRef kSOSAccountDebugScope = CFSTR("Scope"); -(bool) ensureFactoryCircles { - if (!self){ + if (self.factory == nil){ return false; } - if (!self.factory){ - return false; - } - - NSString* circle_name = (__bridge_transfer NSString*)SOSDataSourceFactoryCopyName(self.factory); - + NSString* circle_name = CFBridgingRelease(SOSDataSourceFactoryCopyName(self.factory)); if (!circle_name){ return false; } @@ -241,7 +215,6 @@ const CFStringRef kSOSAccountDebugScope = CFSTR("Scope"); self.lock_notification_token = NOTIFY_TOKEN_INVALID; self.change_blocks = [NSMutableArray array]; - self.waitForInitialSync_blocks = NULL; self.key_transport = nil; self.circle_transport = NULL; @@ -262,10 +235,26 @@ const CFStringRef kSOSAccountDebugScope = CFSTR("Scope"); self.previousAccountKey = NULL; self.saveBlock = nil; + + self.settings = [[NSUserDefaults alloc] initWithSuiteName:SOSAccountUserDefaultsSuite]; + + [self ensureFactoryCircles]; + SOSAccountEnsureUUID(self); + +#if OCTAGON + [self setupStateMachine]; +#endif } return self; } +- (void)startStateMachine +{ +#if OCTAGON + [self.stateMachine startOperation]; +#endif +} + -(BOOL)isEqual:(id) object { if(![object isKindOfClass:[SOSAccount class]]) @@ -737,7 +726,7 @@ static bool Flush(CFErrorRef *error) { CFReleaseNull(error); } -- (void)triggerSync:(NSArray *)peers complete:(void(^)(bool success, NSError *))complete +- (void)rpcTriggerSync:(NSArray *)peers complete:(void(^)(bool success, NSError *))complete { __block CFErrorRef localError = NULL; __block bool res = false; @@ -762,6 +751,31 @@ static bool Flush(CFErrorRef *error) { CFReleaseNull(localError); } +- (void)rpcTriggerBackup:(NSArray* _Nullable)backupPeers complete:(void (^)(NSError *error))complete +{ + __block CFErrorRef localError = NULL; + + if (backupPeers.count == 0) { + SOSEngineRef engine = (SOSEngineRef) [self.kvs_message_transport SOSTransportMessageGetEngine]; + backupPeers = CFBridgingRelease(SOSEngineCopyBackupPeerNames(engine, &localError)); + } + +#if OCTAGON + [self triggerBackupForPeers:backupPeers]; +#endif + + complete((__bridge NSError *)localError); + CFReleaseNull(localError); +} + +- (void)rpcTriggerRingUpdate:(void (^)(NSError *error))complete +{ +#if OCTAGON + [self triggerRingUpdate]; +#endif + complete(NULL); +} + - (void)getWatchdogParameters:(void (^)(NSDictionary* parameters, NSError* error))complete { // SecdWatchdog is only available in the secd/securityd - no other binary will contain that class @@ -867,10 +881,10 @@ SOSAccount* SOSAccountCreate(CFAllocatorRef allocator, SOSDataSourceFactoryRef factory) { SOSAccount* a = [[SOSAccount alloc] initWithGestalt:gestalt factory:factory]; - [a ensureFactoryCircles]; - SOSAccountEnsureUUID(a); - secnotice("circleop", "Setting account.key_interests_need_updating to true in SOSAccountCreate"); - a.key_interests_need_updating = true; + dispatch_sync(a.queue, ^{ + secnotice("circleop", "Setting account.key_interests_need_updating to true in SOSAccountCreate"); + a.key_interests_need_updating = true; + }); return a; } @@ -1421,26 +1435,28 @@ bool SOSAccountRemoveIncompleteiCloudIdentities(SOSAccount* account, SOSCircleR // -bool SOSAccountEnsureInBackupRings(SOSAccount* account) { +- (bool)_onQueueEnsureInBackupRings { __block bool result = false; __block CFErrorRef error = NULL; secnotice("backup", "Ensuring in rings"); - if(!account.backup_key){ + dispatch_assert_queue(self.queue); + + if(!self.backup_key){ return true; } - if(!SOSBSKBIsGoodBackupPublic((__bridge CFDataRef)account.backup_key, &error)){ + if(!SOSBSKBIsGoodBackupPublic((__bridge CFDataRef)self.backup_key, &error)){ secnotice("backupkey", "account backup key isn't valid: %@", error); - account.backup_key = nil; + self.backup_key = nil; CFReleaseNull(error); return false; } - NSData *peerBackupKey = (__bridge_transfer NSData*)SOSPeerInfoCopyBackupKey(account.peerInfo); - if(![peerBackupKey isEqual:account.backup_key]) { - result = SOSAccountUpdatePeerInfo(account, CFSTR("Backup public key"), &error, ^bool(SOSFullPeerInfoRef fpi, CFErrorRef *error) { - return SOSFullPeerInfoUpdateBackupKey(fpi, (__bridge CFDataRef)(account.backup_key), error); + NSData *peerBackupKey = (__bridge_transfer NSData*)SOSPeerInfoCopyBackupKey(self.peerInfo); + if(![peerBackupKey isEqual:self.backup_key]) { + result = SOSAccountUpdatePeerInfo(self, CFSTR("Backup public key"), &error, ^bool(SOSFullPeerInfoRef fpi, CFErrorRef *error) { + return SOSFullPeerInfoUpdateBackupKey(fpi, (__bridge CFDataRef)(self.backup_key), error); }); if (!result) { secnotice("backupkey", "Failed to setup backup public key in peerInfo from account: %@", error); @@ -1457,12 +1473,12 @@ bool SOSAccountEnsureInBackupRings(SOSAccount* account) { CFReleaseNull(localError); // Setup backups the new way. - SOSAccountForEachBackupView(account, ^(const void *value) { + SOSAccountForEachBackupView(self, ^(const void *value) { CFStringRef viewName = asString(value, NULL); - bool resetRing = SOSAccountValidateBackupRingForView(account, viewName, NULL); + bool resetRing = SOSAccountValidateBackupRingForView(self, viewName, NULL); if(resetRing) { - SOSAccountUpdateBackupRing(account, viewName, NULL, ^SOSRingRef(SOSRingRef existing, CFErrorRef *error) { - SOSRingRef newRing = SOSAccountCreateBackupRingForView(account, viewName, error); + SOSAccountUpdateBackupRing(self, viewName, NULL, ^SOSRingRef(SOSRingRef existing, CFErrorRef *error) { + SOSRingRef newRing = SOSAccountCreateBackupRingForView(self, viewName, error); return newRing; }); } @@ -1993,7 +2009,7 @@ bool SOSAccountEnsurePeerRegistration(SOSAccount* account, CFErrorRef *error) { SOSEngineInitializePeerCoder((SOSEngineRef)[account.kvs_message_transport SOSTransportMessageGetEngine], trust.fullPeerInfo, peer, &localError); if (localError) secnotice("updates", "can't initialize transport for peer %@ with %@ (%@)", peer, trust.fullPeerInfo, localError); - CFReleaseSafe(localError); + CFReleaseNull(localError); } }); @@ -2043,13 +2059,16 @@ bool SOSAccountAddEscrowToPeerInfo(SOSAccount* account, SOSFullPeerInfoRef myPe return success; } -void SOSAccountRecordRetiredPeersInCircle(SOSAccount* account) { - if (![account isInCircle:NULL]) { +- (void)_onQueueRecordRetiredPeersInCircle { + + dispatch_assert_queue(self.queue); + + if (![self isInCircle:NULL]) { return; } __block bool updateRings = false; - SOSAccountTrustClassic *trust = account.trust; - [trust modifyCircle:account.circle_transport err:NULL action:^bool (SOSCircleRef circle) { + SOSAccountTrustClassic *trust = self.trust; + [trust modifyCircle:self.circle_transport err:NULL action:^bool (SOSCircleRef circle) { __block bool updated = false; CFSetForEach((__bridge CFMutableSetRef)trust.retirees, ^(CFTypeRef element){ SOSPeerInfoRef retiree = asSOSPeerInfo(element); @@ -2058,7 +2077,7 @@ void SOSAccountRecordRetiredPeersInCircle(SOSAccount* account) { updated = true; secnotice("retirement", "Updated retired peer %@ in %@", retiree, circle); CFErrorRef cleanupError = NULL; - if (![account.trust cleanupAfterPeer:account.kvs_message_transport circleTransport:account.circle_transport seconds:RETIREMENT_FINALIZATION_SECONDS circle:circle cleanupPeer:retiree err:&cleanupError]) + if (![self.trust cleanupAfterPeer:self.kvs_message_transport circleTransport:self.circle_transport seconds:RETIREMENT_FINALIZATION_SECONDS circle:circle cleanupPeer:retiree err:&cleanupError]) secerror("Error cleanup up after peer (%@): %@", retiree, cleanupError); CFReleaseSafe(cleanupError); updateRings = true; @@ -2067,7 +2086,7 @@ void SOSAccountRecordRetiredPeersInCircle(SOSAccount* account) { return updated; }]; if(updateRings) { - SOSAccountProcessBackupRings(account, NULL); + SOSAccountProcessBackupRings(self, NULL); } } @@ -2900,6 +2919,258 @@ void SOSAccountTimerFiredSendNextMessage(SOSAccountTransaction* txn, NSString* p CFReleaseNull(error); } +#if OCTAGON + +/* + * State machine + */ + +OctagonFlag* SOSFlagTriggerBackup = (OctagonFlag*)@"trigger_backup"; +OctagonFlag* SOSFlagTriggerRingUpdate = (OctagonFlag*)@"trigger_ring_update"; + +OctagonState* SOSStateReady = (OctagonState*)@"ready"; +OctagonState* SOSStateError = (OctagonState*)@"error"; +OctagonState* SOSStatePerformBackup = (OctagonState*)@"perform_backup"; +OctagonState* SOSStatePerformRingUpdate = (OctagonState*)@"perform_ring_update"; + +static NSDictionary* SOSStateMap(void) { + static NSDictionary* map = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + map = @{ + SOSStateReady: @0U, + SOSStateError: @1U, + SOSStatePerformBackup: @2U, + SOSStatePerformRingUpdate: @3U, + }; + }); + return map; +} + +static NSSet* SOSFlagsSet(void) { + static NSSet* set = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + set = [NSSet setWithArray:@[ + SOSFlagTriggerBackup, + SOSFlagTriggerRingUpdate, + ]]; + }); + return set; +} + + + ++ (NSURL *)urlForSOSAccountSettings { + return (__bridge NSURL *)SecCopyURLForFileInKeychainDirectory(CFSTR("SOSAccountSettings.pb")); +} + + +- (void)setupStateMachine { + WEAKIFY(self); + + self.accountConfiguration = [[CKKSPBFileStorage alloc] initWithStoragePath:[[self class] urlForSOSAccountSettings] + storageClass:[SOSAccountConfiguration class]]; + + NSAssert(self.stateMachine == nil, @"cant bootstrap more the once"); + + self.stateMachineQueue = dispatch_queue_create("SOS-statemachine", NULL); + + self.stateMachine = [[OctagonStateMachine alloc] initWithName:@"sosaccount" + states:[NSSet setWithArray:[SOSStateMap() allKeys]] + flags:SOSFlagsSet() + initialState:SOSStateReady + queue:self.stateMachineQueue + stateEngine:self + lockStateTracker:[CKKSLockStateTracker globalTracker]]; + + + self.performBackups = [[CKKSNearFutureScheduler alloc] initWithName:@"performBackups" + initialDelay:5*NSEC_PER_SEC + continuingDelay:30*NSEC_PER_SEC + keepProcessAlive:YES + dependencyDescriptionCode:CKKSResultDescriptionNone + block:^{ + STRONGIFY(self); + [self addBackupFlag]; + }]; + + self.performRingUpdates = [[CKKSNearFutureScheduler alloc] initWithName:@"performRingUpdates" + initialDelay:5*NSEC_PER_SEC + expontialBackoff:2.0 + maximumDelay:15*60*NSEC_PER_SEC + keepProcessAlive:YES + dependencyDescriptionCode:CKKSResultDescriptionNone + block:^{ + STRONGIFY(self); + [self addRingUpdateFlag]; + }]; + + SOSAccountConfiguration *conf = self.accountConfiguration.storage; + + if (conf.pendingBackupPeers.count) { + [self addBackupFlag]; + } + if (conf.ringUpdateFlag) { + [self addRingUpdateFlag]; + } +} + + +/* + * Flag adding to state machine + */ + +- (void)addBackupFlag { + OctagonPendingFlag *pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:SOSFlagTriggerBackup + conditions:OctagonPendingConditionsDeviceUnlocked]; + [self.stateMachine handlePendingFlag:pendingFlag]; +} + +- (void)addRingUpdateFlag { + OctagonPendingFlag *pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:SOSFlagTriggerRingUpdate + conditions:OctagonPendingConditionsDeviceUnlocked]; + [self.stateMachine handlePendingFlag:pendingFlag]; +} + +//Mark: -- Set up state for state machine + + +- (void)triggerBackupForPeers:(NSArray*)backupPeers +{ + NSMutableSet *pending = [NSMutableSet set]; + if (backupPeers) { + [pending addObjectsFromArray:backupPeers]; + } + + WEAKIFY(self); + dispatch_async(self.stateMachineQueue, ^{ + STRONGIFY(self); + + SOSAccountConfiguration *storage = self.accountConfiguration.storage; + + if (storage.pendingBackupPeers) { + [pending addObjectsFromArray:storage.pendingBackupPeers]; + } + storage.pendingBackupPeers = [[pending allObjects] mutableCopy]; + [self.accountConfiguration setStorage:storage]; + [self.performBackups trigger]; + secnotice("sos-sm", "trigger backup for peers: %@ at %@", + backupPeers, self.performBackups.nextFireTime); + }); +} + +- (void)triggerRingUpdate +{ + + WEAKIFY(self); + dispatch_async(self.stateMachineQueue, ^{ + STRONGIFY(self); + SOSAccountConfiguration *storage = self.accountConfiguration.storage; + storage.ringUpdateFlag = YES; + [self.accountConfiguration setStorage:storage]; + [self.performRingUpdates trigger]; + secnotice("sos-sm", "trigger ring update at %@", + self.performRingUpdates.nextFireTime); + }); +} + +//Mark: -- State machine and opertions + +- (OctagonStateTransitionOperation *)performBackup { + + WEAKIFY(self); + return [OctagonStateTransitionOperation named:@"perform-backup-state" + intending:SOSStateReady + errorState:SOSStateError + withBlockTakingSelf:^void(OctagonStateTransitionOperation * _Nonnull op) { + STRONGIFY(self); + SOSAccountConfiguration *storage = self.accountConfiguration.storage; + + secnotice("sos-sm", "performing backup for %@", storage.pendingBackupPeers); + + if (storage.pendingBackupPeers.count) { + SOSCCRequestSyncWithBackupPeerList((__bridge CFArrayRef)storage.pendingBackupPeers); + [storage clearPendingBackupPeers]; + } + [self.accountConfiguration setStorage:storage]; + + op.nextState = SOSStateReady; + }]; +} + +- (OctagonStateTransitionOperation *)performRingUpdate { + + WEAKIFY(self); + return [OctagonStateTransitionOperation named:@"perform-ring-update" + intending:SOSStateReady + errorState:SOSStateError + withBlockTakingSelf:^void(OctagonStateTransitionOperation * _Nonnull op) { + STRONGIFY(self); + + SOSAccountConfiguration *storage = self.accountConfiguration.storage; + storage.ringUpdateFlag = NO; + [self.accountConfiguration setStorage:storage]; + + [self performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + + [self _onQueueRecordRetiredPeersInCircle]; + + SOSAccountEnsureRecoveryRing(self); + [self _onQueueEnsureInBackupRings]; + + CFErrorRef localError = NULL; + if(![self.circle_transport flushChanges:&localError]){ + secerror("flush circle failed %@", localError); + } + CFReleaseNull(localError); + + if(!SecCKKSTestDisableSOS()) { + SOSAccountNotifyEngines(self); + } + }]; + + op.nextState = SOSStateReady; + }]; + +} + + +- (CKKSResultOperation* _Nullable)_onqueueNextStateMachineTransition:(OctagonState*)currentState + flags:(nonnull OctagonFlags *)flags + pendingFlags:(nonnull id)pendingFlagHandler +{ + dispatch_assert_queue(self.stateMachineQueue); + + secnotice("sos-sm", "Entering state: %@ [flags: %@]", currentState, flags); + + if ([currentState isEqualToString:SOSStateReady]) { + if([flags _onqueueContains:SOSFlagTriggerBackup]) { + [flags _onqueueRemoveFlag:SOSFlagTriggerBackup]; + return [OctagonStateTransitionOperation named:@"perform-backup-flag" + entering:SOSStatePerformBackup]; + } + + if ([flags _onqueueContains:SOSFlagTriggerRingUpdate]) { + [flags _onqueueRemoveFlag:SOSFlagTriggerRingUpdate]; + return [OctagonStateTransitionOperation named:@"perform-ring-update-flag" + entering:SOSStatePerformRingUpdate]; + } + return nil; + + } else if ([currentState isEqualToString:SOSStateError]) { + return nil; + } else if ([currentState isEqualToString:SOSStatePerformRingUpdate]) { + return [self performRingUpdate]; + + } else if ([currentState isEqualToString:SOSStatePerformBackup]) { + return [self performBackup]; + } + + return nil; +} +#endif + @end diff --git a/keychain/SecureObjectSync/SOSAccountConfiguration.proto b/keychain/SecureObjectSync/SOSAccountConfiguration.proto new file mode 100644 index 00000000..bb26993a --- /dev/null +++ b/keychain/SecureObjectSync/SOSAccountConfiguration.proto @@ -0,0 +1,12 @@ + +syntax = "proto2"; + +option objc_class_naming = "extended"; +option objc_class_visibility = "hidden"; + +package SOS; + +message AccountConfiguration { + repeated string pendingBackupPeers = 1; + optional bool ringUpdateFlag = 2; +} diff --git a/keychain/SecureObjectSync/SOSAccountPersistence.m b/keychain/SecureObjectSync/SOSAccountPersistence.m index 5b63e744..eb4b7a0f 100644 --- a/keychain/SecureObjectSync/SOSAccountPersistence.m +++ b/keychain/SecureObjectSync/SOSAccountPersistence.m @@ -457,9 +457,10 @@ static SOSAccount* SOSAccountCreateFromDER(CFAllocatorRef allocator, } CFReleaseNull(oldPI); - SOSAccountEnsureRecoveryRing(account); [account performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + SOSAccountEnsureRecoveryRing(account); + secnotice("circleop", "Setting account.key_interests_need_updating to true in SOSAccountCreateFromDER"); account.key_interests_need_updating = true; }]; diff --git a/keychain/SecureObjectSync/SOSAccountPriv.h b/keychain/SecureObjectSync/SOSAccountPriv.h index fd6d2b1b..798d1fb1 100644 --- a/keychain/SecureObjectSync/SOSAccountPriv.h +++ b/keychain/SecureObjectSync/SOSAccountPriv.h @@ -125,9 +125,11 @@ typedef void (^SOSAccountSaveBlock)(CFDataRef flattenedAccount, CFErrorRef flatt --(id) init; +-(id) init NS_UNAVAILABLE; -(id) initWithGestalt:(CFDictionaryRef)gestalt factory:(SOSDataSourceFactoryRef)factory; +- (void)startStateMachine; + void SOSAccountAddSyncablePeerBlock(SOSAccount* a, CFStringRef ds_name, SOSAccountSyncablePeersBlock changeBlock); @@ -141,6 +143,11 @@ void SOSAccountAddSyncablePeerBlock(SOSAccount* a, + (SOSAccountGhostBustingOptions) ghostBustGetRampSettings; - (bool) ghostBustCheckDate; +#if OCTAGON +- (void)triggerBackupForPeers:(NSArray*)backupPeer; +- (void)triggerRingUpdate; +#endif + void SOSAccountSetToNew(SOSAccount* a); @@ -199,8 +206,6 @@ bool SOSAccountHandleCircleMessage(SOSAccount* account, CF_RETURNS_RETAINED CFDictionaryRef SOSAccountHandleRetirementMessages(SOSAccount* account, CFDictionaryRef circle_retirement_messages, CFErrorRef *error); -void SOSAccountRecordRetiredPeersInCircle(SOSAccount* account); - bool SOSAccountHandleUpdateCircle(SOSAccount* account, SOSCircleRef prospective_circle, bool writeUpdate, @@ -270,7 +275,6 @@ bool sosAccountLeaveRing(SOSAccount* account, SOSRingRef ring, CFErrorRef* erro bool SOSAccountForEachRing(SOSAccount* account, SOSRingRef (^action)(CFStringRef name, SOSRingRef ring)); bool SOSAccountUpdateBackUp(SOSAccount* account, CFStringRef viewname, CFErrorRef *error); void SOSAccountEnsureRecoveryRing(SOSAccount* account); -bool SOSAccountEnsureInBackupRings(SOSAccount* account); bool SOSAccountEnsurePeerRegistration(SOSAccount* account, CFErrorRef *error); diff --git a/keychain/SecureObjectSync/SOSAccountRecovery.m b/keychain/SecureObjectSync/SOSAccountRecovery.m index cd272013..39d74993 100644 --- a/keychain/SecureObjectSync/SOSAccountRecovery.m +++ b/keychain/SecureObjectSync/SOSAccountRecovery.m @@ -196,6 +196,8 @@ static void sosRecoveryAlertAndNotify(SOSAccount* account, SOSRecoveryKeyBagRef } void SOSAccountEnsureRecoveryRing(SOSAccount* account) { + dispatch_assert_queue(account.queue); + static SOSRecoveryKeyBagRef oldRingRKBG = NULL; SOSRecoveryKeyBagRef acctRKBG = SOSAccountCopyRecoveryKeyBagEntry(kCFAllocatorDefault, account, NULL); if(!CFEqualSafe(acctRKBG, oldRingRKBG)) { diff --git a/keychain/SecureObjectSync/SOSAccountTransaction.m b/keychain/SecureObjectSync/SOSAccountTransaction.m index 1c014b29..168d096d 100644 --- a/keychain/SecureObjectSync/SOSAccountTransaction.m +++ b/keychain/SecureObjectSync/SOSAccountTransaction.m @@ -277,18 +277,10 @@ static void SOSViewsSetCachedStatus(SOSAccount *account) { } if(self.account.circle_rings_retirements_need_attention){ - SOSAccountRecordRetiredPeersInCircle(self.account); - - SOSAccountEnsureRecoveryRing(self.account); - SOSAccountEnsureInBackupRings(self.account); - - CFErrorRef localError = NULL; - if(![self.account.circle_transport flushChanges:&localError]){ - secerror("flush circle failed %@", localError); - } - CFReleaseSafe(localError); - - notifyEngines = true; + self.account.circle_rings_retirements_need_attention = false; +#if OCTAGON + [self.account triggerRingUpdate]; +#endif } if (notifyEngines) { @@ -305,7 +297,6 @@ static void SOSViewsSetCachedStatus(SOSAccount *account) { SOSUpdateKeyInterest(self.account); } - self.account.circle_rings_retirements_need_attention = false; self.account.engine_peer_state_needs_repair = false; [self.account flattenToSaveBlock]; diff --git a/keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.m b/keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.m index ef78b198..b6273573 100644 --- a/keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.m +++ b/keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.m @@ -15,7 +15,7 @@ #import "keychain/SecureObjectSync/SOSPeerInfoCollections.h" #import "keychain/SecureObjectSync/SOSTransportCircleKVS.h" #import "keychain/SecureObjectSync/SOSRingRecovery.h" -#import "keychain/Signin Metrics/SFSignInAnalytics.h" +#import "keychain/SigninMetrics/SFSignInAnalytics.h" @implementation SOSAccountTrustClassic (Expansion) typedef enum { @@ -27,11 +27,9 @@ typedef enum { ignore } ringAction_t; -#if !defined(NDEBUG) -static const char * __unused actionstring[] = { +static const char *actionstring[] = { "accept", "countersign", "leave", "revert", "modify", "ignore", }; -#endif static NSString* kSOSRingKey = @"trusted_rings"; // @@ -331,7 +329,9 @@ errOut: SOSRingRef newRing = NULL; SOSRingRef oldRing = NULL; - secdebug("ringSigning", "start:[%s] %@", localRemote, prospectiveRing); + CFStringRef modifierPeerID = CFStringCreateTruncatedCopy(SOSRingGetLastModifier(prospectiveRing), 8); + secnotice("ring", "start:[%s] modifier: %@", localRemote, modifierPeerID); + CFReleaseNull(modifierPeerID); require_quiet(SOSAccountHasPublicKey(account, error), errOut); require_action_quiet(peerPubKey, errOut, SOSCreateError(kSOSErrorPublicKeyAbsent, CFSTR("No device public key to work with"), NULL, error)); require_action_quiet(peerPrivKey, errOut, SOSCreateError(kSOSErrorPrivateKeyAbsent, CFSTR("No device private key to work with"), NULL, error)); @@ -360,7 +360,7 @@ errOut: SOSConcordanceStatus concstat = SOSRingConcordanceTrust(fpi, peers, oldRing, newRing, oldKey, userPublic, peerID, error); - CFStringRef concStr = NULL; + CFStringRef concStr = CFSTR("NA"); switch(concstat) { case kSOSConcordanceTrusted: ringAction = countersign; @@ -382,7 +382,7 @@ errOut: case kSOSConcordanceNoPeerSig: ringAction = accept; // We might like this one eventually but don't countersign. concStr = CFSTR("No trusted peer signature"); - secnotice("signing", "##### No trusted peer signature found, accepting hoping for concordance later %@", newRing); + secnotice("signing", "##### No trusted peer signature found, accepting hoping for concordance later"); break; case kSOSConcordanceNoPeer: ringAction = leave; @@ -390,6 +390,7 @@ errOut: break; case kSOSConcordanceNoUserKey: secerror("##### No User Public Key Available, this shouldn't ever happen!!!"); + concStr = CFSTR("No User Public Key Available"); ringAction = ignore; break; @@ -407,13 +408,12 @@ errOut: break; default: secerror("##### Bad Error Return from ConcordanceTrust"); + concStr = CFSTR("Bad Error Return from ConcordanceTrust"); ringAction = ignore; break; } - (void)concStr; - - secdebug("ringSigning", "Decided on action [%s] based on concordance state [%@] and [%s] circle.", + secnotice("ring", "Decided on action [%s] based on concordance state [%@] and [%s] ring.", actionstring[ringAction], concStr, userTrustedoldRing ? "trusted" : "untrusted"); // if we're ignoring this ring we're done @@ -477,7 +477,7 @@ errOut: if(SOSRingSetBackupKeyBag(newRing, fpi, viewSet, bskb, &localError) == false) { stopCountersign = true; - secnotice("recovery", "Couldn't fix BSKB (%@)", localError); + secnotice("ring", "Couldn't fix BSKB (%@)", localError); } SOSRingRemoveSignatures(newRing, NULL); SOSRingGenerationSign(newRing, NULL, fpi, error); @@ -493,7 +493,7 @@ errOut: if(stopCountersign) { ringAction = ignore; } else if (SOSRingPeerTrusted(newRing, fpi, NULL)) { - secdebug("ringSigning", "Already concur with: %@", newRing); + secnotice("ring", "Already concur with newRing"); ringAction = accept; } else { CFErrorRef signingError = NULL; @@ -501,7 +501,7 @@ errOut: ringToPush = newRing; ringAction = accept; } else { - secerror("Failed to concordance sign, error: %@ Old: %@ New: %@", signingError, oldRing, newRing); + secnotice("ring", "Failed to concordance sign, error: %@", signingError); success = false; ringAction = ignore; } @@ -545,10 +545,12 @@ leaveAndAccept: if (ringAction == revert) { if(haveOldRing && SOSRingHasPeerID(oldRing, peerID)) { - secdebug("ringSigning", "%@, Rejecting: %@ re-publishing %@", concStr, newRing, oldRing); + secnotice("ring", "Rejecting: %@", newRing); + secnotice("ring", " RePush: %@", oldRing); ringToPush = oldRing; } else { - secdebug("ringSigning", "%@, Rejecting: %@ Have no old ring - would reset", concStr, newRing); + secnotice("ring", "Rejecting: %@", newRing); + secnotice("ring", "Have no old ring - would reset"); } } @@ -558,14 +560,14 @@ leaveAndAccept: } else if(ringIsRecovery) { recRingProcessed++; } - secdebug("ringSigning", "Pushing:[%s] %@", localRemote, ringToPush); + secnotice("ring", "Pushing:[%s] %@", localRemote, ringToPush); CFDataRef ringData = SOSRingCopyEncodedData(ringToPush, error); if (ringData) { success = [circleTransport kvsRingPostRing:SOSRingGetName(ringToPush) ring:ringData err:error]; } else { success = false; } - secnotice("circleop", "Setting account.key_interests_need_updating to true in handleUpdateRing"); + secnotice("ring", "Setting account.key_interests_need_updating to true in handleUpdateRing"); account.key_interests_need_updating = true; CFReleaseNull(ringData); } diff --git a/keychain/SecureObjectSync/SOSAccountUpdate.m b/keychain/SecureObjectSync/SOSAccountUpdate.m index 9c0cad82..f24e6713 100644 --- a/keychain/SecureObjectSync/SOSAccountUpdate.m +++ b/keychain/SecureObjectSync/SOSAccountUpdate.m @@ -162,6 +162,8 @@ bool SOSAccountSyncingV0(SOSAccount* account) { void SOSAccountNotifyEngines(SOSAccount* account) { + dispatch_assert_queue(account.queue); + SOSAccountTrustClassic *trust = account.trust; SOSFullPeerInfoRef identity = trust.fullPeerInfo; SOSCircleRef circle = trust.trustedCircle; diff --git a/keychain/SecureObjectSync/SOSCircle.c b/keychain/SecureObjectSync/SOSCircle.c index cba4a3b6..68d47e37 100644 --- a/keychain/SecureObjectSync/SOSCircle.c +++ b/keychain/SecureObjectSync/SOSCircle.c @@ -1313,7 +1313,7 @@ void SOSCircleForEachValidSyncingPeer(SOSCircleRef circle, SecKeyRef user_public void SOSCircleForEachBackupCapablePeerForView(SOSCircleRef circle, SecKeyRef user_public_key, CFStringRef viewName, void (^action)(SOSPeerInfoRef peer)) { SOSCircleForEachPeerMatching(circle, action, ^bool(SOSPeerInfoRef peer) { - return (!isHiddenPeer(peer) && SOSPeerInfoIsEnabledView(peer, viewName) && SOSPeerInfoHasBackupKey(peer) && SOSPeerInfoApplicationVerify(peer, user_public_key, NULL)); + return (!isHiddenPeer(peer) && SOSPeerInfoIsEnabledView(peer, viewName) /* let the wookie win --- && SOSPeerInfoHasBackupKey(peer)*/ && SOSPeerInfoApplicationVerify(peer, user_public_key, NULL)); }); } diff --git a/keychain/SecureObjectSync/SOSControlHelper.m b/keychain/SecureObjectSync/SOSControlHelper.m index a8335cac..aaf58c28 100644 --- a/keychain/SecureObjectSync/SOSControlHelper.m +++ b/keychain/SecureObjectSync/SOSControlHelper.m @@ -62,8 +62,10 @@ _SOSControlSetupInterface(NSXPCInterface *interface) [interface setClasses:errClasses forSelector:@selector(joinCircleWithBlob:version:complete:) argumentIndex:1 ofReply:YES]; [interface setClasses:errClasses forSelector:@selector(initialSyncCredentials:complete:) argumentIndex:1 ofReply:YES]; [interface setClasses:errClasses forSelector:@selector(importInitialSyncCredentials:complete:) argumentIndex:1 ofReply:YES]; - [interface setClasses:errClasses forSelector:@selector(triggerSync:complete:) argumentIndex:1 ofReply:YES]; [interface setClasses:errClasses forSelector:@selector(getWatchdogParameters:) argumentIndex:1 ofReply:YES]; [interface setClasses:errClasses forSelector:@selector(setWatchdogParmeters:complete:) argumentIndex:0 ofReply:YES]; [interface setClasses:errClasses forSelector:@selector(ghostBust:complete:) argumentIndex:1 ofReply:YES]; + [interface setClasses:errClasses forSelector:@selector(rpcTriggerSync:complete:) argumentIndex:1 ofReply:YES]; + [interface setClasses:errClasses forSelector:@selector(rpcTriggerBackup:complete:) argumentIndex:0 ofReply:YES]; + [interface setClasses:errClasses forSelector:@selector(rpcTriggerRingUpdate:) argumentIndex:0 ofReply:YES]; } diff --git a/keychain/SecureObjectSync/SOSControlServer.m b/keychain/SecureObjectSync/SOSControlServer.m index 6412bad3..5f8a748d 100644 --- a/keychain/SecureObjectSync/SOSControlServer.m +++ b/keychain/SecureObjectSync/SOSControlServer.m @@ -31,7 +31,14 @@ return NO; } - SOSClientRemote *sosClient = [[SOSClientRemote alloc] initSOSConnectionWithConnection:newConnection account:(__bridge SOSAccount *)SOSKeychainAccountGetSharedAccount()]; + SOSAccount *account = (__bridge SOSAccount *)SOSKeychainAccountGetSharedAccount(); + if (account == nil) { + secerror("sos: SOS have not launched yet, come later, pid: %d", + [newConnection processIdentifier]); + return NO; + } + + SOSClientRemote *sosClient = [[SOSClientRemote alloc] initSOSConnectionWithConnection:newConnection account:account]; newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(SOSControlProtocol)]; _SOSControlSetupInterface(newConnection.exportedInterface); @@ -142,14 +149,9 @@ [self.account importInitialSyncCredentials:items complete:complete]; } -- (void)triggerSync:(NSArray *)peers complete:(void(^)(bool success, NSError *))complete +- (void)rpcTriggerSync:(NSArray *)peers complete:(void(^)(bool success, NSError *))complete { - if (![self checkEntitlement:(__bridge NSString *)kSecEntitlementKeychainCloudCircle]) { - complete(false, [NSError errorWithDomain:(__bridge NSString *)kSOSErrorDomain code:kSOSEntitlementMissing userInfo:NULL]); - return; - } - - [self.account triggerSync:peers complete:complete]; + [self.account rpcTriggerSync:peers complete:complete]; } - (void)getWatchdogParameters:(void (^)(NSDictionary* parameters, NSError* error))complete @@ -178,6 +180,15 @@ [self.account ghostBustInfo:complete]; } +- (void)rpcTriggerBackup:(NSArray* _Nullable)backupPeers complete:(void (^)(NSError *error))complete +{ + [self.account rpcTriggerBackup:backupPeers complete:complete]; +} + +- (void)rpcTriggerRingUpdate:(void (^)(NSError *))complete { + [self.account rpcTriggerRingUpdate:complete]; +} + @end @implementation SOSClientRemote diff --git a/keychain/SecureObjectSync/SOSManifest.c b/keychain/SecureObjectSync/SOSManifest.c index 92b85f6c..12d928e2 100644 --- a/keychain/SecureObjectSync/SOSManifest.c +++ b/keychain/SecureObjectSync/SOSManifest.c @@ -217,7 +217,7 @@ void SOSManifestForEach(SOSManifestRef m, void(^block)(CFDataRef e, bool *stop)) bool stop = false; for (p = SOSManifestGetBytePtr(m), q = p + SOSManifestGetSize(m); !stop && p + SOSDigestSize <= q; p += SOSDigestSize) { - e = CFDataCreateWithBytesNoCopy(0, p, SOSDigestSize, kCFAllocatorNull); + e = CFDataCreate(kCFAllocatorDefault, p, SOSDigestSize); if (e) { block(e, &stop); CFRelease(e); diff --git a/keychain/SecureObjectSync/SOSPeer.m b/keychain/SecureObjectSync/SOSPeer.m index 495c561c..25375bad 100644 --- a/keychain/SecureObjectSync/SOSPeer.m +++ b/keychain/SecureObjectSync/SOSPeer.m @@ -738,7 +738,7 @@ void SOSPeerKeyBagDidChange(SOSPeerRef peer) { // Attempt to write a reset (ignoring failures since it will // be pended stickily if it fails). SOSPeerWriteReset(peer, NULL); - SOSCCRequestSyncWithBackupPeer(SOSPeerGetID(peer)); + SOSCCAccountTriggerSyncWithBackupPeer_server(SOSPeerGetID(peer)); } } @@ -1063,7 +1063,8 @@ bool SOSPeerDataSourceWillChange(SOSPeerRef peer, SOSDataSourceRef dataSource, S if (!ok) { // We were unable to stream everything out neatly - SOSCCRequestSyncWithBackupPeer(SOSPeerGetID(peer)); + NSArray *backupPeerList = @[ (__bridge NSString *)SOSPeerGetID(peer) ]; + SOSCCRequestSyncWithBackupPeerList((__bridge CFArrayRef)backupPeerList); } return ok; } diff --git a/keychain/SecureObjectSync/SOSRingTypes.m b/keychain/SecureObjectSync/SOSRingTypes.m index 5cee2f1e..6a5ed6be 100644 --- a/keychain/SecureObjectSync/SOSRingTypes.m +++ b/keychain/SecureObjectSync/SOSRingTypes.m @@ -181,8 +181,17 @@ SOSConcordanceStatus SOSRingConcordanceTrust(SOSFullPeerInfoRef me, CFSetRef pee return kSOSConcordanceError; } - secnotice("ring", "concordance trust (%s) knownRing: %@ proposedRing: %@ knownkey: %@ userkey: %@ excluded: %@", - ringTypes[type1]->typeName, knownRing, proposedRing, knownPubkey, userPubkey, excludePeerID); + secnotice("ring", "concordance trust (%s)", ringTypes[type1]->typeName); + secnotice("ring", " knownRing: %@", knownRing); + secnotice("ring", " proposedRing: %@", proposedRing); + CFStringRef knownKeyID = SOSCopyIDOfKeyWithLength(knownPubkey, 8, NULL); + CFStringRef userKeyID = SOSCopyIDOfKeyWithLength(userPubkey, 8, NULL); + CFStringRef mypeerSPID = CFStringCreateTruncatedCopy(excludePeerID, 8); + + secnotice("ring", "knownkey: %@ userkey: %@ myPeerID: %@", knownKeyID, userKeyID, mypeerSPID); + CFReleaseNull(knownKeyID); + CFReleaseNull(userKeyID); + CFReleaseNull(mypeerSPID); if(!(ringTypes[type1]->sosRingConcordanceTrust)){ return kSOSConcordanceError; diff --git a/keychain/SecureObjectSync/SOSRingUtils.c b/keychain/SecureObjectSync/SOSRingUtils.c index e1592ccc..bb0d6221 100644 --- a/keychain/SecureObjectSync/SOSRingUtils.c +++ b/keychain/SecureObjectSync/SOSRingUtils.c @@ -740,7 +740,9 @@ static CFStringRef CreateCommaSeparatedPeerIDs(CFSetRef peers) { if (addSeparator) { CFStringAppendCString(result, ", ", kCFStringEncodingUTF8); } - CFStringAppend(result, peerID); + CFStringRef spid = CFStringCreateTruncatedCopy(peerID, 8); + CFStringAppend(result, spid); + CFReleaseNull(spid); addSeparator = true; }); @@ -769,9 +771,11 @@ CFDictionaryRef SOSRingCopyPeerIDList(SOSRingRef ring) { CFMutableStringRef signers = CFStringCreateMutable(ALLOCATOR, 0); CFDictionaryForEach(ring->signatures, ^(const void *key, const void *value) { CFStringRef peerID = (CFStringRef) key; + CFStringRef spid = CFStringCreateTruncatedCopy(peerID, 8); if (addSeparator) CFStringAppendCString(signers, ", ", kCFStringEncodingUTF8); - CFStringAppend(signers, peerID); + CFStringAppend(signers, spid); + CFReleaseNull(spid); addSeparator = true; }); return signers; @@ -784,29 +788,17 @@ static CFStringRef SOSRingCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef CFDictionaryRef peers = SOSRingCopyPeerIDList(ring); CFStringRef signers = SOSRingCopySignerList(ring); - - CFDataRef payload = SOSRingGetPayload(ring, NULL); - CFStringRef gcString = SOSGenerationCountCopyDescription(SOSRingGetGeneration(ring)); CFMutableStringRef description = CFStringCreateMutable(kCFAllocatorDefault, 0); - CFStringAppendFormat(description, formatOpts, CFSTR(" *)peers complete:(void(^)(bool success, NSError *))complete; +- (void)rpcTriggerSync:(NSArray *)peers complete:(void(^)(bool success, NSError *))complete; - (void)getWatchdogParameters:(void (^)(NSDictionary* parameters, NSError* error))complete; - (void)setWatchdogParmeters:(NSDictionary*)parameters complete:(void (^)(NSError* error))complete; + +- (void)rpcTriggerBackup:(NSArray*)backupPeers complete:(void (^)(NSError *error))complete; +- (void)rpcTriggerRingUpdate:(void (^)(NSError *error))complete; + @end #endif diff --git a/keychain/SecureObjectSync/generated_source/SOSAccountConfiguration.h b/keychain/SecureObjectSync/generated_source/SOSAccountConfiguration.h new file mode 100644 index 00000000..c381e08a --- /dev/null +++ b/keychain/SecureObjectSync/generated_source/SOSAccountConfiguration.h @@ -0,0 +1,47 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from SOSAccountConfiguration.proto + +#import +#import + +#ifdef __cplusplus +#define SOSACCOUNTCONFIGURATION_FUNCTION extern "C" __attribute__((visibility("hidden"))) +#else +#define SOSACCOUNTCONFIGURATION_FUNCTION extern __attribute__((visibility("hidden"))) +#endif + +__attribute__((visibility("hidden"))) +@interface SOSAccountConfiguration : PBCodable +{ + NSMutableArray *_pendingBackupPeers; + BOOL _ringUpdateFlag; + struct { + int ringUpdateFlag:1; + } _has; +} + + +@property (nonatomic, retain) NSMutableArray *pendingBackupPeers; +- (void)clearPendingBackupPeers; +- (void)addPendingBackupPeers:(NSString *)i; +- (NSUInteger)pendingBackupPeersCount; +- (NSString *)pendingBackupPeersAtIndex:(NSUInteger)idx; ++ (Class)pendingBackupPeersType; + +@property (nonatomic) BOOL hasRingUpdateFlag; +@property (nonatomic) BOOL ringUpdateFlag; + +// Performs a shallow copy into other +- (void)copyTo:(SOSAccountConfiguration *)other; + +// Performs a deep merge from other into self +// If set in other, singular values in self are replaced in self +// Singular composite values are recursively merged +// Repeated values from other are appended to repeated values in self +- (void)mergeFrom:(SOSAccountConfiguration *)other; + +SOSACCOUNTCONFIGURATION_FUNCTION BOOL SOSAccountConfigurationReadFrom(__unsafe_unretained SOSAccountConfiguration *self, __unsafe_unretained PBDataReader *reader); + +@end + diff --git a/keychain/SecureObjectSync/generated_source/SOSAccountConfiguration.m b/keychain/SecureObjectSync/generated_source/SOSAccountConfiguration.m new file mode 100644 index 00000000..0314479a --- /dev/null +++ b/keychain/SecureObjectSync/generated_source/SOSAccountConfiguration.m @@ -0,0 +1,206 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from SOSAccountConfiguration.proto + +#import "SOSAccountConfiguration.h" +#import +#import +#import + +#if !__has_feature(objc_arc) +# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code. +#endif + +@implementation SOSAccountConfiguration + +@synthesize pendingBackupPeers = _pendingBackupPeers; +- (void)clearPendingBackupPeers +{ + [_pendingBackupPeers removeAllObjects]; +} +- (void)addPendingBackupPeers:(NSString *)i +{ + if (!_pendingBackupPeers) + { + _pendingBackupPeers = [[NSMutableArray alloc] init]; + } + [_pendingBackupPeers addObject:i]; +} +- (NSUInteger)pendingBackupPeersCount +{ + return [_pendingBackupPeers count]; +} +- (NSString *)pendingBackupPeersAtIndex:(NSUInteger)idx +{ + return [_pendingBackupPeers objectAtIndex:idx]; +} ++ (Class)pendingBackupPeersType +{ + return [NSString class]; +} +@synthesize ringUpdateFlag = _ringUpdateFlag; +- (void)setRingUpdateFlag:(BOOL)v +{ + _has.ringUpdateFlag = YES; + _ringUpdateFlag = v; +} +- (void)setHasRingUpdateFlag:(BOOL)f +{ + _has.ringUpdateFlag = f; +} +- (BOOL)hasRingUpdateFlag +{ + return _has.ringUpdateFlag; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]]; +} + +- (NSDictionary *)dictionaryRepresentation +{ + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + if (self->_pendingBackupPeers) + { + [dict setObject:self->_pendingBackupPeers forKey:@"pendingBackupPeers"]; + } + if (self->_has.ringUpdateFlag) + { + [dict setObject:[NSNumber numberWithBool:self->_ringUpdateFlag] forKey:@"ringUpdateFlag"]; + } + return dict; +} + +BOOL SOSAccountConfigurationReadFrom(__unsafe_unretained SOSAccountConfiguration *self, __unsafe_unretained PBDataReader *reader) { + while (PBReaderHasMoreData(reader)) { + uint32_t tag = 0; + uint8_t aType = 0; + + PBReaderReadTag32AndType(reader, &tag, &aType); + + if (PBReaderHasError(reader)) + break; + + if (aType == TYPE_END_GROUP) { + break; + } + + switch (tag) { + + case 1 /* pendingBackupPeers */: + { + NSString *new_pendingBackupPeers = PBReaderReadString(reader); + if (new_pendingBackupPeers) + { + [self addPendingBackupPeers:new_pendingBackupPeers]; + } + } + break; + case 2 /* ringUpdateFlag */: + { + self->_has.ringUpdateFlag = YES; + self->_ringUpdateFlag = PBReaderReadBOOL(reader); + } + break; + default: + if (!PBReaderSkipValueWithTag(reader, tag, aType)) + return NO; + break; + } + } + return !PBReaderHasError(reader); +} + +- (BOOL)readFrom:(PBDataReader *)reader +{ + return SOSAccountConfigurationReadFrom(self, reader); +} +- (void)writeTo:(PBDataWriter *)writer +{ + /* pendingBackupPeers */ + { + for (NSString *s_pendingBackupPeers in self->_pendingBackupPeers) + { + PBDataWriterWriteStringField(writer, s_pendingBackupPeers, 1); + } + } + /* ringUpdateFlag */ + { + if (self->_has.ringUpdateFlag) + { + PBDataWriterWriteBOOLField(writer, self->_ringUpdateFlag, 2); + } + } +} + +- (void)copyTo:(SOSAccountConfiguration *)other +{ + if ([self pendingBackupPeersCount]) + { + [other clearPendingBackupPeers]; + NSUInteger pendingBackupPeersCnt = [self pendingBackupPeersCount]; + for (NSUInteger i = 0; i < pendingBackupPeersCnt; i++) + { + [other addPendingBackupPeers:[self pendingBackupPeersAtIndex:i]]; + } + } + if (self->_has.ringUpdateFlag) + { + other->_ringUpdateFlag = _ringUpdateFlag; + other->_has.ringUpdateFlag = YES; + } +} + +- (id)copyWithZone:(NSZone *)zone +{ + SOSAccountConfiguration *copy = [[[self class] allocWithZone:zone] init]; + for (NSString *v in _pendingBackupPeers) + { + NSString *vCopy = [v copyWithZone:zone]; + [copy addPendingBackupPeers:vCopy]; + } + if (self->_has.ringUpdateFlag) + { + copy->_ringUpdateFlag = _ringUpdateFlag; + copy->_has.ringUpdateFlag = YES; + } + return copy; +} + +- (BOOL)isEqual:(id)object +{ + SOSAccountConfiguration *other = (SOSAccountConfiguration *)object; + return [other isMemberOfClass:[self class]] + && + ((!self->_pendingBackupPeers && !other->_pendingBackupPeers) || [self->_pendingBackupPeers isEqual:other->_pendingBackupPeers]) + && + ((self->_has.ringUpdateFlag && other->_has.ringUpdateFlag && ((self->_ringUpdateFlag && other->_ringUpdateFlag) || (!self->_ringUpdateFlag && !other->_ringUpdateFlag))) || (!self->_has.ringUpdateFlag && !other->_has.ringUpdateFlag)) + ; +} + +- (NSUInteger)hash +{ + return 0 + ^ + [self->_pendingBackupPeers hash] + ^ + (self->_has.ringUpdateFlag ? PBHashInt((NSUInteger)self->_ringUpdateFlag) : 0) + ; +} + +- (void)mergeFrom:(SOSAccountConfiguration *)other +{ + for (NSString *iter_pendingBackupPeers in other->_pendingBackupPeers) + { + [self addPendingBackupPeers:iter_pendingBackupPeers]; + } + if (other->_has.ringUpdateFlag) + { + self->_ringUpdateFlag = other->_ringUpdateFlag; + self->_has.ringUpdateFlag = YES; + } +} + +@end + diff --git a/keychain/SigninMetrics/OctagonSignPosts.h b/keychain/SigninMetrics/OctagonSignPosts.h new file mode 100644 index 00000000..34c07c65 --- /dev/null +++ b/keychain/SigninMetrics/OctagonSignPosts.h @@ -0,0 +1,155 @@ +/* +* Copyright (c) 2019 Apple Inc. All Rights Reserved. +* +* @APPLE_LICENSE_HEADER_START@ +* +* This file contains Original Code and/or Modifications of Original Code +* as defined in and that are subject to the Apple Public Source License +* Version 2.0 (the 'License'). You may not use this file except in +* compliance with the License. Please obtain a copy of the License at +* http://www.opensource.apple.com/apsl/ and read it before using this +* file. +* +* The Original Code and all software distributed under the License are +* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +* Please see the License for the specific language governing rights and +* limitations under the License. +* +* @APPLE_LICENSE_HEADER_END@ +*/ + +#ifndef OctagonSignPosts_h +#define OctagonSignPosts_h + +#import +#import +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +typedef struct octagon_signpost_s { + const os_signpost_id_t identifier; + const uint64_t timestamp; +} OctagonSignpost; + +#define OctagonSignpostNamePerformEscrowRecovery "OctagonSignpostNamePerformEscrowRecovery" +#define OctagonSignpostNamePerformRecoveryFromSBD "OctagonSignpostNamePerformRecoveryFromSBD" +#define OctagonSignpostNamePerformBottleRecovery "OctagonSignpostNamePerformBottleRecovery" +#define OctagonSignpostNamePerformResetAndEstablishAfterFailedBottle "OctagonSignpostNamePerformResetAndEstablishAfterFailedBottle" +#define OctagonSignpostNameFetchEgoPeer "OctagonSignpostNameFetchEgoPeer" +#define OctagonSignpostNameEstablish "OctagonSignpostNameEstablish" +#define OctagonSignpostNameResetAndEstablish "OctagonSignpostNameResetAndEstablish" +#define OctagonSignpostNameMakeNewFriends "OctagonSignpostNameMakeNewFriends" +#define OctagonSignpostNameFetchCliqueStatus "OctagonSignpostNameFetchCliqueStatus" +#define OctagonSignpostNameRemoveFriendsInClique "OctagonSignpostNameRemoveFriendsInClique" +#define OctagonSignpostNameLeaveClique "OctagonSignpostNameLeaveClique" +#define OctagonSignpostNamePeerDeviceNamesByPeerID "OctagonSignpostNamePeerDeviceNamesByPeerID" +#define OctagonSignpostNameJoinAfterRestore "OctagonSignpostNameJoinAfterRestore" +#define OctagonSignpostNameSafariPasswordSyncingEnabled "OctagonSignpostNameSafariPasswordSyncingEnabled" +#define OctagonSignpostNameWaitForInitialSync "OctagonSignpostNameWaitForInitialSync" +#define OctagonSignpostNameCopyViewUnawarePeerInfo "OctagonSignpostNameCopyViewUnawarePeerInfo" +#define OctagonSignpostNameViewSet "OctagonSignpostNameViewSet" +#define OctagonSignpostNameSetUserCredentialsAndDSID "OctagonSignpostNameSetUserCredentialsAndDSID" +#define OctagonSignpostNameTryUserCredentialsAndDSID "OctagonSignpostNameTryUserCredentialsAndDSID" +#define OctagonSignpostNameCopyPeerPeerInfo "OctagonSignpostNameCopyPeerPeerInfo" +#define OctagonSignpostNamePeersHaveViewsEnabled "OctagonSignpostNamePeersHaveViewsEnabled" +#define OctagonSignpostNameRequestToJoinCircle "OctagonSignpostNameRequestToJoinCircle" +#define OctagonSignpostNameAccountUserKeyAvailable "OctagonSignpostNameAccountUserKeyAvailable" +#define OctagonSignpostNameFindOptimalBottleIDsWithContextData "OctagonSignpostNameFindOptimalBottleIDsWithContextData" +#define OctagonSignpostNameFetchEscrowContents "OctagonSignpostNameFetchEscrowContents" +#define OctagonSignpostNameSetNewRecoveryKeyWithData "OctagonSignpostNameSetNewRecoveryKeyWithData" +#define OctagonSignpostNameRecoverOctagonUsingData "OctagonSignpostNameRecoverOctagonUsingData" +#define OctagonSignpostNamePerformedCDPStateMachineRun "OctagonSignpostNamePerformedCDPStateMachineRun" +#define OctagonSignpostNameWaitForOctagonUpgrade "OctagonSignpostNameWaitForOctagonUpgrade" + +#define SOSSignpostNameAssertUserCredentialsAndOptionalDSID "SOSSignpostNameAssertUserCredentialsAndOptionalDSID" +#define SOSSignpostNameSOSCCTryUserCredentials "SOSSignpostNameSOSCCTryUserCredentials" +#define SOSSignpostNameSOSCCCanAuthenticate "SOSSignpostNameSOSCCCanAuthenticate" +#define SOSSignpostNameSOSCCRequestToJoinCircle "SOSSignpostNameSOSCCRequestToJoinCircle" +#define SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore "SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore" +#define SOSSignpostNameSOSCCResetToOffering "SOSSignpostNameSOSCCResetToOffering" +#define SOSSignpostNameSOSCCResetToEmpty "SOSSignpostNameSOSCCResetToEmpty" +#define SOSSignpostNameSOSCCRemoveThisDeviceFromCircle "SOSSignpostNameSOSCCRemoveThisDeviceFromCircle" +#define SOSSignpostNameSOSCCRemovePeersFromCircle "SOSSignpostNameSOSCCRemovePeersFromCircle" +#define SOSSignpostNameSOSCCLoggedOutOfAccount "SOSSignpostNameSOSCCLoggedOutOfAccount" +#define SOSSignpostNameSOSCCCopyApplicantPeerInfo "SOSSignpostNameSOSCCCopyApplicantPeerInfo" +#define SOSSignpostNameFlush "SOSSignpostNameFlush" +#define SOSSignpostNameSyncKVSAndWait "SOSSignpostNameSyncKVSAndWait" +#define SOSSignpostNameSyncTheLastDataToKVS "SOSSignpostNameSyncTheLastDataToKVS" +#define SOSSignpostNameSOSCCViewSet "SOSSignpostNameSOSCCViewSet" +#define SOSSignpostNameSOSCCCopyValidPeerPeerInfo "SOSSignpostNameSOSCCCopyValidPeerPeerInfo" +#define SOSSignpostNameSOSCCValidateUserPublic "SOSSignpostNameSOSCCValidateUserPublic" +#define SOSSignpostNameSOSCCCopyViewUnawarePeerInfo "SOSSignpostNameSOSCCCopyViewUnawarePeerInfo" +#define SOSSignpostNameSOSCCWaitForInitialSync "SOSSignpostNameSOSCCWaitForInitialSync" +#define SOSSignpostNameSOSCCAcceptApplicants "SOSSignpostNameSOSCCAcceptApplicants" +#define SOSSignpostNameSOSCCRejectApplicants "SOSSignpostNameSOSCCRejectApplicants" +#define SOSSignpostNameSOSCCCopyConcurringPeerPeerInfo "SOSSignpostNameSOSCCCopyConcurringPeerPeerInfo" +#define SOSSignpostNameSOSCCCopyMyPeerInfo "SOSSignpostNameSOSCCCopyMyPeerInfo" +#define SOSSignpostNameSOSCCSetNewPublicBackupKey "SOSSignpostNameSOSCCSetNewPublicBackupKey" +#define SOSSignpostNameSOSCCRegisterSingleRecoverySecret "SOSSignpostNameSOSCCRegisterSingleRecoverySecret" +#define SOSSignpostNameSOSCCProcessEnsurePeerRegistration "SOSSignpostNameSOSCCProcessEnsurePeerRegistration" +#define SOSSignpostNameSOSCCProcessSyncWithPeers "SOSSignpostNameSOSCCProcessSyncWithPeers" +#define SOSSignpostNameSOSCCProcessSyncWithAllPeers "SOSSignpostNameSOSCCProcessSyncWithAllPeers" +#define SOSSignpostNameSOSCCRequestSyncWithPeersList "SOSSignpostNameSOSCCRequestSyncWithPeersList" +#define SOSSignpostNameSOSCCRequestSyncWithBackupPeerList "SOSSignpostNameSOSCCRequestSyncWithBackupPeerList" +#define SOSSignpostNameSOSCCEnsurePeerRegistration "SOSSignpostNameSOSCCEnsurePeerRegistration" +#define SOSSignpostNameSOSCCHandleUpdateMessage "SOSSignpostNameSOSCCHandleUpdateMessage" +#define SOSSignpostNameSOSCCCopyApplication "SOSSignpostNameSOSCCCopyApplication" +#define SOSSignpostNameSOSCCCopyCircleJoiningBlob "SOSSignpostNameSOSCCCopyCircleJoiningBlob" +#define SOSSignpostNameSOSCCCopyInitialSyncData "SOSSignpostNameSOSCCCopyInitialSyncData" +#define SOSSignpostNameSOSCCJoinWithCircleJoiningBlob "SOSSignpostNameSOSCCJoinWithCircleJoiningBlob" +#define SOSSignpostNameSOSCCPeersHaveViewsEnabled "SOSSignpostNameSOSCCPeersHaveViewsEnabled" +#define SOSSignpostNameSOSCCRegisterRecoveryPublicKey "SOSSignpostNameSOSCCRegisterRecoveryPublicKey" +#define SOSSignpostNameSOSCCCopyRecoveryPublicKey "SOSSignpostNameSOSCCCopyRecoveryPublicKey" +#define SOSSignpostNameSOSCCMessageFromPeerIsPending "SOSSignpostNameSOSCCMessageFromPeerIsPending" +#define SOSSignpostNameSOSCCSendToPeerIsPending "SOSSignpostNameSOSCCSendToPeerIsPending" + +#define OctagonSignpostString1(label) " "#label"=%{public,signpost.telemetry:string1,name="#label"}@ " +#define OctagonSignpostString2(label) " "#label"=%{public,signpost.telemetry:string2,name="#label"}@ " +#define OctagonSignpostNumber1(label) " "#label"=%{public,signpost.telemetry:number1,name="#label"}d " +#define OctagonSignpostNumber2(label) " "#label"=%{public,signpost.telemetry:number2,name="#label"}d " + +// Used to begin tracking a timed event. +#define OctagonSignpostBegin(name) _OctagonSignpostBegin(_OctagonSignpostLogSystem(), name, OS_SIGNPOST_ENABLE_TELEMETRY) + +// For marking a significant event. +#define OctagonSignpostEvent(signpost, name, ...) _OctagonSignpostEvent(_OctagonSignpostLogSystem(), signpost, name, __VA_ARGS__) + +// For completing a timed event associated with the given signpost. +#define OctagonSignpostEnd(signpost, name, ...) _OctagonSignpostEnd(_OctagonSignpostLogSystem(), signpost, name, __VA_ARGS__) + +extern os_log_t _OctagonSignpostLogSystem(void); + +extern OctagonSignpost _OctagonSignpostCreate(os_log_t subsystem); +extern uint64_t _OctagonSignpostGetNanoseconds(OctagonSignpost signpost); + +#define _OctagonSignpostBegin(subsystem, name, ...) __extension__({ \ + OctagonSignpost internalSignpost = _OctagonSignpostCreate(subsystem); \ + os_signpost_interval_begin(subsystem, internalSignpost.identifier, name, __VA_ARGS__); \ + os_log(subsystem, "BEGIN [%lld]: " name " " _OctagonSwizzle1(internalSignpost.identifier, __VA_ARGS__)); \ + internalSignpost; \ +}) + +#define _OctagonSignpostEvent(subsystem, signpost, name, ...) __extension__({ \ + double interval = ((double)_OctagonSignpostGetNanoseconds(_signpost) / NSEC_PER_SEC); \ + os_signpost_event_emit(subsystem, signpost.identifier, name, __VA_ARGS__); \ + os_log(subsystem, "EVENT [%lld] %fs: " name " " _OctagonSwizzle2(signpost.identifier, interval, __VA_ARGS__)); \ +}) + +#define _OctagonSignpostEnd(subsystem, signpost, name, ...) __extension__({ \ + double interval = ((double)_OctagonSignpostGetNanoseconds(signpost) / NSEC_PER_SEC); \ + os_signpost_interval_end(subsystem, signpost.identifier, name, __VA_ARGS__); \ + os_log(subsystem, "END [%lld] %fs: " name " " _OctagonSwizzle2(signpost.identifier, interval, __VA_ARGS__)); \ +}) + +#define _OctagonSwizzle1(x, a, ...) a, x, ##__VA_ARGS__ +#define _OctagonSwizzle2(x, y, a, ...) a, x, y, ##__VA_ARGS__ + +NS_ASSUME_NONNULL_END + +#endif /* OctagonSignPosts_h */ diff --git a/keychain/SigninMetrics/OctagonSignPosts.m b/keychain/SigninMetrics/OctagonSignPosts.m new file mode 100644 index 00000000..5466a389 --- /dev/null +++ b/keychain/SigninMetrics/OctagonSignPosts.m @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2019 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#import +#import + +#import "OctagonSignPosts.h" + +os_log_t _OctagonSignpostLogSystem(void) { + static os_log_t log = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + log = os_log_create("com.apple.security", "signpost"); + }); + return log; +} + +#pragma mark - Signpost Methods + +OctagonSignpost _OctagonSignpostCreate(os_log_t subsystem) { + os_signpost_id_t identifier = os_signpost_id_generate(subsystem); + uint64_t timestamp = mach_continuous_time(); + return (OctagonSignpost){ + .identifier = identifier, + .timestamp = timestamp, + }; +} + +uint64_t _OctagonSignpostGetNanoseconds(OctagonSignpost signpost) { + static struct mach_timebase_info timebase_info; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + mach_timebase_info(&timebase_info); + }); + + uint64_t interval = mach_continuous_time() - signpost.timestamp; + + return (uint64_t)(interval * + ((double)timebase_info.numer / timebase_info.denom)); +} diff --git a/keychain/Signin Metrics/Resources/SFTMTests-Info.plist b/keychain/SigninMetrics/Resources/SFTMTests-Info.plist similarity index 100% rename from keychain/Signin Metrics/Resources/SFTMTests-Info.plist rename to keychain/SigninMetrics/Resources/SFTMTests-Info.plist diff --git a/keychain/SigninMetrics/Resources/com.apple.security.signposts.plist b/keychain/SigninMetrics/Resources/com.apple.security.signposts.plist new file mode 100644 index 00000000..8b1c81da --- /dev/null +++ b/keychain/SigninMetrics/Resources/com.apple.security.signposts.plist @@ -0,0 +1,27 @@ + + + + + DEFAULT-OPTIONS + + Propagate-with-Activity + + TTL + + Default + 7 + Info + 7 + Debug + 0 + + Level + + Enable + Default + Persist + Default + + + + diff --git a/keychain/Signin Metrics/SFSignInAnalytics+Internal.h b/keychain/SigninMetrics/SFSignInAnalytics+Internal.h similarity index 100% rename from keychain/Signin Metrics/SFSignInAnalytics+Internal.h rename to keychain/SigninMetrics/SFSignInAnalytics+Internal.h diff --git a/keychain/Signin Metrics/SFSignInAnalytics.h b/keychain/SigninMetrics/SFSignInAnalytics.h similarity index 100% rename from keychain/Signin Metrics/SFSignInAnalytics.h rename to keychain/SigninMetrics/SFSignInAnalytics.h diff --git a/keychain/Signin Metrics/SFSignInAnalytics.m b/keychain/SigninMetrics/SFSignInAnalytics.m similarity index 100% rename from keychain/Signin Metrics/SFSignInAnalytics.m rename to keychain/SigninMetrics/SFSignInAnalytics.m diff --git a/keychain/Signin Metrics/tests/SFSignInAnalyticsTests.m b/keychain/SigninMetrics/tests/SFSignInAnalyticsTests.m similarity index 99% rename from keychain/Signin Metrics/tests/SFSignInAnalyticsTests.m rename to keychain/SigninMetrics/tests/SFSignInAnalyticsTests.m index 8cafd23f..b52d9b4e 100644 --- a/keychain/Signin Metrics/tests/SFSignInAnalyticsTests.m +++ b/keychain/SigninMetrics/tests/SFSignInAnalyticsTests.m @@ -22,8 +22,8 @@ */ #import -#import "keychain/Signin Metrics/SFSignInAnalytics.h" -#import "keychain/Signin Metrics/SFSignInAnalytics+Internal.h" +#import "keychain/SigninMetrics/SFSignInAnalytics.h" +#import "keychain/SigninMetrics/SFSignInAnalytics+Internal.h" #import "keychain/ot/OTDefines.h" #import "SFAnalytics+Signin.h" #import diff --git a/keychain/Trieste/OctagonTestHarnessXPCService/Entitlements.plist b/keychain/Trieste/OctagonTestHarnessXPCService/Entitlements.plist index f8ec5419..0058b605 100644 --- a/keychain/Trieste/OctagonTestHarnessXPCService/Entitlements.plist +++ b/keychain/Trieste/OctagonTestHarnessXPCService/Entitlements.plist @@ -8,5 +8,7 @@ com.apple.private.octagon + com.apple.securebackupd.access + diff --git a/keychain/Trieste/OctagonTestHarnessXPCService/OctagonTestHarnessXPCService.m b/keychain/Trieste/OctagonTestHarnessXPCService/OctagonTestHarnessXPCService.m index 00fe0159..6724a7d9 100644 --- a/keychain/Trieste/OctagonTestHarnessXPCService/OctagonTestHarnessXPCService.m +++ b/keychain/Trieste/OctagonTestHarnessXPCService/OctagonTestHarnessXPCService.m @@ -5,6 +5,8 @@ #import #import #import +#import + #import "SecDbKeychainItem.h" #import "SecRemoteDevice.h" #import "OTControl.h" @@ -16,6 +18,22 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wprotocol" +@interface NSError (OctagonTestHarnessXPCService) +- (NSDictionary*)errorAsDictionary; +@end + + +@implementation NSError (OctagonTestHarnessXPCService) + +- (NSDictionary*)errorAsDictionary { + return @{ + @"domain": self.domain, + @"code": @(self.code), + }; +} +@end + + @implementation OctagonTestHarnessXPCService - (instancetype)init { @@ -50,7 +68,100 @@ } +//MARK: Keychain + + +- (void)secItemAdd:(NSDictionary *)input complete:(void (^)(NSNumber *, NSDictionary * _Nullable))reply +{ + NSMutableDictionary *attributes = [input mutableCopy]; + CFTypeRef data = NULL; + + attributes[(__bridge NSString *)kSecReturnAttributes] = @YES; + attributes[(__bridge NSString *)kSecReturnPersistentRef] = @YES; + attributes[(__bridge NSString *)kSecReturnData] = @YES; + + OSStatus status = SecItemAdd((__bridge CFDictionaryRef)attributes, &data); + NSDictionary *returnData = CFBridgingRelease(data); + + reply(@(status), returnData); + +} +- (void)secItemCopyMatching:(NSDictionary *)input complete:(void (^)(NSNumber *, NSArray* _Nullable))reply +{ + NSMutableDictionary *attributes = [input mutableCopy]; + CFTypeRef data = NULL; + + attributes[(__bridge NSString *)kSecReturnAttributes] = @YES; + attributes[(__bridge NSString *)kSecReturnData] = @YES; + attributes[(__bridge NSString *)kSecReturnPersistentRef] = @YES; + attributes[(__bridge NSString *)kSecMatchLimit] = (__bridge id)kSecMatchLimitAll; + + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)attributes, &data); + NSArray* array = CFBridgingRelease(data); + NSMutableArray *result = [NSMutableArray array]; + for (NSDictionary *d in array) { + NSMutableDictionary *r = [d mutableCopy]; + r[@"accc"] = nil; + [result addObject:r]; + } + + reply(@(status), result); + +} +- (void)secItemDelete:(NSDictionary *)input complete:(void (^)(NSNumber *))reply +{ + NSMutableDictionary *attributes = [input mutableCopy]; + + attributes[(__bridge NSString *)kSecReturnAttributes] = @YES; + attributes[(__bridge NSString *)kSecReturnPersistentRef] = @YES; + attributes[(__bridge NSString *)kSecReturnData] = @YES; + + OSStatus status = SecItemDelete((__bridge CFDictionaryRef)attributes); + + reply(@(status)); +} + +//MARK: CloudServices + +- (void)csAccountInfo:(NSDictionary *)info complete:(void (^)(NSDictionary * _Nullable, NSDictionary * _Nullable))reply +{ + SecureBackup *sb = [[SecureBackup alloc] init]; + + [sb getAccountInfoWithInfo:info completionBlock:^(NSDictionary *results, NSError *error) { + reply(results, [error errorAsDictionary]); + }]; +} +- (void)csEnableInfo:(NSDictionary *)info complete:(void (^)(NSDictionary * _Nullable, NSDictionary * _Nullable))reply +{ + SecureBackup *sb = [[SecureBackup alloc] init]; + + [sb enableWithInfo:info completionBlock:^(NSError *error) { + reply(@{}, [error errorAsDictionary]); + }]; +} +- (void)csUpdateInfo:(NSDictionary *)info complete:(void (^)(NSDictionary * _Nullable, NSDictionary * _Nullable))reply +{ + SecureBackup *sb = [[SecureBackup alloc] init]; + [sb updateMetadataWithInfo:info completionBlock:^(NSError *error) { + reply(@{}, [error errorAsDictionary]); + }]; +} +- (void)csDisableInfo:(NSDictionary *)info complete:(void (^)(NSDictionary * _Nullable, NSDictionary * _Nullable))reply +{ + SecureBackup *sb = [[SecureBackup alloc] init]; + [sb disableWithInfo:info completionBlock:^(NSError *error) { + reply(@{}, [error errorAsDictionary]); + }]; +} + +- (void)csRecoverInfo:(NSDictionary *)info complete:(void (^)(NSDictionary * _Nullable, NSDictionary * _Nullable))reply +{ + SecureBackup *sb = [[SecureBackup alloc] init]; + [sb recoverWithInfo:info completionBlock:^(NSDictionary *results, NSError *error) { + reply(results, [error errorAsDictionary]); + }]; +} @end diff --git a/keychain/Trieste/OctagonTestHarnessXPCService/SecRemoteDevice.m b/keychain/Trieste/OctagonTestHarnessXPCService/SecRemoteDevice.m index c6404265..db9d9914 100644 --- a/keychain/Trieste/OctagonTestHarnessXPCService/SecRemoteDevice.m +++ b/keychain/Trieste/OctagonTestHarnessXPCService/SecRemoteDevice.m @@ -109,42 +109,6 @@ @implementation SecRemoteDevice -- (void)secItemAdd:(NSDictionary *)input complete:(void (^)(OSStatus, NSDictionary *))reply -{ - NSMutableDictionary *attributes = [input mutableCopy]; - CFTypeRef data = NULL; - - attributes[(__bridge NSString *)kSecReturnAttributes] = @YES; - attributes[(__bridge NSString *)kSecReturnPersistentRef] = @YES; - attributes[(__bridge NSString *)kSecReturnData] = @YES; - - OSStatus status = SecItemAdd((__bridge CFDictionaryRef)attributes, &data); - NSDictionary *returnData = CFBridgingRelease(data); - - reply(status, returnData); -} - -- (void)secItemCopyMatching:(NSDictionary *)input complete:(void (^)(OSStatus, NSArray*))reply -{ - NSMutableDictionary *attributes = [input mutableCopy]; - CFTypeRef data = NULL; - - attributes[(__bridge NSString *)kSecReturnAttributes] = @YES; - attributes[(__bridge NSString *)kSecReturnData] = @YES; - attributes[(__bridge NSString *)kSecReturnPersistentRef] = @YES; - attributes[(__bridge NSString *)kSecMatchLimit] = (__bridge id)kSecMatchLimitAll; - - OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)attributes, &data); - NSArray* array = CFBridgingRelease(data); - NSMutableArray *result = [NSMutableArray array]; - for (NSDictionary *d in array) { - NSMutableDictionary *r = [d mutableCopy]; - r[@"accc"] = nil; - [result addObject:r]; - } - - reply(status, result); -} - (void)setUserCredentials:(NSString *)username password:(NSString *)password complete:(void (^)(bool success, NSError *error))complete { @@ -367,16 +331,7 @@ } - (void) deviceInfo:(nonnull void (^)(NSString * _Nullable, NSString * _Nullable, NSError * _Nullable))complete { -#if SECD_SERVER - __block NSString *deviceSerial = @""; - [self sosPeerSerial:^(NSString * _Nullable peerSerial) { - deviceSerial = peerSerial; - }]; - complete([SOSAuthKitHelpers machineID], deviceSerial, NULL); -#else complete(@"", @"", NULL); -#endif - } @@ -416,12 +371,6 @@ } } -// MARK: - CKKS -- (void)selfPeersForView:(NSString *)view complete:(void (^)(NSArray *result, NSError *error))complete -{ - complete(@[], NULL); -} - // MARK: - Octagon - (void)otReset:(NSString *)altDSID complete:(void (^)(bool success, NSError *_Nullable error))complete { diff --git a/keychain/Trieste/OctagonTestHarnessXPCService/SecRemoteDeviceProtocol.h b/keychain/Trieste/OctagonTestHarnessXPCService/SecRemoteDeviceProtocol.h index b2194038..22a41217 100644 --- a/keychain/Trieste/OctagonTestHarnessXPCService/SecRemoteDeviceProtocol.h +++ b/keychain/Trieste/OctagonTestHarnessXPCService/SecRemoteDeviceProtocol.h @@ -36,10 +36,6 @@ NS_ASSUME_NONNULL_BEGIN @protocol SecRemoteDeviceProtocol -// Local Keychain -- (void)secItemAdd:(NSDictionary *)input complete:(void (^)(OSStatus, NSDictionary * _Nullable))reply; -- (void)secItemCopyMatching:(NSDictionary *)input complete:(void (^)(OSStatus, NSArray* _Nullable))replyreply; - // SOS trust - (void)setUserCredentials:(NSString *)username password:(NSString *)password complete:(void (^)(bool success, NSError *error))complete; - (void)setupSOSCircle:(NSString *)username password:(NSString *)password complete:(void (^)(bool success, NSError *_Nullable error))complete; @@ -73,9 +69,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)diagnosticsCPUUsage:(void(^)(bool success, uint64_t user_usec, uint64_t sys_usec, NSError *_Nullable error))complete; - (void)diagnosticsDiskUsage:(void(^)(bool success, uint64_t usage, NSError * _Nullable error))complete; -// CKKS -- (void)selfPeersForView:(NSString *)view complete:(void (^)(NSArray *result, NSError *error))complete; - // Octagon - (void)otReset:(NSString *)altDSID complete:(void (^)(bool success, NSError *_Nullable error))complete; diff --git a/keychain/Trieste/OctagonTestHarnessXPCServiceProtocol/Sources/OctagonTestHarnessXPCServiceProtocol/include/OctagonTestHarnessXPCServiceProtocol.h b/keychain/Trieste/OctagonTestHarnessXPCServiceProtocol/Sources/OctagonTestHarnessXPCServiceProtocol/include/OctagonTestHarnessXPCServiceProtocol.h index af5f2089..9ca2bfe7 100644 --- a/keychain/Trieste/OctagonTestHarnessXPCServiceProtocol/Sources/OctagonTestHarnessXPCServiceProtocol/include/OctagonTestHarnessXPCServiceProtocol.h +++ b/keychain/Trieste/OctagonTestHarnessXPCServiceProtocol/Sources/OctagonTestHarnessXPCServiceProtocol/include/OctagonTestHarnessXPCServiceProtocol.h @@ -11,6 +11,19 @@ NS_ASSUME_NONNULL_BEGIN - (void)octagonPeerID:(NSString *)altDSID complete:(void (^)(NSString *, NSError *_Nullable))complete; - (void)octagonInCircle:(NSString *)altDSID complete:(void (^)(NSNumber *, NSError * _Nullable))complete; +// Local Keychain +- (void)secItemAdd:(NSDictionary *)input complete:(void (^)(NSNumber *, NSDictionary * _Nullable))reply; +- (void)secItemCopyMatching:(NSDictionary *)input complete:(void (^)(NSNumber *, NSArray* _Nullable))reply; +- (void)secItemDelete:(NSDictionary *)input complete:(void (^)(NSNumber *))reply; + + +// CloudServices +- (void)csAccountInfo:(NSDictionary *)info complete:(void (^)(NSDictionary * _Nullable, NSDictionary * _Nullable))reply; +- (void)csEnableInfo:(NSDictionary *)info complete:(void (^)(NSDictionary * _Nullable, NSDictionary * _Nullable))reply; +- (void)csUpdateInfo:(NSDictionary *)info complete:(void (^)(NSDictionary * _Nullable, NSDictionary * _Nullable))reply; +- (void)csDisableInfo:(NSDictionary *)info complete:(void (^)(NSDictionary * _Nullable, NSDictionary * _Nullable))reply; +- (void)csRecoverInfo:(NSDictionary *)info complete:(void (^)(NSDictionary * _Nullable, NSDictionary * _Nullable))reply; + @end NS_ASSUME_NONNULL_END diff --git a/keychain/TrustedPeersHelper/Client.swift b/keychain/TrustedPeersHelper/Client.swift index a7c5f127..0a062b79 100644 --- a/keychain/TrustedPeersHelper/Client.swift +++ b/keychain/TrustedPeersHelper/Client.swift @@ -89,7 +89,13 @@ class Client: TrustedPeersHelperProtocol { container.trustStatus(reply: reply) } catch { os_log("Trust status failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg) - reply(TrustedPeersHelperEgoPeerStatus(egoPeerID: nil, status: TPPeerStatus.unknown, viablePeerCountsByModelID: [:], isExcluded: false, isLocked: false), CKXPCSuitableError(error)) + reply(TrustedPeersHelperEgoPeerStatus(egoPeerID: nil, + status: TPPeerStatus.unknown, + viablePeerCountsByModelID: [:], + peerCountsByMachineID: [:], + isExcluded: false, + isLocked: false), + CKXPCSuitableError(error)) } } @@ -188,6 +194,21 @@ class Client: TrustedPeersHelperProtocol { } } + func fetchAllowedMachineIDs(withContainer container: String, context: String, reply: @escaping (Set?, Error?) -> Void) { + do { + let containerName = ContainerName(container: container, context: context) + os_log("Fetching allowed machineIDs for %@", log: tplogDebug, type: .default, containerName.description) + let container = try self.containerMap.findOrCreate(name: containerName) + container.fetchAllowedMachineIDs() { mids, error in + self.logComplete(function: "Fetched allowed machineIDs", container: container.name, error: error) + reply(mids, CKXPCSuitableError(error)) + } + } catch { + os_log("Fetching allowed machineIDs failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg) + reply(nil, CKXPCSuitableError(error)) + } + } + func fetchEgoEpoch(withContainer container: String, context: String, reply: @escaping (UInt64, Error?) -> Void) { do { let containerName = ContainerName(container: container, context: context) @@ -631,4 +652,19 @@ class Client: TrustedPeersHelperProtocol { reply(false, false, false, CKXPCSuitableError(error)) } } + + func getSupportAppInfo(withContainer container: String, context: String, reply: @escaping (Data?, Error?) -> Void) { + do { + let containerName = ContainerName(container: container, context: context) + os_log("getSupportInfo %d for %@", log: tplogDebug, type: .default, containerName.description) + let container = try self.containerMap.findOrCreate(name: containerName) + container.getSupportAppInfo { info, error in + reply(info, CKXPCSuitableError(error)) + } + } catch { + os_log("getSupportInfo failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg) + reply(nil, CKXPCSuitableError(error)) + } + + } } diff --git a/keychain/TrustedPeersHelper/Container.swift b/keychain/TrustedPeersHelper/Container.swift index c64e51b8..fffd68b1 100644 --- a/keychain/TrustedPeersHelper/Container.swift +++ b/keychain/TrustedPeersHelper/Container.swift @@ -98,6 +98,7 @@ public enum ContainerError: Error { case invalidPeerID case failedToStoreSecret(errorCode: Int) case unknownSecurityFoundationError + case failedToSerializeData } extension ContainerError: LocalizedError { @@ -185,6 +186,8 @@ extension ContainerError: LocalizedError { return "failed to store the secret in the keychain \(errorCode)" case .unknownSecurityFoundationError: return "SecurityFoundation returned an unknown type" + case .failedToSerializeData: + return "Failed to encode protobuf data" } } } @@ -281,6 +284,8 @@ extension ContainerError: CustomNSError { return 42 case .unknownSecurityFoundationError: return 43 + case .failedToSerializeData: + return 44 } } @@ -849,6 +854,7 @@ class Container: NSObject { func onQueueDetermineLocalTrustStatus(reply: @escaping (TrustedPeersHelperEgoPeerStatus, Error?) -> Void) { let viablePeerCountsByModelID = self.model.viablePeerCountsByModelID() + let peerCountsByMachineID = self.model.peerCountsByMachineID() if let egoPeerID = self.containerMO.egoPeerID { var status = self.model.statusOfPeer(withID: egoPeerID) @@ -875,6 +881,7 @@ class Container: NSObject { let egoStatus = TrustedPeersHelperEgoPeerStatus(egoPeerID: egoPeerID, status: status, viablePeerCountsByModelID: viablePeerCountsByModelID, + peerCountsByMachineID: peerCountsByMachineID, isExcluded: isExcluded, isLocked: isLocked) reply(egoStatus, returnError) @@ -887,6 +894,7 @@ class Container: NSObject { let egoStatus = TrustedPeersHelperEgoPeerStatus(egoPeerID: egoPeerID, status: .excluded, viablePeerCountsByModelID: viablePeerCountsByModelID, + peerCountsByMachineID: peerCountsByMachineID, isExcluded: true, isLocked: false) @@ -897,6 +905,7 @@ class Container: NSObject { let egoStatus = TrustedPeersHelperEgoPeerStatus(egoPeerID: egoPeerID, status: status, viablePeerCountsByModelID: viablePeerCountsByModelID, + peerCountsByMachineID: peerCountsByMachineID, isExcluded: isExcluded, isLocked: false) reply(egoStatus, nil) @@ -910,6 +919,7 @@ class Container: NSObject { let egoStatus = TrustedPeersHelperEgoPeerStatus(egoPeerID: nil, status: .unknown, viablePeerCountsByModelID: viablePeerCountsByModelID, + peerCountsByMachineID: peerCountsByMachineID, isExcluded: false, isLocked: false) reply(egoStatus, nil) @@ -919,6 +929,7 @@ class Container: NSObject { let egoStatus = TrustedPeersHelperEgoPeerStatus(egoPeerID: nil, status: .excluded, viablePeerCountsByModelID: viablePeerCountsByModelID, + peerCountsByMachineID: peerCountsByMachineID, isExcluded: true, isLocked: false) reply(egoStatus, nil) @@ -950,6 +961,7 @@ class Container: NSObject { let egoStatus = TrustedPeersHelperEgoPeerStatus(egoPeerID: nil, status: .unknown, viablePeerCountsByModelID: [:], + peerCountsByMachineID: [:], isExcluded: false, isLocked: false) reply(egoStatus, fetchError) @@ -2995,6 +3007,33 @@ class Container: NSObject { } } + func getSupportAppInfo(reply: @escaping (Data?, Error?) -> Void) { + self.semaphore.wait() + let reply: (Data?, Error?) -> Void = { + os_log("getSupportAppInfo complete: %@", log: tplogTrace, type: .info, traceError($1)) + self.semaphore.signal() + reply($0, $1) + } + + self.cuttlefish.getSupportAppInfo { response, error in + os_log("getSupportAppInfo(): %@, error: %@", log: tplogDebug, + "(\(String(describing: response))", "\(String(describing: error))") + guard let response = response, error == nil else { + os_log("getSupportAppInfo failed: %@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "no error") + reply(nil, error ?? ContainerError.cloudkitResponseMissing) + return + } + + guard let data = try? response.serializedData() else { + reply(nil, ContainerError.failedToSerializeData) + return + } + + reply(data, nil) + } + + } + func preflightPreapprovedJoin(reply: @escaping (Bool, Error?) -> Void) { self.semaphore.wait() let reply: (Bool, Error?) -> Void = { diff --git a/keychain/TrustedPeersHelper/Container_MachineIDs.swift b/keychain/TrustedPeersHelper/Container_MachineIDs.swift index 0e5f5c8c..0a8dd0bc 100644 --- a/keychain/TrustedPeersHelper/Container_MachineIDs.swift +++ b/keychain/TrustedPeersHelper/Container_MachineIDs.swift @@ -293,6 +293,24 @@ extension Container { } } + func fetchAllowedMachineIDs(reply: @escaping (Set?, Error?) -> Void) { + self.semaphore.wait() + let reply: (Set?, Error?) -> Void = { + os_log("fetchAllowedMachineIDs complete: %@", log: tplogTrace, type: .info, traceError($1)) + self.semaphore.signal() + reply($0, $1) + } + + os_log("Fetching allowed machine IDs", log: tplogDebug, type: .default) + + self.moc.performAndWait { + let knownMachines = containerMO.machines as? Set ?? Set() + let allowedMachineIDs = knownMachines.filter { $0.status == Int64(TPMachineIDStatus.allowed.rawValue) }.compactMap({ $0.machineID }) + + reply(Set(allowedMachineIDs), nil) + } + } + func onqueueMachineIDAllowedByIDMS(machineID: String) -> Bool { // For Demo accounts, if the list is entirely empty, then everything is allowed let machines = containerMO.machines as? Set ?? Set() diff --git a/keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h b/keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h index be36cc1f..197d419b 100644 --- a/keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h +++ b/keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h @@ -69,12 +69,17 @@ NS_ASSUME_NONNULL_BEGIN // Note: this field does not include untrusted peers @property NSDictionary* viablePeerCountsByModelID; + +// Note: this field does include untrusted peers +@property NSDictionary* peerCountsByMachineID; + @property BOOL isExcluded; @property BOOL isLocked; - (instancetype)initWithEgoPeerID:(NSString* _Nullable)egoPeerID status:(TPPeerStatus)egoStatus viablePeerCountsByModelID:(NSDictionary*)viablePeerCountsByModelID + peerCountsByMachineID:(NSDictionary*)peerCountsByMachineID isExcluded:(BOOL)isExcluded isLocked:(BOOL)isLocked; @@ -136,6 +141,10 @@ NS_ASSUME_NONNULL_BEGIN machineIDs:(NSArray *)machineIDs reply:(void (^)(NSError * _Nullable error))reply; +- (void)fetchAllowedMachineIDsWithContainer:(NSString *)container + context:(NSString *)context + reply:(void (^)(NSSet* _Nullable machineIDs, NSError* _Nullable error))reply; + - (void)fetchEgoEpochWithContainer:(NSString *)container context:(NSString *)context reply:(void (^)(unsigned long long epoch, @@ -336,6 +345,11 @@ NS_ASSUME_NONNULL_BEGIN context:(NSString *)context requiresEscrowCheck:(BOOL)requiresEscrowCheck reply:(void (^)(BOOL postRepairCFU, BOOL postEscrowCFU, BOOL resetOctagon, NSError* _Nullable))reply; + +- (void)getSupportAppInfoWithContainer:(NSString *)container + context:(NSString *)context + reply:(void (^)(NSData * _Nullable, NSError * _Nullable))reply; + @end /* diff --git a/keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.m b/keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.m index f04ac68e..66031113 100644 --- a/keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.m +++ b/keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.m @@ -205,6 +205,7 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface) - (instancetype)initWithEgoPeerID:(NSString* _Nullable)egoPeerID status:(TPPeerStatus)egoStatus viablePeerCountsByModelID:(NSDictionary*)viablePeerCountsByModelID + peerCountsByMachineID:(NSDictionary * _Nonnull)peerCountsByMachineID isExcluded:(BOOL)isExcluded isLocked:(BOOL)isLocked { @@ -212,6 +213,7 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface) _egoPeerID = egoPeerID; _egoStatus = egoStatus; _viablePeerCountsByModelID = viablePeerCountsByModelID; + _peerCountsByMachineID = peerCountsByMachineID; _numberOfPeersInOctagon = 0; for(NSNumber* n in viablePeerCountsByModelID.allValues) { _numberOfPeersInOctagon += [n unsignedIntegerValue]; @@ -241,6 +243,8 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface) _numberOfPeersInOctagon += [n unsignedIntegerValue]; } + _peerCountsByMachineID = [coder decodeObjectOfClasses:[NSSet setWithArray:@[[NSDictionary class], [NSString class], [NSNumber class]]] forKey:@"peerCountsByMachineID"]; + _isExcluded = (BOOL)[coder decodeBoolForKey:@"isExcluded"]; _isLocked = (BOOL)[coder decodeBoolForKey:@"isLocked"]; } @@ -251,6 +255,7 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface) [coder encodeObject:self.egoPeerID forKey:@"peerID"]; [coder encodeInt64:self.egoStatus forKey:@"egoStatus"]; [coder encodeObject:self.viablePeerCountsByModelID forKey:@"viablePeerCountsByModelID"]; + [coder encodeObject:self.peerCountsByMachineID forKey:@"peerCountsByMachineID"]; [coder encodeBool:self.isExcluded forKey:@"isExcluded"]; [coder encodeBool:self.isLocked forKey:@"isLocked"]; } diff --git a/keychain/TrustedPeersHelperUnitTests/ContainerSync.swift b/keychain/TrustedPeersHelperUnitTests/ContainerSync.swift index 30916147..f3b3eb19 100644 --- a/keychain/TrustedPeersHelperUnitTests/ContainerSync.swift +++ b/keychain/TrustedPeersHelperUnitTests/ContainerSync.swift @@ -249,6 +249,19 @@ extension Container { return reterr } + func fetchAllowedMachineIDsSync(test: XCTestCase) -> (Set?, Error?) { + let expectation = XCTestExpectation(description: "fetchMIDList replied") + var retlist: Set? + var reterr: Error? + self.fetchAllowedMachineIDs() { list, err in + retlist = list + reterr = err + expectation.fulfill() + } + test.wait(for: [expectation], timeout: 10.0) + return (retlist, reterr) + } + func departByDistrustingSelfSync(test: XCTestCase) -> Error? { let expectation = XCTestExpectation(description: "departByDistrustingSelf replied") var reterr: Error? @@ -322,7 +335,12 @@ extension Container { func trustStatusSync(test: XCTestCase) -> (TrustedPeersHelperEgoPeerStatus, Error?) { let expectation = XCTestExpectation(description: "trustStatus replied") - var retEgoStatus = TrustedPeersHelperEgoPeerStatus(egoPeerID: nil, status: .unknown, viablePeerCountsByModelID: [:], isExcluded: false, isLocked: false) + var retEgoStatus = TrustedPeersHelperEgoPeerStatus(egoPeerID: nil, + status: .unknown, + viablePeerCountsByModelID: [:], + peerCountsByMachineID: [:], + isExcluded: false, + isLocked: false) var reterror: Error? self.trustStatus { egoStatus, error in retEgoStatus = egoStatus diff --git a/keychain/TrustedPeersHelperUnitTests/TrustedPeersHelperUnitTests.swift b/keychain/TrustedPeersHelperUnitTests/TrustedPeersHelperUnitTests.swift index 0516c23a..7d7ecae1 100644 --- a/keychain/TrustedPeersHelperUnitTests/TrustedPeersHelperUnitTests.swift +++ b/keychain/TrustedPeersHelperUnitTests/TrustedPeersHelperUnitTests.swift @@ -2018,6 +2018,11 @@ class TrustedPeersHelperUnitTests: XCTestCase { XCTAssertEqual(midList.machineIDs(in: .disallowed), disallowedMachineIDs, "List of disallowed machine IDs should match") XCTAssertEqual(midList.machineIDs(in: .unknown), unknownMachineIDs, "List of unknown machine IDs should match") + + let (fetchedAllowList, fetchErr) = container.fetchAllowedMachineIDsSync(test: self) + XCTAssertNil(fetchErr, "Should be no error fetching the allowed list") + XCTAssertEqual(fetchedAllowList, allowedMachineIDs, "A fetched list of allowed machine IDs should match the loaded list") + // if we reload the container, does it still match? let reloadedContainer = try Container(name: ContainerName(container: "test", context: OTDefaultContext), persistentStoreDescription: persistentStore, cuttlefish: cuttlefish) @@ -2399,8 +2404,6 @@ class TrustedPeersHelperUnitTests: XCTestCase { try self.assert(container: container, allowedMachineIDs: Set([]), disallowedMachineIDs: [], unknownMachineIDs: Set([]), persistentStore: description, cuttlefish: self.cuttlefish) XCTAssertFalse(container.onqueueFullIDMSListWouldBeHelpful(), "Container shouldn't think it could use an IDMS list set") - - } func testContainerAndModelConsistency() throws { diff --git a/keychain/ckks/CKKS.h b/keychain/ckks/CKKS.h index 88584fcb..50070ebc 100644 --- a/keychain/ckks/CKKS.h +++ b/keychain/ckks/CKKS.h @@ -362,7 +362,7 @@ typedef CF_ENUM(CFIndex, CKKSResultDescriptionErrorCode) { typedef CF_ENUM(CFIndex, CKKSServerExtensionErrorCode) { // Generic Errors //CKKSServerMissingField = 1, - //CKKSServerMissingRecord = 2, + CKKSServerMissingRecord = 2, //CKKSServerUnexpectedFieldType = 3, //CKKSServerUnexpectedRecordType = 4, //CKKSServerUnepxectedRecordID = 5, diff --git a/keychain/ckks/CKKSAnalytics.h b/keychain/ckks/CKKSAnalytics.h index dd876eaf..6c80b5c5 100644 --- a/keychain/ckks/CKKSAnalytics.h +++ b/keychain/ckks/CKKSAnalytics.h @@ -41,6 +41,7 @@ extern NSString* const CKKSAnalyticsLastInCircle; extern NSString* const OctagonAnalyticsStateMachineState; extern NSString* const OctagonAnalyticIcloudAccountState; extern NSString* const OctagonAnalyticsTrustState; +extern NSString* const OctagonAnalyticsAttemptedJoin; extern NSString* const OctagonAnalyticsLastHealthCheck; extern NSString* const OctagonAnalyticsSOSStatus; extern NSString* const OctagonAnalyticsDateOfLastPreflightPreapprovedJoin; @@ -51,6 +52,10 @@ extern NSString* const OctagonAnalyticsCoreFollowupLastFailureTime; extern NSString* const OctagonAnalyticsPrerecordPending; extern NSString* const OctagonAnalyticsCDPStateRun; +extern NSString* const OctagonAnalyticsHaveMachineID; +extern NSString* const OctagonAnalyticsMIDOnMemoizedList; +extern NSString* const OctagonAnalyticsPeersWithMID; + extern NSString* const CKKSAnalyticsLastCKKSPush; extern NSString* const CKKSAnalyticsLastOctagonPush; @@ -159,6 +164,8 @@ extern CKKSAnalyticsFailableEvent* const OctagonEventCompanionPairing; /* trust state from trusted peers helper*/ extern CKKSAnalyticsFailableEvent* const OctagonEventTPHHealthCheckStatus; +extern CKKSAnalyticsFailableEvent* const OctagonEventAuthKitDeviceList; + @protocol CKKSAnalyticsSignpostEvent @end typedef NSString CKKSAnalyticsSignpostEvent; diff --git a/keychain/ckks/CKKSAnalytics.m b/keychain/ckks/CKKSAnalytics.m index ce66283d..dea0502b 100644 --- a/keychain/ckks/CKKSAnalytics.m +++ b/keychain/ckks/CKKSAnalytics.m @@ -50,6 +50,7 @@ NSString* const CKKSAnalyticsLastInCircle = @"lastInCircle"; NSString* const OctagonAnalyticsStateMachineState = @"OASMState"; NSString* const OctagonAnalyticIcloudAccountState = @"OAiC"; NSString* const OctagonAnalyticsTrustState = @"OATrust"; +NSString* const OctagonAnalyticsAttemptedJoin = @"OAAttemptedJoin"; NSString* const OctagonAnalyticsLastHealthCheck = @"OAHealthCheck"; NSString* const OctagonAnalyticsSOSStatus = @"OASOSStatus"; NSString* const OctagonAnalyticsDateOfLastPreflightPreapprovedJoin = @"OALastPPJ"; @@ -61,6 +62,10 @@ NSString* const OctagonAnalyticsCoreFollowupLastFailureTime = @"OACFULastFailure NSString* const OctagonAnalyticsPrerecordPending = @"OAPrerecordPending"; NSString* const OctagonAnalyticsCDPStateRun = @"OACDPStateRun"; +NSString* const OctagonAnalyticsHaveMachineID = @"OAMIDPresent"; +NSString* const OctagonAnalyticsMIDOnMemoizedList = @"OAMIDOnList"; +NSString* const OctagonAnalyticsPeersWithMID = @"OAPeersWithMID"; + NSString* const CKKSAnalyticsLastCKKSPush = @"lastCKKSPush"; NSString* const CKKSAnalyticsLastOctagonPush = @"lastOctagonPush"; @@ -154,6 +159,8 @@ CKKSAnalyticsSignpostEvent* const CKKSEventReachabilityTimerExpired = (CKKSAnaly CKKSAnalyticsFailableEvent* const OctagonEventTPHHealthCheckStatus = (CKKSAnalyticsFailableEvent*)@"OctagonEventTPHHealthCheckStatus"; +CKKSAnalyticsFailableEvent* const OctagonEventAuthKitDeviceList = (CKKSAnalyticsFailableEvent *)@"OctagonEventAuthKitDeviceList"; + CKKSAnalyticsActivity* const CKKSActivityOTFetchRampState = (CKKSAnalyticsActivity *)@"CKKSActivityOTFetchRampState"; CKKSAnalyticsActivity* const CKKSActivityOctagonPreflightBottle = (CKKSAnalyticsActivity *)@"CKKSActivityOctagonPreflightBottle"; CKKSAnalyticsActivity* const CKKSActivityOctagonLaunchBottle = (CKKSAnalyticsActivity *)@"CKKSActivityOctagonLaunchBottle"; diff --git a/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.h b/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.h index 763195b2..ae8a2d95 100644 --- a/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.h +++ b/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.h @@ -60,8 +60,10 @@ extern CKKSFetchBecause* const CKKSFetchBecauseResync; @end @class CKKSCloudKitDeletion; + @protocol CKKSChangeFetcherClient - (CKRecordZoneID*)zoneID; +- (BOOL)zoneIsReadyForFetching; - (CKKSCloudKitFetchRequest*)participateInFetch; // Return false if this is a 'fatal' error and you don't want another fetch to be tried diff --git a/keychain/ckks/CKKSKeychainView.m b/keychain/ckks/CKKSKeychainView.m index 1bbb06cd..3e7a16fe 100644 --- a/keychain/ckks/CKKSKeychainView.m +++ b/keychain/ckks/CKKSKeychainView.m @@ -2809,8 +2809,14 @@ return nil; } + CKKSResultOperation *fetchOp = [self.zoneChangeFetcher requestFetchDueToAPNS:notification]; + if (fetchOp == nil) { + ckksnotice("ckks", self, "Skipping push induced processCKChanges due to zones are not ready"); + return nil; + } + // We fetched some changes; try to process them! - return [self processIncomingQueue:false after:[self.zoneChangeFetcher requestSuccessfulFetchDueToAPNS:notification]]; + return [self processIncomingQueue:false after:fetchOp]; } // Lets the view know about a failed CloudKit write. If the error is "already have one of these records", it will @@ -2875,6 +2881,13 @@ // Issue a key hierarchy fetch and see what's what. ckkserror("ckks", self, "CKKS Server extension has told us about %@ for record %@; requesting refetch and reprocess of key hierarchy", thirdLevelError, recordID); [self _onqueueKeyStateMachineRequestFetch]; + + } else if(thirdLevelError.code == CKKSServerMissingRecord) { + // The server is concerned that there's a missing record somewhere. + // Issue a key hierarchy fetch and see what's happening + ckkserror("ckks", self, "CKKS Server extension has told us about %@ for record %@; requesting refetch and reprocess of key hierarchy", thirdLevelError, recordID); + [self _onqueueKeyStateMachineRequestFetch]; + } else { ckkserror("ckks", self, "CKKS Server extension has told us about %@ for record %@, but we don't currently handle this error", thirdLevelError, recordID); } @@ -3807,19 +3820,39 @@ #pragma mark - CKKSChangeFetcherClient +- (BOOL)zoneIsReadyForFetching +{ + __block BOOL ready = NO; + + [self dispatchSync: ^bool { + ready = (bool)[self _onQueueZoneIsReadyForFetching]; + return ready; + }]; + + return ready; +} + +- (BOOL)_onQueueZoneIsReadyForFetching +{ + if(self.accountStatus != CKKSAccountStatusAvailable) { + ckksnotice("ckksfetch", self, "Not participating in fetch: not logged in"); + return NO; + } + + if(!self.zoneCreated) { + ckksnotice("ckksfetch", self, "Not participating in fetch: zone not created yet"); + return NO; + } + return YES; +} + - (CKKSCloudKitFetchRequest*)participateInFetch { __block CKKSCloudKitFetchRequest* request = [[CKKSCloudKitFetchRequest alloc] init]; - [self dispatchSync: ^bool { - if(self.accountStatus != CKKSAccountStatusAvailable) { - ckksnotice("ckksfetch", self, "Not participating in fetch: not logged in"); - request.participateInFetch = false; - return false; - } - if(!self.zoneCreated) { - ckksnotice("ckksfetch", self, "Not participating in fetch: zone not created yet"); - request.participateInFetch = false; + [self dispatchSync: ^bool { + if (![self _onQueueZoneIsReadyForFetching]) { + ckksnotice("ckksfetch", self, "skipping fetch since zones are not ready"); return false; } @@ -3963,6 +3996,9 @@ NSError* error = nil; [self _onqueueResetLocalData:&error]; + // We need to rescan the local keychain once we return to a good state + self.droppedItems = true; + if(error) { ckksnotice("ckksreset", self, "CloudKit-inspired local reset of %@ ended with error: %@", self.zoneID, error); } else { diff --git a/keychain/ckks/CKKSNearFutureScheduler.h b/keychain/ckks/CKKSNearFutureScheduler.h index e84f7f59..e034f438 100644 --- a/keychain/ckks/CKKSNearFutureScheduler.h +++ b/keychain/ckks/CKKSNearFutureScheduler.h @@ -82,6 +82,9 @@ NS_ASSUME_NONNULL_BEGIN - (void)changeDelays:(dispatch_time_t)initialDelay continuingDelay:(dispatch_time_t)continuingDelay; +// tests +@property CKKSCondition* liveRequestReceived; + @end NS_ASSUME_NONNULL_END diff --git a/keychain/ckks/CKKSNearFutureScheduler.m b/keychain/ckks/CKKSNearFutureScheduler.m index 815b2197..162af55d 100644 --- a/keychain/ckks/CKKSNearFutureScheduler.m +++ b/keychain/ckks/CKKSNearFutureScheduler.m @@ -45,7 +45,6 @@ @property NSDate* predictedNextFireTime; @property bool liveRequest; -@property CKKSCondition* liveRequestReceived; // Triggered when liveRequest goes to true. @property dispatch_source_t timer; @property dispatch_queue_t queue; diff --git a/keychain/ckks/CKKSOutgoingQueueOperation.m b/keychain/ckks/CKKSOutgoingQueueOperation.m index c1d3810d..940cf26a 100644 --- a/keychain/ckks/CKKSOutgoingQueueOperation.m +++ b/keychain/ckks/CKKSOutgoingQueueOperation.m @@ -35,6 +35,7 @@ #import "CKKSReencryptOutgoingItemsOperation.h" #import "CKKSManifest.h" #import "CKKSAnalytics.h" +#import "keychain/ckks/CloudKitCategories.h" #import "keychain/ot/ObjCImprovements.h" #include "keychain/securityd/SecItemServer.h" @@ -343,6 +344,12 @@ ckksnotice("ckksoutgoing", strongCKKS, "Error is simply due to current key pointers changing; marking all records as 'needs reencrypt'"); [self _onqueueModifyAllRecords:failedRecords.allKeys as:SecCKKSStateReencrypt]; askForReencrypt = true; + + } else if([self _onqueueIsErrorMissingSyncKey:ckerror]) { + ckksnotice("ckksoutgoing", strongCKKS, "Error is due to the key records missing. Marking all as 'needs reencrypt'"); + [self _onqueueModifyAllRecords:failedRecords.allKeys as:SecCKKSStateReencrypt]; + askForReencrypt = true; + } else { // Iterate all failures, and reset each item for(CKRecordID* recordID in failedRecords) { @@ -616,6 +623,23 @@ } } +- (BOOL)_onqueueIsErrorMissingSyncKey:(NSError*)ckerror { + if([ckerror.domain isEqualToString:CKErrorDomain] && (ckerror.code == CKErrorPartialFailure)) { + NSMutableDictionary* failedRecords = ckerror.userInfo[CKPartialErrorsByItemIDKey]; + + for(CKRecordID* recordID in failedRecords) { + NSError* recordError = failedRecords[recordID]; + + if([recordError isCKKSServerPluginError:CKKSServerMissingRecord]) { + secnotice("ckksoutgoing", "Error is a 'missing record' error: %@", recordError); + return YES; + } + } + } + + return NO; +} + - (bool)_onqueueIsErrorBadEtagOnKeyPointersOnly:(NSError*)ckerror { bool anyOtherErrors = false; diff --git a/keychain/ckks/CKKSPBFileStorage.h b/keychain/ckks/CKKSPBFileStorage.h new file mode 100644 index 00000000..90fd08e3 --- /dev/null +++ b/keychain/ckks/CKKSPBFileStorage.h @@ -0,0 +1,29 @@ +// +// CKKSPBFileStorage.h +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + + +@protocol CKKSPBCodable +@property (nonatomic, readonly) NSData *data; ++ (instancetype)alloc; +- (id)initWithData:(NSData*)data; +@end + +@interface CKKSPBFileStorage<__covariant CKKSConfigurationStorageType : PBCodable *> : NSObject + +- (CKKSPBFileStorage *)initWithStoragePath:(NSURL *)storageFile + storageClass:(Class)storageClass; + +- (CKKSConfigurationStorageType _Nullable)storage; +- (void)setStorage:(CKKSConfigurationStorageType _Nonnull)storage; +@end + +@interface PBCodable () +@end + +NS_ASSUME_NONNULL_END diff --git a/keychain/ckks/CKKSPBFileStorage.m b/keychain/ckks/CKKSPBFileStorage.m new file mode 100644 index 00000000..a7ef6283 --- /dev/null +++ b/keychain/ckks/CKKSPBFileStorage.m @@ -0,0 +1,56 @@ +// +// CKKSPBFileStorage.m +// + +#import "keychain/ckks/CKKSPBFileStorage.h" + +@interface CKKSPBFileStorage () +@property NSURL *storageFile; +@property Class storageClass; +@property id protobufStorage; +@end + +@implementation CKKSPBFileStorage + +- (CKKSPBFileStorage *)initWithStoragePath:(NSURL *)storageFile + storageClass:(Class) storageClass +{ + if ((self = [super init]) == nil) { + return nil; + } + self.storageFile = storageFile; + self.storageClass = storageClass; + + NSData *data = [NSData dataWithContentsOfURL:storageFile]; + if (data != nil) { + self.protobufStorage = [[self.storageClass alloc] initWithData:data]; + } + /* if not storage, or storage is corrupted, this function will return a empty storage */ + if (self.protobufStorage == nil) { + self.protobufStorage = [[self.storageClass alloc] init]; + } + + return self; +} + +- (id _Nullable)storage +{ + __block id storage; + @synchronized (self) { + storage = self.protobufStorage; + } + return storage; +} + +- (void)setStorage:(id _Nonnull)storage +{ + @synchronized (self) { + id c = storage; + NSData *data = c.data; + [data writeToURL:self.storageFile atomically:YES]; + self.protobufStorage = [[self.storageClass alloc] initWithData:data]; + } +} + + +@end diff --git a/keychain/ckks/CKKSResultOperation.h b/keychain/ckks/CKKSResultOperation.h index 95a14286..5b29fccc 100644 --- a/keychain/ckks/CKKSResultOperation.h +++ b/keychain/ckks/CKKSResultOperation.h @@ -66,8 +66,8 @@ enum { // Convenience constructor. + (instancetype)operationWithBlock:(void (^)(void))block; -+ (instancetype)named:(NSString*)name withBlock:(void (^)(void))block; -+ (instancetype)named:(NSString*)name withBlockTakingSelf:(void(^)(CKKSResultOperation* op))block; ++ (instancetype)named:(NSString*)name withBlock:(void (^)(void))block NS_SWIFT_NAME(init(name:block:)); ++ (instancetype)named:(NSString*)name withBlockTakingSelf:(void(^)(CKKSResultOperation* op))block NS_SWIFT_NAME(init(name:blockTakingSelf:)); // Determine if all these operations were successful, and set this operation's result if not. - (bool)allSuccessful:(NSArray*)operations; diff --git a/keychain/ckks/CKKSResultOperation.m b/keychain/ckks/CKKSResultOperation.m index 1c107b4f..57417657 100644 --- a/keychain/ckks/CKKSResultOperation.m +++ b/keychain/ckks/CKKSResultOperation.m @@ -268,6 +268,7 @@ op.name = name; return op; } + @end #endif // OCTAGON diff --git a/keychain/ckks/CKKSZoneChangeFetcher.h b/keychain/ckks/CKKSZoneChangeFetcher.h index d1e60c14..08510fb2 100644 --- a/keychain/ckks/CKKSZoneChangeFetcher.h +++ b/keychain/ckks/CKKSZoneChangeFetcher.h @@ -55,7 +55,9 @@ NS_ASSUME_NONNULL_BEGIN - (CKKSResultOperation*)requestSuccessfulFetch:(CKKSFetchBecause*)why; - (CKKSResultOperation*)requestSuccessfulFetchForManyReasons:(NSSet*)why; -- (CKKSResultOperation*)requestSuccessfulFetchDueToAPNS:(CKRecordZoneNotification*)notification; + +// let server know we seen this push and if zones are ready actually perform a fetch +- (CKKSResultOperation* _Nullable)requestFetchDueToAPNS:(CKRecordZoneNotification*)notification; // We don't particularly care what this does, as long as it finishes - (void)holdFetchesUntil:(CKKSResultOperation* _Nullable)holdOperation; diff --git a/keychain/ckks/CKKSZoneChangeFetcher.m b/keychain/ckks/CKKSZoneChangeFetcher.m index 0ec4cff4..ead140b9 100644 --- a/keychain/ckks/CKKSZoneChangeFetcher.m +++ b/keychain/ckks/CKKSZoneChangeFetcher.m @@ -169,31 +169,41 @@ CKKSFetchBecause* const CKKSFetchBecauseMoreComing = (CKKSFetchBecause*) @"more- } } +- (NSArray>*)clients { + NSMutableArray> *clients = [NSMutableArray array]; + @synchronized (self.clientMap) { + for(id client in [self.clientMap objectEnumerator]) { + if (client) { + [clients addObject:client]; + } + } + } + return clients; +} - (CKKSResultOperation*)requestSuccessfulFetch:(CKKSFetchBecause*)why { return [self requestSuccessfulFetchForManyReasons:[NSSet setWithObject:why]]; } -- (CKKSResultOperation*)requestSuccessfulFetchForManyReasons:(NSSet*)why +- (CKKSResultOperation*)requestFetchDueToAPNS:(CKRecordZoneNotification*)notification { - return [self requestSuccessfulFetchForManyReasons:why apns:nil]; -} + __block BOOL notReady = YES; -- (CKKSResultOperation*)requestSuccessfulFetchDueToAPNS:(CKRecordZoneNotification*)notification -{ - return [self requestSuccessfulFetchForManyReasons:[NSSet setWithObject:CKKSFetchBecauseAPNS] apns:notification]; -} + // make sure we don't hold the self.queue when we call out to clients since that will lead + // to lock inversions + + NSArray> *clients = [self clients]; + + for(id client in clients) { + if([client zoneIsReadyForFetching]) { + notReady = NO; + } + } -- (CKKSResultOperation*)requestSuccessfulFetchForManyReasons:(NSSet*)why apns:(CKRecordZoneNotification*)notification -{ - __block CKKSResultOperation* dependency = nil; dispatch_sync(self.queue, ^{ - dependency = self.successfulFetchDependency; - self.newRequests = true; - [self.currentFetchReasons unionSet:why]; + if(notification) { [self.apnsPushes addObject:notification]; - if(notification.ckksPushTracingEnabled) { // Report that we saw this notification before doing anything else secnotice("ckksfetch", "Submitting initial CKEventMetric due to notification %@", notification); @@ -203,6 +213,7 @@ CKKSFetchBecause* const CKKSFetchBecauseMoreComing = (CKKSFetchBecause*) @"more- metric[@"push_token_uuid"] = notification.ckksPushTracingUUID; metric[@"push_received_date"] = notification.ckksPushReceivedDate; metric[@"push_event_name"] = @"CKKS APNS Push Received"; + metric[@"zones_status"] = notReady ? @"not-ready" : @"ready"; [self.container submitEventMetric:metric]; @@ -210,13 +221,30 @@ CKKSFetchBecause* const CKKSFetchBecauseMoreComing = (CKKSFetchBecause*) @"more- metric2[@"push_token_uuid"] = notification.ckksPushTracingUUID; metric2[@"push_received_date"] = notification.ckksPushReceivedDate; metric2[@"push_event_name"] = @"CKKS APNS Push Received-webtunnel"; + metric[@"zones_status"] = notReady ? @"not-ready" : @"ready"; [[SecMetrics managerObject] submitEvent:metric2]; - } - } + }); + + if (notReady) { + secnotice("ckksfetch", "Skipping fetching size no zone is ready"); + return NULL; + } + + return [self requestSuccessfulFetchForManyReasons:[NSSet setWithObject:CKKSFetchBecauseAPNS]]; +} + +- (CKKSResultOperation*)requestSuccessfulFetchForManyReasons:(NSSet*)why +{ + __block CKKSResultOperation* dependency = nil; + dispatch_sync(self.queue, ^{ + dependency = self.successfulFetchDependency; + self.newRequests = true; + [self.currentFetchReasons unionSet:why]; + [self.fetchScheduler trigger]; }); @@ -256,14 +284,7 @@ CKKSFetchBecause* const CKKSFetchBecauseMoreComing = (CKKSFetchBecause*) @"more- CKOperationGroup* operationGroup = [CKOperationGroup CKKSGroupWithName: reasonsString]; - NSMutableArray>* clients = [NSMutableArray array]; - @synchronized(self.clientMap) { - for(id client in [self.clientMap objectEnumerator]) { - if(client != nil) { - [clients addObject:client]; - } - } - } + NSArray> *clients = [self clients]; if(clients.count == 0u) { secnotice("ckksfetcher", "No clients"); diff --git a/keychain/ckks/CKKSZoneModifier.m b/keychain/ckks/CKKSZoneModifier.m index d8afc74b..58905c26 100644 --- a/keychain/ckks/CKKSZoneModifier.m +++ b/keychain/ckks/CKKSZoneModifier.m @@ -189,9 +189,9 @@ CKDatabaseOperation* modifyZonesOperation = [self createModifyZonesOperation:ops]; CKDatabaseOperation* zoneSubscriptionOperation = [self createModifySubscriptionsOperation:ops]; - [self.operationQueue addOperation:modifyZonesOperation]; + [self.database addOperation:modifyZonesOperation]; if(zoneSubscriptionOperation) { - [self.operationQueue addOperation:zoneSubscriptionOperation]; + [self.database addOperation:zoneSubscriptionOperation]; } }); } diff --git a/keychain/ckks/CloudKitCategories.h b/keychain/ckks/CloudKitCategories.h index 2bf92f57..c7995009 100644 --- a/keychain/ckks/CloudKitCategories.h +++ b/keychain/ckks/CloudKitCategories.h @@ -42,6 +42,8 @@ NS_ASSUME_NONNULL_BEGIN - (bool)ckksIsCKErrorRecordChangedError; - (BOOL)isCuttlefishError:(CuttlefishErrorCode)cuttlefishError; - (NSTimeInterval)cuttlefishRetryAfter; + +- (BOOL)isCKKSServerPluginError:(NSInteger)code; @end // Ensure we don't print addresses @interface CKAccountInfo (CKKS) diff --git a/keychain/ckks/CloudKitCategories.m b/keychain/ckks/CloudKitCategories.m index 22f57597..50bb8904 100644 --- a/keychain/ckks/CloudKitCategories.m +++ b/keychain/ckks/CloudKitCategories.m @@ -92,6 +92,22 @@ return 0; } + +- (BOOL)isCKKSServerPluginError:(NSInteger)code +{ + NSError* underlyingError = self.userInfo[NSUnderlyingErrorKey]; + NSError* thirdLevelError = underlyingError.userInfo[NSUnderlyingErrorKey]; + + return ([self.domain isEqualToString:CKErrorDomain] && + self.code == CKErrorServerRejectedRequest && + underlyingError && + [underlyingError.domain isEqualToString:CKInternalErrorDomain] && + underlyingError.code == CKErrorInternalPluginError && + thirdLevelError && + [thirdLevelError.domain isEqualToString:@"CloudkitKeychainService"] && + thirdLevelError.code == code); +} + @end @implementation CKAccountInfo (CKKS) diff --git a/keychain/ckks/OctagonAPSReceiver.h b/keychain/ckks/OctagonAPSReceiver.h index 5271338d..98b8920c 100644 --- a/keychain/ckks/OctagonAPSReceiver.h +++ b/keychain/ckks/OctagonAPSReceiver.h @@ -66,16 +66,17 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithEnvironmentName:(NSString*)environmentName namedDelegatePort:(NSString*)namedDelegatePort apsConnectionClass:(Class)apsConnectionClass; +- (instancetype)initWithEnvironmentName:(NSString*)environmentName + namedDelegatePort:(NSString*)namedDelegatePort + apsConnectionClass:(Class)apsConnectionClass + stalePushTimeout:(uint64_t)stalePushTimeout; // This is the queue that APNS will use send the notifications to us + (dispatch_queue_t)apsDeliveryQueue; - -// timeout for stale push cache, in nanoseconds -+ (int64_t)stalePushTimeout; - @end @interface OctagonAPSReceiver (Testing) + (void)resetGlobalEnviornmentMap; +- (void)reportDroppedPushes:(NSDictionary*>*)notifications; @end NS_ASSUME_NONNULL_END diff --git a/keychain/ckks/OctagonAPSReceiver.m b/keychain/ckks/OctagonAPSReceiver.m index 10499da9..e8eeb4f7 100644 --- a/keychain/ckks/OctagonAPSReceiver.m +++ b/keychain/ckks/OctagonAPSReceiver.m @@ -133,10 +133,6 @@ return aps_dispatch_queue; } -+ (int64_t)stalePushTimeout { - return 5*60*NSEC_PER_SEC; -} - - (BOOL) haveStalePushes { __block BOOL haveStalePushes = NO; @@ -160,7 +156,19 @@ - (instancetype)initWithEnvironmentName:(NSString*)environmentName namedDelegatePort:(NSString*)namedDelegatePort - apsConnectionClass:(Class)apsConnectionClass { + apsConnectionClass:(Class)apsConnectionClass +{ + return [self initWithEnvironmentName:environmentName + namedDelegatePort:namedDelegatePort + apsConnectionClass:apsConnectionClass + stalePushTimeout:5*60*NSEC_PER_SEC]; +} + +- (instancetype)initWithEnvironmentName:(NSString*)environmentName + namedDelegatePort:(NSString*)namedDelegatePort + apsConnectionClass:(Class)apsConnectionClass + stalePushTimeout:(uint64_t)stalePushTimeout +{ if(self = [super init]) { _apsConnectionClass = apsConnectionClass; _apsConnection = NULL; @@ -204,15 +212,12 @@ self.undeliveredUpdates = [NSMutableDictionary dictionary]; [self.undeliveredCuttlefishUpdates removeAllObjects]; - dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{ - STRONGIFY(self); - [self reportDroppedPushes:droppedUpdates]; - }); + [self reportDroppedPushes:droppedUpdates]; }); }; _clearStalePushNotifications = [[CKKSNearFutureScheduler alloc] initWithName: @"clearStalePushNotifications" - delay:[[self class] stalePushTimeout] + delay:stalePushTimeout keepProcessAlive:false dependencyDescriptionCode:CKKSResultDescriptionNone block:clearPushBlock]; diff --git a/keychain/ckks/tests/CKKSAPSHandlingTests.m b/keychain/ckks/tests/CKKSAPSHandlingTests.m index 748de40c..4aa357ac 100644 --- a/keychain/ckks/tests/CKKSAPSHandlingTests.m +++ b/keychain/ckks/tests/CKKSAPSHandlingTests.m @@ -285,38 +285,24 @@ OCMVerifyAllWithDelay(self.mockDatabase, 20); } -- (int64_t)stalePushTimeoutShort -{ - return 4 * NSEC_PER_SEC; -} - - (void)testDropStalePushes { CKRecordZoneID* pushTestZone = [[CKRecordZoneID alloc] initWithZoneName:@"PushTestZone" ownerName:CKCurrentUserDefaultName]; - id nearFutureSchduler = OCMClassMock([OctagonAPSReceiver class]); - OCMStub([nearFutureSchduler stalePushTimeout]).andCall(self, @selector(stalePushTimeoutShort)); - APSIncomingMessage* apsMessage = [CKKSAPSHandlingTests messageWithTracingEnabledForZoneID:pushTestZone]; // Don't use the global map here, because we need to ensure we create a new object (to use the stalePushTimeout we injected above) - OctagonAPSReceiver* apsReceiver = [[OctagonAPSReceiver alloc] initWithEnvironmentName:self.apsEnvironment - namedDelegatePort:SecCKKSAPSNamedPort - apsConnectionClass:[FakeAPSConnection class]]; + OctagonAPSReceiver* apsReceiver = OCMPartialMock([[OctagonAPSReceiver alloc] initWithEnvironmentName:self.apsEnvironment + namedDelegatePort:SecCKKSAPSNamedPort + apsConnectionClass:[FakeAPSConnection class] + stalePushTimeout:4 * NSEC_PER_SEC]); XCTAssertNotNil(apsReceiver, "Should have gotten an APS receiver"); + OCMExpect([apsReceiver reportDroppedPushes:[OCMArg any]]); [apsReceiver connection:nil didReceiveIncomingMessage:apsMessage]; XCTAssertEqual(apsReceiver.haveStalePushes, YES, "should have stale pushes"); - - XCTestExpectation *expection = [self expectationWithDescription:@"no push"]; - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, [self stalePushTimeoutShort] + (2*NSEC_PER_SEC)), dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{ - XCTAssertEqual(apsReceiver.haveStalePushes, NO, "should have cleared out stale pushes"); - [expection fulfill]; - }); - - [self waitForExpectations: @[expection] timeout:([self stalePushTimeoutShort] * 4)/NSEC_PER_SEC]; - - [nearFutureSchduler stopMocking]; + OCMVerifyAllWithDelay((id)apsReceiver, 20); + XCTAssertEqual(apsReceiver.haveStalePushes, NO, "should no longer have stale pushes"); } diff --git a/keychain/ckks/tests/CKKSPBFileStorageTests.m b/keychain/ckks/tests/CKKSPBFileStorageTests.m new file mode 100644 index 00000000..112bd55a --- /dev/null +++ b/keychain/ckks/tests/CKKSPBFileStorageTests.m @@ -0,0 +1,49 @@ +// +// CKKSPBFileStorageTests.m +// + +#import + +#import "keychain/ckks/CKKSPBFileStorage.h" +#import "keychain/ckks/proto/generated_source/CKKSSerializedKey.h" + +@interface CKKSPBFileStorageTests : XCTestCase +@property NSURL * tempDir; +@end + +@implementation CKKSPBFileStorageTests + +- (void)setUp { + self.tempDir = [[NSFileManager defaultManager] temporaryDirectory]; +} +- (void)tearDown { + [[NSFileManager defaultManager] removeItemAtURL:self.tempDir error:nil]; + self.tempDir = nil; +} + +- (void)testCKKSPBStorage { + + NSURL *file = [self.tempDir URLByAppendingPathComponent:@"file"]; + + CKKSPBFileStorage *pbstorage; + + pbstorage = [[CKKSPBFileStorage alloc] initWithStoragePath:file + storageClass:[CKKSSerializedKey class]]; + XCTAssertNotNil(pbstorage, "CKKSPBFileStorage should create an object"); + + CKKSSerializedKey *storage = pbstorage.storage; + storage.uuid = @"uuid"; + storage.zoneName = @"uuid"; + storage.keyclass = @"ak"; + storage.key = [NSData data]; + + [pbstorage setStorage:storage]; + + pbstorage = [[CKKSPBFileStorage alloc] initWithStoragePath:file + storageClass:[CKKSSerializedKey class]]; + XCTAssertNotNil(pbstorage, "CKKSPBFileStorage should create an object"); + + XCTAssertEqualObjects(pbstorage.storage.keyclass, @"ak", "should be the same"); +} + +@end diff --git a/keychain/ckks/tests/CKKSTests.m b/keychain/ckks/tests/CKKSTests.m index 8a057b6c..1aaf5cd8 100644 --- a/keychain/ckks/tests/CKKSTests.m +++ b/keychain/ckks/tests/CKKSTests.m @@ -1806,6 +1806,57 @@ OCMVerifyAllWithDelay(self.mockDatabase, 20); } +- (void)testAcceptKeyHierarchyResetAndUploadReencryptedItem { + // Test starts with nothing in CloudKit. CKKS uploads a key hierarchy, then it's silently replaced. + // CKKS should notice the replacement, and reupload the item. + + [self startCKKSSubsystem]; + + [self performOctagonTLKUpload:self.ckksViews]; + OCMVerifyAllWithDelay(self.mockDatabase, 20); + + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"key state should enter 'ready'"); + + // We expect a single record to be uploaded. + [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID checkItem: [self checkClassCBlock:self.keychainZoneID message:@"Object was encrypted under class C key in hierarchy"]]; + + [self addGenericPassword: @"data" account: @"account-delete-me"]; + + OCMVerifyAllWithDelay(self.mockDatabase, 20); + [self waitForCKModifications]; + + // A new peer arrives and resets the world! It sends us a share, though. + CKKSSOSSelfPeer* remotePeer1 = [[CKKSSOSSelfPeer alloc] initWithSOSPeerID:@"remote-peer1" + encryptionKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]] + signingKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]] + viewList:self.managedViewList]; + [self.mockSOSAdapter.trustedPeers addObject:remotePeer1]; + + NSString* classCUUID = self.keychainZoneKeys.classC.uuid; + + self.zones[self.keychainZoneID] = [[FakeCKZone alloc] initZone:self.keychainZoneID]; + self.keys[self.keychainZoneID] = nil; + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + [self putTLKSharesInCloudKit:self.keychainZoneKeys.tlk from:remotePeer1 zoneID:self.keychainZoneID]; + + XCTAssertNotEqual(classCUUID, self.keychainZoneKeys.classC.uuid, @"Class C UUID should have changed"); + + // Upon adding an item, we expect a failed OQO, then another OQO with the two items (encrypted correctly) + [self expectCKAtomicModifyItemRecordsUpdateFailure:self.keychainZoneID]; + + [self expectCKModifyItemRecords:2 + currentKeyPointerRecords:1 + zoneID:self.keychainZoneID + checkItem:[self checkClassCBlock:self.keychainZoneID message:@"Object was encrypted under class C key in hierarchy"]]; + + // We also expect a self share upload, once CKKS figures out the right key hierarchy + [self expectCKKSTLKSelfShareUpload:self.keychainZoneID]; + + [self addGenericPassword: @"data" account: @"account-delete-me-after-reset"]; + + OCMVerifyAllWithDelay(self.mockDatabase, 20); +} + - (void)testRecoverFromRequestKeyRefetchWithoutRolling { // Simply requesting a key state refetch shouldn't roll the key hierarchy. @@ -4274,6 +4325,31 @@ }]; } +- (void)testReceiveNotificationDuringLaunch { + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + + [self holdCloudKitModifyRecordZones]; + + // Spin up CKKS subsystem. + [self startCKKSSubsystem]; + + CKKSCondition* fetcherCondition = self.keychainView.zoneChangeFetcher.fetchScheduler.liveRequestReceived; + + [self saveTLKMaterialToKeychainSimulatingSOS:self.keychainZoneID]; + + [self.keychainView notifyZoneChange:nil]; + + XCTAssertNotEqual(0, [fetcherCondition wait:(3 * NSEC_PER_SEC)], "not supposed to get a fetch data"); + + [self expectCKKSTLKSelfShareUpload:self.keychainZoneID]; + self.silentFetchesAllowed = false; + [self expectCKFetch]; + [self releaseCloudKitModifyRecordZonesHold]; + + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "CKKS entered ready"); + OCMVerifyAllWithDelay(self.mockDatabase, 20); +} + @end #endif // OCTAGON diff --git a/keychain/ckks/tests/CloudKitMockXCTest.h b/keychain/ckks/tests/CloudKitMockXCTest.h index a108921e..0e3573d6 100644 --- a/keychain/ckks/tests/CloudKitMockXCTest.h +++ b/keychain/ckks/tests/CloudKitMockXCTest.h @@ -94,6 +94,8 @@ NS_ASSUME_NONNULL_BEGIN @property (nullable) NSBlockOperation* ckModifyHoldOperation; @property (nullable) NSBlockOperation* ckFetchHoldOperation; +@property (nullable) NSBlockOperation* ckModifyRecordZonesHoldOperation; +@property (nullable) NSBlockOperation* ckModifySubscriptionsHoldOperation; @property bool silentFetchesAllowed; @property bool silentZoneDeletesAllowed; @@ -195,6 +197,13 @@ NS_ASSUME_NONNULL_BEGIN // Unblocks the hold you've added with holdCloudKitFetches; CloudKit fetches will finish - (void)releaseCloudKitFetchHold; +- (void)holdCloudKitModifyRecordZones; +- (void)releaseCloudKitModifyRecordZonesHold; + +- (void)holdCloudKitModifySubscription; +- (void)releaseCloudKitModifySubscriptionHold; + + // Make a CK internal server extension error with a given code and description. - (NSError*)ckInternalServerExtensionError:(NSInteger)code description:(NSString*)desc; diff --git a/keychain/ckks/tests/CloudKitMockXCTest.m b/keychain/ckks/tests/CloudKitMockXCTest.m index 1eded344..76916eab 100644 --- a/keychain/ckks/tests/CloudKitMockXCTest.m +++ b/keychain/ckks/tests/CloudKitMockXCTest.m @@ -303,6 +303,30 @@ return matches; }]]); + OCMStub([self.mockDatabase addOperation: [OCMArg checkWithBlock:^BOOL(id obj) { + __strong __typeof(self) strongSelf = weakSelf; + BOOL matches = NO; + if ([obj isKindOfClass: [FakeCKModifyRecordZonesOperation class]]) { + FakeCKModifyRecordZonesOperation *frzco = (FakeCKModifyRecordZonesOperation *)obj; + [frzco addNullableDependency:strongSelf.ckModifyRecordZonesHoldOperation]; + [strongSelf.operationQueue addOperation: frzco]; + matches = YES; + } + return matches; + }]]); + + OCMStub([self.mockDatabase addOperation: [OCMArg checkWithBlock:^BOOL(id obj) { + __strong __typeof(self) strongSelf = weakSelf; + BOOL matches = NO; + if ([obj isKindOfClass: [FakeCKModifySubscriptionsOperation class]]) { + FakeCKModifySubscriptionsOperation *frzco = (FakeCKModifySubscriptionsOperation *)obj; + [frzco addNullableDependency:strongSelf.ckModifySubscriptionsHoldOperation]; + [strongSelf.operationQueue addOperation: frzco]; + matches = YES; + } + return matches; + }]]); + self.testZoneID = [[CKRecordZoneID alloc] initWithZoneName:@"testzone" ownerName:CKCurrentUserDefaultName]; // We don't want to use class mocks here, because they don't play well with partial mocks @@ -544,6 +568,30 @@ } } +-(void)holdCloudKitModifyRecordZones { + XCTAssertFalse([self.ckModifyRecordZonesHoldOperation isPending], "Shouldn't already be a pending cloudkit zone create hold operation"); + self.ckModifyRecordZonesHoldOperation = [NSBlockOperation blockOperationWithBlock:^{ + secnotice("ckks", "Released CloudKit zone create hold."); + }]; +} +-(void)releaseCloudKitModifyRecordZonesHold { + if([self.ckModifyRecordZonesHoldOperation isPending]) { + [self.operationQueue addOperation: self.ckModifyRecordZonesHoldOperation]; + } +} + +-(void)holdCloudKitModifySubscription { + XCTAssertFalse([self.ckModifySubscriptionsHoldOperation isPending], "Shouldn't already be a pending cloudkit subscription hold operation"); + self.ckModifySubscriptionsHoldOperation = [NSBlockOperation blockOperationWithBlock:^{ + secnotice("ckks", "Released CloudKit zone create hold."); + }]; +} +-(void)releaseCloudKitModifySubscriptionHold { + if([self.ckModifySubscriptionsHoldOperation isPending]) { + [self.operationQueue addOperation: self.ckModifySubscriptionsHoldOperation]; + } +} + - (void)expectCKModifyItemRecords: (NSUInteger) expectedNumberOfRecords currentKeyPointerRecords: (NSUInteger) expectedCurrentKeyRecords zoneID: (CKRecordZoneID*) zoneID { [self expectCKModifyItemRecords:expectedNumberOfRecords currentKeyPointerRecords:expectedCurrentKeyRecords @@ -1098,26 +1146,7 @@ } - (NSError*)ckInternalServerExtensionError:(NSInteger)code description:(NSString*)desc { - NSError* extensionError = [[CKPrettyError alloc] initWithDomain:@"CloudkitKeychainService" - code:code - userInfo:@{ - CKErrorServerDescriptionKey: desc, - NSLocalizedDescriptionKey: desc, - }]; - NSError* internalError = [[CKPrettyError alloc] initWithDomain:CKInternalErrorDomain - code:CKErrorInternalPluginError - userInfo:@{CKErrorServerDescriptionKey: desc, - NSLocalizedDescriptionKey: desc, - NSUnderlyingErrorKey: extensionError, - }]; - NSError* error = [[CKPrettyError alloc] initWithDomain:CKErrorDomain - code:CKErrorServerRejectedRequest - userInfo:@{NSUnderlyingErrorKey: internalError, - CKErrorServerDescriptionKey: desc, - NSLocalizedDescriptionKey: desc, - CKContainerIDKey: SecCKKSContainerName, - }]; - return error; + return [FakeCKZone internalPluginError:@"CloudkitKeychainService" code:code description:desc]; } @end diff --git a/keychain/ckks/tests/MockCloudKit.h b/keychain/ckks/tests/MockCloudKit.h index b551e87a..91226056 100644 --- a/keychain/ckks/tests/MockCloudKit.h +++ b/keychain/ckks/tests/MockCloudKit.h @@ -144,6 +144,9 @@ typedef NSMutableDictionary FakeCKDatabase; // Checks if this record add/modification should fail - (NSError* _Nullable)errorFromSavingRecord:(CKRecord*)record; + +// Helpfully creates an internal plugin error that CK would return ++ (NSError*)internalPluginError:(NSString*)serverDomain code:(NSInteger)code description:(NSString*)desc; @end @interface FakeCKKSNotifier : NSObject diff --git a/keychain/ckks/tests/MockCloudKit.m b/keychain/ckks/tests/MockCloudKit.m index a4172271..1a15ff54 100644 --- a/keychain/ckks/tests/MockCloudKit.m +++ b/keychain/ckks/tests/MockCloudKit.m @@ -716,6 +716,21 @@ - (NSError * _Nullable)errorFromSavingRecord:(CKRecord*) record { CKRecord* existingRecord = self.currentDatabase[record.recordID]; + + // First, implement CKKS-specific server-side checks + if([record.recordType isEqualToString:SecCKRecordCurrentKeyType]) { + CKReference* parentKey = record[SecCKRecordParentKeyRefKey]; + + CKRecord* existingParentKey = self.currentDatabase[parentKey.recordID]; + + if(!existingParentKey) { + ckksnotice("fakeck", self.zoneID, "bad sync key reference! Fail the write: %@ %@", record, existingRecord); + + return [FakeCKZone internalPluginError:@"CloudkitKeychainService" code:CKKSServerMissingRecord description:@"synckey record: record not found"]; + } + } + // + if(existingRecord && ![existingRecord.recordChangeTag isEqualToString: record.recordChangeTag]) { ckksnotice("fakeck", self.zoneID, "change tag mismatch! Fail the write: %@ %@", record, existingRecord); @@ -776,6 +791,32 @@ } return error; } + ++ (NSError*)internalPluginError:(NSString*)serverDomain code:(NSInteger)code description:(NSString*)desc +{ + // Note: uses SecCKKSContainerName, but that's probably okay + NSError* extensionError = [[CKPrettyError alloc] initWithDomain:serverDomain + code:code + userInfo:@{ + CKErrorServerDescriptionKey: desc, + NSLocalizedDescriptionKey: desc, + }]; + NSError* internalError = [[CKPrettyError alloc] initWithDomain:CKInternalErrorDomain + code:CKErrorInternalPluginError + userInfo:@{CKErrorServerDescriptionKey: desc, + NSLocalizedDescriptionKey: desc, + NSUnderlyingErrorKey: extensionError, + }]; + NSError* error = [[CKPrettyError alloc] initWithDomain:CKErrorDomain + code:CKErrorServerRejectedRequest + userInfo:@{NSUnderlyingErrorKey: internalError, + CKErrorServerDescriptionKey: desc, + NSLocalizedDescriptionKey: desc, + CKContainerIDKey: SecCKKSContainerName, + }]; + + return error; +} @end @implementation FakeCKKSNotifier diff --git a/keychain/escrowrequest/EscrowRequestController.m b/keychain/escrowrequest/EscrowRequestController.m index f985e503..517279ee 100644 --- a/keychain/escrowrequest/EscrowRequestController.m +++ b/keychain/escrowrequest/EscrowRequestController.m @@ -38,9 +38,10 @@ OctagonState* const EscrowRequestStateWaitForUnlock = (OctagonState*)@"wait_for_ _stateMachine = [[OctagonStateMachine alloc] initWithName:@"escrowrequest" states:[NSSet setWithArray:@[EscrowRequestStateNothingToDo, - EscrowRequestStateTriggerCloudServices, - EscrowRequestStateAttemptEscrowUpload, - EscrowRequestStateWaitForUnlock]] + EscrowRequestStateTriggerCloudServices, + EscrowRequestStateAttemptEscrowUpload, + EscrowRequestStateWaitForUnlock]] + flags: [NSSet setWithArray:@[OctagonFlagEscrowRequestInformCloudServicesOperation]] initialState:EscrowRequestStateNothingToDo queue:_queue stateEngine:self diff --git a/keychain/ot/CuttlefishXPCWrapper.m b/keychain/ot/CuttlefishXPCWrapper.m index c531fb82..c67395bb 100644 --- a/keychain/ot/CuttlefishXPCWrapper.m +++ b/keychain/ot/CuttlefishXPCWrapper.m @@ -255,6 +255,28 @@ enum {NUM_RETRIES = 5}; } while (retry); } + +- (void)fetchAllowedMachineIDsWithContainer:(nonnull NSString *)container + context:(nonnull NSString *)context + reply:(nonnull void (^)(NSSet * _Nullable, NSError * _Nullable))reply { + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(nil, error); + } + ++i; + }] fetchAllowedMachineIDsWithContainer:container context:context reply:reply]; + } while (retry); +} + + - (void)fetchEgoEpochWithContainer:(NSString *)container context:(NSString *)context reply:(void (^)(unsigned long long epoch, @@ -841,4 +863,27 @@ enum {NUM_RETRIES = 5}; }] requestHealthCheckWithContainer:container context:context requiresEscrowCheck:requiresEscrowCheck reply:reply]; } while (retry); } + +- (void)getSupportAppInfoWithContainer:(NSString *)container + context:(NSString *)context + reply:(void (^)(NSData * _Nullable, NSError * _Nullable))reply +{ + __block int i = 0; + __block bool retry; + do { + retry = false; + [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) { + if (i < NUM_RETRIES && [self.class retryable:error]) { + secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error); + retry = true; + } else { + secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); + reply(nil, error); + } + ++i; + }] getSupportAppInfoWithContainer:container context:context reply:reply]; + } while (retry); + +} + @end diff --git a/keychain/ot/OTAuthKitAdapter.h b/keychain/ot/OTAuthKitAdapter.h index d2e4053c..5539aa1f 100644 --- a/keychain/ot/OTAuthKitAdapter.h +++ b/keychain/ot/OTAuthKitAdapter.h @@ -17,7 +17,7 @@ NS_ASSUME_NONNULL_BEGIN @protocol OTAuthKitAdapter // Returns nil if there is no such primary account -- (NSString* _Nullable)primaryiCloudAccountAltDSID; +- (NSString* _Nullable)primaryiCloudAccountAltDSID:(NSError **)error; - (BOOL)accountIsHSA2ByAltDSID:(NSString*)altDSID; diff --git a/keychain/ot/OTAuthKitAdapter.m b/keychain/ot/OTAuthKitAdapter.m index 939e58c5..b9452d2e 100644 --- a/keychain/ot/OTAuthKitAdapter.m +++ b/keychain/ot/OTAuthKitAdapter.m @@ -1,6 +1,7 @@ #if OCTAGON #import "OTAuthKitAdapter.h" +#import "OTConstants.h" #import "utilities/SecCFError.h" #import "keychain/categories/NSError+UsefulConstructors.h" @@ -12,6 +13,9 @@ #import #import #import "keychain/ckks/CKKSListenerCollection.h" +#import "keychain/ckks/CKKSAnalytics.h" + +#include "utilities/SecABC.h" #import @@ -21,15 +25,30 @@ @implementation OTAuthKitActualAdapter -- (NSString* _Nullable)primaryiCloudAccountAltDSID +- (NSString* _Nullable)primaryiCloudAccountAltDSID:(NSError **)error { ACAccountStore *store = [[ACAccountStore alloc] init]; ACAccount* primaryAccount = [store aa_primaryAppleAccount]; if(!primaryAccount) { + secnotice("authkit", "No primary account"); + if (error) { + *error = [NSError errorWithDomain:OctagonErrorDomain + code:OTAuthKitNoPrimaryAccount + description:@"No primary account"]; + } return nil; } - return [primaryAccount aa_altDSID]; + NSString *altDSID = [primaryAccount aa_altDSID]; + if (altDSID == NULL) { + secnotice("authkit", "No altDSID on primary account"); + if (error) { + *error = [NSError errorWithDomain:OctagonErrorDomain + code:OTAuthKitPrimaryAccountHaveNoDSID + description:@"No altdsid on primary account"]; + } + } + return altDSID; } - (BOOL)accountIsHSA2ByAltDSID:(NSString*)altDSID @@ -63,9 +82,9 @@ if(!machineID) { secnotice("authkit", "Anisette data does not have machineID"); if(error) { - // TODO: this is a terrible error - *error = [NSError errorWithDomain:(__bridge NSString *)kSecErrorDomain - code:errSecParam + [SecABC triggerAutoBugCaptureWithType:@"AuthKit" subType:@"missingMID"]; + *error = [NSError errorWithDomain:OctagonErrorDomain + code:OTAuthKitMachineIDMissing description:@"Anisette data does not have machineID"]; } return nil; @@ -78,30 +97,36 @@ - (void)fetchCurrentDeviceList:(void (^)(NSSet* _Nullable machineIDs, NSError* _Nullable error))complete { - ACAccountStore *store = [[ACAccountStore alloc] init]; - ACAccount* primaryAccount = [store aa_primaryAppleAccount]; - if(primaryAccount == nil) { - secnotice("authkit", "can't get account"); - complete(nil, [NSError errorWithDomain:(__bridge NSString *)kSecErrorDomain - code:errSecParam - description:@"no primary account"]); - return; - } - AKDeviceListRequestContext* context = [[AKDeviceListRequestContext alloc] init]; if (context == nil) { - complete(nil, [NSError errorWithDomain:(__bridge NSString *)kSecErrorDomain - code:errSecParam - description:@"can't get AKDeviceListRequestContextClass"]); + NSError *error = [NSError errorWithDomain:OctagonErrorDomain + code:OTAuthKitAKDeviceListRequestContextClass + description:@"can't get AKDeviceListRequestContextClass"]; + [[CKKSAnalytics logger] logUnrecoverableError:error forEvent:OctagonEventAuthKitDeviceList withAttributes:nil]; + complete(nil, error); + return; + } + NSError *authKitError = nil; + context.altDSID = [self primaryiCloudAccountAltDSID:&authKitError]; + if (context.altDSID == NULL) { + secnotice("authkit", "Failed to get primary account AltDSID: %@", authKitError); + NSError *error = [NSError errorWithDomain:OctagonErrorDomain + code:OTAuthKitPrimaryAccountHaveNoDSID + description:@"Can't get primary AltDSID" + underlying:authKitError]; + [[CKKSAnalytics logger] logUnrecoverableError:error forEvent:OctagonEventAuthKitDeviceList withAttributes:nil]; + [SecABC triggerAutoBugCaptureWithType:@"AuthKit" subType:@"missingAltDSID"]; + complete(nil, error); return; } - context.altDSID = primaryAccount.aa_altDSID; AKAppleIDAuthenticationController *authController = [[AKAppleIDAuthenticationController alloc] init]; if(authController == nil) { - complete(nil, [NSError errorWithDomain:(__bridge NSString *)kSecErrorDomain - code:errSecParam - description:@"can't get authController"]); + NSError *error = [NSError errorWithDomain:OctagonErrorDomain + code:OTAuthKitNoAuthenticationController + description:@"can't get authController"]; + [[CKKSAnalytics logger] logUnrecoverableError:error forEvent:OctagonEventAuthKitDeviceList withAttributes:nil]; + complete(nil, error); return; } @@ -115,7 +140,10 @@ secnotice("authkit", "Current machine ID list: %@", mids); complete(mids, error); + [[CKKSAnalytics logger] logSuccessForEventNamed:OctagonEventAuthKitDeviceList]; + } else { + [[CKKSAnalytics logger] logUnrecoverableError:error forEvent:OctagonEventAuthKitDeviceList withAttributes:nil]; secnotice("authkit", "received no device list: %@", error); complete(nil, error); } diff --git a/keychain/ot/OTClientStateMachine.m b/keychain/ot/OTClientStateMachine.m index 32f8f044..b36a24aa 100644 --- a/keychain/ot/OTClientStateMachine.m +++ b/keychain/ot/OTClientStateMachine.m @@ -263,7 +263,6 @@ NSDictionary* OctagonClientStateMap(void) { return [OctagonStateTransitionOperation named:@"octagon-voucher-prepared" intending:OctagonStateAcceptorDone errorState:OctagonStateError - timeout:10*NSEC_PER_SEC withBlockTakingSelf:^(OctagonStateTransitionOperation * _Nonnull op) { otclientnotice(self.clientScope, "moving to state done for %@", clientName); op.nextState = OctagonStateAcceptorDone; diff --git a/keychain/ot/OTClique.m b/keychain/ot/OTClique.m index 8a6c33b3..5bf39cee 100644 --- a/keychain/ot/OTClique.m +++ b/keychain/ot/OTClique.m @@ -29,6 +29,7 @@ #import "keychain/ot/OTClique.h" #import "keychain/ot/OTConstants.h" #import "keychain/ot/OTDefines.h" +#import "keychain/SigninMetrics/OctagonSignPosts.h" #import #import @@ -213,12 +214,15 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) { #if OCTAGON __block NSString* retPeerID = nil; + __block bool subTaskSuccess = false; + OctagonSignpost fetchEgoPeerSignPost = OctagonSignpostBegin(OctagonSignpostNameFetchEgoPeer); if(OctagonIsEnabled()) { NSError* localError = nil; OTControl* control = [self makeOTControl:&localError]; if(!control) { secerror("octagon: Failed to create OTControl: %@", localError); + OctagonSignpostEnd(fetchEgoPeerSignPost, OctagonSignpostNameFetchEgoPeer, OctagonSignpostNumber1(OctagonSignpostNameFetchEgoPeer), (int)subTaskSuccess); return nil; } @@ -241,6 +245,8 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) } secnotice("clique", "cliqueMemberIdentifier complete: %@", retPeerID); + subTaskSuccess = retPeerID ? true : false; + OctagonSignpostEnd(fetchEgoPeerSignPost, OctagonSignpostNameFetchEgoPeer, OctagonSignpostNumber1(OctagonSignpostNameFetchEgoPeer), (int)subTaskSuccess); return retPeerID; #else return nil; @@ -256,19 +262,21 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) - (BOOL)establish:(NSError**)error { secnotice("clique-establish", "establish started"); - + OctagonSignpost establishSignPost = OctagonSignpostBegin(OctagonSignpostNameEstablish); + bool subTaskSuccess = false; OTControl* control = [self makeOTControl:error]; if(!control) { + OctagonSignpostEnd(establishSignPost, OctagonSignpostNameEstablish, OctagonSignpostNumber1(OctagonSignpostNameEstablish), (int)subTaskSuccess); return false; } __block BOOL success = NO; __block NSError* localError = nil; + //only establish [control establish:nil context:self.ctx.context altDSID:self.ctx.altDSID reply:^(NSError * _Nullable operationError) { - if(operationError) { - secnotice("clique-establish", "reenact establish returned an error: %@", operationError); + secnotice("clique-establish", "establish returned an error: %@", operationError); } success = !!operationError; localError = operationError; @@ -278,6 +286,8 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) *error = localError; } secnotice("clique-establish", "establish complete: %@", success ? @"YES" : @"NO"); + subTaskSuccess = success ? true : false; + OctagonSignpostEnd(establishSignPost, OctagonSignpostNameEstablish, OctagonSignpostNumber1(OctagonSignpostNameEstablish), (int)subTaskSuccess); return success; } @@ -285,11 +295,14 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) - (BOOL)resetAndEstablish:(CuttlefishResetReason)resetReason error:(NSError**)error { secnotice("clique-resetandestablish", "resetAndEstablish started"); + bool subTaskSuccess = false; + OctagonSignpost resetAndEstablishSignPost = OctagonSignpostBegin(OctagonSignpostNameResetAndEstablish); OTControl* control = [self makeOTControl:error]; if(!control) { - return false; + OctagonSignpostEnd(resetAndEstablishSignPost, OctagonSignpostNameResetAndEstablish, OctagonSignpostNumber1(OctagonSignpostNameResetAndEstablish), (int)subTaskSuccess); + return NO; } __block BOOL success = NO; @@ -308,6 +321,8 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) } secnotice("clique-resetandestablish", "establish complete: %@", success ? @"YES" : @"NO"); + subTaskSuccess = success ? true : false; + OctagonSignpostEnd(resetAndEstablishSignPost, OctagonSignpostNameResetAndEstablish, OctagonSignpostNumber1(OctagonSignpostNameResetAndEstablish), (int)subTaskSuccess); return success; } @@ -323,7 +338,9 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) #if OCTAGON secnotice("clique-newfriends", "makeNewFriends invoked using context: %@, dsid: %@", data.context, data.dsid); bool result = false; - + bool subTaskSuccess = false; + OctagonSignpost performEscrowRecoverySignpost = OctagonSignpostBegin(OctagonSignpostNameMakeNewFriends); + OTClique* clique = [[OTClique alloc] initWithContextData:data error:error]; if(OctagonIsEnabled()) { @@ -335,6 +352,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) if(error) { *error = localError; } + OctagonSignpostEnd(performEscrowRecoverySignpost, OctagonSignpostNameMakeNewFriends, OctagonSignpostNumber1(OctagonSignpostNameMakeNewFriends), (int)subTaskSuccess); return nil; } else { secnotice("clique-newfriends", "Octagon account reset succeeded"); @@ -353,17 +371,14 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) } } - if(analyticsData) { - result = SOSCCResetToEmptyWithAnalytics((__bridge CFDataRef)analyticsData, &resetError); - } else { - result = SOSCCResetToEmpty(&resetError); - } + result = SOSCCResetToOffering(&resetError); if(!result || resetError){ secnotice("clique-newfriends", "newFriendsWithContextData: resetToOffering failed: %@", resetError); if(error) { *error = CFBridgingRelease(resetError); } + OctagonSignpostEnd(performEscrowRecoverySignpost, OctagonSignpostNameMakeNewFriends, OctagonSignpostNumber1(OctagonSignpostNameMakeNewFriends), (int)subTaskSuccess); return nil; } secnotice("clique-newfriends", "newFriendsWithContextData: reset the SOS circle"); @@ -372,6 +387,9 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) } secnotice("clique-newfriends", "makeNewFriends complete"); + subTaskSuccess = true; + OctagonSignpostEnd(performEscrowRecoverySignpost, OctagonSignpostNameMakeNewFriends, OctagonSignpostNumber1(OctagonSignpostNameMakeNewFriends), (int)subTaskSuccess); + return clique; #else // !OCTAGON @@ -386,17 +404,35 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) error:(NSError**)error { #if OCTAGON - secnotice("clique-recovery", "attempting an escrow recovery for context:%@, altdsid:%@", data.context, data.altDSID); + OctagonSignpost performEscrowRecoverySignpost = OctagonSignpostBegin(OctagonSignpostNamePerformEscrowRecovery); + bool subTaskSuccess = false; + NSError* localError = nil; + OTClique* clique = [[OTClique alloc] initWithContextData:data + error:&localError]; + if(!clique || localError) { + secnotice("clique-recovery", "unable to create otclique: %@", localError); + if(error) { + *error = localError; + } + OctagonSignpostEnd(performEscrowRecoverySignpost, OctagonSignpostNamePerformEscrowRecovery, OctagonSignpostNumber1(OctagonSignpostNamePerformEscrowRecovery), (int)subTaskSuccess); + return nil; + } + + // Attempt the recovery from sbd + secnotice("clique-recovery", "attempting an escrow recovery for context:%@, altdsid:%@", data.context, data.altDSID); id sb = data.sbd ?: [[getSecureBackupClass() alloc] init]; - NSDictionary* recoveredInformation = nil; + + OctagonSignpost recoverFromSBDSignPost = OctagonSignpostBegin(OctagonSignpostNamePerformRecoveryFromSBD); NSError* recoverError = [sb recoverWithInfo:sbdRecoveryArguments results:&recoveredInformation]; - + subTaskSuccess = (recoverError == nil) ? true : false; + OctagonSignpostEnd(recoverFromSBDSignPost, OctagonSignpostNamePerformRecoveryFromSBD, OctagonSignpostNumber1(OctagonSignpostNamePerformRecoveryFromSBD), (int)subTaskSuccess); + if(recoverError) { secnotice("clique-recovery", "sbd escrow recovery failed: %@", recoverError); - if([OTClique platformSupportsSOS]) { - if(recoverError.code == 17 /* kSecureBackupRestoringLegacyBackupKeychainError */ && [recoverError.domain isEqualToString:getkSecureBackupErrorDomain()]) { /* XXX */ + if(recoverError.code == 17 /* kSecureBackupRestoringLegacyBackupKeychainError */ && [recoverError.domain isEqualToString:getkSecureBackupErrorDomain()]) { /* XXX */ + if([OTClique platformSupportsSOS]) { secnotice("clique-recovery", "Can't restore legacy backup with no keybag. Resetting SOS to offering"); CFErrorRef blowItAwayError = NULL; bool successfulReset = SOSCCResetToOffering(&blowItAwayError); @@ -406,37 +442,33 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) secnotice("clique-recovery", "resetting SOS circle successful"); } } else { - if(error) { - *error = recoverError; - } - return nil; + secnotice("clique-recovery", "Legacy restore failed on a non-SOS platform"); } } else { - if(error){ + if(error) { *error = recoverError; } + subTaskSuccess = false; + OctagonSignpostEnd(performEscrowRecoverySignpost, OctagonSignpostNamePerformEscrowRecovery, OctagonSignpostNumber1(OctagonSignpostNamePerformEscrowRecovery), (int)subTaskSuccess); return nil; } - } - - NSError* localError = nil; - OTClique* clique = [[OTClique alloc] initWithContextData:data - error:&localError]; - - if(!clique || localError) { - secnotice("clique-recovery", "unable to create otclique: %@", localError); - if(error) { - *error = localError; + } else { + if(OctagonPlatformSupportsSOS()) { // Join if the legacy restore is complete now. + secnotice("clique-recovery", "attempting joinAfterRestore"); + [clique joinAfterRestore:&localError]; + secnotice("clique-recovery", "joinAfterRestore: %@", localError); } - return nil; } + // look for OT Bottles OTControl* control = [clique makeOTControl:&localError]; if (!control) { secnotice("clique-recovery", "unable to create otcontrol: %@", localError); if (error) { *error = localError; } + subTaskSuccess = false; + OctagonSignpostEnd(performEscrowRecoverySignpost, OctagonSignpostNamePerformEscrowRecovery, OctagonSignpostNumber1(OctagonSignpostNamePerformEscrowRecovery), (int)subTaskSuccess); return nil; } @@ -448,7 +480,8 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) if(bottledPeerEntropy && bottleID && [isValid isEqualToString:@"valid"]){ secnotice("clique-recovery", "recovering from bottle: %@", bottleID); __block NSError* restoreBottleError = nil; - + + OctagonSignpost bottleRecoverySignPost = OctagonSignpostBegin(OctagonSignpostNamePerformBottleRecovery); //restore bottle! [control restore:OTCKContainerName contextID:data.context @@ -463,27 +496,31 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) } restoreBottleError = restoreError; }]; - + + subTaskSuccess = (restoreBottleError == nil) ? true : false; + OctagonSignpostEnd(bottleRecoverySignPost, OctagonSignpostNamePerformBottleRecovery, OctagonSignpostNumber1(OctagonSignpostNamePerformBottleRecovery), (int)subTaskSuccess); + if(restoreBottleError) { if(error){ *error = restoreBottleError; } + subTaskSuccess = false; + OctagonSignpostEnd(performEscrowRecoverySignpost, OctagonSignpostNamePerformEscrowRecovery, OctagonSignpostNumber1(OctagonSignpostNamePerformEscrowRecovery), (int)subTaskSuccess); return nil; } } else { shouldResetOctagon = true; } - - if(OctagonPlatformSupportsSOS()) { - secnotice("clique-recovery", "attempting joinAfterRestore"); - [clique joinAfterRestore:&localError]; - secnotice("clique-recovery", "joinAfterRestore: %@", localError); - } if(shouldResetOctagon) { secnotice("clique-recovery", "bottle %@ is not valid, resetting octagon", bottleID); NSError* resetError = nil; + + OctagonSignpost resetSignPost = OctagonSignpostBegin(OctagonSignpostNamePerformResetAndEstablishAfterFailedBottle); [clique resetAndEstablish:CuttlefishResetReasonNoBottleDuringEscrowRecovery error:&resetError]; + subTaskSuccess = (resetError == nil) ? true : false; + OctagonSignpostEnd(resetSignPost, OctagonSignpostNamePerformResetAndEstablishAfterFailedBottle, OctagonSignpostNumber1(OctagonSignpostNamePerformResetAndEstablishAfterFailedBottle), (int)subTaskSuccess); + if(resetError) { secnotice("clique-recovery", "failed to reset octagon: %@", resetError); } else{ @@ -493,6 +530,9 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) secnotice("clique-recovery", "recovery complete: %@", clique); + subTaskSuccess = clique ? true : false; + OctagonSignpostEnd(performEscrowRecoverySignpost, OctagonSignpostNamePerformEscrowRecovery, OctagonSignpostNumber1(OctagonSignpostNamePerformEscrowRecovery), (int)subTaskSuccess); + return clique; #else if (error) { @@ -544,6 +584,9 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) #if OCTAGON __block CliqueStatus sosStatus = CliqueStatusError; __block CliqueStatus octagonStatus = CliqueStatusError; + bool subTaskSuccess = false; + + OctagonSignpost fetchCliqueStatusSignPost = OctagonSignpostBegin(OctagonSignpostNameFetchCliqueStatus); // Octagon is supreme. @@ -551,6 +594,8 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) OTControl* control = [self makeOTControl:error]; if(!control) { secnotice("clique-status", "cliqueStatus noOTControl"); + OctagonSignpostEnd(fetchCliqueStatusSignPost, OctagonSignpostNameFetchCliqueStatus, OctagonSignpostNumber1(OctagonSignpostNameFetchCliqueStatus), (int)subTaskSuccess); + return CliqueStatusError; } @@ -572,7 +617,11 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) OTCliqueStatusToString(octagonStatus), localError); if (localError && error) { *error = localError; + subTaskSuccess = false; + } else { + subTaskSuccess = true; } + OctagonSignpostEnd(fetchCliqueStatusSignPost, OctagonSignpostNameFetchCliqueStatus, OctagonSignpostNumber1(OctagonSignpostNameFetchCliqueStatus), (int)subTaskSuccess); return octagonStatus; } } @@ -597,6 +646,10 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) configuration.useCachedAccountStatus ? "" : "non-", self.ctx.context, self.ctx.altDSID, OTCliqueStatusToString(octagonStatus)); + + subTaskSuccess = true; + OctagonSignpostEnd(fetchCliqueStatusSignPost, OctagonSignpostNameFetchCliqueStatus, OctagonSignpostNumber1(OctagonSignpostNameFetchCliqueStatus), (int)subTaskSuccess); + return octagonStatus; #else // !OCTAGON if(error){ @@ -641,6 +694,8 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) { #if OCTAGON secnotice("clique-removefriends", "removeFriendsInClique invoked using context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); + OctagonSignpost removeFriendsSignPost = OctagonSignpostBegin(OctagonSignpostNameRemoveFriendsInClique); + bool subTaskSuccess = false; // Annoying: we must sort friendIdentifiers into octagon/sos lists. NSMutableArray* octagonIdentifiers = [NSMutableArray array]; @@ -663,6 +718,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) if(error) { *error = localError; } + OctagonSignpostEnd(removeFriendsSignPost, OctagonSignpostNameRemoveFriendsInClique, OctagonSignpostNumber1(OctagonSignpostNameRemoveFriendsInClique), (int)subTaskSuccess); return NO; } @@ -674,6 +730,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) if(error) { *error = localError; } + OctagonSignpostEnd(removeFriendsSignPost, OctagonSignpostNameRemoveFriendsInClique, OctagonSignpostNumber1(OctagonSignpostNameRemoveFriendsInClique), (int)subTaskSuccess); return NO; } @@ -684,11 +741,11 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) if(OctagonIsEnabled() && octagonIdentifiers.count > 0) { OTControl* control = [self makeOTControl:error]; if(!control) { + OctagonSignpostEnd(removeFriendsSignPost, OctagonSignpostNameRemoveFriendsInClique, OctagonSignpostNumber1(OctagonSignpostNameRemoveFriendsInClique), (int)subTaskSuccess); return NO; } secnotice("clique-removefriends", "octagon: removing octagon friends: %@", octagonIdentifiers); - [control removeFriendsInClique:nil context:self.ctx.context peerIDs:octagonIdentifiers @@ -730,6 +787,9 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) } secnotice("clique-removefriends", "removeFriendsInClique complete: %d", result); + subTaskSuccess = result; + OctagonSignpostEnd(removeFriendsSignPost, OctagonSignpostNameRemoveFriendsInClique, OctagonSignpostNumber1(OctagonSignpostNameRemoveFriendsInClique), (int)subTaskSuccess); + return result && localError == nil; #else // !OCTAGON return NO; @@ -742,14 +802,37 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) secnotice("clique-leaveClique", "leaveClique invoked using context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); CFErrorRef removeThisDeviceError = NULL; bool result = false; + bool subTaskSuccess = false; + + OctagonSignpost leaveCliqueSignPost = OctagonSignpostBegin(OctagonSignpostNameLeaveClique); if(OctagonIsEnabled()) { OTControl* control = [self makeOTControl:error]; if(!control) { - return false; + OctagonSignpostEnd(leaveCliqueSignPost, OctagonSignpostNameLeaveClique, OctagonSignpostNumber1(OctagonSignpostNameLeaveClique), (int)subTaskSuccess); + return NO; } + // We only want to issue a "leave" command if we're actively in a clique __block NSError* localError = nil; + CliqueStatus currentStatus = [self fetchCliqueStatus:[[OTOperationConfiguration alloc] init] + error:&localError]; + + if(localError) { + secnotice("clique-leaveClique", "fetching current status errored: %@", localError); + if(error) { + *error = localError; + } + OctagonSignpostEnd(leaveCliqueSignPost, OctagonSignpostNameLeaveClique, OctagonSignpostNumber1(OctagonSignpostNameLeaveClique), (int)subTaskSuccess); + return NO; + } + + if(currentStatus == CliqueStatusNotIn) { + secnotice("clique-leaveClique", "current status is Not In; no need to leave"); + subTaskSuccess = true; + OctagonSignpostEnd(leaveCliqueSignPost, OctagonSignpostNameLeaveClique, OctagonSignpostNumber1(OctagonSignpostNameLeaveClique), (int)subTaskSuccess); + return YES; + } [control leaveClique:nil context:self.ctx.context reply:^(NSError * _Nullable leaveError) { if(leaveError) { secnotice("clique-leaveClique", "leaveClique errored: %@", leaveError); @@ -781,7 +864,6 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) } else { result &= SOSCCRemoveThisDeviceFromCircle(&removeThisDeviceError); } - if (error) { *error = (NSError*)CFBridgingRelease(removeThisDeviceError); } else { @@ -790,6 +872,9 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) } secnotice("clique-leaveClique", "leaveClique complete: %d", result); + subTaskSuccess = result; + OctagonSignpostEnd(leaveCliqueSignPost, OctagonSignpostNameLeaveClique, OctagonSignpostNumber1(OctagonSignpostNameLeaveClique), (int)subTaskSuccess); + return result ? YES : NO; #else // !OCTAGON return NO; @@ -800,12 +885,14 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) { #if OCTAGON secnotice("clique", "peerDeviceNamesByPeerID invoked using context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); - + OctagonSignpost peerNamesSignPost = OctagonSignpostBegin(OctagonSignpostNamePeerDeviceNamesByPeerID); + __block bool subTaskSuccess = false; NSMutableDictionary* retPeers = [NSMutableDictionary dictionary]; if(OctagonIsEnabled()) { OTControl* control = [self makeOTControl:error]; if(!control) { + OctagonSignpostEnd(peerNamesSignPost, OctagonSignpostNamePeerDeviceNamesByPeerID, OctagonSignpostNumber1(OctagonSignpostNamePeerDeviceNamesByPeerID), (int)subTaskSuccess); return nil; } @@ -826,6 +913,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) *error = localError; } if(localError) { + OctagonSignpostEnd(peerNamesSignPost, OctagonSignpostNamePeerDeviceNamesByPeerID, OctagonSignpostNumber1(OctagonSignpostNamePeerDeviceNamesByPeerID), (int)subTaskSuccess); return nil; } [retPeers addEntriesFromDictionary:localPeers]; @@ -844,16 +932,18 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) } }]; } + subTaskSuccess = (peerErrorRef == NULL || [retPeers count] == 0) ? true : false; + if (error) { *error = (NSError*)CFBridgingRelease(peerErrorRef); } else { CFBridgingRelease(peerErrorRef); } - [retPeers addEntriesFromDictionary:peerMapping]; secnotice("clique", "Received %lu SOS peers", (unsigned long)peerMapping.count); } + OctagonSignpostEnd(peerNamesSignPost, OctagonSignpostNamePeerDeviceNamesByPeerID, OctagonSignpostNumber1(OctagonSignpostNamePeerDeviceNamesByPeerID), (int)subTaskSuccess); return retPeers; #else // !OCTAGON return NULL; @@ -863,9 +953,11 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) - (BOOL)joinAfterRestore:(NSError * __autoreleasing *)error { secnotice("clique-recovery", "joinAfterRestore for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); + OctagonSignpost joinAfterRestoreSignPost = OctagonSignpostBegin(OctagonSignpostNameJoinAfterRestore); + bool subTaskSuccess = false; + if([OTClique platformSupportsSOS]) { CFErrorRef restoreError = NULL; - bool res = SOSCCRequestToJoinCircleAfterRestore(&restoreError); if (error) { *error = (NSError*)CFBridgingRelease(restoreError); @@ -873,7 +965,11 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) CFBridgingRelease(restoreError); } secnotice("clique-recovery", "joinAfterRestore complete: %d %@", res, error ? *error : @"no error pointer provided"); - return res; + + subTaskSuccess = res; + OctagonSignpostEnd(joinAfterRestoreSignPost, OctagonSignpostNameJoinAfterRestore, OctagonSignpostNumber1(OctagonSignpostNameJoinAfterRestore), (int)subTaskSuccess); + + return res ? YES : NO; } else { secnotice("clique-recovery", "SOS disabled for this platform, returning NO"); if(error){ @@ -881,6 +977,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) code:errSecUnimplemented userInfo:@{NSLocalizedDescriptionKey: @"join after restore unimplemented"}]; } + OctagonSignpostEnd(joinAfterRestoreSignPost, OctagonSignpostNameJoinAfterRestore, OctagonSignpostNumber1(OctagonSignpostNameJoinAfterRestore), (int)subTaskSuccess); return NO; } } @@ -888,11 +985,14 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) - (BOOL)safariPasswordSyncingEnabled:(NSError **)error { secnotice("clique-safari", "safariPasswordSyncingEnabled for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); + OctagonSignpost safariSyncingEnabledSignPost = OctagonSignpostBegin(OctagonSignpostNameSafariPasswordSyncingEnabled); + bool subTaskSuccess = false; if([OTClique platformSupportsSOS]) { CFErrorRef viewErrorRef = NULL; SOSViewResultCode result = SOSCCView(kSOSViewAutofillPasswords, kSOSCCViewQuery, &viewErrorRef); + subTaskSuccess = (viewErrorRef == NULL) ? true : false; BOOL viewMember = result == kSOSCCViewMember; if (error) { @@ -900,9 +1000,9 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) } else { CFBridgingRelease(viewErrorRef); } + OctagonSignpostEnd(safariSyncingEnabledSignPost, OctagonSignpostNameSafariPasswordSyncingEnabled, OctagonSignpostNumber1(OctagonSignpostNameSafariPasswordSyncingEnabled), (int)subTaskSuccess); secnotice("clique-safari", "safariPasswordSyncingEnabled complete: %@", viewMember ? @"YES" : @"NO"); - return viewMember; } else { secnotice("clique-safari", "SOS disabled for this platform, returning NO"); @@ -911,6 +1011,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) code:errSecUnimplemented userInfo:@{NSLocalizedDescriptionKey: @"safari password syncing enabled unimplemented"}]; } + OctagonSignpostEnd(safariSyncingEnabledSignPost, OctagonSignpostNameSafariPasswordSyncingEnabled, OctagonSignpostNumber1(OctagonSignpostNameSafariPasswordSyncingEnabled), (int)subTaskSuccess); return NO; } } @@ -924,6 +1025,10 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) - (BOOL)waitForInitialSync:(NSError *__autoreleasing*)error { secnotice("clique-legacy", "waitForInitialSync for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); + + OctagonSignpost waitForInitialSyncSignPost = OctagonSignpostBegin(OctagonSignpostNameWaitForInitialSync); + bool subTaskSuccess = false; + if([OTClique platformSupportsSOS]) { CFErrorRef initialSyncErrorRef = NULL; bool result = false; @@ -939,13 +1044,17 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) result = SOSCCWaitForInitialSync(&initialSyncErrorRef); } - BOOL initialSyncResult = (result == true); + BOOL initialSyncResult = result ? YES : NO; if (error) { *error = (NSError*)CFBridgingRelease(initialSyncErrorRef); } else { CFBridgingRelease(initialSyncErrorRef); } secnotice("clique-legacy", "waitForInitialSync waited: %d %@", initialSyncResult, error ? *error : @"no error pointer provided"); + + subTaskSuccess = initialSyncResult ? true : false; + OctagonSignpostEnd(waitForInitialSyncSignPost, OctagonSignpostNameWaitForInitialSync, OctagonSignpostNumber1(OctagonSignpostNameWaitForInitialSync), (int)subTaskSuccess); + return initialSyncResult; } else { secnotice("clique-legacy", "SOS disabled for this platform, returning NO"); @@ -954,6 +1063,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) code:errSecUnimplemented userInfo:@{NSLocalizedDescriptionKey: @"wait for initial sync unimplemented"}]; } + OctagonSignpostEnd(waitForInitialSyncSignPost, OctagonSignpostNameWaitForInitialSync, OctagonSignpostNumber1(OctagonSignpostNameWaitForInitialSync), (int)subTaskSuccess); return NO; } } @@ -962,6 +1072,9 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) { secnotice("clique-legacy", "copyViewUnawarePeerInfo for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); + OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNameCopyViewUnawarePeerInfo); + bool subTaskSuccess = false; + if([OTClique platformSupportsSOS]) { CFErrorRef copyViewUnawarePeerInfoErrorRef = NULL; CFArrayRef peerListRef = SOSCCCopyViewUnawarePeerInfo(©ViewUnawarePeerInfoErrorRef); @@ -972,6 +1085,9 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) } else { CFBridgingRelease(copyViewUnawarePeerInfoErrorRef); } + subTaskSuccess = (peerList != nil) ? true : false; + OctagonSignpostEnd(signPost, OctagonSignpostNameCopyViewUnawarePeerInfo, OctagonSignpostNumber1(OctagonSignpostNameCopyViewUnawarePeerInfo), (int)subTaskSuccess); + return peerList; } else { secnotice("clique-legacy", "SOS disabled for this platform, returning NULL"); @@ -980,6 +1096,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) code:errSecUnimplemented userInfo:@{NSLocalizedDescriptionKey: @"copy view unaware peer info unimplemented"}]; } + OctagonSignpostEnd(signPost, OctagonSignpostNameCopyViewUnawarePeerInfo, OctagonSignpostNumber1(OctagonSignpostNameCopyViewUnawarePeerInfo), (int)subTaskSuccess); return nil; } } @@ -987,6 +1104,9 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) - (BOOL)viewSet:(NSSet*)enabledViews disabledViews:(NSSet*)disabledViews { secnotice("clique-legacy", "viewSet for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); + OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNameViewSet); + bool subTaskSuccess = false; + if([OTClique platformSupportsSOS]) { bool result = false; if(self.ctx.analytics){ @@ -1001,10 +1121,13 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) result = SOSCCViewSet((__bridge CFSetRef)enabledViews, (__bridge CFSetRef)disabledViews); } - BOOL viewSetResult = (result == true); + BOOL viewSetResult = result ? YES : NO; + subTaskSuccess = result; + OctagonSignpostEnd(signPost, OctagonSignpostNameViewSet, OctagonSignpostNumber1(OctagonSignpostNameViewSet), (int)subTaskSuccess); return viewSetResult; } else { secnotice("clique-legacy", "SOS disabled for this platform, returning NO"); + OctagonSignpostEnd(signPost, OctagonSignpostNameViewSet, OctagonSignpostNumber1(OctagonSignpostNameViewSet), (int)subTaskSuccess); return NO; } } @@ -1014,6 +1137,9 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) error:(NSError *__autoreleasing*)error { secnotice("clique-legacy", "setUserCredentialsAndDSID for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); + OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNameSetUserCredentialsAndDSID); + bool subTaskSuccess = false; + if([OTClique platformSupportsSOS]) { CFErrorRef setCredentialsErrorRef = NULL; bool result = false; @@ -1039,13 +1165,16 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) &setCredentialsErrorRef); } - BOOL setCredentialsResult = (result == true); + BOOL setCredentialsResult = result ? YES : NO; if (error) { *error = (NSError*)CFBridgingRelease(setCredentialsErrorRef); } else { CFBridgingRelease(setCredentialsErrorRef); } secnotice("clique-legacy", "setUserCredentialsAndDSID results: %d %@", setCredentialsResult, setCredentialsErrorRef); + subTaskSuccess = result; + OctagonSignpostEnd(signPost, OctagonSignpostNameSetUserCredentialsAndDSID, OctagonSignpostNumber1(OctagonSignpostNameSetUserCredentialsAndDSID), (int)subTaskSuccess); + return setCredentialsResult; } else { secnotice("clique-legacy", "SOS disabled for this platform, returning NO"); @@ -1054,6 +1183,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) code:errSecUnimplemented userInfo:@{NSLocalizedDescriptionKey: @"set user credentials unimplemented"}]; } + OctagonSignpostEnd(signPost, OctagonSignpostNameSetUserCredentialsAndDSID, OctagonSignpostNumber1(OctagonSignpostNameSetUserCredentialsAndDSID), (int)subTaskSuccess); return NO; } } @@ -1063,6 +1193,8 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) error:(NSError *__autoreleasing*)error { secnotice("clique-legacy", "tryUserCredentialsAndDSID for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); + OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNameTryUserCredentialsAndDSID); + bool subTaskSuccess = false; if([OTClique platformSupportsSOS]) { CFErrorRef tryCredentialsErrorRef = NULL; @@ -1071,14 +1203,17 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) (__bridge CFStringRef)self.ctx.dsid, &tryCredentialsErrorRef); - BOOL tryCredentialsResult = (result == true); + BOOL tryCredentialsResult = result ? YES : NO; if (error) { *error = (NSError*)CFBridgingRelease(tryCredentialsErrorRef); } else { CFBridgingRelease(tryCredentialsErrorRef); } secnotice("clique-legacy", "tryUserCredentialsAndDSID results: %d %@", tryCredentialsResult, tryCredentialsErrorRef); + subTaskSuccess = result; + OctagonSignpostEnd(signPost, OctagonSignpostNameTryUserCredentialsAndDSID, OctagonSignpostNumber1(OctagonSignpostNameTryUserCredentialsAndDSID), (int)subTaskSuccess); return tryCredentialsResult; + } else { secnotice("clique-legacy", "SOS disabled for this platform, returning NO"); if(error){ @@ -1086,6 +1221,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) code:errSecUnimplemented userInfo:@{NSLocalizedDescriptionKey: @"try user credentials unimplemented"}]; } + OctagonSignpostEnd(signPost, OctagonSignpostNameTryUserCredentialsAndDSID, OctagonSignpostNumber1(OctagonSignpostNameTryUserCredentialsAndDSID), (int)subTaskSuccess); return NO; } } @@ -1093,6 +1229,8 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) - (NSArray* _Nullable)copyPeerPeerInfo:(NSError *__autoreleasing*)error { secnotice("clique-legacy", "copyPeerPeerInfo for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); + OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNameCopyPeerPeerInfo); + bool subTaskSuccess = false; if([OTClique platformSupportsSOS]) { CFErrorRef copyPeerErrorRef = NULL; @@ -1106,7 +1244,8 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) CFBridgingRelease(copyPeerErrorRef); } secnotice("clique-legacy", "copyPeerPeerInfo results: %@", peerList); - + subTaskSuccess = (peerList != nil) ? true : false; + OctagonSignpostEnd(signPost, OctagonSignpostNameCopyPeerPeerInfo, OctagonSignpostNumber1(OctagonSignpostNameCopyPeerPeerInfo), (int)subTaskSuccess); return peerList; } else { secnotice("clique-legacy", "SOS disabled for this platform, returning NO"); @@ -1115,6 +1254,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) code:errSecUnimplemented userInfo:@{NSLocalizedDescriptionKey: @"copy peer peer info unimplemented"}]; } + OctagonSignpostEnd(signPost, OctagonSignpostNameCopyPeerPeerInfo, OctagonSignpostNumber1(OctagonSignpostNameCopyPeerPeerInfo), (int)subTaskSuccess); return nil; } } @@ -1122,6 +1262,8 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) - (BOOL)peersHaveViewsEnabled:(NSArray*)viewNames error:(NSError *__autoreleasing*)error { secnotice("clique-legacy", "peersHaveViewsEnabled for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); + OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNamePeersHaveViewsEnabled); + bool subTaskSuccess = false; if([OTClique platformSupportsSOS]) { CFErrorRef viewsEnabledErrorRef = NULL; @@ -1129,7 +1271,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) CFBooleanRef result = SOSCCPeersHaveViewsEnabled((__bridge CFArrayRef)viewNames, &viewsEnabledErrorRef); if(result){ - viewsEnabledResult = CFBooleanGetValue(result); + viewsEnabledResult = CFBooleanGetValue(result) ? YES : NO; } if (error) { *error = (NSError*)CFBridgingRelease(viewsEnabledErrorRef); @@ -1137,7 +1279,8 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) CFBridgingRelease(viewsEnabledErrorRef); } secnotice("clique-legacy", "peersHaveViewsEnabled results: %@", viewsEnabledResult ? @"YES" : @"NO"); - + subTaskSuccess = viewsEnabledResult ? true : false; + OctagonSignpostEnd(signPost, OctagonSignpostNamePeersHaveViewsEnabled, OctagonSignpostNumber1(OctagonSignpostNamePeersHaveViewsEnabled), (int)subTaskSuccess); return viewsEnabledResult; } else { secnotice("clique-legacy", "SOS disabled for this platform, returning NO"); @@ -1146,6 +1289,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) code:errSecUnimplemented userInfo:@{NSLocalizedDescriptionKey: @"peers have views enabled unimplemented"}]; } + OctagonSignpostEnd(signPost, OctagonSignpostNamePeersHaveViewsEnabled, OctagonSignpostNumber1(OctagonSignpostNamePeersHaveViewsEnabled), (int)subTaskSuccess); return NO; } } @@ -1154,27 +1298,51 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) { bool result = false; CFErrorRef joinErrorRef = NULL; + bool subTaskSuccess = false; + OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNameRequestToJoinCircle); #if OCTAGON secnotice("clique-legacy", "requestToJoinCircle for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); if(OctagonIsEnabled()) { + // Sometimes, CoreCDP calls this to cause a circle creation to occur. + // So, for Octagon, we might want to request a establish, but not a reset. + + // Fetch the current trust status, so we know if we should fire off the establish. NSError* localError = nil; - [self resetAndEstablish:CuttlefishResetReasonLegacyJoinCircle error:&localError]; + CliqueStatus status = [self fetchCliqueStatus: &localError]; if(localError) { - secnotice("clique-legacy", "account reset failed: %@", localError); + secnotice("clique-legacy", "fetching clique status failed: %@", localError); if(error) { *error = localError; } + OctagonSignpostEnd(signPost, OctagonSignpostNameRequestToJoinCircle, OctagonSignpostNumber1(OctagonSignpostNameRequestToJoinCircle), (int)subTaskSuccess); return NO; + } + + if(status == CliqueStatusAbsent) { + secnotice("clique-legacy", "clique status is %@; beginning an establish", OTCliqueStatusToString(status)); + [self establish:&localError]; + + if(localError) { + if(error) { + *error = localError; + } + OctagonSignpostEnd(signPost, OctagonSignpostNameRequestToJoinCircle, OctagonSignpostNumber1(OctagonSignpostNameRequestToJoinCircle), (int)subTaskSuccess); + return NO; + } else { + secnotice("clique-legacy", "establish succeeded"); + } } else { - secnotice("clique-legacy", "account reset succeeded"); + secnotice("clique-legacy", "clique status is %@; performing no Octagon actions", OTCliqueStatusToString(status)); } // If we didn't early-exit, and we aren't going to invoke SOS below, we succeeded. if(!OctagonPlatformSupportsSOS()) { - secnotice("clique-legacy", "sos requestToJoinCircle results: %d %@", result, joinErrorRef); + secnotice("clique-legacy", "requestToJoinCircle results: %d %@", result, joinErrorRef); + subTaskSuccess = true; + OctagonSignpostEnd(signPost, OctagonSignpostNameRequestToJoinCircle, OctagonSignpostNumber1(OctagonSignpostNameRequestToJoinCircle), (int)subTaskSuccess); return YES; } } @@ -1201,21 +1369,29 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) } else { CFBridgingRelease(joinErrorRef); } + subTaskSuccess = result; + OctagonSignpostEnd(signPost, OctagonSignpostNameRequestToJoinCircle, OctagonSignpostNumber1(OctagonSignpostNameRequestToJoinCircle), (int)subTaskSuccess); + return result ? YES : NO; } - (BOOL)accountUserKeyAvailable { secnotice("clique-legacy", "accountUserKeyAvailable for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); + OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNameAccountUserKeyAvailable); + bool subTaskSuccess = false; if([OTClique platformSupportsSOS]) { - BOOL canAuthenticate = (BOOL)SOSCCCanAuthenticate(NULL); + BOOL canAuthenticate = SOSCCCanAuthenticate(NULL) ? YES : NO; if (canAuthenticate == NO) { secnotice("clique-legacy", "Security requires credentials..."); } + subTaskSuccess = canAuthenticate ? true : false; + OctagonSignpostEnd(signPost, OctagonSignpostNameAccountUserKeyAvailable, OctagonSignpostNumber1(OctagonSignpostNameAccountUserKeyAvailable), (int)subTaskSuccess); return canAuthenticate; } else { secnotice("clique-legacy", "SOS disabled for this platform, returning NO"); + OctagonSignpostEnd(signPost, OctagonSignpostNameAccountUserKeyAvailable, OctagonSignpostNumber1(OctagonSignpostNameAccountUserKeyAvailable), (int)subTaskSuccess); return NO; } } @@ -1226,6 +1402,8 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) { #if OCTAGON secnotice("clique-findbottle", "finding optimal bottles for context:%@, altdsid:%@", data.context, data.altDSID); + OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNameFindOptimalBottleIDsWithContextData); + bool subTaskSuccess = false; if(OctagonIsEnabled()) { __block NSError* localError = nil; @@ -1238,6 +1416,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) if (error) { *error = localError; } + OctagonSignpostEnd(signPost, OctagonSignpostNameFindOptimalBottleIDsWithContextData, OctagonSignpostNumber1(OctagonSignpostNameFindOptimalBottleIDsWithContextData), (int)subTaskSuccess); return nil; } [control fetchAllViableBottles:OTCKContainerName @@ -1264,6 +1443,8 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) secnotice("clique-findbottle", "findOptimalBottleIDsWithContextData complete"); + subTaskSuccess = (localError == nil) ? true : false; + OctagonSignpostEnd(signPost, OctagonSignpostNameFindOptimalBottleIDsWithContextData, OctagonSignpostNumber1(OctagonSignpostNameFindOptimalBottleIDsWithContextData), (int)subTaskSuccess); return bottleIDs; } else { // With octagon off, fail with 'unimplemented' @@ -1272,6 +1453,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) code:errSecUnimplemented userInfo:@{NSLocalizedDescriptionKey: @"optimal bottle IDs unimplemented"}]; } + OctagonSignpostEnd(signPost, OctagonSignpostNameFindOptimalBottleIDsWithContextData, OctagonSignpostNumber1(OctagonSignpostNameFindOptimalBottleIDsWithContextData), (int)subTaskSuccess); return nil; } #else // !OCTAGON @@ -1307,11 +1489,13 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) { #if OCTAGON secnotice("clique-fetchescrow", "fetching entropy for bottling for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); - + OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNameFetchEscrowContents); + __block bool subTaskSuccess = false; if(OctagonIsEnabled()) { NSError* controlError = nil; OTControl* control = [self makeOTControl:&controlError]; if (!control) { + OctagonSignpostEnd(signPost, OctagonSignpostNameFetchEscrowContents, OctagonSignpostNumber1(OctagonSignpostNameFetchEscrowContents), (int)subTaskSuccess); reply(nil, nil, nil, controlError); return; } @@ -1326,12 +1510,13 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) } else{ secnotice("clique-fetchescrow","fetchEscrowContents succeeded"); } + subTaskSuccess = (error == nil) ? true : false; + OctagonSignpostEnd(signPost, OctagonSignpostNameFetchEscrowContents, OctagonSignpostNumber1(OctagonSignpostNameFetchEscrowContents), (int)subTaskSuccess); reply (entropy, bottleID, signingPublicKey, error); }]; - - return; } else { // With octagon off, fail with 'unimplemented' + OctagonSignpostEnd(signPost, OctagonSignpostNameFetchEscrowContents, OctagonSignpostNumber1(OctagonSignpostNameFetchEscrowContents), (int)subTaskSuccess); reply(nil, nil, nil, [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:@{NSLocalizedDescriptionKey: @"fetchEscrowRecordContents unimplemented"}]); @@ -1350,6 +1535,8 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) NSError* createRecoveryKeyError = nil; NSMutableDictionary *userInfo = [NSMutableDictionary new]; NSError* retError = nil; + OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNameSetNewRecoveryKeyWithData); + __block bool subTaskSuccess = false; SecRecoveryKey *rk = SecRKCreateRecoveryKeyWithError(recoveryKey, &createRecoveryKeyError); if (rk == nil) { @@ -1357,6 +1544,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) userInfo[NSLocalizedDescriptionKey] = @"SecRKCreateRecoveryKeyWithError() failed"; userInfo[NSUnderlyingErrorKey] = createRecoveryKeyError; retError = [NSError errorWithDomain:getkSecureBackupErrorDomain() code:kSecureBackupInternalError userInfo:userInfo]; + OctagonSignpostEnd(signPost, OctagonSignpostNameSetNewRecoveryKeyWithData, OctagonSignpostNumber1(OctagonSignpostNameSetNewRecoveryKeyWithData), (int)subTaskSuccess); reply(nil, retError); return; } @@ -1368,6 +1556,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) userInfo[NSLocalizedDescriptionKey] = @"SecRKRegisterBackupPublicKey() failed"; userInfo[NSUnderlyingErrorKey] = underlyingError; retError = [NSError errorWithDomain:getkSecureBackupErrorDomain() code:kSecureBackupInternalError userInfo:userInfo]; + OctagonSignpostEnd(signPost, OctagonSignpostNameSetNewRecoveryKeyWithData, OctagonSignpostNumber1(OctagonSignpostNameSetNewRecoveryKeyWithData), (int)subTaskSuccess); reply(nil,retError); return; } else { @@ -1381,16 +1570,20 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) OTControl* control = [ctx makeOTControl:&controlError]; if(!control) { secnotice("octagon-setrecoverykey", "failed to fetch OTControl object: %@", controlError); + OctagonSignpostEnd(signPost, OctagonSignpostNameSetNewRecoveryKeyWithData, OctagonSignpostNumber1(OctagonSignpostNameSetNewRecoveryKeyWithData), (int)subTaskSuccess); reply(nil, controlError); return; } [control createRecoveryKey:OTCKContainerName contextID:ctx.context recoveryKey:recoveryKey reply:^(NSError * createError) { if(createError){ secerror("octagon-setrecoverykey, failed to create octagon recovery key"); + OctagonSignpostEnd(signPost, OctagonSignpostNameSetNewRecoveryKeyWithData, OctagonSignpostNumber1(OctagonSignpostNameSetNewRecoveryKeyWithData), (int)subTaskSuccess); reply(nil, createError); return; } else { secnotice("octagon-setrecoverykey", "successfully set octagon recovery key"); + subTaskSuccess = true; + OctagonSignpostEnd(signPost, OctagonSignpostNameSetNewRecoveryKeyWithData, OctagonSignpostNumber1(OctagonSignpostNameSetNewRecoveryKeyWithData), (int)subTaskSuccess); reply(rk, nil); return; } @@ -1406,6 +1599,9 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) reply:(void(^)(NSError* _Nullable error))reply { #if OCTAGON + OctagonSignpost signpost = OctagonSignpostBegin(OctagonSignpostNameRecoverOctagonUsingData); + __block bool subTaskSuccess = false; + if(OctagonRecoveryKeyIsEnabled()) { NSError* controlError = nil; OTControl* control = [ctx makeOTControl:&controlError]; @@ -1414,16 +1610,20 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) if(!control) { secnotice("clique-recoverykey", "failed to fetch OTControl object: %@", controlError); + OctagonSignpostEnd(signpost, OctagonSignpostNameRecoverOctagonUsingData, OctagonSignpostNumber1(OctagonSignpostNameRecoverOctagonUsingData), (int)subTaskSuccess); reply(controlError); return; } [control joinWithRecoveryKey:OTCKContainerName contextID:ctx.context recoveryKey:recoveryKey reply:^(NSError *joinError) { if(joinError){ secnotice("clique-recoverykey", "failed to join using recovery key: %@", joinError); + OctagonSignpostEnd(signpost, OctagonSignpostNameRecoverOctagonUsingData, OctagonSignpostNumber1(OctagonSignpostNameRecoverOctagonUsingData), (int)subTaskSuccess); reply(joinError); return; } secnotice("clique-recoverykey", "successfully joined using recovery key"); + subTaskSuccess = true; + OctagonSignpostEnd(signpost, OctagonSignpostNameRecoverOctagonUsingData, OctagonSignpostNumber1(OctagonSignpostNameRecoverOctagonUsingData), (int)subTaskSuccess); reply(nil); }]; } @@ -1439,10 +1639,14 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) reply:(void(^)(NSError* _Nullable error))reply { #if OCTAGON + OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNamePerformedCDPStateMachineRun); NSError* controlError = nil; + __block bool subTaskSuccess = false; + OTControl* control = [self makeOTControl:&controlError]; if(!control) { secnotice("clique-cdp-sm", "octagon, failed to fetch OTControl object: %@", controlError); + OctagonSignpostEnd(signPost, OctagonSignpostNamePerformedCDPStateMachineRun, OctagonSignpostNumber1(OctagonSignpostNamePerformedCDPStateMachineRun), (int)subTaskSuccess); reply(controlError); return; } @@ -1450,6 +1654,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) [control postCDPFollowupResult:success type:type error:error containerName:OTCKContainerName contextName:OTDefaultContext reply:^(NSError *postError) { if(postError){ secnotice("clique-cdp-sm", "failed to post %@ result: %@ ", type, postError); + OctagonSignpostEnd(signPost, OctagonSignpostNamePerformedCDPStateMachineRun, OctagonSignpostNumber1(OctagonSignpostNamePerformedCDPStateMachineRun), (int)subTaskSuccess); reply(postError); return; } @@ -1458,7 +1663,9 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) } else { secnotice("clique-cdp-sm", "posted error: %@: %@", type, error); } - reply(NULL); + subTaskSuccess = success ? true : false; + OctagonSignpostEnd(signPost, OctagonSignpostNamePerformedCDPStateMachineRun, OctagonSignpostNumber1(OctagonSignpostNamePerformedCDPStateMachineRun), (int)subTaskSuccess); + reply(nil); }]; #else // !OCTAGON reply([NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil]); @@ -1469,12 +1676,16 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) { #if OCTAGON OTControl* control = nil; + OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNameWaitForOctagonUpgrade); + __block bool subTaskSuccess = false; if (!OctagonIsEnabled()) { secnotice("clique-waitforoctagonupgrade", "cannot upgrade, octagon is not enabled"); if (error) { *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:@{NSLocalizedDescriptionKey: @"Octagon is not enabled"}]; } + OctagonSignpostEnd(signPost, OctagonSignpostNameWaitForOctagonUpgrade, OctagonSignpostNumber1(OctagonSignpostNameWaitForOctagonUpgrade), (int)subTaskSuccess); + return NO; } @@ -1485,6 +1696,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) if (error) { *error = controlError; } + OctagonSignpostEnd(signPost, OctagonSignpostNameWaitForOctagonUpgrade, OctagonSignpostNumber1(OctagonSignpostNameWaitForOctagonUpgrade), (int)subTaskSuccess); return NO; } @@ -1505,7 +1717,8 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) if (blockError && error) { *error = blockError; } - + subTaskSuccess = ret ? true : false; + OctagonSignpostEnd(signPost, OctagonSignpostNameWaitForOctagonUpgrade, OctagonSignpostNumber1(OctagonSignpostNameWaitForOctagonUpgrade), (int)subTaskSuccess); return ret; #else // !OCTAGON if(error) { diff --git a/keychain/ot/OTConstants.h b/keychain/ot/OTConstants.h index 1b7ba2d2..736ab162 100644 --- a/keychain/ot/OTConstants.h +++ b/keychain/ot/OTConstants.h @@ -34,7 +34,7 @@ bool OctagonIsEnabled(void); extern NSString* OTDefaultContext; -extern NSString* const OctagonErrorDomain; +extern NSErrorDomain const OctagonErrorDomain; /* used for defaults writes */ extern NSString* OTDefaultsDomain; diff --git a/keychain/ot/OTConstants.m b/keychain/ot/OTConstants.m index 9fbf29a3..e839d139 100644 --- a/keychain/ot/OTConstants.m +++ b/keychain/ot/OTConstants.m @@ -31,7 +31,7 @@ #import "keychain/ot/OTConstants.h" #import "utilities/debugging.h" -NSString* const OctagonErrorDomain = @"com.apple.security.octagon"; +NSErrorDomain const OctagonErrorDomain = @"com.apple.security.octagon"; NSString* OTDefaultContext = @"defaultContext"; NSString* OTDefaultsDomain = @"com.apple.security.octagon"; diff --git a/keychain/ot/OTCuttlefishContext.h b/keychain/ot/OTCuttlefishContext.h index 4665950c..426c5dc8 100644 --- a/keychain/ot/OTCuttlefishContext.h +++ b/keychain/ot/OTCuttlefishContext.h @@ -197,6 +197,10 @@ preapprovedKeys:(NSArray* _Nullable)preapprovedKeys - (void)postConfirmPasscodeCFU:(NSError**)error; - (void)postRecoveryKeyCFU:(NSError**)error; +// For reporting +- (BOOL)machineIDOnMemoizedList:(NSString*)machineID error:(NSError**)error NS_SWIFT_NOTHROW; +- (NSNumber* _Nullable)numberOfPeersInModelWithMachineID:(NSString*)machineID error:(NSError**)error; + @end NS_ASSUME_NONNULL_END diff --git a/keychain/ot/OTCuttlefishContext.m b/keychain/ot/OTCuttlefishContext.m index 3ebe0853..0eac866a 100644 --- a/keychain/ot/OTCuttlefishContext.m +++ b/keychain/ot/OTCuttlefishContext.m @@ -186,6 +186,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; _stateMachine = [[OctagonStateMachine alloc] initWithName:@"octagon" states:[NSSet setWithArray:[OctagonStateMap() allKeys]] + flags:AllOctagonFlags() initialState:OctagonStateInitializing queue:_queue stateEngine:self @@ -381,24 +382,22 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; - (BOOL)accountAvailable:(NSString*)altDSID error:(NSError**)error { - __block NSError* localError = nil; secnotice("octagon", "Account available with altDSID: %@ %@", altDSID, self); self.launchSequence.firstLaunch = true; - - dispatch_sync(self.queue, ^{ - [self.accountMetadataStore _onqueuePersistAccountChanges:^OTAccountMetadataClassC * _Nonnull(OTAccountMetadataClassC * _Nonnull metadata) { - // Do not set the account available bit here, since we need to check if it's HSA2. The initializing state should do that for us... - metadata.altDSID = altDSID; - return metadata; - } error:&localError]; + NSError* localError = nil; + [self.accountMetadataStore persistAccountChanges:^OTAccountMetadataClassC * _Nonnull(OTAccountMetadataClassC * _Nonnull metadata) { + // Do not set the account available bit here, since we need to check if it's HSA2. The initializing state should do that for us... + metadata.altDSID = altDSID; + + return metadata; + } error:&localError]; + + if(localError) { + secerror("octagon: unable to persist new account availability: %@", localError); + } - if(localError) { - secerror("octagon: unable to persist new account availability: %@", localError); - } - }); - [self.stateMachine handleFlag:OctagonFlagAccountIsAvailable]; if(localError) { @@ -437,7 +436,6 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; OctagonStateTransitionOperation* attemptOp = [OctagonStateTransitionOperation named:@"octagon-account-gone" intending:OctagonStateNoAccountDoReset errorState:OctagonStateNoAccountDoReset - timeout:OctagonStateTransitionDefaultTimeout withBlockTakingSelf:^(OctagonStateTransitionOperation * _Nonnull op) { __block NSError* localError = nil; @@ -815,11 +813,11 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; return [OctagonStateTransitionOperation named:@"octagon-determine-icloud-state" intending:OctagonStateNoAccount errorState:OctagonStateError - timeout:OctagonStateTransitionDefaultTimeout withBlockTakingSelf:^(OctagonStateTransitionOperation * _Nonnull op) { STRONGIFY(self); - NSString* primaryAccountAltDSID = self.authKitAdapter.primaryiCloudAccountAltDSID; + NSError *authKitError = nil; + NSString* primaryAccountAltDSID = [self.authKitAdapter primaryiCloudAccountAltDSID:&authKitError]; dispatch_sync(self.queue, ^{ NSError* error = nil; @@ -849,7 +847,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; } } else { - secnotice("octagon", "iCloud account is not present"); + secnotice("octagon", "iCloud account is not present: %@", authKitError); [self.accountMetadataStore _onqueuePersistAccountChanges:^OTAccountMetadataClassC *(OTAccountMetadataClassC * metadata) { metadata.icloudAccountState = OTAccountMetadataClassC_AccountState_NO_ACCOUNT; @@ -1113,6 +1111,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; if([flags _onqueueContains:OctagonFlagFetchAuthKitMachineIDList]) { [flags _onqueueRemoveFlag:OctagonFlagFetchAuthKitMachineIDList]; + secnotice("octagon", "Received an suggestion to update the machine ID list (while ready); updating trusted device list"); // If the cached list changes due to this fetch, go into 'updated'. Otherwise, back into ready with you! @@ -1179,7 +1178,6 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; return [OctagonStateTransitionOperation named:@"octagon-initializing" intending:OctagonStateNoAccount errorState:OctagonStateError - timeout:OctagonStateTransitionDefaultTimeout withBlockTakingSelf:^(OctagonStateTransitionOperation * _Nonnull op) { STRONGIFY(self); NSError* localError = nil; @@ -1230,7 +1228,6 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; return [OctagonStateTransitionOperation named:@"octagon-health-securityd-trust-check" intending:OctagonStateTPHTrustCheck errorState:OctagonStatePostRepairCFU - timeout:OctagonStateTransitionDefaultTimeout withBlockTakingSelf:^(OctagonStateTransitionOperation * _Nonnull op) { NSError* localError = nil; OTAccountMetadataClassC* account = [self.accountMetadataStore loadOrCreateAccountMetadata:&localError]; @@ -1250,7 +1247,6 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; return [OctagonStateTransitionOperation named:@"octagon-health-tph-trust-check" intending:OctagonStateCuttlefishTrustCheck errorState:OctagonStatePostRepairCFU - timeout:OctagonStateTransitionDefaultTimeout withBlockTakingSelf:^(OctagonStateTransitionOperation * _Nonnull op) { [self checkTrustStatusAndPostRepairCFUIfNecessary:^(CliqueStatus status, BOOL posted, BOOL hasIdentity, NSError *trustFromTPHError) { @@ -1328,7 +1324,6 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; return [OctagonStateTransitionOperation named:@"octagon-health-post-repair-cfu" intending:OctagonStateUntrusted errorState:OctagonStateError - timeout:OctagonStateTransitionDefaultTimeout withBlockTakingSelf:^(OctagonStateTransitionOperation * _Nonnull op) { [self checkTrustStatusAndPostRepairCFUIfNecessary:^(CliqueStatus status, BOOL posted, @@ -1350,7 +1345,6 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; return [OctagonStateTransitionOperation named:@"octagon-icloud-account-available" intending:OctagonStateCheckTrustState errorState:OctagonStateError - timeout:OctagonStateTransitionDefaultTimeout withBlockTakingSelf:^(OctagonStateTransitionOperation * _Nonnull op) { STRONGIFY(self); // Register with APS, but don't bother to wait until it's complete. @@ -1543,7 +1537,6 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; return [OctagonStateTransitionOperation named:@"start-companion-pairing" intending:OctagonStateBecomeUntrusted errorState:OctagonStateError - timeout:OctagonStateTransitionDefaultTimeout withBlockTakingSelf:^(OctagonStateTransitionOperation * _Nonnull op) { STRONGIFY(self); OTPairingInitiateWithCompletion(self.queue, ^(bool success, NSError *error) { @@ -1568,7 +1561,6 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; return [OctagonStateTransitionOperation named:@"octagon-become-untrusted" intending:intendedState errorState:OctagonStateError - timeout:OctagonStateTransitionDefaultTimeout withBlockTakingSelf:^(OctagonStateTransitionOperation * _Nonnull op) { STRONGIFY(self); NSError* localError = nil; @@ -1621,7 +1613,6 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; return [OctagonStateTransitionOperation named:@"octagon-ready" intending:OctagonStateReady errorState:OctagonStateError - timeout:OctagonStateTransitionDefaultTimeout withBlockTakingSelf:^(OctagonStateTransitionOperation * _Nonnull op) { STRONGIFY(self); @@ -2362,8 +2353,10 @@ preapprovedKeys:(NSArray* _Nullable)preapprovedKeys __block BOOL excluded = NO; __block CliqueStatus trustStatus = CliqueStatusError; - [self.cuttlefishXPCWrapper trustStatusWithContainer:self.containerName context:self.contextID reply:^(TrustedPeersHelperEgoPeerStatus *egoStatus, - NSError *xpcError) { + [self.cuttlefishXPCWrapper trustStatusWithContainer:self.containerName + context:self.contextID + reply:^(TrustedPeersHelperEgoPeerStatus *egoStatus, + NSError *xpcError) { TPPeerStatus status = egoStatus.egoStatus; peerID = egoStatus.egoPeerID; excluded = egoStatus.isExcluded; @@ -2701,5 +2694,55 @@ preapprovedKeys:(NSArray* _Nullable)preapprovedKeys self.postedRepairCFU = NO; } +// Metrics passthroughs + +- (BOOL)machineIDOnMemoizedList:(NSString*)machineID error:(NSError**)error +{ + __block BOOL onList = NO; + __block NSError* reterror = nil; + [self.cuttlefishXPCWrapper fetchAllowedMachineIDsWithContainer:self.containerName + context:self.contextID + reply:^(NSSet * _Nonnull machineIDs, NSError * _Nullable miderror) { + if(miderror) { + secnotice("octagon-metrics", "Failed to fetch allowed machineIDs: %@", miderror); + reterror = miderror; + } else { + if([machineIDs containsObject:machineID]) { + onList = YES; + } + secnotice("octagon-metrics", "MID (%@) on list: %@", machineID, onList ? @"yes" : @"no"); + } + }]; + + if(reterror && error) { + *error = reterror; + } + return onList; +} + +- (NSNumber* _Nullable)numberOfPeersInModelWithMachineID:(NSString*)machineID error:(NSError**)error +{ + __block NSNumber* ret = nil; + __block NSError* retError = nil; + [self.cuttlefishXPCWrapper trustStatusWithContainer:self.containerName + context:self.contextID + reply:^(TrustedPeersHelperEgoPeerStatus *egoStatus, + NSError *xpcError) { + if(xpcError) { + secnotice("octagon-metrics", "Unable to fetch trust status: %@", xpcError); + retError = xpcError; + } else { + ret = egoStatus.peerCountsByMachineID[machineID] ?: @(0); + secnotice("octagon-metrics", "Number of peers with machineID (%@): %@", machineID, ret); + } + }]; + + if(retError && error) { + *error = retError; + } + + return ret; +} + @end #endif diff --git a/keychain/ot/OTDefines.h b/keychain/ot/OTDefines.h index 216d2614..8d5f6e71 100644 --- a/keychain/ot/OTDefines.h +++ b/keychain/ot/OTDefines.h @@ -26,6 +26,8 @@ #if OCTAGON #include #include +#import "keychain/ot/OTConstants.h" + NS_ASSUME_NONNULL_BEGIN extern NSString* const OctagonEventAttributeZoneName; @@ -40,7 +42,7 @@ extern NSString* const TrustedPeersHelperErrorDomain; extern NSString* const CuttlefishErrorRetryAfterKey; /* Octagon Errors */ -typedef enum { +typedef NS_ERROR_ENUM(OctagonErrorDomain, OctagonError) { //OTErrorNoColumn = 1, //OTErrorKeyGeneration = 2, //OTErrorEmptySecret = 3, @@ -82,7 +84,13 @@ typedef enum { OTErrorSOSAdapter = 39, //OctagonErrorNoAccount = 40, OTErrorRecoveryKeyMalformed = 41, -} OctagonErrorCode; + OTAuthKitNoAltDSID = 42, + OTAuthKitAKDeviceListRequestContextClass = 43, + OTAuthKitNoPrimaryAccount = 44, + OTAuthKitNoAuthenticationController = 45, + OTAuthKitMachineIDMissing = 46, + OTAuthKitPrimaryAccountHaveNoDSID = 47, +}; #define OTMasterSecretLength 72 diff --git a/keychain/ot/OTDetermineHSA2AccountStatusOperation.m b/keychain/ot/OTDetermineHSA2AccountStatusOperation.m index a74ff515..43a5f127 100644 --- a/keychain/ot/OTDetermineHSA2AccountStatusOperation.m +++ b/keychain/ot/OTDetermineHSA2AccountStatusOperation.m @@ -45,9 +45,9 @@ self.finishedOp = [[NSOperation alloc] init]; [self dependOnBeforeGroupFinished:self.finishedOp]; - NSString* primaryAccountAltDSID = self.deps.authKitAdapter.primaryiCloudAccountAltDSID; + NSError *error = nil; + NSString* primaryAccountAltDSID = [self.deps.authKitAdapter primaryiCloudAccountAltDSID:&error]; - NSError* error = nil; if(primaryAccountAltDSID != nil) { secnotice("octagon", "iCloud account is present; checking HSA2 status"); @@ -74,7 +74,7 @@ } } else { - secnotice("octagon", "iCloud account is not present"); + secnotice("octagon", "iCloud account is not present: %@", error); [self.deps.stateHolder persistAccountChanges:^OTAccountMetadataClassC *(OTAccountMetadataClassC * metadata) { metadata.icloudAccountState = OTAccountMetadataClassC_AccountState_NO_ACCOUNT; diff --git a/keychain/ot/OTManager.m b/keychain/ot/OTManager.m index 323919c1..92c0caae 100644 --- a/keychain/ot/OTManager.m +++ b/keychain/ot/OTManager.m @@ -240,20 +240,6 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; } } --(NSString*) askAccountsForDSID -{ - NSString *dsid = nil; - @try { - ACAccountStore *accountStore = [[ACAccountStore alloc] init]; - - ACAccount *account = [accountStore aa_primaryAppleAccount]; - dsid = [account aa_personID]; - } @catch (NSException * e) { - secerror("octagon: failed to retrieve account: %@", e); - } - return dsid; -} - + (instancetype _Nullable)manager { if(!OctagonIsEnabled()) { secerror("octagon: Attempt to fetch a manager while Octagon is disabled"); @@ -988,14 +974,51 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; values[OctagonAnalyticsStateMachineState] = OctagonStateMap()[cuttlefishContext.stateMachine.currentState]; - values[OctagonAnalyticIcloudAccountState] = @([cuttlefishContext currentMemoizedAccountState]); - values[OctagonAnalyticsTrustState] = @([cuttlefishContext currentMemoizedTrustState]); + NSError* metadataError = nil; + OTAccountMetadataClassC* metadata = [cuttlefishContext.accountMetadataStore loadOrCreateAccountMetadata:&metadataError]; + if(!metadata || metadataError) { + secnotice("octagon-analytics", "Error fetching Octagon metadata: %@", metadataError); + } + values[OctagonAnalyticIcloudAccountState] = metadata ? @(metadata.icloudAccountState) : nil; + values[OctagonAnalyticsTrustState] = metadata ? @(metadata.trustState) : nil; + NSDate* healthCheck = [cuttlefishContext currentMemoizedLastHealthCheck]; values[OctagonAnalyticsLastHealthCheck] = @([CKKSAnalytics fuzzyDaysSinceDate:healthCheck]); NSDate* dateOfLastKSR = [[CKKSAnalytics logger] datePropertyForKey: OctagonAnalyticsLastKeystateReady]; values[OctagonAnalyticsLastKeystateReady] = @([CKKSAnalytics fuzzyDaysSinceDate:dateOfLastKSR]); + if(metadata && metadata.icloudAccountState == OTAccountMetadataClassC_AccountState_ACCOUNT_AVAILABLE) { + values[OctagonAnalyticsAttemptedJoin] = @(metadata.attemptedJoin); + + NSError* machineIDError = nil; + NSString* machineID = [cuttlefishContext.authKitAdapter machineID:&machineIDError]; + if(machineIDError) { + secnotice("octagon-analytics", "Error fetching machine ID: %@", metadataError); + } + + values[OctagonAnalyticsHaveMachineID] = @(machineID != nil); + + if(machineID) { + NSError* midOnListError = nil; + BOOL midOnList = [cuttlefishContext machineIDOnMemoizedList:machineID error:&midOnListError]; + + if(midOnListError) { + secnotice("octagon-analytics", "Error fetching 'mid on list': %@", midOnListError); + } else { + values[OctagonAnalyticsMIDOnMemoizedList] = @(midOnList); + } + + NSError* peersWithMIDError = nil; + NSNumber* peersWithMID = [cuttlefishContext numberOfPeersInModelWithMachineID:machineID error:&peersWithMIDError]; + if(peersWithMID && peersWithMIDError == nil) { + values[OctagonAnalyticsPeersWithMID] = peersWithMID; + } else { + secnotice("octagon-analytics", "Error fetching how many peers have our MID: %@", midOnListError); + } + } + } + // Track CFU usage and success/failure metrics // 1. Users in a good state will have no outstanding CFU, and will not have done a CFU // 2. Users in a bad state who have not repsonded to the CFU (repaired) will have a pending CFU. diff --git a/keychain/ot/OTPrepareOperation.m b/keychain/ot/OTPrepareOperation.m index b2e5dd96..2b34ec23 100644 --- a/keychain/ot/OTPrepareOperation.m +++ b/keychain/ot/OTPrepareOperation.m @@ -71,10 +71,15 @@ NSString* bottleSalt = nil; - if(self.deps.authKitAdapter.primaryiCloudAccountAltDSID){ - bottleSalt = self.deps.authKitAdapter.primaryiCloudAccountAltDSID; + NSError *authKitError = nil; + NSString *altDSID = [self.deps.authKitAdapter primaryiCloudAccountAltDSID:&authKitError]; + + if (altDSID) { + bottleSalt = altDSID; } else { + secnotice("octagon-sos", "AuthKit doesn't know about the altDSID: %@", authKitError); + NSError* accountError = nil; OTAccountMetadataClassC* account = [self.deps.stateHolder loadOrCreateAccountMetadata:&accountError]; diff --git a/keychain/ot/OTSOSUpgradeOperation.m b/keychain/ot/OTSOSUpgradeOperation.m index fad75dd8..8f223984 100644 --- a/keychain/ot/OTSOSUpgradeOperation.m +++ b/keychain/ot/OTSOSUpgradeOperation.m @@ -167,9 +167,11 @@ [self dependOnBeforeGroupFinished:self.finishedOp]; NSString* bottleSalt = nil; + NSError *authKitError = nil; - if(self.deps.authKitAdapter.primaryiCloudAccountAltDSID){ - bottleSalt = self.deps.authKitAdapter.primaryiCloudAccountAltDSID; + NSString *altDSID = [self.deps.authKitAdapter primaryiCloudAccountAltDSID:&authKitError]; + if(altDSID){ + bottleSalt = altDSID; } else { NSError* accountError = nil; diff --git a/keychain/ot/OTSetRecoveryKeyOperation.m b/keychain/ot/OTSetRecoveryKeyOperation.m index b83cbefa..4761d525 100644 --- a/keychain/ot/OTSetRecoveryKeyOperation.m +++ b/keychain/ot/OTSetRecoveryKeyOperation.m @@ -58,10 +58,15 @@ NSString* salt = nil; - if(self.deps.authKitAdapter.primaryiCloudAccountAltDSID){ - salt = self.deps.authKitAdapter.primaryiCloudAccountAltDSID; + NSError *authKitError = nil; + NSString *altDSID = [self.deps.authKitAdapter primaryiCloudAccountAltDSID:&authKitError]; + + if (altDSID) { + salt = altDSID; } else { + secnotice("octagon", "authkit doesn't know about the altdsid, using stored value: %@", authKitError); + NSError* accountError = nil; OTAccountMetadataClassC* account = [self.deps.stateHolder loadOrCreateAccountMetadata:&accountError]; diff --git a/keychain/ot/OTStates.h b/keychain/ot/OTStates.h index 5133b381..ede2cb05 100644 --- a/keychain/ot/OTStates.h +++ b/keychain/ot/OTStates.h @@ -147,6 +147,7 @@ NSDictionary* OctagonStateInverseMap(void); // Octagon: ensure Octagon operations can't occur on SA accounts NSSet* OctagonInAccountStates(void); NSSet* OctagonHealthSourceStates(void); +NSSet* AllOctagonFlags(void); ////// State machine flags extern OctagonFlag* const OctagonFlagIDMSLevelChanged; @@ -156,7 +157,8 @@ extern OctagonFlag* const OctagonFlagEgoPeerPreapproved; extern OctagonFlag* const OctagonFlagCKKSRequestsTLKUpload; // We've received a change notification from cuttlefish; we should probably see what's new -extern OctagonFlag* const OctagonFlagCuttlefishNotification; +extern OctagonFlag* const OctagonFlagCuttlefishNotification NS_SWIFT_NAME(OctagonFlagCuttlefishNotification); + extern OctagonFlag* const OctagonFlagFetchAuthKitMachineIDList; diff --git a/keychain/ot/OTStates.m b/keychain/ot/OTStates.m index 18e42299..5af0ffb4 100644 --- a/keychain/ot/OTStates.m +++ b/keychain/ot/OTStates.m @@ -248,4 +248,28 @@ OctagonFlag* const OctagonFlagUnlocked = (OctagonFlag*)@"unlocked"; OctagonFlag* const OctagonFlagAttemptSOSUpdatePreapprovals = (OctagonFlag*)@"attempt_sos_update_preapprovals"; OctagonFlag* const OctagonFlagAttemptSOSConsistency = (OctagonFlag*)@"attempt_sos_consistency"; OctagonFlag* const OctagonFlagEscrowRequestInformCloudServicesOperation = (OctagonFlag*)@"escrowrequest_inform_cloudservices"; + +NSSet* AllOctagonFlags(void) +{ + static NSSet* f = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSMutableSet* flags = [NSMutableSet set]; + + [flags addObject:OctagonFlagIDMSLevelChanged]; + [flags addObject:OctagonFlagEgoPeerPreapproved]; + [flags addObject:OctagonFlagCKKSRequestsTLKUpload]; + [flags addObject:OctagonFlagCuttlefishNotification]; + [flags addObject:OctagonFlagAccountIsAvailable]; + [flags addObject:OctagonFlagAttemptSOSUpgrade]; + [flags addObject:OctagonFlagFetchAuthKitMachineIDList]; + [flags addObject:OctagonFlagUnlocked]; + [flags addObject:OctagonFlagAttemptSOSUpdatePreapprovals]; + [flags addObject:OctagonFlagAttemptSOSConsistency]; + + f = flags; + }); + return f; +} + #endif // OCTAGON diff --git a/keychain/ot/OTVouchWithBottleOperation.m b/keychain/ot/OTVouchWithBottleOperation.m index c96ba590..48a381bc 100644 --- a/keychain/ot/OTVouchWithBottleOperation.m +++ b/keychain/ot/OTVouchWithBottleOperation.m @@ -71,12 +71,16 @@ if(self.bottleSalt != nil) { secnotice("octagon", "using passed in altdsid, altdsid is: %@", self.bottleSalt); } else{ - NSString* altDSID = self.deps.authKitAdapter.primaryiCloudAccountAltDSID; + NSError *error = nil; + + NSString* altDSID = [self.deps.authKitAdapter primaryiCloudAccountAltDSID:&error]; if(altDSID){ secnotice("octagon", "fetched altdsid is: %@", altDSID); self.bottleSalt = altDSID; } else { + secnotice("octagon", "authkit doesn't know about the altdsid, using stored value: %@", error); + NSError* accountError = nil; OTAccountMetadataClassC* account = [self.deps.stateHolder loadOrCreateAccountMetadata:&accountError]; diff --git a/keychain/ot/OTVouchWithRecoveryKeyOperation.m b/keychain/ot/OTVouchWithRecoveryKeyOperation.m index cded9242..0bb767fe 100644 --- a/keychain/ot/OTVouchWithRecoveryKeyOperation.m +++ b/keychain/ot/OTVouchWithRecoveryKeyOperation.m @@ -70,9 +70,10 @@ secnotice("octagon", "using passed in altdsid, altdsid is: %@", self.salt); salt = self.salt; } else{ - if(self.deps.authKitAdapter.primaryiCloudAccountAltDSID){ - secnotice("octagon", "using auth kit adapter, altdsid is: %@", self.deps.authKitAdapter.primaryiCloudAccountAltDSID); - salt = self.deps.authKitAdapter.primaryiCloudAccountAltDSID; + NSString *altDSID = [self.deps.authKitAdapter primaryiCloudAccountAltDSID:nil]; + if(altDSID){ + secnotice("octagon", "using auth kit adapter, altdsid is: %@", altDSID); + salt = altDSID; } else { NSError* accountError = nil; diff --git a/keychain/ot/ObjCImprovements.h b/keychain/ot/ObjCImprovements.h index 8e2f54ff..90f93499 100644 --- a/keychain/ot/ObjCImprovements.h +++ b/keychain/ot/ObjCImprovements.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 20178 Apple Inc. All Rights Reserved. + * Copyright (c) 2019 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * diff --git a/keychain/ot/OctagonCKKSPeerAdapter.m b/keychain/ot/OctagonCKKSPeerAdapter.m index 2aac36d8..b7707e9e 100644 --- a/keychain/ot/OctagonCKKSPeerAdapter.m +++ b/keychain/ot/OctagonCKKSPeerAdapter.m @@ -104,7 +104,7 @@ { // Async to sync again! No other option. dispatch_semaphore_t sema = dispatch_semaphore_create(0); - SFKeychainManager* keychainManager = [SFKeychainManager defaultManager]; + SFKeychainManager* keychainManager = [SFKeychainManager defaultOverCommitManager]; __block SFIdentity* identity = nil; __block NSError* localError = nil; diff --git a/keychain/ot/OctagonFlags.h b/keychain/ot/OctagonFlags.h index 6170941e..60d85855 100644 --- a/keychain/ot/OctagonFlags.h +++ b/keychain/ot/OctagonFlags.h @@ -13,6 +13,7 @@ NS_ASSUME_NONNULL_BEGIN @protocol OctagonFlagContainer - (BOOL)_onqueueContains:(OctagonFlag*)flag; - (NSArray*)dumpFlags; +- (CKKSCondition*)conditionForFlag:(OctagonFlag*)flag; @end @protocol OctagonFlagSetter @@ -27,7 +28,11 @@ NS_ASSUME_NONNULL_BEGIN @interface OctagonFlags : NSObject -- (instancetype)initWithQueue:(dispatch_queue_t)queue; + +@property NSMutableDictionary* flagConditions; + +- (instancetype)initWithQueue:(dispatch_queue_t)queue + flags:(NSSet*)possibleFlags; - (NSString*)contentsAsString; @end diff --git a/keychain/ot/OctagonFlags.m b/keychain/ot/OctagonFlags.m index 766ab3fb..b42fc447 100644 --- a/keychain/ot/OctagonFlags.m +++ b/keychain/ot/OctagonFlags.m @@ -2,19 +2,29 @@ #if OCTAGON #import "keychain/ot/OctagonFlags.h" +#import "keychain/ot/OTStates.h" +#import "keychain/ckks/CKKSCondition.h" @interface OctagonFlags () @property dispatch_queue_t queue; @property NSMutableSet* flags; +@property (readonly) NSSet* allowableFlags; @end @implementation OctagonFlags - (instancetype)initWithQueue:(dispatch_queue_t)queue + flags:(NSSet*)possibleFlags { if((self = [super init])) { _queue = queue; _flags = [NSMutableSet set]; + _flagConditions = [[NSMutableDictionary alloc] init]; + _allowableFlags = possibleFlags; + + [possibleFlags enumerateObjectsUsingBlock:^(OctagonState * _Nonnull obj, BOOL * _Nonnull stop) { + self.flagConditions[obj] = [[CKKSCondition alloc] init]; + }]; } return self; } @@ -47,6 +57,10 @@ [self.flags addObject:flag]; } +- (CKKSCondition*)conditionForFlag:(OctagonFlag*)flag { + return self.flagConditions[flag]; +} + - (void)setFlag:(nonnull OctagonFlag *)flag { dispatch_sync(self.queue, ^{ [self _onqueueSetFlag:flag]; @@ -55,7 +69,12 @@ - (void)_onqueueRemoveFlag:(nonnull OctagonFlag *)flag { dispatch_assert_queue(self.queue); + + NSAssert([self.allowableFlags containsObject:flag], @"state machine tried to handle unknown flag %@", flag); + [self.flags removeObject:flag]; + [self.flagConditions[flag] fulfill]; + self.flagConditions[flag] = [[CKKSCondition alloc]init]; } @end diff --git a/keychain/ot/OctagonStateMachine.h b/keychain/ot/OctagonStateMachine.h index a4503e08..4aeabe1c 100644 --- a/keychain/ot/OctagonStateMachine.h +++ b/keychain/ot/OctagonStateMachine.h @@ -43,6 +43,7 @@ NS_ASSUME_NONNULL_BEGIN @property (readonly) id flags; @property NSMutableDictionary* stateConditions; + @property (readonly) CKKSCondition* paused; @property (readonly) NSSet* allowableStates; @@ -54,10 +55,11 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithName:(NSString*)name states:(NSSet*)possibleStates + flags:(NSSet*)possibleFlags initialState:(OctagonState*)initialState queue:(dispatch_queue_t)queue stateEngine:(id)stateEngine - lockStateTracker:(CKKSLockStateTracker* _Nullable)lockStateTracker; + lockStateTracker:(CKKSLockStateTracker*)lockStateTracker; - (void)startOperation; - (void)haltOperation; diff --git a/keychain/ot/OctagonStateMachine.m b/keychain/ot/OctagonStateMachine.m index ef550aad..dcd693ad 100644 --- a/keychain/ot/OctagonStateMachine.m +++ b/keychain/ot/OctagonStateMachine.m @@ -6,7 +6,7 @@ #import "keychain/ot/ObjCImprovements.h" #import "keychain/ckks/CKKSNearFutureScheduler.h" #import "keychain/ckks/CKKS.h" - +#import "keychain/ot/OTStates.h" #import "utilities/debugging.h" #define statemachinelog(scope, format, ...) \ @@ -55,6 +55,7 @@ format, - (instancetype)initWithName:(NSString*)name states:(NSSet*)possibleStates + flags:(NSSet*)possibleFlags initialState:(OctagonState*)initialState queue:(dispatch_queue_t)queue stateEngine:(id)stateEngine @@ -72,7 +73,7 @@ format, _queue = queue; _operationQueue = [[NSOperationQueue alloc] init]; - _currentFlags = [[OctagonFlags alloc] initWithQueue:queue]; + _currentFlags = [[OctagonFlags alloc] initWithQueue:queue flags:possibleFlags]; _stateEngine = stateEngine; @@ -302,6 +303,8 @@ format, // Overwrite any existing pending flag! self.pendingFlags[pendingFlag.flag] = pendingFlag; + self.currentFlags.flagConditions[pendingFlag.flag] = [[CKKSCondition alloc]init]; + // Do we need to recheck any conditions? Anything which is currently the state of the world needs checking OctagonPendingConditions recheck = pendingFlag.conditions & self.currentConditions; if(recheck != 0x0) { @@ -324,7 +327,7 @@ format, __block NSMutableDictionary* d = [NSMutableDictionary dictionary]; dispatch_sync(self.queue, ^{ for(OctagonFlag* flag in [self.pendingFlags allKeys]) { - d[flag] = [self.pendingFlags[flag] description];; + d[flag] = [self.pendingFlags[flag] description]; } }); @@ -531,10 +534,23 @@ format, { statemachinelog("state-rpc", "Beginning a '%@' rpc", name); + CKKSResultOperation* initialTransitionOp + = [OctagonStateTransitionOperation named:[NSString stringWithFormat:@"intial-transition-%@", name] + entering:path.initialState]; + + // Note that this has an initial timeout of 10s, and isn't configurable. + OctagonStateTransitionRequest* request = [[OctagonStateTransitionRequest alloc] init:name + sourceStates:sourceStates + serialQueue:self.queue + timeout:10 * NSEC_PER_SEC + transitionOp:initialTransitionOp]; + OctagonStateTransitionWatcher* watcher = [[OctagonStateTransitionWatcher alloc] initNamed:[NSString stringWithFormat:@"watcher-%@", name] serialQueue:self.queue - path:path]; + path:path + initialRequest:request]; [watcher timeout:self.timeout?:120*NSEC_PER_SEC]; + [self registerStateTransitionWatcher:watcher]; WEAKIFY(self); @@ -548,15 +564,6 @@ format, [self.operationQueue addOperation:replyOp]; - CKKSResultOperation* initialTransitionOp - = [OctagonStateTransitionOperation named:[NSString stringWithFormat:@"intial-transition-%@", name] - entering:path.initialState]; - - OctagonStateTransitionRequest* request = [[OctagonStateTransitionRequest alloc] init:name - sourceStates:sourceStates - serialQueue:self.queue - timeout:10*NSEC_PER_SEC - transitionOp:initialTransitionOp]; [self handleExternalRequest:request]; } diff --git a/keychain/ot/OctagonStateMachineHelpers.h b/keychain/ot/OctagonStateMachineHelpers.h index aa2fc920..d936223d 100644 --- a/keychain/ot/OctagonStateMachineHelpers.h +++ b/keychain/ot/OctagonStateMachineHelpers.h @@ -59,12 +59,11 @@ extern OctagonState* const OctagonStateMachineHalted; + (instancetype)named:(NSString*)name intending:(OctagonState*)intendedState errorState:(OctagonState*)errorState - timeout:(dispatch_time_t)timeout withBlockTakingSelf:(void(^)(OctagonStateTransitionOperation* op))block; // convenience constructor. Will always succeed at entering the state. + (instancetype)named:(NSString*)name - entering:(OctagonState*)intendedState; + entering:(OctagonState*)intendedState NS_SWIFT_NAME(init(name:entering:)); @end diff --git a/keychain/ot/OctagonStateMachineHelpers.m b/keychain/ot/OctagonStateMachineHelpers.m index 1ebd4cb9..a2362e32 100644 --- a/keychain/ot/OctagonStateMachineHelpers.m +++ b/keychain/ot/OctagonStateMachineHelpers.m @@ -51,7 +51,6 @@ OctagonState* const OctagonStateMachineHalted = (OctagonState*) @"halted"; + (instancetype)named:(NSString*)name intending:(OctagonState*)intendedState errorState:(OctagonState*)errorState - timeout:(dispatch_time_t)timeout withBlockTakingSelf:(void(^)(OctagonStateTransitionOperation* op))block { OctagonStateTransitionOperation* op = [[self alloc] initIntending:intendedState @@ -62,7 +61,6 @@ OctagonState* const OctagonStateMachineHalted = (OctagonState*) @"halted"; block(op); }]; op.name = name; - [op timeout:timeout]; return op; } @@ -74,6 +72,7 @@ OctagonState* const OctagonStateMachineHalted = (OctagonState*) @"halted"; op.name = name; return op; } + @end @interface OctagonStateTransitionRequest () diff --git a/keychain/ot/OctagonStateMachineObservers.h b/keychain/ot/OctagonStateMachineObservers.h index 17094bd0..afa30844 100644 --- a/keychain/ot/OctagonStateMachineObservers.h +++ b/keychain/ot/OctagonStateMachineObservers.h @@ -49,9 +49,11 @@ NS_ASSUME_NONNULL_BEGIN @property (readonly) CKKSResultOperation* result; @property (readonly) OctagonStateTransitionPath* intendedPath; +// If the initial request times out, the watcher will fail as well. - (instancetype)initNamed:(NSString*)name serialQueue:(dispatch_queue_t)queue - path:(OctagonStateTransitionPath*)path; + path:(OctagonStateTransitionPath*)path + initialRequest:(OctagonStateTransitionRequest* _Nullable)initialRequest; - (instancetype)timeout:(dispatch_time_t)timeout; diff --git a/keychain/ot/OctagonStateMachineObservers.m b/keychain/ot/OctagonStateMachineObservers.m index b770f8f3..d7e86808 100644 --- a/keychain/ot/OctagonStateMachineObservers.m +++ b/keychain/ot/OctagonStateMachineObservers.m @@ -107,6 +107,10 @@ @property BOOL completed; @property (nullable) OctagonStateTransitionPathStep* remainingPath; @property NSOperationQueue* operationQueue; + +@property (nullable) OctagonStateTransitionRequest* initialRequest; +@property (nullable) CKKSResultOperation* initialTimeoutListenerOp; + @property bool timeoutCanOccur; @property dispatch_queue_t queue; @end @@ -115,7 +119,8 @@ - (instancetype)initNamed:(NSString*)name serialQueue:(dispatch_queue_t)queue - path:(OctagonStateTransitionPath*)pathBeginning + path:(OctagonStateTransitionPath*)pathBeginning + initialRequest:(OctagonStateTransitionRequest* _Nullable)initialRequest { if((self = [super init])) { _name = name; @@ -128,6 +133,28 @@ _queue = queue; _timeoutCanOccur = true; + _initialRequest = initialRequest; + if(initialRequest) { + WEAKIFY(self); + _initialTimeoutListenerOp = [CKKSResultOperation named:[NSString stringWithFormat:@"watcher-timeout-%@", name] withBlock:^{ + STRONGIFY(self); + if(!self) { + return; + } + + NSError* opError = initialRequest.transitionOperation.error; + + if(opError && + [opError.domain isEqualToString:CKKSResultErrorDomain] && + opError.code == CKKSResultTimedOut) { + dispatch_sync(self.queue, ^{ + [self _onqueuePerformTimeoutWithUnderlyingError:opError]; + }); + } + }]; + [_initialTimeoutListenerOp addDependency:initialRequest.transitionOperation]; + [_operationQueue addOperation:_initialTimeoutListenerOp]; + } _active = NO; _completed = NO; @@ -162,25 +189,31 @@ } } +- (void)_onqueuePerformTimeoutWithUnderlyingError:(NSError* _Nullable)underlyingError +{ + dispatch_assert_queue(self.queue); + + if(self.timeoutCanOccur) { + self.timeoutCanOccur = false; + + NSString* description = [NSString stringWithFormat:@"Operation(%@) timed out waiting to start for [%@]", + self.name, + self.remainingPath]; + + self.result.error = [NSError errorWithDomain:CKKSResultErrorDomain + code:CKKSResultTimedOut + description:description + underlying:underlyingError]; + [self onqueueStartFinishOperation]; + } +} + - (instancetype)timeout:(dispatch_time_t)timeout { WEAKIFY(self); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeout), self.queue, ^{ STRONGIFY(self); - if(self.timeoutCanOccur) { - self.timeoutCanOccur = false; - - NSString* description = [NSString stringWithFormat:@"Operation(%@) timed out waiting to start for [%@]", - self.name, - self.remainingPath]; - - self.result.error = [NSError errorWithDomain:CKKSResultErrorDomain - code:CKKSResultTimedOut - description:description - underlying:nil]; - [self onqueueStartFinishOperation]; - - } + [self _onqueuePerformTimeoutWithUnderlyingError:nil]; }); return self; @@ -194,7 +227,6 @@ return; } - OctagonStateTransitionPathStep* nextPath = [self.remainingPath nextStep:attempt.nextState]; if(nextPath) { diff --git a/keychain/ot/tests/octagon/OctagonTests+DeviceList.swift b/keychain/ot/tests/octagon/OctagonTests+DeviceList.swift index 3fa30c28..848bb213 100644 --- a/keychain/ot/tests/octagon/OctagonTests+DeviceList.swift +++ b/keychain/ot/tests/octagon/OctagonTests+DeviceList.swift @@ -104,6 +104,32 @@ class OctagonDeviceListTests: OctagonTestsBase { "peer 1 should distrust peer 2 after update") } + func testNumberOfPeersInModel() throws { + self.startCKAccountStatusMock() + + XCTAssert(self.mockAuthKit.currentDeviceList().contains(self.mockAuthKit2.currentMachineID), "AuthKit should already have device 2 on the list") + + _ = self.assertResetAndBecomeTrustedInDefaultContext() + + self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) + self.verifyDatabaseMocks() + + do { + let number = try self.cuttlefishContext.numberOfPeersInModel(withMachineID: self.mockAuthKit.currentMachineID) + XCTAssertEqual(number.intValue, 1, "Should have a one peer for numberOfPeersInModel after an initial join") + } catch { + XCTFail("Should not have failed fetching the number of peers with a mid: \(error)") + } + + do { + let number = try self.cuttlefishContext.numberOfPeersInModel(withMachineID: "not-a-real-machine-id") + XCTAssertEqual(number.intValue, 0, "Should have a zero peers for an invalid MID") + } catch { + XCTFail("Should not have failed fetching the number of peers with a mid: \(error)") + } + } + func testRemovePeerWhenRemovedFromDeviceListViaIncompleteNotification() throws { self.startCKAccountStatusMock() @@ -491,13 +517,13 @@ class OctagonDeviceListTests: OctagonTestsBase { sleep(1) - XCTAssertTrue(self.cuttlefishContext.stateMachine.possiblePendingFlags().contains("recd_push"), "Should have recd_push pending flag") + XCTAssertTrue(self.cuttlefishContext.stateMachine.possiblePendingFlags().contains(OctagonFlagCuttlefishNotification), "Should have recd_push pending flag") // Now, peer should unlock and receive an Octagon push self.aksLockState = false self.lockStateTracker.recheck() - sleep(1) + self.assertPendingFlagHandled(context: self.cuttlefishContext, pendingFlag: OctagonFlagCuttlefishNotification, within: 10 * NSEC_PER_SEC) XCTAssertEqual(self.cuttlefishContext.stateMachine.possiblePendingFlags(), [], "Should have 0 pending flags") self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) diff --git a/keychain/ot/tests/octagon/OctagonTests+ErrorHandling.swift b/keychain/ot/tests/octagon/OctagonTests+ErrorHandling.swift index e838a1af..b5069a73 100644 --- a/keychain/ot/tests/octagon/OctagonTests+ErrorHandling.swift +++ b/keychain/ot/tests/octagon/OctagonTests+ErrorHandling.swift @@ -122,13 +122,12 @@ class OctagonErrorHandlingTests: OctagonTestsBase { self.sendContainerChange(context: self.cuttlefishContext) sleep(1) - XCTAssertTrue(self.cuttlefishContext.stateMachine.possiblePendingFlags().contains("recd_push"), "Should have recd_push pending flag") + XCTAssertTrue(self.cuttlefishContext.stateMachine.possiblePendingFlags().contains(OctagonFlagCuttlefishNotification), "Should have recd_push pending flag") let waitForUnlockStateCondition = self.cuttlefishContext.stateMachine.stateConditions[OctagonStateWaitForUnlock] as! CKKSCondition XCTAssertEqual(0, self.cuttlefishContext.stateMachine.paused.wait(10 * NSEC_PER_SEC), "state machine should pause") self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) - sleep(1) // Check that we haven't been spinning let sameWaitForUnlockStateCondition = self.cuttlefishContext.stateMachine.stateConditions[OctagonStateWaitForUnlock] as! CKKSCondition XCTAssert(waitForUnlockStateCondition == sameWaitForUnlockStateCondition, "Conditions should be the same (as the state machine should be halted)") @@ -136,7 +135,7 @@ class OctagonErrorHandlingTests: OctagonTestsBase { self.aksLockState = false self.lockStateTracker.recheck() - sleep(1) + self.assertPendingFlagHandled(context: self.cuttlefishContext, pendingFlag: OctagonFlagCuttlefishNotification, within: 10 * NSEC_PER_SEC) XCTAssertEqual(self.cuttlefishContext.stateMachine.possiblePendingFlags(), [], "Should have 0 pending flags") @@ -211,12 +210,12 @@ class OctagonErrorHandlingTests: OctagonTestsBase { sleep(1) - XCTAssertTrue(self.cuttlefishContext.stateMachine.possiblePendingFlags().contains("recd_push"), "Should have recd_push pending flag") + XCTAssertTrue(self.cuttlefishContext.stateMachine.possiblePendingFlags().contains(OctagonFlagCuttlefishNotification), "Should have recd_push pending flag") self.aksLockState = false self.lockStateTracker.recheck() - sleep(1) + self.assertPendingFlagHandled(context: self.cuttlefishContext, pendingFlag: OctagonFlagCuttlefishNotification, within: 10 * NSEC_PER_SEC) XCTAssertEqual(self.cuttlefishContext.stateMachine.possiblePendingFlags(), [], "Should have 0 pending flags") self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) @@ -247,13 +246,12 @@ class OctagonErrorHandlingTests: OctagonTestsBase { self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext) - sleep(5) - XCTAssertEqual(0, self.cuttlefishContext.stateMachine.paused.wait(10 * NSEC_PER_SEC), "state machine should pause") self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) XCTAssertEqual(self.cuttlefishContext.stateMachine.possiblePendingFlags(), [], "Should have zero pending flags after retry") + sleep(5) let post = self.fakeCuttlefishServer.fetchChangesCalledCount XCTAssertEqual(post, pre + 2, "should have fetched two times, the first response would have been a transaction error") } @@ -335,13 +333,11 @@ class OctagonErrorHandlingTests: OctagonTestsBase { self.assertEnters(context: peer2, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) sleep(1) - XCTAssertTrue(peer2.stateMachine.possiblePendingFlags().contains("recd_push"), "Should have recd_push pending flag") + XCTAssertTrue(peer2.stateMachine.possiblePendingFlags().contains(OctagonFlagCuttlefishNotification), "Should have recd_push pending flag") self.aksLockState = false self.lockStateTracker.recheck() - sleep(1) - XCTAssertEqual(self.cuttlefishContext.stateMachine.possiblePendingFlags(), [], "Should have 0 pending flags") self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) @@ -474,7 +470,7 @@ class OctagonErrorHandlingTests: OctagonTestsBase { // Now, CKKS decides to reset the world, but a conflict occurs on hierarchy upload self.silentZoneDeletesAllowed = true - var tlkUUIDs : [CKRecordZone.ID:String] = [:] + var tlkUUIDs: [CKRecordZone.ID: String] = [:] self.silentFetchesAllowed = false self.expectCKFetchAndRun(beforeFinished: { @@ -507,7 +503,7 @@ class OctagonErrorHandlingTests: OctagonTestsBase { self.verifyDatabaseMocks() XCTAssertEqual(tlkUUIDs.count, self.ckksZones.count, "Should have the right number of conflicted TLKs") - for (zoneID,tlkUUID) in tlkUUIDs { + for (zoneID, tlkUUID) in tlkUUIDs { XCTAssertEqual(tlkUUID, (self.keys![zoneID] as? ZoneKeys)?.tlk?.uuid, "TLK should match conflicted version") } } diff --git a/keychain/ot/tests/octagon/OctagonTests+RecoveryKey.swift b/keychain/ot/tests/octagon/OctagonTests+RecoveryKey.swift index 0bf2b04c..ad69de5b 100644 --- a/keychain/ot/tests/octagon/OctagonTests+RecoveryKey.swift +++ b/keychain/ot/tests/octagon/OctagonTests+RecoveryKey.swift @@ -923,7 +923,7 @@ let createKeyExpectation = self.expectation(description: "createKeyExpectation returns") self.manager.createRecoveryKey(OTCKContainerName, contextID: self.otcliqueContext.context ?? "defaultContext", recoveryKey: recoveryKey) { error in XCTAssertNotNil(error, "error should not be nil") - XCTAssertEqual((error! as NSError).code, Int(OTErrorLimitedPeer.rawValue), "error code should be limited peer") + XCTAssertEqual((error! as NSError).code, OctagonError.OTErrorLimitedPeer.rawValue, "error code should be limited peer") createKeyExpectation.fulfill() } self.wait(for: [createKeyExpectation], timeout: 10) @@ -1194,7 +1194,6 @@ XCTAssertNotNil(recoveryKey, "recoveryKey should not be nil") self.manager.setSOSEnabledForPlatformFlag(true) - let createKeyExpectation = self.expectation(description: "createKeyExpectation returns") self.manager.createRecoveryKey(OTCKContainerName, contextID: self.otcliqueContext.context ?? "defaultContext", recoveryKey: recoveryKey) { error in XCTAssertNotNil(error, "error should NOT be nil") diff --git a/keychain/ot/tests/octagon/OctagonTests+Reset.swift b/keychain/ot/tests/octagon/OctagonTests+Reset.swift index 562d6270..00037248 100644 --- a/keychain/ot/tests/octagon/OctagonTests+Reset.swift +++ b/keychain/ot/tests/octagon/OctagonTests+Reset.swift @@ -510,7 +510,7 @@ class OctagonResetTests: OctagonTestsBase { self.assertEnters(context: cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) } - func testResetReasonLegacyJoinCircle() throws { + func testLegacyJoinCircleDoesNotReset() throws { self.cuttlefishContext.startOctagonStateMachine() self.startCKAccountStatusMock() @@ -537,11 +537,8 @@ class OctagonResetTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) self.verifyDatabaseMocks() - let resetExpectation = self.expectation(description: "resetExpectation callback occurs") self.fakeCuttlefishServer.resetListener = { request in - self.fakeCuttlefishServer.resetListener = nil - resetExpectation.fulfill() - XCTAssertTrue(request.resetReason.rawValue == CuttlefishResetReason.legacyJoinCircle.rawValue, "reset reason should be legacy join circle") + XCTFail("requestToJoinCircle should not reset Octagon") return nil } @@ -551,7 +548,8 @@ class OctagonResetTests: OctagonTestsBase { XCTFail("Shouldn't have errored requesting to join circle: \(error)") throw error } - self.wait(for: [resetExpectation], timeout: 10) + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) } func testResetReasonTestGenerated() throws { diff --git a/keychain/ot/tests/octagon/OctagonTests+SOS.swift b/keychain/ot/tests/octagon/OctagonTests+SOS.swift index 67a55f23..a239ad9b 100644 --- a/keychain/ot/tests/octagon/OctagonTests+SOS.swift +++ b/keychain/ot/tests/octagon/OctagonTests+SOS.swift @@ -222,31 +222,32 @@ class OctagonSOSTests: OctagonTestsBase { var clique: OTClique do { - clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext) + clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext, + resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") throw error } - do{ + do { try clique.joinAfterRestore() } catch { XCTAssertNotNil(error, "error should not be nil") } - do{ + do { try clique.isLastFriend() } catch { XCTAssertNotNil(error, "error should not be nil") } - do{ + do { try clique.safariPasswordSyncingEnabled() } catch { XCTAssertNotNil(error, "error should not be nil") } - do{ + do { try clique.waitForInitialSync() } catch { XCTAssertNotNil(error, "error should not be nil") @@ -254,25 +255,25 @@ class OctagonSOSTests: OctagonTestsBase { clique.viewSet(Set(), disabledViews: Set()) - do{ + do { try clique.setUserCredentialsAndDSID("", password: Data()) } catch { XCTAssertNotNil(error, "error should not be nil") } - do{ + do { try clique.tryUserCredentialsAndDSID("", password: Data()) } catch { XCTAssertNotNil(error, "error should not be nil") } - do{ + do { try clique.peersHaveViewsEnabled([""]) } catch { XCTAssertNotNil(error, "error should not be nil") } - do{ + do { try clique.requestToJoinCircle() } catch { XCTAssertNotNil(error, "error should not be nil") @@ -280,14 +281,14 @@ class OctagonSOSTests: OctagonTestsBase { clique.accountUserKeyAvailable() - do{ + do { _ = try clique.copyViewUnawarePeerInfo() - }catch{ + } catch { XCTAssertNotNil(error, "error should not be nil") } do { _ = try clique.copyPeerPeerInfo() - }catch{ + } catch { XCTAssertNotNil(error, "error should not be nil") } } diff --git a/keychain/ot/tests/octagon/OctagonTests-BridgingHeader.h b/keychain/ot/tests/octagon/OctagonTests-BridgingHeader.h index 086a45bc..850a15b1 100644 --- a/keychain/ot/tests/octagon/OctagonTests-BridgingHeader.h +++ b/keychain/ot/tests/octagon/OctagonTests-BridgingHeader.h @@ -25,6 +25,7 @@ #import #import "keychain/ckks/CKKS.h" #import "keychain/ckks/CKKSKeychainView.h" +#import "keychain/ckks/CKKSResultOperation.h" #import #import @@ -46,6 +47,7 @@ #import "keychain/ot/OTStates.h" #import "keychain/ot/OTCuttlefishContext.h" #import "keychain/ot/OctagonStateMachine.h" +#import "keychain/ot/OctagonStateMachineHelpers.h" #import "keychain/ot/OTDeviceInformationAdapter.h" diff --git a/keychain/ot/tests/octagon/OctagonTests.swift b/keychain/ot/tests/octagon/OctagonTests.swift index 0fa46d15..de42b910 100644 --- a/keychain/ot/tests/octagon/OctagonTests.swift +++ b/keychain/ot/tests/octagon/OctagonTests.swift @@ -77,8 +77,13 @@ class OTMockAuthKitAdapter: OTAuthKitAdapter { self.listeners = CKKSListenerCollection(name: "test-authkit") } - func primaryiCloudAccountAltDSID() -> String? { - return self.altDSID + func primaryiCloudAccountAltDSID() throws -> String { + guard let altDSID = self.altDSID else { + throw NSError(domain: OctagonErrorDomain, + code: OctagonError.OTAuthKitNoPrimaryAccount.rawValue, + userInfo: nil) + } + return altDSID } func accountIsHSA2(byAltDSID altDSID: String) -> Bool { @@ -418,6 +423,10 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { } } + func assertPendingFlagHandled(context: OTCuttlefishContext, pendingFlag: String, within: UInt64) { + XCTAssertEqual(0, (context.stateMachine.flags.condition(forFlag: pendingFlag)).wait(within), "State machine should have handled '\(pendingFlag)'") + } + func assertConsidersSelfTrusted(context: OTCuttlefishContext, isLocked: Bool = false) { XCTAssertEqual(context.currentMemoizedTrustState(), .TRUSTED, "Trust state (for \(context)) should be trusted") @@ -604,6 +613,29 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { XCTAssertEqual(midList.machineIDs(in: .disallowed), disallowed, "Model's disallowed list should match pattern") XCTAssertEqual(midList.machineIDs(in: .unknown), unknown, "Model's unknown list should match pattern") } + + for allowedMID in allowed { + var err : NSError? + let onList = context.machineID(onMemoizedList: allowedMID, error: &err) + + XCTAssertNil(err, "Should not have failed determining memoized list state") + XCTAssertTrue(onList, "MID on allowed list should return 'is on list'") + + do { + let number = try context.numberOfPeersInModel(withMachineID: allowedMID) + XCTAssert(number.intValue >= 0, "Should have a non-negative number for numberOfPeersInModel") + } catch { + XCTFail("Should not have failed fetching the number of peers with a mid: \(error)") + } + } + + for disallowedMID in disallowed { + var err : NSError? + let onList = context.machineID(onMemoizedList: disallowedMID, error: &err) + + XCTAssertNil(err, "Should not have failed determining memoized list state") + XCTAssertFalse(onList, "MID on allowed list should return 'not on list'") + } } func loadSecret(label: String) throws -> (Data?) { @@ -764,7 +796,7 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { let entropy = try self.loadSecret(label: sponsorPeerID!) XCTAssertNotNil(entropy, "entropy should not be nil") - let altDSID = joiningContext.authKitAdapter.primaryiCloudAccountAltDSID() + let altDSID = try joiningContext.authKitAdapter.primaryiCloudAccountAltDSID() XCTAssertNotNil(altDSID, "Should have an altDSID") let bottles = self.fakeCuttlefishServer.state.bottles.filter { $0.peerID == sponsorPeerID } @@ -772,7 +804,7 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { let bottle = bottles[0] let joinWithBottleExpectation = self.expectation(description: "joinWithBottle callback occurs") - joiningContext.join(withBottle: bottle.bottleID, entropy: entropy!, bottleSalt: altDSID!) { error in + joiningContext.join(withBottle: bottle.bottleID, entropy: entropy!, bottleSalt: altDSID) { error in XCTAssertNil(error, "error should be nil") joinWithBottleExpectation.fulfill() } @@ -1158,6 +1190,39 @@ class OctagonTests: OctagonTestsBase { self.assertSelfTLKSharesInCloudKit(context: self.cuttlefishContext) } + func testRequestToJoinCircleForEmptyAccount() throws { + self.startCKAccountStatusMock() + + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + + let clique = try OTClique(contextData: self.otcliqueContext) + + // Now, call requestToJoin. It should cause an establish to happen + try clique.requestToJoinCircle() + + // Now, we should be in 'ready' + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfTrusted(context: self.cuttlefishContext) + self.assertConsidersSelfTrustedCachedAccountStatus(context: self.cuttlefishContext) + + // and all subCKKSes should enter ready... + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) + self.verifyDatabaseMocks() + + self.assertSelfTLKSharesInCloudKit(context: self.cuttlefishContext) + + // But calling it again shouldn't make establish() occur again + self.fakeCuttlefishServer.establishListener = { _ in + XCTFail("establish called at incorrect time") + return nil + } + + // call should be a nop + try clique.requestToJoinCircle() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + } + func testCliqueStatusWhileLocked() throws { self.startCKAccountStatusMock() @@ -2093,7 +2158,8 @@ class OctagonTests: OctagonTestsBase { ]) let watcher = OctagonStateTransitionWatcher(named: "should-fail", serialQueue: self.cuttlefishContext.queue, - path: path!) + path: path!, + initialRequest: nil) self.cuttlefishContext.stateMachine.register(watcher) let watcherCompleteOperationExpectation = self.expectation(description: "watcherCompleteOperationExpectation returns") @@ -2119,6 +2185,49 @@ class OctagonTests: OctagonTestsBase { self.verifyDatabaseMocks() } + func testTimingOutStateTransitionWatcher() throws { + self.startCKAccountStatusMock() + + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + + let stateTransitionOp = OctagonStateTransitionOperation(name: "will-never-run", + entering: OctagonStateReady) + let requestNever = OctagonStateTransitionRequest("name", + sourceStates: Set([OctagonStateWaitForHSA2]), + serialQueue: self.cuttlefishContext.queue, + timeout: 1 * NSEC_PER_SEC, + transitionOp: stateTransitionOp) + + // Set up a watcher that we expect to fail due to its initial transition op timing out... + let path = OctagonStateTransitionPath(from: [ + OctagonStateResetAndEstablish: [ + OctagonStateInitiatorVouchWithBottle: [ + OctagonStateResetAndEstablish: OctagonStateTransitionPathStep.success(), + ], + ], + ]) + let watcher = OctagonStateTransitionWatcher(named: "should-fail", + serialQueue: self.cuttlefishContext.queue, + path: path!, + initialRequest: (requestNever as! OctagonStateTransitionRequest)) + self.cuttlefishContext.stateMachine.register(watcher) + + let watcherCompleteOperationExpectation = self.expectation(description: "watcherCompleteOperationExpectation returns") + let watcherFinishOp = CKKSResultOperation.named("should-fail-cleanup", with: { + XCTAssertNotNil(watcher.result.error, "watcher should have errored") + watcherCompleteOperationExpectation.fulfill() + }) + + watcherFinishOp.addDependency(watcher.result) + self.operationQueue.addOperation(watcherFinishOp) + + // and the watcher should finish, too + self.wait(for: [watcherCompleteOperationExpectation], timeout: 10) + + self.verifyDatabaseMocks() + } + func testLeaveCliqueAndPostCFU() throws { self.startCKAccountStatusMock() @@ -2146,6 +2255,10 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) self.assertConsidersSelfUntrusted(context: self.cuttlefishContext) + // As a bonus, calling leave again should be fast (and not error) + XCTAssertNoThrow(try clique.leave(), "Should be no error departing clique (again)") + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + let cfuExpectation = self.expectation(description: "cfu callback occurs") self.cuttlefishContext.setPostedBool(false) self.cuttlefishContext.checkTrustStatusAndPostRepairCFUIfNecessary { _, posted, _, error in diff --git a/keychain/securityd/Regressions/SOSAccountTesting.h b/keychain/securityd/Regressions/SOSAccountTesting.h index 37565454..f2d431ee 100644 --- a/keychain/securityd/Regressions/SOSAccountTesting.h +++ b/keychain/securityd/Regressions/SOSAccountTesting.h @@ -776,38 +776,49 @@ static inline void showActiveValidPeers(SOSAccount* account) { #define ok_or_quit(COND,MESSAGE,LABEL) ok(COND, MESSAGE); if(!(COND)) goto LABEL static inline bool testAccountPersistence(SOSAccount* account) { + + __block bool retval = false; + __block NSData* accountDER = NULL; + SOSDataSourceFactoryRef test_factory = SOSTestDataSourceFactoryCreate(); SOSDataSourceRef test_source = SOSTestDataSourceCreate(); SOSTestDataSourceFactorySetDataSource(test_factory, CFSTR("TestType"), test_source); - NSError* error = nil; - - bool retval = false; - SOSAccount* reinflatedAccount = NULL; - NSData* accountDER = NULL; SOSAccountCheckHasBeenInSync_wTxn(account); - // DER encode account to accountData - this allows checking discreet DER functions - size_t size = [account.trust getDEREncodedSize:account err:&error]; - error = nil; - uint8_t buffer[size]; - uint8_t* start = [account.trust encodeToDER:account err:&error start:buffer end:buffer + sizeof(buffer)]; - error = nil; + [account performTransaction:^(SOSAccountTransaction * _Nonnull txn) { + NSError* error = nil; + + // DER encode account to accountData - this allows checking discreet DER functions + size_t size = [account.trust getDEREncodedSize:account err:&error]; + error = nil; + uint8_t buffer[size]; + uint8_t* start = [account.trust encodeToDER:account err:&error start:buffer end:buffer + sizeof(buffer)]; + error = nil; - ok_or_quit(start, "successful encoding", errOut); - ok_or_quit(start == buffer, "Used whole buffer", errOut); + ok_or_quit(start, "successful encoding", errOut); + ok_or_quit(start == buffer, "Used whole buffer", errOut); - accountDER = [NSData dataWithBytes:buffer length:size]; - ok_or_quit(accountDER, "Made CFData for Account", errOut); + accountDER = [NSData dataWithBytes:buffer length:size]; + ok_or_quit(accountDER, "Made CFData for Account", errOut); + retval = true; + errOut: + do {} while(0); + }]; + + SOSAccount* reinflatedAccount = NULL; + NSError* error = nil; + + require(retval, errOut); // Re-inflate to "inflated" reinflatedAccount = [SOSAccount accountFromData:accountDER factory:test_factory error:&error]; + ok(reinflatedAccount, "inflated: %@", error); error = nil; - ok(reinflatedAccount, "inflated"); ok(CFEqualSafe((__bridge CFTypeRef)reinflatedAccount, (__bridge CFTypeRef)account), "Compares"); // Repeat through SOSAccountCopyEncodedData() interface - this is the normally called combined interface @@ -817,10 +828,10 @@ static inline bool testAccountPersistence(SOSAccount* account) { ok(reinflatedAccount, "inflated2: %@", error); ok(CFEqual((__bridge CFTypeRef)account, (__bridge CFTypeRef)reinflatedAccount), "Compares"); - error = nil; retval = true; - errOut: + error = nil; + return retval; } diff --git a/keychain/securityd/Regressions/secd-62-account-backup.m b/keychain/securityd/Regressions/secd-62-account-backup.m index 8205fdd9..f62cc022 100644 --- a/keychain/securityd/Regressions/secd-62-account-backup.m +++ b/keychain/securityd/Regressions/secd-62-account-backup.m @@ -156,7 +156,7 @@ static void tests(void) ok([bob_account.trust checkForRings:&error], "Alice_account is good"); CFReleaseNull(error); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 4, "updates"); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 5, "updates"); ok([alice_account.trust checkForRings:&error], "Alice_account is good"); @@ -269,7 +269,7 @@ static void tests(void) int secd_62_account_backup(int argc, char *const *argv) { #if !TARGET_OS_SIMULATOR - plan_tests(95); + plan_tests(98); #else plan_tests(1); #endif diff --git a/keychain/securityd/Regressions/secd-66-account-recovery.m b/keychain/securityd/Regressions/secd-66-account-recovery.m index 60664cb8..2a2fa0ba 100644 --- a/keychain/securityd/Regressions/secd-66-account-recovery.m +++ b/keychain/securityd/Regressions/secd-66-account-recovery.m @@ -226,8 +226,8 @@ static void tests(bool recKeyFirst) ok([bob_account.trust checkForRings:&error], "Alice_account is good"); CFReleaseNull(error); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 4, "updates"); - + int passes = ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL); + ok(passes < 6, "updates"); // this was varying between 4 and 5 on different BATS runs - we just don't want it going crazy ok([alice_account.trust checkForRings:&error], "Alice_account is good"); CFReleaseNull(error); @@ -362,7 +362,7 @@ static void tests(bool recKeyFirst) } int secd_66_account_recovery(int argc, char *const *argv) { - plan_tests(278); + plan_tests(281); secd_test_setup_temp_keychain(__FUNCTION__, NULL); diff --git a/keychain/securityd/SOSCloudCircleServer.h b/keychain/securityd/SOSCloudCircleServer.h index 6c363684..3adf34eb 100644 --- a/keychain/securityd/SOSCloudCircleServer.h +++ b/keychain/securityd/SOSCloudCircleServer.h @@ -125,9 +125,11 @@ CF_RETURNS_RETAINED CFArrayRef SOSCCHandleUpdateMessage(CFDictionaryRef updates) void SOSCCRequestSyncWithPeer(CFStringRef peerID); void SOSCCRequestSyncWithPeers(CFSetRef /*SOSPeerInfoRef/CFStringRef*/ peerIDs); void SOSCCRequestSyncWithPeersList(CFArrayRef /*CFStringRef*/ peerIDs); -void SOSCCRequestSyncWithBackupPeer(CFStringRef backupPeerId); +void SOSCCRequestSyncWithBackupPeerList(CFArrayRef /* CFStringRef */ backupPeerIDs); bool SOSCCIsSyncPendingFor(CFStringRef peerID, CFErrorRef *error); +void SOSCCAccountTriggerSyncWithBackupPeer_server(CFStringRef peer); + void SOSCCEnsurePeerRegistration(void); typedef void (^SOSAccountSyncablePeersBlock)(CFArrayRef trustedPeers, CFArrayRef addedPeers, CFArrayRef removedPeers); diff --git a/keychain/securityd/SOSCloudCircleServer.m b/keychain/securityd/SOSCloudCircleServer.m index ef07ff98..51bccb51 100644 --- a/keychain/securityd/SOSCloudCircleServer.m +++ b/keychain/securityd/SOSCloudCircleServer.m @@ -53,6 +53,7 @@ #import "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h" #import "keychain/SecureObjectSync/SOSAuthKitHelpers.h" #import "keychain/ot/OTManager.h" +#import "keychain/SigninMetrics/OctagonSignPosts.h" #import "NSError+UsefulConstructors.h" #include @@ -257,6 +258,8 @@ static SOSAccount* SOSKeychainAccountCreateSharedAccount(CFDictionaryRef our_ges secerror("Got NULL creating account"); } + [account startStateMachine]; + done: CFReleaseNull(savedAccount); return account; @@ -818,11 +821,13 @@ SOSViewResultCode SOSCCView_Server(CFStringRef viewname, SOSViewActionCode actio bool SOSCCViewSetWithAnalytics_Server(CFSetRef enabledViews, CFSetRef disabledViews, CFDataRef parentEvent) { __block bool status = false; + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCViewSet); do_with_account_if_after_first_unlock(NULL, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { status = [txn.account.trust updateViewSetsWithAnalytics:txn.account enabled:enabledViews disabled:disabledViews parentEvent:(__bridge NSData*)parentEvent]; return true; }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCViewSet, OctagonSignpostNumber1(SOSSignpostNameSOSCCViewSet), (int)status); return status; } @@ -833,7 +838,9 @@ bool SOSCCViewSet_Server(CFSetRef enabledViews, CFSetRef disabledViews) { void sync_the_last_data_to_kvs(CFTypeRef account, bool waitForeverForSynchronization){ - + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSyncTheLastDataToKVS); + __block CFErrorRef localError = NULL; + dispatch_semaphore_t wait_for = dispatch_semaphore_create(0); secnoticeq("force-push", "calling SOSCloudKeychainSynchronizeAndWait"); @@ -841,6 +848,7 @@ void sync_the_last_data_to_kvs(CFTypeRef account, bool waitForeverForSynchroniza SOSCloudKeychainSynchronizeAndWait(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) { if (sync_error) { secerrorq("SOSCloudKeychainSynchronizeAndWait: %@", sync_error); + localError = sync_error; } else { secnoticeq("force-push", "returned from call; in callback to SOSCloudKeychainSynchronizeAndWait: results: %@", returnedValues); } @@ -854,11 +862,15 @@ void sync_the_last_data_to_kvs(CFTypeRef account, bool waitForeverForSynchroniza dispatch_semaphore_wait(wait_for, dispatch_time(DISPATCH_TIME_NOW, 60ull * NSEC_PER_SEC)); wait_for = nil; + bool subTaskSuccess = (localError == NULL) ? true : false; + OctagonSignpostEnd(signPost, SOSSignpostNameSyncTheLastDataToKVS, OctagonSignpostNumber1(SOSSignpostNameSyncTheLastDataToKVS), (int)subTaskSuccess); } #define kWAIT2MINID "EFRESH" static bool SyncKVSAndWait(CFErrorRef *error) { + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSyncKVSAndWait); + dispatch_semaphore_t wait_for = dispatch_semaphore_create(0); __block bool success = false; @@ -881,12 +893,14 @@ static bool SyncKVSAndWait(CFErrorRef *error) { dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER); secnotice("fresh", "EFP complete: %s %@", success ? "success" : "failure", error ? *error : NULL); }); + OctagonSignpostEnd(signPost, SOSSignpostNameSyncKVSAndWait, OctagonSignpostNumber1(SOSSignpostNameSyncKVSAndWait), (int)success); return success; } static bool Flush(CFErrorRef *error) { __block bool success = false; + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameFlush); dispatch_semaphore_t wait_for = dispatch_semaphore_create(0); secnotice("flush", "Starting"); @@ -904,11 +918,14 @@ static bool Flush(CFErrorRef *error) { secnotice("flush", "Returned %s", success? "Success": "Failure"); + OctagonSignpostEnd(signPost, SOSSignpostNameFlush, OctagonSignpostNumber1(SOSSignpostNameFlush), (int)success); + return success; } bool SOSCCTryUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error) { secnotice("updates", "Trying credentials and dsid (%@) for %@", dsid, user_label); + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCTryUserCredentials); bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { if (dsid != NULL && CFStringCompare(dsid, CFSTR(""), 0) != 0) { @@ -930,12 +947,16 @@ bool SOSCCTryUserCredentials_Server(CFStringRef user_label, CFDataRef user_passw require_quiet(Flush(error), done); done: + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCTryUserCredentials, OctagonSignpostNumber1(SOSSignpostNameSOSCCTryUserCredentials), (int)result); + return result; } static bool SOSCCAssertUserCredentialsAndOptionalDSID(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error) { secnotice("updates", "Setting credentials and dsid (%@) for %@", dsid, user_label); + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameAssertUserCredentialsAndOptionalDSID); + bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { if (dsid != NULL && CFStringCompare(dsid, CFSTR(""), 0) != 0) { SOSAccountAssertDSID(txn.account, dsid); @@ -962,11 +983,13 @@ static bool SOSCCAssertUserCredentialsAndOptionalDSID(CFStringRef user_label, CF secnotice("updates", "Complete credentials and dsid (%@) for %@: %d %@", dsid, user_label, result, error ? *error : NULL); done: + OctagonSignpostEnd(signPost, SOSSignpostNameAssertUserCredentialsAndOptionalDSID, OctagonSignpostNumber1(SOSSignpostNameAssertUserCredentialsAndOptionalDSID), (int)result); return result; } static bool SOSCCAssertUserCredentialsAndOptionalDSIDWithAnalytics(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, NSData* parentEvent, CFErrorRef *error) { secnotice("updates", "Setting credentials and dsid (%@) for %@", dsid, user_label); + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameAssertUserCredentialsAndOptionalDSID); NSError* localError = nil; SFSignInAnalytics* parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:parentEvent error:&localError]; @@ -1024,6 +1047,8 @@ done: secnotice("updates", "Complete credentials and dsid (%@) for %@: %d %@", dsid, user_label, result, error ? *error : NULL); + OctagonSignpostEnd(signPost, SOSSignpostNameAssertUserCredentialsAndOptionalDSID, OctagonSignpostNumber1(SOSSignpostNameAssertUserCredentialsAndOptionalDSID), (int)result); + return result; } @@ -1044,6 +1069,8 @@ bool SOSCCSetUserCredentials_Server(CFStringRef user_label, CFDataRef user_passw bool SOSCCCanAuthenticate_Server(CFErrorRef *error) { + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCanAuthenticate); + bool result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { // If we reply that yes we can authenticate, then let's make sure we can authenticate for a while yet. // @@ -1058,6 +1085,8 @@ bool SOSCCCanAuthenticate_Server(CFErrorRef *error) } } + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCanAuthenticate, OctagonSignpostNumber1(SOSSignpostNameSOSCCCanAuthenticate), (int)result); + return result; } @@ -1083,21 +1112,28 @@ SOSCCStatus SOSCCThisDeviceIsInCircle_Server(CFErrorRef *error) bool SOSCCRequestToJoinCircle_Server(CFErrorRef* error) { __block bool result = true; + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRequestToJoinCircle); - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + bool joined = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { result = SOSAccountJoinCircles(txn, block_error); return result; }); + + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRequestToJoinCircle, OctagonSignpostNumber1(SOSSignpostNameSOSCCRequestToJoinCircle), (int)joined); + return joined; } bool SOSCCRequestToJoinCircleWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error) { __block bool result = true; + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRequestToJoinCircle); - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + bool requested = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { result = SOSAccountJoinCirclesWithAnalytics(txn, (__bridge NSData*)parentEvent, block_error); return result; }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRequestToJoinCircle, OctagonSignpostNumber1(SOSSignpostNameSOSCCRequestToJoinCircle), (int)requested); + return requested; } bool SOSCCAccountHasPublicKey_Server(CFErrorRef *error) @@ -1135,11 +1171,13 @@ bool SOSCCRequestToJoinCircleAfterRestore_Server(CFErrorRef* error) { __block bool result = true; bool returned = false; + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore); returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { SOSAccountEnsurePeerRegistration(txn.account, block_error); result = SOSAccountJoinCirclesAfterRestore(txn, block_error); return result; }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore, OctagonSignpostNumber1(SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore), (int)result); return returned; } @@ -1148,6 +1186,7 @@ bool SOSCCRequestToJoinCircleAfterRestoreWithAnalytics_Server(CFDataRef parentEv { __block bool result = true; bool returned = false; + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore); returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { NSError* localError = nil; SFSignInAnalytics* parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:(__bridge NSData*)parentEvent error:&localError]; @@ -1165,6 +1204,7 @@ bool SOSCCRequestToJoinCircleAfterRestoreWithAnalytics_Server(CFDataRef parentEv result = SOSAccountJoinCirclesAfterRestoreWithAnalytics(txn, (__bridge NSData*)parentEvent, block_error); return result; }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore, OctagonSignpostNumber1(SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore), (int)result); return returned; } @@ -1272,68 +1312,113 @@ bool SOSCCAccountSetToNew_Server(CFErrorRef *error) bool SOSCCResetToOffering_Server(CFErrorRef* error) { - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCResetToOffering); + + bool resetResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + bool result = false; + SecKeyRef user_key = SOSAccountGetPrivateCredential(txn.account, error); - if (!user_key) - return false; - return [txn.account.trust resetToOffering:txn key:user_key err:block_error]; + if (!user_key) { + return result; + } + result = [txn.account.trust resetToOffering:txn key:user_key err:block_error]; + return result; }); - + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCResetToOffering, OctagonSignpostNumber1(SOSSignpostNameSOSCCResetToOffering), (int)resetResult); + return resetResult; } bool SOSCCResetToEmpty_Server(CFErrorRef* error) { - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - if (!SOSAccountHasPublicKey(txn.account, error)) - return false; - return [txn.account.trust resetAccountToEmpty:txn.account transport:txn.account.circle_transport err:block_error]; - }); + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCResetToEmpty); + + bool resetResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + bool result = false; + if (!SOSAccountHasPublicKey(txn.account, error)) { + return result; + } + result = [txn.account.trust resetAccountToEmpty:txn.account transport:txn.account.circle_transport err:block_error]; + return result; + }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCResetToEmpty, OctagonSignpostNumber1(SOSSignpostNameSOSCCResetToEmpty), (int)resetResult); + return resetResult; } bool SOSCCResetToEmptyWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error) { - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - if (!SOSAccountHasPublicKey(txn.account, error)) - return false; - return [txn.account.trust resetAccountToEmptyWithAnalytics:txn.account transport:txn.account.circle_transport parentEvent:(__bridge NSData*)parentEvent err:block_error]; - }); + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCResetToEmpty); + + bool resetResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + bool result = false; + if (!SOSAccountHasPublicKey(txn.account, error)) { + return result; + } + result = [txn.account.trust resetAccountToEmptyWithAnalytics:txn.account transport:txn.account.circle_transport parentEvent:(__bridge NSData*)parentEvent err:block_error]; + return result; + }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCResetToEmpty, OctagonSignpostNumber1(SOSSignpostNameSOSCCResetToEmpty), (int)resetResult); + return resetResult; } bool SOSCCRemoveThisDeviceFromCircleWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error) { - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - return [txn.account.trust leaveCircleWithAccount:txn.account withAnalytics:(__bridge NSData*)parentEvent err:error]; + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRemoveThisDeviceFromCircle); + + bool removeResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + bool result = [txn.account.trust leaveCircleWithAccount:txn.account withAnalytics:(__bridge NSData*)parentEvent err:error]; + return result; }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRemoveThisDeviceFromCircle, OctagonSignpostNumber1(SOSSignpostNameSOSCCRemoveThisDeviceFromCircle), (int)removeResult); + + return removeResult; } bool SOSCCRemoveThisDeviceFromCircle_Server(CFErrorRef* error) { - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - return [txn.account.trust leaveCircle:txn.account err:block_error]; + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRemoveThisDeviceFromCircle); + + bool removeResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + bool result = [txn.account.trust leaveCircle:txn.account err:block_error]; + return result; }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRemoveThisDeviceFromCircle, OctagonSignpostNumber1(SOSSignpostNameSOSCCRemoveThisDeviceFromCircle), (int)removeResult); + return removeResult; } bool SOSCCRemovePeersFromCircle_Server(CFArrayRef peers, CFErrorRef* error) { - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - return SOSAccountRemovePeersFromCircle(txn.account, peers, block_error); + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRemovePeersFromCircle); + + bool removeResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + bool result = SOSAccountRemovePeersFromCircle(txn.account, peers, block_error); + return result; }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRemovePeersFromCircle, OctagonSignpostNumber1(SOSSignpostNameSOSCCRemovePeersFromCircle), (int)removeResult); + return removeResult; } bool SOSCCRemovePeersFromCircleWithAnalytics_Server(CFArrayRef peers, CFDataRef parentEvent, CFErrorRef* error) { - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - return SOSAccountRemovePeersFromCircleWithAnalytics(txn.account, peers, (__bridge NSData*)parentEvent, block_error); + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRemovePeersFromCircle); + + bool removeResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + bool result = SOSAccountRemovePeersFromCircleWithAnalytics(txn.account, peers, (__bridge NSData*)parentEvent, block_error); + return result; }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRemovePeersFromCircle, OctagonSignpostNumber1(SOSSignpostNameSOSCCRemovePeersFromCircle), (int)removeResult); + return removeResult; } bool SOSCCLoggedOutOfAccount_Server(CFErrorRef *error) { - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCLoggedOutOfAccount); + + bool loggedOutResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { secnotice("circleOps", "Signed out of account!"); - + + bool waitForeverForSynchronization = true; bool result = [txn.account.trust leaveCircle:txn.account err:block_error]; @@ -1344,8 +1429,11 @@ bool SOSCCLoggedOutOfAccount_Server(CFErrorRef *error) SOSAccountSetToNew(txn.account); + return result; }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCLoggedOutOfAccount, OctagonSignpostNumber1(SOSSignpostNameSOSCCLoggedOutOfAccount), (int)loggedOutResult); + return loggedOutResult; } bool SOSCCBailFromCircle_Server(uint64_t limit_in_seconds, CFErrorRef* error) @@ -1368,11 +1456,15 @@ CFArrayRef SOSCCCopyApplicantPeerInfo_Server(CFErrorRef* error) { __block CFArrayRef result = NULL; + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyApplicantPeerInfo); + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { result = SOSAccountCopyApplicants(txn.account, block_error); return result != NULL; }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyApplicantPeerInfo, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyApplicantPeerInfo), (int)(result != NULL)); + return result; } @@ -1391,6 +1483,7 @@ CFArrayRef SOSCCCopyGenerationPeerInfo_Server(CFErrorRef* error) CFArrayRef SOSCCCopyValidPeerPeerInfo_Server(CFErrorRef* error) { __block CFArrayRef result = NULL; + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyValidPeerPeerInfo); @autoreleasepool { @@ -1401,6 +1494,7 @@ CFArrayRef SOSCCCopyValidPeerPeerInfo_Server(CFErrorRef* error) return result != NULL; }); } + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyValidPeerPeerInfo, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyValidPeerPeerInfo), (int)(result != NULL)); return result; } @@ -1408,12 +1502,14 @@ CFArrayRef SOSCCCopyValidPeerPeerInfo_Server(CFErrorRef* error) bool SOSCCValidateUserPublic_Server(CFErrorRef* error) { __block bool result = NULL; - + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCValidateUserPublic); + (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { result = SOSValidateUserPublic(txn.account, block_error); return result; }); - + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCValidateUserPublic, OctagonSignpostNumber1(SOSSignpostNameSOSCCValidateUserPublic), (int)result); + return result; } @@ -1444,11 +1540,13 @@ CFArrayRef SOSCCCopyRetirementPeerInfo_Server(CFErrorRef* error) CFArrayRef SOSCCCopyViewUnawarePeerInfo_Server(CFErrorRef* error) { __block CFArrayRef result = NULL; + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyViewUnawarePeerInfo); (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { result = SOSAccountCopyViewUnaware(txn.account, block_error); return result != NULL; }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyViewUnawarePeerInfo, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyViewUnawarePeerInfo), (int)(result != NULL)); return result; } @@ -1502,6 +1600,7 @@ bool SOSCCWaitForInitialSyncWithAnalytics_Server(CFDataRef parentEvent, CFErrorR __block time_t start; __block CFBooleanRef shouldUseInitialSyncV0 = false; SFSignInAnalytics* syncingEvent = nil; + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCWaitForInitialSync); NSError* localError = nil; SFSignInAnalytics* parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:(__bridge NSData*)parentEvent error:&localError]; @@ -1580,6 +1679,8 @@ bool SOSCCWaitForInitialSyncWithAnalytics_Server(CFDataRef parentEvent, CFErrorR fail: CFReleaseNull(inSyncCallID); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCWaitForInitialSync, OctagonSignpostNumber1(SOSSignpostNameSOSCCWaitForInitialSync), (int)result); + return result; } @@ -1592,6 +1693,7 @@ bool SOSCCWaitForInitialSync_Server(CFErrorRef* error) { __block CFStringRef inSyncCallID = NULL; __block time_t start; __block CFBooleanRef shouldUseInitialSyncV0 = false; + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCWaitForInitialSync); secnotice("initial sync", "Wait for initial sync start!"); @@ -1657,6 +1759,8 @@ bool SOSCCWaitForInitialSync_Server(CFErrorRef* error) { fail: CFReleaseNull(inSyncCallID); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCWaitForInitialSync, OctagonSignpostNumber1(SOSSignpostNameSOSCCWaitForInitialSync), (int)result); + return result; } @@ -1876,17 +1980,26 @@ bool SOSCCSetEscrowRecord_Server(CFStringRef escrow_label, uint64_t tries, CFErr bool SOSCCAcceptApplicants_Server(CFArrayRef applicants, CFErrorRef* error) { - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - return SOSAccountAcceptApplicants(txn.account, applicants, block_error); - }); + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCAcceptApplicants); + bool acceptResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + bool result = SOSAccountAcceptApplicants(txn.account, applicants, block_error); + return result; + }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCAcceptApplicants, OctagonSignpostNumber1(SOSSignpostNameSOSCCAcceptApplicants), (int)acceptResult); + return acceptResult; } bool SOSCCRejectApplicants_Server(CFArrayRef applicants, CFErrorRef* error) { - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - return SOSAccountRejectApplicants(txn.account, applicants, block_error); + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCAcceptApplicants); + + bool rejectResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + bool result = SOSAccountRejectApplicants(txn.account, applicants, block_error); + return result; }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCAcceptApplicants, OctagonSignpostNumber1(SOSSignpostNameSOSCCAcceptApplicants), (int)rejectResult); + return rejectResult; } CFArrayRef SOSCCCopyPeerPeerInfo_Server(CFErrorRef* error) @@ -1904,11 +2017,13 @@ CFArrayRef SOSCCCopyPeerPeerInfo_Server(CFErrorRef* error) CFArrayRef SOSCCCopyConcurringPeerPeerInfo_Server(CFErrorRef* error) { __block CFArrayRef result = NULL; + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyConcurringPeerPeerInfo); (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { result = SOSAccountCopyConcurringPeers(txn.account, block_error); return result != NULL; }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyConcurringPeerPeerInfo, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyConcurringPeerPeerInfo), (int)(result != NULL)); return result; } @@ -1916,12 +2031,14 @@ CFArrayRef SOSCCCopyConcurringPeerPeerInfo_Server(CFErrorRef* error) SOSPeerInfoRef SOSCCCopyMyPeerInfo_Server(CFErrorRef* error) { __block SOSPeerInfoRef result = NULL; + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyMyPeerInfo); (void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { // Create a copy to be DERed/sent back to client result = SOSPeerInfoCreateCopy(kCFAllocatorDefault, txn.account.peerInfo, block_error); return result != NULL; }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyMyPeerInfo, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyMyPeerInfo), (int)(result != NULL)); return result; } @@ -1982,6 +2099,7 @@ bool SOSCCDeleteEngineState_Server(CFErrorRef* error) SOSPeerInfoRef SOSCCSetNewPublicBackupKey_Server(CFDataRef newPublicBackup, CFErrorRef *error){ __block SOSPeerInfoRef result = NULL; + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCSetNewPublicBackupKey); secnotice("devRecovery", "SOSCCSetNewPublicBackupKey_Server acquiring account lock"); (void) do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { @@ -2001,13 +2119,19 @@ SOSPeerInfoRef SOSCCSetNewPublicBackupKey_Server(CFDataRef newPublicBackup, CFEr return result != NULL; }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCSetNewPublicBackupKey, OctagonSignpostNumber1(SOSSignpostNameSOSCCSetNewPublicBackupKey), (int)(result != NULL)); return result; } bool SOSCCRegisterSingleRecoverySecret_Server(CFDataRef aks_bag, bool setupV0Only, CFErrorRef *error){ - return do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { - return SOSAccountSetBSKBagForAllSlices(txn.account, aks_bag, setupV0Only, error); + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRegisterSingleRecoverySecret); + + bool registerResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) { + bool result = SOSAccountSetBSKBagForAllSlices(txn.account, aks_bag, setupV0Only, error); + return result; }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRegisterSingleRecoverySecret, OctagonSignpostNumber1(SOSSignpostNameSOSCCRegisterSingleRecoverySecret), (int)registerResult); + return registerResult; } CFStringRef SOSCCCopyIncompatibilityInfo_Server(CFErrorRef* error) @@ -2051,13 +2175,20 @@ bool SOSCCSetLastDepartureReason_Server(enum DepartureReason reason, CFErrorRef bool SOSCCProcessEnsurePeerRegistration_Server(CFErrorRef* error) { secnotice("updates", "Request for registering peers"); - return do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { - return SOSAccountEnsurePeerRegistration(txn.account, error); + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCProcessEnsurePeerRegistration); + + bool processResult = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + bool result = SOSAccountEnsurePeerRegistration(txn.account, error); + return result; }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCProcessEnsurePeerRegistration, OctagonSignpostNumber1(SOSSignpostNameSOSCCProcessEnsurePeerRegistration), (int)processResult); + return processResult; } CF_RETURNS_RETAINED CFSetRef SOSCCProcessSyncWithPeers_Server(CFSetRef peers, CFSetRef backupPeers, CFErrorRef *error) { __block CFSetRef result = NULL; + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCProcessSyncWithPeers); + if (!do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { result = SOSAccountProcessSyncWithPeers(txn, peers, backupPeers, error); return result != NULL; @@ -2065,6 +2196,7 @@ CF_RETURNS_RETAINED CFSetRef SOSCCProcessSyncWithPeers_Server(CFSetRef peers, CF // Be sure we don't return a result if we got an error CFReleaseNull(result); } + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCProcessSyncWithPeers, OctagonSignpostNumber1(SOSSignpostNameSOSCCProcessSyncWithPeers), (int)(result != NULL)); return result; } @@ -2076,6 +2208,7 @@ SyncWithAllPeersReason SOSCCProcessSyncWithAllPeers_Server(CFErrorRef* error) #define kIOReturnLockedWrite iokit_common_err(0x2c4) // device write locked */ __block SyncWithAllPeersReason result = kSyncWithAllPeersSuccess; + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCProcessSyncWithAllPeers); CFErrorRef action_error = NULL; @@ -2095,6 +2228,8 @@ SyncWithAllPeersReason SOSCCProcessSyncWithAllPeers_Server(CFErrorRef* error) SecErrorPropagate(action_error, error); } + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCProcessSyncWithAllPeers, OctagonSignpostNumber1(SOSSignpostNameSOSCCProcessSyncWithAllPeers), (int)result); + return result; } @@ -2131,6 +2266,8 @@ void SOSCCRequestSyncWithPeers(CFSetRef /*SOSPeerInfoRef/CFStringRef*/ peerIDs) void SOSCCRequestSyncWithPeersList(CFArrayRef /*CFStringRef*/ peerIDs) { os_activity_initiate("CloudCircle RequestSyncWithPeersList", OS_ACTIVITY_FLAG_DEFAULT, ^(void) { + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRequestSyncWithPeersList); + CFArrayRef empty = CFArrayCreateForCFTypes(kCFAllocatorDefault, NULL); CFStringArrayPerformWithDescription(peerIDs, ^(CFStringRef description) { @@ -2140,23 +2277,26 @@ void SOSCCRequestSyncWithPeersList(CFArrayRef /*CFStringRef*/ peerIDs) { SOSCloudKeychainRequestSyncWithPeers(peerIDs, empty, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL); CFReleaseNull(empty); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRequestSyncWithPeersList, OctagonSignpostNumber1(SOSSignpostNameSOSCCRequestSyncWithPeersList), (int)true); }); } -void SOSCCRequestSyncWithBackupPeer(CFStringRef backupPeerId) { - os_activity_initiate("CloudCircle SOSCCRequestSyncWithBackupPeer", OS_ACTIVITY_FLAG_DEFAULT, ^(void) { +void SOSCCRequestSyncWithBackupPeerList(CFArrayRef /* CFStringRef */ backupPeerIDs) { + os_activity_initiate("CloudCircle SOSCCRequestSyncWithBackupPeerList", OS_ACTIVITY_FLAG_DEFAULT, ^(void) { + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRequestSyncWithBackupPeerList); + CFArrayRef empty = CFArrayCreateForCFTypes(kCFAllocatorDefault, NULL); - CFArrayRef backupPeerList = CFArrayCreateForCFTypes(kCFAllocatorDefault, backupPeerId, NULL); - CFStringArrayPerformWithDescription(backupPeerList, ^(CFStringRef description) { + CFStringArrayPerformWithDescription(backupPeerIDs, ^(CFStringRef description) { secnotice("syncwith", "Request backup sync With: %@", description); }); - SOSCloudKeychainRequestSyncWithPeers(empty, backupPeerList, + SOSCloudKeychainRequestSyncWithPeers(empty, backupPeerIDs, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL); CFReleaseNull(empty); - CFReleaseNull(backupPeerList); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRequestSyncWithBackupPeerList, OctagonSignpostNumber1(SOSSignpostNameSOSCCRequestSyncWithBackupPeerList), (int)true); + }); } @@ -2167,27 +2307,37 @@ bool SOSCCIsSyncPendingFor(CFStringRef peerID, CFErrorRef *error) { void SOSCCEnsurePeerRegistration(void) { os_activity_initiate("CloudCircle EnsurePeerRegistration", OS_ACTIVITY_FLAG_DEFAULT, ^(void) { - + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCEnsurePeerRegistration); SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCEnsurePeerRegistration, OctagonSignpostNumber1(SOSSignpostNameSOSCCEnsurePeerRegistration), (int)true); }); } CF_RETURNS_RETAINED CFArrayRef SOSCCHandleUpdateMessage(CFDictionaryRef updates) { + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCHandleUpdateMessage); + CFArrayRef result = NULL; SOSAccount* account = (__bridge SOSAccount *)(SOSKeychainAccountGetSharedAccount()); //HACK to make sure itemsChangedBlock is set - (account) ? (result = SOSCloudKeychainHandleUpdateMessage(updates)) : (result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault)); + result = account ? SOSCloudKeychainHandleUpdateMessage(updates) : CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCHandleUpdateMessage, OctagonSignpostNumber1(SOSSignpostNameSOSCCHandleUpdateMessage), (int)(result != NULL)); + return result; } SOSPeerInfoRef SOSCCCopyApplication_Server(CFErrorRef *error) { __block SOSPeerInfoRef application = NULL; + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyApplication); + do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { application = SOSAccountCopyApplication(txn.account, error); return application != NULL; }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyApplication, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyApplication), (int)(application != NULL)); + return application; } @@ -2211,33 +2361,48 @@ bool SOSCCTestPopulateKVSWithBadKeys_Server(CFErrorRef *error) } CFDataRef SOSCCCopyCircleJoiningBlob_Server(SOSPeerInfoRef applicant, CFErrorRef *error) { __block CFDataRef pbblob = NULL; + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyCircleJoiningBlob); + do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { pbblob = SOSAccountCopyCircleJoiningBlob(txn.account, applicant, error); return pbblob != NULL; }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyCircleJoiningBlob, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyCircleJoiningBlob), (int)(pbblob != NULL)); + return pbblob; } CFDataRef SOSCCCopyInitialSyncData_Server(SOSInitialSyncFlags flags, CFErrorRef *error) { __block CFDataRef pbblob = NULL; + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyInitialSyncData); + do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { pbblob = SOSAccountCopyInitialSyncData(txn.account, flags, error); return pbblob != NULL; }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyInitialSyncData, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyInitialSyncData), (int)(pbblob != NULL)); + return pbblob; } bool SOSCCJoinWithCircleJoiningBlob_Server(CFDataRef joiningBlob, PiggyBackProtocolVersion version, CFErrorRef *error) { - return do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { - return SOSAccountJoinWithCircleJoiningBlob(txn.account, joiningBlob, version, error); + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCJoinWithCircleJoiningBlob); + + bool joinResult = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + bool result = SOSAccountJoinWithCircleJoiningBlob(txn.account, joiningBlob, version, error); + return result; }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCJoinWithCircleJoiningBlob, OctagonSignpostNumber1(SOSSignpostNameSOSCCJoinWithCircleJoiningBlob), (int)joinResult); + return joinResult; } CFBooleanRef SOSCCPeersHaveViewsEnabled_Server(CFArrayRef viewNames, CFErrorRef *error) { __block CFBooleanRef result = NULL; do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCPeersHaveViewsEnabled); result = SOSAccountPeersHaveViewsEnabled(txn.account, viewNames, error); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCPeersHaveViewsEnabled, OctagonSignpostNumber1(SOSSignpostNameSOSCCPeersHaveViewsEnabled), (int)(result != NULL)); return result != NULL; }); @@ -2245,35 +2410,54 @@ CFBooleanRef SOSCCPeersHaveViewsEnabled_Server(CFArrayRef viewNames, CFErrorRef } bool SOSCCRegisterRecoveryPublicKey_Server(CFDataRef recovery_key, CFErrorRef *error){ - return do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { - if(recovery_key != NULL && CFDataGetLength(recovery_key) != 0) - return SOSAccountRegisterRecoveryPublicKey(txn, recovery_key, error); - else - return SOSAccountClearRecoveryPublicKey(txn, recovery_key, error); + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRegisterRecoveryPublicKey); + + bool registerResult = do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + bool result = false; + if(recovery_key != NULL && CFDataGetLength(recovery_key) != 0) { + result = SOSAccountRegisterRecoveryPublicKey(txn, recovery_key, error); + } + else { + result = SOSAccountClearRecoveryPublicKey(txn, recovery_key, error); + } + return result; }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRegisterRecoveryPublicKey, OctagonSignpostNumber1(SOSSignpostNameSOSCCRegisterRecoveryPublicKey), (int)registerResult); + return registerResult; } CFDataRef SOSCCCopyRecoveryPublicKey_Server(CFErrorRef *error){ __block CFDataRef result = NULL; + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCCopyRecoveryPublicKey); do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { result = SOSAccountCopyRecoveryPublicKey(txn, error); return result != NULL; }); - + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCCopyRecoveryPublicKey, OctagonSignpostNumber1(SOSSignpostNameSOSCCCopyRecoveryPublicKey), (int)(result != NULL)); return result; } bool SOSCCMessageFromPeerIsPending_Server(SOSPeerInfoRef peer, CFErrorRef *error) { - return do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { - return SOSAccountMessageFromPeerIsPending(txn, peer, error); + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCMessageFromPeerIsPending); + + bool pendingResult = do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + bool result = SOSAccountMessageFromPeerIsPending(txn, peer, error); + return result; }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCMessageFromPeerIsPending, OctagonSignpostNumber1(SOSSignpostNameSOSCCMessageFromPeerIsPending), (int)pendingResult); + return pendingResult; } bool SOSCCSendToPeerIsPending_Server(SOSPeerInfoRef peer, CFErrorRef *error) { - return do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { - return SOSAccountSendToPeerIsPending(txn, peer, error); + OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCSendToPeerIsPending); + + bool sendResult = do_with_account_if_after_first_unlock(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { + bool result = SOSAccountSendToPeerIsPending(txn, peer, error); + return result; }); + OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCSendToPeerIsPending, OctagonSignpostNumber1(SOSSignpostNameSOSCCSendToPeerIsPending), (int)sendResult); + return sendResult; } void SOSCCResetOTRNegotiation_Server(CFStringRef peerid) @@ -2569,3 +2753,17 @@ void SOSCCPerformWithPeerID(void (^action)(CFStringRef peerID, CFErrorRef error) }); CFReleaseNull(cfAccountError); } + +void +SOSCCAccountTriggerSyncWithBackupPeer_server(CFStringRef peer) +{ +#if OCTAGON + secnotice("syncwith", "SOSCCAccountTriggerSyncWithBackupPeer_server: %@", peer); + if (peer == NULL) { + return; + } + SOSAccount* account = (__bridge SOSAccount*)GetSharedAccountRef(); + [account triggerBackupForPeers:@[(__bridge NSString *)peer]]; +#endif +} + diff --git a/keychain/securityd/SecDbKeychainItemV7.m b/keychain/securityd/SecDbKeychainItemV7.m index 1fd3957d..90ccbe00 100644 --- a/keychain/securityd/SecDbKeychainItemV7.m +++ b/keychain/securityd/SecDbKeychainItemV7.m @@ -355,7 +355,7 @@ typedef NS_ENUM(uint32_t, SecDbKeychainAKSWrappedKeyType) { } if (!self && error) { - *error = [NSError errorWithDomain:(id)kCFErrorDomainOSStatus code:errSecItemNotFound userInfo:@{NSLocalizedDescriptionKey : @"failed to deserialize keychain item blob"}]; + *error = [NSError errorWithDomain:(id)kCFErrorDomainOSStatus code:errSecDecode userInfo:@{NSLocalizedDescriptionKey : @"failed to deserialize keychain item blob"}]; } return self; diff --git a/keychain/securityd/SecDbKeychainMetadataKeyStore.m b/keychain/securityd/SecDbKeychainMetadataKeyStore.m index 9a366661..860529cf 100644 --- a/keychain/securityd/SecDbKeychainMetadataKeyStore.m +++ b/keychain/securityd/SecDbKeychainMetadataKeyStore.m @@ -38,10 +38,13 @@ static void initializeSharedMetadataStoreQueue(void) { }); } -@implementation SecDbKeychainMetadataKeyStore { - NSMutableDictionary* _keysDict; - dispatch_queue_t _queue; -} +@interface SecDbKeychainMetadataKeyStore () +@property dispatch_queue_t queue; +@property NSMutableDictionary* keysDict; +@property int keybagNotificationToken; +@end + +@implementation SecDbKeychainMetadataKeyStore + (void)resetSharedStore { @@ -81,9 +84,10 @@ static void initializeSharedMetadataStoreQueue(void) { if (self = [super init]) { _keysDict = [[NSMutableDictionary alloc] init]; _queue = dispatch_queue_create("SecDbKeychainMetadataKeyStore", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL); - int token = 0; + _keybagNotificationToken = NOTIFY_TOKEN_INVALID; + __weak __typeof(self) weakSelf = self; - notify_register_dispatch(kUserKeybagStateChangeNotification, &token, _queue, ^(int inToken) { + notify_register_dispatch(kUserKeybagStateChangeNotification, &_keybagNotificationToken, _queue, ^(int inToken) { bool locked = true; CFErrorRef error = NULL; if (!SecAKSGetIsLocked(&locked, &error)) { @@ -100,6 +104,13 @@ static void initializeSharedMetadataStoreQueue(void) { return self; } +- (void)dealloc { + if (_keybagNotificationToken != NOTIFY_TOKEN_INVALID) { + notify_cancel(_keybagNotificationToken); + _keybagNotificationToken = NOTIFY_TOKEN_INVALID; + } +} + - (void)dropClassAKeys { dispatch_sync(_queue, ^{ diff --git a/keychain/tpctl/main.swift b/keychain/tpctl/main.swift index 4f20f4b7..fd98b353 100644 --- a/keychain/tpctl/main.swift +++ b/keychain/tpctl/main.swift @@ -43,6 +43,7 @@ enum Command { case vouch(String, Data, Data, Data, Data) case vouchWithBottle(String, Data, String) case allow(Set, Bool) + case supportApp } func printUsage() { @@ -61,6 +62,7 @@ func printUsage() { print(" local-reset Resets the local cuttlefish database, and ignores all previous information. Does not change anything off-device") print(" prepare [--modelid MODELID] [--machineid MACHINEID] [--epoch EPOCH] [--bottlesalt BOTTLESALT]") print(" Creates a new identity and returns its attributes. If not provided, modelid and machineid will be given some defaults (ignoring the local device)") + print(" supportApp Get SupportApp information from Cuttlefish") print(" update Fetch new information from Cuttlefish, and perform any actions this node deems necessary") print(" validate Vvalidate SOS and Octagon data structures from server side") print(" viable-bottles Show bottles in preference order of server") @@ -315,6 +317,9 @@ while let arg = argIterator.next() { case "update": commands.append(.update) + case "supportApp": + commands.append(.supportApp) + case "validate": commands.append(.validate) @@ -582,6 +587,27 @@ for command in commands { print("Local reset successful") } + case .supportApp: + os_log("supportApp (%@, %@)", log: tplogDebug, type: .default, container, context) + + tpHelper.getSupportAppInfo(withContainer: container, context: context) { data, error in + guard error == nil else { + print("Error getting supportApp:", error!) + return + } + + if let data = data { + do { + let string = try GetSupportAppInfoResponse(serializedData: data).jsonString() + print("\(string)") + } catch { + print("Error decoding protobuf: \(error)") + } + } else { + print("Error: no results, but no error either?") + } + } + case .prepare: os_log("preparing (%@, %@)", log: tplogDebug, type: .default, container, context) diff --git a/protocol/SecProtocol.c b/protocol/SecProtocol.c index 048db40f..ad12a40e 100644 --- a/protocol/SecProtocol.c +++ b/protocol/SecProtocol.c @@ -1200,6 +1200,41 @@ sec_protocol_options_set_tls_grease_enabled(sec_protocol_options_t options, bool }); } +void +sec_protocol_options_set_experiment_identifier(sec_protocol_options_t options, const char *experiment_identifier) +{ + SEC_PROTOCOL_OPTIONS_VALIDATE(options,); + SEC_PROTOCOL_OPTIONS_VALIDATE(experiment_identifier,); + + (void)sec_protocol_options_access_handle(options, ^bool(void *handle) { + sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle; + SEC_PROTOCOL_OPTIONS_VALIDATE(content, false); + + if (content->experiment_identifier != NULL) { + free(content->experiment_identifier); + } + if (experiment_identifier != NULL) { + content->experiment_identifier = strdup(experiment_identifier); + } + return true; + }); +} + +void +sec_protocol_options_set_connection_id(sec_protocol_options_t options, uuid_t _Nonnull connection_id) +{ + SEC_PROTOCOL_OPTIONS_VALIDATE(options,); + SEC_PROTOCOL_OPTIONS_VALIDATE(connection_id,); + + sec_protocol_options_access_handle(options, ^bool(void *handle) { + sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle; + SEC_PROTOCOL_OPTIONS_VALIDATE(content, false); + + memcpy(content->connection_id, connection_id, sizeof(content->connection_id)); + return true; + }); +} + void sec_protocol_options_set_tls_ticket_request_count(sec_protocol_options_t options, uint8_t tls_ticket_request_count) { @@ -2030,6 +2065,37 @@ sec_protocol_metadata_copy_serialized_session(sec_protocol_metadata_t metadata) return session; } +const char * __nullable +sec_protocol_metadata_get_experiment_identifier(sec_protocol_metadata_t metadata) +{ + SEC_PROTOCOL_METADATA_VALIDATE(metadata, NULL); + + __block const char *experiment_identifer = NULL; + sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) { + sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle; + SEC_PROTOCOL_METADATA_VALIDATE(content, false); + + experiment_identifer = content->experiment_identifier; + return true; + }); + return experiment_identifer; +} + +void +sec_protocol_metadata_copy_connection_id(sec_protocol_metadata_t metadata, uuid_t _Nonnull output_uuid) +{ + SEC_PROTOCOL_METADATA_VALIDATE(metadata,); + SEC_PROTOCOL_METADATA_VALIDATE(output_uuid,); + + (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) { + sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle; + SEC_PROTOCOL_METADATA_VALIDATE(content, false); + + memcpy(output_uuid, content->connection_id, sizeof(content->connection_id)); + return true; + }); +} + static const char *_options_uint64_keys[] = { SEC_PROTOCOL_OPTIONS_KEY_min_version, SEC_PROTOCOL_OPTIONS_KEY_max_version, @@ -2081,32 +2147,6 @@ _dictionary_has_key(xpc_object_t dict, const char *target_key) }); } -static bool -_arrays_uint64_contents_are_equal(xpc_object_t arrayA, xpc_object_t arrayB) -{ - if (xpc_array_get_count(arrayA) != xpc_array_get_count(arrayB)) { - return false; - } - - return xpc_array_apply(arrayA, ^bool(size_t indexA, xpc_object_t _Nonnull valueA) { - uint64_t raw_valueA = xpc_array_get_uint64(arrayA, indexA); - - bool contains_value = !xpc_array_apply(arrayB, ^bool(size_t indexB, xpc_object_t _Nonnull valueB) { - uint64_t raw_valueB = xpc_array_get_uint64(arrayB, indexB); - if (raw_valueA == raw_valueB) { - return false; - } - return true; - }); - - if (!contains_value) { - return false; - } - - return true; - }); -} - static bool _options_config_matches_partial_config(xpc_object_t full, xpc_object_t partial) { @@ -2142,24 +2182,6 @@ _options_config_matches_partial_config(xpc_object_t full, xpc_object_t partial) } } - // Now check for ciphersuite options, as these are not expressed via serialized configs - if (strncmp(entry_key, SEC_PROTOCOL_OPTIONS_KEY_ciphersuites, entry_key_len) == 0) { - if (xpc_get_type(value) == XPC_TYPE_ARRAY) { - bool matching = xpc_dictionary_apply(full, ^bool(const char * _Nonnull full_key, xpc_object_t _Nonnull full_value) { - if (strncmp(full_key, SEC_PROTOCOL_OPTIONS_KEY_ciphersuites, entry_key_len) == 0) { - if (xpc_get_type(full_value) == XPC_TYPE_ARRAY) { - return _arrays_uint64_contents_are_equal(value, full_value); - } - } - return true; - }); - - if (!matching) { - return false; - } - } - } - return true; }); } @@ -2167,15 +2189,6 @@ _options_config_matches_partial_config(xpc_object_t full, xpc_object_t partial) static bool _serialize_options(xpc_object_t dictionary, sec_protocol_options_content_t options_content) { -#define xpc_dictionary_set_string_default(d, key, value, default) \ - do { \ - if (value != NULL) { \ - xpc_dictionary_set_string(d, key, value); \ - } else { \ - xpc_dictionary_set_string(d, key, default); \ - } \ - } while (0); - #define EXPAND_PARAMETER(field) \ SEC_PROTOCOL_OPTIONS_KEY_##field , options_content->field @@ -2209,7 +2222,6 @@ _serialize_options(xpc_object_t dictionary, sec_protocol_options_content_t optio xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(tls_grease_enabled)); #undef EXPAND_PARAMETER -#undef xpc_dictionary_set_string_default return true; } @@ -2655,12 +2667,7 @@ sec_protocol_options_create_config(sec_protocol_options_t options) sec_protocol_options_content_t options_content = (sec_protocol_options_content_t)options_handle; SEC_PROTOCOL_METADATA_VALIDATE(options_content, false); - if (_serialize_options(dictionary, options_content)) { - xpc_dictionary_set_value(dictionary, SEC_PROTOCOL_OPTIONS_KEY_ciphersuites, options_content->ciphersuites); - return true; - } - - return false; + return _serialize_options(dictionary, options_content); }); if (serialized) { diff --git a/protocol/SecProtocolPriv.h b/protocol/SecProtocolPriv.h index 0101c43f..b209bc6f 100644 --- a/protocol/SecProtocolPriv.h +++ b/protocol/SecProtocolPriv.h @@ -581,6 +581,41 @@ API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)) void sec_protocol_options_set_tls_grease_enabled(sec_protocol_options_t options, bool tls_grease_enabled); +/*! + * @function sec_protocol_options_set_experiment_identifier + * + * @abstract + * Set the SecExperiment identifier for a given connection. + * + * Note: this SPI is meant to be called by libnetcore. It should not be called in any other circumstances. + * + * @param options + * A `sec_protocol_options_t` instance. + * + * @param experiment_identifier + * The identifier for a secure connection experiment. + */ +#define SEC_PROTOCOL_HAS_EXPERIMENT_IDENTIFIER 1 +API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)) +void +sec_protocol_options_set_experiment_identifier(sec_protocol_options_t options, const char *experiment_identifier); + +/*! + * @function sec_protocol_options_set_connection_id + * + * @abstract + * Set the explciit connection identifier. If not set, one will be populated internally. + * + * @param options + * A `sec_protocol_options_t` instance. + * + * @param connection_id + * The `uuid_t`` connection identifier. + */ +API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)) +void +sec_protocol_options_set_connection_id(sec_protocol_options_t options, uuid_t _Nonnull connection_id); + /*! * @function sec_protocol_options_create_config * @@ -647,6 +682,39 @@ API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)) const char * __nullable sec_protocol_metadata_get_tls_negotiated_group(sec_protocol_metadata_t metadata); +/*! + * @function sec_protocol_metadata_get_experiment_identifier + * + * @abstract + * Get the SecExperiment identifier for a given connection. + * + * Note: this SPI is meant to be called by libnetcore. It should not be called in any other circumstances. + * + * @param options + * A `sec_protocol_metadata_t` instance. + * + * @return The identifier for a secure connection experiment, or NULL if none was specified. + */ +API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)) +const char * __nullable +sec_protocol_metadata_get_experiment_identifier(sec_protocol_metadata_t metadata); + +/*! + * @function sec_protocol_metadata_copy_connection_id + * + * @abstract + * Copy the secure connection identifier. + * + * @param metadata + * A `sec_protocol_metadata_t` instance. + * + * @param output_uuid + * A `uuid_t` into which the connection identifier is written. + */ +API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)) +void +sec_protocol_metadata_copy_connection_id(sec_protocol_metadata_t metadata, uuid_t _Nonnull output_uuid); + /*! * @function sec_protocol_metadata_get_tls_false_start_used * @@ -1109,8 +1177,9 @@ struct sec_protocol_options_content { SSLProtocol min_version; SSLProtocol max_version; - // Reference-counted types char *server_name; + char *experiment_identifier; + uuid_t connection_id; __nullable xpc_object_t ciphersuites; xpc_object_t application_protocols; sec_identity_t identity; @@ -1196,6 +1265,8 @@ struct sec_protocol_metadata_content { SSLCipherSuite negotiated_ciphersuite; const char *negotiated_protocol; const char *server_name; + const char *experiment_identifier; + uuid_t connection_id; sec_array_t sent_certificate_chain; sec_array_t peer_certificate_chain; diff --git a/protocol/SecProtocolTest.m b/protocol/SecProtocolTest.m index e1b8cdb9..4ae69401 100644 --- a/protocol/SecProtocolTest.m +++ b/protocol/SecProtocolTest.m @@ -983,31 +983,6 @@ _sec_protocol_test_metadata_session_exporter(void *handle) } } -- (void)test_sec_protocol_options_matches_config_with_mismatch_ciphersuites { - sec_protocol_options_t options = [self create_sec_protocol_options]; - - sec_protocol_options_append_tls_ciphersuite(options, 1); - - xpc_object_t config = sec_protocol_options_create_config(options); - XCTAssertTrue(config != NULL); - if (config != NULL) { - // Flip a value in the config, and expect the match to fail - __block const char *ciphersuites_key = "ciphersuites"; - xpc_object_t mismatched_config = xpc_dictionary_create(NULL, NULL, 0); - xpc_dictionary_apply(config, ^bool(const char * _Nonnull key, xpc_object_t _Nonnull value) { - if (strncmp(key, ciphersuites_key, strlen(ciphersuites_key)) != 0) { - xpc_dictionary_set_value(mismatched_config, key, value); - } else { - xpc_object_t ciphersuites = xpc_array_create(NULL, 0); - xpc_array_set_uint64(ciphersuites, XPC_ARRAY_APPEND, 2); - xpc_dictionary_set_value(mismatched_config, key, ciphersuites); - } - return true; - }); - XCTAssertFalse(sec_protocol_options_matches_config(options, mismatched_config)); - } -} - - (void)test_protocol_version_map { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" @@ -1107,4 +1082,74 @@ _sec_protocol_test_metadata_session_exporter(void *handle) XCTAssertTrue(accessed, @"Expected sec_protocol_metadata_access_pre_shared_keys to traverse PSK list"); } +- (void)test_sec_protocol_experiment_identifier { + sec_protocol_options_t options = [self create_sec_protocol_options]; + + (void)sec_protocol_options_access_handle(options, ^bool(void *handle) { + sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle; + SEC_PROTOCOL_OPTIONS_VALIDATE(content, false); + XCTAssertTrue(content->experiment_identifier == NULL); + return true; + }); + + const char *identifier = "first_experiment"; + sec_protocol_options_set_experiment_identifier(options, identifier); + (void)sec_protocol_options_access_handle(options, ^bool(void *handle) { + sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle; + SEC_PROTOCOL_OPTIONS_VALIDATE(content, false); + XCTAssertTrue(content->experiment_identifier != NULL); + XCTAssertTrue(strncmp(identifier, content->experiment_identifier, strlen(identifier)) == 0); + return true; + }); + + sec_protocol_metadata_t metadata = [self create_sec_protocol_metadata]; + XCTAssertTrue(sec_protocol_metadata_get_experiment_identifier(metadata) == NULL); + + (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) { + sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle; + SEC_PROTOCOL_OPTIONS_VALIDATE(content, false); + content->experiment_identifier = strdup(identifier); + return true; + }); + + XCTAssertTrue(strncmp(identifier, sec_protocol_metadata_get_experiment_identifier(metadata), strlen(identifier)) == 0); +} + +- (void)test_sec_protocol_connection_id { + sec_protocol_options_t options = [self create_sec_protocol_options]; + + (void)sec_protocol_options_access_handle(options, ^bool(void *handle) { + sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle; + SEC_PROTOCOL_OPTIONS_VALIDATE(content, false); + uuid_t zeroes = {}; + XCTAssertTrue(memcmp(zeroes, content->connection_id, sizeof(zeroes)) == 0); + return true; + }); + + uuid_t uuid = {}; + __block uint8_t *uuid_ptr = uuid; + __block size_t uuid_len = sizeof(uuid); + (void)SecRandomCopyBytes(NULL, sizeof(uuid), uuid); + sec_protocol_options_set_connection_id(options, uuid); + (void)sec_protocol_options_access_handle(options, ^bool(void *handle) { + sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle; + SEC_PROTOCOL_OPTIONS_VALIDATE(content, false); + XCTAssertTrue(memcmp(content->connection_id, uuid_ptr, uuid_len) == 0); + return true; + }); + + sec_protocol_metadata_t metadata = [self create_sec_protocol_metadata]; + (void)sec_protocol_metadata_access_handle(metadata, ^bool(void *handle) { + sec_protocol_metadata_content_t content = (sec_protocol_metadata_content_t)handle; + SEC_PROTOCOL_OPTIONS_VALIDATE(content, false); + memcpy(content->connection_id, uuid_ptr, uuid_len); + return true; + }); + + uuid_t copied_metadata = {}; + sec_protocol_metadata_copy_connection_id(metadata, copied_metadata); + + XCTAssertTrue(memcmp(uuid, copied_metadata, sizeof(copied_metadata)) == 0); +} + @end diff --git a/secdxctests/KeychainAPITests.m b/secdxctests/KeychainAPITests.m index 5c54545b..a68d4f2d 100644 --- a/secdxctests/KeychainAPITests.m +++ b/secdxctests/KeychainAPITests.m @@ -134,6 +134,24 @@ void* testlist = NULL; #endif } +- (void)testBadTypeInParams +{ + NSMutableDictionary *attrs = @{ + (id)kSecClass: (id)kSecClassGenericPassword, + (id)kSecUseDataProtectionKeychain: @YES, + (id)kSecAttrLabel: @"testentry", + }.mutableCopy; + + SecItemDelete((CFDictionaryRef)attrs); + XCTAssertEqual(errSecSuccess, SecItemAdd((CFDictionaryRef)attrs, NULL)); + XCTAssertEqual(errSecSuccess, SecItemDelete((CFDictionaryRef)attrs)); + + // We try to fool SecItem API with unexpected type of kSecAttrAccessControl attribute in query and it should not crash. + attrs[(id)kSecAttrAccessControl] = @"string, no SecAccessControlRef!"; + XCTAssertEqual(errSecParam, SecItemAdd((CFDictionaryRef)attrs, NULL)); + XCTAssertEqual(errSecParam, SecItemDelete((CFDictionaryRef)attrs)); +} + #pragma mark - Corruption Tests const uint8_t keychain_data[] = { diff --git a/securityd/etc/com.apple.securityd.sb b/securityd/etc/com.apple.securityd.sb index c91b48fb..c59ca4d2 100644 --- a/securityd/etc/com.apple.securityd.sb +++ b/securityd/etc/com.apple.securityd.sb @@ -42,6 +42,7 @@ (allow system-audit) (allow mach-lookup + (global-name "com.apple.SecurityServer") (global-name "com.apple.CoreServices.coreservicesd") (global-name "com.apple.system.opendirectoryd.api") (global-name "com.apple.securitydservice") diff --git a/tests/TrustTests/TestData/TestCopyProperties_ios-data/TestCopyProperties_ios.plist b/tests/TrustTests/TestData/TestCopyProperties_ios-data/TestCopyProperties_ios.plist index cafcfaf1..7305d055 100644 --- a/tests/TrustTests/TestData/TestCopyProperties_ios-data/TestCopyProperties_ios.plist +++ b/tests/TrustTests/TestData/TestCopyProperties_ios-data/TestCopyProperties_ios.plist @@ -425,7 +425,7 @@ Policies PolicyIdentifier - 1.2.840.113635.100.1.24 + 1.2.840.113635.100.1.51 Leaf escrow_service_key_049F9D11 diff --git a/tests/secdmockaks/MockAKSOptionalParameters.proto b/tests/secdmockaks/MockAKSOptionalParameters.proto new file mode 100644 index 00000000..02a9d20e --- /dev/null +++ b/tests/secdmockaks/MockAKSOptionalParameters.proto @@ -0,0 +1,7 @@ +syntax = "proto2"; + +message MockAKSOptionalParameters { + optional bytes access_groups = 1; + optional bytes external_data = 2; + optional bytes acm_handle = 3; +} diff --git a/tests/secdmockaks/MockAKSRefKey.proto b/tests/secdmockaks/MockAKSRefKey.proto new file mode 100644 index 00000000..91620414 --- /dev/null +++ b/tests/secdmockaks/MockAKSRefKey.proto @@ -0,0 +1,6 @@ +syntax = "proto2"; + +message MockAKSRefKey { + optional bytes key = 1; + optional bytes optional_params = 2; +} diff --git a/tests/secdmockaks/generated_source/MockAKSOptionalParameters.h b/tests/secdmockaks/generated_source/MockAKSOptionalParameters.h new file mode 100644 index 00000000..eb39a40c --- /dev/null +++ b/tests/secdmockaks/generated_source/MockAKSOptionalParameters.h @@ -0,0 +1,43 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from MockAKSOptionalParameters.proto + +#import +#import + +#ifdef __cplusplus +#define MOCKAKSOPTIONALPARAMETERS_FUNCTION extern "C" +#else +#define MOCKAKSOPTIONALPARAMETERS_FUNCTION extern +#endif + +@interface MockAKSOptionalParameters : PBCodable +{ + NSData *_accessGroups; + NSData *_acmHandle; + NSData *_externalData; +} + + +@property (nonatomic, readonly) BOOL hasAccessGroups; +@property (nonatomic, retain) NSData *accessGroups; + +@property (nonatomic, readonly) BOOL hasExternalData; +@property (nonatomic, retain) NSData *externalData; + +@property (nonatomic, readonly) BOOL hasAcmHandle; +@property (nonatomic, retain) NSData *acmHandle; + +// Performs a shallow copy into other +- (void)copyTo:(MockAKSOptionalParameters *)other; + +// Performs a deep merge from other into self +// If set in other, singular values in self are replaced in self +// Singular composite values are recursively merged +// Repeated values from other are appended to repeated values in self +- (void)mergeFrom:(MockAKSOptionalParameters *)other; + +MOCKAKSOPTIONALPARAMETERS_FUNCTION BOOL MockAKSOptionalParametersReadFrom(__unsafe_unretained MockAKSOptionalParameters *self, __unsafe_unretained PBDataReader *reader); + +@end + diff --git a/tests/secdmockaks/generated_source/MockAKSOptionalParameters.m b/tests/secdmockaks/generated_source/MockAKSOptionalParameters.m new file mode 100644 index 00000000..2d4450a8 --- /dev/null +++ b/tests/secdmockaks/generated_source/MockAKSOptionalParameters.m @@ -0,0 +1,194 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from MockAKSOptionalParameters.proto + +#import "MockAKSOptionalParameters.h" +#import +#import +#import + +#if !__has_feature(objc_arc) +# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code. +#endif + +@implementation MockAKSOptionalParameters + +- (BOOL)hasAccessGroups +{ + return _accessGroups != nil; +} +@synthesize accessGroups = _accessGroups; +- (BOOL)hasExternalData +{ + return _externalData != nil; +} +@synthesize externalData = _externalData; +- (BOOL)hasAcmHandle +{ + return _acmHandle != nil; +} +@synthesize acmHandle = _acmHandle; + +- (NSString *)description +{ + return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]]; +} + +- (NSDictionary *)dictionaryRepresentation +{ + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + if (self->_accessGroups) + { + [dict setObject:self->_accessGroups forKey:@"access_groups"]; + } + if (self->_externalData) + { + [dict setObject:self->_externalData forKey:@"external_data"]; + } + if (self->_acmHandle) + { + [dict setObject:self->_acmHandle forKey:@"acm_handle"]; + } + return dict; +} + +BOOL MockAKSOptionalParametersReadFrom(__unsafe_unretained MockAKSOptionalParameters *self, __unsafe_unretained PBDataReader *reader) { + while (PBReaderHasMoreData(reader)) { + uint32_t tag = 0; + uint8_t aType = 0; + + PBReaderReadTag32AndType(reader, &tag, &aType); + + if (PBReaderHasError(reader)) + break; + + if (aType == TYPE_END_GROUP) { + break; + } + + switch (tag) { + + case 1 /* accessGroups */: + { + NSData *new_accessGroups = PBReaderReadData(reader); + self->_accessGroups = new_accessGroups; + } + break; + case 2 /* externalData */: + { + NSData *new_externalData = PBReaderReadData(reader); + self->_externalData = new_externalData; + } + break; + case 3 /* acmHandle */: + { + NSData *new_acmHandle = PBReaderReadData(reader); + self->_acmHandle = new_acmHandle; + } + break; + default: + if (!PBReaderSkipValueWithTag(reader, tag, aType)) + return NO; + break; + } + } + return !PBReaderHasError(reader); +} + +- (BOOL)readFrom:(PBDataReader *)reader +{ + return MockAKSOptionalParametersReadFrom(self, reader); +} +- (void)writeTo:(PBDataWriter *)writer +{ + /* accessGroups */ + { + if (self->_accessGroups) + { + PBDataWriterWriteDataField(writer, self->_accessGroups, 1); + } + } + /* externalData */ + { + if (self->_externalData) + { + PBDataWriterWriteDataField(writer, self->_externalData, 2); + } + } + /* acmHandle */ + { + if (self->_acmHandle) + { + PBDataWriterWriteDataField(writer, self->_acmHandle, 3); + } + } +} + +- (void)copyTo:(MockAKSOptionalParameters *)other +{ + if (_accessGroups) + { + other.accessGroups = _accessGroups; + } + if (_externalData) + { + other.externalData = _externalData; + } + if (_acmHandle) + { + other.acmHandle = _acmHandle; + } +} + +- (id)copyWithZone:(NSZone *)zone +{ + MockAKSOptionalParameters *copy = [[[self class] allocWithZone:zone] init]; + copy->_accessGroups = [_accessGroups copyWithZone:zone]; + copy->_externalData = [_externalData copyWithZone:zone]; + copy->_acmHandle = [_acmHandle copyWithZone:zone]; + return copy; +} + +- (BOOL)isEqual:(id)object +{ + MockAKSOptionalParameters *other = (MockAKSOptionalParameters *)object; + return [other isMemberOfClass:[self class]] + && + ((!self->_accessGroups && !other->_accessGroups) || [self->_accessGroups isEqual:other->_accessGroups]) + && + ((!self->_externalData && !other->_externalData) || [self->_externalData isEqual:other->_externalData]) + && + ((!self->_acmHandle && !other->_acmHandle) || [self->_acmHandle isEqual:other->_acmHandle]) + ; +} + +- (NSUInteger)hash +{ + return 0 + ^ + [self->_accessGroups hash] + ^ + [self->_externalData hash] + ^ + [self->_acmHandle hash] + ; +} + +- (void)mergeFrom:(MockAKSOptionalParameters *)other +{ + if (other->_accessGroups) + { + [self setAccessGroups:other->_accessGroups]; + } + if (other->_externalData) + { + [self setExternalData:other->_externalData]; + } + if (other->_acmHandle) + { + [self setAcmHandle:other->_acmHandle]; + } +} + +@end + diff --git a/tests/secdmockaks/generated_source/MockAKSRefKey.h b/tests/secdmockaks/generated_source/MockAKSRefKey.h new file mode 100644 index 00000000..84420ef5 --- /dev/null +++ b/tests/secdmockaks/generated_source/MockAKSRefKey.h @@ -0,0 +1,39 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from MockAKSRefKey.proto + +#import +#import + +#ifdef __cplusplus +#define MOCKAKSREFKEY_FUNCTION extern "C" +#else +#define MOCKAKSREFKEY_FUNCTION extern +#endif + +@interface MockAKSRefKey : PBCodable +{ + NSData *_key; + NSData *_optionalParams; +} + + +@property (nonatomic, readonly) BOOL hasKey; +@property (nonatomic, retain) NSData *key; + +@property (nonatomic, readonly) BOOL hasOptionalParams; +@property (nonatomic, retain) NSData *optionalParams; + +// Performs a shallow copy into other +- (void)copyTo:(MockAKSRefKey *)other; + +// Performs a deep merge from other into self +// If set in other, singular values in self are replaced in self +// Singular composite values are recursively merged +// Repeated values from other are appended to repeated values in self +- (void)mergeFrom:(MockAKSRefKey *)other; + +MOCKAKSREFKEY_FUNCTION BOOL MockAKSRefKeyReadFrom(__unsafe_unretained MockAKSRefKey *self, __unsafe_unretained PBDataReader *reader); + +@end + diff --git a/tests/secdmockaks/generated_source/MockAKSRefKey.m b/tests/secdmockaks/generated_source/MockAKSRefKey.m new file mode 100644 index 00000000..f0c8c7aa --- /dev/null +++ b/tests/secdmockaks/generated_source/MockAKSRefKey.m @@ -0,0 +1,159 @@ +// This file was automatically generated by protocompiler +// DO NOT EDIT! +// Compiled from MockAKSRefKey.proto + +#import "MockAKSRefKey.h" +#import +#import +#import + +#if !__has_feature(objc_arc) +# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code. +#endif + +@implementation MockAKSRefKey + +- (BOOL)hasKey +{ + return _key != nil; +} +@synthesize key = _key; +- (BOOL)hasOptionalParams +{ + return _optionalParams != nil; +} +@synthesize optionalParams = _optionalParams; + +- (NSString *)description +{ + return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]]; +} + +- (NSDictionary *)dictionaryRepresentation +{ + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + if (self->_key) + { + [dict setObject:self->_key forKey:@"key"]; + } + if (self->_optionalParams) + { + [dict setObject:self->_optionalParams forKey:@"optional_params"]; + } + return dict; +} + +BOOL MockAKSRefKeyReadFrom(__unsafe_unretained MockAKSRefKey *self, __unsafe_unretained PBDataReader *reader) { + while (PBReaderHasMoreData(reader)) { + uint32_t tag = 0; + uint8_t aType = 0; + + PBReaderReadTag32AndType(reader, &tag, &aType); + + if (PBReaderHasError(reader)) + break; + + if (aType == TYPE_END_GROUP) { + break; + } + + switch (tag) { + + case 1 /* key */: + { + NSData *new_key = PBReaderReadData(reader); + self->_key = new_key; + } + break; + case 2 /* optionalParams */: + { + NSData *new_optionalParams = PBReaderReadData(reader); + self->_optionalParams = new_optionalParams; + } + break; + default: + if (!PBReaderSkipValueWithTag(reader, tag, aType)) + return NO; + break; + } + } + return !PBReaderHasError(reader); +} + +- (BOOL)readFrom:(PBDataReader *)reader +{ + return MockAKSRefKeyReadFrom(self, reader); +} +- (void)writeTo:(PBDataWriter *)writer +{ + /* key */ + { + if (self->_key) + { + PBDataWriterWriteDataField(writer, self->_key, 1); + } + } + /* optionalParams */ + { + if (self->_optionalParams) + { + PBDataWriterWriteDataField(writer, self->_optionalParams, 2); + } + } +} + +- (void)copyTo:(MockAKSRefKey *)other +{ + if (_key) + { + other.key = _key; + } + if (_optionalParams) + { + other.optionalParams = _optionalParams; + } +} + +- (id)copyWithZone:(NSZone *)zone +{ + MockAKSRefKey *copy = [[[self class] allocWithZone:zone] init]; + copy->_key = [_key copyWithZone:zone]; + copy->_optionalParams = [_optionalParams copyWithZone:zone]; + return copy; +} + +- (BOOL)isEqual:(id)object +{ + MockAKSRefKey *other = (MockAKSRefKey *)object; + return [other isMemberOfClass:[self class]] + && + ((!self->_key && !other->_key) || [self->_key isEqual:other->_key]) + && + ((!self->_optionalParams && !other->_optionalParams) || [self->_optionalParams isEqual:other->_optionalParams]) + ; +} + +- (NSUInteger)hash +{ + return 0 + ^ + [self->_key hash] + ^ + [self->_optionalParams hash] + ; +} + +- (void)mergeFrom:(MockAKSRefKey *)other +{ + if (other->_key) + { + [self setKey:other->_key]; + } + if (other->_optionalParams) + { + [self setOptionalParams:other->_optionalParams]; + } +} + +@end + diff --git a/tests/secdmockaks/mockaks.h b/tests/secdmockaks/mockaks.h index d4d0ee8f..068c33fb 100644 --- a/tests/secdmockaks/mockaks.h +++ b/tests/secdmockaks/mockaks.h @@ -28,19 +28,28 @@ #if __has_include() #include -#else +#define HAVE_MobileKeyBag_MobileKeyBag 1 +#endif + +#if __OBJC2__ +#import +#endif + +CF_ASSUME_NONNULL_BEGIN + +#if !HAVE_MobileKeyBag_MobileKeyBag typedef struct __MKBKeyBagHandle* MKBKeyBagHandleRef; -int MKBKeyBagCreateWithData(CFDataRef keybagBlob, MKBKeyBagHandleRef* newHandle); +int MKBKeyBagCreateWithData(CFDataRef keybagBlob, MKBKeyBagHandleRef _Nullable * _Nonnull newHandle); #define kMobileKeyBagDeviceIsLocked 1 #define kMobileKeyBagDeviceIsUnlocked 0 -int MKBKeyBagUnlock(MKBKeyBagHandleRef keybag, CFDataRef passcode); -int MKBKeyBagGetAKSHandle(MKBKeyBagHandleRef keybag, int32_t *handle); -int MKBGetDeviceLockState(CFDictionaryRef options); -CF_RETURNS_RETAINED CFDictionaryRef MKBUserTypeDeviceMode(CFDictionaryRef options, CFErrorRef * error); -int MKBForegroundUserSessionID( CFErrorRef * error); +int MKBKeyBagUnlock(MKBKeyBagHandleRef keybag, CFDataRef _Nullable passcode); +int MKBKeyBagGetAKSHandle(MKBKeyBagHandleRef _Nonnull keybag, int32_t *_Nullable handle); +int MKBGetDeviceLockState(CFDictionaryRef _Nullable options); +CF_RETURNS_RETAINED CFDictionaryRef _Nullable MKBUserTypeDeviceMode(CFDictionaryRef _Nullable options, CFErrorRef _Nullable * _Nullable error); +int MKBForegroundUserSessionID( CFErrorRef _Nullable * _Nullable error); #define kMobileKeyBagSuccess (0) #define kMobileKeyBagError (-1) @@ -49,8 +58,8 @@ int MKBForegroundUserSessionID( CFErrorRef * error); #define kMobileKeyBagExistsError (-4) #define kMobileKeyBagNoMemoryError (-5) -#endif // +#endif // HAVE_MobileKeyBag_MobileKeyBag #if __OBJC2__ @@ -67,8 +76,15 @@ int MKBForegroundUserSessionID( CFErrorRef * error); + (void)unlockAllClasses; + (void)reset; + ++ (void)failNextDecryptRefKey:(NSError* _Nonnull) decryptRefKeyError; ++ (NSError * _Nullable)popDecryptRefKeyFailure; + @end #endif // OBJC2 +CF_ASSUME_NONNULL_END + + #endif /* mockaks_h */ diff --git a/tests/secdmockaks/mockaks.m b/tests/secdmockaks/mockaks.m index 71ac9ce5..4bf815b8 100644 --- a/tests/secdmockaks/mockaks.m +++ b/tests/secdmockaks/mockaks.m @@ -48,6 +48,9 @@ #import #import #import "mockaks.h" +#import "utilities/der_plist.h" +#import "tests/secdmockaks/generated_source/MockAKSRefKey.h" +#import "tests/secdmockaks/generated_source/MockAKSOptionalParameters.h" bool hwaes_key_available(void) { @@ -66,7 +69,7 @@ bool hwaes_key_available(void) static NSMutableDictionary* _lockedStates = nil; static dispatch_queue_t _mutabilityQueue = nil; static keybag_state_t _keybag_state = keybag_state_unlocked | keybag_state_been_unlocked; - +static NSMutableArray* _decryptRefKeyErrors = nil; /* * Method that limit where this rather in-secure version of AKS can run */ @@ -196,6 +199,30 @@ static keybag_state_t _keybag_state = keybag_state_unlocked | keybag_state_been_ }); } ++ (void)failNextDecryptRefKey: (NSError* _Nonnull) decryptRefKeyError { + if (_decryptRefKeyErrors == NULL) { + _decryptRefKeyErrors = [NSMutableArray array]; + } + @synchronized(_decryptRefKeyErrors) { + [_decryptRefKeyErrors addObject: decryptRefKeyError]; + } +} + ++ (NSError * _Nullable)popDecryptRefKeyFailure { + NSError* error = nil; + if (_decryptRefKeyErrors == NULL) { + return nil; + } + @synchronized(_decryptRefKeyErrors) { + if(_decryptRefKeyErrors.count > 0) { + error = _decryptRefKeyErrors[0]; + [_decryptRefKeyErrors removeObjectAtIndex:0]; + } + } + return error; +} + + @end kern_return_t @@ -342,19 +369,92 @@ aks_unwrap_key(const void * wrapped_key, int wrapped_key_size, keyclass_t key_cl return kAKSReturnSuccess; } +@interface MockAKSRefKeyObject: NSObject +@property NSData *keyData; +@property SFAESKey *key; +@property NSData *acmHandle; +@property NSData *externalData; + +@property NSData *blob; // blob is exteralized format + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithKeyData:(NSData *)keyData parameters:(NSData *)parameters error:(NSError **)error; + +@end +@implementation MockAKSRefKeyObject + +- (instancetype)initWithKeyData:(NSData *)keyData + parameters:(NSData *)parameters + error:(NSError **)error +{ + if ((self = [super init]) != NULL) { + + self.keyData = [keyData copy]; + SFAESKeySpecifier* keySpecifier = [[SFAESKeySpecifier alloc] initWithBitSize: SFAESKeyBitSize256]; + @try { + self.key = [[SFAESKey alloc] initWithData:self.keyData specifier:keySpecifier error:error]; + if (self.key == NULL) { + return NULL; + } + } @catch (NSException *exception) { + *error = [NSError errorWithDomain:@"foo" code:kAKSReturnBadArgument userInfo:nil]; + return NULL; + } + + MockAKSOptionalParameters *params = [[MockAKSOptionalParameters alloc] initWithData:parameters]; + + // enforce that the extra data is DER like + if (params.externalData) { + CFTypeRef cf = NULL; + CFErrorRef cferror = NULL; + uint8_t *der = (uint8_t *)params.externalData.bytes; + der_decode_plist(NULL, false, &cf, &cferror, der, der + params.externalData.length); + if (cf == NULL) { + *error = [NSError errorWithDomain:@"foo" code:kAKSReturnBadArgument userInfo:nil]; + return NULL; + } + CFReleaseNull(cf); + } + + + self.externalData = params.externalData; + self.acmHandle = params.acmHandle; + + MockAKSRefKey *blob = [[MockAKSRefKey alloc] init]; + blob.key = self.keyData; + blob.optionalParams = parameters; + self.blob = blob.data; + } + return self; +} + +@end + int -aks_ref_key_create(keybag_handle_t handle, keyclass_t cls, aks_key_type_t type, const uint8_t *params, size_t params_len, aks_ref_key_t *ot) +aks_ref_key_create(keybag_handle_t handle, keyclass_t key_class, aks_key_type_t type, const uint8_t *params, size_t params_len, aks_ref_key_t *ot) { - [SecMockAKS trapdoor]; + MockAKSRefKeyObject *key; + @autoreleasepool { + [SecMockAKS trapdoor]; + NSError *error = NULL; - // For now, mock AKS keys are all the same key - NSData* keyData = [NSData dataWithBytes:"1234567890123456789012345678901" length:32]; - SFAESKeySpecifier* keySpecifier = [[SFAESKeySpecifier alloc] initWithBitSize:SFAESKeyBitSize256]; - NSError* error = nil; - SFAESKey* key = [[SFAESKey alloc] initWithData:keyData specifier:keySpecifier error:&error]; + if ([SecMockAKS isLocked:key_class]) { + return kAKSReturnNoPermission; + } - if(error) { - return kAKSReturnError; + NSData *keyData = [NSData dataWithBytes:"1234567890123456789012345678901" length:32]; + NSData *parameters = NULL; + if (params && params_len != 0) { + parameters = [NSData dataWithBytes:params length:params_len]; + } + + key = [[MockAKSRefKeyObject alloc] initWithKeyData:keyData parameters:parameters error:&error]; + if(key == NULL) { + if (error) { + return (int)error.code; + } + return kAKSReturnError; + } } *ot = (__bridge_retained aks_ref_key_t)key; @@ -373,18 +473,17 @@ aks_ref_key_encrypt(aks_ref_key_t handle, NSError* error = nil; NSData* nsdata = [NSData dataWithBytes:data length:data_len]; - SFAESKey* key = (__bridge SFAESKey*)handle; - SFAuthenticatedEncryptionOperation* op = [[SFAuthenticatedEncryptionOperation alloc] initWithKeySpecifier:key.keySpecifier authenticationMode:SFAuthenticatedEncryptionModeGCM]; + MockAKSRefKeyObject *key = (__bridge MockAKSRefKeyObject*)handle; + + SFAuthenticatedEncryptionOperation* op = [[SFAuthenticatedEncryptionOperation alloc] initWithKeySpecifier:key.key.keySpecifier authenticationMode:SFAuthenticatedEncryptionModeGCM]; - SFAuthenticatedCiphertext* ciphertext = [op encrypt:nsdata withKey:key error:&error]; + SFAuthenticatedCiphertext* ciphertext = [op encrypt:nsdata withKey:key.key error:&error]; if(error || !ciphertext || !out_der || !out_der_len) { return kAKSReturnError; } - //[NSKeyedUnarchiver unarchivedObjectOfClass:[SFAuthenticatedCiphertext class] fromData:_serializedHolder.ciphertext error:&error]; - NSData* cipherBytes = [NSKeyedArchiver archivedDataWithRootObject:ciphertext requiringSecureCoding:YES error:&error]; if(error || !cipherBytes) { return kAKSReturnError; @@ -400,41 +499,88 @@ aks_ref_key_encrypt(aks_ref_key_t handle, int aks_ref_key_decrypt(aks_ref_key_t handle, - const uint8_t *der_params, size_t der_params_len, - const void * data, size_t data_len, - void ** out_der, size_t * out_der_len) + const uint8_t *der_params, size_t der_params_len, + const void * data, size_t data_len, + void ** out_der, size_t * out_der_len) { - [SecMockAKS trapdoor]; + @autoreleasepool { + [SecMockAKS trapdoor]; - if (!out_der || !out_der_len || !data) { - return kAKSReturnError; - } + NSError *error = [SecMockAKS popDecryptRefKeyFailure]; + if (error) { + return (int)error.code; + } - NSError* error = nil; - NSData* nsdata = [NSData dataWithBytes:data length:data_len]; + if (!out_der || !out_der_len || !data) { + return kAKSReturnError; + } - SFAESKey* key = (__bridge SFAESKey*)handle; + if (der_params) { + NSData *paramsData = [NSData dataWithBytes:der_params length:der_params_len]; + MockAKSOptionalParameters *params = [[MockAKSOptionalParameters alloc] initWithData:paramsData]; - NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:nsdata error:&error]; - SFAuthenticatedCiphertext* ciphertext = [unarchiver decodeObjectOfClass:[SFAuthenticatedCiphertext class] forKey:NSKeyedArchiveRootObjectKey]; + if (params.hasExternalData && !params.hasAcmHandle) { + return kSKSReturnPolicyInvalid; + } + (void)params; /* check ACM context if the item uses policy */ + } - if(error || !ciphertext) { - return kAKSReturnError; - } - SFAuthenticatedEncryptionOperation* op = [[SFAuthenticatedEncryptionOperation alloc] initWithKeySpecifier:key.keySpecifier authenticationMode:SFAuthenticatedEncryptionModeGCM]; - NSData* plaintext = [op decrypt:ciphertext withKey:key error:&error]; + NSData* nsdata = [NSData dataWithBytes:data length:data_len]; - if(error || !plaintext) { - return kAKSReturnDecodeError; - } + MockAKSRefKeyObject* key = (__bridge MockAKSRefKeyObject*)handle; + + SFAuthenticatedCiphertext* ciphertext = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFAuthenticatedCiphertext class] fromData:nsdata error:&error]; - *out_der = calloc(1, plaintext.length); + if(error || !ciphertext) { + return kAKSReturnDecodeError; + } - memcpy(*out_der, plaintext.bytes, plaintext.length); - *out_der_len = plaintext.length; + // this should not be needed... + if (![ciphertext isKindOfClass:[SFAuthenticatedCiphertext class]]) { + return kAKSReturnDecodeError; + } + if (![ciphertext.ciphertext isKindOfClass:[NSData class]]) { + return kAKSReturnDecodeError; + } + if (![ciphertext.authenticationCode isKindOfClass:[NSData class]]) { + return kAKSReturnDecodeError; + } + if (![ciphertext.initializationVector isKindOfClass:[NSData class]]) { + return kAKSReturnDecodeError; + } - return kAKSReturnSuccess; + NSData* plaintext = NULL; + + SFAuthenticatedEncryptionOperation* op = [[SFAuthenticatedEncryptionOperation alloc] initWithKeySpecifier:key.key.keySpecifier authenticationMode:SFAuthenticatedEncryptionModeGCM]; + plaintext = [op decrypt:ciphertext withKey:key.key error:&error]; + + if(error || !plaintext) { + return kAKSReturnDecodeError; + } + + /* + * AAAAAAAAHHHHHHHHH + * The output of aks_ref_key_encrypt is not the decrypted data, it's a DER blob that contains an octet string of the data.... + */ + + CFErrorRef cfError = NULL; + NSData* derData = (__bridge_transfer NSData*)CFPropertyListCreateDERData(NULL, (__bridge CFTypeRef)plaintext, &cfError); + CFReleaseNull(cfError); + if (derData == NULL) { + return kAKSReturnDecodeError; + } + + *out_der = calloc(1, derData.length); + if (*out_der == NULL) { + abort(); + } + + memcpy(*out_der, derData.bytes, derData.length); + *out_der_len = derData.length; + + return kAKSReturnSuccess; + } } int aks_ref_key_wrap(aks_ref_key_t handle, @@ -467,39 +613,87 @@ aks_ref_key_delete(aks_ref_key_t handle, const uint8_t *der_params, size_t der_p int aks_operation_optional_params(const uint8_t * access_groups, size_t access_groups_len, const uint8_t * external_data, size_t external_data_len, const void * acm_handle, int acm_handle_len, void ** out_der, size_t * out_der_len) { - // ugh. Let's at least pretend we're doing something here. - assert((out_der && out_der_len) || !(out_der || out_der_len)); - if (out_der) { - *out_der = calloc(1, 150); - memset(*out_der, 'A', 150); - *out_der_len = 150; - } + @autoreleasepool { + [SecMockAKS trapdoor]; - return kAKSReturnSuccess; + MockAKSOptionalParameters* params = [[MockAKSOptionalParameters alloc] init]; + + if (access_groups) { + params.accessGroups = [NSData dataWithBytes:access_groups length:access_groups_len]; + } + if (external_data) { + params.externalData = [NSData dataWithBytes:external_data length:external_data_len]; + } + if (acm_handle) { + params.acmHandle = [NSData dataWithBytes:acm_handle length:acm_handle_len]; + } + + NSData *result = params.data; + *out_der = malloc(result.length); + memcpy(*out_der, result.bytes, result.length); + *out_der_len = result.length; + return kAKSReturnSuccess; + } } int aks_ref_key_create_with_blob(keybag_handle_t keybag, const uint8_t *ref_key_blob, size_t ref_key_blob_len, aks_ref_key_t* handle) { - aks_ref_key_create(keybag, 0, 0, NULL, 0, handle); + NSError *error = NULL; + MockAKSRefKeyObject *key = NULL; + + @autoreleasepool { + [SecMockAKS trapdoor]; + NSData *data = [NSData dataWithBytes:ref_key_blob length:ref_key_blob_len]; + + MockAKSRefKey *blob = [[MockAKSRefKey alloc] initWithData:data]; + if (blob == NULL) { + return kAKSReturnBadData; + } + if (!blob.hasKey || blob.key.length == 0) { + return kAKSReturnBadData; + } + + key = [[MockAKSRefKeyObject alloc] initWithKeyData:blob.key parameters:blob.optionalParams error:&error]; + } + if (key == NULL) { + *handle = (aks_ref_key_t)-1; + if (error.code) { + return (int)error.code; + } + return kAKSReturnError; + } + + *handle = (__bridge_retained aks_ref_key_t)key; return kAKSReturnSuccess; } const uint8_t * aks_ref_key_get_blob(aks_ref_key_t refkey, size_t *out_blob_len) { - *out_blob_len = 2; - return (const uint8_t *)"20"; + MockAKSRefKeyObject *key = (__bridge MockAKSRefKeyObject*)refkey; + + *out_blob_len = key.blob.length; + return (const uint8_t *)key.blob.bytes; } + int -aks_ref_key_free(aks_ref_key_t* key) +aks_ref_key_free(aks_ref_key_t* refkey) { + if (*refkey != NULL) { + MockAKSRefKeyObject *key = (__bridge MockAKSRefKeyObject*)*refkey; + CFTypeRef cfkey = CFBridgingRetain(key); + CFRelease(cfkey); + *refkey = NULL; + } return kAKSReturnSuccess; } const uint8_t * aks_ref_key_get_external_data(aks_ref_key_t refkey, size_t *out_external_data_len) { - *out_external_data_len = 2; - return (const uint8_t *)"21"; + MockAKSRefKeyObject *key = (__bridge MockAKSRefKeyObject*)refkey; + + *out_external_data_len = key.externalData.length; + return (const uint8_t *)key.externalData.bytes; } kern_return_t diff --git a/tests/secdmockaks/mockaksKeychain.m b/tests/secdmockaks/mockaksKeychain.m index 27662ddd..d69762fe 100644 --- a/tests/secdmockaks/mockaksKeychain.m +++ b/tests/secdmockaks/mockaksKeychain.m @@ -29,9 +29,11 @@ #import "SecItemServer.h" #import "SecItemSchema.h" #include "OSX/sec/Security/SecItemShim.h" +#import "server_security_helpers.h" #import "spi.h" #import #import +#import "utilities/der_plist.h" #import #import #import @@ -51,6 +53,29 @@ @interface secdmockaks : mockaksxcbase @end +@interface NSData (secdmockaks) +- (NSString *)hexString; +@end + +@implementation NSData (secdmockaks) +- (NSString *)hexString +{ + static const char tbl[] = "0123456789ABCDEF"; + NSUInteger len = self.length; + char *buf = malloc(len * 2); + [self enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) { + const uint8_t *p = (const uint8_t *)bytes; + for (NSUInteger i = byteRange.location; i < NSMaxRange(byteRange); i++) { + uint8_t byte = *p++; + buf[i * 2 + 0] = tbl[(byte >> 4) & 0xf]; + buf[i * 2 + 1] = tbl[(byte >> 0) & 0xf]; + } + }]; + return [[NSString alloc] initWithBytesNoCopy:buf length:len * 2 encoding:NSUTF8StringEncoding freeWhenDone:YES]; +} +@end + + @implementation secdmockaks @@ -93,6 +118,39 @@ } } +- (void)createECKeyWithACL:(NSString *)label +{ + NSDictionary* keyParams = @{ + (__bridge id)kSecAttrKeyClass : (__bridge id)kSecAttrKeyClassPrivate, + (__bridge id)kSecAttrKeyType : (__bridge id)kSecAttrKeyTypeEC, + (__bridge id)kSecAttrKeySizeInBits: @(256), + }; + SecAccessControlRef ref = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenUnlocked, 0, NULL); + XCTAssertNotEqual(ref, NULL, @"SAC"); + + SecKeyRef key = SecKeyCreateRandomKey((__bridge CFDictionaryRef)keyParams, NULL); + XCTAssertNotEqual(key, NULL, @"failed to create test key to keychain"); + + NSDictionary* item = @{ + (__bridge id)kSecClass: (__bridge id)kSecClassKey, + (__bridge id)kSecValueRef: (__bridge id)key, + (__bridge id)kSecAttrLabel: label, + (__bridge id)kSecUseDataProtectionKeychain: @(YES), + (__bridge id)kSecAttrAccessControl: (__bridge id)ref, + }; + + OSStatus result = SecItemAdd((__bridge CFDictionaryRef)item, NULL); + XCTAssertEqual(result, 0, @"failed to add test key to keychain"); +} + +- (void)createManyACLKeyItems +{ + unsigned n; + for (n = 0; n < 50; n++) { + [self createECKeyWithACL: [NSString stringWithFormat:@"TestLabel-EC-%u", n]]; + } +} + - (void)findManyItems:(unsigned)searchLimit { unsigned n; @@ -136,8 +194,10 @@ - (void)testSecItemServerDeleteAll { + [self addAccessGroup:@"com.apple.bluetooth"]; [self addAccessGroup:@"lockdown-identities"]; + [self addAccessGroup:@"apple"]; // BT root key, should not be deleted NSMutableDictionary* bt = [@{ @@ -248,6 +308,7 @@ { [self createManyItems]; [self createManyKeys]; + [self createManyACLKeyItems]; NSDictionary* item = @{ (id)kSecClass : (id)kSecClassGenericPassword, @@ -309,6 +370,7 @@ [self createManyItems]; [self createManyKeys]; + [self createManyACLKeyItems]; /* sleep(600); @@ -635,6 +697,218 @@ XCTAssertEqual(CFDictionaryGetValue(output, (id)kSecAttrKeyType), (__bridge CFNumberRef)[NSNumber numberWithUnsignedInt:0x80000001L], "keytype is unchanged"); } +- (NSData *)objectToDER:(NSDictionary *)dict +{ + CFPropertyListRef object = (__bridge CFPropertyListRef)dict; + CFErrorRef error = NULL; + + size_t size = der_sizeof_plist(object, &error); + if (!size) { + return NULL; + } + NSMutableData *data = [NSMutableData dataWithLength:size]; + uint8_t *der = [data mutableBytes]; + uint8_t *der_end = der + size; + uint8_t *der_start = der_encode_plist(object, &error, der, der_end); + if (!der_start) { + return NULL; + } + return data; +} + +#if !TARGET_OS_WATCH +/* this should be enabled for watch too, but that cause a crash in the mock aks layer */ + +- (void)testUpgradeWithBadACLKey +{ + SecAccessControlRef ref = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenUnlocked, 0, NULL); + XCTAssertNotEqual(ref, NULL, @"SAC"); + + NSDictionary *canaryItem = @{ + (__bridge NSString *)kSecClass : (__bridge NSString *)kSecClassInternetPassword, + (__bridge NSString *)kSecAttrServer : @"server-here", + (__bridge NSString *)kSecAttrAccount : @"foo", + (__bridge NSString *)kSecAttrPort : @80, + (__bridge NSString *)kSecAttrProtocol : @"http", + (__bridge NSString *)kSecAttrAuthenticationType : @"dflt", + (__bridge NSString *)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding], + }; + + NSDictionary* canaryQuery = @{ + (id)kSecClass : (id)kSecClassInternetPassword, + (__bridge NSString *)kSecAttrServer : @"server-here", + (__bridge NSString *)kSecAttrAccount : @"foo", + (__bridge NSString *)kSecAttrPort : @80, + (__bridge NSString *)kSecAttrProtocol : @"http", + (__bridge NSString *)kSecAttrAuthenticationType : @"dflt", + (id)kSecUseDataProtectionKeychain : @(YES), + }; + + NSDictionary* baseQuery = @{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccount : @"TestAccount-0", + (id)kSecAttrService : @"TestService", + (id)kSecUseDataProtectionKeychain : @(YES), + }; + + NSMutableDictionary* query = [baseQuery mutableCopy]; + [query addEntriesFromDictionary:@{ + (id)kSecReturnAttributes: @YES, + (id)kSecReturnData: @YES, + }]; + + NSMutableDictionary* add = [baseQuery mutableCopy]; + [add addEntriesFromDictionary:@{ + (__bridge id)kSecValueData: [@"foo" dataUsingEncoding:NSUTF8StringEncoding], + (__bridge id)kSecAttrAccessControl: (__bridge id)ref, + }]; + + XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)canaryItem, NULL), errSecSuccess, "should successfully add canaryItem"); + XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)canaryQuery, NULL), errSecSuccess, "should successfully get canaryItem"); + + __block NSUInteger counter = 0; + __block bool mutatedDatabase = true; + while (mutatedDatabase) { + mutatedDatabase = false; + + if (counter == 0) { + /* corruption of version is not great if its > 7 */ + counter++; + } + + kc_with_dbt(true, NULL, ^bool (SecDbConnectionRef dbt) { + CFErrorRef localError = NULL; + (void)SecDbExec(dbt, CFSTR("DELETE FROM genp"), &localError); + CFReleaseNull(localError); + return true; + }); + SecKeychainDbReset(NULL); + + XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecItemNotFound, "should successfully get item"); + XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)add, NULL), errSecSuccess, "should successfully add item"); + XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess, "should successfully get item"); + + XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)canaryQuery, NULL), errSecSuccess, + "should successfully get canaryItem pre %d", (int)counter); + + // lower database and destroy the item + kc_with_dbt(true, NULL, ^bool (SecDbConnectionRef dbt) { + CFErrorRef localError2 = NULL; + __block bool ok = true; + int version = 0; + + SecKeychainDbGetVersion(dbt, &version, &localError2); + CFReleaseNull(localError2); + + // force a minor (if more then zero), otherwise pick major + NSString *downgradeString = nil; + if ((version & (0xff00)) != 0) { + downgradeString = [NSString stringWithFormat:@"UPDATE tversion SET version='%d', minor='%d'", + (version & 0xff), 0]; + } else { + downgradeString = [NSString stringWithFormat:@"UPDATE tversion SET version='%d', minor='%d'", + ((version & 0xff) - 1), 0]; + } + + ok = SecDbExec(dbt, (__bridge CFStringRef)downgradeString, &localError2); + XCTAssertTrue(ok, "downgrade should be successful: %@", localError2); + CFReleaseNull(localError2); + + __block NSData *data = nil; + __block unsigned steps = 0; + ok &= SecDbPrepare(dbt, CFSTR("SELECT data FROM genp"), &localError2, ^(sqlite3_stmt *stmt) { + ok = SecDbStep(dbt, stmt, NULL, ^(bool *stop) { + steps++; + + void *ptr = (uint8_t *)sqlite3_column_blob(stmt, 0); + size_t length = sqlite3_column_bytes(stmt, 0); + XCTAssertNotEqual(ptr, NULL, "should have ptr"); + XCTAssertNotEqual(length, 0, "should have data"); + data = [NSData dataWithBytes:ptr length:length]; + }); + }); + XCTAssertTrue(ok, "copy should be successful: %@", localError2); + XCTAssertEqual(steps, 1, "steps should be 1, since we should only have one genp"); + XCTAssertNotNil(data, "should find the row"); + CFReleaseNull(localError2); + + + NSMutableData *mutatedData = [data mutableCopy]; + + if (counter < mutatedData.length) { + mutatedDatabase = true; + ((uint8_t *)[mutatedData mutableBytes])[counter] = 'X'; + counter++; + } else { + counter = 0; + } + + + NSString *mutateString = [NSString stringWithFormat:@"UPDATE genp SET data=x'%@'", + [mutatedData hexString]]; + + ok &= SecDbPrepare(dbt, (__bridge CFStringRef)mutateString, &localError2, ^(sqlite3_stmt *stmt) { + ok = SecDbStep(dbt, stmt, NULL, ^(bool *stop) { + }); + }); + XCTAssertTrue(ok, "corruption should be successful: %@", localError2); + CFReleaseNull(localError2); + + return ok; + }); + + // force it to reload + SecKeychainDbReset(NULL); + + //dont care about result, we might have done a good number on this item + (void)SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL); + XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)canaryQuery, NULL), errSecSuccess, + "should successfully get canaryItem final %d", (int)counter); + } + + NSLog(@"count: %lu", (unsigned long)counter); + + XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)canaryQuery, NULL), errSecSuccess, + "should successfully get canaryItem final %d", (int)counter); +} +#endif /* !TARGET_OS_WATCH */ + +- (void)testInteractionFailuresFromReferenceKeys +{ + SecAccessControlRef ref = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenUnlocked, 0, NULL); + XCTAssertNotEqual(ref, NULL, @"SAC"); + + NSDictionary* query = @{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccount : @"TestAccount-0", + (id)kSecAttrService : @"TestService", + (id)kSecUseDataProtectionKeychain : @(YES), + (id)kSecReturnAttributes: @YES, + (id)kSecReturnData: @YES, + }; + + NSDictionary* add = @{ + (id)kSecClass : (id)kSecClassGenericPassword, + (id)kSecAttrAccount : @"TestAccount-0", + (id)kSecAttrService : @"TestService", + (id)kSecUseDataProtectionKeychain : @(YES), + (id)kSecValueData: [@"foo" dataUsingEncoding:NSUTF8StringEncoding], + (id)kSecAttrAccessControl: (__bridge id)ref, + }; + + + XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecItemNotFound, "should successfully get item"); + XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)add, NULL), errSecSuccess, "should successfully add item"); + XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess, "should successfully get item"); + + [SecMockAKS failNextDecryptRefKey:[NSError errorWithDomain:@"foo" code:kAKSReturnNoPermission userInfo:nil]]; + XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecInteractionNotAllowed, "should successfully get item"); + + XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess, "should successfully get item"); +} + + + #endif /* USE_KEYSTORE */ @end diff --git a/tests/secdmockaks/mockaksxcbase.m b/tests/secdmockaks/mockaksxcbase.m index 22dfdc0a..86670e17 100644 --- a/tests/secdmockaks/mockaksxcbase.m +++ b/tests/secdmockaks/mockaksxcbase.m @@ -49,6 +49,7 @@ NSString* homeDirUUID; #if OCTAGON SecCKKSTestSetDisableSOS(true); #endif + // Give this test run a UUID within which each test has a directory homeDirUUID = [[NSUUID UUID] UUIDString]; } diff --git a/trust/trustd/SecRevocationDb.c b/trust/trustd/SecRevocationDb.c index 92f9ae42..fb0028ca 100644 --- a/trust/trustd/SecRevocationDb.c +++ b/trust/trustd/SecRevocationDb.c @@ -906,6 +906,7 @@ static bool SecValidUpdateSchedule(bool updateEnabled, CFStringRef server, CFInd /* If update not permitted return */ if (!updateEnabled) { + secnotice("validupdate", "skipping update"); return false; } @@ -1208,8 +1209,11 @@ static bool _SecRevocationDbCheckNextUpdate(void) { } // determine whether update fetching is enabled -#if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101300 || __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000) - bool updateEnabled = true; // macOS 10.13 or iOS 11.0 +#if !TARGET_OS_WATCH && !TARGET_OS_BRIDGE + // Valid update fetching was initially enabled on macOS 10.13 and iOS 11.0. + // This conditional has been changed to include every platform and version + // except for those where the db should not be updated over the air. + bool updateEnabled = true; #else bool updateEnabled = false; #endif diff --git a/trust/trustd/SecTrustServer.c b/trust/trustd/SecTrustServer.c index 1227f246..06f56077 100644 --- a/trust/trustd/SecTrustServer.c +++ b/trust/trustd/SecTrustServer.c @@ -32,6 +32,7 @@ #include "trust/trustd/SecRevocationServer.h" #include "trust/trustd/SecCertificateServer.h" #include "trust/trustd/SecPinningDb.h" +#include "trust/trustd/md.h" #include #include @@ -1162,14 +1163,15 @@ static bool SecPathBuilderReportResult(SecPathBuilderRef builder) { * got a revocation response as well. */ if (builder->info && SecCertificatePathVCIsEV(builder->bestPath) && SecPathBuilderIsOkResult(builder)) { #if !TARGET_OS_WATCH - if (SecCertificatePathVCIsRevocationDone(builder->bestPath)) { - CFAbsoluteTime nextUpdate = SecCertificatePathVCGetEarliestNextUpdate(builder->bestPath); - if (nextUpdate != 0) { -#else /* We don't do networking on watchOS, so we can't require OCSP for EV */ + if (SecCertificatePathVCIsRevocationDone(builder->bestPath)) +#endif { - { +#if !TARGET_OS_WATCH + CFAbsoluteTime nextUpdate = SecCertificatePathVCGetEarliestNextUpdate(builder->bestPath); + if (nextUpdate != 0) #endif + { /* Successful revocation check, so this cert is EV */ CFDictionarySetValue(builder->info, kSecTrustInfoExtendedValidationKey, kCFBooleanTrue); /* iOS key */ diff --git a/trust/trustd/SecTrustServer.h b/trust/trustd/SecTrustServer.h index 531ba549..898e71f3 100644 --- a/trust/trustd/SecTrustServer.h +++ b/trust/trustd/SecTrustServer.h @@ -179,6 +179,7 @@ typedef CF_OPTIONS(uint8_t, TAValidStatus) { typedef struct { uint64_t start_time; + bool suspected_mitm; // Certificate Transparency TA_SCTSource sct_sources; uint32_t number_scts; diff --git a/trust/trustd/md.h b/trust/trustd/md.h new file mode 100644 index 00000000..8a8e12cc --- /dev/null +++ b/trust/trustd/md.h @@ -0,0 +1,23 @@ +/* +* Copyright (c) 2019 Apple Inc. All Rights Reserved. +* +* @APPLE_LICENSE_HEADER_START@ +* +* This file contains Original Code and/or Modifications of Original Code +* as defined in and that are subject to the Apple Public Source License +* Version 2.0 (the 'License'). You may not use this file except in +* compliance with the License. Please obtain a copy of the License at +* http://www.opensource.apple.com/apsl/ and read it before using this +* file. +* +* The Original Code and all software distributed under the License are +* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +* Please see the License for the specific language governing rights and +* limitations under the License. +* +* @APPLE_LICENSE_HEADER_END@ +*/ + diff --git a/trust/trustd/md.m b/trust/trustd/md.m new file mode 100644 index 00000000..c918e7d2 --- /dev/null +++ b/trust/trustd/md.m @@ -0,0 +1,43 @@ +/* +* Copyright (c) 2019 Apple Inc. All Rights Reserved. +* +* @APPLE_LICENSE_HEADER_START@ +* +* This file contains Original Code and/or Modifications of Original Code +* as defined in and that are subject to the Apple Public Source License +* Version 2.0 (the 'License'). You may not use this file except in +* compliance with the License. Please obtain a copy of the License at +* http://www.opensource.apple.com/apsl/ and read it before using this +* file. +* +* The Original Code and all software distributed under the License are +* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. +* Please see the License for the specific language governing rights and +* limitations under the License. +* +* @APPLE_LICENSE_HEADER_END@ +*/ + +#include +#import +#import +#import +#import + +#import +#import +#import +#import + +#include +#include +#include + +#include "trust/trustd/SecTrustServer.h" +#include "trust/trustd/SecCertificateSource.h" +#include "trust/trustd/SecPolicyServer.h" +#include "trust/trustd/SecTrustLoggingServer.h" + diff --git a/xcconfig/PlatformLibraries.xcconfig b/xcconfig/PlatformLibraries.xcconfig index 8c2490e6..1960abdc 100644 --- a/xcconfig/PlatformLibraries.xcconfig +++ b/xcconfig/PlatformLibraries.xcconfig @@ -4,7 +4,7 @@ OTHER_LDFLAGS_AKS_LIBRARY[sdk=macosx*] = -L$(SDKROOT)/usr/local/lib -laks -laks_ OTHER_LDFLAGS_AKS_LIBRARY[sdk=iphoneos*] = -L$(SDKROOT)/usr/local/lib -laks -laks_real_witness OTHER_LDFLAGS_AKS_LIBRARY[sdk=watchos*] = -L$(SDKROOT)/usr/local/lib -laks -laks_real_witness OTHER_LDFLAGS_AKS_LIBRARY[sdk=appletvos*] = -L$(SDKROOT)/usr/local/lib -laks -laks_real_witness -OTHER_LDFLAGS_AKS_LIBRARY[sdk=iphonesimulator*] = -laks_mock -Wl,-upward_framework,SecurityFoundation +OTHER_LDFLAGS_AKS_LIBRARY[sdk=iphonesimulator*] = -laks_mock -Wl,-upward_framework,SecurityFoundation -Wl,-upward_framework,ProtocolBuffer OTHER_LDFLAGS_MOBILE_KEYBAG[sdk=macosx*] = -framework MobileKeyBag OTHER_LDFLAGS_MOBILE_KEYBAG[sdk=iphoneos*] = -framework MobileKeyBag diff --git a/xcconfig/Security.xcconfig b/xcconfig/Security.xcconfig index c4dd5a07..195db7c3 100644 --- a/xcconfig/Security.xcconfig +++ b/xcconfig/Security.xcconfig @@ -37,7 +37,11 @@ OTHER_TAPI_FLAGS_SOS = -extra-public-header $(PROJECT_DIR)/keychain/SecureObject // This isn't OTHER_TAPI_FLAGS because we'll mess up other, non-Security.framework frameworks in the project // Please don't add any more headers here. -OTHER_TAPI_FLAGS_SECURITY_FRAMEWORK = --verify-api-error-as-warning -D SECURITY_PROJECT_TAPI_HACKS=1 -extra-private-header $(PROJECT_DIR)/OSX/sec/Security/SecTrustInternal.h $(OTHER_TAPI_FLAGS_SOS) +OTHER_TAPI_FLAGS_SECURITY_FRAMEWORK_COMMON = --verify-api-error-as-warning -D SECURITY_PROJECT_TAPI_HACKS=1 -extra-private-header $(PROJECT_DIR)/OSX/sec/Security/SecTrustInternal.h $(OTHER_TAPI_FLAGS_SOS) -extra-private-header $(PROJECT_DIR)/OSX/libsecurity_codesigning/lib/SecCodePriv.h -extra-private-header $(PROJECT_DIR)/Analytics/SQLite/SFSQLite.h -extra-private-header $(PROJECT_DIR)/OSX/libsecurity_ssl/lib/sslDeprecated.h -extra-private-header $(PROJECT_DIR)/OSX/libsecurity_asn1/lib/secport-tapi.h -extra-private-header $(PROJECT_DIR)/OSX/libsecurity_smime/lib/cms-tapi.h -extra-private-header $(PROJECT_DIR)/OSX/utilities/SecAppleAnchor-tapi.h -extra-private-header $(PROJECT_DIR)/OSX/sec/Security/SecRSAKey.h -extra-private-header $(PROJECT_DIR)/OSX/sec/Security/SecPolicy-tapi.h -extra-private-header $(PROJECT_DIR)/OSX/sec/Security/SecEC-tapi.h -extra-private-header $(PROJECT_DIR)/OSX/sec/Security/Security-tapi.h + +OTHER_TAPI_FLAGS_SECURITY_FRAMEWORK_PLATFORM[sdk=macos*] = $(OTHER_TAPI_FLAGS_SECURITY_FRAMEWORK_COMMON) -extra-private-header $(PROJECT_DIR)/OSX/libsecurity_transform/lib/SecCollectTransform.h -extra-private-header $(PROJECT_DIR)/OSX/libsecurity_transform/lib/SecMaskGenerationFunctionTransform.h -extra-private-header $(PROJECT_DIR)/OSX/libsecurity_transform/lib/SecTransformValidator.h +OTHER_TAPI_FLAGS_SECURITY_FRAMEWORK_PLATFORM[sdk=embedded*] = $(OTHER_TAPI_FLAGS_SECURITY_FRAMEWORK_COMMON) +OTHER_TAPI_FLAGS_SECURITY_FRAMEWORK = $(OTHER_TAPI_FLAGS_SECURITY_FRAMEWORK_PLATFORM) SECURITY_XCTEST_DIRECTORY = /AppleInternal/XCTests/com.apple.security -- 2.45.2